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
));
55 STRUT_PARTIAL_SET(dock_strut
, 0, 0, 0, 0,
56 0, 0, 0, 0, 0, 0, 0, 0);
58 dock
= g_new0(ObDock
, 1);
59 dock
->obwin
.type
= Window_Dock
;
63 attrib
.event_mask
= DOCK_EVENT_MASK
;
64 attrib
.override_redirect
= True
;
65 dock
->frame
= XCreateWindow(ob_display
, RootWindow(ob_display
, ob_screen
),
67 RrDepth(ob_rr_inst
), InputOutput
,
69 CWOverrideRedirect
| CWEventMask
,
71 dock
->a_frame
= RrAppearanceCopy(ob_rr_theme
->a_unfocused_title
);
72 XSetWindowBorder(ob_display
, dock
->frame
,
73 RrColorPixel(ob_rr_theme
->b_color
));
74 XSetWindowBorderWidth(ob_display
, dock
->frame
, ob_rr_theme
->bwidth
);
76 g_hash_table_insert(window_map
, &dock
->frame
, dock
);
77 stacking_add(DOCK_AS_WINDOW(dock
));
80 void dock_shutdown(gboolean reconfig
)
83 stacking_remove(DOCK_AS_WINDOW(dock
));
87 XDestroyWindow(ob_display
, dock
->frame
);
88 RrAppearanceFree(dock
->a_frame
);
89 g_hash_table_remove(window_map
, &dock
->frame
);
90 stacking_remove(dock
);
93 void dock_add(Window win
, XWMHints
*wmhints
)
96 XWindowAttributes attrib
;
99 app
= g_new0(ObDockApp
, 1);
100 app
->obwin
.type
= Window_DockApp
;
102 app
->icon_win
= (wmhints
->flags
& IconWindowHint
) ?
103 wmhints
->icon_window
: win
;
105 if (PROP_GETSS(app
->win
, wm_class
, locale
, &data
)) {
107 app
->name
= g_strdup(data
[0]);
109 app
->class = g_strdup(data
[1]);
114 if (app
->name
== NULL
) app
->name
= g_strdup("");
115 if (app
->class == NULL
) app
->class = g_strdup("");
117 if (XGetWindowAttributes(ob_display
, app
->icon_win
, &attrib
)) {
118 app
->w
= attrib
.width
;
119 app
->h
= attrib
.height
;
121 app
->w
= app
->h
= 64;
124 dock
->dock_apps
= g_list_append(dock
->dock_apps
, app
);
127 XReparentWindow(ob_display
, app
->icon_win
, dock
->frame
, app
->x
, app
->y
);
129 This is the same case as in frame.c for client windows. When Openbox is
130 starting, the window is already mapped so we see unmap events occur for
131 it. There are 2 unmap events generated that we see, one with the 'event'
132 member set the root window, and one set to the client, but both get
133 handled and need to be ignored.
135 if (ob_state() == OB_STATE_STARTING
)
136 app
->ignore_unmaps
+= 2;
138 if (app
->win
!= app
->icon_win
) {
139 /* have to map it so that it can be re-managed on a restart */
140 XMoveWindow(ob_display
, app
->win
, -1000, -1000);
141 XMapWindow(ob_display
, app
->win
);
143 XMapWindow(ob_display
, app
->icon_win
);
144 XSync(ob_display
, False
);
146 /* specify that if we exit, the window should not be destroyed and should
147 be reparented back to root automatically */
148 XChangeSaveSet(ob_display
, app
->icon_win
, SetModeInsert
);
149 XSelectInput(ob_display
, app
->icon_win
, DOCKAPP_EVENT_MASK
);
151 grab_button_full(2, 0, app
->icon_win
,
152 ButtonPressMask
| ButtonReleaseMask
| ButtonMotionMask
,
153 GrabModeAsync
, OB_CURSOR_MOVE
);
155 g_hash_table_insert(window_map
, &app
->icon_win
, app
);
157 ob_debug("Managed Dock App: 0x%lx (%s)\n", app
->icon_win
, app
->class);
160 void dock_remove_all()
162 while (dock
->dock_apps
)
163 dock_remove(dock
->dock_apps
->data
, TRUE
);
166 void dock_remove(ObDockApp
*app
, gboolean reparent
)
168 ungrab_button(2, 0, app
->icon_win
);
169 XSelectInput(ob_display
, app
->icon_win
, NoEventMask
);
170 /* remove the window from our save set */
171 XChangeSaveSet(ob_display
, app
->icon_win
, SetModeDelete
);
172 XSync(ob_display
, False
);
174 g_hash_table_remove(window_map
, &app
->icon_win
);
177 XReparentWindow(ob_display
, app
->icon_win
,
178 RootWindow(ob_display
, ob_screen
), app
->x
, app
->y
);
180 dock
->dock_apps
= g_list_remove(dock
->dock_apps
, app
);
183 ob_debug("Unmanaged Dock App: 0x%lx (%s)\n", app
->icon_win
, app
->class);
190 void dock_configure()
199 RrMinsize(dock
->a_frame
, &minw
, &minh
);
201 dock
->w
= dock
->h
= 0;
204 for (it
= dock
->dock_apps
; it
; it
= it
->next
) {
205 ObDockApp
*app
= it
->data
;
206 switch (config_dock_orient
) {
207 case OB_ORIENTATION_HORZ
:
209 dock
->h
= MAX(dock
->h
, app
->h
);
211 case OB_ORIENTATION_VERT
:
212 dock
->w
= MAX(dock
->w
, app
->w
);
218 spot
= (config_dock_orient
== OB_ORIENTATION_HORZ
? minw
: minh
) / 2;
220 /* position the apps */
221 for (it
= dock
->dock_apps
; it
; it
= it
->next
) {
222 ObDockApp
*app
= it
->data
;
223 switch (config_dock_orient
) {
224 case OB_ORIENTATION_HORZ
:
226 app
->y
= (dock
->h
- app
->h
) / 2;
229 case OB_ORIENTATION_VERT
:
230 app
->x
= (dock
->w
- app
->w
) / 2;
236 XMoveWindow(ob_display
, app
->icon_win
, app
->x
, app
->y
);
239 /* used for calculating offsets */
240 dock
->w
+= ob_rr_theme
->bwidth
* 2;
241 dock
->h
+= ob_rr_theme
->bwidth
* 2;
243 a
= screen_physical_area();
245 /* calculate position */
246 if (config_dock_floating
) {
247 dock
->x
= config_dock_x
;
248 dock
->y
= config_dock_y
;
249 gravity
= NorthWestGravity
;
251 switch (config_dock_pos
) {
252 case OB_DIRECTION_NORTHWEST
:
255 gravity
= NorthWestGravity
;
257 case OB_DIRECTION_NORTH
:
258 dock
->x
= a
->width
/ 2;
260 gravity
= NorthGravity
;
262 case OB_DIRECTION_NORTHEAST
:
265 gravity
= NorthEastGravity
;
267 case OB_DIRECTION_WEST
:
269 dock
->y
= a
->height
/ 2;
270 gravity
= WestGravity
;
272 case OB_DIRECTION_EAST
:
274 dock
->y
= a
->height
/ 2;
275 gravity
= EastGravity
;
277 case OB_DIRECTION_SOUTHWEST
:
280 gravity
= SouthWestGravity
;
282 case OB_DIRECTION_SOUTH
:
283 dock
->x
= a
->width
/ 2;
285 gravity
= SouthGravity
;
287 case OB_DIRECTION_SOUTHEAST
:
290 gravity
= SouthEastGravity
;
299 dock
->x
-= dock
->w
/ 2;
301 case NorthEastGravity
:
303 case SouthEastGravity
:
311 dock
->y
-= dock
->h
/ 2;
313 case SouthWestGravity
:
315 case SouthEastGravity
:
320 if (config_dock_hide
&& dock
->hidden
) {
321 if (!config_dock_floating
) {
322 switch (config_dock_pos
) {
323 case OB_DIRECTION_NORTHWEST
:
324 switch (config_dock_orient
) {
325 case OB_ORIENTATION_HORZ
:
326 dock
->y
-= dock
->h
- ob_rr_theme
->bwidth
;
328 case OB_ORIENTATION_VERT
:
329 dock
->x
-= dock
->w
- ob_rr_theme
->bwidth
;
333 case OB_DIRECTION_NORTH
:
334 dock
->y
-= dock
->h
- ob_rr_theme
->bwidth
;
336 case OB_DIRECTION_NORTHEAST
:
337 switch (config_dock_orient
) {
338 case OB_ORIENTATION_HORZ
:
339 dock
->y
-= dock
->h
- ob_rr_theme
->bwidth
;
341 case OB_ORIENTATION_VERT
:
342 dock
->x
+= dock
->w
- ob_rr_theme
->bwidth
;
346 case OB_DIRECTION_WEST
:
347 dock
->x
-= dock
->w
- ob_rr_theme
->bwidth
;
349 case OB_DIRECTION_EAST
:
350 dock
->x
+= dock
->w
- ob_rr_theme
->bwidth
;
352 case OB_DIRECTION_SOUTHWEST
:
353 switch (config_dock_orient
) {
354 case OB_ORIENTATION_HORZ
:
355 dock
->y
+= dock
->h
- ob_rr_theme
->bwidth
;
357 case OB_ORIENTATION_VERT
:
358 dock
->x
-= dock
->w
- ob_rr_theme
->bwidth
;
361 case OB_DIRECTION_SOUTH
:
362 dock
->y
+= dock
->h
- ob_rr_theme
->bwidth
;
364 case OB_DIRECTION_SOUTHEAST
:
365 switch (config_dock_orient
) {
366 case OB_ORIENTATION_HORZ
:
367 dock
->y
+= dock
->h
- ob_rr_theme
->bwidth
;
369 case OB_ORIENTATION_VERT
:
370 dock
->x
+= dock
->w
- ob_rr_theme
->bwidth
;
378 if (!config_dock_floating
&& config_dock_hide
) {
379 strw
= ob_rr_theme
->bwidth
;
380 strh
= ob_rr_theme
->bwidth
;
387 if (!dock
->dock_apps
) {
388 STRUT_PARTIAL_SET(dock_strut
, 0, 0, 0, 0,
389 0, 0, 0, 0, 0, 0, 0, 0);
390 } else if (config_dock_floating
) {
391 STRUT_PARTIAL_SET(dock_strut
, 0, 0, 0, 0,
392 0, 0, 0, 0, 0, 0, 0, 0);
394 switch (config_dock_pos
) {
395 case OB_DIRECTION_NORTHWEST
:
396 switch (config_dock_orient
) {
397 case OB_ORIENTATION_HORZ
:
398 STRUT_PARTIAL_SET(dock_strut
, 0, strh
, 0, 0,
399 0, 0, dock
->x
, dock
->x
+ dock
->w
- 1,
402 case OB_ORIENTATION_VERT
:
403 STRUT_PARTIAL_SET(dock_strut
, strw
, 0, 0, 0,
404 dock
->y
, dock
->y
+ dock
->h
- 1,
409 case OB_DIRECTION_NORTH
:
410 STRUT_PARTIAL_SET(dock_strut
, 0, strh
, 0, 0,
411 dock
->x
, dock
->x
+ dock
->w
- 1,
414 case OB_DIRECTION_NORTHEAST
:
415 switch (config_dock_orient
) {
416 case OB_ORIENTATION_HORZ
:
417 STRUT_PARTIAL_SET(dock_strut
, 0, strh
, 0, 0,
418 0, 0, dock
->x
, dock
->x
+ dock
->w
-1,
421 case OB_ORIENTATION_VERT
:
422 STRUT_PARTIAL_SET(dock_strut
, 0, 0, strw
, 0,
424 dock
->y
, dock
->y
+ dock
->h
- 1, 0, 0);
428 case OB_DIRECTION_WEST
:
429 STRUT_PARTIAL_SET(dock_strut
, strw
, 0, 0, 0,
430 dock
->y
, dock
->y
+ dock
->h
- 1,
433 case OB_DIRECTION_EAST
:
434 STRUT_PARTIAL_SET(dock_strut
, 0, 0, strw
, 0,
436 dock
->y
, dock
->y
+ dock
->h
- 1, 0, 0);
438 case OB_DIRECTION_SOUTHWEST
:
439 switch (config_dock_orient
) {
440 case OB_ORIENTATION_HORZ
:
441 STRUT_PARTIAL_SET(dock_strut
, 0, 0, 0, strh
,
443 dock
->x
, dock
->x
+ dock
->w
- 1);
445 case OB_ORIENTATION_VERT
:
446 STRUT_PARTIAL_SET(dock_strut
, strw
, 0, 0, 0,
447 dock
->y
, dock
->y
+ dock
->h
- 1,
452 case OB_DIRECTION_SOUTH
:
453 STRUT_PARTIAL_SET(dock_strut
, 0, 0, 0, strh
,
455 dock
->x
, dock
->x
+ dock
->w
- 1);
457 case OB_DIRECTION_SOUTHEAST
:
458 switch (config_dock_orient
) {
459 case OB_ORIENTATION_HORZ
:
460 STRUT_PARTIAL_SET(dock_strut
, 0, 0, 0, strh
,
462 dock
->x
, dock
->x
+ dock
->w
- 1);
464 case OB_ORIENTATION_VERT
:
465 STRUT_PARTIAL_SET(dock_strut
, 0, 0, strw
, 0,
467 dock
->y
, dock
->y
+ dock
->h
- 1, 0, 0);
477 /* not used for actually sizing shit */
478 dock
->w
-= ob_rr_theme
->bwidth
* 2;
479 dock
->h
-= ob_rr_theme
->bwidth
* 2;
481 if (dock
->dock_apps
) {
482 g_assert(dock
->w
> 0);
483 g_assert(dock
->h
> 0);
485 XMoveResizeWindow(ob_display
, dock
->frame
,
486 dock
->x
, dock
->y
, dock
->w
, dock
->h
);
488 RrPaint(dock
->a_frame
, dock
->frame
, dock
->w
, dock
->h
);
489 XMapWindow(ob_display
, dock
->frame
);
491 XUnmapWindow(ob_display
, dock
->frame
);
493 /* but they are useful outside of this function! */
494 dock
->w
+= ob_rr_theme
->bwidth
* 2;
495 dock
->h
+= ob_rr_theme
->bwidth
* 2;
497 screen_update_areas();
500 void dock_app_configure(ObDockApp
*app
, gint w
, gint h
)
507 void dock_app_drag(ObDockApp
*app
, XMotionEvent
*e
)
509 ObDockApp
*over
= NULL
;
518 /* are we on top of the dock? */
519 if (!(x
>= dock
->x
&&
521 x
< dock
->x
+ dock
->w
&&
522 y
< dock
->y
+ dock
->h
))
528 /* which dock app are we on top of? */
530 for (it
= dock
->dock_apps
; it
; it
= it
->next
) {
532 switch (config_dock_orient
) {
533 case OB_ORIENTATION_HORZ
:
534 if (x
>= over
->x
&& x
< over
->x
+ over
->w
)
537 case OB_ORIENTATION_VERT
:
538 if (y
>= over
->y
&& y
< over
->y
+ over
->h
)
542 /* dont go to it->next! */
545 if (!it
|| app
== over
) return;
550 switch (config_dock_orient
) {
551 case OB_ORIENTATION_HORZ
:
552 after
= (x
> over
->w
/ 2);
554 case OB_ORIENTATION_VERT
:
555 after
= (y
> over
->h
/ 2);
559 /* remove before doing the it->next! */
560 dock
->dock_apps
= g_list_remove(dock
->dock_apps
, app
);
562 if (after
) it
= it
->next
;
564 dock
->dock_apps
= g_list_insert_before(dock
->dock_apps
, it
, app
);
568 static gboolean
hide_timeout(gpointer data
)
574 return FALSE
; /* don't repeat */
577 void dock_hide(gboolean hide
)
581 dock
->hidden
= FALSE
;
584 /* if was hiding, stop it */
585 ob_main_loop_timeout_remove(ob_main_loop
, hide_timeout
);
586 } else if (!dock
->hidden
&& config_dock_hide
) {
587 ob_main_loop_timeout_add(ob_main_loop
, config_dock_hide_delay
,
588 hide_timeout
, NULL
, NULL
);