diff options
Diffstat (limited to 'src/plugins/platforms/xcb')
-rw-r--r-- | src/plugins/platforms/xcb/qxcbclipboard.cpp | 16 | ||||
-rw-r--r-- | src/plugins/platforms/xcb/qxcbconnection.cpp | 8 | ||||
-rw-r--r-- | src/plugins/platforms/xcb/qxcbconnection_basic.cpp | 8 | ||||
-rw-r--r-- | src/plugins/platforms/xcb/qxcbeventqueue.cpp | 8 | ||||
-rw-r--r-- | src/plugins/platforms/xcb/qxcbeventqueue.h | 4 | ||||
-rw-r--r-- | src/plugins/platforms/xcb/qxcbwindow.cpp | 49 |
6 files changed, 68 insertions, 25 deletions
diff --git a/src/plugins/platforms/xcb/qxcbclipboard.cpp b/src/plugins/platforms/xcb/qxcbclipboard.cpp index ac8b029916..a4940f1c49 100644 --- a/src/plugins/platforms/xcb/qxcbclipboard.cpp +++ b/src/plugins/platforms/xcb/qxcbclipboard.cpp @@ -787,6 +787,12 @@ xcb_generic_event_t *QXcbClipboard::waitForClipboardEvent(xcb_window_t window, i if (e) // found the waited for event return e; + // It is safe to assume here that the pointed to node won't be re-used + // while we are holding the pointer to it. The nodes can be recycled + // only when they are dequeued, which is done only by + // QXcbConnection::processXcbEvents(). + const QXcbEventNode *flushedTailNode = queue->flushedTail(); + if (checkManager) { auto reply = Q_XCB_REPLY(xcb_get_selection_owner, xcb_connection(), atom(QXcbAtom::CLIPBOARD_MANAGER)); if (!reply || reply->owner == XCB_NONE) @@ -812,7 +818,7 @@ xcb_generic_event_t *QXcbClipboard::waitForClipboardEvent(xcb_window_t window, i const auto elapsed = timer.elapsed(); if (elapsed < clipboard_timeout) - queue->waitForNewEvents(clipboard_timeout - elapsed); + queue->waitForNewEvents(flushedTailNode, clipboard_timeout - elapsed); } while (timer.elapsed() < clipboard_timeout); return nullptr; @@ -835,6 +841,8 @@ QByteArray QXcbClipboard::clipboardReadIncrementalProperty(xcb_window_t win, xcb alloc_error = buf.size() != nbytes+1; } + QElapsedTimer timer; + timer.start(); for (;;) { connection()->flush(); xcb_generic_event_t *ge = waitForClipboardEvent(win, XCB_PROPERTY_NOTIFY); @@ -870,9 +878,11 @@ QByteArray QXcbClipboard::clipboardReadIncrementalProperty(xcb_window_t win, xcb tmp_buf.resize(0); offset += length; } - } else { - break; } + + const auto elapsed = timer.elapsed(); + if (elapsed > clipboard_timeout) + break; } // timed out ... create a new requestor window, otherwise the requestor diff --git a/src/plugins/platforms/xcb/qxcbconnection.cpp b/src/plugins/platforms/xcb/qxcbconnection.cpp index a563bf6005..8f0281c176 100644 --- a/src/plugins/platforms/xcb/qxcbconnection.cpp +++ b/src/plugins/platforms/xcb/qxcbconnection.cpp @@ -806,7 +806,13 @@ xcb_timestamp_t QXcbConnection::getTimestamp() xcb_window_t QXcbConnection::getSelectionOwner(xcb_atom_t atom) const { - return Q_XCB_REPLY(xcb_get_selection_owner, xcb_connection(), atom)->owner; + auto reply = Q_XCB_REPLY(xcb_get_selection_owner, xcb_connection(), atom); + if (!reply) { + qCDebug(lcQpaXcb) << "failed to query selection owner"; + return XCB_NONE; + } + + return reply->owner; } xcb_window_t QXcbConnection::getQtSelectionOwner() diff --git a/src/plugins/platforms/xcb/qxcbconnection_basic.cpp b/src/plugins/platforms/xcb/qxcbconnection_basic.cpp index af72285135..bdd7e2d98a 100644 --- a/src/plugins/platforms/xcb/qxcbconnection_basic.cpp +++ b/src/plugins/platforms/xcb/qxcbconnection_basic.cpp @@ -183,7 +183,13 @@ xcb_atom_t QXcbBasicConnection::internAtom(const char *name) if (!name || *name == 0) return XCB_NONE; - return Q_XCB_REPLY(xcb_intern_atom, m_xcbConnection, false, strlen(name), name)->atom; + auto reply = Q_XCB_REPLY(xcb_intern_atom, m_xcbConnection, false, strlen(name), name); + if (!reply) { + qCDebug(lcQpaXcb) << "failed to query intern atom: " << name; + return XCB_NONE; + } + + return reply->atom; } QByteArray QXcbBasicConnection::atomName(xcb_atom_t atom) diff --git a/src/plugins/platforms/xcb/qxcbeventqueue.cpp b/src/plugins/platforms/xcb/qxcbeventqueue.cpp index 4ca73e3048..b96bda3194 100644 --- a/src/plugins/platforms/xcb/qxcbeventqueue.cpp +++ b/src/plugins/platforms/xcb/qxcbeventqueue.cpp @@ -226,6 +226,8 @@ void QXcbEventQueue::run() }; while (!m_closeConnectionDetected && (event = xcb_wait_for_event(connection))) { + // This lock can block only if there are users of waitForNewEvents(). + // Currently only the clipboard implementation relies on it. m_newEventsMutex.lock(); enqueueEvent(event); while (!m_closeConnectionDetected && (event = xcb_poll_for_queued_event(connection))) @@ -350,12 +352,12 @@ bool QXcbEventQueue::peekEventQueue(PeekerCallback peeker, void *peekerData, return result; } -void QXcbEventQueue::waitForNewEvents(unsigned long time) +void QXcbEventQueue::waitForNewEvents(const QXcbEventNode *sinceFlushedTail, + unsigned long time) { QMutexLocker locker(&m_newEventsMutex); - QXcbEventNode *tailBeforeFlush = m_flushedTail; flushBufferedEvents(); - if (tailBeforeFlush != m_flushedTail) + if (sinceFlushedTail != m_flushedTail) return; m_newEventsCondition.wait(&m_newEventsMutex, time); } diff --git a/src/plugins/platforms/xcb/qxcbeventqueue.h b/src/plugins/platforms/xcb/qxcbeventqueue.h index 11d0b8e963..c8f09ed9e3 100644 --- a/src/plugins/platforms/xcb/qxcbeventqueue.h +++ b/src/plugins/platforms/xcb/qxcbeventqueue.h @@ -106,7 +106,9 @@ public: bool peekEventQueue(PeekerCallback peeker, void *peekerData = nullptr, PeekOptions option = PeekDefault, qint32 peekerId = -1); - void waitForNewEvents(unsigned long time = ULONG_MAX); + const QXcbEventNode *flushedTail() const { return m_flushedTail; } + void waitForNewEvents(const QXcbEventNode *sinceFlushedTail, + unsigned long time = ULONG_MAX); private: QXcbEventNode *qXcbEventNodeFactory(xcb_generic_event_t *event); diff --git a/src/plugins/platforms/xcb/qxcbwindow.cpp b/src/plugins/platforms/xcb/qxcbwindow.cpp index d7d5bd3958..a6d2054110 100644 --- a/src/plugins/platforms/xcb/qxcbwindow.cpp +++ b/src/plugins/platforms/xcb/qxcbwindow.cpp @@ -1172,27 +1172,44 @@ void QXcbWindow::setWindowState(Qt::WindowStates state) if (state == m_windowState) return; - if ((m_windowState & Qt::WindowMinimized) && !(state & Qt::WindowMinimized)) { + // unset old state + if (m_windowState & Qt::WindowMinimized) xcb_map_window(xcb_connection(), m_window); - } else if (!(m_windowState & Qt::WindowMinimized) && (state & Qt::WindowMinimized)) { - xcb_client_message_event_t event; + if (m_windowState & Qt::WindowMaximized) + setNetWmState(false, + atom(QXcbAtom::_NET_WM_STATE_MAXIMIZED_HORZ), + atom(QXcbAtom::_NET_WM_STATE_MAXIMIZED_VERT)); + if (m_windowState & Qt::WindowFullScreen) + setNetWmState(false, atom(QXcbAtom::_NET_WM_STATE_FULLSCREEN)); - event.response_type = XCB_CLIENT_MESSAGE; - event.format = 32; - event.sequence = 0; - event.window = m_window; - event.type = atom(QXcbAtom::WM_CHANGE_STATE); - event.data.data32[0] = XCB_ICCCM_WM_STATE_ICONIC; - event.data.data32[1] = 0; - event.data.data32[2] = 0; - event.data.data32[3] = 0; - event.data.data32[4] = 0; + // set new state + if (state & Qt::WindowMinimized) { + { + xcb_client_message_event_t event; + + event.response_type = XCB_CLIENT_MESSAGE; + event.format = 32; + event.sequence = 0; + event.window = m_window; + event.type = atom(QXcbAtom::WM_CHANGE_STATE); + event.data.data32[0] = XCB_ICCCM_WM_STATE_ICONIC; + event.data.data32[1] = 0; + event.data.data32[2] = 0; + event.data.data32[3] = 0; + event.data.data32[4] = 0; - xcb_send_event(xcb_connection(), 0, xcbScreen()->root(), - XCB_EVENT_MASK_STRUCTURE_NOTIFY | XCB_EVENT_MASK_SUBSTRUCTURE_REDIRECT, - (const char *)&event); + xcb_send_event(xcb_connection(), 0, xcbScreen()->root(), + XCB_EVENT_MASK_STRUCTURE_NOTIFY | XCB_EVENT_MASK_SUBSTRUCTURE_REDIRECT, + (const char *)&event); + } m_minimized = true; } + if (state & Qt::WindowMaximized) + setNetWmState(true, + atom(QXcbAtom::_NET_WM_STATE_MAXIMIZED_HORZ), + atom(QXcbAtom::_NET_WM_STATE_MAXIMIZED_VERT)); + if (state & Qt::WindowFullScreen) + setNetWmState(true, atom(QXcbAtom::_NET_WM_STATE_FULLSCREEN)); setNetWmState(state); |