move window files into main window directory rather than being window wrapper

macos-click-through
Keith Simmons 3 years ago
parent b78a714be0
commit 6b96f79bb1

@ -256,4 +256,3 @@ fn windows_attach_to_console() {
AttachConsole(ATTACH_PARENT_PROCESS); AttachConsole(ATTACH_PARENT_PROCESS);
} }
} }

@ -100,8 +100,9 @@ impl GridRenderer {
.set_color(style.background(&self.default_style.colors).to_color()); .set_color(style.background(&self.default_style.colors).to_color());
} }
if (SETTINGS.get::<WindowSettings>().transparency - 1.0).abs() > f32::EPSILON && if (SETTINGS.get::<WindowSettings>().transparency - 1.0).abs() > f32::EPSILON
self.paint.color() == self.get_default_background() { && self.paint.color() == self.get_default_background()
{
if is_floating { if is_floating {
self.paint self.paint
.set_alpha((255.0 * SETTINGS.get::<RendererSettings>().floating_opacity) as u8); .set_alpha((255.0 * SETTINGS.get::<RendererSettings>().floating_opacity) as u8);

@ -1,5 +1,351 @@
mod keyboard_manager;
mod mouse_manager;
mod renderer;
mod settings; mod settings;
mod window_wrapper;
pub use settings::*; use std::{
pub use window_wrapper::create_window; sync::mpsc::Receiver,
time::{Duration, Instant},
};
use glutin::{
self,
dpi::PhysicalSize,
event::{Event, WindowEvent},
event_loop::{ControlFlow, EventLoop},
window::{self, Fullscreen, Icon},
ContextBuilder, GlProfile, WindowedContext,
};
use log::trace;
#[cfg(target_os = "linux")]
use glutin::platform::unix::WindowBuilderExtUnix;
use crate::{
bridge::{ParallelCommand, UiCommand},
channel_utils::*,
cmd_line::CmdLineSettings,
editor::DrawCommand,
editor::WindowCommand,
redraw_scheduler::REDRAW_SCHEDULER,
renderer::Renderer,
running_tracker::*,
settings::{maybe_save_window_size, SETTINGS},
utils::Dimensions,
};
use image::{load_from_memory, GenericImageView, Pixel};
use keyboard_manager::KeyboardManager;
use mouse_manager::MouseManager;
use renderer::SkiaRenderer;
pub use settings::{KeyboardSettings, WindowSettings};
static ICON: &[u8] = include_bytes!("../../assets/neovide.ico");
const MIN_WINDOW_WIDTH: u64 = 20;
const MIN_WINDOW_HEIGHT: u64 = 6;
pub struct GlutinWindowWrapper {
windowed_context: WindowedContext<glutin::PossiblyCurrent>,
skia_renderer: SkiaRenderer,
renderer: Renderer,
keyboard_manager: KeyboardManager,
mouse_manager: MouseManager,
title: String,
fullscreen: bool,
saved_inner_size: PhysicalSize<u32>,
saved_grid_size: Option<Dimensions>,
ui_command_sender: LoggingTx<UiCommand>,
window_command_receiver: Receiver<WindowCommand>,
}
impl GlutinWindowWrapper {
pub fn toggle_fullscreen(&mut self) {
let window = self.windowed_context.window();
if self.fullscreen {
window.set_fullscreen(None);
} else {
let handle = window.current_monitor();
window.set_fullscreen(Some(Fullscreen::Borderless(handle)));
}
self.fullscreen = !self.fullscreen;
}
pub fn synchronize_settings(&mut self) {
let fullscreen = { SETTINGS.get::<WindowSettings>().fullscreen };
if self.fullscreen != fullscreen {
self.toggle_fullscreen();
}
}
#[allow(clippy::needless_collect)]
pub fn handle_window_commands(&mut self) {
let window_commands: Vec<WindowCommand> = self.window_command_receiver.try_iter().collect();
for window_command in window_commands.into_iter() {
match window_command {
WindowCommand::TitleChanged(new_title) => self.handle_title_changed(new_title),
WindowCommand::SetMouseEnabled(mouse_enabled) => {
self.mouse_manager.enabled = mouse_enabled
}
}
}
}
pub fn handle_title_changed(&mut self, new_title: String) {
self.title = new_title;
self.windowed_context.window().set_title(&self.title);
}
pub fn handle_quit(&mut self) {
if SETTINGS.get::<CmdLineSettings>().remote_tcp.is_none() {
self.ui_command_sender
.send(ParallelCommand::Quit.into())
.expect("Could not send quit command to bridge");
} else {
RUNNING_TRACKER.quit("window closed");
}
}
pub fn handle_focus_lost(&mut self) {
self.ui_command_sender
.send(ParallelCommand::FocusLost.into())
.ok();
}
pub fn handle_focus_gained(&mut self) {
self.ui_command_sender
.send(ParallelCommand::FocusGained.into())
.ok();
REDRAW_SCHEDULER.queue_next_frame();
}
pub fn handle_event(&mut self, event: Event<()>) {
self.keyboard_manager.handle_event(&event);
self.mouse_manager.handle_event(
&event,
&self.keyboard_manager,
&self.renderer,
&self.windowed_context,
);
match event {
Event::LoopDestroyed => {
self.handle_quit();
}
Event::WindowEvent {
event: WindowEvent::CloseRequested,
..
} => {
self.handle_quit();
}
Event::WindowEvent {
event: WindowEvent::ScaleFactorChanged { scale_factor, .. },
..
} => {
self.handle_scale_factor_update(scale_factor);
}
Event::WindowEvent {
event: WindowEvent::DroppedFile(path),
..
} => {
self.ui_command_sender
.send(
ParallelCommand::FileDrop(path.into_os_string().into_string().unwrap())
.into(),
)
.ok();
}
Event::WindowEvent {
event: WindowEvent::Focused(focus),
..
} => {
if focus {
self.handle_focus_gained();
} else {
self.handle_focus_lost();
}
}
Event::RedrawRequested(..) | Event::WindowEvent { .. } => {
REDRAW_SCHEDULER.queue_next_frame()
}
_ => {}
}
}
pub fn draw_frame(&mut self, dt: f32) {
let window = self.windowed_context.window();
let mut font_changed = false;
if REDRAW_SCHEDULER.should_draw() || SETTINGS.get::<WindowSettings>().no_idle {
font_changed = self.renderer.draw_frame(self.skia_renderer.canvas(), dt);
self.skia_renderer.gr_context.flush(None);
self.windowed_context.swap_buffers().unwrap();
}
// Wait until fonts are loaded, so we can set proper window size.
if !self.renderer.grid_renderer.is_ready {
return;
}
let new_size = window.inner_size();
let settings = SETTINGS.get::<CmdLineSettings>();
// Resize at startup happens when window is maximized or when using tiling WM
// which already resized window.
let resized_at_startup = settings.maximized || is_already_resized(new_size);
if self.saved_grid_size.is_none() && !resized_at_startup {
window.set_inner_size(
self.renderer
.grid_renderer
.convert_grid_to_physical(settings.geometry),
);
self.saved_grid_size = Some(settings.geometry);
// Font change at startup is ignored, so grid size (and startup screen) could be preserved.
// But only when not resized yet. With maximized or resized window we should redraw grid.
font_changed = false;
}
if self.saved_inner_size != new_size || font_changed {
self.saved_inner_size = new_size;
self.handle_new_grid_size(new_size);
self.skia_renderer.resize(&self.windowed_context);
}
}
fn handle_new_grid_size(&mut self, new_size: PhysicalSize<u32>) {
let grid_size = self
.renderer
.grid_renderer
.convert_physical_to_grid(new_size);
// Have a minimum size
if grid_size.width < MIN_WINDOW_WIDTH || grid_size.height < MIN_WINDOW_HEIGHT {
return;
}
if self.saved_grid_size == Some(grid_size) {
trace!("Grid matched saved size, skip update.");
return;
}
self.saved_grid_size = Some(grid_size);
self.ui_command_sender
.send(
ParallelCommand::Resize {
width: grid_size.width,
height: grid_size.height,
}
.into(),
)
.ok();
}
fn handle_scale_factor_update(&mut self, scale_factor: f64) {
self.renderer
.grid_renderer
.handle_scale_factor_update(scale_factor);
}
}
pub fn create_window(
batched_draw_command_receiver: Receiver<Vec<DrawCommand>>,
window_command_receiver: Receiver<WindowCommand>,
ui_command_sender: LoggingTx<UiCommand>,
) {
let icon = {
let icon = load_from_memory(ICON).expect("Failed to parse icon data");
let (width, height) = icon.dimensions();
let mut rgba = Vec::with_capacity((width * height) as usize * 4);
for (_, _, pixel) in icon.pixels() {
rgba.extend_from_slice(&pixel.to_rgba().0);
}
Icon::from_rgba(rgba, width, height).expect("Failed to create icon object")
};
let event_loop = EventLoop::new();
let cmd_line_settings = SETTINGS.get::<CmdLineSettings>();
let winit_window_builder = window::WindowBuilder::new()
.with_title("Neovide")
.with_window_icon(Some(icon))
.with_maximized(cmd_line_settings.maximized)
.with_transparent(true)
.with_decorations(!cmd_line_settings.frameless);
#[cfg(target_os = "linux")]
let winit_window_builder = winit_window_builder
.with_app_id(SETTINGS.get::<CmdLineSettings>().wayland_app_id)
.with_class(
"neovide".to_string(),
SETTINGS.get::<CmdLineSettings>().x11_wm_class,
);
let windowed_context = ContextBuilder::new()
.with_pixel_format(24, 8)
.with_stencil_buffer(8)
.with_gl_profile(GlProfile::Core)
.with_vsync(false)
.with_srgb(cmd_line_settings.srgb)
.build_windowed(winit_window_builder, &event_loop)
.unwrap();
let windowed_context = unsafe { windowed_context.make_current().unwrap() };
let window = windowed_context.window();
let scale_factor = windowed_context.window().scale_factor();
let renderer = Renderer::new(batched_draw_command_receiver, scale_factor);
let saved_inner_size = window.inner_size();
let skia_renderer = SkiaRenderer::new(&windowed_context);
log::info!(
"window created (scale_factor: {:.4}, font_dimensions: {:?})",
scale_factor,
renderer.grid_renderer.font_dimensions,
);
let mut window_wrapper = GlutinWindowWrapper {
windowed_context,
skia_renderer,
renderer,
keyboard_manager: KeyboardManager::new(ui_command_sender.clone()),
mouse_manager: MouseManager::new(ui_command_sender.clone()),
title: String::from("Neovide"),
fullscreen: false,
saved_inner_size,
saved_grid_size: None,
ui_command_sender,
window_command_receiver,
};
let mut previous_frame_start = Instant::now();
event_loop.run(move |e, _window_target, control_flow| {
if !RUNNING_TRACKER.is_running() {
maybe_save_window_size(window_wrapper.saved_grid_size);
std::process::exit(0);
}
let frame_start = Instant::now();
window_wrapper.handle_window_commands();
window_wrapper.synchronize_settings();
window_wrapper.handle_event(e);
let refresh_rate = { SETTINGS.get::<WindowSettings>().refresh_rate as f32 };
let expected_frame_length_seconds = 1.0 / refresh_rate;
let frame_duration = Duration::from_secs_f32(expected_frame_length_seconds);
if frame_start - previous_frame_start > frame_duration {
let dt = previous_frame_start.elapsed().as_secs_f32();
window_wrapper.draw_frame(dt);
previous_frame_start = frame_start;
}
*control_flow = ControlFlow::WaitUntil(previous_frame_start + frame_duration)
});
}
fn is_already_resized(size: PhysicalSize<u32>) -> bool {
size != PhysicalSize::from((800, 600))
}

@ -1,349 +0,0 @@
mod keyboard_manager;
mod mouse_manager;
mod renderer;
use std::{
sync::mpsc::Receiver,
time::{Duration, Instant},
};
use glutin::{
self,
dpi::PhysicalSize,
event::{Event, WindowEvent},
event_loop::{ControlFlow, EventLoop},
window::{self, Fullscreen, Icon},
ContextBuilder, GlProfile, WindowedContext,
};
use log::trace;
#[cfg(target_os = "linux")]
use glutin::platform::unix::WindowBuilderExtUnix;
use super::settings::WindowSettings;
use crate::{
bridge::{ParallelCommand, UiCommand},
channel_utils::*,
cmd_line::CmdLineSettings,
editor::DrawCommand,
editor::WindowCommand,
redraw_scheduler::REDRAW_SCHEDULER,
renderer::Renderer,
running_tracker::*,
settings::{maybe_save_window_size, SETTINGS},
utils::Dimensions,
};
use image::{load_from_memory, GenericImageView, Pixel};
use keyboard_manager::KeyboardManager;
use mouse_manager::MouseManager;
use renderer::SkiaRenderer;
static ICON: &[u8] = include_bytes!("../../../assets/neovide.ico");
const MIN_WINDOW_WIDTH: u64 = 20;
const MIN_WINDOW_HEIGHT: u64 = 6;
pub struct GlutinWindowWrapper {
windowed_context: WindowedContext<glutin::PossiblyCurrent>,
skia_renderer: SkiaRenderer,
renderer: Renderer,
keyboard_manager: KeyboardManager,
mouse_manager: MouseManager,
title: String,
fullscreen: bool,
saved_inner_size: PhysicalSize<u32>,
saved_grid_size: Option<Dimensions>,
ui_command_sender: LoggingTx<UiCommand>,
window_command_receiver: Receiver<WindowCommand>,
}
impl GlutinWindowWrapper {
pub fn toggle_fullscreen(&mut self) {
let window = self.windowed_context.window();
if self.fullscreen {
window.set_fullscreen(None);
} else {
let handle = window.current_monitor();
window.set_fullscreen(Some(Fullscreen::Borderless(handle)));
}
self.fullscreen = !self.fullscreen;
}
pub fn synchronize_settings(&mut self) {
let fullscreen = { SETTINGS.get::<WindowSettings>().fullscreen };
if self.fullscreen != fullscreen {
self.toggle_fullscreen();
}
}
#[allow(clippy::needless_collect)]
pub fn handle_window_commands(&mut self) {
let window_commands: Vec<WindowCommand> = self.window_command_receiver.try_iter().collect();
for window_command in window_commands.into_iter() {
match window_command {
WindowCommand::TitleChanged(new_title) => self.handle_title_changed(new_title),
WindowCommand::SetMouseEnabled(mouse_enabled) => {
self.mouse_manager.enabled = mouse_enabled
}
}
}
}
pub fn handle_title_changed(&mut self, new_title: String) {
self.title = new_title;
self.windowed_context.window().set_title(&self.title);
}
pub fn handle_quit(&mut self) {
if SETTINGS.get::<CmdLineSettings>().remote_tcp.is_none() {
self.ui_command_sender
.send(ParallelCommand::Quit.into())
.expect("Could not send quit command to bridge");
} else {
RUNNING_TRACKER.quit("window closed");
}
}
pub fn handle_focus_lost(&mut self) {
self.ui_command_sender
.send(ParallelCommand::FocusLost.into())
.ok();
}
pub fn handle_focus_gained(&mut self) {
self.ui_command_sender
.send(ParallelCommand::FocusGained.into())
.ok();
REDRAW_SCHEDULER.queue_next_frame();
}
pub fn handle_event(&mut self, event: Event<()>) {
self.keyboard_manager.handle_event(&event);
self.mouse_manager.handle_event(
&event,
&self.keyboard_manager,
&self.renderer,
&self.windowed_context,
);
match event {
Event::LoopDestroyed => {
self.handle_quit();
}
Event::WindowEvent {
event: WindowEvent::CloseRequested,
..
} => {
self.handle_quit();
}
Event::WindowEvent {
event: WindowEvent::ScaleFactorChanged { scale_factor, .. },
..
} => {
self.handle_scale_factor_update(scale_factor);
}
Event::WindowEvent {
event: WindowEvent::DroppedFile(path),
..
} => {
self.ui_command_sender
.send(
ParallelCommand::FileDrop(path.into_os_string().into_string().unwrap())
.into(),
)
.ok();
}
Event::WindowEvent {
event: WindowEvent::Focused(focus),
..
} => {
if focus {
self.handle_focus_gained();
} else {
self.handle_focus_lost();
}
}
Event::RedrawRequested(..) | Event::WindowEvent { .. } => {
REDRAW_SCHEDULER.queue_next_frame()
}
_ => {}
}
}
pub fn draw_frame(&mut self, dt: f32) {
let window = self.windowed_context.window();
let mut font_changed = false;
if REDRAW_SCHEDULER.should_draw() || SETTINGS.get::<WindowSettings>().no_idle {
font_changed = self.renderer.draw_frame(self.skia_renderer.canvas(), dt);
self.skia_renderer.gr_context.flush(None);
self.windowed_context.swap_buffers().unwrap();
}
// Wait until fonts are loaded, so we can set proper window size.
if !self.renderer.grid_renderer.is_ready {
return;
}
let new_size = window.inner_size();
let settings = SETTINGS.get::<CmdLineSettings>();
// Resize at startup happens when window is maximized or when using tiling WM
// which already resized window.
let resized_at_startup = settings.maximized || is_already_resized(new_size);
if self.saved_grid_size.is_none() && !resized_at_startup {
window.set_inner_size(
self.renderer
.grid_renderer
.convert_grid_to_physical(settings.geometry),
);
self.saved_grid_size = Some(settings.geometry);
// Font change at startup is ignored, so grid size (and startup screen) could be preserved.
// But only when not resized yet. With maximized or resized window we should redraw grid.
font_changed = false;
}
if self.saved_inner_size != new_size || font_changed {
self.saved_inner_size = new_size;
self.handle_new_grid_size(new_size);
self.skia_renderer.resize(&self.windowed_context);
}
}
fn handle_new_grid_size(&mut self, new_size: PhysicalSize<u32>) {
let grid_size = self
.renderer
.grid_renderer
.convert_physical_to_grid(new_size);
// Have a minimum size
if grid_size.width < MIN_WINDOW_WIDTH || grid_size.height < MIN_WINDOW_HEIGHT {
return;
}
if self.saved_grid_size == Some(grid_size) {
trace!("Grid matched saved size, skip update.");
return;
}
self.saved_grid_size = Some(grid_size);
self.ui_command_sender
.send(
ParallelCommand::Resize {
width: grid_size.width,
height: grid_size.height,
}
.into(),
)
.ok();
}
fn handle_scale_factor_update(&mut self, scale_factor: f64) {
self.renderer
.grid_renderer
.handle_scale_factor_update(scale_factor);
}
}
pub fn create_window(
batched_draw_command_receiver: Receiver<Vec<DrawCommand>>,
window_command_receiver: Receiver<WindowCommand>,
ui_command_sender: LoggingTx<UiCommand>,
) {
let icon = {
let icon = load_from_memory(ICON).expect("Failed to parse icon data");
let (width, height) = icon.dimensions();
let mut rgba = Vec::with_capacity((width * height) as usize * 4);
for (_, _, pixel) in icon.pixels() {
rgba.extend_from_slice(&pixel.to_rgba().0);
}
Icon::from_rgba(rgba, width, height).expect("Failed to create icon object")
};
let event_loop = EventLoop::new();
let cmd_line_settings = SETTINGS.get::<CmdLineSettings>();
let winit_window_builder = window::WindowBuilder::new()
.with_title("Neovide")
.with_window_icon(Some(icon))
.with_maximized(cmd_line_settings.maximized)
.with_transparent(true)
.with_decorations(!cmd_line_settings.frameless);
#[cfg(target_os = "linux")]
let winit_window_builder = winit_window_builder
.with_app_id(SETTINGS.get::<CmdLineSettings>().wayland_app_id)
.with_class(
"neovide".to_string(),
SETTINGS.get::<CmdLineSettings>().x11_wm_class,
);
let windowed_context = ContextBuilder::new()
.with_pixel_format(24, 8)
.with_stencil_buffer(8)
.with_gl_profile(GlProfile::Core)
.with_vsync(false)
.with_srgb(cmd_line_settings.srgb)
.build_windowed(winit_window_builder, &event_loop)
.unwrap();
let windowed_context = unsafe { windowed_context.make_current().unwrap() };
let window = windowed_context.window();
let scale_factor = windowed_context.window().scale_factor();
let renderer = Renderer::new(batched_draw_command_receiver, scale_factor);
let saved_inner_size = window.inner_size();
let skia_renderer = SkiaRenderer::new(&windowed_context);
log::info!(
"window created (scale_factor: {:.4}, font_dimensions: {:?})",
scale_factor,
renderer.grid_renderer.font_dimensions,
);
let mut window_wrapper = GlutinWindowWrapper {
windowed_context,
skia_renderer,
renderer,
keyboard_manager: KeyboardManager::new(ui_command_sender.clone()),
mouse_manager: MouseManager::new(ui_command_sender.clone()),
title: String::from("Neovide"),
fullscreen: false,
saved_inner_size,
saved_grid_size: None,
ui_command_sender,
window_command_receiver,
};
let mut previous_frame_start = Instant::now();
event_loop.run(move |e, _window_target, control_flow| {
if !RUNNING_TRACKER.is_running() {
maybe_save_window_size(window_wrapper.saved_grid_size);
std::process::exit(0);
}
let frame_start = Instant::now();
window_wrapper.handle_window_commands();
window_wrapper.synchronize_settings();
window_wrapper.handle_event(e);
let refresh_rate = { SETTINGS.get::<WindowSettings>().refresh_rate as f32 };
let expected_frame_length_seconds = 1.0 / refresh_rate;
let frame_duration = Duration::from_secs_f32(expected_frame_length_seconds);
if frame_start - previous_frame_start > frame_duration {
let dt = previous_frame_start.elapsed().as_secs_f32();
window_wrapper.draw_frame(dt);
previous_frame_start = frame_start;
}
*control_flow = ControlFlow::WaitUntil(previous_frame_start + frame_duration)
});
}
fn is_already_resized(size: PhysicalSize<u32>) -> bool {
size != PhysicalSize::from((800, 600))
}
Loading…
Cancel
Save