1 /* -*- indent-tabs-mode: nil; tab-width: 4; c-basic-offset: 4; -*-
3 frame.c for the Openbox window manager
4 Copyright (c) 2004 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
);
46 static void flash_client_dest(ObClient
*client
, gpointer data
);
48 static void set_theme_statics(ObFrame
*self
);
49 static void free_theme_statics(ObFrame
*self
);
51 static Window
createWindow(Window parent
, gulong mask
,
52 XSetWindowAttributes
*attrib
)
54 return XCreateWindow(ob_display
, parent
, 0, 0, 1, 1, 0,
55 RrDepth(ob_rr_inst
), InputOutput
,
56 RrVisual(ob_rr_inst
), mask
, attrib
);
60 void frame_startup(gboolean reconfig
)
63 client_add_destructor(flash_client_dest
, NULL
);
66 void frame_shutdown(gboolean reconfig
)
69 client_remove_destructor(flash_client_dest
);
74 XSetWindowAttributes attrib
;
78 self
= g_new0(ObFrame
, 1);
80 self
->obscured
= TRUE
;
82 /* create all of the decor windows */
84 attrib
.event_mask
= FRAME_EVENTMASK
;
85 self
->window
= createWindow(RootWindow(ob_display
, ob_screen
),
89 self
->plate
= createWindow(self
->window
, mask
, &attrib
);
92 attrib
.event_mask
= ELEMENT_EVENTMASK
;
93 self
->title
= createWindow(self
->window
, mask
, &attrib
);
96 attrib
.cursor
= ob_cursor(OB_CURSOR_NORTHWEST
);
97 self
->tlresize
= createWindow(self
->title
, mask
, &attrib
);
98 attrib
.cursor
= ob_cursor(OB_CURSOR_NORTHEAST
);
99 self
->trresize
= createWindow(self
->title
, mask
, &attrib
);
102 self
->label
= createWindow(self
->title
, mask
, &attrib
);
103 self
->max
= createWindow(self
->title
, mask
, &attrib
);
104 self
->close
= createWindow(self
->title
, mask
, &attrib
);
105 self
->desk
= createWindow(self
->title
, mask
, &attrib
);
106 self
->shade
= createWindow(self
->title
, mask
, &attrib
);
107 self
->icon
= createWindow(self
->title
, mask
, &attrib
);
108 self
->iconify
= createWindow(self
->title
, mask
, &attrib
);
109 self
->handle
= createWindow(self
->window
, mask
, &attrib
);
112 attrib
.cursor
= ob_cursor(OB_CURSOR_SOUTHWEST
);
113 self
->lgrip
= createWindow(self
->handle
, mask
, &attrib
);
114 attrib
.cursor
= ob_cursor(OB_CURSOR_SOUTHEAST
);
115 self
->rgrip
= createWindow(self
->handle
, mask
, &attrib
);
117 self
->focused
= FALSE
;
119 /* the other stuff is shown based on decor settings */
120 XMapWindow(ob_display
, self
->plate
);
121 XMapWindow(ob_display
, self
->lgrip
);
122 XMapWindow(ob_display
, self
->rgrip
);
123 XMapWindow(ob_display
, self
->label
);
125 self
->max_press
= self
->close_press
= self
->desk_press
=
126 self
->iconify_press
= self
->shade_press
= FALSE
;
127 self
->max_hover
= self
->close_hover
= self
->desk_hover
=
128 self
->iconify_hover
= self
->shade_hover
= FALSE
;
130 set_theme_statics(self
);
132 return (ObFrame
*)self
;
135 static void set_theme_statics(ObFrame
*self
)
137 /* set colors/appearance/sizes for stuff that doesn't change */
138 XSetWindowBorder(ob_display
, self
->window
,
139 RrColorPixel(ob_rr_theme
->b_color
));
140 XSetWindowBorder(ob_display
, self
->title
,
141 RrColorPixel(ob_rr_theme
->b_color
));
142 XSetWindowBorder(ob_display
, self
->handle
,
143 RrColorPixel(ob_rr_theme
->b_color
));
144 XSetWindowBorder(ob_display
, self
->rgrip
,
145 RrColorPixel(ob_rr_theme
->b_color
));
146 XSetWindowBorder(ob_display
, self
->lgrip
,
147 RrColorPixel(ob_rr_theme
->b_color
));
149 XResizeWindow(ob_display
, self
->max
,
150 ob_rr_theme
->button_size
, ob_rr_theme
->button_size
);
151 XResizeWindow(ob_display
, self
->iconify
,
152 ob_rr_theme
->button_size
, ob_rr_theme
->button_size
);
153 XResizeWindow(ob_display
, self
->icon
,
154 ob_rr_theme
->button_size
+ 2, ob_rr_theme
->button_size
+ 2);
155 XResizeWindow(ob_display
, self
->close
,
156 ob_rr_theme
->button_size
, ob_rr_theme
->button_size
);
157 XResizeWindow(ob_display
, self
->desk
,
158 ob_rr_theme
->button_size
, ob_rr_theme
->button_size
);
159 XResizeWindow(ob_display
, self
->shade
,
160 ob_rr_theme
->button_size
, ob_rr_theme
->button_size
);
161 XResizeWindow(ob_display
, self
->lgrip
,
162 ob_rr_theme
->grip_width
, ob_rr_theme
->handle_height
);
163 XResizeWindow(ob_display
, self
->rgrip
,
164 ob_rr_theme
->grip_width
, ob_rr_theme
->handle_height
);
165 XResizeWindow(ob_display
, self
->tlresize
,
166 ob_rr_theme
->grip_width
, ob_rr_theme
->handle_height
);
167 XResizeWindow(ob_display
, self
->trresize
,
168 ob_rr_theme
->grip_width
, ob_rr_theme
->handle_height
);
170 /* set up the dynamic appearances */
171 self
->a_unfocused_title
= RrAppearanceCopy(ob_rr_theme
->a_unfocused_title
);
172 self
->a_focused_title
= RrAppearanceCopy(ob_rr_theme
->a_focused_title
);
173 self
->a_unfocused_label
= RrAppearanceCopy(ob_rr_theme
->a_unfocused_label
);
174 self
->a_focused_label
= RrAppearanceCopy(ob_rr_theme
->a_focused_label
);
175 self
->a_unfocused_handle
=
176 RrAppearanceCopy(ob_rr_theme
->a_unfocused_handle
);
177 self
->a_focused_handle
= RrAppearanceCopy(ob_rr_theme
->a_focused_handle
);
178 self
->a_icon
= RrAppearanceCopy(ob_rr_theme
->a_icon
);
181 static void free_theme_statics(ObFrame
*self
)
183 RrAppearanceFree(self
->a_unfocused_title
);
184 RrAppearanceFree(self
->a_focused_title
);
185 RrAppearanceFree(self
->a_unfocused_label
);
186 RrAppearanceFree(self
->a_focused_label
);
187 RrAppearanceFree(self
->a_unfocused_handle
);
188 RrAppearanceFree(self
->a_focused_handle
);
189 RrAppearanceFree(self
->a_icon
);
192 static void frame_free(ObFrame
*self
)
194 free_theme_statics(self
);
196 XDestroyWindow(ob_display
, self
->window
);
201 void frame_show(ObFrame
*self
)
203 if (!self
->visible
) {
204 self
->visible
= TRUE
;
205 XMapWindow(ob_display
, self
->client
->window
);
206 XMapWindow(ob_display
, self
->window
);
210 void frame_hide(ObFrame
*self
)
213 self
->visible
= FALSE
;
214 self
->client
->ignore_unmaps
+= 2;
215 /* we unmap the client itself so that we can get MapRequest
216 events, and because the ICCCM tells us to! */
217 XUnmapWindow(ob_display
, self
->window
);
218 XUnmapWindow(ob_display
, self
->client
->window
);
222 void frame_adjust_theme(ObFrame
*self
)
224 free_theme_statics(self
);
225 set_theme_statics(self
);
228 void frame_adjust_shape(ObFrame
*self
)
234 if (!self
->client
->shaped
) {
235 /* clear the shape on the frame window */
236 XShapeCombineMask(ob_display
, self
->window
, ShapeBounding
,
237 self
->innersize
.left
,
241 /* make the frame's shape match the clients */
242 XShapeCombineShape(ob_display
, self
->window
, ShapeBounding
,
243 self
->innersize
.left
,
245 self
->client
->window
,
246 ShapeBounding
, ShapeSet
);
249 if (self
->decorations
& OB_FRAME_DECOR_TITLEBAR
) {
250 xrect
[0].x
= -ob_rr_theme
->bwidth
;
251 xrect
[0].y
= -ob_rr_theme
->bwidth
;
252 xrect
[0].width
= self
->width
+ self
->rbwidth
* 2;
253 xrect
[0].height
= ob_rr_theme
->title_height
+
258 if (self
->decorations
& OB_FRAME_DECOR_HANDLE
) {
259 xrect
[1].x
= -ob_rr_theme
->bwidth
;
260 xrect
[1].y
= FRAME_HANDLE_Y(self
);
261 xrect
[1].width
= self
->width
+ self
->rbwidth
* 2;
262 xrect
[1].height
= ob_rr_theme
->handle_height
+
267 XShapeCombineRectangles(ob_display
, self
->window
,
268 ShapeBounding
, 0, 0, xrect
, num
,
269 ShapeUnion
, Unsorted
);
274 void frame_adjust_area(ObFrame
*self
, gboolean moved
,
275 gboolean resized
, gboolean fake
)
279 oldsize
= self
->size
;
282 self
->decorations
= self
->client
->decorations
;
283 self
->max_horz
= self
->client
->max_horz
;
285 if (self
->decorations
& OB_FRAME_DECOR_BORDER
) {
286 self
->bwidth
= ob_rr_theme
->bwidth
;
287 self
->cbwidth_x
= self
->cbwidth_y
= ob_rr_theme
->cbwidth
;
289 self
->bwidth
= self
->cbwidth_x
= self
->cbwidth_y
= 0;
291 self
->rbwidth
= self
->bwidth
;
294 self
->bwidth
= self
->cbwidth_x
= 0;
296 STRUT_SET(self
->innersize
,
301 self
->width
= self
->client
->area
.width
+ self
->cbwidth_x
* 2 -
302 (self
->max_horz
? self
->rbwidth
* 2 : 0);
303 self
->width
= MAX(self
->width
, 1); /* no lower than 1 */
305 /* set border widths */
307 XSetWindowBorderWidth(ob_display
, self
->window
, self
->bwidth
);
308 XSetWindowBorderWidth(ob_display
, self
->title
, self
->rbwidth
);
309 XSetWindowBorderWidth(ob_display
, self
->handle
, self
->rbwidth
);
310 XSetWindowBorderWidth(ob_display
, self
->lgrip
, self
->rbwidth
);
311 XSetWindowBorderWidth(ob_display
, self
->rgrip
, self
->rbwidth
);
314 if (self
->decorations
& OB_FRAME_DECOR_TITLEBAR
)
315 self
->innersize
.top
+= ob_rr_theme
->title_height
+ self
->rbwidth
+
316 (self
->rbwidth
- self
->bwidth
);
317 if (self
->decorations
& OB_FRAME_DECOR_HANDLE
&&
318 ob_rr_theme
->show_handle
)
319 self
->innersize
.bottom
+= ob_rr_theme
->handle_height
+
320 self
->rbwidth
+ (self
->rbwidth
- self
->bwidth
);
322 /* they all default off, they're turned on in layout_title */
326 self
->iconify_x
= -1;
331 /* position/size and map/unmap all the windows */
334 if (self
->decorations
& OB_FRAME_DECOR_TITLEBAR
) {
335 XMoveResizeWindow(ob_display
, self
->title
,
336 -self
->bwidth
, -self
->bwidth
,
337 self
->width
, ob_rr_theme
->title_height
);
338 XMapWindow(ob_display
, self
->title
);
340 if (self
->decorations
& OB_FRAME_DECOR_GRIPS
) {
341 XMoveWindow(ob_display
, self
->tlresize
, 0, 0);
342 XMoveWindow(ob_display
, self
->trresize
,
343 self
->width
- ob_rr_theme
->grip_width
, 0);
344 XMapWindow(ob_display
, self
->tlresize
);
345 XMapWindow(ob_display
, self
->trresize
);
347 XUnmapWindow(ob_display
, self
->tlresize
);
348 XUnmapWindow(ob_display
, self
->trresize
);
351 XUnmapWindow(ob_display
, self
->title
);
354 if (self
->decorations
& OB_FRAME_DECOR_TITLEBAR
)
355 /* layout the title bar elements */
359 if (self
->decorations
& OB_FRAME_DECOR_HANDLE
&&
360 ob_rr_theme
->show_handle
)
362 XMoveResizeWindow(ob_display
, self
->handle
,
363 -self
->bwidth
, FRAME_HANDLE_Y(self
),
364 self
->width
, ob_rr_theme
->handle_height
);
365 XMapWindow(ob_display
, self
->handle
);
367 if (self
->decorations
& OB_FRAME_DECOR_GRIPS
) {
368 XMoveWindow(ob_display
, self
->lgrip
,
369 -self
->rbwidth
, -self
->rbwidth
);
370 XMoveWindow(ob_display
, self
->rgrip
,
371 -self
->rbwidth
+ self
->width
-
372 ob_rr_theme
->grip_width
, -self
->rbwidth
);
373 XMapWindow(ob_display
, self
->lgrip
);
374 XMapWindow(ob_display
, self
->rgrip
);
376 XUnmapWindow(ob_display
, self
->lgrip
);
377 XUnmapWindow(ob_display
, self
->rgrip
);
380 /* XXX make a subwindow with these dimentions?
381 ob_rr_theme->grip_width + self->bwidth, 0,
382 self->width - (ob_rr_theme->grip_width + self->bwidth) * 2,
383 ob_rr_theme->handle_height);
386 XUnmapWindow(ob_display
, self
->handle
);
388 /* move and resize the plate */
389 XMoveResizeWindow(ob_display
, self
->plate
,
390 self
->innersize
.left
- self
->cbwidth_x
,
391 self
->innersize
.top
- self
->cbwidth_y
,
392 self
->client
->area
.width
+ self
->cbwidth_x
* 2,
393 self
->client
->area
.height
+ self
->cbwidth_y
* 2);
394 /* when the client has StaticGravity, it likes to move around. */
395 XMoveWindow(ob_display
, self
->client
->window
,
396 self
->cbwidth_x
, self
->cbwidth_y
);
399 STRUT_SET(self
->size
,
400 self
->innersize
.left
+ self
->bwidth
,
401 self
->innersize
.top
+ self
->bwidth
,
402 self
->innersize
.right
+ self
->bwidth
,
403 self
->innersize
.bottom
+ self
->bwidth
);
406 /* shading can change without being moved or resized */
407 RECT_SET_SIZE(self
->area
,
408 self
->client
->area
.width
+
409 self
->size
.left
+ self
->size
.right
,
410 (self
->client
->shaded
?
411 ob_rr_theme
->title_height
+ self
->rbwidth
* 2:
412 self
->client
->area
.height
+
413 self
->size
.top
+ self
->size
.bottom
));
416 /* find the new coordinates, done after setting the frame.size, for
417 frame_client_gravity. */
418 self
->area
.x
= self
->client
->area
.x
;
419 self
->area
.y
= self
->client
->area
.y
;
420 frame_client_gravity(self
, &self
->area
.x
, &self
->area
.y
);
424 /* move and resize the top level frame.
425 shading can change without being moved or resized */
426 XMoveResizeWindow(ob_display
, self
->window
,
427 self
->area
.x
, self
->area
.y
,
428 self
->area
.width
- self
->bwidth
* 2,
429 self
->area
.height
- self
->bwidth
* 2);
432 framerender_frame(self
);
433 frame_adjust_shape(self
);
436 if (!STRUT_EQUAL(self
->size
, oldsize
)) {
438 vals
[0] = self
->size
.left
;
439 vals
[1] = self
->size
.right
;
440 vals
[2] = self
->size
.top
;
441 vals
[3] = self
->size
.bottom
;
442 PROP_SETA32(self
->client
->window
, kde_net_wm_frame_strut
,
446 /* if this occurs while we are focus cycling, the indicator needs to
448 if (focus_cycle_target
== self
->client
)
449 focus_cycle_draw_indicator();
451 if (resized
&& (self
->decorations
& OB_FRAME_DECOR_TITLEBAR
))
452 XResizeWindow(ob_display
, self
->label
, self
->label_width
,
453 ob_rr_theme
->label_height
);
456 void frame_adjust_state(ObFrame
*self
)
458 framerender_frame(self
);
461 void frame_adjust_focus(ObFrame
*self
, gboolean hilite
)
463 self
->focused
= hilite
;
464 framerender_frame(self
);
467 void frame_adjust_title(ObFrame
*self
)
469 framerender_frame(self
);
472 void frame_adjust_icon(ObFrame
*self
)
474 framerender_frame(self
);
477 void frame_grab_client(ObFrame
*self
, ObClient
*client
)
479 self
->client
= client
;
481 /* reparent the client to the frame */
482 XReparentWindow(ob_display
, client
->window
, self
->plate
, 0, 0);
484 When reparenting the client window, it is usually not mapped yet, since
485 this occurs from a MapRequest. However, in the case where Openbox is
486 starting up, the window is already mapped, so we'll see unmap events for
487 it. There are 2 unmap events generated that we see, one with the 'event'
488 member set the root window, and one set to the client, but both get
489 handled and need to be ignored.
491 if (ob_state() == OB_STATE_STARTING
)
492 client
->ignore_unmaps
+= 2;
494 /* select the event mask on the client's parent (to receive config/map
495 req's) the ButtonPress is to catch clicks on the client border */
496 XSelectInput(ob_display
, self
->plate
, PLATE_EVENTMASK
);
498 /* map the client so it maps when the frame does */
499 XMapWindow(ob_display
, client
->window
);
501 frame_adjust_area(self
, TRUE
, TRUE
, FALSE
);
503 /* set all the windows for the frame in the window_map */
504 g_hash_table_insert(window_map
, &self
->window
, client
);
505 g_hash_table_insert(window_map
, &self
->plate
, client
);
506 g_hash_table_insert(window_map
, &self
->title
, client
);
507 g_hash_table_insert(window_map
, &self
->label
, client
);
508 g_hash_table_insert(window_map
, &self
->max
, client
);
509 g_hash_table_insert(window_map
, &self
->close
, client
);
510 g_hash_table_insert(window_map
, &self
->desk
, client
);
511 g_hash_table_insert(window_map
, &self
->shade
, client
);
512 g_hash_table_insert(window_map
, &self
->icon
, client
);
513 g_hash_table_insert(window_map
, &self
->iconify
, client
);
514 g_hash_table_insert(window_map
, &self
->handle
, client
);
515 g_hash_table_insert(window_map
, &self
->lgrip
, client
);
516 g_hash_table_insert(window_map
, &self
->rgrip
, client
);
517 g_hash_table_insert(window_map
, &self
->tlresize
, client
);
518 g_hash_table_insert(window_map
, &self
->trresize
, client
);
521 void frame_release_client(ObFrame
*self
, ObClient
*client
)
524 gboolean reparent
= TRUE
;
526 g_assert(self
->client
== client
);
528 /* check if the app has already reparented its window away */
529 while (XCheckTypedWindowEvent(ob_display
, client
->window
,
530 ReparentNotify
, &ev
))
532 /* This check makes sure we don't catch our own reparent action to
533 our frame window. This doesn't count as the app reparenting itself
536 Reparent events that are generated by us are just discarded here.
537 They are of no consequence to us anyhow.
539 if (ev
.xreparent
.parent
!= self
->plate
) {
541 XPutBackEvent(ob_display
, &ev
);
547 /* according to the ICCCM - if the client doesn't reparent itself,
548 then we will reparent the window to root for them */
549 XReparentWindow(ob_display
, client
->window
,
550 RootWindow(ob_display
, ob_screen
),
555 /* remove all the windows for the frame from the window_map */
556 g_hash_table_remove(window_map
, &self
->window
);
557 g_hash_table_remove(window_map
, &self
->plate
);
558 g_hash_table_remove(window_map
, &self
->title
);
559 g_hash_table_remove(window_map
, &self
->label
);
560 g_hash_table_remove(window_map
, &self
->max
);
561 g_hash_table_remove(window_map
, &self
->close
);
562 g_hash_table_remove(window_map
, &self
->desk
);
563 g_hash_table_remove(window_map
, &self
->shade
);
564 g_hash_table_remove(window_map
, &self
->icon
);
565 g_hash_table_remove(window_map
, &self
->iconify
);
566 g_hash_table_remove(window_map
, &self
->handle
);
567 g_hash_table_remove(window_map
, &self
->lgrip
);
568 g_hash_table_remove(window_map
, &self
->rgrip
);
569 g_hash_table_remove(window_map
, &self
->tlresize
);
570 g_hash_table_remove(window_map
, &self
->trresize
);
572 ob_main_loop_timeout_remove_data(ob_main_loop
, flash_timeout
, self
);
577 static void layout_title(ObFrame
*self
)
581 gboolean n
, d
, i
, l
, m
, c
, s
;
583 n
= d
= i
= l
= m
= c
= s
= FALSE
;
585 /* figure out whats being shown, and the width of the label */
586 self
->label_width
= self
->width
- (ob_rr_theme
->padding
+ 1) * 2;
587 for (lc
= config_title_layout
; *lc
!= '\0'; ++lc
) {
590 if (n
) { *lc
= ' '; break; } /* rm duplicates */
592 self
->label_width
-= (ob_rr_theme
->button_size
+ 2 +
593 ob_rr_theme
->padding
+ 1);
596 if (d
) { *lc
= ' '; break; }
597 if (!(self
->decorations
& OB_FRAME_DECOR_ALLDESKTOPS
) && config_theme_hidedisabled
)
600 self
->label_width
-= (ob_rr_theme
->button_size
+
601 ob_rr_theme
->padding
+ 1);
604 if (s
) { *lc
= ' '; break; }
605 if (!(self
->decorations
& OB_FRAME_DECOR_SHADE
) && config_theme_hidedisabled
)
608 self
->label_width
-= (ob_rr_theme
->button_size
+
609 ob_rr_theme
->padding
+ 1);
612 if (i
) { *lc
= ' '; break; }
613 if (!(self
->decorations
& OB_FRAME_DECOR_ICONIFY
) && config_theme_hidedisabled
)
616 self
->label_width
-= (ob_rr_theme
->button_size
+
617 ob_rr_theme
->padding
+ 1);
620 if (l
) { *lc
= ' '; break; }
624 if (m
) { *lc
= ' '; break; }
625 if (!(self
->decorations
& OB_FRAME_DECOR_MAXIMIZE
) && config_theme_hidedisabled
)
628 self
->label_width
-= (ob_rr_theme
->button_size
+
629 ob_rr_theme
->padding
+ 1);
632 if (c
) { *lc
= ' '; break; }
633 if (!(self
->decorations
& OB_FRAME_DECOR_CLOSE
) && config_theme_hidedisabled
)
636 self
->label_width
-= (ob_rr_theme
->button_size
+
637 ob_rr_theme
->padding
+ 1);
641 if (self
->label_width
< 1) self
->label_width
= 1;
643 if (!n
) XUnmapWindow(ob_display
, self
->icon
);
644 if (!d
) XUnmapWindow(ob_display
, self
->desk
);
645 if (!s
) XUnmapWindow(ob_display
, self
->shade
);
646 if (!i
) XUnmapWindow(ob_display
, self
->iconify
);
647 if (!l
) XUnmapWindow(ob_display
, self
->label
);
648 if (!m
) XUnmapWindow(ob_display
, self
->max
);
649 if (!c
) XUnmapWindow(ob_display
, self
->close
);
651 x
= ob_rr_theme
->padding
+ 1;
652 for (lc
= config_title_layout
; *lc
!= '\0'; ++lc
) {
657 XMapWindow(ob_display
, self
->icon
);
658 XMoveWindow(ob_display
, self
->icon
, x
, ob_rr_theme
->padding
);
659 x
+= ob_rr_theme
->button_size
+ 2 + ob_rr_theme
->padding
+ 1;
664 XMapWindow(ob_display
, self
->desk
);
665 XMoveWindow(ob_display
, self
->desk
, x
, ob_rr_theme
->padding
+ 1);
666 x
+= ob_rr_theme
->button_size
+ ob_rr_theme
->padding
+ 1;
671 XMapWindow(ob_display
, self
->shade
);
672 XMoveWindow(ob_display
, self
->shade
, x
, ob_rr_theme
->padding
+ 1);
673 x
+= ob_rr_theme
->button_size
+ ob_rr_theme
->padding
+ 1;
678 XMapWindow(ob_display
, self
->iconify
);
679 XMoveWindow(ob_display
,self
->iconify
, x
, ob_rr_theme
->padding
+ 1);
680 x
+= ob_rr_theme
->button_size
+ ob_rr_theme
->padding
+ 1;
685 XMapWindow(ob_display
, self
->label
);
686 XMoveWindow(ob_display
, self
->label
, x
, ob_rr_theme
->padding
);
687 x
+= self
->label_width
+ ob_rr_theme
->padding
+ 1;
692 XMapWindow(ob_display
, self
->max
);
693 XMoveWindow(ob_display
, self
->max
, x
, ob_rr_theme
->padding
+ 1);
694 x
+= ob_rr_theme
->button_size
+ ob_rr_theme
->padding
+ 1;
699 XMapWindow(ob_display
, self
->close
);
700 XMoveWindow(ob_display
, self
->close
, x
, ob_rr_theme
->padding
+ 1);
701 x
+= ob_rr_theme
->button_size
+ ob_rr_theme
->padding
+ 1;
707 ObFrameContext
frame_context_from_string(const gchar
*name
)
709 if (!g_ascii_strcasecmp("Desktop", name
))
710 return OB_FRAME_CONTEXT_DESKTOP
;
711 else if (!g_ascii_strcasecmp("Client", name
))
712 return OB_FRAME_CONTEXT_CLIENT
;
713 else if (!g_ascii_strcasecmp("Titlebar", name
))
714 return OB_FRAME_CONTEXT_TITLEBAR
;
715 else if (!g_ascii_strcasecmp("Handle", name
))
716 return OB_FRAME_CONTEXT_HANDLE
;
717 else if (!g_ascii_strcasecmp("Frame", name
))
718 return OB_FRAME_CONTEXT_FRAME
;
719 else if (!g_ascii_strcasecmp("TLCorner", name
))
720 return OB_FRAME_CONTEXT_TLCORNER
;
721 else if (!g_ascii_strcasecmp("TRCorner", name
))
722 return OB_FRAME_CONTEXT_TRCORNER
;
723 else if (!g_ascii_strcasecmp("BLCorner", name
))
724 return OB_FRAME_CONTEXT_BLCORNER
;
725 else if (!g_ascii_strcasecmp("BRCorner", name
))
726 return OB_FRAME_CONTEXT_BRCORNER
;
727 else if (!g_ascii_strcasecmp("Maximize", name
))
728 return OB_FRAME_CONTEXT_MAXIMIZE
;
729 else if (!g_ascii_strcasecmp("AllDesktops", name
))
730 return OB_FRAME_CONTEXT_ALLDESKTOPS
;
731 else if (!g_ascii_strcasecmp("Shade", name
))
732 return OB_FRAME_CONTEXT_SHADE
;
733 else if (!g_ascii_strcasecmp("Iconify", name
))
734 return OB_FRAME_CONTEXT_ICONIFY
;
735 else if (!g_ascii_strcasecmp("Icon", name
))
736 return OB_FRAME_CONTEXT_ICON
;
737 else if (!g_ascii_strcasecmp("Close", name
))
738 return OB_FRAME_CONTEXT_CLOSE
;
739 else if (!g_ascii_strcasecmp("MoveResize", name
))
740 return OB_FRAME_CONTEXT_MOVE_RESIZE
;
741 return OB_FRAME_CONTEXT_NONE
;
744 ObFrameContext
frame_context(ObClient
*client
, Window win
)
748 if (moveresize_in_progress
)
749 return OB_FRAME_CONTEXT_MOVE_RESIZE
;
751 if (win
== RootWindow(ob_display
, ob_screen
))
752 return OB_FRAME_CONTEXT_DESKTOP
;
753 if (client
== NULL
) return OB_FRAME_CONTEXT_NONE
;
754 if (win
== client
->window
) {
755 /* conceptually, this is the desktop, as far as users are
757 if (client
->type
== OB_CLIENT_TYPE_DESKTOP
)
758 return OB_FRAME_CONTEXT_DESKTOP
;
759 return OB_FRAME_CONTEXT_CLIENT
;
762 self
= client
->frame
;
763 if (win
== self
->plate
) {
764 /* conceptually, this is the desktop, as far as users are
766 if (client
->type
== OB_CLIENT_TYPE_DESKTOP
)
767 return OB_FRAME_CONTEXT_DESKTOP
;
768 return OB_FRAME_CONTEXT_CLIENT
;
771 if (win
== self
->window
) return OB_FRAME_CONTEXT_FRAME
;
772 if (win
== self
->title
) return OB_FRAME_CONTEXT_TITLEBAR
;
773 if (win
== self
->label
) return OB_FRAME_CONTEXT_TITLEBAR
;
774 if (win
== self
->handle
) return OB_FRAME_CONTEXT_HANDLE
;
775 if (win
== self
->lgrip
) return OB_FRAME_CONTEXT_BLCORNER
;
776 if (win
== self
->rgrip
) return OB_FRAME_CONTEXT_BRCORNER
;
777 if (win
== self
->tlresize
) return OB_FRAME_CONTEXT_TLCORNER
;
778 if (win
== self
->trresize
) return OB_FRAME_CONTEXT_TRCORNER
;
779 if (win
== self
->max
) return OB_FRAME_CONTEXT_MAXIMIZE
;
780 if (win
== self
->iconify
) return OB_FRAME_CONTEXT_ICONIFY
;
781 if (win
== self
->close
) return OB_FRAME_CONTEXT_CLOSE
;
782 if (win
== self
->icon
) return OB_FRAME_CONTEXT_ICON
;
783 if (win
== self
->desk
) return OB_FRAME_CONTEXT_ALLDESKTOPS
;
784 if (win
== self
->shade
) return OB_FRAME_CONTEXT_SHADE
;
786 return OB_FRAME_CONTEXT_NONE
;
789 void frame_client_gravity(ObFrame
*self
, gint
*x
, gint
*y
)
792 switch (self
->client
->gravity
) {
794 case NorthWestGravity
:
795 case SouthWestGravity
:
802 *x
-= (self
->size
.left
+ self
->size
.right
) / 2;
805 case NorthEastGravity
:
806 case SouthEastGravity
:
808 *x
-= self
->size
.left
+ self
->size
.right
;
813 *x
-= self
->size
.left
;
818 switch (self
->client
->gravity
) {
820 case NorthWestGravity
:
821 case NorthEastGravity
:
828 *y
-= (self
->size
.top
+ self
->size
.bottom
) / 2;
831 case SouthWestGravity
:
832 case SouthEastGravity
:
834 *y
-= self
->size
.top
+ self
->size
.bottom
;
839 *y
-= self
->size
.top
;
844 void frame_frame_gravity(ObFrame
*self
, gint
*x
, gint
*y
)
847 switch (self
->client
->gravity
) {
849 case NorthWestGravity
:
851 case SouthWestGravity
:
856 *x
+= (self
->size
.left
+ self
->size
.right
) / 2;
858 case NorthEastGravity
:
860 case SouthEastGravity
:
861 *x
+= self
->size
.left
+ self
->size
.right
;
865 *x
+= self
->size
.left
;
870 switch (self
->client
->gravity
) {
872 case NorthWestGravity
:
874 case NorthEastGravity
:
879 *y
+= (self
->size
.top
+ self
->size
.bottom
) / 2;
881 case SouthWestGravity
:
883 case SouthEastGravity
:
884 *y
+= self
->size
.top
+ self
->size
.bottom
;
888 *y
+= self
->size
.top
;
893 static void flash_done(gpointer data
)
895 ObFrame
*self
= data
;
897 if (self
->focused
!= self
->flash_on
)
898 frame_adjust_focus(self
, self
->focused
);
901 static gboolean
flash_timeout(gpointer data
)
903 ObFrame
*self
= data
;
906 g_get_current_time(&now
);
907 if (now
.tv_sec
> self
->flash_end
.tv_sec
||
908 (now
.tv_sec
== self
->flash_end
.tv_sec
&&
909 now
.tv_usec
>= self
->flash_end
.tv_usec
))
910 self
->flashing
= FALSE
;
913 return FALSE
; /* we are done */
915 self
->flash_on
= !self
->flash_on
;
916 if (!self
->focused
) {
917 frame_adjust_focus(self
, self
->flash_on
);
918 self
->focused
= FALSE
;
921 return TRUE
; /* go again */
924 static void flash_client_dest(ObClient
*client
, gpointer data
)
926 ob_main_loop_timeout_remove_data(ob_main_loop
, flash_timeout
, client
);
929 void frame_flash_start(ObFrame
*self
)
931 self
->flash_on
= self
->focused
;
934 ob_main_loop_timeout_add(ob_main_loop
,
935 G_USEC_PER_SEC
* 0.6,
939 g_get_current_time(&self
->flash_end
);
940 g_time_val_add(&self
->flash_end
, G_USEC_PER_SEC
* 5);
942 self
->flashing
= TRUE
;
945 void frame_flash_stop(ObFrame
*self
)
947 self
->flashing
= FALSE
;