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