]> Dogcows Code - chaz/openbox/blob - openbox/slit.c
a43edccf6aa2ba1b95d2c0f2ef3aefa324415591
[chaz/openbox] / openbox / slit.c
1 #include "slit.h"
2 #include "screen.h"
3 #include "timer.h"
4 #include "openbox.h"
5 #include "render/theme.h"
6 #include "render/render.h"
7
8 #define SLIT_EVENT_MASK (EnterWindowMask | LeaveWindowMask)
9 #define SLITAPP_EVENT_MASK (StructureNotifyMask)
10
11 struct Slit {
12 Window frame;
13
14 /* user-requested position stuff */
15 SlitPosition pos;
16 int gravity;
17 int user_x, user_y;
18
19 /* actual position (when not auto-hidden) */
20 int x, y;
21 int w, h;
22
23 gboolean horz;
24 gboolean hide;
25 gboolean hidden;
26
27 Appearance *a_frame;
28
29 Timer *hide_timer;
30
31 GList *slit_apps;
32 };
33
34 GHashTable *slit_map = NULL;
35 GHashTable *slit_app_map = NULL;
36
37 static Slit *slit;
38 static int nslits;
39
40 static void slit_configure(Slit *self);
41
42 void slit_startup()
43 {
44 XSetWindowAttributes attrib;
45 int i;
46
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);
49
50 nslits = 1;
51 slit = g_new0(struct Slit, nslits);
52
53 for (i = 0; i < nslits; ++i) {
54 slit[i].horz = FALSE;
55 slit[i].hide = TRUE;
56 slit[i].hidden = TRUE;
57 slit[i].pos = SlitPos_TopRight;
58
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,
64 &attrib);
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);
68
69 g_hash_table_insert(slit_map, &slit[i].frame, &slit[i]);
70 }
71 }
72
73 void slit_shutdown()
74 {
75 int i;
76
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);
81 }
82 g_hash_table_destroy(slit_app_map);
83 g_hash_table_destroy(slit_map);
84 }
85
86 void slit_add(Window win, XWMHints *wmhints, XWindowAttributes *attrib)
87 {
88 Slit *s;
89 SlitApp *app;
90
91 /* XXX pick a slit */
92 s = &slit[0];
93
94 app = g_new0(SlitApp, 1);
95 app->slit = s;
96 app->win = win;
97 app->icon_win = (wmhints->flags & IconWindowHint) ?
98 wmhints->icon_window : win;
99
100 app->w = attrib->width;
101 app->h = attrib->height;
102
103 s->slit_apps = g_list_append(s->slit_apps, app);
104 slit_configure(s);
105
106 XReparentWindow(ob_display, app->icon_win, s->frame, app->x, app->y);
107 /*
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.
113 */
114 if (ob_state == State_Starting)
115 app->ignore_unmaps += 2;
116
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);
121 }
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);
125
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);
130
131 g_hash_table_insert(slit_app_map, &app->icon_win, app);
132
133 g_message("Managed Slit App: 0x%lx", app->icon_win);
134 }
135
136 void slit_remove_all()
137 {
138 int i;
139
140 for (i = 0; i < nslits; ++i)
141 while (slit[i].slit_apps)
142 slit_remove(slit[i].slit_apps->data, TRUE);
143 }
144
145 void slit_remove(SlitApp *app, gboolean reparent)
146 {
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);
151
152 g_hash_table_remove(slit_app_map, &app->icon_win);
153
154 if (reparent)
155 XReparentWindow(ob_display, app->icon_win, ob_root, app->x, app->y);
156
157 app->slit->slit_apps = g_list_remove(app->slit->slit_apps, app);
158 slit_configure(app->slit);
159
160 g_message("Unmanaged Slit App: 0x%lx", app->icon_win);
161
162 g_free(app);
163 }
164
165 void slit_configure_all()
166 {
167 int i; for (i = 0; i < nslits; ++i) slit_configure(&slit[i]);
168 }
169
170 static void slit_configure(Slit *self)
171 {
172 GList *it;
173 int spot;
174
175 self->w = self->h = spot = 0;
176
177 for (it = self->slit_apps; it; it = it->next) {
178 struct SlitApp *app = it->data;
179 if (self->horz) {
180 app->x = spot;
181 app->y = 0;
182 self->w += app->w;
183 self->h = MAX(self->h, app->h);
184 spot += app->w;
185 } else {
186 app->x = 0;
187 app->y = spot;
188 self->w = MAX(self->h, app->w);
189 self->h += app->h;
190 spot += app->h;
191 }
192
193 XMoveWindow(ob_display, app->icon_win, app->x, app->y);
194 }
195
196 /* used for calculating offsets */
197 self->w += theme_bwidth * 2;
198 self->h += theme_bwidth * 2;
199
200 /* calculate position */
201 switch (self->pos) {
202 case SlitPos_Floating:
203 self->x = self->user_x;
204 self->y = self->user_y;
205 break;
206 case SlitPos_TopLeft:
207 self->x = 0;
208 self->y = 0;
209 self->gravity = NorthWestGravity;
210 break;
211 case SlitPos_Top:
212 self->x = screen_physical_size.width / 2;
213 self->y = 0;
214 self->gravity = NorthGravity;
215 break;
216 case SlitPos_TopRight:
217 self->x = screen_physical_size.width;
218 self->y = 0;
219 self->gravity = NorthEastGravity;
220 break;
221 case SlitPos_Left:
222 self->x = 0;
223 self->y = screen_physical_size.height / 2;
224 self->gravity = WestGravity;
225 break;
226 case SlitPos_Right:
227 self->x = screen_physical_size.width;
228 self->y = screen_physical_size.height / 2;
229 self->gravity = EastGravity;
230 break;
231 case SlitPos_BottomLeft:
232 self->x = 0;
233 self->y = screen_physical_size.height;
234 self->gravity = SouthWestGravity;
235 break;
236 case SlitPos_Bottom:
237 self->x = screen_physical_size.width / 2;
238 self->y = screen_physical_size.height;
239 self->gravity = SouthGravity;
240 break;
241 case SlitPos_BottomRight:
242 self->x = screen_physical_size.width;
243 self->y = screen_physical_size.height;
244 self->gravity = SouthEastGravity;
245 break;
246 }
247
248 switch(self->gravity) {
249 case NorthGravity:
250 case CenterGravity:
251 case SouthGravity:
252 self->x -= self->w / 2;
253 break;
254 case NorthEastGravity:
255 case EastGravity:
256 case SouthEastGravity:
257 self->x -= self->w;
258 break;
259 }
260 switch(self->gravity) {
261 case WestGravity:
262 case CenterGravity:
263 case EastGravity:
264 self->y -= self->h / 2;
265 break;
266 case SouthWestGravity:
267 case SouthGravity:
268 case SouthEastGravity:
269 self->y -= self->h;
270 break;
271 }
272
273 if (self->hide && self->hidden) {
274 g_message("hidden");
275 switch (self->pos) {
276 case SlitPos_Floating:
277 break;
278 case SlitPos_TopLeft:
279 if (self->horz)
280 self->y -= self->h - theme_bwidth;
281 else
282 self->x -= self->w - theme_bwidth;
283 break;
284 case SlitPos_Top:
285 self->y -= self->h - theme_bwidth;
286 break;
287 case SlitPos_TopRight:
288 if (self->horz)
289 self->y -= self->h - theme_bwidth;
290 else
291 self->x += self->w - theme_bwidth;
292 break;
293 case SlitPos_Left:
294 self->x -= self->w - theme_bwidth;
295 break;
296 case SlitPos_Right:
297 self->x += self->w - theme_bwidth;
298 break;
299 case SlitPos_BottomLeft:
300 if (self->horz)
301 self->y += self->h - theme_bwidth;
302 else
303 self->x -= self->w - theme_bwidth;
304 break;
305 case SlitPos_Bottom:
306 self->y += self->h - theme_bwidth;
307 break;
308 case SlitPos_BottomRight:
309 if (self->horz)
310 self->y += self->h - theme_bwidth;
311 else
312 self->x += self->w - theme_bwidth;
313 break;
314 }
315 }
316
317 /* not used for actually sizing shit */
318 self->w -= theme_bwidth * 2;
319 self->h -= theme_bwidth * 2;
320
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);
325
326 paint(self->frame, self->a_frame);
327 XMapWindow(ob_display, self->frame);
328 } else
329 XUnmapWindow(ob_display, self->frame);
330 }
331
332 void slit_app_configure(SlitApp *app, int w, int h)
333 {
334 app->w = w;
335 app->h = h;
336 slit_configure(app->slit);
337 }
338
339 static void hide_timeout(Slit *self)
340 {
341 /* dont repeat */
342 timer_stop(self->hide_timer);
343 self->hide_timer = NULL;
344
345 /* hide */
346 self->hidden = TRUE;
347 slit_configure(self);
348 }
349
350 void slit_hide(Slit *self, gboolean hide)
351 {
352 if (self->hidden == hide)
353 return;
354 if (!hide) {
355 /* show */
356 self->hidden = FALSE;
357 slit_configure(self);
358
359 /* if was hiding, stop it */
360 if (self->hide_timer) {
361 timer_stop(self->hide_timer);
362 self->hide_timer = NULL;
363 }
364 } else {
365 g_assert(!self->hide_timer);
366 self->hide_timer = timer_start(3000000,
367 (TimeoutHandler)hide_timeout, self);
368 }
369 }
This page took 0.046192 seconds and 3 git commands to generate.