5 #include "render/theme.h"
6 #include "render/render.h"
8 #define SLIT_EVENT_MASK (EnterWindowMask | LeaveWindowMask)
9 #define SLITAPP_EVENT_MASK (StructureNotifyMask)
14 /* user-requested position stuff */
19 /* actual position (when not auto-hidden) */
34 GHashTable
*slit_map
= NULL
;
35 GHashTable
*slit_app_map
= NULL
;
40 static void slit_configure(Slit
*self
);
44 XSetWindowAttributes attrib
;
47 slit_map
= g_hash_table_new(g_int_hash
, g_int_equal
);
48 slit_app_map
= g_hash_table_new(g_int_hash
, g_int_equal
);
51 slit
= g_new0(struct Slit
, nslits
);
53 for (i
= 0; i
< nslits
; ++i
) {
56 slit
[i
].hidden
= TRUE
;
57 slit
[i
].pos
= SlitPos_TopRight
;
59 attrib
.event_mask
= SLIT_EVENT_MASK
;
60 attrib
.override_redirect
= True
;
61 slit
[i
].frame
= XCreateWindow(ob_display
, ob_root
, 0, 0, 1, 1, 0,
62 render_depth
, InputOutput
, render_visual
,
63 CWOverrideRedirect
| CWEventMask
,
65 slit
[i
].a_frame
= appearance_copy(theme_a_unfocused_title
);
66 XSetWindowBorder(ob_display
, slit
[i
].frame
, theme_b_color
->pixel
);
67 XSetWindowBorderWidth(ob_display
, slit
[i
].frame
, theme_bwidth
);
69 g_hash_table_insert(slit_map
, &slit
[i
].frame
, &slit
[i
]);
77 for (i
= 0; i
< nslits
; ++i
) {
78 XDestroyWindow(ob_display
, slit
[i
].frame
);
79 appearance_free(slit
[i
].a_frame
);
80 g_hash_table_remove(slit_map
, &slit
[i
].frame
);
82 g_hash_table_destroy(slit_app_map
);
83 g_hash_table_destroy(slit_map
);
86 void slit_add(Window win
, XWMHints
*wmhints
, XWindowAttributes
*attrib
)
94 app
= g_new0(SlitApp
, 1);
97 app
->icon_win
= (wmhints
->flags
& IconWindowHint
) ?
98 wmhints
->icon_window
: win
;
100 app
->w
= attrib
->width
;
101 app
->h
= attrib
->height
;
103 s
->slit_apps
= g_list_append(s
->slit_apps
, app
);
106 XReparentWindow(ob_display
, app
->icon_win
, s
->frame
, app
->x
, app
->y
);
108 This is the same case as in frame.c for client windows. When Openbox is
109 starting, the window is already mapped so we see unmap events occur for
110 it. There are 2 unmap events generated that we see, one with the 'event'
111 member set the root window, and one set to the client, but both get
112 handled and need to be ignored.
114 if (ob_state
== State_Starting
)
115 app
->ignore_unmaps
+= 2;
117 if (app
->win
!= app
->icon_win
) {
118 /* have to map it so that it can be re-managed on a restart */
119 XMoveWindow(ob_display
, app
->win
, -1000, -1000);
120 XMapWindow(ob_display
, app
->win
);
122 g_message(" Slitting 0x%lx 0x%lx", app
->icon_win
, app
->win
);
123 XMapWindow(ob_display
, app
->icon_win
);
124 XSync(ob_display
, False
);
126 /* specify that if we exit, the window should not be destroyed and should
127 be reparented back to root automatically */
128 XChangeSaveSet(ob_display
, app
->icon_win
, SetModeInsert
);
129 XSelectInput(ob_display
, app
->icon_win
, SLITAPP_EVENT_MASK
);
131 g_hash_table_insert(slit_app_map
, &app
->icon_win
, app
);
133 g_message("Managed Slit App: 0x%lx", app
->icon_win
);
136 void slit_remove_all()
140 for (i
= 0; i
< nslits
; ++i
)
141 while (slit
[i
].slit_apps
)
142 slit_remove(slit
[i
].slit_apps
->data
, TRUE
);
145 void slit_remove(SlitApp
*app
, gboolean reparent
)
147 XSelectInput(ob_display
, app
->icon_win
, NoEventMask
);
148 /* remove the window from our save set */
149 XChangeSaveSet(ob_display
, app
->icon_win
, SetModeDelete
);
150 XSync(ob_display
, False
);
152 g_hash_table_remove(slit_app_map
, &app
->icon_win
);
155 XReparentWindow(ob_display
, app
->icon_win
, ob_root
, app
->x
, app
->y
);
157 app
->slit
->slit_apps
= g_list_remove(app
->slit
->slit_apps
, app
);
158 slit_configure(app
->slit
);
160 g_message("Unmanaged Slit App: 0x%lx", app
->icon_win
);
165 void slit_configure_all()
167 int i
; for (i
= 0; i
< nslits
; ++i
) slit_configure(&slit
[i
]);
170 static void slit_configure(Slit
*self
)
175 self
->w
= self
->h
= spot
= 0;
177 for (it
= self
->slit_apps
; it
; it
= it
->next
) {
178 struct SlitApp
*app
= it
->data
;
183 self
->h
= MAX(self
->h
, app
->h
);
188 self
->w
= MAX(self
->h
, app
->w
);
193 XMoveWindow(ob_display
, app
->icon_win
, app
->x
, app
->y
);
196 /* used for calculating offsets */
197 self
->w
+= theme_bwidth
* 2;
198 self
->h
+= theme_bwidth
* 2;
200 /* calculate position */
202 case SlitPos_Floating
:
203 self
->x
= self
->user_x
;
204 self
->y
= self
->user_y
;
206 case SlitPos_TopLeft
:
209 self
->gravity
= NorthWestGravity
;
212 self
->x
= screen_physical_size
.width
/ 2;
214 self
->gravity
= NorthGravity
;
216 case SlitPos_TopRight
:
217 self
->x
= screen_physical_size
.width
;
219 self
->gravity
= NorthEastGravity
;
223 self
->y
= screen_physical_size
.height
/ 2;
224 self
->gravity
= WestGravity
;
227 self
->x
= screen_physical_size
.width
;
228 self
->y
= screen_physical_size
.height
/ 2;
229 self
->gravity
= EastGravity
;
231 case SlitPos_BottomLeft
:
233 self
->y
= screen_physical_size
.height
;
234 self
->gravity
= SouthWestGravity
;
237 self
->x
= screen_physical_size
.width
/ 2;
238 self
->y
= screen_physical_size
.height
;
239 self
->gravity
= SouthGravity
;
241 case SlitPos_BottomRight
:
242 self
->x
= screen_physical_size
.width
;
243 self
->y
= screen_physical_size
.height
;
244 self
->gravity
= SouthEastGravity
;
248 switch(self
->gravity
) {
252 self
->x
-= self
->w
/ 2;
254 case NorthEastGravity
:
256 case SouthEastGravity
:
260 switch(self
->gravity
) {
264 self
->y
-= self
->h
/ 2;
266 case SouthWestGravity
:
268 case SouthEastGravity
:
273 if (self
->hide
&& self
->hidden
) {
276 case SlitPos_Floating
:
278 case SlitPos_TopLeft
:
280 self
->y
-= self
->h
- theme_bwidth
;
282 self
->x
-= self
->w
- theme_bwidth
;
285 self
->y
-= self
->h
- theme_bwidth
;
287 case SlitPos_TopRight
:
289 self
->y
-= self
->h
- theme_bwidth
;
291 self
->x
+= self
->w
- theme_bwidth
;
294 self
->x
-= self
->w
- theme_bwidth
;
297 self
->x
+= self
->w
- theme_bwidth
;
299 case SlitPos_BottomLeft
:
301 self
->y
+= self
->h
- theme_bwidth
;
303 self
->x
-= self
->w
- theme_bwidth
;
306 self
->y
+= self
->h
- theme_bwidth
;
308 case SlitPos_BottomRight
:
310 self
->y
+= self
->h
- theme_bwidth
;
312 self
->x
+= self
->w
- theme_bwidth
;
317 /* not used for actually sizing shit */
318 self
->w
-= theme_bwidth
* 2;
319 self
->h
-= theme_bwidth
* 2;
321 if (self
->w
> 0 && self
->h
> 0) {
322 RECT_SET(self
->a_frame
->area
, 0, 0, self
->w
, self
->h
);
323 XMoveResizeWindow(ob_display
, self
->frame
,
324 self
->x
, self
->y
, self
->w
, self
->h
);
326 paint(self
->frame
, self
->a_frame
);
327 XMapWindow(ob_display
, self
->frame
);
329 XUnmapWindow(ob_display
, self
->frame
);
332 void slit_app_configure(SlitApp
*app
, int w
, int h
)
336 slit_configure(app
->slit
);
339 static void hide_timeout(Slit
*self
)
342 timer_stop(self
->hide_timer
);
343 self
->hide_timer
= NULL
;
347 slit_configure(self
);
350 void slit_hide(Slit
*self
, gboolean hide
)
352 if (self
->hidden
== hide
)
356 self
->hidden
= FALSE
;
357 slit_configure(self
);
359 /* if was hiding, stop it */
360 if (self
->hide_timer
) {
361 timer_stop(self
->hide_timer
);
362 self
->hide_timer
= NULL
;
365 g_assert(!self
->hide_timer
);
366 self
->hide_timer
= timer_start(3000000,
367 (TimeoutHandler
)hide_timeout
, self
);