windows: Use drop target helper (#33203)
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  Release Notes: - N/A --------- Co-authored-by: 张小白 <364772080@qq.com>
This commit is contained in:
parent
1a6c1b2159
commit
a067c16c82
2 changed files with 37 additions and 5 deletions
|
@ -42,6 +42,7 @@ pub(crate) struct WindowsPlatform {
|
||||||
text_system: Arc<DirectWriteTextSystem>,
|
text_system: Arc<DirectWriteTextSystem>,
|
||||||
windows_version: WindowsVersion,
|
windows_version: WindowsVersion,
|
||||||
bitmap_factory: ManuallyDrop<IWICImagingFactory>,
|
bitmap_factory: ManuallyDrop<IWICImagingFactory>,
|
||||||
|
drop_target_helper: IDropTargetHelper,
|
||||||
validation_number: usize,
|
validation_number: usize,
|
||||||
main_thread_id_win32: u32,
|
main_thread_id_win32: u32,
|
||||||
}
|
}
|
||||||
|
@ -103,6 +104,10 @@ impl WindowsPlatform {
|
||||||
DirectWriteTextSystem::new(&bitmap_factory)
|
DirectWriteTextSystem::new(&bitmap_factory)
|
||||||
.context("Error creating DirectWriteTextSystem")?,
|
.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 icon = load_icon().unwrap_or_default();
|
||||||
let state = RefCell::new(WindowsPlatformState::new());
|
let state = RefCell::new(WindowsPlatformState::new());
|
||||||
let raw_window_handles = RwLock::new(SmallVec::new());
|
let raw_window_handles = RwLock::new(SmallVec::new());
|
||||||
|
@ -120,6 +125,7 @@ impl WindowsPlatform {
|
||||||
text_system,
|
text_system,
|
||||||
windows_version,
|
windows_version,
|
||||||
bitmap_factory,
|
bitmap_factory,
|
||||||
|
drop_target_helper,
|
||||||
validation_number,
|
validation_number,
|
||||||
main_thread_id_win32,
|
main_thread_id_win32,
|
||||||
})
|
})
|
||||||
|
@ -177,6 +183,7 @@ impl WindowsPlatform {
|
||||||
executor: self.foreground_executor.clone(),
|
executor: self.foreground_executor.clone(),
|
||||||
current_cursor: self.state.borrow().current_cursor,
|
current_cursor: self.state.borrow().current_cursor,
|
||||||
windows_version: self.windows_version,
|
windows_version: self.windows_version,
|
||||||
|
drop_target_helper: self.drop_target_helper.clone(),
|
||||||
validation_number: self.validation_number,
|
validation_number: self.validation_number,
|
||||||
main_receiver: self.main_receiver.clone(),
|
main_receiver: self.main_receiver.clone(),
|
||||||
main_thread_id_win32: self.main_thread_id_win32,
|
main_thread_id_win32: self.main_thread_id_win32,
|
||||||
|
@ -728,6 +735,7 @@ pub(crate) struct WindowCreationInfo {
|
||||||
pub(crate) executor: ForegroundExecutor,
|
pub(crate) executor: ForegroundExecutor,
|
||||||
pub(crate) current_cursor: Option<HCURSOR>,
|
pub(crate) current_cursor: Option<HCURSOR>,
|
||||||
pub(crate) windows_version: WindowsVersion,
|
pub(crate) windows_version: WindowsVersion,
|
||||||
|
pub(crate) drop_target_helper: IDropTargetHelper,
|
||||||
pub(crate) validation_number: usize,
|
pub(crate) validation_number: usize,
|
||||||
pub(crate) main_receiver: flume::Receiver<Runnable>,
|
pub(crate) main_receiver: flume::Receiver<Runnable>,
|
||||||
pub(crate) main_thread_id_win32: u32,
|
pub(crate) main_thread_id_win32: u32,
|
||||||
|
|
|
@ -63,6 +63,7 @@ pub struct WindowsWindowState {
|
||||||
pub(crate) struct WindowsWindowStatePtr {
|
pub(crate) struct WindowsWindowStatePtr {
|
||||||
hwnd: HWND,
|
hwnd: HWND,
|
||||||
this: Weak<Self>,
|
this: Weak<Self>,
|
||||||
|
drop_target_helper: IDropTargetHelper,
|
||||||
pub(crate) state: RefCell<WindowsWindowState>,
|
pub(crate) state: RefCell<WindowsWindowState>,
|
||||||
pub(crate) handle: AnyWindowHandle,
|
pub(crate) handle: AnyWindowHandle,
|
||||||
pub(crate) hide_title_bar: bool,
|
pub(crate) hide_title_bar: bool,
|
||||||
|
@ -210,6 +211,7 @@ impl WindowsWindowStatePtr {
|
||||||
Ok(Rc::new_cyclic(|this| Self {
|
Ok(Rc::new_cyclic(|this| Self {
|
||||||
hwnd,
|
hwnd,
|
||||||
this: this.clone(),
|
this: this.clone(),
|
||||||
|
drop_target_helper: context.drop_target_helper.clone(),
|
||||||
state,
|
state,
|
||||||
handle: context.handle,
|
handle: context.handle,
|
||||||
hide_title_bar: context.hide_title_bar,
|
hide_title_bar: context.hide_title_bar,
|
||||||
|
@ -331,6 +333,7 @@ struct WindowCreateContext<'a> {
|
||||||
executor: ForegroundExecutor,
|
executor: ForegroundExecutor,
|
||||||
current_cursor: Option<HCURSOR>,
|
current_cursor: Option<HCURSOR>,
|
||||||
windows_version: WindowsVersion,
|
windows_version: WindowsVersion,
|
||||||
|
drop_target_helper: IDropTargetHelper,
|
||||||
validation_number: usize,
|
validation_number: usize,
|
||||||
main_receiver: flume::Receiver<Runnable>,
|
main_receiver: flume::Receiver<Runnable>,
|
||||||
gpu_context: &'a BladeContext,
|
gpu_context: &'a BladeContext,
|
||||||
|
@ -349,6 +352,7 @@ impl WindowsWindow {
|
||||||
executor,
|
executor,
|
||||||
current_cursor,
|
current_cursor,
|
||||||
windows_version,
|
windows_version,
|
||||||
|
drop_target_helper,
|
||||||
validation_number,
|
validation_number,
|
||||||
main_receiver,
|
main_receiver,
|
||||||
main_thread_id_win32,
|
main_thread_id_win32,
|
||||||
|
@ -394,6 +398,7 @@ impl WindowsWindow {
|
||||||
executor,
|
executor,
|
||||||
current_cursor,
|
current_cursor,
|
||||||
windows_version,
|
windows_version,
|
||||||
|
drop_target_helper,
|
||||||
validation_number,
|
validation_number,
|
||||||
main_receiver,
|
main_receiver,
|
||||||
gpu_context,
|
gpu_context,
|
||||||
|
@ -831,8 +836,9 @@ impl IDropTarget_Impl for WindowsDragDropHandler_Impl {
|
||||||
lindex: -1,
|
lindex: -1,
|
||||||
tymed: TYMED_HGLOBAL.0 as _,
|
tymed: TYMED_HGLOBAL.0 as _,
|
||||||
};
|
};
|
||||||
|
let cursor_position = POINT { x: pt.x, y: pt.y };
|
||||||
if idata_obj.QueryGetData(&config as _) == S_OK {
|
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 {
|
let Some(mut idata) = idata_obj.GetData(&config as _).log_err() else {
|
||||||
return Ok(());
|
return Ok(());
|
||||||
};
|
};
|
||||||
|
@ -847,7 +853,7 @@ impl IDropTarget_Impl for WindowsDragDropHandler_Impl {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
ReleaseStgMedium(&mut idata);
|
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)
|
ScreenToClient(self.0.hwnd, &mut cursor_position)
|
||||||
.ok()
|
.ok()
|
||||||
.log_err();
|
.log_err();
|
||||||
|
@ -864,6 +870,10 @@ impl IDropTarget_Impl for WindowsDragDropHandler_Impl {
|
||||||
} else {
|
} else {
|
||||||
*pdweffect = DROPEFFECT_NONE;
|
*pdweffect = DROPEFFECT_NONE;
|
||||||
}
|
}
|
||||||
|
self.0
|
||||||
|
.drop_target_helper
|
||||||
|
.DragEnter(self.0.hwnd, idata_obj, &cursor_position, *pdweffect)
|
||||||
|
.log_err();
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
@ -872,10 +882,15 @@ impl IDropTarget_Impl for WindowsDragDropHandler_Impl {
|
||||||
&self,
|
&self,
|
||||||
_grfkeystate: MODIFIERKEYS_FLAGS,
|
_grfkeystate: MODIFIERKEYS_FLAGS,
|
||||||
pt: &POINTL,
|
pt: &POINTL,
|
||||||
_pdweffect: *mut DROPEFFECT,
|
pdweffect: *mut DROPEFFECT,
|
||||||
) -> windows::core::Result<()> {
|
) -> windows::core::Result<()> {
|
||||||
let mut cursor_position = POINT { x: pt.x, y: pt.y };
|
let mut cursor_position = POINT { x: pt.x, y: pt.y };
|
||||||
unsafe {
|
unsafe {
|
||||||
|
*pdweffect = DROPEFFECT_COPY;
|
||||||
|
self.0
|
||||||
|
.drop_target_helper
|
||||||
|
.DragOver(&cursor_position, *pdweffect)
|
||||||
|
.log_err();
|
||||||
ScreenToClient(self.0.hwnd, &mut cursor_position)
|
ScreenToClient(self.0.hwnd, &mut cursor_position)
|
||||||
.ok()
|
.ok()
|
||||||
.log_err();
|
.log_err();
|
||||||
|
@ -894,6 +909,9 @@ impl IDropTarget_Impl for WindowsDragDropHandler_Impl {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn DragLeave(&self) -> windows::core::Result<()> {
|
fn DragLeave(&self) -> windows::core::Result<()> {
|
||||||
|
unsafe {
|
||||||
|
self.0.drop_target_helper.DragLeave().log_err();
|
||||||
|
}
|
||||||
let input = PlatformInput::FileDrop(FileDropEvent::Exited);
|
let input = PlatformInput::FileDrop(FileDropEvent::Exited);
|
||||||
self.handle_drag_drop(input);
|
self.handle_drag_drop(input);
|
||||||
|
|
||||||
|
@ -902,13 +920,19 @@ impl IDropTarget_Impl for WindowsDragDropHandler_Impl {
|
||||||
|
|
||||||
fn Drop(
|
fn Drop(
|
||||||
&self,
|
&self,
|
||||||
_pdataobj: windows::core::Ref<IDataObject>,
|
pdataobj: windows::core::Ref<IDataObject>,
|
||||||
_grfkeystate: MODIFIERKEYS_FLAGS,
|
_grfkeystate: MODIFIERKEYS_FLAGS,
|
||||||
pt: &POINTL,
|
pt: &POINTL,
|
||||||
_pdweffect: *mut DROPEFFECT,
|
pdweffect: *mut DROPEFFECT,
|
||||||
) -> windows::core::Result<()> {
|
) -> windows::core::Result<()> {
|
||||||
|
let idata_obj = pdataobj.ok()?;
|
||||||
let mut cursor_position = POINT { x: pt.x, y: pt.y };
|
let mut cursor_position = POINT { x: pt.x, y: pt.y };
|
||||||
unsafe {
|
unsafe {
|
||||||
|
*pdweffect = DROPEFFECT_COPY;
|
||||||
|
self.0
|
||||||
|
.drop_target_helper
|
||||||
|
.Drop(idata_obj, &cursor_position, *pdweffect)
|
||||||
|
.log_err();
|
||||||
ScreenToClient(self.0.hwnd, &mut cursor_position)
|
ScreenToClient(self.0.hwnd, &mut cursor_position)
|
||||||
.ok()
|
.ok()
|
||||||
.log_err();
|
.log_err();
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue