diff options
Diffstat (limited to 'src/plugins/platforms')
18 files changed, 275 insertions, 267 deletions
diff --git a/src/plugins/platforms/cocoa/qcocoafiledialoghelper.mm b/src/plugins/platforms/cocoa/qcocoafiledialoghelper.mm index e7243ec250..d1695ea860 100644 --- a/src/plugins/platforms/cocoa/qcocoafiledialoghelper.mm +++ b/src/plugins/platforms/cocoa/qcocoafiledialoghelper.mm @@ -55,7 +55,6 @@ #include <qbuffer.h> #include <qdebug.h> #include <qstringlist.h> -#include <qtextcodec.h> #include <qvarlengtharray.h> #include <stdlib.h> #include <qabstracteventdispatcher.h> diff --git a/src/plugins/platforms/cocoa/qcocoascreen.mm b/src/plugins/platforms/cocoa/qcocoascreen.mm index f82ef202b1..0d6567070e 100644 --- a/src/plugins/platforms/cocoa/qcocoascreen.mm +++ b/src/plugins/platforms/cocoa/qcocoascreen.mm @@ -466,6 +466,7 @@ QPixmap QCocoaScreen::grabWindow(WId window, int x, int y, int width, int height const qreal dpr = devicePixelRatio(); QPixmap windowPixmap(windowSize * dpr); + windowPixmap.setDevicePixelRatio(dpr); windowPixmap.fill(Qt::transparent); for (uint i = 0; i < displayCount; ++i) { @@ -473,8 +474,8 @@ QPixmap QCocoaScreen::grabWindow(WId window, int x, int y, int width, int height // Calculate the position and size of the requested area QPoint pos(qAbs(bounds.origin.x - x), qAbs(bounds.origin.y - y)); - QSize size(qMin(pos.x() + width, qRound(bounds.size.width)), - qMin(pos.y() + height, qRound(bounds.size.height))); + QSize size(qMin(width, qRound(bounds.size.width)), + qMin(height, qRound(bounds.size.height))); pos *= dpr; size *= dpr; diff --git a/src/plugins/platforms/cocoa/qpaintengine_mac.mm b/src/plugins/platforms/cocoa/qpaintengine_mac.mm index 96506c67fa..ce7f92f2c7 100644 --- a/src/plugins/platforms/cocoa/qpaintengine_mac.mm +++ b/src/plugins/platforms/cocoa/qpaintengine_mac.mm @@ -47,7 +47,6 @@ #include <private/qpaintengine_raster_p.h> #include <qprinter.h> #include <qstack.h> -#include <qtextcodec.h> #include <qwidget.h> #include <qvarlengtharray.h> #include <qdebug.h> diff --git a/src/plugins/platforms/windows/qwindowsdialoghelpers.cpp b/src/plugins/platforms/windows/qwindowsdialoghelpers.cpp index 681b35eb7c..b629cc00a3 100644 --- a/src/plugins/platforms/windows/qwindowsdialoghelpers.cpp +++ b/src/plugins/platforms/windows/qwindowsdialoghelpers.cpp @@ -558,6 +558,10 @@ public: SFGAOF attributes() const { return m_attributes; } QString normalDisplay() const // base name, usually { return displayName(m_item, SIGDN_NORMALDISPLAY); } + QString urlString() const + { return displayName(m_item, SIGDN_URL); } + QString fileSysPath() const + { return displayName(m_item, SIGDN_FILESYSPATH); } QString desktopAbsoluteParsing() const { return displayName(m_item, SIGDN_DESKTOPABSOLUTEPARSING); } QString path() const; // Only set for 'FileSystem' (SFGAO_FILESYSTEM) items @@ -734,7 +738,8 @@ void QWindowsShellItem::format(QDebug &d) const if (canCopy()) d << " [copyable]"; d << ", normalDisplay=\"" << normalDisplay() - << "\", desktopAbsoluteParsing=\"" << desktopAbsoluteParsing() << '"'; + << "\", desktopAbsoluteParsing=\"" << desktopAbsoluteParsing() + << "\", urlString=\"" << urlString() << "\", fileSysPath=\"" << fileSysPath() << '"'; const QString pathS = path(); if (!pathS.isEmpty()) d << ", path=\"" << pathS << '"'; diff --git a/src/plugins/platforms/windows/qwindowsintegration.cpp b/src/plugins/platforms/windows/qwindowsintegration.cpp index 9e03d09607..cae1452885 100644 --- a/src/plugins/platforms/windows/qwindowsintegration.cpp +++ b/src/plugins/platforms/windows/qwindowsintegration.cpp @@ -312,7 +312,7 @@ bool QWindowsIntegration::hasCapability(QPlatformIntegration::Capability cap) co case AllGLFunctionsQueryable: return true; case SwitchableWidgetComposition: - return true; + return false; // QTBUG-68329 QTBUG-53515 QTBUG-54734 default: return QPlatformIntegration::hasCapability(cap); } diff --git a/src/plugins/platforms/windows/qwindowskeymapper.cpp b/src/plugins/platforms/windows/qwindowskeymapper.cpp index 9e6101b758..96abfdb9d7 100644 --- a/src/plugins/platforms/windows/qwindowskeymapper.cpp +++ b/src/plugins/platforms/windows/qwindowskeymapper.cpp @@ -1263,6 +1263,13 @@ bool QWindowsKeyMapper::translateKeyEventInternal(QWindow *window, MSG msg, } #endif // !QT_NO_SHORTCUT key_recorder.storeKey(int(msg.wParam), a, state, text); + + // QTBUG-71210 + // VK_PACKET specifies multiple characters. The system only sends the first + // character of this sequence for each. + if (msg.wParam == VK_PACKET) + code = asciiToKeycode(char(uch.cell()), state); + QWindowSystemInterface::handleExtendedKeyEvent(receiver, QEvent::KeyPress, code, modifiers, scancode, quint32(msg.wParam), nModifiers, text, false); result =true; diff --git a/src/plugins/platforms/windows/qwindowspointerhandler.cpp b/src/plugins/platforms/windows/qwindowspointerhandler.cpp index 3c7372958f..0bac382a90 100644 --- a/src/plugins/platforms/windows/qwindowspointerhandler.cpp +++ b/src/plugins/platforms/windows/qwindowspointerhandler.cpp @@ -629,6 +629,7 @@ bool QWindowsPointerHandler::translateTouchEvent(QWindow *window, HWND hwnd, bool QWindowsPointerHandler::translatePenEvent(QWindow *window, HWND hwnd, QtWindows::WindowsEventType et, MSG msg, PVOID vPenInfo) { +#if QT_CONFIG(tabletevent) if (et & QtWindows::NonClientEventFlag) return false; // Let DefWindowProc() handle Non Client messages. @@ -723,6 +724,14 @@ bool QWindowsPointerHandler::translatePenEvent(QWindow *window, HWND hwnd, QtWin } } return true; +#else + Q_UNUSED(window); + Q_UNUSED(hwnd); + Q_UNUSED(et); + Q_UNUSED(msg); + Q_UNUSED(vPenInfo); + return false; +#endif } // Process old-style mouse messages here. diff --git a/src/plugins/platforms/xcb/gl_integrations/xcb_glx/qglxintegration.cpp b/src/plugins/platforms/xcb/gl_integrations/xcb_glx/qglxintegration.cpp index 741885e321..6316aa2d99 100644 --- a/src/plugins/platforms/xcb/gl_integrations/xcb_glx/qglxintegration.cpp +++ b/src/plugins/platforms/xcb/gl_integrations/xcb_glx/qglxintegration.cpp @@ -51,6 +51,7 @@ #undef register #include <GL/glx.h> +#include <QtCore/QRegularExpression> #include <QtGui/QOpenGLContext> #include <QtGui/QOffscreenSurface> @@ -692,32 +693,6 @@ static const char *qglx_threadedgl_blacklist_renderer[] = { 0 }; -// This disables threaded rendering on anything using mesa, e.g. -// - nvidia/nouveau -// - amd/gallium -// - intel -// - some software opengl implementations -// -// The client glx vendor string is used to identify those setups as that seems to show the least -// variance between the bad configurations. It's always "Mesa Project and SGI". There are some -// configurations which don't use mesa and which can do threaded rendering (amd and nvidia chips -// with their own proprietary drivers). -// -// This, of course, is very broad and disables threaded rendering on a lot of devices which would -// be able to use it. However, the bugs listed below don't follow any easily recognizable pattern -// and we should rather be safe. -// -// http://cgit.freedesktop.org/xcb/libxcb/commit/?id=be0fe56c3bcad5124dcc6c47a2fad01acd16f71a will -// fix some of the issues. Basically, the proprietary drivers seem to have a way of working around -// a fundamental flaw with multithreaded access to xcb, but mesa doesn't. The blacklist should be -// reevaluated once that patch is released in some version of xcb. -static const char *qglx_threadedgl_blacklist_vendor[] = { - "Mesa Project and SGI", // QTCREATORBUG-10875 (crash in creator) - // QTBUG-34492 (flickering in fullscreen) - // QTBUG-38221 - 0 -}; - void QGLXContext::queryDummyContext() { if (m_queriedDummyContext) @@ -777,18 +752,33 @@ void QGLXContext::queryDummyContext() } } - if (glxvendor) { - for (int i = 0; qglx_threadedgl_blacklist_vendor[i]; ++i) { - if (strstr(glxvendor, qglx_threadedgl_blacklist_vendor[i]) != 0) { - qCDebug(lcQpaGl).nospace() << "Multithreaded OpenGL disabled: " - "blacklisted vendor \"" - << qglx_threadedgl_blacklist_vendor[i] - << "\""; + if (glxvendor && m_supportsThreading) { + // Blacklist Mesa drivers due to QTCREATORBUG-10875 (crash in creator), + // QTBUG-34492 (flickering in fullscreen) and QTBUG-38221 + const char *mesaVersionStr = nullptr; + if (strstr(glxvendor, "Mesa Project") != 0) { + mesaVersionStr = (const char *) glGetString(GL_VERSION); + m_supportsThreading = false; + } - m_supportsThreading = false; - break; + if (mesaVersionStr) { + // The issue was fixed in Xcb 1.11, but we can't check for that + // at runtime, so instead assume it fixed with recent Mesa versions + // released several years after the Xcb fix. + QRegularExpression versionTest(QStringLiteral("Mesa (\\d+)")); + QRegularExpressionMatch result = versionTest.match(QString::fromLatin1(mesaVersionStr)); + int versionNr = 0; + if (result.hasMatch()) + versionNr = result.captured(1).toInt(); + if (versionNr >= 17) { + // White-listed + m_supportsThreading = true; } } + if (!m_supportsThreading) { + qCDebug(lcQpaGl).nospace() << "Multithreaded OpenGL disabled: " + "blacklisted vendor \"Mesa Project\""; + } } context.doneCurrent(); diff --git a/src/plugins/platforms/xcb/qxcbbackingstore.cpp b/src/plugins/platforms/xcb/qxcbbackingstore.cpp index c8c806749f..ba9a3e68ee 100644 --- a/src/plugins/platforms/xcb/qxcbbackingstore.cpp +++ b/src/plugins/platforms/xcb/qxcbbackingstore.cpp @@ -837,6 +837,9 @@ void QXcbBackingStore::endPaint() QImage QXcbBackingStore::toImage() const { + // If the backingstore is rgbSwapped, return the internal image type here. + if (!m_rgbImage.isNull()) + return m_rgbImage; return m_image && m_image->image() ? *m_image->image() : QImage(); } 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/qxcbcursor.cpp b/src/plugins/platforms/xcb/qxcbcursor.cpp index 57629ac03a..7831671d42 100644 --- a/src/plugins/platforms/xcb/qxcbcursor.cpp +++ b/src/plugins/platforms/xcb/qxcbcursor.cpp @@ -255,6 +255,7 @@ static const uint8_t * const cursor_bits20[] = { forbidden_bits, forbiddenm_bits }; +// ### FIXME This mapping is incomplete - QTBUG-71423 static const std::vector<const char *> cursorNames[] = { { "left_ptr", "default", "top_left_arrow", "left_arrow" }, { "up_arrow" }, @@ -273,7 +274,7 @@ static const std::vector<const char *> cursorNames[] = { { "forbidden", "not-allowed", "crossed_circle", "circle", "03b6e0fcb3499374a867c041f52298f0" }, { "whats_this", "help", "question_arrow", "5c6cd98b3f3ebcb1f9c7f1c204630408", "d9ce0ab605698f320427677b458ad60b" }, { "left_ptr_watch", "half-busy", "progress", "00000000000000020006000e7e9ffc3f", "08e8e1c95fe2fc01f976f1e063a24ccd" }, - { "openhand", "fleur", "5aca4d189052212118709018842178c0", "9d800788f1b08800ae810202380a0822" }, + { "openhand", "grab", "fleur", "5aca4d189052212118709018842178c0", "9d800788f1b08800ae810202380a0822" }, { "closedhand", "grabbing", "208530c400c041818281048008011002" }, { "dnd-copy", "copy" }, { "dnd-move", "move" }, 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/qxcbmime.cpp b/src/plugins/platforms/xcb/qxcbmime.cpp index 7170d259fd..d611f86a9c 100644 --- a/src/plugins/platforms/xcb/qxcbmime.cpp +++ b/src/plugins/platforms/xcb/qxcbmime.cpp @@ -168,7 +168,7 @@ QVariant QXcbMime::mimeConvertToFormat(QXcbConnection *connection, xcb_atom_t a, if (!encoding.isEmpty() && atomName == format + QLatin1String(";charset=") + QLatin1String(encoding)) { -#ifndef QT_NO_TEXTCODEC +#if QT_CONFIG(textcodec) if (requestedType == QVariant::String) { QTextCodec *codec = QTextCodec::codecForName(encoding); if (codec) 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); |