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 void dock_startup(gboolean reconfig
)
39 XSetWindowAttributes attrib
;
42 XSetWindowBorder(ob_display
, dock
->frame
,
43 RrColorPixel(ob_rr_theme
->b_color
));
44 XSetWindowBorderWidth(ob_display
, dock
->frame
, ob_rr_theme
->bwidth
);
46 RrAppearanceFree(dock
->a_frame
);
47 dock
->a_frame
= RrAppearanceCopy(ob_rr_theme
->a_unfocused_title
);
49 stacking_add(DOCK_AS_WINDOW(dock
));
56 STRUT_PARTIAL_SET(dock_strut
, 0, 0, 0, 0,
57 0, 0, 0, 0, 0, 0, 0, 0);
59 dock
= g_new0(ObDock
, 1);
60 dock
->obwin
.type
= Window_Dock
;
64 attrib
.event_mask
= DOCK_EVENT_MASK
;
65 attrib
.override_redirect
= True
;
66 dock
->frame
= XCreateWindow(ob_display
, RootWindow(ob_display
, ob_screen
),
68 RrDepth(ob_rr_inst
), InputOutput
,
70 CWOverrideRedirect
| CWEventMask
,
72 dock
->a_frame
= RrAppearanceCopy(ob_rr_theme
->a_unfocused_title
);
73 XSetWindowBorder(ob_display
, dock
->frame
,
74 RrColorPixel(ob_rr_theme
->b_color
));
75 XSetWindowBorderWidth(ob_display
, dock
->frame
, ob_rr_theme
->bwidth
);
77 g_hash_table_insert(window_map
, &dock
->frame
, dock
);
78 stacking_add(DOCK_AS_WINDOW(dock
));
81 void dock_shutdown(gboolean reconfig
)
84 stacking_remove(DOCK_AS_WINDOW(dock
));
88 XDestroyWindow(ob_display
, dock
->frame
);
89 RrAppearanceFree(dock
->a_frame
);
90 g_hash_table_remove(window_map
, &dock
->frame
);
91 stacking_remove(dock
);
94 void dock_add(Window win
, XWMHints
*wmhints
)
97 XWindowAttributes attrib
;
100 app
= g_new0(ObDockApp
, 1);
101 app
->obwin
.type
= Window_DockApp
;
103 app
->icon_win
= (wmhints
->flags
& IconWindowHint
) ?
104 wmhints
->icon_window
: win
;
106 if (PROP_GETSS(app
->win
, wm_class
, locale
, &data
)) {
108 app
->name
= g_strdup(data
[0]);
110 app
->class = g_strdup(data
[1]);
115 if (app
->name
== NULL
) app
->name
= g_strdup("");
116 if (app
->class == NULL
) app
->class = g_strdup("");
118 if (XGetWindowAttributes(ob_display
, app
->icon_win
, &attrib
)) {
119 app
->w
= attrib
.width
;
120 app
->h
= attrib
.height
;
122 app
->w
= app
->h
= 64;
125 dock
->dock_apps
= g_list_append(dock
->dock_apps
, app
);
128 XReparentWindow(ob_display
, app
->icon_win
, dock
->frame
, app
->x
, app
->y
);
130 This is the same case as in frame.c for client windows. When Openbox is
131 starting, the window is already mapped so we see unmap events occur for
132 it. There are 2 unmap events generated that we see, one with the 'event'
133 member set the root window, and one set to the client, but both get
134 handled and need to be ignored.
136 if (ob_state() == OB_STATE_STARTING
)
137 app
->ignore_unmaps
+= 2;
139 if (app
->win
!= app
->icon_win
) {
140 /* have to map it so that it can be re-managed on a restart */
141 XMoveWindow(ob_display
, app
->win
, -1000, -1000);
142 XMapWindow(ob_display
, app
->win
);
144 XMapWindow(ob_display
, app
->icon_win
);
145 XSync(ob_display
, False
);
147 /* specify that if we exit, the window should not be destroyed and should
148 be reparented back to root automatically */
149 XChangeSaveSet(ob_display
, app
->icon_win
, SetModeInsert
);
150 XSelectInput(ob_display
, app
->icon_win
, DOCKAPP_EVENT_MASK
);
152 grab_button_full(2, 0, app
->icon_win
,
153 ButtonPressMask
| ButtonReleaseMask
| ButtonMotionMask
,
154 GrabModeAsync
, OB_CURSOR_MOVE
);
156 g_hash_table_insert(window_map
, &app
->icon_win
, app
);
158 ob_debug("Managed Dock App: 0x%lx (%s)\n", app
->icon_win
, app
->class);
161 void dock_remove_all()
163 while (dock
->dock_apps
)
164 dock_remove(dock
->dock_apps
->data
, TRUE
);
167 void dock_remove(ObDockApp
*app
, gboolean reparent
)
169 ungrab_button(2, 0, app
->icon_win
);
170 XSelectInput(ob_display
, app
->icon_win
, NoEventMask
);
171 /* remove the window from our save set */
172 XChangeSaveSet(ob_display
, app
->icon_win
, SetModeDelete
);
173 XSync(ob_display
, False
);
175 g_hash_table_remove(window_map
, &app
->icon_win
);
178 XReparentWindow(ob_display
, app
->icon_win
,
179 RootWindow(ob_display
, ob_screen
), app
->x
, app
->y
);
181 dock
->dock_apps
= g_list_remove(dock
->dock_apps
, app
);
184 ob_debug("Unmanaged Dock App: 0x%lx (%s)\n", app
->icon_win
, app
->class);
191 void dock_configure()
200 RrMinsize(dock
->a_frame
, &minw
, &minh
);
202 dock
->w
= dock
->h
= 0;
205 for (it
= dock
->dock_apps
; it
; it
= it
->next
) {
206 ObDockApp
*app
= it
->data
;
207 switch (config_dock_orient
) {
208 case OB_ORIENTATION_HORZ
:
210 dock
->h
= MAX(dock
->h
, app
->h
);
212 case OB_ORIENTATION_VERT
:
213 dock
->w
= MAX(dock
->w
, app
->w
);
219 spot
= (config_dock_orient
== OB_ORIENTATION_HORZ
? minw
: minh
) / 2;
221 /* position the apps */
222 for (it
= dock
->dock_apps
; it
; it
= it
->next
) {
223 ObDockApp
*app
= it
->data
;
224 switch (config_dock_orient
) {
225 case OB_ORIENTATION_HORZ
:
227 app
->y
= (dock
->h
- app
->h
) / 2;
230 case OB_ORIENTATION_VERT
:
231 app
->x
= (dock
->w
- app
->w
) / 2;
237 XMoveWindow(ob_display
, app
->icon_win
, app
->x
, app
->y
);
240 /* used for calculating offsets */
241 dock
->w
+= ob_rr_theme
->bwidth
* 2;
242 dock
->h
+= ob_rr_theme
->bwidth
* 2;
244 a
= screen_physical_area();
246 /* calculate position */
247 if (config_dock_floating
) {
248 dock
->x
= config_dock_x
;
249 dock
->y
= config_dock_y
;
250 gravity
= NorthWestGravity
;
252 switch (config_dock_pos
) {
253 case OB_DIRECTION_NORTHWEST
:
256 gravity
= NorthWestGravity
;
258 case OB_DIRECTION_NORTH
:
259 dock
->x
= a
->width
/ 2;
261 gravity
= NorthGravity
;
263 case OB_DIRECTION_NORTHEAST
:
266 gravity
= NorthEastGravity
;
268 case OB_DIRECTION_WEST
:
270 dock
->y
= a
->height
/ 2;
271 gravity
= WestGravity
;
273 case OB_DIRECTION_EAST
:
275 dock
->y
= a
->height
/ 2;
276 gravity
= EastGravity
;
278 case OB_DIRECTION_SOUTHWEST
:
281 gravity
= SouthWestGravity
;
283 case OB_DIRECTION_SOUTH
:
284 dock
->x
= a
->width
/ 2;
286 gravity
= SouthGravity
;
288 case OB_DIRECTION_SOUTHEAST
:
291 gravity
= SouthEastGravity
;
300 dock
->x
-= dock
->w
/ 2;
302 case NorthEastGravity
:
304 case SouthEastGravity
:
312 dock
->y
-= dock
->h
/ 2;
314 case SouthWestGravity
:
316 case SouthEastGravity
:
321 if (config_dock_hide
&& dock
->hidden
) {
322 if (!config_dock_floating
) {
323 switch (config_dock_pos
) {
324 case OB_DIRECTION_NORTHWEST
:
325 switch (config_dock_orient
) {
326 case OB_ORIENTATION_HORZ
:
327 dock
->y
-= dock
->h
- ob_rr_theme
->bwidth
;
329 case OB_ORIENTATION_VERT
:
330 dock
->x
-= dock
->w
- ob_rr_theme
->bwidth
;
334 case OB_DIRECTION_NORTH
:
335 dock
->y
-= dock
->h
- ob_rr_theme
->bwidth
;
337 case OB_DIRECTION_NORTHEAST
:
338 switch (config_dock_orient
) {
339 case OB_ORIENTATION_HORZ
:
340 dock
->y
-= dock
->h
- ob_rr_theme
->bwidth
;
342 case OB_ORIENTATION_VERT
:
343 dock
->x
+= dock
->w
- ob_rr_theme
->bwidth
;
347 case OB_DIRECTION_WEST
:
348 dock
->x
-= dock
->w
- ob_rr_theme
->bwidth
;
350 case OB_DIRECTION_EAST
:
351 dock
->x
+= dock
->w
- ob_rr_theme
->bwidth
;
353 case OB_DIRECTION_SOUTHWEST
:
354 switch (config_dock_orient
) {
355 case OB_ORIENTATION_HORZ
:
356 dock
->y
+= dock
->h
- ob_rr_theme
->bwidth
;
358 case OB_ORIENTATION_VERT
:
359 dock
->x
-= dock
->w
- ob_rr_theme
->bwidth
;
362 case OB_DIRECTION_SOUTH
:
363 dock
->y
+= dock
->h
- ob_rr_theme
->bwidth
;
365 case OB_DIRECTION_SOUTHEAST
:
366 switch (config_dock_orient
) {
367 case OB_ORIENTATION_HORZ
:
368 dock
->y
+= dock
->h
- ob_rr_theme
->bwidth
;
370 case OB_ORIENTATION_VERT
:
371 dock
->x
+= dock
->w
- ob_rr_theme
->bwidth
;
379 if (!config_dock_floating
&& config_dock_hide
) {
380 strw
= ob_rr_theme
->bwidth
;
381 strh
= ob_rr_theme
->bwidth
;
388 if (!dock
->dock_apps
) {
389 STRUT_PARTIAL_SET(dock_strut
, 0, 0, 0, 0,
390 0, 0, 0, 0, 0, 0, 0, 0);
391 } else if (config_dock_floating
) {
392 STRUT_PARTIAL_SET(dock_strut
, 0, 0, 0, 0,
393 0, 0, 0, 0, 0, 0, 0, 0);
395 switch (config_dock_pos
) {
396 case OB_DIRECTION_NORTHWEST
:
397 switch (config_dock_orient
) {
398 case OB_ORIENTATION_HORZ
:
399 STRUT_PARTIAL_SET(dock_strut
, 0, strh
, 0, 0,
400 0, 0, dock
->x
, dock
->x
+ dock
->w
- 1,
403 case OB_ORIENTATION_VERT
:
404 STRUT_PARTIAL_SET(dock_strut
, strw
, 0, 0, 0,
405 dock
->y
, dock
->y
+ dock
->h
- 1,
410 case OB_DIRECTION_NORTH
:
411 STRUT_PARTIAL_SET(dock_strut
, 0, strh
, 0, 0,
412 dock
->x
, dock
->x
+ dock
->w
- 1,
415 case OB_DIRECTION_NORTHEAST
:
416 switch (config_dock_orient
) {
417 case OB_ORIENTATION_HORZ
:
418 STRUT_PARTIAL_SET(dock_strut
, 0, strh
, 0, 0,
419 0, 0, dock
->x
, dock
->x
+ dock
->w
-1,
422 case OB_ORIENTATION_VERT
:
423 STRUT_PARTIAL_SET(dock_strut
, 0, 0, strw
, 0,
425 dock
->y
, dock
->y
+ dock
->h
- 1, 0, 0);
429 case OB_DIRECTION_WEST
:
430 STRUT_PARTIAL_SET(dock_strut
, strw
, 0, 0, 0,
431 dock
->y
, dock
->y
+ dock
->h
- 1,
434 case OB_DIRECTION_EAST
:
435 STRUT_PARTIAL_SET(dock_strut
, 0, 0, strw
, 0,
437 dock
->y
, dock
->y
+ dock
->h
- 1, 0, 0);
439 case OB_DIRECTION_SOUTHWEST
:
440 switch (config_dock_orient
) {
441 case OB_ORIENTATION_HORZ
:
442 STRUT_PARTIAL_SET(dock_strut
, 0, 0, 0, strh
,
444 dock
->x
, dock
->x
+ dock
->w
- 1);
446 case OB_ORIENTATION_VERT
:
447 STRUT_PARTIAL_SET(dock_strut
, strw
, 0, 0, 0,
448 dock
->y
, dock
->y
+ dock
->h
- 1,
453 case OB_DIRECTION_SOUTH
:
454 STRUT_PARTIAL_SET(dock_strut
, 0, 0, 0, strh
,
456 dock
->x
, dock
->x
+ dock
->w
- 1);
458 case OB_DIRECTION_SOUTHEAST
:
459 switch (config_dock_orient
) {
460 case OB_ORIENTATION_HORZ
:
461 STRUT_PARTIAL_SET(dock_strut
, 0, 0, 0, strh
,
463 dock
->x
, dock
->x
+ dock
->w
- 1);
465 case OB_ORIENTATION_VERT
:
466 STRUT_PARTIAL_SET(dock_strut
, 0, 0, strw
, 0,
468 dock
->y
, dock
->y
+ dock
->h
- 1, 0, 0);
478 /* not used for actually sizing shit */
479 dock
->w
-= ob_rr_theme
->bwidth
* 2;
480 dock
->h
-= ob_rr_theme
->bwidth
* 2;
482 if (dock
->dock_apps
) {
483 g_assert(dock
->w
> 0);
484 g_assert(dock
->h
> 0);
486 XMoveResizeWindow(ob_display
, dock
->frame
,
487 dock
->x
, dock
->y
, dock
->w
, dock
->h
);
489 RrPaint(dock
->a_frame
, dock
->frame
, dock
->w
, dock
->h
);
490 XMapWindow(ob_display
, dock
->frame
);
492 XUnmapWindow(ob_display
, dock
->frame
);
494 /* but they are useful outside of this function! */
495 dock
->w
+= ob_rr_theme
->bwidth
* 2;
496 dock
->h
+= ob_rr_theme
->bwidth
* 2;
498 screen_update_areas();
501 void dock_app_configure(ObDockApp
*app
, gint w
, gint h
)
508 void dock_app_drag(ObDockApp
*app
, XMotionEvent
*e
)
510 ObDockApp
*over
= NULL
;
519 /* are we on top of the dock? */
520 if (!(x
>= dock
->x
&&
522 x
< dock
->x
+ dock
->w
&&
523 y
< dock
->y
+ dock
->h
))
529 /* which dock app are we on top of? */
531 for (it
= dock
->dock_apps
; it
; it
= it
->next
) {
533 switch (config_dock_orient
) {
534 case OB_ORIENTATION_HORZ
:
535 if (x
>= over
->x
&& x
< over
->x
+ over
->w
)
538 case OB_ORIENTATION_VERT
:
539 if (y
>= over
->y
&& y
< over
->y
+ over
->h
)
543 /* dont go to it->next! */
546 if (!it
|| app
== over
) return;
551 switch (config_dock_orient
) {
552 case OB_ORIENTATION_HORZ
:
553 after
= (x
> over
->w
/ 2);
555 case OB_ORIENTATION_VERT
:
556 after
= (y
> over
->h
/ 2);
560 /* remove before doing the it->next! */
561 dock
->dock_apps
= g_list_remove(dock
->dock_apps
, app
);
563 if (after
) it
= it
->next
;
565 dock
->dock_apps
= g_list_insert_before(dock
->dock_apps
, it
, app
);
569 static gboolean
hide_timeout(gpointer data
)
575 return FALSE
; /* don't repeat */
578 void dock_hide(gboolean hide
)
582 dock
->hidden
= FALSE
;
585 /* if was hiding, stop it */
586 ob_main_loop_timeout_remove(ob_main_loop
, hide_timeout
);
587 } else if (!dock
->hidden
&& config_dock_hide
) {
588 ob_main_loop_timeout_add(ob_main_loop
, config_dock_hide_delay
,
589 hide_timeout
, NULL
, NULL
);