]> Dogcows Code - chaz/openbox/blob - openbox/focus.c
ea3d4fab0d75eb37c7d0a6d451c772f4effa22ac
[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;
42 ObClient *focus_cycle_target;
43
44 struct {
45 InternalWindow top;
46 InternalWindow left;
47 InternalWindow right;
48 InternalWindow bottom;
49 } focus_indicator;
50
51 RrAppearance *a_focus_indicator;
52 RrColor *color_white;
53
54 static ObIconPopup *focus_cycle_popup;
55
56 static void focus_cycle_destructor(ObClient *client, gpointer data)
57 {
58 /* end cycling if the target disappears. CurrentTime is fine, time won't
59 be used
60 */
61 if (focus_cycle_target == client)
62 focus_cycle(TRUE, TRUE, TRUE, TRUE, TRUE, TRUE);
63 }
64
65 static Window createWindow(Window parent, gulong mask,
66 XSetWindowAttributes *attrib)
67 {
68 return XCreateWindow(ob_display, parent, 0, 0, 1, 1, 0,
69 RrDepth(ob_rr_inst), InputOutput,
70 RrVisual(ob_rr_inst), mask, attrib);
71
72 }
73
74 void focus_startup(gboolean reconfig)
75 {
76 focus_cycle_popup = icon_popup_new(TRUE);
77
78 if (!reconfig) {
79 XSetWindowAttributes attr;
80
81 client_add_destructor(focus_cycle_destructor, NULL);
82
83 /* start with nothing focused */
84 focus_set_client(NULL);
85
86 focus_indicator.top.obwin.type = Window_Internal;
87 focus_indicator.left.obwin.type = Window_Internal;
88 focus_indicator.right.obwin.type = Window_Internal;
89 focus_indicator.bottom.obwin.type = Window_Internal;
90
91 attr.override_redirect = True;
92 attr.background_pixel = BlackPixel(ob_display, ob_screen);
93 focus_indicator.top.win =
94 createWindow(RootWindow(ob_display, ob_screen),
95 CWOverrideRedirect | CWBackPixel, &attr);
96 focus_indicator.left.win =
97 createWindow(RootWindow(ob_display, ob_screen),
98 CWOverrideRedirect | CWBackPixel, &attr);
99 focus_indicator.right.win =
100 createWindow(RootWindow(ob_display, ob_screen),
101 CWOverrideRedirect | CWBackPixel, &attr);
102 focus_indicator.bottom.win =
103 createWindow(RootWindow(ob_display, ob_screen),
104 CWOverrideRedirect | CWBackPixel, &attr);
105
106 stacking_add(INTERNAL_AS_WINDOW(&focus_indicator.top));
107 stacking_add(INTERNAL_AS_WINDOW(&focus_indicator.left));
108 stacking_add(INTERNAL_AS_WINDOW(&focus_indicator.right));
109 stacking_add(INTERNAL_AS_WINDOW(&focus_indicator.bottom));
110
111 color_white = RrColorNew(ob_rr_inst, 0xff, 0xff, 0xff);
112
113 a_focus_indicator = RrAppearanceNew(ob_rr_inst, 4);
114 a_focus_indicator->surface.grad = RR_SURFACE_SOLID;
115 a_focus_indicator->surface.relief = RR_RELIEF_FLAT;
116 a_focus_indicator->surface.primary = RrColorNew(ob_rr_inst,
117 0, 0, 0);
118 a_focus_indicator->texture[0].type = RR_TEXTURE_LINE_ART;
119 a_focus_indicator->texture[0].data.lineart.color = color_white;
120 a_focus_indicator->texture[1].type = RR_TEXTURE_LINE_ART;
121 a_focus_indicator->texture[1].data.lineart.color = color_white;
122 a_focus_indicator->texture[2].type = RR_TEXTURE_LINE_ART;
123 a_focus_indicator->texture[2].data.lineart.color = color_white;
124 a_focus_indicator->texture[3].type = RR_TEXTURE_LINE_ART;
125 a_focus_indicator->texture[3].data.lineart.color = color_white;
126 }
127 }
128
129 void focus_shutdown(gboolean reconfig)
130 {
131 icon_popup_free(focus_cycle_popup);
132
133 if (!reconfig) {
134 client_remove_destructor(focus_cycle_destructor);
135
136 /* reset focus to root */
137 XSetInputFocus(ob_display, PointerRoot, RevertToNone, CurrentTime);
138
139 RrColorFree(color_white);
140
141 RrAppearanceFree(a_focus_indicator);
142
143 XDestroyWindow(ob_display, focus_indicator.top.win);
144 XDestroyWindow(ob_display, focus_indicator.left.win);
145 XDestroyWindow(ob_display, focus_indicator.right.win);
146 XDestroyWindow(ob_display, focus_indicator.bottom.win);
147 }
148 }
149
150 static void push_to_top(ObClient *client)
151 {
152 focus_order = g_list_remove(focus_order, client);
153 focus_order = g_list_prepend(focus_order, client);
154 }
155
156 void focus_set_client(ObClient *client)
157 {
158 Window active;
159 ObClient *old;
160
161 ob_debug_type(OB_DEBUG_FOCUS,
162 "focus_set_client 0x%lx\n", client ? client->window : 0);
163
164 /* uninstall the old colormap, and install the new one */
165 screen_install_colormap(focus_client, FALSE);
166 screen_install_colormap(client, TRUE);
167
168 if (client == NULL) {
169 ob_debug_type(OB_DEBUG_FOCUS, "actively focusing NONWINDOW\n");
170
171 /* when nothing will be focused, send focus to the backup target */
172 XSetInputFocus(ob_display, screen_support_win, RevertToNone,
173 event_curtime);
174 XSync(ob_display, FALSE);
175 }
176
177 /* in the middle of cycling..? kill it. CurrentTime is fine, time won't
178 be used.
179 */
180 if (focus_cycle_target)
181 focus_cycle(TRUE, TRUE, TRUE, TRUE, TRUE, TRUE);
182
183 old = focus_client;
184 focus_client = client;
185
186 /* move to the top of the list */
187 if (client != NULL)
188 push_to_top(client);
189
190 /* set the NET_ACTIVE_WINDOW hint, but preserve it on shutdown */
191 if (ob_state() != OB_STATE_EXITING) {
192 active = client ? client->window : None;
193 PROP_SET32(RootWindow(ob_display, ob_screen),
194 net_active_window, window, active);
195
196 /* remove hiliting from the window when it gets focused */
197 if (client != NULL)
198 client_hilite(client, FALSE);
199 }
200 }
201
202 ObClient* focus_fallback_target(gboolean allow_refocus, ObClient *old)
203 {
204 GList *it;
205 ObClient *target = NULL;
206 ObClient *desktop = NULL;
207
208 ob_debug_type(OB_DEBUG_FOCUS, "trying pointer stuff\n");
209 if (config_focus_follow && !config_focus_last)
210 {
211 if ((target = client_under_pointer()))
212 if (allow_refocus || target != old)
213 if (client_normal(target) && client_can_focus(target)) {
214 ob_debug_type(OB_DEBUG_FOCUS, "found in pointer stuff\n");
215 return target;
216 }
217 }
218
219 #if 0
220 /* try for group relations */
221 if (old->group) {
222 GSList *sit;
223
224 for (it = focus_order[screen_desktop]; it; it = g_list_next(it))
225 for (sit = old->group->members; sit; sit = g_slist_next(sit))
226 if (sit->data == it->data)
227 if (sit->data != old && client_normal(sit->data))
228 if (client_can_focus(sit->data))
229 return sit->data;
230 }
231 #endif
232
233 ob_debug_type(OB_DEBUG_FOCUS, "trying omnipresentness\n");
234 if (allow_refocus && old && old->desktop == DESKTOP_ALL)
235 return old;
236
237
238 ob_debug_type(OB_DEBUG_FOCUS, "trying the focus order\n");
239 for (it = focus_order; it; it = g_list_next(it))
240 if (allow_refocus || it->data != old) {
241 ObClient *c = it->data;
242 /* fallback focus to a window if:
243 1. it is actually focusable, cuz if it's not then we're sending
244 focus off to nothing
245 2. it is validated. if the window is about to disappear, then
246 don't try focus it.
247 3. it is visible on the current desktop. this ignores
248 omnipresent windows, which are problematic in their own rite.
249 4. it's not iconic
250 5. it is a normal type window, don't fall back onto a dock or
251 a splashscreen or a desktop window (save the desktop as a
252 backup fallback though)
253 */
254 if (client_can_focus(c) && c->desktop == screen_desktop &&
255 !c->iconic)
256 {
257 if (client_normal(c)) {
258 ob_debug_type(OB_DEBUG_FOCUS, "found in focus order\n");
259 return it->data;
260 } else if (c->type == OB_CLIENT_TYPE_DESKTOP && !desktop)
261 desktop = c;
262 }
263 }
264
265 /* as a last resort fallback to the desktop window if there is one.
266 (if there's more than one, then the one most recently focused.)
267 */
268 return desktop;
269 }
270
271 void focus_fallback(gboolean allow_refocus)
272 {
273 ObClient *new;
274 ObClient *old;
275
276 /* save this before moving focus away to nothing */
277 old = focus_client;
278
279 /* unfocus any focused clients.. they can be focused by Pointer events
280 and such, and then when I try focus them, I won't get a FocusIn event
281 at all for them.
282 */
283 focus_set_client(NULL);
284
285 if ((new = focus_fallback_target(allow_refocus, old)))
286 client_focus(new);
287 }
288
289 static void popup_cycle(ObClient *c, gboolean show)
290 {
291 if (!show) {
292 icon_popup_hide(focus_cycle_popup);
293 } else {
294 Rect *a;
295 ObClient *p = c;
296 gchar *title = NULL;
297
298 a = screen_physical_area_monitor(0);
299 icon_popup_position(focus_cycle_popup, CenterGravity,
300 a->x + a->width / 2, a->y + a->height / 2);
301 /* icon_popup_size(focus_cycle_popup, a->height/2, a->height/16);
302 icon_popup_show(focus_cycle_popup, c->title,
303 client_icon(c, a->height/16, a->height/16));
304 */
305 /* XXX the size and the font extents need to be related on some level
306 */
307 icon_popup_size(focus_cycle_popup, POPUP_WIDTH, POPUP_HEIGHT);
308
309 /* use the transient's parent's title/icon */
310 while (p->transient_for && p->transient_for != OB_TRAN_GROUP)
311 p = p->transient_for;
312
313 if (p != c && !strcmp("", (c->iconic ? c->icon_title : c->title)))
314 title = g_strdup(p->iconic ? p->icon_title : p->title);
315 /*title = g_strconcat((c->iconic ? c->icon_title : c->title),
316 " - ",
317 (p->iconic ? p->icon_title : p->title),
318 NULL);
319 */
320 icon_popup_show(focus_cycle_popup,
321 (title ? title :
322 (c->iconic ? c->icon_title : c->title)),
323 client_icon(p, 48, 48));
324 g_free(title);
325 }
326 }
327
328 void focus_cycle_draw_indicator()
329 {
330 if (!focus_cycle_target) {
331 XEvent e;
332
333 XUnmapWindow(ob_display, focus_indicator.top.win);
334 XUnmapWindow(ob_display, focus_indicator.left.win);
335 XUnmapWindow(ob_display, focus_indicator.right.win);
336 XUnmapWindow(ob_display, focus_indicator.bottom.win);
337
338 /* kill enter events cause by this unmapping */
339 XSync(ob_display, FALSE);
340 while (XCheckTypedEvent(ob_display, EnterNotify, &e));
341 } else {
342 /*
343 if (focus_cycle_target)
344 frame_adjust_focus(focus_cycle_target->frame, FALSE);
345 frame_adjust_focus(focus_cycle_target->frame, TRUE);
346 */
347 gint x, y, w, h;
348 gint wt, wl, wr, wb;
349
350 wt = wl = wr = wb = MAX(3,
351 MAX(1, MAX(ob_rr_theme->paddingx,
352 ob_rr_theme->paddingy)) * 2 +
353 ob_rr_theme->fbwidth * 2);
354
355 x = focus_cycle_target->frame->area.x;
356 y = focus_cycle_target->frame->area.y;
357 w = focus_cycle_target->frame->area.width;
358 h = wt;
359
360 XMoveResizeWindow(ob_display, focus_indicator.top.win,
361 x, y, w, h);
362 a_focus_indicator->texture[0].data.lineart.x1 = 0;
363 a_focus_indicator->texture[0].data.lineart.y1 = h-1;
364 a_focus_indicator->texture[0].data.lineart.x2 = 0;
365 a_focus_indicator->texture[0].data.lineart.y2 = 0;
366 a_focus_indicator->texture[1].data.lineart.x1 = 0;
367 a_focus_indicator->texture[1].data.lineart.y1 = 0;
368 a_focus_indicator->texture[1].data.lineart.x2 = w-1;
369 a_focus_indicator->texture[1].data.lineart.y2 = 0;
370 a_focus_indicator->texture[2].data.lineart.x1 = w-1;
371 a_focus_indicator->texture[2].data.lineart.y1 = 0;
372 a_focus_indicator->texture[2].data.lineart.x2 = w-1;
373 a_focus_indicator->texture[2].data.lineart.y2 = h-1;
374 a_focus_indicator->texture[3].data.lineart.x1 = (wl-1);
375 a_focus_indicator->texture[3].data.lineart.y1 = h-1;
376 a_focus_indicator->texture[3].data.lineart.x2 = w - wr;
377 a_focus_indicator->texture[3].data.lineart.y2 = h-1;
378 RrPaint(a_focus_indicator, focus_indicator.top.win,
379 w, h);
380
381 x = focus_cycle_target->frame->area.x;
382 y = focus_cycle_target->frame->area.y;
383 w = wl;
384 h = focus_cycle_target->frame->area.height;
385
386 XMoveResizeWindow(ob_display, focus_indicator.left.win,
387 x, y, w, h);
388 a_focus_indicator->texture[0].data.lineart.x1 = w-1;
389 a_focus_indicator->texture[0].data.lineart.y1 = 0;
390 a_focus_indicator->texture[0].data.lineart.x2 = 0;
391 a_focus_indicator->texture[0].data.lineart.y2 = 0;
392 a_focus_indicator->texture[1].data.lineart.x1 = 0;
393 a_focus_indicator->texture[1].data.lineart.y1 = 0;
394 a_focus_indicator->texture[1].data.lineart.x2 = 0;
395 a_focus_indicator->texture[1].data.lineart.y2 = h-1;
396 a_focus_indicator->texture[2].data.lineart.x1 = 0;
397 a_focus_indicator->texture[2].data.lineart.y1 = h-1;
398 a_focus_indicator->texture[2].data.lineart.x2 = w-1;
399 a_focus_indicator->texture[2].data.lineart.y2 = h-1;
400 a_focus_indicator->texture[3].data.lineart.x1 = w-1;
401 a_focus_indicator->texture[3].data.lineart.y1 = wt-1;
402 a_focus_indicator->texture[3].data.lineart.x2 = w-1;
403 a_focus_indicator->texture[3].data.lineart.y2 = h - wb;
404 RrPaint(a_focus_indicator, focus_indicator.left.win,
405 w, h);
406
407 x = focus_cycle_target->frame->area.x +
408 focus_cycle_target->frame->area.width - wr;
409 y = focus_cycle_target->frame->area.y;
410 w = wr;
411 h = focus_cycle_target->frame->area.height ;
412
413 XMoveResizeWindow(ob_display, focus_indicator.right.win,
414 x, y, w, h);
415 a_focus_indicator->texture[0].data.lineart.x1 = 0;
416 a_focus_indicator->texture[0].data.lineart.y1 = 0;
417 a_focus_indicator->texture[0].data.lineart.x2 = w-1;
418 a_focus_indicator->texture[0].data.lineart.y2 = 0;
419 a_focus_indicator->texture[1].data.lineart.x1 = w-1;
420 a_focus_indicator->texture[1].data.lineart.y1 = 0;
421 a_focus_indicator->texture[1].data.lineart.x2 = w-1;
422 a_focus_indicator->texture[1].data.lineart.y2 = h-1;
423 a_focus_indicator->texture[2].data.lineart.x1 = w-1;
424 a_focus_indicator->texture[2].data.lineart.y1 = h-1;
425 a_focus_indicator->texture[2].data.lineart.x2 = 0;
426 a_focus_indicator->texture[2].data.lineart.y2 = h-1;
427 a_focus_indicator->texture[3].data.lineart.x1 = 0;
428 a_focus_indicator->texture[3].data.lineart.y1 = wt-1;
429 a_focus_indicator->texture[3].data.lineart.x2 = 0;
430 a_focus_indicator->texture[3].data.lineart.y2 = h - wb;
431 RrPaint(a_focus_indicator, focus_indicator.right.win,
432 w, h);
433
434 x = focus_cycle_target->frame->area.x;
435 y = focus_cycle_target->frame->area.y +
436 focus_cycle_target->frame->area.height - wb;
437 w = focus_cycle_target->frame->area.width;
438 h = wb;
439
440 XMoveResizeWindow(ob_display, focus_indicator.bottom.win,
441 x, y, w, h);
442 a_focus_indicator->texture[0].data.lineart.x1 = 0;
443 a_focus_indicator->texture[0].data.lineart.y1 = 0;
444 a_focus_indicator->texture[0].data.lineart.x2 = 0;
445 a_focus_indicator->texture[0].data.lineart.y2 = h-1;
446 a_focus_indicator->texture[1].data.lineart.x1 = 0;
447 a_focus_indicator->texture[1].data.lineart.y1 = h-1;
448 a_focus_indicator->texture[1].data.lineart.x2 = w-1;
449 a_focus_indicator->texture[1].data.lineart.y2 = h-1;
450 a_focus_indicator->texture[2].data.lineart.x1 = w-1;
451 a_focus_indicator->texture[2].data.lineart.y1 = h-1;
452 a_focus_indicator->texture[2].data.lineart.x2 = w-1;
453 a_focus_indicator->texture[2].data.lineart.y2 = 0;
454 a_focus_indicator->texture[3].data.lineart.x1 = wl-1;
455 a_focus_indicator->texture[3].data.lineart.y1 = 0;
456 a_focus_indicator->texture[3].data.lineart.x2 = w - wr;
457 a_focus_indicator->texture[3].data.lineart.y2 = 0;
458 RrPaint(a_focus_indicator, focus_indicator.bottom.win,
459 w, h);
460
461 XMapWindow(ob_display, focus_indicator.top.win);
462 XMapWindow(ob_display, focus_indicator.left.win);
463 XMapWindow(ob_display, focus_indicator.right.win);
464 XMapWindow(ob_display, focus_indicator.bottom.win);
465 }
466 }
467
468 static gboolean valid_focus_target(ObClient *ft)
469 {
470 /* we don't use client_can_focus here, because that doesn't let you
471 focus an iconic window, but we want to be able to, so we just check
472 if the focus flags on the window allow it, and its on the current
473 desktop */
474 if ((ft->type == OB_CLIENT_TYPE_NORMAL ||
475 ft->type == OB_CLIENT_TYPE_DIALOG ||
476 (!client_has_group_siblings(ft) &&
477 (ft->type == OB_CLIENT_TYPE_TOOLBAR ||
478 ft->type == OB_CLIENT_TYPE_MENU ||
479 ft->type == OB_CLIENT_TYPE_UTILITY))) &&
480 ((ft->can_focus || ft->focus_notify) &&
481 !ft->skip_pager &&
482 (ft->desktop == screen_desktop || ft->desktop == DESKTOP_ALL)) &&
483 ft == client_focus_target(ft))
484 return TRUE;
485 /*
486 {
487 GSList *it;
488
489 for (it = ft->transients; it; it = g_slist_next(it)) {
490 ObClient *c = it->data;
491
492 if (c->frame->visible)
493 return FALSE;
494 }
495 return TRUE;
496 }
497 */
498
499 return FALSE;
500 }
501
502 void focus_cycle(gboolean forward, gboolean linear, gboolean interactive,
503 gboolean dialog, gboolean done, gboolean cancel)
504 {
505 static ObClient *first = NULL;
506 static ObClient *t = NULL;
507 static GList *order = NULL;
508 GList *it, *start, *list;
509 ObClient *ft = NULL;
510
511 if (interactive) {
512 if (cancel) {
513 focus_cycle_target = NULL;
514 goto done_cycle;
515 } else if (done)
516 goto done_cycle;
517
518 if (!focus_order)
519 goto done_cycle;
520
521 if (!first) first = focus_client;
522
523 if (linear) list = client_list;
524 else list = focus_order;
525 } else {
526 if (!focus_order)
527 goto done_cycle;
528 list = client_list;
529 }
530 if (!focus_cycle_target) focus_cycle_target = focus_client;
531
532 start = it = g_list_find(list, focus_cycle_target);
533 if (!start) /* switched desktops or something? */
534 start = it = forward ? g_list_last(list) : g_list_first(list);
535 if (!start) goto done_cycle;
536
537 do {
538 if (forward) {
539 it = it->next;
540 if (it == NULL) it = g_list_first(list);
541 } else {
542 it = it->prev;
543 if (it == NULL) it = g_list_last(list);
544 }
545 ft = it->data;
546 if (valid_focus_target(ft)) {
547 if (interactive) {
548 if (ft != focus_cycle_target) { /* prevents flicker */
549 focus_cycle_target = ft;
550 focus_cycle_draw_indicator();
551 }
552 popup_cycle(ft, dialog);
553 return;
554 } else if (ft != focus_cycle_target) {
555 focus_cycle_target = ft;
556 done = TRUE;
557 break;
558 }
559 }
560 } while (it != start);
561
562 done_cycle:
563 if (done && focus_cycle_target)
564 client_activate(focus_cycle_target, FALSE, TRUE);
565
566 t = NULL;
567 first = NULL;
568 focus_cycle_target = NULL;
569 g_list_free(order);
570 order = NULL;
571
572 if (interactive) {
573 focus_cycle_draw_indicator();
574 popup_cycle(ft, FALSE);
575 }
576
577 return;
578 }
579
580 void focus_directional_cycle(ObDirection dir, gboolean interactive,
581 gboolean dialog, gboolean done, gboolean cancel)
582 {
583 static ObClient *first = NULL;
584 ObClient *ft = NULL;
585
586 if (!interactive)
587 return;
588
589 if (cancel) {
590 focus_cycle_target = NULL;
591 goto done_cycle;
592 } else if (done)
593 goto done_cycle;
594
595 if (!focus_order)
596 goto done_cycle;
597
598 if (!first) first = focus_client;
599 if (!focus_cycle_target) focus_cycle_target = focus_client;
600
601 if (focus_cycle_target)
602 ft = client_find_directional(focus_cycle_target, dir);
603 else {
604 GList *it;
605
606 for (it = focus_order; it; it = g_list_next(it))
607 if (valid_focus_target(it->data))
608 ft = it->data;
609 }
610
611 if (ft) {
612 if (ft != focus_cycle_target) {/* prevents flicker */
613 focus_cycle_target = ft;
614 focus_cycle_draw_indicator();
615 }
616 }
617 if (focus_cycle_target) {
618 popup_cycle(focus_cycle_target, dialog);
619 if (dialog)
620 return;
621 }
622
623
624 done_cycle:
625 if (done && focus_cycle_target)
626 client_activate(focus_cycle_target, FALSE, TRUE);
627
628 first = NULL;
629 focus_cycle_target = NULL;
630
631 focus_cycle_draw_indicator();
632 popup_cycle(ft, FALSE);
633
634 return;
635 }
636
637 void focus_order_add_new(ObClient *c)
638 {
639 if (c->iconic)
640 focus_order_to_top(c);
641 else {
642 g_assert(!g_list_find(focus_order, c));
643 /* if there are any iconic windows, put this above them in the order,
644 but if there are not, then put it under the currently focused one */
645 if (focus_order && ((ObClient*)focus_order->data)->iconic)
646 focus_order = g_list_insert(focus_order, c, 0);
647 else
648 focus_order = g_list_insert(focus_order, c, 1);
649 }
650 }
651
652 void focus_order_remove(ObClient *c)
653 {
654 focus_order = g_list_remove(focus_order, c);
655 }
656
657 void focus_order_to_top(ObClient *c)
658 {
659 focus_order = g_list_remove(focus_order, c);
660 if (!c->iconic) {
661 focus_order = g_list_prepend(focus_order, c);
662 } else {
663 GList *it;
664
665 /* insert before first iconic window */
666 for (it = focus_order;
667 it && !((ObClient*)it->data)->iconic; it = g_list_next(it));
668 focus_order = g_list_insert_before(focus_order, it, c);
669 }
670 }
671
672 void focus_order_to_bottom(ObClient *c)
673 {
674 focus_order = g_list_remove(focus_order, c);
675 if (c->iconic) {
676 focus_order = g_list_append(focus_order, c);
677 } else {
678 GList *it;
679
680 /* insert before first iconic window */
681 for (it = focus_order;
682 it && !((ObClient*)it->data)->iconic; it = g_list_next(it));
683 focus_order = g_list_insert_before(focus_order, it, c);
684 }
685 }
686
687 ObClient *focus_order_find_first(guint desktop)
688 {
689 GList *it;
690 for (it = focus_order; it; it = g_list_next(it)) {
691 ObClient *c = it->data;
692 if (c->desktop == desktop || c->desktop == DESKTOP_ALL)
693 return c;
694 }
695 return NULL;
696 }
This page took 0.061064 seconds and 3 git commands to generate.