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