6 #include "render/theme.h"
7 #include "render/render.h"
9 #define SLIT_EVENT_MASK (ButtonPressMask | ButtonReleaseMask | \
10 EnterWindowMask | LeaveWindowMask)
11 #define SLITAPP_EVENT_MASK (StructureNotifyMask)
16 /* user-requested position stuff */
21 /* actual position (when not auto-hidden) */
36 GHashTable
*slit_map
= NULL
;
37 GHashTable
*slit_app_map
= NULL
;
42 static guint slit_hide_timeout
= 3000; /* XXX make a config option */
44 static void slit_configure(Slit
*self
);
48 XSetWindowAttributes attrib
;
51 slit_map
= g_hash_table_new(g_int_hash
, g_int_equal
);
52 slit_app_map
= g_hash_table_new(g_int_hash
, g_int_equal
);
55 slit
= g_new0(struct Slit
, nslits
);
57 for (i
= 0; i
< nslits
; ++i
) {
60 slit
[i
].hidden
= TRUE
;
61 slit
[i
].pos
= SlitPos_TopRight
;
63 attrib
.event_mask
= SLIT_EVENT_MASK
;
64 attrib
.override_redirect
= True
;
65 slit
[i
].frame
= XCreateWindow(ob_display
, ob_root
, 0, 0, 1, 1, 0,
66 render_depth
, InputOutput
, render_visual
,
67 CWOverrideRedirect
| CWEventMask
,
69 slit
[i
].a_frame
= appearance_copy(theme_a_unfocused_title
);
70 XSetWindowBorder(ob_display
, slit
[i
].frame
, theme_b_color
->pixel
);
71 XSetWindowBorderWidth(ob_display
, slit
[i
].frame
, theme_bwidth
);
73 g_hash_table_insert(slit_map
, &slit
[i
].frame
, &slit
[i
]);
81 for (i
= 0; i
< nslits
; ++i
) {
82 XDestroyWindow(ob_display
, slit
[i
].frame
);
83 appearance_free(slit
[i
].a_frame
);
84 g_hash_table_remove(slit_map
, &slit
[i
].frame
);
86 g_hash_table_destroy(slit_app_map
);
87 g_hash_table_destroy(slit_map
);
90 void slit_add(Window win
, XWMHints
*wmhints
)
94 XWindowAttributes attrib
;
99 app
= g_new0(SlitApp
, 1);
102 app
->icon_win
= (wmhints
->flags
& IconWindowHint
) ?
103 wmhints
->icon_window
: win
;
105 if (XGetWindowAttributes(ob_display
, app
->icon_win
, &attrib
)) {
106 app
->w
= attrib
.width
;
107 app
->h
= attrib
.height
;
109 app
->w
= app
->h
= 64;
112 s
->slit_apps
= g_list_append(s
->slit_apps
, app
);
115 XReparentWindow(ob_display
, app
->icon_win
, s
->frame
, app
->x
, app
->y
);
117 This is the same case as in frame.c for client windows. When Openbox is
118 starting, the window is already mapped so we see unmap events occur for
119 it. There are 2 unmap events generated that we see, one with the 'event'
120 member set the root window, and one set to the client, but both get
121 handled and need to be ignored.
123 if (ob_state
== State_Starting
)
124 app
->ignore_unmaps
+= 2;
126 if (app
->win
!= app
->icon_win
) {
127 /* have to map it so that it can be re-managed on a restart */
128 XMoveWindow(ob_display
, app
->win
, -1000, -1000);
129 XMapWindow(ob_display
, app
->win
);
131 XMapWindow(ob_display
, app
->icon_win
);
132 XSync(ob_display
, False
);
134 /* specify that if we exit, the window should not be destroyed and should
135 be reparented back to root automatically */
136 XChangeSaveSet(ob_display
, app
->icon_win
, SetModeInsert
);
137 XSelectInput(ob_display
, app
->icon_win
, SLITAPP_EVENT_MASK
);
139 grab_button_full(2, 0, app
->icon_win
,
140 ButtonPressMask
| ButtonReleaseMask
| ButtonMotionMask
,
141 GrabModeAsync
, ob_cursors
.move
);
143 g_hash_table_insert(slit_app_map
, &app
->icon_win
, app
);
145 g_message("Managed Slit App: 0x%lx", app
->icon_win
);
148 void slit_remove_all()
152 for (i
= 0; i
< nslits
; ++i
)
153 while (slit
[i
].slit_apps
)
154 slit_remove(slit
[i
].slit_apps
->data
, TRUE
);
157 void slit_remove(SlitApp
*app
, gboolean reparent
)
159 ungrab_button(2, 0, app
->icon_win
);
160 XSelectInput(ob_display
, app
->icon_win
, NoEventMask
);
161 /* remove the window from our save set */
162 XChangeSaveSet(ob_display
, app
->icon_win
, SetModeDelete
);
163 XSync(ob_display
, False
);
165 g_hash_table_remove(slit_app_map
, &app
->icon_win
);
168 XReparentWindow(ob_display
, app
->icon_win
, ob_root
, app
->x
, app
->y
);
170 app
->slit
->slit_apps
= g_list_remove(app
->slit
->slit_apps
, app
);
171 slit_configure(app
->slit
);
173 g_message("Unmanaged Slit App: 0x%lx", app
->icon_win
);
178 void slit_configure_all()
180 int i
; for (i
= 0; i
< nslits
; ++i
) slit_configure(&slit
[i
]);
183 static void slit_configure(Slit
*self
)
188 self
->w
= self
->h
= spot
= 0;
190 for (it
= self
->slit_apps
; it
; it
= it
->next
) {
191 struct SlitApp
*app
= it
->data
;
196 self
->h
= MAX(self
->h
, app
->h
);
201 self
->w
= MAX(self
->w
, app
->w
);
206 XMoveWindow(ob_display
, app
->icon_win
, app
->x
, app
->y
);
209 /* used for calculating offsets */
210 self
->w
+= theme_bwidth
* 2;
211 self
->h
+= theme_bwidth
* 2;
213 /* calculate position */
215 case SlitPos_Floating
:
216 self
->x
= self
->user_x
;
217 self
->y
= self
->user_y
;
219 case SlitPos_TopLeft
:
222 self
->gravity
= NorthWestGravity
;
225 self
->x
= screen_physical_size
.width
/ 2;
227 self
->gravity
= NorthGravity
;
229 case SlitPos_TopRight
:
230 self
->x
= screen_physical_size
.width
;
232 self
->gravity
= NorthEastGravity
;
236 self
->y
= screen_physical_size
.height
/ 2;
237 self
->gravity
= WestGravity
;
240 self
->x
= screen_physical_size
.width
;
241 self
->y
= screen_physical_size
.height
/ 2;
242 self
->gravity
= EastGravity
;
244 case SlitPos_BottomLeft
:
246 self
->y
= screen_physical_size
.height
;
247 self
->gravity
= SouthWestGravity
;
250 self
->x
= screen_physical_size
.width
/ 2;
251 self
->y
= screen_physical_size
.height
;
252 self
->gravity
= SouthGravity
;
254 case SlitPos_BottomRight
:
255 self
->x
= screen_physical_size
.width
;
256 self
->y
= screen_physical_size
.height
;
257 self
->gravity
= SouthEastGravity
;
261 switch(self
->gravity
) {
265 self
->x
-= self
->w
/ 2;
267 case NorthEastGravity
:
269 case SouthEastGravity
:
273 switch(self
->gravity
) {
277 self
->y
-= self
->h
/ 2;
279 case SouthWestGravity
:
281 case SouthEastGravity
:
286 if (self
->hide
&& self
->hidden
) {
289 case SlitPos_Floating
:
291 case SlitPos_TopLeft
:
293 self
->y
-= self
->h
- theme_bwidth
;
295 self
->x
-= self
->w
- theme_bwidth
;
298 self
->y
-= self
->h
- theme_bwidth
;
300 case SlitPos_TopRight
:
302 self
->y
-= self
->h
- theme_bwidth
;
304 self
->x
+= self
->w
- theme_bwidth
;
307 self
->x
-= self
->w
- theme_bwidth
;
310 self
->x
+= self
->w
- theme_bwidth
;
312 case SlitPos_BottomLeft
:
314 self
->y
+= self
->h
- theme_bwidth
;
316 self
->x
-= self
->w
- theme_bwidth
;
319 self
->y
+= self
->h
- theme_bwidth
;
321 case SlitPos_BottomRight
:
323 self
->y
+= self
->h
- theme_bwidth
;
325 self
->x
+= self
->w
- theme_bwidth
;
330 /* not used for actually sizing shit */
331 self
->w
-= theme_bwidth
* 2;
332 self
->h
-= theme_bwidth
* 2;
334 if (self
->w
> 0 && self
->h
> 0) {
335 RECT_SET(self
->a_frame
->area
, 0, 0, self
->w
, self
->h
);
336 XMoveResizeWindow(ob_display
, self
->frame
,
337 self
->x
, self
->y
, self
->w
, self
->h
);
339 paint(self
->frame
, self
->a_frame
);
340 XMapWindow(ob_display
, self
->frame
);
342 XUnmapWindow(ob_display
, self
->frame
);
344 /* but they are useful outside of this function! */
345 self
->w
+= theme_bwidth
* 2;
346 self
->h
+= theme_bwidth
* 2;
349 void slit_app_configure(SlitApp
*app
, int w
, int h
)
353 slit_configure(app
->slit
);
356 void slit_app_drag(SlitApp
*app
, XMotionEvent
*e
)
358 Slit
*src
, *dest
= NULL
;
359 SlitApp
*over
= NULL
;
369 /* which slit are we on top of? */
370 for (i
= 0; i
< nslits
; ++i
)
371 if (x
>= slit
[i
].x
&&
373 x
< slit
[i
].x
+ slit
[i
].w
&&
374 y
< slit
[i
].y
+ slit
[i
].h
) {
383 /* which slit app are we on top of? */
384 for (it
= dest
->slit_apps
; it
; it
= it
->next
) {
387 if (x
>= over
->x
&& x
< over
->x
+ over
->w
)
390 if (y
>= over
->y
&& y
< over
->y
+ over
->h
)
394 if (!it
|| app
== over
) return;
400 after
= (x
> over
->w
/ 2);
402 after
= (y
> over
->h
/ 2);
404 /* remove before doing the it->next! */
405 src
->slit_apps
= g_list_remove(src
->slit_apps
, app
);
406 if (src
!= dest
) slit_configure(src
);
408 if (after
) it
= it
->next
;
410 dest
->slit_apps
= g_list_insert_before(dest
->slit_apps
, it
, app
);
411 slit_configure(dest
);
414 static void hide_timeout(Slit
*self
)
417 timer_stop(self
->hide_timer
);
418 self
->hide_timer
= NULL
;
422 slit_configure(self
);
425 void slit_hide(Slit
*self
, gboolean hide
)
427 if (self
->hidden
== hide
|| !self
->hide
)
431 self
->hidden
= FALSE
;
432 slit_configure(self
);
434 /* if was hiding, stop it */
435 if (self
->hide_timer
) {
436 timer_stop(self
->hide_timer
);
437 self
->hide_timer
= NULL
;
440 g_assert(!self
->hide_timer
);
441 self
->hide_timer
= timer_start(slit_hide_timeout
* 1000,
442 (TimeoutHandler
)hide_timeout
, self
);