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;
|
handled = false;
|
||||||
break;
|
break;
|
||||||
case XCB_PROPERTY_NOTIFY:
|
case XCB_PROPERTY_NOTIFY:
|
||||||
|
{
|
||||||
|
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);
|
HANDLE_PLATFORM_WINDOW_EVENT(xcb_property_notify_event_t, window, handlePropertyNotifyEvent);
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
#if defined(XCB_USE_XINPUT2)
|
#if defined(XCB_USE_XINPUT2)
|
||||||
case XCB_GE_GENERIC:
|
case XCB_GE_GENERIC:
|
||||||
// Here the windowEventListener is invoked from xi2HandleEvent()
|
// Here the windowEventListener is invoked from xi2HandleEvent()
|
||||||
|
@ -58,6 +58,8 @@ QXcbVirtualDesktop::QXcbVirtualDesktop(QXcbConnection *connection, xcb_screen_t
|
|||||||
cmAtomName += QByteArray::number(m_number);
|
cmAtomName += QByteArray::number(m_number);
|
||||||
m_net_wm_cm_atom = connection->internAtom(cmAtomName.constData());
|
m_net_wm_cm_atom = connection->internAtom(cmAtomName.constData());
|
||||||
m_compositingActive = connection->getSelectionOwner(m_net_wm_cm_atom);
|
m_compositingActive = connection->getSelectionOwner(m_net_wm_cm_atom);
|
||||||
|
|
||||||
|
m_workArea = getWorkArea();
|
||||||
}
|
}
|
||||||
|
|
||||||
QXcbVirtualDesktop::~QXcbVirtualDesktop()
|
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,
|
QXcbScreen::QXcbScreen(QXcbConnection *connection, QXcbVirtualDesktop *virtualDesktop,
|
||||||
xcb_randr_output_t outputId, xcb_randr_get_output_info_reply_t *output,
|
xcb_randr_output_t outputId, xcb_randr_get_output_info_reply_t *output,
|
||||||
QString outputName)
|
QString outputName)
|
||||||
@ -457,7 +493,6 @@ void QXcbScreen::updateGeometry(xcb_timestamp_t timestamp)
|
|||||||
void QXcbScreen::updateGeometry(const QRect &geom, uint8_t rotation)
|
void QXcbScreen::updateGeometry(const QRect &geom, uint8_t rotation)
|
||||||
{
|
{
|
||||||
QRect xGeometry = geom;
|
QRect xGeometry = geom;
|
||||||
QRect xAvailableGeometry = xGeometry;
|
|
||||||
switch (rotation) {
|
switch (rotation) {
|
||||||
case XCB_RANDR_ROTATION_ROTATE_0: // xrandr --rotate normal
|
case XCB_RANDR_ROTATION_ROTATE_0: // xrandr --rotate normal
|
||||||
m_orientation = Qt::LandscapeOrientation;
|
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);
|
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);
|
qreal dpi = xGeometry.width() / physicalSize().width() * qreal(25.4);
|
||||||
m_pixelDensity = qRound(dpi/96);
|
m_pixelDensity = qRound(dpi/96);
|
||||||
m_geometry = QRect(xGeometry.topLeft(), xGeometry.size());
|
m_geometry = QRect(xGeometry.topLeft(), xGeometry.size());
|
||||||
m_nativeGeometry = 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);
|
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)
|
void QXcbScreen::updateRefreshRate(xcb_randr_mode_t mode)
|
||||||
{
|
{
|
||||||
if (!connection()->hasXRandr())
|
if (!connection()->hasXRandr())
|
||||||
|
@ -77,10 +77,15 @@ public:
|
|||||||
|
|
||||||
bool compositingActive() const;
|
bool compositingActive() const;
|
||||||
|
|
||||||
|
QRect workArea() const { return m_workArea; }
|
||||||
|
void updateWorkArea();
|
||||||
|
|
||||||
void handleXFixesSelectionNotify(xcb_xfixes_selection_notify_event_t *notify_event);
|
void handleXFixesSelectionNotify(xcb_xfixes_selection_notify_event_t *notify_event);
|
||||||
void subscribeToXFixesSelectionNotify();
|
void subscribeToXFixesSelectionNotify();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
QRect getWorkArea() const;
|
||||||
|
|
||||||
xcb_screen_t *m_screen;
|
xcb_screen_t *m_screen;
|
||||||
int m_number;
|
int m_number;
|
||||||
QList<QPlatformScreen *> m_screens;
|
QList<QPlatformScreen *> m_screens;
|
||||||
@ -88,6 +93,8 @@ private:
|
|||||||
QXcbXSettings *m_xSettings;
|
QXcbXSettings *m_xSettings;
|
||||||
xcb_atom_t m_net_wm_cm_atom;
|
xcb_atom_t m_net_wm_cm_atom;
|
||||||
bool m_compositingActive;
|
bool m_compositingActive;
|
||||||
|
|
||||||
|
QRect m_workArea;
|
||||||
};
|
};
|
||||||
|
|
||||||
class Q_XCB_EXPORT QXcbScreen : public QXcbObject, public QPlatformScreen
|
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 handleScreenChange(xcb_randr_screen_change_notify_event_t *change_event);
|
||||||
void updateGeometry(const QRect &geom, uint8_t rotation);
|
void updateGeometry(const QRect &geom, uint8_t rotation);
|
||||||
void updateGeometry(xcb_timestamp_t timestamp = XCB_TIME_CURRENT_TIME);
|
void updateGeometry(xcb_timestamp_t timestamp = XCB_TIME_CURRENT_TIME);
|
||||||
|
void updateAvailableGeometry();
|
||||||
void updateRefreshRate(xcb_randr_mode_t mode);
|
void updateRefreshRate(xcb_randr_mode_t mode);
|
||||||
|
|
||||||
void readXResources();
|
void readXResources();
|
||||||
|
@ -2378,8 +2378,6 @@ void QXcbWindow::handlePropertyNotifyEvent(const xcb_property_notify_event_t *ev
|
|||||||
return;
|
return;
|
||||||
} else if (event->atom == atom(QXcbAtom::_NET_FRAME_EXTENTS)) {
|
} else if (event->atom == atom(QXcbAtom::_NET_FRAME_EXTENTS)) {
|
||||||
m_dirtyFrameMargins = true;
|
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