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 Ben 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)
33 #define FRAME_EVENTMASK (EnterWindowMask | LeaveWindowMask | \
34 ButtonPressMask | ButtonReleaseMask | \
36 #define ELEMENT_EVENTMASK (ButtonPressMask | ButtonReleaseMask | \
37 ButtonMotionMask | ExposureMask | \
38 EnterWindowMask | LeaveWindowMask)
40 #define FRAME_HANDLE_Y(f) (f->innersize.top + f->client->area.height + \
43 static void layout_title(ObFrame
*self
);
44 static void flash_done(gpointer data
);
45 static gboolean
flash_timeout(gpointer data
);
47 static void set_theme_statics(ObFrame
*self
);
48 static void free_theme_statics(ObFrame
*self
);
50 static Window
createWindow(Window parent
, Visual
*visual
,
51 gulong mask
, XSetWindowAttributes
*attrib
)
53 return XCreateWindow(ob_display
, parent
, 0, 0, 1, 1, 0,
54 (visual
? 32 : RrDepth(ob_rr_inst
)), InputOutput
,
55 (visual
? visual
: RrVisual(ob_rr_inst
)),
60 static Visual
*check_32bit_client(ObClient
*c
)
62 XWindowAttributes wattrib
;
65 ret
= XGetWindowAttributes(ob_display
, c
->window
, &wattrib
);
66 g_assert(ret
!= BadDrawable
);
67 g_assert(ret
!= BadWindow
);
69 if (wattrib
.depth
== 32)
70 return wattrib
.visual
;
74 ObFrame
*frame_new(ObClient
*client
)
76 XSetWindowAttributes attrib
;
81 self
= g_new0(ObFrame
, 1);
83 self
->obscured
= TRUE
;
85 visual
= check_32bit_client(client
);
87 /* create the non-visible decor windows */
91 /* client has a 32-bit visual */
92 mask
|= CWColormap
| CWBackPixel
| CWBorderPixel
;
93 /* create a colormap with the visual */
94 self
->colormap
= attrib
.colormap
=
95 XCreateColormap(ob_display
,
96 RootWindow(ob_display
, ob_screen
),
98 attrib
.background_pixel
= BlackPixel(ob_display
, 0);
99 attrib
.border_pixel
= BlackPixel(ob_display
, 0);
101 attrib
.event_mask
= FRAME_EVENTMASK
;
102 self
->window
= createWindow(RootWindow(ob_display
, ob_screen
), visual
,
104 mask
&= ~CWEventMask
;
105 self
->plate
= createWindow(self
->window
, visual
, mask
, &attrib
);
107 /* create the visible decor windows */
111 /* client has a 32-bit visual */
112 mask
|= CWColormap
| CWBackPixel
| CWBorderPixel
;
113 attrib
.colormap
= RrColormap(ob_rr_inst
);
115 attrib
.event_mask
= ELEMENT_EVENTMASK
;
116 self
->title
= createWindow(self
->window
, NULL
, mask
, &attrib
);
119 attrib
.cursor
= ob_cursor(OB_CURSOR_NORTHWEST
);
120 self
->tltresize
= createWindow(self
->title
, NULL
, mask
, &attrib
);
121 self
->tllresize
= createWindow(self
->title
, NULL
, mask
, &attrib
);
122 attrib
.cursor
= ob_cursor(OB_CURSOR_NORTHEAST
);
123 self
->trtresize
= createWindow(self
->title
, NULL
, mask
, &attrib
);
124 self
->trrresize
= createWindow(self
->title
, NULL
, mask
, &attrib
);
127 self
->label
= createWindow(self
->title
, NULL
, mask
, &attrib
);
128 self
->max
= createWindow(self
->title
, NULL
, mask
, &attrib
);
129 self
->close
= createWindow(self
->title
, NULL
, mask
, &attrib
);
130 self
->desk
= createWindow(self
->title
, NULL
, mask
, &attrib
);
131 self
->shade
= createWindow(self
->title
, NULL
, mask
, &attrib
);
132 self
->icon
= createWindow(self
->title
, NULL
, mask
, &attrib
);
133 self
->iconify
= createWindow(self
->title
, NULL
, mask
, &attrib
);
134 self
->handle
= createWindow(self
->window
, NULL
, mask
, &attrib
);
137 attrib
.cursor
= ob_cursor(OB_CURSOR_SOUTHWEST
);
138 self
->lgrip
= createWindow(self
->handle
, NULL
, mask
, &attrib
);
139 attrib
.cursor
= ob_cursor(OB_CURSOR_SOUTHEAST
);
140 self
->rgrip
= createWindow(self
->handle
, NULL
, mask
, &attrib
);
142 self
->focused
= FALSE
;
144 /* the other stuff is shown based on decor settings */
145 XMapWindow(ob_display
, self
->plate
);
146 XMapWindow(ob_display
, self
->lgrip
);
147 XMapWindow(ob_display
, self
->rgrip
);
148 XMapWindow(ob_display
, self
->label
);
150 self
->max_press
= self
->close_press
= self
->desk_press
=
151 self
->iconify_press
= self
->shade_press
= FALSE
;
152 self
->max_hover
= self
->close_hover
= self
->desk_hover
=
153 self
->iconify_hover
= self
->shade_hover
= FALSE
;
155 set_theme_statics(self
);
157 return (ObFrame
*)self
;
160 static void set_theme_statics(ObFrame
*self
)
162 /* set colors/appearance/sizes for stuff that doesn't change */
163 XSetWindowBorder(ob_display
, self
->window
,
164 RrColorPixel(ob_rr_theme
->frame_b_color
));
165 XSetWindowBorder(ob_display
, self
->title
,
166 RrColorPixel(ob_rr_theme
->frame_b_color
));
167 XSetWindowBorder(ob_display
, self
->handle
,
168 RrColorPixel(ob_rr_theme
->frame_b_color
));
169 XSetWindowBorder(ob_display
, self
->rgrip
,
170 RrColorPixel(ob_rr_theme
->frame_b_color
));
171 XSetWindowBorder(ob_display
, self
->lgrip
,
172 RrColorPixel(ob_rr_theme
->frame_b_color
));
174 XResizeWindow(ob_display
, self
->max
,
175 ob_rr_theme
->button_size
, ob_rr_theme
->button_size
);
176 XResizeWindow(ob_display
, self
->iconify
,
177 ob_rr_theme
->button_size
, ob_rr_theme
->button_size
);
178 XResizeWindow(ob_display
, self
->icon
,
179 ob_rr_theme
->button_size
+ 2, ob_rr_theme
->button_size
+ 2);
180 XResizeWindow(ob_display
, self
->close
,
181 ob_rr_theme
->button_size
, ob_rr_theme
->button_size
);
182 XResizeWindow(ob_display
, self
->desk
,
183 ob_rr_theme
->button_size
, ob_rr_theme
->button_size
);
184 XResizeWindow(ob_display
, self
->shade
,
185 ob_rr_theme
->button_size
, ob_rr_theme
->button_size
);
186 if (ob_rr_theme
->handle_height
> 0) {
187 XResizeWindow(ob_display
, self
->lgrip
,
188 ob_rr_theme
->grip_width
, ob_rr_theme
->handle_height
);
189 XResizeWindow(ob_display
, self
->rgrip
,
190 ob_rr_theme
->grip_width
, ob_rr_theme
->handle_height
);
192 XResizeWindow(ob_display
, self
->tltresize
,
193 ob_rr_theme
->grip_width
, ob_rr_theme
->paddingy
+ 1);
194 XResizeWindow(ob_display
, self
->trtresize
,
195 ob_rr_theme
->grip_width
, ob_rr_theme
->paddingy
+ 1);
196 XResizeWindow(ob_display
, self
->tllresize
,
197 ob_rr_theme
->paddingx
+ 1, ob_rr_theme
->title_height
);
198 XResizeWindow(ob_display
, self
->trrresize
,
199 ob_rr_theme
->paddingx
+ 1, ob_rr_theme
->title_height
);
201 /* set up the dynamic appearances */
202 self
->a_unfocused_title
= RrAppearanceCopy(ob_rr_theme
->a_unfocused_title
);
203 self
->a_focused_title
= RrAppearanceCopy(ob_rr_theme
->a_focused_title
);
204 self
->a_unfocused_label
= RrAppearanceCopy(ob_rr_theme
->a_unfocused_label
);
205 self
->a_focused_label
= RrAppearanceCopy(ob_rr_theme
->a_focused_label
);
206 self
->a_unfocused_handle
=
207 RrAppearanceCopy(ob_rr_theme
->a_unfocused_handle
);
208 self
->a_focused_handle
= RrAppearanceCopy(ob_rr_theme
->a_focused_handle
);
209 self
->a_icon
= RrAppearanceCopy(ob_rr_theme
->a_icon
);
212 static void free_theme_statics(ObFrame
*self
)
214 RrAppearanceFree(self
->a_unfocused_title
);
215 RrAppearanceFree(self
->a_focused_title
);
216 RrAppearanceFree(self
->a_unfocused_label
);
217 RrAppearanceFree(self
->a_focused_label
);
218 RrAppearanceFree(self
->a_unfocused_handle
);
219 RrAppearanceFree(self
->a_focused_handle
);
220 RrAppearanceFree(self
->a_icon
);
223 static void frame_free(ObFrame
*self
)
225 free_theme_statics(self
);
227 XDestroyWindow(ob_display
, self
->window
);
229 XFreeColormap(ob_display
, self
->colormap
);
234 void frame_show(ObFrame
*self
)
236 if (!self
->visible
) {
237 self
->visible
= TRUE
;
238 XMapWindow(ob_display
, self
->client
->window
);
239 XMapWindow(ob_display
, self
->window
);
243 void frame_hide(ObFrame
*self
)
246 self
->visible
= FALSE
;
247 self
->client
->ignore_unmaps
+= 2;
248 /* we unmap the client itself so that we can get MapRequest
249 events, and because the ICCCM tells us to! */
250 XUnmapWindow(ob_display
, self
->window
);
251 XUnmapWindow(ob_display
, self
->client
->window
);
255 void frame_adjust_theme(ObFrame
*self
)
257 free_theme_statics(self
);
258 set_theme_statics(self
);
261 void frame_adjust_shape(ObFrame
*self
)
267 if (!self
->client
->shaped
) {
268 /* clear the shape on the frame window */
269 XShapeCombineMask(ob_display
, self
->window
, ShapeBounding
,
270 self
->innersize
.left
,
274 /* make the frame's shape match the clients */
275 XShapeCombineShape(ob_display
, self
->window
, ShapeBounding
,
276 self
->innersize
.left
,
278 self
->client
->window
,
279 ShapeBounding
, ShapeSet
);
282 if (self
->decorations
& OB_FRAME_DECOR_TITLEBAR
) {
283 xrect
[0].x
= -ob_rr_theme
->fbwidth
;
284 xrect
[0].y
= -ob_rr_theme
->fbwidth
;
285 xrect
[0].width
= self
->width
+ self
->rbwidth
* 2;
286 xrect
[0].height
= ob_rr_theme
->title_height
+
291 if (self
->decorations
& OB_FRAME_DECOR_HANDLE
) {
292 xrect
[1].x
= -ob_rr_theme
->fbwidth
;
293 xrect
[1].y
= FRAME_HANDLE_Y(self
);
294 xrect
[1].width
= self
->width
+ self
->rbwidth
* 2;
295 xrect
[1].height
= ob_rr_theme
->handle_height
+
300 XShapeCombineRectangles(ob_display
, self
->window
,
301 ShapeBounding
, 0, 0, xrect
, num
,
302 ShapeUnion
, Unsorted
);
307 void frame_adjust_area(ObFrame
*self
, gboolean moved
,
308 gboolean resized
, gboolean fake
)
312 oldsize
= self
->size
;
315 self
->decorations
= self
->client
->decorations
;
316 self
->max_horz
= self
->client
->max_horz
;
318 if (self
->decorations
& OB_FRAME_DECOR_BORDER
) {
319 self
->bwidth
= ob_rr_theme
->fbwidth
;
320 self
->cbwidth_x
= ob_rr_theme
->cbwidthx
;
321 self
->cbwidth_y
= ob_rr_theme
->cbwidthy
;
323 self
->bwidth
= self
->cbwidth_x
= self
->cbwidth_y
= 0;
325 self
->rbwidth
= self
->bwidth
;
328 self
->bwidth
= self
->cbwidth_x
= 0;
330 STRUT_SET(self
->innersize
,
335 self
->width
= self
->client
->area
.width
+ self
->cbwidth_x
* 2 -
336 (self
->max_horz
? self
->rbwidth
* 2 : 0);
337 self
->width
= MAX(self
->width
, 1); /* no lower than 1 */
339 /* set border widths */
341 XSetWindowBorderWidth(ob_display
, self
->window
, self
->bwidth
);
342 XSetWindowBorderWidth(ob_display
, self
->title
, self
->rbwidth
);
343 XSetWindowBorderWidth(ob_display
, self
->handle
, self
->rbwidth
);
344 XSetWindowBorderWidth(ob_display
, self
->lgrip
, self
->rbwidth
);
345 XSetWindowBorderWidth(ob_display
, self
->rgrip
, self
->rbwidth
);
348 if (self
->decorations
& OB_FRAME_DECOR_TITLEBAR
)
349 self
->innersize
.top
+= ob_rr_theme
->title_height
+ self
->rbwidth
+
350 (self
->rbwidth
- self
->bwidth
);
351 if (self
->decorations
& OB_FRAME_DECOR_HANDLE
&&
352 ob_rr_theme
->handle_height
> 0)
353 self
->innersize
.bottom
+= ob_rr_theme
->handle_height
+
354 self
->rbwidth
+ (self
->rbwidth
- self
->bwidth
);
356 /* they all default off, they're turned on in layout_title */
360 self
->iconify_x
= -1;
365 /* position/size and map/unmap all the windows */
368 if (self
->decorations
& OB_FRAME_DECOR_TITLEBAR
) {
369 XMoveResizeWindow(ob_display
, self
->title
,
370 -self
->bwidth
, -self
->bwidth
,
371 self
->width
, ob_rr_theme
->title_height
);
372 XMapWindow(ob_display
, self
->title
);
374 if (self
->decorations
& OB_FRAME_DECOR_GRIPS
) {
375 XMoveWindow(ob_display
, self
->tltresize
, 0, 0);
376 XMoveWindow(ob_display
, self
->tllresize
, 0, 0);
377 XMoveWindow(ob_display
, self
->trtresize
,
378 self
->width
- ob_rr_theme
->grip_width
, 0);
379 XMoveWindow(ob_display
, self
->trrresize
,
380 self
->width
- ob_rr_theme
->paddingx
- 1, 0);
381 XMapWindow(ob_display
, self
->tltresize
);
382 XMapWindow(ob_display
, self
->tllresize
);
383 XMapWindow(ob_display
, self
->trtresize
);
384 XMapWindow(ob_display
, self
->trrresize
);
386 XUnmapWindow(ob_display
, self
->tltresize
);
387 XUnmapWindow(ob_display
, self
->tllresize
);
388 XUnmapWindow(ob_display
, self
->trtresize
);
389 XUnmapWindow(ob_display
, self
->trrresize
);
392 XUnmapWindow(ob_display
, self
->title
);
395 if (self
->decorations
& OB_FRAME_DECOR_TITLEBAR
)
396 /* layout the title bar elements */
400 if (self
->decorations
& OB_FRAME_DECOR_HANDLE
&&
401 ob_rr_theme
->handle_height
> 0)
403 XMoveResizeWindow(ob_display
, self
->handle
,
404 -self
->bwidth
, FRAME_HANDLE_Y(self
),
405 self
->width
, ob_rr_theme
->handle_height
);
406 XMapWindow(ob_display
, self
->handle
);
408 if (self
->decorations
& OB_FRAME_DECOR_GRIPS
) {
409 XMoveWindow(ob_display
, self
->lgrip
,
410 -self
->rbwidth
, -self
->rbwidth
);
411 XMoveWindow(ob_display
, self
->rgrip
,
412 -self
->rbwidth
+ self
->width
-
413 ob_rr_theme
->grip_width
, -self
->rbwidth
);
414 XMapWindow(ob_display
, self
->lgrip
);
415 XMapWindow(ob_display
, self
->rgrip
);
417 XUnmapWindow(ob_display
, self
->lgrip
);
418 XUnmapWindow(ob_display
, self
->rgrip
);
421 XUnmapWindow(ob_display
, self
->handle
);
423 /* move and resize the plate */
424 XMoveResizeWindow(ob_display
, self
->plate
,
425 self
->innersize
.left
- self
->cbwidth_x
,
426 self
->innersize
.top
- self
->cbwidth_y
,
427 self
->client
->area
.width
+ self
->cbwidth_x
* 2,
428 self
->client
->area
.height
+ self
->cbwidth_y
* 2);
429 /* when the client has StaticGravity, it likes to move around. */
430 XMoveWindow(ob_display
, self
->client
->window
,
431 self
->cbwidth_x
, self
->cbwidth_y
);
434 STRUT_SET(self
->size
,
435 self
->innersize
.left
+ self
->bwidth
,
436 self
->innersize
.top
+ self
->bwidth
,
437 self
->innersize
.right
+ self
->bwidth
,
438 self
->innersize
.bottom
+ self
->bwidth
);
441 /* shading can change without being moved or resized */
442 RECT_SET_SIZE(self
->area
,
443 self
->client
->area
.width
+
444 self
->size
.left
+ self
->size
.right
,
445 (self
->client
->shaded
?
446 ob_rr_theme
->title_height
+ self
->rbwidth
* 2:
447 self
->client
->area
.height
+
448 self
->size
.top
+ self
->size
.bottom
));
451 /* find the new coordinates, done after setting the frame.size, for
452 frame_client_gravity. */
453 self
->area
.x
= self
->client
->area
.x
;
454 self
->area
.y
= self
->client
->area
.y
;
455 frame_client_gravity(self
, &self
->area
.x
, &self
->area
.y
);
459 /* move and resize the top level frame.
460 shading can change without being moved or resized */
461 XMoveResizeWindow(ob_display
, self
->window
,
462 self
->area
.x
, self
->area
.y
,
463 self
->area
.width
- self
->bwidth
* 2,
464 self
->area
.height
- self
->bwidth
* 2);
467 framerender_frame(self
);
468 frame_adjust_shape(self
);
471 if (!STRUT_EQUAL(self
->size
, oldsize
)) {
473 vals
[0] = self
->size
.left
;
474 vals
[1] = self
->size
.right
;
475 vals
[2] = self
->size
.top
;
476 vals
[3] = self
->size
.bottom
;
477 PROP_SETA32(self
->client
->window
, net_frame_extents
,
481 /* if this occurs while we are focus cycling, the indicator needs to
483 if (focus_cycle_target
== self
->client
)
484 focus_cycle_draw_indicator();
486 if (resized
&& (self
->decorations
& OB_FRAME_DECOR_TITLEBAR
))
487 XResizeWindow(ob_display
, self
->label
, self
->label_width
,
488 ob_rr_theme
->label_height
);
491 void frame_adjust_state(ObFrame
*self
)
493 framerender_frame(self
);
496 void frame_adjust_focus(ObFrame
*self
, gboolean hilite
)
498 self
->focused
= hilite
;
499 framerender_frame(self
);
502 void frame_adjust_title(ObFrame
*self
)
504 framerender_frame(self
);
507 void frame_adjust_icon(ObFrame
*self
)
509 framerender_frame(self
);
512 void frame_grab_client(ObFrame
*self
, ObClient
*client
)
514 self
->client
= client
;
516 /* reparent the client to the frame */
517 XReparentWindow(ob_display
, client
->window
, self
->plate
, 0, 0);
519 When reparenting the client window, it is usually not mapped yet, since
520 this occurs from a MapRequest. However, in the case where Openbox is
521 starting up, the window is already mapped, so we'll see unmap events for
522 it. There are 2 unmap events generated that we see, one with the 'event'
523 member set the root window, and one set to the client, but both get
524 handled and need to be ignored.
526 if (ob_state() == OB_STATE_STARTING
)
527 client
->ignore_unmaps
+= 2;
529 /* select the event mask on the client's parent (to receive config/map
530 req's) the ButtonPress is to catch clicks on the client border */
531 XSelectInput(ob_display
, self
->plate
, PLATE_EVENTMASK
);
533 /* map the client so it maps when the frame does */
534 XMapWindow(ob_display
, client
->window
);
536 frame_adjust_area(self
, TRUE
, TRUE
, FALSE
);
538 /* set all the windows for the frame in the window_map */
539 g_hash_table_insert(window_map
, &self
->window
, client
);
540 g_hash_table_insert(window_map
, &self
->plate
, client
);
541 g_hash_table_insert(window_map
, &self
->title
, client
);
542 g_hash_table_insert(window_map
, &self
->label
, client
);
543 g_hash_table_insert(window_map
, &self
->max
, client
);
544 g_hash_table_insert(window_map
, &self
->close
, client
);
545 g_hash_table_insert(window_map
, &self
->desk
, client
);
546 g_hash_table_insert(window_map
, &self
->shade
, client
);
547 g_hash_table_insert(window_map
, &self
->icon
, client
);
548 g_hash_table_insert(window_map
, &self
->iconify
, client
);
549 g_hash_table_insert(window_map
, &self
->handle
, client
);
550 g_hash_table_insert(window_map
, &self
->lgrip
, client
);
551 g_hash_table_insert(window_map
, &self
->rgrip
, client
);
552 g_hash_table_insert(window_map
, &self
->tltresize
, client
);
553 g_hash_table_insert(window_map
, &self
->tllresize
, client
);
554 g_hash_table_insert(window_map
, &self
->trtresize
, client
);
555 g_hash_table_insert(window_map
, &self
->trrresize
, client
);
558 void frame_release_client(ObFrame
*self
, ObClient
*client
)
561 gboolean reparent
= TRUE
;
563 g_assert(self
->client
== client
);
565 /* check if the app has already reparented its window away */
566 while (XCheckTypedWindowEvent(ob_display
, client
->window
,
567 ReparentNotify
, &ev
))
569 /* This check makes sure we don't catch our own reparent action to
570 our frame window. This doesn't count as the app reparenting itself
573 Reparent events that are generated by us are just discarded here.
574 They are of no consequence to us anyhow.
576 if (ev
.xreparent
.parent
!= self
->plate
) {
578 XPutBackEvent(ob_display
, &ev
);
584 /* according to the ICCCM - if the client doesn't reparent itself,
585 then we will reparent the window to root for them */
586 XReparentWindow(ob_display
, client
->window
,
587 RootWindow(ob_display
, ob_screen
),
592 /* remove all the windows for the frame from the window_map */
593 g_hash_table_remove(window_map
, &self
->window
);
594 g_hash_table_remove(window_map
, &self
->plate
);
595 g_hash_table_remove(window_map
, &self
->title
);
596 g_hash_table_remove(window_map
, &self
->label
);
597 g_hash_table_remove(window_map
, &self
->max
);
598 g_hash_table_remove(window_map
, &self
->close
);
599 g_hash_table_remove(window_map
, &self
->desk
);
600 g_hash_table_remove(window_map
, &self
->shade
);
601 g_hash_table_remove(window_map
, &self
->icon
);
602 g_hash_table_remove(window_map
, &self
->iconify
);
603 g_hash_table_remove(window_map
, &self
->handle
);
604 g_hash_table_remove(window_map
, &self
->lgrip
);
605 g_hash_table_remove(window_map
, &self
->rgrip
);
606 g_hash_table_remove(window_map
, &self
->tltresize
);
607 g_hash_table_remove(window_map
, &self
->tllresize
);
608 g_hash_table_remove(window_map
, &self
->trtresize
);
609 g_hash_table_remove(window_map
, &self
->trrresize
);
611 ob_main_loop_timeout_remove_data(ob_main_loop
, flash_timeout
, self
, TRUE
);
616 static void layout_title(ObFrame
*self
)
620 gboolean n
, d
, i
, l
, m
, c
, s
;
622 n
= d
= i
= l
= m
= c
= s
= FALSE
;
624 /* figure out whats being shown, and the width of the label */
625 self
->label_width
= self
->width
- (ob_rr_theme
->paddingx
+ 1) * 2;
626 for (lc
= config_title_layout
; *lc
!= '\0'; ++lc
) {
629 if (n
) { *lc
= ' '; break; } /* rm duplicates */
631 self
->label_width
-= (ob_rr_theme
->button_size
+ 2 +
632 ob_rr_theme
->paddingx
+ 1);
635 if (d
) { *lc
= ' '; break; }
636 if (!(self
->decorations
& OB_FRAME_DECOR_ALLDESKTOPS
)
637 && config_theme_hidedisabled
)
640 self
->label_width
-= (ob_rr_theme
->button_size
+
641 ob_rr_theme
->paddingx
+ 1);
644 if (s
) { *lc
= ' '; break; }
645 if (!(self
->decorations
& OB_FRAME_DECOR_SHADE
)
646 && config_theme_hidedisabled
)
649 self
->label_width
-= (ob_rr_theme
->button_size
+
650 ob_rr_theme
->paddingx
+ 1);
653 if (i
) { *lc
= ' '; break; }
654 if (!(self
->decorations
& OB_FRAME_DECOR_ICONIFY
)
655 && config_theme_hidedisabled
)
658 self
->label_width
-= (ob_rr_theme
->button_size
+
659 ob_rr_theme
->paddingx
+ 1);
662 if (l
) { *lc
= ' '; break; }
666 if (m
) { *lc
= ' '; break; }
667 if (!(self
->decorations
& OB_FRAME_DECOR_MAXIMIZE
)
668 && config_theme_hidedisabled
)
671 self
->label_width
-= (ob_rr_theme
->button_size
+
672 ob_rr_theme
->paddingx
+ 1);
675 if (c
) { *lc
= ' '; break; }
676 if (!(self
->decorations
& OB_FRAME_DECOR_CLOSE
)
677 && config_theme_hidedisabled
)
680 self
->label_width
-= (ob_rr_theme
->button_size
+
681 ob_rr_theme
->paddingx
+ 1);
685 if (self
->label_width
< 1) self
->label_width
= 1;
687 if (!n
) XUnmapWindow(ob_display
, self
->icon
);
688 if (!d
) XUnmapWindow(ob_display
, self
->desk
);
689 if (!s
) XUnmapWindow(ob_display
, self
->shade
);
690 if (!i
) XUnmapWindow(ob_display
, self
->iconify
);
691 if (!l
) XUnmapWindow(ob_display
, self
->label
);
692 if (!m
) XUnmapWindow(ob_display
, self
->max
);
693 if (!c
) XUnmapWindow(ob_display
, self
->close
);
695 x
= ob_rr_theme
->paddingx
+ 1;
696 for (lc
= config_title_layout
; *lc
!= '\0'; ++lc
) {
701 XMapWindow(ob_display
, self
->icon
);
702 XMoveWindow(ob_display
, self
->icon
, x
, ob_rr_theme
->paddingy
);
703 x
+= ob_rr_theme
->button_size
+ 2 + ob_rr_theme
->paddingx
+ 1;
708 XMapWindow(ob_display
, self
->desk
);
709 XMoveWindow(ob_display
, self
->desk
, x
, ob_rr_theme
->paddingy
+ 1);
710 x
+= ob_rr_theme
->button_size
+ ob_rr_theme
->paddingx
+ 1;
715 XMapWindow(ob_display
, self
->shade
);
716 XMoveWindow(ob_display
, self
->shade
, x
, ob_rr_theme
->paddingy
+ 1);
717 x
+= ob_rr_theme
->button_size
+ ob_rr_theme
->paddingx
+ 1;
722 XMapWindow(ob_display
, self
->iconify
);
723 XMoveWindow(ob_display
,self
->iconify
, x
, ob_rr_theme
->paddingy
+ 1);
724 x
+= ob_rr_theme
->button_size
+ ob_rr_theme
->paddingx
+ 1;
729 XMapWindow(ob_display
, self
->label
);
730 XMoveWindow(ob_display
, self
->label
, x
, ob_rr_theme
->paddingy
);
731 x
+= self
->label_width
+ ob_rr_theme
->paddingx
+ 1;
736 XMapWindow(ob_display
, self
->max
);
737 XMoveWindow(ob_display
, self
->max
, x
, ob_rr_theme
->paddingy
+ 1);
738 x
+= ob_rr_theme
->button_size
+ ob_rr_theme
->paddingx
+ 1;
743 XMapWindow(ob_display
, self
->close
);
744 XMoveWindow(ob_display
, self
->close
, x
, ob_rr_theme
->paddingy
+ 1);
745 x
+= ob_rr_theme
->button_size
+ ob_rr_theme
->paddingx
+ 1;
751 ObFrameContext
frame_context_from_string(const gchar
*name
)
753 if (!g_ascii_strcasecmp("Desktop", name
))
754 return OB_FRAME_CONTEXT_DESKTOP
;
755 else if (!g_ascii_strcasecmp("Client", name
))
756 return OB_FRAME_CONTEXT_CLIENT
;
757 else if (!g_ascii_strcasecmp("Titlebar", name
))
758 return OB_FRAME_CONTEXT_TITLEBAR
;
759 else if (!g_ascii_strcasecmp("Handle", name
))
760 return OB_FRAME_CONTEXT_HANDLE
;
761 else if (!g_ascii_strcasecmp("Frame", name
))
762 return OB_FRAME_CONTEXT_FRAME
;
763 else if (!g_ascii_strcasecmp("TLCorner", name
))
764 return OB_FRAME_CONTEXT_TLCORNER
;
765 else if (!g_ascii_strcasecmp("TRCorner", name
))
766 return OB_FRAME_CONTEXT_TRCORNER
;
767 else if (!g_ascii_strcasecmp("BLCorner", name
))
768 return OB_FRAME_CONTEXT_BLCORNER
;
769 else if (!g_ascii_strcasecmp("BRCorner", name
))
770 return OB_FRAME_CONTEXT_BRCORNER
;
771 else if (!g_ascii_strcasecmp("Maximize", name
))
772 return OB_FRAME_CONTEXT_MAXIMIZE
;
773 else if (!g_ascii_strcasecmp("AllDesktops", name
))
774 return OB_FRAME_CONTEXT_ALLDESKTOPS
;
775 else if (!g_ascii_strcasecmp("Shade", name
))
776 return OB_FRAME_CONTEXT_SHADE
;
777 else if (!g_ascii_strcasecmp("Iconify", name
))
778 return OB_FRAME_CONTEXT_ICONIFY
;
779 else if (!g_ascii_strcasecmp("Icon", name
))
780 return OB_FRAME_CONTEXT_ICON
;
781 else if (!g_ascii_strcasecmp("Close", name
))
782 return OB_FRAME_CONTEXT_CLOSE
;
783 else if (!g_ascii_strcasecmp("MoveResize", name
))
784 return OB_FRAME_CONTEXT_MOVE_RESIZE
;
785 return OB_FRAME_CONTEXT_NONE
;
788 ObFrameContext
frame_context(ObClient
*client
, Window win
)
792 if (moveresize_in_progress
)
793 return OB_FRAME_CONTEXT_MOVE_RESIZE
;
795 if (win
== RootWindow(ob_display
, ob_screen
))
796 return OB_FRAME_CONTEXT_DESKTOP
;
797 if (client
== NULL
) return OB_FRAME_CONTEXT_NONE
;
798 if (win
== client
->window
) {
799 /* conceptually, this is the desktop, as far as users are
801 if (client
->type
== OB_CLIENT_TYPE_DESKTOP
)
802 return OB_FRAME_CONTEXT_DESKTOP
;
803 return OB_FRAME_CONTEXT_CLIENT
;
806 self
= client
->frame
;
807 if (win
== self
->plate
) {
808 /* conceptually, this is the desktop, as far as users are
810 if (client
->type
== OB_CLIENT_TYPE_DESKTOP
)
811 return OB_FRAME_CONTEXT_DESKTOP
;
812 return OB_FRAME_CONTEXT_CLIENT
;
815 if (win
== self
->window
) return OB_FRAME_CONTEXT_FRAME
;
816 if (win
== self
->title
) return OB_FRAME_CONTEXT_TITLEBAR
;
817 if (win
== self
->label
) return OB_FRAME_CONTEXT_TITLEBAR
;
818 if (win
== self
->handle
) return OB_FRAME_CONTEXT_HANDLE
;
819 if (win
== self
->lgrip
) return OB_FRAME_CONTEXT_BLCORNER
;
820 if (win
== self
->rgrip
) return OB_FRAME_CONTEXT_BRCORNER
;
821 if (win
== self
->tltresize
) return OB_FRAME_CONTEXT_TLCORNER
;
822 if (win
== self
->tllresize
) return OB_FRAME_CONTEXT_TLCORNER
;
823 if (win
== self
->trtresize
) return OB_FRAME_CONTEXT_TRCORNER
;
824 if (win
== self
->trrresize
) return OB_FRAME_CONTEXT_TRCORNER
;
825 if (win
== self
->max
) return OB_FRAME_CONTEXT_MAXIMIZE
;
826 if (win
== self
->iconify
) return OB_FRAME_CONTEXT_ICONIFY
;
827 if (win
== self
->close
) return OB_FRAME_CONTEXT_CLOSE
;
828 if (win
== self
->icon
) return OB_FRAME_CONTEXT_ICON
;
829 if (win
== self
->desk
) return OB_FRAME_CONTEXT_ALLDESKTOPS
;
830 if (win
== self
->shade
) return OB_FRAME_CONTEXT_SHADE
;
832 return OB_FRAME_CONTEXT_NONE
;
835 void frame_client_gravity(ObFrame
*self
, gint
*x
, gint
*y
)
838 switch (self
->client
->gravity
) {
840 case NorthWestGravity
:
841 case SouthWestGravity
:
848 *x
-= (self
->size
.left
+ self
->size
.right
) / 2;
851 case NorthEastGravity
:
852 case SouthEastGravity
:
854 *x
-= self
->size
.left
+ self
->size
.right
;
859 *x
-= self
->size
.left
;
864 switch (self
->client
->gravity
) {
866 case NorthWestGravity
:
867 case NorthEastGravity
:
874 *y
-= (self
->size
.top
+ self
->size
.bottom
) / 2;
877 case SouthWestGravity
:
878 case SouthEastGravity
:
880 *y
-= self
->size
.top
+ self
->size
.bottom
;
885 *y
-= self
->size
.top
;
890 void frame_frame_gravity(ObFrame
*self
, gint
*x
, gint
*y
)
893 switch (self
->client
->gravity
) {
895 case NorthWestGravity
:
897 case SouthWestGravity
:
902 *x
+= (self
->size
.left
+ self
->size
.right
) / 2;
904 case NorthEastGravity
:
906 case SouthEastGravity
:
907 *x
+= self
->size
.left
+ self
->size
.right
;
911 *x
+= self
->size
.left
;
916 switch (self
->client
->gravity
) {
918 case NorthWestGravity
:
920 case NorthEastGravity
:
925 *y
+= (self
->size
.top
+ self
->size
.bottom
) / 2;
927 case SouthWestGravity
:
929 case SouthEastGravity
:
930 *y
+= self
->size
.top
+ self
->size
.bottom
;
934 *y
+= self
->size
.top
;
939 static void flash_done(gpointer data
)
941 ObFrame
*self
= data
;
943 if (self
->focused
!= self
->flash_on
)
944 frame_adjust_focus(self
, self
->focused
);
947 static gboolean
flash_timeout(gpointer data
)
949 ObFrame
*self
= data
;
952 g_get_current_time(&now
);
953 if (now
.tv_sec
> self
->flash_end
.tv_sec
||
954 (now
.tv_sec
== self
->flash_end
.tv_sec
&&
955 now
.tv_usec
>= self
->flash_end
.tv_usec
))
956 self
->flashing
= FALSE
;
959 return FALSE
; /* we are done */
961 self
->flash_on
= !self
->flash_on
;
962 if (!self
->focused
) {
963 frame_adjust_focus(self
, self
->flash_on
);
964 self
->focused
= FALSE
;
967 return TRUE
; /* go again */
970 void frame_flash_start(ObFrame
*self
)
972 self
->flash_on
= self
->focused
;
975 ob_main_loop_timeout_add(ob_main_loop
,
976 G_USEC_PER_SEC
* 0.6,
980 g_get_current_time(&self
->flash_end
);
981 g_time_val_add(&self
->flash_end
, G_USEC_PER_SEC
* 5);
983 self
->flashing
= TRUE
;
986 void frame_flash_stop(ObFrame
*self
)
988 self
->flashing
= FALSE
;