Hello all,

for a project of mine, I need a systray icon. I know that it is possible to get a one with PyKDE and there is a solution for PyGtk, but not for PyQt itself. But the code is rather easy and I found out that the ppl of qjackcontrol implemented a systray icon in Qt for themselves, using the spec + sample code from freedesktop.org (sorry, but I'm too lazy right know to find out all the links). All you need to do is to call some functions in libX11.so. For that, you need the Display (qt_x11_display()) and the WindowID (QWidget.winId())

So far, there are several ways to do the C calls from Python:
- extension module
- Pyrex
- ctypes
I chose the ctypes way and after some hassle (mostly typos!), I got it to actually work. It's not very advanced by now. To try it out, just replace the icon filename with something icon on your system. I put in all values in good faith and they are poorly documented right now, but I'll fix that later on.

I'll go to bed now....


greetings

Torsten
--
Torsten Marek <[EMAIL PROTECTED]>
ID: A244C858 -- FP: 1902 0002 5DFC 856B F146  894C 7CC5 451E A244 C858
www.keyserver.net -- wwwkeys.eu.pgp.net

import sys
import qt
from ctypes import *


class SystrayIcon(qt.QLabel):
    def __init__(self, parent = None, name = ""):
        qt.QLabel.__init__(self, parent, name, qt.Qt.WMouseNoMask | qt.Qt.WRepaintNoErase | qt.Qt.WType_TopLevel | qt.Qt.WStyle_Customize | qt.Qt.WStyle_NoBorder | qt.Qt.WStyle_StaysOnTop)
        self.setMinimumSize(22, 22);
        self.setBackgroundMode(qt.Qt.X11ParentRelative)
        self.setBackgroundOrigin(qt.QWidget.WindowOrigin)

        libX11 = cdll.LoadLibrary("/usr/X11R6/lib/libX11.so")
        # get all functions, set arguments + return types
        XDefaultScreenOfDisplay = libX11.XDefaultScreenOfDisplay
        XDefaultScreenOfDisplay.argtypes = [c_void_p]
        XDefaultScreenOfDisplay.restype = c_void_p
        
        XScreenNumberOfScreen = libX11.XScreenNumberOfScreen
        XScreenNumberOfScreen.argtypes = [c_void_p]
        
        XInternAtom = libX11.XInternAtom
        XInternAtom.argtypes = [c_void_p, c_char_p, c_int]
        
        XGrabServer = libX11.XGrabServer
        XGrabServer.argtypes = [c_void_p]
        
        XGetSelectionOwner = libX11.XGetSelectionOwner
        XGetSelectionOwner.argtypes = [c_void_p, c_int]
        
        XSelectInput = libX11.XSelectInput
        XSelectInput.argtypes = [c_void_p, c_int, c_long]
        
        
        XUngrabServer = libX11.XUngrabServer
        XUngrabServer.argtypes = [c_void_p]
        
        XFlush = libX11.XFlush
        XFlush.argtypes = [c_void_p]
        
        
        # XClientMessageEvent
        class data(Union):
            _fields_ = [("b", c_char * 20),
                        ("s", c_short * 10),
                        ("l", c_long * 5)]
        class XClientMessageEvent(Structure):
            _fields_ = [("type", c_int),
                        ("serial", c_ulong),
                        ("send_event", c_int),
                        ("display", c_void_p),
                        ("window", c_int),
                        ("message_type", c_int),
                        ("format", c_int),
                        ("data", data)]
        # XEvent struct
        class XEvent(Union):
            _fields_ = [("xclient", XClientMessageEvent)]
            
        XSendEvent = libX11.XSendEvent
        XSendEvent.argtypes = [c_void_p, c_int, c_int, c_long, c_void_p]
                               
        XSync = libX11.XSync
        XSync.argtypes = [c_void_p, c_int]

        dpy = int(qt.qt_xdisplay())
        trayWin  = self.winId();

        print "mywinid: 0x%x" % trayWin
        
        screen = XDefaultScreenOfDisplay(dpy)
        iscreen = XScreenNumberOfScreen(screen)
        selectionAtom = XInternAtom(dpy, "_NET_SYSTEM_TRAY_S%i" % iscreen, 0)
        XGrabServer(dpy)
        managerWin = XGetSelectionOwner(dpy, selectionAtom)
        print "managerWin: 0x%x" % managerWin
        if managerWin != 0:
            XSelectInput(dpy, managerWin, 1L << 17)
        XUngrabServer(dpy);
        XFlush(dpy);
        print managerWin
        if managerWin != 0:
            k = data()
            k.l = (0, 0, trayWin, 0, 0)
            ev = XClientMessageEvent(33, #type
                                     0, # serial
                                     0, # send_event
                                     dpy, # display
                                     managerWin, # window
                                     XInternAtom(dpy, "_NET_SYSTEM_TRAY_OPCODE", 0), # message type
                                     32, # format
                                     k)
            XSendEvent(dpy, managerWin, 0, 0, addressof(ev))
            XSync(dpy, 0)
            
        img = qt.QImage("/usr/share/rattlesnake/pixmaps/rattlesnake64.png")
        pm = qt.QPixmap()
        pm.convertFromImage(img.smoothScale(22, 22), 0)
        self.setPixmap(pm)
        self.setAlignment(qt.Qt.AlignHCenter)

        self.popup = qt.QPopupMenu()
        self.popup.insertItem("This is amazing, but please quit now!", self.close)

        
    def mousePressEvent(self, e):
        if e.button() == qt.Qt.RightButton:
            self.popup.popup(e.globalPos())
            print "test"


a = qt.QApplication(sys.argv)
w = SystrayIcon()
qt.QObject.connect(a,qt.SIGNAL("lastWindowClosed()"),a,qt.SLOT("quit()"))
w.show()
a.exec_loop()

Attachment: signature.asc
Description: OpenPGP digital signature

Reply via email to