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 void set_theme_statics(ObFrame
*self
);
26 static void free_theme_statics(ObFrame
*self
);
28 static Window
createWindow(Window parent
, unsigned long mask
,
29 XSetWindowAttributes
*attrib
)
31 return XCreateWindow(ob_display
, parent
, 0, 0, 1, 1, 0,
32 RrDepth(ob_rr_inst
), InputOutput
,
33 RrVisual(ob_rr_inst
), mask
, attrib
);
39 XSetWindowAttributes attrib
;
43 self
= g_new(ObFrame
, 1);
45 self
->visible
= FALSE
;
46 self
->obscured
= TRUE
;
47 self
->decorations
= 0;
48 self
->flashing
= FALSE
;
50 /* create all of the decor windows */
51 mask
= CWOverrideRedirect
| CWEventMask
;
52 attrib
.event_mask
= FRAME_EVENTMASK
;
53 attrib
.override_redirect
= TRUE
;
54 self
->window
= createWindow(RootWindow(ob_display
, ob_screen
),
58 self
->plate
= createWindow(self
->window
, mask
, &attrib
);
61 attrib
.event_mask
= ELEMENT_EVENTMASK
;
62 self
->title
= createWindow(self
->window
, mask
, &attrib
);
65 attrib
.cursor
= ob_cursor(OB_CURSOR_NORTHWEST
);
66 self
->tlresize
= createWindow(self
->title
, mask
, &attrib
);
67 attrib
.cursor
= ob_cursor(OB_CURSOR_NORTHEAST
);
68 self
->trresize
= createWindow(self
->title
, mask
, &attrib
);
71 self
->label
= createWindow(self
->title
, mask
, &attrib
);
72 self
->max
= createWindow(self
->title
, mask
, &attrib
);
73 self
->close
= createWindow(self
->title
, mask
, &attrib
);
74 self
->desk
= createWindow(self
->title
, mask
, &attrib
);
75 self
->shade
= createWindow(self
->title
, mask
, &attrib
);
76 self
->icon
= createWindow(self
->title
, mask
, &attrib
);
77 self
->iconify
= createWindow(self
->title
, mask
, &attrib
);
78 self
->handle
= createWindow(self
->window
, mask
, &attrib
);
81 attrib
.cursor
= ob_cursor(OB_CURSOR_SOUTHWEST
);
82 self
->lgrip
= createWindow(self
->handle
, mask
, &attrib
);
83 attrib
.cursor
= ob_cursor(OB_CURSOR_SOUTHEAST
);
84 self
->rgrip
= createWindow(self
->handle
, mask
, &attrib
);
86 self
->focused
= FALSE
;
88 /* the other stuff is shown based on decor settings */
89 XMapWindow(ob_display
, self
->plate
);
90 XMapWindow(ob_display
, self
->lgrip
);
91 XMapWindow(ob_display
, self
->rgrip
);
92 XMapWindow(ob_display
, self
->label
);
94 self
->max_press
= self
->close_press
= self
->desk_press
=
95 self
->iconify_press
= self
->shade_press
= FALSE
;
96 self
->max_hover
= self
->close_hover
= self
->desk_hover
=
97 self
->iconify_hover
= self
->shade_hover
= FALSE
;
99 set_theme_statics(self
);
101 return (ObFrame
*)self
;
104 static void set_theme_statics(ObFrame
*self
)
106 /* set colors/appearance/sizes for stuff that doesn't change */
107 XSetWindowBorder(ob_display
, self
->window
, ob_rr_theme
->b_color
->pixel
);
108 XSetWindowBorder(ob_display
, self
->title
, ob_rr_theme
->b_color
->pixel
);
109 XSetWindowBorder(ob_display
, self
->handle
, ob_rr_theme
->b_color
->pixel
);
110 XSetWindowBorder(ob_display
, self
->rgrip
, ob_rr_theme
->b_color
->pixel
);
111 XSetWindowBorder(ob_display
, self
->lgrip
, ob_rr_theme
->b_color
->pixel
);
113 XResizeWindow(ob_display
, self
->max
,
114 ob_rr_theme
->button_size
, ob_rr_theme
->button_size
);
115 XResizeWindow(ob_display
, self
->iconify
,
116 ob_rr_theme
->button_size
, ob_rr_theme
->button_size
);
117 XResizeWindow(ob_display
, self
->icon
,
118 ob_rr_theme
->button_size
+ 2, ob_rr_theme
->button_size
+ 2);
119 XResizeWindow(ob_display
, self
->close
,
120 ob_rr_theme
->button_size
, ob_rr_theme
->button_size
);
121 XResizeWindow(ob_display
, self
->desk
,
122 ob_rr_theme
->button_size
, ob_rr_theme
->button_size
);
123 XResizeWindow(ob_display
, self
->shade
,
124 ob_rr_theme
->button_size
, ob_rr_theme
->button_size
);
125 XResizeWindow(ob_display
, self
->lgrip
,
126 ob_rr_theme
->grip_width
, ob_rr_theme
->handle_height
);
127 XResizeWindow(ob_display
, self
->rgrip
,
128 ob_rr_theme
->grip_width
, ob_rr_theme
->handle_height
);
129 XResizeWindow(ob_display
, self
->tlresize
,
130 ob_rr_theme
->grip_width
, ob_rr_theme
->handle_height
);
131 XResizeWindow(ob_display
, self
->trresize
,
132 ob_rr_theme
->grip_width
, ob_rr_theme
->handle_height
);
134 /* set up the dynamic appearances */
135 self
->a_unfocused_title
= RrAppearanceCopy(ob_rr_theme
->a_unfocused_title
);
136 self
->a_focused_title
= RrAppearanceCopy(ob_rr_theme
->a_focused_title
);
137 self
->a_unfocused_label
= RrAppearanceCopy(ob_rr_theme
->a_unfocused_label
);
138 self
->a_focused_label
= RrAppearanceCopy(ob_rr_theme
->a_focused_label
);
139 self
->a_unfocused_handle
=
140 RrAppearanceCopy(ob_rr_theme
->a_unfocused_handle
);
141 self
->a_focused_handle
= RrAppearanceCopy(ob_rr_theme
->a_focused_handle
);
142 self
->a_icon
= RrAppearanceCopy(ob_rr_theme
->a_icon
);
145 static void free_theme_statics(ObFrame
*self
)
147 RrAppearanceFree(self
->a_unfocused_title
);
148 RrAppearanceFree(self
->a_focused_title
);
149 RrAppearanceFree(self
->a_unfocused_label
);
150 RrAppearanceFree(self
->a_focused_label
);
151 RrAppearanceFree(self
->a_unfocused_handle
);
152 RrAppearanceFree(self
->a_focused_handle
);
153 RrAppearanceFree(self
->a_icon
);
156 static void frame_free(ObFrame
*self
)
158 free_theme_statics(self
);
160 XDestroyWindow(ob_display
, self
->window
);
165 void frame_show(ObFrame
*self
)
167 if (!self
->visible
) {
168 self
->visible
= TRUE
;
169 XMapWindow(ob_display
, self
->window
);
173 void frame_hide(ObFrame
*self
)
176 self
->visible
= FALSE
;
177 self
->client
->ignore_unmaps
++;
178 XUnmapWindow(ob_display
, self
->window
);
182 void frame_adjust_theme(ObFrame
*self
)
184 free_theme_statics(self
);
185 set_theme_statics(self
);
188 void frame_adjust_shape(ObFrame
*self
)
194 if (!self
->client
->shaped
) {
195 /* clear the shape on the frame window */
196 XShapeCombineMask(ob_display
, self
->window
, ShapeBounding
,
197 self
->innersize
.left
,
201 /* make the frame's shape match the clients */
202 XShapeCombineShape(ob_display
, self
->window
, ShapeBounding
,
203 self
->innersize
.left
,
205 self
->client
->window
,
206 ShapeBounding
, ShapeSet
);
209 if (self
->decorations
& OB_FRAME_DECOR_TITLEBAR
) {
210 xrect
[0].x
= -ob_rr_theme
->bwidth
;
211 xrect
[0].y
= -ob_rr_theme
->bwidth
;
212 xrect
[0].width
= self
->width
+ self
->rbwidth
* 2;
213 xrect
[0].height
= ob_rr_theme
->title_height
+
218 if (self
->decorations
& OB_FRAME_DECOR_HANDLE
) {
219 xrect
[1].x
= -ob_rr_theme
->bwidth
;
220 xrect
[1].y
= FRAME_HANDLE_Y(self
);
221 xrect
[1].width
= self
->width
+ self
->rbwidth
* 2;
222 xrect
[1].height
= ob_rr_theme
->handle_height
+
227 XShapeCombineRectangles(ob_display
, self
->window
,
228 ShapeBounding
, 0, 0, xrect
, num
,
229 ShapeUnion
, Unsorted
);
234 void frame_adjust_area(ObFrame
*self
, gboolean moved
,
235 gboolean resized
, gboolean fake
)
238 self
->decorations
= self
->client
->decorations
;
239 self
->max_horz
= self
->client
->max_horz
;
241 if (self
->decorations
& OB_FRAME_DECOR_BORDER
) {
242 self
->bwidth
= ob_rr_theme
->bwidth
;
243 self
->cbwidth_x
= self
->cbwidth_y
= ob_rr_theme
->cbwidth
;
245 self
->bwidth
= self
->cbwidth_x
= self
->cbwidth_y
= 0;
247 self
->rbwidth
= self
->bwidth
;
250 self
->bwidth
= self
->cbwidth_x
= 0;
252 STRUT_SET(self
->innersize
,
257 self
->width
= self
->client
->area
.width
+ self
->cbwidth_x
* 2 -
258 (self
->max_horz
? self
->rbwidth
* 2 : 0);
259 self
->width
= MAX(self
->width
, 1); /* no lower than 1 */
261 /* set border widths */
263 XSetWindowBorderWidth(ob_display
, self
->window
, self
->bwidth
);
264 XSetWindowBorderWidth(ob_display
, self
->title
, self
->rbwidth
);
265 XSetWindowBorderWidth(ob_display
, self
->handle
, self
->rbwidth
);
266 XSetWindowBorderWidth(ob_display
, self
->lgrip
, self
->rbwidth
);
267 XSetWindowBorderWidth(ob_display
, self
->rgrip
, self
->rbwidth
);
270 if (self
->decorations
& OB_FRAME_DECOR_TITLEBAR
)
271 self
->innersize
.top
+= ob_rr_theme
->title_height
+ self
->rbwidth
+
272 (self
->rbwidth
- self
->bwidth
);
273 if (self
->decorations
& OB_FRAME_DECOR_HANDLE
&&
274 ob_rr_theme
->show_handle
)
275 self
->innersize
.bottom
+= ob_rr_theme
->handle_height
+
276 self
->rbwidth
+ (self
->rbwidth
- self
->bwidth
);
278 /* they all default off, they're turned on in layout_title */
282 self
->iconify_x
= -1;
287 /* position/size and map/unmap all the windows */
290 if (self
->decorations
& OB_FRAME_DECOR_TITLEBAR
) {
291 XMoveResizeWindow(ob_display
, self
->title
,
292 -self
->bwidth
, -self
->bwidth
,
293 self
->width
, ob_rr_theme
->title_height
);
294 XMapWindow(ob_display
, self
->title
);
296 if (self
->decorations
& OB_FRAME_DECOR_GRIPS
) {
297 XMoveWindow(ob_display
, self
->tlresize
, 0, 0);
298 XMoveWindow(ob_display
, self
->trresize
,
299 self
->width
- ob_rr_theme
->grip_width
, 0);
300 XMapWindow(ob_display
, self
->tlresize
);
301 XMapWindow(ob_display
, self
->trresize
);
303 XUnmapWindow(ob_display
, self
->tlresize
);
304 XUnmapWindow(ob_display
, self
->trresize
);
307 XUnmapWindow(ob_display
, self
->title
);
310 if (self
->decorations
& OB_FRAME_DECOR_TITLEBAR
)
311 /* layout the title bar elements */
315 if (self
->decorations
& OB_FRAME_DECOR_HANDLE
&&
316 ob_rr_theme
->show_handle
)
318 XMoveResizeWindow(ob_display
, self
->handle
,
319 -self
->bwidth
, FRAME_HANDLE_Y(self
),
320 self
->width
, ob_rr_theme
->handle_height
);
321 XMapWindow(ob_display
, self
->handle
);
323 if (self
->decorations
& OB_FRAME_DECOR_GRIPS
) {
324 XMoveWindow(ob_display
, self
->lgrip
,
325 -self
->rbwidth
, -self
->rbwidth
);
326 XMoveWindow(ob_display
, self
->rgrip
,
327 -self
->rbwidth
+ self
->width
-
328 ob_rr_theme
->grip_width
, -self
->rbwidth
);
329 XMapWindow(ob_display
, self
->lgrip
);
330 XMapWindow(ob_display
, self
->rgrip
);
332 XUnmapWindow(ob_display
, self
->lgrip
);
333 XUnmapWindow(ob_display
, self
->rgrip
);
336 /* XXX make a subwindow with these dimentions?
337 ob_rr_theme->grip_width + self->bwidth, 0,
338 self->width - (ob_rr_theme->grip_width + self->bwidth) * 2,
339 ob_rr_theme->handle_height);
342 XUnmapWindow(ob_display
, self
->handle
);
344 /* move and resize the plate */
345 XMoveResizeWindow(ob_display
, self
->plate
,
346 self
->innersize
.left
- self
->cbwidth_x
,
347 self
->innersize
.top
- self
->cbwidth_y
,
348 self
->client
->area
.width
+ self
->cbwidth_x
* 2,
349 self
->client
->area
.height
+ self
->cbwidth_y
* 2);
350 /* when the client has StaticGravity, it likes to move around. */
351 XMoveWindow(ob_display
, self
->client
->window
,
352 self
->cbwidth_x
, self
->cbwidth_y
);
355 STRUT_SET(self
->size
,
356 self
->innersize
.left
+ self
->bwidth
,
357 self
->innersize
.top
+ self
->bwidth
,
358 self
->innersize
.right
+ self
->bwidth
,
359 self
->innersize
.bottom
+ self
->bwidth
);
362 /* shading can change without being moved or resized */
363 RECT_SET_SIZE(self
->area
,
364 self
->client
->area
.width
+
365 self
->size
.left
+ self
->size
.right
,
366 (self
->client
->shaded
?
367 ob_rr_theme
->title_height
+ self
->rbwidth
* 2:
368 self
->client
->area
.height
+
369 self
->size
.top
+ self
->size
.bottom
));
372 /* find the new coordinates, done after setting the frame.size, for
373 frame_client_gravity. */
374 self
->area
.x
= self
->client
->area
.x
;
375 self
->area
.y
= self
->client
->area
.y
;
376 frame_client_gravity(self
, &self
->area
.x
, &self
->area
.y
);
380 /* move and resize the top level frame.
381 shading can change without being moved or resized */
382 XMoveResizeWindow(ob_display
, self
->window
,
383 self
->area
.x
, self
->area
.y
,
384 self
->area
.width
- self
->bwidth
* 2,
385 self
->area
.height
- self
->bwidth
* 2);
388 framerender_frame(self
);
390 frame_adjust_shape(self
);
395 void frame_adjust_state(ObFrame
*self
)
397 framerender_frame(self
);
400 void frame_adjust_focus(ObFrame
*self
, gboolean hilite
)
402 self
->focused
= hilite
;
403 framerender_frame(self
);
406 void frame_adjust_title(ObFrame
*self
)
408 framerender_frame(self
);
411 void frame_adjust_icon(ObFrame
*self
)
413 framerender_frame(self
);
416 void frame_grab_client(ObFrame
*self
, ObClient
*client
)
418 self
->client
= client
;
420 /* reparent the client to the frame */
421 XReparentWindow(ob_display
, client
->window
, self
->plate
, 0, 0);
423 When reparenting the client window, it is usually not mapped yet, since
424 this occurs from a MapRequest. However, in the case where Openbox is
425 starting up, the window is already mapped, so we'll see unmap events for
426 it. There are 2 unmap events generated that we see, one with the 'event'
427 member set the root window, and one set to the client, but both get
428 handled and need to be ignored.
430 if (ob_state() == OB_STATE_STARTING
)
431 client
->ignore_unmaps
+= 2;
433 /* select the event mask on the client's parent (to receive config/map
434 req's) the ButtonPress is to catch clicks on the client border */
435 XSelectInput(ob_display
, self
->plate
, PLATE_EVENTMASK
);
437 /* map the client so it maps when the frame does */
438 XMapWindow(ob_display
, client
->window
);
440 frame_adjust_area(self
, TRUE
, TRUE
, FALSE
);
442 /* set all the windows for the frame in the window_map */
443 g_hash_table_insert(window_map
, &self
->window
, client
);
444 g_hash_table_insert(window_map
, &self
->plate
, client
);
445 g_hash_table_insert(window_map
, &self
->title
, client
);
446 g_hash_table_insert(window_map
, &self
->label
, client
);
447 g_hash_table_insert(window_map
, &self
->max
, client
);
448 g_hash_table_insert(window_map
, &self
->close
, client
);
449 g_hash_table_insert(window_map
, &self
->desk
, client
);
450 g_hash_table_insert(window_map
, &self
->shade
, client
);
451 g_hash_table_insert(window_map
, &self
->icon
, client
);
452 g_hash_table_insert(window_map
, &self
->iconify
, client
);
453 g_hash_table_insert(window_map
, &self
->handle
, client
);
454 g_hash_table_insert(window_map
, &self
->lgrip
, client
);
455 g_hash_table_insert(window_map
, &self
->rgrip
, client
);
456 g_hash_table_insert(window_map
, &self
->tlresize
, client
);
457 g_hash_table_insert(window_map
, &self
->trresize
, client
);
460 void frame_release_client(ObFrame
*self
, ObClient
*client
)
464 g_assert(self
->client
== client
);
466 /* check if the app has already reparented its window away */
467 if (XCheckTypedWindowEvent(ob_display
, client
->window
,
468 ReparentNotify
, &ev
)) {
469 XPutBackEvent(ob_display
, &ev
);
471 /* re-map the window since the unmanaging process unmaps it */
473 /* XXX ... um no it doesnt it unmaps its parent, the window itself
474 retains its mapped state, no?! XXX
475 XMapWindow(ob_display, client->window); */
477 /* according to the ICCCM - if the client doesn't reparent itself,
478 then we will reparent the window to root for them */
479 XReparentWindow(ob_display
, client
->window
,
480 RootWindow(ob_display
, ob_screen
),
485 /* remove all the windows for the frame from the window_map */
486 g_hash_table_remove(window_map
, &self
->window
);
487 g_hash_table_remove(window_map
, &self
->plate
);
488 g_hash_table_remove(window_map
, &self
->title
);
489 g_hash_table_remove(window_map
, &self
->label
);
490 g_hash_table_remove(window_map
, &self
->max
);
491 g_hash_table_remove(window_map
, &self
->close
);
492 g_hash_table_remove(window_map
, &self
->desk
);
493 g_hash_table_remove(window_map
, &self
->shade
);
494 g_hash_table_remove(window_map
, &self
->icon
);
495 g_hash_table_remove(window_map
, &self
->iconify
);
496 g_hash_table_remove(window_map
, &self
->handle
);
497 g_hash_table_remove(window_map
, &self
->lgrip
);
498 g_hash_table_remove(window_map
, &self
->rgrip
);
499 g_hash_table_remove(window_map
, &self
->tlresize
);
500 g_hash_table_remove(window_map
, &self
->trresize
);
502 ob_main_loop_timeout_remove_data(ob_main_loop
, flash_timeout
, self
);
507 static void layout_title(ObFrame
*self
)
511 gboolean n
, d
, i
, l
, m
, c
, s
;
513 n
= d
= i
= l
= m
= c
= s
= FALSE
;
515 /* figure out whats being shown, and the width of the label */
516 self
->label_width
= self
->width
- (ob_rr_theme
->padding
+ 1) * 2;
517 for (lc
= config_title_layout
; *lc
!= '\0'; ++lc
) {
520 if (n
) { *lc
= ' '; break; } /* rm duplicates */
522 self
->label_width
-= (ob_rr_theme
->button_size
+ 2 +
523 ob_rr_theme
->padding
+ 1);
526 if (d
) { *lc
= ' '; break; } /* rm duplicates */
528 self
->label_width
-= (ob_rr_theme
->button_size
+
529 ob_rr_theme
->padding
+ 1);
532 if (s
) { *lc
= ' '; break; } /* rm duplicates */
534 self
->label_width
-= (ob_rr_theme
->button_size
+
535 ob_rr_theme
->padding
+ 1);
538 if (i
) { *lc
= ' '; break; } /* rm duplicates */
540 self
->label_width
-= (ob_rr_theme
->button_size
+
541 ob_rr_theme
->padding
+ 1);
544 if (l
) { *lc
= ' '; break; } /* rm duplicates */
548 if (m
) { *lc
= ' '; break; } /* rm duplicates */
550 self
->label_width
-= (ob_rr_theme
->button_size
+
551 ob_rr_theme
->padding
+ 1);
554 if (c
) { *lc
= ' '; break; } /* rm duplicates */
556 self
->label_width
-= (ob_rr_theme
->button_size
+
557 ob_rr_theme
->padding
+ 1);
561 if (self
->label_width
< 1) self
->label_width
= 1;
563 XResizeWindow(ob_display
, self
->label
, self
->label_width
,
564 ob_rr_theme
->label_height
);
566 if (!n
) XUnmapWindow(ob_display
, self
->icon
);
567 if (!d
) XUnmapWindow(ob_display
, self
->desk
);
568 if (!s
) XUnmapWindow(ob_display
, self
->shade
);
569 if (!i
) XUnmapWindow(ob_display
, self
->iconify
);
570 if (!l
) XUnmapWindow(ob_display
, self
->label
);
571 if (!m
) XUnmapWindow(ob_display
, self
->max
);
572 if (!c
) XUnmapWindow(ob_display
, self
->close
);
574 x
= ob_rr_theme
->padding
+ 1;
575 for (lc
= config_title_layout
; *lc
!= '\0'; ++lc
) {
580 XMapWindow(ob_display
, self
->icon
);
581 XMoveWindow(ob_display
, self
->icon
, x
, ob_rr_theme
->padding
);
582 x
+= ob_rr_theme
->button_size
+ 2 + ob_rr_theme
->padding
+ 1;
587 XMapWindow(ob_display
, self
->desk
);
588 XMoveWindow(ob_display
, self
->desk
, x
, ob_rr_theme
->padding
+ 1);
589 x
+= ob_rr_theme
->button_size
+ ob_rr_theme
->padding
+ 1;
594 XMapWindow(ob_display
, self
->shade
);
595 XMoveWindow(ob_display
, self
->shade
, x
, ob_rr_theme
->padding
+ 1);
596 x
+= ob_rr_theme
->button_size
+ ob_rr_theme
->padding
+ 1;
601 XMapWindow(ob_display
, self
->iconify
);
602 XMoveWindow(ob_display
,self
->iconify
, x
, ob_rr_theme
->padding
+ 1);
603 x
+= ob_rr_theme
->button_size
+ ob_rr_theme
->padding
+ 1;
608 XMapWindow(ob_display
, self
->label
);
609 XMoveWindow(ob_display
, self
->label
, x
, ob_rr_theme
->padding
);
610 x
+= self
->label_width
+ ob_rr_theme
->padding
+ 1;
615 XMapWindow(ob_display
, self
->max
);
616 XMoveWindow(ob_display
, self
->max
, x
, ob_rr_theme
->padding
+ 1);
617 x
+= ob_rr_theme
->button_size
+ ob_rr_theme
->padding
+ 1;
622 XMapWindow(ob_display
, self
->close
);
623 XMoveWindow(ob_display
, self
->close
, x
, ob_rr_theme
->padding
+ 1);
624 x
+= ob_rr_theme
->button_size
+ ob_rr_theme
->padding
+ 1;
630 ObFrameContext
frame_context_from_string(char *name
)
632 if (!g_ascii_strcasecmp("desktop", name
))
633 return OB_FRAME_CONTEXT_DESKTOP
;
634 else if (!g_ascii_strcasecmp("client", name
))
635 return OB_FRAME_CONTEXT_CLIENT
;
636 else if (!g_ascii_strcasecmp("titlebar", name
))
637 return OB_FRAME_CONTEXT_TITLEBAR
;
638 else if (!g_ascii_strcasecmp("handle", name
))
639 return OB_FRAME_CONTEXT_HANDLE
;
640 else if (!g_ascii_strcasecmp("frame", name
))
641 return OB_FRAME_CONTEXT_FRAME
;
642 else if (!g_ascii_strcasecmp("tlcorner", name
))
643 return OB_FRAME_CONTEXT_TLCORNER
;
644 else if (!g_ascii_strcasecmp("trcorner", name
))
645 return OB_FRAME_CONTEXT_TRCORNER
;
646 else if (!g_ascii_strcasecmp("blcorner", name
))
647 return OB_FRAME_CONTEXT_BLCORNER
;
648 else if (!g_ascii_strcasecmp("brcorner", name
))
649 return OB_FRAME_CONTEXT_BRCORNER
;
650 else if (!g_ascii_strcasecmp("maximize", name
))
651 return OB_FRAME_CONTEXT_MAXIMIZE
;
652 else if (!g_ascii_strcasecmp("alldesktops", name
))
653 return OB_FRAME_CONTEXT_ALLDESKTOPS
;
654 else if (!g_ascii_strcasecmp("shade", name
))
655 return OB_FRAME_CONTEXT_SHADE
;
656 else if (!g_ascii_strcasecmp("iconify", name
))
657 return OB_FRAME_CONTEXT_ICONIFY
;
658 else if (!g_ascii_strcasecmp("icon", name
))
659 return OB_FRAME_CONTEXT_ICON
;
660 else if (!g_ascii_strcasecmp("close", name
))
661 return OB_FRAME_CONTEXT_CLOSE
;
662 return OB_FRAME_CONTEXT_NONE
;
665 ObFrameContext
frame_context(ObClient
*client
, Window win
)
669 if (win
== RootWindow(ob_display
, ob_screen
))
670 return OB_FRAME_CONTEXT_DESKTOP
;
671 if (client
== NULL
) return OB_FRAME_CONTEXT_NONE
;
672 if (win
== client
->window
) {
673 /* conceptually, this is the desktop, as far as users are
675 if (client
->type
== OB_CLIENT_TYPE_DESKTOP
)
676 return OB_FRAME_CONTEXT_DESKTOP
;
677 return OB_FRAME_CONTEXT_CLIENT
;
680 self
= client
->frame
;
681 if (win
== self
->plate
) {
682 /* conceptually, this is the desktop, as far as users are
684 if (client
->type
== OB_CLIENT_TYPE_DESKTOP
)
685 return OB_FRAME_CONTEXT_DESKTOP
;
686 return OB_FRAME_CONTEXT_CLIENT
;
689 if (win
== self
->window
) return OB_FRAME_CONTEXT_FRAME
;
690 if (win
== self
->title
) return OB_FRAME_CONTEXT_TITLEBAR
;
691 if (win
== self
->label
) return OB_FRAME_CONTEXT_TITLEBAR
;
692 if (win
== self
->handle
) return OB_FRAME_CONTEXT_HANDLE
;
693 if (win
== self
->lgrip
) return OB_FRAME_CONTEXT_BLCORNER
;
694 if (win
== self
->rgrip
) return OB_FRAME_CONTEXT_BRCORNER
;
695 if (win
== self
->tlresize
) return OB_FRAME_CONTEXT_TLCORNER
;
696 if (win
== self
->trresize
) return OB_FRAME_CONTEXT_TRCORNER
;
697 if (win
== self
->max
) return OB_FRAME_CONTEXT_MAXIMIZE
;
698 if (win
== self
->iconify
) return OB_FRAME_CONTEXT_ICONIFY
;
699 if (win
== self
->close
) return OB_FRAME_CONTEXT_CLOSE
;
700 if (win
== self
->icon
) return OB_FRAME_CONTEXT_ICON
;
701 if (win
== self
->desk
) return OB_FRAME_CONTEXT_ALLDESKTOPS
;
702 if (win
== self
->shade
) return OB_FRAME_CONTEXT_SHADE
;
704 return OB_FRAME_CONTEXT_NONE
;
707 void frame_client_gravity(ObFrame
*self
, int *x
, int *y
)
710 switch (self
->client
->gravity
) {
712 case NorthWestGravity
:
713 case SouthWestGravity
:
720 *x
-= (self
->size
.left
+ self
->size
.right
) / 2;
723 case NorthEastGravity
:
724 case SouthEastGravity
:
726 *x
-= self
->size
.left
+ self
->size
.right
;
731 *x
-= self
->size
.left
;
736 switch (self
->client
->gravity
) {
738 case NorthWestGravity
:
739 case NorthEastGravity
:
746 *y
-= (self
->size
.top
+ self
->size
.bottom
) / 2;
749 case SouthWestGravity
:
750 case SouthEastGravity
:
752 *y
-= self
->size
.top
+ self
->size
.bottom
;
757 *y
-= self
->size
.top
;
762 void frame_frame_gravity(ObFrame
*self
, int *x
, int *y
)
765 switch (self
->client
->gravity
) {
767 case NorthWestGravity
:
769 case SouthWestGravity
:
774 *x
+= (self
->size
.left
+ self
->size
.right
) / 2;
776 case NorthEastGravity
:
778 case SouthEastGravity
:
779 *x
+= self
->size
.left
+ self
->size
.right
;
783 *x
+= self
->size
.left
;
788 switch (self
->client
->gravity
) {
790 case NorthWestGravity
:
792 case NorthEastGravity
:
797 *y
+= (self
->size
.top
+ self
->size
.bottom
) / 2;
799 case SouthWestGravity
:
801 case SouthEastGravity
:
802 *y
+= self
->size
.top
+ self
->size
.bottom
;
806 *y
+= self
->size
.top
;
811 static void flash_done(gpointer data
)
813 ObFrame
*self
= data
;
815 if (self
->focused
!= self
->flash_on
)
816 frame_adjust_focus(self
, self
->focused
);
819 static gboolean
flash_timeout(gpointer data
)
821 ObFrame
*self
= data
;
824 g_get_current_time(&now
);
825 if (now
.tv_sec
> self
->flash_end
.tv_sec
||
826 (now
.tv_sec
== self
->flash_end
.tv_sec
&&
827 now
.tv_usec
>= self
->flash_end
.tv_usec
))
828 self
->flashing
= FALSE
;
831 return FALSE
; /* we are done */
833 self
->flash_on
= !self
->flash_on
;
837 focused
= self
->focused
; /* save the focused flag */
838 frame_adjust_focus(self
, self
->flash_on
);
839 self
->focused
= focused
;
842 return TRUE
; /* go again */
845 void frame_flash_start(ObFrame
*self
)
847 self
->flash_on
= self
->focused
;
850 ob_main_loop_timeout_add(ob_main_loop
,
851 G_USEC_PER_SEC
* 0.75,
855 g_get_current_time(&self
->flash_end
);
856 g_time_val_add(&self
->flash_end
, G_USEC_PER_SEC
* 5);
858 self
->flashing
= TRUE
;
861 void frame_flash_stop(ObFrame
*self
)
863 self
->flashing
= FALSE
;