prefixing and capitalization for the Frame->ObFrame struct and the Context->ObFrameCo...
[dana/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
14 #define FRAME_HANDLE_Y(f) (f->innersize.top + f->client->area.height + \
15                            f->cbwidth)
16
17 static void layout_title(ObFrame *self);
18
19 void frame_startup()
20 {
21 }
22
23 void frame_shutdown()
24 {
25 }
26
27 static Window createWindow(Window parent, unsigned long mask,
28                            XSetWindowAttributes *attrib)
29 {
30     return XCreateWindow(ob_display, parent, 0, 0, 1, 1, 0,
31                          RrDepth(ob_rr_inst), InputOutput,
32                          RrVisual(ob_rr_inst), mask, attrib);
33                        
34 }
35
36 ObFrame *frame_new()
37 {
38     XSetWindowAttributes attrib;
39     unsigned long mask;
40     ObFrame *self;
41
42     self = g_new(ObFrame, 1);
43
44     self->visible = FALSE;
45     self->decorations = 0;
46
47     /* create all of the decor windows */
48     mask = CWOverrideRedirect | CWEventMask;
49     attrib.event_mask = FRAME_EVENTMASK;
50     attrib.override_redirect = TRUE;
51     self->window = createWindow(ob_root, mask, &attrib);
52
53     mask = 0;
54     self->plate = createWindow(self->window, mask, &attrib);
55
56     mask = CWEventMask;
57     attrib.event_mask = ELEMENT_EVENTMASK;
58     self->title = createWindow(self->window, mask, &attrib);
59     self->label = createWindow(self->title, mask, &attrib);
60     self->max = createWindow(self->title, mask, &attrib);
61     self->close = createWindow(self->title, mask, &attrib);
62     self->desk = createWindow(self->title, mask, &attrib);
63     self->shade = createWindow(self->title, mask, &attrib);
64     self->icon = createWindow(self->title, mask, &attrib);
65     self->iconify = createWindow(self->title, mask, &attrib);
66     self->handle = createWindow(self->window, mask, &attrib);
67     mask |= CWCursor;
68     attrib.cursor = ob_cursor(OB_CURSOR_SOUTHWEST);
69     self->lgrip = createWindow(self->handle, mask, &attrib);
70     attrib.cursor = ob_cursor(OB_CURSOR_SOUTHEAST);
71     self->rgrip = createWindow(self->handle, mask, &attrib);
72
73     self->focused = FALSE;
74
75     /* the other stuff is shown based on decor settings */
76     XMapWindow(ob_display, self->plate);
77     XMapWindow(ob_display, self->lgrip);
78     XMapWindow(ob_display, self->rgrip);
79     XMapWindow(ob_display, self->label);
80
81     /* set colors/appearance/sizes for stuff that doesn't change */
82     XSetWindowBorder(ob_display, self->window, ob_rr_theme->b_color->pixel);
83     XSetWindowBorder(ob_display, self->label, ob_rr_theme->b_color->pixel);
84     XSetWindowBorder(ob_display, self->rgrip, ob_rr_theme->b_color->pixel);
85     XSetWindowBorder(ob_display, self->lgrip, ob_rr_theme->b_color->pixel);
86
87     XResizeWindow(ob_display, self->max,
88                   ob_rr_theme->button_size, ob_rr_theme->button_size);
89     XResizeWindow(ob_display, self->iconify,
90                   ob_rr_theme->button_size, ob_rr_theme->button_size);
91     XResizeWindow(ob_display, self->icon,
92                   ob_rr_theme->button_size + 2, ob_rr_theme->button_size + 2);
93     XResizeWindow(ob_display, self->close,
94                   ob_rr_theme->button_size, ob_rr_theme->button_size);
95     XResizeWindow(ob_display, self->desk,
96                   ob_rr_theme->button_size, ob_rr_theme->button_size);
97     XResizeWindow(ob_display, self->shade,
98                   ob_rr_theme->button_size, ob_rr_theme->button_size);
99     XResizeWindow(ob_display, self->lgrip,
100                   ob_rr_theme->grip_width, ob_rr_theme->handle_height);
101     XResizeWindow(ob_display, self->rgrip,
102                   ob_rr_theme->grip_width, ob_rr_theme->handle_height);
103
104     /* set up the dynamic appearances */
105     self->a_unfocused_title = RrAppearanceCopy(ob_rr_theme->a_unfocused_title);
106     self->a_focused_title = RrAppearanceCopy(ob_rr_theme->a_focused_title);
107     self->a_unfocused_label = RrAppearanceCopy(ob_rr_theme->a_unfocused_label);
108     self->a_focused_label = RrAppearanceCopy(ob_rr_theme->a_focused_label);
109     self->a_unfocused_handle =
110         RrAppearanceCopy(ob_rr_theme->a_unfocused_handle);
111     self->a_focused_handle = RrAppearanceCopy(ob_rr_theme->a_focused_handle);
112     self->a_icon = RrAppearanceCopy(ob_rr_theme->a_icon);
113
114     self->max_press = self->close_press = self->desk_press = 
115         self->iconify_press = self->shade_press = FALSE;
116
117     return (ObFrame*)self;
118 }
119
120 static void frame_free(ObFrame *self)
121 {
122     RrAppearanceFree(self->a_unfocused_title); 
123     RrAppearanceFree(self->a_focused_title);
124     RrAppearanceFree(self->a_unfocused_label);
125     RrAppearanceFree(self->a_focused_label);
126     RrAppearanceFree(self->a_unfocused_handle);
127     RrAppearanceFree(self->a_focused_handle);
128     RrAppearanceFree(self->a_icon);
129
130     XDestroyWindow(ob_display, self->window);
131
132     g_free(self);
133 }
134
135 void frame_show(ObFrame *self)
136 {
137     if (!self->visible) {
138         self->visible = TRUE;
139         XMapWindow(ob_display, self->window);
140     }
141 }
142
143 void frame_hide(ObFrame *self)
144 {
145     if (self->visible) {
146         self->visible = FALSE;
147         self->client->ignore_unmaps++;
148         XUnmapWindow(ob_display, self->window);
149     }
150 }
151
152 void frame_adjust_shape(ObFrame *self)
153 {
154 #ifdef SHAPE
155     int num;
156     XRectangle xrect[2];
157
158     if (!self->client->shaped) {
159         /* clear the shape on the frame window */
160         XShapeCombineMask(ob_display, self->window, ShapeBounding,
161                           self->innersize.left,
162                           self->innersize.top,
163                           None, ShapeSet);
164     } else {
165         /* make the frame's shape match the clients */
166         XShapeCombineShape(ob_display, self->window, ShapeBounding,
167                            self->innersize.left,
168                            self->innersize.top,
169                            self->client->window,
170                            ShapeBounding, ShapeSet);
171
172         num = 0;
173         if (self->decorations & Decor_Titlebar) {
174             xrect[0].x = -ob_rr_theme->bevel;
175             xrect[0].y = -ob_rr_theme->bevel;
176             xrect[0].width = self->width + self->bwidth * 2;
177             xrect[0].height = ob_rr_theme->title_height +
178                 self->bwidth * 2;
179             ++num;
180         }
181
182         if (self->decorations & Decor_Handle) {
183             xrect[1].x = -ob_rr_theme->bevel;
184             xrect[1].y = FRAME_HANDLE_Y(self);
185             xrect[1].width = self->width + self->bwidth * 2;
186             xrect[1].height = ob_rr_theme->handle_height +
187                 self->bwidth * 2;
188             ++num;
189         }
190
191         XShapeCombineRectangles(ob_display, self->window,
192                                 ShapeBounding, 0, 0, xrect, num,
193                                 ShapeUnion, Unsorted);
194     }
195 #endif
196 }
197
198 void frame_adjust_area(ObFrame *self, gboolean moved, gboolean resized)
199 {
200     if (resized) {
201         self->decorations = self->client->decorations;
202         if (self->decorations & Decor_Border) {
203             self->bwidth = ob_rr_theme->bwidth;
204             self->cbwidth = ob_rr_theme->cbwidth;
205         } else {
206             self->bwidth = self->cbwidth = 0;
207         }
208         STRUT_SET(self->innersize, self->cbwidth, self->cbwidth,
209                   self->cbwidth, self->cbwidth);
210         self->width = self->client->area.width + self->cbwidth * 2;
211         g_assert(self->width > 0);
212
213         /* set border widths */
214         XSetWindowBorderWidth(ob_display, self->plate,  self->cbwidth);
215         XSetWindowBorderWidth(ob_display, self->window, self->bwidth);
216         XSetWindowBorderWidth(ob_display, self->title,  self->bwidth);
217         XSetWindowBorderWidth(ob_display, self->handle, self->bwidth);
218         XSetWindowBorderWidth(ob_display, self->lgrip,  self->bwidth);
219         XSetWindowBorderWidth(ob_display, self->rgrip,  self->bwidth);
220   
221         /* position/size and map/unmap all the windows */
222
223         /* they all default off, they're turned on in layout_title */
224         self->icon_x = -1;
225         self->desk_x = -1;
226         self->shade_x = -1;
227         self->iconify_x = -1;
228         self->label_x = -1;
229         self->max_x = -1;
230         self->close_x = -1;
231
232         if (self->decorations & Decor_Titlebar) {
233             XMoveResizeWindow(ob_display, self->title,
234                               -self->bwidth, -self->bwidth,
235                               self->width, ob_rr_theme->title_height);
236             self->innersize.top += ob_rr_theme->title_height + self->bwidth;
237             XMapWindow(ob_display, self->title);
238
239             /* layout the title bar elements */
240             layout_title(self);
241         } else
242             XUnmapWindow(ob_display, self->title);
243
244         if (self->decorations & Decor_Handle) {
245             XMoveResizeWindow(ob_display, self->handle,
246                               -self->bwidth, FRAME_HANDLE_Y(self),
247                               self->width, ob_rr_theme->handle_height);
248             XMoveWindow(ob_display, self->lgrip,
249                         -self->bwidth, -self->bwidth);
250             XMoveWindow(ob_display, self->rgrip,
251                         -self->bwidth + self->width -
252                         ob_rr_theme->grip_width, -self->bwidth);
253             self->innersize.bottom += ob_rr_theme->handle_height +
254                 self->bwidth;
255             XMapWindow(ob_display, self->handle);
256
257             /* XXX make a subwindow with these dimentions?
258                ob_rr_theme->grip_width + self->bwidth, 0,
259                self->width - (ob_rr_theme->grip_width + self->bwidth) * 2,
260                ob_rr_theme->handle_height);
261             */
262         } else
263             XUnmapWindow(ob_display, self->handle);
264     }
265
266     if (resized) {
267         /* move and resize the plate */
268         XMoveResizeWindow(ob_display, self->plate,
269                           self->innersize.left - self->cbwidth,
270                           self->innersize.top - self->cbwidth,
271                           self->client->area.width,
272                           self->client->area.height);
273         /* when the client has StaticGravity, it likes to move around. */
274         XMoveWindow(ob_display, self->client->window, 0, 0);
275     }
276
277     if (resized) {
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 ? ob_rr_theme->title_height + self->bwidth*2:
290                    self->client->area.height +
291                    self->size.top + self->size.bottom));
292
293     if (moved) {
294         /* find the new coordinates, done after setting the frame.size, for
295            frame_client_gravity. */
296         self->area.x = self->client->area.x;
297         self->area.y = self->client->area.y;
298         frame_client_gravity((ObFrame*)self,
299                              &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, ob_root,
399                         client->area.x,
400                         client->area.y);
401     }
402
403     /* remove all the windows for the frame from the window_map */
404     g_hash_table_remove(window_map, &self->window);
405     g_hash_table_remove(window_map, &self->plate);
406     g_hash_table_remove(window_map, &self->title);
407     g_hash_table_remove(window_map, &self->label);
408     g_hash_table_remove(window_map, &self->max);
409     g_hash_table_remove(window_map, &self->close);
410     g_hash_table_remove(window_map, &self->desk);
411     g_hash_table_remove(window_map, &self->shade);
412     g_hash_table_remove(window_map, &self->icon);
413     g_hash_table_remove(window_map, &self->iconify);
414     g_hash_table_remove(window_map, &self->handle);
415     g_hash_table_remove(window_map, &self->lgrip);
416     g_hash_table_remove(window_map, &self->rgrip);
417
418     frame_free(self);
419 }
420
421 static void layout_title(ObFrame *self)
422 {
423     char *lc;
424     int x;
425     gboolean n, d, i, l, m, c, s;
426
427     n = d = i = l = m = c = s = FALSE;
428
429     /* figure out whats being shown, and the width of the label */
430     self->label_width = self->width - (ob_rr_theme->bevel + 1) * 2;
431     for (lc = ob_rr_theme->title_layout; *lc != '\0'; ++lc) {
432         switch (*lc) {
433         case 'N':
434             if (!(self->decorations & Decor_Icon)) break;
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 (!(self->decorations & Decor_AllDesktops)) break;
442             if (d) { *lc = ' '; break; } /* rm duplicates */
443             d = TRUE;
444             self->label_width -= (ob_rr_theme->button_size +
445                                   ob_rr_theme->bevel + 1);
446             break;
447         case 'S':
448             if (!(self->decorations & Decor_Shade)) break;
449             if (s) { *lc = ' '; break; } /* rm duplicates */
450             s = TRUE;
451             self->label_width -= (ob_rr_theme->button_size +
452                                   ob_rr_theme->bevel + 1);
453             break;
454         case 'I':
455             if (!(self->decorations & Decor_Iconify)) break;
456             if (i) { *lc = ' '; break; } /* rm duplicates */
457             i = TRUE;
458             self->label_width -= (ob_rr_theme->button_size +
459                                   ob_rr_theme->bevel + 1);
460             break;
461         case 'L':
462             if (l) { *lc = ' '; break; } /* rm duplicates */
463             l = TRUE;
464             break;
465         case 'M':
466             if (!(self->decorations & Decor_Maximize)) break;
467             if (m) { *lc = ' '; break; } /* rm duplicates */
468             m = TRUE;
469             self->label_width -= (ob_rr_theme->button_size +
470                                   ob_rr_theme->bevel + 1);
471             break;
472         case 'C':
473             if (!(self->decorations & Decor_Close)) break;
474             if (c) { *lc = ' '; break; } /* rm duplicates */
475             c = TRUE;
476             self->label_width -= (ob_rr_theme->button_size +
477                                   ob_rr_theme->bevel + 1);
478             break;
479         }
480     }
481     if (self->label_width < 1) self->label_width = 1;
482
483     XResizeWindow(ob_display, self->label, self->label_width,
484                   ob_rr_theme->label_height);
485   
486     if (!n) XUnmapWindow(ob_display, self->icon);
487     if (!d) XUnmapWindow(ob_display, self->desk);
488     if (!s) XUnmapWindow(ob_display, self->shade);
489     if (!i) XUnmapWindow(ob_display, self->iconify);
490     if (!l) XUnmapWindow(ob_display, self->label);
491     if (!m) XUnmapWindow(ob_display, self->max);
492     if (!c) XUnmapWindow(ob_display, self->close);
493
494     x = ob_rr_theme->bevel + 1;
495     for (lc = ob_rr_theme->title_layout; *lc != '\0'; ++lc) {
496         switch (*lc) {
497         case 'N':
498             if (!n) break;
499             self->icon_x = x;
500             XMapWindow(ob_display, self->icon);
501             XMoveWindow(ob_display, self->icon, x, ob_rr_theme->bevel);
502             x += ob_rr_theme->button_size + 2 + ob_rr_theme->bevel + 1;
503             break;
504         case 'D':
505             if (!d) break;
506             self->desk_x = x;
507             XMapWindow(ob_display, self->desk);
508             XMoveWindow(ob_display, self->desk, x, ob_rr_theme->bevel + 1);
509             x += ob_rr_theme->button_size + ob_rr_theme->bevel + 1;
510             break;
511         case 'S':
512             if (!s) break;
513             self->shade_x = x;
514             XMapWindow(ob_display, self->shade);
515             XMoveWindow(ob_display, self->shade, x, ob_rr_theme->bevel + 1);
516             x += ob_rr_theme->button_size + ob_rr_theme->bevel + 1;
517             break;
518         case 'I':
519             if (!i) break;
520             self->iconify_x = x;
521             XMapWindow(ob_display, self->iconify);
522             XMoveWindow(ob_display, self->iconify, x, ob_rr_theme->bevel + 1);
523             x += ob_rr_theme->button_size + ob_rr_theme->bevel + 1;
524             break;
525         case 'L':
526             if (!l) break;
527             self->label_x = x;
528             XMapWindow(ob_display, self->label);
529             XMoveWindow(ob_display, self->label, x, ob_rr_theme->bevel);
530             x += self->label_width + ob_rr_theme->bevel + 1;
531             break;
532         case 'M':
533             if (!m) break;
534             self->max_x = x;
535             XMapWindow(ob_display, self->max);
536             XMoveWindow(ob_display, self->max, x, ob_rr_theme->bevel + 1);
537             x += ob_rr_theme->button_size + ob_rr_theme->bevel + 1;
538             break;
539         case 'C':
540             if (!c) break;
541             self->close_x = x;
542             XMapWindow(ob_display, self->close);
543             XMoveWindow(ob_display, self->close, x, ob_rr_theme->bevel + 1);
544             x += ob_rr_theme->button_size + ob_rr_theme->bevel + 1;
545             break;
546         }
547     }
548 }
549
550 ObFrameContext frame_context_from_string(char *name)
551 {
552     if (!g_ascii_strcasecmp("root", name))
553         return OB_FRAME_CONTEXT_ROOT;
554     else if (!g_ascii_strcasecmp("client", name))
555         return OB_FRAME_CONTEXT_CLIENT;
556     else if (!g_ascii_strcasecmp("titlebar", name))
557         return OB_FRAME_CONTEXT_TITLEBAR;
558     else if (!g_ascii_strcasecmp("handle", name))
559         return OB_FRAME_CONTEXT_HANDLE;
560     else if (!g_ascii_strcasecmp("frame", name))
561         return OB_FRAME_CONTEXT_FRAME;
562     else if (!g_ascii_strcasecmp("blcorner", name))
563         return OB_FRAME_CONTEXT_BLCORNER;
564     else if (!g_ascii_strcasecmp("brcorner", name))
565         return OB_FRAME_CONTEXT_BRCORNER;
566     else if (!g_ascii_strcasecmp("maximize", name))
567         return OB_FRAME_CONTEXT_MAXIMIZE;
568     else if (!g_ascii_strcasecmp("alldesktops", name))
569         return OB_FRAME_CONTEXT_ALLDESKTOPS;
570     else if (!g_ascii_strcasecmp("shade", name))
571         return OB_FRAME_CONTEXT_SHADE;
572     else if (!g_ascii_strcasecmp("iconify", name))
573         return OB_FRAME_CONTEXT_ICONIFY;
574     else if (!g_ascii_strcasecmp("icon", name))
575         return OB_FRAME_CONTEXT_ICON;
576     else if (!g_ascii_strcasecmp("close", name))
577         return OB_FRAME_CONTEXT_CLOSE;
578     return OB_FRAME_CONTEXT_NONE;
579 }
580
581 ObFrameContext frame_context(ObClient *client, Window win)
582 {
583     ObFrame *self;
584
585     if (win == ob_root) return OB_FRAME_CONTEXT_ROOT;
586     if (client == NULL) return OB_FRAME_CONTEXT_NONE;
587     if (win == client->window) return OB_FRAME_CONTEXT_CLIENT;
588
589     self = client->frame;
590     if (win == self->window) return OB_FRAME_CONTEXT_FRAME;
591     if (win == self->plate)  return OB_FRAME_CONTEXT_CLIENT;
592     if (win == self->title)  return OB_FRAME_CONTEXT_TITLEBAR;
593     if (win == self->label)  return OB_FRAME_CONTEXT_TITLEBAR;
594     if (win == self->handle) return OB_FRAME_CONTEXT_HANDLE;
595     if (win == self->lgrip)  return OB_FRAME_CONTEXT_BLCORNER;
596     if (win == self->rgrip)  return OB_FRAME_CONTEXT_BRCORNER;
597     if (win == self->max)    return OB_FRAME_CONTEXT_MAXIMIZE;
598     if (win == self->iconify)return OB_FRAME_CONTEXT_ICONIFY;
599     if (win == self->close)  return OB_FRAME_CONTEXT_CLOSE;
600     if (win == self->icon)   return OB_FRAME_CONTEXT_ICON;
601     if (win == self->desk)   return OB_FRAME_CONTEXT_ALLDESKTOPS;
602     if (win == self->shade)  return OB_FRAME_CONTEXT_SHADE;
603
604     return OB_FRAME_CONTEXT_NONE;
605 }
606
607 void frame_client_gravity(ObFrame *self, int *x, int *y)
608 {
609     /* horizontal */
610     switch (self->client->gravity) {
611     default:
612     case NorthWestGravity:
613     case SouthWestGravity:
614     case WestGravity:
615         break;
616
617     case NorthGravity:
618     case SouthGravity:
619     case CenterGravity:
620         *x -= (self->size.left + self->size.right) / 2;
621         break;
622
623     case NorthEastGravity:
624     case SouthEastGravity:
625     case EastGravity:
626         *x -= self->size.left + self->size.right;
627         break;
628
629     case ForgetGravity:
630     case StaticGravity:
631         *x -= self->size.left;
632         break;
633     }
634
635     /* vertical */
636     switch (self->client->gravity) {
637     default:
638     case NorthWestGravity:
639     case NorthEastGravity:
640     case NorthGravity:
641         break;
642
643     case CenterGravity:
644     case EastGravity:
645     case WestGravity:
646         *y -= (self->size.top + self->size.bottom) / 2;
647         break;
648
649     case SouthWestGravity:
650     case SouthEastGravity:
651     case SouthGravity:
652         *y -= self->size.top + self->size.bottom;
653         break;
654
655     case ForgetGravity:
656     case StaticGravity:
657         *y -= self->size.top;
658         break;
659     }
660 }
661
662 void frame_frame_gravity(ObFrame *self, int *x, int *y)
663 {
664     /* horizontal */
665     switch (self->client->gravity) {
666     default:
667     case NorthWestGravity:
668     case WestGravity:
669     case SouthWestGravity:
670         break;
671     case NorthGravity:
672     case CenterGravity:
673     case SouthGravity:
674         *x += (self->size.left + self->size.right) / 2;
675         break;
676     case NorthEastGravity:
677     case EastGravity:
678     case SouthEastGravity:
679         *x += self->size.left + self->size.right;
680         break;
681     case StaticGravity:
682     case ForgetGravity:
683         *x += self->size.left;
684         break;
685     }
686
687     /* vertical */
688     switch (self->client->gravity) {
689     default:
690     case NorthWestGravity:
691     case WestGravity:
692     case SouthWestGravity:
693         break;
694     case NorthGravity:
695     case CenterGravity:
696     case SouthGravity:
697         *y += (self->size.top + self->size.bottom) / 2;
698         break;
699     case NorthEastGravity:
700     case EastGravity:
701     case SouthEastGravity:
702         *y += self->size.top + self->size.bottom;
703         break;
704     case StaticGravity:
705     case ForgetGravity:
706         *y += self->size.top;
707         break;
708     }
709 }