1 /* -*- indent-tabs-mode: nil; tab-width: 4; c-basic-offset: 4; -*-
3 frame_default_plugin.c for the Openbox window manager
4 Copyright (c) 2006 Mikael Magnusson
5 Copyright (c) 2003-2007 Dana Jansens
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2 of the License, or
10 (at your option) any later version.
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 See the COPYING file for a copy of the GNU General Public License.
20 #include "openbox/client.h"
21 #include "openbox/openbox.h"
22 #include "openbox/prop.h"
23 #include "openbox/grab.h"
24 #include "openbox/config.h"
25 #include "obt/mainloop.h"
26 #include "openbox/focus_cycle.h"
27 #include "openbox/focus_cycle_indicator.h"
28 #include "openbox/moveresize.h"
29 #include "openbox/screen.h"
30 #include "render/theme.h"
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 static gulong frame_animate_iconify_time_left(gpointer _self,
58 Window createWindow(Window parent, Visual *visual, gulong mask,
59 XSetWindowAttributes *attrib)
61 return XCreateWindow(plugin.ob_display, parent, 0, 0, 1, 1, 0, (visual ? 32
62 : RrDepth(plugin.ob_rr_inst)), InputOutput, (visual ? visual
63 : RrVisual(plugin.ob_rr_inst)), mask, attrib);
67 Visual *check_32bit_client(ObClient *c)
69 XWindowAttributes wattrib;
72 /* we're already running at 32 bit depth, yay. we don't need to use their
74 if (RrDepth(plugin.ob_rr_inst) == 32)
77 ret = XGetWindowAttributes(plugin.ob_display, c->window, &wattrib);
78 g_assert(ret != BadDrawable);
79 g_assert(ret != BadWindow);
81 if (wattrib.depth == 32)
82 return wattrib.visual;
87 gint init(Display * display, gint screen)
89 plugin.ob_display = display;
90 plugin.ob_screen = screen;
94 gpointer frame_new(struct _ObClient * client)
96 XSetWindowAttributes attrib;
101 self = g_new0(ObConceptFrame, 1);
102 self->client = client;
104 visual = check_32bit_client(client);
106 /* create the non-visible decor windows */
110 /* client has a 32-bit visual */
111 mask |= CWColormap | CWBackPixel | CWBorderPixel;
112 /* create a colormap with the visual */
113 OBCONCEPTFRAME(self)->colormap = attrib.colormap = XCreateColormap(
114 plugin.ob_display, RootWindow(plugin.ob_display,
115 plugin.ob_screen), visual, AllocNone);
116 attrib.background_pixel = BlackPixel(plugin.ob_display,
118 attrib.border_pixel = BlackPixel(plugin.ob_display, plugin.ob_screen);
120 self->window = createWindow(
121 RootWindow(plugin.ob_display, plugin.ob_screen), visual, mask,
124 /* create the visible decor windows */
128 /* client has a 32-bit visual */
129 mask |= CWColormap | CWBackPixel | CWBorderPixel;
130 attrib.colormap = RrColormap(plugin.ob_rr_inst);
133 self->background = createWindow(self->window, NULL, mask, &attrib);
136 attrib.event_mask = ELEMENT_EVENTMASK;
138 self->title = createWindow(self->window, NULL, mask, &attrib);
140 self->top = createWindow(self->window, NULL, mask, &attrib);
141 self->bottom = createWindow(self->window, NULL, mask, &attrib);
142 self->left = createWindow(self->window, NULL, mask, &attrib);
143 self->right = createWindow(self->window, NULL, mask, &attrib);
145 self->top_left = createWindow(self->window, NULL, mask, &attrib);
146 self->top_right = createWindow(self->window, NULL, mask, &attrib);
147 self->bottom_left = createWindow(self->window, NULL, mask, &attrib);
148 self->bottom_right = createWindow(self->window, NULL, mask, &attrib);
150 XMapWindow(plugin.ob_display, self->background);
152 self->focused = FALSE;
154 self->hover_flag = OB_BUTTON_NONE;
155 self->press_flag = OB_BUTTON_NONE;
157 set_theme_statics(self);
162 void set_theme_statics(gpointer _self)
164 ObConceptFrame * self = (ObConceptFrame *) _self;
165 /* do this before changing the frame's status like max_horz max_vert */
167 XResizeWindow(plugin.ob_display, self->top_left, 5, 5);
168 XResizeWindow(plugin.ob_display, self->top_right, 5, 5);
169 XResizeWindow(plugin.ob_display, self->bottom_left, 5, 5);
170 XResizeWindow(plugin.ob_display, self->bottom_right, 5, 5);
173 void free_theme_statics(gpointer _self)
175 ObConceptFrame * self = (ObConceptFrame *) _self;
178 void frame_free(gpointer self)
180 free_theme_statics(OBCONCEPTFRAME(self));
181 XDestroyWindow(plugin.ob_display, OBCONCEPTFRAME(self)->window);
182 if (OBCONCEPTFRAME(self)->colormap)
183 XFreeColormap(plugin.ob_display, OBCONCEPTFRAME(self)->colormap);
187 void frame_show(gpointer _self)
189 ObConceptFrame * self = (ObConceptFrame *) _self;
190 if (!self->visible) {
191 self->visible = TRUE;
192 frame_update_skin(self);
193 /* Grab the server to make sure that the frame window is mapped before
194 the client gets its MapNotify, i.e. to make sure the client is
195 _visible_ when it gets MapNotify. */
197 XMapWindow(plugin.ob_display, self->client->window);
198 XMapWindow(plugin.ob_display, self->window);
203 gint frame_hide(gpointer self)
205 if (OBCONCEPTFRAME(self)->visible) {
206 OBCONCEPTFRAME(self)->visible = FALSE;
207 if (!frame_iconify_animating(self))
208 XUnmapWindow(plugin.ob_display, OBCONCEPTFRAME(self)->window);
209 /* we unmap the client itself so that we can get MapRequest
210 events, and because the ICCCM tells us to! */
211 XUnmapWindow(plugin.ob_display, OBCONCEPTFRAME(self)->client->window);
212 /* We ignore 1 unmap */
219 void frame_adjust_theme(gpointer self)
221 free_theme_statics(self);
222 set_theme_statics(self);
225 void frame_adjust_shape(gpointer _self)
228 ObConceptFrame * self = (ObConceptFrame *) _self;
232 if (!self->client->shaped)
234 /* clear the shape on the frame window */
235 XShapeCombineMask(plugin.ob_display, self->window, ShapeBounding,
242 /* make the frame's shape match the clients */
243 XShapeCombineShape(plugin.ob_display, self->window, ShapeBounding,
246 self->client->window,
247 ShapeBounding, ShapeSet);
250 if (self->decorations)
254 xrect[0].width = self->window_area.width;
255 xrect[0].height = self->size.top;
259 XShapeCombineRectangles(plugin.ob_display, self->window,
260 ShapeBounding, 0, 0, xrect, num,
261 ShapeUnion, Unsorted);
266 void frame_grab(gpointer _self, GHashTable * map)
268 ObConceptFrame * self = (ObConceptFrame *) _self;
269 /* DO NOT map the client window here. we used to do that, but it is bogus.
270 we need to set up the client's dimensions and everything before we
271 send a mapnotify or we create race conditions.
274 /* reparent the client to the frame */
275 XReparentWindow(plugin.ob_display, self->client->window, self->window, 0, 0);
278 When reparenting the client window, it is usually not mapped yet, since
279 this occurs from a MapRequest. However, in the case where Openbox is
280 starting up, the window is already mapped, so we'll see an unmap event
283 if (ob_state() == OB_STATE_STARTING)
284 ++self->client->ignore_unmaps;
286 /* select the event mask on the client's parent (to receive config/map
287 req's) the ButtonPress is to catch clicks on the client border */
288 XSelectInput(plugin.ob_display, self->window, FRAME_EVENTMASK);
290 /* set all the windows for the frame in the window_map */
291 g_hash_table_insert(map, &self->window, self->client);
293 g_hash_table_insert(map, &self->title, self->client);
295 g_hash_table_insert(map, &self->left, self->client);
296 g_hash_table_insert(map, &self->right, self->client);
297 g_hash_table_insert(map, &self->top, self->client);
298 g_hash_table_insert(map, &self->bottom, self->client);
300 g_hash_table_insert(map, &self->top_left, self->client);
301 g_hash_table_insert(map, &self->top_right, self->client);
302 g_hash_table_insert(map, &self->bottom_left, self->client);
303 g_hash_table_insert(map, &self->bottom_right, self->client);
307 void frame_ungrab(gpointer _self, GHashTable * map)
309 ObConceptFrame * self = (ObConceptFrame *) _self;
311 gboolean reparent = TRUE;
313 /* if there was any animation going on, kill it */
314 obt_main_loop_timeout_remove_data(plugin.ob_main_loop,
315 frame_animate_iconify, self, FALSE);
317 /* check if the app has already reparented its window away */
318 while (XCheckTypedWindowEvent(plugin.ob_display, self->client->window,
319 ReparentNotify, &ev)) {
320 /* This check makes sure we don't catch our own reparent action to
321 our frame window. This doesn't count as the app reparenting itself
324 Reparent events that are generated by us are just discarded here.
325 They are of no consequence to us anyhow.
327 if (ev.xreparent.parent != self->window) {
329 XPutBackEvent(plugin.ob_display, &ev);
335 /* according to the ICCCM - if the client doesn't reparent itself,
336 then we will reparent the window to root for them */
337 XReparentWindow(plugin.ob_display, self->client->window, RootWindow(
338 plugin.ob_display, plugin.ob_screen), self->client->area.x,
339 self->client->area.y);
342 /* remove all the windows for the frame from the window_map */
343 g_hash_table_remove(map, &self->window);
345 g_hash_table_remove(map, &self->title);
347 g_hash_table_remove(map, &self->left);
348 g_hash_table_remove(map, &self->right);
349 g_hash_table_remove(map, &self->top);
350 g_hash_table_remove(map, &self->bottom);
352 g_hash_table_remove(map, &self->top_left);
353 g_hash_table_remove(map, &self->top_right);
354 g_hash_table_remove(map, &self->bottom_left);
355 g_hash_table_remove(map, &self->bottom_right);
357 obt_main_loop_timeout_remove_data(plugin.ob_main_loop, flash_timeout, self,
361 ObFrameContext frame_context(gpointer _self, Window win, gint x, gint y)
363 /* Here because client can be NULL */
364 ObConceptFrame *self = OBCONCEPTFRAME(_self);
367 return OB_FRAME_CONTEXT_TITLEBAR;
368 if (win == self->title)
369 return OB_FRAME_CONTEXT_TITLEBAR;
371 if (win == self->window)
372 return OB_FRAME_CONTEXT_FRAME;
374 if (win == self->bottom)
375 return OB_FRAME_CONTEXT_BOTTOM;
377 if (win == self->bottom_left)
378 return OB_FRAME_CONTEXT_BLCORNER;
380 if (win == self->bottom_right)
381 return OB_FRAME_CONTEXT_BRCORNER;
383 if (win == self->top)
384 return OB_FRAME_CONTEXT_TOP;
386 if (win == self->top_left)
387 return OB_FRAME_CONTEXT_TLCORNER;
389 if (win == self->top_right)
390 return OB_FRAME_CONTEXT_TRCORNER;
392 if (win == self->left)
393 return OB_FRAME_CONTEXT_LEFT;
394 if (win == self->right)
395 return OB_FRAME_CONTEXT_RIGHT;
397 return OB_FRAME_CONTEXT_NONE;
400 void frame_set_is_visible(gpointer self, gboolean b)
402 OBCONCEPTFRAME(self)->visible = b;
404 OBCONCEPTFRAME(self)->frame_stase_flags |= OB_FRAME_STASE_IS_VISIBLE;
407 OBCONCEPTFRAME(self)->frame_stase_flags &= ~OB_FRAME_STASE_IS_VISIBLE;
411 void frame_set_is_focus(gpointer self, gboolean b)
413 OBCONCEPTFRAME(self)->focused = b;
415 OBCONCEPTFRAME(self)->frame_stase_flags |= OB_FRAME_STASE_IS_FOCUS;
418 OBCONCEPTFRAME(self)->frame_stase_flags &= ~OB_FRAME_STASE_IS_FOCUS;
422 void frame_set_is_max_vert(gpointer self, gboolean b)
424 OBCONCEPTFRAME(self)->max_vert = b;
426 OBCONCEPTFRAME(self)->frame_stase_flags |= OB_FRAME_STASE_IS_MAX_VERT;
429 OBCONCEPTFRAME(self)->frame_stase_flags &= ~OB_FRAME_STASE_IS_MAX_VERT;
433 void frame_set_is_max_horz(gpointer self, gboolean b)
435 OBCONCEPTFRAME(self)->max_horz = b;
437 OBCONCEPTFRAME(self)->frame_stase_flags |= OB_FRAME_STASE_IS_MAX_HORZ;
440 OBCONCEPTFRAME(self)->frame_stase_flags &= ~OB_FRAME_STASE_IS_MAX_HORZ;
444 void frame_set_is_shaded(gpointer self, gboolean b)
446 OBCONCEPTFRAME(self)->shaded = b;
448 OBCONCEPTFRAME(self)->frame_stase_flags |= OB_FRAME_STASE_IS_SHADED;
451 OBCONCEPTFRAME(self)->frame_stase_flags &= ~OB_FRAME_STASE_IS_SHADED;
455 void frame_unfocus(gpointer self)
457 OBCONCEPTFRAME(self)->focused = FALSE;
460 void frame_flash_start(gpointer _self)
462 ObConceptFrame * self = (ObConceptFrame *) _self;
463 self->flash_on = self->focused;
466 obt_main_loop_timeout_add(plugin.ob_main_loop, G_USEC_PER_SEC * 0.6,
467 flash_timeout, self, g_direct_equal, flash_done);
468 g_get_current_time(&self->flash_end);
469 g_time_val_add(&self->flash_end, G_USEC_PER_SEC * 5);
471 self->flashing = TRUE;
474 void frame_flash_stop(gpointer _self)
476 ObConceptFrame * self = (ObConceptFrame *) _self;
477 self->flashing = FALSE;
480 void frame_begin_iconify_animation(gpointer _self, gboolean iconifying)
482 ObConceptFrame * self = (ObConceptFrame *) _self;
484 gboolean new_anim = FALSE;
485 gboolean set_end = TRUE;
488 /* if there is no titlebar, just don't animate for now
489 XXX it would be nice tho.. */
490 if (!(self->decorations & OB_FRAME_DECOR_TITLEBAR))
493 /* get the current time */
494 g_get_current_time(&now);
496 /* get how long until the end */
497 time = FRAME_ANIMATE_ICONIFY_TIME;
498 if (self->iconify_animation_going) {
499 if (!!iconifying != (self->iconify_animation_going > 0)) {
500 /* animation was already going on in the opposite direction */
501 time = time - frame_animate_iconify_time_left(self, &now);
504 /* animation was already going in the same direction */
509 self->iconify_animation_going = iconifying ? 1 : -1;
511 /* set the ending time */
513 self->iconify_animation_end.tv_sec = now.tv_sec;
514 self->iconify_animation_end.tv_usec = now.tv_usec;
515 g_time_val_add(&self->iconify_animation_end, time);
519 obt_main_loop_timeout_remove_data(plugin.ob_main_loop,
520 frame_animate_iconify, self, FALSE);
521 obt_main_loop_timeout_add(plugin.ob_main_loop,
522 FRAME_ANIMATE_ICONIFY_STEP_TIME, frame_animate_iconify, self,
523 g_direct_equal, NULL);
525 /* do the first step */
526 frame_animate_iconify(self);
528 /* show it during the animation even if it is not "visible" */
530 XMapWindow(plugin.ob_display, self->window);
534 void frame_end_iconify_animation(gpointer _self)
536 ObConceptFrame * self = (ObConceptFrame *) _self;
537 /* see if there is an animation going */
538 if (self->iconify_animation_going == 0)
542 XUnmapWindow(plugin.ob_display, self->window);
544 /* Send a ConfigureNotify when the animation is done, this fixes
545 KDE's pager showing the window in the wrong place. since the
546 window is mapped at a different location and is then moved, we
547 need to send the synthetic configurenotify, since apps may have
548 read the position when the client mapped, apparently. */
549 client_reconfigure(self->client, TRUE);
552 /* we're not animating any more ! */
553 self->iconify_animation_going = 0;
555 XMoveResizeWindow(plugin.ob_display, self->window, self->window_area.x,
556 self->window_area.y, self->window_area.width,
557 self->window_area.height);
558 /* we delay re-rendering until after we're done animating */
559 frame_update_skin(self);
560 XFlush(plugin.ob_display);
563 gboolean frame_iconify_animating(gpointer _self)
565 ObConceptFrame * self = (ObConceptFrame *) _self;
566 return self->iconify_animation_going != 0;
569 void frame_set_decorations(gpointer self, ObFrameDecorations d)
571 OBCONCEPTFRAME(self)->decorations = d;
574 Rect frame_get_window_area(gpointer self)
576 return OBCONCEPTFRAME(self)->window_area;
578 void frame_set_client_area(gpointer self, Rect r)
580 OBCONCEPTFRAME(self)->client_area = r;
583 void frame_update_layout(gpointer _self, gboolean is_resize, gboolean is_fake)
585 ObConceptFrame * self = (ObConceptFrame *) _self;
587 /* do this before changing the frame's status like max_horz max_vert */
588 frame_adjust_cursors(self);
590 if (self->decorations && !self->shaded) {
596 self->title_width = 20;
598 STRUT_SET(self->size, self->cbwidth_l, self->cbwidth_t, self->cbwidth_r
599 + self->title_width, self->cbwidth_b);
601 RECT_SET_SIZE(self->window_area, self->client_area.width
602 + self->size.left + self->size.right, self->client_area.height
603 + self->size.top + self->size.bottom);
607 XMoveResizeWindow(plugin.ob_display, self->top, 5, 0,
608 self->window_area.width - 10, theme_config.border_width);
609 XMapWindow(plugin.ob_display, self->top);
611 XMoveResizeWindow(plugin.ob_display, self->bottom, 5,
612 self->window_area.height - theme_config.border_width,
613 self->window_area.width - 10, theme_config.border_width);
614 XMapWindow(plugin.ob_display, self->bottom);
616 XMoveResizeWindow(plugin.ob_display, self->left, 0,
617 theme_config.border_width, theme_config.border_width,
618 self->window_area.height - 2*theme_config.border_width);
619 XMapWindow(plugin.ob_display, self->left);
621 XMoveResizeWindow(plugin.ob_display, self->right,
622 self->window_area.width - theme_config.border_width,
623 theme_config.border_width, theme_config.border_width,
624 self->window_area.height - 2 *theme_config.border_width);
625 XMapWindow(plugin.ob_display, self->right);
627 XMoveWindow(plugin.ob_display, self->top_left, 0, 0);
628 XMapWindow(plugin.ob_display, self->top_left);
629 XMoveWindow(plugin.ob_display, self->top_right,
630 self->window_area.width - 5, 0);
631 XMapWindow(plugin.ob_display, self->top_right);
632 XMoveWindow(plugin.ob_display, self->bottom_left, 0,
633 self->window_area.height - theme_config.border_width);
634 XMapWindow(plugin.ob_display, self->bottom_left);
635 XMoveWindow(plugin.ob_display, self->bottom_right,
636 self->window_area.width - 5, self->window_area.height
637 - theme_config.border_width);
638 XMapWindow(plugin.ob_display, self->bottom_right);
640 XMoveResizeWindow(plugin.ob_display, self->title,
641 self->window_area.width - theme_config.border_width
642 - self->title_width, theme_config.border_width,
643 self->title_width, self->window_area.height - 2
644 *theme_config.border_width);
645 XMapWindow(plugin.ob_display, self->title);
647 /* find the new coordinates, done after setting the frame.size, for
648 frame_client_gravity. */
649 self->window_area.x = self->client_area.x;
650 self->window_area.y = self->client_area.y;
651 frame_client_gravity(self->client, &self->window_area.x,
652 &self->window_area.y);
654 XMoveResizeWindow(plugin.ob_display, self->background,
655 theme_config.border_width, theme_config.border_width,
656 self->window_area.width - 2 * theme_config.border_width
657 - self->title_width, self->window_area.height - 2
658 * theme_config.border_width);
659 XMapWindow(plugin.ob_display, self->background);
662 XMoveResizeWindow(plugin.ob_display, self->client->window,
663 self->size.left, self->size.top,
664 self->window_area.width - self->size.left
665 - self->size.right, self->window_area.height
666 - self->size.top - self->size.bottom);
668 XMoveResizeWindow(plugin.ob_display, self->window,
669 self->window_area.x, self->window_area.y,
670 self->window_area.width, self->window_area.height);
674 else if (self->shaded) {
680 self->title_width = 20;
682 STRUT_SET(self->size, self->cbwidth_l, self->cbwidth_t, self->cbwidth_r
683 + self->title_width, self->cbwidth_b);
685 RECT_SET_SIZE(self->window_area, 30, 30);
687 /* find the new coordinates, done after setting the frame.size, for
688 frame_client_gravity. */
689 frame_client_gravity(self->client, &self->window_area.x,
690 &self->window_area.y);
693 XUnmapWindow(plugin.ob_display, self->top);
694 XUnmapWindow(plugin.ob_display, self->bottom);
695 XUnmapWindow(plugin.ob_display, self->left);
696 XUnmapWindow(plugin.ob_display, self->right);
697 XUnmapWindow(plugin.ob_display, self->top_left);
698 XUnmapWindow(plugin.ob_display, self->top_right);
699 XUnmapWindow(plugin.ob_display, self->bottom_left);
700 XUnmapWindow(plugin.ob_display, self->bottom_right);
702 XUnmapWindow(plugin.ob_display, self->title);
704 XMoveResizeWindow(plugin.ob_display, self->background, 0, 0, 30, 30);
705 XMapWindow(plugin.ob_display, self->background);
707 XMoveWindow(plugin.ob_display, self->window, 35, 35);
708 XResizeWindow(plugin.ob_display, self->window, 30, 30);
717 STRUT_SET(self->size, self->cbwidth_l, self->cbwidth_t,
718 self->cbwidth_r, self->cbwidth_b);
720 RECT_SET_SIZE(self->window_area, self->client->area.width
721 + self->size.left + self->size.right, self->client->area.height
722 + self->size.top + self->size.bottom);
724 /* find the new coordinates, done after setting the frame.size, for
725 frame_client_gravity. */
726 self->window_area.x = self->client_area.x;
727 self->window_area.y = self->client_area.y;
728 frame_client_gravity(self->client, &self->window_area.x,
729 &self->window_area.y);
732 XUnmapWindow(plugin.ob_display, self->top);
733 XUnmapWindow(plugin.ob_display, self->bottom);
734 XUnmapWindow(plugin.ob_display, self->left);
735 XUnmapWindow(plugin.ob_display, self->right);
736 XUnmapWindow(plugin.ob_display, self->top_left);
737 XUnmapWindow(plugin.ob_display, self->top_right);
738 XUnmapWindow(plugin.ob_display, self->bottom_left);
739 XUnmapWindow(plugin.ob_display, self->bottom_right);
741 XUnmapWindow(plugin.ob_display, self->title);
743 XMoveResizeWindow(plugin.ob_display, self->background, 0, 0,
744 self->window_area.width, self->window_area.height);
745 XMapWindow(plugin.ob_display, self->background);
747 XMoveResizeWindow(plugin.ob_display, self->client->window,
748 self->size.left, self->size.top,
749 self->window_area.width, self->window_area.height);
751 XMoveResizeWindow(plugin.ob_display, self->window,
752 self->window_area.x, self->window_area.y,
753 self->window_area.width, self->window_area.height);
758 void frame_update_skin(gpointer _self)
760 ObConceptFrame * self = (ObConceptFrame *) _self;
761 if (plugin.frame_iconify_animating(self))
762 return; /* delay redrawing until the animation is done */
766 self->need_render = FALSE;
768 gulong border_px, corner_px;
771 border_px = RrColorPixel(theme_config.focus_border_color);
772 corner_px = RrColorPixel(theme_config.focus_corner_color);
773 XSetWindowBackgroundPixmap(plugin.ob_display, self->left,
774 theme_config.px_focus_left);
775 XClearWindow(plugin.ob_display, self->left);
776 XSetWindowBackgroundPixmap(plugin.ob_display, self->right,
777 theme_config.px_focus_right);
778 XClearWindow(plugin.ob_display, self->right);
780 XSetWindowBackgroundPixmap(plugin.ob_display, self->top,
781 theme_config.px_focus_top);
782 XClearWindow(plugin.ob_display, self->top);
783 XSetWindowBackgroundPixmap(plugin.ob_display, self->bottom,
784 theme_config.px_focus_bottom);
785 XClearWindow(plugin.ob_display, self->bottom);
787 XSetWindowBackgroundPixmap(plugin.ob_display, self->top_left,
788 theme_config.px_focus_topleft);
789 XClearWindow(plugin.ob_display, self->top_left);
790 XSetWindowBackgroundPixmap(plugin.ob_display, self->top_right,
791 theme_config.px_focus_topright);
792 XClearWindow(plugin.ob_display, self->top_right);
794 XSetWindowBackgroundPixmap(plugin.ob_display, self->bottom_left,
795 theme_config.px_focus_bottomleft);
796 XClearWindow(plugin.ob_display, self->bottom_left);
797 XSetWindowBackgroundPixmap(plugin.ob_display, self->bottom_right,
798 theme_config.px_focus_bottomright);
799 XClearWindow(plugin.ob_display, self->bottom_right);
801 XSetWindowBackground(plugin.ob_display, self->title, 0x00ffff);
802 XClearWindow(plugin.ob_display, self->title);
803 XSetWindowBackground(plugin.ob_display, self->background, 0);
804 XClearWindow(plugin.ob_display, self->background);
807 border_px = RrColorPixel(theme_config.unfocus_border_color);
808 corner_px = RrColorPixel(theme_config.unfocus_corner_color);
809 XSetWindowBackgroundPixmap(plugin.ob_display, self->left,
810 theme_config.px_unfocus_left);
811 XClearWindow(plugin.ob_display, self->left);
812 XSetWindowBackgroundPixmap(plugin.ob_display, self->right,
813 theme_config.px_unfocus_right);
814 XClearWindow(plugin.ob_display, self->right);
816 XSetWindowBackgroundPixmap(plugin.ob_display, self->top,
817 theme_config.px_unfocus_top);
818 XClearWindow(plugin.ob_display, self->top);
819 XSetWindowBackgroundPixmap(plugin.ob_display, self->bottom,
820 theme_config.px_unfocus_bottom);
821 XClearWindow(plugin.ob_display, self->bottom);
823 XSetWindowBackgroundPixmap(plugin.ob_display, self->top_left,
824 theme_config.px_unfocus_topleft);
825 XClearWindow(plugin.ob_display, self->top_left);
826 XSetWindowBackgroundPixmap(plugin.ob_display, self->top_right,
827 theme_config.px_unfocus_topright);
828 XClearWindow(plugin.ob_display, self->top_right);
830 XSetWindowBackgroundPixmap(plugin.ob_display, self->bottom_left,
831 theme_config.px_unfocus_bottomleft);
832 XClearWindow(plugin.ob_display, self->bottom_left);
833 XSetWindowBackgroundPixmap(plugin.ob_display, self->bottom_right,
834 theme_config.px_unfocus_bottomright);
835 XClearWindow(plugin.ob_display, self->bottom_right);
837 XSetWindowBackground(plugin.ob_display, self->title, 0x00ffff);
838 XClearWindow(plugin.ob_display, self->title);
839 XSetWindowBackground(plugin.ob_display, self->background, 0);
840 XClearWindow(plugin.ob_display, self->background);
842 XFlush(plugin.ob_display);
845 void frame_set_hover_flag(gpointer self, ObFrameButton button)
847 if (OBCONCEPTFRAME(self)->hover_flag != button) {
848 OBCONCEPTFRAME(self)->hover_flag = button;
849 frame_update_skin(self);
853 void frame_set_press_flag(gpointer self, ObFrameButton button)
855 if (OBCONCEPTFRAME(self)->press_flag != button) {
856 OBCONCEPTFRAME(self)->press_flag = button;
857 frame_update_skin(self);
861 Window frame_get_window(gpointer self)
863 return OBCONCEPTFRAME(self)->window;
866 Strut frame_get_size(gpointer self)
868 return OBCONCEPTFRAME(self)->size;
871 gint frame_get_decorations(gpointer self)
873 return OBCONCEPTFRAME(self)->decorations;
876 gboolean frame_is_visible(gpointer self)
878 return OBCONCEPTFRAME(self)->visible;
881 gboolean frame_is_max_horz(gpointer self)
883 return OBCONCEPTFRAME(self)->max_horz;
886 gboolean frame_is_max_vert(gpointer self)
888 return OBCONCEPTFRAME(self)->max_vert;
891 static gulong frame_animate_iconify_time_left(gpointer _self,
894 ObConceptFrame * self = (ObConceptFrame *) _self;
896 sec = self->iconify_animation_end.tv_sec - now->tv_sec;
897 usec = self->iconify_animation_end.tv_usec - now->tv_usec;
899 usec += G_USEC_PER_SEC;
902 /* no negative values */
903 return MAX(sec * G_USEC_PER_SEC + usec, 0);
906 gboolean frame_animate_iconify(gpointer p)
908 ObConceptFrame *self = p;
910 gint iconx, icony, iconw;
915 if (self->client->icon_geometry.width == 0) {
916 /* there is no icon geometry set so just go straight down */
919 screen_physical_area_monitor(screen_find_monitor(&self->window_area));
920 iconx = self->window_area.x + self->window_area.width / 2 + 32;
921 icony = a->y + a->width;
926 iconx = self->client->icon_geometry.x;
927 icony = self->client->icon_geometry.y;
928 iconw = self->client->icon_geometry.width;
931 iconifying = self->iconify_animation_going > 0;
933 /* how far do we have left to go ? */
934 g_get_current_time(&now);
935 time = frame_animate_iconify_time_left(self, &now);
937 if (time == 0 || iconifying) {
938 /* start where the frame is supposed to be */
939 x = self->window_area.x;
940 y = self->window_area.y;
941 w = self->window_area.width;
942 h = self->window_area.height;
945 /* start at the icon */
949 h = self->size.top; /* just the titlebar */
956 dx = self->window_area.x - iconx;
957 dy = self->window_area.y - icony;
958 dw = self->window_area.width - iconw;
959 /* if restoring, we move in the opposite direction */
966 elapsed = FRAME_ANIMATE_ICONIFY_TIME - time;
967 x = x - (dx * elapsed) / FRAME_ANIMATE_ICONIFY_TIME;
968 y = y - (dy * elapsed) / FRAME_ANIMATE_ICONIFY_TIME;
969 w = w - (dw * elapsed) / FRAME_ANIMATE_ICONIFY_TIME;
970 h = self->size.top; /* just the titlebar */
974 frame_end_iconify_animation(self);
976 XMoveResizeWindow(plugin.ob_display, self->window, x, y, w, h);
977 XFlush(plugin.ob_display);
980 return time > 0; /* repeat until we're out of time */
983 /* change the cursor */
984 void frame_adjust_cursors(gpointer _self)
986 ObConceptFrame * self = (ObConceptFrame *) _self;
988 XSetWindowAttributes a;
989 a.cursor = ob_cursor(OB_CURSOR_NORTH);
990 XChangeWindowAttributes(plugin.ob_display, self->top, CWCursor, &a);
992 a.cursor = ob_cursor(OB_CURSOR_SOUTH);
993 XChangeWindowAttributes(plugin.ob_display, self->bottom, CWCursor, &a);
995 a.cursor = ob_cursor(OB_CURSOR_WEST);
996 XChangeWindowAttributes(plugin.ob_display, self->left, CWCursor, &a);
998 a.cursor = ob_cursor(OB_CURSOR_EAST);
999 XChangeWindowAttributes(plugin.ob_display, self->right, CWCursor, &a);
1001 a.cursor = ob_cursor(OB_CURSOR_NORTHWEST);
1002 XChangeWindowAttributes(plugin.ob_display, self->top_left, CWCursor, &a);
1004 a.cursor = ob_cursor(OB_CURSOR_NORTHEAST);
1005 XChangeWindowAttributes(plugin.ob_display, self->top_right, CWCursor, &a);
1007 a.cursor = ob_cursor(OB_CURSOR_SOUTHWEST);
1008 XChangeWindowAttributes(plugin.ob_display, self->bottom_left, CWCursor, &a);
1010 a.cursor = ob_cursor(OB_CURSOR_SOUTHEAST);
1011 XChangeWindowAttributes(plugin.ob_display, self->bottom_right, CWCursor, &a);
1015 void frame_adjust_client_area(gpointer _self)
1017 ObConceptFrame * self = (ObConceptFrame *) _self;
1018 /* adjust the window which is there to prevent flashing on unmap */
1019 XMoveResizeWindow(plugin.ob_display, self->background, 0, 0,
1020 self->client->area.width, self->client->area.height);
1023 void frame_adjust_state(gpointer _self)
1025 ObConceptFrame * self = (ObConceptFrame *) _self;
1026 self->need_render = TRUE;
1027 frame_update_skin(self);
1030 void frame_adjust_focus(gpointer _self, gboolean hilite)
1032 ObConceptFrame * self = (ObConceptFrame *) _self;
1033 self->focused = hilite;
1034 self->need_render = TRUE;
1035 frame_update_skin(self);
1036 XFlush(plugin.ob_display);
1039 void frame_adjust_title(gpointer _self)
1041 ObConceptFrame * self = (ObConceptFrame *) _self;
1042 self->need_render = TRUE;
1043 frame_update_skin(self);
1046 void frame_adjust_icon(gpointer _self)
1048 ObConceptFrame * self = (ObConceptFrame *) _self;
1049 self->need_render = TRUE;
1050 frame_update_skin(self);
1053 /* is there anything present between us and the label? */
1054 static gboolean is_button_present(ObConceptFrame *_self, const gchar *lc,
1057 ObConceptFrame * self = (ObConceptFrame *) _self;
1058 for (; *lc != '\0' && lc >= plugin.config_title_layout; lc += dir) {
1060 continue; /* it was invalid */
1061 if (*lc == 'N' && self->decorations & OB_FRAME_DECOR_ICON)
1063 if (*lc == 'D' && self->decorations & OB_FRAME_DECOR_ALLDESKTOPS)
1065 if (*lc == 'S' && self->decorations & OB_FRAME_DECOR_SHADE)
1067 if (*lc == 'I' && self->decorations & OB_FRAME_DECOR_ICONIFY)
1069 if (*lc == 'M' && self->decorations & OB_FRAME_DECOR_MAXIMIZE)
1071 if (*lc == 'C' && self->decorations & OB_FRAME_DECOR_CLOSE)
1079 void flash_done(gpointer data)
1081 ObConceptFrame *self = data;
1083 if (self->focused != self->flash_on)
1084 frame_adjust_focus(self, self->focused);
1087 gboolean flash_timeout(gpointer data)
1089 ObConceptFrame *self = data;
1092 g_get_current_time(&now);
1093 if (now.tv_sec > self->flash_end.tv_sec
1094 || (now.tv_sec == self->flash_end.tv_sec && now.tv_usec
1095 >= self->flash_end.tv_usec))
1096 self->flashing = FALSE;
1098 if (!self->flashing)
1099 return FALSE; /* we are done */
1101 self->flash_on = !self->flash_on;
1102 if (!self->focused) {
1103 frame_adjust_focus(self, self->flash_on);
1104 self->focused = FALSE;
1107 return TRUE; /* go again */
1110 ObFramePlugin plugin = { 0, //gpointer handler;
1111 "libconcept.la", //gchar * filename;
1112 "Concept", //gchar * name;
1113 init, //gint (*init) (Display * display, gint screen);
1114 0, frame_new, //gpointer (*frame_new) (struct _ObClient *c);
1115 frame_free, //void (*frame_free) (gpointer self);
1116 frame_show, //void (*frame_show) (gpointer self);
1117 frame_hide, //void (*frame_hide) (gpointer self);
1118 frame_adjust_theme, //void (*frame_adjust_theme) (gpointer self);
1119 frame_adjust_shape, //void (*frame_adjust_shape) (gpointer self);
1120 frame_grab, //void (*frame_adjust_area) (gpointer self, gboolean moved, gboolean resized, gboolean fake);
1121 frame_ungrab, frame_context, //void (*frame_adjust_state) (gpointer self);
1122 frame_set_is_visible, frame_set_is_focus, frame_set_is_max_vert,
1123 frame_set_is_max_horz, frame_set_is_shaded,
1125 frame_flash_start, frame_flash_stop, frame_begin_iconify_animation,
1126 frame_end_iconify_animation, frame_iconify_animating,
1128 frame_set_decorations,
1129 /* This give the window area */
1130 frame_get_window_area, frame_set_client_area,
1131 /* Draw the frame */
1132 frame_update_layout, frame_update_skin,
1134 frame_set_hover_flag, frame_set_press_flag,
1138 frame_get_size, frame_get_decorations,
1140 frame_is_visible, frame_is_max_horz, frame_is_max_vert,
1144 /* This fields are fill by openbox. */
1145 0, //Display * ob_display;
1146 0, //gint ob_screen;
1147 0, //RrInstance *ob_rr_inst;
1148 0, //gboolean config_theme_keepborder;
1149 0, //struct _ObClient *focus_cycle_target;
1150 0, //gchar *config_title_layout;
1151 FALSE, //gboolean moveresize_in_progress;
1152 0, //struct _ObMainLoop *ob_main_loop;
1155 ObFramePlugin * get_info()