8 #include "render/theme.h"
10 #define DOCK_EVENT_MASK (ButtonPressMask | ButtonReleaseMask | \
11 EnterWindowMask | LeaveWindowMask)
12 #define DOCKAPP_EVENT_MASK (StructureNotifyMask)
16 StrutPartial dock_strut
;
20 XSetWindowAttributes attrib
;
22 STRUT_PARTIAL_SET(dock_strut
, 0, 0, 0, 0,
23 0, 0, 0, 0, 0, 0, 0, 0);
25 dock
= g_new0(ObDock
, 1);
26 dock
->obwin
.type
= Window_Dock
;
30 attrib
.event_mask
= DOCK_EVENT_MASK
;
31 attrib
.override_redirect
= True
;
32 dock
->frame
= XCreateWindow(ob_display
, RootWindow(ob_display
, ob_screen
),
34 RrDepth(ob_rr_inst
), InputOutput
,
36 CWOverrideRedirect
| CWEventMask
,
38 dock
->a_frame
= RrAppearanceCopy(ob_rr_theme
->a_unfocused_title
);
39 XSetWindowBorder(ob_display
, dock
->frame
,
40 RrColorPixel(ob_rr_theme
->b_color
));
41 XSetWindowBorderWidth(ob_display
, dock
->frame
, ob_rr_theme
->bwidth
);
43 g_hash_table_insert(window_map
, &dock
->frame
, dock
);
44 stacking_add(DOCK_AS_WINDOW(dock
));
45 stacking_raise(DOCK_AS_WINDOW(dock
));
50 XDestroyWindow(ob_display
, dock
->frame
);
51 RrAppearanceFree(dock
->a_frame
);
52 g_hash_table_remove(window_map
, &dock
->frame
);
53 stacking_remove(dock
);
56 void dock_add(Window win
, XWMHints
*wmhints
)
59 XWindowAttributes attrib
;
62 app
= g_new0(ObDockApp
, 1);
63 app
->obwin
.type
= Window_DockApp
;
65 app
->icon_win
= (wmhints
->flags
& IconWindowHint
) ?
66 wmhints
->icon_window
: win
;
68 if (PROP_GETSS(app
->win
, wm_class
, locale
, &data
)) {
70 app
->name
= g_strdup(data
[0]);
72 app
->class = g_strdup(data
[1]);
77 if (app
->name
== NULL
) app
->name
= g_strdup("");
78 if (app
->class == NULL
) app
->class = g_strdup("");
80 if (XGetWindowAttributes(ob_display
, app
->icon_win
, &attrib
)) {
81 app
->w
= attrib
.width
;
82 app
->h
= attrib
.height
;
87 dock
->dock_apps
= g_list_append(dock
->dock_apps
, app
);
90 XReparentWindow(ob_display
, app
->icon_win
, dock
->frame
, app
->x
, app
->y
);
92 This is the same case as in frame.c for client windows. When Openbox is
93 starting, the window is already mapped so we see unmap events occur for
94 it. There are 2 unmap events generated that we see, one with the 'event'
95 member set the root window, and one set to the client, but both get
96 handled and need to be ignored.
98 if (ob_state() == OB_STATE_STARTING
)
99 app
->ignore_unmaps
+= 2;
101 if (app
->win
!= app
->icon_win
) {
102 /* have to map it so that it can be re-managed on a restart */
103 XMoveWindow(ob_display
, app
->win
, -1000, -1000);
104 XMapWindow(ob_display
, app
->win
);
106 XMapWindow(ob_display
, app
->icon_win
);
107 XSync(ob_display
, False
);
109 /* specify that if we exit, the window should not be destroyed and should
110 be reparented back to root automatically */
111 XChangeSaveSet(ob_display
, app
->icon_win
, SetModeInsert
);
112 XSelectInput(ob_display
, app
->icon_win
, DOCKAPP_EVENT_MASK
);
114 grab_button_full(2, 0, app
->icon_win
,
115 ButtonPressMask
| ButtonReleaseMask
| ButtonMotionMask
,
116 GrabModeAsync
, OB_CURSOR_MOVE
);
118 g_hash_table_insert(window_map
, &app
->icon_win
, app
);
120 ob_debug("Managed Dock App: 0x%lx (%s)\n", app
->icon_win
, app
->class);
123 void dock_remove_all()
125 while (dock
->dock_apps
)
126 dock_remove(dock
->dock_apps
->data
, TRUE
);
129 void dock_remove(ObDockApp
*app
, gboolean reparent
)
131 ungrab_button(2, 0, app
->icon_win
);
132 XSelectInput(ob_display
, app
->icon_win
, NoEventMask
);
133 /* remove the window from our save set */
134 XChangeSaveSet(ob_display
, app
->icon_win
, SetModeDelete
);
135 XSync(ob_display
, False
);
137 g_hash_table_remove(window_map
, &app
->icon_win
);
140 XReparentWindow(ob_display
, app
->icon_win
,
141 RootWindow(ob_display
, ob_screen
), app
->x
, app
->y
);
143 dock
->dock_apps
= g_list_remove(dock
->dock_apps
, app
);
146 ob_debug("Unmanaged Dock App: 0x%lx (%s)\n", app
->icon_win
, app
->class);
153 void dock_configure()
162 RrMinsize(dock
->a_frame
, &minw
, &minh
);
164 dock
->w
= dock
->h
= 0;
167 for (it
= dock
->dock_apps
; it
; it
= it
->next
) {
168 ObDockApp
*app
= it
->data
;
169 switch (config_dock_orient
) {
170 case OB_ORIENTATION_HORZ
:
172 dock
->h
= MAX(dock
->h
, app
->h
);
174 case OB_ORIENTATION_VERT
:
175 dock
->w
= MAX(dock
->w
, app
->w
);
181 spot
= (config_dock_orient
== OB_ORIENTATION_HORZ
? minw
: minh
) / 2;
183 /* position the apps */
184 for (it
= dock
->dock_apps
; it
; it
= it
->next
) {
185 ObDockApp
*app
= it
->data
;
186 switch (config_dock_orient
) {
187 case OB_ORIENTATION_HORZ
:
189 app
->y
= (dock
->h
- app
->h
) / 2;
192 case OB_ORIENTATION_VERT
:
193 app
->x
= (dock
->w
- app
->w
) / 2;
199 XMoveWindow(ob_display
, app
->icon_win
, app
->x
, app
->y
);
202 /* used for calculating offsets */
203 dock
->w
+= ob_rr_theme
->bwidth
* 2;
204 dock
->h
+= ob_rr_theme
->bwidth
* 2;
206 a
= screen_physical_area();
208 /* calculate position */
209 if (config_dock_floating
) {
210 dock
->x
= config_dock_x
;
211 dock
->y
= config_dock_y
;
212 gravity
= NorthWestGravity
;
214 switch (config_dock_pos
) {
215 case OB_DIRECTION_NORTHWEST
:
218 gravity
= NorthWestGravity
;
220 case OB_DIRECTION_NORTH
:
221 dock
->x
= a
->width
/ 2;
223 gravity
= NorthGravity
;
225 case OB_DIRECTION_NORTHEAST
:
228 gravity
= NorthEastGravity
;
230 case OB_DIRECTION_WEST
:
232 dock
->y
= a
->height
/ 2;
233 gravity
= WestGravity
;
235 case OB_DIRECTION_EAST
:
237 dock
->y
= a
->height
/ 2;
238 gravity
= EastGravity
;
240 case OB_DIRECTION_SOUTHWEST
:
243 gravity
= SouthWestGravity
;
245 case OB_DIRECTION_SOUTH
:
246 dock
->x
= a
->width
/ 2;
248 gravity
= SouthGravity
;
250 case OB_DIRECTION_SOUTHEAST
:
253 gravity
= SouthEastGravity
;
262 dock
->x
-= dock
->w
/ 2;
264 case NorthEastGravity
:
266 case SouthEastGravity
:
274 dock
->y
-= dock
->h
/ 2;
276 case SouthWestGravity
:
278 case SouthEastGravity
:
283 if (config_dock_hide
&& dock
->hidden
) {
284 if (!config_dock_floating
) {
285 switch (config_dock_pos
) {
286 case OB_DIRECTION_NORTHWEST
:
287 switch (config_dock_orient
) {
288 case OB_ORIENTATION_HORZ
:
289 dock
->y
-= dock
->h
- ob_rr_theme
->bwidth
;
291 case OB_ORIENTATION_VERT
:
292 dock
->x
-= dock
->w
- ob_rr_theme
->bwidth
;
296 case OB_DIRECTION_NORTH
:
297 dock
->y
-= dock
->h
- ob_rr_theme
->bwidth
;
299 case OB_DIRECTION_NORTHEAST
:
300 switch (config_dock_orient
) {
301 case OB_ORIENTATION_HORZ
:
302 dock
->y
-= dock
->h
- ob_rr_theme
->bwidth
;
304 case OB_ORIENTATION_VERT
:
305 dock
->x
+= dock
->w
- ob_rr_theme
->bwidth
;
309 case OB_DIRECTION_WEST
:
310 dock
->x
-= dock
->w
- ob_rr_theme
->bwidth
;
312 case OB_DIRECTION_EAST
:
313 dock
->x
+= dock
->w
- ob_rr_theme
->bwidth
;
315 case OB_DIRECTION_SOUTHWEST
:
316 switch (config_dock_orient
) {
317 case OB_ORIENTATION_HORZ
:
318 dock
->y
+= dock
->h
- ob_rr_theme
->bwidth
;
320 case OB_ORIENTATION_VERT
:
321 dock
->x
-= dock
->w
- ob_rr_theme
->bwidth
;
324 case OB_DIRECTION_SOUTH
:
325 dock
->y
+= dock
->h
- ob_rr_theme
->bwidth
;
327 case OB_DIRECTION_SOUTHEAST
:
328 switch (config_dock_orient
) {
329 case OB_ORIENTATION_HORZ
:
330 dock
->y
+= dock
->h
- ob_rr_theme
->bwidth
;
332 case OB_ORIENTATION_VERT
:
333 dock
->x
+= dock
->w
- ob_rr_theme
->bwidth
;
341 if (!config_dock_floating
&& config_dock_hide
) {
342 strw
= ob_rr_theme
->bwidth
;
343 strh
= ob_rr_theme
->bwidth
;
350 if (config_dock_floating
) {
351 STRUT_PARTIAL_SET(dock_strut
, 0, 0, 0, 0,
352 0, 0, 0, 0, 0, 0, 0, 0);
354 switch (config_dock_pos
) {
355 case OB_DIRECTION_NORTHWEST
:
356 switch (config_dock_orient
) {
357 case OB_ORIENTATION_HORZ
:
358 STRUT_PARTIAL_SET(dock_strut
, 0, strh
, 0, 0,
359 0, 0, dock
->x
, dock
->x
+ dock
->w
- 1,
362 case OB_ORIENTATION_VERT
:
363 STRUT_PARTIAL_SET(dock_strut
, strw
, 0, 0, 0,
364 dock
->y
, dock
->y
+ dock
->h
- 1,
369 case OB_DIRECTION_NORTH
:
370 STRUT_PARTIAL_SET(dock_strut
, 0, strh
, 0, 0,
371 dock
->x
, dock
->x
+ dock
->w
- 1,
374 case OB_DIRECTION_NORTHEAST
:
375 switch (config_dock_orient
) {
376 case OB_ORIENTATION_HORZ
:
377 STRUT_PARTIAL_SET(dock_strut
, 0, strh
, 0, 0,
378 0, 0, dock
->x
, dock
->x
+ dock
->w
-1,
381 case OB_ORIENTATION_VERT
:
382 STRUT_PARTIAL_SET(dock_strut
, 0, 0, strw
, 0,
384 dock
->y
, dock
->y
+ dock
->h
- 1, 0, 0);
388 case OB_DIRECTION_WEST
:
389 STRUT_PARTIAL_SET(dock_strut
, strw
, 0, 0, 0,
390 dock
->y
, dock
->y
+ dock
->h
- 1,
393 case OB_DIRECTION_EAST
:
394 STRUT_PARTIAL_SET(dock_strut
, 0, 0, strw
, 0,
396 dock
->y
, dock
->y
+ dock
->h
- 1, 0, 0);
398 case OB_DIRECTION_SOUTHWEST
:
399 switch (config_dock_orient
) {
400 case OB_ORIENTATION_HORZ
:
401 STRUT_PARTIAL_SET(dock_strut
, 0, 0, 0, strh
,
403 dock
->x
, dock
->x
+ dock
->w
- 1);
405 case OB_ORIENTATION_VERT
:
406 STRUT_PARTIAL_SET(dock_strut
, strw
, 0, 0, 0,
407 dock
->y
, dock
->y
+ dock
->h
- 1,
412 case OB_DIRECTION_SOUTH
:
413 STRUT_PARTIAL_SET(dock_strut
, 0, 0, 0, strh
,
415 dock
->x
, dock
->x
+ dock
->w
- 1);
417 case OB_DIRECTION_SOUTHEAST
:
418 switch (config_dock_orient
) {
419 case OB_ORIENTATION_HORZ
:
420 STRUT_PARTIAL_SET(dock_strut
, 0, 0, 0, strh
,
422 dock
->x
, dock
->x
+ dock
->w
- 1);
424 case OB_ORIENTATION_VERT
:
425 STRUT_PARTIAL_SET(dock_strut
, 0, 0, strw
, 0,
427 dock
->y
, dock
->y
+ dock
->h
- 1, 0, 0);
437 /* not used for actually sizing shit */
438 dock
->w
-= ob_rr_theme
->bwidth
* 2;
439 dock
->h
-= ob_rr_theme
->bwidth
* 2;
441 if (dock
->w
> 0 && dock
->h
> 0) {
442 XMoveResizeWindow(ob_display
, dock
->frame
,
443 dock
->x
, dock
->y
, dock
->w
, dock
->h
);
445 RrPaint(dock
->a_frame
, dock
->frame
, dock
->w
, dock
->h
);
446 XMapWindow(ob_display
, dock
->frame
);
448 XUnmapWindow(ob_display
, dock
->frame
);
450 /* but they are useful outside of this function! */
451 dock
->w
+= ob_rr_theme
->bwidth
* 2;
452 dock
->h
+= ob_rr_theme
->bwidth
* 2;
454 screen_update_areas();
457 void dock_app_configure(ObDockApp
*app
, gint w
, gint h
)
464 void dock_app_drag(ObDockApp
*app
, XMotionEvent
*e
)
466 ObDockApp
*over
= NULL
;
475 /* are we on top of the dock? */
476 if (!(x
>= dock
->x
&&
478 x
< dock
->x
+ dock
->w
&&
479 y
< dock
->y
+ dock
->h
))
485 /* which dock app are we on top of? */
487 for (it
= dock
->dock_apps
; it
; it
= it
->next
) {
489 switch (config_dock_orient
) {
490 case OB_ORIENTATION_HORZ
:
491 if (x
>= over
->x
&& x
< over
->x
+ over
->w
)
494 case OB_ORIENTATION_VERT
:
495 if (y
>= over
->y
&& y
< over
->y
+ over
->h
)
499 /* dont go to it->next! */
502 if (!it
|| app
== over
) return;
507 switch (config_dock_orient
) {
508 case OB_ORIENTATION_HORZ
:
509 after
= (x
> over
->w
/ 2);
511 case OB_ORIENTATION_VERT
:
512 after
= (y
> over
->h
/ 2);
516 /* remove before doing the it->next! */
517 dock
->dock_apps
= g_list_remove(dock
->dock_apps
, app
);
519 if (after
) it
= it
->next
;
521 dock
->dock_apps
= g_list_insert_before(dock
->dock_apps
, it
, app
);
525 static void hide_timeout(void *n
)
528 timer_stop(dock
->hide_timer
);
529 dock
->hide_timer
= NULL
;
536 void dock_hide(gboolean hide
)
538 if (dock
->hidden
== hide
|| !config_dock_hide
)
542 dock
->hidden
= FALSE
;
545 /* if was hiding, stop it */
546 if (dock
->hide_timer
) {
547 timer_stop(dock
->hide_timer
);
548 dock
->hide_timer
= NULL
;
551 g_assert(!dock
->hide_timer
);
552 dock
->hide_timer
= timer_start(config_dock_hide_timeout
* 1000,
553 (ObTimeoutHandler
)hide_timeout
,