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"
27 #include "moveresize.h"
28 #include "render/theme.h"
30 #define PLATE_EVENTMASK (SubstructureRedirectMask | ButtonPressMask)
31 #define FRAME_EVENTMASK (EnterWindowMask | LeaveWindowMask | \
32 ButtonPressMask | ButtonReleaseMask | \
34 #define ELEMENT_EVENTMASK (ButtonPressMask | ButtonReleaseMask | \
35 ButtonMotionMask | ExposureMask | \
36 EnterWindowMask | LeaveWindowMask)
38 #define FRAME_HANDLE_Y(f) (f->innersize.top + f->client->area.height + \
41 static void layout_title(ObFrame
*self
);
42 static void flash_done(gpointer data
);
43 static gboolean
flash_timeout(gpointer data
);
45 static void set_theme_statics(ObFrame
*self
);
46 static void free_theme_statics(ObFrame
*self
);
48 static Window
createWindow(Window parent
, unsigned long mask
,
49 XSetWindowAttributes
*attrib
)
51 return XCreateWindow(ob_display
, parent
, 0, 0, 1, 1, 0,
52 RrDepth(ob_rr_inst
), InputOutput
,
53 RrVisual(ob_rr_inst
), mask
, attrib
);
59 XSetWindowAttributes attrib
;
63 self
= g_new0(ObFrame
, 1);
65 self
->obscured
= TRUE
;
67 /* create all of the decor windows */
68 mask
= CWOverrideRedirect
| CWEventMask
;
69 attrib
.event_mask
= FRAME_EVENTMASK
;
70 attrib
.override_redirect
= TRUE
;
71 self
->window
= createWindow(RootWindow(ob_display
, ob_screen
),
75 self
->plate
= createWindow(self
->window
, mask
, &attrib
);
78 attrib
.event_mask
= ELEMENT_EVENTMASK
;
79 self
->title
= createWindow(self
->window
, mask
, &attrib
);
82 attrib
.cursor
= ob_cursor(OB_CURSOR_NORTHWEST
);
83 self
->tlresize
= createWindow(self
->title
, mask
, &attrib
);
84 attrib
.cursor
= ob_cursor(OB_CURSOR_NORTHEAST
);
85 self
->trresize
= createWindow(self
->title
, mask
, &attrib
);
88 self
->label
= createWindow(self
->title
, mask
, &attrib
);
89 self
->max
= createWindow(self
->title
, mask
, &attrib
);
90 self
->close
= createWindow(self
->title
, mask
, &attrib
);
91 self
->desk
= createWindow(self
->title
, mask
, &attrib
);
92 self
->shade
= createWindow(self
->title
, mask
, &attrib
);
93 self
->icon
= createWindow(self
->title
, mask
, &attrib
);
94 self
->iconify
= createWindow(self
->title
, mask
, &attrib
);
95 self
->handle
= createWindow(self
->window
, mask
, &attrib
);
98 attrib
.cursor
= ob_cursor(OB_CURSOR_SOUTHWEST
);
99 self
->lgrip
= createWindow(self
->handle
, mask
, &attrib
);
100 attrib
.cursor
= ob_cursor(OB_CURSOR_SOUTHEAST
);
101 self
->rgrip
= createWindow(self
->handle
, mask
, &attrib
);
103 self
->focused
= FALSE
;
105 /* the other stuff is shown based on decor settings */
106 XMapWindow(ob_display
, self
->plate
);
107 XMapWindow(ob_display
, self
->lgrip
);
108 XMapWindow(ob_display
, self
->rgrip
);
109 XMapWindow(ob_display
, self
->label
);
111 self
->max_press
= self
->close_press
= self
->desk_press
=
112 self
->iconify_press
= self
->shade_press
= FALSE
;
113 self
->max_hover
= self
->close_hover
= self
->desk_hover
=
114 self
->iconify_hover
= self
->shade_hover
= FALSE
;
116 set_theme_statics(self
);
118 return (ObFrame
*)self
;
121 static void set_theme_statics(ObFrame
*self
)
123 /* set colors/appearance/sizes for stuff that doesn't change */
124 XSetWindowBorder(ob_display
, self
->window
, ob_rr_theme
->b_color
->pixel
);
125 XSetWindowBorder(ob_display
, self
->title
, ob_rr_theme
->b_color
->pixel
);
126 XSetWindowBorder(ob_display
, self
->handle
, ob_rr_theme
->b_color
->pixel
);
127 XSetWindowBorder(ob_display
, self
->rgrip
, ob_rr_theme
->b_color
->pixel
);
128 XSetWindowBorder(ob_display
, self
->lgrip
, ob_rr_theme
->b_color
->pixel
);
130 XResizeWindow(ob_display
, self
->max
,
131 ob_rr_theme
->button_size
, ob_rr_theme
->button_size
);
132 XResizeWindow(ob_display
, self
->iconify
,
133 ob_rr_theme
->button_size
, ob_rr_theme
->button_size
);
134 XResizeWindow(ob_display
, self
->icon
,
135 ob_rr_theme
->button_size
+ 2, ob_rr_theme
->button_size
+ 2);
136 XResizeWindow(ob_display
, self
->close
,
137 ob_rr_theme
->button_size
, ob_rr_theme
->button_size
);
138 XResizeWindow(ob_display
, self
->desk
,
139 ob_rr_theme
->button_size
, ob_rr_theme
->button_size
);
140 XResizeWindow(ob_display
, self
->shade
,
141 ob_rr_theme
->button_size
, ob_rr_theme
->button_size
);
142 XResizeWindow(ob_display
, self
->lgrip
,
143 ob_rr_theme
->grip_width
, ob_rr_theme
->handle_height
);
144 XResizeWindow(ob_display
, self
->rgrip
,
145 ob_rr_theme
->grip_width
, ob_rr_theme
->handle_height
);
146 XResizeWindow(ob_display
, self
->tlresize
,
147 ob_rr_theme
->grip_width
, ob_rr_theme
->handle_height
);
148 XResizeWindow(ob_display
, self
->trresize
,
149 ob_rr_theme
->grip_width
, ob_rr_theme
->handle_height
);
151 /* set up the dynamic appearances */
152 self
->a_unfocused_title
= RrAppearanceCopy(ob_rr_theme
->a_unfocused_title
);
153 self
->a_focused_title
= RrAppearanceCopy(ob_rr_theme
->a_focused_title
);
154 self
->a_unfocused_label
= RrAppearanceCopy(ob_rr_theme
->a_unfocused_label
);
155 self
->a_focused_label
= RrAppearanceCopy(ob_rr_theme
->a_focused_label
);
156 self
->a_unfocused_handle
=
157 RrAppearanceCopy(ob_rr_theme
->a_unfocused_handle
);
158 self
->a_focused_handle
= RrAppearanceCopy(ob_rr_theme
->a_focused_handle
);
159 self
->a_icon
= RrAppearanceCopy(ob_rr_theme
->a_icon
);
162 static void free_theme_statics(ObFrame
*self
)
164 RrAppearanceFree(self
->a_unfocused_title
);
165 RrAppearanceFree(self
->a_focused_title
);
166 RrAppearanceFree(self
->a_unfocused_label
);
167 RrAppearanceFree(self
->a_focused_label
);
168 RrAppearanceFree(self
->a_unfocused_handle
);
169 RrAppearanceFree(self
->a_focused_handle
);
170 RrAppearanceFree(self
->a_icon
);
173 static void frame_free(ObFrame
*self
)
175 free_theme_statics(self
);
177 XDestroyWindow(ob_display
, self
->window
);
182 void frame_show(ObFrame
*self
)
184 if (!self
->visible
) {
185 self
->visible
= TRUE
;
186 XMapWindow(ob_display
, self
->window
);
190 void frame_hide(ObFrame
*self
)
193 self
->visible
= FALSE
;
194 self
->client
->ignore_unmaps
++;
195 XUnmapWindow(ob_display
, self
->window
);
199 void frame_adjust_theme(ObFrame
*self
)
201 free_theme_statics(self
);
202 set_theme_statics(self
);
205 void frame_adjust_shape(ObFrame
*self
)
211 if (!self
->client
->shaped
) {
212 /* clear the shape on the frame window */
213 XShapeCombineMask(ob_display
, self
->window
, ShapeBounding
,
214 self
->innersize
.left
,
218 /* make the frame's shape match the clients */
219 XShapeCombineShape(ob_display
, self
->window
, ShapeBounding
,
220 self
->innersize
.left
,
222 self
->client
->window
,
223 ShapeBounding
, ShapeSet
);
226 if (self
->decorations
& OB_FRAME_DECOR_TITLEBAR
) {
227 xrect
[0].x
= -ob_rr_theme
->bwidth
;
228 xrect
[0].y
= -ob_rr_theme
->bwidth
;
229 xrect
[0].width
= self
->width
+ self
->rbwidth
* 2;
230 xrect
[0].height
= ob_rr_theme
->title_height
+
235 if (self
->decorations
& OB_FRAME_DECOR_HANDLE
) {
236 xrect
[1].x
= -ob_rr_theme
->bwidth
;
237 xrect
[1].y
= FRAME_HANDLE_Y(self
);
238 xrect
[1].width
= self
->width
+ self
->rbwidth
* 2;
239 xrect
[1].height
= ob_rr_theme
->handle_height
+
244 XShapeCombineRectangles(ob_display
, self
->window
,
245 ShapeBounding
, 0, 0, xrect
, num
,
246 ShapeUnion
, Unsorted
);
251 void frame_adjust_area(ObFrame
*self
, gboolean moved
,
252 gboolean resized
, gboolean fake
)
256 oldsize
= self
->size
;
259 self
->decorations
= self
->client
->decorations
;
260 self
->max_horz
= self
->client
->max_horz
;
262 if (self
->decorations
& OB_FRAME_DECOR_BORDER
) {
263 self
->bwidth
= ob_rr_theme
->bwidth
;
264 self
->cbwidth_x
= self
->cbwidth_y
= ob_rr_theme
->cbwidth
;
266 self
->bwidth
= self
->cbwidth_x
= self
->cbwidth_y
= 0;
268 self
->rbwidth
= self
->bwidth
;
271 self
->bwidth
= self
->cbwidth_x
= 0;
273 STRUT_SET(self
->innersize
,
278 self
->width
= self
->client
->area
.width
+ self
->cbwidth_x
* 2 -
279 (self
->max_horz
? self
->rbwidth
* 2 : 0);
280 self
->width
= MAX(self
->width
, 1); /* no lower than 1 */
282 /* set border widths */
284 XSetWindowBorderWidth(ob_display
, self
->window
, self
->bwidth
);
285 XSetWindowBorderWidth(ob_display
, self
->title
, self
->rbwidth
);
286 XSetWindowBorderWidth(ob_display
, self
->handle
, self
->rbwidth
);
287 XSetWindowBorderWidth(ob_display
, self
->lgrip
, self
->rbwidth
);
288 XSetWindowBorderWidth(ob_display
, self
->rgrip
, self
->rbwidth
);
291 if (self
->decorations
& OB_FRAME_DECOR_TITLEBAR
)
292 self
->innersize
.top
+= ob_rr_theme
->title_height
+ self
->rbwidth
+
293 (self
->rbwidth
- self
->bwidth
);
294 if (self
->decorations
& OB_FRAME_DECOR_HANDLE
&&
295 ob_rr_theme
->show_handle
)
296 self
->innersize
.bottom
+= ob_rr_theme
->handle_height
+
297 self
->rbwidth
+ (self
->rbwidth
- self
->bwidth
);
299 /* they all default off, they're turned on in layout_title */
303 self
->iconify_x
= -1;
308 /* position/size and map/unmap all the windows */
311 if (self
->decorations
& OB_FRAME_DECOR_TITLEBAR
) {
312 XMoveResizeWindow(ob_display
, self
->title
,
313 -self
->bwidth
, -self
->bwidth
,
314 self
->width
, ob_rr_theme
->title_height
);
315 XMapWindow(ob_display
, self
->title
);
317 if (self
->decorations
& OB_FRAME_DECOR_GRIPS
) {
318 XMoveWindow(ob_display
, self
->tlresize
, 0, 0);
319 XMoveWindow(ob_display
, self
->trresize
,
320 self
->width
- ob_rr_theme
->grip_width
, 0);
321 XMapWindow(ob_display
, self
->tlresize
);
322 XMapWindow(ob_display
, self
->trresize
);
324 XUnmapWindow(ob_display
, self
->tlresize
);
325 XUnmapWindow(ob_display
, self
->trresize
);
328 XUnmapWindow(ob_display
, self
->title
);
331 if (self
->decorations
& OB_FRAME_DECOR_TITLEBAR
)
332 /* layout the title bar elements */
336 if (self
->decorations
& OB_FRAME_DECOR_HANDLE
&&
337 ob_rr_theme
->show_handle
)
339 XMoveResizeWindow(ob_display
, self
->handle
,
340 -self
->bwidth
, FRAME_HANDLE_Y(self
),
341 self
->width
, ob_rr_theme
->handle_height
);
342 XMapWindow(ob_display
, self
->handle
);
344 if (self
->decorations
& OB_FRAME_DECOR_GRIPS
) {
345 XMoveWindow(ob_display
, self
->lgrip
,
346 -self
->rbwidth
, -self
->rbwidth
);
347 XMoveWindow(ob_display
, self
->rgrip
,
348 -self
->rbwidth
+ self
->width
-
349 ob_rr_theme
->grip_width
, -self
->rbwidth
);
350 XMapWindow(ob_display
, self
->lgrip
);
351 XMapWindow(ob_display
, self
->rgrip
);
353 XUnmapWindow(ob_display
, self
->lgrip
);
354 XUnmapWindow(ob_display
, self
->rgrip
);
357 /* XXX make a subwindow with these dimentions?
358 ob_rr_theme->grip_width + self->bwidth, 0,
359 self->width - (ob_rr_theme->grip_width + self->bwidth) * 2,
360 ob_rr_theme->handle_height);
363 XUnmapWindow(ob_display
, self
->handle
);
365 /* move and resize the plate */
366 XMoveResizeWindow(ob_display
, self
->plate
,
367 self
->innersize
.left
- self
->cbwidth_x
,
368 self
->innersize
.top
- self
->cbwidth_y
,
369 self
->client
->area
.width
+ self
->cbwidth_x
* 2,
370 self
->client
->area
.height
+ self
->cbwidth_y
* 2);
371 /* when the client has StaticGravity, it likes to move around. */
372 XMoveWindow(ob_display
, self
->client
->window
,
373 self
->cbwidth_x
, self
->cbwidth_y
);
376 STRUT_SET(self
->size
,
377 self
->innersize
.left
+ self
->bwidth
,
378 self
->innersize
.top
+ self
->bwidth
,
379 self
->innersize
.right
+ self
->bwidth
,
380 self
->innersize
.bottom
+ self
->bwidth
);
383 /* shading can change without being moved or resized */
384 RECT_SET_SIZE(self
->area
,
385 self
->client
->area
.width
+
386 self
->size
.left
+ self
->size
.right
,
387 (self
->client
->shaded
?
388 ob_rr_theme
->title_height
+ self
->rbwidth
* 2:
389 self
->client
->area
.height
+
390 self
->size
.top
+ self
->size
.bottom
));
393 /* find the new coordinates, done after setting the frame.size, for
394 frame_client_gravity. */
395 self
->area
.x
= self
->client
->area
.x
;
396 self
->area
.y
= self
->client
->area
.y
;
397 frame_client_gravity(self
, &self
->area
.x
, &self
->area
.y
);
401 /* move and resize the top level frame.
402 shading can change without being moved or resized */
403 XMoveResizeWindow(ob_display
, self
->window
,
404 self
->area
.x
, self
->area
.y
,
405 self
->area
.width
- self
->bwidth
* 2,
406 self
->area
.height
- self
->bwidth
* 2);
409 framerender_frame(self
);
411 frame_adjust_shape(self
);
414 if (!STRUT_EQUAL(self
->size
, oldsize
)) {
416 vals
[0] = self
->size
.left
;
417 vals
[1] = self
->size
.right
;
418 vals
[2] = self
->size
.top
;
419 vals
[3] = self
->size
.bottom
;
420 PROP_SETA32(self
->client
->window
, kde_net_wm_frame_strut
,
426 void frame_adjust_state(ObFrame
*self
)
428 framerender_frame(self
);
431 void frame_adjust_focus(ObFrame
*self
, gboolean hilite
)
433 self
->focused
= hilite
;
434 framerender_frame(self
);
437 void frame_adjust_title(ObFrame
*self
)
439 framerender_frame(self
);
442 void frame_adjust_icon(ObFrame
*self
)
444 framerender_frame(self
);
447 void frame_grab_client(ObFrame
*self
, ObClient
*client
)
449 self
->client
= client
;
451 /* reparent the client to the frame */
452 XReparentWindow(ob_display
, client
->window
, self
->plate
, 0, 0);
454 When reparenting the client window, it is usually not mapped yet, since
455 this occurs from a MapRequest. However, in the case where Openbox is
456 starting up, the window is already mapped, so we'll see unmap events for
457 it. There are 2 unmap events generated that we see, one with the 'event'
458 member set the root window, and one set to the client, but both get
459 handled and need to be ignored.
461 if (ob_state() == OB_STATE_STARTING
)
462 client
->ignore_unmaps
+= 2;
464 /* select the event mask on the client's parent (to receive config/map
465 req's) the ButtonPress is to catch clicks on the client border */
466 XSelectInput(ob_display
, self
->plate
, PLATE_EVENTMASK
);
468 /* map the client so it maps when the frame does */
469 XMapWindow(ob_display
, client
->window
);
471 frame_adjust_area(self
, TRUE
, TRUE
, FALSE
);
473 /* set all the windows for the frame in the window_map */
474 g_hash_table_insert(window_map
, &self
->window
, client
);
475 g_hash_table_insert(window_map
, &self
->plate
, client
);
476 g_hash_table_insert(window_map
, &self
->title
, client
);
477 g_hash_table_insert(window_map
, &self
->label
, client
);
478 g_hash_table_insert(window_map
, &self
->max
, client
);
479 g_hash_table_insert(window_map
, &self
->close
, client
);
480 g_hash_table_insert(window_map
, &self
->desk
, client
);
481 g_hash_table_insert(window_map
, &self
->shade
, client
);
482 g_hash_table_insert(window_map
, &self
->icon
, client
);
483 g_hash_table_insert(window_map
, &self
->iconify
, client
);
484 g_hash_table_insert(window_map
, &self
->handle
, client
);
485 g_hash_table_insert(window_map
, &self
->lgrip
, client
);
486 g_hash_table_insert(window_map
, &self
->rgrip
, client
);
487 g_hash_table_insert(window_map
, &self
->tlresize
, client
);
488 g_hash_table_insert(window_map
, &self
->trresize
, client
);
491 void frame_release_client(ObFrame
*self
, ObClient
*client
)
495 g_assert(self
->client
== client
);
497 /* check if the app has already reparented its window away */
498 if (XCheckTypedWindowEvent(ob_display
, client
->window
,
499 ReparentNotify
, &ev
)) {
500 XPutBackEvent(ob_display
, &ev
);
502 /* re-map the window since the unmanaging process unmaps it */
504 /* XXX ... um no it doesnt it unmaps its parent, the window itself
505 retains its mapped state, no?! XXX
506 XMapWindow(ob_display, client->window); */
508 /* according to the ICCCM - if the client doesn't reparent itself,
509 then we will reparent the window to root for them */
510 XReparentWindow(ob_display
, client
->window
,
511 RootWindow(ob_display
, ob_screen
),
516 /* remove all the windows for the frame from the window_map */
517 g_hash_table_remove(window_map
, &self
->window
);
518 g_hash_table_remove(window_map
, &self
->plate
);
519 g_hash_table_remove(window_map
, &self
->title
);
520 g_hash_table_remove(window_map
, &self
->label
);
521 g_hash_table_remove(window_map
, &self
->max
);
522 g_hash_table_remove(window_map
, &self
->close
);
523 g_hash_table_remove(window_map
, &self
->desk
);
524 g_hash_table_remove(window_map
, &self
->shade
);
525 g_hash_table_remove(window_map
, &self
->icon
);
526 g_hash_table_remove(window_map
, &self
->iconify
);
527 g_hash_table_remove(window_map
, &self
->handle
);
528 g_hash_table_remove(window_map
, &self
->lgrip
);
529 g_hash_table_remove(window_map
, &self
->rgrip
);
530 g_hash_table_remove(window_map
, &self
->tlresize
);
531 g_hash_table_remove(window_map
, &self
->trresize
);
533 ob_main_loop_timeout_remove_data(ob_main_loop
, flash_timeout
, self
);
538 static void layout_title(ObFrame
*self
)
542 gboolean n
, d
, i
, l
, m
, c
, s
;
544 n
= d
= i
= l
= m
= c
= s
= FALSE
;
546 /* figure out whats being shown, and the width of the label */
547 self
->label_width
= self
->width
- (ob_rr_theme
->padding
+ 1) * 2;
548 for (lc
= config_title_layout
; *lc
!= '\0'; ++lc
) {
551 if (n
) { *lc
= ' '; break; } /* rm duplicates */
553 self
->label_width
-= (ob_rr_theme
->button_size
+ 2 +
554 ob_rr_theme
->padding
+ 1);
557 if (d
) { *lc
= ' '; break; } /* rm duplicates */
559 self
->label_width
-= (ob_rr_theme
->button_size
+
560 ob_rr_theme
->padding
+ 1);
563 if (s
) { *lc
= ' '; break; } /* rm duplicates */
565 self
->label_width
-= (ob_rr_theme
->button_size
+
566 ob_rr_theme
->padding
+ 1);
569 if (i
) { *lc
= ' '; break; } /* rm duplicates */
571 self
->label_width
-= (ob_rr_theme
->button_size
+
572 ob_rr_theme
->padding
+ 1);
575 if (l
) { *lc
= ' '; break; } /* rm duplicates */
579 if (m
) { *lc
= ' '; break; } /* rm duplicates */
581 self
->label_width
-= (ob_rr_theme
->button_size
+
582 ob_rr_theme
->padding
+ 1);
585 if (c
) { *lc
= ' '; break; } /* rm duplicates */
587 self
->label_width
-= (ob_rr_theme
->button_size
+
588 ob_rr_theme
->padding
+ 1);
592 if (self
->label_width
< 1) self
->label_width
= 1;
594 XResizeWindow(ob_display
, self
->label
, self
->label_width
,
595 ob_rr_theme
->label_height
);
597 if (!n
) XUnmapWindow(ob_display
, self
->icon
);
598 if (!d
) XUnmapWindow(ob_display
, self
->desk
);
599 if (!s
) XUnmapWindow(ob_display
, self
->shade
);
600 if (!i
) XUnmapWindow(ob_display
, self
->iconify
);
601 if (!l
) XUnmapWindow(ob_display
, self
->label
);
602 if (!m
) XUnmapWindow(ob_display
, self
->max
);
603 if (!c
) XUnmapWindow(ob_display
, self
->close
);
605 x
= ob_rr_theme
->padding
+ 1;
606 for (lc
= config_title_layout
; *lc
!= '\0'; ++lc
) {
611 XMapWindow(ob_display
, self
->icon
);
612 XMoveWindow(ob_display
, self
->icon
, x
, ob_rr_theme
->padding
);
613 x
+= ob_rr_theme
->button_size
+ 2 + ob_rr_theme
->padding
+ 1;
618 XMapWindow(ob_display
, self
->desk
);
619 XMoveWindow(ob_display
, self
->desk
, x
, ob_rr_theme
->padding
+ 1);
620 x
+= ob_rr_theme
->button_size
+ ob_rr_theme
->padding
+ 1;
625 XMapWindow(ob_display
, self
->shade
);
626 XMoveWindow(ob_display
, self
->shade
, x
, ob_rr_theme
->padding
+ 1);
627 x
+= ob_rr_theme
->button_size
+ ob_rr_theme
->padding
+ 1;
632 XMapWindow(ob_display
, self
->iconify
);
633 XMoveWindow(ob_display
,self
->iconify
, x
, ob_rr_theme
->padding
+ 1);
634 x
+= ob_rr_theme
->button_size
+ ob_rr_theme
->padding
+ 1;
639 XMapWindow(ob_display
, self
->label
);
640 XMoveWindow(ob_display
, self
->label
, x
, ob_rr_theme
->padding
);
641 x
+= self
->label_width
+ ob_rr_theme
->padding
+ 1;
646 XMapWindow(ob_display
, self
->max
);
647 XMoveWindow(ob_display
, self
->max
, x
, ob_rr_theme
->padding
+ 1);
648 x
+= ob_rr_theme
->button_size
+ ob_rr_theme
->padding
+ 1;
653 XMapWindow(ob_display
, self
->close
);
654 XMoveWindow(ob_display
, self
->close
, x
, ob_rr_theme
->padding
+ 1);
655 x
+= ob_rr_theme
->button_size
+ ob_rr_theme
->padding
+ 1;
661 ObFrameContext
frame_context_from_string(const gchar
*name
)
663 if (!g_ascii_strcasecmp("Desktop", name
))
664 return OB_FRAME_CONTEXT_DESKTOP
;
665 else if (!g_ascii_strcasecmp("Client", name
))
666 return OB_FRAME_CONTEXT_CLIENT
;
667 else if (!g_ascii_strcasecmp("Titlebar", name
))
668 return OB_FRAME_CONTEXT_TITLEBAR
;
669 else if (!g_ascii_strcasecmp("Handle", name
))
670 return OB_FRAME_CONTEXT_HANDLE
;
671 else if (!g_ascii_strcasecmp("Frame", name
))
672 return OB_FRAME_CONTEXT_FRAME
;
673 else if (!g_ascii_strcasecmp("TLCorner", name
))
674 return OB_FRAME_CONTEXT_TLCORNER
;
675 else if (!g_ascii_strcasecmp("TRCorner", name
))
676 return OB_FRAME_CONTEXT_TRCORNER
;
677 else if (!g_ascii_strcasecmp("BLCorner", name
))
678 return OB_FRAME_CONTEXT_BLCORNER
;
679 else if (!g_ascii_strcasecmp("BRCorner", name
))
680 return OB_FRAME_CONTEXT_BRCORNER
;
681 else if (!g_ascii_strcasecmp("Maximize", name
))
682 return OB_FRAME_CONTEXT_MAXIMIZE
;
683 else if (!g_ascii_strcasecmp("AllDesktops", name
))
684 return OB_FRAME_CONTEXT_ALLDESKTOPS
;
685 else if (!g_ascii_strcasecmp("Shade", name
))
686 return OB_FRAME_CONTEXT_SHADE
;
687 else if (!g_ascii_strcasecmp("Iconify", name
))
688 return OB_FRAME_CONTEXT_ICONIFY
;
689 else if (!g_ascii_strcasecmp("Icon", name
))
690 return OB_FRAME_CONTEXT_ICON
;
691 else if (!g_ascii_strcasecmp("Close", name
))
692 return OB_FRAME_CONTEXT_CLOSE
;
693 else if (!g_ascii_strcasecmp("MoveResize", name
))
694 return OB_FRAME_CONTEXT_MOVE_RESIZE
;
695 return OB_FRAME_CONTEXT_NONE
;
698 ObFrameContext
frame_context(ObClient
*client
, Window win
)
702 if (moveresize_in_progress
)
703 return OB_FRAME_CONTEXT_MOVE_RESIZE
;
705 if (win
== RootWindow(ob_display
, ob_screen
))
706 return OB_FRAME_CONTEXT_DESKTOP
;
707 if (client
== NULL
) return OB_FRAME_CONTEXT_NONE
;
708 if (win
== client
->window
) {
709 /* conceptually, this is the desktop, as far as users are
711 if (client
->type
== OB_CLIENT_TYPE_DESKTOP
)
712 return OB_FRAME_CONTEXT_DESKTOP
;
713 return OB_FRAME_CONTEXT_CLIENT
;
716 self
= client
->frame
;
717 if (win
== self
->plate
) {
718 /* conceptually, this is the desktop, as far as users are
720 if (client
->type
== OB_CLIENT_TYPE_DESKTOP
)
721 return OB_FRAME_CONTEXT_DESKTOP
;
722 return OB_FRAME_CONTEXT_CLIENT
;
725 if (win
== self
->window
) return OB_FRAME_CONTEXT_FRAME
;
726 if (win
== self
->title
) return OB_FRAME_CONTEXT_TITLEBAR
;
727 if (win
== self
->label
) return OB_FRAME_CONTEXT_TITLEBAR
;
728 if (win
== self
->handle
) return OB_FRAME_CONTEXT_HANDLE
;
729 if (win
== self
->lgrip
) return OB_FRAME_CONTEXT_BLCORNER
;
730 if (win
== self
->rgrip
) return OB_FRAME_CONTEXT_BRCORNER
;
731 if (win
== self
->tlresize
) return OB_FRAME_CONTEXT_TLCORNER
;
732 if (win
== self
->trresize
) return OB_FRAME_CONTEXT_TRCORNER
;
733 if (win
== self
->max
) return OB_FRAME_CONTEXT_MAXIMIZE
;
734 if (win
== self
->iconify
) return OB_FRAME_CONTEXT_ICONIFY
;
735 if (win
== self
->close
) return OB_FRAME_CONTEXT_CLOSE
;
736 if (win
== self
->icon
) return OB_FRAME_CONTEXT_ICON
;
737 if (win
== self
->desk
) return OB_FRAME_CONTEXT_ALLDESKTOPS
;
738 if (win
== self
->shade
) return OB_FRAME_CONTEXT_SHADE
;
740 return OB_FRAME_CONTEXT_NONE
;
743 void frame_client_gravity(ObFrame
*self
, int *x
, int *y
)
746 switch (self
->client
->gravity
) {
748 case NorthWestGravity
:
749 case SouthWestGravity
:
756 *x
-= (self
->size
.left
+ self
->size
.right
) / 2;
759 case NorthEastGravity
:
760 case SouthEastGravity
:
762 *x
-= self
->size
.left
+ self
->size
.right
;
767 *x
-= self
->size
.left
;
772 switch (self
->client
->gravity
) {
774 case NorthWestGravity
:
775 case NorthEastGravity
:
782 *y
-= (self
->size
.top
+ self
->size
.bottom
) / 2;
785 case SouthWestGravity
:
786 case SouthEastGravity
:
788 *y
-= self
->size
.top
+ self
->size
.bottom
;
793 *y
-= self
->size
.top
;
798 void frame_frame_gravity(ObFrame
*self
, int *x
, int *y
)
801 switch (self
->client
->gravity
) {
803 case NorthWestGravity
:
805 case SouthWestGravity
:
810 *x
+= (self
->size
.left
+ self
->size
.right
) / 2;
812 case NorthEastGravity
:
814 case SouthEastGravity
:
815 *x
+= self
->size
.left
+ self
->size
.right
;
819 *x
+= self
->size
.left
;
824 switch (self
->client
->gravity
) {
826 case NorthWestGravity
:
828 case NorthEastGravity
:
833 *y
+= (self
->size
.top
+ self
->size
.bottom
) / 2;
835 case SouthWestGravity
:
837 case SouthEastGravity
:
838 *y
+= self
->size
.top
+ self
->size
.bottom
;
842 *y
+= self
->size
.top
;
847 static void flash_done(gpointer data
)
849 ObFrame
*self
= data
;
851 if (self
->focused
!= self
->flash_on
)
852 frame_adjust_focus(self
, self
->focused
);
855 static gboolean
flash_timeout(gpointer data
)
857 ObFrame
*self
= data
;
860 g_get_current_time(&now
);
861 if (now
.tv_sec
> self
->flash_end
.tv_sec
||
862 (now
.tv_sec
== self
->flash_end
.tv_sec
&&
863 now
.tv_usec
>= self
->flash_end
.tv_usec
))
864 self
->flashing
= FALSE
;
867 return FALSE
; /* we are done */
869 self
->flash_on
= !self
->flash_on
;
870 if (!self
->focused
) {
871 frame_adjust_focus(self
, self
->flash_on
);
872 self
->focused
= FALSE
;
875 return TRUE
; /* go again */
878 void frame_flash_start(ObFrame
*self
)
880 self
->flash_on
= self
->focused
;
883 ob_main_loop_timeout_add(ob_main_loop
,
884 G_USEC_PER_SEC
* 0.6,
888 g_get_current_time(&self
->flash_end
);
889 g_time_val_add(&self
->flash_end
, G_USEC_PER_SEC
* 5);
891 self
->flashing
= TRUE
;
894 void frame_flash_stop(ObFrame
*self
)
896 self
->flashing
= FALSE
;