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 Ben 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
->b_color
));
61 XSetWindowBorderWidth(ob_display
, dock
->frame
, ob_rr_theme
->bwidth
);
63 RrAppearanceFree(dock
->a_frame
);
64 dock
->a_frame
= RrAppearanceCopy(ob_rr_theme
->a_focused_title
);
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
->a_focused_title
);
93 XSetWindowBorder(ob_display
, dock
->frame
,
94 RrColorPixel(ob_rr_theme
->b_color
));
95 XSetWindowBorderWidth(ob_display
, dock
->frame
, ob_rr_theme
->bwidth
);
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
->bwidth
* 2;
265 dock
->h
+= ob_rr_theme
->bwidth
* 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
;
323 dock
->x
-= dock
->w
/ 2;
325 case NorthEastGravity
:
327 case SouthEastGravity
:
335 dock
->y
-= dock
->h
/ 2;
337 case SouthWestGravity
:
339 case SouthEastGravity
:
344 if (config_dock_hide
&& dock
->hidden
) {
345 if (!config_dock_floating
) {
346 switch (config_dock_pos
) {
347 case OB_DIRECTION_NORTHWEST
:
348 switch (config_dock_orient
) {
349 case OB_ORIENTATION_HORZ
:
350 dock
->y
-= dock
->h
- ob_rr_theme
->bwidth
;
352 case OB_ORIENTATION_VERT
:
353 dock
->x
-= dock
->w
- ob_rr_theme
->bwidth
;
357 case OB_DIRECTION_NORTH
:
358 dock
->y
-= dock
->h
- ob_rr_theme
->bwidth
;
360 case OB_DIRECTION_NORTHEAST
:
361 switch (config_dock_orient
) {
362 case OB_ORIENTATION_HORZ
:
363 dock
->y
-= dock
->h
- ob_rr_theme
->bwidth
;
365 case OB_ORIENTATION_VERT
:
366 dock
->x
+= dock
->w
- ob_rr_theme
->bwidth
;
370 case OB_DIRECTION_WEST
:
371 dock
->x
-= dock
->w
- ob_rr_theme
->bwidth
;
373 case OB_DIRECTION_EAST
:
374 dock
->x
+= dock
->w
- ob_rr_theme
->bwidth
;
376 case OB_DIRECTION_SOUTHWEST
:
377 switch (config_dock_orient
) {
378 case OB_ORIENTATION_HORZ
:
379 dock
->y
+= dock
->h
- ob_rr_theme
->bwidth
;
381 case OB_ORIENTATION_VERT
:
382 dock
->x
-= dock
->w
- ob_rr_theme
->bwidth
;
385 case OB_DIRECTION_SOUTH
:
386 dock
->y
+= dock
->h
- ob_rr_theme
->bwidth
;
388 case OB_DIRECTION_SOUTHEAST
:
389 switch (config_dock_orient
) {
390 case OB_ORIENTATION_HORZ
:
391 dock
->y
+= dock
->h
- ob_rr_theme
->bwidth
;
393 case OB_ORIENTATION_VERT
:
394 dock
->x
+= dock
->w
- ob_rr_theme
->bwidth
;
402 if (!config_dock_floating
&& config_dock_hide
) {
403 strw
= ob_rr_theme
->bwidth
;
404 strh
= ob_rr_theme
->bwidth
;
411 if (!dock
->dock_apps
) {
412 STRUT_PARTIAL_SET(dock_strut
, 0, 0, 0, 0,
413 0, 0, 0, 0, 0, 0, 0, 0);
414 } else if (config_dock_floating
|| config_dock_nostrut
) {
415 STRUT_PARTIAL_SET(dock_strut
, 0, 0, 0, 0,
416 0, 0, 0, 0, 0, 0, 0, 0);
418 switch (config_dock_pos
) {
419 case OB_DIRECTION_NORTHWEST
:
420 switch (config_dock_orient
) {
421 case OB_ORIENTATION_HORZ
:
422 STRUT_PARTIAL_SET(dock_strut
, 0, strh
, 0, 0,
423 0, 0, dock
->x
, dock
->x
+ dock
->w
- 1,
426 case OB_ORIENTATION_VERT
:
427 STRUT_PARTIAL_SET(dock_strut
, strw
, 0, 0, 0,
428 dock
->y
, dock
->y
+ dock
->h
- 1,
433 case OB_DIRECTION_NORTH
:
434 STRUT_PARTIAL_SET(dock_strut
, 0, strh
, 0, 0,
435 dock
->x
, dock
->x
+ dock
->w
- 1,
438 case OB_DIRECTION_NORTHEAST
:
439 switch (config_dock_orient
) {
440 case OB_ORIENTATION_HORZ
:
441 STRUT_PARTIAL_SET(dock_strut
, 0, strh
, 0, 0,
442 0, 0, dock
->x
, dock
->x
+ dock
->w
-1,
445 case OB_ORIENTATION_VERT
:
446 STRUT_PARTIAL_SET(dock_strut
, 0, 0, strw
, 0,
448 dock
->y
, dock
->y
+ dock
->h
- 1, 0, 0);
452 case OB_DIRECTION_WEST
:
453 STRUT_PARTIAL_SET(dock_strut
, strw
, 0, 0, 0,
454 dock
->y
, dock
->y
+ dock
->h
- 1,
457 case OB_DIRECTION_EAST
:
458 STRUT_PARTIAL_SET(dock_strut
, 0, 0, strw
, 0,
460 dock
->y
, dock
->y
+ dock
->h
- 1, 0, 0);
462 case OB_DIRECTION_SOUTHWEST
:
463 switch (config_dock_orient
) {
464 case OB_ORIENTATION_HORZ
:
465 STRUT_PARTIAL_SET(dock_strut
, 0, 0, 0, strh
,
467 dock
->x
, dock
->x
+ dock
->w
- 1);
469 case OB_ORIENTATION_VERT
:
470 STRUT_PARTIAL_SET(dock_strut
, strw
, 0, 0, 0,
471 dock
->y
, dock
->y
+ dock
->h
- 1,
476 case OB_DIRECTION_SOUTH
:
477 STRUT_PARTIAL_SET(dock_strut
, 0, 0, 0, strh
,
479 dock
->x
, dock
->x
+ dock
->w
- 1);
481 case OB_DIRECTION_SOUTHEAST
:
482 switch (config_dock_orient
) {
483 case OB_ORIENTATION_HORZ
:
484 STRUT_PARTIAL_SET(dock_strut
, 0, 0, 0, strh
,
486 dock
->x
, dock
->x
+ dock
->w
- 1);
488 case OB_ORIENTATION_VERT
:
489 STRUT_PARTIAL_SET(dock_strut
, 0, 0, strw
, 0,
491 dock
->y
, dock
->y
+ dock
->h
- 1, 0, 0);
501 /* not used for actually sizing shit */
502 dock
->w
-= ob_rr_theme
->bwidth
* 2;
503 dock
->h
-= ob_rr_theme
->bwidth
* 2;
505 if (dock
->dock_apps
) {
506 g_assert(dock
->w
> 0);
507 g_assert(dock
->h
> 0);
509 XMoveResizeWindow(ob_display
, dock
->frame
,
510 dock
->x
, dock
->y
, dock
->w
, dock
->h
);
512 RrPaint(dock
->a_frame
, dock
->frame
, dock
->w
, dock
->h
);
513 XMapWindow(ob_display
, dock
->frame
);
515 XUnmapWindow(ob_display
, dock
->frame
);
517 /* but they are useful outside of this function! */
518 dock
->w
+= ob_rr_theme
->bwidth
* 2;
519 dock
->h
+= ob_rr_theme
->bwidth
* 2;
521 screen_update_areas();
524 void dock_app_configure(ObDockApp
*app
, gint w
, gint h
)
531 void dock_app_drag(ObDockApp
*app
, XMotionEvent
*e
)
533 ObDockApp
*over
= NULL
;
542 /* are we on top of the dock? */
543 if (!(x
>= dock
->x
&&
545 x
< dock
->x
+ dock
->w
&&
546 y
< dock
->y
+ dock
->h
))
552 /* which dock app are we on top of? */
554 for (it
= dock
->dock_apps
; it
; it
= g_list_next(it
)) {
556 switch (config_dock_orient
) {
557 case OB_ORIENTATION_HORZ
:
558 if (x
>= over
->x
&& x
< over
->x
+ over
->w
)
561 case OB_ORIENTATION_VERT
:
562 if (y
>= over
->y
&& y
< over
->y
+ over
->h
)
566 /* dont go to it->next! */
569 if (!it
|| app
== over
) return;
574 switch (config_dock_orient
) {
575 case OB_ORIENTATION_HORZ
:
576 after
= (x
> over
->w
/ 2);
578 case OB_ORIENTATION_VERT
:
579 after
= (y
> over
->h
/ 2);
583 /* remove before doing the it->next! */
584 dock
->dock_apps
= g_list_remove(dock
->dock_apps
, app
);
586 if (after
) it
= it
->next
;
588 dock
->dock_apps
= g_list_insert_before(dock
->dock_apps
, it
, app
);
592 static gboolean
hide_timeout(gpointer data
)
598 return FALSE
; /* don't repeat */
601 static gboolean
show_timeout(gpointer data
)
604 dock
->hidden
= FALSE
;
607 return FALSE
; /* don't repeat */
610 void dock_hide(gboolean hide
)
613 if (dock
->hidden
&& config_dock_hide
) {
614 ob_main_loop_timeout_add(ob_main_loop
, config_dock_show_delay
,
615 show_timeout
, NULL
, NULL
);
616 } else if (!dock
->hidden
&& config_dock_hide
) {
617 ob_main_loop_timeout_remove(ob_main_loop
, hide_timeout
);
620 if (!dock
->hidden
&& config_dock_hide
) {
621 ob_main_loop_timeout_add(ob_main_loop
, config_dock_hide_delay
,
622 hide_timeout
, NULL
, NULL
);
623 } else if (dock
->hidden
&& config_dock_hide
) {
624 ob_main_loop_timeout_remove(ob_main_loop
, show_timeout
);