refactor window event handling to be more organized

macos-click-through
keith 5 years ago
parent b33327d951
commit ff67afaa46

@ -4,9 +4,11 @@ use std::thread::sleep;
use log::{info, trace, debug, error}; use log::{info, trace, debug, error};
use skulpin::{LogicalSize, PhysicalSize}; use skulpin::{LogicalSize, PhysicalSize};
use skulpin::sdl2; use skulpin::sdl2;
use skulpin::sdl2::Sdl;
use skulpin::sdl2::video::Window;
use skulpin::sdl2::event::Event; use skulpin::sdl2::event::Event;
use skulpin::sdl2::keyboard::Mod; use skulpin::sdl2::keyboard::{Mod, Keycode};
use skulpin::{RendererBuilder, PresentMode, CoordinateSystem, dpis}; use skulpin::{RendererBuilder, Renderer as SkulpinRenderer, PresentMode, CoordinateSystem, dpis};
use crate::bridge::{parse_keycode, append_modifiers, BRIDGE, UiCommand}; use crate::bridge::{parse_keycode, append_modifiers, BRIDGE, UiCommand};
use crate::renderer::Renderer; use crate::renderer::Renderer;
@ -37,184 +39,245 @@ fn handle_new_grid_size(new_size: LogicalSize, renderer: &Renderer) {
} }
} }
pub fn ui_loop() { struct WindowWrapper {
let sdl_context = sdl2::init().expect("Failed to initialize sdl2"); context: Sdl,
let video_subsystem = sdl_context.video().expect("Failed to create sdl video subsystem"); window: Window,
skulpin_renderer: SkulpinRenderer,
let (width, height) = INITIAL_DIMENSIONS; renderer: Renderer,
mouse_down: bool,
let mut renderer = Renderer::new(); mouse_position: LogicalSize,
let logical_size = LogicalSize { title: String,
width: (width as f32 * renderer.font_width) as u32, previous_size: LogicalSize,
height: (height as f32 * renderer.font_height + 1.0) as u32 previous_dpis: (f32, f32),
}; ignore_text_input: bool
}
// let icon = {
// let icon_data = Asset::get("nvim.ico").expect("Failed to read icon data");
// let icon = load_from_memory(&icon_data).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")
// };
// info!("icon created");
#[cfg(target_os = "windows")]
windows_fix_dpi();
sdl2::hint::set("SDL_MOUSE_FOCUS_CLICKTHROUGH", "1");
let mut window = video_subsystem.window("Neovide", logical_size.width, logical_size.height)
.position_centered()
.allow_highdpi()
.resizable()
.vulkan()
.build()
.expect("Failed to create window");
info!("window created");
let mut skulpin_renderer = RendererBuilder::new()
.prefer_integrated_gpu()
.use_vulkan_debug_layer(true)
.present_mode_priority(vec![PresentMode::Immediate])
.coordinate_system(CoordinateSystem::Logical)
.build(&window)
.expect("Failed to create renderer");
info!("renderer created");
let mut mouse_down = false;
let mut mouse_position = LogicalSize {
width: 0,
height: 0
};
let mut title = "Neovide".to_string();
let mut previous_size = LogicalSize::new(&window).unwrap();
let mut previous_dpis = dpis(&window).unwrap();
info!("Starting window event loop"); impl WindowWrapper {
let mut event_pump = sdl_context.event_pump().expect("Could not create sdl event pump"); pub fn new() -> WindowWrapper {
'running: loop { let context = sdl2::init().expect("Failed to initialize sdl2");
let frame_start = Instant::now(); let video_subsystem = context.video().expect("Failed to create sdl video subsystem");
let (width, height) = INITIAL_DIMENSIONS;
let renderer = Renderer::new();
let logical_size = LogicalSize {
width: (width as f32 * renderer.font_width) as u32,
height: (height as f32 * renderer.font_height + 1.0) as u32
};
#[cfg(target_os = "windows")]
windows_fix_dpi();
sdl2::hint::set("SDL_MOUSE_FOCUS_CLICKTHROUGH", "1");
// let icon = {
// let icon_data = Asset::get("nvim.ico").expect("Failed to read icon data");
// let icon = load_from_memory(&icon_data).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")
// };
// info!("icon created");
let window = video_subsystem.window("Neovide", logical_size.width, logical_size.height)
.position_centered()
.allow_highdpi()
.resizable()
.vulkan()
.build()
.expect("Failed to create window");
info!("window created");
let skulpin_renderer = RendererBuilder::new()
.prefer_integrated_gpu()
.use_vulkan_debug_layer(true)
.present_mode_priority(vec![PresentMode::Immediate])
.coordinate_system(CoordinateSystem::Logical)
.build(&window)
.expect("Failed to create renderer");
info!("renderer created");
let previous_size = LogicalSize::new(&window).unwrap();
let previous_dpis = dpis(&window).unwrap();
WindowWrapper {
context, window, skulpin_renderer, renderer,
mouse_down: false,
mouse_position: LogicalSize {
width: 0,
height: 0
},
title: String::from("Neovide"),
previous_size,
previous_dpis,
ignore_text_input: false
}
}
pub fn synchronize_title(&mut self) {
let editor_title = { EDITOR.lock().title.clone() }; let editor_title = { EDITOR.lock().title.clone() };
if title != editor_title { if self.title != editor_title {
title = editor_title; self.title = editor_title;
window.set_title(&title).expect("Could not set title"); self.window.set_title(&self.title).expect("Could not set title");
} }
}
let mut ignore_text_input = false; pub fn handle_key_down(&mut self, keycode: Keycode, modifiers: Mod) {
for event in event_pump.poll_iter() { trace!("KeyDown Received: {}", keycode);
match event { if let Some((key_text, special)) = parse_keycode(keycode) {
Event::Quit {..} => break 'running, let will_text_input =
Event::Window {..} => REDRAW_SCHEDULER.queue_next_frame(), !modifiers.contains(Mod::LCTRLMOD) &&
Event::KeyDown { keycode: Some(keycode), keymod: modifiers, .. } => { !modifiers.contains(Mod::RCTRLMOD) &&
trace!("KeyDown Received: {}", keycode); !modifiers.contains(Mod::LALTMOD) &&
if let Some((key_text, special)) = parse_keycode(keycode) { !modifiers.contains(Mod::RALTMOD) &&
let will_text_input = !modifiers.contains(Mod::LGUIMOD) &&
!modifiers.contains(Mod::RGUIMOD);
!modifiers.contains(Mod::LCTRLMOD) && if modifiers.contains(Mod::MODEMOD) || (will_text_input && !special) {
!modifiers.contains(Mod::RCTRLMOD) && self.ignore_text_input = false;
!modifiers.contains(Mod::LALTMOD) && return;
!modifiers.contains(Mod::RALTMOD) &&
!modifiers.contains(Mod::LGUIMOD) &&
!modifiers.contains(Mod::RGUIMOD);
if will_text_input && !special {
break;
}
BRIDGE.queue_command(UiCommand::Keyboard(append_modifiers(modifiers, key_text, special)));
ignore_text_input = true;
}
},
Event::TextInput { text, .. } => {
trace!("Keyboard Input Received: {}", &text);
if ignore_text_input {
ignore_text_input = false;
} else {
let text = if text == "<" {
String::from("<lt>")
} else {
text
};
BRIDGE.queue_command(UiCommand::Keyboard(text))
}
},
Event::MouseMotion { x, y, .. } => {
let previous_position = mouse_position;
mouse_position = LogicalSize::from_physical_size_tuple((
(x as f32 / renderer.font_width) as u32,
(y as f32 / renderer.font_height) as u32
),
&window
).expect("Could not calculate logical mouse position");
if mouse_down && previous_position != mouse_position {
BRIDGE.queue_command(UiCommand::Drag(mouse_position.width, mouse_position.height));
}
},
Event::MouseButtonDown { .. } => {
BRIDGE.queue_command(UiCommand::MouseButton { action: String::from("press"), position: (mouse_position.width, mouse_position.height) });
mouse_down = true;
},
Event::MouseButtonUp { .. } => {
BRIDGE.queue_command(UiCommand::MouseButton { action: String::from("release"), position: (mouse_position.width, mouse_position.height) });
mouse_down = false;
},
Event::MouseWheel { x, y, .. } => {
let vertical_input_type = if y > 0 {
Some("up")
} else if y < 0 {
Some("down")
} else {
None
};
if let Some(input_type) = vertical_input_type {
BRIDGE.queue_command(UiCommand::Scroll { direction: input_type.to_string(), position: (mouse_position.width, mouse_position.height) });
}
let horizontal_input_type = if x > 0 {
Some("right")
} else if x < 0 {
Some("left")
} else {
None
};
if let Some(input_type) = horizontal_input_type {
BRIDGE.queue_command(UiCommand::Scroll { direction: input_type.to_string(), position: (mouse_position.width, mouse_position.height) });
}
},
_ => {}
} }
BRIDGE.queue_command(UiCommand::Keyboard(append_modifiers(modifiers, key_text, special)));
self.ignore_text_input = true;
} }
}
let new_size = LogicalSize::new(&window).unwrap(); pub fn handle_text_input(&mut self, text: String) {
if previous_size != new_size { trace!("Keyboard Input Received: {}", &text);
handle_new_grid_size(new_size, &renderer); if self.ignore_text_input {
previous_size = new_size; self.ignore_text_input = false;
} else {
let text = if text == "<" {
String::from("<lt>")
} else {
text
};
BRIDGE.queue_command(UiCommand::Keyboard(text))
} }
}
let new_dpis = dpis(&window).unwrap(); pub fn handle_pointer_motion(&mut self, x: i32, y: i32) {
if previous_dpis != new_dpis { let previous_position = self.mouse_position;
let physical_size = PhysicalSize::new(&window); self.mouse_position = LogicalSize::from_physical_size_tuple((
window.set_size( (x as f32 / self.renderer.font_width) as u32,
(physical_size.width as f32 * new_dpis.0 / previous_dpis.0) as u32, (y as f32 / self.renderer.font_height) as u32
(physical_size.height as f32 * new_dpis.1 / previous_dpis.1) as u32).unwrap(); ),
previous_dpis = new_dpis; &self.window
).expect("Could not calculate logical mouse position");
if self.mouse_down && previous_position != self.mouse_position {
BRIDGE.queue_command(UiCommand::Drag(self.mouse_position.width, self.mouse_position.height));
}
}
pub fn handle_pointer_down(&mut self) {
BRIDGE.queue_command(UiCommand::MouseButton {
action: String::from("press"),
position: (self.mouse_position.width, self.mouse_position.height)
});
self.mouse_down = true;
}
pub fn handle_pointer_up(&mut self) {
BRIDGE.queue_command(UiCommand::MouseButton {
action: String::from("release"),
position: (self.mouse_position.width, self.mouse_position.height)
});
self.mouse_down = false;
}
pub fn handle_mouse_wheel(&mut self, x: i32, y: i32) {
let vertical_input_type = if y > 0 {
Some("up")
} else if y < 0 {
Some("down")
} else {
None
};
if let Some(input_type) = vertical_input_type {
BRIDGE.queue_command(UiCommand::Scroll {
direction: input_type.to_string(),
position: (self.mouse_position.width, self.mouse_position.height)
});
}
let horizontal_input_type = if x > 0 {
Some("right")
} else if x < 0 {
Some("left")
} else {
None
};
if let Some(input_type) = horizontal_input_type {
BRIDGE.queue_command(UiCommand::Scroll {
direction: input_type.to_string(),
position: (self.mouse_position.width, self.mouse_position.height)
});
}
}
pub fn draw_frame(&mut self) -> bool {
let new_size = LogicalSize::new(&self.window).unwrap();
if self.previous_size != new_size {
handle_new_grid_size(new_size, &self.renderer);
self.previous_size = new_size;
}
let new_dpis = dpis(&self.window).unwrap();
if self.previous_dpis != new_dpis {
let physical_size = PhysicalSize::new(&self.window);
self.window.set_size(
(physical_size.width as f32 * new_dpis.0 / self.previous_dpis.0) as u32,
(physical_size.height as f32 * new_dpis.1 / self.previous_dpis.1) as u32).unwrap();
self.previous_dpis = new_dpis;
} }
debug!("Render Triggered"); debug!("Render Triggered");
if REDRAW_SCHEDULER.should_draw() || SETTINGS.get("no_idle").read_bool() { if REDRAW_SCHEDULER.should_draw() || SETTINGS.get("no_idle").read_bool() {
if skulpin_renderer.draw(&window, |canvas, coordinate_system_helper| { let renderer = &mut self.renderer;
if self.skulpin_renderer.draw(&self.window, |canvas, coordinate_system_helper| {
if renderer.draw(canvas, coordinate_system_helper) { if renderer.draw(canvas, coordinate_system_helper) {
handle_new_grid_size(new_size, &renderer) handle_new_grid_size(new_size, &renderer)
} }
}).is_err() { }).is_err() {
error!("Render failed. Closing"); error!("Render failed. Closing");
break; return false;
} }
} }
return true;
}
}
pub fn ui_loop() {
let mut window = WindowWrapper::new();
info!("Starting window event loop");
let mut event_pump = window.context.event_pump().expect("Could not create sdl event pump");
'running: loop {
let frame_start = Instant::now();
window.synchronize_title();
for event in event_pump.poll_iter() {
match event {
Event::Quit {..} => break 'running,
Event::Window {..} => REDRAW_SCHEDULER.queue_next_frame(),
Event::KeyDown { keycode: Some(keycode), keymod: modifiers, .. } => window.handle_key_down(keycode, modifiers),
Event::TextInput { text, .. } => window.handle_text_input(text),
Event::MouseMotion { x, y, .. } => window.handle_pointer_motion(x, y),
Event::MouseButtonDown { .. } => window.handle_pointer_down(),
Event::MouseButtonUp { .. } => window.handle_pointer_up(),
Event::MouseWheel { x, y, .. } => window.handle_mouse_wheel(x, y),
_ => {}
}
}
if !window.draw_frame() {
break;
}
let elapsed = frame_start.elapsed(); let elapsed = frame_start.elapsed();
let refresh_rate = SETTINGS.get("refresh_rate").read_u16() as f32; let refresh_rate = SETTINGS.get("refresh_rate").read_u16() as f32;

Loading…
Cancel
Save