diff options
Diffstat (limited to 'src/plugins/platforms/xcb')
21 files changed, 290 insertions, 137 deletions
diff --git a/src/plugins/platforms/xcb/gl_integrations/xcb_egl/xcb_egl.pro b/src/plugins/platforms/xcb/gl_integrations/xcb_egl/xcb_egl.pro index 28a572a2c9..6d52332bad 100644 --- a/src/plugins/platforms/xcb/gl_integrations/xcb_egl/xcb_egl.pro +++ b/src/plugins/platforms/xcb/gl_integrations/xcb_egl/xcb_egl.pro @@ -1,10 +1,5 @@ TARGET = qxcb-egl-integration -PLUGIN_CLASS_NAME = QXcbEglIntegrationPlugin -PLUGIN_TYPE = xcbglintegrations - -load(qt_plugin) - include(../gl_integrations_plugin_base.pri) CONFIG += egl @@ -22,3 +17,7 @@ SOURCES += \ qxcbeglwindow.cpp \ qxcbeglmain.cpp \ qxcbeglnativeinterfacehandler.cpp + +PLUGIN_CLASS_NAME = QXcbEglIntegrationPlugin +PLUGIN_TYPE = xcbglintegrations +load(qt_plugin) 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 ff624d9755..4290ec54fc 100644 --- a/src/plugins/platforms/xcb/gl_integrations/xcb_glx/qglxintegration.cpp +++ b/src/plugins/platforms/xcb/gl_integrations/xcb_glx/qglxintegration.cpp @@ -550,10 +550,10 @@ void QGLXContext::swapBuffers(QPlatformSurface *surface) } } -void (*QGLXContext::getProcAddress(const QByteArray &procName)) () +QFunctionPointer QGLXContext::getProcAddress(const char *procName) { #ifdef QT_STATIC - return glXGetProcAddressARB(reinterpret_cast<const GLubyte *>(procName.constData())); + return glXGetProcAddressARB(reinterpret_cast<const GLubyte *>(procName)); #else typedef void *(*qt_glXGetProcAddressARB)(const GLubyte *); static qt_glXGetProcAddressARB glXGetProcAddressARB = 0; @@ -585,7 +585,7 @@ void (*QGLXContext::getProcAddress(const QByteArray &procName)) () } if (!glXGetProcAddressARB) return 0; - return (void (*)())glXGetProcAddressARB(reinterpret_cast<const GLubyte *>(procName.constData())); + return (void (*)())glXGetProcAddressARB(reinterpret_cast<const GLubyte *>(procName)); #endif } diff --git a/src/plugins/platforms/xcb/gl_integrations/xcb_glx/qglxintegration.h b/src/plugins/platforms/xcb/gl_integrations/xcb_glx/qglxintegration.h index e5cbee3363..f00d96e6d5 100644 --- a/src/plugins/platforms/xcb/gl_integrations/xcb_glx/qglxintegration.h +++ b/src/plugins/platforms/xcb/gl_integrations/xcb_glx/qglxintegration.h @@ -63,7 +63,7 @@ public: bool makeCurrent(QPlatformSurface *surface) Q_DECL_OVERRIDE; void doneCurrent() Q_DECL_OVERRIDE; void swapBuffers(QPlatformSurface *surface) Q_DECL_OVERRIDE; - QFunctionPointer getProcAddress(const QByteArray &procName) Q_DECL_OVERRIDE; + QFunctionPointer getProcAddress(const char *procName) Q_DECL_OVERRIDE; QSurfaceFormat format() const Q_DECL_OVERRIDE; bool isSharing() const Q_DECL_OVERRIDE; diff --git a/src/plugins/platforms/xcb/gl_integrations/xcb_glx/xcb_glx.pro b/src/plugins/platforms/xcb/gl_integrations/xcb_glx/xcb_glx.pro index 1c577e5dc9..67fd68765a 100644 --- a/src/plugins/platforms/xcb/gl_integrations/xcb_glx/xcb_glx.pro +++ b/src/plugins/platforms/xcb/gl_integrations/xcb_glx/xcb_glx.pro @@ -1,10 +1,5 @@ TARGET = qxcb-glx-integration -PLUGIN_CLASS_NAME = QXcbGlxIntegrationPlugin -PLUGIN_TYPE = xcbglintegrations - -load(qt_plugin) - include(../gl_integrations_plugin_base.pri) #should be removed from the sources @@ -31,3 +26,7 @@ SOURCES += \ qxcbglxwindow.cpp \ qglxintegration.cpp \ qxcbglxnativeinterfacehandler.cpp + +PLUGIN_CLASS_NAME = QXcbGlxIntegrationPlugin +PLUGIN_TYPE = xcbglintegrations +load(qt_plugin) diff --git a/src/plugins/platforms/xcb/qxcbbackingstore.cpp b/src/plugins/platforms/xcb/qxcbbackingstore.cpp index 3d22c9f4dd..9ea1f5c33d 100644 --- a/src/plugins/platforms/xcb/qxcbbackingstore.cpp +++ b/src/plugins/platforms/xcb/qxcbbackingstore.cpp @@ -74,13 +74,17 @@ public: QSize size() const { return m_qimage.size(); } bool hasAlpha() const { return m_hasAlpha; } + bool hasShm() const { return m_shm_info.shmaddr != nullptr; } - void put(xcb_window_t window, const QPoint &dst, const QRect &source); + void put(xcb_window_t window, const QRegion ®ion, const QPoint &offset); void preparePaint(const QRegion ®ion); private: void destroy(); + void flushPixmap(const QRegion ®ion); + void setClip(const QRegion ®ion); + xcb_shm_segment_info_t m_shm_info; xcb_image_t *m_xcb_image; @@ -91,7 +95,15 @@ private: xcb_gcontext_t m_gc; xcb_window_t m_gc_window; - QRegion m_dirty; + // When using shared memory this is the region currently shared with the server + QRegion m_dirtyShm; + + // When not using shared memory, we maintain a server-side pixmap with the backing + // store as well as repainted content not yet flushed to the pixmap. We only flush + // the regions we need and only when these are marked dirty. This way we can just + // do a server-side copy on expose instead of sending the pixels every time + xcb_pixmap_t m_xcb_pixmap; + QRegion m_pendingFlush; bool m_hasAlpha; }; @@ -131,17 +143,12 @@ QXcbShmImage::QXcbShmImage(QXcbScreen *screen, const QSize &size, uint depth, QI , m_graphics_buffer(Q_NULLPTR) , m_gc(0) , m_gc_window(0) + , m_xcb_pixmap(0) { Q_XCB_NOOP(connection()); - const xcb_setup_t *setup = xcb_get_setup(xcb_connection()); - xcb_format_t *fmt = xcb_setup_pixmap_formats(setup); - xcb_format_t *fmtend = fmt + xcb_setup_pixmap_formats_length(setup); - for (; fmt != fmtend; ++fmt) - if (fmt->depth == depth) - break; - - Q_ASSERT(fmt != fmtend); + const xcb_format_t *fmt = connection()->formatForDepth(depth); + Q_ASSERT(fmt); m_xcb_image = xcb_image_create(size.width(), size.height(), XCB_IMAGE_FORMAT_Z_PIXMAP, @@ -180,7 +187,7 @@ QXcbShmImage::QXcbShmImage(QXcbScreen *screen, const QSize &size, uint depth, QI m_xcb_image->data = (uint8_t *)malloc(segmentSize); } else { if (shmctl(m_shm_info.shmid, IPC_RMID, 0) == -1) - qWarning() << "QXcbBackingStore: Error while marking the shared memory segment to be destroyed"; + qWarning("QXcbBackingStore: Error while marking the shared memory segment to be destroyed"); } m_hasAlpha = QImage::toPixelFormat(format).alphaUsage() == QPixelFormat::UsesAlpha; @@ -189,6 +196,15 @@ QXcbShmImage::QXcbShmImage(QXcbScreen *screen, const QSize &size, uint depth, QI m_qimage = QImage( (uchar*) m_xcb_image->data, m_xcb_image->width, m_xcb_image->height, m_xcb_image->stride, format); m_graphics_buffer = new QXcbShmGraphicsBuffer(&m_qimage); + + if (!hasShm()) { + m_xcb_pixmap = xcb_generate_id(xcb_connection()); + Q_XCB_CALL(xcb_create_pixmap(xcb_connection(), + m_xcb_image->depth, + m_xcb_pixmap, + screen->screen()->root, + m_xcb_image->width, m_xcb_image->height)); + } } void QXcbShmImage::destroy() @@ -212,95 +228,163 @@ void QXcbShmImage::destroy() Q_XCB_CALL(xcb_free_gc(xcb_connection(), m_gc)); delete m_graphics_buffer; m_graphics_buffer = Q_NULLPTR; -} -void QXcbShmImage::put(xcb_window_t window, const QPoint &target, const QRect &source) -{ - Q_XCB_NOOP(connection()); - if (m_gc_window != window) { - if (m_gc) - Q_XCB_CALL(xcb_free_gc(xcb_connection(), m_gc)); - - m_gc = xcb_generate_id(xcb_connection()); - Q_XCB_CALL(xcb_create_gc(xcb_connection(), m_gc, window, 0, 0)); - - m_gc_window = window; + if (m_xcb_pixmap) { + Q_XCB_CALL(xcb_free_pixmap(xcb_connection(), m_xcb_pixmap)); + m_xcb_pixmap = 0; } +} - Q_XCB_NOOP(connection()); - if (m_shm_info.shmaddr) { - xcb_image_shm_put(xcb_connection(), - window, - m_gc, - m_xcb_image, - m_shm_info, - source.x(), - source.y(), - target.x(), - target.y(), - source.width(), - source.height(), - false); - } else { - // If we upload the whole image in a single chunk, the result might be - // larger than the server's maximum request size and stuff breaks. - // To work around that, we upload the image in chunks where each chunk - // is small enough for a single request. - int src_x = source.x(); - int src_y = source.y(); - int target_x = target.x(); - int target_y = target.y(); - int width = source.width(); - int height = source.height(); +void QXcbShmImage::flushPixmap(const QRegion ®ion) +{ + const QVector<QRect> rects = m_pendingFlush.intersected(region).rects(); + m_pendingFlush -= region; + for (const QRect &rect : rects) { // We must make sure that each request is not larger than max_req_size. // Each request takes req_size + m_xcb_image->stride * height bytes. - uint32_t max_req_size = xcb_get_maximum_request_length(xcb_connection()); - uint32_t req_size = sizeof(xcb_put_image_request_t); - int rows_per_put = (max_req_size - req_size) / m_xcb_image->stride; + static const uint32_t req_size = sizeof(xcb_put_image_request_t); + const uint32_t max_req_size = xcb_get_maximum_request_length(xcb_connection()); + const int rows_per_put = (max_req_size - req_size) / m_xcb_image->stride; // This assert could trigger if a single row has more pixels than fit in // a single PutImage request. However, max_req_size is guaranteed to be // at least 16384 bytes. That should be enough for quite large images. Q_ASSERT(rows_per_put > 0); - // Convert the image to the native byte order. - xcb_image_t *converted_image = xcb_image_native(xcb_connection(), m_xcb_image, 1); + // If we upload the whole image in a single chunk, the result might be + // larger than the server's maximum request size and stuff breaks. + // To work around that, we upload the image in chunks where each chunk + // is small enough for a single request. + int src_x = rect.x(); + int src_y = rect.y(); + int target_x = rect.x(); + int target_y = rect.y(); + int width = rect.width(); + int height = rect.height(); while (height > 0) { int rows = std::min(height, rows_per_put); - xcb_image_t *subimage = xcb_image_subimage(converted_image, src_x, src_y, width, rows, + xcb_image_t *subimage = xcb_image_subimage(m_xcb_image, src_x, src_y, width, rows, 0, 0, 0); + + // Convert the image to the native byte order. + xcb_image_t *native_subimage = xcb_image_native(xcb_connection(), subimage, 1); + xcb_image_put(xcb_connection(), - window, + m_xcb_pixmap, m_gc, - subimage, + native_subimage, target_x, target_y, 0); + if (native_subimage != subimage) + xcb_image_destroy(native_subimage); + xcb_image_destroy(subimage); src_y += rows; target_y += rows; height -= rows; } + } +} + +void QXcbShmImage::setClip(const QRegion ®ion) +{ + if (region.isEmpty()) { + static const uint32_t mask = XCB_GC_CLIP_MASK; + static const uint32_t values[] = { XCB_NONE }; + Q_XCB_CALL(xcb_change_gc(xcb_connection(), + m_gc, + mask, + values)); + } else { + const QVector<QRect> qrects = region.rects(); + QVector<xcb_rectangle_t> xcb_rects(qrects.size()); + + for (int i = 0; i < qrects.size(); i++) { + xcb_rects[i].x = qrects[i].x(); + xcb_rects[i].y = qrects[i].y(); + xcb_rects[i].width = qrects[i].width(); + xcb_rects[i].height = qrects[i].height(); + } - if (converted_image != m_xcb_image) - xcb_image_destroy(converted_image); + Q_XCB_CALL(xcb_set_clip_rectangles(xcb_connection(), + XCB_CLIP_ORDERING_YX_BANDED, + m_gc, + 0, 0, + xcb_rects.size(), xcb_rects.constData())); } +} + +void QXcbShmImage::put(xcb_window_t window, const QRegion ®ion, const QPoint &offset) +{ Q_XCB_NOOP(connection()); - m_dirty = m_dirty | source; + if (m_gc_window != window) { + if (m_gc) + Q_XCB_CALL(xcb_free_gc(xcb_connection(), m_gc)); + + static const uint32_t mask = XCB_GC_GRAPHICS_EXPOSURES; + static const uint32_t values[] = { 0 }; + + m_gc = xcb_generate_id(xcb_connection()); + Q_XCB_CALL(xcb_create_gc(xcb_connection(), m_gc, window, mask, values)); + + m_gc_window = window; + } + + Q_XCB_NOOP(connection()); + + setClip(region); + + const QRect bounds = region.boundingRect(); + const QPoint target = bounds.topLeft(); + const QRect source = bounds.translated(offset); + + if (hasShm()) { + Q_XCB_CALL(xcb_shm_put_image(xcb_connection(), + window, + m_gc, + m_xcb_image->width, + m_xcb_image->height, + source.x(), source.y(), + source.width(), source.height(), + target.x(), target.y(), + m_xcb_image->depth, + m_xcb_image->format, + 0, // send event? + m_shm_info.shmseg, + m_xcb_image->data - m_shm_info.shmaddr)); + m_dirtyShm |= region.translated(offset); + } else { + flushPixmap(region); + Q_XCB_CALL(xcb_copy_area(xcb_connection(), + m_xcb_pixmap, + window, + m_gc, + source.x(), source.y(), + target.x(), target.y(), + source.width(), source.height())); + } + + setClip(QRegion()); + Q_XCB_NOOP(connection()); } void QXcbShmImage::preparePaint(const QRegion ®ion) { - // to prevent X from reading from the image region while we're writing to it - if (m_dirty.intersects(region)) { - connection()->sync(); - m_dirty = QRegion(); + if (hasShm()) { + // to prevent X from reading from the image region while we're writing to it + if (m_dirtyShm.intersects(region)) { + connection()->sync(); + m_dirtyShm = QRegion(); + } + } else { + m_pendingFlush |= region; } } @@ -396,10 +480,7 @@ void QXcbBackingStore::flush(QWindow *window, const QRegion ®ion, const QPoin return; } - for (const QRect &r : clipped) { - QRect rect = QRect(r.topLeft(), r.size()); - m_image->put(platformWindow->xcb_window(), rect.topLeft(), rect.translated(offset)); - } + m_image->put(platformWindow->xcb_window(), clipped, offset); Q_XCB_NOOP(connection()); diff --git a/src/plugins/platforms/xcb/qxcbconnection.cpp b/src/plugins/platforms/xcb/qxcbconnection.cpp index 998f4884aa..4fee772cd6 100644 --- a/src/plugins/platforms/xcb/qxcbconnection.cpp +++ b/src/plugins/platforms/xcb/qxcbconnection.cpp @@ -1962,7 +1962,9 @@ static const char * xcb_atomnames = { "_COMPIZ_DECOR_PENDING\0" "_COMPIZ_DECOR_REQUEST\0" "_COMPIZ_DECOR_DELETE_PIXMAP\0" - "_COMPIZ_TOOLKIT_ACTION\0" // \0\0 terminates loop. + "_COMPIZ_TOOLKIT_ACTION\0" + "_GTK_LOAD_ICONTHEMES\0" + // \0\0 terminates loop. }; QXcbAtom::Atom QXcbConnection::qatom(xcb_atom_t xatom) const @@ -2173,7 +2175,7 @@ void QXcbConnection::initializeXKB() #ifndef QT_NO_XKB const xcb_query_extension_reply_t *reply = xcb_get_extension_data(m_connection, &xcb_xkb_id); if (!reply || !reply->present) { - qWarning() << "Qt: XKEYBOARD extension not present on the X server."; + qWarning("Qt: XKEYBOARD extension not present on the X server."); xkb_first_event = 0; return; } @@ -2227,7 +2229,7 @@ void QXcbConnection::initializeXKB() xcb_generic_error_t *error = xcb_request_check(c, select); if (error) { free(error); - qWarning() << "Qt: failed to select notify events from xcb-xkb"; + qWarning("Qt: failed to select notify events from xcb-xkb"); return; } #endif diff --git a/src/plugins/platforms/xcb/qxcbconnection.h b/src/plugins/platforms/xcb/qxcbconnection.h index 02dc95e852..9fed7b52f1 100644 --- a/src/plugins/platforms/xcb/qxcbconnection.h +++ b/src/plugins/platforms/xcb/qxcbconnection.h @@ -294,6 +294,7 @@ namespace QXcbAtom { _COMPIZ_DECOR_REQUEST, _COMPIZ_DECOR_DELETE_PIXMAP, _COMPIZ_TOOLKIT_ACTION, + _GTK_LOAD_ICONTHEMES, NPredefinedAtoms, @@ -355,7 +356,7 @@ public: virtual void handleFocusOutEvent(const xcb_focus_out_event_t *) {} virtual void handlePropertyNotifyEvent(const xcb_property_notify_event_t *) {} #ifdef XCB_USE_XINPUT22 - virtual void handleXIMouseEvent(xcb_ge_event_t *) {} + virtual void handleXIMouseEvent(xcb_ge_event_t *, Qt::MouseEventSource = Qt::MouseEventNotSynthesized) {} virtual void handleXIEnterLeave(xcb_ge_event_t *) {} #endif virtual QXcbWindow *toWindow() { return 0; } diff --git a/src/plugins/platforms/xcb/qxcbconnection_xi2.cpp b/src/plugins/platforms/xcb/qxcbconnection_xi2.cpp index e94433dd4b..63a650a514 100644 --- a/src/plugins/platforms/xcb/qxcbconnection_xi2.cpp +++ b/src/plugins/platforms/xcb/qxcbconnection_xi2.cpp @@ -1136,7 +1136,7 @@ bool QXcbConnection::xi2HandleTabletEvent(void *event, TabletData *tabletData, Q // Synthesize mouse events since otherwise there are no mouse events from // the pen on the XI 2.2+ path. if (xi2MouseEvents() && eventListener) - eventListener->handleXIMouseEvent(reinterpret_cast<xcb_ge_event_t *>(event)); + eventListener->handleXIMouseEvent(reinterpret_cast<xcb_ge_event_t *>(event), Qt::MouseEventSynthesizedByQt); #else Q_UNUSED(eventListener); #endif diff --git a/src/plugins/platforms/xcb/qxcbdrag.cpp b/src/plugins/platforms/xcb/qxcbdrag.cpp index 9409de2406..ea20ef7a04 100644 --- a/src/plugins/platforms/xcb/qxcbdrag.cpp +++ b/src/plugins/platforms/xcb/qxcbdrag.cpp @@ -429,6 +429,7 @@ void QXcbDrag::move(const QPoint &globalPos) xcb_client_message_event_t enter; enter.response_type = XCB_CLIENT_MESSAGE; + enter.sequence = 0; enter.window = target; enter.format = 32; enter.type = atom(QXcbAtom::XdndEnter); @@ -457,6 +458,7 @@ void QXcbDrag::move(const QPoint &globalPos) xcb_client_message_event_t move; move.response_type = XCB_CLIENT_MESSAGE; + move.sequence = 0; move.window = target; move.format = 32; move.type = atom(QXcbAtom::XdndPosition); @@ -485,6 +487,7 @@ void QXcbDrag::drop(const QPoint &globalPos) xcb_client_message_event_t drop; drop.response_type = XCB_CLIENT_MESSAGE; + drop.sequence = 0; drop.window = current_target; drop.format = 32; drop.type = atom(QXcbAtom::XdndDrop); @@ -746,6 +749,7 @@ void QXcbDrag::handle_xdnd_position(QPlatformWindow *w, const xcb_client_message xcb_client_message_event_t response; response.response_type = XCB_CLIENT_MESSAGE; + response.sequence = 0; response.window = xdnd_dragsource; response.format = 32; response.type = atom(QXcbAtom::XdndStatus); @@ -892,6 +896,7 @@ void QXcbDrag::send_leave() xcb_client_message_event_t leave; leave.response_type = XCB_CLIENT_MESSAGE; + leave.sequence = 0; leave.window = current_target; leave.format = 32; leave.type = atom(QXcbAtom::XdndLeave); @@ -962,6 +967,7 @@ void QXcbDrag::handleDrop(QPlatformWindow *, const xcb_client_message_event_t *e xcb_client_message_event_t finished; finished.response_type = XCB_CLIENT_MESSAGE; + finished.sequence = 0; finished.window = xdnd_dragsource; finished.format = 32; finished.type = atom(QXcbAtom::XdndFinished); diff --git a/src/plugins/platforms/xcb/qxcbintegration.cpp b/src/plugins/platforms/xcb/qxcbintegration.cpp index 6e8755a220..b5e03e68fe 100644 --- a/src/plugins/platforms/xcb/qxcbintegration.cpp +++ b/src/plugins/platforms/xcb/qxcbintegration.cpp @@ -164,7 +164,7 @@ QXcbIntegration::QXcbIntegration(const QStringList ¶meters, int &argc, char bool underDebugger = runningUnderDebugger(); if (noGrabArg && doGrabArg && underDebugger) { - qWarning() << "Both -nograb and -dograb command line arguments specified. Please pick one. -nograb takes prcedence"; + qWarning("Both -nograb and -dograb command line arguments specified. Please pick one. -nograb takes prcedence"); doGrabArg = false; } @@ -203,7 +203,7 @@ QPlatformWindow *QXcbIntegration::createPlatformWindow(QWindow *window) const { QXcbScreen *screen = static_cast<QXcbScreen *>(window->screen()->handle()); QXcbGlIntegration *glIntegration = screen->connection()->glIntegration(); - if (window->type() != Qt::Desktop) { + if (window->type() != Qt::Desktop && window->supportsOpenGL()) { if (glIntegration) { QXcbWindow *xcbWindow = glIntegration->createWindow(window); xcbWindow->create(); diff --git a/src/plugins/platforms/xcb/qxcbkeyboard.cpp b/src/plugins/platforms/xcb/qxcbkeyboard.cpp index 4de7716703..a16e24061c 100644 --- a/src/plugins/platforms/xcb/qxcbkeyboard.cpp +++ b/src/plugins/platforms/xcb/qxcbkeyboard.cpp @@ -676,13 +676,13 @@ void QXcbKeyboard::printKeymapError(const char *error) const { qWarning() << error; if (xkb_context) { - qWarning() << "Current XKB configuration data search paths are: "; + qWarning("Current XKB configuration data search paths are: "); for (unsigned int i = 0; i < xkb_context_num_include_paths(xkb_context); ++i) qWarning() << xkb_context_include_path_get(xkb_context, i); } - qWarning() << "Use QT_XKB_CONFIG_ROOT environmental variable to provide an additional search path, " - "add ':' as separator to provide several search paths and/or make sure that XKB configuration data " - "directory contains recent enough contents, to update please see http://cgit.freedesktop.org/xkeyboard-config/ ."; + qWarning("Use QT_XKB_CONFIG_ROOT environmental variable to provide an additional search path, " + "add ':' as separator to provide several search paths and/or make sure that XKB configuration data " + "directory contains recent enough contents, to update please see http://cgit.freedesktop.org/xkeyboard-config/ ."); } void QXcbKeyboard::updateKeymap() diff --git a/src/plugins/platforms/xcb/qxcbnativeinterface.cpp b/src/plugins/platforms/xcb/qxcbnativeinterface.cpp index 189053c5bf..a8d401e15b 100644 --- a/src/plugins/platforms/xcb/qxcbnativeinterface.cpp +++ b/src/plugins/platforms/xcb/qxcbnativeinterface.cpp @@ -55,6 +55,7 @@ #include <QtPlatformHeaders/qxcbwindowfunctions.h> #include <QtPlatformHeaders/qxcbintegrationfunctions.h> +#include <QtPlatformHeaders/qxcbscreenfunctions.h> #ifndef QT_NO_DBUS #include "QtPlatformSupport/private/qdbusmenuconnection_p.h" @@ -83,9 +84,10 @@ static int resourceType(const QByteArray &key) QByteArrayLiteral("startupid"), QByteArrayLiteral("traywindow"), QByteArrayLiteral("gettimestamp"), QByteArrayLiteral("x11screen"), QByteArrayLiteral("rootwindow"), - QByteArrayLiteral("subpixeltype"), QByteArrayLiteral("antialiasingEnabled"), + QByteArrayLiteral("subpixeltype"), QByteArrayLiteral("antialiasingenabled"), QByteArrayLiteral("nofonthinting"), - QByteArrayLiteral("atspibus") + QByteArrayLiteral("atspibus"), + QByteArrayLiteral("compositingenabled") }; const QByteArray *end = names + sizeof(names) / sizeof(names[0]); const QByteArray *result = std::find(names, end, key); @@ -202,7 +204,7 @@ void *QXcbNativeInterface::nativeResourceForContext(const QByteArray &resourceSt void *QXcbNativeInterface::nativeResourceForScreen(const QByteArray &resourceString, QScreen *screen) { if (!screen) { - qWarning() << "nativeResourceForScreen: null screen"; + qWarning("nativeResourceForScreen: null screen"); return Q_NULLPTR; } @@ -246,6 +248,10 @@ void *QXcbNativeInterface::nativeResourceForScreen(const QByteArray &resourceStr case RootWindow: result = reinterpret_cast<void *>(xcbScreen->root()); break; + case CompositingEnabled: + if (QXcbVirtualDesktop *vd = xcbScreen->virtualDesktop()) + result = vd->compositingActive() ? this : Q_NULLPTR; + break; default: break; } @@ -376,6 +382,10 @@ QFunctionPointer QXcbNativeInterface::platformFunction(const QByteArray &functio if (function == QXcbWindowFunctions::visualIdIdentifier()) { return QFunctionPointer(QXcbWindowFunctions::VisualId(QXcbWindow::visualIdStatic)); } + + if (function == QXcbScreenFunctions::virtualDesktopNumberIdentifier()) + return QFunctionPointer(QXcbScreenFunctions::VirtualDesktopNumber(QXcbScreen::virtualDesktopNumberStatic)); + return Q_NULLPTR; } diff --git a/src/plugins/platforms/xcb/qxcbnativeinterface.h b/src/plugins/platforms/xcb/qxcbnativeinterface.h index a3e188195f..ba19cd869c 100644 --- a/src/plugins/platforms/xcb/qxcbnativeinterface.h +++ b/src/plugins/platforms/xcb/qxcbnativeinterface.h @@ -74,7 +74,8 @@ public: ScreenSubpixelType, ScreenAntialiasingEnabled, NoFontHinting, - AtspiBus + AtspiBus, + CompositingEnabled }; QXcbNativeInterface(); diff --git a/src/plugins/platforms/xcb/qxcbscreen.cpp b/src/plugins/platforms/xcb/qxcbscreen.cpp index 339529edf1..67a9b2f190 100644 --- a/src/plugins/platforms/xcb/qxcbscreen.cpp +++ b/src/plugins/platforms/xcb/qxcbscreen.cpp @@ -367,6 +367,7 @@ void QXcbScreen::sendStartupMessage(const QByteArray &message) const ev.response_type = XCB_CLIENT_MESSAGE; ev.format = 8; ev.type = connection()->atom(QXcbAtom::_NET_STARTUP_INFO_BEGIN); + ev.sequence = 0; ev.window = rootWindow; int sent = 0; int length = message.length() + 1; // include NUL byte @@ -444,6 +445,14 @@ void QXcbScreen::setOutput(xcb_randr_output_t outputId, // TODO: Send an event to the QScreen instance that the screen changed its name } +int QXcbScreen::virtualDesktopNumberStatic(const QScreen *screen) +{ + if (screen && screen->handle()) + return static_cast<const QXcbScreen *>(screen->handle())->screenNumber(); + + return 0; +} + /*! \brief handle the XCB screen change event and update properties diff --git a/src/plugins/platforms/xcb/qxcbscreen.h b/src/plugins/platforms/xcb/qxcbscreen.h index e97631e2af..30c5073459 100644 --- a/src/plugins/platforms/xcb/qxcbscreen.h +++ b/src/plugins/platforms/xcb/qxcbscreen.h @@ -139,6 +139,7 @@ public: bool isPrimary() const { return m_primary; } int screenNumber() const { return m_virtualDesktop->number(); } + static int virtualDesktopNumberStatic(const QScreen *screen); xcb_screen_t *screen() const { return m_virtualDesktop->screen(); } xcb_window_t root() const { return screen()->root; } diff --git a/src/plugins/platforms/xcb/qxcbsystemtraytracker.cpp b/src/plugins/platforms/xcb/qxcbsystemtraytracker.cpp index cfed556ec9..5522af86de 100644 --- a/src/plugins/platforms/xcb/qxcbsystemtraytracker.cpp +++ b/src/plugins/platforms/xcb/qxcbsystemtraytracker.cpp @@ -100,9 +100,9 @@ xcb_window_t QXcbSystemTrayTracker::locateTrayWindow(const QXcbConnection *conne void QXcbSystemTrayTracker::requestSystemTrayWindowDock(xcb_window_t window) const { xcb_client_message_event_t trayRequest; - memset(&trayRequest, 0, sizeof(trayRequest)); trayRequest.response_type = XCB_CLIENT_MESSAGE; trayRequest.format = 32; + trayRequest.sequence = 0; trayRequest.window = m_trayWindow; trayRequest.type = m_trayAtom; trayRequest.data.data32[0] = XCB_CURRENT_TIME; diff --git a/src/plugins/platforms/xcb/qxcbwindow.cpp b/src/plugins/platforms/xcb/qxcbwindow.cpp index c910ec18ed..a426e04721 100644 --- a/src/plugins/platforms/xcb/qxcbwindow.cpp +++ b/src/plugins/platforms/xcb/qxcbwindow.cpp @@ -40,6 +40,7 @@ #include "qxcbwindow.h" #include <QtDebug> +#include <QMetaEnum> #include <QScreen> #include <QtGui/QIcon> #include <QtGui/QRegion> @@ -201,6 +202,20 @@ static inline QImage::Format imageFormatForVisual(int depth, quint32 red_mask, q case 16: if (blue_mask == 0x1f) return QImage::Format_RGB16; + if (red_mask == 0x1f) { + if (rgbSwap) + *rgbSwap = true; + return QImage::Format_RGB16; + } + break; + case 15: + if (blue_mask == 0x1f) + return QImage::Format_RGB555; + if (red_mask == 0x1f) { + if (rgbSwap) + *rgbSwap = true; + return QImage::Format_RGB555; + } break; default: break; @@ -358,7 +373,7 @@ void QXcbWindow::create() if (visual) m_visualId = connection()->defaultVisualId(); if (!visual) - qWarning() << "Could not use default visual id. Falling back to root_visual for screen."; + qWarning("Could not use default visual id. Falling back to root_visual for screen."); } if (!visual) visual = platformScreen->visualForId(m_visualId); @@ -1096,21 +1111,37 @@ QXcbWindow::NetWmStates QXcbWindow::netWmStates() void QXcbWindow::setNetWmStates(NetWmStates states) { QVector<xcb_atom_t> atoms; - if (states & NetWmStateAbove) + + xcb_get_property_cookie_t get_cookie = + xcb_get_property_unchecked(xcb_connection(), 0, m_window, atom(QXcbAtom::_NET_WM_STATE), + XCB_ATOM_ATOM, 0, 1024); + + xcb_get_property_reply_t *reply = + xcb_get_property_reply(xcb_connection(), get_cookie, NULL); + + 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)); + atoms.resize(reply->value_len); + memcpy((void *)&atoms.first(), (void *)data, reply->value_len * sizeof(xcb_atom_t)); + } + + free(reply); + + if (states & NetWmStateAbove && !atoms.contains(atom(QXcbAtom::_NET_WM_STATE_ABOVE))) atoms.push_back(atom(QXcbAtom::_NET_WM_STATE_ABOVE)); - if (states & NetWmStateBelow) + if (states & NetWmStateBelow && !atoms.contains(atom(QXcbAtom::_NET_WM_STATE_BELOW))) atoms.push_back(atom(QXcbAtom::_NET_WM_STATE_BELOW)); - if (states & NetWmStateFullScreen) + if (states & NetWmStateFullScreen && !atoms.contains(atom(QXcbAtom::_NET_WM_STATE_FULLSCREEN))) atoms.push_back(atom(QXcbAtom::_NET_WM_STATE_FULLSCREEN)); - if (states & NetWmStateMaximizedHorz) + 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) + 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) + if (states & NetWmStateModal && !atoms.contains(atom(QXcbAtom::_NET_WM_STATE_MODAL))) atoms.push_back(atom(QXcbAtom::_NET_WM_STATE_MODAL)); - if (states & NetWmStateStaysOnTop) + 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) + 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()) { @@ -1230,6 +1261,7 @@ void QXcbWindow::changeNetWmState(bool set, xcb_atom_t one, xcb_atom_t two) event.response_type = XCB_CLIENT_MESSAGE; event.format = 32; + event.sequence = 0; event.window = m_window; event.type = atom(QXcbAtom::_NET_WM_STATE); event.data.data32[0] = set ? 1 : 0; @@ -1271,6 +1303,7 @@ void QXcbWindow::setWindowState(Qt::WindowState state) 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_WM_STATE_ICONIC; @@ -1675,6 +1708,7 @@ void QXcbWindow::requestActivateWindow() event.response_type = XCB_CLIENT_MESSAGE; event.format = 32; + event.sequence = 0; event.window = m_window; event.type = atom(QXcbAtom::_NET_ACTIVE_WINDOW); event.data.data32[0] = 1; @@ -2049,8 +2083,9 @@ void QXcbWindow::handleClientMessageEvent(const xcb_client_message_event_t *even } else if (event->type == atom(QXcbAtom::_COMPIZ_DECOR_PENDING) || event->type == atom(QXcbAtom::_COMPIZ_DECOR_REQUEST) || event->type == atom(QXcbAtom::_COMPIZ_DECOR_DELETE_PIXMAP) - || event->type == atom(QXcbAtom::_COMPIZ_TOOLKIT_ACTION)) { - //silence the _COMPIZ messages for now + || event->type == atom(QXcbAtom::_COMPIZ_TOOLKIT_ACTION) + || event->type == atom(QXcbAtom::_GTK_LOAD_ICONTHEMES)) { + //silence the _COMPIZ and _GTK messages for now } else { qWarning() << "QXcbWindow: Unhandled client message:" << connection()->atomName(event->type); } @@ -2171,7 +2206,7 @@ void QXcbWindow::handleUnmapNotifyEvent(const xcb_unmap_notify_event_t *event) } void QXcbWindow::handleButtonPressEvent(int event_x, int event_y, int root_x, int root_y, - int detail, Qt::KeyboardModifiers modifiers, xcb_timestamp_t timestamp) + int detail, Qt::KeyboardModifiers modifiers, xcb_timestamp_t timestamp, Qt::MouseEventSource source) { const bool isWheel = detail >= 4 && detail <= 7; if (!isWheel && window() != QGuiApplication::focusWindow()) { @@ -2207,11 +2242,11 @@ void QXcbWindow::handleButtonPressEvent(int event_x, int event_y, int root_x, in return; } - handleMouseEvent(timestamp, local, global, modifiers); + handleMouseEvent(timestamp, local, global, modifiers, source); } void QXcbWindow::handleButtonReleaseEvent(int event_x, int event_y, int root_x, int root_y, - int detail, Qt::KeyboardModifiers modifiers, xcb_timestamp_t timestamp) + int detail, Qt::KeyboardModifiers modifiers, xcb_timestamp_t timestamp, Qt::MouseEventSource source) { QPoint local(event_x, event_y); QPoint global(root_x, root_y); @@ -2221,7 +2256,7 @@ void QXcbWindow::handleButtonReleaseEvent(int event_x, int event_y, int root_x, return; } - handleMouseEvent(timestamp, local, global, modifiers); + handleMouseEvent(timestamp, local, global, modifiers, source); } static bool ignoreLeaveEvent(quint8 mode, quint8 detail) @@ -2304,11 +2339,11 @@ void QXcbWindow::handleLeaveNotifyEvent(int root_x, int root_y, } void QXcbWindow::handleMotionNotifyEvent(int event_x, int event_y, int root_x, int root_y, - Qt::KeyboardModifiers modifiers, xcb_timestamp_t timestamp) + Qt::KeyboardModifiers modifiers, xcb_timestamp_t timestamp, Qt::MouseEventSource source) { QPoint local(event_x, event_y); QPoint global(root_x, root_y); - handleMouseEvent(timestamp, local, global, modifiers); + handleMouseEvent(timestamp, local, global, modifiers, source); } // Handlers for plain xcb events. Used only when XI 2.2 or newer is not available. @@ -2339,7 +2374,7 @@ static inline int fixed1616ToInt(FP1616 val) } // With XI 2.2+ press/release/motion comes here instead of the above handlers. -void QXcbWindow::handleXIMouseEvent(xcb_ge_event_t *event) +void QXcbWindow::handleXIMouseEvent(xcb_ge_event_t *event, Qt::MouseEventSource source) { QXcbConnection *conn = connection(); xXIDeviceEvent *ev = reinterpret_cast<xXIDeviceEvent *>(event); @@ -2359,20 +2394,27 @@ void QXcbWindow::handleXIMouseEvent(xcb_ge_event_t *event) conn->setButton(conn->translateMouseButton(i), XIMaskIsSet(buttonMask, i)); } + const char *sourceName = nullptr; + if (lcQpaXInput().isDebugEnabled()) { + const QMetaObject *metaObject = qt_getEnumMetaObject(source); + const QMetaEnum me = metaObject->enumerator(metaObject->indexOfEnumerator(qt_getEnumName(source))); + sourceName = me.valueToKey(source); + } + switch (ev->evtype) { case XI_ButtonPress: - qCDebug(lcQpaXInput, "XI2 mouse press, button %d, time %d", button, ev->time); + qCDebug(lcQpaXInput, "XI2 mouse press, button %d, time %d, source %s", button, ev->time, sourceName); conn->setButton(button, true); - handleButtonPressEvent(event_x, event_y, root_x, root_y, ev->detail, modifiers, ev->time); + handleButtonPressEvent(event_x, event_y, root_x, root_y, ev->detail, modifiers, ev->time, source); break; case XI_ButtonRelease: - qCDebug(lcQpaXInput, "XI2 mouse release, button %d, time %d", button, ev->time); + qCDebug(lcQpaXInput, "XI2 mouse release, button %d, time %d, source %s", button, ev->time, sourceName); conn->setButton(button, false); - handleButtonReleaseEvent(event_x, event_y, root_x, root_y, ev->detail, modifiers, ev->time); + handleButtonReleaseEvent(event_x, event_y, root_x, root_y, ev->detail, modifiers, ev->time, source); break; case XI_Motion: - qCDebug(lcQpaXInput, "XI2 mouse motion %d,%d, time %d", event_x, event_y, ev->time); - handleMotionNotifyEvent(event_x, event_y, root_x, root_y, modifiers, ev->time); + qCDebug(lcQpaXInput, "XI2 mouse motion %d,%d, time %d, source %s", event_x, event_y, ev->time, sourceName); + handleMotionNotifyEvent(event_x, event_y, root_x, root_y, modifiers, ev->time, source); break; default: qWarning() << "Unrecognized XI2 mouse event" << ev->evtype; @@ -2415,10 +2457,11 @@ void QXcbWindow::handleXIEnterLeave(xcb_ge_event_t *event) QXcbWindow *QXcbWindow::toWindow() { return this; } -void QXcbWindow::handleMouseEvent(xcb_timestamp_t time, const QPoint &local, const QPoint &global, Qt::KeyboardModifiers modifiers) +void QXcbWindow::handleMouseEvent(xcb_timestamp_t time, const QPoint &local, const QPoint &global, + Qt::KeyboardModifiers modifiers, Qt::MouseEventSource source) { connection()->setTime(time); - QWindowSystemInterface::handleMouseEvent(window(), time, local, global, connection()->buttons(), modifiers); + QWindowSystemInterface::handleMouseEvent(window(), time, local, global, connection()->buttons(), modifiers, source); } void QXcbWindow::handleEnterNotifyEvent(const xcb_enter_notify_event_t *event) @@ -2612,6 +2655,7 @@ bool QXcbWindow::startSystemResize(const QPoint &pos, Qt::Corner corner) xcb_client_message_event_t xev; xev.response_type = XCB_CLIENT_MESSAGE; xev.type = moveResize; + xev.sequence = 0; xev.window = xcb_window(); xev.format = 32; const QPoint globalPos = window()->mapToGlobal(pos); @@ -2640,6 +2684,7 @@ void QXcbWindow::sendXEmbedMessage(xcb_window_t window, quint32 message, event.response_type = XCB_CLIENT_MESSAGE; event.format = 32; + event.sequence = 0; event.window = window; event.type = atom(QXcbAtom::_XEMBED); event.data.data32[0] = connection()->time(); diff --git a/src/plugins/platforms/xcb/qxcbwindow.h b/src/plugins/platforms/xcb/qxcbwindow.h index 72688cdf16..7b70dc2ef8 100644 --- a/src/plugins/platforms/xcb/qxcbwindow.h +++ b/src/plugins/platforms/xcb/qxcbwindow.h @@ -139,13 +139,14 @@ public: void handleFocusOutEvent(const xcb_focus_out_event_t *event) Q_DECL_OVERRIDE; void handlePropertyNotifyEvent(const xcb_property_notify_event_t *event) Q_DECL_OVERRIDE; #ifdef XCB_USE_XINPUT22 - void handleXIMouseEvent(xcb_ge_event_t *) Q_DECL_OVERRIDE; + void handleXIMouseEvent(xcb_ge_event_t *, Qt::MouseEventSource source = Qt::MouseEventNotSynthesized) Q_DECL_OVERRIDE; void handleXIEnterLeave(xcb_ge_event_t *) Q_DECL_OVERRIDE; #endif QXcbWindow *toWindow() Q_DECL_OVERRIDE; - void handleMouseEvent(xcb_timestamp_t time, const QPoint &local, const QPoint &global, Qt::KeyboardModifiers modifiers); + void handleMouseEvent(xcb_timestamp_t time, const QPoint &local, const QPoint &global, + Qt::KeyboardModifiers modifiers, Qt::MouseEventSource source); void updateNetWmUserTime(xcb_timestamp_t timestamp); @@ -214,13 +215,13 @@ protected: bool compressExposeEvent(QRegion &exposeRegion); void handleButtonPressEvent(int event_x, int event_y, int root_x, int root_y, - int detail, Qt::KeyboardModifiers modifiers, xcb_timestamp_t timestamp); + int detail, Qt::KeyboardModifiers modifiers, xcb_timestamp_t timestamp, Qt::MouseEventSource source = Qt::MouseEventNotSynthesized); void handleButtonReleaseEvent(int event_x, int event_y, int root_x, int root_y, - int detail, Qt::KeyboardModifiers modifiers, xcb_timestamp_t timestamp); + int detail, Qt::KeyboardModifiers modifiers, xcb_timestamp_t timestamp, Qt::MouseEventSource source = Qt::MouseEventNotSynthesized); void handleMotionNotifyEvent(int event_x, int event_y, int root_x, int root_y, - Qt::KeyboardModifiers modifiers, xcb_timestamp_t timestamp); + Qt::KeyboardModifiers modifiers, xcb_timestamp_t timestamp, Qt::MouseEventSource source = Qt::MouseEventNotSynthesized); void handleEnterNotifyEvent(int event_x, int event_y, int root_x, int root_y, quint8 mode, quint8 detail, xcb_timestamp_t timestamp); diff --git a/src/plugins/platforms/xcb/qxcbwmsupport.cpp b/src/plugins/platforms/xcb/qxcbwmsupport.cpp index 38116ac239..470f021314 100644 --- a/src/plugins/platforms/xcb/qxcbwmsupport.cpp +++ b/src/plugins/platforms/xcb/qxcbwmsupport.cpp @@ -122,10 +122,10 @@ void QXcbWMSupport::updateVirtualRoots() } while (remaining > 0); #ifdef Q_XCB_DEBUG - qDebug() << "======== updateVirtualRoots"; + qDebug("======== updateVirtualRoots"); for (int i = 0; i < net_virtual_roots.size(); ++i) qDebug() << connection()->atomName(net_virtual_roots.at(i)); - qDebug() << "======== updateVirtualRoots"; + qDebug("======== updateVirtualRoots"); #endif } diff --git a/src/plugins/platforms/xcb/xcb-plugin.pro b/src/plugins/platforms/xcb/xcb-plugin.pro index 09ab1ad77a..75684a769b 100644 --- a/src/plugins/platforms/xcb/xcb-plugin.pro +++ b/src/plugins/platforms/xcb/xcb-plugin.pro @@ -1,13 +1,12 @@ TARGET = qxcb -PLUGIN_TYPE = platforms -PLUGIN_CLASS_NAME = QXcbIntegrationPlugin -!equals(TARGET, $$QT_DEFAULT_QPA_PLUGIN): PLUGIN_EXTENDS = - -load(qt_plugin) - QT += core-private gui-private platformsupport-private xcb_qpa_lib-private SOURCES = \ qxcbmain.cpp OTHER_FILES += xcb.json README +PLUGIN_TYPE = platforms +PLUGIN_CLASS_NAME = QXcbIntegrationPlugin +!equals(TARGET, $$QT_DEFAULT_QPA_PLUGIN): PLUGIN_EXTENDS = - +load(qt_plugin) diff --git a/src/plugins/platforms/xcb/xcb_qpa_lib.pro b/src/plugins/platforms/xcb/xcb_qpa_lib.pro index 302d87e007..f4a4e5a78a 100644 --- a/src/plugins/platforms/xcb/xcb_qpa_lib.pro +++ b/src/plugins/platforms/xcb/xcb_qpa_lib.pro @@ -1,8 +1,6 @@ TARGET = QtXcbQpa CONFIG += no_module_headers internal_module -load(qt_module) - QT += core-private gui-private platformsupport-private SOURCES = \ @@ -105,3 +103,4 @@ contains(QT_CONFIG, xkbcommon-qt) { QMAKE_CXXFLAGS += $$QMAKE_CFLAGS_XKBCOMMON } +load(qt_module) |