]> git.neil.brown.name Git - plato.git/blob - lib/wmctrl.py
Remove some more white space
[plato.git] / lib / 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, id, list):
19         self.id = id
20         self.win = win
21         self.name = name
22         self.pid = pid
23         self.list = list
24
25     def raise_win(self):
26         msg = Xlib.protocol.event.ClientMessage(window = self.win,
27                                                 client_type = self.list.ACTIVE_WINDOW,
28                                                 data = (32, [0,0,0,0,0])
29                                                 )
30         msg.send_event = 1
31         mask = (Xlib.X.SubstructureRedirectMask |
32                 Xlib.X.SubstructureNotifyMask)
33         self.list.root.send_event(msg, event_mask = mask)
34         self.win.map()
35         self.win.raise_window()
36         #p = w.query_tree().parent
37         #if p:
38         #    p.map()
39         #    p.raise_window()
40         self.list.display.flush()
41
42     def close_win(self):
43         msg = Xlib.protocol.event.ClientMessage(window = self.win,
44                                                 client_type = self.list.CLOSE_WINDOW,
45                                                 data = (32, [0,0,0,0,0])
46                                                 )
47         msg.send_event = 1
48         mask = (Xlib.X.SubstructureRedirectMask |
49                 Xlib.X.SubstructureNotifyMask)
50         self.list.root.send_event(msg, event_mask = mask)
51         self.list.display.flush()
52
53 class winlist:
54     def __init__(self, add_handle = None):
55         self.display = Xlib.display.Display()
56         self.root = self.display.screen().root
57         self.winfo = {}
58         self.windows = ()
59         self.WM_STRUT = self.display.intern_atom('_NET_WM_STRUT')
60         self.CARDINAL = self.display.intern_atom('CARDINAL')
61         self.ACTIVE_WINDOW = self.display.intern_atom('_NET_ACTIVE_WINDOW')
62         self.CLOSE_WINDOW = self.display.intern_atom('_NET_CLOSE_WINDOW')
63         self.NAME = self.display.intern_atom('WM_NAME')
64         self.STRING = self.display.intern_atom('STRING')
65         self.PID = self.display.intern_atom('_NET_WM_PID')
66         self.LIST = self.display.intern_atom('_NET_CLIENT_LIST_STACKING')
67         self.WINDOW = self.display.intern_atom('WINDOW')
68
69         self.fd = self.display.fileno()
70         self.change_handle = None
71         self.add_handle = add_handle
72         self.del_handle = None
73
74         self.root.change_attributes(event_mask = Xlib.X.PropertyChangeMask )
75         self.get_list()
76
77
78     def add_win(self, id):
79         if id in self.winfo:
80             return self.winfo[id]
81         w = self.display.create_resource_object('window', id)
82         p = w.get_property(self.WM_STRUT, self.CARDINAL, 0, 100)
83         self.winfo[id] = None
84         if p:
85             return None
86         p = w.get_property(self.NAME, self.STRING, 0, 100)
87         if p and p.format == 8:
88             name = p.value
89             name = name.replace('&','&')
90             name = name.replace('<','&lt;')
91             name = name.replace('>','&gt;')
92         else:
93             return None
94
95         p = w.get_property(self.PID, self.CARDINAL, 0, 100)
96         if p and p.format == 32:
97             pid = p.value[0]
98         else:
99             pid = 0
100
101         self.winfo[id] = mywindow(w, name, pid, id, self)
102
103         if self.add_handle:
104             self.add_handle(self.winfo[id])
105         return self.winfo[id]
106
107
108     def get_list(self):
109         l = self.root.get_property(self.LIST, self.WINDOW, 0, 100)
110         windows = []
111         for w in l.value:
112             if self.add_win(w):
113                 windows.append(w)
114         self.windows = windows
115         self.clean_winfo()
116         if self.change_handle:
117             self.change_handle()
118
119     def clean_winfo(self):
120         togo = []
121         for w in self.winfo:
122             if w not in self.windows:
123                 togo.append(w)
124         for w in togo:
125             del self.winfo[w]
126             if self.del_handle:
127                 self.del_handle(w)
128
129     def events(self, *a):
130         i = self.display.pending_events()
131         while i > 0:
132             event = self.display.next_event()
133             self.handle_event(event)
134             i = i - 1
135         return True
136
137     def handle_event(self, event):
138         if event.atom != self.LIST:
139             return False
140         self.get_list()
141         return True
142
143     def top(self, num = 0):
144         if num > len(self.windows) or num < 0:
145             return None
146         return self.winfo[self.windows[-1-num]]
147
148     def on_change(self, func, add=None, delete=None):
149         self.change_handle = func
150         self.add_handle = add
151         self.del_handle = delete
152
153
154 if __name__ == '__main__':
155     w = winlist()
156     for i in w.winfo:
157         print i, w.winfo[i].name
158     while 1:
159         event = w.display.next_event()
160         if w.handle_event(event):
161             print "First is", w.top(1).name
162             w.top(1).raise_win()
163