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