Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Rework DnD redux #4079

Merged
merged 24 commits into from
Jan 28, 2025
Merged

Conversation

valadaptive
Copy link
Contributor

@valadaptive valadaptive commented Jan 8, 2025

This picks up from #2615, rebasing it atop the latest winit version and fixing a couple coordinate-space bugs. Part of #720.

Resolves #1550. Closes #2615.

  • Tested on all platforms changed
    • Windows (low- and high-DPI)
    • macOS (low- and high-DPI)
    • Linux X11 (low- and high-DPI)
  • Added an entry to the changelog module if knowledge of this change could be valuable to users
  • Updated documentation to reflect any user-facing changes, including notes of platform-specific behavior
  • Created or updated an example program if it would help users understand this functionality

@valadaptive valadaptive mentioned this pull request Jan 8, 2025
8 tasks
@valadaptive valadaptive force-pushed the dnd-cursor-location-rebase branch from 008f86a to aa18119 Compare January 8, 2025 19:40
@valadaptive valadaptive changed the title DnD changes so far (rebased) Rework DnD redux Jan 8, 2025
@valadaptive valadaptive force-pushed the dnd-cursor-location-rebase branch from aa18119 to 4f0819f Compare January 8, 2025 19:42
@valadaptive valadaptive marked this pull request as ready for review January 8, 2025 19:50
@valadaptive valadaptive force-pushed the dnd-cursor-location-rebase branch 3 times, most recently from b6eba6b to fe7132e Compare January 9, 2025 19:26
Copy link
Member

@kchibisov kchibisov left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Will leave macOS re-review up to @madsmtm .

src/event.rs Outdated Show resolved Hide resolved
src/changelog/unreleased.md Outdated Show resolved Hide resolved
src/platform_impl/linux/x11/event_processor.rs Outdated Show resolved Hide resolved
src/platform_impl/linux/x11/event_processor.rs Outdated Show resolved Hide resolved
src/platform_impl/windows/drop_handler.rs Outdated Show resolved Hide resolved
window_id: WindowId::from_raw(drop_handler.window as usize),
event: DragEnter { paths, position },
});
drop_handler.enter_is_valid = hdrop.is_some();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if we want to utilize it, we should use it for sedening the Enter as well?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Changed it so no events are emitted if !enter_is_valid.

X11 has the opposite issue: if there are no valid files being dragged, it won't emit any drag start/position events but will emit DragLeave. That's a pre-existing issue (in the current master branch, it will emit HoveredFileCancelled without any prior HoveredFile events), but I'll go ahead and fix that too

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can't we stash whether the enter was emitted for X11?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes; it's already stored as self.dnd.has_entered (I'll push those changes)

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we actually need to do something when we have invalid drag from our perspective? Can't we early return throughout and do nothing?

src/event.rs Outdated Show resolved Hide resolved
src/event.rs Outdated Show resolved Hide resolved
@valadaptive valadaptive requested a review from kchibisov January 10, 2025 16:31
@@ -426,9 +457,16 @@ declare_class!(

/// Invoked when the dragging operation is cancelled
#[method(draggingExited:)]
fn dragging_exited(&self, _sender: Option<&NSObject>) {
fn dragging_exited(&self, info: Option<&ProtocolObject<dyn NSDraggingInfo>>) {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For @madsmtm: is this the right way to represent a sender param that may be null? The Swift docs note that for this specific callback, this parameter is nullable.

(As a side node, kinda alarming how the Objective-C docs just don't mention its nullability at all, as far as I can tell. Any idea what's going on there?)

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, this is correct, see also the docs in objc2-app-kit. In the future, I plan to make it required to have the same signature as in objc2-app-kit, but haven't gotten around to it yet.

The docs on Apple's website don't mention it, probably to be less verbose, but the header does contain a nullability attribute:

// AppKit.framework/Headers/NSDragging.h
- (void)draggingExited:(nullable id <NSDraggingInfo>)sender;

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: Please keep the name as sender.

@valadaptive valadaptive force-pushed the dnd-cursor-location-rebase branch from 18849af to 1084930 Compare January 10, 2025 17:28
@valadaptive
Copy link
Contributor Author

Made the requested review changes.

src/platform_impl/windows/drop_handler.rs Outdated Show resolved Hide resolved
src/platform_impl/windows/drop_handler.rs Outdated Show resolved Hide resolved
window_id: WindowId::from_raw(drop_handler.window as usize),
event: DragEnter { paths, position },
});
drop_handler.enter_is_valid = hdrop.is_some();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we actually need to do something when we have invalid drag from our perspective? Can't we early return throughout and do nothing?

src/platform_impl/windows/drop_handler.rs Outdated Show resolved Hide resolved
};
if let Some(hdrop) = hdrop {
unsafe { DragFinish(hdrop) };
if drop_handler.enter_is_valid {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can early return.

Copy link
Contributor Author

@valadaptive valadaptive Jan 17, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For some reason I can't comment on the above thread:

Do we actually need to do something when we have invalid drag from our perspective? Can't we early return throughout and do nothing?

Regarding this thread and that one, I believe we need to set pdwEffect regardless of whether the drag is valid, so we cannot early-return.

The Windows documentation says:

The IDropTarget::DragEnter method must choose one of these effects or disable the drop.

And for DragOver:

Upon return, pdwEffect is set to one of the DROPEFFECT flags.

It appears that other apps like Chromium set pdwEffect on all callbacks that pass it in.

An aside: Setting pdwEffect to DROPEFFECT_NONE doesn't work here and uses the "copy" cursor instead. I have no idea why. If you set it to any other value (e.g. DROPEFFECT_MOVE), it works. If you copy and paste this exact same drag-and-drop handler code into the windows-sys create_window example, it works properly and shows the "not allowed" cursor. I spent a few hours trying to figure this out to no avail, and this bug existed previously, so it's not a blocker.

In scenarios other than this specific one which doesn't work for unfathomable reasons, you do need to set DROPEFFECT_NONE on every frame or it'll reset to the "copy" cursor.

src/platform_impl/linux/x11/event_processor.rs Outdated Show resolved Hide resolved
src/platform_impl/linux/x11/event_processor.rs Outdated Show resolved Hide resolved
src/platform_impl/linux/x11/event_processor.rs Outdated Show resolved Hide resolved
src/platform_impl/linux/x11/dnd.rs Outdated Show resolved Hide resolved
amrbashir and others added 12 commits January 17, 2025 17:34
Fixes GTK drag-and-drop coords being offset by (-100, -100). The
relevant spec says:

> data.l[2] contains the coordinates of the mouse position relative
> to the root window.

https://www.freedesktop.org/wiki/Specifications/XDND/#xdndposition
We also need to use `convertPoint_fromView` for coordinate conversion--
attempting to do it manually resulted in (0, 0) being the top-left of
the window *including* decorations.
It's what translate_coords takes anyway, so the extra precision is
misleading if we're going to cast it to i16 everywhere it's used.

We can also simplify the "unpacking" from the XdndPosition message--we
can and should use the value of 16 as the shift instead of
size_of::<c_short> * 2 or something like that, because the specification
gives us the constant 16.
ProtocolObject is new in objc2, and lets us use the generated AppKit
bindings instead of roughing it with `msg_send!`.
@valadaptive valadaptive force-pushed the dnd-cursor-location-rebase branch from 7b82760 to 2153865 Compare January 17, 2025 22:35
@valadaptive valadaptive requested a review from kchibisov January 17, 2025 22:42
@valadaptive
Copy link
Contributor Author

Made the requested review changes again.

@valadaptive
Copy link
Contributor Author

@madsmtm Still awaiting your review for the macOS parts.

The main changes from #2615 are:

  • Switched from taking &NSObject as the sender param to &ProtocolObject<dyn NSDraggingInfo> in the drag callback methods (both the existing and new ones), which means we don't need to use msg_send_id!.
  • Used convertPoint_fromView to convert the drag coords to window-space instead of doing the transform manually. This correctly takes into account the size of the window frame-- (0, 0) is now the top-left corner of the window contents, excluding the title bar.

Would it be possible to get this in before #4092 to avoid having to do another rebase?

@madsmtm madsmtm mentioned this pull request Jan 28, 2025
Copy link
Member

@madsmtm madsmtm left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

API looks good, and AppKit impl looks good, thanks for rebasing this!

Comment on lines +182 to +185
/// (x,y) coordinates in pixels relative to the top-left corner of the window. May be
/// negative on some platforms if something is dragged over a window's decorations (title
/// bar, frame, etc).
position: PhysicalPosition<f64>,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: This extra text with "may be negative" sounds confusing, and probably only relevant on Wayland given that the coordinates are actually in window coordinates, and not surface coordinates. But that's to be resolved in #3891.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

By "surface coordinates", do you mean relative to the contents of the window? Because the drag position is currently in surface coordinates, to match the pointer position. Unless I'm misunderstanding.

If you run the dnd example and drag a file over the window's title bar, the y-position will be negative in macOS and Windows. On X11, no drag events are emitted unless you're dragging over the window's contents/surface.

Copy link
Contributor Author

@valadaptive valadaptive Jan 28, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My understanding is that "window coordinates" are relative to the top-left corner of the window including decorations, and that "surface coordinates" are relative to the top-left corner of the window's contents. Pointer events are in surface coordinates.

DnD events in Windows and X11 were also in surface coordinates in the original PR, so I changed macOS to match those platforms (EDIT: and also the pointer events).

@madsmtm madsmtm merged commit f5dcd2a into rust-windowing:master Jan 28, 2025
58 checks passed
@madsmtm madsmtm added this to the Version 0.31.0 milestone Jan 28, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Development

Successfully merging this pull request may close these issues.

Drag&Drop API / HoveredFile, DroppedFile
4 participants