mirror of https://github.com/sgoudham/neovide.git
move window files into main window directory rather than being window wrapper
parent
b78a714be0
commit
6b96f79bb1
@ -1,5 +1,351 @@
|
||||
mod keyboard_manager;
|
||||
mod mouse_manager;
|
||||
mod renderer;
|
||||
mod settings;
|
||||
mod window_wrapper;
|
||||
|
||||
pub use settings::*;
|
||||
pub use window_wrapper::create_window;
|
||||
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 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…
Reference in New Issue