Parse drop data
Only handling files for now
This commit is contained in:
parent
ef64cae538
commit
b5f3939930
|
@ -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", "ole2", "oleidl", "winerror"] }
|
winapi = { version = "0.3.8", features = ["libloaderapi", "winuser", "windef", "minwindef", "guiddef", "combaseapi", "wingdi", "errhandlingapi", "ole2", "oleidl", "shellapi", "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]
|
||||||
|
|
19
src/event.rs
19
src/event.rs
|
@ -1,3 +1,5 @@
|
||||||
|
use std::path::PathBuf;
|
||||||
|
|
||||||
use keyboard_types::{KeyboardEvent, Modifiers};
|
use keyboard_types::{KeyboardEvent, Modifiers};
|
||||||
|
|
||||||
use crate::{Point, WindowInfo};
|
use crate::{Point, WindowInfo};
|
||||||
|
@ -32,7 +34,7 @@ pub enum ScrollDelta {
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy, PartialEq)]
|
#[derive(Debug, Clone, PartialEq)]
|
||||||
pub enum MouseEvent {
|
pub enum MouseEvent {
|
||||||
/// The mouse cursor was moved
|
/// The mouse cursor was moved
|
||||||
CursorMoved {
|
CursorMoved {
|
||||||
|
@ -77,10 +79,16 @@ pub enum MouseEvent {
|
||||||
CursorLeft,
|
CursorLeft,
|
||||||
|
|
||||||
// TODO: Document
|
// TODO: Document
|
||||||
DragEntered,
|
DragEntered {
|
||||||
|
data: Option<DropData>,
|
||||||
|
},
|
||||||
|
|
||||||
DragMoved,
|
DragMoved,
|
||||||
DragLeft,
|
DragLeft,
|
||||||
DragDropped,
|
|
||||||
|
DragDropped {
|
||||||
|
data: Option<DropData>,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
|
@ -106,6 +114,11 @@ pub enum DropEffect {
|
||||||
Scroll,
|
Scroll,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, PartialEq)]
|
||||||
|
pub enum DropData {
|
||||||
|
Files(Vec<PathBuf>),
|
||||||
|
}
|
||||||
|
|
||||||
/// Return value for [WindowHandler::on_event](`crate::WindowHandler::on_event()`),
|
/// Return value for [WindowHandler::on_event](`crate::WindowHandler::on_event()`),
|
||||||
/// indicating whether the event was handled by your window or should be passed
|
/// indicating whether the event was handled by your window or should be passed
|
||||||
/// back to the platform.
|
/// back to the platform.
|
||||||
|
|
|
@ -4,10 +4,12 @@ use winapi::shared::minwindef::{ATOM, FALSE, LPARAM, LRESULT, UINT, WPARAM, DWOR
|
||||||
use winapi::shared::ntdef::{HRESULT, ULONG};
|
use winapi::shared::ntdef::{HRESULT, ULONG};
|
||||||
use winapi::shared::windef::{HWND, RECT, POINTL};
|
use winapi::shared::windef::{HWND, RECT, POINTL};
|
||||||
use winapi::shared::winerror::{S_OK, E_NOINTERFACE};
|
use winapi::shared::winerror::{S_OK, E_NOINTERFACE};
|
||||||
|
use winapi::shared::wtypes::DVASPECT_CONTENT;
|
||||||
use winapi::um::combaseapi::CoCreateGuid;
|
use winapi::um::combaseapi::CoCreateGuid;
|
||||||
use winapi::um::objidl::IDataObject;
|
use winapi::um::objidl::{IDataObject, STGMEDIUM, FORMATETC, TYMED_HGLOBAL};
|
||||||
use winapi::um::ole2::{RegisterDragDrop, OleInitialize};
|
use winapi::um::ole2::{RegisterDragDrop, OleInitialize};
|
||||||
use winapi::um::oleidl::{IDropTarget, IDropTargetVtbl, LPDROPTARGET, DROPEFFECT_COPY, DROPEFFECT_NONE, DROPEFFECT_MOVE, DROPEFFECT_LINK, DROPEFFECT_SCROLL};
|
use winapi::um::oleidl::{IDropTarget, IDropTargetVtbl, LPDROPTARGET, DROPEFFECT_COPY, DROPEFFECT_NONE, DROPEFFECT_MOVE, DROPEFFECT_LINK, DROPEFFECT_SCROLL};
|
||||||
|
use winapi::um::shellapi::DragQueryFileW;
|
||||||
use winapi::um::unknwnbase::{IUnknownVtbl, IUnknown};
|
use winapi::um::unknwnbase::{IUnknownVtbl, IUnknown};
|
||||||
use winapi::um::winuser::{
|
use winapi::um::winuser::{
|
||||||
AdjustWindowRectEx, CreateWindowExW, DefWindowProcW, DestroyWindow, DispatchMessageW,
|
AdjustWindowRectEx, CreateWindowExW, DefWindowProcW, DestroyWindow, DispatchMessageW,
|
||||||
|
@ -20,15 +22,16 @@ use winapi::um::winuser::{
|
||||||
WM_RBUTTONDOWN, WM_RBUTTONUP, WM_SHOWWINDOW, WM_SIZE, WM_SYSCHAR, WM_SYSKEYDOWN, WM_SYSKEYUP,
|
WM_RBUTTONDOWN, WM_RBUTTONUP, WM_SHOWWINDOW, WM_SIZE, WM_SYSCHAR, WM_SYSKEYDOWN, WM_SYSKEYUP,
|
||||||
WM_TIMER, WM_USER, WM_XBUTTONDOWN, WM_XBUTTONUP, WNDCLASSW, WS_CAPTION, WS_CHILD,
|
WM_TIMER, WM_USER, WM_XBUTTONDOWN, WM_XBUTTONUP, WNDCLASSW, WS_CAPTION, WS_CHILD,
|
||||||
WS_CLIPSIBLINGS, WS_MAXIMIZEBOX, WS_MINIMIZEBOX, WS_POPUPWINDOW, WS_SIZEBOX, WS_VISIBLE,
|
WS_CLIPSIBLINGS, WS_MAXIMIZEBOX, WS_MINIMIZEBOX, WS_POPUPWINDOW, WS_SIZEBOX, WS_VISIBLE,
|
||||||
XBUTTON1, XBUTTON2,
|
XBUTTON1, XBUTTON2, CF_HDROP,
|
||||||
};
|
};
|
||||||
|
|
||||||
use std::cell::{Cell, RefCell};
|
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, OsString};
|
||||||
use std::marker::PhantomData;
|
use std::marker::PhantomData;
|
||||||
use std::mem::transmute;
|
use std::mem::transmute;
|
||||||
use std::os::windows::ffi::OsStrExt;
|
use std::os::windows::ffi::OsStrExt;
|
||||||
|
use std::os::windows::prelude::OsStringExt;
|
||||||
use std::ptr::null_mut;
|
use std::ptr::null_mut;
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
@ -39,7 +42,7 @@ const BV_WINDOW_MUST_CLOSE: UINT = WM_USER + 1;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
Event, MouseButton, MouseEvent, PhyPoint, PhySize, ScrollDelta, Size, WindowEvent,
|
Event, MouseButton, MouseEvent, PhyPoint, PhySize, ScrollDelta, Size, WindowEvent,
|
||||||
WindowHandler, WindowInfo, WindowOpenOptions, WindowScalePolicy, DropEffect, EventStatus,
|
WindowHandler, WindowInfo, WindowOpenOptions, WindowScalePolicy, DropEffect, EventStatus, DropData,
|
||||||
};
|
};
|
||||||
|
|
||||||
use super::keyboard::KeyboardState;
|
use super::keyboard::KeyboardState;
|
||||||
|
@ -843,6 +846,49 @@ impl DropTarget {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn parse_drop_data(data_object: &IDataObject) -> Option<DropData> {
|
||||||
|
let format = FORMATETC {
|
||||||
|
cfFormat: CF_HDROP as u16,
|
||||||
|
ptd: null_mut(),
|
||||||
|
dwAspect: DVASPECT_CONTENT,
|
||||||
|
lindex: -1,
|
||||||
|
tymed: TYMED_HGLOBAL,
|
||||||
|
};
|
||||||
|
|
||||||
|
let mut medium = STGMEDIUM {
|
||||||
|
tymed: 0,
|
||||||
|
u: null_mut(),
|
||||||
|
pUnkForRelease: null_mut(),
|
||||||
|
};
|
||||||
|
|
||||||
|
unsafe {
|
||||||
|
let hresult = data_object.GetData(&format, &mut medium);
|
||||||
|
assert!(hresult == S_OK); // TODO: Error handling
|
||||||
|
|
||||||
|
let hdrop = transmute((*medium.u).hGlobal());
|
||||||
|
|
||||||
|
let item_count = DragQueryFileW(hdrop, 0xFFFFFFFF, null_mut(), 0);
|
||||||
|
if item_count == 0 {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut paths = Vec::with_capacity(item_count as usize);
|
||||||
|
|
||||||
|
for i in 0..item_count {
|
||||||
|
let characters = DragQueryFileW(hdrop, i, null_mut(), 0);
|
||||||
|
let buffer_size = characters as usize + 1;
|
||||||
|
let mut buffer = Vec::<u16>::with_capacity(buffer_size);
|
||||||
|
|
||||||
|
DragQueryFileW(hdrop, i, transmute(buffer.spare_capacity_mut().as_mut_ptr()), buffer_size as u32);
|
||||||
|
buffer.set_len(buffer_size);
|
||||||
|
|
||||||
|
paths.push(OsString::from_wide(&buffer[..characters as usize]).into())
|
||||||
|
}
|
||||||
|
|
||||||
|
Some(DropData::Files(paths))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
unsafe extern "system" fn query_interface(
|
unsafe extern "system" fn query_interface(
|
||||||
this: *mut IUnknown,
|
this: *mut IUnknown,
|
||||||
riid: REFIID,
|
riid: REFIID,
|
||||||
|
@ -888,7 +934,12 @@ impl DropTarget {
|
||||||
pdwEffect: *mut DWORD,
|
pdwEffect: *mut DWORD,
|
||||||
) -> HRESULT
|
) -> HRESULT
|
||||||
{
|
{
|
||||||
Self::on_event(this, Some(pdwEffect), MouseEvent::DragEntered {});
|
let data = Self::parse_drop_data(&*pDataObj);
|
||||||
|
let event = MouseEvent::DragEntered {
|
||||||
|
data
|
||||||
|
};
|
||||||
|
|
||||||
|
Self::on_event(this, Some(pdwEffect), event);
|
||||||
S_OK
|
S_OK
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -899,12 +950,13 @@ impl DropTarget {
|
||||||
pdwEffect: *mut DWORD,
|
pdwEffect: *mut DWORD,
|
||||||
) -> HRESULT
|
) -> HRESULT
|
||||||
{
|
{
|
||||||
Self::on_event(this, Some(pdwEffect), MouseEvent::DragMoved {});
|
let event = MouseEvent::DragMoved {};
|
||||||
|
Self::on_event(this, Some(pdwEffect), event);
|
||||||
S_OK
|
S_OK
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe extern "system" fn drag_leave(this: *mut IDropTarget) -> HRESULT {
|
unsafe extern "system" fn drag_leave(this: *mut IDropTarget) -> HRESULT {
|
||||||
Self::on_event(this, None, MouseEvent::DragLeft {});
|
Self::on_event(this, None, MouseEvent::DragLeft);
|
||||||
S_OK
|
S_OK
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -916,7 +968,12 @@ impl DropTarget {
|
||||||
pdwEffect: *mut DWORD,
|
pdwEffect: *mut DWORD,
|
||||||
) -> HRESULT
|
) -> HRESULT
|
||||||
{
|
{
|
||||||
Self::on_event(this, Some(pdwEffect), MouseEvent::DragDropped {});
|
let data = Self::parse_drop_data(&*pDataObj);
|
||||||
|
let event = MouseEvent::DragDropped {
|
||||||
|
data
|
||||||
|
};
|
||||||
|
|
||||||
|
Self::on_event(this, Some(pdwEffect), event);
|
||||||
S_OK
|
S_OK
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue