aboutsummaryrefslogtreecommitdiff
path: root/xlib.py
blob: b86a8b1184f73c5ae916c5d1b333cad5b248e900 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
#!/usr/bin/python3
import Xlib
import Xlib.display

from zope import interface
from interfaces import desktopEvent
from threading import Thread

from interfaces.message import IMessage, Debug
from zope import component

@interface.implementer(desktopEvent.IDesktop)
class Listener(Thread):

    def __init__(self, mapping, queue):
        Thread.__init__(self)
        self.queue = queue
        self.mapping = mapping
        self.active_window = None
        self.last_code = None
        self.running = False

    def getForegroundWindowTitle(self):
        """ Return the name of the selected window
        """
        return self.active_window

    def run(self):
        disp = Xlib.display.Display()
        NET_WM_NAME = disp.intern_atom('_NET_WM_NAME')
        WM_CLASS = disp.intern_atom('WM_CLASS')
        NET_ACTIVE_WINDOW = disp.intern_atom('_NET_ACTIVE_WINDOW')
        root = disp.screen().root
        root.change_attributes(event_mask=Xlib.X.PropertyChangeMask)

        component.handle(Debug("Waiting for xlib event"))
        self.running = True
        while self.running:
            try:
                window_id = root.get_full_property(NET_ACTIVE_WINDOW, Xlib.X.AnyPropertyType).value[0]
                window = disp.create_resource_object('window', window_id)
                window.change_attributes(event_mask=Xlib.X.PropertyChangeMask)
                window_name = str(window.get_full_property(NET_WM_NAME, 0).value).lower()
                class_name = str(window.get_full_property(WM_CLASS, 0).value).lower()
            except Xlib.error.XError:
                window_name = None
                class_name = None

            if window_name is not None and window_name != self.active_window:

                self.active_window = window_name
                for pattern, code in self.mapping.items():
                    if (pattern in window_name or pattern in class_name) and code != self.last_code:

                        component.handle(Debug("Switching to '%s' for '%s'" % (code, window_name)))
                        self.queue.put ( (code, None) )
                        self.last_code = code
                        break
            event = disp.next_event()

    def stop(self):
        self.running = False