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