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