[prev in list] [next in list] [prev in thread] [next in thread] 

List:       pykde
Subject:    Re: [PyKDE] Systray icons in PyQt
From:       Torsten Marek <shlomme () gmx ! net>
Date:       2004-05-27 15:22:13
Message-ID: 40B607A5.3080305 () gmx ! net
[Download RAW message or body]

[Attachment #2 (multipart/mixed)]


Hello,

2nd version of ctypes code and Python extension module with one func
only.

The spec can be found here
http://freedesktop.org/Standards/systemtray-spec/systemtray-spec-0.1.html,
the code itself is taken from qjackctl (qjackctl.sf.net).

When the code has undergone some review, I'll put it into the wiki.
Should it be distributed somewhere else? Maybe it could go into the PyQt
examples directory?


greetings

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



["SystrayIcon.py" (text/x-python)]

import qt
import ctypes as c

class SystrayIcon(qt.QLabel):
    """On construction, you have to supply a QPixmap instance holding the application \
icon.  The pixmap should not be bigger than 32x32, preferably 22x22. Currently, no \
check is made.

    The class can emits two signals:
    Leftclick on icon: activated()
    Rightclick on icon: contextMenuRequested(const QPoint&)
    """
    def __init__(self, icon, 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 = c.cdll.LoadLibrary("/usr/X11R6/lib/libX11.so")
        # get all functions, set arguments + return types
        XDefaultScreenOfDisplay = libX11.XDefaultScreenOfDisplay
        XDefaultScreenOfDisplay.argtypes = [c.c_void_p]
        XDefaultScreenOfDisplay.restype = c.c_void_p
        
        XScreenNumberOfScreen = libX11.XScreenNumberOfScreen
        XScreenNumberOfScreen.argtypes = [c.c_void_p]
        
        XInternAtom = libX11.XInternAtom
        XInternAtom.argtypes = [c.c_void_p, c.c_char_p, c.c_int]
        
        XGrabServer = libX11.XGrabServer
        XGrabServer.argtypes = [c.c_void_p]
        
        XGetSelectionOwner = libX11.XGetSelectionOwner
        XGetSelectionOwner.argtypes = [c.c_void_p, c.c_int]
        
        XSelectInput = libX11.XSelectInput
        XSelectInput.argtypes = [c.c_void_p, c.c_int, c.c_long]
        
        
        XUngrabServer = libX11.XUngrabServer
        XUngrabServer.argtypes = [c.c_void_p]
        
        XFlush = libX11.XFlush
        XFlush.argtypes = [c.c_void_p]
        
        class data(c.Union):
            _fields_ = [("b", c.c_char * 20),
                        ("s", c.c_short * 10),
                        ("l", c.c_long * 5)]
        class XClientMessageEvent(c.Structure):
            _fields_ = [("type", c.c_int),
                        ("serial", c.c_ulong),
                        ("send_event", c.c_int),
                        ("display", c.c_void_p),
                        ("window", c.c_int),
                        ("message_type", c.c_int),
                        ("format", c.c_int),
                        ("data", data)]

        XSendEvent = libX11.XSendEvent
        XSendEvent.argtypes = [c.c_void_p, c.c_int, c.c_int, c.c_long, c.c_void_p]
                               
        XSync = libX11.XSync
        XSync.argtypes = [c.c_void_p, c.c_int]

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

        iscreen = XScreenNumberOfScreen(XDefaultScreenOfDisplay(dpy))
        # get systray window (holds _NET_SYSTEM_TRAY_S<screen> atom)
        selectionAtom = XInternAtom(dpy, "_NET_SYSTEM_TRAY_S%i" % iscreen, 0)
        XGrabServer(dpy)
        managerWin = XGetSelectionOwner(dpy, selectionAtom)
        if managerWin != 0:
            # set StructureNotifyMask (1L << 17)
            XSelectInput(dpy, managerWin, 1L << 17)
        XUngrabServer(dpy);
        XFlush(dpy);
        if managerWin != 0:
            # send "SYSTEM_TRAY_OPCODE_REQUEST_DOCK to managerWin
            k = data()
            k.l = (0, # CurrentTime
                   0, # REQUEST_DOCK
                   trayWin, # window ID
                   0, # empty
                   0) # empty
            ev = XClientMessageEvent(33, #type: ClientMessage
                                     0, # serial
                                     0, # send_event
                                     dpy, # display
                                     managerWin, # systray manager
                                     XInternAtom(dpy, "_NET_SYSTEM_TRAY_OPCODE", 0), \
# message type  32, # format
                                     k) # message data
            XSendEvent(dpy, managerWin, 0, 0, c.addressof(ev))
            XSync(dpy, 0)
        
        self.setPixmap(icon)
        self.setAlignment(qt.Qt.AlignHCenter)

        if parent:
            qt.QToolTip.add(self, parent.caption())


    def setTooltipText(self, text):
        qt.QToolTip.add(self, text)

        
    def mousePressEvent(self, e):
        if e.button() == qt.Qt.RightButton:
            self.emit(qt.PYSIGNAL("contextMenuRequested(const QPoint&)"), \
(e.globalPos(),))  elif e.button() == qt.Qt.LeftButton:
            self.emit(qt.PYSIGNAL("activated()"), ())
            


["traywin.c" (text/x-csrc)]

#include <Python.h>

#include <X11/Xatom.h>
#include <X11/Xlib.h>
/* System Tray Protocol Specification opcodes. */
#define SYSTEM_TRAY_REQUEST_DOCK    0
#define SYSTEM_TRAY_BEGIN_MESSAGE   1
#define SYSTEM_TRAY_CANCEL_MESSAGE  2


static PyObject* setTrayIcon(PyObject* self, PyObject* args) /*Display *dpy, Window trayWin*/
{
    /* System Tray Protocol Specification. */
    Display *dpy;
    Window trayWin;
    PyArg_ParseTuple(args, "ll", &dpy, &trayWin);
    Screen *screen = XDefaultScreenOfDisplay(dpy);
    int iScreen = XScreenNumberOfScreen(screen);
    char szAtom[32];
    snprintf(szAtom, sizeof(szAtom), "_NET_SYSTEM_TRAY_S%d", iScreen);
    Atom selectionAtom = XInternAtom(dpy, szAtom, False);
    XGrabServer(dpy);
    Window managerWin = XGetSelectionOwner(dpy, selectionAtom);
    if (managerWin != None)
        XSelectInput(dpy, managerWin, StructureNotifyMask);
    XUngrabServer(dpy);
    XFlush(dpy);
    if (managerWin != None) {
        XEvent ev;
        memset(&ev, 0, sizeof(ev));
        ev.xclient.type = ClientMessage;
        ev.xclient.window = managerWin;
        ev.xclient.message_type = XInternAtom(dpy, "_NET_SYSTEM_TRAY_OPCODE", False);
        ev.xclient.format = 32;
        ev.xclient.data.l[0] = CurrentTime;
        ev.xclient.data.l[1] = SYSTEM_TRAY_REQUEST_DOCK;
        ev.xclient.data.l[2] = trayWin;
        ev.xclient.data.l[3] = 0;
        ev.xclient.data.l[4] = 0;
        XSendEvent(dpy, managerWin, False, NoEventMask, &ev);
        XSync(dpy, False);
    }
    return Py_None;
}

static char traywin_docs[] = 
    "setTrayIcon: make the window WID a tray icon\n";
     
static PyMethodDef traywin_funcs[]= {
    {"setTrayIcon", (PyCFunction)setTrayIcon, METH_VARARGS, traywin_docs},
    {NULL}
};

void inittraywin(void)
{
    PyObject* thismod = Py_InitModule3("traywin", traywin_funcs, "empty");
}


["systray2.py" (text/x-python)]

import qt
import sys
import traywin
class SystrayIcon(qt.QLabel):
    def __init__(self, icon, 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)

        dpy = int(qt.qt_xdisplay())
        winid  = self.winId();
        print "test"
        traywin.setTrayIcon(dpy, winid)
        
        self.setPixmap(icon)
        self.setAlignment(qt.Qt.AlignHCenter)

        if parent:
            qt.QToolTip.add(self, parent.caption())


    def setTooltipText(self, text):
        qt.QToolTip.add(self, text)

        
    def mousePressEvent(self, e):
        if e.button() == qt.Qt.RightButton:
            self.emit(qt.PYSIGNAL("contextMenuRequested(const QPoint&)"), \
(e.globalPos(),))  elif e.button() == qt.Qt.LeftButton:
            self.emit(qt.PYSIGNAL("activated()"), ())
            


def showPopup(pos):
    popup.popup(pos)


a = qt.QApplication(sys.argv)
img = qt.QImage("/home/shlomme/bilder/rattlesnake_tray.png")
pm = qt.QPixmap()
pm.convertFromImage(img.smoothScale(22, 22), 0)
w = SystrayIcon(pm)
w.setTooltipText("Rattlesnake")
popup = qt.QPopupMenu()
popup.insertItem("This is amazing, but please quit now!", w.close)
qt.QObject.connect(w, qt.PYSIGNAL("contextMenuRequested(const QPoint&)"), showPopup)
qt.QObject.connect(a,qt.SIGNAL("lastWindowClosed()"),a,qt.SLOT("quit()"))
w.show()
a.exec_loop()


["signature.asc" (application/pgp-signature)]
_______________________________________________
PyKDE mailing list    PyKDE@mats.imk.fraunhofer.de
http://mats.imk.fraunhofer.de/mailman/listinfo/pykde

[prev in list] [next in list] [prev in thread] [next in thread] 

Configure | About | News | Add a list | Sponsored by KoreLogic