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