1 /* -*- indent-tabs-mode: nil; tab-width: 4; c-basic-offset: 4; -*-
3 frame.c for the Openbox window manager
4 Copyright (c) 2003 Ben Jansens
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 See the COPYING file for a copy of the GNU General Public License.
22 #include "extensions.h"
25 #include "framerender.h"
28 #include "moveresize.h"
29 #include "render/theme.h"
31 #define PLATE_EVENTMASK (SubstructureRedirectMask | ButtonPressMask)
32 #define FRAME_EVENTMASK (EnterWindowMask | LeaveWindowMask | \
33 ButtonPressMask | ButtonReleaseMask | \
35 #define ELEMENT_EVENTMASK (ButtonPressMask | ButtonReleaseMask | \
36 ButtonMotionMask | ExposureMask | \
37 EnterWindowMask | LeaveWindowMask)
39 #define FRAME_HANDLE_Y(f) (f->innersize.top + f->client->area.height + \
42 static void layout_title(ObFrame
*self
);
43 static void flash_done(gpointer data
);
44 static gboolean
flash_timeout(gpointer data
);
46 static void set_theme_statics(ObFrame
*self
);
47 static void free_theme_statics(ObFrame
*self
);
49 static Window
createWindow(Window parent
, gulong mask
,
50 XSetWindowAttributes
*attrib
)
52 return XCreateWindow(ob_display
, parent
, 0, 0, 1, 1, 0,
53 RrDepth(ob_rr_inst
), InputOutput
,
54 RrVisual(ob_rr_inst
), mask
, attrib
);
60 XSetWindowAttributes attrib
;
64 self
= g_new0(ObFrame
, 1);
66 self
->obscured
= TRUE
;
68 /* create all of the decor windows */
70 attrib
.event_mask
= FRAME_EVENTMASK
;
71 self
->window
= createWindow(RootWindow(ob_display
, ob_screen
),
75 self
->plate
= createWindow(self
->window
, mask
, &attrib
);
78 attrib
.event_mask
= ELEMENT_EVENTMASK
;
79 self
->title
= createWindow(self
->window
, mask
, &attrib
);
82 attrib
.cursor
= ob_cursor(OB_CURSOR_NORTHWEST
);
83 self
->tlresize
= createWindow(self
->title
, mask
, &attrib
);
84 attrib
.cursor
= ob_cursor(OB_CURSOR_NORTHEAST
);
85 self
->trresize
= createWindow(self
->title
, mask
, &attrib
);
88 self
->label
= createWindow(self
->title
, mask
, &attrib
);
89 self
->max
= createWindow(self
->title
, mask
, &attrib
);
90 self
->close
= createWindow(self
->title
, mask
, &attrib
);
91 self
->desk
= createWindow(self
->title
, mask
, &attrib
);
92 self
->shade
= createWindow(self
->title
, mask
, &attrib
);
93 self
->icon
= createWindow(self
->title
, mask
, &attrib
);
94 self
->iconify
= createWindow(self
->title
, mask
, &attrib
);
95 self
->handle
= createWindow(self
->window
, mask
, &attrib
);
98 attrib
.cursor
= ob_cursor(OB_CURSOR_SOUTHWEST
);
99 self
->lgrip
= createWindow(self
->handle
, mask
, &attrib
);
100 attrib
.cursor
= ob_cursor(OB_CURSOR_SOUTHEAST
);
101 self
->rgrip
= createWindow(self
->handle
, mask
, &attrib
);
103 self
->focused
= FALSE
;
105 /* the other stuff is shown based on decor settings */
106 XMapWindow(ob_display
, self
->plate
);
107 XMapWindow(ob_display
, self
->lgrip
);
108 XMapWindow(ob_display
, self
->rgrip
);
109 XMapWindow(ob_display
, self
->label
);
111 self
->max_press
= self
->close_press
= self
->desk_press
=
112 self
->iconify_press
= self
->shade_press
= FALSE
;
113 self
->max_hover
= self
->close_hover
= self
->desk_hover
=
114 self
->iconify_hover
= self
->shade_hover
= FALSE
;
116 set_theme_statics(self
);
118 return (ObFrame
*)self
;
121 static void set_theme_statics(ObFrame
*self
)
123 /* set colors/appearance/sizes for stuff that doesn't change */
124 XSetWindowBorder(ob_display
, self
->window
,
125 RrColorPixel(ob_rr_theme
->b_color
));
126 XSetWindowBorder(ob_display
, self
->title
,
127 RrColorPixel(ob_rr_theme
->b_color
));
128 XSetWindowBorder(ob_display
, self
->handle
,
129 RrColorPixel(ob_rr_theme
->b_color
));
130 XSetWindowBorder(ob_display
, self
->rgrip
,
131 RrColorPixel(ob_rr_theme
->b_color
));
132 XSetWindowBorder(ob_display
, self
->lgrip
,
133 RrColorPixel(ob_rr_theme
->b_color
));
135 XResizeWindow(ob_display
, self
->max
,
136 ob_rr_theme
->button_size
, ob_rr_theme
->button_size
);
137 XResizeWindow(ob_display
, self
->iconify
,
138 ob_rr_theme
->button_size
, ob_rr_theme
->button_size
);
139 XResizeWindow(ob_display
, self
->icon
,
140 ob_rr_theme
->button_size
+ 2, ob_rr_theme
->button_size
+ 2);
141 XResizeWindow(ob_display
, self
->close
,
142 ob_rr_theme
->button_size
, ob_rr_theme
->button_size
);
143 XResizeWindow(ob_display
, self
->desk
,
144 ob_rr_theme
->button_size
, ob_rr_theme
->button_size
);
145 XResizeWindow(ob_display
, self
->shade
,
146 ob_rr_theme
->button_size
, ob_rr_theme
->button_size
);
147 XResizeWindow(ob_display
, self
->lgrip
,
148 ob_rr_theme
->grip_width
, ob_rr_theme
->handle_height
);
149 XResizeWindow(ob_display
, self
->rgrip
,
150 ob_rr_theme
->grip_width
, ob_rr_theme
->handle_height
);
151 XResizeWindow(ob_display
, self
->tlresize
,
152 ob_rr_theme
->grip_width
, ob_rr_theme
->handle_height
);
153 XResizeWindow(ob_display
, self
->trresize
,
154 ob_rr_theme
->grip_width
, ob_rr_theme
->handle_height
);
156 /* set up the dynamic appearances */
157 self
->a_unfocused_title
= RrAppearanceCopy(ob_rr_theme
->a_unfocused_title
);
158 self
->a_focused_title
= RrAppearanceCopy(ob_rr_theme
->a_focused_title
);
159 self
->a_unfocused_label
= RrAppearanceCopy(ob_rr_theme
->a_unfocused_label
);
160 self
->a_focused_label
= RrAppearanceCopy(ob_rr_theme
->a_focused_label
);
161 self
->a_unfocused_handle
=
162 RrAppearanceCopy(ob_rr_theme
->a_unfocused_handle
);
163 self
->a_focused_handle
= RrAppearanceCopy(ob_rr_theme
->a_focused_handle
);
164 self
->a_icon
= RrAppearanceCopy(ob_rr_theme
->a_icon
);
167 static void free_theme_statics(ObFrame
*self
)
169 RrAppearanceFree(self
->a_unfocused_title
);
170 RrAppearanceFree(self
->a_focused_title
);
171 RrAppearanceFree(self
->a_unfocused_label
);
172 RrAppearanceFree(self
->a_focused_label
);
173 RrAppearanceFree(self
->a_unfocused_handle
);
174 RrAppearanceFree(self
->a_focused_handle
);
175 RrAppearanceFree(self
->a_icon
);
178 static void frame_free(ObFrame
*self
)
180 free_theme_statics(self
);
182 XDestroyWindow(ob_display
, self
->window
);
187 void frame_show(ObFrame
*self
)
189 if (!self
->visible
) {
190 self
->visible
= TRUE
;
191 XMapWindow(ob_display
, self
->client
->window
);
192 XMapWindow(ob_display
, self
->window
);
196 void frame_hide(ObFrame
*self
)
199 self
->visible
= FALSE
;
200 self
->client
->ignore_unmaps
+= 2;
201 /* we unmap the client itself so that we can get MapRequest
202 events, and because the ICCCM tells us to! */
203 XUnmapWindow(ob_display
, self
->window
);
204 XUnmapWindow(ob_display
, self
->client
->window
);
208 void frame_adjust_theme(ObFrame
*self
)
210 free_theme_statics(self
);
211 set_theme_statics(self
);
214 void frame_adjust_shape(ObFrame
*self
)
220 if (!self
->client
->shaped
) {
221 /* clear the shape on the frame window */
222 XShapeCombineMask(ob_display
, self
->window
, ShapeBounding
,
223 self
->innersize
.left
,
227 /* make the frame's shape match the clients */
228 XShapeCombineShape(ob_display
, self
->window
, ShapeBounding
,
229 self
->innersize
.left
,
231 self
->client
->window
,
232 ShapeBounding
, ShapeSet
);
235 if (self
->decorations
& OB_FRAME_DECOR_TITLEBAR
) {
236 xrect
[0].x
= -ob_rr_theme
->bwidth
;
237 xrect
[0].y
= -ob_rr_theme
->bwidth
;
238 xrect
[0].width
= self
->width
+ self
->rbwidth
* 2;
239 xrect
[0].height
= ob_rr_theme
->title_height
+
244 if (self
->decorations
& OB_FRAME_DECOR_HANDLE
) {
245 xrect
[1].x
= -ob_rr_theme
->bwidth
;
246 xrect
[1].y
= FRAME_HANDLE_Y(self
);
247 xrect
[1].width
= self
->width
+ self
->rbwidth
* 2;
248 xrect
[1].height
= ob_rr_theme
->handle_height
+
253 XShapeCombineRectangles(ob_display
, self
->window
,
254 ShapeBounding
, 0, 0, xrect
, num
,
255 ShapeUnion
, Unsorted
);
260 void frame_adjust_area(ObFrame
*self
, gboolean moved
,
261 gboolean resized
, gboolean fake
)
265 oldsize
= self
->size
;
268 self
->decorations
= self
->client
->decorations
;
269 self
->max_horz
= self
->client
->max_horz
;
271 if (self
->decorations
& OB_FRAME_DECOR_BORDER
) {
272 self
->bwidth
= ob_rr_theme
->bwidth
;
273 self
->cbwidth_x
= self
->cbwidth_y
= ob_rr_theme
->cbwidth
;
275 self
->bwidth
= self
->cbwidth_x
= self
->cbwidth_y
= 0;
277 self
->rbwidth
= self
->bwidth
;
280 self
->bwidth
= self
->cbwidth_x
= 0;
282 STRUT_SET(self
->innersize
,
287 self
->width
= self
->client
->area
.width
+ self
->cbwidth_x
* 2 -
288 (self
->max_horz
? self
->rbwidth
* 2 : 0);
289 self
->width
= MAX(self
->width
, 1); /* no lower than 1 */
291 /* set border widths */
293 XSetWindowBorderWidth(ob_display
, self
->window
, self
->bwidth
);
294 XSetWindowBorderWidth(ob_display
, self
->title
, self
->rbwidth
);
295 XSetWindowBorderWidth(ob_display
, self
->handle
, self
->rbwidth
);
296 XSetWindowBorderWidth(ob_display
, self
->lgrip
, self
->rbwidth
);
297 XSetWindowBorderWidth(ob_display
, self
->rgrip
, self
->rbwidth
);
300 if (self
->decorations
& OB_FRAME_DECOR_TITLEBAR
)
301 self
->innersize
.top
+= ob_rr_theme
->title_height
+ self
->rbwidth
+
302 (self
->rbwidth
- self
->bwidth
);
303 if (self
->decorations
& OB_FRAME_DECOR_HANDLE
&&
304 ob_rr_theme
->show_handle
)
305 self
->innersize
.bottom
+= ob_rr_theme
->handle_height
+
306 self
->rbwidth
+ (self
->rbwidth
- self
->bwidth
);
308 /* they all default off, they're turned on in layout_title */
312 self
->iconify_x
= -1;
317 /* position/size and map/unmap all the windows */
320 if (self
->decorations
& OB_FRAME_DECOR_TITLEBAR
) {
321 XMoveResizeWindow(ob_display
, self
->title
,
322 -self
->bwidth
, -self
->bwidth
,
323 self
->width
, ob_rr_theme
->title_height
);
324 XMapWindow(ob_display
, self
->title
);
326 if (self
->decorations
& OB_FRAME_DECOR_GRIPS
) {
327 XMoveWindow(ob_display
, self
->tlresize
, 0, 0);
328 XMoveWindow(ob_display
, self
->trresize
,
329 self
->width
- ob_rr_theme
->grip_width
, 0);
330 XMapWindow(ob_display
, self
->tlresize
);
331 XMapWindow(ob_display
, self
->trresize
);
333 XUnmapWindow(ob_display
, self
->tlresize
);
334 XUnmapWindow(ob_display
, self
->trresize
);
337 XUnmapWindow(ob_display
, self
->title
);
340 if (self
->decorations
& OB_FRAME_DECOR_TITLEBAR
)
341 /* layout the title bar elements */
345 if (self
->decorations
& OB_FRAME_DECOR_HANDLE
&&
346 ob_rr_theme
->show_handle
)
348 XMoveResizeWindow(ob_display
, self
->handle
,
349 -self
->bwidth
, FRAME_HANDLE_Y(self
),
350 self
->width
, ob_rr_theme
->handle_height
);
351 XMapWindow(ob_display
, self
->handle
);
353 if (self
->decorations
& OB_FRAME_DECOR_GRIPS
) {
354 XMoveWindow(ob_display
, self
->lgrip
,
355 -self
->rbwidth
, -self
->rbwidth
);
356 XMoveWindow(ob_display
, self
->rgrip
,
357 -self
->rbwidth
+ self
->width
-
358 ob_rr_theme
->grip_width
, -self
->rbwidth
);
359 XMapWindow(ob_display
, self
->lgrip
);
360 XMapWindow(ob_display
, self
->rgrip
);
362 XUnmapWindow(ob_display
, self
->lgrip
);
363 XUnmapWindow(ob_display
, self
->rgrip
);
366 /* XXX make a subwindow with these dimentions?
367 ob_rr_theme->grip_width + self->bwidth, 0,
368 self->width - (ob_rr_theme->grip_width + self->bwidth) * 2,
369 ob_rr_theme->handle_height);
372 XUnmapWindow(ob_display
, self
->handle
);
374 /* move and resize the plate */
375 XMoveResizeWindow(ob_display
, self
->plate
,
376 self
->innersize
.left
- self
->cbwidth_x
,
377 self
->innersize
.top
- self
->cbwidth_y
,
378 self
->client
->area
.width
+ self
->cbwidth_x
* 2,
379 self
->client
->area
.height
+ self
->cbwidth_y
* 2);
380 /* when the client has StaticGravity, it likes to move around. */
381 XMoveWindow(ob_display
, self
->client
->window
,
382 self
->cbwidth_x
, self
->cbwidth_y
);
385 STRUT_SET(self
->size
,
386 self
->innersize
.left
+ self
->bwidth
,
387 self
->innersize
.top
+ self
->bwidth
,
388 self
->innersize
.right
+ self
->bwidth
,
389 self
->innersize
.bottom
+ self
->bwidth
);
392 /* shading can change without being moved or resized */
393 RECT_SET_SIZE(self
->area
,
394 self
->client
->area
.width
+
395 self
->size
.left
+ self
->size
.right
,
396 (self
->client
->shaded
?
397 ob_rr_theme
->title_height
+ self
->rbwidth
* 2:
398 self
->client
->area
.height
+
399 self
->size
.top
+ self
->size
.bottom
));
402 /* find the new coordinates, done after setting the frame.size, for
403 frame_client_gravity. */
404 self
->area
.x
= self
->client
->area
.x
;
405 self
->area
.y
= self
->client
->area
.y
;
406 frame_client_gravity(self
, &self
->area
.x
, &self
->area
.y
);
410 /* move and resize the top level frame.
411 shading can change without being moved or resized */
412 XMoveResizeWindow(ob_display
, self
->window
,
413 self
->area
.x
, self
->area
.y
,
414 self
->area
.width
- self
->bwidth
* 2,
415 self
->area
.height
- self
->bwidth
* 2);
418 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();
440 void frame_adjust_state(ObFrame
*self
)
442 framerender_frame(self
);
445 void frame_adjust_focus(ObFrame
*self
, gboolean hilite
)
447 self
->focused
= hilite
;
448 framerender_frame(self
);
451 void frame_adjust_title(ObFrame
*self
)
453 framerender_frame(self
);
456 void frame_adjust_icon(ObFrame
*self
)
458 framerender_frame(self
);
461 void frame_grab_client(ObFrame
*self
, ObClient
*client
)
463 self
->client
= client
;
465 /* reparent the client to the frame */
466 XReparentWindow(ob_display
, client
->window
, self
->plate
, 0, 0);
468 When reparenting the client window, it is usually not mapped yet, since
469 this occurs from a MapRequest. However, in the case where Openbox is
470 starting up, the window is already mapped, so we'll see unmap events for
471 it. There are 2 unmap events generated that we see, one with the 'event'
472 member set the root window, and one set to the client, but both get
473 handled and need to be ignored.
475 if (ob_state() == OB_STATE_STARTING
)
476 client
->ignore_unmaps
+= 2;
478 /* select the event mask on the client's parent (to receive config/map
479 req's) the ButtonPress is to catch clicks on the client border */
480 XSelectInput(ob_display
, self
->plate
, PLATE_EVENTMASK
);
482 /* map the client so it maps when the frame does */
483 XMapWindow(ob_display
, client
->window
);
485 frame_adjust_area(self
, TRUE
, TRUE
, FALSE
);
487 /* set all the windows for the frame in the window_map */
488 g_hash_table_insert(window_map
, &self
->window
, client
);
489 g_hash_table_insert(window_map
, &self
->plate
, client
);
490 g_hash_table_insert(window_map
, &self
->title
, client
);
491 g_hash_table_insert(window_map
, &self
->label
, client
);
492 g_hash_table_insert(window_map
, &self
->max
, client
);
493 g_hash_table_insert(window_map
, &self
->close
, client
);
494 g_hash_table_insert(window_map
, &self
->desk
, client
);
495 g_hash_table_insert(window_map
, &self
->shade
, client
);
496 g_hash_table_insert(window_map
, &self
->icon
, client
);
497 g_hash_table_insert(window_map
, &self
->iconify
, client
);
498 g_hash_table_insert(window_map
, &self
->handle
, client
);
499 g_hash_table_insert(window_map
, &self
->lgrip
, client
);
500 g_hash_table_insert(window_map
, &self
->rgrip
, client
);
501 g_hash_table_insert(window_map
, &self
->tlresize
, client
);
502 g_hash_table_insert(window_map
, &self
->trresize
, client
);
505 void frame_release_client(ObFrame
*self
, ObClient
*client
)
509 g_assert(self
->client
== client
);
511 /* check if the app has already reparented its window away */
512 if (XCheckTypedWindowEvent(ob_display
, client
->window
,
513 ReparentNotify
, &ev
)) {
514 XPutBackEvent(ob_display
, &ev
);
516 /* re-map the window since the unmanaging process unmaps it */
518 /* XXX ... um no it doesnt it unmaps its parent, the window itself
519 retains its mapped state, no?! XXX
520 XMapWindow(ob_display, client->window); */
522 /* according to the ICCCM - if the client doesn't reparent itself,
523 then we will reparent the window to root for them */
524 XReparentWindow(ob_display
, client
->window
,
525 RootWindow(ob_display
, ob_screen
),
530 /* remove all the windows for the frame from the window_map */
531 g_hash_table_remove(window_map
, &self
->window
);
532 g_hash_table_remove(window_map
, &self
->plate
);
533 g_hash_table_remove(window_map
, &self
->title
);
534 g_hash_table_remove(window_map
, &self
->label
);
535 g_hash_table_remove(window_map
, &self
->max
);
536 g_hash_table_remove(window_map
, &self
->close
);
537 g_hash_table_remove(window_map
, &self
->desk
);
538 g_hash_table_remove(window_map
, &self
->shade
);
539 g_hash_table_remove(window_map
, &self
->icon
);
540 g_hash_table_remove(window_map
, &self
->iconify
);
541 g_hash_table_remove(window_map
, &self
->handle
);
542 g_hash_table_remove(window_map
, &self
->lgrip
);
543 g_hash_table_remove(window_map
, &self
->rgrip
);
544 g_hash_table_remove(window_map
, &self
->tlresize
);
545 g_hash_table_remove(window_map
, &self
->trresize
);
547 ob_main_loop_timeout_remove_data(ob_main_loop
, flash_timeout
, self
);
552 static void layout_title(ObFrame
*self
)
556 gboolean n
, d
, i
, l
, m
, c
, s
;
558 n
= d
= i
= l
= m
= c
= s
= FALSE
;
560 /* figure out whats being shown, and the width of the label */
561 self
->label_width
= self
->width
- (ob_rr_theme
->padding
+ 1) * 2;
562 for (lc
= config_title_layout
; *lc
!= '\0'; ++lc
) {
565 if (n
) { *lc
= ' '; break; } /* rm duplicates */
567 self
->label_width
-= (ob_rr_theme
->button_size
+ 2 +
568 ob_rr_theme
->padding
+ 1);
571 if (d
) { *lc
= ' '; break; } /* rm duplicates */
573 self
->label_width
-= (ob_rr_theme
->button_size
+
574 ob_rr_theme
->padding
+ 1);
577 if (s
) { *lc
= ' '; break; } /* rm duplicates */
579 self
->label_width
-= (ob_rr_theme
->button_size
+
580 ob_rr_theme
->padding
+ 1);
583 if (i
) { *lc
= ' '; break; } /* rm duplicates */
585 self
->label_width
-= (ob_rr_theme
->button_size
+
586 ob_rr_theme
->padding
+ 1);
589 if (l
) { *lc
= ' '; break; } /* rm duplicates */
593 if (m
) { *lc
= ' '; break; } /* rm duplicates */
595 self
->label_width
-= (ob_rr_theme
->button_size
+
596 ob_rr_theme
->padding
+ 1);
599 if (c
) { *lc
= ' '; break; } /* rm duplicates */
601 self
->label_width
-= (ob_rr_theme
->button_size
+
602 ob_rr_theme
->padding
+ 1);
606 if (self
->label_width
< 1) self
->label_width
= 1;
608 XResizeWindow(ob_display
, self
->label
, self
->label_width
,
609 ob_rr_theme
->label_height
);
611 if (!n
) XUnmapWindow(ob_display
, self
->icon
);
612 if (!d
) XUnmapWindow(ob_display
, self
->desk
);
613 if (!s
) XUnmapWindow(ob_display
, self
->shade
);
614 if (!i
) XUnmapWindow(ob_display
, self
->iconify
);
615 if (!l
) XUnmapWindow(ob_display
, self
->label
);
616 if (!m
) XUnmapWindow(ob_display
, self
->max
);
617 if (!c
) XUnmapWindow(ob_display
, self
->close
);
619 x
= ob_rr_theme
->padding
+ 1;
620 for (lc
= config_title_layout
; *lc
!= '\0'; ++lc
) {
625 XMapWindow(ob_display
, self
->icon
);
626 XMoveWindow(ob_display
, self
->icon
, x
, ob_rr_theme
->padding
);
627 x
+= ob_rr_theme
->button_size
+ 2 + ob_rr_theme
->padding
+ 1;
632 XMapWindow(ob_display
, self
->desk
);
633 XMoveWindow(ob_display
, self
->desk
, x
, ob_rr_theme
->padding
+ 1);
634 x
+= ob_rr_theme
->button_size
+ ob_rr_theme
->padding
+ 1;
639 XMapWindow(ob_display
, self
->shade
);
640 XMoveWindow(ob_display
, self
->shade
, x
, ob_rr_theme
->padding
+ 1);
641 x
+= ob_rr_theme
->button_size
+ ob_rr_theme
->padding
+ 1;
646 XMapWindow(ob_display
, self
->iconify
);
647 XMoveWindow(ob_display
,self
->iconify
, x
, ob_rr_theme
->padding
+ 1);
648 x
+= ob_rr_theme
->button_size
+ ob_rr_theme
->padding
+ 1;
653 XMapWindow(ob_display
, self
->label
);
654 XMoveWindow(ob_display
, self
->label
, x
, ob_rr_theme
->padding
);
655 x
+= self
->label_width
+ ob_rr_theme
->padding
+ 1;
660 XMapWindow(ob_display
, self
->max
);
661 XMoveWindow(ob_display
, self
->max
, x
, ob_rr_theme
->padding
+ 1);
662 x
+= ob_rr_theme
->button_size
+ ob_rr_theme
->padding
+ 1;
667 XMapWindow(ob_display
, self
->close
);
668 XMoveWindow(ob_display
, self
->close
, x
, ob_rr_theme
->padding
+ 1);
669 x
+= ob_rr_theme
->button_size
+ ob_rr_theme
->padding
+ 1;
675 ObFrameContext
frame_context_from_string(const gchar
*name
)
677 if (!g_ascii_strcasecmp("Desktop", name
))
678 return OB_FRAME_CONTEXT_DESKTOP
;
679 else if (!g_ascii_strcasecmp("Client", name
))
680 return OB_FRAME_CONTEXT_CLIENT
;
681 else if (!g_ascii_strcasecmp("Titlebar", name
))
682 return OB_FRAME_CONTEXT_TITLEBAR
;
683 else if (!g_ascii_strcasecmp("Handle", name
))
684 return OB_FRAME_CONTEXT_HANDLE
;
685 else if (!g_ascii_strcasecmp("Frame", name
))
686 return OB_FRAME_CONTEXT_FRAME
;
687 else if (!g_ascii_strcasecmp("TLCorner", name
))
688 return OB_FRAME_CONTEXT_TLCORNER
;
689 else if (!g_ascii_strcasecmp("TRCorner", name
))
690 return OB_FRAME_CONTEXT_TRCORNER
;
691 else if (!g_ascii_strcasecmp("BLCorner", name
))
692 return OB_FRAME_CONTEXT_BLCORNER
;
693 else if (!g_ascii_strcasecmp("BRCorner", name
))
694 return OB_FRAME_CONTEXT_BRCORNER
;
695 else if (!g_ascii_strcasecmp("Maximize", name
))
696 return OB_FRAME_CONTEXT_MAXIMIZE
;
697 else if (!g_ascii_strcasecmp("AllDesktops", name
))
698 return OB_FRAME_CONTEXT_ALLDESKTOPS
;
699 else if (!g_ascii_strcasecmp("Shade", name
))
700 return OB_FRAME_CONTEXT_SHADE
;
701 else if (!g_ascii_strcasecmp("Iconify", name
))
702 return OB_FRAME_CONTEXT_ICONIFY
;
703 else if (!g_ascii_strcasecmp("Icon", name
))
704 return OB_FRAME_CONTEXT_ICON
;
705 else if (!g_ascii_strcasecmp("Close", name
))
706 return OB_FRAME_CONTEXT_CLOSE
;
707 else if (!g_ascii_strcasecmp("MoveResize", name
))
708 return OB_FRAME_CONTEXT_MOVE_RESIZE
;
709 return OB_FRAME_CONTEXT_NONE
;
712 ObFrameContext
frame_context(ObClient
*client
, Window win
)
716 if (moveresize_in_progress
)
717 return OB_FRAME_CONTEXT_MOVE_RESIZE
;
719 if (win
== RootWindow(ob_display
, ob_screen
))
720 return OB_FRAME_CONTEXT_DESKTOP
;
721 if (client
== NULL
) return OB_FRAME_CONTEXT_NONE
;
722 if (win
== client
->window
) {
723 /* conceptually, this is the desktop, as far as users are
725 if (client
->type
== OB_CLIENT_TYPE_DESKTOP
)
726 return OB_FRAME_CONTEXT_DESKTOP
;
727 return OB_FRAME_CONTEXT_CLIENT
;
730 self
= client
->frame
;
731 if (win
== self
->plate
) {
732 /* conceptually, this is the desktop, as far as users are
734 if (client
->type
== OB_CLIENT_TYPE_DESKTOP
)
735 return OB_FRAME_CONTEXT_DESKTOP
;
736 return OB_FRAME_CONTEXT_CLIENT
;
739 if (win
== self
->window
) return OB_FRAME_CONTEXT_FRAME
;
740 if (win
== self
->title
) return OB_FRAME_CONTEXT_TITLEBAR
;
741 if (win
== self
->label
) return OB_FRAME_CONTEXT_TITLEBAR
;
742 if (win
== self
->handle
) return OB_FRAME_CONTEXT_HANDLE
;
743 if (win
== self
->lgrip
) return OB_FRAME_CONTEXT_BLCORNER
;
744 if (win
== self
->rgrip
) return OB_FRAME_CONTEXT_BRCORNER
;
745 if (win
== self
->tlresize
) return OB_FRAME_CONTEXT_TLCORNER
;
746 if (win
== self
->trresize
) return OB_FRAME_CONTEXT_TRCORNER
;
747 if (win
== self
->max
) return OB_FRAME_CONTEXT_MAXIMIZE
;
748 if (win
== self
->iconify
) return OB_FRAME_CONTEXT_ICONIFY
;
749 if (win
== self
->close
) return OB_FRAME_CONTEXT_CLOSE
;
750 if (win
== self
->icon
) return OB_FRAME_CONTEXT_ICON
;
751 if (win
== self
->desk
) return OB_FRAME_CONTEXT_ALLDESKTOPS
;
752 if (win
== self
->shade
) return OB_FRAME_CONTEXT_SHADE
;
754 return OB_FRAME_CONTEXT_NONE
;
757 void frame_client_gravity(ObFrame
*self
, gint
*x
, gint
*y
)
760 switch (self
->client
->gravity
) {
762 case NorthWestGravity
:
763 case SouthWestGravity
:
770 *x
-= (self
->size
.left
+ self
->size
.right
) / 2;
773 case NorthEastGravity
:
774 case SouthEastGravity
:
776 *x
-= self
->size
.left
+ self
->size
.right
;
781 *x
-= self
->size
.left
;
786 switch (self
->client
->gravity
) {
788 case NorthWestGravity
:
789 case NorthEastGravity
:
796 *y
-= (self
->size
.top
+ self
->size
.bottom
) / 2;
799 case SouthWestGravity
:
800 case SouthEastGravity
:
802 *y
-= self
->size
.top
+ self
->size
.bottom
;
807 *y
-= self
->size
.top
;
812 void frame_frame_gravity(ObFrame
*self
, gint
*x
, gint
*y
)
815 switch (self
->client
->gravity
) {
817 case NorthWestGravity
:
819 case SouthWestGravity
:
824 *x
+= (self
->size
.left
+ self
->size
.right
) / 2;
826 case NorthEastGravity
:
828 case SouthEastGravity
:
829 *x
+= self
->size
.left
+ self
->size
.right
;
833 *x
+= self
->size
.left
;
838 switch (self
->client
->gravity
) {
840 case NorthWestGravity
:
842 case NorthEastGravity
:
847 *y
+= (self
->size
.top
+ self
->size
.bottom
) / 2;
849 case SouthWestGravity
:
851 case SouthEastGravity
:
852 *y
+= self
->size
.top
+ self
->size
.bottom
;
856 *y
+= self
->size
.top
;
861 static void flash_done(gpointer data
)
863 ObFrame
*self
= data
;
865 if (self
->focused
!= self
->flash_on
)
866 frame_adjust_focus(self
, self
->focused
);
869 static gboolean
flash_timeout(gpointer data
)
871 ObFrame
*self
= data
;
874 g_get_current_time(&now
);
875 if (now
.tv_sec
> self
->flash_end
.tv_sec
||
876 (now
.tv_sec
== self
->flash_end
.tv_sec
&&
877 now
.tv_usec
>= self
->flash_end
.tv_usec
))
878 self
->flashing
= FALSE
;
881 return FALSE
; /* we are done */
883 self
->flash_on
= !self
->flash_on
;
884 if (!self
->focused
) {
885 frame_adjust_focus(self
, self
->flash_on
);
886 self
->focused
= FALSE
;
889 return TRUE
; /* go again */
892 void frame_flash_start(ObFrame
*self
)
894 self
->flash_on
= self
->focused
;
897 ob_main_loop_timeout_add(ob_main_loop
,
898 G_USEC_PER_SEC
* 0.6,
902 g_get_current_time(&self
->flash_end
);
903 g_time_val_add(&self
->flash_end
, G_USEC_PER_SEC
* 5);
905 self
->flashing
= TRUE
;
908 void frame_flash_stop(ObFrame
*self
)
910 self
->flashing
= FALSE
;