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
,
106 /* create the visible decor windows */
109 /* client has a 32-bit visual */
110 mask
|= CWColormap
| CWBackPixel
| CWBorderPixel
;
111 attrib
.colormap
= RrColormap(ob_rr_inst
);
113 attrib
.event_mask
= ELEMENT_EVENTMASK
;
114 self
->inner
= createWindow(self
->window
, NULL
, mask
, &attrib
);
115 self
->title
= createWindow(self
->window
, NULL
, mask
, &attrib
);
118 attrib
.cursor
= ob_cursor(OB_CURSOR_NORTHWEST
);
119 self
->tltresize
= createWindow(self
->title
, NULL
, mask
, &attrib
);
120 self
->tllresize
= createWindow(self
->title
, NULL
, mask
, &attrib
);
121 attrib
.cursor
= ob_cursor(OB_CURSOR_NORTHEAST
);
122 self
->trtresize
= createWindow(self
->title
, NULL
, mask
, &attrib
);
123 self
->trrresize
= createWindow(self
->title
, NULL
, mask
, &attrib
);
126 self
->label
= createWindow(self
->title
, NULL
, mask
, &attrib
);
127 self
->max
= createWindow(self
->title
, NULL
, mask
, &attrib
);
128 self
->close
= createWindow(self
->title
, NULL
, mask
, &attrib
);
129 self
->desk
= createWindow(self
->title
, NULL
, mask
, &attrib
);
130 self
->shade
= createWindow(self
->title
, NULL
, mask
, &attrib
);
131 self
->icon
= createWindow(self
->title
, NULL
, mask
, &attrib
);
132 self
->iconify
= createWindow(self
->title
, NULL
, mask
, &attrib
);
133 self
->handle
= createWindow(self
->window
, NULL
, mask
, &attrib
);
136 attrib
.cursor
= ob_cursor(OB_CURSOR_SOUTHWEST
);
137 self
->lgrip
= createWindow(self
->handle
, NULL
, mask
, &attrib
);
138 attrib
.cursor
= ob_cursor(OB_CURSOR_SOUTHEAST
);
139 self
->rgrip
= createWindow(self
->handle
, NULL
, mask
, &attrib
);
141 /* create the plate window which holds the client */
143 mask
&= ~(CWEventMask
| CWCursor
);
144 self
->plate
= createWindow(self
->inner
, visual
, mask
, &attrib
);
146 self
->focused
= FALSE
;
148 /* the other stuff is shown based on decor settings */
149 XMapWindow(ob_display
, self
->plate
);
150 XMapWindow(ob_display
, self
->inner
);
151 XMapWindow(ob_display
, self
->lgrip
);
152 XMapWindow(ob_display
, self
->rgrip
);
153 XMapWindow(ob_display
, self
->label
);
155 self
->max_press
= self
->close_press
= self
->desk_press
=
156 self
->iconify_press
= self
->shade_press
= FALSE
;
157 self
->max_hover
= self
->close_hover
= self
->desk_hover
=
158 self
->iconify_hover
= self
->shade_hover
= FALSE
;
160 set_theme_statics(self
);
162 return (ObFrame
*)self
;
165 static void set_theme_statics(ObFrame
*self
)
167 /* set colors/appearance/sizes for stuff that doesn't change */
168 XSetWindowBorder(ob_display
, self
->window
,
169 RrColorPixel(ob_rr_theme
->frame_b_color
));
170 XSetWindowBorder(ob_display
, self
->title
,
171 RrColorPixel(ob_rr_theme
->frame_b_color
));
172 XSetWindowBorder(ob_display
, self
->handle
,
173 RrColorPixel(ob_rr_theme
->frame_b_color
));
174 XSetWindowBorder(ob_display
, self
->rgrip
,
175 RrColorPixel(ob_rr_theme
->frame_b_color
));
176 XSetWindowBorder(ob_display
, self
->lgrip
,
177 RrColorPixel(ob_rr_theme
->frame_b_color
));
179 XResizeWindow(ob_display
, self
->max
,
180 ob_rr_theme
->button_size
, ob_rr_theme
->button_size
);
181 XResizeWindow(ob_display
, self
->iconify
,
182 ob_rr_theme
->button_size
, ob_rr_theme
->button_size
);
183 XResizeWindow(ob_display
, self
->icon
,
184 ob_rr_theme
->button_size
+ 2, ob_rr_theme
->button_size
+ 2);
185 XResizeWindow(ob_display
, self
->close
,
186 ob_rr_theme
->button_size
, ob_rr_theme
->button_size
);
187 XResizeWindow(ob_display
, self
->desk
,
188 ob_rr_theme
->button_size
, ob_rr_theme
->button_size
);
189 XResizeWindow(ob_display
, self
->shade
,
190 ob_rr_theme
->button_size
, ob_rr_theme
->button_size
);
191 if (ob_rr_theme
->handle_height
> 0) {
192 XResizeWindow(ob_display
, self
->lgrip
,
193 ob_rr_theme
->grip_width
, ob_rr_theme
->handle_height
);
194 XResizeWindow(ob_display
, self
->rgrip
,
195 ob_rr_theme
->grip_width
, ob_rr_theme
->handle_height
);
197 XResizeWindow(ob_display
, self
->tltresize
,
198 ob_rr_theme
->grip_width
, ob_rr_theme
->paddingy
+ 1);
199 XResizeWindow(ob_display
, self
->trtresize
,
200 ob_rr_theme
->grip_width
, ob_rr_theme
->paddingy
+ 1);
201 XResizeWindow(ob_display
, self
->tllresize
,
202 ob_rr_theme
->paddingx
+ 1, ob_rr_theme
->title_height
);
203 XResizeWindow(ob_display
, self
->trrresize
,
204 ob_rr_theme
->paddingx
+ 1, ob_rr_theme
->title_height
);
206 /* set up the dynamic appearances */
207 self
->a_unfocused_title
= RrAppearanceCopy(ob_rr_theme
->a_unfocused_title
);
208 self
->a_focused_title
= RrAppearanceCopy(ob_rr_theme
->a_focused_title
);
209 self
->a_unfocused_label
= RrAppearanceCopy(ob_rr_theme
->a_unfocused_label
);
210 self
->a_focused_label
= RrAppearanceCopy(ob_rr_theme
->a_focused_label
);
211 self
->a_unfocused_handle
=
212 RrAppearanceCopy(ob_rr_theme
->a_unfocused_handle
);
213 self
->a_focused_handle
= RrAppearanceCopy(ob_rr_theme
->a_focused_handle
);
214 self
->a_icon
= RrAppearanceCopy(ob_rr_theme
->a_icon
);
217 static void free_theme_statics(ObFrame
*self
)
219 RrAppearanceFree(self
->a_unfocused_title
);
220 RrAppearanceFree(self
->a_focused_title
);
221 RrAppearanceFree(self
->a_unfocused_label
);
222 RrAppearanceFree(self
->a_focused_label
);
223 RrAppearanceFree(self
->a_unfocused_handle
);
224 RrAppearanceFree(self
->a_focused_handle
);
225 RrAppearanceFree(self
->a_icon
);
228 static void frame_free(ObFrame
*self
)
230 free_theme_statics(self
);
232 XDestroyWindow(ob_display
, self
->window
);
234 XFreeColormap(ob_display
, self
->colormap
);
239 void frame_show(ObFrame
*self
)
241 if (!self
->visible
) {
242 self
->visible
= TRUE
;
243 XMapWindow(ob_display
, self
->client
->window
);
244 XMapWindow(ob_display
, self
->window
);
248 void frame_hide(ObFrame
*self
)
251 self
->visible
= FALSE
;
252 self
->client
->ignore_unmaps
+= 1;
253 /* we unmap the client itself so that we can get MapRequest
254 events, and because the ICCCM tells us to! */
255 XUnmapWindow(ob_display
, self
->window
);
256 XUnmapWindow(ob_display
, self
->client
->window
);
260 void frame_adjust_theme(ObFrame
*self
)
262 free_theme_statics(self
);
263 set_theme_statics(self
);
266 void frame_adjust_shape(ObFrame
*self
)
272 if (!self
->client
->shaped
) {
273 /* clear the shape on the frame window */
274 XShapeCombineMask(ob_display
, self
->window
, ShapeBounding
,
275 self
->innersize
.left
,
279 /* make the frame's shape match the clients */
280 XShapeCombineShape(ob_display
, self
->window
, ShapeBounding
,
281 self
->innersize
.left
,
283 self
->client
->window
,
284 ShapeBounding
, ShapeSet
);
287 if (self
->decorations
& OB_FRAME_DECOR_TITLEBAR
) {
288 xrect
[0].x
= -ob_rr_theme
->fbwidth
;
289 xrect
[0].y
= -ob_rr_theme
->fbwidth
;
290 xrect
[0].width
= self
->width
+ self
->rbwidth
* 2;
291 xrect
[0].height
= ob_rr_theme
->title_height
+
296 if (self
->decorations
& OB_FRAME_DECOR_HANDLE
) {
297 xrect
[1].x
= -ob_rr_theme
->fbwidth
;
298 xrect
[1].y
= FRAME_HANDLE_Y(self
);
299 xrect
[1].width
= self
->width
+ self
->rbwidth
* 2;
300 xrect
[1].height
= ob_rr_theme
->handle_height
+
305 XShapeCombineRectangles(ob_display
, self
->window
,
306 ShapeBounding
, 0, 0, xrect
, num
,
307 ShapeUnion
, Unsorted
);
312 void frame_adjust_area(ObFrame
*self
, gboolean moved
,
313 gboolean resized
, gboolean fake
)
317 oldsize
= self
->size
;
320 self
->decorations
= self
->client
->decorations
;
321 self
->max_horz
= self
->client
->max_horz
;
323 if (self
->decorations
& OB_FRAME_DECOR_BORDER
) {
324 self
->bwidth
= ob_rr_theme
->fbwidth
;
325 self
->cbwidth_x
= ob_rr_theme
->cbwidthx
;
326 self
->cbwidth_y
= ob_rr_theme
->cbwidthy
;
328 self
->bwidth
= self
->cbwidth_x
= self
->cbwidth_y
= 0;
330 self
->rbwidth
= self
->bwidth
;
333 self
->bwidth
= self
->cbwidth_x
= 0;
335 STRUT_SET(self
->innersize
,
340 self
->width
= self
->client
->area
.width
+ self
->cbwidth_x
* 2 -
341 (self
->max_horz
? self
->rbwidth
* 2 : 0);
342 self
->width
= MAX(self
->width
, 1); /* no lower than 1 */
344 /* set border widths */
346 XSetWindowBorderWidth(ob_display
, self
->window
, self
->bwidth
);
347 XSetWindowBorderWidth(ob_display
, self
->title
, self
->rbwidth
);
348 XSetWindowBorderWidth(ob_display
, self
->handle
, self
->rbwidth
);
349 XSetWindowBorderWidth(ob_display
, self
->lgrip
, self
->rbwidth
);
350 XSetWindowBorderWidth(ob_display
, self
->rgrip
, self
->rbwidth
);
353 if (self
->decorations
& OB_FRAME_DECOR_TITLEBAR
)
354 self
->innersize
.top
+= ob_rr_theme
->title_height
+ self
->rbwidth
+
355 (self
->rbwidth
- self
->bwidth
);
356 if (self
->decorations
& OB_FRAME_DECOR_HANDLE
&&
357 ob_rr_theme
->handle_height
> 0)
358 self
->innersize
.bottom
+= ob_rr_theme
->handle_height
+
359 self
->rbwidth
+ (self
->rbwidth
- self
->bwidth
);
361 /* they all default off, they're turned on in layout_title */
365 self
->iconify_x
= -1;
370 /* position/size and map/unmap all the windows */
373 if (self
->decorations
& OB_FRAME_DECOR_TITLEBAR
) {
374 XMoveResizeWindow(ob_display
, self
->title
,
375 -self
->bwidth
, -self
->bwidth
,
376 self
->width
, ob_rr_theme
->title_height
);
377 XMapWindow(ob_display
, self
->title
);
379 if (self
->decorations
& OB_FRAME_DECOR_GRIPS
) {
380 XMoveWindow(ob_display
, self
->tltresize
, 0, 0);
381 XMoveWindow(ob_display
, self
->tllresize
, 0, 0);
382 XMoveWindow(ob_display
, self
->trtresize
,
383 self
->width
- ob_rr_theme
->grip_width
, 0);
384 XMoveWindow(ob_display
, self
->trrresize
,
385 self
->width
- ob_rr_theme
->paddingx
- 1, 0);
386 XMapWindow(ob_display
, self
->tltresize
);
387 XMapWindow(ob_display
, self
->tllresize
);
388 XMapWindow(ob_display
, self
->trtresize
);
389 XMapWindow(ob_display
, self
->trrresize
);
391 XUnmapWindow(ob_display
, self
->tltresize
);
392 XUnmapWindow(ob_display
, self
->tllresize
);
393 XUnmapWindow(ob_display
, self
->trtresize
);
394 XUnmapWindow(ob_display
, self
->trrresize
);
397 XUnmapWindow(ob_display
, self
->title
);
400 if (self
->decorations
& OB_FRAME_DECOR_TITLEBAR
)
401 /* layout the title bar elements */
405 if (self
->decorations
& OB_FRAME_DECOR_HANDLE
&&
406 ob_rr_theme
->handle_height
> 0)
408 XMoveResizeWindow(ob_display
, self
->handle
,
409 -self
->bwidth
, FRAME_HANDLE_Y(self
),
410 self
->width
, ob_rr_theme
->handle_height
);
411 XMapWindow(ob_display
, self
->handle
);
413 if (self
->decorations
& OB_FRAME_DECOR_GRIPS
) {
414 XMoveWindow(ob_display
, self
->lgrip
,
415 -self
->rbwidth
, -self
->rbwidth
);
416 XMoveWindow(ob_display
, self
->rgrip
,
417 -self
->rbwidth
+ self
->width
-
418 ob_rr_theme
->grip_width
, -self
->rbwidth
);
419 XMapWindow(ob_display
, self
->lgrip
);
420 XMapWindow(ob_display
, self
->rgrip
);
422 XUnmapWindow(ob_display
, self
->lgrip
);
423 XUnmapWindow(ob_display
, self
->rgrip
);
426 XUnmapWindow(ob_display
, self
->handle
);
428 /* move and resize the inner border window which contains the plate
430 XMoveResizeWindow(ob_display
, self
->inner
,
431 self
->innersize
.left
- self
->cbwidth_x
,
432 self
->innersize
.top
- self
->cbwidth_y
,
433 self
->client
->area
.width
+
435 self
->client
->area
.height
+
436 self
->cbwidth_y
* 2);
438 /* move and resize the plate */
439 XMoveResizeWindow(ob_display
, self
->plate
,
442 self
->client
->area
.width
,
443 self
->client
->area
.height
);
444 /* when the client has StaticGravity, it likes to move around. */
445 XMoveWindow(ob_display
, self
->client
->window
, 0, 0);
448 STRUT_SET(self
->size
,
449 self
->innersize
.left
+ self
->bwidth
,
450 self
->innersize
.top
+ self
->bwidth
,
451 self
->innersize
.right
+ self
->bwidth
,
452 self
->innersize
.bottom
+ self
->bwidth
);
455 /* shading can change without being moved or resized */
456 RECT_SET_SIZE(self
->area
,
457 self
->client
->area
.width
+
458 self
->size
.left
+ self
->size
.right
,
459 (self
->client
->shaded
?
460 ob_rr_theme
->title_height
+ self
->rbwidth
* 2:
461 self
->client
->area
.height
+
462 self
->size
.top
+ self
->size
.bottom
));
465 /* find the new coordinates, done after setting the frame.size, for
466 frame_client_gravity. */
467 self
->area
.x
= self
->client
->area
.x
;
468 self
->area
.y
= self
->client
->area
.y
;
469 frame_client_gravity(self
, &self
->area
.x
, &self
->area
.y
);
473 /* move and resize the top level frame.
474 shading can change without being moved or resized */
475 XMoveResizeWindow(ob_display
, self
->window
,
476 self
->area
.x
, self
->area
.y
,
477 self
->area
.width
- self
->bwidth
* 2,
478 self
->area
.height
- self
->bwidth
* 2);
481 framerender_frame(self
);
482 frame_adjust_shape(self
);
485 if (!STRUT_EQUAL(self
->size
, oldsize
)) {
487 vals
[0] = self
->size
.left
;
488 vals
[1] = self
->size
.right
;
489 vals
[2] = self
->size
.top
;
490 vals
[3] = self
->size
.bottom
;
491 PROP_SETA32(self
->client
->window
, net_frame_extents
,
495 /* if this occurs while we are focus cycling, the indicator needs to
497 if (focus_cycle_target
== self
->client
)
498 focus_cycle_draw_indicator();
500 if (resized
&& (self
->decorations
& OB_FRAME_DECOR_TITLEBAR
))
501 XResizeWindow(ob_display
, self
->label
, self
->label_width
,
502 ob_rr_theme
->label_height
);
505 void frame_adjust_state(ObFrame
*self
)
507 framerender_frame(self
);
510 void frame_adjust_focus(ObFrame
*self
, gboolean hilite
)
512 self
->focused
= hilite
;
513 framerender_frame(self
);
517 void frame_adjust_title(ObFrame
*self
)
519 framerender_frame(self
);
522 void frame_adjust_icon(ObFrame
*self
)
524 framerender_frame(self
);
527 void frame_grab_client(ObFrame
*self
, ObClient
*client
)
529 self
->client
= client
;
531 /* reparent the client to the frame */
532 XReparentWindow(ob_display
, client
->window
, self
->plate
, 0, 0);
534 When reparenting the client window, it is usually not mapped yet, since
535 this occurs from a MapRequest. However, in the case where Openbox is
536 starting up, the window is already mapped, so we'll see unmap events for
537 it. There are 2 unmap events generated that we see, one with the 'event'
538 member set the root window, and one set to the client, but both get
539 handled and need to be ignored.
541 if (ob_state() == OB_STATE_STARTING
)
542 client
->ignore_unmaps
+= 2;
544 /* select the event mask on the client's parent (to receive config/map
545 req's) the ButtonPress is to catch clicks on the client border */
546 XSelectInput(ob_display
, self
->plate
, PLATE_EVENTMASK
);
548 frame_adjust_area(self
, TRUE
, TRUE
, FALSE
);
550 /* map the client so it maps when the frame does */
551 XMapWindow(ob_display
, client
->window
);
553 /* set all the windows for the frame in the window_map */
554 g_hash_table_insert(window_map
, &self
->window
, client
);
555 g_hash_table_insert(window_map
, &self
->plate
, client
);
556 g_hash_table_insert(window_map
, &self
->inner
, client
);
557 g_hash_table_insert(window_map
, &self
->title
, client
);
558 g_hash_table_insert(window_map
, &self
->label
, client
);
559 g_hash_table_insert(window_map
, &self
->max
, client
);
560 g_hash_table_insert(window_map
, &self
->close
, client
);
561 g_hash_table_insert(window_map
, &self
->desk
, client
);
562 g_hash_table_insert(window_map
, &self
->shade
, client
);
563 g_hash_table_insert(window_map
, &self
->icon
, client
);
564 g_hash_table_insert(window_map
, &self
->iconify
, client
);
565 g_hash_table_insert(window_map
, &self
->handle
, client
);
566 g_hash_table_insert(window_map
, &self
->lgrip
, client
);
567 g_hash_table_insert(window_map
, &self
->rgrip
, client
);
568 g_hash_table_insert(window_map
, &self
->tltresize
, client
);
569 g_hash_table_insert(window_map
, &self
->tllresize
, client
);
570 g_hash_table_insert(window_map
, &self
->trtresize
, client
);
571 g_hash_table_insert(window_map
, &self
->trrresize
, client
);
574 void frame_release_client(ObFrame
*self
, ObClient
*client
)
577 gboolean reparent
= TRUE
;
579 g_assert(self
->client
== client
);
581 /* check if the app has already reparented its window away */
582 while (XCheckTypedWindowEvent(ob_display
, client
->window
,
583 ReparentNotify
, &ev
))
585 /* This check makes sure we don't catch our own reparent action to
586 our frame window. This doesn't count as the app reparenting itself
589 Reparent events that are generated by us are just discarded here.
590 They are of no consequence to us anyhow.
592 if (ev
.xreparent
.parent
!= self
->plate
) {
594 XPutBackEvent(ob_display
, &ev
);
600 /* according to the ICCCM - if the client doesn't reparent itself,
601 then we will reparent the window to root for them */
602 XReparentWindow(ob_display
, client
->window
,
603 RootWindow(ob_display
, ob_screen
),
608 /* remove all the windows for the frame from the window_map */
609 g_hash_table_remove(window_map
, &self
->window
);
610 g_hash_table_remove(window_map
, &self
->plate
);
611 g_hash_table_remove(window_map
, &self
->inner
);
612 g_hash_table_remove(window_map
, &self
->title
);
613 g_hash_table_remove(window_map
, &self
->label
);
614 g_hash_table_remove(window_map
, &self
->max
);
615 g_hash_table_remove(window_map
, &self
->close
);
616 g_hash_table_remove(window_map
, &self
->desk
);
617 g_hash_table_remove(window_map
, &self
->shade
);
618 g_hash_table_remove(window_map
, &self
->icon
);
619 g_hash_table_remove(window_map
, &self
->iconify
);
620 g_hash_table_remove(window_map
, &self
->handle
);
621 g_hash_table_remove(window_map
, &self
->lgrip
);
622 g_hash_table_remove(window_map
, &self
->rgrip
);
623 g_hash_table_remove(window_map
, &self
->tltresize
);
624 g_hash_table_remove(window_map
, &self
->tllresize
);
625 g_hash_table_remove(window_map
, &self
->trtresize
);
626 g_hash_table_remove(window_map
, &self
->trrresize
);
628 ob_main_loop_timeout_remove_data(ob_main_loop
, flash_timeout
, self
, TRUE
);
633 static void layout_title(ObFrame
*self
)
637 gboolean n
, d
, i
, l
, m
, c
, s
;
639 n
= d
= i
= l
= m
= c
= s
= FALSE
;
641 /* figure out whats being shown, and the width of the label */
642 self
->label_width
= self
->width
- (ob_rr_theme
->paddingx
+ 1) * 2;
643 for (lc
= config_title_layout
; *lc
!= '\0'; ++lc
) {
646 if (n
) { *lc
= ' '; break; } /* rm duplicates */
648 self
->label_width
-= (ob_rr_theme
->button_size
+ 2 +
649 ob_rr_theme
->paddingx
+ 1);
652 if (d
) { *lc
= ' '; break; }
653 if (!(self
->decorations
& OB_FRAME_DECOR_ALLDESKTOPS
)
654 && config_theme_hidedisabled
)
657 self
->label_width
-= (ob_rr_theme
->button_size
+
658 ob_rr_theme
->paddingx
+ 1);
661 if (s
) { *lc
= ' '; break; }
662 if (!(self
->decorations
& OB_FRAME_DECOR_SHADE
)
663 && config_theme_hidedisabled
)
666 self
->label_width
-= (ob_rr_theme
->button_size
+
667 ob_rr_theme
->paddingx
+ 1);
670 if (i
) { *lc
= ' '; break; }
671 if (!(self
->decorations
& OB_FRAME_DECOR_ICONIFY
)
672 && config_theme_hidedisabled
)
675 self
->label_width
-= (ob_rr_theme
->button_size
+
676 ob_rr_theme
->paddingx
+ 1);
679 if (l
) { *lc
= ' '; break; }
683 if (m
) { *lc
= ' '; break; }
684 if (!(self
->decorations
& OB_FRAME_DECOR_MAXIMIZE
)
685 && config_theme_hidedisabled
)
688 self
->label_width
-= (ob_rr_theme
->button_size
+
689 ob_rr_theme
->paddingx
+ 1);
692 if (c
) { *lc
= ' '; break; }
693 if (!(self
->decorations
& OB_FRAME_DECOR_CLOSE
)
694 && config_theme_hidedisabled
)
697 self
->label_width
-= (ob_rr_theme
->button_size
+
698 ob_rr_theme
->paddingx
+ 1);
702 if (self
->label_width
< 1) self
->label_width
= 1;
704 if (!n
) XUnmapWindow(ob_display
, self
->icon
);
705 if (!d
) XUnmapWindow(ob_display
, self
->desk
);
706 if (!s
) XUnmapWindow(ob_display
, self
->shade
);
707 if (!i
) XUnmapWindow(ob_display
, self
->iconify
);
708 if (!l
) XUnmapWindow(ob_display
, self
->label
);
709 if (!m
) XUnmapWindow(ob_display
, self
->max
);
710 if (!c
) XUnmapWindow(ob_display
, self
->close
);
712 x
= ob_rr_theme
->paddingx
+ 1;
713 for (lc
= config_title_layout
; *lc
!= '\0'; ++lc
) {
718 XMapWindow(ob_display
, self
->icon
);
719 XMoveWindow(ob_display
, self
->icon
, x
, ob_rr_theme
->paddingy
);
720 x
+= ob_rr_theme
->button_size
+ 2 + ob_rr_theme
->paddingx
+ 1;
725 XMapWindow(ob_display
, self
->desk
);
726 XMoveWindow(ob_display
, self
->desk
, x
, ob_rr_theme
->paddingy
+ 1);
727 x
+= ob_rr_theme
->button_size
+ ob_rr_theme
->paddingx
+ 1;
732 XMapWindow(ob_display
, self
->shade
);
733 XMoveWindow(ob_display
, self
->shade
, x
, ob_rr_theme
->paddingy
+ 1);
734 x
+= ob_rr_theme
->button_size
+ ob_rr_theme
->paddingx
+ 1;
739 XMapWindow(ob_display
, self
->iconify
);
740 XMoveWindow(ob_display
,self
->iconify
, x
, ob_rr_theme
->paddingy
+ 1);
741 x
+= ob_rr_theme
->button_size
+ ob_rr_theme
->paddingx
+ 1;
746 XMapWindow(ob_display
, self
->label
);
747 XMoveWindow(ob_display
, self
->label
, x
, ob_rr_theme
->paddingy
);
748 x
+= self
->label_width
+ ob_rr_theme
->paddingx
+ 1;
753 XMapWindow(ob_display
, self
->max
);
754 XMoveWindow(ob_display
, self
->max
, x
, ob_rr_theme
->paddingy
+ 1);
755 x
+= ob_rr_theme
->button_size
+ ob_rr_theme
->paddingx
+ 1;
760 XMapWindow(ob_display
, self
->close
);
761 XMoveWindow(ob_display
, self
->close
, x
, ob_rr_theme
->paddingy
+ 1);
762 x
+= ob_rr_theme
->button_size
+ ob_rr_theme
->paddingx
+ 1;
768 ObFrameContext
frame_context_from_string(const gchar
*name
)
770 if (!g_ascii_strcasecmp("Desktop", name
))
771 return OB_FRAME_CONTEXT_DESKTOP
;
772 else if (!g_ascii_strcasecmp("Client", name
))
773 return OB_FRAME_CONTEXT_CLIENT
;
774 else if (!g_ascii_strcasecmp("Titlebar", name
))
775 return OB_FRAME_CONTEXT_TITLEBAR
;
776 else if (!g_ascii_strcasecmp("Handle", name
))
777 return OB_FRAME_CONTEXT_HANDLE
;
778 else if (!g_ascii_strcasecmp("Frame", name
))
779 return OB_FRAME_CONTEXT_FRAME
;
780 else if (!g_ascii_strcasecmp("TLCorner", name
))
781 return OB_FRAME_CONTEXT_TLCORNER
;
782 else if (!g_ascii_strcasecmp("TRCorner", name
))
783 return OB_FRAME_CONTEXT_TRCORNER
;
784 else if (!g_ascii_strcasecmp("BLCorner", name
))
785 return OB_FRAME_CONTEXT_BLCORNER
;
786 else if (!g_ascii_strcasecmp("BRCorner", name
))
787 return OB_FRAME_CONTEXT_BRCORNER
;
788 else if (!g_ascii_strcasecmp("Maximize", name
))
789 return OB_FRAME_CONTEXT_MAXIMIZE
;
790 else if (!g_ascii_strcasecmp("AllDesktops", name
))
791 return OB_FRAME_CONTEXT_ALLDESKTOPS
;
792 else if (!g_ascii_strcasecmp("Shade", name
))
793 return OB_FRAME_CONTEXT_SHADE
;
794 else if (!g_ascii_strcasecmp("Iconify", name
))
795 return OB_FRAME_CONTEXT_ICONIFY
;
796 else if (!g_ascii_strcasecmp("Icon", name
))
797 return OB_FRAME_CONTEXT_ICON
;
798 else if (!g_ascii_strcasecmp("Close", name
))
799 return OB_FRAME_CONTEXT_CLOSE
;
800 else if (!g_ascii_strcasecmp("MoveResize", name
))
801 return OB_FRAME_CONTEXT_MOVE_RESIZE
;
802 return OB_FRAME_CONTEXT_NONE
;
805 ObFrameContext
frame_context(ObClient
*client
, Window win
)
809 if (moveresize_in_progress
)
810 return OB_FRAME_CONTEXT_MOVE_RESIZE
;
812 if (win
== RootWindow(ob_display
, ob_screen
))
813 return OB_FRAME_CONTEXT_DESKTOP
;
814 if (client
== NULL
) return OB_FRAME_CONTEXT_NONE
;
815 if (win
== client
->window
) {
816 /* conceptually, this is the desktop, as far as users are
818 if (client
->type
== OB_CLIENT_TYPE_DESKTOP
)
819 return OB_FRAME_CONTEXT_DESKTOP
;
820 return OB_FRAME_CONTEXT_CLIENT
;
823 self
= client
->frame
;
824 if (win
== self
->plate
) {
825 /* conceptually, this is the desktop, as far as users are
827 if (client
->type
== OB_CLIENT_TYPE_DESKTOP
)
828 return OB_FRAME_CONTEXT_DESKTOP
;
829 return OB_FRAME_CONTEXT_CLIENT
;
832 if (win
== self
->window
) return OB_FRAME_CONTEXT_FRAME
;
833 if (win
== self
->inner
) return OB_FRAME_CONTEXT_FRAME
;
834 if (win
== self
->title
) return OB_FRAME_CONTEXT_TITLEBAR
;
835 if (win
== self
->label
) return OB_FRAME_CONTEXT_TITLEBAR
;
836 if (win
== self
->handle
) return OB_FRAME_CONTEXT_HANDLE
;
837 if (win
== self
->lgrip
) return OB_FRAME_CONTEXT_BLCORNER
;
838 if (win
== self
->rgrip
) return OB_FRAME_CONTEXT_BRCORNER
;
839 if (win
== self
->tltresize
) return OB_FRAME_CONTEXT_TLCORNER
;
840 if (win
== self
->tllresize
) return OB_FRAME_CONTEXT_TLCORNER
;
841 if (win
== self
->trtresize
) return OB_FRAME_CONTEXT_TRCORNER
;
842 if (win
== self
->trrresize
) return OB_FRAME_CONTEXT_TRCORNER
;
843 if (win
== self
->max
) return OB_FRAME_CONTEXT_MAXIMIZE
;
844 if (win
== self
->iconify
) return OB_FRAME_CONTEXT_ICONIFY
;
845 if (win
== self
->close
) return OB_FRAME_CONTEXT_CLOSE
;
846 if (win
== self
->icon
) return OB_FRAME_CONTEXT_ICON
;
847 if (win
== self
->desk
) return OB_FRAME_CONTEXT_ALLDESKTOPS
;
848 if (win
== self
->shade
) return OB_FRAME_CONTEXT_SHADE
;
850 return OB_FRAME_CONTEXT_NONE
;
853 void frame_client_gravity(ObFrame
*self
, gint
*x
, gint
*y
)
856 switch (self
->client
->gravity
) {
858 case NorthWestGravity
:
859 case SouthWestGravity
:
866 *x
-= (self
->size
.left
+ self
->size
.right
) / 2;
869 case NorthEastGravity
:
870 case SouthEastGravity
:
872 *x
-= self
->size
.left
+ self
->size
.right
;
877 *x
-= self
->size
.left
;
882 switch (self
->client
->gravity
) {
884 case NorthWestGravity
:
885 case NorthEastGravity
:
892 *y
-= (self
->size
.top
+ self
->size
.bottom
) / 2;
895 case SouthWestGravity
:
896 case SouthEastGravity
:
898 *y
-= self
->size
.top
+ self
->size
.bottom
;
903 *y
-= self
->size
.top
;
908 void frame_frame_gravity(ObFrame
*self
, gint
*x
, gint
*y
)
911 switch (self
->client
->gravity
) {
913 case NorthWestGravity
:
915 case SouthWestGravity
:
920 *x
+= (self
->size
.left
+ self
->size
.right
) / 2;
922 case NorthEastGravity
:
924 case SouthEastGravity
:
925 *x
+= self
->size
.left
+ self
->size
.right
;
929 *x
+= self
->size
.left
;
934 switch (self
->client
->gravity
) {
936 case NorthWestGravity
:
938 case NorthEastGravity
:
943 *y
+= (self
->size
.top
+ self
->size
.bottom
) / 2;
945 case SouthWestGravity
:
947 case SouthEastGravity
:
948 *y
+= self
->size
.top
+ self
->size
.bottom
;
952 *y
+= self
->size
.top
;
957 static void flash_done(gpointer data
)
959 ObFrame
*self
= data
;
961 if (self
->focused
!= self
->flash_on
)
962 frame_adjust_focus(self
, self
->focused
);
965 static gboolean
flash_timeout(gpointer data
)
967 ObFrame
*self
= data
;
970 g_get_current_time(&now
);
971 if (now
.tv_sec
> self
->flash_end
.tv_sec
||
972 (now
.tv_sec
== self
->flash_end
.tv_sec
&&
973 now
.tv_usec
>= self
->flash_end
.tv_usec
))
974 self
->flashing
= FALSE
;
977 return FALSE
; /* we are done */
979 self
->flash_on
= !self
->flash_on
;
980 if (!self
->focused
) {
981 frame_adjust_focus(self
, self
->flash_on
);
982 self
->focused
= FALSE
;
985 return TRUE
; /* go again */
988 void frame_flash_start(ObFrame
*self
)
990 self
->flash_on
= self
->focused
;
993 ob_main_loop_timeout_add(ob_main_loop
,
994 G_USEC_PER_SEC
* 0.6,
999 g_get_current_time(&self
->flash_end
);
1000 g_time_val_add(&self
->flash_end
, G_USEC_PER_SEC
* 5);
1002 self
->flashing
= TRUE
;
1005 void frame_flash_stop(ObFrame
*self
)
1007 self
->flashing
= FALSE
;