]> icculus.org git repositories - mikachu/openbox.git/blob - scripts/focus.py
stacked_cycle_popup_list done
[mikachu/openbox.git] / scripts / focus.py
1 ###########################################################################
2 ###          Functions for helping out with your window focus.          ###
3 ###########################################################################
4
5 ###########################################################################
6 ###         Options that affect the behavior of the focus module.       ###
7 ###                                                                     ###
8 # raise the window also when it is focused                              ###
9 cycle_raise = 1                                                         ###
10 # raise as you cycle in stacked mode                                    ###
11 stacked_cycle_raise = 0                                                 ###
12 # show a pop-up list of windows while cycling                           ###
13 stacked_cycle_popup_list = 1                                            ###
14 # send focus somewhere when nothing is left with the focus, if possible ###
15 fallback = 0                                                            ###
16 ###                                                                     ###
17 ###########################################################################
18
19 import otk
20 import ob
21
22 # maintain a list of clients, stacked in focus order
23 _clients = []
24 # maintaint he current focused window
25 _doing_stacked = 0
26
27 def _new_win(data):
28     global _clients
29     global _doing_stacked
30     global _cyc_w;
31
32     if _doing_stacked:
33         _clients.insert(_clients.index(_cyc_w), data.client.window())
34         _create_popup_list(data)
35         _hilite_popup_list()
36     else:
37         if not len(_clients):
38             _clients.append(data.client.window())
39         else:
40             _clients.insert(1, data.client.window()) # insert in 2nd slot
41
42 def _close_win(data):
43     global _clients
44     global _cyc_w;
45     global _doing_stacked
46
47     if not _doing_stacked:
48         # not in the middle of stacked cycling, so who cares
49         _clients.remove(data.client.window())
50     else:
51         # have to fix the cycling if we remove anything
52         win = data.client.window()
53         if _cyc_w == win:
54             _do_stacked_cycle(data, 1) # cycle off the window first, forward
55         _clients.remove(win)
56         _create_popup_list(data)
57
58 def _focused(data):
59     global _clients
60     global _doing_stacked
61     global _cyc_w
62     
63     if data.client:
64         if not _doing_stacked: # only move the window when we're not cycling
65             win = data.client.window()
66             # move it to the top
67             _clients.remove(win)
68             _clients.insert(0, win)
69         else: # if we are cycling, then update our pointer
70             _cyc_w = data.client.window()
71             _hilite_popup_list()
72     elif fallback: 
73         # pass around focus
74         desktop = ob.openbox.screen(_cyc_screen).desktop()
75         for w in _clients:
76             client = ob.openbox.findClient(w)
77             if client and (client.desktop() == desktop and \
78                            client.normal() and client.focus()):
79                 break
80
81 _cyc_mask = 0
82 _cyc_key = 0
83 _cyc_w = 0 # last window cycled to
84 _cyc_screen = 0
85
86 def _do_stacked_cycle(data, forward):
87     global _cyc_w
88     global stacked_cycle_raise
89     global _clients
90
91     clients = _clients[:] # make a copy
92
93     if not forward:
94         clients.reverse()
95
96     try:
97         i = clients.index(_cyc_w) + 1
98     except ValueError:
99         i = 1
100     clients = clients[i:] + clients[:i]
101         
102     desktop = ob.openbox.screen(data.screen).desktop()
103     for w in clients:
104         client = ob.openbox.findClient(w)
105         if client and (client.desktop() == desktop and \
106                        client.normal() and client.focus()):
107             if stacked_cycle_raise:
108                 ob.openbox.screen(data.screen).raiseWindow(client)
109             return
110
111 def _focus_stacked_ungrab(data):
112     global _cyc_mask;
113     global _cyc_key;
114     global _doing_stacked;
115
116     if data.action == ob.KeyAction.Release:
117         # have all the modifiers this started with been released?
118         if not _cyc_mask & data.state:
119             ob.kungrab() # ungrab ourself
120             _doing_stacked = 0;
121             if cycle_raise:
122                 client = ob.openbox.findClient(_cyc_w)
123                 if client:
124                     ob.openbox.screen(data.screen).raiseWindow(client)
125             _destroy_popup_list()
126
127 _list_widget = 0
128 _list_labels = []
129 _list_windows = []
130
131 def _hilite_popup_list():
132     global _cyc_w
133     global _list_widget, _list_labels, _list_windows
134     if _list_widget:
135         i = 0
136         for w in _list_windows:
137             if w == _cyc_w: _list_labels[i].focus()
138             else: _list_labels[i].unfocus()
139             i += 1
140
141 def _destroy_popup_list():
142     global _list_widget, _list_labels, _list_windows
143     if _list_widget:
144         _list_windows = []
145         _list_labels = []
146         _list_widget = 0
147     
148 def _create_popup_list(data):
149     global _list_widget, _list_labels, _list_windows, _clients
150
151     if _list_widget:
152         _destroy_popup_list()
153     
154     style = ob.openbox.screen(data.screen).style()
155     _list_widget = otk.Widget(ob.openbox, style,
156                               otk.Widget.Vertical, 0,
157                               style.bevelWidth(), 1)
158     t = style.titlebarFocusBackground()
159     _list_widget.setTexture(t)
160
161     titles = []
162     font = style.labelFont()
163     height = font.height()
164     longest = 0
165     for c in _clients:
166         client = ob.openbox.findClient(c)
167         desktop = ob.openbox.screen(data.screen).desktop()
168         if client and (client.desktop() == desktop and \
169                        client.normal()):
170             t = client.title()
171             if len(t) > 50: # limit the length of titles
172                 t = t[:24] + "..." + t[-24:]
173             titles.append(t)
174             _list_windows.append(c)
175             l = font.measureString(t) + 10 # add margin
176             if l > longest: longest = l
177     if len(titles):
178         for t in titles:
179             w = otk.FocusLabel(_list_widget)
180             w.resize(longest, height)
181             w.setText(t)
182             w.unfocus()
183             _list_labels.append(w)
184         _list_labels[0].focus()
185         _list_widget.update()
186         area = otk.display.screenInfo(data.screen).rect()
187         _list_widget.move(area.x() + (area.width() -
188                                       _list_widget.width()) / 2,
189                           area.y() + (area.height() -
190                                       _list_widget.height()) / 2)
191         _list_widget.show(1)
192     else:
193         _list_widget = 0 #nothing to list
194
195 def focus_next_stacked(data, forward=1):
196     """Focus the next (or previous, with forward=0) window in a stacked
197        order."""
198     global _cyc_mask
199     global _cyc_key
200     global _cyc_w
201     global _cyc_screen
202     global _doing_stacked
203
204     if _doing_stacked:
205         if _cyc_key == data.key:
206             _do_stacked_cycle(data,forward)
207     else:
208         _cyc_mask = data.state
209         _cyc_key = data.key
210         _cyc_w = 0
211         _cyc_screen = data.screen
212         _doing_stacked = 1
213
214         global stacked_cycle_popup_list
215         if stacked_cycle_popup_list:
216             _create_popup_list(data)
217
218         ob.kgrab(data.screen, _focus_stacked_ungrab)
219         focus_next_stacked(data, forward) # start with the first press
220
221 def focus_prev_stacked(data):
222     """Focus the previous window in a stacked order."""
223     focus_next_stacked(data, forward=0)
224
225 def focus_next(data, num=1, forward=1):
226     """Focus the next (or previous, with forward=0) window in a linear
227        order."""
228     screen = ob.openbox.screen(data.screen)
229     count = screen.clientCount()
230
231     if not count: return # no clients
232     
233     target = 0
234     if data.client:
235         client_win = data.client.window()
236         found = 0
237         r = range(count)
238         if not forward:
239             r.reverse()
240         for i in r:
241             if found:
242                 target = i
243                 found = 2
244                 break
245             elif screen.client(i).window() == client_win:
246                 found = 1
247         if found == 1: # wraparound
248             if forward: target = 0
249             else: target = count - 1
250
251     t = target
252     curdesk = screen.desktop()
253     while 1:
254         client = screen.client(t)
255         if client.normal() and \
256                (client.desktop() == curdesk or client.desktop() == 0xffffffff)\
257                and client.focus():
258             if cycle_raise:
259                 screen.raiseWindow(client)
260             return
261         if forward:
262             t += num
263             if t >= count: t -= count
264         else:
265             t -= num
266             if t < 0: t += count
267         if t == target: return # nothing to focus
268
269 def focus_prev(data, num=1):
270     """Focus the previous window in a linear order."""
271     focus_next(data, num, forward=0)
272
273
274 ob.ebind(ob.EventAction.NewWindow, _new_win)
275 ob.ebind(ob.EventAction.CloseWindow, _close_win)
276 ob.ebind(ob.EventAction.Focus, _focused)
277
278 print "Loaded focus.py"