Wayland: render drag preview and overlays as child widgets instead of top-level Qt::Tool#837
Open
facontidavide wants to merge 1 commit intogithubuser0xFFFF:masterfrom
Open
Conversation
Wayland refuses client-driven placement of top-level windows in screen coordinates. CFloatingDragPreview, CDockOverlay, and CDockOverlayCross were all top-level Qt::Tool windows positioned via move(globalCoords) every mouse event, so under native Wayland the preview drifted off the cursor and the drop indicators rendered over the wrong dock area. Reparent all three to the dock manager's top-level window so they render as child widgets inside an existing surface, and drop the Linux X11 bypass-window-manager hint that only ever applied to top-levels. In moveFloating() / showOverlay() translate the screen-coord target into parent-local coordinates via mapFromGlobal() before move(). Replace windowHandle()->devicePixelRatio() with devicePixelRatioF() in updateOverlayIcons() - the former returns nullptr for a child widget and segfaulted as soon as the cross attempted to refresh icon DPR after reparenting. Add WA_TransparentForMouseEvents on preview and overlays so a release directly on a visible drop indicator is no longer intercepted by the translucent preview rectangle. This is an alternative to PR githubuser0xFFFF#789's Qt::ToolTip approach, which the author confirms still has unresolved overlay positioning issues on Wayland (see PR githubuser0xFFFF#789 thread, comment from 2025-11-29).
|
Glad to see you have some progress with QtAds on wayland. However, have you test the Demo on KDE wayland? On my CachyOS KDE wayland, the overlay still cannot be moved with following warning: So I think you cannot get rid of Qt::Popup flag although it will make floating window in trouble. Or you can find another solution. Still X11 is OK in my env with your patch. |
|
If you can fully solve the wayland issue, I will close PR myself. I keep my PR open to remind other people who need this workaround. Thanks for your contribution. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
First of all, thanks a lot for your software, I have been using it for years in Plotjuggler ❤️
While testing it on ubuntu 26.04, i found some problems that this PR is pparently fixing.
Sorry for the AI generated description that follows.
Summary
Under native Wayland, the drag preview drifts off the cursor and drop indicators render over the wrong dock area. This is because
CFloatingDragPreview,CDockOverlay, andCDockOverlayCrossare all top-levelQt::Toolwindows that the client repositions every mouse-move viamove(globalCoords). Wayland'sxdg_toplevelprotocol has no client-driven "move to (x,y)" verb — the compositor owns top-level placement — so thosemove()calls are silently lossy.This PR makes the three widgets child widgets of the dock manager's top-level window. Positioning happens inside the parent's surface via
parentWidget()->mapFromGlobal(...), which Qt translates correctly on every backend (xcb, Wayland, Windows, macOS).Why not just
Qt::ToolTip(PR #789)?PR #789 takes a different approach: keep the widgets as top-levels, swap the window flag from
Qt::TooltoQt::ToolTipso Wayland usesxdg_popup(which is client-positionable). It's a smaller patch, but the PR author themselves notes on 2025-11-29:The overlay positioning issue is the load-bearing visible bug.
Qt::ToolTippartially helps the floating preview but still leaves the overlay broken. The child-widget approach in this PR addresses both with one architectural decision: stop being top-level when you need parent-relative positioning that always honors client requests.PR #789 and this PR are mutually exclusive — pick one, not both.
What this PR changes
src/FloatingDragPreview.cpp:!DragPreviewHasWindowFrame), parent toparent->window()and drop theQt::Tool | Qt::FramelessWindowHintflag setup. AddWA_TransparentForMouseEventsso a release directly on a visible drop indicator is no longer intercepted by the translucent preview rectangle.moveFloating(): convert the screen-coord target to parent-local viamapFromGlobal()when the widget is a child. The legacy top-level path (isWindow() || !parentWidget()) is preserved forDragPreviewHasWindowFrame=true.startFloating():raise()aftershow()so the child preview paints above sibling docks.src/DockOverlay.cpp:CDockOverlayandCDockOverlayCrossconstructors: parent toparent->window(), drop theQt::Tool | FramelessWindowHint | WindowStaysOnTopHint | X11BypassWindowManagerHintblock (only meaningful for top-levels), addWA_TransparentForMouseEvents.CDockOverlay::showOverlay(): convert the target's top-left to parent-local beforemove().raise()aftershow().CDockOverlayCross::updatePosition(): simplified — both widgets share the same parent now, so the offset math is straightforward.raise()after move.CDockOverlayCross::updateOverlayIcons(): replacewindowHandle()->devicePixelRatio()withdevicePixelRatioF().windowHandle()returns nullptr for a child widget and the original code segfaults as soon as the cross attempts to refresh icon DPR after reparenting.What this PR does NOT change
DragPreviewHasWindowFrame=trueconfig (Windows-style framed preview) keeps the original top-levelQt::Windowpath. The cross-platform behavior on Windows is untouched.WindowStaysOnTopHint | X11BypassWindowManagerHintblock onQ_OS_UNIXwas tied to the top-levelQt::Toolwindow; with no top-level there's nothing to bypass.mousePress/mouseMove/mouseReleaseflow throughDockAreaTitleBar,DockWidgetTab, etc.) is untouched.Forecloses two known follow-ups from the #789 thread
Qt::ToolTip" (cristianadam, fix docking drag drop problem on Linux wayland #789): doesn't apply — we're not usingQt::ToolTip, and the preview's bounds are intentionally limited to the manager window for now (the typical rearrangement target is inside the app anyway).WindowStaysOnTopHintfor Wayland" (Wing-summer, fix docking drag drop problem on Linux wayland #789): doesn't apply — the StaysOnTop hint is only relevant for top-levels, and we're not top-level in this code path.Verification
A standalone reproducer is available at
PlotJuggler/PJ4(https://github.com/PlotJuggler/PJ4/tree/feature/m2-plot-canvas-skeleton/pj_plot_widgets/sandbox/dock_drag_repro). It mirrors a typical ADS embedding (HiddenTitleBar + custom toolbar puppet-forwarding to the title bar) without any extra widgets. SetPJ_AUTO_DRAG=1to fire a synthetic press / 8-step move / release sequence on dock A so the test runs without manual cursor input.Tested under Ubuntu 26.04, Qt 6.8.3:
QT_QPA_PLATFORM=xcb: drag works, identical UX to before this patch.QT_QPA_PLATFORM=wayland(native): drag works — preview tracks the cursor, drop indicators highlight correctly under the cursor's dock area, releases land on the indicated edge.Repo / branch
This PR comes from
PlotJuggler/Qt-Advanced-Docking-System:feature/wayland-fix, a single commit on top of upstream master985ff74. We're carrying it as a submodule pin in our PJ4 application; happy to rebase / split / amend per review feedback.