-
Notifications
You must be signed in to change notification settings - Fork 934
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
Rework DnD redux #4079
Conversation
008f86a
to
aa18119
Compare
aa18119
to
4f0819f
Compare
b6eba6b
to
fe7132e
Compare
There was a problem hiding this 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 .
window_id: WindowId::from_raw(drop_handler.window as usize), | ||
event: DragEnter { paths, position }, | ||
}); | ||
drop_handler.enter_is_valid = hdrop.is_some(); |
There was a problem hiding this comment.
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?
There was a problem hiding this comment.
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
There was a problem hiding this comment.
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?
There was a problem hiding this comment.
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)
There was a problem hiding this comment.
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?
@@ -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>>) { |
There was a problem hiding this comment.
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?)
There was a problem hiding this comment.
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;
There was a problem hiding this comment.
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
.
18849af
to
1084930
Compare
Made the requested review changes. |
window_id: WindowId::from_raw(drop_handler.window as usize), | ||
event: DragEnter { paths, position }, | ||
}); | ||
drop_handler.enter_is_valid = hdrop.is_some(); |
There was a problem hiding this comment.
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?
}; | ||
if let Some(hdrop) = hdrop { | ||
unsafe { DragFinish(hdrop) }; | ||
if drop_handler.enter_is_valid { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
can early return.
There was a problem hiding this comment.
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.
(Original work at rust-windowing#2615; rebased by @valadaptive)
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!`.
Not yet implemented on macOS
The Swift docs say the dragging info may be nullable here specifically: https://developer.apple.com/documentation/appkit/nsdraggingdestination/draggingexited(_:)
Keep everything in past-tense
Make it clearer that drag events are for dragged *files*, and remove the outdated bit about spurious DragLeft events.
Needed to display anything on Wayland. DnD still doesn't work on Wayland but the example should at least run.
It appears other apps (like Chromium) set pdwEffect on Drop too: https://github.com/chromium/chromium/blob/61a391b86bd946d6e1105412539e77ba9fb2a6b3/ui/base/dragdrop/drop_target_win.cc
7b82760
to
2153865
Compare
Made the requested review changes again. |
@madsmtm Still awaiting your review for the macOS parts. The main changes from #2615 are:
Would it be possible to get this in before #4092 to avoid having to do another rebase? |
There was a problem hiding this 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!
/// (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>, |
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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).
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.
changelog
module if knowledge of this change could be valuable to users