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 static void dock_app_grab_button(ObDockApp
*app
, gboolean grab
)
40 grab_button_full(config_dock_app_move_button
,
41 config_dock_app_move_modifiers
, app
->icon_win
,
42 ButtonPressMask
| ButtonReleaseMask
|
44 GrabModeAsync
, OB_CURSOR_MOVE
);
46 ungrab_button(config_dock_app_move_button
,
47 config_dock_app_move_modifiers
, app
->icon_win
);
51 void dock_startup(gboolean reconfig
)
53 XSetWindowAttributes attrib
;
58 XSetWindowBorder(ob_display
, dock
->frame
,
59 RrColorPixel(ob_rr_theme
->b_color
));
60 XSetWindowBorderWidth(ob_display
, dock
->frame
, ob_rr_theme
->bwidth
);
62 RrAppearanceFree(dock
->a_frame
);
63 dock
->a_frame
= RrAppearanceCopy(ob_rr_theme
->a_unfocused_title
);
65 stacking_add(DOCK_AS_WINDOW(dock
));
70 for (it
= dock
->dock_apps
; it
; it
= g_list_next(it
))
71 dock_app_grab_button(it
->data
, TRUE
);
75 STRUT_PARTIAL_SET(dock_strut
, 0, 0, 0, 0,
76 0, 0, 0, 0, 0, 0, 0, 0);
78 dock
= g_new0(ObDock
, 1);
79 dock
->obwin
.type
= Window_Dock
;
83 attrib
.event_mask
= DOCK_EVENT_MASK
;
84 attrib
.override_redirect
= True
;
85 dock
->frame
= XCreateWindow(ob_display
, RootWindow(ob_display
, ob_screen
),
87 RrDepth(ob_rr_inst
), InputOutput
,
89 CWOverrideRedirect
| CWEventMask
,
91 dock
->a_frame
= RrAppearanceCopy(ob_rr_theme
->a_unfocused_title
);
92 XSetWindowBorder(ob_display
, dock
->frame
,
93 RrColorPixel(ob_rr_theme
->b_color
));
94 XSetWindowBorderWidth(ob_display
, dock
->frame
, ob_rr_theme
->bwidth
);
96 g_hash_table_insert(window_map
, &dock
->frame
, dock
);
97 stacking_add(DOCK_AS_WINDOW(dock
));
100 void dock_shutdown(gboolean reconfig
)
105 stacking_remove(DOCK_AS_WINDOW(dock
));
107 for (it
= dock
->dock_apps
; it
; it
= g_list_next(it
))
108 dock_app_grab_button(it
->data
, FALSE
);
112 XDestroyWindow(ob_display
, dock
->frame
);
113 RrAppearanceFree(dock
->a_frame
);
114 g_hash_table_remove(window_map
, &dock
->frame
);
115 stacking_remove(dock
);
118 void dock_add(Window win
, XWMHints
*wmhints
)
121 XWindowAttributes attrib
;
124 app
= g_new0(ObDockApp
, 1);
125 app
->obwin
.type
= Window_DockApp
;
127 app
->icon_win
= (wmhints
->flags
& IconWindowHint
) ?
128 wmhints
->icon_window
: win
;
130 if (PROP_GETSS(app
->win
, wm_class
, locale
, &data
)) {
132 app
->name
= g_strdup(data
[0]);
134 app
->class = g_strdup(data
[1]);
139 if (app
->name
== NULL
) app
->name
= g_strdup("");
140 if (app
->class == NULL
) app
->class = g_strdup("");
142 if (XGetWindowAttributes(ob_display
, app
->icon_win
, &attrib
)) {
143 app
->w
= attrib
.width
;
144 app
->h
= attrib
.height
;
146 app
->w
= app
->h
= 64;
149 dock
->dock_apps
= g_list_append(dock
->dock_apps
, app
);
152 XReparentWindow(ob_display
, app
->icon_win
, dock
->frame
, app
->x
, app
->y
);
154 This is the same case as in frame.c for client windows. When Openbox is
155 starting, the window is already mapped so we see unmap events occur for
156 it. There are 2 unmap events generated that we see, one with the 'event'
157 member set the root window, and one set to the client, but both get
158 handled and need to be ignored.
160 if (ob_state() == OB_STATE_STARTING
)
161 app
->ignore_unmaps
+= 2;
163 if (app
->win
!= app
->icon_win
) {
164 /* have to map it so that it can be re-managed on a restart */
165 XMoveWindow(ob_display
, app
->win
, -1000, -1000);
166 XMapWindow(ob_display
, app
->win
);
168 XMapWindow(ob_display
, app
->icon_win
);
169 XSync(ob_display
, False
);
171 /* specify that if we exit, the window should not be destroyed and should
172 be reparented back to root automatically */
173 XChangeSaveSet(ob_display
, app
->icon_win
, SetModeInsert
);
174 XSelectInput(ob_display
, app
->icon_win
, DOCKAPP_EVENT_MASK
);
176 dock_app_grab_button(app
, TRUE
);
178 g_hash_table_insert(window_map
, &app
->icon_win
, app
);
180 ob_debug("Managed Dock App: 0x%lx (%s)\n", app
->icon_win
, app
->class);
183 void dock_remove_all()
185 while (dock
->dock_apps
)
186 dock_remove(dock
->dock_apps
->data
, TRUE
);
189 void dock_remove(ObDockApp
*app
, gboolean reparent
)
191 dock_app_grab_button(app
, FALSE
);
192 XSelectInput(ob_display
, app
->icon_win
, NoEventMask
);
193 /* remove the window from our save set */
194 XChangeSaveSet(ob_display
, app
->icon_win
, SetModeDelete
);
195 XSync(ob_display
, False
);
197 g_hash_table_remove(window_map
, &app
->icon_win
);
200 XReparentWindow(ob_display
, app
->icon_win
,
201 RootWindow(ob_display
, ob_screen
), app
->x
, app
->y
);
203 dock
->dock_apps
= g_list_remove(dock
->dock_apps
, app
);
206 ob_debug("Unmanaged Dock App: 0x%lx (%s)\n", app
->icon_win
, app
->class);
213 void dock_configure()
222 RrMinsize(dock
->a_frame
, &minw
, &minh
);
224 dock
->w
= dock
->h
= 0;
227 for (it
= dock
->dock_apps
; it
; it
= g_list_next(it
)) {
228 ObDockApp
*app
= it
->data
;
229 switch (config_dock_orient
) {
230 case OB_ORIENTATION_HORZ
:
232 dock
->h
= MAX(dock
->h
, app
->h
);
234 case OB_ORIENTATION_VERT
:
235 dock
->w
= MAX(dock
->w
, app
->w
);
241 spot
= (config_dock_orient
== OB_ORIENTATION_HORZ
? minw
: minh
) / 2;
243 /* position the apps */
244 for (it
= dock
->dock_apps
; it
; it
= g_list_next(it
)) {
245 ObDockApp
*app
= it
->data
;
246 switch (config_dock_orient
) {
247 case OB_ORIENTATION_HORZ
:
249 app
->y
= (dock
->h
- app
->h
) / 2;
252 case OB_ORIENTATION_VERT
:
253 app
->x
= (dock
->w
- app
->w
) / 2;
259 XMoveWindow(ob_display
, app
->icon_win
, app
->x
, app
->y
);
262 /* used for calculating offsets */
263 dock
->w
+= ob_rr_theme
->bwidth
* 2;
264 dock
->h
+= ob_rr_theme
->bwidth
* 2;
266 a
= screen_physical_area();
268 /* calculate position */
269 if (config_dock_floating
) {
270 dock
->x
= config_dock_x
;
271 dock
->y
= config_dock_y
;
272 gravity
= NorthWestGravity
;
274 switch (config_dock_pos
) {
275 case OB_DIRECTION_NORTHWEST
:
278 gravity
= NorthWestGravity
;
280 case OB_DIRECTION_NORTH
:
281 dock
->x
= a
->width
/ 2;
283 gravity
= NorthGravity
;
285 case OB_DIRECTION_NORTHEAST
:
288 gravity
= NorthEastGravity
;
290 case OB_DIRECTION_WEST
:
292 dock
->y
= a
->height
/ 2;
293 gravity
= WestGravity
;
295 case OB_DIRECTION_EAST
:
297 dock
->y
= a
->height
/ 2;
298 gravity
= EastGravity
;
300 case OB_DIRECTION_SOUTHWEST
:
303 gravity
= SouthWestGravity
;
305 case OB_DIRECTION_SOUTH
:
306 dock
->x
= a
->width
/ 2;
308 gravity
= SouthGravity
;
310 case OB_DIRECTION_SOUTHEAST
:
313 gravity
= SouthEastGravity
;
322 dock
->x
-= dock
->w
/ 2;
324 case NorthEastGravity
:
326 case SouthEastGravity
:
334 dock
->y
-= dock
->h
/ 2;
336 case SouthWestGravity
:
338 case SouthEastGravity
:
343 if (config_dock_hide
&& dock
->hidden
) {
344 if (!config_dock_floating
) {
345 switch (config_dock_pos
) {
346 case OB_DIRECTION_NORTHWEST
:
347 switch (config_dock_orient
) {
348 case OB_ORIENTATION_HORZ
:
349 dock
->y
-= dock
->h
- ob_rr_theme
->bwidth
;
351 case OB_ORIENTATION_VERT
:
352 dock
->x
-= dock
->w
- ob_rr_theme
->bwidth
;
356 case OB_DIRECTION_NORTH
:
357 dock
->y
-= dock
->h
- ob_rr_theme
->bwidth
;
359 case OB_DIRECTION_NORTHEAST
:
360 switch (config_dock_orient
) {
361 case OB_ORIENTATION_HORZ
:
362 dock
->y
-= dock
->h
- ob_rr_theme
->bwidth
;
364 case OB_ORIENTATION_VERT
:
365 dock
->x
+= dock
->w
- ob_rr_theme
->bwidth
;
369 case OB_DIRECTION_WEST
:
370 dock
->x
-= dock
->w
- ob_rr_theme
->bwidth
;
372 case OB_DIRECTION_EAST
:
373 dock
->x
+= dock
->w
- ob_rr_theme
->bwidth
;
375 case OB_DIRECTION_SOUTHWEST
:
376 switch (config_dock_orient
) {
377 case OB_ORIENTATION_HORZ
:
378 dock
->y
+= dock
->h
- ob_rr_theme
->bwidth
;
380 case OB_ORIENTATION_VERT
:
381 dock
->x
-= dock
->w
- ob_rr_theme
->bwidth
;
384 case OB_DIRECTION_SOUTH
:
385 dock
->y
+= dock
->h
- ob_rr_theme
->bwidth
;
387 case OB_DIRECTION_SOUTHEAST
:
388 switch (config_dock_orient
) {
389 case OB_ORIENTATION_HORZ
:
390 dock
->y
+= dock
->h
- ob_rr_theme
->bwidth
;
392 case OB_ORIENTATION_VERT
:
393 dock
->x
+= dock
->w
- ob_rr_theme
->bwidth
;
401 if (!config_dock_floating
&& config_dock_hide
) {
402 strw
= ob_rr_theme
->bwidth
;
403 strh
= ob_rr_theme
->bwidth
;
410 if (!dock
->dock_apps
) {
411 STRUT_PARTIAL_SET(dock_strut
, 0, 0, 0, 0,
412 0, 0, 0, 0, 0, 0, 0, 0);
413 } else if (config_dock_floating
) {
414 STRUT_PARTIAL_SET(dock_strut
, 0, 0, 0, 0,
415 0, 0, 0, 0, 0, 0, 0, 0);
417 switch (config_dock_pos
) {
418 case OB_DIRECTION_NORTHWEST
:
419 switch (config_dock_orient
) {
420 case OB_ORIENTATION_HORZ
:
421 STRUT_PARTIAL_SET(dock_strut
, 0, strh
, 0, 0,
422 0, 0, dock
->x
, dock
->x
+ dock
->w
- 1,
425 case OB_ORIENTATION_VERT
:
426 STRUT_PARTIAL_SET(dock_strut
, strw
, 0, 0, 0,
427 dock
->y
, dock
->y
+ dock
->h
- 1,
432 case OB_DIRECTION_NORTH
:
433 STRUT_PARTIAL_SET(dock_strut
, 0, strh
, 0, 0,
434 dock
->x
, dock
->x
+ dock
->w
- 1,
437 case OB_DIRECTION_NORTHEAST
:
438 switch (config_dock_orient
) {
439 case OB_ORIENTATION_HORZ
:
440 STRUT_PARTIAL_SET(dock_strut
, 0, strh
, 0, 0,
441 0, 0, dock
->x
, dock
->x
+ dock
->w
-1,
444 case OB_ORIENTATION_VERT
:
445 STRUT_PARTIAL_SET(dock_strut
, 0, 0, strw
, 0,
447 dock
->y
, dock
->y
+ dock
->h
- 1, 0, 0);
451 case OB_DIRECTION_WEST
:
452 STRUT_PARTIAL_SET(dock_strut
, strw
, 0, 0, 0,
453 dock
->y
, dock
->y
+ dock
->h
- 1,
456 case OB_DIRECTION_EAST
:
457 STRUT_PARTIAL_SET(dock_strut
, 0, 0, strw
, 0,
459 dock
->y
, dock
->y
+ dock
->h
- 1, 0, 0);
461 case OB_DIRECTION_SOUTHWEST
:
462 switch (config_dock_orient
) {
463 case OB_ORIENTATION_HORZ
:
464 STRUT_PARTIAL_SET(dock_strut
, 0, 0, 0, strh
,
466 dock
->x
, dock
->x
+ dock
->w
- 1);
468 case OB_ORIENTATION_VERT
:
469 STRUT_PARTIAL_SET(dock_strut
, strw
, 0, 0, 0,
470 dock
->y
, dock
->y
+ dock
->h
- 1,
475 case OB_DIRECTION_SOUTH
:
476 STRUT_PARTIAL_SET(dock_strut
, 0, 0, 0, strh
,
478 dock
->x
, dock
->x
+ dock
->w
- 1);
480 case OB_DIRECTION_SOUTHEAST
:
481 switch (config_dock_orient
) {
482 case OB_ORIENTATION_HORZ
:
483 STRUT_PARTIAL_SET(dock_strut
, 0, 0, 0, strh
,
485 dock
->x
, dock
->x
+ dock
->w
- 1);
487 case OB_ORIENTATION_VERT
:
488 STRUT_PARTIAL_SET(dock_strut
, 0, 0, strw
, 0,
490 dock
->y
, dock
->y
+ dock
->h
- 1, 0, 0);
500 /* not used for actually sizing shit */
501 dock
->w
-= ob_rr_theme
->bwidth
* 2;
502 dock
->h
-= ob_rr_theme
->bwidth
* 2;
504 if (dock
->dock_apps
) {
505 g_assert(dock
->w
> 0);
506 g_assert(dock
->h
> 0);
508 XMoveResizeWindow(ob_display
, dock
->frame
,
509 dock
->x
, dock
->y
, dock
->w
, dock
->h
);
511 RrPaint(dock
->a_frame
, dock
->frame
, dock
->w
, dock
->h
);
512 XMapWindow(ob_display
, dock
->frame
);
514 XUnmapWindow(ob_display
, dock
->frame
);
516 /* but they are useful outside of this function! */
517 dock
->w
+= ob_rr_theme
->bwidth
* 2;
518 dock
->h
+= ob_rr_theme
->bwidth
* 2;
520 screen_update_areas();
523 void dock_app_configure(ObDockApp
*app
, gint w
, gint h
)
530 void dock_app_drag(ObDockApp
*app
, XMotionEvent
*e
)
532 ObDockApp
*over
= NULL
;
541 /* are we on top of the dock? */
542 if (!(x
>= dock
->x
&&
544 x
< dock
->x
+ dock
->w
&&
545 y
< dock
->y
+ dock
->h
))
551 /* which dock app are we on top of? */
553 for (it
= dock
->dock_apps
; it
; it
= g_list_next(it
)) {
555 switch (config_dock_orient
) {
556 case OB_ORIENTATION_HORZ
:
557 if (x
>= over
->x
&& x
< over
->x
+ over
->w
)
560 case OB_ORIENTATION_VERT
:
561 if (y
>= over
->y
&& y
< over
->y
+ over
->h
)
565 /* dont go to it->next! */
568 if (!it
|| app
== over
) return;
573 switch (config_dock_orient
) {
574 case OB_ORIENTATION_HORZ
:
575 after
= (x
> over
->w
/ 2);
577 case OB_ORIENTATION_VERT
:
578 after
= (y
> over
->h
/ 2);
582 /* remove before doing the it->next! */
583 dock
->dock_apps
= g_list_remove(dock
->dock_apps
, app
);
585 if (after
) it
= it
->next
;
587 dock
->dock_apps
= g_list_insert_before(dock
->dock_apps
, it
, app
);
591 static gboolean
hide_timeout(gpointer data
)
597 return FALSE
; /* don't repeat */
600 void dock_hide(gboolean hide
)
604 dock
->hidden
= FALSE
;
607 /* if was hiding, stop it */
608 ob_main_loop_timeout_remove(ob_main_loop
, hide_timeout
);
609 } else if (!dock
->hidden
&& config_dock_hide
) {
610 ob_main_loop_timeout_add(ob_main_loop
, config_dock_hide_delay
,
611 hide_timeout
, NULL
, NULL
);