1 /* -*- indent-tabs-mode: nil; tab-width: 4; c-basic-offset: 4; -*-
2 
3    dock.c for the Openbox window manager
4    Copyright (c) 2006        Mikael Magnusson
5    Copyright (c) 2003-2007   Dana Jansens
6 
7    This program is free software; you can redistribute it and/or modify
8    it under the terms of the GNU General Public License as published by
9    the Free Software Foundation; either version 2 of the License, or
10    (at your option) any later version.
11 
12    This program is distributed in the hope that it will be useful,
13    but WITHOUT ANY WARRANTY; without even the implied warranty of
14    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15    GNU General Public License for more details.
16 
17    See the COPYING file for a copy of the GNU General Public License.
18 */
19 
20 #include "debug.h"
21 #include "dock.h"
22 #include "screen.h"
23 #include "config.h"
24 #include "grab.h"
25 #include "openbox.h"
26 #include "obrender/theme.h"
27 #include "obt/prop.h"
28 
29 #define DOCK_EVENT_MASK (ButtonPressMask | ButtonReleaseMask | \
30                          EnterWindowMask | LeaveWindowMask)
31 #define DOCKAPP_EVENT_MASK (StructureNotifyMask)
32 #define DOCK_NOPROPAGATEMASK (ButtonPressMask | ButtonReleaseMask | \
33                               ButtonMotionMask)
34 
35 static ObDock *dock;
36 static guint show_timeout_id;
37 static guint hide_timeout_id;
38 
39 StrutPartial dock_strut;
40 
dock_app_grab_button(ObDockApp * app,gboolean grab)41 static void dock_app_grab_button(ObDockApp *app, gboolean grab)
42 {
43     if (grab) {
44         grab_button_full(config_dock_app_move_button,
45                          config_dock_app_move_modifiers, app->icon_win,
46                          ButtonPressMask | ButtonReleaseMask |
47                          ButtonMotionMask,
48                          GrabModeAsync, OB_CURSOR_MOVE);
49     } else {
50         ungrab_button(config_dock_app_move_button,
51                       config_dock_app_move_modifiers, app->icon_win);
52     }
53 }
54 
window_hash(Window * w)55 static guint window_hash(Window *w) { return *w; }
window_comp(Window * w1,Window * w2)56 static gboolean window_comp(Window *w1, Window *w2) { return *w1 == *w2; }
57 
dock_startup(gboolean reconfig)58 void dock_startup(gboolean reconfig)
59 {
60     XSetWindowAttributes attrib;
61 
62     if (reconfig) {
63         GList *it;
64 
65         XSetWindowBorder(obt_display, dock->frame,
66                          RrColorPixel(ob_rr_theme->osd_border_color));
67         XSetWindowBorderWidth(obt_display, dock->frame, ob_rr_theme->obwidth);
68 
69         RrAppearanceFree(dock->a_frame);
70         dock->a_frame = RrAppearanceCopy(ob_rr_theme->osd_bg);
71 
72         stacking_add(DOCK_AS_WINDOW(dock));
73 
74         dock_configure();
75         dock_hide(TRUE);
76 
77         for (it = dock->dock_apps; it; it = g_list_next(it))
78             dock_app_grab_button(it->data, TRUE);
79         return;
80     }
81 
82     STRUT_PARTIAL_SET(dock_strut, 0, 0, 0, 0,
83                       0, 0, 0, 0, 0, 0, 0, 0);
84 
85     dock = g_slice_new0(ObDock);
86     dock->obwin.type = OB_WINDOW_CLASS_DOCK;
87 
88     dock->hidden = TRUE;
89 
90     dock->dock_map = g_hash_table_new((GHashFunc)window_hash,
91                                       (GEqualFunc)window_comp);
92 
93     attrib.event_mask = DOCK_EVENT_MASK;
94     attrib.override_redirect = True;
95     attrib.do_not_propagate_mask = DOCK_NOPROPAGATEMASK;
96     dock->frame = XCreateWindow(obt_display, obt_root(ob_screen),
97                                 0, 0, 1, 1, 0,
98                                 RrDepth(ob_rr_inst), InputOutput,
99                                 RrVisual(ob_rr_inst),
100                                 CWOverrideRedirect | CWEventMask |
101                                 CWDontPropagate,
102                                 &attrib);
103     dock->a_frame = RrAppearanceCopy(ob_rr_theme->osd_bg);
104     XSetWindowBorder(obt_display, dock->frame,
105                      RrColorPixel(ob_rr_theme->osd_border_color));
106     XSetWindowBorderWidth(obt_display, dock->frame, ob_rr_theme->obwidth);
107 
108     /* Setting the window type so xcompmgr can tell what it is */
109     OBT_PROP_SET32(dock->frame, NET_WM_WINDOW_TYPE, ATOM,
110                    OBT_PROP_ATOM(NET_WM_WINDOW_TYPE_DOCK));
111 
112     window_add(&dock->frame, DOCK_AS_WINDOW(dock));
113     stacking_add(DOCK_AS_WINDOW(dock));
114 }
115 
dock_shutdown(gboolean reconfig)116 void dock_shutdown(gboolean reconfig)
117 {
118     if (reconfig) {
119         GList *it;
120 
121         stacking_remove(DOCK_AS_WINDOW(dock));
122 
123         for (it = dock->dock_apps; it; it = g_list_next(it))
124             dock_app_grab_button(it->data, FALSE);
125         return;
126     }
127 
128     g_hash_table_destroy(dock->dock_map);
129 
130     XDestroyWindow(obt_display, dock->frame);
131     RrAppearanceFree(dock->a_frame);
132     window_remove(dock->frame);
133     stacking_remove(dock);
134     g_slice_free(ObDock, dock);
135     dock = NULL;
136 }
137 
dock_manage(Window icon_win,Window name_win)138 void dock_manage(Window icon_win, Window name_win)
139 {
140     ObDockApp *app;
141     XWindowAttributes attrib;
142     gchar **data;
143 
144     app = g_slice_new0(ObDockApp);
145     app->name_win = name_win;
146     app->icon_win = icon_win;
147 
148     if (OBT_PROP_GETSS_TYPE(app->name_win, WM_CLASS, STRING_NO_CC, &data)) {
149         if (data[0]) {
150             app->name = g_strdup(data[0]);
151             if (data[1])
152                 app->class = g_strdup(data[1]);
153         }
154         g_strfreev(data);
155     }
156 
157     if (app->name == NULL) app->name = g_strdup("");
158     if (app->class == NULL) app->class = g_strdup("");
159 
160     if (XGetWindowAttributes(obt_display, app->icon_win, &attrib)) {
161         app->w = attrib.width;
162         app->h = attrib.height;
163     } else {
164         app->w = app->h = 64;
165     }
166 
167     dock->dock_apps = g_list_append(dock->dock_apps, app);
168     g_hash_table_insert(dock->dock_map, &app->icon_win, app);
169     dock_configure();
170 
171     XReparentWindow(obt_display, app->icon_win, dock->frame, app->x, app->y);
172     /*
173       This is the same case as in frame.c for client windows. When Openbox is
174       starting, the window is already mapped so we see unmap events occur for
175       it. There are 2 unmap events generated that we see, one with the 'event'
176       member set the root window, and one set to the client, but both get
177       handled and need to be ignored.
178     */
179     if (ob_state() == OB_STATE_STARTING)
180         app->ignore_unmaps += 2;
181     XChangeSaveSet(obt_display, app->icon_win, SetModeInsert);
182     XMapWindow(obt_display, app->icon_win);
183 
184     if (app->name_win != app->icon_win) {
185         XReparentWindow(obt_display, app->name_win, dock->frame, -1000, -1000);
186         XChangeSaveSet(obt_display, app->name_win, SetModeInsert);
187         XMapWindow(obt_display, app->name_win);
188     }
189 
190     XSync(obt_display, False);
191 
192     XSelectInput(obt_display, app->icon_win, DOCKAPP_EVENT_MASK);
193 
194     dock_app_grab_button(app, TRUE);
195 
196     ob_debug("Managed Dock App: 0x%lx 0x%lx (%s)",
197              app->icon_win, app->name_win, app->class);
198 
199     grab_server(FALSE);
200 }
201 
dock_unmanage_all(void)202 void dock_unmanage_all(void)
203 {
204     while (dock->dock_apps)
205         dock_unmanage(dock->dock_apps->data, TRUE);
206 }
207 
dock_unmanage(ObDockApp * app,gboolean reparent)208 void dock_unmanage(ObDockApp *app, gboolean reparent)
209 {
210     dock_app_grab_button(app, FALSE);
211     XSelectInput(obt_display, app->icon_win, NoEventMask);
212     /* remove the window from our save set */
213     XChangeSaveSet(obt_display, app->icon_win, SetModeDelete);
214     XSync(obt_display, False);
215 
216     if (reparent) {
217         XReparentWindow(obt_display, app->icon_win, obt_root(ob_screen), 0, 0);
218         if (app->name_win != app->icon_win)
219             XReparentWindow(obt_display, app->name_win,
220                             obt_root(ob_screen), 0, 0);
221     }
222 
223     dock->dock_apps = g_list_remove(dock->dock_apps, app);
224     g_hash_table_remove(dock->dock_map, &app->icon_win);
225     dock_configure();
226 
227     ob_debug("Unmanaged Dock App: 0x%lx (%s)", app->icon_win, app->class);
228 
229     g_free(app->name);
230     g_free(app->class);
231     g_slice_free(ObDockApp, app);
232 }
233 
dock_configure(void)234 void dock_configure(void)
235 {
236     GList *it;
237     gint hspot, vspot;
238     gint gravity;
239     gint l, r, t, b;
240     gint strw, strh;
241     const Rect *a;
242     gint hidesize;
243 
244     RrMargins(dock->a_frame, &l, &t, &r, &b);
245     hidesize = MAX(1, ob_rr_theme->obwidth);
246 
247     dock->area.width = dock->area.height = 0;
248 
249     /* get the size */
250     for (it = dock->dock_apps; it; it = g_list_next(it)) {
251         ObDockApp *app = it->data;
252         switch (config_dock_orient) {
253         case OB_ORIENTATION_HORZ:
254             dock->area.width += app->w;
255             dock->area.height = MAX(dock->area.height, app->h);
256             break;
257         case OB_ORIENTATION_VERT:
258             dock->area.width = MAX(dock->area.width, app->w);
259             dock->area.height += app->h;
260             break;
261         }
262     }
263 
264     if (dock->dock_apps) {
265         dock->area.width += l + r;
266         dock->area.height += t + b;
267     }
268 
269     hspot = l;
270     vspot = t;
271 
272     /* position the apps */
273     for (it = dock->dock_apps; it; it = g_list_next(it)) {
274         ObDockApp *app = it->data;
275         switch (config_dock_orient) {
276         case OB_ORIENTATION_HORZ:
277             app->x = hspot;
278             app->y = (dock->area.height - app->h) / 2;
279             hspot += app->w;
280             break;
281         case OB_ORIENTATION_VERT:
282             app->x = (dock->area.width - app->w) / 2;
283             app->y = vspot;
284             vspot += app->h;
285             break;
286         }
287 
288         XMoveWindow(obt_display, app->icon_win, app->x, app->y);
289     }
290 
291     /* used for calculating offsets */
292     dock->area.width += ob_rr_theme->obwidth * 2;
293     dock->area.height += ob_rr_theme->obwidth * 2;
294 
295     a = screen_physical_area_all_monitors();
296 
297     /* calculate position */
298     if (config_dock_floating) {
299         dock->area.x = config_dock_x;
300         dock->area.y = config_dock_y;
301         gravity = NorthWestGravity;
302     } else {
303         switch (config_dock_pos) {
304         case OB_DIRECTION_NORTHWEST:
305             dock->area.x = 0;
306             dock->area.y = 0;
307             gravity = NorthWestGravity;
308             break;
309         case OB_DIRECTION_NORTH:
310             dock->area.x = a->width / 2;
311             dock->area.y = 0;
312             gravity = NorthGravity;
313             break;
314         case OB_DIRECTION_NORTHEAST:
315             dock->area.x = a->width;
316             dock->area.y = 0;
317             gravity = NorthEastGravity;
318             break;
319         case OB_DIRECTION_WEST:
320             dock->area.x = 0;
321             dock->area.y = a->height / 2;
322             gravity = WestGravity;
323             break;
324         case OB_DIRECTION_EAST:
325             dock->area.x = a->width;
326             dock->area.y = a->height / 2;
327             gravity = EastGravity;
328             break;
329         case OB_DIRECTION_SOUTHWEST:
330             dock->area.x = 0;
331             dock->area.y = a->height;
332             gravity = SouthWestGravity;
333             break;
334         case OB_DIRECTION_SOUTH:
335             dock->area.x = a->width / 2;
336             dock->area.y = a->height;
337             gravity = SouthGravity;
338             break;
339         case OB_DIRECTION_SOUTHEAST:
340             dock->area.x = a->width;
341             dock->area.y = a->height;
342             gravity = SouthEastGravity;
343             break;
344         default:
345             g_assert_not_reached();
346         }
347     }
348 
349     switch(gravity) {
350     case NorthGravity:
351     case CenterGravity:
352     case SouthGravity:
353         dock->area.x -= dock->area.width / 2;
354         break;
355     case NorthEastGravity:
356     case EastGravity:
357     case SouthEastGravity:
358         dock->area.x -= dock->area.width;
359         break;
360     }
361     switch(gravity) {
362     case WestGravity:
363     case CenterGravity:
364     case EastGravity:
365         dock->area.y -= dock->area.height / 2;
366         break;
367     case SouthWestGravity:
368     case SouthGravity:
369     case SouthEastGravity:
370         dock->area.y -= dock->area.height;
371         break;
372     }
373 
374     if (config_dock_hide && dock->hidden) {
375         if (!config_dock_floating) {
376             switch (config_dock_pos) {
377             case OB_DIRECTION_NORTHWEST:
378                 switch (config_dock_orient) {
379                 case OB_ORIENTATION_HORZ:
380                     dock->area.y -= dock->area.height - hidesize;
381                     break;
382                 case OB_ORIENTATION_VERT:
383                     dock->area.x -= dock->area.width - hidesize;
384                     break;
385                 }
386                 break;
387             case OB_DIRECTION_NORTH:
388                 dock->area.y -= dock->area.height - hidesize;
389                 break;
390             case OB_DIRECTION_NORTHEAST:
391                 switch (config_dock_orient) {
392                 case OB_ORIENTATION_HORZ:
393                     dock->area.y -= dock->area.height - hidesize;
394                     break;
395                 case OB_ORIENTATION_VERT:
396                     dock->area.x += dock->area.width - hidesize;
397                     break;
398                 }
399                 break;
400             case OB_DIRECTION_WEST:
401                 dock->area.x -= dock->area.width - hidesize;
402                 break;
403             case OB_DIRECTION_EAST:
404                 dock->area.x += dock->area.width - hidesize;
405                 break;
406             case OB_DIRECTION_SOUTHWEST:
407                 switch (config_dock_orient) {
408                 case OB_ORIENTATION_HORZ:
409                     dock->area.y += dock->area.height - hidesize;
410                     break;
411                 case OB_ORIENTATION_VERT:
412                     dock->area.x -= dock->area.width - hidesize;
413                     break;
414                 } break;
415             case OB_DIRECTION_SOUTH:
416                 dock->area.y += dock->area.height - hidesize;
417                 break;
418             case OB_DIRECTION_SOUTHEAST:
419                 switch (config_dock_orient) {
420                 case OB_ORIENTATION_HORZ:
421                     dock->area.y += dock->area.height - hidesize;
422                     break;
423                 case OB_ORIENTATION_VERT:
424                     dock->area.x += dock->area.width - hidesize;
425                     break;
426                 }
427                 break;
428             }
429         }
430     }
431 
432     if (!config_dock_floating && config_dock_hide) {
433         strw = hidesize;
434         strh = hidesize;
435     } else {
436         strw = dock->area.width;
437         strh = dock->area.height;
438     }
439 
440     /* set the strut */
441     if (!dock->dock_apps) {
442         STRUT_PARTIAL_SET(dock_strut, 0, 0, 0, 0,
443                           0, 0, 0, 0, 0, 0, 0, 0);
444     }
445     else if (config_dock_floating || config_dock_nostrut) {
446         STRUT_PARTIAL_SET(dock_strut, 0, 0, 0, 0,
447                           0, 0, 0, 0, 0, 0, 0, 0);
448     }
449     else {
450         switch (config_dock_pos) {
451         case OB_DIRECTION_NORTHWEST:
452             switch (config_dock_orient) {
453             case OB_ORIENTATION_HORZ:
454                 STRUT_PARTIAL_SET(dock_strut, 0, strh, 0, 0,
455                                   0, 0, dock->area.x, dock->area.x
456                                   + dock->area.width - 1, 0, 0, 0, 0);
457                 break;
458             case OB_ORIENTATION_VERT:
459                 STRUT_PARTIAL_SET(dock_strut, strw, 0, 0, 0,
460                                   dock->area.y, dock->area.y
461                                   + dock->area.height - 1, 0, 0, 0, 0, 0, 0);
462                 break;
463             }
464             break;
465         case OB_DIRECTION_NORTH:
466             STRUT_PARTIAL_SET(dock_strut, 0, strh, 0, 0,
467                               0, 0, dock->area.x, dock->area.x
468                               + dock->area.width - 1, 0, 0, 0, 0);
469             break;
470         case OB_DIRECTION_NORTHEAST:
471             switch (config_dock_orient) {
472             case OB_ORIENTATION_HORZ:
473                 STRUT_PARTIAL_SET(dock_strut, 0, strh, 0, 0,
474                                   0, 0, dock->area.x, dock->area.x
475                                   + dock->area.width -1, 0, 0, 0, 0);
476                 break;
477             case OB_ORIENTATION_VERT:
478                 STRUT_PARTIAL_SET(dock_strut, 0, 0, strw, 0,
479                                   0, 0, 0, 0, dock->area.y, dock->area.y
480                                   + dock->area.height - 1, 0, 0);
481                 break;
482             }
483             break;
484         case OB_DIRECTION_WEST:
485             STRUT_PARTIAL_SET(dock_strut, strw, 0, 0, 0,
486                               dock->area.y, dock->area.y
487                               + dock->area.height - 1, 0, 0, 0, 0, 0, 0);
488             break;
489         case OB_DIRECTION_EAST:
490             STRUT_PARTIAL_SET(dock_strut, 0, 0, strw, 0,
491                               0, 0, 0, 0, dock->area.y, dock->area.y
492                               + dock->area.height - 1, 0, 0);
493             break;
494         case OB_DIRECTION_SOUTHWEST:
495             switch (config_dock_orient) {
496             case OB_ORIENTATION_HORZ:
497                 STRUT_PARTIAL_SET(dock_strut, 0, 0, 0, strh,
498                                   0, 0, 0, 0, 0, 0, dock->area.x, dock->area.x
499                                   + dock->area.width - 1);
500                 break;
501             case OB_ORIENTATION_VERT:
502                 STRUT_PARTIAL_SET(dock_strut, strw, 0, 0, 0,
503                                   dock->area.y, dock->area.y
504                                   + dock->area.height - 1, 0, 0, 0, 0, 0, 0);
505                 break;
506             }
507             break;
508         case OB_DIRECTION_SOUTH:
509             STRUT_PARTIAL_SET(dock_strut, 0, 0, 0, strh,
510                               0, 0, 0, 0, 0, 0, dock->area.x, dock->area.x
511                               + dock->area.width - 1);
512             break;
513         case OB_DIRECTION_SOUTHEAST:
514             switch (config_dock_orient) {
515             case OB_ORIENTATION_HORZ:
516                 STRUT_PARTIAL_SET(dock_strut, 0, 0, 0, strh,
517                                   0, 0, 0, 0, 0, 0, dock->area.x,
518                                   dock->area.x + dock->area.width - 1);
519                 break;
520             case OB_ORIENTATION_VERT:
521                 STRUT_PARTIAL_SET(dock_strut, 0, 0, strw, 0,
522                                   0, 0, 0, 0, dock->area.y, dock->area.y
523                                   + dock->area.height - 1, 0, 0);
524                 break;
525             }
526             break;
527         }
528     }
529 
530     /* not used for actually sizing shit */
531     dock->area.width -= ob_rr_theme->obwidth * 2;
532     dock->area.height -= ob_rr_theme->obwidth * 2;
533 
534     if (dock->dock_apps) {
535         g_assert(dock->area.width > 0);
536         g_assert(dock->area.height > 0);
537 
538         XMoveResizeWindow(obt_display, dock->frame, dock->area.x, dock->area.y,
539                           dock->area.width, dock->area.height);
540 
541         RrPaint(dock->a_frame, dock->frame, dock->area.width,
542                 dock->area.height);
543         XMapWindow(obt_display, dock->frame);
544     } else
545         XUnmapWindow(obt_display, dock->frame);
546 
547     /* but they are useful outside of this function! but don't add it if the
548        dock is actually not visible */
549     if (dock->dock_apps) {
550         dock->area.width += ob_rr_theme->obwidth * 2;
551         dock->area.height += ob_rr_theme->obwidth * 2;
552     }
553 
554     /* screen_resize() depends on this function to call screen_update_areas(),
555        so if this changes, also update screen_resize(). */
556     screen_update_areas();
557 }
558 
dock_app_configure(ObDockApp * app,gint w,gint h)559 void dock_app_configure(ObDockApp *app, gint w, gint h)
560 {
561     app->w = w;
562     app->h = h;
563     dock_configure();
564 }
565 
dock_app_drag(ObDockApp * app,XMotionEvent * e)566 void dock_app_drag(ObDockApp *app, XMotionEvent *e)
567 {
568     ObDockApp *over = NULL;
569     GList *it;
570     gint x, y;
571     gboolean after;
572     gboolean stop;
573 
574     x = e->x_root;
575     y = e->y_root;
576 
577     /* are we on top of the dock? */
578     if (!(x >= dock->area.x &&
579           y >= dock->area.y &&
580           x < dock->area.x + dock->area.width &&
581           y < dock->area.y + dock->area.height))
582         return;
583 
584     x -= dock->area.x;
585     y -= dock->area.y;
586 
587     /* which dock app are we on top of? */
588     stop = FALSE;
589     for (it = dock->dock_apps; it; it = g_list_next(it)) {
590         over = it->data;
591         switch (config_dock_orient) {
592         case OB_ORIENTATION_HORZ:
593             if (x >= over->x && x < over->x + over->w)
594                 stop = TRUE;
595             break;
596         case OB_ORIENTATION_VERT:
597             if (y >= over->y && y < over->y + over->h)
598                 stop = TRUE;
599             break;
600         }
601         /* dont go to it->next! */
602         if (stop) break;
603     }
604     if (!it || app == over) return;
605 
606     x -= over->x;
607     y -= over->y;
608 
609     switch (config_dock_orient) {
610     case OB_ORIENTATION_HORZ:
611         after = (x > over->w / 2);
612         break;
613     case OB_ORIENTATION_VERT:
614         after = (y > over->h / 2);
615         break;
616     default:
617         g_assert_not_reached();
618     }
619 
620     /* remove before doing the it->next! */
621     dock->dock_apps = g_list_remove(dock->dock_apps, app);
622 
623     if (after) it = it->next;
624 
625     dock->dock_apps = g_list_insert_before(dock->dock_apps, it, app);
626     dock_configure();
627 }
628 
hide_timeout(gpointer data)629 static gboolean hide_timeout(gpointer data)
630 {
631     /* hide */
632     dock->hidden = TRUE;
633     dock_configure();
634 
635     return FALSE; /* don't repeat */
636 }
637 
show_timeout(gpointer data)638 static gboolean show_timeout(gpointer data)
639 {
640     /* show */
641     dock->hidden = FALSE;
642     dock_configure();
643 
644     return FALSE; /* don't repeat */
645 }
646 
destroy_timeout(gpointer data)647 static void destroy_timeout(gpointer data)
648 {
649     gint *id = data;
650     *id = 0;
651 }
652 
dock_hide(gboolean hide)653 void dock_hide(gboolean hide)
654 {
655     if (!hide) {
656         if (dock->hidden && config_dock_hide) {
657             show_timeout_id = g_timeout_add_full(G_PRIORITY_DEFAULT,
658                                                  config_dock_show_delay,
659                                                  show_timeout, &show_timeout_id, destroy_timeout);
660         } else if (!dock->hidden && config_dock_hide && hide_timeout_id) {
661             if (hide_timeout_id) g_source_remove(hide_timeout_id);
662         }
663     } else {
664         if (!dock->hidden && config_dock_hide) {
665             hide_timeout_id = g_timeout_add_full(G_PRIORITY_DEFAULT,
666                                                  config_dock_hide_delay,
667                                                  hide_timeout, &hide_timeout_id, destroy_timeout);
668         } else if (dock->hidden && config_dock_hide && show_timeout_id) {
669             if (show_timeout_id) g_source_remove(show_timeout_id);
670         }
671     }
672 }
673 
dock_get_area(Rect * a)674 void dock_get_area(Rect *a)
675 {
676     RECT_SET(*a, dock->area.x, dock->area.y,
677              dock->area.width, dock->area.height);
678 }
679 
dock_raise_dock(void)680 void dock_raise_dock(void)
681 {
682     stacking_raise(DOCK_AS_WINDOW(dock));
683 }
684 
dock_lower_dock(void)685 void dock_lower_dock(void)
686 {
687     stacking_lower(DOCK_AS_WINDOW(dock));
688 }
689 
dock_find_dockapp(Window xwin)690 ObDockApp* dock_find_dockapp(Window xwin)
691 {
692     return g_hash_table_lookup(dock->dock_map, &xwin);
693 }
694