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