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