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