4 #include "extensions.h"
6 #include "framerender.h"
8 #include "render/theme.h"
10 #define PLATE_EVENTMASK (SubstructureRedirectMask | ButtonPressMask)
11 #define FRAME_EVENTMASK (EnterWindowMask | LeaveWindowMask | \
12 ButtonPressMask | ButtonReleaseMask | \
14 #define ELEMENT_EVENTMASK (ButtonPressMask | ButtonReleaseMask | \
15 ButtonMotionMask | ExposureMask | \
16 EnterWindowMask | LeaveWindowMask)
18 #define FRAME_HANDLE_Y(f) (f->innersize.top + f->client->area.height + \
21 static void layout_title(ObFrame
*self
);
22 static void flash_done(gpointer data
);
23 static gboolean
flash_timeout(gpointer data
);
25 static Window
createWindow(Window parent
, unsigned long mask
,
26 XSetWindowAttributes
*attrib
)
28 return XCreateWindow(ob_display
, parent
, 0, 0, 1, 1, 0,
29 RrDepth(ob_rr_inst
), InputOutput
,
30 RrVisual(ob_rr_inst
), mask
, attrib
);
36 XSetWindowAttributes attrib
;
40 self
= g_new(ObFrame
, 1);
42 self
->visible
= FALSE
;
43 self
->obscured
= TRUE
;
44 self
->decorations
= 0;
45 self
->flashing
= FALSE
;
47 /* create all of the decor windows */
48 mask
= CWOverrideRedirect
| CWEventMask
;
49 attrib
.event_mask
= FRAME_EVENTMASK
;
50 attrib
.override_redirect
= TRUE
;
51 self
->window
= createWindow(RootWindow(ob_display
, ob_screen
),
55 self
->plate
= createWindow(self
->window
, mask
, &attrib
);
58 attrib
.event_mask
= ELEMENT_EVENTMASK
;
59 self
->title
= createWindow(self
->window
, mask
, &attrib
);
62 attrib
.cursor
= ob_cursor(OB_CURSOR_NORTHWEST
);
63 self
->tlresize
= createWindow(self
->title
, mask
, &attrib
);
64 attrib
.cursor
= ob_cursor(OB_CURSOR_NORTHEAST
);
65 self
->trresize
= createWindow(self
->title
, mask
, &attrib
);
68 self
->label
= createWindow(self
->title
, mask
, &attrib
);
69 self
->max
= createWindow(self
->title
, mask
, &attrib
);
70 self
->close
= createWindow(self
->title
, mask
, &attrib
);
71 self
->desk
= createWindow(self
->title
, mask
, &attrib
);
72 self
->shade
= createWindow(self
->title
, mask
, &attrib
);
73 self
->icon
= createWindow(self
->title
, mask
, &attrib
);
74 self
->iconify
= createWindow(self
->title
, mask
, &attrib
);
75 self
->handle
= createWindow(self
->window
, mask
, &attrib
);
78 attrib
.cursor
= ob_cursor(OB_CURSOR_SOUTHWEST
);
79 self
->lgrip
= createWindow(self
->handle
, mask
, &attrib
);
80 attrib
.cursor
= ob_cursor(OB_CURSOR_SOUTHEAST
);
81 self
->rgrip
= createWindow(self
->handle
, mask
, &attrib
);
83 self
->focused
= FALSE
;
85 /* the other stuff is shown based on decor settings */
86 XMapWindow(ob_display
, self
->plate
);
87 XMapWindow(ob_display
, self
->lgrip
);
88 XMapWindow(ob_display
, self
->rgrip
);
89 XMapWindow(ob_display
, self
->label
);
91 /* set colors/appearance/sizes for stuff that doesn't change */
92 XSetWindowBorder(ob_display
, self
->window
, ob_rr_theme
->b_color
->pixel
);
93 XSetWindowBorder(ob_display
, self
->title
, ob_rr_theme
->b_color
->pixel
);
94 XSetWindowBorder(ob_display
, self
->handle
, ob_rr_theme
->b_color
->pixel
);
95 XSetWindowBorder(ob_display
, self
->rgrip
, ob_rr_theme
->b_color
->pixel
);
96 XSetWindowBorder(ob_display
, self
->lgrip
, ob_rr_theme
->b_color
->pixel
);
98 XResizeWindow(ob_display
, self
->max
,
99 ob_rr_theme
->button_size
, ob_rr_theme
->button_size
);
100 XResizeWindow(ob_display
, self
->iconify
,
101 ob_rr_theme
->button_size
, ob_rr_theme
->button_size
);
102 XResizeWindow(ob_display
, self
->icon
,
103 ob_rr_theme
->button_size
+ 2, ob_rr_theme
->button_size
+ 2);
104 XResizeWindow(ob_display
, self
->close
,
105 ob_rr_theme
->button_size
, ob_rr_theme
->button_size
);
106 XResizeWindow(ob_display
, self
->desk
,
107 ob_rr_theme
->button_size
, ob_rr_theme
->button_size
);
108 XResizeWindow(ob_display
, self
->shade
,
109 ob_rr_theme
->button_size
, ob_rr_theme
->button_size
);
110 XResizeWindow(ob_display
, self
->lgrip
,
111 ob_rr_theme
->grip_width
, ob_rr_theme
->handle_height
);
112 XResizeWindow(ob_display
, self
->rgrip
,
113 ob_rr_theme
->grip_width
, ob_rr_theme
->handle_height
);
114 XResizeWindow(ob_display
, self
->tlresize
,
115 ob_rr_theme
->grip_width
, ob_rr_theme
->handle_height
);
116 XResizeWindow(ob_display
, self
->trresize
,
117 ob_rr_theme
->grip_width
, ob_rr_theme
->handle_height
);
119 /* set up the dynamic appearances */
120 self
->a_unfocused_title
= RrAppearanceCopy(ob_rr_theme
->a_unfocused_title
);
121 self
->a_focused_title
= RrAppearanceCopy(ob_rr_theme
->a_focused_title
);
122 self
->a_unfocused_label
= RrAppearanceCopy(ob_rr_theme
->a_unfocused_label
);
123 self
->a_focused_label
= RrAppearanceCopy(ob_rr_theme
->a_focused_label
);
124 self
->a_unfocused_handle
=
125 RrAppearanceCopy(ob_rr_theme
->a_unfocused_handle
);
126 self
->a_focused_handle
= RrAppearanceCopy(ob_rr_theme
->a_focused_handle
);
127 self
->a_icon
= RrAppearanceCopy(ob_rr_theme
->a_icon
);
129 self
->max_press
= self
->close_press
= self
->desk_press
=
130 self
->iconify_press
= self
->shade_press
= FALSE
;
131 self
->max_hover
= self
->close_hover
= self
->desk_hover
=
132 self
->iconify_hover
= self
->shade_hover
= FALSE
;
134 return (ObFrame
*)self
;
137 static void frame_free(ObFrame
*self
)
139 RrAppearanceFree(self
->a_unfocused_title
);
140 RrAppearanceFree(self
->a_focused_title
);
141 RrAppearanceFree(self
->a_unfocused_label
);
142 RrAppearanceFree(self
->a_focused_label
);
143 RrAppearanceFree(self
->a_unfocused_handle
);
144 RrAppearanceFree(self
->a_focused_handle
);
145 RrAppearanceFree(self
->a_icon
);
147 XDestroyWindow(ob_display
, self
->window
);
152 void frame_show(ObFrame
*self
)
154 if (!self
->visible
) {
155 self
->visible
= TRUE
;
156 XMapWindow(ob_display
, self
->window
);
160 void frame_hide(ObFrame
*self
)
163 self
->visible
= FALSE
;
164 self
->client
->ignore_unmaps
++;
165 XUnmapWindow(ob_display
, self
->window
);
169 void frame_adjust_shape(ObFrame
*self
)
175 if (!self
->client
->shaped
) {
176 /* clear the shape on the frame window */
177 XShapeCombineMask(ob_display
, self
->window
, ShapeBounding
,
178 self
->innersize
.left
,
182 /* make the frame's shape match the clients */
183 XShapeCombineShape(ob_display
, self
->window
, ShapeBounding
,
184 self
->innersize
.left
,
186 self
->client
->window
,
187 ShapeBounding
, ShapeSet
);
190 if (self
->decorations
& OB_FRAME_DECOR_TITLEBAR
) {
191 xrect
[0].x
= -ob_rr_theme
->bwidth
;
192 xrect
[0].y
= -ob_rr_theme
->bwidth
;
193 xrect
[0].width
= self
->width
+ self
->rbwidth
* 2;
194 xrect
[0].height
= ob_rr_theme
->title_height
+
199 if (self
->decorations
& OB_FRAME_DECOR_HANDLE
) {
200 xrect
[1].x
= -ob_rr_theme
->bwidth
;
201 xrect
[1].y
= FRAME_HANDLE_Y(self
);
202 xrect
[1].width
= self
->width
+ self
->rbwidth
* 2;
203 xrect
[1].height
= ob_rr_theme
->handle_height
+
208 XShapeCombineRectangles(ob_display
, self
->window
,
209 ShapeBounding
, 0, 0, xrect
, num
,
210 ShapeUnion
, Unsorted
);
215 void frame_adjust_area(ObFrame
*self
, gboolean moved
,
216 gboolean resized
, gboolean fake
)
219 self
->decorations
= self
->client
->decorations
;
220 self
->max_horz
= self
->client
->max_horz
;
222 if (self
->decorations
& OB_FRAME_DECOR_BORDER
) {
223 self
->bwidth
= ob_rr_theme
->bwidth
;
224 self
->cbwidth_x
= self
->cbwidth_y
= ob_rr_theme
->cbwidth
;
226 self
->bwidth
= self
->cbwidth_x
= self
->cbwidth_y
= 0;
228 self
->rbwidth
= self
->bwidth
;
231 self
->bwidth
= self
->cbwidth_x
= 0;
233 STRUT_SET(self
->innersize
,
238 self
->width
= self
->client
->area
.width
+ self
->cbwidth_x
* 2 -
239 (self
->max_horz
? self
->rbwidth
* 2 : 0);
240 self
->width
= MAX(self
->width
, 1); /* no lower than 1 */
242 /* set border widths */
244 XSetWindowBorderWidth(ob_display
, self
->window
, self
->bwidth
);
245 XSetWindowBorderWidth(ob_display
, self
->title
, self
->rbwidth
);
246 XSetWindowBorderWidth(ob_display
, self
->handle
, self
->rbwidth
);
247 XSetWindowBorderWidth(ob_display
, self
->lgrip
, self
->rbwidth
);
248 XSetWindowBorderWidth(ob_display
, self
->rgrip
, self
->rbwidth
);
251 if (self
->decorations
& OB_FRAME_DECOR_TITLEBAR
)
252 self
->innersize
.top
+= ob_rr_theme
->title_height
+ self
->rbwidth
+
253 (self
->rbwidth
- self
->bwidth
);
254 if (self
->decorations
& OB_FRAME_DECOR_HANDLE
)
255 self
->innersize
.bottom
+= ob_rr_theme
->handle_height
+
256 self
->rbwidth
+ (self
->rbwidth
- self
->bwidth
);
258 /* they all default off, they're turned on in layout_title */
262 self
->iconify_x
= -1;
267 /* position/size and map/unmap all the windows */
270 if (self
->decorations
& OB_FRAME_DECOR_TITLEBAR
) {
271 XMoveResizeWindow(ob_display
, self
->title
,
272 -self
->bwidth
, -self
->bwidth
,
273 self
->width
, ob_rr_theme
->title_height
);
274 XMapWindow(ob_display
, self
->title
);
276 if (self
->decorations
& OB_FRAME_DECOR_GRIPS
) {
277 XMoveWindow(ob_display
, self
->tlresize
, 0, 0);
278 XMoveWindow(ob_display
, self
->trresize
,
279 self
->width
- ob_rr_theme
->grip_width
, 0);
280 XMapWindow(ob_display
, self
->tlresize
);
281 XMapWindow(ob_display
, self
->trresize
);
283 XUnmapWindow(ob_display
, self
->tlresize
);
284 XUnmapWindow(ob_display
, self
->trresize
);
287 XUnmapWindow(ob_display
, self
->title
);
290 if (self
->decorations
& OB_FRAME_DECOR_TITLEBAR
)
291 /* layout the title bar elements */
295 if (self
->decorations
& OB_FRAME_DECOR_HANDLE
) {
296 XMoveResizeWindow(ob_display
, self
->handle
,
297 -self
->bwidth
, FRAME_HANDLE_Y(self
),
298 self
->width
, ob_rr_theme
->handle_height
);
299 XMapWindow(ob_display
, self
->handle
);
301 if (self
->decorations
& OB_FRAME_DECOR_GRIPS
) {
302 XMoveWindow(ob_display
, self
->lgrip
,
303 -self
->rbwidth
, -self
->rbwidth
);
304 XMoveWindow(ob_display
, self
->rgrip
,
305 -self
->rbwidth
+ self
->width
-
306 ob_rr_theme
->grip_width
, -self
->rbwidth
);
307 XMapWindow(ob_display
, self
->lgrip
);
308 XMapWindow(ob_display
, self
->rgrip
);
310 XUnmapWindow(ob_display
, self
->lgrip
);
311 XUnmapWindow(ob_display
, self
->rgrip
);
314 /* XXX make a subwindow with these dimentions?
315 ob_rr_theme->grip_width + self->bwidth, 0,
316 self->width - (ob_rr_theme->grip_width + self->bwidth) * 2,
317 ob_rr_theme->handle_height);
320 XUnmapWindow(ob_display
, self
->handle
);
322 /* move and resize the plate */
323 XMoveResizeWindow(ob_display
, self
->plate
,
324 self
->innersize
.left
- self
->cbwidth_x
,
325 self
->innersize
.top
- self
->cbwidth_y
,
326 self
->client
->area
.width
+ self
->cbwidth_x
* 2,
327 self
->client
->area
.height
+ self
->cbwidth_y
* 2);
328 /* when the client has StaticGravity, it likes to move around. */
329 XMoveWindow(ob_display
, self
->client
->window
,
330 self
->cbwidth_x
, self
->cbwidth_y
);
333 STRUT_SET(self
->size
,
334 self
->innersize
.left
+ self
->bwidth
,
335 self
->innersize
.top
+ self
->bwidth
,
336 self
->innersize
.right
+ self
->bwidth
,
337 self
->innersize
.bottom
+ self
->bwidth
);
340 /* shading can change without being moved or resized */
341 RECT_SET_SIZE(self
->area
,
342 self
->client
->area
.width
+
343 self
->size
.left
+ self
->size
.right
,
344 (self
->client
->shaded
?
345 ob_rr_theme
->title_height
+ self
->rbwidth
* 2:
346 self
->client
->area
.height
+
347 self
->size
.top
+ self
->size
.bottom
));
350 /* find the new coordinates, done after setting the frame.size, for
351 frame_client_gravity. */
352 self
->area
.x
= self
->client
->area
.x
;
353 self
->area
.y
= self
->client
->area
.y
;
354 frame_client_gravity(self
, &self
->area
.x
, &self
->area
.y
);
358 /* move and resize the top level frame.
359 shading can change without being moved or resized */
360 XMoveResizeWindow(ob_display
, self
->window
,
361 self
->area
.x
, self
->area
.y
,
362 self
->area
.width
- self
->bwidth
* 2,
363 self
->area
.height
- self
->bwidth
* 2);
366 framerender_frame(self
);
368 frame_adjust_shape(self
);
373 void frame_adjust_state(ObFrame
*self
)
375 framerender_frame(self
);
378 void frame_adjust_focus(ObFrame
*self
, gboolean hilite
)
380 self
->focused
= hilite
;
381 framerender_frame(self
);
384 void frame_adjust_title(ObFrame
*self
)
386 framerender_frame(self
);
389 void frame_adjust_icon(ObFrame
*self
)
391 framerender_frame(self
);
394 void frame_grab_client(ObFrame
*self
, ObClient
*client
)
396 self
->client
= client
;
398 /* reparent the client to the frame */
399 XReparentWindow(ob_display
, client
->window
, self
->plate
, 0, 0);
401 When reparenting the client window, it is usually not mapped yet, since
402 this occurs from a MapRequest. However, in the case where Openbox is
403 starting up, the window is already mapped, so we'll see unmap events for
404 it. There are 2 unmap events generated that we see, one with the 'event'
405 member set the root window, and one set to the client, but both get
406 handled and need to be ignored.
408 if (ob_state() == OB_STATE_STARTING
)
409 client
->ignore_unmaps
+= 2;
411 /* select the event mask on the client's parent (to receive config/map
412 req's) the ButtonPress is to catch clicks on the client border */
413 XSelectInput(ob_display
, self
->plate
, PLATE_EVENTMASK
);
415 /* map the client so it maps when the frame does */
416 XMapWindow(ob_display
, client
->window
);
418 frame_adjust_area(self
, TRUE
, TRUE
, FALSE
);
420 /* set all the windows for the frame in the window_map */
421 g_hash_table_insert(window_map
, &self
->window
, client
);
422 g_hash_table_insert(window_map
, &self
->plate
, client
);
423 g_hash_table_insert(window_map
, &self
->title
, client
);
424 g_hash_table_insert(window_map
, &self
->label
, client
);
425 g_hash_table_insert(window_map
, &self
->max
, client
);
426 g_hash_table_insert(window_map
, &self
->close
, client
);
427 g_hash_table_insert(window_map
, &self
->desk
, client
);
428 g_hash_table_insert(window_map
, &self
->shade
, client
);
429 g_hash_table_insert(window_map
, &self
->icon
, client
);
430 g_hash_table_insert(window_map
, &self
->iconify
, client
);
431 g_hash_table_insert(window_map
, &self
->handle
, client
);
432 g_hash_table_insert(window_map
, &self
->lgrip
, client
);
433 g_hash_table_insert(window_map
, &self
->rgrip
, client
);
434 g_hash_table_insert(window_map
, &self
->tlresize
, client
);
435 g_hash_table_insert(window_map
, &self
->trresize
, client
);
438 void frame_release_client(ObFrame
*self
, ObClient
*client
)
442 g_assert(self
->client
== client
);
444 /* check if the app has already reparented its window away */
445 if (XCheckTypedWindowEvent(ob_display
, client
->window
,
446 ReparentNotify
, &ev
)) {
447 XPutBackEvent(ob_display
, &ev
);
449 /* re-map the window since the unmanaging process unmaps it */
451 /* XXX ... um no it doesnt it unmaps its parent, the window itself
452 retains its mapped state, no?! XXX
453 XMapWindow(ob_display, client->window); */
455 /* according to the ICCCM - if the client doesn't reparent itself,
456 then we will reparent the window to root for them */
457 XReparentWindow(ob_display
, client
->window
,
458 RootWindow(ob_display
, ob_screen
),
463 /* remove all the windows for the frame from the window_map */
464 g_hash_table_remove(window_map
, &self
->window
);
465 g_hash_table_remove(window_map
, &self
->plate
);
466 g_hash_table_remove(window_map
, &self
->title
);
467 g_hash_table_remove(window_map
, &self
->label
);
468 g_hash_table_remove(window_map
, &self
->max
);
469 g_hash_table_remove(window_map
, &self
->close
);
470 g_hash_table_remove(window_map
, &self
->desk
);
471 g_hash_table_remove(window_map
, &self
->shade
);
472 g_hash_table_remove(window_map
, &self
->icon
);
473 g_hash_table_remove(window_map
, &self
->iconify
);
474 g_hash_table_remove(window_map
, &self
->handle
);
475 g_hash_table_remove(window_map
, &self
->lgrip
);
476 g_hash_table_remove(window_map
, &self
->rgrip
);
477 g_hash_table_remove(window_map
, &self
->tlresize
);
478 g_hash_table_remove(window_map
, &self
->trresize
);
480 ob_main_loop_timeout_remove(ob_main_loop
, flash_timeout
);
485 static void layout_title(ObFrame
*self
)
489 gboolean n
, d
, i
, l
, m
, c
, s
;
491 n
= d
= i
= l
= m
= c
= s
= FALSE
;
493 /* figure out whats being shown, and the width of the label */
494 self
->label_width
= self
->width
- (ob_rr_theme
->bevel
+ 1) * 2;
495 for (lc
= config_title_layout
; *lc
!= '\0'; ++lc
) {
498 if (n
) { *lc
= ' '; break; } /* rm duplicates */
500 self
->label_width
-= (ob_rr_theme
->button_size
+ 2 +
501 ob_rr_theme
->bevel
+ 1);
504 if (d
) { *lc
= ' '; break; } /* rm duplicates */
506 self
->label_width
-= (ob_rr_theme
->button_size
+
507 ob_rr_theme
->bevel
+ 1);
510 if (s
) { *lc
= ' '; break; } /* rm duplicates */
512 self
->label_width
-= (ob_rr_theme
->button_size
+
513 ob_rr_theme
->bevel
+ 1);
516 if (i
) { *lc
= ' '; break; } /* rm duplicates */
518 self
->label_width
-= (ob_rr_theme
->button_size
+
519 ob_rr_theme
->bevel
+ 1);
522 if (l
) { *lc
= ' '; break; } /* rm duplicates */
526 if (m
) { *lc
= ' '; break; } /* rm duplicates */
528 self
->label_width
-= (ob_rr_theme
->button_size
+
529 ob_rr_theme
->bevel
+ 1);
532 if (c
) { *lc
= ' '; break; } /* rm duplicates */
534 self
->label_width
-= (ob_rr_theme
->button_size
+
535 ob_rr_theme
->bevel
+ 1);
539 if (self
->label_width
< 1) self
->label_width
= 1;
541 XResizeWindow(ob_display
, self
->label
, self
->label_width
,
542 ob_rr_theme
->label_height
);
544 if (!n
) XUnmapWindow(ob_display
, self
->icon
);
545 if (!d
) XUnmapWindow(ob_display
, self
->desk
);
546 if (!s
) XUnmapWindow(ob_display
, self
->shade
);
547 if (!i
) XUnmapWindow(ob_display
, self
->iconify
);
548 if (!l
) XUnmapWindow(ob_display
, self
->label
);
549 if (!m
) XUnmapWindow(ob_display
, self
->max
);
550 if (!c
) XUnmapWindow(ob_display
, self
->close
);
552 x
= ob_rr_theme
->bevel
+ 1;
553 for (lc
= config_title_layout
; *lc
!= '\0'; ++lc
) {
558 XMapWindow(ob_display
, self
->icon
);
559 XMoveWindow(ob_display
, self
->icon
, x
, ob_rr_theme
->bevel
);
560 x
+= ob_rr_theme
->button_size
+ 2 + ob_rr_theme
->bevel
+ 1;
565 XMapWindow(ob_display
, self
->desk
);
566 XMoveWindow(ob_display
, self
->desk
, x
, ob_rr_theme
->bevel
+ 1);
567 x
+= ob_rr_theme
->button_size
+ ob_rr_theme
->bevel
+ 1;
572 XMapWindow(ob_display
, self
->shade
);
573 XMoveWindow(ob_display
, self
->shade
, x
, ob_rr_theme
->bevel
+ 1);
574 x
+= ob_rr_theme
->button_size
+ ob_rr_theme
->bevel
+ 1;
579 XMapWindow(ob_display
, self
->iconify
);
580 XMoveWindow(ob_display
, self
->iconify
, x
, ob_rr_theme
->bevel
+ 1);
581 x
+= ob_rr_theme
->button_size
+ ob_rr_theme
->bevel
+ 1;
586 XMapWindow(ob_display
, self
->label
);
587 XMoveWindow(ob_display
, self
->label
, x
, ob_rr_theme
->bevel
);
588 x
+= self
->label_width
+ ob_rr_theme
->bevel
+ 1;
593 XMapWindow(ob_display
, self
->max
);
594 XMoveWindow(ob_display
, self
->max
, x
, ob_rr_theme
->bevel
+ 1);
595 x
+= ob_rr_theme
->button_size
+ ob_rr_theme
->bevel
+ 1;
600 XMapWindow(ob_display
, self
->close
);
601 XMoveWindow(ob_display
, self
->close
, x
, ob_rr_theme
->bevel
+ 1);
602 x
+= ob_rr_theme
->button_size
+ ob_rr_theme
->bevel
+ 1;
608 ObFrameContext
frame_context_from_string(char *name
)
610 if (!g_ascii_strcasecmp("desktop", name
))
611 return OB_FRAME_CONTEXT_DESKTOP
;
612 else if (!g_ascii_strcasecmp("client", name
))
613 return OB_FRAME_CONTEXT_CLIENT
;
614 else if (!g_ascii_strcasecmp("titlebar", name
))
615 return OB_FRAME_CONTEXT_TITLEBAR
;
616 else if (!g_ascii_strcasecmp("handle", name
))
617 return OB_FRAME_CONTEXT_HANDLE
;
618 else if (!g_ascii_strcasecmp("frame", name
))
619 return OB_FRAME_CONTEXT_FRAME
;
620 else if (!g_ascii_strcasecmp("tlcorner", name
))
621 return OB_FRAME_CONTEXT_TLCORNER
;
622 else if (!g_ascii_strcasecmp("trcorner", name
))
623 return OB_FRAME_CONTEXT_TRCORNER
;
624 else if (!g_ascii_strcasecmp("blcorner", name
))
625 return OB_FRAME_CONTEXT_BLCORNER
;
626 else if (!g_ascii_strcasecmp("brcorner", name
))
627 return OB_FRAME_CONTEXT_BRCORNER
;
628 else if (!g_ascii_strcasecmp("maximize", name
))
629 return OB_FRAME_CONTEXT_MAXIMIZE
;
630 else if (!g_ascii_strcasecmp("alldesktops", name
))
631 return OB_FRAME_CONTEXT_ALLDESKTOPS
;
632 else if (!g_ascii_strcasecmp("shade", name
))
633 return OB_FRAME_CONTEXT_SHADE
;
634 else if (!g_ascii_strcasecmp("iconify", name
))
635 return OB_FRAME_CONTEXT_ICONIFY
;
636 else if (!g_ascii_strcasecmp("icon", name
))
637 return OB_FRAME_CONTEXT_ICON
;
638 else if (!g_ascii_strcasecmp("close", name
))
639 return OB_FRAME_CONTEXT_CLOSE
;
640 return OB_FRAME_CONTEXT_NONE
;
643 ObFrameContext
frame_context(ObClient
*client
, Window win
)
647 if (win
== RootWindow(ob_display
, ob_screen
))
648 return OB_FRAME_CONTEXT_DESKTOP
;
649 if (client
== NULL
) return OB_FRAME_CONTEXT_NONE
;
650 if (win
== client
->window
) {
651 /* conceptually, this is the desktop, as far as users are
653 if (client
->type
== OB_CLIENT_TYPE_DESKTOP
)
654 return OB_FRAME_CONTEXT_DESKTOP
;
655 return OB_FRAME_CONTEXT_CLIENT
;
658 self
= client
->frame
;
659 if (win
== self
->plate
) {
660 /* conceptually, this is the desktop, as far as users are
662 if (client
->type
== OB_CLIENT_TYPE_DESKTOP
)
663 return OB_FRAME_CONTEXT_DESKTOP
;
664 return OB_FRAME_CONTEXT_CLIENT
;
667 if (win
== self
->window
) return OB_FRAME_CONTEXT_FRAME
;
668 if (win
== self
->title
) return OB_FRAME_CONTEXT_TITLEBAR
;
669 if (win
== self
->label
) return OB_FRAME_CONTEXT_TITLEBAR
;
670 if (win
== self
->handle
) return OB_FRAME_CONTEXT_HANDLE
;
671 if (win
== self
->lgrip
) return OB_FRAME_CONTEXT_BLCORNER
;
672 if (win
== self
->rgrip
) return OB_FRAME_CONTEXT_BRCORNER
;
673 if (win
== self
->tlresize
) return OB_FRAME_CONTEXT_TLCORNER
;
674 if (win
== self
->trresize
) return OB_FRAME_CONTEXT_TRCORNER
;
675 if (win
== self
->max
) return OB_FRAME_CONTEXT_MAXIMIZE
;
676 if (win
== self
->iconify
) return OB_FRAME_CONTEXT_ICONIFY
;
677 if (win
== self
->close
) return OB_FRAME_CONTEXT_CLOSE
;
678 if (win
== self
->icon
) return OB_FRAME_CONTEXT_ICON
;
679 if (win
== self
->desk
) return OB_FRAME_CONTEXT_ALLDESKTOPS
;
680 if (win
== self
->shade
) return OB_FRAME_CONTEXT_SHADE
;
682 return OB_FRAME_CONTEXT_NONE
;
685 void frame_client_gravity(ObFrame
*self
, int *x
, int *y
)
688 switch (self
->client
->gravity
) {
690 case NorthWestGravity
:
691 case SouthWestGravity
:
698 *x
-= (self
->size
.left
+ self
->size
.right
) / 2;
701 case NorthEastGravity
:
702 case SouthEastGravity
:
704 *x
-= self
->size
.left
+ self
->size
.right
;
709 *x
-= self
->size
.left
;
714 switch (self
->client
->gravity
) {
716 case NorthWestGravity
:
717 case NorthEastGravity
:
724 *y
-= (self
->size
.top
+ self
->size
.bottom
) / 2;
727 case SouthWestGravity
:
728 case SouthEastGravity
:
730 *y
-= self
->size
.top
+ self
->size
.bottom
;
735 *y
-= self
->size
.top
;
740 void frame_frame_gravity(ObFrame
*self
, int *x
, int *y
)
743 switch (self
->client
->gravity
) {
745 case NorthWestGravity
:
747 case SouthWestGravity
:
752 *x
+= (self
->size
.left
+ self
->size
.right
) / 2;
754 case NorthEastGravity
:
756 case SouthEastGravity
:
757 *x
+= self
->size
.left
+ self
->size
.right
;
761 *x
+= self
->size
.left
;
766 switch (self
->client
->gravity
) {
768 case NorthWestGravity
:
770 case NorthEastGravity
:
775 *y
+= (self
->size
.top
+ self
->size
.bottom
) / 2;
777 case SouthWestGravity
:
779 case SouthEastGravity
:
780 *y
+= self
->size
.top
+ self
->size
.bottom
;
784 *y
+= self
->size
.top
;
789 static void flash_done(gpointer data
)
791 ObFrame
*self
= data
;
793 if (self
->focused
!= self
->flash_on
)
794 frame_adjust_focus(self
, self
->focused
);
797 static gboolean
flash_timeout(gpointer data
)
799 ObFrame
*self
= data
;
802 g_get_current_time(&now
);
803 if (now
.tv_sec
> self
->flash_end
.tv_sec
||
804 (now
.tv_sec
== self
->flash_end
.tv_sec
&&
805 now
.tv_usec
>= self
->flash_end
.tv_usec
))
806 self
->flashing
= FALSE
;
809 return FALSE
; /* we are done */
811 self
->flash_on
= !self
->flash_on
;
815 focused
= self
->focused
; /* save the focused flag */
816 frame_adjust_focus(self
, self
->flash_on
);
817 self
->focused
= focused
;
820 return TRUE
; /* go again */
823 void frame_flash_start(ObFrame
*self
)
825 self
->flash_on
= self
->focused
;
828 ob_main_loop_timeout_add(ob_main_loop
,
829 G_USEC_PER_SEC
* 0.75,
833 g_get_current_time(&self
->flash_end
);
834 g_time_val_add(&self
->flash_end
, G_USEC_PER_SEC
* 5);
836 self
->flashing
= TRUE
;
839 void frame_flash_stop(ObFrame
*self
)
841 self
->flashing
= FALSE
;