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 "moveresize.h"
32 #include "render/theme.h"
34 #define PLATE_EVENTMASK (SubstructureRedirectMask | FocusChangeMask)
35 #define FRAME_EVENTMASK (EnterWindowMask | LeaveWindowMask | \
36 ButtonPressMask | ButtonReleaseMask)
37 #define ELEMENT_EVENTMASK (ButtonPressMask | ButtonReleaseMask | \
38 ButtonMotionMask | PointerMotionMask | \
39 EnterWindowMask | LeaveWindowMask)
41 #define FRAME_ANIMATE_ICONIFY_TIME 150000 /* .15 seconds */
42 #define FRAME_ANIMATE_ICONIFY_STEP_TIME (G_USEC_PER_SEC / 60) /* 60 Hz */
44 #define FRAME_HANDLE_Y(f) (f->size.top + f->client->area.height + f->cbwidth_y)
46 static void flash_done(gpointer data
);
47 static gboolean
flash_timeout(gpointer data
);
49 static void layout_title(ObFrame
*self
);
50 static void set_theme_statics(ObFrame
*self
);
51 static void free_theme_statics(ObFrame
*self
);
52 static gboolean
frame_animate_iconify(gpointer self
);
53 static void frame_adjust_cursors(ObFrame
*self
);
55 static Window
createWindow(Window parent
, Visual
*visual
,
56 gulong mask
, XSetWindowAttributes
*attrib
)
58 return XCreateWindow(ob_display
, parent
, 0, 0, 1, 1, 0,
59 (visual
? 32 : RrDepth(ob_rr_inst
)), InputOutput
,
60 (visual
? visual
: RrVisual(ob_rr_inst
)),
65 static Visual
*check_32bit_client(ObClient
*c
)
67 XWindowAttributes wattrib
;
70 /* we're already running at 32 bit depth, yay. we don't need to use their
72 if (RrDepth(ob_rr_inst
) == 32)
75 ret
= XGetWindowAttributes(ob_display
, c
->window
, &wattrib
);
76 g_assert(ret
!= BadDrawable
);
77 g_assert(ret
!= BadWindow
);
79 if (wattrib
.depth
== 32)
80 return wattrib
.visual
;
84 ObFrame
*frame_new(ObClient
*client
)
86 XSetWindowAttributes attrib
;
91 self
= g_new0(ObFrame
, 1);
92 self
->client
= client
;
94 visual
= check_32bit_client(client
);
96 /* create the non-visible decor windows */
100 /* client has a 32-bit visual */
101 mask
|= CWColormap
| CWBackPixel
| CWBorderPixel
;
102 /* create a colormap with the visual */
103 self
->colormap
= attrib
.colormap
=
104 XCreateColormap(ob_display
,
105 RootWindow(ob_display
, ob_screen
),
107 attrib
.background_pixel
= BlackPixel(ob_display
, ob_screen
);
108 attrib
.border_pixel
= BlackPixel(ob_display
, ob_screen
);
110 attrib
.event_mask
= FRAME_EVENTMASK
;
111 self
->window
= createWindow(RootWindow(ob_display
, ob_screen
), visual
,
114 mask
&= ~CWEventMask
;
115 self
->plate
= createWindow(self
->window
, visual
, mask
, &attrib
);
117 /* create the visible decor windows */
121 /* client has a 32-bit visual */
122 mask
|= CWColormap
| CWBackPixel
| CWBorderPixel
;
123 attrib
.colormap
= RrColormap(ob_rr_inst
);
125 attrib
.event_mask
= ELEMENT_EVENTMASK
;
126 self
->title
= createWindow(self
->window
, NULL
, mask
, &attrib
);
127 self
->titleleft
= createWindow(self
->window
, NULL
, mask
, &attrib
);
128 self
->titletop
= createWindow(self
->window
, NULL
, mask
, &attrib
);
129 self
->titletopleft
= createWindow(self
->window
, NULL
, mask
, &attrib
);
130 self
->titletopright
= createWindow(self
->window
, NULL
, mask
, &attrib
);
131 self
->titleright
= createWindow(self
->window
, NULL
, mask
, &attrib
);
132 self
->titlebottom
= createWindow(self
->window
, NULL
, mask
, &attrib
);
134 self
->topresize
= createWindow(self
->title
, NULL
, mask
, &attrib
);
135 self
->tltresize
= createWindow(self
->title
, NULL
, mask
, &attrib
);
136 self
->tllresize
= createWindow(self
->title
, NULL
, mask
, &attrib
);
137 self
->trtresize
= createWindow(self
->title
, NULL
, mask
, &attrib
);
138 self
->trrresize
= createWindow(self
->title
, NULL
, mask
, &attrib
);
140 self
->left
= createWindow(self
->window
, NULL
, mask
, &attrib
);
141 self
->right
= createWindow(self
->window
, NULL
, mask
, &attrib
);
143 self
->innerleft
= createWindow(self
->window
, NULL
, mask
, &attrib
);
144 self
->innertop
= createWindow(self
->window
, NULL
, mask
, &attrib
);
145 self
->innerright
= createWindow(self
->window
, NULL
, mask
, &attrib
);
146 self
->innerbottom
= createWindow(self
->window
, NULL
, mask
, &attrib
);
148 self
->label
= createWindow(self
->title
, NULL
, mask
, &attrib
);
149 self
->max
= createWindow(self
->title
, NULL
, mask
, &attrib
);
150 self
->close
= createWindow(self
->title
, NULL
, mask
, &attrib
);
151 self
->desk
= createWindow(self
->title
, NULL
, mask
, &attrib
);
152 self
->shade
= createWindow(self
->title
, NULL
, mask
, &attrib
);
153 self
->icon
= createWindow(self
->title
, NULL
, mask
, &attrib
);
154 self
->iconify
= createWindow(self
->title
, NULL
, mask
, &attrib
);
156 self
->handle
= createWindow(self
->window
, NULL
, mask
, &attrib
);
157 self
->lgrip
= createWindow(self
->handle
, NULL
, mask
, &attrib
);
158 self
->rgrip
= createWindow(self
->handle
, NULL
, mask
, &attrib
);
160 self
->handleleft
= createWindow(self
->handle
, NULL
, mask
, &attrib
);
161 self
->handleright
= createWindow(self
->handle
, NULL
, mask
, &attrib
);
163 self
->handletop
= createWindow(self
->window
, NULL
, mask
, &attrib
);
164 self
->handlebottom
= createWindow(self
->window
, NULL
, mask
, &attrib
);
165 self
->lgripleft
= createWindow(self
->window
, NULL
, mask
, &attrib
);
166 self
->lgriptop
= createWindow(self
->window
, NULL
, mask
, &attrib
);
167 self
->lgripbottom
= createWindow(self
->window
, NULL
, mask
, &attrib
);
168 self
->rgripright
= createWindow(self
->window
, NULL
, mask
, &attrib
);
169 self
->rgriptop
= createWindow(self
->window
, NULL
, mask
, &attrib
);
170 self
->rgripbottom
= createWindow(self
->window
, NULL
, mask
, &attrib
);
172 self
->focused
= FALSE
;
174 /* the other stuff is shown based on decor settings */
175 XMapWindow(ob_display
, self
->plate
);
176 XMapWindow(ob_display
, self
->label
);
178 self
->max_press
= self
->close_press
= self
->desk_press
=
179 self
->iconify_press
= self
->shade_press
= FALSE
;
180 self
->max_hover
= self
->close_hover
= self
->desk_hover
=
181 self
->iconify_hover
= self
->shade_hover
= FALSE
;
183 set_theme_statics(self
);
185 return (ObFrame
*)self
;
188 static void set_theme_statics(ObFrame
*self
)
190 /* set colors/appearance/sizes for stuff that doesn't change */
191 XResizeWindow(ob_display
, self
->max
,
192 ob_rr_theme
->button_size
, ob_rr_theme
->button_size
);
193 XResizeWindow(ob_display
, self
->iconify
,
194 ob_rr_theme
->button_size
, ob_rr_theme
->button_size
);
195 XResizeWindow(ob_display
, self
->icon
,
196 ob_rr_theme
->button_size
+ 2, ob_rr_theme
->button_size
+ 2);
197 XResizeWindow(ob_display
, self
->close
,
198 ob_rr_theme
->button_size
, ob_rr_theme
->button_size
);
199 XResizeWindow(ob_display
, self
->desk
,
200 ob_rr_theme
->button_size
, ob_rr_theme
->button_size
);
201 XResizeWindow(ob_display
, self
->shade
,
202 ob_rr_theme
->button_size
, ob_rr_theme
->button_size
);
203 XResizeWindow(ob_display
, self
->tltresize
,
204 ob_rr_theme
->grip_width
, ob_rr_theme
->paddingy
+ 1);
205 XResizeWindow(ob_display
, self
->trtresize
,
206 ob_rr_theme
->grip_width
, ob_rr_theme
->paddingy
+ 1);
207 XResizeWindow(ob_display
, self
->tllresize
,
208 ob_rr_theme
->paddingx
+ 1, ob_rr_theme
->title_height
);
209 XResizeWindow(ob_display
, self
->trrresize
,
210 ob_rr_theme
->paddingx
+ 1, ob_rr_theme
->title_height
);
212 /* set up the dynamic appearances */
213 self
->a_unfocused_title
= RrAppearanceCopy(ob_rr_theme
->a_unfocused_title
);
214 self
->a_focused_title
= RrAppearanceCopy(ob_rr_theme
->a_focused_title
);
215 self
->a_unfocused_label
= RrAppearanceCopy(ob_rr_theme
->a_unfocused_label
);
216 self
->a_focused_label
= RrAppearanceCopy(ob_rr_theme
->a_focused_label
);
217 self
->a_unfocused_handle
=
218 RrAppearanceCopy(ob_rr_theme
->a_unfocused_handle
);
219 self
->a_focused_handle
= RrAppearanceCopy(ob_rr_theme
->a_focused_handle
);
220 self
->a_icon
= RrAppearanceCopy(ob_rr_theme
->a_icon
);
223 static void free_theme_statics(ObFrame
*self
)
225 RrAppearanceFree(self
->a_unfocused_title
);
226 RrAppearanceFree(self
->a_focused_title
);
227 RrAppearanceFree(self
->a_unfocused_label
);
228 RrAppearanceFree(self
->a_focused_label
);
229 RrAppearanceFree(self
->a_unfocused_handle
);
230 RrAppearanceFree(self
->a_focused_handle
);
231 RrAppearanceFree(self
->a_icon
);
234 void frame_free(ObFrame
*self
)
236 free_theme_statics(self
);
238 XDestroyWindow(ob_display
, self
->window
);
240 XFreeColormap(ob_display
, self
->colormap
);
245 void frame_show(ObFrame
*self
)
247 if (!self
->visible
) {
248 self
->visible
= TRUE
;
249 XMapWindow(ob_display
, self
->client
->window
);
250 XMapWindow(ob_display
, self
->window
);
254 void frame_hide(ObFrame
*self
)
257 self
->visible
= FALSE
;
258 if (!frame_iconify_animating(self
))
259 XUnmapWindow(ob_display
, self
->window
);
260 /* we unmap the client itself so that we can get MapRequest
261 events, and because the ICCCM tells us to! */
262 XUnmapWindow(ob_display
, self
->client
->window
);
263 self
->client
->ignore_unmaps
+= 1;
267 void frame_adjust_theme(ObFrame
*self
)
269 free_theme_statics(self
);
270 set_theme_statics(self
);
273 void frame_adjust_shape(ObFrame
*self
)
279 if (!self
->client
->shaped
) {
280 /* clear the shape on the frame window */
281 XShapeCombineMask(ob_display
, self
->window
, ShapeBounding
,
286 /* make the frame's shape match the clients */
287 XShapeCombineShape(ob_display
, self
->window
, ShapeBounding
,
290 self
->client
->window
,
291 ShapeBounding
, ShapeSet
);
294 if (self
->decorations
& OB_FRAME_DECOR_TITLEBAR
) {
297 xrect
[0].width
= self
->area
.width
;
298 xrect
[0].height
= ob_rr_theme
->title_height
+
299 self
->bwidth
+ self
->rbwidth
;
303 if (self
->decorations
& OB_FRAME_DECOR_HANDLE
&&
304 ob_rr_theme
->handle_height
> 0)
307 xrect
[1].y
= FRAME_HANDLE_Y(self
);
308 xrect
[1].width
= self
->area
.width
;
309 xrect
[1].height
= ob_rr_theme
->handle_height
+
314 XShapeCombineRectangles(ob_display
, self
->window
,
315 ShapeBounding
, 0, 0, xrect
, num
,
316 ShapeUnion
, Unsorted
);
321 void frame_adjust_area(ObFrame
*self
, gboolean moved
,
322 gboolean resized
, gboolean fake
)
326 oldsize
= self
->size
;
329 /* do this before changing the frame's status like max_horz max_vert */
330 frame_adjust_cursors(self
);
332 self
->functions
= self
->client
->functions
;
333 self
->decorations
= self
->client
->decorations
;
334 self
->max_horz
= self
->client
->max_horz
;
335 self
->max_vert
= self
->client
->max_vert
;
337 if (self
->decorations
& OB_FRAME_DECOR_BORDER
) {
338 self
->bwidth
= ob_rr_theme
->fbwidth
;
339 self
->cbwidth_x
= ob_rr_theme
->cbwidthx
;
340 self
->cbwidth_y
= ob_rr_theme
->cbwidthy
;
342 self
->bwidth
= self
->cbwidth_x
= self
->cbwidth_y
= 0;
344 self
->rbwidth
= self
->bwidth
;
346 if (self
->max_horz
) {
348 self
->width
= self
->client
->area
.width
- self
->bwidth
* 2;
350 self
->width
= self
->client
->area
.width
+ self
->cbwidth_x
* 2;
352 /* some elements are sized based of the width, so don't let them have
354 self
->width
= MAX(self
->width
,
355 (ob_rr_theme
->grip_width
+ self
->bwidth
) * 2 + 1);
357 STRUT_SET(self
->size
,
358 self
->cbwidth_x
+ (!self
->max_horz
? self
->bwidth
: 0),
359 self
->cbwidth_y
+ self
->bwidth
,
360 self
->cbwidth_x
+ (!self
->max_horz
? self
->bwidth
: 0),
361 self
->cbwidth_y
+ self
->bwidth
);
363 if (self
->decorations
& OB_FRAME_DECOR_TITLEBAR
)
364 self
->size
.top
+= ob_rr_theme
->title_height
+ self
->rbwidth
;
365 if (self
->decorations
& OB_FRAME_DECOR_HANDLE
&&
366 ob_rr_theme
->handle_height
> 0)
368 self
->size
.bottom
+= ob_rr_theme
->handle_height
+ self
->bwidth
;
371 /* position/size and map/unmap all the windows */
374 if (self
->cbwidth_x
) {
375 XMoveResizeWindow(ob_display
, self
->innerleft
,
376 self
->size
.left
- self
->cbwidth_x
,
378 self
->cbwidth_x
, self
->client
->area
.height
);
379 XMoveResizeWindow(ob_display
, self
->innerright
,
380 self
->size
.left
+ self
->client
->area
.width
,
382 self
->cbwidth_x
, self
->client
->area
.height
);
384 XMapWindow(ob_display
, self
->innerleft
);
385 XMapWindow(ob_display
, self
->innerright
);
387 XUnmapWindow(ob_display
, self
->innerleft
);
388 XUnmapWindow(ob_display
, self
->innerright
);
391 if (self
->cbwidth_y
) {
392 XMoveResizeWindow(ob_display
, self
->innertop
,
393 self
->size
.left
- self
->cbwidth_x
,
394 self
->size
.top
- self
->cbwidth_y
,
395 self
->client
->area
.width
+
396 self
->cbwidth_x
* 2, self
->cbwidth_y
);
397 XMoveResizeWindow(ob_display
, self
->innerbottom
,
398 self
->size
.left
- self
->cbwidth_x
,
399 self
->size
.top
+ self
->client
->area
.height
,
400 self
->client
->area
.width
+
401 self
->cbwidth_x
* 2, self
->cbwidth_y
);
403 XMapWindow(ob_display
, self
->innertop
);
404 XMapWindow(ob_display
, self
->innerbottom
);
406 XUnmapWindow(ob_display
, self
->innertop
);
407 XUnmapWindow(ob_display
, self
->innerbottom
);
413 /* height of titleleft and titleright */
414 titlesides
= (!self
->max_horz
?
415 ob_rr_theme
->grip_width
:
416 self
->size
.top
- self
->bwidth
);
418 XMoveResizeWindow(ob_display
, self
->titletop
,
419 ob_rr_theme
->grip_width
+ self
->bwidth
, 0,
420 /* width + bwidth*2 - bwidth*2 - grips*2 */
421 self
->width
- ob_rr_theme
->grip_width
* 2,
423 XMoveResizeWindow(ob_display
, self
->titletopleft
,
425 ob_rr_theme
->grip_width
+ self
->bwidth
,
427 XMoveResizeWindow(ob_display
, self
->titletopright
,
428 self
->client
->area
.width
+
429 self
->size
.left
+ self
->size
.right
-
430 ob_rr_theme
->grip_width
- self
->bwidth
,
432 ob_rr_theme
->grip_width
+ self
->bwidth
,
435 if (titlesides
> 0) {
436 XMoveResizeWindow(ob_display
, self
->titleleft
,
440 XMoveResizeWindow(ob_display
, self
->titleright
,
441 self
->client
->area
.width
+
442 self
->size
.left
+ self
->size
.right
-
448 XMapWindow(ob_display
, self
->titleleft
);
449 XMapWindow(ob_display
, self
->titleright
);
451 XUnmapWindow(ob_display
, self
->titleleft
);
452 XUnmapWindow(ob_display
, self
->titleright
);
455 XMapWindow(ob_display
, self
->titletop
);
456 XMapWindow(ob_display
, self
->titletopleft
);
457 XMapWindow(ob_display
, self
->titletopright
);
459 if (self
->decorations
& OB_FRAME_DECOR_TITLEBAR
&&
462 XMoveResizeWindow(ob_display
, self
->titlebottom
,
464 ob_rr_theme
->title_height
+ self
->bwidth
,
468 XMapWindow(ob_display
, self
->titlebottom
);
470 XUnmapWindow(ob_display
, self
->titlebottom
);
472 XUnmapWindow(ob_display
, self
->titlebottom
);
474 XUnmapWindow(ob_display
, self
->titletop
);
475 XUnmapWindow(ob_display
, self
->titletopleft
);
476 XUnmapWindow(ob_display
, self
->titletopright
);
477 XUnmapWindow(ob_display
, self
->titleleft
);
478 XUnmapWindow(ob_display
, self
->titleright
);
481 if (self
->decorations
& OB_FRAME_DECOR_TITLEBAR
) {
482 XMoveResizeWindow(ob_display
, self
->title
,
483 self
->bwidth
, self
->bwidth
,
484 self
->width
, ob_rr_theme
->title_height
);
486 XMapWindow(ob_display
, self
->title
);
488 if (self
->decorations
& OB_FRAME_DECOR_GRIPS
) {
489 XMoveResizeWindow(ob_display
, self
->topresize
,
490 ob_rr_theme
->grip_width
,
492 self
->width
- ob_rr_theme
->grip_width
*2,
493 ob_rr_theme
->paddingy
+ 1);
495 XMoveWindow(ob_display
, self
->tltresize
, 0, 0);
496 XMoveWindow(ob_display
, self
->tllresize
, 0, 0);
497 XMoveWindow(ob_display
, self
->trtresize
,
498 self
->width
- ob_rr_theme
->grip_width
, 0);
499 XMoveWindow(ob_display
, self
->trrresize
,
500 self
->width
- ob_rr_theme
->paddingx
- 1, 0);
502 XMapWindow(ob_display
, self
->topresize
);
503 XMapWindow(ob_display
, self
->tltresize
);
504 XMapWindow(ob_display
, self
->tllresize
);
505 XMapWindow(ob_display
, self
->trtresize
);
506 XMapWindow(ob_display
, self
->trrresize
);
508 XUnmapWindow(ob_display
, self
->topresize
);
509 XUnmapWindow(ob_display
, self
->tltresize
);
510 XUnmapWindow(ob_display
, self
->tllresize
);
511 XUnmapWindow(ob_display
, self
->trtresize
);
512 XUnmapWindow(ob_display
, self
->trrresize
);
515 XUnmapWindow(ob_display
, self
->title
);
518 if ((self
->decorations
& OB_FRAME_DECOR_TITLEBAR
))
519 /* layout the title bar elements */
524 XMoveResizeWindow(ob_display
, self
->handlebottom
,
525 ob_rr_theme
->grip_width
+
527 self
->size
.top
+ self
->client
->area
.height
+
528 self
->size
.bottom
- self
->bwidth
,
529 self
->width
- (ob_rr_theme
->grip_width
+
533 XMoveResizeWindow(ob_display
, self
->lgripleft
,
535 self
->size
.top
+ self
->client
->area
.height
+
538 ob_rr_theme
->grip_width
:
542 ob_rr_theme
->grip_width
:
544 XMoveResizeWindow(ob_display
, self
->rgripright
,
545 self
->size
.left
+ self
->client
->area
.width
+
546 self
->size
.right
- self
->bwidth
,
547 self
->size
.top
+ self
->client
->area
.height
+
550 ob_rr_theme
->grip_width
:
554 ob_rr_theme
->grip_width
:
557 XMoveResizeWindow(ob_display
, self
->lgripbottom
,
559 self
->size
.top
+ self
->client
->area
.height
+
560 self
->size
.bottom
- self
->bwidth
,
561 ob_rr_theme
->grip_width
+ self
->bwidth
,
563 XMoveResizeWindow(ob_display
, self
->rgripbottom
,
564 self
->size
.left
+ self
->client
->area
.width
+
565 self
->size
.right
- self
->bwidth
* 2 -
566 ob_rr_theme
->grip_width
,
567 self
->size
.top
+ self
->client
->area
.height
+
568 self
->size
.bottom
- self
->bwidth
,
569 ob_rr_theme
->grip_width
+ self
->bwidth
,
572 XMapWindow(ob_display
, self
->handlebottom
);
573 XMapWindow(ob_display
, self
->lgripleft
);
574 XMapWindow(ob_display
, self
->rgripright
);
575 XMapWindow(ob_display
, self
->lgripbottom
);
576 XMapWindow(ob_display
, self
->rgripbottom
);
578 if (self
->decorations
& OB_FRAME_DECOR_HANDLE
&&
579 ob_rr_theme
->handle_height
> 0)
581 XMoveResizeWindow(ob_display
, self
->handletop
,
582 ob_rr_theme
->grip_width
+
584 FRAME_HANDLE_Y(self
),
585 self
->width
- (ob_rr_theme
->grip_width
+
588 XMapWindow(ob_display
, self
->handletop
);
590 if (self
->decorations
& OB_FRAME_DECOR_GRIPS
) {
591 XMoveResizeWindow(ob_display
, self
->handleleft
,
592 ob_rr_theme
->grip_width
,
595 ob_rr_theme
->handle_height
);
596 XMoveResizeWindow(ob_display
, self
->handleright
,
598 ob_rr_theme
->grip_width
-
602 ob_rr_theme
->handle_height
);
604 XMoveResizeWindow(ob_display
, self
->lgriptop
,
606 FRAME_HANDLE_Y(self
),
607 ob_rr_theme
->grip_width
+
610 XMoveResizeWindow(ob_display
, self
->rgriptop
,
612 self
->client
->area
.width
+
613 self
->size
.right
- self
->bwidth
* 2 -
614 ob_rr_theme
->grip_width
,
615 FRAME_HANDLE_Y(self
),
616 ob_rr_theme
->grip_width
+
620 XMapWindow(ob_display
, self
->handleleft
);
621 XMapWindow(ob_display
, self
->handleright
);
622 XMapWindow(ob_display
, self
->lgriptop
);
623 XMapWindow(ob_display
, self
->rgriptop
);
625 XUnmapWindow(ob_display
, self
->handleleft
);
626 XUnmapWindow(ob_display
, self
->handleright
);
627 XUnmapWindow(ob_display
, self
->lgriptop
);
628 XUnmapWindow(ob_display
, self
->rgriptop
);
631 XUnmapWindow(ob_display
, self
->handleleft
);
632 XUnmapWindow(ob_display
, self
->handleright
);
633 XUnmapWindow(ob_display
, self
->lgriptop
);
634 XUnmapWindow(ob_display
, self
->rgriptop
);
636 XUnmapWindow(ob_display
, self
->handletop
);
639 XUnmapWindow(ob_display
, self
->handleleft
);
640 XUnmapWindow(ob_display
, self
->handleright
);
641 XUnmapWindow(ob_display
, self
->lgriptop
);
642 XUnmapWindow(ob_display
, self
->rgriptop
);
644 XUnmapWindow(ob_display
, self
->handletop
);
646 XUnmapWindow(ob_display
, self
->handlebottom
);
647 XUnmapWindow(ob_display
, self
->lgripleft
);
648 XUnmapWindow(ob_display
, self
->rgripright
);
649 XUnmapWindow(ob_display
, self
->lgripbottom
);
650 XUnmapWindow(ob_display
, self
->rgripbottom
);
653 if (self
->decorations
& OB_FRAME_DECOR_HANDLE
&&
654 ob_rr_theme
->handle_height
> 0)
656 XMoveResizeWindow(ob_display
, self
->handle
,
658 FRAME_HANDLE_Y(self
) + self
->bwidth
,
659 self
->width
, ob_rr_theme
->handle_height
);
660 XMapWindow(ob_display
, self
->handle
);
662 if (self
->decorations
& OB_FRAME_DECOR_GRIPS
) {
663 XMoveResizeWindow(ob_display
, self
->lgrip
,
665 ob_rr_theme
->grip_width
,
666 ob_rr_theme
->handle_height
);
667 XMoveResizeWindow(ob_display
, self
->rgrip
,
668 self
->width
- ob_rr_theme
->grip_width
,
670 ob_rr_theme
->grip_width
,
671 ob_rr_theme
->handle_height
);
673 XMapWindow(ob_display
, self
->lgrip
);
674 XMapWindow(ob_display
, self
->rgrip
);
676 XUnmapWindow(ob_display
, self
->lgrip
);
677 XUnmapWindow(ob_display
, self
->rgrip
);
680 XUnmapWindow(ob_display
, self
->lgrip
);
681 XUnmapWindow(ob_display
, self
->rgrip
);
683 XUnmapWindow(ob_display
, self
->handle
);
686 if (self
->bwidth
&& !self
->max_horz
) {
687 XMoveResizeWindow(ob_display
, self
->left
,
689 self
->bwidth
+ ob_rr_theme
->grip_width
,
691 self
->client
->area
.height
+
692 self
->size
.top
+ self
->size
.bottom
-
693 ob_rr_theme
->grip_width
* 2);
695 XMapWindow(ob_display
, self
->left
);
697 XUnmapWindow(ob_display
, self
->left
);
699 if (self
->bwidth
&& !self
->max_horz
) {
700 XMoveResizeWindow(ob_display
, self
->right
,
701 self
->client
->area
.width
+
702 self
->cbwidth_x
* 2 + self
->bwidth
,
703 self
->bwidth
+ ob_rr_theme
->grip_width
,
705 self
->client
->area
.height
+
706 self
->size
.top
+ self
->size
.bottom
-
707 ob_rr_theme
->grip_width
* 2);
709 XMapWindow(ob_display
, self
->right
);
711 XUnmapWindow(ob_display
, self
->right
);
714 XMoveWindow(ob_display
, self
->plate
,
715 self
->size
.left
, self
->size
.top
);
717 /* when the client has StaticGravity, it likes to move around. */
718 XMoveWindow(ob_display
, self
->client
->window
,
719 -self
->client
->border_width
,
720 -self
->client
->border_width
);
724 /* shading can change without being moved or resized */
725 RECT_SET_SIZE(self
->area
,
726 self
->client
->area
.width
+
727 self
->size
.left
+ self
->size
.right
,
728 (self
->client
->shaded
?
729 ob_rr_theme
->title_height
+ self
->bwidth
* 2:
730 self
->client
->area
.height
+
731 self
->size
.top
+ self
->size
.bottom
));
733 if ((moved
|| resized
) && !fake
) {
734 /* find the new coordinates, done after setting the frame.size, for
735 frame_client_gravity. */
736 self
->area
.x
= self
->client
->area
.x
;
737 self
->area
.y
= self
->client
->area
.y
;
738 frame_client_gravity(self
, &self
->area
.x
, &self
->area
.y
,
739 self
->client
->area
.width
,
740 self
->client
->area
.height
);
744 if (!frame_iconify_animating(self
))
745 /* move and resize the top level frame.
746 shading can change without being moved or resized.
748 but don't do this during an iconify animation. it will be
749 reflected afterwards.
751 XMoveResizeWindow(ob_display
, self
->window
,
758 framerender_frame(self
);
759 frame_adjust_shape(self
);
762 if (!STRUT_EQUAL(self
->size
, oldsize
)) {
764 vals
[0] = self
->size
.left
;
765 vals
[1] = self
->size
.right
;
766 vals
[2] = self
->size
.top
;
767 vals
[3] = self
->size
.bottom
;
768 PROP_SETA32(self
->client
->window
, net_frame_extents
,
770 PROP_SETA32(self
->client
->window
, kde_net_wm_frame_strut
,
774 /* if this occurs while we are focus cycling, the indicator needs to
776 if (focus_cycle_target
== self
->client
)
777 focus_cycle_draw_indicator(self
->client
);
779 if (resized
&& (self
->decorations
& OB_FRAME_DECOR_TITLEBAR
))
780 XResizeWindow(ob_display
, self
->label
, self
->label_width
,
781 ob_rr_theme
->label_height
);
785 static void frame_adjust_cursors(ObFrame
*self
)
787 if ((self
->functions
& OB_CLIENT_FUNC_RESIZE
) !=
788 (self
->client
->functions
& OB_CLIENT_FUNC_RESIZE
) ||
789 self
->max_horz
!= self
->client
->max_horz
||
790 self
->max_vert
!= self
->client
->max_vert
)
792 gboolean r
= (self
->client
->functions
& OB_CLIENT_FUNC_RESIZE
) &&
793 !(self
->client
->max_horz
&& self
->client
->max_vert
);
794 gboolean topbot
= !self
->client
->max_vert
;
795 XSetWindowAttributes a
;
797 /* these ones turn off when max vert */
798 a
.cursor
= ob_cursor(r
&& topbot
? OB_CURSOR_NORTH
: OB_CURSOR_NONE
);
799 XChangeWindowAttributes(ob_display
, self
->topresize
, CWCursor
, &a
);
800 XChangeWindowAttributes(ob_display
, self
->titletop
, CWCursor
, &a
);
801 a
.cursor
= ob_cursor(r
&& topbot
? OB_CURSOR_SOUTH
: OB_CURSOR_NONE
);
802 XChangeWindowAttributes(ob_display
, self
->handle
, CWCursor
, &a
);
803 XChangeWindowAttributes(ob_display
, self
->handletop
, CWCursor
, &a
);
804 XChangeWindowAttributes(ob_display
, self
->handlebottom
, CWCursor
, &a
);
805 XChangeWindowAttributes(ob_display
, self
->innerbottom
, CWCursor
, &a
);
807 /* these ones don't */
808 a
.cursor
= ob_cursor(r
? OB_CURSOR_NORTHWEST
: OB_CURSOR_NONE
);
809 XChangeWindowAttributes(ob_display
, self
->tltresize
, CWCursor
, &a
);
810 XChangeWindowAttributes(ob_display
, self
->tllresize
, CWCursor
, &a
);
811 XChangeWindowAttributes(ob_display
, self
->titletopleft
, CWCursor
, &a
);
812 XChangeWindowAttributes(ob_display
, self
->titleleft
, CWCursor
, &a
);
813 a
.cursor
= ob_cursor(r
? OB_CURSOR_NORTHEAST
: OB_CURSOR_NONE
);
814 XChangeWindowAttributes(ob_display
, self
->trtresize
, CWCursor
, &a
);
815 XChangeWindowAttributes(ob_display
, self
->trrresize
, CWCursor
, &a
);
816 XChangeWindowAttributes(ob_display
, self
->titletopright
, CWCursor
, &a
);
817 XChangeWindowAttributes(ob_display
, self
->titleright
, CWCursor
, &a
);
818 a
.cursor
= ob_cursor(r
? OB_CURSOR_WEST
: OB_CURSOR_NONE
);
819 XChangeWindowAttributes(ob_display
, self
->left
, CWCursor
, &a
);
820 XChangeWindowAttributes(ob_display
, self
->innerleft
, CWCursor
, &a
);
821 a
.cursor
= ob_cursor(r
? OB_CURSOR_EAST
: OB_CURSOR_NONE
);
822 XChangeWindowAttributes(ob_display
, self
->right
, CWCursor
, &a
);
823 XChangeWindowAttributes(ob_display
, self
->innerright
, CWCursor
, &a
);
824 a
.cursor
= ob_cursor(r
? OB_CURSOR_SOUTHWEST
: OB_CURSOR_NONE
);
825 XChangeWindowAttributes(ob_display
, self
->lgrip
, CWCursor
, &a
);
826 XChangeWindowAttributes(ob_display
, self
->handleleft
, CWCursor
, &a
);
827 XChangeWindowAttributes(ob_display
, self
->lgripleft
, CWCursor
, &a
);
828 XChangeWindowAttributes(ob_display
, self
->lgriptop
, CWCursor
, &a
);
829 XChangeWindowAttributes(ob_display
, self
->lgripbottom
, CWCursor
, &a
);
830 a
.cursor
= ob_cursor(r
? OB_CURSOR_SOUTHEAST
: OB_CURSOR_NONE
);
831 XChangeWindowAttributes(ob_display
, self
->rgrip
, CWCursor
, &a
);
832 XChangeWindowAttributes(ob_display
, self
->handleright
, CWCursor
, &a
);
833 XChangeWindowAttributes(ob_display
, self
->rgripright
, CWCursor
, &a
);
834 XChangeWindowAttributes(ob_display
, self
->rgriptop
, CWCursor
, &a
);
835 XChangeWindowAttributes(ob_display
, self
->rgripbottom
, CWCursor
, &a
);
839 void frame_adjust_client_area(ObFrame
*self
)
841 /* resize the plate */
842 XResizeWindow(ob_display
, self
->plate
,
843 self
->client
->area
.width
, self
->client
->area
.height
);
846 void frame_adjust_state(ObFrame
*self
)
848 framerender_frame(self
);
851 void frame_adjust_focus(ObFrame
*self
, gboolean hilite
)
853 self
->focused
= hilite
;
854 framerender_frame(self
);
858 void frame_adjust_title(ObFrame
*self
)
860 framerender_frame(self
);
863 void frame_adjust_icon(ObFrame
*self
)
865 framerender_frame(self
);
868 void frame_grab_client(ObFrame
*self
)
870 /* DO NOT map the client window here. we used to do that, but it is bogus.
871 we need to set up the client's dimensions and everything before we
872 send a mapnotify or we create race conditions.
875 /* reparent the client to the frame */
876 XReparentWindow(ob_display
, self
->client
->window
, self
->plate
,
877 -self
->client
->border_width
, -self
->client
->border_width
);
880 When reparenting the client window, it is usually not mapped yet, since
881 this occurs from a MapRequest. However, in the case where Openbox is
882 starting up, the window is already mapped, so we'll see an unmap event
885 if (ob_state() == OB_STATE_STARTING
)
886 ++self
->client
->ignore_unmaps
;
888 /* select the event mask on the client's parent (to receive config/map
889 req's) the ButtonPress is to catch clicks on the client border */
890 XSelectInput(ob_display
, self
->plate
, PLATE_EVENTMASK
);
892 /* set all the windows for the frame in the window_map */
893 g_hash_table_insert(window_map
, &self
->window
, self
->client
);
894 g_hash_table_insert(window_map
, &self
->plate
, self
->client
);
895 g_hash_table_insert(window_map
, &self
->innerleft
, self
->client
);
896 g_hash_table_insert(window_map
, &self
->innertop
, self
->client
);
897 g_hash_table_insert(window_map
, &self
->innerright
, self
->client
);
898 g_hash_table_insert(window_map
, &self
->innerbottom
, self
->client
);
899 g_hash_table_insert(window_map
, &self
->title
, self
->client
);
900 g_hash_table_insert(window_map
, &self
->label
, self
->client
);
901 g_hash_table_insert(window_map
, &self
->max
, self
->client
);
902 g_hash_table_insert(window_map
, &self
->close
, self
->client
);
903 g_hash_table_insert(window_map
, &self
->desk
, self
->client
);
904 g_hash_table_insert(window_map
, &self
->shade
, self
->client
);
905 g_hash_table_insert(window_map
, &self
->icon
, self
->client
);
906 g_hash_table_insert(window_map
, &self
->iconify
, self
->client
);
907 g_hash_table_insert(window_map
, &self
->handle
, self
->client
);
908 g_hash_table_insert(window_map
, &self
->lgrip
, self
->client
);
909 g_hash_table_insert(window_map
, &self
->rgrip
, self
->client
);
910 g_hash_table_insert(window_map
, &self
->topresize
, self
->client
);
911 g_hash_table_insert(window_map
, &self
->tltresize
, self
->client
);
912 g_hash_table_insert(window_map
, &self
->tllresize
, self
->client
);
913 g_hash_table_insert(window_map
, &self
->trtresize
, self
->client
);
914 g_hash_table_insert(window_map
, &self
->trrresize
, self
->client
);
915 g_hash_table_insert(window_map
, &self
->left
, self
->client
);
916 g_hash_table_insert(window_map
, &self
->right
, self
->client
);
917 g_hash_table_insert(window_map
, &self
->titleleft
, self
->client
);
918 g_hash_table_insert(window_map
, &self
->titletop
, self
->client
);
919 g_hash_table_insert(window_map
, &self
->titletopleft
, self
->client
);
920 g_hash_table_insert(window_map
, &self
->titletopright
, self
->client
);
921 g_hash_table_insert(window_map
, &self
->titleright
, self
->client
);
922 g_hash_table_insert(window_map
, &self
->titlebottom
, self
->client
);
923 g_hash_table_insert(window_map
, &self
->handleleft
, self
->client
);
924 g_hash_table_insert(window_map
, &self
->handletop
, self
->client
);
925 g_hash_table_insert(window_map
, &self
->handleright
, self
->client
);
926 g_hash_table_insert(window_map
, &self
->handlebottom
, self
->client
);
927 g_hash_table_insert(window_map
, &self
->lgripleft
, self
->client
);
928 g_hash_table_insert(window_map
, &self
->lgriptop
, self
->client
);
929 g_hash_table_insert(window_map
, &self
->lgripbottom
, self
->client
);
930 g_hash_table_insert(window_map
, &self
->rgripright
, self
->client
);
931 g_hash_table_insert(window_map
, &self
->rgriptop
, self
->client
);
932 g_hash_table_insert(window_map
, &self
->rgripbottom
, self
->client
);
935 void frame_release_client(ObFrame
*self
)
938 gboolean reparent
= TRUE
;
940 /* if there was any animation going on, kill it */
941 ob_main_loop_timeout_remove_data(ob_main_loop
, frame_animate_iconify
,
944 /* check if the app has already reparented its window away */
945 while (XCheckTypedWindowEvent(ob_display
, self
->client
->window
,
946 ReparentNotify
, &ev
))
948 /* This check makes sure we don't catch our own reparent action to
949 our frame window. This doesn't count as the app reparenting itself
952 Reparent events that are generated by us are just discarded here.
953 They are of no consequence to us anyhow.
955 if (ev
.xreparent
.parent
!= self
->plate
) {
957 XPutBackEvent(ob_display
, &ev
);
963 /* according to the ICCCM - if the client doesn't reparent itself,
964 then we will reparent the window to root for them */
965 XReparentWindow(ob_display
, self
->client
->window
,
966 RootWindow(ob_display
, ob_screen
),
967 self
->client
->area
.x
,
968 self
->client
->area
.y
);
971 /* remove all the windows for the frame from the window_map */
972 g_hash_table_remove(window_map
, &self
->window
);
973 g_hash_table_remove(window_map
, &self
->plate
);
974 g_hash_table_remove(window_map
, &self
->innerleft
);
975 g_hash_table_remove(window_map
, &self
->innertop
);
976 g_hash_table_remove(window_map
, &self
->innerright
);
977 g_hash_table_remove(window_map
, &self
->innerbottom
);
978 g_hash_table_remove(window_map
, &self
->title
);
979 g_hash_table_remove(window_map
, &self
->label
);
980 g_hash_table_remove(window_map
, &self
->max
);
981 g_hash_table_remove(window_map
, &self
->close
);
982 g_hash_table_remove(window_map
, &self
->desk
);
983 g_hash_table_remove(window_map
, &self
->shade
);
984 g_hash_table_remove(window_map
, &self
->icon
);
985 g_hash_table_remove(window_map
, &self
->iconify
);
986 g_hash_table_remove(window_map
, &self
->handle
);
987 g_hash_table_remove(window_map
, &self
->lgrip
);
988 g_hash_table_remove(window_map
, &self
->rgrip
);
989 g_hash_table_remove(window_map
, &self
->topresize
);
990 g_hash_table_remove(window_map
, &self
->tltresize
);
991 g_hash_table_remove(window_map
, &self
->tllresize
);
992 g_hash_table_remove(window_map
, &self
->trtresize
);
993 g_hash_table_remove(window_map
, &self
->trrresize
);
994 g_hash_table_remove(window_map
, &self
->left
);
995 g_hash_table_remove(window_map
, &self
->right
);
996 g_hash_table_remove(window_map
, &self
->titleleft
);
997 g_hash_table_remove(window_map
, &self
->titletop
);
998 g_hash_table_remove(window_map
, &self
->titletopleft
);
999 g_hash_table_remove(window_map
, &self
->titletopright
);
1000 g_hash_table_remove(window_map
, &self
->titleright
);
1001 g_hash_table_remove(window_map
, &self
->titlebottom
);
1002 g_hash_table_remove(window_map
, &self
->handleleft
);
1003 g_hash_table_remove(window_map
, &self
->handletop
);
1004 g_hash_table_remove(window_map
, &self
->handleright
);
1005 g_hash_table_remove(window_map
, &self
->handlebottom
);
1006 g_hash_table_remove(window_map
, &self
->lgripleft
);
1007 g_hash_table_remove(window_map
, &self
->lgriptop
);
1008 g_hash_table_remove(window_map
, &self
->lgripbottom
);
1009 g_hash_table_remove(window_map
, &self
->rgripright
);
1010 g_hash_table_remove(window_map
, &self
->rgriptop
);
1011 g_hash_table_remove(window_map
, &self
->rgripbottom
);
1013 ob_main_loop_timeout_remove_data(ob_main_loop
, flash_timeout
, self
, TRUE
);
1016 /* is there anything present between us and the label? */
1017 static gboolean
is_button_present(ObFrame
*self
, const gchar
*lc
, gint dir
) {
1018 for (; *lc
!= '\0' && lc
>= config_title_layout
; lc
+= dir
) {
1019 if (*lc
== ' ') continue; /* it was invalid */
1020 if (*lc
== 'N' && self
->decorations
& OB_FRAME_DECOR_ICON
)
1022 if (*lc
== 'D' && self
->decorations
& OB_FRAME_DECOR_ALLDESKTOPS
)
1024 if (*lc
== 'S' && self
->decorations
& OB_FRAME_DECOR_SHADE
)
1026 if (*lc
== 'I' && self
->decorations
& OB_FRAME_DECOR_ICONIFY
)
1028 if (*lc
== 'M' && self
->decorations
& OB_FRAME_DECOR_MAXIMIZE
)
1030 if (*lc
== 'C' && self
->decorations
& OB_FRAME_DECOR_CLOSE
)
1032 if (*lc
== 'L') return FALSE
;
1037 static void layout_title(ObFrame
*self
)
1042 const gint bwidth
= ob_rr_theme
->button_size
+ ob_rr_theme
->paddingx
+ 1;
1043 /* position of the left most button */
1044 const gint left
= ob_rr_theme
->paddingx
+ 1;
1045 /* position of the right most button */
1046 const gint right
= self
->width
;
1048 /* turn them all off */
1049 self
->icon_on
= self
->desk_on
= self
->shade_on
= self
->iconify_on
=
1050 self
->max_on
= self
->close_on
= self
->label_on
= FALSE
;
1051 self
->label_width
= self
->width
- (ob_rr_theme
->paddingx
+ 1) * 2;
1052 self
->leftmost
= self
->rightmost
= OB_FRAME_CONTEXT_NONE
;
1054 /* figure out what's being show, find each element's position, and the
1057 do the ones before the label, then after the label,
1058 i will be +1 the first time through when working to the left,
1059 and -1 the second time through when working to the right */
1060 for (i
= 1; i
>= -1; i
-=2) {
1062 ObFrameContext
*firstcon
;
1066 lc
= config_title_layout
;
1067 firstcon
= &self
->leftmost
;
1070 lc
= config_title_layout
+ strlen(config_title_layout
)-1;
1071 firstcon
= &self
->rightmost
;
1074 /* stop at the end of the string (or the label, which calls break) */
1075 for (; *lc
!= '\0' && lc
>= config_title_layout
; lc
+=i
) {
1078 self
->label_on
= TRUE
;
1081 break; /* break the for loop, do other side of label */
1082 } else if (*lc
== 'N') {
1083 if (firstcon
) *firstcon
= OB_FRAME_CONTEXT_ICON
;
1084 if ((self
->icon_on
= is_button_present(self
, lc
, i
))) {
1085 /* icon is bigger than buttons */
1086 self
->label_width
-= bwidth
+ 2;
1087 if (i
> 0) self
->icon_x
= x
;
1088 x
+= i
* (bwidth
+ 2);
1089 if (i
< 0) self
->icon_x
= x
;
1091 } else if (*lc
== 'D') {
1092 if (firstcon
) *firstcon
= OB_FRAME_CONTEXT_ALLDESKTOPS
;
1093 if ((self
->desk_on
= is_button_present(self
, lc
, i
))) {
1094 self
->label_width
-= bwidth
;
1095 if (i
> 0) self
->desk_x
= x
;
1097 if (i
< 0) self
->desk_x
= x
;
1099 } else if (*lc
== 'S') {
1100 if (firstcon
) *firstcon
= OB_FRAME_CONTEXT_SHADE
;
1101 if ((self
->shade_on
= is_button_present(self
, lc
, i
))) {
1102 self
->label_width
-= bwidth
;
1103 if (i
> 0) self
->shade_x
= x
;
1105 if (i
< 0) self
->shade_x
= x
;
1107 } else if (*lc
== 'I') {
1108 if (firstcon
) *firstcon
= OB_FRAME_CONTEXT_ICONIFY
;
1109 if ((self
->iconify_on
= is_button_present(self
, lc
, i
))) {
1110 self
->label_width
-= bwidth
;
1111 if (i
> 0) self
->iconify_x
= x
;
1113 if (i
< 0) self
->iconify_x
= x
;
1115 } else if (*lc
== 'M') {
1116 if (firstcon
) *firstcon
= OB_FRAME_CONTEXT_MAXIMIZE
;
1117 if ((self
->max_on
= is_button_present(self
, lc
, i
))) {
1118 self
->label_width
-= bwidth
;
1119 if (i
> 0) self
->max_x
= x
;
1121 if (i
< 0) self
->max_x
= x
;
1123 } else if (*lc
== 'C') {
1124 if (firstcon
) *firstcon
= OB_FRAME_CONTEXT_CLOSE
;
1125 if ((self
->close_on
= is_button_present(self
, lc
, i
))) {
1126 self
->label_width
-= bwidth
;
1127 if (i
> 0) self
->close_x
= x
;
1129 if (i
< 0) self
->close_x
= x
;
1132 continue; /* don't set firstcon */
1137 /* position and map the elements */
1138 if (self
->icon_on
) {
1139 XMapWindow(ob_display
, self
->icon
);
1140 XMoveWindow(ob_display
, self
->icon
, self
->icon_x
,
1141 ob_rr_theme
->paddingy
);
1143 XUnmapWindow(ob_display
, self
->icon
);
1145 if (self
->desk_on
) {
1146 XMapWindow(ob_display
, self
->desk
);
1147 XMoveWindow(ob_display
, self
->desk
, self
->desk_x
,
1148 ob_rr_theme
->paddingy
+ 1);
1150 XUnmapWindow(ob_display
, self
->desk
);
1152 if (self
->shade_on
) {
1153 XMapWindow(ob_display
, self
->shade
);
1154 XMoveWindow(ob_display
, self
->shade
, self
->shade_x
,
1155 ob_rr_theme
->paddingy
+ 1);
1157 XUnmapWindow(ob_display
, self
->shade
);
1159 if (self
->iconify_on
) {
1160 XMapWindow(ob_display
, self
->iconify
);
1161 XMoveWindow(ob_display
, self
->iconify
, self
->iconify_x
,
1162 ob_rr_theme
->paddingy
+ 1);
1164 XUnmapWindow(ob_display
, self
->iconify
);
1167 XMapWindow(ob_display
, self
->max
);
1168 XMoveWindow(ob_display
, self
->max
, self
->max_x
,
1169 ob_rr_theme
->paddingy
+ 1);
1171 XUnmapWindow(ob_display
, self
->max
);
1173 if (self
->close_on
) {
1174 XMapWindow(ob_display
, self
->close
);
1175 XMoveWindow(ob_display
, self
->close
, self
->close_x
,
1176 ob_rr_theme
->paddingy
+ 1);
1178 XUnmapWindow(ob_display
, self
->close
);
1180 if (self
->label_on
) {
1181 self
->label_width
= MAX(1, self
->label_width
); /* no lower than 1 */
1182 XMapWindow(ob_display
, self
->label
);
1183 XMoveWindow(ob_display
, self
->label
, self
->label_x
,
1184 ob_rr_theme
->paddingy
);
1186 XUnmapWindow(ob_display
, self
->label
);
1189 ObFrameContext
frame_context_from_string(const gchar
*name
)
1191 if (!g_ascii_strcasecmp("Desktop", name
))
1192 return OB_FRAME_CONTEXT_DESKTOP
;
1193 else if (!g_ascii_strcasecmp("Root", name
))
1194 return OB_FRAME_CONTEXT_ROOT
;
1195 else if (!g_ascii_strcasecmp("Client", name
))
1196 return OB_FRAME_CONTEXT_CLIENT
;
1197 else if (!g_ascii_strcasecmp("Titlebar", name
))
1198 return OB_FRAME_CONTEXT_TITLEBAR
;
1199 else if (!g_ascii_strcasecmp("Frame", name
))
1200 return OB_FRAME_CONTEXT_FRAME
;
1201 else if (!g_ascii_strcasecmp("TLCorner", name
))
1202 return OB_FRAME_CONTEXT_TLCORNER
;
1203 else if (!g_ascii_strcasecmp("TRCorner", name
))
1204 return OB_FRAME_CONTEXT_TRCORNER
;
1205 else if (!g_ascii_strcasecmp("BLCorner", name
))
1206 return OB_FRAME_CONTEXT_BLCORNER
;
1207 else if (!g_ascii_strcasecmp("BRCorner", name
))
1208 return OB_FRAME_CONTEXT_BRCORNER
;
1209 else if (!g_ascii_strcasecmp("Top", name
))
1210 return OB_FRAME_CONTEXT_TOP
;
1211 else if (!g_ascii_strcasecmp("Bottom", name
))
1212 return OB_FRAME_CONTEXT_BOTTOM
;
1213 else if (!g_ascii_strcasecmp("Left", name
))
1214 return OB_FRAME_CONTEXT_LEFT
;
1215 else if (!g_ascii_strcasecmp("Right", name
))
1216 return OB_FRAME_CONTEXT_RIGHT
;
1217 else if (!g_ascii_strcasecmp("Maximize", name
))
1218 return OB_FRAME_CONTEXT_MAXIMIZE
;
1219 else if (!g_ascii_strcasecmp("AllDesktops", name
))
1220 return OB_FRAME_CONTEXT_ALLDESKTOPS
;
1221 else if (!g_ascii_strcasecmp("Shade", name
))
1222 return OB_FRAME_CONTEXT_SHADE
;
1223 else if (!g_ascii_strcasecmp("Iconify", name
))
1224 return OB_FRAME_CONTEXT_ICONIFY
;
1225 else if (!g_ascii_strcasecmp("Icon", name
))
1226 return OB_FRAME_CONTEXT_ICON
;
1227 else if (!g_ascii_strcasecmp("Close", name
))
1228 return OB_FRAME_CONTEXT_CLOSE
;
1229 else if (!g_ascii_strcasecmp("MoveResize", name
))
1230 return OB_FRAME_CONTEXT_MOVE_RESIZE
;
1231 return OB_FRAME_CONTEXT_NONE
;
1234 ObFrameContext
frame_context(ObClient
*client
, Window win
, gint x
, gint y
)
1238 if (moveresize_in_progress
)
1239 return OB_FRAME_CONTEXT_MOVE_RESIZE
;
1241 if (win
== RootWindow(ob_display
, ob_screen
))
1242 return OB_FRAME_CONTEXT_ROOT
;
1243 if (client
== NULL
) return OB_FRAME_CONTEXT_NONE
;
1244 if (win
== client
->window
) {
1245 /* conceptually, this is the desktop, as far as users are
1247 if (client
->type
== OB_CLIENT_TYPE_DESKTOP
)
1248 return OB_FRAME_CONTEXT_DESKTOP
;
1249 return OB_FRAME_CONTEXT_CLIENT
;
1252 self
= client
->frame
;
1253 if (win
== self
->plate
) {
1254 /* conceptually, this is the desktop, as far as users are
1256 if (client
->type
== OB_CLIENT_TYPE_DESKTOP
)
1257 return OB_FRAME_CONTEXT_DESKTOP
;
1258 return OB_FRAME_CONTEXT_CLIENT
;
1261 /* when the user clicks in the corners of the titlebar and the client
1262 is fully maximized, then treat it like they clicked in the
1263 button that is there */
1264 if (self
->max_horz
&& self
->max_vert
&&
1265 (win
== self
->title
|| win
== self
->titletop
||
1266 win
== self
->titleleft
|| win
== self
->titletopleft
||
1267 win
== self
->titleright
|| win
== self
->titletopright
))
1269 /* get the mouse coords in reference to the whole frame */
1273 /* these windows are down a border width from the top of the frame */
1274 if (win
== self
->title
||
1275 win
== self
->titleleft
|| win
== self
->titleright
)
1278 /* title is a border width in from the edge */
1279 if (win
== self
->title
)
1281 /* titletop is a bit to the right */
1282 else if (win
== self
->titletop
)
1283 fx
+= ob_rr_theme
->grip_width
+ self
->bwidth
;
1284 /* titletopright is way to the right edge */
1285 else if (win
== self
->titletopright
)
1286 fx
+= self
->area
.width
- (ob_rr_theme
->grip_width
+ self
->bwidth
);
1287 /* titleright is even more way to the right edge */
1288 else if (win
== self
->titleright
)
1289 fx
+= self
->area
.width
- self
->bwidth
;
1291 /* figure out if we're over the area that should be considered a
1293 if (fy
< self
->bwidth
+ ob_rr_theme
->paddingy
+ 1 +
1294 ob_rr_theme
->button_size
)
1296 if (fx
< (self
->bwidth
+ ob_rr_theme
->paddingx
+ 1 +
1297 ob_rr_theme
->button_size
))
1299 if (self
->leftmost
!= OB_FRAME_CONTEXT_NONE
)
1300 return self
->leftmost
;
1302 else if (fx
>= (self
->area
.width
-
1303 (self
->bwidth
+ ob_rr_theme
->paddingx
+ 1 +
1304 ob_rr_theme
->button_size
)))
1306 if (self
->rightmost
!= OB_FRAME_CONTEXT_NONE
)
1307 return self
->rightmost
;
1311 /* there is no resizing maximized windows so make them the titlebar
1313 return OB_FRAME_CONTEXT_TITLEBAR
;
1315 else if (self
->max_vert
&&
1316 (win
== self
->titletop
|| win
== self
->topresize
))
1317 /* can't resize vertically when max vert */
1318 return OB_FRAME_CONTEXT_TITLEBAR
;
1320 if (win
== self
->window
) return OB_FRAME_CONTEXT_FRAME
;
1321 if (win
== self
->label
) return OB_FRAME_CONTEXT_TITLEBAR
;
1322 if (win
== self
->handle
) return OB_FRAME_CONTEXT_BOTTOM
;
1323 if (win
== self
->handletop
) return OB_FRAME_CONTEXT_BOTTOM
;
1324 if (win
== self
->handlebottom
) return OB_FRAME_CONTEXT_BOTTOM
;
1325 if (win
== self
->handleleft
) return OB_FRAME_CONTEXT_BLCORNER
;
1326 if (win
== self
->lgrip
) return OB_FRAME_CONTEXT_BLCORNER
;
1327 if (win
== self
->lgripleft
) return OB_FRAME_CONTEXT_BLCORNER
;
1328 if (win
== self
->lgriptop
) return OB_FRAME_CONTEXT_BLCORNER
;
1329 if (win
== self
->lgripbottom
) return OB_FRAME_CONTEXT_BLCORNER
;
1330 if (win
== self
->handleright
) return OB_FRAME_CONTEXT_BRCORNER
;
1331 if (win
== self
->rgrip
) return OB_FRAME_CONTEXT_BRCORNER
;
1332 if (win
== self
->rgripright
) return OB_FRAME_CONTEXT_BLCORNER
;
1333 if (win
== self
->rgriptop
) return OB_FRAME_CONTEXT_BLCORNER
;
1334 if (win
== self
->rgripbottom
) return OB_FRAME_CONTEXT_BLCORNER
;
1335 if (win
== self
->title
) return OB_FRAME_CONTEXT_TITLEBAR
;
1336 if (win
== self
->titlebottom
) return OB_FRAME_CONTEXT_TITLEBAR
;
1337 if (win
== self
->titleleft
) return OB_FRAME_CONTEXT_TLCORNER
;
1338 if (win
== self
->titletopleft
) return OB_FRAME_CONTEXT_TLCORNER
;
1339 if (win
== self
->titleright
) return OB_FRAME_CONTEXT_TRCORNER
;
1340 if (win
== self
->titletopright
) return OB_FRAME_CONTEXT_TRCORNER
;
1341 if (win
== self
->titletop
) return OB_FRAME_CONTEXT_TOP
;
1342 if (win
== self
->topresize
) return OB_FRAME_CONTEXT_TOP
;
1343 if (win
== self
->tltresize
) return OB_FRAME_CONTEXT_TLCORNER
;
1344 if (win
== self
->tllresize
) return OB_FRAME_CONTEXT_TLCORNER
;
1345 if (win
== self
->trtresize
) return OB_FRAME_CONTEXT_TRCORNER
;
1346 if (win
== self
->trrresize
) return OB_FRAME_CONTEXT_TRCORNER
;
1347 if (win
== self
->left
) return OB_FRAME_CONTEXT_LEFT
;
1348 if (win
== self
->right
) return OB_FRAME_CONTEXT_RIGHT
;
1349 if (win
== self
->innertop
) return OB_FRAME_CONTEXT_TITLEBAR
;
1350 if (win
== self
->innerleft
) return OB_FRAME_CONTEXT_LEFT
;
1351 if (win
== self
->innerbottom
) return OB_FRAME_CONTEXT_BOTTOM
;
1352 if (win
== self
->innerright
) return OB_FRAME_CONTEXT_RIGHT
;
1353 if (win
== self
->max
) return OB_FRAME_CONTEXT_MAXIMIZE
;
1354 if (win
== self
->iconify
) return OB_FRAME_CONTEXT_ICONIFY
;
1355 if (win
== self
->close
) return OB_FRAME_CONTEXT_CLOSE
;
1356 if (win
== self
->icon
) return OB_FRAME_CONTEXT_ICON
;
1357 if (win
== self
->desk
) return OB_FRAME_CONTEXT_ALLDESKTOPS
;
1358 if (win
== self
->shade
) return OB_FRAME_CONTEXT_SHADE
;
1360 return OB_FRAME_CONTEXT_NONE
;
1363 void frame_client_gravity(ObFrame
*self
, gint
*x
, gint
*y
, gint w
, gint h
)
1366 switch (self
->client
->gravity
) {
1368 case NorthWestGravity
:
1369 case SouthWestGravity
:
1376 /* the middle of the client will be the middle of the frame */
1377 *x
-= (self
->size
.right
- self
->size
.left
) / 2;
1380 case NorthEastGravity
:
1381 case SouthEastGravity
:
1383 /* the right side of the client will be the right side of the frame */
1384 *x
-= self
->size
.right
+ self
->size
.left
-
1385 self
->client
->border_width
* 2;
1390 /* the client's position won't move */
1391 *x
-= self
->size
.left
- self
->client
->border_width
;
1396 switch (self
->client
->gravity
) {
1398 case NorthWestGravity
:
1399 case NorthEastGravity
:
1406 /* the middle of the client will be the middle of the frame */
1407 *y
-= (self
->size
.bottom
- self
->size
.top
) / 2;
1410 case SouthWestGravity
:
1411 case SouthEastGravity
:
1413 /* the bottom of the client will be the bottom of the frame */
1414 *y
-= self
->size
.bottom
+ self
->size
.top
-
1415 self
->client
->border_width
* 2;
1420 /* the client's position won't move */
1421 *y
-= self
->size
.top
- self
->client
->border_width
;
1426 void frame_frame_gravity(ObFrame
*self
, gint
*x
, gint
*y
, gint w
, gint h
)
1429 switch (self
->client
->gravity
) {
1431 case NorthWestGravity
:
1433 case SouthWestGravity
:
1438 /* the middle of the client will be the middle of the frame */
1439 *x
+= (self
->size
.right
- self
->size
.left
) / 2;
1441 case NorthEastGravity
:
1443 case SouthEastGravity
:
1444 /* the right side of the client will be the right side of the frame */
1445 *x
+= self
->size
.right
+ self
->size
.left
-
1446 self
->client
->border_width
* 2;
1450 /* the client's position won't move */
1451 *x
+= self
->size
.left
- self
->client
->border_width
;
1456 switch (self
->client
->gravity
) {
1458 case NorthWestGravity
:
1460 case NorthEastGravity
:
1465 /* the middle of the client will be the middle of the frame */
1466 *y
+= (self
->size
.bottom
- self
->size
.top
) / 2;
1468 case SouthWestGravity
:
1470 case SouthEastGravity
:
1471 /* the bottom of the client will be the bottom of the frame */
1472 *y
+= self
->size
.bottom
+ self
->size
.top
-
1473 self
->client
->border_width
* 2;
1477 /* the client's position won't move */
1478 *y
+= self
->size
.top
- self
->client
->border_width
;
1483 static void flash_done(gpointer data
)
1485 ObFrame
*self
= data
;
1487 if (self
->focused
!= self
->flash_on
)
1488 frame_adjust_focus(self
, self
->focused
);
1491 static gboolean
flash_timeout(gpointer data
)
1493 ObFrame
*self
= data
;
1496 g_get_current_time(&now
);
1497 if (now
.tv_sec
> self
->flash_end
.tv_sec
||
1498 (now
.tv_sec
== self
->flash_end
.tv_sec
&&
1499 now
.tv_usec
>= self
->flash_end
.tv_usec
))
1500 self
->flashing
= FALSE
;
1502 if (!self
->flashing
)
1503 return FALSE
; /* we are done */
1505 self
->flash_on
= !self
->flash_on
;
1506 if (!self
->focused
) {
1507 frame_adjust_focus(self
, self
->flash_on
);
1508 self
->focused
= FALSE
;
1511 return TRUE
; /* go again */
1514 void frame_flash_start(ObFrame
*self
)
1516 self
->flash_on
= self
->focused
;
1518 if (!self
->flashing
)
1519 ob_main_loop_timeout_add(ob_main_loop
,
1520 G_USEC_PER_SEC
* 0.6,
1525 g_get_current_time(&self
->flash_end
);
1526 g_time_val_add(&self
->flash_end
, G_USEC_PER_SEC
* 5);
1528 self
->flashing
= TRUE
;
1531 void frame_flash_stop(ObFrame
*self
)
1533 self
->flashing
= FALSE
;
1536 static gulong
frame_animate_iconify_time_left(ObFrame
*self
,
1537 const GTimeVal
*now
)
1540 sec
= self
->iconify_animation_end
.tv_sec
- now
->tv_sec
;
1541 usec
= self
->iconify_animation_end
.tv_usec
- now
->tv_usec
;
1543 usec
+= G_USEC_PER_SEC
;
1546 /* no negative values */
1547 return MAX(sec
* G_USEC_PER_SEC
+ usec
, 0);
1550 static gboolean
frame_animate_iconify(gpointer p
)
1554 gint iconx
, icony
, iconw
;
1557 gboolean iconifying
;
1559 if (self
->client
->icon_geometry
.width
== 0) {
1560 /* there is no icon geometry set so just go straight down */
1561 Rect
*a
= screen_physical_area();
1562 iconx
= self
->area
.x
+ self
->area
.width
/ 2 + 32;
1563 icony
= a
->y
+ a
->width
;
1566 iconx
= self
->client
->icon_geometry
.x
;
1567 icony
= self
->client
->icon_geometry
.y
;
1568 iconw
= self
->client
->icon_geometry
.width
;
1571 iconifying
= self
->iconify_animation_going
> 0;
1573 /* how far do we have left to go ? */
1574 g_get_current_time(&now
);
1575 time
= frame_animate_iconify_time_left(self
, &now
);
1577 if (time
== 0 || iconifying
) {
1578 /* start where the frame is supposed to be */
1581 w
= self
->area
.width
;
1582 h
= self
->area
.height
;
1584 /* start at the icon */
1588 h
= self
->size
.top
; /* just the titlebar */
1595 dx
= self
->area
.x
- iconx
;
1596 dy
= self
->area
.y
- icony
;
1597 dw
= self
->area
.width
- self
->bwidth
* 2 - iconw
;
1598 /* if restoring, we move in the opposite direction */
1599 if (!iconifying
) { dx
= -dx
; dy
= -dy
; dw
= -dw
; }
1601 elapsed
= FRAME_ANIMATE_ICONIFY_TIME
- time
;
1602 x
= x
- (dx
* elapsed
) / FRAME_ANIMATE_ICONIFY_TIME
;
1603 y
= y
- (dy
* elapsed
) / FRAME_ANIMATE_ICONIFY_TIME
;
1604 w
= w
- (dw
* elapsed
) / FRAME_ANIMATE_ICONIFY_TIME
;
1605 h
= self
->size
.top
; /* just the titlebar */
1609 frame_end_iconify_animation(self
);
1611 XMoveResizeWindow(ob_display
, self
->window
, x
, y
, w
, h
);
1615 return time
> 0; /* repeat until we're out of time */
1618 void frame_end_iconify_animation(ObFrame
*self
)
1620 /* see if there is an animation going */
1621 if (self
->iconify_animation_going
== 0) return;
1624 XUnmapWindow(ob_display
, self
->window
);
1626 /* Send a ConfigureNotify when the animation is done, this fixes
1627 KDE's pager showing the window in the wrong place. */
1628 client_reconfigure(self
->client
);
1630 /* we're not animating any more ! */
1631 self
->iconify_animation_going
= 0;
1633 XMoveResizeWindow(ob_display
, self
->window
,
1634 self
->area
.x
, self
->area
.y
,
1635 self
->area
.width
, self
->area
.height
);
1639 void frame_begin_iconify_animation(ObFrame
*self
, gboolean iconifying
)
1642 gboolean new_anim
= FALSE
;
1643 gboolean set_end
= TRUE
;
1646 /* if there is no titlebar, just don't animate for now
1647 XXX it would be nice tho.. */
1648 if (!(self
->decorations
& OB_FRAME_DECOR_TITLEBAR
))
1651 /* get the current time */
1652 g_get_current_time(&now
);
1654 /* get how long until the end */
1655 time
= FRAME_ANIMATE_ICONIFY_TIME
;
1656 if (self
->iconify_animation_going
) {
1657 if (!!iconifying
!= (self
->iconify_animation_going
> 0)) {
1658 /* animation was already going on in the opposite direction */
1659 time
= time
- frame_animate_iconify_time_left(self
, &now
);
1661 /* animation was already going in the same direction */
1665 self
->iconify_animation_going
= iconifying
? 1 : -1;
1667 /* set the ending time */
1669 self
->iconify_animation_end
.tv_sec
= now
.tv_sec
;
1670 self
->iconify_animation_end
.tv_usec
= now
.tv_usec
;
1671 g_time_val_add(&self
->iconify_animation_end
, time
);
1675 ob_main_loop_timeout_remove_data(ob_main_loop
, frame_animate_iconify
,
1677 ob_main_loop_timeout_add(ob_main_loop
,
1678 FRAME_ANIMATE_ICONIFY_STEP_TIME
,
1679 frame_animate_iconify
, self
,
1680 g_direct_equal
, NULL
);
1682 /* do the first step */
1683 frame_animate_iconify(self
);
1685 /* show it during the animation even if it is not "visible" */
1687 XMapWindow(ob_display
, self
->window
);