]> icculus.org git repositories - dana/openbox.git/blob - engines/default/plugin.c
Fix bug that openbox don't draw title on new 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 "openbox/client.h"
21 #include "openbox/openbox.h"
22 #include "obt/prop.h"
23 #include "openbox/grab.h"
24 #include "openbox/config.h"
25 #include "obt/mainloop.h"
26 #include "openbox/focus_cycle.h"
27 #include "openbox/focus_cycle_indicator.h"
28 #include "openbox/moveresize.h"
29 #include "openbox/screen.h"
30 #include "render/theme.h"
31
32 #include "plugin.h"
33 #include "render.h"
34
35 typedef enum
36 {
37     OB_FLAG_MAX = 1 << 0,
38     OB_FLAG_CLOSE = 1 << 1,
39     OB_FLAG_DESK = 1 << 2,
40     OB_FLAG_SHADE = 1 << 3,
41     OB_FLAG_ICONIFY = 1 << 4
42 } ObFrameFlags;
43
44 #define FRAME_EVENTMASK (EnterWindowMask | LeaveWindowMask | \
45                          ButtonPressMask | ButtonReleaseMask | \
46                          SubstructureRedirectMask | FocusChangeMask)
47 #define ELEMENT_EVENTMASK (ButtonPressMask | ButtonReleaseMask | \
48                            ButtonMotionMask | PointerMotionMask | \
49                            EnterWindowMask | LeaveWindowMask)
50
51 #define FRAME_ANIMATE_ICONIFY_TIME 150000 /* .15 seconds */
52 #define FRAME_ANIMATE_ICONIFY_STEP_TIME (G_USEC_PER_SEC / 60) /* 60 Hz */
53
54 #define FRAME_HANDLE_Y(f) (f->size.top + f->client_area.height + f->cbwidth_b)
55
56 Window createWindow(Window parent, Visual *visual, gulong mask,
57         XSetWindowAttributes *attrib)
58 {
59     return XCreateWindow(plugin.ob_display, parent, 0, 0, 1, 1, 0, (visual ? 32
60             : RrDepth(plugin.ob_rr_inst)), InputOutput, (visual ? visual
61             : RrVisual(plugin.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(plugin.ob_rr_inst) == 32)
73         return NULL;
74
75     ret = XGetWindowAttributes(plugin.ob_display, c->window, &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     plugin.ob_display = display;
88     plugin.ob_screen = screen;
89 }
90
91 gpointer frame_new(struct _ObClient * client)
92 {
93     XSetWindowAttributes attrib;
94     gulong mask;
95     ObDefaultFrame *self;
96     Visual *visual;
97
98     self = g_new0(ObDefaultFrame, 1);
99     self->client = client;
100
101     visual = check_32bit_client(client);
102
103     /* create the non-visible decor windows */
104
105     mask = 0;
106     if (visual) {
107         /* client has a 32-bit visual */
108         mask |= CWColormap | CWBackPixel | CWBorderPixel;
109         /* create a colormap with the visual */
110         OBDEFAULTFRAME(self)->colormap = attrib.colormap = XCreateColormap(
111                 plugin.ob_display, RootWindow(plugin.ob_display,
112                         plugin.ob_screen), visual, AllocNone);
113         attrib.background_pixel = BlackPixel(plugin.ob_display,
114                 plugin.ob_screen);
115         attrib.border_pixel = BlackPixel(plugin.ob_display, plugin.ob_screen);
116     }
117     self->window = createWindow(
118             RootWindow(plugin.ob_display, plugin.ob_screen), visual, mask,
119             &attrib);
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(plugin.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(plugin.ob_display, self->label);
191     XMapWindow(plugin.ob_display, self->backback);
192     XMapWindow(plugin.ob_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(plugin.ob_display, self->max, theme_config.button_size,
207             theme_config.button_size);
208     XResizeWindow(plugin.ob_display, self->iconify, theme_config.button_size,
209             theme_config.button_size);
210     XResizeWindow(plugin.ob_display, self->icon, theme_config.button_size + 2,
211             theme_config.button_size + 2);
212     XResizeWindow(plugin.ob_display, self->close, theme_config.button_size,
213             theme_config.button_size);
214     XResizeWindow(plugin.ob_display, self->desk, theme_config.button_size,
215             theme_config.button_size);
216     XResizeWindow(plugin.ob_display, self->shade, theme_config.button_size,
217             theme_config.button_size);
218     XResizeWindow(plugin.ob_display, self->tltresize, theme_config.grip_width,
219             theme_config.paddingy + 1);
220     XResizeWindow(plugin.ob_display, self->trtresize, theme_config.grip_width,
221             theme_config.paddingy + 1);
222     XResizeWindow(plugin.ob_display, self->tllresize,
223             theme_config.paddingx + 1, theme_config.title_height);
224     XResizeWindow(plugin.ob_display, self->trrresize,
225             theme_config.paddingx + 1, 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(plugin.ob_display, OBDEFAULTFRAME(self)->window);
254     if (OBDEFAULTFRAME(self)->colormap)
255         XFreeColormap(plugin.ob_display, OBDEFAULTFRAME(self)->colormap);
256     
257     g_free(OBDEFAULTFRAME(self)->stitle);
258     g_free(self);
259 }
260
261 void frame_show(gpointer _self)
262 {
263     ObDefaultFrame * self = (ObDefaultFrame *) _self;
264     if (!self->visible) {
265         self->visible = TRUE;
266         frame_update_skin(self);
267         /* Grab the server to make sure that the frame window is mapped before
268          the client gets its MapNotify, i.e. to make sure the client is
269          _visible_ when it gets MapNotify. */
270         grab_server(TRUE);
271         XMapWindow(plugin.ob_display, self->client->window);
272         XMapWindow(plugin.ob_display, self->window);
273         grab_server(FALSE);
274     }
275 }
276
277 gint frame_hide(gpointer self)
278 {
279     if (OBDEFAULTFRAME(self)->visible) {
280         OBDEFAULTFRAME(self)->visible = FALSE;
281         if (!frame_iconify_animating(self))
282             XUnmapWindow(plugin.ob_display, OBDEFAULTFRAME(self)->window);
283         /* we unmap the client itself so that we can get MapRequest
284          events, and because the ICCCM tells us to! */
285         XUnmapWindow(plugin.ob_display, OBDEFAULTFRAME(self)->client->window);
286         return 1;
287     }
288     else {
289         return 0;
290     }
291 }
292
293 void frame_adjust_theme(gpointer self)
294 {
295     free_theme_statics(self);
296     set_theme_statics(self);
297 }
298
299 void frame_adjust_shape(gpointer _self)
300 {
301 #ifdef SHAPE
302     ObDefaultFrame * self = (ObDefaultFrame *) _self;
303     gint num;
304     XRectangle xrect[2];
305
306     if (!self->client->shaped)
307     {
308         /* clear the shape on the frame window */
309         XShapeCombineMask(plugin.ob_display, self->window, ShapeBounding,
310                 self->size.left,
311                 self->size.top,
312                 None, ShapeSet);
313     }
314     else
315     {
316         /* make the frame's shape match the clients */
317         XShapeCombineShape(plugin.ob_display, self->window, ShapeBounding,
318                 self->size.left,
319                 self->size.top,
320                 self->client->window,
321                 ShapeBounding, ShapeSet);
322
323         num = 0;
324         if (self->decorations & OB_FRAME_DECOR_TITLEBAR)
325         {
326             xrect[0].x = 0;
327             xrect[0].y = 0;
328             xrect[0].width = self->area.width;
329             xrect[0].height = self->size.top;
330             ++num;
331         }
332
333         if (self->decorations & OB_FRAME_DECOR_HANDLE &&
334                 theme_config.handle_height> 0)
335         {
336             xrect[1].x = 0;
337             xrect[1].y = FRAME_HANDLE_Y(self);
338             xrect[1].width = self->area.width;
339             xrect[1].height = theme_config.handle_height +
340             self->bwidth * 2;
341             ++num;
342         }
343
344         XShapeCombineRectangles(plugin.ob_display, self->window,
345                 ShapeBounding, 0, 0, xrect, num,
346                 ShapeUnion, Unsorted);
347     }
348 #endif
349 }
350
351 void frame_grab(gpointer _self, GHashTable * window_map)
352 {
353     ObDefaultFrame * self = (ObDefaultFrame *) _self;
354     /* DO NOT map the client window here. we used to do that, but it is bogus.
355      we need to set up the client's dimensions and everything before we
356      send a mapnotify or we create race conditions.
357      */
358
359     /* reparent the client to the frame */
360     XReparentWindow(plugin.ob_display, self->client->window, self->window, 0, 0);
361
362     /*
363      When reparenting the client window, it is usually not mapped yet, since
364      this occurs from a MapRequest. However, in the case where Openbox is
365      starting up, the window is already mapped, so we'll see an unmap event
366      for it.
367      */
368     if (ob_state() == OB_STATE_STARTING)
369         ++self->client->ignore_unmaps;
370
371     /* select the event mask on the client's parent (to receive config/map
372      req's) the ButtonPress is to catch clicks on the client border */
373     XSelectInput(plugin.ob_display, self->window, FRAME_EVENTMASK);
374
375     /* set all the windows for the frame in the window_map */
376     g_hash_table_insert(window_map, &self->window, self->client);
377     g_hash_table_insert(window_map, &self->backback, self->client);
378     g_hash_table_insert(window_map, &self->backfront, self->client);
379     g_hash_table_insert(window_map, &self->innerleft, self->client);
380     g_hash_table_insert(window_map, &self->innertop, self->client);
381     g_hash_table_insert(window_map, &self->innerright, self->client);
382     g_hash_table_insert(window_map, &self->innerbottom, self->client);
383     g_hash_table_insert(window_map, &self->title, self->client);
384     g_hash_table_insert(window_map, &self->label, self->client);
385     g_hash_table_insert(window_map, &self->max, self->client);
386     g_hash_table_insert(window_map, &self->close, self->client);
387     g_hash_table_insert(window_map, &self->desk, self->client);
388     g_hash_table_insert(window_map, &self->shade, self->client);
389     g_hash_table_insert(window_map, &self->icon, self->client);
390     g_hash_table_insert(window_map, &self->iconify, self->client);
391     g_hash_table_insert(window_map, &self->handle, self->client);
392     g_hash_table_insert(window_map, &self->lgrip, self->client);
393     g_hash_table_insert(window_map, &self->rgrip, self->client);
394     g_hash_table_insert(window_map, &self->topresize, self->client);
395     g_hash_table_insert(window_map, &self->tltresize, self->client);
396     g_hash_table_insert(window_map, &self->tllresize, self->client);
397     g_hash_table_insert(window_map, &self->trtresize, self->client);
398     g_hash_table_insert(window_map, &self->trrresize, self->client);
399     g_hash_table_insert(window_map, &self->left, self->client);
400     g_hash_table_insert(window_map, &self->right, self->client);
401     g_hash_table_insert(window_map, &self->titleleft, self->client);
402     g_hash_table_insert(window_map, &self->titletop, self->client);
403     g_hash_table_insert(window_map, &self->titletopleft, self->client);
404     g_hash_table_insert(window_map, &self->titletopright, self->client);
405     g_hash_table_insert(window_map, &self->titleright, self->client);
406     g_hash_table_insert(window_map, &self->titlebottom, self->client);
407     g_hash_table_insert(window_map, &self->handleleft, self->client);
408     g_hash_table_insert(window_map, &self->handletop, self->client);
409     g_hash_table_insert(window_map, &self->handleright, self->client);
410     g_hash_table_insert(window_map, &self->handlebottom, self->client);
411     g_hash_table_insert(window_map, &self->lgripleft, self->client);
412     g_hash_table_insert(window_map, &self->lgriptop, self->client);
413     g_hash_table_insert(window_map, &self->lgripbottom, self->client);
414     g_hash_table_insert(window_map, &self->rgripright, self->client);
415     g_hash_table_insert(window_map, &self->rgriptop, self->client);
416     g_hash_table_insert(window_map, &self->rgripbottom, self->client);
417 }
418
419 void frame_ungrab(gpointer _self, GHashTable * window_map)
420 {
421     ObDefaultFrame * self = (ObDefaultFrame *) _self;
422     XEvent ev;
423     gboolean reparent = TRUE;
424
425     /* if there was any animation going on, kill it */
426     obt_main_loop_timeout_remove_data(plugin.ob_main_loop,
427             frame_animate_iconify, self, FALSE);
428
429     /* check if the app has already reparented its window away */
430     while (XCheckTypedWindowEvent(plugin.ob_display, self->client->window,
431             ReparentNotify, &ev)) {
432         /* This check makes sure we don't catch our own reparent action to
433          our frame window. This doesn't count as the app reparenting itself
434          away of course.
435
436          Reparent events that are generated by us are just discarded here.
437          They are of no consequence to us anyhow.
438          */
439         if (ev.xreparent.parent != self->window) {
440             reparent = FALSE;
441             XPutBackEvent(plugin.ob_display, &ev);
442             break;
443         }
444     }
445
446     if (reparent) {
447         /* according to the ICCCM - if the client doesn't reparent itself,
448          then we will reparent the window to root for them */
449         XReparentWindow(plugin.ob_display, self->client->window, RootWindow(
450                 plugin.ob_display, plugin.ob_screen), self->client_area.x,
451                 self->client_area.y);
452     }
453
454     /* remove all the windows for the frame from the window_map */
455     g_hash_table_remove(window_map, &self->window);
456     g_hash_table_remove(window_map, &self->backback);
457     g_hash_table_remove(window_map, &self->backfront);
458     g_hash_table_remove(window_map, &self->innerleft);
459     g_hash_table_remove(window_map, &self->innertop);
460     g_hash_table_remove(window_map, &self->innerright);
461     g_hash_table_remove(window_map, &self->innerbottom);
462     g_hash_table_remove(window_map, &self->title);
463     g_hash_table_remove(window_map, &self->label);
464     g_hash_table_remove(window_map, &self->max);
465     g_hash_table_remove(window_map, &self->close);
466     g_hash_table_remove(window_map, &self->desk);
467     g_hash_table_remove(window_map, &self->shade);
468     g_hash_table_remove(window_map, &self->icon);
469     g_hash_table_remove(window_map, &self->iconify);
470     g_hash_table_remove(window_map, &self->handle);
471     g_hash_table_remove(window_map, &self->lgrip);
472     g_hash_table_remove(window_map, &self->rgrip);
473     g_hash_table_remove(window_map, &self->topresize);
474     g_hash_table_remove(window_map, &self->tltresize);
475     g_hash_table_remove(window_map, &self->tllresize);
476     g_hash_table_remove(window_map, &self->trtresize);
477     g_hash_table_remove(window_map, &self->trrresize);
478     g_hash_table_remove(window_map, &self->left);
479     g_hash_table_remove(window_map, &self->right);
480     g_hash_table_remove(window_map, &self->titleleft);
481     g_hash_table_remove(window_map, &self->titletop);
482     g_hash_table_remove(window_map, &self->titletopleft);
483     g_hash_table_remove(window_map, &self->titletopright);
484     g_hash_table_remove(window_map, &self->titleright);
485     g_hash_table_remove(window_map, &self->titlebottom);
486     g_hash_table_remove(window_map, &self->handleleft);
487     g_hash_table_remove(window_map, &self->handletop);
488     g_hash_table_remove(window_map, &self->handleright);
489     g_hash_table_remove(window_map, &self->handlebottom);
490     g_hash_table_remove(window_map, &self->lgripleft);
491     g_hash_table_remove(window_map, &self->lgriptop);
492     g_hash_table_remove(window_map, &self->lgripbottom);
493     g_hash_table_remove(window_map, &self->rgripright);
494     g_hash_table_remove(window_map, &self->rgriptop);
495     g_hash_table_remove(window_map, &self->rgripbottom);
496
497     obt_main_loop_timeout_remove_data(plugin.ob_main_loop, flash_timeout, self,
498             TRUE);
499 }
500
501 ObFrameContext frame_context(gpointer _self, Window win, gint x, gint y)
502 {
503     ObDefaultFrame * self = OBDEFAULTFRAME(_self);
504
505     /* when the user clicks in the corners of the titlebar and the client
506      is fully maximized, then treat it like they clicked in the
507      button that is there */
508     if (self->max_horz && self->max_vert && (win == self->title || win
509             == self->titletop || win == self->titleleft || win
510             == self->titletopleft || win == self->titleright || win
511             == self->titletopright)) {
512         /* get the mouse coords in reference to the whole frame */
513         gint fx = x;
514         gint fy = y;
515
516         /* these windows are down a border width from the top of the frame */
517         if (win == self->title || win == self->titleleft || win
518                 == self->titleright)
519             fy += self->bwidth;
520
521         /* title is a border width in from the edge */
522         if (win == self->title)
523             fx += self->bwidth;
524         /* titletop is a bit to the right */
525         else if (win == self->titletop)
526             fx += theme_config.grip_width + self->bwidth;
527         /* titletopright is way to the right edge */
528         else if (win == self->titletopright)
529             fx += self->area.width - (theme_config.grip_width + self->bwidth);
530         /* titleright is even more way to the right edge */
531         else if (win == self->titleright)
532             fx += self->area.width - self->bwidth;
533
534         /* figure out if we're over the area that should be considered a
535          button */
536         if (fy < self->bwidth + theme_config.paddingy + 1
537                 + theme_config.button_size) {
538             if (fx < (self->bwidth + theme_config.paddingx + 1
539                     + theme_config.button_size)) {
540                 if (self->leftmost != OB_FRAME_CONTEXT_NONE)
541                     return self->leftmost;
542             }
543             else if (fx >= (self->area.width - (self->bwidth
544                     + theme_config.paddingx + 1 + theme_config.button_size))) {
545                 if (self->rightmost != OB_FRAME_CONTEXT_NONE)
546                     return self->rightmost;
547             }
548         }
549
550         /* there is no resizing maximized windows so make them the titlebar
551          context */
552         return OB_FRAME_CONTEXT_TITLEBAR;
553     }
554     else if (self->max_vert
555             && (win == self->titletop || win == self->topresize))
556         /* can't resize vertically when max vert */
557         return OB_FRAME_CONTEXT_TITLEBAR;
558     else if (self->shaded && (win == self->titletop || win == self->topresize))
559         /* can't resize vertically when shaded */
560         return OB_FRAME_CONTEXT_TITLEBAR;
561
562     if (win == self->window)
563         return OB_FRAME_CONTEXT_FRAME;
564     if (win == self->label)
565         return OB_FRAME_CONTEXT_TITLEBAR;
566     if (win == self->handle)
567         return OB_FRAME_CONTEXT_BOTTOM;
568     if (win == self->handletop)
569         return OB_FRAME_CONTEXT_BOTTOM;
570     if (win == self->handlebottom)
571         return OB_FRAME_CONTEXT_BOTTOM;
572     if (win == self->handleleft)
573         return OB_FRAME_CONTEXT_BLCORNER;
574     if (win == self->lgrip)
575         return OB_FRAME_CONTEXT_BLCORNER;
576     if (win == self->lgripleft)
577         return OB_FRAME_CONTEXT_BLCORNER;
578     if (win == self->lgriptop)
579         return OB_FRAME_CONTEXT_BLCORNER;
580     if (win == self->lgripbottom)
581         return OB_FRAME_CONTEXT_BLCORNER;
582     if (win == self->handleright)
583         return OB_FRAME_CONTEXT_BRCORNER;
584     if (win == self->rgrip)
585         return OB_FRAME_CONTEXT_BRCORNER;
586     if (win == self->rgripright)
587         return OB_FRAME_CONTEXT_BLCORNER;
588     if (win == self->rgriptop)
589         return OB_FRAME_CONTEXT_BLCORNER;
590     if (win == self->rgripbottom)
591         return OB_FRAME_CONTEXT_BLCORNER;
592     if (win == self->title)
593         return OB_FRAME_CONTEXT_TITLEBAR;
594     if (win == self->titlebottom)
595         return OB_FRAME_CONTEXT_TITLEBAR;
596     if (win == self->titleleft)
597         return OB_FRAME_CONTEXT_TLCORNER;
598     if (win == self->titletopleft)
599         return OB_FRAME_CONTEXT_TLCORNER;
600     if (win == self->titleright)
601         return OB_FRAME_CONTEXT_TRCORNER;
602     if (win == self->titletopright)
603         return OB_FRAME_CONTEXT_TRCORNER;
604     if (win == self->titletop)
605         return OB_FRAME_CONTEXT_TOP;
606     if (win == self->topresize)
607         return OB_FRAME_CONTEXT_TOP;
608     if (win == self->tltresize)
609         return OB_FRAME_CONTEXT_TLCORNER;
610     if (win == self->tllresize)
611         return OB_FRAME_CONTEXT_TLCORNER;
612     if (win == self->trtresize)
613         return OB_FRAME_CONTEXT_TRCORNER;
614     if (win == self->trrresize)
615         return OB_FRAME_CONTEXT_TRCORNER;
616     if (win == self->left)
617         return OB_FRAME_CONTEXT_LEFT;
618     if (win == self->right)
619         return OB_FRAME_CONTEXT_RIGHT;
620     if (win == self->innertop)
621         return OB_FRAME_CONTEXT_TITLEBAR;
622     if (win == self->innerleft)
623         return OB_FRAME_CONTEXT_LEFT;
624     if (win == self->innerbottom)
625         return OB_FRAME_CONTEXT_BOTTOM;
626     if (win == self->innerright)
627         return OB_FRAME_CONTEXT_RIGHT;
628     if (win == self->max)
629         return OB_FRAME_CONTEXT_MAXIMIZE;
630     if (win == self->iconify)
631         return OB_FRAME_CONTEXT_ICONIFY;
632     if (win == self->close)
633         return OB_FRAME_CONTEXT_CLOSE;
634     if (win == self->icon)
635         return OB_FRAME_CONTEXT_ICON;
636     if (win == self->desk)
637         return OB_FRAME_CONTEXT_ALLDESKTOPS;
638     if (win == self->shade)
639         return OB_FRAME_CONTEXT_SHADE;
640
641     return OB_FRAME_CONTEXT_NONE;
642 }
643
644 void frame_set_is_visible(gpointer self, gboolean b)
645 {
646     OBDEFAULTFRAME(self)->visible = b;
647 }
648
649 void frame_set_is_focus(gpointer self, gboolean b)
650 {
651     OBDEFAULTFRAME(self)->focused = b;
652 }
653
654 void frame_set_is_max_vert(gpointer self, gboolean b)
655 {
656     OBDEFAULTFRAME(self)->max_vert = b;
657 }
658
659 void frame_set_is_max_horz(gpointer self, gboolean b)
660 {
661     OBDEFAULTFRAME(self)->max_horz = b;
662 }
663
664 void frame_set_is_shaded(gpointer self, gboolean b)
665 {
666     OBDEFAULTFRAME(self)->shaded = b;
667 }
668
669 void frame_unfocus(gpointer self)
670 {
671     OBDEFAULTFRAME(self)->focused = FALSE;
672 }
673
674 void frame_flash_start(gpointer _self)
675 {
676     ObDefaultFrame * self = (ObDefaultFrame *) _self;
677     self->flash_on = self->focused;
678
679     if (!self->flashing)
680         obt_main_loop_timeout_add(plugin.ob_main_loop, G_USEC_PER_SEC * 0.6,
681                 flash_timeout, self, g_direct_equal, flash_done);
682     g_get_current_time(&self->flash_end);
683     g_time_val_add(&self->flash_end, G_USEC_PER_SEC * 5);
684
685     self->flashing = TRUE;
686 }
687
688 void frame_flash_stop(gpointer _self)
689 {
690     ObDefaultFrame * self = (ObDefaultFrame *) _self;
691     self->flashing = FALSE;
692 }
693
694 void frame_begin_iconify_animation(gpointer _self, gboolean iconifying)
695 {
696     ObDefaultFrame * self = (ObDefaultFrame *) _self;
697     gulong time;
698     gboolean new_anim = FALSE;
699     gboolean set_end = TRUE;
700     GTimeVal now;
701
702     /* if there is no titlebar, just don't animate for now
703      XXX it would be nice tho.. */
704     if (!(self->decorations & OB_FRAME_DECOR_TITLEBAR))
705         return;
706
707     /* get the current time */
708     g_get_current_time(&now);
709
710     /* get how long until the end */
711     time = FRAME_ANIMATE_ICONIFY_TIME;
712     if (self->iconify_animation_going) {
713         if (!!iconifying != (self->iconify_animation_going > 0)) {
714             /* animation was already going on in the opposite direction */
715             time = time - frame_animate_iconify_time_left(_self, &now);
716         }
717         else
718             /* animation was already going in the same direction */
719             set_end = FALSE;
720     }
721     else
722         new_anim = TRUE;
723     self->iconify_animation_going = iconifying ? 1 : -1;
724
725     /* set the ending time */
726     if (set_end) {
727         self->iconify_animation_end.tv_sec = now.tv_sec;
728         self->iconify_animation_end.tv_usec = now.tv_usec;
729         g_time_val_add(&self->iconify_animation_end, time);
730     }
731
732     if (new_anim) {
733         obt_main_loop_timeout_remove_data(plugin.ob_main_loop,
734                 frame_animate_iconify, self, FALSE);
735         obt_main_loop_timeout_add(plugin.ob_main_loop, 
736         FRAME_ANIMATE_ICONIFY_STEP_TIME, frame_animate_iconify, self,
737                 g_direct_equal, NULL);
738
739         /* do the first step */
740         frame_animate_iconify(self);
741
742         /* show it during the animation even if it is not "visible" */
743         if (!self->visible)
744             XMapWindow(plugin.ob_display, self->window);
745     }
746 }
747
748 void frame_end_iconify_animation(gpointer _self)
749 {
750     ObDefaultFrame * self = (ObDefaultFrame *) _self;
751     /* see if there is an animation going */
752     if (self->iconify_animation_going == 0)
753         return;
754
755     if (!self->visible)
756         XUnmapWindow(plugin.ob_display, self->window);
757     else {
758         /* Send a ConfigureNotify when the animation is done, this fixes
759          KDE's pager showing the window in the wrong place.  since the
760          window is mapped at a different location and is then moved, we
761          need to send the synthetic configurenotify, since apps may have
762          read the position when the client mapped, apparently. */
763         client_reconfigure(self->client, TRUE);
764     }
765
766     /* we're not animating any more ! */
767     self->iconify_animation_going = 0;
768
769     XMoveResizeWindow(plugin.ob_display, self->window, self->area.x,
770             self->area.y, self->area.width, self->area.height);
771     /* we delay re-rendering until after we're done animating */
772     frame_update_skin(self);
773     XFlush(plugin.ob_display);
774 }
775
776 gboolean frame_iconify_animating(gpointer _self)
777 {
778     ObDefaultFrame * self = (ObDefaultFrame *) _self;
779     return self->iconify_animation_going != 0;
780 }
781
782 void frame_set_decorations(gpointer self, ObFrameDecorations d)
783 {
784     OBDEFAULTFRAME(self)->decorations = d;
785 }
786
787 Rect frame_get_window_area(gpointer self)
788 {
789     return OBDEFAULTFRAME(self)->area;
790 }
791 void frame_set_client_area(gpointer self, Rect r)
792 {
793     OBDEFAULTFRAME(self)->client_area = r;
794 }
795
796 void frame_update_layout(gpointer _self, gboolean is_resize, gboolean is_fake)
797 {
798     ObDefaultFrame * self = (ObDefaultFrame *) _self;
799     Strut oldsize;
800
801     oldsize = self->size;
802     self->area = self->client_area;
803
804     /* do this before changing the frame's status like max_horz max_vert */
805     frame_adjust_cursors(self);
806
807     if (self->decorations & OB_FRAME_DECOR_BORDER
808             || (plugin.config_theme_keepborder)) {
809         self->bwidth = theme_config.fbwidth;
810     }
811     else {
812         self->bwidth = 0;
813     }
814
815     if (self->decorations & OB_FRAME_DECOR_BORDER) {
816         self->cbwidth_l = theme_config.cbwidthx;
817         self->cbwidth_r = theme_config.cbwidthx;
818         self->cbwidth_t = theme_config.cbwidthy;
819         self->cbwidth_b = theme_config.cbwidthy;
820     }
821     else {
822         self->cbwidth_l = 0;
823         self->cbwidth_t = 0;
824         self->cbwidth_r = 0;
825         self->cbwidth_b = 0;
826     }
827
828     if (self->max_horz) {
829         self->cbwidth_l = 0;
830         self->cbwidth_r = 0;
831         self->width = self->client_area.width;
832         if (self->max_vert)
833             self->cbwidth_b = 0;
834     }
835     else {
836         self->width = self->client_area.width + self->cbwidth_l
837                 + self->cbwidth_r;
838     }
839
840     /* some elements are sized based of the width, so don't let them have
841      negative values */
842     self->width = MAX(self->width, (theme_config.grip_width + self->bwidth) * 2
843             + 1);
844
845     STRUT_SET(self->size, self->cbwidth_l
846             + (!self->max_horz ? self->bwidth : 0), self->cbwidth_t
847             + self->bwidth, self->cbwidth_r + (!self->max_horz ? self->bwidth
848             : 0), self->cbwidth_b
849             + (!self->max_horz || !self->max_vert ? self->bwidth : 0));
850
851     if (self->decorations & OB_FRAME_DECOR_TITLEBAR)
852         self->size.top += theme_config.title_height + self->bwidth;
853     if (self->decorations & OB_FRAME_DECOR_HANDLE && theme_config.handle_height
854             > 0) {
855         self->size.bottom += theme_config.handle_height + self->bwidth;
856     }
857
858     /* position/size and map/unmap all the windows */
859     if (!is_fake) {
860         gint innercornerheight = theme_config.grip_width - self->size.bottom;
861
862         if (self->cbwidth_l) {
863             XMoveResizeWindow(plugin.ob_display, self->innerleft,
864                     self->size.left - self->cbwidth_l, self->size.top,
865                     self->cbwidth_l, self->client_area.height);
866
867             XMapWindow(plugin.ob_display, self->innerleft);
868         }
869         else
870             XUnmapWindow(plugin.ob_display, self->innerleft);
871
872         if (self->cbwidth_l && innercornerheight > 0) {
873             XMoveResizeWindow(plugin.ob_display, self->innerbll, 0,
874                     self->client_area.height - (theme_config.grip_width
875                             - self->size.bottom), self->cbwidth_l,
876                     theme_config.grip_width - self->size.bottom);
877
878             XMapWindow(plugin.ob_display, self->innerbll);
879         }
880         else
881             XUnmapWindow(plugin.ob_display, self->innerbll);
882
883         if (self->cbwidth_r) {
884             XMoveResizeWindow(plugin.ob_display, self->innerright,
885                     self->size.left + self->client_area.width, self->size.top,
886                     self->cbwidth_r, self->client_area.height);
887
888             XMapWindow(plugin.ob_display, self->innerright);
889         }
890         else
891             XUnmapWindow(plugin.ob_display, self->innerright);
892
893         if (self->cbwidth_r && innercornerheight > 0) {
894             XMoveResizeWindow(plugin.ob_display, self->innerbrr, 0,
895                     self->client_area.height - (theme_config.grip_width
896                             - self->size.bottom), self->cbwidth_r,
897                     theme_config.grip_width - self->size.bottom);
898
899             XMapWindow(plugin.ob_display, self->innerbrr);
900         }
901         else
902             XUnmapWindow(plugin.ob_display, self->innerbrr);
903
904         if (self->cbwidth_t) {
905             XMoveResizeWindow(plugin.ob_display, self->innertop,
906                     self->size.left - self->cbwidth_l, self->size.top
907                             - self->cbwidth_t, self->client_area.width
908                             + self->cbwidth_l + self->cbwidth_r,
909                     self->cbwidth_t);
910
911             XMapWindow(plugin.ob_display, self->innertop);
912         }
913         else
914             XUnmapWindow(plugin.ob_display, self->innertop);
915
916         if (self->cbwidth_b) {
917             XMoveResizeWindow(plugin.ob_display, self->innerbottom,
918                     self->size.left - self->cbwidth_l, self->size.top
919                             + self->client_area.height, self->client_area.width
920                             + self->cbwidth_l + self->cbwidth_r,
921                     self->cbwidth_b);
922
923             XMoveResizeWindow(plugin.ob_display, self->innerblb, 0, 0,
924                     theme_config.grip_width + self->bwidth, self->cbwidth_b);
925             XMoveResizeWindow(plugin.ob_display, self->innerbrb,
926                     self->client_area.width + self->cbwidth_l + self->cbwidth_r
927                             - (theme_config.grip_width + self->bwidth), 0,
928                     theme_config.grip_width + self->bwidth, self->cbwidth_b);
929
930             XMapWindow(plugin.ob_display, self->innerbottom);
931             XMapWindow(plugin.ob_display, self->innerblb);
932             XMapWindow(plugin.ob_display, self->innerbrb);
933         }
934         else {
935             XUnmapWindow(plugin.ob_display, self->innerbottom);
936             XUnmapWindow(plugin.ob_display, self->innerblb);
937             XUnmapWindow(plugin.ob_display, self->innerbrb);
938         }
939
940         if (self->bwidth) {
941             gint titlesides;
942
943             /* height of titleleft and titleright */
944             titlesides = (!self->max_horz ? theme_config.grip_width : 0);
945
946             XMoveResizeWindow(plugin.ob_display, self->titletop,
947                     theme_config.grip_width + self->bwidth, 0,
948                     /* width + bwidth*2 - bwidth*2 - grips*2 */
949                     self->width - theme_config.grip_width * 2, self->bwidth);
950             XMoveResizeWindow(plugin.ob_display, self->titletopleft, 0, 0,
951                     theme_config.grip_width + self->bwidth, self->bwidth);
952             XMoveResizeWindow(plugin.ob_display, self->titletopright,
953                     self->client_area.width + self->size.left
954                             + self->size.right - theme_config.grip_width
955                             - self->bwidth, 0, theme_config.grip_width
956                             + self->bwidth, self->bwidth);
957
958             if (titlesides > 0) {
959                 XMoveResizeWindow(plugin.ob_display, self->titleleft, 0,
960                         self->bwidth, self->bwidth, titlesides);
961                 XMoveResizeWindow(plugin.ob_display, self->titleright,
962                         self->client_area.width + self->size.left
963                                 + self->size.right - self->bwidth,
964                         self->bwidth, self->bwidth, titlesides);
965
966                 XMapWindow(plugin.ob_display, self->titleleft);
967                 XMapWindow(plugin.ob_display, self->titleright);
968             }
969             else {
970                 XUnmapWindow(plugin.ob_display, self->titleleft);
971                 XUnmapWindow(plugin.ob_display, self->titleright);
972             }
973
974             XMapWindow(plugin.ob_display, self->titletop);
975             XMapWindow(plugin.ob_display, self->titletopleft);
976             XMapWindow(plugin.ob_display, self->titletopright);
977
978             if (self->decorations & OB_FRAME_DECOR_TITLEBAR) {
979                 XMoveResizeWindow(plugin.ob_display, self->titlebottom,
980                         (self->max_horz ? 0 : self->bwidth),
981                         theme_config.title_height + self->bwidth, self->width,
982                         self->bwidth);
983
984                 XMapWindow(plugin.ob_display, self->titlebottom);
985             }
986             else
987                 XUnmapWindow(plugin.ob_display, self->titlebottom);
988         }
989         else {
990             XUnmapWindow(plugin.ob_display, self->titlebottom);
991
992             XUnmapWindow(plugin.ob_display, self->titletop);
993             XUnmapWindow(plugin.ob_display, self->titletopleft);
994             XUnmapWindow(plugin.ob_display, self->titletopright);
995             XUnmapWindow(plugin.ob_display, self->titleleft);
996             XUnmapWindow(plugin.ob_display, self->titleright);
997         }
998
999         if (self->decorations & OB_FRAME_DECOR_TITLEBAR) {
1000             XMoveResizeWindow(plugin.ob_display, self->title,
1001                     (self->max_horz ? 0 : self->bwidth), self->bwidth,
1002                     self->width, theme_config.title_height);
1003
1004             XMapWindow(plugin.ob_display, self->title);
1005
1006             if (self->decorations & OB_FRAME_DECOR_GRIPS) {
1007                 XMoveResizeWindow(plugin.ob_display, self->topresize,
1008                         theme_config.grip_width, 0, self->width
1009                                 - theme_config.grip_width *2,
1010                         theme_config.paddingy + 1);
1011
1012                 XMoveWindow(plugin.ob_display, self->tltresize, 0, 0);
1013                 XMoveWindow(plugin.ob_display, self->tllresize, 0, 0);
1014                 XMoveWindow(plugin.ob_display, self->trtresize, self->width
1015                         - theme_config.grip_width, 0);
1016                 XMoveWindow(plugin.ob_display, self->trrresize, self->width
1017                         - theme_config.paddingx - 1, 0);
1018
1019                 XMapWindow(plugin.ob_display, self->topresize);
1020                 XMapWindow(plugin.ob_display, self->tltresize);
1021                 XMapWindow(plugin.ob_display, self->tllresize);
1022                 XMapWindow(plugin.ob_display, self->trtresize);
1023                 XMapWindow(plugin.ob_display, self->trrresize);
1024             }
1025             else {
1026                 XUnmapWindow(plugin.ob_display, self->topresize);
1027                 XUnmapWindow(plugin.ob_display, self->tltresize);
1028                 XUnmapWindow(plugin.ob_display, self->tllresize);
1029                 XUnmapWindow(plugin.ob_display, self->trtresize);
1030                 XUnmapWindow(plugin.ob_display, self->trrresize);
1031             }
1032         }
1033         else
1034             XUnmapWindow(plugin.ob_display, self->title);
1035     }
1036
1037     if ((self->decorations & OB_FRAME_DECOR_TITLEBAR))
1038         /* layout the title bar elements */
1039         layout_title(self);
1040
1041     if (!is_fake) {
1042         gint sidebwidth = self->max_horz ? 0 : self->bwidth;
1043
1044         if (self->bwidth && self->size.bottom) {
1045             XMoveResizeWindow(plugin.ob_display, self->handlebottom,
1046                     theme_config.grip_width + self->bwidth + sidebwidth,
1047                     self->size.top + self->client_area.height
1048                             + self->size.bottom - self->bwidth, self->width
1049                             - (theme_config.grip_width + sidebwidth) * 2,
1050                     self->bwidth);
1051
1052             if (sidebwidth) {
1053                 XMoveResizeWindow(plugin.ob_display, self->lgripleft, 0,
1054                         self->size.top + self->client_area.height
1055                                 + self->size.bottom
1056                                 - (!self->max_horz ? theme_config.grip_width
1057                                         : self->size.bottom - self->cbwidth_b),
1058                         self->bwidth,
1059                         (!self->max_horz ? theme_config.grip_width
1060                                 : self->size.bottom - self->cbwidth_b));
1061                 XMoveResizeWindow(plugin.ob_display, self->rgripright,
1062                         self->size.left + self->client_area.width
1063                                 + self->size.right - self->bwidth,
1064                         self->size.top + self->client_area.height
1065                                 + self->size.bottom
1066                                 - (!self->max_horz ? theme_config.grip_width
1067                                         : self->size.bottom - self->cbwidth_b),
1068                         self->bwidth,
1069                         (!self->max_horz ? theme_config.grip_width
1070                                 : self->size.bottom - self->cbwidth_b));
1071
1072                 XMapWindow(plugin.ob_display, self->lgripleft);
1073                 XMapWindow(plugin.ob_display, self->rgripright);
1074             }
1075             else {
1076                 XUnmapWindow(plugin.ob_display, self->lgripleft);
1077                 XUnmapWindow(plugin.ob_display, self->rgripright);
1078             }
1079
1080             XMoveResizeWindow(plugin.ob_display, self->lgripbottom, sidebwidth,
1081                     self->size.top + self->client_area.height
1082                             + self->size.bottom - self->bwidth,
1083                     theme_config.grip_width + self->bwidth, self->bwidth);
1084             XMoveResizeWindow(plugin.ob_display, self->rgripbottom,
1085                     self->size.left + self->client_area.width
1086                             + self->size.right - self->bwidth - sidebwidth
1087                             - theme_config.grip_width, self->size.top
1088                             + self->client_area.height + self->size.bottom
1089                             - self->bwidth, theme_config.grip_width
1090                             + self->bwidth, self->bwidth);
1091
1092             XMapWindow(plugin.ob_display, self->handlebottom);
1093             XMapWindow(plugin.ob_display, self->lgripbottom);
1094             XMapWindow(plugin.ob_display, self->rgripbottom);
1095
1096             if (self->decorations & OB_FRAME_DECOR_HANDLE
1097                     && theme_config.handle_height > 0) {
1098                 XMoveResizeWindow(plugin.ob_display, self->handletop,
1099                         theme_config.grip_width + self->bwidth + sidebwidth, 
1100                         FRAME_HANDLE_Y(self), self->width - (theme_config.grip_width
1101                                 + sidebwidth) * 2, self->bwidth);
1102                 XMapWindow(plugin.ob_display, self->handletop);
1103
1104                 if (self->decorations & OB_FRAME_DECOR_GRIPS) {
1105                     XMoveResizeWindow(plugin.ob_display, self->handleleft,
1106                             theme_config.grip_width, 0, self->bwidth,
1107                             theme_config.handle_height);
1108                     XMoveResizeWindow(plugin.ob_display, self->handleright,
1109                             self->width - theme_config.grip_width
1110                                     - self->bwidth, 0, self->bwidth,
1111                             theme_config.handle_height);
1112
1113                     XMoveResizeWindow(plugin.ob_display, self->lgriptop,
1114                             sidebwidth, 
1115                             FRAME_HANDLE_Y(self), theme_config.grip_width
1116                                     + self->bwidth, self->bwidth);
1117                     XMoveResizeWindow(plugin.ob_display, self->rgriptop,
1118                             self->size.left + self->client_area.width
1119                                     + self->size.right - self->bwidth
1120                                     - sidebwidth - theme_config.grip_width, 
1121                             FRAME_HANDLE_Y(self), theme_config.grip_width
1122                                     + self->bwidth, self->bwidth);
1123
1124                     XMapWindow(plugin.ob_display, self->handleleft);
1125                     XMapWindow(plugin.ob_display, self->handleright);
1126                     XMapWindow(plugin.ob_display, self->lgriptop);
1127                     XMapWindow(plugin.ob_display, self->rgriptop);
1128                 }
1129                 else {
1130                     XUnmapWindow(plugin.ob_display, self->handleleft);
1131                     XUnmapWindow(plugin.ob_display, self->handleright);
1132                     XUnmapWindow(plugin.ob_display, self->lgriptop);
1133                     XUnmapWindow(plugin.ob_display, self->rgriptop);
1134                 }
1135             }
1136             else {
1137                 XUnmapWindow(plugin.ob_display, self->handleleft);
1138                 XUnmapWindow(plugin.ob_display, self->handleright);
1139                 XUnmapWindow(plugin.ob_display, self->lgriptop);
1140                 XUnmapWindow(plugin.ob_display, self->rgriptop);
1141
1142                 XUnmapWindow(plugin.ob_display, self->handletop);
1143             }
1144         }
1145         else {
1146             XUnmapWindow(plugin.ob_display, self->handleleft);
1147             XUnmapWindow(plugin.ob_display, self->handleright);
1148             XUnmapWindow(plugin.ob_display, self->lgriptop);
1149             XUnmapWindow(plugin.ob_display, self->rgriptop);
1150
1151             XUnmapWindow(plugin.ob_display, self->handletop);
1152
1153             XUnmapWindow(plugin.ob_display, self->handlebottom);
1154             XUnmapWindow(plugin.ob_display, self->lgripleft);
1155             XUnmapWindow(plugin.ob_display, self->rgripright);
1156             XUnmapWindow(plugin.ob_display, self->lgripbottom);
1157             XUnmapWindow(plugin.ob_display, self->rgripbottom);
1158         }
1159
1160         if (self->decorations & OB_FRAME_DECOR_HANDLE
1161                 && theme_config.handle_height > 0) {
1162             XMoveResizeWindow(plugin.ob_display, self->handle, sidebwidth, 
1163             FRAME_HANDLE_Y(self) + self->bwidth, self->width,
1164                     theme_config.handle_height);
1165             XMapWindow(plugin.ob_display, self->handle);
1166
1167             if (self->decorations & OB_FRAME_DECOR_GRIPS) {
1168                 XMoveResizeWindow(plugin.ob_display, self->lgrip, 0, 0,
1169                         theme_config.grip_width, theme_config.handle_height);
1170                 XMoveResizeWindow(plugin.ob_display, self->rgrip, self->width
1171                         - theme_config.grip_width, 0, theme_config.grip_width,
1172                         theme_config.handle_height);
1173
1174                 XMapWindow(plugin.ob_display, self->lgrip);
1175                 XMapWindow(plugin.ob_display, self->rgrip);
1176             }
1177             else {
1178                 XUnmapWindow(plugin.ob_display, self->lgrip);
1179                 XUnmapWindow(plugin.ob_display, self->rgrip);
1180             }
1181         }
1182         else {
1183             XUnmapWindow(plugin.ob_display, self->lgrip);
1184             XUnmapWindow(plugin.ob_display, self->rgrip);
1185
1186             XUnmapWindow(plugin.ob_display, self->handle);
1187         }
1188
1189         if (self->bwidth && !self->max_horz && (self->client_area.height
1190                 + self->size.top + self->size.bottom) > theme_config.grip_width
1191                 * 2) {
1192             XMoveResizeWindow(plugin.ob_display, self->left, 0, self->bwidth
1193                     + theme_config.grip_width, self->bwidth,
1194                     self->client_area.height + self->size.top
1195                             + self->size.bottom - theme_config.grip_width * 2);
1196
1197             XMapWindow(plugin.ob_display, self->left);
1198         }
1199         else
1200             XUnmapWindow(plugin.ob_display, self->left);
1201
1202         if (self->bwidth && !self->max_horz && (self->client_area.height
1203                 + self->size.top + self->size.bottom) > theme_config.grip_width
1204                 * 2) {
1205             XMoveResizeWindow(plugin.ob_display, self->right,
1206                     self->client_area.width + self->cbwidth_l + self->cbwidth_r
1207                             + self->bwidth, self->bwidth
1208                             + theme_config.grip_width, self->bwidth,
1209                     self->client_area.height + self->size.top
1210                             + self->size.bottom - theme_config.grip_width * 2);
1211
1212             XMapWindow(plugin.ob_display, self->right);
1213         }
1214         else
1215             XUnmapWindow(plugin.ob_display, self->right);
1216
1217         XMoveResizeWindow(plugin.ob_display, self->backback, self->size.left,
1218                 self->size.top, self->client_area.width,
1219                 self->client_area.height);
1220     }
1221
1222     /* shading can change without being moved or resized */
1223     RECT_SET_SIZE(self->area, self->client_area.width + self->size.left
1224             + self->size.right, (self->shaded ? theme_config.title_height
1225             + self->bwidth * 2 : self->client_area.height + self->size.top
1226             + self->size.bottom));
1227
1228     if ((is_resize) && !is_fake) {
1229         /* find the new coordinates, done after setting the frame.size, for
1230          frame_client_gravity. */
1231         self->area.x = self->client_area.x;
1232         self->area.y = self->client_area.y;
1233         frame_client_gravity(OBDEFAULTFRAME(_self)->client, &self->area.x, &self->area.y);
1234     }
1235
1236     if (!is_fake) {
1237         if (!frame_iconify_animating(self))
1238             /* move and resize the top level frame.
1239              shading can change without being moved or resized.
1240
1241              but don't do this during an iconify animation. it will be
1242              reflected afterwards.
1243              */
1244             XMoveResizeWindow(plugin.ob_display, self->window, self->area.x,
1245                     self->area.y, self->area.width, self->area.height);
1246
1247         /* when the client has StaticGravity, it likes to move around.
1248          also this correctly positions the client when it maps.
1249          this also needs to be run when the frame's decorations sizes change!
1250          */
1251         if (!is_resize)
1252             XMoveResizeWindow(plugin.ob_display, self->client->window,
1253                     self->size.left, self->size.top, self->client_area.width,
1254                     self->client_area.height);
1255
1256         if (is_resize) {
1257             self->need_render = TRUE;
1258             frame_update_skin(self);
1259             frame_adjust_shape(self);
1260         }
1261
1262         if (!STRUT_EQUAL(self->size, oldsize)) {
1263             gulong vals[4];
1264             vals[0] = self->size.left;
1265             vals[1] = self->size.right;
1266             vals[2] = self->size.top;
1267             vals[3] = self->size.bottom;
1268             OBT_PROP_SETA32(self->client->window, NET_FRAME_EXTENTS, CARDINAL,
1269                     vals, 4);
1270             OBT_PROP_SETA32(self->client->window, KDE_NET_WM_FRAME_STRUT,
1271                     CARDINAL, vals, 4);
1272         }
1273
1274         /* if this occurs while we are focus cycling, the indicator needs to
1275          match the changes */
1276         if (plugin.focus_cycle_target == self->client)
1277             focus_cycle_draw_indicator(self->client);
1278     }
1279     if (is_resize && (self->decorations & OB_FRAME_DECOR_TITLEBAR))
1280         XResizeWindow(plugin.ob_display, self->label, self->label_width,
1281                 theme_config.label_height);
1282 }
1283
1284 void frame_set_hover_flag(gpointer self, ObFrameButton button)
1285 {
1286     if (OBDEFAULTFRAME(self)->hover_flag != button) {
1287         OBDEFAULTFRAME(self)->hover_flag = button;
1288         frame_update_skin(self);
1289     }
1290 }
1291
1292 void frame_set_press_flag(gpointer self, ObFrameButton button)
1293 {
1294     if (OBDEFAULTFRAME(self)->press_flag != button) {
1295         OBDEFAULTFRAME(self)->press_flag = button;
1296         frame_update_skin(self);
1297     }
1298 }
1299
1300 Window frame_get_window(gpointer self)
1301 {
1302     return OBDEFAULTFRAME(self)->window;
1303 }
1304
1305 Strut frame_get_size(gpointer self)
1306 {
1307     return OBDEFAULTFRAME(self)->size;
1308 }
1309
1310 gint frame_get_decorations(gpointer self)
1311 {
1312     return OBDEFAULTFRAME(self)->decorations;
1313 }
1314
1315 void frame_update_title (gpointer self, const gchar * src)
1316 {
1317     g_free(OBDEFAULTFRAME(self)->stitle);
1318     OBDEFAULTFRAME(self)->stitle = g_strdup(src);
1319 }
1320
1321 gboolean frame_is_visible(gpointer self)
1322 {
1323     return OBDEFAULTFRAME(self)->visible;
1324 }
1325
1326 gboolean frame_is_max_horz(gpointer self)
1327 {
1328     return OBDEFAULTFRAME(self)->max_horz;
1329 }
1330
1331 gboolean frame_is_max_vert(gpointer self)
1332 {
1333     return OBDEFAULTFRAME(self)->max_vert;
1334 }
1335
1336 gulong frame_animate_iconify_time_left(gpointer _self, const GTimeVal *now)
1337 {
1338     ObDefaultFrame * self = (ObDefaultFrame *) _self;
1339     glong sec, usec;
1340     sec = self->iconify_animation_end.tv_sec - now->tv_sec;
1341     usec = self->iconify_animation_end.tv_usec - now->tv_usec;
1342     if (usec < 0) {
1343         usec += G_USEC_PER_SEC;
1344         sec--;
1345     }
1346     /* no negative values */
1347     return MAX(sec * G_USEC_PER_SEC + usec, 0);
1348 }
1349
1350 gboolean frame_animate_iconify(gpointer p)
1351 {
1352     ObDefaultFrame *self = p;
1353     gint x, y, w, h;
1354     gint iconx, icony, iconw;
1355     GTimeVal now;
1356     gulong time;
1357     gboolean iconifying;
1358
1359     if (self->client->icon_geometry.width == 0) {
1360         /* there is no icon geometry set so just go straight down */
1361         Rect *a =
1362                 screen_physical_area_monitor(screen_find_monitor(&self->area));
1363         iconx = self->area.x + self->area.width / 2 + 32;
1364         icony = a->y + a->width;
1365         iconw = 64;
1366         g_free(a);
1367     }
1368     else {
1369         iconx = self->client->icon_geometry.x;
1370         icony = self->client->icon_geometry.y;
1371         iconw = self->client->icon_geometry.width;
1372     }
1373
1374     iconifying = self->iconify_animation_going > 0;
1375
1376     /* how far do we have left to go ? */
1377     g_get_current_time(&now);
1378     time = frame_animate_iconify_time_left(self, &now);
1379
1380     if (time == 0 || iconifying) {
1381         /* start where the frame is supposed to be */
1382         x = self->area.x;
1383         y = self->area.y;
1384         w = self->area.width;
1385         h = self->area.height;
1386     }
1387     else {
1388         /* start at the icon */
1389         x = iconx;
1390         y = icony;
1391         w = iconw;
1392         h = self->size.top; /* just the titlebar */
1393     }
1394
1395     if (time > 0) {
1396         glong dx, dy, dw;
1397         glong elapsed;
1398
1399         dx = self->area.x - iconx;
1400         dy = self->area.y - icony;
1401         dw = self->area.width - self->bwidth * 2 - iconw;
1402         /* if restoring, we move in the opposite direction */
1403         if (!iconifying) {
1404             dx = -dx;
1405             dy = -dy;
1406             dw = -dw;
1407         }
1408
1409         elapsed = FRAME_ANIMATE_ICONIFY_TIME - time;
1410         x = x - (dx * elapsed) / FRAME_ANIMATE_ICONIFY_TIME;
1411         y = y - (dy * elapsed) / FRAME_ANIMATE_ICONIFY_TIME;
1412         w = w - (dw * elapsed) / FRAME_ANIMATE_ICONIFY_TIME;
1413         h = self->size.top; /* just the titlebar */
1414     }
1415
1416     if (time == 0)
1417         frame_end_iconify_animation(self);
1418     else {
1419         XMoveResizeWindow(plugin.ob_display, self->window, x, y, w, h);
1420         XFlush(plugin.ob_display);
1421     }
1422
1423     return time > 0; /* repeat until we're out of time */
1424 }
1425
1426 void frame_adjust_cursors(gpointer _self)
1427 {
1428     ObDefaultFrame * self = (ObDefaultFrame *) _self;
1429     if ((self->functions & OB_CLIENT_FUNC_RESIZE) != (self->functions
1430             & OB_CLIENT_FUNC_RESIZE) || self->max_horz != self->max_horz
1431             || self->max_vert != self->max_vert || self->shaded != self->shaded) {
1432         gboolean r = (self->functions & OB_CLIENT_FUNC_RESIZE)
1433                 && !(self->max_horz && self->max_vert);
1434         gboolean topbot = !self->max_vert;
1435         gboolean sh = self->shaded;
1436         XSetWindowAttributes a;
1437
1438         /* these ones turn off when max vert, and some when shaded */
1439         a.cursor = ob_cursor(r && topbot && !sh ? OB_CURSOR_NORTH
1440                 : OB_CURSOR_NONE);
1441         XChangeWindowAttributes(plugin.ob_display, self->topresize, CWCursor,
1442                 &a);
1443         XChangeWindowAttributes(plugin.ob_display, self->titletop, CWCursor, &a);
1444         a.cursor = ob_cursor(r && topbot ? OB_CURSOR_SOUTH : OB_CURSOR_NONE);
1445         XChangeWindowAttributes(plugin.ob_display, self->handle, CWCursor, &a);
1446         XChangeWindowAttributes(plugin.ob_display, self->handletop, CWCursor,
1447                 &a);
1448         XChangeWindowAttributes(plugin.ob_display, self->handlebottom,
1449                 CWCursor, &a);
1450         XChangeWindowAttributes(plugin.ob_display, self->innerbottom, CWCursor,
1451                 &a);
1452
1453         /* these ones change when shaded */
1454         a.cursor = ob_cursor(r ? (sh ? OB_CURSOR_WEST : OB_CURSOR_NORTHWEST)
1455                 : OB_CURSOR_NONE);
1456         XChangeWindowAttributes(plugin.ob_display, self->titleleft, CWCursor,
1457                 &a);
1458         XChangeWindowAttributes(plugin.ob_display, self->tltresize, CWCursor,
1459                 &a);
1460         XChangeWindowAttributes(plugin.ob_display, self->tllresize, CWCursor,
1461                 &a);
1462         XChangeWindowAttributes(plugin.ob_display, self->titletopleft,
1463                 CWCursor, &a);
1464         a.cursor = ob_cursor(r ? (sh ? OB_CURSOR_EAST : OB_CURSOR_NORTHEAST)
1465                 : OB_CURSOR_NONE);
1466         XChangeWindowAttributes(plugin.ob_display, self->titleright, CWCursor,
1467                 &a);
1468         XChangeWindowAttributes(plugin.ob_display, self->trtresize, CWCursor,
1469                 &a);
1470         XChangeWindowAttributes(plugin.ob_display, self->trrresize, CWCursor,
1471                 &a);
1472         XChangeWindowAttributes(plugin.ob_display, self->titletopright,
1473                 CWCursor, &a);
1474
1475         /* these ones are pretty static */
1476         a.cursor = ob_cursor(r ? OB_CURSOR_WEST : OB_CURSOR_NONE);
1477         XChangeWindowAttributes(plugin.ob_display, self->left, CWCursor, &a);
1478         XChangeWindowAttributes(plugin.ob_display, self->innerleft, CWCursor,
1479                 &a);
1480         a.cursor = ob_cursor(r ? OB_CURSOR_EAST : OB_CURSOR_NONE);
1481         XChangeWindowAttributes(plugin.ob_display, self->right, CWCursor, &a);
1482         XChangeWindowAttributes(plugin.ob_display, self->innerright, CWCursor,
1483                 &a);
1484         a.cursor = ob_cursor(r ? OB_CURSOR_SOUTHWEST : OB_CURSOR_NONE);
1485         XChangeWindowAttributes(plugin.ob_display, self->lgrip, CWCursor, &a);
1486         XChangeWindowAttributes(plugin.ob_display, self->handleleft, CWCursor,
1487                 &a);
1488         XChangeWindowAttributes(plugin.ob_display, self->lgripleft, CWCursor,
1489                 &a);
1490         XChangeWindowAttributes(plugin.ob_display, self->lgriptop, CWCursor, &a);
1491         XChangeWindowAttributes(plugin.ob_display, self->lgripbottom, CWCursor,
1492                 &a);
1493         XChangeWindowAttributes(plugin.ob_display, self->innerbll, CWCursor, &a);
1494         XChangeWindowAttributes(plugin.ob_display, self->innerblb, CWCursor, &a);
1495         a.cursor = ob_cursor(r ? OB_CURSOR_SOUTHEAST : OB_CURSOR_NONE);
1496         XChangeWindowAttributes(plugin.ob_display, self->rgrip, CWCursor, &a);
1497         XChangeWindowAttributes(plugin.ob_display, self->handleright, CWCursor,
1498                 &a);
1499         XChangeWindowAttributes(plugin.ob_display, self->rgripright, CWCursor,
1500                 &a);
1501         XChangeWindowAttributes(plugin.ob_display, self->rgriptop, CWCursor, &a);
1502         XChangeWindowAttributes(plugin.ob_display, self->rgripbottom, CWCursor,
1503                 &a);
1504         XChangeWindowAttributes(plugin.ob_display, self->innerbrr, CWCursor, &a);
1505         XChangeWindowAttributes(plugin.ob_display, self->innerbrb, CWCursor, &a);
1506     }
1507 }
1508
1509 void frame_adjust_client_area(gpointer _self)
1510 {
1511     ObDefaultFrame * self = (ObDefaultFrame *) _self;
1512     /* adjust the window which is there to prevent flashing on unmap */
1513     XMoveResizeWindow(plugin.ob_display, self->backfront, 0, 0,
1514             self->client_area.width, self->client_area.height);
1515 }
1516
1517 void frame_adjust_state(gpointer _self)
1518 {
1519     ObDefaultFrame * self = (ObDefaultFrame *) _self;
1520     self->need_render = TRUE;
1521     frame_update_skin(self);
1522 }
1523
1524 void frame_adjust_focus(gpointer _self, gboolean hilite)
1525 {
1526     ObDefaultFrame * self = (ObDefaultFrame *) _self;
1527     self->focused = hilite;
1528     self->need_render = TRUE;
1529     frame_update_skin(self);
1530     XFlush(plugin.ob_display);
1531 }
1532
1533 void frame_adjust_title(gpointer _self)
1534 {
1535     ObDefaultFrame * self = (ObDefaultFrame *) _self;
1536     self->need_render = TRUE;
1537     frame_update_skin(self);
1538 }
1539
1540 void frame_adjust_icon(gpointer _self)
1541 {
1542     ObDefaultFrame * self = (ObDefaultFrame *) _self;
1543     self->need_render = TRUE;
1544     frame_update_skin(self);
1545 }
1546
1547 /* is there anything present between us and the label? */
1548 static gboolean is_button_present(ObDefaultFrame *_self, const gchar *lc,
1549         gint dir)
1550 {
1551     ObDefaultFrame * self = (ObDefaultFrame *) _self;
1552     for (; *lc != '\0' && lc >= plugin.config_title_layout; lc += dir) {
1553         if (*lc == ' ')
1554             continue; /* it was invalid */
1555         if (*lc == 'N' && self->decorations & OB_FRAME_DECOR_ICON)
1556             return TRUE;
1557         if (*lc == 'D' && self->decorations & OB_FRAME_DECOR_ALLDESKTOPS)
1558             return TRUE;
1559         if (*lc == 'S' && self->decorations & OB_FRAME_DECOR_SHADE)
1560             return TRUE;
1561         if (*lc == 'I' && self->decorations & OB_FRAME_DECOR_ICONIFY)
1562             return TRUE;
1563         if (*lc == 'M' && self->decorations & OB_FRAME_DECOR_MAXIMIZE)
1564             return TRUE;
1565         if (*lc == 'C' && self->decorations & OB_FRAME_DECOR_CLOSE)
1566             return TRUE;
1567         if (*lc == 'L')
1568             return FALSE;
1569     }
1570     return FALSE;
1571 }
1572
1573 void flash_done(gpointer data)
1574 {
1575     ObDefaultFrame *self = data;
1576
1577     if (self->focused != self->flash_on)
1578         frame_adjust_focus(self, self->focused);
1579 }
1580
1581 gboolean flash_timeout(gpointer data)
1582 {
1583     ObDefaultFrame *self = data;
1584     GTimeVal now;
1585
1586     g_get_current_time(&now);
1587     if (now.tv_sec > self->flash_end.tv_sec
1588             || (now.tv_sec == self->flash_end.tv_sec && now.tv_usec
1589                     >= self->flash_end.tv_usec))
1590         self->flashing = FALSE;
1591
1592     if (!self->flashing)
1593         return FALSE; /* we are done */
1594
1595     self->flash_on = !self->flash_on;
1596     if (!self->focused) {
1597         frame_adjust_focus(self, self->flash_on);
1598         self->focused = FALSE;
1599     }
1600
1601     return TRUE; /* go again */
1602 }
1603
1604 void layout_title(ObDefaultFrame * self)
1605 {
1606     gchar *lc;
1607     gint i;
1608
1609     const gint bwidth = theme_config.button_size + theme_config.paddingx + 1;
1610     /* position of the left most button */
1611     const gint left = theme_config.paddingx + 1;
1612     /* position of the right most button */
1613     const gint right = self->width;
1614
1615     /* turn them all off */
1616     self->icon_on = self->desk_on = self->shade_on = self->iconify_on
1617             = self->max_on = self->close_on = self->label_on = FALSE;
1618     self->label_width = self->width - (theme_config.paddingx + 1) * 2;
1619     self->leftmost = self->rightmost = OB_FRAME_CONTEXT_NONE;
1620
1621     /* figure out what's being show, find each element's position, and the
1622      width of the label
1623
1624      do the ones before the label, then after the label,
1625      i will be +1 the first time through when working to the left,
1626      and -1 the second time through when working to the right */
1627     for (i = 1; i >= -1; i-=2) {
1628         gint x;
1629         ObFrameContext *firstcon;
1630
1631         if (i > 0) {
1632             x = left;
1633             lc = plugin.config_title_layout;
1634             firstcon = &self->leftmost;
1635         }
1636         else {
1637             x = right;
1638             lc = plugin.config_title_layout
1639                     + strlen(plugin.config_title_layout)-1;
1640             firstcon = &self->rightmost;
1641         }
1642
1643         /* stop at the end of the string (or the label, which calls break) */
1644         for (; *lc != '\0' && lc >= plugin.config_title_layout; lc+=i) {
1645             if (*lc == 'L') {
1646                 if (i > 0) {
1647                     self->label_on = TRUE;
1648                     self->label_x = x;
1649                 }
1650                 break; /* break the for loop, do other side of label */
1651             }
1652             else if (*lc == 'N') {
1653                 if (firstcon)
1654                     *firstcon = OB_FRAME_CONTEXT_ICON;
1655                 if ((self->icon_on = is_button_present(self, lc, i))) {
1656                     /* icon is bigger than buttons */
1657                     self->label_width -= bwidth + 2;
1658                     if (i > 0)
1659                         self->icon_x = x;
1660                     x += i * (bwidth + 2);
1661                     if (i < 0)
1662                         self->icon_x = x;
1663                 }
1664             }
1665             else if (*lc == 'D') {
1666                 if (firstcon)
1667                     *firstcon = OB_FRAME_CONTEXT_ALLDESKTOPS;
1668                 if ((self->desk_on = is_button_present(self, lc, i))) {
1669                     self->label_width -= bwidth;
1670                     if (i > 0)
1671                         self->desk_x = x;
1672                     x += i * bwidth;
1673                     if (i < 0)
1674                         self->desk_x = x;
1675                 }
1676             }
1677             else if (*lc == 'S') {
1678                 if (firstcon)
1679                     *firstcon = OB_FRAME_CONTEXT_SHADE;
1680                 if ((self->shade_on = is_button_present(self, lc, i))) {
1681                     self->label_width -= bwidth;
1682                     if (i > 0)
1683                         self->shade_x = x;
1684                     x += i * bwidth;
1685                     if (i < 0)
1686                         self->shade_x = x;
1687                 }
1688             }
1689             else if (*lc == 'I') {
1690                 if (firstcon)
1691                     *firstcon = OB_FRAME_CONTEXT_ICONIFY;
1692                 if ((self->iconify_on = is_button_present(self, lc, i))) {
1693                     self->label_width -= bwidth;
1694                     if (i > 0)
1695                         self->iconify_x = x;
1696                     x += i * bwidth;
1697                     if (i < 0)
1698                         self->iconify_x = x;
1699                 }
1700             }
1701             else if (*lc == 'M') {
1702                 if (firstcon)
1703                     *firstcon = OB_FRAME_CONTEXT_MAXIMIZE;
1704                 if ((self->max_on = is_button_present(self, lc, i))) {
1705                     self->label_width -= bwidth;
1706                     if (i > 0)
1707                         self->max_x = x;
1708                     x += i * bwidth;
1709                     if (i < 0)
1710                         self->max_x = x;
1711                 }
1712             }
1713             else if (*lc == 'C') {
1714                 if (firstcon)
1715                     *firstcon = OB_FRAME_CONTEXT_CLOSE;
1716                 if ((self->close_on = is_button_present(self, lc, i))) {
1717                     self->label_width -= bwidth;
1718                     if (i > 0)
1719                         self->close_x = x;
1720                     x += i * bwidth;
1721                     if (i < 0)
1722                         self->close_x = x;
1723                 }
1724             }
1725             else
1726                 continue; /* don't set firstcon */
1727             firstcon = NULL;
1728         }
1729     }
1730
1731     /* position and map the elements */
1732     if (self->icon_on) {
1733         XMapWindow(plugin.ob_display, self->icon);
1734         XMoveWindow(plugin.ob_display, self->icon, self->icon_x,
1735                 theme_config.paddingy);
1736     }
1737     else
1738         XUnmapWindow(plugin.ob_display, self->icon);
1739
1740     if (self->desk_on) {
1741         XMapWindow(plugin.ob_display, self->desk);
1742         XMoveWindow(plugin.ob_display, self->desk, self->desk_x,
1743                 theme_config.paddingy + 1);
1744     }
1745     else
1746         XUnmapWindow(plugin.ob_display, self->desk);
1747
1748     if (self->shade_on) {
1749         XMapWindow(plugin.ob_display, self->shade);
1750         XMoveWindow(plugin.ob_display, self->shade, self->shade_x,
1751                 theme_config.paddingy + 1);
1752     }
1753     else
1754         XUnmapWindow(plugin.ob_display, self->shade);
1755
1756     if (self->iconify_on) {
1757         XMapWindow(plugin.ob_display, self->iconify);
1758         XMoveWindow(plugin.ob_display, self->iconify, self->iconify_x,
1759                 theme_config.paddingy + 1);
1760     }
1761     else
1762         XUnmapWindow(plugin.ob_display, self->iconify);
1763
1764     if (self->max_on) {
1765         XMapWindow(plugin.ob_display, self->max);
1766         XMoveWindow(plugin.ob_display, self->max, self->max_x,
1767                 theme_config.paddingy + 1);
1768     }
1769     else
1770         XUnmapWindow(plugin.ob_display, self->max);
1771
1772     if (self->close_on) {
1773         XMapWindow(plugin.ob_display, self->close);
1774         XMoveWindow(plugin.ob_display, self->close, self->close_x,
1775                 theme_config.paddingy + 1);
1776     }
1777     else
1778         XUnmapWindow(plugin.ob_display, self->close);
1779
1780     if (self->label_on) {
1781         self->label_width = MAX(1, self->label_width); /* no lower than 1 */
1782         XMapWindow(plugin.ob_display, self->label);
1783         XMoveWindow(plugin.ob_display, self->label, self->label_x,
1784                 theme_config.paddingy);
1785     }
1786     else
1787         XUnmapWindow(plugin.ob_display, self->label);
1788 }
1789
1790 void trigger_none (gpointer self) {}
1791 void trigger_iconify(gpointer self) {}
1792 void trigger_uniconnity(gpointer self) {}
1793 void trigger_iconify_toggle(gpointer self) {}
1794 void trigger_shade(gpointer self) {}
1795 void trigger_unshade(gpointer self) {}
1796 void trigger_shade_toggle(gpointer self) {}
1797 void trigger_max(gpointer self) {}
1798 void trigger_unmax(gpointer self) {}
1799 void trigger_max_troggle(gpointer self) {}
1800 void trigger_max_vert(gpointer self) {OBDEFAULTFRAME(self)->max_vert = TRUE;}
1801 void trigger_unmax_vert(gpointer self) {OBDEFAULTFRAME(self)->max_vert = FALSE;}
1802 void trigger_max_toggle(gpointer self) {}
1803 void trigger_max_horz(gpointer self) {OBDEFAULTFRAME(self)->max_horz = TRUE;}
1804 void trigger_unmax_horz(gpointer self) {OBDEFAULTFRAME(self)->max_horz = FALSE;}
1805 void trigger_max_horz_toggle(gpointer self) {}
1806 void trigger_plugin1(gpointer self) {}
1807 void trigger_plugin2(gpointer self) {}
1808 void trigger_plugin3(gpointer self) {}
1809 void trigger_plugin4(gpointer self) {}
1810 void trigger_plugin5(gpointer self) {}
1811 void trigger_plugin6(gpointer self) {}
1812 void trigger_plugin7(gpointer self) {}
1813 void trigger_plugin8(gpointer self) {}
1814 void trigger_plugin9(gpointer self) {}
1815
1816 void frame_trigger(gpointer self, ObFrameTrigger trigger_name)
1817 {
1818
1819     static void (*trigger_func[64])(gpointer) = { 
1820             trigger_none,
1821             trigger_iconify,
1822             trigger_uniconnity,
1823             trigger_iconify_toggle,
1824             trigger_shade,
1825             trigger_unshade,
1826             trigger_shade_toggle,
1827             trigger_max,
1828             trigger_unmax,
1829             trigger_max_troggle,
1830             trigger_max_vert,
1831             trigger_unmax_vert,
1832             trigger_max_toggle,
1833             trigger_max_horz,
1834             trigger_unmax_horz,
1835             trigger_max_horz_toggle,
1836             trigger_plugin1,
1837             trigger_plugin2,
1838             trigger_plugin3,
1839             trigger_plugin4,
1840             trigger_plugin5,
1841             trigger_plugin6,
1842             trigger_plugin7,
1843             trigger_plugin8,
1844             trigger_plugin9,
1845             NULL,
1846     };
1847     
1848     void (*call_trigger_func)(gpointer) = trigger_func[trigger_name];
1849     if(!call_trigger_func)
1850     {
1851         call_trigger_func (self);
1852     }
1853 }
1854
1855 ObFramePlugin plugin = { 0, //gpointer handler;
1856         "libdefault.la", //gchar * filename;
1857         "Default", //gchar * name;
1858         init, //gint (*init) (Display * display, gint screen);
1859         0, /* */
1860         frame_new, //gpointer (*frame_new) (struct _ObClient *c);
1861         frame_free, //void (*frame_free) (gpointer self);
1862         frame_show, //void (*frame_show) (gpointer self);
1863         frame_hide, //void (*frame_hide) (gpointer self);
1864         frame_adjust_theme, //void (*frame_adjust_theme) (gpointer self);
1865         frame_adjust_shape, //void (*frame_adjust_shape) (gpointer self);
1866         frame_grab, //void (*frame_adjust_area) (gpointer self, gboolean moved, gboolean resized, gboolean fake);
1867         frame_ungrab, frame_context, //void (*frame_adjust_state) (gpointer self);
1868         frame_set_is_visible, /* */
1869         frame_set_is_focus, /* */
1870         frame_set_is_max_vert, /* */
1871         frame_set_is_max_horz, /* */
1872         frame_set_is_shaded, /* */
1873
1874         frame_flash_start, /* */
1875         frame_flash_stop, /* */
1876         frame_begin_iconify_animation, /* */
1877         frame_end_iconify_animation, /* */
1878         frame_iconify_animating, /* */
1879
1880         frame_set_decorations, /* */
1881         
1882         frame_update_title, /* */
1883         /* This give the window area */
1884         frame_get_window_area, /* */
1885         frame_set_client_area, /* */
1886         /* Draw the frame */
1887         frame_update_layout, /* */
1888         frame_update_skin, /* */
1889
1890         frame_set_hover_flag, /* */
1891         frame_set_press_flag, /* */
1892
1893         frame_get_window,/* */
1894
1895         frame_get_size, /* */
1896         frame_get_decorations, /* */
1897
1898         frame_is_visible, /* */
1899         frame_is_max_horz, /* */
1900         frame_is_max_vert, /* */
1901
1902         frame_trigger, /* */
1903
1904         load_theme_config, /* */
1905
1906         /* This fields are fill by openbox. */
1907         0, //Display * ob_display;
1908         0, //gint ob_screen;
1909         0, //RrInstance *ob_rr_inst;
1910         0, //gboolean config_theme_keepborder;
1911         0, //struct _ObClient *focus_cycle_target;
1912         0, //gchar *config_title_layout;
1913         FALSE, //gboolean moveresize_in_progress;
1914         0, //struct _ObMainLoop *ob_main_loop;
1915 };
1916
1917 ObFramePlugin * get_info()
1918 {
1919     return &plugin;
1920 }