3 # manage a list of current windows and allow a selected
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)
15 import Xlib.protocol.event
18 def __init__(self, win, name, pid, id, list):
26 msg = Xlib.protocol.event.ClientMessage(window = self.win,
27 client_type = self.list.ACTIVE_WINDOW,
28 data = (32, [0,0,0,0,0])
31 mask = (Xlib.X.SubstructureRedirectMask |
32 Xlib.X.SubstructureNotifyMask)
33 self.list.root.send_event(msg, event_mask = mask)
35 self.win.raise_window()
36 #p = w.query_tree().parent
40 self.list.display.flush()
43 msg = Xlib.protocol.event.ClientMessage(window = self.win,
44 client_type = self.list.CLOSE_WINDOW,
45 data = (32, [0,0,0,0,0])
48 mask = (Xlib.X.SubstructureRedirectMask |
49 Xlib.X.SubstructureNotifyMask)
50 self.list.root.send_event(msg, event_mask = mask)
51 self.list.display.flush()
54 def __init__(self, add_handle = None):
55 self.display = Xlib.display.Display()
56 self.root = self.display.screen().root
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')
69 self.fd = self.display.fileno()
70 self.change_handle = None
71 self.add_handle = add_handle
72 self.del_handle = None
74 self.root.change_attributes(event_mask = Xlib.X.PropertyChangeMask )
78 def add_win(self, id):
81 w = self.display.create_resource_object('window', id)
82 p = w.get_property(self.WM_STRUT, self.CARDINAL, 0, 100)
86 p = w.get_property(self.NAME, self.STRING, 0, 100)
87 if p and p.format == 8:
89 name = name.replace('&','&')
90 name = name.replace('<','<')
91 name = name.replace('>','>')
95 p = w.get_property(self.PID, self.CARDINAL, 0, 100)
96 if p and p.format == 32:
101 self.winfo[id] = mywindow(w, name, pid, id, self)
104 self.add_handle(self.winfo[id])
105 return self.winfo[id]
109 l = self.root.get_property(self.LIST, self.WINDOW, 0, 100)
114 self.windows = windows
116 if self.change_handle:
119 def clean_winfo(self):
122 if w not in self.windows:
129 def events(self, *a):
130 i = self.display.pending_events()
132 event = self.display.next_event()
133 self.handle_event(event)
137 def handle_event(self, event):
138 if event.atom != self.LIST:
143 def top(self, num = 0):
144 if num > len(self.windows) or num < 0:
146 return self.winfo[self.windows[-1-num]]
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
154 if __name__ == '__main__':
157 print i, w.winfo[i].name
159 event = w.display.next_event()
160 if w.handle_event(event):
161 print "First is", w.top(1).name