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