diff options
-rw-r--r-- | src/plugins/platforms/xcb/qxcbnativeinterface.cpp | 12 | ||||
-rw-r--r-- | src/plugins/platforms/xcb/qxcbnativeinterface.h | 1 | ||||
-rw-r--r-- | src/widgets/util/qsystemtrayicon_x11.cpp | 27 |
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); |