]> Dogcows Code - chaz/openbox/blob - python/stackedcycle.py
merge the C branch into HEAD
[chaz/openbox] / python / stackedcycle.py
1 import ob, config, hooks, focus
2 from input import Pointer, Keyboard
3
4 config.add('stackedcycle',
5 'activate_while_cycling',
6 'Activate While Cycling',
7 "If this is True then windows will be activated as they are" + \
8 "highlighted in the cycling list (except iconified windows).",
9 'boolean',
10 True)
11
12 config.add('stackedcycle',
13 'raise_window',
14 'Raise After Cycling',
15 "If this is True, the selected window will be raised as well as " +\
16 "focused.",
17 'boolean',
18 True)
19
20 config.add('stackedcycle',
21 'include_all_desktops',
22 'Include Windows From All Desktops',
23 "If this is True then windows from all desktops will be included" +\
24 " in the stacking list.",
25 'boolean',
26 False)
27
28 config.add('stackedcycle',
29 'include_icons',
30 'Include Icons',
31 "If this is True then windows which are iconified on the current" +\
32 " desktop will be included in the stacking list.",
33 'boolean',
34 False)
35
36 config.add('stackedcycle',
37 'include_icons_all_desktops',
38 'Include Icons From All Desktops',
39 "If this is True then windows which are iconified from all " +\
40 "desktops will be included in the stacking list (if Include Icons"+\
41 " is also True).",
42 'boolean',
43 True)
44
45 config.add('stackedcycle',
46 'include_omnipresent',
47 'Include Omnipresent Windows',
48 "If this is True then windows which are on all-desktops at once " +\
49 "will be included in the stacking list.",
50 'boolean',
51 True)
52
53 def next(keydata, client): _cycle(keydata, client, True)
54 def previous(keydata, client): _cycle(keydata, client, False)
55
56 def _shouldAdd(client):
57 """Determines if a client should be added to the cycling list."""
58 curdesk = ob.Openbox.desktop()
59 desk = client.desktop()
60
61 if not (client.normal() and client.canFocus()): return False
62 if config.get('focus', 'avoid_skip_taskbar') and client.skipTaskbar():
63 return False
64
65 if client.iconic():
66 if config.get('stackedcycle', 'include_icons'):
67 if config.get('stackedcycle', 'include_icons_all_desktops'):
68 return True
69 if desk == curdesk: return True
70 return False
71 if config.get('stackedcycle', 'include_omnipresent') and \
72 desk == 0xffffffff: return True
73 if config.get('stackedcycle', 'include_all_desktops'): return True
74 if desk == curdesk: return True
75
76 return False
77
78 def _populateItems():
79 global _items
80 # get the list of clients, keeping iconic windows at the bottom
81 _items = []
82 iconic_clients = []
83 for c in focus._clients:
84 if _shouldAdd(c):
85 if c.iconic(): iconic_clients.append(c)
86 else: _items.append(c)
87 _items.extend(iconic_clients)
88
89 def _populate():
90 global _pos, _items
91 try:
92 current = _items[_pos]
93 except IndexError:
94 current = None
95 oldpos = _pos
96 _pos = -1
97
98 _populateItems()
99
100 i = 0
101 for item in _items:
102 # current item might have shifted after a populateItems()
103 # call, so we need to do this test.
104 if current == item:
105 _pos = i
106 i += 1
107
108 # The item we were on might be gone entirely
109 if _pos < 0:
110 # try stay at the same spot in the menu
111 if oldpos >= len(_items):
112 _pos = len(_items) - 1
113 else:
114 _pos = oldpos
115
116
117 def _activate(final):
118 """
119 Activates (focuses and, if the user requested it, raises a window).
120 If final is True, then this is the very last window we're activating
121 and the user has finished cycling.
122 """
123 print "_activate"
124 try:
125 client = _items[_pos]
126 except IndexError: return # empty list
127 print client
128
129 # move the to client's desktop if required
130 if not (client.iconic() or client.desktop() == 0xffffffff or \
131 client.desktop() == ob.Openbox.desktop()):
132 ob.Openbox.setDesktop(client.desktop())
133
134 if final or not client.iconic():
135 if final: r = config.get('stackedcycle', 'raise_window')
136 else: r = False
137 client.focus(True)
138 if final and client.shaded(): client.setShaded(False)
139 print "final", final, "raising", r
140 if r: client.raiseWindow()
141 if not final:
142 focus._skip += 1
143
144 def _cycle(keydata, client, forward):
145 global _cycling, _state, _pos, _inititem, _items
146
147 if not _cycling:
148 _items = [] # so it doesnt try start partway through the list
149 _populate()
150
151 if not _items: return # don't bother doing anything
152
153 Keyboard.grab(_grabfunc)
154 # the pointer grab causes pointer events during the keyboard grab
155 # to go away, which means we don't get enter notifies when the
156 # popup disappears, screwing up the focus
157 Pointer.grabPointer(True)
158
159 _cycling = True
160 _state = keydata.state
161 _pos = 0
162 _inititem = _items[_pos]
163
164 if forward:
165 _pos += 1
166 else:
167 _pos -= 1
168 # wrap around
169 if _pos < 0: _pos = len(_items) - 1
170 elif _pos >= len(_items): _pos = 0
171 if config.get('stackedcycle', 'activate_while_cycling'):
172 _activate(False) # activate, but dont deiconify/unshade/raise
173
174 def _grabfunc(keydata, client):
175 global _cycling
176
177 done = False
178 notreverting = True
179 # have all the modifiers this started with been released?
180 if not _state & keydata.state:
181 done = True
182 elif keydata.press:
183 # has Escape been pressed?
184 if keydata.keychain == "Escape":
185 done = True
186 notreverting = False
187 # revert
188 try:
189 _pos = _items.index(_inititem)
190 except:
191 _pos = -1
192 # has Enter been pressed?
193 elif keydata.keychain == "Return":
194 done = True
195
196 if done:
197 # activate, and deiconify/unshade/raise
198 _activate(notreverting)
199 _cycling = False
200 Keyboard.ungrab()
201 Pointer.grabPointer(False)
202
203
204 _cycling = False
205 _pos = 0
206 _inititem = None
207 _items = []
208 _state = 0
209
210 def _newwin(data):
211 if _cycling: _populate()
212 def _closewin(data):
213 if _cycling: _populate()
214
215 hooks.managed.append(_newwin)
216 hooks.closed.append(_closewin)
This page took 0.047471 seconds and 4 git commands to generate.