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
) {
418 STRUT_PARTIAL_SET(dock_strut
, 0, 0, 0, 0,
419 0, 0, 0, 0, 0, 0, 0, 0);
421 switch (config_dock_pos
) {
422 case OB_DIRECTION_NORTHWEST
:
423 switch (config_dock_orient
) {
424 case OB_ORIENTATION_HORZ
:
425 STRUT_PARTIAL_SET(dock_strut
, 0, strh
, 0, 0,
426 0, 0, dock
->x
, dock
->x
+ dock
->w
- 1,
429 case OB_ORIENTATION_VERT
:
430 STRUT_PARTIAL_SET(dock_strut
, strw
, 0, 0, 0,
431 dock
->y
, dock
->y
+ dock
->h
- 1,
436 case OB_DIRECTION_NORTH
:
437 STRUT_PARTIAL_SET(dock_strut
, 0, strh
, 0, 0,
438 dock
->x
, dock
->x
+ dock
->w
- 1,
441 case OB_DIRECTION_NORTHEAST
:
442 switch (config_dock_orient
) {
443 case OB_ORIENTATION_HORZ
:
444 STRUT_PARTIAL_SET(dock_strut
, 0, strh
, 0, 0,
445 0, 0, dock
->x
, dock
->x
+ dock
->w
-1,
448 case OB_ORIENTATION_VERT
:
449 STRUT_PARTIAL_SET(dock_strut
, 0, 0, strw
, 0,
451 dock
->y
, dock
->y
+ dock
->h
- 1, 0, 0);
455 case OB_DIRECTION_WEST
:
456 STRUT_PARTIAL_SET(dock_strut
, strw
, 0, 0, 0,
457 dock
->y
, dock
->y
+ dock
->h
- 1,
460 case OB_DIRECTION_EAST
:
461 STRUT_PARTIAL_SET(dock_strut
, 0, 0, strw
, 0,
463 dock
->y
, dock
->y
+ dock
->h
- 1, 0, 0);
465 case OB_DIRECTION_SOUTHWEST
:
466 switch (config_dock_orient
) {
467 case OB_ORIENTATION_HORZ
:
468 STRUT_PARTIAL_SET(dock_strut
, 0, 0, 0, strh
,
470 dock
->x
, dock
->x
+ dock
->w
- 1);
472 case OB_ORIENTATION_VERT
:
473 STRUT_PARTIAL_SET(dock_strut
, strw
, 0, 0, 0,
474 dock
->y
, dock
->y
+ dock
->h
- 1,
479 case OB_DIRECTION_SOUTH
:
480 STRUT_PARTIAL_SET(dock_strut
, 0, 0, 0, strh
,
482 dock
->x
, dock
->x
+ dock
->w
- 1);
484 case OB_DIRECTION_SOUTHEAST
:
485 switch (config_dock_orient
) {
486 case OB_ORIENTATION_HORZ
:
487 STRUT_PARTIAL_SET(dock_strut
, 0, 0, 0, strh
,
489 dock
->x
, dock
->x
+ dock
->w
- 1);
491 case OB_ORIENTATION_VERT
:
492 STRUT_PARTIAL_SET(dock_strut
, 0, 0, strw
, 0,
494 dock
->y
, dock
->y
+ dock
->h
- 1, 0, 0);
504 /* not used for actually sizing shit */
505 dock
->w
-= ob_rr_theme
->fbwidth
* 2;
506 dock
->h
-= ob_rr_theme
->fbwidth
* 2;
508 if (dock
->dock_apps
) {
509 g_assert(dock
->w
> 0);
510 g_assert(dock
->h
> 0);
512 XMoveResizeWindow(ob_display
, dock
->frame
,
513 dock
->x
, dock
->y
, dock
->w
, dock
->h
);
515 RrPaint(dock
->a_frame
, dock
->frame
, dock
->w
, dock
->h
);
516 XMapWindow(ob_display
, dock
->frame
);
518 XUnmapWindow(ob_display
, dock
->frame
);
520 /* but they are useful outside of this function! */
521 dock
->w
+= ob_rr_theme
->fbwidth
* 2;
522 dock
->h
+= ob_rr_theme
->fbwidth
* 2;
524 screen_update_areas();
527 void dock_app_configure(ObDockApp
*app
, gint w
, gint h
)
534 void dock_app_drag(ObDockApp
*app
, XMotionEvent
*e
)
536 ObDockApp
*over
= NULL
;
545 /* are we on top of the dock? */
546 if (!(x
>= dock
->x
&&
548 x
< dock
->x
+ dock
->w
&&
549 y
< dock
->y
+ dock
->h
))
555 /* which dock app are we on top of? */
557 for (it
= dock
->dock_apps
; it
; it
= g_list_next(it
)) {
559 switch (config_dock_orient
) {
560 case OB_ORIENTATION_HORZ
:
561 if (x
>= over
->x
&& x
< over
->x
+ over
->w
)
564 case OB_ORIENTATION_VERT
:
565 if (y
>= over
->y
&& y
< over
->y
+ over
->h
)
569 /* dont go to it->next! */
572 if (!it
|| app
== over
) return;
577 switch (config_dock_orient
) {
578 case OB_ORIENTATION_HORZ
:
579 after
= (x
> over
->w
/ 2);
581 case OB_ORIENTATION_VERT
:
582 after
= (y
> over
->h
/ 2);
585 g_assert_not_reached();
588 /* remove before doing the it->next! */
589 dock
->dock_apps
= g_list_remove(dock
->dock_apps
, app
);
591 if (after
) it
= it
->next
;
593 dock
->dock_apps
= g_list_insert_before(dock
->dock_apps
, it
, app
);
597 static gboolean
hide_timeout(gpointer data
)
603 return FALSE
; /* don't repeat */
606 static gboolean
show_timeout(gpointer data
)
609 dock
->hidden
= FALSE
;
612 return FALSE
; /* don't repeat */
615 void dock_hide(gboolean hide
)
618 if (dock
->hidden
&& config_dock_hide
) {
619 ob_main_loop_timeout_add(ob_main_loop
, config_dock_show_delay
,
620 show_timeout
, NULL
, g_direct_equal
, NULL
);
621 } else if (!dock
->hidden
&& config_dock_hide
) {
622 ob_main_loop_timeout_remove(ob_main_loop
, hide_timeout
);
625 if (!dock
->hidden
&& config_dock_hide
) {
626 ob_main_loop_timeout_add(ob_main_loop
, config_dock_hide_delay
,
627 hide_timeout
, NULL
, g_direct_equal
, NULL
);
628 } else if (dock
->hidden
&& config_dock_hide
) {
629 ob_main_loop_timeout_remove(ob_main_loop
, show_timeout
);