Fix menu size in multiscreen setups
During QMenuPrivate::popup() and QMenuBarPrivate::popupAction(), QMenuPrivate::popupGeometry() is called from updateActionRects() with screen = 0 several times (from sizeHint() and various event handlers triggered), which causes it to return the primary screen geometry always. To fix this for the non-QGraphicsView case, use the screen of the menu when it is visible or the screen stored in a newly introduced popupScreen member variable, which is set from a few places in QMenuPrivate::popup(). Fixes: QTBUG-118434 Pick-to: 6.7 6.6 6.5 Change-Id: I6b18593d313719d628b0856004197ac59f46c270 Reviewed-by: Volker Hilsheimer <volker.hilsheimer@qt.io>
This commit is contained in:
parent
9069b7fb20
commit
8cd7a3d472
@ -292,6 +292,13 @@ inline bool QMenuPrivate::useFullScreenForPopup() const
|
|||||||
QRect QMenuPrivate::popupGeometry(QScreen *screen) const
|
QRect QMenuPrivate::popupGeometry(QScreen *screen) const
|
||||||
{
|
{
|
||||||
Q_Q(const QMenu);
|
Q_Q(const QMenu);
|
||||||
|
if (screen == nullptr
|
||||||
|
#if QT_CONFIG(graphicsview)
|
||||||
|
&& q->graphicsProxyWidget() == nullptr
|
||||||
|
#endif
|
||||||
|
) {
|
||||||
|
screen = q->isVisible() ? q->screen() : popupScreen.data();
|
||||||
|
}
|
||||||
if (useFullScreenForPopup())
|
if (useFullScreenForPopup())
|
||||||
return screen ? screen->geometry()
|
return screen ? screen->geometry()
|
||||||
: QWidgetPrivate::screenGeometry(q);
|
: QWidgetPrivate::screenGeometry(q);
|
||||||
@ -2309,6 +2316,9 @@ void QMenu::popup(const QPoint &p, QAction *atAction)
|
|||||||
void QMenuPrivate::popup(const QPoint &p, QAction *atAction, PositionFunction positionFunction)
|
void QMenuPrivate::popup(const QPoint &p, QAction *atAction, PositionFunction positionFunction)
|
||||||
{
|
{
|
||||||
Q_Q(QMenu);
|
Q_Q(QMenu);
|
||||||
|
popupScreen = QGuiApplication::screenAt(p);
|
||||||
|
QScopeGuard popupScreenGuard([this](){ popupScreen.clear(); });
|
||||||
|
|
||||||
if (scroll) { // reset scroll state from last popup
|
if (scroll) { // reset scroll state from last popup
|
||||||
if (scroll->scrollOffset)
|
if (scroll->scrollOffset)
|
||||||
itemsDirty = 1; // sizeHint will be incorrect if there is previous scroll
|
itemsDirty = 1; // sizeHint will be incorrect if there is previous scroll
|
||||||
@ -2384,6 +2394,7 @@ void QMenuPrivate::popup(const QPoint &p, QAction *atAction, PositionFunction po
|
|||||||
pos = QPushButtonPrivate::get(causedButton)->adjustedMenuPosition();
|
pos = QPushButtonPrivate::get(causedButton)->adjustedMenuPosition();
|
||||||
else
|
else
|
||||||
pos = p;
|
pos = p;
|
||||||
|
popupScreen = QGuiApplication::screenAt(pos);
|
||||||
|
|
||||||
const QSize menuSizeHint(q->sizeHint());
|
const QSize menuSizeHint(q->sizeHint());
|
||||||
QSize size = menuSizeHint;
|
QSize size = menuSizeHint;
|
||||||
@ -2522,6 +2533,7 @@ void QMenuPrivate::popup(const QPoint &p, QAction *atAction, PositionFunction po
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
popupScreen = QGuiApplication::screenAt(pos);
|
||||||
q->setGeometry(QRect(pos, size));
|
q->setGeometry(QRect(pos, size));
|
||||||
#if QT_CONFIG(effects)
|
#if QT_CONFIG(effects)
|
||||||
int hGuess = q->isRightToLeft() ? QEffects::LeftScroll : QEffects::RightScroll;
|
int hGuess = q->isRightToLeft() ? QEffects::LeftScroll : QEffects::RightScroll;
|
||||||
|
@ -473,6 +473,11 @@ public:
|
|||||||
|
|
||||||
mutable quint8 ncols = 0; // "255cols ought to be enough for anybody."
|
mutable quint8 ncols = 0; // "255cols ought to be enough for anybody."
|
||||||
|
|
||||||
|
// Contains the screen of the popup point during popup(QPoint).
|
||||||
|
// This is to make sure the screen is remembered,
|
||||||
|
// when the menu contains many items on multiple screens
|
||||||
|
QPointer<QScreen> popupScreen;
|
||||||
|
|
||||||
mutable bool itemsDirty : 1;
|
mutable bool itemsDirty : 1;
|
||||||
mutable bool hasCheckableItems : 1;
|
mutable bool hasCheckableItems : 1;
|
||||||
bool lastContextMenu : 1;
|
bool lastContextMenu : 1;
|
||||||
|
@ -281,17 +281,21 @@ void QMenuBarPrivate::popupAction(QAction *action, bool activateFirst)
|
|||||||
if (action->isEnabled() && action->menu()->isEnabled()) {
|
if (action->isEnabled() && action->menu()->isEnabled()) {
|
||||||
closePopupMode = 0;
|
closePopupMode = 0;
|
||||||
activeMenu = action->menu();
|
activeMenu = action->menu();
|
||||||
activeMenu->d_func()->causedPopup.widget = q;
|
auto *activeMenuPriv = activeMenu->d_func();
|
||||||
activeMenu->d_func()->causedPopup.action = action;
|
activeMenuPriv->causedPopup.widget = q;
|
||||||
|
activeMenuPriv->causedPopup.action = action;
|
||||||
|
|
||||||
QRect adjustedActionRect = actionRect(action);
|
QRect adjustedActionRect = actionRect(action);
|
||||||
QPoint pos(q->mapToGlobal(QPoint(adjustedActionRect.left(), adjustedActionRect.bottom() + 1)));
|
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
|
//we put the popup menu on the screen containing the bottom-center of the action rect
|
||||||
QScreen *menubarScreen = q->window()->windowHandle()->screen();
|
QScreen *menubarScreen = q->window()->windowHandle()->screen();
|
||||||
QScreen *popupScreen = menubarScreen->virtualSiblingAt(pos + QPoint(adjustedActionRect.width() / 2, 0));
|
QPointer<QScreen> popupScreen = menubarScreen->virtualSiblingAt(pos + QPoint(adjustedActionRect.width() / 2, 0));
|
||||||
if (!popupScreen)
|
if (!popupScreen)
|
||||||
popupScreen = menubarScreen;
|
popupScreen = menubarScreen;
|
||||||
|
std::swap(popupScreen, activeMenuPriv->popupScreen);
|
||||||
|
const QSize popup_size = activeMenu->sizeHint();
|
||||||
|
std::swap(popupScreen, activeMenuPriv->popupScreen);
|
||||||
|
|
||||||
QRect screenRect = popupScreen->geometry();
|
QRect screenRect = popupScreen->geometry();
|
||||||
pos = QPoint(qMax(pos.x(), screenRect.x()), qMax(pos.y(), screenRect.y()));
|
pos = QPoint(qMax(pos.x(), screenRect.x()), qMax(pos.y(), screenRect.y()));
|
||||||
const bool fitUp = (pos.y() - popup_size.height() >= screenRect.top());
|
const bool fitUp = (pos.y() - popup_size.height() >= screenRect.top());
|
||||||
|
Loading…
x
Reference in New Issue
Block a user