1 /* -*- indent-tabs-mode: nil; tab-width: 4; c-basic-offset: 4; -*-
3 frame_default_plugin.c for the Openbox window manager
4 Copyright (c) 2006 Mikael Magnusson
5 Copyright (c) 2003-2007 Dana Jansens
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.
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.
17 See the COPYING file for a copy of the GNU General Public License.
20 #include "openbox/client.h"
21 #include "openbox/openbox.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"
38 OB_FLAG_CLOSE = 1 << 1,
39 OB_FLAG_DESK = 1 << 2,
40 OB_FLAG_SHADE = 1 << 3,
41 OB_FLAG_ICONIFY = 1 << 4
44 #define FRAME_EVENTMASK (EnterWindowMask | LeaveWindowMask | \
45 ButtonPressMask | ButtonReleaseMask | \
46 SubstructureRedirectMask | FocusChangeMask)
47 #define ELEMENT_EVENTMASK (ButtonPressMask | ButtonReleaseMask | \
48 ButtonMotionMask | PointerMotionMask | \
49 EnterWindowMask | LeaveWindowMask)
51 #define FRAME_ANIMATE_ICONIFY_TIME 150000 /* .15 seconds */
52 #define FRAME_ANIMATE_ICONIFY_STEP_TIME (G_USEC_PER_SEC / 60) /* 60 Hz */
54 #define FRAME_HANDLE_Y(f) (f->size.top + f->client_area.height + f->cbwidth_b)
56 Window createWindow(Window parent, Visual *visual, gulong mask,
57 XSetWindowAttributes *attrib)
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);
65 Visual *check_32bit_client(ObClient *c)
67 XWindowAttributes wattrib;
70 /* we're already running at 32 bit depth, yay. we don't need to use their
72 if (RrDepth(plugin.ob_rr_inst) == 32)
75 ret = XGetWindowAttributes(plugin.ob_display, c->window, &wattrib);
76 g_assert(ret != BadDrawable);
77 g_assert(ret != BadWindow);
79 if (wattrib.depth == 32)
80 return wattrib.visual;
85 gint init(Display * display, gint screen)
87 plugin.ob_display = display;
88 plugin.ob_screen = screen;
91 gpointer frame_new(struct _ObClient * client)
93 XSetWindowAttributes attrib;
98 self = g_new0(ObDefaultFrame, 1);
99 self->client = client;
101 visual = check_32bit_client(client);
103 /* create the non-visible decor windows */
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,
115 attrib.border_pixel = BlackPixel(plugin.ob_display, plugin.ob_screen);
117 self->window = createWindow(
118 RootWindow(plugin.ob_display, plugin.ob_screen), visual, mask,
121 /* create the visible decor windows */
125 /* client has a 32-bit visual */
126 mask |= CWColormap | CWBackPixel | CWBorderPixel;
127 attrib.colormap = RrColormap(plugin.ob_rr_inst);
130 self->backback = createWindow(self->window, NULL, mask, &attrib);
131 self->backfront = createWindow(self->backback, NULL, mask, &attrib);
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);
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);
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);
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);
159 self->left = createWindow(self->window, NULL, mask, &attrib);
160 self->right = createWindow(self->window, NULL, mask, &attrib);
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);
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);
174 self->handleleft = createWindow(self->handle, NULL, mask, &attrib);
175 self->handleright = createWindow(self->handle, NULL, mask, &attrib);
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);
186 self->focused = FALSE;
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);
193 self->hover_flag = OB_BUTTON_NONE;
194 self->press_flag = OB_BUTTON_NONE;
196 set_theme_statics(self);
201 void set_theme_statics(gpointer _self)
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);
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);
237 void free_theme_statics(gpointer _self)
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);
249 void frame_free(gpointer self)
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);
258 void frame_show(gpointer _self)
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. */
268 XMapWindow(plugin.ob_display, self->client->window);
269 XMapWindow(plugin.ob_display, self->window);
274 gint frame_hide(gpointer self)
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);
290 void frame_adjust_theme(gpointer self)
292 free_theme_statics(self);
293 set_theme_statics(self);
296 void frame_adjust_shape(gpointer _self)
299 ObDefaultFrame * self = (ObDefaultFrame *) _self;
303 if (!self->client->shaped)
305 /* clear the shape on the frame window */
306 XShapeCombineMask(plugin.ob_display, self->window, ShapeBounding,
313 /* make the frame's shape match the clients */
314 XShapeCombineShape(plugin.ob_display, self->window, ShapeBounding,
317 self->client->window,
318 ShapeBounding, ShapeSet);
321 if (self->decorations & OB_FRAME_DECOR_TITLEBAR)
325 xrect[0].width = self->area.width;
326 xrect[0].height = self->size.top;
330 if (self->decorations & OB_FRAME_DECOR_HANDLE &&
331 theme_config.handle_height> 0)
334 xrect[1].y = FRAME_HANDLE_Y(self);
335 xrect[1].width = self->area.width;
336 xrect[1].height = theme_config.handle_height +
341 XShapeCombineRectangles(plugin.ob_display, self->window,
342 ShapeBounding, 0, 0, xrect, num,
343 ShapeUnion, Unsorted);
348 void frame_grab(gpointer _self, GHashTable * window_map)
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.
356 /* reparent the client to the frame */
357 XReparentWindow(plugin.ob_display, self->client->window, self->window, 0, 0);
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
365 if (ob_state() == OB_STATE_STARTING)
366 ++self->client->ignore_unmaps;
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);
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);
416 void frame_ungrab(gpointer _self, GHashTable * window_map)
418 ObDefaultFrame * self = (ObDefaultFrame *) _self;
420 gboolean reparent = TRUE;
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);
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
433 Reparent events that are generated by us are just discarded here.
434 They are of no consequence to us anyhow.
436 if (ev.xreparent.parent != self->window) {
438 XPutBackEvent(plugin.ob_display, &ev);
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);
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);
494 obt_main_loop_timeout_remove_data(plugin.ob_main_loop, flash_timeout, self,
498 ObFrameContext frame_context(gpointer _self, Window win, gint x, gint y)
500 ObDefaultFrame * self = OBDEFAULTFRAME(_self);
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 */
513 /* these windows are down a border width from the top of the frame */
514 if (win == self->title || win == self->titleleft || win
518 /* title is a border width in from the edge */
519 if (win == self->title)
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;
531 /* figure out if we're over the area that should be considered a
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;
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;
547 /* there is no resizing maximized windows so make them the titlebar
549 return OB_FRAME_CONTEXT_TITLEBAR;
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;
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;
638 return OB_FRAME_CONTEXT_NONE;
641 void frame_set_is_visible(gpointer self, gboolean b)
643 OBDEFAULTFRAME(self)->visible = b;
646 void frame_set_is_focus(gpointer self, gboolean b)
648 OBDEFAULTFRAME(self)->focused = b;
651 void frame_set_is_max_vert(gpointer self, gboolean b)
653 OBDEFAULTFRAME(self)->max_vert = b;
656 void frame_set_is_max_horz(gpointer self, gboolean b)
658 OBDEFAULTFRAME(self)->max_horz = b;
661 void frame_set_is_shaded(gpointer self, gboolean b)
663 OBDEFAULTFRAME(self)->shaded = b;
666 void frame_unfocus(gpointer self)
668 OBDEFAULTFRAME(self)->focused = FALSE;
671 void frame_flash_start(gpointer _self)
673 ObDefaultFrame * self = (ObDefaultFrame *) _self;
674 self->flash_on = self->focused;
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);
682 self->flashing = TRUE;
685 void frame_flash_stop(gpointer _self)
687 ObDefaultFrame * self = (ObDefaultFrame *) _self;
688 self->flashing = FALSE;
691 void frame_begin_iconify_animation(gpointer _self, gboolean iconifying)
693 ObDefaultFrame * self = (ObDefaultFrame *) _self;
695 gboolean new_anim = FALSE;
696 gboolean set_end = TRUE;
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))
704 /* get the current time */
705 g_get_current_time(&now);
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);
715 /* animation was already going in the same direction */
720 self->iconify_animation_going = iconifying ? 1 : -1;
722 /* set the ending time */
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);
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);
736 /* do the first step */
737 frame_animate_iconify(self);
739 /* show it during the animation even if it is not "visible" */
741 XMapWindow(plugin.ob_display, self->window);
745 void frame_end_iconify_animation(gpointer _self)
747 ObDefaultFrame * self = (ObDefaultFrame *) _self;
748 /* see if there is an animation going */
749 if (self->iconify_animation_going == 0)
753 XUnmapWindow(plugin.ob_display, self->window);
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);
763 /* we're not animating any more ! */
764 self->iconify_animation_going = 0;
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);
773 gboolean frame_iconify_animating(gpointer _self)
775 ObDefaultFrame * self = (ObDefaultFrame *) _self;
776 return self->iconify_animation_going != 0;
779 void frame_set_decorations(gpointer self, ObFrameDecorations d)
781 OBDEFAULTFRAME(self)->decorations = d;
784 Rect frame_get_window_area(gpointer self)
786 return OBDEFAULTFRAME(self)->area;
788 void frame_set_client_area(gpointer self, Rect r)
790 OBDEFAULTFRAME(self)->client_area = r;
793 void frame_update_layout(gpointer _self, gboolean is_resize, gboolean is_fake)
795 ObDefaultFrame * self = (ObDefaultFrame *) _self;
798 oldsize = self->size;
799 self->area = self->client_area;
801 /* do this before changing the frame's status like max_horz max_vert */
802 frame_adjust_cursors(self);
804 if (self->decorations & OB_FRAME_DECOR_BORDER
805 || (plugin.config_theme_keepborder)) {
806 self->bwidth = theme_config.fbwidth;
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;
825 if (self->max_horz) {
828 self->width = self->client_area.width;
833 self->width = self->client_area.width + self->cbwidth_l
837 /* some elements are sized based of the width, so don't let them have
839 self->width = MAX(self->width, (theme_config.grip_width + self->bwidth) * 2
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));
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
852 self->size.bottom += theme_config.handle_height + self->bwidth;
855 /* position/size and map/unmap all the windows */
857 gint innercornerheight = theme_config.grip_width - self->size.bottom;
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);
864 XMapWindow(plugin.ob_display, self->innerleft);
867 XUnmapWindow(plugin.ob_display, self->innerleft);
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);
875 XMapWindow(plugin.ob_display, self->innerbll);
878 XUnmapWindow(plugin.ob_display, self->innerbll);
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);
885 XMapWindow(plugin.ob_display, self->innerright);
888 XUnmapWindow(plugin.ob_display, self->innerright);
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);
896 XMapWindow(plugin.ob_display, self->innerbrr);
899 XUnmapWindow(plugin.ob_display, self->innerbrr);
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,
908 XMapWindow(plugin.ob_display, self->innertop);
911 XUnmapWindow(plugin.ob_display, self->innertop);
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,
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);
927 XMapWindow(plugin.ob_display, self->innerbottom);
928 XMapWindow(plugin.ob_display, self->innerblb);
929 XMapWindow(plugin.ob_display, self->innerbrb);
932 XUnmapWindow(plugin.ob_display, self->innerbottom);
933 XUnmapWindow(plugin.ob_display, self->innerblb);
934 XUnmapWindow(plugin.ob_display, self->innerbrb);
940 /* height of titleleft and titleright */
941 titlesides = (!self->max_horz ? theme_config.grip_width : 0);
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);
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);
963 XMapWindow(plugin.ob_display, self->titleleft);
964 XMapWindow(plugin.ob_display, self->titleright);
967 XUnmapWindow(plugin.ob_display, self->titleleft);
968 XUnmapWindow(plugin.ob_display, self->titleright);
971 XMapWindow(plugin.ob_display, self->titletop);
972 XMapWindow(plugin.ob_display, self->titletopleft);
973 XMapWindow(plugin.ob_display, self->titletopright);
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,
981 XMapWindow(plugin.ob_display, self->titlebottom);
984 XUnmapWindow(plugin.ob_display, self->titlebottom);
987 XUnmapWindow(plugin.ob_display, self->titlebottom);
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);
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);
1001 XMapWindow(plugin.ob_display, self->title);
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);
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);
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);
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);
1031 XUnmapWindow(plugin.ob_display, self->title);
1034 if ((self->decorations & OB_FRAME_DECOR_TITLEBAR))
1035 /* layout the title bar elements */
1039 gint sidebwidth = self->max_horz ? 0 : self->bwidth;
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,
1050 XMoveResizeWindow(plugin.ob_display, self->lgripleft, 0,
1051 self->size.top + self->client_area.height
1053 - (!self->max_horz ? theme_config.grip_width
1054 : self->size.bottom - self->cbwidth_b),
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
1063 - (!self->max_horz ? theme_config.grip_width
1064 : self->size.bottom - self->cbwidth_b),
1066 (!self->max_horz ? theme_config.grip_width
1067 : self->size.bottom - self->cbwidth_b));
1069 XMapWindow(plugin.ob_display, self->lgripleft);
1070 XMapWindow(plugin.ob_display, self->rgripright);
1073 XUnmapWindow(plugin.ob_display, self->lgripleft);
1074 XUnmapWindow(plugin.ob_display, self->rgripright);
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);
1089 XMapWindow(plugin.ob_display, self->handlebottom);
1090 XMapWindow(plugin.ob_display, self->lgripbottom);
1091 XMapWindow(plugin.ob_display, self->rgripbottom);
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);
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);
1110 XMoveResizeWindow(plugin.ob_display, self->lgriptop,
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);
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);
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);
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);
1139 XUnmapWindow(plugin.ob_display, self->handletop);
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);
1148 XUnmapWindow(plugin.ob_display, self->handletop);
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);
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);
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);
1171 XMapWindow(plugin.ob_display, self->lgrip);
1172 XMapWindow(plugin.ob_display, self->rgrip);
1175 XUnmapWindow(plugin.ob_display, self->lgrip);
1176 XUnmapWindow(plugin.ob_display, self->rgrip);
1180 XUnmapWindow(plugin.ob_display, self->lgrip);
1181 XUnmapWindow(plugin.ob_display, self->rgrip);
1183 XUnmapWindow(plugin.ob_display, self->handle);
1186 if (self->bwidth && !self->max_horz && (self->client_area.height
1187 + self->size.top + self->size.bottom) > theme_config.grip_width
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);
1194 XMapWindow(plugin.ob_display, self->left);
1197 XUnmapWindow(plugin.ob_display, self->left);
1199 if (self->bwidth && !self->max_horz && (self->client_area.height
1200 + self->size.top + self->size.bottom) > theme_config.grip_width
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);
1209 XMapWindow(plugin.ob_display, self->right);
1212 XUnmapWindow(plugin.ob_display, self->right);
1214 XMoveResizeWindow(plugin.ob_display, self->backback, self->size.left,
1215 self->size.top, self->client_area.width,
1216 self->client_area.height);
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));
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);
1234 if (!frame_iconify_animating(self))
1235 /* move and resize the top level frame.
1236 shading can change without being moved or resized.
1238 but don't do this during an iconify animation. it will be
1239 reflected afterwards.
1241 XMoveResizeWindow(plugin.ob_display, self->window, self->area.x,
1242 self->area.y, self->area.width, self->area.height);
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!
1249 XMoveResizeWindow(plugin.ob_display, self->client->window,
1250 self->size.left, self->size.top, self->client_area.width,
1251 self->client_area.height);
1254 self->need_render = TRUE;
1255 frame_update_skin(self);
1256 frame_adjust_shape(self);
1259 if (!STRUT_EQUAL(self->size, oldsize)) {
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,
1267 OBT_PROP_SETA32(self->client->window, KDE_NET_WM_FRAME_STRUT,
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);
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);
1281 void frame_set_hover_flag(gpointer self, ObFrameButton button)
1283 if (OBDEFAULTFRAME(self)->hover_flag != button) {
1284 OBDEFAULTFRAME(self)->hover_flag = button;
1285 frame_update_skin(self);
1289 void frame_set_press_flag(gpointer self, ObFrameButton button)
1291 if (OBDEFAULTFRAME(self)->press_flag != button) {
1292 OBDEFAULTFRAME(self)->press_flag = button;
1293 frame_update_skin(self);
1297 Window frame_get_window(gpointer self)
1299 return OBDEFAULTFRAME(self)->window;
1302 Strut frame_get_size(gpointer self)
1304 return OBDEFAULTFRAME(self)->size;
1307 gint frame_get_decorations(gpointer self)
1309 return OBDEFAULTFRAME(self)->decorations;
1312 gboolean frame_is_visible(gpointer self)
1314 return OBDEFAULTFRAME(self)->visible;
1317 gboolean frame_is_max_horz(gpointer self)
1319 return OBDEFAULTFRAME(self)->max_horz;
1322 gboolean frame_is_max_vert(gpointer self)
1324 return OBDEFAULTFRAME(self)->max_vert;
1327 gulong frame_animate_iconify_time_left(gpointer _self, const GTimeVal *now)
1329 ObDefaultFrame * self = (ObDefaultFrame *) _self;
1331 sec = self->iconify_animation_end.tv_sec - now->tv_sec;
1332 usec = self->iconify_animation_end.tv_usec - now->tv_usec;
1334 usec += G_USEC_PER_SEC;
1337 /* no negative values */
1338 return MAX(sec * G_USEC_PER_SEC + usec, 0);
1341 gboolean frame_animate_iconify(gpointer p)
1343 ObDefaultFrame *self = p;
1345 gint iconx, icony, iconw;
1348 gboolean iconifying;
1350 if (self->client->icon_geometry.width == 0) {
1351 /* there is no icon geometry set so just go straight down */
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;
1360 iconx = self->client->icon_geometry.x;
1361 icony = self->client->icon_geometry.y;
1362 iconw = self->client->icon_geometry.width;
1365 iconifying = self->iconify_animation_going > 0;
1367 /* how far do we have left to go ? */
1368 g_get_current_time(&now);
1369 time = frame_animate_iconify_time_left(self, &now);
1371 if (time == 0 || iconifying) {
1372 /* start where the frame is supposed to be */
1375 w = self->area.width;
1376 h = self->area.height;
1379 /* start at the icon */
1383 h = self->size.top; /* just the titlebar */
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 */
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 */
1408 frame_end_iconify_animation(self);
1410 XMoveResizeWindow(plugin.ob_display, self->window, x, y, w, h);
1411 XFlush(plugin.ob_display);
1414 return time > 0; /* repeat until we're out of time */
1417 void frame_adjust_cursors(gpointer _self)
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;
1429 /* these ones turn off when max vert, and some when shaded */
1430 a.cursor = ob_cursor(r && topbot && !sh ? OB_CURSOR_NORTH
1432 XChangeWindowAttributes(plugin.ob_display, self->topresize, CWCursor,
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,
1439 XChangeWindowAttributes(plugin.ob_display, self->handlebottom,
1441 XChangeWindowAttributes(plugin.ob_display, self->innerbottom, CWCursor,
1444 /* these ones change when shaded */
1445 a.cursor = ob_cursor(r ? (sh ? OB_CURSOR_WEST : OB_CURSOR_NORTHWEST)
1447 XChangeWindowAttributes(plugin.ob_display, self->titleleft, CWCursor,
1449 XChangeWindowAttributes(plugin.ob_display, self->tltresize, CWCursor,
1451 XChangeWindowAttributes(plugin.ob_display, self->tllresize, CWCursor,
1453 XChangeWindowAttributes(plugin.ob_display, self->titletopleft,
1455 a.cursor = ob_cursor(r ? (sh ? OB_CURSOR_EAST : OB_CURSOR_NORTHEAST)
1457 XChangeWindowAttributes(plugin.ob_display, self->titleright, CWCursor,
1459 XChangeWindowAttributes(plugin.ob_display, self->trtresize, CWCursor,
1461 XChangeWindowAttributes(plugin.ob_display, self->trrresize, CWCursor,
1463 XChangeWindowAttributes(plugin.ob_display, self->titletopright,
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,
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,
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,
1479 XChangeWindowAttributes(plugin.ob_display, self->lgripleft, CWCursor,
1481 XChangeWindowAttributes(plugin.ob_display, self->lgriptop, CWCursor, &a);
1482 XChangeWindowAttributes(plugin.ob_display, self->lgripbottom, CWCursor,
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,
1490 XChangeWindowAttributes(plugin.ob_display, self->rgripright, CWCursor,
1492 XChangeWindowAttributes(plugin.ob_display, self->rgriptop, CWCursor, &a);
1493 XChangeWindowAttributes(plugin.ob_display, self->rgripbottom, CWCursor,
1495 XChangeWindowAttributes(plugin.ob_display, self->innerbrr, CWCursor, &a);
1496 XChangeWindowAttributes(plugin.ob_display, self->innerbrb, CWCursor, &a);
1500 void frame_adjust_client_area(gpointer _self)
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);
1508 void frame_adjust_state(gpointer _self)
1510 ObDefaultFrame * self = (ObDefaultFrame *) _self;
1511 self->need_render = TRUE;
1512 frame_update_skin(self);
1515 void frame_adjust_focus(gpointer _self, gboolean hilite)
1517 ObDefaultFrame * self = (ObDefaultFrame *) _self;
1518 self->focused = hilite;
1519 self->need_render = TRUE;
1520 frame_update_skin(self);
1521 XFlush(plugin.ob_display);
1524 void frame_adjust_title(gpointer _self)
1526 ObDefaultFrame * self = (ObDefaultFrame *) _self;
1527 self->need_render = TRUE;
1528 frame_update_skin(self);
1531 void frame_adjust_icon(gpointer _self)
1533 ObDefaultFrame * self = (ObDefaultFrame *) _self;
1534 self->need_render = TRUE;
1535 frame_update_skin(self);
1538 /* is there anything present between us and the label? */
1539 static gboolean is_button_present(ObDefaultFrame *_self, const gchar *lc,
1542 ObDefaultFrame * self = (ObDefaultFrame *) _self;
1543 for (; *lc != '\0' && lc >= plugin.config_title_layout; lc += dir) {
1545 continue; /* it was invalid */
1546 if (*lc == 'N' && self->decorations & OB_FRAME_DECOR_ICON)
1548 if (*lc == 'D' && self->decorations & OB_FRAME_DECOR_ALLDESKTOPS)
1550 if (*lc == 'S' && self->decorations & OB_FRAME_DECOR_SHADE)
1552 if (*lc == 'I' && self->decorations & OB_FRAME_DECOR_ICONIFY)
1554 if (*lc == 'M' && self->decorations & OB_FRAME_DECOR_MAXIMIZE)
1556 if (*lc == 'C' && self->decorations & OB_FRAME_DECOR_CLOSE)
1564 void flash_done(gpointer data)
1566 ObDefaultFrame *self = data;
1568 if (self->focused != self->flash_on)
1569 frame_adjust_focus(self, self->focused);
1572 gboolean flash_timeout(gpointer data)
1574 ObDefaultFrame *self = data;
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;
1583 if (!self->flashing)
1584 return FALSE; /* we are done */
1586 self->flash_on = !self->flash_on;
1587 if (!self->focused) {
1588 frame_adjust_focus(self, self->flash_on);
1589 self->focused = FALSE;
1592 return TRUE; /* go again */
1595 void layout_title(ObDefaultFrame * self)
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;
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;
1612 /* figure out what's being show, find each element's position, and the
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) {
1620 ObFrameContext *firstcon;
1624 lc = plugin.config_title_layout;
1625 firstcon = &self->leftmost;
1629 lc = plugin.config_title_layout
1630 + strlen(plugin.config_title_layout)-1;
1631 firstcon = &self->rightmost;
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) {
1638 self->label_on = TRUE;
1641 break; /* break the for loop, do other side of label */
1643 else if (*lc == 'N') {
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;
1651 x += i * (bwidth + 2);
1656 else if (*lc == 'D') {
1658 *firstcon = OB_FRAME_CONTEXT_ALLDESKTOPS;
1659 if ((self->desk_on = is_button_present(self, lc, i))) {
1660 self->label_width -= bwidth;
1668 else if (*lc == 'S') {
1670 *firstcon = OB_FRAME_CONTEXT_SHADE;
1671 if ((self->shade_on = is_button_present(self, lc, i))) {
1672 self->label_width -= bwidth;
1680 else if (*lc == 'I') {
1682 *firstcon = OB_FRAME_CONTEXT_ICONIFY;
1683 if ((self->iconify_on = is_button_present(self, lc, i))) {
1684 self->label_width -= bwidth;
1686 self->iconify_x = x;
1689 self->iconify_x = x;
1692 else if (*lc == 'M') {
1694 *firstcon = OB_FRAME_CONTEXT_MAXIMIZE;
1695 if ((self->max_on = is_button_present(self, lc, i))) {
1696 self->label_width -= bwidth;
1704 else if (*lc == 'C') {
1706 *firstcon = OB_FRAME_CONTEXT_CLOSE;
1707 if ((self->close_on = is_button_present(self, lc, i))) {
1708 self->label_width -= bwidth;
1717 continue; /* don't set firstcon */
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);
1729 XUnmapWindow(plugin.ob_display, self->icon);
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);
1737 XUnmapWindow(plugin.ob_display, self->desk);
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);
1745 XUnmapWindow(plugin.ob_display, self->shade);
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);
1753 XUnmapWindow(plugin.ob_display, self->iconify);
1756 XMapWindow(plugin.ob_display, self->max);
1757 XMoveWindow(plugin.ob_display, self->max, self->max_x,
1758 theme_config.paddingy + 1);
1761 XUnmapWindow(plugin.ob_display, self->max);
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);
1769 XUnmapWindow(plugin.ob_display, self->close);
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);
1778 XUnmapWindow(plugin.ob_display, self->label);
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) {}
1807 void frame_trigger(gpointer self, ObFrameTrigger trigger_name)
1810 static void (*trigger_func[64])(gpointer) = {
1814 trigger_iconify_toggle,
1817 trigger_shade_toggle,
1820 trigger_max_troggle,
1826 trigger_max_horz_toggle,
1839 void (*call_trigger_func)(gpointer) = trigger_func[trigger_name];
1840 if(!call_trigger_func)
1842 call_trigger_func (self);
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, /* */
1864 frame_flash_start, /* */
1865 frame_flash_stop, /* */
1866 frame_begin_iconify_animation, /* */
1867 frame_end_iconify_animation, /* */
1868 frame_iconify_animating, /* */
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, /* */
1878 frame_set_hover_flag, /* */
1879 frame_set_press_flag, /* */
1881 frame_get_window,/* */
1883 frame_get_size, /* */
1884 frame_get_decorations, /* */
1886 frame_is_visible, /* */
1887 frame_is_max_horz, /* */
1888 frame_is_max_vert, /* */
1890 frame_trigger, /* */
1892 load_theme_config, /* */
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;
1905 ObFramePlugin * get_info()