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
, unsigned long 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 */
69 mask
= CWOverrideRedirect
| CWEventMask
;
70 attrib
.event_mask
= FRAME_EVENTMASK
;
71 attrib
.override_redirect
= TRUE
;
72 self
->window
= createWindow(RootWindow(ob_display
, ob_screen
),
76 self
->plate
= createWindow(self
->window
, mask
, &attrib
);
79 attrib
.event_mask
= ELEMENT_EVENTMASK
;
80 self
->title
= createWindow(self
->window
, mask
, &attrib
);
83 attrib
.cursor
= ob_cursor(OB_CURSOR_NORTHWEST
);
84 self
->tlresize
= createWindow(self
->title
, mask
, &attrib
);
85 attrib
.cursor
= ob_cursor(OB_CURSOR_NORTHEAST
);
86 self
->trresize
= createWindow(self
->title
, mask
, &attrib
);
89 self
->label
= createWindow(self
->title
, mask
, &attrib
);
90 self
->max
= createWindow(self
->title
, mask
, &attrib
);
91 self
->close
= createWindow(self
->title
, mask
, &attrib
);
92 self
->desk
= createWindow(self
->title
, mask
, &attrib
);
93 self
->shade
= createWindow(self
->title
, mask
, &attrib
);
94 self
->icon
= createWindow(self
->title
, mask
, &attrib
);
95 self
->iconify
= createWindow(self
->title
, mask
, &attrib
);
96 self
->handle
= createWindow(self
->window
, mask
, &attrib
);
99 attrib
.cursor
= ob_cursor(OB_CURSOR_SOUTHWEST
);
100 self
->lgrip
= createWindow(self
->handle
, mask
, &attrib
);
101 attrib
.cursor
= ob_cursor(OB_CURSOR_SOUTHEAST
);
102 self
->rgrip
= createWindow(self
->handle
, mask
, &attrib
);
104 self
->focused
= FALSE
;
106 /* the other stuff is shown based on decor settings */
107 XMapWindow(ob_display
, self
->plate
);
108 XMapWindow(ob_display
, self
->lgrip
);
109 XMapWindow(ob_display
, self
->rgrip
);
110 XMapWindow(ob_display
, self
->label
);
112 self
->max_press
= self
->close_press
= self
->desk_press
=
113 self
->iconify_press
= self
->shade_press
= FALSE
;
114 self
->max_hover
= self
->close_hover
= self
->desk_hover
=
115 self
->iconify_hover
= self
->shade_hover
= FALSE
;
117 set_theme_statics(self
);
119 return (ObFrame
*)self
;
122 static void set_theme_statics(ObFrame
*self
)
124 /* set colors/appearance/sizes for stuff that doesn't change */
125 XSetWindowBorder(ob_display
, self
->window
,
126 RrColorPixel(ob_rr_theme
->b_color
));
127 XSetWindowBorder(ob_display
, self
->title
,
128 RrColorPixel(ob_rr_theme
->b_color
));
129 XSetWindowBorder(ob_display
, self
->handle
,
130 RrColorPixel(ob_rr_theme
->b_color
));
131 XSetWindowBorder(ob_display
, self
->rgrip
,
132 RrColorPixel(ob_rr_theme
->b_color
));
133 XSetWindowBorder(ob_display
, self
->lgrip
,
134 RrColorPixel(ob_rr_theme
->b_color
));
136 XResizeWindow(ob_display
, self
->max
,
137 ob_rr_theme
->button_size
, ob_rr_theme
->button_size
);
138 XResizeWindow(ob_display
, self
->iconify
,
139 ob_rr_theme
->button_size
, ob_rr_theme
->button_size
);
140 XResizeWindow(ob_display
, self
->icon
,
141 ob_rr_theme
->button_size
+ 2, ob_rr_theme
->button_size
+ 2);
142 XResizeWindow(ob_display
, self
->close
,
143 ob_rr_theme
->button_size
, ob_rr_theme
->button_size
);
144 XResizeWindow(ob_display
, self
->desk
,
145 ob_rr_theme
->button_size
, ob_rr_theme
->button_size
);
146 XResizeWindow(ob_display
, self
->shade
,
147 ob_rr_theme
->button_size
, ob_rr_theme
->button_size
);
148 XResizeWindow(ob_display
, self
->lgrip
,
149 ob_rr_theme
->grip_width
, ob_rr_theme
->handle_height
);
150 XResizeWindow(ob_display
, self
->rgrip
,
151 ob_rr_theme
->grip_width
, ob_rr_theme
->handle_height
);
152 XResizeWindow(ob_display
, self
->tlresize
,
153 ob_rr_theme
->grip_width
, ob_rr_theme
->handle_height
);
154 XResizeWindow(ob_display
, self
->trresize
,
155 ob_rr_theme
->grip_width
, ob_rr_theme
->handle_height
);
157 /* set up the dynamic appearances */
158 self
->a_unfocused_title
= RrAppearanceCopy(ob_rr_theme
->a_unfocused_title
);
159 self
->a_focused_title
= RrAppearanceCopy(ob_rr_theme
->a_focused_title
);
160 self
->a_unfocused_label
= RrAppearanceCopy(ob_rr_theme
->a_unfocused_label
);
161 self
->a_focused_label
= RrAppearanceCopy(ob_rr_theme
->a_focused_label
);
162 self
->a_unfocused_handle
=
163 RrAppearanceCopy(ob_rr_theme
->a_unfocused_handle
);
164 self
->a_focused_handle
= RrAppearanceCopy(ob_rr_theme
->a_focused_handle
);
165 self
->a_icon
= RrAppearanceCopy(ob_rr_theme
->a_icon
);
168 static void free_theme_statics(ObFrame
*self
)
170 RrAppearanceFree(self
->a_unfocused_title
);
171 RrAppearanceFree(self
->a_focused_title
);
172 RrAppearanceFree(self
->a_unfocused_label
);
173 RrAppearanceFree(self
->a_focused_label
);
174 RrAppearanceFree(self
->a_unfocused_handle
);
175 RrAppearanceFree(self
->a_focused_handle
);
176 RrAppearanceFree(self
->a_icon
);
179 static void frame_free(ObFrame
*self
)
181 free_theme_statics(self
);
183 XDestroyWindow(ob_display
, self
->window
);
188 void frame_show(ObFrame
*self
)
190 if (!self
->visible
) {
191 self
->visible
= TRUE
;
192 XMapWindow(ob_display
, self
->window
);
196 void frame_hide(ObFrame
*self
)
199 self
->visible
= FALSE
;
200 self
->client
->ignore_unmaps
++;
201 XUnmapWindow(ob_display
, self
->window
);
205 void frame_adjust_theme(ObFrame
*self
)
207 free_theme_statics(self
);
208 set_theme_statics(self
);
211 void frame_adjust_shape(ObFrame
*self
)
217 if (!self
->client
->shaped
) {
218 /* clear the shape on the frame window */
219 XShapeCombineMask(ob_display
, self
->window
, ShapeBounding
,
220 self
->innersize
.left
,
224 /* make the frame's shape match the clients */
225 XShapeCombineShape(ob_display
, self
->window
, ShapeBounding
,
226 self
->innersize
.left
,
228 self
->client
->window
,
229 ShapeBounding
, ShapeSet
);
232 if (self
->decorations
& OB_FRAME_DECOR_TITLEBAR
) {
233 xrect
[0].x
= -ob_rr_theme
->bwidth
;
234 xrect
[0].y
= -ob_rr_theme
->bwidth
;
235 xrect
[0].width
= self
->width
+ self
->rbwidth
* 2;
236 xrect
[0].height
= ob_rr_theme
->title_height
+
241 if (self
->decorations
& OB_FRAME_DECOR_HANDLE
) {
242 xrect
[1].x
= -ob_rr_theme
->bwidth
;
243 xrect
[1].y
= FRAME_HANDLE_Y(self
);
244 xrect
[1].width
= self
->width
+ self
->rbwidth
* 2;
245 xrect
[1].height
= ob_rr_theme
->handle_height
+
250 XShapeCombineRectangles(ob_display
, self
->window
,
251 ShapeBounding
, 0, 0, xrect
, num
,
252 ShapeUnion
, Unsorted
);
257 void frame_adjust_area(ObFrame
*self
, gboolean moved
,
258 gboolean resized
, gboolean fake
)
262 oldsize
= self
->size
;
265 self
->decorations
= self
->client
->decorations
;
266 self
->max_horz
= self
->client
->max_horz
;
268 if (self
->decorations
& OB_FRAME_DECOR_BORDER
) {
269 self
->bwidth
= ob_rr_theme
->bwidth
;
270 self
->cbwidth_x
= self
->cbwidth_y
= ob_rr_theme
->cbwidth
;
272 self
->bwidth
= self
->cbwidth_x
= self
->cbwidth_y
= 0;
274 self
->rbwidth
= self
->bwidth
;
277 self
->bwidth
= self
->cbwidth_x
= 0;
279 STRUT_SET(self
->innersize
,
284 self
->width
= self
->client
->area
.width
+ self
->cbwidth_x
* 2 -
285 (self
->max_horz
? self
->rbwidth
* 2 : 0);
286 self
->width
= MAX(self
->width
, 1); /* no lower than 1 */
288 /* set border widths */
290 XSetWindowBorderWidth(ob_display
, self
->window
, self
->bwidth
);
291 XSetWindowBorderWidth(ob_display
, self
->title
, self
->rbwidth
);
292 XSetWindowBorderWidth(ob_display
, self
->handle
, self
->rbwidth
);
293 XSetWindowBorderWidth(ob_display
, self
->lgrip
, self
->rbwidth
);
294 XSetWindowBorderWidth(ob_display
, self
->rgrip
, self
->rbwidth
);
297 if (self
->decorations
& OB_FRAME_DECOR_TITLEBAR
)
298 self
->innersize
.top
+= ob_rr_theme
->title_height
+ self
->rbwidth
+
299 (self
->rbwidth
- self
->bwidth
);
300 if (self
->decorations
& OB_FRAME_DECOR_HANDLE
&&
301 ob_rr_theme
->show_handle
)
302 self
->innersize
.bottom
+= ob_rr_theme
->handle_height
+
303 self
->rbwidth
+ (self
->rbwidth
- self
->bwidth
);
305 /* they all default off, they're turned on in layout_title */
309 self
->iconify_x
= -1;
314 /* position/size and map/unmap all the windows */
317 if (self
->decorations
& OB_FRAME_DECOR_TITLEBAR
) {
318 XMoveResizeWindow(ob_display
, self
->title
,
319 -self
->bwidth
, -self
->bwidth
,
320 self
->width
, ob_rr_theme
->title_height
);
321 XMapWindow(ob_display
, self
->title
);
323 if (self
->decorations
& OB_FRAME_DECOR_GRIPS
) {
324 XMoveWindow(ob_display
, self
->tlresize
, 0, 0);
325 XMoveWindow(ob_display
, self
->trresize
,
326 self
->width
- ob_rr_theme
->grip_width
, 0);
327 XMapWindow(ob_display
, self
->tlresize
);
328 XMapWindow(ob_display
, self
->trresize
);
330 XUnmapWindow(ob_display
, self
->tlresize
);
331 XUnmapWindow(ob_display
, self
->trresize
);
334 XUnmapWindow(ob_display
, self
->title
);
337 if (self
->decorations
& OB_FRAME_DECOR_TITLEBAR
)
338 /* layout the title bar elements */
342 if (self
->decorations
& OB_FRAME_DECOR_HANDLE
&&
343 ob_rr_theme
->show_handle
)
345 XMoveResizeWindow(ob_display
, self
->handle
,
346 -self
->bwidth
, FRAME_HANDLE_Y(self
),
347 self
->width
, ob_rr_theme
->handle_height
);
348 XMapWindow(ob_display
, self
->handle
);
350 if (self
->decorations
& OB_FRAME_DECOR_GRIPS
) {
351 XMoveWindow(ob_display
, self
->lgrip
,
352 -self
->rbwidth
, -self
->rbwidth
);
353 XMoveWindow(ob_display
, self
->rgrip
,
354 -self
->rbwidth
+ self
->width
-
355 ob_rr_theme
->grip_width
, -self
->rbwidth
);
356 XMapWindow(ob_display
, self
->lgrip
);
357 XMapWindow(ob_display
, self
->rgrip
);
359 XUnmapWindow(ob_display
, self
->lgrip
);
360 XUnmapWindow(ob_display
, self
->rgrip
);
363 /* XXX make a subwindow with these dimentions?
364 ob_rr_theme->grip_width + self->bwidth, 0,
365 self->width - (ob_rr_theme->grip_width + self->bwidth) * 2,
366 ob_rr_theme->handle_height);
369 XUnmapWindow(ob_display
, self
->handle
);
371 /* move and resize the plate */
372 XMoveResizeWindow(ob_display
, self
->plate
,
373 self
->innersize
.left
- self
->cbwidth_x
,
374 self
->innersize
.top
- self
->cbwidth_y
,
375 self
->client
->area
.width
+ self
->cbwidth_x
* 2,
376 self
->client
->area
.height
+ self
->cbwidth_y
* 2);
377 /* when the client has StaticGravity, it likes to move around. */
378 XMoveWindow(ob_display
, self
->client
->window
,
379 self
->cbwidth_x
, self
->cbwidth_y
);
382 STRUT_SET(self
->size
,
383 self
->innersize
.left
+ self
->bwidth
,
384 self
->innersize
.top
+ self
->bwidth
,
385 self
->innersize
.right
+ self
->bwidth
,
386 self
->innersize
.bottom
+ self
->bwidth
);
389 /* shading can change without being moved or resized */
390 RECT_SET_SIZE(self
->area
,
391 self
->client
->area
.width
+
392 self
->size
.left
+ self
->size
.right
,
393 (self
->client
->shaded
?
394 ob_rr_theme
->title_height
+ self
->rbwidth
* 2:
395 self
->client
->area
.height
+
396 self
->size
.top
+ self
->size
.bottom
));
399 /* find the new coordinates, done after setting the frame.size, for
400 frame_client_gravity. */
401 self
->area
.x
= self
->client
->area
.x
;
402 self
->area
.y
= self
->client
->area
.y
;
403 frame_client_gravity(self
, &self
->area
.x
, &self
->area
.y
);
407 /* move and resize the top level frame.
408 shading can change without being moved or resized */
409 XMoveResizeWindow(ob_display
, self
->window
,
410 self
->area
.x
, self
->area
.y
,
411 self
->area
.width
- self
->bwidth
* 2,
412 self
->area
.height
- self
->bwidth
* 2);
415 framerender_frame(self
);
417 frame_adjust_shape(self
);
420 if (!STRUT_EQUAL(self
->size
, oldsize
)) {
422 vals
[0] = self
->size
.left
;
423 vals
[1] = self
->size
.right
;
424 vals
[2] = self
->size
.top
;
425 vals
[3] = self
->size
.bottom
;
426 PROP_SETA32(self
->client
->window
, kde_net_wm_frame_strut
,
430 /* if this occurs while we are focus cycling, the indicator needs to
432 if (focus_cycle_target
== self
->client
)
433 focus_cycle_draw_indicator();
437 void frame_adjust_state(ObFrame
*self
)
439 framerender_frame(self
);
442 void frame_adjust_focus(ObFrame
*self
, gboolean hilite
)
444 self
->focused
= hilite
;
445 framerender_frame(self
);
448 void frame_adjust_title(ObFrame
*self
)
450 framerender_frame(self
);
453 void frame_adjust_icon(ObFrame
*self
)
455 framerender_frame(self
);
458 void frame_grab_client(ObFrame
*self
, ObClient
*client
)
460 self
->client
= client
;
462 /* reparent the client to the frame */
463 XReparentWindow(ob_display
, client
->window
, self
->plate
, 0, 0);
465 When reparenting the client window, it is usually not mapped yet, since
466 this occurs from a MapRequest. However, in the case where Openbox is
467 starting up, the window is already mapped, so we'll see unmap events for
468 it. There are 2 unmap events generated that we see, one with the 'event'
469 member set the root window, and one set to the client, but both get
470 handled and need to be ignored.
472 if (ob_state() == OB_STATE_STARTING
)
473 client
->ignore_unmaps
+= 2;
475 /* select the event mask on the client's parent (to receive config/map
476 req's) the ButtonPress is to catch clicks on the client border */
477 XSelectInput(ob_display
, self
->plate
, PLATE_EVENTMASK
);
479 /* map the client so it maps when the frame does */
480 XMapWindow(ob_display
, client
->window
);
482 frame_adjust_area(self
, TRUE
, TRUE
, FALSE
);
484 /* set all the windows for the frame in the window_map */
485 g_hash_table_insert(window_map
, &self
->window
, client
);
486 g_hash_table_insert(window_map
, &self
->plate
, client
);
487 g_hash_table_insert(window_map
, &self
->title
, client
);
488 g_hash_table_insert(window_map
, &self
->label
, client
);
489 g_hash_table_insert(window_map
, &self
->max
, client
);
490 g_hash_table_insert(window_map
, &self
->close
, client
);
491 g_hash_table_insert(window_map
, &self
->desk
, client
);
492 g_hash_table_insert(window_map
, &self
->shade
, client
);
493 g_hash_table_insert(window_map
, &self
->icon
, client
);
494 g_hash_table_insert(window_map
, &self
->iconify
, client
);
495 g_hash_table_insert(window_map
, &self
->handle
, client
);
496 g_hash_table_insert(window_map
, &self
->lgrip
, client
);
497 g_hash_table_insert(window_map
, &self
->rgrip
, client
);
498 g_hash_table_insert(window_map
, &self
->tlresize
, client
);
499 g_hash_table_insert(window_map
, &self
->trresize
, client
);
502 void frame_release_client(ObFrame
*self
, ObClient
*client
)
506 g_assert(self
->client
== client
);
508 /* check if the app has already reparented its window away */
509 if (XCheckTypedWindowEvent(ob_display
, client
->window
,
510 ReparentNotify
, &ev
)) {
511 XPutBackEvent(ob_display
, &ev
);
513 /* re-map the window since the unmanaging process unmaps it */
515 /* XXX ... um no it doesnt it unmaps its parent, the window itself
516 retains its mapped state, no?! XXX
517 XMapWindow(ob_display, client->window); */
519 /* according to the ICCCM - if the client doesn't reparent itself,
520 then we will reparent the window to root for them */
521 XReparentWindow(ob_display
, client
->window
,
522 RootWindow(ob_display
, ob_screen
),
527 /* remove all the windows for the frame from the window_map */
528 g_hash_table_remove(window_map
, &self
->window
);
529 g_hash_table_remove(window_map
, &self
->plate
);
530 g_hash_table_remove(window_map
, &self
->title
);
531 g_hash_table_remove(window_map
, &self
->label
);
532 g_hash_table_remove(window_map
, &self
->max
);
533 g_hash_table_remove(window_map
, &self
->close
);
534 g_hash_table_remove(window_map
, &self
->desk
);
535 g_hash_table_remove(window_map
, &self
->shade
);
536 g_hash_table_remove(window_map
, &self
->icon
);
537 g_hash_table_remove(window_map
, &self
->iconify
);
538 g_hash_table_remove(window_map
, &self
->handle
);
539 g_hash_table_remove(window_map
, &self
->lgrip
);
540 g_hash_table_remove(window_map
, &self
->rgrip
);
541 g_hash_table_remove(window_map
, &self
->tlresize
);
542 g_hash_table_remove(window_map
, &self
->trresize
);
544 ob_main_loop_timeout_remove_data(ob_main_loop
, flash_timeout
, self
);
549 static void layout_title(ObFrame
*self
)
553 gboolean n
, d
, i
, l
, m
, c
, s
;
555 n
= d
= i
= l
= m
= c
= s
= FALSE
;
557 /* figure out whats being shown, and the width of the label */
558 self
->label_width
= self
->width
- (ob_rr_theme
->padding
+ 1) * 2;
559 for (lc
= config_title_layout
; *lc
!= '\0'; ++lc
) {
562 if (n
) { *lc
= ' '; break; } /* rm duplicates */
564 self
->label_width
-= (ob_rr_theme
->button_size
+ 2 +
565 ob_rr_theme
->padding
+ 1);
568 if (d
) { *lc
= ' '; break; } /* rm duplicates */
570 self
->label_width
-= (ob_rr_theme
->button_size
+
571 ob_rr_theme
->padding
+ 1);
574 if (s
) { *lc
= ' '; break; } /* rm duplicates */
576 self
->label_width
-= (ob_rr_theme
->button_size
+
577 ob_rr_theme
->padding
+ 1);
580 if (i
) { *lc
= ' '; break; } /* rm duplicates */
582 self
->label_width
-= (ob_rr_theme
->button_size
+
583 ob_rr_theme
->padding
+ 1);
586 if (l
) { *lc
= ' '; break; } /* rm duplicates */
590 if (m
) { *lc
= ' '; break; } /* rm duplicates */
592 self
->label_width
-= (ob_rr_theme
->button_size
+
593 ob_rr_theme
->padding
+ 1);
596 if (c
) { *lc
= ' '; break; } /* rm duplicates */
598 self
->label_width
-= (ob_rr_theme
->button_size
+
599 ob_rr_theme
->padding
+ 1);
603 if (self
->label_width
< 1) self
->label_width
= 1;
605 XResizeWindow(ob_display
, self
->label
, self
->label_width
,
606 ob_rr_theme
->label_height
);
608 if (!n
) XUnmapWindow(ob_display
, self
->icon
);
609 if (!d
) XUnmapWindow(ob_display
, self
->desk
);
610 if (!s
) XUnmapWindow(ob_display
, self
->shade
);
611 if (!i
) XUnmapWindow(ob_display
, self
->iconify
);
612 if (!l
) XUnmapWindow(ob_display
, self
->label
);
613 if (!m
) XUnmapWindow(ob_display
, self
->max
);
614 if (!c
) XUnmapWindow(ob_display
, self
->close
);
616 x
= ob_rr_theme
->padding
+ 1;
617 for (lc
= config_title_layout
; *lc
!= '\0'; ++lc
) {
622 XMapWindow(ob_display
, self
->icon
);
623 XMoveWindow(ob_display
, self
->icon
, x
, ob_rr_theme
->padding
);
624 x
+= ob_rr_theme
->button_size
+ 2 + ob_rr_theme
->padding
+ 1;
629 XMapWindow(ob_display
, self
->desk
);
630 XMoveWindow(ob_display
, self
->desk
, x
, ob_rr_theme
->padding
+ 1);
631 x
+= ob_rr_theme
->button_size
+ ob_rr_theme
->padding
+ 1;
636 XMapWindow(ob_display
, self
->shade
);
637 XMoveWindow(ob_display
, self
->shade
, x
, ob_rr_theme
->padding
+ 1);
638 x
+= ob_rr_theme
->button_size
+ ob_rr_theme
->padding
+ 1;
643 XMapWindow(ob_display
, self
->iconify
);
644 XMoveWindow(ob_display
,self
->iconify
, x
, ob_rr_theme
->padding
+ 1);
645 x
+= ob_rr_theme
->button_size
+ ob_rr_theme
->padding
+ 1;
650 XMapWindow(ob_display
, self
->label
);
651 XMoveWindow(ob_display
, self
->label
, x
, ob_rr_theme
->padding
);
652 x
+= self
->label_width
+ ob_rr_theme
->padding
+ 1;
657 XMapWindow(ob_display
, self
->max
);
658 XMoveWindow(ob_display
, self
->max
, x
, ob_rr_theme
->padding
+ 1);
659 x
+= ob_rr_theme
->button_size
+ ob_rr_theme
->padding
+ 1;
664 XMapWindow(ob_display
, self
->close
);
665 XMoveWindow(ob_display
, self
->close
, x
, ob_rr_theme
->padding
+ 1);
666 x
+= ob_rr_theme
->button_size
+ ob_rr_theme
->padding
+ 1;
672 ObFrameContext
frame_context_from_string(const gchar
*name
)
674 if (!g_ascii_strcasecmp("Desktop", name
))
675 return OB_FRAME_CONTEXT_DESKTOP
;
676 else if (!g_ascii_strcasecmp("Client", name
))
677 return OB_FRAME_CONTEXT_CLIENT
;
678 else if (!g_ascii_strcasecmp("Titlebar", name
))
679 return OB_FRAME_CONTEXT_TITLEBAR
;
680 else if (!g_ascii_strcasecmp("Handle", name
))
681 return OB_FRAME_CONTEXT_HANDLE
;
682 else if (!g_ascii_strcasecmp("Frame", name
))
683 return OB_FRAME_CONTEXT_FRAME
;
684 else if (!g_ascii_strcasecmp("TLCorner", name
))
685 return OB_FRAME_CONTEXT_TLCORNER
;
686 else if (!g_ascii_strcasecmp("TRCorner", name
))
687 return OB_FRAME_CONTEXT_TRCORNER
;
688 else if (!g_ascii_strcasecmp("BLCorner", name
))
689 return OB_FRAME_CONTEXT_BLCORNER
;
690 else if (!g_ascii_strcasecmp("BRCorner", name
))
691 return OB_FRAME_CONTEXT_BRCORNER
;
692 else if (!g_ascii_strcasecmp("Maximize", name
))
693 return OB_FRAME_CONTEXT_MAXIMIZE
;
694 else if (!g_ascii_strcasecmp("AllDesktops", name
))
695 return OB_FRAME_CONTEXT_ALLDESKTOPS
;
696 else if (!g_ascii_strcasecmp("Shade", name
))
697 return OB_FRAME_CONTEXT_SHADE
;
698 else if (!g_ascii_strcasecmp("Iconify", name
))
699 return OB_FRAME_CONTEXT_ICONIFY
;
700 else if (!g_ascii_strcasecmp("Icon", name
))
701 return OB_FRAME_CONTEXT_ICON
;
702 else if (!g_ascii_strcasecmp("Close", name
))
703 return OB_FRAME_CONTEXT_CLOSE
;
704 else if (!g_ascii_strcasecmp("MoveResize", name
))
705 return OB_FRAME_CONTEXT_MOVE_RESIZE
;
706 return OB_FRAME_CONTEXT_NONE
;
709 ObFrameContext
frame_context(ObClient
*client
, Window win
)
713 if (moveresize_in_progress
)
714 return OB_FRAME_CONTEXT_MOVE_RESIZE
;
716 if (win
== RootWindow(ob_display
, ob_screen
))
717 return OB_FRAME_CONTEXT_DESKTOP
;
718 if (client
== NULL
) return OB_FRAME_CONTEXT_NONE
;
719 if (win
== client
->window
) {
720 /* conceptually, this is the desktop, as far as users are
722 if (client
->type
== OB_CLIENT_TYPE_DESKTOP
)
723 return OB_FRAME_CONTEXT_DESKTOP
;
724 return OB_FRAME_CONTEXT_CLIENT
;
727 self
= client
->frame
;
728 if (win
== self
->plate
) {
729 /* conceptually, this is the desktop, as far as users are
731 if (client
->type
== OB_CLIENT_TYPE_DESKTOP
)
732 return OB_FRAME_CONTEXT_DESKTOP
;
733 return OB_FRAME_CONTEXT_CLIENT
;
736 if (win
== self
->window
) return OB_FRAME_CONTEXT_FRAME
;
737 if (win
== self
->title
) return OB_FRAME_CONTEXT_TITLEBAR
;
738 if (win
== self
->label
) return OB_FRAME_CONTEXT_TITLEBAR
;
739 if (win
== self
->handle
) return OB_FRAME_CONTEXT_HANDLE
;
740 if (win
== self
->lgrip
) return OB_FRAME_CONTEXT_BLCORNER
;
741 if (win
== self
->rgrip
) return OB_FRAME_CONTEXT_BRCORNER
;
742 if (win
== self
->tlresize
) return OB_FRAME_CONTEXT_TLCORNER
;
743 if (win
== self
->trresize
) return OB_FRAME_CONTEXT_TRCORNER
;
744 if (win
== self
->max
) return OB_FRAME_CONTEXT_MAXIMIZE
;
745 if (win
== self
->iconify
) return OB_FRAME_CONTEXT_ICONIFY
;
746 if (win
== self
->close
) return OB_FRAME_CONTEXT_CLOSE
;
747 if (win
== self
->icon
) return OB_FRAME_CONTEXT_ICON
;
748 if (win
== self
->desk
) return OB_FRAME_CONTEXT_ALLDESKTOPS
;
749 if (win
== self
->shade
) return OB_FRAME_CONTEXT_SHADE
;
751 return OB_FRAME_CONTEXT_NONE
;
754 void frame_client_gravity(ObFrame
*self
, int *x
, int *y
)
757 switch (self
->client
->gravity
) {
759 case NorthWestGravity
:
760 case SouthWestGravity
:
767 *x
-= (self
->size
.left
+ self
->size
.right
) / 2;
770 case NorthEastGravity
:
771 case SouthEastGravity
:
773 *x
-= self
->size
.left
+ self
->size
.right
;
778 *x
-= self
->size
.left
;
783 switch (self
->client
->gravity
) {
785 case NorthWestGravity
:
786 case NorthEastGravity
:
793 *y
-= (self
->size
.top
+ self
->size
.bottom
) / 2;
796 case SouthWestGravity
:
797 case SouthEastGravity
:
799 *y
-= self
->size
.top
+ self
->size
.bottom
;
804 *y
-= self
->size
.top
;
809 void frame_frame_gravity(ObFrame
*self
, int *x
, int *y
)
812 switch (self
->client
->gravity
) {
814 case NorthWestGravity
:
816 case SouthWestGravity
:
821 *x
+= (self
->size
.left
+ self
->size
.right
) / 2;
823 case NorthEastGravity
:
825 case SouthEastGravity
:
826 *x
+= self
->size
.left
+ self
->size
.right
;
830 *x
+= self
->size
.left
;
835 switch (self
->client
->gravity
) {
837 case NorthWestGravity
:
839 case NorthEastGravity
:
844 *y
+= (self
->size
.top
+ self
->size
.bottom
) / 2;
846 case SouthWestGravity
:
848 case SouthEastGravity
:
849 *y
+= self
->size
.top
+ self
->size
.bottom
;
853 *y
+= self
->size
.top
;
858 static void flash_done(gpointer data
)
860 ObFrame
*self
= data
;
862 if (self
->focused
!= self
->flash_on
)
863 frame_adjust_focus(self
, self
->focused
);
866 static gboolean
flash_timeout(gpointer data
)
868 ObFrame
*self
= data
;
871 g_get_current_time(&now
);
872 if (now
.tv_sec
> self
->flash_end
.tv_sec
||
873 (now
.tv_sec
== self
->flash_end
.tv_sec
&&
874 now
.tv_usec
>= self
->flash_end
.tv_usec
))
875 self
->flashing
= FALSE
;
878 return FALSE
; /* we are done */
880 self
->flash_on
= !self
->flash_on
;
881 if (!self
->focused
) {
882 frame_adjust_focus(self
, self
->flash_on
);
883 self
->focused
= FALSE
;
886 return TRUE
; /* go again */
889 void frame_flash_start(ObFrame
*self
)
891 self
->flash_on
= self
->focused
;
894 ob_main_loop_timeout_add(ob_main_loop
,
895 G_USEC_PER_SEC
* 0.6,
899 g_get_current_time(&self
->flash_end
);
900 g_time_val_add(&self
->flash_end
, G_USEC_PER_SEC
* 5);
902 self
->flashing
= TRUE
;
905 void frame_flash_stop(ObFrame
*self
)
907 self
->flashing
= FALSE
;