windows: Use a message-only window for `WindowsPlatform` (#37313)

å¼ å°ç™½ and reflectronic created

Previously, we were using `PostThreadMessage` to pass messages to
`WindowsPlatform`. This PR switches to an approach similar to `winit`
which using a hidden window as the message window (I guess that’s why
winit uses a hidden window?). The difference is that this PR creates it
as a message-only window.

Thanks to @reflectronic for the original PR #37255, this implementation
just fits better with the current code style.


Release Notes:

- N/A

---------

Co-authored-by: reflectronic <john-tur@outlook.com>

Change summary

crates/gpui/src/platform/windows/dispatcher.rs |  17 
crates/gpui/src/platform/windows/events.rs     |  19 
crates/gpui/src/platform/windows/platform.rs   | 383 ++++++++++++-------
crates/gpui/src/platform/windows/window.rs     |  10 
4 files changed, 275 insertions(+), 154 deletions(-)

Detailed changes

crates/gpui/src/platform/windows/dispatcher.rs 🔗

@@ -14,34 +14,37 @@ use windows::{
     },
     Win32::{
         Foundation::{LPARAM, WPARAM},
-        UI::WindowsAndMessaging::PostThreadMessageW,
+        UI::WindowsAndMessaging::PostMessageW,
     },
 };
 
-use crate::{PlatformDispatcher, TaskLabel, WM_GPUI_TASK_DISPATCHED_ON_MAIN_THREAD};
+use crate::{
+    HWND, PlatformDispatcher, SafeHwnd, TaskLabel, WM_GPUI_TASK_DISPATCHED_ON_MAIN_THREAD,
+};
 
 pub(crate) struct WindowsDispatcher {
     main_sender: Sender<Runnable>,
     parker: Mutex<Parker>,
     main_thread_id: ThreadId,
-    main_thread_id_win32: u32,
+    platform_window_handle: SafeHwnd,
     validation_number: usize,
 }
 
 impl WindowsDispatcher {
     pub(crate) fn new(
         main_sender: Sender<Runnable>,
-        main_thread_id_win32: u32,
+        platform_window_handle: HWND,
         validation_number: usize,
     ) -> Self {
         let parker = Mutex::new(Parker::new());
         let main_thread_id = current().id();
+        let platform_window_handle = platform_window_handle.into();
 
         WindowsDispatcher {
             main_sender,
             parker,
             main_thread_id,
-            main_thread_id_win32,
+            platform_window_handle,
             validation_number,
         }
     }
@@ -84,8 +87,8 @@ impl PlatformDispatcher for WindowsDispatcher {
     fn dispatch_on_main_thread(&self, runnable: Runnable) {
         match self.main_sender.send(runnable) {
             Ok(_) => unsafe {
-                PostThreadMessageW(
-                    self.main_thread_id_win32,
+                PostMessageW(
+                    Some(self.platform_window_handle.as_raw()),
                     WM_GPUI_TASK_DISPATCHED_ON_MAIN_THREAD,
                     WPARAM(self.validation_number),
                     LPARAM(0),

crates/gpui/src/platform/windows/events.rs 🔗

@@ -24,6 +24,7 @@ pub(crate) const WM_GPUI_CLOSE_ONE_WINDOW: u32 = WM_USER + 2;
 pub(crate) const WM_GPUI_TASK_DISPATCHED_ON_MAIN_THREAD: u32 = WM_USER + 3;
 pub(crate) const WM_GPUI_DOCK_MENU_ACTION: u32 = WM_USER + 4;
 pub(crate) const WM_GPUI_FORCE_UPDATE_WINDOW: u32 = WM_USER + 5;
+pub(crate) const WM_GPUI_KEYBOARD_LAYOUT_CHANGED: u32 = WM_USER + 6;
 
 const SIZE_MOVE_LOOP_TIMER_ID: usize = 1;
 const AUTO_HIDE_TASKBAR_THICKNESS_PX: i32 = 1;
@@ -99,7 +100,7 @@ impl WindowsWindowInner {
             WM_IME_COMPOSITION => self.handle_ime_composition(handle, lparam),
             WM_SETCURSOR => self.handle_set_cursor(handle, lparam),
             WM_SETTINGCHANGE => self.handle_system_settings_changed(handle, wparam, lparam),
-            WM_INPUTLANGCHANGE => self.handle_input_language_changed(lparam),
+            WM_INPUTLANGCHANGE => self.handle_input_language_changed(),
             WM_SHOWWINDOW => self.handle_window_visibility_changed(handle, wparam),
             WM_GPUI_CURSOR_STYLE_CHANGED => self.handle_cursor_changed(lparam),
             WM_GPUI_FORCE_UPDATE_WINDOW => self.draw_window(handle, true),
@@ -264,8 +265,8 @@ impl WindowsWindowInner {
             callback();
         }
         unsafe {
-            PostThreadMessageW(
-                self.main_thread_id_win32,
+            PostMessageW(
+                Some(self.platform_window_handle),
                 WM_GPUI_CLOSE_ONE_WINDOW,
                 WPARAM(self.validation_number),
                 LPARAM(handle.0 as isize),
@@ -1146,11 +1147,15 @@ impl WindowsWindowInner {
         Some(0)
     }
 
-    fn handle_input_language_changed(&self, lparam: LPARAM) -> Option<isize> {
-        let thread = self.main_thread_id_win32;
-        let validation = self.validation_number;
+    fn handle_input_language_changed(&self) -> Option<isize> {
         unsafe {
-            PostThreadMessageW(thread, WM_INPUTLANGCHANGE, WPARAM(validation), lparam).log_err();
+            PostMessageW(
+                Some(self.platform_window_handle),
+                WM_GPUI_KEYBOARD_LAYOUT_CHANGED,
+                WPARAM(self.validation_number),
+                LPARAM(0),
+            )
+            .log_err();
         }
         Some(0)
     }

crates/gpui/src/platform/windows/platform.rs 🔗

@@ -2,7 +2,7 @@ use std::{
     cell::RefCell,
     ffi::OsStr,
     path::{Path, PathBuf},
-    rc::Rc,
+    rc::{Rc, Weak},
     sync::Arc,
 };
 
@@ -19,7 +19,7 @@ use windows::{
         Foundation::*,
         Graphics::Gdi::*,
         Security::Credentials::*,
-        System::{Com::*, LibraryLoader::*, Ole::*, SystemInformation::*, Threading::*},
+        System::{Com::*, LibraryLoader::*, Ole::*, SystemInformation::*},
         UI::{Input::KeyboardAndMouse::*, Shell::*, WindowsAndMessaging::*},
     },
     core::*,
@@ -28,21 +28,27 @@ use windows::{
 use crate::*;
 
 pub(crate) struct WindowsPlatform {
-    state: RefCell<WindowsPlatformState>,
+    inner: Rc<WindowsPlatformInner>,
     raw_window_handles: Arc<RwLock<SmallVec<[SafeHwnd; 4]>>>,
     // The below members will never change throughout the entire lifecycle of the app.
     icon: HICON,
-    main_receiver: flume::Receiver<Runnable>,
     background_executor: BackgroundExecutor,
     foreground_executor: ForegroundExecutor,
     text_system: Arc<DirectWriteTextSystem>,
     windows_version: WindowsVersion,
     drop_target_helper: IDropTargetHelper,
-    validation_number: usize,
-    main_thread_id_win32: u32,
+    handle: HWND,
     disable_direct_composition: bool,
 }
 
+struct WindowsPlatformInner {
+    state: RefCell<WindowsPlatformState>,
+    raw_window_handles: std::sync::Weak<RwLock<SmallVec<[SafeHwnd; 4]>>>,
+    // The below members will never change throughout the entire lifecycle of the app.
+    validation_number: usize,
+    main_receiver: flume::Receiver<Runnable>,
+}
+
 pub(crate) struct WindowsPlatformState {
     callbacks: PlatformCallbacks,
     menus: Vec<OwnedMenu>,
@@ -83,11 +89,36 @@ impl WindowsPlatform {
             OleInitialize(None).context("unable to initialize Windows OLE")?;
         }
         let (main_sender, main_receiver) = flume::unbounded::<Runnable>();
-        let main_thread_id_win32 = unsafe { GetCurrentThreadId() };
         let validation_number = rand::random::<usize>();
+        let raw_window_handles = Arc::new(RwLock::new(SmallVec::new()));
+        register_platform_window_class();
+        let mut context = PlatformWindowCreateContext {
+            inner: None,
+            raw_window_handles: Arc::downgrade(&raw_window_handles),
+            validation_number,
+            main_receiver: Some(main_receiver),
+        };
+        let result = unsafe {
+            CreateWindowExW(
+                WINDOW_EX_STYLE(0),
+                PLATFORM_WINDOW_CLASS_NAME,
+                None,
+                WINDOW_STYLE(0),
+                0,
+                0,
+                0,
+                0,
+                Some(HWND_MESSAGE),
+                None,
+                None,
+                Some(&context as *const _ as *const _),
+            )
+        };
+        let inner = context.inner.take().unwrap()?;
+        let handle = result?;
         let dispatcher = Arc::new(WindowsDispatcher::new(
             main_sender,
-            main_thread_id_win32,
+            handle,
             validation_number,
         ));
         let disable_direct_composition = std::env::var(DISABLE_DIRECT_COMPOSITION)
@@ -105,23 +136,19 @@ impl WindowsPlatform {
                 .context("Error creating drop target helper.")?
         };
         let icon = load_icon().unwrap_or_default();
-        let state = RefCell::new(WindowsPlatformState::new());
-        let raw_window_handles = Arc::new(RwLock::new(SmallVec::new()));
         let windows_version = WindowsVersion::new().context("Error retrieve windows version")?;
 
         Ok(Self {
-            state,
+            inner,
+            handle,
             raw_window_handles,
             icon,
-            main_receiver,
             background_executor,
             foreground_executor,
             text_system,
             disable_direct_composition,
             windows_version,
             drop_target_helper,
-            validation_number,
-            main_thread_id_win32,
         })
     }
 
@@ -143,119 +170,20 @@ impl WindowsPlatform {
             });
     }
 
-    fn close_one_window(&self, target_window: HWND) -> bool {
-        let mut lock = self.raw_window_handles.write();
-        let index = lock
-            .iter()
-            .position(|handle| handle.as_raw() == target_window)
-            .unwrap();
-        lock.remove(index);
-
-        lock.is_empty()
-    }
-
-    #[inline]
-    fn run_foreground_task(&self) {
-        for runnable in self.main_receiver.drain() {
-            runnable.run();
-        }
-    }
-
     fn generate_creation_info(&self) -> WindowCreationInfo {
         WindowCreationInfo {
             icon: self.icon,
             executor: self.foreground_executor.clone(),
-            current_cursor: self.state.borrow().current_cursor,
+            current_cursor: self.inner.state.borrow().current_cursor,
             windows_version: self.windows_version,
             drop_target_helper: self.drop_target_helper.clone(),
-            validation_number: self.validation_number,
-            main_receiver: self.main_receiver.clone(),
-            main_thread_id_win32: self.main_thread_id_win32,
+            validation_number: self.inner.validation_number,
+            main_receiver: self.inner.main_receiver.clone(),
+            platform_window_handle: self.handle,
             disable_direct_composition: self.disable_direct_composition,
         }
     }
 
-    fn handle_dock_action_event(&self, action_idx: usize) {
-        let mut lock = self.state.borrow_mut();
-        if let Some(mut callback) = lock.callbacks.app_menu_action.take() {
-            let Some(action) = lock
-                .jump_list
-                .dock_menus
-                .get(action_idx)
-                .map(|dock_menu| dock_menu.action.boxed_clone())
-            else {
-                lock.callbacks.app_menu_action = Some(callback);
-                log::error!("Dock menu for index {action_idx} not found");
-                return;
-            };
-            drop(lock);
-            callback(&*action);
-            self.state.borrow_mut().callbacks.app_menu_action = Some(callback);
-        }
-    }
-
-    fn handle_input_lang_change(&self) {
-        let mut lock = self.state.borrow_mut();
-        if let Some(mut callback) = lock.callbacks.keyboard_layout_change.take() {
-            drop(lock);
-            callback();
-            self.state
-                .borrow_mut()
-                .callbacks
-                .keyboard_layout_change
-                .get_or_insert(callback);
-        }
-    }
-
-    // Returns if the app should quit.
-    fn handle_events(&self) {
-        let mut msg = MSG::default();
-        unsafe {
-            while GetMessageW(&mut msg, None, 0, 0).as_bool() {
-                match msg.message {
-                    WM_QUIT => return,
-                    WM_INPUTLANGCHANGE
-                    | WM_GPUI_CLOSE_ONE_WINDOW
-                    | WM_GPUI_TASK_DISPATCHED_ON_MAIN_THREAD
-                    | WM_GPUI_DOCK_MENU_ACTION => {
-                        if self.handle_gpui_events(msg.message, msg.wParam, msg.lParam, &msg) {
-                            return;
-                        }
-                    }
-                    _ => {
-                        DispatchMessageW(&msg);
-                    }
-                }
-            }
-        }
-    }
-
-    // Returns true if the app should quit.
-    fn handle_gpui_events(
-        &self,
-        message: u32,
-        wparam: WPARAM,
-        lparam: LPARAM,
-        msg: *const MSG,
-    ) -> bool {
-        if wparam.0 != self.validation_number {
-            unsafe { DispatchMessageW(msg) };
-            return false;
-        }
-        match message {
-            WM_GPUI_CLOSE_ONE_WINDOW => {
-                if self.close_one_window(HWND(lparam.0 as _)) {
-                    return true;
-                }
-            }
-            WM_GPUI_TASK_DISPATCHED_ON_MAIN_THREAD => self.run_foreground_task(),
-            WM_GPUI_DOCK_MENU_ACTION => self.handle_dock_action_event(lparam.0 as _),
-            WM_INPUTLANGCHANGE => self.handle_input_lang_change(),
-            _ => unreachable!(),
-        }
-        false
-    }
-
     fn set_dock_menus(&self, menus: Vec<MenuItem>) {
         let mut actions = Vec::new();
         menus.into_iter().for_each(|menu| {
@@ -263,7 +191,7 @@ impl WindowsPlatform {
                 actions.push(dock_menu);
             }
         });
-        let mut lock = self.state.borrow_mut();
+        let mut lock = self.inner.state.borrow_mut();
         lock.jump_list.dock_menus = actions;
         update_jump_list(&lock.jump_list).log_err();
     }
@@ -279,7 +207,7 @@ impl WindowsPlatform {
                 actions.push(dock_menu);
             }
         });
-        let mut lock = self.state.borrow_mut();
+        let mut lock = self.inner.state.borrow_mut();
         lock.jump_list.dock_menus = actions;
         lock.jump_list.recent_workspaces = entries;
         update_jump_list(&lock.jump_list)
@@ -346,15 +274,25 @@ impl Platform for WindowsPlatform {
     }
 
     fn on_keyboard_layout_change(&self, callback: Box<dyn FnMut()>) {
-        self.state.borrow_mut().callbacks.keyboard_layout_change = Some(callback);
+        self.inner
+            .state
+            .borrow_mut()
+            .callbacks
+            .keyboard_layout_change = Some(callback);
     }
 
     fn run(&self, on_finish_launching: Box<dyn 'static + FnOnce()>) {
         on_finish_launching();
         self.begin_vsync_thread();
-        self.handle_events();
 
-        if let Some(ref mut callback) = self.state.borrow_mut().callbacks.quit {
+        let mut msg = MSG::default();
+        unsafe {
+            while GetMessageW(&mut msg, None, 0, 0).as_bool() {
+                DispatchMessageW(&msg);
+            }
+        }
+
+        if let Some(ref mut callback) = self.inner.state.borrow_mut().callbacks.quit {
             callback();
         }
     }
@@ -469,7 +407,7 @@ impl Platform for WindowsPlatform {
     }
 
     fn on_open_urls(&self, callback: Box<dyn FnMut(Vec<String>)>) {
-        self.state.borrow_mut().callbacks.open_urls = Some(callback);
+        self.inner.state.borrow_mut().callbacks.open_urls = Some(callback);
     }
 
     fn prompt_for_paths(
@@ -539,19 +477,19 @@ impl Platform for WindowsPlatform {
     }
 
     fn on_quit(&self, callback: Box<dyn FnMut()>) {
-        self.state.borrow_mut().callbacks.quit = Some(callback);
+        self.inner.state.borrow_mut().callbacks.quit = Some(callback);
     }
 
     fn on_reopen(&self, callback: Box<dyn FnMut()>) {
-        self.state.borrow_mut().callbacks.reopen = Some(callback);
+        self.inner.state.borrow_mut().callbacks.reopen = Some(callback);
     }
 
     fn set_menus(&self, menus: Vec<Menu>, _keymap: &Keymap) {
-        self.state.borrow_mut().menus = menus.into_iter().map(|menu| menu.owned()).collect();
+        self.inner.state.borrow_mut().menus = menus.into_iter().map(|menu| menu.owned()).collect();
     }
 
     fn get_menus(&self) -> Option<Vec<OwnedMenu>> {
-        Some(self.state.borrow().menus.clone())
+        Some(self.inner.state.borrow().menus.clone())
     }
 
     fn set_dock_menu(&self, menus: Vec<MenuItem>, _keymap: &Keymap) {
@@ -559,15 +497,19 @@ impl Platform for WindowsPlatform {
     }
 
     fn on_app_menu_action(&self, callback: Box<dyn FnMut(&dyn Action)>) {
-        self.state.borrow_mut().callbacks.app_menu_action = Some(callback);
+        self.inner.state.borrow_mut().callbacks.app_menu_action = Some(callback);
     }
 
     fn on_will_open_app_menu(&self, callback: Box<dyn FnMut()>) {
-        self.state.borrow_mut().callbacks.will_open_app_menu = Some(callback);
+        self.inner.state.borrow_mut().callbacks.will_open_app_menu = Some(callback);
     }
 
     fn on_validate_app_menu_command(&self, callback: Box<dyn FnMut(&dyn Action) -> bool>) {
-        self.state.borrow_mut().callbacks.validate_app_menu_command = Some(callback);
+        self.inner
+            .state
+            .borrow_mut()
+            .callbacks
+            .validate_app_menu_command = Some(callback);
     }
 
     fn app_path(&self) -> Result<PathBuf> {
@@ -581,7 +523,7 @@ impl Platform for WindowsPlatform {
 
     fn set_cursor_style(&self, style: CursorStyle) {
         let hcursor = load_cursor(style);
-        let mut lock = self.state.borrow_mut();
+        let mut lock = self.inner.state.borrow_mut();
         if lock.current_cursor.map(|c| c.0) != hcursor.map(|c| c.0) {
             self.post_message(
                 WM_GPUI_CURSOR_STYLE_CHANGED,
@@ -684,10 +626,10 @@ impl Platform for WindowsPlatform {
 
     fn perform_dock_menu_action(&self, action: usize) {
         unsafe {
-            PostThreadMessageW(
-                self.main_thread_id_win32,
+            PostMessageW(
+                Some(self.handle),
                 WM_GPUI_DOCK_MENU_ACTION,
-                WPARAM(self.validation_number),
+                WPARAM(self.inner.validation_number),
                 LPARAM(action as isize),
             )
             .log_err();
@@ -703,9 +645,118 @@ impl Platform for WindowsPlatform {
     }
 }
 
+impl WindowsPlatformInner {
+    fn new(context: &mut PlatformWindowCreateContext) -> Result<Rc<Self>> {
+        let state = RefCell::new(WindowsPlatformState::new());
+        Ok(Rc::new(Self {
+            state,
+            raw_window_handles: context.raw_window_handles.clone(),
+            validation_number: context.validation_number,
+            main_receiver: context.main_receiver.take().unwrap(),
+        }))
+    }
+
+    fn handle_msg(
+        self: &Rc<Self>,
+        handle: HWND,
+        msg: u32,
+        wparam: WPARAM,
+        lparam: LPARAM,
+    ) -> LRESULT {
+        let handled = match msg {
+            WM_GPUI_CLOSE_ONE_WINDOW
+            | WM_GPUI_TASK_DISPATCHED_ON_MAIN_THREAD
+            | WM_GPUI_DOCK_MENU_ACTION
+            | WM_GPUI_KEYBOARD_LAYOUT_CHANGED => self.handle_gpui_events(msg, wparam, lparam),
+            _ => None,
+        };
+        if let Some(result) = handled {
+            LRESULT(result)
+        } else {
+            unsafe { DefWindowProcW(handle, msg, wparam, lparam) }
+        }
+    }
+
+    fn handle_gpui_events(&self, message: u32, wparam: WPARAM, lparam: LPARAM) -> Option<isize> {
+        if wparam.0 != self.validation_number {
+            log::error!("Wrong validation number while processing message: {message}");
+            return None;
+        }
+        match message {
+            WM_GPUI_CLOSE_ONE_WINDOW => {
+                if self.close_one_window(HWND(lparam.0 as _)) {
+                    unsafe { PostQuitMessage(0) };
+                }
+                Some(0)
+            }
+            WM_GPUI_TASK_DISPATCHED_ON_MAIN_THREAD => self.run_foreground_task(),
+            WM_GPUI_DOCK_MENU_ACTION => self.handle_dock_action_event(lparam.0 as _),
+            WM_GPUI_KEYBOARD_LAYOUT_CHANGED => self.handle_keyboard_layout_change(),
+            _ => unreachable!(),
+        }
+    }
+
+    fn close_one_window(&self, target_window: HWND) -> bool {
+        let Some(all_windows) = self.raw_window_handles.upgrade() else {
+            log::error!("Failed to upgrade raw window handles");
+            return false;
+        };
+        let mut lock = all_windows.write();
+        let index = lock
+            .iter()
+            .position(|handle| handle.as_raw() == target_window)
+            .unwrap();
+        lock.remove(index);
+
+        lock.is_empty()
+    }
+
+    #[inline]
+    fn run_foreground_task(&self) -> Option<isize> {
+        for runnable in self.main_receiver.drain() {
+            runnable.run();
+        }
+        Some(0)
+    }
+
+    fn handle_dock_action_event(&self, action_idx: usize) -> Option<isize> {
+        let mut lock = self.state.borrow_mut();
+        let mut callback = lock.callbacks.app_menu_action.take()?;
+        let Some(action) = lock
+            .jump_list
+            .dock_menus
+            .get(action_idx)
+            .map(|dock_menu| dock_menu.action.boxed_clone())
+        else {
+            lock.callbacks.app_menu_action = Some(callback);
+            log::error!("Dock menu for index {action_idx} not found");
+            return Some(1);
+        };
+        drop(lock);
+        callback(&*action);
+        self.state.borrow_mut().callbacks.app_menu_action = Some(callback);
+        Some(0)
+    }
+
+    fn handle_keyboard_layout_change(&self) -> Option<isize> {
+        let mut callback = self
+            .state
+            .borrow_mut()
+            .callbacks
+            .keyboard_layout_change
+            .take()?;
+        callback();
+        self.state.borrow_mut().callbacks.keyboard_layout_change = Some(callback);
+        Some(0)
+    }
+}
+
 impl Drop for WindowsPlatform {
     fn drop(&mut self) {
         unsafe {
+            DestroyWindow(self.handle)
+                .context("Destroying platform window")
+                .log_err();
             OleUninitialize();
         }
     }
@@ -719,10 +770,17 @@ pub(crate) struct WindowCreationInfo {
     pub(crate) drop_target_helper: IDropTargetHelper,
     pub(crate) validation_number: usize,
     pub(crate) main_receiver: flume::Receiver<Runnable>,
-    pub(crate) main_thread_id_win32: u32,
+    pub(crate) platform_window_handle: HWND,
     pub(crate) disable_direct_composition: bool,
 }
 
+struct PlatformWindowCreateContext {
+    inner: Option<Result<Rc<WindowsPlatformInner>>>,
+    raw_window_handles: std::sync::Weak<RwLock<SmallVec<[SafeHwnd; 4]>>>,
+    validation_number: usize,
+    main_receiver: Option<flume::Receiver<Runnable>>,
+}
+
 fn open_target(target: impl AsRef<OsStr>) -> Result<()> {
     let target = target.as_ref();
     let ret = unsafe {
@@ -893,6 +951,61 @@ fn should_auto_hide_scrollbars() -> Result<bool> {
     Ok(ui_settings.AutoHideScrollBars()?)
 }
 
+const PLATFORM_WINDOW_CLASS_NAME: PCWSTR = w!("Zed::PlatformWindow");
+
+fn register_platform_window_class() {
+    let wc = WNDCLASSW {
+        lpfnWndProc: Some(window_procedure),
+        lpszClassName: PCWSTR(PLATFORM_WINDOW_CLASS_NAME.as_ptr()),
+        ..Default::default()
+    };
+    unsafe { RegisterClassW(&wc) };
+}
+
+unsafe extern "system" fn window_procedure(
+    hwnd: HWND,
+    msg: u32,
+    wparam: WPARAM,
+    lparam: LPARAM,
+) -> LRESULT {
+    if msg == WM_NCCREATE {
+        let params = lparam.0 as *const CREATESTRUCTW;
+        let params = unsafe { &*params };
+        let creation_context = params.lpCreateParams as *mut PlatformWindowCreateContext;
+        let creation_context = unsafe { &mut *creation_context };
+        return match WindowsPlatformInner::new(creation_context) {
+            Ok(inner) => {
+                let weak = Box::new(Rc::downgrade(&inner));
+                unsafe { set_window_long(hwnd, GWLP_USERDATA, Box::into_raw(weak) as isize) };
+                creation_context.inner = Some(Ok(inner));
+                unsafe { DefWindowProcW(hwnd, msg, wparam, lparam) }
+            }
+            Err(error) => {
+                creation_context.inner = Some(Err(error));
+                LRESULT(0)
+            }
+        };
+    }
+
+    let ptr = unsafe { get_window_long(hwnd, GWLP_USERDATA) } as *mut Weak<WindowsPlatformInner>;
+    if ptr.is_null() {
+        return unsafe { DefWindowProcW(hwnd, msg, wparam, lparam) };
+    }
+    let inner = unsafe { &*ptr };
+    let result = if let Some(inner) = inner.upgrade() {
+        inner.handle_msg(hwnd, msg, wparam, lparam)
+    } else {
+        unsafe { DefWindowProcW(hwnd, msg, wparam, lparam) }
+    };
+
+    if msg == WM_NCDESTROY {
+        unsafe { set_window_long(hwnd, GWLP_USERDATA, 0) };
+        unsafe { drop(Box::from_raw(ptr)) };
+    }
+
+    result
+}
+
 #[cfg(test)]
 mod tests {
     use crate::{ClipboardItem, read_from_clipboard, write_to_clipboard};

crates/gpui/src/platform/windows/window.rs 🔗

@@ -73,7 +73,7 @@ pub(crate) struct WindowsWindowInner {
     pub(crate) windows_version: WindowsVersion,
     pub(crate) validation_number: usize,
     pub(crate) main_receiver: flume::Receiver<Runnable>,
-    pub(crate) main_thread_id_win32: u32,
+    pub(crate) platform_window_handle: HWND,
 }
 
 impl WindowsWindowState {
@@ -228,7 +228,7 @@ impl WindowsWindowInner {
             windows_version: context.windows_version,
             validation_number: context.validation_number,
             main_receiver: context.main_receiver.clone(),
-            main_thread_id_win32: context.main_thread_id_win32,
+            platform_window_handle: context.platform_window_handle,
         }))
     }
 
@@ -342,7 +342,7 @@ struct WindowCreateContext {
     drop_target_helper: IDropTargetHelper,
     validation_number: usize,
     main_receiver: flume::Receiver<Runnable>,
-    main_thread_id_win32: u32,
+    platform_window_handle: HWND,
     appearance: WindowAppearance,
     disable_direct_composition: bool,
 }
@@ -361,7 +361,7 @@ impl WindowsWindow {
             drop_target_helper,
             validation_number,
             main_receiver,
-            main_thread_id_win32,
+            platform_window_handle,
             disable_direct_composition,
         } = creation_info;
         register_window_class(icon);
@@ -419,7 +419,7 @@ impl WindowsWindow {
             drop_target_helper,
             validation_number,
             main_receiver,
-            main_thread_id_win32,
+            platform_window_handle,
             appearance,
             disable_direct_composition,
         };