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 /* some elements are sized based of the width, so don't let them have
358 self
->width
= MAX(self
->width
,
359 (ob_rr_theme
->grip_width
+ self
->bwidth
) * 2 + 1);
361 STRUT_SET(self
->size
,
362 self
->cbwidth_x
+ (!self
->max_horz
? self
->bwidth
: 0),
363 self
->cbwidth_y
+ self
->bwidth
,
364 self
->cbwidth_x
+ (!self
->max_horz
? self
->bwidth
: 0),
365 self
->cbwidth_y
+ self
->bwidth
);
367 if (self
->decorations
& OB_FRAME_DECOR_TITLEBAR
)
368 self
->size
.top
+= ob_rr_theme
->title_height
+ self
->rbwidth
;
369 if (self
->decorations
& OB_FRAME_DECOR_HANDLE
&&
370 ob_rr_theme
->handle_height
> 0)
372 self
->size
.bottom
+= ob_rr_theme
->handle_height
+ self
->bwidth
;
375 /* position/size and map/unmap all the windows */
381 /* height of titleleft and titleright */
382 titlesides
= (!self
->max_horz
?
383 ob_rr_theme
->grip_width
:
384 self
->size
.top
- self
->bwidth
);
386 XMoveResizeWindow(ob_display
, self
->titletop
,
387 ob_rr_theme
->grip_width
+ self
->bwidth
, 0,
388 /* width + bwidth*2 - bwidth*2 - grips*2 */
389 self
->width
- ob_rr_theme
->grip_width
* 2,
391 XMoveResizeWindow(ob_display
, self
->titletopleft
,
393 ob_rr_theme
->grip_width
+ self
->bwidth
,
395 XMoveResizeWindow(ob_display
, self
->titletopright
,
396 self
->client
->area
.width
+
397 self
->size
.left
+ self
->size
.right
-
398 ob_rr_theme
->grip_width
- self
->bwidth
,
400 ob_rr_theme
->grip_width
+ self
->bwidth
,
403 if (titlesides
> 0) {
404 XMoveResizeWindow(ob_display
, self
->titleleft
,
408 XMoveResizeWindow(ob_display
, self
->titleright
,
409 self
->client
->area
.width
+
410 self
->size
.left
+ self
->size
.right
-
416 XMapWindow(ob_display
, self
->titleleft
);
417 XMapWindow(ob_display
, self
->titleright
);
419 XUnmapWindow(ob_display
, self
->titleleft
);
420 XUnmapWindow(ob_display
, self
->titleright
);
423 XMapWindow(ob_display
, self
->titletop
);
424 XMapWindow(ob_display
, self
->titletopleft
);
425 XMapWindow(ob_display
, self
->titletopright
);
427 if (self
->decorations
& OB_FRAME_DECOR_TITLEBAR
&&
430 XMoveResizeWindow(ob_display
, self
->titlebottom
,
432 ob_rr_theme
->title_height
+ self
->bwidth
,
436 XMapWindow(ob_display
, self
->titlebottom
);
438 XUnmapWindow(ob_display
, self
->titlebottom
);
440 XUnmapWindow(ob_display
, self
->titlebottom
);
442 XUnmapWindow(ob_display
, self
->titletop
);
443 XUnmapWindow(ob_display
, self
->titletopleft
);
444 XUnmapWindow(ob_display
, self
->titletopright
);
445 XUnmapWindow(ob_display
, self
->titleleft
);
446 XUnmapWindow(ob_display
, self
->titleright
);
449 if (self
->decorations
& OB_FRAME_DECOR_TITLEBAR
) {
450 XMoveResizeWindow(ob_display
, self
->title
,
451 self
->bwidth
, self
->bwidth
,
452 self
->width
, ob_rr_theme
->title_height
);
454 XMapWindow(ob_display
, self
->title
);
456 if (self
->decorations
& OB_FRAME_DECOR_GRIPS
) {
457 XMoveResizeWindow(ob_display
, self
->topresize
,
458 ob_rr_theme
->grip_width
,
460 self
->width
- ob_rr_theme
->grip_width
*2,
461 ob_rr_theme
->paddingy
+ 1);
463 XMoveWindow(ob_display
, self
->tltresize
, 0, 0);
464 XMoveWindow(ob_display
, self
->tllresize
, 0, 0);
465 XMoveWindow(ob_display
, self
->trtresize
,
466 self
->width
- ob_rr_theme
->grip_width
, 0);
467 XMoveWindow(ob_display
, self
->trrresize
,
468 self
->width
- ob_rr_theme
->paddingx
- 1, 0);
470 XMapWindow(ob_display
, self
->topresize
);
471 XMapWindow(ob_display
, self
->tltresize
);
472 XMapWindow(ob_display
, self
->tllresize
);
473 XMapWindow(ob_display
, self
->trtresize
);
474 XMapWindow(ob_display
, self
->trrresize
);
476 XUnmapWindow(ob_display
, self
->topresize
);
477 XUnmapWindow(ob_display
, self
->tltresize
);
478 XUnmapWindow(ob_display
, self
->tllresize
);
479 XUnmapWindow(ob_display
, self
->trtresize
);
480 XUnmapWindow(ob_display
, self
->trrresize
);
483 XUnmapWindow(ob_display
, self
->title
);
486 if ((self
->decorations
& OB_FRAME_DECOR_TITLEBAR
))
487 /* layout the title bar elements */
492 XMoveResizeWindow(ob_display
, self
->handlebottom
,
493 ob_rr_theme
->grip_width
+
495 self
->size
.top
+ self
->client
->area
.height
+
496 self
->size
.bottom
- self
->bwidth
,
497 self
->width
- (ob_rr_theme
->grip_width
+
501 XMoveResizeWindow(ob_display
, self
->lgripleft
,
503 self
->size
.top
+ self
->client
->area
.height
+
506 ob_rr_theme
->grip_width
:
510 ob_rr_theme
->grip_width
:
512 XMoveResizeWindow(ob_display
, self
->rgripright
,
513 self
->size
.left
+ self
->client
->area
.width
+
514 self
->size
.right
- self
->bwidth
,
515 self
->size
.top
+ self
->client
->area
.height
+
518 ob_rr_theme
->grip_width
:
522 ob_rr_theme
->grip_width
:
525 XMoveResizeWindow(ob_display
, self
->lgripbottom
,
527 self
->size
.top
+ self
->client
->area
.height
+
528 self
->size
.bottom
- self
->bwidth
,
529 ob_rr_theme
->grip_width
+ self
->bwidth
,
531 XMoveResizeWindow(ob_display
, self
->rgripbottom
,
532 self
->size
.left
+ self
->client
->area
.width
+
533 self
->size
.right
- self
->bwidth
* 2 -
534 ob_rr_theme
->grip_width
,
535 self
->size
.top
+ self
->client
->area
.height
+
536 self
->size
.bottom
- self
->bwidth
,
537 ob_rr_theme
->grip_width
+ self
->bwidth
,
540 XMapWindow(ob_display
, self
->handlebottom
);
541 XMapWindow(ob_display
, self
->lgripleft
);
542 XMapWindow(ob_display
, self
->rgripright
);
543 XMapWindow(ob_display
, self
->lgripbottom
);
544 XMapWindow(ob_display
, self
->rgripbottom
);
546 if (self
->decorations
& OB_FRAME_DECOR_HANDLE
&&
547 ob_rr_theme
->handle_height
> 0)
549 XMoveResizeWindow(ob_display
, self
->handletop
,
550 ob_rr_theme
->grip_width
+
552 FRAME_HANDLE_Y(self
),
553 self
->width
- (ob_rr_theme
->grip_width
+
556 XMapWindow(ob_display
, self
->handletop
);
558 if (self
->decorations
& OB_FRAME_DECOR_GRIPS
) {
559 XMoveResizeWindow(ob_display
, self
->handleleft
,
560 ob_rr_theme
->grip_width
,
563 ob_rr_theme
->handle_height
);
564 XMoveResizeWindow(ob_display
, self
->handleright
,
566 ob_rr_theme
->grip_width
-
570 ob_rr_theme
->handle_height
);
572 XMoveResizeWindow(ob_display
, self
->lgriptop
,
574 FRAME_HANDLE_Y(self
),
575 ob_rr_theme
->grip_width
+
578 XMoveResizeWindow(ob_display
, self
->rgriptop
,
580 self
->client
->area
.width
+
581 self
->size
.right
- self
->bwidth
* 2 -
582 ob_rr_theme
->grip_width
,
583 FRAME_HANDLE_Y(self
),
584 ob_rr_theme
->grip_width
+
588 XMapWindow(ob_display
, self
->handleleft
);
589 XMapWindow(ob_display
, self
->handleright
);
590 XMapWindow(ob_display
, self
->lgriptop
);
591 XMapWindow(ob_display
, self
->rgriptop
);
593 XUnmapWindow(ob_display
, self
->handleleft
);
594 XUnmapWindow(ob_display
, self
->handleright
);
595 XUnmapWindow(ob_display
, self
->lgriptop
);
596 XUnmapWindow(ob_display
, self
->rgriptop
);
599 XUnmapWindow(ob_display
, self
->handleleft
);
600 XUnmapWindow(ob_display
, self
->handleright
);
601 XUnmapWindow(ob_display
, self
->lgriptop
);
602 XUnmapWindow(ob_display
, self
->rgriptop
);
604 XUnmapWindow(ob_display
, self
->handletop
);
607 XUnmapWindow(ob_display
, self
->handleleft
);
608 XUnmapWindow(ob_display
, self
->handleright
);
609 XUnmapWindow(ob_display
, self
->lgriptop
);
610 XUnmapWindow(ob_display
, self
->rgriptop
);
612 XUnmapWindow(ob_display
, self
->handletop
);
614 XUnmapWindow(ob_display
, self
->handlebottom
);
615 XUnmapWindow(ob_display
, self
->lgripleft
);
616 XUnmapWindow(ob_display
, self
->rgripright
);
617 XUnmapWindow(ob_display
, self
->lgripbottom
);
618 XUnmapWindow(ob_display
, self
->rgripbottom
);
621 if (self
->decorations
& OB_FRAME_DECOR_HANDLE
&&
622 ob_rr_theme
->handle_height
> 0)
624 XMoveResizeWindow(ob_display
, self
->handle
,
626 FRAME_HANDLE_Y(self
) + self
->bwidth
,
627 self
->width
, ob_rr_theme
->handle_height
);
628 XMapWindow(ob_display
, self
->handle
);
630 if (self
->decorations
& OB_FRAME_DECOR_GRIPS
) {
631 XMoveResizeWindow(ob_display
, self
->lgrip
,
633 ob_rr_theme
->grip_width
,
634 ob_rr_theme
->handle_height
);
635 XMoveResizeWindow(ob_display
, self
->rgrip
,
636 self
->width
- ob_rr_theme
->grip_width
,
638 ob_rr_theme
->grip_width
,
639 ob_rr_theme
->handle_height
);
641 XMapWindow(ob_display
, self
->lgrip
);
642 XMapWindow(ob_display
, self
->rgrip
);
644 XUnmapWindow(ob_display
, self
->lgrip
);
645 XUnmapWindow(ob_display
, self
->rgrip
);
648 XUnmapWindow(ob_display
, self
->lgrip
);
649 XUnmapWindow(ob_display
, self
->rgrip
);
651 XUnmapWindow(ob_display
, self
->handle
);
654 if (self
->bwidth
&& !self
->max_horz
) {
655 XMoveResizeWindow(ob_display
, self
->left
,
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
->left
);
665 XUnmapWindow(ob_display
, self
->left
);
667 if (self
->bwidth
&& !self
->max_horz
) {
668 XMoveResizeWindow(ob_display
, self
->right
,
669 self
->client
->area
.width
+
670 self
->cbwidth_x
* 2 + self
->bwidth
,
671 self
->bwidth
+ ob_rr_theme
->grip_width
,
673 self
->client
->area
.height
+
674 self
->size
.top
+ self
->size
.bottom
-
675 ob_rr_theme
->grip_width
* 2);
677 XMapWindow(ob_display
, self
->right
);
679 XUnmapWindow(ob_display
, self
->right
);
681 /* move and resize the inner border window which contains the plate
683 XMoveResizeWindow(ob_display
, self
->inner
,
685 self
->size
.top
- self
->cbwidth_y
,
686 self
->client
->area
.width
+
687 self
->cbwidth_x
* 2 +
688 (!self
->max_horz
? self
->bwidth
* 2 : 0),
689 self
->client
->area
.height
+
690 self
->cbwidth_y
* 2);
693 XMoveWindow(ob_display
, self
->plate
,
694 (!self
->max_horz
? self
->bwidth
: 0) + self
->cbwidth_x
,
697 /* when the client has StaticGravity, it likes to move around. */
698 XMoveWindow(ob_display
, self
->client
->window
,
699 -self
->client
->border_width
,
700 -self
->client
->border_width
);
704 /* shading can change without being moved or resized */
705 RECT_SET_SIZE(self
->area
,
706 self
->client
->area
.width
+
707 self
->size
.left
+ self
->size
.right
,
708 (self
->client
->shaded
?
709 ob_rr_theme
->title_height
+ self
->bwidth
* 2:
710 self
->client
->area
.height
+
711 self
->size
.top
+ self
->size
.bottom
));
713 if ((moved
|| resized
) && !fake
) {
714 /* find the new coordinates, done after setting the frame.size, for
715 frame_client_gravity. */
716 self
->area
.x
= self
->client
->area
.x
;
717 self
->area
.y
= self
->client
->area
.y
;
718 frame_client_gravity(self
, &self
->area
.x
, &self
->area
.y
,
719 self
->client
->area
.width
,
720 self
->client
->area
.height
);
724 if (!frame_iconify_animating(self
))
725 /* move and resize the top level frame.
726 shading can change without being moved or resized.
728 but don't do this during an iconify animation. it will be
729 reflected afterwards.
731 XMoveResizeWindow(ob_display
, self
->window
,
738 framerender_frame(self
);
739 frame_adjust_shape(self
);
742 if (!STRUT_EQUAL(self
->size
, oldsize
)) {
744 vals
[0] = self
->size
.left
;
745 vals
[1] = self
->size
.right
;
746 vals
[2] = self
->size
.top
;
747 vals
[3] = self
->size
.bottom
;
748 PROP_SETA32(self
->client
->window
, net_frame_extents
,
750 PROP_SETA32(self
->client
->window
, kde_net_wm_frame_strut
,
754 /* if this occurs while we are focus cycling, the indicator needs to
756 if (focus_cycle_target
== self
->client
)
757 focus_cycle_draw_indicator(self
->client
);
759 if (resized
&& (self
->decorations
& OB_FRAME_DECOR_TITLEBAR
))
760 XResizeWindow(ob_display
, self
->label
, self
->label_width
,
761 ob_rr_theme
->label_height
);
765 static void frame_adjust_cursors(ObFrame
*self
)
767 if ((self
->functions
& OB_CLIENT_FUNC_RESIZE
) !=
768 (self
->client
->functions
& OB_CLIENT_FUNC_RESIZE
) ||
769 self
->max_horz
!= self
->client
->max_horz
||
770 self
->max_vert
!= self
->client
->max_vert
)
772 gboolean r
= (self
->client
->functions
& OB_CLIENT_FUNC_RESIZE
) &&
773 !(self
->client
->max_horz
&& self
->client
->max_vert
);
774 gboolean topbot
= !self
->client
->max_vert
;
775 XSetWindowAttributes a
;
777 /* these ones turn off when max vert */
778 a
.cursor
= ob_cursor(r
&& topbot
? OB_CURSOR_NORTH
: OB_CURSOR_NONE
);
779 XChangeWindowAttributes(ob_display
, self
->topresize
, CWCursor
, &a
);
780 XChangeWindowAttributes(ob_display
, self
->titletop
, CWCursor
, &a
);
781 a
.cursor
= ob_cursor(r
&& topbot
? OB_CURSOR_SOUTH
: OB_CURSOR_NONE
);
782 XChangeWindowAttributes(ob_display
, self
->handle
, CWCursor
, &a
);
783 XChangeWindowAttributes(ob_display
, self
->handletop
, CWCursor
, &a
);
784 XChangeWindowAttributes(ob_display
, self
->handlebottom
, CWCursor
, &a
);
786 /* these ones don't */
787 a
.cursor
= ob_cursor(r
? OB_CURSOR_NORTHWEST
: OB_CURSOR_NONE
);
788 XChangeWindowAttributes(ob_display
, self
->tltresize
, CWCursor
, &a
);
789 XChangeWindowAttributes(ob_display
, self
->tllresize
, CWCursor
, &a
);
790 XChangeWindowAttributes(ob_display
, self
->titletopleft
, CWCursor
, &a
);
791 XChangeWindowAttributes(ob_display
, self
->titleleft
, CWCursor
, &a
);
792 a
.cursor
= ob_cursor(r
? OB_CURSOR_NORTHEAST
: OB_CURSOR_NONE
);
793 XChangeWindowAttributes(ob_display
, self
->trtresize
, CWCursor
, &a
);
794 XChangeWindowAttributes(ob_display
, self
->trrresize
, CWCursor
, &a
);
795 XChangeWindowAttributes(ob_display
, self
->titletopright
, CWCursor
, &a
);
796 XChangeWindowAttributes(ob_display
, self
->titleright
, CWCursor
, &a
);
797 a
.cursor
= ob_cursor(r
? OB_CURSOR_WEST
: OB_CURSOR_NONE
);
798 XChangeWindowAttributes(ob_display
, self
->left
, CWCursor
, &a
);
799 a
.cursor
= ob_cursor(r
? OB_CURSOR_EAST
: OB_CURSOR_NONE
);
800 XChangeWindowAttributes(ob_display
, self
->right
, CWCursor
, &a
);
801 a
.cursor
= ob_cursor(r
? OB_CURSOR_SOUTHWEST
: OB_CURSOR_NONE
);
802 XChangeWindowAttributes(ob_display
, self
->lgrip
, CWCursor
, &a
);
803 XChangeWindowAttributes(ob_display
, self
->handleleft
, CWCursor
, &a
);
804 XChangeWindowAttributes(ob_display
, self
->lgripleft
, CWCursor
, &a
);
805 XChangeWindowAttributes(ob_display
, self
->lgriptop
, CWCursor
, &a
);
806 XChangeWindowAttributes(ob_display
, self
->lgripbottom
, CWCursor
, &a
);
807 a
.cursor
= ob_cursor(r
? OB_CURSOR_SOUTHEAST
: OB_CURSOR_NONE
);
808 XChangeWindowAttributes(ob_display
, self
->rgrip
, CWCursor
, &a
);
809 XChangeWindowAttributes(ob_display
, self
->handleright
, CWCursor
, &a
);
810 XChangeWindowAttributes(ob_display
, self
->rgripright
, CWCursor
, &a
);
811 XChangeWindowAttributes(ob_display
, self
->rgriptop
, CWCursor
, &a
);
812 XChangeWindowAttributes(ob_display
, self
->rgripbottom
, CWCursor
, &a
);
816 void frame_adjust_client_area(ObFrame
*self
)
818 /* resize the plate */
819 XResizeWindow(ob_display
, self
->plate
,
820 self
->client
->area
.width
, self
->client
->area
.height
);
823 void frame_adjust_state(ObFrame
*self
)
825 framerender_frame(self
);
828 void frame_adjust_focus(ObFrame
*self
, gboolean hilite
)
830 self
->focused
= hilite
;
831 framerender_frame(self
);
835 void frame_adjust_title(ObFrame
*self
)
837 framerender_frame(self
);
840 void frame_adjust_icon(ObFrame
*self
)
842 framerender_frame(self
);
845 void frame_grab_client(ObFrame
*self
)
847 /* DO NOT map the client window here. we used to do that, but it is bogus.
848 we need to set up the client's dimensions and everything before we
849 send a mapnotify or we create race conditions.
852 /* reparent the client to the frame */
853 XReparentWindow(ob_display
, self
->client
->window
, self
->plate
,
854 -self
->client
->border_width
, -self
->client
->border_width
);
857 When reparenting the client window, it is usually not mapped yet, since
858 this occurs from a MapRequest. However, in the case where Openbox is
859 starting up, the window is already mapped, so we'll see unmap events for
860 it. There are 2 unmap events generated that we see, one with the 'event'
861 member set the root window, and one set to the client, but both get
862 handled and need to be ignored.
864 if (ob_state() == OB_STATE_STARTING
)
865 self
->client
->ignore_unmaps
+= 2;
867 /* select the event mask on the client's parent (to receive config/map
868 req's) the ButtonPress is to catch clicks on the client border */
869 XSelectInput(ob_display
, self
->plate
, PLATE_EVENTMASK
);
871 /* set all the windows for the frame in the window_map */
872 g_hash_table_insert(window_map
, &self
->window
, self
->client
);
873 g_hash_table_insert(window_map
, &self
->plate
, self
->client
);
874 g_hash_table_insert(window_map
, &self
->inner
, self
->client
);
875 g_hash_table_insert(window_map
, &self
->title
, self
->client
);
876 g_hash_table_insert(window_map
, &self
->label
, self
->client
);
877 g_hash_table_insert(window_map
, &self
->max
, self
->client
);
878 g_hash_table_insert(window_map
, &self
->close
, self
->client
);
879 g_hash_table_insert(window_map
, &self
->desk
, self
->client
);
880 g_hash_table_insert(window_map
, &self
->shade
, self
->client
);
881 g_hash_table_insert(window_map
, &self
->icon
, self
->client
);
882 g_hash_table_insert(window_map
, &self
->iconify
, self
->client
);
883 g_hash_table_insert(window_map
, &self
->handle
, self
->client
);
884 g_hash_table_insert(window_map
, &self
->lgrip
, self
->client
);
885 g_hash_table_insert(window_map
, &self
->rgrip
, self
->client
);
886 g_hash_table_insert(window_map
, &self
->topresize
, self
->client
);
887 g_hash_table_insert(window_map
, &self
->tltresize
, self
->client
);
888 g_hash_table_insert(window_map
, &self
->tllresize
, self
->client
);
889 g_hash_table_insert(window_map
, &self
->trtresize
, self
->client
);
890 g_hash_table_insert(window_map
, &self
->trrresize
, self
->client
);
891 g_hash_table_insert(window_map
, &self
->left
, self
->client
);
892 g_hash_table_insert(window_map
, &self
->right
, self
->client
);
893 g_hash_table_insert(window_map
, &self
->titleleft
, self
->client
);
894 g_hash_table_insert(window_map
, &self
->titletop
, self
->client
);
895 g_hash_table_insert(window_map
, &self
->titletopleft
, self
->client
);
896 g_hash_table_insert(window_map
, &self
->titletopright
, self
->client
);
897 g_hash_table_insert(window_map
, &self
->titleright
, self
->client
);
898 g_hash_table_insert(window_map
, &self
->titlebottom
, self
->client
);
899 g_hash_table_insert(window_map
, &self
->handleleft
, self
->client
);
900 g_hash_table_insert(window_map
, &self
->handletop
, self
->client
);
901 g_hash_table_insert(window_map
, &self
->handleright
, self
->client
);
902 g_hash_table_insert(window_map
, &self
->handlebottom
, self
->client
);
903 g_hash_table_insert(window_map
, &self
->lgripleft
, self
->client
);
904 g_hash_table_insert(window_map
, &self
->lgriptop
, self
->client
);
905 g_hash_table_insert(window_map
, &self
->lgripbottom
, self
->client
);
906 g_hash_table_insert(window_map
, &self
->rgripright
, self
->client
);
907 g_hash_table_insert(window_map
, &self
->rgriptop
, self
->client
);
908 g_hash_table_insert(window_map
, &self
->rgripbottom
, self
->client
);
911 void frame_release_client(ObFrame
*self
)
914 gboolean reparent
= TRUE
;
916 /* if there was any animation going on, kill it */
917 ob_main_loop_timeout_remove_data(ob_main_loop
, frame_animate_iconify
,
920 /* check if the app has already reparented its window away */
921 while (XCheckTypedWindowEvent(ob_display
, self
->client
->window
,
922 ReparentNotify
, &ev
))
924 /* This check makes sure we don't catch our own reparent action to
925 our frame window. This doesn't count as the app reparenting itself
928 Reparent events that are generated by us are just discarded here.
929 They are of no consequence to us anyhow.
931 if (ev
.xreparent
.parent
!= self
->plate
) {
933 XPutBackEvent(ob_display
, &ev
);
939 /* according to the ICCCM - if the client doesn't reparent itself,
940 then we will reparent the window to root for them */
941 XReparentWindow(ob_display
, self
->client
->window
,
942 RootWindow(ob_display
, ob_screen
),
943 self
->client
->area
.x
,
944 self
->client
->area
.y
);
947 /* remove all the windows for the frame from the window_map */
948 g_hash_table_remove(window_map
, &self
->window
);
949 g_hash_table_remove(window_map
, &self
->plate
);
950 g_hash_table_remove(window_map
, &self
->inner
);
951 g_hash_table_remove(window_map
, &self
->title
);
952 g_hash_table_remove(window_map
, &self
->label
);
953 g_hash_table_remove(window_map
, &self
->max
);
954 g_hash_table_remove(window_map
, &self
->close
);
955 g_hash_table_remove(window_map
, &self
->desk
);
956 g_hash_table_remove(window_map
, &self
->shade
);
957 g_hash_table_remove(window_map
, &self
->icon
);
958 g_hash_table_remove(window_map
, &self
->iconify
);
959 g_hash_table_remove(window_map
, &self
->handle
);
960 g_hash_table_remove(window_map
, &self
->lgrip
);
961 g_hash_table_remove(window_map
, &self
->rgrip
);
962 g_hash_table_remove(window_map
, &self
->topresize
);
963 g_hash_table_remove(window_map
, &self
->tltresize
);
964 g_hash_table_remove(window_map
, &self
->tllresize
);
965 g_hash_table_remove(window_map
, &self
->trtresize
);
966 g_hash_table_remove(window_map
, &self
->trrresize
);
967 g_hash_table_remove(window_map
, &self
->left
);
968 g_hash_table_remove(window_map
, &self
->right
);
969 g_hash_table_remove(window_map
, &self
->titleleft
);
970 g_hash_table_remove(window_map
, &self
->titletop
);
971 g_hash_table_remove(window_map
, &self
->titletopleft
);
972 g_hash_table_remove(window_map
, &self
->titletopright
);
973 g_hash_table_remove(window_map
, &self
->titleright
);
974 g_hash_table_remove(window_map
, &self
->titlebottom
);
975 g_hash_table_remove(window_map
, &self
->handleleft
);
976 g_hash_table_remove(window_map
, &self
->handletop
);
977 g_hash_table_remove(window_map
, &self
->handleright
);
978 g_hash_table_remove(window_map
, &self
->handlebottom
);
979 g_hash_table_remove(window_map
, &self
->lgripleft
);
980 g_hash_table_remove(window_map
, &self
->lgriptop
);
981 g_hash_table_remove(window_map
, &self
->lgripbottom
);
982 g_hash_table_remove(window_map
, &self
->rgripright
);
983 g_hash_table_remove(window_map
, &self
->rgriptop
);
984 g_hash_table_remove(window_map
, &self
->rgripbottom
);
986 ob_main_loop_timeout_remove_data(ob_main_loop
, flash_timeout
, self
, TRUE
);
989 /* is there anything present between us and the label? */
990 static gboolean
is_button_present(ObFrame
*self
, const gchar
*lc
, gint dir
) {
991 for (; *lc
!= '\0' && lc
>= config_title_layout
; lc
+= dir
) {
992 if (*lc
== ' ') continue; /* it was invalid */
993 if (*lc
== 'N' && self
->decorations
& OB_FRAME_DECOR_ICON
)
995 if (*lc
== 'D' && self
->decorations
& OB_FRAME_DECOR_ALLDESKTOPS
)
997 if (*lc
== 'S' && self
->decorations
& OB_FRAME_DECOR_SHADE
)
999 if (*lc
== 'I' && self
->decorations
& OB_FRAME_DECOR_ICONIFY
)
1001 if (*lc
== 'M' && self
->decorations
& OB_FRAME_DECOR_MAXIMIZE
)
1003 if (*lc
== 'C' && self
->decorations
& OB_FRAME_DECOR_CLOSE
)
1005 if (*lc
== 'L') return FALSE
;
1010 static void layout_title(ObFrame
*self
)
1015 const gint bwidth
= ob_rr_theme
->button_size
+ ob_rr_theme
->paddingx
+ 1;
1016 /* position of the left most button */
1017 const gint left
= ob_rr_theme
->paddingx
+ 1;
1018 /* position of the right most button */
1019 const gint right
= self
->width
- bwidth
;
1021 /* turn them all off */
1022 self
->icon_on
= self
->desk_on
= self
->shade_on
= self
->iconify_on
=
1023 self
->max_on
= self
->close_on
= self
->label_on
= FALSE
;
1024 self
->label_width
= self
->width
- (ob_rr_theme
->paddingx
+ 1) * 2;
1025 self
->leftmost
= self
->rightmost
= OB_FRAME_CONTEXT_NONE
;
1027 /* figure out what's being show, find each element's position, and the
1030 do the ones before the label, then after the label,
1031 i will be +1 the first time through when working to the left,
1032 and -1 the second time through when working to the right */
1033 for (i
= 1; i
>= -1; i
-=2) {
1035 ObFrameContext
*firstcon
;
1039 lc
= config_title_layout
;
1040 firstcon
= &self
->leftmost
;
1043 lc
= config_title_layout
+ strlen(config_title_layout
)-1;
1044 firstcon
= &self
->rightmost
;
1047 /* stop at the end of the string (or the label, which calls break) */
1048 for (; *lc
!= '\0' && lc
>= config_title_layout
; lc
+=i
) {
1051 self
->label_on
= TRUE
;
1054 break; /* break the for loop, do other side of label */
1055 } else if (*lc
== 'N') {
1056 if (firstcon
) *firstcon
= OB_FRAME_CONTEXT_ICON
;
1057 if ((self
->icon_on
= is_button_present(self
, lc
, i
))) {
1058 /* icon is bigger than buttons */
1059 self
->label_width
-= bwidth
+ 2;
1061 x
+= i
* (bwidth
+ 2);
1063 } else if (*lc
== 'D') {
1064 if (firstcon
) *firstcon
= OB_FRAME_CONTEXT_ALLDESKTOPS
;
1065 if ((self
->desk_on
= is_button_present(self
, lc
, i
))) {
1066 self
->label_width
-= bwidth
;
1070 } else if (*lc
== 'S') {
1071 if (firstcon
) *firstcon
= OB_FRAME_CONTEXT_SHADE
;
1072 if ((self
->shade_on
= is_button_present(self
, lc
, i
))) {
1073 self
->label_width
-= bwidth
;
1077 } else if (*lc
== 'I') {
1078 if (firstcon
) *firstcon
= OB_FRAME_CONTEXT_ICONIFY
;
1079 if ((self
->iconify_on
= is_button_present(self
, lc
, i
))) {
1080 self
->label_width
-= bwidth
;
1081 self
->iconify_x
= x
;
1084 } else if (*lc
== 'M') {
1085 if (firstcon
) *firstcon
= OB_FRAME_CONTEXT_MAXIMIZE
;
1086 if ((self
->max_on
= is_button_present(self
, lc
, i
))) {
1087 self
->label_width
-= bwidth
;
1091 } else if (*lc
== 'C') {
1092 if (firstcon
) *firstcon
= OB_FRAME_CONTEXT_CLOSE
;
1093 if ((self
->close_on
= is_button_present(self
, lc
, i
))) {
1094 self
->label_width
-= bwidth
;
1099 continue; /* don't set firstcon */
1104 /* position and map the elements */
1105 if (self
->icon_on
) {
1106 XMapWindow(ob_display
, self
->icon
);
1107 XMoveWindow(ob_display
, self
->icon
, self
->icon_x
,
1108 ob_rr_theme
->paddingy
);
1110 XUnmapWindow(ob_display
, self
->icon
);
1112 if (self
->desk_on
) {
1113 XMapWindow(ob_display
, self
->desk
);
1114 XMoveWindow(ob_display
, self
->desk
, self
->desk_x
,
1115 ob_rr_theme
->paddingy
+ 1);
1117 XUnmapWindow(ob_display
, self
->desk
);
1119 if (self
->shade_on
) {
1120 XMapWindow(ob_display
, self
->shade
);
1121 XMoveWindow(ob_display
, self
->shade
, self
->shade_x
,
1122 ob_rr_theme
->paddingy
+ 1);
1124 XUnmapWindow(ob_display
, self
->shade
);
1126 if (self
->iconify_on
) {
1127 XMapWindow(ob_display
, self
->iconify
);
1128 XMoveWindow(ob_display
, self
->iconify
, self
->iconify_x
,
1129 ob_rr_theme
->paddingy
+ 1);
1131 XUnmapWindow(ob_display
, self
->iconify
);
1134 XMapWindow(ob_display
, self
->max
);
1135 XMoveWindow(ob_display
, self
->max
, self
->max_x
,
1136 ob_rr_theme
->paddingy
+ 1);
1138 XUnmapWindow(ob_display
, self
->max
);
1140 if (self
->close_on
) {
1141 XMapWindow(ob_display
, self
->close
);
1142 XMoveWindow(ob_display
, self
->close
, self
->close_x
,
1143 ob_rr_theme
->paddingy
+ 1);
1145 XUnmapWindow(ob_display
, self
->close
);
1147 if (self
->label_on
) {
1148 self
->label_width
= MAX(1, self
->label_width
); /* no lower than 1 */
1149 XMapWindow(ob_display
, self
->label
);
1150 XMoveWindow(ob_display
, self
->label
, self
->label_x
,
1151 ob_rr_theme
->paddingy
);
1153 XUnmapWindow(ob_display
, self
->label
);
1156 ObFrameContext
frame_context_from_string(const gchar
*name
)
1158 if (!g_ascii_strcasecmp("Desktop", name
))
1159 return OB_FRAME_CONTEXT_DESKTOP
;
1160 else if (!g_ascii_strcasecmp("Root", name
))
1161 return OB_FRAME_CONTEXT_ROOT
;
1162 else if (!g_ascii_strcasecmp("Client", name
))
1163 return OB_FRAME_CONTEXT_CLIENT
;
1164 else if (!g_ascii_strcasecmp("Titlebar", name
))
1165 return OB_FRAME_CONTEXT_TITLEBAR
;
1166 else if (!g_ascii_strcasecmp("Frame", name
))
1167 return OB_FRAME_CONTEXT_FRAME
;
1168 else if (!g_ascii_strcasecmp("TLCorner", name
))
1169 return OB_FRAME_CONTEXT_TLCORNER
;
1170 else if (!g_ascii_strcasecmp("TRCorner", name
))
1171 return OB_FRAME_CONTEXT_TRCORNER
;
1172 else if (!g_ascii_strcasecmp("BLCorner", name
))
1173 return OB_FRAME_CONTEXT_BLCORNER
;
1174 else if (!g_ascii_strcasecmp("BRCorner", name
))
1175 return OB_FRAME_CONTEXT_BRCORNER
;
1176 else if (!g_ascii_strcasecmp("Top", name
))
1177 return OB_FRAME_CONTEXT_TOP
;
1178 else if (!g_ascii_strcasecmp("Bottom", name
))
1179 return OB_FRAME_CONTEXT_BOTTOM
;
1180 else if (!g_ascii_strcasecmp("Left", name
))
1181 return OB_FRAME_CONTEXT_LEFT
;
1182 else if (!g_ascii_strcasecmp("Right", name
))
1183 return OB_FRAME_CONTEXT_RIGHT
;
1184 else if (!g_ascii_strcasecmp("Maximize", name
))
1185 return OB_FRAME_CONTEXT_MAXIMIZE
;
1186 else if (!g_ascii_strcasecmp("AllDesktops", name
))
1187 return OB_FRAME_CONTEXT_ALLDESKTOPS
;
1188 else if (!g_ascii_strcasecmp("Shade", name
))
1189 return OB_FRAME_CONTEXT_SHADE
;
1190 else if (!g_ascii_strcasecmp("Iconify", name
))
1191 return OB_FRAME_CONTEXT_ICONIFY
;
1192 else if (!g_ascii_strcasecmp("Icon", name
))
1193 return OB_FRAME_CONTEXT_ICON
;
1194 else if (!g_ascii_strcasecmp("Close", name
))
1195 return OB_FRAME_CONTEXT_CLOSE
;
1196 else if (!g_ascii_strcasecmp("MoveResize", name
))
1197 return OB_FRAME_CONTEXT_MOVE_RESIZE
;
1198 return OB_FRAME_CONTEXT_NONE
;
1201 ObFrameContext
frame_context(ObClient
*client
, Window win
, gint x
, gint y
)
1205 if (moveresize_in_progress
)
1206 return OB_FRAME_CONTEXT_MOVE_RESIZE
;
1208 if (win
== RootWindow(ob_display
, ob_screen
))
1209 return OB_FRAME_CONTEXT_ROOT
;
1210 if (client
== NULL
) return OB_FRAME_CONTEXT_NONE
;
1211 if (win
== client
->window
) {
1212 /* conceptually, this is the desktop, as far as users are
1214 if (client
->type
== OB_CLIENT_TYPE_DESKTOP
)
1215 return OB_FRAME_CONTEXT_DESKTOP
;
1216 return OB_FRAME_CONTEXT_CLIENT
;
1219 self
= client
->frame
;
1220 if (win
== self
->inner
|| win
== self
->plate
) {
1221 /* conceptually, this is the desktop, as far as users are
1223 if (client
->type
== OB_CLIENT_TYPE_DESKTOP
)
1224 return OB_FRAME_CONTEXT_DESKTOP
;
1225 return OB_FRAME_CONTEXT_CLIENT
;
1228 /* when the user clicks in the corners of the titlebar and the client
1229 is fully maximized, then treat it like they clicked in the
1230 button that is there */
1231 if (self
->max_horz
&& self
->max_vert
&&
1232 (win
== self
->title
|| win
== self
->titletop
||
1233 win
== self
->titleleft
|| win
== self
->titletopleft
||
1234 win
== self
->titleright
|| win
== self
->titletopright
))
1236 /* get the mouse coords in reference to the whole frame */
1240 /* these windows are down a border width from the top of the frame */
1241 if (win
== self
->title
||
1242 win
== self
->titleleft
|| win
== self
->titleright
)
1245 /* title is a border width in from the edge */
1246 if (win
== self
->title
)
1248 /* titletop is a bit to the right */
1249 else if (win
== self
->titletop
)
1250 fx
+= ob_rr_theme
->grip_width
+ self
->bwidth
;
1251 /* titletopright is way to the right edge */
1252 else if (win
== self
->titletopright
)
1253 fx
+= self
->area
.width
- (ob_rr_theme
->grip_width
+ self
->bwidth
);
1254 /* titleright is even more way to the right edge */
1255 else if (win
== self
->titleright
)
1256 fx
+= self
->area
.width
- self
->bwidth
;
1258 /* figure out if we're over the area that should be considered a
1260 if (fy
< self
->bwidth
+ ob_rr_theme
->paddingy
+ 1 +
1261 ob_rr_theme
->button_size
)
1263 if (fx
< (self
->bwidth
+ ob_rr_theme
->paddingx
+ 1 +
1264 ob_rr_theme
->button_size
))
1266 if (self
->leftmost
!= OB_FRAME_CONTEXT_NONE
)
1267 return self
->leftmost
;
1269 else if (fx
>= (self
->area
.width
-
1270 (self
->bwidth
+ ob_rr_theme
->paddingx
+ 1 +
1271 ob_rr_theme
->button_size
)))
1273 if (self
->rightmost
!= OB_FRAME_CONTEXT_NONE
)
1274 return self
->rightmost
;
1278 /* there is no resizing maximized windows so make them the titlebar
1280 return OB_FRAME_CONTEXT_TITLEBAR
;
1282 else if (self
->max_vert
&&
1283 (win
== self
->titletop
|| win
== self
->topresize
))
1284 /* can't resize vertically when max vert */
1285 return OB_FRAME_CONTEXT_TITLEBAR
;
1287 if (win
== self
->window
) return OB_FRAME_CONTEXT_FRAME
;
1288 if (win
== self
->label
) return OB_FRAME_CONTEXT_TITLEBAR
;
1289 if (win
== self
->handle
) return OB_FRAME_CONTEXT_BOTTOM
;
1290 if (win
== self
->handletop
) return OB_FRAME_CONTEXT_BOTTOM
;
1291 if (win
== self
->handlebottom
) return OB_FRAME_CONTEXT_BOTTOM
;
1292 if (win
== self
->handleleft
) return OB_FRAME_CONTEXT_BLCORNER
;
1293 if (win
== self
->lgrip
) return OB_FRAME_CONTEXT_BLCORNER
;
1294 if (win
== self
->lgripleft
) return OB_FRAME_CONTEXT_BLCORNER
;
1295 if (win
== self
->lgriptop
) return OB_FRAME_CONTEXT_BLCORNER
;
1296 if (win
== self
->lgripbottom
) return OB_FRAME_CONTEXT_BLCORNER
;
1297 if (win
== self
->handleright
) return OB_FRAME_CONTEXT_BRCORNER
;
1298 if (win
== self
->rgrip
) return OB_FRAME_CONTEXT_BRCORNER
;
1299 if (win
== self
->rgripright
) return OB_FRAME_CONTEXT_BLCORNER
;
1300 if (win
== self
->rgriptop
) return OB_FRAME_CONTEXT_BLCORNER
;
1301 if (win
== self
->rgripbottom
) return OB_FRAME_CONTEXT_BLCORNER
;
1302 if (win
== self
->title
) return OB_FRAME_CONTEXT_TITLEBAR
;
1303 if (win
== self
->titleleft
) return OB_FRAME_CONTEXT_TLCORNER
;
1304 if (win
== self
->titletopleft
) return OB_FRAME_CONTEXT_TLCORNER
;
1305 if (win
== self
->titleright
) return OB_FRAME_CONTEXT_TRCORNER
;
1306 if (win
== self
->titletopright
) return OB_FRAME_CONTEXT_TRCORNER
;
1307 if (win
== self
->titletop
) return OB_FRAME_CONTEXT_TOP
;
1308 if (win
== self
->topresize
) return OB_FRAME_CONTEXT_TOP
;
1309 if (win
== self
->tltresize
) return OB_FRAME_CONTEXT_TLCORNER
;
1310 if (win
== self
->tllresize
) return OB_FRAME_CONTEXT_TLCORNER
;
1311 if (win
== self
->trtresize
) return OB_FRAME_CONTEXT_TRCORNER
;
1312 if (win
== self
->trrresize
) return OB_FRAME_CONTEXT_TRCORNER
;
1313 if (win
== self
->left
) return OB_FRAME_CONTEXT_LEFT
;
1314 if (win
== self
->right
) return OB_FRAME_CONTEXT_RIGHT
;
1315 if (win
== self
->max
) return OB_FRAME_CONTEXT_MAXIMIZE
;
1316 if (win
== self
->iconify
) return OB_FRAME_CONTEXT_ICONIFY
;
1317 if (win
== self
->close
) return OB_FRAME_CONTEXT_CLOSE
;
1318 if (win
== self
->icon
) return OB_FRAME_CONTEXT_ICON
;
1319 if (win
== self
->desk
) return OB_FRAME_CONTEXT_ALLDESKTOPS
;
1320 if (win
== self
->shade
) return OB_FRAME_CONTEXT_SHADE
;
1322 return OB_FRAME_CONTEXT_NONE
;
1325 void frame_client_gravity(ObFrame
*self
, gint
*x
, gint
*y
, gint w
, gint h
)
1328 switch (self
->client
->gravity
) {
1330 case NorthWestGravity
:
1331 case SouthWestGravity
:
1338 /* the middle of the client will be the middle of the frame */
1339 *x
-= (self
->size
.right
- self
->size
.left
) / 2;
1342 case NorthEastGravity
:
1343 case SouthEastGravity
:
1345 /* the right side of the client will be the right side of the frame */
1346 *x
-= self
->size
.right
+ self
->size
.left
-
1347 self
->client
->border_width
* 2;
1352 /* the client's position won't move */
1353 *x
-= self
->size
.left
- self
->client
->border_width
;
1358 switch (self
->client
->gravity
) {
1360 case NorthWestGravity
:
1361 case NorthEastGravity
:
1368 /* the middle of the client will be the middle of the frame */
1369 *y
-= (self
->size
.bottom
- self
->size
.top
) / 2;
1372 case SouthWestGravity
:
1373 case SouthEastGravity
:
1375 /* the bottom of the client will be the bottom of the frame */
1376 *y
-= self
->size
.bottom
+ self
->size
.top
-
1377 self
->client
->border_width
* 2;
1382 /* the client's position won't move */
1383 *y
-= self
->size
.top
- self
->client
->border_width
;
1388 void frame_frame_gravity(ObFrame
*self
, gint
*x
, gint
*y
, gint w
, gint h
)
1391 switch (self
->client
->gravity
) {
1393 case NorthWestGravity
:
1395 case SouthWestGravity
:
1400 /* the middle of the client will be the middle of the frame */
1401 *x
+= (self
->size
.right
- self
->size
.left
) / 2;
1403 case NorthEastGravity
:
1405 case SouthEastGravity
:
1406 /* the right side of the client will be the right side of the frame */
1407 *x
+= self
->size
.right
+ self
->size
.left
-
1408 self
->client
->border_width
* 2;
1412 /* the client's position won't move */
1413 *x
+= self
->size
.left
- self
->client
->border_width
;
1418 switch (self
->client
->gravity
) {
1420 case NorthWestGravity
:
1422 case NorthEastGravity
:
1427 /* the middle of the client will be the middle of the frame */
1428 *y
+= (self
->size
.bottom
- self
->size
.top
) / 2;
1430 case SouthWestGravity
:
1432 case SouthEastGravity
:
1433 /* the bottom of the client will be the bottom of the frame */
1434 *y
+= self
->size
.bottom
+ self
->size
.top
-
1435 self
->client
->border_width
* 2;
1439 /* the client's position won't move */
1440 *y
+= self
->size
.top
- self
->client
->border_width
;
1445 static void flash_done(gpointer data
)
1447 ObFrame
*self
= data
;
1449 if (self
->focused
!= self
->flash_on
)
1450 frame_adjust_focus(self
, self
->focused
);
1453 static gboolean
flash_timeout(gpointer data
)
1455 ObFrame
*self
= data
;
1458 g_get_current_time(&now
);
1459 if (now
.tv_sec
> self
->flash_end
.tv_sec
||
1460 (now
.tv_sec
== self
->flash_end
.tv_sec
&&
1461 now
.tv_usec
>= self
->flash_end
.tv_usec
))
1462 self
->flashing
= FALSE
;
1464 if (!self
->flashing
)
1465 return FALSE
; /* we are done */
1467 self
->flash_on
= !self
->flash_on
;
1468 if (!self
->focused
) {
1469 frame_adjust_focus(self
, self
->flash_on
);
1470 self
->focused
= FALSE
;
1473 return TRUE
; /* go again */
1476 void frame_flash_start(ObFrame
*self
)
1478 self
->flash_on
= self
->focused
;
1480 if (!self
->flashing
)
1481 ob_main_loop_timeout_add(ob_main_loop
,
1482 G_USEC_PER_SEC
* 0.6,
1487 g_get_current_time(&self
->flash_end
);
1488 g_time_val_add(&self
->flash_end
, G_USEC_PER_SEC
* 5);
1490 self
->flashing
= TRUE
;
1493 void frame_flash_stop(ObFrame
*self
)
1495 self
->flashing
= FALSE
;
1498 static gulong
frame_animate_iconify_time_left(ObFrame
*self
,
1499 const GTimeVal
*now
)
1502 sec
= self
->iconify_animation_end
.tv_sec
- now
->tv_sec
;
1503 usec
= self
->iconify_animation_end
.tv_usec
- now
->tv_usec
;
1505 usec
+= G_USEC_PER_SEC
;
1508 /* no negative values */
1509 return MAX(sec
* G_USEC_PER_SEC
+ usec
, 0);
1512 static gboolean
frame_animate_iconify(gpointer p
)
1516 gint iconx
, icony
, iconw
;
1519 gboolean iconifying
;
1521 if (self
->client
->icon_geometry
.width
== 0) {
1522 /* there is no icon geometry set so just go straight down */
1523 Rect
*a
= screen_physical_area();
1524 iconx
= self
->area
.x
+ self
->area
.width
/ 2 + 32;
1525 icony
= a
->y
+ a
->width
;
1528 iconx
= self
->client
->icon_geometry
.x
;
1529 icony
= self
->client
->icon_geometry
.y
;
1530 iconw
= self
->client
->icon_geometry
.width
;
1533 iconifying
= self
->iconify_animation_going
> 0;
1535 /* how far do we have left to go ? */
1536 g_get_current_time(&now
);
1537 time
= frame_animate_iconify_time_left(self
, &now
);
1539 if (time
== 0 || iconifying
) {
1540 /* start where the frame is supposed to be */
1543 w
= self
->area
.width
;
1544 h
= self
->area
.height
;
1546 /* start at the icon */
1550 h
= self
->size
.top
; /* just the titlebar */
1557 dx
= self
->area
.x
- iconx
;
1558 dy
= self
->area
.y
- icony
;
1559 dw
= self
->area
.width
- self
->bwidth
* 2 - iconw
;
1560 /* if restoring, we move in the opposite direction */
1561 if (!iconifying
) { dx
= -dx
; dy
= -dy
; dw
= -dw
; }
1563 elapsed
= FRAME_ANIMATE_ICONIFY_TIME
- time
;
1564 x
= x
- (dx
* elapsed
) / FRAME_ANIMATE_ICONIFY_TIME
;
1565 y
= y
- (dy
* elapsed
) / FRAME_ANIMATE_ICONIFY_TIME
;
1566 w
= w
- (dw
* elapsed
) / FRAME_ANIMATE_ICONIFY_TIME
;
1567 h
= self
->size
.top
; /* just the titlebar */
1571 frame_end_iconify_animation(self
);
1573 XMoveResizeWindow(ob_display
, self
->window
, x
, y
, w
, h
);
1577 return time
> 0; /* repeat until we're out of time */
1580 void frame_end_iconify_animation(ObFrame
*self
)
1582 /* see if there is an animation going */
1583 if (self
->iconify_animation_going
== 0) return;
1586 XUnmapWindow(ob_display
, self
->window
);
1588 /* Send a ConfigureNotify when the animation is done, this fixes
1589 KDE's pager showing the window in the wrong place. */
1590 client_reconfigure(self
->client
);
1592 /* we're not animating any more ! */
1593 self
->iconify_animation_going
= 0;
1595 XMoveResizeWindow(ob_display
, self
->window
,
1596 self
->area
.x
, self
->area
.y
,
1597 self
->area
.width
, self
->area
.height
);
1601 void frame_begin_iconify_animation(ObFrame
*self
, gboolean iconifying
)
1604 gboolean new_anim
= FALSE
;
1605 gboolean set_end
= TRUE
;
1608 /* if there is no titlebar, just don't animate for now
1609 XXX it would be nice tho.. */
1610 if (!(self
->decorations
& OB_FRAME_DECOR_TITLEBAR
))
1613 /* get the current time */
1614 g_get_current_time(&now
);
1616 /* get how long until the end */
1617 time
= FRAME_ANIMATE_ICONIFY_TIME
;
1618 if (self
->iconify_animation_going
) {
1619 if (!!iconifying
!= (self
->iconify_animation_going
> 0)) {
1620 /* animation was already going on in the opposite direction */
1621 time
= time
- frame_animate_iconify_time_left(self
, &now
);
1623 /* animation was already going in the same direction */
1627 self
->iconify_animation_going
= iconifying
? 1 : -1;
1629 /* set the ending time */
1631 self
->iconify_animation_end
.tv_sec
= now
.tv_sec
;
1632 self
->iconify_animation_end
.tv_usec
= now
.tv_usec
;
1633 g_time_val_add(&self
->iconify_animation_end
, time
);
1637 ob_main_loop_timeout_remove_data(ob_main_loop
, frame_animate_iconify
,
1639 ob_main_loop_timeout_add(ob_main_loop
,
1640 FRAME_ANIMATE_ICONIFY_STEP_TIME
,
1641 frame_animate_iconify
, self
,
1642 g_direct_equal
, NULL
);
1644 /* do the first step */
1645 frame_animate_iconify(self
);
1647 /* show it during the animation even if it is not "visible" */
1649 XMapWindow(ob_display
, self
->window
);