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