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),
382 (!self
->max_horz
|| !self
->max_vert
? self
->bwidth
: 0),
383 self
->cbwidth_r
+ (!self
->max_horz
? self
->bwidth
: 0),
385 (!self
->max_horz
|| !self
->max_vert
? self
->bwidth
: 0));
387 if (self
->decorations
& OB_FRAME_DECOR_TITLEBAR
)
388 self
->size
.top
+= ob_rr_theme
->title_height
+ self
->bwidth
;
389 else if (self
->max_horz
&& self
->max_vert
) {
390 /* A maximized and undecorated window needs a border on the
391 top of the window to let the user still undecorate/unmaximize the
392 window via the client menu. */
393 self
->size
.top
+= self
->bwidth
;
396 if (self
->decorations
& OB_FRAME_DECOR_HANDLE
&&
397 ob_rr_theme
->handle_height
> 0)
399 self
->size
.bottom
+= ob_rr_theme
->handle_height
+ self
->bwidth
;
402 /* position/size and map/unmap all the windows */
405 gint innercornerheight
=
406 ob_rr_theme
->grip_width
- self
->size
.bottom
;
408 if (self
->cbwidth_l
) {
409 XMoveResizeWindow(obt_display
, self
->innerleft
,
410 self
->size
.left
- self
->cbwidth_l
,
412 self
->cbwidth_l
, self
->client
->area
.height
);
414 XMapWindow(obt_display
, self
->innerleft
);
416 XUnmapWindow(obt_display
, self
->innerleft
);
418 if (self
->cbwidth_l
&& innercornerheight
> 0) {
419 XMoveResizeWindow(obt_display
, self
->innerbll
,
421 self
->client
->area
.height
-
422 (ob_rr_theme
->grip_width
-
425 ob_rr_theme
->grip_width
- self
->size
.bottom
);
427 XMapWindow(obt_display
, self
->innerbll
);
429 XUnmapWindow(obt_display
, self
->innerbll
);
431 if (self
->cbwidth_r
) {
432 XMoveResizeWindow(obt_display
, self
->innerright
,
433 self
->size
.left
+ self
->client
->area
.width
,
435 self
->cbwidth_r
, self
->client
->area
.height
);
437 XMapWindow(obt_display
, self
->innerright
);
439 XUnmapWindow(obt_display
, self
->innerright
);
441 if (self
->cbwidth_r
&& innercornerheight
> 0) {
442 XMoveResizeWindow(obt_display
, self
->innerbrr
,
444 self
->client
->area
.height
-
445 (ob_rr_theme
->grip_width
-
448 ob_rr_theme
->grip_width
- self
->size
.bottom
);
450 XMapWindow(obt_display
, self
->innerbrr
);
452 XUnmapWindow(obt_display
, self
->innerbrr
);
454 if (self
->cbwidth_t
) {
455 XMoveResizeWindow(obt_display
, self
->innertop
,
456 self
->size
.left
- self
->cbwidth_l
,
457 self
->size
.top
- self
->cbwidth_t
,
458 self
->client
->area
.width
+
459 self
->cbwidth_l
+ self
->cbwidth_r
,
462 XMapWindow(obt_display
, self
->innertop
);
464 XUnmapWindow(obt_display
, self
->innertop
);
466 if (self
->cbwidth_b
) {
467 XMoveResizeWindow(obt_display
, self
->innerbottom
,
468 self
->size
.left
- self
->cbwidth_l
,
469 self
->size
.top
+ self
->client
->area
.height
,
470 self
->client
->area
.width
+
471 self
->cbwidth_l
+ self
->cbwidth_r
,
474 XMoveResizeWindow(obt_display
, self
->innerblb
,
476 ob_rr_theme
->grip_width
+ self
->bwidth
,
478 XMoveResizeWindow(obt_display
, self
->innerbrb
,
479 self
->client
->area
.width
+
480 self
->cbwidth_l
+ self
->cbwidth_r
-
481 (ob_rr_theme
->grip_width
+ self
->bwidth
),
483 ob_rr_theme
->grip_width
+ self
->bwidth
,
486 XMapWindow(obt_display
, self
->innerbottom
);
487 XMapWindow(obt_display
, self
->innerblb
);
488 XMapWindow(obt_display
, self
->innerbrb
);
490 XUnmapWindow(obt_display
, self
->innerbottom
);
491 XUnmapWindow(obt_display
, self
->innerblb
);
492 XUnmapWindow(obt_display
, self
->innerbrb
);
498 /* height of titleleft and titleright */
499 titlesides
= (!self
->max_horz
? ob_rr_theme
->grip_width
: 0);
501 XMoveResizeWindow(obt_display
, self
->titletop
,
502 ob_rr_theme
->grip_width
+ self
->bwidth
, 0,
503 /* width + bwidth*2 - bwidth*2 - grips*2 */
504 self
->width
- ob_rr_theme
->grip_width
* 2,
506 XMoveResizeWindow(obt_display
, self
->titletopleft
,
508 ob_rr_theme
->grip_width
+ self
->bwidth
,
510 XMoveResizeWindow(obt_display
, self
->titletopright
,
511 self
->client
->area
.width
+
512 self
->size
.left
+ self
->size
.right
-
513 ob_rr_theme
->grip_width
- self
->bwidth
,
515 ob_rr_theme
->grip_width
+ self
->bwidth
,
518 if (titlesides
> 0) {
519 XMoveResizeWindow(obt_display
, self
->titleleft
,
523 XMoveResizeWindow(obt_display
, self
->titleright
,
524 self
->client
->area
.width
+
525 self
->size
.left
+ self
->size
.right
-
531 XMapWindow(obt_display
, self
->titleleft
);
532 XMapWindow(obt_display
, self
->titleright
);
534 XUnmapWindow(obt_display
, self
->titleleft
);
535 XUnmapWindow(obt_display
, self
->titleright
);
538 XMapWindow(obt_display
, self
->titletop
);
539 XMapWindow(obt_display
, self
->titletopleft
);
540 XMapWindow(obt_display
, self
->titletopright
);
542 if (self
->decorations
& OB_FRAME_DECOR_TITLEBAR
) {
543 XMoveResizeWindow(obt_display
, self
->titlebottom
,
544 (self
->max_horz
? 0 : self
->bwidth
),
545 ob_rr_theme
->title_height
+ self
->bwidth
,
549 XMapWindow(obt_display
, self
->titlebottom
);
551 XUnmapWindow(obt_display
, self
->titlebottom
);
553 XUnmapWindow(obt_display
, self
->titlebottom
);
555 XUnmapWindow(obt_display
, self
->titletop
);
556 XUnmapWindow(obt_display
, self
->titletopleft
);
557 XUnmapWindow(obt_display
, self
->titletopright
);
558 XUnmapWindow(obt_display
, self
->titleleft
);
559 XUnmapWindow(obt_display
, self
->titleright
);
562 if (self
->decorations
& OB_FRAME_DECOR_TITLEBAR
) {
563 XMoveResizeWindow(obt_display
, self
->title
,
564 (self
->max_horz
? 0 : self
->bwidth
),
566 self
->width
, ob_rr_theme
->title_height
);
568 XMapWindow(obt_display
, self
->title
);
570 if (self
->decorations
& OB_FRAME_DECOR_GRIPS
) {
571 XMoveResizeWindow(obt_display
, self
->topresize
,
572 ob_rr_theme
->grip_width
,
574 self
->width
- ob_rr_theme
->grip_width
*2,
575 ob_rr_theme
->paddingy
+ 1);
577 XMoveWindow(obt_display
, self
->tltresize
, 0, 0);
578 XMoveWindow(obt_display
, self
->tllresize
, 0, 0);
579 XMoveWindow(obt_display
, self
->trtresize
,
580 self
->width
- ob_rr_theme
->grip_width
, 0);
581 XMoveWindow(obt_display
, self
->trrresize
,
582 self
->width
- ob_rr_theme
->paddingx
- 1, 0);
584 XMapWindow(obt_display
, self
->topresize
);
585 XMapWindow(obt_display
, self
->tltresize
);
586 XMapWindow(obt_display
, self
->tllresize
);
587 XMapWindow(obt_display
, self
->trtresize
);
588 XMapWindow(obt_display
, self
->trrresize
);
590 XUnmapWindow(obt_display
, self
->topresize
);
591 XUnmapWindow(obt_display
, self
->tltresize
);
592 XUnmapWindow(obt_display
, self
->tllresize
);
593 XUnmapWindow(obt_display
, self
->trtresize
);
594 XUnmapWindow(obt_display
, self
->trrresize
);
597 XUnmapWindow(obt_display
, self
->title
);
600 if ((self
->decorations
& OB_FRAME_DECOR_TITLEBAR
))
601 /* layout the title bar elements */
605 gint sidebwidth
= self
->max_horz
? 0 : self
->bwidth
;
607 if (self
->bwidth
&& self
->size
.bottom
) {
608 XMoveResizeWindow(obt_display
, self
->handlebottom
,
609 ob_rr_theme
->grip_width
+
610 self
->bwidth
+ sidebwidth
,
611 self
->size
.top
+ self
->client
->area
.height
+
612 self
->size
.bottom
- self
->bwidth
,
613 self
->width
- (ob_rr_theme
->grip_width
+
619 XMoveResizeWindow(obt_display
, self
->lgripleft
,
622 self
->client
->area
.height
+
625 ob_rr_theme
->grip_width
:
626 self
->size
.bottom
- self
->cbwidth_b
),
629 ob_rr_theme
->grip_width
:
630 self
->size
.bottom
- self
->cbwidth_b
));
631 XMoveResizeWindow(obt_display
, self
->rgripright
,
633 self
->client
->area
.width
+
634 self
->size
.right
- self
->bwidth
,
636 self
->client
->area
.height
+
639 ob_rr_theme
->grip_width
:
640 self
->size
.bottom
- self
->cbwidth_b
),
643 ob_rr_theme
->grip_width
:
644 self
->size
.bottom
- self
->cbwidth_b
));
646 XMapWindow(obt_display
, self
->lgripleft
);
647 XMapWindow(obt_display
, self
->rgripright
);
649 XUnmapWindow(obt_display
, self
->lgripleft
);
650 XUnmapWindow(obt_display
, self
->rgripright
);
653 XMoveResizeWindow(obt_display
, self
->lgripbottom
,
655 self
->size
.top
+ self
->client
->area
.height
+
656 self
->size
.bottom
- self
->bwidth
,
657 ob_rr_theme
->grip_width
+ self
->bwidth
,
659 XMoveResizeWindow(obt_display
, self
->rgripbottom
,
660 self
->size
.left
+ self
->client
->area
.width
+
661 self
->size
.right
- self
->bwidth
- sidebwidth
-
662 ob_rr_theme
->grip_width
,
663 self
->size
.top
+ self
->client
->area
.height
+
664 self
->size
.bottom
- self
->bwidth
,
665 ob_rr_theme
->grip_width
+ self
->bwidth
,
668 XMapWindow(obt_display
, self
->handlebottom
);
669 XMapWindow(obt_display
, self
->lgripbottom
);
670 XMapWindow(obt_display
, self
->rgripbottom
);
672 if (self
->decorations
& OB_FRAME_DECOR_HANDLE
&&
673 ob_rr_theme
->handle_height
> 0)
675 XMoveResizeWindow(obt_display
, self
->handletop
,
676 ob_rr_theme
->grip_width
+
677 self
->bwidth
+ sidebwidth
,
678 FRAME_HANDLE_Y(self
),
679 self
->width
- (ob_rr_theme
->grip_width
+
682 XMapWindow(obt_display
, self
->handletop
);
684 if (self
->decorations
& OB_FRAME_DECOR_GRIPS
) {
685 XMoveResizeWindow(obt_display
, self
->handleleft
,
686 ob_rr_theme
->grip_width
,
689 ob_rr_theme
->handle_height
);
690 XMoveResizeWindow(obt_display
, self
->handleright
,
692 ob_rr_theme
->grip_width
-
696 ob_rr_theme
->handle_height
);
698 XMoveResizeWindow(obt_display
, self
->lgriptop
,
700 FRAME_HANDLE_Y(self
),
701 ob_rr_theme
->grip_width
+
704 XMoveResizeWindow(obt_display
, self
->rgriptop
,
706 self
->client
->area
.width
+
707 self
->size
.right
- self
->bwidth
-
708 sidebwidth
- ob_rr_theme
->grip_width
,
709 FRAME_HANDLE_Y(self
),
710 ob_rr_theme
->grip_width
+
714 XMapWindow(obt_display
, self
->handleleft
);
715 XMapWindow(obt_display
, self
->handleright
);
716 XMapWindow(obt_display
, self
->lgriptop
);
717 XMapWindow(obt_display
, self
->rgriptop
);
719 XUnmapWindow(obt_display
, self
->handleleft
);
720 XUnmapWindow(obt_display
, self
->handleright
);
721 XUnmapWindow(obt_display
, self
->lgriptop
);
722 XUnmapWindow(obt_display
, self
->rgriptop
);
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
);
733 XUnmapWindow(obt_display
, self
->handleleft
);
734 XUnmapWindow(obt_display
, self
->handleright
);
735 XUnmapWindow(obt_display
, self
->lgriptop
);
736 XUnmapWindow(obt_display
, self
->rgriptop
);
738 XUnmapWindow(obt_display
, self
->handletop
);
740 XUnmapWindow(obt_display
, self
->handlebottom
);
741 XUnmapWindow(obt_display
, self
->lgripleft
);
742 XUnmapWindow(obt_display
, self
->rgripright
);
743 XUnmapWindow(obt_display
, self
->lgripbottom
);
744 XUnmapWindow(obt_display
, self
->rgripbottom
);
747 if (self
->decorations
& OB_FRAME_DECOR_HANDLE
&&
748 ob_rr_theme
->handle_height
> 0)
750 XMoveResizeWindow(obt_display
, self
->handle
,
752 FRAME_HANDLE_Y(self
) + self
->bwidth
,
753 self
->width
, ob_rr_theme
->handle_height
);
754 XMapWindow(obt_display
, self
->handle
);
756 if (self
->decorations
& OB_FRAME_DECOR_GRIPS
) {
757 XMoveResizeWindow(obt_display
, self
->lgrip
,
759 ob_rr_theme
->grip_width
,
760 ob_rr_theme
->handle_height
);
761 XMoveResizeWindow(obt_display
, self
->rgrip
,
762 self
->width
- ob_rr_theme
->grip_width
,
764 ob_rr_theme
->grip_width
,
765 ob_rr_theme
->handle_height
);
767 XMapWindow(obt_display
, self
->lgrip
);
768 XMapWindow(obt_display
, self
->rgrip
);
770 XUnmapWindow(obt_display
, self
->lgrip
);
771 XUnmapWindow(obt_display
, self
->rgrip
);
774 XUnmapWindow(obt_display
, self
->lgrip
);
775 XUnmapWindow(obt_display
, self
->rgrip
);
777 XUnmapWindow(obt_display
, self
->handle
);
780 if (self
->bwidth
&& !self
->max_horz
&&
781 (self
->client
->area
.height
+ self
->size
.top
+
782 self
->size
.bottom
) > ob_rr_theme
->grip_width
* 2)
784 XMoveResizeWindow(obt_display
, self
->left
,
786 self
->bwidth
+ ob_rr_theme
->grip_width
,
788 self
->client
->area
.height
+
789 self
->size
.top
+ self
->size
.bottom
-
790 ob_rr_theme
->grip_width
* 2);
792 XMapWindow(obt_display
, self
->left
);
794 XUnmapWindow(obt_display
, self
->left
);
796 if (self
->bwidth
&& !self
->max_horz
&&
797 (self
->client
->area
.height
+ self
->size
.top
+
798 self
->size
.bottom
) > ob_rr_theme
->grip_width
* 2)
800 XMoveResizeWindow(obt_display
, self
->right
,
801 self
->client
->area
.width
+ self
->cbwidth_l
+
802 self
->cbwidth_r
+ self
->bwidth
,
803 self
->bwidth
+ ob_rr_theme
->grip_width
,
805 self
->client
->area
.height
+
806 self
->size
.top
+ self
->size
.bottom
-
807 ob_rr_theme
->grip_width
* 2);
809 XMapWindow(obt_display
, self
->right
);
811 XUnmapWindow(obt_display
, self
->right
);
813 XMoveResizeWindow(obt_display
, self
->backback
,
814 self
->size
.left
, self
->size
.top
,
815 self
->client
->area
.width
,
816 self
->client
->area
.height
);
820 /* shading can change without being moved or resized */
821 RECT_SET_SIZE(self
->area
,
822 self
->client
->area
.width
+
823 self
->size
.left
+ self
->size
.right
,
824 (self
->client
->shaded
?
825 ob_rr_theme
->title_height
+ self
->bwidth
* 2:
826 self
->client
->area
.height
+
827 self
->size
.top
+ self
->size
.bottom
));
829 if ((moved
|| resized
) && !fake
) {
830 /* find the new coordinates, done after setting the frame.size, for
831 frame_client_gravity. */
832 self
->area
.x
= self
->client
->area
.x
;
833 self
->area
.y
= self
->client
->area
.y
;
834 frame_client_gravity(self
, &self
->area
.x
, &self
->area
.y
);
838 if (!frame_iconify_animating(self
))
839 /* move and resize the top level frame.
840 shading can change without being moved or resized.
842 but don't do this during an iconify animation. it will be
843 reflected afterwards.
845 XMoveResizeWindow(obt_display
, self
->window
,
851 /* when the client has StaticGravity, it likes to move around.
852 also this correctly positions the client when it maps.
853 this also needs to be run when the frame's decorations sizes change!
855 XMoveWindow(obt_display
, self
->client
->window
,
856 self
->size
.left
, self
->size
.top
);
859 self
->need_render
= TRUE
;
860 framerender_frame(self
);
861 frame_adjust_shape(self
);
864 if (!STRUT_EQUAL(self
->size
, self
->oldsize
)) {
866 vals
[0] = self
->size
.left
;
867 vals
[1] = self
->size
.right
;
868 vals
[2] = self
->size
.top
;
869 vals
[3] = self
->size
.bottom
;
870 OBT_PROP_SETA32(self
->client
->window
, NET_FRAME_EXTENTS
,
872 OBT_PROP_SETA32(self
->client
->window
, KDE_NET_WM_FRAME_STRUT
,
874 self
->oldsize
= self
->size
;
877 /* if this occurs while we are focus cycling, the indicator needs to
879 if (focus_cycle_target
== self
->client
)
880 focus_cycle_update_indicator(self
->client
);
882 if (resized
&& (self
->decorations
& OB_FRAME_DECOR_TITLEBAR
) &&
885 XResizeWindow(obt_display
, self
->label
, self
->label_width
,
886 ob_rr_theme
->label_height
);
890 static void frame_adjust_cursors(ObFrame
*self
)
892 if ((self
->functions
& OB_CLIENT_FUNC_RESIZE
) !=
893 (self
->client
->functions
& OB_CLIENT_FUNC_RESIZE
) ||
894 self
->max_horz
!= self
->client
->max_horz
||
895 self
->max_vert
!= self
->client
->max_vert
||
896 self
->shaded
!= self
->client
->shaded
)
898 gboolean r
= (self
->client
->functions
& OB_CLIENT_FUNC_RESIZE
) &&
899 !(self
->client
->max_horz
&& self
->client
->max_vert
);
900 gboolean topbot
= !self
->client
->max_vert
;
901 gboolean sh
= self
->client
->shaded
;
902 XSetWindowAttributes a
;
904 /* these ones turn off when max vert, and some when shaded */
905 a
.cursor
= ob_cursor(r
&& topbot
&& !sh
?
906 OB_CURSOR_NORTH
: OB_CURSOR_NONE
);
907 XChangeWindowAttributes(obt_display
, self
->topresize
, CWCursor
, &a
);
908 XChangeWindowAttributes(obt_display
, self
->titletop
, CWCursor
, &a
);
909 a
.cursor
= ob_cursor(r
&& topbot
? OB_CURSOR_SOUTH
: OB_CURSOR_NONE
);
910 XChangeWindowAttributes(obt_display
, self
->handle
, CWCursor
, &a
);
911 XChangeWindowAttributes(obt_display
, self
->handletop
, CWCursor
, &a
);
912 XChangeWindowAttributes(obt_display
, self
->handlebottom
, CWCursor
, &a
);
913 XChangeWindowAttributes(obt_display
, self
->innerbottom
, CWCursor
, &a
);
915 /* these ones change when shaded */
916 a
.cursor
= ob_cursor(r
? (sh
? OB_CURSOR_WEST
: OB_CURSOR_NORTHWEST
) :
918 XChangeWindowAttributes(obt_display
, self
->titleleft
, CWCursor
, &a
);
919 XChangeWindowAttributes(obt_display
, self
->tltresize
, CWCursor
, &a
);
920 XChangeWindowAttributes(obt_display
, self
->tllresize
, CWCursor
, &a
);
921 XChangeWindowAttributes(obt_display
, self
->titletopleft
, CWCursor
, &a
);
922 a
.cursor
= ob_cursor(r
? (sh
? OB_CURSOR_EAST
: OB_CURSOR_NORTHEAST
) :
924 XChangeWindowAttributes(obt_display
, self
->titleright
, CWCursor
, &a
);
925 XChangeWindowAttributes(obt_display
, self
->trtresize
, CWCursor
, &a
);
926 XChangeWindowAttributes(obt_display
, self
->trrresize
, CWCursor
, &a
);
927 XChangeWindowAttributes(obt_display
, self
->titletopright
, CWCursor
,&a
);
929 /* these ones are pretty static */
930 a
.cursor
= ob_cursor(r
? OB_CURSOR_WEST
: OB_CURSOR_NONE
);
931 XChangeWindowAttributes(obt_display
, self
->left
, CWCursor
, &a
);
932 XChangeWindowAttributes(obt_display
, self
->innerleft
, CWCursor
, &a
);
933 a
.cursor
= ob_cursor(r
? OB_CURSOR_EAST
: OB_CURSOR_NONE
);
934 XChangeWindowAttributes(obt_display
, self
->right
, CWCursor
, &a
);
935 XChangeWindowAttributes(obt_display
, self
->innerright
, CWCursor
, &a
);
936 a
.cursor
= ob_cursor(r
? OB_CURSOR_SOUTHWEST
: OB_CURSOR_NONE
);
937 XChangeWindowAttributes(obt_display
, self
->lgrip
, CWCursor
, &a
);
938 XChangeWindowAttributes(obt_display
, self
->handleleft
, CWCursor
, &a
);
939 XChangeWindowAttributes(obt_display
, self
->lgripleft
, CWCursor
, &a
);
940 XChangeWindowAttributes(obt_display
, self
->lgriptop
, CWCursor
, &a
);
941 XChangeWindowAttributes(obt_display
, self
->lgripbottom
, CWCursor
, &a
);
942 XChangeWindowAttributes(obt_display
, self
->innerbll
, CWCursor
, &a
);
943 XChangeWindowAttributes(obt_display
, self
->innerblb
, CWCursor
, &a
);
944 a
.cursor
= ob_cursor(r
? OB_CURSOR_SOUTHEAST
: OB_CURSOR_NONE
);
945 XChangeWindowAttributes(obt_display
, self
->rgrip
, CWCursor
, &a
);
946 XChangeWindowAttributes(obt_display
, self
->handleright
, CWCursor
, &a
);
947 XChangeWindowAttributes(obt_display
, self
->rgripright
, CWCursor
, &a
);
948 XChangeWindowAttributes(obt_display
, self
->rgriptop
, CWCursor
, &a
);
949 XChangeWindowAttributes(obt_display
, self
->rgripbottom
, CWCursor
, &a
);
950 XChangeWindowAttributes(obt_display
, self
->innerbrr
, CWCursor
, &a
);
951 XChangeWindowAttributes(obt_display
, self
->innerbrb
, CWCursor
, &a
);
955 void frame_adjust_client_area(ObFrame
*self
)
957 /* adjust the window which is there to prevent flashing on unmap */
958 XMoveResizeWindow(obt_display
, self
->backfront
, 0, 0,
959 self
->client
->area
.width
,
960 self
->client
->area
.height
);
963 void frame_adjust_state(ObFrame
*self
)
965 self
->need_render
= TRUE
;
966 framerender_frame(self
);
969 void frame_adjust_focus(ObFrame
*self
, gboolean hilite
)
971 ob_debug_type(OB_DEBUG_FOCUS
,
972 "Frame for 0x%x has focus: %d",
973 self
->client
->window
, hilite
);
974 self
->focused
= hilite
;
975 self
->need_render
= TRUE
;
976 framerender_frame(self
);
980 void frame_adjust_title(ObFrame
*self
)
982 self
->need_render
= TRUE
;
983 framerender_frame(self
);
986 void frame_adjust_icon(ObFrame
*self
)
988 self
->need_render
= TRUE
;
989 framerender_frame(self
);
992 void frame_grab_client(ObFrame
*self
)
994 /* DO NOT map the client window here. we used to do that, but it is bogus.
995 we need to set up the client's dimensions and everything before we
996 send a mapnotify or we create race conditions.
999 /* reparent the client to the frame */
1000 XReparentWindow(obt_display
, self
->client
->window
, self
->window
, 0, 0);
1003 When reparenting the client window, it is usually not mapped yet, since
1004 this occurs from a MapRequest. However, in the case where Openbox is
1005 starting up, the window is already mapped, so we'll see an unmap event
1008 if (ob_state() == OB_STATE_STARTING
)
1009 ++self
->client
->ignore_unmaps
;
1011 /* select the event mask on the client's parent (to receive config/map
1012 req's) the ButtonPress is to catch clicks on the client border */
1013 XSelectInput(obt_display
, self
->window
, FRAME_EVENTMASK
);
1015 /* set all the windows for the frame in the window_map */
1016 window_add(&self
->window
, CLIENT_AS_WINDOW(self
->client
));
1017 window_add(&self
->backback
, CLIENT_AS_WINDOW(self
->client
));
1018 window_add(&self
->backfront
, CLIENT_AS_WINDOW(self
->client
));
1019 window_add(&self
->innerleft
, CLIENT_AS_WINDOW(self
->client
));
1020 window_add(&self
->innertop
, CLIENT_AS_WINDOW(self
->client
));
1021 window_add(&self
->innerright
, CLIENT_AS_WINDOW(self
->client
));
1022 window_add(&self
->innerbottom
, CLIENT_AS_WINDOW(self
->client
));
1023 window_add(&self
->innerblb
, CLIENT_AS_WINDOW(self
->client
));
1024 window_add(&self
->innerbll
, CLIENT_AS_WINDOW(self
->client
));
1025 window_add(&self
->innerbrb
, CLIENT_AS_WINDOW(self
->client
));
1026 window_add(&self
->innerbrr
, CLIENT_AS_WINDOW(self
->client
));
1027 window_add(&self
->title
, CLIENT_AS_WINDOW(self
->client
));
1028 window_add(&self
->label
, CLIENT_AS_WINDOW(self
->client
));
1029 window_add(&self
->max
, CLIENT_AS_WINDOW(self
->client
));
1030 window_add(&self
->close
, CLIENT_AS_WINDOW(self
->client
));
1031 window_add(&self
->desk
, CLIENT_AS_WINDOW(self
->client
));
1032 window_add(&self
->shade
, CLIENT_AS_WINDOW(self
->client
));
1033 window_add(&self
->icon
, CLIENT_AS_WINDOW(self
->client
));
1034 window_add(&self
->iconify
, CLIENT_AS_WINDOW(self
->client
));
1035 window_add(&self
->handle
, CLIENT_AS_WINDOW(self
->client
));
1036 window_add(&self
->lgrip
, CLIENT_AS_WINDOW(self
->client
));
1037 window_add(&self
->rgrip
, CLIENT_AS_WINDOW(self
->client
));
1038 window_add(&self
->topresize
, CLIENT_AS_WINDOW(self
->client
));
1039 window_add(&self
->tltresize
, CLIENT_AS_WINDOW(self
->client
));
1040 window_add(&self
->tllresize
, CLIENT_AS_WINDOW(self
->client
));
1041 window_add(&self
->trtresize
, CLIENT_AS_WINDOW(self
->client
));
1042 window_add(&self
->trrresize
, CLIENT_AS_WINDOW(self
->client
));
1043 window_add(&self
->left
, CLIENT_AS_WINDOW(self
->client
));
1044 window_add(&self
->right
, CLIENT_AS_WINDOW(self
->client
));
1045 window_add(&self
->titleleft
, CLIENT_AS_WINDOW(self
->client
));
1046 window_add(&self
->titletop
, CLIENT_AS_WINDOW(self
->client
));
1047 window_add(&self
->titletopleft
, CLIENT_AS_WINDOW(self
->client
));
1048 window_add(&self
->titletopright
, CLIENT_AS_WINDOW(self
->client
));
1049 window_add(&self
->titleright
, CLIENT_AS_WINDOW(self
->client
));
1050 window_add(&self
->titlebottom
, CLIENT_AS_WINDOW(self
->client
));
1051 window_add(&self
->handleleft
, CLIENT_AS_WINDOW(self
->client
));
1052 window_add(&self
->handletop
, CLIENT_AS_WINDOW(self
->client
));
1053 window_add(&self
->handleright
, CLIENT_AS_WINDOW(self
->client
));
1054 window_add(&self
->handlebottom
, CLIENT_AS_WINDOW(self
->client
));
1055 window_add(&self
->lgripleft
, CLIENT_AS_WINDOW(self
->client
));
1056 window_add(&self
->lgriptop
, CLIENT_AS_WINDOW(self
->client
));
1057 window_add(&self
->lgripbottom
, CLIENT_AS_WINDOW(self
->client
));
1058 window_add(&self
->rgripright
, CLIENT_AS_WINDOW(self
->client
));
1059 window_add(&self
->rgriptop
, CLIENT_AS_WINDOW(self
->client
));
1060 window_add(&self
->rgripbottom
, CLIENT_AS_WINDOW(self
->client
));
1063 static gboolean
find_reparent(XEvent
*e
, gpointer data
)
1065 const ObFrame
*self
= data
;
1067 /* Find ReparentNotify events for the window that aren't being reparented into the
1068 frame, thus the client reparenting itself off the frame. */
1069 return e
->type
== ReparentNotify
&& e
->xreparent
.window
== self
->client
->window
&&
1070 e
->xreparent
.parent
!= self
->window
;
1073 void frame_release_client(ObFrame
*self
)
1075 /* if there was any animation going on, kill it */
1076 if (self
->iconify_animation_timer
)
1077 g_source_remove(self
->iconify_animation_timer
);
1079 /* check if the app has already reparented its window away */
1080 if (!xqueue_exists_local(find_reparent
, self
)) {
1081 /* according to the ICCCM - if the client doesn't reparent itself,
1082 then we will reparent the window to root for them */
1083 XReparentWindow(obt_display
, self
->client
->window
, obt_root(ob_screen
),
1084 self
->client
->area
.x
, self
->client
->area
.y
);
1087 /* remove all the windows for the frame from the window_map */
1088 window_remove(self
->window
);
1089 window_remove(self
->backback
);
1090 window_remove(self
->backfront
);
1091 window_remove(self
->innerleft
);
1092 window_remove(self
->innertop
);
1093 window_remove(self
->innerright
);
1094 window_remove(self
->innerbottom
);
1095 window_remove(self
->innerblb
);
1096 window_remove(self
->innerbll
);
1097 window_remove(self
->innerbrb
);
1098 window_remove(self
->innerbrr
);
1099 window_remove(self
->title
);
1100 window_remove(self
->label
);
1101 window_remove(self
->max
);
1102 window_remove(self
->close
);
1103 window_remove(self
->desk
);
1104 window_remove(self
->shade
);
1105 window_remove(self
->icon
);
1106 window_remove(self
->iconify
);
1107 window_remove(self
->handle
);
1108 window_remove(self
->lgrip
);
1109 window_remove(self
->rgrip
);
1110 window_remove(self
->topresize
);
1111 window_remove(self
->tltresize
);
1112 window_remove(self
->tllresize
);
1113 window_remove(self
->trtresize
);
1114 window_remove(self
->trrresize
);
1115 window_remove(self
->left
);
1116 window_remove(self
->right
);
1117 window_remove(self
->titleleft
);
1118 window_remove(self
->titletop
);
1119 window_remove(self
->titletopleft
);
1120 window_remove(self
->titletopright
);
1121 window_remove(self
->titleright
);
1122 window_remove(self
->titlebottom
);
1123 window_remove(self
->handleleft
);
1124 window_remove(self
->handletop
);
1125 window_remove(self
->handleright
);
1126 window_remove(self
->handlebottom
);
1127 window_remove(self
->lgripleft
);
1128 window_remove(self
->lgriptop
);
1129 window_remove(self
->lgripbottom
);
1130 window_remove(self
->rgripright
);
1131 window_remove(self
->rgriptop
);
1132 window_remove(self
->rgripbottom
);
1134 if (self
->flash_timer
) g_source_remove(self
->flash_timer
);
1137 /* is there anything present between us and the label? */
1138 static gboolean
is_button_present(ObFrame
*self
, const gchar
*lc
, gint dir
) {
1139 for (; *lc
!= '\0' && lc
>= config_title_layout
; lc
+= dir
) {
1140 if (*lc
== ' ') continue; /* it was invalid */
1141 if (*lc
== 'N' && self
->decorations
& OB_FRAME_DECOR_ICON
)
1143 if (*lc
== 'D' && self
->decorations
& OB_FRAME_DECOR_ALLDESKTOPS
)
1145 if (*lc
== 'S' && self
->decorations
& OB_FRAME_DECOR_SHADE
)
1147 if (*lc
== 'I' && self
->decorations
& OB_FRAME_DECOR_ICONIFY
)
1149 if (*lc
== 'M' && self
->decorations
& OB_FRAME_DECOR_MAXIMIZE
)
1151 if (*lc
== 'C' && self
->decorations
& OB_FRAME_DECOR_CLOSE
)
1153 if (*lc
== 'L') return FALSE
;
1158 static void place_button(ObFrame
*self
, const char *lc
, gint bwidth
,
1160 gint
*x
, gint
*button_on
, gint
*button_x
)
1162 if (!(*button_on
= is_button_present(self
, lc
, i
)))
1165 self
->label_width
-= bwidth
;
1170 if (self
->label_x
<= left
|| *x
> self
->label_x
) {
1173 /* the button would have been drawn on top of another button */
1175 self
->label_width
+= bwidth
;
1180 static void layout_title(ObFrame
*self
)
1185 const gint bwidth
= ob_rr_theme
->button_size
+ ob_rr_theme
->paddingx
+ 1;
1186 /* position of the leftmost button */
1187 const gint left
= ob_rr_theme
->paddingx
+ 1;
1188 /* position of the rightmost button */
1189 const gint right
= self
->width
;
1191 /* turn them all off */
1192 self
->icon_on
= self
->desk_on
= self
->shade_on
= self
->iconify_on
=
1193 self
->max_on
= self
->close_on
= self
->label_on
= FALSE
;
1194 self
->label_width
= self
->width
- (ob_rr_theme
->paddingx
+ 1) * 2;
1195 self
->leftmost
= self
->rightmost
= OB_FRAME_CONTEXT_NONE
;
1197 /* figure out what's being shown, find each element's position, and the
1200 do the ones before the label, then after the label,
1201 i will be +1 the first time through when working to the left,
1202 and -1 the second time through when working to the right */
1203 for (i
= 1; i
>= -1; i
-=2) {
1205 ObFrameContext
*firstcon
;
1209 lc
= config_title_layout
;
1210 firstcon
= &self
->leftmost
;
1213 lc
= config_title_layout
+ strlen(config_title_layout
)-1;
1214 firstcon
= &self
->rightmost
;
1217 /* stop at the end of the string (or the label, which calls break) */
1218 for (; *lc
!= '\0' && lc
>= config_title_layout
; lc
+=i
) {
1221 self
->label_on
= TRUE
;
1224 break; /* break the for loop, do other side of label */
1225 } else if (*lc
== 'N') {
1226 if (firstcon
) *firstcon
= OB_FRAME_CONTEXT_ICON
;
1227 /* icon is bigger than buttons */
1228 place_button(self
, lc
, bwidth
+ 2, left
, i
, &x
, &self
->icon_on
, &self
->icon_x
);
1229 } else if (*lc
== 'D') {
1230 if (firstcon
) *firstcon
= OB_FRAME_CONTEXT_ALLDESKTOPS
;
1231 place_button(self
, lc
, bwidth
, left
, i
, &x
, &self
->desk_on
, &self
->desk_x
);
1232 } else if (*lc
== 'S') {
1233 if (firstcon
) *firstcon
= OB_FRAME_CONTEXT_SHADE
;
1234 place_button(self
, lc
, bwidth
, left
, i
, &x
, &self
->shade_on
, &self
->shade_x
);
1235 } else if (*lc
== 'I') {
1236 if (firstcon
) *firstcon
= OB_FRAME_CONTEXT_ICONIFY
;
1237 place_button(self
, lc
, bwidth
, left
, i
, &x
, &self
->iconify_on
, &self
->iconify_x
);
1238 } else if (*lc
== 'M') {
1239 if (firstcon
) *firstcon
= OB_FRAME_CONTEXT_MAXIMIZE
;
1240 place_button(self
, lc
, bwidth
, left
, i
, &x
, &self
->max_on
, &self
->max_x
);
1241 } else if (*lc
== 'C') {
1242 if (firstcon
) *firstcon
= OB_FRAME_CONTEXT_CLOSE
;
1243 place_button(self
, lc
, bwidth
, left
, i
, &x
, &self
->close_on
, &self
->close_x
);
1245 continue; /* don't set firstcon */
1250 /* position and map the elements */
1251 if (self
->icon_on
) {
1252 XMapWindow(obt_display
, self
->icon
);
1253 XMoveWindow(obt_display
, self
->icon
, self
->icon_x
,
1254 ob_rr_theme
->paddingy
);
1256 XUnmapWindow(obt_display
, self
->icon
);
1258 if (self
->desk_on
) {
1259 XMapWindow(obt_display
, self
->desk
);
1260 XMoveWindow(obt_display
, self
->desk
, self
->desk_x
,
1261 ob_rr_theme
->paddingy
+ 1);
1263 XUnmapWindow(obt_display
, self
->desk
);
1265 if (self
->shade_on
) {
1266 XMapWindow(obt_display
, self
->shade
);
1267 XMoveWindow(obt_display
, self
->shade
, self
->shade_x
,
1268 ob_rr_theme
->paddingy
+ 1);
1270 XUnmapWindow(obt_display
, self
->shade
);
1272 if (self
->iconify_on
) {
1273 XMapWindow(obt_display
, self
->iconify
);
1274 XMoveWindow(obt_display
, self
->iconify
, self
->iconify_x
,
1275 ob_rr_theme
->paddingy
+ 1);
1277 XUnmapWindow(obt_display
, self
->iconify
);
1280 XMapWindow(obt_display
, self
->max
);
1281 XMoveWindow(obt_display
, self
->max
, self
->max_x
,
1282 ob_rr_theme
->paddingy
+ 1);
1284 XUnmapWindow(obt_display
, self
->max
);
1286 if (self
->close_on
) {
1287 XMapWindow(obt_display
, self
->close
);
1288 XMoveWindow(obt_display
, self
->close
, self
->close_x
,
1289 ob_rr_theme
->paddingy
+ 1);
1291 XUnmapWindow(obt_display
, self
->close
);
1293 if (self
->label_on
&& self
->label_width
> 0) {
1294 XMapWindow(obt_display
, self
->label
);
1295 XMoveWindow(obt_display
, self
->label
, self
->label_x
,
1296 ob_rr_theme
->paddingy
);
1298 XUnmapWindow(obt_display
, self
->label
);
1301 gboolean
frame_next_context_from_string(gchar
*names
, ObFrameContext
*cx
)
1305 if (!*names
) /* empty string */
1308 /* find the first space */
1309 for (p
= names
; *p
; p
= g_utf8_next_char(p
)) {
1310 const gunichar c
= g_utf8_get_char(p
);
1311 if (g_unichar_isspace(c
)) break;
1315 /* leading spaces in the string */
1316 n
= g_utf8_next_char(names
);
1317 if (!frame_next_context_from_string(n
, cx
))
1322 /* delete the space with null zero(s) */
1323 while (n
< g_utf8_next_char(p
))
1327 *cx
= frame_context_from_string(names
);
1329 /* find the next non-space */
1330 for (; *n
; n
= g_utf8_next_char(n
)) {
1331 const gunichar c
= g_utf8_get_char(n
);
1332 if (!g_unichar_isspace(c
)) break;
1336 /* delete everything we just read (copy everything at n to the start of
1338 for (p
= names
; *n
; ++p
, ++n
)
1345 ObFrameContext
frame_context_from_string(const gchar
*name
)
1347 if (!g_ascii_strcasecmp("Desktop", name
))
1348 return OB_FRAME_CONTEXT_DESKTOP
;
1349 else if (!g_ascii_strcasecmp("Root", name
))
1350 return OB_FRAME_CONTEXT_ROOT
;
1351 else if (!g_ascii_strcasecmp("Client", name
))
1352 return OB_FRAME_CONTEXT_CLIENT
;
1353 else if (!g_ascii_strcasecmp("Titlebar", name
))
1354 return OB_FRAME_CONTEXT_TITLEBAR
;
1355 else if (!g_ascii_strcasecmp("Frame", name
))
1356 return OB_FRAME_CONTEXT_FRAME
;
1357 else if (!g_ascii_strcasecmp("TLCorner", name
))
1358 return OB_FRAME_CONTEXT_TLCORNER
;
1359 else if (!g_ascii_strcasecmp("TRCorner", name
))
1360 return OB_FRAME_CONTEXT_TRCORNER
;
1361 else if (!g_ascii_strcasecmp("BLCorner", name
))
1362 return OB_FRAME_CONTEXT_BLCORNER
;
1363 else if (!g_ascii_strcasecmp("BRCorner", name
))
1364 return OB_FRAME_CONTEXT_BRCORNER
;
1365 else if (!g_ascii_strcasecmp("Top", name
))
1366 return OB_FRAME_CONTEXT_TOP
;
1367 else if (!g_ascii_strcasecmp("Bottom", name
))
1368 return OB_FRAME_CONTEXT_BOTTOM
;
1369 else if (!g_ascii_strcasecmp("Left", name
))
1370 return OB_FRAME_CONTEXT_LEFT
;
1371 else if (!g_ascii_strcasecmp("Right", name
))
1372 return OB_FRAME_CONTEXT_RIGHT
;
1373 else if (!g_ascii_strcasecmp("Maximize", name
))
1374 return OB_FRAME_CONTEXT_MAXIMIZE
;
1375 else if (!g_ascii_strcasecmp("AllDesktops", name
))
1376 return OB_FRAME_CONTEXT_ALLDESKTOPS
;
1377 else if (!g_ascii_strcasecmp("Shade", name
))
1378 return OB_FRAME_CONTEXT_SHADE
;
1379 else if (!g_ascii_strcasecmp("Iconify", name
))
1380 return OB_FRAME_CONTEXT_ICONIFY
;
1381 else if (!g_ascii_strcasecmp("Icon", name
))
1382 return OB_FRAME_CONTEXT_ICON
;
1383 else if (!g_ascii_strcasecmp("Close", name
))
1384 return OB_FRAME_CONTEXT_CLOSE
;
1385 else if (!g_ascii_strcasecmp("MoveResize", name
))
1386 return OB_FRAME_CONTEXT_MOVE_RESIZE
;
1387 else if (!g_ascii_strcasecmp("Dock", name
))
1388 return OB_FRAME_CONTEXT_DOCK
;
1390 return OB_FRAME_CONTEXT_NONE
;
1393 ObFrameContext
frame_context(ObClient
*client
, Window win
, gint x
, gint y
)
1398 if (moveresize_in_progress
)
1399 return OB_FRAME_CONTEXT_MOVE_RESIZE
;
1401 if (win
== obt_root(ob_screen
))
1402 return OB_FRAME_CONTEXT_ROOT
;
1403 if ((obwin
= window_find(win
))) {
1404 if (WINDOW_IS_DOCK(obwin
)) {
1405 return OB_FRAME_CONTEXT_DOCK
;
1408 if (client
== NULL
) return OB_FRAME_CONTEXT_NONE
;
1409 if (win
== client
->window
) {
1410 /* conceptually, this is the desktop, as far as users are
1412 if (client
->type
== OB_CLIENT_TYPE_DESKTOP
)
1413 return OB_FRAME_CONTEXT_DESKTOP
;
1414 return OB_FRAME_CONTEXT_CLIENT
;
1417 self
= client
->frame
;
1419 /* when the user clicks in the corners of the titlebar and the client
1420 is fully maximized, then treat it like they clicked in the
1421 button that is there */
1422 if (self
->max_horz
&& self
->max_vert
&&
1423 (win
== self
->title
|| win
== self
->titletop
||
1424 win
== self
->titleleft
|| win
== self
->titletopleft
||
1425 win
== self
->titleright
|| win
== self
->titletopright
))
1427 /* get the mouse coords in reference to the whole frame */
1431 /* these windows are down a border width from the top of the frame */
1432 if (win
== self
->title
||
1433 win
== self
->titleleft
|| win
== self
->titleright
)
1436 /* title is a border width in from the edge */
1437 if (win
== self
->title
)
1439 /* titletop is a bit to the right */
1440 else if (win
== self
->titletop
)
1441 fx
+= ob_rr_theme
->grip_width
+ self
->bwidth
;
1442 /* titletopright is way to the right edge */
1443 else if (win
== self
->titletopright
)
1444 fx
+= self
->area
.width
- (ob_rr_theme
->grip_width
+ self
->bwidth
);
1445 /* titleright is even more way to the right edge */
1446 else if (win
== self
->titleright
)
1447 fx
+= self
->area
.width
- self
->bwidth
;
1449 /* figure out if we're over the area that should be considered a
1451 if (fy
< self
->bwidth
+ ob_rr_theme
->paddingy
+ 1 +
1452 ob_rr_theme
->button_size
)
1454 if (fx
< (self
->bwidth
+ ob_rr_theme
->paddingx
+ 1 +
1455 ob_rr_theme
->button_size
))
1457 if (self
->leftmost
!= OB_FRAME_CONTEXT_NONE
)
1458 return self
->leftmost
;
1460 else if (fx
>= (self
->area
.width
-
1461 (self
->bwidth
+ ob_rr_theme
->paddingx
+ 1 +
1462 ob_rr_theme
->button_size
)))
1464 if (self
->rightmost
!= OB_FRAME_CONTEXT_NONE
)
1465 return self
->rightmost
;
1469 /* there is no resizing maximized windows so make them the titlebar
1471 return OB_FRAME_CONTEXT_TITLEBAR
;
1473 else if (self
->max_vert
&&
1474 (win
== self
->titletop
|| win
== self
->topresize
))
1475 /* can't resize vertically when max vert */
1476 return OB_FRAME_CONTEXT_TITLEBAR
;
1477 else if (self
->shaded
&&
1478 (win
== self
->titletop
|| win
== self
->topresize
))
1479 /* can't resize vertically when shaded */
1480 return OB_FRAME_CONTEXT_TITLEBAR
;
1482 if (win
== self
->window
) return OB_FRAME_CONTEXT_FRAME
;
1483 if (win
== self
->label
) return OB_FRAME_CONTEXT_TITLEBAR
;
1484 if (win
== self
->handle
) return OB_FRAME_CONTEXT_BOTTOM
;
1485 if (win
== self
->handletop
) return OB_FRAME_CONTEXT_BOTTOM
;
1486 if (win
== self
->handlebottom
) return OB_FRAME_CONTEXT_BOTTOM
;
1487 if (win
== self
->handleleft
) return OB_FRAME_CONTEXT_BLCORNER
;
1488 if (win
== self
->lgrip
) return OB_FRAME_CONTEXT_BLCORNER
;
1489 if (win
== self
->lgripleft
) return OB_FRAME_CONTEXT_BLCORNER
;
1490 if (win
== self
->lgriptop
) return OB_FRAME_CONTEXT_BLCORNER
;
1491 if (win
== self
->lgripbottom
) return OB_FRAME_CONTEXT_BLCORNER
;
1492 if (win
== self
->handleright
) return OB_FRAME_CONTEXT_BRCORNER
;
1493 if (win
== self
->rgrip
) return OB_FRAME_CONTEXT_BRCORNER
;
1494 if (win
== self
->rgripright
) return OB_FRAME_CONTEXT_BRCORNER
;
1495 if (win
== self
->rgriptop
) return OB_FRAME_CONTEXT_BRCORNER
;
1496 if (win
== self
->rgripbottom
) return OB_FRAME_CONTEXT_BRCORNER
;
1497 if (win
== self
->title
) return OB_FRAME_CONTEXT_TITLEBAR
;
1498 if (win
== self
->titlebottom
) return OB_FRAME_CONTEXT_TITLEBAR
;
1499 if (win
== self
->titleleft
) return OB_FRAME_CONTEXT_TLCORNER
;
1500 if (win
== self
->titletopleft
) return OB_FRAME_CONTEXT_TLCORNER
;
1501 if (win
== self
->titleright
) return OB_FRAME_CONTEXT_TRCORNER
;
1502 if (win
== self
->titletopright
) return OB_FRAME_CONTEXT_TRCORNER
;
1503 if (win
== self
->titletop
) return OB_FRAME_CONTEXT_TOP
;
1504 if (win
== self
->topresize
) return OB_FRAME_CONTEXT_TOP
;
1505 if (win
== self
->tltresize
) return OB_FRAME_CONTEXT_TLCORNER
;
1506 if (win
== self
->tllresize
) return OB_FRAME_CONTEXT_TLCORNER
;
1507 if (win
== self
->trtresize
) return OB_FRAME_CONTEXT_TRCORNER
;
1508 if (win
== self
->trrresize
) return OB_FRAME_CONTEXT_TRCORNER
;
1509 if (win
== self
->left
) return OB_FRAME_CONTEXT_LEFT
;
1510 if (win
== self
->right
) return OB_FRAME_CONTEXT_RIGHT
;
1511 if (win
== self
->innertop
) return OB_FRAME_CONTEXT_TITLEBAR
;
1512 if (win
== self
->innerleft
) return OB_FRAME_CONTEXT_LEFT
;
1513 if (win
== self
->innerbottom
) return OB_FRAME_CONTEXT_BOTTOM
;
1514 if (win
== self
->innerright
) return OB_FRAME_CONTEXT_RIGHT
;
1515 if (win
== self
->innerbll
) return OB_FRAME_CONTEXT_BLCORNER
;
1516 if (win
== self
->innerblb
) return OB_FRAME_CONTEXT_BLCORNER
;
1517 if (win
== self
->innerbrr
) return OB_FRAME_CONTEXT_BRCORNER
;
1518 if (win
== self
->innerbrb
) return OB_FRAME_CONTEXT_BRCORNER
;
1519 if (win
== self
->max
) return OB_FRAME_CONTEXT_MAXIMIZE
;
1520 if (win
== self
->iconify
) return OB_FRAME_CONTEXT_ICONIFY
;
1521 if (win
== self
->close
) return OB_FRAME_CONTEXT_CLOSE
;
1522 if (win
== self
->icon
) return OB_FRAME_CONTEXT_ICON
;
1523 if (win
== self
->desk
) return OB_FRAME_CONTEXT_ALLDESKTOPS
;
1524 if (win
== self
->shade
) return OB_FRAME_CONTEXT_SHADE
;
1526 return OB_FRAME_CONTEXT_NONE
;
1529 void frame_client_gravity(ObFrame
*self
, gint
*x
, gint
*y
)
1532 switch (self
->client
->gravity
) {
1534 case NorthWestGravity
:
1535 case SouthWestGravity
:
1542 /* the middle of the client will be the middle of the frame */
1543 *x
-= (self
->size
.right
- self
->size
.left
) / 2;
1546 case NorthEastGravity
:
1547 case SouthEastGravity
:
1549 /* the right side of the client will be the right side of the frame */
1550 *x
-= self
->size
.right
+ self
->size
.left
-
1551 self
->client
->border_width
* 2;
1556 /* the client's position won't move */
1557 *x
-= self
->size
.left
- self
->client
->border_width
;
1562 switch (self
->client
->gravity
) {
1564 case NorthWestGravity
:
1565 case NorthEastGravity
:
1572 /* the middle of the client will be the middle of the frame */
1573 *y
-= (self
->size
.bottom
- self
->size
.top
) / 2;
1576 case SouthWestGravity
:
1577 case SouthEastGravity
:
1579 /* the bottom of the client will be the bottom of the frame */
1580 *y
-= self
->size
.bottom
+ self
->size
.top
-
1581 self
->client
->border_width
* 2;
1586 /* the client's position won't move */
1587 *y
-= self
->size
.top
- self
->client
->border_width
;
1592 void frame_frame_gravity(ObFrame
*self
, gint
*x
, gint
*y
)
1595 switch (self
->client
->gravity
) {
1597 case NorthWestGravity
:
1599 case SouthWestGravity
:
1604 /* the middle of the client will be the middle of the frame */
1605 *x
+= (self
->size
.right
- self
->size
.left
) / 2;
1607 case NorthEastGravity
:
1609 case SouthEastGravity
:
1610 /* the right side of the client will be the right side of the frame */
1611 *x
+= self
->size
.right
+ self
->size
.left
-
1612 self
->client
->border_width
* 2;
1616 /* the client's position won't move */
1617 *x
+= self
->size
.left
- self
->client
->border_width
;
1622 switch (self
->client
->gravity
) {
1624 case NorthWestGravity
:
1626 case NorthEastGravity
:
1631 /* the middle of the client will be the middle of the frame */
1632 *y
+= (self
->size
.bottom
- self
->size
.top
) / 2;
1634 case SouthWestGravity
:
1636 case SouthEastGravity
:
1637 /* the bottom of the client will be the bottom of the frame */
1638 *y
+= self
->size
.bottom
+ self
->size
.top
-
1639 self
->client
->border_width
* 2;
1643 /* the client's position won't move */
1644 *y
+= self
->size
.top
- self
->client
->border_width
;
1649 void frame_rect_to_frame(ObFrame
*self
, Rect
*r
)
1651 r
->width
+= self
->size
.left
+ self
->size
.right
;
1652 r
->height
+= self
->size
.top
+ self
->size
.bottom
;
1653 frame_client_gravity(self
, &r
->x
, &r
->y
);
1656 void frame_rect_to_client(ObFrame
*self
, Rect
*r
)
1658 r
->width
-= self
->size
.left
+ self
->size
.right
;
1659 r
->height
-= self
->size
.top
+ self
->size
.bottom
;
1660 frame_frame_gravity(self
, &r
->x
, &r
->y
);
1663 static void flash_done(gpointer data
)
1665 ObFrame
*self
= data
;
1667 if (self
->focused
!= self
->flash_on
)
1668 frame_adjust_focus(self
, self
->focused
);
1671 static gboolean
flash_timeout(gpointer data
)
1673 ObFrame
*self
= data
;
1676 g_get_current_time(&now
);
1677 if (now
.tv_sec
> self
->flash_end
.tv_sec
||
1678 (now
.tv_sec
== self
->flash_end
.tv_sec
&&
1679 now
.tv_usec
>= self
->flash_end
.tv_usec
))
1680 self
->flashing
= FALSE
;
1682 if (!self
->flashing
)
1683 return FALSE
; /* we are done */
1685 self
->flash_on
= !self
->flash_on
;
1686 if (!self
->focused
) {
1687 frame_adjust_focus(self
, self
->flash_on
);
1688 self
->focused
= FALSE
;
1691 return TRUE
; /* go again */
1694 void frame_flash_start(ObFrame
*self
)
1696 self
->flash_on
= self
->focused
;
1698 if (!self
->flashing
)
1699 self
->flash_timer
= g_timeout_add_full(G_PRIORITY_DEFAULT
,
1700 600, flash_timeout
, self
,
1702 g_get_current_time(&self
->flash_end
);
1703 g_time_val_add(&self
->flash_end
, G_USEC_PER_SEC
* 5);
1705 self
->flashing
= TRUE
;
1708 void frame_flash_stop(ObFrame
*self
)
1710 self
->flashing
= FALSE
;
1713 static gulong
frame_animate_iconify_time_left(ObFrame
*self
,
1714 const GTimeVal
*now
)
1717 sec
= self
->iconify_animation_end
.tv_sec
- now
->tv_sec
;
1718 usec
= self
->iconify_animation_end
.tv_usec
- now
->tv_usec
;
1720 usec
+= G_USEC_PER_SEC
;
1723 /* no negative values */
1724 return MAX(sec
* G_USEC_PER_SEC
+ usec
, 0);
1727 static gboolean
frame_animate_iconify(gpointer p
)
1731 gint iconx
, icony
, iconw
;
1734 gboolean iconifying
;
1736 if (self
->client
->icon_geometry
.width
== 0) {
1737 /* there is no icon geometry set so just go straight down */
1740 a
= screen_physical_area_monitor(screen_find_monitor(&self
->area
));
1741 iconx
= self
->area
.x
+ self
->area
.width
/ 2 + 32;
1742 icony
= a
->y
+ a
->width
;
1745 iconx
= self
->client
->icon_geometry
.x
;
1746 icony
= self
->client
->icon_geometry
.y
;
1747 iconw
= self
->client
->icon_geometry
.width
;
1750 iconifying
= self
->iconify_animation_going
> 0;
1752 /* how far do we have left to go ? */
1753 g_get_current_time(&now
);
1754 time
= frame_animate_iconify_time_left(self
, &now
);
1756 if ((time
> 0 && iconifying
) || (time
== 0 && !iconifying
)) {
1757 /* start where the frame is supposed to be */
1760 w
= self
->area
.width
;
1761 h
= self
->area
.height
;
1763 /* start at the icon */
1767 h
= self
->size
.top
; /* just the titlebar */
1774 dx
= self
->area
.x
- iconx
;
1775 dy
= self
->area
.y
- icony
;
1776 dw
= self
->area
.width
- self
->bwidth
* 2 - iconw
;
1777 /* if restoring, we move in the opposite direction */
1778 if (!iconifying
) { dx
= -dx
; dy
= -dy
; dw
= -dw
; }
1780 elapsed
= FRAME_ANIMATE_ICONIFY_TIME
- time
;
1781 x
= x
- (dx
* elapsed
) / FRAME_ANIMATE_ICONIFY_TIME
;
1782 y
= y
- (dy
* elapsed
) / FRAME_ANIMATE_ICONIFY_TIME
;
1783 w
= w
- (dw
* elapsed
) / FRAME_ANIMATE_ICONIFY_TIME
;
1784 h
= self
->size
.top
; /* just the titlebar */
1787 XMoveResizeWindow(obt_display
, self
->window
, x
, y
, w
, h
);
1788 XFlush(obt_display
);
1791 frame_end_iconify_animation(self
);
1793 return time
> 0; /* repeat until we're out of time */
1796 void frame_end_iconify_animation(ObFrame
*self
)
1798 /* see if there is an animation going */
1799 if (self
->iconify_animation_going
== 0) return;
1802 XUnmapWindow(obt_display
, self
->window
);
1804 /* Send a ConfigureNotify when the animation is done, this fixes
1805 KDE's pager showing the window in the wrong place. since the
1806 window is mapped at a different location and is then moved, we
1807 need to send the synthetic configurenotify, since apps may have
1808 read the position when the client mapped, apparently. */
1809 client_reconfigure(self
->client
, TRUE
);
1812 /* we're not animating any more ! */
1813 self
->iconify_animation_going
= 0;
1815 XMoveResizeWindow(obt_display
, self
->window
,
1816 self
->area
.x
, self
->area
.y
,
1817 self
->area
.width
, self
->area
.height
);
1818 /* we delay re-rendering until after we're done animating */
1819 framerender_frame(self
);
1820 XFlush(obt_display
);
1823 void frame_begin_iconify_animation(ObFrame
*self
, gboolean iconifying
)
1826 gboolean new_anim
= FALSE
;
1827 gboolean set_end
= TRUE
;
1830 /* if there is no titlebar, just don't animate for now
1831 XXX it would be nice tho.. */
1832 if (!(self
->decorations
& OB_FRAME_DECOR_TITLEBAR
))
1835 /* get the current time */
1836 g_get_current_time(&now
);
1838 /* get how long until the end */
1839 time
= FRAME_ANIMATE_ICONIFY_TIME
;
1840 if (self
->iconify_animation_going
) {
1841 if (!!iconifying
!= (self
->iconify_animation_going
> 0)) {
1842 /* animation was already going on in the opposite direction */
1843 time
= time
- frame_animate_iconify_time_left(self
, &now
);
1845 /* animation was already going in the same direction */
1849 self
->iconify_animation_going
= iconifying
? 1 : -1;
1851 /* set the ending time */
1853 self
->iconify_animation_end
.tv_sec
= now
.tv_sec
;
1854 self
->iconify_animation_end
.tv_usec
= now
.tv_usec
;
1855 g_time_val_add(&self
->iconify_animation_end
, time
);
1859 if (self
->iconify_animation_timer
)
1860 g_source_remove(self
->iconify_animation_timer
);
1861 self
->iconify_animation_timer
=
1862 g_timeout_add_full(G_PRIORITY_DEFAULT
,
1863 FRAME_ANIMATE_ICONIFY_STEP_TIME
,
1864 frame_animate_iconify
, self
, NULL
);
1867 /* do the first step */
1868 frame_animate_iconify(self
);
1870 /* show it during the animation even if it is not "visible" */
1872 XMapWindow(obt_display
, self
->window
);