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
;
21 XSetWindowAttributes attrib
;
23 STRUT_PARTIAL_SET(dock_strut
, 0, 0, 0, 0,
24 0, 0, 0, 0, 0, 0, 0, 0);
26 dock
= g_new0(ObDock
, 1);
27 dock
->obwin
.type
= Window_Dock
;
31 attrib
.event_mask
= DOCK_EVENT_MASK
;
32 attrib
.override_redirect
= True
;
33 dock
->frame
= XCreateWindow(ob_display
, RootWindow(ob_display
, ob_screen
),
35 RrDepth(ob_rr_inst
), InputOutput
,
37 CWOverrideRedirect
| CWEventMask
,
39 dock
->a_frame
= RrAppearanceCopy(ob_rr_theme
->a_unfocused_title
);
40 XSetWindowBorder(ob_display
, dock
->frame
,
41 RrColorPixel(ob_rr_theme
->b_color
));
42 XSetWindowBorderWidth(ob_display
, dock
->frame
, ob_rr_theme
->bwidth
);
44 g_hash_table_insert(window_map
, &dock
->frame
, dock
);
45 stacking_add(DOCK_AS_WINDOW(dock
));
46 stacking_raise(DOCK_AS_WINDOW(dock
));
51 XDestroyWindow(ob_display
, dock
->frame
);
52 RrAppearanceFree(dock
->a_frame
);
53 g_hash_table_remove(window_map
, &dock
->frame
);
54 stacking_remove(dock
);
57 void dock_add(Window win
, XWMHints
*wmhints
)
60 XWindowAttributes attrib
;
63 app
= g_new0(ObDockApp
, 1);
64 app
->obwin
.type
= Window_DockApp
;
66 app
->icon_win
= (wmhints
->flags
& IconWindowHint
) ?
67 wmhints
->icon_window
: win
;
69 if (PROP_GETSS(app
->win
, wm_class
, locale
, &data
)) {
71 app
->name
= g_strdup(data
[0]);
73 app
->class = g_strdup(data
[1]);
78 if (app
->name
== NULL
) app
->name
= g_strdup("");
79 if (app
->class == NULL
) app
->class = g_strdup("");
81 if (XGetWindowAttributes(ob_display
, app
->icon_win
, &attrib
)) {
82 app
->w
= attrib
.width
;
83 app
->h
= attrib
.height
;
88 dock
->dock_apps
= g_list_append(dock
->dock_apps
, app
);
91 XReparentWindow(ob_display
, app
->icon_win
, dock
->frame
, app
->x
, app
->y
);
93 This is the same case as in frame.c for client windows. When Openbox is
94 starting, the window is already mapped so we see unmap events occur for
95 it. There are 2 unmap events generated that we see, one with the 'event'
96 member set the root window, and one set to the client, but both get
97 handled and need to be ignored.
99 if (ob_state() == OB_STATE_STARTING
)
100 app
->ignore_unmaps
+= 2;
102 if (app
->win
!= app
->icon_win
) {
103 /* have to map it so that it can be re-managed on a restart */
104 XMoveWindow(ob_display
, app
->win
, -1000, -1000);
105 XMapWindow(ob_display
, app
->win
);
107 XMapWindow(ob_display
, app
->icon_win
);
108 XSync(ob_display
, False
);
110 /* specify that if we exit, the window should not be destroyed and should
111 be reparented back to root automatically */
112 XChangeSaveSet(ob_display
, app
->icon_win
, SetModeInsert
);
113 XSelectInput(ob_display
, app
->icon_win
, DOCKAPP_EVENT_MASK
);
115 grab_button_full(2, 0, app
->icon_win
,
116 ButtonPressMask
| ButtonReleaseMask
| ButtonMotionMask
,
117 GrabModeAsync
, OB_CURSOR_MOVE
);
119 g_hash_table_insert(window_map
, &app
->icon_win
, app
);
121 ob_debug("Managed Dock App: 0x%lx (%s)\n", app
->icon_win
, app
->class);
124 void dock_remove_all()
126 while (dock
->dock_apps
)
127 dock_remove(dock
->dock_apps
->data
, TRUE
);
130 void dock_remove(ObDockApp
*app
, gboolean reparent
)
132 ungrab_button(2, 0, app
->icon_win
);
133 XSelectInput(ob_display
, app
->icon_win
, NoEventMask
);
134 /* remove the window from our save set */
135 XChangeSaveSet(ob_display
, app
->icon_win
, SetModeDelete
);
136 XSync(ob_display
, False
);
138 g_hash_table_remove(window_map
, &app
->icon_win
);
141 XReparentWindow(ob_display
, app
->icon_win
,
142 RootWindow(ob_display
, ob_screen
), app
->x
, app
->y
);
144 dock
->dock_apps
= g_list_remove(dock
->dock_apps
, app
);
147 ob_debug("Unmanaged Dock App: 0x%lx (%s)\n", app
->icon_win
, app
->class);
154 void dock_configure()
163 RrMinsize(dock
->a_frame
, &minw
, &minh
);
165 dock
->w
= dock
->h
= 0;
168 for (it
= dock
->dock_apps
; it
; it
= it
->next
) {
169 ObDockApp
*app
= it
->data
;
170 switch (config_dock_orient
) {
171 case OB_ORIENTATION_HORZ
:
173 dock
->h
= MAX(dock
->h
, app
->h
);
175 case OB_ORIENTATION_VERT
:
176 dock
->w
= MAX(dock
->w
, app
->w
);
182 spot
= (config_dock_orient
== OB_ORIENTATION_HORZ
? minw
: minh
) / 2;
184 /* position the apps */
185 for (it
= dock
->dock_apps
; it
; it
= it
->next
) {
186 ObDockApp
*app
= it
->data
;
187 switch (config_dock_orient
) {
188 case OB_ORIENTATION_HORZ
:
190 app
->y
= (dock
->h
- app
->h
) / 2;
193 case OB_ORIENTATION_VERT
:
194 app
->x
= (dock
->w
- app
->w
) / 2;
200 XMoveWindow(ob_display
, app
->icon_win
, app
->x
, app
->y
);
203 /* used for calculating offsets */
204 dock
->w
+= ob_rr_theme
->bwidth
* 2;
205 dock
->h
+= ob_rr_theme
->bwidth
* 2;
207 a
= screen_physical_area();
209 /* calculate position */
210 if (config_dock_floating
) {
211 dock
->x
= config_dock_x
;
212 dock
->y
= config_dock_y
;
213 gravity
= NorthWestGravity
;
215 switch (config_dock_pos
) {
216 case OB_DIRECTION_NORTHWEST
:
219 gravity
= NorthWestGravity
;
221 case OB_DIRECTION_NORTH
:
222 dock
->x
= a
->width
/ 2;
224 gravity
= NorthGravity
;
226 case OB_DIRECTION_NORTHEAST
:
229 gravity
= NorthEastGravity
;
231 case OB_DIRECTION_WEST
:
233 dock
->y
= a
->height
/ 2;
234 gravity
= WestGravity
;
236 case OB_DIRECTION_EAST
:
238 dock
->y
= a
->height
/ 2;
239 gravity
= EastGravity
;
241 case OB_DIRECTION_SOUTHWEST
:
244 gravity
= SouthWestGravity
;
246 case OB_DIRECTION_SOUTH
:
247 dock
->x
= a
->width
/ 2;
249 gravity
= SouthGravity
;
251 case OB_DIRECTION_SOUTHEAST
:
254 gravity
= SouthEastGravity
;
263 dock
->x
-= dock
->w
/ 2;
265 case NorthEastGravity
:
267 case SouthEastGravity
:
275 dock
->y
-= dock
->h
/ 2;
277 case SouthWestGravity
:
279 case SouthEastGravity
:
284 if (config_dock_hide
&& dock
->hidden
) {
285 if (!config_dock_floating
) {
286 switch (config_dock_pos
) {
287 case OB_DIRECTION_NORTHWEST
:
288 switch (config_dock_orient
) {
289 case OB_ORIENTATION_HORZ
:
290 dock
->y
-= dock
->h
- ob_rr_theme
->bwidth
;
292 case OB_ORIENTATION_VERT
:
293 dock
->x
-= dock
->w
- ob_rr_theme
->bwidth
;
297 case OB_DIRECTION_NORTH
:
298 dock
->y
-= dock
->h
- ob_rr_theme
->bwidth
;
300 case OB_DIRECTION_NORTHEAST
:
301 switch (config_dock_orient
) {
302 case OB_ORIENTATION_HORZ
:
303 dock
->y
-= dock
->h
- ob_rr_theme
->bwidth
;
305 case OB_ORIENTATION_VERT
:
306 dock
->x
+= dock
->w
- ob_rr_theme
->bwidth
;
310 case OB_DIRECTION_WEST
:
311 dock
->x
-= dock
->w
- ob_rr_theme
->bwidth
;
313 case OB_DIRECTION_EAST
:
314 dock
->x
+= dock
->w
- ob_rr_theme
->bwidth
;
316 case OB_DIRECTION_SOUTHWEST
:
317 switch (config_dock_orient
) {
318 case OB_ORIENTATION_HORZ
:
319 dock
->y
+= dock
->h
- ob_rr_theme
->bwidth
;
321 case OB_ORIENTATION_VERT
:
322 dock
->x
-= dock
->w
- ob_rr_theme
->bwidth
;
325 case OB_DIRECTION_SOUTH
:
326 dock
->y
+= dock
->h
- ob_rr_theme
->bwidth
;
328 case OB_DIRECTION_SOUTHEAST
:
329 switch (config_dock_orient
) {
330 case OB_ORIENTATION_HORZ
:
331 dock
->y
+= dock
->h
- ob_rr_theme
->bwidth
;
333 case OB_ORIENTATION_VERT
:
334 dock
->x
+= dock
->w
- ob_rr_theme
->bwidth
;
342 if (!config_dock_floating
&& config_dock_hide
) {
343 strw
= ob_rr_theme
->bwidth
;
344 strh
= ob_rr_theme
->bwidth
;
351 if (config_dock_floating
) {
352 STRUT_PARTIAL_SET(dock_strut
, 0, 0, 0, 0,
353 0, 0, 0, 0, 0, 0, 0, 0);
355 switch (config_dock_pos
) {
356 case OB_DIRECTION_NORTHWEST
:
357 switch (config_dock_orient
) {
358 case OB_ORIENTATION_HORZ
:
359 STRUT_PARTIAL_SET(dock_strut
, 0, strh
, 0, 0,
360 0, 0, dock
->x
, dock
->x
+ dock
->w
- 1,
363 case OB_ORIENTATION_VERT
:
364 STRUT_PARTIAL_SET(dock_strut
, strw
, 0, 0, 0,
365 dock
->y
, dock
->y
+ dock
->h
- 1,
370 case OB_DIRECTION_NORTH
:
371 STRUT_PARTIAL_SET(dock_strut
, 0, strh
, 0, 0,
372 dock
->x
, dock
->x
+ dock
->w
- 1,
375 case OB_DIRECTION_NORTHEAST
:
376 switch (config_dock_orient
) {
377 case OB_ORIENTATION_HORZ
:
378 STRUT_PARTIAL_SET(dock_strut
, 0, strh
, 0, 0,
379 0, 0, dock
->x
, dock
->x
+ dock
->w
-1,
382 case OB_ORIENTATION_VERT
:
383 STRUT_PARTIAL_SET(dock_strut
, 0, 0, strw
, 0,
385 dock
->y
, dock
->y
+ dock
->h
- 1, 0, 0);
389 case OB_DIRECTION_WEST
:
390 STRUT_PARTIAL_SET(dock_strut
, strw
, 0, 0, 0,
391 dock
->y
, dock
->y
+ dock
->h
- 1,
394 case OB_DIRECTION_EAST
:
395 STRUT_PARTIAL_SET(dock_strut
, 0, 0, strw
, 0,
397 dock
->y
, dock
->y
+ dock
->h
- 1, 0, 0);
399 case OB_DIRECTION_SOUTHWEST
:
400 switch (config_dock_orient
) {
401 case OB_ORIENTATION_HORZ
:
402 STRUT_PARTIAL_SET(dock_strut
, 0, 0, 0, strh
,
404 dock
->x
, dock
->x
+ dock
->w
- 1);
406 case OB_ORIENTATION_VERT
:
407 STRUT_PARTIAL_SET(dock_strut
, strw
, 0, 0, 0,
408 dock
->y
, dock
->y
+ dock
->h
- 1,
413 case OB_DIRECTION_SOUTH
:
414 STRUT_PARTIAL_SET(dock_strut
, 0, 0, 0, strh
,
416 dock
->x
, dock
->x
+ dock
->w
- 1);
418 case OB_DIRECTION_SOUTHEAST
:
419 switch (config_dock_orient
) {
420 case OB_ORIENTATION_HORZ
:
421 STRUT_PARTIAL_SET(dock_strut
, 0, 0, 0, strh
,
423 dock
->x
, dock
->x
+ dock
->w
- 1);
425 case OB_ORIENTATION_VERT
:
426 STRUT_PARTIAL_SET(dock_strut
, 0, 0, strw
, 0,
428 dock
->y
, dock
->y
+ dock
->h
- 1, 0, 0);
438 /* not used for actually sizing shit */
439 dock
->w
-= ob_rr_theme
->bwidth
* 2;
440 dock
->h
-= ob_rr_theme
->bwidth
* 2;
442 if (dock
->w
> 0 && dock
->h
> 0) {
443 XMoveResizeWindow(ob_display
, dock
->frame
,
444 dock
->x
, dock
->y
, dock
->w
, dock
->h
);
446 RrPaint(dock
->a_frame
, dock
->frame
, dock
->w
, dock
->h
);
447 XMapWindow(ob_display
, dock
->frame
);
449 XUnmapWindow(ob_display
, dock
->frame
);
451 /* but they are useful outside of this function! */
452 dock
->w
+= ob_rr_theme
->bwidth
* 2;
453 dock
->h
+= ob_rr_theme
->bwidth
* 2;
455 screen_update_areas();
458 void dock_app_configure(ObDockApp
*app
, gint w
, gint h
)
465 void dock_app_drag(ObDockApp
*app
, XMotionEvent
*e
)
467 ObDockApp
*over
= NULL
;
476 /* are we on top of the dock? */
477 if (!(x
>= dock
->x
&&
479 x
< dock
->x
+ dock
->w
&&
480 y
< dock
->y
+ dock
->h
))
486 /* which dock app are we on top of? */
488 for (it
= dock
->dock_apps
; it
; it
= it
->next
) {
490 switch (config_dock_orient
) {
491 case OB_ORIENTATION_HORZ
:
492 if (x
>= over
->x
&& x
< over
->x
+ over
->w
)
495 case OB_ORIENTATION_VERT
:
496 if (y
>= over
->y
&& y
< over
->y
+ over
->h
)
500 /* dont go to it->next! */
503 if (!it
|| app
== over
) return;
508 switch (config_dock_orient
) {
509 case OB_ORIENTATION_HORZ
:
510 after
= (x
> over
->w
/ 2);
512 case OB_ORIENTATION_VERT
:
513 after
= (y
> over
->h
/ 2);
517 /* remove before doing the it->next! */
518 dock
->dock_apps
= g_list_remove(dock
->dock_apps
, app
);
520 if (after
) it
= it
->next
;
522 dock
->dock_apps
= g_list_insert_before(dock
->dock_apps
, it
, app
);
526 static gboolean
hide_timeout(gpointer data
)
532 return FALSE
; /* don't repeat */
535 void dock_hide(gboolean hide
)
537 if (dock
->hidden
== hide
|| !config_dock_hide
)
541 dock
->hidden
= FALSE
;
544 /* if was hiding, stop it */
545 ob_main_loop_timeout_remove(ob_main_loop
, hide_timeout
);
547 ob_main_loop_timeout_add(ob_main_loop
, config_dock_hide_timeout
* 1000,
548 hide_timeout
, NULL
, NULL
);