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"
29 #include "moveresize.h"
30 #include "render/theme.h"
32 #define PLATE_EVENTMASK (SubstructureRedirectMask | ButtonPressMask | \
34 #define FRAME_EVENTMASK (EnterWindowMask | LeaveWindowMask | \
35 ButtonPressMask | ButtonReleaseMask | \
37 #define ELEMENT_EVENTMASK (ButtonPressMask | ButtonReleaseMask | \
38 ButtonMotionMask | ExposureMask | \
39 EnterWindowMask | LeaveWindowMask)
41 #define FRAME_HANDLE_Y(f) (f->innersize.top + f->client->area.height + \
44 static void layout_title(ObFrame
*self
);
45 static void flash_done(gpointer data
);
46 static gboolean
flash_timeout(gpointer data
);
48 static void set_theme_statics(ObFrame
*self
);
49 static void free_theme_statics(ObFrame
*self
);
51 static Window
createWindow(Window parent
, Visual
*visual
,
52 gulong mask
, XSetWindowAttributes
*attrib
)
54 return XCreateWindow(ob_display
, parent
, 0, 0, 1, 1, 0,
55 (visual
? 32 : RrDepth(ob_rr_inst
)), InputOutput
,
56 (visual
? visual
: RrVisual(ob_rr_inst
)),
61 static Visual
*check_32bit_client(ObClient
*c
)
63 XWindowAttributes wattrib
;
66 ret
= XGetWindowAttributes(ob_display
, c
->window
, &wattrib
);
67 g_assert(ret
!= BadDrawable
);
68 g_assert(ret
!= BadWindow
);
70 if (wattrib
.depth
== 32)
71 return wattrib
.visual
;
75 ObFrame
*frame_new(ObClient
*client
)
77 XSetWindowAttributes attrib
;
82 self
= g_new0(ObFrame
, 1);
84 self
->obscured
= TRUE
;
86 visual
= check_32bit_client(client
);
88 /* create the non-visible decor windows */
92 /* client has a 32-bit visual */
93 mask
|= CWColormap
| CWBackPixel
| CWBorderPixel
;
94 /* create a colormap with the visual */
95 self
->colormap
= attrib
.colormap
=
96 XCreateColormap(ob_display
,
97 RootWindow(ob_display
, ob_screen
),
99 attrib
.background_pixel
= BlackPixel(ob_display
, 0);
100 attrib
.border_pixel
= BlackPixel(ob_display
, 0);
102 attrib
.event_mask
= FRAME_EVENTMASK
;
103 self
->window
= createWindow(RootWindow(ob_display
, ob_screen
), visual
,
105 mask
&= ~CWEventMask
;
106 self
->plate
= createWindow(self
->window
, visual
, mask
, &attrib
);
108 /* create the visible decor windows */
112 /* client has a 32-bit visual */
113 mask
|= CWColormap
| CWBackPixel
| CWBorderPixel
;
114 attrib
.colormap
= RrColormap(ob_rr_inst
);
116 attrib
.event_mask
= ELEMENT_EVENTMASK
;
117 self
->title
= createWindow(self
->window
, NULL
, mask
, &attrib
);
120 attrib
.cursor
= ob_cursor(OB_CURSOR_NORTHWEST
);
121 self
->tltresize
= createWindow(self
->title
, NULL
, mask
, &attrib
);
122 self
->tllresize
= createWindow(self
->title
, NULL
, mask
, &attrib
);
123 attrib
.cursor
= ob_cursor(OB_CURSOR_NORTHEAST
);
124 self
->trtresize
= createWindow(self
->title
, NULL
, mask
, &attrib
);
125 self
->trrresize
= createWindow(self
->title
, NULL
, mask
, &attrib
);
128 self
->label
= createWindow(self
->title
, NULL
, mask
, &attrib
);
129 self
->max
= createWindow(self
->title
, NULL
, mask
, &attrib
);
130 self
->close
= createWindow(self
->title
, NULL
, mask
, &attrib
);
131 self
->desk
= createWindow(self
->title
, NULL
, mask
, &attrib
);
132 self
->shade
= createWindow(self
->title
, NULL
, mask
, &attrib
);
133 self
->icon
= createWindow(self
->title
, NULL
, mask
, &attrib
);
134 self
->iconify
= createWindow(self
->title
, NULL
, mask
, &attrib
);
135 self
->handle
= createWindow(self
->window
, NULL
, mask
, &attrib
);
138 attrib
.cursor
= ob_cursor(OB_CURSOR_SOUTHWEST
);
139 self
->lgrip
= createWindow(self
->handle
, NULL
, mask
, &attrib
);
140 attrib
.cursor
= ob_cursor(OB_CURSOR_SOUTHEAST
);
141 self
->rgrip
= createWindow(self
->handle
, NULL
, mask
, &attrib
);
143 self
->focused
= FALSE
;
145 /* the other stuff is shown based on decor settings */
146 XMapWindow(ob_display
, self
->plate
);
147 XMapWindow(ob_display
, self
->lgrip
);
148 XMapWindow(ob_display
, self
->rgrip
);
149 XMapWindow(ob_display
, self
->label
);
151 self
->max_press
= self
->close_press
= self
->desk_press
=
152 self
->iconify_press
= self
->shade_press
= FALSE
;
153 self
->max_hover
= self
->close_hover
= self
->desk_hover
=
154 self
->iconify_hover
= self
->shade_hover
= FALSE
;
156 set_theme_statics(self
);
158 return (ObFrame
*)self
;
161 static void set_theme_statics(ObFrame
*self
)
163 /* set colors/appearance/sizes for stuff that doesn't change */
164 XSetWindowBorder(ob_display
, self
->window
,
165 RrColorPixel(ob_rr_theme
->frame_b_color
));
166 XSetWindowBorder(ob_display
, self
->title
,
167 RrColorPixel(ob_rr_theme
->frame_b_color
));
168 XSetWindowBorder(ob_display
, self
->handle
,
169 RrColorPixel(ob_rr_theme
->frame_b_color
));
170 XSetWindowBorder(ob_display
, self
->rgrip
,
171 RrColorPixel(ob_rr_theme
->frame_b_color
));
172 XSetWindowBorder(ob_display
, self
->lgrip
,
173 RrColorPixel(ob_rr_theme
->frame_b_color
));
175 XResizeWindow(ob_display
, self
->max
,
176 ob_rr_theme
->button_size
, ob_rr_theme
->button_size
);
177 XResizeWindow(ob_display
, self
->iconify
,
178 ob_rr_theme
->button_size
, ob_rr_theme
->button_size
);
179 XResizeWindow(ob_display
, self
->icon
,
180 ob_rr_theme
->button_size
+ 2, ob_rr_theme
->button_size
+ 2);
181 XResizeWindow(ob_display
, self
->close
,
182 ob_rr_theme
->button_size
, ob_rr_theme
->button_size
);
183 XResizeWindow(ob_display
, self
->desk
,
184 ob_rr_theme
->button_size
, ob_rr_theme
->button_size
);
185 XResizeWindow(ob_display
, self
->shade
,
186 ob_rr_theme
->button_size
, ob_rr_theme
->button_size
);
187 if (ob_rr_theme
->handle_height
> 0) {
188 XResizeWindow(ob_display
, self
->lgrip
,
189 ob_rr_theme
->grip_width
, ob_rr_theme
->handle_height
);
190 XResizeWindow(ob_display
, self
->rgrip
,
191 ob_rr_theme
->grip_width
, ob_rr_theme
->handle_height
);
193 XResizeWindow(ob_display
, self
->tltresize
,
194 ob_rr_theme
->grip_width
, ob_rr_theme
->paddingy
+ 1);
195 XResizeWindow(ob_display
, self
->trtresize
,
196 ob_rr_theme
->grip_width
, ob_rr_theme
->paddingy
+ 1);
197 XResizeWindow(ob_display
, self
->tllresize
,
198 ob_rr_theme
->paddingx
+ 1, ob_rr_theme
->title_height
);
199 XResizeWindow(ob_display
, self
->trrresize
,
200 ob_rr_theme
->paddingx
+ 1, ob_rr_theme
->title_height
);
202 /* set up the dynamic appearances */
203 self
->a_unfocused_title
= RrAppearanceCopy(ob_rr_theme
->a_unfocused_title
);
204 self
->a_focused_title
= RrAppearanceCopy(ob_rr_theme
->a_focused_title
);
205 self
->a_unfocused_label
= RrAppearanceCopy(ob_rr_theme
->a_unfocused_label
);
206 self
->a_focused_label
= RrAppearanceCopy(ob_rr_theme
->a_focused_label
);
207 self
->a_unfocused_handle
=
208 RrAppearanceCopy(ob_rr_theme
->a_unfocused_handle
);
209 self
->a_focused_handle
= RrAppearanceCopy(ob_rr_theme
->a_focused_handle
);
210 self
->a_icon
= RrAppearanceCopy(ob_rr_theme
->a_icon
);
213 static void free_theme_statics(ObFrame
*self
)
215 RrAppearanceFree(self
->a_unfocused_title
);
216 RrAppearanceFree(self
->a_focused_title
);
217 RrAppearanceFree(self
->a_unfocused_label
);
218 RrAppearanceFree(self
->a_focused_label
);
219 RrAppearanceFree(self
->a_unfocused_handle
);
220 RrAppearanceFree(self
->a_focused_handle
);
221 RrAppearanceFree(self
->a_icon
);
224 static void frame_free(ObFrame
*self
)
226 free_theme_statics(self
);
228 XDestroyWindow(ob_display
, self
->window
);
230 XFreeColormap(ob_display
, self
->colormap
);
235 void frame_show(ObFrame
*self
)
237 if (!self
->visible
) {
238 self
->visible
= TRUE
;
239 XMapWindow(ob_display
, self
->client
->window
);
240 XMapWindow(ob_display
, self
->window
);
244 void frame_hide(ObFrame
*self
)
247 self
->visible
= FALSE
;
248 self
->client
->ignore_unmaps
+= 1;
249 /* we unmap the client itself so that we can get MapRequest
250 events, and because the ICCCM tells us to! */
251 XUnmapWindow(ob_display
, self
->window
);
252 XUnmapWindow(ob_display
, self
->client
->window
);
256 void frame_adjust_theme(ObFrame
*self
)
258 free_theme_statics(self
);
259 set_theme_statics(self
);
262 void frame_adjust_shape(ObFrame
*self
)
268 if (!self
->client
->shaped
) {
269 /* clear the shape on the frame window */
270 XShapeCombineMask(ob_display
, self
->window
, ShapeBounding
,
271 self
->innersize
.left
,
275 /* make the frame's shape match the clients */
276 XShapeCombineShape(ob_display
, self
->window
, ShapeBounding
,
277 self
->innersize
.left
,
279 self
->client
->window
,
280 ShapeBounding
, ShapeSet
);
283 if (self
->decorations
& OB_FRAME_DECOR_TITLEBAR
) {
284 xrect
[0].x
= -ob_rr_theme
->fbwidth
;
285 xrect
[0].y
= -ob_rr_theme
->fbwidth
;
286 xrect
[0].width
= self
->width
+ self
->rbwidth
* 2;
287 xrect
[0].height
= ob_rr_theme
->title_height
+
292 if (self
->decorations
& OB_FRAME_DECOR_HANDLE
) {
293 xrect
[1].x
= -ob_rr_theme
->fbwidth
;
294 xrect
[1].y
= FRAME_HANDLE_Y(self
);
295 xrect
[1].width
= self
->width
+ self
->rbwidth
* 2;
296 xrect
[1].height
= ob_rr_theme
->handle_height
+
301 XShapeCombineRectangles(ob_display
, self
->window
,
302 ShapeBounding
, 0, 0, xrect
, num
,
303 ShapeUnion
, Unsorted
);
308 void frame_adjust_area(ObFrame
*self
, gboolean moved
,
309 gboolean resized
, gboolean fake
)
313 oldsize
= self
->size
;
316 self
->decorations
= self
->client
->decorations
;
317 self
->max_horz
= self
->client
->max_horz
;
319 if (self
->decorations
& OB_FRAME_DECOR_BORDER
) {
320 self
->bwidth
= ob_rr_theme
->fbwidth
;
321 self
->cbwidth_x
= ob_rr_theme
->cbwidthx
;
322 self
->cbwidth_y
= ob_rr_theme
->cbwidthy
;
324 self
->bwidth
= self
->cbwidth_x
= self
->cbwidth_y
= 0;
326 self
->rbwidth
= self
->bwidth
;
329 self
->bwidth
= self
->cbwidth_x
= 0;
331 STRUT_SET(self
->innersize
,
336 self
->width
= self
->client
->area
.width
+ self
->cbwidth_x
* 2 -
337 (self
->max_horz
? self
->rbwidth
* 2 : 0);
338 self
->width
= MAX(self
->width
, 1); /* no lower than 1 */
340 /* set border widths */
342 XSetWindowBorderWidth(ob_display
, self
->window
, self
->bwidth
);
343 XSetWindowBorderWidth(ob_display
, self
->title
, self
->rbwidth
);
344 XSetWindowBorderWidth(ob_display
, self
->handle
, self
->rbwidth
);
345 XSetWindowBorderWidth(ob_display
, self
->lgrip
, self
->rbwidth
);
346 XSetWindowBorderWidth(ob_display
, self
->rgrip
, self
->rbwidth
);
349 if (self
->decorations
& OB_FRAME_DECOR_TITLEBAR
)
350 self
->innersize
.top
+= ob_rr_theme
->title_height
+ self
->rbwidth
+
351 (self
->rbwidth
- self
->bwidth
);
352 if (self
->decorations
& OB_FRAME_DECOR_HANDLE
&&
353 ob_rr_theme
->handle_height
> 0)
354 self
->innersize
.bottom
+= ob_rr_theme
->handle_height
+
355 self
->rbwidth
+ (self
->rbwidth
- self
->bwidth
);
357 /* they all default off, they're turned on in layout_title */
361 self
->iconify_x
= -1;
366 /* position/size and map/unmap all the windows */
369 if (self
->decorations
& OB_FRAME_DECOR_TITLEBAR
) {
370 XMoveResizeWindow(ob_display
, self
->title
,
371 -self
->bwidth
, -self
->bwidth
,
372 self
->width
, ob_rr_theme
->title_height
);
373 XMapWindow(ob_display
, self
->title
);
375 if (self
->decorations
& OB_FRAME_DECOR_GRIPS
) {
376 XMoveWindow(ob_display
, self
->tltresize
, 0, 0);
377 XMoveWindow(ob_display
, self
->tllresize
, 0, 0);
378 XMoveWindow(ob_display
, self
->trtresize
,
379 self
->width
- ob_rr_theme
->grip_width
, 0);
380 XMoveWindow(ob_display
, self
->trrresize
,
381 self
->width
- ob_rr_theme
->paddingx
- 1, 0);
382 XMapWindow(ob_display
, self
->tltresize
);
383 XMapWindow(ob_display
, self
->tllresize
);
384 XMapWindow(ob_display
, self
->trtresize
);
385 XMapWindow(ob_display
, self
->trrresize
);
387 XUnmapWindow(ob_display
, self
->tltresize
);
388 XUnmapWindow(ob_display
, self
->tllresize
);
389 XUnmapWindow(ob_display
, self
->trtresize
);
390 XUnmapWindow(ob_display
, self
->trrresize
);
393 XUnmapWindow(ob_display
, self
->title
);
396 if (self
->decorations
& OB_FRAME_DECOR_TITLEBAR
)
397 /* layout the title bar elements */
401 if (self
->decorations
& OB_FRAME_DECOR_HANDLE
&&
402 ob_rr_theme
->handle_height
> 0)
404 XMoveResizeWindow(ob_display
, self
->handle
,
405 -self
->bwidth
, FRAME_HANDLE_Y(self
),
406 self
->width
, ob_rr_theme
->handle_height
);
407 XMapWindow(ob_display
, self
->handle
);
409 if (self
->decorations
& OB_FRAME_DECOR_GRIPS
) {
410 XMoveWindow(ob_display
, self
->lgrip
,
411 -self
->rbwidth
, -self
->rbwidth
);
412 XMoveWindow(ob_display
, self
->rgrip
,
413 -self
->rbwidth
+ self
->width
-
414 ob_rr_theme
->grip_width
, -self
->rbwidth
);
415 XMapWindow(ob_display
, self
->lgrip
);
416 XMapWindow(ob_display
, self
->rgrip
);
418 XUnmapWindow(ob_display
, self
->lgrip
);
419 XUnmapWindow(ob_display
, self
->rgrip
);
422 XUnmapWindow(ob_display
, self
->handle
);
424 /* move and resize the plate */
425 XMoveResizeWindow(ob_display
, self
->plate
,
426 self
->innersize
.left
- self
->cbwidth_x
,
427 self
->innersize
.top
- self
->cbwidth_y
,
428 self
->client
->area
.width
+ self
->cbwidth_x
* 2,
429 self
->client
->area
.height
+ self
->cbwidth_y
* 2);
430 /* when the client has StaticGravity, it likes to move around. */
431 XMoveWindow(ob_display
, self
->client
->window
,
432 self
->cbwidth_x
, self
->cbwidth_y
);
435 STRUT_SET(self
->size
,
436 self
->innersize
.left
+ self
->bwidth
,
437 self
->innersize
.top
+ self
->bwidth
,
438 self
->innersize
.right
+ self
->bwidth
,
439 self
->innersize
.bottom
+ self
->bwidth
);
442 /* shading can change without being moved or resized */
443 RECT_SET_SIZE(self
->area
,
444 self
->client
->area
.width
+
445 self
->size
.left
+ self
->size
.right
,
446 (self
->client
->shaded
?
447 ob_rr_theme
->title_height
+ self
->rbwidth
* 2:
448 self
->client
->area
.height
+
449 self
->size
.top
+ self
->size
.bottom
));
452 /* find the new coordinates, done after setting the frame.size, for
453 frame_client_gravity. */
454 self
->area
.x
= self
->client
->area
.x
;
455 self
->area
.y
= self
->client
->area
.y
;
456 frame_client_gravity(self
, &self
->area
.x
, &self
->area
.y
);
460 /* move and resize the top level frame.
461 shading can change without being moved or resized */
462 XMoveResizeWindow(ob_display
, self
->window
,
463 self
->area
.x
, self
->area
.y
,
464 self
->area
.width
- self
->bwidth
* 2,
465 self
->area
.height
- self
->bwidth
* 2);
468 framerender_frame(self
);
469 frame_adjust_shape(self
);
472 if (!STRUT_EQUAL(self
->size
, oldsize
)) {
474 vals
[0] = self
->size
.left
;
475 vals
[1] = self
->size
.right
;
476 vals
[2] = self
->size
.top
;
477 vals
[3] = self
->size
.bottom
;
478 PROP_SETA32(self
->client
->window
, net_frame_extents
,
482 /* if this occurs while we are focus cycling, the indicator needs to
484 if (focus_cycle_target
== self
->client
)
485 focus_cycle_draw_indicator();
487 if (resized
&& (self
->decorations
& OB_FRAME_DECOR_TITLEBAR
))
488 XResizeWindow(ob_display
, self
->label
, self
->label_width
,
489 ob_rr_theme
->label_height
);
492 void frame_adjust_state(ObFrame
*self
)
494 framerender_frame(self
);
497 void frame_adjust_focus(ObFrame
*self
, gboolean hilite
)
499 self
->focused
= hilite
;
500 framerender_frame(self
);
504 void frame_adjust_title(ObFrame
*self
)
506 framerender_frame(self
);
509 void frame_adjust_icon(ObFrame
*self
)
511 framerender_frame(self
);
514 void frame_grab_client(ObFrame
*self
, ObClient
*client
)
516 self
->client
= client
;
518 /* reparent the client to the frame */
519 XReparentWindow(ob_display
, client
->window
, self
->plate
, 0, 0);
521 When reparenting the client window, it is usually not mapped yet, since
522 this occurs from a MapRequest. However, in the case where Openbox is
523 starting up, the window is already mapped, so we'll see unmap events for
524 it. There are 2 unmap events generated that we see, one with the 'event'
525 member set the root window, and one set to the client, but both get
526 handled and need to be ignored.
528 if (ob_state() == OB_STATE_STARTING
)
529 client
->ignore_unmaps
+= 2;
531 /* select the event mask on the client's parent (to receive config/map
532 req's) the ButtonPress is to catch clicks on the client border */
533 XSelectInput(ob_display
, self
->plate
, PLATE_EVENTMASK
);
535 frame_adjust_area(self
, TRUE
, TRUE
, FALSE
);
537 /* map the client so it maps when the frame does */
538 XMapWindow(ob_display
, client
->window
);
540 /* set all the windows for the frame in the window_map */
541 g_hash_table_insert(window_map
, &self
->window
, client
);
542 g_hash_table_insert(window_map
, &self
->plate
, client
);
543 g_hash_table_insert(window_map
, &self
->title
, client
);
544 g_hash_table_insert(window_map
, &self
->label
, client
);
545 g_hash_table_insert(window_map
, &self
->max
, client
);
546 g_hash_table_insert(window_map
, &self
->close
, client
);
547 g_hash_table_insert(window_map
, &self
->desk
, client
);
548 g_hash_table_insert(window_map
, &self
->shade
, client
);
549 g_hash_table_insert(window_map
, &self
->icon
, client
);
550 g_hash_table_insert(window_map
, &self
->iconify
, client
);
551 g_hash_table_insert(window_map
, &self
->handle
, client
);
552 g_hash_table_insert(window_map
, &self
->lgrip
, client
);
553 g_hash_table_insert(window_map
, &self
->rgrip
, client
);
554 g_hash_table_insert(window_map
, &self
->tltresize
, client
);
555 g_hash_table_insert(window_map
, &self
->tllresize
, client
);
556 g_hash_table_insert(window_map
, &self
->trtresize
, client
);
557 g_hash_table_insert(window_map
, &self
->trrresize
, client
);
560 void frame_release_client(ObFrame
*self
, ObClient
*client
)
563 gboolean reparent
= TRUE
;
565 g_assert(self
->client
== client
);
567 /* check if the app has already reparented its window away */
568 while (XCheckTypedWindowEvent(ob_display
, client
->window
,
569 ReparentNotify
, &ev
))
571 /* This check makes sure we don't catch our own reparent action to
572 our frame window. This doesn't count as the app reparenting itself
575 Reparent events that are generated by us are just discarded here.
576 They are of no consequence to us anyhow.
578 if (ev
.xreparent
.parent
!= self
->plate
) {
580 XPutBackEvent(ob_display
, &ev
);
586 /* according to the ICCCM - if the client doesn't reparent itself,
587 then we will reparent the window to root for them */
588 XReparentWindow(ob_display
, client
->window
,
589 RootWindow(ob_display
, ob_screen
),
594 /* remove all the windows for the frame from the window_map */
595 g_hash_table_remove(window_map
, &self
->window
);
596 g_hash_table_remove(window_map
, &self
->plate
);
597 g_hash_table_remove(window_map
, &self
->title
);
598 g_hash_table_remove(window_map
, &self
->label
);
599 g_hash_table_remove(window_map
, &self
->max
);
600 g_hash_table_remove(window_map
, &self
->close
);
601 g_hash_table_remove(window_map
, &self
->desk
);
602 g_hash_table_remove(window_map
, &self
->shade
);
603 g_hash_table_remove(window_map
, &self
->icon
);
604 g_hash_table_remove(window_map
, &self
->iconify
);
605 g_hash_table_remove(window_map
, &self
->handle
);
606 g_hash_table_remove(window_map
, &self
->lgrip
);
607 g_hash_table_remove(window_map
, &self
->rgrip
);
608 g_hash_table_remove(window_map
, &self
->tltresize
);
609 g_hash_table_remove(window_map
, &self
->tllresize
);
610 g_hash_table_remove(window_map
, &self
->trtresize
);
611 g_hash_table_remove(window_map
, &self
->trrresize
);
613 ob_main_loop_timeout_remove_data(ob_main_loop
, flash_timeout
, self
, TRUE
);
618 static void layout_title(ObFrame
*self
)
622 gboolean n
, d
, i
, l
, m
, c
, s
;
624 n
= d
= i
= l
= m
= c
= s
= FALSE
;
626 /* figure out whats being shown, and the width of the label */
627 self
->label_width
= self
->width
- (ob_rr_theme
->paddingx
+ 1) * 2;
628 for (lc
= config_title_layout
; *lc
!= '\0'; ++lc
) {
631 if (n
) { *lc
= ' '; break; } /* rm duplicates */
633 self
->label_width
-= (ob_rr_theme
->button_size
+ 2 +
634 ob_rr_theme
->paddingx
+ 1);
637 if (d
) { *lc
= ' '; break; }
638 if (!(self
->decorations
& OB_FRAME_DECOR_ALLDESKTOPS
)
639 && config_theme_hidedisabled
)
642 self
->label_width
-= (ob_rr_theme
->button_size
+
643 ob_rr_theme
->paddingx
+ 1);
646 if (s
) { *lc
= ' '; break; }
647 if (!(self
->decorations
& OB_FRAME_DECOR_SHADE
)
648 && config_theme_hidedisabled
)
651 self
->label_width
-= (ob_rr_theme
->button_size
+
652 ob_rr_theme
->paddingx
+ 1);
655 if (i
) { *lc
= ' '; break; }
656 if (!(self
->decorations
& OB_FRAME_DECOR_ICONIFY
)
657 && config_theme_hidedisabled
)
660 self
->label_width
-= (ob_rr_theme
->button_size
+
661 ob_rr_theme
->paddingx
+ 1);
664 if (l
) { *lc
= ' '; break; }
668 if (m
) { *lc
= ' '; break; }
669 if (!(self
->decorations
& OB_FRAME_DECOR_MAXIMIZE
)
670 && config_theme_hidedisabled
)
673 self
->label_width
-= (ob_rr_theme
->button_size
+
674 ob_rr_theme
->paddingx
+ 1);
677 if (c
) { *lc
= ' '; break; }
678 if (!(self
->decorations
& OB_FRAME_DECOR_CLOSE
)
679 && config_theme_hidedisabled
)
682 self
->label_width
-= (ob_rr_theme
->button_size
+
683 ob_rr_theme
->paddingx
+ 1);
687 if (self
->label_width
< 1) self
->label_width
= 1;
689 if (!n
) XUnmapWindow(ob_display
, self
->icon
);
690 if (!d
) XUnmapWindow(ob_display
, self
->desk
);
691 if (!s
) XUnmapWindow(ob_display
, self
->shade
);
692 if (!i
) XUnmapWindow(ob_display
, self
->iconify
);
693 if (!l
) XUnmapWindow(ob_display
, self
->label
);
694 if (!m
) XUnmapWindow(ob_display
, self
->max
);
695 if (!c
) XUnmapWindow(ob_display
, self
->close
);
697 x
= ob_rr_theme
->paddingx
+ 1;
698 for (lc
= config_title_layout
; *lc
!= '\0'; ++lc
) {
703 XMapWindow(ob_display
, self
->icon
);
704 XMoveWindow(ob_display
, self
->icon
, x
, ob_rr_theme
->paddingy
);
705 x
+= ob_rr_theme
->button_size
+ 2 + ob_rr_theme
->paddingx
+ 1;
710 XMapWindow(ob_display
, self
->desk
);
711 XMoveWindow(ob_display
, self
->desk
, x
, ob_rr_theme
->paddingy
+ 1);
712 x
+= ob_rr_theme
->button_size
+ ob_rr_theme
->paddingx
+ 1;
717 XMapWindow(ob_display
, self
->shade
);
718 XMoveWindow(ob_display
, self
->shade
, x
, ob_rr_theme
->paddingy
+ 1);
719 x
+= ob_rr_theme
->button_size
+ ob_rr_theme
->paddingx
+ 1;
724 XMapWindow(ob_display
, self
->iconify
);
725 XMoveWindow(ob_display
,self
->iconify
, x
, ob_rr_theme
->paddingy
+ 1);
726 x
+= ob_rr_theme
->button_size
+ ob_rr_theme
->paddingx
+ 1;
731 XMapWindow(ob_display
, self
->label
);
732 XMoveWindow(ob_display
, self
->label
, x
, ob_rr_theme
->paddingy
);
733 x
+= self
->label_width
+ ob_rr_theme
->paddingx
+ 1;
738 XMapWindow(ob_display
, self
->max
);
739 XMoveWindow(ob_display
, self
->max
, x
, ob_rr_theme
->paddingy
+ 1);
740 x
+= ob_rr_theme
->button_size
+ ob_rr_theme
->paddingx
+ 1;
745 XMapWindow(ob_display
, self
->close
);
746 XMoveWindow(ob_display
, self
->close
, x
, ob_rr_theme
->paddingy
+ 1);
747 x
+= ob_rr_theme
->button_size
+ ob_rr_theme
->paddingx
+ 1;
753 ObFrameContext
frame_context_from_string(const gchar
*name
)
755 if (!g_ascii_strcasecmp("Desktop", name
))
756 return OB_FRAME_CONTEXT_DESKTOP
;
757 else if (!g_ascii_strcasecmp("Client", name
))
758 return OB_FRAME_CONTEXT_CLIENT
;
759 else if (!g_ascii_strcasecmp("Titlebar", name
))
760 return OB_FRAME_CONTEXT_TITLEBAR
;
761 else if (!g_ascii_strcasecmp("Handle", name
))
762 return OB_FRAME_CONTEXT_HANDLE
;
763 else if (!g_ascii_strcasecmp("Frame", name
))
764 return OB_FRAME_CONTEXT_FRAME
;
765 else if (!g_ascii_strcasecmp("TLCorner", name
))
766 return OB_FRAME_CONTEXT_TLCORNER
;
767 else if (!g_ascii_strcasecmp("TRCorner", name
))
768 return OB_FRAME_CONTEXT_TRCORNER
;
769 else if (!g_ascii_strcasecmp("BLCorner", name
))
770 return OB_FRAME_CONTEXT_BLCORNER
;
771 else if (!g_ascii_strcasecmp("BRCorner", name
))
772 return OB_FRAME_CONTEXT_BRCORNER
;
773 else if (!g_ascii_strcasecmp("Maximize", name
))
774 return OB_FRAME_CONTEXT_MAXIMIZE
;
775 else if (!g_ascii_strcasecmp("AllDesktops", name
))
776 return OB_FRAME_CONTEXT_ALLDESKTOPS
;
777 else if (!g_ascii_strcasecmp("Shade", name
))
778 return OB_FRAME_CONTEXT_SHADE
;
779 else if (!g_ascii_strcasecmp("Iconify", name
))
780 return OB_FRAME_CONTEXT_ICONIFY
;
781 else if (!g_ascii_strcasecmp("Icon", name
))
782 return OB_FRAME_CONTEXT_ICON
;
783 else if (!g_ascii_strcasecmp("Close", name
))
784 return OB_FRAME_CONTEXT_CLOSE
;
785 else if (!g_ascii_strcasecmp("MoveResize", name
))
786 return OB_FRAME_CONTEXT_MOVE_RESIZE
;
787 return OB_FRAME_CONTEXT_NONE
;
790 ObFrameContext
frame_context(ObClient
*client
, Window win
)
794 if (moveresize_in_progress
)
795 return OB_FRAME_CONTEXT_MOVE_RESIZE
;
797 if (win
== RootWindow(ob_display
, ob_screen
))
798 return OB_FRAME_CONTEXT_DESKTOP
;
799 if (client
== NULL
) return OB_FRAME_CONTEXT_NONE
;
800 if (win
== client
->window
) {
801 /* conceptually, this is the desktop, as far as users are
803 if (client
->type
== OB_CLIENT_TYPE_DESKTOP
)
804 return OB_FRAME_CONTEXT_DESKTOP
;
805 return OB_FRAME_CONTEXT_CLIENT
;
808 self
= client
->frame
;
809 if (win
== self
->plate
) {
810 /* conceptually, this is the desktop, as far as users are
812 if (client
->type
== OB_CLIENT_TYPE_DESKTOP
)
813 return OB_FRAME_CONTEXT_DESKTOP
;
814 return OB_FRAME_CONTEXT_CLIENT
;
817 if (win
== self
->window
) return OB_FRAME_CONTEXT_FRAME
;
818 if (win
== self
->title
) return OB_FRAME_CONTEXT_TITLEBAR
;
819 if (win
== self
->label
) return OB_FRAME_CONTEXT_TITLEBAR
;
820 if (win
== self
->handle
) return OB_FRAME_CONTEXT_HANDLE
;
821 if (win
== self
->lgrip
) return OB_FRAME_CONTEXT_BLCORNER
;
822 if (win
== self
->rgrip
) return OB_FRAME_CONTEXT_BRCORNER
;
823 if (win
== self
->tltresize
) return OB_FRAME_CONTEXT_TLCORNER
;
824 if (win
== self
->tllresize
) return OB_FRAME_CONTEXT_TLCORNER
;
825 if (win
== self
->trtresize
) return OB_FRAME_CONTEXT_TRCORNER
;
826 if (win
== self
->trrresize
) return OB_FRAME_CONTEXT_TRCORNER
;
827 if (win
== self
->max
) return OB_FRAME_CONTEXT_MAXIMIZE
;
828 if (win
== self
->iconify
) return OB_FRAME_CONTEXT_ICONIFY
;
829 if (win
== self
->close
) return OB_FRAME_CONTEXT_CLOSE
;
830 if (win
== self
->icon
) return OB_FRAME_CONTEXT_ICON
;
831 if (win
== self
->desk
) return OB_FRAME_CONTEXT_ALLDESKTOPS
;
832 if (win
== self
->shade
) return OB_FRAME_CONTEXT_SHADE
;
834 return OB_FRAME_CONTEXT_NONE
;
837 void frame_client_gravity(ObFrame
*self
, gint
*x
, gint
*y
)
840 switch (self
->client
->gravity
) {
842 case NorthWestGravity
:
843 case SouthWestGravity
:
850 *x
-= (self
->size
.left
+ self
->size
.right
) / 2;
853 case NorthEastGravity
:
854 case SouthEastGravity
:
856 *x
-= self
->size
.left
+ self
->size
.right
;
861 *x
-= self
->size
.left
;
866 switch (self
->client
->gravity
) {
868 case NorthWestGravity
:
869 case NorthEastGravity
:
876 *y
-= (self
->size
.top
+ self
->size
.bottom
) / 2;
879 case SouthWestGravity
:
880 case SouthEastGravity
:
882 *y
-= self
->size
.top
+ self
->size
.bottom
;
887 *y
-= self
->size
.top
;
892 void frame_frame_gravity(ObFrame
*self
, gint
*x
, gint
*y
)
895 switch (self
->client
->gravity
) {
897 case NorthWestGravity
:
899 case SouthWestGravity
:
904 *x
+= (self
->size
.left
+ self
->size
.right
) / 2;
906 case NorthEastGravity
:
908 case SouthEastGravity
:
909 *x
+= self
->size
.left
+ self
->size
.right
;
913 *x
+= self
->size
.left
;
918 switch (self
->client
->gravity
) {
920 case NorthWestGravity
:
922 case NorthEastGravity
:
927 *y
+= (self
->size
.top
+ self
->size
.bottom
) / 2;
929 case SouthWestGravity
:
931 case SouthEastGravity
:
932 *y
+= self
->size
.top
+ self
->size
.bottom
;
936 *y
+= self
->size
.top
;
941 static void flash_done(gpointer data
)
943 ObFrame
*self
= data
;
945 if (self
->focused
!= self
->flash_on
)
946 frame_adjust_focus(self
, self
->focused
);
949 static gboolean
flash_timeout(gpointer data
)
951 ObFrame
*self
= data
;
954 g_get_current_time(&now
);
955 if (now
.tv_sec
> self
->flash_end
.tv_sec
||
956 (now
.tv_sec
== self
->flash_end
.tv_sec
&&
957 now
.tv_usec
>= self
->flash_end
.tv_usec
))
958 self
->flashing
= FALSE
;
961 return FALSE
; /* we are done */
963 self
->flash_on
= !self
->flash_on
;
964 if (!self
->focused
) {
965 frame_adjust_focus(self
, self
->flash_on
);
966 self
->focused
= FALSE
;
969 return TRUE
; /* go again */
972 void frame_flash_start(ObFrame
*self
)
974 self
->flash_on
= self
->focused
;
977 ob_main_loop_timeout_add(ob_main_loop
,
978 G_USEC_PER_SEC
* 0.6,
983 g_get_current_time(&self
->flash_end
);
984 g_time_val_add(&self
->flash_end
, G_USEC_PER_SEC
* 5);
986 self
->flashing
= TRUE
;
989 void frame_flash_stop(ObFrame
*self
)
991 self
->flashing
= FALSE
;