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 FRAME_EVENTMASK (EnterWindowMask | LeaveWindowMask | \
35 ButtonPressMask | ButtonReleaseMask | \
36 SubstructureRedirectMask | FocusChangeMask)
37 #define ELEMENT_EVENTMASK (ButtonPressMask | ButtonReleaseMask | \
38 ButtonMotionMask | PointerMotionMask | \
39 EnterWindowMask | LeaveWindowMask)
41 #define FRAME_ANIMATE_ICONIFY_TIME 150000 /* .15 seconds */
42 #define FRAME_ANIMATE_ICONIFY_STEP_TIME (G_USEC_PER_SEC / 60) /* 60 Hz */
44 #define FRAME_HANDLE_Y(f) (f->size.top + f->client->area.height + f->cbwidth_y)
46 static void flash_done(gpointer data
);
47 static gboolean
flash_timeout(gpointer data
);
49 static void layout_title(ObFrame
*self
);
50 static void set_theme_statics(ObFrame
*self
);
51 static void free_theme_statics(ObFrame
*self
);
52 static gboolean
frame_animate_iconify(gpointer self
);
53 static void frame_adjust_cursors(ObFrame
*self
);
55 static Window
createWindow(Window parent
, Visual
*visual
,
56 gulong mask
, XSetWindowAttributes
*attrib
)
58 return XCreateWindow(ob_display
, parent
, 0, 0, 1, 1, 0,
59 (visual
? 32 : RrDepth(ob_rr_inst
)), InputOutput
,
60 (visual
? visual
: RrVisual(ob_rr_inst
)),
65 static Visual
*check_32bit_client(ObClient
*c
)
67 XWindowAttributes wattrib
;
70 /* we're already running at 32 bit depth, yay. we don't need to use their
72 if (RrDepth(ob_rr_inst
) == 32)
75 ret
= XGetWindowAttributes(ob_display
, c
->window
, &wattrib
);
76 g_assert(ret
!= BadDrawable
);
77 g_assert(ret
!= BadWindow
);
79 if (wattrib
.depth
== 32)
80 return wattrib
.visual
;
84 ObFrame
*frame_new(ObClient
*client
)
86 XSetWindowAttributes attrib
;
91 self
= g_new0(ObFrame
, 1);
92 self
->client
= client
;
94 visual
= check_32bit_client(client
);
96 /* create the non-visible decor windows */
100 /* client has a 32-bit visual */
101 mask
|= CWColormap
| CWBackPixel
| CWBorderPixel
;
102 /* create a colormap with the visual */
103 self
->colormap
= attrib
.colormap
=
104 XCreateColormap(ob_display
,
105 RootWindow(ob_display
, ob_screen
),
107 attrib
.background_pixel
= BlackPixel(ob_display
, ob_screen
);
108 attrib
.border_pixel
= BlackPixel(ob_display
, ob_screen
);
110 self
->window
= createWindow(RootWindow(ob_display
, ob_screen
), visual
,
113 /* create the visible decor windows */
117 /* client has a 32-bit visual */
118 mask
|= CWColormap
| CWBackPixel
| CWBorderPixel
;
119 attrib
.colormap
= RrColormap(ob_rr_inst
);
121 attrib
.event_mask
= ELEMENT_EVENTMASK
;
122 self
->title
= createWindow(self
->window
, NULL
, mask
, &attrib
);
123 self
->titleleft
= createWindow(self
->window
, NULL
, mask
, &attrib
);
124 self
->titletop
= createWindow(self
->window
, NULL
, mask
, &attrib
);
125 self
->titletopleft
= createWindow(self
->window
, NULL
, mask
, &attrib
);
126 self
->titletopright
= createWindow(self
->window
, NULL
, mask
, &attrib
);
127 self
->titleright
= createWindow(self
->window
, NULL
, mask
, &attrib
);
128 self
->titlebottom
= createWindow(self
->window
, NULL
, mask
, &attrib
);
130 self
->topresize
= createWindow(self
->title
, NULL
, mask
, &attrib
);
131 self
->tltresize
= createWindow(self
->title
, NULL
, mask
, &attrib
);
132 self
->tllresize
= createWindow(self
->title
, NULL
, mask
, &attrib
);
133 self
->trtresize
= createWindow(self
->title
, NULL
, mask
, &attrib
);
134 self
->trrresize
= createWindow(self
->title
, NULL
, mask
, &attrib
);
136 self
->left
= createWindow(self
->window
, NULL
, mask
, &attrib
);
137 self
->right
= createWindow(self
->window
, NULL
, mask
, &attrib
);
139 self
->innerleft
= createWindow(self
->window
, NULL
, mask
, &attrib
);
140 self
->innertop
= createWindow(self
->window
, NULL
, mask
, &attrib
);
141 self
->innerright
= createWindow(self
->window
, NULL
, mask
, &attrib
);
142 self
->innerbottom
= createWindow(self
->window
, NULL
, mask
, &attrib
);
144 self
->label
= createWindow(self
->title
, NULL
, mask
, &attrib
);
145 self
->max
= createWindow(self
->title
, NULL
, mask
, &attrib
);
146 self
->close
= createWindow(self
->title
, NULL
, mask
, &attrib
);
147 self
->desk
= createWindow(self
->title
, NULL
, mask
, &attrib
);
148 self
->shade
= createWindow(self
->title
, NULL
, mask
, &attrib
);
149 self
->icon
= createWindow(self
->title
, NULL
, mask
, &attrib
);
150 self
->iconify
= createWindow(self
->title
, NULL
, mask
, &attrib
);
152 self
->handle
= createWindow(self
->window
, NULL
, mask
, &attrib
);
153 self
->lgrip
= createWindow(self
->handle
, NULL
, mask
, &attrib
);
154 self
->rgrip
= createWindow(self
->handle
, NULL
, mask
, &attrib
);
156 self
->handleleft
= createWindow(self
->handle
, NULL
, mask
, &attrib
);
157 self
->handleright
= createWindow(self
->handle
, NULL
, mask
, &attrib
);
159 self
->handletop
= createWindow(self
->window
, NULL
, mask
, &attrib
);
160 self
->handlebottom
= createWindow(self
->window
, NULL
, mask
, &attrib
);
161 self
->lgripleft
= createWindow(self
->window
, NULL
, mask
, &attrib
);
162 self
->lgriptop
= createWindow(self
->window
, NULL
, mask
, &attrib
);
163 self
->lgripbottom
= createWindow(self
->window
, NULL
, mask
, &attrib
);
164 self
->rgripright
= createWindow(self
->window
, NULL
, mask
, &attrib
);
165 self
->rgriptop
= createWindow(self
->window
, NULL
, mask
, &attrib
);
166 self
->rgripbottom
= createWindow(self
->window
, NULL
, mask
, &attrib
);
168 self
->focused
= FALSE
;
170 /* the other stuff is shown based on decor settings */
171 XMapWindow(ob_display
, self
->label
);
173 self
->max_press
= self
->close_press
= self
->desk_press
=
174 self
->iconify_press
= self
->shade_press
= FALSE
;
175 self
->max_hover
= self
->close_hover
= self
->desk_hover
=
176 self
->iconify_hover
= self
->shade_hover
= FALSE
;
178 set_theme_statics(self
);
180 return (ObFrame
*)self
;
183 static void set_theme_statics(ObFrame
*self
)
185 /* set colors/appearance/sizes for stuff that doesn't change */
186 XResizeWindow(ob_display
, self
->max
,
187 ob_rr_theme
->button_size
, ob_rr_theme
->button_size
);
188 XResizeWindow(ob_display
, self
->iconify
,
189 ob_rr_theme
->button_size
, ob_rr_theme
->button_size
);
190 XResizeWindow(ob_display
, self
->icon
,
191 ob_rr_theme
->button_size
+ 2, ob_rr_theme
->button_size
+ 2);
192 XResizeWindow(ob_display
, self
->close
,
193 ob_rr_theme
->button_size
, ob_rr_theme
->button_size
);
194 XResizeWindow(ob_display
, self
->desk
,
195 ob_rr_theme
->button_size
, ob_rr_theme
->button_size
);
196 XResizeWindow(ob_display
, self
->shade
,
197 ob_rr_theme
->button_size
, ob_rr_theme
->button_size
);
198 XResizeWindow(ob_display
, self
->tltresize
,
199 ob_rr_theme
->grip_width
, ob_rr_theme
->paddingy
+ 1);
200 XResizeWindow(ob_display
, self
->trtresize
,
201 ob_rr_theme
->grip_width
, ob_rr_theme
->paddingy
+ 1);
202 XResizeWindow(ob_display
, self
->tllresize
,
203 ob_rr_theme
->paddingx
+ 1, ob_rr_theme
->title_height
);
204 XResizeWindow(ob_display
, self
->trrresize
,
205 ob_rr_theme
->paddingx
+ 1, ob_rr_theme
->title_height
);
207 /* set up the dynamic appearances */
208 self
->a_unfocused_title
= RrAppearanceCopy(ob_rr_theme
->a_unfocused_title
);
209 self
->a_focused_title
= RrAppearanceCopy(ob_rr_theme
->a_focused_title
);
210 self
->a_unfocused_label
= RrAppearanceCopy(ob_rr_theme
->a_unfocused_label
);
211 self
->a_focused_label
= RrAppearanceCopy(ob_rr_theme
->a_focused_label
);
212 self
->a_unfocused_handle
=
213 RrAppearanceCopy(ob_rr_theme
->a_unfocused_handle
);
214 self
->a_focused_handle
= RrAppearanceCopy(ob_rr_theme
->a_focused_handle
);
215 self
->a_icon
= RrAppearanceCopy(ob_rr_theme
->a_icon
);
218 static void free_theme_statics(ObFrame
*self
)
220 RrAppearanceFree(self
->a_unfocused_title
);
221 RrAppearanceFree(self
->a_focused_title
);
222 RrAppearanceFree(self
->a_unfocused_label
);
223 RrAppearanceFree(self
->a_focused_label
);
224 RrAppearanceFree(self
->a_unfocused_handle
);
225 RrAppearanceFree(self
->a_focused_handle
);
226 RrAppearanceFree(self
->a_icon
);
229 void frame_free(ObFrame
*self
)
231 free_theme_statics(self
);
233 XDestroyWindow(ob_display
, self
->window
);
235 XFreeColormap(ob_display
, self
->colormap
);
240 void frame_show(ObFrame
*self
)
242 if (!self
->visible
) {
243 self
->visible
= TRUE
;
244 XMapWindow(ob_display
, self
->client
->window
);
245 XMapWindow(ob_display
, self
->window
);
249 void frame_hide(ObFrame
*self
)
252 self
->visible
= FALSE
;
253 if (!frame_iconify_animating(self
))
254 XUnmapWindow(ob_display
, self
->window
);
255 /* we unmap the client itself so that we can get MapRequest
256 events, and because the ICCCM tells us to! */
257 XUnmapWindow(ob_display
, self
->client
->window
);
258 self
->client
->ignore_unmaps
+= 1;
262 void frame_adjust_theme(ObFrame
*self
)
264 free_theme_statics(self
);
265 set_theme_statics(self
);
268 void frame_adjust_shape(ObFrame
*self
)
274 if (!self
->client
->shaped
) {
275 /* clear the shape on the frame window */
276 XShapeCombineMask(ob_display
, self
->window
, ShapeBounding
,
281 /* make the frame's shape match the clients */
282 XShapeCombineShape(ob_display
, self
->window
, ShapeBounding
,
285 self
->client
->window
,
286 ShapeBounding
, ShapeSet
);
289 if (self
->decorations
& OB_FRAME_DECOR_TITLEBAR
) {
292 xrect
[0].width
= self
->area
.width
;
293 xrect
[0].height
= ob_rr_theme
->title_height
+
294 self
->bwidth
+ self
->rbwidth
;
298 if (self
->decorations
& OB_FRAME_DECOR_HANDLE
&&
299 ob_rr_theme
->handle_height
> 0)
302 xrect
[1].y
= FRAME_HANDLE_Y(self
);
303 xrect
[1].width
= self
->area
.width
;
304 xrect
[1].height
= ob_rr_theme
->handle_height
+
309 XShapeCombineRectangles(ob_display
, self
->window
,
310 ShapeBounding
, 0, 0, xrect
, num
,
311 ShapeUnion
, Unsorted
);
316 void frame_adjust_area(ObFrame
*self
, gboolean moved
,
317 gboolean resized
, gboolean fake
)
321 oldsize
= self
->size
;
324 /* do this before changing the frame's status like max_horz max_vert */
325 frame_adjust_cursors(self
);
327 self
->functions
= self
->client
->functions
;
328 self
->decorations
= self
->client
->decorations
;
329 self
->max_horz
= self
->client
->max_horz
;
330 self
->max_vert
= self
->client
->max_vert
;
332 if (self
->decorations
& OB_FRAME_DECOR_BORDER
) {
333 self
->bwidth
= ob_rr_theme
->fbwidth
;
334 self
->cbwidth_x
= ob_rr_theme
->cbwidthx
;
335 self
->cbwidth_y
= ob_rr_theme
->cbwidthy
;
337 self
->bwidth
= self
->cbwidth_x
= self
->cbwidth_y
= 0;
339 self
->rbwidth
= self
->bwidth
;
341 if (self
->max_horz
) {
343 self
->width
= self
->client
->area
.width
- self
->bwidth
* 2;
345 self
->width
= self
->client
->area
.width
+ self
->cbwidth_x
* 2;
347 /* some elements are sized based of the width, so don't let them have
349 self
->width
= MAX(self
->width
,
350 (ob_rr_theme
->grip_width
+ self
->bwidth
) * 2 + 1);
352 STRUT_SET(self
->size
,
353 self
->cbwidth_x
+ (!self
->max_horz
? self
->bwidth
: 0),
354 self
->cbwidth_y
+ self
->bwidth
,
355 self
->cbwidth_x
+ (!self
->max_horz
? self
->bwidth
: 0),
356 self
->cbwidth_y
+ self
->bwidth
);
358 if (self
->decorations
& OB_FRAME_DECOR_TITLEBAR
)
359 self
->size
.top
+= ob_rr_theme
->title_height
+ self
->rbwidth
;
360 if (self
->decorations
& OB_FRAME_DECOR_HANDLE
&&
361 ob_rr_theme
->handle_height
> 0)
363 self
->size
.bottom
+= ob_rr_theme
->handle_height
+ self
->bwidth
;
366 /* position/size and map/unmap all the windows */
369 if (self
->cbwidth_x
) {
370 XMoveResizeWindow(ob_display
, self
->innerleft
,
371 self
->size
.left
- self
->cbwidth_x
,
373 self
->cbwidth_x
, self
->client
->area
.height
);
374 XMoveResizeWindow(ob_display
, self
->innerright
,
375 self
->size
.left
+ self
->client
->area
.width
,
377 self
->cbwidth_x
, self
->client
->area
.height
);
379 XMapWindow(ob_display
, self
->innerleft
);
380 XMapWindow(ob_display
, self
->innerright
);
382 XUnmapWindow(ob_display
, self
->innerleft
);
383 XUnmapWindow(ob_display
, self
->innerright
);
386 if (self
->cbwidth_y
) {
387 XMoveResizeWindow(ob_display
, self
->innertop
,
388 self
->size
.left
- self
->cbwidth_x
,
389 self
->size
.top
- self
->cbwidth_y
,
390 self
->client
->area
.width
+
391 self
->cbwidth_x
* 2, self
->cbwidth_y
);
392 XMoveResizeWindow(ob_display
, self
->innerbottom
,
393 self
->size
.left
- self
->cbwidth_x
,
394 self
->size
.top
+ self
->client
->area
.height
,
395 self
->client
->area
.width
+
396 self
->cbwidth_x
* 2, self
->cbwidth_y
);
398 XMapWindow(ob_display
, self
->innertop
);
399 XMapWindow(ob_display
, self
->innerbottom
);
401 XUnmapWindow(ob_display
, self
->innertop
);
402 XUnmapWindow(ob_display
, self
->innerbottom
);
408 /* height of titleleft and titleright */
409 titlesides
= (!self
->max_horz
?
410 ob_rr_theme
->grip_width
:
411 self
->size
.top
- self
->bwidth
);
413 XMoveResizeWindow(ob_display
, self
->titletop
,
414 ob_rr_theme
->grip_width
+ self
->bwidth
, 0,
415 /* width + bwidth*2 - bwidth*2 - grips*2 */
416 self
->width
- ob_rr_theme
->grip_width
* 2,
418 XMoveResizeWindow(ob_display
, self
->titletopleft
,
420 ob_rr_theme
->grip_width
+ self
->bwidth
,
422 XMoveResizeWindow(ob_display
, self
->titletopright
,
423 self
->client
->area
.width
+
424 self
->size
.left
+ self
->size
.right
-
425 ob_rr_theme
->grip_width
- self
->bwidth
,
427 ob_rr_theme
->grip_width
+ self
->bwidth
,
430 if (titlesides
> 0) {
431 XMoveResizeWindow(ob_display
, self
->titleleft
,
435 XMoveResizeWindow(ob_display
, self
->titleright
,
436 self
->client
->area
.width
+
437 self
->size
.left
+ self
->size
.right
-
443 XMapWindow(ob_display
, self
->titleleft
);
444 XMapWindow(ob_display
, self
->titleright
);
446 XUnmapWindow(ob_display
, self
->titleleft
);
447 XUnmapWindow(ob_display
, self
->titleright
);
450 XMapWindow(ob_display
, self
->titletop
);
451 XMapWindow(ob_display
, self
->titletopleft
);
452 XMapWindow(ob_display
, self
->titletopright
);
454 if (self
->decorations
& OB_FRAME_DECOR_TITLEBAR
&&
457 XMoveResizeWindow(ob_display
, self
->titlebottom
,
459 ob_rr_theme
->title_height
+ self
->bwidth
,
463 XMapWindow(ob_display
, self
->titlebottom
);
465 XUnmapWindow(ob_display
, self
->titlebottom
);
467 XUnmapWindow(ob_display
, self
->titlebottom
);
469 XUnmapWindow(ob_display
, self
->titletop
);
470 XUnmapWindow(ob_display
, self
->titletopleft
);
471 XUnmapWindow(ob_display
, self
->titletopright
);
472 XUnmapWindow(ob_display
, self
->titleleft
);
473 XUnmapWindow(ob_display
, self
->titleright
);
476 if (self
->decorations
& OB_FRAME_DECOR_TITLEBAR
) {
477 XMoveResizeWindow(ob_display
, self
->title
,
478 self
->bwidth
, self
->bwidth
,
479 self
->width
, ob_rr_theme
->title_height
);
481 XMapWindow(ob_display
, self
->title
);
483 if (self
->decorations
& OB_FRAME_DECOR_GRIPS
) {
484 XMoveResizeWindow(ob_display
, self
->topresize
,
485 ob_rr_theme
->grip_width
,
487 self
->width
- ob_rr_theme
->grip_width
*2,
488 ob_rr_theme
->paddingy
+ 1);
490 XMoveWindow(ob_display
, self
->tltresize
, 0, 0);
491 XMoveWindow(ob_display
, self
->tllresize
, 0, 0);
492 XMoveWindow(ob_display
, self
->trtresize
,
493 self
->width
- ob_rr_theme
->grip_width
, 0);
494 XMoveWindow(ob_display
, self
->trrresize
,
495 self
->width
- ob_rr_theme
->paddingx
- 1, 0);
497 XMapWindow(ob_display
, self
->topresize
);
498 XMapWindow(ob_display
, self
->tltresize
);
499 XMapWindow(ob_display
, self
->tllresize
);
500 XMapWindow(ob_display
, self
->trtresize
);
501 XMapWindow(ob_display
, self
->trrresize
);
503 XUnmapWindow(ob_display
, self
->topresize
);
504 XUnmapWindow(ob_display
, self
->tltresize
);
505 XUnmapWindow(ob_display
, self
->tllresize
);
506 XUnmapWindow(ob_display
, self
->trtresize
);
507 XUnmapWindow(ob_display
, self
->trrresize
);
510 XUnmapWindow(ob_display
, self
->title
);
513 if ((self
->decorations
& OB_FRAME_DECOR_TITLEBAR
))
514 /* layout the title bar elements */
519 XMoveResizeWindow(ob_display
, self
->handlebottom
,
520 ob_rr_theme
->grip_width
+
522 self
->size
.top
+ self
->client
->area
.height
+
523 self
->size
.bottom
- self
->bwidth
,
524 self
->width
- (ob_rr_theme
->grip_width
+
528 XMoveResizeWindow(ob_display
, self
->lgripleft
,
530 self
->size
.top
+ self
->client
->area
.height
+
533 ob_rr_theme
->grip_width
:
537 ob_rr_theme
->grip_width
:
539 XMoveResizeWindow(ob_display
, self
->rgripright
,
540 self
->size
.left
+ self
->client
->area
.width
+
541 self
->size
.right
- self
->bwidth
,
542 self
->size
.top
+ self
->client
->area
.height
+
545 ob_rr_theme
->grip_width
:
549 ob_rr_theme
->grip_width
:
552 XMoveResizeWindow(ob_display
, self
->lgripbottom
,
554 self
->size
.top
+ self
->client
->area
.height
+
555 self
->size
.bottom
- self
->bwidth
,
556 ob_rr_theme
->grip_width
+ self
->bwidth
,
558 XMoveResizeWindow(ob_display
, self
->rgripbottom
,
559 self
->size
.left
+ self
->client
->area
.width
+
560 self
->size
.right
- self
->bwidth
* 2 -
561 ob_rr_theme
->grip_width
,
562 self
->size
.top
+ self
->client
->area
.height
+
563 self
->size
.bottom
- self
->bwidth
,
564 ob_rr_theme
->grip_width
+ self
->bwidth
,
567 XMapWindow(ob_display
, self
->handlebottom
);
568 XMapWindow(ob_display
, self
->lgripleft
);
569 XMapWindow(ob_display
, self
->rgripright
);
570 XMapWindow(ob_display
, self
->lgripbottom
);
571 XMapWindow(ob_display
, self
->rgripbottom
);
573 if (self
->decorations
& OB_FRAME_DECOR_HANDLE
&&
574 ob_rr_theme
->handle_height
> 0)
576 XMoveResizeWindow(ob_display
, self
->handletop
,
577 ob_rr_theme
->grip_width
+
579 FRAME_HANDLE_Y(self
),
580 self
->width
- (ob_rr_theme
->grip_width
+
583 XMapWindow(ob_display
, self
->handletop
);
585 if (self
->decorations
& OB_FRAME_DECOR_GRIPS
) {
586 XMoveResizeWindow(ob_display
, self
->handleleft
,
587 ob_rr_theme
->grip_width
,
590 ob_rr_theme
->handle_height
);
591 XMoveResizeWindow(ob_display
, self
->handleright
,
593 ob_rr_theme
->grip_width
-
597 ob_rr_theme
->handle_height
);
599 XMoveResizeWindow(ob_display
, self
->lgriptop
,
601 FRAME_HANDLE_Y(self
),
602 ob_rr_theme
->grip_width
+
605 XMoveResizeWindow(ob_display
, self
->rgriptop
,
607 self
->client
->area
.width
+
608 self
->size
.right
- self
->bwidth
* 2 -
609 ob_rr_theme
->grip_width
,
610 FRAME_HANDLE_Y(self
),
611 ob_rr_theme
->grip_width
+
615 XMapWindow(ob_display
, self
->handleleft
);
616 XMapWindow(ob_display
, self
->handleright
);
617 XMapWindow(ob_display
, self
->lgriptop
);
618 XMapWindow(ob_display
, self
->rgriptop
);
620 XUnmapWindow(ob_display
, self
->handleleft
);
621 XUnmapWindow(ob_display
, self
->handleright
);
622 XUnmapWindow(ob_display
, self
->lgriptop
);
623 XUnmapWindow(ob_display
, self
->rgriptop
);
626 XUnmapWindow(ob_display
, self
->handleleft
);
627 XUnmapWindow(ob_display
, self
->handleright
);
628 XUnmapWindow(ob_display
, self
->lgriptop
);
629 XUnmapWindow(ob_display
, self
->rgriptop
);
631 XUnmapWindow(ob_display
, self
->handletop
);
634 XUnmapWindow(ob_display
, self
->handleleft
);
635 XUnmapWindow(ob_display
, self
->handleright
);
636 XUnmapWindow(ob_display
, self
->lgriptop
);
637 XUnmapWindow(ob_display
, self
->rgriptop
);
639 XUnmapWindow(ob_display
, self
->handletop
);
641 XUnmapWindow(ob_display
, self
->handlebottom
);
642 XUnmapWindow(ob_display
, self
->lgripleft
);
643 XUnmapWindow(ob_display
, self
->rgripright
);
644 XUnmapWindow(ob_display
, self
->lgripbottom
);
645 XUnmapWindow(ob_display
, self
->rgripbottom
);
648 if (self
->decorations
& OB_FRAME_DECOR_HANDLE
&&
649 ob_rr_theme
->handle_height
> 0)
651 XMoveResizeWindow(ob_display
, self
->handle
,
653 FRAME_HANDLE_Y(self
) + self
->bwidth
,
654 self
->width
, ob_rr_theme
->handle_height
);
655 XMapWindow(ob_display
, self
->handle
);
657 if (self
->decorations
& OB_FRAME_DECOR_GRIPS
) {
658 XMoveResizeWindow(ob_display
, self
->lgrip
,
660 ob_rr_theme
->grip_width
,
661 ob_rr_theme
->handle_height
);
662 XMoveResizeWindow(ob_display
, self
->rgrip
,
663 self
->width
- ob_rr_theme
->grip_width
,
665 ob_rr_theme
->grip_width
,
666 ob_rr_theme
->handle_height
);
668 XMapWindow(ob_display
, self
->lgrip
);
669 XMapWindow(ob_display
, self
->rgrip
);
671 XUnmapWindow(ob_display
, self
->lgrip
);
672 XUnmapWindow(ob_display
, self
->rgrip
);
675 XUnmapWindow(ob_display
, self
->lgrip
);
676 XUnmapWindow(ob_display
, self
->rgrip
);
678 XUnmapWindow(ob_display
, self
->handle
);
681 if (self
->bwidth
&& !self
->max_horz
) {
682 XMoveResizeWindow(ob_display
, self
->left
,
684 self
->bwidth
+ ob_rr_theme
->grip_width
,
686 self
->client
->area
.height
+
687 self
->size
.top
+ self
->size
.bottom
-
688 ob_rr_theme
->grip_width
* 2);
690 XMapWindow(ob_display
, self
->left
);
692 XUnmapWindow(ob_display
, self
->left
);
694 if (self
->bwidth
&& !self
->max_horz
) {
695 XMoveResizeWindow(ob_display
, self
->right
,
696 self
->client
->area
.width
+
697 self
->cbwidth_x
* 2 + self
->bwidth
,
698 self
->bwidth
+ ob_rr_theme
->grip_width
,
700 self
->client
->area
.height
+
701 self
->size
.top
+ self
->size
.bottom
-
702 ob_rr_theme
->grip_width
* 2);
704 XMapWindow(ob_display
, self
->right
);
706 XUnmapWindow(ob_display
, self
->right
);
708 /* when the client has StaticGravity, it likes to move around. */
709 XMoveWindow(ob_display
, self
->client
->window
,
710 self
->size
.left
- self
->client
->border_width
,
711 self
->size
.top
- self
->client
->border_width
);
715 /* shading can change without being moved or resized */
716 RECT_SET_SIZE(self
->area
,
717 self
->client
->area
.width
+
718 self
->size
.left
+ self
->size
.right
,
719 (self
->client
->shaded
?
720 ob_rr_theme
->title_height
+ self
->bwidth
* 2:
721 self
->client
->area
.height
+
722 self
->size
.top
+ self
->size
.bottom
));
724 if ((moved
|| resized
) && !fake
) {
725 /* find the new coordinates, done after setting the frame.size, for
726 frame_client_gravity. */
727 self
->area
.x
= self
->client
->area
.x
;
728 self
->area
.y
= self
->client
->area
.y
;
729 frame_client_gravity(self
, &self
->area
.x
, &self
->area
.y
,
730 self
->client
->area
.width
,
731 self
->client
->area
.height
);
735 if (!frame_iconify_animating(self
))
736 /* move and resize the top level frame.
737 shading can change without being moved or resized.
739 but don't do this during an iconify animation. it will be
740 reflected afterwards.
742 XMoveResizeWindow(ob_display
, self
->window
,
749 framerender_frame(self
);
750 frame_adjust_shape(self
);
753 if (!STRUT_EQUAL(self
->size
, oldsize
)) {
755 vals
[0] = self
->size
.left
;
756 vals
[1] = self
->size
.right
;
757 vals
[2] = self
->size
.top
;
758 vals
[3] = self
->size
.bottom
;
759 PROP_SETA32(self
->client
->window
, net_frame_extents
,
761 PROP_SETA32(self
->client
->window
, kde_net_wm_frame_strut
,
765 /* if this occurs while we are focus cycling, the indicator needs to
767 if (focus_cycle_target
== self
->client
)
768 focus_cycle_draw_indicator(self
->client
);
770 if (resized
&& (self
->decorations
& OB_FRAME_DECOR_TITLEBAR
))
771 XResizeWindow(ob_display
, self
->label
, self
->label_width
,
772 ob_rr_theme
->label_height
);
776 static void frame_adjust_cursors(ObFrame
*self
)
778 if ((self
->functions
& OB_CLIENT_FUNC_RESIZE
) !=
779 (self
->client
->functions
& OB_CLIENT_FUNC_RESIZE
) ||
780 self
->max_horz
!= self
->client
->max_horz
||
781 self
->max_vert
!= self
->client
->max_vert
)
783 gboolean r
= (self
->client
->functions
& OB_CLIENT_FUNC_RESIZE
) &&
784 !(self
->client
->max_horz
&& self
->client
->max_vert
);
785 gboolean topbot
= !self
->client
->max_vert
;
786 XSetWindowAttributes a
;
788 /* these ones turn off when max vert */
789 a
.cursor
= ob_cursor(r
&& topbot
? OB_CURSOR_NORTH
: OB_CURSOR_NONE
);
790 XChangeWindowAttributes(ob_display
, self
->topresize
, CWCursor
, &a
);
791 XChangeWindowAttributes(ob_display
, self
->titletop
, CWCursor
, &a
);
792 a
.cursor
= ob_cursor(r
&& topbot
? OB_CURSOR_SOUTH
: OB_CURSOR_NONE
);
793 XChangeWindowAttributes(ob_display
, self
->handle
, CWCursor
, &a
);
794 XChangeWindowAttributes(ob_display
, self
->handletop
, CWCursor
, &a
);
795 XChangeWindowAttributes(ob_display
, self
->handlebottom
, CWCursor
, &a
);
796 XChangeWindowAttributes(ob_display
, self
->innerbottom
, CWCursor
, &a
);
798 /* these ones don't */
799 a
.cursor
= ob_cursor(r
? OB_CURSOR_NORTHWEST
: OB_CURSOR_NONE
);
800 XChangeWindowAttributes(ob_display
, self
->tltresize
, CWCursor
, &a
);
801 XChangeWindowAttributes(ob_display
, self
->tllresize
, CWCursor
, &a
);
802 XChangeWindowAttributes(ob_display
, self
->titletopleft
, CWCursor
, &a
);
803 XChangeWindowAttributes(ob_display
, self
->titleleft
, CWCursor
, &a
);
804 a
.cursor
= ob_cursor(r
? OB_CURSOR_NORTHEAST
: OB_CURSOR_NONE
);
805 XChangeWindowAttributes(ob_display
, self
->trtresize
, CWCursor
, &a
);
806 XChangeWindowAttributes(ob_display
, self
->trrresize
, CWCursor
, &a
);
807 XChangeWindowAttributes(ob_display
, self
->titletopright
, CWCursor
, &a
);
808 XChangeWindowAttributes(ob_display
, self
->titleright
, CWCursor
, &a
);
809 a
.cursor
= ob_cursor(r
? OB_CURSOR_WEST
: OB_CURSOR_NONE
);
810 XChangeWindowAttributes(ob_display
, self
->left
, CWCursor
, &a
);
811 XChangeWindowAttributes(ob_display
, self
->innerleft
, CWCursor
, &a
);
812 a
.cursor
= ob_cursor(r
? OB_CURSOR_EAST
: OB_CURSOR_NONE
);
813 XChangeWindowAttributes(ob_display
, self
->right
, CWCursor
, &a
);
814 XChangeWindowAttributes(ob_display
, self
->innerright
, CWCursor
, &a
);
815 a
.cursor
= ob_cursor(r
? OB_CURSOR_SOUTHWEST
: OB_CURSOR_NONE
);
816 XChangeWindowAttributes(ob_display
, self
->lgrip
, CWCursor
, &a
);
817 XChangeWindowAttributes(ob_display
, self
->handleleft
, CWCursor
, &a
);
818 XChangeWindowAttributes(ob_display
, self
->lgripleft
, CWCursor
, &a
);
819 XChangeWindowAttributes(ob_display
, self
->lgriptop
, CWCursor
, &a
);
820 XChangeWindowAttributes(ob_display
, self
->lgripbottom
, CWCursor
, &a
);
821 a
.cursor
= ob_cursor(r
? OB_CURSOR_SOUTHEAST
: OB_CURSOR_NONE
);
822 XChangeWindowAttributes(ob_display
, self
->rgrip
, CWCursor
, &a
);
823 XChangeWindowAttributes(ob_display
, self
->handleright
, CWCursor
, &a
);
824 XChangeWindowAttributes(ob_display
, self
->rgripright
, CWCursor
, &a
);
825 XChangeWindowAttributes(ob_display
, self
->rgriptop
, CWCursor
, &a
);
826 XChangeWindowAttributes(ob_display
, self
->rgripbottom
, CWCursor
, &a
);
830 void frame_adjust_state(ObFrame
*self
)
832 framerender_frame(self
);
835 void frame_adjust_focus(ObFrame
*self
, gboolean hilite
)
837 self
->focused
= hilite
;
838 framerender_frame(self
);
842 void frame_adjust_title(ObFrame
*self
)
844 framerender_frame(self
);
847 void frame_adjust_icon(ObFrame
*self
)
849 framerender_frame(self
);
852 void frame_grab_client(ObFrame
*self
)
854 /* DO NOT map the client window here. we used to do that, but it is bogus.
855 we need to set up the client's dimensions and everything before we
856 send a mapnotify or we create race conditions.
859 /* reparent the client to the frame */
860 XReparentWindow(ob_display
, self
->client
->window
, self
->window
, 0, 0);
863 When reparenting the client window, it is usually not mapped yet, since
864 this occurs from a MapRequest. However, in the case where Openbox is
865 starting up, the window is already mapped, so we'll see an unmap event
868 if (ob_state() == OB_STATE_STARTING
)
869 ++self
->client
->ignore_unmaps
;
871 /* select the event mask on the client's parent (to receive config/map
872 req's) the ButtonPress is to catch clicks on the client border */
873 XSelectInput(ob_display
, self
->window
, FRAME_EVENTMASK
);
875 /* set all the windows for the frame in the window_map */
876 g_hash_table_insert(window_map
, &self
->window
, self
->client
);
877 g_hash_table_insert(window_map
, &self
->innerleft
, self
->client
);
878 g_hash_table_insert(window_map
, &self
->innertop
, self
->client
);
879 g_hash_table_insert(window_map
, &self
->innerright
, self
->client
);
880 g_hash_table_insert(window_map
, &self
->innerbottom
, self
->client
);
881 g_hash_table_insert(window_map
, &self
->title
, self
->client
);
882 g_hash_table_insert(window_map
, &self
->label
, self
->client
);
883 g_hash_table_insert(window_map
, &self
->max
, self
->client
);
884 g_hash_table_insert(window_map
, &self
->close
, self
->client
);
885 g_hash_table_insert(window_map
, &self
->desk
, self
->client
);
886 g_hash_table_insert(window_map
, &self
->shade
, self
->client
);
887 g_hash_table_insert(window_map
, &self
->icon
, self
->client
);
888 g_hash_table_insert(window_map
, &self
->iconify
, self
->client
);
889 g_hash_table_insert(window_map
, &self
->handle
, self
->client
);
890 g_hash_table_insert(window_map
, &self
->lgrip
, self
->client
);
891 g_hash_table_insert(window_map
, &self
->rgrip
, self
->client
);
892 g_hash_table_insert(window_map
, &self
->topresize
, self
->client
);
893 g_hash_table_insert(window_map
, &self
->tltresize
, self
->client
);
894 g_hash_table_insert(window_map
, &self
->tllresize
, self
->client
);
895 g_hash_table_insert(window_map
, &self
->trtresize
, self
->client
);
896 g_hash_table_insert(window_map
, &self
->trrresize
, self
->client
);
897 g_hash_table_insert(window_map
, &self
->left
, self
->client
);
898 g_hash_table_insert(window_map
, &self
->right
, self
->client
);
899 g_hash_table_insert(window_map
, &self
->titleleft
, self
->client
);
900 g_hash_table_insert(window_map
, &self
->titletop
, self
->client
);
901 g_hash_table_insert(window_map
, &self
->titletopleft
, self
->client
);
902 g_hash_table_insert(window_map
, &self
->titletopright
, self
->client
);
903 g_hash_table_insert(window_map
, &self
->titleright
, self
->client
);
904 g_hash_table_insert(window_map
, &self
->titlebottom
, self
->client
);
905 g_hash_table_insert(window_map
, &self
->handleleft
, self
->client
);
906 g_hash_table_insert(window_map
, &self
->handletop
, self
->client
);
907 g_hash_table_insert(window_map
, &self
->handleright
, self
->client
);
908 g_hash_table_insert(window_map
, &self
->handlebottom
, self
->client
);
909 g_hash_table_insert(window_map
, &self
->lgripleft
, self
->client
);
910 g_hash_table_insert(window_map
, &self
->lgriptop
, self
->client
);
911 g_hash_table_insert(window_map
, &self
->lgripbottom
, self
->client
);
912 g_hash_table_insert(window_map
, &self
->rgripright
, self
->client
);
913 g_hash_table_insert(window_map
, &self
->rgriptop
, self
->client
);
914 g_hash_table_insert(window_map
, &self
->rgripbottom
, self
->client
);
917 void frame_release_client(ObFrame
*self
)
920 gboolean reparent
= TRUE
;
922 /* if there was any animation going on, kill it */
923 ob_main_loop_timeout_remove_data(ob_main_loop
, frame_animate_iconify
,
926 /* check if the app has already reparented its window away */
927 while (XCheckTypedWindowEvent(ob_display
, self
->client
->window
,
928 ReparentNotify
, &ev
))
930 /* This check makes sure we don't catch our own reparent action to
931 our frame window. This doesn't count as the app reparenting itself
934 Reparent events that are generated by us are just discarded here.
935 They are of no consequence to us anyhow.
937 if (ev
.xreparent
.parent
!= self
->window
) {
939 XPutBackEvent(ob_display
, &ev
);
945 /* according to the ICCCM - if the client doesn't reparent itself,
946 then we will reparent the window to root for them */
947 XReparentWindow(ob_display
, self
->client
->window
,
948 RootWindow(ob_display
, ob_screen
),
949 self
->client
->area
.x
,
950 self
->client
->area
.y
);
953 /* remove all the windows for the frame from the window_map */
954 g_hash_table_remove(window_map
, &self
->window
);
955 g_hash_table_remove(window_map
, &self
->innerleft
);
956 g_hash_table_remove(window_map
, &self
->innertop
);
957 g_hash_table_remove(window_map
, &self
->innerright
);
958 g_hash_table_remove(window_map
, &self
->innerbottom
);
959 g_hash_table_remove(window_map
, &self
->title
);
960 g_hash_table_remove(window_map
, &self
->label
);
961 g_hash_table_remove(window_map
, &self
->max
);
962 g_hash_table_remove(window_map
, &self
->close
);
963 g_hash_table_remove(window_map
, &self
->desk
);
964 g_hash_table_remove(window_map
, &self
->shade
);
965 g_hash_table_remove(window_map
, &self
->icon
);
966 g_hash_table_remove(window_map
, &self
->iconify
);
967 g_hash_table_remove(window_map
, &self
->handle
);
968 g_hash_table_remove(window_map
, &self
->lgrip
);
969 g_hash_table_remove(window_map
, &self
->rgrip
);
970 g_hash_table_remove(window_map
, &self
->topresize
);
971 g_hash_table_remove(window_map
, &self
->tltresize
);
972 g_hash_table_remove(window_map
, &self
->tllresize
);
973 g_hash_table_remove(window_map
, &self
->trtresize
);
974 g_hash_table_remove(window_map
, &self
->trrresize
);
975 g_hash_table_remove(window_map
, &self
->left
);
976 g_hash_table_remove(window_map
, &self
->right
);
977 g_hash_table_remove(window_map
, &self
->titleleft
);
978 g_hash_table_remove(window_map
, &self
->titletop
);
979 g_hash_table_remove(window_map
, &self
->titletopleft
);
980 g_hash_table_remove(window_map
, &self
->titletopright
);
981 g_hash_table_remove(window_map
, &self
->titleright
);
982 g_hash_table_remove(window_map
, &self
->titlebottom
);
983 g_hash_table_remove(window_map
, &self
->handleleft
);
984 g_hash_table_remove(window_map
, &self
->handletop
);
985 g_hash_table_remove(window_map
, &self
->handleright
);
986 g_hash_table_remove(window_map
, &self
->handlebottom
);
987 g_hash_table_remove(window_map
, &self
->lgripleft
);
988 g_hash_table_remove(window_map
, &self
->lgriptop
);
989 g_hash_table_remove(window_map
, &self
->lgripbottom
);
990 g_hash_table_remove(window_map
, &self
->rgripright
);
991 g_hash_table_remove(window_map
, &self
->rgriptop
);
992 g_hash_table_remove(window_map
, &self
->rgripbottom
);
994 ob_main_loop_timeout_remove_data(ob_main_loop
, flash_timeout
, self
, TRUE
);
997 /* is there anything present between us and the label? */
998 static gboolean
is_button_present(ObFrame
*self
, const gchar
*lc
, gint dir
) {
999 for (; *lc
!= '\0' && lc
>= config_title_layout
; lc
+= dir
) {
1000 if (*lc
== ' ') continue; /* it was invalid */
1001 if (*lc
== 'N' && self
->decorations
& OB_FRAME_DECOR_ICON
)
1003 if (*lc
== 'D' && self
->decorations
& OB_FRAME_DECOR_ALLDESKTOPS
)
1005 if (*lc
== 'S' && self
->decorations
& OB_FRAME_DECOR_SHADE
)
1007 if (*lc
== 'I' && self
->decorations
& OB_FRAME_DECOR_ICONIFY
)
1009 if (*lc
== 'M' && self
->decorations
& OB_FRAME_DECOR_MAXIMIZE
)
1011 if (*lc
== 'C' && self
->decorations
& OB_FRAME_DECOR_CLOSE
)
1013 if (*lc
== 'L') return FALSE
;
1018 static void layout_title(ObFrame
*self
)
1023 const gint bwidth
= ob_rr_theme
->button_size
+ ob_rr_theme
->paddingx
+ 1;
1024 /* position of the left most button */
1025 const gint left
= ob_rr_theme
->paddingx
+ 1;
1026 /* position of the right most button */
1027 const gint right
= self
->width
;
1029 /* turn them all off */
1030 self
->icon_on
= self
->desk_on
= self
->shade_on
= self
->iconify_on
=
1031 self
->max_on
= self
->close_on
= self
->label_on
= FALSE
;
1032 self
->label_width
= self
->width
- (ob_rr_theme
->paddingx
+ 1) * 2;
1033 self
->leftmost
= self
->rightmost
= OB_FRAME_CONTEXT_NONE
;
1035 /* figure out what's being show, find each element's position, and the
1038 do the ones before the label, then after the label,
1039 i will be +1 the first time through when working to the left,
1040 and -1 the second time through when working to the right */
1041 for (i
= 1; i
>= -1; i
-=2) {
1043 ObFrameContext
*firstcon
;
1047 lc
= config_title_layout
;
1048 firstcon
= &self
->leftmost
;
1051 lc
= config_title_layout
+ strlen(config_title_layout
)-1;
1052 firstcon
= &self
->rightmost
;
1055 /* stop at the end of the string (or the label, which calls break) */
1056 for (; *lc
!= '\0' && lc
>= config_title_layout
; lc
+=i
) {
1059 self
->label_on
= TRUE
;
1062 break; /* break the for loop, do other side of label */
1063 } else if (*lc
== 'N') {
1064 if (firstcon
) *firstcon
= OB_FRAME_CONTEXT_ICON
;
1065 if ((self
->icon_on
= is_button_present(self
, lc
, i
))) {
1066 /* icon is bigger than buttons */
1067 self
->label_width
-= bwidth
+ 2;
1068 if (i
> 0) self
->icon_x
= x
;
1069 x
+= i
* (bwidth
+ 2);
1070 if (i
< 0) self
->icon_x
= x
;
1072 } else if (*lc
== 'D') {
1073 if (firstcon
) *firstcon
= OB_FRAME_CONTEXT_ALLDESKTOPS
;
1074 if ((self
->desk_on
= is_button_present(self
, lc
, i
))) {
1075 self
->label_width
-= bwidth
;
1076 if (i
> 0) self
->desk_x
= x
;
1078 if (i
< 0) self
->desk_x
= x
;
1080 } else if (*lc
== 'S') {
1081 if (firstcon
) *firstcon
= OB_FRAME_CONTEXT_SHADE
;
1082 if ((self
->shade_on
= is_button_present(self
, lc
, i
))) {
1083 self
->label_width
-= bwidth
;
1084 if (i
> 0) self
->shade_x
= x
;
1086 if (i
< 0) self
->shade_x
= x
;
1088 } else if (*lc
== 'I') {
1089 if (firstcon
) *firstcon
= OB_FRAME_CONTEXT_ICONIFY
;
1090 if ((self
->iconify_on
= is_button_present(self
, lc
, i
))) {
1091 self
->label_width
-= bwidth
;
1092 if (i
> 0) self
->iconify_x
= x
;
1094 if (i
< 0) self
->iconify_x
= x
;
1096 } else if (*lc
== 'M') {
1097 if (firstcon
) *firstcon
= OB_FRAME_CONTEXT_MAXIMIZE
;
1098 if ((self
->max_on
= is_button_present(self
, lc
, i
))) {
1099 self
->label_width
-= bwidth
;
1100 if (i
> 0) self
->max_x
= x
;
1102 if (i
< 0) self
->max_x
= x
;
1104 } else if (*lc
== 'C') {
1105 if (firstcon
) *firstcon
= OB_FRAME_CONTEXT_CLOSE
;
1106 if ((self
->close_on
= is_button_present(self
, lc
, i
))) {
1107 self
->label_width
-= bwidth
;
1108 if (i
> 0) self
->close_x
= x
;
1110 if (i
< 0) self
->close_x
= x
;
1113 continue; /* don't set firstcon */
1118 /* position and map the elements */
1119 if (self
->icon_on
) {
1120 XMapWindow(ob_display
, self
->icon
);
1121 XMoveWindow(ob_display
, self
->icon
, self
->icon_x
,
1122 ob_rr_theme
->paddingy
);
1124 XUnmapWindow(ob_display
, self
->icon
);
1126 if (self
->desk_on
) {
1127 XMapWindow(ob_display
, self
->desk
);
1128 XMoveWindow(ob_display
, self
->desk
, self
->desk_x
,
1129 ob_rr_theme
->paddingy
+ 1);
1131 XUnmapWindow(ob_display
, self
->desk
);
1133 if (self
->shade_on
) {
1134 XMapWindow(ob_display
, self
->shade
);
1135 XMoveWindow(ob_display
, self
->shade
, self
->shade_x
,
1136 ob_rr_theme
->paddingy
+ 1);
1138 XUnmapWindow(ob_display
, self
->shade
);
1140 if (self
->iconify_on
) {
1141 XMapWindow(ob_display
, self
->iconify
);
1142 XMoveWindow(ob_display
, self
->iconify
, self
->iconify_x
,
1143 ob_rr_theme
->paddingy
+ 1);
1145 XUnmapWindow(ob_display
, self
->iconify
);
1148 XMapWindow(ob_display
, self
->max
);
1149 XMoveWindow(ob_display
, self
->max
, self
->max_x
,
1150 ob_rr_theme
->paddingy
+ 1);
1152 XUnmapWindow(ob_display
, self
->max
);
1154 if (self
->close_on
) {
1155 XMapWindow(ob_display
, self
->close
);
1156 XMoveWindow(ob_display
, self
->close
, self
->close_x
,
1157 ob_rr_theme
->paddingy
+ 1);
1159 XUnmapWindow(ob_display
, self
->close
);
1161 if (self
->label_on
) {
1162 self
->label_width
= MAX(1, self
->label_width
); /* no lower than 1 */
1163 XMapWindow(ob_display
, self
->label
);
1164 XMoveWindow(ob_display
, self
->label
, self
->label_x
,
1165 ob_rr_theme
->paddingy
);
1167 XUnmapWindow(ob_display
, self
->label
);
1170 ObFrameContext
frame_context_from_string(const gchar
*name
)
1172 if (!g_ascii_strcasecmp("Desktop", name
))
1173 return OB_FRAME_CONTEXT_DESKTOP
;
1174 else if (!g_ascii_strcasecmp("Root", name
))
1175 return OB_FRAME_CONTEXT_ROOT
;
1176 else if (!g_ascii_strcasecmp("Client", name
))
1177 return OB_FRAME_CONTEXT_CLIENT
;
1178 else if (!g_ascii_strcasecmp("Titlebar", name
))
1179 return OB_FRAME_CONTEXT_TITLEBAR
;
1180 else if (!g_ascii_strcasecmp("Frame", name
))
1181 return OB_FRAME_CONTEXT_FRAME
;
1182 else if (!g_ascii_strcasecmp("TLCorner", name
))
1183 return OB_FRAME_CONTEXT_TLCORNER
;
1184 else if (!g_ascii_strcasecmp("TRCorner", name
))
1185 return OB_FRAME_CONTEXT_TRCORNER
;
1186 else if (!g_ascii_strcasecmp("BLCorner", name
))
1187 return OB_FRAME_CONTEXT_BLCORNER
;
1188 else if (!g_ascii_strcasecmp("BRCorner", name
))
1189 return OB_FRAME_CONTEXT_BRCORNER
;
1190 else if (!g_ascii_strcasecmp("Top", name
))
1191 return OB_FRAME_CONTEXT_TOP
;
1192 else if (!g_ascii_strcasecmp("Bottom", name
))
1193 return OB_FRAME_CONTEXT_BOTTOM
;
1194 else if (!g_ascii_strcasecmp("Left", name
))
1195 return OB_FRAME_CONTEXT_LEFT
;
1196 else if (!g_ascii_strcasecmp("Right", name
))
1197 return OB_FRAME_CONTEXT_RIGHT
;
1198 else if (!g_ascii_strcasecmp("Maximize", name
))
1199 return OB_FRAME_CONTEXT_MAXIMIZE
;
1200 else if (!g_ascii_strcasecmp("AllDesktops", name
))
1201 return OB_FRAME_CONTEXT_ALLDESKTOPS
;
1202 else if (!g_ascii_strcasecmp("Shade", name
))
1203 return OB_FRAME_CONTEXT_SHADE
;
1204 else if (!g_ascii_strcasecmp("Iconify", name
))
1205 return OB_FRAME_CONTEXT_ICONIFY
;
1206 else if (!g_ascii_strcasecmp("Icon", name
))
1207 return OB_FRAME_CONTEXT_ICON
;
1208 else if (!g_ascii_strcasecmp("Close", name
))
1209 return OB_FRAME_CONTEXT_CLOSE
;
1210 else if (!g_ascii_strcasecmp("MoveResize", name
))
1211 return OB_FRAME_CONTEXT_MOVE_RESIZE
;
1212 return OB_FRAME_CONTEXT_NONE
;
1215 ObFrameContext
frame_context(ObClient
*client
, Window win
, gint x
, gint y
)
1219 if (moveresize_in_progress
)
1220 return OB_FRAME_CONTEXT_MOVE_RESIZE
;
1222 if (win
== RootWindow(ob_display
, ob_screen
))
1223 return OB_FRAME_CONTEXT_ROOT
;
1224 if (client
== NULL
) return OB_FRAME_CONTEXT_NONE
;
1225 if (win
== client
->window
) {
1226 /* conceptually, this is the desktop, as far as users are
1228 if (client
->type
== OB_CLIENT_TYPE_DESKTOP
)
1229 return OB_FRAME_CONTEXT_DESKTOP
;
1230 return OB_FRAME_CONTEXT_CLIENT
;
1233 self
= client
->frame
;
1235 /* when the user clicks in the corners of the titlebar and the client
1236 is fully maximized, then treat it like they clicked in the
1237 button that is there */
1238 if (self
->max_horz
&& self
->max_vert
&&
1239 (win
== self
->title
|| win
== self
->titletop
||
1240 win
== self
->titleleft
|| win
== self
->titletopleft
||
1241 win
== self
->titleright
|| win
== self
->titletopright
))
1243 /* get the mouse coords in reference to the whole frame */
1247 /* these windows are down a border width from the top of the frame */
1248 if (win
== self
->title
||
1249 win
== self
->titleleft
|| win
== self
->titleright
)
1252 /* title is a border width in from the edge */
1253 if (win
== self
->title
)
1255 /* titletop is a bit to the right */
1256 else if (win
== self
->titletop
)
1257 fx
+= ob_rr_theme
->grip_width
+ self
->bwidth
;
1258 /* titletopright is way to the right edge */
1259 else if (win
== self
->titletopright
)
1260 fx
+= self
->area
.width
- (ob_rr_theme
->grip_width
+ self
->bwidth
);
1261 /* titleright is even more way to the right edge */
1262 else if (win
== self
->titleright
)
1263 fx
+= self
->area
.width
- self
->bwidth
;
1265 /* figure out if we're over the area that should be considered a
1267 if (fy
< self
->bwidth
+ ob_rr_theme
->paddingy
+ 1 +
1268 ob_rr_theme
->button_size
)
1270 if (fx
< (self
->bwidth
+ ob_rr_theme
->paddingx
+ 1 +
1271 ob_rr_theme
->button_size
))
1273 if (self
->leftmost
!= OB_FRAME_CONTEXT_NONE
)
1274 return self
->leftmost
;
1276 else if (fx
>= (self
->area
.width
-
1277 (self
->bwidth
+ ob_rr_theme
->paddingx
+ 1 +
1278 ob_rr_theme
->button_size
)))
1280 if (self
->rightmost
!= OB_FRAME_CONTEXT_NONE
)
1281 return self
->rightmost
;
1285 /* there is no resizing maximized windows so make them the titlebar
1287 return OB_FRAME_CONTEXT_TITLEBAR
;
1289 else if (self
->max_vert
&&
1290 (win
== self
->titletop
|| win
== self
->topresize
))
1291 /* can't resize vertically when max vert */
1292 return OB_FRAME_CONTEXT_TITLEBAR
;
1294 if (win
== self
->window
) return OB_FRAME_CONTEXT_FRAME
;
1295 if (win
== self
->label
) return OB_FRAME_CONTEXT_TITLEBAR
;
1296 if (win
== self
->handle
) return OB_FRAME_CONTEXT_BOTTOM
;
1297 if (win
== self
->handletop
) return OB_FRAME_CONTEXT_BOTTOM
;
1298 if (win
== self
->handlebottom
) return OB_FRAME_CONTEXT_BOTTOM
;
1299 if (win
== self
->handleleft
) return OB_FRAME_CONTEXT_BLCORNER
;
1300 if (win
== self
->lgrip
) return OB_FRAME_CONTEXT_BLCORNER
;
1301 if (win
== self
->lgripleft
) return OB_FRAME_CONTEXT_BLCORNER
;
1302 if (win
== self
->lgriptop
) return OB_FRAME_CONTEXT_BLCORNER
;
1303 if (win
== self
->lgripbottom
) return OB_FRAME_CONTEXT_BLCORNER
;
1304 if (win
== self
->handleright
) return OB_FRAME_CONTEXT_BRCORNER
;
1305 if (win
== self
->rgrip
) return OB_FRAME_CONTEXT_BRCORNER
;
1306 if (win
== self
->rgripright
) return OB_FRAME_CONTEXT_BLCORNER
;
1307 if (win
== self
->rgriptop
) return OB_FRAME_CONTEXT_BLCORNER
;
1308 if (win
== self
->rgripbottom
) return OB_FRAME_CONTEXT_BLCORNER
;
1309 if (win
== self
->title
) return OB_FRAME_CONTEXT_TITLEBAR
;
1310 if (win
== self
->titlebottom
) return OB_FRAME_CONTEXT_TITLEBAR
;
1311 if (win
== self
->titleleft
) return OB_FRAME_CONTEXT_TLCORNER
;
1312 if (win
== self
->titletopleft
) return OB_FRAME_CONTEXT_TLCORNER
;
1313 if (win
== self
->titleright
) return OB_FRAME_CONTEXT_TRCORNER
;
1314 if (win
== self
->titletopright
) return OB_FRAME_CONTEXT_TRCORNER
;
1315 if (win
== self
->titletop
) return OB_FRAME_CONTEXT_TOP
;
1316 if (win
== self
->topresize
) return OB_FRAME_CONTEXT_TOP
;
1317 if (win
== self
->tltresize
) return OB_FRAME_CONTEXT_TLCORNER
;
1318 if (win
== self
->tllresize
) return OB_FRAME_CONTEXT_TLCORNER
;
1319 if (win
== self
->trtresize
) return OB_FRAME_CONTEXT_TRCORNER
;
1320 if (win
== self
->trrresize
) return OB_FRAME_CONTEXT_TRCORNER
;
1321 if (win
== self
->left
) return OB_FRAME_CONTEXT_LEFT
;
1322 if (win
== self
->right
) return OB_FRAME_CONTEXT_RIGHT
;
1323 if (win
== self
->innertop
) return OB_FRAME_CONTEXT_TITLEBAR
;
1324 if (win
== self
->innerleft
) return OB_FRAME_CONTEXT_LEFT
;
1325 if (win
== self
->innerbottom
) return OB_FRAME_CONTEXT_BOTTOM
;
1326 if (win
== self
->innerright
) return OB_FRAME_CONTEXT_RIGHT
;
1327 if (win
== self
->max
) return OB_FRAME_CONTEXT_MAXIMIZE
;
1328 if (win
== self
->iconify
) return OB_FRAME_CONTEXT_ICONIFY
;
1329 if (win
== self
->close
) return OB_FRAME_CONTEXT_CLOSE
;
1330 if (win
== self
->icon
) return OB_FRAME_CONTEXT_ICON
;
1331 if (win
== self
->desk
) return OB_FRAME_CONTEXT_ALLDESKTOPS
;
1332 if (win
== self
->shade
) return OB_FRAME_CONTEXT_SHADE
;
1334 return OB_FRAME_CONTEXT_NONE
;
1337 void frame_client_gravity(ObFrame
*self
, gint
*x
, gint
*y
, gint w
, gint h
)
1340 switch (self
->client
->gravity
) {
1342 case NorthWestGravity
:
1343 case SouthWestGravity
:
1350 /* the middle of the client will be the middle of the frame */
1351 *x
-= (self
->size
.right
- self
->size
.left
) / 2;
1354 case NorthEastGravity
:
1355 case SouthEastGravity
:
1357 /* the right side of the client will be the right side of the frame */
1358 *x
-= self
->size
.right
+ self
->size
.left
-
1359 self
->client
->border_width
* 2;
1364 /* the client's position won't move */
1365 *x
-= self
->size
.left
- self
->client
->border_width
;
1370 switch (self
->client
->gravity
) {
1372 case NorthWestGravity
:
1373 case NorthEastGravity
:
1380 /* the middle of the client will be the middle of the frame */
1381 *y
-= (self
->size
.bottom
- self
->size
.top
) / 2;
1384 case SouthWestGravity
:
1385 case SouthEastGravity
:
1387 /* the bottom of the client will be the bottom of the frame */
1388 *y
-= self
->size
.bottom
+ self
->size
.top
-
1389 self
->client
->border_width
* 2;
1394 /* the client's position won't move */
1395 *y
-= self
->size
.top
- self
->client
->border_width
;
1400 void frame_frame_gravity(ObFrame
*self
, gint
*x
, gint
*y
, gint w
, gint h
)
1403 switch (self
->client
->gravity
) {
1405 case NorthWestGravity
:
1407 case SouthWestGravity
:
1412 /* the middle of the client will be the middle of the frame */
1413 *x
+= (self
->size
.right
- self
->size
.left
) / 2;
1415 case NorthEastGravity
:
1417 case SouthEastGravity
:
1418 /* the right side of the client will be the right side of the frame */
1419 *x
+= self
->size
.right
+ self
->size
.left
-
1420 self
->client
->border_width
* 2;
1424 /* the client's position won't move */
1425 *x
+= self
->size
.left
- self
->client
->border_width
;
1430 switch (self
->client
->gravity
) {
1432 case NorthWestGravity
:
1434 case NorthEastGravity
:
1439 /* the middle of the client will be the middle of the frame */
1440 *y
+= (self
->size
.bottom
- self
->size
.top
) / 2;
1442 case SouthWestGravity
:
1444 case SouthEastGravity
:
1445 /* the bottom of the client will be the bottom of the frame */
1446 *y
+= self
->size
.bottom
+ self
->size
.top
-
1447 self
->client
->border_width
* 2;
1451 /* the client's position won't move */
1452 *y
+= self
->size
.top
- self
->client
->border_width
;
1457 static void flash_done(gpointer data
)
1459 ObFrame
*self
= data
;
1461 if (self
->focused
!= self
->flash_on
)
1462 frame_adjust_focus(self
, self
->focused
);
1465 static gboolean
flash_timeout(gpointer data
)
1467 ObFrame
*self
= data
;
1470 g_get_current_time(&now
);
1471 if (now
.tv_sec
> self
->flash_end
.tv_sec
||
1472 (now
.tv_sec
== self
->flash_end
.tv_sec
&&
1473 now
.tv_usec
>= self
->flash_end
.tv_usec
))
1474 self
->flashing
= FALSE
;
1476 if (!self
->flashing
)
1477 return FALSE
; /* we are done */
1479 self
->flash_on
= !self
->flash_on
;
1480 if (!self
->focused
) {
1481 frame_adjust_focus(self
, self
->flash_on
);
1482 self
->focused
= FALSE
;
1485 return TRUE
; /* go again */
1488 void frame_flash_start(ObFrame
*self
)
1490 self
->flash_on
= self
->focused
;
1492 if (!self
->flashing
)
1493 ob_main_loop_timeout_add(ob_main_loop
,
1494 G_USEC_PER_SEC
* 0.6,
1499 g_get_current_time(&self
->flash_end
);
1500 g_time_val_add(&self
->flash_end
, G_USEC_PER_SEC
* 5);
1502 self
->flashing
= TRUE
;
1505 void frame_flash_stop(ObFrame
*self
)
1507 self
->flashing
= FALSE
;
1510 static gulong
frame_animate_iconify_time_left(ObFrame
*self
,
1511 const GTimeVal
*now
)
1514 sec
= self
->iconify_animation_end
.tv_sec
- now
->tv_sec
;
1515 usec
= self
->iconify_animation_end
.tv_usec
- now
->tv_usec
;
1517 usec
+= G_USEC_PER_SEC
;
1520 /* no negative values */
1521 return MAX(sec
* G_USEC_PER_SEC
+ usec
, 0);
1524 static gboolean
frame_animate_iconify(gpointer p
)
1528 gint iconx
, icony
, iconw
;
1531 gboolean iconifying
;
1533 if (self
->client
->icon_geometry
.width
== 0) {
1534 /* there is no icon geometry set so just go straight down */
1535 Rect
*a
= screen_physical_area();
1536 iconx
= self
->area
.x
+ self
->area
.width
/ 2 + 32;
1537 icony
= a
->y
+ a
->width
;
1540 iconx
= self
->client
->icon_geometry
.x
;
1541 icony
= self
->client
->icon_geometry
.y
;
1542 iconw
= self
->client
->icon_geometry
.width
;
1545 iconifying
= self
->iconify_animation_going
> 0;
1547 /* how far do we have left to go ? */
1548 g_get_current_time(&now
);
1549 time
= frame_animate_iconify_time_left(self
, &now
);
1551 if (time
== 0 || iconifying
) {
1552 /* start where the frame is supposed to be */
1555 w
= self
->area
.width
;
1556 h
= self
->area
.height
;
1558 /* start at the icon */
1562 h
= self
->size
.top
; /* just the titlebar */
1569 dx
= self
->area
.x
- iconx
;
1570 dy
= self
->area
.y
- icony
;
1571 dw
= self
->area
.width
- self
->bwidth
* 2 - iconw
;
1572 /* if restoring, we move in the opposite direction */
1573 if (!iconifying
) { dx
= -dx
; dy
= -dy
; dw
= -dw
; }
1575 elapsed
= FRAME_ANIMATE_ICONIFY_TIME
- time
;
1576 x
= x
- (dx
* elapsed
) / FRAME_ANIMATE_ICONIFY_TIME
;
1577 y
= y
- (dy
* elapsed
) / FRAME_ANIMATE_ICONIFY_TIME
;
1578 w
= w
- (dw
* elapsed
) / FRAME_ANIMATE_ICONIFY_TIME
;
1579 h
= self
->size
.top
; /* just the titlebar */
1583 frame_end_iconify_animation(self
);
1585 XMoveResizeWindow(ob_display
, self
->window
, x
, y
, w
, h
);
1589 return time
> 0; /* repeat until we're out of time */
1592 void frame_end_iconify_animation(ObFrame
*self
)
1594 /* see if there is an animation going */
1595 if (self
->iconify_animation_going
== 0) return;
1598 XUnmapWindow(ob_display
, self
->window
);
1600 /* Send a ConfigureNotify when the animation is done, this fixes
1601 KDE's pager showing the window in the wrong place. */
1602 client_reconfigure(self
->client
);
1604 /* we're not animating any more ! */
1605 self
->iconify_animation_going
= 0;
1607 XMoveResizeWindow(ob_display
, self
->window
,
1608 self
->area
.x
, self
->area
.y
,
1609 self
->area
.width
, self
->area
.height
);
1613 void frame_begin_iconify_animation(ObFrame
*self
, gboolean iconifying
)
1616 gboolean new_anim
= FALSE
;
1617 gboolean set_end
= TRUE
;
1620 /* if there is no titlebar, just don't animate for now
1621 XXX it would be nice tho.. */
1622 if (!(self
->decorations
& OB_FRAME_DECOR_TITLEBAR
))
1625 /* get the current time */
1626 g_get_current_time(&now
);
1628 /* get how long until the end */
1629 time
= FRAME_ANIMATE_ICONIFY_TIME
;
1630 if (self
->iconify_animation_going
) {
1631 if (!!iconifying
!= (self
->iconify_animation_going
> 0)) {
1632 /* animation was already going on in the opposite direction */
1633 time
= time
- frame_animate_iconify_time_left(self
, &now
);
1635 /* animation was already going in the same direction */
1639 self
->iconify_animation_going
= iconifying
? 1 : -1;
1641 /* set the ending time */
1643 self
->iconify_animation_end
.tv_sec
= now
.tv_sec
;
1644 self
->iconify_animation_end
.tv_usec
= now
.tv_usec
;
1645 g_time_val_add(&self
->iconify_animation_end
, time
);
1649 ob_main_loop_timeout_remove_data(ob_main_loop
, frame_animate_iconify
,
1651 ob_main_loop_timeout_add(ob_main_loop
,
1652 FRAME_ANIMATE_ICONIFY_STEP_TIME
,
1653 frame_animate_iconify
, self
,
1654 g_direct_equal
, NULL
);
1656 /* do the first step */
1657 frame_animate_iconify(self
);
1659 /* show it during the animation even if it is not "visible" */
1661 XMapWindow(ob_display
, self
->window
);