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