]> Dogcows Code - chaz/openbox/blob - openbox/slit.c
add anotehr stacking_add function.
[chaz/openbox] / openbox / slit.c
1 #include "slit.h"
2 #include "screen.h"
3 #include "grab.h"
4 #include "openbox.h"
5 #include "render/theme.h"
6
7 #define SLIT_EVENT_MASK (ButtonPressMask | ButtonReleaseMask | \
8 EnterWindowMask | LeaveWindowMask)
9 #define SLITAPP_EVENT_MASK (StructureNotifyMask)
10
11 GHashTable *slit_map = NULL;
12 GHashTable *slit_app_map = NULL;
13
14 static Slit *slit;
15 static int nslits;
16
17 static guint slit_hide_timeout = 3000; /* XXX make a config option */
18
19 static void slit_configure(Slit *self);
20
21 void slit_startup()
22 {
23 XSetWindowAttributes attrib;
24 int i;
25
26 slit_map = g_hash_table_new(g_int_hash, g_int_equal);
27 slit_app_map = g_hash_table_new(g_int_hash, g_int_equal);
28
29 nslits = 1;
30 slit = g_new0(struct Slit, nslits);
31 slit->obwin.type = Window_Slit;
32
33 for (i = 0; i < nslits; ++i) {
34 slit[i].horz = FALSE;
35 slit[i].hide = FALSE;
36 slit[i].hidden = TRUE;
37 slit[i].pos = SlitPos_TopRight;
38 slit[i].layer = Layer_Top;
39
40 attrib.event_mask = SLIT_EVENT_MASK;
41 attrib.override_redirect = True;
42 slit[i].frame = XCreateWindow(ob_display, ob_root, 0, 0, 1, 1, 0,
43 render_depth, InputOutput, render_visual,
44 CWOverrideRedirect | CWEventMask,
45 &attrib);
46 slit[i].a_frame = appearance_copy(theme_a_unfocused_title);
47 XSetWindowBorder(ob_display, slit[i].frame, theme_b_color->pixel);
48 XSetWindowBorderWidth(ob_display, slit[i].frame, theme_bwidth);
49
50 g_hash_table_insert(slit_map, &slit[i].frame, &slit[i]);
51 stacking_add(SLIT_AS_WINDOW(&slit[i]));
52 stacking_raise(SLIT_AS_WINDOW(&slit[i]));
53 }
54 }
55
56 void slit_shutdown()
57 {
58 int i;
59
60 for (i = 0; i < nslits; ++i) {
61 XDestroyWindow(ob_display, slit[i].frame);
62 appearance_free(slit[i].a_frame);
63 g_hash_table_remove(slit_map, &slit[i].frame);
64 stacking_remove(&slit[i]);
65 }
66 g_hash_table_destroy(slit_app_map);
67 g_hash_table_destroy(slit_map);
68 }
69
70 void slit_add(Window win, XWMHints *wmhints)
71 {
72 Slit *s;
73 SlitApp *app;
74 XWindowAttributes attrib;
75
76 /* XXX pick a slit */
77 s = &slit[0];
78
79 app = g_new0(SlitApp, 1);
80 app->slit = s;
81 app->win = win;
82 app->icon_win = (wmhints->flags & IconWindowHint) ?
83 wmhints->icon_window : win;
84
85 if (XGetWindowAttributes(ob_display, app->icon_win, &attrib)) {
86 app->w = attrib.width;
87 app->h = attrib.height;
88 } else {
89 app->w = app->h = 64;
90 }
91
92 s->slit_apps = g_list_append(s->slit_apps, app);
93 slit_configure(s);
94
95 XReparentWindow(ob_display, app->icon_win, s->frame, app->x, app->y);
96 /*
97 This is the same case as in frame.c for client windows. When Openbox is
98 starting, the window is already mapped so we see unmap events occur for
99 it. There are 2 unmap events generated that we see, one with the 'event'
100 member set the root window, and one set to the client, but both get
101 handled and need to be ignored.
102 */
103 if (ob_state == State_Starting)
104 app->ignore_unmaps += 2;
105
106 if (app->win != app->icon_win) {
107 /* have to map it so that it can be re-managed on a restart */
108 XMoveWindow(ob_display, app->win, -1000, -1000);
109 XMapWindow(ob_display, app->win);
110 }
111 XMapWindow(ob_display, app->icon_win);
112 XSync(ob_display, False);
113
114 /* specify that if we exit, the window should not be destroyed and should
115 be reparented back to root automatically */
116 XChangeSaveSet(ob_display, app->icon_win, SetModeInsert);
117 XSelectInput(ob_display, app->icon_win, SLITAPP_EVENT_MASK);
118
119 grab_button_full(2, 0, app->icon_win,
120 ButtonPressMask | ButtonReleaseMask | ButtonMotionMask,
121 GrabModeAsync, ob_cursors.move);
122
123 g_hash_table_insert(slit_app_map, &app->icon_win, app);
124
125 g_message("Managed Slit App: 0x%lx", app->icon_win);
126 }
127
128 void slit_remove_all()
129 {
130 int i;
131
132 for (i = 0; i < nslits; ++i)
133 while (slit[i].slit_apps)
134 slit_remove(slit[i].slit_apps->data, TRUE);
135 }
136
137 void slit_remove(SlitApp *app, gboolean reparent)
138 {
139 ungrab_button(2, 0, app->icon_win);
140 XSelectInput(ob_display, app->icon_win, NoEventMask);
141 /* remove the window from our save set */
142 XChangeSaveSet(ob_display, app->icon_win, SetModeDelete);
143 XSync(ob_display, False);
144
145 g_hash_table_remove(slit_app_map, &app->icon_win);
146
147 if (reparent)
148 XReparentWindow(ob_display, app->icon_win, ob_root, app->x, app->y);
149
150 app->slit->slit_apps = g_list_remove(app->slit->slit_apps, app);
151 slit_configure(app->slit);
152
153 g_message("Unmanaged Slit App: 0x%lx", app->icon_win);
154
155 g_free(app);
156 }
157
158 void slit_configure_all()
159 {
160 int i; for (i = 0; i < nslits; ++i) slit_configure(&slit[i]);
161 }
162
163 static void slit_configure(Slit *self)
164 {
165 GList *it;
166 int spot;
167
168 self->w = self->h = spot = 0;
169
170 for (it = self->slit_apps; it; it = it->next) {
171 struct SlitApp *app = it->data;
172 if (self->horz) {
173 app->x = spot;
174 app->y = 0;
175 self->w += app->w;
176 self->h = MAX(self->h, app->h);
177 spot += app->w;
178 } else {
179 app->x = 0;
180 app->y = spot;
181 self->w = MAX(self->w, app->w);
182 self->h += app->h;
183 spot += app->h;
184 }
185
186 XMoveWindow(ob_display, app->icon_win, app->x, app->y);
187 }
188
189 /* used for calculating offsets */
190 self->w += theme_bwidth * 2;
191 self->h += theme_bwidth * 2;
192
193 /* calculate position */
194 switch (self->pos) {
195 case SlitPos_Floating:
196 self->x = self->user_x;
197 self->y = self->user_y;
198 break;
199 case SlitPos_TopLeft:
200 self->x = 0;
201 self->y = 0;
202 self->gravity = NorthWestGravity;
203 break;
204 case SlitPos_Top:
205 self->x = screen_physical_size.width / 2;
206 self->y = 0;
207 self->gravity = NorthGravity;
208 break;
209 case SlitPos_TopRight:
210 self->x = screen_physical_size.width;
211 self->y = 0;
212 self->gravity = NorthEastGravity;
213 break;
214 case SlitPos_Left:
215 self->x = 0;
216 self->y = screen_physical_size.height / 2;
217 self->gravity = WestGravity;
218 break;
219 case SlitPos_Right:
220 self->x = screen_physical_size.width;
221 self->y = screen_physical_size.height / 2;
222 self->gravity = EastGravity;
223 break;
224 case SlitPos_BottomLeft:
225 self->x = 0;
226 self->y = screen_physical_size.height;
227 self->gravity = SouthWestGravity;
228 break;
229 case SlitPos_Bottom:
230 self->x = screen_physical_size.width / 2;
231 self->y = screen_physical_size.height;
232 self->gravity = SouthGravity;
233 break;
234 case SlitPos_BottomRight:
235 self->x = screen_physical_size.width;
236 self->y = screen_physical_size.height;
237 self->gravity = SouthEastGravity;
238 break;
239 }
240
241 switch(self->gravity) {
242 case NorthGravity:
243 case CenterGravity:
244 case SouthGravity:
245 self->x -= self->w / 2;
246 break;
247 case NorthEastGravity:
248 case EastGravity:
249 case SouthEastGravity:
250 self->x -= self->w;
251 break;
252 }
253 switch(self->gravity) {
254 case WestGravity:
255 case CenterGravity:
256 case EastGravity:
257 self->y -= self->h / 2;
258 break;
259 case SouthWestGravity:
260 case SouthGravity:
261 case SouthEastGravity:
262 self->y -= self->h;
263 break;
264 }
265
266 if (self->hide && self->hidden) {
267 g_message("hidden");
268 switch (self->pos) {
269 case SlitPos_Floating:
270 break;
271 case SlitPos_TopLeft:
272 if (self->horz)
273 self->y -= self->h - theme_bwidth;
274 else
275 self->x -= self->w - theme_bwidth;
276 break;
277 case SlitPos_Top:
278 self->y -= self->h - theme_bwidth;
279 break;
280 case SlitPos_TopRight:
281 if (self->horz)
282 self->y -= self->h - theme_bwidth;
283 else
284 self->x += self->w - theme_bwidth;
285 break;
286 case SlitPos_Left:
287 self->x -= self->w - theme_bwidth;
288 break;
289 case SlitPos_Right:
290 self->x += self->w - theme_bwidth;
291 break;
292 case SlitPos_BottomLeft:
293 if (self->horz)
294 self->y += self->h - theme_bwidth;
295 else
296 self->x -= self->w - theme_bwidth;
297 break;
298 case SlitPos_Bottom:
299 self->y += self->h - theme_bwidth;
300 break;
301 case SlitPos_BottomRight:
302 if (self->horz)
303 self->y += self->h - theme_bwidth;
304 else
305 self->x += self->w - theme_bwidth;
306 break;
307 }
308 }
309
310 /* not used for actually sizing shit */
311 self->w -= theme_bwidth * 2;
312 self->h -= theme_bwidth * 2;
313
314 if (self->w > 0 && self->h > 0) {
315 RECT_SET(self->a_frame->area, 0, 0, self->w, self->h);
316 XMoveResizeWindow(ob_display, self->frame,
317 self->x, self->y, self->w, self->h);
318
319 paint(self->frame, self->a_frame);
320 XMapWindow(ob_display, self->frame);
321 } else
322 XUnmapWindow(ob_display, self->frame);
323
324 /* but they are useful outside of this function! */
325 self->w += theme_bwidth * 2;
326 self->h += theme_bwidth * 2;
327 }
328
329 void slit_app_configure(SlitApp *app, int w, int h)
330 {
331 app->w = w;
332 app->h = h;
333 slit_configure(app->slit);
334 }
335
336 void slit_app_drag(SlitApp *app, XMotionEvent *e)
337 {
338 Slit *src, *dest = NULL;
339 SlitApp *over = NULL;
340 GList *it;
341 int i;
342 int x, y;
343 gboolean after;
344
345 src = app->slit;
346 x = e->x_root;
347 y = e->y_root;
348
349 /* which slit are we on top of? */
350 for (i = 0; i < nslits; ++i)
351 if (x >= slit[i].x &&
352 y >= slit[i].y &&
353 x < slit[i].x + slit[i].w &&
354 y < slit[i].y + slit[i].h) {
355 dest = &slit[i];
356 break;
357 }
358 if (!dest) return;
359
360 x -= dest->x;
361 y -= dest->y;
362
363 /* which slit app are we on top of? */
364 for (it = dest->slit_apps; it; it = it->next) {
365 over = it->data;
366 if (dest->horz) {
367 if (x >= over->x && x < over->x + over->w)
368 break;
369 } else {
370 if (y >= over->y && y < over->y + over->h)
371 break;
372 }
373 }
374 if (!it || app == over) return;
375
376 x -= over->x;
377 y -= over->y;
378
379 if (dest->horz)
380 after = (x > over->w / 2);
381 else
382 after = (y > over->h / 2);
383
384 /* remove before doing the it->next! */
385 src->slit_apps = g_list_remove(src->slit_apps, app);
386 if (src != dest) slit_configure(src);
387
388 if (after) it = it->next;
389
390 dest->slit_apps = g_list_insert_before(dest->slit_apps, it, app);
391 slit_configure(dest);
392 }
393
394 static void hide_timeout(Slit *self)
395 {
396 /* dont repeat */
397 timer_stop(self->hide_timer);
398 self->hide_timer = NULL;
399
400 /* hide */
401 self->hidden = TRUE;
402 slit_configure(self);
403 }
404
405 void slit_hide(Slit *self, gboolean hide)
406 {
407 if (self->hidden == hide || !self->hide)
408 return;
409 if (!hide) {
410 /* show */
411 self->hidden = FALSE;
412 slit_configure(self);
413
414 /* if was hiding, stop it */
415 if (self->hide_timer) {
416 timer_stop(self->hide_timer);
417 self->hide_timer = NULL;
418 }
419 } else {
420 g_assert(!self->hide_timer);
421 self->hide_timer = timer_start(slit_hide_timeout * 1000,
422 (TimeoutHandler)hide_timeout, self);
423 }
424 }
This page took 0.059322 seconds and 4 git commands to generate.