6 #include "render/theme.h"
7 #include "render/render.h"
9 #define SLIT_EVENT_MASK (EnterWindowMask | LeaveWindowMask)
10 #define SLITAPP_EVENT_MASK (StructureNotifyMask)
15 /* user-requested position stuff */
20 /* actual position (when not auto-hidden) */
35 GHashTable
*slit_map
= NULL
;
36 GHashTable
*slit_app_map
= NULL
;
41 static guint slit_hide_timeout
= 3000; /* XXX make a config option */
43 static void slit_configure(Slit
*self
);
47 XSetWindowAttributes attrib
;
50 slit_map
= g_hash_table_new(g_int_hash
, g_int_equal
);
51 slit_app_map
= g_hash_table_new(g_int_hash
, g_int_equal
);
54 slit
= g_new0(struct Slit
, nslits
);
56 for (i
= 0; i
< nslits
; ++i
) {
59 slit
[i
].hidden
= TRUE
;
60 slit
[i
].pos
= SlitPos_TopRight
;
62 attrib
.event_mask
= SLIT_EVENT_MASK
;
63 attrib
.override_redirect
= True
;
64 slit
[i
].frame
= XCreateWindow(ob_display
, ob_root
, 0, 0, 1, 1, 0,
65 render_depth
, InputOutput
, render_visual
,
66 CWOverrideRedirect
| CWEventMask
,
68 slit
[i
].a_frame
= appearance_copy(theme_a_unfocused_title
);
69 XSetWindowBorder(ob_display
, slit
[i
].frame
, theme_b_color
->pixel
);
70 XSetWindowBorderWidth(ob_display
, slit
[i
].frame
, theme_bwidth
);
72 g_hash_table_insert(slit_map
, &slit
[i
].frame
, &slit
[i
]);
80 for (i
= 0; i
< nslits
; ++i
) {
81 XDestroyWindow(ob_display
, slit
[i
].frame
);
82 appearance_free(slit
[i
].a_frame
);
83 g_hash_table_remove(slit_map
, &slit
[i
].frame
);
85 g_hash_table_destroy(slit_app_map
);
86 g_hash_table_destroy(slit_map
);
89 void slit_add(Window win
, XWMHints
*wmhints
)
93 XWindowAttributes attrib
;
98 app
= g_new0(SlitApp
, 1);
101 app
->icon_win
= (wmhints
->flags
& IconWindowHint
) ?
102 wmhints
->icon_window
: win
;
104 if (XGetWindowAttributes(ob_display
, app
->icon_win
, &attrib
)) {
105 app
->w
= attrib
.width
;
106 app
->h
= attrib
.height
;
108 app
->w
= app
->h
= 64;
111 s
->slit_apps
= g_list_append(s
->slit_apps
, app
);
114 XReparentWindow(ob_display
, app
->icon_win
, s
->frame
, app
->x
, app
->y
);
116 This is the same case as in frame.c for client windows. When Openbox is
117 starting, the window is already mapped so we see unmap events occur for
118 it. There are 2 unmap events generated that we see, one with the 'event'
119 member set the root window, and one set to the client, but both get
120 handled and need to be ignored.
122 if (ob_state
== State_Starting
)
123 app
->ignore_unmaps
+= 2;
125 if (app
->win
!= app
->icon_win
) {
126 /* have to map it so that it can be re-managed on a restart */
127 XMoveWindow(ob_display
, app
->win
, -1000, -1000);
128 XMapWindow(ob_display
, app
->win
);
130 XMapWindow(ob_display
, app
->icon_win
);
131 XSync(ob_display
, False
);
133 /* specify that if we exit, the window should not be destroyed and should
134 be reparented back to root automatically */
135 XChangeSaveSet(ob_display
, app
->icon_win
, SetModeInsert
);
136 XSelectInput(ob_display
, app
->icon_win
, SLITAPP_EVENT_MASK
);
138 grab_button_full(2, 0, app
->icon_win
, ButtonMotionMask
, GrabModeAsync
,
141 g_hash_table_insert(slit_app_map
, &app
->icon_win
, app
);
143 g_message("Managed Slit App: 0x%lx", app
->icon_win
);
146 void slit_remove_all()
150 for (i
= 0; i
< nslits
; ++i
)
151 while (slit
[i
].slit_apps
)
152 slit_remove(slit
[i
].slit_apps
->data
, TRUE
);
155 void slit_remove(SlitApp
*app
, gboolean reparent
)
157 ungrab_button(2, 0, app
->icon_win
);
158 XSelectInput(ob_display
, app
->icon_win
, NoEventMask
);
159 /* remove the window from our save set */
160 XChangeSaveSet(ob_display
, app
->icon_win
, SetModeDelete
);
161 XSync(ob_display
, False
);
163 g_hash_table_remove(slit_app_map
, &app
->icon_win
);
166 XReparentWindow(ob_display
, app
->icon_win
, ob_root
, app
->x
, app
->y
);
168 app
->slit
->slit_apps
= g_list_remove(app
->slit
->slit_apps
, app
);
169 slit_configure(app
->slit
);
171 g_message("Unmanaged Slit App: 0x%lx", app
->icon_win
);
176 void slit_configure_all()
178 int i
; for (i
= 0; i
< nslits
; ++i
) slit_configure(&slit
[i
]);
181 static void slit_configure(Slit
*self
)
186 self
->w
= self
->h
= spot
= 0;
188 for (it
= self
->slit_apps
; it
; it
= it
->next
) {
189 struct SlitApp
*app
= it
->data
;
194 self
->h
= MAX(self
->h
, app
->h
);
199 self
->w
= MAX(self
->w
, app
->w
);
204 XMoveWindow(ob_display
, app
->icon_win
, app
->x
, app
->y
);
207 /* used for calculating offsets */
208 self
->w
+= theme_bwidth
* 2;
209 self
->h
+= theme_bwidth
* 2;
211 /* calculate position */
213 case SlitPos_Floating
:
214 self
->x
= self
->user_x
;
215 self
->y
= self
->user_y
;
217 case SlitPos_TopLeft
:
220 self
->gravity
= NorthWestGravity
;
223 self
->x
= screen_physical_size
.width
/ 2;
225 self
->gravity
= NorthGravity
;
227 case SlitPos_TopRight
:
228 self
->x
= screen_physical_size
.width
;
230 self
->gravity
= NorthEastGravity
;
234 self
->y
= screen_physical_size
.height
/ 2;
235 self
->gravity
= WestGravity
;
238 self
->x
= screen_physical_size
.width
;
239 self
->y
= screen_physical_size
.height
/ 2;
240 self
->gravity
= EastGravity
;
242 case SlitPos_BottomLeft
:
244 self
->y
= screen_physical_size
.height
;
245 self
->gravity
= SouthWestGravity
;
248 self
->x
= screen_physical_size
.width
/ 2;
249 self
->y
= screen_physical_size
.height
;
250 self
->gravity
= SouthGravity
;
252 case SlitPos_BottomRight
:
253 self
->x
= screen_physical_size
.width
;
254 self
->y
= screen_physical_size
.height
;
255 self
->gravity
= SouthEastGravity
;
259 switch(self
->gravity
) {
263 self
->x
-= self
->w
/ 2;
265 case NorthEastGravity
:
267 case SouthEastGravity
:
271 switch(self
->gravity
) {
275 self
->y
-= self
->h
/ 2;
277 case SouthWestGravity
:
279 case SouthEastGravity
:
284 if (self
->hide
&& self
->hidden
) {
287 case SlitPos_Floating
:
289 case SlitPos_TopLeft
:
291 self
->y
-= self
->h
- theme_bwidth
;
293 self
->x
-= self
->w
- theme_bwidth
;
296 self
->y
-= self
->h
- theme_bwidth
;
298 case SlitPos_TopRight
:
300 self
->y
-= self
->h
- theme_bwidth
;
302 self
->x
+= self
->w
- theme_bwidth
;
305 self
->x
-= self
->w
- theme_bwidth
;
308 self
->x
+= self
->w
- theme_bwidth
;
310 case SlitPos_BottomLeft
:
312 self
->y
+= self
->h
- theme_bwidth
;
314 self
->x
-= self
->w
- theme_bwidth
;
317 self
->y
+= self
->h
- theme_bwidth
;
319 case SlitPos_BottomRight
:
321 self
->y
+= self
->h
- theme_bwidth
;
323 self
->x
+= self
->w
- theme_bwidth
;
328 /* not used for actually sizing shit */
329 self
->w
-= theme_bwidth
* 2;
330 self
->h
-= theme_bwidth
* 2;
332 if (self
->w
> 0 && self
->h
> 0) {
333 RECT_SET(self
->a_frame
->area
, 0, 0, self
->w
, self
->h
);
334 XMoveResizeWindow(ob_display
, self
->frame
,
335 self
->x
, self
->y
, self
->w
, self
->h
);
337 paint(self
->frame
, self
->a_frame
);
338 XMapWindow(ob_display
, self
->frame
);
340 XUnmapWindow(ob_display
, self
->frame
);
342 /* but they are useful outside of this function! */
343 self
->w
+= theme_bwidth
* 2;
344 self
->h
+= theme_bwidth
* 2;
347 void slit_app_configure(SlitApp
*app
, int w
, int h
)
351 slit_configure(app
->slit
);
354 void slit_app_drag(SlitApp
*app
, XMotionEvent
*e
)
356 Slit
*src
, *dest
= NULL
;
357 SlitApp
*over
= NULL
;
367 /* which slit are we on top of? */
368 for (i
= 0; i
< nslits
; ++i
)
369 if (x
>= slit
[i
].x
&&
371 x
< slit
[i
].x
+ slit
[i
].w
&&
372 y
< slit
[i
].y
+ slit
[i
].h
) {
381 /* which slit app are we on top of? */
382 for (it
= dest
->slit_apps
; it
; it
= it
->next
) {
385 if (x
>= over
->x
&& x
< over
->x
+ over
->w
)
388 if (y
>= over
->y
&& y
< over
->y
+ over
->h
)
392 if (!it
|| app
== over
) return;
398 after
= (x
> over
->w
/ 2);
400 after
= (y
> over
->h
/ 2);
402 /* remove before doing the it->next! */
403 src
->slit_apps
= g_list_remove(src
->slit_apps
, app
);
404 if (src
!= dest
) slit_configure(src
);
406 if (after
) it
= it
->next
;
408 dest
->slit_apps
= g_list_insert_before(dest
->slit_apps
, it
, app
);
409 slit_configure(dest
);
412 static void hide_timeout(Slit
*self
)
415 timer_stop(self
->hide_timer
);
416 self
->hide_timer
= NULL
;
420 slit_configure(self
);
423 void slit_hide(Slit
*self
, gboolean hide
)
425 if (self
->hidden
== hide
|| !self
->hide
)
429 self
->hidden
= FALSE
;
430 slit_configure(self
);
432 /* if was hiding, stop it */
433 if (self
->hide_timer
) {
434 timer_stop(self
->hide_timer
);
435 self
->hide_timer
= NULL
;
438 g_assert(!self
->hide_timer
);
439 self
->hide_timer
= timer_start(slit_hide_timeout
* 1000,
440 (TimeoutHandler
)hide_timeout
, self
);