]> icculus.org git repositories - mikachu/openbox.git/blob - openbox/focus.c
make em saveunder
[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, unsigned long 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, ObClient *skip)
214 {
215     GSList *it;
216     ObClient *ret;
217
218     for (it = c->transients; it; it = it->next) {
219         if (it->data == top) return NULL;
220         ret = find_transient_recursive(it->data, top, skip);
221         if (ret && ret != skip && client_normal(ret)) return ret;
222         if (it->data != skip && client_normal(it->data)) return it->data;
223     }
224     return NULL;
225 }
226
227 static ObClient* focus_fallback_transient(ObClient *top, ObClient *old)
228 {
229     ObClient *target = find_transient_recursive(top, top, old);
230     if (!target) {
231         /* make sure client_normal is true always */
232         if (!client_normal(top))
233             return NULL;
234         target = top; /* no transient, keep the top */
235     }
236     if (client_can_focus(target))
237         return target;
238     else
239         return NULL;
240 }
241
242 ObClient* focus_fallback_target(ObFocusFallbackType type)
243 {
244     GList *it;
245     ObClient *old = NULL;
246     ObClient *target = NULL;
247
248     old = focus_client;
249
250     if (type == OB_FOCUS_FALLBACK_UNFOCUSING && old) {
251         if (old->transient_for) {
252             gboolean trans = FALSE;
253
254             if (!config_focus_follow)
255                 trans = TRUE;
256             else {
257                 if ((target = client_under_pointer()) &&
258                     client_search_transient
259                     (client_search_top_transient(target), old))
260                 {
261                     trans = TRUE;
262                 }
263             }
264
265             /* try for transient relations */
266             if (trans) {
267                 if (old->transient_for == OB_TRAN_GROUP) {
268                     for (it = focus_order[screen_desktop]; it; it = it->next) {
269                         GSList *sit;
270
271                         for (sit = old->group->members; sit; sit = sit->next)
272                             if (sit->data == it->data)
273                                 if ((target =
274                                      focus_fallback_transient(sit->data, old)))
275                                     return target;
276                     }
277                 } else {
278                     if ((target =
279                          focus_fallback_transient(old->transient_for, old)))
280                         return target;
281                 }
282             }
283         }
284     }
285
286     if (config_focus_follow) {
287         if ((target = client_under_pointer()))
288             if (client_normal(target) && client_can_focus(target))
289                 return target;
290     }
291
292 #if 0
293         /* try for group relations */
294         if (old->group) {
295             GSList *sit;
296
297             for (it = focus_order[screen_desktop]; it != NULL; it = it->next)
298                 for (sit = old->group->members; sit; sit = sit->next)
299                     if (sit->data == it->data)
300                         if (sit->data != old && client_normal(sit->data))
301                             if (client_can_focus(sit->data))
302                                 return sit->data;
303         }
304 #endif
305
306     for (it = focus_order[screen_desktop]; it != NULL; it = it->next)
307         if (type != OB_FOCUS_FALLBACK_UNFOCUSING || it->data != old)
308             if (client_normal(it->data) && client_can_focus(it->data))
309                 return it->data;
310
311     return NULL;
312 }
313
314 void focus_fallback(ObFocusFallbackType type)
315 {
316     ObClient *new;
317
318     /* unfocus any focused clients.. they can be focused by Pointer events
319        and such, and then when I try focus them, I won't get a FocusIn event
320        at all for them.
321     */
322     focus_set_client(NULL);
323
324     if ((new = focus_fallback_target(type)))
325         client_focus(new);
326 }
327
328 static void popup_cycle(ObClient *c, gboolean show)
329 {
330     if (!show) {
331         icon_popup_hide(focus_cycle_popup);
332     } else {
333         Rect *a;
334         ObClient *p = c;
335         char *title;
336
337         a = screen_physical_area_monitor(0);
338         icon_popup_position(focus_cycle_popup, CenterGravity,
339                             a->x + a->width / 2, a->y + a->height / 2);
340 /*        icon_popup_size(focus_cycle_popup, a->height/2, a->height/16);
341         icon_popup_show(focus_cycle_popup, c->title,
342                         client_icon(c, a->height/16, a->height/16));
343 */
344         /* XXX the size and the font extents need to be related on some level
345          */
346         icon_popup_size(focus_cycle_popup, POPUP_WIDTH, POPUP_HEIGHT);
347
348         /* use the transient's parent's title/icon */
349         while (p->transient_for && p->transient_for != OB_TRAN_GROUP)
350             p = p->transient_for;
351
352         if (p == c)
353             title = NULL;
354         else
355             title = g_strconcat((c->iconic ? c->icon_title : c->title),
356                                 " - ",
357                                 (p->iconic ? p->icon_title : p->title),
358                                 NULL);
359
360         icon_popup_show(focus_cycle_popup,
361                         (title ? title :
362                          (c->iconic ? c->icon_title : c->title)),
363                         client_icon(p, 48, 48));
364         g_free(title);
365     }
366 }
367
368 void focus_cycle_draw_indicator()
369 {
370     if (!focus_cycle_target) {
371         XUnmapWindow(ob_display, focus_indicator.top.win);
372         XUnmapWindow(ob_display, focus_indicator.left.win);
373         XUnmapWindow(ob_display, focus_indicator.right.win);
374         XUnmapWindow(ob_display, focus_indicator.bottom.win);
375     } else {
376         /*
377           if (focus_cycle_target)
378               frame_adjust_focus(focus_cycle_target->frame, FALSE);
379           frame_adjust_focus(focus_cycle_target->frame, TRUE);
380         */
381         int x, y, w, h;
382         int wt, wl, wr, wb;
383
384         wt = wl = wr = wb = MAX(3,
385                                 ob_rr_theme->handle_height +
386                                 ob_rr_theme->bwidth * 2);
387
388         x = focus_cycle_target->frame->area.x;
389         y = focus_cycle_target->frame->area.y;
390         w = focus_cycle_target->frame->area.width;
391         h = wt;
392
393         XMoveResizeWindow(ob_display, focus_indicator.top.win,
394                           x, y, w, h);
395         a_focus_indicator->texture[0].data.lineart.x1 = 0;
396         a_focus_indicator->texture[0].data.lineart.y1 = h-1;
397         a_focus_indicator->texture[0].data.lineart.x2 = 0;
398         a_focus_indicator->texture[0].data.lineart.y2 = 0;
399         a_focus_indicator->texture[1].data.lineart.x1 = 0;
400         a_focus_indicator->texture[1].data.lineart.y1 = 0;
401         a_focus_indicator->texture[1].data.lineart.x2 = w-1;
402         a_focus_indicator->texture[1].data.lineart.y2 = 0;
403         a_focus_indicator->texture[2].data.lineart.x1 = w-1;
404         a_focus_indicator->texture[2].data.lineart.y1 = 0;
405         a_focus_indicator->texture[2].data.lineart.x2 = w-1;
406         a_focus_indicator->texture[2].data.lineart.y2 = h-1;
407         a_focus_indicator->texture[3].data.lineart.x1 = (wl-1);
408         a_focus_indicator->texture[3].data.lineart.y1 = h-1;
409         a_focus_indicator->texture[3].data.lineart.x2 = w - wr;
410         a_focus_indicator->texture[3].data.lineart.y2 = h-1;
411         RrPaint(a_focus_indicator, focus_indicator.top.win,
412                 w, h);
413
414         x = focus_cycle_target->frame->area.x;
415         y = focus_cycle_target->frame->area.y;
416         w = wl;
417         h = focus_cycle_target->frame->area.height;
418
419         XMoveResizeWindow(ob_display, focus_indicator.left.win,
420                           x, y, w, h);
421         a_focus_indicator->texture[0].data.lineart.x1 = w-1;
422         a_focus_indicator->texture[0].data.lineart.y1 = 0;
423         a_focus_indicator->texture[0].data.lineart.x2 = 0;
424         a_focus_indicator->texture[0].data.lineart.y2 = 0;
425         a_focus_indicator->texture[1].data.lineart.x1 = 0;
426         a_focus_indicator->texture[1].data.lineart.y1 = 0;
427         a_focus_indicator->texture[1].data.lineart.x2 = 0;
428         a_focus_indicator->texture[1].data.lineart.y2 = h-1;
429         a_focus_indicator->texture[2].data.lineart.x1 = 0;
430         a_focus_indicator->texture[2].data.lineart.y1 = h-1;
431         a_focus_indicator->texture[2].data.lineart.x2 = w-1;
432         a_focus_indicator->texture[2].data.lineart.y2 = h-1;
433         a_focus_indicator->texture[3].data.lineart.x1 = w-1;
434         a_focus_indicator->texture[3].data.lineart.y1 = wt-1;
435         a_focus_indicator->texture[3].data.lineart.x2 = w-1;
436         a_focus_indicator->texture[3].data.lineart.y2 = h - wb;
437         RrPaint(a_focus_indicator, focus_indicator.left.win,
438                 w, h);
439
440         x = focus_cycle_target->frame->area.x +
441             focus_cycle_target->frame->area.width - wr;
442         y = focus_cycle_target->frame->area.y;
443         w = wr;
444         h = focus_cycle_target->frame->area.height ;
445
446         XMoveResizeWindow(ob_display, focus_indicator.right.win,
447                           x, y, w, h);
448         a_focus_indicator->texture[0].data.lineart.x1 = 0;
449         a_focus_indicator->texture[0].data.lineart.y1 = 0;
450         a_focus_indicator->texture[0].data.lineart.x2 = w-1;
451         a_focus_indicator->texture[0].data.lineart.y2 = 0;
452         a_focus_indicator->texture[1].data.lineart.x1 = w-1;
453         a_focus_indicator->texture[1].data.lineart.y1 = 0;
454         a_focus_indicator->texture[1].data.lineart.x2 = w-1;
455         a_focus_indicator->texture[1].data.lineart.y2 = h-1;
456         a_focus_indicator->texture[2].data.lineart.x1 = w-1;
457         a_focus_indicator->texture[2].data.lineart.y1 = h-1;
458         a_focus_indicator->texture[2].data.lineart.x2 = 0;
459         a_focus_indicator->texture[2].data.lineart.y2 = h-1;
460         a_focus_indicator->texture[3].data.lineart.x1 = 0;
461         a_focus_indicator->texture[3].data.lineart.y1 = wt-1;
462         a_focus_indicator->texture[3].data.lineart.x2 = 0;
463         a_focus_indicator->texture[3].data.lineart.y2 = h - wb;
464         RrPaint(a_focus_indicator, focus_indicator.right.win,
465                 w, h);
466
467         x = focus_cycle_target->frame->area.x;
468         y = focus_cycle_target->frame->area.y +
469             focus_cycle_target->frame->area.height - wb;
470         w = focus_cycle_target->frame->area.width;
471         h = wb;
472
473         XMoveResizeWindow(ob_display, focus_indicator.bottom.win,
474                           x, y, w, h);
475         a_focus_indicator->texture[0].data.lineart.x1 = 0;
476         a_focus_indicator->texture[0].data.lineart.y1 = 0;
477         a_focus_indicator->texture[0].data.lineart.x2 = 0;
478         a_focus_indicator->texture[0].data.lineart.y2 = h-1;
479         a_focus_indicator->texture[1].data.lineart.x1 = 0;
480         a_focus_indicator->texture[1].data.lineart.y1 = h-1;
481         a_focus_indicator->texture[1].data.lineart.x2 = w-1;
482         a_focus_indicator->texture[1].data.lineart.y2 = h-1;
483         a_focus_indicator->texture[2].data.lineart.x1 = w-1;
484         a_focus_indicator->texture[2].data.lineart.y1 = h-1;
485         a_focus_indicator->texture[2].data.lineart.x2 = w-1;
486         a_focus_indicator->texture[2].data.lineart.y2 = 0;
487         a_focus_indicator->texture[3].data.lineart.x1 = wl-1;
488         a_focus_indicator->texture[3].data.lineart.y1 = 0;
489         a_focus_indicator->texture[3].data.lineart.x2 = w - wr;
490         a_focus_indicator->texture[3].data.lineart.y2 = 0;
491         RrPaint(a_focus_indicator, focus_indicator.bottom.win,
492                 w, h);
493
494         XMapWindow(ob_display, focus_indicator.top.win);
495         XMapWindow(ob_display, focus_indicator.left.win);
496         XMapWindow(ob_display, focus_indicator.right.win);
497         XMapWindow(ob_display, focus_indicator.bottom.win);
498     }
499 }
500
501 static gboolean valid_focus_target(ObClient *ft)
502 {
503     /* we don't use client_can_focus here, because that doesn't let you
504        focus an iconic window, but we want to be able to, so we just check
505        if the focus flags on the window allow it, and its on the current
506        desktop */
507     return ((ft->type == OB_CLIENT_TYPE_NORMAL ||
508              ft->type == OB_CLIENT_TYPE_DIALOG ||
509              (!client_has_group_siblings(ft) &&
510               (ft->type == OB_CLIENT_TYPE_TOOLBAR ||
511                ft->type == OB_CLIENT_TYPE_MENU ||
512                ft->type == OB_CLIENT_TYPE_UTILITY))) &&
513             !ft->transients &&
514             ((ft->can_focus || ft->focus_notify) &&
515              !ft->skip_taskbar &&
516              (ft->desktop == screen_desktop || ft->desktop == DESKTOP_ALL)));
517 }
518
519 void focus_cycle(gboolean forward, gboolean linear,
520                  gboolean dialog, gboolean done, gboolean cancel)
521 {
522     static ObClient *first = NULL;
523     static ObClient *t = NULL;
524     static GList *order = NULL;
525     GList *it, *start, *list;
526     ObClient *ft = NULL;
527
528     if (cancel) {
529         focus_cycle_target = NULL;
530         goto done_cycle;
531     } else if (done)
532         goto done_cycle;
533
534     if (!focus_order[screen_desktop])
535         goto done_cycle;
536
537     if (!first) first = focus_client;
538     if (!focus_cycle_target) focus_cycle_target = focus_client;
539
540     if (linear) list = client_list;
541     else        list = focus_order[screen_desktop];
542
543     start = it = g_list_find(list, focus_cycle_target);
544     if (!start) /* switched desktops or something? */
545         start = it = forward ? g_list_last(list) : g_list_first(list);
546     if (!start) goto done_cycle;
547
548     do {
549         if (forward) {
550             it = it->next;
551             if (it == NULL) it = g_list_first(list);
552         } else {
553             it = it->prev;
554             if (it == NULL) it = g_list_last(list);
555         }
556         ft = it->data;
557         if (valid_focus_target(ft)) {
558             if (ft != focus_cycle_target) { /* prevents flicker */
559                 focus_cycle_target = ft;
560                 focus_cycle_draw_indicator();
561             }
562             popup_cycle(ft, dialog);
563             return;
564         }
565     } while (it != start);
566
567 done_cycle:
568     if (done && focus_cycle_target)
569         client_activate(focus_cycle_target, FALSE);
570
571     t = NULL;
572     first = NULL;
573     focus_cycle_target = NULL;
574     g_list_free(order);
575     order = NULL;
576
577     focus_cycle_draw_indicator();
578     popup_cycle(ft, FALSE);
579
580     return;
581 }
582
583 void focus_directional_cycle(ObDirection dir,
584                              gboolean dialog, gboolean done, gboolean cancel)
585 {
586     static ObClient *first = NULL;
587     ObClient *ft = NULL;
588
589     if (cancel) {
590         focus_cycle_target = NULL;
591         goto done_cycle;
592     } else if (done)
593         goto done_cycle;
594
595     if (!focus_order[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 }