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