8 #include "render/theme.h"
10 #define DOCK_EVENT_MASK (ButtonPressMask | ButtonReleaseMask | \
11 EnterWindowMask | LeaveWindowMask)
12 #define DOCKAPP_EVENT_MASK (StructureNotifyMask)
20 XSetWindowAttributes attrib
;
22 STRUT_SET(dock_strut
, 0, 0, 0, 0);
24 dock
= g_new0(ObDock
, 1);
25 dock
->obwin
.type
= Window_Dock
;
29 attrib
.event_mask
= DOCK_EVENT_MASK
;
30 attrib
.override_redirect
= True
;
31 dock
->frame
= XCreateWindow(ob_display
, RootWindow(ob_display
, ob_screen
),
33 RrDepth(ob_rr_inst
), InputOutput
,
35 CWOverrideRedirect
| CWEventMask
,
37 dock
->a_frame
= RrAppearanceCopy(ob_rr_theme
->a_unfocused_title
);
38 XSetWindowBorder(ob_display
, dock
->frame
,
39 RrColorPixel(ob_rr_theme
->b_color
));
40 XSetWindowBorderWidth(ob_display
, dock
->frame
, ob_rr_theme
->bwidth
);
42 g_hash_table_insert(window_map
, &dock
->frame
, dock
);
43 stacking_add(DOCK_AS_WINDOW(dock
));
44 stacking_raise(DOCK_AS_WINDOW(dock
));
49 XDestroyWindow(ob_display
, dock
->frame
);
50 RrAppearanceFree(dock
->a_frame
);
51 g_hash_table_remove(window_map
, &dock
->frame
);
52 stacking_remove(dock
);
55 void dock_add(Window win
, XWMHints
*wmhints
)
58 XWindowAttributes attrib
;
61 app
= g_new0(ObDockApp
, 1);
62 app
->obwin
.type
= Window_DockApp
;
64 app
->icon_win
= (wmhints
->flags
& IconWindowHint
) ?
65 wmhints
->icon_window
: win
;
67 if (PROP_GETSS(app
->win
, wm_class
, locale
, &data
)) {
69 app
->name
= g_strdup(data
[0]);
71 app
->class = g_strdup(data
[1]);
76 if (app
->name
== NULL
) app
->name
= g_strdup("");
77 if (app
->class == NULL
) app
->class = g_strdup("");
79 if (XGetWindowAttributes(ob_display
, app
->icon_win
, &attrib
)) {
80 app
->w
= attrib
.width
;
81 app
->h
= attrib
.height
;
86 dock
->dock_apps
= g_list_append(dock
->dock_apps
, app
);
89 XReparentWindow(ob_display
, app
->icon_win
, dock
->frame
, app
->x
, app
->y
);
91 This is the same case as in frame.c for client windows. When Openbox is
92 starting, the window is already mapped so we see unmap events occur for
93 it. There are 2 unmap events generated that we see, one with the 'event'
94 member set the root window, and one set to the client, but both get
95 handled and need to be ignored.
97 if (ob_state() == OB_STATE_STARTING
)
98 app
->ignore_unmaps
+= 2;
100 if (app
->win
!= app
->icon_win
) {
101 /* have to map it so that it can be re-managed on a restart */
102 XMoveWindow(ob_display
, app
->win
, -1000, -1000);
103 XMapWindow(ob_display
, app
->win
);
105 XMapWindow(ob_display
, app
->icon_win
);
106 XSync(ob_display
, False
);
108 /* specify that if we exit, the window should not be destroyed and should
109 be reparented back to root automatically */
110 XChangeSaveSet(ob_display
, app
->icon_win
, SetModeInsert
);
111 XSelectInput(ob_display
, app
->icon_win
, DOCKAPP_EVENT_MASK
);
113 grab_button_full(2, 0, app
->icon_win
,
114 ButtonPressMask
| ButtonReleaseMask
| ButtonMotionMask
,
115 GrabModeAsync
, OB_CURSOR_MOVE
);
117 g_hash_table_insert(window_map
, &app
->icon_win
, app
);
119 ob_debug("Managed Dock App: 0x%lx (%s)\n", app
->icon_win
, app
->class);
122 void dock_remove_all()
124 while (dock
->dock_apps
)
125 dock_remove(dock
->dock_apps
->data
, TRUE
);
128 void dock_remove(ObDockApp
*app
, gboolean reparent
)
130 ungrab_button(2, 0, app
->icon_win
);
131 XSelectInput(ob_display
, app
->icon_win
, NoEventMask
);
132 /* remove the window from our save set */
133 XChangeSaveSet(ob_display
, app
->icon_win
, SetModeDelete
);
134 XSync(ob_display
, False
);
136 g_hash_table_remove(window_map
, &app
->icon_win
);
139 XReparentWindow(ob_display
, app
->icon_win
,
140 RootWindow(ob_display
, ob_screen
), app
->x
, app
->y
);
142 dock
->dock_apps
= g_list_remove(dock
->dock_apps
, app
);
145 ob_debug("Unmanaged Dock App: 0x%lx (%s)\n", app
->icon_win
, app
->class);
152 void dock_configure()
161 RrMinsize(dock
->a_frame
, &minw
, &minh
);
163 dock
->w
= dock
->h
= 0;
166 for (it
= dock
->dock_apps
; it
; it
= it
->next
) {
167 ObDockApp
*app
= it
->data
;
168 switch (config_dock_orient
) {
169 case OB_ORIENTATION_HORZ
:
171 dock
->h
= MAX(dock
->h
, app
->h
);
173 case OB_ORIENTATION_VERT
:
174 dock
->w
= MAX(dock
->w
, app
->w
);
180 spot
= (config_dock_orient
== OB_ORIENTATION_HORZ
? minw
: minh
) / 2;
182 /* position the apps */
183 for (it
= dock
->dock_apps
; it
; it
= it
->next
) {
184 ObDockApp
*app
= it
->data
;
185 switch (config_dock_orient
) {
186 case OB_ORIENTATION_HORZ
:
188 app
->y
= (dock
->h
- app
->h
) / 2;
191 case OB_ORIENTATION_VERT
:
192 app
->x
= (dock
->w
- app
->w
) / 2;
198 XMoveWindow(ob_display
, app
->icon_win
, app
->x
, app
->y
);
201 /* used for calculating offsets */
202 dock
->w
+= ob_rr_theme
->bwidth
* 2;
203 dock
->h
+= ob_rr_theme
->bwidth
* 2;
205 a
= screen_physical_area();
207 /* calculate position */
208 if (config_dock_floating
) {
209 dock
->x
= config_dock_x
;
210 dock
->y
= config_dock_y
;
211 gravity
= NorthWestGravity
;
213 switch (config_dock_pos
) {
214 case OB_DIRECTION_NORTHWEST
:
217 gravity
= NorthWestGravity
;
219 case OB_DIRECTION_NORTH
:
220 dock
->x
= a
->width
/ 2;
222 gravity
= NorthGravity
;
224 case OB_DIRECTION_NORTHEAST
:
227 gravity
= NorthEastGravity
;
229 case OB_DIRECTION_WEST
:
231 dock
->y
= a
->height
/ 2;
232 gravity
= WestGravity
;
234 case OB_DIRECTION_EAST
:
236 dock
->y
= a
->height
/ 2;
237 gravity
= EastGravity
;
239 case OB_DIRECTION_SOUTHWEST
:
242 gravity
= SouthWestGravity
;
244 case OB_DIRECTION_SOUTH
:
245 dock
->x
= a
->width
/ 2;
247 gravity
= SouthGravity
;
249 case OB_DIRECTION_SOUTHEAST
:
252 gravity
= SouthEastGravity
;
261 dock
->x
-= dock
->w
/ 2;
263 case NorthEastGravity
:
265 case SouthEastGravity
:
273 dock
->y
-= dock
->h
/ 2;
275 case SouthWestGravity
:
277 case SouthEastGravity
:
282 if (config_dock_hide
&& dock
->hidden
) {
283 if (!config_dock_floating
) {
284 switch (config_dock_pos
) {
285 case OB_DIRECTION_NORTHWEST
:
286 switch (config_dock_orient
) {
287 case OB_ORIENTATION_HORZ
:
288 dock
->y
-= dock
->h
- ob_rr_theme
->bwidth
;
290 case OB_ORIENTATION_VERT
:
291 dock
->x
-= dock
->w
- ob_rr_theme
->bwidth
;
295 case OB_DIRECTION_NORTH
:
296 dock
->y
-= dock
->h
- ob_rr_theme
->bwidth
;
298 case OB_DIRECTION_NORTHEAST
:
299 switch (config_dock_orient
) {
300 case OB_ORIENTATION_HORZ
:
301 dock
->y
-= dock
->h
- ob_rr_theme
->bwidth
;
303 case OB_ORIENTATION_VERT
:
304 dock
->x
+= dock
->w
- ob_rr_theme
->bwidth
;
308 case OB_DIRECTION_WEST
:
309 dock
->x
-= dock
->w
- ob_rr_theme
->bwidth
;
311 case OB_DIRECTION_EAST
:
312 dock
->x
+= dock
->w
- ob_rr_theme
->bwidth
;
314 case OB_DIRECTION_SOUTHWEST
:
315 switch (config_dock_orient
) {
316 case OB_ORIENTATION_HORZ
:
317 dock
->y
+= dock
->h
- ob_rr_theme
->bwidth
;
319 case OB_ORIENTATION_VERT
:
320 dock
->x
-= dock
->w
- ob_rr_theme
->bwidth
;
323 case OB_DIRECTION_SOUTH
:
324 dock
->y
+= dock
->h
- ob_rr_theme
->bwidth
;
326 case OB_DIRECTION_SOUTHEAST
:
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
;
340 if (!config_dock_floating
&& config_dock_hide
) {
341 strw
= strh
= ob_rr_theme
->bwidth
;
348 if (config_dock_floating
) {
349 STRUT_SET(dock_strut
, 0, 0, 0, 0);
351 switch (config_dock_pos
) {
352 case OB_DIRECTION_NORTHWEST
:
353 switch (config_dock_orient
) {
354 case OB_ORIENTATION_HORZ
:
355 STRUT_SET(dock_strut
, 0, strh
, 0, 0);
357 case OB_ORIENTATION_VERT
:
358 STRUT_SET(dock_strut
, strw
, 0, 0, 0);
362 case OB_DIRECTION_NORTH
:
363 STRUT_SET(dock_strut
, 0, strh
, 0, 0);
365 case OB_DIRECTION_NORTHEAST
:
366 switch (config_dock_orient
) {
367 case OB_ORIENTATION_HORZ
:
368 STRUT_SET(dock_strut
, 0, strh
, 0, 0);
370 case OB_ORIENTATION_VERT
:
371 STRUT_SET(dock_strut
, 0, 0, strw
, 0);
375 case OB_DIRECTION_WEST
:
376 STRUT_SET(dock_strut
, strw
, 0, 0, 0);
378 case OB_DIRECTION_EAST
:
379 STRUT_SET(dock_strut
, 0, 0, strw
, 0);
381 case OB_DIRECTION_SOUTHWEST
:
382 switch (config_dock_orient
) {
383 case OB_ORIENTATION_HORZ
:
384 STRUT_SET(dock_strut
, 0, 0, 0, strh
);
386 case OB_ORIENTATION_VERT
:
387 STRUT_SET(dock_strut
, strw
, 0, 0, 0);
391 case OB_DIRECTION_SOUTH
:
392 STRUT_SET(dock_strut
, 0, 0, 0, strh
);
394 case OB_DIRECTION_SOUTHEAST
:
395 switch (config_dock_orient
) {
396 case OB_ORIENTATION_HORZ
:
397 STRUT_SET(dock_strut
, 0, 0, 0, strh
);
399 case OB_ORIENTATION_VERT
:
400 STRUT_SET(dock_strut
, 0, 0, strw
, 0);
410 /* not used for actually sizing shit */
411 dock
->w
-= ob_rr_theme
->bwidth
* 2;
412 dock
->h
-= ob_rr_theme
->bwidth
* 2;
414 if (dock
->w
> 0 && dock
->h
> 0) {
415 XMoveResizeWindow(ob_display
, dock
->frame
,
416 dock
->x
, dock
->y
, dock
->w
, dock
->h
);
418 RrPaint(dock
->a_frame
, dock
->frame
, dock
->w
, dock
->h
);
419 XMapWindow(ob_display
, dock
->frame
);
421 XUnmapWindow(ob_display
, dock
->frame
);
423 /* but they are useful outside of this function! */
424 dock
->w
+= ob_rr_theme
->bwidth
* 2;
425 dock
->h
+= ob_rr_theme
->bwidth
* 2;
427 screen_update_areas();
430 void dock_app_configure(ObDockApp
*app
, gint w
, gint h
)
437 void dock_app_drag(ObDockApp
*app
, XMotionEvent
*e
)
439 ObDockApp
*over
= NULL
;
448 /* are we on top of the dock? */
449 if (!(x
>= dock
->x
&&
451 x
< dock
->x
+ dock
->w
&&
452 y
< dock
->y
+ dock
->h
))
458 /* which dock app are we on top of? */
460 for (it
= dock
->dock_apps
; it
; it
= it
->next
) {
462 switch (config_dock_orient
) {
463 case OB_ORIENTATION_HORZ
:
464 if (x
>= over
->x
&& x
< over
->x
+ over
->w
)
467 case OB_ORIENTATION_VERT
:
468 if (y
>= over
->y
&& y
< over
->y
+ over
->h
)
472 /* dont go to it->next! */
475 if (!it
|| app
== over
) return;
480 switch (config_dock_orient
) {
481 case OB_ORIENTATION_HORZ
:
482 after
= (x
> over
->w
/ 2);
484 case OB_ORIENTATION_VERT
:
485 after
= (y
> over
->h
/ 2);
489 /* remove before doing the it->next! */
490 dock
->dock_apps
= g_list_remove(dock
->dock_apps
, app
);
492 if (after
) it
= it
->next
;
494 dock
->dock_apps
= g_list_insert_before(dock
->dock_apps
, it
, app
);
498 static void hide_timeout(void *n
)
501 timer_stop(dock
->hide_timer
);
502 dock
->hide_timer
= NULL
;
509 void dock_hide(gboolean hide
)
511 if (dock
->hidden
== hide
|| !config_dock_hide
)
515 dock
->hidden
= FALSE
;
518 /* if was hiding, stop it */
519 if (dock
->hide_timer
) {
520 timer_stop(dock
->hide_timer
);
521 dock
->hide_timer
= NULL
;
524 g_assert(!dock
->hide_timer
);
525 dock
->hide_timer
= timer_start(config_dock_hide_timeout
* 1000,
526 (ObTimeoutHandler
)hide_timeout
,