]> Dogcows Code - chaz/openbox/blob - openbox/focus.c
remove debug print
[chaz/openbox] / openbox / focus.c
1 #include "debug.h"
2 #include "event.h"
3 #include "openbox.h"
4 #include "grab.h"
5 #include "framerender.h"
6 #include "client.h"
7 #include "config.h"
8 #include "frame.h"
9 #include "screen.h"
10 #include "group.h"
11 #include "prop.h"
12 #include "focus.h"
13 #include "stacking.h"
14 #include "popup.h"
15
16 #include <X11/Xlib.h>
17 #include <glib.h>
18 #include <assert.h>
19
20 ObClient *focus_client;
21 GList **focus_order; /* these lists are created when screen_startup
22 sets the number of desktops */
23 ObClient *focus_cycle_target;
24
25 static ObIconPopup *focus_cycle_popup;
26
27 void focus_startup(gboolean reconfig)
28 {
29 focus_cycle_popup = icon_popup_new(TRUE);
30
31 if (!reconfig)
32 /* start with nothing focused */
33 focus_set_client(NULL);
34 }
35
36 void focus_shutdown(gboolean reconfig)
37 {
38 guint i;
39
40 icon_popup_free(focus_cycle_popup);
41
42 if (!reconfig) {
43 for (i = 0; i < screen_num_desktops; ++i)
44 g_list_free(focus_order[i]);
45 g_free(focus_order);
46
47 /* reset focus to root */
48 XSetInputFocus(ob_display, PointerRoot, RevertToPointerRoot,
49 event_lasttime);
50 }
51 }
52
53 static void push_to_top(ObClient *client)
54 {
55 guint desktop;
56
57 desktop = client->desktop;
58 if (desktop == DESKTOP_ALL) desktop = screen_desktop;
59 focus_order[desktop] = g_list_remove(focus_order[desktop], client);
60 focus_order[desktop] = g_list_prepend(focus_order[desktop], client);
61 }
62
63 void focus_set_client(ObClient *client)
64 {
65 Window active;
66 ObClient *old;
67
68 #ifdef DEBUG_FOCUS
69 ob_debug("focus_set_client 0x%lx\n", client ? client->window : 0);
70 #endif
71
72 /* uninstall the old colormap, and install the new one */
73 screen_install_colormap(focus_client, FALSE);
74 screen_install_colormap(client, TRUE);
75
76 if (client == NULL) {
77 /* when nothing will be focused, send focus to the backup target */
78 XSetInputFocus(ob_display, screen_support_win, RevertToPointerRoot,
79 event_lasttime);
80 XSync(ob_display, FALSE);
81 }
82
83 /* in the middle of cycling..? kill it. */
84 if (focus_cycle_target)
85 focus_cycle(TRUE, TRUE, TRUE, TRUE, TRUE);
86
87 old = focus_client;
88 focus_client = client;
89
90 /* move to the top of the list */
91 if (client != NULL)
92 push_to_top(client);
93
94 /* set the NET_ACTIVE_WINDOW hint, but preserve it on shutdown */
95 if (ob_state() != OB_STATE_EXITING) {
96 active = client ? client->window : None;
97 PROP_SET32(RootWindow(ob_display, ob_screen),
98 net_active_window, window, active);
99 }
100 }
101
102 static gboolean focus_under_pointer()
103 {
104 int x, y;
105 GList *it;
106
107 if (screen_pointer_pos(&x, &y)) {
108 for (it = stacking_list; it != NULL; it = it->next) {
109 if (WINDOW_IS_CLIENT(it->data)) {
110 ObClient *c = WINDOW_AS_CLIENT(it->data);
111 if (c->desktop == screen_desktop &&
112 RECT_CONTAINS(c->frame->area, x, y))
113 break;
114 }
115 }
116 if (it != NULL) {
117 g_assert(WINDOW_IS_CLIENT(it->data));
118 return client_normal(it->data) && client_focus(it->data);
119 }
120 }
121 return FALSE;
122 }
123
124 /* finds the first transient that isn't 'skip' and ensure's that client_normal
125 is true for it */
126 static ObClient *find_transient_recursive(ObClient *c, ObClient *top, ObClient *skip)
127 {
128 GSList *it;
129 ObClient *ret;
130
131 for (it = c->transients; it; it = it->next) {
132 if (it->data == top) return NULL;
133 ret = find_transient_recursive(it->data, top, skip);
134 if (ret && ret != skip && client_normal(ret)) return ret;
135 if (it->data != skip && client_normal(it->data)) return it->data;
136 }
137 return NULL;
138 }
139
140 static gboolean focus_fallback_transient(ObClient *top, ObClient *old)
141 {
142 ObClient *target = find_transient_recursive(top, top, old);
143 if (!target) {
144 /* make sure client_normal is true always */
145 if (!client_normal(top))
146 return FALSE;
147 target = top; /* no transient, keep the top */
148 }
149 return client_focus(target);
150 }
151
152 void focus_fallback(ObFocusFallbackType type)
153 {
154 GList *it;
155 ObClient *old = NULL;
156
157 old = focus_client;
158
159 /* unfocus any focused clients.. they can be focused by Pointer events
160 and such, and then when I try focus them, I won't get a FocusIn event
161 at all for them.
162 */
163 focus_set_client(NULL);
164
165 if (!(type == OB_FOCUS_FALLBACK_DESKTOP ?
166 config_focus_last_on_desktop : config_focus_last)) {
167 if (config_focus_follow) focus_under_pointer();
168 return;
169 }
170
171 if (type == OB_FOCUS_FALLBACK_UNFOCUSING && old) {
172 /* try for transient relations */
173 if (old->transient_for) {
174 if (old->transient_for == OB_TRAN_GROUP) {
175 for (it = focus_order[screen_desktop]; it; it = it->next) {
176 GSList *sit;
177
178 for (sit = old->group->members; sit; sit = sit->next)
179 if (sit->data == it->data)
180 if (focus_fallback_transient(sit->data, old))
181 return;
182 }
183 } else {
184 if (focus_fallback_transient(old->transient_for, old))
185 return;
186 }
187 }
188
189 #if 0
190 /* try for group relations */
191 if (old->group) {
192 GSList *sit;
193
194 for (it = focus_order[screen_desktop]; it != NULL; it = it->next)
195 for (sit = old->group->members; sit; sit = sit->next)
196 if (sit->data == it->data)
197 if (sit->data != old && client_normal(sit->data))
198 if (client_can_focus(sit->data)) {
199 gboolean r = client_focus(sit->data);
200 assert(r);
201 return;
202 }
203 }
204 #endif
205 }
206
207 for (it = focus_order[screen_desktop]; it != NULL; it = it->next)
208 if (type != OB_FOCUS_FALLBACK_UNFOCUSING || it->data != old)
209 if (client_normal(it->data) &&
210 /* dont fall back to 'anonymous' fullscreen windows. theres no
211 checks for this is in transient/group fallbacks, so they can
212 be fallback targets there. */
213 !((ObClient*)it->data)->fullscreen &&
214 client_can_focus(it->data)) {
215 gboolean r = client_focus(it->data);
216 assert(r);
217 return;
218 }
219
220 /* nothing to focus, and already set it to none above */
221 }
222
223 static void popup_cycle(ObClient *c, gboolean show)
224 {
225 if (!show) {
226 icon_popup_hide(focus_cycle_popup);
227 } else {
228 Rect *a;
229 ObClient *p = c;
230 char *title;
231
232 a = screen_physical_area_monitor(0);
233 icon_popup_position(focus_cycle_popup, CenterGravity,
234 a->x + a->width / 2, a->y + a->height / 2);
235 /* icon_popup_size(focus_cycle_popup, a->height/2, a->height/16);
236 icon_popup_show(focus_cycle_popup, c->title,
237 client_icon(c, a->height/16, a->height/16));
238 */
239 /* XXX the size and the font extents need to be related on some level
240 */
241 icon_popup_size(focus_cycle_popup, POPUP_WIDTH, POPUP_HEIGHT);
242
243 /* use the transient's parent's title/icon */
244 while (p->transient_for && p->transient_for != OB_TRAN_GROUP)
245 p = p->transient_for;
246
247 if (p == c)
248 title = NULL;
249 else
250 title = g_strconcat((c->iconic ? c->icon_title : c->title),
251 " - ",
252 (p->iconic ? p->icon_title : p->title),
253 NULL);
254
255 icon_popup_show(focus_cycle_popup,
256 (title ? title :
257 (c->iconic ? c->icon_title : c->title)),
258 client_icon(p, 48, 48));
259 g_free(title);
260 }
261 }
262
263 void focus_cycle(gboolean forward, gboolean linear,
264 gboolean dialog, gboolean done, gboolean cancel)
265 {
266 static ObClient *first = NULL;
267 static ObClient *t = NULL;
268 static GList *order = NULL;
269 GList *it, *start, *list;
270 ObClient *ft;
271
272 if (cancel) {
273 if (focus_cycle_target)
274 frame_adjust_focus(focus_cycle_target->frame, FALSE);
275 if (focus_client)
276 frame_adjust_focus(focus_client->frame, TRUE);
277 focus_cycle_target = NULL;
278 goto done_cycle;
279 } else if (done && dialog) {
280 goto done_cycle;
281 }
282
283 if (!focus_order[screen_desktop])
284 goto done_cycle;
285
286 if (!first) first = focus_order[screen_desktop]->data;
287 if (!focus_cycle_target) focus_cycle_target =
288 focus_order[screen_desktop]->data;
289
290 if (linear) list = client_list;
291 else list = focus_order[screen_desktop];
292
293 start = it = g_list_find(list, focus_cycle_target);
294 if (!start) /* switched desktops or something? */
295 start = it = forward ? g_list_last(list) : g_list_first(list);
296 if (!start) goto done_cycle;
297
298 do {
299 if (forward) {
300 it = it->next;
301 if (it == NULL) it = g_list_first(list);
302 } else {
303 it = it->prev;
304 if (it == NULL) it = g_list_last(list);
305 }
306 /*ft = client_focus_target(it->data);*/
307 ft = it->data;
308 /* we don't use client_can_focus here, because that doesn't let you
309 focus an iconic window, but we want to be able to, so we just check
310 if the focus flags on the window allow it, and its on the current
311 desktop */
312 if (ft->transients == NULL && client_normal(ft) &&
313 ((ft->can_focus || ft->focus_notify) &&
314 !ft->skip_taskbar &&
315 (ft->desktop == screen_desktop || ft->desktop == DESKTOP_ALL))) {
316 if (ft != focus_cycle_target) { /* prevents flicker */
317 if (focus_cycle_target)
318 frame_adjust_focus(focus_cycle_target->frame, FALSE);
319 focus_cycle_target = ft;
320 frame_adjust_focus(focus_cycle_target->frame, TRUE);
321 }
322 popup_cycle(ft, dialog);
323 return;
324 }
325 } while (it != start);
326
327 done_cycle:
328 if (done && focus_cycle_target)
329 client_activate(focus_cycle_target, FALSE);
330
331 t = NULL;
332 first = NULL;
333 focus_cycle_target = NULL;
334 g_list_free(order);
335 order = NULL;
336
337 popup_cycle(ft, FALSE);
338
339 return;
340 }
341
342 void focus_directional_cycle(ObDirection dir,
343 gboolean dialog, gboolean done, gboolean cancel)
344 {
345 static ObClient *first = NULL;
346 ObClient *ft;
347
348 if (cancel) {
349 if (focus_cycle_target)
350 frame_adjust_focus(focus_cycle_target->frame, FALSE);
351 if (focus_client)
352 frame_adjust_focus(focus_client->frame, TRUE);
353 focus_cycle_target = NULL;
354 goto done_cycle;
355 } else if (done && dialog) {
356 goto done_cycle;
357 }
358
359 if (!focus_order[screen_desktop])
360 goto done_cycle;
361
362 if (!first) first = focus_order[screen_desktop]->data;
363 if (!focus_cycle_target) focus_cycle_target =
364 focus_order[screen_desktop]->data;
365
366 if ((ft = client_find_directional(focus_cycle_target, dir))) {
367 if (ft != focus_cycle_target) {/* prevents flicker */
368 if (focus_cycle_target)
369 frame_adjust_focus(focus_cycle_target->frame, FALSE);
370 focus_cycle_target = ft;
371 frame_adjust_focus(focus_cycle_target->frame, TRUE);
372 }
373 popup_cycle(ft, dialog);
374 }
375 if (dialog)
376 return;
377
378 done_cycle:
379 if (done && focus_cycle_target)
380 client_activate(focus_cycle_target, FALSE);
381
382 first = NULL;
383 focus_cycle_target = NULL;
384
385 popup_cycle(ft, FALSE);
386
387 return;
388 }
389
390 void focus_order_add_new(ObClient *c)
391 {
392 guint d, i;
393
394 if (c->iconic)
395 focus_order_to_top(c);
396 else {
397 d = c->desktop;
398 if (d == DESKTOP_ALL) {
399 for (i = 0; i < screen_num_desktops; ++i) {
400 if (focus_order[i] && ((ObClient*)focus_order[i]->data)->iconic)
401 focus_order[i] = g_list_insert(focus_order[i], c, 0);
402 else
403 focus_order[i] = g_list_insert(focus_order[i], c, 1);
404 }
405 } else
406 if (focus_order[d] && ((ObClient*)focus_order[d]->data)->iconic)
407 focus_order[d] = g_list_insert(focus_order[d], c, 0);
408 else
409 focus_order[d] = g_list_insert(focus_order[d], c, 1);
410 }
411 }
412
413 void focus_order_remove(ObClient *c)
414 {
415 guint d, i;
416
417 d = c->desktop;
418 if (d == DESKTOP_ALL) {
419 for (i = 0; i < screen_num_desktops; ++i)
420 focus_order[i] = g_list_remove(focus_order[i], c);
421 } else
422 focus_order[d] = g_list_remove(focus_order[d], c);
423 }
424
425 static void to_top(ObClient *c, guint d)
426 {
427 focus_order[d] = g_list_remove(focus_order[d], c);
428 if (!c->iconic) {
429 focus_order[d] = g_list_prepend(focus_order[d], c);
430 } else {
431 GList *it;
432
433 /* insert before first iconic window */
434 for (it = focus_order[d];
435 it && !((ObClient*)it->data)->iconic; it = it->next);
436 focus_order[d] = g_list_insert_before(focus_order[d], it, c);
437 }
438 }
439
440 void focus_order_to_top(ObClient *c)
441 {
442 guint d, i;
443
444 d = c->desktop;
445 if (d == DESKTOP_ALL) {
446 for (i = 0; i < screen_num_desktops; ++i)
447 to_top(c, i);
448 } else
449 to_top(c, d);
450 }
451
452 static void to_bottom(ObClient *c, guint d)
453 {
454 focus_order[d] = g_list_remove(focus_order[d], c);
455 if (c->iconic) {
456 focus_order[d] = g_list_append(focus_order[d], c);
457 } else {
458 GList *it;
459
460 /* insert before first iconic window */
461 for (it = focus_order[d];
462 it && !((ObClient*)it->data)->iconic; it = it->next);
463 g_list_insert_before(focus_order[d], it, c);
464 }
465 }
466
467 void focus_order_to_bottom(ObClient *c)
468 {
469 guint d, i;
470
471 d = c->desktop;
472 if (d == DESKTOP_ALL) {
473 for (i = 0; i < screen_num_desktops; ++i)
474 to_bottom(c, i);
475 } else
476 to_bottom(c, d);
477 }
This page took 0.056334 seconds and 4 git commands to generate.