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