]> Dogcows Code - chaz/openbox/blob - openbox/focus.c
7b40db5e585bd1a512a2980afeb96fe2a797e668
[chaz/openbox] / openbox / focus.c
1 /* -*- indent-tabs-mode: nil; tab-width: 4; c-basic-offset: 4; -*-
2
3 focus.c for the Openbox window manager
4 Copyright (c) 2006 Mikael Magnusson
5 Copyright (c) 2003 Ben Jansens
6
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2 of the License, or
10 (at your option) any later version.
11
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
16
17 See the COPYING file for a copy of the GNU General Public License.
18 */
19
20 #include "debug.h"
21 #include "event.h"
22 #include "openbox.h"
23 #include "grab.h"
24 #include "framerender.h"
25 #include "client.h"
26 #include "config.h"
27 #include "frame.h"
28 #include "screen.h"
29 #include "group.h"
30 #include "prop.h"
31 #include "focus.h"
32 #include "stacking.h"
33 #include "popup.h"
34 #include "render/render.h"
35
36 #include <X11/Xlib.h>
37 #include <glib.h>
38 #include <assert.h>
39
40 ObClient *focus_client, *focus_hilite;
41 GList **focus_order; /* these lists are created when screen_startup
42 sets the number of desktops */
43 ObClient *focus_cycle_target;
44
45 struct {
46 InternalWindow top;
47 InternalWindow left;
48 InternalWindow right;
49 InternalWindow bottom;
50 } focus_indicator;
51
52 RrAppearance *a_focus_indicator;
53 RrColor *color_white;
54
55 static ObIconPopup *focus_cycle_popup;
56
57 static void focus_cycle_destructor(ObClient *client, gpointer data)
58 {
59 /* end cycling if the target disappears. CurrentTime is fine, time won't
60 be used
61 */
62 if (focus_cycle_target == client)
63 focus_cycle(TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, CurrentTime);
64 }
65
66 static Window createWindow(Window parent, gulong mask,
67 XSetWindowAttributes *attrib)
68 {
69 return XCreateWindow(ob_display, parent, 0, 0, 1, 1, 0,
70 RrDepth(ob_rr_inst), InputOutput,
71 RrVisual(ob_rr_inst), mask, attrib);
72
73 }
74
75 void focus_startup(gboolean reconfig)
76 {
77 focus_cycle_popup = icon_popup_new(TRUE);
78
79 if (!reconfig) {
80 XSetWindowAttributes attr;
81
82 client_add_destructor(focus_cycle_destructor, NULL);
83
84 /* start with nothing focused */
85 focus_set_client(NULL);
86
87 focus_indicator.top.obwin.type = Window_Internal;
88 focus_indicator.left.obwin.type = Window_Internal;
89 focus_indicator.right.obwin.type = Window_Internal;
90 focus_indicator.bottom.obwin.type = Window_Internal;
91
92 attr.override_redirect = True;
93 attr.background_pixel = BlackPixel(ob_display, ob_screen);
94 focus_indicator.top.win =
95 createWindow(RootWindow(ob_display, ob_screen),
96 CWOverrideRedirect | CWBackPixel, &attr);
97 focus_indicator.left.win =
98 createWindow(RootWindow(ob_display, ob_screen),
99 CWOverrideRedirect | CWBackPixel, &attr);
100 focus_indicator.right.win =
101 createWindow(RootWindow(ob_display, ob_screen),
102 CWOverrideRedirect | CWBackPixel, &attr);
103 focus_indicator.bottom.win =
104 createWindow(RootWindow(ob_display, ob_screen),
105 CWOverrideRedirect | CWBackPixel, &attr);
106
107 stacking_add(INTERNAL_AS_WINDOW(&focus_indicator.top));
108 stacking_add(INTERNAL_AS_WINDOW(&focus_indicator.left));
109 stacking_add(INTERNAL_AS_WINDOW(&focus_indicator.right));
110 stacking_add(INTERNAL_AS_WINDOW(&focus_indicator.bottom));
111
112 color_white = RrColorNew(ob_rr_inst, 0xff, 0xff, 0xff);
113
114 a_focus_indicator = RrAppearanceNew(ob_rr_inst, 4);
115 a_focus_indicator->surface.grad = RR_SURFACE_SOLID;
116 a_focus_indicator->surface.relief = RR_RELIEF_FLAT;
117 a_focus_indicator->surface.primary = RrColorNew(ob_rr_inst,
118 0, 0, 0);
119 a_focus_indicator->texture[0].type = RR_TEXTURE_LINE_ART;
120 a_focus_indicator->texture[0].data.lineart.color = color_white;
121 a_focus_indicator->texture[1].type = RR_TEXTURE_LINE_ART;
122 a_focus_indicator->texture[1].data.lineart.color = color_white;
123 a_focus_indicator->texture[2].type = RR_TEXTURE_LINE_ART;
124 a_focus_indicator->texture[2].data.lineart.color = color_white;
125 a_focus_indicator->texture[3].type = RR_TEXTURE_LINE_ART;
126 a_focus_indicator->texture[3].data.lineart.color = color_white;
127 }
128 }
129
130 void focus_shutdown(gboolean reconfig)
131 {
132 guint i;
133
134 icon_popup_free(focus_cycle_popup);
135
136 if (!reconfig) {
137 client_remove_destructor(focus_cycle_destructor);
138
139 for (i = 0; i < screen_num_desktops; ++i)
140 g_list_free(focus_order[i]);
141 g_free(focus_order);
142
143 /* reset focus to root */
144 XSetInputFocus(ob_display, PointerRoot, RevertToNone, CurrentTime);
145
146 RrColorFree(color_white);
147
148 RrAppearanceFree(a_focus_indicator);
149
150 XDestroyWindow(ob_display, focus_indicator.top.win);
151 XDestroyWindow(ob_display, focus_indicator.left.win);
152 XDestroyWindow(ob_display, focus_indicator.right.win);
153 XDestroyWindow(ob_display, focus_indicator.bottom.win);
154 }
155 }
156
157 static void push_to_top(ObClient *client)
158 {
159 guint desktop;
160
161 desktop = client->desktop;
162 if (desktop == DESKTOP_ALL) desktop = screen_desktop;
163 focus_order[desktop] = g_list_remove(focus_order[desktop], client);
164 focus_order[desktop] = g_list_prepend(focus_order[desktop], client);
165 }
166
167 void focus_set_client(ObClient *client)
168 {
169 Window active;
170 ObClient *old;
171
172 #ifdef DEBUG_FOCUS
173 ob_debug("focus_set_client 0x%lx\n", client ? client->window : 0);
174 #endif
175
176 /* uninstall the old colormap, and install the new one */
177 screen_install_colormap(focus_client, FALSE);
178 screen_install_colormap(client, TRUE);
179
180 if (client == NULL) {
181 #ifdef DEBUG_FOCUS
182 ob_debug("actively focusing NONWINDOW\n");
183 #endif
184 /* when nothing will be focused, send focus to the backup target */
185 XSetInputFocus(ob_display, screen_support_win, RevertToNone,
186 event_curtime);
187 XSync(ob_display, FALSE);
188 }
189
190 /* in the middle of cycling..? kill it. CurrentTime is fine, time won't
191 be used.
192 */
193 if (focus_cycle_target)
194 focus_cycle(TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, CurrentTime);
195
196 old = focus_client;
197 focus_client = client;
198
199 /* move to the top of the list */
200 if (client != NULL)
201 push_to_top(client);
202
203 /* set the NET_ACTIVE_WINDOW hint, but preserve it on shutdown */
204 if (ob_state() != OB_STATE_EXITING) {
205 active = client ? client->window : None;
206 PROP_SET32(RootWindow(ob_display, ob_screen),
207 net_active_window, window, active);
208
209 /* remove hiliting from the window when it gets focused */
210 if (client != NULL)
211 client_hilite(client, FALSE);
212 }
213 }
214
215 /* finds the first transient that isn't 'skip' and ensure's that client_normal
216 is true for it */
217 static ObClient *find_transient_recursive(ObClient *c, ObClient *top,
218 ObClient *skip)
219 {
220 GSList *it;
221 ObClient *ret;
222
223 for (it = c->transients; it; it = g_slist_next(it)) {
224 if (it->data == top) return NULL;
225 ret = find_transient_recursive(it->data, top, skip);
226 if (ret && ret != skip && client_normal(ret)) return ret;
227 if (it->data != skip && client_normal(it->data)) return it->data;
228 }
229 return NULL;
230 }
231
232 static ObClient* focus_fallback_transient(ObClient *top, ObClient *old)
233 {
234 ObClient *target = find_transient_recursive(top, top, old);
235 if (!target) {
236 /* make sure client_normal is true always */
237 if (!client_normal(top))
238 return NULL;
239 target = top; /* no transient, keep the top */
240 }
241 if (client_can_focus(target))
242 return target;
243 else
244 return NULL;
245 }
246
247 ObClient* focus_fallback_target(ObFocusFallbackType type, ObClient *old)
248 {
249 GList *it;
250 ObClient *target = NULL;
251
252 if ((type == OB_FOCUS_FALLBACK_UNFOCUSING
253 || type == OB_FOCUS_FALLBACK_CLOSED) && old) {
254 if (old->transient_for) {
255 gboolean trans = FALSE;
256
257 if (!config_focus_follow || config_focus_last)
258 trans = TRUE;
259 else if ((target = client_under_pointer()) &&
260 (client_search_transient
261 (client_search_top_parent(target), old)))
262 trans = TRUE;
263
264 /* try for transient relations */
265 if (trans) {
266 if (old->transient_for == OB_TRAN_GROUP) {
267 for (it = focus_order[screen_desktop]; it;
268 it = g_list_next(it))
269 {
270 GSList *sit;
271
272 for (sit = old->group->members; sit;
273 sit = g_slist_next(sit))
274 {
275 if (sit->data == it->data)
276 if ((target =
277 focus_fallback_transient(sit->data, old)))
278 {
279 ob_debug("found in transient #1\n");
280 return target;
281 }
282 }
283 }
284 } else {
285 if ((target =
286 focus_fallback_transient(old->transient_for, old)))
287 {
288 ob_debug("found in transient #2\n");
289 return target;
290 }
291 }
292 }
293 }
294 }
295
296 ob_debug("trying pointer stuff\n");
297 if (config_focus_follow &&
298 (type == OB_FOCUS_FALLBACK_UNFOCUSING || !config_focus_last))
299 {
300 if ((target = client_under_pointer()))
301 if (client_normal(target) && client_can_focus(target)) {
302 ob_debug("found in pointer stuff\n");
303 return target;
304 }
305 }
306
307 #if 0
308 /* try for group relations */
309 if (old->group) {
310 GSList *sit;
311
312 for (it = focus_order[screen_desktop]; it; it = g_list_next(it))
313 for (sit = old->group->members; sit; sit = g_slist_next(sit))
314 if (sit->data == it->data)
315 if (sit->data != old && client_normal(sit->data))
316 if (client_can_focus(sit->data))
317 return sit->data;
318 }
319 #endif
320
321 ob_debug("trying the focus order\n");
322 for (it = focus_order[screen_desktop]; it; it = g_list_next(it))
323 if (type != OB_FOCUS_FALLBACK_UNFOCUSING || it->data != old)
324 if (client_normal(it->data) && client_can_focus(it->data)) {
325 ob_debug("found in focus order\n");
326 return it->data;
327 }
328
329 /* XXX fallback to the "desktop window" if one exists ?
330 could store it while going through all the windows in the loop right
331 above this..
332 */
333
334 return NULL;
335 }
336
337 void focus_fallback(ObFocusFallbackType type)
338 {
339 ObClient *new;
340 ObClient *old = focus_client;
341
342 /* unfocus any focused clients.. they can be focused by Pointer events
343 and such, and then when I try focus them, I won't get a FocusIn event
344 at all for them.
345 */
346 focus_set_client(NULL);
347
348 if ((new = focus_fallback_target(type, old)))
349 client_focus(new);
350 }
351
352 static void popup_cycle(ObClient *c, gboolean show)
353 {
354 if (!show) {
355 icon_popup_hide(focus_cycle_popup);
356 } else {
357 Rect *a;
358 ObClient *p = c;
359 gchar *title = NULL;
360
361 a = screen_physical_area_monitor(0);
362 icon_popup_position(focus_cycle_popup, CenterGravity,
363 a->x + a->width / 2, a->y + a->height / 2);
364 /* icon_popup_size(focus_cycle_popup, a->height/2, a->height/16);
365 icon_popup_show(focus_cycle_popup, c->title,
366 client_icon(c, a->height/16, a->height/16));
367 */
368 /* XXX the size and the font extents need to be related on some level
369 */
370 icon_popup_size(focus_cycle_popup, POPUP_WIDTH, POPUP_HEIGHT);
371
372 /* use the transient's parent's title/icon */
373 while (p->transient_for && p->transient_for != OB_TRAN_GROUP)
374 p = p->transient_for;
375
376 if (p != c && !strcmp("", (c->iconic ? c->icon_title : c->title)))
377 title = g_strdup(p->iconic ? p->icon_title : p->title);
378 /*title = g_strconcat((c->iconic ? c->icon_title : c->title),
379 " - ",
380 (p->iconic ? p->icon_title : p->title),
381 NULL);
382 */
383 icon_popup_show(focus_cycle_popup,
384 (title ? title :
385 (c->iconic ? c->icon_title : c->title)),
386 client_icon(p, 48, 48));
387 g_free(title);
388 }
389 }
390
391 void focus_cycle_draw_indicator()
392 {
393 if (!focus_cycle_target) {
394 XUnmapWindow(ob_display, focus_indicator.top.win);
395 XUnmapWindow(ob_display, focus_indicator.left.win);
396 XUnmapWindow(ob_display, focus_indicator.right.win);
397 XUnmapWindow(ob_display, focus_indicator.bottom.win);
398 } else {
399 /*
400 if (focus_cycle_target)
401 frame_adjust_focus(focus_cycle_target->frame, FALSE);
402 frame_adjust_focus(focus_cycle_target->frame, TRUE);
403 */
404 gint x, y, w, h;
405 gint wt, wl, wr, wb;
406
407 wt = wl = wr = wb = MAX(3,
408 MAX(1, MAX(ob_rr_theme->paddingx,
409 ob_rr_theme->paddingy)) * 2 +
410 ob_rr_theme->fbwidth * 2);
411
412 x = focus_cycle_target->frame->area.x;
413 y = focus_cycle_target->frame->area.y;
414 w = focus_cycle_target->frame->area.width;
415 h = wt;
416
417 XMoveResizeWindow(ob_display, focus_indicator.top.win,
418 x, y, w, h);
419 a_focus_indicator->texture[0].data.lineart.x1 = 0;
420 a_focus_indicator->texture[0].data.lineart.y1 = h-1;
421 a_focus_indicator->texture[0].data.lineart.x2 = 0;
422 a_focus_indicator->texture[0].data.lineart.y2 = 0;
423 a_focus_indicator->texture[1].data.lineart.x1 = 0;
424 a_focus_indicator->texture[1].data.lineart.y1 = 0;
425 a_focus_indicator->texture[1].data.lineart.x2 = w-1;
426 a_focus_indicator->texture[1].data.lineart.y2 = 0;
427 a_focus_indicator->texture[2].data.lineart.x1 = w-1;
428 a_focus_indicator->texture[2].data.lineart.y1 = 0;
429 a_focus_indicator->texture[2].data.lineart.x2 = w-1;
430 a_focus_indicator->texture[2].data.lineart.y2 = h-1;
431 a_focus_indicator->texture[3].data.lineart.x1 = (wl-1);
432 a_focus_indicator->texture[3].data.lineart.y1 = h-1;
433 a_focus_indicator->texture[3].data.lineart.x2 = w - wr;
434 a_focus_indicator->texture[3].data.lineart.y2 = h-1;
435 RrPaint(a_focus_indicator, focus_indicator.top.win,
436 w, h);
437
438 x = focus_cycle_target->frame->area.x;
439 y = focus_cycle_target->frame->area.y;
440 w = wl;
441 h = focus_cycle_target->frame->area.height;
442
443 XMoveResizeWindow(ob_display, focus_indicator.left.win,
444 x, y, w, h);
445 a_focus_indicator->texture[0].data.lineart.x1 = w-1;
446 a_focus_indicator->texture[0].data.lineart.y1 = 0;
447 a_focus_indicator->texture[0].data.lineart.x2 = 0;
448 a_focus_indicator->texture[0].data.lineart.y2 = 0;
449 a_focus_indicator->texture[1].data.lineart.x1 = 0;
450 a_focus_indicator->texture[1].data.lineart.y1 = 0;
451 a_focus_indicator->texture[1].data.lineart.x2 = 0;
452 a_focus_indicator->texture[1].data.lineart.y2 = h-1;
453 a_focus_indicator->texture[2].data.lineart.x1 = 0;
454 a_focus_indicator->texture[2].data.lineart.y1 = h-1;
455 a_focus_indicator->texture[2].data.lineart.x2 = w-1;
456 a_focus_indicator->texture[2].data.lineart.y2 = h-1;
457 a_focus_indicator->texture[3].data.lineart.x1 = w-1;
458 a_focus_indicator->texture[3].data.lineart.y1 = wt-1;
459 a_focus_indicator->texture[3].data.lineart.x2 = w-1;
460 a_focus_indicator->texture[3].data.lineart.y2 = h - wb;
461 RrPaint(a_focus_indicator, focus_indicator.left.win,
462 w, h);
463
464 x = focus_cycle_target->frame->area.x +
465 focus_cycle_target->frame->area.width - wr;
466 y = focus_cycle_target->frame->area.y;
467 w = wr;
468 h = focus_cycle_target->frame->area.height ;
469
470 XMoveResizeWindow(ob_display, focus_indicator.right.win,
471 x, y, w, h);
472 a_focus_indicator->texture[0].data.lineart.x1 = 0;
473 a_focus_indicator->texture[0].data.lineart.y1 = 0;
474 a_focus_indicator->texture[0].data.lineart.x2 = w-1;
475 a_focus_indicator->texture[0].data.lineart.y2 = 0;
476 a_focus_indicator->texture[1].data.lineart.x1 = w-1;
477 a_focus_indicator->texture[1].data.lineart.y1 = 0;
478 a_focus_indicator->texture[1].data.lineart.x2 = w-1;
479 a_focus_indicator->texture[1].data.lineart.y2 = h-1;
480 a_focus_indicator->texture[2].data.lineart.x1 = w-1;
481 a_focus_indicator->texture[2].data.lineart.y1 = h-1;
482 a_focus_indicator->texture[2].data.lineart.x2 = 0;
483 a_focus_indicator->texture[2].data.lineart.y2 = h-1;
484 a_focus_indicator->texture[3].data.lineart.x1 = 0;
485 a_focus_indicator->texture[3].data.lineart.y1 = wt-1;
486 a_focus_indicator->texture[3].data.lineart.x2 = 0;
487 a_focus_indicator->texture[3].data.lineart.y2 = h - wb;
488 RrPaint(a_focus_indicator, focus_indicator.right.win,
489 w, h);
490
491 x = focus_cycle_target->frame->area.x;
492 y = focus_cycle_target->frame->area.y +
493 focus_cycle_target->frame->area.height - wb;
494 w = focus_cycle_target->frame->area.width;
495 h = wb;
496
497 XMoveResizeWindow(ob_display, focus_indicator.bottom.win,
498 x, y, w, h);
499 a_focus_indicator->texture[0].data.lineart.x1 = 0;
500 a_focus_indicator->texture[0].data.lineart.y1 = 0;
501 a_focus_indicator->texture[0].data.lineart.x2 = 0;
502 a_focus_indicator->texture[0].data.lineart.y2 = h-1;
503 a_focus_indicator->texture[1].data.lineart.x1 = 0;
504 a_focus_indicator->texture[1].data.lineart.y1 = h-1;
505 a_focus_indicator->texture[1].data.lineart.x2 = w-1;
506 a_focus_indicator->texture[1].data.lineart.y2 = h-1;
507 a_focus_indicator->texture[2].data.lineart.x1 = w-1;
508 a_focus_indicator->texture[2].data.lineart.y1 = h-1;
509 a_focus_indicator->texture[2].data.lineart.x2 = w-1;
510 a_focus_indicator->texture[2].data.lineart.y2 = 0;
511 a_focus_indicator->texture[3].data.lineart.x1 = wl-1;
512 a_focus_indicator->texture[3].data.lineart.y1 = 0;
513 a_focus_indicator->texture[3].data.lineart.x2 = w - wr;
514 a_focus_indicator->texture[3].data.lineart.y2 = 0;
515 RrPaint(a_focus_indicator, focus_indicator.bottom.win,
516 w, h);
517
518 XMapWindow(ob_display, focus_indicator.top.win);
519 XMapWindow(ob_display, focus_indicator.left.win);
520 XMapWindow(ob_display, focus_indicator.right.win);
521 XMapWindow(ob_display, focus_indicator.bottom.win);
522 }
523 }
524
525 static gboolean valid_focus_target(ObClient *ft)
526 {
527 /* we don't use client_can_focus here, because that doesn't let you
528 focus an iconic window, but we want to be able to, so we just check
529 if the focus flags on the window allow it, and its on the current
530 desktop */
531 if ((ft->type == OB_CLIENT_TYPE_NORMAL ||
532 ft->type == OB_CLIENT_TYPE_DIALOG ||
533 (!client_has_group_siblings(ft) &&
534 (ft->type == OB_CLIENT_TYPE_TOOLBAR ||
535 ft->type == OB_CLIENT_TYPE_MENU ||
536 ft->type == OB_CLIENT_TYPE_UTILITY))) &&
537 ((ft->can_focus || ft->focus_notify) &&
538 !ft->skip_pager &&
539 (ft->desktop == screen_desktop || ft->desktop == DESKTOP_ALL)) &&
540 ft == client_focus_target(ft))
541 return TRUE;
542 /*
543 {
544 GSList *it;
545
546 for (it = ft->transients; it; it = g_slist_next(it)) {
547 ObClient *c = it->data;
548
549 if (c->frame->visible)
550 return FALSE;
551 }
552 return TRUE;
553 }
554 */
555
556 return FALSE;
557 }
558
559 void focus_cycle(gboolean forward, gboolean linear, gboolean interactive,
560 gboolean dialog, gboolean done, gboolean cancel, Time time)
561 {
562 static ObClient *first = NULL;
563 static ObClient *t = NULL;
564 static GList *order = NULL;
565 GList *it, *start, *list;
566 ObClient *ft = NULL;
567
568 if (interactive) {
569 if (cancel) {
570 focus_cycle_target = NULL;
571 goto done_cycle;
572 } else if (done)
573 goto done_cycle;
574
575 if (!focus_order[screen_desktop])
576 goto done_cycle;
577
578 if (!first) first = focus_client;
579
580 if (linear) list = client_list;
581 else list = focus_order[screen_desktop];
582 } else {
583 if (!focus_order[screen_desktop])
584 goto done_cycle;
585 list = client_list;
586 }
587 if (!focus_cycle_target) focus_cycle_target = focus_client;
588
589 start = it = g_list_find(list, focus_cycle_target);
590 if (!start) /* switched desktops or something? */
591 start = it = forward ? g_list_last(list) : g_list_first(list);
592 if (!start) goto done_cycle;
593
594 do {
595 if (forward) {
596 it = it->next;
597 if (it == NULL) it = g_list_first(list);
598 } else {
599 it = it->prev;
600 if (it == NULL) it = g_list_last(list);
601 }
602 ft = it->data;
603 if (valid_focus_target(ft)) {
604 if (interactive) {
605 if (ft != focus_cycle_target) { /* prevents flicker */
606 focus_cycle_target = ft;
607 focus_cycle_draw_indicator();
608 }
609 popup_cycle(ft, dialog);
610 return;
611 } else if (ft != focus_cycle_target) {
612 focus_cycle_target = ft;
613 done = TRUE;
614 break;
615 }
616 }
617 } while (it != start);
618
619 done_cycle:
620 if (done && focus_cycle_target)
621 client_activate(focus_cycle_target, FALSE, TRUE, time);
622
623 t = NULL;
624 first = NULL;
625 focus_cycle_target = NULL;
626 g_list_free(order);
627 order = NULL;
628
629 if (interactive) {
630 focus_cycle_draw_indicator();
631 popup_cycle(ft, FALSE);
632 }
633
634 return;
635 }
636
637 void focus_directional_cycle(ObDirection dir, gboolean interactive,
638 gboolean dialog, gboolean done, gboolean cancel,
639 Time time)
640 {
641 static ObClient *first = NULL;
642 ObClient *ft = NULL;
643
644 if (!interactive)
645 return;
646
647 if (cancel) {
648 focus_cycle_target = NULL;
649 goto done_cycle;
650 } else if (done)
651 goto done_cycle;
652
653 if (!focus_order[screen_desktop])
654 goto done_cycle;
655
656 if (!first) first = focus_client;
657 if (!focus_cycle_target) focus_cycle_target = focus_client;
658
659 if (focus_cycle_target)
660 ft = client_find_directional(focus_cycle_target, dir);
661 else {
662 GList *it;
663
664 for (it = focus_order[screen_desktop]; it; it = g_list_next(it))
665 if (valid_focus_target(it->data))
666 ft = it->data;
667 }
668
669 if (ft) {
670 if (ft != focus_cycle_target) {/* prevents flicker */
671 focus_cycle_target = ft;
672 focus_cycle_draw_indicator();
673 }
674 }
675 if (focus_cycle_target) {
676 popup_cycle(focus_cycle_target, dialog);
677 if (dialog)
678 return;
679 }
680
681
682 done_cycle:
683 if (done && focus_cycle_target)
684 client_activate(focus_cycle_target, FALSE, TRUE, time);
685
686 first = NULL;
687 focus_cycle_target = NULL;
688
689 focus_cycle_draw_indicator();
690 popup_cycle(ft, FALSE);
691
692 return;
693 }
694
695 void focus_order_add_new(ObClient *c)
696 {
697 guint d, i;
698
699 if (c->iconic)
700 focus_order_to_top(c);
701 else {
702 d = c->desktop;
703 if (d == DESKTOP_ALL) {
704 for (i = 0; i < screen_num_desktops; ++i) {
705 g_assert(!g_list_find(focus_order[i], c));
706 if (focus_order[i] && ((ObClient*)focus_order[i]->data)->iconic)
707 focus_order[i] = g_list_insert(focus_order[i], c, 0);
708 else
709 focus_order[i] = g_list_insert(focus_order[i], c, 1);
710 }
711 } else {
712 g_assert(!g_list_find(focus_order[d], c));
713 if (focus_order[d] && ((ObClient*)focus_order[d]->data)->iconic)
714 focus_order[d] = g_list_insert(focus_order[d], c, 0);
715 else
716 focus_order[d] = g_list_insert(focus_order[d], c, 1);
717 }
718 }
719 }
720
721 void focus_order_remove(ObClient *c)
722 {
723 guint d, i;
724
725 d = c->desktop;
726 if (d == DESKTOP_ALL) {
727 for (i = 0; i < screen_num_desktops; ++i)
728 focus_order[i] = g_list_remove(focus_order[i], c);
729 } else
730 focus_order[d] = g_list_remove(focus_order[d], c);
731 }
732
733 static void to_top(ObClient *c, guint d)
734 {
735 focus_order[d] = g_list_remove(focus_order[d], c);
736 if (!c->iconic) {
737 focus_order[d] = g_list_prepend(focus_order[d], c);
738 } else {
739 GList *it;
740
741 /* insert before first iconic window */
742 for (it = focus_order[d];
743 it && !((ObClient*)it->data)->iconic; it = g_list_next(it));
744 focus_order[d] = g_list_insert_before(focus_order[d], it, c);
745 }
746 }
747
748 void focus_order_to_top(ObClient *c)
749 {
750 guint d, i;
751
752 d = c->desktop;
753 if (d == DESKTOP_ALL) {
754 for (i = 0; i < screen_num_desktops; ++i)
755 to_top(c, i);
756 } else
757 to_top(c, d);
758 }
759
760 static void to_bottom(ObClient *c, guint d)
761 {
762 focus_order[d] = g_list_remove(focus_order[d], c);
763 if (c->iconic) {
764 focus_order[d] = g_list_append(focus_order[d], c);
765 } else {
766 GList *it;
767
768 /* insert before first iconic window */
769 for (it = focus_order[d];
770 it && !((ObClient*)it->data)->iconic; it = g_list_next(it));
771 focus_order[d] = g_list_insert_before(focus_order[d], it, c);
772 }
773 }
774
775 void focus_order_to_bottom(ObClient *c)
776 {
777 guint d, i;
778
779 d = c->desktop;
780 if (d == DESKTOP_ALL) {
781 for (i = 0; i < screen_num_desktops; ++i)
782 to_bottom(c, i);
783 } else
784 to_bottom(c, d);
785 }
This page took 0.069596 seconds and 3 git commands to generate.