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
->tlresize
= createWindow(self
->title
, NULL
, mask
, &attrib
);
121 attrib
.cursor
= ob_cursor(OB_CURSOR_NORTHEAST
);
122 self
->trresize
= createWindow(self
->title
, NULL
, mask
, &attrib
);
125 self
->label
= createWindow(self
->title
, NULL
, mask
, &attrib
);
126 self
->max
= createWindow(self
->title
, NULL
, mask
, &attrib
);
127 self
->close
= createWindow(self
->title
, NULL
, mask
, &attrib
);
128 self
->desk
= createWindow(self
->title
, NULL
, mask
, &attrib
);
129 self
->shade
= createWindow(self
->title
, NULL
, mask
, &attrib
);
130 self
->icon
= createWindow(self
->title
, NULL
, mask
, &attrib
);
131 self
->iconify
= createWindow(self
->title
, NULL
, mask
, &attrib
);
132 self
->handle
= createWindow(self
->window
, NULL
, mask
, &attrib
);
135 attrib
.cursor
= ob_cursor(OB_CURSOR_SOUTHWEST
);
136 self
->lgrip
= createWindow(self
->handle
, NULL
, mask
, &attrib
);
137 attrib
.cursor
= ob_cursor(OB_CURSOR_SOUTHEAST
);
138 self
->rgrip
= createWindow(self
->handle
, NULL
, mask
, &attrib
);
140 self
->focused
= FALSE
;
142 /* the other stuff is shown based on decor settings */
143 XMapWindow(ob_display
, self
->plate
);
144 XMapWindow(ob_display
, self
->lgrip
);
145 XMapWindow(ob_display
, self
->rgrip
);
146 XMapWindow(ob_display
, self
->label
);
148 self
->max_press
= self
->close_press
= self
->desk_press
=
149 self
->iconify_press
= self
->shade_press
= FALSE
;
150 self
->max_hover
= self
->close_hover
= self
->desk_hover
=
151 self
->iconify_hover
= self
->shade_hover
= FALSE
;
153 set_theme_statics(self
);
155 return (ObFrame
*)self
;
158 static void set_theme_statics(ObFrame
*self
)
160 /* set colors/appearance/sizes for stuff that doesn't change */
161 XSetWindowBorder(ob_display
, self
->window
,
162 RrColorPixel(ob_rr_theme
->frame_b_color
));
163 XSetWindowBorder(ob_display
, self
->title
,
164 RrColorPixel(ob_rr_theme
->frame_b_color
));
165 XSetWindowBorder(ob_display
, self
->handle
,
166 RrColorPixel(ob_rr_theme
->frame_b_color
));
167 XSetWindowBorder(ob_display
, self
->rgrip
,
168 RrColorPixel(ob_rr_theme
->frame_b_color
));
169 XSetWindowBorder(ob_display
, self
->lgrip
,
170 RrColorPixel(ob_rr_theme
->frame_b_color
));
172 XResizeWindow(ob_display
, self
->max
,
173 ob_rr_theme
->button_size
, ob_rr_theme
->button_size
);
174 XResizeWindow(ob_display
, self
->iconify
,
175 ob_rr_theme
->button_size
, ob_rr_theme
->button_size
);
176 XResizeWindow(ob_display
, self
->icon
,
177 ob_rr_theme
->button_size
+ 2, ob_rr_theme
->button_size
+ 2);
178 XResizeWindow(ob_display
, self
->close
,
179 ob_rr_theme
->button_size
, ob_rr_theme
->button_size
);
180 XResizeWindow(ob_display
, self
->desk
,
181 ob_rr_theme
->button_size
, ob_rr_theme
->button_size
);
182 XResizeWindow(ob_display
, self
->shade
,
183 ob_rr_theme
->button_size
, ob_rr_theme
->button_size
);
184 if (ob_rr_theme
->handle_height
> 0) {
185 XResizeWindow(ob_display
, self
->lgrip
,
186 ob_rr_theme
->grip_width
, ob_rr_theme
->handle_height
);
187 XResizeWindow(ob_display
, self
->rgrip
,
188 ob_rr_theme
->grip_width
, ob_rr_theme
->handle_height
);
190 XResizeWindow(ob_display
, self
->tlresize
,
191 ob_rr_theme
->grip_width
, ob_rr_theme
->top_grip_height
);
192 XResizeWindow(ob_display
, self
->trresize
,
193 ob_rr_theme
->grip_width
, ob_rr_theme
->top_grip_height
);
195 /* set up the dynamic appearances */
196 self
->a_unfocused_title
= RrAppearanceCopy(ob_rr_theme
->a_unfocused_title
);
197 self
->a_focused_title
= RrAppearanceCopy(ob_rr_theme
->a_focused_title
);
198 self
->a_unfocused_label
= RrAppearanceCopy(ob_rr_theme
->a_unfocused_label
);
199 self
->a_focused_label
= RrAppearanceCopy(ob_rr_theme
->a_focused_label
);
200 self
->a_unfocused_handle
=
201 RrAppearanceCopy(ob_rr_theme
->a_unfocused_handle
);
202 self
->a_focused_handle
= RrAppearanceCopy(ob_rr_theme
->a_focused_handle
);
203 self
->a_icon
= RrAppearanceCopy(ob_rr_theme
->a_icon
);
206 static void free_theme_statics(ObFrame
*self
)
208 RrAppearanceFree(self
->a_unfocused_title
);
209 RrAppearanceFree(self
->a_focused_title
);
210 RrAppearanceFree(self
->a_unfocused_label
);
211 RrAppearanceFree(self
->a_focused_label
);
212 RrAppearanceFree(self
->a_unfocused_handle
);
213 RrAppearanceFree(self
->a_focused_handle
);
214 RrAppearanceFree(self
->a_icon
);
217 static void frame_free(ObFrame
*self
)
219 free_theme_statics(self
);
221 XDestroyWindow(ob_display
, self
->window
);
223 XFreeColormap(ob_display
, self
->colormap
);
228 void frame_show(ObFrame
*self
)
230 if (!self
->visible
) {
231 self
->visible
= TRUE
;
232 XMapWindow(ob_display
, self
->client
->window
);
233 XMapWindow(ob_display
, self
->window
);
237 void frame_hide(ObFrame
*self
)
240 self
->visible
= FALSE
;
241 self
->client
->ignore_unmaps
+= 2;
242 /* we unmap the client itself so that we can get MapRequest
243 events, and because the ICCCM tells us to! */
244 XUnmapWindow(ob_display
, self
->window
);
245 XUnmapWindow(ob_display
, self
->client
->window
);
249 void frame_adjust_theme(ObFrame
*self
)
251 free_theme_statics(self
);
252 set_theme_statics(self
);
255 void frame_adjust_shape(ObFrame
*self
)
261 if (!self
->client
->shaped
) {
262 /* clear the shape on the frame window */
263 XShapeCombineMask(ob_display
, self
->window
, ShapeBounding
,
264 self
->innersize
.left
,
268 /* make the frame's shape match the clients */
269 XShapeCombineShape(ob_display
, self
->window
, ShapeBounding
,
270 self
->innersize
.left
,
272 self
->client
->window
,
273 ShapeBounding
, ShapeSet
);
276 if (self
->decorations
& OB_FRAME_DECOR_TITLEBAR
) {
277 xrect
[0].x
= -ob_rr_theme
->fbwidth
;
278 xrect
[0].y
= -ob_rr_theme
->fbwidth
;
279 xrect
[0].width
= self
->width
+ self
->rbwidth
* 2;
280 xrect
[0].height
= ob_rr_theme
->title_height
+
285 if (self
->decorations
& OB_FRAME_DECOR_HANDLE
) {
286 xrect
[1].x
= -ob_rr_theme
->fbwidth
;
287 xrect
[1].y
= FRAME_HANDLE_Y(self
);
288 xrect
[1].width
= self
->width
+ self
->rbwidth
* 2;
289 xrect
[1].height
= ob_rr_theme
->handle_height
+
294 XShapeCombineRectangles(ob_display
, self
->window
,
295 ShapeBounding
, 0, 0, xrect
, num
,
296 ShapeUnion
, Unsorted
);
301 void frame_adjust_area(ObFrame
*self
, gboolean moved
,
302 gboolean resized
, gboolean fake
)
306 oldsize
= self
->size
;
309 self
->decorations
= self
->client
->decorations
;
310 self
->max_horz
= self
->client
->max_horz
;
312 if (self
->decorations
& OB_FRAME_DECOR_BORDER
) {
313 self
->bwidth
= ob_rr_theme
->fbwidth
;
314 self
->cbwidth_x
= ob_rr_theme
->cbwidthx
;
315 self
->cbwidth_y
= ob_rr_theme
->cbwidthy
;
317 self
->bwidth
= self
->cbwidth_x
= self
->cbwidth_y
= 0;
319 self
->rbwidth
= self
->bwidth
;
322 self
->bwidth
= self
->cbwidth_x
= 0;
324 STRUT_SET(self
->innersize
,
329 self
->width
= self
->client
->area
.width
+ self
->cbwidth_x
* 2 -
330 (self
->max_horz
? self
->rbwidth
* 2 : 0);
331 self
->width
= MAX(self
->width
, 1); /* no lower than 1 */
333 /* set border widths */
335 XSetWindowBorderWidth(ob_display
, self
->window
, self
->bwidth
);
336 XSetWindowBorderWidth(ob_display
, self
->title
, self
->rbwidth
);
337 XSetWindowBorderWidth(ob_display
, self
->handle
, self
->rbwidth
);
338 XSetWindowBorderWidth(ob_display
, self
->lgrip
, self
->rbwidth
);
339 XSetWindowBorderWidth(ob_display
, self
->rgrip
, self
->rbwidth
);
342 if (self
->decorations
& OB_FRAME_DECOR_TITLEBAR
)
343 self
->innersize
.top
+= ob_rr_theme
->title_height
+ self
->rbwidth
+
344 (self
->rbwidth
- self
->bwidth
);
345 if (self
->decorations
& OB_FRAME_DECOR_HANDLE
&&
346 ob_rr_theme
->handle_height
> 0)
347 self
->innersize
.bottom
+= ob_rr_theme
->handle_height
+
348 self
->rbwidth
+ (self
->rbwidth
- self
->bwidth
);
350 /* they all default off, they're turned on in layout_title */
354 self
->iconify_x
= -1;
359 /* position/size and map/unmap all the windows */
362 if (self
->decorations
& OB_FRAME_DECOR_TITLEBAR
) {
363 XMoveResizeWindow(ob_display
, self
->title
,
364 -self
->bwidth
, -self
->bwidth
,
365 self
->width
, ob_rr_theme
->title_height
);
366 XMapWindow(ob_display
, self
->title
);
368 if (self
->decorations
& OB_FRAME_DECOR_GRIPS
) {
369 XMoveWindow(ob_display
, self
->tlresize
, 0, 0);
370 XMoveWindow(ob_display
, self
->trresize
,
371 self
->width
- ob_rr_theme
->grip_width
, 0);
372 XMapWindow(ob_display
, self
->tlresize
);
373 XMapWindow(ob_display
, self
->trresize
);
375 XUnmapWindow(ob_display
, self
->tlresize
);
376 XUnmapWindow(ob_display
, self
->trresize
);
379 XUnmapWindow(ob_display
, self
->title
);
382 if (self
->decorations
& OB_FRAME_DECOR_TITLEBAR
)
383 /* layout the title bar elements */
387 if (self
->decorations
& OB_FRAME_DECOR_HANDLE
&&
388 ob_rr_theme
->handle_height
> 0)
390 XMoveResizeWindow(ob_display
, self
->handle
,
391 -self
->bwidth
, FRAME_HANDLE_Y(self
),
392 self
->width
, ob_rr_theme
->handle_height
);
393 XMapWindow(ob_display
, self
->handle
);
395 if (self
->decorations
& OB_FRAME_DECOR_GRIPS
) {
396 XMoveWindow(ob_display
, self
->lgrip
,
397 -self
->rbwidth
, -self
->rbwidth
);
398 XMoveWindow(ob_display
, self
->rgrip
,
399 -self
->rbwidth
+ self
->width
-
400 ob_rr_theme
->grip_width
, -self
->rbwidth
);
401 XMapWindow(ob_display
, self
->lgrip
);
402 XMapWindow(ob_display
, self
->rgrip
);
404 XUnmapWindow(ob_display
, self
->lgrip
);
405 XUnmapWindow(ob_display
, self
->rgrip
);
408 XUnmapWindow(ob_display
, self
->handle
);
410 /* move and resize the plate */
411 XMoveResizeWindow(ob_display
, self
->plate
,
412 self
->innersize
.left
- self
->cbwidth_x
,
413 self
->innersize
.top
- self
->cbwidth_y
,
414 self
->client
->area
.width
+ self
->cbwidth_x
* 2,
415 self
->client
->area
.height
+ self
->cbwidth_y
* 2);
416 /* when the client has StaticGravity, it likes to move around. */
417 XMoveWindow(ob_display
, self
->client
->window
,
418 self
->cbwidth_x
, self
->cbwidth_y
);
421 STRUT_SET(self
->size
,
422 self
->innersize
.left
+ self
->bwidth
,
423 self
->innersize
.top
+ self
->bwidth
,
424 self
->innersize
.right
+ self
->bwidth
,
425 self
->innersize
.bottom
+ self
->bwidth
);
428 /* shading can change without being moved or resized */
429 RECT_SET_SIZE(self
->area
,
430 self
->client
->area
.width
+
431 self
->size
.left
+ self
->size
.right
,
432 (self
->client
->shaded
?
433 ob_rr_theme
->title_height
+ self
->rbwidth
* 2:
434 self
->client
->area
.height
+
435 self
->size
.top
+ self
->size
.bottom
));
438 /* find the new coordinates, done after setting the frame.size, for
439 frame_client_gravity. */
440 self
->area
.x
= self
->client
->area
.x
;
441 self
->area
.y
= self
->client
->area
.y
;
442 frame_client_gravity(self
, &self
->area
.x
, &self
->area
.y
);
446 /* move and resize the top level frame.
447 shading can change without being moved or resized */
448 XMoveResizeWindow(ob_display
, self
->window
,
449 self
->area
.x
, self
->area
.y
,
450 self
->area
.width
- self
->bwidth
* 2,
451 self
->area
.height
- self
->bwidth
* 2);
454 framerender_frame(self
);
455 frame_adjust_shape(self
);
458 if (!STRUT_EQUAL(self
->size
, oldsize
)) {
460 vals
[0] = self
->size
.left
;
461 vals
[1] = self
->size
.right
;
462 vals
[2] = self
->size
.top
;
463 vals
[3] = self
->size
.bottom
;
464 PROP_SETA32(self
->client
->window
, kde_net_wm_frame_strut
,
468 /* if this occurs while we are focus cycling, the indicator needs to
470 if (focus_cycle_target
== self
->client
)
471 focus_cycle_draw_indicator();
473 if (resized
&& (self
->decorations
& OB_FRAME_DECOR_TITLEBAR
))
474 XResizeWindow(ob_display
, self
->label
, self
->label_width
,
475 ob_rr_theme
->label_height
);
478 void frame_adjust_state(ObFrame
*self
)
480 framerender_frame(self
);
483 void frame_adjust_focus(ObFrame
*self
, gboolean hilite
)
485 self
->focused
= hilite
;
486 framerender_frame(self
);
489 void frame_adjust_title(ObFrame
*self
)
491 framerender_frame(self
);
494 void frame_adjust_icon(ObFrame
*self
)
496 framerender_frame(self
);
499 void frame_grab_client(ObFrame
*self
, ObClient
*client
)
501 self
->client
= client
;
503 /* reparent the client to the frame */
504 XReparentWindow(ob_display
, client
->window
, self
->plate
, 0, 0);
506 When reparenting the client window, it is usually not mapped yet, since
507 this occurs from a MapRequest. However, in the case where Openbox is
508 starting up, the window is already mapped, so we'll see unmap events for
509 it. There are 2 unmap events generated that we see, one with the 'event'
510 member set the root window, and one set to the client, but both get
511 handled and need to be ignored.
513 if (ob_state() == OB_STATE_STARTING
)
514 client
->ignore_unmaps
+= 2;
516 /* select the event mask on the client's parent (to receive config/map
517 req's) the ButtonPress is to catch clicks on the client border */
518 XSelectInput(ob_display
, self
->plate
, PLATE_EVENTMASK
);
520 /* map the client so it maps when the frame does */
521 XMapWindow(ob_display
, client
->window
);
523 frame_adjust_area(self
, TRUE
, TRUE
, FALSE
);
525 /* set all the windows for the frame in the window_map */
526 g_hash_table_insert(window_map
, &self
->window
, client
);
527 g_hash_table_insert(window_map
, &self
->plate
, client
);
528 g_hash_table_insert(window_map
, &self
->title
, client
);
529 g_hash_table_insert(window_map
, &self
->label
, client
);
530 g_hash_table_insert(window_map
, &self
->max
, client
);
531 g_hash_table_insert(window_map
, &self
->close
, client
);
532 g_hash_table_insert(window_map
, &self
->desk
, client
);
533 g_hash_table_insert(window_map
, &self
->shade
, client
);
534 g_hash_table_insert(window_map
, &self
->icon
, client
);
535 g_hash_table_insert(window_map
, &self
->iconify
, client
);
536 g_hash_table_insert(window_map
, &self
->handle
, client
);
537 g_hash_table_insert(window_map
, &self
->lgrip
, client
);
538 g_hash_table_insert(window_map
, &self
->rgrip
, client
);
539 g_hash_table_insert(window_map
, &self
->tlresize
, client
);
540 g_hash_table_insert(window_map
, &self
->trresize
, client
);
543 void frame_release_client(ObFrame
*self
, ObClient
*client
)
546 gboolean reparent
= TRUE
;
548 g_assert(self
->client
== client
);
550 /* check if the app has already reparented its window away */
551 while (XCheckTypedWindowEvent(ob_display
, client
->window
,
552 ReparentNotify
, &ev
))
554 /* This check makes sure we don't catch our own reparent action to
555 our frame window. This doesn't count as the app reparenting itself
558 Reparent events that are generated by us are just discarded here.
559 They are of no consequence to us anyhow.
561 if (ev
.xreparent
.parent
!= self
->plate
) {
563 XPutBackEvent(ob_display
, &ev
);
569 /* according to the ICCCM - if the client doesn't reparent itself,
570 then we will reparent the window to root for them */
571 XReparentWindow(ob_display
, client
->window
,
572 RootWindow(ob_display
, ob_screen
),
577 /* remove all the windows for the frame from the window_map */
578 g_hash_table_remove(window_map
, &self
->window
);
579 g_hash_table_remove(window_map
, &self
->plate
);
580 g_hash_table_remove(window_map
, &self
->title
);
581 g_hash_table_remove(window_map
, &self
->label
);
582 g_hash_table_remove(window_map
, &self
->max
);
583 g_hash_table_remove(window_map
, &self
->close
);
584 g_hash_table_remove(window_map
, &self
->desk
);
585 g_hash_table_remove(window_map
, &self
->shade
);
586 g_hash_table_remove(window_map
, &self
->icon
);
587 g_hash_table_remove(window_map
, &self
->iconify
);
588 g_hash_table_remove(window_map
, &self
->handle
);
589 g_hash_table_remove(window_map
, &self
->lgrip
);
590 g_hash_table_remove(window_map
, &self
->rgrip
);
591 g_hash_table_remove(window_map
, &self
->tlresize
);
592 g_hash_table_remove(window_map
, &self
->trresize
);
594 ob_main_loop_timeout_remove_data(ob_main_loop
, flash_timeout
, self
, TRUE
);
599 static void layout_title(ObFrame
*self
)
603 gboolean n
, d
, i
, l
, m
, c
, s
;
605 n
= d
= i
= l
= m
= c
= s
= FALSE
;
607 /* figure out whats being shown, and the width of the label */
608 self
->label_width
= self
->width
- (ob_rr_theme
->paddingx
+ 1) * 2;
609 for (lc
= config_title_layout
; *lc
!= '\0'; ++lc
) {
612 if (n
) { *lc
= ' '; break; } /* rm duplicates */
614 self
->label_width
-= (ob_rr_theme
->button_size
+ 2 +
615 ob_rr_theme
->paddingx
+ 1);
618 if (d
) { *lc
= ' '; break; }
619 if (!(self
->decorations
& OB_FRAME_DECOR_ALLDESKTOPS
)
620 && config_theme_hidedisabled
)
623 self
->label_width
-= (ob_rr_theme
->button_size
+
624 ob_rr_theme
->paddingx
+ 1);
627 if (s
) { *lc
= ' '; break; }
628 if (!(self
->decorations
& OB_FRAME_DECOR_SHADE
)
629 && config_theme_hidedisabled
)
632 self
->label_width
-= (ob_rr_theme
->button_size
+
633 ob_rr_theme
->paddingx
+ 1);
636 if (i
) { *lc
= ' '; break; }
637 if (!(self
->decorations
& OB_FRAME_DECOR_ICONIFY
)
638 && config_theme_hidedisabled
)
641 self
->label_width
-= (ob_rr_theme
->button_size
+
642 ob_rr_theme
->paddingx
+ 1);
645 if (l
) { *lc
= ' '; break; }
649 if (m
) { *lc
= ' '; break; }
650 if (!(self
->decorations
& OB_FRAME_DECOR_MAXIMIZE
)
651 && config_theme_hidedisabled
)
654 self
->label_width
-= (ob_rr_theme
->button_size
+
655 ob_rr_theme
->paddingx
+ 1);
658 if (c
) { *lc
= ' '; break; }
659 if (!(self
->decorations
& OB_FRAME_DECOR_CLOSE
)
660 && config_theme_hidedisabled
)
663 self
->label_width
-= (ob_rr_theme
->button_size
+
664 ob_rr_theme
->paddingx
+ 1);
668 if (self
->label_width
< 1) self
->label_width
= 1;
670 if (!n
) XUnmapWindow(ob_display
, self
->icon
);
671 if (!d
) XUnmapWindow(ob_display
, self
->desk
);
672 if (!s
) XUnmapWindow(ob_display
, self
->shade
);
673 if (!i
) XUnmapWindow(ob_display
, self
->iconify
);
674 if (!l
) XUnmapWindow(ob_display
, self
->label
);
675 if (!m
) XUnmapWindow(ob_display
, self
->max
);
676 if (!c
) XUnmapWindow(ob_display
, self
->close
);
678 x
= ob_rr_theme
->paddingx
+ 1;
679 for (lc
= config_title_layout
; *lc
!= '\0'; ++lc
) {
684 XMapWindow(ob_display
, self
->icon
);
685 XMoveWindow(ob_display
, self
->icon
, x
, ob_rr_theme
->paddingx
);
686 x
+= ob_rr_theme
->button_size
+ 2 + ob_rr_theme
->paddingx
+ 1;
691 XMapWindow(ob_display
, self
->desk
);
692 XMoveWindow(ob_display
, self
->desk
, x
, ob_rr_theme
->paddingx
+ 1);
693 x
+= ob_rr_theme
->button_size
+ ob_rr_theme
->paddingx
+ 1;
698 XMapWindow(ob_display
, self
->shade
);
699 XMoveWindow(ob_display
, self
->shade
, x
, ob_rr_theme
->paddingx
+ 1);
700 x
+= ob_rr_theme
->button_size
+ ob_rr_theme
->paddingx
+ 1;
705 XMapWindow(ob_display
, self
->iconify
);
706 XMoveWindow(ob_display
,self
->iconify
, x
, ob_rr_theme
->paddingx
+ 1);
707 x
+= ob_rr_theme
->button_size
+ ob_rr_theme
->paddingx
+ 1;
712 XMapWindow(ob_display
, self
->label
);
713 XMoveWindow(ob_display
, self
->label
, x
, ob_rr_theme
->paddingx
);
714 x
+= self
->label_width
+ ob_rr_theme
->paddingx
+ 1;
719 XMapWindow(ob_display
, self
->max
);
720 XMoveWindow(ob_display
, self
->max
, x
, ob_rr_theme
->paddingx
+ 1);
721 x
+= ob_rr_theme
->button_size
+ ob_rr_theme
->paddingx
+ 1;
726 XMapWindow(ob_display
, self
->close
);
727 XMoveWindow(ob_display
, self
->close
, x
, ob_rr_theme
->paddingx
+ 1);
728 x
+= ob_rr_theme
->button_size
+ ob_rr_theme
->paddingx
+ 1;
734 ObFrameContext
frame_context_from_string(const gchar
*name
)
736 if (!g_ascii_strcasecmp("Desktop", name
))
737 return OB_FRAME_CONTEXT_DESKTOP
;
738 else if (!g_ascii_strcasecmp("Client", name
))
739 return OB_FRAME_CONTEXT_CLIENT
;
740 else if (!g_ascii_strcasecmp("Titlebar", name
))
741 return OB_FRAME_CONTEXT_TITLEBAR
;
742 else if (!g_ascii_strcasecmp("Handle", name
))
743 return OB_FRAME_CONTEXT_HANDLE
;
744 else if (!g_ascii_strcasecmp("Frame", name
))
745 return OB_FRAME_CONTEXT_FRAME
;
746 else if (!g_ascii_strcasecmp("TLCorner", name
))
747 return OB_FRAME_CONTEXT_TLCORNER
;
748 else if (!g_ascii_strcasecmp("TRCorner", name
))
749 return OB_FRAME_CONTEXT_TRCORNER
;
750 else if (!g_ascii_strcasecmp("BLCorner", name
))
751 return OB_FRAME_CONTEXT_BLCORNER
;
752 else if (!g_ascii_strcasecmp("BRCorner", name
))
753 return OB_FRAME_CONTEXT_BRCORNER
;
754 else if (!g_ascii_strcasecmp("Maximize", name
))
755 return OB_FRAME_CONTEXT_MAXIMIZE
;
756 else if (!g_ascii_strcasecmp("AllDesktops", name
))
757 return OB_FRAME_CONTEXT_ALLDESKTOPS
;
758 else if (!g_ascii_strcasecmp("Shade", name
))
759 return OB_FRAME_CONTEXT_SHADE
;
760 else if (!g_ascii_strcasecmp("Iconify", name
))
761 return OB_FRAME_CONTEXT_ICONIFY
;
762 else if (!g_ascii_strcasecmp("Icon", name
))
763 return OB_FRAME_CONTEXT_ICON
;
764 else if (!g_ascii_strcasecmp("Close", name
))
765 return OB_FRAME_CONTEXT_CLOSE
;
766 else if (!g_ascii_strcasecmp("MoveResize", name
))
767 return OB_FRAME_CONTEXT_MOVE_RESIZE
;
768 return OB_FRAME_CONTEXT_NONE
;
771 ObFrameContext
frame_context(ObClient
*client
, Window win
)
775 if (moveresize_in_progress
)
776 return OB_FRAME_CONTEXT_MOVE_RESIZE
;
778 if (win
== RootWindow(ob_display
, ob_screen
))
779 return OB_FRAME_CONTEXT_DESKTOP
;
780 if (client
== NULL
) return OB_FRAME_CONTEXT_NONE
;
781 if (win
== client
->window
) {
782 /* conceptually, this is the desktop, as far as users are
784 if (client
->type
== OB_CLIENT_TYPE_DESKTOP
)
785 return OB_FRAME_CONTEXT_DESKTOP
;
786 return OB_FRAME_CONTEXT_CLIENT
;
789 self
= client
->frame
;
790 if (win
== self
->plate
) {
791 /* conceptually, this is the desktop, as far as users are
793 if (client
->type
== OB_CLIENT_TYPE_DESKTOP
)
794 return OB_FRAME_CONTEXT_DESKTOP
;
795 return OB_FRAME_CONTEXT_CLIENT
;
798 if (win
== self
->window
) return OB_FRAME_CONTEXT_FRAME
;
799 if (win
== self
->title
) return OB_FRAME_CONTEXT_TITLEBAR
;
800 if (win
== self
->label
) return OB_FRAME_CONTEXT_TITLEBAR
;
801 if (win
== self
->handle
) return OB_FRAME_CONTEXT_HANDLE
;
802 if (win
== self
->lgrip
) return OB_FRAME_CONTEXT_BLCORNER
;
803 if (win
== self
->rgrip
) return OB_FRAME_CONTEXT_BRCORNER
;
804 if (win
== self
->tlresize
) return OB_FRAME_CONTEXT_TLCORNER
;
805 if (win
== self
->trresize
) return OB_FRAME_CONTEXT_TRCORNER
;
806 if (win
== self
->max
) return OB_FRAME_CONTEXT_MAXIMIZE
;
807 if (win
== self
->iconify
) return OB_FRAME_CONTEXT_ICONIFY
;
808 if (win
== self
->close
) return OB_FRAME_CONTEXT_CLOSE
;
809 if (win
== self
->icon
) return OB_FRAME_CONTEXT_ICON
;
810 if (win
== self
->desk
) return OB_FRAME_CONTEXT_ALLDESKTOPS
;
811 if (win
== self
->shade
) return OB_FRAME_CONTEXT_SHADE
;
813 return OB_FRAME_CONTEXT_NONE
;
816 void frame_client_gravity(ObFrame
*self
, gint
*x
, gint
*y
)
819 switch (self
->client
->gravity
) {
821 case NorthWestGravity
:
822 case SouthWestGravity
:
829 *x
-= (self
->size
.left
+ self
->size
.right
) / 2;
832 case NorthEastGravity
:
833 case SouthEastGravity
:
835 *x
-= self
->size
.left
+ self
->size
.right
;
840 *x
-= self
->size
.left
;
845 switch (self
->client
->gravity
) {
847 case NorthWestGravity
:
848 case NorthEastGravity
:
855 *y
-= (self
->size
.top
+ self
->size
.bottom
) / 2;
858 case SouthWestGravity
:
859 case SouthEastGravity
:
861 *y
-= self
->size
.top
+ self
->size
.bottom
;
866 *y
-= self
->size
.top
;
871 void frame_frame_gravity(ObFrame
*self
, gint
*x
, gint
*y
)
874 switch (self
->client
->gravity
) {
876 case NorthWestGravity
:
878 case SouthWestGravity
:
883 *x
+= (self
->size
.left
+ self
->size
.right
) / 2;
885 case NorthEastGravity
:
887 case SouthEastGravity
:
888 *x
+= self
->size
.left
+ self
->size
.right
;
892 *x
+= self
->size
.left
;
897 switch (self
->client
->gravity
) {
899 case NorthWestGravity
:
901 case NorthEastGravity
:
906 *y
+= (self
->size
.top
+ self
->size
.bottom
) / 2;
908 case SouthWestGravity
:
910 case SouthEastGravity
:
911 *y
+= self
->size
.top
+ self
->size
.bottom
;
915 *y
+= self
->size
.top
;
920 static void flash_done(gpointer data
)
922 ObFrame
*self
= data
;
924 if (self
->focused
!= self
->flash_on
)
925 frame_adjust_focus(self
, self
->focused
);
928 static gboolean
flash_timeout(gpointer data
)
930 ObFrame
*self
= data
;
933 g_get_current_time(&now
);
934 if (now
.tv_sec
> self
->flash_end
.tv_sec
||
935 (now
.tv_sec
== self
->flash_end
.tv_sec
&&
936 now
.tv_usec
>= self
->flash_end
.tv_usec
))
937 self
->flashing
= FALSE
;
940 return FALSE
; /* we are done */
942 self
->flash_on
= !self
->flash_on
;
943 if (!self
->focused
) {
944 frame_adjust_focus(self
, self
->flash_on
);
945 self
->focused
= FALSE
;
948 return TRUE
; /* go again */
951 void frame_flash_start(ObFrame
*self
)
953 self
->flash_on
= self
->focused
;
956 ob_main_loop_timeout_add(ob_main_loop
,
957 G_USEC_PER_SEC
* 0.6,
961 g_get_current_time(&self
->flash_end
);
962 g_time_val_add(&self
->flash_end
, G_USEC_PER_SEC
* 5);
964 self
->flashing
= TRUE
;
967 void frame_flash_stop(ObFrame
*self
)
969 self
->flashing
= FALSE
;