mirror of
https://github.com/italicsjenga/winit-sonoma-fix.git
synced 2024-12-24 06:11:30 +11:00
* Fix panic when dragging text onto a window on Windws (#697) * Changed `panic` to `debug` (log) when unknow error occurs in `GetData` while processing a drag-drop / hover event. Plus added appropriate cursor effect if hovered item can not be processed. * Improved code clarity. * Add documentation to clarify behaviour of `DroppedFile`, `HoveredFile`, and `HoveredFileCancelled` * Add period at the end of sentences in documentation.
This commit is contained in:
parent
b049a4dc66
commit
04ca2cf9f4
|
@ -7,6 +7,7 @@
|
||||||
- On Windows, fix issue where resizing or moving window would eat `Awakened` events.
|
- On Windows, fix issue where resizing or moving window would eat `Awakened` events.
|
||||||
- On X11, fixed a segfault when using virtual monitors with XRandR.
|
- On X11, fixed a segfault when using virtual monitors with XRandR.
|
||||||
- Derive `Ord` and `PartialOrd` for `VirtualKeyCode` enum.
|
- Derive `Ord` and `PartialOrd` for `VirtualKeyCode` enum.
|
||||||
|
- On Windows, fix issue where hovering or dropping a non file item would create a panic.
|
||||||
|
|
||||||
# Version 0.18.0 (2018-11-07)
|
# Version 0.18.0 (2018-11-07)
|
||||||
|
|
||||||
|
|
|
@ -37,12 +37,21 @@ pub enum WindowEvent {
|
||||||
Destroyed,
|
Destroyed,
|
||||||
|
|
||||||
/// A file has been dropped into the window.
|
/// A file has been dropped into the window.
|
||||||
|
///
|
||||||
|
/// When the user drops multiple files at once, this event will be emitted for each file
|
||||||
|
/// separately.
|
||||||
DroppedFile(PathBuf),
|
DroppedFile(PathBuf),
|
||||||
|
|
||||||
/// A file is being hovered over the window.
|
/// A file is being hovered over the window.
|
||||||
|
///
|
||||||
|
/// When the user hovers multiple files at once, this event will be emitted for each file
|
||||||
|
/// separately.
|
||||||
HoveredFile(PathBuf),
|
HoveredFile(PathBuf),
|
||||||
|
|
||||||
/// A file was hovered, but has exited the window.
|
/// A file was hovered, but has exited the window.
|
||||||
|
///
|
||||||
|
/// There will be a single `HoveredFileCancelled` event triggered even if multiple files were
|
||||||
|
/// hovered.
|
||||||
HoveredFileCancelled,
|
HoveredFileCancelled,
|
||||||
|
|
||||||
/// The window received a unicode character.
|
/// The window received a unicode character.
|
||||||
|
|
|
@ -10,7 +10,7 @@ use winapi::shared::minwindef::{DWORD, MAX_PATH, UINT, ULONG};
|
||||||
use winapi::shared::windef::{HWND, POINTL};
|
use winapi::shared::windef::{HWND, POINTL};
|
||||||
use winapi::shared::winerror::S_OK;
|
use winapi::shared::winerror::S_OK;
|
||||||
use winapi::um::objidl::IDataObject;
|
use winapi::um::objidl::IDataObject;
|
||||||
use winapi::um::oleidl::{IDropTarget, IDropTargetVtbl};
|
use winapi::um::oleidl::{DROPEFFECT_COPY, DROPEFFECT_NONE, IDropTarget, IDropTargetVtbl};
|
||||||
use winapi::um::winnt::HRESULT;
|
use winapi::um::winnt::HRESULT;
|
||||||
use winapi::um::{shellapi, unknwnbase};
|
use winapi::um::{shellapi, unknwnbase};
|
||||||
|
|
||||||
|
@ -24,6 +24,8 @@ pub struct FileDropHandlerData {
|
||||||
pub interface: IDropTarget,
|
pub interface: IDropTarget,
|
||||||
refcount: AtomicUsize,
|
refcount: AtomicUsize,
|
||||||
window: HWND,
|
window: HWND,
|
||||||
|
cursor_effect: DWORD,
|
||||||
|
hovered_is_valid: bool, // If the currently hovered item is not valid there must not be any `HoveredFileCancelled` emitted
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct FileDropHandler {
|
pub struct FileDropHandler {
|
||||||
|
@ -39,6 +41,8 @@ impl FileDropHandler {
|
||||||
},
|
},
|
||||||
refcount: AtomicUsize::new(1),
|
refcount: AtomicUsize::new(1),
|
||||||
window,
|
window,
|
||||||
|
cursor_effect: DROPEFFECT_NONE,
|
||||||
|
hovered_is_valid: false,
|
||||||
});
|
});
|
||||||
FileDropHandler {
|
FileDropHandler {
|
||||||
data: Box::into_raw(data),
|
data: Box::into_raw(data),
|
||||||
|
@ -77,36 +81,48 @@ impl FileDropHandler {
|
||||||
pDataObj: *const IDataObject,
|
pDataObj: *const IDataObject,
|
||||||
_grfKeyState: DWORD,
|
_grfKeyState: DWORD,
|
||||||
_pt: *const POINTL,
|
_pt: *const POINTL,
|
||||||
_pdwEffect: *mut DWORD,
|
pdwEffect: *mut DWORD,
|
||||||
) -> HRESULT {
|
) -> HRESULT {
|
||||||
use events::WindowEvent::HoveredFile;
|
use events::WindowEvent::HoveredFile;
|
||||||
let drop_handler = Self::from_interface(this);
|
let drop_handler = Self::from_interface(this);
|
||||||
Self::iterate_filenames(pDataObj, |filename| {
|
let hdrop = Self::iterate_filenames(pDataObj, |filename| {
|
||||||
send_event(Event::WindowEvent {
|
send_event(Event::WindowEvent {
|
||||||
window_id: SuperWindowId(WindowId(drop_handler.window)),
|
window_id: SuperWindowId(WindowId(drop_handler.window)),
|
||||||
event: HoveredFile(filename),
|
event: HoveredFile(filename),
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
drop_handler.hovered_is_valid = hdrop.is_some();
|
||||||
|
drop_handler.cursor_effect = if drop_handler.hovered_is_valid {
|
||||||
|
DROPEFFECT_COPY
|
||||||
|
} else {
|
||||||
|
DROPEFFECT_NONE
|
||||||
|
};
|
||||||
|
*pdwEffect = drop_handler.cursor_effect;
|
||||||
|
|
||||||
S_OK
|
S_OK
|
||||||
}
|
}
|
||||||
|
|
||||||
pub unsafe extern "system" fn DragOver(
|
pub unsafe extern "system" fn DragOver(
|
||||||
_this: *mut IDropTarget,
|
this: *mut IDropTarget,
|
||||||
_grfKeyState: DWORD,
|
_grfKeyState: DWORD,
|
||||||
_pt: *const POINTL,
|
_pt: *const POINTL,
|
||||||
_pdwEffect: *mut DWORD,
|
pdwEffect: *mut DWORD,
|
||||||
) -> HRESULT {
|
) -> HRESULT {
|
||||||
|
let drop_handler = Self::from_interface(this);
|
||||||
|
*pdwEffect = drop_handler.cursor_effect;
|
||||||
|
|
||||||
S_OK
|
S_OK
|
||||||
}
|
}
|
||||||
|
|
||||||
pub unsafe extern "system" fn DragLeave(this: *mut IDropTarget) -> HRESULT {
|
pub unsafe extern "system" fn DragLeave(this: *mut IDropTarget) -> HRESULT {
|
||||||
use events::WindowEvent::HoveredFileCancelled;
|
use events::WindowEvent::HoveredFileCancelled;
|
||||||
let drop_handler = Self::from_interface(this);
|
let drop_handler = Self::from_interface(this);
|
||||||
send_event(Event::WindowEvent {
|
if drop_handler.hovered_is_valid {
|
||||||
window_id: SuperWindowId(WindowId(drop_handler.window)),
|
send_event(Event::WindowEvent {
|
||||||
event: HoveredFileCancelled,
|
window_id: SuperWindowId(WindowId(drop_handler.window)),
|
||||||
});
|
event: HoveredFileCancelled,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
S_OK
|
S_OK
|
||||||
}
|
}
|
||||||
|
@ -126,7 +142,9 @@ impl FileDropHandler {
|
||||||
event: DroppedFile(filename),
|
event: DroppedFile(filename),
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
shellapi::DragFinish(hdrop);
|
if let Some(hdrop) = hdrop {
|
||||||
|
shellapi::DragFinish(hdrop);
|
||||||
|
}
|
||||||
|
|
||||||
S_OK
|
S_OK
|
||||||
}
|
}
|
||||||
|
@ -135,12 +153,12 @@ impl FileDropHandler {
|
||||||
&mut *(this as *mut _)
|
&mut *(this as *mut _)
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe fn iterate_filenames<F>(data_obj: *const IDataObject, callback: F) -> shellapi::HDROP
|
unsafe fn iterate_filenames<F>(data_obj: *const IDataObject, callback: F) -> Option<shellapi::HDROP>
|
||||||
where
|
where
|
||||||
F: Fn(PathBuf),
|
F: Fn(PathBuf),
|
||||||
{
|
{
|
||||||
use winapi::ctypes::wchar_t;
|
use winapi::ctypes::wchar_t;
|
||||||
use winapi::shared::winerror::SUCCEEDED;
|
use winapi::shared::winerror::{SUCCEEDED, DV_E_FORMATETC};
|
||||||
use winapi::shared::wtypes::{CLIPFORMAT, DVASPECT_CONTENT};
|
use winapi::shared::wtypes::{CLIPFORMAT, DVASPECT_CONTENT};
|
||||||
use winapi::um::objidl::{FORMATETC, TYMED_HGLOBAL};
|
use winapi::um::objidl::{FORMATETC, TYMED_HGLOBAL};
|
||||||
use winapi::um::shellapi::DragQueryFileW;
|
use winapi::um::shellapi::DragQueryFileW;
|
||||||
|
@ -155,7 +173,8 @@ impl FileDropHandler {
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut medium = mem::uninitialized();
|
let mut medium = mem::uninitialized();
|
||||||
if SUCCEEDED((*data_obj).GetData(&mut drop_format, &mut medium)) {
|
let get_data_result = (*data_obj).GetData(&mut drop_format, &mut medium);
|
||||||
|
if SUCCEEDED(get_data_result) {
|
||||||
let hglobal = (*medium.u).hGlobal();
|
let hglobal = (*medium.u).hGlobal();
|
||||||
let hdrop = (*hglobal) as shellapi::HDROP;
|
let hdrop = (*hglobal) as shellapi::HDROP;
|
||||||
|
|
||||||
|
@ -173,12 +192,16 @@ impl FileDropHandler {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return hdrop;
|
return Some(hdrop);
|
||||||
|
} else if get_data_result == DV_E_FORMATETC {
|
||||||
|
// If the dropped item is not a file this error will occur.
|
||||||
|
// In this case it is OK to return without taking further action.
|
||||||
|
debug!("Error occured while processing dropped/hovered item: item is not a file.");
|
||||||
|
return None;
|
||||||
|
} else {
|
||||||
|
debug!("Unexpected error occured while processing dropped/hovered item.");
|
||||||
|
return None;
|
||||||
}
|
}
|
||||||
|
|
||||||
// The call to `GetData` must succeed and the file handle must be returned before this
|
|
||||||
// point
|
|
||||||
unreachable!();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue