]> git.neil.brown.name Git - freerunner.git/blob - launcher/wmctrl.py
Lots of random updates
[freerunner.git] / launcher / wmctrl.py
1
2 #
3 # manage a list of current windows and allow a selected
4 # window to be raised.
5 # I'm using Xlib for this, which doesn't have a built-in event
6 # mechanism like gtk does in gobject.
7 # So if you want to make sure property change notify events
8 # get handled, you need to arrange that read events on
9 # winlist.fd are passed to winlist.events.
10 # e.g. gobject.io_add_watch(winlist.fd, gobject.IO_IN, winlist.events)
11 #
12
13 import Xlib.X
14 import Xlib.display
15 import Xlib.protocol.event
16
17 class mywindow:
18     def __init__(self, win, name, pid, list):
19         self.win = win
20         self.name = name
21         self.pid = pid
22         self.list = list
23
24     def raise_win(self):
25         msg = Xlib.protocol.event.ClientMessage(window = self.win,
26                                                 client_type = self.list.ACTIVE_WINDOW,
27                                                 data = (32, [0,0,0,0,0])
28                                                 )
29         msg.send_event = 1
30         mask = (Xlib.X.SubstructureRedirectMask | 
31                 Xlib.X.SubstructureNotifyMask)
32         self.list.root.send_event(msg, event_mask = mask)
33         self.win.map()
34         self.win.raise_window()
35         #p = w.query_tree().parent
36         #if p:
37         #    p.map()
38         #    p.raise_window()
39         self.list.display.flush()
40
41     def close_win(self):
42         msg = Xlib.protocol.event.ClientMessage(window = self.win,
43                                                 client_type = self.list.CLOSE_WINDOW,
44                                                 data = (32, [0,0,0,0,0])
45                                                 )
46         msg.send_event = 1
47         mask = (Xlib.X.SubstructureRedirectMask | 
48                 Xlib.X.SubstructureNotifyMask)
49         self.list.root.send_event(msg, event_mask = mask)
50         self.list.display.flush()
51         
52 class winlist:
53     def __init__(self):
54         self.display = Xlib.display.Display()
55         self.root = self.display.screen().root
56         self.winfo = {}
57         self.windows = ()
58         self.WM_STRUT = self.display.intern_atom('_NET_WM_STRUT')
59         self.CARDINAL = self.display.intern_atom('CARDINAL')
60         self.ACTIVE_WINDOW = self.display.intern_atom('_NET_ACTIVE_WINDOW')
61         self.CLOSE_WINDOW = self.display.intern_atom('_NET_CLOSE_WINDOW')
62         self.NAME = self.display.intern_atom('WM_NAME')
63         self.STRING = self.display.intern_atom('STRING')
64         self.PID = self.display.intern_atom('_NET_WM_PID')
65         self.LIST = self.display.intern_atom('_NET_CLIENT_LIST_STACKING')
66         self.WINDOW = self.display.intern_atom('WINDOW')
67
68         self.fd = self.display.fileno()
69         self.change_handle = None
70
71         self.root.change_attributes(event_mask = Xlib.X.PropertyChangeMask )
72         self.get_list()
73         
74
75     def add_win(self, id):
76         if id in self.winfo:
77             return self.winfo[id]
78         w = self.display.create_resource_object('window', id)
79         p = w.get_property(self.WM_STRUT, self.CARDINAL, 0, 100)
80         self.winfo[id] = None
81         if p:
82             return None
83         p = w.get_property(self.NAME, self.STRING, 0, 100)
84         if p and p.format == 8:
85             name = p.value
86             name = name.replace('&','&')
87             name = name.replace('<','&lt;')
88             name = name.replace('>','&gt;')
89         else:
90             return None
91
92         p = w.get_property(self.PID, self.CARDINAL, 0, 100)
93         if p and p.format == 32:
94             pid = p.value[0]
95         else:
96             pid = 0
97
98         self.winfo[id] = mywindow(w, name, pid, self)
99         return self.winfo[id]
100
101
102     def get_list(self):
103         l = self.root.get_property(self.LIST, self.WINDOW, 0, 100)
104         windows = []
105         for w in l.value:
106             if self.add_win(w):
107                 windows.append(w)
108         self.windows = windows
109         self.clean_winfo()
110         if self.change_handle:
111             self.change_handle()
112
113     def clean_winfo(self):
114         togo = []
115         for w in self.winfo:
116             if w not in self.windows:
117                 togo.append(w)
118         for w in togo:
119             del self.winfo[w]
120
121     def events(self, *a):
122         i = self.display.pending_events()
123         while i > 0:
124             event = self.display.next_event()
125             self.handle_event(event)
126             i = i - 1
127         return True
128
129     def handle_event(self, event):
130         if event.atom != self.LIST:
131             return False
132         self.get_list()
133         return True
134
135     def top(self, num = 0):
136         if num > len(self.windows) or num < 0:
137             return None
138         return self.winfo[self.windows[-1-num]]
139
140     def on_change(self, func):
141         self.change_handle = func
142         
143
144 if __name__ == '__main__':
145     w = winlist()
146     for i in w.winfo:
147         print i, w.winfo[i].name
148     while 1:
149         event = w.display.next_event()
150         if w.handle_event(event):
151             print "First is", w.top(1).name
152             w.top(1).raise_win()
153