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"
24 #include "framerender.h"
26 #include "moveresize.h"
27 #include "render/theme.h"
29 #define PLATE_EVENTMASK (SubstructureRedirectMask | ButtonPressMask)
30 #define FRAME_EVENTMASK (EnterWindowMask | LeaveWindowMask | \
31 ButtonPressMask | ButtonReleaseMask | \
33 #define ELEMENT_EVENTMASK (ButtonPressMask | ButtonReleaseMask | \
34 ButtonMotionMask | ExposureMask | \
35 EnterWindowMask | LeaveWindowMask)
37 #define FRAME_HANDLE_Y(f) (f->innersize.top + f->client->area.height + \
40 static void layout_title(ObFrame
*self
);
41 static void flash_done(gpointer data
);
42 static gboolean
flash_timeout(gpointer data
);
44 static void set_theme_statics(ObFrame
*self
);
45 static void free_theme_statics(ObFrame
*self
);
47 static Window
createWindow(Window parent
, unsigned long mask
,
48 XSetWindowAttributes
*attrib
)
50 return XCreateWindow(ob_display
, parent
, 0, 0, 1, 1, 0,
51 RrDepth(ob_rr_inst
), InputOutput
,
52 RrVisual(ob_rr_inst
), mask
, attrib
);
58 XSetWindowAttributes attrib
;
62 self
= g_new(ObFrame
, 1);
64 self
->visible
= FALSE
;
65 self
->obscured
= TRUE
;
66 self
->decorations
= 0;
67 self
->flashing
= FALSE
;
69 /* create all of the decor windows */
70 mask
= CWOverrideRedirect
| CWEventMask
;
71 attrib
.event_mask
= FRAME_EVENTMASK
;
72 attrib
.override_redirect
= TRUE
;
73 self
->window
= createWindow(RootWindow(ob_display
, ob_screen
),
77 self
->plate
= createWindow(self
->window
, mask
, &attrib
);
80 attrib
.event_mask
= ELEMENT_EVENTMASK
;
81 self
->title
= createWindow(self
->window
, mask
, &attrib
);
84 attrib
.cursor
= ob_cursor(OB_CURSOR_NORTHWEST
);
85 self
->tlresize
= createWindow(self
->title
, mask
, &attrib
);
86 attrib
.cursor
= ob_cursor(OB_CURSOR_NORTHEAST
);
87 self
->trresize
= createWindow(self
->title
, mask
, &attrib
);
90 self
->label
= createWindow(self
->title
, mask
, &attrib
);
91 self
->max
= createWindow(self
->title
, mask
, &attrib
);
92 self
->close
= createWindow(self
->title
, mask
, &attrib
);
93 self
->desk
= createWindow(self
->title
, mask
, &attrib
);
94 self
->shade
= createWindow(self
->title
, mask
, &attrib
);
95 self
->icon
= createWindow(self
->title
, mask
, &attrib
);
96 self
->iconify
= createWindow(self
->title
, mask
, &attrib
);
97 self
->handle
= createWindow(self
->window
, mask
, &attrib
);
100 attrib
.cursor
= ob_cursor(OB_CURSOR_SOUTHWEST
);
101 self
->lgrip
= createWindow(self
->handle
, mask
, &attrib
);
102 attrib
.cursor
= ob_cursor(OB_CURSOR_SOUTHEAST
);
103 self
->rgrip
= createWindow(self
->handle
, mask
, &attrib
);
105 self
->focused
= FALSE
;
107 /* the other stuff is shown based on decor settings */
108 XMapWindow(ob_display
, self
->plate
);
109 XMapWindow(ob_display
, self
->lgrip
);
110 XMapWindow(ob_display
, self
->rgrip
);
111 XMapWindow(ob_display
, self
->label
);
113 self
->max_press
= self
->close_press
= self
->desk_press
=
114 self
->iconify_press
= self
->shade_press
= FALSE
;
115 self
->max_hover
= self
->close_hover
= self
->desk_hover
=
116 self
->iconify_hover
= self
->shade_hover
= FALSE
;
118 set_theme_statics(self
);
120 return (ObFrame
*)self
;
123 static void set_theme_statics(ObFrame
*self
)
125 /* set colors/appearance/sizes for stuff that doesn't change */
126 XSetWindowBorder(ob_display
, self
->window
, ob_rr_theme
->b_color
->pixel
);
127 XSetWindowBorder(ob_display
, self
->title
, ob_rr_theme
->b_color
->pixel
);
128 XSetWindowBorder(ob_display
, self
->handle
, ob_rr_theme
->b_color
->pixel
);
129 XSetWindowBorder(ob_display
, self
->rgrip
, ob_rr_theme
->b_color
->pixel
);
130 XSetWindowBorder(ob_display
, self
->lgrip
, ob_rr_theme
->b_color
->pixel
);
132 XResizeWindow(ob_display
, self
->max
,
133 ob_rr_theme
->button_size
, ob_rr_theme
->button_size
);
134 XResizeWindow(ob_display
, self
->iconify
,
135 ob_rr_theme
->button_size
, ob_rr_theme
->button_size
);
136 XResizeWindow(ob_display
, self
->icon
,
137 ob_rr_theme
->button_size
+ 2, ob_rr_theme
->button_size
+ 2);
138 XResizeWindow(ob_display
, self
->close
,
139 ob_rr_theme
->button_size
, ob_rr_theme
->button_size
);
140 XResizeWindow(ob_display
, self
->desk
,
141 ob_rr_theme
->button_size
, ob_rr_theme
->button_size
);
142 XResizeWindow(ob_display
, self
->shade
,
143 ob_rr_theme
->button_size
, ob_rr_theme
->button_size
);
144 XResizeWindow(ob_display
, self
->lgrip
,
145 ob_rr_theme
->grip_width
, ob_rr_theme
->handle_height
);
146 XResizeWindow(ob_display
, self
->rgrip
,
147 ob_rr_theme
->grip_width
, ob_rr_theme
->handle_height
);
148 XResizeWindow(ob_display
, self
->tlresize
,
149 ob_rr_theme
->grip_width
, ob_rr_theme
->handle_height
);
150 XResizeWindow(ob_display
, self
->trresize
,
151 ob_rr_theme
->grip_width
, ob_rr_theme
->handle_height
);
153 /* set up the dynamic appearances */
154 self
->a_unfocused_title
= RrAppearanceCopy(ob_rr_theme
->a_unfocused_title
);
155 self
->a_focused_title
= RrAppearanceCopy(ob_rr_theme
->a_focused_title
);
156 self
->a_unfocused_label
= RrAppearanceCopy(ob_rr_theme
->a_unfocused_label
);
157 self
->a_focused_label
= RrAppearanceCopy(ob_rr_theme
->a_focused_label
);
158 self
->a_unfocused_handle
=
159 RrAppearanceCopy(ob_rr_theme
->a_unfocused_handle
);
160 self
->a_focused_handle
= RrAppearanceCopy(ob_rr_theme
->a_focused_handle
);
161 self
->a_icon
= RrAppearanceCopy(ob_rr_theme
->a_icon
);
164 static void free_theme_statics(ObFrame
*self
)
166 RrAppearanceFree(self
->a_unfocused_title
);
167 RrAppearanceFree(self
->a_focused_title
);
168 RrAppearanceFree(self
->a_unfocused_label
);
169 RrAppearanceFree(self
->a_focused_label
);
170 RrAppearanceFree(self
->a_unfocused_handle
);
171 RrAppearanceFree(self
->a_focused_handle
);
172 RrAppearanceFree(self
->a_icon
);
175 static void frame_free(ObFrame
*self
)
177 free_theme_statics(self
);
179 XDestroyWindow(ob_display
, self
->window
);
184 void frame_show(ObFrame
*self
)
186 if (!self
->visible
) {
187 self
->visible
= TRUE
;
188 XMapWindow(ob_display
, self
->window
);
192 void frame_hide(ObFrame
*self
)
195 self
->visible
= FALSE
;
196 self
->client
->ignore_unmaps
++;
197 XUnmapWindow(ob_display
, self
->window
);
201 void frame_adjust_theme(ObFrame
*self
)
203 free_theme_statics(self
);
204 set_theme_statics(self
);
207 void frame_adjust_shape(ObFrame
*self
)
213 if (!self
->client
->shaped
) {
214 /* clear the shape on the frame window */
215 XShapeCombineMask(ob_display
, self
->window
, ShapeBounding
,
216 self
->innersize
.left
,
220 /* make the frame's shape match the clients */
221 XShapeCombineShape(ob_display
, self
->window
, ShapeBounding
,
222 self
->innersize
.left
,
224 self
->client
->window
,
225 ShapeBounding
, ShapeSet
);
228 if (self
->decorations
& OB_FRAME_DECOR_TITLEBAR
) {
229 xrect
[0].x
= -ob_rr_theme
->bwidth
;
230 xrect
[0].y
= -ob_rr_theme
->bwidth
;
231 xrect
[0].width
= self
->width
+ self
->rbwidth
* 2;
232 xrect
[0].height
= ob_rr_theme
->title_height
+
237 if (self
->decorations
& OB_FRAME_DECOR_HANDLE
) {
238 xrect
[1].x
= -ob_rr_theme
->bwidth
;
239 xrect
[1].y
= FRAME_HANDLE_Y(self
);
240 xrect
[1].width
= self
->width
+ self
->rbwidth
* 2;
241 xrect
[1].height
= ob_rr_theme
->handle_height
+
246 XShapeCombineRectangles(ob_display
, self
->window
,
247 ShapeBounding
, 0, 0, xrect
, num
,
248 ShapeUnion
, Unsorted
);
253 void frame_adjust_area(ObFrame
*self
, gboolean moved
,
254 gboolean resized
, gboolean fake
)
257 self
->decorations
= self
->client
->decorations
;
258 self
->max_horz
= self
->client
->max_horz
;
260 if (self
->decorations
& OB_FRAME_DECOR_BORDER
) {
261 self
->bwidth
= ob_rr_theme
->bwidth
;
262 self
->cbwidth_x
= self
->cbwidth_y
= ob_rr_theme
->cbwidth
;
264 self
->bwidth
= self
->cbwidth_x
= self
->cbwidth_y
= 0;
266 self
->rbwidth
= self
->bwidth
;
269 self
->bwidth
= self
->cbwidth_x
= 0;
271 STRUT_SET(self
->innersize
,
276 self
->width
= self
->client
->area
.width
+ self
->cbwidth_x
* 2 -
277 (self
->max_horz
? self
->rbwidth
* 2 : 0);
278 self
->width
= MAX(self
->width
, 1); /* no lower than 1 */
280 /* set border widths */
282 XSetWindowBorderWidth(ob_display
, self
->window
, self
->bwidth
);
283 XSetWindowBorderWidth(ob_display
, self
->title
, self
->rbwidth
);
284 XSetWindowBorderWidth(ob_display
, self
->handle
, self
->rbwidth
);
285 XSetWindowBorderWidth(ob_display
, self
->lgrip
, self
->rbwidth
);
286 XSetWindowBorderWidth(ob_display
, self
->rgrip
, self
->rbwidth
);
289 if (self
->decorations
& OB_FRAME_DECOR_TITLEBAR
)
290 self
->innersize
.top
+= ob_rr_theme
->title_height
+ self
->rbwidth
+
291 (self
->rbwidth
- self
->bwidth
);
292 if (self
->decorations
& OB_FRAME_DECOR_HANDLE
&&
293 ob_rr_theme
->show_handle
)
294 self
->innersize
.bottom
+= ob_rr_theme
->handle_height
+
295 self
->rbwidth
+ (self
->rbwidth
- self
->bwidth
);
297 /* they all default off, they're turned on in layout_title */
301 self
->iconify_x
= -1;
306 /* position/size and map/unmap all the windows */
309 if (self
->decorations
& OB_FRAME_DECOR_TITLEBAR
) {
310 XMoveResizeWindow(ob_display
, self
->title
,
311 -self
->bwidth
, -self
->bwidth
,
312 self
->width
, ob_rr_theme
->title_height
);
313 XMapWindow(ob_display
, self
->title
);
315 if (self
->decorations
& OB_FRAME_DECOR_GRIPS
) {
316 XMoveWindow(ob_display
, self
->tlresize
, 0, 0);
317 XMoveWindow(ob_display
, self
->trresize
,
318 self
->width
- ob_rr_theme
->grip_width
, 0);
319 XMapWindow(ob_display
, self
->tlresize
);
320 XMapWindow(ob_display
, self
->trresize
);
322 XUnmapWindow(ob_display
, self
->tlresize
);
323 XUnmapWindow(ob_display
, self
->trresize
);
326 XUnmapWindow(ob_display
, self
->title
);
329 if (self
->decorations
& OB_FRAME_DECOR_TITLEBAR
)
330 /* layout the title bar elements */
334 if (self
->decorations
& OB_FRAME_DECOR_HANDLE
&&
335 ob_rr_theme
->show_handle
)
337 XMoveResizeWindow(ob_display
, self
->handle
,
338 -self
->bwidth
, FRAME_HANDLE_Y(self
),
339 self
->width
, ob_rr_theme
->handle_height
);
340 XMapWindow(ob_display
, self
->handle
);
342 if (self
->decorations
& OB_FRAME_DECOR_GRIPS
) {
343 XMoveWindow(ob_display
, self
->lgrip
,
344 -self
->rbwidth
, -self
->rbwidth
);
345 XMoveWindow(ob_display
, self
->rgrip
,
346 -self
->rbwidth
+ self
->width
-
347 ob_rr_theme
->grip_width
, -self
->rbwidth
);
348 XMapWindow(ob_display
, self
->lgrip
);
349 XMapWindow(ob_display
, self
->rgrip
);
351 XUnmapWindow(ob_display
, self
->lgrip
);
352 XUnmapWindow(ob_display
, self
->rgrip
);
355 /* XXX make a subwindow with these dimentions?
356 ob_rr_theme->grip_width + self->bwidth, 0,
357 self->width - (ob_rr_theme->grip_width + self->bwidth) * 2,
358 ob_rr_theme->handle_height);
361 XUnmapWindow(ob_display
, self
->handle
);
363 /* move and resize the plate */
364 XMoveResizeWindow(ob_display
, self
->plate
,
365 self
->innersize
.left
- self
->cbwidth_x
,
366 self
->innersize
.top
- self
->cbwidth_y
,
367 self
->client
->area
.width
+ self
->cbwidth_x
* 2,
368 self
->client
->area
.height
+ self
->cbwidth_y
* 2);
369 /* when the client has StaticGravity, it likes to move around. */
370 XMoveWindow(ob_display
, self
->client
->window
,
371 self
->cbwidth_x
, self
->cbwidth_y
);
374 STRUT_SET(self
->size
,
375 self
->innersize
.left
+ self
->bwidth
,
376 self
->innersize
.top
+ self
->bwidth
,
377 self
->innersize
.right
+ self
->bwidth
,
378 self
->innersize
.bottom
+ self
->bwidth
);
381 /* shading can change without being moved or resized */
382 RECT_SET_SIZE(self
->area
,
383 self
->client
->area
.width
+
384 self
->size
.left
+ self
->size
.right
,
385 (self
->client
->shaded
?
386 ob_rr_theme
->title_height
+ self
->rbwidth
* 2:
387 self
->client
->area
.height
+
388 self
->size
.top
+ self
->size
.bottom
));
391 /* find the new coordinates, done after setting the frame.size, for
392 frame_client_gravity. */
393 self
->area
.x
= self
->client
->area
.x
;
394 self
->area
.y
= self
->client
->area
.y
;
395 frame_client_gravity(self
, &self
->area
.x
, &self
->area
.y
);
399 /* move and resize the top level frame.
400 shading can change without being moved or resized */
401 XMoveResizeWindow(ob_display
, self
->window
,
402 self
->area
.x
, self
->area
.y
,
403 self
->area
.width
- self
->bwidth
* 2,
404 self
->area
.height
- self
->bwidth
* 2);
407 framerender_frame(self
);
409 frame_adjust_shape(self
);
414 void frame_adjust_state(ObFrame
*self
)
416 framerender_frame(self
);
419 void frame_adjust_focus(ObFrame
*self
, gboolean hilite
)
421 self
->focused
= hilite
;
422 framerender_frame(self
);
425 void frame_adjust_title(ObFrame
*self
)
427 framerender_frame(self
);
430 void frame_adjust_icon(ObFrame
*self
)
432 framerender_frame(self
);
435 void frame_grab_client(ObFrame
*self
, ObClient
*client
)
437 self
->client
= client
;
439 /* reparent the client to the frame */
440 XReparentWindow(ob_display
, client
->window
, self
->plate
, 0, 0);
442 When reparenting the client window, it is usually not mapped yet, since
443 this occurs from a MapRequest. However, in the case where Openbox is
444 starting up, the window is already mapped, so we'll see unmap events for
445 it. There are 2 unmap events generated that we see, one with the 'event'
446 member set the root window, and one set to the client, but both get
447 handled and need to be ignored.
449 if (ob_state() == OB_STATE_STARTING
)
450 client
->ignore_unmaps
+= 2;
452 /* select the event mask on the client's parent (to receive config/map
453 req's) the ButtonPress is to catch clicks on the client border */
454 XSelectInput(ob_display
, self
->plate
, PLATE_EVENTMASK
);
456 /* map the client so it maps when the frame does */
457 XMapWindow(ob_display
, client
->window
);
459 frame_adjust_area(self
, TRUE
, TRUE
, FALSE
);
461 /* set all the windows for the frame in the window_map */
462 g_hash_table_insert(window_map
, &self
->window
, client
);
463 g_hash_table_insert(window_map
, &self
->plate
, client
);
464 g_hash_table_insert(window_map
, &self
->title
, client
);
465 g_hash_table_insert(window_map
, &self
->label
, client
);
466 g_hash_table_insert(window_map
, &self
->max
, client
);
467 g_hash_table_insert(window_map
, &self
->close
, client
);
468 g_hash_table_insert(window_map
, &self
->desk
, client
);
469 g_hash_table_insert(window_map
, &self
->shade
, client
);
470 g_hash_table_insert(window_map
, &self
->icon
, client
);
471 g_hash_table_insert(window_map
, &self
->iconify
, client
);
472 g_hash_table_insert(window_map
, &self
->handle
, client
);
473 g_hash_table_insert(window_map
, &self
->lgrip
, client
);
474 g_hash_table_insert(window_map
, &self
->rgrip
, client
);
475 g_hash_table_insert(window_map
, &self
->tlresize
, client
);
476 g_hash_table_insert(window_map
, &self
->trresize
, client
);
479 void frame_release_client(ObFrame
*self
, ObClient
*client
)
483 g_assert(self
->client
== client
);
485 /* check if the app has already reparented its window away */
486 if (XCheckTypedWindowEvent(ob_display
, client
->window
,
487 ReparentNotify
, &ev
)) {
488 XPutBackEvent(ob_display
, &ev
);
490 /* re-map the window since the unmanaging process unmaps it */
492 /* XXX ... um no it doesnt it unmaps its parent, the window itself
493 retains its mapped state, no?! XXX
494 XMapWindow(ob_display, client->window); */
496 /* according to the ICCCM - if the client doesn't reparent itself,
497 then we will reparent the window to root for them */
498 XReparentWindow(ob_display
, client
->window
,
499 RootWindow(ob_display
, ob_screen
),
504 /* remove all the windows for the frame from the window_map */
505 g_hash_table_remove(window_map
, &self
->window
);
506 g_hash_table_remove(window_map
, &self
->plate
);
507 g_hash_table_remove(window_map
, &self
->title
);
508 g_hash_table_remove(window_map
, &self
->label
);
509 g_hash_table_remove(window_map
, &self
->max
);
510 g_hash_table_remove(window_map
, &self
->close
);
511 g_hash_table_remove(window_map
, &self
->desk
);
512 g_hash_table_remove(window_map
, &self
->shade
);
513 g_hash_table_remove(window_map
, &self
->icon
);
514 g_hash_table_remove(window_map
, &self
->iconify
);
515 g_hash_table_remove(window_map
, &self
->handle
);
516 g_hash_table_remove(window_map
, &self
->lgrip
);
517 g_hash_table_remove(window_map
, &self
->rgrip
);
518 g_hash_table_remove(window_map
, &self
->tlresize
);
519 g_hash_table_remove(window_map
, &self
->trresize
);
521 ob_main_loop_timeout_remove_data(ob_main_loop
, flash_timeout
, self
);
526 static void layout_title(ObFrame
*self
)
530 gboolean n
, d
, i
, l
, m
, c
, s
;
532 n
= d
= i
= l
= m
= c
= s
= FALSE
;
534 /* figure out whats being shown, and the width of the label */
535 self
->label_width
= self
->width
- (ob_rr_theme
->padding
+ 1) * 2;
536 for (lc
= config_title_layout
; *lc
!= '\0'; ++lc
) {
539 if (n
) { *lc
= ' '; break; } /* rm duplicates */
541 self
->label_width
-= (ob_rr_theme
->button_size
+ 2 +
542 ob_rr_theme
->padding
+ 1);
545 if (d
) { *lc
= ' '; break; } /* rm duplicates */
547 self
->label_width
-= (ob_rr_theme
->button_size
+
548 ob_rr_theme
->padding
+ 1);
551 if (s
) { *lc
= ' '; break; } /* rm duplicates */
553 self
->label_width
-= (ob_rr_theme
->button_size
+
554 ob_rr_theme
->padding
+ 1);
557 if (i
) { *lc
= ' '; break; } /* rm duplicates */
559 self
->label_width
-= (ob_rr_theme
->button_size
+
560 ob_rr_theme
->padding
+ 1);
563 if (l
) { *lc
= ' '; break; } /* rm duplicates */
567 if (m
) { *lc
= ' '; break; } /* rm duplicates */
569 self
->label_width
-= (ob_rr_theme
->button_size
+
570 ob_rr_theme
->padding
+ 1);
573 if (c
) { *lc
= ' '; break; } /* rm duplicates */
575 self
->label_width
-= (ob_rr_theme
->button_size
+
576 ob_rr_theme
->padding
+ 1);
580 if (self
->label_width
< 1) self
->label_width
= 1;
582 XResizeWindow(ob_display
, self
->label
, self
->label_width
,
583 ob_rr_theme
->label_height
);
585 if (!n
) XUnmapWindow(ob_display
, self
->icon
);
586 if (!d
) XUnmapWindow(ob_display
, self
->desk
);
587 if (!s
) XUnmapWindow(ob_display
, self
->shade
);
588 if (!i
) XUnmapWindow(ob_display
, self
->iconify
);
589 if (!l
) XUnmapWindow(ob_display
, self
->label
);
590 if (!m
) XUnmapWindow(ob_display
, self
->max
);
591 if (!c
) XUnmapWindow(ob_display
, self
->close
);
593 x
= ob_rr_theme
->padding
+ 1;
594 for (lc
= config_title_layout
; *lc
!= '\0'; ++lc
) {
599 XMapWindow(ob_display
, self
->icon
);
600 XMoveWindow(ob_display
, self
->icon
, x
, ob_rr_theme
->padding
);
601 x
+= ob_rr_theme
->button_size
+ 2 + ob_rr_theme
->padding
+ 1;
606 XMapWindow(ob_display
, self
->desk
);
607 XMoveWindow(ob_display
, self
->desk
, x
, ob_rr_theme
->padding
+ 1);
608 x
+= ob_rr_theme
->button_size
+ ob_rr_theme
->padding
+ 1;
613 XMapWindow(ob_display
, self
->shade
);
614 XMoveWindow(ob_display
, self
->shade
, x
, ob_rr_theme
->padding
+ 1);
615 x
+= ob_rr_theme
->button_size
+ ob_rr_theme
->padding
+ 1;
620 XMapWindow(ob_display
, self
->iconify
);
621 XMoveWindow(ob_display
,self
->iconify
, x
, ob_rr_theme
->padding
+ 1);
622 x
+= ob_rr_theme
->button_size
+ ob_rr_theme
->padding
+ 1;
627 XMapWindow(ob_display
, self
->label
);
628 XMoveWindow(ob_display
, self
->label
, x
, ob_rr_theme
->padding
);
629 x
+= self
->label_width
+ ob_rr_theme
->padding
+ 1;
634 XMapWindow(ob_display
, self
->max
);
635 XMoveWindow(ob_display
, self
->max
, x
, ob_rr_theme
->padding
+ 1);
636 x
+= ob_rr_theme
->button_size
+ ob_rr_theme
->padding
+ 1;
641 XMapWindow(ob_display
, self
->close
);
642 XMoveWindow(ob_display
, self
->close
, x
, ob_rr_theme
->padding
+ 1);
643 x
+= ob_rr_theme
->button_size
+ ob_rr_theme
->padding
+ 1;
649 ObFrameContext
frame_context_from_string(const gchar
*name
)
651 if (!g_ascii_strcasecmp("Desktop", name
))
652 return OB_FRAME_CONTEXT_DESKTOP
;
653 else if (!g_ascii_strcasecmp("Client", name
))
654 return OB_FRAME_CONTEXT_CLIENT
;
655 else if (!g_ascii_strcasecmp("Titlebar", name
))
656 return OB_FRAME_CONTEXT_TITLEBAR
;
657 else if (!g_ascii_strcasecmp("Handle", name
))
658 return OB_FRAME_CONTEXT_HANDLE
;
659 else if (!g_ascii_strcasecmp("Frame", name
))
660 return OB_FRAME_CONTEXT_FRAME
;
661 else if (!g_ascii_strcasecmp("TLCorner", name
))
662 return OB_FRAME_CONTEXT_TLCORNER
;
663 else if (!g_ascii_strcasecmp("TRCorner", name
))
664 return OB_FRAME_CONTEXT_TRCORNER
;
665 else if (!g_ascii_strcasecmp("BLCorner", name
))
666 return OB_FRAME_CONTEXT_BLCORNER
;
667 else if (!g_ascii_strcasecmp("BRCorner", name
))
668 return OB_FRAME_CONTEXT_BRCORNER
;
669 else if (!g_ascii_strcasecmp("Maximize", name
))
670 return OB_FRAME_CONTEXT_MAXIMIZE
;
671 else if (!g_ascii_strcasecmp("AllDesktops", name
))
672 return OB_FRAME_CONTEXT_ALLDESKTOPS
;
673 else if (!g_ascii_strcasecmp("Shade", name
))
674 return OB_FRAME_CONTEXT_SHADE
;
675 else if (!g_ascii_strcasecmp("Iconify", name
))
676 return OB_FRAME_CONTEXT_ICONIFY
;
677 else if (!g_ascii_strcasecmp("Icon", name
))
678 return OB_FRAME_CONTEXT_ICON
;
679 else if (!g_ascii_strcasecmp("Close", name
))
680 return OB_FRAME_CONTEXT_CLOSE
;
681 else if (!g_ascii_strcasecmp("MoveResize", name
))
682 return OB_FRAME_CONTEXT_MOVE_RESIZE
;
683 return OB_FRAME_CONTEXT_NONE
;
686 ObFrameContext
frame_context(ObClient
*client
, Window win
)
690 if (moveresize_in_progress
)
691 return OB_FRAME_CONTEXT_MOVE_RESIZE
;
693 if (win
== RootWindow(ob_display
, ob_screen
))
694 return OB_FRAME_CONTEXT_DESKTOP
;
695 if (client
== NULL
) return OB_FRAME_CONTEXT_NONE
;
696 if (win
== client
->window
) {
697 /* conceptually, this is the desktop, as far as users are
699 if (client
->type
== OB_CLIENT_TYPE_DESKTOP
)
700 return OB_FRAME_CONTEXT_DESKTOP
;
701 return OB_FRAME_CONTEXT_CLIENT
;
704 self
= client
->frame
;
705 if (win
== self
->plate
) {
706 /* conceptually, this is the desktop, as far as users are
708 if (client
->type
== OB_CLIENT_TYPE_DESKTOP
)
709 return OB_FRAME_CONTEXT_DESKTOP
;
710 return OB_FRAME_CONTEXT_CLIENT
;
713 if (win
== self
->window
) return OB_FRAME_CONTEXT_FRAME
;
714 if (win
== self
->title
) return OB_FRAME_CONTEXT_TITLEBAR
;
715 if (win
== self
->label
) return OB_FRAME_CONTEXT_TITLEBAR
;
716 if (win
== self
->handle
) return OB_FRAME_CONTEXT_HANDLE
;
717 if (win
== self
->lgrip
) return OB_FRAME_CONTEXT_BLCORNER
;
718 if (win
== self
->rgrip
) return OB_FRAME_CONTEXT_BRCORNER
;
719 if (win
== self
->tlresize
) return OB_FRAME_CONTEXT_TLCORNER
;
720 if (win
== self
->trresize
) return OB_FRAME_CONTEXT_TRCORNER
;
721 if (win
== self
->max
) return OB_FRAME_CONTEXT_MAXIMIZE
;
722 if (win
== self
->iconify
) return OB_FRAME_CONTEXT_ICONIFY
;
723 if (win
== self
->close
) return OB_FRAME_CONTEXT_CLOSE
;
724 if (win
== self
->icon
) return OB_FRAME_CONTEXT_ICON
;
725 if (win
== self
->desk
) return OB_FRAME_CONTEXT_ALLDESKTOPS
;
726 if (win
== self
->shade
) return OB_FRAME_CONTEXT_SHADE
;
728 return OB_FRAME_CONTEXT_NONE
;
731 void frame_client_gravity(ObFrame
*self
, int *x
, int *y
)
734 switch (self
->client
->gravity
) {
736 case NorthWestGravity
:
737 case SouthWestGravity
:
744 *x
-= (self
->size
.left
+ self
->size
.right
) / 2;
747 case NorthEastGravity
:
748 case SouthEastGravity
:
750 *x
-= self
->size
.left
+ self
->size
.right
;
755 *x
-= self
->size
.left
;
760 switch (self
->client
->gravity
) {
762 case NorthWestGravity
:
763 case NorthEastGravity
:
770 *y
-= (self
->size
.top
+ self
->size
.bottom
) / 2;
773 case SouthWestGravity
:
774 case SouthEastGravity
:
776 *y
-= self
->size
.top
+ self
->size
.bottom
;
781 *y
-= self
->size
.top
;
786 void frame_frame_gravity(ObFrame
*self
, int *x
, int *y
)
789 switch (self
->client
->gravity
) {
791 case NorthWestGravity
:
793 case SouthWestGravity
:
798 *x
+= (self
->size
.left
+ self
->size
.right
) / 2;
800 case NorthEastGravity
:
802 case SouthEastGravity
:
803 *x
+= self
->size
.left
+ self
->size
.right
;
807 *x
+= self
->size
.left
;
812 switch (self
->client
->gravity
) {
814 case NorthWestGravity
:
816 case NorthEastGravity
:
821 *y
+= (self
->size
.top
+ self
->size
.bottom
) / 2;
823 case SouthWestGravity
:
825 case SouthEastGravity
:
826 *y
+= self
->size
.top
+ self
->size
.bottom
;
830 *y
+= self
->size
.top
;
835 static void flash_done(gpointer data
)
837 ObFrame
*self
= data
;
839 if (self
->focused
!= self
->flash_on
)
840 frame_adjust_focus(self
, self
->focused
);
843 static gboolean
flash_timeout(gpointer data
)
845 ObFrame
*self
= data
;
848 g_get_current_time(&now
);
849 if (now
.tv_sec
> self
->flash_end
.tv_sec
||
850 (now
.tv_sec
== self
->flash_end
.tv_sec
&&
851 now
.tv_usec
>= self
->flash_end
.tv_usec
))
852 self
->flashing
= FALSE
;
855 return FALSE
; /* we are done */
857 self
->flash_on
= !self
->flash_on
;
861 focused
= self
->focused
; /* save the focused flag */
862 frame_adjust_focus(self
, self
->flash_on
);
863 self
->focused
= focused
;
866 return TRUE
; /* go again */
869 void frame_flash_start(ObFrame
*self
)
871 self
->flash_on
= self
->focused
;
874 ob_main_loop_timeout_add(ob_main_loop
,
875 G_USEC_PER_SEC
* 0.75,
879 g_get_current_time(&self
->flash_end
);
880 g_time_val_add(&self
->flash_end
, G_USEC_PER_SEC
* 5);
882 self
->flashing
= TRUE
;
885 void frame_flash_stop(ObFrame
*self
)
887 self
->flashing
= FALSE
;