1 /* -*- indent-tabs-mode: nil; tab-width: 4; c-basic-offset: 4; -*-
3 frame.c for the Openbox window manager
4 Copyright (c) 2006 Mikael Magnusson
5 Copyright (c) 2003-2007 Dana Jansens
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2 of the License, or
10 (at your option) any later version.
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 See the COPYING file for a copy of the GNU General Public License.
23 #include "extensions.h"
26 #include "framerender.h"
28 #include "focus_cycle.h"
29 #include "focus_cycle_indicator.h"
30 #include "moveresize.h"
32 #include "render/theme.h"
34 #define PLATE_EVENTMASK (SubstructureRedirectMask | FocusChangeMask)
35 #define FRAME_EVENTMASK (EnterWindowMask | LeaveWindowMask | \
36 ButtonPressMask | ButtonReleaseMask)
37 #define ELEMENT_EVENTMASK (ButtonPressMask | ButtonReleaseMask | \
38 ButtonMotionMask | PointerMotionMask | \
39 EnterWindowMask | LeaveWindowMask)
40 /* The inner window does not need enter/leave events.
41 If it does get them, then it needs its own context for enter events
42 because sloppy focus will focus the window when you enter the inner window
44 #define INNER_EVENTMASK (ButtonPressMask)
46 #define FRAME_ANIMATE_ICONIFY_TIME 150000 /* .15 seconds */
47 #define FRAME_ANIMATE_ICONIFY_STEP_TIME (G_USEC_PER_SEC / 60) /* 60 Hz */
49 #define FRAME_HANDLE_Y(f) (f->size.top + f->client->area.height + f->cbwidth_y)
51 static void flash_done(gpointer data
);
52 static gboolean
flash_timeout(gpointer data
);
54 static void layout_title(ObFrame
*self
);
55 static void set_theme_statics(ObFrame
*self
);
56 static void free_theme_statics(ObFrame
*self
);
57 static gboolean
frame_animate_iconify(gpointer self
);
59 static Window
createWindow(Window parent
, Visual
*visual
,
60 gulong mask
, XSetWindowAttributes
*attrib
)
62 return XCreateWindow(ob_display
, parent
, 0, 0, 1, 1, 0,
63 (visual
? 32 : RrDepth(ob_rr_inst
)), InputOutput
,
64 (visual
? visual
: RrVisual(ob_rr_inst
)),
69 static Visual
*check_32bit_client(ObClient
*c
)
71 XWindowAttributes wattrib
;
74 /* we're already running at 32 bit depth, yay. we don't need to use their
76 if (RrDepth(ob_rr_inst
) == 32)
79 ret
= XGetWindowAttributes(ob_display
, c
->window
, &wattrib
);
80 g_assert(ret
!= BadDrawable
);
81 g_assert(ret
!= BadWindow
);
83 if (wattrib
.depth
== 32)
84 return wattrib
.visual
;
88 ObFrame
*frame_new(ObClient
*client
)
90 XSetWindowAttributes attrib
;
95 self
= g_new0(ObFrame
, 1);
96 self
->client
= client
;
98 visual
= check_32bit_client(client
);
100 /* create the non-visible decor windows */
104 /* client has a 32-bit visual */
105 mask
|= CWColormap
| CWBackPixel
| CWBorderPixel
;
106 /* create a colormap with the visual */
107 self
->colormap
= attrib
.colormap
=
108 XCreateColormap(ob_display
,
109 RootWindow(ob_display
, ob_screen
),
111 attrib
.background_pixel
= BlackPixel(ob_display
, ob_screen
);
112 attrib
.border_pixel
= BlackPixel(ob_display
, ob_screen
);
114 attrib
.event_mask
= FRAME_EVENTMASK
;
115 self
->window
= createWindow(RootWindow(ob_display
, ob_screen
), visual
,
118 attrib
.event_mask
= INNER_EVENTMASK
;
119 self
->inner
= createWindow(self
->window
, visual
, mask
, &attrib
);
121 mask
&= ~CWEventMask
;
122 self
->plate
= createWindow(self
->inner
, visual
, mask
, &attrib
);
124 /* create the visible decor windows */
128 /* client has a 32-bit visual */
129 mask
|= CWColormap
| CWBackPixel
| CWBorderPixel
;
130 attrib
.colormap
= RrColormap(ob_rr_inst
);
132 attrib
.event_mask
= ELEMENT_EVENTMASK
;
133 self
->title
= createWindow(self
->window
, NULL
, mask
, &attrib
);
134 self
->titleleft
= createWindow(self
->window
, NULL
, mask
, &attrib
);
135 self
->titletop
= createWindow(self
->window
, NULL
, mask
, &attrib
);
136 self
->titletopleft
= createWindow(self
->window
, NULL
, mask
, &attrib
);
137 self
->titletopright
= createWindow(self
->window
, NULL
, mask
, &attrib
);
138 self
->titleright
= createWindow(self
->window
, NULL
, mask
, &attrib
);
139 self
->titlebottom
= createWindow(self
->window
, NULL
, mask
, &attrib
);
141 self
->topresize
= createWindow(self
->title
, NULL
, mask
, &attrib
);
142 self
->tltresize
= createWindow(self
->title
, NULL
, mask
, &attrib
);
143 self
->tllresize
= createWindow(self
->title
, NULL
, mask
, &attrib
);
144 self
->trtresize
= createWindow(self
->title
, NULL
, mask
, &attrib
);
145 self
->trrresize
= createWindow(self
->title
, NULL
, mask
, &attrib
);
147 self
->left
= createWindow(self
->window
, NULL
, mask
, &attrib
);
148 self
->right
= createWindow(self
->window
, NULL
, mask
, &attrib
);
150 self
->label
= createWindow(self
->title
, NULL
, mask
, &attrib
);
151 self
->max
= createWindow(self
->title
, NULL
, mask
, &attrib
);
152 self
->close
= createWindow(self
->title
, NULL
, mask
, &attrib
);
153 self
->desk
= createWindow(self
->title
, NULL
, mask
, &attrib
);
154 self
->shade
= createWindow(self
->title
, NULL
, mask
, &attrib
);
155 self
->icon
= createWindow(self
->title
, NULL
, mask
, &attrib
);
156 self
->iconify
= createWindow(self
->title
, NULL
, mask
, &attrib
);
158 self
->handle
= createWindow(self
->window
, NULL
, mask
, &attrib
);
159 self
->lgrip
= createWindow(self
->handle
, NULL
, mask
, &attrib
);
160 self
->rgrip
= createWindow(self
->handle
, NULL
, mask
, &attrib
);
162 self
->handleleft
= createWindow(self
->handle
, NULL
, mask
, &attrib
);
163 self
->handleright
= createWindow(self
->handle
, NULL
, mask
, &attrib
);
165 self
->handletop
= createWindow(self
->window
, NULL
, mask
, &attrib
);
166 self
->handlebottom
= createWindow(self
->window
, NULL
, mask
, &attrib
);
167 self
->lgripleft
= createWindow(self
->window
, NULL
, mask
, &attrib
);
168 self
->lgriptop
= createWindow(self
->window
, NULL
, mask
, &attrib
);
169 self
->lgripbottom
= createWindow(self
->window
, NULL
, mask
, &attrib
);
170 self
->rgripright
= createWindow(self
->window
, NULL
, mask
, &attrib
);
171 self
->rgriptop
= createWindow(self
->window
, NULL
, mask
, &attrib
);
172 self
->rgripbottom
= createWindow(self
->window
, NULL
, mask
, &attrib
);
174 self
->focused
= FALSE
;
176 /* the other stuff is shown based on decor settings */
177 XMapWindow(ob_display
, self
->plate
);
178 XMapWindow(ob_display
, self
->inner
);
179 XMapWindow(ob_display
, self
->label
);
181 self
->max_press
= self
->close_press
= self
->desk_press
=
182 self
->iconify_press
= self
->shade_press
= FALSE
;
183 self
->max_hover
= self
->close_hover
= self
->desk_hover
=
184 self
->iconify_hover
= self
->shade_hover
= FALSE
;
186 set_theme_statics(self
);
188 return (ObFrame
*)self
;
191 static void set_theme_statics(ObFrame
*self
)
193 /* set colors/appearance/sizes for stuff that doesn't change */
194 XResizeWindow(ob_display
, self
->max
,
195 ob_rr_theme
->button_size
, ob_rr_theme
->button_size
);
196 XResizeWindow(ob_display
, self
->iconify
,
197 ob_rr_theme
->button_size
, ob_rr_theme
->button_size
);
198 XResizeWindow(ob_display
, self
->icon
,
199 ob_rr_theme
->button_size
+ 2, ob_rr_theme
->button_size
+ 2);
200 XResizeWindow(ob_display
, self
->close
,
201 ob_rr_theme
->button_size
, ob_rr_theme
->button_size
);
202 XResizeWindow(ob_display
, self
->desk
,
203 ob_rr_theme
->button_size
, ob_rr_theme
->button_size
);
204 XResizeWindow(ob_display
, self
->shade
,
205 ob_rr_theme
->button_size
, ob_rr_theme
->button_size
);
206 XResizeWindow(ob_display
, self
->tltresize
,
207 ob_rr_theme
->grip_width
, ob_rr_theme
->paddingy
+ 1);
208 XResizeWindow(ob_display
, self
->trtresize
,
209 ob_rr_theme
->grip_width
, ob_rr_theme
->paddingy
+ 1);
210 XResizeWindow(ob_display
, self
->tllresize
,
211 ob_rr_theme
->paddingx
+ 1, ob_rr_theme
->title_height
);
212 XResizeWindow(ob_display
, self
->trrresize
,
213 ob_rr_theme
->paddingx
+ 1, ob_rr_theme
->title_height
);
215 /* set up the dynamic appearances */
216 self
->a_unfocused_title
= RrAppearanceCopy(ob_rr_theme
->a_unfocused_title
);
217 self
->a_focused_title
= RrAppearanceCopy(ob_rr_theme
->a_focused_title
);
218 self
->a_unfocused_label
= RrAppearanceCopy(ob_rr_theme
->a_unfocused_label
);
219 self
->a_focused_label
= RrAppearanceCopy(ob_rr_theme
->a_focused_label
);
220 self
->a_unfocused_handle
=
221 RrAppearanceCopy(ob_rr_theme
->a_unfocused_handle
);
222 self
->a_focused_handle
= RrAppearanceCopy(ob_rr_theme
->a_focused_handle
);
223 self
->a_icon
= RrAppearanceCopy(ob_rr_theme
->a_icon
);
226 static void free_theme_statics(ObFrame
*self
)
228 RrAppearanceFree(self
->a_unfocused_title
);
229 RrAppearanceFree(self
->a_focused_title
);
230 RrAppearanceFree(self
->a_unfocused_label
);
231 RrAppearanceFree(self
->a_focused_label
);
232 RrAppearanceFree(self
->a_unfocused_handle
);
233 RrAppearanceFree(self
->a_focused_handle
);
234 RrAppearanceFree(self
->a_icon
);
237 void frame_free(ObFrame
*self
)
239 free_theme_statics(self
);
241 XDestroyWindow(ob_display
, self
->window
);
243 XFreeColormap(ob_display
, self
->colormap
);
248 void frame_show(ObFrame
*self
)
250 if (!self
->visible
) {
251 self
->visible
= TRUE
;
252 XMapWindow(ob_display
, self
->client
->window
);
253 XMapWindow(ob_display
, self
->window
);
257 void frame_hide(ObFrame
*self
)
260 self
->visible
= FALSE
;
261 if (!frame_iconify_animating(self
))
262 XUnmapWindow(ob_display
, self
->window
);
263 /* we unmap the client itself so that we can get MapRequest
264 events, and because the ICCCM tells us to! */
265 XUnmapWindow(ob_display
, self
->client
->window
);
266 self
->client
->ignore_unmaps
+= 1;
270 void frame_adjust_theme(ObFrame
*self
)
272 free_theme_statics(self
);
273 set_theme_statics(self
);
276 void frame_adjust_shape(ObFrame
*self
)
282 if (!self
->client
->shaped
) {
283 /* clear the shape on the frame window */
284 XShapeCombineMask(ob_display
, self
->window
, ShapeBounding
,
289 /* make the frame's shape match the clients */
290 XShapeCombineShape(ob_display
, self
->window
, ShapeBounding
,
293 self
->client
->window
,
294 ShapeBounding
, ShapeSet
);
297 if (self
->decorations
& OB_FRAME_DECOR_TITLEBAR
) {
298 xrect
[0].x
= -ob_rr_theme
->fbwidth
;
299 xrect
[0].y
= -ob_rr_theme
->fbwidth
;
300 xrect
[0].width
= self
->width
+ self
->bwidth
* 2;
301 xrect
[0].height
= ob_rr_theme
->title_height
+
306 if (self
->decorations
& OB_FRAME_DECOR_HANDLE
) {
307 xrect
[1].x
= -ob_rr_theme
->fbwidth
;
308 xrect
[1].y
= FRAME_HANDLE_Y(self
);
309 xrect
[1].width
= self
->width
+ self
->bwidth
* 2;
310 xrect
[1].height
= ob_rr_theme
->handle_height
+
315 XShapeCombineRectangles(ob_display
, self
->window
,
316 ShapeBounding
, 0, 0, xrect
, num
,
317 ShapeUnion
, Unsorted
);
322 void frame_adjust_area(ObFrame
*self
, gboolean moved
,
323 gboolean resized
, gboolean fake
)
327 oldsize
= self
->size
;
330 self
->decorations
= self
->client
->decorations
;
331 self
->max_horz
= self
->client
->max_horz
;
333 if (self
->decorations
& OB_FRAME_DECOR_BORDER
) {
334 self
->bwidth
= ob_rr_theme
->fbwidth
;
335 self
->cbwidth_x
= ob_rr_theme
->cbwidthx
;
336 self
->cbwidth_y
= ob_rr_theme
->cbwidthy
;
338 self
->bwidth
= self
->cbwidth_x
= self
->cbwidth_y
= 0;
340 self
->rbwidth
= self
->bwidth
;
341 self
->leftb
= self
->rightb
= TRUE
;
343 if (self
->max_horz
) {
344 self
->leftb
= self
->rightb
= FALSE
;
348 self
->width
= self
->client
->area
.width
+ self
->cbwidth_x
* 2;
349 self
->width
= MAX(self
->width
, 1); /* no lower than 1 */
351 STRUT_SET(self
->size
,
352 self
->cbwidth_x
+ (self
->leftb
? self
->bwidth
: 0),
353 self
->cbwidth_y
+ self
->bwidth
,
354 self
->cbwidth_x
+ (self
->rightb
? self
->bwidth
: 0),
355 self
->cbwidth_y
+ self
->bwidth
);
357 if (self
->decorations
& OB_FRAME_DECOR_TITLEBAR
)
358 self
->size
.top
+= ob_rr_theme
->title_height
+ self
->rbwidth
;
359 if (self
->decorations
& OB_FRAME_DECOR_HANDLE
&&
360 ob_rr_theme
->handle_height
> 0)
362 self
->size
.bottom
+= ob_rr_theme
->handle_height
+ self
->bwidth
;
365 /* position/size and map/unmap all the windows */
369 XMoveResizeWindow(ob_display
, self
->titletop
,
370 ob_rr_theme
->grip_width
+ self
->bwidth
, 0,
371 self
->client
->area
.width
+
372 self
->cbwidth_x
* 2 + self
->bwidth
* 2 -
373 (ob_rr_theme
->grip_width
+ self
->bwidth
) * 2,
375 XMoveResizeWindow(ob_display
, self
->titletopleft
,
377 ob_rr_theme
->grip_width
+ self
->bwidth
,
379 XMoveResizeWindow(ob_display
, self
->titletopright
,
380 self
->client
->area
.width
+
381 self
->cbwidth_x
* 2 + self
->bwidth
* 2 -
382 ob_rr_theme
->grip_width
- self
->bwidth
,
384 ob_rr_theme
->grip_width
+ self
->bwidth
,
387 XMoveResizeWindow(ob_display
, self
->titleleft
,
391 ob_rr_theme
->grip_width
:
392 self
->size
.top
- self
->bwidth
));
393 XMoveResizeWindow(ob_display
, self
->titleright
,
394 self
->client
->area
.width
+
395 self
->cbwidth_x
* 2 + self
->bwidth
,
399 ob_rr_theme
->grip_width
:
400 self
->size
.top
- self
->bwidth
));
402 XMapWindow(ob_display
, self
->titletop
);
403 XMapWindow(ob_display
, self
->titletopleft
);
404 XMapWindow(ob_display
, self
->titletopright
);
405 XMapWindow(ob_display
, self
->titleleft
);
406 XMapWindow(ob_display
, self
->titleright
);
408 if (self
->decorations
& OB_FRAME_DECOR_TITLEBAR
&&
411 XMoveResizeWindow(ob_display
, self
->titlebottom
,
413 ob_rr_theme
->title_height
+ self
->bwidth
,
414 self
->client
->area
.width
+
418 XMapWindow(ob_display
, self
->titlebottom
);
420 XUnmapWindow(ob_display
, self
->titlebottom
);
422 XUnmapWindow(ob_display
, self
->titletop
);
423 XUnmapWindow(ob_display
, self
->titletopleft
);
424 XUnmapWindow(ob_display
, self
->titletopright
);
425 XUnmapWindow(ob_display
, self
->titleleft
);
426 XUnmapWindow(ob_display
, self
->titleright
);
429 if (self
->decorations
& OB_FRAME_DECOR_TITLEBAR
) {
430 XMoveResizeWindow(ob_display
, self
->title
,
431 self
->bwidth
, self
->bwidth
,
432 self
->width
, ob_rr_theme
->title_height
);
434 XMapWindow(ob_display
, self
->title
);
436 if (self
->decorations
& OB_FRAME_DECOR_GRIPS
) {
437 XMoveResizeWindow(ob_display
, self
->topresize
,
438 ob_rr_theme
->grip_width
+ self
->bwidth
,
440 self
->width
- (ob_rr_theme
->grip_width
+
442 ob_rr_theme
->paddingy
+ 1);
444 XMoveWindow(ob_display
, self
->tltresize
, 0, 0);
445 XMoveWindow(ob_display
, self
->tllresize
, 0, 0);
446 XMoveWindow(ob_display
, self
->trtresize
,
447 self
->width
- ob_rr_theme
->grip_width
, 0);
448 XMoveWindow(ob_display
, self
->trrresize
,
449 self
->width
- ob_rr_theme
->paddingx
- 1, 0);
451 XMapWindow(ob_display
, self
->topresize
);
452 XMapWindow(ob_display
, self
->tltresize
);
453 XMapWindow(ob_display
, self
->tllresize
);
454 XMapWindow(ob_display
, self
->trtresize
);
455 XMapWindow(ob_display
, self
->trrresize
);
457 XUnmapWindow(ob_display
, self
->topresize
);
458 XUnmapWindow(ob_display
, self
->tltresize
);
459 XUnmapWindow(ob_display
, self
->tllresize
);
460 XUnmapWindow(ob_display
, self
->trtresize
);
461 XUnmapWindow(ob_display
, self
->trrresize
);
464 XUnmapWindow(ob_display
, self
->title
);
467 if ((self
->decorations
& OB_FRAME_DECOR_TITLEBAR
))
468 /* layout the title bar elements */
473 XMoveResizeWindow(ob_display
, self
->handlebottom
,
474 ob_rr_theme
->grip_width
+
476 self
->size
.top
+ self
->client
->area
.height
+
477 self
->size
.bottom
- self
->bwidth
,
478 self
->width
- (ob_rr_theme
->grip_width
+
482 XMoveResizeWindow(ob_display
, self
->lgripleft
,
484 self
->size
.top
+ self
->client
->area
.height
+
487 ob_rr_theme
->grip_width
:
491 ob_rr_theme
->grip_width
:
493 XMoveResizeWindow(ob_display
, self
->rgripright
,
494 self
->size
.left
+ self
->client
->area
.width
+
495 self
->size
.right
- self
->bwidth
,
496 self
->size
.top
+ self
->client
->area
.height
+
499 ob_rr_theme
->grip_width
:
503 ob_rr_theme
->grip_width
:
506 XMoveResizeWindow(ob_display
, self
->lgripbottom
,
508 self
->size
.top
+ self
->client
->area
.height
+
509 self
->size
.bottom
- self
->bwidth
,
510 ob_rr_theme
->grip_width
+ self
->bwidth
,
512 XMoveResizeWindow(ob_display
, self
->rgripbottom
,
513 self
->size
.left
+ self
->client
->area
.width
+
514 self
->size
.right
- self
->bwidth
* 2 -
515 ob_rr_theme
->grip_width
,
516 self
->size
.top
+ self
->client
->area
.height
+
517 self
->size
.bottom
- self
->bwidth
,
518 ob_rr_theme
->grip_width
+ self
->bwidth
,
521 XMapWindow(ob_display
, self
->handlebottom
);
522 XMapWindow(ob_display
, self
->lgripleft
);
523 XMapWindow(ob_display
, self
->rgripright
);
524 XMapWindow(ob_display
, self
->lgripbottom
);
525 XMapWindow(ob_display
, self
->rgripbottom
);
527 if (self
->decorations
& OB_FRAME_DECOR_HANDLE
&&
528 ob_rr_theme
->handle_height
> 0)
530 XMoveResizeWindow(ob_display
, self
->handletop
,
531 ob_rr_theme
->grip_width
+
533 FRAME_HANDLE_Y(self
),
534 self
->width
- (ob_rr_theme
->grip_width
+
537 XMapWindow(ob_display
, self
->handletop
);
539 if (self
->decorations
& OB_FRAME_DECOR_GRIPS
) {
540 XMoveResizeWindow(ob_display
, self
->handleleft
,
541 ob_rr_theme
->grip_width
,
544 ob_rr_theme
->handle_height
);
545 XMoveResizeWindow(ob_display
, self
->handleright
,
547 ob_rr_theme
->grip_width
-
551 ob_rr_theme
->handle_height
);
553 XMoveResizeWindow(ob_display
, self
->lgriptop
,
555 FRAME_HANDLE_Y(self
),
556 ob_rr_theme
->grip_width
+
559 XMoveResizeWindow(ob_display
, self
->rgriptop
,
561 self
->client
->area
.width
+
562 self
->size
.right
- self
->bwidth
* 2 -
563 ob_rr_theme
->grip_width
,
564 FRAME_HANDLE_Y(self
),
565 ob_rr_theme
->grip_width
+
569 XMapWindow(ob_display
, self
->handleleft
);
570 XMapWindow(ob_display
, self
->handleright
);
571 XMapWindow(ob_display
, self
->lgriptop
);
572 XMapWindow(ob_display
, self
->rgriptop
);
574 XUnmapWindow(ob_display
, self
->handleleft
);
575 XUnmapWindow(ob_display
, self
->handleright
);
576 XUnmapWindow(ob_display
, self
->lgriptop
);
577 XUnmapWindow(ob_display
, self
->rgriptop
);
580 XUnmapWindow(ob_display
, self
->handletop
);
582 XUnmapWindow(ob_display
, self
->handlebottom
);
583 XUnmapWindow(ob_display
, self
->lgripleft
);
584 XUnmapWindow(ob_display
, self
->rgripright
);
585 XUnmapWindow(ob_display
, self
->lgripbottom
);
586 XUnmapWindow(ob_display
, self
->rgripbottom
);
589 if (self
->decorations
& OB_FRAME_DECOR_HANDLE
&&
590 ob_rr_theme
->handle_height
> 0)
592 XMoveResizeWindow(ob_display
, self
->handle
,
594 FRAME_HANDLE_Y(self
) + self
->bwidth
,
595 self
->width
, ob_rr_theme
->handle_height
);
596 XMapWindow(ob_display
, self
->handle
);
598 if (self
->decorations
& OB_FRAME_DECOR_GRIPS
) {
599 XMoveResizeWindow(ob_display
, self
->lgrip
,
601 ob_rr_theme
->grip_width
,
602 ob_rr_theme
->handle_height
);
603 XMoveResizeWindow(ob_display
, self
->rgrip
,
604 self
->width
- ob_rr_theme
->grip_width
,
606 ob_rr_theme
->grip_width
,
607 ob_rr_theme
->handle_height
);
609 XMapWindow(ob_display
, self
->lgrip
);
610 XMapWindow(ob_display
, self
->rgrip
);
612 XUnmapWindow(ob_display
, self
->lgrip
);
613 XUnmapWindow(ob_display
, self
->rgrip
);
616 XUnmapWindow(ob_display
, self
->handle
);
618 if (self
->bwidth
&& !self
->max_horz
) {
619 XMoveResizeWindow(ob_display
, self
->left
,
621 self
->bwidth
+ ob_rr_theme
->grip_width
,
623 self
->client
->area
.height
+
624 self
->size
.top
+ self
->size
.bottom
-
625 ob_rr_theme
->grip_width
* 2);
626 XMoveResizeWindow(ob_display
, self
->right
,
627 self
->client
->area
.width
+
628 self
->cbwidth_x
* 2 + self
->bwidth
,
629 self
->bwidth
+ ob_rr_theme
->grip_width
,
631 self
->client
->area
.height
+
632 self
->size
.top
+ self
->size
.bottom
-
633 ob_rr_theme
->grip_width
* 2);
635 XMapWindow(ob_display
, self
->left
);
636 XMapWindow(ob_display
, self
->right
);
638 XUnmapWindow(ob_display
, self
->left
);
639 XUnmapWindow(ob_display
, self
->right
);
642 /* move and resize the inner border window which contains the plate
644 XMoveResizeWindow(ob_display
, self
->inner
,
646 self
->size
.top
- self
->cbwidth_y
,
647 self
->client
->area
.width
+
648 self
->cbwidth_x
* 2 +
649 (self
->leftb
? self
->bwidth
: 0) +
650 (self
->rightb
? self
->bwidth
: 0),
651 self
->client
->area
.height
+
652 self
->cbwidth_y
* 2);
655 XMoveWindow(ob_display
, self
->plate
,
656 (self
->leftb
? self
->bwidth
: 0) + self
->cbwidth_x
,
659 /* when the client has StaticGravity, it likes to move around. */
660 XMoveWindow(ob_display
, self
->client
->window
, 0, 0);
664 /* shading can change without being moved or resized */
665 RECT_SET_SIZE(self
->area
,
666 self
->client
->area
.width
+
667 self
->size
.left
+ self
->size
.right
,
668 (self
->client
->shaded
?
669 ob_rr_theme
->title_height
+ self
->bwidth
* 2:
670 self
->client
->area
.height
+
671 self
->size
.top
+ self
->size
.bottom
));
673 if (moved
|| resized
) {
674 /* find the new coordinates, done after setting the frame.size, for
675 frame_client_gravity. */
676 self
->area
.x
= self
->client
->area
.x
;
677 self
->area
.y
= self
->client
->area
.y
;
678 frame_client_gravity(self
, &self
->area
.x
, &self
->area
.y
,
679 self
->client
->area
.width
,
680 self
->client
->area
.height
);
684 if (!frame_iconify_animating(self
))
685 /* move and resize the top level frame.
686 shading can change without being moved or resized.
688 but don't do this during an iconify animation. it will be
689 reflected afterwards.
691 XMoveResizeWindow(ob_display
, self
->window
,
698 framerender_frame(self
);
699 frame_adjust_shape(self
);
702 if (!STRUT_EQUAL(self
->size
, oldsize
)) {
704 vals
[0] = self
->size
.left
;
705 vals
[1] = self
->size
.right
;
706 vals
[2] = self
->size
.top
;
707 vals
[3] = self
->size
.bottom
;
708 PROP_SETA32(self
->client
->window
, net_frame_extents
,
710 PROP_SETA32(self
->client
->window
, kde_net_wm_frame_strut
,
714 /* if this occurs while we are focus cycling, the indicator needs to
716 if (focus_cycle_target
== self
->client
)
717 focus_cycle_draw_indicator(self
->client
);
719 if (resized
&& (self
->decorations
& OB_FRAME_DECOR_TITLEBAR
))
720 XResizeWindow(ob_display
, self
->label
, self
->label_width
,
721 ob_rr_theme
->label_height
);
725 (self
->functions
& OB_CLIENT_FUNC_RESIZE
) !=
726 (self
->client
->functions
& OB_CLIENT_FUNC_RESIZE
))
728 gboolean r
= self
->client
->functions
& OB_CLIENT_FUNC_RESIZE
;
729 XSetWindowAttributes a
;
731 a
.cursor
= ob_cursor(r
? OB_CURSOR_NORTH
: OB_CURSOR_NONE
);
732 XChangeWindowAttributes(ob_display
, self
->topresize
, CWCursor
, &a
);
733 XChangeWindowAttributes(ob_display
, self
->titletop
, CWCursor
, &a
);
734 a
.cursor
= ob_cursor(r
? OB_CURSOR_NORTHWEST
: OB_CURSOR_NONE
);
735 XChangeWindowAttributes(ob_display
, self
->tltresize
, CWCursor
, &a
);
736 XChangeWindowAttributes(ob_display
, self
->tllresize
, CWCursor
, &a
);
737 XChangeWindowAttributes(ob_display
, self
->titletopleft
, CWCursor
, &a
);
738 XChangeWindowAttributes(ob_display
, self
->titleleft
, CWCursor
, &a
);
739 a
.cursor
= ob_cursor(r
? OB_CURSOR_NORTHEAST
: OB_CURSOR_NONE
);
740 XChangeWindowAttributes(ob_display
, self
->trtresize
, CWCursor
, &a
);
741 XChangeWindowAttributes(ob_display
, self
->trrresize
, CWCursor
, &a
);
742 XChangeWindowAttributes(ob_display
, self
->titletopright
, CWCursor
, &a
);
743 XChangeWindowAttributes(ob_display
, self
->titleright
, CWCursor
, &a
);
744 a
.cursor
= ob_cursor(r
? OB_CURSOR_WEST
: OB_CURSOR_NONE
);
745 XChangeWindowAttributes(ob_display
, self
->left
, CWCursor
, &a
);
746 a
.cursor
= ob_cursor(r
? OB_CURSOR_EAST
: OB_CURSOR_NONE
);
747 XChangeWindowAttributes(ob_display
, self
->right
, CWCursor
, &a
);
748 a
.cursor
= ob_cursor(r
? OB_CURSOR_SOUTH
: OB_CURSOR_NONE
);
749 XChangeWindowAttributes(ob_display
, self
->handle
, CWCursor
, &a
);
750 XChangeWindowAttributes(ob_display
, self
->handletop
, CWCursor
, &a
);
751 XChangeWindowAttributes(ob_display
, self
->handlebottom
, CWCursor
, &a
);
752 a
.cursor
= ob_cursor(r
? OB_CURSOR_SOUTHWEST
: OB_CURSOR_NONE
);
753 XChangeWindowAttributes(ob_display
, self
->lgrip
, CWCursor
, &a
);
754 XChangeWindowAttributes(ob_display
, self
->handleleft
, CWCursor
, &a
);
755 XChangeWindowAttributes(ob_display
, self
->lgripleft
, CWCursor
, &a
);
756 XChangeWindowAttributes(ob_display
, self
->lgriptop
, CWCursor
, &a
);
757 XChangeWindowAttributes(ob_display
, self
->lgripbottom
, CWCursor
, &a
);
758 a
.cursor
= ob_cursor(r
? OB_CURSOR_SOUTHEAST
: OB_CURSOR_NONE
);
759 XChangeWindowAttributes(ob_display
, self
->rgrip
, CWCursor
, &a
);
760 XChangeWindowAttributes(ob_display
, self
->handleright
, CWCursor
, &a
);
761 XChangeWindowAttributes(ob_display
, self
->rgripright
, CWCursor
, &a
);
762 XChangeWindowAttributes(ob_display
, self
->rgriptop
, CWCursor
, &a
);
763 XChangeWindowAttributes(ob_display
, self
->rgripbottom
, CWCursor
, &a
);
765 self
->functions
= self
->client
->functions
;
769 void frame_adjust_client_area(ObFrame
*self
)
771 /* resize the plate */
772 XResizeWindow(ob_display
, self
->plate
,
773 self
->client
->area
.width
, self
->client
->area
.height
);
776 void frame_adjust_state(ObFrame
*self
)
778 framerender_frame(self
);
781 void frame_adjust_focus(ObFrame
*self
, gboolean hilite
)
783 self
->focused
= hilite
;
784 framerender_frame(self
);
788 void frame_adjust_title(ObFrame
*self
)
790 framerender_frame(self
);
793 void frame_adjust_icon(ObFrame
*self
)
795 framerender_frame(self
);
798 void frame_grab_client(ObFrame
*self
)
800 /* reparent the client to the frame */
801 XReparentWindow(ob_display
, self
->client
->window
, self
->plate
, 0, 0);
804 When reparenting the client window, it is usually not mapped yet, since
805 this occurs from a MapRequest. However, in the case where Openbox is
806 starting up, the window is already mapped, so we'll see unmap events for
807 it. There are 2 unmap events generated that we see, one with the 'event'
808 member set the root window, and one set to the client, but both get
809 handled and need to be ignored.
811 if (ob_state() == OB_STATE_STARTING
)
812 self
->client
->ignore_unmaps
+= 2;
814 /* select the event mask on the client's parent (to receive config/map
815 req's) the ButtonPress is to catch clicks on the client border */
816 XSelectInput(ob_display
, self
->plate
, PLATE_EVENTMASK
);
818 /* map the client so it maps when the frame does */
819 XMapWindow(ob_display
, self
->client
->window
);
821 /* set all the windows for the frame in the window_map */
822 g_hash_table_insert(window_map
, &self
->window
, self
->client
);
823 g_hash_table_insert(window_map
, &self
->plate
, self
->client
);
824 g_hash_table_insert(window_map
, &self
->inner
, self
->client
);
825 g_hash_table_insert(window_map
, &self
->title
, self
->client
);
826 g_hash_table_insert(window_map
, &self
->label
, self
->client
);
827 g_hash_table_insert(window_map
, &self
->max
, self
->client
);
828 g_hash_table_insert(window_map
, &self
->close
, self
->client
);
829 g_hash_table_insert(window_map
, &self
->desk
, self
->client
);
830 g_hash_table_insert(window_map
, &self
->shade
, self
->client
);
831 g_hash_table_insert(window_map
, &self
->icon
, self
->client
);
832 g_hash_table_insert(window_map
, &self
->iconify
, self
->client
);
833 g_hash_table_insert(window_map
, &self
->handle
, self
->client
);
834 g_hash_table_insert(window_map
, &self
->lgrip
, self
->client
);
835 g_hash_table_insert(window_map
, &self
->rgrip
, self
->client
);
836 g_hash_table_insert(window_map
, &self
->topresize
, self
->client
);
837 g_hash_table_insert(window_map
, &self
->tltresize
, self
->client
);
838 g_hash_table_insert(window_map
, &self
->tllresize
, self
->client
);
839 g_hash_table_insert(window_map
, &self
->trtresize
, self
->client
);
840 g_hash_table_insert(window_map
, &self
->trrresize
, self
->client
);
841 g_hash_table_insert(window_map
, &self
->left
, self
->client
);
842 g_hash_table_insert(window_map
, &self
->right
, self
->client
);
843 g_hash_table_insert(window_map
, &self
->titleleft
, self
->client
);
844 g_hash_table_insert(window_map
, &self
->titletop
, self
->client
);
845 g_hash_table_insert(window_map
, &self
->titletopleft
, self
->client
);
846 g_hash_table_insert(window_map
, &self
->titletopright
, self
->client
);
847 g_hash_table_insert(window_map
, &self
->titleright
, self
->client
);
848 g_hash_table_insert(window_map
, &self
->titlebottom
, self
->client
);
849 g_hash_table_insert(window_map
, &self
->handleleft
, self
->client
);
850 g_hash_table_insert(window_map
, &self
->handletop
, self
->client
);
851 g_hash_table_insert(window_map
, &self
->handleright
, self
->client
);
852 g_hash_table_insert(window_map
, &self
->handlebottom
, self
->client
);
853 g_hash_table_insert(window_map
, &self
->lgripleft
, self
->client
);
854 g_hash_table_insert(window_map
, &self
->lgriptop
, self
->client
);
855 g_hash_table_insert(window_map
, &self
->lgripbottom
, self
->client
);
856 g_hash_table_insert(window_map
, &self
->rgripright
, self
->client
);
857 g_hash_table_insert(window_map
, &self
->rgriptop
, self
->client
);
858 g_hash_table_insert(window_map
, &self
->rgripbottom
, self
->client
);
861 void frame_release_client(ObFrame
*self
)
864 gboolean reparent
= TRUE
;
866 /* if there was any animation going on, kill it */
867 ob_main_loop_timeout_remove_data(ob_main_loop
, frame_animate_iconify
,
870 /* check if the app has already reparented its window away */
871 while (XCheckTypedWindowEvent(ob_display
, self
->client
->window
,
872 ReparentNotify
, &ev
))
874 /* This check makes sure we don't catch our own reparent action to
875 our frame window. This doesn't count as the app reparenting itself
878 Reparent events that are generated by us are just discarded here.
879 They are of no consequence to us anyhow.
881 if (ev
.xreparent
.parent
!= self
->plate
) {
883 XPutBackEvent(ob_display
, &ev
);
889 /* according to the ICCCM - if the client doesn't reparent itself,
890 then we will reparent the window to root for them */
891 XReparentWindow(ob_display
, self
->client
->window
,
892 RootWindow(ob_display
, ob_screen
),
893 self
->client
->area
.x
,
894 self
->client
->area
.y
);
897 /* remove all the windows for the frame from the window_map */
898 g_hash_table_remove(window_map
, &self
->window
);
899 g_hash_table_remove(window_map
, &self
->plate
);
900 g_hash_table_remove(window_map
, &self
->inner
);
901 g_hash_table_remove(window_map
, &self
->title
);
902 g_hash_table_remove(window_map
, &self
->label
);
903 g_hash_table_remove(window_map
, &self
->max
);
904 g_hash_table_remove(window_map
, &self
->close
);
905 g_hash_table_remove(window_map
, &self
->desk
);
906 g_hash_table_remove(window_map
, &self
->shade
);
907 g_hash_table_remove(window_map
, &self
->icon
);
908 g_hash_table_remove(window_map
, &self
->iconify
);
909 g_hash_table_remove(window_map
, &self
->handle
);
910 g_hash_table_remove(window_map
, &self
->lgrip
);
911 g_hash_table_remove(window_map
, &self
->rgrip
);
912 g_hash_table_remove(window_map
, &self
->topresize
);
913 g_hash_table_remove(window_map
, &self
->tltresize
);
914 g_hash_table_remove(window_map
, &self
->tllresize
);
915 g_hash_table_remove(window_map
, &self
->trtresize
);
916 g_hash_table_remove(window_map
, &self
->trrresize
);
917 g_hash_table_remove(window_map
, &self
->left
);
918 g_hash_table_remove(window_map
, &self
->right
);
919 g_hash_table_remove(window_map
, &self
->titleleft
);
920 g_hash_table_remove(window_map
, &self
->titletop
);
921 g_hash_table_remove(window_map
, &self
->titletopleft
);
922 g_hash_table_remove(window_map
, &self
->titletopright
);
923 g_hash_table_remove(window_map
, &self
->titleright
);
924 g_hash_table_remove(window_map
, &self
->titlebottom
);
925 g_hash_table_remove(window_map
, &self
->handleleft
);
926 g_hash_table_remove(window_map
, &self
->handletop
);
927 g_hash_table_remove(window_map
, &self
->handleright
);
928 g_hash_table_remove(window_map
, &self
->handlebottom
);
929 g_hash_table_remove(window_map
, &self
->lgripleft
);
930 g_hash_table_remove(window_map
, &self
->lgriptop
);
931 g_hash_table_remove(window_map
, &self
->lgripbottom
);
932 g_hash_table_remove(window_map
, &self
->rgripright
);
933 g_hash_table_remove(window_map
, &self
->rgriptop
);
934 g_hash_table_remove(window_map
, &self
->rgripbottom
);
936 ob_main_loop_timeout_remove_data(ob_main_loop
, flash_timeout
, self
, TRUE
);
939 /* is there anything present between us and the label? */
940 static gboolean
is_button_present(ObFrame
*self
, const gchar
*lc
, gint dir
) {
941 for (; *lc
!= '\0' && lc
>= config_title_layout
; lc
+= dir
) {
942 if (*lc
== ' ') continue; /* it was invalid */
943 if (*lc
== 'N' && self
->decorations
& OB_FRAME_DECOR_ICON
)
945 if (*lc
== 'D' && self
->decorations
& OB_FRAME_DECOR_ALLDESKTOPS
)
947 if (*lc
== 'S' && self
->decorations
& OB_FRAME_DECOR_SHADE
)
949 if (*lc
== 'I' && self
->decorations
& OB_FRAME_DECOR_ICONIFY
)
951 if (*lc
== 'M' && self
->decorations
& OB_FRAME_DECOR_MAXIMIZE
)
953 if (*lc
== 'C' && self
->decorations
& OB_FRAME_DECOR_CLOSE
)
955 if (*lc
== 'L') return FALSE
;
960 static void layout_title(ObFrame
*self
)
965 const gint bwidth
= ob_rr_theme
->button_size
+ ob_rr_theme
->paddingx
+ 1;
966 /* position of the left most button */
967 const gint left
= ob_rr_theme
->paddingx
+ 1;
968 /* position of the right most button */
969 const gint right
= self
->width
- bwidth
;
971 /* turn them all off */
972 self
->icon_on
= self
->desk_on
= self
->shade_on
= self
->iconify_on
=
973 self
->max_on
= self
->close_on
= self
->label_on
= FALSE
;
974 self
->label_width
= self
->width
- (ob_rr_theme
->paddingx
+ 1) * 2;
975 self
->leftmost
= self
->rightmost
= OB_FRAME_CONTEXT_NONE
;
977 /* figure out what's being show, find each element's position, and the
980 do the ones before the label, then after the label,
981 i will be +1 the first time through when working to the left,
982 and -1 the second time through when working to the right */
983 for (i
= 1; i
>= -1; i
-=2) {
985 ObFrameContext
*firstcon
;
989 lc
= config_title_layout
;
990 firstcon
= &self
->leftmost
;
993 lc
= config_title_layout
+ strlen(config_title_layout
)-1;
994 firstcon
= &self
->rightmost
;
997 /* stop at the end of the string (or the label, which calls break) */
998 for (; *lc
!= '\0' && lc
>= config_title_layout
; lc
+=i
) {
1001 self
->label_on
= TRUE
;
1004 break; /* break the for loop, do other side of label */
1005 } else if (*lc
== 'N') {
1006 if (firstcon
) *firstcon
= OB_FRAME_CONTEXT_ICON
;
1007 if ((self
->icon_on
= is_button_present(self
, lc
, i
))) {
1008 /* icon is bigger than buttons */
1009 self
->label_width
-= bwidth
+ 2;
1011 x
+= i
* (bwidth
+ 2);
1013 } else if (*lc
== 'D') {
1014 if (firstcon
) *firstcon
= OB_FRAME_CONTEXT_ALLDESKTOPS
;
1015 if ((self
->desk_on
= is_button_present(self
, lc
, i
))) {
1016 self
->label_width
-= bwidth
;
1020 } else if (*lc
== 'S') {
1021 if (firstcon
) *firstcon
= OB_FRAME_CONTEXT_SHADE
;
1022 if ((self
->shade_on
= is_button_present(self
, lc
, i
))) {
1023 self
->label_width
-= bwidth
;
1027 } else if (*lc
== 'I') {
1028 if (firstcon
) *firstcon
= OB_FRAME_CONTEXT_ICONIFY
;
1029 if ((self
->iconify_on
= is_button_present(self
, lc
, i
))) {
1030 self
->label_width
-= bwidth
;
1031 self
->iconify_x
= x
;
1034 } else if (*lc
== 'M') {
1035 if (firstcon
) *firstcon
= OB_FRAME_CONTEXT_MAXIMIZE
;
1036 if ((self
->max_on
= is_button_present(self
, lc
, i
))) {
1037 self
->label_width
-= bwidth
;
1041 } else if (*lc
== 'C') {
1042 if (firstcon
) *firstcon
= OB_FRAME_CONTEXT_CLOSE
;
1043 if ((self
->close_on
= is_button_present(self
, lc
, i
))) {
1044 self
->label_width
-= bwidth
;
1049 continue; /* don't set firstcon */
1054 /* position and map the elements */
1055 if (self
->icon_on
) {
1056 XMapWindow(ob_display
, self
->icon
);
1057 XMoveWindow(ob_display
, self
->icon
, self
->icon_x
,
1058 ob_rr_theme
->paddingy
);
1060 XUnmapWindow(ob_display
, self
->icon
);
1062 if (self
->desk_on
) {
1063 XMapWindow(ob_display
, self
->desk
);
1064 XMoveWindow(ob_display
, self
->desk
, self
->desk_x
,
1065 ob_rr_theme
->paddingy
+ 1);
1067 XUnmapWindow(ob_display
, self
->desk
);
1069 if (self
->shade_on
) {
1070 XMapWindow(ob_display
, self
->shade
);
1071 XMoveWindow(ob_display
, self
->shade
, self
->shade_x
,
1072 ob_rr_theme
->paddingy
+ 1);
1074 XUnmapWindow(ob_display
, self
->shade
);
1076 if (self
->iconify_on
) {
1077 XMapWindow(ob_display
, self
->iconify
);
1078 XMoveWindow(ob_display
, self
->iconify
, self
->iconify_x
,
1079 ob_rr_theme
->paddingy
+ 1);
1081 XUnmapWindow(ob_display
, self
->iconify
);
1084 XMapWindow(ob_display
, self
->max
);
1085 XMoveWindow(ob_display
, self
->max
, self
->max_x
,
1086 ob_rr_theme
->paddingy
+ 1);
1088 XUnmapWindow(ob_display
, self
->max
);
1090 if (self
->close_on
) {
1091 XMapWindow(ob_display
, self
->close
);
1092 XMoveWindow(ob_display
, self
->close
, self
->close_x
,
1093 ob_rr_theme
->paddingy
+ 1);
1095 XUnmapWindow(ob_display
, self
->close
);
1097 if (self
->label_on
) {
1098 self
->label_width
= MAX(1, self
->label_width
); /* no lower than 1 */
1099 XMapWindow(ob_display
, self
->label
);
1100 XMoveWindow(ob_display
, self
->label
, self
->label_x
,
1101 ob_rr_theme
->paddingy
);
1103 XUnmapWindow(ob_display
, self
->label
);
1106 ObFrameContext
frame_context_from_string(const gchar
*name
)
1108 if (!g_ascii_strcasecmp("Desktop", name
))
1109 return OB_FRAME_CONTEXT_DESKTOP
;
1110 else if (!g_ascii_strcasecmp("Root", name
))
1111 return OB_FRAME_CONTEXT_ROOT
;
1112 else if (!g_ascii_strcasecmp("Client", name
))
1113 return OB_FRAME_CONTEXT_CLIENT
;
1114 else if (!g_ascii_strcasecmp("Titlebar", name
))
1115 return OB_FRAME_CONTEXT_TITLEBAR
;
1116 else if (!g_ascii_strcasecmp("Frame", name
))
1117 return OB_FRAME_CONTEXT_FRAME
;
1118 else if (!g_ascii_strcasecmp("TLCorner", name
))
1119 return OB_FRAME_CONTEXT_TLCORNER
;
1120 else if (!g_ascii_strcasecmp("TRCorner", name
))
1121 return OB_FRAME_CONTEXT_TRCORNER
;
1122 else if (!g_ascii_strcasecmp("BLCorner", name
))
1123 return OB_FRAME_CONTEXT_BLCORNER
;
1124 else if (!g_ascii_strcasecmp("BRCorner", name
))
1125 return OB_FRAME_CONTEXT_BRCORNER
;
1126 else if (!g_ascii_strcasecmp("Top", name
))
1127 return OB_FRAME_CONTEXT_TOP
;
1128 else if (!g_ascii_strcasecmp("Bottom", name
))
1129 return OB_FRAME_CONTEXT_BOTTOM
;
1130 else if (!g_ascii_strcasecmp("Left", name
))
1131 return OB_FRAME_CONTEXT_LEFT
;
1132 else if (!g_ascii_strcasecmp("Right", name
))
1133 return OB_FRAME_CONTEXT_RIGHT
;
1134 else if (!g_ascii_strcasecmp("Maximize", name
))
1135 return OB_FRAME_CONTEXT_MAXIMIZE
;
1136 else if (!g_ascii_strcasecmp("AllDesktops", name
))
1137 return OB_FRAME_CONTEXT_ALLDESKTOPS
;
1138 else if (!g_ascii_strcasecmp("Shade", name
))
1139 return OB_FRAME_CONTEXT_SHADE
;
1140 else if (!g_ascii_strcasecmp("Iconify", name
))
1141 return OB_FRAME_CONTEXT_ICONIFY
;
1142 else if (!g_ascii_strcasecmp("Icon", name
))
1143 return OB_FRAME_CONTEXT_ICON
;
1144 else if (!g_ascii_strcasecmp("Close", name
))
1145 return OB_FRAME_CONTEXT_CLOSE
;
1146 else if (!g_ascii_strcasecmp("MoveResize", name
))
1147 return OB_FRAME_CONTEXT_MOVE_RESIZE
;
1148 return OB_FRAME_CONTEXT_NONE
;
1151 ObFrameContext
frame_context(ObClient
*client
, Window win
, gint x
, gint y
)
1155 if (moveresize_in_progress
)
1156 return OB_FRAME_CONTEXT_MOVE_RESIZE
;
1158 if (win
== RootWindow(ob_display
, ob_screen
))
1159 return OB_FRAME_CONTEXT_ROOT
;
1160 if (client
== NULL
) return OB_FRAME_CONTEXT_NONE
;
1161 if (win
== client
->window
) {
1162 /* conceptually, this is the desktop, as far as users are
1164 if (client
->type
== OB_CLIENT_TYPE_DESKTOP
)
1165 return OB_FRAME_CONTEXT_DESKTOP
;
1166 return OB_FRAME_CONTEXT_CLIENT
;
1169 self
= client
->frame
;
1170 if (win
== self
->inner
|| win
== self
->plate
) {
1171 /* conceptually, this is the desktop, as far as users are
1173 if (client
->type
== OB_CLIENT_TYPE_DESKTOP
)
1174 return OB_FRAME_CONTEXT_DESKTOP
;
1175 return OB_FRAME_CONTEXT_CLIENT
;
1178 if (win
== self
->title
) {
1179 /* when the user clicks in the corners of the titlebar and the client
1180 is fully maximized, then treat it like they clicked in the
1181 button that is there */
1182 if (self
->client
->max_horz
&& self
->client
->max_vert
&&
1183 y
< ob_rr_theme
->paddingy
+ 1 + ob_rr_theme
->button_size
)
1185 if (x
< ((ob_rr_theme
->paddingx
+ 1) * 2 +
1186 ob_rr_theme
->button_size
)) {
1187 if (self
->leftmost
!= OB_FRAME_CONTEXT_NONE
)
1188 return self
->leftmost
;
1190 else if (x
> (self
->width
-
1191 (ob_rr_theme
->paddingx
+ 1 +
1192 ob_rr_theme
->button_size
)))
1194 if (self
->rightmost
!= OB_FRAME_CONTEXT_NONE
)
1195 return self
->rightmost
;
1198 return OB_FRAME_CONTEXT_TITLEBAR
;
1201 if (win
== self
->window
) return OB_FRAME_CONTEXT_FRAME
;
1202 if (win
== self
->label
) return OB_FRAME_CONTEXT_TITLEBAR
;
1203 if (win
== self
->handle
) return OB_FRAME_CONTEXT_BOTTOM
;
1204 if (win
== self
->handletop
) return OB_FRAME_CONTEXT_BOTTOM
;
1205 if (win
== self
->handlebottom
) return OB_FRAME_CONTEXT_BOTTOM
;
1206 if (win
== self
->handleleft
) return OB_FRAME_CONTEXT_BLCORNER
;
1207 if (win
== self
->lgrip
) return OB_FRAME_CONTEXT_BLCORNER
;
1208 if (win
== self
->lgripleft
) return OB_FRAME_CONTEXT_BLCORNER
;
1209 if (win
== self
->lgriptop
) return OB_FRAME_CONTEXT_BLCORNER
;
1210 if (win
== self
->lgripbottom
) return OB_FRAME_CONTEXT_BLCORNER
;
1211 if (win
== self
->handleright
) return OB_FRAME_CONTEXT_BRCORNER
;
1212 if (win
== self
->rgrip
) return OB_FRAME_CONTEXT_BRCORNER
;
1213 if (win
== self
->rgripright
) return OB_FRAME_CONTEXT_BLCORNER
;
1214 if (win
== self
->rgriptop
) return OB_FRAME_CONTEXT_BLCORNER
;
1215 if (win
== self
->rgripbottom
) return OB_FRAME_CONTEXT_BLCORNER
;
1216 if (win
== self
->titletop
) return OB_FRAME_CONTEXT_TOP
;
1217 if (win
== self
->topresize
) return OB_FRAME_CONTEXT_TOP
;
1218 if (win
== self
->tltresize
) return OB_FRAME_CONTEXT_TLCORNER
;
1219 if (win
== self
->tllresize
) return OB_FRAME_CONTEXT_TLCORNER
;
1220 if (win
== self
->titleleft
) return OB_FRAME_CONTEXT_TLCORNER
;
1221 if (win
== self
->titletopleft
) return OB_FRAME_CONTEXT_TLCORNER
;
1222 if (win
== self
->trtresize
) return OB_FRAME_CONTEXT_TRCORNER
;
1223 if (win
== self
->trrresize
) return OB_FRAME_CONTEXT_TRCORNER
;
1224 if (win
== self
->titleright
) return OB_FRAME_CONTEXT_TRCORNER
;
1225 if (win
== self
->titletopright
) return OB_FRAME_CONTEXT_TRCORNER
;
1226 if (win
== self
->left
) return OB_FRAME_CONTEXT_LEFT
;
1227 if (win
== self
->right
) return OB_FRAME_CONTEXT_RIGHT
;
1228 if (win
== self
->max
) return OB_FRAME_CONTEXT_MAXIMIZE
;
1229 if (win
== self
->iconify
) return OB_FRAME_CONTEXT_ICONIFY
;
1230 if (win
== self
->close
) return OB_FRAME_CONTEXT_CLOSE
;
1231 if (win
== self
->icon
) return OB_FRAME_CONTEXT_ICON
;
1232 if (win
== self
->desk
) return OB_FRAME_CONTEXT_ALLDESKTOPS
;
1233 if (win
== self
->shade
) return OB_FRAME_CONTEXT_SHADE
;
1235 return OB_FRAME_CONTEXT_NONE
;
1238 void frame_client_gravity(ObFrame
*self
, gint
*x
, gint
*y
, gint w
, gint h
)
1241 switch (self
->client
->gravity
) {
1243 case NorthWestGravity
:
1244 case SouthWestGravity
:
1251 *x
-= (self
->size
.left
+ w
) / 2;
1254 case NorthEastGravity
:
1255 case SouthEastGravity
:
1257 *x
-= (self
->size
.left
+ self
->size
.right
+ w
) - 1;
1262 *x
-= self
->size
.left
;
1267 switch (self
->client
->gravity
) {
1269 case NorthWestGravity
:
1270 case NorthEastGravity
:
1277 *y
-= (self
->size
.top
+ h
) / 2;
1280 case SouthWestGravity
:
1281 case SouthEastGravity
:
1283 *y
-= (self
->size
.top
+ self
->size
.bottom
+ h
) - 1;
1288 *y
-= self
->size
.top
;
1293 void frame_frame_gravity(ObFrame
*self
, gint
*x
, gint
*y
, gint w
, gint h
)
1296 switch (self
->client
->gravity
) {
1298 case NorthWestGravity
:
1300 case SouthWestGravity
:
1305 *x
+= (self
->size
.left
+ w
) / 2;
1307 case NorthEastGravity
:
1309 case SouthEastGravity
:
1310 *x
+= (self
->size
.left
+ self
->size
.right
+ w
) - 1;
1314 *x
+= self
->size
.left
;
1319 switch (self
->client
->gravity
) {
1321 case NorthWestGravity
:
1323 case NorthEastGravity
:
1328 *y
+= (self
->size
.top
+ h
) / 2;
1330 case SouthWestGravity
:
1332 case SouthEastGravity
:
1333 *y
+= (self
->size
.top
+ self
->size
.bottom
+ h
) - 1;
1337 *y
+= self
->size
.top
;
1342 static void flash_done(gpointer data
)
1344 ObFrame
*self
= data
;
1346 if (self
->focused
!= self
->flash_on
)
1347 frame_adjust_focus(self
, self
->focused
);
1350 static gboolean
flash_timeout(gpointer data
)
1352 ObFrame
*self
= data
;
1355 g_get_current_time(&now
);
1356 if (now
.tv_sec
> self
->flash_end
.tv_sec
||
1357 (now
.tv_sec
== self
->flash_end
.tv_sec
&&
1358 now
.tv_usec
>= self
->flash_end
.tv_usec
))
1359 self
->flashing
= FALSE
;
1361 if (!self
->flashing
)
1362 return FALSE
; /* we are done */
1364 self
->flash_on
= !self
->flash_on
;
1365 if (!self
->focused
) {
1366 frame_adjust_focus(self
, self
->flash_on
);
1367 self
->focused
= FALSE
;
1370 return TRUE
; /* go again */
1373 void frame_flash_start(ObFrame
*self
)
1375 self
->flash_on
= self
->focused
;
1377 if (!self
->flashing
)
1378 ob_main_loop_timeout_add(ob_main_loop
,
1379 G_USEC_PER_SEC
* 0.6,
1384 g_get_current_time(&self
->flash_end
);
1385 g_time_val_add(&self
->flash_end
, G_USEC_PER_SEC
* 5);
1387 self
->flashing
= TRUE
;
1390 void frame_flash_stop(ObFrame
*self
)
1392 self
->flashing
= FALSE
;
1395 static gulong
frame_animate_iconify_time_left(ObFrame
*self
,
1396 const GTimeVal
*now
)
1399 sec
= self
->iconify_animation_end
.tv_sec
- now
->tv_sec
;
1400 usec
= self
->iconify_animation_end
.tv_usec
- now
->tv_usec
;
1402 usec
+= G_USEC_PER_SEC
;
1405 /* no negative values */
1406 return MAX(sec
* G_USEC_PER_SEC
+ usec
, 0);
1409 static gboolean
frame_animate_iconify(gpointer p
)
1413 gint iconx
, icony
, iconw
;
1416 gboolean iconifying
;
1418 if (self
->client
->icon_geometry
.width
== 0) {
1419 /* there is no icon geometry set so just go straight down */
1420 Rect
*a
= screen_physical_area();
1421 iconx
= self
->area
.x
+ self
->area
.width
/ 2 + 32;
1422 icony
= a
->y
+ a
->width
;
1425 iconx
= self
->client
->icon_geometry
.x
;
1426 icony
= self
->client
->icon_geometry
.y
;
1427 iconw
= self
->client
->icon_geometry
.width
;
1430 iconifying
= self
->iconify_animation_going
> 0;
1432 /* how far do we have left to go ? */
1433 g_get_current_time(&now
);
1434 time
= frame_animate_iconify_time_left(self
, &now
);
1436 if (time
== 0 || iconifying
) {
1437 /* start where the frame is supposed to be */
1440 w
= self
->area
.width
- self
->bwidth
* 2;
1441 h
= self
->area
.height
- self
->bwidth
* 2;
1443 /* start at the icon */
1447 h
= self
->size
.top
; /* just the titlebar */
1454 dx
= self
->area
.x
- iconx
;
1455 dy
= self
->area
.y
- icony
;
1456 dw
= self
->area
.width
- self
->bwidth
* 2 - iconw
;
1457 /* if restoring, we move in the opposite direction */
1458 if (!iconifying
) { dx
= -dx
; dy
= -dy
; dw
= -dw
; }
1460 elapsed
= FRAME_ANIMATE_ICONIFY_TIME
- time
;
1461 x
= x
- (dx
* elapsed
) / FRAME_ANIMATE_ICONIFY_TIME
;
1462 y
= y
- (dy
* elapsed
) / FRAME_ANIMATE_ICONIFY_TIME
;
1463 w
= w
- (dw
* elapsed
) / FRAME_ANIMATE_ICONIFY_TIME
;
1464 h
= self
->size
.top
; /* just the titlebar */
1468 frame_end_iconify_animation(self
);
1470 XMoveResizeWindow(ob_display
, self
->window
, x
, y
, w
, h
);
1474 return time
> 0; /* repeat until we're out of time */
1477 void frame_end_iconify_animation(ObFrame
*self
)
1479 /* see if there is an animation going */
1480 if (self
->iconify_animation_going
== 0) return;
1483 XUnmapWindow(ob_display
, self
->window
);
1485 /* Send a ConfigureNotify when the animation is done, this fixes
1486 KDE's pager showing the window in the wrong place. */
1487 client_reconfigure(self
->client
);
1489 /* we're not animating any more ! */
1490 self
->iconify_animation_going
= 0;
1492 XMoveResizeWindow(ob_display
, self
->window
,
1493 self
->area
.x
, self
->area
.y
,
1494 self
->area
.width
- self
->bwidth
* 2,
1495 self
->area
.height
- self
->bwidth
* 2);
1499 void frame_begin_iconify_animation(ObFrame
*self
, gboolean iconifying
)
1502 gboolean new_anim
= FALSE
;
1503 gboolean set_end
= TRUE
;
1506 /* if there is no titlebar, just don't animate for now
1507 XXX it would be nice tho.. */
1508 if (!(self
->decorations
& OB_FRAME_DECOR_TITLEBAR
))
1511 /* get the current time */
1512 g_get_current_time(&now
);
1514 /* get how long until the end */
1515 time
= FRAME_ANIMATE_ICONIFY_TIME
;
1516 if (self
->iconify_animation_going
) {
1517 if (!!iconifying
!= (self
->iconify_animation_going
> 0)) {
1518 /* animation was already going on in the opposite direction */
1519 time
= time
- frame_animate_iconify_time_left(self
, &now
);
1521 /* animation was already going in the same direction */
1525 self
->iconify_animation_going
= iconifying
? 1 : -1;
1527 /* set the ending time */
1529 self
->iconify_animation_end
.tv_sec
= now
.tv_sec
;
1530 self
->iconify_animation_end
.tv_usec
= now
.tv_usec
;
1531 g_time_val_add(&self
->iconify_animation_end
, time
);
1535 ob_main_loop_timeout_remove_data(ob_main_loop
, frame_animate_iconify
,
1537 ob_main_loop_timeout_add(ob_main_loop
,
1538 FRAME_ANIMATE_ICONIFY_STEP_TIME
,
1539 frame_animate_iconify
, self
,
1540 g_direct_equal
, NULL
);
1542 /* do the first step */
1543 frame_animate_iconify(self
);
1545 /* show it during the animation even if it is not "visible" */
1547 XMapWindow(ob_display
, self
->window
);