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->stitle = g_strdup("");
187 self->focused = FALSE;
189 /* the other stuff is shown based on decor settings */
190 XMapWindow(plugin.ob_display, self->label);
191 XMapWindow(plugin.ob_display, self->backback);
192 XMapWindow(plugin.ob_display, self->backfront);
194 self->hover_flag = OB_BUTTON_NONE;
195 self->press_flag = OB_BUTTON_NONE;
197 set_theme_statics(self);
202 void set_theme_statics(gpointer _self)
204 ObDefaultFrame * self = (ObDefaultFrame *) _self;
205 /* set colors/appearance/sizes for stuff that doesn't change */
206 XResizeWindow(plugin.ob_display, self->max, theme_config.button_size,
207 theme_config.button_size);
208 XResizeWindow(plugin.ob_display, self->iconify, theme_config.button_size,
209 theme_config.button_size);
210 XResizeWindow(plugin.ob_display, self->icon, theme_config.button_size + 2,
211 theme_config.button_size + 2);
212 XResizeWindow(plugin.ob_display, self->close, theme_config.button_size,
213 theme_config.button_size);
214 XResizeWindow(plugin.ob_display, self->desk, theme_config.button_size,
215 theme_config.button_size);
216 XResizeWindow(plugin.ob_display, self->shade, theme_config.button_size,
217 theme_config.button_size);
218 XResizeWindow(plugin.ob_display, self->tltresize, theme_config.grip_width,
219 theme_config.paddingy + 1);
220 XResizeWindow(plugin.ob_display, self->trtresize, theme_config.grip_width,
221 theme_config.paddingy + 1);
222 XResizeWindow(plugin.ob_display, self->tllresize,
223 theme_config.paddingx + 1, theme_config.title_height);
224 XResizeWindow(plugin.ob_display, self->trrresize,
225 theme_config.paddingx + 1, theme_config.title_height);
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);
238 void free_theme_statics(gpointer _self)
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);
250 void frame_free(gpointer self)
252 free_theme_statics(OBDEFAULTFRAME(self));
253 XDestroyWindow(plugin.ob_display, OBDEFAULTFRAME(self)->window);
254 if (OBDEFAULTFRAME(self)->colormap)
255 XFreeColormap(plugin.ob_display, OBDEFAULTFRAME(self)->colormap);
257 g_free(OBDEFAULTFRAME(self)->stitle);
261 void frame_show(gpointer _self)
263 ObDefaultFrame * self = (ObDefaultFrame *) _self;
264 if (!self->visible) {
265 self->visible = TRUE;
266 frame_update_skin(self);
267 /* Grab the server to make sure that the frame window is mapped before
268 the client gets its MapNotify, i.e. to make sure the client is
269 _visible_ when it gets MapNotify. */
271 XMapWindow(plugin.ob_display, self->client->window);
272 XMapWindow(plugin.ob_display, self->window);
277 gint frame_hide(gpointer self)
279 if (OBDEFAULTFRAME(self)->visible) {
280 OBDEFAULTFRAME(self)->visible = FALSE;
281 if (!frame_iconify_animating(self))
282 XUnmapWindow(plugin.ob_display, OBDEFAULTFRAME(self)->window);
283 /* we unmap the client itself so that we can get MapRequest
284 events, and because the ICCCM tells us to! */
285 XUnmapWindow(plugin.ob_display, OBDEFAULTFRAME(self)->client->window);
293 void frame_adjust_theme(gpointer self)
295 free_theme_statics(self);
296 set_theme_statics(self);
299 void frame_adjust_shape(gpointer _self)
302 ObDefaultFrame * self = (ObDefaultFrame *) _self;
306 if (!self->client->shaped)
308 /* clear the shape on the frame window */
309 XShapeCombineMask(plugin.ob_display, self->window, ShapeBounding,
316 /* make the frame's shape match the clients */
317 XShapeCombineShape(plugin.ob_display, self->window, ShapeBounding,
320 self->client->window,
321 ShapeBounding, ShapeSet);
324 if (self->decorations & OB_FRAME_DECOR_TITLEBAR)
328 xrect[0].width = self->area.width;
329 xrect[0].height = self->size.top;
333 if (self->decorations & OB_FRAME_DECOR_HANDLE &&
334 theme_config.handle_height> 0)
337 xrect[1].y = FRAME_HANDLE_Y(self);
338 xrect[1].width = self->area.width;
339 xrect[1].height = theme_config.handle_height +
344 XShapeCombineRectangles(plugin.ob_display, self->window,
345 ShapeBounding, 0, 0, xrect, num,
346 ShapeUnion, Unsorted);
351 void frame_grab(gpointer _self, GHashTable * window_map)
353 ObDefaultFrame * self = (ObDefaultFrame *) _self;
354 /* DO NOT map the client window here. we used to do that, but it is bogus.
355 we need to set up the client's dimensions and everything before we
356 send a mapnotify or we create race conditions.
359 /* reparent the client to the frame */
360 XReparentWindow(plugin.ob_display, self->client->window, self->window, 0, 0);
363 When reparenting the client window, it is usually not mapped yet, since
364 this occurs from a MapRequest. However, in the case where Openbox is
365 starting up, the window is already mapped, so we'll see an unmap event
368 if (ob_state() == OB_STATE_STARTING)
369 ++self->client->ignore_unmaps;
371 /* select the event mask on the client's parent (to receive config/map
372 req's) the ButtonPress is to catch clicks on the client border */
373 XSelectInput(plugin.ob_display, self->window, FRAME_EVENTMASK);
375 /* set all the windows for the frame in the window_map */
376 g_hash_table_insert(window_map, &self->window, self->client);
377 g_hash_table_insert(window_map, &self->backback, self->client);
378 g_hash_table_insert(window_map, &self->backfront, self->client);
379 g_hash_table_insert(window_map, &self->innerleft, self->client);
380 g_hash_table_insert(window_map, &self->innertop, self->client);
381 g_hash_table_insert(window_map, &self->innerright, self->client);
382 g_hash_table_insert(window_map, &self->innerbottom, self->client);
383 g_hash_table_insert(window_map, &self->title, self->client);
384 g_hash_table_insert(window_map, &self->label, self->client);
385 g_hash_table_insert(window_map, &self->max, self->client);
386 g_hash_table_insert(window_map, &self->close, self->client);
387 g_hash_table_insert(window_map, &self->desk, self->client);
388 g_hash_table_insert(window_map, &self->shade, self->client);
389 g_hash_table_insert(window_map, &self->icon, self->client);
390 g_hash_table_insert(window_map, &self->iconify, self->client);
391 g_hash_table_insert(window_map, &self->handle, self->client);
392 g_hash_table_insert(window_map, &self->lgrip, self->client);
393 g_hash_table_insert(window_map, &self->rgrip, self->client);
394 g_hash_table_insert(window_map, &self->topresize, self->client);
395 g_hash_table_insert(window_map, &self->tltresize, self->client);
396 g_hash_table_insert(window_map, &self->tllresize, self->client);
397 g_hash_table_insert(window_map, &self->trtresize, self->client);
398 g_hash_table_insert(window_map, &self->trrresize, self->client);
399 g_hash_table_insert(window_map, &self->left, self->client);
400 g_hash_table_insert(window_map, &self->right, self->client);
401 g_hash_table_insert(window_map, &self->titleleft, self->client);
402 g_hash_table_insert(window_map, &self->titletop, self->client);
403 g_hash_table_insert(window_map, &self->titletopleft, self->client);
404 g_hash_table_insert(window_map, &self->titletopright, self->client);
405 g_hash_table_insert(window_map, &self->titleright, self->client);
406 g_hash_table_insert(window_map, &self->titlebottom, self->client);
407 g_hash_table_insert(window_map, &self->handleleft, self->client);
408 g_hash_table_insert(window_map, &self->handletop, self->client);
409 g_hash_table_insert(window_map, &self->handleright, self->client);
410 g_hash_table_insert(window_map, &self->handlebottom, self->client);
411 g_hash_table_insert(window_map, &self->lgripleft, self->client);
412 g_hash_table_insert(window_map, &self->lgriptop, self->client);
413 g_hash_table_insert(window_map, &self->lgripbottom, self->client);
414 g_hash_table_insert(window_map, &self->rgripright, self->client);
415 g_hash_table_insert(window_map, &self->rgriptop, self->client);
416 g_hash_table_insert(window_map, &self->rgripbottom, self->client);
419 void frame_ungrab(gpointer _self, GHashTable * window_map)
421 ObDefaultFrame * self = (ObDefaultFrame *) _self;
423 gboolean reparent = TRUE;
425 /* if there was any animation going on, kill it */
426 obt_main_loop_timeout_remove_data(plugin.ob_main_loop,
427 frame_animate_iconify, self, FALSE);
429 /* check if the app has already reparented its window away */
430 while (XCheckTypedWindowEvent(plugin.ob_display, self->client->window,
431 ReparentNotify, &ev)) {
432 /* This check makes sure we don't catch our own reparent action to
433 our frame window. This doesn't count as the app reparenting itself
436 Reparent events that are generated by us are just discarded here.
437 They are of no consequence to us anyhow.
439 if (ev.xreparent.parent != self->window) {
441 XPutBackEvent(plugin.ob_display, &ev);
447 /* according to the ICCCM - if the client doesn't reparent itself,
448 then we will reparent the window to root for them */
449 XReparentWindow(plugin.ob_display, self->client->window, RootWindow(
450 plugin.ob_display, plugin.ob_screen), self->client_area.x,
451 self->client_area.y);
454 /* remove all the windows for the frame from the window_map */
455 g_hash_table_remove(window_map, &self->window);
456 g_hash_table_remove(window_map, &self->backback);
457 g_hash_table_remove(window_map, &self->backfront);
458 g_hash_table_remove(window_map, &self->innerleft);
459 g_hash_table_remove(window_map, &self->innertop);
460 g_hash_table_remove(window_map, &self->innerright);
461 g_hash_table_remove(window_map, &self->innerbottom);
462 g_hash_table_remove(window_map, &self->title);
463 g_hash_table_remove(window_map, &self->label);
464 g_hash_table_remove(window_map, &self->max);
465 g_hash_table_remove(window_map, &self->close);
466 g_hash_table_remove(window_map, &self->desk);
467 g_hash_table_remove(window_map, &self->shade);
468 g_hash_table_remove(window_map, &self->icon);
469 g_hash_table_remove(window_map, &self->iconify);
470 g_hash_table_remove(window_map, &self->handle);
471 g_hash_table_remove(window_map, &self->lgrip);
472 g_hash_table_remove(window_map, &self->rgrip);
473 g_hash_table_remove(window_map, &self->topresize);
474 g_hash_table_remove(window_map, &self->tltresize);
475 g_hash_table_remove(window_map, &self->tllresize);
476 g_hash_table_remove(window_map, &self->trtresize);
477 g_hash_table_remove(window_map, &self->trrresize);
478 g_hash_table_remove(window_map, &self->left);
479 g_hash_table_remove(window_map, &self->right);
480 g_hash_table_remove(window_map, &self->titleleft);
481 g_hash_table_remove(window_map, &self->titletop);
482 g_hash_table_remove(window_map, &self->titletopleft);
483 g_hash_table_remove(window_map, &self->titletopright);
484 g_hash_table_remove(window_map, &self->titleright);
485 g_hash_table_remove(window_map, &self->titlebottom);
486 g_hash_table_remove(window_map, &self->handleleft);
487 g_hash_table_remove(window_map, &self->handletop);
488 g_hash_table_remove(window_map, &self->handleright);
489 g_hash_table_remove(window_map, &self->handlebottom);
490 g_hash_table_remove(window_map, &self->lgripleft);
491 g_hash_table_remove(window_map, &self->lgriptop);
492 g_hash_table_remove(window_map, &self->lgripbottom);
493 g_hash_table_remove(window_map, &self->rgripright);
494 g_hash_table_remove(window_map, &self->rgriptop);
495 g_hash_table_remove(window_map, &self->rgripbottom);
497 obt_main_loop_timeout_remove_data(plugin.ob_main_loop, flash_timeout, self,
501 ObFrameContext frame_context(gpointer _self, Window win, gint x, gint y)
503 ObDefaultFrame * self = OBDEFAULTFRAME(_self);
505 /* when the user clicks in the corners of the titlebar and the client
506 is fully maximized, then treat it like they clicked in the
507 button that is there */
508 if (self->max_horz && self->max_vert && (win == self->title || win
509 == self->titletop || win == self->titleleft || win
510 == self->titletopleft || win == self->titleright || win
511 == self->titletopright)) {
512 /* get the mouse coords in reference to the whole frame */
516 /* these windows are down a border width from the top of the frame */
517 if (win == self->title || win == self->titleleft || win
521 /* title is a border width in from the edge */
522 if (win == self->title)
524 /* titletop is a bit to the right */
525 else if (win == self->titletop)
526 fx += theme_config.grip_width + self->bwidth;
527 /* titletopright is way to the right edge */
528 else if (win == self->titletopright)
529 fx += self->area.width - (theme_config.grip_width + self->bwidth);
530 /* titleright is even more way to the right edge */
531 else if (win == self->titleright)
532 fx += self->area.width - self->bwidth;
534 /* figure out if we're over the area that should be considered a
536 if (fy < self->bwidth + theme_config.paddingy + 1
537 + theme_config.button_size) {
538 if (fx < (self->bwidth + theme_config.paddingx + 1
539 + theme_config.button_size)) {
540 if (self->leftmost != OB_FRAME_CONTEXT_NONE)
541 return self->leftmost;
543 else if (fx >= (self->area.width - (self->bwidth
544 + theme_config.paddingx + 1 + theme_config.button_size))) {
545 if (self->rightmost != OB_FRAME_CONTEXT_NONE)
546 return self->rightmost;
550 /* there is no resizing maximized windows so make them the titlebar
552 return OB_FRAME_CONTEXT_TITLEBAR;
554 else if (self->max_vert
555 && (win == self->titletop || win == self->topresize))
556 /* can't resize vertically when max vert */
557 return OB_FRAME_CONTEXT_TITLEBAR;
558 else if (self->shaded && (win == self->titletop || win == self->topresize))
559 /* can't resize vertically when shaded */
560 return OB_FRAME_CONTEXT_TITLEBAR;
562 if (win == self->window)
563 return OB_FRAME_CONTEXT_FRAME;
564 if (win == self->label)
565 return OB_FRAME_CONTEXT_TITLEBAR;
566 if (win == self->handle)
567 return OB_FRAME_CONTEXT_BOTTOM;
568 if (win == self->handletop)
569 return OB_FRAME_CONTEXT_BOTTOM;
570 if (win == self->handlebottom)
571 return OB_FRAME_CONTEXT_BOTTOM;
572 if (win == self->handleleft)
573 return OB_FRAME_CONTEXT_BLCORNER;
574 if (win == self->lgrip)
575 return OB_FRAME_CONTEXT_BLCORNER;
576 if (win == self->lgripleft)
577 return OB_FRAME_CONTEXT_BLCORNER;
578 if (win == self->lgriptop)
579 return OB_FRAME_CONTEXT_BLCORNER;
580 if (win == self->lgripbottom)
581 return OB_FRAME_CONTEXT_BLCORNER;
582 if (win == self->handleright)
583 return OB_FRAME_CONTEXT_BRCORNER;
584 if (win == self->rgrip)
585 return OB_FRAME_CONTEXT_BRCORNER;
586 if (win == self->rgripright)
587 return OB_FRAME_CONTEXT_BLCORNER;
588 if (win == self->rgriptop)
589 return OB_FRAME_CONTEXT_BLCORNER;
590 if (win == self->rgripbottom)
591 return OB_FRAME_CONTEXT_BLCORNER;
592 if (win == self->title)
593 return OB_FRAME_CONTEXT_TITLEBAR;
594 if (win == self->titlebottom)
595 return OB_FRAME_CONTEXT_TITLEBAR;
596 if (win == self->titleleft)
597 return OB_FRAME_CONTEXT_TLCORNER;
598 if (win == self->titletopleft)
599 return OB_FRAME_CONTEXT_TLCORNER;
600 if (win == self->titleright)
601 return OB_FRAME_CONTEXT_TRCORNER;
602 if (win == self->titletopright)
603 return OB_FRAME_CONTEXT_TRCORNER;
604 if (win == self->titletop)
605 return OB_FRAME_CONTEXT_TOP;
606 if (win == self->topresize)
607 return OB_FRAME_CONTEXT_TOP;
608 if (win == self->tltresize)
609 return OB_FRAME_CONTEXT_TLCORNER;
610 if (win == self->tllresize)
611 return OB_FRAME_CONTEXT_TLCORNER;
612 if (win == self->trtresize)
613 return OB_FRAME_CONTEXT_TRCORNER;
614 if (win == self->trrresize)
615 return OB_FRAME_CONTEXT_TRCORNER;
616 if (win == self->left)
617 return OB_FRAME_CONTEXT_LEFT;
618 if (win == self->right)
619 return OB_FRAME_CONTEXT_RIGHT;
620 if (win == self->innertop)
621 return OB_FRAME_CONTEXT_TITLEBAR;
622 if (win == self->innerleft)
623 return OB_FRAME_CONTEXT_LEFT;
624 if (win == self->innerbottom)
625 return OB_FRAME_CONTEXT_BOTTOM;
626 if (win == self->innerright)
627 return OB_FRAME_CONTEXT_RIGHT;
628 if (win == self->max)
629 return OB_FRAME_CONTEXT_MAXIMIZE;
630 if (win == self->iconify)
631 return OB_FRAME_CONTEXT_ICONIFY;
632 if (win == self->close)
633 return OB_FRAME_CONTEXT_CLOSE;
634 if (win == self->icon)
635 return OB_FRAME_CONTEXT_ICON;
636 if (win == self->desk)
637 return OB_FRAME_CONTEXT_ALLDESKTOPS;
638 if (win == self->shade)
639 return OB_FRAME_CONTEXT_SHADE;
641 return OB_FRAME_CONTEXT_NONE;
644 void frame_set_is_visible(gpointer self, gboolean b)
646 OBDEFAULTFRAME(self)->visible = b;
649 void frame_set_is_focus(gpointer self, gboolean b)
651 OBDEFAULTFRAME(self)->focused = b;
654 void frame_set_is_max_vert(gpointer self, gboolean b)
656 OBDEFAULTFRAME(self)->max_vert = b;
659 void frame_set_is_max_horz(gpointer self, gboolean b)
661 OBDEFAULTFRAME(self)->max_horz = b;
664 void frame_set_is_shaded(gpointer self, gboolean b)
666 OBDEFAULTFRAME(self)->shaded = b;
669 void frame_unfocus(gpointer self)
671 OBDEFAULTFRAME(self)->focused = FALSE;
674 void frame_flash_start(gpointer _self)
676 ObDefaultFrame * self = (ObDefaultFrame *) _self;
677 self->flash_on = self->focused;
680 obt_main_loop_timeout_add(plugin.ob_main_loop, G_USEC_PER_SEC * 0.6,
681 flash_timeout, self, g_direct_equal, flash_done);
682 g_get_current_time(&self->flash_end);
683 g_time_val_add(&self->flash_end, G_USEC_PER_SEC * 5);
685 self->flashing = TRUE;
688 void frame_flash_stop(gpointer _self)
690 ObDefaultFrame * self = (ObDefaultFrame *) _self;
691 self->flashing = FALSE;
694 void frame_begin_iconify_animation(gpointer _self, gboolean iconifying)
696 ObDefaultFrame * self = (ObDefaultFrame *) _self;
698 gboolean new_anim = FALSE;
699 gboolean set_end = TRUE;
702 /* if there is no titlebar, just don't animate for now
703 XXX it would be nice tho.. */
704 if (!(self->decorations & OB_FRAME_DECOR_TITLEBAR))
707 /* get the current time */
708 g_get_current_time(&now);
710 /* get how long until the end */
711 time = FRAME_ANIMATE_ICONIFY_TIME;
712 if (self->iconify_animation_going) {
713 if (!!iconifying != (self->iconify_animation_going > 0)) {
714 /* animation was already going on in the opposite direction */
715 time = time - frame_animate_iconify_time_left(_self, &now);
718 /* animation was already going in the same direction */
723 self->iconify_animation_going = iconifying ? 1 : -1;
725 /* set the ending time */
727 self->iconify_animation_end.tv_sec = now.tv_sec;
728 self->iconify_animation_end.tv_usec = now.tv_usec;
729 g_time_val_add(&self->iconify_animation_end, time);
733 obt_main_loop_timeout_remove_data(plugin.ob_main_loop,
734 frame_animate_iconify, self, FALSE);
735 obt_main_loop_timeout_add(plugin.ob_main_loop,
736 FRAME_ANIMATE_ICONIFY_STEP_TIME, frame_animate_iconify, self,
737 g_direct_equal, NULL);
739 /* do the first step */
740 frame_animate_iconify(self);
742 /* show it during the animation even if it is not "visible" */
744 XMapWindow(plugin.ob_display, self->window);
748 void frame_end_iconify_animation(gpointer _self)
750 ObDefaultFrame * self = (ObDefaultFrame *) _self;
751 /* see if there is an animation going */
752 if (self->iconify_animation_going == 0)
756 XUnmapWindow(plugin.ob_display, self->window);
758 /* Send a ConfigureNotify when the animation is done, this fixes
759 KDE's pager showing the window in the wrong place. since the
760 window is mapped at a different location and is then moved, we
761 need to send the synthetic configurenotify, since apps may have
762 read the position when the client mapped, apparently. */
763 client_reconfigure(self->client, TRUE);
766 /* we're not animating any more ! */
767 self->iconify_animation_going = 0;
769 XMoveResizeWindow(plugin.ob_display, self->window, self->area.x,
770 self->area.y, self->area.width, self->area.height);
771 /* we delay re-rendering until after we're done animating */
772 frame_update_skin(self);
773 XFlush(plugin.ob_display);
776 gboolean frame_iconify_animating(gpointer _self)
778 ObDefaultFrame * self = (ObDefaultFrame *) _self;
779 return self->iconify_animation_going != 0;
782 void frame_set_decorations(gpointer self, ObFrameDecorations d)
784 OBDEFAULTFRAME(self)->decorations = d;
787 Rect frame_get_window_area(gpointer self)
789 return OBDEFAULTFRAME(self)->area;
791 void frame_set_client_area(gpointer self, Rect r)
793 OBDEFAULTFRAME(self)->client_area = r;
796 void frame_update_layout(gpointer _self, gboolean is_resize, gboolean is_fake)
798 ObDefaultFrame * self = (ObDefaultFrame *) _self;
801 oldsize = self->size;
802 self->area = self->client_area;
804 /* do this before changing the frame's status like max_horz max_vert */
805 frame_adjust_cursors(self);
807 if (self->decorations & OB_FRAME_DECOR_BORDER
808 || (plugin.config_theme_keepborder)) {
809 self->bwidth = theme_config.fbwidth;
815 if (self->decorations & OB_FRAME_DECOR_BORDER) {
816 self->cbwidth_l = theme_config.cbwidthx;
817 self->cbwidth_r = theme_config.cbwidthx;
818 self->cbwidth_t = theme_config.cbwidthy;
819 self->cbwidth_b = theme_config.cbwidthy;
828 if (self->max_horz) {
831 self->width = self->client_area.width;
836 self->width = self->client_area.width + self->cbwidth_l
840 /* some elements are sized based of the width, so don't let them have
842 self->width = MAX(self->width, (theme_config.grip_width + self->bwidth) * 2
845 STRUT_SET(self->size, self->cbwidth_l
846 + (!self->max_horz ? self->bwidth : 0), self->cbwidth_t
847 + self->bwidth, self->cbwidth_r + (!self->max_horz ? self->bwidth
848 : 0), self->cbwidth_b
849 + (!self->max_horz || !self->max_vert ? self->bwidth : 0));
851 if (self->decorations & OB_FRAME_DECOR_TITLEBAR)
852 self->size.top += theme_config.title_height + self->bwidth;
853 if (self->decorations & OB_FRAME_DECOR_HANDLE && theme_config.handle_height
855 self->size.bottom += theme_config.handle_height + self->bwidth;
858 /* position/size and map/unmap all the windows */
860 gint innercornerheight = theme_config.grip_width - self->size.bottom;
862 if (self->cbwidth_l) {
863 XMoveResizeWindow(plugin.ob_display, self->innerleft,
864 self->size.left - self->cbwidth_l, self->size.top,
865 self->cbwidth_l, self->client_area.height);
867 XMapWindow(plugin.ob_display, self->innerleft);
870 XUnmapWindow(plugin.ob_display, self->innerleft);
872 if (self->cbwidth_l && innercornerheight > 0) {
873 XMoveResizeWindow(plugin.ob_display, self->innerbll, 0,
874 self->client_area.height - (theme_config.grip_width
875 - self->size.bottom), self->cbwidth_l,
876 theme_config.grip_width - self->size.bottom);
878 XMapWindow(plugin.ob_display, self->innerbll);
881 XUnmapWindow(plugin.ob_display, self->innerbll);
883 if (self->cbwidth_r) {
884 XMoveResizeWindow(plugin.ob_display, self->innerright,
885 self->size.left + self->client_area.width, self->size.top,
886 self->cbwidth_r, self->client_area.height);
888 XMapWindow(plugin.ob_display, self->innerright);
891 XUnmapWindow(plugin.ob_display, self->innerright);
893 if (self->cbwidth_r && innercornerheight > 0) {
894 XMoveResizeWindow(plugin.ob_display, self->innerbrr, 0,
895 self->client_area.height - (theme_config.grip_width
896 - self->size.bottom), self->cbwidth_r,
897 theme_config.grip_width - self->size.bottom);
899 XMapWindow(plugin.ob_display, self->innerbrr);
902 XUnmapWindow(plugin.ob_display, self->innerbrr);
904 if (self->cbwidth_t) {
905 XMoveResizeWindow(plugin.ob_display, self->innertop,
906 self->size.left - self->cbwidth_l, self->size.top
907 - self->cbwidth_t, self->client_area.width
908 + self->cbwidth_l + self->cbwidth_r,
911 XMapWindow(plugin.ob_display, self->innertop);
914 XUnmapWindow(plugin.ob_display, self->innertop);
916 if (self->cbwidth_b) {
917 XMoveResizeWindow(plugin.ob_display, self->innerbottom,
918 self->size.left - self->cbwidth_l, self->size.top
919 + self->client_area.height, self->client_area.width
920 + self->cbwidth_l + self->cbwidth_r,
923 XMoveResizeWindow(plugin.ob_display, self->innerblb, 0, 0,
924 theme_config.grip_width + self->bwidth, self->cbwidth_b);
925 XMoveResizeWindow(plugin.ob_display, self->innerbrb,
926 self->client_area.width + self->cbwidth_l + self->cbwidth_r
927 - (theme_config.grip_width + self->bwidth), 0,
928 theme_config.grip_width + self->bwidth, self->cbwidth_b);
930 XMapWindow(plugin.ob_display, self->innerbottom);
931 XMapWindow(plugin.ob_display, self->innerblb);
932 XMapWindow(plugin.ob_display, self->innerbrb);
935 XUnmapWindow(plugin.ob_display, self->innerbottom);
936 XUnmapWindow(plugin.ob_display, self->innerblb);
937 XUnmapWindow(plugin.ob_display, self->innerbrb);
943 /* height of titleleft and titleright */
944 titlesides = (!self->max_horz ? theme_config.grip_width : 0);
946 XMoveResizeWindow(plugin.ob_display, self->titletop,
947 theme_config.grip_width + self->bwidth, 0,
948 /* width + bwidth*2 - bwidth*2 - grips*2 */
949 self->width - theme_config.grip_width * 2, self->bwidth);
950 XMoveResizeWindow(plugin.ob_display, self->titletopleft, 0, 0,
951 theme_config.grip_width + self->bwidth, self->bwidth);
952 XMoveResizeWindow(plugin.ob_display, self->titletopright,
953 self->client_area.width + self->size.left
954 + self->size.right - theme_config.grip_width
955 - self->bwidth, 0, theme_config.grip_width
956 + self->bwidth, self->bwidth);
958 if (titlesides > 0) {
959 XMoveResizeWindow(plugin.ob_display, self->titleleft, 0,
960 self->bwidth, self->bwidth, titlesides);
961 XMoveResizeWindow(plugin.ob_display, self->titleright,
962 self->client_area.width + self->size.left
963 + self->size.right - self->bwidth,
964 self->bwidth, self->bwidth, titlesides);
966 XMapWindow(plugin.ob_display, self->titleleft);
967 XMapWindow(plugin.ob_display, self->titleright);
970 XUnmapWindow(plugin.ob_display, self->titleleft);
971 XUnmapWindow(plugin.ob_display, self->titleright);
974 XMapWindow(plugin.ob_display, self->titletop);
975 XMapWindow(plugin.ob_display, self->titletopleft);
976 XMapWindow(plugin.ob_display, self->titletopright);
978 if (self->decorations & OB_FRAME_DECOR_TITLEBAR) {
979 XMoveResizeWindow(plugin.ob_display, self->titlebottom,
980 (self->max_horz ? 0 : self->bwidth),
981 theme_config.title_height + self->bwidth, self->width,
984 XMapWindow(plugin.ob_display, self->titlebottom);
987 XUnmapWindow(plugin.ob_display, self->titlebottom);
990 XUnmapWindow(plugin.ob_display, self->titlebottom);
992 XUnmapWindow(plugin.ob_display, self->titletop);
993 XUnmapWindow(plugin.ob_display, self->titletopleft);
994 XUnmapWindow(plugin.ob_display, self->titletopright);
995 XUnmapWindow(plugin.ob_display, self->titleleft);
996 XUnmapWindow(plugin.ob_display, self->titleright);
999 if (self->decorations & OB_FRAME_DECOR_TITLEBAR) {
1000 XMoveResizeWindow(plugin.ob_display, self->title,
1001 (self->max_horz ? 0 : self->bwidth), self->bwidth,
1002 self->width, theme_config.title_height);
1004 XMapWindow(plugin.ob_display, self->title);
1006 if (self->decorations & OB_FRAME_DECOR_GRIPS) {
1007 XMoveResizeWindow(plugin.ob_display, self->topresize,
1008 theme_config.grip_width, 0, self->width
1009 - theme_config.grip_width *2,
1010 theme_config.paddingy + 1);
1012 XMoveWindow(plugin.ob_display, self->tltresize, 0, 0);
1013 XMoveWindow(plugin.ob_display, self->tllresize, 0, 0);
1014 XMoveWindow(plugin.ob_display, self->trtresize, self->width
1015 - theme_config.grip_width, 0);
1016 XMoveWindow(plugin.ob_display, self->trrresize, self->width
1017 - theme_config.paddingx - 1, 0);
1019 XMapWindow(plugin.ob_display, self->topresize);
1020 XMapWindow(plugin.ob_display, self->tltresize);
1021 XMapWindow(plugin.ob_display, self->tllresize);
1022 XMapWindow(plugin.ob_display, self->trtresize);
1023 XMapWindow(plugin.ob_display, self->trrresize);
1026 XUnmapWindow(plugin.ob_display, self->topresize);
1027 XUnmapWindow(plugin.ob_display, self->tltresize);
1028 XUnmapWindow(plugin.ob_display, self->tllresize);
1029 XUnmapWindow(plugin.ob_display, self->trtresize);
1030 XUnmapWindow(plugin.ob_display, self->trrresize);
1034 XUnmapWindow(plugin.ob_display, self->title);
1037 if ((self->decorations & OB_FRAME_DECOR_TITLEBAR))
1038 /* layout the title bar elements */
1042 gint sidebwidth = self->max_horz ? 0 : self->bwidth;
1044 if (self->bwidth && self->size.bottom) {
1045 XMoveResizeWindow(plugin.ob_display, self->handlebottom,
1046 theme_config.grip_width + self->bwidth + sidebwidth,
1047 self->size.top + self->client_area.height
1048 + self->size.bottom - self->bwidth, self->width
1049 - (theme_config.grip_width + sidebwidth) * 2,
1053 XMoveResizeWindow(plugin.ob_display, self->lgripleft, 0,
1054 self->size.top + self->client_area.height
1056 - (!self->max_horz ? theme_config.grip_width
1057 : self->size.bottom - self->cbwidth_b),
1059 (!self->max_horz ? theme_config.grip_width
1060 : self->size.bottom - self->cbwidth_b));
1061 XMoveResizeWindow(plugin.ob_display, self->rgripright,
1062 self->size.left + self->client_area.width
1063 + self->size.right - self->bwidth,
1064 self->size.top + self->client_area.height
1066 - (!self->max_horz ? theme_config.grip_width
1067 : self->size.bottom - self->cbwidth_b),
1069 (!self->max_horz ? theme_config.grip_width
1070 : self->size.bottom - self->cbwidth_b));
1072 XMapWindow(plugin.ob_display, self->lgripleft);
1073 XMapWindow(plugin.ob_display, self->rgripright);
1076 XUnmapWindow(plugin.ob_display, self->lgripleft);
1077 XUnmapWindow(plugin.ob_display, self->rgripright);
1080 XMoveResizeWindow(plugin.ob_display, self->lgripbottom, sidebwidth,
1081 self->size.top + self->client_area.height
1082 + self->size.bottom - self->bwidth,
1083 theme_config.grip_width + self->bwidth, self->bwidth);
1084 XMoveResizeWindow(plugin.ob_display, self->rgripbottom,
1085 self->size.left + self->client_area.width
1086 + self->size.right - self->bwidth - sidebwidth
1087 - theme_config.grip_width, self->size.top
1088 + self->client_area.height + self->size.bottom
1089 - self->bwidth, theme_config.grip_width
1090 + self->bwidth, self->bwidth);
1092 XMapWindow(plugin.ob_display, self->handlebottom);
1093 XMapWindow(plugin.ob_display, self->lgripbottom);
1094 XMapWindow(plugin.ob_display, self->rgripbottom);
1096 if (self->decorations & OB_FRAME_DECOR_HANDLE
1097 && theme_config.handle_height > 0) {
1098 XMoveResizeWindow(plugin.ob_display, self->handletop,
1099 theme_config.grip_width + self->bwidth + sidebwidth,
1100 FRAME_HANDLE_Y(self), self->width - (theme_config.grip_width
1101 + sidebwidth) * 2, self->bwidth);
1102 XMapWindow(plugin.ob_display, self->handletop);
1104 if (self->decorations & OB_FRAME_DECOR_GRIPS) {
1105 XMoveResizeWindow(plugin.ob_display, self->handleleft,
1106 theme_config.grip_width, 0, self->bwidth,
1107 theme_config.handle_height);
1108 XMoveResizeWindow(plugin.ob_display, self->handleright,
1109 self->width - theme_config.grip_width
1110 - self->bwidth, 0, self->bwidth,
1111 theme_config.handle_height);
1113 XMoveResizeWindow(plugin.ob_display, self->lgriptop,
1115 FRAME_HANDLE_Y(self), theme_config.grip_width
1116 + self->bwidth, self->bwidth);
1117 XMoveResizeWindow(plugin.ob_display, self->rgriptop,
1118 self->size.left + self->client_area.width
1119 + self->size.right - self->bwidth
1120 - sidebwidth - theme_config.grip_width,
1121 FRAME_HANDLE_Y(self), theme_config.grip_width
1122 + self->bwidth, self->bwidth);
1124 XMapWindow(plugin.ob_display, self->handleleft);
1125 XMapWindow(plugin.ob_display, self->handleright);
1126 XMapWindow(plugin.ob_display, self->lgriptop);
1127 XMapWindow(plugin.ob_display, self->rgriptop);
1130 XUnmapWindow(plugin.ob_display, self->handleleft);
1131 XUnmapWindow(plugin.ob_display, self->handleright);
1132 XUnmapWindow(plugin.ob_display, self->lgriptop);
1133 XUnmapWindow(plugin.ob_display, self->rgriptop);
1137 XUnmapWindow(plugin.ob_display, self->handleleft);
1138 XUnmapWindow(plugin.ob_display, self->handleright);
1139 XUnmapWindow(plugin.ob_display, self->lgriptop);
1140 XUnmapWindow(plugin.ob_display, self->rgriptop);
1142 XUnmapWindow(plugin.ob_display, self->handletop);
1146 XUnmapWindow(plugin.ob_display, self->handleleft);
1147 XUnmapWindow(plugin.ob_display, self->handleright);
1148 XUnmapWindow(plugin.ob_display, self->lgriptop);
1149 XUnmapWindow(plugin.ob_display, self->rgriptop);
1151 XUnmapWindow(plugin.ob_display, self->handletop);
1153 XUnmapWindow(plugin.ob_display, self->handlebottom);
1154 XUnmapWindow(plugin.ob_display, self->lgripleft);
1155 XUnmapWindow(plugin.ob_display, self->rgripright);
1156 XUnmapWindow(plugin.ob_display, self->lgripbottom);
1157 XUnmapWindow(plugin.ob_display, self->rgripbottom);
1160 if (self->decorations & OB_FRAME_DECOR_HANDLE
1161 && theme_config.handle_height > 0) {
1162 XMoveResizeWindow(plugin.ob_display, self->handle, sidebwidth,
1163 FRAME_HANDLE_Y(self) + self->bwidth, self->width,
1164 theme_config.handle_height);
1165 XMapWindow(plugin.ob_display, self->handle);
1167 if (self->decorations & OB_FRAME_DECOR_GRIPS) {
1168 XMoveResizeWindow(plugin.ob_display, self->lgrip, 0, 0,
1169 theme_config.grip_width, theme_config.handle_height);
1170 XMoveResizeWindow(plugin.ob_display, self->rgrip, self->width
1171 - theme_config.grip_width, 0, theme_config.grip_width,
1172 theme_config.handle_height);
1174 XMapWindow(plugin.ob_display, self->lgrip);
1175 XMapWindow(plugin.ob_display, self->rgrip);
1178 XUnmapWindow(plugin.ob_display, self->lgrip);
1179 XUnmapWindow(plugin.ob_display, self->rgrip);
1183 XUnmapWindow(plugin.ob_display, self->lgrip);
1184 XUnmapWindow(plugin.ob_display, self->rgrip);
1186 XUnmapWindow(plugin.ob_display, self->handle);
1189 if (self->bwidth && !self->max_horz && (self->client_area.height
1190 + self->size.top + self->size.bottom) > theme_config.grip_width
1192 XMoveResizeWindow(plugin.ob_display, self->left, 0, self->bwidth
1193 + theme_config.grip_width, self->bwidth,
1194 self->client_area.height + self->size.top
1195 + self->size.bottom - theme_config.grip_width * 2);
1197 XMapWindow(plugin.ob_display, self->left);
1200 XUnmapWindow(plugin.ob_display, self->left);
1202 if (self->bwidth && !self->max_horz && (self->client_area.height
1203 + self->size.top + self->size.bottom) > theme_config.grip_width
1205 XMoveResizeWindow(plugin.ob_display, self->right,
1206 self->client_area.width + self->cbwidth_l + self->cbwidth_r
1207 + self->bwidth, self->bwidth
1208 + theme_config.grip_width, self->bwidth,
1209 self->client_area.height + self->size.top
1210 + self->size.bottom - theme_config.grip_width * 2);
1212 XMapWindow(plugin.ob_display, self->right);
1215 XUnmapWindow(plugin.ob_display, self->right);
1217 XMoveResizeWindow(plugin.ob_display, self->backback, self->size.left,
1218 self->size.top, self->client_area.width,
1219 self->client_area.height);
1222 /* shading can change without being moved or resized */
1223 RECT_SET_SIZE(self->area, self->client_area.width + self->size.left
1224 + self->size.right, (self->shaded ? theme_config.title_height
1225 + self->bwidth * 2 : self->client_area.height + self->size.top
1226 + self->size.bottom));
1228 if ((is_resize) && !is_fake) {
1229 /* find the new coordinates, done after setting the frame.size, for
1230 frame_client_gravity. */
1231 self->area.x = self->client_area.x;
1232 self->area.y = self->client_area.y;
1233 frame_client_gravity(OBDEFAULTFRAME(_self)->client, &self->area.x, &self->area.y);
1237 if (!frame_iconify_animating(self))
1238 /* move and resize the top level frame.
1239 shading can change without being moved or resized.
1241 but don't do this during an iconify animation. it will be
1242 reflected afterwards.
1244 XMoveResizeWindow(plugin.ob_display, self->window, self->area.x,
1245 self->area.y, self->area.width, self->area.height);
1247 /* when the client has StaticGravity, it likes to move around.
1248 also this correctly positions the client when it maps.
1249 this also needs to be run when the frame's decorations sizes change!
1252 XMoveResizeWindow(plugin.ob_display, self->client->window,
1253 self->size.left, self->size.top, self->client_area.width,
1254 self->client_area.height);
1257 self->need_render = TRUE;
1258 frame_update_skin(self);
1259 frame_adjust_shape(self);
1262 if (!STRUT_EQUAL(self->size, oldsize)) {
1264 vals[0] = self->size.left;
1265 vals[1] = self->size.right;
1266 vals[2] = self->size.top;
1267 vals[3] = self->size.bottom;
1268 OBT_PROP_SETA32(self->client->window, NET_FRAME_EXTENTS, CARDINAL,
1270 OBT_PROP_SETA32(self->client->window, KDE_NET_WM_FRAME_STRUT,
1274 /* if this occurs while we are focus cycling, the indicator needs to
1275 match the changes */
1276 if (plugin.focus_cycle_target == self->client)
1277 focus_cycle_draw_indicator(self->client);
1279 if (is_resize && (self->decorations & OB_FRAME_DECOR_TITLEBAR))
1280 XResizeWindow(plugin.ob_display, self->label, self->label_width,
1281 theme_config.label_height);
1284 void frame_set_hover_flag(gpointer self, ObFrameButton button)
1286 if (OBDEFAULTFRAME(self)->hover_flag != button) {
1287 OBDEFAULTFRAME(self)->hover_flag = button;
1288 frame_update_skin(self);
1292 void frame_set_press_flag(gpointer self, ObFrameButton button)
1294 if (OBDEFAULTFRAME(self)->press_flag != button) {
1295 OBDEFAULTFRAME(self)->press_flag = button;
1296 frame_update_skin(self);
1300 Window frame_get_window(gpointer self)
1302 return OBDEFAULTFRAME(self)->window;
1305 Strut frame_get_size(gpointer self)
1307 return OBDEFAULTFRAME(self)->size;
1310 gint frame_get_decorations(gpointer self)
1312 return OBDEFAULTFRAME(self)->decorations;
1315 void frame_update_title (gpointer self, const gchar * src)
1317 g_free(OBDEFAULTFRAME(self)->stitle);
1318 OBDEFAULTFRAME(self)->stitle = g_strdup(src);
1321 gboolean frame_is_visible(gpointer self)
1323 return OBDEFAULTFRAME(self)->visible;
1326 gboolean frame_is_max_horz(gpointer self)
1328 return OBDEFAULTFRAME(self)->max_horz;
1331 gboolean frame_is_max_vert(gpointer self)
1333 return OBDEFAULTFRAME(self)->max_vert;
1336 gulong frame_animate_iconify_time_left(gpointer _self, const GTimeVal *now)
1338 ObDefaultFrame * self = (ObDefaultFrame *) _self;
1340 sec = self->iconify_animation_end.tv_sec - now->tv_sec;
1341 usec = self->iconify_animation_end.tv_usec - now->tv_usec;
1343 usec += G_USEC_PER_SEC;
1346 /* no negative values */
1347 return MAX(sec * G_USEC_PER_SEC + usec, 0);
1350 gboolean frame_animate_iconify(gpointer p)
1352 ObDefaultFrame *self = p;
1354 gint iconx, icony, iconw;
1357 gboolean iconifying;
1359 if (self->client->icon_geometry.width == 0) {
1360 /* there is no icon geometry set so just go straight down */
1362 screen_physical_area_monitor(screen_find_monitor(&self->area));
1363 iconx = self->area.x + self->area.width / 2 + 32;
1364 icony = a->y + a->width;
1369 iconx = self->client->icon_geometry.x;
1370 icony = self->client->icon_geometry.y;
1371 iconw = self->client->icon_geometry.width;
1374 iconifying = self->iconify_animation_going > 0;
1376 /* how far do we have left to go ? */
1377 g_get_current_time(&now);
1378 time = frame_animate_iconify_time_left(self, &now);
1380 if (time == 0 || iconifying) {
1381 /* start where the frame is supposed to be */
1384 w = self->area.width;
1385 h = self->area.height;
1388 /* start at the icon */
1392 h = self->size.top; /* just the titlebar */
1399 dx = self->area.x - iconx;
1400 dy = self->area.y - icony;
1401 dw = self->area.width - self->bwidth * 2 - iconw;
1402 /* if restoring, we move in the opposite direction */
1409 elapsed = FRAME_ANIMATE_ICONIFY_TIME - time;
1410 x = x - (dx * elapsed) / FRAME_ANIMATE_ICONIFY_TIME;
1411 y = y - (dy * elapsed) / FRAME_ANIMATE_ICONIFY_TIME;
1412 w = w - (dw * elapsed) / FRAME_ANIMATE_ICONIFY_TIME;
1413 h = self->size.top; /* just the titlebar */
1417 frame_end_iconify_animation(self);
1419 XMoveResizeWindow(plugin.ob_display, self->window, x, y, w, h);
1420 XFlush(plugin.ob_display);
1423 return time > 0; /* repeat until we're out of time */
1426 void frame_adjust_cursors(gpointer _self)
1428 ObDefaultFrame * self = (ObDefaultFrame *) _self;
1429 if ((self->functions & OB_CLIENT_FUNC_RESIZE) != (self->functions
1430 & OB_CLIENT_FUNC_RESIZE) || self->max_horz != self->max_horz
1431 || self->max_vert != self->max_vert || self->shaded != self->shaded) {
1432 gboolean r = (self->functions & OB_CLIENT_FUNC_RESIZE)
1433 && !(self->max_horz && self->max_vert);
1434 gboolean topbot = !self->max_vert;
1435 gboolean sh = self->shaded;
1436 XSetWindowAttributes a;
1438 /* these ones turn off when max vert, and some when shaded */
1439 a.cursor = ob_cursor(r && topbot && !sh ? OB_CURSOR_NORTH
1441 XChangeWindowAttributes(plugin.ob_display, self->topresize, CWCursor,
1443 XChangeWindowAttributes(plugin.ob_display, self->titletop, CWCursor, &a);
1444 a.cursor = ob_cursor(r && topbot ? OB_CURSOR_SOUTH : OB_CURSOR_NONE);
1445 XChangeWindowAttributes(plugin.ob_display, self->handle, CWCursor, &a);
1446 XChangeWindowAttributes(plugin.ob_display, self->handletop, CWCursor,
1448 XChangeWindowAttributes(plugin.ob_display, self->handlebottom,
1450 XChangeWindowAttributes(plugin.ob_display, self->innerbottom, CWCursor,
1453 /* these ones change when shaded */
1454 a.cursor = ob_cursor(r ? (sh ? OB_CURSOR_WEST : OB_CURSOR_NORTHWEST)
1456 XChangeWindowAttributes(plugin.ob_display, self->titleleft, CWCursor,
1458 XChangeWindowAttributes(plugin.ob_display, self->tltresize, CWCursor,
1460 XChangeWindowAttributes(plugin.ob_display, self->tllresize, CWCursor,
1462 XChangeWindowAttributes(plugin.ob_display, self->titletopleft,
1464 a.cursor = ob_cursor(r ? (sh ? OB_CURSOR_EAST : OB_CURSOR_NORTHEAST)
1466 XChangeWindowAttributes(plugin.ob_display, self->titleright, CWCursor,
1468 XChangeWindowAttributes(plugin.ob_display, self->trtresize, CWCursor,
1470 XChangeWindowAttributes(plugin.ob_display, self->trrresize, CWCursor,
1472 XChangeWindowAttributes(plugin.ob_display, self->titletopright,
1475 /* these ones are pretty static */
1476 a.cursor = ob_cursor(r ? OB_CURSOR_WEST : OB_CURSOR_NONE);
1477 XChangeWindowAttributes(plugin.ob_display, self->left, CWCursor, &a);
1478 XChangeWindowAttributes(plugin.ob_display, self->innerleft, CWCursor,
1480 a.cursor = ob_cursor(r ? OB_CURSOR_EAST : OB_CURSOR_NONE);
1481 XChangeWindowAttributes(plugin.ob_display, self->right, CWCursor, &a);
1482 XChangeWindowAttributes(plugin.ob_display, self->innerright, CWCursor,
1484 a.cursor = ob_cursor(r ? OB_CURSOR_SOUTHWEST : OB_CURSOR_NONE);
1485 XChangeWindowAttributes(plugin.ob_display, self->lgrip, CWCursor, &a);
1486 XChangeWindowAttributes(plugin.ob_display, self->handleleft, CWCursor,
1488 XChangeWindowAttributes(plugin.ob_display, self->lgripleft, CWCursor,
1490 XChangeWindowAttributes(plugin.ob_display, self->lgriptop, CWCursor, &a);
1491 XChangeWindowAttributes(plugin.ob_display, self->lgripbottom, CWCursor,
1493 XChangeWindowAttributes(plugin.ob_display, self->innerbll, CWCursor, &a);
1494 XChangeWindowAttributes(plugin.ob_display, self->innerblb, CWCursor, &a);
1495 a.cursor = ob_cursor(r ? OB_CURSOR_SOUTHEAST : OB_CURSOR_NONE);
1496 XChangeWindowAttributes(plugin.ob_display, self->rgrip, CWCursor, &a);
1497 XChangeWindowAttributes(plugin.ob_display, self->handleright, CWCursor,
1499 XChangeWindowAttributes(plugin.ob_display, self->rgripright, CWCursor,
1501 XChangeWindowAttributes(plugin.ob_display, self->rgriptop, CWCursor, &a);
1502 XChangeWindowAttributes(plugin.ob_display, self->rgripbottom, CWCursor,
1504 XChangeWindowAttributes(plugin.ob_display, self->innerbrr, CWCursor, &a);
1505 XChangeWindowAttributes(plugin.ob_display, self->innerbrb, CWCursor, &a);
1509 void frame_adjust_client_area(gpointer _self)
1511 ObDefaultFrame * self = (ObDefaultFrame *) _self;
1512 /* adjust the window which is there to prevent flashing on unmap */
1513 XMoveResizeWindow(plugin.ob_display, self->backfront, 0, 0,
1514 self->client_area.width, self->client_area.height);
1517 void frame_adjust_state(gpointer _self)
1519 ObDefaultFrame * self = (ObDefaultFrame *) _self;
1520 self->need_render = TRUE;
1521 frame_update_skin(self);
1524 void frame_adjust_focus(gpointer _self, gboolean hilite)
1526 ObDefaultFrame * self = (ObDefaultFrame *) _self;
1527 self->focused = hilite;
1528 self->need_render = TRUE;
1529 frame_update_skin(self);
1530 XFlush(plugin.ob_display);
1533 void frame_adjust_title(gpointer _self)
1535 ObDefaultFrame * self = (ObDefaultFrame *) _self;
1536 self->need_render = TRUE;
1537 frame_update_skin(self);
1540 void frame_adjust_icon(gpointer _self)
1542 ObDefaultFrame * self = (ObDefaultFrame *) _self;
1543 self->need_render = TRUE;
1544 frame_update_skin(self);
1547 /* is there anything present between us and the label? */
1548 static gboolean is_button_present(ObDefaultFrame *_self, const gchar *lc,
1551 ObDefaultFrame * self = (ObDefaultFrame *) _self;
1552 for (; *lc != '\0' && lc >= plugin.config_title_layout; lc += dir) {
1554 continue; /* it was invalid */
1555 if (*lc == 'N' && self->decorations & OB_FRAME_DECOR_ICON)
1557 if (*lc == 'D' && self->decorations & OB_FRAME_DECOR_ALLDESKTOPS)
1559 if (*lc == 'S' && self->decorations & OB_FRAME_DECOR_SHADE)
1561 if (*lc == 'I' && self->decorations & OB_FRAME_DECOR_ICONIFY)
1563 if (*lc == 'M' && self->decorations & OB_FRAME_DECOR_MAXIMIZE)
1565 if (*lc == 'C' && self->decorations & OB_FRAME_DECOR_CLOSE)
1573 void flash_done(gpointer data)
1575 ObDefaultFrame *self = data;
1577 if (self->focused != self->flash_on)
1578 frame_adjust_focus(self, self->focused);
1581 gboolean flash_timeout(gpointer data)
1583 ObDefaultFrame *self = data;
1586 g_get_current_time(&now);
1587 if (now.tv_sec > self->flash_end.tv_sec
1588 || (now.tv_sec == self->flash_end.tv_sec && now.tv_usec
1589 >= self->flash_end.tv_usec))
1590 self->flashing = FALSE;
1592 if (!self->flashing)
1593 return FALSE; /* we are done */
1595 self->flash_on = !self->flash_on;
1596 if (!self->focused) {
1597 frame_adjust_focus(self, self->flash_on);
1598 self->focused = FALSE;
1601 return TRUE; /* go again */
1604 void layout_title(ObDefaultFrame * self)
1609 const gint bwidth = theme_config.button_size + theme_config.paddingx + 1;
1610 /* position of the left most button */
1611 const gint left = theme_config.paddingx + 1;
1612 /* position of the right most button */
1613 const gint right = self->width;
1615 /* turn them all off */
1616 self->icon_on = self->desk_on = self->shade_on = self->iconify_on
1617 = self->max_on = self->close_on = self->label_on = FALSE;
1618 self->label_width = self->width - (theme_config.paddingx + 1) * 2;
1619 self->leftmost = self->rightmost = OB_FRAME_CONTEXT_NONE;
1621 /* figure out what's being show, find each element's position, and the
1624 do the ones before the label, then after the label,
1625 i will be +1 the first time through when working to the left,
1626 and -1 the second time through when working to the right */
1627 for (i = 1; i >= -1; i-=2) {
1629 ObFrameContext *firstcon;
1633 lc = plugin.config_title_layout;
1634 firstcon = &self->leftmost;
1638 lc = plugin.config_title_layout
1639 + strlen(plugin.config_title_layout)-1;
1640 firstcon = &self->rightmost;
1643 /* stop at the end of the string (or the label, which calls break) */
1644 for (; *lc != '\0' && lc >= plugin.config_title_layout; lc+=i) {
1647 self->label_on = TRUE;
1650 break; /* break the for loop, do other side of label */
1652 else if (*lc == 'N') {
1654 *firstcon = OB_FRAME_CONTEXT_ICON;
1655 if ((self->icon_on = is_button_present(self, lc, i))) {
1656 /* icon is bigger than buttons */
1657 self->label_width -= bwidth + 2;
1660 x += i * (bwidth + 2);
1665 else if (*lc == 'D') {
1667 *firstcon = OB_FRAME_CONTEXT_ALLDESKTOPS;
1668 if ((self->desk_on = is_button_present(self, lc, i))) {
1669 self->label_width -= bwidth;
1677 else if (*lc == 'S') {
1679 *firstcon = OB_FRAME_CONTEXT_SHADE;
1680 if ((self->shade_on = is_button_present(self, lc, i))) {
1681 self->label_width -= bwidth;
1689 else if (*lc == 'I') {
1691 *firstcon = OB_FRAME_CONTEXT_ICONIFY;
1692 if ((self->iconify_on = is_button_present(self, lc, i))) {
1693 self->label_width -= bwidth;
1695 self->iconify_x = x;
1698 self->iconify_x = x;
1701 else if (*lc == 'M') {
1703 *firstcon = OB_FRAME_CONTEXT_MAXIMIZE;
1704 if ((self->max_on = is_button_present(self, lc, i))) {
1705 self->label_width -= bwidth;
1713 else if (*lc == 'C') {
1715 *firstcon = OB_FRAME_CONTEXT_CLOSE;
1716 if ((self->close_on = is_button_present(self, lc, i))) {
1717 self->label_width -= bwidth;
1726 continue; /* don't set firstcon */
1731 /* position and map the elements */
1732 if (self->icon_on) {
1733 XMapWindow(plugin.ob_display, self->icon);
1734 XMoveWindow(plugin.ob_display, self->icon, self->icon_x,
1735 theme_config.paddingy);
1738 XUnmapWindow(plugin.ob_display, self->icon);
1740 if (self->desk_on) {
1741 XMapWindow(plugin.ob_display, self->desk);
1742 XMoveWindow(plugin.ob_display, self->desk, self->desk_x,
1743 theme_config.paddingy + 1);
1746 XUnmapWindow(plugin.ob_display, self->desk);
1748 if (self->shade_on) {
1749 XMapWindow(plugin.ob_display, self->shade);
1750 XMoveWindow(plugin.ob_display, self->shade, self->shade_x,
1751 theme_config.paddingy + 1);
1754 XUnmapWindow(plugin.ob_display, self->shade);
1756 if (self->iconify_on) {
1757 XMapWindow(plugin.ob_display, self->iconify);
1758 XMoveWindow(plugin.ob_display, self->iconify, self->iconify_x,
1759 theme_config.paddingy + 1);
1762 XUnmapWindow(plugin.ob_display, self->iconify);
1765 XMapWindow(plugin.ob_display, self->max);
1766 XMoveWindow(plugin.ob_display, self->max, self->max_x,
1767 theme_config.paddingy + 1);
1770 XUnmapWindow(plugin.ob_display, self->max);
1772 if (self->close_on) {
1773 XMapWindow(plugin.ob_display, self->close);
1774 XMoveWindow(plugin.ob_display, self->close, self->close_x,
1775 theme_config.paddingy + 1);
1778 XUnmapWindow(plugin.ob_display, self->close);
1780 if (self->label_on) {
1781 self->label_width = MAX(1, self->label_width); /* no lower than 1 */
1782 XMapWindow(plugin.ob_display, self->label);
1783 XMoveWindow(plugin.ob_display, self->label, self->label_x,
1784 theme_config.paddingy);
1787 XUnmapWindow(plugin.ob_display, self->label);
1790 void trigger_none (gpointer self) {}
1791 void trigger_iconify(gpointer self) {}
1792 void trigger_uniconnity(gpointer self) {}
1793 void trigger_iconify_toggle(gpointer self) {}
1794 void trigger_shade(gpointer self) {}
1795 void trigger_unshade(gpointer self) {}
1796 void trigger_shade_toggle(gpointer self) {}
1797 void trigger_max(gpointer self) {}
1798 void trigger_unmax(gpointer self) {}
1799 void trigger_max_troggle(gpointer self) {}
1800 void trigger_max_vert(gpointer self) {OBDEFAULTFRAME(self)->max_vert = TRUE;}
1801 void trigger_unmax_vert(gpointer self) {OBDEFAULTFRAME(self)->max_vert = FALSE;}
1802 void trigger_max_toggle(gpointer self) {}
1803 void trigger_max_horz(gpointer self) {OBDEFAULTFRAME(self)->max_horz = TRUE;}
1804 void trigger_unmax_horz(gpointer self) {OBDEFAULTFRAME(self)->max_horz = FALSE;}
1805 void trigger_max_horz_toggle(gpointer self) {}
1806 void trigger_plugin1(gpointer self) {}
1807 void trigger_plugin2(gpointer self) {}
1808 void trigger_plugin3(gpointer self) {}
1809 void trigger_plugin4(gpointer self) {}
1810 void trigger_plugin5(gpointer self) {}
1811 void trigger_plugin6(gpointer self) {}
1812 void trigger_plugin7(gpointer self) {}
1813 void trigger_plugin8(gpointer self) {}
1814 void trigger_plugin9(gpointer self) {}
1816 void frame_trigger(gpointer self, ObFrameTrigger trigger_name)
1819 static void (*trigger_func[64])(gpointer) = {
1823 trigger_iconify_toggle,
1826 trigger_shade_toggle,
1829 trigger_max_troggle,
1835 trigger_max_horz_toggle,
1848 void (*call_trigger_func)(gpointer) = trigger_func[trigger_name];
1849 if(!call_trigger_func)
1851 call_trigger_func (self);
1855 ObFramePlugin plugin = { 0, //gpointer handler;
1856 "libdefault.la", //gchar * filename;
1857 "Default", //gchar * name;
1858 init, //gint (*init) (Display * display, gint screen);
1860 frame_new, //gpointer (*frame_new) (struct _ObClient *c);
1861 frame_free, //void (*frame_free) (gpointer self);
1862 frame_show, //void (*frame_show) (gpointer self);
1863 frame_hide, //void (*frame_hide) (gpointer self);
1864 frame_adjust_theme, //void (*frame_adjust_theme) (gpointer self);
1865 frame_adjust_shape, //void (*frame_adjust_shape) (gpointer self);
1866 frame_grab, //void (*frame_adjust_area) (gpointer self, gboolean moved, gboolean resized, gboolean fake);
1867 frame_ungrab, frame_context, //void (*frame_adjust_state) (gpointer self);
1868 frame_set_is_visible, /* */
1869 frame_set_is_focus, /* */
1870 frame_set_is_max_vert, /* */
1871 frame_set_is_max_horz, /* */
1872 frame_set_is_shaded, /* */
1874 frame_flash_start, /* */
1875 frame_flash_stop, /* */
1876 frame_begin_iconify_animation, /* */
1877 frame_end_iconify_animation, /* */
1878 frame_iconify_animating, /* */
1880 frame_set_decorations, /* */
1882 frame_update_title, /* */
1883 /* This give the window area */
1884 frame_get_window_area, /* */
1885 frame_set_client_area, /* */
1886 /* Draw the frame */
1887 frame_update_layout, /* */
1888 frame_update_skin, /* */
1890 frame_set_hover_flag, /* */
1891 frame_set_press_flag, /* */
1893 frame_get_window,/* */
1895 frame_get_size, /* */
1896 frame_get_decorations, /* */
1898 frame_is_visible, /* */
1899 frame_is_max_horz, /* */
1900 frame_is_max_vert, /* */
1902 frame_trigger, /* */
1904 load_theme_config, /* */
1906 /* This fields are fill by openbox. */
1907 0, //Display * ob_display;
1908 0, //gint ob_screen;
1909 0, //RrInstance *ob_rr_inst;
1910 0, //gboolean config_theme_keepborder;
1911 0, //struct _ObClient *focus_cycle_target;
1912 0, //gchar *config_title_layout;
1913 FALSE, //gboolean moveresize_in_progress;
1914 0, //struct _ObMainLoop *ob_main_loop;
1917 ObFramePlugin * get_info()