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 "frame_concept2_plugin.h"
21 #include "frame_concept2_render.h"
23 #include "openbox/frame.h"
24 #include "openbox/client.h"
25 #include "openbox/openbox.h"
26 #include "openbox/extensions.h"
27 #include "openbox/prop.h"
28 #include "openbox/grab.h"
29 #include "openbox/config.h"
30 #include "openbox/mainloop.h"
31 #include "openbox/focus_cycle.h"
32 #include "openbox/focus_cycle_indicator.h"
33 #include "openbox/moveresize.h"
34 #include "openbox/screen.h"
35 #include "render/theme.h"
40 OB_FLAG_CLOSE = 1 << 1,
41 OB_FLAG_DESK = 1 << 2,
42 OB_FLAG_SHADE = 1 << 3,
43 OB_FLAG_ICONIFY = 1 << 4
46 #define FRAME_EVENTMASK (EnterWindowMask | LeaveWindowMask | \
47 ButtonPressMask | ButtonReleaseMask | \
48 SubstructureRedirectMask | FocusChangeMask)
49 #define ELEMENT_EVENTMASK (ButtonPressMask | ButtonReleaseMask | \
50 ButtonMotionMask | PointerMotionMask | \
51 EnterWindowMask | LeaveWindowMask)
53 #define FRAME_ANIMATE_ICONIFY_TIME 150000 /* .15 seconds */
54 #define FRAME_ANIMATE_ICONIFY_STEP_TIME (G_USEC_PER_SEC / 60) /* 60 Hz */
56 #define FRAME_HANDLE_Y(f) (f->size.top + f->client->area.height + f->cbwidth_b)
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;
93 gpointer frame_new(struct _ObClient * client)
95 XSetWindowAttributes attrib;
100 self = g_new0(ObConceptFrame, 1);
101 self->client = client;
103 visual = check_32bit_client(client);
105 /* create the non-visible decor windows */
109 /* client has a 32-bit visual */
110 mask |= CWColormap | CWBackPixel | CWBorderPixel;
111 /* create a colormap with the visual */
112 OBCONCEPTFRAME(self)->colormap = attrib.colormap = XCreateColormap(
113 plugin.ob_display, RootWindow(plugin.ob_display,
114 plugin.ob_screen), visual, AllocNone);
115 attrib.background_pixel = BlackPixel(plugin.ob_display,
117 attrib.border_pixel = BlackPixel(plugin.ob_display, plugin.ob_screen);
119 self->window = createWindow(
120 RootWindow(plugin.ob_display, plugin.ob_screen), visual, mask,
123 /* create the visible decor windows */
127 /* client has a 32-bit visual */
128 mask |= CWColormap | CWBackPixel | CWBorderPixel;
129 attrib.colormap = RrColormap(plugin.ob_rr_inst);
132 self->background = createWindow(self->window, NULL, mask, &attrib);
135 attrib.event_mask = ELEMENT_EVENTMASK;
137 self->top = createWindow(self->window, NULL, mask, &attrib);
138 self->bottom = createWindow(self->window, NULL, mask, &attrib);
139 self->left = createWindow(self->window, NULL, mask, &attrib);
140 self->right = createWindow(self->window, NULL, mask, &attrib);
142 self->left_close = createWindow(self->left, NULL, mask, &attrib);
143 self->left_iconify = createWindow(self->left, NULL, mask, &attrib);
144 self->left_maximize = createWindow(self->left, NULL, mask, &attrib);
145 self->left_shade = createWindow(self->left, NULL, mask, &attrib);
147 self->handle = createWindow(self->left, NULL, mask, &attrib);
149 self->top_left = createWindow(self->window, NULL, mask, &attrib);
150 self->top_right = createWindow(self->window, NULL, mask, &attrib);
152 self->bottom_left = createWindow(self->window, NULL, mask, &attrib);
153 self->bottom_right = createWindow(self->window, NULL, mask, &attrib);
155 XMapWindow(plugin.ob_display, self->background);
157 self->focused = FALSE;
159 self->max_press = FALSE;
160 self->close_press = FALSE;
161 self->desk_press = FALSE;
162 self->iconify_press = FALSE;
163 self->shade_press = FALSE;
164 self->max_hover = FALSE;
165 self->close_hover = FALSE;
166 self->desk_hover = FALSE;
167 self->iconify_hover = FALSE;
168 self->shade_hover = FALSE;
170 set_theme_statics(self);
172 return (ObFrame*)self;
175 void set_theme_statics(gpointer _self)
177 ObConceptFrame * self = (ObConceptFrame *) _self;
178 /* do this before changing the frame's status like max_horz max_vert */
180 XResizeWindow(plugin.ob_display, self->top_left, 15,
181 theme_config.border_width);
182 XResizeWindow(plugin.ob_display, self->top_right, 15,
183 theme_config.border_width);
184 XResizeWindow(plugin.ob_display, self->bottom_left, 15,
185 theme_config.border_width);
186 XResizeWindow(plugin.ob_display, self->bottom_right, 15,
187 theme_config.border_width);
189 XResizeWindow(plugin.ob_display, self->left_close, theme_config.left_width,
191 XResizeWindow(plugin.ob_display, self->left_iconify,
192 theme_config.left_width, 15);
193 XResizeWindow(plugin.ob_display, self->left_maximize,
194 theme_config.left_width, 15);
195 XResizeWindow(plugin.ob_display, self->left_shade, theme_config.left_width,
197 XResizeWindow(plugin.ob_display, self->handle, theme_config.left_width, 15);
199 XMoveWindow(plugin.ob_display, self->left_close, 0, 0);
200 XMoveWindow(plugin.ob_display, self->left_iconify, 0, 15);
201 XMoveWindow(plugin.ob_display, self->left_maximize, 0, 30);
202 XMoveWindow(plugin.ob_display, self->left_shade, 0, 45);
203 XMoveWindow(plugin.ob_display, self->handle, 0, 60);
207 void free_theme_statics(gpointer _self)
209 ObConceptFrame * self = (ObConceptFrame *) _self;
212 void frame_free(gpointer self)
214 free_theme_statics(OBCONCEPTFRAME(self));
215 XDestroyWindow(plugin.ob_display, OBCONCEPTFRAME(self)->window);
216 if (OBCONCEPTFRAME(self)->colormap)
217 XFreeColormap(plugin.ob_display, OBCONCEPTFRAME(self)->colormap);
221 void frame_show(gpointer _self)
223 ObConceptFrame * self = (ObConceptFrame *) _self;
224 if (!self->visible) {
225 self->visible = TRUE;
226 frame_update_skin(self);
227 /* Grab the server to make sure that the frame window is mapped before
228 the client gets its MapNotify, i.e. to make sure the client is
229 _visible_ when it gets MapNotify. */
231 XMapWindow(plugin.ob_display, self->client->window);
232 XMapWindow(plugin.ob_display, self->window);
237 void frame_hide(gpointer _self)
239 ObConceptFrame * self = (ObConceptFrame *) _self;
241 self->visible = FALSE;
242 if (!frame_iconify_animating(self))
243 XUnmapWindow(plugin.ob_display, self->window);
244 /* we unmap the client itself so that we can get MapRequest
245 events, and because the ICCCM tells us to! */
246 XUnmapWindow(plugin.ob_display, self->client->window);
247 self->client->ignore_unmaps += 1;
251 void frame_adjust_theme(gpointer _self)
253 ObConceptFrame * self = (ObConceptFrame *) _self;
254 free_theme_statics(self);
255 set_theme_statics(self);
258 void frame_adjust_shape(gpointer _self)
261 ObConceptFrame * self = (ObConceptFrame *) _self;
265 if (!self->client->shaped)
267 /* clear the shape on the frame window */
268 XShapeCombineMask(plugin.ob_display, self->window, ShapeBounding,
275 /* make the frame's shape match the clients */
276 XShapeCombineShape(plugin.ob_display, self->window, ShapeBounding,
279 self->client->window,
280 ShapeBounding, ShapeSet);
283 if (self->decorations)
287 xrect[0].width = self->area.width;
288 xrect[0].height = self->size.top;
292 XShapeCombineRectangles(plugin.ob_display, self->window,
293 ShapeBounding, 0, 0, xrect, num,
294 ShapeUnion, Unsorted);
299 void frame_adjust_area(gpointer _self, gboolean moved, gboolean resized,
302 ObConceptFrame * self = (ObConceptFrame *) _self;
304 /* do this before changing the frame's status like max_horz max_vert */
305 frame_adjust_cursors(self);
307 /* Copy client status */
308 self->functions = self->client->functions;
309 self->decorations = self->client->decorations;
310 self->max_horz = self->client->max_horz;
311 self->max_vert = self->client->max_vert;
312 self->shaded = self->client->shaded;
314 if (self->decorations && !self->shaded) {
315 self->cbwidth_l = theme_config.left_width;
316 self->cbwidth_r = theme_config.border_width;
317 self->cbwidth_t = theme_config.border_width;
318 self->cbwidth_b = theme_config.border_width;
320 if (self->max_horz) {
321 self->cbwidth_l = theme_config.left_width;
325 if (self->max_vert) {
330 STRUT_SET(self->size, self->cbwidth_l, self->cbwidth_t,
331 self->cbwidth_r, self->cbwidth_b);
333 RECT_SET_SIZE(self->area, self->client->area.width + self->size.left
334 + self->size.right, self->client->area.height + self->size.top
335 + self->size.bottom);
337 self->width = self->area.width;
341 XMoveResizeWindow(plugin.ob_display, self->top, 15, 0,
342 self->area.width - 30, theme_config.border_width);
343 XMapWindow(plugin.ob_display, self->top);
345 XMoveResizeWindow(plugin.ob_display, self->bottom, 15,
346 self->area.height - theme_config.border_width,
347 self->area.width - 30, theme_config.border_width);
348 XMapWindow(plugin.ob_display, self->bottom);
350 XMoveResizeWindow(plugin.ob_display, self->left, 0,
351 theme_config.border_width, theme_config.left_width,
352 self->area.height - 2*theme_config.border_width);
353 XMapWindow(plugin.ob_display, self->left);
355 XMoveResizeWindow(plugin.ob_display, self->right, self->area.width
356 - theme_config.border_width, theme_config.border_width,
357 theme_config.border_width, self->area.height - 2
358 *theme_config.border_width);
359 XMapWindow(plugin.ob_display, self->right);
361 XMoveWindow(plugin.ob_display, self->top_left, 0, 0);
362 XMapWindow(plugin.ob_display, self->top_left);
363 XMoveWindow(plugin.ob_display, self->top_right, self->area.width
365 XMapWindow(plugin.ob_display, self->top_right);
366 XMoveWindow(plugin.ob_display, self->bottom_left, 0,
367 self->area.height - theme_config.border_width);
368 XMapWindow(plugin.ob_display, self->bottom_left);
369 XMoveWindow(plugin.ob_display, self->bottom_right, self->area.width
370 - 15, self->area.height - theme_config.border_width);
371 XMapWindow(plugin.ob_display, self->bottom_right);
373 XMapWindow(plugin.ob_display, self->left_close);
374 XMapWindow(plugin.ob_display, self->left_iconify);
375 XMapWindow(plugin.ob_display, self->left_maximize);
376 XMapWindow(plugin.ob_display, self->left_shade);
377 XMapWindow(plugin.ob_display, self->handle);
378 /* find the new coordinates, done after setting the frame.size, for
379 frame_client_gravity. */
380 self->area.x = self->client->area.x;
381 self->area.y = self->client->area.y;
382 frame_client_gravity(self, &self->area.x, &self->area.y);
384 XMoveResizeWindow(plugin.ob_display, self->background,
385 theme_config.border_width, theme_config.border_width,
386 self->area.width - 2 * theme_config.border_width,
387 self->area.height - 2 * theme_config.border_width);
388 XMapWindow(plugin.ob_display, self->background);
391 XMoveWindow(plugin.ob_display, self->client->window, self->size.left,
393 XMoveResizeWindow(plugin.ob_display, self->window, self->area.x,
394 self->area.y, self->area.width, self->area.height);
397 else if (self->shaded) {
398 self->cbwidth_l = theme_config.left_width;
402 STRUT_SET(self->size, self->cbwidth_l, self->cbwidth_t,
403 self->cbwidth_r, self->cbwidth_b);
405 RECT_SET_SIZE(self->area, theme_config.left_width, self->area.height);
407 /* find the new coordinates, done after setting the frame.size, for
408 frame_client_gravity. */
409 self->area.x = self->client->area.x;
410 self->area.y = self->client->area.y;
411 //frame_client_gravity(self, &self->area.x, &self->area.y);
412 self->width = self->area.width;
414 XUnmapWindow(plugin.ob_display, self->top);
415 XUnmapWindow(plugin.ob_display, self->bottom);
416 XUnmapWindow(plugin.ob_display, self->right);
417 XUnmapWindow(plugin.ob_display, self->top_left);
418 XUnmapWindow(plugin.ob_display, self->top_right);
419 XUnmapWindow(plugin.ob_display, self->bottom_left);
420 XUnmapWindow(plugin.ob_display, self->bottom_right);
422 XMoveResizeWindow(plugin.ob_display, self->left, 0, 0,
423 theme_config.left_width, self->area.height);
424 XMapWindow(plugin.ob_display, self->left);
427 XMoveWindow(plugin.ob_display, self->client->window,
428 theme_config.left_width, 0);
429 XMoveResizeWindow(plugin.ob_display, self->window, self->area.x,
430 self->area.y, self->area.width, self->area.height);
437 STRUT_SET(self->size, self->cbwidth_l, self->cbwidth_t,
438 self->cbwidth_r, self->cbwidth_b);
440 RECT_SET_SIZE(self->area, self->client->area.width + self->size.left
441 + self->size.right, self->client->area.height + self->size.top
442 + self->size.bottom);
444 /* find the new coordinates, done after setting the frame.size, for
445 frame_client_gravity. */
446 self->area.x = self->client->area.x;
447 self->area.y = self->client->area.y;
448 frame_client_gravity(self, &self->area.x, &self->area.y);
450 self->width = self->area.width;
452 XUnmapWindow(plugin.ob_display, self->top);
453 XUnmapWindow(plugin.ob_display, self->bottom);
454 XUnmapWindow(plugin.ob_display, self->left);
455 XUnmapWindow(plugin.ob_display, self->right);
456 XUnmapWindow(plugin.ob_display, self->top_left);
457 XUnmapWindow(plugin.ob_display, self->top_right);
458 XUnmapWindow(plugin.ob_display, self->bottom_left);
459 XUnmapWindow(plugin.ob_display, self->bottom_right);
461 XUnmapWindow(plugin.ob_display, self->handle);
463 XMoveResizeWindow(plugin.ob_display, self->background, 0, 0,
464 self->area.width, self->area.height);
465 XMapWindow(plugin.ob_display, self->background);
468 XMoveWindow(plugin.ob_display, self->client->window, self->size.left,
470 XMoveResizeWindow(plugin.ob_display, self->window, self->area.x,
471 self->area.y, self->area.width, self->area.height);
475 void frame_adjust_cursors(gpointer _self)
477 ObConceptFrame * self = (ObConceptFrame *) _self;
479 XSetWindowAttributes a;
480 a.cursor = ob_cursor(OB_CURSOR_NORTH);
481 XChangeWindowAttributes(plugin.ob_display, self->top, CWCursor, &a);
483 a.cursor = ob_cursor(OB_CURSOR_SOUTH);
484 XChangeWindowAttributes(plugin.ob_display, self->bottom, CWCursor, &a);
486 a.cursor = ob_cursor(OB_CURSOR_WEST);
487 XChangeWindowAttributes(plugin.ob_display, self->left, CWCursor, &a);
489 a.cursor = ob_cursor(OB_CURSOR_EAST);
490 XChangeWindowAttributes(plugin.ob_display, self->right, CWCursor, &a);
492 a.cursor = ob_cursor(OB_CURSOR_NORTHWEST);
493 XChangeWindowAttributes(plugin.ob_display, self->top_left, CWCursor, &a);
495 a.cursor = ob_cursor(OB_CURSOR_NORTHEAST);
496 XChangeWindowAttributes(plugin.ob_display, self->top_right, CWCursor, &a);
498 a.cursor = ob_cursor(OB_CURSOR_SOUTHWEST);
499 XChangeWindowAttributes(plugin.ob_display, self->bottom_left, CWCursor, &a);
501 a.cursor = ob_cursor(OB_CURSOR_SOUTHEAST);
502 XChangeWindowAttributes(plugin.ob_display, self->bottom_right, CWCursor, &a);
504 a.cursor = ob_cursor(OB_CURSOR_POINTER);
505 XChangeWindowAttributes(plugin.ob_display, self->left_close, CWCursor, &a);
506 XChangeWindowAttributes(plugin.ob_display, self->left_iconify, CWCursor, &a);
507 XChangeWindowAttributes(plugin.ob_display, self->left_maximize, CWCursor,
509 XChangeWindowAttributes(plugin.ob_display, self->left_shade, CWCursor, &a);
510 XChangeWindowAttributes(plugin.ob_display, self->handle, CWCursor, &a);
514 void frame_adjust_client_area(gpointer _self)
516 ObConceptFrame * self = (ObConceptFrame *) _self;
517 /* adjust the window which is there to prevent flashing on unmap */
518 XMoveResizeWindow(plugin.ob_display, self->background, 0, 0,
519 self->client->area.width, self->client->area.height);
522 void frame_adjust_state(gpointer _self)
524 ObConceptFrame * self = (ObConceptFrame *) _self;
525 self->need_render = TRUE;
526 framerender_frame(self);
529 void frame_adjust_focus(gpointer _self, gboolean hilite)
531 ObConceptFrame * self = (ObConceptFrame *) _self;
532 self->focused = hilite;
533 self->need_render = TRUE;
534 framerender_frame(self);
535 XFlush(plugin.ob_display);
538 void frame_adjust_title(gpointer _self)
540 ObConceptFrame * self = (ObConceptFrame *) _self;
541 self->need_render = TRUE;
542 framerender_frame(self);
545 void frame_adjust_icon(gpointer _self)
547 ObConceptFrame * self = (ObConceptFrame *) _self;
548 self->need_render = TRUE;
549 framerender_frame(self);
552 void frame_grab_client(gpointer _self, GHashTable * map)
554 ObConceptFrame * self = (ObConceptFrame *) _self;
555 /* DO NOT map the client window here. we used to do that, but it is bogus.
556 we need to set up the client's dimensions and everything before we
557 send a mapnotify or we create race conditions.
560 /* reparent the client to the frame */
561 XReparentWindow(plugin.ob_display, self->client->window, self->window, 0, 0);
564 When reparenting the client window, it is usually not mapped yet, since
565 this occurs from a MapRequest. However, in the case where Openbox is
566 starting up, the window is already mapped, so we'll see an unmap event
569 if (ob_state() == OB_STATE_STARTING)
570 ++self->client->ignore_unmaps;
572 /* select the event mask on the client's parent (to receive config/map
573 req's) the ButtonPress is to catch clicks on the client border */
574 XSelectInput(plugin.ob_display, self->window, FRAME_EVENTMASK);
576 /* set all the windows for the frame in the window_map */
577 g_hash_table_insert(map, &self->window, self->client);
578 g_hash_table_insert(map, &self->left, self->client);
579 g_hash_table_insert(map, &self->right, self->client);
581 g_hash_table_insert(map, &self->top, self->client);
582 g_hash_table_insert(map, &self->bottom, self->client);
584 g_hash_table_insert(map, &self->top_left, self->client);
585 g_hash_table_insert(map, &self->top_right, self->client);
587 g_hash_table_insert(map, &self->bottom_left, self->client);
588 g_hash_table_insert(map, &self->bottom_right, self->client);
590 g_hash_table_insert(map, &self->left_close, self->client);
591 g_hash_table_insert(map, &self->left_iconify, self->client);
592 g_hash_table_insert(map, &self->left_maximize, self->client);
593 g_hash_table_insert(map, &self->left_shade, self->client);
595 g_hash_table_insert(map, &self->handle, self->client);
599 void frame_release_client(gpointer _self, GHashTable * map)
601 ObConceptFrame * self = (ObConceptFrame *) _self;
603 gboolean reparent = TRUE;
605 /* if there was any animation going on, kill it */
606 ob_main_loop_timeout_remove_data(plugin.ob_main_loop,
607 frame_animate_iconify, self, FALSE);
609 /* check if the app has already reparented its window away */
610 while (XCheckTypedWindowEvent(plugin.ob_display, self->client->window,
611 ReparentNotify, &ev)) {
612 /* This check makes sure we don't catch our own reparent action to
613 our frame window. This doesn't count as the app reparenting itself
616 Reparent events that are generated by us are just discarded here.
617 They are of no consequence to us anyhow.
619 if (ev.xreparent.parent != self->window) {
621 XPutBackEvent(plugin.ob_display, &ev);
627 /* according to the ICCCM - if the client doesn't reparent itself,
628 then we will reparent the window to root for them */
629 XReparentWindow(plugin.ob_display, self->client->window, RootWindow(
630 plugin.ob_display, plugin.ob_screen), self->client->area.x,
631 self->client->area.y);
634 /* remove all the windows for the frame from the window_map */
635 g_hash_table_remove(map, &self->window);
637 g_hash_table_remove(map, &self->left);
638 g_hash_table_remove(map, &self->right);
640 g_hash_table_remove(map, &self->top);
641 g_hash_table_remove(map, &self->bottom);
643 g_hash_table_remove(map, &self->top_left);
644 g_hash_table_remove(map, &self->top_right);
646 g_hash_table_remove(map, &self->bottom_left);
647 g_hash_table_remove(map, &self->bottom_right);
649 g_hash_table_remove(map, &self->left_close);
650 g_hash_table_remove(map, &self->left_iconify);
651 g_hash_table_remove(map, &self->left_maximize);
652 g_hash_table_remove(map, &self->left_shade);
654 g_hash_table_remove(map, &self->handle);
656 ob_main_loop_timeout_remove_data(plugin.ob_main_loop, flash_timeout, self,
660 /* is there anything present between us and the label? */
661 static gboolean is_button_present(ObConceptFrame *_self, const gchar *lc,
664 ObConceptFrame * self = (ObConceptFrame *) _self;
665 for (; *lc != '\0' && lc >= plugin.config_title_layout; lc += dir) {
667 continue; /* it was invalid */
668 if (*lc == 'N' && self->decorations & OB_FRAME_DECOR_ICON)
670 if (*lc == 'D' && self->decorations & OB_FRAME_DECOR_ALLDESKTOPS)
672 if (*lc == 'S' && self->decorations & OB_FRAME_DECOR_SHADE)
674 if (*lc == 'I' && self->decorations & OB_FRAME_DECOR_ICONIFY)
676 if (*lc == 'M' && self->decorations & OB_FRAME_DECOR_MAXIMIZE)
678 if (*lc == 'C' && self->decorations & OB_FRAME_DECOR_CLOSE)
686 ObFrameContext frame_context(gpointer _self, Window win, gint x, gint y)
688 /* Here because client can be NULL */
689 ObConceptFrame *self = OBCONCEPTFRAME(_self);
691 if (win == self->window)
692 return OB_FRAME_CONTEXT_FRAME;
694 if (win == self->bottom)
695 return OB_FRAME_CONTEXT_BOTTOM;
697 if (win == self->bottom_left)
698 return OB_FRAME_CONTEXT_BLCORNER;
700 if (win == self->bottom_right)
701 return OB_FRAME_CONTEXT_BRCORNER;
703 if (win == self->top)
704 return OB_FRAME_CONTEXT_TOP;
706 if (win == self->top_left)
707 return OB_FRAME_CONTEXT_TLCORNER;
709 if (win == self->top_right)
710 return OB_FRAME_CONTEXT_TRCORNER;
712 if (win == self->left_close)
713 return OB_FRAME_CONTEXT_CLOSE;
714 if (win == self->left_iconify)
715 return OB_FRAME_CONTEXT_ICONIFY;
716 if (win == self->left_maximize)
717 return OB_FRAME_CONTEXT_MAXIMIZE;
718 if (win == self->left_shade)
719 return OB_FRAME_CONTEXT_SHADE;
720 if (win == self->handle)
721 return OB_FRAME_CONTEXT_TITLEBAR;
723 if (win == self->left)
724 return OB_FRAME_CONTEXT_LEFT;
725 if (win == self->right)
726 return OB_FRAME_CONTEXT_RIGHT;
728 return OB_FRAME_CONTEXT_NONE;
731 void frame_client_gravity(gpointer _self, gint *x, gint *y)
733 ObConceptFrame * self = OBCONCEPTFRAME(_self);
735 switch (self->client->gravity) {
737 case NorthWestGravity:
738 case SouthWestGravity:
745 /* the middle of the client will be the middle of the frame */
746 *x -= (self->size.right - self->size.left) / 2;
749 case NorthEastGravity:
750 case SouthEastGravity:
752 /* the right side of the client will be the right side of the frame */
753 *x -= self->size.right + self->size.left - self->client->border_width
759 /* the client's position won't move */
760 *x -= self->size.left - self->client->border_width;
765 switch (self->client->gravity) {
767 case NorthWestGravity:
768 case NorthEastGravity:
775 /* the middle of the client will be the middle of the frame */
776 *y -= (self->size.bottom - self->size.top) / 2;
779 case SouthWestGravity:
780 case SouthEastGravity:
782 /* the bottom of the client will be the bottom of the frame */
783 *y -= self->size.bottom + self->size.top - self->client->border_width
789 /* the client's position won't move */
790 *y -= self->size.top - self->client->border_width;
795 void frame_frame_gravity(gpointer _self, gint *x, gint *y)
797 ObConceptFrame * self = (ObConceptFrame *) _self;
799 switch (self->client->gravity) {
801 case NorthWestGravity:
803 case SouthWestGravity:
808 /* the middle of the client will be the middle of the frame */
809 *x += (self->size.right - self->size.left) / 2;
811 case NorthEastGravity:
813 case SouthEastGravity:
814 /* the right side of the client will be the right side of the frame */
815 *x += self->size.right + self->size.left - self->client->border_width
820 /* the client's position won't move */
821 *x += self->size.left - self->client->border_width;
826 switch (self->client->gravity) {
828 case NorthWestGravity:
830 case NorthEastGravity:
835 /* the middle of the client will be the middle of the frame */
836 *y += (self->size.bottom - self->size.top) / 2;
838 case SouthWestGravity:
840 case SouthEastGravity:
841 /* the bottom of the client will be the bottom of the frame */
842 *y += self->size.bottom + self->size.top - self->client->border_width
847 /* the client's position won't move */
848 *y += self->size.top - self->client->border_width;
853 void frame_rect_to_frame(gpointer _self, Rect *r)
855 ObConceptFrame * self = (ObConceptFrame *) _self;
856 r->width += self->size.left + self->size.right;
857 r->height += self->size.top + self->size.bottom;
858 frame_client_gravity(self, &r->x, &r->y);
861 void frame_rect_to_client(gpointer _self, Rect *r)
863 ObConceptFrame * self = (ObConceptFrame *) _self;
864 r->width -= self->size.left + self->size.right;
865 r->height -= self->size.top + self->size.bottom;
866 frame_frame_gravity(self, &r->x, &r->y);
869 void flash_done(gpointer data)
871 ObConceptFrame *self = data;
873 if (self->focused != self->flash_on)
874 frame_adjust_focus(self, self->focused);
877 gboolean flash_timeout(gpointer data)
879 ObConceptFrame *self = data;
882 g_get_current_time(&now);
883 if (now.tv_sec > self->flash_end.tv_sec
884 || (now.tv_sec == self->flash_end.tv_sec && now.tv_usec
885 >= self->flash_end.tv_usec))
886 self->flashing = FALSE;
889 return FALSE; /* we are done */
891 self->flash_on = !self->flash_on;
892 if (!self->focused) {
893 frame_adjust_focus(self, self->flash_on);
894 self->focused = FALSE;
897 return TRUE; /* go again */
900 void frame_flash_start(gpointer _self)
902 ObConceptFrame * self = (ObConceptFrame *) _self;
903 self->flash_on = self->focused;
906 ob_main_loop_timeout_add(plugin.ob_main_loop, G_USEC_PER_SEC * 0.6,
907 flash_timeout, self, g_direct_equal, flash_done);
908 g_get_current_time(&self->flash_end);
909 g_time_val_add(&self->flash_end, G_USEC_PER_SEC * 5);
911 self->flashing = TRUE;
914 void frame_flash_stop(gpointer _self)
916 ObConceptFrame * self = (ObConceptFrame *) _self;
917 self->flashing = FALSE;
920 static gulong frame_animate_iconify_time_left(gpointer _self,
923 ObConceptFrame * self = (ObConceptFrame *) _self;
925 sec = self->iconify_animation_end.tv_sec - now->tv_sec;
926 usec = self->iconify_animation_end.tv_usec - now->tv_usec;
928 usec += G_USEC_PER_SEC;
931 /* no negative values */
932 return MAX(sec * G_USEC_PER_SEC + usec, 0);
935 gboolean frame_animate_iconify(gpointer p)
937 ObConceptFrame *self = p;
939 gint iconx, icony, iconw;
944 if (self->client->icon_geometry.width == 0) {
945 /* there is no icon geometry set so just go straight down */
947 screen_physical_area_monitor(screen_find_monitor(&self->area));
948 iconx = self->area.x + self->area.width / 2 + 32;
949 icony = a->y + a->width;
954 iconx = self->client->icon_geometry.x;
955 icony = self->client->icon_geometry.y;
956 iconw = self->client->icon_geometry.width;
959 iconifying = self->iconify_animation_going > 0;
961 /* how far do we have left to go ? */
962 g_get_current_time(&now);
963 time = frame_animate_iconify_time_left(self, &now);
965 if (time == 0 || iconifying) {
966 /* start where the frame is supposed to be */
969 w = self->area.width;
970 h = self->area.height;
973 /* start at the icon */
977 h = self->size.top; /* just the titlebar */
984 dx = self->area.x - iconx;
985 dy = self->area.y - icony;
986 dw = self->area.width - self->bwidth * 2 - iconw;
987 /* if restoring, we move in the opposite direction */
994 elapsed = FRAME_ANIMATE_ICONIFY_TIME - time;
995 x = x - (dx * elapsed) / FRAME_ANIMATE_ICONIFY_TIME;
996 y = y - (dy * elapsed) / FRAME_ANIMATE_ICONIFY_TIME;
997 w = w - (dw * elapsed) / FRAME_ANIMATE_ICONIFY_TIME;
998 h = self->size.top; /* just the titlebar */
1002 frame_end_iconify_animation(self);
1004 XMoveResizeWindow(plugin.ob_display, self->window, x, y, w, h);
1005 XFlush(plugin.ob_display);
1008 return time > 0; /* repeat until we're out of time */
1011 void frame_end_iconify_animation(gpointer _self)
1013 ObConceptFrame * self = (ObConceptFrame *) _self;
1014 /* see if there is an animation going */
1015 if (self->iconify_animation_going == 0)
1019 XUnmapWindow(plugin.ob_display, self->window);
1021 /* Send a ConfigureNotify when the animation is done, this fixes
1022 KDE's pager showing the window in the wrong place. since the
1023 window is mapped at a different location and is then moved, we
1024 need to send the synthetic configurenotify, since apps may have
1025 read the position when the client mapped, apparently. */
1026 client_reconfigure(self->client, TRUE);
1029 /* we're not animating any more ! */
1030 self->iconify_animation_going = 0;
1032 XMoveResizeWindow(plugin.ob_display, self->window, self->area.x,
1033 self->area.y, self->area.width, self->area.height);
1034 /* we delay re-rendering until after we're done animating */
1035 framerender_frame(self);
1036 XFlush(plugin.ob_display);
1039 void frame_begin_iconify_animation(gpointer _self, gboolean iconifying)
1041 ObConceptFrame * self = (ObConceptFrame *) _self;
1043 gboolean new_anim = FALSE;
1044 gboolean set_end = TRUE;
1047 /* if there is no titlebar, just don't animate for now
1048 XXX it would be nice tho.. */
1049 if (!(self->decorations & OB_FRAME_DECOR_TITLEBAR))
1052 /* get the current time */
1053 g_get_current_time(&now);
1055 /* get how long until the end */
1056 time = FRAME_ANIMATE_ICONIFY_TIME;
1057 if (self->iconify_animation_going) {
1058 if (!!iconifying != (self->iconify_animation_going > 0)) {
1059 /* animation was already going on in the opposite direction */
1060 time = time - frame_animate_iconify_time_left(self, &now);
1063 /* animation was already going in the same direction */
1068 self->iconify_animation_going = iconifying ? 1 : -1;
1070 /* set the ending time */
1072 self->iconify_animation_end.tv_sec = now.tv_sec;
1073 self->iconify_animation_end.tv_usec = now.tv_usec;
1074 g_time_val_add(&self->iconify_animation_end, time);
1078 ob_main_loop_timeout_remove_data(plugin.ob_main_loop,
1079 frame_animate_iconify, self, FALSE);
1080 ob_main_loop_timeout_add(plugin.ob_main_loop,
1081 FRAME_ANIMATE_ICONIFY_STEP_TIME, frame_animate_iconify, self,
1082 g_direct_equal, NULL);
1084 /* do the first step */
1085 frame_animate_iconify(self);
1087 /* show it during the animation even if it is not "visible" */
1089 XMapWindow(plugin.ob_display, self->window);
1093 gboolean frame_iconify_animating(gpointer _self)
1095 ObConceptFrame * self = (ObConceptFrame *) _self;
1096 return self->iconify_animation_going != 0;
1099 ObFramePlugin plugin = { 0, //gpointer handler;
1100 "libdefault.la", //gchar * filename;
1101 "Default", //gchar * name;
1102 init, //gint (*init) (Display * display, gint screen);
1104 frame_new, //gpointer (*frame_new) (struct _ObClient *c);
1105 frame_free, //void (*frame_free) (gpointer self);
1106 frame_show, //void (*frame_show) (gpointer self);
1107 frame_hide, //void (*frame_hide) (gpointer self);
1108 frame_adjust_theme, //void (*frame_adjust_theme) (gpointer self);
1109 frame_adjust_shape, //void (*frame_adjust_shape) (gpointer self);
1110 frame_adjust_area, //void (*frame_adjust_area) (gpointer self, gboolean moved, gboolean resized, gboolean fake);
1111 frame_adjust_client_area, //void (*frame_adjust_client_area) (gpointer self);
1112 frame_adjust_state, //void (*frame_adjust_state) (gpointer self);
1113 frame_adjust_focus, //void (*frame_adjust_focus) (gpointer self, gboolean hilite);
1114 frame_adjust_title, //void (*frame_adjust_title) (gpointer self);
1115 frame_adjust_icon, //void (*frame_adjust_icon) (gpointer self);
1116 frame_grab_client, //void (*frame_grab_client) (gpointer self);
1117 frame_release_client, //void (*frame_release_client) (gpointer self);
1118 frame_context, //ObFrameContext (*frame_context) (struct _ObClient *self, Window win, gint x, gint y);
1119 frame_client_gravity, //void (*frame_client_gravity) (gpointer self, gint *x, gint *y);
1120 frame_frame_gravity, //void (*frame_frame_gravity) (gpointer self, gint *x, gint *y);
1121 frame_rect_to_frame, //void (*frame_rect_to_frame) (gpointer self, Rect *r);
1122 frame_rect_to_client, //void (*frame_rect_to_client) (gpointer self, Rect *r);
1123 frame_flash_start, //void (*frame_flash_start) (gpointer self);
1124 frame_flash_stop, //void (*frame_flash_stop) (gpointer self);
1125 frame_begin_iconify_animation, //void (*frame_begin_iconify_animation) (gpointer self, gboolean iconifying);
1126 frame_end_iconify_animation, //void (*frame_end_iconify_animation) (gpointer self);
1127 frame_iconify_animating, // gboolean (*frame_iconify_animating)(gpointer p);
1130 /* This fields are fill by openbox. */
1131 0, //Display * ob_display;
1132 0, //gint ob_screen;
1133 0, //RrInstance *ob_rr_inst;
1134 0, //gboolean config_theme_keepborder;
1135 0, //struct _ObClient *focus_cycle_target;
1136 0, //gchar *config_title_layout;
1137 FALSE, //gboolean moveresize_in_progress;
1138 0, //struct _ObMainLoop *ob_main_loop;
1141 ObFramePlugin * get_info()