summaryrefslogtreecommitdiffstats
path: root/src/plugins/platforms/xcb
diff options
context:
space:
mode:
Diffstat (limited to 'src/plugins/platforms/xcb')
-rw-r--r--src/plugins/platforms/xcb/gl_integrations/qxcbglintegration.h2
-rw-r--r--src/plugins/platforms/xcb/gl_integrations/qxcbnativeinterfacehandler.cpp12
-rw-r--r--src/plugins/platforms/xcb/gl_integrations/xcb_egl/qxcbeglcontext.h8
-rw-r--r--src/plugins/platforms/xcb/gl_integrations/xcb_egl/qxcbeglintegration.cpp2
-rw-r--r--src/plugins/platforms/xcb/gl_integrations/xcb_egl/qxcbeglnativeinterfacehandler.cpp10
-rw-r--r--src/plugins/platforms/xcb/gl_integrations/xcb_egl/qxcbeglwindow.cpp2
-rw-r--r--src/plugins/platforms/xcb/gl_integrations/xcb_glx/qglxintegration.cpp4
-rw-r--r--src/plugins/platforms/xcb/gl_integrations/xcb_glx/qxcbglxintegration.cpp2
-rw-r--r--src/plugins/platforms/xcb/gl_integrations/xcb_glx/qxcbglxnativeinterfacehandler.cpp2
-rw-r--r--src/plugins/platforms/xcb/gl_integrations/xcb_glx/qxcbglxwindow.cpp4
-rw-r--r--src/plugins/platforms/xcb/nativepainting/qbackingstore_x11.cpp6
-rw-r--r--src/plugins/platforms/xcb/nativepainting/qpaintengine_x11_p.h38
-rw-r--r--src/plugins/platforms/xcb/nativepainting/qpixmap_x11_p.h34
-rw-r--r--src/plugins/platforms/xcb/nativepainting/qxcbnativepainting.cpp6
-rw-r--r--src/plugins/platforms/xcb/qxcbbackingstore.cpp215
-rw-r--r--src/plugins/platforms/xcb/qxcbclipboard.cpp5
-rw-r--r--src/plugins/platforms/xcb/qxcbconnection.cpp29
-rw-r--r--src/plugins/platforms/xcb/qxcbconnection.h28
-rw-r--r--src/plugins/platforms/xcb/qxcbconnection_xi2.cpp110
-rw-r--r--src/plugins/platforms/xcb/qxcbcursor.cpp72
-rw-r--r--src/plugins/platforms/xcb/qxcbdrag.cpp6
-rw-r--r--src/plugins/platforms/xcb/qxcbimage.cpp170
-rw-r--r--src/plugins/platforms/xcb/qxcbimage.h4
-rw-r--r--src/plugins/platforms/xcb/qxcbintegration.cpp8
-rw-r--r--src/plugins/platforms/xcb/qxcbkeyboard.cpp438
-rw-r--r--src/plugins/platforms/xcb/qxcbkeyboard.h6
-rw-r--r--src/plugins/platforms/xcb/qxcbmime.cpp11
-rw-r--r--src/plugins/platforms/xcb/qxcbnativeinterface.cpp54
-rw-r--r--src/plugins/platforms/xcb/qxcbscreen.cpp6
-rw-r--r--src/plugins/platforms/xcb/qxcbscreen.h2
-rw-r--r--src/plugins/platforms/xcb/qxcbwindow.cpp189
-rw-r--r--src/plugins/platforms/xcb/qxcbwindow.h14
-rw-r--r--src/plugins/platforms/xcb/xcb-plugin.pro2
33 files changed, 1005 insertions, 496 deletions
diff --git a/src/plugins/platforms/xcb/gl_integrations/qxcbglintegration.h b/src/plugins/platforms/xcb/gl_integrations/qxcbglintegration.h
index 926e5e22df..07e983a499 100644
--- a/src/plugins/platforms/xcb/gl_integrations/qxcbglintegration.h
+++ b/src/plugins/platforms/xcb/gl_integrations/qxcbglintegration.h
@@ -69,7 +69,7 @@ public:
#endif
virtual QPlatformOffscreenSurface *createPlatformOffscreenSurface(QOffscreenSurface *surface) const = 0;
- virtual QXcbNativeInterfaceHandler *nativeInterfaceHandler() const { return Q_NULLPTR; }
+ virtual QXcbNativeInterfaceHandler *nativeInterfaceHandler() const { return nullptr; }
};
QT_END_NAMESPACE
diff --git a/src/plugins/platforms/xcb/gl_integrations/qxcbnativeinterfacehandler.cpp b/src/plugins/platforms/xcb/gl_integrations/qxcbnativeinterfacehandler.cpp
index ac992b859d..e18656c6ec 100644
--- a/src/plugins/platforms/xcb/gl_integrations/qxcbnativeinterfacehandler.cpp
+++ b/src/plugins/platforms/xcb/gl_integrations/qxcbnativeinterfacehandler.cpp
@@ -56,37 +56,37 @@ QXcbNativeInterfaceHandler::~QXcbNativeInterfaceHandler()
QPlatformNativeInterface::NativeResourceForIntegrationFunction QXcbNativeInterfaceHandler::nativeResourceFunctionForIntegration(const QByteArray &resource) const
{
Q_UNUSED(resource);
- return Q_NULLPTR;
+ return nullptr;
}
QPlatformNativeInterface::NativeResourceForContextFunction QXcbNativeInterfaceHandler::nativeResourceFunctionForContext(const QByteArray &resource) const
{
Q_UNUSED(resource);
- return Q_NULLPTR;
+ return nullptr;
}
QPlatformNativeInterface::NativeResourceForScreenFunction QXcbNativeInterfaceHandler::nativeResourceFunctionForScreen(const QByteArray &resource) const
{
Q_UNUSED(resource);
- return Q_NULLPTR;
+ return nullptr;
}
QPlatformNativeInterface::NativeResourceForWindowFunction QXcbNativeInterfaceHandler::nativeResourceFunctionForWindow(const QByteArray &resource) const
{
Q_UNUSED(resource);
- return Q_NULLPTR;
+ return nullptr;
}
QPlatformNativeInterface::NativeResourceForBackingStoreFunction QXcbNativeInterfaceHandler::nativeResourceFunctionForBackingStore(const QByteArray &resource) const
{
Q_UNUSED(resource);
- return Q_NULLPTR;
+ return nullptr;
}
QFunctionPointer QXcbNativeInterfaceHandler::platformFunction(const QByteArray &function) const
{
Q_UNUSED(function);
- return Q_NULLPTR;
+ return nullptr;
}
QT_END_NAMESPACE
diff --git a/src/plugins/platforms/xcb/gl_integrations/xcb_egl/qxcbeglcontext.h b/src/plugins/platforms/xcb/gl_integrations/xcb_egl/qxcbeglcontext.h
index fe50afa62a..c3ce8d8745 100644
--- a/src/plugins/platforms/xcb/gl_integrations/xcb_egl/qxcbeglcontext.h
+++ b/src/plugins/platforms/xcb/gl_integrations/xcb_egl/qxcbeglcontext.h
@@ -59,6 +59,14 @@ public:
void swapBuffers(QPlatformSurface *surface)
{
QEGLPlatformContext::swapBuffers(surface);
+ if (surface->surface()->surfaceClass() == QSurface::Window) {
+ QXcbWindow *platformWindow = static_cast<QXcbWindow *>(surface);
+ // OpenGL context might be bound to a non-gui thread use QueuedConnection to sync
+ // the window from the platformWindow's thread as QXcbWindow is no QObject, an
+ // event is sent to QXcbConnection. (this is faster than a metacall)
+ if (platformWindow->needsSync())
+ platformWindow->postSyncWindowRequest();
+ }
}
bool makeCurrent(QPlatformSurface *surface)
diff --git a/src/plugins/platforms/xcb/gl_integrations/xcb_egl/qxcbeglintegration.cpp b/src/plugins/platforms/xcb/gl_integrations/xcb_egl/qxcbeglintegration.cpp
index 7aa1d631df..fe18bc24db 100644
--- a/src/plugins/platforms/xcb/gl_integrations/xcb_egl/qxcbeglintegration.cpp
+++ b/src/plugins/platforms/xcb/gl_integrations/xcb_egl/qxcbeglintegration.cpp
@@ -49,7 +49,7 @@
QT_BEGIN_NAMESPACE
QXcbEglIntegration::QXcbEglIntegration()
- : m_connection(Q_NULLPTR)
+ : m_connection(nullptr)
, m_egl_display(EGL_NO_DISPLAY)
{
qCDebug(lcQpaGl) << "Xcb EGL gl-integration created";
diff --git a/src/plugins/platforms/xcb/gl_integrations/xcb_egl/qxcbeglnativeinterfacehandler.cpp b/src/plugins/platforms/xcb/gl_integrations/xcb_egl/qxcbeglnativeinterfacehandler.cpp
index 30f5e3a00d..c0e3f820fe 100644
--- a/src/plugins/platforms/xcb/gl_integrations/xcb_egl/qxcbeglnativeinterfacehandler.cpp
+++ b/src/plugins/platforms/xcb/gl_integrations/xcb_egl/qxcbeglnativeinterfacehandler.cpp
@@ -77,7 +77,7 @@ QPlatformNativeInterface::NativeResourceForIntegrationFunction QXcbEglNativeInte
default:
break;
}
- return Q_NULLPTR;
+ return nullptr;
}
QPlatformNativeInterface::NativeResourceForContextFunction QXcbEglNativeInterfaceHandler::nativeResourceFunctionForContext(const QByteArray &resource) const
@@ -90,7 +90,7 @@ QPlatformNativeInterface::NativeResourceForContextFunction QXcbEglNativeInterfac
default:
break;
}
- return Q_NULLPTR;
+ return nullptr;
}
QPlatformNativeInterface::NativeResourceForWindowFunction QXcbEglNativeInterfaceHandler::nativeResourceFunctionForWindow(const QByteArray &resource) const
@@ -101,7 +101,7 @@ QPlatformNativeInterface::NativeResourceForWindowFunction QXcbEglNativeInterface
default:
break;
}
- return Q_NULLPTR;
+ return nullptr;
}
void *QXcbEglNativeInterfaceHandler::eglDisplay()
@@ -114,11 +114,11 @@ void *QXcbEglNativeInterfaceHandler::eglDisplay()
void *QXcbEglNativeInterfaceHandler::eglDisplayForWindow(QWindow *window)
{
Q_ASSERT(window);
- if (window->supportsOpenGL() && window->handle() == Q_NULLPTR)
+ if (window->supportsOpenGL() && window->handle() == nullptr)
return eglDisplay();
else if (window->supportsOpenGL())
return static_cast<QXcbEglWindow *>(window->handle())->glIntegration()->eglDisplay();
- return Q_NULLPTR;
+ return nullptr;
}
void *QXcbEglNativeInterfaceHandler::eglContextForContext(QOpenGLContext *context)
diff --git a/src/plugins/platforms/xcb/gl_integrations/xcb_egl/qxcbeglwindow.cpp b/src/plugins/platforms/xcb/gl_integrations/xcb_egl/qxcbeglwindow.cpp
index 9c3fd26d49..65beac227c 100644
--- a/src/plugins/platforms/xcb/gl_integrations/xcb_egl/qxcbeglwindow.cpp
+++ b/src/plugins/platforms/xcb/gl_integrations/xcb_egl/qxcbeglwindow.cpp
@@ -49,7 +49,7 @@ QT_BEGIN_NAMESPACE
QXcbEglWindow::QXcbEglWindow(QWindow *window, QXcbEglIntegration *glIntegration)
: QXcbWindow(window)
, m_glIntegration(glIntegration)
- , m_config(Q_NULLPTR)
+ , m_config(nullptr)
, m_surface(EGL_NO_SURFACE)
{
}
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 3bc8590d36..56a737e882 100644
--- a/src/plugins/platforms/xcb/gl_integrations/xcb_glx/qglxintegration.cpp
+++ b/src/plugins/platforms/xcb/gl_integrations/xcb_glx/qglxintegration.cpp
@@ -321,7 +321,7 @@ void QGLXContext::init(QXcbScreen *screen, QPlatformOpenGLContext *share)
if (!m_context && m_shareContext) {
// re-try without a shared glx context
m_shareContext = 0;
- m_context = glXCreateContext(m_display, visualInfo, Q_NULLPTR, true);
+ m_context = glXCreateContext(m_display, visualInfo, nullptr, true);
}
// Create a temporary window so that we can make the new context current
@@ -470,7 +470,7 @@ static QXcbScreen *screenForPlatformSurface(QPlatformSurface *surface)
} else if (surfaceClass == QSurface::Offscreen) {
return static_cast<QXcbScreen *>(static_cast<QGLXPbuffer *>(surface)->screen());
}
- return Q_NULLPTR;
+ return nullptr;
}
QVariant QGLXContext::nativeHandle() const
diff --git a/src/plugins/platforms/xcb/gl_integrations/xcb_glx/qxcbglxintegration.cpp b/src/plugins/platforms/xcb/gl_integrations/xcb_glx/qxcbglxintegration.cpp
index 377066df61..13f03f8bf3 100644
--- a/src/plugins/platforms/xcb/gl_integrations/xcb_glx/qxcbglxintegration.cpp
+++ b/src/plugins/platforms/xcb/gl_integrations/xcb_glx/qxcbglxintegration.cpp
@@ -87,7 +87,7 @@ QT_BEGIN_NAMESPACE
#endif
QXcbGlxIntegration::QXcbGlxIntegration()
- : m_connection(Q_NULLPTR)
+ : m_connection(nullptr)
, m_glx_first_event(0)
{
qCDebug(lcQpaGl) << "Xcb GLX gl-integration created";
diff --git a/src/plugins/platforms/xcb/gl_integrations/xcb_glx/qxcbglxnativeinterfacehandler.cpp b/src/plugins/platforms/xcb/gl_integrations/xcb_glx/qxcbglxnativeinterfacehandler.cpp
index 638fdd46b5..e9bb4460ff 100644
--- a/src/plugins/platforms/xcb/gl_integrations/xcb_glx/qxcbglxnativeinterfacehandler.cpp
+++ b/src/plugins/platforms/xcb/gl_integrations/xcb_glx/qxcbglxnativeinterfacehandler.cpp
@@ -72,7 +72,7 @@ QPlatformNativeInterface::NativeResourceForContextFunction QXcbGlxNativeInterfac
default:
break;
}
- return Q_NULLPTR;
+ return nullptr;
}
void *QXcbGlxNativeInterfaceHandler::glxContextForContext(QOpenGLContext *context)
diff --git a/src/plugins/platforms/xcb/gl_integrations/xcb_glx/qxcbglxwindow.cpp b/src/plugins/platforms/xcb/gl_integrations/xcb_glx/qxcbglxwindow.cpp
index 145a11a5e3..d682ea87fb 100644
--- a/src/plugins/platforms/xcb/gl_integrations/xcb_glx/qxcbglxwindow.cpp
+++ b/src/plugins/platforms/xcb/gl_integrations/xcb_glx/qxcbglxwindow.cpp
@@ -58,7 +58,7 @@ const xcb_visualtype_t *QXcbGlxWindow::createVisual()
{
QXcbScreen *scr = xcbScreen();
if (!scr)
- return Q_NULLPTR;
+ return nullptr;
qDebug(lcQpaGl) << "Requested format before FBConfig/Visual selection:" << m_format;
@@ -74,7 +74,7 @@ const xcb_visualtype_t *QXcbGlxWindow::createVisual()
XVisualInfo *visualInfo = qglx_findVisualInfo(dpy, scr->screenNumber(), &m_format, GLX_WINDOW_BIT, flags);
if (!visualInfo) {
qWarning() << "No XVisualInfo for format" << m_format;
- return Q_NULLPTR;
+ return nullptr;
}
const xcb_visualtype_t *xcb_visualtype = scr->visualForId(visualInfo->visualid);
XFree(visualInfo);
diff --git a/src/plugins/platforms/xcb/nativepainting/qbackingstore_x11.cpp b/src/plugins/platforms/xcb/nativepainting/qbackingstore_x11.cpp
index bdf78b5255..9b31998620 100644
--- a/src/plugins/platforms/xcb/nativepainting/qbackingstore_x11.cpp
+++ b/src/plugins/platforms/xcb/nativepainting/qbackingstore_x11.cpp
@@ -121,7 +121,7 @@ void QXcbNativeBackingStore::flush(QWindow *window, const QRegion &region, const
else
#endif
{
- GC gc = XCreateGC(display(), wid, 0, Q_NULLPTR);
+ GC gc = XCreateGC(display(), wid, 0, nullptr);
if (clipRects.size() != 1)
XSetClipRectangles(display(), gc, 0, 0, clipRects.data(), clipRects.size(), YXBanded);
@@ -161,7 +161,7 @@ void QXcbNativeBackingStore::resize(const QSize &size, const QRegion &staticCont
QRect br = staticContents.boundingRect().intersected(QRect(QPoint(0, 0), size));
if (!br.isEmpty()) {
- GC gc = XCreateGC(display(), to, 0, Q_NULLPTR);
+ GC gc = XCreateGC(display(), to, 0, nullptr);
XCopyArea(display(), from, to, gc, br.x(), br.y(), br.width(), br.height(), br.x(), br.y());
XFreeGC(display(), gc);
}
@@ -178,7 +178,7 @@ bool QXcbNativeBackingStore::scroll(const QRegion &area, int dx, int dy)
QRect rect = area.boundingRect();
Pixmap pix = qt_x11PixmapHandle(m_pixmap);
- GC gc = XCreateGC(display(), pix, 0, Q_NULLPTR);
+ GC gc = XCreateGC(display(), pix, 0, nullptr);
XCopyArea(display(), pix, pix, gc,
rect.x(), rect.y(), rect.width(), rect.height(),
rect.x()+dx, rect.y()+dy);
diff --git a/src/plugins/platforms/xcb/nativepainting/qpaintengine_x11_p.h b/src/plugins/platforms/xcb/nativepainting/qpaintengine_x11_p.h
index 5338b5fe08..9b01c0a3fc 100644
--- a/src/plugins/platforms/xcb/nativepainting/qpaintengine_x11_p.h
+++ b/src/plugins/platforms/xcb/nativepainting/qpaintengine_x11_p.h
@@ -62,10 +62,10 @@ public:
QX11PaintEngine();
~QX11PaintEngine();
- bool begin(QPaintDevice *pdev) Q_DECL_OVERRIDE;
- bool end() Q_DECL_OVERRIDE;
+ bool begin(QPaintDevice *pdev) override;
+ bool end() override;
- void updateState(const QPaintEngineState &state) Q_DECL_OVERRIDE;
+ void updateState(const QPaintEngineState &state) override;
void updatePen(const QPen &pen);
void updateBrush(const QBrush &brush, const QPointF &pt);
@@ -74,31 +74,31 @@ public:
void updateMatrix(const QTransform &matrix);
void updateClipRegion_dev(const QRegion &region, Qt::ClipOperation op);
- void drawLines(const QLine *lines, int lineCount) Q_DECL_OVERRIDE;
- void drawLines(const QLineF *lines, int lineCount) Q_DECL_OVERRIDE;
+ void drawLines(const QLine *lines, int lineCount) override;
+ void drawLines(const QLineF *lines, int lineCount) override;
- void drawRects(const QRect *rects, int rectCount) Q_DECL_OVERRIDE;
- void drawRects(const QRectF *rects, int rectCount) Q_DECL_OVERRIDE;
+ void drawRects(const QRect *rects, int rectCount) override;
+ void drawRects(const QRectF *rects, int rectCount) override;
- void drawPoints(const QPoint *points, int pointCount) Q_DECL_OVERRIDE;
- void drawPoints(const QPointF *points, int pointCount) Q_DECL_OVERRIDE;
+ void drawPoints(const QPoint *points, int pointCount) override;
+ void drawPoints(const QPointF *points, int pointCount) override;
- void drawEllipse(const QRect &r) Q_DECL_OVERRIDE;
- void drawEllipse(const QRectF &r) Q_DECL_OVERRIDE;
+ void drawEllipse(const QRect &r) override;
+ void drawEllipse(const QRectF &r) override;
- virtual void drawPolygon(const QPointF *points, int pointCount, PolygonDrawMode mode) Q_DECL_OVERRIDE;
- inline void drawPolygon(const QPoint *points, int pointCount, PolygonDrawMode mode) Q_DECL_OVERRIDE
+ virtual void drawPolygon(const QPointF *points, int pointCount, PolygonDrawMode mode) override;
+ inline void drawPolygon(const QPoint *points, int pointCount, PolygonDrawMode mode) override
{ QPaintEngine::drawPolygon(points, pointCount, mode); }
- void drawPixmap(const QRectF &r, const QPixmap &pm, const QRectF &sr) Q_DECL_OVERRIDE;
- void drawTiledPixmap(const QRectF &r, const QPixmap &pixmap, const QPointF &s) Q_DECL_OVERRIDE;
- void drawPath(const QPainterPath &path) Q_DECL_OVERRIDE;
- void drawTextItem(const QPointF &p, const QTextItem &textItem) Q_DECL_OVERRIDE;
+ void drawPixmap(const QRectF &r, const QPixmap &pm, const QRectF &sr) override;
+ void drawTiledPixmap(const QRectF &r, const QPixmap &pixmap, const QPointF &s) override;
+ void drawPath(const QPainterPath &path) override;
+ void drawTextItem(const QPointF &p, const QTextItem &textItem) override;
void drawImage(const QRectF &r, const QImage &img, const QRectF &sr,
- Qt::ImageConversionFlags flags = Qt::AutoColor) Q_DECL_OVERRIDE;
+ Qt::ImageConversionFlags flags = Qt::AutoColor) override;
virtual Drawable handle() const;
- inline Type type() const Q_DECL_OVERRIDE { return QPaintEngine::X11; }
+ inline Type type() const override { return QPaintEngine::X11; }
QPainter::RenderHints supportedRenderHints() const;
diff --git a/src/plugins/platforms/xcb/nativepainting/qpixmap_x11_p.h b/src/plugins/platforms/xcb/nativepainting/qpixmap_x11_p.h
index 8bff9e0d93..7392cbfccf 100644
--- a/src/plugins/platforms/xcb/nativepainting/qpixmap_x11_p.h
+++ b/src/plugins/platforms/xcb/nativepainting/qpixmap_x11_p.h
@@ -62,22 +62,22 @@ public:
QX11PlatformPixmap(PixelType pixelType);
~QX11PlatformPixmap();
- QPlatformPixmap *createCompatiblePlatformPixmap() const Q_DECL_OVERRIDE;
- void resize(int width, int height) Q_DECL_OVERRIDE;
- void fromImage(const QImage &img, Qt::ImageConversionFlags flags) Q_DECL_OVERRIDE;
- void copy(const QPlatformPixmap *data, const QRect &rect) Q_DECL_OVERRIDE;
- bool scroll(int dx, int dy, const QRect &rect) Q_DECL_OVERRIDE;
- int metric(QPaintDevice::PaintDeviceMetric metric) const Q_DECL_OVERRIDE;
- void fill(const QColor &fillColor) Q_DECL_OVERRIDE;
- QBitmap mask() const Q_DECL_OVERRIDE;
- void setMask(const QBitmap &mask) Q_DECL_OVERRIDE;
- bool hasAlphaChannel() const Q_DECL_OVERRIDE;
- QPixmap transformed(const QTransform &matrix, Qt::TransformationMode mode) const Q_DECL_OVERRIDE;
- QImage toImage() const Q_DECL_OVERRIDE;
- QImage toImage(const QRect &rect) const Q_DECL_OVERRIDE;
- QPaintEngine *paintEngine() const Q_DECL_OVERRIDE;
- qreal devicePixelRatio() const Q_DECL_OVERRIDE;
- void setDevicePixelRatio(qreal scaleFactor) Q_DECL_OVERRIDE;
+ QPlatformPixmap *createCompatiblePlatformPixmap() const override;
+ void resize(int width, int height) override;
+ void fromImage(const QImage &img, Qt::ImageConversionFlags flags) override;
+ void copy(const QPlatformPixmap *data, const QRect &rect) override;
+ bool scroll(int dx, int dy, const QRect &rect) override;
+ int metric(QPaintDevice::PaintDeviceMetric metric) const override;
+ void fill(const QColor &fillColor) override;
+ QBitmap mask() const override;
+ void setMask(const QBitmap &mask) override;
+ bool hasAlphaChannel() const override;
+ QPixmap transformed(const QTransform &matrix, Qt::TransformationMode mode) const override;
+ QImage toImage() const override;
+ QImage toImage(const QRect &rect) const override;
+ QPaintEngine *paintEngine() const override;
+ qreal devicePixelRatio() const override;
+ void setDevicePixelRatio(qreal scaleFactor) override;
inline Drawable handle() const { return hd; }
inline Picture x11PictureHandle() const { return picture; }
@@ -129,7 +129,7 @@ inline QX11PlatformPixmap *qt_x11Pixmap(const QPixmap &pixmap)
{
return (pixmap.handle() && pixmap.handle()->classId() == QPlatformPixmap::X11Class)
? static_cast<QX11PlatformPixmap *>(pixmap.handle())
- : Q_NULLPTR;
+ : nullptr;
}
inline Picture qt_x11PictureHandle(const QPixmap &pixmap)
diff --git a/src/plugins/platforms/xcb/nativepainting/qxcbnativepainting.cpp b/src/plugins/platforms/xcb/nativepainting/qxcbnativepainting.cpp
index 4a587ceb36..57b1882e4b 100644
--- a/src/plugins/platforms/xcb/nativepainting/qxcbnativepainting.cpp
+++ b/src/plugins/platforms/xcb/nativepainting/qxcbnativepainting.cpp
@@ -44,7 +44,7 @@
QT_BEGIN_NAMESPACE
-QXcbX11Data *qt_x11Data = Q_NULLPTR;
+QXcbX11Data *qt_x11Data = nullptr;
void qt_xcb_native_x11_info_init(QXcbConnection *conn)
{
@@ -111,7 +111,7 @@ void qt_xcb_native_x11_info_init(QXcbConnection *conn)
QVector<XRectangle> qt_region_to_xrectangles(const QRegion &r)
{
const int numRects = r.rectCount();
- const QVector<QRect> input = r.rects();
+ const auto input = r.begin();
QVector<XRectangle> output(numRects);
for (int i = 0; i < numRects; ++i) {
const QRect &in = input[i];
@@ -128,7 +128,7 @@ class QXcbX11InfoData : public QSharedData, public QX11InfoData
{};
QXcbX11Info::QXcbX11Info()
- : d(Q_NULLPTR)
+ : d(nullptr)
{}
QXcbX11Info::~QXcbX11Info()
diff --git a/src/plugins/platforms/xcb/qxcbbackingstore.cpp b/src/plugins/platforms/xcb/qxcbbackingstore.cpp
index 420d1ac7c5..1cf45c96d1 100644
--- a/src/plugins/platforms/xcb/qxcbbackingstore.cpp
+++ b/src/plugins/platforms/xcb/qxcbbackingstore.cpp
@@ -69,6 +69,8 @@ public:
QXcbShmImage(QXcbScreen *connection, const QSize &size, uint depth, QImage::Format format);
~QXcbShmImage() { destroy(); }
+ void flushScrolledRegion(bool clientSideScroll);
+
bool scroll(const QRegion &area, int dx, int dy);
QImage *image() { return &m_qimage; }
@@ -86,7 +88,8 @@ private:
void destroy();
void ensureGC(xcb_drawable_t dst);
- void flushPixmap(const QRegion &region);
+ void shmPutImage(xcb_drawable_t drawable, const QRegion &region, const QPoint &offset = QPoint());
+ void flushPixmap(const QRegion &region, bool fullRegion = false);
void setClip(const QRegion &region);
xcb_shm_segment_info_t m_shm_info;
@@ -99,18 +102,26 @@ private:
xcb_gcontext_t m_gc;
xcb_drawable_t m_gc_drawable;
- // When using shared memory this is the region currently shared with the server
- QRegion m_dirtyShm;
-
+ // When using shared memory these variables are used only for server-side scrolling.
// 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;
+
+ // This is the scrolled region which is stored in server-side pixmap
+ QRegion m_scrolledRegion;
+
+ // When using shared memory this is the region currently shared with the server
+ QRegion m_dirtyShm;
+
+ // When not using shared memory this is a temporary buffer which is uploaded
+ // as a pixmap region to server
QByteArray m_flushBuffer;
bool m_hasAlpha;
+ bool m_clientSideScroll;
};
class QXcbShmGraphicsBuffer : public QPlatformGraphicsBuffer
@@ -145,10 +156,11 @@ private:
QXcbShmImage::QXcbShmImage(QXcbScreen *screen, const QSize &size, uint depth, QImage::Format format)
: QXcbObject(screen->connection())
- , m_graphics_buffer(Q_NULLPTR)
+ , m_graphics_buffer(nullptr)
, m_gc(0)
, m_gc_drawable(0)
, m_xcb_pixmap(0)
+ , m_clientSideScroll(false)
{
const xcb_format_t *fmt = connection()->formatForDepth(depth);
Q_ASSERT(fmt);
@@ -202,13 +214,59 @@ 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());
- xcb_create_pixmap(xcb_connection(),
- m_xcb_image->depth,
- m_xcb_pixmap,
- screen->screen()->root,
- m_xcb_image->width, m_xcb_image->height);
+ m_xcb_pixmap = xcb_generate_id(xcb_connection());
+ 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::flushScrolledRegion(bool clientSideScroll)
+{
+ if (m_clientSideScroll == clientSideScroll)
+ return;
+
+ m_clientSideScroll = clientSideScroll;
+
+ if (m_scrolledRegion.isNull())
+ return;
+
+ if (hasShm() && m_dirtyShm.intersects(m_scrolledRegion)) {
+ connection()->sync();
+ m_dirtyShm = QRegion();
+ }
+
+ if (m_clientSideScroll) {
+ // Copy scrolled image region from server-side pixmap to client-side memory
+ for (const QRect &rect : m_scrolledRegion) {
+ const int w = rect.width();
+ const int h = rect.height();
+
+ auto reply = Q_XCB_REPLY_UNCHECKED(xcb_get_image,
+ xcb_connection(),
+ m_xcb_image->format,
+ m_xcb_pixmap,
+ rect.x(), rect.y(),
+ w, h,
+ ~0u);
+
+ if (reply && reply->depth == m_xcb_image->depth) {
+ const QImage img(xcb_get_image_data(reply.get()), w, h, m_qimage.format());
+
+ QPainter p(&m_qimage);
+ p.setCompositionMode(QPainter::CompositionMode_Source);
+ p.drawImage(rect.topLeft(), img);
+ }
+ }
+ m_scrolledRegion = QRegion();
+ } else {
+ // Copy scrolled image region from client-side memory to server-side pixmap
+ ensureGC(m_xcb_pixmap);
+ if (hasShm())
+ shmPutImage(m_xcb_pixmap, m_scrolledRegion);
+ else
+ flushPixmap(m_scrolledRegion, true);
}
}
@@ -216,21 +274,28 @@ extern void qt_scrollRectInImage(QImage &img, const QRect &rect, const QPoint &o
bool QXcbShmImage::scroll(const QRegion &area, int dx, int dy)
{
- if (image()->isNull())
- return false;
+ const QRect bounds(QPoint(), size());
+ const QRegion scrollArea(area & bounds);
+ const QPoint delta(dx, dy);
- if (hasShm())
- preparePaint(area);
+ if (m_clientSideScroll) {
+ if (m_qimage.isNull())
+ return false;
- const QPoint delta(dx, dy);
- for (const QRect &rect : area)
- qt_scrollRectInImage(*image(), rect, delta);
+ if (hasShm())
+ preparePaint(scrollArea);
+
+ for (const QRect &rect : scrollArea)
+ qt_scrollRectInImage(m_qimage, rect, delta);
+ } else {
+ if (hasShm())
+ shmPutImage(m_xcb_pixmap, m_pendingFlush.intersected(scrollArea));
+ else
+ flushPixmap(scrollArea);
- if (m_xcb_pixmap) {
- flushPixmap(area);
ensureGC(m_xcb_pixmap);
- const QRect bounds(QPoint(0, 0), size());
- for (const QRect &src : area) {
+
+ for (const QRect &src : scrollArea) {
const QRect dst = src.translated(delta).intersected(bounds);
xcb_copy_area(xcb_connection(),
m_xcb_pixmap,
@@ -242,6 +307,12 @@ bool QXcbShmImage::scroll(const QRegion &area, int dx, int dy)
}
}
+ m_scrolledRegion |= scrollArea.translated(delta).intersected(bounds);
+ if (hasShm()) {
+ m_pendingFlush -= scrollArea;
+ m_pendingFlush -= m_scrolledRegion;
+ }
+
return true;
}
@@ -265,12 +336,10 @@ void QXcbShmImage::destroy()
if (m_gc)
xcb_free_gc(xcb_connection(), m_gc);
delete m_graphics_buffer;
- m_graphics_buffer = Q_NULLPTR;
+ m_graphics_buffer = nullptr;
- if (m_xcb_pixmap) {
- xcb_free_pixmap(xcb_connection(), m_xcb_pixmap);
- m_xcb_pixmap = 0;
- }
+ xcb_free_pixmap(xcb_connection(), m_xcb_pixmap);
+ m_xcb_pixmap = 0;
}
void QXcbShmImage::ensureGC(xcb_drawable_t dst)
@@ -353,10 +422,35 @@ static inline quint32 round_up_scanline(quint32 base, quint32 pad)
return (base + pad - 1) & -pad;
}
-void QXcbShmImage::flushPixmap(const QRegion &region)
+void QXcbShmImage::shmPutImage(xcb_drawable_t drawable, const QRegion &region, const QPoint &offset)
+{
+ for (const QRect &rect : region) {
+ const QPoint source = rect.translated(offset).topLeft();
+ xcb_shm_put_image(xcb_connection(),
+ drawable,
+ m_gc,
+ m_xcb_image->width,
+ m_xcb_image->height,
+ source.x(), source.y(),
+ rect.width(), rect.height(),
+ rect.x(), rect.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);
+}
+
+void QXcbShmImage::flushPixmap(const QRegion &region, bool fullRegion)
{
- const QVector<QRect> rects = m_pendingFlush.intersected(region).rects();
- m_pendingFlush -= region;
+ if (!fullRegion) {
+ auto actualRegion = m_pendingFlush.intersected(region);
+ m_pendingFlush -= region;
+ flushPixmap(actualRegion, true);
+ return;
+ }
xcb_image_t xcb_subimage;
memset(&xcb_subimage, 0, sizeof(xcb_image_t));
@@ -372,7 +466,7 @@ void QXcbShmImage::flushPixmap(const QRegion &region)
const bool needsByteSwap = xcb_subimage.byte_order != m_xcb_image->byte_order;
- for (const QRect &rect : rects) {
+ for (const QRect &rect : region) {
// 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.
static const uint32_t req_size = sizeof(xcb_put_image_request_t);
@@ -425,16 +519,7 @@ void QXcbShmImage::setClip(const QRegion &region)
static const uint32_t values[] = { XCB_NONE };
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();
- }
-
+ const auto xcb_rects = qRegionToXcbRectangleList(region);
xcb_set_clip_rectangles(xcb_connection(),
XCB_CLIP_ORDERING_YX_BANDED,
m_gc,
@@ -445,29 +530,32 @@ void QXcbShmImage::setClip(const QRegion &region)
void QXcbShmImage::put(xcb_drawable_t dst, const QRegion &region, const QPoint &offset)
{
+ Q_ASSERT(!m_clientSideScroll);
+
ensureGC(dst);
setClip(region);
- const QRect bounds = region.boundingRect();
- const QPoint target = bounds.topLeft();
- const QRect source = bounds.translated(offset);
-
if (hasShm()) {
- xcb_shm_put_image(xcb_connection(),
+ // Copy scrolled area on server-side from pixmap to window
+ const QRegion scrolledRegion = m_scrolledRegion.translated(-offset);
+ for (const QRect &rect : scrolledRegion) {
+ const QPoint source = rect.translated(offset).topLeft();
+ xcb_copy_area(xcb_connection(),
+ m_xcb_pixmap,
dst,
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);
+ rect.x(), rect.y(),
+ rect.width(), rect.height());
+ }
+
+ // Copy non-scrolled image from client-side memory to server-side window
+ const QRegion notScrolledArea = region - scrolledRegion;
+ shmPutImage(dst, notScrolledArea, offset);
} else {
+ const QRect bounds = region.boundingRect();
+ const QPoint target = bounds.topLeft();
+ const QRect source = bounds.translated(offset);
flushPixmap(region);
xcb_copy_area(xcb_connection(),
m_xcb_pixmap,
@@ -489,9 +577,9 @@ void QXcbShmImage::preparePaint(const QRegion &region)
connection()->sync();
m_dirtyShm = QRegion();
}
- } else {
- m_pendingFlush |= region;
}
+ m_scrolledRegion -= region;
+ m_pendingFlush |= region;
}
QXcbBackingStore::QXcbBackingStore(QWindow *window)
@@ -565,7 +653,7 @@ QImage QXcbBackingStore::toImage() const
QPlatformGraphicsBuffer *QXcbBackingStore::graphicsBuffer() const
{
- return m_image ? m_image->graphicsBuffer() : Q_NULLPTR;
+ return m_image ? m_image->graphicsBuffer() : nullptr;
}
void QXcbBackingStore::flush(QWindow *window, const QRegion &region, const QPoint &offset)
@@ -573,6 +661,8 @@ void QXcbBackingStore::flush(QWindow *window, const QRegion &region, const QPoin
if (!m_image || m_image->size().isEmpty())
return;
+ m_image->flushScrolledRegion(false);
+
QSize imageSize = m_image->size();
QRegion clipped = region;
@@ -603,6 +693,11 @@ void QXcbBackingStore::composeAndFlush(QWindow *window, const QRegion &region, c
QPlatformTextureList *textures,
bool translucentBackground)
{
+ if (!m_image || m_image->size().isEmpty())
+ return;
+
+ m_image->flushScrolledRegion(true);
+
QPlatformBackingStore::composeAndFlush(window, region, offset, textures, translucentBackground);
QXcbWindow *platformWindow = static_cast<QXcbWindow *>(window->handle());
diff --git a/src/plugins/platforms/xcb/qxcbclipboard.cpp b/src/plugins/platforms/xcb/qxcbclipboard.cpp
index 30ab669432..b091928e8c 100644
--- a/src/plugins/platforms/xcb/qxcbclipboard.cpp
+++ b/src/plugins/platforms/xcb/qxcbclipboard.cpp
@@ -899,10 +899,7 @@ xcb_generic_event_t *QXcbClipboard::waitForClipboardEvent(xcb_window_t win, int
connection()->flush();
// sleep 50 ms, so we don't use up CPU cycles all the time.
- struct timeval usleep_tv;
- usleep_tv.tv_sec = 0;
- usleep_tv.tv_usec = 50000;
- select(0, 0, 0, 0, &usleep_tv);
+ QThread::msleep(50);
} while (timer.elapsed() < timeout);
return 0;
diff --git a/src/plugins/platforms/xcb/qxcbconnection.cpp b/src/plugins/platforms/xcb/qxcbconnection.cpp
index 536c709dbe..c5eae20266 100644
--- a/src/plugins/platforms/xcb/qxcbconnection.cpp
+++ b/src/plugins/platforms/xcb/qxcbconnection.cpp
@@ -369,7 +369,7 @@ void QXcbConnection::destroyScreen(QXcbScreen *screen)
// If there are no other screens on the same virtual desktop,
// then transform the physical screen into a fake screen.
const QString nameWas = screen->name();
- screen->setOutput(XCB_NONE, Q_NULLPTR);
+ screen->setOutput(XCB_NONE, nullptr);
qCDebug(lcQpaScreen) << "transformed" << nameWas << "to fake" << screen;
} else {
// There is more than one screen on the same virtual desktop, remove the screen
@@ -395,7 +395,7 @@ void QXcbConnection::initializeScreens()
{
xcb_screen_iterator_t it = xcb_setup_roots_iterator(m_setup);
int xcbScreenNumber = 0; // screen number in the xcb sense
- QXcbScreen *primaryScreen = Q_NULLPTR;
+ QXcbScreen *primaryScreen = nullptr;
while (it.rem) {
// Each "screen" in xcb terminology is a virtual desktop,
// potentially a collection of separate juxtaposed monitors.
@@ -415,7 +415,7 @@ void QXcbConnection::initializeScreens()
qWarning("failed to get the current screen resources");
} else {
xcb_timestamp_t timestamp = 0;
- xcb_randr_output_t *outputs = Q_NULLPTR;
+ xcb_randr_output_t *outputs = nullptr;
int outputCount = xcb_randr_get_screen_resources_current_outputs_length(resources_current.get());
if (outputCount) {
timestamp = resources_current->config_timestamp;
@@ -487,7 +487,7 @@ void QXcbConnection::initializeScreens()
while (it.rem) {
xcb_xinerama_screen_info_t *screen_info = it.data;
QXcbScreen *screen = new QXcbScreen(this, virtualDesktop,
- XCB_NONE, Q_NULLPTR,
+ XCB_NONE, nullptr,
screen_info, it.index);
siblings << screen;
m_screens << screen;
@@ -498,7 +498,7 @@ void QXcbConnection::initializeScreens()
if (siblings.isEmpty()) {
// If there are no XRandR outputs or XRandR extension is missing,
// then create a fake/legacy screen.
- QXcbScreen *screen = new QXcbScreen(this, virtualDesktop, XCB_NONE, Q_NULLPTR);
+ QXcbScreen *screen = new QXcbScreen(this, virtualDesktop, XCB_NONE, nullptr);
qCDebug(lcQpaScreen) << "created fake screen" << screen;
m_screens << screen;
if (m_primaryScreenNumber == xcbScreenNumber) {
@@ -631,7 +631,7 @@ QXcbConnection::QXcbConnection(QXcbNativeInterface *nativeInterface, bool canGra
if (m_glIntegration && !m_glIntegration->initialize(this)) {
qCDebug(lcQpaGl) << "Failed to initialize xcb gl-integration" << glIntegrationNames.at(i);
delete m_glIntegration;
- m_glIntegration = Q_NULLPTR;
+ m_glIntegration = nullptr;
}
}
if (!m_glIntegration)
@@ -689,7 +689,7 @@ QXcbScreen *QXcbConnection::primaryScreen() const
return m_screens.first();
}
- return Q_NULLPTR;
+ return nullptr;
}
void QXcbConnection::addWindowEventListener(xcb_window_t id, QXcbWindowEventListener *eventListener)
@@ -983,6 +983,12 @@ static Qt::MouseButtons translateMouseButtons(int s)
return ret;
}
+void QXcbConnection::setButtonState(Qt::MouseButton button, bool down)
+{
+ m_buttonState.setFlag(button, down);
+ m_button = button;
+}
+
Qt::MouseButton QXcbConnection::translateMouseButton(xcb_button_t s)
{
switch (s) {
@@ -1055,7 +1061,7 @@ void QXcbConnection::handleXcbEvent(xcb_generic_event_t *event)
// the event explicitly contains the state of the three first buttons,
// the rest we need to manage ourselves
m_buttonState = (m_buttonState & ~0x7) | translateMouseButtons(ev->state);
- m_buttonState |= translateMouseButton(ev->detail);
+ setButtonState(translateMouseButton(ev->detail), true);
if (Q_UNLIKELY(lcQpaXInputEvents().isDebugEnabled()))
qCDebug(lcQpaXInputEvents, "legacy mouse press, button %d state %X", ev->detail, static_cast<unsigned int>(m_buttonState));
HANDLE_PLATFORM_WINDOW_EVENT(xcb_button_press_event_t, event, handleButtonPressEvent);
@@ -1064,7 +1070,7 @@ void QXcbConnection::handleXcbEvent(xcb_generic_event_t *event)
xcb_button_release_event_t *ev = (xcb_button_release_event_t *)event;
m_keyboard->updateXKBStateFromCore(ev->state);
m_buttonState = (m_buttonState & ~0x7) | translateMouseButtons(ev->state);
- m_buttonState &= ~translateMouseButton(ev->detail);
+ setButtonState(translateMouseButton(ev->detail), false);
if (Q_UNLIKELY(lcQpaXInputEvents().isDebugEnabled()))
qCDebug(lcQpaXInputEvents, "legacy mouse release, button %d state %X", ev->detail, static_cast<unsigned int>(m_buttonState));
HANDLE_PLATFORM_WINDOW_EVENT(xcb_button_release_event_t, event, handleButtonReleaseEvent);
@@ -1413,7 +1419,7 @@ void QXcbConnection::setFocusWindow(QWindow *w)
void QXcbConnection::setMouseGrabber(QXcbWindow *w)
{
m_mouseGrabber = w;
- m_mousePressWindow = Q_NULLPTR;
+ m_mousePressWindow = nullptr;
}
void QXcbConnection::setMousePressWindow(QXcbWindow *w)
{
@@ -2070,7 +2076,8 @@ const xcb_format_t *QXcbConnection::formatForDepth(uint8_t depth) const
xcb_format_next(&iterator);
}
- return 0;
+ qWarning() << "XCB failed to find an xcb_format_t for depth:" << depth;
+ return nullptr;
}
void QXcbConnection::sync()
diff --git a/src/plugins/platforms/xcb/qxcbconnection.h b/src/plugins/platforms/xcb/qxcbconnection.h
index 999dc0630c..92825acb6d 100644
--- a/src/plugins/platforms/xcb/qxcbconnection.h
+++ b/src/plugins/platforms/xcb/qxcbconnection.h
@@ -409,6 +409,15 @@ public:
const xcb_setup_t *setup() const { return m_setup; }
const xcb_format_t *formatForDepth(uint8_t depth) const;
+ bool imageNeedsEndianSwap() const
+ {
+#if Q_BYTE_ORDER == Q_BIG_ENDIAN
+ return m_setup->image_byte_order != XCB_IMAGE_ORDER_MSB_FIRST;
+#else
+ return m_setup->image_byte_order != XCB_IMAGE_ORDER_LSB_FIRST;
+#endif
+ }
+
QXcbKeyboard *keyboard() const { return m_keyboard; }
#ifndef QT_NO_CLIPBOARD
@@ -476,8 +485,9 @@ public:
xcb_window_t getSelectionOwner(xcb_atom_t atom) const;
xcb_window_t getQtSelectionOwner();
- void setButtonState(Qt::MouseButton button, bool down) { m_buttonState.setFlag(button, down); }
+ void setButtonState(Qt::MouseButton button, bool down);
Qt::MouseButtons buttonState() const { return m_buttonState; }
+ Qt::MouseButton button() const { return m_button; }
Qt::MouseButton translateMouseButton(xcb_button_t s);
QXcbWindow *focusWindow() const { return m_focusWindow; }
@@ -691,6 +701,7 @@ private:
bool has_render_extension = false;
Qt::MouseButtons m_buttonState = 0;
+ Qt::MouseButton m_button = Qt::NoButton;
QXcbWindow *m_focusWindow = nullptr;
QXcbWindow *m_mouseGrabber = nullptr;
@@ -701,6 +712,7 @@ private:
QXcbSystemTrayTracker *m_systemTrayTracker = nullptr;
QXcbGlIntegration *m_glIntegration = nullptr;
bool m_xiGrab = false;
+ QVector<int> m_xiMasterPointerIds;
xcb_window_t m_qtSelectionOwner = 0;
@@ -746,16 +758,18 @@ private:
#define Q_XCB_REPLY_CONNECTION_ARG(connection, ...) connection
+struct QStdFreeDeleter {
+ void operator()(void *p) const Q_DECL_NOTHROW { return std::free(p); }
+};
+
#define Q_XCB_REPLY(call, ...) \
- std::unique_ptr<call##_reply_t, decltype(std::free) *>( \
- call##_reply(Q_XCB_REPLY_CONNECTION_ARG(__VA_ARGS__), call(__VA_ARGS__), nullptr), \
- std::free \
+ std::unique_ptr<call##_reply_t, QStdFreeDeleter>( \
+ call##_reply(Q_XCB_REPLY_CONNECTION_ARG(__VA_ARGS__), call(__VA_ARGS__), nullptr) \
)
#define Q_XCB_REPLY_UNCHECKED(call, ...) \
- std::unique_ptr<call##_reply_t, decltype(std::free) *>( \
- call##_reply(Q_XCB_REPLY_CONNECTION_ARG(__VA_ARGS__), call##_unchecked(__VA_ARGS__), nullptr), \
- std::free \
+ std::unique_ptr<call##_reply_t, QStdFreeDeleter>( \
+ call##_reply(Q_XCB_REPLY_CONNECTION_ARG(__VA_ARGS__), call##_unchecked(__VA_ARGS__), nullptr) \
)
template <typename T>
diff --git a/src/plugins/platforms/xcb/qxcbconnection_xi2.cpp b/src/plugins/platforms/xcb/qxcbconnection_xi2.cpp
index 335ec344d5..ba6481082a 100644
--- a/src/plugins/platforms/xcb/qxcbconnection_xi2.cpp
+++ b/src/plugins/platforms/xcb/qxcbconnection_xi2.cpp
@@ -52,12 +52,6 @@
void QXcbConnection::initializeXInput2()
{
- // TODO Qt 6 (or perhaps earlier): remove these redundant env variables
- if (qEnvironmentVariableIsSet("QT_XCB_DEBUG_XINPUT"))
- const_cast<QLoggingCategory&>(lcQpaXInput()).setEnabled(QtDebugMsg, true);
- if (qEnvironmentVariableIsSet("QT_XCB_DEBUG_XINPUT_DEVICES"))
- const_cast<QLoggingCategory&>(lcQpaXInputDevices()).setEnabled(QtDebugMsg, true);
-
Display *xDisplay = static_cast<Display *>(m_xlib_display);
if (XQueryExtension(xDisplay, "XInputExtension", &m_xiOpCode, &m_xiEventBase, &m_xiErrorBase)) {
int xiMajor = 2;
@@ -325,12 +319,18 @@ void QXcbConnection::xi2SetupDevices()
Display *xDisplay = static_cast<Display *>(m_xlib_display);
int deviceCount = 0;
XIDeviceInfo *devices = XIQueryDevice(xDisplay, XIAllDevices, &deviceCount);
+ m_xiMasterPointerIds.clear();
for (int i = 0; i < deviceCount; ++i) {
- // Only non-master pointing devices are relevant here.
- if (devices[i].use != XISlavePointer)
+ XIDeviceInfo deviceInfo = devices[i];
+ if (deviceInfo.use == XIMasterPointer) {
+ m_xiMasterPointerIds.append(deviceInfo.deviceid);
continue;
- xi2SetupDevice(&devices[i], false);
+ }
+ if (deviceInfo.use == XISlavePointer) // only slave pointer devices are relevant here
+ xi2SetupDevice(&deviceInfo, false);
}
+ if (m_xiMasterPointerIds.size() > 1)
+ qCDebug(lcQpaXInputDevices) << "multi-pointer X detected";
XIFreeDeviceInfo(devices);
}
@@ -849,62 +849,54 @@ bool QXcbConnection::startSystemResizeForTouchBegin(xcb_window_t window, const Q
bool QXcbConnection::xi2SetMouseGrabEnabled(xcb_window_t w, bool grab)
{
- if (grab && !canGrab())
- return false;
-
- int num_devices = 0;
Display *xDisplay = static_cast<Display *>(xlib_display());
- XIDeviceInfo *info = XIQueryDevice(xDisplay, XIAllMasterDevices, &num_devices);
- if (!info)
- return false;
-
- XIEventMask evmask;
- unsigned char mask[XIMaskLen(XI_LASTEVENT)];
- evmask.mask = mask;
- evmask.mask_len = sizeof(mask);
- memset(mask, 0, sizeof(mask));
- evmask.deviceid = XIAllMasterDevices;
-
- XISetMask(mask, XI_ButtonPress);
- XISetMask(mask, XI_ButtonRelease);
- XISetMask(mask, XI_Motion);
- XISetMask(mask, XI_Enter);
- XISetMask(mask, XI_Leave);
- XISetMask(mask, XI_TouchBegin);
- XISetMask(mask, XI_TouchUpdate);
- XISetMask(mask, XI_TouchEnd);
-
- bool grabbed = true;
- for (int i = 0; i < num_devices; i++) {
- int id = info[i].deviceid, n = 0;
- XIDeviceInfo *deviceInfo = XIQueryDevice(xDisplay, id, &n);
- if (deviceInfo) {
- const bool grabbable = deviceInfo->use != XIMasterKeyboard;
- XIFreeDeviceInfo(deviceInfo);
- if (!grabbable)
- continue;
- }
- if (!grab) {
- Status result = XIUngrabDevice(xDisplay, id, CurrentTime);
- if (result != Success) {
- grabbed = false;
- qCDebug(lcQpaXInput, "XInput 2.2: failed to ungrab events for device %d (result %d)", id, result);
- }
- } else {
- Status result = XIGrabDevice(xDisplay, id, w, CurrentTime, None, XIGrabModeAsync,
- XIGrabModeAsync, False, &evmask);
+ bool ok = false;
+
+ if (grab) { // grab
+ XIEventMask evmask;
+ unsigned char mask[XIMaskLen(XI_LASTEVENT)];
+ evmask.mask = mask;
+ evmask.mask_len = sizeof(mask);
+ memset(mask, 0, sizeof(mask));
+ XISetMask(mask, XI_ButtonPress);
+ XISetMask(mask, XI_ButtonRelease);
+ XISetMask(mask, XI_Motion);
+ XISetMask(mask, XI_Enter);
+ XISetMask(mask, XI_Leave);
+ XISetMask(mask, XI_TouchBegin);
+ XISetMask(mask, XI_TouchUpdate);
+ XISetMask(mask, XI_TouchEnd);
+
+ for (int id : m_xiMasterPointerIds) {
+ evmask.deviceid = id;
+ Status result = XIGrabDevice(xDisplay, id, w, CurrentTime, None,
+ XIGrabModeAsync, XIGrabModeAsync, False, &evmask);
if (result != Success) {
- grabbed = false;
- qCDebug(lcQpaXInput, "XInput 2.2: failed to grab events for device %d on window %x (result %d)", id, w, result);
+ qCDebug(lcQpaXInput, "failed to grab events for device %d on window %x"
+ "(result %d)", id, w, result);
+ } else {
+ // Managed to grab at least one of master pointers, that should be enough
+ // to properly dismiss windows that rely on mouse grabbing.
+ ok = true;
}
}
+ } else { // ungrab
+ for (int id : m_xiMasterPointerIds) {
+ Status result = XIUngrabDevice(xDisplay, id, CurrentTime);
+ if (result != Success)
+ qCDebug(lcQpaXInput, "XIUngrabDevice failed - id: %d (result %d)", id, result);
+ }
+ // XIUngrabDevice does not seem to wait for a reply from X server (similar to
+ // xcb_ungrab_pointer). Ungrabbing won't fail, unless NoSuchExtension error
+ // has occurred due to a programming error somewhere else in the stack. That
+ // would mean that things will crash soon anyway.
+ ok = true;
}
- XIFreeDeviceInfo(info);
-
- m_xiGrab = grabbed;
+ if (ok)
+ m_xiGrab = grab;
- return grabbed;
+ return ok;
}
void QXcbConnection::xi2HandleHierarchyEvent(void *event)
@@ -1342,7 +1334,7 @@ QXcbConnection::TabletData *QXcbConnection::tabletDataForDevice(int id)
if (m_tabletData.at(i).deviceId == id)
return &m_tabletData[i];
}
- return Q_NULLPTR;
+ return nullptr;
}
#endif // QT_CONFIG(tabletevent)
diff --git a/src/plugins/platforms/xcb/qxcbcursor.cpp b/src/plugins/platforms/xcb/qxcbcursor.cpp
index da63360333..34b7d0d236 100644
--- a/src/plugins/platforms/xcb/qxcbcursor.cpp
+++ b/src/plugins/platforms/xcb/qxcbcursor.cpp
@@ -255,29 +255,29 @@ static const uint8_t * const cursor_bits20[] = {
forbidden_bits, forbiddenm_bits
};
-static const char * const cursorNames[] = {
- "left_ptr",
- "up_arrow",
- "cross",
- "wait",
- "ibeam",
- "size_ver",
- "size_hor",
- "size_bdiag",
- "size_fdiag",
- "size_all",
- "blank",
- "split_v",
- "split_h",
- "pointing_hand",
- "forbidden",
- "whats_this",
- "left_ptr_watch",
- "openhand",
- "closedhand",
- "copy",
- "move",
- "link"
+static const std::vector<const char *> cursorNames[] = {
+ { "left_ptr", "default", "top_left_arrow", "left_arrow" },
+ { "up_arrow" },
+ { "cross" },
+ { "wait", "watch", "0426c94ea35c87780ff01dc239897213" },
+ { "ibeam", "text", "xterm" },
+ { "size_ver", "ns-resize", "v_double_arrow", "00008160000006810000408080010102" },
+ { "size_hor", "ew-resize", "h_double_arrow", "028006030e0e7ebffc7f7070c0600140" },
+ { "size_bdiag", "nesw-resize", "50585d75b494802d0151028115016902", "fcf1c3c7cd4491d801f1e1c78f100000" },
+ { "size_fdiag", "nwse-resize", "38c5dff7c7b8962045400281044508d2", "c7088f0f3e6c8088236ef8e1e3e70000" },
+ { "size_all" },
+ { "blank" },
+ { "split_v", "row-resize", "sb_v_double_arrow", "2870a09082c103050810ffdffffe0204", "c07385c7190e701020ff7ffffd08103c" },
+ { "split_h", "col-resize", "sb_h_double_arrow", "043a9f68147c53184671403ffa811cc5", "14fef782d02440884392942c11205230" },
+ { "pointing_hand", "pointer", "hand1", "e29285e634086352946a0e7090d73106" },
+ { "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" },
+ { "closedhand", "grabbing", "208530c400c041818281048008011002" },
+ { "dnd-copy", "copy" },
+ { "dnd-move", "move" },
+ { "dnd-link", "link" }
};
QXcbCursorCacheKey::QXcbCursorCacheKey(const QCursor &c)
@@ -535,22 +535,13 @@ static xcb_cursor_t loadCursor(void *dpy, int cshape)
xcb_cursor_t cursor = XCB_NONE;
if (!ptrXcursorLibraryLoadCursor || !dpy)
return cursor;
- switch (cshape) {
- case Qt::DragCopyCursor:
- cursor = ptrXcursorLibraryLoadCursor(dpy, "dnd-copy");
- break;
- case Qt::DragMoveCursor:
- cursor = ptrXcursorLibraryLoadCursor(dpy, "dnd-move");
- break;
- case Qt::DragLinkCursor:
- cursor = ptrXcursorLibraryLoadCursor(dpy, "dnd-link");
- break;
- default:
- break;
- }
- if (!cursor) {
- cursor = ptrXcursorLibraryLoadCursor(dpy, cursorNames[cshape]);
+
+ for (const char *cursorName: cursorNames[cshape]) {
+ cursor = ptrXcursorLibraryLoadCursor(dpy, cursorName);
+ if (cursor != XCB_NONE)
+ break;
}
+
return cursor;
}
#endif // QT_CONFIG(xcb_xlib) / QT_CONFIG(library)
@@ -565,7 +556,6 @@ xcb_cursor_t QXcbCursor::createFontCursor(int cshape)
#if QT_CONFIG(xcb_xlib) && QT_CONFIG(library)
if (cshape >= 0 && cshape <= Qt::LastCursor) {
void *dpy = connection()->xlib_display();
- // special case for non-standard dnd-* cursors
cursor = loadCursor(dpy, cshape);
if (!cursor && !m_gtkCursorThemeInitialized && m_screen->xSettings()->initialized()) {
QByteArray gtkCursorTheme = m_screen->xSettings()->setting("Gtk/CursorThemeName").toByteArray();
@@ -598,7 +588,7 @@ xcb_cursor_t QXcbCursor::createFontCursor(int cshape)
}
if (cursor && cshape >= 0 && cshape < Qt::LastCursor && connection()->hasXFixes()) {
- const char *name = cursorNames[cshape];
+ const char *name = cursorNames[cshape].front();
xcb_xfixes_set_cursor_name(conn, cursor, strlen(name), name);
}
@@ -660,7 +650,7 @@ QPoint QXcbCursor::pos() const
void QXcbCursor::setPos(const QPoint &pos)
{
- QXcbVirtualDesktop *virtualDesktop = Q_NULLPTR;
+ QXcbVirtualDesktop *virtualDesktop = nullptr;
queryPointer(connection(), &virtualDesktop, 0);
xcb_warp_pointer(xcb_connection(), XCB_NONE, virtualDesktop->root(), 0, 0, 0, 0, pos.x(), pos.y());
xcb_flush(xcb_connection());
diff --git a/src/plugins/platforms/xcb/qxcbdrag.cpp b/src/plugins/platforms/xcb/qxcbdrag.cpp
index 1e963268ef..8ea0ebf966 100644
--- a/src/plugins/platforms/xcb/qxcbdrag.cpp
+++ b/src/plugins/platforms/xcb/qxcbdrag.cpp
@@ -211,7 +211,7 @@ void QXcbDrag::startDrag()
setScreen(current_virtual_desktop->screens().constFirst()->screen());
initiatorWindow = QGuiApplicationPrivate::currentMouseWindow;
QBasicDrag::startDrag();
- if (connection()->mouseGrabber() == Q_NULLPTR)
+ if (connection()->mouseGrabber() == nullptr)
shapedPixmapWindow()->setMouseGrabEnabled(true);
}
@@ -315,7 +315,7 @@ void QXcbDrag::move(const QPoint &globalPos)
if (source_sameanswer.contains(globalPos) && source_sameanswer.isValid())
return;
- QXcbVirtualDesktop *virtualDesktop = Q_NULLPTR;
+ QXcbVirtualDesktop *virtualDesktop = nullptr;
QPoint cursorPos;
QXcbCursor::queryPointer(connection(), &virtualDesktop, &cursorPos);
QXcbScreen *screen = virtualDesktop->screenAt(cursorPos);
@@ -324,7 +324,7 @@ void QXcbDrag::move(const QPoint &globalPos)
if (virtualDesktop != current_virtual_desktop) {
setUseCompositing(virtualDesktop->compositingActive());
recreateShapedPixmapWindow(static_cast<QPlatformScreen*>(screen)->screen(), deviceIndependentPos);
- if (connection()->mouseGrabber() == Q_NULLPTR)
+ if (connection()->mouseGrabber() == nullptr)
shapedPixmapWindow()->setMouseGrabEnabled(true);
current_virtual_desktop = virtualDesktop;
diff --git a/src/plugins/platforms/xcb/qxcbimage.cpp b/src/plugins/platforms/xcb/qxcbimage.cpp
index 36536e0602..e18a08755b 100644
--- a/src/plugins/platforms/xcb/qxcbimage.cpp
+++ b/src/plugins/platforms/xcb/qxcbimage.cpp
@@ -38,6 +38,7 @@
****************************************************************************/
#include "qxcbimage.h"
+#include <QtCore/QtEndian>
#include <QtGui/QColor>
#include <QtGui/private/qimage_p.h>
#include <QtGui/private/qdrawhelper_p.h>
@@ -52,47 +53,108 @@ extern "C" {
#undef template
#endif
+#include "qxcbconnection.h"
+#include "qxcbintegration.h"
+
+namespace {
+
+QImage::Format imageFormatForMasks(int depth, int bits_per_pixel, int red_mask, int blue_mask)
+{
+ if (bits_per_pixel == 32) {
+ switch (depth) {
+ case 32:
+ if (red_mask == 0xff0000 && blue_mask == 0xff)
+ return QImage::Format_ARGB32_Premultiplied;
+#if Q_BYTE_ORDER == Q_LITTLE_ENDIAN
+ if (red_mask == 0xff && blue_mask == 0xff0000)
+ return QImage::Format_RGBA8888_Premultiplied;
+#else
+ if (red_mask == 0xff000000 && blue_mask == 0xff00)
+ return QImage::Format_RGBA8888_Premultiplied;
+#endif
+ if (red_mask == 0x3ff && blue_mask == 0x3ff00000)
+ return QImage::Format_A2BGR30_Premultiplied;
+ if (red_mask == 0x3ff00000 && blue_mask == 0x3ff)
+ return QImage::Format_A2RGB30_Premultiplied;
+ break;
+ case 30:
+ if (red_mask == 0x3ff && blue_mask == 0x3ff00000)
+ return QImage::Format_BGR30;
+ if (blue_mask == 0x3ff && red_mask == 0x3ff00000)
+ return QImage::Format_RGB30;
+ break;
+ case 24:
+ if (red_mask == 0xff0000 && blue_mask == 0xff)
+ return QImage::Format_RGB32;
+#if Q_BYTE_ORDER == Q_LITTLE_ENDIAN
+ if (red_mask == 0xff && blue_mask == 0xff0000)
+ return QImage::Format_RGBX8888;
+#else
+ if (red_mask == 0xff000000 && blue_mask == 0xff00)
+ return QImage::Format_RGBX8888;
+#endif
+ break;
+ }
+ } else if (bits_per_pixel == 16) {
+ if (depth == 16 && red_mask == 0xf800 && blue_mask == 0x1f)
+ return QImage::Format_RGB16;
+ if (depth == 15 && red_mask == 0x7c00 && blue_mask == 0x1f)
+ return QImage::Format_RGB555;
+ }
+ return QImage::Format_Invalid;
+}
+
+} // namespace
+
QT_BEGIN_NAMESPACE
-QImage::Format qt_xcb_imageFormatForVisual(QXcbConnection *connection, uint8_t depth,
- const xcb_visualtype_t *visual)
+bool qt_xcb_imageFormatForVisual(QXcbConnection *connection, uint8_t depth, const xcb_visualtype_t *visual,
+ QImage::Format *imageFormat, bool *needsRgbSwap)
{
+ Q_ASSERT(connection && visual && imageFormat);
+
+ if (needsRgbSwap)
+ *needsRgbSwap = false;
+ *imageFormat = QImage::Format_Invalid;
+
+ if (depth == 8) {
+ if (visual->_class == XCB_VISUAL_CLASS_GRAY_SCALE) {
+ *imageFormat = QImage::Format_Grayscale8;
+ return true;
+ }
+#if QT_CONFIG(xcb_native_painting)
+ if (QXcbIntegration::instance() && QXcbIntegration::instance()->nativePaintingEnabled()) {
+ *imageFormat = QImage::Format_Indexed8;
+ return true;
+ }
+#endif
+ return false;
+ }
+
const xcb_format_t *format = connection->formatForDepth(depth);
+ if (!format)
+ return false;
+
+ const bool connectionEndianSwap = connection->imageNeedsEndianSwap();
+ // We swap the masks and see if we can recognize it as a host format
+ const quint32 red_mask = connectionEndianSwap ? qbswap(visual->red_mask) : visual->red_mask;
+ const quint32 blue_mask = connectionEndianSwap ? qbswap(visual->blue_mask) : visual->blue_mask;
- if (!visual || !format)
- return QImage::Format_Invalid;
-
- if (depth == 32 && format->bits_per_pixel == 32 && visual->red_mask == 0xff0000
- && visual->green_mask == 0xff00 && visual->blue_mask == 0xff)
- return QImage::Format_ARGB32_Premultiplied;
-
- if (depth == 30 && format->bits_per_pixel == 32 && visual->red_mask == 0x3ff
- && visual->green_mask == 0x0ffc00 && visual->blue_mask == 0x3ff00000)
- return QImage::Format_BGR30;
-
- if (depth == 30 && format->bits_per_pixel == 32 && visual->blue_mask == 0x3ff
- && visual->green_mask == 0x0ffc00 && visual->red_mask == 0x3ff00000)
- return QImage::Format_RGB30;
-
- if (depth == 24 && format->bits_per_pixel == 32 && visual->red_mask == 0xff0000
- && visual->green_mask == 0xff00 && visual->blue_mask == 0xff)
- return QImage::Format_RGB32;
-
- if (QSysInfo::ByteOrder == QSysInfo::LittleEndian) {
- if (depth == 24 && format->bits_per_pixel == 32 && visual->blue_mask == 0xff0000
- && visual->green_mask == 0xff00 && visual->red_mask == 0xff)
- return QImage::Format_RGBX8888;
- } else {
- if (depth == 24 && format->bits_per_pixel == 32 && visual->blue_mask == 0xff00
- && visual->green_mask == 0xff0000 && visual->red_mask == 0xff000000)
- return QImage::Format_RGBX8888;
+ *imageFormat = imageFormatForMasks(depth, format->bits_per_pixel, red_mask, blue_mask);
+ if (*imageFormat != QImage::Format_Invalid)
+ return true;
+
+ if (needsRgbSwap) {
+ *imageFormat = imageFormatForMasks(depth, format->bits_per_pixel, blue_mask, red_mask);
+ if (*imageFormat != QImage::Format_Invalid) {
+ *needsRgbSwap = true;
+ return true;
+ }
}
- if (depth == 16 && format->bits_per_pixel == 16 && visual->red_mask == 0xf800
- && visual->green_mask == 0x7e0 && visual->blue_mask == 0x1f)
- return QImage::Format_RGB16;
+ qWarning("Unsupported screen format: depth: %d, bits_per_pixel: %d, red_mask: %x, blue_mask: %x", depth, format->bits_per_pixel, red_mask, blue_mask);
- return QImage::Format_Invalid;
+ return false;
}
QPixmap qt_xcb_pixmapFromXPixmap(QXcbConnection *connection, xcb_pixmap_t pixmap,
@@ -112,44 +174,14 @@ QPixmap qt_xcb_pixmapFromXPixmap(QXcbConnection *connection, xcb_pixmap_t pixmap
QPixmap result;
- QImage::Format format = qt_xcb_imageFormatForVisual(connection, depth, visual);
- if (format != QImage::Format_Invalid) {
+ QImage::Format format;
+ bool needsRgbSwap;
+ if (qt_xcb_imageFormatForVisual(connection, depth, visual, &format, &needsRgbSwap)) {
uint32_t bytes_per_line = length / height;
QImage image(const_cast<uint8_t *>(data), width, height, bytes_per_line, format);
- uint8_t image_byte_order = connection->setup()->image_byte_order;
-
- // we may have to swap the byte order
- if ((QSysInfo::ByteOrder == QSysInfo::LittleEndian && image_byte_order == XCB_IMAGE_ORDER_MSB_FIRST)
- || (QSysInfo::ByteOrder == QSysInfo::BigEndian && image_byte_order == XCB_IMAGE_ORDER_LSB_FIRST))
- {
- for (int i=0; i < image.height(); i++) {
- switch (format) {
- case QImage::Format_RGB16: {
- ushort *p = (ushort*)image.scanLine(i);
- ushort *end = p + image.width();
- while (p < end) {
- *p = ((*p << 8) & 0xff00) | ((*p >> 8) & 0x00ff);
- p++;
- }
- break;
- }
- case QImage::Format_RGB32:
- case QImage::Format_ARGB32_Premultiplied:
- case QImage::Format_RGBX8888: {
- uint *p = (uint*)image.scanLine(i);
- uint *end = p + image.width();
- while (p < end) {
- *p = ((*p << 24) & 0xff000000) | ((*p << 8) & 0x00ff0000)
- | ((*p >> 8) & 0x0000ff00) | ((*p >> 24) & 0x000000ff);
- p++;
- }
- break;
- }
- default:
- Q_ASSERT(false);
- }
- }
- }
+
+ if (needsRgbSwap)
+ image = std::move(image).rgbSwapped();
// fix-up alpha channel
if (format == QImage::Format_RGB32 || format == QImage::Format_RGBX8888) {
diff --git a/src/plugins/platforms/xcb/qxcbimage.h b/src/plugins/platforms/xcb/qxcbimage.h
index a9071a45de..d718089ec2 100644
--- a/src/plugins/platforms/xcb/qxcbimage.h
+++ b/src/plugins/platforms/xcb/qxcbimage.h
@@ -48,8 +48,8 @@
QT_BEGIN_NAMESPACE
-QImage::Format qt_xcb_imageFormatForVisual(QXcbConnection *connection,
- uint8_t depth, const xcb_visualtype_t *visual);
+bool qt_xcb_imageFormatForVisual(QXcbConnection *connection, uint8_t depth, const xcb_visualtype_t *visual,
+ QImage::Format *imageFormat, bool *needsRgbSwap = nullptr);
QPixmap qt_xcb_pixmapFromXPixmap(QXcbConnection *connection, xcb_pixmap_t pixmap,
int width, int height, int depth,
const xcb_visualtype_t *visual);
diff --git a/src/plugins/platforms/xcb/qxcbintegration.cpp b/src/plugins/platforms/xcb/qxcbintegration.cpp
index 72d31060db..6afa7bc934 100644
--- a/src/plugins/platforms/xcb/qxcbintegration.cpp
+++ b/src/plugins/platforms/xcb/qxcbintegration.cpp
@@ -121,7 +121,7 @@ static bool runningUnderDebugger()
#endif
}
-QXcbIntegration *QXcbIntegration::m_instance = Q_NULLPTR;
+QXcbIntegration *QXcbIntegration::m_instance = nullptr;
QXcbIntegration::QXcbIntegration(const QStringList &parameters, int &argc, char **argv)
: m_services(new QGenericUnixServices)
@@ -222,7 +222,7 @@ QXcbIntegration::QXcbIntegration(const QStringList &parameters, int &argc, char
QXcbIntegration::~QXcbIntegration()
{
qDeleteAll(m_connections);
- m_instance = Q_NULLPTR;
+ m_instance = nullptr;
}
QPlatformPixmap *QXcbIntegration::createPlatformPixmap(QPlatformPixmap::PixelType type) const
@@ -274,7 +274,7 @@ QPlatformOpenGLContext *QXcbIntegration::createPlatformOpenGLContext(QOpenGLCont
QXcbGlIntegration *glIntegration = screen->connection()->glIntegration();
if (!glIntegration) {
qWarning("QXcbIntegration: Cannot create platform OpenGL context, neither GLX nor EGL are enabled");
- return Q_NULLPTR;
+ return nullptr;
}
return glIntegration->createPlatformOpenGLContext(context);
}
@@ -296,7 +296,7 @@ QPlatformOffscreenSurface *QXcbIntegration::createPlatformOffscreenSurface(QOffs
QXcbGlIntegration *glIntegration = screen->connection()->glIntegration();
if (!glIntegration) {
qWarning("QXcbIntegration: Cannot create platform offscreen surface, neither GLX nor EGL are enabled");
- return Q_NULLPTR;
+ return nullptr;
}
return glIntegration->createPlatformOffscreenSurface(surface);
}
diff --git a/src/plugins/platforms/xcb/qxcbkeyboard.cpp b/src/plugins/platforms/xcb/qxcbkeyboard.cpp
index e24bd07b6f..136faec855 100644
--- a/src/plugins/platforms/xcb/qxcbkeyboard.cpp
+++ b/src/plugins/platforms/xcb/qxcbkeyboard.cpp
@@ -59,6 +59,12 @@
#undef KeyRelease
#endif
+#if QT_CONFIG(xcb_xlib)
+#include <X11/Xutil.h>
+#undef KeyPress
+#undef KeyRelease
+#endif
+
#ifndef XK_ISO_Left_Tab
#define XK_ISO_Left_Tab 0xFE20
#endif
@@ -678,9 +684,303 @@ void QXcbKeyboard::printKeymapError(const char *error) const
"directory contains recent enough contents, to update please see http://cgit.freedesktop.org/xkeyboard-config/ .");
}
+#if QT_CONFIG(xcb_xlib)
+/* Look at a pair of unshifted and shifted key symbols.
+ * If the 'unshifted' symbol is uppercase and there is no shifted symbol,
+ * return the matching lowercase symbol; otherwise return 0.
+ * The caller can then use the previously 'unshifted' symbol as the new
+ * 'shifted' (uppercase) symbol and the symbol returned by the function
+ * as the new 'unshifted' (lowercase) symbol.) */
+static xcb_keysym_t getUnshiftedXKey(xcb_keysym_t unshifted, xcb_keysym_t shifted)
+{
+ if (shifted != XKB_KEY_NoSymbol) // Has a shifted symbol
+ return 0;
+
+ KeySym xlower;
+ KeySym xupper;
+ /* libxkbcommon >= 0.8.0 will have public API functions providing
+ * functionality equivalent to XConvertCase(), use these once the
+ * minimal libxkbcommon version is high enough. After that the
+ * xcb-xlib dependency can be removed */
+ XConvertCase(static_cast<KeySym>(unshifted), &xlower, &xupper);
+
+ if (xlower != xupper // Check if symbol is cased
+ && unshifted == static_cast<xcb_keysym_t>(xupper)) { // Unshifted must be upper case
+ return static_cast<xcb_keysym_t>(xlower);
+ }
+ return 0;
+}
+
+static QByteArray symbolsGroupString(const xcb_keysym_t *symbols, int count)
+{
+ // Don't output trailing NoSymbols
+ while (count > 0 && symbols[count - 1] == XKB_KEY_NoSymbol)
+ count--;
+
+ QByteArray groupString;
+ for (int symIndex = 0; symIndex < count; symIndex++) {
+ xcb_keysym_t sym = symbols[symIndex];
+ char symString[64];
+ if (sym == XKB_KEY_NoSymbol)
+ strcpy(symString, "NoSymbol");
+ else
+ xkb_keysym_get_name(sym, symString, sizeof(symString));
+
+ if (!groupString.isEmpty())
+ groupString += ", ";
+ groupString += symString;
+ }
+ return groupString;
+}
+
+struct xkb_keymap *QXcbKeyboard::keymapFromCore()
+{
+ /* Construct an XKB keymap string from information queried from
+ * the X server */
+ QByteArray keymap;
+ keymap += "xkb_keymap {\n";
+
+ const xcb_keycode_t minKeycode = connection()->setup()->min_keycode;
+ const xcb_keycode_t maxKeycode = connection()->setup()->max_keycode;
+
+ // Generate symbolic names from keycodes
+ {
+ keymap +=
+ "xkb_keycodes \"core\" {\n"
+ "\tminimum = " + QByteArray::number(minKeycode) + ";\n"
+ "\tmaximum = " + QByteArray::number(maxKeycode) + ";\n";
+ for (int code = minKeycode; code <= maxKeycode; code++) {
+ auto codeStr = QByteArray::number(code);
+ keymap += "<K" + codeStr + "> = " + codeStr + ";\n";
+ }
+ /* TODO: indicators?
+ */
+ keymap += "};\n"; // xkb_keycodes
+ }
+
+ /* Set up default types (xkbcommon automatically assigns these to
+ * symbols, but doesn't have shift info) */
+ keymap +=
+ "xkb_types \"core\" {\n"
+ "virtual_modifiers NumLock,Alt,LevelThree;\n"
+ "type \"ONE_LEVEL\" {\n"
+ "modifiers= none;\n"
+ "level_name[Level1] = \"Any\";\n"
+ "};\n"
+ "type \"TWO_LEVEL\" {\n"
+ "modifiers= Shift;\n"
+ "map[Shift]= Level2;\n"
+ "level_name[Level1] = \"Base\";\n"
+ "level_name[Level2] = \"Shift\";\n"
+ "};\n"
+ "type \"ALPHABETIC\" {\n"
+ "modifiers= Shift+Lock;\n"
+ "map[Shift]= Level2;\n"
+ "map[Lock]= Level2;\n"
+ "level_name[Level1] = \"Base\";\n"
+ "level_name[Level2] = \"Caps\";\n"
+ "};\n"
+ "type \"KEYPAD\" {\n"
+ "modifiers= Shift+NumLock;\n"
+ "map[Shift]= Level2;\n"
+ "map[NumLock]= Level2;\n"
+ "level_name[Level1] = \"Base\";\n"
+ "level_name[Level2] = \"Number\";\n"
+ "};\n"
+ "type \"FOUR_LEVEL\" {\n"
+ "modifiers= Shift+LevelThree;\n"
+ "map[Shift]= Level2;\n"
+ "map[LevelThree]= Level3;\n"
+ "map[Shift+LevelThree]= Level4;\n"
+ "level_name[Level1] = \"Base\";\n"
+ "level_name[Level2] = \"Shift\";\n"
+ "level_name[Level3] = \"Alt Base\";\n"
+ "level_name[Level4] = \"Shift Alt\";\n"
+ "};\n"
+ "type \"FOUR_LEVEL_ALPHABETIC\" {\n"
+ "modifiers= Shift+Lock+LevelThree;\n"
+ "map[Shift]= Level2;\n"
+ "map[Lock]= Level2;\n"
+ "map[LevelThree]= Level3;\n"
+ "map[Shift+LevelThree]= Level4;\n"
+ "map[Lock+LevelThree]= Level4;\n"
+ "map[Shift+Lock+LevelThree]= Level3;\n"
+ "level_name[Level1] = \"Base\";\n"
+ "level_name[Level2] = \"Shift\";\n"
+ "level_name[Level3] = \"Alt Base\";\n"
+ "level_name[Level4] = \"Shift Alt\";\n"
+ "};\n"
+ "type \"FOUR_LEVEL_SEMIALPHABETIC\" {\n"
+ "modifiers= Shift+Lock+LevelThree;\n"
+ "map[Shift]= Level2;\n"
+ "map[Lock]= Level2;\n"
+ "map[LevelThree]= Level3;\n"
+ "map[Shift+LevelThree]= Level4;\n"
+ "map[Lock+LevelThree]= Level3;\n"
+ "preserve[Lock+LevelThree]= Lock;\n"
+ "map[Shift+Lock+LevelThree]= Level4;\n"
+ "preserve[Shift+Lock+LevelThree]= Lock;\n"
+ "level_name[Level1] = \"Base\";\n"
+ "level_name[Level2] = \"Shift\";\n"
+ "level_name[Level3] = \"Alt Base\";\n"
+ "level_name[Level4] = \"Shift Alt\";\n"
+ "};\n"
+ "type \"FOUR_LEVEL_KEYPAD\" {\n"
+ "modifiers= Shift+NumLock+LevelThree;\n"
+ "map[Shift]= Level2;\n"
+ "map[NumLock]= Level2;\n"
+ "map[LevelThree]= Level3;\n"
+ "map[Shift+LevelThree]= Level4;\n"
+ "map[NumLock+LevelThree]= Level4;\n"
+ "map[Shift+NumLock+LevelThree]= Level3;\n"
+ "level_name[Level1] = \"Base\";\n"
+ "level_name[Level2] = \"Number\";\n"
+ "level_name[Level3] = \"Alt Base\";\n"
+ "level_name[Level4] = \"Alt Number\";\n"
+ "};\n"
+ "};\n"; // xkb_types
+
+ // Generate mapping between symbolic names and keysyms
+ {
+ QVector<xcb_keysym_t> xkeymap;
+ int keysymsPerKeycode = 0;
+ {
+ int keycodeCount = maxKeycode - minKeycode + 1;
+ if (auto keymapReply = Q_XCB_REPLY(xcb_get_keyboard_mapping, xcb_connection(),
+ minKeycode, keycodeCount)) {
+ keysymsPerKeycode = keymapReply->keysyms_per_keycode;
+ int numSyms = keycodeCount * keysymsPerKeycode;
+ auto keymapPtr = xcb_get_keyboard_mapping_keysyms(keymapReply.get());
+ xkeymap.resize(numSyms);
+ for (int i = 0; i < numSyms; i++)
+ xkeymap[i] = keymapPtr[i];
+ }
+ }
+ if (xkeymap.isEmpty())
+ return nullptr;
+
+ KeysymModifierMap keysymMods(keysymsToModifiers());
+ static const char *const builtinModifiers[] =
+ { "Shift", "Lock", "Control", "Mod1", "Mod2", "Mod3", "Mod4", "Mod5" };
+
+ /* Level 3 symbols (e.g. AltGr+something) seem to come in two flavors:
+ * - as a proper level 3 in group 1, at least on recent X.org versions
+ * - 'disguised' as group 2, on 'legacy' X servers
+ * In the 2nd case, remap group 2 to level 3, that seems to work better
+ * in practice */
+ bool mapGroup2ToLevel3 = keysymsPerKeycode < 5;
+
+ keymap += "xkb_symbols \"core\" {\n";
+ for (int code = minKeycode; code <= maxKeycode; code++) {
+ auto codeMap = xkeymap.constData() + (code - minKeycode) * keysymsPerKeycode;
+
+ const int maxGroup1 = 4; // We only support 4 shift states anyway
+ const int maxGroup2 = 2; // Only 3rd and 4th keysym are group 2
+ xcb_keysym_t symbolsGroup1[maxGroup1];
+ xcb_keysym_t symbolsGroup2[maxGroup2];
+ for (int i = 0; i < maxGroup1 + maxGroup2; i++) {
+ xcb_keysym_t sym = i < keysymsPerKeycode ? codeMap[i] : XKB_KEY_NoSymbol;
+ if (mapGroup2ToLevel3) {
+ // Merge into single group
+ if (i < maxGroup1)
+ symbolsGroup1[i] = sym;
+ } else {
+ // Preserve groups
+ if (i < 2)
+ symbolsGroup1[i] = sym;
+ else if (i < 4)
+ symbolsGroup2[i - 2] = sym;
+ else
+ symbolsGroup1[i - 2] = sym;
+ }
+ }
+
+ /* Fix symbols so the unshifted and shifted symbols have
+ * lower resp. upper case */
+ if (auto lowered = getUnshiftedXKey(symbolsGroup1[0], symbolsGroup1[1])) {
+ symbolsGroup1[1] = symbolsGroup1[0];
+ symbolsGroup1[0] = lowered;
+ }
+ if (auto lowered = getUnshiftedXKey(symbolsGroup2[0], symbolsGroup2[1])) {
+ symbolsGroup2[1] = symbolsGroup2[0];
+ symbolsGroup2[0] = lowered;
+ }
+
+ QByteArray groupStr1 = symbolsGroupString(symbolsGroup1, maxGroup1);
+ if (groupStr1.isEmpty())
+ continue;
+
+ keymap += "key <K" + QByteArray::number(code) + "> { ";
+ keymap += "symbols[Group1] = [ " + groupStr1 + " ]";
+ QByteArray groupStr2 = symbolsGroupString(symbolsGroup2, maxGroup2);
+ if (!groupStr2.isEmpty())
+ keymap += ", symbols[Group2] = [ " + groupStr2 + " ]";
+
+ // See if this key code is for a modifier
+ xcb_keysym_t modifierSym = XKB_KEY_NoSymbol;
+ for (int symIndex = 0; symIndex < keysymsPerKeycode; symIndex++) {
+ xcb_keysym_t sym = codeMap[symIndex];
+
+ if (sym == XKB_KEY_Alt_L
+ || sym == XKB_KEY_Meta_L
+ || sym == XKB_KEY_Mode_switch
+ || sym == XKB_KEY_Super_L
+ || sym == XKB_KEY_Super_R
+ || sym == XKB_KEY_Hyper_L
+ || sym == XKB_KEY_Hyper_R) {
+ modifierSym = sym;
+ break;
+ }
+ }
+
+ // AltGr
+ if (modifierSym == XKB_KEY_Mode_switch)
+ keymap += ", virtualMods=LevelThree";
+ keymap += " };\n"; // key
+
+ // Generate modifier mappings
+ int modNum = keysymMods.value(modifierSym, -1);
+ if (modNum != -1) {
+ // Here modNum is always < 8 (see keysymsToModifiers())
+ keymap += QByteArray("modifier_map ") + builtinModifiers[modNum]
+ + " { <K" + QByteArray::number(code) + "> };\n";
+ }
+ }
+ // TODO: indicators?
+ keymap += "};\n"; // xkb_symbols
+ }
+
+ // We need an "Alt" modifier, provide via the xkb_compatibility section
+ keymap +=
+ "xkb_compatibility \"core\" {\n"
+ "virtual_modifiers NumLock,Alt,LevelThree;\n"
+ "interpret Alt_L+AnyOf(all) {\n"
+ "virtualModifier= Alt;\n"
+ "action= SetMods(modifiers=modMapMods,clearLocks);\n"
+ "};\n"
+ "interpret Alt_R+AnyOf(all) {\n"
+ "virtualModifier= Alt;\n"
+ "action= SetMods(modifiers=modMapMods,clearLocks);\n"
+ "};\n"
+ "};\n";
+
+ /* TODO: There is an issue with modifier state not being handled
+ * correctly if using Xming with XKEYBOARD disabled. */
+
+ keymap += "};\n"; // xkb_keymap
+
+ return xkb_keymap_new_from_buffer(xkb_context,
+ keymap.constData(),
+ keymap.size(),
+ XKB_KEYMAP_FORMAT_TEXT_V1,
+ static_cast<xkb_keymap_compile_flags>(0));
+}
+#endif
+
void QXcbKeyboard::updateKeymap()
{
m_config = true;
+ m_keymap_is_core = false;
// set xkb context object
if (!xkb_context) {
if (qEnvironmentVariableIsSet("QT_XKB_CONFIG_ROOT")) {
@@ -714,9 +1014,23 @@ void QXcbKeyboard::updateKeymap()
}
#endif
if (!xkb_keymap) {
- // Compile a keymap from RMLVO (rules, models, layouts, variants and options) names
+ // Read xkb RMLVO (rules, models, layouts, variants and options) names
readXKBConfig();
- xkb_keymap = xkb_keymap_new_from_names(xkb_context, &xkb_names, (xkb_keymap_compile_flags)0);
+#if QT_CONFIG(xcb_xlib)
+ bool rmlvo_is_incomplete = !xkb_names.rules || !(*xkb_names.rules)
+ || !xkb_names.model || !(*xkb_names.model)
+ || !xkb_names.layout || !(*xkb_names.layout);
+ if (rmlvo_is_incomplete) {
+ // Try to build xkb map from core mapping information
+ xkb_keymap = keymapFromCore();
+ m_keymap_is_core = xkb_keymap != 0;
+ }
+#endif
+ if (!xkb_keymap) {
+ // Compile a keymap from RMLVO
+ xkb_keymap = xkb_keymap_new_from_names(xkb_context, &xkb_names,
+ static_cast<xkb_keymap_compile_flags> (0));
+ }
if (!xkb_keymap) {
// last fallback is to used hard-coded keymap name, see DEFAULT_XKB_* in xkbcommon.pri
qWarning() << "Qt: Could not determine keyboard configuration data"
@@ -908,9 +1222,11 @@ xkb_keysym_t QXcbKeyboard::lookupLatinKeysym(xkb_keycode_t keycode) const
// If user layouts don't contain any layout that results in a latin key, we query a
// key from "US" layout, this allows for latin-key-based shorcuts to work even when
// users have only one (non-latin) layout set.
+ // But don't do this if using keymap obtained through the core protocol, as the key
+ // codes may not match up with those expected by the XKB keymap.
xkb_mod_mask_t latchedMods = xkb_state_serialize_mods(xkb_state, XKB_STATE_MODS_LATCHED);
xkb_mod_mask_t lockedMods = xkb_state_serialize_mods(xkb_state, XKB_STATE_MODS_LOCKED);
- if (sym == XKB_KEY_NoSymbol && !m_hasLatinLayout) {
+ if (sym == XKB_KEY_NoSymbol && !m_hasLatinLayout && !m_keymap_is_core) {
if (!latin_keymap) {
const struct xkb_rule_names names = { xkb_names.rules, xkb_names.model, "us", 0, 0 };
latin_keymap = xkb_keymap_new_from_names(xkb_context, &names, (xkb_keymap_compile_flags)0);
@@ -1289,20 +1605,56 @@ void QXcbKeyboard::updateVModToRModMapping()
#endif
}
+// Small helper: set modifier bit, if modifier position is valid
+static inline void applyModifier(uint *mask, int modifierBit)
+{
+ if (modifierBit >= 0 && modifierBit < 8)
+ *mask |= 1 << modifierBit;
+}
+
void QXcbKeyboard::updateModifiers()
{
+ memset(&rmod_masks, 0, sizeof(rmod_masks));
+
+ // Compute X modifier bits for Qt modifiers
+ KeysymModifierMap keysymMods(keysymsToModifiers());
+ applyModifier(&rmod_masks.alt, keysymMods.value(XK_Alt_L, -1));
+ applyModifier(&rmod_masks.alt, keysymMods.value(XK_Alt_R, -1));
+ applyModifier(&rmod_masks.meta, keysymMods.value(XK_Meta_L, -1));
+ applyModifier(&rmod_masks.meta, keysymMods.value(XK_Meta_R, -1));
+ applyModifier(&rmod_masks.altgr, keysymMods.value(XK_Mode_switch, -1));
+ applyModifier(&rmod_masks.super, keysymMods.value(XK_Super_L, -1));
+ applyModifier(&rmod_masks.super, keysymMods.value(XK_Super_R, -1));
+ applyModifier(&rmod_masks.hyper, keysymMods.value(XK_Hyper_L, -1));
+ applyModifier(&rmod_masks.hyper, keysymMods.value(XK_Hyper_R, -1));
+
+ resolveMaskConflicts();
+}
+
+// Small helper: check if an array of xcb_keycode_t contains a certain code
+static inline bool keycodes_contains(xcb_keycode_t *codes, xcb_keycode_t which)
+{
+ while (*codes != XCB_NO_SYMBOL) {
+ if (*codes == which) return true;
+ codes++;
+ }
+ return false;
+}
+
+QXcbKeyboard::KeysymModifierMap QXcbKeyboard::keysymsToModifiers()
+{
// The core protocol does not provide a convenient way to determine the mapping
// of modifier bits. Clients must retrieve and search the modifier map to determine
// the keycodes bound to each modifier, and then retrieve and search the keyboard
// mapping to determine the keysyms bound to the keycodes. They must repeat this
// process for all modifiers whenever any part of the modifier mapping is changed.
- memset(&rmod_masks, 0, sizeof(rmod_masks));
- xcb_connection_t *conn = xcb_connection();
- auto modMapReply = Q_XCB_REPLY(xcb_get_modifier_mapping, conn);
+ KeysymModifierMap map;
+
+ auto modMapReply = Q_XCB_REPLY(xcb_get_modifier_mapping, xcb_connection());
if (!modMapReply) {
qWarning("Qt: failed to get modifier mapping");
- return;
+ return map;
}
// for Alt and Meta L and R are the same
@@ -1318,34 +1670,62 @@ void QXcbKeyboard::updateModifiers()
modKeyCodes[i] = xcb_key_symbols_get_keycode(m_key_symbols, symbols[i]);
xcb_keycode_t *modMap = xcb_get_modifier_mapping_keycodes(modMapReply.get());
- const int w = modMapReply->keycodes_per_modifier;
- for (size_t i = 0; i < numSymbols; ++i) {
- for (int bit = 0; bit < 8; ++bit) {
- uint mask = 1 << bit;
- for (int x = 0; x < w; ++x) {
- xcb_keycode_t keyCode = modMap[x + bit * w];
- xcb_keycode_t *itk = modKeyCodes[i];
- while (itk && *itk != XCB_NO_SYMBOL)
- if (*itk++ == keyCode) {
- uint sym = symbols[i];
- if ((sym == XK_Alt_L || sym == XK_Alt_R))
- rmod_masks.alt = mask;
- if ((sym == XK_Meta_L || sym == XK_Meta_R))
- rmod_masks.meta = mask;
- if (sym == XK_Mode_switch)
- rmod_masks.altgr = mask;
- if ((sym == XK_Super_L) || (sym == XK_Super_R))
- rmod_masks.super = mask;
- if ((sym == XK_Hyper_L) || (sym == XK_Hyper_R))
- rmod_masks.hyper = mask;
- }
+ const int modMapLength = xcb_get_modifier_mapping_keycodes_length(modMapReply.get());
+ /* For each modifier of "Shift, Lock, Control, Mod1, Mod2, Mod3,
+ * Mod4, and Mod5" the modifier map contains keycodes_per_modifier
+ * key codes that are associated with a modifier.
+ *
+ * As an example, take this 'xmodmap' output:
+ * xmodmap: up to 4 keys per modifier, (keycodes in parentheses):
+ *
+ * shift Shift_L (0x32), Shift_R (0x3e)
+ * lock Caps_Lock (0x42)
+ * control Control_L (0x25), Control_R (0x69)
+ * mod1 Alt_L (0x40), Alt_R (0x6c), Meta_L (0xcd)
+ * mod2 Num_Lock (0x4d)
+ * mod3
+ * mod4 Super_L (0x85), Super_R (0x86), Super_L (0xce), Hyper_L (0xcf)
+ * mod5 ISO_Level3_Shift (0x5c), Mode_switch (0xcb)
+ *
+ * The corresponding raw modifier map would contain keycodes for:
+ * Shift_L (0x32), Shift_R (0x3e), 0, 0,
+ * Caps_Lock (0x42), 0, 0, 0,
+ * Control_L (0x25), Control_R (0x69), 0, 0,
+ * Alt_L (0x40), Alt_R (0x6c), Meta_L (0xcd), 0,
+ * Num_Lock (0x4d), 0, 0, 0,
+ * 0,0,0,0,
+ * Super_L (0x85), Super_R (0x86), Super_L (0xce), Hyper_L (0xcf),
+ * ISO_Level3_Shift (0x5c), Mode_switch (0xcb), 0, 0
+ */
+
+ /* Create a map between a modifier keysym (as per the symbols array)
+ * and the modifier bit it's associated with (if any).
+ * As modMap contains key codes, search modKeyCodes for a match;
+ * if one is found we can look up the associated keysym.
+ * Together with the modifier index this will be used
+ * to compute a mapping between X modifier bits and Qt's
+ * modifiers (Alt, Ctrl etc). */
+ for (int i = 0; i < modMapLength; i++) {
+ if (modMap[i] == XCB_NO_SYMBOL)
+ continue;
+ // Get key symbol for key code
+ for (size_t k = 0; k < numSymbols; k++) {
+ if (modKeyCodes[k] && keycodes_contains(modKeyCodes[k], modMap[i])) {
+ // Key code is for modifier. Record mapping
+ xcb_keysym_t sym = symbols[k];
+ /* As per modMap layout explanation above, dividing
+ * by keycodes_per_modifier gives the 'row' in the
+ * modifier map, which in turn is the modifier bit. */
+ map[sym] = i / modMapReply->keycodes_per_modifier;
+ break;
}
}
}
for (size_t i = 0; i < numSymbols; ++i)
free(modKeyCodes[i]);
- resolveMaskConflicts();
+
+ return map;
}
void QXcbKeyboard::resolveMaskConflicts()
diff --git a/src/plugins/platforms/xcb/qxcbkeyboard.h b/src/plugins/platforms/xcb/qxcbkeyboard.h
index 7f1c51fab8..7ee8e9e90d 100644
--- a/src/plugins/platforms/xcb/qxcbkeyboard.h
+++ b/src/plugins/platforms/xcb/qxcbkeyboard.h
@@ -94,8 +94,13 @@ protected:
void readXKBConfig();
void clearXKBConfig();
+#if QT_CONFIG(xcb_xlib)
+ struct xkb_keymap *keymapFromCore();
+#endif
// when XKEYBOARD not present on the X server
void updateModifiers();
+ typedef QMap<xcb_keysym_t, int> KeysymModifierMap;
+ KeysymModifierMap keysymsToModifiers();
// when XKEYBOARD is present on the X server
void updateVModMapping();
void updateVModToRModMapping();
@@ -107,6 +112,7 @@ private:
void updateXKBStateFromState(struct xkb_state *kb_state, quint16 state);
bool m_config = false;
+ bool m_keymap_is_core = false;
xcb_keycode_t m_autorepeat_code = 0;
struct xkb_context *xkb_context = nullptr;
diff --git a/src/plugins/platforms/xcb/qxcbmime.cpp b/src/plugins/platforms/xcb/qxcbmime.cpp
index 2848446098..58e2e8c0e6 100644
--- a/src/plugins/platforms/xcb/qxcbmime.cpp
+++ b/src/plugins/platforms/xcb/qxcbmime.cpp
@@ -160,9 +160,10 @@ QVector<xcb_atom_t> QXcbMime::mimeAtomsForFormat(QXcbConnection *connection, con
return atoms;
}
-QVariant QXcbMime::mimeConvertToFormat(QXcbConnection *connection, xcb_atom_t a, const QByteArray &data, const QString &format,
+QVariant QXcbMime::mimeConvertToFormat(QXcbConnection *connection, xcb_atom_t a, const QByteArray &d, const QString &format,
QVariant::Type requestedType, const QByteArray &encoding)
{
+ QByteArray data = d;
QString atomName = mimeAtomToString(connection, a);
// qDebug() << "mimeConvertDataToFormat" << format << atomName << data;
@@ -182,8 +183,11 @@ QVariant QXcbMime::mimeConvertToFormat(QXcbConnection *connection, xcb_atom_t a,
// special cases for string types
if (format == QLatin1String("text/plain")) {
- if (a == connection->atom(QXcbAtom::UTF8_STRING))
+ if (data.endsWith('\0'))
+ data.chop(1);
+ if (a == connection->atom(QXcbAtom::UTF8_STRING)) {
return QString::fromUtf8(data);
+ }
if (a == XCB_ATOM_STRING ||
a == connection->atom(QXcbAtom::TEXT))
return QString::fromLatin1(data);
@@ -221,6 +225,9 @@ QVariant QXcbMime::mimeConvertToFormat(QXcbConnection *connection, xcb_atom_t a,
}
}
}
+ // 8 byte encoding, remove a possible 0 at the end
+ if (data.endsWith('\0'))
+ data.chop(1);
}
if (atomName == format)
diff --git a/src/plugins/platforms/xcb/qxcbnativeinterface.cpp b/src/plugins/platforms/xcb/qxcbnativeinterface.cpp
index caa9499c45..d989761297 100644
--- a/src/plugins/platforms/xcb/qxcbnativeinterface.cpp
+++ b/src/plugins/platforms/xcb/qxcbnativeinterface.cpp
@@ -101,7 +101,7 @@ QXcbNativeInterface::QXcbNativeInterface() :
static inline QXcbSystemTrayTracker *systemTrayTracker(const QScreen *s)
{
if (!s)
- return Q_NULLPTR;
+ return nullptr;
return static_cast<const QXcbScreen *>(s->handle())->connection()->systemTrayTracker();
}
@@ -194,7 +194,7 @@ void *QXcbNativeInterface::nativeResourceForScreen(const QByteArray &resourceStr
{
if (!screen) {
qWarning("nativeResourceForScreen: null screen");
- return Q_NULLPTR;
+ return nullptr;
}
QByteArray lowerCaseResource = resourceString.toLower();
@@ -236,7 +236,7 @@ void *QXcbNativeInterface::nativeResourceForScreen(const QByteArray &resourceStr
break;
case CompositingEnabled:
if (QXcbVirtualDesktop *vd = xcbScreen->virtualDesktop())
- result = vd->compositingActive() ? this : Q_NULLPTR;
+ result = vd->compositingActive() ? this : nullptr;
break;
default:
break;
@@ -294,7 +294,7 @@ void *QXcbNativeInterface::nativeResourceForCursor(const QByteArray &resource, c
}
}
}
- return Q_NULLPTR;
+ return nullptr;
}
#endif // !QT_NO_CURSOR
@@ -323,7 +323,7 @@ QPlatformNativeInterface::NativeResourceForContextFunction QXcbNativeInterface::
QPlatformNativeInterface::NativeResourceForContextFunction func = handlerNativeResourceFunctionForContext(lowerCaseResource);
if (func)
return func;
- return Q_NULLPTR;
+ return nullptr;
}
QPlatformNativeInterface::NativeResourceForScreenFunction QXcbNativeInterface::nativeResourceFunctionForScreen(const QByteArray &resource)
@@ -390,13 +390,13 @@ QFunctionPointer QXcbNativeInterface::platformFunction(const QByteArray &functio
if (function == QXcbScreenFunctions::virtualDesktopNumberIdentifier())
return QFunctionPointer(QXcbScreenFunctions::VirtualDesktopNumber(QXcbScreen::virtualDesktopNumberStatic));
- return Q_NULLPTR;
+ return nullptr;
}
void *QXcbNativeInterface::appTime(const QXcbScreen *screen)
{
if (!screen)
- return Q_NULLPTR;
+ return nullptr;
return reinterpret_cast<void *>(quintptr(screen->connection()->time()));
}
@@ -404,7 +404,7 @@ void *QXcbNativeInterface::appTime(const QXcbScreen *screen)
void *QXcbNativeInterface::appUserTime(const QXcbScreen *screen)
{
if (!screen)
- return Q_NULLPTR;
+ return nullptr;
return reinterpret_cast<void *>(quintptr(screen->connection()->netWmUserTime()));
}
@@ -412,7 +412,7 @@ void *QXcbNativeInterface::appUserTime(const QXcbScreen *screen)
void *QXcbNativeInterface::getTimestamp(const QXcbScreen *screen)
{
if (!screen)
- return Q_NULLPTR;
+ return nullptr;
return reinterpret_cast<void *>(quintptr(screen->connection()->getTimestamp()));
}
@@ -452,7 +452,7 @@ void *QXcbNativeInterface::display()
if (defaultConnection)
return defaultConnection->xlib_display();
#endif
- return Q_NULLPTR;
+ return nullptr;
}
void *QXcbNativeInterface::connection()
@@ -525,10 +525,10 @@ QXcbScreen *QXcbNativeInterface::qPlatformScreenForWindow(QWindow *window)
QXcbScreen *screen;
if (window) {
QScreen *qs = window->screen();
- screen = static_cast<QXcbScreen *>(qs ? qs->handle() : Q_NULLPTR);
+ screen = static_cast<QXcbScreen *>(qs ? qs->handle() : nullptr);
} else {
QScreen *qs = QGuiApplication::primaryScreen();
- screen = static_cast<QXcbScreen *>(qs ? qs->handle() : Q_NULLPTR);
+ screen = static_cast<QXcbScreen *>(qs ? qs->handle() : nullptr);
}
return screen;
}
@@ -537,23 +537,23 @@ void *QXcbNativeInterface::displayForWindow(QWindow *window)
{
#if QT_CONFIG(xcb_xlib)
QXcbScreen *screen = qPlatformScreenForWindow(window);
- return screen ? screen->connection()->xlib_display() : Q_NULLPTR;
+ return screen ? screen->connection()->xlib_display() : nullptr;
#else
Q_UNUSED(window);
- return Q_NULLPTR;
+ return nullptr;
#endif
}
void *QXcbNativeInterface::connectionForWindow(QWindow *window)
{
QXcbScreen *screen = qPlatformScreenForWindow(window);
- return screen ? screen->xcb_connection() : Q_NULLPTR;
+ return screen ? screen->xcb_connection() : nullptr;
}
void *QXcbNativeInterface::screenForWindow(QWindow *window)
{
QXcbScreen *screen = qPlatformScreenForWindow(window);
- return screen ? screen->screen() : Q_NULLPTR;
+ return screen ? screen->screen() : nullptr;
}
void QXcbNativeInterface::addHandler(QXcbNativeInterfaceHandler *handler)
@@ -575,7 +575,7 @@ QPlatformNativeInterface::NativeResourceForIntegrationFunction QXcbNativeInterfa
if (result)
return result;
}
- return Q_NULLPTR;
+ return nullptr;
}
QPlatformNativeInterface::NativeResourceForContextFunction QXcbNativeInterface::handlerNativeResourceFunctionForContext(const QByteArray &resource) const
@@ -586,7 +586,7 @@ QPlatformNativeInterface::NativeResourceForContextFunction QXcbNativeInterface::
if (result)
return result;
}
- return Q_NULLPTR;
+ return nullptr;
}
QPlatformNativeInterface::NativeResourceForScreenFunction QXcbNativeInterface::handlerNativeResourceFunctionForScreen(const QByteArray &resource) const
@@ -597,7 +597,7 @@ QPlatformNativeInterface::NativeResourceForScreenFunction QXcbNativeInterface::h
if (result)
return result;
}
- return Q_NULLPTR;
+ return nullptr;
}
QPlatformNativeInterface::NativeResourceForWindowFunction QXcbNativeInterface::handlerNativeResourceFunctionForWindow(const QByteArray &resource) const
@@ -608,7 +608,7 @@ QPlatformNativeInterface::NativeResourceForWindowFunction QXcbNativeInterface::h
if (result)
return result;
}
- return Q_NULLPTR;
+ return nullptr;
}
QPlatformNativeInterface::NativeResourceForBackingStoreFunction QXcbNativeInterface::handlerNativeResourceFunctionForBackingStore(const QByteArray &resource) const
@@ -619,7 +619,7 @@ QPlatformNativeInterface::NativeResourceForBackingStoreFunction QXcbNativeInterf
if (result)
return result;
}
- return Q_NULLPTR;
+ return nullptr;
}
QFunctionPointer QXcbNativeInterface::handlerPlatformFunction(const QByteArray &function) const
@@ -630,7 +630,7 @@ QFunctionPointer QXcbNativeInterface::handlerPlatformFunction(const QByteArray &
if (func)
return func;
}
- return Q_NULLPTR;
+ return nullptr;
}
void *QXcbNativeInterface::handlerNativeResourceForIntegration(const QByteArray &resource) const
@@ -638,7 +638,7 @@ void *QXcbNativeInterface::handlerNativeResourceForIntegration(const QByteArray
NativeResourceForIntegrationFunction func = handlerNativeResourceFunctionForIntegration(resource);
if (func)
return func();
- return Q_NULLPTR;
+ return nullptr;
}
void *QXcbNativeInterface::handlerNativeResourceForContext(const QByteArray &resource, QOpenGLContext *context) const
@@ -646,7 +646,7 @@ void *QXcbNativeInterface::handlerNativeResourceForContext(const QByteArray &res
NativeResourceForContextFunction func = handlerNativeResourceFunctionForContext(resource);
if (func)
return func(context);
- return Q_NULLPTR;
+ return nullptr;
}
void *QXcbNativeInterface::handlerNativeResourceForScreen(const QByteArray &resource, QScreen *screen) const
@@ -654,7 +654,7 @@ void *QXcbNativeInterface::handlerNativeResourceForScreen(const QByteArray &reso
NativeResourceForScreenFunction func = handlerNativeResourceFunctionForScreen(resource);
if (func)
return func(screen);
- return Q_NULLPTR;
+ return nullptr;
}
void *QXcbNativeInterface::handlerNativeResourceForWindow(const QByteArray &resource, QWindow *window) const
@@ -662,7 +662,7 @@ void *QXcbNativeInterface::handlerNativeResourceForWindow(const QByteArray &reso
NativeResourceForWindowFunction func = handlerNativeResourceFunctionForWindow(resource);
if (func)
return func(window);
- return Q_NULLPTR;
+ return nullptr;
}
void *QXcbNativeInterface::handlerNativeResourceForBackingStore(const QByteArray &resource, QBackingStore *backingStore) const
@@ -670,7 +670,7 @@ void *QXcbNativeInterface::handlerNativeResourceForBackingStore(const QByteArray
NativeResourceForBackingStoreFunction func = handlerNativeResourceFunctionForBackingStore(resource);
if (func)
return func(backingStore);
- return Q_NULLPTR;
+ return nullptr;
}
QT_END_NAMESPACE
diff --git a/src/plugins/platforms/xcb/qxcbscreen.cpp b/src/plugins/platforms/xcb/qxcbscreen.cpp
index 67c96b2d80..e3d9bc7a3d 100644
--- a/src/plugins/platforms/xcb/qxcbscreen.cpp
+++ b/src/plugins/platforms/xcb/qxcbscreen.cpp
@@ -140,7 +140,7 @@ QXcbScreen *QXcbVirtualDesktop::screenAt(const QPoint &pos) const
if (screen->virtualDesktop() == this && screen->geometry().contains(pos))
return screen;
}
- return Q_NULLPTR;
+ return nullptr;
}
void QXcbVirtualDesktop::addScreen(QPlatformScreen *s)
@@ -590,7 +590,9 @@ QRect QXcbScreen::availableGeometry() const
QImage::Format QXcbScreen::format() const
{
- return qt_xcb_imageFormatForVisual(connection(), screen()->root_depth, visualForId(screen()->root_visual));
+ QImage::Format format;
+ qt_xcb_imageFormatForVisual(connection(), screen()->root_depth, visualForId(screen()->root_visual), &format);
+ return format;
}
QDpi QXcbScreen::virtualDpi() const
diff --git a/src/plugins/platforms/xcb/qxcbscreen.h b/src/plugins/platforms/xcb/qxcbscreen.h
index 842738b622..4a9b1bd209 100644
--- a/src/plugins/platforms/xcb/qxcbscreen.h
+++ b/src/plugins/platforms/xcb/qxcbscreen.h
@@ -140,7 +140,7 @@ class Q_XCB_EXPORT QXcbScreen : public QXcbObject, public QPlatformScreen
public:
QXcbScreen(QXcbConnection *connection, QXcbVirtualDesktop *virtualDesktop,
xcb_randr_output_t outputId, xcb_randr_get_output_info_reply_t *outputInfo,
- const xcb_xinerama_screen_info_t *xineramaScreenInfo = Q_NULLPTR, int xineramaScreenIdx = -1);
+ const xcb_xinerama_screen_info_t *xineramaScreenInfo = nullptr, int xineramaScreenIdx = -1);
~QXcbScreen();
QString getOutputName(xcb_randr_get_output_info_reply_t *outputInfo);
diff --git a/src/plugins/platforms/xcb/qxcbwindow.cpp b/src/plugins/platforms/xcb/qxcbwindow.cpp
index c8a668b72c..20d030b5c9 100644
--- a/src/plugins/platforms/xcb/qxcbwindow.cpp
+++ b/src/plugins/platforms/xcb/qxcbwindow.cpp
@@ -51,6 +51,7 @@
#include "qxcbscreen.h"
#include "qxcbdrag.h"
#include "qxcbkeyboard.h"
+#include "qxcbimage.h"
#include "qxcbwmsupport.h"
#include "qxcbimage.h"
#include "qxcbnativeinterface.h"
@@ -176,80 +177,23 @@ static inline bool isTransient(const QWindow *w)
|| w->type() == Qt::Popup;
}
-static inline QImage::Format imageFormatForVisual(int depth, quint32 red_mask, quint32 blue_mask, bool *rgbSwap)
+void QXcbWindow::setImageFormatForVisual(const xcb_visualtype_t *visual)
{
- if (rgbSwap)
- *rgbSwap = false;
- switch (depth) {
- case 32:
- if (blue_mask == 0xff)
- return QImage::Format_ARGB32_Premultiplied;
- if (red_mask == 0x3ff)
- return QImage::Format_A2BGR30_Premultiplied;
- if (blue_mask == 0x3ff)
- return QImage::Format_A2RGB30_Premultiplied;
- if (red_mask == 0xff) {
- if (rgbSwap)
- *rgbSwap = true;
- return QImage::Format_ARGB32_Premultiplied;
- }
- break;
- case 30:
- if (red_mask == 0x3ff)
- return QImage::Format_BGR30;
- if (blue_mask == 0x3ff)
- return QImage::Format_RGB30;
- break;
- case 24:
- if (blue_mask == 0xff)
- return QImage::Format_RGB32;
- if (red_mask == 0xff) {
- if (rgbSwap)
- *rgbSwap = true;
- return QImage::Format_RGB32;
- }
- break;
- 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;
-#if QT_CONFIG(xcb_native_painting)
- case 8:
- if (QXcbIntegration::instance() && QXcbIntegration::instance()->nativePaintingEnabled())
- return QImage::Format_Indexed8;
- break;
-#endif
- default:
- break;
- }
- qWarning("Unsupported screen format: depth: %d, red_mask: %x, blue_mask: %x", depth, red_mask, blue_mask);
+ if (qt_xcb_imageFormatForVisual(connection(), m_depth, visual, &m_imageFormat, &m_imageRgbSwap))
+ return;
- switch (depth) {
+ switch (m_depth) {
+ case 32:
case 24:
qWarning("Using RGB32 fallback, if this works your X11 server is reporting a bad screen format.");
- return QImage::Format_RGB32;
+ m_imageFormat = QImage::Format_RGB32;
+ break;
case 16:
qWarning("Using RGB16 fallback, if this works your X11 server is reporting a bad screen format.");
- return QImage::Format_RGB16;
+ m_imageFormat = QImage::Format_RGB16;
default:
break;
}
-
- return QImage::Format_Invalid;
}
static inline bool positionIncludesFrame(QWindow *w)
@@ -287,7 +231,7 @@ static inline XTextProperty* qstringToXTP(Display *dpy, const QString& s)
if (!mapper || errCode < 0) {
mapper = QTextCodec::codecForName("latin1");
if (!mapper || !mapper->canEncode(s))
- return Q_NULLPTR;
+ return nullptr;
#endif
static QByteArray qcs;
qcs = s.toLatin1();
@@ -322,7 +266,7 @@ static QWindow *childWindowAt(QWindow *win, const QPoint &p)
&& win->geometry().contains(win->parent()->mapFromGlobal(p))) {
return win;
}
- return Q_NULLPTR;
+ return nullptr;
}
static const char *wm_window_type_property_id = "_q_xcb_wm_window_type";
@@ -381,7 +325,7 @@ void QXcbWindow::create()
}
if (!visual)
visual = platformScreen->visualForId(m_visualId);
- m_imageFormat = imageFormatForVisual(m_depth, visual->red_mask, visual->blue_mask, &m_imageRgbSwap);
+ setImageFormatForVisual(visual);
connection()->addWindowEventListener(m_window, this);
return;
}
@@ -418,7 +362,7 @@ void QXcbWindow::create()
resolveFormat(platformScreen->surfaceFormatFor(window()->requestedFormat()));
- const xcb_visualtype_t *visual = Q_NULLPTR;
+ const xcb_visualtype_t *visual = nullptr;
if (connection()->hasDefaultVisualId()) {
visual = platformScreen->visualForId(connection()->defaultVisualId());
@@ -451,7 +395,7 @@ void QXcbWindow::create()
m_visualId = visual->visual_id;
m_depth = platformScreen->depthOfVisual(m_visualId);
- m_imageFormat = imageFormatForVisual(m_depth, visual->red_mask, visual->blue_mask, &m_imageRgbSwap);
+ setImageFormatForVisual(visual);
quint32 mask = XCB_CW_BACK_PIXMAP
| XCB_CW_BORDER_PIXEL
@@ -641,7 +585,7 @@ void QXcbWindow::destroy()
if (connection()->focusWindow() == this)
doFocusOut();
if (connection()->mouseGrabber() == this)
- connection()->setMouseGrabber(Q_NULLPTR);
+ connection()->setMouseGrabber(nullptr);
if (m_syncCounter && m_usingSyncProtocol)
xcb_sync_destroy_counter(xcb_connection(), m_syncCounter);
@@ -700,6 +644,15 @@ void QXcbWindow::setGeometry(const QRect &rect)
qBound<qint32>(1, wmGeometry.height(), XCOORD_MAX),
};
xcb_configure_window(xcb_connection(), m_window, mask, reinterpret_cast<const quint32*>(values));
+ if (window()->parent() && !window()->transientParent()) {
+ // Wait for server reply for parented windows to ensure that a few window
+ // moves will come as a one event. This is important when native widget is
+ // moved a few times in X and Y directions causing native scroll. Widget
+ // must get single event to not trigger unwanted widget position changes
+ // and then expose events causing backingstore flushes with incorrect
+ // offset causing image crruption.
+ connection()->sync();
+ }
}
xcb_flush(xcb_connection());
@@ -877,12 +830,12 @@ void QXcbWindow::hide()
xcb_flush(xcb_connection());
if (connection()->mouseGrabber() == this)
- connection()->setMouseGrabber(Q_NULLPTR);
+ connection()->setMouseGrabber(nullptr);
if (QPlatformWindow *w = connection()->mousePressWindow()) {
// Unset mousePressWindow when it (or one of its parents) is unmapped
while (w) {
if (w == this) {
- connection()->setMousePressWindow(Q_NULLPTR);
+ connection()->setMousePressWindow(nullptr);
break;
}
w = w->parent();
@@ -900,7 +853,7 @@ void QXcbWindow::hide()
// Find the top level window at cursor position.
// Don't use QGuiApplication::topLevelAt(): search only the virtual siblings of this window's screen
- QWindow *enterWindow = Q_NULLPTR;
+ QWindow *enterWindow = nullptr;
const auto screens = xcbScreen()->virtualSiblings();
for (QPlatformScreen *screen : screens) {
if (screen->geometry().contains(cursorPos)) {
@@ -2000,13 +1953,14 @@ void QXcbWindow::handleClientMessageEvent(const xcb_client_message_event_t *even
return;
if (event->type == atom(QXcbAtom::WM_PROTOCOLS)) {
- if (event->data.data32[0] == atom(QXcbAtom::WM_DELETE_WINDOW)) {
+ xcb_atom_t protocolAtom = event->data.data32[0];
+ if (protocolAtom == atom(QXcbAtom::WM_DELETE_WINDOW)) {
QWindowSystemInterface::handleCloseEvent(window());
- } else if (event->data.data32[0] == atom(QXcbAtom::WM_TAKE_FOCUS)) {
+ } else if (protocolAtom == atom(QXcbAtom::WM_TAKE_FOCUS)) {
connection()->setTime(event->data.data32[1]);
relayFocusToModalWindow();
return;
- } else if (event->data.data32[0] == atom(QXcbAtom::_NET_WM_PING)) {
+ } else if (protocolAtom == atom(QXcbAtom::_NET_WM_PING)) {
if (event->window == xcbScreen()->root())
return;
@@ -2015,20 +1969,23 @@ void QXcbWindow::handleClientMessageEvent(const xcb_client_message_event_t *even
reply.response_type = XCB_CLIENT_MESSAGE;
reply.window = xcbScreen()->root();
- xcb_send_event(xcb_connection(), 0, xcbScreen()->root(), XCB_EVENT_MASK_STRUCTURE_NOTIFY | XCB_EVENT_MASK_SUBSTRUCTURE_REDIRECT, (const char *)&reply);
+ xcb_send_event(xcb_connection(), 0, xcbScreen()->root(),
+ XCB_EVENT_MASK_STRUCTURE_NOTIFY | XCB_EVENT_MASK_SUBSTRUCTURE_REDIRECT,
+ (const char *)&reply);
xcb_flush(xcb_connection());
- } else if (event->data.data32[0] == atom(QXcbAtom::_NET_WM_SYNC_REQUEST)) {
+ } else if (protocolAtom == atom(QXcbAtom::_NET_WM_SYNC_REQUEST)) {
connection()->setTime(event->data.data32[1]);
m_syncValue.lo = event->data.data32[2];
m_syncValue.hi = event->data.data32[3];
if (m_usingSyncProtocol)
m_syncState = SyncReceived;
#ifndef QT_NO_WHATSTHIS
- } else if (event->data.data32[0] == atom(QXcbAtom::_NET_WM_CONTEXT_HELP)) {
+ } else if (protocolAtom == atom(QXcbAtom::_NET_WM_CONTEXT_HELP)) {
QWindowSystemInterface::handleEnterWhatsThisEvent();
#endif
} else {
- qWarning() << "QXcbWindow: Unhandled WM_PROTOCOLS message:" << connection()->atomName(event->data.data32[0]);
+ qCWarning(lcQpaXcb, "Unhandled WM_PROTOCOLS (%s)",
+ connection()->atomName(protocolAtom).constData());
}
#ifndef QT_NO_DRAGANDDROP
} else if (event->type == atom(QXcbAtom::XdndEnter)) {
@@ -2056,7 +2013,7 @@ void QXcbWindow::handleClientMessageEvent(const xcb_client_message_event_t *even
|| 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);
+ qCWarning(lcQpaXcb) << "Unhandled client message: " << connection()->atomName(event->type);
}
}
@@ -2165,7 +2122,8 @@ 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, Qt::MouseEventSource source)
+ int detail, Qt::KeyboardModifiers modifiers, xcb_timestamp_t timestamp,
+ QEvent::Type type, Qt::MouseEventSource source)
{
const bool isWheel = detail >= 4 && detail <= 7;
if (!isWheel && window() != QGuiApplication::focusWindow()) {
@@ -2214,11 +2172,12 @@ void QXcbWindow::handleButtonPressEvent(int event_x, int event_y, int root_x, in
connection()->setMousePressWindow(this);
- handleMouseEvent(timestamp, local, global, modifiers, source);
+ handleMouseEvent(timestamp, local, global, modifiers, type, 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, Qt::MouseEventSource source)
+ int detail, Qt::KeyboardModifiers modifiers, xcb_timestamp_t timestamp,
+ QEvent::Type type, Qt::MouseEventSource source)
{
QPoint local(event_x, event_y);
QPoint global(root_x, root_y);
@@ -2229,9 +2188,9 @@ void QXcbWindow::handleButtonReleaseEvent(int event_x, int event_y, int root_x,
}
if (connection()->buttonState() == Qt::NoButton)
- connection()->setMousePressWindow(Q_NULLPTR);
+ connection()->setMousePressWindow(nullptr);
- handleMouseEvent(timestamp, local, global, modifiers, source);
+ handleMouseEvent(timestamp, local, global, modifiers, type, source);
}
static inline bool doCheckUnGrabAncestor(QXcbConnection *conn)
@@ -2254,7 +2213,7 @@ static inline bool doCheckUnGrabAncestor(QXcbConnection *conn)
return true;
}
-static bool ignoreLeaveEvent(quint8 mode, quint8 detail, QXcbConnection *conn = Q_NULLPTR)
+static bool ignoreLeaveEvent(quint8 mode, quint8 detail, QXcbConnection *conn = nullptr)
{
return ((doCheckUnGrabAncestor(conn)
&& mode == XCB_NOTIFY_MODE_GRAB && detail == XCB_NOTIFY_DETAIL_ANCESTOR)
@@ -2263,7 +2222,7 @@ static bool ignoreLeaveEvent(quint8 mode, quint8 detail, QXcbConnection *conn =
|| detail == XCB_NOTIFY_DETAIL_NONLINEAR_VIRTUAL);
}
-static bool ignoreEnterEvent(quint8 mode, quint8 detail, QXcbConnection *conn = Q_NULLPTR)
+static bool ignoreEnterEvent(quint8 mode, quint8 detail, QXcbConnection *conn = nullptr)
{
return ((doCheckUnGrabAncestor(conn)
&& mode == XCB_NOTIFY_MODE_UNGRAB && detail == XCB_NOTIFY_DETAIL_ANCESTOR)
@@ -2332,7 +2291,8 @@ 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::MouseEventSource source)
+ Qt::KeyboardModifiers modifiers, xcb_timestamp_t timestamp,
+ QEvent::Type type, Qt::MouseEventSource source)
{
QPoint local(event_x, event_y);
QPoint global(root_x, root_y);
@@ -2340,33 +2300,34 @@ void QXcbWindow::handleMotionNotifyEvent(int event_x, int event_y, int root_x, i
// "mousePressWindow" can be NULL i.e. if a window will be grabbed or unmapped, so set it again here.
// Unset "mousePressWindow" when mouse button isn't pressed - in some cases the release event won't arrive.
const bool isMouseButtonPressed = (connection()->buttonState() != Qt::NoButton);
- const bool hasMousePressWindow = (connection()->mousePressWindow() != Q_NULLPTR);
+ const bool hasMousePressWindow = (connection()->mousePressWindow() != nullptr);
if (isMouseButtonPressed && !hasMousePressWindow)
connection()->setMousePressWindow(this);
else if (hasMousePressWindow && !isMouseButtonPressed)
- connection()->setMousePressWindow(Q_NULLPTR);
+ connection()->setMousePressWindow(nullptr);
- handleMouseEvent(timestamp, local, global, modifiers, source);
+ handleMouseEvent(timestamp, local, global, modifiers, type, source);
}
void QXcbWindow::handleButtonPressEvent(const xcb_button_press_event_t *event)
{
Qt::KeyboardModifiers modifiers = connection()->keyboard()->translateModifiers(event->state);
handleButtonPressEvent(event->event_x, event->event_y, event->root_x, event->root_y, event->detail,
- modifiers, event->time);
+ modifiers, event->time, QEvent::MouseButtonPress);
}
void QXcbWindow::handleButtonReleaseEvent(const xcb_button_release_event_t *event)
{
Qt::KeyboardModifiers modifiers = connection()->keyboard()->translateModifiers(event->state);
handleButtonReleaseEvent(event->event_x, event->event_y, event->root_x, event->root_y, event->detail,
- modifiers, event->time);
+ modifiers, event->time, QEvent::MouseButtonRelease);
}
void QXcbWindow::handleMotionNotifyEvent(const xcb_motion_notify_event_t *event)
{
Qt::KeyboardModifiers modifiers = connection()->keyboard()->translateModifiers(event->state);
- handleMotionNotifyEvent(event->event_x, event->event_y, event->root_x, event->root_y, modifiers, event->time);
+ handleMotionNotifyEvent(event->event_x, event->event_y, event->root_x, event->root_y, modifiers,
+ event->time, QEvent::MouseMove);
}
#if QT_CONFIG(xinput2)
@@ -2417,18 +2378,18 @@ void QXcbWindow::handleXIMouseEvent(xcb_ge_event_t *event, Qt::MouseEventSource
if (Q_UNLIKELY(lcQpaXInputEvents().isDebugEnabled()))
qCDebug(lcQpaXInputEvents, "XI2 mouse press, button %d, time %d, source %s", button, ev->time, sourceName);
conn->setButtonState(button, true);
- handleButtonPressEvent(event_x, event_y, root_x, root_y, ev->detail, modifiers, ev->time, source);
+ handleButtonPressEvent(event_x, event_y, root_x, root_y, ev->detail, modifiers, ev->time, QEvent::MouseButtonPress, source);
break;
case XI_ButtonRelease:
if (Q_UNLIKELY(lcQpaXInputEvents().isDebugEnabled()))
qCDebug(lcQpaXInputEvents, "XI2 mouse release, button %d, time %d, source %s", button, ev->time, sourceName);
conn->setButtonState(button, false);
- handleButtonReleaseEvent(event_x, event_y, root_x, root_y, ev->detail, modifiers, ev->time, source);
+ handleButtonReleaseEvent(event_x, event_y, root_x, root_y, ev->detail, modifiers, ev->time, QEvent::MouseButtonRelease, source);
break;
case XI_Motion:
if (Q_UNLIKELY(lcQpaXInputEvents().isDebugEnabled()))
qCDebug(lcQpaXInputEvents, "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);
+ handleMotionNotifyEvent(event_x, event_y, root_x, root_y, modifiers, ev->time, QEvent::MouseMove, source);
break;
default:
qWarning() << "Unrecognized XI2 mouse event" << ev->evtype;
@@ -2473,10 +2434,13 @@ 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, Qt::MouseEventSource source)
+ Qt::KeyboardModifiers modifiers, QEvent::Type type, Qt::MouseEventSource source)
{
connection()->setTime(time);
- QWindowSystemInterface::handleMouseEvent(window(), time, local, global, connection()->buttonState(), modifiers, source);
+ Qt::MouseButton button = type == QEvent::MouseMove ? Qt::NoButton : connection()->button();
+ QWindowSystemInterface::handleMouseEvent(window(), time, local, global,
+ connection()->buttonState(), button,
+ type, modifiers, source);
}
void QXcbWindow::handleEnterNotifyEvent(const xcb_enter_notify_event_t *event)
@@ -2526,7 +2490,7 @@ void QXcbWindow::handlePropertyNotifyEvent(const xcb_property_notify_event_t *ev
m_lastWindowStateEvent = newState;
m_windowState = newState;
if ((m_windowState & Qt::WindowMinimized) && connection()->mouseGrabber() == this)
- connection()->setMouseGrabber(Q_NULLPTR);
+ connection()->setMouseGrabber(nullptr);
}
return;
} else if (event->atom == atom(QXcbAtom::_NET_FRAME_EXTENTS)) {
@@ -2594,7 +2558,10 @@ bool QXcbWindow::setKeyboardGrabEnabled(bool grab)
bool QXcbWindow::setMouseGrabEnabled(bool grab)
{
if (!grab && connection()->mouseGrabber() == this)
- connection()->setMouseGrabber(Q_NULLPTR);
+ connection()->setMouseGrabber(nullptr);
+
+ if (grab && !connection()->canGrab())
+ return false;
#if QT_CONFIG(xinput2)
if (connection()->hasXInput2() && !connection()->xi2MouseEventsDisabled()) {
@@ -2604,8 +2571,6 @@ bool QXcbWindow::setMouseGrabEnabled(bool grab)
return result;
}
#endif
- if (grab && !connection()->canGrab())
- return false;
if (!grab) {
xcb_ungrab_pointer(xcb_connection(), XCB_TIME_CURRENT_TIME);
@@ -2812,6 +2777,15 @@ void QXcbWindow::setOpacity(qreal level)
(uchar *)&value);
}
+QVector<xcb_rectangle_t> qRegionToXcbRectangleList(const QRegion &region)
+{
+ QVector<xcb_rectangle_t> rects;
+ rects.reserve(region.rectCount());
+ for (const QRect &r : region)
+ rects.push_back(qRectToXCBRectangle(r));
+ return rects;
+}
+
void QXcbWindow::setMask(const QRegion &region)
{
if (!connection()->hasXShape())
@@ -2820,10 +2794,7 @@ void QXcbWindow::setMask(const QRegion &region)
xcb_shape_mask(connection()->xcb_connection(), XCB_SHAPE_SO_SET,
XCB_SHAPE_SK_BOUNDING, xcb_window(), 0, 0, XCB_NONE);
} else {
- QVector<xcb_rectangle_t> rects;
- rects.reserve(region.rectCount());
- for (const QRect &r : region)
- rects.push_back(qRectToXCBRectangle(r));
+ const auto rects = qRegionToXcbRectangleList(region);
xcb_shape_rectangles(connection()->xcb_connection(), XCB_SHAPE_SO_SET,
XCB_SHAPE_SK_BOUNDING, XCB_CLIP_ORDERING_UNSORTED,
xcb_window(), 0, 0, rects.size(), &rects[0]);
diff --git a/src/plugins/platforms/xcb/qxcbwindow.h b/src/plugins/platforms/xcb/qxcbwindow.h
index 1ce9b0a42f..638ab26cea 100644
--- a/src/plugins/platforms/xcb/qxcbwindow.h
+++ b/src/plugins/platforms/xcb/qxcbwindow.h
@@ -146,7 +146,7 @@ public:
QXcbWindow *toWindow() override;
void handleMouseEvent(xcb_timestamp_t time, const QPoint &local, const QPoint &global,
- Qt::KeyboardModifiers modifiers, Qt::MouseEventSource source);
+ Qt::KeyboardModifiers modifiers, QEvent::Type type, Qt::MouseEventSource source);
void updateNetWmUserTime(xcb_timestamp_t timestamp);
@@ -188,6 +188,7 @@ public Q_SLOTS:
protected:
virtual void resolveFormat(const QSurfaceFormat &format) { m_format = format; }
virtual const xcb_visualtype_t *createVisual();
+ void setImageFormatForVisual(const xcb_visualtype_t *visual);
QXcbScreen *parentScreen();
@@ -220,13 +221,16 @@ 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, Qt::MouseEventSource source = Qt::MouseEventNotSynthesized);
+ int detail, Qt::KeyboardModifiers modifiers, xcb_timestamp_t timestamp,
+ QEvent::Type type, 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, Qt::MouseEventSource source = Qt::MouseEventNotSynthesized);
+ int detail, Qt::KeyboardModifiers modifiers, xcb_timestamp_t timestamp,
+ QEvent::Type type, 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::MouseEventSource source = Qt::MouseEventNotSynthesized);
+ Qt::KeyboardModifiers modifiers, xcb_timestamp_t timestamp,
+ QEvent::Type type, 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);
@@ -292,6 +296,8 @@ protected:
void create() override {} // No-op
};
+QVector<xcb_rectangle_t> qRegionToXcbRectangleList(const QRegion &region);
+
QT_END_NAMESPACE
Q_DECLARE_METATYPE(QXcbWindow*)
diff --git a/src/plugins/platforms/xcb/xcb-plugin.pro b/src/plugins/platforms/xcb/xcb-plugin.pro
index 01d493156d..a2c56a3dcf 100644
--- a/src/plugins/platforms/xcb/xcb-plugin.pro
+++ b/src/plugins/platforms/xcb/xcb-plugin.pro
@@ -4,6 +4,8 @@ QT += core-private gui-private xcb_qpa_lib-private
DEFINES += QT_NO_FOREACH
+macos: CONFIG += no_app_extension_api_only
+
SOURCES = \
qxcbmain.cpp
OTHER_FILES += xcb.json README