QSystemTrayIconSys::QSystemTrayIconSys(QSystemTrayIcon *q) : QWidget(0, Qt::FramelessWindowHint | Qt::X11BypassWindowManagerHint), q(q), colormap(0) { setAttribute(Qt::WA_AlwaysShowToolTips); setAttribute(Qt::WA_QuitOnClose, false); setAttribute(Qt::WA_NoSystemBackground, true); setAttribute(Qt::WA_PaintOnScreen); static bool eventFilterAdded = false; Display *display = QX11Info::display(); if (!eventFilterAdded) { oldEventFilter = qApp->setEventFilter(sysTrayTracker); eventFilterAdded = true; Window root = QX11Info::appRootWindow(); XWindowAttributes attr; XGetWindowAttributes(display, root, &attr); if ((attr.your_event_mask & StructureNotifyMask) != StructureNotifyMask) { (void) QApplication::desktop(); // lame trick to ensure our event mask is not overridden XSelectInput(display, root, attr.your_event_mask | StructureNotifyMask); // for MANAGER selection } } if (trayIcons.isEmpty()) { sysTrayWindow = locateSystemTray(); if (sysTrayWindow != XNone) XSelectInput(display, sysTrayWindow, StructureNotifyMask); // track tray events } trayIcons.append(this); setMouseTracking(true); #ifndef QT_NO_TOOLTIP setToolTip(q->toolTip()); #endif if (sysTrayWindow != XNone) addToTray(); }
bool QSystemTrayIconSys::sysTrayTracker(void *message, long *result) { bool retval = false; if (QSystemTrayIconSys::oldEventFilter) retval = QSystemTrayIconSys::oldEventFilter(message, result); if (trayIcons.isEmpty()) return retval; Display *display = QX11Info::display(); XEvent *ev = (XEvent *)message; if (ev->type == DestroyNotify && ev->xany.window == sysTrayWindow) { sysTrayWindow = locateSystemTray(); memset(&sysTrayVisual, 0, sizeof(sysTrayVisual)); for (int i = 0; i < trayIcons.count(); i++) { if (sysTrayWindow == XNone) { QBalloonTip::hideBalloon(); trayIcons[i]->hide(); // still no luck trayIcons[i]->destroy(); trayIcons[i]->create(); } else trayIcons[i]->addToTray(); // add it to the new tray } retval = true; } else if (ev->type == ClientMessage && sysTrayWindow == XNone) { static Atom manager_atom = XInternAtom(display, "MANAGER", False); XClientMessageEvent *cm = (XClientMessageEvent *)message; if ((cm->message_type == manager_atom) && ((Atom)cm->data.l[1] == sysTraySelection)) { sysTrayWindow = cm->data.l[2]; memset(&sysTrayVisual, 0, sizeof(sysTrayVisual)); XSelectInput(display, sysTrayWindow, StructureNotifyMask); for (int i = 0; i < trayIcons.count(); i++) { trayIcons[i]->addToTray(); } retval = true; } } else if (ev->type == PropertyNotify && ev->xproperty.atom == ATOM(_NET_SYSTEM_TRAY_VISUAL) && ev->xproperty.window == sysTrayWindow) { memset(&sysTrayVisual, 0, sizeof(sysTrayVisual)); for (int i = 0; i < trayIcons.count(); i++) { trayIcons[i]->addToTray(); } } return retval; }
XVisualInfo* QSystemTrayIconSys::getSysTrayVisualInfo() { Display *display = QX11Info::display(); if (!sysTrayVisual.visual) { Window win = locateSystemTray(); if (win != XNone) { Atom actual_type; int actual_format; ulong nitems, bytes_remaining; uchar *data = 0; int result = XGetWindowProperty(display, win, ATOM(_NET_SYSTEM_TRAY_VISUAL), 0, 1, False, XA_VISUALID, &actual_type, &actual_format, &nitems, &bytes_remaining, &data); VisualID vid = 0; if (result == Success && data && actual_type == XA_VISUALID && actual_format == 32 && nitems == 1 && bytes_remaining == 0) vid = *(VisualID*)data; if (data) XFree(data); if (vid == 0) return 0; uint mask = VisualIDMask; XVisualInfo *vi, rvi; int count; rvi.visualid = vid; vi = XGetVisualInfo(display, mask, &rvi, &count); if (vi) { sysTrayVisual = vi[0]; XFree((char*)vi); } if (sysTrayVisual.depth != 32) memset(&sysTrayVisual, 0, sizeof(sysTrayVisual)); } } return sysTrayVisual.visual ? &sysTrayVisual : 0; }
bool QXcbNativeInterface::systrayVisualHasAlphaChannel() { const QXcbScreen *screen = static_cast<QXcbScreen *>(QGuiApplication::primaryScreen()->handle()); if (m_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; 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, 0); if (!systray_atom_reply) 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); m_systrayVisualId = vids[0]; } free(systray_atom_reply); } if (m_systrayVisualId != XCB_NONE) { quint8 depth = screen->depthOfVisual(m_systrayVisualId); return depth == 32; } else { return false; } }