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