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
;
24 stacking_add(DOCK_AS_WINDOW(dock
));
29 STRUT_PARTIAL_SET(dock_strut
, 0, 0, 0, 0,
30 0, 0, 0, 0, 0, 0, 0, 0);
32 dock
= g_new0(ObDock
, 1);
33 dock
->obwin
.type
= Window_Dock
;
37 attrib
.event_mask
= DOCK_EVENT_MASK
;
38 attrib
.override_redirect
= True
;
39 dock
->frame
= XCreateWindow(ob_display
, RootWindow(ob_display
, ob_screen
),
41 RrDepth(ob_rr_inst
), InputOutput
,
43 CWOverrideRedirect
| CWEventMask
,
45 dock
->a_frame
= RrAppearanceCopy(ob_rr_theme
->a_unfocused_title
);
46 XSetWindowBorder(ob_display
, dock
->frame
,
47 RrColorPixel(ob_rr_theme
->b_color
));
48 XSetWindowBorderWidth(ob_display
, dock
->frame
, ob_rr_theme
->bwidth
);
50 g_hash_table_insert(window_map
, &dock
->frame
, dock
);
51 stacking_add(DOCK_AS_WINDOW(dock
));
54 void dock_shutdown(gboolean reconfig
)
57 stacking_remove(DOCK_AS_WINDOW(dock
));
61 XDestroyWindow(ob_display
, dock
->frame
);
62 RrAppearanceFree(dock
->a_frame
);
63 g_hash_table_remove(window_map
, &dock
->frame
);
64 stacking_remove(dock
);
67 void dock_add(Window win
, XWMHints
*wmhints
)
70 XWindowAttributes attrib
;
73 app
= g_new0(ObDockApp
, 1);
74 app
->obwin
.type
= Window_DockApp
;
76 app
->icon_win
= (wmhints
->flags
& IconWindowHint
) ?
77 wmhints
->icon_window
: win
;
79 if (PROP_GETSS(app
->win
, wm_class
, locale
, &data
)) {
81 app
->name
= g_strdup(data
[0]);
83 app
->class = g_strdup(data
[1]);
88 if (app
->name
== NULL
) app
->name
= g_strdup("");
89 if (app
->class == NULL
) app
->class = g_strdup("");
91 if (XGetWindowAttributes(ob_display
, app
->icon_win
, &attrib
)) {
92 app
->w
= attrib
.width
;
93 app
->h
= attrib
.height
;
98 dock
->dock_apps
= g_list_append(dock
->dock_apps
, app
);
101 XReparentWindow(ob_display
, app
->icon_win
, dock
->frame
, app
->x
, app
->y
);
103 This is the same case as in frame.c for client windows. When Openbox is
104 starting, the window is already mapped so we see unmap events occur for
105 it. There are 2 unmap events generated that we see, one with the 'event'
106 member set the root window, and one set to the client, but both get
107 handled and need to be ignored.
109 if (ob_state() == OB_STATE_STARTING
)
110 app
->ignore_unmaps
+= 2;
112 if (app
->win
!= app
->icon_win
) {
113 /* have to map it so that it can be re-managed on a restart */
114 XMoveWindow(ob_display
, app
->win
, -1000, -1000);
115 XMapWindow(ob_display
, app
->win
);
117 XMapWindow(ob_display
, app
->icon_win
);
118 XSync(ob_display
, False
);
120 /* specify that if we exit, the window should not be destroyed and should
121 be reparented back to root automatically */
122 XChangeSaveSet(ob_display
, app
->icon_win
, SetModeInsert
);
123 XSelectInput(ob_display
, app
->icon_win
, DOCKAPP_EVENT_MASK
);
125 grab_button_full(2, 0, app
->icon_win
,
126 ButtonPressMask
| ButtonReleaseMask
| ButtonMotionMask
,
127 GrabModeAsync
, OB_CURSOR_MOVE
);
129 g_hash_table_insert(window_map
, &app
->icon_win
, app
);
131 ob_debug("Managed Dock App: 0x%lx (%s)\n", app
->icon_win
, app
->class);
134 void dock_remove_all()
136 while (dock
->dock_apps
)
137 dock_remove(dock
->dock_apps
->data
, TRUE
);
140 void dock_remove(ObDockApp
*app
, gboolean reparent
)
142 ungrab_button(2, 0, app
->icon_win
);
143 XSelectInput(ob_display
, app
->icon_win
, NoEventMask
);
144 /* remove the window from our save set */
145 XChangeSaveSet(ob_display
, app
->icon_win
, SetModeDelete
);
146 XSync(ob_display
, False
);
148 g_hash_table_remove(window_map
, &app
->icon_win
);
151 XReparentWindow(ob_display
, app
->icon_win
,
152 RootWindow(ob_display
, ob_screen
), app
->x
, app
->y
);
154 dock
->dock_apps
= g_list_remove(dock
->dock_apps
, app
);
157 ob_debug("Unmanaged Dock App: 0x%lx (%s)\n", app
->icon_win
, app
->class);
164 void dock_configure()
173 RrMinsize(dock
->a_frame
, &minw
, &minh
);
175 dock
->w
= dock
->h
= 0;
178 for (it
= dock
->dock_apps
; it
; it
= it
->next
) {
179 ObDockApp
*app
= it
->data
;
180 switch (config_dock_orient
) {
181 case OB_ORIENTATION_HORZ
:
183 dock
->h
= MAX(dock
->h
, app
->h
);
185 case OB_ORIENTATION_VERT
:
186 dock
->w
= MAX(dock
->w
, app
->w
);
192 spot
= (config_dock_orient
== OB_ORIENTATION_HORZ
? minw
: minh
) / 2;
194 /* position the apps */
195 for (it
= dock
->dock_apps
; it
; it
= it
->next
) {
196 ObDockApp
*app
= it
->data
;
197 switch (config_dock_orient
) {
198 case OB_ORIENTATION_HORZ
:
200 app
->y
= (dock
->h
- app
->h
) / 2;
203 case OB_ORIENTATION_VERT
:
204 app
->x
= (dock
->w
- app
->w
) / 2;
210 XMoveWindow(ob_display
, app
->icon_win
, app
->x
, app
->y
);
213 /* used for calculating offsets */
214 dock
->w
+= ob_rr_theme
->bwidth
* 2;
215 dock
->h
+= ob_rr_theme
->bwidth
* 2;
217 a
= screen_physical_area();
219 /* calculate position */
220 if (config_dock_floating
) {
221 dock
->x
= config_dock_x
;
222 dock
->y
= config_dock_y
;
223 gravity
= NorthWestGravity
;
225 switch (config_dock_pos
) {
226 case OB_DIRECTION_NORTHWEST
:
229 gravity
= NorthWestGravity
;
231 case OB_DIRECTION_NORTH
:
232 dock
->x
= a
->width
/ 2;
234 gravity
= NorthGravity
;
236 case OB_DIRECTION_NORTHEAST
:
239 gravity
= NorthEastGravity
;
241 case OB_DIRECTION_WEST
:
243 dock
->y
= a
->height
/ 2;
244 gravity
= WestGravity
;
246 case OB_DIRECTION_EAST
:
248 dock
->y
= a
->height
/ 2;
249 gravity
= EastGravity
;
251 case OB_DIRECTION_SOUTHWEST
:
254 gravity
= SouthWestGravity
;
256 case OB_DIRECTION_SOUTH
:
257 dock
->x
= a
->width
/ 2;
259 gravity
= SouthGravity
;
261 case OB_DIRECTION_SOUTHEAST
:
264 gravity
= SouthEastGravity
;
273 dock
->x
-= dock
->w
/ 2;
275 case NorthEastGravity
:
277 case SouthEastGravity
:
285 dock
->y
-= dock
->h
/ 2;
287 case SouthWestGravity
:
289 case SouthEastGravity
:
294 if (config_dock_hide
&& dock
->hidden
) {
295 if (!config_dock_floating
) {
296 switch (config_dock_pos
) {
297 case OB_DIRECTION_NORTHWEST
:
298 switch (config_dock_orient
) {
299 case OB_ORIENTATION_HORZ
:
300 dock
->y
-= dock
->h
- ob_rr_theme
->bwidth
;
302 case OB_ORIENTATION_VERT
:
303 dock
->x
-= dock
->w
- ob_rr_theme
->bwidth
;
307 case OB_DIRECTION_NORTH
:
308 dock
->y
-= dock
->h
- ob_rr_theme
->bwidth
;
310 case OB_DIRECTION_NORTHEAST
:
311 switch (config_dock_orient
) {
312 case OB_ORIENTATION_HORZ
:
313 dock
->y
-= dock
->h
- ob_rr_theme
->bwidth
;
315 case OB_ORIENTATION_VERT
:
316 dock
->x
+= dock
->w
- ob_rr_theme
->bwidth
;
320 case OB_DIRECTION_WEST
:
321 dock
->x
-= dock
->w
- ob_rr_theme
->bwidth
;
323 case OB_DIRECTION_EAST
:
324 dock
->x
+= dock
->w
- ob_rr_theme
->bwidth
;
326 case OB_DIRECTION_SOUTHWEST
:
327 switch (config_dock_orient
) {
328 case OB_ORIENTATION_HORZ
:
329 dock
->y
+= dock
->h
- ob_rr_theme
->bwidth
;
331 case OB_ORIENTATION_VERT
:
332 dock
->x
-= dock
->w
- ob_rr_theme
->bwidth
;
335 case OB_DIRECTION_SOUTH
:
336 dock
->y
+= dock
->h
- ob_rr_theme
->bwidth
;
338 case OB_DIRECTION_SOUTHEAST
:
339 switch (config_dock_orient
) {
340 case OB_ORIENTATION_HORZ
:
341 dock
->y
+= dock
->h
- ob_rr_theme
->bwidth
;
343 case OB_ORIENTATION_VERT
:
344 dock
->x
+= dock
->w
- ob_rr_theme
->bwidth
;
352 if (!config_dock_floating
&& config_dock_hide
) {
353 strw
= ob_rr_theme
->bwidth
;
354 strh
= ob_rr_theme
->bwidth
;
361 if (!dock
->dock_apps
) {
362 STRUT_PARTIAL_SET(dock_strut
, 0, 0, 0, 0,
363 0, 0, 0, 0, 0, 0, 0, 0);
364 } else if (config_dock_floating
) {
365 STRUT_PARTIAL_SET(dock_strut
, 0, 0, 0, 0,
366 0, 0, 0, 0, 0, 0, 0, 0);
368 switch (config_dock_pos
) {
369 case OB_DIRECTION_NORTHWEST
:
370 switch (config_dock_orient
) {
371 case OB_ORIENTATION_HORZ
:
372 STRUT_PARTIAL_SET(dock_strut
, 0, strh
, 0, 0,
373 0, 0, dock
->x
, dock
->x
+ dock
->w
- 1,
376 case OB_ORIENTATION_VERT
:
377 STRUT_PARTIAL_SET(dock_strut
, strw
, 0, 0, 0,
378 dock
->y
, dock
->y
+ dock
->h
- 1,
383 case OB_DIRECTION_NORTH
:
384 STRUT_PARTIAL_SET(dock_strut
, 0, strh
, 0, 0,
385 dock
->x
, dock
->x
+ dock
->w
- 1,
388 case OB_DIRECTION_NORTHEAST
:
389 switch (config_dock_orient
) {
390 case OB_ORIENTATION_HORZ
:
391 STRUT_PARTIAL_SET(dock_strut
, 0, strh
, 0, 0,
392 0, 0, dock
->x
, dock
->x
+ dock
->w
-1,
395 case OB_ORIENTATION_VERT
:
396 STRUT_PARTIAL_SET(dock_strut
, 0, 0, strw
, 0,
398 dock
->y
, dock
->y
+ dock
->h
- 1, 0, 0);
402 case OB_DIRECTION_WEST
:
403 STRUT_PARTIAL_SET(dock_strut
, strw
, 0, 0, 0,
404 dock
->y
, dock
->y
+ dock
->h
- 1,
407 case OB_DIRECTION_EAST
:
408 STRUT_PARTIAL_SET(dock_strut
, 0, 0, strw
, 0,
410 dock
->y
, dock
->y
+ dock
->h
- 1, 0, 0);
412 case OB_DIRECTION_SOUTHWEST
:
413 switch (config_dock_orient
) {
414 case OB_ORIENTATION_HORZ
:
415 STRUT_PARTIAL_SET(dock_strut
, 0, 0, 0, strh
,
417 dock
->x
, dock
->x
+ dock
->w
- 1);
419 case OB_ORIENTATION_VERT
:
420 STRUT_PARTIAL_SET(dock_strut
, strw
, 0, 0, 0,
421 dock
->y
, dock
->y
+ dock
->h
- 1,
426 case OB_DIRECTION_SOUTH
:
427 STRUT_PARTIAL_SET(dock_strut
, 0, 0, 0, strh
,
429 dock
->x
, dock
->x
+ dock
->w
- 1);
431 case OB_DIRECTION_SOUTHEAST
:
432 switch (config_dock_orient
) {
433 case OB_ORIENTATION_HORZ
:
434 STRUT_PARTIAL_SET(dock_strut
, 0, 0, 0, strh
,
436 dock
->x
, dock
->x
+ dock
->w
- 1);
438 case OB_ORIENTATION_VERT
:
439 STRUT_PARTIAL_SET(dock_strut
, 0, 0, strw
, 0,
441 dock
->y
, dock
->y
+ dock
->h
- 1, 0, 0);
451 /* not used for actually sizing shit */
452 dock
->w
-= ob_rr_theme
->bwidth
* 2;
453 dock
->h
-= ob_rr_theme
->bwidth
* 2;
455 if (dock
->dock_apps
) {
456 g_assert(dock
->w
> 0);
457 g_assert(dock
->h
> 0);
459 XMoveResizeWindow(ob_display
, dock
->frame
,
460 dock
->x
, dock
->y
, dock
->w
, dock
->h
);
462 RrPaint(dock
->a_frame
, dock
->frame
, dock
->w
, dock
->h
);
463 XMapWindow(ob_display
, dock
->frame
);
465 XUnmapWindow(ob_display
, dock
->frame
);
467 /* but they are useful outside of this function! */
468 dock
->w
+= ob_rr_theme
->bwidth
* 2;
469 dock
->h
+= ob_rr_theme
->bwidth
* 2;
471 screen_update_areas();
474 void dock_app_configure(ObDockApp
*app
, gint w
, gint h
)
481 void dock_app_drag(ObDockApp
*app
, XMotionEvent
*e
)
483 ObDockApp
*over
= NULL
;
492 /* are we on top of the dock? */
493 if (!(x
>= dock
->x
&&
495 x
< dock
->x
+ dock
->w
&&
496 y
< dock
->y
+ dock
->h
))
502 /* which dock app are we on top of? */
504 for (it
= dock
->dock_apps
; it
; it
= it
->next
) {
506 switch (config_dock_orient
) {
507 case OB_ORIENTATION_HORZ
:
508 if (x
>= over
->x
&& x
< over
->x
+ over
->w
)
511 case OB_ORIENTATION_VERT
:
512 if (y
>= over
->y
&& y
< over
->y
+ over
->h
)
516 /* dont go to it->next! */
519 if (!it
|| app
== over
) return;
524 switch (config_dock_orient
) {
525 case OB_ORIENTATION_HORZ
:
526 after
= (x
> over
->w
/ 2);
528 case OB_ORIENTATION_VERT
:
529 after
= (y
> over
->h
/ 2);
533 /* remove before doing the it->next! */
534 dock
->dock_apps
= g_list_remove(dock
->dock_apps
, app
);
536 if (after
) it
= it
->next
;
538 dock
->dock_apps
= g_list_insert_before(dock
->dock_apps
, it
, app
);
542 static gboolean
hide_timeout(gpointer data
)
548 return FALSE
; /* don't repeat */
551 void dock_hide(gboolean hide
)
555 dock
->hidden
= FALSE
;
558 /* if was hiding, stop it */
559 ob_main_loop_timeout_remove(ob_main_loop
, hide_timeout
);
560 } else if (!dock
->hidden
&& config_dock_hide
) {
561 ob_main_loop_timeout_add(ob_main_loop
, config_dock_hide_timeout
,
562 hide_timeout
, NULL
, NULL
);