diff --git a/src/DockOverlay.cpp b/src/DockOverlay.cpp index 3ae43a2d..60baa28d 100644 --- a/src/DockOverlay.cpp +++ b/src/DockOverlay.cpp @@ -397,21 +397,20 @@ int DockOverlayPrivate::sideBarMouseZone(SideBarLocation sideBarLocation) //============================================================================ +// Wayland: parent the overlay to the manager's top-level window and drop +// the Qt::Tool flags. Top-level placement in screen coordinates is unreliable +// under Wayland, which left the indicators stuck over the wrong dock area. CDockOverlay::CDockOverlay(QWidget* parent, eMode Mode) : - QFrame(parent), + QFrame(parent ? parent->window() : nullptr), d(new DockOverlayPrivate(this)) { d->Mode = Mode; d->Cross = new CDockOverlayCross(this); -#if defined(Q_OS_UNIX) && !defined(Q_OS_MACOS) - setWindowFlags(Qt::Tool | Qt::FramelessWindowHint | Qt::WindowStaysOnTopHint | Qt::X11BypassWindowManagerHint); -#else - setWindowFlags(Qt::Tool | Qt::FramelessWindowHint); -#endif setWindowOpacity(1); setWindowTitle("DockOverlay"); setAttribute(Qt::WA_NoSystemBackground); setAttribute(Qt::WA_TranslucentBackground); + setAttribute(Qt::WA_TransparentForMouseEvents); d->Cross->setVisible(false); setVisible(false); @@ -570,9 +569,10 @@ DockWidgetArea CDockOverlay::showOverlay(QWidget* target) // Move it over the target. hide(); resize(target->size()); - QPoint TopLeft = target->mapToGlobal(target->rect().topLeft()); - move(TopLeft); + const QPoint TopLeftGlobal = target->mapToGlobal(target->rect().topLeft()); + move(parentWidget() ? parentWidget()->mapFromGlobal(TopLeftGlobal) : TopLeftGlobal); show(); + raise(); d->Cross->updatePosition(); d->Cross->updateOverlayIcons(); return dropAreaUnderCursor(); @@ -733,18 +733,15 @@ QPoint DockOverlayCrossPrivate::areaGridPosition(const DockWidgetArea area) //============================================================================ +// Wayland: see CDockOverlay above for the rationale. CDockOverlayCross::CDockOverlayCross(CDockOverlay* overlay) : - QWidget(overlay->parentWidget()), + QWidget(overlay->parentWidget() ? overlay->parentWidget()->window() : nullptr), d(new DockOverlayCrossPrivate(this)) { d->DockOverlay = overlay; -#if defined(Q_OS_UNIX) && !defined(Q_OS_MACOS) - setWindowFlags(Qt::Tool | Qt::FramelessWindowHint | Qt::WindowStaysOnTopHint | Qt::X11BypassWindowManagerHint); -#else - setWindowFlags(Qt::Tool | Qt::FramelessWindowHint); -#endif setWindowTitle("DockOverlayCross"); setAttribute(Qt::WA_TranslucentBackground); + setAttribute(Qt::WA_TransparentForMouseEvents); d->GridLayout = new QGridLayout(); d->GridLayout->setSpacing(0); @@ -784,7 +781,10 @@ void CDockOverlayCross::setupOverlayCross(CDockOverlay::eMode Mode) //============================================================================ void CDockOverlayCross::updateOverlayIcons() { - if (windowHandle()->devicePixelRatio() == d->LastDevicePixelRatio) + // Wayland: devicePixelRatioF() walks the parent chain; the original + // windowHandle()->devicePixelRatio() segfaults for a child widget. + const qreal CurrentRatio = devicePixelRatioF(); + if (CurrentRatio == d->LastDevicePixelRatio) { return; } @@ -793,11 +793,7 @@ void CDockOverlayCross::updateOverlayIcons() { d->updateDropIndicatorIcon(Widget); } -#if QT_VERSION >= 0x050600 - d->LastDevicePixelRatio = devicePixelRatioF(); -#else - d->LastDevicePixelRatio = devicePixelRatio(); -#endif + d->LastDevicePixelRatio = CurrentRatio; } @@ -911,11 +907,10 @@ void CDockOverlayCross::showEvent(QShowEvent*) void CDockOverlayCross::updatePosition() { resize(d->DockOverlay->size()); - QPoint TopLeft = d->DockOverlay->pos(); - QPoint Offest((this->width() - d->DockOverlay->width()) / 2, + const QPoint Offset((this->width() - d->DockOverlay->width()) / 2, (this->height() - d->DockOverlay->height()) / 2); - QPoint CrossTopLeft = TopLeft - Offest; - move(CrossTopLeft); + move(d->DockOverlay->pos() - Offset); + raise(); } diff --git a/src/FloatingDragPreview.cpp b/src/FloatingDragPreview.cpp index f7a45a2b..ced26431 100644 --- a/src/FloatingDragPreview.cpp +++ b/src/FloatingDragPreview.cpp @@ -276,8 +276,14 @@ void FloatingDragPreviewPrivate::createFloatingWidget() //============================================================================ +// Wayland: in the frameless config, parent the preview to the manager's +// top-level window so it renders as a translucent child instead of a Qt::Tool +// top-level. Wayland refuses to honour client-driven move() of top-levels in +// screen coordinates; child widgets work on every backend. CFloatingDragPreview::CFloatingDragPreview(QWidget* Content, QWidget* parent) : - QWidget(parent), + QWidget((parent && !CDockManager::testConfigFlag(CDockManager::DragPreviewHasWindowFrame)) + ? parent->window() + : parent), d(new FloatingDragPreviewPrivate(this)) { d->Content = Content; @@ -287,20 +293,21 @@ CFloatingDragPreview::CFloatingDragPreview(QWidget* Content, QWidget* parent) : { setWindowFlags( Qt::Window | Qt::WindowMaximizeButtonHint | Qt::WindowCloseButtonHint); + +#if defined(Q_OS_UNIX) && !defined(Q_OS_MACOS) + auto Flags = windowFlags(); + Flags |= Qt::WindowStaysOnTopHint | Qt::X11BypassWindowManagerHint; + setWindowFlags(Flags); +#endif } else { - setWindowFlags(Qt::Tool | Qt::FramelessWindowHint); setAttribute(Qt::WA_NoSystemBackground); setAttribute(Qt::WA_TranslucentBackground); + // Let releases over visible drop indicators fall through to them. + setAttribute(Qt::WA_TransparentForMouseEvents); } -#if defined(Q_OS_UNIX) && !defined(Q_OS_MACOS) - auto Flags = windowFlags(); - Flags |= Qt::WindowStaysOnTopHint | Qt::X11BypassWindowManagerHint; - setWindowFlags(Flags); -#endif - // Create a static image of the widget that should get undocked // This is like some kind preview image like it is uses in drag and drop // operations @@ -352,10 +359,20 @@ CFloatingDragPreview::~CFloatingDragPreview() //============================================================================ void CFloatingDragPreview::moveFloating() { - int BorderSize = (frameSize().width() - size().width()) / 2; - const QPoint moveToPos = QCursor::pos() - d->DragStartMousePosition + const int BorderSize = (frameSize().width() - size().width()) / 2; + const QPoint TargetGlobal = QCursor::pos() - d->DragStartMousePosition - QPoint(BorderSize, 0); - move(moveToPos); + // Wayland: when we're a child widget (frameless config), translate + // the screen-coord target into parent-local space so move() actually + // places us under the cursor. + if (isWindow() || !parentWidget()) + { + move(TargetGlobal); + } + else + { + move(parentWidget()->mapFromGlobal(TargetGlobal)); + } d->updateDropOverlays(QCursor::pos()); } @@ -370,7 +387,7 @@ void CFloatingDragPreview::startFloating(const QPoint &DragStartMousePos, d->DragStartMousePosition = DragStartMousePos; moveFloating(); show(); - + raise(); }