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.
23 /* Needed for the _() function */
27 #include "openbox/screen.h"
29 /* Needed for the grab_server */
30 #include "openbox/grab.h"
32 #include <X11/extensions/shape.h>
37 OB_FLAG_CLOSE = 1 << 1,
38 OB_FLAG_DESK = 1 << 2,
39 OB_FLAG_SHADE = 1 << 3,
40 OB_FLAG_ICONIFY = 1 << 4
43 #define FRAME_EVENTMASK (EnterWindowMask | LeaveWindowMask | \
44 ButtonPressMask | ButtonReleaseMask | \
45 SubstructureRedirectMask | FocusChangeMask)
46 #define ELEMENT_EVENTMASK (ButtonPressMask | ButtonReleaseMask | \
47 ButtonMotionMask | PointerMotionMask | \
48 EnterWindowMask | LeaveWindowMask)
50 #define FRAME_ANIMATE_ICONIFY_TIME 150000 /* .15 seconds */
51 #define FRAME_ANIMATE_ICONIFY_STEP_TIME (G_USEC_PER_SEC / 60) /* 60 Hz */
53 #define FRAME_HANDLE_Y(f) (f->size.top + f->client_area.height + f->cbwidth_b)
55 Display * obp_display;
57 RrInstance *ob_rr_inst;
59 Window createWindow(Window parent, Visual *visual, gulong mask,
60 XSetWindowAttributes *attrib)
62 return XCreateWindow(obp_display, parent, 0, 0, 1, 1, 0, (visual ? 32
63 : RrDepth(ob_rr_inst)), InputOutput, (visual ? visual
64 : RrVisual(ob_rr_inst)), mask, attrib);
68 Visual *check_32bit_client(ObClient *c)
70 XWindowAttributes wattrib;
73 /* we're already running at 32 bit depth, yay. we don't need to use their
75 if (RrDepth(ob_rr_inst) == 32)
78 ret = XGetWindowAttributes(obp_display, c->window, &wattrib);
79 g_assert(ret != BadDrawable);
80 g_assert(ret != BadWindow);
82 if (wattrib.depth == 32)
83 return wattrib.visual;
88 gint init(Display * display, gint screen)
90 ob_rr_inst = RrInstanceNew(display, screen);
91 if (ob_rr_inst == NULL)
92 ob_exit_with_error(_("Failed to initialize the obrender library."));
93 obp_display = display;
97 gpointer frame_new(struct _ObClient * client)
99 XSetWindowAttributes attrib;
101 ObDefaultFrame *self;
104 self = g_new0(ObDefaultFrame, 1);
105 self->client = client;
107 visual = check_32bit_client(client);
109 /* create the non-visible decor windows */
113 /* client has a 32-bit visual */
114 mask |= CWColormap | CWBackPixel | CWBorderPixel;
115 /* create a colormap with the visual */
116 OBDEFAULTFRAME(self)->colormap = attrib.colormap = XCreateColormap(
117 obp_display, RootWindow(obp_display,
118 obp_screen), visual, AllocNone);
119 attrib.background_pixel = BlackPixel(obp_display,
121 attrib.border_pixel = BlackPixel(obp_display, obp_screen);
123 self->window = createWindow(
124 RootWindow(obp_display, obp_screen), visual, mask,
127 /* create the visible decor windows */
131 /* client has a 32-bit visual */
132 mask |= CWColormap | CWBackPixel | CWBorderPixel;
133 attrib.colormap = RrColormap(ob_rr_inst);
136 self->backback = createWindow(self->window, NULL, mask, &attrib);
137 self->backfront = createWindow(self->backback, NULL, mask, &attrib);
140 attrib.event_mask = ELEMENT_EVENTMASK;
141 self->innerleft = createWindow(self->window, NULL, mask, &attrib);
142 self->innertop = createWindow(self->window, NULL, mask, &attrib);
143 self->innerright = createWindow(self->window, NULL, mask, &attrib);
144 self->innerbottom = createWindow(self->window, NULL, mask, &attrib);
146 self->innerblb = createWindow(self->innerbottom, NULL, mask, &attrib);
147 self->innerbrb = createWindow(self->innerbottom, NULL, mask, &attrib);
148 self->innerbll = createWindow(self->innerleft, NULL, mask, &attrib);
149 self->innerbrr = createWindow(self->innerright, NULL, mask, &attrib);
151 self->title = createWindow(self->window, NULL, mask, &attrib);
152 self->titleleft = createWindow(self->window, NULL, mask, &attrib);
153 self->titletop = createWindow(self->window, NULL, mask, &attrib);
154 self->titletopleft = createWindow(self->window, NULL, mask, &attrib);
155 self->titletopright = createWindow(self->window, NULL, mask, &attrib);
156 self->titleright = createWindow(self->window, NULL, mask, &attrib);
157 self->titlebottom = createWindow(self->window, NULL, mask, &attrib);
159 self->topresize = createWindow(self->title, NULL, mask, &attrib);
160 self->tltresize = createWindow(self->title, NULL, mask, &attrib);
161 self->tllresize = createWindow(self->title, NULL, mask, &attrib);
162 self->trtresize = createWindow(self->title, NULL, mask, &attrib);
163 self->trrresize = createWindow(self->title, NULL, mask, &attrib);
165 self->left = createWindow(self->window, NULL, mask, &attrib);
166 self->right = createWindow(self->window, NULL, mask, &attrib);
168 self->label = createWindow(self->title, NULL, mask, &attrib);
169 self->max = createWindow(self->title, NULL, mask, &attrib);
170 self->close = createWindow(self->title, NULL, mask, &attrib);
171 self->desk = createWindow(self->title, NULL, mask, &attrib);
172 self->shade = createWindow(self->title, NULL, mask, &attrib);
173 self->icon = createWindow(self->title, NULL, mask, &attrib);
174 self->iconify = createWindow(self->title, NULL, mask, &attrib);
176 self->handle = createWindow(self->window, NULL, mask, &attrib);
177 self->lgrip = createWindow(self->handle, NULL, mask, &attrib);
178 self->rgrip = createWindow(self->handle, NULL, mask, &attrib);
180 self->handleleft = createWindow(self->handle, NULL, mask, &attrib);
181 self->handleright = createWindow(self->handle, NULL, mask, &attrib);
183 self->handletop = createWindow(self->window, NULL, mask, &attrib);
184 self->handlebottom = createWindow(self->window, NULL, mask, &attrib);
185 self->lgripleft = createWindow(self->window, NULL, mask, &attrib);
186 self->lgriptop = createWindow(self->window, NULL, mask, &attrib);
187 self->lgripbottom = createWindow(self->window, NULL, mask, &attrib);
188 self->rgripright = createWindow(self->window, NULL, mask, &attrib);
189 self->rgriptop = createWindow(self->window, NULL, mask, &attrib);
190 self->rgripbottom = createWindow(self->window, NULL, mask, &attrib);
192 self->stitle = g_strdup("");
193 self->focused = FALSE;
195 /* the other stuff is shown based on decor settings */
196 XMapWindow(obp_display, self->label);
197 XMapWindow(obp_display, self->backback);
198 XMapWindow(obp_display, self->backfront);
200 self->hover_flag = OB_BUTTON_NONE;
201 self->press_flag = OB_BUTTON_NONE;
203 set_theme_statics(self);
208 void set_theme_statics(gpointer _self)
210 ObDefaultFrame * self = (ObDefaultFrame *) _self;
211 /* set colors/appearance/sizes for stuff that doesn't change */
212 XResizeWindow(obp_display, self->max, theme_config.button_size,
213 theme_config.button_size);
214 XResizeWindow(obp_display, self->iconify, theme_config.button_size,
215 theme_config.button_size);
216 XResizeWindow(obp_display, self->icon, theme_config.button_size + 2,
217 theme_config.button_size + 2);
218 XResizeWindow(obp_display, self->close, theme_config.button_size,
219 theme_config.button_size);
220 XResizeWindow(obp_display, self->desk, theme_config.button_size,
221 theme_config.button_size);
222 XResizeWindow(obp_display, self->shade, theme_config.button_size,
223 theme_config.button_size);
224 XResizeWindow(obp_display, self->tltresize, theme_config.grip_width,
225 theme_config.paddingy + 1);
226 XResizeWindow(obp_display, self->trtresize, theme_config.grip_width,
227 theme_config.paddingy + 1);
228 XResizeWindow(obp_display, self->tllresize,
229 theme_config.paddingx + 1, theme_config.title_height);
230 XResizeWindow(obp_display, self->trrresize,
231 theme_config.paddingx + 1, theme_config.title_height);
233 /* set up the dynamic appearances */
234 self->a_unfocused_title = RrAppearanceCopy(theme_config.a_unfocused_title);
235 self->a_focused_title = RrAppearanceCopy(theme_config.a_focused_title);
236 self->a_unfocused_label = RrAppearanceCopy(theme_config.a_unfocused_label);
237 self->a_focused_label = RrAppearanceCopy(theme_config.a_focused_label);
238 self->a_unfocused_handle
239 = RrAppearanceCopy(theme_config.a_unfocused_handle);
240 self->a_focused_handle = RrAppearanceCopy(theme_config.a_focused_handle);
241 self->a_icon = RrAppearanceCopy(theme_config.a_icon);
244 void free_theme_statics(gpointer _self)
246 ObDefaultFrame * self = (ObDefaultFrame *) _self;
247 RrAppearanceFree(self->a_unfocused_title);
248 RrAppearanceFree(self->a_focused_title);
249 RrAppearanceFree(self->a_unfocused_label);
250 RrAppearanceFree(self->a_focused_label);
251 RrAppearanceFree(self->a_unfocused_handle);
252 RrAppearanceFree(self->a_focused_handle);
253 RrAppearanceFree(self->a_icon);
256 void frame_free(gpointer self)
258 free_theme_statics(OBDEFAULTFRAME(self));
259 XDestroyWindow(obp_display, OBDEFAULTFRAME(self)->window);
260 if (OBDEFAULTFRAME(self)->colormap)
261 XFreeColormap(obp_display, OBDEFAULTFRAME(self)->colormap);
263 g_free(OBDEFAULTFRAME(self)->stitle);
267 void frame_show(gpointer _self)
269 ObDefaultFrame * self = (ObDefaultFrame *) _self;
270 if (!self->visible) {
271 self->visible = TRUE;
272 frame_update_skin(self);
273 /* Grab the server to make sure that the frame window is mapped before
274 the client gets its MapNotify, i.e. to make sure the client is
275 _visible_ when it gets MapNotify. */
277 XMapWindow(obp_display, self->client->window);
278 XMapWindow(obp_display, self->window);
283 gint frame_hide(gpointer self)
285 if (OBDEFAULTFRAME(self)->visible) {
286 OBDEFAULTFRAME(self)->visible = FALSE;
287 if (!frame_iconify_animating(self))
288 XUnmapWindow(obp_display, OBDEFAULTFRAME(self)->window);
289 /* we unmap the client itself so that we can get MapRequest
290 events, and because the ICCCM tells us to! */
291 XUnmapWindow(obp_display, OBDEFAULTFRAME(self)->client->window);
299 void frame_adjust_theme(gpointer self)
301 free_theme_statics(self);
302 set_theme_statics(self);
305 void frame_adjust_shape(gpointer _self)
308 ObDefaultFrame * self = (ObDefaultFrame *) _self;
312 if (!self->client->shaped)
314 /* clear the shape on the frame window */
315 XShapeCombineMask(obp_display, self->window, ShapeBounding,
322 /* make the frame's shape match the clients */
323 XShapeCombineShape(obp_display, self->window, ShapeBounding,
326 self->client->window,
327 ShapeBounding, ShapeSet);
330 if (self->decorations & OB_FRAME_DECOR_TITLEBAR)
334 xrect[0].width = self->area.width;
335 xrect[0].height = self->size.top;
339 if (self->decorations & OB_FRAME_DECOR_HANDLE &&
340 theme_config.handle_height> 0)
343 xrect[1].y = FRAME_HANDLE_Y(self);
344 xrect[1].width = self->area.width;
345 xrect[1].height = theme_config.handle_height +
350 XShapeCombineRectangles(obp_display, self->window,
351 ShapeBounding, 0, 0, xrect, num,
352 ShapeUnion, Unsorted);
357 void frame_grab(gpointer _self, GHashTable * window_map)
359 ObDefaultFrame * self = (ObDefaultFrame *) _self;
360 /* DO NOT map the client window here. we used to do that, but it is bogus.
361 we need to set up the client's dimensions and everything before we
362 send a mapnotify or we create race conditions.
365 /* reparent the client to the frame */
366 XReparentWindow(obp_display, self->client->window, self->window, 0, 0);
369 When reparenting the client window, it is usually not mapped yet, since
370 this occurs from a MapRequest. However, in the case where Openbox is
371 starting up, the window is already mapped, so we'll see an unmap event
374 if (ob_state() == OB_STATE_STARTING)
375 ++self->client->ignore_unmaps;
377 /* select the event mask on the client's parent (to receive config/map
378 req's) the ButtonPress is to catch clicks on the client border */
379 XSelectInput(obp_display, self->window, FRAME_EVENTMASK);
381 /* set all the windows for the frame in the window_map */
382 g_hash_table_insert(window_map, &self->window, self->client);
383 g_hash_table_insert(window_map, &self->backback, self->client);
384 g_hash_table_insert(window_map, &self->backfront, self->client);
385 g_hash_table_insert(window_map, &self->innerleft, self->client);
386 g_hash_table_insert(window_map, &self->innertop, self->client);
387 g_hash_table_insert(window_map, &self->innerright, self->client);
388 g_hash_table_insert(window_map, &self->innerbottom, self->client);
389 g_hash_table_insert(window_map, &self->title, self->client);
390 g_hash_table_insert(window_map, &self->label, self->client);
391 g_hash_table_insert(window_map, &self->max, self->client);
392 g_hash_table_insert(window_map, &self->close, self->client);
393 g_hash_table_insert(window_map, &self->desk, self->client);
394 g_hash_table_insert(window_map, &self->shade, self->client);
395 g_hash_table_insert(window_map, &self->icon, self->client);
396 g_hash_table_insert(window_map, &self->iconify, self->client);
397 g_hash_table_insert(window_map, &self->handle, self->client);
398 g_hash_table_insert(window_map, &self->lgrip, self->client);
399 g_hash_table_insert(window_map, &self->rgrip, self->client);
400 g_hash_table_insert(window_map, &self->topresize, self->client);
401 g_hash_table_insert(window_map, &self->tltresize, self->client);
402 g_hash_table_insert(window_map, &self->tllresize, self->client);
403 g_hash_table_insert(window_map, &self->trtresize, self->client);
404 g_hash_table_insert(window_map, &self->trrresize, self->client);
405 g_hash_table_insert(window_map, &self->left, self->client);
406 g_hash_table_insert(window_map, &self->right, self->client);
407 g_hash_table_insert(window_map, &self->titleleft, self->client);
408 g_hash_table_insert(window_map, &self->titletop, self->client);
409 g_hash_table_insert(window_map, &self->titletopleft, self->client);
410 g_hash_table_insert(window_map, &self->titletopright, self->client);
411 g_hash_table_insert(window_map, &self->titleright, self->client);
412 g_hash_table_insert(window_map, &self->titlebottom, self->client);
413 g_hash_table_insert(window_map, &self->handleleft, self->client);
414 g_hash_table_insert(window_map, &self->handletop, self->client);
415 g_hash_table_insert(window_map, &self->handleright, self->client);
416 g_hash_table_insert(window_map, &self->handlebottom, self->client);
417 g_hash_table_insert(window_map, &self->lgripleft, self->client);
418 g_hash_table_insert(window_map, &self->lgriptop, self->client);
419 g_hash_table_insert(window_map, &self->lgripbottom, self->client);
420 g_hash_table_insert(window_map, &self->rgripright, self->client);
421 g_hash_table_insert(window_map, &self->rgriptop, self->client);
422 g_hash_table_insert(window_map, &self->rgripbottom, self->client);
425 void frame_ungrab(gpointer _self, GHashTable * window_map)
427 ObDefaultFrame * self = (ObDefaultFrame *) _self;
429 gboolean reparent = TRUE;
431 /* if there was any animation going on, kill it */
432 obt_main_loop_timeout_remove_data(plugin.ob_main_loop,
433 frame_animate_iconify, self, FALSE);
435 /* check if the app has already reparented its window away */
436 while (XCheckTypedWindowEvent(obp_display, self->client->window,
437 ReparentNotify, &ev)) {
438 /* This check makes sure we don't catch our own reparent action to
439 our frame window. This doesn't count as the app reparenting itself
442 Reparent events that are generated by us are just discarded here.
443 They are of no consequence to us anyhow.
445 if (ev.xreparent.parent != self->window) {
447 XPutBackEvent(obp_display, &ev);
453 /* according to the ICCCM - if the client doesn't reparent itself,
454 then we will reparent the window to root for them */
455 XReparentWindow(obp_display, self->client->window, RootWindow(
456 obp_display, obp_screen), self->client_area.x,
457 self->client_area.y);
460 /* remove all the windows for the frame from the window_map */
461 g_hash_table_remove(window_map, &self->window);
462 g_hash_table_remove(window_map, &self->backback);
463 g_hash_table_remove(window_map, &self->backfront);
464 g_hash_table_remove(window_map, &self->innerleft);
465 g_hash_table_remove(window_map, &self->innertop);
466 g_hash_table_remove(window_map, &self->innerright);
467 g_hash_table_remove(window_map, &self->innerbottom);
468 g_hash_table_remove(window_map, &self->title);
469 g_hash_table_remove(window_map, &self->label);
470 g_hash_table_remove(window_map, &self->max);
471 g_hash_table_remove(window_map, &self->close);
472 g_hash_table_remove(window_map, &self->desk);
473 g_hash_table_remove(window_map, &self->shade);
474 g_hash_table_remove(window_map, &self->icon);
475 g_hash_table_remove(window_map, &self->iconify);
476 g_hash_table_remove(window_map, &self->handle);
477 g_hash_table_remove(window_map, &self->lgrip);
478 g_hash_table_remove(window_map, &self->rgrip);
479 g_hash_table_remove(window_map, &self->topresize);
480 g_hash_table_remove(window_map, &self->tltresize);
481 g_hash_table_remove(window_map, &self->tllresize);
482 g_hash_table_remove(window_map, &self->trtresize);
483 g_hash_table_remove(window_map, &self->trrresize);
484 g_hash_table_remove(window_map, &self->left);
485 g_hash_table_remove(window_map, &self->right);
486 g_hash_table_remove(window_map, &self->titleleft);
487 g_hash_table_remove(window_map, &self->titletop);
488 g_hash_table_remove(window_map, &self->titletopleft);
489 g_hash_table_remove(window_map, &self->titletopright);
490 g_hash_table_remove(window_map, &self->titleright);
491 g_hash_table_remove(window_map, &self->titlebottom);
492 g_hash_table_remove(window_map, &self->handleleft);
493 g_hash_table_remove(window_map, &self->handletop);
494 g_hash_table_remove(window_map, &self->handleright);
495 g_hash_table_remove(window_map, &self->handlebottom);
496 g_hash_table_remove(window_map, &self->lgripleft);
497 g_hash_table_remove(window_map, &self->lgriptop);
498 g_hash_table_remove(window_map, &self->lgripbottom);
499 g_hash_table_remove(window_map, &self->rgripright);
500 g_hash_table_remove(window_map, &self->rgriptop);
501 g_hash_table_remove(window_map, &self->rgripbottom);
503 obt_main_loop_timeout_remove_data(plugin.ob_main_loop, flash_timeout, self,
507 ObFrameContext frame_context(gpointer _self, Window win, gint x, gint y)
509 ObDefaultFrame * self = OBDEFAULTFRAME(_self);
511 /* when the user clicks in the corners of the titlebar and the client
512 is fully maximized, then treat it like they clicked in the
513 button that is there */
514 if (self->max_horz && self->max_vert && (win == self->title || win
515 == self->titletop || win == self->titleleft || win
516 == self->titletopleft || win == self->titleright || win
517 == self->titletopright)) {
518 /* get the mouse coords in reference to the whole frame */
522 /* these windows are down a border width from the top of the frame */
523 if (win == self->title || win == self->titleleft || win
527 /* title is a border width in from the edge */
528 if (win == self->title)
530 /* titletop is a bit to the right */
531 else if (win == self->titletop)
532 fx += theme_config.grip_width + self->bwidth;
533 /* titletopright is way to the right edge */
534 else if (win == self->titletopright)
535 fx += self->area.width - (theme_config.grip_width + self->bwidth);
536 /* titleright is even more way to the right edge */
537 else if (win == self->titleright)
538 fx += self->area.width - self->bwidth;
540 /* figure out if we're over the area that should be considered a
542 if (fy < self->bwidth + theme_config.paddingy + 1
543 + theme_config.button_size) {
544 if (fx < (self->bwidth + theme_config.paddingx + 1
545 + theme_config.button_size)) {
546 if (self->leftmost != OB_FRAME_CONTEXT_NONE)
547 return self->leftmost;
549 else if (fx >= (self->area.width - (self->bwidth
550 + theme_config.paddingx + 1 + theme_config.button_size))) {
551 if (self->rightmost != OB_FRAME_CONTEXT_NONE)
552 return self->rightmost;
556 /* there is no resizing maximized windows so make them the titlebar
558 return OB_FRAME_CONTEXT_TITLEBAR;
560 else if (self->max_vert
561 && (win == self->titletop || win == self->topresize))
562 /* can't resize vertically when max vert */
563 return OB_FRAME_CONTEXT_TITLEBAR;
564 else if (self->shaded && (win == self->titletop || win == self->topresize))
565 /* can't resize vertically when shaded */
566 return OB_FRAME_CONTEXT_TITLEBAR;
568 if (win == self->window)
569 return OB_FRAME_CONTEXT_FRAME;
570 if (win == self->label)
571 return OB_FRAME_CONTEXT_TITLEBAR;
572 if (win == self->handle)
573 return OB_FRAME_CONTEXT_BOTTOM;
574 if (win == self->handletop)
575 return OB_FRAME_CONTEXT_BOTTOM;
576 if (win == self->handlebottom)
577 return OB_FRAME_CONTEXT_BOTTOM;
578 if (win == self->handleleft)
579 return OB_FRAME_CONTEXT_BLCORNER;
580 if (win == self->lgrip)
581 return OB_FRAME_CONTEXT_BLCORNER;
582 if (win == self->lgripleft)
583 return OB_FRAME_CONTEXT_BLCORNER;
584 if (win == self->lgriptop)
585 return OB_FRAME_CONTEXT_BLCORNER;
586 if (win == self->lgripbottom)
587 return OB_FRAME_CONTEXT_BLCORNER;
588 if (win == self->handleright)
589 return OB_FRAME_CONTEXT_BRCORNER;
590 if (win == self->rgrip)
591 return OB_FRAME_CONTEXT_BRCORNER;
592 if (win == self->rgripright)
593 return OB_FRAME_CONTEXT_BLCORNER;
594 if (win == self->rgriptop)
595 return OB_FRAME_CONTEXT_BLCORNER;
596 if (win == self->rgripbottom)
597 return OB_FRAME_CONTEXT_BLCORNER;
598 if (win == self->title)
599 return OB_FRAME_CONTEXT_TITLEBAR;
600 if (win == self->titlebottom)
601 return OB_FRAME_CONTEXT_TITLEBAR;
602 if (win == self->titleleft)
603 return OB_FRAME_CONTEXT_TLCORNER;
604 if (win == self->titletopleft)
605 return OB_FRAME_CONTEXT_TLCORNER;
606 if (win == self->titleright)
607 return OB_FRAME_CONTEXT_TRCORNER;
608 if (win == self->titletopright)
609 return OB_FRAME_CONTEXT_TRCORNER;
610 if (win == self->titletop)
611 return OB_FRAME_CONTEXT_TOP;
612 if (win == self->topresize)
613 return OB_FRAME_CONTEXT_TOP;
614 if (win == self->tltresize)
615 return OB_FRAME_CONTEXT_TLCORNER;
616 if (win == self->tllresize)
617 return OB_FRAME_CONTEXT_TLCORNER;
618 if (win == self->trtresize)
619 return OB_FRAME_CONTEXT_TRCORNER;
620 if (win == self->trrresize)
621 return OB_FRAME_CONTEXT_TRCORNER;
622 if (win == self->left)
623 return OB_FRAME_CONTEXT_LEFT;
624 if (win == self->right)
625 return OB_FRAME_CONTEXT_RIGHT;
626 if (win == self->innertop)
627 return OB_FRAME_CONTEXT_TITLEBAR;
628 if (win == self->innerleft)
629 return OB_FRAME_CONTEXT_LEFT;
630 if (win == self->innerbottom)
631 return OB_FRAME_CONTEXT_BOTTOM;
632 if (win == self->innerright)
633 return OB_FRAME_CONTEXT_RIGHT;
634 if (win == self->max)
635 return OB_FRAME_CONTEXT_MAXIMIZE;
636 if (win == self->iconify)
637 return OB_FRAME_CONTEXT_ICONIFY;
638 if (win == self->close)
639 return OB_FRAME_CONTEXT_CLOSE;
640 if (win == self->icon)
641 return OB_FRAME_CONTEXT_ICON;
642 if (win == self->desk)
643 return OB_FRAME_CONTEXT_ALLDESKTOPS;
644 if (win == self->shade)
645 return OB_FRAME_CONTEXT_SHADE;
647 return OB_FRAME_CONTEXT_NONE;
650 void frame_set_is_visible(gpointer self, gboolean b)
652 OBDEFAULTFRAME(self)->visible = b;
655 void frame_set_is_focus(gpointer self, gboolean b)
657 OBDEFAULTFRAME(self)->focused = b;
660 void frame_set_is_max_vert(gpointer self, gboolean b)
662 OBDEFAULTFRAME(self)->max_vert = b;
665 void frame_set_is_max_horz(gpointer self, gboolean b)
667 OBDEFAULTFRAME(self)->max_horz = b;
670 void frame_set_is_shaded(gpointer self, gboolean b)
672 OBDEFAULTFRAME(self)->shaded = b;
675 void frame_unfocus(gpointer self)
677 OBDEFAULTFRAME(self)->focused = FALSE;
680 void frame_flash_start(gpointer _self)
682 ObDefaultFrame * self = (ObDefaultFrame *) _self;
683 self->flash_on = self->focused;
686 obt_main_loop_timeout_add(plugin.ob_main_loop, G_USEC_PER_SEC * 0.6,
687 flash_timeout, self, g_direct_equal, flash_done);
688 g_get_current_time(&self->flash_end);
689 g_time_val_add(&self->flash_end, G_USEC_PER_SEC * 5);
691 self->flashing = TRUE;
694 void frame_flash_stop(gpointer _self)
696 ObDefaultFrame * self = (ObDefaultFrame *) _self;
697 self->flashing = FALSE;
700 void frame_begin_iconify_animation(gpointer _self, gboolean iconifying)
702 ObDefaultFrame * self = (ObDefaultFrame *) _self;
704 gboolean new_anim = FALSE;
705 gboolean set_end = TRUE;
708 /* if there is no titlebar, just don't animate for now
709 XXX it would be nice tho.. */
710 if (!(self->decorations & OB_FRAME_DECOR_TITLEBAR))
713 /* get the current time */
714 g_get_current_time(&now);
716 /* get how long until the end */
717 time = FRAME_ANIMATE_ICONIFY_TIME;
718 if (self->iconify_animation_going) {
719 if (!!iconifying != (self->iconify_animation_going > 0)) {
720 /* animation was already going on in the opposite direction */
721 time = time - frame_animate_iconify_time_left(_self, &now);
724 /* animation was already going in the same direction */
729 self->iconify_animation_going = iconifying ? 1 : -1;
731 /* set the ending time */
733 self->iconify_animation_end.tv_sec = now.tv_sec;
734 self->iconify_animation_end.tv_usec = now.tv_usec;
735 g_time_val_add(&self->iconify_animation_end, time);
739 obt_main_loop_timeout_remove_data(plugin.ob_main_loop,
740 frame_animate_iconify, self, FALSE);
741 obt_main_loop_timeout_add(plugin.ob_main_loop,
742 FRAME_ANIMATE_ICONIFY_STEP_TIME, frame_animate_iconify, self,
743 g_direct_equal, NULL);
745 /* do the first step */
746 frame_animate_iconify(self);
748 /* show it during the animation even if it is not "visible" */
750 XMapWindow(obp_display, self->window);
754 void frame_end_iconify_animation(gpointer _self)
756 ObDefaultFrame * self = (ObDefaultFrame *) _self;
757 /* see if there is an animation going */
758 if (self->iconify_animation_going == 0)
762 XUnmapWindow(obp_display, self->window);
764 /* Send a ConfigureNotify when the animation is done, this fixes
765 KDE's pager showing the window in the wrong place. since the
766 window is mapped at a different location and is then moved, we
767 need to send the synthetic configurenotify, since apps may have
768 read the position when the client mapped, apparently. */
769 client_reconfigure(self->client, TRUE);
772 /* we're not animating any more ! */
773 self->iconify_animation_going = 0;
775 XMoveResizeWindow(obp_display, self->window, self->area.x,
776 self->area.y, self->area.width, self->area.height);
777 /* we delay re-rendering until after we're done animating */
778 frame_update_skin(self);
782 gboolean frame_iconify_animating(gpointer _self)
784 ObDefaultFrame * self = (ObDefaultFrame *) _self;
785 return self->iconify_animation_going != 0;
788 void frame_set_decorations(gpointer self, ObFrameDecorations d)
790 OBDEFAULTFRAME(self)->decorations = d;
793 Rect frame_get_window_area(gpointer self)
795 return OBDEFAULTFRAME(self)->area;
797 void frame_set_client_area(gpointer self, Rect r)
799 OBDEFAULTFRAME(self)->client_area = r;
802 void frame_update_layout(gpointer _self, gboolean is_resize, gboolean is_fake)
804 ObDefaultFrame * self = (ObDefaultFrame *) _self;
807 oldsize = self->size;
808 self->area = self->client_area;
810 /* do this before changing the frame's status like max_horz max_vert */
811 frame_adjust_cursors(self);
813 if (self->decorations & OB_FRAME_DECOR_BORDER
814 || (plugin.config_theme_keepborder)) {
815 self->bwidth = theme_config.fbwidth;
821 if (self->decorations & OB_FRAME_DECOR_BORDER) {
822 self->cbwidth_l = theme_config.cbwidthx;
823 self->cbwidth_r = theme_config.cbwidthx;
824 self->cbwidth_t = theme_config.cbwidthy;
825 self->cbwidth_b = theme_config.cbwidthy;
834 if (self->max_horz) {
837 self->width = self->client_area.width;
842 self->width = self->client_area.width + self->cbwidth_l
846 /* some elements are sized based of the width, so don't let them have
848 self->width = MAX(self->width, (theme_config.grip_width + self->bwidth) * 2
851 STRUT_SET(self->size, self->cbwidth_l
852 + (!self->max_horz ? self->bwidth : 0), self->cbwidth_t
853 + self->bwidth, self->cbwidth_r + (!self->max_horz ? self->bwidth
854 : 0), self->cbwidth_b
855 + (!self->max_horz || !self->max_vert ? self->bwidth : 0));
857 if (self->decorations & OB_FRAME_DECOR_TITLEBAR)
858 self->size.top += theme_config.title_height + self->bwidth;
859 if (self->decorations & OB_FRAME_DECOR_HANDLE && theme_config.handle_height
861 self->size.bottom += theme_config.handle_height + self->bwidth;
864 /* position/size and map/unmap all the windows */
866 gint innercornerheight = theme_config.grip_width - self->size.bottom;
868 if (self->cbwidth_l) {
869 XMoveResizeWindow(obp_display, self->innerleft,
870 self->size.left - self->cbwidth_l, self->size.top,
871 self->cbwidth_l, self->client_area.height);
873 XMapWindow(obp_display, self->innerleft);
876 XUnmapWindow(obp_display, self->innerleft);
878 if (self->cbwidth_l && innercornerheight > 0) {
879 XMoveResizeWindow(obp_display, self->innerbll, 0,
880 self->client_area.height - (theme_config.grip_width
881 - self->size.bottom), self->cbwidth_l,
882 theme_config.grip_width - self->size.bottom);
884 XMapWindow(obp_display, self->innerbll);
887 XUnmapWindow(obp_display, self->innerbll);
889 if (self->cbwidth_r) {
890 XMoveResizeWindow(obp_display, self->innerright,
891 self->size.left + self->client_area.width, self->size.top,
892 self->cbwidth_r, self->client_area.height);
894 XMapWindow(obp_display, self->innerright);
897 XUnmapWindow(obp_display, self->innerright);
899 if (self->cbwidth_r && innercornerheight > 0) {
900 XMoveResizeWindow(obp_display, self->innerbrr, 0,
901 self->client_area.height - (theme_config.grip_width
902 - self->size.bottom), self->cbwidth_r,
903 theme_config.grip_width - self->size.bottom);
905 XMapWindow(obp_display, self->innerbrr);
908 XUnmapWindow(obp_display, self->innerbrr);
910 if (self->cbwidth_t) {
911 XMoveResizeWindow(obp_display, self->innertop,
912 self->size.left - self->cbwidth_l, self->size.top
913 - self->cbwidth_t, self->client_area.width
914 + self->cbwidth_l + self->cbwidth_r,
917 XMapWindow(obp_display, self->innertop);
920 XUnmapWindow(obp_display, self->innertop);
922 if (self->cbwidth_b) {
923 XMoveResizeWindow(obp_display, self->innerbottom,
924 self->size.left - self->cbwidth_l, self->size.top
925 + self->client_area.height, self->client_area.width
926 + self->cbwidth_l + self->cbwidth_r,
929 XMoveResizeWindow(obp_display, self->innerblb, 0, 0,
930 theme_config.grip_width + self->bwidth, self->cbwidth_b);
931 XMoveResizeWindow(obp_display, self->innerbrb,
932 self->client_area.width + self->cbwidth_l + self->cbwidth_r
933 - (theme_config.grip_width + self->bwidth), 0,
934 theme_config.grip_width + self->bwidth, self->cbwidth_b);
936 XMapWindow(obp_display, self->innerbottom);
937 XMapWindow(obp_display, self->innerblb);
938 XMapWindow(obp_display, self->innerbrb);
941 XUnmapWindow(obp_display, self->innerbottom);
942 XUnmapWindow(obp_display, self->innerblb);
943 XUnmapWindow(obp_display, self->innerbrb);
949 /* height of titleleft and titleright */
950 titlesides = (!self->max_horz ? theme_config.grip_width : 0);
952 XMoveResizeWindow(obp_display, self->titletop,
953 theme_config.grip_width + self->bwidth, 0,
954 /* width + bwidth*2 - bwidth*2 - grips*2 */
955 self->width - theme_config.grip_width * 2, self->bwidth);
956 XMoveResizeWindow(obp_display, self->titletopleft, 0, 0,
957 theme_config.grip_width + self->bwidth, self->bwidth);
958 XMoveResizeWindow(obp_display, self->titletopright,
959 self->client_area.width + self->size.left
960 + self->size.right - theme_config.grip_width
961 - self->bwidth, 0, theme_config.grip_width
962 + self->bwidth, self->bwidth);
964 if (titlesides > 0) {
965 XMoveResizeWindow(obp_display, self->titleleft, 0,
966 self->bwidth, self->bwidth, titlesides);
967 XMoveResizeWindow(obp_display, self->titleright,
968 self->client_area.width + self->size.left
969 + self->size.right - self->bwidth,
970 self->bwidth, self->bwidth, titlesides);
972 XMapWindow(obp_display, self->titleleft);
973 XMapWindow(obp_display, self->titleright);
976 XUnmapWindow(obp_display, self->titleleft);
977 XUnmapWindow(obp_display, self->titleright);
980 XMapWindow(obp_display, self->titletop);
981 XMapWindow(obp_display, self->titletopleft);
982 XMapWindow(obp_display, self->titletopright);
984 if (self->decorations & OB_FRAME_DECOR_TITLEBAR) {
985 XMoveResizeWindow(obp_display, self->titlebottom,
986 (self->max_horz ? 0 : self->bwidth),
987 theme_config.title_height + self->bwidth, self->width,
990 XMapWindow(obp_display, self->titlebottom);
993 XUnmapWindow(obp_display, self->titlebottom);
996 XUnmapWindow(obp_display, self->titlebottom);
998 XUnmapWindow(obp_display, self->titletop);
999 XUnmapWindow(obp_display, self->titletopleft);
1000 XUnmapWindow(obp_display, self->titletopright);
1001 XUnmapWindow(obp_display, self->titleleft);
1002 XUnmapWindow(obp_display, self->titleright);
1005 if (self->decorations & OB_FRAME_DECOR_TITLEBAR) {
1006 XMoveResizeWindow(obp_display, self->title,
1007 (self->max_horz ? 0 : self->bwidth), self->bwidth,
1008 self->width, theme_config.title_height);
1010 XMapWindow(obp_display, self->title);
1012 if (self->decorations & OB_FRAME_DECOR_GRIPS) {
1013 XMoveResizeWindow(obp_display, self->topresize,
1014 theme_config.grip_width, 0, self->width
1015 - theme_config.grip_width *2,
1016 theme_config.paddingy + 1);
1018 XMoveWindow(obp_display, self->tltresize, 0, 0);
1019 XMoveWindow(obp_display, self->tllresize, 0, 0);
1020 XMoveWindow(obp_display, self->trtresize, self->width
1021 - theme_config.grip_width, 0);
1022 XMoveWindow(obp_display, self->trrresize, self->width
1023 - theme_config.paddingx - 1, 0);
1025 XMapWindow(obp_display, self->topresize);
1026 XMapWindow(obp_display, self->tltresize);
1027 XMapWindow(obp_display, self->tllresize);
1028 XMapWindow(obp_display, self->trtresize);
1029 XMapWindow(obp_display, self->trrresize);
1032 XUnmapWindow(obp_display, self->topresize);
1033 XUnmapWindow(obp_display, self->tltresize);
1034 XUnmapWindow(obp_display, self->tllresize);
1035 XUnmapWindow(obp_display, self->trtresize);
1036 XUnmapWindow(obp_display, self->trrresize);
1040 XUnmapWindow(obp_display, self->title);
1043 if ((self->decorations & OB_FRAME_DECOR_TITLEBAR))
1044 /* layout the title bar elements */
1048 gint sidebwidth = self->max_horz ? 0 : self->bwidth;
1050 if (self->bwidth && self->size.bottom) {
1051 XMoveResizeWindow(obp_display, self->handlebottom,
1052 theme_config.grip_width + self->bwidth + sidebwidth,
1053 self->size.top + self->client_area.height
1054 + self->size.bottom - self->bwidth, self->width
1055 - (theme_config.grip_width + sidebwidth) * 2,
1059 XMoveResizeWindow(obp_display, self->lgripleft, 0,
1060 self->size.top + self->client_area.height
1062 - (!self->max_horz ? theme_config.grip_width
1063 : self->size.bottom - self->cbwidth_b),
1065 (!self->max_horz ? theme_config.grip_width
1066 : self->size.bottom - self->cbwidth_b));
1067 XMoveResizeWindow(obp_display, self->rgripright,
1068 self->size.left + self->client_area.width
1069 + self->size.right - self->bwidth,
1070 self->size.top + self->client_area.height
1072 - (!self->max_horz ? theme_config.grip_width
1073 : self->size.bottom - self->cbwidth_b),
1075 (!self->max_horz ? theme_config.grip_width
1076 : self->size.bottom - self->cbwidth_b));
1078 XMapWindow(obp_display, self->lgripleft);
1079 XMapWindow(obp_display, self->rgripright);
1082 XUnmapWindow(obp_display, self->lgripleft);
1083 XUnmapWindow(obp_display, self->rgripright);
1086 XMoveResizeWindow(obp_display, self->lgripbottom, sidebwidth,
1087 self->size.top + self->client_area.height
1088 + self->size.bottom - self->bwidth,
1089 theme_config.grip_width + self->bwidth, self->bwidth);
1090 XMoveResizeWindow(obp_display, self->rgripbottom,
1091 self->size.left + self->client_area.width
1092 + self->size.right - self->bwidth - sidebwidth
1093 - theme_config.grip_width, self->size.top
1094 + self->client_area.height + self->size.bottom
1095 - self->bwidth, theme_config.grip_width
1096 + self->bwidth, self->bwidth);
1098 XMapWindow(obp_display, self->handlebottom);
1099 XMapWindow(obp_display, self->lgripbottom);
1100 XMapWindow(obp_display, self->rgripbottom);
1102 if (self->decorations & OB_FRAME_DECOR_HANDLE
1103 && theme_config.handle_height > 0) {
1104 XMoveResizeWindow(obp_display, self->handletop,
1105 theme_config.grip_width + self->bwidth + sidebwidth,
1106 FRAME_HANDLE_Y(self), self->width - (theme_config.grip_width
1107 + sidebwidth) * 2, self->bwidth);
1108 XMapWindow(obp_display, self->handletop);
1110 if (self->decorations & OB_FRAME_DECOR_GRIPS) {
1111 XMoveResizeWindow(obp_display, self->handleleft,
1112 theme_config.grip_width, 0, self->bwidth,
1113 theme_config.handle_height);
1114 XMoveResizeWindow(obp_display, self->handleright,
1115 self->width - theme_config.grip_width
1116 - self->bwidth, 0, self->bwidth,
1117 theme_config.handle_height);
1119 XMoveResizeWindow(obp_display, self->lgriptop,
1121 FRAME_HANDLE_Y(self), theme_config.grip_width
1122 + self->bwidth, self->bwidth);
1123 XMoveResizeWindow(obp_display, self->rgriptop,
1124 self->size.left + self->client_area.width
1125 + self->size.right - self->bwidth
1126 - sidebwidth - theme_config.grip_width,
1127 FRAME_HANDLE_Y(self), theme_config.grip_width
1128 + self->bwidth, self->bwidth);
1130 XMapWindow(obp_display, self->handleleft);
1131 XMapWindow(obp_display, self->handleright);
1132 XMapWindow(obp_display, self->lgriptop);
1133 XMapWindow(obp_display, self->rgriptop);
1136 XUnmapWindow(obp_display, self->handleleft);
1137 XUnmapWindow(obp_display, self->handleright);
1138 XUnmapWindow(obp_display, self->lgriptop);
1139 XUnmapWindow(obp_display, self->rgriptop);
1143 XUnmapWindow(obp_display, self->handleleft);
1144 XUnmapWindow(obp_display, self->handleright);
1145 XUnmapWindow(obp_display, self->lgriptop);
1146 XUnmapWindow(obp_display, self->rgriptop);
1148 XUnmapWindow(obp_display, self->handletop);
1152 XUnmapWindow(obp_display, self->handleleft);
1153 XUnmapWindow(obp_display, self->handleright);
1154 XUnmapWindow(obp_display, self->lgriptop);
1155 XUnmapWindow(obp_display, self->rgriptop);
1157 XUnmapWindow(obp_display, self->handletop);
1159 XUnmapWindow(obp_display, self->handlebottom);
1160 XUnmapWindow(obp_display, self->lgripleft);
1161 XUnmapWindow(obp_display, self->rgripright);
1162 XUnmapWindow(obp_display, self->lgripbottom);
1163 XUnmapWindow(obp_display, self->rgripbottom);
1166 if (self->decorations & OB_FRAME_DECOR_HANDLE
1167 && theme_config.handle_height > 0) {
1168 XMoveResizeWindow(obp_display, self->handle, sidebwidth,
1169 FRAME_HANDLE_Y(self) + self->bwidth, self->width,
1170 theme_config.handle_height);
1171 XMapWindow(obp_display, self->handle);
1173 if (self->decorations & OB_FRAME_DECOR_GRIPS) {
1174 XMoveResizeWindow(obp_display, self->lgrip, 0, 0,
1175 theme_config.grip_width, theme_config.handle_height);
1176 XMoveResizeWindow(obp_display, self->rgrip, self->width
1177 - theme_config.grip_width, 0, theme_config.grip_width,
1178 theme_config.handle_height);
1180 XMapWindow(obp_display, self->lgrip);
1181 XMapWindow(obp_display, self->rgrip);
1184 XUnmapWindow(obp_display, self->lgrip);
1185 XUnmapWindow(obp_display, self->rgrip);
1189 XUnmapWindow(obp_display, self->lgrip);
1190 XUnmapWindow(obp_display, self->rgrip);
1192 XUnmapWindow(obp_display, self->handle);
1195 if (self->bwidth && !self->max_horz && (self->client_area.height
1196 + self->size.top + self->size.bottom) > theme_config.grip_width
1198 XMoveResizeWindow(obp_display, self->left, 0, self->bwidth
1199 + theme_config.grip_width, self->bwidth,
1200 self->client_area.height + self->size.top
1201 + self->size.bottom - theme_config.grip_width * 2);
1203 XMapWindow(obp_display, self->left);
1206 XUnmapWindow(obp_display, self->left);
1208 if (self->bwidth && !self->max_horz && (self->client_area.height
1209 + self->size.top + self->size.bottom) > theme_config.grip_width
1211 XMoveResizeWindow(obp_display, self->right,
1212 self->client_area.width + self->cbwidth_l + self->cbwidth_r
1213 + self->bwidth, self->bwidth
1214 + theme_config.grip_width, self->bwidth,
1215 self->client_area.height + self->size.top
1216 + self->size.bottom - theme_config.grip_width * 2);
1218 XMapWindow(obp_display, self->right);
1221 XUnmapWindow(obp_display, self->right);
1223 XMoveResizeWindow(obp_display, self->backback, self->size.left,
1224 self->size.top, self->client_area.width,
1225 self->client_area.height);
1228 /* shading can change without being moved or resized */
1229 RECT_SET_SIZE(self->area, self->client_area.width + self->size.left
1230 + self->size.right, (self->shaded ? theme_config.title_height
1231 + self->bwidth * 2 : self->client_area.height + self->size.top
1232 + self->size.bottom));
1234 if ((is_resize) && !is_fake) {
1235 /* find the new coordinates, done after setting the frame.size, for
1236 frame_client_gravity. */
1237 self->area.x = self->client_area.x;
1238 self->area.y = self->client_area.y;
1239 frame_client_gravity(OBDEFAULTFRAME(_self)->client, &self->area.x, &self->area.y);
1243 if (!frame_iconify_animating(self))
1244 /* move and resize the top level frame.
1245 shading can change without being moved or resized.
1247 but don't do this during an iconify animation. it will be
1248 reflected afterwards.
1250 XMoveResizeWindow(obp_display, self->window, self->area.x,
1251 self->area.y, self->area.width, self->area.height);
1253 /* when the client has StaticGravity, it likes to move around.
1254 also this correctly positions the client when it maps.
1255 this also needs to be run when the frame's decorations sizes change!
1258 XMoveResizeWindow(obp_display, self->client->window,
1259 self->size.left, self->size.top, self->client_area.width,
1260 self->client_area.height);
1263 self->need_render = TRUE;
1264 frame_update_skin(self);
1265 frame_adjust_shape(self);
1268 if (!STRUT_EQUAL(self->size, oldsize)) {
1270 vals[0] = self->size.left;
1271 vals[1] = self->size.right;
1272 vals[2] = self->size.top;
1273 vals[3] = self->size.bottom;
1274 OBT_PROP_SETA32(self->client->window, NET_FRAME_EXTENTS, CARDINAL,
1276 OBT_PROP_SETA32(self->client->window, KDE_NET_WM_FRAME_STRUT,
1280 /* if this occurs while we are focus cycling, the indicator needs to
1281 match the changes */
1282 if (plugin.focus_cycle_target == self->client)
1283 focus_cycle_draw_indicator(self->client);
1285 if (is_resize && (self->decorations & OB_FRAME_DECOR_TITLEBAR))
1286 XResizeWindow(obp_display, self->label, self->label_width,
1287 theme_config.label_height);
1290 void frame_set_hover_flag(gpointer self, ObFrameButton button)
1292 if (OBDEFAULTFRAME(self)->hover_flag != button) {
1293 OBDEFAULTFRAME(self)->hover_flag = button;
1294 frame_update_skin(self);
1298 void frame_set_press_flag(gpointer self, ObFrameButton button)
1300 if (OBDEFAULTFRAME(self)->press_flag != button) {
1301 OBDEFAULTFRAME(self)->press_flag = button;
1302 frame_update_skin(self);
1306 Window frame_get_window(gpointer self)
1308 return OBDEFAULTFRAME(self)->window;
1311 Strut frame_get_size(gpointer self)
1313 return OBDEFAULTFRAME(self)->size;
1316 gint frame_get_decorations(gpointer self)
1318 return OBDEFAULTFRAME(self)->decorations;
1321 void frame_update_title (gpointer self, const gchar * src)
1323 g_free(OBDEFAULTFRAME(self)->stitle);
1324 OBDEFAULTFRAME(self)->stitle = g_strdup(src);
1327 gboolean frame_is_visible(gpointer self)
1329 return OBDEFAULTFRAME(self)->visible;
1332 gboolean frame_is_max_horz(gpointer self)
1334 return OBDEFAULTFRAME(self)->max_horz;
1337 gboolean frame_is_max_vert(gpointer self)
1339 return OBDEFAULTFRAME(self)->max_vert;
1342 gulong frame_animate_iconify_time_left(gpointer _self, const GTimeVal *now)
1344 ObDefaultFrame * self = (ObDefaultFrame *) _self;
1346 sec = self->iconify_animation_end.tv_sec - now->tv_sec;
1347 usec = self->iconify_animation_end.tv_usec - now->tv_usec;
1349 usec += G_USEC_PER_SEC;
1352 /* no negative values */
1353 return MAX(sec * G_USEC_PER_SEC + usec, 0);
1356 gboolean frame_animate_iconify(gpointer p)
1358 ObDefaultFrame *self = p;
1360 gint iconx, icony, iconw;
1363 gboolean iconifying;
1365 if (self->client->icon_geometry.width == 0) {
1366 /* there is no icon geometry set so just go straight down */
1368 screen_physical_area_monitor(screen_find_monitor(&self->area));
1369 iconx = self->area.x + self->area.width / 2 + 32;
1370 icony = a->y + a->width;
1375 iconx = self->client->icon_geometry.x;
1376 icony = self->client->icon_geometry.y;
1377 iconw = self->client->icon_geometry.width;
1380 iconifying = self->iconify_animation_going > 0;
1382 /* how far do we have left to go ? */
1383 g_get_current_time(&now);
1384 time = frame_animate_iconify_time_left(self, &now);
1386 if (time == 0 || iconifying) {
1387 /* start where the frame is supposed to be */
1390 w = self->area.width;
1391 h = self->area.height;
1394 /* start at the icon */
1398 h = self->size.top; /* just the titlebar */
1405 dx = self->area.x - iconx;
1406 dy = self->area.y - icony;
1407 dw = self->area.width - self->bwidth * 2 - iconw;
1408 /* if restoring, we move in the opposite direction */
1415 elapsed = FRAME_ANIMATE_ICONIFY_TIME - time;
1416 x = x - (dx * elapsed) / FRAME_ANIMATE_ICONIFY_TIME;
1417 y = y - (dy * elapsed) / FRAME_ANIMATE_ICONIFY_TIME;
1418 w = w - (dw * elapsed) / FRAME_ANIMATE_ICONIFY_TIME;
1419 h = self->size.top; /* just the titlebar */
1423 frame_end_iconify_animation(self);
1425 XMoveResizeWindow(obp_display, self->window, x, y, w, h);
1426 XFlush(obp_display);
1429 return time > 0; /* repeat until we're out of time */
1432 void frame_adjust_cursors(gpointer _self)
1434 ObDefaultFrame * self = (ObDefaultFrame *) _self;
1435 if ((self->functions & OB_CLIENT_FUNC_RESIZE) != (self->functions
1436 & OB_CLIENT_FUNC_RESIZE) || self->max_horz != self->max_horz
1437 || self->max_vert != self->max_vert || self->shaded != self->shaded) {
1438 gboolean r = (self->functions & OB_CLIENT_FUNC_RESIZE)
1439 && !(self->max_horz && self->max_vert);
1440 gboolean topbot = !self->max_vert;
1441 gboolean sh = self->shaded;
1442 XSetWindowAttributes a;
1444 /* these ones turn off when max vert, and some when shaded */
1445 a.cursor = ob_cursor(r && topbot && !sh ? OB_CURSOR_NORTH
1447 XChangeWindowAttributes(obp_display, self->topresize, CWCursor,
1449 XChangeWindowAttributes(obp_display, self->titletop, CWCursor, &a);
1450 a.cursor = ob_cursor(r && topbot ? OB_CURSOR_SOUTH : OB_CURSOR_NONE);
1451 XChangeWindowAttributes(obp_display, self->handle, CWCursor, &a);
1452 XChangeWindowAttributes(obp_display, self->handletop, CWCursor,
1454 XChangeWindowAttributes(obp_display, self->handlebottom,
1456 XChangeWindowAttributes(obp_display, self->innerbottom, CWCursor,
1459 /* these ones change when shaded */
1460 a.cursor = ob_cursor(r ? (sh ? OB_CURSOR_WEST : OB_CURSOR_NORTHWEST)
1462 XChangeWindowAttributes(obp_display, self->titleleft, CWCursor,
1464 XChangeWindowAttributes(obp_display, self->tltresize, CWCursor,
1466 XChangeWindowAttributes(obp_display, self->tllresize, CWCursor,
1468 XChangeWindowAttributes(obp_display, self->titletopleft,
1470 a.cursor = ob_cursor(r ? (sh ? OB_CURSOR_EAST : OB_CURSOR_NORTHEAST)
1472 XChangeWindowAttributes(obp_display, self->titleright, CWCursor,
1474 XChangeWindowAttributes(obp_display, self->trtresize, CWCursor,
1476 XChangeWindowAttributes(obp_display, self->trrresize, CWCursor,
1478 XChangeWindowAttributes(obp_display, self->titletopright,
1481 /* these ones are pretty static */
1482 a.cursor = ob_cursor(r ? OB_CURSOR_WEST : OB_CURSOR_NONE);
1483 XChangeWindowAttributes(obp_display, self->left, CWCursor, &a);
1484 XChangeWindowAttributes(obp_display, self->innerleft, CWCursor,
1486 a.cursor = ob_cursor(r ? OB_CURSOR_EAST : OB_CURSOR_NONE);
1487 XChangeWindowAttributes(obp_display, self->right, CWCursor, &a);
1488 XChangeWindowAttributes(obp_display, self->innerright, CWCursor,
1490 a.cursor = ob_cursor(r ? OB_CURSOR_SOUTHWEST : OB_CURSOR_NONE);
1491 XChangeWindowAttributes(obp_display, self->lgrip, CWCursor, &a);
1492 XChangeWindowAttributes(obp_display, self->handleleft, CWCursor,
1494 XChangeWindowAttributes(obp_display, self->lgripleft, CWCursor,
1496 XChangeWindowAttributes(obp_display, self->lgriptop, CWCursor, &a);
1497 XChangeWindowAttributes(obp_display, self->lgripbottom, CWCursor,
1499 XChangeWindowAttributes(obp_display, self->innerbll, CWCursor, &a);
1500 XChangeWindowAttributes(obp_display, self->innerblb, CWCursor, &a);
1501 a.cursor = ob_cursor(r ? OB_CURSOR_SOUTHEAST : OB_CURSOR_NONE);
1502 XChangeWindowAttributes(obp_display, self->rgrip, CWCursor, &a);
1503 XChangeWindowAttributes(obp_display, self->handleright, CWCursor,
1505 XChangeWindowAttributes(obp_display, self->rgripright, CWCursor,
1507 XChangeWindowAttributes(obp_display, self->rgriptop, CWCursor, &a);
1508 XChangeWindowAttributes(obp_display, self->rgripbottom, CWCursor,
1510 XChangeWindowAttributes(obp_display, self->innerbrr, CWCursor, &a);
1511 XChangeWindowAttributes(obp_display, self->innerbrb, CWCursor, &a);
1515 void frame_adjust_client_area(gpointer _self)
1517 ObDefaultFrame * self = (ObDefaultFrame *) _self;
1518 /* adjust the window which is there to prevent flashing on unmap */
1519 XMoveResizeWindow(obp_display, self->backfront, 0, 0,
1520 self->client_area.width, self->client_area.height);
1523 void frame_adjust_state(gpointer _self)
1525 ObDefaultFrame * self = (ObDefaultFrame *) _self;
1526 self->need_render = TRUE;
1527 frame_update_skin(self);
1530 void frame_adjust_focus(gpointer _self, gboolean hilite)
1532 ObDefaultFrame * self = (ObDefaultFrame *) _self;
1533 self->focused = hilite;
1534 self->need_render = TRUE;
1535 frame_update_skin(self);
1536 XFlush(obp_display);
1539 void frame_adjust_title(gpointer _self)
1541 ObDefaultFrame * self = (ObDefaultFrame *) _self;
1542 self->need_render = TRUE;
1543 frame_update_skin(self);
1546 void frame_adjust_icon(gpointer _self)
1548 ObDefaultFrame * self = (ObDefaultFrame *) _self;
1549 self->need_render = TRUE;
1550 frame_update_skin(self);
1553 /* is there anything present between us and the label? */
1554 static gboolean is_button_present(ObDefaultFrame *_self, const gchar *lc,
1557 ObDefaultFrame * self = (ObDefaultFrame *) _self;
1558 for (; *lc != '\0' && lc >= plugin.config_title_layout; lc += dir) {
1560 continue; /* it was invalid */
1561 if (*lc == 'N' && self->decorations & OB_FRAME_DECOR_ICON)
1563 if (*lc == 'D' && self->decorations & OB_FRAME_DECOR_ALLDESKTOPS)
1565 if (*lc == 'S' && self->decorations & OB_FRAME_DECOR_SHADE)
1567 if (*lc == 'I' && self->decorations & OB_FRAME_DECOR_ICONIFY)
1569 if (*lc == 'M' && self->decorations & OB_FRAME_DECOR_MAXIMIZE)
1571 if (*lc == 'C' && self->decorations & OB_FRAME_DECOR_CLOSE)
1579 void flash_done(gpointer data)
1581 ObDefaultFrame *self = data;
1583 if (self->focused != self->flash_on)
1584 frame_adjust_focus(self, self->focused);
1587 gboolean flash_timeout(gpointer data)
1589 ObDefaultFrame *self = data;
1592 g_get_current_time(&now);
1593 if (now.tv_sec > self->flash_end.tv_sec
1594 || (now.tv_sec == self->flash_end.tv_sec && now.tv_usec
1595 >= self->flash_end.tv_usec))
1596 self->flashing = FALSE;
1598 if (!self->flashing)
1599 return FALSE; /* we are done */
1601 self->flash_on = !self->flash_on;
1602 if (!self->focused) {
1603 frame_adjust_focus(self, self->flash_on);
1604 self->focused = FALSE;
1607 return TRUE; /* go again */
1610 void layout_title(ObDefaultFrame * self)
1615 const gint bwidth = theme_config.button_size + theme_config.paddingx + 1;
1616 /* position of the left most button */
1617 const gint left = theme_config.paddingx + 1;
1618 /* position of the right most button */
1619 const gint right = self->width;
1621 /* turn them all off */
1622 self->icon_on = self->desk_on = self->shade_on = self->iconify_on
1623 = self->max_on = self->close_on = self->label_on = FALSE;
1624 self->label_width = self->width - (theme_config.paddingx + 1) * 2;
1625 self->leftmost = self->rightmost = OB_FRAME_CONTEXT_NONE;
1627 /* figure out what's being show, find each element's position, and the
1630 do the ones before the label, then after the label,
1631 i will be +1 the first time through when working to the left,
1632 and -1 the second time through when working to the right */
1633 for (i = 1; i >= -1; i-=2) {
1635 ObFrameContext *firstcon;
1639 lc = plugin.config_title_layout;
1640 firstcon = &self->leftmost;
1644 lc = plugin.config_title_layout
1645 + strlen(plugin.config_title_layout)-1;
1646 firstcon = &self->rightmost;
1649 /* stop at the end of the string (or the label, which calls break) */
1650 for (; *lc != '\0' && lc >= plugin.config_title_layout; lc+=i) {
1653 self->label_on = TRUE;
1656 break; /* break the for loop, do other side of label */
1658 else if (*lc == 'N') {
1660 *firstcon = OB_FRAME_CONTEXT_ICON;
1661 if ((self->icon_on = is_button_present(self, lc, i))) {
1662 /* icon is bigger than buttons */
1663 self->label_width -= bwidth + 2;
1666 x += i * (bwidth + 2);
1671 else if (*lc == 'D') {
1673 *firstcon = OB_FRAME_CONTEXT_ALLDESKTOPS;
1674 if ((self->desk_on = is_button_present(self, lc, i))) {
1675 self->label_width -= bwidth;
1683 else if (*lc == 'S') {
1685 *firstcon = OB_FRAME_CONTEXT_SHADE;
1686 if ((self->shade_on = is_button_present(self, lc, i))) {
1687 self->label_width -= bwidth;
1695 else if (*lc == 'I') {
1697 *firstcon = OB_FRAME_CONTEXT_ICONIFY;
1698 if ((self->iconify_on = is_button_present(self, lc, i))) {
1699 self->label_width -= bwidth;
1701 self->iconify_x = x;
1704 self->iconify_x = x;
1707 else if (*lc == 'M') {
1709 *firstcon = OB_FRAME_CONTEXT_MAXIMIZE;
1710 if ((self->max_on = is_button_present(self, lc, i))) {
1711 self->label_width -= bwidth;
1719 else if (*lc == 'C') {
1721 *firstcon = OB_FRAME_CONTEXT_CLOSE;
1722 if ((self->close_on = is_button_present(self, lc, i))) {
1723 self->label_width -= bwidth;
1732 continue; /* don't set firstcon */
1737 /* position and map the elements */
1738 if (self->icon_on) {
1739 XMapWindow(obp_display, self->icon);
1740 XMoveWindow(obp_display, self->icon, self->icon_x,
1741 theme_config.paddingy);
1744 XUnmapWindow(obp_display, self->icon);
1746 if (self->desk_on) {
1747 XMapWindow(obp_display, self->desk);
1748 XMoveWindow(obp_display, self->desk, self->desk_x,
1749 theme_config.paddingy + 1);
1752 XUnmapWindow(obp_display, self->desk);
1754 if (self->shade_on) {
1755 XMapWindow(obp_display, self->shade);
1756 XMoveWindow(obp_display, self->shade, self->shade_x,
1757 theme_config.paddingy + 1);
1760 XUnmapWindow(obp_display, self->shade);
1762 if (self->iconify_on) {
1763 XMapWindow(obp_display, self->iconify);
1764 XMoveWindow(obp_display, self->iconify, self->iconify_x,
1765 theme_config.paddingy + 1);
1768 XUnmapWindow(obp_display, self->iconify);
1771 XMapWindow(obp_display, self->max);
1772 XMoveWindow(obp_display, self->max, self->max_x,
1773 theme_config.paddingy + 1);
1776 XUnmapWindow(obp_display, self->max);
1778 if (self->close_on) {
1779 XMapWindow(obp_display, self->close);
1780 XMoveWindow(obp_display, self->close, self->close_x,
1781 theme_config.paddingy + 1);
1784 XUnmapWindow(obp_display, self->close);
1786 if (self->label_on) {
1787 self->label_width = MAX(1, self->label_width); /* no lower than 1 */
1788 XMapWindow(obp_display, self->label);
1789 XMoveWindow(obp_display, self->label, self->label_x,
1790 theme_config.paddingy);
1793 XUnmapWindow(obp_display, self->label);
1796 void trigger_none (gpointer self) {}
1797 void trigger_iconify(gpointer self) {}
1798 void trigger_uniconnity(gpointer self) {}
1799 void trigger_iconify_toggle(gpointer self) {}
1800 void trigger_shade(gpointer self) {}
1801 void trigger_unshade(gpointer self) {}
1802 void trigger_shade_toggle(gpointer self) {}
1803 void trigger_max(gpointer self) {}
1804 void trigger_unmax(gpointer self) {}
1805 void trigger_max_troggle(gpointer self) {}
1806 void trigger_max_vert(gpointer self) {OBDEFAULTFRAME(self)->max_vert = TRUE;}
1807 void trigger_unmax_vert(gpointer self) {OBDEFAULTFRAME(self)->max_vert = FALSE;}
1808 void trigger_max_toggle(gpointer self) {}
1809 void trigger_max_horz(gpointer self) {OBDEFAULTFRAME(self)->max_horz = TRUE;}
1810 void trigger_unmax_horz(gpointer self) {OBDEFAULTFRAME(self)->max_horz = FALSE;}
1811 void trigger_max_horz_toggle(gpointer self) {}
1812 void trigger_plugin1(gpointer self) {}
1813 void trigger_plugin2(gpointer self) {}
1814 void trigger_plugin3(gpointer self) {}
1815 void trigger_plugin4(gpointer self) {}
1816 void trigger_plugin5(gpointer self) {}
1817 void trigger_plugin6(gpointer self) {}
1818 void trigger_plugin7(gpointer self) {}
1819 void trigger_plugin8(gpointer self) {}
1820 void trigger_plugin9(gpointer self) {}
1822 void frame_trigger(gpointer self, ObFrameTrigger trigger_name)
1825 static void (*trigger_func[64])(gpointer) = {
1829 trigger_iconify_toggle,
1832 trigger_shade_toggle,
1835 trigger_max_troggle,
1841 trigger_max_horz_toggle,
1854 void (*call_trigger_func)(gpointer) = trigger_func[trigger_name];
1855 if(!call_trigger_func)
1857 call_trigger_func (self);
1861 ObFramePlugin plugin = {
1862 0, /* gpointer handler */
1863 "libdefault.la", /* gchar * filename */
1864 "Default", /* gchar * name */
1865 init, //gint (*init) (Display * display, gint screen);
1867 frame_new, //gpointer (*frame_new) (struct _ObClient *c);
1868 frame_free, //void (*frame_free) (gpointer self);
1869 frame_show, //void (*frame_show) (gpointer self);
1870 frame_hide, //void (*frame_hide) (gpointer self);
1871 frame_adjust_theme, //void (*frame_adjust_theme) (gpointer self);
1872 frame_adjust_shape, //void (*frame_adjust_shape) (gpointer self);
1873 frame_grab, //void (*frame_adjust_area) (gpointer self, gboolean moved, gboolean resized, gboolean fake);
1874 frame_ungrab, frame_context, //void (*frame_adjust_state) (gpointer self);
1875 frame_set_is_visible, /* */
1876 frame_set_is_focus, /* */
1877 frame_set_is_max_vert, /* */
1878 frame_set_is_max_horz, /* */
1879 frame_set_is_shaded, /* */
1881 frame_flash_start, /* */
1882 frame_flash_stop, /* */
1883 frame_begin_iconify_animation, /* */
1884 frame_end_iconify_animation, /* */
1885 frame_iconify_animating, /* */
1887 frame_set_decorations, /* */
1889 frame_update_title, /* */
1890 /* This give the window area */
1891 frame_get_window_area, /* */
1892 frame_set_client_area, /* */
1893 /* Draw the frame */
1894 frame_update_layout, /* */
1895 frame_update_skin, /* */
1897 frame_set_hover_flag, /* */
1898 frame_set_press_flag, /* */
1900 frame_get_window,/* */
1902 frame_get_size, /* */
1903 frame_get_decorations, /* */
1905 frame_is_visible, /* */
1906 frame_is_max_horz, /* */
1907 frame_is_max_vert, /* */
1909 frame_trigger, /* */
1911 load_theme_config, /* */
1913 /* This fields are fill by openbox. */
1914 //0, //Display * ob_display;
1915 //0, //gint ob_screen;
1916 //0, //RrInstance *ob_rr_inst;
1917 0, //gboolean config_theme_keepborder;
1918 0, //struct _ObClient *focus_cycle_target;
1919 0, //gchar *config_title_layout;
1920 FALSE, //gboolean moveresize_in_progress;
1921 0, //struct _ObMainLoop *ob_main_loop;
1924 ObFramePlugin * get_info()