From 54f718e55287d0cfa7e7e53473b07ca68678e7f2 Mon Sep 17 00:00:00 2001 From: Friedemann Kleint Date: Tue, 10 Apr 2012 13:52:12 +0200 Subject: XCB: Compress window state change events. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Avoid sending Window State change events from WM_STATE/NET_WM_STATE changes irrelevant to Qt::WindowState. - Introduce QFlags for the NetWmState getter and setter to avoid passing QVector<> around. Change-Id: I74730928c7fffca0fa1cab3b90ded90b06304c06 Reviewed-by: Samuel Rødal --- src/plugins/platforms/xcb/qxcbwindow.cpp | 156 ++++++++++++++++--------------- src/plugins/platforms/xcb/qxcbwindow.h | 19 +++- 2 files changed, 97 insertions(+), 78 deletions(-) (limited to 'src/plugins') diff --git a/src/plugins/platforms/xcb/qxcbwindow.cpp b/src/plugins/platforms/xcb/qxcbwindow.cpp index 5a8f90b7ad..06cc5ad123 100644 --- a/src/plugins/platforms/xcb/qxcbwindow.cpp +++ b/src/plugins/platforms/xcb/qxcbwindow.cpp @@ -149,6 +149,7 @@ QXcbWindow::QXcbWindow(QWindow *window) #if defined(XCB_USE_EGL) , m_eglSurface(0) #endif + , m_lastWindowStateEvent(-1) { m_screen = static_cast(window->screen()->handle()); @@ -636,29 +637,9 @@ static void setMotifWmHints(QXcbConnection *c, xcb_window_t window, const QtMoti } } -void QXcbWindow::printNetWmState(const QVector &state) +QXcbWindow::NetWmStates QXcbWindow::netWmStates() { - printf("_NET_WM_STATE (%d): ", state.size()); - for (int i = 0; i < state.size(); ++i) { -#define CHECK_WM_STATE(state_atom) \ - if (state.at(i) == atom(QXcbAtom::state_atom))\ - printf(#state_atom " "); - CHECK_WM_STATE(_NET_WM_STATE_ABOVE) - CHECK_WM_STATE(_NET_WM_STATE_BELOW) - CHECK_WM_STATE(_NET_WM_STATE_FULLSCREEN) - CHECK_WM_STATE(_NET_WM_STATE_MAXIMIZED_HORZ) - CHECK_WM_STATE(_NET_WM_STATE_MAXIMIZED_VERT) - CHECK_WM_STATE(_NET_WM_STATE_MODAL) - CHECK_WM_STATE(_NET_WM_STATE_STAYS_ON_TOP) - CHECK_WM_STATE(_NET_WM_STATE_DEMANDS_ATTENTION) -#undef CHECK_WM_STATE - } - printf("\n"); -} - -QVector QXcbWindow::getNetWmState() -{ - QVector result; + NetWmStates result(0); xcb_get_property_cookie_t get_cookie = xcb_get_property_unchecked(xcb_connection(), 0, m_window, atom(QXcbAtom::_NET_WM_STATE), @@ -668,15 +649,24 @@ QVector QXcbWindow::getNetWmState() xcb_get_property_reply(xcb_connection(), get_cookie, NULL); if (reply && reply->format == 32 && reply->type == XCB_ATOM_ATOM) { - result.resize(reply->length); - - memcpy(result.data(), xcb_get_property_value(reply), reply->length * sizeof(xcb_atom_t)); - -#ifdef NET_WM_STATE_DEBUG - printf("getting net wm state (%x)\n", m_window); - printNetWmState(result); -#endif - + const xcb_atom_t *states = static_cast(xcb_get_property_value(reply)); + const xcb_atom_t *statesEnd = states + reply->length; + if (statesEnd != qFind(states, statesEnd, atom(QXcbAtom::_NET_WM_STATE_ABOVE))) + result |= NetWmStateAbove; + if (statesEnd != qFind(states, statesEnd, atom(QXcbAtom::_NET_WM_STATE_BELOW))) + result |= NetWmStateBelow; + if (statesEnd != qFind(states, statesEnd, atom(QXcbAtom::_NET_WM_STATE_FULLSCREEN))) + result |= NetWmStateFullScreen; + if (statesEnd != qFind(states, statesEnd, atom(QXcbAtom::_NET_WM_STATE_MAXIMIZED_HORZ))) + result |= NetWmStateMaximizedHorz; + if (statesEnd != qFind(states, statesEnd, atom(QXcbAtom::_NET_WM_STATE_MAXIMIZED_VERT))) + result |= NetWmStateMaximizedVert; + if (statesEnd != qFind(states, statesEnd, atom(QXcbAtom::_NET_WM_STATE_MODAL))) + result |= NetWmStateModal; + if (statesEnd != qFind(states, statesEnd, atom(QXcbAtom::_NET_WM_STATE_STAYS_ON_TOP))) + result |= NetWmStateStaysOnTop; + if (statesEnd != qFind(states, statesEnd, atom(QXcbAtom::_NET_WM_STATE_DEMANDS_ATTENTION))) + result |= NetWmStateDemandsAttention; free(reply); } else { #ifdef NET_WM_STATE_DEBUG @@ -687,8 +677,26 @@ QVector QXcbWindow::getNetWmState() return result; } -void QXcbWindow::setNetWmState(const QVector &atoms) +void QXcbWindow::setNetWmStates(NetWmStates states) { + QVector atoms; + if (states & NetWmStateAbove) + atoms.push_back(atom(QXcbAtom::_NET_WM_STATE_ABOVE)); + if (states & NetWmStateBelow) + atoms.push_back(atom(QXcbAtom::_NET_WM_STATE_BELOW)); + if (states & NetWmStateFullScreen) + atoms.push_back(atom(QXcbAtom::_NET_WM_STATE_FULLSCREEN)); + if (states & NetWmStateMaximizedHorz) + atoms.push_back(atom(QXcbAtom::_NET_WM_STATE_MAXIMIZED_HORZ)); + if (states & NetWmStateMaximizedVert) + atoms.push_back(atom(QXcbAtom::_NET_WM_STATE_MAXIMIZED_VERT)); + if (states & NetWmStateModal) + atoms.push_back(atom(QXcbAtom::_NET_WM_STATE_MODAL)); + if (states & NetWmStateStaysOnTop) + atoms.push_back(atom(QXcbAtom::_NET_WM_STATE_STAYS_ON_TOP)); + if (states & NetWmStateDemandsAttention) + atoms.push_back(atom(QXcbAtom::_NET_WM_STATE_DEMANDS_ATTENTION)); + if (atoms.isEmpty()) { Q_XCB_CALL(xcb_delete_property(xcb_connection(), m_window, atom(QXcbAtom::_NET_WM_STATE))); } else { @@ -699,7 +707,6 @@ void QXcbWindow::setNetWmState(const QVector &atoms) xcb_flush(xcb_connection()); } - Qt::WindowFlags QXcbWindow::setWindowFlags(Qt::WindowFlags flags) { Qt::WindowType type = static_cast(int(flags & Qt::WindowType_Mask)); @@ -966,30 +973,28 @@ void QXcbWindow::updateMotifWmHintsBeforeMap() void QXcbWindow::updateNetWmStateBeforeMap() { - QVector netWmState; + NetWmStates states(0); - Qt::WindowFlags flags = window()->windowFlags(); + const Qt::WindowFlags flags = window()->windowFlags(); if (flags & Qt::WindowStaysOnTopHint) { - netWmState.append(atom(QXcbAtom::_NET_WM_STATE_ABOVE)); - netWmState.append(atom(QXcbAtom::_NET_WM_STATE_STAYS_ON_TOP)); + states |= NetWmStateAbove; + states |= NetWmStateStaysOnTop; } else if (flags & Qt::WindowStaysOnBottomHint) { - netWmState.append(atom(QXcbAtom::_NET_WM_STATE_BELOW)); + states |= NetWmStateBelow; } - if (window()->windowState() & Qt::WindowFullScreen) { - netWmState.append(atom(QXcbAtom::_NET_WM_STATE_FULLSCREEN)); - } + if (window()->windowState() & Qt::WindowFullScreen) + states |= NetWmStateFullScreen; if (window()->windowState() & Qt::WindowMaximized) { - netWmState.append(atom(QXcbAtom::_NET_WM_STATE_MAXIMIZED_HORZ)); - netWmState.append(atom(QXcbAtom::_NET_WM_STATE_MAXIMIZED_VERT)); + states |= NetWmStateMaximizedHorz; + states |= NetWmStateMaximizedVert; } - if (window()->windowModality() != Qt::NonModal) { - netWmState.append(atom(QXcbAtom::_NET_WM_STATE_MODAL)); - } + if (window()->windowModality() != Qt::NonModal) + states |= NetWmStateModal; - setNetWmState(netWmState); + setNetWmStates(states); } void QXcbWindow::updateNetWmUserTime(xcb_timestamp_t timestamp) @@ -1452,41 +1457,42 @@ void QXcbWindow::handlePropertyNotifyEvent(const xcb_property_notify_event_t *ev { connection()->setTime(event->time); - bool propertyDeleted = event->state == XCB_PROPERTY_DELETE; + const bool propertyDeleted = event->state == XCB_PROPERTY_DELETE; + const xcb_atom_t netWmStateAtom = atom(QXcbAtom::_NET_WM_STATE); + const xcb_atom_t wmStateAtom = atom(QXcbAtom::WM_STATE); - if (event->atom == atom(QXcbAtom::_NET_WM_STATE) || event->atom == atom(QXcbAtom::WM_STATE)) { + if (event->atom == netWmStateAtom || event->atom == wmStateAtom) { if (propertyDeleted) return; - xcb_get_property_cookie_t get_cookie = - xcb_get_property(xcb_connection(), 0, m_window, atom(QXcbAtom::WM_STATE), - XCB_ATOM_ANY, 0, 1024); + Qt::WindowState newState = Qt::WindowNoState; + if (event->atom == wmStateAtom) { // WM_STATE: Quick check for 'Minimize'. + const xcb_get_property_cookie_t get_cookie = + xcb_get_property(xcb_connection(), 0, m_window, wmStateAtom, + XCB_ATOM_ANY, 0, 1024); - xcb_get_property_reply_t *reply = - xcb_get_property_reply(xcb_connection(), get_cookie, NULL); + xcb_get_property_reply_t *reply = + xcb_get_property_reply(xcb_connection(), get_cookie, NULL); - xcb_atom_t wm_state = XCB_WM_STATE_WITHDRAWN; - if (reply && reply->format == 32 && reply->type == atom(QXcbAtom::WM_STATE)) { - if (reply->length != 0) - wm_state = ((long *)xcb_get_property_value(reply))[0]; - free(reply); + if (reply && reply->format == 32 && reply->type == wmStateAtom) { + const long *data = (const long *)xcb_get_property_value(reply); + if (reply->length != 0 && XCB_WM_STATE_ICONIC == data[0]) + newState = Qt::WindowMinimized; + free(reply); + } + } // WM_STATE: Quick check for 'Minimize'. + if (newState != Qt::WindowMinimized) { // Something else changed, get _NET_WM_STATE. + const NetWmStates states = netWmStates(); + if ((states & NetWmStateMaximizedHorz) && (states & NetWmStateMaximizedVert)) + newState = Qt::WindowMaximized; + else if (states & NetWmStateFullScreen) + newState = Qt::WindowFullScreen; + } + // Send Window state, compress events in case other flags (modality, etc) are changed. + if (m_lastWindowStateEvent != newState) { + QWindowSystemInterface::handleWindowStateChanged(window(), newState); + m_lastWindowStateEvent = newState; } - - QVector netWmState = getNetWmState(); - - bool maximized = netWmState.contains(atom(QXcbAtom::_NET_WM_STATE_MAXIMIZED_HORZ)) - && netWmState.contains(atom(QXcbAtom::_NET_WM_STATE_MAXIMIZED_VERT)); - bool fullscreen = netWmState.contains(atom(QXcbAtom::_NET_WM_STATE_FULLSCREEN)); - - Qt::WindowState state = Qt::WindowNoState; - if (wm_state == XCB_WM_STATE_ICONIC) - state = Qt::WindowMinimized; - else if (maximized) - state = Qt::WindowMaximized; - else if (fullscreen) - state = Qt::WindowFullScreen; - - QWindowSystemInterface::handleWindowStateChanged(window(), state); } } diff --git a/src/plugins/platforms/xcb/qxcbwindow.h b/src/plugins/platforms/xcb/qxcbwindow.h index c212095e98..d4c8804486 100644 --- a/src/plugins/platforms/xcb/qxcbwindow.h +++ b/src/plugins/platforms/xcb/qxcbwindow.h @@ -59,6 +59,19 @@ class QXcbEGLSurface; class QXcbWindow : public QXcbObject, public QPlatformWindow { public: + enum NetWmState { + NetWmStateAbove = 0x1, + NetWmStateBelow = 0x2, + NetWmStateFullScreen = 0x4, + NetWmStateMaximizedHorz = 0x8, + NetWmStateMaximizedVert = 0x10, + NetWmStateModal = 0x20, + NetWmStateStaysOnTop = 0x40, + NetWmStateDemandsAttention = 0x80 + }; + + Q_DECLARE_FLAGS(NetWmStates, NetWmState) + QXcbWindow(QWindow *window); ~QXcbWindow(); @@ -121,9 +134,8 @@ public: private: void changeNetWmState(bool set, xcb_atom_t one, xcb_atom_t two = 0); - QVector getNetWmState(); - void setNetWmState(const QVector &atoms); - void printNetWmState(const QVector &state); + NetWmStates netWmStates(); + void setNetWmStates(NetWmStates); void setNetWmWindowFlags(Qt::WindowFlags flags); void setMotifWindowFlags(Qt::WindowFlags flags); @@ -169,6 +181,7 @@ private: QRegion m_exposeRegion; xcb_visualid_t m_visualId; + int m_lastWindowStateEvent; }; QT_END_NAMESPACE -- cgit v1.2.3