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"
26 #include "framerender.h"
28 #include "focus_cycle.h"
29 #include "focus_cycle_indicator.h"
30 #include "composite.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
);
55 static void frame_get_offscreen_buffer(ObFrame
*self
);
56 static void frame_free_offscreen_buffer(ObFrame
*self
);
58 static Window
createWindow(Window parent
, Visual
*visual
,
59 gulong mask
, XSetWindowAttributes
*attrib
)
61 return XCreateWindow(ob_display
, parent
, 0, 0, 1, 1, 0,
62 (visual
? 32 : RrDepth(ob_rr_inst
)), InputOutput
,
63 (visual
? visual
: RrVisual(ob_rr_inst
)),
68 ObFrame
*frame_new(ObClient
*client
)
70 XSetWindowAttributes attrib
;
73 XWindowAttributes wattrib
;
76 self
= g_new0(ObFrame
, 1);
77 self
->client
= client
;
79 ret
= XGetWindowAttributes(ob_display
, client
->window
, &wattrib
);
80 g_assert(ret
!= BadDrawable
);
81 g_assert(ret
!= BadWindow
);
82 self
->has_alpha
= composite_window_has_alpha(wattrib
.visual
);
84 /* create the non-visible decor windows */
87 if (self
->has_alpha
) {
88 /* the colormap/backpixel/borderpixel are required for supporting
89 windows with 32bit visuals */
90 mask
= CWColormap
| CWBackPixel
| CWBorderPixel
;
91 /* create a colormap with the visual */
92 self
->colormap
= attrib
.colormap
=
93 XCreateColormap(ob_display
,
94 RootWindow(ob_display
, ob_screen
),
95 wattrib
.visual
, AllocNone
);
96 attrib
.background_pixel
= BlackPixel(ob_display
, ob_screen
);
97 attrib
.border_pixel
= BlackPixel(ob_display
, ob_screen
);
100 self
->window
= createWindow(RootWindow(ob_display
, ob_screen
),
101 (self
->has_alpha
? wattrib
.visual
: NULL
),
104 /* create the visible decor windows */
107 if (self
->has_alpha
) {
108 /* client has a 32-bit visual */
109 mask
|= CWColormap
| CWBackPixel
| CWBorderPixel
;
110 attrib
.colormap
= RrColormap(ob_rr_inst
);
113 self
->backback
= createWindow(self
->window
, NULL
, mask
, &attrib
);
114 self
->backfront
= createWindow(self
->backback
, NULL
, mask
, &attrib
);
117 attrib
.event_mask
= ELEMENT_EVENTMASK
;
118 self
->innerleft
= createWindow(self
->window
, NULL
, mask
, &attrib
);
119 self
->innertop
= createWindow(self
->window
, NULL
, mask
, &attrib
);
120 self
->innerright
= createWindow(self
->window
, NULL
, mask
, &attrib
);
121 self
->innerbottom
= createWindow(self
->window
, NULL
, mask
, &attrib
);
123 self
->title
= createWindow(self
->window
, NULL
, mask
, &attrib
);
124 self
->titleleft
= createWindow(self
->window
, NULL
, mask
, &attrib
);
125 self
->titletop
= createWindow(self
->window
, NULL
, mask
, &attrib
);
126 self
->titletopleft
= createWindow(self
->window
, NULL
, mask
, &attrib
);
127 self
->titletopright
= createWindow(self
->window
, NULL
, mask
, &attrib
);
128 self
->titleright
= createWindow(self
->window
, NULL
, mask
, &attrib
);
129 self
->titlebottom
= createWindow(self
->window
, NULL
, mask
, &attrib
);
131 self
->topresize
= createWindow(self
->title
, NULL
, mask
, &attrib
);
132 self
->tltresize
= createWindow(self
->title
, NULL
, mask
, &attrib
);
133 self
->tllresize
= createWindow(self
->title
, NULL
, mask
, &attrib
);
134 self
->trtresize
= createWindow(self
->title
, NULL
, mask
, &attrib
);
135 self
->trrresize
= createWindow(self
->title
, NULL
, mask
, &attrib
);
137 self
->left
= createWindow(self
->window
, NULL
, mask
, &attrib
);
138 self
->right
= createWindow(self
->window
, NULL
, mask
, &attrib
);
140 self
->label
= createWindow(self
->title
, NULL
, mask
, &attrib
);
141 self
->max
= createWindow(self
->title
, NULL
, mask
, &attrib
);
142 self
->close
= createWindow(self
->title
, NULL
, mask
, &attrib
);
143 self
->desk
= createWindow(self
->title
, NULL
, mask
, &attrib
);
144 self
->shade
= createWindow(self
->title
, NULL
, mask
, &attrib
);
145 self
->icon
= createWindow(self
->title
, NULL
, mask
, &attrib
);
146 self
->iconify
= createWindow(self
->title
, NULL
, mask
, &attrib
);
148 self
->handle
= createWindow(self
->window
, NULL
, mask
, &attrib
);
149 self
->lgrip
= createWindow(self
->handle
, NULL
, mask
, &attrib
);
150 self
->rgrip
= createWindow(self
->handle
, NULL
, mask
, &attrib
);
152 self
->handleleft
= createWindow(self
->handle
, NULL
, mask
, &attrib
);
153 self
->handleright
= createWindow(self
->handle
, NULL
, mask
, &attrib
);
155 self
->handletop
= createWindow(self
->window
, NULL
, mask
, &attrib
);
156 self
->handlebottom
= createWindow(self
->window
, NULL
, mask
, &attrib
);
157 self
->lgripleft
= createWindow(self
->window
, NULL
, mask
, &attrib
);
158 self
->lgriptop
= createWindow(self
->window
, NULL
, mask
, &attrib
);
159 self
->lgripbottom
= createWindow(self
->window
, NULL
, mask
, &attrib
);
160 self
->rgripright
= createWindow(self
->window
, NULL
, mask
, &attrib
);
161 self
->rgriptop
= createWindow(self
->window
, NULL
, mask
, &attrib
);
162 self
->rgripbottom
= createWindow(self
->window
, NULL
, mask
, &attrib
);
164 self
->focused
= FALSE
;
166 /* the other stuff is shown based on decor settings */
167 XMapWindow(ob_display
, self
->label
);
168 XMapWindow(ob_display
, self
->backback
);
169 XMapWindow(ob_display
, self
->backfront
);
171 self
->max_press
= self
->close_press
= self
->desk_press
=
172 self
->iconify_press
= self
->shade_press
= FALSE
;
173 self
->max_hover
= self
->close_hover
= self
->desk_hover
=
174 self
->iconify_hover
= self
->shade_hover
= FALSE
;
176 set_theme_statics(self
);
178 return (ObFrame
*)self
;
181 static void set_theme_statics(ObFrame
*self
)
183 /* set colors/appearance/sizes for stuff that doesn't change */
184 XResizeWindow(ob_display
, self
->max
,
185 ob_rr_theme
->button_size
, ob_rr_theme
->button_size
);
186 XResizeWindow(ob_display
, self
->iconify
,
187 ob_rr_theme
->button_size
, ob_rr_theme
->button_size
);
188 XResizeWindow(ob_display
, self
->icon
,
189 ob_rr_theme
->button_size
+ 2, ob_rr_theme
->button_size
+ 2);
190 XResizeWindow(ob_display
, self
->close
,
191 ob_rr_theme
->button_size
, ob_rr_theme
->button_size
);
192 XResizeWindow(ob_display
, self
->desk
,
193 ob_rr_theme
->button_size
, ob_rr_theme
->button_size
);
194 XResizeWindow(ob_display
, self
->shade
,
195 ob_rr_theme
->button_size
, ob_rr_theme
->button_size
);
196 XResizeWindow(ob_display
, self
->tltresize
,
197 ob_rr_theme
->grip_width
, ob_rr_theme
->paddingy
+ 1);
198 XResizeWindow(ob_display
, self
->trtresize
,
199 ob_rr_theme
->grip_width
, ob_rr_theme
->paddingy
+ 1);
200 XResizeWindow(ob_display
, self
->tllresize
,
201 ob_rr_theme
->paddingx
+ 1, ob_rr_theme
->title_height
);
202 XResizeWindow(ob_display
, self
->trrresize
,
203 ob_rr_theme
->paddingx
+ 1, ob_rr_theme
->title_height
);
205 /* set up the dynamic appearances */
206 self
->a_unfocused_title
= RrAppearanceCopy(ob_rr_theme
->a_unfocused_title
);
207 self
->a_focused_title
= RrAppearanceCopy(ob_rr_theme
->a_focused_title
);
208 self
->a_unfocused_label
= RrAppearanceCopy(ob_rr_theme
->a_unfocused_label
);
209 self
->a_focused_label
= RrAppearanceCopy(ob_rr_theme
->a_focused_label
);
210 self
->a_unfocused_handle
=
211 RrAppearanceCopy(ob_rr_theme
->a_unfocused_handle
);
212 self
->a_focused_handle
= RrAppearanceCopy(ob_rr_theme
->a_focused_handle
);
213 self
->a_icon
= RrAppearanceCopy(ob_rr_theme
->a_icon
);
216 static void free_theme_statics(ObFrame
*self
)
218 RrAppearanceFree(self
->a_unfocused_title
);
219 RrAppearanceFree(self
->a_focused_title
);
220 RrAppearanceFree(self
->a_unfocused_label
);
221 RrAppearanceFree(self
->a_focused_label
);
222 RrAppearanceFree(self
->a_unfocused_handle
);
223 RrAppearanceFree(self
->a_focused_handle
);
224 RrAppearanceFree(self
->a_icon
);
227 void frame_free(ObFrame
*self
)
229 free_theme_statics(self
);
231 XDestroyWindow(ob_display
, self
->window
);
233 XFreeColormap(ob_display
, self
->colormap
);
234 frame_free_offscreen_buffer(self
);
239 void frame_show(ObFrame
*self
)
241 if (!self
->visible
) {
242 self
->visible
= TRUE
;
243 framerender_frame(self
);
244 XMapWindow(ob_display
, self
->client
->window
);
245 XMapWindow(ob_display
, self
->window
);
247 frame_get_offscreen_buffer(self
);
251 void frame_hide(ObFrame
*self
)
254 self
->visible
= FALSE
;
255 if (!frame_iconify_animating(self
))
256 XUnmapWindow(ob_display
, self
->window
);
258 /* we unmap the client itself so that we can get MapRequest
259 events, and because the ICCCM tells us to! */
260 XUnmapWindow(ob_display
, self
->client
->window
);
261 self
->client
->ignore_unmaps
+= 1;
265 void frame_adjust_theme(ObFrame
*self
)
267 free_theme_statics(self
);
268 set_theme_statics(self
);
271 void frame_adjust_shape(ObFrame
*self
)
277 if (!self
->client
->shaped
) {
278 /* clear the shape on the frame window */
279 XShapeCombineMask(ob_display
, self
->window
, ShapeBounding
,
284 /* make the frame's shape match the clients */
285 XShapeCombineShape(ob_display
, self
->window
, ShapeBounding
,
288 self
->client
->window
,
289 ShapeBounding
, ShapeSet
);
291 /* shape the offscreen buffer to match the window */
293 XShapeCombineShape(ob_display
, self
->pixmap
, ShapeBounding
,
294 0, 0, self
->client
->window
,
295 ShapeBounding
, ShapeSet
);
298 if (self
->decorations
& OB_FRAME_DECOR_TITLEBAR
) {
301 xrect
[0].width
= self
->area
.width
;
302 xrect
[0].height
= self
->size
.top
;
306 if (self
->decorations
& OB_FRAME_DECOR_HANDLE
&&
307 ob_rr_theme
->handle_height
> 0)
310 xrect
[1].y
= FRAME_HANDLE_Y(self
);
311 xrect
[1].width
= self
->area
.width
;
312 xrect
[1].height
= ob_rr_theme
->handle_height
+
317 XShapeCombineRectangles(ob_display
, self
->window
,
318 ShapeBounding
, 0, 0, xrect
, num
,
319 ShapeUnion
, Unsorted
);
325 void frame_adjust_area(ObFrame
*self
, gboolean moved
,
326 gboolean resized
, gboolean fake
)
330 oldsize
= self
->size
;
333 /* do this before changing the frame's status like max_horz max_vert */
334 frame_adjust_cursors(self
);
336 self
->functions
= self
->client
->functions
;
337 self
->decorations
= self
->client
->decorations
;
338 self
->max_horz
= self
->client
->max_horz
;
339 self
->max_vert
= self
->client
->max_vert
;
340 self
->shaded
= self
->client
->shaded
;
342 if (self
->decorations
& OB_FRAME_DECOR_BORDER
||
343 (self
->client
->undecorated
&& config_theme_keepborder
))
344 self
->bwidth
= ob_rr_theme
->fbwidth
;
348 if (self
->decorations
& OB_FRAME_DECOR_BORDER
) {
349 self
->cbwidth_l
= self
->cbwidth_r
= ob_rr_theme
->cbwidthx
;
350 self
->cbwidth_t
= self
->cbwidth_b
= ob_rr_theme
->cbwidthy
;
352 self
->cbwidth_l
= self
->cbwidth_t
=
353 self
->cbwidth_r
= self
->cbwidth_b
= 0;
355 if (self
->max_horz
) {
356 self
->cbwidth_l
= self
->cbwidth_r
= 0;
357 self
->width
= self
->client
->area
.width
;
361 self
->width
= self
->client
->area
.width
+
362 self
->cbwidth_l
+ self
->cbwidth_r
;
364 /* some elements are sized based of the width, so don't let them have
366 self
->width
= MAX(self
->width
,
367 (ob_rr_theme
->grip_width
+ self
->bwidth
) * 2 + 1);
369 STRUT_SET(self
->size
,
370 self
->cbwidth_l
+ (!self
->max_horz
? self
->bwidth
: 0),
371 self
->cbwidth_t
+ self
->bwidth
,
372 self
->cbwidth_r
+ (!self
->max_horz
? self
->bwidth
: 0),
373 self
->cbwidth_b
+ (!self
->max_horz
|| !self
->max_vert
?
376 if (self
->decorations
& OB_FRAME_DECOR_TITLEBAR
)
377 self
->size
.top
+= ob_rr_theme
->title_height
+ self
->bwidth
;
378 if (self
->decorations
& OB_FRAME_DECOR_HANDLE
&&
379 ob_rr_theme
->handle_height
> 0)
381 self
->size
.bottom
+= ob_rr_theme
->handle_height
+ self
->bwidth
;
384 /* position/size and map/unmap all the windows */
387 if (self
->cbwidth_l
) {
388 XMoveResizeWindow(ob_display
, self
->innerleft
,
389 self
->size
.left
- self
->cbwidth_l
,
391 self
->cbwidth_l
, self
->client
->area
.height
);
393 XMapWindow(ob_display
, self
->innerleft
);
395 XUnmapWindow(ob_display
, self
->innerleft
);
397 if (self
->cbwidth_r
) {
398 XMoveResizeWindow(ob_display
, self
->innerright
,
399 self
->size
.left
+ self
->client
->area
.width
,
401 self
->cbwidth_r
, self
->client
->area
.height
);
403 XMapWindow(ob_display
, self
->innerright
);
405 XUnmapWindow(ob_display
, self
->innerright
);
407 if (self
->cbwidth_t
) {
408 XMoveResizeWindow(ob_display
, self
->innertop
,
409 self
->size
.left
- self
->cbwidth_l
,
410 self
->size
.top
- self
->cbwidth_t
,
411 self
->client
->area
.width
+
412 self
->cbwidth_l
+ self
->cbwidth_r
,
415 XMapWindow(ob_display
, self
->innertop
);
417 XUnmapWindow(ob_display
, self
->innertop
);
419 if (self
->cbwidth_b
) {
420 XMoveResizeWindow(ob_display
, self
->innerbottom
,
421 self
->size
.left
- self
->cbwidth_l
,
422 self
->size
.top
+ self
->client
->area
.height
,
423 self
->client
->area
.width
+
424 self
->cbwidth_l
+ self
->cbwidth_r
,
427 XMapWindow(ob_display
, self
->innerbottom
);
429 XUnmapWindow(ob_display
, self
->innerbottom
);
434 /* height of titleleft and titleright */
435 titlesides
= (!self
->max_horz
? ob_rr_theme
->grip_width
: 0);
437 XMoveResizeWindow(ob_display
, self
->titletop
,
438 ob_rr_theme
->grip_width
+ self
->bwidth
, 0,
439 /* width + bwidth*2 - bwidth*2 - grips*2 */
440 self
->width
- ob_rr_theme
->grip_width
* 2,
442 XMoveResizeWindow(ob_display
, self
->titletopleft
,
444 ob_rr_theme
->grip_width
+ self
->bwidth
,
446 XMoveResizeWindow(ob_display
, self
->titletopright
,
447 self
->client
->area
.width
+
448 self
->size
.left
+ self
->size
.right
-
449 ob_rr_theme
->grip_width
- self
->bwidth
,
451 ob_rr_theme
->grip_width
+ self
->bwidth
,
454 if (titlesides
> 0) {
455 XMoveResizeWindow(ob_display
, self
->titleleft
,
459 XMoveResizeWindow(ob_display
, self
->titleright
,
460 self
->client
->area
.width
+
461 self
->size
.left
+ self
->size
.right
-
467 XMapWindow(ob_display
, self
->titleleft
);
468 XMapWindow(ob_display
, self
->titleright
);
470 XUnmapWindow(ob_display
, self
->titleleft
);
471 XUnmapWindow(ob_display
, self
->titleright
);
474 XMapWindow(ob_display
, self
->titletop
);
475 XMapWindow(ob_display
, self
->titletopleft
);
476 XMapWindow(ob_display
, self
->titletopright
);
478 if (self
->decorations
& OB_FRAME_DECOR_TITLEBAR
) {
479 XMoveResizeWindow(ob_display
, self
->titlebottom
,
480 (self
->max_horz
? 0 : self
->bwidth
),
481 ob_rr_theme
->title_height
+ self
->bwidth
,
485 XMapWindow(ob_display
, self
->titlebottom
);
487 XUnmapWindow(ob_display
, self
->titlebottom
);
489 XUnmapWindow(ob_display
, self
->titlebottom
);
491 XUnmapWindow(ob_display
, self
->titletop
);
492 XUnmapWindow(ob_display
, self
->titletopleft
);
493 XUnmapWindow(ob_display
, self
->titletopright
);
494 XUnmapWindow(ob_display
, self
->titleleft
);
495 XUnmapWindow(ob_display
, self
->titleright
);
498 if (self
->decorations
& OB_FRAME_DECOR_TITLEBAR
) {
499 XMoveResizeWindow(ob_display
, self
->title
,
500 (self
->max_horz
? 0 : self
->bwidth
),
502 self
->width
, ob_rr_theme
->title_height
);
504 XMapWindow(ob_display
, self
->title
);
506 if (self
->decorations
& OB_FRAME_DECOR_GRIPS
) {
507 XMoveResizeWindow(ob_display
, self
->topresize
,
508 ob_rr_theme
->grip_width
,
510 self
->width
- ob_rr_theme
->grip_width
*2,
511 ob_rr_theme
->paddingy
+ 1);
513 XMoveWindow(ob_display
, self
->tltresize
, 0, 0);
514 XMoveWindow(ob_display
, self
->tllresize
, 0, 0);
515 XMoveWindow(ob_display
, self
->trtresize
,
516 self
->width
- ob_rr_theme
->grip_width
, 0);
517 XMoveWindow(ob_display
, self
->trrresize
,
518 self
->width
- ob_rr_theme
->paddingx
- 1, 0);
520 XMapWindow(ob_display
, self
->topresize
);
521 XMapWindow(ob_display
, self
->tltresize
);
522 XMapWindow(ob_display
, self
->tllresize
);
523 XMapWindow(ob_display
, self
->trtresize
);
524 XMapWindow(ob_display
, self
->trrresize
);
526 XUnmapWindow(ob_display
, self
->topresize
);
527 XUnmapWindow(ob_display
, self
->tltresize
);
528 XUnmapWindow(ob_display
, self
->tllresize
);
529 XUnmapWindow(ob_display
, self
->trtresize
);
530 XUnmapWindow(ob_display
, self
->trrresize
);
533 XUnmapWindow(ob_display
, self
->title
);
536 if ((self
->decorations
& OB_FRAME_DECOR_TITLEBAR
))
537 /* layout the title bar elements */
541 gint sidebwidth
= self
->max_horz
? 0 : self
->bwidth
;
543 if (self
->bwidth
&& self
->size
.bottom
) {
544 XMoveResizeWindow(ob_display
, self
->handlebottom
,
545 ob_rr_theme
->grip_width
+
546 self
->bwidth
+ sidebwidth
,
547 self
->size
.top
+ self
->client
->area
.height
+
548 self
->size
.bottom
- self
->bwidth
,
549 self
->width
- (ob_rr_theme
->grip_width
+
555 XMoveResizeWindow(ob_display
, self
->lgripleft
,
558 self
->client
->area
.height
+
561 ob_rr_theme
->grip_width
:
562 self
->size
.bottom
- self
->cbwidth_b
),
565 ob_rr_theme
->grip_width
:
566 self
->size
.bottom
- self
->cbwidth_b
));
567 XMoveResizeWindow(ob_display
, self
->rgripright
,
569 self
->client
->area
.width
+
570 self
->size
.right
- self
->bwidth
,
572 self
->client
->area
.height
+
575 ob_rr_theme
->grip_width
:
576 self
->size
.bottom
- self
->cbwidth_b
),
579 ob_rr_theme
->grip_width
:
580 self
->size
.bottom
- self
->cbwidth_b
));
582 XMapWindow(ob_display
, self
->lgripleft
);
583 XMapWindow(ob_display
, self
->rgripright
);
585 XUnmapWindow(ob_display
, self
->lgripleft
);
586 XUnmapWindow(ob_display
, self
->rgripright
);
589 XMoveResizeWindow(ob_display
, self
->lgripbottom
,
591 self
->size
.top
+ self
->client
->area
.height
+
592 self
->size
.bottom
- self
->bwidth
,
593 ob_rr_theme
->grip_width
+ self
->bwidth
,
595 XMoveResizeWindow(ob_display
, self
->rgripbottom
,
596 self
->size
.left
+ self
->client
->area
.width
+
597 self
->size
.right
- self
->bwidth
- sidebwidth
-
598 ob_rr_theme
->grip_width
,
599 self
->size
.top
+ self
->client
->area
.height
+
600 self
->size
.bottom
- self
->bwidth
,
601 ob_rr_theme
->grip_width
+ self
->bwidth
,
604 XMapWindow(ob_display
, self
->handlebottom
);
605 XMapWindow(ob_display
, self
->lgripbottom
);
606 XMapWindow(ob_display
, self
->rgripbottom
);
608 if (self
->decorations
& OB_FRAME_DECOR_HANDLE
&&
609 ob_rr_theme
->handle_height
> 0)
611 XMoveResizeWindow(ob_display
, self
->handletop
,
612 ob_rr_theme
->grip_width
+
613 self
->bwidth
+ sidebwidth
,
614 FRAME_HANDLE_Y(self
),
615 self
->width
- (ob_rr_theme
->grip_width
+
618 XMapWindow(ob_display
, self
->handletop
);
620 if (self
->decorations
& OB_FRAME_DECOR_GRIPS
) {
621 XMoveResizeWindow(ob_display
, self
->handleleft
,
622 ob_rr_theme
->grip_width
,
625 ob_rr_theme
->handle_height
);
626 XMoveResizeWindow(ob_display
, self
->handleright
,
628 ob_rr_theme
->grip_width
-
632 ob_rr_theme
->handle_height
);
634 XMoveResizeWindow(ob_display
, self
->lgriptop
,
636 FRAME_HANDLE_Y(self
),
637 ob_rr_theme
->grip_width
+
640 XMoveResizeWindow(ob_display
, self
->rgriptop
,
642 self
->client
->area
.width
+
643 self
->size
.right
- self
->bwidth
-
644 sidebwidth
- ob_rr_theme
->grip_width
,
645 FRAME_HANDLE_Y(self
),
646 ob_rr_theme
->grip_width
+
650 XMapWindow(ob_display
, self
->handleleft
);
651 XMapWindow(ob_display
, self
->handleright
);
652 XMapWindow(ob_display
, self
->lgriptop
);
653 XMapWindow(ob_display
, self
->rgriptop
);
655 XUnmapWindow(ob_display
, self
->handleleft
);
656 XUnmapWindow(ob_display
, self
->handleright
);
657 XUnmapWindow(ob_display
, self
->lgriptop
);
658 XUnmapWindow(ob_display
, self
->rgriptop
);
661 XUnmapWindow(ob_display
, self
->handleleft
);
662 XUnmapWindow(ob_display
, self
->handleright
);
663 XUnmapWindow(ob_display
, self
->lgriptop
);
664 XUnmapWindow(ob_display
, self
->rgriptop
);
666 XUnmapWindow(ob_display
, self
->handletop
);
669 XUnmapWindow(ob_display
, self
->handleleft
);
670 XUnmapWindow(ob_display
, self
->handleright
);
671 XUnmapWindow(ob_display
, self
->lgriptop
);
672 XUnmapWindow(ob_display
, self
->rgriptop
);
674 XUnmapWindow(ob_display
, self
->handletop
);
676 XUnmapWindow(ob_display
, self
->handlebottom
);
677 XUnmapWindow(ob_display
, self
->lgripleft
);
678 XUnmapWindow(ob_display
, self
->rgripright
);
679 XUnmapWindow(ob_display
, self
->lgripbottom
);
680 XUnmapWindow(ob_display
, self
->rgripbottom
);
683 if (self
->decorations
& OB_FRAME_DECOR_HANDLE
&&
684 ob_rr_theme
->handle_height
> 0)
686 XMoveResizeWindow(ob_display
, self
->handle
,
688 FRAME_HANDLE_Y(self
) + self
->bwidth
,
689 self
->width
, ob_rr_theme
->handle_height
);
690 XMapWindow(ob_display
, self
->handle
);
692 if (self
->decorations
& OB_FRAME_DECOR_GRIPS
) {
693 XMoveResizeWindow(ob_display
, self
->lgrip
,
695 ob_rr_theme
->grip_width
,
696 ob_rr_theme
->handle_height
);
697 XMoveResizeWindow(ob_display
, self
->rgrip
,
698 self
->width
- ob_rr_theme
->grip_width
,
700 ob_rr_theme
->grip_width
,
701 ob_rr_theme
->handle_height
);
703 XMapWindow(ob_display
, self
->lgrip
);
704 XMapWindow(ob_display
, self
->rgrip
);
706 XUnmapWindow(ob_display
, self
->lgrip
);
707 XUnmapWindow(ob_display
, self
->rgrip
);
710 XUnmapWindow(ob_display
, self
->lgrip
);
711 XUnmapWindow(ob_display
, self
->rgrip
);
713 XUnmapWindow(ob_display
, self
->handle
);
716 if (self
->bwidth
&& !self
->max_horz
) {
717 XMoveResizeWindow(ob_display
, self
->left
,
719 self
->bwidth
+ ob_rr_theme
->grip_width
,
721 self
->client
->area
.height
+
722 self
->size
.top
+ self
->size
.bottom
-
723 ob_rr_theme
->grip_width
* 2);
725 XMapWindow(ob_display
, self
->left
);
727 XUnmapWindow(ob_display
, self
->left
);
729 if (self
->bwidth
&& !self
->max_horz
) {
730 XMoveResizeWindow(ob_display
, self
->right
,
731 self
->client
->area
.width
+
732 self
->cbwidth_l
+ self
->cbwidth_r
+ self
->bwidth
,
733 self
->bwidth
+ ob_rr_theme
->grip_width
,
735 self
->client
->area
.height
+
736 self
->size
.top
+ self
->size
.bottom
-
737 ob_rr_theme
->grip_width
* 2);
739 XMapWindow(ob_display
, self
->right
);
741 XUnmapWindow(ob_display
, self
->right
);
743 XMoveResizeWindow(ob_display
, self
->backback
,
744 self
->size
.left
, self
->size
.top
,
745 self
->client
->area
.width
,
746 self
->client
->area
.height
);
750 /* shading can change without being moved or resized */
751 RECT_SET_SIZE(self
->area
,
752 self
->client
->area
.width
+
753 self
->size
.left
+ self
->size
.right
,
754 (self
->client
->shaded
?
755 ob_rr_theme
->title_height
+ self
->bwidth
* 2:
756 self
->client
->area
.height
+
757 self
->size
.top
+ self
->size
.bottom
));
759 if ((moved
|| resized
) && !fake
) {
760 /* find the new coordinates, done after setting the frame.size, for
761 frame_client_gravity. */
762 self
->area
.x
= self
->client
->area
.x
;
763 self
->area
.y
= self
->client
->area
.y
;
764 frame_client_gravity(self
, &self
->area
.x
, &self
->area
.y
,
765 self
->client
->area
.width
,
766 self
->client
->area
.height
);
770 if (!frame_iconify_animating(self
))
771 /* move and resize the top level frame.
772 shading can change without being moved or resized.
774 but don't do this during an iconify animation. it will be
775 reflected afterwards.
777 XMoveResizeWindow(ob_display
, self
->window
,
783 /* when the client has StaticGravity, it likes to move around.
784 also this correctly positions the client when it maps.
785 this also needs to be run when the frame's decorations sizes change!
787 XMoveWindow(ob_display
, self
->client
->window
,
788 self
->size
.left
, self
->size
.top
);
791 self
->need_render
= TRUE
;
792 framerender_frame(self
);
793 frame_adjust_shape(self
);
795 /* the offscreen buffer is invalid when the window is resized */
797 frame_get_offscreen_buffer(self
);
800 if (!STRUT_EQUAL(self
->size
, oldsize
)) {
802 vals
[0] = self
->size
.left
;
803 vals
[1] = self
->size
.right
;
804 vals
[2] = self
->size
.top
;
805 vals
[3] = self
->size
.bottom
;
806 PROP_SETA32(self
->client
->window
, net_frame_extents
,
808 PROP_SETA32(self
->client
->window
, kde_net_wm_frame_strut
,
812 /* if this occurs while we are focus cycling, the indicator needs to
814 if (focus_cycle_target
== self
->client
)
815 focus_cycle_draw_indicator(self
->client
);
817 if (resized
&& (self
->decorations
& OB_FRAME_DECOR_TITLEBAR
))
818 XResizeWindow(ob_display
, self
->label
, self
->label_width
,
819 ob_rr_theme
->label_height
);
823 static void frame_adjust_cursors(ObFrame
*self
)
825 if ((self
->functions
& OB_CLIENT_FUNC_RESIZE
) !=
826 (self
->client
->functions
& OB_CLIENT_FUNC_RESIZE
) ||
827 self
->max_horz
!= self
->client
->max_horz
||
828 self
->max_vert
!= self
->client
->max_vert
||
829 self
->shaded
!= self
->client
->shaded
)
831 gboolean r
= (self
->client
->functions
& OB_CLIENT_FUNC_RESIZE
) &&
832 !(self
->client
->max_horz
&& self
->client
->max_vert
);
833 gboolean topbot
= !self
->client
->max_vert
;
834 gboolean sh
= self
->client
->shaded
;
835 XSetWindowAttributes a
;
837 /* these ones turn off when max vert, and some when shaded */
838 a
.cursor
= ob_cursor(r
&& topbot
&& !sh
?
839 OB_CURSOR_NORTH
: OB_CURSOR_NONE
);
840 XChangeWindowAttributes(ob_display
, self
->topresize
, CWCursor
, &a
);
841 XChangeWindowAttributes(ob_display
, self
->titletop
, CWCursor
, &a
);
842 a
.cursor
= ob_cursor(r
&& topbot
? OB_CURSOR_SOUTH
: OB_CURSOR_NONE
);
843 XChangeWindowAttributes(ob_display
, self
->handle
, CWCursor
, &a
);
844 XChangeWindowAttributes(ob_display
, self
->handletop
, CWCursor
, &a
);
845 XChangeWindowAttributes(ob_display
, self
->handlebottom
, CWCursor
, &a
);
846 XChangeWindowAttributes(ob_display
, self
->innerbottom
, CWCursor
, &a
);
848 /* these ones change when shaded */
849 a
.cursor
= ob_cursor(r
? (sh
? OB_CURSOR_WEST
: OB_CURSOR_NORTHWEST
) :
851 XChangeWindowAttributes(ob_display
, self
->titleleft
, CWCursor
, &a
);
852 XChangeWindowAttributes(ob_display
, self
->tltresize
, CWCursor
, &a
);
853 XChangeWindowAttributes(ob_display
, self
->tllresize
, CWCursor
, &a
);
854 XChangeWindowAttributes(ob_display
, self
->titletopleft
, CWCursor
, &a
);
855 a
.cursor
= ob_cursor(r
? (sh
? OB_CURSOR_EAST
: OB_CURSOR_NORTHEAST
) :
857 XChangeWindowAttributes(ob_display
, self
->titleright
, CWCursor
, &a
);
858 XChangeWindowAttributes(ob_display
, self
->trtresize
, CWCursor
, &a
);
859 XChangeWindowAttributes(ob_display
, self
->trrresize
, CWCursor
, &a
);
860 XChangeWindowAttributes(ob_display
, self
->titletopright
, CWCursor
, &a
);
862 /* these ones are pretty static */
863 a
.cursor
= ob_cursor(r
? OB_CURSOR_WEST
: OB_CURSOR_NONE
);
864 XChangeWindowAttributes(ob_display
, self
->left
, CWCursor
, &a
);
865 XChangeWindowAttributes(ob_display
, self
->innerleft
, CWCursor
, &a
);
866 a
.cursor
= ob_cursor(r
? OB_CURSOR_EAST
: OB_CURSOR_NONE
);
867 XChangeWindowAttributes(ob_display
, self
->right
, CWCursor
, &a
);
868 XChangeWindowAttributes(ob_display
, self
->innerright
, CWCursor
, &a
);
869 a
.cursor
= ob_cursor(r
? OB_CURSOR_SOUTHWEST
: OB_CURSOR_NONE
);
870 XChangeWindowAttributes(ob_display
, self
->lgrip
, CWCursor
, &a
);
871 XChangeWindowAttributes(ob_display
, self
->handleleft
, CWCursor
, &a
);
872 XChangeWindowAttributes(ob_display
, self
->lgripleft
, CWCursor
, &a
);
873 XChangeWindowAttributes(ob_display
, self
->lgriptop
, CWCursor
, &a
);
874 XChangeWindowAttributes(ob_display
, self
->lgripbottom
, CWCursor
, &a
);
875 a
.cursor
= ob_cursor(r
? OB_CURSOR_SOUTHEAST
: OB_CURSOR_NONE
);
876 XChangeWindowAttributes(ob_display
, self
->rgrip
, CWCursor
, &a
);
877 XChangeWindowAttributes(ob_display
, self
->handleright
, CWCursor
, &a
);
878 XChangeWindowAttributes(ob_display
, self
->rgripright
, CWCursor
, &a
);
879 XChangeWindowAttributes(ob_display
, self
->rgriptop
, CWCursor
, &a
);
880 XChangeWindowAttributes(ob_display
, self
->rgripbottom
, CWCursor
, &a
);
884 void frame_adjust_client_area(ObFrame
*self
)
886 /* adjust the window which is there to prevent flashing on unmap */
887 XMoveResizeWindow(ob_display
, self
->backfront
, 0, 0,
888 self
->client
->area
.width
,
889 self
->client
->area
.height
);
892 void frame_adjust_state(ObFrame
*self
)
894 self
->need_render
= TRUE
;
895 framerender_frame(self
);
898 void frame_adjust_focus(ObFrame
*self
, gboolean hilite
)
900 self
->focused
= hilite
;
901 self
->need_render
= TRUE
;
902 framerender_frame(self
);
906 void frame_adjust_title(ObFrame
*self
)
908 self
->need_render
= TRUE
;
909 framerender_frame(self
);
912 void frame_adjust_icon(ObFrame
*self
)
914 self
->need_render
= TRUE
;
915 framerender_frame(self
);
918 void frame_grab_client(ObFrame
*self
)
920 /* DO NOT map the client window here. we used to do that, but it is bogus.
921 we need to set up the client's dimensions and everything before we
922 send a mapnotify or we create race conditions.
925 /* reparent the client to the frame */
926 XReparentWindow(ob_display
, self
->client
->window
, self
->window
, 0, 0);
928 /* enable the offscreen composite buffer for the client window */
929 composite_enable_for_window(self
->client
->window
);
932 When reparenting the client window, it is usually not mapped yet, since
933 this occurs from a MapRequest. However, in the case where Openbox is
934 starting up, the window is already mapped, so we'll see an unmap event
937 if (ob_state() == OB_STATE_STARTING
)
938 ++self
->client
->ignore_unmaps
;
940 /* select the event mask on the client's parent (to receive config/map
941 req's) the ButtonPress is to catch clicks on the client border */
942 XSelectInput(ob_display
, self
->window
, FRAME_EVENTMASK
);
944 /* set all the windows for the frame in the window_map */
945 g_hash_table_insert(window_map
, &self
->window
, self
->client
);
946 g_hash_table_insert(window_map
, &self
->backback
, self
->client
);
947 g_hash_table_insert(window_map
, &self
->backfront
, self
->client
);
948 g_hash_table_insert(window_map
, &self
->innerleft
, self
->client
);
949 g_hash_table_insert(window_map
, &self
->innertop
, self
->client
);
950 g_hash_table_insert(window_map
, &self
->innerright
, self
->client
);
951 g_hash_table_insert(window_map
, &self
->innerbottom
, self
->client
);
952 g_hash_table_insert(window_map
, &self
->title
, self
->client
);
953 g_hash_table_insert(window_map
, &self
->label
, self
->client
);
954 g_hash_table_insert(window_map
, &self
->max
, self
->client
);
955 g_hash_table_insert(window_map
, &self
->close
, self
->client
);
956 g_hash_table_insert(window_map
, &self
->desk
, self
->client
);
957 g_hash_table_insert(window_map
, &self
->shade
, self
->client
);
958 g_hash_table_insert(window_map
, &self
->icon
, self
->client
);
959 g_hash_table_insert(window_map
, &self
->iconify
, self
->client
);
960 g_hash_table_insert(window_map
, &self
->handle
, self
->client
);
961 g_hash_table_insert(window_map
, &self
->lgrip
, self
->client
);
962 g_hash_table_insert(window_map
, &self
->rgrip
, self
->client
);
963 g_hash_table_insert(window_map
, &self
->topresize
, self
->client
);
964 g_hash_table_insert(window_map
, &self
->tltresize
, self
->client
);
965 g_hash_table_insert(window_map
, &self
->tllresize
, self
->client
);
966 g_hash_table_insert(window_map
, &self
->trtresize
, self
->client
);
967 g_hash_table_insert(window_map
, &self
->trrresize
, self
->client
);
968 g_hash_table_insert(window_map
, &self
->left
, self
->client
);
969 g_hash_table_insert(window_map
, &self
->right
, self
->client
);
970 g_hash_table_insert(window_map
, &self
->titleleft
, self
->client
);
971 g_hash_table_insert(window_map
, &self
->titletop
, self
->client
);
972 g_hash_table_insert(window_map
, &self
->titletopleft
, self
->client
);
973 g_hash_table_insert(window_map
, &self
->titletopright
, self
->client
);
974 g_hash_table_insert(window_map
, &self
->titleright
, self
->client
);
975 g_hash_table_insert(window_map
, &self
->titlebottom
, self
->client
);
976 g_hash_table_insert(window_map
, &self
->handleleft
, self
->client
);
977 g_hash_table_insert(window_map
, &self
->handletop
, self
->client
);
978 g_hash_table_insert(window_map
, &self
->handleright
, self
->client
);
979 g_hash_table_insert(window_map
, &self
->handlebottom
, self
->client
);
980 g_hash_table_insert(window_map
, &self
->lgripleft
, self
->client
);
981 g_hash_table_insert(window_map
, &self
->lgriptop
, self
->client
);
982 g_hash_table_insert(window_map
, &self
->lgripbottom
, self
->client
);
983 g_hash_table_insert(window_map
, &self
->rgripright
, self
->client
);
984 g_hash_table_insert(window_map
, &self
->rgriptop
, self
->client
);
985 g_hash_table_insert(window_map
, &self
->rgripbottom
, self
->client
);
988 void frame_release_client(ObFrame
*self
)
991 gboolean reparent
= TRUE
;
993 /* if there was any animation going on, kill it */
994 ob_main_loop_timeout_remove_data(ob_main_loop
, frame_animate_iconify
,
997 /* check if the app has already reparented its window away */
998 while (XCheckTypedWindowEvent(ob_display
, self
->client
->window
,
999 ReparentNotify
, &ev
))
1001 /* This check makes sure we don't catch our own reparent action to
1002 our frame window. This doesn't count as the app reparenting itself
1005 Reparent events that are generated by us are just discarded here.
1006 They are of no consequence to us anyhow.
1008 if (ev
.xreparent
.parent
!= self
->window
) {
1010 XPutBackEvent(ob_display
, &ev
);
1016 /* according to the ICCCM - if the client doesn't reparent itself,
1017 then we will reparent the window to root for them */
1018 XReparentWindow(ob_display
, self
->client
->window
,
1019 RootWindow(ob_display
, ob_screen
),
1020 self
->client
->area
.x
,
1021 self
->client
->area
.y
);
1024 /* remove all the windows for the frame from the window_map */
1025 g_hash_table_remove(window_map
, &self
->window
);
1026 g_hash_table_remove(window_map
, &self
->backback
);
1027 g_hash_table_remove(window_map
, &self
->backfront
);
1028 g_hash_table_remove(window_map
, &self
->innerleft
);
1029 g_hash_table_remove(window_map
, &self
->innertop
);
1030 g_hash_table_remove(window_map
, &self
->innerright
);
1031 g_hash_table_remove(window_map
, &self
->innerbottom
);
1032 g_hash_table_remove(window_map
, &self
->title
);
1033 g_hash_table_remove(window_map
, &self
->label
);
1034 g_hash_table_remove(window_map
, &self
->max
);
1035 g_hash_table_remove(window_map
, &self
->close
);
1036 g_hash_table_remove(window_map
, &self
->desk
);
1037 g_hash_table_remove(window_map
, &self
->shade
);
1038 g_hash_table_remove(window_map
, &self
->icon
);
1039 g_hash_table_remove(window_map
, &self
->iconify
);
1040 g_hash_table_remove(window_map
, &self
->handle
);
1041 g_hash_table_remove(window_map
, &self
->lgrip
);
1042 g_hash_table_remove(window_map
, &self
->rgrip
);
1043 g_hash_table_remove(window_map
, &self
->topresize
);
1044 g_hash_table_remove(window_map
, &self
->tltresize
);
1045 g_hash_table_remove(window_map
, &self
->tllresize
);
1046 g_hash_table_remove(window_map
, &self
->trtresize
);
1047 g_hash_table_remove(window_map
, &self
->trrresize
);
1048 g_hash_table_remove(window_map
, &self
->left
);
1049 g_hash_table_remove(window_map
, &self
->right
);
1050 g_hash_table_remove(window_map
, &self
->titleleft
);
1051 g_hash_table_remove(window_map
, &self
->titletop
);
1052 g_hash_table_remove(window_map
, &self
->titletopleft
);
1053 g_hash_table_remove(window_map
, &self
->titletopright
);
1054 g_hash_table_remove(window_map
, &self
->titleright
);
1055 g_hash_table_remove(window_map
, &self
->titlebottom
);
1056 g_hash_table_remove(window_map
, &self
->handleleft
);
1057 g_hash_table_remove(window_map
, &self
->handletop
);
1058 g_hash_table_remove(window_map
, &self
->handleright
);
1059 g_hash_table_remove(window_map
, &self
->handlebottom
);
1060 g_hash_table_remove(window_map
, &self
->lgripleft
);
1061 g_hash_table_remove(window_map
, &self
->lgriptop
);
1062 g_hash_table_remove(window_map
, &self
->lgripbottom
);
1063 g_hash_table_remove(window_map
, &self
->rgripright
);
1064 g_hash_table_remove(window_map
, &self
->rgriptop
);
1065 g_hash_table_remove(window_map
, &self
->rgripbottom
);
1067 ob_main_loop_timeout_remove_data(ob_main_loop
, flash_timeout
, self
, TRUE
);
1070 /* is there anything present between us and the label? */
1071 static gboolean
is_button_present(ObFrame
*self
, const gchar
*lc
, gint dir
) {
1072 for (; *lc
!= '\0' && lc
>= config_title_layout
; lc
+= dir
) {
1073 if (*lc
== ' ') continue; /* it was invalid */
1074 if (*lc
== 'N' && self
->decorations
& OB_FRAME_DECOR_ICON
)
1076 if (*lc
== 'D' && self
->decorations
& OB_FRAME_DECOR_ALLDESKTOPS
)
1078 if (*lc
== 'S' && self
->decorations
& OB_FRAME_DECOR_SHADE
)
1080 if (*lc
== 'I' && self
->decorations
& OB_FRAME_DECOR_ICONIFY
)
1082 if (*lc
== 'M' && self
->decorations
& OB_FRAME_DECOR_MAXIMIZE
)
1084 if (*lc
== 'C' && self
->decorations
& OB_FRAME_DECOR_CLOSE
)
1086 if (*lc
== 'L') return FALSE
;
1091 static void layout_title(ObFrame
*self
)
1096 const gint bwidth
= ob_rr_theme
->button_size
+ ob_rr_theme
->paddingx
+ 1;
1097 /* position of the left most button */
1098 const gint left
= ob_rr_theme
->paddingx
+ 1;
1099 /* position of the right most button */
1100 const gint right
= self
->width
;
1102 /* turn them all off */
1103 self
->icon_on
= self
->desk_on
= self
->shade_on
= self
->iconify_on
=
1104 self
->max_on
= self
->close_on
= self
->label_on
= FALSE
;
1105 self
->label_width
= self
->width
- (ob_rr_theme
->paddingx
+ 1) * 2;
1106 self
->leftmost
= self
->rightmost
= OB_FRAME_CONTEXT_NONE
;
1108 /* figure out what's being show, find each element's position, and the
1111 do the ones before the label, then after the label,
1112 i will be +1 the first time through when working to the left,
1113 and -1 the second time through when working to the right */
1114 for (i
= 1; i
>= -1; i
-=2) {
1116 ObFrameContext
*firstcon
;
1120 lc
= config_title_layout
;
1121 firstcon
= &self
->leftmost
;
1124 lc
= config_title_layout
+ strlen(config_title_layout
)-1;
1125 firstcon
= &self
->rightmost
;
1128 /* stop at the end of the string (or the label, which calls break) */
1129 for (; *lc
!= '\0' && lc
>= config_title_layout
; lc
+=i
) {
1132 self
->label_on
= TRUE
;
1135 break; /* break the for loop, do other side of label */
1136 } else if (*lc
== 'N') {
1137 if (firstcon
) *firstcon
= OB_FRAME_CONTEXT_ICON
;
1138 if ((self
->icon_on
= is_button_present(self
, lc
, i
))) {
1139 /* icon is bigger than buttons */
1140 self
->label_width
-= bwidth
+ 2;
1141 if (i
> 0) self
->icon_x
= x
;
1142 x
+= i
* (bwidth
+ 2);
1143 if (i
< 0) self
->icon_x
= x
;
1145 } else if (*lc
== 'D') {
1146 if (firstcon
) *firstcon
= OB_FRAME_CONTEXT_ALLDESKTOPS
;
1147 if ((self
->desk_on
= is_button_present(self
, lc
, i
))) {
1148 self
->label_width
-= bwidth
;
1149 if (i
> 0) self
->desk_x
= x
;
1151 if (i
< 0) self
->desk_x
= x
;
1153 } else if (*lc
== 'S') {
1154 if (firstcon
) *firstcon
= OB_FRAME_CONTEXT_SHADE
;
1155 if ((self
->shade_on
= is_button_present(self
, lc
, i
))) {
1156 self
->label_width
-= bwidth
;
1157 if (i
> 0) self
->shade_x
= x
;
1159 if (i
< 0) self
->shade_x
= x
;
1161 } else if (*lc
== 'I') {
1162 if (firstcon
) *firstcon
= OB_FRAME_CONTEXT_ICONIFY
;
1163 if ((self
->iconify_on
= is_button_present(self
, lc
, i
))) {
1164 self
->label_width
-= bwidth
;
1165 if (i
> 0) self
->iconify_x
= x
;
1167 if (i
< 0) self
->iconify_x
= x
;
1169 } else if (*lc
== 'M') {
1170 if (firstcon
) *firstcon
= OB_FRAME_CONTEXT_MAXIMIZE
;
1171 if ((self
->max_on
= is_button_present(self
, lc
, i
))) {
1172 self
->label_width
-= bwidth
;
1173 if (i
> 0) self
->max_x
= x
;
1175 if (i
< 0) self
->max_x
= x
;
1177 } else if (*lc
== 'C') {
1178 if (firstcon
) *firstcon
= OB_FRAME_CONTEXT_CLOSE
;
1179 if ((self
->close_on
= is_button_present(self
, lc
, i
))) {
1180 self
->label_width
-= bwidth
;
1181 if (i
> 0) self
->close_x
= x
;
1183 if (i
< 0) self
->close_x
= x
;
1186 continue; /* don't set firstcon */
1191 /* position and map the elements */
1192 if (self
->icon_on
) {
1193 XMapWindow(ob_display
, self
->icon
);
1194 XMoveWindow(ob_display
, self
->icon
, self
->icon_x
,
1195 ob_rr_theme
->paddingy
);
1197 XUnmapWindow(ob_display
, self
->icon
);
1199 if (self
->desk_on
) {
1200 XMapWindow(ob_display
, self
->desk
);
1201 XMoveWindow(ob_display
, self
->desk
, self
->desk_x
,
1202 ob_rr_theme
->paddingy
+ 1);
1204 XUnmapWindow(ob_display
, self
->desk
);
1206 if (self
->shade_on
) {
1207 XMapWindow(ob_display
, self
->shade
);
1208 XMoveWindow(ob_display
, self
->shade
, self
->shade_x
,
1209 ob_rr_theme
->paddingy
+ 1);
1211 XUnmapWindow(ob_display
, self
->shade
);
1213 if (self
->iconify_on
) {
1214 XMapWindow(ob_display
, self
->iconify
);
1215 XMoveWindow(ob_display
, self
->iconify
, self
->iconify_x
,
1216 ob_rr_theme
->paddingy
+ 1);
1218 XUnmapWindow(ob_display
, self
->iconify
);
1221 XMapWindow(ob_display
, self
->max
);
1222 XMoveWindow(ob_display
, self
->max
, self
->max_x
,
1223 ob_rr_theme
->paddingy
+ 1);
1225 XUnmapWindow(ob_display
, self
->max
);
1227 if (self
->close_on
) {
1228 XMapWindow(ob_display
, self
->close
);
1229 XMoveWindow(ob_display
, self
->close
, self
->close_x
,
1230 ob_rr_theme
->paddingy
+ 1);
1232 XUnmapWindow(ob_display
, self
->close
);
1234 if (self
->label_on
) {
1235 self
->label_width
= MAX(1, self
->label_width
); /* no lower than 1 */
1236 XMapWindow(ob_display
, self
->label
);
1237 XMoveWindow(ob_display
, self
->label
, self
->label_x
,
1238 ob_rr_theme
->paddingy
);
1240 XUnmapWindow(ob_display
, self
->label
);
1243 ObFrameContext
frame_context_from_string(const gchar
*name
)
1245 if (!g_ascii_strcasecmp("Desktop", name
))
1246 return OB_FRAME_CONTEXT_DESKTOP
;
1247 else if (!g_ascii_strcasecmp("Root", name
))
1248 return OB_FRAME_CONTEXT_ROOT
;
1249 else if (!g_ascii_strcasecmp("Client", name
))
1250 return OB_FRAME_CONTEXT_CLIENT
;
1251 else if (!g_ascii_strcasecmp("Titlebar", name
))
1252 return OB_FRAME_CONTEXT_TITLEBAR
;
1253 else if (!g_ascii_strcasecmp("Frame", name
))
1254 return OB_FRAME_CONTEXT_FRAME
;
1255 else if (!g_ascii_strcasecmp("TLCorner", name
))
1256 return OB_FRAME_CONTEXT_TLCORNER
;
1257 else if (!g_ascii_strcasecmp("TRCorner", name
))
1258 return OB_FRAME_CONTEXT_TRCORNER
;
1259 else if (!g_ascii_strcasecmp("BLCorner", name
))
1260 return OB_FRAME_CONTEXT_BLCORNER
;
1261 else if (!g_ascii_strcasecmp("BRCorner", name
))
1262 return OB_FRAME_CONTEXT_BRCORNER
;
1263 else if (!g_ascii_strcasecmp("Top", name
))
1264 return OB_FRAME_CONTEXT_TOP
;
1265 else if (!g_ascii_strcasecmp("Bottom", name
))
1266 return OB_FRAME_CONTEXT_BOTTOM
;
1267 else if (!g_ascii_strcasecmp("Left", name
))
1268 return OB_FRAME_CONTEXT_LEFT
;
1269 else if (!g_ascii_strcasecmp("Right", name
))
1270 return OB_FRAME_CONTEXT_RIGHT
;
1271 else if (!g_ascii_strcasecmp("Maximize", name
))
1272 return OB_FRAME_CONTEXT_MAXIMIZE
;
1273 else if (!g_ascii_strcasecmp("AllDesktops", name
))
1274 return OB_FRAME_CONTEXT_ALLDESKTOPS
;
1275 else if (!g_ascii_strcasecmp("Shade", name
))
1276 return OB_FRAME_CONTEXT_SHADE
;
1277 else if (!g_ascii_strcasecmp("Iconify", name
))
1278 return OB_FRAME_CONTEXT_ICONIFY
;
1279 else if (!g_ascii_strcasecmp("Icon", name
))
1280 return OB_FRAME_CONTEXT_ICON
;
1281 else if (!g_ascii_strcasecmp("Close", name
))
1282 return OB_FRAME_CONTEXT_CLOSE
;
1283 else if (!g_ascii_strcasecmp("MoveResize", name
))
1284 return OB_FRAME_CONTEXT_MOVE_RESIZE
;
1285 return OB_FRAME_CONTEXT_NONE
;
1288 ObFrameContext
frame_context(ObClient
*client
, Window win
, gint x
, gint y
)
1292 if (moveresize_in_progress
)
1293 return OB_FRAME_CONTEXT_MOVE_RESIZE
;
1295 if (win
== RootWindow(ob_display
, ob_screen
))
1296 return OB_FRAME_CONTEXT_ROOT
;
1297 if (client
== NULL
) return OB_FRAME_CONTEXT_NONE
;
1298 if (win
== client
->window
) {
1299 /* conceptually, this is the desktop, as far as users are
1301 if (client
->type
== OB_CLIENT_TYPE_DESKTOP
)
1302 return OB_FRAME_CONTEXT_DESKTOP
;
1303 return OB_FRAME_CONTEXT_CLIENT
;
1306 self
= client
->frame
;
1308 /* when the user clicks in the corners of the titlebar and the client
1309 is fully maximized, then treat it like they clicked in the
1310 button that is there */
1311 if (self
->max_horz
&& self
->max_vert
&&
1312 (win
== self
->title
|| win
== self
->titletop
||
1313 win
== self
->titleleft
|| win
== self
->titletopleft
||
1314 win
== self
->titleright
|| win
== self
->titletopright
))
1316 /* get the mouse coords in reference to the whole frame */
1320 /* these windows are down a border width from the top of the frame */
1321 if (win
== self
->title
||
1322 win
== self
->titleleft
|| win
== self
->titleright
)
1325 /* title is a border width in from the edge */
1326 if (win
== self
->title
)
1328 /* titletop is a bit to the right */
1329 else if (win
== self
->titletop
)
1330 fx
+= ob_rr_theme
->grip_width
+ self
->bwidth
;
1331 /* titletopright is way to the right edge */
1332 else if (win
== self
->titletopright
)
1333 fx
+= self
->area
.width
- (ob_rr_theme
->grip_width
+ self
->bwidth
);
1334 /* titleright is even more way to the right edge */
1335 else if (win
== self
->titleright
)
1336 fx
+= self
->area
.width
- self
->bwidth
;
1338 /* figure out if we're over the area that should be considered a
1340 if (fy
< self
->bwidth
+ ob_rr_theme
->paddingy
+ 1 +
1341 ob_rr_theme
->button_size
)
1343 if (fx
< (self
->bwidth
+ ob_rr_theme
->paddingx
+ 1 +
1344 ob_rr_theme
->button_size
))
1346 if (self
->leftmost
!= OB_FRAME_CONTEXT_NONE
)
1347 return self
->leftmost
;
1349 else if (fx
>= (self
->area
.width
-
1350 (self
->bwidth
+ ob_rr_theme
->paddingx
+ 1 +
1351 ob_rr_theme
->button_size
)))
1353 if (self
->rightmost
!= OB_FRAME_CONTEXT_NONE
)
1354 return self
->rightmost
;
1358 /* there is no resizing maximized windows so make them the titlebar
1360 return OB_FRAME_CONTEXT_TITLEBAR
;
1362 else if (self
->max_vert
&&
1363 (win
== self
->titletop
|| win
== self
->topresize
))
1364 /* can't resize vertically when max vert */
1365 return OB_FRAME_CONTEXT_TITLEBAR
;
1366 else if (self
->shaded
&&
1367 (win
== self
->titletop
|| win
== self
->topresize
))
1368 /* can't resize vertically when shaded */
1369 return OB_FRAME_CONTEXT_TITLEBAR
;
1371 if (win
== self
->window
) return OB_FRAME_CONTEXT_FRAME
;
1372 if (win
== self
->label
) return OB_FRAME_CONTEXT_TITLEBAR
;
1373 if (win
== self
->handle
) return OB_FRAME_CONTEXT_BOTTOM
;
1374 if (win
== self
->handletop
) return OB_FRAME_CONTEXT_BOTTOM
;
1375 if (win
== self
->handlebottom
) return OB_FRAME_CONTEXT_BOTTOM
;
1376 if (win
== self
->handleleft
) return OB_FRAME_CONTEXT_BLCORNER
;
1377 if (win
== self
->lgrip
) return OB_FRAME_CONTEXT_BLCORNER
;
1378 if (win
== self
->lgripleft
) return OB_FRAME_CONTEXT_BLCORNER
;
1379 if (win
== self
->lgriptop
) return OB_FRAME_CONTEXT_BLCORNER
;
1380 if (win
== self
->lgripbottom
) return OB_FRAME_CONTEXT_BLCORNER
;
1381 if (win
== self
->handleright
) return OB_FRAME_CONTEXT_BRCORNER
;
1382 if (win
== self
->rgrip
) return OB_FRAME_CONTEXT_BRCORNER
;
1383 if (win
== self
->rgripright
) return OB_FRAME_CONTEXT_BLCORNER
;
1384 if (win
== self
->rgriptop
) return OB_FRAME_CONTEXT_BLCORNER
;
1385 if (win
== self
->rgripbottom
) return OB_FRAME_CONTEXT_BLCORNER
;
1386 if (win
== self
->title
) return OB_FRAME_CONTEXT_TITLEBAR
;
1387 if (win
== self
->titlebottom
) return OB_FRAME_CONTEXT_TITLEBAR
;
1388 if (win
== self
->titleleft
) return OB_FRAME_CONTEXT_TLCORNER
;
1389 if (win
== self
->titletopleft
) return OB_FRAME_CONTEXT_TLCORNER
;
1390 if (win
== self
->titleright
) return OB_FRAME_CONTEXT_TRCORNER
;
1391 if (win
== self
->titletopright
) return OB_FRAME_CONTEXT_TRCORNER
;
1392 if (win
== self
->titletop
) return OB_FRAME_CONTEXT_TOP
;
1393 if (win
== self
->topresize
) return OB_FRAME_CONTEXT_TOP
;
1394 if (win
== self
->tltresize
) return OB_FRAME_CONTEXT_TLCORNER
;
1395 if (win
== self
->tllresize
) return OB_FRAME_CONTEXT_TLCORNER
;
1396 if (win
== self
->trtresize
) return OB_FRAME_CONTEXT_TRCORNER
;
1397 if (win
== self
->trrresize
) return OB_FRAME_CONTEXT_TRCORNER
;
1398 if (win
== self
->left
) return OB_FRAME_CONTEXT_LEFT
;
1399 if (win
== self
->right
) return OB_FRAME_CONTEXT_RIGHT
;
1400 if (win
== self
->innertop
) return OB_FRAME_CONTEXT_TITLEBAR
;
1401 if (win
== self
->innerleft
) return OB_FRAME_CONTEXT_LEFT
;
1402 if (win
== self
->innerbottom
) return OB_FRAME_CONTEXT_BOTTOM
;
1403 if (win
== self
->innerright
) return OB_FRAME_CONTEXT_RIGHT
;
1404 if (win
== self
->max
) return OB_FRAME_CONTEXT_MAXIMIZE
;
1405 if (win
== self
->iconify
) return OB_FRAME_CONTEXT_ICONIFY
;
1406 if (win
== self
->close
) return OB_FRAME_CONTEXT_CLOSE
;
1407 if (win
== self
->icon
) return OB_FRAME_CONTEXT_ICON
;
1408 if (win
== self
->desk
) return OB_FRAME_CONTEXT_ALLDESKTOPS
;
1409 if (win
== self
->shade
) return OB_FRAME_CONTEXT_SHADE
;
1411 return OB_FRAME_CONTEXT_NONE
;
1414 void frame_client_gravity(ObFrame
*self
, gint
*x
, gint
*y
, gint w
, gint h
)
1417 switch (self
->client
->gravity
) {
1419 case NorthWestGravity
:
1420 case SouthWestGravity
:
1427 /* the middle of the client will be the middle of the frame */
1428 *x
-= (self
->size
.right
- self
->size
.left
) / 2;
1431 case NorthEastGravity
:
1432 case SouthEastGravity
:
1434 /* the right side of the client will be the right side of the frame */
1435 *x
-= self
->size
.right
+ self
->size
.left
-
1436 self
->client
->border_width
* 2;
1441 /* the client's position won't move */
1442 *x
-= self
->size
.left
- self
->client
->border_width
;
1447 switch (self
->client
->gravity
) {
1449 case NorthWestGravity
:
1450 case NorthEastGravity
:
1457 /* the middle of the client will be the middle of the frame */
1458 *y
-= (self
->size
.bottom
- self
->size
.top
) / 2;
1461 case SouthWestGravity
:
1462 case SouthEastGravity
:
1464 /* the bottom of the client will be the bottom of the frame */
1465 *y
-= self
->size
.bottom
+ self
->size
.top
-
1466 self
->client
->border_width
* 2;
1471 /* the client's position won't move */
1472 *y
-= self
->size
.top
- self
->client
->border_width
;
1477 void frame_frame_gravity(ObFrame
*self
, gint
*x
, gint
*y
, gint w
, gint h
)
1480 switch (self
->client
->gravity
) {
1482 case NorthWestGravity
:
1484 case SouthWestGravity
:
1489 /* the middle of the client will be the middle of the frame */
1490 *x
+= (self
->size
.right
- self
->size
.left
) / 2;
1492 case NorthEastGravity
:
1494 case SouthEastGravity
:
1495 /* the right side of the client will be the right side of the frame */
1496 *x
+= self
->size
.right
+ self
->size
.left
-
1497 self
->client
->border_width
* 2;
1501 /* the client's position won't move */
1502 *x
+= self
->size
.left
- self
->client
->border_width
;
1507 switch (self
->client
->gravity
) {
1509 case NorthWestGravity
:
1511 case NorthEastGravity
:
1516 /* the middle of the client will be the middle of the frame */
1517 *y
+= (self
->size
.bottom
- self
->size
.top
) / 2;
1519 case SouthWestGravity
:
1521 case SouthEastGravity
:
1522 /* the bottom of the client will be the bottom of the frame */
1523 *y
+= self
->size
.bottom
+ self
->size
.top
-
1524 self
->client
->border_width
* 2;
1528 /* the client's position won't move */
1529 *y
+= self
->size
.top
- self
->client
->border_width
;
1534 void frame_rect_to_frame(ObFrame
*self
, Rect
*r
)
1536 r
->width
+= self
->size
.left
+ self
->size
.right
;
1537 r
->height
+= self
->size
.top
+ self
->size
.bottom
;
1538 frame_client_gravity(self
, &r
->x
, &r
->y
, r
->width
, r
->height
);
1541 static void flash_done(gpointer data
)
1543 ObFrame
*self
= data
;
1545 if (self
->focused
!= self
->flash_on
)
1546 frame_adjust_focus(self
, self
->focused
);
1549 static gboolean
flash_timeout(gpointer data
)
1551 ObFrame
*self
= data
;
1554 g_get_current_time(&now
);
1555 if (now
.tv_sec
> self
->flash_end
.tv_sec
||
1556 (now
.tv_sec
== self
->flash_end
.tv_sec
&&
1557 now
.tv_usec
>= self
->flash_end
.tv_usec
))
1558 self
->flashing
= FALSE
;
1560 if (!self
->flashing
)
1561 return FALSE
; /* we are done */
1563 self
->flash_on
= !self
->flash_on
;
1564 if (!self
->focused
) {
1565 frame_adjust_focus(self
, self
->flash_on
);
1566 self
->focused
= FALSE
;
1569 return TRUE
; /* go again */
1572 void frame_flash_start(ObFrame
*self
)
1574 self
->flash_on
= self
->focused
;
1576 if (!self
->flashing
)
1577 ob_main_loop_timeout_add(ob_main_loop
,
1578 G_USEC_PER_SEC
* 0.6,
1583 g_get_current_time(&self
->flash_end
);
1584 g_time_val_add(&self
->flash_end
, G_USEC_PER_SEC
* 5);
1586 self
->flashing
= TRUE
;
1589 void frame_flash_stop(ObFrame
*self
)
1591 self
->flashing
= FALSE
;
1594 static gulong
frame_animate_iconify_time_left(ObFrame
*self
,
1595 const GTimeVal
*now
)
1598 sec
= self
->iconify_animation_end
.tv_sec
- now
->tv_sec
;
1599 usec
= self
->iconify_animation_end
.tv_usec
- now
->tv_usec
;
1601 usec
+= G_USEC_PER_SEC
;
1604 /* no negative values */
1605 return MAX(sec
* G_USEC_PER_SEC
+ usec
, 0);
1608 static gboolean
frame_animate_iconify(gpointer p
)
1612 gint iconx
, icony
, iconw
;
1615 gboolean iconifying
;
1617 if (self
->client
->icon_geometry
.width
== 0) {
1618 /* there is no icon geometry set so just go straight down */
1619 Rect
*a
= screen_physical_area_monitor
1620 (screen_find_monitor(&self
->area
));
1621 iconx
= self
->area
.x
+ self
->area
.width
/ 2 + 32;
1622 icony
= a
->y
+ a
->width
;
1626 iconx
= self
->client
->icon_geometry
.x
;
1627 icony
= self
->client
->icon_geometry
.y
;
1628 iconw
= self
->client
->icon_geometry
.width
;
1631 iconifying
= self
->iconify_animation_going
> 0;
1633 /* how far do we have left to go ? */
1634 g_get_current_time(&now
);
1635 time
= frame_animate_iconify_time_left(self
, &now
);
1637 if (time
== 0 || iconifying
) {
1638 /* start where the frame is supposed to be */
1641 w
= self
->area
.width
;
1642 h
= self
->area
.height
;
1644 /* start at the icon */
1648 h
= self
->size
.top
; /* just the titlebar */
1655 dx
= self
->area
.x
- iconx
;
1656 dy
= self
->area
.y
- icony
;
1657 dw
= self
->area
.width
- self
->bwidth
* 2 - iconw
;
1658 /* if restoring, we move in the opposite direction */
1659 if (!iconifying
) { dx
= -dx
; dy
= -dy
; dw
= -dw
; }
1661 elapsed
= FRAME_ANIMATE_ICONIFY_TIME
- time
;
1662 x
= x
- (dx
* elapsed
) / FRAME_ANIMATE_ICONIFY_TIME
;
1663 y
= y
- (dy
* elapsed
) / FRAME_ANIMATE_ICONIFY_TIME
;
1664 w
= w
- (dw
* elapsed
) / FRAME_ANIMATE_ICONIFY_TIME
;
1665 h
= self
->size
.top
; /* just the titlebar */
1669 frame_end_iconify_animation(self
);
1671 XMoveResizeWindow(ob_display
, self
->window
, x
, y
, w
, h
);
1675 return time
> 0; /* repeat until we're out of time */
1678 void frame_end_iconify_animation(ObFrame
*self
)
1680 /* see if there is an animation going */
1681 if (self
->iconify_animation_going
== 0) return;
1684 XUnmapWindow(ob_display
, self
->window
);
1686 /* Send a ConfigureNotify when the animation is done, this fixes
1687 KDE's pager showing the window in the wrong place. */
1688 client_reconfigure(self
->client
, TRUE
);
1690 /* the offscreen buffer is invalid when the window is resized */
1691 frame_get_offscreen_buffer(self
);
1694 /* we're not animating any more ! */
1695 self
->iconify_animation_going
= 0;
1697 XMoveResizeWindow(ob_display
, self
->window
,
1698 self
->area
.x
, self
->area
.y
,
1699 self
->area
.width
, self
->area
.height
);
1700 /* we delay re-rendering until after we're done animating */
1701 framerender_frame(self
);
1705 void frame_begin_iconify_animation(ObFrame
*self
, gboolean iconifying
)
1708 gboolean new_anim
= FALSE
;
1709 gboolean set_end
= TRUE
;
1712 /* if there is no titlebar, just don't animate for now
1713 XXX it would be nice tho.. */
1714 if (!(self
->decorations
& OB_FRAME_DECOR_TITLEBAR
))
1717 /* get the current time */
1718 g_get_current_time(&now
);
1720 /* get how long until the end */
1721 time
= FRAME_ANIMATE_ICONIFY_TIME
;
1722 if (self
->iconify_animation_going
) {
1723 if (!!iconifying
!= (self
->iconify_animation_going
> 0)) {
1724 /* animation was already going on in the opposite direction */
1725 time
= time
- frame_animate_iconify_time_left(self
, &now
);
1727 /* animation was already going in the same direction */
1731 self
->iconify_animation_going
= iconifying
? 1 : -1;
1733 /* set the ending time */
1735 self
->iconify_animation_end
.tv_sec
= now
.tv_sec
;
1736 self
->iconify_animation_end
.tv_usec
= now
.tv_usec
;
1737 g_time_val_add(&self
->iconify_animation_end
, time
);
1741 ob_main_loop_timeout_remove_data(ob_main_loop
, frame_animate_iconify
,
1743 ob_main_loop_timeout_add(ob_main_loop
,
1744 FRAME_ANIMATE_ICONIFY_STEP_TIME
,
1745 frame_animate_iconify
, self
,
1746 g_direct_equal
, NULL
);
1748 /* do the first step */
1749 frame_animate_iconify(self
);
1751 /* show it during the animation even if it is not "visible" */
1753 XMapWindow(ob_display
, self
->window
);
1757 static void frame_get_offscreen_buffer(ObFrame
*self
)
1759 frame_free_offscreen_buffer(self
);
1761 if (self
->visible
|| frame_iconify_animating(self
)) {
1762 self
->pixmap
= composite_get_window_pixmap(self
->client
->window
);
1764 self->picture = composite_create_picture(self->window,
1772 static void frame_free_offscreen_buffer(ObFrame
*self
)
1775 XFreePixmap(ob_display
, self
->pixmap
);
1776 self
->pixmap
= None
;