1
0
Fork 0

Clean up ownership around WindowState and DropTarget

- WindowState no longer holds a reference to DropTarget
- DropTarget is passed to RegisterDragDrop() with Rc::into_raw() instead of Rc::as_ptr() so it keeps the reference
- WindowState is created with Rc instead of Box so DropTarget can hold a Rc to it
This commit is contained in:
Jussi Viiri 2023-06-10 22:47:22 +03:00
parent eb3a02115a
commit 481bf73293

View file

@ -160,7 +160,7 @@ unsafe extern "system" fn wnd_proc(
if msg == WM_NCDESTROY { if msg == WM_NCDESTROY {
unregister_wnd_class((*window_state_ptr).window_class); unregister_wnd_class((*window_state_ptr).window_class);
SetWindowLongPtrW(hwnd, GWLP_USERDATA, 0); SetWindowLongPtrW(hwnd, GWLP_USERDATA, 0);
drop(Box::from_raw(window_state_ptr)); drop(Rc::from_raw(window_state_ptr));
} }
// The actual custom window proc has been moved to another function so we can always handle // The actual custom window proc has been moved to another function so we can always handle
@ -471,7 +471,6 @@ 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<Rc<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,7 +665,7 @@ impl Window<'_> {
let (parent_handle, window_handle) = ParentHandle::new(hwnd); let (parent_handle, window_handle) = ParentHandle::new(hwnd);
let parent_handle = if parented { Some(parent_handle) } else { None }; let parent_handle = if parented { Some(parent_handle) } else { None };
let window_state = Box::new(WindowState { let window_state = Rc::new(WindowState {
hwnd, hwnd,
window_class, window_class,
window_info: RefCell::new(window_info), window_info: RefCell::new(window_info),
@ -678,7 +677,6 @@ 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)),
@ -724,15 +722,12 @@ impl Window<'_> {
None None
}; };
let window_state_ptr = Box::into_raw(window_state); let drop_target = Rc::new(DropTarget::new(window_state.clone()));
let drop_target = Rc::new(DropTarget::new(window_state_ptr));
OleInitialize(null_mut()); OleInitialize(null_mut());
RegisterDragDrop(hwnd, Rc::as_ptr(&drop_target) as LPDROPTARGET); RegisterDragDrop(hwnd, Rc::into_raw(drop_target) as LPDROPTARGET);
(*window_state_ptr)._drop_target = Some(drop_target); SetWindowLongPtrW(hwnd, GWLP_USERDATA, Rc::into_raw(window_state) as *const _ as _);
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 {
@ -789,18 +784,6 @@ pub fn copy_to_clipboard(data: &str) {
todo!() todo!()
} }
#[repr(C)]
pub struct DropTarget {
base: IDropTarget,
window_state: *mut WindowState,
// These are cached since DragOver and DragLeave callbacks don't provide them,
// and handling drag move events gets awkward on the client end otherwise
drag_position: Point,
drop_data: DropData,
}
// These function pointers have to be stored in a (const) variable before they can be transmuted // These function pointers have to be stored in a (const) variable before they can be transmuted
const DRAG_ENTER_PTR: unsafe extern "system" fn(this: *mut IDropTarget, pDataObj: *const IDataObject, grfKeyState: DWORD, pt: POINTL, pdwEffect: *mut DWORD) -> HRESULT = DropTarget::drag_enter; const DRAG_ENTER_PTR: unsafe extern "system" fn(this: *mut IDropTarget, pDataObj: *const IDataObject, grfKeyState: DWORD, pt: POINTL, pdwEffect: *mut DWORD) -> HRESULT = DropTarget::drag_enter;
const DRAG_OVER_PTR: unsafe extern "system" fn(this: *mut IDropTarget, grfKeyState: DWORD, pt: POINTL, pdwEffect: *mut DWORD) -> HRESULT = DropTarget::drag_over; const DRAG_OVER_PTR: unsafe extern "system" fn(this: *mut IDropTarget, grfKeyState: DWORD, pt: POINTL, pdwEffect: *mut DWORD) -> HRESULT = DropTarget::drag_over;
@ -817,8 +800,20 @@ const DROP_TARGET_VTBL: IDropTargetVtbl = IDropTargetVtbl {
Drop: unsafe { transmute(DROP_PTR) }, Drop: unsafe { transmute(DROP_PTR) },
}; };
#[repr(C)]
pub struct DropTarget {
base: IDropTarget,
window_state: Rc<WindowState>,
// These are cached since DragOver and DragLeave callbacks don't provide them,
// and handling drag move events gets awkward on the client end otherwise
drag_position: Point,
drop_data: DropData,
}
impl DropTarget { impl DropTarget {
fn new(window_state: *mut WindowState) -> Self { fn new(window_state: Rc<WindowState>) -> Self {
Self { Self {
base: IDropTarget { lpVtbl: &DROP_TARGET_VTBL }, base: IDropTarget { lpVtbl: &DROP_TARGET_VTBL },
@ -948,17 +943,14 @@ impl DropTarget {
) -> HRESULT ) -> HRESULT
{ {
let drop_target = &mut *(this as *mut DropTarget); let drop_target = &mut *(this as *mut DropTarget);
let window_state = unsafe { &*drop_target.window_state }; let modifiers = drop_target.window_state.keyboard_state.borrow().get_modifiers_from_mouse_wparam(grfKeyState as WPARAM);
drop_target.parse_coordinates(pt); drop_target.parse_coordinates(pt);
drop_target.parse_drop_data(&*pDataObj); drop_target.parse_drop_data(&*pDataObj);
let event = MouseEvent::DragEntered { let event = MouseEvent::DragEntered {
position: drop_target.drag_position, position: drop_target.drag_position,
modifiers: window_state modifiers,
.keyboard_state
.borrow()
.get_modifiers_from_mouse_wparam(grfKeyState as WPARAM),
data: drop_target.drop_data.clone(), data: drop_target.drop_data.clone(),
}; };
@ -974,16 +966,13 @@ impl DropTarget {
) -> HRESULT ) -> HRESULT
{ {
let drop_target = &mut *(this as *mut DropTarget); let drop_target = &mut *(this as *mut DropTarget);
let window_state = unsafe { &*drop_target.window_state }; let modifiers = drop_target.window_state.keyboard_state.borrow().get_modifiers_from_mouse_wparam(grfKeyState as WPARAM);
drop_target.parse_coordinates(pt); drop_target.parse_coordinates(pt);
let event = MouseEvent::DragMoved { let event = MouseEvent::DragMoved {
position: drop_target.drag_position, position: drop_target.drag_position,
modifiers: window_state modifiers,
.keyboard_state
.borrow()
.get_modifiers_from_mouse_wparam(grfKeyState as WPARAM),
data: drop_target.drop_data.clone(), data: drop_target.drop_data.clone(),
}; };
@ -1006,17 +995,14 @@ impl DropTarget {
) -> HRESULT ) -> HRESULT
{ {
let drop_target = &mut *(this as *mut DropTarget); let drop_target = &mut *(this as *mut DropTarget);
let window_state = unsafe { &*drop_target.window_state }; let modifiers = drop_target.window_state.keyboard_state.borrow().get_modifiers_from_mouse_wparam(grfKeyState as WPARAM);
drop_target.parse_coordinates(pt); drop_target.parse_coordinates(pt);
drop_target.parse_drop_data(&*pDataObj); drop_target.parse_drop_data(&*pDataObj);
let event = MouseEvent::DragDropped { let event = MouseEvent::DragDropped {
position: drop_target.drag_position, position: drop_target.drag_position,
modifiers: window_state modifiers,
.keyboard_state
.borrow()
.get_modifiers_from_mouse_wparam(grfKeyState as WPARAM),
data: drop_target.drop_data.clone(), data: drop_target.drop_data.clone(),
}; };