]> icculus.org git repositories - dana/openbox.git/blob - openbox/focus.c
change the min width of the indicator to 3 and use the actual height of the handle
[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 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(3,
382                                 ob_rr_theme->handle_height +
383                                 ob_rr_theme->bwidth * 2);
384
385         x = focus_cycle_target->frame->area.x;
386         y = focus_cycle_target->frame->area.y;
387         w = focus_cycle_target->frame->area.width;
388         h = wt;
389
390         XMoveResizeWindow(ob_display, focus_indicator.top.win,
391                           x, y, w, h);
392         a_focus_indicator->texture[0].data.lineart.x1 = 0;
393         a_focus_indicator->texture[0].data.lineart.y1 = h-1;
394         a_focus_indicator->texture[0].data.lineart.x2 = 0;
395         a_focus_indicator->texture[0].data.lineart.y2 = 0;
396         a_focus_indicator->texture[1].data.lineart.x1 = 0;
397         a_focus_indicator->texture[1].data.lineart.y1 = 0;
398         a_focus_indicator->texture[1].data.lineart.x2 = w-1;
399         a_focus_indicator->texture[1].data.lineart.y2 = 0;
400         a_focus_indicator->texture[2].data.lineart.x1 = w-1;
401         a_focus_indicator->texture[2].data.lineart.y1 = 0;
402         a_focus_indicator->texture[2].data.lineart.x2 = w-1;
403         a_focus_indicator->texture[2].data.lineart.y2 = h-1;
404         a_focus_indicator->texture[3].data.lineart.x1 = (wl-1);
405         a_focus_indicator->texture[3].data.lineart.y1 = h-1;
406         a_focus_indicator->texture[3].data.lineart.x2 = w - wr;
407         a_focus_indicator->texture[3].data.lineart.y2 = h-1;
408         RrPaint(a_focus_indicator, focus_indicator.top.win,
409                 w, h);
410
411         x = focus_cycle_target->frame->area.x;
412         y = focus_cycle_target->frame->area.y;
413         w = wl;
414         h = focus_cycle_target->frame->area.height;
415
416         XMoveResizeWindow(ob_display, focus_indicator.left.win,
417                           x, y, w, h);
418         a_focus_indicator->texture[0].data.lineart.x1 = w-1;
419         a_focus_indicator->texture[0].data.lineart.y1 = 0;
420         a_focus_indicator->texture[0].data.lineart.x2 = 0;
421         a_focus_indicator->texture[0].data.lineart.y2 = 0;
422         a_focus_indicator->texture[1].data.lineart.x1 = 0;
423         a_focus_indicator->texture[1].data.lineart.y1 = 0;
424         a_focus_indicator->texture[1].data.lineart.x2 = 0;
425         a_focus_indicator->texture[1].data.lineart.y2 = h-1;
426         a_focus_indicator->texture[2].data.lineart.x1 = 0;
427         a_focus_indicator->texture[2].data.lineart.y1 = h-1;
428         a_focus_indicator->texture[2].data.lineart.x2 = w-1;
429         a_focus_indicator->texture[2].data.lineart.y2 = h-1;
430         a_focus_indicator->texture[3].data.lineart.x1 = w-1;
431         a_focus_indicator->texture[3].data.lineart.y1 = wt-1;
432         a_focus_indicator->texture[3].data.lineart.x2 = w-1;
433         a_focus_indicator->texture[3].data.lineart.y2 = h - wb;
434         RrPaint(a_focus_indicator, focus_indicator.left.win,
435                 w, h);
436
437         x = focus_cycle_target->frame->area.x +
438             focus_cycle_target->frame->area.width - wr;
439         y = focus_cycle_target->frame->area.y;
440         w = wr;
441         h = focus_cycle_target->frame->area.height ;
442
443         XMoveResizeWindow(ob_display, focus_indicator.right.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 = 0;
447         a_focus_indicator->texture[0].data.lineart.x2 = w-1;
448         a_focus_indicator->texture[0].data.lineart.y2 = 0;
449         a_focus_indicator->texture[1].data.lineart.x1 = w-1;
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 = h-1;
453         a_focus_indicator->texture[2].data.lineart.x1 = w-1;
454         a_focus_indicator->texture[2].data.lineart.y1 = h-1;
455         a_focus_indicator->texture[2].data.lineart.x2 = 0;
456         a_focus_indicator->texture[2].data.lineart.y2 = h-1;
457         a_focus_indicator->texture[3].data.lineart.x1 = 0;
458         a_focus_indicator->texture[3].data.lineart.y1 = wt-1;
459         a_focus_indicator->texture[3].data.lineart.x2 = 0;
460         a_focus_indicator->texture[3].data.lineart.y2 = h - wb;
461         RrPaint(a_focus_indicator, focus_indicator.right.win,
462                 w, h);
463
464         x = focus_cycle_target->frame->area.x;
465         y = focus_cycle_target->frame->area.y +
466             focus_cycle_target->frame->area.height - wb;
467         w = focus_cycle_target->frame->area.width;
468         h = wb;
469
470         XMoveResizeWindow(ob_display, focus_indicator.bottom.win,
471                           x, y, w, h);
472         a_focus_indicator->texture[0].data.lineart.x1 = 0;
473         a_focus_indicator->texture[0].data.lineart.y1 = 0;
474         a_focus_indicator->texture[0].data.lineart.x2 = 0;
475         a_focus_indicator->texture[0].data.lineart.y2 = h-1;
476         a_focus_indicator->texture[1].data.lineart.x1 = 0;
477         a_focus_indicator->texture[1].data.lineart.y1 = h-1;
478         a_focus_indicator->texture[1].data.lineart.x2 = w-1;
479         a_focus_indicator->texture[1].data.lineart.y2 = h-1;
480         a_focus_indicator->texture[2].data.lineart.x1 = w-1;
481         a_focus_indicator->texture[2].data.lineart.y1 = h-1;
482         a_focus_indicator->texture[2].data.lineart.x2 = w-1;
483         a_focus_indicator->texture[2].data.lineart.y2 = 0;
484         a_focus_indicator->texture[3].data.lineart.x1 = wl-1;
485         a_focus_indicator->texture[3].data.lineart.y1 = 0;
486         a_focus_indicator->texture[3].data.lineart.x2 = w - wr;
487         a_focus_indicator->texture[3].data.lineart.y2 = 0;
488         RrPaint(a_focus_indicator, focus_indicator.bottom.win,
489                 w, h);
490
491         XMapWindow(ob_display, focus_indicator.top.win);
492         XMapWindow(ob_display, focus_indicator.left.win);
493         XMapWindow(ob_display, focus_indicator.right.win);
494         XMapWindow(ob_display, focus_indicator.bottom.win);
495     }
496 }
497
498 static gboolean valid_focus_target(ObClient *ft)
499 {
500     /* we don't use client_can_focus here, because that doesn't let you
501        focus an iconic window, but we want to be able to, so we just check
502        if the focus flags on the window allow it, and its on the current
503        desktop */
504     return ((ft->type == OB_CLIENT_TYPE_NORMAL ||
505              ft->type == OB_CLIENT_TYPE_DIALOG ||
506              (!client_has_group_siblings(ft) &&
507               (ft->type == OB_CLIENT_TYPE_TOOLBAR ||
508                ft->type == OB_CLIENT_TYPE_MENU ||
509                ft->type == OB_CLIENT_TYPE_UTILITY))) &&
510             !ft->transients &&
511             ((ft->can_focus || ft->focus_notify) &&
512              !ft->skip_taskbar &&
513              (ft->desktop == screen_desktop || ft->desktop == DESKTOP_ALL)));
514 }
515
516 void focus_cycle(gboolean forward, gboolean linear,
517                  gboolean dialog, gboolean done, gboolean cancel)
518 {
519     static ObClient *first = NULL;
520     static ObClient *t = NULL;
521     static GList *order = NULL;
522     GList *it, *start, *list;
523     ObClient *ft = NULL;
524
525     if (cancel) {
526         /*
527         if (focus_cycle_target)
528             frame_adjust_focus(focus_cycle_target->frame, FALSE);
529         if (focus_client)
530             frame_adjust_focus(focus_client->frame, TRUE);
531         */
532         focus_cycle_target = NULL;
533         goto done_cycle;
534     } else if (done && dialog) {
535         goto done_cycle;
536     }
537
538     if (!focus_order[screen_desktop])
539         goto done_cycle;
540
541     if (!first) first = focus_client;
542     if (!focus_cycle_target) focus_cycle_target = focus_client;
543
544     if (linear) list = client_list;
545     else        list = focus_order[screen_desktop];
546
547     start = it = g_list_find(list, focus_cycle_target);
548     if (!start) /* switched desktops or something? */
549         start = it = forward ? g_list_last(list) : g_list_first(list);
550     if (!start) goto done_cycle;
551
552     do {
553         if (forward) {
554             it = it->next;
555             if (it == NULL) it = g_list_first(list);
556         } else {
557             it = it->prev;
558             if (it == NULL) it = g_list_last(list);
559         }
560         ft = it->data;
561         if (valid_focus_target(ft)) {
562             if (ft != focus_cycle_target) { /* prevents flicker */
563                 focus_cycle_target = ft;
564                 focus_cycle_draw_indicator();
565             }
566             popup_cycle(ft, dialog);
567             return;
568         }
569     } while (it != start);
570
571 done_cycle:
572     if (done && focus_cycle_target)
573         client_activate(focus_cycle_target, FALSE);
574
575     t = NULL;
576     first = NULL;
577     focus_cycle_target = NULL;
578     g_list_free(order);
579     order = NULL;
580
581     focus_cycle_draw_indicator();
582     popup_cycle(ft, FALSE);
583
584     return;
585 }
586
587 void focus_directional_cycle(ObDirection dir,
588                              gboolean dialog, gboolean done, gboolean cancel)
589 {
590     static ObClient *first = NULL;
591     ObClient *ft = NULL;
592
593     if (cancel) {
594         if (focus_cycle_target)
595             frame_adjust_focus(focus_cycle_target->frame, FALSE);
596         if (focus_client)
597             frame_adjust_focus(focus_client->frame, TRUE);
598         focus_cycle_target = NULL;
599         goto done_cycle;
600     } else if (done && dialog) {
601         goto done_cycle;
602     }
603
604     if (!focus_order[screen_desktop])
605         goto done_cycle;
606
607     if (!first) first = focus_client;
608     if (!focus_cycle_target) focus_cycle_target = focus_client;
609
610     if (focus_cycle_target)
611         ft = client_find_directional(focus_cycle_target, dir);
612     else {
613         GList *it;
614
615         for (it = focus_order[screen_desktop]; it; it = g_list_next(it))
616             if (valid_focus_target(it->data))
617                 ft = it->data;
618     }
619         
620     if (ft) {
621         if (ft != focus_cycle_target) {/* prevents flicker */
622             if (focus_cycle_target)
623                 frame_adjust_focus(focus_cycle_target->frame, FALSE);
624             focus_cycle_target = ft;
625             frame_adjust_focus(focus_cycle_target->frame, TRUE);
626         }
627     }
628     if (focus_cycle_target) {
629         popup_cycle(focus_cycle_target, dialog);
630         if (dialog)
631             return;
632     }
633
634
635 done_cycle:
636     if (done && focus_cycle_target)
637         client_activate(focus_cycle_target, FALSE);
638
639     first = NULL;
640     focus_cycle_target = NULL;
641
642     popup_cycle(ft, FALSE);
643
644     return;
645 }
646
647 void focus_order_add_new(ObClient *c)
648 {
649     guint d, i;
650
651     if (c->iconic)
652         focus_order_to_top(c);
653     else {
654         d = c->desktop;
655         if (d == DESKTOP_ALL) {
656             for (i = 0; i < screen_num_desktops; ++i) {
657                 if (focus_order[i] && ((ObClient*)focus_order[i]->data)->iconic)
658                     focus_order[i] = g_list_insert(focus_order[i], c, 0);
659                 else
660                     focus_order[i] = g_list_insert(focus_order[i], c, 1);
661             }
662         } else
663              if (focus_order[d] && ((ObClient*)focus_order[d]->data)->iconic)
664                 focus_order[d] = g_list_insert(focus_order[d], c, 0);
665             else
666                 focus_order[d] = g_list_insert(focus_order[d], c, 1);
667     }
668 }
669
670 void focus_order_remove(ObClient *c)
671 {
672     guint d, i;
673
674     d = c->desktop;
675     if (d == DESKTOP_ALL) {
676         for (i = 0; i < screen_num_desktops; ++i)
677             focus_order[i] = g_list_remove(focus_order[i], c);
678     } else
679         focus_order[d] = g_list_remove(focus_order[d], c);
680 }
681
682 static void to_top(ObClient *c, guint d)
683 {
684     focus_order[d] = g_list_remove(focus_order[d], c);
685     if (!c->iconic) {
686         focus_order[d] = g_list_prepend(focus_order[d], c);
687     } else {
688         GList *it;
689
690         /* insert before first iconic window */
691         for (it = focus_order[d];
692              it && !((ObClient*)it->data)->iconic; it = it->next);
693         focus_order[d] = g_list_insert_before(focus_order[d], it, c);
694     }
695 }
696
697 void focus_order_to_top(ObClient *c)
698 {
699     guint d, i;
700
701     d = c->desktop;
702     if (d == DESKTOP_ALL) {
703         for (i = 0; i < screen_num_desktops; ++i)
704             to_top(c, i);
705     } else
706         to_top(c, d);
707 }
708
709 static void to_bottom(ObClient *c, guint d)
710 {
711     focus_order[d] = g_list_remove(focus_order[d], c);
712     if (c->iconic) {
713         focus_order[d] = g_list_append(focus_order[d], c);
714     } else {
715         GList *it;
716
717         /* insert before first iconic window */
718         for (it = focus_order[d];
719              it && !((ObClient*)it->data)->iconic; it = it->next);
720         g_list_insert_before(focus_order[d], it, c);
721     }
722 }
723
724 void focus_order_to_bottom(ObClient *c)
725 {
726     guint d, i;
727
728     d = c->desktop;
729     if (d == DESKTOP_ALL) {
730         for (i = 0; i < screen_num_desktops; ++i)
731             to_bottom(c, i);
732     } else
733         to_bottom(c, d);
734 }