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