From ef0eb181d58f71b1a125085f6171922efca166f8 Mon Sep 17 00:00:00 2001 From: Jonathan Ami <126116089+jonathan-ami@users.noreply.github.com> Date: Thu, 21 Mar 2024 11:11:40 -0700 Subject: [PATCH] working termination --- Cargo.lock | 17 +++++++--- Cargo.toml | 4 +-- src/callbacks.rs | 6 +--- src/keybinds.rs | 26 +++++++-------- src/main.rs | 53 +++++++++++++++++++++--------- src/window.rs | 6 ++-- src/window_manager.rs | 76 ++++++++++++------------------------------- 7 files changed, 88 insertions(+), 100 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 7cb34a1..3d84972 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3,16 +3,25 @@ version = 3 [[package]] -name = "lazy_static" -version = "1.4.0" +name = "crossbeam-channel" +version = "0.5.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" +checksum = "ab3db02a9c5b5121e1e42fbdb1aeb65f5e02624cc58c43f2884c6ccac0b82f95" +dependencies = [ + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-utils" +version = "0.8.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "248e3bacc7dc6baa3b21e405ee045c3047101a49145e7e9eca583ab4c2ca5345" [[package]] name = "whirlwin" version = "0.1.0" dependencies = [ - "lazy_static", + "crossbeam-channel", "windows", ] diff --git a/Cargo.toml b/Cargo.toml index 0b3c2af..74170d2 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -4,9 +4,9 @@ version = "0.1.0" edition = "2021" [dependencies] -lazy_static = "1.4.0" +crossbeam-channel = "0.5" [dependencies.windows] version = "0.54" -features = ["Win32_UI_WindowsAndMessaging","Win32_Foundation","Win32_Graphics_Gdi","Win32_UI_Accessibility","Win32_UI_Input_KeyboardAndMouse"] +features = ["Win32_UI_WindowsAndMessaging","Win32_Foundation","Win32_Graphics_Gdi","Win32_UI_Accessibility","Win32_UI_Input_KeyboardAndMouse", "Win32_System_Threading"] diff --git a/src/callbacks.rs b/src/callbacks.rs index 35fc141..f31f4e6 100644 --- a/src/callbacks.rs +++ b/src/callbacks.rs @@ -8,7 +8,7 @@ use windows::Win32::UI::WindowsAndMessaging::{ GetWindowTextW, IsWindowVisible, PostMessageW, EVENT_SYSTEM_FOREGROUND, }; -//Checks if leader is pressed and signals window manager to re enumerate windows +//Used to update window_manager when user does not use whirlwin pub unsafe extern "system" fn win_event_proc( _: HWINEVENTHOOK, event: u32, @@ -18,14 +18,10 @@ pub unsafe extern "system" fn win_event_proc( _: u32, _: u32, ) { - println!("callback called"); let leader_pressed = LEADER_PRESSED.load(Ordering::Acquire); if event == EVENT_SYSTEM_FOREGROUND && !leader_pressed { let _ = PostMessageW(None, NEW_FOREGROUND_SET, None, None); - println!("leader in callback {}", leader_pressed); } - - println!("callback finisehd"); } pub unsafe extern "system" fn enum_windows_proc(hwnd: HWND, lparam: LPARAM) -> BOOL { diff --git a/src/keybinds.rs b/src/keybinds.rs index 9352b11..fb3fea3 100644 --- a/src/keybinds.rs +++ b/src/keybinds.rs @@ -1,13 +1,12 @@ use crate::window_manager::{Direction, WindowManagerMessage}; -use crate::EXIT_PROGRAM; + use std::io::Error; -use std::process; use std::sync::mpsc::Sender; use std::sync::Arc; + use windows::Win32::UI::Input::KeyboardAndMouse::{ RegisterHotKey, UnregisterHotKey, HOT_KEY_MODIFIERS, }; -use windows::Win32::UI::WindowsAndMessaging::PostMessageW; //Hotkey indentifies const EXIT: i32 = 1; @@ -45,9 +44,6 @@ pub fn handle_hotkey( if leader_pressed { match wparam { EXIT => { - if let Err(_err) = unsafe { PostMessageW(None, EXIT_PROGRAM, None, None) } { - process::exit(0); - } if let Err(err) = sender.send(WindowManagerMessage::EndListener) { return Err(format!("Failed to send message: {}", err)); } @@ -116,7 +112,7 @@ pub fn register_leader() -> Result<(), Error> { pub fn unregister_leader() { unsafe { - UnregisterHotKey(None, LEADER); + let _ = UnregisterHotKey(None, LEADER); } } fn register_hotkeys() -> Result<(), Error> { @@ -158,14 +154,14 @@ fn register_hotkeys() -> Result<(), Error> { pub fn unregister_hotkeys() { unsafe { - UnregisterHotKey(None, EXIT); - UnregisterHotKey(None, SWITCH_LEFT); - UnregisterHotKey(None, SWITCH_RIGHT); - UnregisterHotKey(None, SWITCH_ABOVE); - UnregisterHotKey(None, SWITCH_BELOW); - UnregisterHotKey(None, SWITCH_NEXT); - UnregisterHotKey(None, CLOSE_WINDOW); - UnregisterHotKey(None, SWITCH_PREVIOUS); + let _ = UnregisterHotKey(None, EXIT); + let _ = UnregisterHotKey(None, SWITCH_LEFT); + let _ = UnregisterHotKey(None, SWITCH_RIGHT); + let _ = UnregisterHotKey(None, SWITCH_ABOVE); + let _ = UnregisterHotKey(None, SWITCH_BELOW); + let _ = UnregisterHotKey(None, SWITCH_NEXT); + let _ = UnregisterHotKey(None, CLOSE_WINDOW); + let _ = UnregisterHotKey(None, SWITCH_PREVIOUS); } } diff --git a/src/main.rs b/src/main.rs index 4aa1e74..2bbe705 100644 --- a/src/main.rs +++ b/src/main.rs @@ -12,16 +12,23 @@ use std::sync::atomic::{AtomicBool, Ordering}; use std::sync::mpsc::{channel, Sender}; use std::sync::Arc; use std::thread; + +use crossbeam_channel; +use windows::Win32::System::Threading::GetCurrentThreadId; use windows::Win32::UI::Accessibility::SetWinEventHook; use windows::Win32::UI::WindowsAndMessaging::{ - DispatchMessageW, GetMessageW, TranslateMessage, EVENT_SYSTEM_FOREGROUND, MSG, - WINEVENT_OUTOFCONTEXT, WM_HOTKEY, WM_USER, + DispatchMessageW, GetMessageW, PostThreadMessageW, TranslateMessage, EVENT_SYSTEM_FOREGROUND, + MSG, WINEVENT_OUTOFCONTEXT, WM_HOTKEY, WM_USER, }; static LEADER_PRESSED: AtomicBool = AtomicBool::new(false); const NEW_FOREGROUND_SET: u32 = WM_USER + 1; +const EXIT_PROGRAM: u32 = WM_USER + 2; -fn spawn_hook(sender: Arc>) { +fn spawn_hook( + sender: Arc>, + thread_id_sender: crossbeam_channel::Sender, +) { unsafe { SetWinEventHook( EVENT_SYSTEM_FOREGROUND, @@ -33,18 +40,28 @@ fn spawn_hook(sender: Arc>) { WINEVENT_OUTOFCONTEXT, ); } + let thread_id = unsafe { GetCurrentThreadId() }; + if let Err(e) = thread_id_sender.send(thread_id) { + println!("Error sending thread id {}", e); + } let mut msg: MSG = MSG::default(); - unsafe { - loop { + loop { + unsafe { if GetMessageW(&mut msg, None, 0, 0).into() { if msg.message == NEW_FOREGROUND_SET { + println!("new foreground set in handle_callback"); + if let Err(err) = sender.send(WindowManagerMessage::ClearWindows) { + println!("{}", err); + } if let Err(err) = sender.send(WindowManagerMessage::SetCurrent) { println!("{}", err); } if let Err(err) = sender.send(WindowManagerMessage::SetWindows) { println!("{}", err); } + } else if msg.message == EXIT_PROGRAM { + break; } } TranslateMessage(&msg); @@ -53,7 +70,7 @@ fn spawn_hook(sender: Arc>) { } } -fn key_listener(sender: Arc>) { +fn key_listener(sender: Arc>, callback_thread_id: u32) { unsafe { let mut msg: MSG = MSG::default(); while GetMessageW(&mut msg, None, 0, 0).into() { @@ -62,11 +79,14 @@ fn key_listener(sender: Arc>) { let wparam = msg.wParam.0 as i32; match handle_hotkey(wparam, &sender, leader_pressed) { Ok(leader) => { - println!("leader after hotkey {}", leader); LEADER_PRESSED.store(leader, Ordering::Relaxed); - println!("leader pressed updated"); } Err(e) => { + if let Err(e) = + PostThreadMessageW(callback_thread_id, EXIT_PROGRAM, None, None) + { + println!("error sending thread message {}", e); + } println!("Error {}", e); break; } @@ -83,21 +103,24 @@ fn main() -> Result<(), Error> { let mut window_manager = WindowManager::new(receiver); window_manager.set_windows(); let window_manger_listener = thread::spawn(move || window_manager.start()); - let callback_listener = { - let sender = Arc::clone(&sender_arc); - thread::spawn(move || spawn_hook(sender)) - }; - unregister_leader(); match register_leader() { Ok(()) => println!("Leader Registered"), Err(e) => println!("Failed to registrer leader: {}", e), } - key_listener(Arc::clone(&sender_arc)); + //Channel used for retreiving thread id of callback listener + let (callback_sender, callback_receiver) = crossbeam_channel::unbounded(); + let callback_listener = { + let thread_id_sender = callback_sender.clone(); + let sender = Arc::clone(&sender_arc); + thread::spawn(move || spawn_hook(sender, thread_id_sender)) + }; + let callback_thread_id = callback_receiver.recv().unwrap(); + + key_listener(Arc::clone(&sender_arc), callback_thread_id); window_manger_listener.join().unwrap(); - println!("callback listenern joined"); callback_listener.join().unwrap(); unregister_leader(); Ok(()) diff --git a/src/window.rs b/src/window.rs index ff83f37..2c45ba6 100644 --- a/src/window.rs +++ b/src/window.rs @@ -27,8 +27,8 @@ impl Window { let mut placement: WINDOWPLACEMENT = WINDOWPLACEMENT::default(); let mut info: WINDOWINFO = WINDOWINFO::default(); unsafe { - GetWindowPlacement(hwnd, &mut placement); - GetWindowInfo(hwnd, &mut info); + let _ = GetWindowPlacement(hwnd, &mut placement); + let _ = GetWindowInfo(hwnd, &mut info); } Self { hwnd, @@ -43,7 +43,7 @@ impl Window { fn set_rect(hwnd: HWND, info: WINDOWINFO) -> Rect { let mut rect: RECT = RECT::default(); unsafe { - GetWindowRect(hwnd, &mut rect); + let _ = GetWindowRect(hwnd, &mut rect); } Rect { right: rect.right - info.cxWindowBorders as i32, diff --git a/src/window_manager.rs b/src/window_manager.rs index 33027fb..0a02762 100644 --- a/src/window_manager.rs +++ b/src/window_manager.rs @@ -2,10 +2,10 @@ use crate::callbacks::enum_windows_proc; use crate::window::Window; use std::sync::mpsc::Receiver; -use windows::Win32::Foundation::{HWND, LPARAM, WPARAM}; +use windows::Win32::Foundation::{HWND, LPARAM}; use windows::Win32::UI::WindowsAndMessaging::{ - CloseWindow, EnumWindows, GetForegroundWindow, SendMessageW, SetForegroundWindow, SetWindowPos, - HWND_BOTTOM, SWP_NOMOVE, SWP_NOSIZE, WM_CLOSE, + CloseWindow, EnumWindows, GetForegroundWindow, SetForegroundWindow, SetWindowPos, HWND_BOTTOM, + SWP_NOMOVE, SWP_NOSIZE, }; pub enum Direction { Left, @@ -55,7 +55,6 @@ impl WindowManager { pub fn start(mut self) { while let Ok(message) = self.receiver.recv() { - println!("message received in window_manager"); match message { WindowManagerMessage::SetWindows => self.set_windows(), WindowManagerMessage::CloseWindow => self.close_window(), @@ -90,23 +89,14 @@ impl WindowManager { } fn switch_to_direction(&mut self, direction: Direction) { - let mut option = None; - match direction { - Direction::Left => { - option = Some(self.left.take()); - } - Direction::Right => { - option = Some(self.right.take()); - } - Direction::Below => { - option = Some(self.below.take()); - } - Direction::Above => { - option = Some(self.above.take()); - } - } + let window = match direction { + Direction::Left => self.left.take(), + Direction::Right => self.right.take(), + Direction::Below => self.below.take(), + Direction::Above => self.above.take(), + }; - if let Some(window) = option.unwrap() { + if let Some(window) = window { unsafe { if !SetForegroundWindow(window.hwnd).as_bool() { println!("Failed to switch windows"); @@ -120,8 +110,9 @@ impl WindowManager { pub fn close_window(&mut self) { unsafe { - //CloseWindow(self.current.hwnd); - SendMessageW(self.current.hwnd, WM_CLOSE, WPARAM(0), LPARAM(0)); + if let Err(e) = CloseWindow(self.current.hwnd) { + println!("Failed to close window {}", e); + } } if let Some(window) = &self.next { self.current = window.to_owned(); @@ -130,24 +121,10 @@ impl WindowManager { } } - /*fn print_window_info(window: &Window) { - println!("order: {}", window.order); - println!("flags {}", window.placement.flags); - println!("dwStyle {}", window.info.dwStyle); - println!("creator version{}", window.info.wCreatorVersion); - println!("atom {}", window.info.atomWindowType); - println!("visibility {}", unsafe { IsWindowVisible(window.hwnd) }); - println!("border width {}", window.info.cxWindowBorders); - println!("cmd {}", window.placement.showCmd); - println!("left {}", window.rect.left); - println!("right {}", window.rect.right); - println!("bottom {}", window.rect.bottom); - println!("top {}", window.rect.top); - println!(""); - }*/ + #[allow(dead_code)] pub fn print_windows(&mut self) { println!("current"); - &self.current.print_title(); + let _ = &self.current.print_title(); println!(""); print!("left"); @@ -188,7 +165,7 @@ impl WindowManager { pub fn set_windows(&mut self) { unsafe { - EnumWindows( + let _ = EnumWindows( Some(enum_windows_proc), LPARAM(self as *mut WindowManager as isize), ); @@ -222,7 +199,7 @@ impl WindowManager { window.print_title(); unsafe { SetForegroundWindow(window.hwnd); - SetWindowPos( + if let Err(e) = SetWindowPos( self.current.hwnd, HWND_BOTTOM, 0, @@ -230,7 +207,9 @@ impl WindowManager { 0, 0, SWP_NOMOVE | SWP_NOSIZE, - ); + ) { + println!("Switch to next {}: ", e); + } } if let Some(hwnd) = self.stack_bottom { if hwnd == window.hwnd { @@ -250,18 +229,3 @@ impl WindowManager { } } -#[macro_export] -macro_rules! switch_to_direction { - ($window_manager:expr, $direction:ident) => { - if let Some(window) = $window_manager.$direction.take() { - if SetForegroundWindow(window.hwnd) == 0 { - println!("Failed to switch windows"); - } - $window_manager.clear_windows(); - $window_manager.current = window; - $window_manager.set_windows(); - println!("Switch to window {}", stringify!($direction)); - } - }; -} -