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