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