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