From cb0f92688d28177ca0953788d807f84f18a6838a Mon Sep 17 00:00:00 2001 From: Keith Simmons Date: Wed, 29 Sep 2021 15:51:54 -0700 Subject: [PATCH] split ui command into serial and parallel --- src/bridge/handler.rs | 6 +- src/bridge/mod.rs | 28 +-- src/bridge/ui_commands.rs | 161 ++++++++++++++---- src/window/window_wrapper/keyboard_manager.rs | 4 +- src/window/window_wrapper/mod.rs | 16 +- src/window/window_wrapper/mouse_manager.rs | 32 +++- 6 files changed, 175 insertions(+), 72 deletions(-) diff --git a/src/bridge/handler.rs b/src/bridge/handler.rs index ad646b1..3885f32 100644 --- a/src/bridge/handler.rs +++ b/src/bridge/handler.rs @@ -8,7 +8,7 @@ use rmpv::Value; use tokio::task; use super::events::{parse_redraw_event, RedrawEvent}; -use super::ui_commands::UiCommand; +use super::ui_commands::{ParallelCommand, UiCommand}; use crate::bridge::TxWrapper; use crate::channel_utils::*; use crate::error_handling::ResultPanicExplanation; @@ -66,12 +66,12 @@ impl Handler for NeovimHandler { #[cfg(windows)] "neovide.register_right_click" => { let ui_command_sender = ui_command_sender.lock(); - ui_command_sender.send(UiCommand::RegisterRightClick).ok(); + ui_command_sender.send(ParallelCommand::RegisterRightClick.into()).ok(); } #[cfg(windows)] "neovide.unregister_right_click" => { let ui_command_sender = ui_command_sender.lock(); - ui_command_sender.send(UiCommand::UnregisterRightClick).ok(); + ui_command_sender.send(ParallelCommand::UnregisterRightClick.into()).ok(); } _ => {} }); diff --git a/src/bridge/mod.rs b/src/bridge/mod.rs index a095bf9..e40eecd 100644 --- a/src/bridge/mod.rs +++ b/src/bridge/mod.rs @@ -22,7 +22,7 @@ use crate::{cmd_line::CmdLineSettings, error_handling::ResultPanicExplanation}; pub use events::*; use handler::NeovimHandler; pub use tx_wrapper::{TxWrapper, WrapTx}; -pub use ui_commands::UiCommand; +pub use ui_commands::{UiCommand, SerialCommand, ParallelCommand, start_ui_command_handler}; #[cfg(windows)] fn set_windows_creation_flags(cmd: &mut Command) { @@ -156,7 +156,7 @@ fn connection_mode() -> ConnectionMode { async fn start_neovim_runtime( ui_command_sender: LoggingTx, - mut ui_command_receiver: UnboundedReceiver, + ui_command_receiver: UnboundedReceiver, redraw_event_sender: LoggingTx, running: Arc, ) { @@ -284,29 +284,7 @@ async fn start_neovim_runtime( let nvim = Arc::new(nvim); - let ui_command_running = running.clone(); - let input_nvim = nvim.clone(); - tokio::spawn(async move { - loop { - if !ui_command_running.load(Ordering::Relaxed) { - break; - } - - match ui_command_receiver.recv().await { - Some(ui_command) => { - let input_nvim = input_nvim.clone(); - tokio::spawn(async move { - ui_command.execute(&input_nvim).await; - }); - } - None => { - ui_command_running.store(false, Ordering::Relaxed); - break; - } - } - } - }); - + start_ui_command_handler(running.clone(), ui_command_receiver, nvim.clone()); SETTINGS.read_initial_values(&nvim).await; SETTINGS.setup_changed_listeners(&nvim).await; } diff --git a/src/bridge/ui_commands.rs b/src/bridge/ui_commands.rs index bb44216..a5ca55f 100644 --- a/src/bridge/ui_commands.rs +++ b/src/bridge/ui_commands.rs @@ -1,24 +1,32 @@ -use log::trace; +use std::sync::{ + Arc, + atomic::{ + AtomicBool, + Ordering, + }, +}; +use log::trace; #[cfg(windows)] use log::error; use nvim_rs::Neovim; +use tokio::sync::mpsc::{ + unbounded_channel, + UnboundedReceiver, + UnboundedSender, +}; use crate::bridge::TxWrapper; - #[cfg(windows)] use crate::windows_utils::{ register_rightclick_directory, register_rightclick_file, unregister_rightclick, }; +// Serial commands are any commands which must complete before the next value is sent. This +// includes keyboard and mouse input which would cuase problems if sent out of order. #[derive(Debug, Clone)] -pub enum UiCommand { - Quit, - Resize { - width: u64, - height: u64, - }, +pub enum SerialCommand { Keyboard(String), MouseButton { button: String, @@ -39,30 +47,16 @@ pub enum UiCommand { position: (u32, u32), modifier_string: String, }, - FileDrop(String), - FocusLost, - FocusGained, - #[cfg(windows)] - RegisterRightClick, - #[cfg(windows)] - UnregisterRightClick, } -impl UiCommand { - pub async fn execute(self, nvim: &Neovim) { +impl SerialCommand { + async fn execute(self, nvim: &Neovim) { match self { - UiCommand::Quit => { - nvim.command("qa!").await.ok(); - } - UiCommand::Resize { width, height } => nvim - .ui_try_resize(width.max(10) as i64, height.max(3) as i64) - .await - .expect("Resize failed"), - UiCommand::Keyboard(input_command) => { + SerialCommand::Keyboard(input_command) => { trace!("Keyboard Input Sent: {}", input_command); nvim.input(&input_command).await.expect("Input failed"); } - UiCommand::MouseButton { + SerialCommand::MouseButton { button, action, grid_id, @@ -80,7 +74,7 @@ impl UiCommand { .await .expect("Mouse Input Failed"); } - UiCommand::Scroll { + SerialCommand::Scroll { direction, grid_id, position: (grid_x, grid_y), @@ -97,8 +91,12 @@ impl UiCommand { .await .expect("Mouse Scroll Failed"); } +<<<<<<< Updated upstream UiCommand::Drag { button, +======= + SerialCommand::Drag { +>>>>>>> Stashed changes grid_id, position: (grid_x, grid_y), modifier_string, @@ -114,19 +112,49 @@ impl UiCommand { .await .expect("Mouse Drag Failed"); } - UiCommand::FocusLost => nvim + } + } +} + +#[derive(Debug, Clone)] +pub enum ParallelCommand { + Quit, + Resize { + width: u64, + height: u64, + }, + FileDrop(String), + FocusLost, + FocusGained, + #[cfg(windows)] + RegisterRightClick, + #[cfg(windows)] + UnregisterRightClick, +} + +impl ParallelCommand { + async fn execute(self, nvim: &Neovim) { + match self { + ParallelCommand::Quit => { + nvim.command("qa!").await.ok(); + } + ParallelCommand::Resize { width, height } => nvim + .ui_try_resize(width.max(10) as i64, height.max(3) as i64) + .await + .expect("Resize failed"), + ParallelCommand::FocusLost => nvim .command("if exists('#FocusLost') | doautocmd FocusLost | endif") .await .expect("Focus Lost Failed"), - UiCommand::FocusGained => nvim + ParallelCommand::FocusGained => nvim .command("if exists('#FocusGained') | doautocmd FocusGained | endif") .await .expect("Focus Gained Failed"), - UiCommand::FileDrop(path) => { + ParallelCommand::FileDrop(path) => { nvim.command(format!("e {}", path).as_str()).await.ok(); } #[cfg(windows)] - UiCommand::RegisterRightClick => { + ParallelCommand::RegisterRightClick => { if unregister_rightclick() { let msg = "Could not unregister previous menu item. Possibly already registered or not running as Admin?"; nvim.err_writeln(msg).await.ok(); @@ -144,7 +172,7 @@ impl UiCommand { } } #[cfg(windows)] - UiCommand::UnregisterRightClick => { + ParallelCommand::UnregisterRightClick => { if !unregister_rightclick() { let msg = "Could not remove context menu items. Possibly already removed or not running as Admin?"; nvim.err_writeln(msg).await.ok(); @@ -154,3 +182,72 @@ impl UiCommand { } } } + + +#[derive(Debug, Clone)] +pub enum UiCommand { + Serial(SerialCommand), + Parallel(ParallelCommand), +} + +impl From for UiCommand { + fn from(serial: SerialCommand) -> Self { + UiCommand::Serial(serial) + } +} + +impl From for UiCommand { + fn from(parallel: ParallelCommand) -> Self { + UiCommand::Parallel(parallel) + } +} + +pub fn start_ui_command_handler(running: Arc, mut ui_command_receiver: UnboundedReceiver, nvim: Arc>) { + let serial_tx = start_serial_command_handler(running, nvim); + + tokio::spawn(async move { + loop { + if !running.load(Ordering::Relaxed) { + break; + } + + match ui_command_receiver.recv().await { + Some(UiCommand::Serial(serial_command)) => + serial_tx.send(serial_command).expect("Could not send serial ui command"), + Some(UiCommand::Parallel(parallel_command)) => { + let nvim = nvim.clone(); + tokio::spawn(async move { + parallel_command.execute(&nvim).await; + }); + } + None => { + running.store(false, Ordering::Relaxed); + break; + } + } + } + }); +} + +pub fn start_serial_command_handler(running: Arc, nvim: Arc>) -> UnboundedSender { + let (serial_tx, serial_rx) = unbounded_channel::(); + tokio::spawn(async move { + loop { + if !running.load(Ordering::Relaxed) { + break; + } + + match serial_rx.recv().await { + Some(serial_command) => { + serial_command.execute(&nvim).await; + }, + None => { + running.store(false, Ordering::Relaxed); + break; + }, + } + } + }); + + serial_tx +} diff --git a/src/window/window_wrapper/keyboard_manager.rs b/src/window/window_wrapper/keyboard_manager.rs index cbdaa03..01803f7 100644 --- a/src/window/window_wrapper/keyboard_manager.rs +++ b/src/window/window_wrapper/keyboard_manager.rs @@ -3,7 +3,7 @@ use glutin::keyboard::Key; use winit::platform::modifier_supplement::KeyEventExtModifierSupplement; -use crate::bridge::UiCommand; +use crate::bridge::{SerialCommand, UiCommand}; use crate::channel_utils::LoggingTx; use crate::settings::SETTINGS; use crate::window::KeyboardSettings; @@ -74,7 +74,7 @@ impl KeyboardManager { if key_event.state == ElementState::Pressed { if let Some(keybinding) = self.maybe_get_keybinding(key_event) { self.command_sender - .send(UiCommand::Keyboard(keybinding)) + .send(SerialCommand::Keyboard(keybinding).into()) .expect("Could not send keyboard ui command"); } } diff --git a/src/window/window_wrapper/mod.rs b/src/window/window_wrapper/mod.rs index 5d736a0..6623dfc 100644 --- a/src/window/window_wrapper/mod.rs +++ b/src/window/window_wrapper/mod.rs @@ -26,7 +26,7 @@ use glutin::platform::unix::WindowBuilderExtUnix; use super::settings::WindowSettings; use crate::{ - bridge::UiCommand, + bridge::{ParallelCommand, UiCommand}, channel_utils::*, cmd_line::CmdLineSettings, editor::DrawCommand, @@ -102,7 +102,7 @@ impl GlutinWindowWrapper { pub fn handle_quit(&mut self, running: &Arc) { if SETTINGS.get::().remote_tcp.is_none() { self.ui_command_sender - .send(UiCommand::Quit) + .send(ParallelCommand::Quit.into()) .expect("Could not send quit command to bridge"); } else { running.store(false, Ordering::Relaxed); @@ -110,11 +110,11 @@ impl GlutinWindowWrapper { } pub fn handle_focus_lost(&mut self) { - self.ui_command_sender.send(UiCommand::FocusLost).ok(); + self.ui_command_sender.send(ParallelCommand::FocusLost.into()).ok(); } pub fn handle_focus_gained(&mut self) { - self.ui_command_sender.send(UiCommand::FocusGained).ok(); + self.ui_command_sender.send(ParallelCommand::FocusGained.into()).ok(); REDRAW_SCHEDULER.queue_next_frame(); } @@ -147,9 +147,9 @@ impl GlutinWindowWrapper { .. } => { self.ui_command_sender - .send(UiCommand::FileDrop( + .send(ParallelCommand::FileDrop( path.into_os_string().into_string().unwrap(), - )) + ).into()) .ok(); } Event::WindowEvent { @@ -224,10 +224,10 @@ impl GlutinWindowWrapper { } self.saved_grid_size = Some(grid_size); self.ui_command_sender - .send(UiCommand::Resize { + .send(ParallelCommand::Resize { width: grid_size.width, height: grid_size.height, - }) + }.into()) .ok(); } diff --git a/src/window/window_wrapper/mouse_manager.rs b/src/window/window_wrapper/mouse_manager.rs index 7a8f81e..332e10e 100644 --- a/src/window/window_wrapper/mouse_manager.rs +++ b/src/window/window_wrapper/mouse_manager.rs @@ -8,8 +8,12 @@ use glutin::{ }; use skia_safe::Rect; +<<<<<<< Updated upstream use super::keyboard_manager::KeyboardManager; use crate::bridge::UiCommand; +======= +use crate::bridge::{SerialCommand, UiCommand}; +>>>>>>> Stashed changes use crate::channel_utils::LoggingTx; use crate::renderer::{Renderer, WindowDrawDetails}; @@ -162,12 +166,19 @@ impl MouseManager { // If dragging and we haven't already sent a position, send a drag command if self.dragging.is_some() && has_moved { self.command_sender +<<<<<<< Updated upstream .send(UiCommand::Drag { button: self.dragging.as_ref().unwrap().to_owned(), grid_id: relevant_window_details.id, position: self.drag_position.into(), modifier_string: keyboard_manager.format_modifier_string(true), }) +======= + .send(SerialCommand::Drag { + grid_id: relevant_window_details.id, + position: self.drag_position.into(), + }.into()) +>>>>>>> Stashed changes .ok(); } else { // otherwise, update the window_id_under_mouse to match the one selected @@ -203,6 +214,7 @@ impl MouseManager { }; self.command_sender +<<<<<<< Updated upstream .send(UiCommand::MouseButton { button: button_text.clone(), action, @@ -210,6 +222,14 @@ impl MouseManager { position: position.into(), modifier_string: keyboard_manager.format_modifier_string(true), }) +======= + .send(SerialCommand::MouseButton { + button: button_text.to_string(), + action, + grid_id: details.id, + position: position.into(), + }.into()) +>>>>>>> Stashed changes .ok(); } @@ -238,7 +258,7 @@ impl MouseManager { }; if let Some(input_type) = vertical_input_type { - let scroll_command = UiCommand::Scroll { + let scroll_command: UiCommand = SerialCommand::Scroll { direction: input_type.to_string(), grid_id: self .window_details_under_mouse @@ -246,8 +266,12 @@ impl MouseManager { .map(|details| details.id) .unwrap_or(0), position: self.drag_position.into(), +<<<<<<< Updated upstream modifier_string: keyboard_manager.format_modifier_string(true), }; +======= + }.into(); +>>>>>>> Stashed changes for _ in 0..(new_y - previous_y).abs() { self.command_sender.send(scroll_command.clone()).ok(); } @@ -264,7 +288,7 @@ impl MouseManager { }; if let Some(input_type) = horizontal_input_type { - let scroll_command = UiCommand::Scroll { + let scroll_command: UiCommand = SerialCommand::Scroll { direction: input_type.to_string(), grid_id: self .window_details_under_mouse @@ -272,8 +296,12 @@ impl MouseManager { .map(|details| details.id) .unwrap_or(0), position: self.drag_position.into(), +<<<<<<< Updated upstream modifier_string: keyboard_manager.format_modifier_string(true), }; +======= + }.into(); +>>>>>>> Stashed changes for _ in 0..(new_x - previous_x).abs() { self.command_sender.send(scroll_command.clone()).ok(); }