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