summaryrefslogtreecommitdiffstats
path: root/src/plugins/platforms/xcb/qxcbwindow.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/plugins/platforms/xcb/qxcbwindow.cpp')
-rw-r--r--src/plugins/platforms/xcb/qxcbwindow.cpp493
1 files changed, 317 insertions, 176 deletions
diff --git a/src/plugins/platforms/xcb/qxcbwindow.cpp b/src/plugins/platforms/xcb/qxcbwindow.cpp
index c0076a9977..3188a7f19d 100644
--- a/src/plugins/platforms/xcb/qxcbwindow.cpp
+++ b/src/plugins/platforms/xcb/qxcbwindow.cpp
@@ -1,7 +1,7 @@
/****************************************************************************
**
-** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
-** Contact: http://www.qt-project.org/legal
+** Copyright (C) 2015 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
**
** This file is part of the plugins of the Qt Toolkit.
**
@@ -10,9 +10,9 @@
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and Digia. For licensing terms and
-** conditions see http://qt.digia.com/licensing. For further information
-** use the contact form at http://qt.digia.com/contact-us.
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
@@ -23,8 +23,8 @@
** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
-** In addition, as a special exception, Digia gives you certain additional
-** rights. These rights are described in the Digia Qt LGPL Exception
+** As a special exception, The Qt Company gives you certain additional
+** rights. These rights are described in The Qt Company LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** $QT_END_LICENSE$
@@ -86,6 +86,7 @@
#include <qpa/qplatformbackingstore.h>
#include <qpa/qwindowsysteminterface.h>
+#include <QTextCodec>
#include <stdio.h>
#ifdef XCB_USE_XLIB
@@ -97,15 +98,6 @@
#include <X11/extensions/XInput2.h>
#endif
-#if defined(XCB_USE_GLX)
-#include "qglxintegration.h"
-#include <QtPlatformSupport/private/qglxconvenience_p.h>
-#elif defined(XCB_USE_EGL)
-#include "qxcbeglsurface.h"
-#include <QtPlatformSupport/private/qeglconvenience_p.h>
-#include <QtPlatformSupport/private/qxlibeglintegration_p.h>
-#endif
-
#define XCOORD_MAX 16383
enum {
defaultWindowWidth = 160,
@@ -146,7 +138,7 @@ enum QX11EmbedMessageType {
const quint32 XEMBED_VERSION = 0;
-static inline QRect mapToNative(const QRect &qtRect, int dpr)
+static inline QRect mapLocalGeometryToNative(const QRect &qtRect, int dpr)
{
return QRect(qtRect.x() * dpr, qtRect.y() * dpr, qtRect.width() * dpr, qtRect.height() * dpr);
}
@@ -164,14 +156,53 @@ static inline QPoint dpr_ceil(const QPoint &p, int dpr)
return QPoint((p.x() + dpr - 1) / dpr, (p.y() + dpr - 1) / dpr);
}
+static inline QSize dpr_ceil(const QSize &s, int dpr)
+{
+ return QSize((s.width() + dpr - 1) / dpr, (s.height() + dpr - 1) / dpr);
+}
+
static inline QRect mapExposeFromNative(const QRect &xRect, int dpr)
{
return QRect(dpr_floor(xRect.topLeft(), dpr), dpr_ceil(xRect.bottomRight(), dpr));
}
-static inline QRect mapGeometryFromNative(const QRect &xRect, int dpr)
+static inline QRect mapLocalGeometryFromNative(const QRect &xRect, int dpr)
{
- return QRect(xRect.topLeft() / dpr, xRect.bottomRight() / dpr);
+ return QRect(xRect.topLeft() / dpr, dpr_ceil(xRect.size(), dpr));
+}
+
+QXcbScreen *QXcbWindow::parentScreen()
+{
+ return parent() ? static_cast<QXcbWindow*>(parent())->parentScreen() : m_xcbScreen;
+}
+
+QPoint QXcbWindow::mapToNative(const QPoint &pos, const QXcbScreen *screen) const
+{
+ if (parent())
+ return pos * int(screen->devicePixelRatio());
+ else
+ return screen->mapToNative(pos);
+}
+QPoint QXcbWindow::mapFromNative(const QPoint &pos, const QXcbScreen *screen) const
+{
+ if (parent())
+ return pos / int(screen->devicePixelRatio());
+ else
+ return screen->mapFromNative(pos);
+}
+QRect QXcbWindow::mapToNative(const QRect &rect, const QXcbScreen *screen) const
+{
+ if (parent())
+ return mapLocalGeometryToNative(rect, int(screen->devicePixelRatio()));
+ else
+ return screen->mapToNative(rect);
+}
+QRect QXcbWindow::mapFromNative(const QRect &rect, const QXcbScreen *screen) const
+{
+ if (parent())
+ return mapLocalGeometryFromNative(rect, int(screen->devicePixelRatio()));
+ else
+ return screen->mapFromNative(rect);
}
// Returns \c true if we should set WM_TRANSIENT_FOR on \a w
@@ -186,8 +217,10 @@ static inline bool isTransient(const QWindow *w)
|| w->type() == Qt::Popup;
}
-static inline QImage::Format imageFormatForVisual(int depth, quint32 red_mask, quint32 blue_mask)
+static inline QImage::Format imageFormatForVisual(int depth, quint32 red_mask, quint32 blue_mask, bool *rgbSwap)
{
+ if (rgbSwap)
+ *rgbSwap = false;
switch (depth) {
case 32:
if (blue_mask == 0xff)
@@ -196,6 +229,11 @@ static inline QImage::Format imageFormatForVisual(int depth, quint32 red_mask, q
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)
@@ -206,6 +244,11 @@ static inline QImage::Format imageFormatForVisual(int depth, quint32 red_mask, q
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)
@@ -235,11 +278,54 @@ static inline bool positionIncludesFrame(QWindow *w)
return qt_window_private(w)->positionPolicy == QWindowPrivate::WindowFrameInclusive;
}
+#ifdef XCB_USE_XLIB
+static inline XTextProperty* qstringToXTP(Display *dpy, const QString& s)
+{
+ #include <X11/Xatom.h>
+
+ static XTextProperty tp = { 0, 0, 0, 0 };
+ static bool free_prop = true; // we can't free tp.value in case it references
+ // the data of the static QByteArray below.
+ if (tp.value) {
+ if (free_prop)
+ XFree(tp.value);
+ tp.value = 0;
+ free_prop = true;
+ }
+
+ static const QTextCodec* mapper = QTextCodec::codecForLocale();
+ int errCode = 0;
+ if (mapper) {
+ QByteArray mapped = mapper->fromUnicode(s);
+ char* tl[2];
+ tl[0] = mapped.data();
+ tl[1] = 0;
+ errCode = XmbTextListToTextProperty(dpy, tl, 1, XStdICCTextStyle, &tp);
+ if (errCode < 0)
+ qDebug("XmbTextListToTextProperty result code %d", errCode);
+ }
+ if (!mapper || errCode < 0) {
+ mapper = QTextCodec::codecForName("latin1");
+ if (!mapper || !mapper->canEncode(s))
+ return Q_NULLPTR;
+ static QByteArray qcs;
+ qcs = s.toLatin1();
+ tp.value = (uchar*)qcs.data();
+ tp.encoding = XA_STRING;
+ tp.format = 8;
+ tp.nitems = qcs.length();
+ free_prop = false;
+ }
+ return &tp;
+}
+#endif // XCB_USE_XLIB
+
static const char *wm_window_type_property_id = "_q_xcb_wm_window_type";
QXcbWindow::QXcbWindow(QWindow *window)
: QPlatformWindow(window)
, m_window(0)
+ , m_xcbScreen(0)
, m_syncCounter(0)
, m_gravity(XCB_GRAVITY_STATIC)
, m_mapped(false)
@@ -250,21 +336,11 @@ QXcbWindow::QXcbWindow(QWindow *window)
, m_alertState(false)
, m_netWmUserTimeWindow(XCB_NONE)
, m_dirtyFrameMargins(false)
-#if defined(XCB_USE_EGL)
- , m_eglSurface(0)
-#endif
, m_lastWindowStateEvent(-1)
, m_syncState(NoSyncNeeded)
, m_pendingSyncRequest(0)
{
- m_screen = static_cast<QXcbScreen *>(window->screen()->handle());
-
- setConnection(m_screen->connection());
-
- if (window->type() != Qt::ForeignWindow)
- create();
- else
- m_window = window->winId();
+ setConnection(xcbScreen()->connection());
}
#ifdef Q_COMPILER_CLASS_ENUM
@@ -290,6 +366,11 @@ enum {
void QXcbWindow::create()
{
+ if (window()->type() == Qt::ForeignWindow) {
+ m_window = window()->winId();
+ return;
+ }
+
destroy();
m_deferredExpose = false;
@@ -298,12 +379,26 @@ void QXcbWindow::create()
Qt::WindowType type = window()->type();
+ QXcbScreen *currentScreen = xcbScreen();
+ QRect rect = window()->geometry();
+ QXcbScreen *platformScreen = parent() ? parentScreen() : static_cast<QXcbScreen*>(screenForGeometry(rect));
+
+ m_xcbScreen = platformScreen;
if (type == Qt::Desktop) {
- m_window = m_screen->root();
- m_depth = m_screen->screen()->root_depth;
- m_visualId = m_screen->screen()->root_visual;
- const xcb_visualtype_t *visual = m_screen->visualForId(m_visualId);
- m_imageFormat = imageFormatForVisual(m_depth, visual->red_mask, visual->blue_mask);
+ m_window = platformScreen->root();
+ m_depth = platformScreen->screen()->root_depth;
+ m_visualId = platformScreen->screen()->root_visual;
+ const xcb_visualtype_t *visual = 0;
+ if (connection()->hasDefaultVisualId()) {
+ visual = platformScreen->visualForId(connection()->defaultVisualId());
+ if (visual)
+ m_visualId = connection()->defaultVisualId();
+ if (!visual)
+ qWarning() << "Could not use default visual id. Falling back to root_visual for screen.";
+ }
+ if (!visual)
+ visual = platformScreen->visualForId(m_visualId);
+ m_imageFormat = imageFormatForVisual(m_depth, visual->red_mask, visual->blue_mask, &m_imageRgbSwap);
connection()->addWindowEventListener(m_window, this);
return;
}
@@ -323,8 +418,11 @@ void QXcbWindow::create()
// Parameters to XCreateWindow() are frame corner + inner size.
// This fits in case position policy is frame inclusive. There is
// currently no way to implement it for frame-exclusive geometries.
- QRect rect = window()->geometry();
QPlatformWindow::setGeometry(rect);
+
+ if (platformScreen != currentScreen)
+ QWindowSystemInterface::handleWindowScreenChanged(window(), platformScreen->QPlatformScreen::screen());
+
const int dpr = int(devicePixelRatio());
QSize minimumSize = window()->minimumSize();
@@ -338,7 +436,7 @@ void QXcbWindow::create()
rect.setHeight(defaultWindowHeight);
}
- xcb_window_t xcb_parent_id = m_screen->root();
+ xcb_window_t xcb_parent_id = platformScreen->root();
if (parent()) {
xcb_parent_id = static_cast<QXcbWindow *>(parent())->xcb_window();
m_embedded = parent()->window()->type() == Qt::ForeignWindow;
@@ -348,27 +446,17 @@ void QXcbWindow::create()
window()->setFormat(parentFormat);
}
}
- m_format = window()->requestedFormat();
-#if (defined(XCB_USE_GLX) || defined(XCB_USE_EGL)) && defined(XCB_USE_XLIB)
+ resolveFormat();
+
+#ifdef XCB_USE_XLIB
if (QGuiApplicationPrivate::platformIntegration()->hasCapability(QPlatformIntegration::OpenGL)) {
-#if defined(XCB_USE_GLX)
- XVisualInfo *visualInfo = qglx_findVisualInfo(DISPLAY_FROM_XCB(m_screen), m_screen->screenNumber(), &m_format);
-#elif defined(XCB_USE_EGL)
- EGLDisplay eglDisplay = connection()->egl_display();
- EGLConfig eglConfig = q_configFromGLFormat(eglDisplay, m_format, true);
- m_format = q_glFormatFromConfig(eglDisplay, eglConfig, m_format);
-
- VisualID id = QXlibEglIntegration::getCompatibleVisualId(DISPLAY_FROM_XCB(this), eglDisplay, eglConfig);
-
- XVisualInfo visualInfoTemplate;
- memset(&visualInfoTemplate, 0, sizeof(XVisualInfo));
- visualInfoTemplate.visualid = id;
-
- XVisualInfo *visualInfo;
- int matchingCount = 0;
- visualInfo = XGetVisualInfo(DISPLAY_FROM_XCB(this), VisualIDMask, &visualInfoTemplate, &matchingCount);
-#endif //XCB_USE_GLX
+ XVisualInfo *visualInfo = Q_NULLPTR;
+ if (connection()->hasDefaultVisualId())
+ visualInfo = CREATE_VISUALINFO_FROM_DEFAULT_VISUALID(this);
+ if (!visualInfo)
+ visualInfo = static_cast<XVisualInfo *>(createVisual());
+
if (!visualInfo && window()->surfaceType() == QSurface::OpenGLSurface)
qFatal("Could not initialize OpenGL");
@@ -376,19 +464,20 @@ void QXcbWindow::create()
qWarning("Could not initialize OpenGL for RasterGLSurface, reverting to RasterSurface.");
window()->setSurfaceType(QSurface::RasterSurface);
}
+
if (visualInfo) {
m_depth = visualInfo->depth;
- m_imageFormat = imageFormatForVisual(visualInfo->depth, visualInfo->red_mask, visualInfo->blue_mask);
+ m_imageFormat = imageFormatForVisual(visualInfo->depth, visualInfo->red_mask, visualInfo->blue_mask, &m_imageRgbSwap);
Colormap cmap = XCreateColormap(DISPLAY_FROM_XCB(this), xcb_parent_id, visualInfo->visual, AllocNone);
XSetWindowAttributes a;
- a.background_pixel = WhitePixel(DISPLAY_FROM_XCB(this), m_screen->screenNumber());
- a.border_pixel = BlackPixel(DISPLAY_FROM_XCB(this), m_screen->screenNumber());
+ a.background_pixel = WhitePixel(DISPLAY_FROM_XCB(this), platformScreen->screenNumber());
+ a.border_pixel = BlackPixel(DISPLAY_FROM_XCB(this), platformScreen->screenNumber());
a.colormap = cmap;
m_visualId = visualInfo->visualid;
- const QRect xRect = mapToNative(rect, dpr);
+ const QRect xRect = mapToNative(rect, platformScreen);
m_window = XCreateWindow(DISPLAY_FROM_XCB(this), xcb_parent_id, xRect.x(), xRect.y(), xRect.width(), xRect.height(),
0, visualInfo->depth, InputOutput, visualInfo->visual,
@@ -397,50 +486,65 @@ void QXcbWindow::create()
XFree(visualInfo);
}
}
+#endif
if (!m_window)
-#endif //defined(XCB_USE_GLX) || defined(XCB_USE_EGL)
{
m_window = xcb_generate_id(xcb_connection());
- m_visualId = m_screen->screen()->root_visual;
- m_depth = m_screen->screen()->root_depth;
+ m_visualId = UINT_MAX;
+ const xcb_visualtype_t *visual = Q_NULLPTR;
+ m_depth = platformScreen->screen()->root_depth;
uint32_t mask = 0;
uint32_t values[3];
- if (m_format.alphaBufferSize() == 8) {
- xcb_depth_iterator_t depthIter = xcb_screen_allowed_depths_iterator(m_screen->screen());
- while (depthIter.rem) {
- if (depthIter.data->depth == 32) {
- xcb_visualtype_iterator_t visualIter = xcb_depth_visuals_iterator(depthIter.data);
- if (visualIter.rem) {
- m_visualId = visualIter.data->visual_id;
- m_depth = 32;
- uint32_t colormap = xcb_generate_id(xcb_connection());
- xcb_create_colormap(xcb_connection(), XCB_COLORMAP_ALLOC_NONE, colormap,
- xcb_parent_id, m_visualId);
- mask |= XCB_CW_BACK_PIXEL | XCB_CW_BORDER_PIXEL | XCB_CW_COLORMAP;
- values[0] = m_screen->screen()->white_pixel;
- values[1] = m_screen->screen()->black_pixel;
- values[2] = colormap;
- break;
+ if (connection()->hasDefaultVisualId()) {
+ m_visualId = connection()->defaultVisualId();
+ visual = platformScreen->visualForId(m_visualId);
+ }
+
+ if (!visual) {
+ if (connection()->hasDefaultVisualId())
+ qWarning("Failed to use default visual id. Falling back to using screens root_visual");
+
+ m_visualId = platformScreen->screen()->root_visual;
+
+ if (m_format.alphaBufferSize() == 8) {
+ xcb_depth_iterator_t depthIter = xcb_screen_allowed_depths_iterator(platformScreen->screen());
+ while (depthIter.rem) {
+ if (depthIter.data->depth == 32) {
+ xcb_visualtype_iterator_t visualIter = xcb_depth_visuals_iterator(depthIter.data);
+ if (visualIter.rem) {
+ m_visualId = visualIter.data->visual_id;
+ m_depth = 32;
+ uint32_t colormap = xcb_generate_id(xcb_connection());
+ xcb_create_colormap(xcb_connection(), XCB_COLORMAP_ALLOC_NONE, colormap,
+ xcb_parent_id, m_visualId);
+ mask |= XCB_CW_BACK_PIXEL | XCB_CW_BORDER_PIXEL | XCB_CW_COLORMAP;
+ values[0] = platformScreen->screen()->white_pixel;
+ values[1] = platformScreen->screen()->black_pixel;
+ values[2] = colormap;
+ break;
+ }
}
+ xcb_depth_next(&depthIter);
}
- xcb_depth_next(&depthIter);
}
+
+ visual = platformScreen->visualForId(m_visualId);
}
- const xcb_visualtype_t *visual = m_screen->visualForId(m_visualId);
- m_imageFormat = imageFormatForVisual(m_depth, visual->red_mask, visual->blue_mask);
+ m_imageFormat = imageFormatForVisual(m_depth, visual->red_mask, visual->blue_mask, &m_imageRgbSwap);
+ const QRect xRect = mapToNative(rect, platformScreen);
Q_XCB_CALL(xcb_create_window(xcb_connection(),
m_depth,
m_window, // window id
xcb_parent_id, // parent window id
- rect.x(),
- rect.y(),
- rect.width(),
- rect.height(),
+ xRect.x(),
+ xRect.y(),
+ xRect.width(),
+ xRect.height(),
0, // border width
XCB_WINDOW_CLASS_INPUT_OUTPUT, // window class
m_visualId, // visual
@@ -460,12 +564,10 @@ void QXcbWindow::create()
properties[propertyCount++] = atom(QXcbAtom::WM_TAKE_FOCUS);
properties[propertyCount++] = atom(QXcbAtom::_NET_WM_PING);
- m_usingSyncProtocol = m_screen->syncRequestSupported();
-#if !defined(XCB_USE_GLX)
- // synced resize only implemented on GLX
- if (window()->supportsOpenGL())
+ if (platformScreen->syncRequestSupported())
+ m_usingSyncProtocol = supportsSyncProtocol();
+ else
m_usingSyncProtocol = false;
-#endif
if (m_usingSyncProtocol)
properties[propertyCount++] = atom(QXcbAtom::_NET_WM_SYNC_REQUEST);
@@ -484,7 +586,7 @@ void QXcbWindow::create()
m_syncValue.hi = 0;
m_syncValue.lo = 0;
- const QByteArray wmClass = static_cast<QXcbIntegration *>(QGuiApplicationPrivate::platformIntegration())->wmClass();
+ const QByteArray wmClass = QXcbIntegration::instance()->wmClass();
if (!wmClass.isEmpty()) {
Q_XCB_CALL(xcb_change_property(xcb_connection(), XCB_PROP_MODE_REPLACE,
m_window, atom(QXcbAtom::WM_CLASS),
@@ -519,7 +621,7 @@ void QXcbWindow::create()
xcb_set_wm_hints(xcb_connection(), m_window, &hints);
- xcb_window_t leader = m_screen->clientLeader();
+ xcb_window_t leader = platformScreen->clientLeader();
Q_XCB_CALL(xcb_change_property(xcb_connection(), XCB_PROP_MODE_REPLACE, m_window,
atom(QXcbAtom::WM_CLIENT_LEADER), XCB_ATOM_WINDOW, 32,
1, &leader));
@@ -545,7 +647,7 @@ void QXcbWindow::create()
#ifdef XCB_USE_XLIB
// force sync to read outstanding requests - see QTBUG-29106
- XSync(DISPLAY_FROM_XCB(m_screen), false);
+ XSync(DISPLAY_FROM_XCB(platformScreen), false);
#endif
#ifndef QT_NO_DRAGANDDROP
@@ -587,24 +689,37 @@ void QXcbWindow::destroy()
}
m_mapped = false;
-#if defined(XCB_USE_EGL)
- delete m_eglSurface;
- m_eglSurface = 0;
-#endif
-
if (m_pendingSyncRequest)
m_pendingSyncRequest->invalidate();
}
+void QXcbWindow::maybeSetScreen(QXcbScreen *screen)
+{
+ if (!window()->screen() && screen->geometry().contains(geometry().topLeft())) {
+ QWindowSystemInterface::handleWindowScreenChanged(window(), static_cast<QPlatformScreen *>(screen)->screen());
+ QWindowSystemInterface::handleExposeEvent(window(), QRegion(QRect(QPoint(0, 0), window()->size())));
+ }
+}
+
void QXcbWindow::setGeometry(const QRect &rect)
{
QPlatformWindow::setGeometry(rect);
propagateSizeHints();
- const QRect xRect = mapToNative(rect, int(devicePixelRatio()));
+ QXcbScreen *currentScreen = xcbScreen();
+ QXcbScreen *newScreen = parent() ? parentScreen() : static_cast<QXcbScreen*>(screenForGeometry(rect));
+
+ if (!newScreen)
+ newScreen = currentScreen;
+
+ m_xcbScreen = newScreen;
+ const QRect xRect = mapToNative(rect, newScreen);
const QRect wmGeometry = windowToWmGeometry(xRect);
+ if (newScreen != currentScreen)
+ QWindowSystemInterface::handleWindowScreenChanged(window(), newScreen->QPlatformScreen::screen());
+
if (qt_window_private(window())->positionAutomatic) {
const quint32 mask = XCB_CONFIG_WINDOW_WIDTH | XCB_CONFIG_WINDOW_HEIGHT;
const qint32 values[] = {
@@ -742,7 +857,7 @@ void QXcbWindow::show()
// Default to client leader if there is no transient parent, else modal dialogs can
// be hidden by their parents.
if (!transientXcbParent)
- transientXcbParent = static_cast<QXcbScreen *>(screen())->clientLeader();
+ transientXcbParent = xcbScreen()->clientLeader();
if (transientXcbParent) { // ICCCM 4.1.2.6
Q_XCB_CALL(xcb_change_property(xcb_connection(), XCB_PROP_MODE_REPLACE, m_window,
XCB_ATOM_WM_TRANSIENT_FOR, XCB_ATOM_WINDOW, 32,
@@ -773,7 +888,7 @@ void QXcbWindow::show()
if (QGuiApplication::modalWindow() == window())
requestActivateWindow();
- m_screen->windowShown(this);
+ xcbScreen()->windowShown(this);
connection()->sync();
}
@@ -783,13 +898,15 @@ void QXcbWindow::hide()
Q_XCB_CALL(xcb_unmap_window(xcb_connection(), m_window));
// send synthetic UnmapNotify event according to icccm 4.1.4
- xcb_unmap_notify_event_t event;
- event.response_type = XCB_UNMAP_NOTIFY;
- event.event = m_screen->root();
- event.window = m_window;
- event.from_configure = false;
- Q_XCB_CALL(xcb_send_event(xcb_connection(), false, m_screen->root(),
- XCB_EVENT_MASK_SUBSTRUCTURE_NOTIFY | XCB_EVENT_MASK_SUBSTRUCTURE_REDIRECT, (const char *)&event));
+ if (xcbScreen()) {
+ xcb_unmap_notify_event_t event;
+ event.response_type = XCB_UNMAP_NOTIFY;
+ event.event = xcbScreen()->root();
+ event.window = m_window;
+ event.from_configure = false;
+ Q_XCB_CALL(xcb_send_event(xcb_connection(), false, xcbScreen()->root(),
+ XCB_EVENT_MASK_SUBSTRUCTURE_NOTIFY | XCB_EVENT_MASK_SUBSTRUCTURE_REDIRECT, (const char *)&event));
+ }
xcb_flush(xcb_connection());
@@ -1108,7 +1225,9 @@ void QXcbWindow::changeNetWmState(bool set, xcb_atom_t one, xcb_atom_t two)
event.data.data32[3] = 0;
event.data.data32[4] = 0;
- Q_XCB_CALL(xcb_send_event(xcb_connection(), 0, m_screen->root(), XCB_EVENT_MASK_STRUCTURE_NOTIFY | XCB_EVENT_MASK_SUBSTRUCTURE_REDIRECT, (const char *)&event));
+ if (!xcbScreen())
+ return;
+ Q_XCB_CALL(xcb_send_event(xcb_connection(), 0, xcbScreen()->root(), XCB_EVENT_MASK_STRUCTURE_NOTIFY | XCB_EVENT_MASK_SUBSTRUCTURE_REDIRECT, (const char *)&event));
}
void QXcbWindow::setWindowState(Qt::WindowState state)
@@ -1149,7 +1268,7 @@ void QXcbWindow::setWindowState(Qt::WindowState state)
event.data.data32[3] = 0;
event.data.data32[4] = 0;
- Q_XCB_CALL(xcb_send_event(xcb_connection(), 0, m_screen->root(), XCB_EVENT_MASK_STRUCTURE_NOTIFY | XCB_EVENT_MASK_SUBSTRUCTURE_REDIRECT, (const char *)&event));
+ Q_XCB_CALL(xcb_send_event(xcb_connection(), 0, xcbScreen()->root(), XCB_EVENT_MASK_STRUCTURE_NOTIFY | XCB_EVENT_MASK_SUBSTRUCTURE_REDIRECT, (const char *)&event));
}
break;
case Qt::WindowMaximized:
@@ -1392,7 +1511,9 @@ void QXcbWindow::setParent(const QPlatformWindow *parent)
xcb_parent_id = qXcbParent->xcb_window();
m_embedded = qXcbParent->window()->type() == Qt::ForeignWindow;
} else {
- xcb_parent_id = m_screen->root();
+ if (!xcbScreen())
+ return;
+ xcb_parent_id = xcbScreen()->root();
m_embedded = false;
}
Q_XCB_CALL(xcb_reparent_window(xcb_connection(), xcb_window(), xcb_parent_id, topLeft.x(), topLeft.y()));
@@ -1410,6 +1531,12 @@ void QXcbWindow::setWindowTitle(const QString &title)
8,
ba.length(),
ba.constData()));
+
+#ifdef XCB_USE_XLIB
+ XTextProperty *text = qstringToXTP(DISPLAY_FROM_XCB(this), title);
+ if (text)
+ XSetWMName(DISPLAY_FROM_XCB(this), m_window, text);
+#endif
xcb_flush(xcb_connection());
}
@@ -1494,7 +1621,7 @@ void QXcbWindow::propagateSizeHints()
memset(&hints, 0, sizeof(hints));
const int dpr = int(devicePixelRatio());
- const QRect xRect = mapToNative(windowToWmGeometry(geometry()), dpr);
+ const QRect xRect = windowToWmGeometry(mapToNative(geometry(), xcbScreen()));
QWindow *win = window();
@@ -1560,7 +1687,7 @@ void QXcbWindow::requestActivateWindow()
event.data.data32[3] = 0;
event.data.data32[4] = 0;
- Q_XCB_CALL(xcb_send_event(xcb_connection(), 0, m_screen->root(), XCB_EVENT_MASK_STRUCTURE_NOTIFY | XCB_EVENT_MASK_SUBSTRUCTURE_REDIRECT, (const char *)&event));
+ Q_XCB_CALL(xcb_send_event(xcb_connection(), 0, xcbScreen()->root(), XCB_EVENT_MASK_STRUCTURE_NOTIFY | XCB_EVENT_MASK_SUBSTRUCTURE_REDIRECT, (const char *)&event));
} else {
Q_XCB_CALL(xcb_set_input_focus(xcb_connection(), XCB_INPUT_FOCUS_PARENT, m_window, connection()->time()));
}
@@ -1570,25 +1697,9 @@ void QXcbWindow::requestActivateWindow()
QSurfaceFormat QXcbWindow::format() const
{
- // ### return actual format
return m_format;
}
-#if defined(XCB_USE_EGL)
-QXcbEGLSurface *QXcbWindow::eglSurface() const
-{
- if (!m_eglSurface) {
- EGLDisplay display = connection()->egl_display();
- EGLConfig config = q_configFromGLFormat(display, window()->requestedFormat(), true);
- EGLSurface surface = eglCreateWindowSurface(display, config, (EGLNativeWindowType)m_window, 0);
-
- m_eglSurface = new QXcbEGLSurface(display, surface);
- }
-
- return m_eglSurface;
-}
-#endif
-
void QXcbWindow::setWmWindowTypeStatic(QWindow *window, QXcbWindowFunctions::WmWindowTypes windowTypes)
{
if (window->handle())
@@ -1597,6 +1708,13 @@ void QXcbWindow::setWmWindowTypeStatic(QWindow *window, QXcbWindowFunctions::WmW
window->setProperty(wm_window_type_property_id, QVariant::fromValue(static_cast<int>(windowTypes)));
}
+uint QXcbWindow::visualIdStatic(QWindow *window)
+{
+ if (window && window->handle())
+ return static_cast<QXcbWindow *>(window->handle())->visualId();
+ return UINT_MAX;
+}
+
QXcbWindowFunctions::WmWindowTypes QXcbWindow::wmWindowTypes() const
{
QXcbWindowFunctions::WmWindowTypes result(0);
@@ -1797,15 +1915,15 @@ void QXcbWindow::handleClientMessageEvent(const xcb_client_message_event_t *even
relayFocusToModalWindow();
return;
} else if (event->data.data32[0] == atom(QXcbAtom::_NET_WM_PING)) {
- if (event->window == m_screen->root())
+ if (event->window == xcbScreen()->root())
return;
xcb_client_message_event_t reply = *event;
reply.response_type = XCB_CLIENT_MESSAGE;
- reply.window = m_screen->root();
+ reply.window = xcbScreen()->root();
- xcb_send_event(xcb_connection(), 0, m_screen->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)) {
connection()->setTime(event->data.data32[1]);
@@ -1848,18 +1966,21 @@ void QXcbWindow::handleClientMessageEvent(const xcb_client_message_event_t *even
}
}
-// Temporary workaround for bug in QPlatformScreen::screenForNativeGeometry
+// Temporary workaround for bug in QPlatformScreen::screenForGeometry
// we need the native geometries to detect our screen, but that's not
// available in cross-platform code. Will be fixed properly when highDPI
// support is refactored to expose the native coordinate system.
-QPlatformScreen *QXcbWindow::screenForNativeGeometry(const QRect &newGeometry) const
+QXcbScreen *QXcbWindow::screenForNativeGeometry(const QRect &newGeometry) const
{
- QXcbScreen *currentScreen = static_cast<QXcbScreen*>(screen());
- if (!parent() && !currentScreen->nativeGeometry().intersects(newGeometry)) {
+ QXcbScreen *currentScreen = xcbScreen();
+ if (!currentScreen && QGuiApplication::primaryScreen())
+ currentScreen = static_cast<QXcbScreen*>(QGuiApplication::primaryScreen()->handle());
+ if (currentScreen && !parent() && !currentScreen->nativeGeometry().intersects(newGeometry)) {
Q_FOREACH (QPlatformScreen* screen, currentScreen->virtualSiblings()) {
- if (static_cast<QXcbScreen*>(screen)->nativeGeometry().intersects(newGeometry))
- return screen;
+ QXcbScreen *xcbScreen = static_cast<QXcbScreen*>(screen);
+ if (xcbScreen->nativeGeometry().intersects(newGeometry))
+ return xcbScreen;
}
}
return currentScreen;
@@ -1869,10 +1990,10 @@ void QXcbWindow::handleConfigureNotifyEvent(const xcb_configure_notify_event_t *
{
bool fromSendEvent = (event->response_type & 0x80);
QPoint pos(event->x, event->y);
- if (!parent() && !fromSendEvent) {
+ if (!parent() && !fromSendEvent && xcbScreen()) {
// Do not trust the position, query it instead.
xcb_translate_coordinates_cookie_t cookie = xcb_translate_coordinates(xcb_connection(), xcb_window(),
- m_screen->root(), 0, 0);
+ xcbScreen()->root(), 0, 0);
xcb_translate_coordinates_reply_t *reply = xcb_translate_coordinates_reply(xcb_connection(), cookie, NULL);
if (reply) {
pos.setX(reply->dst_x);
@@ -1881,24 +2002,19 @@ void QXcbWindow::handleConfigureNotifyEvent(const xcb_configure_notify_event_t *
}
}
- const int dpr = devicePixelRatio();
const QRect nativeRect = QRect(pos, QSize(event->width, event->height));
- const QRect rect = mapGeometryFromNative(nativeRect, dpr);
+ QXcbScreen *newScreen = parent() ? parentScreen() : screenForNativeGeometry(nativeRect);
+
+ QXcbScreen *currentScreen = m_xcbScreen;
+ m_xcbScreen = newScreen;
+ if (!newScreen)
+ return;
+ const QRect rect = mapFromNative(nativeRect, newScreen);
QPlatformWindow::setGeometry(rect);
QWindowSystemInterface::handleGeometryChange(window(), rect);
-
- QPlatformScreen *newScreen = screenForNativeGeometry(nativeRect);
- if (newScreen != m_screen) {
- m_screen = static_cast<QXcbScreen*>(newScreen);
- QWindowSystemInterface::handleWindowScreenChanged(window(), newScreen->screen());
- int newDpr = devicePixelRatio();
- if (newDpr != dpr) {
- QRect newRect = mapGeometryFromNative(nativeRect, newDpr);
- QPlatformWindow::setGeometry(newRect);
- QWindowSystemInterface::handleGeometryChange(window(), newRect);
- }
- }
+ if (newScreen != currentScreen)
+ QWindowSystemInterface::handleWindowScreenChanged(window(), newScreen->QPlatformScreen::screen());
m_configureNotifyPending = false;
@@ -1934,17 +2050,17 @@ QPoint QXcbWindow::mapToGlobal(const QPoint &pos) const
const int dpr = int(devicePixelRatio());
QPoint ret;
xcb_translate_coordinates_cookie_t cookie =
- xcb_translate_coordinates(xcb_connection(), xcb_window(), m_screen->root(),
+ xcb_translate_coordinates(xcb_connection(), xcb_window(), xcbScreen()->root(),
pos.x() * dpr, pos.y() * dpr);
xcb_translate_coordinates_reply_t *reply =
xcb_translate_coordinates_reply(xcb_connection(), cookie, NULL);
if (reply) {
- ret.setX(reply->dst_x / dpr);
- ret.setY(reply->dst_y / dpr);
+ ret.setX(reply->dst_x);
+ ret.setY(reply->dst_y);
free(reply);
}
- return ret;
+ return mapFromNative(ret, xcbScreen());
}
QPoint QXcbWindow::mapFromGlobal(const QPoint &pos) const
@@ -1954,9 +2070,10 @@ QPoint QXcbWindow::mapFromGlobal(const QPoint &pos) const
const int dpr = int(devicePixelRatio());
QPoint ret;
+ QPoint xPos = mapToNative(pos, xcbScreen());
xcb_translate_coordinates_cookie_t cookie =
- xcb_translate_coordinates(xcb_connection(), m_screen->root(), xcb_window(),
- pos.x() *dpr, pos.y() * dpr);
+ xcb_translate_coordinates(xcb_connection(), xcbScreen()->root(), xcb_window(),
+ xPos.x(), xPos.y());
xcb_translate_coordinates_reply_t *reply =
xcb_translate_coordinates_reply(xcb_connection(), cookie, NULL);
if (reply) {
@@ -2010,7 +2127,7 @@ void QXcbWindow::handleButtonPressEvent(const xcb_button_press_event_t *event)
}
const int dpr = int(devicePixelRatio());
QPoint local(event->event_x/dpr, event->event_y/dpr);
- QPoint global(event->root_x/dpr, event->root_y/dpr);
+ QPoint global = xcbScreen()->mapFromNative(QPoint(event->root_x, event->root_y));
Qt::KeyboardModifiers modifiers = connection()->keyboard()->translateModifiers(event->state);
@@ -2035,7 +2152,7 @@ void QXcbWindow::handleButtonReleaseEvent(const xcb_button_release_event_t *even
{
const int dpr = int(devicePixelRatio());
QPoint local(event->event_x/dpr, event->event_y/dpr);
- QPoint global(event->root_x/dpr, event->root_y/dpr);
+ QPoint global = xcbScreen()->mapFromNative(QPoint(event->root_x, event->root_y));
Qt::KeyboardModifiers modifiers = connection()->keyboard()->translateModifiers(event->state);
if (event->detail >= 4 && event->detail <= 7) {
@@ -2050,7 +2167,9 @@ void QXcbWindow::handleMotionNotifyEvent(const xcb_motion_notify_event_t *event)
{
const int dpr = int(devicePixelRatio());
QPoint local(event->event_x/dpr, event->event_y/dpr);
- QPoint global(event->root_x/dpr, event->root_y/dpr);
+ if (!xcbScreen())
+ return;
+ QPoint global = xcbScreen()->mapFromNative(QPoint(event->root_x, event->root_y));
Qt::KeyboardModifiers modifiers = connection()->keyboard()->translateModifiers(event->state);
handleMouseEvent(event->time, local, global, modifiers);
@@ -2107,7 +2226,9 @@ void QXcbWindow::handleEnterNotifyEvent(const xcb_enter_notify_event_t *event)
const int dpr = int(devicePixelRatio());
const QPoint local(event->event_x/dpr, event->event_y/dpr);
- const QPoint global(event->root_x/dpr, event->root_y/dpr);
+ if (!xcbScreen())
+ return;
+ QPoint global = xcbScreen()->mapFromNative(QPoint(event->root_x, event->root_y));
QWindowSystemInterface::handleEnterEvent(window(), local, global);
}
@@ -2125,7 +2246,9 @@ void QXcbWindow::handleLeaveNotifyEvent(const xcb_leave_notify_event_t *event)
if (enterWindow) {
const int dpr = int(devicePixelRatio());
QPoint local(enter->event_x/dpr, enter->event_y/dpr);
- QPoint global(enter->root_x/dpr, enter->root_y/dpr);
+ if (!xcbScreen())
+ return;
+ QPoint global = xcbScreen()->mapFromNative(QPoint(event->root_x, event->root_y));
QWindowSystemInterface::handleEnterLeaveEvent(enterWindow->window(), window(), local, global);
} else {
@@ -2140,6 +2263,8 @@ void QXcbWindow::handlePropertyNotifyEvent(const xcb_property_notify_event_t *ev
connection()->setTime(event->time);
const bool propertyDeleted = event->state == XCB_PROPERTY_DELETE;
+ if (!xcbScreen())
+ return;
if (event->atom == atom(QXcbAtom::_NET_WM_STATE) || event->atom == atom(QXcbAtom::WM_STATE)) {
if (propertyDeleted)
@@ -2179,8 +2304,8 @@ void QXcbWindow::handlePropertyNotifyEvent(const xcb_property_notify_event_t *ev
m_windowState = newState;
}
return;
- } else if (event->atom == atom(QXcbAtom::_NET_WORKAREA) && event->window == m_screen->root()) {
- m_screen->updateGeometry(event->time);
+ } else if (event->atom == atom(QXcbAtom::_NET_WORKAREA) && xcbScreen() && event->window == xcbScreen()->root()) {
+ xcbScreen()->updateGeometry(event->time);
}
}
@@ -2288,7 +2413,6 @@ void QXcbWindow::windowEvent(QEvent *event)
bool QXcbWindow::startSystemResize(const QPoint &pos, Qt::Corner corner)
{
- const int dpr = int(devicePixelRatio());
const xcb_atom_t moveResize = connection()->atom(QXcbAtom::_NET_WM_MOVERESIZE);
if (!connection()->wmSupport()->isSupportedByWM(moveResize))
return false;
@@ -2297,7 +2421,7 @@ bool QXcbWindow::startSystemResize(const QPoint &pos, Qt::Corner corner)
xev.type = moveResize;
xev.window = xcb_window();
xev.format = 32;
- const QPoint globalPos = window()->mapToGlobal(pos) * dpr;
+ const QPoint globalPos = mapToNative(window()->mapToGlobal(pos), xcbScreen());
xev.data.data32[0] = globalPos.x();
xev.data.data32[1] = globalPos.y();
const bool bottom = corner == Qt::BottomRightCorner || corner == Qt::BottomLeftCorner;
@@ -2309,7 +2433,7 @@ bool QXcbWindow::startSystemResize(const QPoint &pos, Qt::Corner corner)
xev.data.data32[3] = XCB_BUTTON_INDEX_1;
xev.data.data32[4] = 0;
xcb_ungrab_pointer(connection()->xcb_connection(), XCB_CURRENT_TIME);
- xcb_send_event(connection()->xcb_connection(), false, m_screen->root(),
+ xcb_send_event(connection()->xcb_connection(), false, xcbScreen()->root(),
XCB_EVENT_MASK_SUBSTRUCTURE_REDIRECT | XCB_EVENT_MASK_SUBSTRUCTURE_NOTIFY,
(const char *)&xev);
return true;
@@ -2354,7 +2478,12 @@ void QXcbWindow::handleXEmbedMessage(const xcb_client_message_event_t *event)
break;
case XEMBED_EMBEDDED_NOTIFY:
Q_XCB_CALL(xcb_map_window(xcb_connection(), m_window));
- m_screen->windowShown(this);
+ xcbScreen()->windowShown(this);
+ // Without Qt::WA_TranslucentBackground, we use a ParentRelative BackPixmap.
+ // Clear the whole tray icon window to its background color as early as possible
+ // so that we can get a clean result from grabWindow() later.
+ Q_XCB_CALL(xcb_clear_area(xcb_connection(), false, m_window, 0, 0, geometry().width(), geometry().height()));
+ xcb_flush(xcb_connection());
break;
case XEMBED_FOCUS_IN:
Qt::FocusReason reason;
@@ -2421,7 +2550,7 @@ void QXcbWindow::setMask(const QRegion &region)
const int dpr = devicePixelRatio();
QVector<xcb_rectangle_t> rects;
foreach (const QRect &r, region.rects())
- rects.push_back(qRectToXCBRectangle(mapToNative(r, dpr)));
+ rects.push_back(qRectToXCBRectangle(mapLocalGeometryToNative(r, dpr)));
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]);
@@ -2438,6 +2567,11 @@ void QXcbWindow::setAlertState(bool enabled)
changeNetWmState(enabled, atom(QXcbAtom::_NET_WM_STATE_DEMANDS_ATTENTION));
}
+uint QXcbWindow::visualId() const
+{
+ return m_visualId;
+}
+
bool QXcbWindow::needsSync() const
{
return m_syncState == SyncAndConfigureReceived;
@@ -2445,16 +2579,23 @@ bool QXcbWindow::needsSync() const
void QXcbWindow::postSyncWindowRequest()
{
+ if (!xcbScreen())
+ return;
if (!m_pendingSyncRequest) {
QXcbSyncWindowRequest *e = new QXcbSyncWindowRequest(this);
m_pendingSyncRequest = e;
- QCoreApplication::postEvent(m_screen->connection(), e);
+ QCoreApplication::postEvent(xcbScreen()->connection(), e);
}
}
qreal QXcbWindow::devicePixelRatio() const
{
- return m_screen ? m_screen->devicePixelRatio() : 1.0;
+ return xcbScreen() ? xcbScreen()->devicePixelRatio() : 1.0;
+}
+
+QXcbScreen *QXcbWindow::xcbScreen() const
+{
+ return static_cast<QXcbScreen *>(screen());
}
QT_END_NAMESPACE