diff options
-rw-r--r-- | src/widgets/kernel/qwidget.cpp | 21 | ||||
-rw-r--r-- | src/widgets/kernel/qwidget_p.h | 2 | ||||
-rw-r--r-- | src/widgets/widgets/qmenu.cpp | 12 | ||||
-rw-r--r-- | src/widgets/widgets/qmenu_p.h | 2 | ||||
-rw-r--r-- | src/widgets/widgets/qmenubar.cpp | 15 |
5 files changed, 44 insertions, 8 deletions
diff --git a/src/widgets/kernel/qwidget.cpp b/src/widgets/kernel/qwidget.cpp index 59053f3539..8b225df8be 100644 --- a/src/widgets/kernel/qwidget.cpp +++ b/src/widgets/kernel/qwidget.cpp @@ -2589,14 +2589,27 @@ bool QWidgetPrivate::setScreenForPoint(const QPoint &pos) Q_Q(QWidget); if (!q->isWindow()) return false; - // Find the screen for pos and make the widget undertand it is on that screen. + // Find the screen for pos and make the widget understand it is on that screen. + return setScreen(QGuiApplication::screenAt(pos)); +} + +/*! +\internal +Ensures that the widget's QWindow is set to be on the given \a screen. +Returns true if the screen was changed. +*/ + +bool QWidgetPrivate::setScreen(QScreen *screen) +{ + Q_Q(QWidget); + if (!screen || !q->isWindow()) + return false; const QScreen *currentScreen = windowHandle() ? windowHandle()->screen() : nullptr; - QScreen *actualScreen = QGuiApplication::screenAt(pos); - if (actualScreen && currentScreen != actualScreen) { + if (currentScreen != screen) { if (!windowHandle()) // Try to create a window handle if not created. createWinId(); if (windowHandle()) - windowHandle()->setScreen(actualScreen); + windowHandle()->setScreen(screen); return true; } return false; diff --git a/src/widgets/kernel/qwidget_p.h b/src/widgets/kernel/qwidget_p.h index ae50624c04..64bc463ae2 100644 --- a/src/widgets/kernel/qwidget_p.h +++ b/src/widgets/kernel/qwidget_p.h @@ -181,6 +181,7 @@ struct QTLWExtra { QRect frameStrut; QRect normalGeometry; // used by showMin/maximized/FullScreen Qt::WindowFlags savedFlags; // Save widget flags while showing fullscreen + // ### TODO replace initialScreenIndex with QScreen *, in case the screens change at runtime int initialScreenIndex; // Screen number when passing a QDesktop[Screen]Widget as parent. QVector<QPlatformTextureList *> widgetTextures; @@ -356,6 +357,7 @@ public: void createWinId(); bool setScreenForPoint(const QPoint &pos); + bool setScreen(QScreen *screen); void createTLExtra(); void createExtra(); diff --git a/src/widgets/widgets/qmenu.cpp b/src/widgets/widgets/qmenu.cpp index 5b1f609b7e..2d107de268 100644 --- a/src/widgets/widgets/qmenu.cpp +++ b/src/widgets/widgets/qmenu.cpp @@ -2359,8 +2359,18 @@ void QMenu::popup(const QPoint &p, QAction *atAction) d->updateLayoutDirection(); // Ensure that we get correct sizeHints by placing this window on the correct screen. - if (d->setScreenForPoint(p)) + // However if the QMenu was constructed with a QDesktopScreenWidget as its parent, + // then initialScreenIndex was set, so we should respect that for the lifetime of this menu. + // Use d->popupScreen to remember, because initialScreenIndex will be reset after the first showing. + const int screenIndex = d->topData()->initialScreenIndex; + if (screenIndex >= 0) + d->popupScreen = screenIndex; + if (auto s = QGuiApplication::screens().value(d->popupScreen)) { + if (d->setScreen(s)) + d->itemsDirty = true; + } else if (d->setScreenForPoint(p)) { d->itemsDirty = true; + } const bool contextMenu = d->isContextMenu(); if (d->lastContextMenu != contextMenu) { diff --git a/src/widgets/widgets/qmenu_p.h b/src/widgets/widgets/qmenu_p.h index d0fa8ff113..b8976385f4 100644 --- a/src/widgets/widgets/qmenu_p.h +++ b/src/widgets/widgets/qmenu_p.h @@ -509,6 +509,8 @@ public: bool tearoffHighlighted : 1; //menu fading/scrolling effects bool doChildEffects : 1; + + int popupScreen = -1; }; QT_END_NAMESPACE diff --git a/src/widgets/widgets/qmenubar.cpp b/src/widgets/widgets/qmenubar.cpp index e7984078de..33c10f3a9a 100644 --- a/src/widgets/widgets/qmenubar.cpp +++ b/src/widgets/widgets/qmenubar.cpp @@ -68,6 +68,7 @@ #include "qmenu_p.h" #include "qmenubar_p.h" +#include <private/qscreen_p.h> #include "qdebug.h" QT_BEGIN_NAMESPACE @@ -322,11 +323,18 @@ void QMenuBarPrivate::popupAction(QAction *action, bool activateFirst) QRect adjustedActionRect = actionRect(action); QPoint pos(q->mapToGlobal(QPoint(adjustedActionRect.left(), adjustedActionRect.bottom() + 1))); QSize popup_size = activeMenu->sizeHint(); - //we put the popup menu on the screen containing the bottom-center of the action rect - QRect screenRect = QDesktopWidgetPrivate::screenGeometry(pos + QPoint(adjustedActionRect.width() / 2, 0)); + QScreen *popupScreen = q->window()->windowHandle()->screen(); + QPoint bottomMiddlePos = pos + QPoint(adjustedActionRect.width() / 2, 0); + const auto &siblings = popupScreen->virtualSiblings(); + for (QScreen *sibling : siblings) { + if (sibling->geometry().contains(bottomMiddlePos)) { + popupScreen = sibling; + break; + } + } + QRect screenRect = popupScreen->geometry(); pos = QPoint(qMax(pos.x(), screenRect.x()), qMax(pos.y(), screenRect.y())); - const bool fitUp = (pos.y() - popup_size.height() >= screenRect.top()); const bool fitDown = (pos.y() + popup_size.height() <= screenRect.bottom()); const bool rtl = q->isRightToLeft(); @@ -352,6 +360,7 @@ void QMenuBarPrivate::popupAction(QAction *action, bool activateFirst) if(!defaultPopDown || (fitUp && !fitDown)) pos.setY(qMax(screenRect.y(), q->mapToGlobal(QPoint(0, adjustedActionRect.top()-popup_size.height())).y())); + QMenuPrivate::get(activeMenu)->topData()->initialScreenIndex = QGuiApplication::screens().indexOf(popupScreen); activeMenu->popup(pos); if(activateFirst) activeMenu->d_func()->setFirstActionActive(); |