1 /* -*- indent-tabs-mode: nil; tab-width: 4; c-basic-offset: 4; -*-
3 frame.c for the Openbox window manager
4 Copyright (c) 2006 Mikael Magnusson
5 Copyright (c) 2003-2007 Dana Jansens
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2 of the License, or
10 (at your option) any later version.
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 See the COPYING file for a copy of the GNU General Public License.
23 #include "extensions.h"
26 #include "framerender.h"
28 #include "focus_cycle.h"
29 #include "focus_cycle_indicator.h"
30 #include "moveresize.h"
32 #include "render/theme.h"
34 #define PLATE_EVENTMASK (SubstructureRedirectMask | FocusChangeMask)
35 #define FRAME_EVENTMASK (EnterWindowMask | LeaveWindowMask | \
36 ButtonPressMask | ButtonReleaseMask)
37 #define ELEMENT_EVENTMASK (ButtonPressMask | ButtonReleaseMask | \
38 ButtonMotionMask | PointerMotionMask | \
39 EnterWindowMask | LeaveWindowMask)
40 /* The inner window does not need enter/leave events.
41 If it does get them, then it needs its own context for enter events
42 because sloppy focus will focus the window when you enter the inner window
44 #define INNER_EVENTMASK (ButtonPressMask)
46 #define FRAME_ANIMATE_ICONIFY_TIME 150000 /* .15 seconds */
47 #define FRAME_ANIMATE_ICONIFY_STEP_TIME (G_USEC_PER_SEC / 60) /* 60 Hz */
49 #define FRAME_HANDLE_Y(f) (f->size.top + f->client->area.height + f->cbwidth_y)
51 static void flash_done(gpointer data
);
52 static gboolean
flash_timeout(gpointer data
);
54 static void layout_title(ObFrame
*self
);
55 static void set_theme_statics(ObFrame
*self
);
56 static void free_theme_statics(ObFrame
*self
);
57 static gboolean
frame_animate_iconify(gpointer self
);
59 static Window
createWindow(Window parent
, Visual
*visual
,
60 gulong mask
, XSetWindowAttributes
*attrib
)
62 return XCreateWindow(ob_display
, parent
, 0, 0, 1, 1, 0,
63 (visual
? 32 : RrDepth(ob_rr_inst
)), InputOutput
,
64 (visual
? visual
: RrVisual(ob_rr_inst
)),
69 static Visual
*check_32bit_client(ObClient
*c
)
71 XWindowAttributes wattrib
;
74 /* we're already running at 32 bit depth, yay. we don't need to use their
76 if (RrDepth(ob_rr_inst
) == 32)
79 ret
= XGetWindowAttributes(ob_display
, c
->window
, &wattrib
);
80 g_assert(ret
!= BadDrawable
);
81 g_assert(ret
!= BadWindow
);
83 if (wattrib
.depth
== 32)
84 return wattrib
.visual
;
88 ObFrame
*frame_new(ObClient
*client
)
90 XSetWindowAttributes attrib
;
95 self
= g_new0(ObFrame
, 1);
96 self
->client
= client
;
98 visual
= check_32bit_client(client
);
100 /* create the non-visible decor windows */
104 /* client has a 32-bit visual */
105 mask
|= CWColormap
| CWBackPixel
| CWBorderPixel
;
106 /* create a colormap with the visual */
107 self
->colormap
= attrib
.colormap
=
108 XCreateColormap(ob_display
,
109 RootWindow(ob_display
, ob_screen
),
111 attrib
.background_pixel
= BlackPixel(ob_display
, ob_screen
);
112 attrib
.border_pixel
= BlackPixel(ob_display
, ob_screen
);
114 attrib
.event_mask
= FRAME_EVENTMASK
;
115 self
->window
= createWindow(RootWindow(ob_display
, ob_screen
), visual
,
118 attrib
.event_mask
= INNER_EVENTMASK
;
119 self
->inner
= createWindow(self
->window
, visual
, mask
, &attrib
);
121 mask
&= ~CWEventMask
;
122 self
->plate
= createWindow(self
->inner
, visual
, mask
, &attrib
);
124 /* create the visible decor windows */
128 /* client has a 32-bit visual */
129 mask
|= CWColormap
| CWBackPixel
| CWBorderPixel
;
130 attrib
.colormap
= RrColormap(ob_rr_inst
);
132 attrib
.event_mask
= ELEMENT_EVENTMASK
;
133 self
->title
= createWindow(self
->window
, NULL
, mask
, &attrib
);
134 self
->titleleft
= createWindow(self
->window
, NULL
, mask
, &attrib
);
135 self
->titletop
= createWindow(self
->window
, NULL
, mask
, &attrib
);
136 self
->titletopleft
= createWindow(self
->window
, NULL
, mask
, &attrib
);
137 self
->titletopright
= createWindow(self
->window
, NULL
, mask
, &attrib
);
138 self
->titleright
= createWindow(self
->window
, NULL
, mask
, &attrib
);
139 self
->titlebottom
= createWindow(self
->window
, NULL
, mask
, &attrib
);
141 self
->topresize
= createWindow(self
->title
, NULL
, mask
, &attrib
);
142 self
->tltresize
= createWindow(self
->title
, NULL
, mask
, &attrib
);
143 self
->tllresize
= createWindow(self
->title
, NULL
, mask
, &attrib
);
144 self
->trtresize
= createWindow(self
->title
, NULL
, mask
, &attrib
);
145 self
->trrresize
= createWindow(self
->title
, NULL
, mask
, &attrib
);
147 self
->left
= createWindow(self
->window
, NULL
, mask
, &attrib
);
148 self
->right
= createWindow(self
->window
, NULL
, mask
, &attrib
);
150 self
->label
= createWindow(self
->title
, NULL
, mask
, &attrib
);
151 self
->max
= createWindow(self
->title
, NULL
, mask
, &attrib
);
152 self
->close
= createWindow(self
->title
, NULL
, mask
, &attrib
);
153 self
->desk
= createWindow(self
->title
, NULL
, mask
, &attrib
);
154 self
->shade
= createWindow(self
->title
, NULL
, mask
, &attrib
);
155 self
->icon
= createWindow(self
->title
, NULL
, mask
, &attrib
);
156 self
->iconify
= createWindow(self
->title
, NULL
, mask
, &attrib
);
158 self
->handle
= createWindow(self
->window
, NULL
, mask
, &attrib
);
159 self
->lgrip
= createWindow(self
->handle
, NULL
, mask
, &attrib
);
160 self
->rgrip
= createWindow(self
->handle
, NULL
, mask
, &attrib
);
162 self
->handleleft
= createWindow(self
->handle
, NULL
, mask
, &attrib
);
163 self
->handleright
= createWindow(self
->handle
, NULL
, mask
, &attrib
);
165 self
->handletop
= createWindow(self
->window
, NULL
, mask
, &attrib
);
166 self
->handlebottom
= createWindow(self
->window
, NULL
, mask
, &attrib
);
167 self
->lgripleft
= createWindow(self
->window
, NULL
, mask
, &attrib
);
168 self
->lgriptop
= createWindow(self
->window
, NULL
, mask
, &attrib
);
169 self
->lgripbottom
= createWindow(self
->window
, NULL
, mask
, &attrib
);
170 self
->rgripright
= createWindow(self
->window
, NULL
, mask
, &attrib
);
171 self
->rgriptop
= createWindow(self
->window
, NULL
, mask
, &attrib
);
172 self
->rgripbottom
= createWindow(self
->window
, NULL
, mask
, &attrib
);
174 self
->focused
= FALSE
;
176 /* the other stuff is shown based on decor settings */
177 XMapWindow(ob_display
, self
->plate
);
178 XMapWindow(ob_display
, self
->inner
);
179 XMapWindow(ob_display
, self
->label
);
181 self
->max_press
= self
->close_press
= self
->desk_press
=
182 self
->iconify_press
= self
->shade_press
= FALSE
;
183 self
->max_hover
= self
->close_hover
= self
->desk_hover
=
184 self
->iconify_hover
= self
->shade_hover
= FALSE
;
186 set_theme_statics(self
);
188 return (ObFrame
*)self
;
191 static void set_theme_statics(ObFrame
*self
)
193 /* set colors/appearance/sizes for stuff that doesn't change */
194 XResizeWindow(ob_display
, self
->max
,
195 ob_rr_theme
->button_size
, ob_rr_theme
->button_size
);
196 XResizeWindow(ob_display
, self
->iconify
,
197 ob_rr_theme
->button_size
, ob_rr_theme
->button_size
);
198 XResizeWindow(ob_display
, self
->icon
,
199 ob_rr_theme
->button_size
+ 2, ob_rr_theme
->button_size
+ 2);
200 XResizeWindow(ob_display
, self
->close
,
201 ob_rr_theme
->button_size
, ob_rr_theme
->button_size
);
202 XResizeWindow(ob_display
, self
->desk
,
203 ob_rr_theme
->button_size
, ob_rr_theme
->button_size
);
204 XResizeWindow(ob_display
, self
->shade
,
205 ob_rr_theme
->button_size
, ob_rr_theme
->button_size
);
206 XResizeWindow(ob_display
, self
->tltresize
,
207 ob_rr_theme
->grip_width
, ob_rr_theme
->paddingy
+ 1);
208 XResizeWindow(ob_display
, self
->trtresize
,
209 ob_rr_theme
->grip_width
, ob_rr_theme
->paddingy
+ 1);
210 XResizeWindow(ob_display
, self
->tllresize
,
211 ob_rr_theme
->paddingx
+ 1, ob_rr_theme
->title_height
);
212 XResizeWindow(ob_display
, self
->trrresize
,
213 ob_rr_theme
->paddingx
+ 1, ob_rr_theme
->title_height
);
215 /* set up the dynamic appearances */
216 self
->a_unfocused_title
= RrAppearanceCopy(ob_rr_theme
->a_unfocused_title
);
217 self
->a_focused_title
= RrAppearanceCopy(ob_rr_theme
->a_focused_title
);
218 self
->a_unfocused_label
= RrAppearanceCopy(ob_rr_theme
->a_unfocused_label
);
219 self
->a_focused_label
= RrAppearanceCopy(ob_rr_theme
->a_focused_label
);
220 self
->a_unfocused_handle
=
221 RrAppearanceCopy(ob_rr_theme
->a_unfocused_handle
);
222 self
->a_focused_handle
= RrAppearanceCopy(ob_rr_theme
->a_focused_handle
);
223 self
->a_icon
= RrAppearanceCopy(ob_rr_theme
->a_icon
);
226 static void free_theme_statics(ObFrame
*self
)
228 RrAppearanceFree(self
->a_unfocused_title
);
229 RrAppearanceFree(self
->a_focused_title
);
230 RrAppearanceFree(self
->a_unfocused_label
);
231 RrAppearanceFree(self
->a_focused_label
);
232 RrAppearanceFree(self
->a_unfocused_handle
);
233 RrAppearanceFree(self
->a_focused_handle
);
234 RrAppearanceFree(self
->a_icon
);
237 void frame_free(ObFrame
*self
)
239 free_theme_statics(self
);
241 XDestroyWindow(ob_display
, self
->window
);
243 XFreeColormap(ob_display
, self
->colormap
);
248 void frame_show(ObFrame
*self
)
250 if (!self
->visible
) {
251 self
->visible
= TRUE
;
252 XMapWindow(ob_display
, self
->client
->window
);
253 XMapWindow(ob_display
, self
->window
);
257 void frame_hide(ObFrame
*self
)
260 self
->visible
= FALSE
;
261 if (!frame_iconify_animating(self
))
262 XUnmapWindow(ob_display
, self
->window
);
263 /* we unmap the client itself so that we can get MapRequest
264 events, and because the ICCCM tells us to! */
265 XUnmapWindow(ob_display
, self
->client
->window
);
266 self
->client
->ignore_unmaps
+= 1;
270 void frame_adjust_theme(ObFrame
*self
)
272 free_theme_statics(self
);
273 set_theme_statics(self
);
276 void frame_adjust_shape(ObFrame
*self
)
282 if (!self
->client
->shaped
) {
283 /* clear the shape on the frame window */
284 XShapeCombineMask(ob_display
, self
->window
, ShapeBounding
,
289 /* make the frame's shape match the clients */
290 XShapeCombineShape(ob_display
, self
->window
, ShapeBounding
,
293 self
->client
->window
,
294 ShapeBounding
, ShapeSet
);
297 if (self
->decorations
& OB_FRAME_DECOR_TITLEBAR
) {
300 xrect
[0].width
= self
->area
.width
;
301 xrect
[0].height
= ob_rr_theme
->title_height
+
302 self
->bwidth
+ self
->rbwidth
;
306 if (self
->decorations
& OB_FRAME_DECOR_HANDLE
&&
307 ob_rr_theme
->handle_height
> 0)
310 xrect
[1].y
= FRAME_HANDLE_Y(self
);
311 xrect
[1].width
= self
->area
.width
;
312 xrect
[1].height
= ob_rr_theme
->handle_height
+
317 XShapeCombineRectangles(ob_display
, self
->window
,
318 ShapeBounding
, 0, 0, xrect
, num
,
319 ShapeUnion
, Unsorted
);
324 void frame_adjust_area(ObFrame
*self
, gboolean moved
,
325 gboolean resized
, gboolean fake
)
329 oldsize
= self
->size
;
332 self
->decorations
= self
->client
->decorations
;
333 self
->max_horz
= self
->client
->max_horz
;
335 if (self
->decorations
& OB_FRAME_DECOR_BORDER
) {
336 self
->bwidth
= ob_rr_theme
->fbwidth
;
337 self
->cbwidth_x
= ob_rr_theme
->cbwidthx
;
338 self
->cbwidth_y
= ob_rr_theme
->cbwidthy
;
340 self
->bwidth
= self
->cbwidth_x
= self
->cbwidth_y
= 0;
342 self
->rbwidth
= self
->bwidth
;
343 self
->leftb
= self
->rightb
= TRUE
;
345 if (self
->max_horz
) {
346 self
->leftb
= self
->rightb
= FALSE
;
350 self
->width
= self
->client
->area
.width
+ self
->cbwidth_x
* 2;
351 self
->width
= MAX(self
->width
, 1); /* no lower than 1 */
353 STRUT_SET(self
->size
,
354 self
->cbwidth_x
+ (self
->leftb
? self
->bwidth
: 0),
355 self
->cbwidth_y
+ self
->bwidth
,
356 self
->cbwidth_x
+ (self
->rightb
? self
->bwidth
: 0),
357 self
->cbwidth_y
+ self
->bwidth
);
359 if (self
->decorations
& OB_FRAME_DECOR_TITLEBAR
)
360 self
->size
.top
+= ob_rr_theme
->title_height
+ self
->rbwidth
;
361 if (self
->decorations
& OB_FRAME_DECOR_HANDLE
&&
362 ob_rr_theme
->handle_height
> 0)
364 self
->size
.bottom
+= ob_rr_theme
->handle_height
+ self
->bwidth
;
367 /* position/size and map/unmap all the windows */
371 XMoveResizeWindow(ob_display
, self
->titletop
,
372 ob_rr_theme
->grip_width
+ self
->bwidth
, 0,
373 self
->client
->area
.width
+
374 self
->cbwidth_x
* 2 + self
->bwidth
* 2 -
375 (ob_rr_theme
->grip_width
+ self
->bwidth
) * 2,
377 XMoveResizeWindow(ob_display
, self
->titletopleft
,
379 ob_rr_theme
->grip_width
+ self
->bwidth
,
381 XMoveResizeWindow(ob_display
, self
->titletopright
,
382 self
->client
->area
.width
+
383 self
->cbwidth_x
* 2 + self
->bwidth
* 2 -
384 ob_rr_theme
->grip_width
- self
->bwidth
,
386 ob_rr_theme
->grip_width
+ self
->bwidth
,
389 XMoveResizeWindow(ob_display
, self
->titleleft
,
393 ob_rr_theme
->grip_width
:
394 self
->size
.top
- self
->bwidth
));
395 XMoveResizeWindow(ob_display
, self
->titleright
,
396 self
->client
->area
.width
+
397 self
->cbwidth_x
* 2 + self
->bwidth
,
401 ob_rr_theme
->grip_width
:
402 self
->size
.top
- self
->bwidth
));
404 XMapWindow(ob_display
, self
->titletop
);
405 XMapWindow(ob_display
, self
->titletopleft
);
406 XMapWindow(ob_display
, self
->titletopright
);
407 XMapWindow(ob_display
, self
->titleleft
);
408 XMapWindow(ob_display
, self
->titleright
);
410 if (self
->decorations
& OB_FRAME_DECOR_TITLEBAR
&&
413 XMoveResizeWindow(ob_display
, self
->titlebottom
,
415 ob_rr_theme
->title_height
+ self
->bwidth
,
416 self
->client
->area
.width
+
420 XMapWindow(ob_display
, self
->titlebottom
);
422 XUnmapWindow(ob_display
, self
->titlebottom
);
424 XUnmapWindow(ob_display
, self
->titlebottom
);
426 XUnmapWindow(ob_display
, self
->titletop
);
427 XUnmapWindow(ob_display
, self
->titletopleft
);
428 XUnmapWindow(ob_display
, self
->titletopright
);
429 XUnmapWindow(ob_display
, self
->titleleft
);
430 XUnmapWindow(ob_display
, self
->titleright
);
433 if (self
->decorations
& OB_FRAME_DECOR_TITLEBAR
) {
434 XMoveResizeWindow(ob_display
, self
->title
,
435 self
->bwidth
, self
->bwidth
,
436 self
->width
, ob_rr_theme
->title_height
);
438 XMapWindow(ob_display
, self
->title
);
440 if (self
->decorations
& OB_FRAME_DECOR_GRIPS
) {
441 XMoveResizeWindow(ob_display
, self
->topresize
,
442 ob_rr_theme
->grip_width
+ self
->bwidth
,
444 self
->width
- (ob_rr_theme
->grip_width
+
446 ob_rr_theme
->paddingy
+ 1);
448 XMoveWindow(ob_display
, self
->tltresize
, 0, 0);
449 XMoveWindow(ob_display
, self
->tllresize
, 0, 0);
450 XMoveWindow(ob_display
, self
->trtresize
,
451 self
->width
- ob_rr_theme
->grip_width
, 0);
452 XMoveWindow(ob_display
, self
->trrresize
,
453 self
->width
- ob_rr_theme
->paddingx
- 1, 0);
455 XMapWindow(ob_display
, self
->topresize
);
456 XMapWindow(ob_display
, self
->tltresize
);
457 XMapWindow(ob_display
, self
->tllresize
);
458 XMapWindow(ob_display
, self
->trtresize
);
459 XMapWindow(ob_display
, self
->trrresize
);
461 XUnmapWindow(ob_display
, self
->topresize
);
462 XUnmapWindow(ob_display
, self
->tltresize
);
463 XUnmapWindow(ob_display
, self
->tllresize
);
464 XUnmapWindow(ob_display
, self
->trtresize
);
465 XUnmapWindow(ob_display
, self
->trrresize
);
468 XUnmapWindow(ob_display
, self
->title
);
471 if ((self
->decorations
& OB_FRAME_DECOR_TITLEBAR
))
472 /* layout the title bar elements */
477 XMoveResizeWindow(ob_display
, self
->handlebottom
,
478 ob_rr_theme
->grip_width
+
480 self
->size
.top
+ self
->client
->area
.height
+
481 self
->size
.bottom
- self
->bwidth
,
482 self
->width
- (ob_rr_theme
->grip_width
+
486 XMoveResizeWindow(ob_display
, self
->lgripleft
,
488 self
->size
.top
+ self
->client
->area
.height
+
491 ob_rr_theme
->grip_width
:
495 ob_rr_theme
->grip_width
:
497 XMoveResizeWindow(ob_display
, self
->rgripright
,
498 self
->size
.left
+ self
->client
->area
.width
+
499 self
->size
.right
- self
->bwidth
,
500 self
->size
.top
+ self
->client
->area
.height
+
503 ob_rr_theme
->grip_width
:
507 ob_rr_theme
->grip_width
:
510 XMoveResizeWindow(ob_display
, self
->lgripbottom
,
512 self
->size
.top
+ self
->client
->area
.height
+
513 self
->size
.bottom
- self
->bwidth
,
514 ob_rr_theme
->grip_width
+ self
->bwidth
,
516 XMoveResizeWindow(ob_display
, self
->rgripbottom
,
517 self
->size
.left
+ self
->client
->area
.width
+
518 self
->size
.right
- self
->bwidth
* 2 -
519 ob_rr_theme
->grip_width
,
520 self
->size
.top
+ self
->client
->area
.height
+
521 self
->size
.bottom
- self
->bwidth
,
522 ob_rr_theme
->grip_width
+ self
->bwidth
,
525 XMapWindow(ob_display
, self
->handlebottom
);
526 XMapWindow(ob_display
, self
->lgripleft
);
527 XMapWindow(ob_display
, self
->rgripright
);
528 XMapWindow(ob_display
, self
->lgripbottom
);
529 XMapWindow(ob_display
, self
->rgripbottom
);
531 if (self
->decorations
& OB_FRAME_DECOR_HANDLE
&&
532 ob_rr_theme
->handle_height
> 0)
534 XMoveResizeWindow(ob_display
, self
->handletop
,
535 ob_rr_theme
->grip_width
+
537 FRAME_HANDLE_Y(self
),
538 self
->width
- (ob_rr_theme
->grip_width
+
541 XMapWindow(ob_display
, self
->handletop
);
543 if (self
->decorations
& OB_FRAME_DECOR_GRIPS
) {
544 XMoveResizeWindow(ob_display
, self
->handleleft
,
545 ob_rr_theme
->grip_width
,
548 ob_rr_theme
->handle_height
);
549 XMoveResizeWindow(ob_display
, self
->handleright
,
551 ob_rr_theme
->grip_width
-
555 ob_rr_theme
->handle_height
);
557 XMoveResizeWindow(ob_display
, self
->lgriptop
,
559 FRAME_HANDLE_Y(self
),
560 ob_rr_theme
->grip_width
+
563 XMoveResizeWindow(ob_display
, self
->rgriptop
,
565 self
->client
->area
.width
+
566 self
->size
.right
- self
->bwidth
* 2 -
567 ob_rr_theme
->grip_width
,
568 FRAME_HANDLE_Y(self
),
569 ob_rr_theme
->grip_width
+
573 XMapWindow(ob_display
, self
->handleleft
);
574 XMapWindow(ob_display
, self
->handleright
);
575 XMapWindow(ob_display
, self
->lgriptop
);
576 XMapWindow(ob_display
, self
->rgriptop
);
578 XUnmapWindow(ob_display
, self
->handleleft
);
579 XUnmapWindow(ob_display
, self
->handleright
);
580 XUnmapWindow(ob_display
, self
->lgriptop
);
581 XUnmapWindow(ob_display
, self
->rgriptop
);
584 XUnmapWindow(ob_display
, self
->handleleft
);
585 XUnmapWindow(ob_display
, self
->handleright
);
586 XUnmapWindow(ob_display
, self
->lgriptop
);
587 XUnmapWindow(ob_display
, self
->rgriptop
);
589 XUnmapWindow(ob_display
, self
->handletop
);
592 XUnmapWindow(ob_display
, self
->handleleft
);
593 XUnmapWindow(ob_display
, self
->handleright
);
594 XUnmapWindow(ob_display
, self
->lgriptop
);
595 XUnmapWindow(ob_display
, self
->rgriptop
);
597 XUnmapWindow(ob_display
, self
->handletop
);
599 XUnmapWindow(ob_display
, self
->handlebottom
);
600 XUnmapWindow(ob_display
, self
->lgripleft
);
601 XUnmapWindow(ob_display
, self
->rgripright
);
602 XUnmapWindow(ob_display
, self
->lgripbottom
);
603 XUnmapWindow(ob_display
, self
->rgripbottom
);
606 if (self
->decorations
& OB_FRAME_DECOR_HANDLE
&&
607 ob_rr_theme
->handle_height
> 0)
609 XMoveResizeWindow(ob_display
, self
->handle
,
611 FRAME_HANDLE_Y(self
) + self
->bwidth
,
612 self
->width
, ob_rr_theme
->handle_height
);
613 XMapWindow(ob_display
, self
->handle
);
615 if (self
->decorations
& OB_FRAME_DECOR_GRIPS
) {
616 XMoveResizeWindow(ob_display
, self
->lgrip
,
618 ob_rr_theme
->grip_width
,
619 ob_rr_theme
->handle_height
);
620 XMoveResizeWindow(ob_display
, self
->rgrip
,
621 self
->width
- ob_rr_theme
->grip_width
,
623 ob_rr_theme
->grip_width
,
624 ob_rr_theme
->handle_height
);
626 XMapWindow(ob_display
, self
->lgrip
);
627 XMapWindow(ob_display
, self
->rgrip
);
629 XUnmapWindow(ob_display
, self
->lgrip
);
630 XUnmapWindow(ob_display
, self
->rgrip
);
633 XUnmapWindow(ob_display
, self
->handle
);
635 if (self
->bwidth
&& !self
->max_horz
) {
636 XMoveResizeWindow(ob_display
, self
->left
,
638 self
->bwidth
+ ob_rr_theme
->grip_width
,
640 self
->client
->area
.height
+
641 self
->size
.top
+ self
->size
.bottom
-
642 ob_rr_theme
->grip_width
* 2);
643 XMoveResizeWindow(ob_display
, self
->right
,
644 self
->client
->area
.width
+
645 self
->cbwidth_x
* 2 + self
->bwidth
,
646 self
->bwidth
+ ob_rr_theme
->grip_width
,
648 self
->client
->area
.height
+
649 self
->size
.top
+ self
->size
.bottom
-
650 ob_rr_theme
->grip_width
* 2);
652 XMapWindow(ob_display
, self
->left
);
653 XMapWindow(ob_display
, self
->right
);
655 XUnmapWindow(ob_display
, self
->left
);
656 XUnmapWindow(ob_display
, self
->right
);
659 /* move and resize the inner border window which contains the plate
661 XMoveResizeWindow(ob_display
, self
->inner
,
663 self
->size
.top
- self
->cbwidth_y
,
664 self
->client
->area
.width
+
665 self
->cbwidth_x
* 2 +
666 (self
->leftb
? self
->bwidth
: 0) +
667 (self
->rightb
? self
->bwidth
: 0),
668 self
->client
->area
.height
+
669 self
->cbwidth_y
* 2);
672 XMoveWindow(ob_display
, self
->plate
,
673 (self
->leftb
? self
->bwidth
: 0) + self
->cbwidth_x
,
676 /* when the client has StaticGravity, it likes to move around. */
677 XMoveWindow(ob_display
, self
->client
->window
, 0, 0);
681 /* shading can change without being moved or resized */
682 RECT_SET_SIZE(self
->area
,
683 self
->client
->area
.width
+
684 self
->size
.left
+ self
->size
.right
,
685 (self
->client
->shaded
?
686 ob_rr_theme
->title_height
+ self
->bwidth
* 2:
687 self
->client
->area
.height
+
688 self
->size
.top
+ self
->size
.bottom
));
690 if (moved
|| resized
) {
691 /* find the new coordinates, done after setting the frame.size, for
692 frame_client_gravity. */
693 self
->area
.x
= self
->client
->area
.x
;
694 self
->area
.y
= self
->client
->area
.y
;
695 frame_client_gravity(self
, &self
->area
.x
, &self
->area
.y
,
696 self
->client
->area
.width
,
697 self
->client
->area
.height
);
701 if (!frame_iconify_animating(self
))
702 /* move and resize the top level frame.
703 shading can change without being moved or resized.
705 but don't do this during an iconify animation. it will be
706 reflected afterwards.
708 XMoveResizeWindow(ob_display
, self
->window
,
715 framerender_frame(self
);
716 frame_adjust_shape(self
);
719 if (!STRUT_EQUAL(self
->size
, oldsize
)) {
721 vals
[0] = self
->size
.left
;
722 vals
[1] = self
->size
.right
;
723 vals
[2] = self
->size
.top
;
724 vals
[3] = self
->size
.bottom
;
725 PROP_SETA32(self
->client
->window
, net_frame_extents
,
727 PROP_SETA32(self
->client
->window
, kde_net_wm_frame_strut
,
731 /* if this occurs while we are focus cycling, the indicator needs to
733 if (focus_cycle_target
== self
->client
)
734 focus_cycle_draw_indicator(self
->client
);
736 if (resized
&& (self
->decorations
& OB_FRAME_DECOR_TITLEBAR
))
737 XResizeWindow(ob_display
, self
->label
, self
->label_width
,
738 ob_rr_theme
->label_height
);
742 (self
->functions
& OB_CLIENT_FUNC_RESIZE
) !=
743 (self
->client
->functions
& OB_CLIENT_FUNC_RESIZE
))
745 gboolean r
= self
->client
->functions
& OB_CLIENT_FUNC_RESIZE
;
746 XSetWindowAttributes a
;
748 a
.cursor
= ob_cursor(r
? OB_CURSOR_NORTH
: OB_CURSOR_NONE
);
749 XChangeWindowAttributes(ob_display
, self
->topresize
, CWCursor
, &a
);
750 XChangeWindowAttributes(ob_display
, self
->titletop
, CWCursor
, &a
);
751 a
.cursor
= ob_cursor(r
? OB_CURSOR_NORTHWEST
: OB_CURSOR_NONE
);
752 XChangeWindowAttributes(ob_display
, self
->tltresize
, CWCursor
, &a
);
753 XChangeWindowAttributes(ob_display
, self
->tllresize
, CWCursor
, &a
);
754 XChangeWindowAttributes(ob_display
, self
->titletopleft
, CWCursor
, &a
);
755 XChangeWindowAttributes(ob_display
, self
->titleleft
, CWCursor
, &a
);
756 a
.cursor
= ob_cursor(r
? OB_CURSOR_NORTHEAST
: OB_CURSOR_NONE
);
757 XChangeWindowAttributes(ob_display
, self
->trtresize
, CWCursor
, &a
);
758 XChangeWindowAttributes(ob_display
, self
->trrresize
, CWCursor
, &a
);
759 XChangeWindowAttributes(ob_display
, self
->titletopright
, CWCursor
, &a
);
760 XChangeWindowAttributes(ob_display
, self
->titleright
, CWCursor
, &a
);
761 a
.cursor
= ob_cursor(r
? OB_CURSOR_WEST
: OB_CURSOR_NONE
);
762 XChangeWindowAttributes(ob_display
, self
->left
, CWCursor
, &a
);
763 a
.cursor
= ob_cursor(r
? OB_CURSOR_EAST
: OB_CURSOR_NONE
);
764 XChangeWindowAttributes(ob_display
, self
->right
, CWCursor
, &a
);
765 a
.cursor
= ob_cursor(r
? OB_CURSOR_SOUTH
: OB_CURSOR_NONE
);
766 XChangeWindowAttributes(ob_display
, self
->handle
, CWCursor
, &a
);
767 XChangeWindowAttributes(ob_display
, self
->handletop
, CWCursor
, &a
);
768 XChangeWindowAttributes(ob_display
, self
->handlebottom
, CWCursor
, &a
);
769 a
.cursor
= ob_cursor(r
? OB_CURSOR_SOUTHWEST
: OB_CURSOR_NONE
);
770 XChangeWindowAttributes(ob_display
, self
->lgrip
, CWCursor
, &a
);
771 XChangeWindowAttributes(ob_display
, self
->handleleft
, CWCursor
, &a
);
772 XChangeWindowAttributes(ob_display
, self
->lgripleft
, CWCursor
, &a
);
773 XChangeWindowAttributes(ob_display
, self
->lgriptop
, CWCursor
, &a
);
774 XChangeWindowAttributes(ob_display
, self
->lgripbottom
, CWCursor
, &a
);
775 a
.cursor
= ob_cursor(r
? OB_CURSOR_SOUTHEAST
: OB_CURSOR_NONE
);
776 XChangeWindowAttributes(ob_display
, self
->rgrip
, CWCursor
, &a
);
777 XChangeWindowAttributes(ob_display
, self
->handleright
, CWCursor
, &a
);
778 XChangeWindowAttributes(ob_display
, self
->rgripright
, CWCursor
, &a
);
779 XChangeWindowAttributes(ob_display
, self
->rgriptop
, CWCursor
, &a
);
780 XChangeWindowAttributes(ob_display
, self
->rgripbottom
, CWCursor
, &a
);
782 self
->functions
= self
->client
->functions
;
786 void frame_adjust_client_area(ObFrame
*self
)
788 /* resize the plate */
789 XResizeWindow(ob_display
, self
->plate
,
790 self
->client
->area
.width
, self
->client
->area
.height
);
793 void frame_adjust_state(ObFrame
*self
)
795 framerender_frame(self
);
798 void frame_adjust_focus(ObFrame
*self
, gboolean hilite
)
800 self
->focused
= hilite
;
801 framerender_frame(self
);
805 void frame_adjust_title(ObFrame
*self
)
807 framerender_frame(self
);
810 void frame_adjust_icon(ObFrame
*self
)
812 framerender_frame(self
);
815 void frame_grab_client(ObFrame
*self
)
817 /* reparent the client to the frame */
818 XReparentWindow(ob_display
, self
->client
->window
, self
->plate
, 0, 0);
821 When reparenting the client window, it is usually not mapped yet, since
822 this occurs from a MapRequest. However, in the case where Openbox is
823 starting up, the window is already mapped, so we'll see unmap events for
824 it. There are 2 unmap events generated that we see, one with the 'event'
825 member set the root window, and one set to the client, but both get
826 handled and need to be ignored.
828 if (ob_state() == OB_STATE_STARTING
)
829 self
->client
->ignore_unmaps
+= 2;
831 /* select the event mask on the client's parent (to receive config/map
832 req's) the ButtonPress is to catch clicks on the client border */
833 XSelectInput(ob_display
, self
->plate
, PLATE_EVENTMASK
);
835 /* map the client so it maps when the frame does */
836 XMapWindow(ob_display
, self
->client
->window
);
838 /* set all the windows for the frame in the window_map */
839 g_hash_table_insert(window_map
, &self
->window
, self
->client
);
840 g_hash_table_insert(window_map
, &self
->plate
, self
->client
);
841 g_hash_table_insert(window_map
, &self
->inner
, self
->client
);
842 g_hash_table_insert(window_map
, &self
->title
, self
->client
);
843 g_hash_table_insert(window_map
, &self
->label
, self
->client
);
844 g_hash_table_insert(window_map
, &self
->max
, self
->client
);
845 g_hash_table_insert(window_map
, &self
->close
, self
->client
);
846 g_hash_table_insert(window_map
, &self
->desk
, self
->client
);
847 g_hash_table_insert(window_map
, &self
->shade
, self
->client
);
848 g_hash_table_insert(window_map
, &self
->icon
, self
->client
);
849 g_hash_table_insert(window_map
, &self
->iconify
, self
->client
);
850 g_hash_table_insert(window_map
, &self
->handle
, self
->client
);
851 g_hash_table_insert(window_map
, &self
->lgrip
, self
->client
);
852 g_hash_table_insert(window_map
, &self
->rgrip
, self
->client
);
853 g_hash_table_insert(window_map
, &self
->topresize
, self
->client
);
854 g_hash_table_insert(window_map
, &self
->tltresize
, self
->client
);
855 g_hash_table_insert(window_map
, &self
->tllresize
, self
->client
);
856 g_hash_table_insert(window_map
, &self
->trtresize
, self
->client
);
857 g_hash_table_insert(window_map
, &self
->trrresize
, self
->client
);
858 g_hash_table_insert(window_map
, &self
->left
, self
->client
);
859 g_hash_table_insert(window_map
, &self
->right
, self
->client
);
860 g_hash_table_insert(window_map
, &self
->titleleft
, self
->client
);
861 g_hash_table_insert(window_map
, &self
->titletop
, self
->client
);
862 g_hash_table_insert(window_map
, &self
->titletopleft
, self
->client
);
863 g_hash_table_insert(window_map
, &self
->titletopright
, self
->client
);
864 g_hash_table_insert(window_map
, &self
->titleright
, self
->client
);
865 g_hash_table_insert(window_map
, &self
->titlebottom
, self
->client
);
866 g_hash_table_insert(window_map
, &self
->handleleft
, self
->client
);
867 g_hash_table_insert(window_map
, &self
->handletop
, self
->client
);
868 g_hash_table_insert(window_map
, &self
->handleright
, self
->client
);
869 g_hash_table_insert(window_map
, &self
->handlebottom
, self
->client
);
870 g_hash_table_insert(window_map
, &self
->lgripleft
, self
->client
);
871 g_hash_table_insert(window_map
, &self
->lgriptop
, self
->client
);
872 g_hash_table_insert(window_map
, &self
->lgripbottom
, self
->client
);
873 g_hash_table_insert(window_map
, &self
->rgripright
, self
->client
);
874 g_hash_table_insert(window_map
, &self
->rgriptop
, self
->client
);
875 g_hash_table_insert(window_map
, &self
->rgripbottom
, self
->client
);
878 void frame_release_client(ObFrame
*self
)
881 gboolean reparent
= TRUE
;
883 /* if there was any animation going on, kill it */
884 ob_main_loop_timeout_remove_data(ob_main_loop
, frame_animate_iconify
,
887 /* check if the app has already reparented its window away */
888 while (XCheckTypedWindowEvent(ob_display
, self
->client
->window
,
889 ReparentNotify
, &ev
))
891 /* This check makes sure we don't catch our own reparent action to
892 our frame window. This doesn't count as the app reparenting itself
895 Reparent events that are generated by us are just discarded here.
896 They are of no consequence to us anyhow.
898 if (ev
.xreparent
.parent
!= self
->plate
) {
900 XPutBackEvent(ob_display
, &ev
);
906 /* according to the ICCCM - if the client doesn't reparent itself,
907 then we will reparent the window to root for them */
908 XReparentWindow(ob_display
, self
->client
->window
,
909 RootWindow(ob_display
, ob_screen
),
910 self
->client
->area
.x
,
911 self
->client
->area
.y
);
914 /* remove all the windows for the frame from the window_map */
915 g_hash_table_remove(window_map
, &self
->window
);
916 g_hash_table_remove(window_map
, &self
->plate
);
917 g_hash_table_remove(window_map
, &self
->inner
);
918 g_hash_table_remove(window_map
, &self
->title
);
919 g_hash_table_remove(window_map
, &self
->label
);
920 g_hash_table_remove(window_map
, &self
->max
);
921 g_hash_table_remove(window_map
, &self
->close
);
922 g_hash_table_remove(window_map
, &self
->desk
);
923 g_hash_table_remove(window_map
, &self
->shade
);
924 g_hash_table_remove(window_map
, &self
->icon
);
925 g_hash_table_remove(window_map
, &self
->iconify
);
926 g_hash_table_remove(window_map
, &self
->handle
);
927 g_hash_table_remove(window_map
, &self
->lgrip
);
928 g_hash_table_remove(window_map
, &self
->rgrip
);
929 g_hash_table_remove(window_map
, &self
->topresize
);
930 g_hash_table_remove(window_map
, &self
->tltresize
);
931 g_hash_table_remove(window_map
, &self
->tllresize
);
932 g_hash_table_remove(window_map
, &self
->trtresize
);
933 g_hash_table_remove(window_map
, &self
->trrresize
);
934 g_hash_table_remove(window_map
, &self
->left
);
935 g_hash_table_remove(window_map
, &self
->right
);
936 g_hash_table_remove(window_map
, &self
->titleleft
);
937 g_hash_table_remove(window_map
, &self
->titletop
);
938 g_hash_table_remove(window_map
, &self
->titletopleft
);
939 g_hash_table_remove(window_map
, &self
->titletopright
);
940 g_hash_table_remove(window_map
, &self
->titleright
);
941 g_hash_table_remove(window_map
, &self
->titlebottom
);
942 g_hash_table_remove(window_map
, &self
->handleleft
);
943 g_hash_table_remove(window_map
, &self
->handletop
);
944 g_hash_table_remove(window_map
, &self
->handleright
);
945 g_hash_table_remove(window_map
, &self
->handlebottom
);
946 g_hash_table_remove(window_map
, &self
->lgripleft
);
947 g_hash_table_remove(window_map
, &self
->lgriptop
);
948 g_hash_table_remove(window_map
, &self
->lgripbottom
);
949 g_hash_table_remove(window_map
, &self
->rgripright
);
950 g_hash_table_remove(window_map
, &self
->rgriptop
);
951 g_hash_table_remove(window_map
, &self
->rgripbottom
);
953 ob_main_loop_timeout_remove_data(ob_main_loop
, flash_timeout
, self
, TRUE
);
956 /* is there anything present between us and the label? */
957 static gboolean
is_button_present(ObFrame
*self
, const gchar
*lc
, gint dir
) {
958 for (; *lc
!= '\0' && lc
>= config_title_layout
; lc
+= dir
) {
959 if (*lc
== ' ') continue; /* it was invalid */
960 if (*lc
== 'N' && self
->decorations
& OB_FRAME_DECOR_ICON
)
962 if (*lc
== 'D' && self
->decorations
& OB_FRAME_DECOR_ALLDESKTOPS
)
964 if (*lc
== 'S' && self
->decorations
& OB_FRAME_DECOR_SHADE
)
966 if (*lc
== 'I' && self
->decorations
& OB_FRAME_DECOR_ICONIFY
)
968 if (*lc
== 'M' && self
->decorations
& OB_FRAME_DECOR_MAXIMIZE
)
970 if (*lc
== 'C' && self
->decorations
& OB_FRAME_DECOR_CLOSE
)
972 if (*lc
== 'L') return FALSE
;
977 static void layout_title(ObFrame
*self
)
982 const gint bwidth
= ob_rr_theme
->button_size
+ ob_rr_theme
->paddingx
+ 1;
983 /* position of the left most button */
984 const gint left
= ob_rr_theme
->paddingx
+ 1;
985 /* position of the right most button */
986 const gint right
= self
->width
- bwidth
;
988 /* turn them all off */
989 self
->icon_on
= self
->desk_on
= self
->shade_on
= self
->iconify_on
=
990 self
->max_on
= self
->close_on
= self
->label_on
= FALSE
;
991 self
->label_width
= self
->width
- (ob_rr_theme
->paddingx
+ 1) * 2;
992 self
->leftmost
= self
->rightmost
= OB_FRAME_CONTEXT_NONE
;
994 /* figure out what's being show, find each element's position, and the
997 do the ones before the label, then after the label,
998 i will be +1 the first time through when working to the left,
999 and -1 the second time through when working to the right */
1000 for (i
= 1; i
>= -1; i
-=2) {
1002 ObFrameContext
*firstcon
;
1006 lc
= config_title_layout
;
1007 firstcon
= &self
->leftmost
;
1010 lc
= config_title_layout
+ strlen(config_title_layout
)-1;
1011 firstcon
= &self
->rightmost
;
1014 /* stop at the end of the string (or the label, which calls break) */
1015 for (; *lc
!= '\0' && lc
>= config_title_layout
; lc
+=i
) {
1018 self
->label_on
= TRUE
;
1021 break; /* break the for loop, do other side of label */
1022 } else if (*lc
== 'N') {
1023 if (firstcon
) *firstcon
= OB_FRAME_CONTEXT_ICON
;
1024 if ((self
->icon_on
= is_button_present(self
, lc
, i
))) {
1025 /* icon is bigger than buttons */
1026 self
->label_width
-= bwidth
+ 2;
1028 x
+= i
* (bwidth
+ 2);
1030 } else if (*lc
== 'D') {
1031 if (firstcon
) *firstcon
= OB_FRAME_CONTEXT_ALLDESKTOPS
;
1032 if ((self
->desk_on
= is_button_present(self
, lc
, i
))) {
1033 self
->label_width
-= bwidth
;
1037 } else if (*lc
== 'S') {
1038 if (firstcon
) *firstcon
= OB_FRAME_CONTEXT_SHADE
;
1039 if ((self
->shade_on
= is_button_present(self
, lc
, i
))) {
1040 self
->label_width
-= bwidth
;
1044 } else if (*lc
== 'I') {
1045 if (firstcon
) *firstcon
= OB_FRAME_CONTEXT_ICONIFY
;
1046 if ((self
->iconify_on
= is_button_present(self
, lc
, i
))) {
1047 self
->label_width
-= bwidth
;
1048 self
->iconify_x
= x
;
1051 } else if (*lc
== 'M') {
1052 if (firstcon
) *firstcon
= OB_FRAME_CONTEXT_MAXIMIZE
;
1053 if ((self
->max_on
= is_button_present(self
, lc
, i
))) {
1054 self
->label_width
-= bwidth
;
1058 } else if (*lc
== 'C') {
1059 if (firstcon
) *firstcon
= OB_FRAME_CONTEXT_CLOSE
;
1060 if ((self
->close_on
= is_button_present(self
, lc
, i
))) {
1061 self
->label_width
-= bwidth
;
1066 continue; /* don't set firstcon */
1071 /* position and map the elements */
1072 if (self
->icon_on
) {
1073 XMapWindow(ob_display
, self
->icon
);
1074 XMoveWindow(ob_display
, self
->icon
, self
->icon_x
,
1075 ob_rr_theme
->paddingy
);
1077 XUnmapWindow(ob_display
, self
->icon
);
1079 if (self
->desk_on
) {
1080 XMapWindow(ob_display
, self
->desk
);
1081 XMoveWindow(ob_display
, self
->desk
, self
->desk_x
,
1082 ob_rr_theme
->paddingy
+ 1);
1084 XUnmapWindow(ob_display
, self
->desk
);
1086 if (self
->shade_on
) {
1087 XMapWindow(ob_display
, self
->shade
);
1088 XMoveWindow(ob_display
, self
->shade
, self
->shade_x
,
1089 ob_rr_theme
->paddingy
+ 1);
1091 XUnmapWindow(ob_display
, self
->shade
);
1093 if (self
->iconify_on
) {
1094 XMapWindow(ob_display
, self
->iconify
);
1095 XMoveWindow(ob_display
, self
->iconify
, self
->iconify_x
,
1096 ob_rr_theme
->paddingy
+ 1);
1098 XUnmapWindow(ob_display
, self
->iconify
);
1101 XMapWindow(ob_display
, self
->max
);
1102 XMoveWindow(ob_display
, self
->max
, self
->max_x
,
1103 ob_rr_theme
->paddingy
+ 1);
1105 XUnmapWindow(ob_display
, self
->max
);
1107 if (self
->close_on
) {
1108 XMapWindow(ob_display
, self
->close
);
1109 XMoveWindow(ob_display
, self
->close
, self
->close_x
,
1110 ob_rr_theme
->paddingy
+ 1);
1112 XUnmapWindow(ob_display
, self
->close
);
1114 if (self
->label_on
) {
1115 self
->label_width
= MAX(1, self
->label_width
); /* no lower than 1 */
1116 XMapWindow(ob_display
, self
->label
);
1117 XMoveWindow(ob_display
, self
->label
, self
->label_x
,
1118 ob_rr_theme
->paddingy
);
1120 XUnmapWindow(ob_display
, self
->label
);
1123 ObFrameContext
frame_context_from_string(const gchar
*name
)
1125 if (!g_ascii_strcasecmp("Desktop", name
))
1126 return OB_FRAME_CONTEXT_DESKTOP
;
1127 else if (!g_ascii_strcasecmp("Root", name
))
1128 return OB_FRAME_CONTEXT_ROOT
;
1129 else if (!g_ascii_strcasecmp("Client", name
))
1130 return OB_FRAME_CONTEXT_CLIENT
;
1131 else if (!g_ascii_strcasecmp("Titlebar", name
))
1132 return OB_FRAME_CONTEXT_TITLEBAR
;
1133 else if (!g_ascii_strcasecmp("Frame", name
))
1134 return OB_FRAME_CONTEXT_FRAME
;
1135 else if (!g_ascii_strcasecmp("TLCorner", name
))
1136 return OB_FRAME_CONTEXT_TLCORNER
;
1137 else if (!g_ascii_strcasecmp("TRCorner", name
))
1138 return OB_FRAME_CONTEXT_TRCORNER
;
1139 else if (!g_ascii_strcasecmp("BLCorner", name
))
1140 return OB_FRAME_CONTEXT_BLCORNER
;
1141 else if (!g_ascii_strcasecmp("BRCorner", name
))
1142 return OB_FRAME_CONTEXT_BRCORNER
;
1143 else if (!g_ascii_strcasecmp("Top", name
))
1144 return OB_FRAME_CONTEXT_TOP
;
1145 else if (!g_ascii_strcasecmp("Bottom", name
))
1146 return OB_FRAME_CONTEXT_BOTTOM
;
1147 else if (!g_ascii_strcasecmp("Left", name
))
1148 return OB_FRAME_CONTEXT_LEFT
;
1149 else if (!g_ascii_strcasecmp("Right", name
))
1150 return OB_FRAME_CONTEXT_RIGHT
;
1151 else if (!g_ascii_strcasecmp("Maximize", name
))
1152 return OB_FRAME_CONTEXT_MAXIMIZE
;
1153 else if (!g_ascii_strcasecmp("AllDesktops", name
))
1154 return OB_FRAME_CONTEXT_ALLDESKTOPS
;
1155 else if (!g_ascii_strcasecmp("Shade", name
))
1156 return OB_FRAME_CONTEXT_SHADE
;
1157 else if (!g_ascii_strcasecmp("Iconify", name
))
1158 return OB_FRAME_CONTEXT_ICONIFY
;
1159 else if (!g_ascii_strcasecmp("Icon", name
))
1160 return OB_FRAME_CONTEXT_ICON
;
1161 else if (!g_ascii_strcasecmp("Close", name
))
1162 return OB_FRAME_CONTEXT_CLOSE
;
1163 else if (!g_ascii_strcasecmp("MoveResize", name
))
1164 return OB_FRAME_CONTEXT_MOVE_RESIZE
;
1165 return OB_FRAME_CONTEXT_NONE
;
1168 ObFrameContext
frame_context(ObClient
*client
, Window win
, gint x
, gint y
)
1172 if (moveresize_in_progress
)
1173 return OB_FRAME_CONTEXT_MOVE_RESIZE
;
1175 if (win
== RootWindow(ob_display
, ob_screen
))
1176 return OB_FRAME_CONTEXT_ROOT
;
1177 if (client
== NULL
) return OB_FRAME_CONTEXT_NONE
;
1178 if (win
== client
->window
) {
1179 /* conceptually, this is the desktop, as far as users are
1181 if (client
->type
== OB_CLIENT_TYPE_DESKTOP
)
1182 return OB_FRAME_CONTEXT_DESKTOP
;
1183 return OB_FRAME_CONTEXT_CLIENT
;
1186 self
= client
->frame
;
1187 if (win
== self
->inner
|| win
== self
->plate
) {
1188 /* conceptually, this is the desktop, as far as users are
1190 if (client
->type
== OB_CLIENT_TYPE_DESKTOP
)
1191 return OB_FRAME_CONTEXT_DESKTOP
;
1192 return OB_FRAME_CONTEXT_CLIENT
;
1195 if (win
== self
->title
) {
1196 /* when the user clicks in the corners of the titlebar and the client
1197 is fully maximized, then treat it like they clicked in the
1198 button that is there */
1199 if (self
->client
->max_horz
&& self
->client
->max_vert
&&
1200 y
< ob_rr_theme
->paddingy
+ 1 + ob_rr_theme
->button_size
)
1202 if (x
< ((ob_rr_theme
->paddingx
+ 1) * 2 +
1203 ob_rr_theme
->button_size
)) {
1204 if (self
->leftmost
!= OB_FRAME_CONTEXT_NONE
)
1205 return self
->leftmost
;
1207 else if (x
> (self
->width
-
1208 (ob_rr_theme
->paddingx
+ 1 +
1209 ob_rr_theme
->button_size
)))
1211 if (self
->rightmost
!= OB_FRAME_CONTEXT_NONE
)
1212 return self
->rightmost
;
1215 return OB_FRAME_CONTEXT_TITLEBAR
;
1218 if (win
== self
->window
) return OB_FRAME_CONTEXT_FRAME
;
1219 if (win
== self
->label
) return OB_FRAME_CONTEXT_TITLEBAR
;
1220 if (win
== self
->handle
) return OB_FRAME_CONTEXT_BOTTOM
;
1221 if (win
== self
->handletop
) return OB_FRAME_CONTEXT_BOTTOM
;
1222 if (win
== self
->handlebottom
) return OB_FRAME_CONTEXT_BOTTOM
;
1223 if (win
== self
->handleleft
) return OB_FRAME_CONTEXT_BLCORNER
;
1224 if (win
== self
->lgrip
) return OB_FRAME_CONTEXT_BLCORNER
;
1225 if (win
== self
->lgripleft
) return OB_FRAME_CONTEXT_BLCORNER
;
1226 if (win
== self
->lgriptop
) return OB_FRAME_CONTEXT_BLCORNER
;
1227 if (win
== self
->lgripbottom
) return OB_FRAME_CONTEXT_BLCORNER
;
1228 if (win
== self
->handleright
) return OB_FRAME_CONTEXT_BRCORNER
;
1229 if (win
== self
->rgrip
) return OB_FRAME_CONTEXT_BRCORNER
;
1230 if (win
== self
->rgripright
) return OB_FRAME_CONTEXT_BLCORNER
;
1231 if (win
== self
->rgriptop
) return OB_FRAME_CONTEXT_BLCORNER
;
1232 if (win
== self
->rgripbottom
) return OB_FRAME_CONTEXT_BLCORNER
;
1233 if (win
== self
->titletop
) return OB_FRAME_CONTEXT_TOP
;
1234 if (win
== self
->topresize
) return OB_FRAME_CONTEXT_TOP
;
1235 if (win
== self
->tltresize
) return OB_FRAME_CONTEXT_TLCORNER
;
1236 if (win
== self
->tllresize
) return OB_FRAME_CONTEXT_TLCORNER
;
1237 if (win
== self
->titleleft
) return OB_FRAME_CONTEXT_TLCORNER
;
1238 if (win
== self
->titletopleft
) return OB_FRAME_CONTEXT_TLCORNER
;
1239 if (win
== self
->trtresize
) return OB_FRAME_CONTEXT_TRCORNER
;
1240 if (win
== self
->trrresize
) return OB_FRAME_CONTEXT_TRCORNER
;
1241 if (win
== self
->titleright
) return OB_FRAME_CONTEXT_TRCORNER
;
1242 if (win
== self
->titletopright
) return OB_FRAME_CONTEXT_TRCORNER
;
1243 if (win
== self
->left
) return OB_FRAME_CONTEXT_LEFT
;
1244 if (win
== self
->right
) return OB_FRAME_CONTEXT_RIGHT
;
1245 if (win
== self
->max
) return OB_FRAME_CONTEXT_MAXIMIZE
;
1246 if (win
== self
->iconify
) return OB_FRAME_CONTEXT_ICONIFY
;
1247 if (win
== self
->close
) return OB_FRAME_CONTEXT_CLOSE
;
1248 if (win
== self
->icon
) return OB_FRAME_CONTEXT_ICON
;
1249 if (win
== self
->desk
) return OB_FRAME_CONTEXT_ALLDESKTOPS
;
1250 if (win
== self
->shade
) return OB_FRAME_CONTEXT_SHADE
;
1252 return OB_FRAME_CONTEXT_NONE
;
1255 void frame_client_gravity(ObFrame
*self
, gint
*x
, gint
*y
, gint w
, gint h
)
1258 switch (self
->client
->gravity
) {
1260 case NorthWestGravity
:
1261 case SouthWestGravity
:
1268 *x
-= (self
->size
.left
+ w
) / 2;
1271 case NorthEastGravity
:
1272 case SouthEastGravity
:
1274 *x
-= (self
->size
.left
+ self
->size
.right
+ w
) - 1;
1279 *x
-= self
->size
.left
;
1284 switch (self
->client
->gravity
) {
1286 case NorthWestGravity
:
1287 case NorthEastGravity
:
1294 *y
-= (self
->size
.top
+ h
) / 2;
1297 case SouthWestGravity
:
1298 case SouthEastGravity
:
1300 *y
-= (self
->size
.top
+ self
->size
.bottom
+ h
) - 1;
1305 *y
-= self
->size
.top
;
1310 void frame_frame_gravity(ObFrame
*self
, gint
*x
, gint
*y
, gint w
, gint h
)
1313 switch (self
->client
->gravity
) {
1315 case NorthWestGravity
:
1317 case SouthWestGravity
:
1322 *x
+= (self
->size
.left
+ w
) / 2;
1324 case NorthEastGravity
:
1326 case SouthEastGravity
:
1327 *x
+= (self
->size
.left
+ self
->size
.right
+ w
) - 1;
1331 *x
+= self
->size
.left
;
1336 switch (self
->client
->gravity
) {
1338 case NorthWestGravity
:
1340 case NorthEastGravity
:
1345 *y
+= (self
->size
.top
+ h
) / 2;
1347 case SouthWestGravity
:
1349 case SouthEastGravity
:
1350 *y
+= (self
->size
.top
+ self
->size
.bottom
+ h
) - 1;
1354 *y
+= self
->size
.top
;
1359 static void flash_done(gpointer data
)
1361 ObFrame
*self
= data
;
1363 if (self
->focused
!= self
->flash_on
)
1364 frame_adjust_focus(self
, self
->focused
);
1367 static gboolean
flash_timeout(gpointer data
)
1369 ObFrame
*self
= data
;
1372 g_get_current_time(&now
);
1373 if (now
.tv_sec
> self
->flash_end
.tv_sec
||
1374 (now
.tv_sec
== self
->flash_end
.tv_sec
&&
1375 now
.tv_usec
>= self
->flash_end
.tv_usec
))
1376 self
->flashing
= FALSE
;
1378 if (!self
->flashing
)
1379 return FALSE
; /* we are done */
1381 self
->flash_on
= !self
->flash_on
;
1382 if (!self
->focused
) {
1383 frame_adjust_focus(self
, self
->flash_on
);
1384 self
->focused
= FALSE
;
1387 return TRUE
; /* go again */
1390 void frame_flash_start(ObFrame
*self
)
1392 self
->flash_on
= self
->focused
;
1394 if (!self
->flashing
)
1395 ob_main_loop_timeout_add(ob_main_loop
,
1396 G_USEC_PER_SEC
* 0.6,
1401 g_get_current_time(&self
->flash_end
);
1402 g_time_val_add(&self
->flash_end
, G_USEC_PER_SEC
* 5);
1404 self
->flashing
= TRUE
;
1407 void frame_flash_stop(ObFrame
*self
)
1409 self
->flashing
= FALSE
;
1412 static gulong
frame_animate_iconify_time_left(ObFrame
*self
,
1413 const GTimeVal
*now
)
1416 sec
= self
->iconify_animation_end
.tv_sec
- now
->tv_sec
;
1417 usec
= self
->iconify_animation_end
.tv_usec
- now
->tv_usec
;
1419 usec
+= G_USEC_PER_SEC
;
1422 /* no negative values */
1423 return MAX(sec
* G_USEC_PER_SEC
+ usec
, 0);
1426 static gboolean
frame_animate_iconify(gpointer p
)
1430 gint iconx
, icony
, iconw
;
1433 gboolean iconifying
;
1435 if (self
->client
->icon_geometry
.width
== 0) {
1436 /* there is no icon geometry set so just go straight down */
1437 Rect
*a
= screen_physical_area();
1438 iconx
= self
->area
.x
+ self
->area
.width
/ 2 + 32;
1439 icony
= a
->y
+ a
->width
;
1442 iconx
= self
->client
->icon_geometry
.x
;
1443 icony
= self
->client
->icon_geometry
.y
;
1444 iconw
= self
->client
->icon_geometry
.width
;
1447 iconifying
= self
->iconify_animation_going
> 0;
1449 /* how far do we have left to go ? */
1450 g_get_current_time(&now
);
1451 time
= frame_animate_iconify_time_left(self
, &now
);
1453 if (time
== 0 || iconifying
) {
1454 /* start where the frame is supposed to be */
1457 w
= self
->area
.width
- self
->bwidth
* 2;
1458 h
= self
->area
.height
- self
->bwidth
* 2;
1460 /* start at the icon */
1464 h
= self
->size
.top
; /* just the titlebar */
1471 dx
= self
->area
.x
- iconx
;
1472 dy
= self
->area
.y
- icony
;
1473 dw
= self
->area
.width
- self
->bwidth
* 2 - iconw
;
1474 /* if restoring, we move in the opposite direction */
1475 if (!iconifying
) { dx
= -dx
; dy
= -dy
; dw
= -dw
; }
1477 elapsed
= FRAME_ANIMATE_ICONIFY_TIME
- time
;
1478 x
= x
- (dx
* elapsed
) / FRAME_ANIMATE_ICONIFY_TIME
;
1479 y
= y
- (dy
* elapsed
) / FRAME_ANIMATE_ICONIFY_TIME
;
1480 w
= w
- (dw
* elapsed
) / FRAME_ANIMATE_ICONIFY_TIME
;
1481 h
= self
->size
.top
; /* just the titlebar */
1485 frame_end_iconify_animation(self
);
1487 XMoveResizeWindow(ob_display
, self
->window
, x
, y
, w
, h
);
1491 return time
> 0; /* repeat until we're out of time */
1494 void frame_end_iconify_animation(ObFrame
*self
)
1496 /* see if there is an animation going */
1497 if (self
->iconify_animation_going
== 0) return;
1500 XUnmapWindow(ob_display
, self
->window
);
1502 /* Send a ConfigureNotify when the animation is done, this fixes
1503 KDE's pager showing the window in the wrong place. */
1504 client_reconfigure(self
->client
);
1506 /* we're not animating any more ! */
1507 self
->iconify_animation_going
= 0;
1509 XMoveResizeWindow(ob_display
, self
->window
,
1510 self
->area
.x
, self
->area
.y
,
1511 self
->area
.width
- self
->bwidth
* 2,
1512 self
->area
.height
- self
->bwidth
* 2);
1516 void frame_begin_iconify_animation(ObFrame
*self
, gboolean iconifying
)
1519 gboolean new_anim
= FALSE
;
1520 gboolean set_end
= TRUE
;
1523 /* if there is no titlebar, just don't animate for now
1524 XXX it would be nice tho.. */
1525 if (!(self
->decorations
& OB_FRAME_DECOR_TITLEBAR
))
1528 /* get the current time */
1529 g_get_current_time(&now
);
1531 /* get how long until the end */
1532 time
= FRAME_ANIMATE_ICONIFY_TIME
;
1533 if (self
->iconify_animation_going
) {
1534 if (!!iconifying
!= (self
->iconify_animation_going
> 0)) {
1535 /* animation was already going on in the opposite direction */
1536 time
= time
- frame_animate_iconify_time_left(self
, &now
);
1538 /* animation was already going in the same direction */
1542 self
->iconify_animation_going
= iconifying
? 1 : -1;
1544 /* set the ending time */
1546 self
->iconify_animation_end
.tv_sec
= now
.tv_sec
;
1547 self
->iconify_animation_end
.tv_usec
= now
.tv_usec
;
1548 g_time_val_add(&self
->iconify_animation_end
, time
);
1552 ob_main_loop_timeout_remove_data(ob_main_loop
, frame_animate_iconify
,
1554 ob_main_loop_timeout_add(ob_main_loop
,
1555 FRAME_ANIMATE_ICONIFY_STEP_TIME
,
1556 frame_animate_iconify
, self
,
1557 g_direct_equal
, NULL
);
1559 /* do the first step */
1560 frame_animate_iconify(self
);
1562 /* show it during the animation even if it is not "visible" */
1564 XMapWindow(ob_display
, self
->window
);