1 /* -*- indent-tabs-mode: nil; tab-width: 4; c-basic-offset: 4; -*-
3 frame.c for the Openbox window manager
4 Copyright (c) 2006 Mikael Magnusson
5 Copyright (c) 2003-2007 Dana Jansens
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2 of the License, or
10 (at your option) any later version.
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 See the COPYING file for a copy of the GNU General Public License.
23 #include "extensions.h"
26 #include "framerender.h"
28 #include "focus_cycle.h"
29 #include "focus_cycle_indicator.h"
30 #include "moveresize.h"
32 #include "render/theme.h"
34 #define PLATE_EVENTMASK (SubstructureRedirectMask | FocusChangeMask)
35 #define FRAME_EVENTMASK (EnterWindowMask | LeaveWindowMask | \
36 ButtonPressMask | ButtonReleaseMask)
37 #define ELEMENT_EVENTMASK (ButtonPressMask | ButtonReleaseMask | \
38 ButtonMotionMask | PointerMotionMask | \
39 EnterWindowMask | LeaveWindowMask)
40 /* The inner window does not need enter/leave events.
41 If it does get them, then it needs its own context for enter events
42 because sloppy focus will focus the window when you enter the inner window
44 #define INNER_EVENTMASK (ButtonPressMask)
46 #define FRAME_ANIMATE_ICONIFY_TIME 150000 /* .15 seconds */
47 #define FRAME_ANIMATE_ICONIFY_STEP_TIME (G_USEC_PER_SEC / 60) /* 60 Hz */
49 #define FRAME_HANDLE_Y(f) (f->size.top + f->client->area.height + f->cbwidth_y)
51 static void flash_done(gpointer data
);
52 static gboolean
flash_timeout(gpointer data
);
54 static void layout_title(ObFrame
*self
);
55 static void set_theme_statics(ObFrame
*self
);
56 static void free_theme_statics(ObFrame
*self
);
57 static gboolean
frame_animate_iconify(gpointer self
);
58 static void frame_adjust_cursors(ObFrame
*self
);
60 static Window
createWindow(Window parent
, Visual
*visual
,
61 gulong mask
, XSetWindowAttributes
*attrib
)
63 return XCreateWindow(ob_display
, parent
, 0, 0, 1, 1, 0,
64 (visual
? 32 : RrDepth(ob_rr_inst
)), InputOutput
,
65 (visual
? visual
: RrVisual(ob_rr_inst
)),
70 static Visual
*check_32bit_client(ObClient
*c
)
72 XWindowAttributes wattrib
;
75 /* we're already running at 32 bit depth, yay. we don't need to use their
77 if (RrDepth(ob_rr_inst
) == 32)
80 ret
= XGetWindowAttributes(ob_display
, c
->window
, &wattrib
);
81 g_assert(ret
!= BadDrawable
);
82 g_assert(ret
!= BadWindow
);
84 if (wattrib
.depth
== 32)
85 return wattrib
.visual
;
89 ObFrame
*frame_new(ObClient
*client
)
91 XSetWindowAttributes attrib
;
96 self
= g_new0(ObFrame
, 1);
97 self
->client
= client
;
99 visual
= check_32bit_client(client
);
101 /* create the non-visible decor windows */
105 /* client has a 32-bit visual */
106 mask
|= CWColormap
| CWBackPixel
| CWBorderPixel
;
107 /* create a colormap with the visual */
108 self
->colormap
= attrib
.colormap
=
109 XCreateColormap(ob_display
,
110 RootWindow(ob_display
, ob_screen
),
112 attrib
.background_pixel
= BlackPixel(ob_display
, ob_screen
);
113 attrib
.border_pixel
= BlackPixel(ob_display
, ob_screen
);
115 attrib
.event_mask
= FRAME_EVENTMASK
;
116 self
->window
= createWindow(RootWindow(ob_display
, ob_screen
), visual
,
119 attrib
.event_mask
= INNER_EVENTMASK
;
120 self
->inner
= createWindow(self
->window
, visual
, mask
, &attrib
);
122 mask
&= ~CWEventMask
;
123 self
->plate
= createWindow(self
->inner
, visual
, mask
, &attrib
);
125 /* create the visible decor windows */
129 /* client has a 32-bit visual */
130 mask
|= CWColormap
| CWBackPixel
| CWBorderPixel
;
131 attrib
.colormap
= RrColormap(ob_rr_inst
);
133 attrib
.event_mask
= ELEMENT_EVENTMASK
;
134 self
->title
= createWindow(self
->window
, NULL
, mask
, &attrib
);
135 self
->titleleft
= createWindow(self
->window
, NULL
, mask
, &attrib
);
136 self
->titletop
= createWindow(self
->window
, NULL
, mask
, &attrib
);
137 self
->titletopleft
= createWindow(self
->window
, NULL
, mask
, &attrib
);
138 self
->titletopright
= createWindow(self
->window
, NULL
, mask
, &attrib
);
139 self
->titleright
= createWindow(self
->window
, NULL
, mask
, &attrib
);
140 self
->titlebottom
= createWindow(self
->window
, NULL
, mask
, &attrib
);
142 self
->topresize
= createWindow(self
->title
, NULL
, mask
, &attrib
);
143 self
->tltresize
= createWindow(self
->title
, NULL
, mask
, &attrib
);
144 self
->tllresize
= createWindow(self
->title
, NULL
, mask
, &attrib
);
145 self
->trtresize
= createWindow(self
->title
, NULL
, mask
, &attrib
);
146 self
->trrresize
= createWindow(self
->title
, NULL
, mask
, &attrib
);
148 self
->left
= createWindow(self
->window
, NULL
, mask
, &attrib
);
149 self
->right
= createWindow(self
->window
, NULL
, mask
, &attrib
);
151 self
->label
= createWindow(self
->title
, NULL
, mask
, &attrib
);
152 self
->max
= createWindow(self
->title
, NULL
, mask
, &attrib
);
153 self
->close
= createWindow(self
->title
, NULL
, mask
, &attrib
);
154 self
->desk
= createWindow(self
->title
, NULL
, mask
, &attrib
);
155 self
->shade
= createWindow(self
->title
, NULL
, mask
, &attrib
);
156 self
->icon
= createWindow(self
->title
, NULL
, mask
, &attrib
);
157 self
->iconify
= createWindow(self
->title
, NULL
, mask
, &attrib
);
159 self
->handle
= createWindow(self
->window
, NULL
, mask
, &attrib
);
160 self
->lgrip
= createWindow(self
->handle
, NULL
, mask
, &attrib
);
161 self
->rgrip
= createWindow(self
->handle
, NULL
, mask
, &attrib
);
163 self
->handleleft
= createWindow(self
->handle
, NULL
, mask
, &attrib
);
164 self
->handleright
= createWindow(self
->handle
, NULL
, mask
, &attrib
);
166 self
->handletop
= createWindow(self
->window
, NULL
, mask
, &attrib
);
167 self
->handlebottom
= createWindow(self
->window
, NULL
, mask
, &attrib
);
168 self
->lgripleft
= createWindow(self
->window
, NULL
, mask
, &attrib
);
169 self
->lgriptop
= createWindow(self
->window
, NULL
, mask
, &attrib
);
170 self
->lgripbottom
= createWindow(self
->window
, NULL
, mask
, &attrib
);
171 self
->rgripright
= createWindow(self
->window
, NULL
, mask
, &attrib
);
172 self
->rgriptop
= createWindow(self
->window
, NULL
, mask
, &attrib
);
173 self
->rgripbottom
= createWindow(self
->window
, NULL
, mask
, &attrib
);
175 self
->focused
= FALSE
;
177 /* the other stuff is shown based on decor settings */
178 XMapWindow(ob_display
, self
->plate
);
179 XMapWindow(ob_display
, self
->inner
);
180 XMapWindow(ob_display
, self
->label
);
182 self
->max_press
= self
->close_press
= self
->desk_press
=
183 self
->iconify_press
= self
->shade_press
= FALSE
;
184 self
->max_hover
= self
->close_hover
= self
->desk_hover
=
185 self
->iconify_hover
= self
->shade_hover
= FALSE
;
187 set_theme_statics(self
);
189 return (ObFrame
*)self
;
192 static void set_theme_statics(ObFrame
*self
)
194 /* set colors/appearance/sizes for stuff that doesn't change */
195 XResizeWindow(ob_display
, self
->max
,
196 ob_rr_theme
->button_size
, ob_rr_theme
->button_size
);
197 XResizeWindow(ob_display
, self
->iconify
,
198 ob_rr_theme
->button_size
, ob_rr_theme
->button_size
);
199 XResizeWindow(ob_display
, self
->icon
,
200 ob_rr_theme
->button_size
+ 2, ob_rr_theme
->button_size
+ 2);
201 XResizeWindow(ob_display
, self
->close
,
202 ob_rr_theme
->button_size
, ob_rr_theme
->button_size
);
203 XResizeWindow(ob_display
, self
->desk
,
204 ob_rr_theme
->button_size
, ob_rr_theme
->button_size
);
205 XResizeWindow(ob_display
, self
->shade
,
206 ob_rr_theme
->button_size
, ob_rr_theme
->button_size
);
207 XResizeWindow(ob_display
, self
->tltresize
,
208 ob_rr_theme
->grip_width
, ob_rr_theme
->paddingy
+ 1);
209 XResizeWindow(ob_display
, self
->trtresize
,
210 ob_rr_theme
->grip_width
, ob_rr_theme
->paddingy
+ 1);
211 XResizeWindow(ob_display
, self
->tllresize
,
212 ob_rr_theme
->paddingx
+ 1, ob_rr_theme
->title_height
);
213 XResizeWindow(ob_display
, self
->trrresize
,
214 ob_rr_theme
->paddingx
+ 1, ob_rr_theme
->title_height
);
216 /* set up the dynamic appearances */
217 self
->a_unfocused_title
= RrAppearanceCopy(ob_rr_theme
->a_unfocused_title
);
218 self
->a_focused_title
= RrAppearanceCopy(ob_rr_theme
->a_focused_title
);
219 self
->a_unfocused_label
= RrAppearanceCopy(ob_rr_theme
->a_unfocused_label
);
220 self
->a_focused_label
= RrAppearanceCopy(ob_rr_theme
->a_focused_label
);
221 self
->a_unfocused_handle
=
222 RrAppearanceCopy(ob_rr_theme
->a_unfocused_handle
);
223 self
->a_focused_handle
= RrAppearanceCopy(ob_rr_theme
->a_focused_handle
);
224 self
->a_icon
= RrAppearanceCopy(ob_rr_theme
->a_icon
);
227 static void free_theme_statics(ObFrame
*self
)
229 RrAppearanceFree(self
->a_unfocused_title
);
230 RrAppearanceFree(self
->a_focused_title
);
231 RrAppearanceFree(self
->a_unfocused_label
);
232 RrAppearanceFree(self
->a_focused_label
);
233 RrAppearanceFree(self
->a_unfocused_handle
);
234 RrAppearanceFree(self
->a_focused_handle
);
235 RrAppearanceFree(self
->a_icon
);
238 void frame_free(ObFrame
*self
)
240 free_theme_statics(self
);
242 XDestroyWindow(ob_display
, self
->window
);
244 XFreeColormap(ob_display
, self
->colormap
);
249 void frame_show(ObFrame
*self
)
251 if (!self
->visible
) {
252 self
->visible
= TRUE
;
253 XMapWindow(ob_display
, self
->client
->window
);
254 XMapWindow(ob_display
, self
->plate
);
255 XMapWindow(ob_display
, self
->window
);
259 void frame_hide(ObFrame
*self
)
262 self
->visible
= FALSE
;
263 if (!frame_iconify_animating(self
))
264 XUnmapWindow(ob_display
, self
->window
);
265 /* unmap the plate along with the client. some people (libwnck) look
266 to see if it is unmapped when the client is iconified, for whatever
267 reason. so let's play along... */
268 XUnmapWindow(ob_display
, self
->plate
);
269 /* we unmap the client itself so that we can get MapRequest
270 events, and because the ICCCM tells us to! */
271 XUnmapWindow(ob_display
, self
->client
->window
);
272 self
->client
->ignore_unmaps
+= 1;
276 void frame_adjust_theme(ObFrame
*self
)
278 free_theme_statics(self
);
279 set_theme_statics(self
);
282 void frame_adjust_shape(ObFrame
*self
)
288 if (!self
->client
->shaped
) {
289 /* clear the shape on the frame window */
290 XShapeCombineMask(ob_display
, self
->window
, ShapeBounding
,
295 /* make the frame's shape match the clients */
296 XShapeCombineShape(ob_display
, self
->window
, ShapeBounding
,
299 self
->client
->window
,
300 ShapeBounding
, ShapeSet
);
303 if (self
->decorations
& OB_FRAME_DECOR_TITLEBAR
) {
306 xrect
[0].width
= self
->area
.width
;
307 xrect
[0].height
= ob_rr_theme
->title_height
+
308 self
->bwidth
+ self
->rbwidth
;
312 if (self
->decorations
& OB_FRAME_DECOR_HANDLE
&&
313 ob_rr_theme
->handle_height
> 0)
316 xrect
[1].y
= FRAME_HANDLE_Y(self
);
317 xrect
[1].width
= self
->area
.width
;
318 xrect
[1].height
= ob_rr_theme
->handle_height
+
323 XShapeCombineRectangles(ob_display
, self
->window
,
324 ShapeBounding
, 0, 0, xrect
, num
,
325 ShapeUnion
, Unsorted
);
330 void frame_adjust_area(ObFrame
*self
, gboolean moved
,
331 gboolean resized
, gboolean fake
)
335 oldsize
= self
->size
;
338 /* do this before changing the frame's status like max_horz max_vert */
339 frame_adjust_cursors(self
);
341 self
->functions
= self
->client
->functions
;
342 self
->decorations
= self
->client
->decorations
;
343 self
->max_horz
= self
->client
->max_horz
;
344 self
->max_vert
= self
->client
->max_vert
;
346 if (self
->decorations
& OB_FRAME_DECOR_BORDER
) {
347 self
->bwidth
= ob_rr_theme
->fbwidth
;
348 self
->cbwidth_x
= ob_rr_theme
->cbwidthx
;
349 self
->cbwidth_y
= ob_rr_theme
->cbwidthy
;
351 self
->bwidth
= self
->cbwidth_x
= self
->cbwidth_y
= 0;
353 self
->rbwidth
= self
->bwidth
;
355 if (self
->max_horz
) {
357 self
->width
= self
->client
->area
.width
- self
->bwidth
* 2;
359 self
->width
= self
->client
->area
.width
+ self
->cbwidth_x
* 2;
361 STRUT_SET(self
->size
,
362 self
->cbwidth_x
+ (!self
->max_horz
? self
->bwidth
: 0),
363 self
->cbwidth_y
+ self
->bwidth
,
364 self
->cbwidth_x
+ (!self
->max_horz
? self
->bwidth
: 0),
365 self
->cbwidth_y
+ self
->bwidth
);
367 if (self
->decorations
& OB_FRAME_DECOR_TITLEBAR
)
368 self
->size
.top
+= ob_rr_theme
->title_height
+ self
->rbwidth
;
369 if (self
->decorations
& OB_FRAME_DECOR_HANDLE
&&
370 ob_rr_theme
->handle_height
> 0)
372 self
->size
.bottom
+= ob_rr_theme
->handle_height
+ self
->bwidth
;
375 /* position/size and map/unmap all the windows */
379 XMoveResizeWindow(ob_display
, self
->titletop
,
380 ob_rr_theme
->grip_width
+ self
->bwidth
, 0,
381 /* width + bwidth*2 - bwidth*2 - grips*2 */
382 self
->width
- ob_rr_theme
->grip_width
* 2,
384 XMoveResizeWindow(ob_display
, self
->titletopleft
,
386 ob_rr_theme
->grip_width
+ self
->bwidth
,
388 XMoveResizeWindow(ob_display
, self
->titletopright
,
389 self
->client
->area
.width
+
390 self
->size
.left
+ self
->size
.right
-
391 ob_rr_theme
->grip_width
- self
->bwidth
,
393 ob_rr_theme
->grip_width
+ self
->bwidth
,
396 XMoveResizeWindow(ob_display
, self
->titleleft
,
400 ob_rr_theme
->grip_width
:
401 self
->size
.top
- self
->bwidth
));
402 XMoveResizeWindow(ob_display
, self
->titleright
,
403 self
->client
->area
.width
+
404 self
->size
.left
+ self
->size
.right
-
409 ob_rr_theme
->grip_width
:
410 self
->size
.top
- self
->bwidth
));
412 XMapWindow(ob_display
, self
->titletop
);
413 XMapWindow(ob_display
, self
->titletopleft
);
414 XMapWindow(ob_display
, self
->titletopright
);
415 XMapWindow(ob_display
, self
->titleleft
);
416 XMapWindow(ob_display
, self
->titleright
);
418 if (self
->decorations
& OB_FRAME_DECOR_TITLEBAR
&&
421 XMoveResizeWindow(ob_display
, self
->titlebottom
,
423 ob_rr_theme
->title_height
+ self
->bwidth
,
427 XMapWindow(ob_display
, self
->titlebottom
);
429 XUnmapWindow(ob_display
, self
->titlebottom
);
431 XUnmapWindow(ob_display
, self
->titlebottom
);
433 XUnmapWindow(ob_display
, self
->titletop
);
434 XUnmapWindow(ob_display
, self
->titletopleft
);
435 XUnmapWindow(ob_display
, self
->titletopright
);
436 XUnmapWindow(ob_display
, self
->titleleft
);
437 XUnmapWindow(ob_display
, self
->titleright
);
440 if (self
->decorations
& OB_FRAME_DECOR_TITLEBAR
) {
441 XMoveResizeWindow(ob_display
, self
->title
,
442 self
->bwidth
, self
->bwidth
,
443 self
->width
, ob_rr_theme
->title_height
);
445 XMapWindow(ob_display
, self
->title
);
447 if (self
->decorations
& OB_FRAME_DECOR_GRIPS
) {
448 XMoveResizeWindow(ob_display
, self
->topresize
,
449 ob_rr_theme
->grip_width
+ self
->bwidth
,
451 self
->width
- ob_rr_theme
->grip_width
*2,
452 ob_rr_theme
->paddingy
+ 1);
454 XMoveWindow(ob_display
, self
->tltresize
, self
->bwidth
, 0);
455 XMoveWindow(ob_display
, self
->tllresize
, self
->bwidth
, 0);
456 XMoveWindow(ob_display
, self
->trtresize
,
457 self
->bwidth
+ self
->width
-
458 ob_rr_theme
->grip_width
, 0);
459 XMoveWindow(ob_display
, self
->trrresize
,
460 self
->bwidth
+ self
->width
-
461 ob_rr_theme
->paddingx
- 1, 0);
463 XMapWindow(ob_display
, self
->topresize
);
464 XMapWindow(ob_display
, self
->tltresize
);
465 XMapWindow(ob_display
, self
->tllresize
);
466 XMapWindow(ob_display
, self
->trtresize
);
467 XMapWindow(ob_display
, self
->trrresize
);
469 XUnmapWindow(ob_display
, self
->topresize
);
470 XUnmapWindow(ob_display
, self
->tltresize
);
471 XUnmapWindow(ob_display
, self
->tllresize
);
472 XUnmapWindow(ob_display
, self
->trtresize
);
473 XUnmapWindow(ob_display
, self
->trrresize
);
476 XUnmapWindow(ob_display
, self
->title
);
479 if ((self
->decorations
& OB_FRAME_DECOR_TITLEBAR
))
480 /* layout the title bar elements */
485 XMoveResizeWindow(ob_display
, self
->handlebottom
,
486 ob_rr_theme
->grip_width
+
488 self
->size
.top
+ self
->client
->area
.height
+
489 self
->size
.bottom
- self
->bwidth
,
490 self
->width
- (ob_rr_theme
->grip_width
+
494 XMoveResizeWindow(ob_display
, self
->lgripleft
,
496 self
->size
.top
+ self
->client
->area
.height
+
499 ob_rr_theme
->grip_width
:
503 ob_rr_theme
->grip_width
:
505 XMoveResizeWindow(ob_display
, self
->rgripright
,
506 self
->size
.left
+ self
->client
->area
.width
+
507 self
->size
.right
- self
->bwidth
,
508 self
->size
.top
+ self
->client
->area
.height
+
511 ob_rr_theme
->grip_width
:
515 ob_rr_theme
->grip_width
:
518 XMoveResizeWindow(ob_display
, self
->lgripbottom
,
520 self
->size
.top
+ self
->client
->area
.height
+
521 self
->size
.bottom
- self
->bwidth
,
522 ob_rr_theme
->grip_width
+ self
->bwidth
,
524 XMoveResizeWindow(ob_display
, self
->rgripbottom
,
525 self
->size
.left
+ self
->client
->area
.width
+
526 self
->size
.right
- self
->bwidth
* 2 -
527 ob_rr_theme
->grip_width
,
528 self
->size
.top
+ self
->client
->area
.height
+
529 self
->size
.bottom
- self
->bwidth
,
530 ob_rr_theme
->grip_width
+ self
->bwidth
,
533 XMapWindow(ob_display
, self
->handlebottom
);
534 XMapWindow(ob_display
, self
->lgripleft
);
535 XMapWindow(ob_display
, self
->rgripright
);
536 XMapWindow(ob_display
, self
->lgripbottom
);
537 XMapWindow(ob_display
, self
->rgripbottom
);
539 if (self
->decorations
& OB_FRAME_DECOR_HANDLE
&&
540 ob_rr_theme
->handle_height
> 0)
542 XMoveResizeWindow(ob_display
, self
->handletop
,
543 ob_rr_theme
->grip_width
+
545 FRAME_HANDLE_Y(self
),
546 self
->width
- (ob_rr_theme
->grip_width
+
549 XMapWindow(ob_display
, self
->handletop
);
551 if (self
->decorations
& OB_FRAME_DECOR_GRIPS
) {
552 XMoveResizeWindow(ob_display
, self
->handleleft
,
553 ob_rr_theme
->grip_width
,
556 ob_rr_theme
->handle_height
);
557 XMoveResizeWindow(ob_display
, self
->handleright
,
559 ob_rr_theme
->grip_width
-
563 ob_rr_theme
->handle_height
);
565 XMoveResizeWindow(ob_display
, self
->lgriptop
,
567 FRAME_HANDLE_Y(self
),
568 ob_rr_theme
->grip_width
+
571 XMoveResizeWindow(ob_display
, self
->rgriptop
,
573 self
->client
->area
.width
+
574 self
->size
.right
- self
->bwidth
* 2 -
575 ob_rr_theme
->grip_width
,
576 FRAME_HANDLE_Y(self
),
577 ob_rr_theme
->grip_width
+
581 XMapWindow(ob_display
, self
->handleleft
);
582 XMapWindow(ob_display
, self
->handleright
);
583 XMapWindow(ob_display
, self
->lgriptop
);
584 XMapWindow(ob_display
, self
->rgriptop
);
586 XUnmapWindow(ob_display
, self
->handleleft
);
587 XUnmapWindow(ob_display
, self
->handleright
);
588 XUnmapWindow(ob_display
, self
->lgriptop
);
589 XUnmapWindow(ob_display
, self
->rgriptop
);
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
);
600 XUnmapWindow(ob_display
, self
->handleleft
);
601 XUnmapWindow(ob_display
, self
->handleright
);
602 XUnmapWindow(ob_display
, self
->lgriptop
);
603 XUnmapWindow(ob_display
, self
->rgriptop
);
605 XUnmapWindow(ob_display
, self
->handletop
);
607 XUnmapWindow(ob_display
, self
->handlebottom
);
608 XUnmapWindow(ob_display
, self
->lgripleft
);
609 XUnmapWindow(ob_display
, self
->rgripright
);
610 XUnmapWindow(ob_display
, self
->lgripbottom
);
611 XUnmapWindow(ob_display
, self
->rgripbottom
);
614 if (self
->decorations
& OB_FRAME_DECOR_HANDLE
&&
615 ob_rr_theme
->handle_height
> 0)
617 XMoveResizeWindow(ob_display
, self
->handle
,
619 FRAME_HANDLE_Y(self
) + self
->bwidth
,
620 self
->width
, ob_rr_theme
->handle_height
);
621 XMapWindow(ob_display
, self
->handle
);
623 if (self
->decorations
& OB_FRAME_DECOR_GRIPS
) {
624 XMoveResizeWindow(ob_display
, self
->lgrip
,
626 ob_rr_theme
->grip_width
,
627 ob_rr_theme
->handle_height
);
628 XMoveResizeWindow(ob_display
, self
->rgrip
,
629 self
->width
- ob_rr_theme
->grip_width
,
631 ob_rr_theme
->grip_width
,
632 ob_rr_theme
->handle_height
);
634 XMapWindow(ob_display
, self
->lgrip
);
635 XMapWindow(ob_display
, self
->rgrip
);
637 XUnmapWindow(ob_display
, self
->lgrip
);
638 XUnmapWindow(ob_display
, self
->rgrip
);
641 XUnmapWindow(ob_display
, self
->lgrip
);
642 XUnmapWindow(ob_display
, self
->rgrip
);
644 XUnmapWindow(ob_display
, self
->handle
);
647 if (self
->bwidth
&& !self
->max_horz
) {
648 XMoveResizeWindow(ob_display
, self
->left
,
650 self
->bwidth
+ ob_rr_theme
->grip_width
,
652 self
->client
->area
.height
+
653 self
->size
.top
+ self
->size
.bottom
-
654 ob_rr_theme
->grip_width
* 2);
656 XMapWindow(ob_display
, self
->left
);
658 XUnmapWindow(ob_display
, self
->left
);
660 if (self
->bwidth
&& !self
->max_horz
) {
661 XMoveResizeWindow(ob_display
, self
->right
,
662 self
->client
->area
.width
+
663 self
->cbwidth_x
* 2 + self
->bwidth
,
664 self
->bwidth
+ ob_rr_theme
->grip_width
,
666 self
->client
->area
.height
+
667 self
->size
.top
+ self
->size
.bottom
-
668 ob_rr_theme
->grip_width
* 2);
670 XMapWindow(ob_display
, self
->right
);
672 XUnmapWindow(ob_display
, self
->right
);
674 /* move and resize the inner border window which contains the plate
676 XMoveResizeWindow(ob_display
, self
->inner
,
678 self
->size
.top
- self
->cbwidth_y
,
679 self
->client
->area
.width
+
680 self
->cbwidth_x
* 2 +
681 (!self
->max_horz
? self
->bwidth
* 2 : 0),
682 self
->client
->area
.height
+
683 self
->cbwidth_y
* 2);
686 XMoveWindow(ob_display
, self
->plate
,
687 (!self
->max_horz
? self
->bwidth
: 0) + self
->cbwidth_x
,
690 /* when the client has StaticGravity, it likes to move around. */
691 XMoveWindow(ob_display
, self
->client
->window
, 0, 0);
695 /* shading can change without being moved or resized */
696 RECT_SET_SIZE(self
->area
,
697 self
->client
->area
.width
+
698 self
->size
.left
+ self
->size
.right
,
699 (self
->client
->shaded
?
700 ob_rr_theme
->title_height
+ self
->bwidth
* 2:
701 self
->client
->area
.height
+
702 self
->size
.top
+ self
->size
.bottom
));
704 if ((moved
|| resized
) && !fake
) {
705 /* find the new coordinates, done after setting the frame.size, for
706 frame_client_gravity. */
707 self
->area
.x
= self
->client
->area
.x
;
708 self
->area
.y
= self
->client
->area
.y
;
709 frame_client_gravity(self
, &self
->area
.x
, &self
->area
.y
,
710 self
->client
->area
.width
,
711 self
->client
->area
.height
);
715 if (!frame_iconify_animating(self
))
716 /* move and resize the top level frame.
717 shading can change without being moved or resized.
719 but don't do this during an iconify animation. it will be
720 reflected afterwards.
722 XMoveResizeWindow(ob_display
, self
->window
,
729 framerender_frame(self
);
730 frame_adjust_shape(self
);
733 if (!STRUT_EQUAL(self
->size
, oldsize
)) {
735 vals
[0] = self
->size
.left
;
736 vals
[1] = self
->size
.right
;
737 vals
[2] = self
->size
.top
;
738 vals
[3] = self
->size
.bottom
;
739 PROP_SETA32(self
->client
->window
, net_frame_extents
,
741 PROP_SETA32(self
->client
->window
, kde_net_wm_frame_strut
,
745 /* if this occurs while we are focus cycling, the indicator needs to
747 if (focus_cycle_target
== self
->client
)
748 focus_cycle_draw_indicator(self
->client
);
750 if (resized
&& (self
->decorations
& OB_FRAME_DECOR_TITLEBAR
))
751 XResizeWindow(ob_display
, self
->label
, self
->label_width
,
752 ob_rr_theme
->label_height
);
755 static void frame_adjust_cursors(ObFrame
*self
)
757 if ((self
->functions
& OB_CLIENT_FUNC_RESIZE
) !=
758 (self
->client
->functions
& OB_CLIENT_FUNC_RESIZE
) ||
759 ((self
->max_horz
&& self
->max_vert
) !=
760 (self
->client
->max_horz
&& self
->client
->max_vert
)))
762 gboolean r
= (self
->client
->functions
& OB_CLIENT_FUNC_RESIZE
) &&
763 !(self
->client
->max_horz
&& self
->client
->max_vert
);
764 XSetWindowAttributes a
;
766 a
.cursor
= ob_cursor(r
? OB_CURSOR_NORTH
: OB_CURSOR_NONE
);
767 XChangeWindowAttributes(ob_display
, self
->topresize
, CWCursor
, &a
);
768 XChangeWindowAttributes(ob_display
, self
->titletop
, CWCursor
, &a
);
769 a
.cursor
= ob_cursor(r
? OB_CURSOR_NORTHWEST
: OB_CURSOR_NONE
);
770 XChangeWindowAttributes(ob_display
, self
->tltresize
, CWCursor
, &a
);
771 XChangeWindowAttributes(ob_display
, self
->tllresize
, CWCursor
, &a
);
772 XChangeWindowAttributes(ob_display
, self
->titletopleft
, CWCursor
, &a
);
773 XChangeWindowAttributes(ob_display
, self
->titleleft
, CWCursor
, &a
);
774 a
.cursor
= ob_cursor(r
? OB_CURSOR_NORTHEAST
: OB_CURSOR_NONE
);
775 XChangeWindowAttributes(ob_display
, self
->trtresize
, CWCursor
, &a
);
776 XChangeWindowAttributes(ob_display
, self
->trrresize
, CWCursor
, &a
);
777 XChangeWindowAttributes(ob_display
, self
->titletopright
, CWCursor
, &a
);
778 XChangeWindowAttributes(ob_display
, self
->titleright
, CWCursor
, &a
);
779 a
.cursor
= ob_cursor(r
? OB_CURSOR_WEST
: OB_CURSOR_NONE
);
780 XChangeWindowAttributes(ob_display
, self
->left
, CWCursor
, &a
);
781 a
.cursor
= ob_cursor(r
? OB_CURSOR_EAST
: OB_CURSOR_NONE
);
782 XChangeWindowAttributes(ob_display
, self
->right
, CWCursor
, &a
);
783 a
.cursor
= ob_cursor(r
? OB_CURSOR_SOUTH
: OB_CURSOR_NONE
);
784 XChangeWindowAttributes(ob_display
, self
->handle
, CWCursor
, &a
);
785 XChangeWindowAttributes(ob_display
, self
->handletop
, CWCursor
, &a
);
786 XChangeWindowAttributes(ob_display
, self
->handlebottom
, CWCursor
, &a
);
787 a
.cursor
= ob_cursor(r
? OB_CURSOR_SOUTHWEST
: OB_CURSOR_NONE
);
788 XChangeWindowAttributes(ob_display
, self
->lgrip
, CWCursor
, &a
);
789 XChangeWindowAttributes(ob_display
, self
->handleleft
, CWCursor
, &a
);
790 XChangeWindowAttributes(ob_display
, self
->lgripleft
, CWCursor
, &a
);
791 XChangeWindowAttributes(ob_display
, self
->lgriptop
, CWCursor
, &a
);
792 XChangeWindowAttributes(ob_display
, self
->lgripbottom
, CWCursor
, &a
);
793 a
.cursor
= ob_cursor(r
? OB_CURSOR_SOUTHEAST
: OB_CURSOR_NONE
);
794 XChangeWindowAttributes(ob_display
, self
->rgrip
, CWCursor
, &a
);
795 XChangeWindowAttributes(ob_display
, self
->handleright
, CWCursor
, &a
);
796 XChangeWindowAttributes(ob_display
, self
->rgripright
, CWCursor
, &a
);
797 XChangeWindowAttributes(ob_display
, self
->rgriptop
, CWCursor
, &a
);
798 XChangeWindowAttributes(ob_display
, self
->rgripbottom
, CWCursor
, &a
);
802 void frame_adjust_client_area(ObFrame
*self
)
804 /* resize the plate */
805 XResizeWindow(ob_display
, self
->plate
,
806 self
->client
->area
.width
, self
->client
->area
.height
);
809 void frame_adjust_state(ObFrame
*self
)
811 framerender_frame(self
);
814 void frame_adjust_focus(ObFrame
*self
, gboolean hilite
)
816 self
->focused
= hilite
;
817 framerender_frame(self
);
821 void frame_adjust_title(ObFrame
*self
)
823 framerender_frame(self
);
826 void frame_adjust_icon(ObFrame
*self
)
828 framerender_frame(self
);
831 void frame_grab_client(ObFrame
*self
)
833 /* reparent the client to the frame */
834 XReparentWindow(ob_display
, self
->client
->window
, self
->plate
, 0, 0);
837 When reparenting the client window, it is usually not mapped yet, since
838 this occurs from a MapRequest. However, in the case where Openbox is
839 starting up, the window is already mapped, so we'll see unmap events for
840 it. There are 2 unmap events generated that we see, one with the 'event'
841 member set the root window, and one set to the client, but both get
842 handled and need to be ignored.
844 if (ob_state() == OB_STATE_STARTING
)
845 self
->client
->ignore_unmaps
+= 2;
847 /* select the event mask on the client's parent (to receive config/map
848 req's) the ButtonPress is to catch clicks on the client border */
849 XSelectInput(ob_display
, self
->plate
, PLATE_EVENTMASK
);
851 /* map the client so it maps when the frame does */
852 XMapWindow(ob_display
, self
->client
->window
);
854 /* set all the windows for the frame in the window_map */
855 g_hash_table_insert(window_map
, &self
->window
, self
->client
);
856 g_hash_table_insert(window_map
, &self
->plate
, self
->client
);
857 g_hash_table_insert(window_map
, &self
->inner
, self
->client
);
858 g_hash_table_insert(window_map
, &self
->title
, self
->client
);
859 g_hash_table_insert(window_map
, &self
->label
, self
->client
);
860 g_hash_table_insert(window_map
, &self
->max
, self
->client
);
861 g_hash_table_insert(window_map
, &self
->close
, self
->client
);
862 g_hash_table_insert(window_map
, &self
->desk
, self
->client
);
863 g_hash_table_insert(window_map
, &self
->shade
, self
->client
);
864 g_hash_table_insert(window_map
, &self
->icon
, self
->client
);
865 g_hash_table_insert(window_map
, &self
->iconify
, self
->client
);
866 g_hash_table_insert(window_map
, &self
->handle
, self
->client
);
867 g_hash_table_insert(window_map
, &self
->lgrip
, self
->client
);
868 g_hash_table_insert(window_map
, &self
->rgrip
, self
->client
);
869 g_hash_table_insert(window_map
, &self
->topresize
, self
->client
);
870 g_hash_table_insert(window_map
, &self
->tltresize
, self
->client
);
871 g_hash_table_insert(window_map
, &self
->tllresize
, self
->client
);
872 g_hash_table_insert(window_map
, &self
->trtresize
, self
->client
);
873 g_hash_table_insert(window_map
, &self
->trrresize
, self
->client
);
874 g_hash_table_insert(window_map
, &self
->left
, self
->client
);
875 g_hash_table_insert(window_map
, &self
->right
, self
->client
);
876 g_hash_table_insert(window_map
, &self
->titleleft
, self
->client
);
877 g_hash_table_insert(window_map
, &self
->titletop
, self
->client
);
878 g_hash_table_insert(window_map
, &self
->titletopleft
, self
->client
);
879 g_hash_table_insert(window_map
, &self
->titletopright
, self
->client
);
880 g_hash_table_insert(window_map
, &self
->titleright
, self
->client
);
881 g_hash_table_insert(window_map
, &self
->titlebottom
, self
->client
);
882 g_hash_table_insert(window_map
, &self
->handleleft
, self
->client
);
883 g_hash_table_insert(window_map
, &self
->handletop
, self
->client
);
884 g_hash_table_insert(window_map
, &self
->handleright
, self
->client
);
885 g_hash_table_insert(window_map
, &self
->handlebottom
, self
->client
);
886 g_hash_table_insert(window_map
, &self
->lgripleft
, self
->client
);
887 g_hash_table_insert(window_map
, &self
->lgriptop
, self
->client
);
888 g_hash_table_insert(window_map
, &self
->lgripbottom
, self
->client
);
889 g_hash_table_insert(window_map
, &self
->rgripright
, self
->client
);
890 g_hash_table_insert(window_map
, &self
->rgriptop
, self
->client
);
891 g_hash_table_insert(window_map
, &self
->rgripbottom
, self
->client
);
894 void frame_release_client(ObFrame
*self
)
897 gboolean reparent
= TRUE
;
899 /* if there was any animation going on, kill it */
900 ob_main_loop_timeout_remove_data(ob_main_loop
, frame_animate_iconify
,
903 /* check if the app has already reparented its window away */
904 while (XCheckTypedWindowEvent(ob_display
, self
->client
->window
,
905 ReparentNotify
, &ev
))
907 /* This check makes sure we don't catch our own reparent action to
908 our frame window. This doesn't count as the app reparenting itself
911 Reparent events that are generated by us are just discarded here.
912 They are of no consequence to us anyhow.
914 if (ev
.xreparent
.parent
!= self
->plate
) {
916 XPutBackEvent(ob_display
, &ev
);
922 /* according to the ICCCM - if the client doesn't reparent itself,
923 then we will reparent the window to root for them */
924 XReparentWindow(ob_display
, self
->client
->window
,
925 RootWindow(ob_display
, ob_screen
),
926 self
->client
->area
.x
,
927 self
->client
->area
.y
);
930 /* remove all the windows for the frame from the window_map */
931 g_hash_table_remove(window_map
, &self
->window
);
932 g_hash_table_remove(window_map
, &self
->plate
);
933 g_hash_table_remove(window_map
, &self
->inner
);
934 g_hash_table_remove(window_map
, &self
->title
);
935 g_hash_table_remove(window_map
, &self
->label
);
936 g_hash_table_remove(window_map
, &self
->max
);
937 g_hash_table_remove(window_map
, &self
->close
);
938 g_hash_table_remove(window_map
, &self
->desk
);
939 g_hash_table_remove(window_map
, &self
->shade
);
940 g_hash_table_remove(window_map
, &self
->icon
);
941 g_hash_table_remove(window_map
, &self
->iconify
);
942 g_hash_table_remove(window_map
, &self
->handle
);
943 g_hash_table_remove(window_map
, &self
->lgrip
);
944 g_hash_table_remove(window_map
, &self
->rgrip
);
945 g_hash_table_remove(window_map
, &self
->topresize
);
946 g_hash_table_remove(window_map
, &self
->tltresize
);
947 g_hash_table_remove(window_map
, &self
->tllresize
);
948 g_hash_table_remove(window_map
, &self
->trtresize
);
949 g_hash_table_remove(window_map
, &self
->trrresize
);
950 g_hash_table_remove(window_map
, &self
->left
);
951 g_hash_table_remove(window_map
, &self
->right
);
952 g_hash_table_remove(window_map
, &self
->titleleft
);
953 g_hash_table_remove(window_map
, &self
->titletop
);
954 g_hash_table_remove(window_map
, &self
->titletopleft
);
955 g_hash_table_remove(window_map
, &self
->titletopright
);
956 g_hash_table_remove(window_map
, &self
->titleright
);
957 g_hash_table_remove(window_map
, &self
->titlebottom
);
958 g_hash_table_remove(window_map
, &self
->handleleft
);
959 g_hash_table_remove(window_map
, &self
->handletop
);
960 g_hash_table_remove(window_map
, &self
->handleright
);
961 g_hash_table_remove(window_map
, &self
->handlebottom
);
962 g_hash_table_remove(window_map
, &self
->lgripleft
);
963 g_hash_table_remove(window_map
, &self
->lgriptop
);
964 g_hash_table_remove(window_map
, &self
->lgripbottom
);
965 g_hash_table_remove(window_map
, &self
->rgripright
);
966 g_hash_table_remove(window_map
, &self
->rgriptop
);
967 g_hash_table_remove(window_map
, &self
->rgripbottom
);
969 ob_main_loop_timeout_remove_data(ob_main_loop
, flash_timeout
, self
, TRUE
);
972 /* is there anything present between us and the label? */
973 static gboolean
is_button_present(ObFrame
*self
, const gchar
*lc
, gint dir
) {
974 for (; *lc
!= '\0' && lc
>= config_title_layout
; lc
+= dir
) {
975 if (*lc
== ' ') continue; /* it was invalid */
976 if (*lc
== 'N' && self
->decorations
& OB_FRAME_DECOR_ICON
)
978 if (*lc
== 'D' && self
->decorations
& OB_FRAME_DECOR_ALLDESKTOPS
)
980 if (*lc
== 'S' && self
->decorations
& OB_FRAME_DECOR_SHADE
)
982 if (*lc
== 'I' && self
->decorations
& OB_FRAME_DECOR_ICONIFY
)
984 if (*lc
== 'M' && self
->decorations
& OB_FRAME_DECOR_MAXIMIZE
)
986 if (*lc
== 'C' && self
->decorations
& OB_FRAME_DECOR_CLOSE
)
988 if (*lc
== 'L') return FALSE
;
993 static void layout_title(ObFrame
*self
)
998 const gint bwidth
= ob_rr_theme
->button_size
+ ob_rr_theme
->paddingx
+ 1;
999 /* position of the left most button */
1000 const gint left
= ob_rr_theme
->paddingx
+ 1;
1001 /* position of the right most button */
1002 const gint right
= self
->width
- bwidth
;
1004 /* turn them all off */
1005 self
->icon_on
= self
->desk_on
= self
->shade_on
= self
->iconify_on
=
1006 self
->max_on
= self
->close_on
= self
->label_on
= FALSE
;
1007 self
->label_width
= self
->width
- (ob_rr_theme
->paddingx
+ 1) * 2;
1008 self
->leftmost
= self
->rightmost
= OB_FRAME_CONTEXT_NONE
;
1010 /* figure out what's being show, find each element's position, and the
1013 do the ones before the label, then after the label,
1014 i will be +1 the first time through when working to the left,
1015 and -1 the second time through when working to the right */
1016 for (i
= 1; i
>= -1; i
-=2) {
1018 ObFrameContext
*firstcon
;
1022 lc
= config_title_layout
;
1023 firstcon
= &self
->leftmost
;
1026 lc
= config_title_layout
+ strlen(config_title_layout
)-1;
1027 firstcon
= &self
->rightmost
;
1030 /* stop at the end of the string (or the label, which calls break) */
1031 for (; *lc
!= '\0' && lc
>= config_title_layout
; lc
+=i
) {
1034 self
->label_on
= TRUE
;
1037 break; /* break the for loop, do other side of label */
1038 } else if (*lc
== 'N') {
1039 if (firstcon
) *firstcon
= OB_FRAME_CONTEXT_ICON
;
1040 if ((self
->icon_on
= is_button_present(self
, lc
, i
))) {
1041 /* icon is bigger than buttons */
1042 self
->label_width
-= bwidth
+ 2;
1044 x
+= i
* (bwidth
+ 2);
1046 } else if (*lc
== 'D') {
1047 if (firstcon
) *firstcon
= OB_FRAME_CONTEXT_ALLDESKTOPS
;
1048 if ((self
->desk_on
= is_button_present(self
, lc
, i
))) {
1049 self
->label_width
-= bwidth
;
1053 } else if (*lc
== 'S') {
1054 if (firstcon
) *firstcon
= OB_FRAME_CONTEXT_SHADE
;
1055 if ((self
->shade_on
= is_button_present(self
, lc
, i
))) {
1056 self
->label_width
-= bwidth
;
1060 } else if (*lc
== 'I') {
1061 if (firstcon
) *firstcon
= OB_FRAME_CONTEXT_ICONIFY
;
1062 if ((self
->iconify_on
= is_button_present(self
, lc
, i
))) {
1063 self
->label_width
-= bwidth
;
1064 self
->iconify_x
= x
;
1067 } else if (*lc
== 'M') {
1068 if (firstcon
) *firstcon
= OB_FRAME_CONTEXT_MAXIMIZE
;
1069 if ((self
->max_on
= is_button_present(self
, lc
, i
))) {
1070 self
->label_width
-= bwidth
;
1074 } else if (*lc
== 'C') {
1075 if (firstcon
) *firstcon
= OB_FRAME_CONTEXT_CLOSE
;
1076 if ((self
->close_on
= is_button_present(self
, lc
, i
))) {
1077 self
->label_width
-= bwidth
;
1082 continue; /* don't set firstcon */
1087 /* position and map the elements */
1088 if (self
->icon_on
) {
1089 XMapWindow(ob_display
, self
->icon
);
1090 XMoveWindow(ob_display
, self
->icon
, self
->icon_x
,
1091 ob_rr_theme
->paddingy
);
1093 XUnmapWindow(ob_display
, self
->icon
);
1095 if (self
->desk_on
) {
1096 XMapWindow(ob_display
, self
->desk
);
1097 XMoveWindow(ob_display
, self
->desk
, self
->desk_x
,
1098 ob_rr_theme
->paddingy
+ 1);
1100 XUnmapWindow(ob_display
, self
->desk
);
1102 if (self
->shade_on
) {
1103 XMapWindow(ob_display
, self
->shade
);
1104 XMoveWindow(ob_display
, self
->shade
, self
->shade_x
,
1105 ob_rr_theme
->paddingy
+ 1);
1107 XUnmapWindow(ob_display
, self
->shade
);
1109 if (self
->iconify_on
) {
1110 XMapWindow(ob_display
, self
->iconify
);
1111 XMoveWindow(ob_display
, self
->iconify
, self
->iconify_x
,
1112 ob_rr_theme
->paddingy
+ 1);
1114 XUnmapWindow(ob_display
, self
->iconify
);
1117 XMapWindow(ob_display
, self
->max
);
1118 XMoveWindow(ob_display
, self
->max
, self
->max_x
,
1119 ob_rr_theme
->paddingy
+ 1);
1121 XUnmapWindow(ob_display
, self
->max
);
1123 if (self
->close_on
) {
1124 XMapWindow(ob_display
, self
->close
);
1125 XMoveWindow(ob_display
, self
->close
, self
->close_x
,
1126 ob_rr_theme
->paddingy
+ 1);
1128 XUnmapWindow(ob_display
, self
->close
);
1130 if (self
->label_on
) {
1131 self
->label_width
= MAX(1, self
->label_width
); /* no lower than 1 */
1132 XMapWindow(ob_display
, self
->label
);
1133 XMoveWindow(ob_display
, self
->label
, self
->label_x
,
1134 ob_rr_theme
->paddingy
);
1136 XUnmapWindow(ob_display
, self
->label
);
1139 ObFrameContext
frame_context_from_string(const gchar
*name
)
1141 if (!g_ascii_strcasecmp("Desktop", name
))
1142 return OB_FRAME_CONTEXT_DESKTOP
;
1143 else if (!g_ascii_strcasecmp("Root", name
))
1144 return OB_FRAME_CONTEXT_ROOT
;
1145 else if (!g_ascii_strcasecmp("Client", name
))
1146 return OB_FRAME_CONTEXT_CLIENT
;
1147 else if (!g_ascii_strcasecmp("Titlebar", name
))
1148 return OB_FRAME_CONTEXT_TITLEBAR
;
1149 else if (!g_ascii_strcasecmp("Frame", name
))
1150 return OB_FRAME_CONTEXT_FRAME
;
1151 else if (!g_ascii_strcasecmp("TLCorner", name
))
1152 return OB_FRAME_CONTEXT_TLCORNER
;
1153 else if (!g_ascii_strcasecmp("TRCorner", name
))
1154 return OB_FRAME_CONTEXT_TRCORNER
;
1155 else if (!g_ascii_strcasecmp("BLCorner", name
))
1156 return OB_FRAME_CONTEXT_BLCORNER
;
1157 else if (!g_ascii_strcasecmp("BRCorner", name
))
1158 return OB_FRAME_CONTEXT_BRCORNER
;
1159 else if (!g_ascii_strcasecmp("Top", name
))
1160 return OB_FRAME_CONTEXT_TOP
;
1161 else if (!g_ascii_strcasecmp("Bottom", name
))
1162 return OB_FRAME_CONTEXT_BOTTOM
;
1163 else if (!g_ascii_strcasecmp("Left", name
))
1164 return OB_FRAME_CONTEXT_LEFT
;
1165 else if (!g_ascii_strcasecmp("Right", name
))
1166 return OB_FRAME_CONTEXT_RIGHT
;
1167 else if (!g_ascii_strcasecmp("Maximize", name
))
1168 return OB_FRAME_CONTEXT_MAXIMIZE
;
1169 else if (!g_ascii_strcasecmp("AllDesktops", name
))
1170 return OB_FRAME_CONTEXT_ALLDESKTOPS
;
1171 else if (!g_ascii_strcasecmp("Shade", name
))
1172 return OB_FRAME_CONTEXT_SHADE
;
1173 else if (!g_ascii_strcasecmp("Iconify", name
))
1174 return OB_FRAME_CONTEXT_ICONIFY
;
1175 else if (!g_ascii_strcasecmp("Icon", name
))
1176 return OB_FRAME_CONTEXT_ICON
;
1177 else if (!g_ascii_strcasecmp("Close", name
))
1178 return OB_FRAME_CONTEXT_CLOSE
;
1179 else if (!g_ascii_strcasecmp("MoveResize", name
))
1180 return OB_FRAME_CONTEXT_MOVE_RESIZE
;
1181 return OB_FRAME_CONTEXT_NONE
;
1184 ObFrameContext
frame_context(ObClient
*client
, Window win
, gint x
, gint y
)
1188 if (moveresize_in_progress
)
1189 return OB_FRAME_CONTEXT_MOVE_RESIZE
;
1191 if (win
== RootWindow(ob_display
, ob_screen
))
1192 return OB_FRAME_CONTEXT_ROOT
;
1193 if (client
== NULL
) return OB_FRAME_CONTEXT_NONE
;
1194 if (win
== client
->window
) {
1195 /* conceptually, this is the desktop, as far as users are
1197 if (client
->type
== OB_CLIENT_TYPE_DESKTOP
)
1198 return OB_FRAME_CONTEXT_DESKTOP
;
1199 return OB_FRAME_CONTEXT_CLIENT
;
1202 self
= client
->frame
;
1203 if (win
== self
->inner
|| win
== self
->plate
) {
1204 /* conceptually, this is the desktop, as far as users are
1206 if (client
->type
== OB_CLIENT_TYPE_DESKTOP
)
1207 return OB_FRAME_CONTEXT_DESKTOP
;
1208 return OB_FRAME_CONTEXT_CLIENT
;
1211 /* when the user clicks in the corners of the titlebar and the client
1212 is fully maximized, then treat it like they clicked in the
1213 button that is there */
1214 if (self
->max_horz
&& self
->max_vert
&&
1215 (win
== self
->title
|| win
== self
->titletop
||
1216 win
== self
->titleleft
|| win
== self
->titletopleft
||
1217 win
== self
->titleright
|| win
== self
->titletopright
))
1219 /* get the mouse coords in reference to the whole frame */
1223 /* these windows are down a border width from the top of the frame */
1224 if (win
== self
->title
||
1225 win
== self
->titleleft
|| win
== self
->titleright
)
1228 /* title is a border width in from the edge */
1229 if (win
== self
->title
)
1231 /* titletop is a bit to the right */
1232 else if (win
== self
->titletop
)
1233 fx
+= ob_rr_theme
->grip_width
+ self
->bwidth
;
1234 /* titletopright is way to the right edge */
1235 else if (win
== self
->titletopright
)
1236 fx
+= self
->area
.width
- (ob_rr_theme
->grip_width
+ self
->bwidth
);
1237 /* titleright is even more way to the right edge */
1238 else if (win
== self
->titleright
)
1239 fx
+= self
->area
.width
- self
->bwidth
;
1241 /* figure out if we're over the area that should be considered a
1243 if (fy
< self
->bwidth
+ ob_rr_theme
->paddingy
+ 1 +
1244 ob_rr_theme
->button_size
)
1246 if (fx
< (self
->bwidth
+ ob_rr_theme
->paddingx
+ 1 +
1247 ob_rr_theme
->button_size
))
1249 if (self
->leftmost
!= OB_FRAME_CONTEXT_NONE
)
1250 return self
->leftmost
;
1252 else if (fx
>= (self
->area
.width
-
1253 (self
->bwidth
+ ob_rr_theme
->paddingx
+ 1 +
1254 ob_rr_theme
->button_size
)))
1256 if (self
->rightmost
!= OB_FRAME_CONTEXT_NONE
)
1257 return self
->rightmost
;
1261 /* there is no resizing maximized windows so make them the titlebar
1263 return OB_FRAME_CONTEXT_TITLEBAR
;
1266 if (win
== self
->window
) return OB_FRAME_CONTEXT_FRAME
;
1267 if (win
== self
->label
) return OB_FRAME_CONTEXT_TITLEBAR
;
1268 if (win
== self
->handle
) return OB_FRAME_CONTEXT_BOTTOM
;
1269 if (win
== self
->handletop
) return OB_FRAME_CONTEXT_BOTTOM
;
1270 if (win
== self
->handlebottom
) return OB_FRAME_CONTEXT_BOTTOM
;
1271 if (win
== self
->handleleft
) return OB_FRAME_CONTEXT_BLCORNER
;
1272 if (win
== self
->lgrip
) return OB_FRAME_CONTEXT_BLCORNER
;
1273 if (win
== self
->lgripleft
) return OB_FRAME_CONTEXT_BLCORNER
;
1274 if (win
== self
->lgriptop
) return OB_FRAME_CONTEXT_BLCORNER
;
1275 if (win
== self
->lgripbottom
) return OB_FRAME_CONTEXT_BLCORNER
;
1276 if (win
== self
->handleright
) return OB_FRAME_CONTEXT_BRCORNER
;
1277 if (win
== self
->rgrip
) return OB_FRAME_CONTEXT_BRCORNER
;
1278 if (win
== self
->rgripright
) return OB_FRAME_CONTEXT_BLCORNER
;
1279 if (win
== self
->rgriptop
) return OB_FRAME_CONTEXT_BLCORNER
;
1280 if (win
== self
->rgripbottom
) return OB_FRAME_CONTEXT_BLCORNER
;
1281 if (win
== self
->title
) return OB_FRAME_CONTEXT_TITLEBAR
;
1282 if (win
== self
->titleleft
) return OB_FRAME_CONTEXT_TLCORNER
;
1283 if (win
== self
->titletopleft
) return OB_FRAME_CONTEXT_TLCORNER
;
1284 if (win
== self
->titleright
) return OB_FRAME_CONTEXT_TRCORNER
;
1285 if (win
== self
->titletopright
) return OB_FRAME_CONTEXT_TRCORNER
;
1286 if (win
== self
->titletop
) return OB_FRAME_CONTEXT_TOP
;
1287 if (win
== self
->topresize
) return OB_FRAME_CONTEXT_TOP
;
1288 if (win
== self
->tltresize
) return OB_FRAME_CONTEXT_TLCORNER
;
1289 if (win
== self
->tllresize
) return OB_FRAME_CONTEXT_TLCORNER
;
1290 if (win
== self
->trtresize
) return OB_FRAME_CONTEXT_TRCORNER
;
1291 if (win
== self
->trrresize
) return OB_FRAME_CONTEXT_TRCORNER
;
1292 if (win
== self
->left
) return OB_FRAME_CONTEXT_LEFT
;
1293 if (win
== self
->right
) return OB_FRAME_CONTEXT_RIGHT
;
1294 if (win
== self
->max
) return OB_FRAME_CONTEXT_MAXIMIZE
;
1295 if (win
== self
->iconify
) return OB_FRAME_CONTEXT_ICONIFY
;
1296 if (win
== self
->close
) return OB_FRAME_CONTEXT_CLOSE
;
1297 if (win
== self
->icon
) return OB_FRAME_CONTEXT_ICON
;
1298 if (win
== self
->desk
) return OB_FRAME_CONTEXT_ALLDESKTOPS
;
1299 if (win
== self
->shade
) return OB_FRAME_CONTEXT_SHADE
;
1301 return OB_FRAME_CONTEXT_NONE
;
1304 void frame_client_gravity(ObFrame
*self
, gint
*x
, gint
*y
, gint w
, gint h
)
1307 switch (self
->client
->gravity
) {
1309 case NorthWestGravity
:
1310 case SouthWestGravity
:
1317 /* the middle of the client will be the middle of the frame */
1318 *x
-= (self
->size
.right
- self
->size
.left
) / 2;
1321 case NorthEastGravity
:
1322 case SouthEastGravity
:
1324 /* the right side of the client will be the right side of the frame */
1325 *x
-= self
->size
.right
+ self
->size
.left
;
1330 /* the client's position won't move */
1331 *x
-= self
->size
.left
;
1336 switch (self
->client
->gravity
) {
1338 case NorthWestGravity
:
1339 case NorthEastGravity
:
1346 /* the middle of the client will be the middle of the frame */
1347 *y
-= (self
->size
.bottom
- self
->size
.top
) / 2;
1350 case SouthWestGravity
:
1351 case SouthEastGravity
:
1353 /* the bottom of the client will be the bottom of the frame */
1354 *y
-= self
->size
.bottom
+ self
->size
.top
;
1359 /* the client's position won't move */
1360 *y
-= self
->size
.top
;
1365 void frame_frame_gravity(ObFrame
*self
, gint
*x
, gint
*y
, gint w
, gint h
)
1368 switch (self
->client
->gravity
) {
1370 case NorthWestGravity
:
1372 case SouthWestGravity
:
1377 /* the middle of the client will be the middle of the frame */
1378 *x
+= (self
->size
.right
- self
->size
.left
) / 2;
1380 case NorthEastGravity
:
1382 case SouthEastGravity
:
1383 /* the right side of the client will be the right side of the frame */
1384 *x
+= self
->size
.right
+ self
->size
.left
;
1388 /* the client's position won't move */
1389 *x
+= self
->size
.left
;
1394 switch (self
->client
->gravity
) {
1396 case NorthWestGravity
:
1398 case NorthEastGravity
:
1403 /* the middle of the client will be the middle of the frame */
1404 *y
+= (self
->size
.bottom
- self
->size
.top
) / 2;
1406 case SouthWestGravity
:
1408 case SouthEastGravity
:
1409 /* the bottom of the client will be the bottom of the frame */
1410 *y
+= self
->size
.bottom
+ self
->size
.top
;
1414 /* the client's position won't move */
1415 *y
+= self
->size
.top
;
1420 static void flash_done(gpointer data
)
1422 ObFrame
*self
= data
;
1424 if (self
->focused
!= self
->flash_on
)
1425 frame_adjust_focus(self
, self
->focused
);
1428 static gboolean
flash_timeout(gpointer data
)
1430 ObFrame
*self
= data
;
1433 g_get_current_time(&now
);
1434 if (now
.tv_sec
> self
->flash_end
.tv_sec
||
1435 (now
.tv_sec
== self
->flash_end
.tv_sec
&&
1436 now
.tv_usec
>= self
->flash_end
.tv_usec
))
1437 self
->flashing
= FALSE
;
1439 if (!self
->flashing
)
1440 return FALSE
; /* we are done */
1442 self
->flash_on
= !self
->flash_on
;
1443 if (!self
->focused
) {
1444 frame_adjust_focus(self
, self
->flash_on
);
1445 self
->focused
= FALSE
;
1448 return TRUE
; /* go again */
1451 void frame_flash_start(ObFrame
*self
)
1453 self
->flash_on
= self
->focused
;
1455 if (!self
->flashing
)
1456 ob_main_loop_timeout_add(ob_main_loop
,
1457 G_USEC_PER_SEC
* 0.6,
1462 g_get_current_time(&self
->flash_end
);
1463 g_time_val_add(&self
->flash_end
, G_USEC_PER_SEC
* 5);
1465 self
->flashing
= TRUE
;
1468 void frame_flash_stop(ObFrame
*self
)
1470 self
->flashing
= FALSE
;
1473 static gulong
frame_animate_iconify_time_left(ObFrame
*self
,
1474 const GTimeVal
*now
)
1477 sec
= self
->iconify_animation_end
.tv_sec
- now
->tv_sec
;
1478 usec
= self
->iconify_animation_end
.tv_usec
- now
->tv_usec
;
1480 usec
+= G_USEC_PER_SEC
;
1483 /* no negative values */
1484 return MAX(sec
* G_USEC_PER_SEC
+ usec
, 0);
1487 static gboolean
frame_animate_iconify(gpointer p
)
1491 gint iconx
, icony
, iconw
;
1494 gboolean iconifying
;
1496 if (self
->client
->icon_geometry
.width
== 0) {
1497 /* there is no icon geometry set so just go straight down */
1498 Rect
*a
= screen_physical_area();
1499 iconx
= self
->area
.x
+ self
->area
.width
/ 2 + 32;
1500 icony
= a
->y
+ a
->width
;
1503 iconx
= self
->client
->icon_geometry
.x
;
1504 icony
= self
->client
->icon_geometry
.y
;
1505 iconw
= self
->client
->icon_geometry
.width
;
1508 iconifying
= self
->iconify_animation_going
> 0;
1510 /* how far do we have left to go ? */
1511 g_get_current_time(&now
);
1512 time
= frame_animate_iconify_time_left(self
, &now
);
1514 if (time
== 0 || iconifying
) {
1515 /* start where the frame is supposed to be */
1518 w
= self
->area
.width
;
1519 h
= self
->area
.height
;
1521 /* start at the icon */
1525 h
= self
->size
.top
; /* just the titlebar */
1532 dx
= self
->area
.x
- iconx
;
1533 dy
= self
->area
.y
- icony
;
1534 dw
= self
->area
.width
- self
->bwidth
* 2 - iconw
;
1535 /* if restoring, we move in the opposite direction */
1536 if (!iconifying
) { dx
= -dx
; dy
= -dy
; dw
= -dw
; }
1538 elapsed
= FRAME_ANIMATE_ICONIFY_TIME
- time
;
1539 x
= x
- (dx
* elapsed
) / FRAME_ANIMATE_ICONIFY_TIME
;
1540 y
= y
- (dy
* elapsed
) / FRAME_ANIMATE_ICONIFY_TIME
;
1541 w
= w
- (dw
* elapsed
) / FRAME_ANIMATE_ICONIFY_TIME
;
1542 h
= self
->size
.top
; /* just the titlebar */
1546 frame_end_iconify_animation(self
);
1548 XMoveResizeWindow(ob_display
, self
->window
, x
, y
, w
, h
);
1552 return time
> 0; /* repeat until we're out of time */
1555 void frame_end_iconify_animation(ObFrame
*self
)
1557 /* see if there is an animation going */
1558 if (self
->iconify_animation_going
== 0) return;
1561 XUnmapWindow(ob_display
, self
->window
);
1563 /* Send a ConfigureNotify when the animation is done, this fixes
1564 KDE's pager showing the window in the wrong place. */
1565 client_reconfigure(self
->client
);
1567 /* we're not animating any more ! */
1568 self
->iconify_animation_going
= 0;
1570 XMoveResizeWindow(ob_display
, self
->window
,
1571 self
->area
.x
, self
->area
.y
,
1572 self
->area
.width
, self
->area
.height
);
1576 void frame_begin_iconify_animation(ObFrame
*self
, gboolean iconifying
)
1579 gboolean new_anim
= FALSE
;
1580 gboolean set_end
= TRUE
;
1583 /* if there is no titlebar, just don't animate for now
1584 XXX it would be nice tho.. */
1585 if (!(self
->decorations
& OB_FRAME_DECOR_TITLEBAR
))
1588 /* get the current time */
1589 g_get_current_time(&now
);
1591 /* get how long until the end */
1592 time
= FRAME_ANIMATE_ICONIFY_TIME
;
1593 if (self
->iconify_animation_going
) {
1594 if (!!iconifying
!= (self
->iconify_animation_going
> 0)) {
1595 /* animation was already going on in the opposite direction */
1596 time
= time
- frame_animate_iconify_time_left(self
, &now
);
1598 /* animation was already going in the same direction */
1602 self
->iconify_animation_going
= iconifying
? 1 : -1;
1604 /* set the ending time */
1606 self
->iconify_animation_end
.tv_sec
= now
.tv_sec
;
1607 self
->iconify_animation_end
.tv_usec
= now
.tv_usec
;
1608 g_time_val_add(&self
->iconify_animation_end
, time
);
1612 ob_main_loop_timeout_remove_data(ob_main_loop
, frame_animate_iconify
,
1614 ob_main_loop_timeout_add(ob_main_loop
,
1615 FRAME_ANIMATE_ICONIFY_STEP_TIME
,
1616 frame_animate_iconify
, self
,
1617 g_direct_equal
, NULL
);
1619 /* do the first step */
1620 frame_animate_iconify(self
);
1622 /* show it during the animation even if it is not "visible" */
1624 XMapWindow(ob_display
, self
->window
);