9 #include "render/theme.h"
11 #define DOCK_EVENT_MASK (ButtonPressMask | ButtonReleaseMask | \
12 EnterWindowMask | LeaveWindowMask)
13 #define DOCKAPP_EVENT_MASK (StructureNotifyMask)
17 StrutPartial dock_strut
;
19 void dock_startup(gboolean reconfig
)
21 XSetWindowAttributes attrib
;
28 STRUT_PARTIAL_SET(dock_strut
, 0, 0, 0, 0,
29 0, 0, 0, 0, 0, 0, 0, 0);
31 dock
= g_new0(ObDock
, 1);
32 dock
->obwin
.type
= Window_Dock
;
36 attrib
.event_mask
= DOCK_EVENT_MASK
;
37 attrib
.override_redirect
= True
;
38 dock
->frame
= XCreateWindow(ob_display
, RootWindow(ob_display
, ob_screen
),
40 RrDepth(ob_rr_inst
), InputOutput
,
42 CWOverrideRedirect
| CWEventMask
,
44 dock
->a_frame
= RrAppearanceCopy(ob_rr_theme
->a_unfocused_title
);
45 XSetWindowBorder(ob_display
, dock
->frame
,
46 RrColorPixel(ob_rr_theme
->b_color
));
47 XSetWindowBorderWidth(ob_display
, dock
->frame
, ob_rr_theme
->bwidth
);
49 g_hash_table_insert(window_map
, &dock
->frame
, dock
);
50 stacking_add(DOCK_AS_WINDOW(dock
));
51 stacking_raise(DOCK_AS_WINDOW(dock
));
54 void dock_shutdown(gboolean reconfig
)
58 XDestroyWindow(ob_display
, dock
->frame
);
59 RrAppearanceFree(dock
->a_frame
);
60 g_hash_table_remove(window_map
, &dock
->frame
);
61 stacking_remove(dock
);
64 void dock_add(Window win
, XWMHints
*wmhints
)
67 XWindowAttributes attrib
;
70 app
= g_new0(ObDockApp
, 1);
71 app
->obwin
.type
= Window_DockApp
;
73 app
->icon_win
= (wmhints
->flags
& IconWindowHint
) ?
74 wmhints
->icon_window
: win
;
76 if (PROP_GETSS(app
->win
, wm_class
, locale
, &data
)) {
78 app
->name
= g_strdup(data
[0]);
80 app
->class = g_strdup(data
[1]);
85 if (app
->name
== NULL
) app
->name
= g_strdup("");
86 if (app
->class == NULL
) app
->class = g_strdup("");
88 if (XGetWindowAttributes(ob_display
, app
->icon_win
, &attrib
)) {
89 app
->w
= attrib
.width
;
90 app
->h
= attrib
.height
;
95 dock
->dock_apps
= g_list_append(dock
->dock_apps
, app
);
98 XReparentWindow(ob_display
, app
->icon_win
, dock
->frame
, app
->x
, app
->y
);
100 This is the same case as in frame.c for client windows. When Openbox is
101 starting, the window is already mapped so we see unmap events occur for
102 it. There are 2 unmap events generated that we see, one with the 'event'
103 member set the root window, and one set to the client, but both get
104 handled and need to be ignored.
106 if (ob_state() == OB_STATE_STARTING
)
107 app
->ignore_unmaps
+= 2;
109 if (app
->win
!= app
->icon_win
) {
110 /* have to map it so that it can be re-managed on a restart */
111 XMoveWindow(ob_display
, app
->win
, -1000, -1000);
112 XMapWindow(ob_display
, app
->win
);
114 XMapWindow(ob_display
, app
->icon_win
);
115 XSync(ob_display
, False
);
117 /* specify that if we exit, the window should not be destroyed and should
118 be reparented back to root automatically */
119 XChangeSaveSet(ob_display
, app
->icon_win
, SetModeInsert
);
120 XSelectInput(ob_display
, app
->icon_win
, DOCKAPP_EVENT_MASK
);
122 grab_button_full(2, 0, app
->icon_win
,
123 ButtonPressMask
| ButtonReleaseMask
| ButtonMotionMask
,
124 GrabModeAsync
, OB_CURSOR_MOVE
);
126 g_hash_table_insert(window_map
, &app
->icon_win
, app
);
128 ob_debug("Managed Dock App: 0x%lx (%s)\n", app
->icon_win
, app
->class);
131 void dock_remove_all()
133 while (dock
->dock_apps
)
134 dock_remove(dock
->dock_apps
->data
, TRUE
);
137 void dock_remove(ObDockApp
*app
, gboolean reparent
)
139 ungrab_button(2, 0, app
->icon_win
);
140 XSelectInput(ob_display
, app
->icon_win
, NoEventMask
);
141 /* remove the window from our save set */
142 XChangeSaveSet(ob_display
, app
->icon_win
, SetModeDelete
);
143 XSync(ob_display
, False
);
145 g_hash_table_remove(window_map
, &app
->icon_win
);
148 XReparentWindow(ob_display
, app
->icon_win
,
149 RootWindow(ob_display
, ob_screen
), app
->x
, app
->y
);
151 dock
->dock_apps
= g_list_remove(dock
->dock_apps
, app
);
154 ob_debug("Unmanaged Dock App: 0x%lx (%s)\n", app
->icon_win
, app
->class);
161 void dock_configure()
170 RrMinsize(dock
->a_frame
, &minw
, &minh
);
172 dock
->w
= dock
->h
= 0;
175 for (it
= dock
->dock_apps
; it
; it
= it
->next
) {
176 ObDockApp
*app
= it
->data
;
177 switch (config_dock_orient
) {
178 case OB_ORIENTATION_HORZ
:
180 dock
->h
= MAX(dock
->h
, app
->h
);
182 case OB_ORIENTATION_VERT
:
183 dock
->w
= MAX(dock
->w
, app
->w
);
189 spot
= (config_dock_orient
== OB_ORIENTATION_HORZ
? minw
: minh
) / 2;
191 /* position the apps */
192 for (it
= dock
->dock_apps
; it
; it
= it
->next
) {
193 ObDockApp
*app
= it
->data
;
194 switch (config_dock_orient
) {
195 case OB_ORIENTATION_HORZ
:
197 app
->y
= (dock
->h
- app
->h
) / 2;
200 case OB_ORIENTATION_VERT
:
201 app
->x
= (dock
->w
- app
->w
) / 2;
207 XMoveWindow(ob_display
, app
->icon_win
, app
->x
, app
->y
);
210 /* used for calculating offsets */
211 dock
->w
+= ob_rr_theme
->bwidth
* 2;
212 dock
->h
+= ob_rr_theme
->bwidth
* 2;
214 a
= screen_physical_area();
216 /* calculate position */
217 if (config_dock_floating
) {
218 dock
->x
= config_dock_x
;
219 dock
->y
= config_dock_y
;
220 gravity
= NorthWestGravity
;
222 switch (config_dock_pos
) {
223 case OB_DIRECTION_NORTHWEST
:
226 gravity
= NorthWestGravity
;
228 case OB_DIRECTION_NORTH
:
229 dock
->x
= a
->width
/ 2;
231 gravity
= NorthGravity
;
233 case OB_DIRECTION_NORTHEAST
:
236 gravity
= NorthEastGravity
;
238 case OB_DIRECTION_WEST
:
240 dock
->y
= a
->height
/ 2;
241 gravity
= WestGravity
;
243 case OB_DIRECTION_EAST
:
245 dock
->y
= a
->height
/ 2;
246 gravity
= EastGravity
;
248 case OB_DIRECTION_SOUTHWEST
:
251 gravity
= SouthWestGravity
;
253 case OB_DIRECTION_SOUTH
:
254 dock
->x
= a
->width
/ 2;
256 gravity
= SouthGravity
;
258 case OB_DIRECTION_SOUTHEAST
:
261 gravity
= SouthEastGravity
;
270 dock
->x
-= dock
->w
/ 2;
272 case NorthEastGravity
:
274 case SouthEastGravity
:
282 dock
->y
-= dock
->h
/ 2;
284 case SouthWestGravity
:
286 case SouthEastGravity
:
291 if (config_dock_hide
&& dock
->hidden
) {
292 if (!config_dock_floating
) {
293 switch (config_dock_pos
) {
294 case OB_DIRECTION_NORTHWEST
:
295 switch (config_dock_orient
) {
296 case OB_ORIENTATION_HORZ
:
297 dock
->y
-= dock
->h
- ob_rr_theme
->bwidth
;
299 case OB_ORIENTATION_VERT
:
300 dock
->x
-= dock
->w
- ob_rr_theme
->bwidth
;
304 case OB_DIRECTION_NORTH
:
305 dock
->y
-= dock
->h
- ob_rr_theme
->bwidth
;
307 case OB_DIRECTION_NORTHEAST
:
308 switch (config_dock_orient
) {
309 case OB_ORIENTATION_HORZ
:
310 dock
->y
-= dock
->h
- ob_rr_theme
->bwidth
;
312 case OB_ORIENTATION_VERT
:
313 dock
->x
+= dock
->w
- ob_rr_theme
->bwidth
;
317 case OB_DIRECTION_WEST
:
318 dock
->x
-= dock
->w
- ob_rr_theme
->bwidth
;
320 case OB_DIRECTION_EAST
:
321 dock
->x
+= dock
->w
- ob_rr_theme
->bwidth
;
323 case OB_DIRECTION_SOUTHWEST
:
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
;
332 case OB_DIRECTION_SOUTH
:
333 dock
->y
+= dock
->h
- ob_rr_theme
->bwidth
;
335 case OB_DIRECTION_SOUTHEAST
:
336 switch (config_dock_orient
) {
337 case OB_ORIENTATION_HORZ
:
338 dock
->y
+= dock
->h
- ob_rr_theme
->bwidth
;
340 case OB_ORIENTATION_VERT
:
341 dock
->x
+= dock
->w
- ob_rr_theme
->bwidth
;
349 if (!config_dock_floating
&& config_dock_hide
) {
350 strw
= ob_rr_theme
->bwidth
;
351 strh
= ob_rr_theme
->bwidth
;
358 if (!dock
->dock_apps
) {
359 STRUT_PARTIAL_SET(dock_strut
, 0, 0, 0, 0,
360 0, 0, 0, 0, 0, 0, 0, 0);
361 } else if (config_dock_floating
) {
362 STRUT_PARTIAL_SET(dock_strut
, 0, 0, 0, 0,
363 0, 0, 0, 0, 0, 0, 0, 0);
365 switch (config_dock_pos
) {
366 case OB_DIRECTION_NORTHWEST
:
367 switch (config_dock_orient
) {
368 case OB_ORIENTATION_HORZ
:
369 STRUT_PARTIAL_SET(dock_strut
, 0, strh
, 0, 0,
370 0, 0, dock
->x
, dock
->x
+ dock
->w
- 1,
373 case OB_ORIENTATION_VERT
:
374 STRUT_PARTIAL_SET(dock_strut
, strw
, 0, 0, 0,
375 dock
->y
, dock
->y
+ dock
->h
- 1,
380 case OB_DIRECTION_NORTH
:
381 STRUT_PARTIAL_SET(dock_strut
, 0, strh
, 0, 0,
382 dock
->x
, dock
->x
+ dock
->w
- 1,
385 case OB_DIRECTION_NORTHEAST
:
386 switch (config_dock_orient
) {
387 case OB_ORIENTATION_HORZ
:
388 STRUT_PARTIAL_SET(dock_strut
, 0, strh
, 0, 0,
389 0, 0, dock
->x
, dock
->x
+ dock
->w
-1,
392 case OB_ORIENTATION_VERT
:
393 STRUT_PARTIAL_SET(dock_strut
, 0, 0, strw
, 0,
395 dock
->y
, dock
->y
+ dock
->h
- 1, 0, 0);
399 case OB_DIRECTION_WEST
:
400 STRUT_PARTIAL_SET(dock_strut
, strw
, 0, 0, 0,
401 dock
->y
, dock
->y
+ dock
->h
- 1,
404 case OB_DIRECTION_EAST
:
405 STRUT_PARTIAL_SET(dock_strut
, 0, 0, strw
, 0,
407 dock
->y
, dock
->y
+ dock
->h
- 1, 0, 0);
409 case OB_DIRECTION_SOUTHWEST
:
410 switch (config_dock_orient
) {
411 case OB_ORIENTATION_HORZ
:
412 STRUT_PARTIAL_SET(dock_strut
, 0, 0, 0, strh
,
414 dock
->x
, dock
->x
+ dock
->w
- 1);
416 case OB_ORIENTATION_VERT
:
417 STRUT_PARTIAL_SET(dock_strut
, strw
, 0, 0, 0,
418 dock
->y
, dock
->y
+ dock
->h
- 1,
423 case OB_DIRECTION_SOUTH
:
424 STRUT_PARTIAL_SET(dock_strut
, 0, 0, 0, strh
,
426 dock
->x
, dock
->x
+ dock
->w
- 1);
428 case OB_DIRECTION_SOUTHEAST
:
429 switch (config_dock_orient
) {
430 case OB_ORIENTATION_HORZ
:
431 STRUT_PARTIAL_SET(dock_strut
, 0, 0, 0, strh
,
433 dock
->x
, dock
->x
+ dock
->w
- 1);
435 case OB_ORIENTATION_VERT
:
436 STRUT_PARTIAL_SET(dock_strut
, 0, 0, strw
, 0,
438 dock
->y
, dock
->y
+ dock
->h
- 1, 0, 0);
448 /* not used for actually sizing shit */
449 dock
->w
-= ob_rr_theme
->bwidth
* 2;
450 dock
->h
-= ob_rr_theme
->bwidth
* 2;
452 if (dock
->dock_apps
) {
453 g_assert(dock
->w
> 0);
454 g_assert(dock
->h
> 0);
456 XMoveResizeWindow(ob_display
, dock
->frame
,
457 dock
->x
, dock
->y
, dock
->w
, dock
->h
);
459 RrPaint(dock
->a_frame
, dock
->frame
, dock
->w
, dock
->h
);
460 XMapWindow(ob_display
, dock
->frame
);
462 XUnmapWindow(ob_display
, dock
->frame
);
464 /* but they are useful outside of this function! */
465 dock
->w
+= ob_rr_theme
->bwidth
* 2;
466 dock
->h
+= ob_rr_theme
->bwidth
* 2;
468 screen_update_areas();
471 void dock_app_configure(ObDockApp
*app
, gint w
, gint h
)
478 void dock_app_drag(ObDockApp
*app
, XMotionEvent
*e
)
480 ObDockApp
*over
= NULL
;
489 /* are we on top of the dock? */
490 if (!(x
>= dock
->x
&&
492 x
< dock
->x
+ dock
->w
&&
493 y
< dock
->y
+ dock
->h
))
499 /* which dock app are we on top of? */
501 for (it
= dock
->dock_apps
; it
; it
= it
->next
) {
503 switch (config_dock_orient
) {
504 case OB_ORIENTATION_HORZ
:
505 if (x
>= over
->x
&& x
< over
->x
+ over
->w
)
508 case OB_ORIENTATION_VERT
:
509 if (y
>= over
->y
&& y
< over
->y
+ over
->h
)
513 /* dont go to it->next! */
516 if (!it
|| app
== over
) return;
521 switch (config_dock_orient
) {
522 case OB_ORIENTATION_HORZ
:
523 after
= (x
> over
->w
/ 2);
525 case OB_ORIENTATION_VERT
:
526 after
= (y
> over
->h
/ 2);
530 /* remove before doing the it->next! */
531 dock
->dock_apps
= g_list_remove(dock
->dock_apps
, app
);
533 if (after
) it
= it
->next
;
535 dock
->dock_apps
= g_list_insert_before(dock
->dock_apps
, it
, app
);
539 static gboolean
hide_timeout(gpointer data
)
545 return FALSE
; /* don't repeat */
548 void dock_hide(gboolean hide
)
550 if (dock
->hidden
== hide
|| !config_dock_hide
)
554 dock
->hidden
= FALSE
;
557 /* if was hiding, stop it */
558 ob_main_loop_timeout_remove(ob_main_loop
, hide_timeout
);
560 ob_main_loop_timeout_add(ob_main_loop
, config_dock_hide_timeout
* 1000,
561 hide_timeout
, NULL
, NULL
);