Add QScreen::virtualSiblingAt() and use it in QMenubarPrivate::popupAction

QGuiApplication::screenAt() is documented "If the point maps to more
than one set of virtual siblings, the first match is returned."
But in many cases it's possible to start from a known screen and
consider only its siblings, as when deciding where to open a QMenu
from a QMenuBar: the QMenuBar is already shown on some screen(s),
so the QMenu must be shown on a sibling from that set.  This function
should be useful in other such cases too, hence it might as well
be public API.

Task-number: QTBUG-76162
Change-Id: I83c74b40eb53f56fb285a6074a3dc2c0ea9c570b
Reviewed-by: Friedemann Kleint <Friedemann.Kleint@qt.io>
Reviewed-by: Tor Arne Vestbø <tor.arne.vestbo@qt.io>
This commit is contained in:
Shawn Rutledge 2019-06-17 17:47:30 +02:00
parent e0cad1aab5
commit ecc8367700
4 changed files with 27 additions and 10 deletions

View File

@ -1040,7 +1040,9 @@ QList<QScreen *> QGuiApplication::screens()
The \a point is in relation to the virtualGeometry() of each set of virtual
siblings. If the point maps to more than one set of virtual siblings the first
match is returned.
match is returned. If you wish to search only the virtual desktop siblings
of a known screen (for example siblings of the screen of your application
window \c QWidget::windowHandle()->screen()), use QScreen::virtualSiblingAt().
\since 5.10
*/

View File

@ -699,6 +699,25 @@ void QScreenPrivate::updatePrimaryOrientation()
primaryOrientation = geometry.width() >= geometry.height() ? Qt::LandscapeOrientation : Qt::PortraitOrientation;
}
/*!
Returns the screen at \a point within the set of \l QScreen::virtualSiblings(),
or \c nullptr if outside of any screen.
The \a point is in relation to the virtualGeometry() of each set of virtual
siblings.
\since 5.15
*/
QScreen *QScreen::virtualSiblingAt(const QPoint &point)
{
const auto &siblings = virtualSiblings();
for (QScreen *sibling : siblings) {
if (sibling->geometry().contains(point))
return sibling;
}
return nullptr;
}
/*!
Creates and returns a pixmap constructed by grabbing the contents
of the given \a window restricted by QRect(\a x, \a y, \a width,

View File

@ -125,6 +125,7 @@ public:
QRect availableGeometry() const;
QList<QScreen *> virtualSiblings() const;
QScreen *virtualSiblingAt(const QPoint &point);
QSize virtualSize() const;
QRect virtualGeometry() const;

View File

@ -324,15 +324,10 @@ void QMenuBarPrivate::popupAction(QAction *action, bool activateFirst)
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
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;
}
}
QScreen *menubarScreen = q->window()->windowHandle()->screen();
QScreen *popupScreen = menubarScreen->virtualSiblingAt(pos + QPoint(adjustedActionRect.width() / 2, 0));
if (!popupScreen)
popupScreen = menubarScreen;
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());