]> Dogcows Code - chaz/openbox/blob - openbox/frame.c
better handling of maximizing, wrt changing decorations on the windows, and showing...
[chaz/openbox] / openbox / frame.c
1 #include "frame.h"
2 #include "client.h"
3 #include "openbox.h"
4 #include "extensions.h"
5 #include "config.h"
6 #include "framerender.h"
7 #include "render/theme.h"
8
9 #define PLATE_EVENTMASK (SubstructureRedirectMask | ButtonPressMask)
10 #define FRAME_EVENTMASK (EnterWindowMask | LeaveWindowMask | \
11 ButtonPressMask | ButtonReleaseMask | \
12 VisibilityChangeMask)
13 #define ELEMENT_EVENTMASK (ButtonPressMask | ButtonReleaseMask | \
14 ButtonMotionMask | ExposureMask | \
15 EnterWindowMask | LeaveWindowMask)
16
17 #define FRAME_HANDLE_Y(f) (f->innersize.top + f->client->area.height + \
18 f->cbwidth_y)
19
20 static void layout_title(ObFrame *self);
21
22 static Window createWindow(Window parent, unsigned long mask,
23 XSetWindowAttributes *attrib)
24 {
25 return XCreateWindow(ob_display, parent, 0, 0, 1, 1, 0,
26 RrDepth(ob_rr_inst), InputOutput,
27 RrVisual(ob_rr_inst), mask, attrib);
28
29 }
30
31 ObFrame *frame_new()
32 {
33 XSetWindowAttributes attrib;
34 unsigned long mask;
35 ObFrame *self;
36
37 self = g_new(ObFrame, 1);
38
39 self->visible = FALSE;
40 self->obscured = TRUE;
41 self->decorations = 0;
42
43 /* create all of the decor windows */
44 mask = CWOverrideRedirect | CWEventMask;
45 attrib.event_mask = FRAME_EVENTMASK;
46 attrib.override_redirect = TRUE;
47 self->window = createWindow(RootWindow(ob_display, ob_screen),
48 mask, &attrib);
49
50 mask = 0;
51 self->plate = createWindow(self->window, mask, &attrib);
52
53 mask = CWEventMask;
54 attrib.event_mask = ELEMENT_EVENTMASK;
55 self->title = createWindow(self->window, mask, &attrib);
56
57 mask |= CWCursor;
58 attrib.cursor = ob_cursor(OB_CURSOR_NORTHWEST);
59 self->tlresize = createWindow(self->title, mask, &attrib);
60 attrib.cursor = ob_cursor(OB_CURSOR_NORTHEAST);
61 self->trresize = createWindow(self->title, mask, &attrib);
62
63 mask &= ~CWCursor;
64 self->label = createWindow(self->title, mask, &attrib);
65 self->max = createWindow(self->title, mask, &attrib);
66 self->close = createWindow(self->title, mask, &attrib);
67 self->desk = createWindow(self->title, mask, &attrib);
68 self->shade = createWindow(self->title, mask, &attrib);
69 self->icon = createWindow(self->title, mask, &attrib);
70 self->iconify = createWindow(self->title, mask, &attrib);
71 self->handle = createWindow(self->window, mask, &attrib);
72
73 mask |= CWCursor;
74 attrib.cursor = ob_cursor(OB_CURSOR_SOUTHWEST);
75 self->lgrip = createWindow(self->handle, mask, &attrib);
76 attrib.cursor = ob_cursor(OB_CURSOR_SOUTHEAST);
77 self->rgrip = createWindow(self->handle, mask, &attrib);
78
79 self->focused = FALSE;
80
81 /* the other stuff is shown based on decor settings */
82 XMapWindow(ob_display, self->plate);
83 XMapWindow(ob_display, self->lgrip);
84 XMapWindow(ob_display, self->rgrip);
85 XMapWindow(ob_display, self->label);
86
87 /* set colors/appearance/sizes for stuff that doesn't change */
88 XSetWindowBorder(ob_display, self->window, ob_rr_theme->b_color->pixel);
89 XSetWindowBorder(ob_display, self->title, ob_rr_theme->b_color->pixel);
90 XSetWindowBorder(ob_display, self->handle, ob_rr_theme->b_color->pixel);
91 XSetWindowBorder(ob_display, self->rgrip, ob_rr_theme->b_color->pixel);
92 XSetWindowBorder(ob_display, self->lgrip, ob_rr_theme->b_color->pixel);
93
94 XResizeWindow(ob_display, self->max,
95 ob_rr_theme->button_size, ob_rr_theme->button_size);
96 XResizeWindow(ob_display, self->iconify,
97 ob_rr_theme->button_size, ob_rr_theme->button_size);
98 XResizeWindow(ob_display, self->icon,
99 ob_rr_theme->button_size + 2, ob_rr_theme->button_size + 2);
100 XResizeWindow(ob_display, self->close,
101 ob_rr_theme->button_size, ob_rr_theme->button_size);
102 XResizeWindow(ob_display, self->desk,
103 ob_rr_theme->button_size, ob_rr_theme->button_size);
104 XResizeWindow(ob_display, self->shade,
105 ob_rr_theme->button_size, ob_rr_theme->button_size);
106 XResizeWindow(ob_display, self->lgrip,
107 ob_rr_theme->grip_width, ob_rr_theme->handle_height);
108 XResizeWindow(ob_display, self->rgrip,
109 ob_rr_theme->grip_width, ob_rr_theme->handle_height);
110 XResizeWindow(ob_display, self->tlresize,
111 ob_rr_theme->grip_width, ob_rr_theme->handle_height);
112 XResizeWindow(ob_display, self->trresize,
113 ob_rr_theme->grip_width, ob_rr_theme->handle_height);
114
115 /* set up the dynamic appearances */
116 self->a_unfocused_title = RrAppearanceCopy(ob_rr_theme->a_unfocused_title);
117 self->a_focused_title = RrAppearanceCopy(ob_rr_theme->a_focused_title);
118 self->a_unfocused_label = RrAppearanceCopy(ob_rr_theme->a_unfocused_label);
119 self->a_focused_label = RrAppearanceCopy(ob_rr_theme->a_focused_label);
120 self->a_unfocused_handle =
121 RrAppearanceCopy(ob_rr_theme->a_unfocused_handle);
122 self->a_focused_handle = RrAppearanceCopy(ob_rr_theme->a_focused_handle);
123 self->a_icon = RrAppearanceCopy(ob_rr_theme->a_icon);
124
125 self->max_press = self->close_press = self->desk_press =
126 self->iconify_press = self->shade_press = FALSE;
127 self->max_hover = self->close_hover = self->desk_hover =
128 self->iconify_hover = self->shade_hover = FALSE;
129
130 return (ObFrame*)self;
131 }
132
133 static void frame_free(ObFrame *self)
134 {
135 RrAppearanceFree(self->a_unfocused_title);
136 RrAppearanceFree(self->a_focused_title);
137 RrAppearanceFree(self->a_unfocused_label);
138 RrAppearanceFree(self->a_focused_label);
139 RrAppearanceFree(self->a_unfocused_handle);
140 RrAppearanceFree(self->a_focused_handle);
141 RrAppearanceFree(self->a_icon);
142
143 XDestroyWindow(ob_display, self->window);
144
145 g_free(self);
146 }
147
148 void frame_show(ObFrame *self)
149 {
150 if (!self->visible) {
151 self->visible = TRUE;
152 XMapWindow(ob_display, self->window);
153 }
154 }
155
156 void frame_hide(ObFrame *self)
157 {
158 if (self->visible) {
159 self->visible = FALSE;
160 self->client->ignore_unmaps++;
161 XUnmapWindow(ob_display, self->window);
162 }
163 }
164
165 void frame_adjust_shape(ObFrame *self)
166 {
167 #ifdef SHAPE
168 int num;
169 XRectangle xrect[2];
170
171 if (!self->client->shaped) {
172 /* clear the shape on the frame window */
173 XShapeCombineMask(ob_display, self->window, ShapeBounding,
174 self->innersize.left,
175 self->innersize.top,
176 None, ShapeSet);
177 } else {
178 /* make the frame's shape match the clients */
179 XShapeCombineShape(ob_display, self->window, ShapeBounding,
180 self->innersize.left,
181 self->innersize.top,
182 self->client->window,
183 ShapeBounding, ShapeSet);
184
185 num = 0;
186 if (self->decorations & OB_FRAME_DECOR_TITLEBAR) {
187 xrect[0].x = -ob_rr_theme->bwidth;
188 xrect[0].y = -ob_rr_theme->bwidth;
189 xrect[0].width = self->width + self->rbwidth * 2;
190 xrect[0].height = ob_rr_theme->title_height +
191 self->bwidth * 2;
192 ++num;
193 }
194
195 if (self->decorations & OB_FRAME_DECOR_HANDLE) {
196 xrect[1].x = -ob_rr_theme->bwidth;
197 xrect[1].y = FRAME_HANDLE_Y(self);
198 xrect[1].width = self->width + self->rbwidth * 2;
199 xrect[1].height = ob_rr_theme->handle_height +
200 self->bwidth * 2;
201 ++num;
202 }
203
204 XShapeCombineRectangles(ob_display, self->window,
205 ShapeBounding, 0, 0, xrect, num,
206 ShapeUnion, Unsorted);
207 }
208 #endif
209 }
210
211 void frame_adjust_area(ObFrame *self, gboolean moved,
212 gboolean resized, gboolean fake)
213 {
214 if (resized) {
215 self->decorations = self->client->decorations;
216 self->max_horz = self->client->max_horz;
217
218 if (self->decorations & OB_FRAME_DECOR_BORDER) {
219 self->bwidth = ob_rr_theme->bwidth;
220 self->cbwidth_x = self->cbwidth_y = ob_rr_theme->cbwidth;
221 } else {
222 self->bwidth = self->cbwidth_x = self->cbwidth_y = 0;
223 }
224 self->rbwidth = self->bwidth;
225
226 if (self->max_horz)
227 self->bwidth = self->cbwidth_x = 0;
228
229 STRUT_SET(self->innersize,
230 self->cbwidth_x,
231 self->cbwidth_y,
232 self->cbwidth_x,
233 self->cbwidth_y);
234 self->width = self->client->area.width + self->cbwidth_x * 2 -
235 (self->max_horz ? self->rbwidth * 2 : 0);
236 self->width = MAX(self->width, 1); /* no lower than 1 */
237
238 /* set border widths */
239 if (!fake) {
240 XSetWindowBorderWidth(ob_display, self->window, self->bwidth);
241 XSetWindowBorderWidth(ob_display, self->title, self->rbwidth);
242 XSetWindowBorderWidth(ob_display, self->handle, self->rbwidth);
243 XSetWindowBorderWidth(ob_display, self->lgrip, self->rbwidth);
244 XSetWindowBorderWidth(ob_display, self->rgrip, self->rbwidth);
245 }
246
247 if (self->decorations & OB_FRAME_DECOR_TITLEBAR)
248 self->innersize.top += ob_rr_theme->title_height + self->rbwidth +
249 (self->rbwidth - self->bwidth);
250 if (self->decorations & OB_FRAME_DECOR_HANDLE)
251 self->innersize.bottom += ob_rr_theme->handle_height +
252 self->rbwidth + (self->rbwidth - self->bwidth);
253
254 /* they all default off, they're turned on in layout_title */
255 self->icon_x = -1;
256 self->desk_x = -1;
257 self->shade_x = -1;
258 self->iconify_x = -1;
259 self->label_x = -1;
260 self->max_x = -1;
261 self->close_x = -1;
262
263 /* position/size and map/unmap all the windows */
264
265 if (!fake) {
266 if (self->decorations & OB_FRAME_DECOR_TITLEBAR) {
267 XMoveResizeWindow(ob_display, self->title,
268 -self->bwidth, -self->bwidth,
269 self->width, ob_rr_theme->title_height);
270 XMapWindow(ob_display, self->title);
271
272 if (self->decorations & OB_FRAME_DECOR_GRIPS) {
273 XMoveWindow(ob_display, self->tlresize, 0, 0);
274 XMoveWindow(ob_display, self->trresize,
275 self->width - ob_rr_theme->grip_width, 0);
276 XMapWindow(ob_display, self->tlresize);
277 XMapWindow(ob_display, self->trresize);
278 } else {
279 XUnmapWindow(ob_display, self->tlresize);
280 XUnmapWindow(ob_display, self->trresize);
281 }
282 } else
283 XUnmapWindow(ob_display, self->title);
284 }
285
286 if (self->decorations & OB_FRAME_DECOR_TITLEBAR)
287 /* layout the title bar elements */
288 layout_title(self);
289
290 if (!fake) {
291 if (self->decorations & OB_FRAME_DECOR_HANDLE) {
292 XMoveResizeWindow(ob_display, self->handle,
293 -self->bwidth, FRAME_HANDLE_Y(self),
294 self->width, ob_rr_theme->handle_height);
295 XMapWindow(ob_display, self->handle);
296
297 if (self->decorations & OB_FRAME_DECOR_GRIPS) {
298 XMoveWindow(ob_display, self->lgrip,
299 -self->rbwidth, -self->rbwidth);
300 XMoveWindow(ob_display, self->rgrip,
301 -self->rbwidth + self->width -
302 ob_rr_theme->grip_width, -self->rbwidth);
303 XMapWindow(ob_display, self->lgrip);
304 XMapWindow(ob_display, self->rgrip);
305 } else {
306 XUnmapWindow(ob_display, self->lgrip);
307 XUnmapWindow(ob_display, self->rgrip);
308 }
309
310 /* XXX make a subwindow with these dimentions?
311 ob_rr_theme->grip_width + self->bwidth, 0,
312 self->width - (ob_rr_theme->grip_width + self->bwidth) * 2,
313 ob_rr_theme->handle_height);
314 */
315 } else
316 XUnmapWindow(ob_display, self->handle);
317
318 /* move and resize the plate */
319 XMoveResizeWindow(ob_display, self->plate,
320 self->innersize.left - self->cbwidth_x,
321 self->innersize.top - self->cbwidth_y,
322 self->client->area.width + self->cbwidth_x * 2,
323 self->client->area.height + self->cbwidth_y * 2);
324 /* when the client has StaticGravity, it likes to move around. */
325 XMoveWindow(ob_display, self->client->window,
326 self->cbwidth_x, self->cbwidth_y);
327 }
328
329 STRUT_SET(self->size,
330 self->innersize.left + self->bwidth,
331 self->innersize.top + self->bwidth,
332 self->innersize.right + self->bwidth,
333 self->innersize.bottom + self->bwidth);
334 }
335
336 /* shading can change without being moved or resized */
337 RECT_SET_SIZE(self->area,
338 self->client->area.width +
339 self->size.left + self->size.right,
340 (self->client->shaded ?
341 ob_rr_theme->title_height + self->bwidth*2:
342 self->client->area.height +
343 self->size.top + self->size.bottom));
344
345 if (moved) {
346 /* find the new coordinates, done after setting the frame.size, for
347 frame_client_gravity. */
348 self->area.x = self->client->area.x;
349 self->area.y = self->client->area.y;
350 frame_client_gravity(self, &self->area.x, &self->area.y);
351 }
352
353 if (!fake) {
354 /* move and resize the top level frame.
355 shading can change without being moved or resized */
356 XMoveResizeWindow(ob_display, self->window,
357 self->area.x, self->area.y,
358 self->area.width - self->bwidth * 2,
359 self->area.height - self->bwidth * 2);
360
361 if (resized) {
362 framerender_frame(self);
363
364 frame_adjust_shape(self);
365 }
366 }
367 }
368
369 void frame_adjust_state(ObFrame *self)
370 {
371 framerender_frame(self);
372 }
373
374 void frame_adjust_focus(ObFrame *self, gboolean hilite)
375 {
376 self->focused = hilite;
377 framerender_frame(self);
378 }
379
380 void frame_adjust_title(ObFrame *self)
381 {
382 framerender_frame(self);
383 }
384
385 void frame_adjust_icon(ObFrame *self)
386 {
387 framerender_frame(self);
388 }
389
390 void frame_grab_client(ObFrame *self, ObClient *client)
391 {
392 self->client = client;
393
394 /* reparent the client to the frame */
395 XReparentWindow(ob_display, client->window, self->plate, 0, 0);
396 /*
397 When reparenting the client window, it is usually not mapped yet, since
398 this occurs from a MapRequest. However, in the case where Openbox is
399 starting up, the window is already mapped, so we'll see unmap events for
400 it. There are 2 unmap events generated that we see, one with the 'event'
401 member set the root window, and one set to the client, but both get
402 handled and need to be ignored.
403 */
404 if (ob_state() == OB_STATE_STARTING)
405 client->ignore_unmaps += 2;
406
407 /* select the event mask on the client's parent (to receive config/map
408 req's) the ButtonPress is to catch clicks on the client border */
409 XSelectInput(ob_display, self->plate, PLATE_EVENTMASK);
410
411 /* map the client so it maps when the frame does */
412 XMapWindow(ob_display, client->window);
413
414 frame_adjust_area(self, TRUE, TRUE, FALSE);
415
416 /* set all the windows for the frame in the window_map */
417 g_hash_table_insert(window_map, &self->window, client);
418 g_hash_table_insert(window_map, &self->plate, client);
419 g_hash_table_insert(window_map, &self->title, client);
420 g_hash_table_insert(window_map, &self->label, client);
421 g_hash_table_insert(window_map, &self->max, client);
422 g_hash_table_insert(window_map, &self->close, client);
423 g_hash_table_insert(window_map, &self->desk, client);
424 g_hash_table_insert(window_map, &self->shade, client);
425 g_hash_table_insert(window_map, &self->icon, client);
426 g_hash_table_insert(window_map, &self->iconify, client);
427 g_hash_table_insert(window_map, &self->handle, client);
428 g_hash_table_insert(window_map, &self->lgrip, client);
429 g_hash_table_insert(window_map, &self->rgrip, client);
430 g_hash_table_insert(window_map, &self->tlresize, client);
431 g_hash_table_insert(window_map, &self->trresize, client);
432 }
433
434 void frame_release_client(ObFrame *self, ObClient *client)
435 {
436 XEvent ev;
437
438 g_assert(self->client == client);
439
440 /* check if the app has already reparented its window away */
441 if (XCheckTypedWindowEvent(ob_display, client->window,
442 ReparentNotify, &ev)) {
443 XPutBackEvent(ob_display, &ev);
444
445 /* re-map the window since the unmanaging process unmaps it */
446
447 /* XXX ... um no it doesnt it unmaps its parent, the window itself
448 retains its mapped state, no?! XXX
449 XMapWindow(ob_display, client->window); */
450 } else {
451 /* according to the ICCCM - if the client doesn't reparent itself,
452 then we will reparent the window to root for them */
453 XReparentWindow(ob_display, client->window,
454 RootWindow(ob_display, ob_screen),
455 client->area.x,
456 client->area.y);
457 }
458
459 /* remove all the windows for the frame from the window_map */
460 g_hash_table_remove(window_map, &self->window);
461 g_hash_table_remove(window_map, &self->plate);
462 g_hash_table_remove(window_map, &self->title);
463 g_hash_table_remove(window_map, &self->label);
464 g_hash_table_remove(window_map, &self->max);
465 g_hash_table_remove(window_map, &self->close);
466 g_hash_table_remove(window_map, &self->desk);
467 g_hash_table_remove(window_map, &self->shade);
468 g_hash_table_remove(window_map, &self->icon);
469 g_hash_table_remove(window_map, &self->iconify);
470 g_hash_table_remove(window_map, &self->handle);
471 g_hash_table_remove(window_map, &self->lgrip);
472 g_hash_table_remove(window_map, &self->rgrip);
473 g_hash_table_remove(window_map, &self->tlresize);
474 g_hash_table_remove(window_map, &self->trresize);
475
476 frame_free(self);
477 }
478
479 static void layout_title(ObFrame *self)
480 {
481 char *lc;
482 int x;
483 gboolean n, d, i, l, m, c, s;
484
485 n = d = i = l = m = c = s = FALSE;
486
487 /* figure out whats being shown, and the width of the label */
488 self->label_width = self->width - (ob_rr_theme->bevel + 1) * 2;
489 for (lc = config_title_layout; *lc != '\0'; ++lc) {
490 switch (*lc) {
491 case 'N':
492 if (n) { *lc = ' '; break; } /* rm duplicates */
493 n = TRUE;
494 self->label_width -= (ob_rr_theme->button_size + 2 +
495 ob_rr_theme->bevel + 1);
496 break;
497 case 'D':
498 if (d) { *lc = ' '; break; } /* rm duplicates */
499 d = TRUE;
500 self->label_width -= (ob_rr_theme->button_size +
501 ob_rr_theme->bevel + 1);
502 break;
503 case 'S':
504 if (s) { *lc = ' '; break; } /* rm duplicates */
505 s = TRUE;
506 self->label_width -= (ob_rr_theme->button_size +
507 ob_rr_theme->bevel + 1);
508 break;
509 case 'I':
510 if (i) { *lc = ' '; break; } /* rm duplicates */
511 i = TRUE;
512 self->label_width -= (ob_rr_theme->button_size +
513 ob_rr_theme->bevel + 1);
514 break;
515 case 'L':
516 if (l) { *lc = ' '; break; } /* rm duplicates */
517 l = TRUE;
518 break;
519 case 'M':
520 if (m) { *lc = ' '; break; } /* rm duplicates */
521 m = TRUE;
522 self->label_width -= (ob_rr_theme->button_size +
523 ob_rr_theme->bevel + 1);
524 break;
525 case 'C':
526 if (c) { *lc = ' '; break; } /* rm duplicates */
527 c = TRUE;
528 self->label_width -= (ob_rr_theme->button_size +
529 ob_rr_theme->bevel + 1);
530 break;
531 }
532 }
533 if (self->label_width < 1) self->label_width = 1;
534
535 XResizeWindow(ob_display, self->label, self->label_width,
536 ob_rr_theme->label_height);
537
538 if (!n) XUnmapWindow(ob_display, self->icon);
539 if (!d) XUnmapWindow(ob_display, self->desk);
540 if (!s) XUnmapWindow(ob_display, self->shade);
541 if (!i) XUnmapWindow(ob_display, self->iconify);
542 if (!l) XUnmapWindow(ob_display, self->label);
543 if (!m) XUnmapWindow(ob_display, self->max);
544 if (!c) XUnmapWindow(ob_display, self->close);
545
546 x = ob_rr_theme->bevel + 1;
547 for (lc = config_title_layout; *lc != '\0'; ++lc) {
548 switch (*lc) {
549 case 'N':
550 if (!n) break;
551 self->icon_x = x;
552 XMapWindow(ob_display, self->icon);
553 XMoveWindow(ob_display, self->icon, x, ob_rr_theme->bevel);
554 x += ob_rr_theme->button_size + 2 + ob_rr_theme->bevel + 1;
555 break;
556 case 'D':
557 if (!d) break;
558 self->desk_x = x;
559 XMapWindow(ob_display, self->desk);
560 XMoveWindow(ob_display, self->desk, x, ob_rr_theme->bevel + 1);
561 x += ob_rr_theme->button_size + ob_rr_theme->bevel + 1;
562 break;
563 case 'S':
564 if (!s) break;
565 self->shade_x = x;
566 XMapWindow(ob_display, self->shade);
567 XMoveWindow(ob_display, self->shade, x, ob_rr_theme->bevel + 1);
568 x += ob_rr_theme->button_size + ob_rr_theme->bevel + 1;
569 break;
570 case 'I':
571 if (!i) break;
572 self->iconify_x = x;
573 XMapWindow(ob_display, self->iconify);
574 XMoveWindow(ob_display, self->iconify, x, ob_rr_theme->bevel + 1);
575 x += ob_rr_theme->button_size + ob_rr_theme->bevel + 1;
576 break;
577 case 'L':
578 if (!l) break;
579 self->label_x = x;
580 XMapWindow(ob_display, self->label);
581 XMoveWindow(ob_display, self->label, x, ob_rr_theme->bevel);
582 x += self->label_width + ob_rr_theme->bevel + 1;
583 break;
584 case 'M':
585 if (!m) break;
586 self->max_x = x;
587 XMapWindow(ob_display, self->max);
588 XMoveWindow(ob_display, self->max, x, ob_rr_theme->bevel + 1);
589 x += ob_rr_theme->button_size + ob_rr_theme->bevel + 1;
590 break;
591 case 'C':
592 if (!c) break;
593 self->close_x = x;
594 XMapWindow(ob_display, self->close);
595 XMoveWindow(ob_display, self->close, x, ob_rr_theme->bevel + 1);
596 x += ob_rr_theme->button_size + ob_rr_theme->bevel + 1;
597 break;
598 }
599 }
600 }
601
602 ObFrameContext frame_context_from_string(char *name)
603 {
604 if (!g_ascii_strcasecmp("desktop", name))
605 return OB_FRAME_CONTEXT_DESKTOP;
606 else if (!g_ascii_strcasecmp("client", name))
607 return OB_FRAME_CONTEXT_CLIENT;
608 else if (!g_ascii_strcasecmp("titlebar", name))
609 return OB_FRAME_CONTEXT_TITLEBAR;
610 else if (!g_ascii_strcasecmp("handle", name))
611 return OB_FRAME_CONTEXT_HANDLE;
612 else if (!g_ascii_strcasecmp("frame", name))
613 return OB_FRAME_CONTEXT_FRAME;
614 else if (!g_ascii_strcasecmp("tlcorner", name))
615 return OB_FRAME_CONTEXT_TLCORNER;
616 else if (!g_ascii_strcasecmp("trcorner", name))
617 return OB_FRAME_CONTEXT_TRCORNER;
618 else if (!g_ascii_strcasecmp("blcorner", name))
619 return OB_FRAME_CONTEXT_BLCORNER;
620 else if (!g_ascii_strcasecmp("brcorner", name))
621 return OB_FRAME_CONTEXT_BRCORNER;
622 else if (!g_ascii_strcasecmp("maximize", name))
623 return OB_FRAME_CONTEXT_MAXIMIZE;
624 else if (!g_ascii_strcasecmp("alldesktops", name))
625 return OB_FRAME_CONTEXT_ALLDESKTOPS;
626 else if (!g_ascii_strcasecmp("shade", name))
627 return OB_FRAME_CONTEXT_SHADE;
628 else if (!g_ascii_strcasecmp("iconify", name))
629 return OB_FRAME_CONTEXT_ICONIFY;
630 else if (!g_ascii_strcasecmp("icon", name))
631 return OB_FRAME_CONTEXT_ICON;
632 else if (!g_ascii_strcasecmp("close", name))
633 return OB_FRAME_CONTEXT_CLOSE;
634 return OB_FRAME_CONTEXT_NONE;
635 }
636
637 ObFrameContext frame_context(ObClient *client, Window win)
638 {
639 ObFrame *self;
640
641 if (win == RootWindow(ob_display, ob_screen))
642 return OB_FRAME_CONTEXT_DESKTOP;
643 if (client == NULL) return OB_FRAME_CONTEXT_NONE;
644 if (win == client->window) {
645 /* conceptually, this is the desktop, as far as users are
646 concerned */
647 if (client->type == OB_CLIENT_TYPE_DESKTOP)
648 return OB_FRAME_CONTEXT_DESKTOP;
649 return OB_FRAME_CONTEXT_CLIENT;
650 }
651
652 self = client->frame;
653 if (win == self->plate) {
654 /* conceptually, this is the desktop, as far as users are
655 concerned */
656 if (client->type == OB_CLIENT_TYPE_DESKTOP)
657 return OB_FRAME_CONTEXT_DESKTOP;
658 return OB_FRAME_CONTEXT_CLIENT;
659 }
660
661 if (win == self->window) return OB_FRAME_CONTEXT_FRAME;
662 if (win == self->title) return OB_FRAME_CONTEXT_TITLEBAR;
663 if (win == self->label) return OB_FRAME_CONTEXT_TITLEBAR;
664 if (win == self->handle) return OB_FRAME_CONTEXT_HANDLE;
665 if (win == self->lgrip) return OB_FRAME_CONTEXT_BLCORNER;
666 if (win == self->rgrip) return OB_FRAME_CONTEXT_BRCORNER;
667 if (win == self->tlresize) return OB_FRAME_CONTEXT_TLCORNER;
668 if (win == self->trresize) return OB_FRAME_CONTEXT_TRCORNER;
669 if (win == self->max) return OB_FRAME_CONTEXT_MAXIMIZE;
670 if (win == self->iconify) return OB_FRAME_CONTEXT_ICONIFY;
671 if (win == self->close) return OB_FRAME_CONTEXT_CLOSE;
672 if (win == self->icon) return OB_FRAME_CONTEXT_ICON;
673 if (win == self->desk) return OB_FRAME_CONTEXT_ALLDESKTOPS;
674 if (win == self->shade) return OB_FRAME_CONTEXT_SHADE;
675
676 return OB_FRAME_CONTEXT_NONE;
677 }
678
679 void frame_client_gravity(ObFrame *self, int *x, int *y)
680 {
681 /* horizontal */
682 switch (self->client->gravity) {
683 default:
684 case NorthWestGravity:
685 case SouthWestGravity:
686 case WestGravity:
687 break;
688
689 case NorthGravity:
690 case SouthGravity:
691 case CenterGravity:
692 *x -= (self->size.left + self->size.right) / 2;
693 break;
694
695 case NorthEastGravity:
696 case SouthEastGravity:
697 case EastGravity:
698 *x -= self->size.left + self->size.right;
699 break;
700
701 case ForgetGravity:
702 case StaticGravity:
703 *x -= self->size.left;
704 break;
705 }
706
707 /* vertical */
708 switch (self->client->gravity) {
709 default:
710 case NorthWestGravity:
711 case NorthEastGravity:
712 case NorthGravity:
713 break;
714
715 case CenterGravity:
716 case EastGravity:
717 case WestGravity:
718 *y -= (self->size.top + self->size.bottom) / 2;
719 break;
720
721 case SouthWestGravity:
722 case SouthEastGravity:
723 case SouthGravity:
724 *y -= self->size.top + self->size.bottom;
725 break;
726
727 case ForgetGravity:
728 case StaticGravity:
729 *y -= self->size.top;
730 break;
731 }
732 }
733
734 void frame_frame_gravity(ObFrame *self, int *x, int *y)
735 {
736 /* horizontal */
737 switch (self->client->gravity) {
738 default:
739 case NorthWestGravity:
740 case WestGravity:
741 case SouthWestGravity:
742 break;
743 case NorthGravity:
744 case CenterGravity:
745 case SouthGravity:
746 *x += (self->size.left + self->size.right) / 2;
747 break;
748 case NorthEastGravity:
749 case EastGravity:
750 case SouthEastGravity:
751 *x += self->size.left + self->size.right;
752 break;
753 case StaticGravity:
754 case ForgetGravity:
755 *x += self->size.left;
756 break;
757 }
758
759 /* vertical */
760 switch (self->client->gravity) {
761 default:
762 case NorthWestGravity:
763 case NorthGravity:
764 case NorthEastGravity:
765 break;
766 case WestGravity:
767 case CenterGravity:
768 case EastGravity:
769 *y += (self->size.top + self->size.bottom) / 2;
770 break;
771 case SouthWestGravity:
772 case SouthGravity:
773 case SouthEastGravity:
774 *y += self->size.top + self->size.bottom;
775 break;
776 case StaticGravity:
777 case ForgetGravity:
778 *y += self->size.top;
779 break;
780 }
781 }
This page took 0.079005 seconds and 4 git commands to generate.