xcb: Use _NET_FRAME_EXTENTS to get frame margins

Some window managers don't reparent the client window into the frame,
so the old method of calculating frame margins by the geometries of the
window and it's frame window is not suitable for them. Use it only as a
fallback.

Change-Id: Ie4d62370425effef4dd91bf27d98e3746e8a375e
Task-number: QTBUG-2280
Reviewed-by: Gatis Paeglis <gatis.paeglis@digia.com>
Reviewed-by: Uli Schlachter <psychon@znc.in>
bb10
Alexander Volkov 2015-05-04 22:41:01 +03:00
parent 8db7bad6e1
commit 27bf6df294
3 changed files with 20 additions and 0 deletions

View File

@ -1578,6 +1578,7 @@ static const char * xcb_atomnames = {
"_KDE_NET_WM_WINDOW_TYPE_OVERRIDE\0"
"_KDE_NET_WM_FRAME_STRUT\0"
"_NET_FRAME_EXTENTS\0"
"_NET_STARTUP_INFO\0"
"_NET_STARTUP_INFO_BEGIN\0"

View File

@ -194,6 +194,7 @@ namespace QXcbAtom {
_KDE_NET_WM_WINDOW_TYPE_OVERRIDE,
_KDE_NET_WM_FRAME_STRUT,
_NET_FRAME_EXTENTS,
_NET_STARTUP_INFO,
_NET_STARTUP_INFO_BEGIN,

View File

@ -745,6 +745,22 @@ void QXcbWindow::setGeometry(const QRect &rect)
QMargins QXcbWindow::frameMargins() const
{
if (m_dirtyFrameMargins) {
if (connection()->wmSupport()->isSupportedByWM(atom(QXcbAtom::_NET_FRAME_EXTENTS))) {
xcb_get_property_cookie_t cookie = xcb_get_property(xcb_connection(), false, m_window,
atom(QXcbAtom::_NET_FRAME_EXTENTS), XCB_ATOM_CARDINAL, 0, 4);
QScopedPointer<xcb_get_property_reply_t, QScopedPointerPodDeleter> reply(
xcb_get_property_reply(xcb_connection(), cookie, NULL));
if (reply && reply->type == XCB_ATOM_CARDINAL && reply->format == 32 && reply->value_len == 4) {
quint32 *data = (quint32 *)xcb_get_property_value(reply.data());
// _NET_FRAME_EXTENTS format is left, right, top, bottom
m_frameMargins = QMargins(data[0], data[2], data[1], data[3]);
m_dirtyFrameMargins = false;
return m_frameMargins;
}
}
// _NET_FRAME_EXTENTS property is not available, so
// walk up the window tree to get the frame parent
xcb_window_t window = m_window;
xcb_window_t parent = m_window;
@ -2385,6 +2401,8 @@ void QXcbWindow::handlePropertyNotifyEvent(const xcb_property_notify_event_t *ev
m_windowState = newState;
}
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);
}