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
->osd_border_color
));
61 XSetWindowBorderWidth(ob_display
, dock
->frame
, ob_rr_theme
->obwidth
);
63 RrAppearanceFree(dock
->a_frame
);
64 dock
->a_frame
= RrAppearanceCopy(ob_rr_theme
->osd_hilite_bg
);
66 stacking_add(DOCK_AS_WINDOW(dock
));
71 for (it
= dock
->dock_apps
; it
; it
= g_list_next(it
))
72 dock_app_grab_button(it
->data
, TRUE
);
76 STRUT_PARTIAL_SET(dock_strut
, 0, 0, 0, 0,
77 0, 0, 0, 0, 0, 0, 0, 0);
79 dock
= g_new0(ObDock
, 1);
80 dock
->obwin
.type
= Window_Dock
;
84 attrib
.event_mask
= DOCK_EVENT_MASK
;
85 attrib
.override_redirect
= True
;
86 dock
->frame
= XCreateWindow(ob_display
, RootWindow(ob_display
, ob_screen
),
88 RrDepth(ob_rr_inst
), InputOutput
,
90 CWOverrideRedirect
| CWEventMask
,
92 dock
->a_frame
= RrAppearanceCopy(ob_rr_theme
->osd_hilite_bg
);
93 XSetWindowBorder(ob_display
, dock
->frame
,
94 RrColorPixel(ob_rr_theme
->osd_border_color
));
95 XSetWindowBorderWidth(ob_display
, dock
->frame
, ob_rr_theme
->obwidth
);
97 g_hash_table_insert(window_map
, &dock
->frame
, dock
);
98 stacking_add(DOCK_AS_WINDOW(dock
));
101 void dock_shutdown(gboolean reconfig
)
106 stacking_remove(DOCK_AS_WINDOW(dock
));
108 for (it
= dock
->dock_apps
; it
; it
= g_list_next(it
))
109 dock_app_grab_button(it
->data
, FALSE
);
113 XDestroyWindow(ob_display
, dock
->frame
);
114 RrAppearanceFree(dock
->a_frame
);
115 g_hash_table_remove(window_map
, &dock
->frame
);
116 stacking_remove(dock
);
119 void dock_add(Window win
, XWMHints
*wmhints
)
122 XWindowAttributes attrib
;
125 app
= g_new0(ObDockApp
, 1);
126 app
->obwin
.type
= Window_DockApp
;
128 app
->icon_win
= (wmhints
->flags
& IconWindowHint
) ?
129 wmhints
->icon_window
: win
;
131 if (PROP_GETSS(app
->win
, wm_class
, locale
, &data
)) {
133 app
->name
= g_strdup(data
[0]);
135 app
->class = g_strdup(data
[1]);
140 if (app
->name
== NULL
) app
->name
= g_strdup("");
141 if (app
->class == NULL
) app
->class = g_strdup("");
143 if (XGetWindowAttributes(ob_display
, app
->icon_win
, &attrib
)) {
144 app
->w
= attrib
.width
;
145 app
->h
= attrib
.height
;
147 app
->w
= app
->h
= 64;
150 dock
->dock_apps
= g_list_append(dock
->dock_apps
, app
);
153 XReparentWindow(ob_display
, app
->icon_win
, dock
->frame
, app
->x
, app
->y
);
155 This is the same case as in frame.c for client windows. When Openbox is
156 starting, the window is already mapped so we see unmap events occur for
157 it. There are 2 unmap events generated that we see, one with the 'event'
158 member set the root window, and one set to the client, but both get
159 handled and need to be ignored.
161 if (ob_state() == OB_STATE_STARTING
)
162 app
->ignore_unmaps
+= 2;
164 if (app
->win
!= app
->icon_win
) {
165 /* have to map it so that it can be re-managed on a restart */
166 XMoveWindow(ob_display
, app
->win
, -1000, -1000);
167 XMapWindow(ob_display
, app
->win
);
169 XMapWindow(ob_display
, app
->icon_win
);
170 XSync(ob_display
, False
);
172 /* specify that if we exit, the window should not be destroyed and should
173 be reparented back to root automatically */
174 XChangeSaveSet(ob_display
, app
->icon_win
, SetModeInsert
);
175 XSelectInput(ob_display
, app
->icon_win
, DOCKAPP_EVENT_MASK
);
177 dock_app_grab_button(app
, TRUE
);
179 g_hash_table_insert(window_map
, &app
->icon_win
, app
);
181 ob_debug("Managed Dock App: 0x%lx (%s)\n", app
->icon_win
, app
->class);
184 void dock_remove_all()
186 while (dock
->dock_apps
)
187 dock_remove(dock
->dock_apps
->data
, TRUE
);
190 void dock_remove(ObDockApp
*app
, gboolean reparent
)
192 dock_app_grab_button(app
, FALSE
);
193 XSelectInput(ob_display
, app
->icon_win
, NoEventMask
);
194 /* remove the window from our save set */
195 XChangeSaveSet(ob_display
, app
->icon_win
, SetModeDelete
);
196 XSync(ob_display
, False
);
198 g_hash_table_remove(window_map
, &app
->icon_win
);
201 XReparentWindow(ob_display
, app
->icon_win
,
202 RootWindow(ob_display
, ob_screen
), app
->x
, app
->y
);
204 dock
->dock_apps
= g_list_remove(dock
->dock_apps
, app
);
207 ob_debug("Unmanaged Dock App: 0x%lx (%s)\n", app
->icon_win
, app
->class);
214 void dock_configure()
223 RrMinSize(dock
->a_frame
, &minw
, &minh
);
225 dock
->w
= dock
->h
= 0;
228 for (it
= dock
->dock_apps
; it
; it
= g_list_next(it
)) {
229 ObDockApp
*app
= it
->data
;
230 switch (config_dock_orient
) {
231 case OB_ORIENTATION_HORZ
:
233 dock
->h
= MAX(dock
->h
, app
->h
);
235 case OB_ORIENTATION_VERT
:
236 dock
->w
= MAX(dock
->w
, app
->w
);
242 spot
= (config_dock_orient
== OB_ORIENTATION_HORZ
? minw
: minh
) / 2;
244 /* position the apps */
245 for (it
= dock
->dock_apps
; it
; it
= g_list_next(it
)) {
246 ObDockApp
*app
= it
->data
;
247 switch (config_dock_orient
) {
248 case OB_ORIENTATION_HORZ
:
250 app
->y
= (dock
->h
- app
->h
) / 2;
253 case OB_ORIENTATION_VERT
:
254 app
->x
= (dock
->w
- app
->w
) / 2;
260 XMoveWindow(ob_display
, app
->icon_win
, app
->x
, app
->y
);
263 /* used for calculating offsets */
264 dock
->w
+= ob_rr_theme
->obwidth
* 2;
265 dock
->h
+= ob_rr_theme
->obwidth
* 2;
267 a
= screen_physical_area();
269 /* calculate position */
270 if (config_dock_floating
) {
271 dock
->x
= config_dock_x
;
272 dock
->y
= config_dock_y
;
273 gravity
= NorthWestGravity
;
275 switch (config_dock_pos
) {
276 case OB_DIRECTION_NORTHWEST
:
279 gravity
= NorthWestGravity
;
281 case OB_DIRECTION_NORTH
:
282 dock
->x
= a
->width
/ 2;
284 gravity
= NorthGravity
;
286 case OB_DIRECTION_NORTHEAST
:
289 gravity
= NorthEastGravity
;
291 case OB_DIRECTION_WEST
:
293 dock
->y
= a
->height
/ 2;
294 gravity
= WestGravity
;
296 case OB_DIRECTION_EAST
:
298 dock
->y
= a
->height
/ 2;
299 gravity
= EastGravity
;
301 case OB_DIRECTION_SOUTHWEST
:
304 gravity
= SouthWestGravity
;
306 case OB_DIRECTION_SOUTH
:
307 dock
->x
= a
->width
/ 2;
309 gravity
= SouthGravity
;
311 case OB_DIRECTION_SOUTHEAST
:
314 gravity
= SouthEastGravity
;
317 g_assert_not_reached();
325 dock
->x
-= dock
->w
/ 2;
327 case NorthEastGravity
:
329 case SouthEastGravity
:
337 dock
->y
-= dock
->h
/ 2;
339 case SouthWestGravity
:
341 case SouthEastGravity
:
346 if (config_dock_hide
&& dock
->hidden
) {
347 if (!config_dock_floating
) {
348 switch (config_dock_pos
) {
349 case OB_DIRECTION_NORTHWEST
:
350 switch (config_dock_orient
) {
351 case OB_ORIENTATION_HORZ
:
352 dock
->y
-= dock
->h
- ob_rr_theme
->obwidth
;
354 case OB_ORIENTATION_VERT
:
355 dock
->x
-= dock
->w
- ob_rr_theme
->obwidth
;
359 case OB_DIRECTION_NORTH
:
360 dock
->y
-= dock
->h
- ob_rr_theme
->obwidth
;
362 case OB_DIRECTION_NORTHEAST
:
363 switch (config_dock_orient
) {
364 case OB_ORIENTATION_HORZ
:
365 dock
->y
-= dock
->h
- ob_rr_theme
->obwidth
;
367 case OB_ORIENTATION_VERT
:
368 dock
->x
+= dock
->w
- ob_rr_theme
->obwidth
;
372 case OB_DIRECTION_WEST
:
373 dock
->x
-= dock
->w
- ob_rr_theme
->obwidth
;
375 case OB_DIRECTION_EAST
:
376 dock
->x
+= dock
->w
- ob_rr_theme
->obwidth
;
378 case OB_DIRECTION_SOUTHWEST
:
379 switch (config_dock_orient
) {
380 case OB_ORIENTATION_HORZ
:
381 dock
->y
+= dock
->h
- ob_rr_theme
->obwidth
;
383 case OB_ORIENTATION_VERT
:
384 dock
->x
-= dock
->w
- ob_rr_theme
->obwidth
;
387 case OB_DIRECTION_SOUTH
:
388 dock
->y
+= dock
->h
- ob_rr_theme
->obwidth
;
390 case OB_DIRECTION_SOUTHEAST
:
391 switch (config_dock_orient
) {
392 case OB_ORIENTATION_HORZ
:
393 dock
->y
+= dock
->h
- ob_rr_theme
->obwidth
;
395 case OB_ORIENTATION_VERT
:
396 dock
->x
+= dock
->w
- ob_rr_theme
->obwidth
;
404 if (!config_dock_floating
&& config_dock_hide
) {
405 strw
= ob_rr_theme
->obwidth
;
406 strh
= ob_rr_theme
->obwidth
;
413 if (!dock
->dock_apps
) {
414 STRUT_PARTIAL_SET(dock_strut
, 0, 0, 0, 0,
415 0, 0, 0, 0, 0, 0, 0, 0);
416 } 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
->obwidth
* 2;
506 dock
->h
-= ob_rr_theme
->obwidth
* 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
->obwidth
* 2;
522 dock
->h
+= ob_rr_theme
->obwidth
* 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
);