From a067c16c823354da63966273ac15d1aa93c0e922 Mon Sep 17 00:00:00 2001 From: Matin Aniss <76515905+MatinAniss@users.noreply.github.com> Date: Mon, 23 Jun 2025 23:30:21 +1000 Subject: [PATCH] windows: Use drop target helper (#33203) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit It now utilises the [`IDropTargetHelper`](https://learn.microsoft.com/en-us/windows/win32/api/shobjidl_core/nn-shobjidl_core-idroptargethelper) in drag and drop events to render the proper item drop cursor icon which includes the thumbnail when available and action text. Also swaps the drop effect from `DROPEFFECT_LINK` to `DROPEFFECT_COPY` to match other Windows application behaviour. Example of drop icon ![example_drop](https://github.com/user-attachments/assets/4f8ea86c-929a-4813-9f8e-b3553ecf4d6e) Release Notes: - N/A --------- Co-authored-by: 张小白 <364772080@qq.com> --- crates/gpui/src/platform/windows/platform.rs | 8 +++++ crates/gpui/src/platform/windows/window.rs | 34 +++++++++++++++++--- 2 files changed, 37 insertions(+), 5 deletions(-) diff --git a/crates/gpui/src/platform/windows/platform.rs b/crates/gpui/src/platform/windows/platform.rs index 83e56ad3ae51b6fadb51e32ab77367e115de4357..2dc3c11c09ca9867a7cf75be8e2805a5ad6f4a37 100644 --- a/crates/gpui/src/platform/windows/platform.rs +++ b/crates/gpui/src/platform/windows/platform.rs @@ -42,6 +42,7 @@ pub(crate) struct WindowsPlatform { text_system: Arc, windows_version: WindowsVersion, bitmap_factory: ManuallyDrop, + drop_target_helper: IDropTargetHelper, validation_number: usize, main_thread_id_win32: u32, } @@ -103,6 +104,10 @@ impl WindowsPlatform { DirectWriteTextSystem::new(&bitmap_factory) .context("Error creating DirectWriteTextSystem")?, ); + let drop_target_helper: IDropTargetHelper = unsafe { + CoCreateInstance(&CLSID_DragDropHelper, None, CLSCTX_INPROC_SERVER) + .context("Error creating drop target helper.")? + }; let icon = load_icon().unwrap_or_default(); let state = RefCell::new(WindowsPlatformState::new()); let raw_window_handles = RwLock::new(SmallVec::new()); @@ -120,6 +125,7 @@ impl WindowsPlatform { text_system, windows_version, bitmap_factory, + drop_target_helper, validation_number, main_thread_id_win32, }) @@ -177,6 +183,7 @@ impl WindowsPlatform { executor: self.foreground_executor.clone(), current_cursor: self.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, @@ -728,6 +735,7 @@ pub(crate) struct WindowCreationInfo { pub(crate) executor: ForegroundExecutor, pub(crate) current_cursor: Option, pub(crate) windows_version: WindowsVersion, + pub(crate) drop_target_helper: IDropTargetHelper, pub(crate) validation_number: usize, pub(crate) main_receiver: flume::Receiver, pub(crate) main_thread_id_win32: u32, diff --git a/crates/gpui/src/platform/windows/window.rs b/crates/gpui/src/platform/windows/window.rs index b969a284b5d4b06366739054dac5264bd0aeb5fa..e84840fb25591ed0d25ab257b7db59eb0b7dd1b5 100644 --- a/crates/gpui/src/platform/windows/window.rs +++ b/crates/gpui/src/platform/windows/window.rs @@ -63,6 +63,7 @@ pub struct WindowsWindowState { pub(crate) struct WindowsWindowStatePtr { hwnd: HWND, this: Weak, + drop_target_helper: IDropTargetHelper, pub(crate) state: RefCell, pub(crate) handle: AnyWindowHandle, pub(crate) hide_title_bar: bool, @@ -210,6 +211,7 @@ impl WindowsWindowStatePtr { Ok(Rc::new_cyclic(|this| Self { hwnd, this: this.clone(), + drop_target_helper: context.drop_target_helper.clone(), state, handle: context.handle, hide_title_bar: context.hide_title_bar, @@ -331,6 +333,7 @@ struct WindowCreateContext<'a> { executor: ForegroundExecutor, current_cursor: Option, windows_version: WindowsVersion, + drop_target_helper: IDropTargetHelper, validation_number: usize, main_receiver: flume::Receiver, gpu_context: &'a BladeContext, @@ -349,6 +352,7 @@ impl WindowsWindow { executor, current_cursor, windows_version, + drop_target_helper, validation_number, main_receiver, main_thread_id_win32, @@ -394,6 +398,7 @@ impl WindowsWindow { executor, current_cursor, windows_version, + drop_target_helper, validation_number, main_receiver, gpu_context, @@ -831,8 +836,9 @@ impl IDropTarget_Impl for WindowsDragDropHandler_Impl { lindex: -1, tymed: TYMED_HGLOBAL.0 as _, }; + let cursor_position = POINT { x: pt.x, y: pt.y }; if idata_obj.QueryGetData(&config as _) == S_OK { - *pdweffect = DROPEFFECT_LINK; + *pdweffect = DROPEFFECT_COPY; let Some(mut idata) = idata_obj.GetData(&config as _).log_err() else { return Ok(()); }; @@ -847,7 +853,7 @@ impl IDropTarget_Impl for WindowsDragDropHandler_Impl { } }); ReleaseStgMedium(&mut idata); - let mut cursor_position = POINT { x: pt.x, y: pt.y }; + let mut cursor_position = cursor_position; ScreenToClient(self.0.hwnd, &mut cursor_position) .ok() .log_err(); @@ -864,6 +870,10 @@ impl IDropTarget_Impl for WindowsDragDropHandler_Impl { } else { *pdweffect = DROPEFFECT_NONE; } + self.0 + .drop_target_helper + .DragEnter(self.0.hwnd, idata_obj, &cursor_position, *pdweffect) + .log_err(); } Ok(()) } @@ -872,10 +882,15 @@ impl IDropTarget_Impl for WindowsDragDropHandler_Impl { &self, _grfkeystate: MODIFIERKEYS_FLAGS, pt: &POINTL, - _pdweffect: *mut DROPEFFECT, + pdweffect: *mut DROPEFFECT, ) -> windows::core::Result<()> { let mut cursor_position = POINT { x: pt.x, y: pt.y }; unsafe { + *pdweffect = DROPEFFECT_COPY; + self.0 + .drop_target_helper + .DragOver(&cursor_position, *pdweffect) + .log_err(); ScreenToClient(self.0.hwnd, &mut cursor_position) .ok() .log_err(); @@ -894,6 +909,9 @@ impl IDropTarget_Impl for WindowsDragDropHandler_Impl { } fn DragLeave(&self) -> windows::core::Result<()> { + unsafe { + self.0.drop_target_helper.DragLeave().log_err(); + } let input = PlatformInput::FileDrop(FileDropEvent::Exited); self.handle_drag_drop(input); @@ -902,13 +920,19 @@ impl IDropTarget_Impl for WindowsDragDropHandler_Impl { fn Drop( &self, - _pdataobj: windows::core::Ref, + pdataobj: windows::core::Ref, _grfkeystate: MODIFIERKEYS_FLAGS, pt: &POINTL, - _pdweffect: *mut DROPEFFECT, + pdweffect: *mut DROPEFFECT, ) -> windows::core::Result<()> { + let idata_obj = pdataobj.ok()?; let mut cursor_position = POINT { x: pt.x, y: pt.y }; unsafe { + *pdweffect = DROPEFFECT_COPY; + self.0 + .drop_target_helper + .Drop(idata_obj, &cursor_position, *pdweffect) + .log_err(); ScreenToClient(self.0.hwnd, &mut cursor_position) .ok() .log_err();