diff --git a/desktop/Cargo.toml b/desktop/Cargo.toml index bfa0a835..1df93314 100644 --- a/desktop/Cargo.toml +++ b/desktop/Cargo.toml @@ -55,6 +55,7 @@ windows = { version = "0.58.0", features = [ "Win32_Graphics_Gdi", "Win32_System_LibraryLoader", "Win32_System_Com", + "Win32_System_Console", "Win32_UI_Controls", "Win32_UI_WindowsAndMessaging", "Win32_UI_HiDpi", diff --git a/desktop/src/lib.rs b/desktop/src/lib.rs index 692adbab..1ae86052 100644 --- a/desktop/src/lib.rs +++ b/desktop/src/lib.rs @@ -93,6 +93,14 @@ pub fn start() { let mut app = App::new(Box::new(cef_context), cef_view_info_sender, wgpu_context, app_event_receiver, app_event_scheduler, cli.files); event_loop.run_app(&mut app).unwrap(); + + // Workaround for a Windows-specific exception that occurs when `app` is dropped. + // The issue causes the window to hang for a few seconds before closing. + // Appears to be related to CEF object destruction order. + // Calling `exit` bypasses rust teardown and lets Windows perform process cleanup. + // TODO: Identify and fix the underlying CEF shutdown issue so this workaround can be removed. + #[cfg(target_os = "windows")] + exit(0); } pub fn start_helper() { diff --git a/desktop/src/window/win.rs b/desktop/src/window/win.rs index 788f0c5b..cc3a45b6 100644 --- a/desktop/src/window/win.rs +++ b/desktop/src/window/win.rs @@ -1,4 +1,5 @@ use windows::Win32::System::Com::{COINIT_APARTMENTTHREADED, CoInitializeEx}; +use windows::Win32::System::Console::{ATTACH_PARENT_PROCESS, AttachConsole}; use windows::Win32::UI::Shell::SetCurrentProcessExplicitAppUserModelID; use windows::core::HSTRING; use winit::event_loop::ActiveEventLoop; @@ -13,6 +14,12 @@ pub(super) struct NativeWindowImpl { impl super::NativeWindow for NativeWindowImpl { fn init() { + // Attach to parent console if launched from a terminal (no-op otherwise) + unsafe { + let _ = AttachConsole(ATTACH_PARENT_PROCESS); + } + + // Set stable app ID let app_id = HSTRING::from(APP_ID); unsafe { let _ = CoInitializeEx(None, COINIT_APARTMENTTHREADED).ok(); diff --git a/desktop/src/window/win/native_handle.rs b/desktop/src/window/win/native_handle.rs index 84fd9a3b..228324dc 100644 --- a/desktop/src/window/win/native_handle.rs +++ b/desktop/src/window/win/native_handle.rs @@ -61,7 +61,7 @@ impl NativeWindowHandle { 0, 0, 0, - None, + main, None, HINSTANCE(std::ptr::null_mut()), // Pass the main window's HWND to WM_NCCREATE so the helper can store it. @@ -118,7 +118,7 @@ impl NativeWindowHandle { } // Force window update - let _ = unsafe { SetWindowPos(main, None, 0, 0, 0, 0, SWP_FRAMECHANGED | SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER) }; + let _ = unsafe { SetWindowPos(main, None, 0, 0, 0, 0, SWP_FRAMECHANGED | SWP_NOMOVE | SWP_NOSIZE) }; native_handle } @@ -325,20 +325,20 @@ unsafe fn position_helper(main: HWND, helper: HWND) { let w = (r.right - r.left) + RESIZE_BAND_THICKNESS * 2; let h = (r.bottom - r.top) + RESIZE_BAND_THICKNESS * 2; - let _ = unsafe { SetWindowPos(helper, main, x, y, w, h, SWP_NOACTIVATE | SWP_NOZORDER | SWP_NOOWNERZORDER | SWP_NOSENDCHANGING) }; + let _ = unsafe { SetWindowPos(helper, main, x, y, w, h, SWP_NOACTIVATE | SWP_NOSENDCHANGING) }; } unsafe fn calculate_hit(helper: HWND, lparam: LPARAM) -> u32 { - let x = (lparam.0 & 0xFFFF) as i16 as u32; - let y = ((lparam.0 >> 16) & 0xFFFF) as i16 as u32; + let x = (lparam.0 & 0xFFFF) as i16 as i32; + let y = ((lparam.0 >> 16) & 0xFFFF) as i16 as i32; let mut r = RECT::default(); let _ = unsafe { GetWindowRect(helper, &mut r) }; - let on_top = y < (r.top + RESIZE_BAND_THICKNESS) as u32; - let on_right = x >= (r.right - RESIZE_BAND_THICKNESS) as u32; - let on_bottom = y >= (r.bottom - RESIZE_BAND_THICKNESS) as u32; - let on_left = x < (r.left + RESIZE_BAND_THICKNESS) as u32; + let on_top = y < (r.top + RESIZE_BAND_THICKNESS) as i32; + let on_right = x >= (r.right - RESIZE_BAND_THICKNESS) as i32; + let on_bottom = y >= (r.bottom - RESIZE_BAND_THICKNESS) as i32; + let on_left = x < (r.left + RESIZE_BAND_THICKNESS) as i32; match (on_top, on_right, on_bottom, on_left) { (true, _, _, true) => HTTOPLEFT,