]> Dogcows Code - chaz/openbox/blob - openbox/focus.c
oh, 2 things in this commit..
[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-2007 Dana 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) &&
227 client_can_focus(ret) && client_validate(ret))
228 return ret;
229 if (it->data != skip && client_normal(it->data) &&
230 client_can_focus(it->data) && client_validate(it->data))
231 return it->data;
232 }
233 return NULL;
234 }
235
236 static ObClient* focus_fallback_transient(ObClient *top, ObClient *old)
237 {
238 ObClient *target = find_transient_recursive(top, top, old);
239 if (!target) {
240 /* make sure client_normal is true always */
241 if (!client_normal(top))
242 return NULL;
243 target = top; /* no transient, keep the top */
244 }
245 if (client_can_focus(target))
246 return target;
247 else
248 return NULL;
249 }
250
251 ObClient* focus_fallback_target(gboolean allow_refocus)
252 {
253 GList *it;
254 ObClient *old;
255 ObClient *target = NULL;
256
257 old = focus_client;
258
259 if (!allow_refocus && old && old->transient_for) {
260 gboolean trans = FALSE;
261
262 if (!config_focus_follow || config_focus_last)
263 trans = TRUE;
264 else if ((target = client_under_pointer()) &&
265 client_search_transient
266 (client_search_top_parent(target), old))
267 trans = TRUE;
268
269 /* try for transient relations */
270 if (trans) {
271 if (old->transient_for == OB_TRAN_GROUP) {
272 for (it = focus_order[screen_desktop]; it;
273 it = g_list_next(it))
274 {
275 GSList *sit;
276
277 for (sit = old->group->members; sit;
278 sit = g_slist_next(sit))
279 {
280 if (sit->data == it->data)
281 if ((target =
282 focus_fallback_transient(sit->data, old)))
283 {
284 ob_debug("found in transient #1\n");
285 return target;
286 }
287 }
288 }
289 } else {
290 if ((target =
291 focus_fallback_transient(old->transient_for, old)))
292 {
293 ob_debug("found in transient #2\n");
294 return target;
295 }
296 }
297 }
298 }
299
300 ob_debug("trying pointer stuff\n");
301 if (config_focus_follow && !config_focus_last)
302 {
303 if ((target = client_under_pointer()))
304 if (allow_refocus || target != old)
305 if (client_normal(target) && client_can_focus(target) &&
306 client_validate(target)) {
307 ob_debug("found in pointer stuff\n");
308 return target;
309 }
310 }
311
312 #if 0
313 /* try for group relations */
314 if (old->group) {
315 GSList *sit;
316
317 for (it = focus_order[screen_desktop]; it; it = g_list_next(it))
318 for (sit = old->group->members; sit; sit = g_slist_next(sit))
319 if (sit->data == it->data)
320 if (sit->data != old && client_normal(sit->data))
321 if (client_can_focus(sit->data))
322 return sit->data;
323 }
324 #endif
325
326 ob_debug("trying the focus order\n");
327 for (it = focus_order[screen_desktop]; it; it = g_list_next(it))
328 if (allow_refocus || it->data != old)
329 if (client_normal(it->data) && client_can_focus(it->data) &&
330 client_validate(it->data))
331 {
332 ob_debug("found in focus order\n");
333 return it->data;
334 }
335
336 /* XXX fallback to the "desktop window" if one exists ?
337 could store it while going through all the windows in the loop right
338 above this..
339 */
340
341 return NULL;
342 }
343
344 void focus_fallback(gboolean allow_refocus)
345 {
346 ObClient *new;
347
348 /* unfocus any focused clients.. they can be focused by Pointer events
349 and such, and then when I try focus them, I won't get a FocusIn event
350 at all for them.
351 */
352 focus_set_client(NULL);
353
354 if ((new = focus_fallback_target(allow_refocus)))
355 client_focus(new);
356 }
357
358 static void popup_cycle(ObClient *c, gboolean show)
359 {
360 if (!show) {
361 icon_popup_hide(focus_cycle_popup);
362 } else {
363 Rect *a;
364 ObClient *p = c;
365 gchar *title = NULL;
366
367 a = screen_physical_area_monitor(0);
368 icon_popup_position(focus_cycle_popup, CenterGravity,
369 a->x + a->width / 2, a->y + a->height / 2);
370 /* icon_popup_size(focus_cycle_popup, a->height/2, a->height/16);
371 icon_popup_show(focus_cycle_popup, c->title,
372 client_icon(c, a->height/16, a->height/16));
373 */
374 /* XXX the size and the font extents need to be related on some level
375 */
376 icon_popup_size(focus_cycle_popup, POPUP_WIDTH, POPUP_HEIGHT);
377
378 /* use the transient's parent's title/icon */
379 while (p->transient_for && p->transient_for != OB_TRAN_GROUP)
380 p = p->transient_for;
381
382 if (p != c && !strcmp("", (c->iconic ? c->icon_title : c->title)))
383 title = g_strdup(p->iconic ? p->icon_title : p->title);
384 /*title = g_strconcat((c->iconic ? c->icon_title : c->title),
385 " - ",
386 (p->iconic ? p->icon_title : p->title),
387 NULL);
388 */
389 icon_popup_show(focus_cycle_popup,
390 (title ? title :
391 (c->iconic ? c->icon_title : c->title)),
392 client_icon(p, 48, 48));
393 g_free(title);
394 }
395 }
396
397 void focus_cycle_draw_indicator()
398 {
399 if (!focus_cycle_target) {
400 XUnmapWindow(ob_display, focus_indicator.top.win);
401 XUnmapWindow(ob_display, focus_indicator.left.win);
402 XUnmapWindow(ob_display, focus_indicator.right.win);
403 XUnmapWindow(ob_display, focus_indicator.bottom.win);
404 } else {
405 /*
406 if (focus_cycle_target)
407 frame_adjust_focus(focus_cycle_target->frame, FALSE);
408 frame_adjust_focus(focus_cycle_target->frame, TRUE);
409 */
410 gint x, y, w, h;
411 gint wt, wl, wr, wb;
412
413 wt = wl = wr = wb = MAX(3,
414 MAX(1, MAX(ob_rr_theme->paddingx,
415 ob_rr_theme->paddingy)) * 2 +
416 ob_rr_theme->fbwidth * 2);
417
418 x = focus_cycle_target->frame->area.x;
419 y = focus_cycle_target->frame->area.y;
420 w = focus_cycle_target->frame->area.width;
421 h = wt;
422
423 XMoveResizeWindow(ob_display, focus_indicator.top.win,
424 x, y, w, h);
425 a_focus_indicator->texture[0].data.lineart.x1 = 0;
426 a_focus_indicator->texture[0].data.lineart.y1 = h-1;
427 a_focus_indicator->texture[0].data.lineart.x2 = 0;
428 a_focus_indicator->texture[0].data.lineart.y2 = 0;
429 a_focus_indicator->texture[1].data.lineart.x1 = 0;
430 a_focus_indicator->texture[1].data.lineart.y1 = 0;
431 a_focus_indicator->texture[1].data.lineart.x2 = w-1;
432 a_focus_indicator->texture[1].data.lineart.y2 = 0;
433 a_focus_indicator->texture[2].data.lineart.x1 = w-1;
434 a_focus_indicator->texture[2].data.lineart.y1 = 0;
435 a_focus_indicator->texture[2].data.lineart.x2 = w-1;
436 a_focus_indicator->texture[2].data.lineart.y2 = h-1;
437 a_focus_indicator->texture[3].data.lineart.x1 = (wl-1);
438 a_focus_indicator->texture[3].data.lineart.y1 = h-1;
439 a_focus_indicator->texture[3].data.lineart.x2 = w - wr;
440 a_focus_indicator->texture[3].data.lineart.y2 = h-1;
441 RrPaint(a_focus_indicator, focus_indicator.top.win,
442 w, h);
443
444 x = focus_cycle_target->frame->area.x;
445 y = focus_cycle_target->frame->area.y;
446 w = wl;
447 h = focus_cycle_target->frame->area.height;
448
449 XMoveResizeWindow(ob_display, focus_indicator.left.win,
450 x, y, w, h);
451 a_focus_indicator->texture[0].data.lineart.x1 = w-1;
452 a_focus_indicator->texture[0].data.lineart.y1 = 0;
453 a_focus_indicator->texture[0].data.lineart.x2 = 0;
454 a_focus_indicator->texture[0].data.lineart.y2 = 0;
455 a_focus_indicator->texture[1].data.lineart.x1 = 0;
456 a_focus_indicator->texture[1].data.lineart.y1 = 0;
457 a_focus_indicator->texture[1].data.lineart.x2 = 0;
458 a_focus_indicator->texture[1].data.lineart.y2 = h-1;
459 a_focus_indicator->texture[2].data.lineart.x1 = 0;
460 a_focus_indicator->texture[2].data.lineart.y1 = h-1;
461 a_focus_indicator->texture[2].data.lineart.x2 = w-1;
462 a_focus_indicator->texture[2].data.lineart.y2 = h-1;
463 a_focus_indicator->texture[3].data.lineart.x1 = w-1;
464 a_focus_indicator->texture[3].data.lineart.y1 = wt-1;
465 a_focus_indicator->texture[3].data.lineart.x2 = w-1;
466 a_focus_indicator->texture[3].data.lineart.y2 = h - wb;
467 RrPaint(a_focus_indicator, focus_indicator.left.win,
468 w, h);
469
470 x = focus_cycle_target->frame->area.x +
471 focus_cycle_target->frame->area.width - wr;
472 y = focus_cycle_target->frame->area.y;
473 w = wr;
474 h = focus_cycle_target->frame->area.height ;
475
476 XMoveResizeWindow(ob_display, focus_indicator.right.win,
477 x, y, w, h);
478 a_focus_indicator->texture[0].data.lineart.x1 = 0;
479 a_focus_indicator->texture[0].data.lineart.y1 = 0;
480 a_focus_indicator->texture[0].data.lineart.x2 = w-1;
481 a_focus_indicator->texture[0].data.lineart.y2 = 0;
482 a_focus_indicator->texture[1].data.lineart.x1 = w-1;
483 a_focus_indicator->texture[1].data.lineart.y1 = 0;
484 a_focus_indicator->texture[1].data.lineart.x2 = w-1;
485 a_focus_indicator->texture[1].data.lineart.y2 = h-1;
486 a_focus_indicator->texture[2].data.lineart.x1 = w-1;
487 a_focus_indicator->texture[2].data.lineart.y1 = h-1;
488 a_focus_indicator->texture[2].data.lineart.x2 = 0;
489 a_focus_indicator->texture[2].data.lineart.y2 = h-1;
490 a_focus_indicator->texture[3].data.lineart.x1 = 0;
491 a_focus_indicator->texture[3].data.lineart.y1 = wt-1;
492 a_focus_indicator->texture[3].data.lineart.x2 = 0;
493 a_focus_indicator->texture[3].data.lineart.y2 = h - wb;
494 RrPaint(a_focus_indicator, focus_indicator.right.win,
495 w, h);
496
497 x = focus_cycle_target->frame->area.x;
498 y = focus_cycle_target->frame->area.y +
499 focus_cycle_target->frame->area.height - wb;
500 w = focus_cycle_target->frame->area.width;
501 h = wb;
502
503 XMoveResizeWindow(ob_display, focus_indicator.bottom.win,
504 x, y, w, h);
505 a_focus_indicator->texture[0].data.lineart.x1 = 0;
506 a_focus_indicator->texture[0].data.lineart.y1 = 0;
507 a_focus_indicator->texture[0].data.lineart.x2 = 0;
508 a_focus_indicator->texture[0].data.lineart.y2 = h-1;
509 a_focus_indicator->texture[1].data.lineart.x1 = 0;
510 a_focus_indicator->texture[1].data.lineart.y1 = h-1;
511 a_focus_indicator->texture[1].data.lineart.x2 = w-1;
512 a_focus_indicator->texture[1].data.lineart.y2 = h-1;
513 a_focus_indicator->texture[2].data.lineart.x1 = w-1;
514 a_focus_indicator->texture[2].data.lineart.y1 = h-1;
515 a_focus_indicator->texture[2].data.lineart.x2 = w-1;
516 a_focus_indicator->texture[2].data.lineart.y2 = 0;
517 a_focus_indicator->texture[3].data.lineart.x1 = wl-1;
518 a_focus_indicator->texture[3].data.lineart.y1 = 0;
519 a_focus_indicator->texture[3].data.lineart.x2 = w - wr;
520 a_focus_indicator->texture[3].data.lineart.y2 = 0;
521 RrPaint(a_focus_indicator, focus_indicator.bottom.win,
522 w, h);
523
524 XMapWindow(ob_display, focus_indicator.top.win);
525 XMapWindow(ob_display, focus_indicator.left.win);
526 XMapWindow(ob_display, focus_indicator.right.win);
527 XMapWindow(ob_display, focus_indicator.bottom.win);
528 }
529 }
530
531 static gboolean valid_focus_target(ObClient *ft)
532 {
533 /* we don't use client_can_focus here, because that doesn't let you
534 focus an iconic window, but we want to be able to, so we just check
535 if the focus flags on the window allow it, and its on the current
536 desktop */
537 if ((ft->type == OB_CLIENT_TYPE_NORMAL ||
538 ft->type == OB_CLIENT_TYPE_DIALOG ||
539 (!client_has_group_siblings(ft) &&
540 (ft->type == OB_CLIENT_TYPE_TOOLBAR ||
541 ft->type == OB_CLIENT_TYPE_MENU ||
542 ft->type == OB_CLIENT_TYPE_UTILITY))) &&
543 ((ft->can_focus || ft->focus_notify) &&
544 !ft->skip_pager &&
545 (ft->desktop == screen_desktop || ft->desktop == DESKTOP_ALL)) &&
546 ft == client_focus_target(ft))
547 return TRUE;
548 /*
549 {
550 GSList *it;
551
552 for (it = ft->transients; it; it = g_slist_next(it)) {
553 ObClient *c = it->data;
554
555 if (c->frame->visible)
556 return FALSE;
557 }
558 return TRUE;
559 }
560 */
561
562 return FALSE;
563 }
564
565 void focus_cycle(gboolean forward, gboolean linear, gboolean interactive,
566 gboolean dialog, gboolean done, gboolean cancel, Time time)
567 {
568 static ObClient *first = NULL;
569 static ObClient *t = NULL;
570 static GList *order = NULL;
571 GList *it, *start, *list;
572 ObClient *ft = NULL;
573
574 if (interactive) {
575 if (cancel) {
576 focus_cycle_target = NULL;
577 goto done_cycle;
578 } else if (done)
579 goto done_cycle;
580
581 if (!focus_order[screen_desktop])
582 goto done_cycle;
583
584 if (!first) first = focus_client;
585
586 if (linear) list = client_list;
587 else list = focus_order[screen_desktop];
588 } else {
589 if (!focus_order[screen_desktop])
590 goto done_cycle;
591 list = client_list;
592 }
593 if (!focus_cycle_target) focus_cycle_target = focus_client;
594
595 start = it = g_list_find(list, focus_cycle_target);
596 if (!start) /* switched desktops or something? */
597 start = it = forward ? g_list_last(list) : g_list_first(list);
598 if (!start) goto done_cycle;
599
600 do {
601 if (forward) {
602 it = it->next;
603 if (it == NULL) it = g_list_first(list);
604 } else {
605 it = it->prev;
606 if (it == NULL) it = g_list_last(list);
607 }
608 ft = it->data;
609 if (valid_focus_target(ft)) {
610 if (interactive) {
611 if (ft != focus_cycle_target) { /* prevents flicker */
612 focus_cycle_target = ft;
613 focus_cycle_draw_indicator();
614 }
615 popup_cycle(ft, dialog);
616 return;
617 } else if (ft != focus_cycle_target) {
618 focus_cycle_target = ft;
619 done = TRUE;
620 break;
621 }
622 }
623 } while (it != start);
624
625 done_cycle:
626 if (done && focus_cycle_target)
627 client_activate(focus_cycle_target, FALSE, TRUE, time);
628
629 t = NULL;
630 first = NULL;
631 focus_cycle_target = NULL;
632 g_list_free(order);
633 order = NULL;
634
635 if (interactive) {
636 focus_cycle_draw_indicator();
637 popup_cycle(ft, FALSE);
638 }
639
640 return;
641 }
642
643 void focus_directional_cycle(ObDirection dir, gboolean interactive,
644 gboolean dialog, gboolean done, gboolean cancel,
645 Time time)
646 {
647 static ObClient *first = NULL;
648 ObClient *ft = NULL;
649
650 if (!interactive)
651 return;
652
653 if (cancel) {
654 focus_cycle_target = NULL;
655 goto done_cycle;
656 } else if (done)
657 goto done_cycle;
658
659 if (!focus_order[screen_desktop])
660 goto done_cycle;
661
662 if (!first) first = focus_client;
663 if (!focus_cycle_target) focus_cycle_target = focus_client;
664
665 if (focus_cycle_target)
666 ft = client_find_directional(focus_cycle_target, dir);
667 else {
668 GList *it;
669
670 for (it = focus_order[screen_desktop]; it; it = g_list_next(it))
671 if (valid_focus_target(it->data))
672 ft = it->data;
673 }
674
675 if (ft) {
676 if (ft != focus_cycle_target) {/* prevents flicker */
677 focus_cycle_target = ft;
678 focus_cycle_draw_indicator();
679 }
680 }
681 if (focus_cycle_target) {
682 popup_cycle(focus_cycle_target, dialog);
683 if (dialog)
684 return;
685 }
686
687
688 done_cycle:
689 if (done && focus_cycle_target)
690 client_activate(focus_cycle_target, FALSE, TRUE, time);
691
692 first = NULL;
693 focus_cycle_target = NULL;
694
695 focus_cycle_draw_indicator();
696 popup_cycle(ft, FALSE);
697
698 return;
699 }
700
701 void focus_order_add_new(ObClient *c)
702 {
703 guint d, i;
704
705 if (c->iconic)
706 focus_order_to_top(c);
707 else {
708 d = c->desktop;
709 if (d == DESKTOP_ALL) {
710 for (i = 0; i < screen_num_desktops; ++i) {
711 g_assert(!g_list_find(focus_order[i], c));
712 if (focus_order[i] && ((ObClient*)focus_order[i]->data)->iconic)
713 focus_order[i] = g_list_insert(focus_order[i], c, 0);
714 else
715 focus_order[i] = g_list_insert(focus_order[i], c, 1);
716 }
717 } else {
718 g_assert(!g_list_find(focus_order[d], c));
719 if (focus_order[d] && ((ObClient*)focus_order[d]->data)->iconic)
720 focus_order[d] = g_list_insert(focus_order[d], c, 0);
721 else
722 focus_order[d] = g_list_insert(focus_order[d], c, 1);
723 }
724 }
725 }
726
727 void focus_order_remove(ObClient *c)
728 {
729 guint d, i;
730
731 d = c->desktop;
732 if (d == DESKTOP_ALL) {
733 for (i = 0; i < screen_num_desktops; ++i)
734 focus_order[i] = g_list_remove(focus_order[i], c);
735 } else
736 focus_order[d] = g_list_remove(focus_order[d], c);
737 }
738
739 static void to_top(ObClient *c, guint d)
740 {
741 focus_order[d] = g_list_remove(focus_order[d], c);
742 if (!c->iconic) {
743 focus_order[d] = g_list_prepend(focus_order[d], c);
744 } else {
745 GList *it;
746
747 /* insert before first iconic window */
748 for (it = focus_order[d];
749 it && !((ObClient*)it->data)->iconic; it = g_list_next(it));
750 focus_order[d] = g_list_insert_before(focus_order[d], it, c);
751 }
752 }
753
754 void focus_order_to_top(ObClient *c)
755 {
756 guint d, i;
757
758 d = c->desktop;
759 if (d == DESKTOP_ALL) {
760 for (i = 0; i < screen_num_desktops; ++i)
761 to_top(c, i);
762 } else
763 to_top(c, d);
764 }
765
766 static void to_bottom(ObClient *c, guint d)
767 {
768 focus_order[d] = g_list_remove(focus_order[d], c);
769 if (c->iconic) {
770 focus_order[d] = g_list_append(focus_order[d], c);
771 } else {
772 GList *it;
773
774 /* insert before first iconic window */
775 for (it = focus_order[d];
776 it && !((ObClient*)it->data)->iconic; it = g_list_next(it));
777 focus_order[d] = g_list_insert_before(focus_order[d], it, c);
778 }
779 }
780
781 void focus_order_to_bottom(ObClient *c)
782 {
783 guint d, i;
784
785 d = c->desktop;
786 if (d == DESKTOP_ALL) {
787 for (i = 0; i < screen_num_desktops; ++i)
788 to_bottom(c, i);
789 } else
790 to_bottom(c, d);
791 }
This page took 0.079102 seconds and 4 git commands to generate.