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)
40 /* The inner window does not need enter/leave events.
41 If it does get them, then it needs its own context for enter events
42 because sloppy focus will focus the window when you enter the inner window
44 #define INNER_EVENTMASK (ButtonPressMask)
46 #define FRAME_ANIMATE_ICONIFY_TIME 150000 /* .15 seconds */
47 #define FRAME_ANIMATE_ICONIFY_STEP_TIME (G_USEC_PER_SEC / 60) /* 60 Hz */
49 #define FRAME_HANDLE_Y(f) (f->size.top + f->client->area.height + f->cbwidth_y)
51 static void flash_done(gpointer data
);
52 static gboolean
flash_timeout(gpointer data
);
54 static void layout_title(ObFrame
*self
);
55 static void set_theme_statics(ObFrame
*self
);
56 static void free_theme_statics(ObFrame
*self
);
57 static gboolean
frame_animate_iconify(gpointer self
);
59 static Window
createWindow(Window parent
, Visual
*visual
,
60 gulong mask
, XSetWindowAttributes
*attrib
)
62 return XCreateWindow(ob_display
, parent
, 0, 0, 1, 1, 0,
63 (visual
? 32 : RrDepth(ob_rr_inst
)), InputOutput
,
64 (visual
? visual
: RrVisual(ob_rr_inst
)),
69 static Visual
*check_32bit_client(ObClient
*c
)
71 XWindowAttributes wattrib
;
74 /* we're already running at 32 bit depth, yay. we don't need to use their
76 if (RrDepth(ob_rr_inst
) == 32)
79 ret
= XGetWindowAttributes(ob_display
, c
->window
, &wattrib
);
80 g_assert(ret
!= BadDrawable
);
81 g_assert(ret
!= BadWindow
);
83 if (wattrib
.depth
== 32)
84 return wattrib
.visual
;
88 ObFrame
*frame_new(ObClient
*client
)
90 XSetWindowAttributes attrib
;
95 self
= g_new0(ObFrame
, 1);
96 self
->client
= client
;
98 visual
= check_32bit_client(client
);
100 /* create the non-visible decor windows */
104 /* client has a 32-bit visual */
105 mask
|= CWColormap
| CWBackPixel
| CWBorderPixel
;
106 /* create a colormap with the visual */
107 self
->colormap
= attrib
.colormap
=
108 XCreateColormap(ob_display
,
109 RootWindow(ob_display
, ob_screen
),
111 attrib
.background_pixel
= BlackPixel(ob_display
, ob_screen
);
112 attrib
.border_pixel
= BlackPixel(ob_display
, ob_screen
);
114 attrib
.event_mask
= FRAME_EVENTMASK
;
115 self
->window
= createWindow(RootWindow(ob_display
, ob_screen
), visual
,
118 attrib
.event_mask
= INNER_EVENTMASK
;
119 self
->inner
= createWindow(self
->window
, visual
, mask
, &attrib
);
121 mask
&= ~CWEventMask
;
122 self
->plate
= createWindow(self
->inner
, visual
, mask
, &attrib
);
124 /* create the visible decor windows */
128 /* client has a 32-bit visual */
129 mask
|= CWColormap
| CWBackPixel
| CWBorderPixel
;
130 attrib
.colormap
= RrColormap(ob_rr_inst
);
132 attrib
.event_mask
= ELEMENT_EVENTMASK
;
133 self
->title
= createWindow(self
->window
, NULL
, mask
, &attrib
);
134 self
->titleleft
= createWindow(self
->window
, NULL
, mask
, &attrib
);
135 self
->titletop
= createWindow(self
->window
, NULL
, mask
, &attrib
);
136 self
->titletopleft
= createWindow(self
->window
, NULL
, mask
, &attrib
);
137 self
->titletopright
= createWindow(self
->window
, NULL
, mask
, &attrib
);
138 self
->titleright
= createWindow(self
->window
, NULL
, mask
, &attrib
);
139 self
->titlebottom
= createWindow(self
->window
, NULL
, mask
, &attrib
);
141 self
->topresize
= createWindow(self
->title
, NULL
, mask
, &attrib
);
142 self
->tltresize
= createWindow(self
->title
, NULL
, mask
, &attrib
);
143 self
->tllresize
= createWindow(self
->title
, NULL
, mask
, &attrib
);
144 self
->trtresize
= createWindow(self
->title
, NULL
, mask
, &attrib
);
145 self
->trrresize
= createWindow(self
->title
, NULL
, mask
, &attrib
);
147 self
->left
= createWindow(self
->window
, NULL
, mask
, &attrib
);
148 self
->right
= createWindow(self
->window
, NULL
, mask
, &attrib
);
150 self
->label
= createWindow(self
->title
, NULL
, mask
, &attrib
);
151 self
->max
= createWindow(self
->title
, NULL
, mask
, &attrib
);
152 self
->close
= createWindow(self
->title
, NULL
, mask
, &attrib
);
153 self
->desk
= createWindow(self
->title
, NULL
, mask
, &attrib
);
154 self
->shade
= createWindow(self
->title
, NULL
, mask
, &attrib
);
155 self
->icon
= createWindow(self
->title
, NULL
, mask
, &attrib
);
156 self
->iconify
= createWindow(self
->title
, NULL
, mask
, &attrib
);
158 self
->handle
= createWindow(self
->window
, NULL
, mask
, &attrib
);
159 self
->lgrip
= createWindow(self
->handle
, NULL
, mask
, &attrib
);
160 self
->rgrip
= createWindow(self
->handle
, NULL
, mask
, &attrib
);
162 self
->handleleft
= createWindow(self
->handle
, NULL
, mask
, &attrib
);
163 self
->handleright
= createWindow(self
->handle
, NULL
, mask
, &attrib
);
165 self
->handletop
= createWindow(self
->window
, NULL
, mask
, &attrib
);
166 self
->handlebottom
= createWindow(self
->window
, NULL
, mask
, &attrib
);
167 self
->lgripleft
= createWindow(self
->window
, NULL
, mask
, &attrib
);
168 self
->lgriptop
= createWindow(self
->window
, NULL
, mask
, &attrib
);
169 self
->lgripbottom
= createWindow(self
->window
, NULL
, mask
, &attrib
);
170 self
->rgripright
= createWindow(self
->window
, NULL
, mask
, &attrib
);
171 self
->rgriptop
= createWindow(self
->window
, NULL
, mask
, &attrib
);
172 self
->rgripbottom
= createWindow(self
->window
, NULL
, mask
, &attrib
);
174 self
->focused
= FALSE
;
176 /* the other stuff is shown based on decor settings */
177 XMapWindow(ob_display
, self
->plate
);
178 XMapWindow(ob_display
, self
->inner
);
179 XMapWindow(ob_display
, self
->label
);
181 self
->max_press
= self
->close_press
= self
->desk_press
=
182 self
->iconify_press
= self
->shade_press
= FALSE
;
183 self
->max_hover
= self
->close_hover
= self
->desk_hover
=
184 self
->iconify_hover
= self
->shade_hover
= FALSE
;
186 set_theme_statics(self
);
188 return (ObFrame
*)self
;
191 static void set_theme_statics(ObFrame
*self
)
193 /* set colors/appearance/sizes for stuff that doesn't change */
194 XResizeWindow(ob_display
, self
->max
,
195 ob_rr_theme
->button_size
, ob_rr_theme
->button_size
);
196 XResizeWindow(ob_display
, self
->iconify
,
197 ob_rr_theme
->button_size
, ob_rr_theme
->button_size
);
198 XResizeWindow(ob_display
, self
->icon
,
199 ob_rr_theme
->button_size
+ 2, ob_rr_theme
->button_size
+ 2);
200 XResizeWindow(ob_display
, self
->close
,
201 ob_rr_theme
->button_size
, ob_rr_theme
->button_size
);
202 XResizeWindow(ob_display
, self
->desk
,
203 ob_rr_theme
->button_size
, ob_rr_theme
->button_size
);
204 XResizeWindow(ob_display
, self
->shade
,
205 ob_rr_theme
->button_size
, ob_rr_theme
->button_size
);
206 XResizeWindow(ob_display
, self
->tltresize
,
207 ob_rr_theme
->grip_width
, ob_rr_theme
->paddingy
+ 1);
208 XResizeWindow(ob_display
, self
->trtresize
,
209 ob_rr_theme
->grip_width
, ob_rr_theme
->paddingy
+ 1);
210 XResizeWindow(ob_display
, self
->tllresize
,
211 ob_rr_theme
->paddingx
+ 1, ob_rr_theme
->title_height
);
212 XResizeWindow(ob_display
, self
->trrresize
,
213 ob_rr_theme
->paddingx
+ 1, ob_rr_theme
->title_height
);
215 /* set up the dynamic appearances */
216 self
->a_unfocused_title
= RrAppearanceCopy(ob_rr_theme
->a_unfocused_title
);
217 self
->a_focused_title
= RrAppearanceCopy(ob_rr_theme
->a_focused_title
);
218 self
->a_unfocused_label
= RrAppearanceCopy(ob_rr_theme
->a_unfocused_label
);
219 self
->a_focused_label
= RrAppearanceCopy(ob_rr_theme
->a_focused_label
);
220 self
->a_unfocused_handle
=
221 RrAppearanceCopy(ob_rr_theme
->a_unfocused_handle
);
222 self
->a_focused_handle
= RrAppearanceCopy(ob_rr_theme
->a_focused_handle
);
223 self
->a_icon
= RrAppearanceCopy(ob_rr_theme
->a_icon
);
226 static void free_theme_statics(ObFrame
*self
)
228 RrAppearanceFree(self
->a_unfocused_title
);
229 RrAppearanceFree(self
->a_focused_title
);
230 RrAppearanceFree(self
->a_unfocused_label
);
231 RrAppearanceFree(self
->a_focused_label
);
232 RrAppearanceFree(self
->a_unfocused_handle
);
233 RrAppearanceFree(self
->a_focused_handle
);
234 RrAppearanceFree(self
->a_icon
);
237 void frame_free(ObFrame
*self
)
239 free_theme_statics(self
);
241 XDestroyWindow(ob_display
, self
->window
);
243 XFreeColormap(ob_display
, self
->colormap
);
248 void frame_show(ObFrame
*self
)
250 if (!self
->visible
) {
251 self
->visible
= TRUE
;
252 XMapWindow(ob_display
, self
->client
->window
);
253 XMapWindow(ob_display
, self
->window
);
257 void frame_hide(ObFrame
*self
)
260 self
->visible
= FALSE
;
261 if (!frame_iconify_animating(self
))
262 XUnmapWindow(ob_display
, self
->window
);
263 /* we unmap the client itself so that we can get MapRequest
264 events, and because the ICCCM tells us to! */
265 XUnmapWindow(ob_display
, self
->client
->window
);
266 self
->client
->ignore_unmaps
+= 1;
270 void frame_adjust_theme(ObFrame
*self
)
272 free_theme_statics(self
);
273 set_theme_statics(self
);
276 void frame_adjust_shape(ObFrame
*self
)
282 if (!self
->client
->shaped
) {
283 /* clear the shape on the frame window */
284 XShapeCombineMask(ob_display
, self
->window
, ShapeBounding
,
289 /* make the frame's shape match the clients */
290 XShapeCombineShape(ob_display
, self
->window
, ShapeBounding
,
293 self
->client
->window
,
294 ShapeBounding
, ShapeSet
);
297 if (self
->decorations
& OB_FRAME_DECOR_TITLEBAR
) {
300 xrect
[0].width
= self
->area
.width
;
301 xrect
[0].height
= ob_rr_theme
->title_height
+
302 self
->bwidth
+ self
->rbwidth
;
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
);
324 void frame_adjust_area(ObFrame
*self
, gboolean moved
,
325 gboolean resized
, gboolean fake
)
329 oldsize
= self
->size
;
332 self
->decorations
= self
->client
->decorations
;
334 if (self
->decorations
& OB_FRAME_DECOR_BORDER
) {
335 self
->bwidth
= ob_rr_theme
->fbwidth
;
336 self
->cbwidth_x
= ob_rr_theme
->cbwidthx
;
337 self
->cbwidth_y
= ob_rr_theme
->cbwidthy
;
339 self
->bwidth
= self
->cbwidth_x
= self
->cbwidth_y
= 0;
341 self
->rbwidth
= self
->bwidth
;
343 self
->max_horz
= self
->client
->max_horz
;
344 self
->max_vert
= self
->client
->max_vert
;
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 STRUT_SET(self
->size
,
353 self
->cbwidth_x
+ (!self
->max_horz
? self
->bwidth
: 0),
354 self
->cbwidth_y
+ self
->bwidth
,
355 self
->cbwidth_x
+ (!self
->max_horz
? self
->bwidth
: 0),
356 self
->cbwidth_y
+ self
->bwidth
);
358 if (self
->decorations
& OB_FRAME_DECOR_TITLEBAR
)
359 self
->size
.top
+= ob_rr_theme
->title_height
+ self
->rbwidth
;
360 if (self
->decorations
& OB_FRAME_DECOR_HANDLE
&&
361 ob_rr_theme
->handle_height
> 0)
363 self
->size
.bottom
+= ob_rr_theme
->handle_height
+ self
->bwidth
;
366 /* position/size and map/unmap all the windows */
370 XMoveResizeWindow(ob_display
, self
->titletop
,
371 ob_rr_theme
->grip_width
+ self
->bwidth
, 0,
372 /* width + bwidth*2 - bwidth*2 - grips*2 */
373 self
->width
+ ob_rr_theme
->grip_width
* 2,
375 XMoveResizeWindow(ob_display
, self
->titletopleft
,
377 ob_rr_theme
->grip_width
+ self
->bwidth
,
379 XMoveResizeWindow(ob_display
, self
->titletopright
,
380 self
->client
->area
.width
+
381 self
->size
.left
+ self
->size
.right
-
382 ob_rr_theme
->grip_width
- self
->bwidth
,
384 ob_rr_theme
->grip_width
+ self
->bwidth
,
387 XMoveResizeWindow(ob_display
, self
->titleleft
,
391 ob_rr_theme
->grip_width
:
392 self
->size
.top
- self
->bwidth
));
393 XMoveResizeWindow(ob_display
, self
->titleright
,
394 self
->client
->area
.width
+
395 self
->size
.left
+ self
->size
.right
-
400 ob_rr_theme
->grip_width
:
401 self
->size
.top
- self
->bwidth
));
403 XMapWindow(ob_display
, self
->titletop
);
404 XMapWindow(ob_display
, self
->titletopleft
);
405 XMapWindow(ob_display
, self
->titletopright
);
406 XMapWindow(ob_display
, self
->titleleft
);
407 XMapWindow(ob_display
, self
->titleright
);
409 if (self
->decorations
& OB_FRAME_DECOR_TITLEBAR
&&
412 XMoveResizeWindow(ob_display
, self
->titlebottom
,
414 ob_rr_theme
->title_height
+ self
->bwidth
,
418 XMapWindow(ob_display
, self
->titlebottom
);
420 XUnmapWindow(ob_display
, self
->titlebottom
);
422 XUnmapWindow(ob_display
, self
->titlebottom
);
424 XUnmapWindow(ob_display
, self
->titletop
);
425 XUnmapWindow(ob_display
, self
->titletopleft
);
426 XUnmapWindow(ob_display
, self
->titletopright
);
427 XUnmapWindow(ob_display
, self
->titleleft
);
428 XUnmapWindow(ob_display
, self
->titleright
);
431 if (self
->decorations
& OB_FRAME_DECOR_TITLEBAR
) {
432 XMoveResizeWindow(ob_display
, self
->title
,
433 self
->bwidth
, self
->bwidth
,
434 self
->width
, ob_rr_theme
->title_height
);
436 XMapWindow(ob_display
, self
->title
);
438 if (self
->decorations
& OB_FRAME_DECOR_GRIPS
) {
439 XMoveResizeWindow(ob_display
, self
->topresize
,
440 ob_rr_theme
->grip_width
+ self
->bwidth
,
442 self
->width
- (ob_rr_theme
->grip_width
+
444 ob_rr_theme
->paddingy
+ 1);
446 XMoveWindow(ob_display
, self
->tltresize
, 0, 0);
447 XMoveWindow(ob_display
, self
->tllresize
, 0, 0);
448 XMoveWindow(ob_display
, self
->trtresize
,
449 self
->width
- ob_rr_theme
->grip_width
, 0);
450 XMoveWindow(ob_display
, self
->trrresize
,
451 self
->width
- ob_rr_theme
->paddingx
- 1, 0);
453 XMapWindow(ob_display
, self
->topresize
);
454 XMapWindow(ob_display
, self
->tltresize
);
455 XMapWindow(ob_display
, self
->tllresize
);
456 XMapWindow(ob_display
, self
->trtresize
);
457 XMapWindow(ob_display
, self
->trrresize
);
459 XUnmapWindow(ob_display
, self
->topresize
);
460 XUnmapWindow(ob_display
, self
->tltresize
);
461 XUnmapWindow(ob_display
, self
->tllresize
);
462 XUnmapWindow(ob_display
, self
->trtresize
);
463 XUnmapWindow(ob_display
, self
->trrresize
);
466 XUnmapWindow(ob_display
, self
->title
);
469 if ((self
->decorations
& OB_FRAME_DECOR_TITLEBAR
))
470 /* layout the title bar elements */
475 XMoveResizeWindow(ob_display
, self
->handlebottom
,
476 ob_rr_theme
->grip_width
+
478 self
->size
.top
+ self
->client
->area
.height
+
479 self
->size
.bottom
- self
->bwidth
,
480 self
->width
- (ob_rr_theme
->grip_width
+
484 XMoveResizeWindow(ob_display
, self
->lgripleft
,
486 self
->size
.top
+ self
->client
->area
.height
+
489 ob_rr_theme
->grip_width
:
493 ob_rr_theme
->grip_width
:
495 XMoveResizeWindow(ob_display
, self
->rgripright
,
496 self
->size
.left
+ self
->client
->area
.width
+
497 self
->size
.right
- self
->bwidth
,
498 self
->size
.top
+ self
->client
->area
.height
+
501 ob_rr_theme
->grip_width
:
505 ob_rr_theme
->grip_width
:
508 XMoveResizeWindow(ob_display
, self
->lgripbottom
,
510 self
->size
.top
+ self
->client
->area
.height
+
511 self
->size
.bottom
- self
->bwidth
,
512 ob_rr_theme
->grip_width
+ self
->bwidth
,
514 XMoveResizeWindow(ob_display
, self
->rgripbottom
,
515 self
->size
.left
+ self
->client
->area
.width
+
516 self
->size
.right
- self
->bwidth
* 2 -
517 ob_rr_theme
->grip_width
,
518 self
->size
.top
+ self
->client
->area
.height
+
519 self
->size
.bottom
- self
->bwidth
,
520 ob_rr_theme
->grip_width
+ self
->bwidth
,
523 XMapWindow(ob_display
, self
->handlebottom
);
524 XMapWindow(ob_display
, self
->lgripleft
);
525 XMapWindow(ob_display
, self
->rgripright
);
526 XMapWindow(ob_display
, self
->lgripbottom
);
527 XMapWindow(ob_display
, self
->rgripbottom
);
529 if (self
->decorations
& OB_FRAME_DECOR_HANDLE
&&
530 ob_rr_theme
->handle_height
> 0)
532 XMoveResizeWindow(ob_display
, self
->handletop
,
533 ob_rr_theme
->grip_width
+
535 FRAME_HANDLE_Y(self
),
536 self
->width
- (ob_rr_theme
->grip_width
+
539 XMapWindow(ob_display
, self
->handletop
);
541 if (self
->decorations
& OB_FRAME_DECOR_GRIPS
) {
542 XMoveResizeWindow(ob_display
, self
->handleleft
,
543 ob_rr_theme
->grip_width
,
546 ob_rr_theme
->handle_height
);
547 XMoveResizeWindow(ob_display
, self
->handleright
,
549 ob_rr_theme
->grip_width
-
553 ob_rr_theme
->handle_height
);
555 XMoveResizeWindow(ob_display
, self
->lgriptop
,
557 FRAME_HANDLE_Y(self
),
558 ob_rr_theme
->grip_width
+
561 XMoveResizeWindow(ob_display
, self
->rgriptop
,
563 self
->client
->area
.width
+
564 self
->size
.right
- self
->bwidth
* 2 -
565 ob_rr_theme
->grip_width
,
566 FRAME_HANDLE_Y(self
),
567 ob_rr_theme
->grip_width
+
571 XMapWindow(ob_display
, self
->handleleft
);
572 XMapWindow(ob_display
, self
->handleright
);
573 XMapWindow(ob_display
, self
->lgriptop
);
574 XMapWindow(ob_display
, self
->rgriptop
);
576 XUnmapWindow(ob_display
, self
->handleleft
);
577 XUnmapWindow(ob_display
, self
->handleright
);
578 XUnmapWindow(ob_display
, self
->lgriptop
);
579 XUnmapWindow(ob_display
, self
->rgriptop
);
582 XUnmapWindow(ob_display
, self
->handleleft
);
583 XUnmapWindow(ob_display
, self
->handleright
);
584 XUnmapWindow(ob_display
, self
->lgriptop
);
585 XUnmapWindow(ob_display
, self
->rgriptop
);
587 XUnmapWindow(ob_display
, self
->handletop
);
590 XUnmapWindow(ob_display
, self
->handleleft
);
591 XUnmapWindow(ob_display
, self
->handleright
);
592 XUnmapWindow(ob_display
, self
->lgriptop
);
593 XUnmapWindow(ob_display
, self
->rgriptop
);
595 XUnmapWindow(ob_display
, self
->handletop
);
597 XUnmapWindow(ob_display
, self
->handlebottom
);
598 XUnmapWindow(ob_display
, self
->lgripleft
);
599 XUnmapWindow(ob_display
, self
->rgripright
);
600 XUnmapWindow(ob_display
, self
->lgripbottom
);
601 XUnmapWindow(ob_display
, self
->rgripbottom
);
604 if (self
->decorations
& OB_FRAME_DECOR_HANDLE
&&
605 ob_rr_theme
->handle_height
> 0)
607 XMoveResizeWindow(ob_display
, self
->handle
,
609 FRAME_HANDLE_Y(self
) + self
->bwidth
,
610 self
->width
, ob_rr_theme
->handle_height
);
611 XMapWindow(ob_display
, self
->handle
);
613 if (self
->decorations
& OB_FRAME_DECOR_GRIPS
) {
614 XMoveResizeWindow(ob_display
, self
->lgrip
,
616 ob_rr_theme
->grip_width
,
617 ob_rr_theme
->handle_height
);
618 XMoveResizeWindow(ob_display
, self
->rgrip
,
619 self
->width
- ob_rr_theme
->grip_width
,
621 ob_rr_theme
->grip_width
,
622 ob_rr_theme
->handle_height
);
624 XMapWindow(ob_display
, self
->lgrip
);
625 XMapWindow(ob_display
, self
->rgrip
);
627 XUnmapWindow(ob_display
, self
->lgrip
);
628 XUnmapWindow(ob_display
, self
->rgrip
);
631 XUnmapWindow(ob_display
, self
->lgrip
);
632 XUnmapWindow(ob_display
, self
->rgrip
);
634 XUnmapWindow(ob_display
, self
->handle
);
637 if (self
->bwidth
&& !self
->max_horz
) {
638 XMoveResizeWindow(ob_display
, self
->left
,
640 self
->bwidth
+ ob_rr_theme
->grip_width
,
642 self
->client
->area
.height
+
643 self
->size
.top
+ self
->size
.bottom
-
644 ob_rr_theme
->grip_width
* 2);
646 XMapWindow(ob_display
, self
->left
);
648 XUnmapWindow(ob_display
, self
->left
);
650 if (self
->bwidth
&& !self
->max_horz
) {
651 XMoveResizeWindow(ob_display
, self
->right
,
652 self
->client
->area
.width
+
653 self
->cbwidth_x
* 2 + self
->bwidth
,
654 self
->bwidth
+ ob_rr_theme
->grip_width
,
656 self
->client
->area
.height
+
657 self
->size
.top
+ self
->size
.bottom
-
658 ob_rr_theme
->grip_width
* 2);
660 XMapWindow(ob_display
, self
->right
);
662 XUnmapWindow(ob_display
, self
->right
);
664 /* move and resize the inner border window which contains the plate
666 XMoveResizeWindow(ob_display
, self
->inner
,
668 self
->size
.top
- self
->cbwidth_y
,
669 self
->client
->area
.width
+
670 self
->cbwidth_x
* 2 +
671 (!self
->max_horz
? self
->bwidth
* 2 : 0),
672 self
->client
->area
.height
+
673 self
->cbwidth_y
* 2);
676 XMoveWindow(ob_display
, self
->plate
,
677 (!self
->max_horz
? self
->bwidth
: 0) + self
->cbwidth_x
,
680 /* when the client has StaticGravity, it likes to move around. */
681 XMoveWindow(ob_display
, self
->client
->window
, 0, 0);
685 /* shading can change without being moved or resized */
686 RECT_SET_SIZE(self
->area
,
687 self
->client
->area
.width
+
688 self
->size
.left
+ self
->size
.right
,
689 (self
->client
->shaded
?
690 ob_rr_theme
->title_height
+ self
->bwidth
* 2:
691 self
->client
->area
.height
+
692 self
->size
.top
+ self
->size
.bottom
));
694 if (moved
|| resized
) {
695 /* find the new coordinates, done after setting the frame.size, for
696 frame_client_gravity. */
697 self
->area
.x
= self
->client
->area
.x
;
698 self
->area
.y
= self
->client
->area
.y
;
699 frame_client_gravity(self
, &self
->area
.x
, &self
->area
.y
,
700 self
->client
->area
.width
,
701 self
->client
->area
.height
);
705 if (!frame_iconify_animating(self
))
706 /* move and resize the top level frame.
707 shading can change without being moved or resized.
709 but don't do this during an iconify animation. it will be
710 reflected afterwards.
712 XMoveResizeWindow(ob_display
, self
->window
,
719 framerender_frame(self
);
720 frame_adjust_shape(self
);
723 if (!STRUT_EQUAL(self
->size
, oldsize
)) {
725 vals
[0] = self
->size
.left
;
726 vals
[1] = self
->size
.right
;
727 vals
[2] = self
->size
.top
;
728 vals
[3] = self
->size
.bottom
;
729 PROP_SETA32(self
->client
->window
, net_frame_extents
,
731 PROP_SETA32(self
->client
->window
, kde_net_wm_frame_strut
,
735 /* if this occurs while we are focus cycling, the indicator needs to
737 if (focus_cycle_target
== self
->client
)
738 focus_cycle_draw_indicator(self
->client
);
740 if (resized
&& (self
->decorations
& OB_FRAME_DECOR_TITLEBAR
))
741 XResizeWindow(ob_display
, self
->label
, self
->label_width
,
742 ob_rr_theme
->label_height
);
746 (self
->functions
& OB_CLIENT_FUNC_RESIZE
) !=
747 (self
->client
->functions
& OB_CLIENT_FUNC_RESIZE
))
749 gboolean r
= self
->client
->functions
& OB_CLIENT_FUNC_RESIZE
&&
750 !(self
->max_horz
&& self
->max_vert
);
751 XSetWindowAttributes a
;
753 a
.cursor
= ob_cursor(r
? OB_CURSOR_NORTH
: OB_CURSOR_NONE
);
754 XChangeWindowAttributes(ob_display
, self
->topresize
, CWCursor
, &a
);
755 XChangeWindowAttributes(ob_display
, self
->titletop
, CWCursor
, &a
);
756 a
.cursor
= ob_cursor(r
? OB_CURSOR_NORTHWEST
: OB_CURSOR_NONE
);
757 XChangeWindowAttributes(ob_display
, self
->tltresize
, CWCursor
, &a
);
758 XChangeWindowAttributes(ob_display
, self
->tllresize
, CWCursor
, &a
);
759 XChangeWindowAttributes(ob_display
, self
->titletopleft
, CWCursor
, &a
);
760 XChangeWindowAttributes(ob_display
, self
->titleleft
, CWCursor
, &a
);
761 a
.cursor
= ob_cursor(r
? OB_CURSOR_NORTHEAST
: OB_CURSOR_NONE
);
762 XChangeWindowAttributes(ob_display
, self
->trtresize
, CWCursor
, &a
);
763 XChangeWindowAttributes(ob_display
, self
->trrresize
, CWCursor
, &a
);
764 XChangeWindowAttributes(ob_display
, self
->titletopright
, CWCursor
, &a
);
765 XChangeWindowAttributes(ob_display
, self
->titleright
, CWCursor
, &a
);
766 a
.cursor
= ob_cursor(r
? OB_CURSOR_WEST
: OB_CURSOR_NONE
);
767 XChangeWindowAttributes(ob_display
, self
->left
, CWCursor
, &a
);
768 a
.cursor
= ob_cursor(r
? OB_CURSOR_EAST
: OB_CURSOR_NONE
);
769 XChangeWindowAttributes(ob_display
, self
->right
, CWCursor
, &a
);
770 a
.cursor
= ob_cursor(r
? OB_CURSOR_SOUTH
: OB_CURSOR_NONE
);
771 XChangeWindowAttributes(ob_display
, self
->handle
, CWCursor
, &a
);
772 XChangeWindowAttributes(ob_display
, self
->handletop
, CWCursor
, &a
);
773 XChangeWindowAttributes(ob_display
, self
->handlebottom
, CWCursor
, &a
);
774 a
.cursor
= ob_cursor(r
? OB_CURSOR_SOUTHWEST
: OB_CURSOR_NONE
);
775 XChangeWindowAttributes(ob_display
, self
->lgrip
, CWCursor
, &a
);
776 XChangeWindowAttributes(ob_display
, self
->handleleft
, CWCursor
, &a
);
777 XChangeWindowAttributes(ob_display
, self
->lgripleft
, CWCursor
, &a
);
778 XChangeWindowAttributes(ob_display
, self
->lgriptop
, CWCursor
, &a
);
779 XChangeWindowAttributes(ob_display
, self
->lgripbottom
, CWCursor
, &a
);
780 a
.cursor
= ob_cursor(r
? OB_CURSOR_SOUTHEAST
: OB_CURSOR_NONE
);
781 XChangeWindowAttributes(ob_display
, self
->rgrip
, CWCursor
, &a
);
782 XChangeWindowAttributes(ob_display
, self
->handleright
, CWCursor
, &a
);
783 XChangeWindowAttributes(ob_display
, self
->rgripright
, CWCursor
, &a
);
784 XChangeWindowAttributes(ob_display
, self
->rgriptop
, CWCursor
, &a
);
785 XChangeWindowAttributes(ob_display
, self
->rgripbottom
, CWCursor
, &a
);
787 self
->functions
= self
->client
->functions
;
791 void frame_adjust_client_area(ObFrame
*self
)
793 /* resize the plate */
794 XResizeWindow(ob_display
, self
->plate
,
795 self
->client
->area
.width
, self
->client
->area
.height
);
798 void frame_adjust_state(ObFrame
*self
)
800 framerender_frame(self
);
803 void frame_adjust_focus(ObFrame
*self
, gboolean hilite
)
805 self
->focused
= hilite
;
806 framerender_frame(self
);
810 void frame_adjust_title(ObFrame
*self
)
812 framerender_frame(self
);
815 void frame_adjust_icon(ObFrame
*self
)
817 framerender_frame(self
);
820 void frame_grab_client(ObFrame
*self
)
822 /* reparent the client to the frame */
823 XReparentWindow(ob_display
, self
->client
->window
, self
->plate
, 0, 0);
826 When reparenting the client window, it is usually not mapped yet, since
827 this occurs from a MapRequest. However, in the case where Openbox is
828 starting up, the window is already mapped, so we'll see unmap events for
829 it. There are 2 unmap events generated that we see, one with the 'event'
830 member set the root window, and one set to the client, but both get
831 handled and need to be ignored.
833 if (ob_state() == OB_STATE_STARTING
)
834 self
->client
->ignore_unmaps
+= 2;
836 /* select the event mask on the client's parent (to receive config/map
837 req's) the ButtonPress is to catch clicks on the client border */
838 XSelectInput(ob_display
, self
->plate
, PLATE_EVENTMASK
);
840 /* map the client so it maps when the frame does */
841 XMapWindow(ob_display
, self
->client
->window
);
843 /* set all the windows for the frame in the window_map */
844 g_hash_table_insert(window_map
, &self
->window
, self
->client
);
845 g_hash_table_insert(window_map
, &self
->plate
, self
->client
);
846 g_hash_table_insert(window_map
, &self
->inner
, self
->client
);
847 g_hash_table_insert(window_map
, &self
->title
, self
->client
);
848 g_hash_table_insert(window_map
, &self
->label
, self
->client
);
849 g_hash_table_insert(window_map
, &self
->max
, self
->client
);
850 g_hash_table_insert(window_map
, &self
->close
, self
->client
);
851 g_hash_table_insert(window_map
, &self
->desk
, self
->client
);
852 g_hash_table_insert(window_map
, &self
->shade
, self
->client
);
853 g_hash_table_insert(window_map
, &self
->icon
, self
->client
);
854 g_hash_table_insert(window_map
, &self
->iconify
, self
->client
);
855 g_hash_table_insert(window_map
, &self
->handle
, self
->client
);
856 g_hash_table_insert(window_map
, &self
->lgrip
, self
->client
);
857 g_hash_table_insert(window_map
, &self
->rgrip
, self
->client
);
858 g_hash_table_insert(window_map
, &self
->topresize
, self
->client
);
859 g_hash_table_insert(window_map
, &self
->tltresize
, self
->client
);
860 g_hash_table_insert(window_map
, &self
->tllresize
, self
->client
);
861 g_hash_table_insert(window_map
, &self
->trtresize
, self
->client
);
862 g_hash_table_insert(window_map
, &self
->trrresize
, self
->client
);
863 g_hash_table_insert(window_map
, &self
->left
, self
->client
);
864 g_hash_table_insert(window_map
, &self
->right
, self
->client
);
865 g_hash_table_insert(window_map
, &self
->titleleft
, self
->client
);
866 g_hash_table_insert(window_map
, &self
->titletop
, self
->client
);
867 g_hash_table_insert(window_map
, &self
->titletopleft
, self
->client
);
868 g_hash_table_insert(window_map
, &self
->titletopright
, self
->client
);
869 g_hash_table_insert(window_map
, &self
->titleright
, self
->client
);
870 g_hash_table_insert(window_map
, &self
->titlebottom
, self
->client
);
871 g_hash_table_insert(window_map
, &self
->handleleft
, self
->client
);
872 g_hash_table_insert(window_map
, &self
->handletop
, self
->client
);
873 g_hash_table_insert(window_map
, &self
->handleright
, self
->client
);
874 g_hash_table_insert(window_map
, &self
->handlebottom
, self
->client
);
875 g_hash_table_insert(window_map
, &self
->lgripleft
, self
->client
);
876 g_hash_table_insert(window_map
, &self
->lgriptop
, self
->client
);
877 g_hash_table_insert(window_map
, &self
->lgripbottom
, self
->client
);
878 g_hash_table_insert(window_map
, &self
->rgripright
, self
->client
);
879 g_hash_table_insert(window_map
, &self
->rgriptop
, self
->client
);
880 g_hash_table_insert(window_map
, &self
->rgripbottom
, self
->client
);
883 void frame_release_client(ObFrame
*self
)
886 gboolean reparent
= TRUE
;
888 /* if there was any animation going on, kill it */
889 ob_main_loop_timeout_remove_data(ob_main_loop
, frame_animate_iconify
,
892 /* check if the app has already reparented its window away */
893 while (XCheckTypedWindowEvent(ob_display
, self
->client
->window
,
894 ReparentNotify
, &ev
))
896 /* This check makes sure we don't catch our own reparent action to
897 our frame window. This doesn't count as the app reparenting itself
900 Reparent events that are generated by us are just discarded here.
901 They are of no consequence to us anyhow.
903 if (ev
.xreparent
.parent
!= self
->plate
) {
905 XPutBackEvent(ob_display
, &ev
);
911 /* according to the ICCCM - if the client doesn't reparent itself,
912 then we will reparent the window to root for them */
913 XReparentWindow(ob_display
, self
->client
->window
,
914 RootWindow(ob_display
, ob_screen
),
915 self
->client
->area
.x
,
916 self
->client
->area
.y
);
919 /* remove all the windows for the frame from the window_map */
920 g_hash_table_remove(window_map
, &self
->window
);
921 g_hash_table_remove(window_map
, &self
->plate
);
922 g_hash_table_remove(window_map
, &self
->inner
);
923 g_hash_table_remove(window_map
, &self
->title
);
924 g_hash_table_remove(window_map
, &self
->label
);
925 g_hash_table_remove(window_map
, &self
->max
);
926 g_hash_table_remove(window_map
, &self
->close
);
927 g_hash_table_remove(window_map
, &self
->desk
);
928 g_hash_table_remove(window_map
, &self
->shade
);
929 g_hash_table_remove(window_map
, &self
->icon
);
930 g_hash_table_remove(window_map
, &self
->iconify
);
931 g_hash_table_remove(window_map
, &self
->handle
);
932 g_hash_table_remove(window_map
, &self
->lgrip
);
933 g_hash_table_remove(window_map
, &self
->rgrip
);
934 g_hash_table_remove(window_map
, &self
->topresize
);
935 g_hash_table_remove(window_map
, &self
->tltresize
);
936 g_hash_table_remove(window_map
, &self
->tllresize
);
937 g_hash_table_remove(window_map
, &self
->trtresize
);
938 g_hash_table_remove(window_map
, &self
->trrresize
);
939 g_hash_table_remove(window_map
, &self
->left
);
940 g_hash_table_remove(window_map
, &self
->right
);
941 g_hash_table_remove(window_map
, &self
->titleleft
);
942 g_hash_table_remove(window_map
, &self
->titletop
);
943 g_hash_table_remove(window_map
, &self
->titletopleft
);
944 g_hash_table_remove(window_map
, &self
->titletopright
);
945 g_hash_table_remove(window_map
, &self
->titleright
);
946 g_hash_table_remove(window_map
, &self
->titlebottom
);
947 g_hash_table_remove(window_map
, &self
->handleleft
);
948 g_hash_table_remove(window_map
, &self
->handletop
);
949 g_hash_table_remove(window_map
, &self
->handleright
);
950 g_hash_table_remove(window_map
, &self
->handlebottom
);
951 g_hash_table_remove(window_map
, &self
->lgripleft
);
952 g_hash_table_remove(window_map
, &self
->lgriptop
);
953 g_hash_table_remove(window_map
, &self
->lgripbottom
);
954 g_hash_table_remove(window_map
, &self
->rgripright
);
955 g_hash_table_remove(window_map
, &self
->rgriptop
);
956 g_hash_table_remove(window_map
, &self
->rgripbottom
);
958 ob_main_loop_timeout_remove_data(ob_main_loop
, flash_timeout
, self
, TRUE
);
961 /* is there anything present between us and the label? */
962 static gboolean
is_button_present(ObFrame
*self
, const gchar
*lc
, gint dir
) {
963 for (; *lc
!= '\0' && lc
>= config_title_layout
; lc
+= dir
) {
964 if (*lc
== ' ') continue; /* it was invalid */
965 if (*lc
== 'N' && self
->decorations
& OB_FRAME_DECOR_ICON
)
967 if (*lc
== 'D' && self
->decorations
& OB_FRAME_DECOR_ALLDESKTOPS
)
969 if (*lc
== 'S' && self
->decorations
& OB_FRAME_DECOR_SHADE
)
971 if (*lc
== 'I' && self
->decorations
& OB_FRAME_DECOR_ICONIFY
)
973 if (*lc
== 'M' && self
->decorations
& OB_FRAME_DECOR_MAXIMIZE
)
975 if (*lc
== 'C' && self
->decorations
& OB_FRAME_DECOR_CLOSE
)
977 if (*lc
== 'L') return FALSE
;
982 static void layout_title(ObFrame
*self
)
987 const gint bwidth
= ob_rr_theme
->button_size
+ ob_rr_theme
->paddingx
+ 1;
988 /* position of the left most button */
989 const gint left
= ob_rr_theme
->paddingx
+ 1;
990 /* position of the right most button */
991 const gint right
= self
->width
- bwidth
;
993 /* turn them all off */
994 self
->icon_on
= self
->desk_on
= self
->shade_on
= self
->iconify_on
=
995 self
->max_on
= self
->close_on
= self
->label_on
= FALSE
;
996 self
->label_width
= self
->width
- (ob_rr_theme
->paddingx
+ 1) * 2;
997 self
->leftmost
= self
->rightmost
= OB_FRAME_CONTEXT_NONE
;
999 /* figure out what's being show, find each element's position, and the
1002 do the ones before the label, then after the label,
1003 i will be +1 the first time through when working to the left,
1004 and -1 the second time through when working to the right */
1005 for (i
= 1; i
>= -1; i
-=2) {
1007 ObFrameContext
*firstcon
;
1011 lc
= config_title_layout
;
1012 firstcon
= &self
->leftmost
;
1015 lc
= config_title_layout
+ strlen(config_title_layout
)-1;
1016 firstcon
= &self
->rightmost
;
1019 /* stop at the end of the string (or the label, which calls break) */
1020 for (; *lc
!= '\0' && lc
>= config_title_layout
; lc
+=i
) {
1023 self
->label_on
= TRUE
;
1026 break; /* break the for loop, do other side of label */
1027 } else if (*lc
== 'N') {
1028 if (firstcon
) *firstcon
= OB_FRAME_CONTEXT_ICON
;
1029 if ((self
->icon_on
= is_button_present(self
, lc
, i
))) {
1030 /* icon is bigger than buttons */
1031 self
->label_width
-= bwidth
+ 2;
1033 x
+= i
* (bwidth
+ 2);
1035 } else if (*lc
== 'D') {
1036 if (firstcon
) *firstcon
= OB_FRAME_CONTEXT_ALLDESKTOPS
;
1037 if ((self
->desk_on
= is_button_present(self
, lc
, i
))) {
1038 self
->label_width
-= bwidth
;
1042 } else if (*lc
== 'S') {
1043 if (firstcon
) *firstcon
= OB_FRAME_CONTEXT_SHADE
;
1044 if ((self
->shade_on
= is_button_present(self
, lc
, i
))) {
1045 self
->label_width
-= bwidth
;
1049 } else if (*lc
== 'I') {
1050 if (firstcon
) *firstcon
= OB_FRAME_CONTEXT_ICONIFY
;
1051 if ((self
->iconify_on
= is_button_present(self
, lc
, i
))) {
1052 self
->label_width
-= bwidth
;
1053 self
->iconify_x
= x
;
1056 } else if (*lc
== 'M') {
1057 if (firstcon
) *firstcon
= OB_FRAME_CONTEXT_MAXIMIZE
;
1058 if ((self
->max_on
= is_button_present(self
, lc
, i
))) {
1059 self
->label_width
-= bwidth
;
1063 } else if (*lc
== 'C') {
1064 if (firstcon
) *firstcon
= OB_FRAME_CONTEXT_CLOSE
;
1065 if ((self
->close_on
= is_button_present(self
, lc
, i
))) {
1066 self
->label_width
-= bwidth
;
1071 continue; /* don't set firstcon */
1076 /* position and map the elements */
1077 if (self
->icon_on
) {
1078 XMapWindow(ob_display
, self
->icon
);
1079 XMoveWindow(ob_display
, self
->icon
, self
->icon_x
,
1080 ob_rr_theme
->paddingy
);
1082 XUnmapWindow(ob_display
, self
->icon
);
1084 if (self
->desk_on
) {
1085 XMapWindow(ob_display
, self
->desk
);
1086 XMoveWindow(ob_display
, self
->desk
, self
->desk_x
,
1087 ob_rr_theme
->paddingy
+ 1);
1089 XUnmapWindow(ob_display
, self
->desk
);
1091 if (self
->shade_on
) {
1092 XMapWindow(ob_display
, self
->shade
);
1093 XMoveWindow(ob_display
, self
->shade
, self
->shade_x
,
1094 ob_rr_theme
->paddingy
+ 1);
1096 XUnmapWindow(ob_display
, self
->shade
);
1098 if (self
->iconify_on
) {
1099 XMapWindow(ob_display
, self
->iconify
);
1100 XMoveWindow(ob_display
, self
->iconify
, self
->iconify_x
,
1101 ob_rr_theme
->paddingy
+ 1);
1103 XUnmapWindow(ob_display
, self
->iconify
);
1106 XMapWindow(ob_display
, self
->max
);
1107 XMoveWindow(ob_display
, self
->max
, self
->max_x
,
1108 ob_rr_theme
->paddingy
+ 1);
1110 XUnmapWindow(ob_display
, self
->max
);
1112 if (self
->close_on
) {
1113 XMapWindow(ob_display
, self
->close
);
1114 XMoveWindow(ob_display
, self
->close
, self
->close_x
,
1115 ob_rr_theme
->paddingy
+ 1);
1117 XUnmapWindow(ob_display
, self
->close
);
1119 if (self
->label_on
) {
1120 self
->label_width
= MAX(1, self
->label_width
); /* no lower than 1 */
1121 XMapWindow(ob_display
, self
->label
);
1122 XMoveWindow(ob_display
, self
->label
, self
->label_x
,
1123 ob_rr_theme
->paddingy
);
1125 XUnmapWindow(ob_display
, self
->label
);
1128 ObFrameContext
frame_context_from_string(const gchar
*name
)
1130 if (!g_ascii_strcasecmp("Desktop", name
))
1131 return OB_FRAME_CONTEXT_DESKTOP
;
1132 else if (!g_ascii_strcasecmp("Root", name
))
1133 return OB_FRAME_CONTEXT_ROOT
;
1134 else if (!g_ascii_strcasecmp("Client", name
))
1135 return OB_FRAME_CONTEXT_CLIENT
;
1136 else if (!g_ascii_strcasecmp("Titlebar", name
))
1137 return OB_FRAME_CONTEXT_TITLEBAR
;
1138 else if (!g_ascii_strcasecmp("Frame", name
))
1139 return OB_FRAME_CONTEXT_FRAME
;
1140 else if (!g_ascii_strcasecmp("TLCorner", name
))
1141 return OB_FRAME_CONTEXT_TLCORNER
;
1142 else if (!g_ascii_strcasecmp("TRCorner", name
))
1143 return OB_FRAME_CONTEXT_TRCORNER
;
1144 else if (!g_ascii_strcasecmp("BLCorner", name
))
1145 return OB_FRAME_CONTEXT_BLCORNER
;
1146 else if (!g_ascii_strcasecmp("BRCorner", name
))
1147 return OB_FRAME_CONTEXT_BRCORNER
;
1148 else if (!g_ascii_strcasecmp("Top", name
))
1149 return OB_FRAME_CONTEXT_TOP
;
1150 else if (!g_ascii_strcasecmp("Bottom", name
))
1151 return OB_FRAME_CONTEXT_BOTTOM
;
1152 else if (!g_ascii_strcasecmp("Left", name
))
1153 return OB_FRAME_CONTEXT_LEFT
;
1154 else if (!g_ascii_strcasecmp("Right", name
))
1155 return OB_FRAME_CONTEXT_RIGHT
;
1156 else if (!g_ascii_strcasecmp("Maximize", name
))
1157 return OB_FRAME_CONTEXT_MAXIMIZE
;
1158 else if (!g_ascii_strcasecmp("AllDesktops", name
))
1159 return OB_FRAME_CONTEXT_ALLDESKTOPS
;
1160 else if (!g_ascii_strcasecmp("Shade", name
))
1161 return OB_FRAME_CONTEXT_SHADE
;
1162 else if (!g_ascii_strcasecmp("Iconify", name
))
1163 return OB_FRAME_CONTEXT_ICONIFY
;
1164 else if (!g_ascii_strcasecmp("Icon", name
))
1165 return OB_FRAME_CONTEXT_ICON
;
1166 else if (!g_ascii_strcasecmp("Close", name
))
1167 return OB_FRAME_CONTEXT_CLOSE
;
1168 else if (!g_ascii_strcasecmp("MoveResize", name
))
1169 return OB_FRAME_CONTEXT_MOVE_RESIZE
;
1170 return OB_FRAME_CONTEXT_NONE
;
1173 ObFrameContext
frame_context(ObClient
*client
, Window win
, gint x
, gint y
)
1177 if (moveresize_in_progress
)
1178 return OB_FRAME_CONTEXT_MOVE_RESIZE
;
1180 if (win
== RootWindow(ob_display
, ob_screen
))
1181 return OB_FRAME_CONTEXT_ROOT
;
1182 if (client
== NULL
) return OB_FRAME_CONTEXT_NONE
;
1183 if (win
== client
->window
) {
1184 /* conceptually, this is the desktop, as far as users are
1186 if (client
->type
== OB_CLIENT_TYPE_DESKTOP
)
1187 return OB_FRAME_CONTEXT_DESKTOP
;
1188 return OB_FRAME_CONTEXT_CLIENT
;
1191 self
= client
->frame
;
1192 if (win
== self
->inner
|| win
== self
->plate
) {
1193 /* conceptually, this is the desktop, as far as users are
1195 if (client
->type
== OB_CLIENT_TYPE_DESKTOP
)
1196 return OB_FRAME_CONTEXT_DESKTOP
;
1197 return OB_FRAME_CONTEXT_CLIENT
;
1200 /* when the user clicks in the corners of the titlebar and the client
1201 is fully maximized, then treat it like they clicked in the
1202 button that is there */
1203 if (self
->max_horz
&& self
->max_vert
&&
1204 (win
== self
->title
||
1205 win
== self
->titleleft
|| win
== self
->titletopleft
||
1206 win
== self
->titleright
|| win
== self
->titletopright
))
1208 /* get the mouse coords in reference to the whole frame */
1212 /* these windows are down a border width from the top of the frame */
1213 if (win
== self
->title
||
1214 win
== self
->titleleft
|| win
== self
->titleright
)
1217 /* title is a border width in from the edge */
1218 if (win
== self
->title
)
1220 /* titletopright is way to the right edge */
1221 else if (win
== self
->titletopright
)
1222 fx
+= self
->area
.width
- (ob_rr_theme
->grip_width
+ self
->bwidth
);
1223 /* titleright is even more way to the right edge */
1224 else if (win
== self
->titleright
)
1225 fx
+= self
->area
.width
- self
->bwidth
;
1227 /* figure out if we're over the area that should be considered a
1229 if (fy
< self
->bwidth
+ ob_rr_theme
->paddingy
+ 1 +
1230 ob_rr_theme
->button_size
)
1232 if (fx
< (self
->bwidth
+ ob_rr_theme
->paddingx
+ 1 +
1233 ob_rr_theme
->button_size
))
1235 if (self
->leftmost
!= OB_FRAME_CONTEXT_NONE
)
1236 return self
->leftmost
;
1238 else if (fx
>= (self
->area
.width
-
1239 (self
->bwidth
+ ob_rr_theme
->paddingx
+ 1 +
1240 ob_rr_theme
->button_size
)))
1242 if (self
->rightmost
!= OB_FRAME_CONTEXT_NONE
)
1243 return self
->rightmost
;
1248 if (win
== self
->window
) return OB_FRAME_CONTEXT_FRAME
;
1249 if (win
== self
->label
) return OB_FRAME_CONTEXT_TITLEBAR
;
1250 if (win
== self
->handle
) return OB_FRAME_CONTEXT_BOTTOM
;
1251 if (win
== self
->handletop
) return OB_FRAME_CONTEXT_BOTTOM
;
1252 if (win
== self
->handlebottom
) return OB_FRAME_CONTEXT_BOTTOM
;
1253 if (win
== self
->handleleft
) return OB_FRAME_CONTEXT_BLCORNER
;
1254 if (win
== self
->lgrip
) return OB_FRAME_CONTEXT_BLCORNER
;
1255 if (win
== self
->lgripleft
) return OB_FRAME_CONTEXT_BLCORNER
;
1256 if (win
== self
->lgriptop
) return OB_FRAME_CONTEXT_BLCORNER
;
1257 if (win
== self
->lgripbottom
) return OB_FRAME_CONTEXT_BLCORNER
;
1258 if (win
== self
->handleright
) return OB_FRAME_CONTEXT_BRCORNER
;
1259 if (win
== self
->rgrip
) return OB_FRAME_CONTEXT_BRCORNER
;
1260 if (win
== self
->rgripright
) return OB_FRAME_CONTEXT_BLCORNER
;
1261 if (win
== self
->rgriptop
) return OB_FRAME_CONTEXT_BLCORNER
;
1262 if (win
== self
->rgripbottom
) return OB_FRAME_CONTEXT_BLCORNER
;
1263 if (win
== self
->title
) return OB_FRAME_CONTEXT_TITLEBAR
;
1264 if (win
== self
->titleleft
) return OB_FRAME_CONTEXT_TLCORNER
;
1265 if (win
== self
->titletopleft
) return OB_FRAME_CONTEXT_TLCORNER
;
1266 if (win
== self
->titleright
) return OB_FRAME_CONTEXT_TRCORNER
;
1267 if (win
== self
->titletopright
) return OB_FRAME_CONTEXT_TRCORNER
;
1268 if (win
== self
->titletop
) return OB_FRAME_CONTEXT_TOP
;
1269 if (win
== self
->topresize
) return OB_FRAME_CONTEXT_TOP
;
1270 if (win
== self
->tltresize
) return OB_FRAME_CONTEXT_TLCORNER
;
1271 if (win
== self
->tllresize
) return OB_FRAME_CONTEXT_TLCORNER
;
1272 if (win
== self
->trtresize
) return OB_FRAME_CONTEXT_TRCORNER
;
1273 if (win
== self
->trrresize
) return OB_FRAME_CONTEXT_TRCORNER
;
1274 if (win
== self
->left
) return OB_FRAME_CONTEXT_LEFT
;
1275 if (win
== self
->right
) return OB_FRAME_CONTEXT_RIGHT
;
1276 if (win
== self
->max
) return OB_FRAME_CONTEXT_MAXIMIZE
;
1277 if (win
== self
->iconify
) return OB_FRAME_CONTEXT_ICONIFY
;
1278 if (win
== self
->close
) return OB_FRAME_CONTEXT_CLOSE
;
1279 if (win
== self
->icon
) return OB_FRAME_CONTEXT_ICON
;
1280 if (win
== self
->desk
) return OB_FRAME_CONTEXT_ALLDESKTOPS
;
1281 if (win
== self
->shade
) return OB_FRAME_CONTEXT_SHADE
;
1283 return OB_FRAME_CONTEXT_NONE
;
1286 void frame_client_gravity(ObFrame
*self
, gint
*x
, gint
*y
, gint w
, gint h
)
1289 switch (self
->client
->gravity
) {
1291 case NorthWestGravity
:
1292 case SouthWestGravity
:
1299 *x
-= (self
->size
.left
+ w
) / 2;
1302 case NorthEastGravity
:
1303 case SouthEastGravity
:
1305 *x
-= (self
->size
.left
+ self
->size
.right
+ w
) - 1;
1310 *x
-= self
->size
.left
;
1315 switch (self
->client
->gravity
) {
1317 case NorthWestGravity
:
1318 case NorthEastGravity
:
1325 *y
-= (self
->size
.top
+ h
) / 2;
1328 case SouthWestGravity
:
1329 case SouthEastGravity
:
1331 *y
-= (self
->size
.top
+ self
->size
.bottom
+ h
) - 1;
1336 *y
-= self
->size
.top
;
1341 void frame_frame_gravity(ObFrame
*self
, gint
*x
, gint
*y
, gint w
, gint h
)
1344 switch (self
->client
->gravity
) {
1346 case NorthWestGravity
:
1348 case SouthWestGravity
:
1353 *x
+= (self
->size
.left
+ w
) / 2;
1355 case NorthEastGravity
:
1357 case SouthEastGravity
:
1358 *x
+= (self
->size
.left
+ self
->size
.right
+ w
) - 1;
1362 *x
+= self
->size
.left
;
1367 switch (self
->client
->gravity
) {
1369 case NorthWestGravity
:
1371 case NorthEastGravity
:
1376 *y
+= (self
->size
.top
+ h
) / 2;
1378 case SouthWestGravity
:
1380 case SouthEastGravity
:
1381 *y
+= (self
->size
.top
+ self
->size
.bottom
+ h
) - 1;
1385 *y
+= self
->size
.top
;
1390 static void flash_done(gpointer data
)
1392 ObFrame
*self
= data
;
1394 if (self
->focused
!= self
->flash_on
)
1395 frame_adjust_focus(self
, self
->focused
);
1398 static gboolean
flash_timeout(gpointer data
)
1400 ObFrame
*self
= data
;
1403 g_get_current_time(&now
);
1404 if (now
.tv_sec
> self
->flash_end
.tv_sec
||
1405 (now
.tv_sec
== self
->flash_end
.tv_sec
&&
1406 now
.tv_usec
>= self
->flash_end
.tv_usec
))
1407 self
->flashing
= FALSE
;
1409 if (!self
->flashing
)
1410 return FALSE
; /* we are done */
1412 self
->flash_on
= !self
->flash_on
;
1413 if (!self
->focused
) {
1414 frame_adjust_focus(self
, self
->flash_on
);
1415 self
->focused
= FALSE
;
1418 return TRUE
; /* go again */
1421 void frame_flash_start(ObFrame
*self
)
1423 self
->flash_on
= self
->focused
;
1425 if (!self
->flashing
)
1426 ob_main_loop_timeout_add(ob_main_loop
,
1427 G_USEC_PER_SEC
* 0.6,
1432 g_get_current_time(&self
->flash_end
);
1433 g_time_val_add(&self
->flash_end
, G_USEC_PER_SEC
* 5);
1435 self
->flashing
= TRUE
;
1438 void frame_flash_stop(ObFrame
*self
)
1440 self
->flashing
= FALSE
;
1443 static gulong
frame_animate_iconify_time_left(ObFrame
*self
,
1444 const GTimeVal
*now
)
1447 sec
= self
->iconify_animation_end
.tv_sec
- now
->tv_sec
;
1448 usec
= self
->iconify_animation_end
.tv_usec
- now
->tv_usec
;
1450 usec
+= G_USEC_PER_SEC
;
1453 /* no negative values */
1454 return MAX(sec
* G_USEC_PER_SEC
+ usec
, 0);
1457 static gboolean
frame_animate_iconify(gpointer p
)
1461 gint iconx
, icony
, iconw
;
1464 gboolean iconifying
;
1466 if (self
->client
->icon_geometry
.width
== 0) {
1467 /* there is no icon geometry set so just go straight down */
1468 Rect
*a
= screen_physical_area();
1469 iconx
= self
->area
.x
+ self
->area
.width
/ 2 + 32;
1470 icony
= a
->y
+ a
->width
;
1473 iconx
= self
->client
->icon_geometry
.x
;
1474 icony
= self
->client
->icon_geometry
.y
;
1475 iconw
= self
->client
->icon_geometry
.width
;
1478 iconifying
= self
->iconify_animation_going
> 0;
1480 /* how far do we have left to go ? */
1481 g_get_current_time(&now
);
1482 time
= frame_animate_iconify_time_left(self
, &now
);
1484 if (time
== 0 || iconifying
) {
1485 /* start where the frame is supposed to be */
1488 w
= self
->area
.width
;
1489 h
= self
->area
.height
;
1491 /* start at the icon */
1495 h
= self
->size
.top
; /* just the titlebar */
1502 dx
= self
->area
.x
- iconx
;
1503 dy
= self
->area
.y
- icony
;
1504 dw
= self
->area
.width
- self
->bwidth
* 2 - iconw
;
1505 /* if restoring, we move in the opposite direction */
1506 if (!iconifying
) { dx
= -dx
; dy
= -dy
; dw
= -dw
; }
1508 elapsed
= FRAME_ANIMATE_ICONIFY_TIME
- time
;
1509 x
= x
- (dx
* elapsed
) / FRAME_ANIMATE_ICONIFY_TIME
;
1510 y
= y
- (dy
* elapsed
) / FRAME_ANIMATE_ICONIFY_TIME
;
1511 w
= w
- (dw
* elapsed
) / FRAME_ANIMATE_ICONIFY_TIME
;
1512 h
= self
->size
.top
; /* just the titlebar */
1516 frame_end_iconify_animation(self
);
1518 XMoveResizeWindow(ob_display
, self
->window
, x
, y
, w
, h
);
1522 return time
> 0; /* repeat until we're out of time */
1525 void frame_end_iconify_animation(ObFrame
*self
)
1527 /* see if there is an animation going */
1528 if (self
->iconify_animation_going
== 0) return;
1531 XUnmapWindow(ob_display
, self
->window
);
1533 /* Send a ConfigureNotify when the animation is done, this fixes
1534 KDE's pager showing the window in the wrong place. */
1535 client_reconfigure(self
->client
);
1537 /* we're not animating any more ! */
1538 self
->iconify_animation_going
= 0;
1540 XMoveResizeWindow(ob_display
, self
->window
,
1541 self
->area
.x
, self
->area
.y
,
1542 self
->area
.width
, self
->area
.height
);
1546 void frame_begin_iconify_animation(ObFrame
*self
, gboolean iconifying
)
1549 gboolean new_anim
= FALSE
;
1550 gboolean set_end
= TRUE
;
1553 /* if there is no titlebar, just don't animate for now
1554 XXX it would be nice tho.. */
1555 if (!(self
->decorations
& OB_FRAME_DECOR_TITLEBAR
))
1558 /* get the current time */
1559 g_get_current_time(&now
);
1561 /* get how long until the end */
1562 time
= FRAME_ANIMATE_ICONIFY_TIME
;
1563 if (self
->iconify_animation_going
) {
1564 if (!!iconifying
!= (self
->iconify_animation_going
> 0)) {
1565 /* animation was already going on in the opposite direction */
1566 time
= time
- frame_animate_iconify_time_left(self
, &now
);
1568 /* animation was already going in the same direction */
1572 self
->iconify_animation_going
= iconifying
? 1 : -1;
1574 /* set the ending time */
1576 self
->iconify_animation_end
.tv_sec
= now
.tv_sec
;
1577 self
->iconify_animation_end
.tv_usec
= now
.tv_usec
;
1578 g_time_val_add(&self
->iconify_animation_end
, time
);
1582 ob_main_loop_timeout_remove_data(ob_main_loop
, frame_animate_iconify
,
1584 ob_main_loop_timeout_add(ob_main_loop
,
1585 FRAME_ANIMATE_ICONIFY_STEP_TIME
,
1586 frame_animate_iconify
, self
,
1587 g_direct_equal
, NULL
);
1589 /* do the first step */
1590 frame_animate_iconify(self
);
1592 /* show it during the animation even if it is not "visible" */
1594 XMapWindow(ob_display
, self
->window
);