Fix compile failure when X_HAVE_UTF8_STRING is not defined
[openbox.git] / openbox / frame.c
blob3dbcf1265d6088acb5358d4877f072efb3ade53a
1 /* -*- indent-tabs-mode: nil; tab-width: 4; c-basic-offset: 4; -*-
3 frame.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.h"
21 #include "client.h"
22 #include "openbox.h"
23 #include "grab.h"
24 #include "debug.h"
25 #include "config.h"
26 #include "framerender.h"
27 #include "focus_cycle.h"
28 #include "focus_cycle_indicator.h"
29 #include "moveresize.h"
30 #include "screen.h"
31 #include "obrender/theme.h"
32 #include "obt/display.h"
33 #include "obt/xqueue.h"
34 #include "obt/prop.h"
36 #define FRAME_EVENTMASK (EnterWindowMask | LeaveWindowMask | \
37 ButtonPressMask | ButtonReleaseMask | \
38 SubstructureRedirectMask | FocusChangeMask)
39 #define ELEMENT_EVENTMASK (ButtonPressMask | ButtonReleaseMask | \
40 ButtonMotionMask | PointerMotionMask | \
41 EnterWindowMask | LeaveWindowMask)
43 #define FRAME_ANIMATE_ICONIFY_TIME 150000 /* .15 seconds */
44 #define FRAME_ANIMATE_ICONIFY_STEP_TIME (1000 / 60) /* 60 Hz */
46 #define FRAME_HANDLE_Y(f) (f->size.top + f->client->area.height + f->cbwidth_b)
48 static void flash_done(gpointer data);
49 static gboolean flash_timeout(gpointer data);
51 static void layout_title(ObFrame *self);
52 static void set_theme_statics(ObFrame *self);
53 static void free_theme_statics(ObFrame *self);
54 static gboolean frame_animate_iconify(gpointer self);
55 static void frame_adjust_cursors(ObFrame *self);
57 static Window createWindow(Window parent, Visual *visual,
58 gulong mask, XSetWindowAttributes *attrib)
60 return XCreateWindow(obt_display, parent, 0, 0, 1, 1, 0,
61 (visual ? 32 : RrDepth(ob_rr_inst)), InputOutput,
62 (visual ? visual : RrVisual(ob_rr_inst)),
63 mask, attrib);
67 static Visual *check_32bit_client(ObClient *c)
69 XWindowAttributes wattrib;
70 Status ret;
72 /* we're already running at 32 bit depth, yay. we don't need to use their
73 visual */
74 if (RrDepth(ob_rr_inst) == 32)
75 return NULL;
77 ret = XGetWindowAttributes(obt_display, c->window, &wattrib);
78 g_assert(ret != BadDrawable);
79 g_assert(ret != BadWindow);
81 if (wattrib.depth == 32)
82 return wattrib.visual;
83 return NULL;
86 ObFrame *frame_new(ObClient *client)
88 XSetWindowAttributes attrib;
89 gulong mask;
90 ObFrame *self;
91 Visual *visual;
93 self = g_slice_new0(ObFrame);
94 self->client = client;
96 visual = check_32bit_client(client);
98 /* create the non-visible decor windows */
100 mask = 0;
101 if (visual) {
102 /* client has a 32-bit visual */
103 mask = CWColormap | CWBackPixel | CWBorderPixel;
104 /* create a colormap with the visual */
105 self->colormap = attrib.colormap =
106 XCreateColormap(obt_display, obt_root(ob_screen),
107 visual, AllocNone);
108 attrib.background_pixel = BlackPixel(obt_display, ob_screen);
109 attrib.border_pixel = BlackPixel(obt_display, ob_screen);
111 self->window = createWindow(obt_root(ob_screen), visual,
112 mask, &attrib);
114 /* create the visible decor windows */
116 mask = 0;
117 if (visual) {
118 /* client has a 32-bit visual */
119 mask = CWColormap | CWBackPixel | CWBorderPixel;
120 attrib.colormap = RrColormap(ob_rr_inst);
123 self->backback = createWindow(self->window, NULL, mask, &attrib);
124 self->backfront = createWindow(self->backback, NULL, mask, &attrib);
126 mask |= CWEventMask;
127 attrib.event_mask = ELEMENT_EVENTMASK;
128 self->innerleft = createWindow(self->window, NULL, mask, &attrib);
129 self->innertop = createWindow(self->window, NULL, mask, &attrib);
130 self->innerright = createWindow(self->window, NULL, mask, &attrib);
131 self->innerbottom = createWindow(self->window, NULL, mask, &attrib);
133 self->innerblb = createWindow(self->innerbottom, NULL, mask, &attrib);
134 self->innerbrb = createWindow(self->innerbottom, NULL, mask, &attrib);
135 self->innerbll = createWindow(self->innerleft, NULL, mask, &attrib);
136 self->innerbrr = createWindow(self->innerright, NULL, mask, &attrib);
138 self->title = createWindow(self->window, NULL, mask, &attrib);
139 self->titleleft = createWindow(self->window, NULL, mask, &attrib);
140 self->titletop = createWindow(self->window, NULL, mask, &attrib);
141 self->titletopleft = createWindow(self->window, NULL, mask, &attrib);
142 self->titletopright = createWindow(self->window, NULL, mask, &attrib);
143 self->titleright = createWindow(self->window, NULL, mask, &attrib);
144 self->titlebottom = createWindow(self->window, NULL, mask, &attrib);
146 self->topresize = createWindow(self->title, NULL, mask, &attrib);
147 self->tltresize = createWindow(self->title, NULL, mask, &attrib);
148 self->tllresize = createWindow(self->title, NULL, mask, &attrib);
149 self->trtresize = createWindow(self->title, NULL, mask, &attrib);
150 self->trrresize = createWindow(self->title, NULL, mask, &attrib);
152 self->left = createWindow(self->window, NULL, mask, &attrib);
153 self->right = createWindow(self->window, NULL, mask, &attrib);
155 self->label = createWindow(self->title, NULL, mask, &attrib);
156 self->max = createWindow(self->title, NULL, mask, &attrib);
157 self->close = createWindow(self->title, NULL, mask, &attrib);
158 self->desk = createWindow(self->title, NULL, mask, &attrib);
159 self->shade = createWindow(self->title, NULL, mask, &attrib);
160 self->icon = createWindow(self->title, NULL, mask, &attrib);
161 self->iconify = createWindow(self->title, NULL, mask, &attrib);
163 self->handle = createWindow(self->window, NULL, mask, &attrib);
164 self->lgrip = createWindow(self->handle, NULL, mask, &attrib);
165 self->rgrip = createWindow(self->handle, NULL, mask, &attrib);
167 self->handleleft = createWindow(self->handle, NULL, mask, &attrib);
168 self->handleright = createWindow(self->handle, NULL, mask, &attrib);
170 self->handletop = createWindow(self->window, NULL, mask, &attrib);
171 self->handlebottom = createWindow(self->window, NULL, mask, &attrib);
172 self->lgripleft = createWindow(self->window, NULL, mask, &attrib);
173 self->lgriptop = createWindow(self->window, NULL, mask, &attrib);
174 self->lgripbottom = createWindow(self->window, NULL, mask, &attrib);
175 self->rgripright = createWindow(self->window, NULL, mask, &attrib);
176 self->rgriptop = createWindow(self->window, NULL, mask, &attrib);
177 self->rgripbottom = createWindow(self->window, NULL, mask, &attrib);
179 self->focused = FALSE;
181 /* the other stuff is shown based on decor settings */
182 XMapWindow(obt_display, self->label);
183 XMapWindow(obt_display, self->backback);
184 XMapWindow(obt_display, self->backfront);
186 self->max_press = self->close_press = self->desk_press =
187 self->iconify_press = self->shade_press = FALSE;
188 self->max_hover = self->close_hover = self->desk_hover =
189 self->iconify_hover = self->shade_hover = FALSE;
191 /* make sure the size will be different the first time, so the extent hints
192 will be set */
193 STRUT_SET(self->oldsize, -1, -1, -1, -1);
195 set_theme_statics(self);
197 return self;
200 static void set_theme_statics(ObFrame *self)
202 /* set colors/appearance/sizes for stuff that doesn't change */
203 XResizeWindow(obt_display, self->max,
204 ob_rr_theme->button_size, ob_rr_theme->button_size);
205 XResizeWindow(obt_display, self->iconify,
206 ob_rr_theme->button_size, ob_rr_theme->button_size);
207 XResizeWindow(obt_display, self->icon,
208 ob_rr_theme->button_size + 2, ob_rr_theme->button_size + 2);
209 XResizeWindow(obt_display, self->close,
210 ob_rr_theme->button_size, ob_rr_theme->button_size);
211 XResizeWindow(obt_display, self->desk,
212 ob_rr_theme->button_size, ob_rr_theme->button_size);
213 XResizeWindow(obt_display, self->shade,
214 ob_rr_theme->button_size, ob_rr_theme->button_size);
215 XResizeWindow(obt_display, self->tltresize,
216 ob_rr_theme->grip_width, ob_rr_theme->paddingy + 1);
217 XResizeWindow(obt_display, self->trtresize,
218 ob_rr_theme->grip_width, ob_rr_theme->paddingy + 1);
219 XResizeWindow(obt_display, self->tllresize,
220 ob_rr_theme->paddingx + 1, ob_rr_theme->title_height);
221 XResizeWindow(obt_display, self->trrresize,
222 ob_rr_theme->paddingx + 1, ob_rr_theme->title_height);
225 static void free_theme_statics(ObFrame *self)
229 void frame_free(ObFrame *self)
231 free_theme_statics(self);
233 XDestroyWindow(obt_display, self->window);
234 if (self->colormap)
235 XFreeColormap(obt_display, self->colormap);
237 g_slice_free(ObFrame, self);
240 void frame_show(ObFrame *self)
242 if (!self->visible) {
243 self->visible = TRUE;
244 framerender_frame(self);
245 /* Grab the server to make sure that the frame window is mapped before
246 the client gets its MapNotify, i.e. to make sure the client is
247 _visible_ when it gets MapNotify. */
248 grab_server(TRUE);
249 XMapWindow(obt_display, self->client->window);
250 XMapWindow(obt_display, self->window);
251 grab_server(FALSE);
255 void frame_hide(ObFrame *self)
257 if (self->visible) {
258 self->visible = FALSE;
259 if (!frame_iconify_animating(self))
260 XUnmapWindow(obt_display, self->window);
261 /* we unmap the client itself so that we can get MapRequest
262 events, and because the ICCCM tells us to! */
263 XUnmapWindow(obt_display, self->client->window);
264 self->client->ignore_unmaps += 1;
268 void frame_adjust_theme(ObFrame *self)
270 free_theme_statics(self);
271 set_theme_statics(self);
274 #ifdef SHAPE
275 void frame_adjust_shape_kind(ObFrame *self, int kind)
277 gint num;
278 XRectangle xrect[2];
279 gboolean shaped;
281 shaped = (kind == ShapeBounding && self->client->shaped);
282 #ifdef ShapeInput
283 shaped |= (kind == ShapeInput && self->client->shaped_input);
284 #endif
286 if (!shaped) {
287 /* clear the shape on the frame window */
288 XShapeCombineMask(obt_display, self->window, kind,
289 self->size.left,
290 self->size.top,
291 None, ShapeSet);
292 } else {
293 /* make the frame's shape match the clients */
294 XShapeCombineShape(obt_display, self->window, kind,
295 self->size.left,
296 self->size.top,
297 self->client->window,
298 kind, ShapeSet);
300 num = 0;
301 if (self->decorations & OB_FRAME_DECOR_TITLEBAR) {
302 xrect[0].x = 0;
303 xrect[0].y = 0;
304 xrect[0].width = self->area.width;
305 xrect[0].height = self->size.top;
306 ++num;
309 if (self->decorations & OB_FRAME_DECOR_HANDLE &&
310 ob_rr_theme->handle_height > 0)
312 xrect[1].x = 0;
313 xrect[1].y = FRAME_HANDLE_Y(self);
314 xrect[1].width = self->area.width;
315 xrect[1].height = ob_rr_theme->handle_height +
316 self->bwidth * 2;
317 ++num;
320 XShapeCombineRectangles(obt_display, self->window,
321 ShapeBounding, 0, 0, xrect, num,
322 ShapeUnion, Unsorted);
325 #endif
327 void frame_adjust_shape(ObFrame *self)
329 #ifdef SHAPE
330 frame_adjust_shape_kind(self, ShapeBounding);
331 #ifdef ShapeInput
332 frame_adjust_shape_kind(self, ShapeInput);
333 #endif
334 #endif
337 void frame_adjust_area(ObFrame *self, gboolean moved,
338 gboolean resized, gboolean fake)
340 if (resized) {
341 /* do this before changing the frame's status like max_horz max_vert */
342 frame_adjust_cursors(self);
344 self->functions = self->client->functions;
345 self->decorations = self->client->decorations;
346 self->max_horz = self->client->max_horz;
347 self->max_vert = self->client->max_vert;
348 self->shaded = self->client->shaded;
350 if (self->decorations & OB_FRAME_DECOR_BORDER)
351 self->bwidth = self->client->undecorated ?
352 ob_rr_theme->ubwidth : ob_rr_theme->fbwidth;
353 else
354 self->bwidth = 0;
356 if (self->decorations & OB_FRAME_DECOR_BORDER &&
357 !self->client->undecorated)
359 self->cbwidth_l = self->cbwidth_r = ob_rr_theme->cbwidthx;
360 self->cbwidth_t = self->cbwidth_b = ob_rr_theme->cbwidthy;
361 } else
362 self->cbwidth_l = self->cbwidth_t =
363 self->cbwidth_r = self->cbwidth_b = 0;
365 if (self->max_horz) {
366 self->cbwidth_l = self->cbwidth_r = 0;
367 self->width = self->client->area.width;
368 if (self->max_vert)
369 self->cbwidth_b = 0;
370 } else
371 self->width = self->client->area.width +
372 self->cbwidth_l + self->cbwidth_r;
374 /* some elements are sized based of the width, so don't let them have
375 negative values */
376 self->width = MAX(self->width,
377 (ob_rr_theme->grip_width + self->bwidth) * 2 + 1);
379 STRUT_SET(self->size,
380 self->cbwidth_l + (!self->max_horz ? self->bwidth : 0),
381 self->cbwidth_t +
382 (!self->max_horz || !self->max_vert ? self->bwidth : 0),
383 self->cbwidth_r + (!self->max_horz ? self->bwidth : 0),
384 self->cbwidth_b +
385 (!self->max_horz || !self->max_vert ? self->bwidth : 0));
387 if (self->decorations & OB_FRAME_DECOR_TITLEBAR)
388 self->size.top += ob_rr_theme->title_height + self->bwidth;
389 else if (self->max_horz && self->max_vert) {
390 /* A maximized and undecorated window needs a border on the
391 top of the window to let the user still undecorate/unmaximize the
392 window via the client menu. */
393 self->size.top += self->bwidth;
396 if (self->decorations & OB_FRAME_DECOR_HANDLE &&
397 ob_rr_theme->handle_height > 0)
399 self->size.bottom += ob_rr_theme->handle_height + self->bwidth;
402 /* position/size and map/unmap all the windows */
404 if (!fake) {
405 gint innercornerheight =
406 ob_rr_theme->grip_width - self->size.bottom;
408 if (self->cbwidth_l) {
409 XMoveResizeWindow(obt_display, self->innerleft,
410 self->size.left - self->cbwidth_l,
411 self->size.top,
412 self->cbwidth_l, self->client->area.height);
414 XMapWindow(obt_display, self->innerleft);
415 } else
416 XUnmapWindow(obt_display, self->innerleft);
418 if (self->cbwidth_l && innercornerheight > 0) {
419 XMoveResizeWindow(obt_display, self->innerbll,
421 self->client->area.height -
422 (ob_rr_theme->grip_width -
423 self->size.bottom),
424 self->cbwidth_l,
425 ob_rr_theme->grip_width - self->size.bottom);
427 XMapWindow(obt_display, self->innerbll);
428 } else
429 XUnmapWindow(obt_display, self->innerbll);
431 if (self->cbwidth_r) {
432 XMoveResizeWindow(obt_display, self->innerright,
433 self->size.left + self->client->area.width,
434 self->size.top,
435 self->cbwidth_r, self->client->area.height);
437 XMapWindow(obt_display, self->innerright);
438 } else
439 XUnmapWindow(obt_display, self->innerright);
441 if (self->cbwidth_r && innercornerheight > 0) {
442 XMoveResizeWindow(obt_display, self->innerbrr,
444 self->client->area.height -
445 (ob_rr_theme->grip_width -
446 self->size.bottom),
447 self->cbwidth_r,
448 ob_rr_theme->grip_width - self->size.bottom);
450 XMapWindow(obt_display, self->innerbrr);
451 } else
452 XUnmapWindow(obt_display, self->innerbrr);
454 if (self->cbwidth_t) {
455 XMoveResizeWindow(obt_display, self->innertop,
456 self->size.left - self->cbwidth_l,
457 self->size.top - self->cbwidth_t,
458 self->client->area.width +
459 self->cbwidth_l + self->cbwidth_r,
460 self->cbwidth_t);
462 XMapWindow(obt_display, self->innertop);
463 } else
464 XUnmapWindow(obt_display, self->innertop);
466 if (self->cbwidth_b) {
467 XMoveResizeWindow(obt_display, self->innerbottom,
468 self->size.left - self->cbwidth_l,
469 self->size.top + self->client->area.height,
470 self->client->area.width +
471 self->cbwidth_l + self->cbwidth_r,
472 self->cbwidth_b);
474 XMoveResizeWindow(obt_display, self->innerblb,
475 0, 0,
476 ob_rr_theme->grip_width + self->bwidth,
477 self->cbwidth_b);
478 XMoveResizeWindow(obt_display, self->innerbrb,
479 self->client->area.width +
480 self->cbwidth_l + self->cbwidth_r -
481 (ob_rr_theme->grip_width + self->bwidth),
483 ob_rr_theme->grip_width + self->bwidth,
484 self->cbwidth_b);
486 XMapWindow(obt_display, self->innerbottom);
487 XMapWindow(obt_display, self->innerblb);
488 XMapWindow(obt_display, self->innerbrb);
489 } else {
490 XUnmapWindow(obt_display, self->innerbottom);
491 XUnmapWindow(obt_display, self->innerblb);
492 XUnmapWindow(obt_display, self->innerbrb);
495 if (self->bwidth) {
496 gint titlesides;
498 /* height of titleleft and titleright */
499 titlesides = (!self->max_horz ? ob_rr_theme->grip_width : 0);
501 XMoveResizeWindow(obt_display, self->titletop,
502 ob_rr_theme->grip_width + self->bwidth, 0,
503 /* width + bwidth*2 - bwidth*2 - grips*2 */
504 self->width - ob_rr_theme->grip_width * 2,
505 self->bwidth);
506 XMoveResizeWindow(obt_display, self->titletopleft,
507 0, 0,
508 ob_rr_theme->grip_width + self->bwidth,
509 self->bwidth);
510 XMoveResizeWindow(obt_display, self->titletopright,
511 self->client->area.width +
512 self->size.left + self->size.right -
513 ob_rr_theme->grip_width - self->bwidth,
515 ob_rr_theme->grip_width + self->bwidth,
516 self->bwidth);
518 if (titlesides > 0) {
519 XMoveResizeWindow(obt_display, self->titleleft,
520 0, self->bwidth,
521 self->bwidth,
522 titlesides);
523 XMoveResizeWindow(obt_display, self->titleright,
524 self->client->area.width +
525 self->size.left + self->size.right -
526 self->bwidth,
527 self->bwidth,
528 self->bwidth,
529 titlesides);
531 XMapWindow(obt_display, self->titleleft);
532 XMapWindow(obt_display, self->titleright);
533 } else {
534 XUnmapWindow(obt_display, self->titleleft);
535 XUnmapWindow(obt_display, self->titleright);
538 XMapWindow(obt_display, self->titletop);
539 XMapWindow(obt_display, self->titletopleft);
540 XMapWindow(obt_display, self->titletopright);
542 if (self->decorations & OB_FRAME_DECOR_TITLEBAR) {
543 XMoveResizeWindow(obt_display, self->titlebottom,
544 (self->max_horz ? 0 : self->bwidth),
545 ob_rr_theme->title_height + self->bwidth,
546 self->width,
547 self->bwidth);
549 XMapWindow(obt_display, self->titlebottom);
550 } else
551 XUnmapWindow(obt_display, self->titlebottom);
552 } else {
553 XUnmapWindow(obt_display, self->titlebottom);
555 XUnmapWindow(obt_display, self->titletop);
556 XUnmapWindow(obt_display, self->titletopleft);
557 XUnmapWindow(obt_display, self->titletopright);
558 XUnmapWindow(obt_display, self->titleleft);
559 XUnmapWindow(obt_display, self->titleright);
562 if (self->decorations & OB_FRAME_DECOR_TITLEBAR) {
563 XMoveResizeWindow(obt_display, self->title,
564 (self->max_horz ? 0 : self->bwidth),
565 self->bwidth,
566 self->width, ob_rr_theme->title_height);
568 XMapWindow(obt_display, self->title);
570 if (self->decorations & OB_FRAME_DECOR_GRIPS) {
571 XMoveResizeWindow(obt_display, self->topresize,
572 ob_rr_theme->grip_width,
574 self->width - ob_rr_theme->grip_width *2,
575 ob_rr_theme->paddingy + 1);
577 XMoveWindow(obt_display, self->tltresize, 0, 0);
578 XMoveWindow(obt_display, self->tllresize, 0, 0);
579 XMoveWindow(obt_display, self->trtresize,
580 self->width - ob_rr_theme->grip_width, 0);
581 XMoveWindow(obt_display, self->trrresize,
582 self->width - ob_rr_theme->paddingx - 1, 0);
584 XMapWindow(obt_display, self->topresize);
585 XMapWindow(obt_display, self->tltresize);
586 XMapWindow(obt_display, self->tllresize);
587 XMapWindow(obt_display, self->trtresize);
588 XMapWindow(obt_display, self->trrresize);
589 } else {
590 XUnmapWindow(obt_display, self->topresize);
591 XUnmapWindow(obt_display, self->tltresize);
592 XUnmapWindow(obt_display, self->tllresize);
593 XUnmapWindow(obt_display, self->trtresize);
594 XUnmapWindow(obt_display, self->trrresize);
596 } else
597 XUnmapWindow(obt_display, self->title);
600 if ((self->decorations & OB_FRAME_DECOR_TITLEBAR))
601 /* layout the title bar elements */
602 layout_title(self);
604 if (!fake) {
605 gint sidebwidth = self->max_horz ? 0 : self->bwidth;
607 if (self->bwidth && self->size.bottom) {
608 XMoveResizeWindow(obt_display, self->handlebottom,
609 ob_rr_theme->grip_width +
610 self->bwidth + sidebwidth,
611 self->size.top + self->client->area.height +
612 self->size.bottom - self->bwidth,
613 self->width - (ob_rr_theme->grip_width +
614 sidebwidth) * 2,
615 self->bwidth);
618 if (sidebwidth) {
619 XMoveResizeWindow(obt_display, self->lgripleft,
621 self->size.top +
622 self->client->area.height +
623 self->size.bottom -
624 (!self->max_horz ?
625 ob_rr_theme->grip_width :
626 self->size.bottom - self->cbwidth_b),
627 self->bwidth,
628 (!self->max_horz ?
629 ob_rr_theme->grip_width :
630 self->size.bottom - self->cbwidth_b));
631 XMoveResizeWindow(obt_display, self->rgripright,
632 self->size.left +
633 self->client->area.width +
634 self->size.right - self->bwidth,
635 self->size.top +
636 self->client->area.height +
637 self->size.bottom -
638 (!self->max_horz ?
639 ob_rr_theme->grip_width :
640 self->size.bottom - self->cbwidth_b),
641 self->bwidth,
642 (!self->max_horz ?
643 ob_rr_theme->grip_width :
644 self->size.bottom - self->cbwidth_b));
646 XMapWindow(obt_display, self->lgripleft);
647 XMapWindow(obt_display, self->rgripright);
648 } else {
649 XUnmapWindow(obt_display, self->lgripleft);
650 XUnmapWindow(obt_display, self->rgripright);
653 XMoveResizeWindow(obt_display, self->lgripbottom,
654 sidebwidth,
655 self->size.top + self->client->area.height +
656 self->size.bottom - self->bwidth,
657 ob_rr_theme->grip_width + self->bwidth,
658 self->bwidth);
659 XMoveResizeWindow(obt_display, self->rgripbottom,
660 self->size.left + self->client->area.width +
661 self->size.right - self->bwidth - sidebwidth-
662 ob_rr_theme->grip_width,
663 self->size.top + self->client->area.height +
664 self->size.bottom - self->bwidth,
665 ob_rr_theme->grip_width + self->bwidth,
666 self->bwidth);
668 XMapWindow(obt_display, self->handlebottom);
669 XMapWindow(obt_display, self->lgripbottom);
670 XMapWindow(obt_display, self->rgripbottom);
672 if (self->decorations & OB_FRAME_DECOR_HANDLE &&
673 ob_rr_theme->handle_height > 0)
675 XMoveResizeWindow(obt_display, self->handletop,
676 ob_rr_theme->grip_width +
677 self->bwidth + sidebwidth,
678 FRAME_HANDLE_Y(self),
679 self->width - (ob_rr_theme->grip_width +
680 sidebwidth) * 2,
681 self->bwidth);
682 XMapWindow(obt_display, self->handletop);
684 if (self->decorations & OB_FRAME_DECOR_GRIPS) {
685 XMoveResizeWindow(obt_display, self->handleleft,
686 ob_rr_theme->grip_width,
688 self->bwidth,
689 ob_rr_theme->handle_height);
690 XMoveResizeWindow(obt_display, self->handleright,
691 self->width -
692 ob_rr_theme->grip_width -
693 self->bwidth,
695 self->bwidth,
696 ob_rr_theme->handle_height);
698 XMoveResizeWindow(obt_display, self->lgriptop,
699 sidebwidth,
700 FRAME_HANDLE_Y(self),
701 ob_rr_theme->grip_width +
702 self->bwidth,
703 self->bwidth);
704 XMoveResizeWindow(obt_display, self->rgriptop,
705 self->size.left +
706 self->client->area.width +
707 self->size.right - self->bwidth -
708 sidebwidth - ob_rr_theme->grip_width,
709 FRAME_HANDLE_Y(self),
710 ob_rr_theme->grip_width +
711 self->bwidth,
712 self->bwidth);
714 XMapWindow(obt_display, self->handleleft);
715 XMapWindow(obt_display, self->handleright);
716 XMapWindow(obt_display, self->lgriptop);
717 XMapWindow(obt_display, self->rgriptop);
718 } else {
719 XUnmapWindow(obt_display, self->handleleft);
720 XUnmapWindow(obt_display, self->handleright);
721 XUnmapWindow(obt_display, self->lgriptop);
722 XUnmapWindow(obt_display, self->rgriptop);
724 } else {
725 XUnmapWindow(obt_display, self->handleleft);
726 XUnmapWindow(obt_display, self->handleright);
727 XUnmapWindow(obt_display, self->lgriptop);
728 XUnmapWindow(obt_display, self->rgriptop);
730 XUnmapWindow(obt_display, self->handletop);
732 } else {
733 XUnmapWindow(obt_display, self->handleleft);
734 XUnmapWindow(obt_display, self->handleright);
735 XUnmapWindow(obt_display, self->lgriptop);
736 XUnmapWindow(obt_display, self->rgriptop);
738 XUnmapWindow(obt_display, self->handletop);
740 XUnmapWindow(obt_display, self->handlebottom);
741 XUnmapWindow(obt_display, self->lgripleft);
742 XUnmapWindow(obt_display, self->rgripright);
743 XUnmapWindow(obt_display, self->lgripbottom);
744 XUnmapWindow(obt_display, self->rgripbottom);
747 if (self->decorations & OB_FRAME_DECOR_HANDLE &&
748 ob_rr_theme->handle_height > 0)
750 XMoveResizeWindow(obt_display, self->handle,
751 sidebwidth,
752 FRAME_HANDLE_Y(self) + self->bwidth,
753 self->width, ob_rr_theme->handle_height);
754 XMapWindow(obt_display, self->handle);
756 if (self->decorations & OB_FRAME_DECOR_GRIPS) {
757 XMoveResizeWindow(obt_display, self->lgrip,
758 0, 0,
759 ob_rr_theme->grip_width,
760 ob_rr_theme->handle_height);
761 XMoveResizeWindow(obt_display, self->rgrip,
762 self->width - ob_rr_theme->grip_width,
764 ob_rr_theme->grip_width,
765 ob_rr_theme->handle_height);
767 XMapWindow(obt_display, self->lgrip);
768 XMapWindow(obt_display, self->rgrip);
769 } else {
770 XUnmapWindow(obt_display, self->lgrip);
771 XUnmapWindow(obt_display, self->rgrip);
773 } else {
774 XUnmapWindow(obt_display, self->lgrip);
775 XUnmapWindow(obt_display, self->rgrip);
777 XUnmapWindow(obt_display, self->handle);
780 if (self->bwidth && !self->max_horz &&
781 (self->client->area.height + self->size.top +
782 self->size.bottom) > ob_rr_theme->grip_width * 2)
784 XMoveResizeWindow(obt_display, self->left,
786 self->bwidth + ob_rr_theme->grip_width,
787 self->bwidth,
788 self->client->area.height +
789 self->size.top + self->size.bottom -
790 ob_rr_theme->grip_width * 2);
792 XMapWindow(obt_display, self->left);
793 } else
794 XUnmapWindow(obt_display, self->left);
796 if (self->bwidth && !self->max_horz &&
797 (self->client->area.height + self->size.top +
798 self->size.bottom) > ob_rr_theme->grip_width * 2)
800 XMoveResizeWindow(obt_display, self->right,
801 self->client->area.width + self->cbwidth_l +
802 self->cbwidth_r + self->bwidth,
803 self->bwidth + ob_rr_theme->grip_width,
804 self->bwidth,
805 self->client->area.height +
806 self->size.top + self->size.bottom -
807 ob_rr_theme->grip_width * 2);
809 XMapWindow(obt_display, self->right);
810 } else
811 XUnmapWindow(obt_display, self->right);
813 XMoveResizeWindow(obt_display, self->backback,
814 self->size.left, self->size.top,
815 self->client->area.width,
816 self->client->area.height);
820 /* shading can change without being moved or resized */
821 RECT_SET_SIZE(self->area,
822 self->client->area.width +
823 self->size.left + self->size.right,
824 (self->client->shaded ?
825 ob_rr_theme->title_height + self->bwidth * 2:
826 self->client->area.height +
827 self->size.top + self->size.bottom));
829 if ((moved || resized) && !fake) {
830 /* find the new coordinates, done after setting the frame.size, for
831 frame_client_gravity. */
832 self->area.x = self->client->area.x;
833 self->area.y = self->client->area.y;
834 frame_client_gravity(self, &self->area.x, &self->area.y);
837 if (!fake) {
838 if (!frame_iconify_animating(self))
839 /* move and resize the top level frame.
840 shading can change without being moved or resized.
842 but don't do this during an iconify animation. it will be
843 reflected afterwards.
845 XMoveResizeWindow(obt_display, self->window,
846 self->area.x,
847 self->area.y,
848 self->area.width,
849 self->area.height);
851 /* when the client has StaticGravity, it likes to move around.
852 also this correctly positions the client when it maps.
853 this also needs to be run when the frame's decorations sizes change!
855 XMoveWindow(obt_display, self->client->window,
856 self->size.left, self->size.top);
858 if (resized) {
859 self->need_render = TRUE;
860 framerender_frame(self);
861 frame_adjust_shape(self);
864 if (!STRUT_EQUAL(self->size, self->oldsize)) {
865 gulong vals[4];
866 vals[0] = self->size.left;
867 vals[1] = self->size.right;
868 vals[2] = self->size.top;
869 vals[3] = self->size.bottom;
870 OBT_PROP_SETA32(self->client->window, NET_FRAME_EXTENTS,
871 CARDINAL, vals, 4);
872 OBT_PROP_SETA32(self->client->window, KDE_NET_WM_FRAME_STRUT,
873 CARDINAL, vals, 4);
874 self->oldsize = self->size;
877 /* if this occurs while we are focus cycling, the indicator needs to
878 match the changes */
879 if (focus_cycle_target == self->client)
880 focus_cycle_update_indicator(self->client);
882 if (resized && (self->decorations & OB_FRAME_DECOR_TITLEBAR) &&
883 self->label_width)
885 XResizeWindow(obt_display, self->label, self->label_width,
886 ob_rr_theme->label_height);
890 static void frame_adjust_cursors(ObFrame *self)
892 if ((self->functions & OB_CLIENT_FUNC_RESIZE) !=
893 (self->client->functions & OB_CLIENT_FUNC_RESIZE) ||
894 self->max_horz != self->client->max_horz ||
895 self->max_vert != self->client->max_vert ||
896 self->shaded != self->client->shaded)
898 gboolean r = (self->client->functions & OB_CLIENT_FUNC_RESIZE) &&
899 !(self->client->max_horz && self->client->max_vert);
900 gboolean topbot = !self->client->max_vert;
901 gboolean sh = self->client->shaded;
902 XSetWindowAttributes a;
904 /* these ones turn off when max vert, and some when shaded */
905 a.cursor = ob_cursor(r && topbot && !sh ?
906 OB_CURSOR_NORTH : OB_CURSOR_NONE);
907 XChangeWindowAttributes(obt_display, self->topresize, CWCursor, &a);
908 XChangeWindowAttributes(obt_display, self->titletop, CWCursor, &a);
909 a.cursor = ob_cursor(r && topbot ? OB_CURSOR_SOUTH : OB_CURSOR_NONE);
910 XChangeWindowAttributes(obt_display, self->handle, CWCursor, &a);
911 XChangeWindowAttributes(obt_display, self->handletop, CWCursor, &a);
912 XChangeWindowAttributes(obt_display, self->handlebottom, CWCursor, &a);
913 XChangeWindowAttributes(obt_display, self->innerbottom, CWCursor, &a);
915 /* these ones change when shaded */
916 a.cursor = ob_cursor(r ? (sh ? OB_CURSOR_WEST : OB_CURSOR_NORTHWEST) :
917 OB_CURSOR_NONE);
918 XChangeWindowAttributes(obt_display, self->titleleft, CWCursor, &a);
919 XChangeWindowAttributes(obt_display, self->tltresize, CWCursor, &a);
920 XChangeWindowAttributes(obt_display, self->tllresize, CWCursor, &a);
921 XChangeWindowAttributes(obt_display, self->titletopleft, CWCursor, &a);
922 a.cursor = ob_cursor(r ? (sh ? OB_CURSOR_EAST : OB_CURSOR_NORTHEAST) :
923 OB_CURSOR_NONE);
924 XChangeWindowAttributes(obt_display, self->titleright, CWCursor, &a);
925 XChangeWindowAttributes(obt_display, self->trtresize, CWCursor, &a);
926 XChangeWindowAttributes(obt_display, self->trrresize, CWCursor, &a);
927 XChangeWindowAttributes(obt_display, self->titletopright, CWCursor,&a);
929 /* these ones are pretty static */
930 a.cursor = ob_cursor(r ? OB_CURSOR_WEST : OB_CURSOR_NONE);
931 XChangeWindowAttributes(obt_display, self->left, CWCursor, &a);
932 XChangeWindowAttributes(obt_display, self->innerleft, CWCursor, &a);
933 a.cursor = ob_cursor(r ? OB_CURSOR_EAST : OB_CURSOR_NONE);
934 XChangeWindowAttributes(obt_display, self->right, CWCursor, &a);
935 XChangeWindowAttributes(obt_display, self->innerright, CWCursor, &a);
936 a.cursor = ob_cursor(r ? OB_CURSOR_SOUTHWEST : OB_CURSOR_NONE);
937 XChangeWindowAttributes(obt_display, self->lgrip, CWCursor, &a);
938 XChangeWindowAttributes(obt_display, self->handleleft, CWCursor, &a);
939 XChangeWindowAttributes(obt_display, self->lgripleft, CWCursor, &a);
940 XChangeWindowAttributes(obt_display, self->lgriptop, CWCursor, &a);
941 XChangeWindowAttributes(obt_display, self->lgripbottom, CWCursor, &a);
942 XChangeWindowAttributes(obt_display, self->innerbll, CWCursor, &a);
943 XChangeWindowAttributes(obt_display, self->innerblb, CWCursor, &a);
944 a.cursor = ob_cursor(r ? OB_CURSOR_SOUTHEAST : OB_CURSOR_NONE);
945 XChangeWindowAttributes(obt_display, self->rgrip, CWCursor, &a);
946 XChangeWindowAttributes(obt_display, self->handleright, CWCursor, &a);
947 XChangeWindowAttributes(obt_display, self->rgripright, CWCursor, &a);
948 XChangeWindowAttributes(obt_display, self->rgriptop, CWCursor, &a);
949 XChangeWindowAttributes(obt_display, self->rgripbottom, CWCursor, &a);
950 XChangeWindowAttributes(obt_display, self->innerbrr, CWCursor, &a);
951 XChangeWindowAttributes(obt_display, self->innerbrb, CWCursor, &a);
955 void frame_adjust_client_area(ObFrame *self)
957 /* adjust the window which is there to prevent flashing on unmap */
958 XMoveResizeWindow(obt_display, self->backfront, 0, 0,
959 self->client->area.width,
960 self->client->area.height);
963 void frame_adjust_state(ObFrame *self)
965 self->need_render = TRUE;
966 framerender_frame(self);
969 void frame_adjust_focus(ObFrame *self, gboolean hilite)
971 ob_debug_type(OB_DEBUG_FOCUS,
972 "Frame for 0x%x has focus: %d",
973 self->client->window, hilite);
974 self->focused = hilite;
975 self->need_render = TRUE;
976 framerender_frame(self);
977 XFlush(obt_display);
980 void frame_adjust_title(ObFrame *self)
982 self->need_render = TRUE;
983 framerender_frame(self);
986 void frame_adjust_icon(ObFrame *self)
988 self->need_render = TRUE;
989 framerender_frame(self);
992 void frame_grab_client(ObFrame *self)
994 /* DO NOT map the client window here. we used to do that, but it is bogus.
995 we need to set up the client's dimensions and everything before we
996 send a mapnotify or we create race conditions.
999 /* reparent the client to the frame */
1000 XReparentWindow(obt_display, self->client->window, self->window, 0, 0);
1003 When reparenting the client window, it is usually not mapped yet, since
1004 this occurs from a MapRequest. However, in the case where Openbox is
1005 starting up, the window is already mapped, so we'll see an unmap event
1006 for it.
1008 if (ob_state() == OB_STATE_STARTING)
1009 ++self->client->ignore_unmaps;
1011 /* select the event mask on the client's parent (to receive config/map
1012 req's) the ButtonPress is to catch clicks on the client border */
1013 XSelectInput(obt_display, self->window, FRAME_EVENTMASK);
1015 /* set all the windows for the frame in the window_map */
1016 window_add(&self->window, CLIENT_AS_WINDOW(self->client));
1017 window_add(&self->backback, CLIENT_AS_WINDOW(self->client));
1018 window_add(&self->backfront, CLIENT_AS_WINDOW(self->client));
1019 window_add(&self->innerleft, CLIENT_AS_WINDOW(self->client));
1020 window_add(&self->innertop, CLIENT_AS_WINDOW(self->client));
1021 window_add(&self->innerright, CLIENT_AS_WINDOW(self->client));
1022 window_add(&self->innerbottom, CLIENT_AS_WINDOW(self->client));
1023 window_add(&self->innerblb, CLIENT_AS_WINDOW(self->client));
1024 window_add(&self->innerbll, CLIENT_AS_WINDOW(self->client));
1025 window_add(&self->innerbrb, CLIENT_AS_WINDOW(self->client));
1026 window_add(&self->innerbrr, CLIENT_AS_WINDOW(self->client));
1027 window_add(&self->title, CLIENT_AS_WINDOW(self->client));
1028 window_add(&self->label, CLIENT_AS_WINDOW(self->client));
1029 window_add(&self->max, CLIENT_AS_WINDOW(self->client));
1030 window_add(&self->close, CLIENT_AS_WINDOW(self->client));
1031 window_add(&self->desk, CLIENT_AS_WINDOW(self->client));
1032 window_add(&self->shade, CLIENT_AS_WINDOW(self->client));
1033 window_add(&self->icon, CLIENT_AS_WINDOW(self->client));
1034 window_add(&self->iconify, CLIENT_AS_WINDOW(self->client));
1035 window_add(&self->handle, CLIENT_AS_WINDOW(self->client));
1036 window_add(&self->lgrip, CLIENT_AS_WINDOW(self->client));
1037 window_add(&self->rgrip, CLIENT_AS_WINDOW(self->client));
1038 window_add(&self->topresize, CLIENT_AS_WINDOW(self->client));
1039 window_add(&self->tltresize, CLIENT_AS_WINDOW(self->client));
1040 window_add(&self->tllresize, CLIENT_AS_WINDOW(self->client));
1041 window_add(&self->trtresize, CLIENT_AS_WINDOW(self->client));
1042 window_add(&self->trrresize, CLIENT_AS_WINDOW(self->client));
1043 window_add(&self->left, CLIENT_AS_WINDOW(self->client));
1044 window_add(&self->right, CLIENT_AS_WINDOW(self->client));
1045 window_add(&self->titleleft, CLIENT_AS_WINDOW(self->client));
1046 window_add(&self->titletop, CLIENT_AS_WINDOW(self->client));
1047 window_add(&self->titletopleft, CLIENT_AS_WINDOW(self->client));
1048 window_add(&self->titletopright, CLIENT_AS_WINDOW(self->client));
1049 window_add(&self->titleright, CLIENT_AS_WINDOW(self->client));
1050 window_add(&self->titlebottom, CLIENT_AS_WINDOW(self->client));
1051 window_add(&self->handleleft, CLIENT_AS_WINDOW(self->client));
1052 window_add(&self->handletop, CLIENT_AS_WINDOW(self->client));
1053 window_add(&self->handleright, CLIENT_AS_WINDOW(self->client));
1054 window_add(&self->handlebottom, CLIENT_AS_WINDOW(self->client));
1055 window_add(&self->lgripleft, CLIENT_AS_WINDOW(self->client));
1056 window_add(&self->lgriptop, CLIENT_AS_WINDOW(self->client));
1057 window_add(&self->lgripbottom, CLIENT_AS_WINDOW(self->client));
1058 window_add(&self->rgripright, CLIENT_AS_WINDOW(self->client));
1059 window_add(&self->rgriptop, CLIENT_AS_WINDOW(self->client));
1060 window_add(&self->rgripbottom, CLIENT_AS_WINDOW(self->client));
1063 static gboolean find_reparent(XEvent *e, gpointer data)
1065 const ObFrame *self = data;
1067 /* Find ReparentNotify events for the window that aren't being reparented into the
1068 frame, thus the client reparenting itself off the frame. */
1069 return e->type == ReparentNotify && e->xreparent.window == self->client->window &&
1070 e->xreparent.parent != self->window;
1073 void frame_release_client(ObFrame *self)
1075 /* if there was any animation going on, kill it */
1076 if (self->iconify_animation_timer)
1077 g_source_remove(self->iconify_animation_timer);
1079 /* check if the app has already reparented its window away */
1080 if (!xqueue_exists_local(find_reparent, self)) {
1081 /* according to the ICCCM - if the client doesn't reparent itself,
1082 then we will reparent the window to root for them */
1083 XReparentWindow(obt_display, self->client->window, obt_root(ob_screen),
1084 self->client->area.x, self->client->area.y);
1087 /* remove all the windows for the frame from the window_map */
1088 window_remove(self->window);
1089 window_remove(self->backback);
1090 window_remove(self->backfront);
1091 window_remove(self->innerleft);
1092 window_remove(self->innertop);
1093 window_remove(self->innerright);
1094 window_remove(self->innerbottom);
1095 window_remove(self->innerblb);
1096 window_remove(self->innerbll);
1097 window_remove(self->innerbrb);
1098 window_remove(self->innerbrr);
1099 window_remove(self->title);
1100 window_remove(self->label);
1101 window_remove(self->max);
1102 window_remove(self->close);
1103 window_remove(self->desk);
1104 window_remove(self->shade);
1105 window_remove(self->icon);
1106 window_remove(self->iconify);
1107 window_remove(self->handle);
1108 window_remove(self->lgrip);
1109 window_remove(self->rgrip);
1110 window_remove(self->topresize);
1111 window_remove(self->tltresize);
1112 window_remove(self->tllresize);
1113 window_remove(self->trtresize);
1114 window_remove(self->trrresize);
1115 window_remove(self->left);
1116 window_remove(self->right);
1117 window_remove(self->titleleft);
1118 window_remove(self->titletop);
1119 window_remove(self->titletopleft);
1120 window_remove(self->titletopright);
1121 window_remove(self->titleright);
1122 window_remove(self->titlebottom);
1123 window_remove(self->handleleft);
1124 window_remove(self->handletop);
1125 window_remove(self->handleright);
1126 window_remove(self->handlebottom);
1127 window_remove(self->lgripleft);
1128 window_remove(self->lgriptop);
1129 window_remove(self->lgripbottom);
1130 window_remove(self->rgripright);
1131 window_remove(self->rgriptop);
1132 window_remove(self->rgripbottom);
1134 if (self->flash_timer) g_source_remove(self->flash_timer);
1137 /* is there anything present between us and the label? */
1138 static gboolean is_button_present(ObFrame *self, const gchar *lc, gint dir) {
1139 for (; *lc != '\0' && lc >= config_title_layout; lc += dir) {
1140 if (*lc == ' ') continue; /* it was invalid */
1141 if (*lc == 'N' && self->decorations & OB_FRAME_DECOR_ICON)
1142 return TRUE;
1143 if (*lc == 'D' && self->decorations & OB_FRAME_DECOR_ALLDESKTOPS)
1144 return TRUE;
1145 if (*lc == 'S' && self->decorations & OB_FRAME_DECOR_SHADE)
1146 return TRUE;
1147 if (*lc == 'I' && self->decorations & OB_FRAME_DECOR_ICONIFY)
1148 return TRUE;
1149 if (*lc == 'M' && self->decorations & OB_FRAME_DECOR_MAXIMIZE)
1150 return TRUE;
1151 if (*lc == 'C' && self->decorations & OB_FRAME_DECOR_CLOSE)
1152 return TRUE;
1153 if (*lc == 'L') return FALSE;
1155 return FALSE;
1158 static void place_button(ObFrame *self, const char *lc, gint bwidth,
1159 gint left, gint i,
1160 gint *x, gint *button_on, gint *button_x)
1162 if (!(*button_on = is_button_present(self, lc, i)))
1163 return;
1165 self->label_width -= bwidth;
1166 if (i > 0)
1167 *button_x = *x;
1168 *x += i * bwidth;
1169 if (i < 0) {
1170 if (self->label_x <= left || *x > self->label_x) {
1171 *button_x = *x;
1172 } else {
1173 /* the button would have been drawn on top of another button */
1174 *button_on = FALSE;
1175 self->label_width += bwidth;
1180 static void layout_title(ObFrame *self)
1182 gchar *lc;
1183 gint i;
1185 const gint bwidth = ob_rr_theme->button_size + ob_rr_theme->paddingx + 1;
1186 /* position of the leftmost button */
1187 const gint left = ob_rr_theme->paddingx + 1;
1188 /* position of the rightmost button */
1189 const gint right = self->width;
1191 /* turn them all off */
1192 self->icon_on = self->desk_on = self->shade_on = self->iconify_on =
1193 self->max_on = self->close_on = self->label_on = FALSE;
1194 self->label_width = self->width - (ob_rr_theme->paddingx + 1) * 2;
1195 self->leftmost = self->rightmost = OB_FRAME_CONTEXT_NONE;
1197 /* figure out what's being shown, find each element's position, and the
1198 width of the label
1200 do the ones before the label, then after the label,
1201 i will be +1 the first time through when working to the left,
1202 and -1 the second time through when working to the right */
1203 for (i = 1; i >= -1; i-=2) {
1204 gint x;
1205 ObFrameContext *firstcon;
1207 if (i > 0) {
1208 x = left;
1209 lc = config_title_layout;
1210 firstcon = &self->leftmost;
1211 } else {
1212 x = right;
1213 lc = config_title_layout + strlen(config_title_layout)-1;
1214 firstcon = &self->rightmost;
1217 /* stop at the end of the string (or the label, which calls break) */
1218 for (; *lc != '\0' && lc >= config_title_layout; lc+=i) {
1219 if (*lc == 'L') {
1220 if (i > 0) {
1221 self->label_on = TRUE;
1222 self->label_x = x;
1224 break; /* break the for loop, do other side of label */
1225 } else if (*lc == 'N') {
1226 if (firstcon) *firstcon = OB_FRAME_CONTEXT_ICON;
1227 /* icon is bigger than buttons */
1228 place_button(self, lc, bwidth + 2, left, i, &x, &self->icon_on, &self->icon_x);
1229 } else if (*lc == 'D') {
1230 if (firstcon) *firstcon = OB_FRAME_CONTEXT_ALLDESKTOPS;
1231 place_button(self, lc, bwidth, left, i, &x, &self->desk_on, &self->desk_x);
1232 } else if (*lc == 'S') {
1233 if (firstcon) *firstcon = OB_FRAME_CONTEXT_SHADE;
1234 place_button(self, lc, bwidth, left, i, &x, &self->shade_on, &self->shade_x);
1235 } else if (*lc == 'I') {
1236 if (firstcon) *firstcon = OB_FRAME_CONTEXT_ICONIFY;
1237 place_button(self, lc, bwidth, left, i, &x, &self->iconify_on, &self->iconify_x);
1238 } else if (*lc == 'M') {
1239 if (firstcon) *firstcon = OB_FRAME_CONTEXT_MAXIMIZE;
1240 place_button(self, lc, bwidth, left, i, &x, &self->max_on, &self->max_x);
1241 } else if (*lc == 'C') {
1242 if (firstcon) *firstcon = OB_FRAME_CONTEXT_CLOSE;
1243 place_button(self, lc, bwidth, left, i, &x, &self->close_on, &self->close_x);
1244 } else
1245 continue; /* don't set firstcon */
1246 firstcon = NULL;
1250 /* position and map the elements */
1251 if (self->icon_on) {
1252 XMapWindow(obt_display, self->icon);
1253 XMoveWindow(obt_display, self->icon, self->icon_x,
1254 ob_rr_theme->paddingy);
1255 } else
1256 XUnmapWindow(obt_display, self->icon);
1258 if (self->desk_on) {
1259 XMapWindow(obt_display, self->desk);
1260 XMoveWindow(obt_display, self->desk, self->desk_x,
1261 ob_rr_theme->paddingy + 1);
1262 } else
1263 XUnmapWindow(obt_display, self->desk);
1265 if (self->shade_on) {
1266 XMapWindow(obt_display, self->shade);
1267 XMoveWindow(obt_display, self->shade, self->shade_x,
1268 ob_rr_theme->paddingy + 1);
1269 } else
1270 XUnmapWindow(obt_display, self->shade);
1272 if (self->iconify_on) {
1273 XMapWindow(obt_display, self->iconify);
1274 XMoveWindow(obt_display, self->iconify, self->iconify_x,
1275 ob_rr_theme->paddingy + 1);
1276 } else
1277 XUnmapWindow(obt_display, self->iconify);
1279 if (self->max_on) {
1280 XMapWindow(obt_display, self->max);
1281 XMoveWindow(obt_display, self->max, self->max_x,
1282 ob_rr_theme->paddingy + 1);
1283 } else
1284 XUnmapWindow(obt_display, self->max);
1286 if (self->close_on) {
1287 XMapWindow(obt_display, self->close);
1288 XMoveWindow(obt_display, self->close, self->close_x,
1289 ob_rr_theme->paddingy + 1);
1290 } else
1291 XUnmapWindow(obt_display, self->close);
1293 if (self->label_on && self->label_width > 0) {
1294 XMapWindow(obt_display, self->label);
1295 XMoveWindow(obt_display, self->label, self->label_x,
1296 ob_rr_theme->paddingy);
1297 } else
1298 XUnmapWindow(obt_display, self->label);
1301 gboolean frame_next_context_from_string(gchar *names, ObFrameContext *cx)
1303 gchar *p, *n;
1305 if (!*names) /* empty string */
1306 return FALSE;
1308 /* find the first space */
1309 for (p = names; *p; p = g_utf8_next_char(p)) {
1310 const gunichar c = g_utf8_get_char(p);
1311 if (g_unichar_isspace(c)) break;
1314 if (p == names) {
1315 /* leading spaces in the string */
1316 n = g_utf8_next_char(names);
1317 if (!frame_next_context_from_string(n, cx))
1318 return FALSE;
1319 } else {
1320 n = p;
1321 if (*p) {
1322 /* delete the space with null zero(s) */
1323 while (n < g_utf8_next_char(p))
1324 *(n++) = '\0';
1327 *cx = frame_context_from_string(names);
1329 /* find the next non-space */
1330 for (; *n; n = g_utf8_next_char(n)) {
1331 const gunichar c = g_utf8_get_char(n);
1332 if (!g_unichar_isspace(c)) break;
1336 /* delete everything we just read (copy everything at n to the start of
1337 the string */
1338 for (p = names; *n; ++p, ++n)
1339 *p = *n;
1340 *p = *n;
1342 return TRUE;
1345 ObFrameContext frame_context_from_string(const gchar *name)
1347 if (!g_ascii_strcasecmp("Desktop", name))
1348 return OB_FRAME_CONTEXT_DESKTOP;
1349 else if (!g_ascii_strcasecmp("Root", name))
1350 return OB_FRAME_CONTEXT_ROOT;
1351 else if (!g_ascii_strcasecmp("Client", name))
1352 return OB_FRAME_CONTEXT_CLIENT;
1353 else if (!g_ascii_strcasecmp("Titlebar", name))
1354 return OB_FRAME_CONTEXT_TITLEBAR;
1355 else if (!g_ascii_strcasecmp("Frame", name))
1356 return OB_FRAME_CONTEXT_FRAME;
1357 else if (!g_ascii_strcasecmp("TLCorner", name))
1358 return OB_FRAME_CONTEXT_TLCORNER;
1359 else if (!g_ascii_strcasecmp("TRCorner", name))
1360 return OB_FRAME_CONTEXT_TRCORNER;
1361 else if (!g_ascii_strcasecmp("BLCorner", name))
1362 return OB_FRAME_CONTEXT_BLCORNER;
1363 else if (!g_ascii_strcasecmp("BRCorner", name))
1364 return OB_FRAME_CONTEXT_BRCORNER;
1365 else if (!g_ascii_strcasecmp("Top", name))
1366 return OB_FRAME_CONTEXT_TOP;
1367 else if (!g_ascii_strcasecmp("Bottom", name))
1368 return OB_FRAME_CONTEXT_BOTTOM;
1369 else if (!g_ascii_strcasecmp("Left", name))
1370 return OB_FRAME_CONTEXT_LEFT;
1371 else if (!g_ascii_strcasecmp("Right", name))
1372 return OB_FRAME_CONTEXT_RIGHT;
1373 else if (!g_ascii_strcasecmp("Maximize", name))
1374 return OB_FRAME_CONTEXT_MAXIMIZE;
1375 else if (!g_ascii_strcasecmp("AllDesktops", name))
1376 return OB_FRAME_CONTEXT_ALLDESKTOPS;
1377 else if (!g_ascii_strcasecmp("Shade", name))
1378 return OB_FRAME_CONTEXT_SHADE;
1379 else if (!g_ascii_strcasecmp("Iconify", name))
1380 return OB_FRAME_CONTEXT_ICONIFY;
1381 else if (!g_ascii_strcasecmp("Icon", name))
1382 return OB_FRAME_CONTEXT_ICON;
1383 else if (!g_ascii_strcasecmp("Close", name))
1384 return OB_FRAME_CONTEXT_CLOSE;
1385 else if (!g_ascii_strcasecmp("MoveResize", name))
1386 return OB_FRAME_CONTEXT_MOVE_RESIZE;
1387 else if (!g_ascii_strcasecmp("Dock", name))
1388 return OB_FRAME_CONTEXT_DOCK;
1390 return OB_FRAME_CONTEXT_NONE;
1393 ObFrameContext frame_context(ObClient *client, Window win, gint x, gint y)
1395 ObFrame *self;
1396 ObWindow *obwin;
1398 if (moveresize_in_progress)
1399 return OB_FRAME_CONTEXT_MOVE_RESIZE;
1401 if (win == obt_root(ob_screen))
1402 return OB_FRAME_CONTEXT_ROOT;
1403 if ((obwin = window_find(win))) {
1404 if (WINDOW_IS_DOCK(obwin)) {
1405 return OB_FRAME_CONTEXT_DOCK;
1408 if (client == NULL) return OB_FRAME_CONTEXT_NONE;
1409 if (win == client->window) {
1410 /* conceptually, this is the desktop, as far as users are
1411 concerned */
1412 if (client->type == OB_CLIENT_TYPE_DESKTOP)
1413 return OB_FRAME_CONTEXT_DESKTOP;
1414 return OB_FRAME_CONTEXT_CLIENT;
1417 self = client->frame;
1419 /* when the user clicks in the corners of the titlebar and the client
1420 is fully maximized, then treat it like they clicked in the
1421 button that is there */
1422 if (self->max_horz && self->max_vert &&
1423 (win == self->title || win == self->titletop ||
1424 win == self->titleleft || win == self->titletopleft ||
1425 win == self->titleright || win == self->titletopright))
1427 /* get the mouse coords in reference to the whole frame */
1428 gint fx = x;
1429 gint fy = y;
1431 /* these windows are down a border width from the top of the frame */
1432 if (win == self->title ||
1433 win == self->titleleft || win == self->titleright)
1434 fy += self->bwidth;
1436 /* title is a border width in from the edge */
1437 if (win == self->title)
1438 fx += self->bwidth;
1439 /* titletop is a bit to the right */
1440 else if (win == self->titletop)
1441 fx += ob_rr_theme->grip_width + self->bwidth;
1442 /* titletopright is way to the right edge */
1443 else if (win == self->titletopright)
1444 fx += self->area.width - (ob_rr_theme->grip_width + self->bwidth);
1445 /* titleright is even more way to the right edge */
1446 else if (win == self->titleright)
1447 fx += self->area.width - self->bwidth;
1449 /* figure out if we're over the area that should be considered a
1450 button */
1451 if (fy < self->bwidth + ob_rr_theme->paddingy + 1 +
1452 ob_rr_theme->button_size)
1454 if (fx < (self->bwidth + ob_rr_theme->paddingx + 1 +
1455 ob_rr_theme->button_size))
1457 if (self->leftmost != OB_FRAME_CONTEXT_NONE)
1458 return self->leftmost;
1460 else if (fx >= (self->area.width -
1461 (self->bwidth + ob_rr_theme->paddingx + 1 +
1462 ob_rr_theme->button_size)))
1464 if (self->rightmost != OB_FRAME_CONTEXT_NONE)
1465 return self->rightmost;
1469 /* there is no resizing maximized windows so make them the titlebar
1470 context */
1471 return OB_FRAME_CONTEXT_TITLEBAR;
1473 else if (self->max_vert &&
1474 (win == self->titletop || win == self->topresize))
1475 /* can't resize vertically when max vert */
1476 return OB_FRAME_CONTEXT_TITLEBAR;
1477 else if (self->shaded &&
1478 (win == self->titletop || win == self->topresize))
1479 /* can't resize vertically when shaded */
1480 return OB_FRAME_CONTEXT_TITLEBAR;
1482 if (win == self->window) return OB_FRAME_CONTEXT_FRAME;
1483 if (win == self->label) return OB_FRAME_CONTEXT_TITLEBAR;
1484 if (win == self->handle) return OB_FRAME_CONTEXT_BOTTOM;
1485 if (win == self->handletop) return OB_FRAME_CONTEXT_BOTTOM;
1486 if (win == self->handlebottom) return OB_FRAME_CONTEXT_BOTTOM;
1487 if (win == self->handleleft) return OB_FRAME_CONTEXT_BLCORNER;
1488 if (win == self->lgrip) return OB_FRAME_CONTEXT_BLCORNER;
1489 if (win == self->lgripleft) return OB_FRAME_CONTEXT_BLCORNER;
1490 if (win == self->lgriptop) return OB_FRAME_CONTEXT_BLCORNER;
1491 if (win == self->lgripbottom) return OB_FRAME_CONTEXT_BLCORNER;
1492 if (win == self->handleright) return OB_FRAME_CONTEXT_BRCORNER;
1493 if (win == self->rgrip) return OB_FRAME_CONTEXT_BRCORNER;
1494 if (win == self->rgripright) return OB_FRAME_CONTEXT_BRCORNER;
1495 if (win == self->rgriptop) return OB_FRAME_CONTEXT_BRCORNER;
1496 if (win == self->rgripbottom) return OB_FRAME_CONTEXT_BRCORNER;
1497 if (win == self->title) return OB_FRAME_CONTEXT_TITLEBAR;
1498 if (win == self->titlebottom) return OB_FRAME_CONTEXT_TITLEBAR;
1499 if (win == self->titleleft) return OB_FRAME_CONTEXT_TLCORNER;
1500 if (win == self->titletopleft) return OB_FRAME_CONTEXT_TLCORNER;
1501 if (win == self->titleright) return OB_FRAME_CONTEXT_TRCORNER;
1502 if (win == self->titletopright) return OB_FRAME_CONTEXT_TRCORNER;
1503 if (win == self->titletop) return OB_FRAME_CONTEXT_TOP;
1504 if (win == self->topresize) return OB_FRAME_CONTEXT_TOP;
1505 if (win == self->tltresize) return OB_FRAME_CONTEXT_TLCORNER;
1506 if (win == self->tllresize) return OB_FRAME_CONTEXT_TLCORNER;
1507 if (win == self->trtresize) return OB_FRAME_CONTEXT_TRCORNER;
1508 if (win == self->trrresize) return OB_FRAME_CONTEXT_TRCORNER;
1509 if (win == self->left) return OB_FRAME_CONTEXT_LEFT;
1510 if (win == self->right) return OB_FRAME_CONTEXT_RIGHT;
1511 if (win == self->innertop) return OB_FRAME_CONTEXT_TITLEBAR;
1512 if (win == self->innerleft) return OB_FRAME_CONTEXT_LEFT;
1513 if (win == self->innerbottom) return OB_FRAME_CONTEXT_BOTTOM;
1514 if (win == self->innerright) return OB_FRAME_CONTEXT_RIGHT;
1515 if (win == self->innerbll) return OB_FRAME_CONTEXT_BLCORNER;
1516 if (win == self->innerblb) return OB_FRAME_CONTEXT_BLCORNER;
1517 if (win == self->innerbrr) return OB_FRAME_CONTEXT_BRCORNER;
1518 if (win == self->innerbrb) return OB_FRAME_CONTEXT_BRCORNER;
1519 if (win == self->max) return OB_FRAME_CONTEXT_MAXIMIZE;
1520 if (win == self->iconify) return OB_FRAME_CONTEXT_ICONIFY;
1521 if (win == self->close) return OB_FRAME_CONTEXT_CLOSE;
1522 if (win == self->icon) return OB_FRAME_CONTEXT_ICON;
1523 if (win == self->desk) return OB_FRAME_CONTEXT_ALLDESKTOPS;
1524 if (win == self->shade) return OB_FRAME_CONTEXT_SHADE;
1526 return OB_FRAME_CONTEXT_NONE;
1529 void frame_client_gravity(ObFrame *self, gint *x, gint *y)
1531 /* horizontal */
1532 switch (self->client->gravity) {
1533 default:
1534 case NorthWestGravity:
1535 case SouthWestGravity:
1536 case WestGravity:
1537 break;
1539 case NorthGravity:
1540 case SouthGravity:
1541 case CenterGravity:
1542 /* the middle of the client will be the middle of the frame */
1543 *x -= (self->size.right - self->size.left) / 2;
1544 break;
1546 case NorthEastGravity:
1547 case SouthEastGravity:
1548 case EastGravity:
1549 /* the right side of the client will be the right side of the frame */
1550 *x -= self->size.right + self->size.left -
1551 self->client->border_width * 2;
1552 break;
1554 case ForgetGravity:
1555 case StaticGravity:
1556 /* the client's position won't move */
1557 *x -= self->size.left - self->client->border_width;
1558 break;
1561 /* vertical */
1562 switch (self->client->gravity) {
1563 default:
1564 case NorthWestGravity:
1565 case NorthEastGravity:
1566 case NorthGravity:
1567 break;
1569 case CenterGravity:
1570 case EastGravity:
1571 case WestGravity:
1572 /* the middle of the client will be the middle of the frame */
1573 *y -= (self->size.bottom - self->size.top) / 2;
1574 break;
1576 case SouthWestGravity:
1577 case SouthEastGravity:
1578 case SouthGravity:
1579 /* the bottom of the client will be the bottom of the frame */
1580 *y -= self->size.bottom + self->size.top -
1581 self->client->border_width * 2;
1582 break;
1584 case ForgetGravity:
1585 case StaticGravity:
1586 /* the client's position won't move */
1587 *y -= self->size.top - self->client->border_width;
1588 break;
1592 void frame_frame_gravity(ObFrame *self, gint *x, gint *y)
1594 /* horizontal */
1595 switch (self->client->gravity) {
1596 default:
1597 case NorthWestGravity:
1598 case WestGravity:
1599 case SouthWestGravity:
1600 break;
1601 case NorthGravity:
1602 case CenterGravity:
1603 case SouthGravity:
1604 /* the middle of the client will be the middle of the frame */
1605 *x += (self->size.right - self->size.left) / 2;
1606 break;
1607 case NorthEastGravity:
1608 case EastGravity:
1609 case SouthEastGravity:
1610 /* the right side of the client will be the right side of the frame */
1611 *x += self->size.right + self->size.left -
1612 self->client->border_width * 2;
1613 break;
1614 case StaticGravity:
1615 case ForgetGravity:
1616 /* the client's position won't move */
1617 *x += self->size.left - self->client->border_width;
1618 break;
1621 /* vertical */
1622 switch (self->client->gravity) {
1623 default:
1624 case NorthWestGravity:
1625 case NorthGravity:
1626 case NorthEastGravity:
1627 break;
1628 case WestGravity:
1629 case CenterGravity:
1630 case EastGravity:
1631 /* the middle of the client will be the middle of the frame */
1632 *y += (self->size.bottom - self->size.top) / 2;
1633 break;
1634 case SouthWestGravity:
1635 case SouthGravity:
1636 case SouthEastGravity:
1637 /* the bottom of the client will be the bottom of the frame */
1638 *y += self->size.bottom + self->size.top -
1639 self->client->border_width * 2;
1640 break;
1641 case StaticGravity:
1642 case ForgetGravity:
1643 /* the client's position won't move */
1644 *y += self->size.top - self->client->border_width;
1645 break;
1649 void frame_rect_to_frame(ObFrame *self, Rect *r)
1651 r->width += self->size.left + self->size.right;
1652 r->height += self->size.top + self->size.bottom;
1653 frame_client_gravity(self, &r->x, &r->y);
1656 void frame_rect_to_client(ObFrame *self, Rect *r)
1658 r->width -= self->size.left + self->size.right;
1659 r->height -= self->size.top + self->size.bottom;
1660 frame_frame_gravity(self, &r->x, &r->y);
1663 static void flash_done(gpointer data)
1665 ObFrame *self = data;
1667 if (self->focused != self->flash_on)
1668 frame_adjust_focus(self, self->focused);
1671 static gboolean flash_timeout(gpointer data)
1673 ObFrame *self = data;
1674 GTimeVal now;
1676 g_get_current_time(&now);
1677 if (now.tv_sec > self->flash_end.tv_sec ||
1678 (now.tv_sec == self->flash_end.tv_sec &&
1679 now.tv_usec >= self->flash_end.tv_usec))
1680 self->flashing = FALSE;
1682 if (!self->flashing)
1683 return FALSE; /* we are done */
1685 self->flash_on = !self->flash_on;
1686 if (!self->focused) {
1687 frame_adjust_focus(self, self->flash_on);
1688 self->focused = FALSE;
1691 return TRUE; /* go again */
1694 void frame_flash_start(ObFrame *self)
1696 self->flash_on = self->focused;
1698 if (!self->flashing)
1699 self->flash_timer = g_timeout_add_full(G_PRIORITY_DEFAULT,
1700 600, flash_timeout, self,
1701 flash_done);
1702 g_get_current_time(&self->flash_end);
1703 g_time_val_add(&self->flash_end, G_USEC_PER_SEC * 5);
1705 self->flashing = TRUE;
1708 void frame_flash_stop(ObFrame *self)
1710 self->flashing = FALSE;
1713 static gulong frame_animate_iconify_time_left(ObFrame *self,
1714 const GTimeVal *now)
1716 glong sec, usec;
1717 sec = self->iconify_animation_end.tv_sec - now->tv_sec;
1718 usec = self->iconify_animation_end.tv_usec - now->tv_usec;
1719 if (usec < 0) {
1720 usec += G_USEC_PER_SEC;
1721 sec--;
1723 /* no negative values */
1724 return MAX(sec * G_USEC_PER_SEC + usec, 0);
1727 static gboolean frame_animate_iconify(gpointer p)
1729 ObFrame *self = p;
1730 gint x, y, w, h;
1731 gint iconx, icony, iconw;
1732 GTimeVal now;
1733 gulong time;
1734 gboolean iconifying;
1736 if (self->client->icon_geometry.width == 0) {
1737 /* there is no icon geometry set so just go straight down */
1738 const Rect *a;
1740 a = screen_physical_area_monitor(screen_find_monitor(&self->area));
1741 iconx = self->area.x + self->area.width / 2 + 32;
1742 icony = a->y + a->width;
1743 iconw = 64;
1744 } else {
1745 iconx = self->client->icon_geometry.x;
1746 icony = self->client->icon_geometry.y;
1747 iconw = self->client->icon_geometry.width;
1750 iconifying = self->iconify_animation_going > 0;
1752 /* how far do we have left to go ? */
1753 g_get_current_time(&now);
1754 time = frame_animate_iconify_time_left(self, &now);
1756 if ((time > 0 && iconifying) || (time == 0 && !iconifying)) {
1757 /* start where the frame is supposed to be */
1758 x = self->area.x;
1759 y = self->area.y;
1760 w = self->area.width;
1761 h = self->area.height;
1762 } else {
1763 /* start at the icon */
1764 x = iconx;
1765 y = icony;
1766 w = iconw;
1767 h = self->size.top; /* just the titlebar */
1770 if (time > 0) {
1771 glong dx, dy, dw;
1772 glong elapsed;
1774 dx = self->area.x - iconx;
1775 dy = self->area.y - icony;
1776 dw = self->area.width - self->bwidth * 2 - iconw;
1777 /* if restoring, we move in the opposite direction */
1778 if (!iconifying) { dx = -dx; dy = -dy; dw = -dw; }
1780 elapsed = FRAME_ANIMATE_ICONIFY_TIME - time;
1781 x = x - (dx * elapsed) / FRAME_ANIMATE_ICONIFY_TIME;
1782 y = y - (dy * elapsed) / FRAME_ANIMATE_ICONIFY_TIME;
1783 w = w - (dw * elapsed) / FRAME_ANIMATE_ICONIFY_TIME;
1784 h = self->size.top; /* just the titlebar */
1787 XMoveResizeWindow(obt_display, self->window, x, y, w, h);
1788 XFlush(obt_display);
1790 if (time == 0)
1791 frame_end_iconify_animation(self);
1793 return time > 0; /* repeat until we're out of time */
1796 void frame_end_iconify_animation(ObFrame *self)
1798 /* see if there is an animation going */
1799 if (self->iconify_animation_going == 0) return;
1801 if (!self->visible)
1802 XUnmapWindow(obt_display, self->window);
1803 else {
1804 /* Send a ConfigureNotify when the animation is done, this fixes
1805 KDE's pager showing the window in the wrong place. since the
1806 window is mapped at a different location and is then moved, we
1807 need to send the synthetic configurenotify, since apps may have
1808 read the position when the client mapped, apparently. */
1809 client_reconfigure(self->client, TRUE);
1812 /* we're not animating any more ! */
1813 self->iconify_animation_going = 0;
1815 XMoveResizeWindow(obt_display, self->window,
1816 self->area.x, self->area.y,
1817 self->area.width, self->area.height);
1818 /* we delay re-rendering until after we're done animating */
1819 framerender_frame(self);
1820 XFlush(obt_display);
1823 void frame_begin_iconify_animation(ObFrame *self, gboolean iconifying)
1825 gulong time;
1826 gboolean new_anim = FALSE;
1827 gboolean set_end = TRUE;
1828 GTimeVal now;
1830 /* if there is no titlebar, just don't animate for now
1831 XXX it would be nice tho.. */
1832 if (!(self->decorations & OB_FRAME_DECOR_TITLEBAR))
1833 return;
1835 /* get the current time */
1836 g_get_current_time(&now);
1838 /* get how long until the end */
1839 time = FRAME_ANIMATE_ICONIFY_TIME;
1840 if (self->iconify_animation_going) {
1841 if (!!iconifying != (self->iconify_animation_going > 0)) {
1842 /* animation was already going on in the opposite direction */
1843 time = time - frame_animate_iconify_time_left(self, &now);
1844 } else
1845 /* animation was already going in the same direction */
1846 set_end = FALSE;
1847 } else
1848 new_anim = TRUE;
1849 self->iconify_animation_going = iconifying ? 1 : -1;
1851 /* set the ending time */
1852 if (set_end) {
1853 self->iconify_animation_end.tv_sec = now.tv_sec;
1854 self->iconify_animation_end.tv_usec = now.tv_usec;
1855 g_time_val_add(&self->iconify_animation_end, time);
1858 if (new_anim) {
1859 if (self->iconify_animation_timer)
1860 g_source_remove(self->iconify_animation_timer);
1861 self->iconify_animation_timer =
1862 g_timeout_add_full(G_PRIORITY_DEFAULT,
1863 FRAME_ANIMATE_ICONIFY_STEP_TIME,
1864 frame_animate_iconify, self, NULL);
1867 /* do the first step */
1868 frame_animate_iconify(self);
1870 /* show it during the animation even if it is not "visible" */
1871 if (!self->visible)
1872 XMapWindow(obt_display, self->window);