]> icculus.org git repositories - dana/openbox.git/blob - engines/default/plugin.c
Ramove unneeded frame_get_window
[dana/openbox.git] / engines / default / plugin.c
1 /* -*- indent-tabs-mode: nil; tab-width: 4; c-basic-offset: 4; -*-
2
3  frame_default_plugin.c for the Openbox window manager
4  Copyright (c) 2006        Mikael Magnusson
5  Copyright (c) 2003-2007   Dana Jansens
6
7  This program is free software; you can redistribute it and/or modify
8  it under the terms of the GNU General Public License as published by
9  the Free Software Foundation; either version 2 of the License, or
10  (at your option) any later version.
11
12  This program is distributed in the hope that it will be useful,
13  but WITHOUT ANY WARRANTY; without even the implied warranty of
14  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  GNU General Public License for more details.
16
17  See the COPYING file for a copy of the GNU General Public License.
18  */
19
20 #include "plugin.h"
21 #include "render.h"
22
23 /* Needed for the _() function */
24 #include <gettext.h>
25
26 #include "obt/prop.h"
27 #include "openbox/screen.h"
28
29 /* Needed for the grab_server */
30 #include "openbox/grab.h"
31
32 #include <X11/extensions/shape.h>
33
34 typedef enum
35 {
36     OB_FLAG_MAX = 1 << 0,
37     OB_FLAG_CLOSE = 1 << 1,
38     OB_FLAG_DESK = 1 << 2,
39     OB_FLAG_SHADE = 1 << 3,
40     OB_FLAG_ICONIFY = 1 << 4
41 } ObFrameFlags;
42
43 #define FRAME_EVENTMASK (EnterWindowMask | LeaveWindowMask | \
44                          ButtonPressMask | ButtonReleaseMask | \
45                          SubstructureRedirectMask | FocusChangeMask)
46 #define ELEMENT_EVENTMASK (ButtonPressMask | ButtonReleaseMask | \
47                            ButtonMotionMask | PointerMotionMask | \
48                            EnterWindowMask | LeaveWindowMask)
49
50 #define FRAME_HANDLE_Y(f) (f->size.top + f->client_area.height + f->cbwidth_b)
51
52 Display * obp_display;
53 gint obp_screen;
54 RrInstance *ob_rr_inst;
55
56 Window createWindow(Window parent, Visual *visual, gulong mask,
57         XSetWindowAttributes *attrib)
58 {
59     return XCreateWindow(obp_display, parent, 0, 0, 1, 1, 0, (visual ? 32
60             : RrDepth(ob_rr_inst)), InputOutput, (visual ? visual
61             : RrVisual(ob_rr_inst)), mask, attrib);
62
63 }
64
65 Visual *check_32bit_client(ObClient *c)
66 {
67     XWindowAttributes wattrib;
68     Status ret;
69
70     /* we're already running at 32 bit depth, yay. we don't need to use their
71      visual */
72     if (RrDepth(ob_rr_inst) == 32)
73         return NULL;
74
75     ret = XGetWindowAttributes(obp_display, c->w_client, &wattrib);
76     g_assert(ret != BadDrawable);
77     g_assert(ret != BadWindow);
78
79     if (wattrib.depth == 32)
80         return wattrib.visual;
81     return NULL;
82 }
83
84 /* Not used */
85 gint init(Display * display, gint screen)
86 {
87     ob_rr_inst = RrInstanceNew(display, screen);
88     if (ob_rr_inst == NULL)
89         ob_exit_with_error(_("Failed to initialize the obrender library."));
90     obp_display = display;
91     obp_screen = screen;
92 }
93
94 gpointer frame_new(struct _ObClient * client, Window w_client, Window w_frame)
95 {
96     XSetWindowAttributes attrib;
97     gulong mask;
98     ObDefaultFrame *self;
99     Visual *visual;
100
101     self = g_new0(ObDefaultFrame, 1);
102     self->client = client;
103
104     visual = check_32bit_client(client);
105
106     /* create the non-visible decor windows */
107
108     mask = 0;
109     if (visual) {
110         /* client has a 32-bit visual */
111         mask |= CWColormap | CWBackPixel | CWBorderPixel;
112         /* create a colormap with the visual */
113         OBDEFAULTFRAME(self)->colormap = attrib.colormap = XCreateColormap(
114                 obp_display, RootWindow(obp_display, obp_screen), visual,
115                 AllocNone);
116         attrib.background_pixel = BlackPixel(obp_display, obp_screen);
117         attrib.border_pixel = BlackPixel(obp_display, obp_screen);
118     }
119     self->window = w_frame;
120
121     /* create the visible decor windows */
122
123     mask = 0;
124     if (visual) {
125         /* client has a 32-bit visual */
126         mask |= CWColormap | CWBackPixel | CWBorderPixel;
127         attrib.colormap = RrColormap(ob_rr_inst);
128     }
129
130     self->backback = createWindow(self->window, NULL, mask, &attrib);
131     self->backfront = createWindow(self->backback, NULL, mask, &attrib);
132
133     mask |= CWEventMask;
134     attrib.event_mask = ELEMENT_EVENTMASK;
135     self->innerleft = createWindow(self->window, NULL, mask, &attrib);
136     self->innertop = createWindow(self->window, NULL, mask, &attrib);
137     self->innerright = createWindow(self->window, NULL, mask, &attrib);
138     self->innerbottom = createWindow(self->window, NULL, mask, &attrib);
139
140     self->innerblb = createWindow(self->innerbottom, NULL, mask, &attrib);
141     self->innerbrb = createWindow(self->innerbottom, NULL, mask, &attrib);
142     self->innerbll = createWindow(self->innerleft, NULL, mask, &attrib);
143     self->innerbrr = createWindow(self->innerright, NULL, mask, &attrib);
144
145     self->title = createWindow(self->window, NULL, mask, &attrib);
146     self->titleleft = createWindow(self->window, NULL, mask, &attrib);
147     self->titletop = createWindow(self->window, NULL, mask, &attrib);
148     self->titletopleft = createWindow(self->window, NULL, mask, &attrib);
149     self->titletopright = createWindow(self->window, NULL, mask, &attrib);
150     self->titleright = createWindow(self->window, NULL, mask, &attrib);
151     self->titlebottom = createWindow(self->window, NULL, mask, &attrib);
152
153     self->topresize = createWindow(self->title, NULL, mask, &attrib);
154     self->tltresize = createWindow(self->title, NULL, mask, &attrib);
155     self->tllresize = createWindow(self->title, NULL, mask, &attrib);
156     self->trtresize = createWindow(self->title, NULL, mask, &attrib);
157     self->trrresize = createWindow(self->title, NULL, mask, &attrib);
158
159     self->left = createWindow(self->window, NULL, mask, &attrib);
160     self->right = createWindow(self->window, NULL, mask, &attrib);
161
162     self->label = createWindow(self->title, NULL, mask, &attrib);
163     self->max = createWindow(self->title, NULL, mask, &attrib);
164     self->close = createWindow(self->title, NULL, mask, &attrib);
165     self->desk = createWindow(self->title, NULL, mask, &attrib);
166     self->shade = createWindow(self->title, NULL, mask, &attrib);
167     self->icon = createWindow(self->title, NULL, mask, &attrib);
168     self->iconify = createWindow(self->title, NULL, mask, &attrib);
169
170     self->handle = createWindow(self->window, NULL, mask, &attrib);
171     self->lgrip = createWindow(self->handle, NULL, mask, &attrib);
172     self->rgrip = createWindow(self->handle, NULL, mask, &attrib);
173
174     self->handleleft = createWindow(self->handle, NULL, mask, &attrib);
175     self->handleright = createWindow(self->handle, NULL, mask, &attrib);
176
177     self->handletop = createWindow(self->window, NULL, mask, &attrib);
178     self->handlebottom = createWindow(self->window, NULL, mask, &attrib);
179     self->lgripleft = createWindow(self->window, NULL, mask, &attrib);
180     self->lgriptop = createWindow(self->window, NULL, mask, &attrib);
181     self->lgripbottom = createWindow(self->window, NULL, mask, &attrib);
182     self->rgripright = createWindow(self->window, NULL, mask, &attrib);
183     self->rgriptop = createWindow(self->window, NULL, mask, &attrib);
184     self->rgripbottom = createWindow(self->window, NULL, mask, &attrib);
185
186     self->stitle = g_strdup("");
187     self->focused = FALSE;
188
189     /* the other stuff is shown based on decor settings */
190     XMapWindow(obp_display, self->label);
191     XMapWindow(obp_display, self->backback);
192     XMapWindow(obp_display, self->backfront);
193
194     self->hover_flag = OB_BUTTON_NONE;
195     self->press_flag = OB_BUTTON_NONE;
196
197     set_theme_statics(self);
198
199     return self;
200 }
201
202 void set_theme_statics(gpointer _self)
203 {
204     ObDefaultFrame * self = (ObDefaultFrame *) _self;
205     /* set colors/appearance/sizes for stuff that doesn't change */
206     XResizeWindow(obp_display, self->max, theme_config.button_size,
207             theme_config.button_size);
208     XResizeWindow(obp_display, self->iconify, theme_config.button_size,
209             theme_config.button_size);
210     XResizeWindow(obp_display, self->icon, theme_config.button_size + 2,
211             theme_config.button_size + 2);
212     XResizeWindow(obp_display, self->close, theme_config.button_size,
213             theme_config.button_size);
214     XResizeWindow(obp_display, self->desk, theme_config.button_size,
215             theme_config.button_size);
216     XResizeWindow(obp_display, self->shade, theme_config.button_size,
217             theme_config.button_size);
218     XResizeWindow(obp_display, self->tltresize, theme_config.grip_width,
219             theme_config.paddingy + 1);
220     XResizeWindow(obp_display, self->trtresize, theme_config.grip_width,
221             theme_config.paddingy + 1);
222     XResizeWindow(obp_display, self->tllresize, theme_config.paddingx + 1,
223             theme_config.title_height);
224     XResizeWindow(obp_display, self->trrresize, theme_config.paddingx + 1,
225             theme_config.title_height);
226
227     /* set up the dynamic appearances */
228     self->a_unfocused_title = RrAppearanceCopy(theme_config.a_unfocused_title);
229     self->a_focused_title = RrAppearanceCopy(theme_config.a_focused_title);
230     self->a_unfocused_label = RrAppearanceCopy(theme_config.a_unfocused_label);
231     self->a_focused_label = RrAppearanceCopy(theme_config.a_focused_label);
232     self->a_unfocused_handle
233             = RrAppearanceCopy(theme_config.a_unfocused_handle);
234     self->a_focused_handle = RrAppearanceCopy(theme_config.a_focused_handle);
235     self->a_icon = RrAppearanceCopy(theme_config.a_icon);
236 }
237
238 void free_theme_statics(gpointer _self)
239 {
240     ObDefaultFrame * self = (ObDefaultFrame *) _self;
241     RrAppearanceFree(self->a_unfocused_title);
242     RrAppearanceFree(self->a_focused_title);
243     RrAppearanceFree(self->a_unfocused_label);
244     RrAppearanceFree(self->a_focused_label);
245     RrAppearanceFree(self->a_unfocused_handle);
246     RrAppearanceFree(self->a_focused_handle);
247     RrAppearanceFree(self->a_icon);
248 }
249
250 void frame_free(gpointer self)
251 {
252     free_theme_statics(OBDEFAULTFRAME(self));
253     XDestroyWindow(obp_display, OBDEFAULTFRAME(self)->window);
254     if (OBDEFAULTFRAME(self)->colormap)
255         XFreeColormap(obp_display, OBDEFAULTFRAME(self)->colormap);
256
257     g_free(OBDEFAULTFRAME(self)->stitle);
258     g_free(self);
259 }
260
261 void frame_adjust_theme(gpointer self)
262 {
263     free_theme_statics(self);
264     set_theme_statics(self);
265 }
266
267 void frame_adjust_shape(gpointer _self)
268 {
269 #ifdef SHAPE
270     ObDefaultFrame * self = (ObDefaultFrame *) _self;
271     gint num;
272     XRectangle xrect[2];
273
274     if (!self->client->shaped)
275     {
276         /* clear the shape on the frame window */
277         XShapeCombineMask(obp_display, self->window, ShapeBounding,
278                 self->size.left,
279                 self->size.top,
280                 None, ShapeSet);
281     }
282     else
283     {
284         /* make the frame's shape match the clients */
285         XShapeCombineShape(obp_display, self->window, ShapeBounding,
286                 self->size.left,
287                 self->size.top,
288                 self->client->w_client,
289                 ShapeBounding, ShapeSet);
290
291         num = 0;
292         if (self->decorations & OB_FRAME_DECOR_TITLEBAR)
293         {
294             xrect[0].x = 0;
295             xrect[0].y = 0;
296             xrect[0].width = self->area.width;
297             xrect[0].height = self->size.top;
298             ++num;
299         }
300
301         if (self->decorations & OB_FRAME_DECOR_HANDLE &&
302                 theme_config.handle_height> 0)
303         {
304             xrect[1].x = 0;
305             xrect[1].y = FRAME_HANDLE_Y(self);
306             xrect[1].width = self->area.width;
307             xrect[1].height = theme_config.handle_height +
308             self->bwidth * 2;
309             ++num;
310         }
311
312         XShapeCombineRectangles(obp_display, self->window,
313                 ShapeBounding, 0, 0, xrect, num,
314                 ShapeUnion, Unsorted);
315     }
316 #endif
317 }
318
319 void frame_grab(gpointer _self, GHashTable * window_map)
320 {
321     ObDefaultFrame * self = (ObDefaultFrame *) _self;
322     /* DO NOT map the client window here. we used to do that, but it is bogus.
323      we need to set up the client's dimensions and everything before we
324      send a mapnotify or we create race conditions.
325      */
326
327     /* reparent the client to the frame */
328     XReparentWindow(obp_display, self->client->w_client, self->window, 0, 0);
329
330     /*
331      When reparenting the client window, it is usually not mapped yet, since
332      this occurs from a MapRequest. However, in the case where Openbox is
333      starting up, the window is already mapped, so we'll see an unmap event
334      for it.
335      */
336     if (ob_state() == OB_STATE_STARTING)
337         ++self->client->ignore_unmaps;
338
339     /* select the event mask on the client's parent (to receive config/map
340      req's) the ButtonPress is to catch clicks on the client border */
341     XSelectInput(obp_display, self->window, FRAME_EVENTMASK);
342
343     /* set all the windows for the frame in the window_map */
344     g_hash_table_insert(window_map, &self->window, self->client);
345     g_hash_table_insert(window_map, &self->backback, self->client);
346     g_hash_table_insert(window_map, &self->backfront, self->client);
347     g_hash_table_insert(window_map, &self->innerleft, self->client);
348     g_hash_table_insert(window_map, &self->innertop, self->client);
349     g_hash_table_insert(window_map, &self->innerright, self->client);
350     g_hash_table_insert(window_map, &self->innerbottom, self->client);
351     g_hash_table_insert(window_map, &self->title, self->client);
352     g_hash_table_insert(window_map, &self->label, self->client);
353     g_hash_table_insert(window_map, &self->max, self->client);
354     g_hash_table_insert(window_map, &self->close, self->client);
355     g_hash_table_insert(window_map, &self->desk, self->client);
356     g_hash_table_insert(window_map, &self->shade, self->client);
357     g_hash_table_insert(window_map, &self->icon, self->client);
358     g_hash_table_insert(window_map, &self->iconify, self->client);
359     g_hash_table_insert(window_map, &self->handle, self->client);
360     g_hash_table_insert(window_map, &self->lgrip, self->client);
361     g_hash_table_insert(window_map, &self->rgrip, self->client);
362     g_hash_table_insert(window_map, &self->topresize, self->client);
363     g_hash_table_insert(window_map, &self->tltresize, self->client);
364     g_hash_table_insert(window_map, &self->tllresize, self->client);
365     g_hash_table_insert(window_map, &self->trtresize, self->client);
366     g_hash_table_insert(window_map, &self->trrresize, self->client);
367     g_hash_table_insert(window_map, &self->left, self->client);
368     g_hash_table_insert(window_map, &self->right, self->client);
369     g_hash_table_insert(window_map, &self->titleleft, self->client);
370     g_hash_table_insert(window_map, &self->titletop, self->client);
371     g_hash_table_insert(window_map, &self->titletopleft, self->client);
372     g_hash_table_insert(window_map, &self->titletopright, self->client);
373     g_hash_table_insert(window_map, &self->titleright, self->client);
374     g_hash_table_insert(window_map, &self->titlebottom, self->client);
375     g_hash_table_insert(window_map, &self->handleleft, self->client);
376     g_hash_table_insert(window_map, &self->handletop, self->client);
377     g_hash_table_insert(window_map, &self->handleright, self->client);
378     g_hash_table_insert(window_map, &self->handlebottom, self->client);
379     g_hash_table_insert(window_map, &self->lgripleft, self->client);
380     g_hash_table_insert(window_map, &self->lgriptop, self->client);
381     g_hash_table_insert(window_map, &self->lgripbottom, self->client);
382     g_hash_table_insert(window_map, &self->rgripright, self->client);
383     g_hash_table_insert(window_map, &self->rgriptop, self->client);
384     g_hash_table_insert(window_map, &self->rgripbottom, self->client);
385 }
386
387 void frame_ungrab(gpointer _self, GHashTable * window_map)
388 {
389     ObDefaultFrame * self = (ObDefaultFrame *) _self;
390     XEvent ev;
391     gboolean reparent = TRUE;
392
393     /* check if the app has already reparented its window away */
394     while (XCheckTypedWindowEvent(obp_display, self->client->w_client,
395             ReparentNotify, &ev)) {
396         /* This check makes sure we don't catch our own reparent action to
397          our frame window. This doesn't count as the app reparenting itself
398          away of course.
399
400          Reparent events that are generated by us are just discarded here.
401          They are of no consequence to us anyhow.
402          */
403         if (ev.xreparent.parent != self->window) {
404             reparent = FALSE;
405             XPutBackEvent(obp_display, &ev);
406             break;
407         }
408     }
409
410     if (reparent) {
411         /* according to the ICCCM - if the client doesn't reparent itself,
412          then we will reparent the window to root for them */
413         XReparentWindow(obp_display, self->client->w_client, RootWindow(
414                 obp_display, obp_screen), self->client_area.x,
415                 self->client_area.y);
416     }
417
418     /* remove all the windows for the frame from the window_map */
419     g_hash_table_remove(window_map, &self->window);
420     g_hash_table_remove(window_map, &self->backback);
421     g_hash_table_remove(window_map, &self->backfront);
422     g_hash_table_remove(window_map, &self->innerleft);
423     g_hash_table_remove(window_map, &self->innertop);
424     g_hash_table_remove(window_map, &self->innerright);
425     g_hash_table_remove(window_map, &self->innerbottom);
426     g_hash_table_remove(window_map, &self->title);
427     g_hash_table_remove(window_map, &self->label);
428     g_hash_table_remove(window_map, &self->max);
429     g_hash_table_remove(window_map, &self->close);
430     g_hash_table_remove(window_map, &self->desk);
431     g_hash_table_remove(window_map, &self->shade);
432     g_hash_table_remove(window_map, &self->icon);
433     g_hash_table_remove(window_map, &self->iconify);
434     g_hash_table_remove(window_map, &self->handle);
435     g_hash_table_remove(window_map, &self->lgrip);
436     g_hash_table_remove(window_map, &self->rgrip);
437     g_hash_table_remove(window_map, &self->topresize);
438     g_hash_table_remove(window_map, &self->tltresize);
439     g_hash_table_remove(window_map, &self->tllresize);
440     g_hash_table_remove(window_map, &self->trtresize);
441     g_hash_table_remove(window_map, &self->trrresize);
442     g_hash_table_remove(window_map, &self->left);
443     g_hash_table_remove(window_map, &self->right);
444     g_hash_table_remove(window_map, &self->titleleft);
445     g_hash_table_remove(window_map, &self->titletop);
446     g_hash_table_remove(window_map, &self->titletopleft);
447     g_hash_table_remove(window_map, &self->titletopright);
448     g_hash_table_remove(window_map, &self->titleright);
449     g_hash_table_remove(window_map, &self->titlebottom);
450     g_hash_table_remove(window_map, &self->handleleft);
451     g_hash_table_remove(window_map, &self->handletop);
452     g_hash_table_remove(window_map, &self->handleright);
453     g_hash_table_remove(window_map, &self->handlebottom);
454     g_hash_table_remove(window_map, &self->lgripleft);
455     g_hash_table_remove(window_map, &self->lgriptop);
456     g_hash_table_remove(window_map, &self->lgripbottom);
457     g_hash_table_remove(window_map, &self->rgripright);
458     g_hash_table_remove(window_map, &self->rgriptop);
459     g_hash_table_remove(window_map, &self->rgripbottom);
460
461     obt_main_loop_timeout_remove_data(plugin.ob_main_loop, flash_timeout, self,
462             TRUE);
463 }
464
465 ObFrameContext frame_context(gpointer _self, Window win, gint x, gint y)
466 {
467     ObDefaultFrame * self = OBDEFAULTFRAME(_self);
468
469     /* when the user clicks in the corners of the titlebar and the client
470      is fully maximized, then treat it like they clicked in the
471      button that is there */
472     if (self->max_horz && self->max_vert && (win == self->title || win
473             == self->titletop || win == self->titleleft || win
474             == self->titletopleft || win == self->titleright || win
475             == self->titletopright)) {
476         /* get the mouse coords in reference to the whole frame */
477         gint fx = x;
478         gint fy = y;
479
480         /* these windows are down a border width from the top of the frame */
481         if (win == self->title || win == self->titleleft || win
482                 == self->titleright)
483             fy += self->bwidth;
484
485         /* title is a border width in from the edge */
486         if (win == self->title)
487             fx += self->bwidth;
488         /* titletop is a bit to the right */
489         else if (win == self->titletop)
490             fx += theme_config.grip_width + self->bwidth;
491         /* titletopright is way to the right edge */
492         else if (win == self->titletopright)
493             fx += self->area.width - (theme_config.grip_width + self->bwidth);
494         /* titleright is even more way to the right edge */
495         else if (win == self->titleright)
496             fx += self->area.width - self->bwidth;
497
498         /* figure out if we're over the area that should be considered a
499          button */
500         if (fy < self->bwidth + theme_config.paddingy + 1
501                 + theme_config.button_size) {
502             if (fx < (self->bwidth + theme_config.paddingx + 1
503                     + theme_config.button_size)) {
504                 if (self->leftmost != OB_FRAME_CONTEXT_NONE)
505                     return self->leftmost;
506             }
507             else if (fx >= (self->area.width - (self->bwidth
508                     + theme_config.paddingx + 1 + theme_config.button_size))) {
509                 if (self->rightmost != OB_FRAME_CONTEXT_NONE)
510                     return self->rightmost;
511             }
512         }
513
514         /* there is no resizing maximized windows so make them the titlebar
515          context */
516         return OB_FRAME_CONTEXT_TITLEBAR;
517     }
518     else if (self->max_vert
519             && (win == self->titletop || win == self->topresize))
520         /* can't resize vertically when max vert */
521         return OB_FRAME_CONTEXT_TITLEBAR;
522     else if (self->shaded && (win == self->titletop || win == self->topresize))
523         /* can't resize vertically when shaded */
524         return OB_FRAME_CONTEXT_TITLEBAR;
525
526     if (win == self->window)
527         return OB_FRAME_CONTEXT_FRAME;
528     if (win == self->label)
529         return OB_FRAME_CONTEXT_TITLEBAR;
530     if (win == self->handle)
531         return OB_FRAME_CONTEXT_BOTTOM;
532     if (win == self->handletop)
533         return OB_FRAME_CONTEXT_BOTTOM;
534     if (win == self->handlebottom)
535         return OB_FRAME_CONTEXT_BOTTOM;
536     if (win == self->handleleft)
537         return OB_FRAME_CONTEXT_BLCORNER;
538     if (win == self->lgrip)
539         return OB_FRAME_CONTEXT_BLCORNER;
540     if (win == self->lgripleft)
541         return OB_FRAME_CONTEXT_BLCORNER;
542     if (win == self->lgriptop)
543         return OB_FRAME_CONTEXT_BLCORNER;
544     if (win == self->lgripbottom)
545         return OB_FRAME_CONTEXT_BLCORNER;
546     if (win == self->handleright)
547         return OB_FRAME_CONTEXT_BRCORNER;
548     if (win == self->rgrip)
549         return OB_FRAME_CONTEXT_BRCORNER;
550     if (win == self->rgripright)
551         return OB_FRAME_CONTEXT_BLCORNER;
552     if (win == self->rgriptop)
553         return OB_FRAME_CONTEXT_BLCORNER;
554     if (win == self->rgripbottom)
555         return OB_FRAME_CONTEXT_BLCORNER;
556     if (win == self->title)
557         return OB_FRAME_CONTEXT_TITLEBAR;
558     if (win == self->titlebottom)
559         return OB_FRAME_CONTEXT_TITLEBAR;
560     if (win == self->titleleft)
561         return OB_FRAME_CONTEXT_TLCORNER;
562     if (win == self->titletopleft)
563         return OB_FRAME_CONTEXT_TLCORNER;
564     if (win == self->titleright)
565         return OB_FRAME_CONTEXT_TRCORNER;
566     if (win == self->titletopright)
567         return OB_FRAME_CONTEXT_TRCORNER;
568     if (win == self->titletop)
569         return OB_FRAME_CONTEXT_TOP;
570     if (win == self->topresize)
571         return OB_FRAME_CONTEXT_TOP;
572     if (win == self->tltresize)
573         return OB_FRAME_CONTEXT_TLCORNER;
574     if (win == self->tllresize)
575         return OB_FRAME_CONTEXT_TLCORNER;
576     if (win == self->trtresize)
577         return OB_FRAME_CONTEXT_TRCORNER;
578     if (win == self->trrresize)
579         return OB_FRAME_CONTEXT_TRCORNER;
580     if (win == self->left)
581         return OB_FRAME_CONTEXT_LEFT;
582     if (win == self->right)
583         return OB_FRAME_CONTEXT_RIGHT;
584     if (win == self->innertop)
585         return OB_FRAME_CONTEXT_TITLEBAR;
586     if (win == self->innerleft)
587         return OB_FRAME_CONTEXT_LEFT;
588     if (win == self->innerbottom)
589         return OB_FRAME_CONTEXT_BOTTOM;
590     if (win == self->innerright)
591         return OB_FRAME_CONTEXT_RIGHT;
592     if (win == self->max)
593         return OB_FRAME_CONTEXT_MAXIMIZE;
594     if (win == self->iconify)
595         return OB_FRAME_CONTEXT_ICONIFY;
596     if (win == self->close)
597         return OB_FRAME_CONTEXT_CLOSE;
598     if (win == self->icon)
599         return OB_FRAME_CONTEXT_ICON;
600     if (win == self->desk)
601         return OB_FRAME_CONTEXT_ALLDESKTOPS;
602     if (win == self->shade)
603         return OB_FRAME_CONTEXT_SHADE;
604
605     return OB_FRAME_CONTEXT_NONE;
606 }
607
608 void frame_set_is_visible(gpointer self, gboolean b)
609 {
610     OBDEFAULTFRAME(self)->visible = b;
611 }
612
613 void frame_set_is_focus(gpointer self, gboolean b)
614 {
615     OBDEFAULTFRAME(self)->focused = b;
616 }
617
618 void frame_set_is_max_vert(gpointer self, gboolean b)
619 {
620     OBDEFAULTFRAME(self)->max_vert = b;
621 }
622
623 void frame_set_is_max_horz(gpointer self, gboolean b)
624 {
625     OBDEFAULTFRAME(self)->max_horz = b;
626 }
627
628 void frame_set_is_shaded(gpointer self, gboolean b)
629 {
630     OBDEFAULTFRAME(self)->shaded = b;
631 }
632
633 void frame_unfocus(gpointer self)
634 {
635     OBDEFAULTFRAME(self)->focused = FALSE;
636 }
637
638 void frame_flash_start(gpointer _self)
639 {
640     ObDefaultFrame * self = (ObDefaultFrame *) _self;
641     self->flash_on = self->focused;
642
643     if (!self->flashing)
644         obt_main_loop_timeout_add(plugin.ob_main_loop, G_USEC_PER_SEC * 0.6,
645                 flash_timeout, self, g_direct_equal, flash_done);
646     g_get_current_time(&self->flash_end);
647     g_time_val_add(&self->flash_end, G_USEC_PER_SEC * 5);
648
649     self->flashing = TRUE;
650 }
651
652 void frame_flash_stop(gpointer _self)
653 {
654     ObDefaultFrame * self = (ObDefaultFrame *) _self;
655     self->flashing = FALSE;
656 }
657
658 void frame_set_decorations(gpointer self, ObFrameDecorations d)
659 {
660     OBDEFAULTFRAME(self)->decorations = d;
661 }
662
663 void frame_get_window_area(gpointer self, Rect * r)
664 {
665     /* *r = (OBDEFAULTFRAME(self)->area) ??? */ 
666     memcpy(r, &(OBDEFAULTFRAME(self)->area), sizeof(Rect));
667 }
668 void frame_set_client_area(gpointer self, Rect r)
669 {
670     OBDEFAULTFRAME(self)->client_area = r;
671 }
672
673 void frame_update_layout(gpointer _self, Rect area, gboolean is_resize, gboolean is_fake)
674 {
675     ObDefaultFrame * self = (ObDefaultFrame *) _self;
676     Strut oldsize;
677
678     oldsize = self->size;
679     self->client_area = area;
680     self->area = self->client_area;
681
682     /* do this before changing the frame's status like max_horz max_vert */
683     frame_adjust_cursors(self);
684
685     if (self->decorations & OB_FRAME_DECOR_BORDER
686             || (plugin.config_theme_keepborder)) {
687         self->bwidth = theme_config.fbwidth;
688     }
689     else {
690         self->bwidth = 0;
691     }
692
693     if (self->decorations & OB_FRAME_DECOR_BORDER) {
694         self->cbwidth_l = theme_config.cbwidthx;
695         self->cbwidth_r = theme_config.cbwidthx;
696         self->cbwidth_t = theme_config.cbwidthy;
697         self->cbwidth_b = theme_config.cbwidthy;
698     }
699     else {
700         self->cbwidth_l = 0;
701         self->cbwidth_t = 0;
702         self->cbwidth_r = 0;
703         self->cbwidth_b = 0;
704     }
705
706     if (self->max_horz) {
707         self->cbwidth_l = 0;
708         self->cbwidth_r = 0;
709         self->width = self->client_area.width;
710         if (self->max_vert)
711             self->cbwidth_b = 0;
712     }
713     else {
714         self->width = self->client_area.width + self->cbwidth_l
715                 + self->cbwidth_r;
716     }
717
718     /* some elements are sized based of the width, so don't let them have
719      negative values */
720     self->width = MAX(self->width, (theme_config.grip_width + self->bwidth) * 2
721             + 1);
722
723     STRUT_SET(self->size, self->cbwidth_l
724             + (!self->max_horz ? self->bwidth : 0), self->cbwidth_t
725             + self->bwidth, self->cbwidth_r + (!self->max_horz ? self->bwidth
726             : 0), self->cbwidth_b
727             + (!self->max_horz || !self->max_vert ? self->bwidth : 0));
728
729     if (self->decorations & OB_FRAME_DECOR_TITLEBAR)
730         self->size.top += theme_config.title_height + self->bwidth;
731     if (self->decorations & OB_FRAME_DECOR_HANDLE && theme_config.handle_height
732             > 0) {
733         self->size.bottom += theme_config.handle_height + self->bwidth;
734     }
735
736     /* position/size and map/unmap all the windows */
737     if (!is_fake) {
738         gint innercornerheight = theme_config.grip_width - self->size.bottom;
739
740         if (self->cbwidth_l) {
741             XMoveResizeWindow(obp_display, self->innerleft, self->size.left
742                     - self->cbwidth_l, self->size.top, self->cbwidth_l,
743                     self->client_area.height);
744
745             XMapWindow(obp_display, self->innerleft);
746         }
747         else
748             XUnmapWindow(obp_display, self->innerleft);
749
750         if (self->cbwidth_l && innercornerheight > 0) {
751             XMoveResizeWindow(obp_display, self->innerbll, 0,
752                     self->client_area.height - (theme_config.grip_width
753                             - self->size.bottom), self->cbwidth_l,
754                     theme_config.grip_width - self->size.bottom);
755
756             XMapWindow(obp_display, self->innerbll);
757         }
758         else
759             XUnmapWindow(obp_display, self->innerbll);
760
761         if (self->cbwidth_r) {
762             XMoveResizeWindow(obp_display, self->innerright, self->size.left
763                     + self->client_area.width, self->size.top, self->cbwidth_r,
764                     self->client_area.height);
765
766             XMapWindow(obp_display, self->innerright);
767         }
768         else
769             XUnmapWindow(obp_display, self->innerright);
770
771         if (self->cbwidth_r && innercornerheight > 0) {
772             XMoveResizeWindow(obp_display, self->innerbrr, 0,
773                     self->client_area.height - (theme_config.grip_width
774                             - self->size.bottom), self->cbwidth_r,
775                     theme_config.grip_width - self->size.bottom);
776
777             XMapWindow(obp_display, self->innerbrr);
778         }
779         else
780             XUnmapWindow(obp_display, self->innerbrr);
781
782         if (self->cbwidth_t) {
783             XMoveResizeWindow(
784                     obp_display,
785                     self->innertop,
786                     self->size.left - self->cbwidth_l,
787                     self->size.top - self->cbwidth_t,
788                     self->client_area.width + self->cbwidth_l + self->cbwidth_r,
789                     self->cbwidth_t);
790
791             XMapWindow(obp_display, self->innertop);
792         }
793         else
794             XUnmapWindow(obp_display, self->innertop);
795
796         if (self->cbwidth_b) {
797             XMoveResizeWindow(obp_display, self->innerbottom, self->size.left
798                     - self->cbwidth_l, self->size.top
799                     + self->client_area.height, self->client_area.width
800                     + self->cbwidth_l + self->cbwidth_r, self->cbwidth_b);
801
802             XMoveResizeWindow(obp_display, self->innerblb, 0, 0,
803                     theme_config.grip_width + self->bwidth, self->cbwidth_b);
804             XMoveResizeWindow(obp_display, self->innerbrb,
805                     self->client_area.width + self->cbwidth_l + self->cbwidth_r
806                             - (theme_config.grip_width + self->bwidth), 0,
807                     theme_config.grip_width + self->bwidth, self->cbwidth_b);
808
809             XMapWindow(obp_display, self->innerbottom);
810             XMapWindow(obp_display, self->innerblb);
811             XMapWindow(obp_display, self->innerbrb);
812         }
813         else {
814             XUnmapWindow(obp_display, self->innerbottom);
815             XUnmapWindow(obp_display, self->innerblb);
816             XUnmapWindow(obp_display, self->innerbrb);
817         }
818
819         if (self->bwidth) {
820             gint titlesides;
821
822             /* height of titleleft and titleright */
823             titlesides = (!self->max_horz ? theme_config.grip_width : 0);
824
825             XMoveResizeWindow(obp_display, self->titletop,
826                     theme_config.grip_width + self->bwidth, 0,
827                     /* width + bwidth*2 - bwidth*2 - grips*2 */
828                     self->width - theme_config.grip_width * 2, self->bwidth);
829             XMoveResizeWindow(obp_display, self->titletopleft, 0, 0,
830                     theme_config.grip_width + self->bwidth, self->bwidth);
831             XMoveResizeWindow(obp_display, self->titletopright,
832                     self->client_area.width + self->size.left
833                             + self->size.right - theme_config.grip_width
834                             - self->bwidth, 0, theme_config.grip_width
835                             + self->bwidth, self->bwidth);
836
837             if (titlesides > 0) {
838                 XMoveResizeWindow(obp_display, self->titleleft, 0,
839                         self->bwidth, self->bwidth, titlesides);
840                 XMoveResizeWindow(obp_display, self->titleright,
841                         self->client_area.width + self->size.left
842                                 + self->size.right - self->bwidth,
843                         self->bwidth, self->bwidth, titlesides);
844
845                 XMapWindow(obp_display, self->titleleft);
846                 XMapWindow(obp_display, self->titleright);
847             }
848             else {
849                 XUnmapWindow(obp_display, self->titleleft);
850                 XUnmapWindow(obp_display, self->titleright);
851             }
852
853             XMapWindow(obp_display, self->titletop);
854             XMapWindow(obp_display, self->titletopleft);
855             XMapWindow(obp_display, self->titletopright);
856
857             if (self->decorations & OB_FRAME_DECOR_TITLEBAR) {
858                 XMoveResizeWindow(obp_display, self->titlebottom,
859                         (self->max_horz ? 0 : self->bwidth),
860                         theme_config.title_height + self->bwidth, self->width,
861                         self->bwidth);
862
863                 XMapWindow(obp_display, self->titlebottom);
864             }
865             else
866                 XUnmapWindow(obp_display, self->titlebottom);
867         }
868         else {
869             XUnmapWindow(obp_display, self->titlebottom);
870
871             XUnmapWindow(obp_display, self->titletop);
872             XUnmapWindow(obp_display, self->titletopleft);
873             XUnmapWindow(obp_display, self->titletopright);
874             XUnmapWindow(obp_display, self->titleleft);
875             XUnmapWindow(obp_display, self->titleright);
876         }
877
878         if (self->decorations & OB_FRAME_DECOR_TITLEBAR) {
879             XMoveResizeWindow(obp_display, self->title, (self->max_horz ? 0
880                     : self->bwidth), self->bwidth, self->width,
881                     theme_config.title_height);
882
883             XMapWindow(obp_display, self->title);
884
885             if (self->decorations & OB_FRAME_DECOR_GRIPS) {
886                 XMoveResizeWindow(obp_display, self->topresize,
887                         theme_config.grip_width, 0, self->width
888                                 - theme_config.grip_width *2,
889                         theme_config.paddingy + 1);
890
891                 XMoveWindow(obp_display, self->tltresize, 0, 0);
892                 XMoveWindow(obp_display, self->tllresize, 0, 0);
893                 XMoveWindow(obp_display, self->trtresize, self->width
894                         - theme_config.grip_width, 0);
895                 XMoveWindow(obp_display, self->trrresize, self->width
896                         - theme_config.paddingx - 1, 0);
897
898                 XMapWindow(obp_display, self->topresize);
899                 XMapWindow(obp_display, self->tltresize);
900                 XMapWindow(obp_display, self->tllresize);
901                 XMapWindow(obp_display, self->trtresize);
902                 XMapWindow(obp_display, self->trrresize);
903             }
904             else {
905                 XUnmapWindow(obp_display, self->topresize);
906                 XUnmapWindow(obp_display, self->tltresize);
907                 XUnmapWindow(obp_display, self->tllresize);
908                 XUnmapWindow(obp_display, self->trtresize);
909                 XUnmapWindow(obp_display, self->trrresize);
910             }
911         }
912         else
913             XUnmapWindow(obp_display, self->title);
914     }
915
916     if ((self->decorations & OB_FRAME_DECOR_TITLEBAR))
917         /* layout the title bar elements */
918         layout_title(self);
919
920     if (!is_fake) {
921         gint sidebwidth = self->max_horz ? 0 : self->bwidth;
922
923         if (self->bwidth && self->size.bottom) {
924             XMoveResizeWindow(obp_display, self->handlebottom,
925                     theme_config.grip_width + self->bwidth + sidebwidth,
926                     self->size.top + self->client_area.height
927                             + self->size.bottom - self->bwidth, self->width
928                             - (theme_config.grip_width + sidebwidth) * 2,
929                     self->bwidth);
930
931             if (sidebwidth) {
932                 XMoveResizeWindow(obp_display, self->lgripleft, 0,
933                         self->size.top + self->client_area.height
934                                 + self->size.bottom
935                                 - (!self->max_horz ? theme_config.grip_width
936                                         : self->size.bottom - self->cbwidth_b),
937                         self->bwidth,
938                         (!self->max_horz ? theme_config.grip_width
939                                 : self->size.bottom - self->cbwidth_b));
940                 XMoveResizeWindow(obp_display, self->rgripright,
941                         self->size.left + self->client_area.width
942                                 + self->size.right - self->bwidth,
943                         self->size.top + self->client_area.height
944                                 + self->size.bottom
945                                 - (!self->max_horz ? theme_config.grip_width
946                                         : self->size.bottom - self->cbwidth_b),
947                         self->bwidth,
948                         (!self->max_horz ? theme_config.grip_width
949                                 : self->size.bottom - self->cbwidth_b));
950
951                 XMapWindow(obp_display, self->lgripleft);
952                 XMapWindow(obp_display, self->rgripright);
953             }
954             else {
955                 XUnmapWindow(obp_display, self->lgripleft);
956                 XUnmapWindow(obp_display, self->rgripright);
957             }
958
959             XMoveResizeWindow(obp_display, self->lgripbottom, sidebwidth,
960                     self->size.top + self->client_area.height
961                             + self->size.bottom - self->bwidth,
962                     theme_config.grip_width + self->bwidth, self->bwidth);
963             XMoveResizeWindow(obp_display, self->rgripbottom, self->size.left
964                     + self->client_area.width + self->size.right - self->bwidth
965                     - sidebwidth - theme_config.grip_width, self->size.top
966                     + self->client_area.height + self->size.bottom
967                     - self->bwidth, theme_config.grip_width + self->bwidth,
968                     self->bwidth);
969
970             XMapWindow(obp_display, self->handlebottom);
971             XMapWindow(obp_display, self->lgripbottom);
972             XMapWindow(obp_display, self->rgripbottom);
973
974             if (self->decorations & OB_FRAME_DECOR_HANDLE
975                     && theme_config.handle_height > 0) {
976                 XMoveResizeWindow(obp_display, self->handletop,
977                         theme_config.grip_width + self->bwidth + sidebwidth, 
978                         FRAME_HANDLE_Y(self), self->width - (theme_config.grip_width
979                                 + sidebwidth) * 2, self->bwidth);
980                 XMapWindow(obp_display, self->handletop);
981
982                 if (self->decorations & OB_FRAME_DECOR_GRIPS) {
983                     XMoveResizeWindow(obp_display, self->handleleft,
984                             theme_config.grip_width, 0, self->bwidth,
985                             theme_config.handle_height);
986                     XMoveResizeWindow(obp_display, self->handleright,
987                             self->width - theme_config.grip_width
988                                     - self->bwidth, 0, self->bwidth,
989                             theme_config.handle_height);
990
991                     XMoveResizeWindow(obp_display, self->lgriptop, sidebwidth, 
992                     FRAME_HANDLE_Y(self), theme_config.grip_width + self->bwidth,
993                             self->bwidth);
994                     XMoveResizeWindow(obp_display, self->rgriptop,
995                             self->size.left + self->client_area.width
996                                     + self->size.right - self->bwidth
997                                     - sidebwidth - theme_config.grip_width, 
998                             FRAME_HANDLE_Y(self), theme_config.grip_width
999                                     + self->bwidth, self->bwidth);
1000
1001                     XMapWindow(obp_display, self->handleleft);
1002                     XMapWindow(obp_display, self->handleright);
1003                     XMapWindow(obp_display, self->lgriptop);
1004                     XMapWindow(obp_display, self->rgriptop);
1005                 }
1006                 else {
1007                     XUnmapWindow(obp_display, self->handleleft);
1008                     XUnmapWindow(obp_display, self->handleright);
1009                     XUnmapWindow(obp_display, self->lgriptop);
1010                     XUnmapWindow(obp_display, self->rgriptop);
1011                 }
1012             }
1013             else {
1014                 XUnmapWindow(obp_display, self->handleleft);
1015                 XUnmapWindow(obp_display, self->handleright);
1016                 XUnmapWindow(obp_display, self->lgriptop);
1017                 XUnmapWindow(obp_display, self->rgriptop);
1018
1019                 XUnmapWindow(obp_display, self->handletop);
1020             }
1021         }
1022         else {
1023             XUnmapWindow(obp_display, self->handleleft);
1024             XUnmapWindow(obp_display, self->handleright);
1025             XUnmapWindow(obp_display, self->lgriptop);
1026             XUnmapWindow(obp_display, self->rgriptop);
1027
1028             XUnmapWindow(obp_display, self->handletop);
1029
1030             XUnmapWindow(obp_display, self->handlebottom);
1031             XUnmapWindow(obp_display, self->lgripleft);
1032             XUnmapWindow(obp_display, self->rgripright);
1033             XUnmapWindow(obp_display, self->lgripbottom);
1034             XUnmapWindow(obp_display, self->rgripbottom);
1035         }
1036
1037         if (self->decorations & OB_FRAME_DECOR_HANDLE
1038                 && theme_config.handle_height > 0) {
1039             XMoveResizeWindow(obp_display, self->handle, sidebwidth, 
1040             FRAME_HANDLE_Y(self) + self->bwidth, self->width,
1041                     theme_config.handle_height);
1042             XMapWindow(obp_display, self->handle);
1043
1044             if (self->decorations & OB_FRAME_DECOR_GRIPS) {
1045                 XMoveResizeWindow(obp_display, self->lgrip, 0, 0,
1046                         theme_config.grip_width, theme_config.handle_height);
1047                 XMoveResizeWindow(obp_display, self->rgrip, self->width
1048                         - theme_config.grip_width, 0, theme_config.grip_width,
1049                         theme_config.handle_height);
1050
1051                 XMapWindow(obp_display, self->lgrip);
1052                 XMapWindow(obp_display, self->rgrip);
1053             }
1054             else {
1055                 XUnmapWindow(obp_display, self->lgrip);
1056                 XUnmapWindow(obp_display, self->rgrip);
1057             }
1058         }
1059         else {
1060             XUnmapWindow(obp_display, self->lgrip);
1061             XUnmapWindow(obp_display, self->rgrip);
1062
1063             XUnmapWindow(obp_display, self->handle);
1064         }
1065
1066         if (self->bwidth && !self->max_horz && (self->client_area.height
1067                 + self->size.top + self->size.bottom) > theme_config.grip_width
1068                 * 2) {
1069             XMoveResizeWindow(obp_display, self->left, 0, self->bwidth
1070                     + theme_config.grip_width, self->bwidth,
1071                     self->client_area.height + self->size.top
1072                             + self->size.bottom - theme_config.grip_width * 2);
1073
1074             XMapWindow(obp_display, self->left);
1075         }
1076         else
1077             XUnmapWindow(obp_display, self->left);
1078
1079         if (self->bwidth && !self->max_horz && (self->client_area.height
1080                 + self->size.top + self->size.bottom) > theme_config.grip_width
1081                 * 2) {
1082             XMoveResizeWindow(obp_display, self->right, self->client_area.width
1083                     + self->cbwidth_l + self->cbwidth_r + self->bwidth,
1084                     self->bwidth + theme_config.grip_width, self->bwidth,
1085                     self->client_area.height + self->size.top
1086                             + self->size.bottom - theme_config.grip_width * 2);
1087
1088             XMapWindow(obp_display, self->right);
1089         }
1090         else
1091             XUnmapWindow(obp_display, self->right);
1092
1093         XMoveResizeWindow(obp_display, self->backback, self->size.left,
1094                 self->size.top, self->client_area.width,
1095                 self->client_area.height);
1096     }
1097
1098     /* shading can change without being moved or resized */
1099     RECT_SET_SIZE(self->area, self->client_area.width + self->size.left
1100             + self->size.right, (self->shaded ? theme_config.title_height
1101             + self->bwidth * 2 : self->client_area.height + self->size.top
1102             + self->size.bottom));
1103
1104     if ((is_resize) && !is_fake) {
1105         /* find the new coordinates, done after setting the frame.size, for
1106          frame_client_gravity. */
1107         self->area.x = self->client_area.x;
1108         self->area.y = self->client_area.y;
1109         frame_client_gravity(OBDEFAULTFRAME(_self)->client, &self->area.x, &self->area.y);
1110     }
1111
1112     if (!is_fake) {
1113         /* move and resize the top level frame.
1114          shading can change without being moved or resized.
1115          but don't do this during an iconify animation. it will be
1116          reflected afterwards.
1117          */
1118         XMoveResizeWindow(obp_display, self->window, self->area.x,
1119                 self->area.y, self->area.width, self->area.height);
1120
1121         /* when the client has StaticGravity, it likes to move around.
1122          also this correctly positions the client when it maps.
1123          this also needs to be run when the frame's decorations sizes change!
1124          */
1125         if (!is_resize)
1126             XMoveResizeWindow(obp_display, self->client->w_client,
1127                     self->size.left, self->size.top, self->client_area.width,
1128                     self->client_area.height);
1129
1130         if (is_resize) {
1131             self->need_render = TRUE;
1132             frame_update_skin(self);
1133             frame_adjust_shape(self);
1134         }
1135
1136         if (!STRUT_EQUAL(self->size, oldsize)) {
1137             gulong vals[4];
1138             vals[0] = self->size.left;
1139             vals[1] = self->size.right;
1140             vals[2] = self->size.top;
1141             vals[3] = self->size.bottom;
1142             OBT_PROP_SETA32(self->client->w_client, NET_FRAME_EXTENTS,
1143                     CARDINAL, vals, 4);
1144             OBT_PROP_SETA32(self->client->w_client, KDE_NET_WM_FRAME_STRUT,
1145                     CARDINAL, vals, 4);
1146         }
1147
1148         /* if this occurs while we are focus cycling, the indicator needs to
1149          match the changes */
1150         if (plugin.focus_cycle_target == self->client)
1151             focus_cycle_draw_indicator(self->client);
1152     }
1153     if (is_resize && (self->decorations & OB_FRAME_DECOR_TITLEBAR))
1154         XResizeWindow(obp_display, self->label, self->label_width,
1155                 theme_config.label_height);
1156 }
1157
1158 void frame_set_hover_flag(gpointer self, ObFrameButton button)
1159 {
1160     if (OBDEFAULTFRAME(self)->hover_flag != button) {
1161         OBDEFAULTFRAME(self)->hover_flag = button;
1162         frame_update_skin(self);
1163     }
1164 }
1165
1166 void frame_set_press_flag(gpointer self, ObFrameButton button)
1167 {
1168     if (OBDEFAULTFRAME(self)->press_flag != button) {
1169         OBDEFAULTFRAME(self)->press_flag = button;
1170         frame_update_skin(self);
1171     }
1172 }
1173
1174 Window frame_get_window(gpointer self)
1175 {
1176     return OBDEFAULTFRAME(self)->window;
1177 }
1178
1179 void frame_get_size(gpointer self, Strut * s)
1180 {
1181     memcpy(s, &(OBDEFAULTFRAME(self)->size), sizeof(Strut));
1182 }
1183
1184 gint frame_get_decorations(gpointer self)
1185 {
1186     return OBDEFAULTFRAME(self)->decorations;
1187 }
1188
1189 void frame_update_title(gpointer self, const gchar * src)
1190 {
1191     g_free(OBDEFAULTFRAME(self)->stitle);
1192     OBDEFAULTFRAME(self)->stitle = g_strdup(src);
1193 }
1194
1195 gboolean frame_is_visible(gpointer self)
1196 {
1197     return OBDEFAULTFRAME(self)->visible;
1198 }
1199
1200 gboolean frame_is_max_horz(gpointer self)
1201 {
1202     return OBDEFAULTFRAME(self)->max_horz;
1203 }
1204
1205 gboolean frame_is_max_vert(gpointer self)
1206 {
1207     return OBDEFAULTFRAME(self)->max_vert;
1208 }
1209
1210 void frame_adjust_cursors(gpointer _self)
1211 {
1212     ObDefaultFrame * self = (ObDefaultFrame *) _self;
1213     if ((self->functions & OB_CLIENT_FUNC_RESIZE) != (self->functions
1214             & OB_CLIENT_FUNC_RESIZE) || self->max_horz != self->max_horz
1215             || self->max_vert != self->max_vert || self->shaded != self->shaded) {
1216         gboolean r = (self->functions & OB_CLIENT_FUNC_RESIZE)
1217                 && !(self->max_horz && self->max_vert);
1218         gboolean topbot = !self->max_vert;
1219         gboolean sh = self->shaded;
1220         XSetWindowAttributes a;
1221
1222         /* these ones turn off when max vert, and some when shaded */
1223         a.cursor = ob_cursor(r && topbot && !sh ? OB_CURSOR_NORTH
1224                 : OB_CURSOR_NONE);
1225         XChangeWindowAttributes(obp_display, self->topresize, CWCursor, &a);
1226         XChangeWindowAttributes(obp_display, self->titletop, CWCursor, &a);
1227         a.cursor = ob_cursor(r && topbot ? OB_CURSOR_SOUTH : OB_CURSOR_NONE);
1228         XChangeWindowAttributes(obp_display, self->handle, CWCursor, &a);
1229         XChangeWindowAttributes(obp_display, self->handletop, CWCursor, &a);
1230         XChangeWindowAttributes(obp_display, self->handlebottom, CWCursor, &a);
1231         XChangeWindowAttributes(obp_display, self->innerbottom, CWCursor, &a);
1232
1233         /* these ones change when shaded */
1234         a.cursor = ob_cursor(r ? (sh ? OB_CURSOR_WEST : OB_CURSOR_NORTHWEST)
1235                 : OB_CURSOR_NONE);
1236         XChangeWindowAttributes(obp_display, self->titleleft, CWCursor, &a);
1237         XChangeWindowAttributes(obp_display, self->tltresize, CWCursor, &a);
1238         XChangeWindowAttributes(obp_display, self->tllresize, CWCursor, &a);
1239         XChangeWindowAttributes(obp_display, self->titletopleft, CWCursor, &a);
1240         a.cursor = ob_cursor(r ? (sh ? OB_CURSOR_EAST : OB_CURSOR_NORTHEAST)
1241                 : OB_CURSOR_NONE);
1242         XChangeWindowAttributes(obp_display, self->titleright, CWCursor, &a);
1243         XChangeWindowAttributes(obp_display, self->trtresize, CWCursor, &a);
1244         XChangeWindowAttributes(obp_display, self->trrresize, CWCursor, &a);
1245         XChangeWindowAttributes(obp_display, self->titletopright, CWCursor, &a);
1246
1247         /* these ones are pretty static */
1248         a.cursor = ob_cursor(r ? OB_CURSOR_WEST : OB_CURSOR_NONE);
1249         XChangeWindowAttributes(obp_display, self->left, CWCursor, &a);
1250         XChangeWindowAttributes(obp_display, self->innerleft, CWCursor, &a);
1251         a.cursor = ob_cursor(r ? OB_CURSOR_EAST : OB_CURSOR_NONE);
1252         XChangeWindowAttributes(obp_display, self->right, CWCursor, &a);
1253         XChangeWindowAttributes(obp_display, self->innerright, CWCursor, &a);
1254         a.cursor = ob_cursor(r ? OB_CURSOR_SOUTHWEST : OB_CURSOR_NONE);
1255         XChangeWindowAttributes(obp_display, self->lgrip, CWCursor, &a);
1256         XChangeWindowAttributes(obp_display, self->handleleft, CWCursor, &a);
1257         XChangeWindowAttributes(obp_display, self->lgripleft, CWCursor, &a);
1258         XChangeWindowAttributes(obp_display, self->lgriptop, CWCursor, &a);
1259         XChangeWindowAttributes(obp_display, self->lgripbottom, CWCursor, &a);
1260         XChangeWindowAttributes(obp_display, self->innerbll, CWCursor, &a);
1261         XChangeWindowAttributes(obp_display, self->innerblb, CWCursor, &a);
1262         a.cursor = ob_cursor(r ? OB_CURSOR_SOUTHEAST : OB_CURSOR_NONE);
1263         XChangeWindowAttributes(obp_display, self->rgrip, CWCursor, &a);
1264         XChangeWindowAttributes(obp_display, self->handleright, CWCursor, &a);
1265         XChangeWindowAttributes(obp_display, self->rgripright, CWCursor, &a);
1266         XChangeWindowAttributes(obp_display, self->rgriptop, CWCursor, &a);
1267         XChangeWindowAttributes(obp_display, self->rgripbottom, CWCursor, &a);
1268         XChangeWindowAttributes(obp_display, self->innerbrr, CWCursor, &a);
1269         XChangeWindowAttributes(obp_display, self->innerbrb, CWCursor, &a);
1270     }
1271 }
1272
1273 void frame_adjust_client_area(gpointer _self)
1274 {
1275     ObDefaultFrame * self = (ObDefaultFrame *) _self;
1276     /* adjust the window which is there to prevent flashing on unmap */
1277     XMoveResizeWindow(obp_display, self->backfront, 0, 0,
1278             self->client_area.width, self->client_area.height);
1279 }
1280
1281 void frame_adjust_state(gpointer _self)
1282 {
1283     ObDefaultFrame * self = (ObDefaultFrame *) _self;
1284     self->need_render = TRUE;
1285     frame_update_skin(self);
1286 }
1287
1288 void frame_adjust_focus(gpointer _self, gboolean hilite)
1289 {
1290     ObDefaultFrame * self = (ObDefaultFrame *) _self;
1291     self->focused = hilite;
1292     self->need_render = TRUE;
1293     frame_update_skin(self);
1294     XFlush(obp_display);
1295 }
1296
1297 void frame_adjust_title(gpointer _self)
1298 {
1299     ObDefaultFrame * self = (ObDefaultFrame *) _self;
1300     self->need_render = TRUE;
1301     frame_update_skin(self);
1302 }
1303
1304 void frame_adjust_icon(gpointer _self)
1305 {
1306     ObDefaultFrame * self = (ObDefaultFrame *) _self;
1307     self->need_render = TRUE;
1308     frame_update_skin(self);
1309 }
1310
1311 /* is there anything present between us and the label? */
1312 static gboolean is_button_present(ObDefaultFrame *_self, const gchar *lc,
1313         gint dir)
1314 {
1315     ObDefaultFrame * self = (ObDefaultFrame *) _self;
1316     for (; *lc != '\0' && lc >= plugin.config_title_layout; lc += dir) {
1317         if (*lc == ' ')
1318             continue; /* it was invalid */
1319         if (*lc == 'N' && self->decorations & OB_FRAME_DECOR_ICON)
1320             return TRUE;
1321         if (*lc == 'D' && self->decorations & OB_FRAME_DECOR_ALLDESKTOPS)
1322             return TRUE;
1323         if (*lc == 'S' && self->decorations & OB_FRAME_DECOR_SHADE)
1324             return TRUE;
1325         if (*lc == 'I' && self->decorations & OB_FRAME_DECOR_ICONIFY)
1326             return TRUE;
1327         if (*lc == 'M' && self->decorations & OB_FRAME_DECOR_MAXIMIZE)
1328             return TRUE;
1329         if (*lc == 'C' && self->decorations & OB_FRAME_DECOR_CLOSE)
1330             return TRUE;
1331         if (*lc == 'L')
1332             return FALSE;
1333     }
1334     return FALSE;
1335 }
1336
1337 void flash_done(gpointer data)
1338 {
1339     ObDefaultFrame *self = data;
1340
1341     if (self->focused != self->flash_on)
1342         frame_adjust_focus(self, self->focused);
1343 }
1344
1345 gboolean flash_timeout(gpointer data)
1346 {
1347     ObDefaultFrame *self = data;
1348     GTimeVal now;
1349
1350     g_get_current_time(&now);
1351     if (now.tv_sec > self->flash_end.tv_sec
1352             || (now.tv_sec == self->flash_end.tv_sec && now.tv_usec
1353                     >= self->flash_end.tv_usec))
1354         self->flashing = FALSE;
1355
1356     if (!self->flashing)
1357         return FALSE; /* we are done */
1358
1359     self->flash_on = !self->flash_on;
1360     if (!self->focused) {
1361         frame_adjust_focus(self, self->flash_on);
1362         self->focused = FALSE;
1363     }
1364
1365     return TRUE; /* go again */
1366 }
1367
1368 void layout_title(ObDefaultFrame * self)
1369 {
1370     gchar *lc;
1371     gint i;
1372
1373     const gint bwidth = theme_config.button_size + theme_config.paddingx + 1;
1374     /* position of the left most button */
1375     const gint left = theme_config.paddingx + 1;
1376     /* position of the right most button */
1377     const gint right = self->width;
1378
1379     /* turn them all off */
1380     self->icon_on = self->desk_on = self->shade_on = self->iconify_on
1381             = self->max_on = self->close_on = self->label_on = FALSE;
1382     self->label_width = self->width - (theme_config.paddingx + 1) * 2;
1383     self->leftmost = self->rightmost = OB_FRAME_CONTEXT_NONE;
1384
1385     /* figure out what's being show, find each element's position, and the
1386      width of the label
1387
1388      do the ones before the label, then after the label,
1389      i will be +1 the first time through when working to the left,
1390      and -1 the second time through when working to the right */
1391     for (i = 1; i >= -1; i-=2) {
1392         gint x;
1393         ObFrameContext *firstcon;
1394
1395         if (i > 0) {
1396             x = left;
1397             lc = plugin.config_title_layout;
1398             firstcon = &self->leftmost;
1399         }
1400         else {
1401             x = right;
1402             lc = plugin.config_title_layout
1403                     + strlen(plugin.config_title_layout)-1;
1404             firstcon = &self->rightmost;
1405         }
1406
1407         /* stop at the end of the string (or the label, which calls break) */
1408         for (; *lc != '\0' && lc >= plugin.config_title_layout; lc+=i) {
1409             if (*lc == 'L') {
1410                 if (i > 0) {
1411                     self->label_on = TRUE;
1412                     self->label_x = x;
1413                 }
1414                 break; /* break the for loop, do other side of label */
1415             }
1416             else if (*lc == 'N') {
1417                 if (firstcon)
1418                     *firstcon = OB_FRAME_CONTEXT_ICON;
1419                 if ((self->icon_on = is_button_present(self, lc, i))) {
1420                     /* icon is bigger than buttons */
1421                     self->label_width -= bwidth + 2;
1422                     if (i > 0)
1423                         self->icon_x = x;
1424                     x += i * (bwidth + 2);
1425                     if (i < 0)
1426                         self->icon_x = x;
1427                 }
1428             }
1429             else if (*lc == 'D') {
1430                 if (firstcon)
1431                     *firstcon = OB_FRAME_CONTEXT_ALLDESKTOPS;
1432                 if ((self->desk_on = is_button_present(self, lc, i))) {
1433                     self->label_width -= bwidth;
1434                     if (i > 0)
1435                         self->desk_x = x;
1436                     x += i * bwidth;
1437                     if (i < 0)
1438                         self->desk_x = x;
1439                 }
1440             }
1441             else if (*lc == 'S') {
1442                 if (firstcon)
1443                     *firstcon = OB_FRAME_CONTEXT_SHADE;
1444                 if ((self->shade_on = is_button_present(self, lc, i))) {
1445                     self->label_width -= bwidth;
1446                     if (i > 0)
1447                         self->shade_x = x;
1448                     x += i * bwidth;
1449                     if (i < 0)
1450                         self->shade_x = x;
1451                 }
1452             }
1453             else if (*lc == 'I') {
1454                 if (firstcon)
1455                     *firstcon = OB_FRAME_CONTEXT_ICONIFY;
1456                 if ((self->iconify_on = is_button_present(self, lc, i))) {
1457                     self->label_width -= bwidth;
1458                     if (i > 0)
1459                         self->iconify_x = x;
1460                     x += i * bwidth;
1461                     if (i < 0)
1462                         self->iconify_x = x;
1463                 }
1464             }
1465             else if (*lc == 'M') {
1466                 if (firstcon)
1467                     *firstcon = OB_FRAME_CONTEXT_MAXIMIZE;
1468                 if ((self->max_on = is_button_present(self, lc, i))) {
1469                     self->label_width -= bwidth;
1470                     if (i > 0)
1471                         self->max_x = x;
1472                     x += i * bwidth;
1473                     if (i < 0)
1474                         self->max_x = x;
1475                 }
1476             }
1477             else if (*lc == 'C') {
1478                 if (firstcon)
1479                     *firstcon = OB_FRAME_CONTEXT_CLOSE;
1480                 if ((self->close_on = is_button_present(self, lc, i))) {
1481                     self->label_width -= bwidth;
1482                     if (i > 0)
1483                         self->close_x = x;
1484                     x += i * bwidth;
1485                     if (i < 0)
1486                         self->close_x = x;
1487                 }
1488             }
1489             else
1490                 continue; /* don't set firstcon */
1491             firstcon = NULL;
1492         }
1493     }
1494
1495     /* position and map the elements */
1496     if (self->icon_on) {
1497         XMapWindow(obp_display, self->icon);
1498         XMoveWindow(obp_display, self->icon, self->icon_x,
1499                 theme_config.paddingy);
1500     }
1501     else
1502         XUnmapWindow(obp_display, self->icon);
1503
1504     if (self->desk_on) {
1505         XMapWindow(obp_display, self->desk);
1506         XMoveWindow(obp_display, self->desk, self->desk_x,
1507                 theme_config.paddingy + 1);
1508     }
1509     else
1510         XUnmapWindow(obp_display, self->desk);
1511
1512     if (self->shade_on) {
1513         XMapWindow(obp_display, self->shade);
1514         XMoveWindow(obp_display, self->shade, self->shade_x,
1515                 theme_config.paddingy + 1);
1516     }
1517     else
1518         XUnmapWindow(obp_display, self->shade);
1519
1520     if (self->iconify_on) {
1521         XMapWindow(obp_display, self->iconify);
1522         XMoveWindow(obp_display, self->iconify, self->iconify_x,
1523                 theme_config.paddingy + 1);
1524     }
1525     else
1526         XUnmapWindow(obp_display, self->iconify);
1527
1528     if (self->max_on) {
1529         XMapWindow(obp_display, self->max);
1530         XMoveWindow(obp_display, self->max, self->max_x, theme_config.paddingy
1531                 + 1);
1532     }
1533     else
1534         XUnmapWindow(obp_display, self->max);
1535
1536     if (self->close_on) {
1537         XMapWindow(obp_display, self->close);
1538         XMoveWindow(obp_display, self->close, self->close_x,
1539                 theme_config.paddingy + 1);
1540     }
1541     else
1542         XUnmapWindow(obp_display, self->close);
1543
1544     if (self->label_on) {
1545         self->label_width = MAX(1, self->label_width); /* no lower than 1 */
1546         XMapWindow(obp_display, self->label);
1547         XMoveWindow(obp_display, self->label, self->label_x,
1548                 theme_config.paddingy);
1549     }
1550     else
1551         XUnmapWindow(obp_display, self->label);
1552 }
1553
1554 void trigger_none(gpointer self)
1555 {
1556 }
1557 void trigger_iconify(gpointer self)
1558 {
1559 }
1560 void trigger_uniconnity(gpointer self)
1561 {
1562 }
1563 void trigger_iconify_toggle(gpointer self)
1564 {
1565 }
1566 void trigger_shade(gpointer self)
1567 {
1568 }
1569 void trigger_unshade(gpointer self)
1570 {
1571 }
1572 void trigger_shade_toggle(gpointer self)
1573 {
1574 }
1575 void trigger_max(gpointer self)
1576 {
1577 }
1578 void trigger_unmax(gpointer self)
1579 {
1580 }
1581 void trigger_max_troggle(gpointer self)
1582 {
1583 }
1584 void trigger_max_vert(gpointer self)
1585 {
1586     OBDEFAULTFRAME(self)->max_vert = TRUE;
1587 }
1588 void trigger_unmax_vert(gpointer self)
1589 {
1590     OBDEFAULTFRAME(self)->max_vert = FALSE;
1591 }
1592 void trigger_max_toggle(gpointer self)
1593 {
1594 }
1595 void trigger_max_horz(gpointer self)
1596 {
1597     OBDEFAULTFRAME(self)->max_horz = TRUE;
1598 }
1599 void trigger_unmax_horz(gpointer self)
1600 {
1601     OBDEFAULTFRAME(self)->max_horz = FALSE;
1602 }
1603 void trigger_max_horz_toggle(gpointer self)
1604 {
1605 }
1606 void trigger_plugin1(gpointer self)
1607 {
1608 }
1609 void trigger_plugin2(gpointer self)
1610 {
1611 }
1612 void trigger_plugin3(gpointer self)
1613 {
1614 }
1615 void trigger_plugin4(gpointer self)
1616 {
1617 }
1618 void trigger_plugin5(gpointer self)
1619 {
1620 }
1621 void trigger_plugin6(gpointer self)
1622 {
1623 }
1624 void trigger_plugin7(gpointer self)
1625 {
1626 }
1627 void trigger_plugin8(gpointer self)
1628 {
1629 }
1630 void trigger_plugin9(gpointer self)
1631 {
1632 }
1633
1634 void frame_trigger(gpointer self, ObFrameTrigger trigger_name)
1635 {
1636
1637     static void (*trigger_func[64])(gpointer) = { trigger_none,
1638             trigger_iconify, trigger_uniconnity, trigger_iconify_toggle,
1639                     trigger_shade, trigger_unshade, trigger_shade_toggle,
1640                     trigger_max, trigger_unmax, trigger_max_troggle,
1641                     trigger_max_vert, trigger_unmax_vert, trigger_max_toggle,
1642                     trigger_max_horz, trigger_unmax_horz,
1643                     trigger_max_horz_toggle, trigger_plugin1, trigger_plugin2,
1644                     trigger_plugin3, trigger_plugin4, trigger_plugin5,
1645                     trigger_plugin6, trigger_plugin7, trigger_plugin8,
1646                     trigger_plugin9, NULL, 
1647 };
1648
1649 void (*call_trigger_func)(gpointer) = trigger_func[trigger_name];
1650 if(!call_trigger_func)
1651 {
1652     call_trigger_func (self);
1653 }
1654 }
1655
1656 ObFrameEngine plugin = {
1657         0, /* gpointer handler */
1658         "libdefault.la", /* gchar * filename */
1659         "Default", /* gchar * name */
1660         init, //gint (*init) (Display * display, gint screen);
1661         0, /* */
1662         frame_new, //gpointer (*frame_new) (struct _ObClient *c);
1663         frame_free, //void (*frame_free) (gpointer self);
1664         frame_adjust_theme, //void (*frame_adjust_theme) (gpointer self);
1665         frame_adjust_shape, //void (*frame_adjust_shape) (gpointer self);
1666         frame_grab, //void (*frame_adjust_area) (gpointer self, gboolean moved, gboolean resized, gboolean fake);
1667         frame_ungrab, /* */
1668         frame_context, //void (*frame_adjust_state) (gpointer self);
1669         frame_set_is_visible, /* */
1670         frame_set_is_focus, /* */
1671         frame_set_is_max_vert, /* */
1672         frame_set_is_max_horz, /* */
1673         frame_set_is_shaded, /* */
1674         frame_flash_start, /* */
1675         frame_flash_stop, /* */
1676         frame_set_decorations, /* */
1677         frame_update_title, /* */
1678         /* This give the window area */
1679         frame_get_window_area, /* */
1680         frame_set_client_area, /* */
1681         /* Draw the frame */
1682         frame_update_layout, /* */
1683         frame_update_skin, /* */
1684         frame_set_hover_flag, /* */
1685         frame_set_press_flag, /* */
1686         frame_get_size, /* */
1687         frame_get_decorations, /* */
1688         frame_is_visible, /* */
1689         frame_is_max_horz, /* */
1690         frame_is_max_vert, /* */
1691         frame_trigger, /* */
1692         load_theme_config, /* */
1693         /* This fields are fill by openbox. */
1694         0, /*gboolean config_theme_keepborder; */
1695         0, /*struct _ObClient *focus_cycle_target; */
1696         0, /*gchar *config_title_layout; */
1697         FALSE, /*gboolean moveresize_in_progress;*/
1698         0, /*struct _ObMainLoop *ob_main_loop;*/
1699 };
1700
1701 ObFrameEngine * get_info()
1702 {
1703     return &plugin;
1704 }