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
, gulong mask
,
51 XSetWindowAttributes
*attrib
)
53 return XCreateWindow(ob_display
, parent
, 0, 0, 1, 1, 0,
54 RrDepth(ob_rr_inst
), InputOutput
,
55 RrVisual(ob_rr_inst
), mask
, attrib
);
61 XSetWindowAttributes attrib
;
65 self
= g_new0(ObFrame
, 1);
67 self
->obscured
= TRUE
;
69 /* create all of the decor windows */
71 attrib
.event_mask
= FRAME_EVENTMASK
;
72 self
->window
= createWindow(RootWindow(ob_display
, ob_screen
),
76 self
->plate
= createWindow(self
->window
, mask
, &attrib
);
79 attrib
.event_mask
= ELEMENT_EVENTMASK
;
80 self
->title
= createWindow(self
->window
, mask
, &attrib
);
83 attrib
.cursor
= ob_cursor(OB_CURSOR_NORTHWEST
);
84 self
->tlresize
= createWindow(self
->title
, mask
, &attrib
);
85 attrib
.cursor
= ob_cursor(OB_CURSOR_NORTHEAST
);
86 self
->trresize
= createWindow(self
->title
, mask
, &attrib
);
89 self
->label
= createWindow(self
->title
, mask
, &attrib
);
90 self
->max
= createWindow(self
->title
, mask
, &attrib
);
91 self
->close
= createWindow(self
->title
, mask
, &attrib
);
92 self
->desk
= createWindow(self
->title
, mask
, &attrib
);
93 self
->shade
= createWindow(self
->title
, mask
, &attrib
);
94 self
->icon
= createWindow(self
->title
, mask
, &attrib
);
95 self
->iconify
= createWindow(self
->title
, mask
, &attrib
);
96 self
->handle
= createWindow(self
->window
, mask
, &attrib
);
99 attrib
.cursor
= ob_cursor(OB_CURSOR_SOUTHWEST
);
100 self
->lgrip
= createWindow(self
->handle
, mask
, &attrib
);
101 attrib
.cursor
= ob_cursor(OB_CURSOR_SOUTHEAST
);
102 self
->rgrip
= createWindow(self
->handle
, mask
, &attrib
);
104 self
->focused
= FALSE
;
106 /* the other stuff is shown based on decor settings */
107 XMapWindow(ob_display
, self
->plate
);
108 XMapWindow(ob_display
, self
->lgrip
);
109 XMapWindow(ob_display
, self
->rgrip
);
110 XMapWindow(ob_display
, self
->label
);
112 self
->max_press
= self
->close_press
= self
->desk_press
=
113 self
->iconify_press
= self
->shade_press
= FALSE
;
114 self
->max_hover
= self
->close_hover
= self
->desk_hover
=
115 self
->iconify_hover
= self
->shade_hover
= FALSE
;
117 set_theme_statics(self
);
119 return (ObFrame
*)self
;
122 static void set_theme_statics(ObFrame
*self
)
124 /* set colors/appearance/sizes for stuff that doesn't change */
125 XSetWindowBorder(ob_display
, self
->window
,
126 RrColorPixel(ob_rr_theme
->b_color
));
127 XSetWindowBorder(ob_display
, self
->title
,
128 RrColorPixel(ob_rr_theme
->b_color
));
129 XSetWindowBorder(ob_display
, self
->handle
,
130 RrColorPixel(ob_rr_theme
->b_color
));
131 XSetWindowBorder(ob_display
, self
->rgrip
,
132 RrColorPixel(ob_rr_theme
->b_color
));
133 XSetWindowBorder(ob_display
, self
->lgrip
,
134 RrColorPixel(ob_rr_theme
->b_color
));
136 XResizeWindow(ob_display
, self
->max
,
137 ob_rr_theme
->button_size
, ob_rr_theme
->button_size
);
138 XResizeWindow(ob_display
, self
->iconify
,
139 ob_rr_theme
->button_size
, ob_rr_theme
->button_size
);
140 XResizeWindow(ob_display
, self
->icon
,
141 ob_rr_theme
->button_size
+ 2, ob_rr_theme
->button_size
+ 2);
142 XResizeWindow(ob_display
, self
->close
,
143 ob_rr_theme
->button_size
, ob_rr_theme
->button_size
);
144 XResizeWindow(ob_display
, self
->desk
,
145 ob_rr_theme
->button_size
, ob_rr_theme
->button_size
);
146 XResizeWindow(ob_display
, self
->shade
,
147 ob_rr_theme
->button_size
, ob_rr_theme
->button_size
);
148 XResizeWindow(ob_display
, self
->lgrip
,
149 ob_rr_theme
->grip_width
, ob_rr_theme
->handle_height
);
150 XResizeWindow(ob_display
, self
->rgrip
,
151 ob_rr_theme
->grip_width
, ob_rr_theme
->handle_height
);
152 XResizeWindow(ob_display
, self
->tlresize
,
153 ob_rr_theme
->grip_width
, ob_rr_theme
->handle_height
);
154 XResizeWindow(ob_display
, self
->trresize
,
155 ob_rr_theme
->grip_width
, ob_rr_theme
->handle_height
);
157 /* set up the dynamic appearances */
158 self
->a_unfocused_title
= RrAppearanceCopy(ob_rr_theme
->a_unfocused_title
);
159 self
->a_focused_title
= RrAppearanceCopy(ob_rr_theme
->a_focused_title
);
160 self
->a_unfocused_label
= RrAppearanceCopy(ob_rr_theme
->a_unfocused_label
);
161 self
->a_focused_label
= RrAppearanceCopy(ob_rr_theme
->a_focused_label
);
162 self
->a_unfocused_handle
=
163 RrAppearanceCopy(ob_rr_theme
->a_unfocused_handle
);
164 self
->a_focused_handle
= RrAppearanceCopy(ob_rr_theme
->a_focused_handle
);
165 self
->a_icon
= RrAppearanceCopy(ob_rr_theme
->a_icon
);
168 static void free_theme_statics(ObFrame
*self
)
170 RrAppearanceFree(self
->a_unfocused_title
);
171 RrAppearanceFree(self
->a_focused_title
);
172 RrAppearanceFree(self
->a_unfocused_label
);
173 RrAppearanceFree(self
->a_focused_label
);
174 RrAppearanceFree(self
->a_unfocused_handle
);
175 RrAppearanceFree(self
->a_focused_handle
);
176 RrAppearanceFree(self
->a_icon
);
179 static void frame_free(ObFrame
*self
)
181 free_theme_statics(self
);
183 XDestroyWindow(ob_display
, self
->window
);
188 void frame_show(ObFrame
*self
)
190 if (!self
->visible
) {
191 self
->visible
= TRUE
;
192 XMapWindow(ob_display
, self
->client
->window
);
193 XMapWindow(ob_display
, self
->window
);
197 void frame_hide(ObFrame
*self
)
200 self
->visible
= FALSE
;
201 self
->client
->ignore_unmaps
+= 2;
202 /* we unmap the client itself so that we can get MapRequest
203 events, and because the ICCCM tells us to! */
204 XUnmapWindow(ob_display
, self
->window
);
205 XUnmapWindow(ob_display
, self
->client
->window
);
209 void frame_adjust_theme(ObFrame
*self
)
211 free_theme_statics(self
);
212 set_theme_statics(self
);
215 void frame_adjust_shape(ObFrame
*self
)
221 if (!self
->client
->shaped
) {
222 /* clear the shape on the frame window */
223 XShapeCombineMask(ob_display
, self
->window
, ShapeBounding
,
224 self
->innersize
.left
,
228 /* make the frame's shape match the clients */
229 XShapeCombineShape(ob_display
, self
->window
, ShapeBounding
,
230 self
->innersize
.left
,
232 self
->client
->window
,
233 ShapeBounding
, ShapeSet
);
236 if (self
->decorations
& OB_FRAME_DECOR_TITLEBAR
) {
237 xrect
[0].x
= -ob_rr_theme
->bwidth
;
238 xrect
[0].y
= -ob_rr_theme
->bwidth
;
239 xrect
[0].width
= self
->width
+ self
->rbwidth
* 2;
240 xrect
[0].height
= ob_rr_theme
->title_height
+
245 if (self
->decorations
& OB_FRAME_DECOR_HANDLE
) {
246 xrect
[1].x
= -ob_rr_theme
->bwidth
;
247 xrect
[1].y
= FRAME_HANDLE_Y(self
);
248 xrect
[1].width
= self
->width
+ self
->rbwidth
* 2;
249 xrect
[1].height
= ob_rr_theme
->handle_height
+
254 XShapeCombineRectangles(ob_display
, self
->window
,
255 ShapeBounding
, 0, 0, xrect
, num
,
256 ShapeUnion
, Unsorted
);
261 void frame_adjust_area(ObFrame
*self
, gboolean moved
,
262 gboolean resized
, gboolean fake
)
266 oldsize
= self
->size
;
269 self
->decorations
= self
->client
->decorations
;
270 self
->max_horz
= self
->client
->max_horz
;
272 if (self
->decorations
& OB_FRAME_DECOR_BORDER
) {
273 self
->bwidth
= ob_rr_theme
->bwidth
;
274 self
->cbwidth_x
= self
->cbwidth_y
= ob_rr_theme
->cbwidth
;
276 self
->bwidth
= self
->cbwidth_x
= self
->cbwidth_y
= 0;
278 self
->rbwidth
= self
->bwidth
;
281 self
->bwidth
= self
->cbwidth_x
= 0;
283 STRUT_SET(self
->innersize
,
288 self
->width
= self
->client
->area
.width
+ self
->cbwidth_x
* 2 -
289 (self
->max_horz
? self
->rbwidth
* 2 : 0);
290 self
->width
= MAX(self
->width
, 1); /* no lower than 1 */
292 /* set border widths */
294 XSetWindowBorderWidth(ob_display
, self
->window
, self
->bwidth
);
295 XSetWindowBorderWidth(ob_display
, self
->title
, self
->rbwidth
);
296 XSetWindowBorderWidth(ob_display
, self
->handle
, self
->rbwidth
);
297 XSetWindowBorderWidth(ob_display
, self
->lgrip
, self
->rbwidth
);
298 XSetWindowBorderWidth(ob_display
, self
->rgrip
, self
->rbwidth
);
301 if (self
->decorations
& OB_FRAME_DECOR_TITLEBAR
)
302 self
->innersize
.top
+= ob_rr_theme
->title_height
+ self
->rbwidth
+
303 (self
->rbwidth
- self
->bwidth
);
304 if (self
->decorations
& OB_FRAME_DECOR_HANDLE
&&
305 ob_rr_theme
->show_handle
)
306 self
->innersize
.bottom
+= ob_rr_theme
->handle_height
+
307 self
->rbwidth
+ (self
->rbwidth
- self
->bwidth
);
309 /* they all default off, they're turned on in layout_title */
313 self
->iconify_x
= -1;
318 /* position/size and map/unmap all the windows */
321 if (self
->decorations
& OB_FRAME_DECOR_TITLEBAR
) {
322 XMoveResizeWindow(ob_display
, self
->title
,
323 -self
->bwidth
, -self
->bwidth
,
324 self
->width
, ob_rr_theme
->title_height
);
325 XMapWindow(ob_display
, self
->title
);
327 if (self
->decorations
& OB_FRAME_DECOR_GRIPS
) {
328 XMoveWindow(ob_display
, self
->tlresize
, 0, 0);
329 XMoveWindow(ob_display
, self
->trresize
,
330 self
->width
- ob_rr_theme
->grip_width
, 0);
331 XMapWindow(ob_display
, self
->tlresize
);
332 XMapWindow(ob_display
, self
->trresize
);
334 XUnmapWindow(ob_display
, self
->tlresize
);
335 XUnmapWindow(ob_display
, self
->trresize
);
338 XUnmapWindow(ob_display
, self
->title
);
341 if (self
->decorations
& OB_FRAME_DECOR_TITLEBAR
)
342 /* layout the title bar elements */
346 if (self
->decorations
& OB_FRAME_DECOR_HANDLE
&&
347 ob_rr_theme
->show_handle
)
349 XMoveResizeWindow(ob_display
, self
->handle
,
350 -self
->bwidth
, FRAME_HANDLE_Y(self
),
351 self
->width
, ob_rr_theme
->handle_height
);
352 XMapWindow(ob_display
, self
->handle
);
354 if (self
->decorations
& OB_FRAME_DECOR_GRIPS
) {
355 XMoveWindow(ob_display
, self
->lgrip
,
356 -self
->rbwidth
, -self
->rbwidth
);
357 XMoveWindow(ob_display
, self
->rgrip
,
358 -self
->rbwidth
+ self
->width
-
359 ob_rr_theme
->grip_width
, -self
->rbwidth
);
360 XMapWindow(ob_display
, self
->lgrip
);
361 XMapWindow(ob_display
, self
->rgrip
);
363 XUnmapWindow(ob_display
, self
->lgrip
);
364 XUnmapWindow(ob_display
, self
->rgrip
);
367 /* XXX make a subwindow with these dimentions?
368 ob_rr_theme->grip_width + self->bwidth, 0,
369 self->width - (ob_rr_theme->grip_width + self->bwidth) * 2,
370 ob_rr_theme->handle_height);
373 XUnmapWindow(ob_display
, self
->handle
);
375 /* move and resize the plate */
376 XMoveResizeWindow(ob_display
, self
->plate
,
377 self
->innersize
.left
- self
->cbwidth_x
,
378 self
->innersize
.top
- self
->cbwidth_y
,
379 self
->client
->area
.width
+ self
->cbwidth_x
* 2,
380 self
->client
->area
.height
+ self
->cbwidth_y
* 2);
381 /* when the client has StaticGravity, it likes to move around. */
382 XMoveWindow(ob_display
, self
->client
->window
,
383 self
->cbwidth_x
, self
->cbwidth_y
);
386 STRUT_SET(self
->size
,
387 self
->innersize
.left
+ self
->bwidth
,
388 self
->innersize
.top
+ self
->bwidth
,
389 self
->innersize
.right
+ self
->bwidth
,
390 self
->innersize
.bottom
+ self
->bwidth
);
393 /* shading can change without being moved or resized */
394 RECT_SET_SIZE(self
->area
,
395 self
->client
->area
.width
+
396 self
->size
.left
+ self
->size
.right
,
397 (self
->client
->shaded
?
398 ob_rr_theme
->title_height
+ self
->rbwidth
* 2:
399 self
->client
->area
.height
+
400 self
->size
.top
+ self
->size
.bottom
));
403 /* find the new coordinates, done after setting the frame.size, for
404 frame_client_gravity. */
405 self
->area
.x
= self
->client
->area
.x
;
406 self
->area
.y
= self
->client
->area
.y
;
407 frame_client_gravity(self
, &self
->area
.x
, &self
->area
.y
);
411 /* move and resize the top level frame.
412 shading can change without being moved or resized */
413 XMoveResizeWindow(ob_display
, self
->window
,
414 self
->area
.x
, self
->area
.y
,
415 self
->area
.width
- self
->bwidth
* 2,
416 self
->area
.height
- self
->bwidth
* 2);
419 framerender_frame(self
);
420 frame_adjust_shape(self
);
423 if (!STRUT_EQUAL(self
->size
, oldsize
)) {
425 vals
[0] = self
->size
.left
;
426 vals
[1] = self
->size
.right
;
427 vals
[2] = self
->size
.top
;
428 vals
[3] = self
->size
.bottom
;
429 PROP_SETA32(self
->client
->window
, kde_net_wm_frame_strut
,
433 /* if this occurs while we are focus cycling, the indicator needs to
435 if (focus_cycle_target
== self
->client
)
436 focus_cycle_draw_indicator();
438 if (resized
&& (self
->decorations
& OB_FRAME_DECOR_TITLEBAR
))
439 XResizeWindow(ob_display
, self
->label
, self
->label_width
,
440 ob_rr_theme
->label_height
);
443 void frame_adjust_state(ObFrame
*self
)
445 framerender_frame(self
);
448 void frame_adjust_focus(ObFrame
*self
, gboolean hilite
)
450 self
->focused
= hilite
;
451 framerender_frame(self
);
454 void frame_adjust_title(ObFrame
*self
)
456 framerender_frame(self
);
459 void frame_adjust_icon(ObFrame
*self
)
461 framerender_frame(self
);
464 void frame_grab_client(ObFrame
*self
, ObClient
*client
)
466 self
->client
= client
;
468 /* reparent the client to the frame */
469 XReparentWindow(ob_display
, client
->window
, self
->plate
, 0, 0);
471 When reparenting the client window, it is usually not mapped yet, since
472 this occurs from a MapRequest. However, in the case where Openbox is
473 starting up, the window is already mapped, so we'll see unmap events for
474 it. There are 2 unmap events generated that we see, one with the 'event'
475 member set the root window, and one set to the client, but both get
476 handled and need to be ignored.
478 if (ob_state() == OB_STATE_STARTING
)
479 client
->ignore_unmaps
+= 2;
481 /* select the event mask on the client's parent (to receive config/map
482 req's) the ButtonPress is to catch clicks on the client border */
483 XSelectInput(ob_display
, self
->plate
, PLATE_EVENTMASK
);
485 /* map the client so it maps when the frame does */
486 XMapWindow(ob_display
, client
->window
);
488 frame_adjust_area(self
, TRUE
, TRUE
, FALSE
);
490 /* set all the windows for the frame in the window_map */
491 g_hash_table_insert(window_map
, &self
->window
, client
);
492 g_hash_table_insert(window_map
, &self
->plate
, client
);
493 g_hash_table_insert(window_map
, &self
->title
, client
);
494 g_hash_table_insert(window_map
, &self
->label
, client
);
495 g_hash_table_insert(window_map
, &self
->max
, client
);
496 g_hash_table_insert(window_map
, &self
->close
, client
);
497 g_hash_table_insert(window_map
, &self
->desk
, client
);
498 g_hash_table_insert(window_map
, &self
->shade
, client
);
499 g_hash_table_insert(window_map
, &self
->icon
, client
);
500 g_hash_table_insert(window_map
, &self
->iconify
, client
);
501 g_hash_table_insert(window_map
, &self
->handle
, client
);
502 g_hash_table_insert(window_map
, &self
->lgrip
, client
);
503 g_hash_table_insert(window_map
, &self
->rgrip
, client
);
504 g_hash_table_insert(window_map
, &self
->tlresize
, client
);
505 g_hash_table_insert(window_map
, &self
->trresize
, client
);
508 void frame_release_client(ObFrame
*self
, ObClient
*client
)
511 gboolean reparent
= TRUE
;
513 g_assert(self
->client
== client
);
515 /* check if the app has already reparented its window away */
516 while (XCheckTypedWindowEvent(ob_display
, client
->window
,
517 ReparentNotify
, &ev
))
519 /* This check makes sure we don't catch our own reparent action to
520 our frame window. This doesn't count as the app reparenting itself
523 Reparent events that are generated by us are just discarded here.
524 They are of no consequence to us anyhow.
526 if (ev
.xreparent
.parent
!= self
->plate
) {
528 XPutBackEvent(ob_display
, &ev
);
534 /* according to the ICCCM - if the client doesn't reparent itself,
535 then we will reparent the window to root for them */
536 XReparentWindow(ob_display
, client
->window
,
537 RootWindow(ob_display
, ob_screen
),
542 /* remove all the windows for the frame from the window_map */
543 g_hash_table_remove(window_map
, &self
->window
);
544 g_hash_table_remove(window_map
, &self
->plate
);
545 g_hash_table_remove(window_map
, &self
->title
);
546 g_hash_table_remove(window_map
, &self
->label
);
547 g_hash_table_remove(window_map
, &self
->max
);
548 g_hash_table_remove(window_map
, &self
->close
);
549 g_hash_table_remove(window_map
, &self
->desk
);
550 g_hash_table_remove(window_map
, &self
->shade
);
551 g_hash_table_remove(window_map
, &self
->icon
);
552 g_hash_table_remove(window_map
, &self
->iconify
);
553 g_hash_table_remove(window_map
, &self
->handle
);
554 g_hash_table_remove(window_map
, &self
->lgrip
);
555 g_hash_table_remove(window_map
, &self
->rgrip
);
556 g_hash_table_remove(window_map
, &self
->tlresize
);
557 g_hash_table_remove(window_map
, &self
->trresize
);
559 ob_main_loop_timeout_remove_data(ob_main_loop
, flash_timeout
, self
, TRUE
);
564 static void layout_title(ObFrame
*self
)
568 gboolean n
, d
, i
, l
, m
, c
, s
;
570 n
= d
= i
= l
= m
= c
= s
= FALSE
;
572 /* figure out whats being shown, and the width of the label */
573 self
->label_width
= self
->width
- (ob_rr_theme
->padding
+ 1) * 2;
574 for (lc
= config_title_layout
; *lc
!= '\0'; ++lc
) {
577 if (n
) { *lc
= ' '; break; } /* rm duplicates */
579 self
->label_width
-= (ob_rr_theme
->button_size
+ 2 +
580 ob_rr_theme
->padding
+ 1);
583 if (d
) { *lc
= ' '; break; }
584 if (!(self
->decorations
& OB_FRAME_DECOR_ALLDESKTOPS
)
585 && config_theme_hidedisabled
)
588 self
->label_width
-= (ob_rr_theme
->button_size
+
589 ob_rr_theme
->padding
+ 1);
592 if (s
) { *lc
= ' '; break; }
593 if (!(self
->decorations
& OB_FRAME_DECOR_SHADE
)
594 && config_theme_hidedisabled
)
597 self
->label_width
-= (ob_rr_theme
->button_size
+
598 ob_rr_theme
->padding
+ 1);
601 if (i
) { *lc
= ' '; break; }
602 if (!(self
->decorations
& OB_FRAME_DECOR_ICONIFY
)
603 && config_theme_hidedisabled
)
606 self
->label_width
-= (ob_rr_theme
->button_size
+
607 ob_rr_theme
->padding
+ 1);
610 if (l
) { *lc
= ' '; break; }
614 if (m
) { *lc
= ' '; break; }
615 if (!(self
->decorations
& OB_FRAME_DECOR_MAXIMIZE
)
616 && config_theme_hidedisabled
)
619 self
->label_width
-= (ob_rr_theme
->button_size
+
620 ob_rr_theme
->padding
+ 1);
623 if (c
) { *lc
= ' '; break; }
624 if (!(self
->decorations
& OB_FRAME_DECOR_CLOSE
)
625 && config_theme_hidedisabled
)
628 self
->label_width
-= (ob_rr_theme
->button_size
+
629 ob_rr_theme
->padding
+ 1);
633 if (self
->label_width
< 1) self
->label_width
= 1;
635 if (!n
) XUnmapWindow(ob_display
, self
->icon
);
636 if (!d
) XUnmapWindow(ob_display
, self
->desk
);
637 if (!s
) XUnmapWindow(ob_display
, self
->shade
);
638 if (!i
) XUnmapWindow(ob_display
, self
->iconify
);
639 if (!l
) XUnmapWindow(ob_display
, self
->label
);
640 if (!m
) XUnmapWindow(ob_display
, self
->max
);
641 if (!c
) XUnmapWindow(ob_display
, self
->close
);
643 x
= ob_rr_theme
->padding
+ 1;
644 for (lc
= config_title_layout
; *lc
!= '\0'; ++lc
) {
649 XMapWindow(ob_display
, self
->icon
);
650 XMoveWindow(ob_display
, self
->icon
, x
, ob_rr_theme
->padding
);
651 x
+= ob_rr_theme
->button_size
+ 2 + ob_rr_theme
->padding
+ 1;
656 XMapWindow(ob_display
, self
->desk
);
657 XMoveWindow(ob_display
, self
->desk
, x
, ob_rr_theme
->padding
+ 1);
658 x
+= ob_rr_theme
->button_size
+ ob_rr_theme
->padding
+ 1;
663 XMapWindow(ob_display
, self
->shade
);
664 XMoveWindow(ob_display
, self
->shade
, x
, ob_rr_theme
->padding
+ 1);
665 x
+= ob_rr_theme
->button_size
+ ob_rr_theme
->padding
+ 1;
670 XMapWindow(ob_display
, self
->iconify
);
671 XMoveWindow(ob_display
,self
->iconify
, x
, ob_rr_theme
->padding
+ 1);
672 x
+= ob_rr_theme
->button_size
+ ob_rr_theme
->padding
+ 1;
677 XMapWindow(ob_display
, self
->label
);
678 XMoveWindow(ob_display
, self
->label
, x
, ob_rr_theme
->padding
);
679 x
+= self
->label_width
+ ob_rr_theme
->padding
+ 1;
684 XMapWindow(ob_display
, self
->max
);
685 XMoveWindow(ob_display
, self
->max
, x
, ob_rr_theme
->padding
+ 1);
686 x
+= ob_rr_theme
->button_size
+ ob_rr_theme
->padding
+ 1;
691 XMapWindow(ob_display
, self
->close
);
692 XMoveWindow(ob_display
, self
->close
, x
, ob_rr_theme
->padding
+ 1);
693 x
+= ob_rr_theme
->button_size
+ ob_rr_theme
->padding
+ 1;
699 ObFrameContext
frame_context_from_string(const gchar
*name
)
701 if (!g_ascii_strcasecmp("Desktop", name
))
702 return OB_FRAME_CONTEXT_DESKTOP
;
703 else if (!g_ascii_strcasecmp("Client", name
))
704 return OB_FRAME_CONTEXT_CLIENT
;
705 else if (!g_ascii_strcasecmp("Titlebar", name
))
706 return OB_FRAME_CONTEXT_TITLEBAR
;
707 else if (!g_ascii_strcasecmp("Handle", name
))
708 return OB_FRAME_CONTEXT_HANDLE
;
709 else if (!g_ascii_strcasecmp("Frame", name
))
710 return OB_FRAME_CONTEXT_FRAME
;
711 else if (!g_ascii_strcasecmp("TLCorner", name
))
712 return OB_FRAME_CONTEXT_TLCORNER
;
713 else if (!g_ascii_strcasecmp("TRCorner", name
))
714 return OB_FRAME_CONTEXT_TRCORNER
;
715 else if (!g_ascii_strcasecmp("BLCorner", name
))
716 return OB_FRAME_CONTEXT_BLCORNER
;
717 else if (!g_ascii_strcasecmp("BRCorner", name
))
718 return OB_FRAME_CONTEXT_BRCORNER
;
719 else if (!g_ascii_strcasecmp("Maximize", name
))
720 return OB_FRAME_CONTEXT_MAXIMIZE
;
721 else if (!g_ascii_strcasecmp("AllDesktops", name
))
722 return OB_FRAME_CONTEXT_ALLDESKTOPS
;
723 else if (!g_ascii_strcasecmp("Shade", name
))
724 return OB_FRAME_CONTEXT_SHADE
;
725 else if (!g_ascii_strcasecmp("Iconify", name
))
726 return OB_FRAME_CONTEXT_ICONIFY
;
727 else if (!g_ascii_strcasecmp("Icon", name
))
728 return OB_FRAME_CONTEXT_ICON
;
729 else if (!g_ascii_strcasecmp("Close", name
))
730 return OB_FRAME_CONTEXT_CLOSE
;
731 else if (!g_ascii_strcasecmp("MoveResize", name
))
732 return OB_FRAME_CONTEXT_MOVE_RESIZE
;
733 return OB_FRAME_CONTEXT_NONE
;
736 ObFrameContext
frame_context(ObClient
*client
, Window win
)
740 if (moveresize_in_progress
)
741 return OB_FRAME_CONTEXT_MOVE_RESIZE
;
743 if (win
== RootWindow(ob_display
, ob_screen
))
744 return OB_FRAME_CONTEXT_DESKTOP
;
745 if (client
== NULL
) return OB_FRAME_CONTEXT_NONE
;
746 if (win
== client
->window
) {
747 /* conceptually, this is the desktop, as far as users are
749 if (client
->type
== OB_CLIENT_TYPE_DESKTOP
)
750 return OB_FRAME_CONTEXT_DESKTOP
;
751 return OB_FRAME_CONTEXT_CLIENT
;
754 self
= client
->frame
;
755 if (win
== self
->plate
) {
756 /* conceptually, this is the desktop, as far as users are
758 if (client
->type
== OB_CLIENT_TYPE_DESKTOP
)
759 return OB_FRAME_CONTEXT_DESKTOP
;
760 return OB_FRAME_CONTEXT_CLIENT
;
763 if (win
== self
->window
) return OB_FRAME_CONTEXT_FRAME
;
764 if (win
== self
->title
) return OB_FRAME_CONTEXT_TITLEBAR
;
765 if (win
== self
->label
) return OB_FRAME_CONTEXT_TITLEBAR
;
766 if (win
== self
->handle
) return OB_FRAME_CONTEXT_HANDLE
;
767 if (win
== self
->lgrip
) return OB_FRAME_CONTEXT_BLCORNER
;
768 if (win
== self
->rgrip
) return OB_FRAME_CONTEXT_BRCORNER
;
769 if (win
== self
->tlresize
) return OB_FRAME_CONTEXT_TLCORNER
;
770 if (win
== self
->trresize
) return OB_FRAME_CONTEXT_TRCORNER
;
771 if (win
== self
->max
) return OB_FRAME_CONTEXT_MAXIMIZE
;
772 if (win
== self
->iconify
) return OB_FRAME_CONTEXT_ICONIFY
;
773 if (win
== self
->close
) return OB_FRAME_CONTEXT_CLOSE
;
774 if (win
== self
->icon
) return OB_FRAME_CONTEXT_ICON
;
775 if (win
== self
->desk
) return OB_FRAME_CONTEXT_ALLDESKTOPS
;
776 if (win
== self
->shade
) return OB_FRAME_CONTEXT_SHADE
;
778 return OB_FRAME_CONTEXT_NONE
;
781 void frame_client_gravity(ObFrame
*self
, gint
*x
, gint
*y
)
784 switch (self
->client
->gravity
) {
786 case NorthWestGravity
:
787 case SouthWestGravity
:
794 *x
-= (self
->size
.left
+ self
->size
.right
) / 2;
797 case NorthEastGravity
:
798 case SouthEastGravity
:
800 *x
-= self
->size
.left
+ self
->size
.right
;
805 *x
-= self
->size
.left
;
810 switch (self
->client
->gravity
) {
812 case NorthWestGravity
:
813 case NorthEastGravity
:
820 *y
-= (self
->size
.top
+ self
->size
.bottom
) / 2;
823 case SouthWestGravity
:
824 case SouthEastGravity
:
826 *y
-= self
->size
.top
+ self
->size
.bottom
;
831 *y
-= self
->size
.top
;
836 void frame_frame_gravity(ObFrame
*self
, gint
*x
, gint
*y
)
839 switch (self
->client
->gravity
) {
841 case NorthWestGravity
:
843 case SouthWestGravity
:
848 *x
+= (self
->size
.left
+ self
->size
.right
) / 2;
850 case NorthEastGravity
:
852 case SouthEastGravity
:
853 *x
+= self
->size
.left
+ self
->size
.right
;
857 *x
+= self
->size
.left
;
862 switch (self
->client
->gravity
) {
864 case NorthWestGravity
:
866 case NorthEastGravity
:
871 *y
+= (self
->size
.top
+ self
->size
.bottom
) / 2;
873 case SouthWestGravity
:
875 case SouthEastGravity
:
876 *y
+= self
->size
.top
+ self
->size
.bottom
;
880 *y
+= self
->size
.top
;
885 static void flash_done(gpointer data
)
887 ObFrame
*self
= data
;
889 if (self
->focused
!= self
->flash_on
)
890 frame_adjust_focus(self
, self
->focused
);
893 static gboolean
flash_timeout(gpointer data
)
895 ObFrame
*self
= data
;
898 g_get_current_time(&now
);
899 if (now
.tv_sec
> self
->flash_end
.tv_sec
||
900 (now
.tv_sec
== self
->flash_end
.tv_sec
&&
901 now
.tv_usec
>= self
->flash_end
.tv_usec
))
902 self
->flashing
= FALSE
;
905 return FALSE
; /* we are done */
907 self
->flash_on
= !self
->flash_on
;
908 if (!self
->focused
) {
909 frame_adjust_focus(self
, self
->flash_on
);
910 self
->focused
= FALSE
;
913 return TRUE
; /* go again */
916 void frame_flash_start(ObFrame
*self
)
918 self
->flash_on
= self
->focused
;
921 ob_main_loop_timeout_add(ob_main_loop
,
922 G_USEC_PER_SEC
* 0.6,
926 g_get_current_time(&self
->flash_end
);
927 g_time_val_add(&self
->flash_end
, G_USEC_PER_SEC
* 5);
929 self
->flashing
= TRUE
;
932 void frame_flash_stop(ObFrame
*self
)
934 self
->flashing
= FALSE
;