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
->b_color
));
163 XSetWindowBorder(ob_display
, self
->title
,
164 RrColorPixel(ob_rr_theme
->b_color
));
165 XSetWindowBorder(ob_display
, self
->handle
,
166 RrColorPixel(ob_rr_theme
->b_color
));
167 XSetWindowBorder(ob_display
, self
->rgrip
,
168 RrColorPixel(ob_rr_theme
->b_color
));
169 XSetWindowBorder(ob_display
, self
->lgrip
,
170 RrColorPixel(ob_rr_theme
->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 XResizeWindow(ob_display
, self
->lgrip
,
185 ob_rr_theme
->grip_width
, ob_rr_theme
->handle_height
);
186 XResizeWindow(ob_display
, self
->rgrip
,
187 ob_rr_theme
->grip_width
, ob_rr_theme
->handle_height
);
188 XResizeWindow(ob_display
, self
->tlresize
,
189 ob_rr_theme
->grip_width
, ob_rr_theme
->handle_height
);
190 XResizeWindow(ob_display
, self
->trresize
,
191 ob_rr_theme
->grip_width
, ob_rr_theme
->handle_height
);
193 /* set up the dynamic appearances */
194 self
->a_unfocused_title
= RrAppearanceCopy(ob_rr_theme
->a_unfocused_title
);
195 self
->a_focused_title
= RrAppearanceCopy(ob_rr_theme
->a_focused_title
);
196 self
->a_unfocused_label
= RrAppearanceCopy(ob_rr_theme
->a_unfocused_label
);
197 self
->a_focused_label
= RrAppearanceCopy(ob_rr_theme
->a_focused_label
);
198 self
->a_unfocused_handle
=
199 RrAppearanceCopy(ob_rr_theme
->a_unfocused_handle
);
200 self
->a_focused_handle
= RrAppearanceCopy(ob_rr_theme
->a_focused_handle
);
201 self
->a_icon
= RrAppearanceCopy(ob_rr_theme
->a_icon
);
204 static void free_theme_statics(ObFrame
*self
)
206 RrAppearanceFree(self
->a_unfocused_title
);
207 RrAppearanceFree(self
->a_focused_title
);
208 RrAppearanceFree(self
->a_unfocused_label
);
209 RrAppearanceFree(self
->a_focused_label
);
210 RrAppearanceFree(self
->a_unfocused_handle
);
211 RrAppearanceFree(self
->a_focused_handle
);
212 RrAppearanceFree(self
->a_icon
);
215 static void frame_free(ObFrame
*self
)
217 free_theme_statics(self
);
219 XDestroyWindow(ob_display
, self
->window
);
221 XFreeColormap(ob_display
, self
->colormap
);
226 void frame_show(ObFrame
*self
)
228 if (!self
->visible
) {
229 self
->visible
= TRUE
;
230 XMapWindow(ob_display
, self
->client
->window
);
231 XMapWindow(ob_display
, self
->window
);
235 void frame_hide(ObFrame
*self
)
238 self
->visible
= FALSE
;
239 self
->client
->ignore_unmaps
+= 2;
240 /* we unmap the client itself so that we can get MapRequest
241 events, and because the ICCCM tells us to! */
242 XUnmapWindow(ob_display
, self
->window
);
243 XUnmapWindow(ob_display
, self
->client
->window
);
247 void frame_adjust_theme(ObFrame
*self
)
249 free_theme_statics(self
);
250 set_theme_statics(self
);
253 void frame_adjust_shape(ObFrame
*self
)
259 if (!self
->client
->shaped
) {
260 /* clear the shape on the frame window */
261 XShapeCombineMask(ob_display
, self
->window
, ShapeBounding
,
262 self
->innersize
.left
,
266 /* make the frame's shape match the clients */
267 XShapeCombineShape(ob_display
, self
->window
, ShapeBounding
,
268 self
->innersize
.left
,
270 self
->client
->window
,
271 ShapeBounding
, ShapeSet
);
274 if (self
->decorations
& OB_FRAME_DECOR_TITLEBAR
) {
275 xrect
[0].x
= -ob_rr_theme
->bwidth
;
276 xrect
[0].y
= -ob_rr_theme
->bwidth
;
277 xrect
[0].width
= self
->width
+ self
->rbwidth
* 2;
278 xrect
[0].height
= ob_rr_theme
->title_height
+
283 if (self
->decorations
& OB_FRAME_DECOR_HANDLE
) {
284 xrect
[1].x
= -ob_rr_theme
->bwidth
;
285 xrect
[1].y
= FRAME_HANDLE_Y(self
);
286 xrect
[1].width
= self
->width
+ self
->rbwidth
* 2;
287 xrect
[1].height
= ob_rr_theme
->handle_height
+
292 XShapeCombineRectangles(ob_display
, self
->window
,
293 ShapeBounding
, 0, 0, xrect
, num
,
294 ShapeUnion
, Unsorted
);
299 void frame_adjust_area(ObFrame
*self
, gboolean moved
,
300 gboolean resized
, gboolean fake
)
304 oldsize
= self
->size
;
307 self
->decorations
= self
->client
->decorations
;
308 self
->max_horz
= self
->client
->max_horz
;
310 if (self
->decorations
& OB_FRAME_DECOR_BORDER
) {
311 self
->bwidth
= ob_rr_theme
->bwidth
;
312 self
->cbwidth_x
= self
->cbwidth_y
= ob_rr_theme
->cbwidth
;
314 self
->bwidth
= self
->cbwidth_x
= self
->cbwidth_y
= 0;
316 self
->rbwidth
= self
->bwidth
;
319 self
->bwidth
= self
->cbwidth_x
= 0;
321 STRUT_SET(self
->innersize
,
326 self
->width
= self
->client
->area
.width
+ self
->cbwidth_x
* 2 -
327 (self
->max_horz
? self
->rbwidth
* 2 : 0);
328 self
->width
= MAX(self
->width
, 1); /* no lower than 1 */
330 /* set border widths */
332 XSetWindowBorderWidth(ob_display
, self
->window
, self
->bwidth
);
333 XSetWindowBorderWidth(ob_display
, self
->title
, self
->rbwidth
);
334 XSetWindowBorderWidth(ob_display
, self
->handle
, self
->rbwidth
);
335 XSetWindowBorderWidth(ob_display
, self
->lgrip
, self
->rbwidth
);
336 XSetWindowBorderWidth(ob_display
, self
->rgrip
, self
->rbwidth
);
339 if (self
->decorations
& OB_FRAME_DECOR_TITLEBAR
)
340 self
->innersize
.top
+= ob_rr_theme
->title_height
+ self
->rbwidth
+
341 (self
->rbwidth
- self
->bwidth
);
342 if (self
->decorations
& OB_FRAME_DECOR_HANDLE
&&
343 ob_rr_theme
->show_handle
)
344 self
->innersize
.bottom
+= ob_rr_theme
->handle_height
+
345 self
->rbwidth
+ (self
->rbwidth
- self
->bwidth
);
347 /* they all default off, they're turned on in layout_title */
351 self
->iconify_x
= -1;
356 /* position/size and map/unmap all the windows */
359 if (self
->decorations
& OB_FRAME_DECOR_TITLEBAR
) {
360 XMoveResizeWindow(ob_display
, self
->title
,
361 -self
->bwidth
, -self
->bwidth
,
362 self
->width
, ob_rr_theme
->title_height
);
363 XMapWindow(ob_display
, self
->title
);
365 if (self
->decorations
& OB_FRAME_DECOR_GRIPS
) {
366 XMoveWindow(ob_display
, self
->tlresize
, 0, 0);
367 XMoveWindow(ob_display
, self
->trresize
,
368 self
->width
- ob_rr_theme
->grip_width
, 0);
369 XMapWindow(ob_display
, self
->tlresize
);
370 XMapWindow(ob_display
, self
->trresize
);
372 XUnmapWindow(ob_display
, self
->tlresize
);
373 XUnmapWindow(ob_display
, self
->trresize
);
376 XUnmapWindow(ob_display
, self
->title
);
379 if (self
->decorations
& OB_FRAME_DECOR_TITLEBAR
)
380 /* layout the title bar elements */
384 if (self
->decorations
& OB_FRAME_DECOR_HANDLE
&&
385 ob_rr_theme
->show_handle
)
387 XMoveResizeWindow(ob_display
, self
->handle
,
388 -self
->bwidth
, FRAME_HANDLE_Y(self
),
389 self
->width
, ob_rr_theme
->handle_height
);
390 XMapWindow(ob_display
, self
->handle
);
392 if (self
->decorations
& OB_FRAME_DECOR_GRIPS
) {
393 XMoveWindow(ob_display
, self
->lgrip
,
394 -self
->rbwidth
, -self
->rbwidth
);
395 XMoveWindow(ob_display
, self
->rgrip
,
396 -self
->rbwidth
+ self
->width
-
397 ob_rr_theme
->grip_width
, -self
->rbwidth
);
398 XMapWindow(ob_display
, self
->lgrip
);
399 XMapWindow(ob_display
, self
->rgrip
);
401 XUnmapWindow(ob_display
, self
->lgrip
);
402 XUnmapWindow(ob_display
, self
->rgrip
);
405 /* XXX make a subwindow with these dimentions?
406 ob_rr_theme->grip_width + self->bwidth, 0,
407 self->width - (ob_rr_theme->grip_width + self->bwidth) * 2,
408 ob_rr_theme->handle_height);
411 XUnmapWindow(ob_display
, self
->handle
);
413 /* move and resize the plate */
414 XMoveResizeWindow(ob_display
, self
->plate
,
415 self
->innersize
.left
- self
->cbwidth_x
,
416 self
->innersize
.top
- self
->cbwidth_y
,
417 self
->client
->area
.width
+ self
->cbwidth_x
* 2,
418 self
->client
->area
.height
+ self
->cbwidth_y
* 2);
419 /* when the client has StaticGravity, it likes to move around. */
420 XMoveWindow(ob_display
, self
->client
->window
,
421 self
->cbwidth_x
, self
->cbwidth_y
);
424 STRUT_SET(self
->size
,
425 self
->innersize
.left
+ self
->bwidth
,
426 self
->innersize
.top
+ self
->bwidth
,
427 self
->innersize
.right
+ self
->bwidth
,
428 self
->innersize
.bottom
+ self
->bwidth
);
431 /* shading can change without being moved or resized */
432 RECT_SET_SIZE(self
->area
,
433 self
->client
->area
.width
+
434 self
->size
.left
+ self
->size
.right
,
435 (self
->client
->shaded
?
436 ob_rr_theme
->title_height
+ self
->rbwidth
* 2:
437 self
->client
->area
.height
+
438 self
->size
.top
+ self
->size
.bottom
));
441 /* find the new coordinates, done after setting the frame.size, for
442 frame_client_gravity. */
443 self
->area
.x
= self
->client
->area
.x
;
444 self
->area
.y
= self
->client
->area
.y
;
445 frame_client_gravity(self
, &self
->area
.x
, &self
->area
.y
);
449 /* move and resize the top level frame.
450 shading can change without being moved or resized */
451 XMoveResizeWindow(ob_display
, self
->window
,
452 self
->area
.x
, self
->area
.y
,
453 self
->area
.width
- self
->bwidth
* 2,
454 self
->area
.height
- self
->bwidth
* 2);
457 framerender_frame(self
);
458 frame_adjust_shape(self
);
461 if (!STRUT_EQUAL(self
->size
, oldsize
)) {
463 vals
[0] = self
->size
.left
;
464 vals
[1] = self
->size
.right
;
465 vals
[2] = self
->size
.top
;
466 vals
[3] = self
->size
.bottom
;
467 PROP_SETA32(self
->client
->window
, kde_net_wm_frame_strut
,
471 /* if this occurs while we are focus cycling, the indicator needs to
473 if (focus_cycle_target
== self
->client
)
474 focus_cycle_draw_indicator();
476 if (resized
&& (self
->decorations
& OB_FRAME_DECOR_TITLEBAR
))
477 XResizeWindow(ob_display
, self
->label
, self
->label_width
,
478 ob_rr_theme
->label_height
);
481 void frame_adjust_state(ObFrame
*self
)
483 framerender_frame(self
);
486 void frame_adjust_focus(ObFrame
*self
, gboolean hilite
)
488 self
->focused
= hilite
;
489 framerender_frame(self
);
492 void frame_adjust_title(ObFrame
*self
)
494 framerender_frame(self
);
497 void frame_adjust_icon(ObFrame
*self
)
499 framerender_frame(self
);
502 void frame_grab_client(ObFrame
*self
, ObClient
*client
)
504 self
->client
= client
;
506 /* reparent the client to the frame */
507 XReparentWindow(ob_display
, client
->window
, self
->plate
, 0, 0);
509 When reparenting the client window, it is usually not mapped yet, since
510 this occurs from a MapRequest. However, in the case where Openbox is
511 starting up, the window is already mapped, so we'll see unmap events for
512 it. There are 2 unmap events generated that we see, one with the 'event'
513 member set the root window, and one set to the client, but both get
514 handled and need to be ignored.
516 if (ob_state() == OB_STATE_STARTING
)
517 client
->ignore_unmaps
+= 2;
519 /* select the event mask on the client's parent (to receive config/map
520 req's) the ButtonPress is to catch clicks on the client border */
521 XSelectInput(ob_display
, self
->plate
, PLATE_EVENTMASK
);
523 /* map the client so it maps when the frame does */
524 XMapWindow(ob_display
, client
->window
);
526 frame_adjust_area(self
, TRUE
, TRUE
, FALSE
);
528 /* set all the windows for the frame in the window_map */
529 g_hash_table_insert(window_map
, &self
->window
, client
);
530 g_hash_table_insert(window_map
, &self
->plate
, client
);
531 g_hash_table_insert(window_map
, &self
->title
, client
);
532 g_hash_table_insert(window_map
, &self
->label
, client
);
533 g_hash_table_insert(window_map
, &self
->max
, client
);
534 g_hash_table_insert(window_map
, &self
->close
, client
);
535 g_hash_table_insert(window_map
, &self
->desk
, client
);
536 g_hash_table_insert(window_map
, &self
->shade
, client
);
537 g_hash_table_insert(window_map
, &self
->icon
, client
);
538 g_hash_table_insert(window_map
, &self
->iconify
, client
);
539 g_hash_table_insert(window_map
, &self
->handle
, client
);
540 g_hash_table_insert(window_map
, &self
->lgrip
, client
);
541 g_hash_table_insert(window_map
, &self
->rgrip
, client
);
542 g_hash_table_insert(window_map
, &self
->tlresize
, client
);
543 g_hash_table_insert(window_map
, &self
->trresize
, client
);
546 void frame_release_client(ObFrame
*self
, ObClient
*client
)
549 gboolean reparent
= TRUE
;
551 g_assert(self
->client
== client
);
553 /* check if the app has already reparented its window away */
554 while (XCheckTypedWindowEvent(ob_display
, client
->window
,
555 ReparentNotify
, &ev
))
557 /* This check makes sure we don't catch our own reparent action to
558 our frame window. This doesn't count as the app reparenting itself
561 Reparent events that are generated by us are just discarded here.
562 They are of no consequence to us anyhow.
564 if (ev
.xreparent
.parent
!= self
->plate
) {
566 XPutBackEvent(ob_display
, &ev
);
572 /* according to the ICCCM - if the client doesn't reparent itself,
573 then we will reparent the window to root for them */
574 XReparentWindow(ob_display
, client
->window
,
575 RootWindow(ob_display
, ob_screen
),
580 /* remove all the windows for the frame from the window_map */
581 g_hash_table_remove(window_map
, &self
->window
);
582 g_hash_table_remove(window_map
, &self
->plate
);
583 g_hash_table_remove(window_map
, &self
->title
);
584 g_hash_table_remove(window_map
, &self
->label
);
585 g_hash_table_remove(window_map
, &self
->max
);
586 g_hash_table_remove(window_map
, &self
->close
);
587 g_hash_table_remove(window_map
, &self
->desk
);
588 g_hash_table_remove(window_map
, &self
->shade
);
589 g_hash_table_remove(window_map
, &self
->icon
);
590 g_hash_table_remove(window_map
, &self
->iconify
);
591 g_hash_table_remove(window_map
, &self
->handle
);
592 g_hash_table_remove(window_map
, &self
->lgrip
);
593 g_hash_table_remove(window_map
, &self
->rgrip
);
594 g_hash_table_remove(window_map
, &self
->tlresize
);
595 g_hash_table_remove(window_map
, &self
->trresize
);
597 ob_main_loop_timeout_remove_data(ob_main_loop
, flash_timeout
, self
, TRUE
);
602 static void layout_title(ObFrame
*self
)
606 gboolean n
, d
, i
, l
, m
, c
, s
;
608 n
= d
= i
= l
= m
= c
= s
= FALSE
;
610 /* figure out whats being shown, and the width of the label */
611 self
->label_width
= self
->width
- (ob_rr_theme
->padding
+ 1) * 2;
612 for (lc
= config_title_layout
; *lc
!= '\0'; ++lc
) {
615 if (n
) { *lc
= ' '; break; } /* rm duplicates */
617 self
->label_width
-= (ob_rr_theme
->button_size
+ 2 +
618 ob_rr_theme
->padding
+ 1);
621 if (d
) { *lc
= ' '; break; }
622 if (!(self
->decorations
& OB_FRAME_DECOR_ALLDESKTOPS
)
623 && config_theme_hidedisabled
)
626 self
->label_width
-= (ob_rr_theme
->button_size
+
627 ob_rr_theme
->padding
+ 1);
630 if (s
) { *lc
= ' '; break; }
631 if (!(self
->decorations
& OB_FRAME_DECOR_SHADE
)
632 && config_theme_hidedisabled
)
635 self
->label_width
-= (ob_rr_theme
->button_size
+
636 ob_rr_theme
->padding
+ 1);
639 if (i
) { *lc
= ' '; break; }
640 if (!(self
->decorations
& OB_FRAME_DECOR_ICONIFY
)
641 && config_theme_hidedisabled
)
644 self
->label_width
-= (ob_rr_theme
->button_size
+
645 ob_rr_theme
->padding
+ 1);
648 if (l
) { *lc
= ' '; break; }
652 if (m
) { *lc
= ' '; break; }
653 if (!(self
->decorations
& OB_FRAME_DECOR_MAXIMIZE
)
654 && config_theme_hidedisabled
)
657 self
->label_width
-= (ob_rr_theme
->button_size
+
658 ob_rr_theme
->padding
+ 1);
661 if (c
) { *lc
= ' '; break; }
662 if (!(self
->decorations
& OB_FRAME_DECOR_CLOSE
)
663 && config_theme_hidedisabled
)
666 self
->label_width
-= (ob_rr_theme
->button_size
+
667 ob_rr_theme
->padding
+ 1);
671 if (self
->label_width
< 1) self
->label_width
= 1;
673 if (!n
) XUnmapWindow(ob_display
, self
->icon
);
674 if (!d
) XUnmapWindow(ob_display
, self
->desk
);
675 if (!s
) XUnmapWindow(ob_display
, self
->shade
);
676 if (!i
) XUnmapWindow(ob_display
, self
->iconify
);
677 if (!l
) XUnmapWindow(ob_display
, self
->label
);
678 if (!m
) XUnmapWindow(ob_display
, self
->max
);
679 if (!c
) XUnmapWindow(ob_display
, self
->close
);
681 x
= ob_rr_theme
->padding
+ 1;
682 for (lc
= config_title_layout
; *lc
!= '\0'; ++lc
) {
687 XMapWindow(ob_display
, self
->icon
);
688 XMoveWindow(ob_display
, self
->icon
, x
, ob_rr_theme
->padding
);
689 x
+= ob_rr_theme
->button_size
+ 2 + ob_rr_theme
->padding
+ 1;
694 XMapWindow(ob_display
, self
->desk
);
695 XMoveWindow(ob_display
, self
->desk
, x
, ob_rr_theme
->padding
+ 1);
696 x
+= ob_rr_theme
->button_size
+ ob_rr_theme
->padding
+ 1;
701 XMapWindow(ob_display
, self
->shade
);
702 XMoveWindow(ob_display
, self
->shade
, x
, ob_rr_theme
->padding
+ 1);
703 x
+= ob_rr_theme
->button_size
+ ob_rr_theme
->padding
+ 1;
708 XMapWindow(ob_display
, self
->iconify
);
709 XMoveWindow(ob_display
,self
->iconify
, x
, ob_rr_theme
->padding
+ 1);
710 x
+= ob_rr_theme
->button_size
+ ob_rr_theme
->padding
+ 1;
715 XMapWindow(ob_display
, self
->label
);
716 XMoveWindow(ob_display
, self
->label
, x
, ob_rr_theme
->padding
);
717 x
+= self
->label_width
+ ob_rr_theme
->padding
+ 1;
722 XMapWindow(ob_display
, self
->max
);
723 XMoveWindow(ob_display
, self
->max
, x
, ob_rr_theme
->padding
+ 1);
724 x
+= ob_rr_theme
->button_size
+ ob_rr_theme
->padding
+ 1;
729 XMapWindow(ob_display
, self
->close
);
730 XMoveWindow(ob_display
, self
->close
, x
, ob_rr_theme
->padding
+ 1);
731 x
+= ob_rr_theme
->button_size
+ ob_rr_theme
->padding
+ 1;
737 ObFrameContext
frame_context_from_string(const gchar
*name
)
739 if (!g_ascii_strcasecmp("Desktop", name
))
740 return OB_FRAME_CONTEXT_DESKTOP
;
741 else if (!g_ascii_strcasecmp("Client", name
))
742 return OB_FRAME_CONTEXT_CLIENT
;
743 else if (!g_ascii_strcasecmp("Titlebar", name
))
744 return OB_FRAME_CONTEXT_TITLEBAR
;
745 else if (!g_ascii_strcasecmp("Handle", name
))
746 return OB_FRAME_CONTEXT_HANDLE
;
747 else if (!g_ascii_strcasecmp("Frame", name
))
748 return OB_FRAME_CONTEXT_FRAME
;
749 else if (!g_ascii_strcasecmp("TLCorner", name
))
750 return OB_FRAME_CONTEXT_TLCORNER
;
751 else if (!g_ascii_strcasecmp("TRCorner", name
))
752 return OB_FRAME_CONTEXT_TRCORNER
;
753 else if (!g_ascii_strcasecmp("BLCorner", name
))
754 return OB_FRAME_CONTEXT_BLCORNER
;
755 else if (!g_ascii_strcasecmp("BRCorner", name
))
756 return OB_FRAME_CONTEXT_BRCORNER
;
757 else if (!g_ascii_strcasecmp("Maximize", name
))
758 return OB_FRAME_CONTEXT_MAXIMIZE
;
759 else if (!g_ascii_strcasecmp("AllDesktops", name
))
760 return OB_FRAME_CONTEXT_ALLDESKTOPS
;
761 else if (!g_ascii_strcasecmp("Shade", name
))
762 return OB_FRAME_CONTEXT_SHADE
;
763 else if (!g_ascii_strcasecmp("Iconify", name
))
764 return OB_FRAME_CONTEXT_ICONIFY
;
765 else if (!g_ascii_strcasecmp("Icon", name
))
766 return OB_FRAME_CONTEXT_ICON
;
767 else if (!g_ascii_strcasecmp("Close", name
))
768 return OB_FRAME_CONTEXT_CLOSE
;
769 else if (!g_ascii_strcasecmp("MoveResize", name
))
770 return OB_FRAME_CONTEXT_MOVE_RESIZE
;
771 return OB_FRAME_CONTEXT_NONE
;
774 ObFrameContext
frame_context(ObClient
*client
, Window win
)
778 if (moveresize_in_progress
)
779 return OB_FRAME_CONTEXT_MOVE_RESIZE
;
781 if (win
== RootWindow(ob_display
, ob_screen
))
782 return OB_FRAME_CONTEXT_DESKTOP
;
783 if (client
== NULL
) return OB_FRAME_CONTEXT_NONE
;
784 if (win
== client
->window
) {
785 /* conceptually, this is the desktop, as far as users are
787 if (client
->type
== OB_CLIENT_TYPE_DESKTOP
)
788 return OB_FRAME_CONTEXT_DESKTOP
;
789 return OB_FRAME_CONTEXT_CLIENT
;
792 self
= client
->frame
;
793 if (win
== self
->plate
) {
794 /* conceptually, this is the desktop, as far as users are
796 if (client
->type
== OB_CLIENT_TYPE_DESKTOP
)
797 return OB_FRAME_CONTEXT_DESKTOP
;
798 return OB_FRAME_CONTEXT_CLIENT
;
801 if (win
== self
->window
) return OB_FRAME_CONTEXT_FRAME
;
802 if (win
== self
->title
) return OB_FRAME_CONTEXT_TITLEBAR
;
803 if (win
== self
->label
) return OB_FRAME_CONTEXT_TITLEBAR
;
804 if (win
== self
->handle
) return OB_FRAME_CONTEXT_HANDLE
;
805 if (win
== self
->lgrip
) return OB_FRAME_CONTEXT_BLCORNER
;
806 if (win
== self
->rgrip
) return OB_FRAME_CONTEXT_BRCORNER
;
807 if (win
== self
->tlresize
) return OB_FRAME_CONTEXT_TLCORNER
;
808 if (win
== self
->trresize
) return OB_FRAME_CONTEXT_TRCORNER
;
809 if (win
== self
->max
) return OB_FRAME_CONTEXT_MAXIMIZE
;
810 if (win
== self
->iconify
) return OB_FRAME_CONTEXT_ICONIFY
;
811 if (win
== self
->close
) return OB_FRAME_CONTEXT_CLOSE
;
812 if (win
== self
->icon
) return OB_FRAME_CONTEXT_ICON
;
813 if (win
== self
->desk
) return OB_FRAME_CONTEXT_ALLDESKTOPS
;
814 if (win
== self
->shade
) return OB_FRAME_CONTEXT_SHADE
;
816 return OB_FRAME_CONTEXT_NONE
;
819 void frame_client_gravity(ObFrame
*self
, gint
*x
, gint
*y
)
822 switch (self
->client
->gravity
) {
824 case NorthWestGravity
:
825 case SouthWestGravity
:
832 *x
-= (self
->size
.left
+ self
->size
.right
) / 2;
835 case NorthEastGravity
:
836 case SouthEastGravity
:
838 *x
-= self
->size
.left
+ self
->size
.right
;
843 *x
-= self
->size
.left
;
848 switch (self
->client
->gravity
) {
850 case NorthWestGravity
:
851 case NorthEastGravity
:
858 *y
-= (self
->size
.top
+ self
->size
.bottom
) / 2;
861 case SouthWestGravity
:
862 case SouthEastGravity
:
864 *y
-= self
->size
.top
+ self
->size
.bottom
;
869 *y
-= self
->size
.top
;
874 void frame_frame_gravity(ObFrame
*self
, gint
*x
, gint
*y
)
877 switch (self
->client
->gravity
) {
879 case NorthWestGravity
:
881 case SouthWestGravity
:
886 *x
+= (self
->size
.left
+ self
->size
.right
) / 2;
888 case NorthEastGravity
:
890 case SouthEastGravity
:
891 *x
+= self
->size
.left
+ self
->size
.right
;
895 *x
+= self
->size
.left
;
900 switch (self
->client
->gravity
) {
902 case NorthWestGravity
:
904 case NorthEastGravity
:
909 *y
+= (self
->size
.top
+ self
->size
.bottom
) / 2;
911 case SouthWestGravity
:
913 case SouthEastGravity
:
914 *y
+= self
->size
.top
+ self
->size
.bottom
;
918 *y
+= self
->size
.top
;
923 static void flash_done(gpointer data
)
925 ObFrame
*self
= data
;
927 if (self
->focused
!= self
->flash_on
)
928 frame_adjust_focus(self
, self
->focused
);
931 static gboolean
flash_timeout(gpointer data
)
933 ObFrame
*self
= data
;
936 g_get_current_time(&now
);
937 if (now
.tv_sec
> self
->flash_end
.tv_sec
||
938 (now
.tv_sec
== self
->flash_end
.tv_sec
&&
939 now
.tv_usec
>= self
->flash_end
.tv_usec
))
940 self
->flashing
= FALSE
;
943 return FALSE
; /* we are done */
945 self
->flash_on
= !self
->flash_on
;
946 if (!self
->focused
) {
947 frame_adjust_focus(self
, self
->flash_on
);
948 self
->focused
= FALSE
;
951 return TRUE
; /* go again */
954 void frame_flash_start(ObFrame
*self
)
956 self
->flash_on
= self
->focused
;
959 ob_main_loop_timeout_add(ob_main_loop
,
960 G_USEC_PER_SEC
* 0.6,
964 g_get_current_time(&self
->flash_end
);
965 g_time_val_add(&self
->flash_end
, G_USEC_PER_SEC
* 5);
967 self
->flashing
= TRUE
;
970 void frame_flash_stop(ObFrame
*self
)
972 self
->flashing
= FALSE
;