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