summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorUli Schlachter <psychon@znc.in>2014-12-04 17:57:02 +0100
committerShawn Rutledge <shawn.rutledge@digia.com>2014-12-09 16:01:59 +0100
commit2203d9d93e24e00d6e9bc9bda0e65a0c7f9923cc (patch)
tree67cf443dc490d58a66c63cc2494fd96f9424d4a2 /src
parent459e22a9dfd7105918528def302604a6c0628115 (diff)
xcb: Fix transparent tray backgrounds with 24bpp tray visuals
Commit 0eefa785a0d8 ported Qt4's method of indirectly drawing the tray icon's background to Qt5. This commit makes it work a bit better. When drawing the tray's background, we use a ClearArea request to make the X11 server fill the tray icon with its background. Then we grab that background from the server and paint the icon on top of it. So this is pretty much pseudo-transparency at work. One small ingredient that was missing before is the BackgroundPixmap of the tray icon. If this attribute is set to ParentRelative, then our tray icon inherits the background of its parent window. That way the ClearArea will actually produce the expected background. Task-number: QTBUG-35832 Change-Id: I63fc4609064d8f858ca9e5cc290409a298b918b7 Reviewed-by: Jørgen Lind <jorgen.lind@theqtcompany.com> Reviewed-by: Shawn Rutledge <shawn.rutledge@digia.com>
Diffstat (limited to 'src')
-rw-r--r--src/plugins/platforms/xcb/qxcbnativeinterface.cpp12
-rw-r--r--src/plugins/platforms/xcb/qxcbnativeinterface.h1
-rw-r--r--src/widgets/util/qsystemtrayicon_x11.cpp27
3 files changed, 38 insertions, 2 deletions
diff --git a/src/plugins/platforms/xcb/qxcbnativeinterface.cpp b/src/plugins/platforms/xcb/qxcbnativeinterface.cpp
index 3058b29f2d..15ba7cc021 100644
--- a/src/plugins/platforms/xcb/qxcbnativeinterface.cpp
+++ b/src/plugins/platforms/xcb/qxcbnativeinterface.cpp
@@ -208,6 +208,18 @@ void QXcbNativeInterface::clearRegion(const QWindow *qwindow, const QRect& rect)
}
}
+void QXcbNativeInterface::setParentRelativeBackPixmap(const QWindow *qwindow)
+{
+ if (const QPlatformWindow *platformWindow = qwindow->handle()) {
+ const QXcbWindow *qxwindow = static_cast<const QXcbWindow *>(platformWindow);
+ xcb_connection_t *xcb_conn = qxwindow->xcb_connection();
+
+ const quint32 mask = XCB_CW_BACK_PIXMAP;
+ const quint32 values[] = { XCB_BACK_PIXMAP_PARENT_RELATIVE };
+ Q_XCB_CALL(xcb_change_window_attributes(xcb_conn, qxwindow->xcb_window(), mask, values));
+ }
+}
+
void *QXcbNativeInterface::nativeResourceForIntegration(const QByteArray &resourceString)
{
void *result = 0;
diff --git a/src/plugins/platforms/xcb/qxcbnativeinterface.h b/src/plugins/platforms/xcb/qxcbnativeinterface.h
index b667f1a372..3ec96975f5 100644
--- a/src/plugins/platforms/xcb/qxcbnativeinterface.h
+++ b/src/plugins/platforms/xcb/qxcbnativeinterface.h
@@ -106,6 +106,7 @@ public:
Q_INVOKABLE void beep();
Q_INVOKABLE bool systemTrayAvailable(const QScreen *screen) const;
Q_INVOKABLE void clearRegion(const QWindow *qwindow, const QRect& rect);
+ Q_INVOKABLE void setParentRelativeBackPixmap(const QWindow *window);
Q_INVOKABLE bool systrayVisualHasAlphaChannel();
Q_INVOKABLE bool requestSystemTrayWindowDock(const QWindow *window);
Q_INVOKABLE QRect systemTrayWindowGlobalGeometry(const QWindow *window);
diff --git a/src/widgets/util/qsystemtrayicon_x11.cpp b/src/widgets/util/qsystemtrayicon_x11.cpp
index eee100d279..ba80734876 100644
--- a/src/widgets/util/qsystemtrayicon_x11.cpp
+++ b/src/widgets/util/qsystemtrayicon_x11.cpp
@@ -107,13 +107,29 @@ QSystemTrayIconSys::QSystemTrayIconSys(QSystemTrayIcon *qIn)
// If we have a visual that has an alpha channel, we can paint this widget with a transparent
// background and it will work.
// However, if there's no alpha channel visual, in order for transparent tray icons to work,
- // we do not have a transparent background on the widget, but call xcb_clear_region before
- // painting the icon
+ // we do not have a transparent background on the widget, but set the BackPixmap property of our
+ // window to ParentRelative (so that it inherits the background of its X11 parent window), call
+ // xcb_clear_region before painting (so that the inherited background is visible) and then grab
+ // the just-drawn background from the X11 server.
bool hasAlphaChannel = false;
QMetaObject::invokeMethod(QGuiApplication::platformNativeInterface(),
"systrayVisualHasAlphaChannel", Qt::DirectConnection,
Q_RETURN_ARG(bool, hasAlphaChannel));
setAttribute(Qt::WA_TranslucentBackground, hasAlphaChannel);
+ if (!hasAlphaChannel) {
+ createWinId();
+ QMetaObject::invokeMethod(QGuiApplication::platformNativeInterface(),
+ "setParentRelativeBackPixmap", Qt::DirectConnection,
+ Q_ARG(const QWindow *, windowHandle())
+ );
+
+ // XXX: This is actually required, but breaks things ("QWidget::paintEngine: Should no
+ // longer be called"). Why is this needed? When the widget is drawn, we use tricks to grab
+ // the tray icon's background from the server. If the tray icon isn't visible (because
+ // another window is on top of it), the trick fails and instead uses the content of that
+ // other window as the background.
+ // setAttribute(Qt::WA_PaintOnScreen);
+ }
addToTray();
}
@@ -214,11 +230,18 @@ void QSystemTrayIconSys::paintEvent(QPaintEvent *)
painter.setCompositionMode(QPainter::CompositionMode_Source);
painter.fillRect(rect, Qt::transparent);
} else {
+ // Without Qt::WA_TranslucentBackground, we use a ParentRelative BackPixmap and jump through
+ // some hops to draw this background below our icon. This clears the whole tray icon to its
+ // background color and thus causes flickering (you can see that the icon is being
+ // repainted). However, we can't really do much about this.
QMetaObject::invokeMethod(QGuiApplication::platformNativeInterface(),
"clearRegion", Qt::DirectConnection,
Q_ARG(const QWindow *, windowHandle()),
Q_ARG(const QRect&, rect)
);
+ painter.drawPixmap(QPoint(0, 0),
+ QGuiApplication::primaryScreen()->grabWindow(winId(),
+ 0, 0, rect.size().width(), rect.size().height()));
}
painter.setCompositionMode(QPainter::CompositionMode_SourceOver);
q->icon().paint(&painter, rect);