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