]> icculus.org git repositories - dana/openbox.git/blob - openbox/focus.c
show an indicator similar to metacity's for focus cycling windows
[dana/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 static gboolean valid_focus_target(ObClient *ft)
366 {
367     /* we don't use client_can_focus here, because that doesn't let you
368        focus an iconic window, but we want to be able to, so we just check
369        if the focus flags on the window allow it, and its on the current
370        desktop */
371     return (!ft->transients && client_normal(ft) &&
372             ((ft->can_focus || ft->focus_notify) &&
373              !ft->skip_taskbar &&
374              (ft->desktop == screen_desktop || ft->desktop == DESKTOP_ALL)));
375 }
376
377 void focus_cycle(gboolean forward, gboolean linear,
378                  gboolean dialog, gboolean done, gboolean cancel)
379 {
380     static ObClient *first = NULL;
381     static ObClient *t = NULL;
382     static GList *order = NULL;
383     GList *it, *start, *list;
384     ObClient *ft = NULL;
385
386     if (cancel) {
387         /*
388         if (focus_cycle_target)
389             frame_adjust_focus(focus_cycle_target->frame, FALSE);
390         if (focus_client)
391             frame_adjust_focus(focus_client->frame, TRUE);
392         */
393         focus_cycle_target = NULL;
394         goto done_cycle;
395     } else if (done && dialog) {
396         goto done_cycle;
397     }
398
399     if (!focus_order[screen_desktop])
400         goto done_cycle;
401
402     if (!first) first = focus_client;
403     if (!focus_cycle_target) focus_cycle_target = focus_client;
404
405     if (linear) list = client_list;
406     else        list = focus_order[screen_desktop];
407
408     start = it = g_list_find(list, focus_cycle_target);
409     if (!start) /* switched desktops or something? */
410         start = it = forward ? g_list_last(list) : g_list_first(list);
411     if (!start) goto done_cycle;
412
413     do {
414         if (forward) {
415             it = it->next;
416             if (it == NULL) it = g_list_first(list);
417         } else {
418             it = it->prev;
419             if (it == NULL) it = g_list_last(list);
420         }
421         ft = it->data;
422         if (valid_focus_target(ft)) {
423             if (ft != focus_cycle_target) { /* prevents flicker */
424                 /*
425                 if (focus_cycle_target)
426                     frame_adjust_focus(focus_cycle_target->frame, FALSE);
427                 */
428                 focus_cycle_target = ft;
429                 /*
430                 frame_adjust_focus(focus_cycle_target->frame, TRUE);
431                 */
432                 {
433                     int x, y, w, h;
434                     int wt, wl, wr, wb;
435
436                     wt = wl = wr = wb = MAX(5, ob_rr_theme->handle_height);
437
438                     x = focus_cycle_target->frame->area.x;
439                     y = focus_cycle_target->frame->area.y;
440                     w = focus_cycle_target->frame->area.width;
441                     h = wt;
442
443                     XMoveResizeWindow(ob_display, focus_indicator.top.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 = h-1;
447                     a_focus_indicator->texture[0].data.lineart.x2 = 0;
448                     a_focus_indicator->texture[0].data.lineart.y2 = 0;
449                     a_focus_indicator->texture[1].data.lineart.x1 = 0;
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 = 0;
453                     a_focus_indicator->texture[2].data.lineart.x1 = w-1;
454                     a_focus_indicator->texture[2].data.lineart.y1 = 0;
455                     a_focus_indicator->texture[2].data.lineart.x2 = w-1;
456                     a_focus_indicator->texture[2].data.lineart.y2 = h-1;
457                     a_focus_indicator->texture[3].data.lineart.x1 = (wl-1);
458                     a_focus_indicator->texture[3].data.lineart.y1 = h-1;
459                     a_focus_indicator->texture[3].data.lineart.x2 = w - wr;
460                     a_focus_indicator->texture[3].data.lineart.y2 = h-1;
461                     RrPaint(a_focus_indicator, focus_indicator.top.win,
462                             w, h);
463
464                     x = focus_cycle_target->frame->area.x;
465                     y = focus_cycle_target->frame->area.y;
466                     w = wl;
467                     h = focus_cycle_target->frame->area.height;
468
469                     XMoveResizeWindow(ob_display, focus_indicator.left.win,
470                                       x, y, w, h);
471                     a_focus_indicator->texture[0].data.lineart.x1 = w-1;
472                     a_focus_indicator->texture[0].data.lineart.y1 = 0;
473                     a_focus_indicator->texture[0].data.lineart.x2 = 0;
474                     a_focus_indicator->texture[0].data.lineart.y2 = 0;
475                     a_focus_indicator->texture[1].data.lineart.x1 = 0;
476                     a_focus_indicator->texture[1].data.lineart.y1 = 0;
477                     a_focus_indicator->texture[1].data.lineart.x2 = 0;
478                     a_focus_indicator->texture[1].data.lineart.y2 = h-1;
479                     a_focus_indicator->texture[2].data.lineart.x1 = 0;
480                     a_focus_indicator->texture[2].data.lineart.y1 = h-1;
481                     a_focus_indicator->texture[2].data.lineart.x2 = w-1;
482                     a_focus_indicator->texture[2].data.lineart.y2 = h-1;
483                     a_focus_indicator->texture[3].data.lineart.x1 = w-1;
484                     a_focus_indicator->texture[3].data.lineart.y1 = wt-1;
485                     a_focus_indicator->texture[3].data.lineart.x2 = w-1;
486                     a_focus_indicator->texture[3].data.lineart.y2 = h - wb;
487                     RrPaint(a_focus_indicator, focus_indicator.left.win,
488                             w, h);
489
490                     x = focus_cycle_target->frame->area.x +
491                         focus_cycle_target->frame->area.width - wr;
492                     y = focus_cycle_target->frame->area.y;
493                     w = wr;
494                     h = focus_cycle_target->frame->area.height ;
495
496                     XMoveResizeWindow(ob_display, focus_indicator.right.win,
497                                       x, y, w, h);
498                     a_focus_indicator->texture[0].data.lineart.x1 = 0;
499                     a_focus_indicator->texture[0].data.lineart.y1 = 0;
500                     a_focus_indicator->texture[0].data.lineart.x2 = w-1;
501                     a_focus_indicator->texture[0].data.lineart.y2 = 0;
502                     a_focus_indicator->texture[1].data.lineart.x1 = w-1;
503                     a_focus_indicator->texture[1].data.lineart.y1 = 0;
504                     a_focus_indicator->texture[1].data.lineart.x2 = w-1;
505                     a_focus_indicator->texture[1].data.lineart.y2 = h-1;
506                     a_focus_indicator->texture[2].data.lineart.x1 = w-1;
507                     a_focus_indicator->texture[2].data.lineart.y1 = h-1;
508                     a_focus_indicator->texture[2].data.lineart.x2 = 0;
509                     a_focus_indicator->texture[2].data.lineart.y2 = h-1;
510                     a_focus_indicator->texture[3].data.lineart.x1 = 0;
511                     a_focus_indicator->texture[3].data.lineart.y1 = wt-1;
512                     a_focus_indicator->texture[3].data.lineart.x2 = 0;
513                     a_focus_indicator->texture[3].data.lineart.y2 = h - wb;
514                     RrPaint(a_focus_indicator, focus_indicator.right.win,
515                             w, h);
516
517                     x = focus_cycle_target->frame->area.x;
518                     y = focus_cycle_target->frame->area.y +
519                         focus_cycle_target->frame->area.height - wb;
520                     w = focus_cycle_target->frame->area.width;
521                     h = wb;
522
523                     XMoveResizeWindow(ob_display, focus_indicator.bottom.win,
524                                       x, y, w, h);
525                     a_focus_indicator->texture[0].data.lineart.x1 = 0;
526                     a_focus_indicator->texture[0].data.lineart.y1 = 0;
527                     a_focus_indicator->texture[0].data.lineart.x2 = 0;
528                     a_focus_indicator->texture[0].data.lineart.y2 = h-1;
529                     a_focus_indicator->texture[1].data.lineart.x1 = 0;
530                     a_focus_indicator->texture[1].data.lineart.y1 = h-1;
531                     a_focus_indicator->texture[1].data.lineart.x2 = w-1;
532                     a_focus_indicator->texture[1].data.lineart.y2 = h-1;
533                     a_focus_indicator->texture[2].data.lineart.x1 = w-1;
534                     a_focus_indicator->texture[2].data.lineart.y1 = h-1;
535                     a_focus_indicator->texture[2].data.lineart.x2 = w-1;
536                     a_focus_indicator->texture[2].data.lineart.y2 = 0;
537                     a_focus_indicator->texture[3].data.lineart.x1 = wl-1;
538                     a_focus_indicator->texture[3].data.lineart.y1 = 0;
539                     a_focus_indicator->texture[3].data.lineart.x2 = w - wr;
540                     a_focus_indicator->texture[3].data.lineart.y2 = 0;
541                     RrPaint(a_focus_indicator, focus_indicator.bottom.win,
542                             w, h);
543                 }
544             }
545             popup_cycle(ft, dialog);
546             XMapWindow(ob_display, focus_indicator.top.win);
547             XMapWindow(ob_display, focus_indicator.left.win);
548             XMapWindow(ob_display, focus_indicator.right.win);
549             XMapWindow(ob_display, focus_indicator.bottom.win);
550             return;
551         }
552     } while (it != start);
553
554 done_cycle:
555     if (done && focus_cycle_target)
556         client_activate(focus_cycle_target, FALSE);
557
558     XUnmapWindow(ob_display, focus_indicator.top.win);
559     XUnmapWindow(ob_display, focus_indicator.left.win);
560     XUnmapWindow(ob_display, focus_indicator.right.win);
561     XUnmapWindow(ob_display, focus_indicator.bottom.win);
562
563     t = NULL;
564     first = NULL;
565     focus_cycle_target = NULL;
566     g_list_free(order);
567     order = NULL;
568
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 }