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