]> icculus.org git repositories - mikachu/openbox.git/blob - openbox/focus.c
make a copy of the color
[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_black;
53 RrColor *color_white;
54
55 static ObIconPopup *focus_cycle_popup;
56
57 static void focus_cycle_destructor(ObClient *client, gpointer data)
58 {
59     /* end cycling if the target disappears */
60     if (focus_cycle_target == client)
61         focus_cycle(TRUE, TRUE, TRUE, TRUE, TRUE);
62 }
63
64 static Window createWindow(Window parent, unsigned long mask,
65                            XSetWindowAttributes *attrib)
66 {
67     return XCreateWindow(ob_display, parent, 0, 0, 1, 1, 0,
68                          RrDepth(ob_rr_inst), InputOutput,
69                          RrVisual(ob_rr_inst), mask, attrib);
70                        
71 }
72
73 void focus_startup(gboolean reconfig)
74 {
75     focus_cycle_popup = icon_popup_new(TRUE);
76
77     if (!reconfig) {
78         XSetWindowAttributes attr;
79
80         client_add_destructor(focus_cycle_destructor, NULL);
81
82         /* start with nothing focused */
83         focus_set_client(NULL);
84
85         focus_indicator.top.obwin.type = Window_Internal;
86         focus_indicator.left.obwin.type = Window_Internal;
87         focus_indicator.right.obwin.type = Window_Internal;
88         focus_indicator.bottom.obwin.type = Window_Internal;
89
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, &attr);
95         focus_indicator.left.win =
96             createWindow(RootWindow(ob_display, ob_screen),
97                          CWOverrideRedirect | CWBackPixel, &attr);
98         focus_indicator.right.win =
99             createWindow(RootWindow(ob_display, ob_screen),
100                          CWOverrideRedirect | CWBackPixel, &attr);
101         focus_indicator.bottom.win =
102             createWindow(RootWindow(ob_display, ob_screen),
103                          CWOverrideRedirect | CWBackPixel, &attr);
104
105         stacking_add(INTERNAL_AS_WINDOW(&focus_indicator.top));
106         stacking_add(INTERNAL_AS_WINDOW(&focus_indicator.left));
107         stacking_add(INTERNAL_AS_WINDOW(&focus_indicator.right));
108         stacking_add(INTERNAL_AS_WINDOW(&focus_indicator.bottom));
109
110         color_black = RrColorNew(ob_rr_inst, 0, 0, 0);
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     guint i;
132
133     icon_popup_free(focus_cycle_popup);
134
135     if (!reconfig) {
136         client_remove_destructor(focus_cycle_destructor);
137
138         for (i = 0; i < screen_num_desktops; ++i)
139             g_list_free(focus_order[i]);
140         g_free(focus_order);
141
142         /* reset focus to root */
143         XSetInputFocus(ob_display, PointerRoot, RevertToNone, event_lasttime);
144
145         RrColorFree(color_black);
146         RrColorFree(color_white);
147
148         RrAppearanceFree(a_focus_indicator);
149
150         XDestroyWindow(ob_display, focus_indicator.top.win);
151         XDestroyWindow(ob_display, focus_indicator.left.win);
152         XDestroyWindow(ob_display, focus_indicator.right.win);
153         XDestroyWindow(ob_display, focus_indicator.bottom.win);
154     }
155 }
156
157 static void push_to_top(ObClient *client)
158 {
159     guint desktop;
160
161     desktop = client->desktop;
162     if (desktop == DESKTOP_ALL) desktop = screen_desktop;
163     focus_order[desktop] = g_list_remove(focus_order[desktop], client);
164     focus_order[desktop] = g_list_prepend(focus_order[desktop], client);
165 }
166
167 void focus_set_client(ObClient *client)
168 {
169     Window active;
170     ObClient *old;
171
172 #ifdef DEBUG_FOCUS
173     ob_debug("focus_set_client 0x%lx\n", client ? client->window : 0);
174 #endif
175
176     /* uninstall the old colormap, and install the new one */
177     screen_install_colormap(focus_client, FALSE);
178     screen_install_colormap(client, TRUE);
179
180     if (client == NULL) {
181 #ifdef DEBUG_FOCUS
182         ob_debug("actively focusing NONWINDOW\n");
183 #endif
184         /* when nothing will be focused, send focus to the backup target */
185         XSetInputFocus(ob_display, screen_support_win, RevertToNone,
186                        event_lasttime);
187         XSync(ob_display, FALSE);
188     }
189
190     /* in the middle of cycling..? kill it. */
191     if (focus_cycle_target)
192         focus_cycle(TRUE, TRUE, TRUE, TRUE, TRUE);
193
194     old = focus_client;
195     focus_client = client;
196
197     /* move to the top of the list */
198     if (client != NULL)
199         push_to_top(client);
200
201     /* set the NET_ACTIVE_WINDOW hint, but preserve it on shutdown */
202     if (ob_state() != OB_STATE_EXITING) {
203         active = client ? client->window : None;
204         PROP_SET32(RootWindow(ob_display, ob_screen),
205                    net_active_window, window, active);
206     }
207 }
208
209 /* finds the first transient that isn't 'skip' and ensure's that client_normal
210  is true for it */
211 static ObClient *find_transient_recursive(ObClient *c, ObClient *top, ObClient *skip)
212 {
213     GSList *it;
214     ObClient *ret;
215
216     for (it = c->transients; it; it = it->next) {
217         if (it->data == top) return NULL;
218         ret = find_transient_recursive(it->data, top, skip);
219         if (ret && ret != skip && client_normal(ret)) return ret;
220         if (it->data != skip && client_normal(it->data)) return it->data;
221     }
222     return NULL;
223 }
224
225 static ObClient* focus_fallback_transient(ObClient *top, ObClient *old)
226 {
227     ObClient *target = find_transient_recursive(top, top, old);
228     if (!target) {
229         /* make sure client_normal is true always */
230         if (!client_normal(top))
231             return NULL;
232         target = top; /* no transient, keep the top */
233     }
234     if (client_can_focus(target))
235         return target;
236     else
237         return NULL;
238 }
239
240 ObClient* focus_fallback_target(ObFocusFallbackType type)
241 {
242     GList *it;
243     ObClient *old = NULL;
244     ObClient *target = NULL;
245
246     old = focus_client;
247
248     if (type == OB_FOCUS_FALLBACK_UNFOCUSING && old) {
249         if (old->transient_for) {
250             gboolean trans = FALSE;
251
252             if (!config_focus_follow)
253                 trans = TRUE;
254             else {
255                 if ((target = client_under_pointer()) &&
256                     client_search_transient
257                     (client_search_top_transient(target), old))
258                 {
259                     trans = TRUE;
260                 }
261             }
262
263             /* try for transient relations */
264             if (trans) {
265                 if (old->transient_for == OB_TRAN_GROUP) {
266                     for (it = focus_order[screen_desktop]; it; it = it->next) {
267                         GSList *sit;
268
269                         for (sit = old->group->members; sit; sit = sit->next)
270                             if (sit->data == it->data)
271                                 if ((target =
272                                      focus_fallback_transient(sit->data, old)))
273                                     return target;
274                     }
275                 } else {
276                     if ((target =
277                          focus_fallback_transient(old->transient_for, old)))
278                         return target;
279                 }
280             }
281         }
282     }
283
284     if (config_focus_follow) {
285         if ((target = client_under_pointer()))
286             if (client_normal(target) && client_can_focus(target))
287                 return target;
288     }
289
290 #if 0
291         /* try for group relations */
292         if (old->group) {
293             GSList *sit;
294
295             for (it = focus_order[screen_desktop]; it != NULL; it = it->next)
296                 for (sit = old->group->members; sit; sit = sit->next)
297                     if (sit->data == it->data)
298                         if (sit->data != old && client_normal(sit->data))
299                             if (client_can_focus(sit->data))
300                                 return sit->data;
301         }
302 #endif
303
304     for (it = focus_order[screen_desktop]; it != NULL; it = it->next)
305         if (type != OB_FOCUS_FALLBACK_UNFOCUSING || it->data != old)
306             if (client_normal(it->data) && client_can_focus(it->data))
307                 return it->data;
308
309     return NULL;
310 }
311
312 void focus_fallback(ObFocusFallbackType type)
313 {
314     ObClient *new;
315
316     /* unfocus any focused clients.. they can be focused by Pointer events
317        and such, and then when I try focus them, I won't get a FocusIn event
318        at all for them.
319     */
320     focus_set_client(NULL);
321
322     if ((new = focus_fallback_target(type)))
323         client_focus(new);
324 }
325
326 static void popup_cycle(ObClient *c, gboolean show)
327 {
328     if (!show) {
329         icon_popup_hide(focus_cycle_popup);
330     } else {
331         Rect *a;
332         ObClient *p = c;
333         char *title;
334
335         a = screen_physical_area_monitor(0);
336         icon_popup_position(focus_cycle_popup, CenterGravity,
337                             a->x + a->width / 2, a->y + a->height / 2);
338 /*        icon_popup_size(focus_cycle_popup, a->height/2, a->height/16);
339         icon_popup_show(focus_cycle_popup, c->title,
340                         client_icon(c, a->height/16, a->height/16));
341 */
342         /* XXX the size and the font extents need to be related on some level
343          */
344         icon_popup_size(focus_cycle_popup, POPUP_WIDTH, POPUP_HEIGHT);
345
346         /* use the transient's parent's title/icon */
347         while (p->transient_for && p->transient_for != OB_TRAN_GROUP)
348             p = p->transient_for;
349
350         if (p == c)
351             title = NULL;
352         else
353             title = g_strconcat((c->iconic ? c->icon_title : c->title),
354                                 " - ",
355                                 (p->iconic ? p->icon_title : p->title),
356                                 NULL);
357
358         icon_popup_show(focus_cycle_popup,
359                         (title ? title :
360                          (c->iconic ? c->icon_title : c->title)),
361                         client_icon(p, 48, 48));
362         g_free(title);
363     }
364 }
365
366 void focus_cycle_draw_indicator()
367 {
368     if (!focus_cycle_target) {
369         XUnmapWindow(ob_display, focus_indicator.top.win);
370         XUnmapWindow(ob_display, focus_indicator.left.win);
371         XUnmapWindow(ob_display, focus_indicator.right.win);
372         XUnmapWindow(ob_display, focus_indicator.bottom.win);
373     } else {
374         /*
375           if (focus_cycle_target)
376               frame_adjust_focus(focus_cycle_target->frame, FALSE);
377           frame_adjust_focus(focus_cycle_target->frame, TRUE);
378         */
379         int x, y, w, h;
380         int wt, wl, wr, wb;
381
382         wt = wl = wr = wb = MAX(3,
383                                 ob_rr_theme->handle_height +
384                                 ob_rr_theme->bwidth * 2);
385
386         x = focus_cycle_target->frame->area.x;
387         y = focus_cycle_target->frame->area.y;
388         w = focus_cycle_target->frame->area.width;
389         h = wt;
390
391         XMoveResizeWindow(ob_display, focus_indicator.top.win,
392                           x, y, w, h);
393         a_focus_indicator->texture[0].data.lineart.x1 = 0;
394         a_focus_indicator->texture[0].data.lineart.y1 = h-1;
395         a_focus_indicator->texture[0].data.lineart.x2 = 0;
396         a_focus_indicator->texture[0].data.lineart.y2 = 0;
397         a_focus_indicator->texture[1].data.lineart.x1 = 0;
398         a_focus_indicator->texture[1].data.lineart.y1 = 0;
399         a_focus_indicator->texture[1].data.lineart.x2 = w-1;
400         a_focus_indicator->texture[1].data.lineart.y2 = 0;
401         a_focus_indicator->texture[2].data.lineart.x1 = w-1;
402         a_focus_indicator->texture[2].data.lineart.y1 = 0;
403         a_focus_indicator->texture[2].data.lineart.x2 = w-1;
404         a_focus_indicator->texture[2].data.lineart.y2 = h-1;
405         a_focus_indicator->texture[3].data.lineart.x1 = (wl-1);
406         a_focus_indicator->texture[3].data.lineart.y1 = h-1;
407         a_focus_indicator->texture[3].data.lineart.x2 = w - wr;
408         a_focus_indicator->texture[3].data.lineart.y2 = h-1;
409         RrPaint(a_focus_indicator, focus_indicator.top.win,
410                 w, h);
411
412         x = focus_cycle_target->frame->area.x;
413         y = focus_cycle_target->frame->area.y;
414         w = wl;
415         h = focus_cycle_target->frame->area.height;
416
417         XMoveResizeWindow(ob_display, focus_indicator.left.win,
418                           x, y, w, h);
419         a_focus_indicator->texture[0].data.lineart.x1 = w-1;
420         a_focus_indicator->texture[0].data.lineart.y1 = 0;
421         a_focus_indicator->texture[0].data.lineart.x2 = 0;
422         a_focus_indicator->texture[0].data.lineart.y2 = 0;
423         a_focus_indicator->texture[1].data.lineart.x1 = 0;
424         a_focus_indicator->texture[1].data.lineart.y1 = 0;
425         a_focus_indicator->texture[1].data.lineart.x2 = 0;
426         a_focus_indicator->texture[1].data.lineart.y2 = h-1;
427         a_focus_indicator->texture[2].data.lineart.x1 = 0;
428         a_focus_indicator->texture[2].data.lineart.y1 = h-1;
429         a_focus_indicator->texture[2].data.lineart.x2 = w-1;
430         a_focus_indicator->texture[2].data.lineart.y2 = h-1;
431         a_focus_indicator->texture[3].data.lineart.x1 = w-1;
432         a_focus_indicator->texture[3].data.lineart.y1 = wt-1;
433         a_focus_indicator->texture[3].data.lineart.x2 = w-1;
434         a_focus_indicator->texture[3].data.lineart.y2 = h - wb;
435         RrPaint(a_focus_indicator, focus_indicator.left.win,
436                 w, h);
437
438         x = focus_cycle_target->frame->area.x +
439             focus_cycle_target->frame->area.width - wr;
440         y = focus_cycle_target->frame->area.y;
441         w = wr;
442         h = focus_cycle_target->frame->area.height ;
443
444         XMoveResizeWindow(ob_display, focus_indicator.right.win,
445                           x, y, w, h);
446         a_focus_indicator->texture[0].data.lineart.x1 = 0;
447         a_focus_indicator->texture[0].data.lineart.y1 = 0;
448         a_focus_indicator->texture[0].data.lineart.x2 = w-1;
449         a_focus_indicator->texture[0].data.lineart.y2 = 0;
450         a_focus_indicator->texture[1].data.lineart.x1 = w-1;
451         a_focus_indicator->texture[1].data.lineart.y1 = 0;
452         a_focus_indicator->texture[1].data.lineart.x2 = w-1;
453         a_focus_indicator->texture[1].data.lineart.y2 = h-1;
454         a_focus_indicator->texture[2].data.lineart.x1 = w-1;
455         a_focus_indicator->texture[2].data.lineart.y1 = h-1;
456         a_focus_indicator->texture[2].data.lineart.x2 = 0;
457         a_focus_indicator->texture[2].data.lineart.y2 = h-1;
458         a_focus_indicator->texture[3].data.lineart.x1 = 0;
459         a_focus_indicator->texture[3].data.lineart.y1 = wt-1;
460         a_focus_indicator->texture[3].data.lineart.x2 = 0;
461         a_focus_indicator->texture[3].data.lineart.y2 = h - wb;
462         RrPaint(a_focus_indicator, focus_indicator.right.win,
463                 w, h);
464
465         x = focus_cycle_target->frame->area.x;
466         y = focus_cycle_target->frame->area.y +
467             focus_cycle_target->frame->area.height - wb;
468         w = focus_cycle_target->frame->area.width;
469         h = wb;
470
471         XMoveResizeWindow(ob_display, focus_indicator.bottom.win,
472                           x, y, w, h);
473         a_focus_indicator->texture[0].data.lineart.x1 = 0;
474         a_focus_indicator->texture[0].data.lineart.y1 = 0;
475         a_focus_indicator->texture[0].data.lineart.x2 = 0;
476         a_focus_indicator->texture[0].data.lineart.y2 = h-1;
477         a_focus_indicator->texture[1].data.lineart.x1 = 0;
478         a_focus_indicator->texture[1].data.lineart.y1 = h-1;
479         a_focus_indicator->texture[1].data.lineart.x2 = w-1;
480         a_focus_indicator->texture[1].data.lineart.y2 = h-1;
481         a_focus_indicator->texture[2].data.lineart.x1 = w-1;
482         a_focus_indicator->texture[2].data.lineart.y1 = h-1;
483         a_focus_indicator->texture[2].data.lineart.x2 = w-1;
484         a_focus_indicator->texture[2].data.lineart.y2 = 0;
485         a_focus_indicator->texture[3].data.lineart.x1 = wl-1;
486         a_focus_indicator->texture[3].data.lineart.y1 = 0;
487         a_focus_indicator->texture[3].data.lineart.x2 = w - wr;
488         a_focus_indicator->texture[3].data.lineart.y2 = 0;
489         RrPaint(a_focus_indicator, focus_indicator.bottom.win,
490                 w, h);
491
492         XMapWindow(ob_display, focus_indicator.top.win);
493         XMapWindow(ob_display, focus_indicator.left.win);
494         XMapWindow(ob_display, focus_indicator.right.win);
495         XMapWindow(ob_display, focus_indicator.bottom.win);
496     }
497 }
498
499 static gboolean valid_focus_target(ObClient *ft)
500 {
501     /* we don't use client_can_focus here, because that doesn't let you
502        focus an iconic window, but we want to be able to, so we just check
503        if the focus flags on the window allow it, and its on the current
504        desktop */
505     return ((ft->type == OB_CLIENT_TYPE_NORMAL ||
506              ft->type == OB_CLIENT_TYPE_DIALOG ||
507              (!client_has_group_siblings(ft) &&
508               (ft->type == OB_CLIENT_TYPE_TOOLBAR ||
509                ft->type == OB_CLIENT_TYPE_MENU ||
510                ft->type == OB_CLIENT_TYPE_UTILITY))) &&
511             !ft->transients &&
512             ((ft->can_focus || ft->focus_notify) &&
513              !ft->skip_taskbar &&
514              (ft->desktop == screen_desktop || ft->desktop == DESKTOP_ALL)));
515 }
516
517 void focus_cycle(gboolean forward, gboolean linear,
518                  gboolean dialog, gboolean done, gboolean cancel)
519 {
520     static ObClient *first = NULL;
521     static ObClient *t = NULL;
522     static GList *order = NULL;
523     GList *it, *start, *list;
524     ObClient *ft = NULL;
525
526     if (cancel) {
527         focus_cycle_target = NULL;
528         goto done_cycle;
529     } else if (done && dialog) {
530         goto done_cycle;
531     }
532
533     if (!focus_order[screen_desktop])
534         goto done_cycle;
535
536     if (!first) first = focus_client;
537     if (!focus_cycle_target) focus_cycle_target = focus_client;
538
539     if (linear) list = client_list;
540     else        list = focus_order[screen_desktop];
541
542     start = it = g_list_find(list, focus_cycle_target);
543     if (!start) /* switched desktops or something? */
544         start = it = forward ? g_list_last(list) : g_list_first(list);
545     if (!start) goto done_cycle;
546
547     do {
548         if (forward) {
549             it = it->next;
550             if (it == NULL) it = g_list_first(list);
551         } else {
552             it = it->prev;
553             if (it == NULL) it = g_list_last(list);
554         }
555         ft = it->data;
556         if (valid_focus_target(ft)) {
557             if (ft != focus_cycle_target) { /* prevents flicker */
558                 focus_cycle_target = ft;
559                 focus_cycle_draw_indicator();
560             }
561             popup_cycle(ft, dialog);
562             return;
563         }
564     } while (it != start);
565
566 done_cycle:
567     if (done && focus_cycle_target)
568         client_activate(focus_cycle_target, FALSE);
569
570     t = NULL;
571     first = NULL;
572     focus_cycle_target = NULL;
573     g_list_free(order);
574     order = NULL;
575
576     focus_cycle_draw_indicator();
577     popup_cycle(ft, FALSE);
578
579     return;
580 }
581
582 void focus_directional_cycle(ObDirection dir,
583                              gboolean dialog, gboolean done, gboolean cancel)
584 {
585     static ObClient *first = NULL;
586     ObClient *ft = NULL;
587
588     if (cancel) {
589         focus_cycle_target = NULL;
590         goto done_cycle;
591     } else if (done && dialog) {
592         goto done_cycle;
593     }
594
595     if (!focus_order[screen_desktop])
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[screen_desktop]; 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);
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     guint d, i;
640
641     if (c->iconic)
642         focus_order_to_top(c);
643     else {
644         d = c->desktop;
645         if (d == DESKTOP_ALL) {
646             for (i = 0; i < screen_num_desktops; ++i) {
647                 if (focus_order[i] && ((ObClient*)focus_order[i]->data)->iconic)
648                     focus_order[i] = g_list_insert(focus_order[i], c, 0);
649                 else
650                     focus_order[i] = g_list_insert(focus_order[i], c, 1);
651             }
652         } else
653              if (focus_order[d] && ((ObClient*)focus_order[d]->data)->iconic)
654                 focus_order[d] = g_list_insert(focus_order[d], c, 0);
655             else
656                 focus_order[d] = g_list_insert(focus_order[d], c, 1);
657     }
658 }
659
660 void focus_order_remove(ObClient *c)
661 {
662     guint d, i;
663
664     d = c->desktop;
665     if (d == DESKTOP_ALL) {
666         for (i = 0; i < screen_num_desktops; ++i)
667             focus_order[i] = g_list_remove(focus_order[i], c);
668     } else
669         focus_order[d] = g_list_remove(focus_order[d], c);
670 }
671
672 static void to_top(ObClient *c, guint d)
673 {
674     focus_order[d] = g_list_remove(focus_order[d], c);
675     if (!c->iconic) {
676         focus_order[d] = g_list_prepend(focus_order[d], c);
677     } else {
678         GList *it;
679
680         /* insert before first iconic window */
681         for (it = focus_order[d];
682              it && !((ObClient*)it->data)->iconic; it = it->next);
683         focus_order[d] = g_list_insert_before(focus_order[d], it, c);
684     }
685 }
686
687 void focus_order_to_top(ObClient *c)
688 {
689     guint d, i;
690
691     d = c->desktop;
692     if (d == DESKTOP_ALL) {
693         for (i = 0; i < screen_num_desktops; ++i)
694             to_top(c, i);
695     } else
696         to_top(c, d);
697 }
698
699 static void to_bottom(ObClient *c, guint d)
700 {
701     focus_order[d] = g_list_remove(focus_order[d], c);
702     if (c->iconic) {
703         focus_order[d] = g_list_append(focus_order[d], c);
704     } else {
705         GList *it;
706
707         /* insert before first iconic window */
708         for (it = focus_order[d];
709              it && !((ObClient*)it->data)->iconic; it = it->next);
710         g_list_insert_before(focus_order[d], it, c);
711     }
712 }
713
714 void focus_order_to_bottom(ObClient *c)
715 {
716     guint d, i;
717
718     d = c->desktop;
719     if (d == DESKTOP_ALL) {
720         for (i = 0; i < screen_num_desktops; ++i)
721             to_bottom(c, i);
722     } else
723         to_bottom(c, d);
724 }