xcb: Process _NET_WORKAREA and screen geometry changes separately
This commit allows to avoid superfluous calls to the X server. We don't request _NET_WORKAREA values when the screen geometry changes, and we avoid RandR calls on each _NET_WORKAREA change. Besides, update the available geometry of all screens with the same root window, rather than only that one which corresponds to Qt::Desktop window. Change-Id: I5ec624717f5f261c986cd9aaf2425f22985e11c0 Reviewed-by: Błażej Szczygieł <spaz16@wp.pl> Reviewed-by: Uli Schlachter <psychon@znc.in> Reviewed-by: Shawn Rutledge <shawn.rutledge@theqtcompany.com>
This commit is contained in:
parent
8beec99899
commit
2047fe9253
@ -1121,8 +1121,17 @@ void QXcbConnection::handleXcbEvent(xcb_generic_event_t *event)
|
||||
handled = false;
|
||||
break;
|
||||
case XCB_PROPERTY_NOTIFY:
|
||||
HANDLE_PLATFORM_WINDOW_EVENT(xcb_property_notify_event_t, window, handlePropertyNotifyEvent);
|
||||
{
|
||||
xcb_property_notify_event_t *pn = (xcb_property_notify_event_t *)event;
|
||||
if (pn->atom == atom(QXcbAtom::_NET_WORKAREA)) {
|
||||
QXcbVirtualDesktop *virtualDesktop = virtualDesktopForRootWindow(pn->window);
|
||||
if (virtualDesktop)
|
||||
virtualDesktop->updateWorkArea();
|
||||
} else {
|
||||
HANDLE_PLATFORM_WINDOW_EVENT(xcb_property_notify_event_t, window, handlePropertyNotifyEvent);
|
||||
}
|
||||
break;
|
||||
}
|
||||
#if defined(XCB_USE_XINPUT2)
|
||||
case XCB_GE_GENERIC:
|
||||
// Here the windowEventListener is invoked from xi2HandleEvent()
|
||||
|
@ -58,6 +58,8 @@ QXcbVirtualDesktop::QXcbVirtualDesktop(QXcbConnection *connection, xcb_screen_t
|
||||
cmAtomName += QByteArray::number(m_number);
|
||||
m_net_wm_cm_atom = connection->internAtom(cmAtomName.constData());
|
||||
m_compositingActive = connection->getSelectionOwner(m_net_wm_cm_atom);
|
||||
|
||||
m_workArea = getWorkArea();
|
||||
}
|
||||
|
||||
QXcbVirtualDesktop::~QXcbVirtualDesktop()
|
||||
@ -112,6 +114,40 @@ void QXcbVirtualDesktop::subscribeToXFixesSelectionNotify()
|
||||
}
|
||||
}
|
||||
|
||||
QRect QXcbVirtualDesktop::getWorkArea() const
|
||||
{
|
||||
QRect r;
|
||||
xcb_get_property_reply_t * workArea =
|
||||
xcb_get_property_reply(xcb_connection(),
|
||||
xcb_get_property_unchecked(xcb_connection(), false, screen()->root,
|
||||
atom(QXcbAtom::_NET_WORKAREA),
|
||||
XCB_ATOM_CARDINAL, 0, 1024), NULL);
|
||||
if (workArea && workArea->type == XCB_ATOM_CARDINAL && workArea->format == 32 && workArea->value_len >= 4) {
|
||||
// If workArea->value_len > 4, the remaining ones seem to be for WM's virtual desktops
|
||||
// (don't mess with QXcbVirtualDesktop which represents an X screen).
|
||||
// But QScreen doesn't know about that concept. In reality there could be a
|
||||
// "docked" panel (with _NET_WM_STRUT_PARTIAL atom set) on just one desktop.
|
||||
// But for now just assume the first 4 values give us the geometry of the
|
||||
// "work area", AKA "available geometry"
|
||||
uint32_t *geom = (uint32_t*)xcb_get_property_value(workArea);
|
||||
r = QRect(geom[0], geom[1], geom[2], geom[3]);
|
||||
} else {
|
||||
r = QRect(QPoint(), size());
|
||||
}
|
||||
free(workArea);
|
||||
return r;
|
||||
}
|
||||
|
||||
void QXcbVirtualDesktop::updateWorkArea()
|
||||
{
|
||||
QRect workArea = getWorkArea();
|
||||
if (m_workArea != workArea) {
|
||||
m_workArea = workArea;
|
||||
foreach (QPlatformScreen *screen, m_screens)
|
||||
((QXcbScreen *)screen)->updateAvailableGeometry();
|
||||
}
|
||||
}
|
||||
|
||||
QXcbScreen::QXcbScreen(QXcbConnection *connection, QXcbVirtualDesktop *virtualDesktop,
|
||||
xcb_randr_output_t outputId, xcb_randr_get_output_info_reply_t *output,
|
||||
QString outputName)
|
||||
@ -457,7 +493,6 @@ void QXcbScreen::updateGeometry(xcb_timestamp_t timestamp)
|
||||
void QXcbScreen::updateGeometry(const QRect &geom, uint8_t rotation)
|
||||
{
|
||||
QRect xGeometry = geom;
|
||||
QRect xAvailableGeometry = xGeometry;
|
||||
switch (rotation) {
|
||||
case XCB_RANDR_ROTATION_ROTATE_0: // xrandr --rotate normal
|
||||
m_orientation = Qt::LandscapeOrientation;
|
||||
@ -486,34 +521,23 @@ void QXcbScreen::updateGeometry(const QRect &geom, uint8_t rotation)
|
||||
Q_MM_PER_INCH * xGeometry.width() / dpi.second);
|
||||
}
|
||||
|
||||
xcb_get_property_reply_t * workArea =
|
||||
xcb_get_property_reply(xcb_connection(),
|
||||
xcb_get_property_unchecked(xcb_connection(), false, screen()->root,
|
||||
atom(QXcbAtom::_NET_WORKAREA),
|
||||
XCB_ATOM_CARDINAL, 0, 1024), NULL);
|
||||
|
||||
if (workArea && workArea->type == XCB_ATOM_CARDINAL && workArea->format == 32 && workArea->value_len >= 4) {
|
||||
// If workArea->value_len > 4, the remaining ones seem to be for virtual desktops.
|
||||
// But QScreen doesn't know about that concept. In reality there could be a
|
||||
// "docked" panel (with _NET_WM_STRUT_PARTIAL atom set) on just one desktop.
|
||||
// But for now just assume the first 4 values give us the geometry of the
|
||||
// "work area", AKA "available geometry"
|
||||
uint32_t *geom = (uint32_t*)xcb_get_property_value(workArea);
|
||||
QRect virtualAvailableGeometry(geom[0], geom[1], geom[2], geom[3]);
|
||||
// Take the intersection of the desktop's available geometry with this screen's geometry
|
||||
// to get the part of the available geometry which belongs to this screen.
|
||||
xAvailableGeometry = xGeometry & virtualAvailableGeometry;
|
||||
}
|
||||
free(workArea);
|
||||
|
||||
qreal dpi = xGeometry.width() / physicalSize().width() * qreal(25.4);
|
||||
m_pixelDensity = qRound(dpi/96);
|
||||
m_geometry = QRect(xGeometry.topLeft(), xGeometry.size());
|
||||
m_nativeGeometry = QRect(xGeometry.topLeft(), xGeometry.size());
|
||||
m_availableGeometry = QRect(xAvailableGeometry.topLeft(), xAvailableGeometry.size());
|
||||
m_availableGeometry = xGeometry & m_virtualDesktop->workArea();
|
||||
QWindowSystemInterface::handleScreenGeometryChange(QPlatformScreen::screen(), m_geometry, m_availableGeometry);
|
||||
}
|
||||
|
||||
void QXcbScreen::updateAvailableGeometry()
|
||||
{
|
||||
QRect availableGeometry = m_geometry & m_virtualDesktop->workArea();
|
||||
if (m_availableGeometry != availableGeometry) {
|
||||
m_availableGeometry = availableGeometry;
|
||||
QWindowSystemInterface::handleScreenGeometryChange(QPlatformScreen::screen(), m_geometry, m_availableGeometry);
|
||||
}
|
||||
}
|
||||
|
||||
void QXcbScreen::updateRefreshRate(xcb_randr_mode_t mode)
|
||||
{
|
||||
if (!connection()->hasXRandr())
|
||||
|
@ -77,10 +77,15 @@ public:
|
||||
|
||||
bool compositingActive() const;
|
||||
|
||||
QRect workArea() const { return m_workArea; }
|
||||
void updateWorkArea();
|
||||
|
||||
void handleXFixesSelectionNotify(xcb_xfixes_selection_notify_event_t *notify_event);
|
||||
void subscribeToXFixesSelectionNotify();
|
||||
|
||||
private:
|
||||
QRect getWorkArea() const;
|
||||
|
||||
xcb_screen_t *m_screen;
|
||||
int m_number;
|
||||
QList<QPlatformScreen *> m_screens;
|
||||
@ -88,6 +93,8 @@ private:
|
||||
QXcbXSettings *m_xSettings;
|
||||
xcb_atom_t m_net_wm_cm_atom;
|
||||
bool m_compositingActive;
|
||||
|
||||
QRect m_workArea;
|
||||
};
|
||||
|
||||
class Q_XCB_EXPORT QXcbScreen : public QXcbObject, public QPlatformScreen
|
||||
@ -142,6 +149,7 @@ public:
|
||||
void handleScreenChange(xcb_randr_screen_change_notify_event_t *change_event);
|
||||
void updateGeometry(const QRect &geom, uint8_t rotation);
|
||||
void updateGeometry(xcb_timestamp_t timestamp = XCB_TIME_CURRENT_TIME);
|
||||
void updateAvailableGeometry();
|
||||
void updateRefreshRate(xcb_randr_mode_t mode);
|
||||
|
||||
void readXResources();
|
||||
|
@ -2378,8 +2378,6 @@ void QXcbWindow::handlePropertyNotifyEvent(const xcb_property_notify_event_t *ev
|
||||
return;
|
||||
} else if (event->atom == atom(QXcbAtom::_NET_FRAME_EXTENTS)) {
|
||||
m_dirtyFrameMargins = true;
|
||||
} else if (event->atom == atom(QXcbAtom::_NET_WORKAREA) && xcbScreen() && event->window == xcbScreen()->root()) {
|
||||
xcbScreen()->updateGeometry(event->time);
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user