]> icculus.org git repositories - mikachu/openbox.git/blob - openbox/focus.c
supply focus_cycle_draw_indicator which draws/moves/resizes the focus cycling indicator
[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(5, ob_rr_theme->handle_height);
382
383         x = focus_cycle_target->frame->area.x;
384         y = focus_cycle_target->frame->area.y;
385         w = focus_cycle_target->frame->area.width;
386         h = wt;
387
388         XMoveResizeWindow(ob_display, focus_indicator.top.win,
389                           x, y, w, h);
390         a_focus_indicator->texture[0].data.lineart.x1 = 0;
391         a_focus_indicator->texture[0].data.lineart.y1 = h-1;
392         a_focus_indicator->texture[0].data.lineart.x2 = 0;
393         a_focus_indicator->texture[0].data.lineart.y2 = 0;
394         a_focus_indicator->texture[1].data.lineart.x1 = 0;
395         a_focus_indicator->texture[1].data.lineart.y1 = 0;
396         a_focus_indicator->texture[1].data.lineart.x2 = w-1;
397         a_focus_indicator->texture[1].data.lineart.y2 = 0;
398         a_focus_indicator->texture[2].data.lineart.x1 = w-1;
399         a_focus_indicator->texture[2].data.lineart.y1 = 0;
400         a_focus_indicator->texture[2].data.lineart.x2 = w-1;
401         a_focus_indicator->texture[2].data.lineart.y2 = h-1;
402         a_focus_indicator->texture[3].data.lineart.x1 = (wl-1);
403         a_focus_indicator->texture[3].data.lineart.y1 = h-1;
404         a_focus_indicator->texture[3].data.lineart.x2 = w - wr;
405         a_focus_indicator->texture[3].data.lineart.y2 = h-1;
406         RrPaint(a_focus_indicator, focus_indicator.top.win,
407                 w, h);
408
409         x = focus_cycle_target->frame->area.x;
410         y = focus_cycle_target->frame->area.y;
411         w = wl;
412         h = focus_cycle_target->frame->area.height;
413
414         XMoveResizeWindow(ob_display, focus_indicator.left.win,
415                           x, y, w, h);
416         a_focus_indicator->texture[0].data.lineart.x1 = w-1;
417         a_focus_indicator->texture[0].data.lineart.y1 = 0;
418         a_focus_indicator->texture[0].data.lineart.x2 = 0;
419         a_focus_indicator->texture[0].data.lineart.y2 = 0;
420         a_focus_indicator->texture[1].data.lineart.x1 = 0;
421         a_focus_indicator->texture[1].data.lineart.y1 = 0;
422         a_focus_indicator->texture[1].data.lineart.x2 = 0;
423         a_focus_indicator->texture[1].data.lineart.y2 = h-1;
424         a_focus_indicator->texture[2].data.lineart.x1 = 0;
425         a_focus_indicator->texture[2].data.lineart.y1 = h-1;
426         a_focus_indicator->texture[2].data.lineart.x2 = w-1;
427         a_focus_indicator->texture[2].data.lineart.y2 = h-1;
428         a_focus_indicator->texture[3].data.lineart.x1 = w-1;
429         a_focus_indicator->texture[3].data.lineart.y1 = wt-1;
430         a_focus_indicator->texture[3].data.lineart.x2 = w-1;
431         a_focus_indicator->texture[3].data.lineart.y2 = h - wb;
432         RrPaint(a_focus_indicator, focus_indicator.left.win,
433                 w, h);
434
435         x = focus_cycle_target->frame->area.x +
436             focus_cycle_target->frame->area.width - wr;
437         y = focus_cycle_target->frame->area.y;
438         w = wr;
439         h = focus_cycle_target->frame->area.height ;
440
441         XMoveResizeWindow(ob_display, focus_indicator.right.win,
442                           x, y, w, h);
443         a_focus_indicator->texture[0].data.lineart.x1 = 0;
444         a_focus_indicator->texture[0].data.lineart.y1 = 0;
445         a_focus_indicator->texture[0].data.lineart.x2 = w-1;
446         a_focus_indicator->texture[0].data.lineart.y2 = 0;
447         a_focus_indicator->texture[1].data.lineart.x1 = w-1;
448         a_focus_indicator->texture[1].data.lineart.y1 = 0;
449         a_focus_indicator->texture[1].data.lineart.x2 = w-1;
450         a_focus_indicator->texture[1].data.lineart.y2 = h-1;
451         a_focus_indicator->texture[2].data.lineart.x1 = w-1;
452         a_focus_indicator->texture[2].data.lineart.y1 = h-1;
453         a_focus_indicator->texture[2].data.lineart.x2 = 0;
454         a_focus_indicator->texture[2].data.lineart.y2 = h-1;
455         a_focus_indicator->texture[3].data.lineart.x1 = 0;
456         a_focus_indicator->texture[3].data.lineart.y1 = wt-1;
457         a_focus_indicator->texture[3].data.lineart.x2 = 0;
458         a_focus_indicator->texture[3].data.lineart.y2 = h - wb;
459         RrPaint(a_focus_indicator, focus_indicator.right.win,
460                 w, h);
461
462         x = focus_cycle_target->frame->area.x;
463         y = focus_cycle_target->frame->area.y +
464             focus_cycle_target->frame->area.height - wb;
465         w = focus_cycle_target->frame->area.width;
466         h = wb;
467
468         XMoveResizeWindow(ob_display, focus_indicator.bottom.win,
469                           x, y, w, h);
470         a_focus_indicator->texture[0].data.lineart.x1 = 0;
471         a_focus_indicator->texture[0].data.lineart.y1 = 0;
472         a_focus_indicator->texture[0].data.lineart.x2 = 0;
473         a_focus_indicator->texture[0].data.lineart.y2 = h-1;
474         a_focus_indicator->texture[1].data.lineart.x1 = 0;
475         a_focus_indicator->texture[1].data.lineart.y1 = h-1;
476         a_focus_indicator->texture[1].data.lineart.x2 = w-1;
477         a_focus_indicator->texture[1].data.lineart.y2 = h-1;
478         a_focus_indicator->texture[2].data.lineart.x1 = w-1;
479         a_focus_indicator->texture[2].data.lineart.y1 = h-1;
480         a_focus_indicator->texture[2].data.lineart.x2 = w-1;
481         a_focus_indicator->texture[2].data.lineart.y2 = 0;
482         a_focus_indicator->texture[3].data.lineart.x1 = wl-1;
483         a_focus_indicator->texture[3].data.lineart.y1 = 0;
484         a_focus_indicator->texture[3].data.lineart.x2 = w - wr;
485         a_focus_indicator->texture[3].data.lineart.y2 = 0;
486         RrPaint(a_focus_indicator, focus_indicator.bottom.win,
487                 w, h);
488     }
489 }
490
491 static gboolean valid_focus_target(ObClient *ft)
492 {
493     /* we don't use client_can_focus here, because that doesn't let you
494        focus an iconic window, but we want to be able to, so we just check
495        if the focus flags on the window allow it, and its on the current
496        desktop */
497     return (!ft->transients && client_normal(ft) &&
498             ((ft->can_focus || ft->focus_notify) &&
499              !ft->skip_taskbar &&
500              (ft->desktop == screen_desktop || ft->desktop == DESKTOP_ALL)));
501 }
502
503 void focus_cycle(gboolean forward, gboolean linear,
504                  gboolean dialog, gboolean done, gboolean cancel)
505 {
506     static ObClient *first = NULL;
507     static ObClient *t = NULL;
508     static GList *order = NULL;
509     GList *it, *start, *list;
510     ObClient *ft = NULL;
511
512     if (cancel) {
513         /*
514         if (focus_cycle_target)
515             frame_adjust_focus(focus_cycle_target->frame, FALSE);
516         if (focus_client)
517             frame_adjust_focus(focus_client->frame, TRUE);
518         */
519         focus_cycle_target = NULL;
520         goto done_cycle;
521     } else if (done && dialog) {
522         goto done_cycle;
523     }
524
525     if (!focus_order[screen_desktop])
526         goto done_cycle;
527
528     if (!first) first = focus_client;
529     if (!focus_cycle_target) focus_cycle_target = focus_client;
530
531     if (linear) list = client_list;
532     else        list = focus_order[screen_desktop];
533
534     start = it = g_list_find(list, focus_cycle_target);
535     if (!start) /* switched desktops or something? */
536         start = it = forward ? g_list_last(list) : g_list_first(list);
537     if (!start) goto done_cycle;
538
539     do {
540         if (forward) {
541             it = it->next;
542             if (it == NULL) it = g_list_first(list);
543         } else {
544             it = it->prev;
545             if (it == NULL) it = g_list_last(list);
546         }
547         ft = it->data;
548         if (valid_focus_target(ft)) {
549             if (ft != focus_cycle_target) { /* prevents flicker */
550                 focus_cycle_target = ft;
551                 focus_cycle_draw_indicator();
552             }
553             popup_cycle(ft, dialog);
554             return;
555         }
556     } while (it != start);
557
558 done_cycle:
559     if (done && focus_cycle_target)
560         client_activate(focus_cycle_target, FALSE);
561
562     t = NULL;
563     first = NULL;
564     focus_cycle_target = NULL;
565     g_list_free(order);
566     order = NULL;
567
568     focus_cycle_draw_indicator();
569     popup_cycle(ft, FALSE);
570
571     return;
572 }
573
574 void focus_directional_cycle(ObDirection dir,
575                              gboolean dialog, gboolean done, gboolean cancel)
576 {
577     static ObClient *first = NULL;
578     ObClient *ft = NULL;
579
580     if (cancel) {
581         if (focus_cycle_target)
582             frame_adjust_focus(focus_cycle_target->frame, FALSE);
583         if (focus_client)
584             frame_adjust_focus(focus_client->frame, TRUE);
585         focus_cycle_target = NULL;
586         goto done_cycle;
587     } else if (done && dialog) {
588         goto done_cycle;
589     }
590
591     if (!focus_order[screen_desktop])
592         goto done_cycle;
593
594     if (!first) first = focus_client;
595     if (!focus_cycle_target) focus_cycle_target = focus_client;
596
597     if (focus_cycle_target)
598         ft = client_find_directional(focus_cycle_target, dir);
599     else {
600         GList *it;
601
602         for (it = focus_order[screen_desktop]; it; it = g_list_next(it))
603             if (valid_focus_target(it->data))
604                 ft = it->data;
605     }
606         
607     if (ft) {
608         if (ft != focus_cycle_target) {/* prevents flicker */
609             if (focus_cycle_target)
610                 frame_adjust_focus(focus_cycle_target->frame, FALSE);
611             focus_cycle_target = ft;
612             frame_adjust_focus(focus_cycle_target->frame, TRUE);
613         }
614     }
615     if (focus_cycle_target) {
616         popup_cycle(focus_cycle_target, dialog);
617         if (dialog)
618             return;
619     }
620
621
622 done_cycle:
623     if (done && focus_cycle_target)
624         client_activate(focus_cycle_target, FALSE);
625
626     first = NULL;
627     focus_cycle_target = NULL;
628
629     popup_cycle(ft, FALSE);
630
631     return;
632 }
633
634 void focus_order_add_new(ObClient *c)
635 {
636     guint d, i;
637
638     if (c->iconic)
639         focus_order_to_top(c);
640     else {
641         d = c->desktop;
642         if (d == DESKTOP_ALL) {
643             for (i = 0; i < screen_num_desktops; ++i) {
644                 if (focus_order[i] && ((ObClient*)focus_order[i]->data)->iconic)
645                     focus_order[i] = g_list_insert(focus_order[i], c, 0);
646                 else
647                     focus_order[i] = g_list_insert(focus_order[i], c, 1);
648             }
649         } else
650              if (focus_order[d] && ((ObClient*)focus_order[d]->data)->iconic)
651                 focus_order[d] = g_list_insert(focus_order[d], c, 0);
652             else
653                 focus_order[d] = g_list_insert(focus_order[d], c, 1);
654     }
655 }
656
657 void focus_order_remove(ObClient *c)
658 {
659     guint d, i;
660
661     d = c->desktop;
662     if (d == DESKTOP_ALL) {
663         for (i = 0; i < screen_num_desktops; ++i)
664             focus_order[i] = g_list_remove(focus_order[i], c);
665     } else
666         focus_order[d] = g_list_remove(focus_order[d], c);
667 }
668
669 static void to_top(ObClient *c, guint d)
670 {
671     focus_order[d] = g_list_remove(focus_order[d], c);
672     if (!c->iconic) {
673         focus_order[d] = g_list_prepend(focus_order[d], c);
674     } else {
675         GList *it;
676
677         /* insert before first iconic window */
678         for (it = focus_order[d];
679              it && !((ObClient*)it->data)->iconic; it = it->next);
680         focus_order[d] = g_list_insert_before(focus_order[d], it, c);
681     }
682 }
683
684 void focus_order_to_top(ObClient *c)
685 {
686     guint d, i;
687
688     d = c->desktop;
689     if (d == DESKTOP_ALL) {
690         for (i = 0; i < screen_num_desktops; ++i)
691             to_top(c, i);
692     } else
693         to_top(c, d);
694 }
695
696 static void to_bottom(ObClient *c, guint d)
697 {
698     focus_order[d] = g_list_remove(focus_order[d], c);
699     if (c->iconic) {
700         focus_order[d] = g_list_append(focus_order[d], c);
701     } else {
702         GList *it;
703
704         /* insert before first iconic window */
705         for (it = focus_order[d];
706              it && !((ObClient*)it->data)->iconic; it = it->next);
707         g_list_insert_before(focus_order[d], it, c);
708     }
709 }
710
711 void focus_order_to_bottom(ObClient *c)
712 {
713     guint d, i;
714
715     d = c->desktop;
716     if (d == DESKTOP_ALL) {
717         for (i = 0; i < screen_num_desktops; ++i)
718             to_bottom(c, i);
719     } else
720         to_bottom(c, d);
721 }