]> icculus.org git repositories - mikachu/openbox.git/blob - openbox/focus.c
use g_[s]list_next/previous consistantly, and check for "it" instead of "it != NULL...
[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, 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 = g_slist_next(it)) {
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;
270                          it = g_list_next(it))
271                     {
272                         GSList *sit;
273
274                         for (sit = old->group->members; sit;
275                              sit = g_slist_next(sit))
276                         {
277                             if (sit->data == it->data)
278                                 if ((target =
279                                      focus_fallback_transient(sit->data, old)))
280                                     return target;
281                         }
282                     }
283                 } else {
284                     if ((target =
285                          focus_fallback_transient(old->transient_for, old)))
286                         return target;
287                 }
288             }
289         }
290     }
291
292     if (config_focus_follow) {
293         if ((target = client_under_pointer()))
294             if (client_normal(target) && client_can_focus(target))
295                 return target;
296     }
297
298 #if 0
299         /* try for group relations */
300         if (old->group) {
301             GSList *sit;
302
303             for (it = focus_order[screen_desktop]; it; it = g_list_next(it))
304                 for (sit = old->group->members; sit; sit = g_slist_next(sit))
305                     if (sit->data == it->data)
306                         if (sit->data != old && client_normal(sit->data))
307                             if (client_can_focus(sit->data))
308                                 return sit->data;
309         }
310 #endif
311
312     for (it = focus_order[screen_desktop]; it; it = g_list_next(it))
313         if (type != OB_FOCUS_FALLBACK_UNFOCUSING || it->data != old)
314             if (client_normal(it->data) && client_can_focus(it->data))
315                 return it->data;
316
317     return NULL;
318 }
319
320 void focus_fallback(ObFocusFallbackType type)
321 {
322     ObClient *new;
323
324     /* unfocus any focused clients.. they can be focused by Pointer events
325        and such, and then when I try focus them, I won't get a FocusIn event
326        at all for them.
327     */
328     focus_set_client(NULL);
329
330     if ((new = focus_fallback_target(type)))
331         client_focus(new);
332 }
333
334 static void popup_cycle(ObClient *c, gboolean show)
335 {
336     if (!show) {
337         icon_popup_hide(focus_cycle_popup);
338     } else {
339         Rect *a;
340         ObClient *p = c;
341         gchar *title = NULL;
342
343         a = screen_physical_area_monitor(0);
344         icon_popup_position(focus_cycle_popup, CenterGravity,
345                             a->x + a->width / 2, a->y + a->height / 2);
346 /*        icon_popup_size(focus_cycle_popup, a->height/2, a->height/16);
347         icon_popup_show(focus_cycle_popup, c->title,
348                         client_icon(c, a->height/16, a->height/16));
349 */
350         /* XXX the size and the font extents need to be related on some level
351          */
352         icon_popup_size(focus_cycle_popup, POPUP_WIDTH, POPUP_HEIGHT);
353
354         /* use the transient's parent's title/icon */
355         while (p->transient_for && p->transient_for != OB_TRAN_GROUP)
356             p = p->transient_for;
357
358 /*
359         if (p != c)
360             title = g_strconcat((c->iconic ? c->icon_title : c->title),
361                                 " - ",
362                                 (p->iconic ? p->icon_title : p->title),
363                                 NULL);
364 */
365
366         icon_popup_show(focus_cycle_popup,
367                         (title ? title :
368                          (c->iconic ? c->icon_title : c->title)),
369                         client_icon(p, 48, 48));
370         g_free(title);
371     }
372 }
373
374 void focus_cycle_draw_indicator()
375 {
376     if (!focus_cycle_target) {
377         XUnmapWindow(ob_display, focus_indicator.top.win);
378         XUnmapWindow(ob_display, focus_indicator.left.win);
379         XUnmapWindow(ob_display, focus_indicator.right.win);
380         XUnmapWindow(ob_display, focus_indicator.bottom.win);
381     } else {
382         /*
383           if (focus_cycle_target)
384               frame_adjust_focus(focus_cycle_target->frame, FALSE);
385           frame_adjust_focus(focus_cycle_target->frame, TRUE);
386         */
387         gint x, y, w, h;
388         gint wt, wl, wr, wb;
389
390         wt = wl = wr = wb = MAX(3,
391                                 ob_rr_theme->handle_height +
392                                 ob_rr_theme->bwidth * 2);
393
394         x = focus_cycle_target->frame->area.x;
395         y = focus_cycle_target->frame->area.y;
396         w = focus_cycle_target->frame->area.width;
397         h = wt;
398
399         XMoveResizeWindow(ob_display, focus_indicator.top.win,
400                           x, y, w, h);
401         a_focus_indicator->texture[0].data.lineart.x1 = 0;
402         a_focus_indicator->texture[0].data.lineart.y1 = h-1;
403         a_focus_indicator->texture[0].data.lineart.x2 = 0;
404         a_focus_indicator->texture[0].data.lineart.y2 = 0;
405         a_focus_indicator->texture[1].data.lineart.x1 = 0;
406         a_focus_indicator->texture[1].data.lineart.y1 = 0;
407         a_focus_indicator->texture[1].data.lineart.x2 = w-1;
408         a_focus_indicator->texture[1].data.lineart.y2 = 0;
409         a_focus_indicator->texture[2].data.lineart.x1 = w-1;
410         a_focus_indicator->texture[2].data.lineart.y1 = 0;
411         a_focus_indicator->texture[2].data.lineart.x2 = w-1;
412         a_focus_indicator->texture[2].data.lineart.y2 = h-1;
413         a_focus_indicator->texture[3].data.lineart.x1 = (wl-1);
414         a_focus_indicator->texture[3].data.lineart.y1 = h-1;
415         a_focus_indicator->texture[3].data.lineart.x2 = w - wr;
416         a_focus_indicator->texture[3].data.lineart.y2 = h-1;
417         RrPaint(a_focus_indicator, focus_indicator.top.win,
418                 w, h);
419
420         x = focus_cycle_target->frame->area.x;
421         y = focus_cycle_target->frame->area.y;
422         w = wl;
423         h = focus_cycle_target->frame->area.height;
424
425         XMoveResizeWindow(ob_display, focus_indicator.left.win,
426                           x, y, w, h);
427         a_focus_indicator->texture[0].data.lineart.x1 = w-1;
428         a_focus_indicator->texture[0].data.lineart.y1 = 0;
429         a_focus_indicator->texture[0].data.lineart.x2 = 0;
430         a_focus_indicator->texture[0].data.lineart.y2 = 0;
431         a_focus_indicator->texture[1].data.lineart.x1 = 0;
432         a_focus_indicator->texture[1].data.lineart.y1 = 0;
433         a_focus_indicator->texture[1].data.lineart.x2 = 0;
434         a_focus_indicator->texture[1].data.lineart.y2 = h-1;
435         a_focus_indicator->texture[2].data.lineart.x1 = 0;
436         a_focus_indicator->texture[2].data.lineart.y1 = h-1;
437         a_focus_indicator->texture[2].data.lineart.x2 = w-1;
438         a_focus_indicator->texture[2].data.lineart.y2 = h-1;
439         a_focus_indicator->texture[3].data.lineart.x1 = w-1;
440         a_focus_indicator->texture[3].data.lineart.y1 = wt-1;
441         a_focus_indicator->texture[3].data.lineart.x2 = w-1;
442         a_focus_indicator->texture[3].data.lineart.y2 = h - wb;
443         RrPaint(a_focus_indicator, focus_indicator.left.win,
444                 w, h);
445
446         x = focus_cycle_target->frame->area.x +
447             focus_cycle_target->frame->area.width - wr;
448         y = focus_cycle_target->frame->area.y;
449         w = wr;
450         h = focus_cycle_target->frame->area.height ;
451
452         XMoveResizeWindow(ob_display, focus_indicator.right.win,
453                           x, y, w, h);
454         a_focus_indicator->texture[0].data.lineart.x1 = 0;
455         a_focus_indicator->texture[0].data.lineart.y1 = 0;
456         a_focus_indicator->texture[0].data.lineart.x2 = w-1;
457         a_focus_indicator->texture[0].data.lineart.y2 = 0;
458         a_focus_indicator->texture[1].data.lineart.x1 = w-1;
459         a_focus_indicator->texture[1].data.lineart.y1 = 0;
460         a_focus_indicator->texture[1].data.lineart.x2 = w-1;
461         a_focus_indicator->texture[1].data.lineart.y2 = h-1;
462         a_focus_indicator->texture[2].data.lineart.x1 = w-1;
463         a_focus_indicator->texture[2].data.lineart.y1 = h-1;
464         a_focus_indicator->texture[2].data.lineart.x2 = 0;
465         a_focus_indicator->texture[2].data.lineart.y2 = h-1;
466         a_focus_indicator->texture[3].data.lineart.x1 = 0;
467         a_focus_indicator->texture[3].data.lineart.y1 = wt-1;
468         a_focus_indicator->texture[3].data.lineart.x2 = 0;
469         a_focus_indicator->texture[3].data.lineart.y2 = h - wb;
470         RrPaint(a_focus_indicator, focus_indicator.right.win,
471                 w, h);
472
473         x = focus_cycle_target->frame->area.x;
474         y = focus_cycle_target->frame->area.y +
475             focus_cycle_target->frame->area.height - wb;
476         w = focus_cycle_target->frame->area.width;
477         h = wb;
478
479         XMoveResizeWindow(ob_display, focus_indicator.bottom.win,
480                           x, y, w, h);
481         a_focus_indicator->texture[0].data.lineart.x1 = 0;
482         a_focus_indicator->texture[0].data.lineart.y1 = 0;
483         a_focus_indicator->texture[0].data.lineart.x2 = 0;
484         a_focus_indicator->texture[0].data.lineart.y2 = h-1;
485         a_focus_indicator->texture[1].data.lineart.x1 = 0;
486         a_focus_indicator->texture[1].data.lineart.y1 = h-1;
487         a_focus_indicator->texture[1].data.lineart.x2 = w-1;
488         a_focus_indicator->texture[1].data.lineart.y2 = h-1;
489         a_focus_indicator->texture[2].data.lineart.x1 = w-1;
490         a_focus_indicator->texture[2].data.lineart.y1 = h-1;
491         a_focus_indicator->texture[2].data.lineart.x2 = w-1;
492         a_focus_indicator->texture[2].data.lineart.y2 = 0;
493         a_focus_indicator->texture[3].data.lineart.x1 = wl-1;
494         a_focus_indicator->texture[3].data.lineart.y1 = 0;
495         a_focus_indicator->texture[3].data.lineart.x2 = w - wr;
496         a_focus_indicator->texture[3].data.lineart.y2 = 0;
497         RrPaint(a_focus_indicator, focus_indicator.bottom.win,
498                 w, h);
499
500         XMapWindow(ob_display, focus_indicator.top.win);
501         XMapWindow(ob_display, focus_indicator.left.win);
502         XMapWindow(ob_display, focus_indicator.right.win);
503         XMapWindow(ob_display, focus_indicator.bottom.win);
504     }
505 }
506
507 static gboolean valid_focus_target(ObClient *ft)
508 {
509     /* we don't use client_can_focus here, because that doesn't let you
510        focus an iconic window, but we want to be able to, so we just check
511        if the focus flags on the window allow it, and its on the current
512        desktop */
513     if ((ft->type == OB_CLIENT_TYPE_NORMAL ||
514          ft->type == OB_CLIENT_TYPE_DIALOG ||
515          (!client_has_group_siblings(ft) &&
516           (ft->type == OB_CLIENT_TYPE_TOOLBAR ||
517            ft->type == OB_CLIENT_TYPE_MENU ||
518            ft->type == OB_CLIENT_TYPE_UTILITY))) &&
519         ((ft->can_focus || ft->focus_notify) &&
520          !ft->skip_taskbar &&
521          (ft->desktop == screen_desktop || ft->desktop == DESKTOP_ALL)) &&
522         ft == client_focus_target(ft))
523         return TRUE;
524 /*
525     {
526         GSList *it;
527
528         for (it = ft->transients; it; it = g_slist_next(it)) {
529             ObClient *c = it->data;
530
531             if (c->frame->visible)
532                 return FALSE;
533         }
534         return TRUE;
535     }
536 */
537
538     return FALSE;
539 }
540
541 void focus_cycle(gboolean forward, gboolean linear,
542                  gboolean dialog, gboolean done, gboolean cancel)
543 {
544     static ObClient *first = NULL;
545     static ObClient *t = NULL;
546     static GList *order = NULL;
547     GList *it, *start, *list;
548     ObClient *ft = NULL;
549
550     if (cancel) {
551         focus_cycle_target = NULL;
552         goto done_cycle;
553     } else if (done)
554         goto done_cycle;
555
556     if (!focus_order[screen_desktop])
557         goto done_cycle;
558
559     if (!first) first = focus_client;
560     if (!focus_cycle_target) focus_cycle_target = focus_client;
561
562     if (linear) list = client_list;
563     else        list = focus_order[screen_desktop];
564
565     start = it = g_list_find(list, focus_cycle_target);
566     if (!start) /* switched desktops or something? */
567         start = it = forward ? g_list_last(list) : g_list_first(list);
568     if (!start) goto done_cycle;
569
570     do {
571         if (forward) {
572             it = it->next;
573             if (it == NULL) it = g_list_first(list);
574         } else {
575             it = it->prev;
576             if (it == NULL) it = g_list_last(list);
577         }
578         ft = it->data;
579         if (valid_focus_target(ft)) {
580             if (ft != focus_cycle_target) { /* prevents flicker */
581                 focus_cycle_target = ft;
582                 focus_cycle_draw_indicator();
583             }
584             popup_cycle(ft, dialog);
585             return;
586         }
587     } while (it != start);
588
589 done_cycle:
590     if (done && focus_cycle_target)
591         client_activate(focus_cycle_target, FALSE);
592
593     t = NULL;
594     first = NULL;
595     focus_cycle_target = NULL;
596     g_list_free(order);
597     order = NULL;
598
599     focus_cycle_draw_indicator();
600     popup_cycle(ft, FALSE);
601
602     return;
603 }
604
605 void focus_directional_cycle(ObDirection dir,
606                              gboolean dialog, gboolean done, gboolean cancel)
607 {
608     static ObClient *first = NULL;
609     ObClient *ft = NULL;
610
611     if (cancel) {
612         focus_cycle_target = NULL;
613         goto done_cycle;
614     } else if (done)
615         goto done_cycle;
616
617     if (!focus_order[screen_desktop])
618         goto done_cycle;
619
620     if (!first) first = focus_client;
621     if (!focus_cycle_target) focus_cycle_target = focus_client;
622
623     if (focus_cycle_target)
624         ft = client_find_directional(focus_cycle_target, dir);
625     else {
626         GList *it;
627
628         for (it = focus_order[screen_desktop]; it; it = g_list_next(it))
629             if (valid_focus_target(it->data))
630                 ft = it->data;
631     }
632         
633     if (ft) {
634         if (ft != focus_cycle_target) {/* prevents flicker */
635             focus_cycle_target = ft;
636             focus_cycle_draw_indicator();
637         }
638     }
639     if (focus_cycle_target) {
640         popup_cycle(focus_cycle_target, dialog);
641         if (dialog)
642             return;
643     }
644
645
646 done_cycle:
647     if (done && focus_cycle_target)
648         client_activate(focus_cycle_target, FALSE);
649
650     first = NULL;
651     focus_cycle_target = NULL;
652
653     focus_cycle_draw_indicator();
654     popup_cycle(ft, FALSE);
655
656     return;
657 }
658
659 void focus_order_add_new(ObClient *c)
660 {
661     guint d, i;
662
663     if (c->iconic)
664         focus_order_to_top(c);
665     else {
666         d = c->desktop;
667         if (d == DESKTOP_ALL) {
668             for (i = 0; i < screen_num_desktops; ++i) {
669                 g_assert(!g_list_find(focus_order[i], c));
670                 if (focus_order[i] && ((ObClient*)focus_order[i]->data)->iconic)
671                     focus_order[i] = g_list_insert(focus_order[i], c, 0);
672                 else
673                     focus_order[i] = g_list_insert(focus_order[i], c, 1);
674             }
675         } else {
676             g_assert(!g_list_find(focus_order[d], c));
677             if (focus_order[d] && ((ObClient*)focus_order[d]->data)->iconic)
678                 focus_order[d] = g_list_insert(focus_order[d], c, 0);
679             else
680                 focus_order[d] = g_list_insert(focus_order[d], c, 1);
681         }
682     }
683 }
684
685 void focus_order_remove(ObClient *c)
686 {
687     guint d, i;
688
689     d = c->desktop;
690     if (d == DESKTOP_ALL) {
691         for (i = 0; i < screen_num_desktops; ++i)
692             focus_order[i] = g_list_remove(focus_order[i], c);
693     } else
694         focus_order[d] = g_list_remove(focus_order[d], c);
695 }
696
697 static void to_top(ObClient *c, guint d)
698 {
699     focus_order[d] = g_list_remove(focus_order[d], c);
700     if (!c->iconic) {
701         focus_order[d] = g_list_prepend(focus_order[d], c);
702     } else {
703         GList *it;
704
705         /* insert before first iconic window */
706         for (it = focus_order[d];
707              it && !((ObClient*)it->data)->iconic; it = g_list_next(it));
708         focus_order[d] = g_list_insert_before(focus_order[d], it, c);
709     }
710 }
711
712 void focus_order_to_top(ObClient *c)
713 {
714     guint d, i;
715
716     d = c->desktop;
717     if (d == DESKTOP_ALL) {
718         for (i = 0; i < screen_num_desktops; ++i)
719             to_top(c, i);
720     } else
721         to_top(c, d);
722 }
723
724 static void to_bottom(ObClient *c, guint d)
725 {
726     focus_order[d] = g_list_remove(focus_order[d], c);
727     if (c->iconic) {
728         focus_order[d] = g_list_append(focus_order[d], c);
729     } else {
730         GList *it;
731
732         /* insert before first iconic window */
733         for (it = focus_order[d];
734              it && !((ObClient*)it->data)->iconic; it = g_list_next(it));
735         g_list_insert_before(focus_order[d], it, c);
736     }
737 }
738
739 void focus_order_to_bottom(ObClient *c)
740 {
741     guint d, i;
742
743     d = c->desktop;
744     if (d == DESKTOP_ALL) {
745         for (i = 0; i < screen_num_desktops; ++i)
746             to_bottom(c, i);
747     } else
748         to_bottom(c, d);
749 }