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->w_client, &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, Window w_client, Window w_frame)
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, obp_screen), visual,
119 attrib.background_pixel = BlackPixel(obp_display, obp_screen);
120 attrib.border_pixel = BlackPixel(obp_display, obp_screen);
122 self->window = createWindow(RootWindow(obp_display, obp_screen), visual,
125 /* create the visible decor windows */
129 /* client has a 32-bit visual */
130 mask |= CWColormap | CWBackPixel | CWBorderPixel;
131 attrib.colormap = RrColormap(ob_rr_inst);
134 self->backback = createWindow(self->window, NULL, mask, &attrib);
135 self->backfront = createWindow(self->backback, NULL, mask, &attrib);
138 attrib.event_mask = ELEMENT_EVENTMASK;
139 self->innerleft = createWindow(self->window, NULL, mask, &attrib);
140 self->innertop = createWindow(self->window, NULL, mask, &attrib);
141 self->innerright = createWindow(self->window, NULL, mask, &attrib);
142 self->innerbottom = createWindow(self->window, NULL, mask, &attrib);
144 self->innerblb = createWindow(self->innerbottom, NULL, mask, &attrib);
145 self->innerbrb = createWindow(self->innerbottom, NULL, mask, &attrib);
146 self->innerbll = createWindow(self->innerleft, NULL, mask, &attrib);
147 self->innerbrr = createWindow(self->innerright, NULL, mask, &attrib);
149 self->title = createWindow(self->window, NULL, mask, &attrib);
150 self->titleleft = createWindow(self->window, NULL, mask, &attrib);
151 self->titletop = createWindow(self->window, NULL, mask, &attrib);
152 self->titletopleft = createWindow(self->window, NULL, mask, &attrib);
153 self->titletopright = createWindow(self->window, NULL, mask, &attrib);
154 self->titleright = createWindow(self->window, NULL, mask, &attrib);
155 self->titlebottom = createWindow(self->window, NULL, mask, &attrib);
157 self->topresize = createWindow(self->title, NULL, mask, &attrib);
158 self->tltresize = createWindow(self->title, NULL, mask, &attrib);
159 self->tllresize = createWindow(self->title, NULL, mask, &attrib);
160 self->trtresize = createWindow(self->title, NULL, mask, &attrib);
161 self->trrresize = createWindow(self->title, NULL, mask, &attrib);
163 self->left = createWindow(self->window, NULL, mask, &attrib);
164 self->right = createWindow(self->window, NULL, mask, &attrib);
166 self->label = createWindow(self->title, NULL, mask, &attrib);
167 self->max = createWindow(self->title, NULL, mask, &attrib);
168 self->close = createWindow(self->title, NULL, mask, &attrib);
169 self->desk = createWindow(self->title, NULL, mask, &attrib);
170 self->shade = createWindow(self->title, NULL, mask, &attrib);
171 self->icon = createWindow(self->title, NULL, mask, &attrib);
172 self->iconify = createWindow(self->title, NULL, mask, &attrib);
174 self->handle = createWindow(self->window, NULL, mask, &attrib);
175 self->lgrip = createWindow(self->handle, NULL, mask, &attrib);
176 self->rgrip = createWindow(self->handle, NULL, mask, &attrib);
178 self->handleleft = createWindow(self->handle, NULL, mask, &attrib);
179 self->handleright = createWindow(self->handle, NULL, mask, &attrib);
181 self->handletop = createWindow(self->window, NULL, mask, &attrib);
182 self->handlebottom = createWindow(self->window, NULL, mask, &attrib);
183 self->lgripleft = createWindow(self->window, NULL, mask, &attrib);
184 self->lgriptop = createWindow(self->window, NULL, mask, &attrib);
185 self->lgripbottom = createWindow(self->window, NULL, mask, &attrib);
186 self->rgripright = createWindow(self->window, NULL, mask, &attrib);
187 self->rgriptop = createWindow(self->window, NULL, mask, &attrib);
188 self->rgripbottom = createWindow(self->window, NULL, mask, &attrib);
190 self->stitle = g_strdup("");
191 self->focused = FALSE;
193 /* the other stuff is shown based on decor settings */
194 XMapWindow(obp_display, self->label);
195 XMapWindow(obp_display, self->backback);
196 XMapWindow(obp_display, self->backfront);
198 self->hover_flag = OB_BUTTON_NONE;
199 self->press_flag = OB_BUTTON_NONE;
201 set_theme_statics(self);
206 void set_theme_statics(gpointer _self)
208 ObDefaultFrame * self = (ObDefaultFrame *) _self;
209 /* set colors/appearance/sizes for stuff that doesn't change */
210 XResizeWindow(obp_display, self->max, theme_config.button_size,
211 theme_config.button_size);
212 XResizeWindow(obp_display, self->iconify, theme_config.button_size,
213 theme_config.button_size);
214 XResizeWindow(obp_display, self->icon, theme_config.button_size + 2,
215 theme_config.button_size + 2);
216 XResizeWindow(obp_display, self->close, theme_config.button_size,
217 theme_config.button_size);
218 XResizeWindow(obp_display, self->desk, theme_config.button_size,
219 theme_config.button_size);
220 XResizeWindow(obp_display, self->shade, theme_config.button_size,
221 theme_config.button_size);
222 XResizeWindow(obp_display, self->tltresize, theme_config.grip_width,
223 theme_config.paddingy + 1);
224 XResizeWindow(obp_display, self->trtresize, theme_config.grip_width,
225 theme_config.paddingy + 1);
226 XResizeWindow(obp_display, self->tllresize, theme_config.paddingx + 1,
227 theme_config.title_height);
228 XResizeWindow(obp_display, self->trrresize, theme_config.paddingx + 1,
229 theme_config.title_height);
231 /* set up the dynamic appearances */
232 self->a_unfocused_title = RrAppearanceCopy(theme_config.a_unfocused_title);
233 self->a_focused_title = RrAppearanceCopy(theme_config.a_focused_title);
234 self->a_unfocused_label = RrAppearanceCopy(theme_config.a_unfocused_label);
235 self->a_focused_label = RrAppearanceCopy(theme_config.a_focused_label);
236 self->a_unfocused_handle
237 = RrAppearanceCopy(theme_config.a_unfocused_handle);
238 self->a_focused_handle = RrAppearanceCopy(theme_config.a_focused_handle);
239 self->a_icon = RrAppearanceCopy(theme_config.a_icon);
242 void free_theme_statics(gpointer _self)
244 ObDefaultFrame * self = (ObDefaultFrame *) _self;
245 RrAppearanceFree(self->a_unfocused_title);
246 RrAppearanceFree(self->a_focused_title);
247 RrAppearanceFree(self->a_unfocused_label);
248 RrAppearanceFree(self->a_focused_label);
249 RrAppearanceFree(self->a_unfocused_handle);
250 RrAppearanceFree(self->a_focused_handle);
251 RrAppearanceFree(self->a_icon);
254 void frame_free(gpointer self)
256 free_theme_statics(OBDEFAULTFRAME(self));
257 XDestroyWindow(obp_display, OBDEFAULTFRAME(self)->window);
258 if (OBDEFAULTFRAME(self)->colormap)
259 XFreeColormap(obp_display, OBDEFAULTFRAME(self)->colormap);
261 g_free(OBDEFAULTFRAME(self)->stitle);
265 void frame_show(gpointer _self)
267 ObDefaultFrame * self = (ObDefaultFrame *) _self;
268 if (!self->visible) {
269 self->visible = TRUE;
270 frame_update_skin(self);
271 /* Grab the server to make sure that the frame window is mapped before
272 the client gets its MapNotify, i.e. to make sure the client is
273 _visible_ when it gets MapNotify. */
275 XMapWindow(obp_display, self->client->w_client);
276 XMapWindow(obp_display, self->window);
281 gint frame_hide(gpointer self)
283 if (OBDEFAULTFRAME(self)->visible) {
284 OBDEFAULTFRAME(self)->visible = FALSE;
285 if (!frame_iconify_animating(self))
286 XUnmapWindow(obp_display, OBDEFAULTFRAME(self)->window);
287 /* we unmap the client itself so that we can get MapRequest
288 events, and because the ICCCM tells us to! */
289 XUnmapWindow(obp_display, OBDEFAULTFRAME(self)->client->w_client);
297 void frame_adjust_theme(gpointer self)
299 free_theme_statics(self);
300 set_theme_statics(self);
303 void frame_adjust_shape(gpointer _self)
306 ObDefaultFrame * self = (ObDefaultFrame *) _self;
310 if (!self->client->shaped)
312 /* clear the shape on the frame window */
313 XShapeCombineMask(obp_display, self->window, ShapeBounding,
320 /* make the frame's shape match the clients */
321 XShapeCombineShape(obp_display, self->window, ShapeBounding,
324 self->client->w_client,
325 ShapeBounding, ShapeSet);
328 if (self->decorations & OB_FRAME_DECOR_TITLEBAR)
332 xrect[0].width = self->area.width;
333 xrect[0].height = self->size.top;
337 if (self->decorations & OB_FRAME_DECOR_HANDLE &&
338 theme_config.handle_height> 0)
341 xrect[1].y = FRAME_HANDLE_Y(self);
342 xrect[1].width = self->area.width;
343 xrect[1].height = theme_config.handle_height +
348 XShapeCombineRectangles(obp_display, self->window,
349 ShapeBounding, 0, 0, xrect, num,
350 ShapeUnion, Unsorted);
355 void frame_grab(gpointer _self, GHashTable * window_map)
357 ObDefaultFrame * self = (ObDefaultFrame *) _self;
358 /* DO NOT map the client window here. we used to do that, but it is bogus.
359 we need to set up the client's dimensions and everything before we
360 send a mapnotify or we create race conditions.
363 /* reparent the client to the frame */
364 XReparentWindow(obp_display, self->client->w_client, self->window, 0, 0);
367 When reparenting the client window, it is usually not mapped yet, since
368 this occurs from a MapRequest. However, in the case where Openbox is
369 starting up, the window is already mapped, so we'll see an unmap event
372 if (ob_state() == OB_STATE_STARTING)
373 ++self->client->ignore_unmaps;
375 /* select the event mask on the client's parent (to receive config/map
376 req's) the ButtonPress is to catch clicks on the client border */
377 XSelectInput(obp_display, self->window, FRAME_EVENTMASK);
379 /* set all the windows for the frame in the window_map */
380 g_hash_table_insert(window_map, &self->window, self->client);
381 g_hash_table_insert(window_map, &self->backback, self->client);
382 g_hash_table_insert(window_map, &self->backfront, self->client);
383 g_hash_table_insert(window_map, &self->innerleft, self->client);
384 g_hash_table_insert(window_map, &self->innertop, self->client);
385 g_hash_table_insert(window_map, &self->innerright, self->client);
386 g_hash_table_insert(window_map, &self->innerbottom, self->client);
387 g_hash_table_insert(window_map, &self->title, self->client);
388 g_hash_table_insert(window_map, &self->label, self->client);
389 g_hash_table_insert(window_map, &self->max, self->client);
390 g_hash_table_insert(window_map, &self->close, self->client);
391 g_hash_table_insert(window_map, &self->desk, self->client);
392 g_hash_table_insert(window_map, &self->shade, self->client);
393 g_hash_table_insert(window_map, &self->icon, self->client);
394 g_hash_table_insert(window_map, &self->iconify, self->client);
395 g_hash_table_insert(window_map, &self->handle, self->client);
396 g_hash_table_insert(window_map, &self->lgrip, self->client);
397 g_hash_table_insert(window_map, &self->rgrip, self->client);
398 g_hash_table_insert(window_map, &self->topresize, self->client);
399 g_hash_table_insert(window_map, &self->tltresize, self->client);
400 g_hash_table_insert(window_map, &self->tllresize, self->client);
401 g_hash_table_insert(window_map, &self->trtresize, self->client);
402 g_hash_table_insert(window_map, &self->trrresize, self->client);
403 g_hash_table_insert(window_map, &self->left, self->client);
404 g_hash_table_insert(window_map, &self->right, self->client);
405 g_hash_table_insert(window_map, &self->titleleft, self->client);
406 g_hash_table_insert(window_map, &self->titletop, self->client);
407 g_hash_table_insert(window_map, &self->titletopleft, self->client);
408 g_hash_table_insert(window_map, &self->titletopright, self->client);
409 g_hash_table_insert(window_map, &self->titleright, self->client);
410 g_hash_table_insert(window_map, &self->titlebottom, self->client);
411 g_hash_table_insert(window_map, &self->handleleft, self->client);
412 g_hash_table_insert(window_map, &self->handletop, self->client);
413 g_hash_table_insert(window_map, &self->handleright, self->client);
414 g_hash_table_insert(window_map, &self->handlebottom, self->client);
415 g_hash_table_insert(window_map, &self->lgripleft, self->client);
416 g_hash_table_insert(window_map, &self->lgriptop, self->client);
417 g_hash_table_insert(window_map, &self->lgripbottom, self->client);
418 g_hash_table_insert(window_map, &self->rgripright, self->client);
419 g_hash_table_insert(window_map, &self->rgriptop, self->client);
420 g_hash_table_insert(window_map, &self->rgripbottom, self->client);
423 void frame_ungrab(gpointer _self, GHashTable * window_map)
425 ObDefaultFrame * self = (ObDefaultFrame *) _self;
427 gboolean reparent = TRUE;
429 /* if there was any animation going on, kill it */
430 obt_main_loop_timeout_remove_data(plugin.ob_main_loop,
431 frame_animate_iconify, self, FALSE);
433 /* check if the app has already reparented its window away */
434 while (XCheckTypedWindowEvent(obp_display, self->client->w_client,
435 ReparentNotify, &ev)) {
436 /* This check makes sure we don't catch our own reparent action to
437 our frame window. This doesn't count as the app reparenting itself
440 Reparent events that are generated by us are just discarded here.
441 They are of no consequence to us anyhow.
443 if (ev.xreparent.parent != self->window) {
445 XPutBackEvent(obp_display, &ev);
451 /* according to the ICCCM - if the client doesn't reparent itself,
452 then we will reparent the window to root for them */
453 XReparentWindow(obp_display, self->client->w_client, RootWindow(
454 obp_display, obp_screen), self->client_area.x,
455 self->client_area.y);
458 /* remove all the windows for the frame from the window_map */
459 g_hash_table_remove(window_map, &self->window);
460 g_hash_table_remove(window_map, &self->backback);
461 g_hash_table_remove(window_map, &self->backfront);
462 g_hash_table_remove(window_map, &self->innerleft);
463 g_hash_table_remove(window_map, &self->innertop);
464 g_hash_table_remove(window_map, &self->innerright);
465 g_hash_table_remove(window_map, &self->innerbottom);
466 g_hash_table_remove(window_map, &self->title);
467 g_hash_table_remove(window_map, &self->label);
468 g_hash_table_remove(window_map, &self->max);
469 g_hash_table_remove(window_map, &self->close);
470 g_hash_table_remove(window_map, &self->desk);
471 g_hash_table_remove(window_map, &self->shade);
472 g_hash_table_remove(window_map, &self->icon);
473 g_hash_table_remove(window_map, &self->iconify);
474 g_hash_table_remove(window_map, &self->handle);
475 g_hash_table_remove(window_map, &self->lgrip);
476 g_hash_table_remove(window_map, &self->rgrip);
477 g_hash_table_remove(window_map, &self->topresize);
478 g_hash_table_remove(window_map, &self->tltresize);
479 g_hash_table_remove(window_map, &self->tllresize);
480 g_hash_table_remove(window_map, &self->trtresize);
481 g_hash_table_remove(window_map, &self->trrresize);
482 g_hash_table_remove(window_map, &self->left);
483 g_hash_table_remove(window_map, &self->right);
484 g_hash_table_remove(window_map, &self->titleleft);
485 g_hash_table_remove(window_map, &self->titletop);
486 g_hash_table_remove(window_map, &self->titletopleft);
487 g_hash_table_remove(window_map, &self->titletopright);
488 g_hash_table_remove(window_map, &self->titleright);
489 g_hash_table_remove(window_map, &self->titlebottom);
490 g_hash_table_remove(window_map, &self->handleleft);
491 g_hash_table_remove(window_map, &self->handletop);
492 g_hash_table_remove(window_map, &self->handleright);
493 g_hash_table_remove(window_map, &self->handlebottom);
494 g_hash_table_remove(window_map, &self->lgripleft);
495 g_hash_table_remove(window_map, &self->lgriptop);
496 g_hash_table_remove(window_map, &self->lgripbottom);
497 g_hash_table_remove(window_map, &self->rgripright);
498 g_hash_table_remove(window_map, &self->rgriptop);
499 g_hash_table_remove(window_map, &self->rgripbottom);
501 obt_main_loop_timeout_remove_data(plugin.ob_main_loop, flash_timeout, self,
505 ObFrameContext frame_context(gpointer _self, Window win, gint x, gint y)
507 ObDefaultFrame * self = OBDEFAULTFRAME(_self);
509 /* when the user clicks in the corners of the titlebar and the client
510 is fully maximized, then treat it like they clicked in the
511 button that is there */
512 if (self->max_horz && self->max_vert && (win == self->title || win
513 == self->titletop || win == self->titleleft || win
514 == self->titletopleft || win == self->titleright || win
515 == self->titletopright)) {
516 /* get the mouse coords in reference to the whole frame */
520 /* these windows are down a border width from the top of the frame */
521 if (win == self->title || win == self->titleleft || win
525 /* title is a border width in from the edge */
526 if (win == self->title)
528 /* titletop is a bit to the right */
529 else if (win == self->titletop)
530 fx += theme_config.grip_width + self->bwidth;
531 /* titletopright is way to the right edge */
532 else if (win == self->titletopright)
533 fx += self->area.width - (theme_config.grip_width + self->bwidth);
534 /* titleright is even more way to the right edge */
535 else if (win == self->titleright)
536 fx += self->area.width - self->bwidth;
538 /* figure out if we're over the area that should be considered a
540 if (fy < self->bwidth + theme_config.paddingy + 1
541 + theme_config.button_size) {
542 if (fx < (self->bwidth + theme_config.paddingx + 1
543 + theme_config.button_size)) {
544 if (self->leftmost != OB_FRAME_CONTEXT_NONE)
545 return self->leftmost;
547 else if (fx >= (self->area.width - (self->bwidth
548 + theme_config.paddingx + 1 + theme_config.button_size))) {
549 if (self->rightmost != OB_FRAME_CONTEXT_NONE)
550 return self->rightmost;
554 /* there is no resizing maximized windows so make them the titlebar
556 return OB_FRAME_CONTEXT_TITLEBAR;
558 else if (self->max_vert
559 && (win == self->titletop || win == self->topresize))
560 /* can't resize vertically when max vert */
561 return OB_FRAME_CONTEXT_TITLEBAR;
562 else if (self->shaded && (win == self->titletop || win == self->topresize))
563 /* can't resize vertically when shaded */
564 return OB_FRAME_CONTEXT_TITLEBAR;
566 if (win == self->window)
567 return OB_FRAME_CONTEXT_FRAME;
568 if (win == self->label)
569 return OB_FRAME_CONTEXT_TITLEBAR;
570 if (win == self->handle)
571 return OB_FRAME_CONTEXT_BOTTOM;
572 if (win == self->handletop)
573 return OB_FRAME_CONTEXT_BOTTOM;
574 if (win == self->handlebottom)
575 return OB_FRAME_CONTEXT_BOTTOM;
576 if (win == self->handleleft)
577 return OB_FRAME_CONTEXT_BLCORNER;
578 if (win == self->lgrip)
579 return OB_FRAME_CONTEXT_BLCORNER;
580 if (win == self->lgripleft)
581 return OB_FRAME_CONTEXT_BLCORNER;
582 if (win == self->lgriptop)
583 return OB_FRAME_CONTEXT_BLCORNER;
584 if (win == self->lgripbottom)
585 return OB_FRAME_CONTEXT_BLCORNER;
586 if (win == self->handleright)
587 return OB_FRAME_CONTEXT_BRCORNER;
588 if (win == self->rgrip)
589 return OB_FRAME_CONTEXT_BRCORNER;
590 if (win == self->rgripright)
591 return OB_FRAME_CONTEXT_BLCORNER;
592 if (win == self->rgriptop)
593 return OB_FRAME_CONTEXT_BLCORNER;
594 if (win == self->rgripbottom)
595 return OB_FRAME_CONTEXT_BLCORNER;
596 if (win == self->title)
597 return OB_FRAME_CONTEXT_TITLEBAR;
598 if (win == self->titlebottom)
599 return OB_FRAME_CONTEXT_TITLEBAR;
600 if (win == self->titleleft)
601 return OB_FRAME_CONTEXT_TLCORNER;
602 if (win == self->titletopleft)
603 return OB_FRAME_CONTEXT_TLCORNER;
604 if (win == self->titleright)
605 return OB_FRAME_CONTEXT_TRCORNER;
606 if (win == self->titletopright)
607 return OB_FRAME_CONTEXT_TRCORNER;
608 if (win == self->titletop)
609 return OB_FRAME_CONTEXT_TOP;
610 if (win == self->topresize)
611 return OB_FRAME_CONTEXT_TOP;
612 if (win == self->tltresize)
613 return OB_FRAME_CONTEXT_TLCORNER;
614 if (win == self->tllresize)
615 return OB_FRAME_CONTEXT_TLCORNER;
616 if (win == self->trtresize)
617 return OB_FRAME_CONTEXT_TRCORNER;
618 if (win == self->trrresize)
619 return OB_FRAME_CONTEXT_TRCORNER;
620 if (win == self->left)
621 return OB_FRAME_CONTEXT_LEFT;
622 if (win == self->right)
623 return OB_FRAME_CONTEXT_RIGHT;
624 if (win == self->innertop)
625 return OB_FRAME_CONTEXT_TITLEBAR;
626 if (win == self->innerleft)
627 return OB_FRAME_CONTEXT_LEFT;
628 if (win == self->innerbottom)
629 return OB_FRAME_CONTEXT_BOTTOM;
630 if (win == self->innerright)
631 return OB_FRAME_CONTEXT_RIGHT;
632 if (win == self->max)
633 return OB_FRAME_CONTEXT_MAXIMIZE;
634 if (win == self->iconify)
635 return OB_FRAME_CONTEXT_ICONIFY;
636 if (win == self->close)
637 return OB_FRAME_CONTEXT_CLOSE;
638 if (win == self->icon)
639 return OB_FRAME_CONTEXT_ICON;
640 if (win == self->desk)
641 return OB_FRAME_CONTEXT_ALLDESKTOPS;
642 if (win == self->shade)
643 return OB_FRAME_CONTEXT_SHADE;
645 return OB_FRAME_CONTEXT_NONE;
648 void frame_set_is_visible(gpointer self, gboolean b)
650 OBDEFAULTFRAME(self)->visible = b;
653 void frame_set_is_focus(gpointer self, gboolean b)
655 OBDEFAULTFRAME(self)->focused = b;
658 void frame_set_is_max_vert(gpointer self, gboolean b)
660 OBDEFAULTFRAME(self)->max_vert = b;
663 void frame_set_is_max_horz(gpointer self, gboolean b)
665 OBDEFAULTFRAME(self)->max_horz = b;
668 void frame_set_is_shaded(gpointer self, gboolean b)
670 OBDEFAULTFRAME(self)->shaded = b;
673 void frame_unfocus(gpointer self)
675 OBDEFAULTFRAME(self)->focused = FALSE;
678 void frame_flash_start(gpointer _self)
680 ObDefaultFrame * self = (ObDefaultFrame *) _self;
681 self->flash_on = self->focused;
684 obt_main_loop_timeout_add(plugin.ob_main_loop, G_USEC_PER_SEC * 0.6,
685 flash_timeout, self, g_direct_equal, flash_done);
686 g_get_current_time(&self->flash_end);
687 g_time_val_add(&self->flash_end, G_USEC_PER_SEC * 5);
689 self->flashing = TRUE;
692 void frame_flash_stop(gpointer _self)
694 ObDefaultFrame * self = (ObDefaultFrame *) _self;
695 self->flashing = FALSE;
698 void frame_begin_iconify_animation(gpointer _self, gboolean iconifying)
700 ObDefaultFrame * self = (ObDefaultFrame *) _self;
702 gboolean new_anim = FALSE;
703 gboolean set_end = TRUE;
706 /* if there is no titlebar, just don't animate for now
707 XXX it would be nice tho.. */
708 if (!(self->decorations & OB_FRAME_DECOR_TITLEBAR))
711 /* get the current time */
712 g_get_current_time(&now);
714 /* get how long until the end */
715 time = FRAME_ANIMATE_ICONIFY_TIME;
716 if (self->iconify_animation_going) {
717 if (!!iconifying != (self->iconify_animation_going > 0)) {
718 /* animation was already going on in the opposite direction */
719 time = time - frame_animate_iconify_time_left(_self, &now);
722 /* animation was already going in the same direction */
727 self->iconify_animation_going = iconifying ? 1 : -1;
729 /* set the ending time */
731 self->iconify_animation_end.tv_sec = now.tv_sec;
732 self->iconify_animation_end.tv_usec = now.tv_usec;
733 g_time_val_add(&self->iconify_animation_end, time);
737 obt_main_loop_timeout_remove_data(plugin.ob_main_loop,
738 frame_animate_iconify, self, FALSE);
739 obt_main_loop_timeout_add(plugin.ob_main_loop,
740 FRAME_ANIMATE_ICONIFY_STEP_TIME, frame_animate_iconify, self,
741 g_direct_equal, NULL);
743 /* do the first step */
744 frame_animate_iconify(self);
746 /* show it during the animation even if it is not "visible" */
748 XMapWindow(obp_display, self->window);
752 void frame_end_iconify_animation(gpointer _self)
754 ObDefaultFrame * self = (ObDefaultFrame *) _self;
755 /* see if there is an animation going */
756 if (self->iconify_animation_going == 0)
760 XUnmapWindow(obp_display, self->window);
762 /* Send a ConfigureNotify when the animation is done, this fixes
763 KDE's pager showing the window in the wrong place. since the
764 window is mapped at a different location and is then moved, we
765 need to send the synthetic configurenotify, since apps may have
766 read the position when the client mapped, apparently. */
767 client_reconfigure(self->client, TRUE);
770 /* we're not animating any more ! */
771 self->iconify_animation_going = 0;
773 XMoveResizeWindow(obp_display, self->window, self->area.x, self->area.y,
774 self->area.width, self->area.height);
775 /* we delay re-rendering until after we're done animating */
776 frame_update_skin(self);
780 gboolean frame_iconify_animating(gpointer _self)
782 ObDefaultFrame * self = (ObDefaultFrame *) _self;
783 return self->iconify_animation_going != 0;
786 void frame_set_decorations(gpointer self, ObFrameDecorations d)
788 OBDEFAULTFRAME(self)->decorations = d;
791 Rect frame_get_window_area(gpointer self)
793 return OBDEFAULTFRAME(self)->area;
795 void frame_set_client_area(gpointer self, Rect r)
797 OBDEFAULTFRAME(self)->client_area = r;
800 void frame_update_layout(gpointer _self, gboolean is_resize, gboolean is_fake)
802 ObDefaultFrame * self = (ObDefaultFrame *) _self;
805 oldsize = self->size;
806 self->area = self->client_area;
808 /* do this before changing the frame's status like max_horz max_vert */
809 frame_adjust_cursors(self);
811 if (self->decorations & OB_FRAME_DECOR_BORDER
812 || (plugin.config_theme_keepborder)) {
813 self->bwidth = theme_config.fbwidth;
819 if (self->decorations & OB_FRAME_DECOR_BORDER) {
820 self->cbwidth_l = theme_config.cbwidthx;
821 self->cbwidth_r = theme_config.cbwidthx;
822 self->cbwidth_t = theme_config.cbwidthy;
823 self->cbwidth_b = theme_config.cbwidthy;
832 if (self->max_horz) {
835 self->width = self->client_area.width;
840 self->width = self->client_area.width + self->cbwidth_l
844 /* some elements are sized based of the width, so don't let them have
846 self->width = MAX(self->width, (theme_config.grip_width + self->bwidth) * 2
849 STRUT_SET(self->size, self->cbwidth_l
850 + (!self->max_horz ? self->bwidth : 0), self->cbwidth_t
851 + self->bwidth, self->cbwidth_r + (!self->max_horz ? self->bwidth
852 : 0), self->cbwidth_b
853 + (!self->max_horz || !self->max_vert ? self->bwidth : 0));
855 if (self->decorations & OB_FRAME_DECOR_TITLEBAR)
856 self->size.top += theme_config.title_height + self->bwidth;
857 if (self->decorations & OB_FRAME_DECOR_HANDLE && theme_config.handle_height
859 self->size.bottom += theme_config.handle_height + self->bwidth;
862 /* position/size and map/unmap all the windows */
864 gint innercornerheight = theme_config.grip_width - self->size.bottom;
866 if (self->cbwidth_l) {
867 XMoveResizeWindow(obp_display, self->innerleft, self->size.left
868 - self->cbwidth_l, self->size.top, self->cbwidth_l,
869 self->client_area.height);
871 XMapWindow(obp_display, self->innerleft);
874 XUnmapWindow(obp_display, self->innerleft);
876 if (self->cbwidth_l && innercornerheight > 0) {
877 XMoveResizeWindow(obp_display, self->innerbll, 0,
878 self->client_area.height - (theme_config.grip_width
879 - self->size.bottom), self->cbwidth_l,
880 theme_config.grip_width - self->size.bottom);
882 XMapWindow(obp_display, self->innerbll);
885 XUnmapWindow(obp_display, self->innerbll);
887 if (self->cbwidth_r) {
888 XMoveResizeWindow(obp_display, self->innerright, self->size.left
889 + self->client_area.width, self->size.top, self->cbwidth_r,
890 self->client_area.height);
892 XMapWindow(obp_display, self->innerright);
895 XUnmapWindow(obp_display, self->innerright);
897 if (self->cbwidth_r && innercornerheight > 0) {
898 XMoveResizeWindow(obp_display, self->innerbrr, 0,
899 self->client_area.height - (theme_config.grip_width
900 - self->size.bottom), self->cbwidth_r,
901 theme_config.grip_width - self->size.bottom);
903 XMapWindow(obp_display, self->innerbrr);
906 XUnmapWindow(obp_display, self->innerbrr);
908 if (self->cbwidth_t) {
912 self->size.left - self->cbwidth_l,
913 self->size.top - self->cbwidth_t,
914 self->client_area.width + 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, self->size.left
924 - self->cbwidth_l, self->size.top
925 + self->client_area.height, self->client_area.width
926 + self->cbwidth_l + self->cbwidth_r, self->cbwidth_b);
928 XMoveResizeWindow(obp_display, self->innerblb, 0, 0,
929 theme_config.grip_width + self->bwidth, self->cbwidth_b);
930 XMoveResizeWindow(obp_display, self->innerbrb,
931 self->client_area.width + self->cbwidth_l + self->cbwidth_r
932 - (theme_config.grip_width + self->bwidth), 0,
933 theme_config.grip_width + self->bwidth, self->cbwidth_b);
935 XMapWindow(obp_display, self->innerbottom);
936 XMapWindow(obp_display, self->innerblb);
937 XMapWindow(obp_display, self->innerbrb);
940 XUnmapWindow(obp_display, self->innerbottom);
941 XUnmapWindow(obp_display, self->innerblb);
942 XUnmapWindow(obp_display, self->innerbrb);
948 /* height of titleleft and titleright */
949 titlesides = (!self->max_horz ? theme_config.grip_width : 0);
951 XMoveResizeWindow(obp_display, self->titletop,
952 theme_config.grip_width + self->bwidth, 0,
953 /* width + bwidth*2 - bwidth*2 - grips*2 */
954 self->width - theme_config.grip_width * 2, self->bwidth);
955 XMoveResizeWindow(obp_display, self->titletopleft, 0, 0,
956 theme_config.grip_width + self->bwidth, self->bwidth);
957 XMoveResizeWindow(obp_display, self->titletopright,
958 self->client_area.width + self->size.left
959 + self->size.right - theme_config.grip_width
960 - self->bwidth, 0, theme_config.grip_width
961 + self->bwidth, self->bwidth);
963 if (titlesides > 0) {
964 XMoveResizeWindow(obp_display, self->titleleft, 0,
965 self->bwidth, self->bwidth, titlesides);
966 XMoveResizeWindow(obp_display, self->titleright,
967 self->client_area.width + self->size.left
968 + self->size.right - self->bwidth,
969 self->bwidth, self->bwidth, titlesides);
971 XMapWindow(obp_display, self->titleleft);
972 XMapWindow(obp_display, self->titleright);
975 XUnmapWindow(obp_display, self->titleleft);
976 XUnmapWindow(obp_display, self->titleright);
979 XMapWindow(obp_display, self->titletop);
980 XMapWindow(obp_display, self->titletopleft);
981 XMapWindow(obp_display, self->titletopright);
983 if (self->decorations & OB_FRAME_DECOR_TITLEBAR) {
984 XMoveResizeWindow(obp_display, self->titlebottom,
985 (self->max_horz ? 0 : self->bwidth),
986 theme_config.title_height + self->bwidth, self->width,
989 XMapWindow(obp_display, self->titlebottom);
992 XUnmapWindow(obp_display, self->titlebottom);
995 XUnmapWindow(obp_display, self->titlebottom);
997 XUnmapWindow(obp_display, self->titletop);
998 XUnmapWindow(obp_display, self->titletopleft);
999 XUnmapWindow(obp_display, self->titletopright);
1000 XUnmapWindow(obp_display, self->titleleft);
1001 XUnmapWindow(obp_display, self->titleright);
1004 if (self->decorations & OB_FRAME_DECOR_TITLEBAR) {
1005 XMoveResizeWindow(obp_display, self->title, (self->max_horz ? 0
1006 : self->bwidth), self->bwidth, self->width,
1007 theme_config.title_height);
1009 XMapWindow(obp_display, self->title);
1011 if (self->decorations & OB_FRAME_DECOR_GRIPS) {
1012 XMoveResizeWindow(obp_display, self->topresize,
1013 theme_config.grip_width, 0, self->width
1014 - theme_config.grip_width *2,
1015 theme_config.paddingy + 1);
1017 XMoveWindow(obp_display, self->tltresize, 0, 0);
1018 XMoveWindow(obp_display, self->tllresize, 0, 0);
1019 XMoveWindow(obp_display, self->trtresize, self->width
1020 - theme_config.grip_width, 0);
1021 XMoveWindow(obp_display, self->trrresize, self->width
1022 - theme_config.paddingx - 1, 0);
1024 XMapWindow(obp_display, self->topresize);
1025 XMapWindow(obp_display, self->tltresize);
1026 XMapWindow(obp_display, self->tllresize);
1027 XMapWindow(obp_display, self->trtresize);
1028 XMapWindow(obp_display, self->trrresize);
1031 XUnmapWindow(obp_display, self->topresize);
1032 XUnmapWindow(obp_display, self->tltresize);
1033 XUnmapWindow(obp_display, self->tllresize);
1034 XUnmapWindow(obp_display, self->trtresize);
1035 XUnmapWindow(obp_display, self->trrresize);
1039 XUnmapWindow(obp_display, self->title);
1042 if ((self->decorations & OB_FRAME_DECOR_TITLEBAR))
1043 /* layout the title bar elements */
1047 gint sidebwidth = self->max_horz ? 0 : self->bwidth;
1049 if (self->bwidth && self->size.bottom) {
1050 XMoveResizeWindow(obp_display, self->handlebottom,
1051 theme_config.grip_width + self->bwidth + sidebwidth,
1052 self->size.top + self->client_area.height
1053 + self->size.bottom - self->bwidth, self->width
1054 - (theme_config.grip_width + sidebwidth) * 2,
1058 XMoveResizeWindow(obp_display, self->lgripleft, 0,
1059 self->size.top + self->client_area.height
1061 - (!self->max_horz ? theme_config.grip_width
1062 : self->size.bottom - self->cbwidth_b),
1064 (!self->max_horz ? theme_config.grip_width
1065 : self->size.bottom - self->cbwidth_b));
1066 XMoveResizeWindow(obp_display, self->rgripright,
1067 self->size.left + self->client_area.width
1068 + self->size.right - self->bwidth,
1069 self->size.top + self->client_area.height
1071 - (!self->max_horz ? theme_config.grip_width
1072 : self->size.bottom - self->cbwidth_b),
1074 (!self->max_horz ? theme_config.grip_width
1075 : self->size.bottom - self->cbwidth_b));
1077 XMapWindow(obp_display, self->lgripleft);
1078 XMapWindow(obp_display, self->rgripright);
1081 XUnmapWindow(obp_display, self->lgripleft);
1082 XUnmapWindow(obp_display, self->rgripright);
1085 XMoveResizeWindow(obp_display, self->lgripbottom, sidebwidth,
1086 self->size.top + self->client_area.height
1087 + self->size.bottom - self->bwidth,
1088 theme_config.grip_width + self->bwidth, self->bwidth);
1089 XMoveResizeWindow(obp_display, self->rgripbottom, self->size.left
1090 + self->client_area.width + self->size.right - self->bwidth
1091 - sidebwidth - theme_config.grip_width, self->size.top
1092 + self->client_area.height + self->size.bottom
1093 - self->bwidth, theme_config.grip_width + self->bwidth,
1096 XMapWindow(obp_display, self->handlebottom);
1097 XMapWindow(obp_display, self->lgripbottom);
1098 XMapWindow(obp_display, self->rgripbottom);
1100 if (self->decorations & OB_FRAME_DECOR_HANDLE
1101 && theme_config.handle_height > 0) {
1102 XMoveResizeWindow(obp_display, self->handletop,
1103 theme_config.grip_width + self->bwidth + sidebwidth,
1104 FRAME_HANDLE_Y(self), self->width - (theme_config.grip_width
1105 + sidebwidth) * 2, self->bwidth);
1106 XMapWindow(obp_display, self->handletop);
1108 if (self->decorations & OB_FRAME_DECOR_GRIPS) {
1109 XMoveResizeWindow(obp_display, self->handleleft,
1110 theme_config.grip_width, 0, self->bwidth,
1111 theme_config.handle_height);
1112 XMoveResizeWindow(obp_display, self->handleright,
1113 self->width - theme_config.grip_width
1114 - self->bwidth, 0, self->bwidth,
1115 theme_config.handle_height);
1117 XMoveResizeWindow(obp_display, self->lgriptop, sidebwidth,
1118 FRAME_HANDLE_Y(self), theme_config.grip_width + self->bwidth,
1120 XMoveResizeWindow(obp_display, self->rgriptop,
1121 self->size.left + self->client_area.width
1122 + self->size.right - self->bwidth
1123 - sidebwidth - theme_config.grip_width,
1124 FRAME_HANDLE_Y(self), theme_config.grip_width
1125 + self->bwidth, self->bwidth);
1127 XMapWindow(obp_display, self->handleleft);
1128 XMapWindow(obp_display, self->handleright);
1129 XMapWindow(obp_display, self->lgriptop);
1130 XMapWindow(obp_display, self->rgriptop);
1133 XUnmapWindow(obp_display, self->handleleft);
1134 XUnmapWindow(obp_display, self->handleright);
1135 XUnmapWindow(obp_display, self->lgriptop);
1136 XUnmapWindow(obp_display, self->rgriptop);
1140 XUnmapWindow(obp_display, self->handleleft);
1141 XUnmapWindow(obp_display, self->handleright);
1142 XUnmapWindow(obp_display, self->lgriptop);
1143 XUnmapWindow(obp_display, self->rgriptop);
1145 XUnmapWindow(obp_display, self->handletop);
1149 XUnmapWindow(obp_display, self->handleleft);
1150 XUnmapWindow(obp_display, self->handleright);
1151 XUnmapWindow(obp_display, self->lgriptop);
1152 XUnmapWindow(obp_display, self->rgriptop);
1154 XUnmapWindow(obp_display, self->handletop);
1156 XUnmapWindow(obp_display, self->handlebottom);
1157 XUnmapWindow(obp_display, self->lgripleft);
1158 XUnmapWindow(obp_display, self->rgripright);
1159 XUnmapWindow(obp_display, self->lgripbottom);
1160 XUnmapWindow(obp_display, self->rgripbottom);
1163 if (self->decorations & OB_FRAME_DECOR_HANDLE
1164 && theme_config.handle_height > 0) {
1165 XMoveResizeWindow(obp_display, self->handle, sidebwidth,
1166 FRAME_HANDLE_Y(self) + self->bwidth, self->width,
1167 theme_config.handle_height);
1168 XMapWindow(obp_display, self->handle);
1170 if (self->decorations & OB_FRAME_DECOR_GRIPS) {
1171 XMoveResizeWindow(obp_display, self->lgrip, 0, 0,
1172 theme_config.grip_width, theme_config.handle_height);
1173 XMoveResizeWindow(obp_display, self->rgrip, self->width
1174 - theme_config.grip_width, 0, theme_config.grip_width,
1175 theme_config.handle_height);
1177 XMapWindow(obp_display, self->lgrip);
1178 XMapWindow(obp_display, self->rgrip);
1181 XUnmapWindow(obp_display, self->lgrip);
1182 XUnmapWindow(obp_display, self->rgrip);
1186 XUnmapWindow(obp_display, self->lgrip);
1187 XUnmapWindow(obp_display, self->rgrip);
1189 XUnmapWindow(obp_display, self->handle);
1192 if (self->bwidth && !self->max_horz && (self->client_area.height
1193 + self->size.top + self->size.bottom) > theme_config.grip_width
1195 XMoveResizeWindow(obp_display, self->left, 0, self->bwidth
1196 + theme_config.grip_width, self->bwidth,
1197 self->client_area.height + self->size.top
1198 + self->size.bottom - theme_config.grip_width * 2);
1200 XMapWindow(obp_display, self->left);
1203 XUnmapWindow(obp_display, self->left);
1205 if (self->bwidth && !self->max_horz && (self->client_area.height
1206 + self->size.top + self->size.bottom) > theme_config.grip_width
1208 XMoveResizeWindow(obp_display, self->right, self->client_area.width
1209 + self->cbwidth_l + self->cbwidth_r + self->bwidth,
1210 self->bwidth + theme_config.grip_width, self->bwidth,
1211 self->client_area.height + self->size.top
1212 + self->size.bottom - theme_config.grip_width * 2);
1214 XMapWindow(obp_display, self->right);
1217 XUnmapWindow(obp_display, self->right);
1219 XMoveResizeWindow(obp_display, self->backback, self->size.left,
1220 self->size.top, self->client_area.width,
1221 self->client_area.height);
1224 /* shading can change without being moved or resized */
1225 RECT_SET_SIZE(self->area, self->client_area.width + self->size.left
1226 + self->size.right, (self->shaded ? theme_config.title_height
1227 + self->bwidth * 2 : self->client_area.height + self->size.top
1228 + self->size.bottom));
1230 if ((is_resize) && !is_fake) {
1231 /* find the new coordinates, done after setting the frame.size, for
1232 frame_client_gravity. */
1233 self->area.x = self->client_area.x;
1234 self->area.y = self->client_area.y;
1235 frame_client_gravity(OBDEFAULTFRAME(_self)->client, &self->area.x, &self->area.y);
1239 if (!frame_iconify_animating(self))
1240 /* move and resize the top level frame.
1241 shading can change without being moved or resized.
1243 but don't do this during an iconify animation. it will be
1244 reflected afterwards.
1246 XMoveResizeWindow(obp_display, self->window, self->area.x,
1247 self->area.y, self->area.width, self->area.height);
1249 /* when the client has StaticGravity, it likes to move around.
1250 also this correctly positions the client when it maps.
1251 this also needs to be run when the frame's decorations sizes change!
1254 XMoveResizeWindow(obp_display, self->client->w_client,
1255 self->size.left, self->size.top, self->client_area.width,
1256 self->client_area.height);
1259 self->need_render = TRUE;
1260 frame_update_skin(self);
1261 frame_adjust_shape(self);
1264 if (!STRUT_EQUAL(self->size, oldsize)) {
1266 vals[0] = self->size.left;
1267 vals[1] = self->size.right;
1268 vals[2] = self->size.top;
1269 vals[3] = self->size.bottom;
1270 OBT_PROP_SETA32(self->client->w_client, NET_FRAME_EXTENTS,
1272 OBT_PROP_SETA32(self->client->w_client, KDE_NET_WM_FRAME_STRUT,
1276 /* if this occurs while we are focus cycling, the indicator needs to
1277 match the changes */
1278 if (plugin.focus_cycle_target == self->client)
1279 focus_cycle_draw_indicator(self->client);
1281 if (is_resize && (self->decorations & OB_FRAME_DECOR_TITLEBAR))
1282 XResizeWindow(obp_display, self->label, self->label_width,
1283 theme_config.label_height);
1286 void frame_set_hover_flag(gpointer self, ObFrameButton button)
1288 if (OBDEFAULTFRAME(self)->hover_flag != button) {
1289 OBDEFAULTFRAME(self)->hover_flag = button;
1290 frame_update_skin(self);
1294 void frame_set_press_flag(gpointer self, ObFrameButton button)
1296 if (OBDEFAULTFRAME(self)->press_flag != button) {
1297 OBDEFAULTFRAME(self)->press_flag = button;
1298 frame_update_skin(self);
1302 Window frame_get_window(gpointer self)
1304 return OBDEFAULTFRAME(self)->window;
1307 Strut frame_get_size(gpointer self)
1309 return OBDEFAULTFRAME(self)->size;
1312 gint frame_get_decorations(gpointer self)
1314 return OBDEFAULTFRAME(self)->decorations;
1317 void frame_update_title(gpointer self, const gchar * src)
1319 g_free(OBDEFAULTFRAME(self)->stitle);
1320 OBDEFAULTFRAME(self)->stitle = g_strdup(src);
1323 gboolean frame_is_visible(gpointer self)
1325 return OBDEFAULTFRAME(self)->visible;
1328 gboolean frame_is_max_horz(gpointer self)
1330 return OBDEFAULTFRAME(self)->max_horz;
1333 gboolean frame_is_max_vert(gpointer self)
1335 return OBDEFAULTFRAME(self)->max_vert;
1338 gulong frame_animate_iconify_time_left(gpointer _self, const GTimeVal *now)
1340 ObDefaultFrame * self = (ObDefaultFrame *) _self;
1342 sec = self->iconify_animation_end.tv_sec - now->tv_sec;
1343 usec = self->iconify_animation_end.tv_usec - now->tv_usec;
1345 usec += G_USEC_PER_SEC;
1348 /* no negative values */
1349 return MAX(sec * G_USEC_PER_SEC + usec, 0);
1352 gboolean frame_animate_iconify(gpointer p)
1354 ObDefaultFrame *self = p;
1356 gint iconx, icony, iconw;
1359 gboolean iconifying;
1361 if (self->client->icon_geometry.width == 0) {
1362 /* there is no icon geometry set so just go straight down */
1364 screen_physical_area_monitor(screen_find_monitor(&self->area));
1365 iconx = self->area.x + self->area.width / 2 + 32;
1366 icony = a->y + a->width;
1371 iconx = self->client->icon_geometry.x;
1372 icony = self->client->icon_geometry.y;
1373 iconw = self->client->icon_geometry.width;
1376 iconifying = self->iconify_animation_going > 0;
1378 /* how far do we have left to go ? */
1379 g_get_current_time(&now);
1380 time = frame_animate_iconify_time_left(self, &now);
1382 if (time == 0 || iconifying) {
1383 /* start where the frame is supposed to be */
1386 w = self->area.width;
1387 h = self->area.height;
1390 /* start at the icon */
1394 h = self->size.top; /* just the titlebar */
1401 dx = self->area.x - iconx;
1402 dy = self->area.y - icony;
1403 dw = self->area.width - self->bwidth * 2 - iconw;
1404 /* if restoring, we move in the opposite direction */
1411 elapsed = FRAME_ANIMATE_ICONIFY_TIME - time;
1412 x = x - (dx * elapsed) / FRAME_ANIMATE_ICONIFY_TIME;
1413 y = y - (dy * elapsed) / FRAME_ANIMATE_ICONIFY_TIME;
1414 w = w - (dw * elapsed) / FRAME_ANIMATE_ICONIFY_TIME;
1415 h = self->size.top; /* just the titlebar */
1419 frame_end_iconify_animation(self);
1421 XMoveResizeWindow(obp_display, self->window, x, y, w, h);
1422 XFlush(obp_display);
1425 return time > 0; /* repeat until we're out of time */
1428 void frame_adjust_cursors(gpointer _self)
1430 ObDefaultFrame * self = (ObDefaultFrame *) _self;
1431 if ((self->functions & OB_CLIENT_FUNC_RESIZE) != (self->functions
1432 & OB_CLIENT_FUNC_RESIZE) || self->max_horz != self->max_horz
1433 || self->max_vert != self->max_vert || self->shaded != self->shaded) {
1434 gboolean r = (self->functions & OB_CLIENT_FUNC_RESIZE)
1435 && !(self->max_horz && self->max_vert);
1436 gboolean topbot = !self->max_vert;
1437 gboolean sh = self->shaded;
1438 XSetWindowAttributes a;
1440 /* these ones turn off when max vert, and some when shaded */
1441 a.cursor = ob_cursor(r && topbot && !sh ? OB_CURSOR_NORTH
1443 XChangeWindowAttributes(obp_display, self->topresize, CWCursor, &a);
1444 XChangeWindowAttributes(obp_display, self->titletop, CWCursor, &a);
1445 a.cursor = ob_cursor(r && topbot ? OB_CURSOR_SOUTH : OB_CURSOR_NONE);
1446 XChangeWindowAttributes(obp_display, self->handle, CWCursor, &a);
1447 XChangeWindowAttributes(obp_display, self->handletop, CWCursor, &a);
1448 XChangeWindowAttributes(obp_display, self->handlebottom, CWCursor, &a);
1449 XChangeWindowAttributes(obp_display, self->innerbottom, CWCursor, &a);
1451 /* these ones change when shaded */
1452 a.cursor = ob_cursor(r ? (sh ? OB_CURSOR_WEST : OB_CURSOR_NORTHWEST)
1454 XChangeWindowAttributes(obp_display, self->titleleft, CWCursor, &a);
1455 XChangeWindowAttributes(obp_display, self->tltresize, CWCursor, &a);
1456 XChangeWindowAttributes(obp_display, self->tllresize, CWCursor, &a);
1457 XChangeWindowAttributes(obp_display, self->titletopleft, CWCursor, &a);
1458 a.cursor = ob_cursor(r ? (sh ? OB_CURSOR_EAST : OB_CURSOR_NORTHEAST)
1460 XChangeWindowAttributes(obp_display, self->titleright, CWCursor, &a);
1461 XChangeWindowAttributes(obp_display, self->trtresize, CWCursor, &a);
1462 XChangeWindowAttributes(obp_display, self->trrresize, CWCursor, &a);
1463 XChangeWindowAttributes(obp_display, self->titletopright, CWCursor, &a);
1465 /* these ones are pretty static */
1466 a.cursor = ob_cursor(r ? OB_CURSOR_WEST : OB_CURSOR_NONE);
1467 XChangeWindowAttributes(obp_display, self->left, CWCursor, &a);
1468 XChangeWindowAttributes(obp_display, self->innerleft, CWCursor, &a);
1469 a.cursor = ob_cursor(r ? OB_CURSOR_EAST : OB_CURSOR_NONE);
1470 XChangeWindowAttributes(obp_display, self->right, CWCursor, &a);
1471 XChangeWindowAttributes(obp_display, self->innerright, CWCursor, &a);
1472 a.cursor = ob_cursor(r ? OB_CURSOR_SOUTHWEST : OB_CURSOR_NONE);
1473 XChangeWindowAttributes(obp_display, self->lgrip, CWCursor, &a);
1474 XChangeWindowAttributes(obp_display, self->handleleft, CWCursor, &a);
1475 XChangeWindowAttributes(obp_display, self->lgripleft, CWCursor, &a);
1476 XChangeWindowAttributes(obp_display, self->lgriptop, CWCursor, &a);
1477 XChangeWindowAttributes(obp_display, self->lgripbottom, CWCursor, &a);
1478 XChangeWindowAttributes(obp_display, self->innerbll, CWCursor, &a);
1479 XChangeWindowAttributes(obp_display, self->innerblb, CWCursor, &a);
1480 a.cursor = ob_cursor(r ? OB_CURSOR_SOUTHEAST : OB_CURSOR_NONE);
1481 XChangeWindowAttributes(obp_display, self->rgrip, CWCursor, &a);
1482 XChangeWindowAttributes(obp_display, self->handleright, CWCursor, &a);
1483 XChangeWindowAttributes(obp_display, self->rgripright, CWCursor, &a);
1484 XChangeWindowAttributes(obp_display, self->rgriptop, CWCursor, &a);
1485 XChangeWindowAttributes(obp_display, self->rgripbottom, CWCursor, &a);
1486 XChangeWindowAttributes(obp_display, self->innerbrr, CWCursor, &a);
1487 XChangeWindowAttributes(obp_display, self->innerbrb, CWCursor, &a);
1491 void frame_adjust_client_area(gpointer _self)
1493 ObDefaultFrame * self = (ObDefaultFrame *) _self;
1494 /* adjust the window which is there to prevent flashing on unmap */
1495 XMoveResizeWindow(obp_display, self->backfront, 0, 0,
1496 self->client_area.width, self->client_area.height);
1499 void frame_adjust_state(gpointer _self)
1501 ObDefaultFrame * self = (ObDefaultFrame *) _self;
1502 self->need_render = TRUE;
1503 frame_update_skin(self);
1506 void frame_adjust_focus(gpointer _self, gboolean hilite)
1508 ObDefaultFrame * self = (ObDefaultFrame *) _self;
1509 self->focused = hilite;
1510 self->need_render = TRUE;
1511 frame_update_skin(self);
1512 XFlush(obp_display);
1515 void frame_adjust_title(gpointer _self)
1517 ObDefaultFrame * self = (ObDefaultFrame *) _self;
1518 self->need_render = TRUE;
1519 frame_update_skin(self);
1522 void frame_adjust_icon(gpointer _self)
1524 ObDefaultFrame * self = (ObDefaultFrame *) _self;
1525 self->need_render = TRUE;
1526 frame_update_skin(self);
1529 /* is there anything present between us and the label? */
1530 static gboolean is_button_present(ObDefaultFrame *_self, const gchar *lc,
1533 ObDefaultFrame * self = (ObDefaultFrame *) _self;
1534 for (; *lc != '\0' && lc >= plugin.config_title_layout; lc += dir) {
1536 continue; /* it was invalid */
1537 if (*lc == 'N' && self->decorations & OB_FRAME_DECOR_ICON)
1539 if (*lc == 'D' && self->decorations & OB_FRAME_DECOR_ALLDESKTOPS)
1541 if (*lc == 'S' && self->decorations & OB_FRAME_DECOR_SHADE)
1543 if (*lc == 'I' && self->decorations & OB_FRAME_DECOR_ICONIFY)
1545 if (*lc == 'M' && self->decorations & OB_FRAME_DECOR_MAXIMIZE)
1547 if (*lc == 'C' && self->decorations & OB_FRAME_DECOR_CLOSE)
1555 void flash_done(gpointer data)
1557 ObDefaultFrame *self = data;
1559 if (self->focused != self->flash_on)
1560 frame_adjust_focus(self, self->focused);
1563 gboolean flash_timeout(gpointer data)
1565 ObDefaultFrame *self = data;
1568 g_get_current_time(&now);
1569 if (now.tv_sec > self->flash_end.tv_sec
1570 || (now.tv_sec == self->flash_end.tv_sec && now.tv_usec
1571 >= self->flash_end.tv_usec))
1572 self->flashing = FALSE;
1574 if (!self->flashing)
1575 return FALSE; /* we are done */
1577 self->flash_on = !self->flash_on;
1578 if (!self->focused) {
1579 frame_adjust_focus(self, self->flash_on);
1580 self->focused = FALSE;
1583 return TRUE; /* go again */
1586 void layout_title(ObDefaultFrame * self)
1591 const gint bwidth = theme_config.button_size + theme_config.paddingx + 1;
1592 /* position of the left most button */
1593 const gint left = theme_config.paddingx + 1;
1594 /* position of the right most button */
1595 const gint right = self->width;
1597 /* turn them all off */
1598 self->icon_on = self->desk_on = self->shade_on = self->iconify_on
1599 = self->max_on = self->close_on = self->label_on = FALSE;
1600 self->label_width = self->width - (theme_config.paddingx + 1) * 2;
1601 self->leftmost = self->rightmost = OB_FRAME_CONTEXT_NONE;
1603 /* figure out what's being show, find each element's position, and the
1606 do the ones before the label, then after the label,
1607 i will be +1 the first time through when working to the left,
1608 and -1 the second time through when working to the right */
1609 for (i = 1; i >= -1; i-=2) {
1611 ObFrameContext *firstcon;
1615 lc = plugin.config_title_layout;
1616 firstcon = &self->leftmost;
1620 lc = plugin.config_title_layout
1621 + strlen(plugin.config_title_layout)-1;
1622 firstcon = &self->rightmost;
1625 /* stop at the end of the string (or the label, which calls break) */
1626 for (; *lc != '\0' && lc >= plugin.config_title_layout; lc+=i) {
1629 self->label_on = TRUE;
1632 break; /* break the for loop, do other side of label */
1634 else if (*lc == 'N') {
1636 *firstcon = OB_FRAME_CONTEXT_ICON;
1637 if ((self->icon_on = is_button_present(self, lc, i))) {
1638 /* icon is bigger than buttons */
1639 self->label_width -= bwidth + 2;
1642 x += i * (bwidth + 2);
1647 else if (*lc == 'D') {
1649 *firstcon = OB_FRAME_CONTEXT_ALLDESKTOPS;
1650 if ((self->desk_on = is_button_present(self, lc, i))) {
1651 self->label_width -= bwidth;
1659 else if (*lc == 'S') {
1661 *firstcon = OB_FRAME_CONTEXT_SHADE;
1662 if ((self->shade_on = is_button_present(self, lc, i))) {
1663 self->label_width -= bwidth;
1671 else if (*lc == 'I') {
1673 *firstcon = OB_FRAME_CONTEXT_ICONIFY;
1674 if ((self->iconify_on = is_button_present(self, lc, i))) {
1675 self->label_width -= bwidth;
1677 self->iconify_x = x;
1680 self->iconify_x = x;
1683 else if (*lc == 'M') {
1685 *firstcon = OB_FRAME_CONTEXT_MAXIMIZE;
1686 if ((self->max_on = is_button_present(self, lc, i))) {
1687 self->label_width -= bwidth;
1695 else if (*lc == 'C') {
1697 *firstcon = OB_FRAME_CONTEXT_CLOSE;
1698 if ((self->close_on = is_button_present(self, lc, i))) {
1699 self->label_width -= bwidth;
1708 continue; /* don't set firstcon */
1713 /* position and map the elements */
1714 if (self->icon_on) {
1715 XMapWindow(obp_display, self->icon);
1716 XMoveWindow(obp_display, self->icon, self->icon_x,
1717 theme_config.paddingy);
1720 XUnmapWindow(obp_display, self->icon);
1722 if (self->desk_on) {
1723 XMapWindow(obp_display, self->desk);
1724 XMoveWindow(obp_display, self->desk, self->desk_x,
1725 theme_config.paddingy + 1);
1728 XUnmapWindow(obp_display, self->desk);
1730 if (self->shade_on) {
1731 XMapWindow(obp_display, self->shade);
1732 XMoveWindow(obp_display, self->shade, self->shade_x,
1733 theme_config.paddingy + 1);
1736 XUnmapWindow(obp_display, self->shade);
1738 if (self->iconify_on) {
1739 XMapWindow(obp_display, self->iconify);
1740 XMoveWindow(obp_display, self->iconify, self->iconify_x,
1741 theme_config.paddingy + 1);
1744 XUnmapWindow(obp_display, self->iconify);
1747 XMapWindow(obp_display, self->max);
1748 XMoveWindow(obp_display, self->max, self->max_x, theme_config.paddingy
1752 XUnmapWindow(obp_display, self->max);
1754 if (self->close_on) {
1755 XMapWindow(obp_display, self->close);
1756 XMoveWindow(obp_display, self->close, self->close_x,
1757 theme_config.paddingy + 1);
1760 XUnmapWindow(obp_display, self->close);
1762 if (self->label_on) {
1763 self->label_width = MAX(1, self->label_width); /* no lower than 1 */
1764 XMapWindow(obp_display, self->label);
1765 XMoveWindow(obp_display, self->label, self->label_x,
1766 theme_config.paddingy);
1769 XUnmapWindow(obp_display, self->label);
1772 void trigger_none(gpointer self)
1775 void trigger_iconify(gpointer self)
1778 void trigger_uniconnity(gpointer self)
1781 void trigger_iconify_toggle(gpointer self)
1784 void trigger_shade(gpointer self)
1787 void trigger_unshade(gpointer self)
1790 void trigger_shade_toggle(gpointer self)
1793 void trigger_max(gpointer self)
1796 void trigger_unmax(gpointer self)
1799 void trigger_max_troggle(gpointer self)
1802 void trigger_max_vert(gpointer self)
1804 OBDEFAULTFRAME(self)->max_vert = TRUE;
1806 void trigger_unmax_vert(gpointer self)
1808 OBDEFAULTFRAME(self)->max_vert = FALSE;
1810 void trigger_max_toggle(gpointer self)
1813 void trigger_max_horz(gpointer self)
1815 OBDEFAULTFRAME(self)->max_horz = TRUE;
1817 void trigger_unmax_horz(gpointer self)
1819 OBDEFAULTFRAME(self)->max_horz = FALSE;
1821 void trigger_max_horz_toggle(gpointer self)
1824 void trigger_plugin1(gpointer self)
1827 void trigger_plugin2(gpointer self)
1830 void trigger_plugin3(gpointer self)
1833 void trigger_plugin4(gpointer self)
1836 void trigger_plugin5(gpointer self)
1839 void trigger_plugin6(gpointer self)
1842 void trigger_plugin7(gpointer self)
1845 void trigger_plugin8(gpointer self)
1848 void trigger_plugin9(gpointer self)
1852 void frame_trigger(gpointer self, ObFrameTrigger trigger_name)
1855 static void (*trigger_func[64])(gpointer) = { trigger_none,
1856 trigger_iconify, trigger_uniconnity, trigger_iconify_toggle,
1857 trigger_shade, trigger_unshade, trigger_shade_toggle,
1858 trigger_max, trigger_unmax, trigger_max_troggle,
1859 trigger_max_vert, trigger_unmax_vert, trigger_max_toggle,
1860 trigger_max_horz, trigger_unmax_horz,
1861 trigger_max_horz_toggle, trigger_plugin1, trigger_plugin2,
1862 trigger_plugin3, trigger_plugin4, trigger_plugin5,
1863 trigger_plugin6, trigger_plugin7, trigger_plugin8,
1864 trigger_plugin9, NULL,
1867 void (*call_trigger_func)(gpointer) = trigger_func[trigger_name];
1868 if(!call_trigger_func)
1870 call_trigger_func (self);
1874 ObFramePlugin plugin = { 0, /* gpointer handler */
1875 "libdefault.la", /* gchar * filename */
1876 "Default", /* gchar * name */
1877 init, //gint (*init) (Display * display, gint screen);
1879 frame_new, //gpointer (*frame_new) (struct _ObClient *c);
1880 frame_free, //void (*frame_free) (gpointer self);
1881 frame_show, //void (*frame_show) (gpointer self);
1882 frame_hide, //void (*frame_hide) (gpointer self);
1883 frame_adjust_theme, //void (*frame_adjust_theme) (gpointer self);
1884 frame_adjust_shape, //void (*frame_adjust_shape) (gpointer self);
1885 frame_grab, //void (*frame_adjust_area) (gpointer self, gboolean moved, gboolean resized, gboolean fake);
1886 frame_ungrab, frame_context, //void (*frame_adjust_state) (gpointer self);
1887 frame_set_is_visible, /* */
1888 frame_set_is_focus, /* */
1889 frame_set_is_max_vert, /* */
1890 frame_set_is_max_horz, /* */
1891 frame_set_is_shaded, /* */
1893 frame_flash_start, /* */
1894 frame_flash_stop, /* */
1895 frame_begin_iconify_animation, /* */
1896 frame_end_iconify_animation, /* */
1897 frame_iconify_animating, /* */
1899 frame_set_decorations, /* */
1901 frame_update_title, /* */
1902 /* This give the window area */
1903 frame_get_window_area, /* */
1904 frame_set_client_area, /* */
1905 /* Draw the frame */
1906 frame_update_layout, /* */
1907 frame_update_skin, /* */
1909 frame_set_hover_flag, /* */
1910 frame_set_press_flag, /* */
1912 frame_get_window,/* */
1914 frame_get_size, /* */
1915 frame_get_decorations, /* */
1917 frame_is_visible, /* */
1918 frame_is_max_horz, /* */
1919 frame_is_max_vert, /* */
1921 frame_trigger, /* */
1923 load_theme_config, /* */
1925 /* This fields are fill by openbox. */
1926 //0, //Display * ob_display;
1927 //0, //gint ob_screen;
1928 //0, //RrInstance *ob_rr_inst;
1929 0, //gboolean config_theme_keepborder;
1930 0, //struct _ObClient *focus_cycle_target;
1931 0, //gchar *config_title_layout;
1932 FALSE, //gboolean moveresize_in_progress;
1933 0, //struct _ObMainLoop *ob_main_loop;
1936 ObFramePlugin * get_info()