commit cbb5ac5ce3baced76e5032175913dc2637ff0a9e
Author: Leo Franchi <lfranchi@dropbox.com>
Date:   Mon Jun 30 02:53:08 2014 -0700

    Support transparency in qt5 system tray icons
    
    This ports the Qt4 method of supporting the system tray
    window visual that has an alpha channel as well as ones
    that do not. We detect whether or not we have a 32-bit
    format and either use a Qt::transparent background, or
    call xcb_clear_region before painting the icon.

diff --git a/qtbase/src/plugins/platforms/xcb/qxcbnativeinterface.cpp b/qtbase/src/plugins/platforms/xcb/qxcbnativeinterface.cpp
index b45bd6a..6ace0a9 100644
--- a/qtbase/src/plugins/platforms/xcb/qxcbnativeinterface.cpp
+++ b/qtbase/src/plugins/platforms/xcb/qxcbnativeinterface.cpp
@@ -66,8 +66,13 @@
 #  include <stdio.h>
 #endif
 
+#include <xcb/xcb_aux.h>
+
 #include <algorithm>
 
+xcb_atom_t QXcbNativeInterface::s_sysTraySelectionAtom = XCB_ATOM_NONE;
+xcb_visualid_t QXcbNativeInterface::s_systrayVisualId = XCB_NONE;
+
 QT_BEGIN_NAMESPACE
 
 // return QXcbNativeInterface::ResourceType for the key.
@@ -133,6 +138,95 @@ QRect QXcbNativeInterface::systemTrayWindowGlobalGeometry(const QWindow *window)
     return QRect();
 }
 
+xcb_window_t QXcbNativeInterface::locateSystemTray(xcb_connection_t *conn, const QXcbScreen *screen)
+{
+    if (s_sysTraySelectionAtom == XCB_ATOM_NONE) {
+        QByteArray net_sys_tray = QString::fromLatin1("_NET_SYSTEM_TRAY_S%1").arg(screen->screenNumber()).toLatin1();
+        xcb_intern_atom_cookie_t intern_c =
+            xcb_intern_atom_unchecked(conn, true, net_sys_tray.length(), net_sys_tray);
+        xcb_generic_error_t *err = 0;
+
+        xcb_intern_atom_reply_t *intern_r = xcb_intern_atom_reply(conn, intern_c, &err);
+
+        if (err) {
+            free(err);
+            return XCB_WINDOW_NONE;
+        }
+
+        s_sysTraySelectionAtom = intern_r->atom;
+        free(intern_r);
+    }
+
+    xcb_get_selection_owner_cookie_t sel_owner_c = xcb_get_selection_owner_unchecked(conn, s_sysTraySelectionAtom);
+    xcb_generic_error_t *err = 0;
+    xcb_get_selection_owner_reply_t *sel_owner_r = xcb_get_selection_owner_reply(conn, sel_owner_c, &err);
+
+    if (err) {
+        free(err);
+        return XCB_WINDOW_NONE;
+    }
+    xcb_window_t selection_window = sel_owner_r->owner;
+    free(sel_owner_r);
+
+    return selection_window;
+}
+
+bool QXcbNativeInterface::systrayVisualHasAlphaChannel() {
+    const QXcbScreen *screen = static_cast<QXcbScreen *>(QGuiApplication::primaryScreen()->handle());
+
+    if (s_systrayVisualId == XCB_NONE) {
+        xcb_connection_t *xcb_conn = screen->xcb_connection();
+        xcb_atom_t tray_atom = screen->atom(QXcbAtom::_NET_SYSTEM_TRAY_VISUAL);
+
+        xcb_window_t systray_window = locateSystemTray(xcb_conn, screen);
+        if (systray_window == XCB_WINDOW_NONE)
+            return false;
+
+        // Get the xcb property for the _NET_SYSTEM_TRAY_VISUAL atom
+        xcb_get_property_cookie_t systray_atom_cookie;
+        xcb_get_property_reply_t *systray_atom_reply;
+        xcb_generic_error_t *err = 0;
+
+        systray_atom_cookie = xcb_get_property_unchecked(xcb_conn, false, systray_window,
+                                                        tray_atom, XCB_ATOM_VISUALID, 0, 1);
+        systray_atom_reply = xcb_get_property_reply(xcb_conn, systray_atom_cookie, &err);
+
+        if (err) {
+            free(err);
+            return false;
+        }
+
+        if (systray_atom_reply->value_len > 0 && xcb_get_property_value_length(systray_atom_reply) > 0) {
+            xcb_visualid_t * vids = (uint32_t *)xcb_get_property_value(systray_atom_reply);
+            s_systrayVisualId = vids[0];
+        }
+
+        free(systray_atom_reply);
+    }
+
+    if (s_systrayVisualId != XCB_NONE) {
+        uint8_t depth = xcb_aux_get_depth_of_visual(screen->screen(), s_systrayVisualId);
+        return depth == 32;
+    } else {
+        return false;
+    }
+}
+
+void QXcbNativeInterface::clearRegion(const QWindow *qwindow, const QRect& rect)
+{
+    if (const QPlatformWindow *platformWindow = qwindow->handle()) {
+        const QXcbWindow *qxwindow = static_cast<const QXcbWindow *>(platformWindow);
+        xcb_connection_t *xcb_conn = qxwindow->xcb_connection();
+
+        xcb_void_cookie_t cookie = xcb_clear_area_checked(xcb_conn, true, qxwindow->xcb_window(), rect.x(), rect.y(), rect.width(), rect.height());
+
+        xcb_generic_error_t *error;
+        if ((error = xcb_request_check(xcb_conn, cookie))) {
+            free(error);
+        }
+    }
+}
+
 void *QXcbNativeInterface::nativeResourceForIntegration(const QByteArray &resourceString)
 {
     void *result = 0;
diff --git a/qtbase/src/plugins/platforms/xcb/qxcbnativeinterface.h b/qtbase/src/plugins/platforms/xcb/qxcbnativeinterface.h
index fb1a460..2779edd 100644
--- a/qtbase/src/plugins/platforms/xcb/qxcbnativeinterface.h
+++ b/qtbase/src/plugins/platforms/xcb/qxcbnativeinterface.h
@@ -103,6 +103,10 @@ 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 bool systrayVisualHasAlphaChannel();
+
     Q_INVOKABLE bool requestSystemTrayWindowDock(const QWindow *window);
     Q_INVOKABLE QRect systemTrayWindowGlobalGeometry(const QWindow *window);
 
@@ -110,9 +114,14 @@ signals:
     void systemTrayWindowChanged(QScreen *screen);
 
 private:
+
     const QByteArray m_genericEventFilterType;
 
     static QXcbScreen *qPlatformScreenForWindow(QWindow *window);
+
+    static xcb_window_t locateSystemTray(xcb_connection_t *conn, const QXcbScreen *screen);
+    static xcb_atom_t s_sysTraySelectionAtom;
+    static xcb_visualid_t s_systrayVisualId;
 };
 
 QT_END_NAMESPACE
diff --git a/qtbase/src/widgets/util/qsystemtrayicon_x11.cpp b/qtbase/src/widgets/util/qsystemtrayicon_x11.cpp
index 347e570..a6919dd 100644
--- a/qtbase/src/widgets/util/qsystemtrayicon_x11.cpp
+++ b/qtbase/src/widgets/util/qsystemtrayicon_x11.cpp
@@ -100,11 +100,17 @@ QSystemTrayIconSys::QSystemTrayIconSys(QSystemTrayIcon *qIn)
     setObjectName(QStringLiteral("QSystemTrayIconSys"));
     setToolTip(q->toolTip());
     setAttribute(Qt::WA_AlwaysShowToolTips, true);
-    setAttribute(Qt::WA_TranslucentBackground, true);
     setAttribute(Qt::WA_QuitOnClose, false);
     const QSize size(22, 22); // Gnome, standard size
     setGeometry(QRect(QPoint(0, 0), size));
     setMinimumSize(size);
+
+    bool hasAlphaChannel = false;
+    QMetaObject::invokeMethod(QGuiApplication::platformNativeInterface(),
+                              "systrayVisualHasAlphaChannel", Qt::DirectConnection,
+                              Q_RETURN_ARG(bool, hasAlphaChannel));
+    setAttribute(Qt::WA_TranslucentBackground, hasAlphaChannel);
+
     addToTray();
 }
 
@@ -125,6 +131,7 @@ bool QSystemTrayIconSys::addToTray()
         qWarning("requestSystemTrayWindowDock failed.");
         return false;
     }
+
     show();
     return true;
 }
@@ -195,14 +202,27 @@ bool QSystemTrayIconSys::event(QEvent *e)
 
 void QSystemTrayIconSys::paintEvent(QPaintEvent *)
 {
-    // Note: Transparent pixels require a particular Visual which XCB
-    // currently does not support yet.
+    bool hasAlphaChannel = false;
+    QMetaObject::invokeMethod(QGuiApplication::platformNativeInterface(),
+                                   "systrayVisualHasAlphaChannel", Qt::DirectConnection,
+                                   Q_RETURN_ARG(bool, hasAlphaChannel));
+
     const QRect rect(QPoint(0, 0), geometry().size());
     QPainter painter(this);
-    painter.setCompositionMode(QPainter::CompositionMode_Source);
-    painter.fillRect(rect, Qt::transparent);
-    painter.setCompositionMode(QPainter::CompositionMode_SourceOver);
-    q->icon().paint(&painter, rect);
+    if (hasAlphaChannel) {
+        painter.setCompositionMode(QPainter::CompositionMode_Source);
+        painter.fillRect(rect, Qt::transparent);
+        painter.setCompositionMode(QPainter::CompositionMode_SourceOver);
+        q->icon().paint(&painter, rect);
+    } else {
+        QMetaObject::invokeMethod(QGuiApplication::platformNativeInterface(),
+                                    "clearRegion", Qt::DirectConnection,
+                                    Q_ARG(const QWindow *, windowHandle()),
+                                    Q_ARG(const QRect&, rect)
+                                );
+        painter.setCompositionMode(QPainter::CompositionMode_SourceOver);
+        q->icon().paint(&painter, rect);
+    }
 }
 
 ////////////////////////////////////////////////////////////////////////////
