Janky first version of drag and drop
Just recognized as a drop target
This commit is contained in:
parent
c129b12ead
commit
0eff674319
|
@ -29,7 +29,7 @@ xcb-util = { version = "0.3", features = ["icccm"] }
|
||||||
nix = "0.22.0"
|
nix = "0.22.0"
|
||||||
|
|
||||||
[target.'cfg(target_os="windows")'.dependencies]
|
[target.'cfg(target_os="windows")'.dependencies]
|
||||||
winapi = { version = "0.3.8", features = ["libloaderapi", "winuser", "windef", "minwindef", "guiddef", "combaseapi", "wingdi", "errhandlingapi"] }
|
winapi = { version = "0.3.8", features = ["libloaderapi", "winuser", "windef", "minwindef", "guiddef", "combaseapi", "wingdi", "errhandlingapi", "ole2", "oleidl", "winerror"] }
|
||||||
uuid = { version = "0.8", features = ["v4"], optional = true }
|
uuid = { version = "0.8", features = ["v4"], optional = true }
|
||||||
|
|
||||||
[target.'cfg(target_os="macos")'.dependencies]
|
[target.'cfg(target_os="macos")'.dependencies]
|
||||||
|
|
|
@ -75,6 +75,12 @@ pub enum MouseEvent {
|
||||||
///
|
///
|
||||||
/// May not be available on all platforms.
|
/// May not be available on all platforms.
|
||||||
CursorLeft,
|
CursorLeft,
|
||||||
|
|
||||||
|
// TODO: Document
|
||||||
|
DragEntered,
|
||||||
|
DragMoved,
|
||||||
|
DragLeft,
|
||||||
|
DragDropped,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
|
|
|
@ -1,7 +1,14 @@
|
||||||
use winapi::shared::guiddef::GUID;
|
use winapi::Interface;
|
||||||
use winapi::shared::minwindef::{ATOM, FALSE, LPARAM, LRESULT, UINT, WPARAM};
|
use winapi::shared::guiddef::{GUID, REFIID, IsEqualIID};
|
||||||
use winapi::shared::windef::{HWND, RECT};
|
use winapi::shared::minwindef::{ATOM, FALSE, LPARAM, LRESULT, UINT, WPARAM, DWORD};
|
||||||
|
use winapi::shared::ntdef::{HRESULT, ULONG};
|
||||||
|
use winapi::shared::windef::{HWND, RECT, POINTL};
|
||||||
|
use winapi::shared::winerror::{S_OK, E_NOINTERFACE};
|
||||||
use winapi::um::combaseapi::CoCreateGuid;
|
use winapi::um::combaseapi::CoCreateGuid;
|
||||||
|
use winapi::um::objidl::IDataObject;
|
||||||
|
use winapi::um::ole2::{RegisterDragDrop, OleInitialize};
|
||||||
|
use winapi::um::oleidl::{IDropTarget, IDropTargetVtbl, LPDROPTARGET, DROPEFFECT_COPY};
|
||||||
|
use winapi::um::unknwnbase::{IUnknownVtbl, IUnknown};
|
||||||
use winapi::um::winuser::{
|
use winapi::um::winuser::{
|
||||||
AdjustWindowRectEx, CreateWindowExW, DefWindowProcW, DestroyWindow, DispatchMessageW,
|
AdjustWindowRectEx, CreateWindowExW, DefWindowProcW, DestroyWindow, DispatchMessageW,
|
||||||
GetDpiForWindow, GetMessageW, GetWindowLongPtrW, LoadCursorW, PostMessageW, RegisterClassW,
|
GetDpiForWindow, GetMessageW, GetWindowLongPtrW, LoadCursorW, PostMessageW, RegisterClassW,
|
||||||
|
@ -20,9 +27,11 @@ use std::cell::{Cell, RefCell};
|
||||||
use std::collections::VecDeque;
|
use std::collections::VecDeque;
|
||||||
use std::ffi::{c_void, OsStr};
|
use std::ffi::{c_void, OsStr};
|
||||||
use std::marker::PhantomData;
|
use std::marker::PhantomData;
|
||||||
|
use std::mem::transmute;
|
||||||
use std::os::windows::ffi::OsStrExt;
|
use std::os::windows::ffi::OsStrExt;
|
||||||
use std::ptr::null_mut;
|
use std::ptr::null_mut;
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
|
use std::sync::Arc;
|
||||||
|
|
||||||
use raw_window_handle::{HasRawWindowHandle, RawWindowHandle, Win32Handle};
|
use raw_window_handle::{HasRawWindowHandle, RawWindowHandle, Win32Handle};
|
||||||
|
|
||||||
|
@ -460,6 +469,7 @@ struct WindowState {
|
||||||
handler: RefCell<Option<Box<dyn WindowHandler>>>,
|
handler: RefCell<Option<Box<dyn WindowHandler>>>,
|
||||||
scale_policy: WindowScalePolicy,
|
scale_policy: WindowScalePolicy,
|
||||||
dw_style: u32,
|
dw_style: u32,
|
||||||
|
_drop_target: Option<Arc<DropTarget>>,
|
||||||
|
|
||||||
/// Tasks that should be executed at the end of `wnd_proc`. This is needed to avoid mutably
|
/// Tasks that should be executed at the end of `wnd_proc`. This is needed to avoid mutably
|
||||||
/// borrowing the fields from `WindowState` more than once. For instance, when the window
|
/// borrowing the fields from `WindowState` more than once. For instance, when the window
|
||||||
|
@ -666,6 +676,7 @@ impl Window<'_> {
|
||||||
handler: RefCell::new(None),
|
handler: RefCell::new(None),
|
||||||
scale_policy: options.scale,
|
scale_policy: options.scale,
|
||||||
dw_style: flags,
|
dw_style: flags,
|
||||||
|
_drop_target: None,
|
||||||
|
|
||||||
deferred_tasks: RefCell::new(VecDeque::with_capacity(4)),
|
deferred_tasks: RefCell::new(VecDeque::with_capacity(4)),
|
||||||
|
|
||||||
|
@ -711,7 +722,19 @@ impl Window<'_> {
|
||||||
None
|
None
|
||||||
};
|
};
|
||||||
|
|
||||||
SetWindowLongPtrW(hwnd, GWLP_USERDATA, Box::into_raw(window_state) as *const _ as _);
|
let window_state_ptr = Box::into_raw(window_state);
|
||||||
|
|
||||||
|
// TODO: Error handling
|
||||||
|
OleInitialize(null_mut());
|
||||||
|
|
||||||
|
let drop_target = Arc::new(DropTarget::new(window_state_ptr));
|
||||||
|
|
||||||
|
// TODO: Error handling
|
||||||
|
RegisterDragDrop(hwnd, Arc::as_ptr(&drop_target) as LPDROPTARGET);
|
||||||
|
|
||||||
|
(*window_state_ptr)._drop_target = Some(drop_target);
|
||||||
|
|
||||||
|
SetWindowLongPtrW(hwnd, GWLP_USERDATA, window_state_ptr as *const _ as _);
|
||||||
SetTimer(hwnd, WIN_FRAME_TIMER, 15, None);
|
SetTimer(hwnd, WIN_FRAME_TIMER, 15, None);
|
||||||
|
|
||||||
if let Some(mut new_rect) = new_rect {
|
if let Some(mut new_rect) = new_rect {
|
||||||
|
@ -767,3 +790,146 @@ unsafe impl HasRawWindowHandle for Window<'_> {
|
||||||
pub fn copy_to_clipboard(data: &str) {
|
pub fn copy_to_clipboard(data: &str) {
|
||||||
todo!()
|
todo!()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[repr(C)]
|
||||||
|
pub struct DropTarget {
|
||||||
|
base: IDropTarget,
|
||||||
|
vtbl: Arc<IDropTargetVtbl>,
|
||||||
|
|
||||||
|
window_state: *mut WindowState,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl DropTarget {
|
||||||
|
fn new(window_state: *mut WindowState) -> Self {
|
||||||
|
let vtbl = Arc::new(IDropTargetVtbl {
|
||||||
|
parent: IUnknownVtbl {
|
||||||
|
QueryInterface: Self::query_interface,
|
||||||
|
AddRef: Self::add_ref,
|
||||||
|
Release: Self::release,
|
||||||
|
},
|
||||||
|
DragEnter: Self::drag_enter,
|
||||||
|
DragOver: Self::drag_over,
|
||||||
|
DragLeave: Self::drag_leave,
|
||||||
|
Drop: Self::drop,
|
||||||
|
});
|
||||||
|
|
||||||
|
Self {
|
||||||
|
base: IDropTarget { lpVtbl: Arc::as_ptr(&vtbl) },
|
||||||
|
vtbl,
|
||||||
|
|
||||||
|
window_state,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe extern "system" fn query_interface(
|
||||||
|
this: *mut IUnknown,
|
||||||
|
riid: REFIID,
|
||||||
|
ppvObject: *mut *mut winapi::ctypes::c_void,
|
||||||
|
) -> HRESULT
|
||||||
|
{
|
||||||
|
println!("query_interface");
|
||||||
|
|
||||||
|
if IsEqualIID(&*riid, &IUnknown::uuidof()) || IsEqualIID(&*riid, &IDropTarget::uuidof()){
|
||||||
|
Self::add_ref(this);
|
||||||
|
*ppvObject = unsafe { transmute(this) };
|
||||||
|
return S_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
return E_NOINTERFACE;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe extern "system" fn add_ref(this: *mut IUnknown) -> ULONG {
|
||||||
|
let arc = Arc::from_raw(this);
|
||||||
|
let result = Arc::strong_count(&arc) + 1;
|
||||||
|
let _ = Arc::into_raw(arc);
|
||||||
|
|
||||||
|
Arc::increment_strong_count(this);
|
||||||
|
|
||||||
|
result as ULONG
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe extern "system" fn release(this: *mut IUnknown) -> ULONG {
|
||||||
|
let arc = Arc::from_raw(this);
|
||||||
|
let result = Arc::strong_count(&arc) - 1;
|
||||||
|
let _ = Arc::into_raw(arc);
|
||||||
|
|
||||||
|
Arc::decrement_strong_count(this);
|
||||||
|
|
||||||
|
result as ULONG
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe extern "system" fn drag_enter(
|
||||||
|
this: *mut IDropTarget,
|
||||||
|
pDataObj: *const IDataObject,
|
||||||
|
grfKeyState: DWORD,
|
||||||
|
pt: *const POINTL,
|
||||||
|
pdwEffect: *mut DWORD,
|
||||||
|
) -> HRESULT
|
||||||
|
{
|
||||||
|
let drop_target = &*(this as *mut DropTarget);
|
||||||
|
let window_state = &*drop_target.window_state;
|
||||||
|
let mut window = window_state.create_window();
|
||||||
|
let mut window = crate::Window::new(&mut window);
|
||||||
|
|
||||||
|
let event = Event::Mouse(MouseEvent::DragEntered {});
|
||||||
|
window_state.handler.borrow_mut().as_mut().unwrap().on_event(&mut window, event);
|
||||||
|
|
||||||
|
*pdwEffect = DROPEFFECT_COPY;
|
||||||
|
|
||||||
|
S_OK
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe extern "system" fn drag_over(
|
||||||
|
this: *mut IDropTarget,
|
||||||
|
grfKeyState: DWORD,
|
||||||
|
pt: *const POINTL,
|
||||||
|
pdwEffect: *mut DWORD,
|
||||||
|
) -> HRESULT
|
||||||
|
{
|
||||||
|
let drop_target = &*(this as *mut DropTarget);
|
||||||
|
let window_state = &*drop_target.window_state;
|
||||||
|
let mut window = window_state.create_window();
|
||||||
|
let mut window = crate::Window::new(&mut window);
|
||||||
|
|
||||||
|
let event = Event::Mouse(MouseEvent::DragMoved {});
|
||||||
|
window_state.handler.borrow_mut().as_mut().unwrap().on_event(&mut window, event);
|
||||||
|
|
||||||
|
*pdwEffect = DROPEFFECT_COPY;
|
||||||
|
|
||||||
|
S_OK
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe extern "system" fn drag_leave(this: *mut IDropTarget) -> HRESULT {
|
||||||
|
let drop_target = &*(this as *mut DropTarget);
|
||||||
|
let window_state = &*drop_target.window_state;
|
||||||
|
let mut window = window_state.create_window();
|
||||||
|
let mut window = crate::Window::new(&mut window);
|
||||||
|
|
||||||
|
let event = Event::Mouse(MouseEvent::DragLeft {});
|
||||||
|
|
||||||
|
window_state.handler.borrow_mut().as_mut().unwrap().on_event(&mut window, event);
|
||||||
|
|
||||||
|
S_OK
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe extern "system" fn drop(
|
||||||
|
this: *mut IDropTarget,
|
||||||
|
pDataObj: *const IDataObject,
|
||||||
|
grfKeyState: DWORD,
|
||||||
|
pt: *const POINTL,
|
||||||
|
pdwEffect: *mut DWORD,
|
||||||
|
) -> HRESULT
|
||||||
|
{
|
||||||
|
let drop_target = &*(this as *mut DropTarget);
|
||||||
|
let window_state = &*drop_target.window_state;
|
||||||
|
let mut window = window_state.create_window();
|
||||||
|
let mut window = crate::Window::new(&mut window);
|
||||||
|
|
||||||
|
let event = Event::Mouse(MouseEvent::DragDropped {});
|
||||||
|
window_state.handler.borrow_mut().as_mut().unwrap().on_event(&mut window, event);
|
||||||
|
|
||||||
|
*pdwEffect = DROPEFFECT_COPY;
|
||||||
|
|
||||||
|
S_OK
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in a new issue