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
);
58 static void frame_adjust_cursors(ObFrame
*self
);
60 static Window
createWindow(Window parent
, Visual
*visual
,
61 gulong mask
, XSetWindowAttributes
*attrib
)
63 return XCreateWindow(ob_display
, parent
, 0, 0, 1, 1, 0,
64 (visual
? 32 : RrDepth(ob_rr_inst
)), InputOutput
,
65 (visual
? visual
: RrVisual(ob_rr_inst
)),
70 static Visual
*check_32bit_client(ObClient
*c
)
72 XWindowAttributes wattrib
;
75 /* we're already running at 32 bit depth, yay. we don't need to use their
77 if (RrDepth(ob_rr_inst
) == 32)
80 ret
= XGetWindowAttributes(ob_display
, c
->window
, &wattrib
);
81 g_assert(ret
!= BadDrawable
);
82 g_assert(ret
!= BadWindow
);
84 if (wattrib
.depth
== 32)
85 return wattrib
.visual
;
89 ObFrame
*frame_new(ObClient
*client
)
91 XSetWindowAttributes attrib
;
96 self
= g_new0(ObFrame
, 1);
97 self
->client
= client
;
99 visual
= check_32bit_client(client
);
101 /* create the non-visible decor windows */
105 /* client has a 32-bit visual */
106 mask
|= CWColormap
| CWBackPixel
| CWBorderPixel
;
107 /* create a colormap with the visual */
108 self
->colormap
= attrib
.colormap
=
109 XCreateColormap(ob_display
,
110 RootWindow(ob_display
, ob_screen
),
112 attrib
.background_pixel
= BlackPixel(ob_display
, ob_screen
);
113 attrib
.border_pixel
= BlackPixel(ob_display
, ob_screen
);
115 attrib
.event_mask
= FRAME_EVENTMASK
;
116 self
->window
= createWindow(RootWindow(ob_display
, ob_screen
), visual
,
119 attrib
.event_mask
= INNER_EVENTMASK
;
120 self
->inner
= createWindow(self
->window
, visual
, mask
, &attrib
);
122 mask
&= ~CWEventMask
;
123 self
->plate
= createWindow(self
->inner
, visual
, mask
, &attrib
);
125 /* create the visible decor windows */
129 /* client has a 32-bit visual */
130 mask
|= CWColormap
| CWBackPixel
| CWBorderPixel
;
131 attrib
.colormap
= RrColormap(ob_rr_inst
);
133 attrib
.event_mask
= ELEMENT_EVENTMASK
;
134 self
->title
= createWindow(self
->window
, NULL
, mask
, &attrib
);
135 self
->titleleft
= createWindow(self
->window
, NULL
, mask
, &attrib
);
136 self
->titletop
= createWindow(self
->window
, NULL
, mask
, &attrib
);
137 self
->titletopleft
= createWindow(self
->window
, NULL
, mask
, &attrib
);
138 self
->titletopright
= createWindow(self
->window
, NULL
, mask
, &attrib
);
139 self
->titleright
= createWindow(self
->window
, NULL
, mask
, &attrib
);
140 self
->titlebottom
= createWindow(self
->window
, NULL
, mask
, &attrib
);
142 self
->topresize
= createWindow(self
->title
, NULL
, mask
, &attrib
);
143 self
->tltresize
= createWindow(self
->title
, NULL
, mask
, &attrib
);
144 self
->tllresize
= createWindow(self
->title
, NULL
, mask
, &attrib
);
145 self
->trtresize
= createWindow(self
->title
, NULL
, mask
, &attrib
);
146 self
->trrresize
= createWindow(self
->title
, NULL
, mask
, &attrib
);
148 self
->left
= createWindow(self
->window
, NULL
, mask
, &attrib
);
149 self
->right
= createWindow(self
->window
, NULL
, mask
, &attrib
);
151 self
->label
= createWindow(self
->title
, NULL
, mask
, &attrib
);
152 self
->max
= createWindow(self
->title
, NULL
, mask
, &attrib
);
153 self
->close
= createWindow(self
->title
, NULL
, mask
, &attrib
);
154 self
->desk
= createWindow(self
->title
, NULL
, mask
, &attrib
);
155 self
->shade
= createWindow(self
->title
, NULL
, mask
, &attrib
);
156 self
->icon
= createWindow(self
->title
, NULL
, mask
, &attrib
);
157 self
->iconify
= createWindow(self
->title
, NULL
, mask
, &attrib
);
159 self
->handle
= createWindow(self
->window
, NULL
, mask
, &attrib
);
160 self
->lgrip
= createWindow(self
->handle
, NULL
, mask
, &attrib
);
161 self
->rgrip
= createWindow(self
->handle
, NULL
, mask
, &attrib
);
163 self
->handleleft
= createWindow(self
->handle
, NULL
, mask
, &attrib
);
164 self
->handleright
= createWindow(self
->handle
, NULL
, mask
, &attrib
);
166 self
->handletop
= createWindow(self
->window
, NULL
, mask
, &attrib
);
167 self
->handlebottom
= createWindow(self
->window
, NULL
, mask
, &attrib
);
168 self
->lgripleft
= createWindow(self
->window
, NULL
, mask
, &attrib
);
169 self
->lgriptop
= createWindow(self
->window
, NULL
, mask
, &attrib
);
170 self
->lgripbottom
= createWindow(self
->window
, NULL
, mask
, &attrib
);
171 self
->rgripright
= createWindow(self
->window
, NULL
, mask
, &attrib
);
172 self
->rgriptop
= createWindow(self
->window
, NULL
, mask
, &attrib
);
173 self
->rgripbottom
= createWindow(self
->window
, NULL
, mask
, &attrib
);
175 self
->focused
= FALSE
;
177 /* the other stuff is shown based on decor settings */
178 XMapWindow(ob_display
, self
->plate
);
179 XMapWindow(ob_display
, self
->inner
);
180 XMapWindow(ob_display
, self
->label
);
182 self
->max_press
= self
->close_press
= self
->desk_press
=
183 self
->iconify_press
= self
->shade_press
= FALSE
;
184 self
->max_hover
= self
->close_hover
= self
->desk_hover
=
185 self
->iconify_hover
= self
->shade_hover
= FALSE
;
187 set_theme_statics(self
);
189 return (ObFrame
*)self
;
192 static void set_theme_statics(ObFrame
*self
)
194 /* set colors/appearance/sizes for stuff that doesn't change */
195 XResizeWindow(ob_display
, self
->max
,
196 ob_rr_theme
->button_size
, ob_rr_theme
->button_size
);
197 XResizeWindow(ob_display
, self
->iconify
,
198 ob_rr_theme
->button_size
, ob_rr_theme
->button_size
);
199 XResizeWindow(ob_display
, self
->icon
,
200 ob_rr_theme
->button_size
+ 2, ob_rr_theme
->button_size
+ 2);
201 XResizeWindow(ob_display
, self
->close
,
202 ob_rr_theme
->button_size
, ob_rr_theme
->button_size
);
203 XResizeWindow(ob_display
, self
->desk
,
204 ob_rr_theme
->button_size
, ob_rr_theme
->button_size
);
205 XResizeWindow(ob_display
, self
->shade
,
206 ob_rr_theme
->button_size
, ob_rr_theme
->button_size
);
207 XResizeWindow(ob_display
, self
->tltresize
,
208 ob_rr_theme
->grip_width
, ob_rr_theme
->paddingy
+ 1);
209 XResizeWindow(ob_display
, self
->trtresize
,
210 ob_rr_theme
->grip_width
, ob_rr_theme
->paddingy
+ 1);
211 XResizeWindow(ob_display
, self
->tllresize
,
212 ob_rr_theme
->paddingx
+ 1, ob_rr_theme
->title_height
);
213 XResizeWindow(ob_display
, self
->trrresize
,
214 ob_rr_theme
->paddingx
+ 1, ob_rr_theme
->title_height
);
216 /* set up the dynamic appearances */
217 self
->a_unfocused_title
= RrAppearanceCopy(ob_rr_theme
->a_unfocused_title
);
218 self
->a_focused_title
= RrAppearanceCopy(ob_rr_theme
->a_focused_title
);
219 self
->a_unfocused_label
= RrAppearanceCopy(ob_rr_theme
->a_unfocused_label
);
220 self
->a_focused_label
= RrAppearanceCopy(ob_rr_theme
->a_focused_label
);
221 self
->a_unfocused_handle
=
222 RrAppearanceCopy(ob_rr_theme
->a_unfocused_handle
);
223 self
->a_focused_handle
= RrAppearanceCopy(ob_rr_theme
->a_focused_handle
);
224 self
->a_icon
= RrAppearanceCopy(ob_rr_theme
->a_icon
);
227 static void free_theme_statics(ObFrame
*self
)
229 RrAppearanceFree(self
->a_unfocused_title
);
230 RrAppearanceFree(self
->a_focused_title
);
231 RrAppearanceFree(self
->a_unfocused_label
);
232 RrAppearanceFree(self
->a_focused_label
);
233 RrAppearanceFree(self
->a_unfocused_handle
);
234 RrAppearanceFree(self
->a_focused_handle
);
235 RrAppearanceFree(self
->a_icon
);
238 void frame_free(ObFrame
*self
)
240 free_theme_statics(self
);
242 XDestroyWindow(ob_display
, self
->window
);
244 XFreeColormap(ob_display
, self
->colormap
);
249 void frame_show(ObFrame
*self
)
251 if (!self
->visible
) {
252 self
->visible
= TRUE
;
253 XMapWindow(ob_display
, self
->client
->window
);
254 XMapWindow(ob_display
, self
->window
);
258 void frame_hide(ObFrame
*self
)
261 self
->visible
= FALSE
;
262 if (!frame_iconify_animating(self
))
263 XUnmapWindow(ob_display
, self
->window
);
264 /* we unmap the client itself so that we can get MapRequest
265 events, and because the ICCCM tells us to! */
266 XUnmapWindow(ob_display
, self
->client
->window
);
267 self
->client
->ignore_unmaps
+= 1;
271 void frame_adjust_theme(ObFrame
*self
)
273 free_theme_statics(self
);
274 set_theme_statics(self
);
277 void frame_adjust_shape(ObFrame
*self
)
283 if (!self
->client
->shaped
) {
284 /* clear the shape on the frame window */
285 XShapeCombineMask(ob_display
, self
->window
, ShapeBounding
,
290 /* make the frame's shape match the clients */
291 XShapeCombineShape(ob_display
, self
->window
, ShapeBounding
,
294 self
->client
->window
,
295 ShapeBounding
, ShapeSet
);
298 if (self
->decorations
& OB_FRAME_DECOR_TITLEBAR
) {
301 xrect
[0].width
= self
->area
.width
;
302 xrect
[0].height
= ob_rr_theme
->title_height
+
303 self
->bwidth
+ self
->rbwidth
;
307 if (self
->decorations
& OB_FRAME_DECOR_HANDLE
&&
308 ob_rr_theme
->handle_height
> 0)
311 xrect
[1].y
= FRAME_HANDLE_Y(self
);
312 xrect
[1].width
= self
->area
.width
;
313 xrect
[1].height
= ob_rr_theme
->handle_height
+
318 XShapeCombineRectangles(ob_display
, self
->window
,
319 ShapeBounding
, 0, 0, xrect
, num
,
320 ShapeUnion
, Unsorted
);
325 void frame_adjust_area(ObFrame
*self
, gboolean moved
,
326 gboolean resized
, gboolean fake
)
330 oldsize
= self
->size
;
333 /* do this before changing the frame's status like max_horz max_vert */
334 frame_adjust_cursors(self
);
336 self
->functions
= self
->client
->functions
;
337 self
->decorations
= self
->client
->decorations
;
338 self
->max_horz
= self
->client
->max_horz
;
339 self
->max_vert
= self
->client
->max_vert
;
341 if (self
->decorations
& OB_FRAME_DECOR_BORDER
) {
342 self
->bwidth
= ob_rr_theme
->fbwidth
;
343 self
->cbwidth_x
= ob_rr_theme
->cbwidthx
;
344 self
->cbwidth_y
= ob_rr_theme
->cbwidthy
;
346 self
->bwidth
= self
->cbwidth_x
= self
->cbwidth_y
= 0;
348 self
->rbwidth
= self
->bwidth
;
350 if (self
->max_horz
) {
352 self
->width
= self
->client
->area
.width
- self
->bwidth
* 2;
354 self
->width
= self
->client
->area
.width
+ self
->cbwidth_x
* 2;
356 STRUT_SET(self
->size
,
357 self
->cbwidth_x
+ (!self
->max_horz
? self
->bwidth
: 0),
358 self
->cbwidth_y
+ self
->bwidth
,
359 self
->cbwidth_x
+ (!self
->max_horz
? self
->bwidth
: 0),
360 self
->cbwidth_y
+ self
->bwidth
);
362 if (self
->decorations
& OB_FRAME_DECOR_TITLEBAR
)
363 self
->size
.top
+= ob_rr_theme
->title_height
+ self
->rbwidth
;
364 if (self
->decorations
& OB_FRAME_DECOR_HANDLE
&&
365 ob_rr_theme
->handle_height
> 0)
367 self
->size
.bottom
+= ob_rr_theme
->handle_height
+ self
->bwidth
;
370 /* position/size and map/unmap all the windows */
374 XMoveResizeWindow(ob_display
, self
->titletop
,
375 ob_rr_theme
->grip_width
+ self
->bwidth
, 0,
376 /* width + bwidth*2 - bwidth*2 - grips*2 */
377 self
->width
- ob_rr_theme
->grip_width
* 2,
379 XMoveResizeWindow(ob_display
, self
->titletopleft
,
381 ob_rr_theme
->grip_width
+ self
->bwidth
,
383 XMoveResizeWindow(ob_display
, self
->titletopright
,
384 self
->client
->area
.width
+
385 self
->size
.left
+ self
->size
.right
-
386 ob_rr_theme
->grip_width
- self
->bwidth
,
388 ob_rr_theme
->grip_width
+ self
->bwidth
,
391 XMoveResizeWindow(ob_display
, self
->titleleft
,
395 ob_rr_theme
->grip_width
:
396 self
->size
.top
- self
->bwidth
));
397 XMoveResizeWindow(ob_display
, self
->titleright
,
398 self
->client
->area
.width
+
399 self
->size
.left
+ self
->size
.right
-
404 ob_rr_theme
->grip_width
:
405 self
->size
.top
- self
->bwidth
));
407 XMapWindow(ob_display
, self
->titletop
);
408 XMapWindow(ob_display
, self
->titletopleft
);
409 XMapWindow(ob_display
, self
->titletopright
);
410 XMapWindow(ob_display
, self
->titleleft
);
411 XMapWindow(ob_display
, self
->titleright
);
413 if (self
->decorations
& OB_FRAME_DECOR_TITLEBAR
&&
416 XMoveResizeWindow(ob_display
, self
->titlebottom
,
418 ob_rr_theme
->title_height
+ self
->bwidth
,
422 XMapWindow(ob_display
, self
->titlebottom
);
424 XUnmapWindow(ob_display
, self
->titlebottom
);
426 XUnmapWindow(ob_display
, self
->titlebottom
);
428 XUnmapWindow(ob_display
, self
->titletop
);
429 XUnmapWindow(ob_display
, self
->titletopleft
);
430 XUnmapWindow(ob_display
, self
->titletopright
);
431 XUnmapWindow(ob_display
, self
->titleleft
);
432 XUnmapWindow(ob_display
, self
->titleright
);
435 if (self
->decorations
& OB_FRAME_DECOR_TITLEBAR
) {
436 XMoveResizeWindow(ob_display
, self
->title
,
437 self
->bwidth
, self
->bwidth
,
438 self
->width
, ob_rr_theme
->title_height
);
440 XMapWindow(ob_display
, self
->title
);
442 if (self
->decorations
& OB_FRAME_DECOR_GRIPS
) {
443 XMoveResizeWindow(ob_display
, self
->topresize
,
444 ob_rr_theme
->grip_width
,
446 self
->width
- ob_rr_theme
->grip_width
*2,
447 ob_rr_theme
->paddingy
+ 1);
449 XMoveWindow(ob_display
, self
->tltresize
, 0, 0);
450 XMoveWindow(ob_display
, self
->tllresize
, 0, 0);
451 XMoveWindow(ob_display
, self
->trtresize
,
452 self
->width
- ob_rr_theme
->grip_width
, 0);
453 XMoveWindow(ob_display
, self
->trrresize
,
454 self
->width
- ob_rr_theme
->paddingx
- 1, 0);
456 XMapWindow(ob_display
, self
->topresize
);
457 XMapWindow(ob_display
, self
->tltresize
);
458 XMapWindow(ob_display
, self
->tllresize
);
459 XMapWindow(ob_display
, self
->trtresize
);
460 XMapWindow(ob_display
, self
->trrresize
);
462 XUnmapWindow(ob_display
, self
->topresize
);
463 XUnmapWindow(ob_display
, self
->tltresize
);
464 XUnmapWindow(ob_display
, self
->tllresize
);
465 XUnmapWindow(ob_display
, self
->trtresize
);
466 XUnmapWindow(ob_display
, self
->trrresize
);
469 XUnmapWindow(ob_display
, self
->title
);
472 if ((self
->decorations
& OB_FRAME_DECOR_TITLEBAR
))
473 /* layout the title bar elements */
478 XMoveResizeWindow(ob_display
, self
->handlebottom
,
479 ob_rr_theme
->grip_width
+
481 self
->size
.top
+ self
->client
->area
.height
+
482 self
->size
.bottom
- self
->bwidth
,
483 self
->width
- (ob_rr_theme
->grip_width
+
487 XMoveResizeWindow(ob_display
, self
->lgripleft
,
489 self
->size
.top
+ self
->client
->area
.height
+
492 ob_rr_theme
->grip_width
:
496 ob_rr_theme
->grip_width
:
498 XMoveResizeWindow(ob_display
, self
->rgripright
,
499 self
->size
.left
+ self
->client
->area
.width
+
500 self
->size
.right
- self
->bwidth
,
501 self
->size
.top
+ self
->client
->area
.height
+
504 ob_rr_theme
->grip_width
:
508 ob_rr_theme
->grip_width
:
511 XMoveResizeWindow(ob_display
, self
->lgripbottom
,
513 self
->size
.top
+ self
->client
->area
.height
+
514 self
->size
.bottom
- self
->bwidth
,
515 ob_rr_theme
->grip_width
+ self
->bwidth
,
517 XMoveResizeWindow(ob_display
, self
->rgripbottom
,
518 self
->size
.left
+ self
->client
->area
.width
+
519 self
->size
.right
- self
->bwidth
* 2 -
520 ob_rr_theme
->grip_width
,
521 self
->size
.top
+ self
->client
->area
.height
+
522 self
->size
.bottom
- self
->bwidth
,
523 ob_rr_theme
->grip_width
+ self
->bwidth
,
526 XMapWindow(ob_display
, self
->handlebottom
);
527 XMapWindow(ob_display
, self
->lgripleft
);
528 XMapWindow(ob_display
, self
->rgripright
);
529 XMapWindow(ob_display
, self
->lgripbottom
);
530 XMapWindow(ob_display
, self
->rgripbottom
);
532 if (self
->decorations
& OB_FRAME_DECOR_HANDLE
&&
533 ob_rr_theme
->handle_height
> 0)
535 XMoveResizeWindow(ob_display
, self
->handletop
,
536 ob_rr_theme
->grip_width
+
538 FRAME_HANDLE_Y(self
),
539 self
->width
- (ob_rr_theme
->grip_width
+
542 XMapWindow(ob_display
, self
->handletop
);
544 if (self
->decorations
& OB_FRAME_DECOR_GRIPS
) {
545 XMoveResizeWindow(ob_display
, self
->handleleft
,
546 ob_rr_theme
->grip_width
,
549 ob_rr_theme
->handle_height
);
550 XMoveResizeWindow(ob_display
, self
->handleright
,
552 ob_rr_theme
->grip_width
-
556 ob_rr_theme
->handle_height
);
558 XMoveResizeWindow(ob_display
, self
->lgriptop
,
560 FRAME_HANDLE_Y(self
),
561 ob_rr_theme
->grip_width
+
564 XMoveResizeWindow(ob_display
, self
->rgriptop
,
566 self
->client
->area
.width
+
567 self
->size
.right
- self
->bwidth
* 2 -
568 ob_rr_theme
->grip_width
,
569 FRAME_HANDLE_Y(self
),
570 ob_rr_theme
->grip_width
+
574 XMapWindow(ob_display
, self
->handleleft
);
575 XMapWindow(ob_display
, self
->handleright
);
576 XMapWindow(ob_display
, self
->lgriptop
);
577 XMapWindow(ob_display
, self
->rgriptop
);
579 XUnmapWindow(ob_display
, self
->handleleft
);
580 XUnmapWindow(ob_display
, self
->handleright
);
581 XUnmapWindow(ob_display
, self
->lgriptop
);
582 XUnmapWindow(ob_display
, self
->rgriptop
);
585 XUnmapWindow(ob_display
, self
->handleleft
);
586 XUnmapWindow(ob_display
, self
->handleright
);
587 XUnmapWindow(ob_display
, self
->lgriptop
);
588 XUnmapWindow(ob_display
, self
->rgriptop
);
590 XUnmapWindow(ob_display
, self
->handletop
);
593 XUnmapWindow(ob_display
, self
->handleleft
);
594 XUnmapWindow(ob_display
, self
->handleright
);
595 XUnmapWindow(ob_display
, self
->lgriptop
);
596 XUnmapWindow(ob_display
, self
->rgriptop
);
598 XUnmapWindow(ob_display
, self
->handletop
);
600 XUnmapWindow(ob_display
, self
->handlebottom
);
601 XUnmapWindow(ob_display
, self
->lgripleft
);
602 XUnmapWindow(ob_display
, self
->rgripright
);
603 XUnmapWindow(ob_display
, self
->lgripbottom
);
604 XUnmapWindow(ob_display
, self
->rgripbottom
);
607 if (self
->decorations
& OB_FRAME_DECOR_HANDLE
&&
608 ob_rr_theme
->handle_height
> 0)
610 XMoveResizeWindow(ob_display
, self
->handle
,
612 FRAME_HANDLE_Y(self
) + self
->bwidth
,
613 self
->width
, ob_rr_theme
->handle_height
);
614 XMapWindow(ob_display
, self
->handle
);
616 if (self
->decorations
& OB_FRAME_DECOR_GRIPS
) {
617 XMoveResizeWindow(ob_display
, self
->lgrip
,
619 ob_rr_theme
->grip_width
,
620 ob_rr_theme
->handle_height
);
621 XMoveResizeWindow(ob_display
, self
->rgrip
,
622 self
->width
- ob_rr_theme
->grip_width
,
624 ob_rr_theme
->grip_width
,
625 ob_rr_theme
->handle_height
);
627 XMapWindow(ob_display
, self
->lgrip
);
628 XMapWindow(ob_display
, self
->rgrip
);
630 XUnmapWindow(ob_display
, self
->lgrip
);
631 XUnmapWindow(ob_display
, self
->rgrip
);
634 XUnmapWindow(ob_display
, self
->lgrip
);
635 XUnmapWindow(ob_display
, self
->rgrip
);
637 XUnmapWindow(ob_display
, self
->handle
);
640 if (self
->bwidth
&& !self
->max_horz
) {
641 XMoveResizeWindow(ob_display
, self
->left
,
643 self
->bwidth
+ ob_rr_theme
->grip_width
,
645 self
->client
->area
.height
+
646 self
->size
.top
+ self
->size
.bottom
-
647 ob_rr_theme
->grip_width
* 2);
649 XMapWindow(ob_display
, self
->left
);
651 XUnmapWindow(ob_display
, self
->left
);
653 if (self
->bwidth
&& !self
->max_horz
) {
654 XMoveResizeWindow(ob_display
, self
->right
,
655 self
->client
->area
.width
+
656 self
->cbwidth_x
* 2 + self
->bwidth
,
657 self
->bwidth
+ ob_rr_theme
->grip_width
,
659 self
->client
->area
.height
+
660 self
->size
.top
+ self
->size
.bottom
-
661 ob_rr_theme
->grip_width
* 2);
663 XMapWindow(ob_display
, self
->right
);
665 XUnmapWindow(ob_display
, self
->right
);
667 /* move and resize the inner border window which contains the plate
669 XMoveResizeWindow(ob_display
, self
->inner
,
671 self
->size
.top
- self
->cbwidth_y
,
672 self
->client
->area
.width
+
673 self
->cbwidth_x
* 2 +
674 (!self
->max_horz
? self
->bwidth
* 2 : 0),
675 self
->client
->area
.height
+
676 self
->cbwidth_y
* 2);
679 XMoveWindow(ob_display
, self
->plate
,
680 (!self
->max_horz
? self
->bwidth
: 0) + self
->cbwidth_x
,
683 /* when the client has StaticGravity, it likes to move around. */
684 XMoveWindow(ob_display
, self
->client
->window
, 0, 0);
688 /* shading can change without being moved or resized */
689 RECT_SET_SIZE(self
->area
,
690 self
->client
->area
.width
+
691 self
->size
.left
+ self
->size
.right
,
692 (self
->client
->shaded
?
693 ob_rr_theme
->title_height
+ self
->bwidth
* 2:
694 self
->client
->area
.height
+
695 self
->size
.top
+ self
->size
.bottom
));
697 if ((moved
|| resized
) && !fake
) {
698 /* find the new coordinates, done after setting the frame.size, for
699 frame_client_gravity. */
700 self
->area
.x
= self
->client
->area
.x
;
701 self
->area
.y
= self
->client
->area
.y
;
702 frame_client_gravity(self
, &self
->area
.x
, &self
->area
.y
,
703 self
->client
->area
.width
,
704 self
->client
->area
.height
);
708 if (!frame_iconify_animating(self
))
709 /* move and resize the top level frame.
710 shading can change without being moved or resized.
712 but don't do this during an iconify animation. it will be
713 reflected afterwards.
715 XMoveResizeWindow(ob_display
, self
->window
,
722 framerender_frame(self
);
723 frame_adjust_shape(self
);
726 if (!STRUT_EQUAL(self
->size
, oldsize
)) {
728 vals
[0] = self
->size
.left
;
729 vals
[1] = self
->size
.right
;
730 vals
[2] = self
->size
.top
;
731 vals
[3] = self
->size
.bottom
;
732 PROP_SETA32(self
->client
->window
, net_frame_extents
,
734 PROP_SETA32(self
->client
->window
, kde_net_wm_frame_strut
,
738 /* if this occurs while we are focus cycling, the indicator needs to
740 if (focus_cycle_target
== self
->client
)
741 focus_cycle_draw_indicator(self
->client
);
743 if (resized
&& (self
->decorations
& OB_FRAME_DECOR_TITLEBAR
))
744 XResizeWindow(ob_display
, self
->label
, self
->label_width
,
745 ob_rr_theme
->label_height
);
748 static void frame_adjust_cursors(ObFrame
*self
)
750 if ((self
->functions
& OB_CLIENT_FUNC_RESIZE
) !=
751 (self
->client
->functions
& OB_CLIENT_FUNC_RESIZE
) ||
752 self
->max_horz
!= self
->client
->max_horz
||
753 self
->max_vert
!= self
->client
->max_vert
)
755 gboolean r
= (self
->client
->functions
& OB_CLIENT_FUNC_RESIZE
) &&
756 !(self
->client
->max_horz
&& self
->client
->max_vert
);
757 gboolean topbot
= !self
->client
->max_vert
;
758 XSetWindowAttributes a
;
760 /* these ones turn off when max vert */
761 a
.cursor
= ob_cursor(r
&& topbot
? OB_CURSOR_NORTH
: OB_CURSOR_NONE
);
762 XChangeWindowAttributes(ob_display
, self
->topresize
, CWCursor
, &a
);
763 XChangeWindowAttributes(ob_display
, self
->titletop
, CWCursor
, &a
);
764 a
.cursor
= ob_cursor(r
&& topbot
? OB_CURSOR_SOUTH
: OB_CURSOR_NONE
);
765 XChangeWindowAttributes(ob_display
, self
->handle
, CWCursor
, &a
);
766 XChangeWindowAttributes(ob_display
, self
->handletop
, CWCursor
, &a
);
767 XChangeWindowAttributes(ob_display
, self
->handlebottom
, CWCursor
, &a
);
769 /* these ones don't */
770 a
.cursor
= ob_cursor(r
? OB_CURSOR_NORTHWEST
: OB_CURSOR_NONE
);
771 XChangeWindowAttributes(ob_display
, self
->tltresize
, CWCursor
, &a
);
772 XChangeWindowAttributes(ob_display
, self
->tllresize
, CWCursor
, &a
);
773 XChangeWindowAttributes(ob_display
, self
->titletopleft
, CWCursor
, &a
);
774 XChangeWindowAttributes(ob_display
, self
->titleleft
, CWCursor
, &a
);
775 a
.cursor
= ob_cursor(r
? OB_CURSOR_NORTHEAST
: OB_CURSOR_NONE
);
776 XChangeWindowAttributes(ob_display
, self
->trtresize
, CWCursor
, &a
);
777 XChangeWindowAttributes(ob_display
, self
->trrresize
, CWCursor
, &a
);
778 XChangeWindowAttributes(ob_display
, self
->titletopright
, CWCursor
, &a
);
779 XChangeWindowAttributes(ob_display
, self
->titleright
, CWCursor
, &a
);
780 a
.cursor
= ob_cursor(r
? OB_CURSOR_WEST
: OB_CURSOR_NONE
);
781 XChangeWindowAttributes(ob_display
, self
->left
, CWCursor
, &a
);
782 a
.cursor
= ob_cursor(r
? OB_CURSOR_EAST
: OB_CURSOR_NONE
);
783 XChangeWindowAttributes(ob_display
, self
->right
, CWCursor
, &a
);
784 a
.cursor
= ob_cursor(r
? OB_CURSOR_SOUTHWEST
: OB_CURSOR_NONE
);
785 XChangeWindowAttributes(ob_display
, self
->lgrip
, CWCursor
, &a
);
786 XChangeWindowAttributes(ob_display
, self
->handleleft
, CWCursor
, &a
);
787 XChangeWindowAttributes(ob_display
, self
->lgripleft
, CWCursor
, &a
);
788 XChangeWindowAttributes(ob_display
, self
->lgriptop
, CWCursor
, &a
);
789 XChangeWindowAttributes(ob_display
, self
->lgripbottom
, CWCursor
, &a
);
790 a
.cursor
= ob_cursor(r
? OB_CURSOR_SOUTHEAST
: OB_CURSOR_NONE
);
791 XChangeWindowAttributes(ob_display
, self
->rgrip
, CWCursor
, &a
);
792 XChangeWindowAttributes(ob_display
, self
->handleright
, CWCursor
, &a
);
793 XChangeWindowAttributes(ob_display
, self
->rgripright
, CWCursor
, &a
);
794 XChangeWindowAttributes(ob_display
, self
->rgriptop
, CWCursor
, &a
);
795 XChangeWindowAttributes(ob_display
, self
->rgripbottom
, CWCursor
, &a
);
799 void frame_adjust_client_area(ObFrame
*self
)
801 /* resize the plate */
802 XResizeWindow(ob_display
, self
->plate
,
803 self
->client
->area
.width
, self
->client
->area
.height
);
806 void frame_adjust_state(ObFrame
*self
)
808 framerender_frame(self
);
811 void frame_adjust_focus(ObFrame
*self
, gboolean hilite
)
813 self
->focused
= hilite
;
814 framerender_frame(self
);
818 void frame_adjust_title(ObFrame
*self
)
820 framerender_frame(self
);
823 void frame_adjust_icon(ObFrame
*self
)
825 framerender_frame(self
);
828 void frame_grab_client(ObFrame
*self
)
830 /* reparent the client to the frame */
831 XReparentWindow(ob_display
, self
->client
->window
, self
->plate
, 0, 0);
834 When reparenting the client window, it is usually not mapped yet, since
835 this occurs from a MapRequest. However, in the case where Openbox is
836 starting up, the window is already mapped, so we'll see unmap events for
837 it. There are 2 unmap events generated that we see, one with the 'event'
838 member set the root window, and one set to the client, but both get
839 handled and need to be ignored.
841 if (ob_state() == OB_STATE_STARTING
)
842 self
->client
->ignore_unmaps
+= 2;
844 /* select the event mask on the client's parent (to receive config/map
845 req's) the ButtonPress is to catch clicks on the client border */
846 XSelectInput(ob_display
, self
->plate
, PLATE_EVENTMASK
);
848 /* map the client so it maps when the frame does */
849 XMapWindow(ob_display
, self
->client
->window
);
851 /* set all the windows for the frame in the window_map */
852 g_hash_table_insert(window_map
, &self
->window
, self
->client
);
853 g_hash_table_insert(window_map
, &self
->plate
, self
->client
);
854 g_hash_table_insert(window_map
, &self
->inner
, self
->client
);
855 g_hash_table_insert(window_map
, &self
->title
, self
->client
);
856 g_hash_table_insert(window_map
, &self
->label
, self
->client
);
857 g_hash_table_insert(window_map
, &self
->max
, self
->client
);
858 g_hash_table_insert(window_map
, &self
->close
, self
->client
);
859 g_hash_table_insert(window_map
, &self
->desk
, self
->client
);
860 g_hash_table_insert(window_map
, &self
->shade
, self
->client
);
861 g_hash_table_insert(window_map
, &self
->icon
, self
->client
);
862 g_hash_table_insert(window_map
, &self
->iconify
, self
->client
);
863 g_hash_table_insert(window_map
, &self
->handle
, self
->client
);
864 g_hash_table_insert(window_map
, &self
->lgrip
, self
->client
);
865 g_hash_table_insert(window_map
, &self
->rgrip
, self
->client
);
866 g_hash_table_insert(window_map
, &self
->topresize
, self
->client
);
867 g_hash_table_insert(window_map
, &self
->tltresize
, self
->client
);
868 g_hash_table_insert(window_map
, &self
->tllresize
, self
->client
);
869 g_hash_table_insert(window_map
, &self
->trtresize
, self
->client
);
870 g_hash_table_insert(window_map
, &self
->trrresize
, self
->client
);
871 g_hash_table_insert(window_map
, &self
->left
, self
->client
);
872 g_hash_table_insert(window_map
, &self
->right
, self
->client
);
873 g_hash_table_insert(window_map
, &self
->titleleft
, self
->client
);
874 g_hash_table_insert(window_map
, &self
->titletop
, self
->client
);
875 g_hash_table_insert(window_map
, &self
->titletopleft
, self
->client
);
876 g_hash_table_insert(window_map
, &self
->titletopright
, self
->client
);
877 g_hash_table_insert(window_map
, &self
->titleright
, self
->client
);
878 g_hash_table_insert(window_map
, &self
->titlebottom
, self
->client
);
879 g_hash_table_insert(window_map
, &self
->handleleft
, self
->client
);
880 g_hash_table_insert(window_map
, &self
->handletop
, self
->client
);
881 g_hash_table_insert(window_map
, &self
->handleright
, self
->client
);
882 g_hash_table_insert(window_map
, &self
->handlebottom
, self
->client
);
883 g_hash_table_insert(window_map
, &self
->lgripleft
, self
->client
);
884 g_hash_table_insert(window_map
, &self
->lgriptop
, self
->client
);
885 g_hash_table_insert(window_map
, &self
->lgripbottom
, self
->client
);
886 g_hash_table_insert(window_map
, &self
->rgripright
, self
->client
);
887 g_hash_table_insert(window_map
, &self
->rgriptop
, self
->client
);
888 g_hash_table_insert(window_map
, &self
->rgripbottom
, self
->client
);
891 void frame_release_client(ObFrame
*self
)
894 gboolean reparent
= TRUE
;
896 /* if there was any animation going on, kill it */
897 ob_main_loop_timeout_remove_data(ob_main_loop
, frame_animate_iconify
,
900 /* check if the app has already reparented its window away */
901 while (XCheckTypedWindowEvent(ob_display
, self
->client
->window
,
902 ReparentNotify
, &ev
))
904 /* This check makes sure we don't catch our own reparent action to
905 our frame window. This doesn't count as the app reparenting itself
908 Reparent events that are generated by us are just discarded here.
909 They are of no consequence to us anyhow.
911 if (ev
.xreparent
.parent
!= self
->plate
) {
913 XPutBackEvent(ob_display
, &ev
);
919 /* according to the ICCCM - if the client doesn't reparent itself,
920 then we will reparent the window to root for them */
921 XReparentWindow(ob_display
, self
->client
->window
,
922 RootWindow(ob_display
, ob_screen
),
923 self
->client
->area
.x
,
924 self
->client
->area
.y
);
927 /* remove all the windows for the frame from the window_map */
928 g_hash_table_remove(window_map
, &self
->window
);
929 g_hash_table_remove(window_map
, &self
->plate
);
930 g_hash_table_remove(window_map
, &self
->inner
);
931 g_hash_table_remove(window_map
, &self
->title
);
932 g_hash_table_remove(window_map
, &self
->label
);
933 g_hash_table_remove(window_map
, &self
->max
);
934 g_hash_table_remove(window_map
, &self
->close
);
935 g_hash_table_remove(window_map
, &self
->desk
);
936 g_hash_table_remove(window_map
, &self
->shade
);
937 g_hash_table_remove(window_map
, &self
->icon
);
938 g_hash_table_remove(window_map
, &self
->iconify
);
939 g_hash_table_remove(window_map
, &self
->handle
);
940 g_hash_table_remove(window_map
, &self
->lgrip
);
941 g_hash_table_remove(window_map
, &self
->rgrip
);
942 g_hash_table_remove(window_map
, &self
->topresize
);
943 g_hash_table_remove(window_map
, &self
->tltresize
);
944 g_hash_table_remove(window_map
, &self
->tllresize
);
945 g_hash_table_remove(window_map
, &self
->trtresize
);
946 g_hash_table_remove(window_map
, &self
->trrresize
);
947 g_hash_table_remove(window_map
, &self
->left
);
948 g_hash_table_remove(window_map
, &self
->right
);
949 g_hash_table_remove(window_map
, &self
->titleleft
);
950 g_hash_table_remove(window_map
, &self
->titletop
);
951 g_hash_table_remove(window_map
, &self
->titletopleft
);
952 g_hash_table_remove(window_map
, &self
->titletopright
);
953 g_hash_table_remove(window_map
, &self
->titleright
);
954 g_hash_table_remove(window_map
, &self
->titlebottom
);
955 g_hash_table_remove(window_map
, &self
->handleleft
);
956 g_hash_table_remove(window_map
, &self
->handletop
);
957 g_hash_table_remove(window_map
, &self
->handleright
);
958 g_hash_table_remove(window_map
, &self
->handlebottom
);
959 g_hash_table_remove(window_map
, &self
->lgripleft
);
960 g_hash_table_remove(window_map
, &self
->lgriptop
);
961 g_hash_table_remove(window_map
, &self
->lgripbottom
);
962 g_hash_table_remove(window_map
, &self
->rgripright
);
963 g_hash_table_remove(window_map
, &self
->rgriptop
);
964 g_hash_table_remove(window_map
, &self
->rgripbottom
);
966 ob_main_loop_timeout_remove_data(ob_main_loop
, flash_timeout
, self
, TRUE
);
969 /* is there anything present between us and the label? */
970 static gboolean
is_button_present(ObFrame
*self
, const gchar
*lc
, gint dir
) {
971 for (; *lc
!= '\0' && lc
>= config_title_layout
; lc
+= dir
) {
972 if (*lc
== ' ') continue; /* it was invalid */
973 if (*lc
== 'N' && self
->decorations
& OB_FRAME_DECOR_ICON
)
975 if (*lc
== 'D' && self
->decorations
& OB_FRAME_DECOR_ALLDESKTOPS
)
977 if (*lc
== 'S' && self
->decorations
& OB_FRAME_DECOR_SHADE
)
979 if (*lc
== 'I' && self
->decorations
& OB_FRAME_DECOR_ICONIFY
)
981 if (*lc
== 'M' && self
->decorations
& OB_FRAME_DECOR_MAXIMIZE
)
983 if (*lc
== 'C' && self
->decorations
& OB_FRAME_DECOR_CLOSE
)
985 if (*lc
== 'L') return FALSE
;
990 static void layout_title(ObFrame
*self
)
995 const gint bwidth
= ob_rr_theme
->button_size
+ ob_rr_theme
->paddingx
+ 1;
996 /* position of the left most button */
997 const gint left
= ob_rr_theme
->paddingx
+ 1;
998 /* position of the right most button */
999 const gint right
= self
->width
- bwidth
;
1001 /* turn them all off */
1002 self
->icon_on
= self
->desk_on
= self
->shade_on
= self
->iconify_on
=
1003 self
->max_on
= self
->close_on
= self
->label_on
= FALSE
;
1004 self
->label_width
= self
->width
- (ob_rr_theme
->paddingx
+ 1) * 2;
1005 self
->leftmost
= self
->rightmost
= OB_FRAME_CONTEXT_NONE
;
1007 /* figure out what's being show, find each element's position, and the
1010 do the ones before the label, then after the label,
1011 i will be +1 the first time through when working to the left,
1012 and -1 the second time through when working to the right */
1013 for (i
= 1; i
>= -1; i
-=2) {
1015 ObFrameContext
*firstcon
;
1019 lc
= config_title_layout
;
1020 firstcon
= &self
->leftmost
;
1023 lc
= config_title_layout
+ strlen(config_title_layout
)-1;
1024 firstcon
= &self
->rightmost
;
1027 /* stop at the end of the string (or the label, which calls break) */
1028 for (; *lc
!= '\0' && lc
>= config_title_layout
; lc
+=i
) {
1031 self
->label_on
= TRUE
;
1034 break; /* break the for loop, do other side of label */
1035 } else if (*lc
== 'N') {
1036 if (firstcon
) *firstcon
= OB_FRAME_CONTEXT_ICON
;
1037 if ((self
->icon_on
= is_button_present(self
, lc
, i
))) {
1038 /* icon is bigger than buttons */
1039 self
->label_width
-= bwidth
+ 2;
1041 x
+= i
* (bwidth
+ 2);
1043 } else if (*lc
== 'D') {
1044 if (firstcon
) *firstcon
= OB_FRAME_CONTEXT_ALLDESKTOPS
;
1045 if ((self
->desk_on
= is_button_present(self
, lc
, i
))) {
1046 self
->label_width
-= bwidth
;
1050 } else if (*lc
== 'S') {
1051 if (firstcon
) *firstcon
= OB_FRAME_CONTEXT_SHADE
;
1052 if ((self
->shade_on
= is_button_present(self
, lc
, i
))) {
1053 self
->label_width
-= bwidth
;
1057 } else if (*lc
== 'I') {
1058 if (firstcon
) *firstcon
= OB_FRAME_CONTEXT_ICONIFY
;
1059 if ((self
->iconify_on
= is_button_present(self
, lc
, i
))) {
1060 self
->label_width
-= bwidth
;
1061 self
->iconify_x
= x
;
1064 } else if (*lc
== 'M') {
1065 if (firstcon
) *firstcon
= OB_FRAME_CONTEXT_MAXIMIZE
;
1066 if ((self
->max_on
= is_button_present(self
, lc
, i
))) {
1067 self
->label_width
-= bwidth
;
1071 } else if (*lc
== 'C') {
1072 if (firstcon
) *firstcon
= OB_FRAME_CONTEXT_CLOSE
;
1073 if ((self
->close_on
= is_button_present(self
, lc
, i
))) {
1074 self
->label_width
-= bwidth
;
1079 continue; /* don't set firstcon */
1084 /* position and map the elements */
1085 if (self
->icon_on
) {
1086 XMapWindow(ob_display
, self
->icon
);
1087 XMoveWindow(ob_display
, self
->icon
, self
->icon_x
,
1088 ob_rr_theme
->paddingy
);
1090 XUnmapWindow(ob_display
, self
->icon
);
1092 if (self
->desk_on
) {
1093 XMapWindow(ob_display
, self
->desk
);
1094 XMoveWindow(ob_display
, self
->desk
, self
->desk_x
,
1095 ob_rr_theme
->paddingy
+ 1);
1097 XUnmapWindow(ob_display
, self
->desk
);
1099 if (self
->shade_on
) {
1100 XMapWindow(ob_display
, self
->shade
);
1101 XMoveWindow(ob_display
, self
->shade
, self
->shade_x
,
1102 ob_rr_theme
->paddingy
+ 1);
1104 XUnmapWindow(ob_display
, self
->shade
);
1106 if (self
->iconify_on
) {
1107 XMapWindow(ob_display
, self
->iconify
);
1108 XMoveWindow(ob_display
, self
->iconify
, self
->iconify_x
,
1109 ob_rr_theme
->paddingy
+ 1);
1111 XUnmapWindow(ob_display
, self
->iconify
);
1114 XMapWindow(ob_display
, self
->max
);
1115 XMoveWindow(ob_display
, self
->max
, self
->max_x
,
1116 ob_rr_theme
->paddingy
+ 1);
1118 XUnmapWindow(ob_display
, self
->max
);
1120 if (self
->close_on
) {
1121 XMapWindow(ob_display
, self
->close
);
1122 XMoveWindow(ob_display
, self
->close
, self
->close_x
,
1123 ob_rr_theme
->paddingy
+ 1);
1125 XUnmapWindow(ob_display
, self
->close
);
1127 if (self
->label_on
) {
1128 self
->label_width
= MAX(1, self
->label_width
); /* no lower than 1 */
1129 XMapWindow(ob_display
, self
->label
);
1130 XMoveWindow(ob_display
, self
->label
, self
->label_x
,
1131 ob_rr_theme
->paddingy
);
1133 XUnmapWindow(ob_display
, self
->label
);
1136 ObFrameContext
frame_context_from_string(const gchar
*name
)
1138 if (!g_ascii_strcasecmp("Desktop", name
))
1139 return OB_FRAME_CONTEXT_DESKTOP
;
1140 else if (!g_ascii_strcasecmp("Root", name
))
1141 return OB_FRAME_CONTEXT_ROOT
;
1142 else if (!g_ascii_strcasecmp("Client", name
))
1143 return OB_FRAME_CONTEXT_CLIENT
;
1144 else if (!g_ascii_strcasecmp("Titlebar", name
))
1145 return OB_FRAME_CONTEXT_TITLEBAR
;
1146 else if (!g_ascii_strcasecmp("Frame", name
))
1147 return OB_FRAME_CONTEXT_FRAME
;
1148 else if (!g_ascii_strcasecmp("TLCorner", name
))
1149 return OB_FRAME_CONTEXT_TLCORNER
;
1150 else if (!g_ascii_strcasecmp("TRCorner", name
))
1151 return OB_FRAME_CONTEXT_TRCORNER
;
1152 else if (!g_ascii_strcasecmp("BLCorner", name
))
1153 return OB_FRAME_CONTEXT_BLCORNER
;
1154 else if (!g_ascii_strcasecmp("BRCorner", name
))
1155 return OB_FRAME_CONTEXT_BRCORNER
;
1156 else if (!g_ascii_strcasecmp("Top", name
))
1157 return OB_FRAME_CONTEXT_TOP
;
1158 else if (!g_ascii_strcasecmp("Bottom", name
))
1159 return OB_FRAME_CONTEXT_BOTTOM
;
1160 else if (!g_ascii_strcasecmp("Left", name
))
1161 return OB_FRAME_CONTEXT_LEFT
;
1162 else if (!g_ascii_strcasecmp("Right", name
))
1163 return OB_FRAME_CONTEXT_RIGHT
;
1164 else if (!g_ascii_strcasecmp("Maximize", name
))
1165 return OB_FRAME_CONTEXT_MAXIMIZE
;
1166 else if (!g_ascii_strcasecmp("AllDesktops", name
))
1167 return OB_FRAME_CONTEXT_ALLDESKTOPS
;
1168 else if (!g_ascii_strcasecmp("Shade", name
))
1169 return OB_FRAME_CONTEXT_SHADE
;
1170 else if (!g_ascii_strcasecmp("Iconify", name
))
1171 return OB_FRAME_CONTEXT_ICONIFY
;
1172 else if (!g_ascii_strcasecmp("Icon", name
))
1173 return OB_FRAME_CONTEXT_ICON
;
1174 else if (!g_ascii_strcasecmp("Close", name
))
1175 return OB_FRAME_CONTEXT_CLOSE
;
1176 else if (!g_ascii_strcasecmp("MoveResize", name
))
1177 return OB_FRAME_CONTEXT_MOVE_RESIZE
;
1178 return OB_FRAME_CONTEXT_NONE
;
1181 ObFrameContext
frame_context(ObClient
*client
, Window win
, gint x
, gint y
)
1185 if (moveresize_in_progress
)
1186 return OB_FRAME_CONTEXT_MOVE_RESIZE
;
1188 if (win
== RootWindow(ob_display
, ob_screen
))
1189 return OB_FRAME_CONTEXT_ROOT
;
1190 if (client
== NULL
) return OB_FRAME_CONTEXT_NONE
;
1191 if (win
== client
->window
) {
1192 /* conceptually, this is the desktop, as far as users are
1194 if (client
->type
== OB_CLIENT_TYPE_DESKTOP
)
1195 return OB_FRAME_CONTEXT_DESKTOP
;
1196 return OB_FRAME_CONTEXT_CLIENT
;
1199 self
= client
->frame
;
1200 if (win
== self
->inner
|| win
== self
->plate
) {
1201 /* conceptually, this is the desktop, as far as users are
1203 if (client
->type
== OB_CLIENT_TYPE_DESKTOP
)
1204 return OB_FRAME_CONTEXT_DESKTOP
;
1205 return OB_FRAME_CONTEXT_CLIENT
;
1208 /* when the user clicks in the corners of the titlebar and the client
1209 is fully maximized, then treat it like they clicked in the
1210 button that is there */
1211 if (self
->max_horz
&& self
->max_vert
&&
1212 (win
== self
->title
|| win
== self
->titletop
||
1213 win
== self
->titleleft
|| win
== self
->titletopleft
||
1214 win
== self
->titleright
|| win
== self
->titletopright
))
1216 /* get the mouse coords in reference to the whole frame */
1220 /* these windows are down a border width from the top of the frame */
1221 if (win
== self
->title
||
1222 win
== self
->titleleft
|| win
== self
->titleright
)
1225 /* title is a border width in from the edge */
1226 if (win
== self
->title
)
1228 /* titletop is a bit to the right */
1229 else if (win
== self
->titletop
)
1230 fx
+= ob_rr_theme
->grip_width
+ self
->bwidth
;
1231 /* titletopright is way to the right edge */
1232 else if (win
== self
->titletopright
)
1233 fx
+= self
->area
.width
- (ob_rr_theme
->grip_width
+ self
->bwidth
);
1234 /* titleright is even more way to the right edge */
1235 else if (win
== self
->titleright
)
1236 fx
+= self
->area
.width
- self
->bwidth
;
1238 /* figure out if we're over the area that should be considered a
1240 if (fy
< self
->bwidth
+ ob_rr_theme
->paddingy
+ 1 +
1241 ob_rr_theme
->button_size
)
1243 if (fx
< (self
->bwidth
+ ob_rr_theme
->paddingx
+ 1 +
1244 ob_rr_theme
->button_size
))
1246 if (self
->leftmost
!= OB_FRAME_CONTEXT_NONE
)
1247 return self
->leftmost
;
1249 else if (fx
>= (self
->area
.width
-
1250 (self
->bwidth
+ ob_rr_theme
->paddingx
+ 1 +
1251 ob_rr_theme
->button_size
)))
1253 if (self
->rightmost
!= OB_FRAME_CONTEXT_NONE
)
1254 return self
->rightmost
;
1258 /* there is no resizing maximized windows so make them the titlebar
1260 return OB_FRAME_CONTEXT_TITLEBAR
;
1262 else if (self
->max_vert
&&
1263 (win
== self
->titletop
|| win
== self
->topresize
))
1264 /* can't resize vertically when max vert */
1265 return OB_FRAME_CONTEXT_TITLEBAR
;
1267 if (win
== self
->window
) return OB_FRAME_CONTEXT_FRAME
;
1268 if (win
== self
->label
) return OB_FRAME_CONTEXT_TITLEBAR
;
1269 if (win
== self
->handle
) return OB_FRAME_CONTEXT_BOTTOM
;
1270 if (win
== self
->handletop
) return OB_FRAME_CONTEXT_BOTTOM
;
1271 if (win
== self
->handlebottom
) return OB_FRAME_CONTEXT_BOTTOM
;
1272 if (win
== self
->handleleft
) return OB_FRAME_CONTEXT_BLCORNER
;
1273 if (win
== self
->lgrip
) return OB_FRAME_CONTEXT_BLCORNER
;
1274 if (win
== self
->lgripleft
) return OB_FRAME_CONTEXT_BLCORNER
;
1275 if (win
== self
->lgriptop
) return OB_FRAME_CONTEXT_BLCORNER
;
1276 if (win
== self
->lgripbottom
) return OB_FRAME_CONTEXT_BLCORNER
;
1277 if (win
== self
->handleright
) return OB_FRAME_CONTEXT_BRCORNER
;
1278 if (win
== self
->rgrip
) return OB_FRAME_CONTEXT_BRCORNER
;
1279 if (win
== self
->rgripright
) return OB_FRAME_CONTEXT_BLCORNER
;
1280 if (win
== self
->rgriptop
) return OB_FRAME_CONTEXT_BLCORNER
;
1281 if (win
== self
->rgripbottom
) return OB_FRAME_CONTEXT_BLCORNER
;
1282 if (win
== self
->title
) return OB_FRAME_CONTEXT_TITLEBAR
;
1283 if (win
== self
->titleleft
) return OB_FRAME_CONTEXT_TLCORNER
;
1284 if (win
== self
->titletopleft
) return OB_FRAME_CONTEXT_TLCORNER
;
1285 if (win
== self
->titleright
) return OB_FRAME_CONTEXT_TRCORNER
;
1286 if (win
== self
->titletopright
) return OB_FRAME_CONTEXT_TRCORNER
;
1287 if (win
== self
->titletop
) return OB_FRAME_CONTEXT_TOP
;
1288 if (win
== self
->topresize
) return OB_FRAME_CONTEXT_TOP
;
1289 if (win
== self
->tltresize
) return OB_FRAME_CONTEXT_TLCORNER
;
1290 if (win
== self
->tllresize
) return OB_FRAME_CONTEXT_TLCORNER
;
1291 if (win
== self
->trtresize
) return OB_FRAME_CONTEXT_TRCORNER
;
1292 if (win
== self
->trrresize
) return OB_FRAME_CONTEXT_TRCORNER
;
1293 if (win
== self
->left
) return OB_FRAME_CONTEXT_LEFT
;
1294 if (win
== self
->right
) return OB_FRAME_CONTEXT_RIGHT
;
1295 if (win
== self
->max
) return OB_FRAME_CONTEXT_MAXIMIZE
;
1296 if (win
== self
->iconify
) return OB_FRAME_CONTEXT_ICONIFY
;
1297 if (win
== self
->close
) return OB_FRAME_CONTEXT_CLOSE
;
1298 if (win
== self
->icon
) return OB_FRAME_CONTEXT_ICON
;
1299 if (win
== self
->desk
) return OB_FRAME_CONTEXT_ALLDESKTOPS
;
1300 if (win
== self
->shade
) return OB_FRAME_CONTEXT_SHADE
;
1302 return OB_FRAME_CONTEXT_NONE
;
1305 void frame_client_gravity(ObFrame
*self
, gint
*x
, gint
*y
, gint w
, gint h
)
1308 switch (self
->client
->gravity
) {
1310 case NorthWestGravity
:
1311 case SouthWestGravity
:
1318 /* the middle of the client will be the middle of the frame */
1319 *x
-= (self
->size
.right
- self
->size
.left
) / 2;
1322 case NorthEastGravity
:
1323 case SouthEastGravity
:
1325 /* the right side of the client will be the right side of the frame */
1326 *x
-= self
->size
.right
+ self
->size
.left
;
1331 /* the client's position won't move */
1332 *x
-= self
->size
.left
;
1337 switch (self
->client
->gravity
) {
1339 case NorthWestGravity
:
1340 case NorthEastGravity
:
1347 /* the middle of the client will be the middle of the frame */
1348 *y
-= (self
->size
.bottom
- self
->size
.top
) / 2;
1351 case SouthWestGravity
:
1352 case SouthEastGravity
:
1354 /* the bottom of the client will be the bottom of the frame */
1355 *y
-= self
->size
.bottom
+ self
->size
.top
;
1360 /* the client's position won't move */
1361 *y
-= self
->size
.top
;
1366 void frame_frame_gravity(ObFrame
*self
, gint
*x
, gint
*y
, gint w
, gint h
)
1369 switch (self
->client
->gravity
) {
1371 case NorthWestGravity
:
1373 case SouthWestGravity
:
1378 /* the middle of the client will be the middle of the frame */
1379 *x
+= (self
->size
.right
- self
->size
.left
) / 2;
1381 case NorthEastGravity
:
1383 case SouthEastGravity
:
1384 /* the right side of the client will be the right side of the frame */
1385 *x
+= self
->size
.right
+ self
->size
.left
;
1389 /* the client's position won't move */
1390 *x
+= self
->size
.left
;
1395 switch (self
->client
->gravity
) {
1397 case NorthWestGravity
:
1399 case NorthEastGravity
:
1404 /* the middle of the client will be the middle of the frame */
1405 *y
+= (self
->size
.bottom
- self
->size
.top
) / 2;
1407 case SouthWestGravity
:
1409 case SouthEastGravity
:
1410 /* the bottom of the client will be the bottom of the frame */
1411 *y
+= self
->size
.bottom
+ self
->size
.top
;
1415 /* the client's position won't move */
1416 *y
+= self
->size
.top
;
1421 static void flash_done(gpointer data
)
1423 ObFrame
*self
= data
;
1425 if (self
->focused
!= self
->flash_on
)
1426 frame_adjust_focus(self
, self
->focused
);
1429 static gboolean
flash_timeout(gpointer data
)
1431 ObFrame
*self
= data
;
1434 g_get_current_time(&now
);
1435 if (now
.tv_sec
> self
->flash_end
.tv_sec
||
1436 (now
.tv_sec
== self
->flash_end
.tv_sec
&&
1437 now
.tv_usec
>= self
->flash_end
.tv_usec
))
1438 self
->flashing
= FALSE
;
1440 if (!self
->flashing
)
1441 return FALSE
; /* we are done */
1443 self
->flash_on
= !self
->flash_on
;
1444 if (!self
->focused
) {
1445 frame_adjust_focus(self
, self
->flash_on
);
1446 self
->focused
= FALSE
;
1449 return TRUE
; /* go again */
1452 void frame_flash_start(ObFrame
*self
)
1454 self
->flash_on
= self
->focused
;
1456 if (!self
->flashing
)
1457 ob_main_loop_timeout_add(ob_main_loop
,
1458 G_USEC_PER_SEC
* 0.6,
1463 g_get_current_time(&self
->flash_end
);
1464 g_time_val_add(&self
->flash_end
, G_USEC_PER_SEC
* 5);
1466 self
->flashing
= TRUE
;
1469 void frame_flash_stop(ObFrame
*self
)
1471 self
->flashing
= FALSE
;
1474 static gulong
frame_animate_iconify_time_left(ObFrame
*self
,
1475 const GTimeVal
*now
)
1478 sec
= self
->iconify_animation_end
.tv_sec
- now
->tv_sec
;
1479 usec
= self
->iconify_animation_end
.tv_usec
- now
->tv_usec
;
1481 usec
+= G_USEC_PER_SEC
;
1484 /* no negative values */
1485 return MAX(sec
* G_USEC_PER_SEC
+ usec
, 0);
1488 static gboolean
frame_animate_iconify(gpointer p
)
1492 gint iconx
, icony
, iconw
;
1495 gboolean iconifying
;
1497 if (self
->client
->icon_geometry
.width
== 0) {
1498 /* there is no icon geometry set so just go straight down */
1499 Rect
*a
= screen_physical_area();
1500 iconx
= self
->area
.x
+ self
->area
.width
/ 2 + 32;
1501 icony
= a
->y
+ a
->width
;
1504 iconx
= self
->client
->icon_geometry
.x
;
1505 icony
= self
->client
->icon_geometry
.y
;
1506 iconw
= self
->client
->icon_geometry
.width
;
1509 iconifying
= self
->iconify_animation_going
> 0;
1511 /* how far do we have left to go ? */
1512 g_get_current_time(&now
);
1513 time
= frame_animate_iconify_time_left(self
, &now
);
1515 if (time
== 0 || iconifying
) {
1516 /* start where the frame is supposed to be */
1519 w
= self
->area
.width
;
1520 h
= self
->area
.height
;
1522 /* start at the icon */
1526 h
= self
->size
.top
; /* just the titlebar */
1533 dx
= self
->area
.x
- iconx
;
1534 dy
= self
->area
.y
- icony
;
1535 dw
= self
->area
.width
- self
->bwidth
* 2 - iconw
;
1536 /* if restoring, we move in the opposite direction */
1537 if (!iconifying
) { dx
= -dx
; dy
= -dy
; dw
= -dw
; }
1539 elapsed
= FRAME_ANIMATE_ICONIFY_TIME
- time
;
1540 x
= x
- (dx
* elapsed
) / FRAME_ANIMATE_ICONIFY_TIME
;
1541 y
= y
- (dy
* elapsed
) / FRAME_ANIMATE_ICONIFY_TIME
;
1542 w
= w
- (dw
* elapsed
) / FRAME_ANIMATE_ICONIFY_TIME
;
1543 h
= self
->size
.top
; /* just the titlebar */
1547 frame_end_iconify_animation(self
);
1549 XMoveResizeWindow(ob_display
, self
->window
, x
, y
, w
, h
);
1553 return time
> 0; /* repeat until we're out of time */
1556 void frame_end_iconify_animation(ObFrame
*self
)
1558 /* see if there is an animation going */
1559 if (self
->iconify_animation_going
== 0) return;
1562 XUnmapWindow(ob_display
, self
->window
);
1564 /* Send a ConfigureNotify when the animation is done, this fixes
1565 KDE's pager showing the window in the wrong place. */
1566 client_reconfigure(self
->client
);
1568 /* we're not animating any more ! */
1569 self
->iconify_animation_going
= 0;
1571 XMoveResizeWindow(ob_display
, self
->window
,
1572 self
->area
.x
, self
->area
.y
,
1573 self
->area
.width
, self
->area
.height
);
1577 void frame_begin_iconify_animation(ObFrame
*self
, gboolean iconifying
)
1580 gboolean new_anim
= FALSE
;
1581 gboolean set_end
= TRUE
;
1584 /* if there is no titlebar, just don't animate for now
1585 XXX it would be nice tho.. */
1586 if (!(self
->decorations
& OB_FRAME_DECOR_TITLEBAR
))
1589 /* get the current time */
1590 g_get_current_time(&now
);
1592 /* get how long until the end */
1593 time
= FRAME_ANIMATE_ICONIFY_TIME
;
1594 if (self
->iconify_animation_going
) {
1595 if (!!iconifying
!= (self
->iconify_animation_going
> 0)) {
1596 /* animation was already going on in the opposite direction */
1597 time
= time
- frame_animate_iconify_time_left(self
, &now
);
1599 /* animation was already going in the same direction */
1603 self
->iconify_animation_going
= iconifying
? 1 : -1;
1605 /* set the ending time */
1607 self
->iconify_animation_end
.tv_sec
= now
.tv_sec
;
1608 self
->iconify_animation_end
.tv_usec
= now
.tv_usec
;
1609 g_time_val_add(&self
->iconify_animation_end
, time
);
1613 ob_main_loop_timeout_remove_data(ob_main_loop
, frame_animate_iconify
,
1615 ob_main_loop_timeout_add(ob_main_loop
,
1616 FRAME_ANIMATE_ICONIFY_STEP_TIME
,
1617 frame_animate_iconify
, self
,
1618 g_direct_equal
, NULL
);
1620 /* do the first step */
1621 frame_animate_iconify(self
);
1623 /* show it during the animation even if it is not "visible" */
1625 XMapWindow(ob_display
, self
->window
);