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.
23 #include "extensions.h"
27 #include "framerender.h"
29 #include "focus_cycle.h"
30 #include "focus_cycle_indicator.h"
31 #include "moveresize.h"
33 #include "render/theme.h"
35 #define FRAME_EVENTMASK (EnterWindowMask | LeaveWindowMask | \
36 ButtonPressMask | ButtonReleaseMask | \
37 SubstructureRedirectMask | FocusChangeMask)
38 #define ELEMENT_EVENTMASK (ButtonPressMask | ButtonReleaseMask | \
39 ButtonMotionMask | PointerMotionMask | \
40 EnterWindowMask | LeaveWindowMask)
42 #define FRAME_ANIMATE_ICONIFY_TIME 150000 /* .15 seconds */
43 #define FRAME_ANIMATE_ICONIFY_STEP_TIME (G_USEC_PER_SEC / 60) /* 60 Hz */
45 #define FRAME_HANDLE_Y(f) (f->size.top + f->client->area.height + f->cbwidth_b)
47 static void flash_done(gpointer data
);
48 static gboolean
flash_timeout(gpointer data
);
50 static void layout_title(ObFrame
*self
);
51 static void set_theme_statics(ObFrame
*self
);
52 static void free_theme_statics(ObFrame
*self
);
53 static gboolean
frame_animate_iconify(gpointer self
);
54 static void frame_adjust_cursors(ObFrame
*self
);
56 static Window
createWindow(Window parent
, Visual
*visual
,
57 gulong mask
, XSetWindowAttributes
*attrib
)
59 return XCreateWindow(ob_display
, parent
, 0, 0, 1, 1, 0,
60 (visual
? 32 : RrDepth(ob_rr_inst
)), InputOutput
,
61 (visual
? visual
: RrVisual(ob_rr_inst
)),
66 static Visual
*check_32bit_client(ObClient
*c
)
68 XWindowAttributes wattrib
;
71 /* we're already running at 32 bit depth, yay. we don't need to use their
73 if (RrDepth(ob_rr_inst
) == 32)
76 ret
= XGetWindowAttributes(ob_display
, c
->window
, &wattrib
);
77 g_assert(ret
!= BadDrawable
);
78 g_assert(ret
!= BadWindow
);
80 if (wattrib
.depth
== 32)
81 return wattrib
.visual
;
85 ObFrame
*frame_new(ObClient
*client
)
87 XSetWindowAttributes attrib
;
92 self
= g_new0(ObFrame
, 1);
93 self
->client
= client
;
95 visual
= check_32bit_client(client
);
97 /* create the non-visible decor windows */
101 /* client has a 32-bit visual */
102 mask
|= CWColormap
| CWBackPixel
| CWBorderPixel
;
103 /* create a colormap with the visual */
104 self
->colormap
= attrib
.colormap
=
105 XCreateColormap(ob_display
,
106 RootWindow(ob_display
, ob_screen
),
108 attrib
.background_pixel
= BlackPixel(ob_display
, ob_screen
);
109 attrib
.border_pixel
= BlackPixel(ob_display
, ob_screen
);
111 self
->window
= createWindow(RootWindow(ob_display
, 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
->title
= createWindow(self
->window
, NULL
, mask
, &attrib
);
134 self
->titleleft
= createWindow(self
->window
, NULL
, mask
, &attrib
);
135 self
->titletop
= createWindow(self
->window
, NULL
, mask
, &attrib
);
136 self
->titletopleft
= createWindow(self
->window
, NULL
, mask
, &attrib
);
137 self
->titletopright
= createWindow(self
->window
, NULL
, mask
, &attrib
);
138 self
->titleright
= createWindow(self
->window
, NULL
, mask
, &attrib
);
139 self
->titlebottom
= createWindow(self
->window
, NULL
, mask
, &attrib
);
141 self
->topresize
= createWindow(self
->title
, NULL
, mask
, &attrib
);
142 self
->tltresize
= createWindow(self
->title
, NULL
, mask
, &attrib
);
143 self
->tllresize
= createWindow(self
->title
, NULL
, mask
, &attrib
);
144 self
->trtresize
= createWindow(self
->title
, NULL
, mask
, &attrib
);
145 self
->trrresize
= createWindow(self
->title
, NULL
, mask
, &attrib
);
147 self
->left
= createWindow(self
->window
, NULL
, mask
, &attrib
);
148 self
->right
= createWindow(self
->window
, NULL
, mask
, &attrib
);
150 self
->label
= createWindow(self
->title
, NULL
, mask
, &attrib
);
151 self
->max
= createWindow(self
->title
, NULL
, mask
, &attrib
);
152 self
->close
= createWindow(self
->title
, NULL
, mask
, &attrib
);
153 self
->desk
= createWindow(self
->title
, NULL
, mask
, &attrib
);
154 self
->shade
= createWindow(self
->title
, NULL
, mask
, &attrib
);
155 self
->icon
= createWindow(self
->title
, NULL
, mask
, &attrib
);
156 self
->iconify
= createWindow(self
->title
, NULL
, mask
, &attrib
);
158 self
->handle
= createWindow(self
->window
, NULL
, mask
, &attrib
);
159 self
->lgrip
= createWindow(self
->handle
, NULL
, mask
, &attrib
);
160 self
->rgrip
= createWindow(self
->handle
, NULL
, mask
, &attrib
);
162 self
->handleleft
= createWindow(self
->handle
, NULL
, mask
, &attrib
);
163 self
->handleright
= createWindow(self
->handle
, NULL
, mask
, &attrib
);
165 self
->handletop
= createWindow(self
->window
, NULL
, mask
, &attrib
);
166 self
->handlebottom
= createWindow(self
->window
, NULL
, mask
, &attrib
);
167 self
->lgripleft
= createWindow(self
->window
, NULL
, mask
, &attrib
);
168 self
->lgriptop
= createWindow(self
->window
, NULL
, mask
, &attrib
);
169 self
->lgripbottom
= createWindow(self
->window
, NULL
, mask
, &attrib
);
170 self
->rgripright
= createWindow(self
->window
, NULL
, mask
, &attrib
);
171 self
->rgriptop
= createWindow(self
->window
, NULL
, mask
, &attrib
);
172 self
->rgripbottom
= createWindow(self
->window
, NULL
, mask
, &attrib
);
174 self
->focused
= FALSE
;
176 /* the other stuff is shown based on decor settings */
177 XMapWindow(ob_display
, self
->label
);
178 XMapWindow(ob_display
, self
->backback
);
179 XMapWindow(ob_display
, self
->backfront
);
181 self
->max_press
= self
->close_press
= self
->desk_press
=
182 self
->iconify_press
= self
->shade_press
= FALSE
;
183 self
->max_hover
= self
->close_hover
= self
->desk_hover
=
184 self
->iconify_hover
= self
->shade_hover
= FALSE
;
186 set_theme_statics(self
);
188 return (ObFrame
*)self
;
191 static void set_theme_statics(ObFrame
*self
)
193 /* set colors/appearance/sizes for stuff that doesn't change */
194 XResizeWindow(ob_display
, self
->max
,
195 ob_rr_theme
->button_size
, ob_rr_theme
->button_size
);
196 XResizeWindow(ob_display
, self
->iconify
,
197 ob_rr_theme
->button_size
, ob_rr_theme
->button_size
);
198 XResizeWindow(ob_display
, self
->icon
,
199 ob_rr_theme
->button_size
+ 2, ob_rr_theme
->button_size
+ 2);
200 XResizeWindow(ob_display
, self
->close
,
201 ob_rr_theme
->button_size
, ob_rr_theme
->button_size
);
202 XResizeWindow(ob_display
, self
->desk
,
203 ob_rr_theme
->button_size
, ob_rr_theme
->button_size
);
204 XResizeWindow(ob_display
, self
->shade
,
205 ob_rr_theme
->button_size
, ob_rr_theme
->button_size
);
206 XResizeWindow(ob_display
, self
->tltresize
,
207 ob_rr_theme
->grip_width
, ob_rr_theme
->paddingy
+ 1);
208 XResizeWindow(ob_display
, self
->trtresize
,
209 ob_rr_theme
->grip_width
, ob_rr_theme
->paddingy
+ 1);
210 XResizeWindow(ob_display
, self
->tllresize
,
211 ob_rr_theme
->paddingx
+ 1, ob_rr_theme
->title_height
);
212 XResizeWindow(ob_display
, self
->trrresize
,
213 ob_rr_theme
->paddingx
+ 1, ob_rr_theme
->title_height
);
215 /* set up the dynamic appearances */
216 self
->a_unfocused_title
= RrAppearanceCopy(ob_rr_theme
->a_unfocused_title
);
217 self
->a_focused_title
= RrAppearanceCopy(ob_rr_theme
->a_focused_title
);
218 self
->a_unfocused_label
= RrAppearanceCopy(ob_rr_theme
->a_unfocused_label
);
219 self
->a_focused_label
= RrAppearanceCopy(ob_rr_theme
->a_focused_label
);
220 self
->a_unfocused_handle
=
221 RrAppearanceCopy(ob_rr_theme
->a_unfocused_handle
);
222 self
->a_focused_handle
= RrAppearanceCopy(ob_rr_theme
->a_focused_handle
);
223 self
->a_icon
= RrAppearanceCopy(ob_rr_theme
->a_icon
);
226 static void free_theme_statics(ObFrame
*self
)
228 RrAppearanceFree(self
->a_unfocused_title
);
229 RrAppearanceFree(self
->a_focused_title
);
230 RrAppearanceFree(self
->a_unfocused_label
);
231 RrAppearanceFree(self
->a_focused_label
);
232 RrAppearanceFree(self
->a_unfocused_handle
);
233 RrAppearanceFree(self
->a_focused_handle
);
234 RrAppearanceFree(self
->a_icon
);
237 void frame_free(ObFrame
*self
)
239 free_theme_statics(self
);
241 XDestroyWindow(ob_display
, self
->window
);
243 XFreeColormap(ob_display
, self
->colormap
);
248 void frame_show(ObFrame
*self
)
250 if (!self
->visible
) {
251 self
->visible
= TRUE
;
252 framerender_frame(self
);
253 /* Grab the server to make sure that the frame window is mapped before
254 the client gets its MapNotify, i.e. to make sure the client is
255 _visible_ when it gets MapNotify. */
257 XMapWindow(ob_display
, self
->client
->window
);
258 XMapWindow(ob_display
, self
->window
);
263 void frame_hide(ObFrame
*self
)
266 self
->visible
= FALSE
;
267 if (!frame_iconify_animating(self
))
268 XUnmapWindow(ob_display
, self
->window
);
269 /* we unmap the client itself so that we can get MapRequest
270 events, and because the ICCCM tells us to! */
271 XUnmapWindow(ob_display
, self
->client
->window
);
272 self
->client
->ignore_unmaps
+= 1;
276 void frame_adjust_theme(ObFrame
*self
)
278 free_theme_statics(self
);
279 set_theme_statics(self
);
282 void frame_adjust_shape(ObFrame
*self
)
288 if (!self
->client
->shaped
) {
289 /* clear the shape on the frame window */
290 XShapeCombineMask(ob_display
, self
->window
, ShapeBounding
,
295 /* make the frame's shape match the clients */
296 XShapeCombineShape(ob_display
, self
->window
, ShapeBounding
,
299 self
->client
->window
,
300 ShapeBounding
, ShapeSet
);
303 if (self
->decorations
& OB_FRAME_DECOR_TITLEBAR
) {
306 xrect
[0].width
= self
->area
.width
;
307 xrect
[0].height
= self
->size
.top
;
311 if (self
->decorations
& OB_FRAME_DECOR_HANDLE
&&
312 ob_rr_theme
->handle_height
> 0)
315 xrect
[1].y
= FRAME_HANDLE_Y(self
);
316 xrect
[1].width
= self
->area
.width
;
317 xrect
[1].height
= ob_rr_theme
->handle_height
+
322 XShapeCombineRectangles(ob_display
, self
->window
,
323 ShapeBounding
, 0, 0, xrect
, num
,
324 ShapeUnion
, Unsorted
);
329 void frame_adjust_area(ObFrame
*self
, gboolean moved
,
330 gboolean resized
, gboolean fake
)
334 oldsize
= self
->size
;
337 /* do this before changing the frame's status like max_horz max_vert */
338 frame_adjust_cursors(self
);
340 self
->functions
= self
->client
->functions
;
341 self
->decorations
= self
->client
->decorations
;
342 self
->max_horz
= self
->client
->max_horz
;
343 self
->max_vert
= self
->client
->max_vert
;
344 self
->shaded
= self
->client
->shaded
;
346 if (self
->decorations
& OB_FRAME_DECOR_BORDER
||
347 (self
->client
->undecorated
&& config_theme_keepborder
))
348 self
->bwidth
= ob_rr_theme
->fbwidth
;
352 if (self
->decorations
& OB_FRAME_DECOR_BORDER
) {
353 self
->cbwidth_l
= self
->cbwidth_r
= ob_rr_theme
->cbwidthx
;
354 self
->cbwidth_t
= self
->cbwidth_b
= ob_rr_theme
->cbwidthy
;
356 self
->cbwidth_l
= self
->cbwidth_t
=
357 self
->cbwidth_r
= self
->cbwidth_b
= 0;
359 if (self
->max_horz
) {
360 self
->cbwidth_l
= self
->cbwidth_r
= 0;
361 self
->width
= self
->client
->area
.width
;
365 self
->width
= self
->client
->area
.width
+
366 self
->cbwidth_l
+ self
->cbwidth_r
;
368 /* some elements are sized based of the width, so don't let them have
370 self
->width
= MAX(self
->width
,
371 (ob_rr_theme
->grip_width
+ self
->bwidth
) * 2 + 1);
373 STRUT_SET(self
->size
,
374 self
->cbwidth_l
+ (!self
->max_horz
? self
->bwidth
: 0),
375 self
->cbwidth_t
+ self
->bwidth
,
376 self
->cbwidth_r
+ (!self
->max_horz
? self
->bwidth
: 0),
378 (!self
->max_horz
|| !self
->max_vert
? self
->bwidth
: 0));
380 if (self
->decorations
& OB_FRAME_DECOR_TITLEBAR
)
381 self
->size
.top
+= ob_rr_theme
->title_height
+ self
->bwidth
;
382 if (self
->decorations
& OB_FRAME_DECOR_HANDLE
&&
383 ob_rr_theme
->handle_height
> 0)
385 self
->size
.bottom
+= ob_rr_theme
->handle_height
+ self
->bwidth
;
388 /* position/size and map/unmap all the windows */
391 if (self
->cbwidth_l
) {
392 XMoveResizeWindow(ob_display
, self
->innerleft
,
393 self
->size
.left
- self
->cbwidth_l
,
395 self
->cbwidth_l
, self
->client
->area
.height
);
397 XMapWindow(ob_display
, self
->innerleft
);
399 XUnmapWindow(ob_display
, self
->innerleft
);
401 if (self
->cbwidth_r
) {
402 XMoveResizeWindow(ob_display
, self
->innerright
,
403 self
->size
.left
+ self
->client
->area
.width
,
405 self
->cbwidth_r
, self
->client
->area
.height
);
407 XMapWindow(ob_display
, self
->innerright
);
409 XUnmapWindow(ob_display
, self
->innerright
);
411 if (self
->cbwidth_t
) {
412 XMoveResizeWindow(ob_display
, self
->innertop
,
413 self
->size
.left
- self
->cbwidth_l
,
414 self
->size
.top
- self
->cbwidth_t
,
415 self
->client
->area
.width
+
416 self
->cbwidth_l
+ self
->cbwidth_r
,
419 XMapWindow(ob_display
, self
->innertop
);
421 XUnmapWindow(ob_display
, self
->innertop
);
423 if (self
->cbwidth_b
) {
424 XMoveResizeWindow(ob_display
, self
->innerbottom
,
425 self
->size
.left
- self
->cbwidth_l
,
426 self
->size
.top
+ self
->client
->area
.height
,
427 self
->client
->area
.width
+
428 self
->cbwidth_l
+ self
->cbwidth_r
,
431 XMapWindow(ob_display
, self
->innerbottom
);
433 XUnmapWindow(ob_display
, self
->innerbottom
);
438 /* height of titleleft and titleright */
439 titlesides
= (!self
->max_horz
? ob_rr_theme
->grip_width
: 0);
441 XMoveResizeWindow(ob_display
, self
->titletop
,
442 ob_rr_theme
->grip_width
+ self
->bwidth
, 0,
443 /* width + bwidth*2 - bwidth*2 - grips*2 */
444 self
->width
- ob_rr_theme
->grip_width
* 2,
446 XMoveResizeWindow(ob_display
, self
->titletopleft
,
448 ob_rr_theme
->grip_width
+ self
->bwidth
,
450 XMoveResizeWindow(ob_display
, self
->titletopright
,
451 self
->client
->area
.width
+
452 self
->size
.left
+ self
->size
.right
-
453 ob_rr_theme
->grip_width
- self
->bwidth
,
455 ob_rr_theme
->grip_width
+ self
->bwidth
,
458 if (titlesides
> 0) {
459 XMoveResizeWindow(ob_display
, self
->titleleft
,
463 XMoveResizeWindow(ob_display
, self
->titleright
,
464 self
->client
->area
.width
+
465 self
->size
.left
+ self
->size
.right
-
471 XMapWindow(ob_display
, self
->titleleft
);
472 XMapWindow(ob_display
, self
->titleright
);
474 XUnmapWindow(ob_display
, self
->titleleft
);
475 XUnmapWindow(ob_display
, self
->titleright
);
478 XMapWindow(ob_display
, self
->titletop
);
479 XMapWindow(ob_display
, self
->titletopleft
);
480 XMapWindow(ob_display
, self
->titletopright
);
482 if (self
->decorations
& OB_FRAME_DECOR_TITLEBAR
) {
483 XMoveResizeWindow(ob_display
, self
->titlebottom
,
484 (self
->max_horz
? 0 : self
->bwidth
),
485 ob_rr_theme
->title_height
+ self
->bwidth
,
489 XMapWindow(ob_display
, self
->titlebottom
);
491 XUnmapWindow(ob_display
, self
->titlebottom
);
493 XUnmapWindow(ob_display
, self
->titlebottom
);
495 XUnmapWindow(ob_display
, self
->titletop
);
496 XUnmapWindow(ob_display
, self
->titletopleft
);
497 XUnmapWindow(ob_display
, self
->titletopright
);
498 XUnmapWindow(ob_display
, self
->titleleft
);
499 XUnmapWindow(ob_display
, self
->titleright
);
502 if (self
->decorations
& OB_FRAME_DECOR_TITLEBAR
) {
503 XMoveResizeWindow(ob_display
, self
->title
,
504 (self
->max_horz
? 0 : self
->bwidth
),
506 self
->width
, ob_rr_theme
->title_height
);
508 XMapWindow(ob_display
, self
->title
);
510 if (self
->decorations
& OB_FRAME_DECOR_GRIPS
) {
511 XMoveResizeWindow(ob_display
, self
->topresize
,
512 ob_rr_theme
->grip_width
,
514 self
->width
- ob_rr_theme
->grip_width
*2,
515 ob_rr_theme
->paddingy
+ 1);
517 XMoveWindow(ob_display
, self
->tltresize
, 0, 0);
518 XMoveWindow(ob_display
, self
->tllresize
, 0, 0);
519 XMoveWindow(ob_display
, self
->trtresize
,
520 self
->width
- ob_rr_theme
->grip_width
, 0);
521 XMoveWindow(ob_display
, self
->trrresize
,
522 self
->width
- ob_rr_theme
->paddingx
- 1, 0);
524 XMapWindow(ob_display
, self
->topresize
);
525 XMapWindow(ob_display
, self
->tltresize
);
526 XMapWindow(ob_display
, self
->tllresize
);
527 XMapWindow(ob_display
, self
->trtresize
);
528 XMapWindow(ob_display
, self
->trrresize
);
530 XUnmapWindow(ob_display
, self
->topresize
);
531 XUnmapWindow(ob_display
, self
->tltresize
);
532 XUnmapWindow(ob_display
, self
->tllresize
);
533 XUnmapWindow(ob_display
, self
->trtresize
);
534 XUnmapWindow(ob_display
, self
->trrresize
);
537 XUnmapWindow(ob_display
, self
->title
);
540 if ((self
->decorations
& OB_FRAME_DECOR_TITLEBAR
))
541 /* layout the title bar elements */
545 gint sidebwidth
= self
->max_horz
? 0 : self
->bwidth
;
547 if (self
->bwidth
&& self
->size
.bottom
) {
548 XMoveResizeWindow(ob_display
, self
->handlebottom
,
549 ob_rr_theme
->grip_width
+
550 self
->bwidth
+ sidebwidth
,
551 self
->size
.top
+ self
->client
->area
.height
+
552 self
->size
.bottom
- self
->bwidth
,
553 self
->width
- (ob_rr_theme
->grip_width
+
559 XMoveResizeWindow(ob_display
, self
->lgripleft
,
562 self
->client
->area
.height
+
565 ob_rr_theme
->grip_width
:
566 self
->size
.bottom
- self
->cbwidth_b
),
569 ob_rr_theme
->grip_width
:
570 self
->size
.bottom
- self
->cbwidth_b
));
571 XMoveResizeWindow(ob_display
, self
->rgripright
,
573 self
->client
->area
.width
+
574 self
->size
.right
- self
->bwidth
,
576 self
->client
->area
.height
+
579 ob_rr_theme
->grip_width
:
580 self
->size
.bottom
- self
->cbwidth_b
),
583 ob_rr_theme
->grip_width
:
584 self
->size
.bottom
- self
->cbwidth_b
));
586 XMapWindow(ob_display
, self
->lgripleft
);
587 XMapWindow(ob_display
, self
->rgripright
);
589 XUnmapWindow(ob_display
, self
->lgripleft
);
590 XUnmapWindow(ob_display
, self
->rgripright
);
593 XMoveResizeWindow(ob_display
, self
->lgripbottom
,
595 self
->size
.top
+ self
->client
->area
.height
+
596 self
->size
.bottom
- self
->bwidth
,
597 ob_rr_theme
->grip_width
+ self
->bwidth
,
599 XMoveResizeWindow(ob_display
, self
->rgripbottom
,
600 self
->size
.left
+ self
->client
->area
.width
+
601 self
->size
.right
- self
->bwidth
- sidebwidth
-
602 ob_rr_theme
->grip_width
,
603 self
->size
.top
+ self
->client
->area
.height
+
604 self
->size
.bottom
- self
->bwidth
,
605 ob_rr_theme
->grip_width
+ self
->bwidth
,
608 XMapWindow(ob_display
, self
->handlebottom
);
609 XMapWindow(ob_display
, self
->lgripbottom
);
610 XMapWindow(ob_display
, self
->rgripbottom
);
612 if (self
->decorations
& OB_FRAME_DECOR_HANDLE
&&
613 ob_rr_theme
->handle_height
> 0)
615 XMoveResizeWindow(ob_display
, self
->handletop
,
616 ob_rr_theme
->grip_width
+
617 self
->bwidth
+ sidebwidth
,
618 FRAME_HANDLE_Y(self
),
619 self
->width
- (ob_rr_theme
->grip_width
+
622 XMapWindow(ob_display
, self
->handletop
);
624 if (self
->decorations
& OB_FRAME_DECOR_GRIPS
) {
625 XMoveResizeWindow(ob_display
, self
->handleleft
,
626 ob_rr_theme
->grip_width
,
629 ob_rr_theme
->handle_height
);
630 XMoveResizeWindow(ob_display
, self
->handleright
,
632 ob_rr_theme
->grip_width
-
636 ob_rr_theme
->handle_height
);
638 XMoveResizeWindow(ob_display
, self
->lgriptop
,
640 FRAME_HANDLE_Y(self
),
641 ob_rr_theme
->grip_width
+
644 XMoveResizeWindow(ob_display
, self
->rgriptop
,
646 self
->client
->area
.width
+
647 self
->size
.right
- self
->bwidth
-
648 sidebwidth
- ob_rr_theme
->grip_width
,
649 FRAME_HANDLE_Y(self
),
650 ob_rr_theme
->grip_width
+
654 XMapWindow(ob_display
, self
->handleleft
);
655 XMapWindow(ob_display
, self
->handleright
);
656 XMapWindow(ob_display
, self
->lgriptop
);
657 XMapWindow(ob_display
, self
->rgriptop
);
659 XUnmapWindow(ob_display
, self
->handleleft
);
660 XUnmapWindow(ob_display
, self
->handleright
);
661 XUnmapWindow(ob_display
, self
->lgriptop
);
662 XUnmapWindow(ob_display
, self
->rgriptop
);
665 XUnmapWindow(ob_display
, self
->handleleft
);
666 XUnmapWindow(ob_display
, self
->handleright
);
667 XUnmapWindow(ob_display
, self
->lgriptop
);
668 XUnmapWindow(ob_display
, self
->rgriptop
);
670 XUnmapWindow(ob_display
, self
->handletop
);
673 XUnmapWindow(ob_display
, self
->handleleft
);
674 XUnmapWindow(ob_display
, self
->handleright
);
675 XUnmapWindow(ob_display
, self
->lgriptop
);
676 XUnmapWindow(ob_display
, self
->rgriptop
);
678 XUnmapWindow(ob_display
, self
->handletop
);
680 XUnmapWindow(ob_display
, self
->handlebottom
);
681 XUnmapWindow(ob_display
, self
->lgripleft
);
682 XUnmapWindow(ob_display
, self
->rgripright
);
683 XUnmapWindow(ob_display
, self
->lgripbottom
);
684 XUnmapWindow(ob_display
, self
->rgripbottom
);
687 if (self
->decorations
& OB_FRAME_DECOR_HANDLE
&&
688 ob_rr_theme
->handle_height
> 0)
690 XMoveResizeWindow(ob_display
, self
->handle
,
692 FRAME_HANDLE_Y(self
) + self
->bwidth
,
693 self
->width
, ob_rr_theme
->handle_height
);
694 XMapWindow(ob_display
, self
->handle
);
696 if (self
->decorations
& OB_FRAME_DECOR_GRIPS
) {
697 XMoveResizeWindow(ob_display
, self
->lgrip
,
699 ob_rr_theme
->grip_width
,
700 ob_rr_theme
->handle_height
);
701 XMoveResizeWindow(ob_display
, self
->rgrip
,
702 self
->width
- ob_rr_theme
->grip_width
,
704 ob_rr_theme
->grip_width
,
705 ob_rr_theme
->handle_height
);
707 XMapWindow(ob_display
, self
->lgrip
);
708 XMapWindow(ob_display
, self
->rgrip
);
710 XUnmapWindow(ob_display
, self
->lgrip
);
711 XUnmapWindow(ob_display
, self
->rgrip
);
714 XUnmapWindow(ob_display
, self
->lgrip
);
715 XUnmapWindow(ob_display
, self
->rgrip
);
717 XUnmapWindow(ob_display
, self
->handle
);
720 if (self
->bwidth
&& !self
->max_horz
&&
721 (self
->client
->area
.height
+ self
->size
.top
+
722 self
->size
.bottom
) > ob_rr_theme
->grip_width
* 2)
724 XMoveResizeWindow(ob_display
, self
->left
,
726 self
->bwidth
+ ob_rr_theme
->grip_width
,
728 self
->client
->area
.height
+
729 self
->size
.top
+ self
->size
.bottom
-
730 ob_rr_theme
->grip_width
* 2);
732 XMapWindow(ob_display
, self
->left
);
734 XUnmapWindow(ob_display
, self
->left
);
736 if (self
->bwidth
&& !self
->max_horz
&&
737 (self
->client
->area
.height
+ self
->size
.top
+
738 self
->size
.bottom
) > ob_rr_theme
->grip_width
* 2)
740 XMoveResizeWindow(ob_display
, self
->right
,
741 self
->client
->area
.width
+ self
->cbwidth_l
+
742 self
->cbwidth_r
+ self
->bwidth
,
743 self
->bwidth
+ ob_rr_theme
->grip_width
,
745 self
->client
->area
.height
+
746 self
->size
.top
+ self
->size
.bottom
-
747 ob_rr_theme
->grip_width
* 2);
749 XMapWindow(ob_display
, self
->right
);
751 XUnmapWindow(ob_display
, self
->right
);
753 XMoveResizeWindow(ob_display
, self
->backback
,
754 self
->size
.left
, self
->size
.top
,
755 self
->client
->area
.width
,
756 self
->client
->area
.height
);
760 /* shading can change without being moved or resized */
761 RECT_SET_SIZE(self
->area
,
762 self
->client
->area
.width
+
763 self
->size
.left
+ self
->size
.right
,
764 (self
->client
->shaded
?
765 ob_rr_theme
->title_height
+ self
->bwidth
* 2:
766 self
->client
->area
.height
+
767 self
->size
.top
+ self
->size
.bottom
));
769 if ((moved
|| resized
) && !fake
) {
770 /* find the new coordinates, done after setting the frame.size, for
771 frame_client_gravity. */
772 self
->area
.x
= self
->client
->area
.x
;
773 self
->area
.y
= self
->client
->area
.y
;
774 frame_client_gravity(self
, &self
->area
.x
, &self
->area
.y
);
778 if (!frame_iconify_animating(self
))
779 /* move and resize the top level frame.
780 shading can change without being moved or resized.
782 but don't do this during an iconify animation. it will be
783 reflected afterwards.
785 XMoveResizeWindow(ob_display
, self
->window
,
791 /* when the client has StaticGravity, it likes to move around.
792 also this correctly positions the client when it maps.
793 this also needs to be run when the frame's decorations sizes change!
795 XMoveWindow(ob_display
, self
->client
->window
,
796 self
->size
.left
, self
->size
.top
);
799 self
->need_render
= TRUE
;
800 framerender_frame(self
);
801 frame_adjust_shape(self
);
804 if (!STRUT_EQUAL(self
->size
, oldsize
)) {
806 vals
[0] = self
->size
.left
;
807 vals
[1] = self
->size
.right
;
808 vals
[2] = self
->size
.top
;
809 vals
[3] = self
->size
.bottom
;
810 PROP_SETA32(self
->client
->window
, net_frame_extents
,
812 PROP_SETA32(self
->client
->window
, kde_net_wm_frame_strut
,
816 /* if this occurs while we are focus cycling, the indicator needs to
818 if (focus_cycle_target
== self
->client
)
819 focus_cycle_draw_indicator(self
->client
);
821 if (resized
&& (self
->decorations
& OB_FRAME_DECOR_TITLEBAR
))
822 XResizeWindow(ob_display
, self
->label
, self
->label_width
,
823 ob_rr_theme
->label_height
);
827 static void frame_adjust_cursors(ObFrame
*self
)
829 if ((self
->functions
& OB_CLIENT_FUNC_RESIZE
) !=
830 (self
->client
->functions
& OB_CLIENT_FUNC_RESIZE
) ||
831 self
->max_horz
!= self
->client
->max_horz
||
832 self
->max_vert
!= self
->client
->max_vert
||
833 self
->shaded
!= self
->client
->shaded
)
835 gboolean r
= (self
->client
->functions
& OB_CLIENT_FUNC_RESIZE
) &&
836 !(self
->client
->max_horz
&& self
->client
->max_vert
);
837 gboolean topbot
= !self
->client
->max_vert
;
838 gboolean sh
= self
->client
->shaded
;
839 XSetWindowAttributes a
;
841 /* these ones turn off when max vert, and some when shaded */
842 a
.cursor
= ob_cursor(r
&& topbot
&& !sh
?
843 OB_CURSOR_NORTH
: OB_CURSOR_NONE
);
844 XChangeWindowAttributes(ob_display
, self
->topresize
, CWCursor
, &a
);
845 XChangeWindowAttributes(ob_display
, self
->titletop
, CWCursor
, &a
);
846 a
.cursor
= ob_cursor(r
&& topbot
? OB_CURSOR_SOUTH
: OB_CURSOR_NONE
);
847 XChangeWindowAttributes(ob_display
, self
->handle
, CWCursor
, &a
);
848 XChangeWindowAttributes(ob_display
, self
->handletop
, CWCursor
, &a
);
849 XChangeWindowAttributes(ob_display
, self
->handlebottom
, CWCursor
, &a
);
850 XChangeWindowAttributes(ob_display
, self
->innerbottom
, CWCursor
, &a
);
852 /* these ones change when shaded */
853 a
.cursor
= ob_cursor(r
? (sh
? OB_CURSOR_WEST
: OB_CURSOR_NORTHWEST
) :
855 XChangeWindowAttributes(ob_display
, self
->titleleft
, CWCursor
, &a
);
856 XChangeWindowAttributes(ob_display
, self
->tltresize
, CWCursor
, &a
);
857 XChangeWindowAttributes(ob_display
, self
->tllresize
, CWCursor
, &a
);
858 XChangeWindowAttributes(ob_display
, self
->titletopleft
, CWCursor
, &a
);
859 a
.cursor
= ob_cursor(r
? (sh
? OB_CURSOR_EAST
: OB_CURSOR_NORTHEAST
) :
861 XChangeWindowAttributes(ob_display
, self
->titleright
, CWCursor
, &a
);
862 XChangeWindowAttributes(ob_display
, self
->trtresize
, CWCursor
, &a
);
863 XChangeWindowAttributes(ob_display
, self
->trrresize
, CWCursor
, &a
);
864 XChangeWindowAttributes(ob_display
, self
->titletopright
, CWCursor
, &a
);
866 /* these ones are pretty static */
867 a
.cursor
= ob_cursor(r
? OB_CURSOR_WEST
: OB_CURSOR_NONE
);
868 XChangeWindowAttributes(ob_display
, self
->left
, CWCursor
, &a
);
869 XChangeWindowAttributes(ob_display
, self
->innerleft
, CWCursor
, &a
);
870 a
.cursor
= ob_cursor(r
? OB_CURSOR_EAST
: OB_CURSOR_NONE
);
871 XChangeWindowAttributes(ob_display
, self
->right
, CWCursor
, &a
);
872 XChangeWindowAttributes(ob_display
, self
->innerright
, CWCursor
, &a
);
873 a
.cursor
= ob_cursor(r
? OB_CURSOR_SOUTHWEST
: OB_CURSOR_NONE
);
874 XChangeWindowAttributes(ob_display
, self
->lgrip
, CWCursor
, &a
);
875 XChangeWindowAttributes(ob_display
, self
->handleleft
, CWCursor
, &a
);
876 XChangeWindowAttributes(ob_display
, self
->lgripleft
, CWCursor
, &a
);
877 XChangeWindowAttributes(ob_display
, self
->lgriptop
, CWCursor
, &a
);
878 XChangeWindowAttributes(ob_display
, self
->lgripbottom
, CWCursor
, &a
);
879 a
.cursor
= ob_cursor(r
? OB_CURSOR_SOUTHEAST
: OB_CURSOR_NONE
);
880 XChangeWindowAttributes(ob_display
, self
->rgrip
, CWCursor
, &a
);
881 XChangeWindowAttributes(ob_display
, self
->handleright
, CWCursor
, &a
);
882 XChangeWindowAttributes(ob_display
, self
->rgripright
, CWCursor
, &a
);
883 XChangeWindowAttributes(ob_display
, self
->rgriptop
, CWCursor
, &a
);
884 XChangeWindowAttributes(ob_display
, self
->rgripbottom
, CWCursor
, &a
);
888 void frame_adjust_client_area(ObFrame
*self
)
890 /* adjust the window which is there to prevent flashing on unmap */
891 XMoveResizeWindow(ob_display
, self
->backfront
, 0, 0,
892 self
->client
->area
.width
,
893 self
->client
->area
.height
);
896 void frame_adjust_state(ObFrame
*self
)
898 self
->need_render
= TRUE
;
899 framerender_frame(self
);
902 void frame_adjust_focus(ObFrame
*self
, gboolean hilite
)
904 self
->focused
= hilite
;
905 self
->need_render
= TRUE
;
906 framerender_frame(self
);
910 void frame_adjust_title(ObFrame
*self
)
912 self
->need_render
= TRUE
;
913 framerender_frame(self
);
916 void frame_adjust_icon(ObFrame
*self
)
918 self
->need_render
= TRUE
;
919 framerender_frame(self
);
922 void frame_grab_client(ObFrame
*self
)
924 /* DO NOT map the client window here. we used to do that, but it is bogus.
925 we need to set up the client's dimensions and everything before we
926 send a mapnotify or we create race conditions.
929 /* reparent the client to the frame */
930 XReparentWindow(ob_display
, self
->client
->window
, self
->window
, 0, 0);
933 When reparenting the client window, it is usually not mapped yet, since
934 this occurs from a MapRequest. However, in the case where Openbox is
935 starting up, the window is already mapped, so we'll see an unmap event
938 if (ob_state() == OB_STATE_STARTING
)
939 ++self
->client
->ignore_unmaps
;
941 /* select the event mask on the client's parent (to receive config/map
942 req's) the ButtonPress is to catch clicks on the client border */
943 XSelectInput(ob_display
, self
->window
, FRAME_EVENTMASK
);
945 /* set all the windows for the frame in the window_map */
946 g_hash_table_insert(window_map
, &self
->window
, self
->client
);
947 g_hash_table_insert(window_map
, &self
->backback
, self
->client
);
948 g_hash_table_insert(window_map
, &self
->backfront
, self
->client
);
949 g_hash_table_insert(window_map
, &self
->innerleft
, self
->client
);
950 g_hash_table_insert(window_map
, &self
->innertop
, self
->client
);
951 g_hash_table_insert(window_map
, &self
->innerright
, self
->client
);
952 g_hash_table_insert(window_map
, &self
->innerbottom
, self
->client
);
953 g_hash_table_insert(window_map
, &self
->title
, self
->client
);
954 g_hash_table_insert(window_map
, &self
->label
, self
->client
);
955 g_hash_table_insert(window_map
, &self
->max
, self
->client
);
956 g_hash_table_insert(window_map
, &self
->close
, self
->client
);
957 g_hash_table_insert(window_map
, &self
->desk
, self
->client
);
958 g_hash_table_insert(window_map
, &self
->shade
, self
->client
);
959 g_hash_table_insert(window_map
, &self
->icon
, self
->client
);
960 g_hash_table_insert(window_map
, &self
->iconify
, self
->client
);
961 g_hash_table_insert(window_map
, &self
->handle
, self
->client
);
962 g_hash_table_insert(window_map
, &self
->lgrip
, self
->client
);
963 g_hash_table_insert(window_map
, &self
->rgrip
, self
->client
);
964 g_hash_table_insert(window_map
, &self
->topresize
, self
->client
);
965 g_hash_table_insert(window_map
, &self
->tltresize
, self
->client
);
966 g_hash_table_insert(window_map
, &self
->tllresize
, self
->client
);
967 g_hash_table_insert(window_map
, &self
->trtresize
, self
->client
);
968 g_hash_table_insert(window_map
, &self
->trrresize
, self
->client
);
969 g_hash_table_insert(window_map
, &self
->left
, self
->client
);
970 g_hash_table_insert(window_map
, &self
->right
, self
->client
);
971 g_hash_table_insert(window_map
, &self
->titleleft
, self
->client
);
972 g_hash_table_insert(window_map
, &self
->titletop
, self
->client
);
973 g_hash_table_insert(window_map
, &self
->titletopleft
, self
->client
);
974 g_hash_table_insert(window_map
, &self
->titletopright
, self
->client
);
975 g_hash_table_insert(window_map
, &self
->titleright
, self
->client
);
976 g_hash_table_insert(window_map
, &self
->titlebottom
, self
->client
);
977 g_hash_table_insert(window_map
, &self
->handleleft
, self
->client
);
978 g_hash_table_insert(window_map
, &self
->handletop
, self
->client
);
979 g_hash_table_insert(window_map
, &self
->handleright
, self
->client
);
980 g_hash_table_insert(window_map
, &self
->handlebottom
, self
->client
);
981 g_hash_table_insert(window_map
, &self
->lgripleft
, self
->client
);
982 g_hash_table_insert(window_map
, &self
->lgriptop
, self
->client
);
983 g_hash_table_insert(window_map
, &self
->lgripbottom
, self
->client
);
984 g_hash_table_insert(window_map
, &self
->rgripright
, self
->client
);
985 g_hash_table_insert(window_map
, &self
->rgriptop
, self
->client
);
986 g_hash_table_insert(window_map
, &self
->rgripbottom
, self
->client
);
989 void frame_release_client(ObFrame
*self
)
992 gboolean reparent
= TRUE
;
994 /* if there was any animation going on, kill it */
995 ob_main_loop_timeout_remove_data(ob_main_loop
, frame_animate_iconify
,
998 /* check if the app has already reparented its window away */
999 while (XCheckTypedWindowEvent(ob_display
, self
->client
->window
,
1000 ReparentNotify
, &ev
))
1002 /* This check makes sure we don't catch our own reparent action to
1003 our frame window. This doesn't count as the app reparenting itself
1006 Reparent events that are generated by us are just discarded here.
1007 They are of no consequence to us anyhow.
1009 if (ev
.xreparent
.parent
!= self
->window
) {
1011 XPutBackEvent(ob_display
, &ev
);
1017 /* according to the ICCCM - if the client doesn't reparent itself,
1018 then we will reparent the window to root for them */
1019 XReparentWindow(ob_display
, self
->client
->window
,
1020 RootWindow(ob_display
, ob_screen
),
1021 self
->client
->area
.x
,
1022 self
->client
->area
.y
);
1025 /* remove all the windows for the frame from the window_map */
1026 g_hash_table_remove(window_map
, &self
->window
);
1027 g_hash_table_remove(window_map
, &self
->backback
);
1028 g_hash_table_remove(window_map
, &self
->backfront
);
1029 g_hash_table_remove(window_map
, &self
->innerleft
);
1030 g_hash_table_remove(window_map
, &self
->innertop
);
1031 g_hash_table_remove(window_map
, &self
->innerright
);
1032 g_hash_table_remove(window_map
, &self
->innerbottom
);
1033 g_hash_table_remove(window_map
, &self
->title
);
1034 g_hash_table_remove(window_map
, &self
->label
);
1035 g_hash_table_remove(window_map
, &self
->max
);
1036 g_hash_table_remove(window_map
, &self
->close
);
1037 g_hash_table_remove(window_map
, &self
->desk
);
1038 g_hash_table_remove(window_map
, &self
->shade
);
1039 g_hash_table_remove(window_map
, &self
->icon
);
1040 g_hash_table_remove(window_map
, &self
->iconify
);
1041 g_hash_table_remove(window_map
, &self
->handle
);
1042 g_hash_table_remove(window_map
, &self
->lgrip
);
1043 g_hash_table_remove(window_map
, &self
->rgrip
);
1044 g_hash_table_remove(window_map
, &self
->topresize
);
1045 g_hash_table_remove(window_map
, &self
->tltresize
);
1046 g_hash_table_remove(window_map
, &self
->tllresize
);
1047 g_hash_table_remove(window_map
, &self
->trtresize
);
1048 g_hash_table_remove(window_map
, &self
->trrresize
);
1049 g_hash_table_remove(window_map
, &self
->left
);
1050 g_hash_table_remove(window_map
, &self
->right
);
1051 g_hash_table_remove(window_map
, &self
->titleleft
);
1052 g_hash_table_remove(window_map
, &self
->titletop
);
1053 g_hash_table_remove(window_map
, &self
->titletopleft
);
1054 g_hash_table_remove(window_map
, &self
->titletopright
);
1055 g_hash_table_remove(window_map
, &self
->titleright
);
1056 g_hash_table_remove(window_map
, &self
->titlebottom
);
1057 g_hash_table_remove(window_map
, &self
->handleleft
);
1058 g_hash_table_remove(window_map
, &self
->handletop
);
1059 g_hash_table_remove(window_map
, &self
->handleright
);
1060 g_hash_table_remove(window_map
, &self
->handlebottom
);
1061 g_hash_table_remove(window_map
, &self
->lgripleft
);
1062 g_hash_table_remove(window_map
, &self
->lgriptop
);
1063 g_hash_table_remove(window_map
, &self
->lgripbottom
);
1064 g_hash_table_remove(window_map
, &self
->rgripright
);
1065 g_hash_table_remove(window_map
, &self
->rgriptop
);
1066 g_hash_table_remove(window_map
, &self
->rgripbottom
);
1068 ob_main_loop_timeout_remove_data(ob_main_loop
, flash_timeout
, self
, TRUE
);
1071 /* is there anything present between us and the label? */
1072 static gboolean
is_button_present(ObFrame
*self
, const gchar
*lc
, gint dir
) {
1073 for (; *lc
!= '\0' && lc
>= config_title_layout
; lc
+= dir
) {
1074 if (*lc
== ' ') continue; /* it was invalid */
1075 if (*lc
== 'N' && self
->decorations
& OB_FRAME_DECOR_ICON
)
1077 if (*lc
== 'D' && self
->decorations
& OB_FRAME_DECOR_ALLDESKTOPS
)
1079 if (*lc
== 'S' && self
->decorations
& OB_FRAME_DECOR_SHADE
)
1081 if (*lc
== 'I' && self
->decorations
& OB_FRAME_DECOR_ICONIFY
)
1083 if (*lc
== 'M' && self
->decorations
& OB_FRAME_DECOR_MAXIMIZE
)
1085 if (*lc
== 'C' && self
->decorations
& OB_FRAME_DECOR_CLOSE
)
1087 if (*lc
== 'L') return FALSE
;
1092 static void layout_title(ObFrame
*self
)
1097 const gint bwidth
= ob_rr_theme
->button_size
+ ob_rr_theme
->paddingx
+ 1;
1098 /* position of the left most button */
1099 const gint left
= ob_rr_theme
->paddingx
+ 1;
1100 /* position of the right most button */
1101 const gint right
= self
->width
;
1103 /* turn them all off */
1104 self
->icon_on
= self
->desk_on
= self
->shade_on
= self
->iconify_on
=
1105 self
->max_on
= self
->close_on
= self
->label_on
= FALSE
;
1106 self
->label_width
= self
->width
- (ob_rr_theme
->paddingx
+ 1) * 2;
1107 self
->leftmost
= self
->rightmost
= OB_FRAME_CONTEXT_NONE
;
1109 /* figure out what's being show, find each element's position, and the
1112 do the ones before the label, then after the label,
1113 i will be +1 the first time through when working to the left,
1114 and -1 the second time through when working to the right */
1115 for (i
= 1; i
>= -1; i
-=2) {
1117 ObFrameContext
*firstcon
;
1121 lc
= config_title_layout
;
1122 firstcon
= &self
->leftmost
;
1125 lc
= config_title_layout
+ strlen(config_title_layout
)-1;
1126 firstcon
= &self
->rightmost
;
1129 /* stop at the end of the string (or the label, which calls break) */
1130 for (; *lc
!= '\0' && lc
>= config_title_layout
; lc
+=i
) {
1133 self
->label_on
= TRUE
;
1136 break; /* break the for loop, do other side of label */
1137 } else if (*lc
== 'N') {
1138 if (firstcon
) *firstcon
= OB_FRAME_CONTEXT_ICON
;
1139 if ((self
->icon_on
= is_button_present(self
, lc
, i
))) {
1140 /* icon is bigger than buttons */
1141 self
->label_width
-= bwidth
+ 2;
1142 if (i
> 0) self
->icon_x
= x
;
1143 x
+= i
* (bwidth
+ 2);
1144 if (i
< 0) self
->icon_x
= x
;
1146 } else if (*lc
== 'D') {
1147 if (firstcon
) *firstcon
= OB_FRAME_CONTEXT_ALLDESKTOPS
;
1148 if ((self
->desk_on
= is_button_present(self
, lc
, i
))) {
1149 self
->label_width
-= bwidth
;
1150 if (i
> 0) self
->desk_x
= x
;
1152 if (i
< 0) self
->desk_x
= x
;
1154 } else if (*lc
== 'S') {
1155 if (firstcon
) *firstcon
= OB_FRAME_CONTEXT_SHADE
;
1156 if ((self
->shade_on
= is_button_present(self
, lc
, i
))) {
1157 self
->label_width
-= bwidth
;
1158 if (i
> 0) self
->shade_x
= x
;
1160 if (i
< 0) self
->shade_x
= x
;
1162 } else if (*lc
== 'I') {
1163 if (firstcon
) *firstcon
= OB_FRAME_CONTEXT_ICONIFY
;
1164 if ((self
->iconify_on
= is_button_present(self
, lc
, i
))) {
1165 self
->label_width
-= bwidth
;
1166 if (i
> 0) self
->iconify_x
= x
;
1168 if (i
< 0) self
->iconify_x
= x
;
1170 } else if (*lc
== 'M') {
1171 if (firstcon
) *firstcon
= OB_FRAME_CONTEXT_MAXIMIZE
;
1172 if ((self
->max_on
= is_button_present(self
, lc
, i
))) {
1173 self
->label_width
-= bwidth
;
1174 if (i
> 0) self
->max_x
= x
;
1176 if (i
< 0) self
->max_x
= x
;
1178 } else if (*lc
== 'C') {
1179 if (firstcon
) *firstcon
= OB_FRAME_CONTEXT_CLOSE
;
1180 if ((self
->close_on
= is_button_present(self
, lc
, i
))) {
1181 self
->label_width
-= bwidth
;
1182 if (i
> 0) self
->close_x
= x
;
1184 if (i
< 0) self
->close_x
= x
;
1187 continue; /* don't set firstcon */
1192 /* position and map the elements */
1193 if (self
->icon_on
) {
1194 XMapWindow(ob_display
, self
->icon
);
1195 XMoveWindow(ob_display
, self
->icon
, self
->icon_x
,
1196 ob_rr_theme
->paddingy
);
1198 XUnmapWindow(ob_display
, self
->icon
);
1200 if (self
->desk_on
) {
1201 XMapWindow(ob_display
, self
->desk
);
1202 XMoveWindow(ob_display
, self
->desk
, self
->desk_x
,
1203 ob_rr_theme
->paddingy
+ 1);
1205 XUnmapWindow(ob_display
, self
->desk
);
1207 if (self
->shade_on
) {
1208 XMapWindow(ob_display
, self
->shade
);
1209 XMoveWindow(ob_display
, self
->shade
, self
->shade_x
,
1210 ob_rr_theme
->paddingy
+ 1);
1212 XUnmapWindow(ob_display
, self
->shade
);
1214 if (self
->iconify_on
) {
1215 XMapWindow(ob_display
, self
->iconify
);
1216 XMoveWindow(ob_display
, self
->iconify
, self
->iconify_x
,
1217 ob_rr_theme
->paddingy
+ 1);
1219 XUnmapWindow(ob_display
, self
->iconify
);
1222 XMapWindow(ob_display
, self
->max
);
1223 XMoveWindow(ob_display
, self
->max
, self
->max_x
,
1224 ob_rr_theme
->paddingy
+ 1);
1226 XUnmapWindow(ob_display
, self
->max
);
1228 if (self
->close_on
) {
1229 XMapWindow(ob_display
, self
->close
);
1230 XMoveWindow(ob_display
, self
->close
, self
->close_x
,
1231 ob_rr_theme
->paddingy
+ 1);
1233 XUnmapWindow(ob_display
, self
->close
);
1235 if (self
->label_on
) {
1236 self
->label_width
= MAX(1, self
->label_width
); /* no lower than 1 */
1237 XMapWindow(ob_display
, self
->label
);
1238 XMoveWindow(ob_display
, self
->label
, self
->label_x
,
1239 ob_rr_theme
->paddingy
);
1241 XUnmapWindow(ob_display
, self
->label
);
1244 ObFrameContext
frame_context_from_string(const gchar
*name
)
1246 if (!g_ascii_strcasecmp("Desktop", name
))
1247 return OB_FRAME_CONTEXT_DESKTOP
;
1248 else if (!g_ascii_strcasecmp("Root", name
))
1249 return OB_FRAME_CONTEXT_ROOT
;
1250 else if (!g_ascii_strcasecmp("Client", name
))
1251 return OB_FRAME_CONTEXT_CLIENT
;
1252 else if (!g_ascii_strcasecmp("Titlebar", name
))
1253 return OB_FRAME_CONTEXT_TITLEBAR
;
1254 else if (!g_ascii_strcasecmp("Frame", name
))
1255 return OB_FRAME_CONTEXT_FRAME
;
1256 else if (!g_ascii_strcasecmp("TLCorner", name
))
1257 return OB_FRAME_CONTEXT_TLCORNER
;
1258 else if (!g_ascii_strcasecmp("TRCorner", name
))
1259 return OB_FRAME_CONTEXT_TRCORNER
;
1260 else if (!g_ascii_strcasecmp("BLCorner", name
))
1261 return OB_FRAME_CONTEXT_BLCORNER
;
1262 else if (!g_ascii_strcasecmp("BRCorner", name
))
1263 return OB_FRAME_CONTEXT_BRCORNER
;
1264 else if (!g_ascii_strcasecmp("Top", name
))
1265 return OB_FRAME_CONTEXT_TOP
;
1266 else if (!g_ascii_strcasecmp("Bottom", name
))
1267 return OB_FRAME_CONTEXT_BOTTOM
;
1268 else if (!g_ascii_strcasecmp("Left", name
))
1269 return OB_FRAME_CONTEXT_LEFT
;
1270 else if (!g_ascii_strcasecmp("Right", name
))
1271 return OB_FRAME_CONTEXT_RIGHT
;
1272 else if (!g_ascii_strcasecmp("Maximize", name
))
1273 return OB_FRAME_CONTEXT_MAXIMIZE
;
1274 else if (!g_ascii_strcasecmp("AllDesktops", name
))
1275 return OB_FRAME_CONTEXT_ALLDESKTOPS
;
1276 else if (!g_ascii_strcasecmp("Shade", name
))
1277 return OB_FRAME_CONTEXT_SHADE
;
1278 else if (!g_ascii_strcasecmp("Iconify", name
))
1279 return OB_FRAME_CONTEXT_ICONIFY
;
1280 else if (!g_ascii_strcasecmp("Icon", name
))
1281 return OB_FRAME_CONTEXT_ICON
;
1282 else if (!g_ascii_strcasecmp("Close", name
))
1283 return OB_FRAME_CONTEXT_CLOSE
;
1284 else if (!g_ascii_strcasecmp("MoveResize", name
))
1285 return OB_FRAME_CONTEXT_MOVE_RESIZE
;
1286 return OB_FRAME_CONTEXT_NONE
;
1289 ObFrameContext
frame_context(ObClient
*client
, Window win
, gint x
, gint y
)
1293 if (moveresize_in_progress
)
1294 return OB_FRAME_CONTEXT_MOVE_RESIZE
;
1296 if (win
== RootWindow(ob_display
, ob_screen
))
1297 return OB_FRAME_CONTEXT_ROOT
;
1298 if (client
== NULL
) return OB_FRAME_CONTEXT_NONE
;
1299 if (win
== client
->window
) {
1300 /* conceptually, this is the desktop, as far as users are
1302 if (client
->type
== OB_CLIENT_TYPE_DESKTOP
)
1303 return OB_FRAME_CONTEXT_DESKTOP
;
1304 return OB_FRAME_CONTEXT_CLIENT
;
1307 self
= client
->frame
;
1309 /* when the user clicks in the corners of the titlebar and the client
1310 is fully maximized, then treat it like they clicked in the
1311 button that is there */
1312 if (self
->max_horz
&& self
->max_vert
&&
1313 (win
== self
->title
|| win
== self
->titletop
||
1314 win
== self
->titleleft
|| win
== self
->titletopleft
||
1315 win
== self
->titleright
|| win
== self
->titletopright
))
1317 /* get the mouse coords in reference to the whole frame */
1321 /* these windows are down a border width from the top of the frame */
1322 if (win
== self
->title
||
1323 win
== self
->titleleft
|| win
== self
->titleright
)
1326 /* title is a border width in from the edge */
1327 if (win
== self
->title
)
1329 /* titletop is a bit to the right */
1330 else if (win
== self
->titletop
)
1331 fx
+= ob_rr_theme
->grip_width
+ self
->bwidth
;
1332 /* titletopright is way to the right edge */
1333 else if (win
== self
->titletopright
)
1334 fx
+= self
->area
.width
- (ob_rr_theme
->grip_width
+ self
->bwidth
);
1335 /* titleright is even more way to the right edge */
1336 else if (win
== self
->titleright
)
1337 fx
+= self
->area
.width
- self
->bwidth
;
1339 /* figure out if we're over the area that should be considered a
1341 if (fy
< self
->bwidth
+ ob_rr_theme
->paddingy
+ 1 +
1342 ob_rr_theme
->button_size
)
1344 if (fx
< (self
->bwidth
+ ob_rr_theme
->paddingx
+ 1 +
1345 ob_rr_theme
->button_size
))
1347 if (self
->leftmost
!= OB_FRAME_CONTEXT_NONE
)
1348 return self
->leftmost
;
1350 else if (fx
>= (self
->area
.width
-
1351 (self
->bwidth
+ ob_rr_theme
->paddingx
+ 1 +
1352 ob_rr_theme
->button_size
)))
1354 if (self
->rightmost
!= OB_FRAME_CONTEXT_NONE
)
1355 return self
->rightmost
;
1359 /* there is no resizing maximized windows so make them the titlebar
1361 return OB_FRAME_CONTEXT_TITLEBAR
;
1363 else if (self
->max_vert
&&
1364 (win
== self
->titletop
|| win
== self
->topresize
))
1365 /* can't resize vertically when max vert */
1366 return OB_FRAME_CONTEXT_TITLEBAR
;
1367 else if (self
->shaded
&&
1368 (win
== self
->titletop
|| win
== self
->topresize
))
1369 /* can't resize vertically when shaded */
1370 return OB_FRAME_CONTEXT_TITLEBAR
;
1372 if (win
== self
->window
) return OB_FRAME_CONTEXT_FRAME
;
1373 if (win
== self
->label
) return OB_FRAME_CONTEXT_TITLEBAR
;
1374 if (win
== self
->handle
) return OB_FRAME_CONTEXT_BOTTOM
;
1375 if (win
== self
->handletop
) return OB_FRAME_CONTEXT_BOTTOM
;
1376 if (win
== self
->handlebottom
) return OB_FRAME_CONTEXT_BOTTOM
;
1377 if (win
== self
->handleleft
) return OB_FRAME_CONTEXT_BLCORNER
;
1378 if (win
== self
->lgrip
) return OB_FRAME_CONTEXT_BLCORNER
;
1379 if (win
== self
->lgripleft
) return OB_FRAME_CONTEXT_BLCORNER
;
1380 if (win
== self
->lgriptop
) return OB_FRAME_CONTEXT_BLCORNER
;
1381 if (win
== self
->lgripbottom
) return OB_FRAME_CONTEXT_BLCORNER
;
1382 if (win
== self
->handleright
) return OB_FRAME_CONTEXT_BRCORNER
;
1383 if (win
== self
->rgrip
) return OB_FRAME_CONTEXT_BRCORNER
;
1384 if (win
== self
->rgripright
) return OB_FRAME_CONTEXT_BLCORNER
;
1385 if (win
== self
->rgriptop
) return OB_FRAME_CONTEXT_BLCORNER
;
1386 if (win
== self
->rgripbottom
) return OB_FRAME_CONTEXT_BLCORNER
;
1387 if (win
== self
->title
) return OB_FRAME_CONTEXT_TITLEBAR
;
1388 if (win
== self
->titlebottom
) return OB_FRAME_CONTEXT_TITLEBAR
;
1389 if (win
== self
->titleleft
) return OB_FRAME_CONTEXT_TLCORNER
;
1390 if (win
== self
->titletopleft
) return OB_FRAME_CONTEXT_TLCORNER
;
1391 if (win
== self
->titleright
) return OB_FRAME_CONTEXT_TRCORNER
;
1392 if (win
== self
->titletopright
) return OB_FRAME_CONTEXT_TRCORNER
;
1393 if (win
== self
->titletop
) return OB_FRAME_CONTEXT_TOP
;
1394 if (win
== self
->topresize
) return OB_FRAME_CONTEXT_TOP
;
1395 if (win
== self
->tltresize
) return OB_FRAME_CONTEXT_TLCORNER
;
1396 if (win
== self
->tllresize
) return OB_FRAME_CONTEXT_TLCORNER
;
1397 if (win
== self
->trtresize
) return OB_FRAME_CONTEXT_TRCORNER
;
1398 if (win
== self
->trrresize
) return OB_FRAME_CONTEXT_TRCORNER
;
1399 if (win
== self
->left
) return OB_FRAME_CONTEXT_LEFT
;
1400 if (win
== self
->right
) return OB_FRAME_CONTEXT_RIGHT
;
1401 if (win
== self
->innertop
) return OB_FRAME_CONTEXT_TITLEBAR
;
1402 if (win
== self
->innerleft
) return OB_FRAME_CONTEXT_LEFT
;
1403 if (win
== self
->innerbottom
) return OB_FRAME_CONTEXT_BOTTOM
;
1404 if (win
== self
->innerright
) return OB_FRAME_CONTEXT_RIGHT
;
1405 if (win
== self
->max
) return OB_FRAME_CONTEXT_MAXIMIZE
;
1406 if (win
== self
->iconify
) return OB_FRAME_CONTEXT_ICONIFY
;
1407 if (win
== self
->close
) return OB_FRAME_CONTEXT_CLOSE
;
1408 if (win
== self
->icon
) return OB_FRAME_CONTEXT_ICON
;
1409 if (win
== self
->desk
) return OB_FRAME_CONTEXT_ALLDESKTOPS
;
1410 if (win
== self
->shade
) return OB_FRAME_CONTEXT_SHADE
;
1412 return OB_FRAME_CONTEXT_NONE
;
1415 void frame_client_gravity(ObFrame
*self
, gint
*x
, gint
*y
)
1418 switch (self
->client
->gravity
) {
1420 case NorthWestGravity
:
1421 case SouthWestGravity
:
1428 /* the middle of the client will be the middle of the frame */
1429 *x
-= (self
->size
.right
- self
->size
.left
) / 2;
1432 case NorthEastGravity
:
1433 case SouthEastGravity
:
1435 /* the right side of the client will be the right side of the frame */
1436 *x
-= self
->size
.right
+ self
->size
.left
-
1437 self
->client
->border_width
* 2;
1442 /* the client's position won't move */
1443 *x
-= self
->size
.left
- self
->client
->border_width
;
1448 switch (self
->client
->gravity
) {
1450 case NorthWestGravity
:
1451 case NorthEastGravity
:
1458 /* the middle of the client will be the middle of the frame */
1459 *y
-= (self
->size
.bottom
- self
->size
.top
) / 2;
1462 case SouthWestGravity
:
1463 case SouthEastGravity
:
1465 /* the bottom of the client will be the bottom of the frame */
1466 *y
-= self
->size
.bottom
+ self
->size
.top
-
1467 self
->client
->border_width
* 2;
1472 /* the client's position won't move */
1473 *y
-= self
->size
.top
- self
->client
->border_width
;
1478 void frame_frame_gravity(ObFrame
*self
, gint
*x
, gint
*y
)
1481 switch (self
->client
->gravity
) {
1483 case NorthWestGravity
:
1485 case SouthWestGravity
:
1490 /* the middle of the client will be the middle of the frame */
1491 *x
+= (self
->size
.right
- self
->size
.left
) / 2;
1493 case NorthEastGravity
:
1495 case SouthEastGravity
:
1496 /* the right side of the client will be the right side of the frame */
1497 *x
+= self
->size
.right
+ self
->size
.left
-
1498 self
->client
->border_width
* 2;
1502 /* the client's position won't move */
1503 *x
+= self
->size
.left
- self
->client
->border_width
;
1508 switch (self
->client
->gravity
) {
1510 case NorthWestGravity
:
1512 case NorthEastGravity
:
1517 /* the middle of the client will be the middle of the frame */
1518 *y
+= (self
->size
.bottom
- self
->size
.top
) / 2;
1520 case SouthWestGravity
:
1522 case SouthEastGravity
:
1523 /* the bottom of the client will be the bottom of the frame */
1524 *y
+= self
->size
.bottom
+ self
->size
.top
-
1525 self
->client
->border_width
* 2;
1529 /* the client's position won't move */
1530 *y
+= self
->size
.top
- self
->client
->border_width
;
1535 void frame_rect_to_frame(ObFrame
*self
, Rect
*r
)
1537 r
->width
+= self
->size
.left
+ self
->size
.right
;
1538 r
->height
+= self
->size
.top
+ self
->size
.bottom
;
1539 frame_client_gravity(self
, &r
->x
, &r
->y
);
1542 static void flash_done(gpointer data
)
1544 ObFrame
*self
= data
;
1546 if (self
->focused
!= self
->flash_on
)
1547 frame_adjust_focus(self
, self
->focused
);
1550 static gboolean
flash_timeout(gpointer data
)
1552 ObFrame
*self
= data
;
1555 g_get_current_time(&now
);
1556 if (now
.tv_sec
> self
->flash_end
.tv_sec
||
1557 (now
.tv_sec
== self
->flash_end
.tv_sec
&&
1558 now
.tv_usec
>= self
->flash_end
.tv_usec
))
1559 self
->flashing
= FALSE
;
1561 if (!self
->flashing
)
1562 return FALSE
; /* we are done */
1564 self
->flash_on
= !self
->flash_on
;
1565 if (!self
->focused
) {
1566 frame_adjust_focus(self
, self
->flash_on
);
1567 self
->focused
= FALSE
;
1570 return TRUE
; /* go again */
1573 void frame_flash_start(ObFrame
*self
)
1575 self
->flash_on
= self
->focused
;
1577 if (!self
->flashing
)
1578 ob_main_loop_timeout_add(ob_main_loop
,
1579 G_USEC_PER_SEC
* 0.6,
1584 g_get_current_time(&self
->flash_end
);
1585 g_time_val_add(&self
->flash_end
, G_USEC_PER_SEC
* 5);
1587 self
->flashing
= TRUE
;
1590 void frame_flash_stop(ObFrame
*self
)
1592 self
->flashing
= FALSE
;
1595 static gulong
frame_animate_iconify_time_left(ObFrame
*self
,
1596 const GTimeVal
*now
)
1599 sec
= self
->iconify_animation_end
.tv_sec
- now
->tv_sec
;
1600 usec
= self
->iconify_animation_end
.tv_usec
- now
->tv_usec
;
1602 usec
+= G_USEC_PER_SEC
;
1605 /* no negative values */
1606 return MAX(sec
* G_USEC_PER_SEC
+ usec
, 0);
1609 static gboolean
frame_animate_iconify(gpointer p
)
1613 gint iconx
, icony
, iconw
;
1616 gboolean iconifying
;
1618 if (self
->client
->icon_geometry
.width
== 0) {
1619 /* there is no icon geometry set so just go straight down */
1620 Rect
*a
= screen_physical_area_monitor
1621 (screen_find_monitor(&self
->area
));
1622 iconx
= self
->area
.x
+ self
->area
.width
/ 2 + 32;
1623 icony
= a
->y
+ a
->width
;
1627 iconx
= self
->client
->icon_geometry
.x
;
1628 icony
= self
->client
->icon_geometry
.y
;
1629 iconw
= self
->client
->icon_geometry
.width
;
1632 iconifying
= self
->iconify_animation_going
> 0;
1634 /* how far do we have left to go ? */
1635 g_get_current_time(&now
);
1636 time
= frame_animate_iconify_time_left(self
, &now
);
1638 if (time
== 0 || iconifying
) {
1639 /* start where the frame is supposed to be */
1642 w
= self
->area
.width
;
1643 h
= self
->area
.height
;
1645 /* start at the icon */
1649 h
= self
->size
.top
; /* just the titlebar */
1656 dx
= self
->area
.x
- iconx
;
1657 dy
= self
->area
.y
- icony
;
1658 dw
= self
->area
.width
- self
->bwidth
* 2 - iconw
;
1659 /* if restoring, we move in the opposite direction */
1660 if (!iconifying
) { dx
= -dx
; dy
= -dy
; dw
= -dw
; }
1662 elapsed
= FRAME_ANIMATE_ICONIFY_TIME
- time
;
1663 x
= x
- (dx
* elapsed
) / FRAME_ANIMATE_ICONIFY_TIME
;
1664 y
= y
- (dy
* elapsed
) / FRAME_ANIMATE_ICONIFY_TIME
;
1665 w
= w
- (dw
* elapsed
) / FRAME_ANIMATE_ICONIFY_TIME
;
1666 h
= self
->size
.top
; /* just the titlebar */
1670 frame_end_iconify_animation(self
);
1672 XMoveResizeWindow(ob_display
, self
->window
, x
, y
, w
, h
);
1676 return time
> 0; /* repeat until we're out of time */
1679 void frame_end_iconify_animation(ObFrame
*self
)
1681 /* see if there is an animation going */
1682 if (self
->iconify_animation_going
== 0) return;
1685 XUnmapWindow(ob_display
, self
->window
);
1687 /* Send a ConfigureNotify when the animation is done, this fixes
1688 KDE's pager showing the window in the wrong place. since the
1689 window is mapped at a different location and is then moved, we
1690 need to send the synthetic configurenotify, since apps may have
1691 read the position when the client mapped, apparently. */
1692 client_reconfigure(self
->client
, TRUE
);
1695 /* we're not animating any more ! */
1696 self
->iconify_animation_going
= 0;
1698 XMoveResizeWindow(ob_display
, self
->window
,
1699 self
->area
.x
, self
->area
.y
,
1700 self
->area
.width
, self
->area
.height
);
1701 /* we delay re-rendering until after we're done animating */
1702 framerender_frame(self
);
1706 void frame_begin_iconify_animation(ObFrame
*self
, gboolean iconifying
)
1709 gboolean new_anim
= FALSE
;
1710 gboolean set_end
= TRUE
;
1713 /* if there is no titlebar, just don't animate for now
1714 XXX it would be nice tho.. */
1715 if (!(self
->decorations
& OB_FRAME_DECOR_TITLEBAR
))
1718 /* get the current time */
1719 g_get_current_time(&now
);
1721 /* get how long until the end */
1722 time
= FRAME_ANIMATE_ICONIFY_TIME
;
1723 if (self
->iconify_animation_going
) {
1724 if (!!iconifying
!= (self
->iconify_animation_going
> 0)) {
1725 /* animation was already going on in the opposite direction */
1726 time
= time
- frame_animate_iconify_time_left(self
, &now
);
1728 /* animation was already going in the same direction */
1732 self
->iconify_animation_going
= iconifying
? 1 : -1;
1734 /* set the ending time */
1736 self
->iconify_animation_end
.tv_sec
= now
.tv_sec
;
1737 self
->iconify_animation_end
.tv_usec
= now
.tv_usec
;
1738 g_time_val_add(&self
->iconify_animation_end
, time
);
1742 ob_main_loop_timeout_remove_data(ob_main_loop
, frame_animate_iconify
,
1744 ob_main_loop_timeout_add(ob_main_loop
,
1745 FRAME_ANIMATE_ICONIFY_STEP_TIME
,
1746 frame_animate_iconify
, self
,
1747 g_direct_equal
, NULL
);
1749 /* do the first step */
1750 frame_animate_iconify(self
);
1752 /* show it during the animation even if it is not "visible" */
1754 XMapWindow(ob_display
, self
->window
);