diff options
Diffstat (limited to 'src/plugins/platforms')
-rw-r--r-- | src/plugins/platforms/xcb/qxcbclipboard.cpp | 190 | ||||
-rw-r--r-- | src/plugins/platforms/xcb/qxcbclipboard.h | 41 | ||||
-rw-r--r-- | src/plugins/platforms/xcb/qxcbconnection.cpp | 13 | ||||
-rw-r--r-- | src/plugins/platforms/xcb/qxcbconnection.h | 1 | ||||
-rw-r--r-- | src/plugins/platforms/xcb/qxcbeventdispatcher.h | 3 | ||||
-rw-r--r-- | src/plugins/platforms/xcb/qxcbwindow.cpp | 182 | ||||
-rw-r--r-- | src/plugins/platforms/xcb/qxcbwindow.h | 12 |
7 files changed, 218 insertions, 224 deletions
diff --git a/src/plugins/platforms/xcb/qxcbclipboard.cpp b/src/plugins/platforms/xcb/qxcbclipboard.cpp index 3fd14a659e..9c7559d514 100644 --- a/src/plugins/platforms/xcb/qxcbclipboard.cpp +++ b/src/plugins/platforms/xcb/qxcbclipboard.cpp @@ -153,114 +153,71 @@ private: QByteArray format_atoms; }; -namespace { -class INCRTransaction; -typedef QMap<xcb_window_t,INCRTransaction*> TransactionMap; -static TransactionMap *transactions = 0; +QXcbClipboardTransaction::QXcbClipboardTransaction(QXcbClipboard *clipboard, xcb_window_t w, + xcb_atom_t p, QByteArray d, xcb_atom_t t, int f) + : m_clipboard(clipboard), m_window(w), m_property(p), m_data(d), m_target(t), m_format(f) +{ + const quint32 values[] = { XCB_EVENT_MASK_PROPERTY_CHANGE }; + xcb_change_window_attributes(m_clipboard->xcb_connection(), m_window, + XCB_CW_EVENT_MASK, values); -//#define INCR_DEBUG + m_abortTimerId = startTimer(m_clipboard->clipboardTimeout()); +} -class INCRTransaction : public QObject +QXcbClipboardTransaction::~QXcbClipboardTransaction() { - Q_OBJECT -public: - INCRTransaction(QXcbConnection *c, xcb_window_t w, xcb_atom_t p, - QByteArray d, uint i, xcb_atom_t t, int f, int to) : - conn(c), win(w), property(p), data(d), increment(i), - target(t), format(f), timeout(to), offset(0) - { - const quint32 values[] = { XCB_EVENT_MASK_PROPERTY_CHANGE }; - xcb_change_window_attributes(conn->xcb_connection(), win, - XCB_CW_EVENT_MASK, values); - if (!transactions) { -#ifdef INCR_DEBUG - qDebug("INCRTransaction: creating the TransactionMap"); -#endif - transactions = new TransactionMap; - conn->clipboard()->setProcessIncr(true); - } - transactions->insert(win, this); - abort_timer = startTimer(timeout); - } + if (m_abortTimerId) + killTimer(m_abortTimerId); + m_abortTimerId = 0; + m_clipboard->removeTransaction(m_window); +} - ~INCRTransaction() - { - if (abort_timer) - killTimer(abort_timer); - abort_timer = 0; - transactions->remove(win); - if (transactions->isEmpty()) { -#ifdef INCR_DEBUG - qDebug("INCRTransaction: no more INCR transactions left in the TransactionMap"); -#endif - delete transactions; - transactions = 0; - conn->clipboard()->setProcessIncr(false); - } - } +bool QXcbClipboardTransaction::updateIncrementalProperty(const xcb_property_notify_event_t *event) +{ + if (event->atom != m_property || event->state != XCB_PROPERTY_DELETE) + return false; - void updateIncrProperty(xcb_property_notify_event_t *event, bool &accepted) - { - xcb_connection_t *c = conn->xcb_connection(); - if (event->atom == property && event->state == XCB_PROPERTY_DELETE) { - accepted = true; - // restart the timer - if (abort_timer) - killTimer(abort_timer); - abort_timer = startTimer(timeout); - - unsigned int bytes_left = data.size() - offset; - if (bytes_left > 0) { - unsigned int bytes_to_send = qMin(increment, bytes_left); -#ifdef INCR_DEBUG - qDebug("INCRTransaction: sending %d bytes, %d remaining (INCR transaction %p)", - bytes_to_send, bytes_left - bytes_to_send, this); -#endif - int dataSize = bytes_to_send / (format / 8); - xcb_change_property(c, XCB_PROP_MODE_REPLACE, win, property, - target, format, dataSize, data.constData() + offset); - offset += bytes_to_send; - } else { -#ifdef INCR_DEBUG - qDebug("INCRTransaction: INCR transaction %p completed", this); -#endif - xcb_change_property(c, XCB_PROP_MODE_REPLACE, win, property, - target, format, 0, (const void *)0); - const quint32 values[] = { XCB_EVENT_MASK_NO_EVENT }; - xcb_change_window_attributes(conn->xcb_connection(), win, - XCB_CW_EVENT_MASK, values); - // self destroy - delete this; - } - } - } + // restart the timer + if (m_abortTimerId) + killTimer(m_abortTimerId); + m_abortTimerId = startTimer(m_clipboard->clipboardTimeout()); -protected: - void timerEvent(QTimerEvent *ev) override - { - if (ev->timerId() == abort_timer) { - // this can happen when the X client we are sending data - // to decides to exit (normally or abnormally) -#ifdef INCR_DEBUG - qDebug("INCRTransaction: Timed out while sending data to %p", this); -#endif - delete this; - } + uint bytes_left = uint(m_data.size()) - m_offset; + if (bytes_left > 0) { + int increment = m_clipboard->increment(); + uint bytes_to_send = qMin(uint(increment), bytes_left); + + qCDebug(lcQpaClipboard, "sending %d bytes, %d remaining, transaction: %p)", + bytes_to_send, bytes_left - bytes_to_send, this); + + uint32_t dataSize = bytes_to_send / (m_format / 8); + xcb_change_property(m_clipboard->xcb_connection(), XCB_PROP_MODE_REPLACE, m_window, + m_property, m_target, m_format, dataSize, m_data.constData() + m_offset); + m_offset += bytes_to_send; + } else { + qCDebug(lcQpaClipboard, "transaction %p completed", this); + + xcb_change_property(m_clipboard->xcb_connection(), XCB_PROP_MODE_REPLACE, m_window, + m_property, m_target, m_format, 0, nullptr); + + const quint32 values[] = { XCB_EVENT_MASK_NO_EVENT }; + xcb_change_window_attributes(m_clipboard->xcb_connection(), m_window, + XCB_CW_EVENT_MASK, values); + delete this; // self destroy } + return true; +} -private: - QXcbConnection *conn; - xcb_window_t win; - xcb_atom_t property; - QByteArray data; - uint increment; - xcb_atom_t target; - int format; - int timeout; - uint offset; - int abort_timer; -}; -} // unnamed namespace + +void QXcbClipboardTransaction::timerEvent(QTimerEvent *ev) +{ + if (ev->timerId() == m_abortTimerId) { + // this can happen when the X client we are sending data + // to decides to exit (normally or abnormally) + qCDebug(lcQpaClipboard, "timed out while sending data to %p", this); + delete this; // self destroy + } +} const int QXcbClipboard::clipboard_timeout = 5000; @@ -282,6 +239,9 @@ QXcbClipboard::QXcbClipboard(QXcbConnection *c) xcb_xfixes_select_selection_input_checked(xcb_connection(), m_owner, XCB_ATOM_PRIMARY, mask); xcb_xfixes_select_selection_input_checked(xcb_connection(), m_owner, atom(QXcbAtom::CLIPBOARD), mask); } + + // change property protocol request is 24 bytes + m_increment = (xcb_get_maximum_request_length(xcb_connection()) * 4) - 24; } QXcbClipboard::~QXcbClipboard() @@ -313,16 +273,17 @@ QXcbClipboard::~QXcbClipboard() delete m_clientClipboard[QClipboard::Selection]; } -void QXcbClipboard::incrTransactionPeeker(xcb_generic_event_t *ge, bool &accepted) +bool QXcbClipboard::handlePropertyNotify(const xcb_generic_event_t *event) { - uint response_type = ge->response_type & ~0x80; - if (response_type == XCB_PROPERTY_NOTIFY) { - xcb_property_notify_event_t *event = (xcb_property_notify_event_t *)ge; - TransactionMap::Iterator it = transactions->find(event->window); - if (it != transactions->end()) { - (*it)->updateIncrProperty(event, accepted); - } - } + if (m_transactions.isEmpty() || event->response_type != XCB_PROPERTY_NOTIFY) + return false; + + auto propertyNotify = reinterpret_cast<const xcb_property_notify_event_t *>(event); + TransactionMap::Iterator it = m_transactions.find(propertyNotify->window); + if (it == m_transactions.constEnd()) + return false; + + return (*it)->updateIncrementalProperty(propertyNotify); } xcb_window_t QXcbClipboard::getSelectionOwner(xcb_atom_t atom) const @@ -522,19 +483,18 @@ xcb_atom_t QXcbClipboard::sendSelection(QMimeData *d, xcb_atom_t target, xcb_win // This 'bool' can be removed once there is a proper fix for QTBUG-32853 if (m_clipboard_closing) allow_incr = false; - // X_ChangeProperty protocol request is 24 bytes - const int increment = (xcb_get_maximum_request_length(xcb_connection()) * 4) - 24; - if (data.size() > increment && allow_incr) { + + if (data.size() > m_increment && allow_incr) { long bytes = data.size(); xcb_change_property(xcb_connection(), XCB_PROP_MODE_REPLACE, window, property, atom(QXcbAtom::INCR), 32, 1, (const void *)&bytes); - new INCRTransaction(connection(), window, property, data, increment, - atomFormat, dataFormat, clipboard_timeout); + auto transaction = new QXcbClipboardTransaction(this, window, property, data, atomFormat, dataFormat); + m_transactions.insert(window, transaction); return property; } // make sure we can perform the XChangeProperty in a single request - if (data.size() > increment) + if (data.size() > m_increment) return XCB_NONE; // ### perhaps use several XChangeProperty calls w/ PropModeAppend? int dataSize = data.size() / (dataFormat / 8); // use a single request to transfer data diff --git a/src/plugins/platforms/xcb/qxcbclipboard.h b/src/plugins/platforms/xcb/qxcbclipboard.h index abab42a613..26d3b3b395 100644 --- a/src/plugins/platforms/xcb/qxcbclipboard.h +++ b/src/plugins/platforms/xcb/qxcbclipboard.h @@ -45,14 +45,41 @@ #include <xcb/xcb.h> #include <xcb/xfixes.h> +#include <QtCore/QObject> + QT_BEGIN_NAMESPACE #ifndef QT_NO_CLIPBOARD class QXcbConnection; class QXcbScreen; +class QXcbClipboard; class QXcbClipboardMime; +class QXcbClipboardTransaction : public QObject +{ + Q_OBJECT +public: + QXcbClipboardTransaction(QXcbClipboard *clipboard, xcb_window_t w, xcb_atom_t p, + QByteArray d, xcb_atom_t t, int f); + ~QXcbClipboardTransaction(); + + bool updateIncrementalProperty(const xcb_property_notify_event_t *event); + +protected: + void timerEvent(QTimerEvent *ev) override; + +private: + QXcbClipboard *m_clipboard; + xcb_window_t m_window; + xcb_atom_t m_property; + QByteArray m_data; + xcb_atom_t m_target; + uint8_t m_format; + uint m_offset = 0; + int m_abortTimerId = 0; +}; + class QXcbClipboard : public QXcbObject, public QPlatformClipboard { public: @@ -81,13 +108,16 @@ public: QByteArray getDataInFormat(xcb_atom_t modeAtom, xcb_atom_t fmtatom); - void setProcessIncr(bool process) { m_incr_active = process; } - bool processIncr() { return m_incr_active; } - void incrTransactionPeeker(xcb_generic_event_t *ge, bool &accepted); + bool handlePropertyNotify(const xcb_generic_event_t *event); xcb_window_t getSelectionOwner(xcb_atom_t atom) const; QByteArray getSelection(xcb_atom_t selection, xcb_atom_t target, xcb_atom_t property, xcb_timestamp_t t = 0); + int increment() const { return m_increment; } + int clipboardTimeout() const { return clipboard_timeout; } + + void removeTransaction(xcb_window_t window) { m_transactions.remove(window); } + private: xcb_generic_event_t *waitForClipboardEvent(xcb_window_t window, int type, bool checkManager = false); @@ -107,9 +137,12 @@ private: static const int clipboard_timeout; - bool m_incr_active = false; + int m_increment = 0; bool m_clipboard_closing = false; xcb_timestamp_t m_incr_receive_time = 0; + + using TransactionMap = QMap<xcb_window_t, QXcbClipboardTransaction *>; + TransactionMap m_transactions; }; #endif // QT_NO_CLIPBOARD diff --git a/src/plugins/platforms/xcb/qxcbconnection.cpp b/src/plugins/platforms/xcb/qxcbconnection.cpp index 45f096a13a..37ee980924 100644 --- a/src/plugins/platforms/xcb/qxcbconnection.cpp +++ b/src/plugins/platforms/xcb/qxcbconnection.cpp @@ -84,6 +84,7 @@ Q_LOGGING_CATEGORY(lcQpaEvents, "qt.qpa.events") Q_LOGGING_CATEGORY(lcQpaEventReader, "qt.qpa.events.reader") Q_LOGGING_CATEGORY(lcQpaPeeker, "qt.qpa.peeker") Q_LOGGING_CATEGORY(lcQpaKeyboard, "qt.qpa.xkeyboard") +Q_LOGGING_CATEGORY(lcQpaClipboard, "qt.qpa.clipboard") Q_LOGGING_CATEGORY(lcQpaXDnd, "qt.qpa.xdnd") // this event type was added in libxcb 1.10, @@ -651,6 +652,10 @@ void QXcbConnection::handleXcbEvent(xcb_generic_event_t *event) break; case XCB_PROPERTY_NOTIFY: { +#ifndef QT_NO_CLIPBOARD + if (m_clipboard->handlePropertyNotify(event)) + break; +#endif auto propertyNotify = reinterpret_cast<xcb_property_notify_event_t *>(event); if (propertyNotify->atom == atom(QXcbAtom::_NET_WORKAREA)) { QXcbVirtualDesktop *virtualDesktop = virtualDesktopForRootWindow(propertyNotify->window); @@ -1010,14 +1015,6 @@ void QXcbConnection::processXcbEvents(QEventLoop::ProcessEventsFlags flags) if (compressEvent(event)) continue; -#ifndef QT_NO_CLIPBOARD - bool accepted = false; - if (clipboard()->processIncr()) - clipboard()->incrTransactionPeeker(event, accepted); - if (accepted) - continue; -#endif - auto isWaitingFor = [=](PeekFunc peekFunc) { // These callbacks return true if the event is what they were // waiting for, remove them from the list in that case. diff --git a/src/plugins/platforms/xcb/qxcbconnection.h b/src/plugins/platforms/xcb/qxcbconnection.h index 5d53b97d37..47036ca257 100644 --- a/src/plugins/platforms/xcb/qxcbconnection.h +++ b/src/plugins/platforms/xcb/qxcbconnection.h @@ -68,6 +68,7 @@ Q_DECLARE_LOGGING_CATEGORY(lcQpaScreen) Q_DECLARE_LOGGING_CATEGORY(lcQpaEvents) Q_DECLARE_LOGGING_CATEGORY(lcQpaPeeker) Q_DECLARE_LOGGING_CATEGORY(lcQpaKeyboard) +Q_DECLARE_LOGGING_CATEGORY(lcQpaClipboard) Q_DECLARE_LOGGING_CATEGORY(lcQpaXDnd) Q_DECLARE_LOGGING_CATEGORY(lcQpaEventReader) diff --git a/src/plugins/platforms/xcb/qxcbeventdispatcher.h b/src/plugins/platforms/xcb/qxcbeventdispatcher.h index 6aadd63a70..ddf448cf87 100644 --- a/src/plugins/platforms/xcb/qxcbeventdispatcher.h +++ b/src/plugins/platforms/xcb/qxcbeventdispatcher.h @@ -107,9 +107,6 @@ class QXcbEventDispatcher { public: static QAbstractEventDispatcher *createEventDispatcher(QXcbConnection *connection); - -private: - QXcbConnection *m_connection; }; QT_END_NAMESPACE diff --git a/src/plugins/platforms/xcb/qxcbwindow.cpp b/src/plugins/platforms/xcb/qxcbwindow.cpp index 70aab77a51..891fe6b155 100644 --- a/src/plugins/platforms/xcb/qxcbwindow.cpp +++ b/src/plugins/platforms/xcb/qxcbwindow.cpp @@ -755,7 +755,7 @@ void QXcbWindow::show() xcb_delete_property(xcb_connection(), m_window, XCB_ATOM_WM_TRANSIENT_FOR); // update _NET_WM_STATE - updateNetWmStateBeforeMap(); + setNetWmStateOnUnmappedWindow(); } // QWidget-attribute Qt::WA_ShowWithoutActivating. @@ -963,46 +963,6 @@ QXcbWindow::NetWmStates QXcbWindow::netWmStates() return result; } -void QXcbWindow::setNetWmStates(NetWmStates states) -{ - QVector<xcb_atom_t> atoms; - - auto reply = Q_XCB_REPLY_UNCHECKED(xcb_get_property, xcb_connection(), - 0, m_window, atom(QXcbAtom::_NET_WM_STATE), - XCB_ATOM_ATOM, 0, 1024); - if (reply && reply->format == 32 && reply->type == XCB_ATOM_ATOM && reply->value_len > 0) { - const xcb_atom_t *data = static_cast<const xcb_atom_t *>(xcb_get_property_value(reply.get())); - atoms.resize(reply->value_len); - memcpy((void *)&atoms.first(), (void *)data, reply->value_len * sizeof(xcb_atom_t)); - } - - if (states & NetWmStateAbove && !atoms.contains(atom(QXcbAtom::_NET_WM_STATE_ABOVE))) - atoms.push_back(atom(QXcbAtom::_NET_WM_STATE_ABOVE)); - if (states & NetWmStateBelow && !atoms.contains(atom(QXcbAtom::_NET_WM_STATE_BELOW))) - atoms.push_back(atom(QXcbAtom::_NET_WM_STATE_BELOW)); - if (states & NetWmStateFullScreen && !atoms.contains(atom(QXcbAtom::_NET_WM_STATE_FULLSCREEN))) - atoms.push_back(atom(QXcbAtom::_NET_WM_STATE_FULLSCREEN)); - if (states & NetWmStateMaximizedHorz && !atoms.contains(atom(QXcbAtom::_NET_WM_STATE_MAXIMIZED_HORZ))) - atoms.push_back(atom(QXcbAtom::_NET_WM_STATE_MAXIMIZED_HORZ)); - if (states & NetWmStateMaximizedVert && !atoms.contains(atom(QXcbAtom::_NET_WM_STATE_MAXIMIZED_VERT))) - atoms.push_back(atom(QXcbAtom::_NET_WM_STATE_MAXIMIZED_VERT)); - if (states & NetWmStateModal && !atoms.contains(atom(QXcbAtom::_NET_WM_STATE_MODAL))) - atoms.push_back(atom(QXcbAtom::_NET_WM_STATE_MODAL)); - if (states & NetWmStateStaysOnTop && !atoms.contains(atom(QXcbAtom::_NET_WM_STATE_STAYS_ON_TOP))) - atoms.push_back(atom(QXcbAtom::_NET_WM_STATE_STAYS_ON_TOP)); - if (states & NetWmStateDemandsAttention && !atoms.contains(atom(QXcbAtom::_NET_WM_STATE_DEMANDS_ATTENTION))) - atoms.push_back(atom(QXcbAtom::_NET_WM_STATE_DEMANDS_ATTENTION)); - - if (atoms.isEmpty()) { - xcb_delete_property(xcb_connection(), m_window, atom(QXcbAtom::_NET_WM_STATE)); - } else { - xcb_change_property(xcb_connection(), XCB_PROP_MODE_REPLACE, m_window, - atom(QXcbAtom::_NET_WM_STATE), XCB_ATOM_ATOM, 32, - atoms.count(), atoms.constData()); - } - xcb_flush(xcb_connection()); -} - void QXcbWindow::setWindowFlags(Qt::WindowFlags flags) { Qt::WindowType type = static_cast<Qt::WindowType>(int(flags & Qt::WindowType_Mask)); @@ -1029,7 +989,7 @@ void QXcbWindow::setWindowFlags(Qt::WindowFlags flags) } setWmWindowType(wmWindowTypes, flags); - setNetWmStateWindowFlags(flags); + setNetWmState(flags); setMotifWmHints(flags); setTransparentForMouseEvents(flags & Qt::WindowTransparentForInput); @@ -1113,7 +1073,7 @@ void QXcbWindow::setMotifWmHints(Qt::WindowFlags flags) } } -void QXcbWindow::changeNetWmState(bool set, xcb_atom_t one, xcb_atom_t two) +void QXcbWindow::setNetWmState(bool set, xcb_atom_t one, xcb_atom_t two) { xcb_client_message_event_t event; @@ -1133,6 +1093,96 @@ void QXcbWindow::changeNetWmState(bool set, xcb_atom_t one, xcb_atom_t two) (const char *)&event); } +void QXcbWindow::setNetWmState(Qt::WindowStates state) +{ + if ((m_windowState ^ state) & Qt::WindowMaximized) { + setNetWmState(state & Qt::WindowMaximized, + atom(QXcbAtom::_NET_WM_STATE_MAXIMIZED_HORZ), + atom(QXcbAtom::_NET_WM_STATE_MAXIMIZED_VERT)); + } + + if ((m_windowState ^ state) & Qt::WindowFullScreen) + setNetWmState(state & Qt::WindowFullScreen, atom(QXcbAtom::_NET_WM_STATE_FULLSCREEN)); +} + +void QXcbWindow::setNetWmState(Qt::WindowFlags flags) +{ + setNetWmState(flags & Qt::WindowStaysOnTopHint, + atom(QXcbAtom::_NET_WM_STATE_ABOVE), + atom(QXcbAtom::_NET_WM_STATE_STAYS_ON_TOP)); + setNetWmState(flags & Qt::WindowStaysOnBottomHint, atom(QXcbAtom::_NET_WM_STATE_BELOW)); +} + +void QXcbWindow::setNetWmStateOnUnmappedWindow() +{ + if (Q_UNLIKELY(m_mapped)) + qCWarning(lcQpaXcb()) << "internal error: " << Q_FUNC_INFO << "called on mapped window"; + + NetWmStates states(0); + const Qt::WindowFlags flags = window()->flags(); + if (flags & Qt::WindowStaysOnTopHint) { + states |= NetWmStateAbove; + states |= NetWmStateStaysOnTop; + } else if (flags & Qt::WindowStaysOnBottomHint) { + states |= NetWmStateBelow; + } + + if (window()->windowStates() & Qt::WindowFullScreen) + states |= NetWmStateFullScreen; + + if (window()->windowStates() & Qt::WindowMaximized) { + states |= NetWmStateMaximizedHorz; + states |= NetWmStateMaximizedVert; + } + + if (window()->modality() != Qt::NonModal) + states |= NetWmStateModal; + + // According to EWMH: + // "The Window Manager should remove _NET_WM_STATE whenever a window is withdrawn". + // Which means that we don't have to read this property before changing it on a withdrawn + // window. But there are situations where users want to adjust this property as well + // (e4cea305ed2ba3c9f580bf9d16c59a1048af0e8a), so instead of overwriting the property + // we first read it and then merge our hints with the existing values, allowing a user + // to set custom hints. + + QVector<xcb_atom_t> atoms; + auto reply = Q_XCB_REPLY_UNCHECKED(xcb_get_property, xcb_connection(), + 0, m_window, atom(QXcbAtom::_NET_WM_STATE), + XCB_ATOM_ATOM, 0, 1024); + if (reply && reply->format == 32 && reply->type == XCB_ATOM_ATOM && reply->value_len > 0) { + const xcb_atom_t *data = static_cast<const xcb_atom_t *>(xcb_get_property_value(reply.get())); + atoms.resize(reply->value_len); + memcpy((void *)&atoms.first(), (void *)data, reply->value_len * sizeof(xcb_atom_t)); + } + + if (states & NetWmStateAbove && !atoms.contains(atom(QXcbAtom::_NET_WM_STATE_ABOVE))) + atoms.push_back(atom(QXcbAtom::_NET_WM_STATE_ABOVE)); + if (states & NetWmStateBelow && !atoms.contains(atom(QXcbAtom::_NET_WM_STATE_BELOW))) + atoms.push_back(atom(QXcbAtom::_NET_WM_STATE_BELOW)); + if (states & NetWmStateFullScreen && !atoms.contains(atom(QXcbAtom::_NET_WM_STATE_FULLSCREEN))) + atoms.push_back(atom(QXcbAtom::_NET_WM_STATE_FULLSCREEN)); + if (states & NetWmStateMaximizedHorz && !atoms.contains(atom(QXcbAtom::_NET_WM_STATE_MAXIMIZED_HORZ))) + atoms.push_back(atom(QXcbAtom::_NET_WM_STATE_MAXIMIZED_HORZ)); + if (states & NetWmStateMaximizedVert && !atoms.contains(atom(QXcbAtom::_NET_WM_STATE_MAXIMIZED_VERT))) + atoms.push_back(atom(QXcbAtom::_NET_WM_STATE_MAXIMIZED_VERT)); + if (states & NetWmStateModal && !atoms.contains(atom(QXcbAtom::_NET_WM_STATE_MODAL))) + atoms.push_back(atom(QXcbAtom::_NET_WM_STATE_MODAL)); + if (states & NetWmStateStaysOnTop && !atoms.contains(atom(QXcbAtom::_NET_WM_STATE_STAYS_ON_TOP))) + atoms.push_back(atom(QXcbAtom::_NET_WM_STATE_STAYS_ON_TOP)); + if (states & NetWmStateDemandsAttention && !atoms.contains(atom(QXcbAtom::_NET_WM_STATE_DEMANDS_ATTENTION))) + atoms.push_back(atom(QXcbAtom::_NET_WM_STATE_DEMANDS_ATTENTION)); + + if (atoms.isEmpty()) { + xcb_delete_property(xcb_connection(), m_window, atom(QXcbAtom::_NET_WM_STATE)); + } else { + xcb_change_property(xcb_connection(), XCB_PROP_MODE_REPLACE, m_window, + atom(QXcbAtom::_NET_WM_STATE), XCB_ATOM_ATOM, 32, + atoms.count(), atoms.constData()); + } + xcb_flush(xcb_connection()); +} + void QXcbWindow::setWindowState(Qt::WindowStates state) { if (state == m_windowState) @@ -1160,14 +1210,7 @@ void QXcbWindow::setWindowState(Qt::WindowStates state) m_minimized = true; } - if ((m_windowState ^ state) & Qt::WindowMaximized) { - changeNetWmState(state & Qt::WindowMaximized, atom(QXcbAtom::_NET_WM_STATE_MAXIMIZED_HORZ), - atom(QXcbAtom::_NET_WM_STATE_MAXIMIZED_VERT)); - } - - if ((m_windowState ^ state) & Qt::WindowFullScreen) { - changeNetWmState(state & Qt::WindowFullScreen, atom(QXcbAtom::_NET_WM_STATE_FULLSCREEN)); - } + setNetWmState(state); xcb_get_property_cookie_t cookie = xcb_get_wm_hints_unchecked(xcb_connection(), m_window); xcb_wm_hints_t hints; @@ -1183,41 +1226,6 @@ void QXcbWindow::setWindowState(Qt::WindowStates state) m_windowState = state; } -void QXcbWindow::updateNetWmStateBeforeMap() -{ - NetWmStates states(0); - - const Qt::WindowFlags flags = window()->flags(); - if (flags & Qt::WindowStaysOnTopHint) { - states |= NetWmStateAbove; - states |= NetWmStateStaysOnTop; - } else if (flags & Qt::WindowStaysOnBottomHint) { - states |= NetWmStateBelow; - } - - if (window()->windowStates() & Qt::WindowFullScreen) - states |= NetWmStateFullScreen; - - if (window()->windowStates() & Qt::WindowMaximized) { - states |= NetWmStateMaximizedHorz; - states |= NetWmStateMaximizedVert; - } - - if (window()->modality() != Qt::NonModal) - states |= NetWmStateModal; - - setNetWmStates(states); -} - -void QXcbWindow::setNetWmStateWindowFlags(Qt::WindowFlags flags) -{ - changeNetWmState(flags & Qt::WindowStaysOnTopHint, - atom(QXcbAtom::_NET_WM_STATE_ABOVE), - atom(QXcbAtom::_NET_WM_STATE_STAYS_ON_TOP)); - changeNetWmState(flags & Qt::WindowStaysOnBottomHint, - atom(QXcbAtom::_NET_WM_STATE_BELOW)); -} - void QXcbWindow::updateNetWmUserTime(xcb_timestamp_t timestamp) { xcb_window_t wid = m_window; @@ -2590,7 +2598,7 @@ void QXcbWindow::setAlertState(bool enabled) m_alertState = enabled; - changeNetWmState(enabled, atom(QXcbAtom::_NET_WM_STATE_DEMANDS_ATTENTION)); + setNetWmState(enabled, atom(QXcbAtom::_NET_WM_STATE_DEMANDS_ATTENTION)); } uint QXcbWindow::visualId() const diff --git a/src/plugins/platforms/xcb/qxcbwindow.h b/src/plugins/platforms/xcb/qxcbwindow.h index 6667f45343..f98cd8a74d 100644 --- a/src/plugins/platforms/xcb/qxcbwindow.h +++ b/src/plugins/platforms/xcb/qxcbwindow.h @@ -193,21 +193,19 @@ protected: void setImageFormatForVisual(const xcb_visualtype_t *visual); QXcbScreen *parentScreen(); - QXcbScreen *initialScreen() const; - void changeNetWmState(bool set, xcb_atom_t one, xcb_atom_t two = 0); + + void setNetWmState(bool set, xcb_atom_t one, xcb_atom_t two = 0); + void setNetWmState(Qt::WindowFlags flags); + void setNetWmState(Qt::WindowStates state); + void setNetWmStateOnUnmappedWindow(); NetWmStates netWmStates(); - void setNetWmStates(NetWmStates); void setMotifWmHints(Qt::WindowFlags flags); - void setNetWmStateWindowFlags(Qt::WindowFlags flags); - void updateNetWmStateBeforeMap(); - void setTransparentForMouseEvents(bool transparent); void updateDoesNotAcceptFocus(bool doesNotAcceptFocus); - QRect windowToWmGeometry(QRect r) const; void sendXEmbedMessage(xcb_window_t window, quint32 message, quint32 detail = 0, quint32 data1 = 0, quint32 data2 = 0); void handleXEmbedMessage(const xcb_client_message_event_t *event); |