File xcb-use-XShape-for-DnD-when-compositing-manager-is-not-running.patch of Package libqt5-qtbase.2170
From e9121328866efa6ba3eb78a991fef785338fd55e Mon Sep 17 00:00:00 2001
From: Alexander Volkov <a.volkov@rusbitech.ru>
Date: Mon, 13 Apr 2015 14:13:34 +0300
Subject: [PATCH] xcb: Use XShape for DnD when a compositing manager is not
running
Otherwise transparent areas of the drag'n'drop pixmap are painted
with the black color.
Task-number: QTBUG-45193
Change-Id: I55b7c7caababe13584fa1c7a52835f112e20f920
Reviewed-by: Lars Knoll <lars.knoll@theqtcompany.com>
---
src/gui/kernel/qshapedpixmapdndwindow.cpp | 13 ++++++--
src/gui/kernel/qshapedpixmapdndwindow_p.h | 2 ++
src/gui/kernel/qsimpledrag.cpp | 3 +-
src/gui/kernel/qsimpledrag_p.h | 4 +++
src/plugins/platforms/xcb/qxcbclipboard.cpp | 24 ++-------------
src/plugins/platforms/xcb/qxcbconnection.cpp | 45 ++++++++++++++++++++++++++--
src/plugins/platforms/xcb/qxcbconnection.h | 4 +++
src/plugins/platforms/xcb/qxcbdrag.cpp | 3 ++
src/plugins/platforms/xcb/qxcbscreen.cpp | 28 +++++++++++++++++
src/plugins/platforms/xcb/qxcbscreen.h | 8 +++++
10 files changed, 106 insertions(+), 28 deletions(-)
diff --git a/src/gui/kernel/qshapedpixmapdndwindow.cpp b/src/gui/kernel/qshapedpixmapdndwindow.cpp
index 5736c41..d77b6dc 100644
--- a/src/gui/kernel/qshapedpixmapdndwindow.cpp
+++ b/src/gui/kernel/qshapedpixmapdndwindow.cpp
@@ -35,12 +35,16 @@
#include <QtGui/QPainter>
#include <QtGui/QCursor>
+#include <QtGui/QGuiApplication>
+#include <QtGui/QPalette>
+#include <QtGui/QBitmap>
QT_BEGIN_NAMESPACE
QShapedPixmapWindow::QShapedPixmapWindow(QScreen *screen)
: QWindow(screen),
- m_backingStore(0)
+ m_backingStore(0),
+ m_useCompositing(true)
{
QSurfaceFormat format;
format.setAlphaBufferSize(8);
@@ -68,7 +72,10 @@ void QShapedPixmapWindow::render()
{
QPainter p(device);
- p.setCompositionMode(QPainter::CompositionMode_Source);
+ if (m_useCompositing)
+ p.setCompositionMode(QPainter::CompositionMode_Source);
+ else
+ p.fillRect(rect, QGuiApplication::palette().base());
p.drawPixmap(0, 0, m_pixmap);
}
@@ -79,6 +86,8 @@ void QShapedPixmapWindow::render()
void QShapedPixmapWindow::setPixmap(const QPixmap &pixmap)
{
m_pixmap = pixmap;
+ if (!m_useCompositing)
+ setMask(m_pixmap.mask());
}
void QShapedPixmapWindow::setHotspot(const QPoint &hotspot)
diff --git a/src/gui/kernel/qshapedpixmapdndwindow_p.h b/src/gui/kernel/qshapedpixmapdndwindow_p.h
index 7536c09..3d7974f 100644
--- a/src/gui/kernel/qshapedpixmapdndwindow_p.h
+++ b/src/gui/kernel/qshapedpixmapdndwindow_p.h
@@ -60,6 +60,7 @@ public:
void render();
+ void setUseCompositing(bool on) { m_useCompositing = on; }
void setPixmap(const QPixmap &pixmap);
void setHotspot(const QPoint &hotspot);
@@ -72,6 +73,7 @@ private:
QBackingStore *m_backingStore;
QPixmap m_pixmap;
QPoint m_hotSpot;
+ bool m_useCompositing;
};
QT_END_NAMESPACE
diff --git a/src/gui/kernel/qsimpledrag.cpp b/src/gui/kernel/qsimpledrag.cpp
index 6acac4c..9f38c9b 100644
--- a/src/gui/kernel/qsimpledrag.cpp
+++ b/src/gui/kernel/qsimpledrag.cpp
@@ -88,7 +88,7 @@ static QWindow* topLevelAt(const QPoint &pos)
QBasicDrag::QBasicDrag() :
m_restoreCursor(false), m_eventLoop(0),
m_executed_drop_action(Qt::IgnoreAction), m_can_drop(false),
- m_drag(0), m_drag_icon_window(0)
+ m_drag(0), m_drag_icon_window(0), m_useCompositing(true)
{
}
@@ -226,6 +226,7 @@ void QBasicDrag::recreateShapedPixmapWindow(QScreen *screen, const QPoint &pos)
// when QDrag is used without a pixmap - QDrag::setPixmap()
m_drag_icon_window = new QShapedPixmapWindow(screen);
+ m_drag_icon_window->setUseCompositing(m_useCompositing);
m_drag_icon_window->setPixmap(m_drag->pixmap());
m_drag_icon_window->setHotspot(m_drag->hotSpot());
m_drag_icon_window->updateGeometry(pos);
diff --git a/src/gui/kernel/qsimpledrag_p.h b/src/gui/kernel/qsimpledrag_p.h
index 4c9edba..055136c 100644
--- a/src/gui/kernel/qsimpledrag_p.h
+++ b/src/gui/kernel/qsimpledrag_p.h
@@ -87,6 +87,9 @@ protected:
bool canDrop() const { return m_can_drop; }
void setCanDrop(bool c) { m_can_drop = c; }
+ bool useCompositing() const { return m_useCompositing; }
+ void setUseCompositing(bool on) { m_useCompositing = on; }
+
Qt::DropAction executedDropAction() const { return m_executed_drop_action; }
void setExecutedDropAction(Qt::DropAction da) { m_executed_drop_action = da; }
@@ -104,6 +107,7 @@ private:
bool m_can_drop;
QDrag *m_drag;
QShapedPixmapWindow *m_drag_icon_window;
+ bool m_useCompositing;
};
class Q_GUI_EXPORT QSimpleDrag : public QBasicDrag
diff --git a/src/plugins/platforms/xcb/qxcbclipboard.cpp b/src/plugins/platforms/xcb/qxcbclipboard.cpp
index 248d1b4..8b75c13 100644
--- a/src/plugins/platforms/xcb/qxcbclipboard.cpp
+++ b/src/plugins/platforms/xcb/qxcbclipboard.cpp
@@ -275,22 +275,8 @@ QXcbClipboard::QXcbClipboard(QXcbConnection *c)
m_clientClipboard[QClipboard::Selection] = 0;
m_timestamp[QClipboard::Clipboard] = XCB_CURRENT_TIME;
m_timestamp[QClipboard::Selection] = XCB_CURRENT_TIME;
+ m_owner = connection()->getQtSelectionOwner();
- QXcbScreen *platformScreen = screen();
-
- int x = 0, y = 0, w = 3, h = 3;
-
- m_owner = xcb_generate_id(xcb_connection());
- Q_XCB_CALL(xcb_create_window(xcb_connection(),
- XCB_COPY_FROM_PARENT, // depth -- same as root
- m_owner, // window id
- platformScreen->screen()->root, // parent window id
- x, y, w, h,
- 0, // border width
- XCB_WINDOW_CLASS_INPUT_OUTPUT, // window class
- platformScreen->screen()->root_visual, // visual
- 0, // value mask
- 0)); // value list
#ifndef QT_NO_DEBUG
QByteArray ba("Qt clipboard window");
Q_XCB_CALL(xcb_change_property(xcb_connection(),
@@ -353,13 +339,7 @@ void QXcbClipboard::incrTransactionPeeker(xcb_generic_event_t *ge, bool &accepte
xcb_window_t QXcbClipboard::getSelectionOwner(xcb_atom_t atom) const
{
- xcb_connection_t *c = xcb_connection();
- xcb_get_selection_owner_cookie_t cookie = xcb_get_selection_owner(c, atom);
- xcb_get_selection_owner_reply_t *reply;
- reply = xcb_get_selection_owner_reply(c, cookie, 0);
- xcb_window_t win = reply->owner;
- free(reply);
- return win;
+ return connection()->getSelectionOwner(atom);
}
xcb_atom_t QXcbClipboard::atomForMode(QClipboard::Mode mode) const
diff --git a/src/plugins/platforms/xcb/qxcbconnection.cpp b/src/plugins/platforms/xcb/qxcbconnection.cpp
index 13d73c7..a20d957 100644
--- a/src/plugins/platforms/xcb/qxcbconnection.cpp
+++ b/src/plugins/platforms/xcb/qxcbconnection.cpp
@@ -449,6 +449,9 @@ void QXcbConnection::initializeScreens()
++xcbScreenNumber;
} // for each xcb screen
+ foreach (QXcbVirtualDesktop *virtualDesktop, m_virtualDesktops)
+ virtualDesktop->subscribeToXFixesSelectionNotify();
+
// If there's no randr extension, or there was some error above, or we found a
// screen which doesn't have outputs for some other reason (e.g. on VNC or ssh -X),
// but the dimensions are known anyway, and we don't already have any lingering
@@ -507,6 +510,7 @@ QXcbConnection::QXcbConnection(QXcbNativeInterface *nativeInterface, bool canGra
, m_systemTrayTracker(0)
, m_glIntegration(Q_NULLPTR)
, m_xiGrab(false)
+ , m_qtSelectionOwner(0)
{
#ifdef XCB_USE_XLIB
Display *dpy = XOpenDisplay(m_displayName.constData());
@@ -551,12 +555,12 @@ QXcbConnection::QXcbConnection(QXcbNativeInterface *nativeInterface, bool canGra
m_netWmUserTime = XCB_CURRENT_TIME;
initializeXRandr();
+ initializeXFixes();
initializeScreens();
if (m_screens.isEmpty())
qFatal("QXcbConnection: no screens available");
- initializeXFixes();
initializeXRender();
m_xi2Enabled = false;
#if defined(XCB_USE_XINPUT2)
@@ -1139,10 +1143,14 @@ void QXcbConnection::handleXcbEvent(xcb_generic_event_t *event)
if (!handled) {
if (response_type == xfixes_first_event + XCB_XFIXES_SELECTION_NOTIFY) {
- setTime(((xcb_xfixes_selection_notify_event_t *)event)->timestamp);
+ xcb_xfixes_selection_notify_event_t *notify_event = (xcb_xfixes_selection_notify_event_t *)event;
+ setTime(notify_event->timestamp);
#ifndef QT_NO_CLIPBOARD
- m_clipboard->handleXFixesSelectionRequest((xcb_xfixes_selection_notify_event_t *)event);
+ m_clipboard->handleXFixesSelectionRequest(notify_event);
#endif
+ foreach (QXcbVirtualDesktop *virtualDesktop, m_virtualDesktops)
+ virtualDesktop->handleXFixesSelectionNotify(notify_event);
+
handled = true;
} else if (has_randr_extension && response_type == xrandr_first_event + XCB_RANDR_NOTIFY) {
updateScreens((xcb_randr_notify_event_t *)event);
@@ -1371,6 +1379,37 @@ xcb_timestamp_t QXcbConnection::getTimestamp()
return timestamp;
}
+xcb_window_t QXcbConnection::getSelectionOwner(xcb_atom_t atom) const
+{
+ xcb_connection_t *c = xcb_connection();
+ xcb_get_selection_owner_cookie_t cookie = xcb_get_selection_owner(c, atom);
+ xcb_get_selection_owner_reply_t *reply;
+ reply = xcb_get_selection_owner_reply(c, cookie, 0);
+ xcb_window_t win = reply->owner;
+ free(reply);
+ return win;
+}
+
+xcb_window_t QXcbConnection::getQtSelectionOwner()
+{
+ if (!m_qtSelectionOwner) {
+ xcb_screen_t *xcbScreen = primaryVirtualDesktop()->screen();
+ int x = 0, y = 0, w = 3, h = 3;
+ m_qtSelectionOwner = xcb_generate_id(xcb_connection());
+ Q_XCB_CALL(xcb_create_window(xcb_connection(),
+ XCB_COPY_FROM_PARENT, // depth -- same as root
+ m_qtSelectionOwner, // window id
+ xcbScreen->root, // parent window id
+ x, y, w, h,
+ 0, // border width
+ XCB_WINDOW_CLASS_INPUT_OUTPUT, // window class
+ xcbScreen->root_visual, // visual
+ 0, // value mask
+ 0)); // value list
+ }
+ return m_qtSelectionOwner;
+}
+
xcb_window_t QXcbConnection::rootWindow()
{
QXcbScreen *s = primaryScreen();
diff --git a/src/plugins/platforms/xcb/qxcbconnection.h b/src/plugins/platforms/xcb/qxcbconnection.h
index fb5b941..3c82170 100644
--- a/src/plugins/platforms/xcb/qxcbconnection.h
+++ b/src/plugins/platforms/xcb/qxcbconnection.h
@@ -460,6 +460,8 @@ public:
bool threadedEventHandling() const { return m_reader->isRunning(); }
xcb_timestamp_t getTimestamp();
+ xcb_window_t getSelectionOwner(xcb_atom_t atom) const;
+ xcb_window_t getQtSelectionOwner();
void setButton(Qt::MouseButton button, bool down) { if (down) m_buttons |= button; else m_buttons &= ~button; }
Qt::MouseButtons buttons() const { return m_buttons; }
@@ -650,6 +652,8 @@ private:
QXcbGlIntegration *m_glIntegration;
bool m_xiGrab;
+ xcb_window_t m_qtSelectionOwner;
+
friend class QXcbEventReader;
};
diff --git a/src/plugins/platforms/xcb/qxcbdrag.cpp b/src/plugins/platforms/xcb/qxcbdrag.cpp
index f9c3aa7..d19ea24 100644
--- a/src/plugins/platforms/xcb/qxcbdrag.cpp
+++ b/src/plugins/platforms/xcb/qxcbdrag.cpp
@@ -191,6 +191,8 @@ void QXcbDrag::startDrag()
xcb_change_property(xcb_connection(), XCB_PROP_MODE_REPLACE, connection()->clipboard()->owner(),
atom(QXcbAtom::XdndTypelist),
XCB_ATOM_ATOM, 32, drag_types.size(), (const void *)drag_types.constData());
+
+ setUseCompositing(current_virtual_desktop->compositingActive());
QBasicDrag::startDrag();
}
@@ -316,6 +318,7 @@ void QXcbDrag::move(const QPoint &globalPos)
QPoint deviceIndependentPos = QHighDpiScaling::mapPositionFromNative(globalPos, screen);
if (virtualDesktop != current_virtual_desktop) {
+ setUseCompositing(virtualDesktop->compositingActive());
recreateShapedPixmapWindow(static_cast<QPlatformScreen*>(screen)->screen(), deviceIndependentPos);
current_virtual_desktop = virtualDesktop;
} else {
diff --git a/src/plugins/platforms/xcb/qxcbscreen.cpp b/src/plugins/platforms/xcb/qxcbscreen.cpp
index 64645b9..0aa5810 100644
--- a/src/plugins/platforms/xcb/qxcbscreen.cpp
+++ b/src/plugins/platforms/xcb/qxcbscreen.cpp
@@ -54,6 +54,10 @@ QXcbVirtualDesktop::QXcbVirtualDesktop(QXcbConnection *connection, xcb_screen_t
, m_number(number)
, m_xSettings(Q_NULLPTR)
{
+ QByteArray cmAtomName("_NET_WM_CM_S");
+ cmAtomName += QByteArray::number(m_number);
+ m_net_wm_cm_atom = connection->internAtom(cmAtomName.constData());
+ m_compositingActive = connection->getSelectionOwner(m_net_wm_cm_atom);
}
QXcbVirtualDesktop::~QXcbVirtualDesktop()
@@ -79,6 +83,30 @@ QXcbXSettings *QXcbVirtualDesktop::xSettings() const
return m_xSettings;
}
+bool QXcbVirtualDesktop::compositingActive() const
+{
+ if (connection()->hasXFixes())
+ return m_compositingActive;
+ else
+ return connection()->getSelectionOwner(m_net_wm_cm_atom);
+}
+
+void QXcbVirtualDesktop::handleXFixesSelectionNotify(xcb_xfixes_selection_notify_event_t *notify_event)
+{
+ if (notify_event->selection == m_net_wm_cm_atom)
+ m_compositingActive = notify_event->owner;
+}
+
+void QXcbVirtualDesktop::subscribeToXFixesSelectionNotify()
+{
+ if (connection()->hasXFixes()) {
+ const uint32_t mask = XCB_XFIXES_SELECTION_EVENT_MASK_SET_SELECTION_OWNER |
+ XCB_XFIXES_SELECTION_EVENT_MASK_SELECTION_WINDOW_DESTROY |
+ XCB_XFIXES_SELECTION_EVENT_MASK_SELECTION_CLIENT_CLOSE;
+ Q_XCB_CALL(xcb_xfixes_select_selection_input_checked(xcb_connection(), connection()->getQtSelectionOwner(), m_net_wm_cm_atom, mask));
+ }
+}
+
QXcbScreen::QXcbScreen(QXcbConnection *connection, QXcbVirtualDesktop *virtualDesktop,
xcb_randr_output_t outputId, xcb_randr_get_output_info_reply_t *output,
QString outputName)
diff --git a/src/plugins/platforms/xcb/qxcbscreen.h b/src/plugins/platforms/xcb/qxcbscreen.h
index d8d6360..51c92a4 100644
--- a/src/plugins/platforms/xcb/qxcbscreen.h
+++ b/src/plugins/platforms/xcb/qxcbscreen.h
@@ -39,6 +39,7 @@
#include <xcb/xcb.h>
#include <xcb/randr.h>
+#include <xcb/xfixes.h>
#include "qxcbobject.h"
#include "qxcbscreen.h"
@@ -69,11 +70,18 @@ public:
QXcbXSettings *xSettings() const;
+ bool compositingActive() const;
+
+ void handleXFixesSelectionNotify(xcb_xfixes_selection_notify_event_t *notify_event);
+ void subscribeToXFixesSelectionNotify();
+
private:
xcb_screen_t *m_screen;
int m_number;
QXcbXSettings *m_xSettings;
+ xcb_atom_t m_net_wm_cm_atom;
+ bool m_compositingActive;
};
class Q_XCB_EXPORT QXcbScreen : public QXcbObject, public QPlatformScreen
--
2.6.3