1 /* -*- indent-tabs-mode: nil; tab-width: 4; c-basic-offset: 4; -*-
3 dock.c for the Openbox window manager
4 Copyright (c) 2003 Ben Jansens
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.
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.
16 See the COPYING file for a copy of the GNU General Public License.
27 #include "render/theme.h"
29 #define DOCK_EVENT_MASK (ButtonPressMask | ButtonReleaseMask | \
30 EnterWindowMask | LeaveWindowMask)
31 #define DOCKAPP_EVENT_MASK (StructureNotifyMask)
35 StrutPartial dock_strut
;
37 void dock_startup(gboolean reconfig
)
39 XSetWindowAttributes attrib
;
42 stacking_add(DOCK_AS_WINDOW(dock
));
47 STRUT_PARTIAL_SET(dock_strut
, 0, 0, 0, 0,
48 0, 0, 0, 0, 0, 0, 0, 0);
50 dock
= g_new0(ObDock
, 1);
51 dock
->obwin
.type
= Window_Dock
;
55 attrib
.event_mask
= DOCK_EVENT_MASK
;
56 attrib
.override_redirect
= True
;
57 dock
->frame
= XCreateWindow(ob_display
, RootWindow(ob_display
, ob_screen
),
59 RrDepth(ob_rr_inst
), InputOutput
,
61 CWOverrideRedirect
| CWEventMask
,
63 dock
->a_frame
= RrAppearanceCopy(ob_rr_theme
->a_unfocused_title
);
64 XSetWindowBorder(ob_display
, dock
->frame
,
65 RrColorPixel(ob_rr_theme
->b_color
));
66 XSetWindowBorderWidth(ob_display
, dock
->frame
, ob_rr_theme
->bwidth
);
68 g_hash_table_insert(window_map
, &dock
->frame
, dock
);
69 stacking_add(DOCK_AS_WINDOW(dock
));
72 void dock_shutdown(gboolean reconfig
)
75 stacking_remove(DOCK_AS_WINDOW(dock
));
79 XDestroyWindow(ob_display
, dock
->frame
);
80 RrAppearanceFree(dock
->a_frame
);
81 g_hash_table_remove(window_map
, &dock
->frame
);
82 stacking_remove(dock
);
85 void dock_add(Window win
, XWMHints
*wmhints
)
88 XWindowAttributes attrib
;
91 app
= g_new0(ObDockApp
, 1);
92 app
->obwin
.type
= Window_DockApp
;
94 app
->icon_win
= (wmhints
->flags
& IconWindowHint
) ?
95 wmhints
->icon_window
: win
;
97 if (PROP_GETSS(app
->win
, wm_class
, locale
, &data
)) {
99 app
->name
= g_strdup(data
[0]);
101 app
->class = g_strdup(data
[1]);
106 if (app
->name
== NULL
) app
->name
= g_strdup("");
107 if (app
->class == NULL
) app
->class = g_strdup("");
109 if (XGetWindowAttributes(ob_display
, app
->icon_win
, &attrib
)) {
110 app
->w
= attrib
.width
;
111 app
->h
= attrib
.height
;
113 app
->w
= app
->h
= 64;
116 dock
->dock_apps
= g_list_append(dock
->dock_apps
, app
);
119 XReparentWindow(ob_display
, app
->icon_win
, dock
->frame
, app
->x
, app
->y
);
121 This is the same case as in frame.c for client windows. When Openbox is
122 starting, the window is already mapped so we see unmap events occur for
123 it. There are 2 unmap events generated that we see, one with the 'event'
124 member set the root window, and one set to the client, but both get
125 handled and need to be ignored.
127 if (ob_state() == OB_STATE_STARTING
)
128 app
->ignore_unmaps
+= 2;
130 if (app
->win
!= app
->icon_win
) {
131 /* have to map it so that it can be re-managed on a restart */
132 XMoveWindow(ob_display
, app
->win
, -1000, -1000);
133 XMapWindow(ob_display
, app
->win
);
135 XMapWindow(ob_display
, app
->icon_win
);
136 XSync(ob_display
, False
);
138 /* specify that if we exit, the window should not be destroyed and should
139 be reparented back to root automatically */
140 XChangeSaveSet(ob_display
, app
->icon_win
, SetModeInsert
);
141 XSelectInput(ob_display
, app
->icon_win
, DOCKAPP_EVENT_MASK
);
143 grab_button_full(2, 0, app
->icon_win
,
144 ButtonPressMask
| ButtonReleaseMask
| ButtonMotionMask
,
145 GrabModeAsync
, OB_CURSOR_MOVE
);
147 g_hash_table_insert(window_map
, &app
->icon_win
, app
);
149 ob_debug("Managed Dock App: 0x%lx (%s)\n", app
->icon_win
, app
->class);
152 void dock_remove_all()
154 while (dock
->dock_apps
)
155 dock_remove(dock
->dock_apps
->data
, TRUE
);
158 void dock_remove(ObDockApp
*app
, gboolean reparent
)
160 ungrab_button(2, 0, app
->icon_win
);
161 XSelectInput(ob_display
, app
->icon_win
, NoEventMask
);
162 /* remove the window from our save set */
163 XChangeSaveSet(ob_display
, app
->icon_win
, SetModeDelete
);
164 XSync(ob_display
, False
);
166 g_hash_table_remove(window_map
, &app
->icon_win
);
169 XReparentWindow(ob_display
, app
->icon_win
,
170 RootWindow(ob_display
, ob_screen
), app
->x
, app
->y
);
172 dock
->dock_apps
= g_list_remove(dock
->dock_apps
, app
);
175 ob_debug("Unmanaged Dock App: 0x%lx (%s)\n", app
->icon_win
, app
->class);
182 void dock_configure()
191 RrMinsize(dock
->a_frame
, &minw
, &minh
);
193 dock
->w
= dock
->h
= 0;
196 for (it
= dock
->dock_apps
; it
; it
= it
->next
) {
197 ObDockApp
*app
= it
->data
;
198 switch (config_dock_orient
) {
199 case OB_ORIENTATION_HORZ
:
201 dock
->h
= MAX(dock
->h
, app
->h
);
203 case OB_ORIENTATION_VERT
:
204 dock
->w
= MAX(dock
->w
, app
->w
);
210 spot
= (config_dock_orient
== OB_ORIENTATION_HORZ
? minw
: minh
) / 2;
212 /* position the apps */
213 for (it
= dock
->dock_apps
; it
; it
= it
->next
) {
214 ObDockApp
*app
= it
->data
;
215 switch (config_dock_orient
) {
216 case OB_ORIENTATION_HORZ
:
218 app
->y
= (dock
->h
- app
->h
) / 2;
221 case OB_ORIENTATION_VERT
:
222 app
->x
= (dock
->w
- app
->w
) / 2;
228 XMoveWindow(ob_display
, app
->icon_win
, app
->x
, app
->y
);
231 /* used for calculating offsets */
232 dock
->w
+= ob_rr_theme
->bwidth
* 2;
233 dock
->h
+= ob_rr_theme
->bwidth
* 2;
235 a
= screen_physical_area();
237 /* calculate position */
238 if (config_dock_floating
) {
239 dock
->x
= config_dock_x
;
240 dock
->y
= config_dock_y
;
241 gravity
= NorthWestGravity
;
243 switch (config_dock_pos
) {
244 case OB_DIRECTION_NORTHWEST
:
247 gravity
= NorthWestGravity
;
249 case OB_DIRECTION_NORTH
:
250 dock
->x
= a
->width
/ 2;
252 gravity
= NorthGravity
;
254 case OB_DIRECTION_NORTHEAST
:
257 gravity
= NorthEastGravity
;
259 case OB_DIRECTION_WEST
:
261 dock
->y
= a
->height
/ 2;
262 gravity
= WestGravity
;
264 case OB_DIRECTION_EAST
:
266 dock
->y
= a
->height
/ 2;
267 gravity
= EastGravity
;
269 case OB_DIRECTION_SOUTHWEST
:
272 gravity
= SouthWestGravity
;
274 case OB_DIRECTION_SOUTH
:
275 dock
->x
= a
->width
/ 2;
277 gravity
= SouthGravity
;
279 case OB_DIRECTION_SOUTHEAST
:
282 gravity
= SouthEastGravity
;
291 dock
->x
-= dock
->w
/ 2;
293 case NorthEastGravity
:
295 case SouthEastGravity
:
303 dock
->y
-= dock
->h
/ 2;
305 case SouthWestGravity
:
307 case SouthEastGravity
:
312 if (config_dock_hide
&& dock
->hidden
) {
313 if (!config_dock_floating
) {
314 switch (config_dock_pos
) {
315 case OB_DIRECTION_NORTHWEST
:
316 switch (config_dock_orient
) {
317 case OB_ORIENTATION_HORZ
:
318 dock
->y
-= dock
->h
- ob_rr_theme
->bwidth
;
320 case OB_ORIENTATION_VERT
:
321 dock
->x
-= dock
->w
- ob_rr_theme
->bwidth
;
325 case OB_DIRECTION_NORTH
:
326 dock
->y
-= dock
->h
- ob_rr_theme
->bwidth
;
328 case OB_DIRECTION_NORTHEAST
:
329 switch (config_dock_orient
) {
330 case OB_ORIENTATION_HORZ
:
331 dock
->y
-= dock
->h
- ob_rr_theme
->bwidth
;
333 case OB_ORIENTATION_VERT
:
334 dock
->x
+= dock
->w
- ob_rr_theme
->bwidth
;
338 case OB_DIRECTION_WEST
:
339 dock
->x
-= dock
->w
- ob_rr_theme
->bwidth
;
341 case OB_DIRECTION_EAST
:
342 dock
->x
+= dock
->w
- ob_rr_theme
->bwidth
;
344 case OB_DIRECTION_SOUTHWEST
:
345 switch (config_dock_orient
) {
346 case OB_ORIENTATION_HORZ
:
347 dock
->y
+= dock
->h
- ob_rr_theme
->bwidth
;
349 case OB_ORIENTATION_VERT
:
350 dock
->x
-= dock
->w
- ob_rr_theme
->bwidth
;
353 case OB_DIRECTION_SOUTH
:
354 dock
->y
+= dock
->h
- ob_rr_theme
->bwidth
;
356 case OB_DIRECTION_SOUTHEAST
:
357 switch (config_dock_orient
) {
358 case OB_ORIENTATION_HORZ
:
359 dock
->y
+= dock
->h
- ob_rr_theme
->bwidth
;
361 case OB_ORIENTATION_VERT
:
362 dock
->x
+= dock
->w
- ob_rr_theme
->bwidth
;
370 if (!config_dock_floating
&& config_dock_hide
) {
371 strw
= ob_rr_theme
->bwidth
;
372 strh
= ob_rr_theme
->bwidth
;
379 if (!dock
->dock_apps
) {
380 STRUT_PARTIAL_SET(dock_strut
, 0, 0, 0, 0,
381 0, 0, 0, 0, 0, 0, 0, 0);
382 } else if (config_dock_floating
) {
383 STRUT_PARTIAL_SET(dock_strut
, 0, 0, 0, 0,
384 0, 0, 0, 0, 0, 0, 0, 0);
386 switch (config_dock_pos
) {
387 case OB_DIRECTION_NORTHWEST
:
388 switch (config_dock_orient
) {
389 case OB_ORIENTATION_HORZ
:
390 STRUT_PARTIAL_SET(dock_strut
, 0, strh
, 0, 0,
391 0, 0, dock
->x
, dock
->x
+ dock
->w
- 1,
394 case OB_ORIENTATION_VERT
:
395 STRUT_PARTIAL_SET(dock_strut
, strw
, 0, 0, 0,
396 dock
->y
, dock
->y
+ dock
->h
- 1,
401 case OB_DIRECTION_NORTH
:
402 STRUT_PARTIAL_SET(dock_strut
, 0, strh
, 0, 0,
403 dock
->x
, dock
->x
+ dock
->w
- 1,
406 case OB_DIRECTION_NORTHEAST
:
407 switch (config_dock_orient
) {
408 case OB_ORIENTATION_HORZ
:
409 STRUT_PARTIAL_SET(dock_strut
, 0, strh
, 0, 0,
410 0, 0, dock
->x
, dock
->x
+ dock
->w
-1,
413 case OB_ORIENTATION_VERT
:
414 STRUT_PARTIAL_SET(dock_strut
, 0, 0, strw
, 0,
416 dock
->y
, dock
->y
+ dock
->h
- 1, 0, 0);
420 case OB_DIRECTION_WEST
:
421 STRUT_PARTIAL_SET(dock_strut
, strw
, 0, 0, 0,
422 dock
->y
, dock
->y
+ dock
->h
- 1,
425 case OB_DIRECTION_EAST
:
426 STRUT_PARTIAL_SET(dock_strut
, 0, 0, strw
, 0,
428 dock
->y
, dock
->y
+ dock
->h
- 1, 0, 0);
430 case OB_DIRECTION_SOUTHWEST
:
431 switch (config_dock_orient
) {
432 case OB_ORIENTATION_HORZ
:
433 STRUT_PARTIAL_SET(dock_strut
, 0, 0, 0, strh
,
435 dock
->x
, dock
->x
+ dock
->w
- 1);
437 case OB_ORIENTATION_VERT
:
438 STRUT_PARTIAL_SET(dock_strut
, strw
, 0, 0, 0,
439 dock
->y
, dock
->y
+ dock
->h
- 1,
444 case OB_DIRECTION_SOUTH
:
445 STRUT_PARTIAL_SET(dock_strut
, 0, 0, 0, strh
,
447 dock
->x
, dock
->x
+ dock
->w
- 1);
449 case OB_DIRECTION_SOUTHEAST
:
450 switch (config_dock_orient
) {
451 case OB_ORIENTATION_HORZ
:
452 STRUT_PARTIAL_SET(dock_strut
, 0, 0, 0, strh
,
454 dock
->x
, dock
->x
+ dock
->w
- 1);
456 case OB_ORIENTATION_VERT
:
457 STRUT_PARTIAL_SET(dock_strut
, 0, 0, strw
, 0,
459 dock
->y
, dock
->y
+ dock
->h
- 1, 0, 0);
469 /* not used for actually sizing shit */
470 dock
->w
-= ob_rr_theme
->bwidth
* 2;
471 dock
->h
-= ob_rr_theme
->bwidth
* 2;
473 if (dock
->dock_apps
) {
474 g_assert(dock
->w
> 0);
475 g_assert(dock
->h
> 0);
477 XMoveResizeWindow(ob_display
, dock
->frame
,
478 dock
->x
, dock
->y
, dock
->w
, dock
->h
);
480 RrPaint(dock
->a_frame
, dock
->frame
, dock
->w
, dock
->h
);
481 XMapWindow(ob_display
, dock
->frame
);
483 XUnmapWindow(ob_display
, dock
->frame
);
485 /* but they are useful outside of this function! */
486 dock
->w
+= ob_rr_theme
->bwidth
* 2;
487 dock
->h
+= ob_rr_theme
->bwidth
* 2;
489 screen_update_areas();
492 void dock_app_configure(ObDockApp
*app
, gint w
, gint h
)
499 void dock_app_drag(ObDockApp
*app
, XMotionEvent
*e
)
501 ObDockApp
*over
= NULL
;
510 /* are we on top of the dock? */
511 if (!(x
>= dock
->x
&&
513 x
< dock
->x
+ dock
->w
&&
514 y
< dock
->y
+ dock
->h
))
520 /* which dock app are we on top of? */
522 for (it
= dock
->dock_apps
; it
; it
= it
->next
) {
524 switch (config_dock_orient
) {
525 case OB_ORIENTATION_HORZ
:
526 if (x
>= over
->x
&& x
< over
->x
+ over
->w
)
529 case OB_ORIENTATION_VERT
:
530 if (y
>= over
->y
&& y
< over
->y
+ over
->h
)
534 /* dont go to it->next! */
537 if (!it
|| app
== over
) return;
542 switch (config_dock_orient
) {
543 case OB_ORIENTATION_HORZ
:
544 after
= (x
> over
->w
/ 2);
546 case OB_ORIENTATION_VERT
:
547 after
= (y
> over
->h
/ 2);
551 /* remove before doing the it->next! */
552 dock
->dock_apps
= g_list_remove(dock
->dock_apps
, app
);
554 if (after
) it
= it
->next
;
556 dock
->dock_apps
= g_list_insert_before(dock
->dock_apps
, it
, app
);
560 static gboolean
hide_timeout(gpointer data
)
566 return FALSE
; /* don't repeat */
569 void dock_hide(gboolean hide
)
573 dock
->hidden
= FALSE
;
576 /* if was hiding, stop it */
577 ob_main_loop_timeout_remove(ob_main_loop
, hide_timeout
);
578 } else if (!dock
->hidden
&& config_dock_hide
) {
579 ob_main_loop_timeout_add(ob_main_loop
, config_dock_hide_timeout
,
580 hide_timeout
, NULL
, NULL
);