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