1 /* -*- indent-tabs-mode: nil; tab-width: 4; c-basic-offset: 4; -*-
3 frame.c for the Openbox window manager
4 Copyright (c) 2006 Mikael Magnusson
5 Copyright (c) 2003-2007 Dana Jansens
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.
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.
17 See the COPYING file for a copy of the GNU General Public License.
26 #include "framerender.h"
27 #include "focus_cycle.h"
28 #include "focus_cycle_indicator.h"
29 #include "moveresize.h"
31 #include "obrender/theme.h"
32 #include "obt/display.h"
33 #include "obt/xqueue.h"
36 #define FRAME_EVENTMASK (EnterWindowMask | LeaveWindowMask | \
37 ButtonPressMask | ButtonReleaseMask | \
38 SubstructureRedirectMask | FocusChangeMask)
39 #define ELEMENT_EVENTMASK (ButtonPressMask | ButtonReleaseMask | \
40 ButtonMotionMask | PointerMotionMask | \
41 EnterWindowMask | LeaveWindowMask)
43 #define FRAME_ANIMATE_ICONIFY_TIME 150000 /* .15 seconds */
44 #define FRAME_ANIMATE_ICONIFY_STEP_TIME (1000 / 60) /* 60 Hz */
46 #define FRAME_HANDLE_Y(f) (f->size.top + f->client->area.height + f->cbwidth_b)
48 static void flash_done(gpointer data
);
49 static gboolean
flash_timeout(gpointer data
);
51 static void layout_title(ObFrame
*self
);
52 static void set_theme_statics(ObFrame
*self
);
53 static void free_theme_statics(ObFrame
*self
);
54 static gboolean
frame_animate_iconify(gpointer self
);
55 static void frame_adjust_cursors(ObFrame
*self
);
57 static Window
createWindow(Window parent
, Visual
*visual
,
58 gulong mask
, XSetWindowAttributes
*attrib
)
60 return XCreateWindow(obt_display
, parent
, 0, 0, 1, 1, 0,
61 (visual
? 32 : RrDepth(ob_rr_inst
)), InputOutput
,
62 (visual
? visual
: RrVisual(ob_rr_inst
)),
67 static Visual
*check_32bit_client(ObClient
*c
)
69 XWindowAttributes wattrib
;
72 /* we're already running at 32 bit depth, yay. we don't need to use their
74 if (RrDepth(ob_rr_inst
) == 32)
77 ret
= XGetWindowAttributes(obt_display
, c
->window
, &wattrib
);
78 g_assert(ret
!= BadDrawable
);
79 g_assert(ret
!= BadWindow
);
81 if (wattrib
.depth
== 32)
82 return wattrib
.visual
;
86 ObFrame
*frame_new(ObClient
*client
)
88 XSetWindowAttributes attrib
;
93 self
= g_slice_new0(ObFrame
);
94 self
->client
= client
;
96 visual
= check_32bit_client(client
);
98 /* create the non-visible decor windows */
102 /* client has a 32-bit visual */
103 mask
= CWColormap
| CWBackPixel
| CWBorderPixel
;
104 /* create a colormap with the visual */
105 self
->colormap
= attrib
.colormap
=
106 XCreateColormap(obt_display
, obt_root(ob_screen
),
108 attrib
.background_pixel
= BlackPixel(obt_display
, ob_screen
);
109 attrib
.border_pixel
= BlackPixel(obt_display
, ob_screen
);
111 self
->window
= createWindow(obt_root(ob_screen
), visual
,
114 /* create the visible decor windows */
118 /* client has a 32-bit visual */
119 mask
= CWColormap
| CWBackPixel
| CWBorderPixel
;
120 attrib
.colormap
= RrColormap(ob_rr_inst
);
123 self
->backback
= createWindow(self
->window
, NULL
, mask
, &attrib
);
124 self
->backfront
= createWindow(self
->backback
, NULL
, mask
, &attrib
);
127 attrib
.event_mask
= ELEMENT_EVENTMASK
;
128 self
->innerleft
= createWindow(self
->window
, NULL
, mask
, &attrib
);
129 self
->innertop
= createWindow(self
->window
, NULL
, mask
, &attrib
);
130 self
->innerright
= createWindow(self
->window
, NULL
, mask
, &attrib
);
131 self
->innerbottom
= createWindow(self
->window
, NULL
, mask
, &attrib
);
133 self
->innerblb
= createWindow(self
->innerbottom
, NULL
, mask
, &attrib
);
134 self
->innerbrb
= createWindow(self
->innerbottom
, NULL
, mask
, &attrib
);
135 self
->innerbll
= createWindow(self
->innerleft
, NULL
, mask
, &attrib
);
136 self
->innerbrr
= createWindow(self
->innerright
, NULL
, mask
, &attrib
);
138 self
->title
= createWindow(self
->window
, NULL
, mask
, &attrib
);
139 self
->titleleft
= createWindow(self
->window
, NULL
, mask
, &attrib
);
140 self
->titletop
= createWindow(self
->window
, NULL
, mask
, &attrib
);
141 self
->titletopleft
= createWindow(self
->window
, NULL
, mask
, &attrib
);
142 self
->titletopright
= createWindow(self
->window
, NULL
, mask
, &attrib
);
143 self
->titleright
= createWindow(self
->window
, NULL
, mask
, &attrib
);
144 self
->titlebottom
= createWindow(self
->window
, NULL
, mask
, &attrib
);
146 self
->topresize
= createWindow(self
->title
, NULL
, mask
, &attrib
);
147 self
->tltresize
= createWindow(self
->title
, NULL
, mask
, &attrib
);
148 self
->tllresize
= createWindow(self
->title
, NULL
, mask
, &attrib
);
149 self
->trtresize
= createWindow(self
->title
, NULL
, mask
, &attrib
);
150 self
->trrresize
= createWindow(self
->title
, NULL
, mask
, &attrib
);
152 self
->left
= createWindow(self
->window
, NULL
, mask
, &attrib
);
153 self
->right
= createWindow(self
->window
, NULL
, mask
, &attrib
);
155 self
->label
= createWindow(self
->title
, NULL
, mask
, &attrib
);
156 self
->max
= createWindow(self
->title
, NULL
, mask
, &attrib
);
157 self
->close
= createWindow(self
->title
, NULL
, mask
, &attrib
);
158 self
->desk
= createWindow(self
->title
, NULL
, mask
, &attrib
);
159 self
->shade
= createWindow(self
->title
, NULL
, mask
, &attrib
);
160 self
->icon
= createWindow(self
->title
, NULL
, mask
, &attrib
);
161 self
->iconify
= createWindow(self
->title
, NULL
, mask
, &attrib
);
163 self
->handle
= createWindow(self
->window
, NULL
, mask
, &attrib
);
164 self
->lgrip
= createWindow(self
->handle
, NULL
, mask
, &attrib
);
165 self
->rgrip
= createWindow(self
->handle
, NULL
, mask
, &attrib
);
167 self
->handleleft
= createWindow(self
->handle
, NULL
, mask
, &attrib
);
168 self
->handleright
= createWindow(self
->handle
, NULL
, mask
, &attrib
);
170 self
->handletop
= createWindow(self
->window
, NULL
, mask
, &attrib
);
171 self
->handlebottom
= createWindow(self
->window
, NULL
, mask
, &attrib
);
172 self
->lgripleft
= createWindow(self
->window
, NULL
, mask
, &attrib
);
173 self
->lgriptop
= createWindow(self
->window
, NULL
, mask
, &attrib
);
174 self
->lgripbottom
= createWindow(self
->window
, NULL
, mask
, &attrib
);
175 self
->rgripright
= createWindow(self
->window
, NULL
, mask
, &attrib
);
176 self
->rgriptop
= createWindow(self
->window
, NULL
, mask
, &attrib
);
177 self
->rgripbottom
= createWindow(self
->window
, NULL
, mask
, &attrib
);
179 self
->focused
= FALSE
;
181 /* the other stuff is shown based on decor settings */
182 XMapWindow(obt_display
, self
->label
);
183 XMapWindow(obt_display
, self
->backback
);
184 XMapWindow(obt_display
, self
->backfront
);
186 self
->max_press
= self
->close_press
= self
->desk_press
=
187 self
->iconify_press
= self
->shade_press
= FALSE
;
188 self
->max_hover
= self
->close_hover
= self
->desk_hover
=
189 self
->iconify_hover
= self
->shade_hover
= FALSE
;
191 /* make sure the size will be different the first time, so the extent hints
193 STRUT_SET(self
->oldsize
, -1, -1, -1, -1);
195 set_theme_statics(self
);
200 static void set_theme_statics(ObFrame
*self
)
202 /* set colors/appearance/sizes for stuff that doesn't change */
203 XResizeWindow(obt_display
, self
->max
,
204 ob_rr_theme
->button_size
, ob_rr_theme
->button_size
);
205 XResizeWindow(obt_display
, self
->iconify
,
206 ob_rr_theme
->button_size
, ob_rr_theme
->button_size
);
207 XResizeWindow(obt_display
, self
->icon
,
208 ob_rr_theme
->button_size
+ 2, ob_rr_theme
->button_size
+ 2);
209 XResizeWindow(obt_display
, self
->close
,
210 ob_rr_theme
->button_size
, ob_rr_theme
->button_size
);
211 XResizeWindow(obt_display
, self
->desk
,
212 ob_rr_theme
->button_size
, ob_rr_theme
->button_size
);
213 XResizeWindow(obt_display
, self
->shade
,
214 ob_rr_theme
->button_size
, ob_rr_theme
->button_size
);
215 XResizeWindow(obt_display
, self
->tltresize
,
216 ob_rr_theme
->grip_width
, ob_rr_theme
->paddingy
+ 1);
217 XResizeWindow(obt_display
, self
->trtresize
,
218 ob_rr_theme
->grip_width
, ob_rr_theme
->paddingy
+ 1);
219 XResizeWindow(obt_display
, self
->tllresize
,
220 ob_rr_theme
->paddingx
+ 1, ob_rr_theme
->title_height
);
221 XResizeWindow(obt_display
, self
->trrresize
,
222 ob_rr_theme
->paddingx
+ 1, ob_rr_theme
->title_height
);
225 static void free_theme_statics(ObFrame
*self
)
229 void frame_free(ObFrame
*self
)
231 free_theme_statics(self
);
233 XDestroyWindow(obt_display
, self
->window
);
235 XFreeColormap(obt_display
, self
->colormap
);
237 g_slice_free(ObFrame
, self
);
240 void frame_show(ObFrame
*self
)
242 if (!self
->visible
) {
243 self
->visible
= TRUE
;
244 framerender_frame(self
);
245 /* Grab the server to make sure that the frame window is mapped before
246 the client gets its MapNotify, i.e. to make sure the client is
247 _visible_ when it gets MapNotify. */
249 XMapWindow(obt_display
, self
->client
->window
);
250 XMapWindow(obt_display
, self
->window
);
255 void frame_hide(ObFrame
*self
)
258 self
->visible
= FALSE
;
259 if (!frame_iconify_animating(self
))
260 XUnmapWindow(obt_display
, self
->window
);
261 /* we unmap the client itself so that we can get MapRequest
262 events, and because the ICCCM tells us to! */
263 XUnmapWindow(obt_display
, self
->client
->window
);
264 self
->client
->ignore_unmaps
+= 1;
268 void frame_adjust_theme(ObFrame
*self
)
270 free_theme_statics(self
);
271 set_theme_statics(self
);
275 void frame_adjust_shape_kind(ObFrame
*self
, int kind
)
281 shaped
= (kind
== ShapeBounding
&& self
->client
->shaped
);
283 shaped
|= (kind
== ShapeInput
&& self
->client
->shaped_input
);
287 /* clear the shape on the frame window */
288 XShapeCombineMask(obt_display
, self
->window
, kind
,
293 /* make the frame's shape match the clients */
294 XShapeCombineShape(obt_display
, self
->window
, kind
,
297 self
->client
->window
,
301 if (self
->decorations
& OB_FRAME_DECOR_TITLEBAR
) {
304 xrect
[0].width
= self
->area
.width
;
305 xrect
[0].height
= self
->size
.top
;
309 if (self
->decorations
& OB_FRAME_DECOR_HANDLE
&&
310 ob_rr_theme
->handle_height
> 0)
313 xrect
[1].y
= FRAME_HANDLE_Y(self
);
314 xrect
[1].width
= self
->area
.width
;
315 xrect
[1].height
= ob_rr_theme
->handle_height
+
320 XShapeCombineRectangles(obt_display
, self
->window
,
321 ShapeBounding
, 0, 0, xrect
, num
,
322 ShapeUnion
, Unsorted
);
327 void frame_adjust_shape(ObFrame
*self
)
330 frame_adjust_shape_kind(self
, ShapeBounding
);
332 frame_adjust_shape_kind(self
, ShapeInput
);
337 void frame_adjust_area(ObFrame
*self
, gboolean moved
,
338 gboolean resized
, gboolean fake
)
341 /* do this before changing the frame's status like max_horz max_vert */
342 frame_adjust_cursors(self
);
344 self
->functions
= self
->client
->functions
;
345 self
->decorations
= self
->client
->decorations
;
346 self
->max_horz
= self
->client
->max_horz
;
347 self
->max_vert
= self
->client
->max_vert
;
348 self
->shaded
= self
->client
->shaded
;
350 if (self
->decorations
& OB_FRAME_DECOR_BORDER
)
351 self
->bwidth
= self
->client
->undecorated
?
352 ob_rr_theme
->ubwidth
: ob_rr_theme
->fbwidth
;
356 if (self
->decorations
& OB_FRAME_DECOR_BORDER
&&
357 !self
->client
->undecorated
)
359 self
->cbwidth_l
= self
->cbwidth_r
= ob_rr_theme
->cbwidthx
;
360 self
->cbwidth_t
= self
->cbwidth_b
= ob_rr_theme
->cbwidthy
;
362 self
->cbwidth_l
= self
->cbwidth_t
=
363 self
->cbwidth_r
= self
->cbwidth_b
= 0;
365 if (self
->max_horz
) {
366 self
->cbwidth_l
= self
->cbwidth_r
= 0;
367 self
->width
= self
->client
->area
.width
;
371 self
->width
= self
->client
->area
.width
+
372 self
->cbwidth_l
+ self
->cbwidth_r
;
374 /* some elements are sized based of the width, so don't let them have
376 self
->width
= MAX(self
->width
,
377 (ob_rr_theme
->grip_width
+ self
->bwidth
) * 2 + 1);
379 STRUT_SET(self
->size
,
380 self
->cbwidth_l
+ (!self
->max_horz
? self
->bwidth
: 0),
381 self
->cbwidth_t
+ self
->bwidth
,
382 self
->cbwidth_r
+ (!self
->max_horz
? self
->bwidth
: 0),
384 (!self
->max_horz
|| !self
->max_vert
? self
->bwidth
: 0));
386 if (self
->decorations
& OB_FRAME_DECOR_TITLEBAR
)
387 self
->size
.top
+= ob_rr_theme
->title_height
+ self
->bwidth
;
388 if (self
->decorations
& OB_FRAME_DECOR_HANDLE
&&
389 ob_rr_theme
->handle_height
> 0)
391 self
->size
.bottom
+= ob_rr_theme
->handle_height
+ self
->bwidth
;
394 /* position/size and map/unmap all the windows */
397 gint innercornerheight
=
398 ob_rr_theme
->grip_width
- self
->size
.bottom
;
400 if (self
->cbwidth_l
) {
401 XMoveResizeWindow(obt_display
, self
->innerleft
,
402 self
->size
.left
- self
->cbwidth_l
,
404 self
->cbwidth_l
, self
->client
->area
.height
);
406 XMapWindow(obt_display
, self
->innerleft
);
408 XUnmapWindow(obt_display
, self
->innerleft
);
410 if (self
->cbwidth_l
&& innercornerheight
> 0) {
411 XMoveResizeWindow(obt_display
, self
->innerbll
,
413 self
->client
->area
.height
-
414 (ob_rr_theme
->grip_width
-
417 ob_rr_theme
->grip_width
- self
->size
.bottom
);
419 XMapWindow(obt_display
, self
->innerbll
);
421 XUnmapWindow(obt_display
, self
->innerbll
);
423 if (self
->cbwidth_r
) {
424 XMoveResizeWindow(obt_display
, self
->innerright
,
425 self
->size
.left
+ self
->client
->area
.width
,
427 self
->cbwidth_r
, self
->client
->area
.height
);
429 XMapWindow(obt_display
, self
->innerright
);
431 XUnmapWindow(obt_display
, self
->innerright
);
433 if (self
->cbwidth_r
&& innercornerheight
> 0) {
434 XMoveResizeWindow(obt_display
, self
->innerbrr
,
436 self
->client
->area
.height
-
437 (ob_rr_theme
->grip_width
-
440 ob_rr_theme
->grip_width
- self
->size
.bottom
);
442 XMapWindow(obt_display
, self
->innerbrr
);
444 XUnmapWindow(obt_display
, self
->innerbrr
);
446 if (self
->cbwidth_t
) {
447 XMoveResizeWindow(obt_display
, self
->innertop
,
448 self
->size
.left
- self
->cbwidth_l
,
449 self
->size
.top
- self
->cbwidth_t
,
450 self
->client
->area
.width
+
451 self
->cbwidth_l
+ self
->cbwidth_r
,
454 XMapWindow(obt_display
, self
->innertop
);
456 XUnmapWindow(obt_display
, self
->innertop
);
458 if (self
->cbwidth_b
) {
459 XMoveResizeWindow(obt_display
, self
->innerbottom
,
460 self
->size
.left
- self
->cbwidth_l
,
461 self
->size
.top
+ self
->client
->area
.height
,
462 self
->client
->area
.width
+
463 self
->cbwidth_l
+ self
->cbwidth_r
,
466 XMoveResizeWindow(obt_display
, self
->innerblb
,
468 ob_rr_theme
->grip_width
+ self
->bwidth
,
470 XMoveResizeWindow(obt_display
, self
->innerbrb
,
471 self
->client
->area
.width
+
472 self
->cbwidth_l
+ self
->cbwidth_r
-
473 (ob_rr_theme
->grip_width
+ self
->bwidth
),
475 ob_rr_theme
->grip_width
+ self
->bwidth
,
478 XMapWindow(obt_display
, self
->innerbottom
);
479 XMapWindow(obt_display
, self
->innerblb
);
480 XMapWindow(obt_display
, self
->innerbrb
);
482 XUnmapWindow(obt_display
, self
->innerbottom
);
483 XUnmapWindow(obt_display
, self
->innerblb
);
484 XUnmapWindow(obt_display
, self
->innerbrb
);
490 /* height of titleleft and titleright */
491 titlesides
= (!self
->max_horz
? ob_rr_theme
->grip_width
: 0);
493 XMoveResizeWindow(obt_display
, self
->titletop
,
494 ob_rr_theme
->grip_width
+ self
->bwidth
, 0,
495 /* width + bwidth*2 - bwidth*2 - grips*2 */
496 self
->width
- ob_rr_theme
->grip_width
* 2,
498 XMoveResizeWindow(obt_display
, self
->titletopleft
,
500 ob_rr_theme
->grip_width
+ self
->bwidth
,
502 XMoveResizeWindow(obt_display
, self
->titletopright
,
503 self
->client
->area
.width
+
504 self
->size
.left
+ self
->size
.right
-
505 ob_rr_theme
->grip_width
- self
->bwidth
,
507 ob_rr_theme
->grip_width
+ self
->bwidth
,
510 if (titlesides
> 0) {
511 XMoveResizeWindow(obt_display
, self
->titleleft
,
515 XMoveResizeWindow(obt_display
, self
->titleright
,
516 self
->client
->area
.width
+
517 self
->size
.left
+ self
->size
.right
-
523 XMapWindow(obt_display
, self
->titleleft
);
524 XMapWindow(obt_display
, self
->titleright
);
526 XUnmapWindow(obt_display
, self
->titleleft
);
527 XUnmapWindow(obt_display
, self
->titleright
);
530 XMapWindow(obt_display
, self
->titletop
);
531 XMapWindow(obt_display
, self
->titletopleft
);
532 XMapWindow(obt_display
, self
->titletopright
);
534 if (self
->decorations
& OB_FRAME_DECOR_TITLEBAR
) {
535 XMoveResizeWindow(obt_display
, self
->titlebottom
,
536 (self
->max_horz
? 0 : self
->bwidth
),
537 ob_rr_theme
->title_height
+ self
->bwidth
,
541 XMapWindow(obt_display
, self
->titlebottom
);
543 XUnmapWindow(obt_display
, self
->titlebottom
);
545 XUnmapWindow(obt_display
, self
->titlebottom
);
547 XUnmapWindow(obt_display
, self
->titletop
);
548 XUnmapWindow(obt_display
, self
->titletopleft
);
549 XUnmapWindow(obt_display
, self
->titletopright
);
550 XUnmapWindow(obt_display
, self
->titleleft
);
551 XUnmapWindow(obt_display
, self
->titleright
);
554 if (self
->decorations
& OB_FRAME_DECOR_TITLEBAR
) {
555 XMoveResizeWindow(obt_display
, self
->title
,
556 (self
->max_horz
? 0 : self
->bwidth
),
558 self
->width
, ob_rr_theme
->title_height
);
560 XMapWindow(obt_display
, self
->title
);
562 if (self
->decorations
& OB_FRAME_DECOR_GRIPS
) {
563 XMoveResizeWindow(obt_display
, self
->topresize
,
564 ob_rr_theme
->grip_width
,
566 self
->width
- ob_rr_theme
->grip_width
*2,
567 ob_rr_theme
->paddingy
+ 1);
569 XMoveWindow(obt_display
, self
->tltresize
, 0, 0);
570 XMoveWindow(obt_display
, self
->tllresize
, 0, 0);
571 XMoveWindow(obt_display
, self
->trtresize
,
572 self
->width
- ob_rr_theme
->grip_width
, 0);
573 XMoveWindow(obt_display
, self
->trrresize
,
574 self
->width
- ob_rr_theme
->paddingx
- 1, 0);
576 XMapWindow(obt_display
, self
->topresize
);
577 XMapWindow(obt_display
, self
->tltresize
);
578 XMapWindow(obt_display
, self
->tllresize
);
579 XMapWindow(obt_display
, self
->trtresize
);
580 XMapWindow(obt_display
, self
->trrresize
);
582 XUnmapWindow(obt_display
, self
->topresize
);
583 XUnmapWindow(obt_display
, self
->tltresize
);
584 XUnmapWindow(obt_display
, self
->tllresize
);
585 XUnmapWindow(obt_display
, self
->trtresize
);
586 XUnmapWindow(obt_display
, self
->trrresize
);
589 XUnmapWindow(obt_display
, self
->title
);
592 if ((self
->decorations
& OB_FRAME_DECOR_TITLEBAR
))
593 /* layout the title bar elements */
597 gint sidebwidth
= self
->max_horz
? 0 : self
->bwidth
;
599 if (self
->bwidth
&& self
->size
.bottom
) {
600 XMoveResizeWindow(obt_display
, self
->handlebottom
,
601 ob_rr_theme
->grip_width
+
602 self
->bwidth
+ sidebwidth
,
603 self
->size
.top
+ self
->client
->area
.height
+
604 self
->size
.bottom
- self
->bwidth
,
605 self
->width
- (ob_rr_theme
->grip_width
+
611 XMoveResizeWindow(obt_display
, self
->lgripleft
,
614 self
->client
->area
.height
+
617 ob_rr_theme
->grip_width
:
618 self
->size
.bottom
- self
->cbwidth_b
),
621 ob_rr_theme
->grip_width
:
622 self
->size
.bottom
- self
->cbwidth_b
));
623 XMoveResizeWindow(obt_display
, self
->rgripright
,
625 self
->client
->area
.width
+
626 self
->size
.right
- self
->bwidth
,
628 self
->client
->area
.height
+
631 ob_rr_theme
->grip_width
:
632 self
->size
.bottom
- self
->cbwidth_b
),
635 ob_rr_theme
->grip_width
:
636 self
->size
.bottom
- self
->cbwidth_b
));
638 XMapWindow(obt_display
, self
->lgripleft
);
639 XMapWindow(obt_display
, self
->rgripright
);
641 XUnmapWindow(obt_display
, self
->lgripleft
);
642 XUnmapWindow(obt_display
, self
->rgripright
);
645 XMoveResizeWindow(obt_display
, self
->lgripbottom
,
647 self
->size
.top
+ self
->client
->area
.height
+
648 self
->size
.bottom
- self
->bwidth
,
649 ob_rr_theme
->grip_width
+ self
->bwidth
,
651 XMoveResizeWindow(obt_display
, self
->rgripbottom
,
652 self
->size
.left
+ self
->client
->area
.width
+
653 self
->size
.right
- self
->bwidth
- sidebwidth
-
654 ob_rr_theme
->grip_width
,
655 self
->size
.top
+ self
->client
->area
.height
+
656 self
->size
.bottom
- self
->bwidth
,
657 ob_rr_theme
->grip_width
+ self
->bwidth
,
660 XMapWindow(obt_display
, self
->handlebottom
);
661 XMapWindow(obt_display
, self
->lgripbottom
);
662 XMapWindow(obt_display
, self
->rgripbottom
);
664 if (self
->decorations
& OB_FRAME_DECOR_HANDLE
&&
665 ob_rr_theme
->handle_height
> 0)
667 XMoveResizeWindow(obt_display
, self
->handletop
,
668 ob_rr_theme
->grip_width
+
669 self
->bwidth
+ sidebwidth
,
670 FRAME_HANDLE_Y(self
),
671 self
->width
- (ob_rr_theme
->grip_width
+
674 XMapWindow(obt_display
, self
->handletop
);
676 if (self
->decorations
& OB_FRAME_DECOR_GRIPS
) {
677 XMoveResizeWindow(obt_display
, self
->handleleft
,
678 ob_rr_theme
->grip_width
,
681 ob_rr_theme
->handle_height
);
682 XMoveResizeWindow(obt_display
, self
->handleright
,
684 ob_rr_theme
->grip_width
-
688 ob_rr_theme
->handle_height
);
690 XMoveResizeWindow(obt_display
, self
->lgriptop
,
692 FRAME_HANDLE_Y(self
),
693 ob_rr_theme
->grip_width
+
696 XMoveResizeWindow(obt_display
, self
->rgriptop
,
698 self
->client
->area
.width
+
699 self
->size
.right
- self
->bwidth
-
700 sidebwidth
- ob_rr_theme
->grip_width
,
701 FRAME_HANDLE_Y(self
),
702 ob_rr_theme
->grip_width
+
706 XMapWindow(obt_display
, self
->handleleft
);
707 XMapWindow(obt_display
, self
->handleright
);
708 XMapWindow(obt_display
, self
->lgriptop
);
709 XMapWindow(obt_display
, self
->rgriptop
);
711 XUnmapWindow(obt_display
, self
->handleleft
);
712 XUnmapWindow(obt_display
, self
->handleright
);
713 XUnmapWindow(obt_display
, self
->lgriptop
);
714 XUnmapWindow(obt_display
, self
->rgriptop
);
717 XUnmapWindow(obt_display
, self
->handleleft
);
718 XUnmapWindow(obt_display
, self
->handleright
);
719 XUnmapWindow(obt_display
, self
->lgriptop
);
720 XUnmapWindow(obt_display
, self
->rgriptop
);
722 XUnmapWindow(obt_display
, self
->handletop
);
725 XUnmapWindow(obt_display
, self
->handleleft
);
726 XUnmapWindow(obt_display
, self
->handleright
);
727 XUnmapWindow(obt_display
, self
->lgriptop
);
728 XUnmapWindow(obt_display
, self
->rgriptop
);
730 XUnmapWindow(obt_display
, self
->handletop
);
732 XUnmapWindow(obt_display
, self
->handlebottom
);
733 XUnmapWindow(obt_display
, self
->lgripleft
);
734 XUnmapWindow(obt_display
, self
->rgripright
);
735 XUnmapWindow(obt_display
, self
->lgripbottom
);
736 XUnmapWindow(obt_display
, self
->rgripbottom
);
739 if (self
->decorations
& OB_FRAME_DECOR_HANDLE
&&
740 ob_rr_theme
->handle_height
> 0)
742 XMoveResizeWindow(obt_display
, self
->handle
,
744 FRAME_HANDLE_Y(self
) + self
->bwidth
,
745 self
->width
, ob_rr_theme
->handle_height
);
746 XMapWindow(obt_display
, self
->handle
);
748 if (self
->decorations
& OB_FRAME_DECOR_GRIPS
) {
749 XMoveResizeWindow(obt_display
, self
->lgrip
,
751 ob_rr_theme
->grip_width
,
752 ob_rr_theme
->handle_height
);
753 XMoveResizeWindow(obt_display
, self
->rgrip
,
754 self
->width
- ob_rr_theme
->grip_width
,
756 ob_rr_theme
->grip_width
,
757 ob_rr_theme
->handle_height
);
759 XMapWindow(obt_display
, self
->lgrip
);
760 XMapWindow(obt_display
, self
->rgrip
);
762 XUnmapWindow(obt_display
, self
->lgrip
);
763 XUnmapWindow(obt_display
, self
->rgrip
);
766 XUnmapWindow(obt_display
, self
->lgrip
);
767 XUnmapWindow(obt_display
, self
->rgrip
);
769 XUnmapWindow(obt_display
, self
->handle
);
772 if (self
->bwidth
&& !self
->max_horz
&&
773 (self
->client
->area
.height
+ self
->size
.top
+
774 self
->size
.bottom
) > ob_rr_theme
->grip_width
* 2)
776 XMoveResizeWindow(obt_display
, self
->left
,
778 self
->bwidth
+ ob_rr_theme
->grip_width
,
780 self
->client
->area
.height
+
781 self
->size
.top
+ self
->size
.bottom
-
782 ob_rr_theme
->grip_width
* 2);
784 XMapWindow(obt_display
, self
->left
);
786 XUnmapWindow(obt_display
, self
->left
);
788 if (self
->bwidth
&& !self
->max_horz
&&
789 (self
->client
->area
.height
+ self
->size
.top
+
790 self
->size
.bottom
) > ob_rr_theme
->grip_width
* 2)
792 XMoveResizeWindow(obt_display
, self
->right
,
793 self
->client
->area
.width
+ self
->cbwidth_l
+
794 self
->cbwidth_r
+ self
->bwidth
,
795 self
->bwidth
+ ob_rr_theme
->grip_width
,
797 self
->client
->area
.height
+
798 self
->size
.top
+ self
->size
.bottom
-
799 ob_rr_theme
->grip_width
* 2);
801 XMapWindow(obt_display
, self
->right
);
803 XUnmapWindow(obt_display
, self
->right
);
805 XMoveResizeWindow(obt_display
, self
->backback
,
806 self
->size
.left
, self
->size
.top
,
807 self
->client
->area
.width
,
808 self
->client
->area
.height
);
812 /* shading can change without being moved or resized */
813 RECT_SET_SIZE(self
->area
,
814 self
->client
->area
.width
+
815 self
->size
.left
+ self
->size
.right
,
816 (self
->client
->shaded
?
817 ob_rr_theme
->title_height
+ self
->bwidth
* 2:
818 self
->client
->area
.height
+
819 self
->size
.top
+ self
->size
.bottom
));
821 if ((moved
|| resized
) && !fake
) {
822 /* find the new coordinates, done after setting the frame.size, for
823 frame_client_gravity. */
824 self
->area
.x
= self
->client
->area
.x
;
825 self
->area
.y
= self
->client
->area
.y
;
826 frame_client_gravity(self
, &self
->area
.x
, &self
->area
.y
);
830 if (!frame_iconify_animating(self
))
831 /* move and resize the top level frame.
832 shading can change without being moved or resized.
834 but don't do this during an iconify animation. it will be
835 reflected afterwards.
837 XMoveResizeWindow(obt_display
, self
->window
,
843 /* when the client has StaticGravity, it likes to move around.
844 also this correctly positions the client when it maps.
845 this also needs to be run when the frame's decorations sizes change!
847 XMoveWindow(obt_display
, self
->client
->window
,
848 self
->size
.left
, self
->size
.top
);
851 self
->need_render
= TRUE
;
852 framerender_frame(self
);
853 frame_adjust_shape(self
);
856 if (!STRUT_EQUAL(self
->size
, self
->oldsize
)) {
858 vals
[0] = self
->size
.left
;
859 vals
[1] = self
->size
.right
;
860 vals
[2] = self
->size
.top
;
861 vals
[3] = self
->size
.bottom
;
862 OBT_PROP_SETA32(self
->client
->window
, NET_FRAME_EXTENTS
,
864 OBT_PROP_SETA32(self
->client
->window
, KDE_NET_WM_FRAME_STRUT
,
866 self
->oldsize
= self
->size
;
869 /* if this occurs while we are focus cycling, the indicator needs to
871 if (focus_cycle_target
== self
->client
)
872 focus_cycle_update_indicator(self
->client
);
874 if (resized
&& (self
->decorations
& OB_FRAME_DECOR_TITLEBAR
) &&
877 XResizeWindow(obt_display
, self
->label
, self
->label_width
,
878 ob_rr_theme
->label_height
);
882 static void frame_adjust_cursors(ObFrame
*self
)
884 if ((self
->functions
& OB_CLIENT_FUNC_RESIZE
) !=
885 (self
->client
->functions
& OB_CLIENT_FUNC_RESIZE
) ||
886 self
->max_horz
!= self
->client
->max_horz
||
887 self
->max_vert
!= self
->client
->max_vert
||
888 self
->shaded
!= self
->client
->shaded
)
890 gboolean r
= (self
->client
->functions
& OB_CLIENT_FUNC_RESIZE
) &&
891 !(self
->client
->max_horz
&& self
->client
->max_vert
);
892 gboolean topbot
= !self
->client
->max_vert
;
893 gboolean sh
= self
->client
->shaded
;
894 XSetWindowAttributes a
;
896 /* these ones turn off when max vert, and some when shaded */
897 a
.cursor
= ob_cursor(r
&& topbot
&& !sh
?
898 OB_CURSOR_NORTH
: OB_CURSOR_NONE
);
899 XChangeWindowAttributes(obt_display
, self
->topresize
, CWCursor
, &a
);
900 XChangeWindowAttributes(obt_display
, self
->titletop
, CWCursor
, &a
);
901 a
.cursor
= ob_cursor(r
&& topbot
? OB_CURSOR_SOUTH
: OB_CURSOR_NONE
);
902 XChangeWindowAttributes(obt_display
, self
->handle
, CWCursor
, &a
);
903 XChangeWindowAttributes(obt_display
, self
->handletop
, CWCursor
, &a
);
904 XChangeWindowAttributes(obt_display
, self
->handlebottom
, CWCursor
, &a
);
905 XChangeWindowAttributes(obt_display
, self
->innerbottom
, CWCursor
, &a
);
907 /* these ones change when shaded */
908 a
.cursor
= ob_cursor(r
? (sh
? OB_CURSOR_WEST
: OB_CURSOR_NORTHWEST
) :
910 XChangeWindowAttributes(obt_display
, self
->titleleft
, CWCursor
, &a
);
911 XChangeWindowAttributes(obt_display
, self
->tltresize
, CWCursor
, &a
);
912 XChangeWindowAttributes(obt_display
, self
->tllresize
, CWCursor
, &a
);
913 XChangeWindowAttributes(obt_display
, self
->titletopleft
, CWCursor
, &a
);
914 a
.cursor
= ob_cursor(r
? (sh
? OB_CURSOR_EAST
: OB_CURSOR_NORTHEAST
) :
916 XChangeWindowAttributes(obt_display
, self
->titleright
, CWCursor
, &a
);
917 XChangeWindowAttributes(obt_display
, self
->trtresize
, CWCursor
, &a
);
918 XChangeWindowAttributes(obt_display
, self
->trrresize
, CWCursor
, &a
);
919 XChangeWindowAttributes(obt_display
, self
->titletopright
, CWCursor
,&a
);
921 /* these ones are pretty static */
922 a
.cursor
= ob_cursor(r
? OB_CURSOR_WEST
: OB_CURSOR_NONE
);
923 XChangeWindowAttributes(obt_display
, self
->left
, CWCursor
, &a
);
924 XChangeWindowAttributes(obt_display
, self
->innerleft
, CWCursor
, &a
);
925 a
.cursor
= ob_cursor(r
? OB_CURSOR_EAST
: OB_CURSOR_NONE
);
926 XChangeWindowAttributes(obt_display
, self
->right
, CWCursor
, &a
);
927 XChangeWindowAttributes(obt_display
, self
->innerright
, CWCursor
, &a
);
928 a
.cursor
= ob_cursor(r
? OB_CURSOR_SOUTHWEST
: OB_CURSOR_NONE
);
929 XChangeWindowAttributes(obt_display
, self
->lgrip
, CWCursor
, &a
);
930 XChangeWindowAttributes(obt_display
, self
->handleleft
, CWCursor
, &a
);
931 XChangeWindowAttributes(obt_display
, self
->lgripleft
, CWCursor
, &a
);
932 XChangeWindowAttributes(obt_display
, self
->lgriptop
, CWCursor
, &a
);
933 XChangeWindowAttributes(obt_display
, self
->lgripbottom
, CWCursor
, &a
);
934 XChangeWindowAttributes(obt_display
, self
->innerbll
, CWCursor
, &a
);
935 XChangeWindowAttributes(obt_display
, self
->innerblb
, CWCursor
, &a
);
936 a
.cursor
= ob_cursor(r
? OB_CURSOR_SOUTHEAST
: OB_CURSOR_NONE
);
937 XChangeWindowAttributes(obt_display
, self
->rgrip
, CWCursor
, &a
);
938 XChangeWindowAttributes(obt_display
, self
->handleright
, CWCursor
, &a
);
939 XChangeWindowAttributes(obt_display
, self
->rgripright
, CWCursor
, &a
);
940 XChangeWindowAttributes(obt_display
, self
->rgriptop
, CWCursor
, &a
);
941 XChangeWindowAttributes(obt_display
, self
->rgripbottom
, CWCursor
, &a
);
942 XChangeWindowAttributes(obt_display
, self
->innerbrr
, CWCursor
, &a
);
943 XChangeWindowAttributes(obt_display
, self
->innerbrb
, CWCursor
, &a
);
947 void frame_adjust_client_area(ObFrame
*self
)
949 /* adjust the window which is there to prevent flashing on unmap */
950 XMoveResizeWindow(obt_display
, self
->backfront
, 0, 0,
951 self
->client
->area
.width
,
952 self
->client
->area
.height
);
955 void frame_adjust_state(ObFrame
*self
)
957 self
->need_render
= TRUE
;
958 framerender_frame(self
);
961 void frame_adjust_focus(ObFrame
*self
, gboolean hilite
)
963 ob_debug_type(OB_DEBUG_FOCUS
,
964 "Frame for 0x%x has focus: %d",
965 self
->client
->window
, hilite
);
966 self
->focused
= hilite
;
967 self
->need_render
= TRUE
;
968 framerender_frame(self
);
972 void frame_adjust_title(ObFrame
*self
)
974 self
->need_render
= TRUE
;
975 framerender_frame(self
);
978 void frame_adjust_icon(ObFrame
*self
)
980 self
->need_render
= TRUE
;
981 framerender_frame(self
);
984 void frame_grab_client(ObFrame
*self
)
986 /* DO NOT map the client window here. we used to do that, but it is bogus.
987 we need to set up the client's dimensions and everything before we
988 send a mapnotify or we create race conditions.
991 /* reparent the client to the frame */
992 XReparentWindow(obt_display
, self
->client
->window
, self
->window
, 0, 0);
995 When reparenting the client window, it is usually not mapped yet, since
996 this occurs from a MapRequest. However, in the case where Openbox is
997 starting up, the window is already mapped, so we'll see an unmap event
1000 if (ob_state() == OB_STATE_STARTING
)
1001 ++self
->client
->ignore_unmaps
;
1003 /* select the event mask on the client's parent (to receive config/map
1004 req's) the ButtonPress is to catch clicks on the client border */
1005 XSelectInput(obt_display
, self
->window
, FRAME_EVENTMASK
);
1007 /* set all the windows for the frame in the window_map */
1008 window_add(&self
->window
, CLIENT_AS_WINDOW(self
->client
));
1009 window_add(&self
->backback
, CLIENT_AS_WINDOW(self
->client
));
1010 window_add(&self
->backfront
, CLIENT_AS_WINDOW(self
->client
));
1011 window_add(&self
->innerleft
, CLIENT_AS_WINDOW(self
->client
));
1012 window_add(&self
->innertop
, CLIENT_AS_WINDOW(self
->client
));
1013 window_add(&self
->innerright
, CLIENT_AS_WINDOW(self
->client
));
1014 window_add(&self
->innerbottom
, CLIENT_AS_WINDOW(self
->client
));
1015 window_add(&self
->innerblb
, CLIENT_AS_WINDOW(self
->client
));
1016 window_add(&self
->innerbll
, CLIENT_AS_WINDOW(self
->client
));
1017 window_add(&self
->innerbrb
, CLIENT_AS_WINDOW(self
->client
));
1018 window_add(&self
->innerbrr
, CLIENT_AS_WINDOW(self
->client
));
1019 window_add(&self
->title
, CLIENT_AS_WINDOW(self
->client
));
1020 window_add(&self
->label
, CLIENT_AS_WINDOW(self
->client
));
1021 window_add(&self
->max
, CLIENT_AS_WINDOW(self
->client
));
1022 window_add(&self
->close
, CLIENT_AS_WINDOW(self
->client
));
1023 window_add(&self
->desk
, CLIENT_AS_WINDOW(self
->client
));
1024 window_add(&self
->shade
, CLIENT_AS_WINDOW(self
->client
));
1025 window_add(&self
->icon
, CLIENT_AS_WINDOW(self
->client
));
1026 window_add(&self
->iconify
, CLIENT_AS_WINDOW(self
->client
));
1027 window_add(&self
->handle
, CLIENT_AS_WINDOW(self
->client
));
1028 window_add(&self
->lgrip
, CLIENT_AS_WINDOW(self
->client
));
1029 window_add(&self
->rgrip
, CLIENT_AS_WINDOW(self
->client
));
1030 window_add(&self
->topresize
, CLIENT_AS_WINDOW(self
->client
));
1031 window_add(&self
->tltresize
, CLIENT_AS_WINDOW(self
->client
));
1032 window_add(&self
->tllresize
, CLIENT_AS_WINDOW(self
->client
));
1033 window_add(&self
->trtresize
, CLIENT_AS_WINDOW(self
->client
));
1034 window_add(&self
->trrresize
, CLIENT_AS_WINDOW(self
->client
));
1035 window_add(&self
->left
, CLIENT_AS_WINDOW(self
->client
));
1036 window_add(&self
->right
, CLIENT_AS_WINDOW(self
->client
));
1037 window_add(&self
->titleleft
, CLIENT_AS_WINDOW(self
->client
));
1038 window_add(&self
->titletop
, CLIENT_AS_WINDOW(self
->client
));
1039 window_add(&self
->titletopleft
, CLIENT_AS_WINDOW(self
->client
));
1040 window_add(&self
->titletopright
, CLIENT_AS_WINDOW(self
->client
));
1041 window_add(&self
->titleright
, CLIENT_AS_WINDOW(self
->client
));
1042 window_add(&self
->titlebottom
, CLIENT_AS_WINDOW(self
->client
));
1043 window_add(&self
->handleleft
, CLIENT_AS_WINDOW(self
->client
));
1044 window_add(&self
->handletop
, CLIENT_AS_WINDOW(self
->client
));
1045 window_add(&self
->handleright
, CLIENT_AS_WINDOW(self
->client
));
1046 window_add(&self
->handlebottom
, CLIENT_AS_WINDOW(self
->client
));
1047 window_add(&self
->lgripleft
, CLIENT_AS_WINDOW(self
->client
));
1048 window_add(&self
->lgriptop
, CLIENT_AS_WINDOW(self
->client
));
1049 window_add(&self
->lgripbottom
, CLIENT_AS_WINDOW(self
->client
));
1050 window_add(&self
->rgripright
, CLIENT_AS_WINDOW(self
->client
));
1051 window_add(&self
->rgriptop
, CLIENT_AS_WINDOW(self
->client
));
1052 window_add(&self
->rgripbottom
, CLIENT_AS_WINDOW(self
->client
));
1055 static gboolean
find_reparent(XEvent
*e
, gpointer data
)
1057 const ObFrame
*self
= data
;
1059 /* Find ReparentNotify events for the window that aren't being reparented into the
1060 frame, thus the client reparenting itself off the frame. */
1061 return e
->type
== ReparentNotify
&& e
->xreparent
.window
== self
->client
->window
&&
1062 e
->xreparent
.parent
!= self
->window
;
1065 void frame_release_client(ObFrame
*self
)
1067 /* if there was any animation going on, kill it */
1068 if (self
->iconify_animation_timer
)
1069 g_source_remove(self
->iconify_animation_timer
);
1071 /* check if the app has already reparented its window away */
1072 if (!xqueue_exists_local(find_reparent
, self
)) {
1073 /* according to the ICCCM - if the client doesn't reparent itself,
1074 then we will reparent the window to root for them */
1075 XReparentWindow(obt_display
, self
->client
->window
, obt_root(ob_screen
),
1076 self
->client
->area
.x
, self
->client
->area
.y
);
1079 /* remove all the windows for the frame from the window_map */
1080 window_remove(self
->window
);
1081 window_remove(self
->backback
);
1082 window_remove(self
->backfront
);
1083 window_remove(self
->innerleft
);
1084 window_remove(self
->innertop
);
1085 window_remove(self
->innerright
);
1086 window_remove(self
->innerbottom
);
1087 window_remove(self
->innerblb
);
1088 window_remove(self
->innerbll
);
1089 window_remove(self
->innerbrb
);
1090 window_remove(self
->innerbrr
);
1091 window_remove(self
->title
);
1092 window_remove(self
->label
);
1093 window_remove(self
->max
);
1094 window_remove(self
->close
);
1095 window_remove(self
->desk
);
1096 window_remove(self
->shade
);
1097 window_remove(self
->icon
);
1098 window_remove(self
->iconify
);
1099 window_remove(self
->handle
);
1100 window_remove(self
->lgrip
);
1101 window_remove(self
->rgrip
);
1102 window_remove(self
->topresize
);
1103 window_remove(self
->tltresize
);
1104 window_remove(self
->tllresize
);
1105 window_remove(self
->trtresize
);
1106 window_remove(self
->trrresize
);
1107 window_remove(self
->left
);
1108 window_remove(self
->right
);
1109 window_remove(self
->titleleft
);
1110 window_remove(self
->titletop
);
1111 window_remove(self
->titletopleft
);
1112 window_remove(self
->titletopright
);
1113 window_remove(self
->titleright
);
1114 window_remove(self
->titlebottom
);
1115 window_remove(self
->handleleft
);
1116 window_remove(self
->handletop
);
1117 window_remove(self
->handleright
);
1118 window_remove(self
->handlebottom
);
1119 window_remove(self
->lgripleft
);
1120 window_remove(self
->lgriptop
);
1121 window_remove(self
->lgripbottom
);
1122 window_remove(self
->rgripright
);
1123 window_remove(self
->rgriptop
);
1124 window_remove(self
->rgripbottom
);
1126 if (self
->flash_timer
) g_source_remove(self
->flash_timer
);
1129 /* is there anything present between us and the label? */
1130 static gboolean
is_button_present(ObFrame
*self
, const gchar
*lc
, gint dir
) {
1131 for (; *lc
!= '\0' && lc
>= config_title_layout
; lc
+= dir
) {
1132 if (*lc
== ' ') continue; /* it was invalid */
1133 if (*lc
== 'N' && self
->decorations
& OB_FRAME_DECOR_ICON
)
1135 if (*lc
== 'D' && self
->decorations
& OB_FRAME_DECOR_ALLDESKTOPS
)
1137 if (*lc
== 'S' && self
->decorations
& OB_FRAME_DECOR_SHADE
)
1139 if (*lc
== 'I' && self
->decorations
& OB_FRAME_DECOR_ICONIFY
)
1141 if (*lc
== 'M' && self
->decorations
& OB_FRAME_DECOR_MAXIMIZE
)
1143 if (*lc
== 'C' && self
->decorations
& OB_FRAME_DECOR_CLOSE
)
1145 if (*lc
== 'L') return FALSE
;
1150 static void place_button(ObFrame
*self
, const char *lc
, gint bwidth
,
1152 gint
*x
, gint
*button_on
, gint
*button_x
)
1154 if (!(*button_on
= is_button_present(self
, lc
, i
)))
1157 self
->label_width
-= bwidth
;
1162 if (self
->label_x
<= left
|| *x
> self
->label_x
) {
1165 /* the button would have been drawn on top of another button */
1167 self
->label_width
+= bwidth
;
1172 static void layout_title(ObFrame
*self
)
1177 const gint bwidth
= ob_rr_theme
->button_size
+ ob_rr_theme
->paddingx
+ 1;
1178 /* position of the leftmost button */
1179 const gint left
= ob_rr_theme
->paddingx
+ 1;
1180 /* position of the rightmost button */
1181 const gint right
= self
->width
;
1183 /* turn them all off */
1184 self
->icon_on
= self
->desk_on
= self
->shade_on
= self
->iconify_on
=
1185 self
->max_on
= self
->close_on
= self
->label_on
= FALSE
;
1186 self
->label_width
= self
->width
- (ob_rr_theme
->paddingx
+ 1) * 2;
1187 self
->leftmost
= self
->rightmost
= OB_FRAME_CONTEXT_NONE
;
1189 /* figure out what's being shown, find each element's position, and the
1192 do the ones before the label, then after the label,
1193 i will be +1 the first time through when working to the left,
1194 and -1 the second time through when working to the right */
1195 for (i
= 1; i
>= -1; i
-=2) {
1197 ObFrameContext
*firstcon
;
1201 lc
= config_title_layout
;
1202 firstcon
= &self
->leftmost
;
1205 lc
= config_title_layout
+ strlen(config_title_layout
)-1;
1206 firstcon
= &self
->rightmost
;
1209 /* stop at the end of the string (or the label, which calls break) */
1210 for (; *lc
!= '\0' && lc
>= config_title_layout
; lc
+=i
) {
1213 self
->label_on
= TRUE
;
1216 break; /* break the for loop, do other side of label */
1217 } else if (*lc
== 'N') {
1218 if (firstcon
) *firstcon
= OB_FRAME_CONTEXT_ICON
;
1219 /* icon is bigger than buttons */
1220 place_button(self
, lc
, bwidth
+ 2, left
, i
, &x
, &self
->icon_on
, &self
->icon_x
);
1221 } else if (*lc
== 'D') {
1222 if (firstcon
) *firstcon
= OB_FRAME_CONTEXT_ALLDESKTOPS
;
1223 place_button(self
, lc
, bwidth
, left
, i
, &x
, &self
->desk_on
, &self
->desk_x
);
1224 } else if (*lc
== 'S') {
1225 if (firstcon
) *firstcon
= OB_FRAME_CONTEXT_SHADE
;
1226 place_button(self
, lc
, bwidth
, left
, i
, &x
, &self
->shade_on
, &self
->shade_x
);
1227 } else if (*lc
== 'I') {
1228 if (firstcon
) *firstcon
= OB_FRAME_CONTEXT_ICONIFY
;
1229 place_button(self
, lc
, bwidth
, left
, i
, &x
, &self
->iconify_on
, &self
->iconify_x
);
1230 } else if (*lc
== 'M') {
1231 if (firstcon
) *firstcon
= OB_FRAME_CONTEXT_MAXIMIZE
;
1232 place_button(self
, lc
, bwidth
, left
, i
, &x
, &self
->max_on
, &self
->max_x
);
1233 } else if (*lc
== 'C') {
1234 if (firstcon
) *firstcon
= OB_FRAME_CONTEXT_CLOSE
;
1235 place_button(self
, lc
, bwidth
, left
, i
, &x
, &self
->close_on
, &self
->close_x
);
1237 continue; /* don't set firstcon */
1242 /* position and map the elements */
1243 if (self
->icon_on
) {
1244 XMapWindow(obt_display
, self
->icon
);
1245 XMoveWindow(obt_display
, self
->icon
, self
->icon_x
,
1246 ob_rr_theme
->paddingy
);
1248 XUnmapWindow(obt_display
, self
->icon
);
1250 if (self
->desk_on
) {
1251 XMapWindow(obt_display
, self
->desk
);
1252 XMoveWindow(obt_display
, self
->desk
, self
->desk_x
,
1253 ob_rr_theme
->paddingy
+ 1);
1255 XUnmapWindow(obt_display
, self
->desk
);
1257 if (self
->shade_on
) {
1258 XMapWindow(obt_display
, self
->shade
);
1259 XMoveWindow(obt_display
, self
->shade
, self
->shade_x
,
1260 ob_rr_theme
->paddingy
+ 1);
1262 XUnmapWindow(obt_display
, self
->shade
);
1264 if (self
->iconify_on
) {
1265 XMapWindow(obt_display
, self
->iconify
);
1266 XMoveWindow(obt_display
, self
->iconify
, self
->iconify_x
,
1267 ob_rr_theme
->paddingy
+ 1);
1269 XUnmapWindow(obt_display
, self
->iconify
);
1272 XMapWindow(obt_display
, self
->max
);
1273 XMoveWindow(obt_display
, self
->max
, self
->max_x
,
1274 ob_rr_theme
->paddingy
+ 1);
1276 XUnmapWindow(obt_display
, self
->max
);
1278 if (self
->close_on
) {
1279 XMapWindow(obt_display
, self
->close
);
1280 XMoveWindow(obt_display
, self
->close
, self
->close_x
,
1281 ob_rr_theme
->paddingy
+ 1);
1283 XUnmapWindow(obt_display
, self
->close
);
1285 if (self
->label_on
&& self
->label_width
> 0) {
1286 XMapWindow(obt_display
, self
->label
);
1287 XMoveWindow(obt_display
, self
->label
, self
->label_x
,
1288 ob_rr_theme
->paddingy
);
1290 XUnmapWindow(obt_display
, self
->label
);
1293 gboolean
frame_next_context_from_string(gchar
*names
, ObFrameContext
*cx
)
1297 if (!*names
) /* empty string */
1300 /* find the first space */
1301 for (p
= names
; *p
; p
= g_utf8_next_char(p
)) {
1302 const gunichar c
= g_utf8_get_char(p
);
1303 if (g_unichar_isspace(c
)) break;
1307 /* leading spaces in the string */
1308 n
= g_utf8_next_char(names
);
1309 if (!frame_next_context_from_string(n
, cx
))
1314 /* delete the space with null zero(s) */
1315 while (n
< g_utf8_next_char(p
))
1319 *cx
= frame_context_from_string(names
);
1321 /* find the next non-space */
1322 for (; *n
; n
= g_utf8_next_char(n
)) {
1323 const gunichar c
= g_utf8_get_char(n
);
1324 if (!g_unichar_isspace(c
)) break;
1328 /* delete everything we just read (copy everything at n to the start of
1330 for (p
= names
; *n
; ++p
, ++n
)
1337 ObFrameContext
frame_context_from_string(const gchar
*name
)
1339 if (!g_ascii_strcasecmp("Desktop", name
))
1340 return OB_FRAME_CONTEXT_DESKTOP
;
1341 else if (!g_ascii_strcasecmp("Root", name
))
1342 return OB_FRAME_CONTEXT_ROOT
;
1343 else if (!g_ascii_strcasecmp("Client", name
))
1344 return OB_FRAME_CONTEXT_CLIENT
;
1345 else if (!g_ascii_strcasecmp("Titlebar", name
))
1346 return OB_FRAME_CONTEXT_TITLEBAR
;
1347 else if (!g_ascii_strcasecmp("Frame", name
))
1348 return OB_FRAME_CONTEXT_FRAME
;
1349 else if (!g_ascii_strcasecmp("TLCorner", name
))
1350 return OB_FRAME_CONTEXT_TLCORNER
;
1351 else if (!g_ascii_strcasecmp("TRCorner", name
))
1352 return OB_FRAME_CONTEXT_TRCORNER
;
1353 else if (!g_ascii_strcasecmp("BLCorner", name
))
1354 return OB_FRAME_CONTEXT_BLCORNER
;
1355 else if (!g_ascii_strcasecmp("BRCorner", name
))
1356 return OB_FRAME_CONTEXT_BRCORNER
;
1357 else if (!g_ascii_strcasecmp("Top", name
))
1358 return OB_FRAME_CONTEXT_TOP
;
1359 else if (!g_ascii_strcasecmp("Bottom", name
))
1360 return OB_FRAME_CONTEXT_BOTTOM
;
1361 else if (!g_ascii_strcasecmp("Left", name
))
1362 return OB_FRAME_CONTEXT_LEFT
;
1363 else if (!g_ascii_strcasecmp("Right", name
))
1364 return OB_FRAME_CONTEXT_RIGHT
;
1365 else if (!g_ascii_strcasecmp("Maximize", name
))
1366 return OB_FRAME_CONTEXT_MAXIMIZE
;
1367 else if (!g_ascii_strcasecmp("AllDesktops", name
))
1368 return OB_FRAME_CONTEXT_ALLDESKTOPS
;
1369 else if (!g_ascii_strcasecmp("Shade", name
))
1370 return OB_FRAME_CONTEXT_SHADE
;
1371 else if (!g_ascii_strcasecmp("Iconify", name
))
1372 return OB_FRAME_CONTEXT_ICONIFY
;
1373 else if (!g_ascii_strcasecmp("Icon", name
))
1374 return OB_FRAME_CONTEXT_ICON
;
1375 else if (!g_ascii_strcasecmp("Close", name
))
1376 return OB_FRAME_CONTEXT_CLOSE
;
1377 else if (!g_ascii_strcasecmp("MoveResize", name
))
1378 return OB_FRAME_CONTEXT_MOVE_RESIZE
;
1379 else if (!g_ascii_strcasecmp("Dock", name
))
1380 return OB_FRAME_CONTEXT_DOCK
;
1382 return OB_FRAME_CONTEXT_NONE
;
1385 ObFrameContext
frame_context(ObClient
*client
, Window win
, gint x
, gint y
)
1390 if (moveresize_in_progress
)
1391 return OB_FRAME_CONTEXT_MOVE_RESIZE
;
1393 if (win
== obt_root(ob_screen
))
1394 return OB_FRAME_CONTEXT_ROOT
;
1395 if ((obwin
= window_find(win
))) {
1396 if (WINDOW_IS_DOCK(obwin
)) {
1397 return OB_FRAME_CONTEXT_DOCK
;
1400 if (client
== NULL
) return OB_FRAME_CONTEXT_NONE
;
1401 if (win
== client
->window
) {
1402 /* conceptually, this is the desktop, as far as users are
1404 if (client
->type
== OB_CLIENT_TYPE_DESKTOP
)
1405 return OB_FRAME_CONTEXT_DESKTOP
;
1406 return OB_FRAME_CONTEXT_CLIENT
;
1409 self
= client
->frame
;
1411 /* when the user clicks in the corners of the titlebar and the client
1412 is fully maximized, then treat it like they clicked in the
1413 button that is there */
1414 if (self
->max_horz
&& self
->max_vert
&&
1415 (win
== self
->title
|| win
== self
->titletop
||
1416 win
== self
->titleleft
|| win
== self
->titletopleft
||
1417 win
== self
->titleright
|| win
== self
->titletopright
))
1419 /* get the mouse coords in reference to the whole frame */
1423 /* these windows are down a border width from the top of the frame */
1424 if (win
== self
->title
||
1425 win
== self
->titleleft
|| win
== self
->titleright
)
1428 /* title is a border width in from the edge */
1429 if (win
== self
->title
)
1431 /* titletop is a bit to the right */
1432 else if (win
== self
->titletop
)
1433 fx
+= ob_rr_theme
->grip_width
+ self
->bwidth
;
1434 /* titletopright is way to the right edge */
1435 else if (win
== self
->titletopright
)
1436 fx
+= self
->area
.width
- (ob_rr_theme
->grip_width
+ self
->bwidth
);
1437 /* titleright is even more way to the right edge */
1438 else if (win
== self
->titleright
)
1439 fx
+= self
->area
.width
- self
->bwidth
;
1441 /* figure out if we're over the area that should be considered a
1443 if (fy
< self
->bwidth
+ ob_rr_theme
->paddingy
+ 1 +
1444 ob_rr_theme
->button_size
)
1446 if (fx
< (self
->bwidth
+ ob_rr_theme
->paddingx
+ 1 +
1447 ob_rr_theme
->button_size
))
1449 if (self
->leftmost
!= OB_FRAME_CONTEXT_NONE
)
1450 return self
->leftmost
;
1452 else if (fx
>= (self
->area
.width
-
1453 (self
->bwidth
+ ob_rr_theme
->paddingx
+ 1 +
1454 ob_rr_theme
->button_size
)))
1456 if (self
->rightmost
!= OB_FRAME_CONTEXT_NONE
)
1457 return self
->rightmost
;
1461 /* there is no resizing maximized windows so make them the titlebar
1463 return OB_FRAME_CONTEXT_TITLEBAR
;
1465 else if (self
->max_vert
&&
1466 (win
== self
->titletop
|| win
== self
->topresize
))
1467 /* can't resize vertically when max vert */
1468 return OB_FRAME_CONTEXT_TITLEBAR
;
1469 else if (self
->shaded
&&
1470 (win
== self
->titletop
|| win
== self
->topresize
))
1471 /* can't resize vertically when shaded */
1472 return OB_FRAME_CONTEXT_TITLEBAR
;
1474 if (win
== self
->window
) return OB_FRAME_CONTEXT_FRAME
;
1475 if (win
== self
->label
) return OB_FRAME_CONTEXT_TITLEBAR
;
1476 if (win
== self
->handle
) return OB_FRAME_CONTEXT_BOTTOM
;
1477 if (win
== self
->handletop
) return OB_FRAME_CONTEXT_BOTTOM
;
1478 if (win
== self
->handlebottom
) return OB_FRAME_CONTEXT_BOTTOM
;
1479 if (win
== self
->handleleft
) return OB_FRAME_CONTEXT_BLCORNER
;
1480 if (win
== self
->lgrip
) return OB_FRAME_CONTEXT_BLCORNER
;
1481 if (win
== self
->lgripleft
) return OB_FRAME_CONTEXT_BLCORNER
;
1482 if (win
== self
->lgriptop
) return OB_FRAME_CONTEXT_BLCORNER
;
1483 if (win
== self
->lgripbottom
) return OB_FRAME_CONTEXT_BLCORNER
;
1484 if (win
== self
->handleright
) return OB_FRAME_CONTEXT_BRCORNER
;
1485 if (win
== self
->rgrip
) return OB_FRAME_CONTEXT_BRCORNER
;
1486 if (win
== self
->rgripright
) return OB_FRAME_CONTEXT_BRCORNER
;
1487 if (win
== self
->rgriptop
) return OB_FRAME_CONTEXT_BRCORNER
;
1488 if (win
== self
->rgripbottom
) return OB_FRAME_CONTEXT_BRCORNER
;
1489 if (win
== self
->title
) return OB_FRAME_CONTEXT_TITLEBAR
;
1490 if (win
== self
->titlebottom
) return OB_FRAME_CONTEXT_TITLEBAR
;
1491 if (win
== self
->titleleft
) return OB_FRAME_CONTEXT_TLCORNER
;
1492 if (win
== self
->titletopleft
) return OB_FRAME_CONTEXT_TLCORNER
;
1493 if (win
== self
->titleright
) return OB_FRAME_CONTEXT_TRCORNER
;
1494 if (win
== self
->titletopright
) return OB_FRAME_CONTEXT_TRCORNER
;
1495 if (win
== self
->titletop
) return OB_FRAME_CONTEXT_TOP
;
1496 if (win
== self
->topresize
) return OB_FRAME_CONTEXT_TOP
;
1497 if (win
== self
->tltresize
) return OB_FRAME_CONTEXT_TLCORNER
;
1498 if (win
== self
->tllresize
) return OB_FRAME_CONTEXT_TLCORNER
;
1499 if (win
== self
->trtresize
) return OB_FRAME_CONTEXT_TRCORNER
;
1500 if (win
== self
->trrresize
) return OB_FRAME_CONTEXT_TRCORNER
;
1501 if (win
== self
->left
) return OB_FRAME_CONTEXT_LEFT
;
1502 if (win
== self
->right
) return OB_FRAME_CONTEXT_RIGHT
;
1503 if (win
== self
->innertop
) return OB_FRAME_CONTEXT_TITLEBAR
;
1504 if (win
== self
->innerleft
) return OB_FRAME_CONTEXT_LEFT
;
1505 if (win
== self
->innerbottom
) return OB_FRAME_CONTEXT_BOTTOM
;
1506 if (win
== self
->innerright
) return OB_FRAME_CONTEXT_RIGHT
;
1507 if (win
== self
->innerbll
) return OB_FRAME_CONTEXT_BLCORNER
;
1508 if (win
== self
->innerblb
) return OB_FRAME_CONTEXT_BLCORNER
;
1509 if (win
== self
->innerbrr
) return OB_FRAME_CONTEXT_BRCORNER
;
1510 if (win
== self
->innerbrb
) return OB_FRAME_CONTEXT_BRCORNER
;
1511 if (win
== self
->max
) return OB_FRAME_CONTEXT_MAXIMIZE
;
1512 if (win
== self
->iconify
) return OB_FRAME_CONTEXT_ICONIFY
;
1513 if (win
== self
->close
) return OB_FRAME_CONTEXT_CLOSE
;
1514 if (win
== self
->icon
) return OB_FRAME_CONTEXT_ICON
;
1515 if (win
== self
->desk
) return OB_FRAME_CONTEXT_ALLDESKTOPS
;
1516 if (win
== self
->shade
) return OB_FRAME_CONTEXT_SHADE
;
1518 return OB_FRAME_CONTEXT_NONE
;
1521 void frame_client_gravity(ObFrame
*self
, gint
*x
, gint
*y
)
1524 switch (self
->client
->gravity
) {
1526 case NorthWestGravity
:
1527 case SouthWestGravity
:
1534 /* the middle of the client will be the middle of the frame */
1535 *x
-= (self
->size
.right
- self
->size
.left
) / 2;
1538 case NorthEastGravity
:
1539 case SouthEastGravity
:
1541 /* the right side of the client will be the right side of the frame */
1542 *x
-= self
->size
.right
+ self
->size
.left
-
1543 self
->client
->border_width
* 2;
1548 /* the client's position won't move */
1549 *x
-= self
->size
.left
- self
->client
->border_width
;
1554 switch (self
->client
->gravity
) {
1556 case NorthWestGravity
:
1557 case NorthEastGravity
:
1564 /* the middle of the client will be the middle of the frame */
1565 *y
-= (self
->size
.bottom
- self
->size
.top
) / 2;
1568 case SouthWestGravity
:
1569 case SouthEastGravity
:
1571 /* the bottom of the client will be the bottom of the frame */
1572 *y
-= self
->size
.bottom
+ self
->size
.top
-
1573 self
->client
->border_width
* 2;
1578 /* the client's position won't move */
1579 *y
-= self
->size
.top
- self
->client
->border_width
;
1584 void frame_frame_gravity(ObFrame
*self
, gint
*x
, gint
*y
)
1587 switch (self
->client
->gravity
) {
1589 case NorthWestGravity
:
1591 case SouthWestGravity
:
1596 /* the middle of the client will be the middle of the frame */
1597 *x
+= (self
->size
.right
- self
->size
.left
) / 2;
1599 case NorthEastGravity
:
1601 case SouthEastGravity
:
1602 /* the right side of the client will be the right side of the frame */
1603 *x
+= self
->size
.right
+ self
->size
.left
-
1604 self
->client
->border_width
* 2;
1608 /* the client's position won't move */
1609 *x
+= self
->size
.left
- self
->client
->border_width
;
1614 switch (self
->client
->gravity
) {
1616 case NorthWestGravity
:
1618 case NorthEastGravity
:
1623 /* the middle of the client will be the middle of the frame */
1624 *y
+= (self
->size
.bottom
- self
->size
.top
) / 2;
1626 case SouthWestGravity
:
1628 case SouthEastGravity
:
1629 /* the bottom of the client will be the bottom of the frame */
1630 *y
+= self
->size
.bottom
+ self
->size
.top
-
1631 self
->client
->border_width
* 2;
1635 /* the client's position won't move */
1636 *y
+= self
->size
.top
- self
->client
->border_width
;
1641 void frame_rect_to_frame(ObFrame
*self
, Rect
*r
)
1643 r
->width
+= self
->size
.left
+ self
->size
.right
;
1644 r
->height
+= self
->size
.top
+ self
->size
.bottom
;
1645 frame_client_gravity(self
, &r
->x
, &r
->y
);
1648 void frame_rect_to_client(ObFrame
*self
, Rect
*r
)
1650 r
->width
-= self
->size
.left
+ self
->size
.right
;
1651 r
->height
-= self
->size
.top
+ self
->size
.bottom
;
1652 frame_frame_gravity(self
, &r
->x
, &r
->y
);
1655 static void flash_done(gpointer data
)
1657 ObFrame
*self
= data
;
1659 if (self
->focused
!= self
->flash_on
)
1660 frame_adjust_focus(self
, self
->focused
);
1663 static gboolean
flash_timeout(gpointer data
)
1665 ObFrame
*self
= data
;
1668 if (config_frame_flash_duration
!= 0) {
1669 g_get_current_time(&now
);
1670 if (now
.tv_sec
> self
->flash_end
.tv_sec
||
1671 (now
.tv_sec
== self
->flash_end
.tv_sec
&&
1672 now
.tv_usec
>= self
->flash_end
.tv_usec
))
1673 self
->flashing
= FALSE
;
1676 if (!self
->flashing
)
1677 return FALSE
; /* we are done */
1679 self
->flash_on
= !self
->flash_on
;
1680 if (!self
->focused
) {
1681 frame_adjust_focus(self
, self
->flash_on
);
1682 self
->focused
= FALSE
;
1685 return TRUE
; /* go again */
1688 void frame_flash_start(ObFrame
*self
)
1690 if (config_frame_flash_delay
== 0) return;
1692 self
->flash_on
= self
->focused
;
1694 if (!self
->flashing
)
1695 self
->flash_timer
= g_timeout_add_full(G_PRIORITY_DEFAULT
,
1696 config_frame_flash_delay
, flash_timeout
, self
,
1699 if (config_frame_flash_duration
!= 0) {
1700 g_get_current_time(&self
->flash_end
);
1701 g_time_val_add(&self
->flash_end
, 1000 * config_frame_flash_duration
);
1704 self
->flashing
= TRUE
;
1707 void frame_flash_stop(ObFrame
*self
)
1709 self
->flashing
= FALSE
;
1712 static gulong
frame_animate_iconify_time_left(ObFrame
*self
,
1713 const GTimeVal
*now
)
1716 sec
= self
->iconify_animation_end
.tv_sec
- now
->tv_sec
;
1717 usec
= self
->iconify_animation_end
.tv_usec
- now
->tv_usec
;
1719 usec
+= G_USEC_PER_SEC
;
1722 /* no negative values */
1723 return MAX(sec
* G_USEC_PER_SEC
+ usec
, 0);
1726 static gboolean
frame_animate_iconify(gpointer p
)
1730 gint iconx
, icony
, iconw
;
1733 gboolean iconifying
;
1735 if (self
->client
->icon_geometry
.width
== 0) {
1736 /* there is no icon geometry set so just go straight down */
1739 a
= screen_physical_area_monitor(screen_find_monitor(&self
->area
));
1740 iconx
= self
->area
.x
+ self
->area
.width
/ 2 + 32;
1741 icony
= a
->y
+ a
->width
;
1744 iconx
= self
->client
->icon_geometry
.x
;
1745 icony
= self
->client
->icon_geometry
.y
;
1746 iconw
= self
->client
->icon_geometry
.width
;
1749 iconifying
= self
->iconify_animation_going
> 0;
1751 /* how far do we have left to go ? */
1752 g_get_current_time(&now
);
1753 time
= frame_animate_iconify_time_left(self
, &now
);
1755 if ((time
> 0 && iconifying
) || (time
== 0 && !iconifying
)) {
1756 /* start where the frame is supposed to be */
1759 w
= self
->area
.width
;
1760 h
= self
->area
.height
;
1762 /* start at the icon */
1766 h
= self
->size
.top
; /* just the titlebar */
1773 dx
= self
->area
.x
- iconx
;
1774 dy
= self
->area
.y
- icony
;
1775 dw
= self
->area
.width
- self
->bwidth
* 2 - iconw
;
1776 /* if restoring, we move in the opposite direction */
1777 if (!iconifying
) { dx
= -dx
; dy
= -dy
; dw
= -dw
; }
1779 elapsed
= FRAME_ANIMATE_ICONIFY_TIME
- time
;
1780 x
= x
- (dx
* elapsed
) / FRAME_ANIMATE_ICONIFY_TIME
;
1781 y
= y
- (dy
* elapsed
) / FRAME_ANIMATE_ICONIFY_TIME
;
1782 w
= w
- (dw
* elapsed
) / FRAME_ANIMATE_ICONIFY_TIME
;
1783 h
= self
->size
.top
; /* just the titlebar */
1786 XMoveResizeWindow(obt_display
, self
->window
, x
, y
, w
, h
);
1787 XFlush(obt_display
);
1790 frame_end_iconify_animation(self
);
1792 return time
> 0; /* repeat until we're out of time */
1795 void frame_end_iconify_animation(ObFrame
*self
)
1797 /* see if there is an animation going */
1798 if (self
->iconify_animation_going
== 0) return;
1801 XUnmapWindow(obt_display
, self
->window
);
1803 /* Send a ConfigureNotify when the animation is done, this fixes
1804 KDE's pager showing the window in the wrong place. since the
1805 window is mapped at a different location and is then moved, we
1806 need to send the synthetic configurenotify, since apps may have
1807 read the position when the client mapped, apparently. */
1808 client_reconfigure(self
->client
, TRUE
);
1811 /* we're not animating any more ! */
1812 self
->iconify_animation_going
= 0;
1814 XMoveResizeWindow(obt_display
, self
->window
,
1815 self
->area
.x
, self
->area
.y
,
1816 self
->area
.width
, self
->area
.height
);
1817 /* we delay re-rendering until after we're done animating */
1818 framerender_frame(self
);
1819 XFlush(obt_display
);
1822 void frame_begin_iconify_animation(ObFrame
*self
, gboolean iconifying
)
1825 gboolean new_anim
= FALSE
;
1826 gboolean set_end
= TRUE
;
1829 /* if there is no titlebar, just don't animate for now
1830 XXX it would be nice tho.. */
1831 if (!(self
->decorations
& OB_FRAME_DECOR_TITLEBAR
))
1834 /* get the current time */
1835 g_get_current_time(&now
);
1837 /* get how long until the end */
1838 time
= FRAME_ANIMATE_ICONIFY_TIME
;
1839 if (self
->iconify_animation_going
) {
1840 if (!!iconifying
!= (self
->iconify_animation_going
> 0)) {
1841 /* animation was already going on in the opposite direction */
1842 time
= time
- frame_animate_iconify_time_left(self
, &now
);
1844 /* animation was already going in the same direction */
1848 self
->iconify_animation_going
= iconifying
? 1 : -1;
1850 /* set the ending time */
1852 self
->iconify_animation_end
.tv_sec
= now
.tv_sec
;
1853 self
->iconify_animation_end
.tv_usec
= now
.tv_usec
;
1854 g_time_val_add(&self
->iconify_animation_end
, time
);
1858 if (self
->iconify_animation_timer
)
1859 g_source_remove(self
->iconify_animation_timer
);
1860 self
->iconify_animation_timer
=
1861 g_timeout_add_full(G_PRIORITY_DEFAULT
,
1862 FRAME_ANIMATE_ICONIFY_STEP_TIME
,
1863 frame_animate_iconify
, self
, NULL
);
1866 /* do the first step */
1867 frame_animate_iconify(self
);
1869 /* show it during the animation even if it is not "visible" */
1871 XMapWindow(obt_display
, self
->window
);