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