diff --git a/crates/gpui/src/platform/windows/platform.rs b/crates/gpui/src/platform/windows/platform.rs index dca29e321c..b60d6ca368 100644 --- a/crates/gpui/src/platform/windows/platform.rs +++ b/crates/gpui/src/platform/windows/platform.rs @@ -11,6 +11,7 @@ use std::{ time::Duration, }; +use ::util::{ResultExt, SemanticVersion}; use anyhow::{anyhow, Result}; use async_task::Runnable; use copypasta::{ClipboardContext, ClipboardProvider}; @@ -19,7 +20,6 @@ use itertools::Itertools; use parking_lot::{Mutex, RwLock}; use smallvec::SmallVec; use time::UtcOffset; -use util::{ResultExt, SemanticVersion}; use windows::{ core::*, Wdk::System::SystemServices::*, @@ -31,12 +31,7 @@ use windows::{ }, }; -use crate::{ - Action, AnyWindowHandle, BackgroundExecutor, ClipboardItem, CursorStyle, ForegroundExecutor, - Keymap, Menu, PathPromptOptions, Platform, PlatformDisplay, PlatformInput, PlatformTextSystem, - PlatformWindow, Task, WindowAppearance, WindowParams, WindowsDispatcher, WindowsDisplay, - WindowsTextSystem, WindowsWindow, -}; +use crate::*; pub(crate) struct WindowsPlatform { inner: Rc, @@ -64,6 +59,19 @@ pub(crate) struct WindowsPlatformInner { pub(crate) settings: RefCell, } +impl WindowsPlatformInner { + pub(crate) fn try_get_windows_inner_from_hwnd( + &self, + hwnd: HWND, + ) -> Option> { + self.raw_window_handles + .read() + .iter() + .find(|entry| *entry == &hwnd) + .and_then(|hwnd| try_get_window_inner(*hwnd)) + } +} + impl Drop for WindowsPlatformInner { fn drop(&mut self) { unsafe { CloseHandle(self.event) }.ok(); @@ -282,9 +290,11 @@ impl Platform for WindowsPlatform { } } - // todo(windows) fn active_window(&self) -> Option { - None + let active_window_hwnd = unsafe { GetActiveWindow() }; + self.inner + .try_get_windows_inner_from_hwnd(active_window_hwnd) + .map(|inner| inner.handle) } fn open_window( diff --git a/crates/gpui/src/platform/windows/window.rs b/crates/gpui/src/platform/windows/window.rs index 06c821982f..567bf38287 100644 --- a/crates/gpui/src/platform/windows/window.rs +++ b/crates/gpui/src/platform/windows/window.rs @@ -47,7 +47,7 @@ pub(crate) struct WindowsWindowInner { renderer: RefCell, callbacks: RefCell, platform_inner: Rc, - handle: AnyWindowHandle, + pub(crate) handle: AnyWindowHandle, scale_factor: f32, } @@ -178,6 +178,7 @@ impl WindowsWindowInner { match msg { WM_ACTIVATE => self.handle_activate_msg(msg, wparam, lparam), WM_CREATE => self.handle_create_msg(lparam), + WM_SETFOCUS => self.handle_set_focus_msg(msg, wparam, lparam), WM_MOVE => self.handle_move_msg(lparam), WM_SIZE => self.handle_size_msg(lparam), WM_NCCALCSIZE => self.handle_calc_client_size(msg, wparam, lparam), @@ -968,6 +969,31 @@ impl WindowsWindowInner { unsafe { DefWindowProcW(self.hwnd, msg, wparam, lparam) } } + + fn handle_set_focus_msg(&self, _msg: u32, wparam: WPARAM, _lparam: LPARAM) -> LRESULT { + // wparam is the window that just lost focus (may be null) + // SEE: https://learn.microsoft.com/en-us/windows/win32/inputdev/wm-setfocus + let lost_focus_hwnd = HWND(wparam.0 as isize); + if let Some(lost_focus_window) = self + .platform_inner + .try_get_windows_inner_from_hwnd(lost_focus_hwnd) + { + lost_focus_window + .callbacks + .borrow_mut() + .active_status_change + .as_mut() + .map(|mut cb| cb(false)); + } + + self.callbacks + .borrow_mut() + .active_status_change + .as_mut() + .map(|mut cb| cb(true)); + + LRESULT(0) + } } #[derive(Default)] @@ -1234,7 +1260,9 @@ impl PlatformWindow for WindowsWindow { } fn activate(&self) { - unsafe { ShowWindowAsync(self.inner.hwnd, SW_NORMAL) }; + unsafe { SetActiveWindow(self.inner.hwnd) }; + unsafe { SetFocus(self.inner.hwnd) }; + unsafe { SetForegroundWindow(self.inner.hwnd) }; } // todo(windows) @@ -1497,6 +1525,10 @@ unsafe extern "system" fn wnd_proc( } pub(crate) fn try_get_window_inner(hwnd: HWND) -> Option> { + if hwnd == HWND(0) { + return None; + } + let ptr = unsafe { get_window_long(hwnd, GWLP_USERDATA) } as *mut Weak; if !ptr.is_null() { let inner = unsafe { &*ptr };