1 /* -*- indent-tabs-mode: nil; tab-width: 4; c-basic-offset: 4; -*-
3 dock.c for the Openbox window manager
4 Copyright (c) 2006 Mikael Magnusson
5 Copyright (c) 2003-2007 Dana Jansens
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.
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.
17 See the COPYING file for a copy of the GNU General Public License.
28 #include "render/theme.h"
30 #define DOCK_EVENT_MASK (ButtonPressMask | ButtonReleaseMask | \
31 EnterWindowMask | LeaveWindowMask)
32 #define DOCKAPP_EVENT_MASK (StructureNotifyMask)
36 StrutPartial dock_strut
;
38 static void dock_app_grab_button(ObDockApp
*app
, gboolean grab
)
41 grab_button_full(config_dock_app_move_button
,
42 config_dock_app_move_modifiers
, app
->icon_win
,
43 ButtonPressMask
| ButtonReleaseMask
|
45 GrabModeAsync
, OB_CURSOR_MOVE
);
47 ungrab_button(config_dock_app_move_button
,
48 config_dock_app_move_modifiers
, app
->icon_win
);
52 void dock_startup(gboolean reconfig
)
54 XSetWindowAttributes attrib
;
59 XSetWindowBorder(ob_display
, dock
->frame
,
60 RrColorPixel(ob_rr_theme
->
61 frame_focused_border_color
));
62 XSetWindowBorderWidth(ob_display
, dock
->frame
, ob_rr_theme
->fbwidth
);
64 RrAppearanceFree(dock
->a_frame
);
65 dock
->a_frame
= RrAppearanceCopy(ob_rr_theme
->a_focused_title
);
67 stacking_add(DOCK_AS_WINDOW(dock
));
72 for (it
= dock
->dock_apps
; it
; it
= g_list_next(it
))
73 dock_app_grab_button(it
->data
, TRUE
);
77 STRUT_PARTIAL_SET(dock_strut
, 0, 0, 0, 0,
78 0, 0, 0, 0, 0, 0, 0, 0);
80 dock
= g_new0(ObDock
, 1);
81 dock
->obwin
.type
= Window_Dock
;
85 attrib
.event_mask
= DOCK_EVENT_MASK
;
86 attrib
.override_redirect
= True
;
87 dock
->frame
= XCreateWindow(ob_display
, RootWindow(ob_display
, ob_screen
),
89 RrDepth(ob_rr_inst
), InputOutput
,
91 CWOverrideRedirect
| CWEventMask
,
93 dock
->a_frame
= RrAppearanceCopy(ob_rr_theme
->a_focused_title
);
94 XSetWindowBorder(ob_display
, dock
->frame
,
95 RrColorPixel(ob_rr_theme
->frame_focused_border_color
));
96 XSetWindowBorderWidth(ob_display
, dock
->frame
, ob_rr_theme
->fbwidth
);
98 g_hash_table_insert(window_map
, &dock
->frame
, dock
);
99 stacking_add(DOCK_AS_WINDOW(dock
));
102 void dock_shutdown(gboolean reconfig
)
107 stacking_remove(DOCK_AS_WINDOW(dock
));
109 for (it
= dock
->dock_apps
; it
; it
= g_list_next(it
))
110 dock_app_grab_button(it
->data
, FALSE
);
114 XDestroyWindow(ob_display
, dock
->frame
);
115 RrAppearanceFree(dock
->a_frame
);
116 g_hash_table_remove(window_map
, &dock
->frame
);
117 stacking_remove(dock
);
120 void dock_add(Window win
, XWMHints
*wmhints
)
123 XWindowAttributes attrib
;
126 app
= g_new0(ObDockApp
, 1);
127 app
->obwin
.type
= Window_DockApp
;
129 app
->icon_win
= (wmhints
->flags
& IconWindowHint
) ?
130 wmhints
->icon_window
: win
;
132 if (PROP_GETSS(app
->win
, wm_class
, locale
, &data
)) {
134 app
->name
= g_strdup(data
[0]);
136 app
->class = g_strdup(data
[1]);
141 if (app
->name
== NULL
) app
->name
= g_strdup("");
142 if (app
->class == NULL
) app
->class = g_strdup("");
144 if (XGetWindowAttributes(ob_display
, app
->icon_win
, &attrib
)) {
145 app
->w
= attrib
.width
;
146 app
->h
= attrib
.height
;
148 app
->w
= app
->h
= 64;
151 dock
->dock_apps
= g_list_append(dock
->dock_apps
, app
);
154 XReparentWindow(ob_display
, app
->icon_win
, dock
->frame
, app
->x
, app
->y
);
156 This is the same case as in frame.c for client windows. When Openbox is
157 starting, the window is already mapped so we see unmap events occur for
158 it. There are 2 unmap events generated that we see, one with the 'event'
159 member set the root window, and one set to the client, but both get
160 handled and need to be ignored.
162 if (ob_state() == OB_STATE_STARTING
)
163 app
->ignore_unmaps
+= 2;
165 if (app
->win
!= app
->icon_win
) {
166 /* have to map it so that it can be re-managed on a restart */
167 XMoveWindow(ob_display
, app
->win
, -1000, -1000);
168 XMapWindow(ob_display
, app
->win
);
170 XMapWindow(ob_display
, app
->icon_win
);
171 XSync(ob_display
, False
);
173 /* specify that if we exit, the window should not be destroyed and should
174 be reparented back to root automatically */
175 XChangeSaveSet(ob_display
, app
->icon_win
, SetModeInsert
);
176 XSelectInput(ob_display
, app
->icon_win
, DOCKAPP_EVENT_MASK
);
178 dock_app_grab_button(app
, TRUE
);
180 g_hash_table_insert(window_map
, &app
->icon_win
, app
);
182 ob_debug("Managed Dock App: 0x%lx (%s)\n", app
->icon_win
, app
->class);
185 void dock_remove_all()
187 while (dock
->dock_apps
)
188 dock_remove(dock
->dock_apps
->data
, TRUE
);
191 void dock_remove(ObDockApp
*app
, gboolean reparent
)
193 dock_app_grab_button(app
, FALSE
);
194 XSelectInput(ob_display
, app
->icon_win
, NoEventMask
);
195 /* remove the window from our save set */
196 XChangeSaveSet(ob_display
, app
->icon_win
, SetModeDelete
);
197 XSync(ob_display
, False
);
199 g_hash_table_remove(window_map
, &app
->icon_win
);
202 XReparentWindow(ob_display
, app
->icon_win
,
203 RootWindow(ob_display
, ob_screen
), app
->x
, app
->y
);
205 dock
->dock_apps
= g_list_remove(dock
->dock_apps
, app
);
208 ob_debug("Unmanaged Dock App: 0x%lx (%s)\n", app
->icon_win
, app
->class);
215 void dock_configure()
224 RrMinSize(dock
->a_frame
, &minw
, &minh
);
226 dock
->w
= dock
->h
= 0;
229 for (it
= dock
->dock_apps
; it
; it
= g_list_next(it
)) {
230 ObDockApp
*app
= it
->data
;
231 switch (config_dock_orient
) {
232 case OB_ORIENTATION_HORZ
:
234 dock
->h
= MAX(dock
->h
, app
->h
);
236 case OB_ORIENTATION_VERT
:
237 dock
->w
= MAX(dock
->w
, app
->w
);
243 spot
= (config_dock_orient
== OB_ORIENTATION_HORZ
? minw
: minh
) / 2;
245 /* position the apps */
246 for (it
= dock
->dock_apps
; it
; it
= g_list_next(it
)) {
247 ObDockApp
*app
= it
->data
;
248 switch (config_dock_orient
) {
249 case OB_ORIENTATION_HORZ
:
251 app
->y
= (dock
->h
- app
->h
) / 2;
254 case OB_ORIENTATION_VERT
:
255 app
->x
= (dock
->w
- app
->w
) / 2;
261 XMoveWindow(ob_display
, app
->icon_win
, app
->x
, app
->y
);
264 /* used for calculating offsets */
265 dock
->w
+= ob_rr_theme
->fbwidth
* 2;
266 dock
->h
+= ob_rr_theme
->fbwidth
* 2;
268 a
= screen_physical_area();
270 /* calculate position */
271 if (config_dock_floating
) {
272 dock
->x
= config_dock_x
;
273 dock
->y
= config_dock_y
;
274 gravity
= NorthWestGravity
;
276 switch (config_dock_pos
) {
277 case OB_DIRECTION_NORTHWEST
:
280 gravity
= NorthWestGravity
;
282 case OB_DIRECTION_NORTH
:
283 dock
->x
= a
->width
/ 2;
285 gravity
= NorthGravity
;
287 case OB_DIRECTION_NORTHEAST
:
290 gravity
= NorthEastGravity
;
292 case OB_DIRECTION_WEST
:
294 dock
->y
= a
->height
/ 2;
295 gravity
= WestGravity
;
297 case OB_DIRECTION_EAST
:
299 dock
->y
= a
->height
/ 2;
300 gravity
= EastGravity
;
302 case OB_DIRECTION_SOUTHWEST
:
305 gravity
= SouthWestGravity
;
307 case OB_DIRECTION_SOUTH
:
308 dock
->x
= a
->width
/ 2;
310 gravity
= SouthGravity
;
312 case OB_DIRECTION_SOUTHEAST
:
315 gravity
= SouthEastGravity
;
318 g_assert_not_reached();
326 dock
->x
-= dock
->w
/ 2;
328 case NorthEastGravity
:
330 case SouthEastGravity
:
338 dock
->y
-= dock
->h
/ 2;
340 case SouthWestGravity
:
342 case SouthEastGravity
:
347 if (config_dock_hide
&& dock
->hidden
) {
348 if (!config_dock_floating
) {
349 switch (config_dock_pos
) {
350 case OB_DIRECTION_NORTHWEST
:
351 switch (config_dock_orient
) {
352 case OB_ORIENTATION_HORZ
:
353 dock
->y
-= dock
->h
- ob_rr_theme
->fbwidth
;
355 case OB_ORIENTATION_VERT
:
356 dock
->x
-= dock
->w
- ob_rr_theme
->fbwidth
;
360 case OB_DIRECTION_NORTH
:
361 dock
->y
-= dock
->h
- ob_rr_theme
->fbwidth
;
363 case OB_DIRECTION_NORTHEAST
:
364 switch (config_dock_orient
) {
365 case OB_ORIENTATION_HORZ
:
366 dock
->y
-= dock
->h
- ob_rr_theme
->fbwidth
;
368 case OB_ORIENTATION_VERT
:
369 dock
->x
+= dock
->w
- ob_rr_theme
->fbwidth
;
373 case OB_DIRECTION_WEST
:
374 dock
->x
-= dock
->w
- ob_rr_theme
->fbwidth
;
376 case OB_DIRECTION_EAST
:
377 dock
->x
+= dock
->w
- ob_rr_theme
->fbwidth
;
379 case OB_DIRECTION_SOUTHWEST
:
380 switch (config_dock_orient
) {
381 case OB_ORIENTATION_HORZ
:
382 dock
->y
+= dock
->h
- ob_rr_theme
->fbwidth
;
384 case OB_ORIENTATION_VERT
:
385 dock
->x
-= dock
->w
- ob_rr_theme
->fbwidth
;
388 case OB_DIRECTION_SOUTH
:
389 dock
->y
+= dock
->h
- ob_rr_theme
->fbwidth
;
391 case OB_DIRECTION_SOUTHEAST
:
392 switch (config_dock_orient
) {
393 case OB_ORIENTATION_HORZ
:
394 dock
->y
+= dock
->h
- ob_rr_theme
->fbwidth
;
396 case OB_ORIENTATION_VERT
:
397 dock
->x
+= dock
->w
- ob_rr_theme
->fbwidth
;
405 if (!config_dock_floating
&& config_dock_hide
) {
406 strw
= ob_rr_theme
->fbwidth
;
407 strh
= ob_rr_theme
->fbwidth
;
414 if (!dock
->dock_apps
) {
415 STRUT_PARTIAL_SET(dock_strut
, 0, 0, 0, 0,
416 0, 0, 0, 0, 0, 0, 0, 0);
417 } else if (config_dock_floating
|| config_dock_nostrut
)
419 STRUT_PARTIAL_SET(dock_strut
, 0, 0, 0, 0,
420 0, 0, 0, 0, 0, 0, 0, 0);
422 switch (config_dock_pos
) {
423 case OB_DIRECTION_NORTHWEST
:
424 switch (config_dock_orient
) {
425 case OB_ORIENTATION_HORZ
:
426 STRUT_PARTIAL_SET(dock_strut
, 0, strh
, 0, 0,
427 0, 0, dock
->x
, dock
->x
+ dock
->w
- 1,
430 case OB_ORIENTATION_VERT
:
431 STRUT_PARTIAL_SET(dock_strut
, strw
, 0, 0, 0,
432 dock
->y
, dock
->y
+ dock
->h
- 1,
437 case OB_DIRECTION_NORTH
:
438 STRUT_PARTIAL_SET(dock_strut
, 0, strh
, 0, 0,
439 dock
->x
, dock
->x
+ dock
->w
- 1,
442 case OB_DIRECTION_NORTHEAST
:
443 switch (config_dock_orient
) {
444 case OB_ORIENTATION_HORZ
:
445 STRUT_PARTIAL_SET(dock_strut
, 0, strh
, 0, 0,
446 0, 0, dock
->x
, dock
->x
+ dock
->w
-1,
449 case OB_ORIENTATION_VERT
:
450 STRUT_PARTIAL_SET(dock_strut
, 0, 0, strw
, 0,
452 dock
->y
, dock
->y
+ dock
->h
- 1, 0, 0);
456 case OB_DIRECTION_WEST
:
457 STRUT_PARTIAL_SET(dock_strut
, strw
, 0, 0, 0,
458 dock
->y
, dock
->y
+ dock
->h
- 1,
461 case OB_DIRECTION_EAST
:
462 STRUT_PARTIAL_SET(dock_strut
, 0, 0, strw
, 0,
464 dock
->y
, dock
->y
+ dock
->h
- 1, 0, 0);
466 case OB_DIRECTION_SOUTHWEST
:
467 switch (config_dock_orient
) {
468 case OB_ORIENTATION_HORZ
:
469 STRUT_PARTIAL_SET(dock_strut
, 0, 0, 0, strh
,
471 dock
->x
, dock
->x
+ dock
->w
- 1);
473 case OB_ORIENTATION_VERT
:
474 STRUT_PARTIAL_SET(dock_strut
, strw
, 0, 0, 0,
475 dock
->y
, dock
->y
+ dock
->h
- 1,
480 case OB_DIRECTION_SOUTH
:
481 STRUT_PARTIAL_SET(dock_strut
, 0, 0, 0, strh
,
483 dock
->x
, dock
->x
+ dock
->w
- 1);
485 case OB_DIRECTION_SOUTHEAST
:
486 switch (config_dock_orient
) {
487 case OB_ORIENTATION_HORZ
:
488 STRUT_PARTIAL_SET(dock_strut
, 0, 0, 0, strh
,
490 dock
->x
, dock
->x
+ dock
->w
- 1);
492 case OB_ORIENTATION_VERT
:
493 STRUT_PARTIAL_SET(dock_strut
, 0, 0, strw
, 0,
495 dock
->y
, dock
->y
+ dock
->h
- 1, 0, 0);
505 /* not used for actually sizing shit */
506 dock
->w
-= ob_rr_theme
->fbwidth
* 2;
507 dock
->h
-= ob_rr_theme
->fbwidth
* 2;
509 if (dock
->dock_apps
) {
510 g_assert(dock
->w
> 0);
511 g_assert(dock
->h
> 0);
513 XMoveResizeWindow(ob_display
, dock
->frame
,
514 dock
->x
, dock
->y
, dock
->w
, dock
->h
);
516 RrPaint(dock
->a_frame
, dock
->frame
, dock
->w
, dock
->h
);
517 XMapWindow(ob_display
, dock
->frame
);
519 XUnmapWindow(ob_display
, dock
->frame
);
521 /* but they are useful outside of this function! */
522 dock
->w
+= ob_rr_theme
->fbwidth
* 2;
523 dock
->h
+= ob_rr_theme
->fbwidth
* 2;
525 screen_update_areas();
528 void dock_app_configure(ObDockApp
*app
, gint w
, gint h
)
535 void dock_app_drag(ObDockApp
*app
, XMotionEvent
*e
)
537 ObDockApp
*over
= NULL
;
546 /* are we on top of the dock? */
547 if (!(x
>= dock
->x
&&
549 x
< dock
->x
+ dock
->w
&&
550 y
< dock
->y
+ dock
->h
))
556 /* which dock app are we on top of? */
558 for (it
= dock
->dock_apps
; it
; it
= g_list_next(it
)) {
560 switch (config_dock_orient
) {
561 case OB_ORIENTATION_HORZ
:
562 if (x
>= over
->x
&& x
< over
->x
+ over
->w
)
565 case OB_ORIENTATION_VERT
:
566 if (y
>= over
->y
&& y
< over
->y
+ over
->h
)
570 /* dont go to it->next! */
573 if (!it
|| app
== over
) return;
578 switch (config_dock_orient
) {
579 case OB_ORIENTATION_HORZ
:
580 after
= (x
> over
->w
/ 2);
582 case OB_ORIENTATION_VERT
:
583 after
= (y
> over
->h
/ 2);
586 g_assert_not_reached();
589 /* remove before doing the it->next! */
590 dock
->dock_apps
= g_list_remove(dock
->dock_apps
, app
);
592 if (after
) it
= it
->next
;
594 dock
->dock_apps
= g_list_insert_before(dock
->dock_apps
, it
, app
);
598 static gboolean
hide_timeout(gpointer data
)
604 return FALSE
; /* don't repeat */
607 static gboolean
show_timeout(gpointer data
)
610 dock
->hidden
= FALSE
;
613 return FALSE
; /* don't repeat */
616 void dock_hide(gboolean hide
)
619 if (dock
->hidden
&& config_dock_hide
) {
620 ob_main_loop_timeout_add(ob_main_loop
, config_dock_show_delay
,
621 show_timeout
, NULL
, g_direct_equal
, NULL
);
622 } else if (!dock
->hidden
&& config_dock_hide
) {
623 ob_main_loop_timeout_remove(ob_main_loop
, hide_timeout
);
626 if (!dock
->hidden
&& config_dock_hide
) {
627 ob_main_loop_timeout_add(ob_main_loop
, config_dock_hide_delay
,
628 hide_timeout
, NULL
, g_direct_equal
, NULL
);
629 } else if (dock
->hidden
&& config_dock_hide
) {
630 ob_main_loop_timeout_remove(ob_main_loop
, show_timeout
);