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
, ob_rr_theme
->b_color
->pixel
);
126 XSetWindowBorder(ob_display
, self
->title
, ob_rr_theme
->b_color
->pixel
);
127 XSetWindowBorder(ob_display
, self
->handle
, ob_rr_theme
->b_color
->pixel
);
128 XSetWindowBorder(ob_display
, self
->rgrip
, ob_rr_theme
->b_color
->pixel
);
129 XSetWindowBorder(ob_display
, self
->lgrip
, ob_rr_theme
->b_color
->pixel
);
131 XResizeWindow(ob_display
, self
->max
,
132 ob_rr_theme
->button_size
, ob_rr_theme
->button_size
);
133 XResizeWindow(ob_display
, self
->iconify
,
134 ob_rr_theme
->button_size
, ob_rr_theme
->button_size
);
135 XResizeWindow(ob_display
, self
->icon
,
136 ob_rr_theme
->button_size
+ 2, ob_rr_theme
->button_size
+ 2);
137 XResizeWindow(ob_display
, self
->close
,
138 ob_rr_theme
->button_size
, ob_rr_theme
->button_size
);
139 XResizeWindow(ob_display
, self
->desk
,
140 ob_rr_theme
->button_size
, ob_rr_theme
->button_size
);
141 XResizeWindow(ob_display
, self
->shade
,
142 ob_rr_theme
->button_size
, ob_rr_theme
->button_size
);
143 XResizeWindow(ob_display
, self
->lgrip
,
144 ob_rr_theme
->grip_width
, ob_rr_theme
->handle_height
);
145 XResizeWindow(ob_display
, self
->rgrip
,
146 ob_rr_theme
->grip_width
, ob_rr_theme
->handle_height
);
147 XResizeWindow(ob_display
, self
->tlresize
,
148 ob_rr_theme
->grip_width
, ob_rr_theme
->handle_height
);
149 XResizeWindow(ob_display
, self
->trresize
,
150 ob_rr_theme
->grip_width
, ob_rr_theme
->handle_height
);
152 /* set up the dynamic appearances */
153 self
->a_unfocused_title
= RrAppearanceCopy(ob_rr_theme
->a_unfocused_title
);
154 self
->a_focused_title
= RrAppearanceCopy(ob_rr_theme
->a_focused_title
);
155 self
->a_unfocused_label
= RrAppearanceCopy(ob_rr_theme
->a_unfocused_label
);
156 self
->a_focused_label
= RrAppearanceCopy(ob_rr_theme
->a_focused_label
);
157 self
->a_unfocused_handle
=
158 RrAppearanceCopy(ob_rr_theme
->a_unfocused_handle
);
159 self
->a_focused_handle
= RrAppearanceCopy(ob_rr_theme
->a_focused_handle
);
160 self
->a_icon
= RrAppearanceCopy(ob_rr_theme
->a_icon
);
163 static void free_theme_statics(ObFrame
*self
)
165 RrAppearanceFree(self
->a_unfocused_title
);
166 RrAppearanceFree(self
->a_focused_title
);
167 RrAppearanceFree(self
->a_unfocused_label
);
168 RrAppearanceFree(self
->a_focused_label
);
169 RrAppearanceFree(self
->a_unfocused_handle
);
170 RrAppearanceFree(self
->a_focused_handle
);
171 RrAppearanceFree(self
->a_icon
);
174 static void frame_free(ObFrame
*self
)
176 free_theme_statics(self
);
178 XDestroyWindow(ob_display
, self
->window
);
183 void frame_show(ObFrame
*self
)
185 if (!self
->visible
) {
186 self
->visible
= TRUE
;
187 XMapWindow(ob_display
, self
->window
);
191 void frame_hide(ObFrame
*self
)
194 self
->visible
= FALSE
;
195 self
->client
->ignore_unmaps
++;
196 XUnmapWindow(ob_display
, self
->window
);
200 void frame_adjust_theme(ObFrame
*self
)
202 free_theme_statics(self
);
203 set_theme_statics(self
);
206 void frame_adjust_shape(ObFrame
*self
)
212 if (!self
->client
->shaped
) {
213 /* clear the shape on the frame window */
214 XShapeCombineMask(ob_display
, self
->window
, ShapeBounding
,
215 self
->innersize
.left
,
219 /* make the frame's shape match the clients */
220 XShapeCombineShape(ob_display
, self
->window
, ShapeBounding
,
221 self
->innersize
.left
,
223 self
->client
->window
,
224 ShapeBounding
, ShapeSet
);
227 if (self
->decorations
& OB_FRAME_DECOR_TITLEBAR
) {
228 xrect
[0].x
= -ob_rr_theme
->bwidth
;
229 xrect
[0].y
= -ob_rr_theme
->bwidth
;
230 xrect
[0].width
= self
->width
+ self
->rbwidth
* 2;
231 xrect
[0].height
= ob_rr_theme
->title_height
+
236 if (self
->decorations
& OB_FRAME_DECOR_HANDLE
) {
237 xrect
[1].x
= -ob_rr_theme
->bwidth
;
238 xrect
[1].y
= FRAME_HANDLE_Y(self
);
239 xrect
[1].width
= self
->width
+ self
->rbwidth
* 2;
240 xrect
[1].height
= ob_rr_theme
->handle_height
+
245 XShapeCombineRectangles(ob_display
, self
->window
,
246 ShapeBounding
, 0, 0, xrect
, num
,
247 ShapeUnion
, Unsorted
);
252 void frame_adjust_area(ObFrame
*self
, gboolean moved
,
253 gboolean resized
, gboolean fake
)
257 oldsize
= self
->size
;
260 self
->decorations
= self
->client
->decorations
;
261 self
->max_horz
= self
->client
->max_horz
;
263 if (self
->decorations
& OB_FRAME_DECOR_BORDER
) {
264 self
->bwidth
= ob_rr_theme
->bwidth
;
265 self
->cbwidth_x
= self
->cbwidth_y
= ob_rr_theme
->cbwidth
;
267 self
->bwidth
= self
->cbwidth_x
= self
->cbwidth_y
= 0;
269 self
->rbwidth
= self
->bwidth
;
272 self
->bwidth
= self
->cbwidth_x
= 0;
274 STRUT_SET(self
->innersize
,
279 self
->width
= self
->client
->area
.width
+ self
->cbwidth_x
* 2 -
280 (self
->max_horz
? self
->rbwidth
* 2 : 0);
281 self
->width
= MAX(self
->width
, 1); /* no lower than 1 */
283 /* set border widths */
285 XSetWindowBorderWidth(ob_display
, self
->window
, self
->bwidth
);
286 XSetWindowBorderWidth(ob_display
, self
->title
, self
->rbwidth
);
287 XSetWindowBorderWidth(ob_display
, self
->handle
, self
->rbwidth
);
288 XSetWindowBorderWidth(ob_display
, self
->lgrip
, self
->rbwidth
);
289 XSetWindowBorderWidth(ob_display
, self
->rgrip
, self
->rbwidth
);
292 if (self
->decorations
& OB_FRAME_DECOR_TITLEBAR
)
293 self
->innersize
.top
+= ob_rr_theme
->title_height
+ self
->rbwidth
+
294 (self
->rbwidth
- self
->bwidth
);
295 if (self
->decorations
& OB_FRAME_DECOR_HANDLE
&&
296 ob_rr_theme
->show_handle
)
297 self
->innersize
.bottom
+= ob_rr_theme
->handle_height
+
298 self
->rbwidth
+ (self
->rbwidth
- self
->bwidth
);
300 /* they all default off, they're turned on in layout_title */
304 self
->iconify_x
= -1;
309 /* position/size and map/unmap all the windows */
312 if (self
->decorations
& OB_FRAME_DECOR_TITLEBAR
) {
313 XMoveResizeWindow(ob_display
, self
->title
,
314 -self
->bwidth
, -self
->bwidth
,
315 self
->width
, ob_rr_theme
->title_height
);
316 XMapWindow(ob_display
, self
->title
);
318 if (self
->decorations
& OB_FRAME_DECOR_GRIPS
) {
319 XMoveWindow(ob_display
, self
->tlresize
, 0, 0);
320 XMoveWindow(ob_display
, self
->trresize
,
321 self
->width
- ob_rr_theme
->grip_width
, 0);
322 XMapWindow(ob_display
, self
->tlresize
);
323 XMapWindow(ob_display
, self
->trresize
);
325 XUnmapWindow(ob_display
, self
->tlresize
);
326 XUnmapWindow(ob_display
, self
->trresize
);
329 XUnmapWindow(ob_display
, self
->title
);
332 if (self
->decorations
& OB_FRAME_DECOR_TITLEBAR
)
333 /* layout the title bar elements */
337 if (self
->decorations
& OB_FRAME_DECOR_HANDLE
&&
338 ob_rr_theme
->show_handle
)
340 XMoveResizeWindow(ob_display
, self
->handle
,
341 -self
->bwidth
, FRAME_HANDLE_Y(self
),
342 self
->width
, ob_rr_theme
->handle_height
);
343 XMapWindow(ob_display
, self
->handle
);
345 if (self
->decorations
& OB_FRAME_DECOR_GRIPS
) {
346 XMoveWindow(ob_display
, self
->lgrip
,
347 -self
->rbwidth
, -self
->rbwidth
);
348 XMoveWindow(ob_display
, self
->rgrip
,
349 -self
->rbwidth
+ self
->width
-
350 ob_rr_theme
->grip_width
, -self
->rbwidth
);
351 XMapWindow(ob_display
, self
->lgrip
);
352 XMapWindow(ob_display
, self
->rgrip
);
354 XUnmapWindow(ob_display
, self
->lgrip
);
355 XUnmapWindow(ob_display
, self
->rgrip
);
358 /* XXX make a subwindow with these dimentions?
359 ob_rr_theme->grip_width + self->bwidth, 0,
360 self->width - (ob_rr_theme->grip_width + self->bwidth) * 2,
361 ob_rr_theme->handle_height);
364 XUnmapWindow(ob_display
, self
->handle
);
366 /* move and resize the plate */
367 XMoveResizeWindow(ob_display
, self
->plate
,
368 self
->innersize
.left
- self
->cbwidth_x
,
369 self
->innersize
.top
- self
->cbwidth_y
,
370 self
->client
->area
.width
+ self
->cbwidth_x
* 2,
371 self
->client
->area
.height
+ self
->cbwidth_y
* 2);
372 /* when the client has StaticGravity, it likes to move around. */
373 XMoveWindow(ob_display
, self
->client
->window
,
374 self
->cbwidth_x
, self
->cbwidth_y
);
377 STRUT_SET(self
->size
,
378 self
->innersize
.left
+ self
->bwidth
,
379 self
->innersize
.top
+ self
->bwidth
,
380 self
->innersize
.right
+ self
->bwidth
,
381 self
->innersize
.bottom
+ self
->bwidth
);
384 /* shading can change without being moved or resized */
385 RECT_SET_SIZE(self
->area
,
386 self
->client
->area
.width
+
387 self
->size
.left
+ self
->size
.right
,
388 (self
->client
->shaded
?
389 ob_rr_theme
->title_height
+ self
->rbwidth
* 2:
390 self
->client
->area
.height
+
391 self
->size
.top
+ self
->size
.bottom
));
394 /* find the new coordinates, done after setting the frame.size, for
395 frame_client_gravity. */
396 self
->area
.x
= self
->client
->area
.x
;
397 self
->area
.y
= self
->client
->area
.y
;
398 frame_client_gravity(self
, &self
->area
.x
, &self
->area
.y
);
402 /* move and resize the top level frame.
403 shading can change without being moved or resized */
404 XMoveResizeWindow(ob_display
, self
->window
,
405 self
->area
.x
, self
->area
.y
,
406 self
->area
.width
- self
->bwidth
* 2,
407 self
->area
.height
- self
->bwidth
* 2);
410 framerender_frame(self
);
412 frame_adjust_shape(self
);
415 if (!STRUT_EQUAL(self
->size
, oldsize
)) {
417 vals
[0] = self
->size
.left
;
418 vals
[1] = self
->size
.right
;
419 vals
[2] = self
->size
.top
;
420 vals
[3] = self
->size
.bottom
;
421 PROP_SETA32(self
->client
->window
, kde_net_wm_frame_strut
,
425 /* if this occurs while we are focus cycling, the indicator needs to
427 if (focus_cycle_target
== self
->client
)
428 focus_cycle_draw_indicator();
432 void frame_adjust_state(ObFrame
*self
)
434 framerender_frame(self
);
437 void frame_adjust_focus(ObFrame
*self
, gboolean hilite
)
439 self
->focused
= hilite
;
440 framerender_frame(self
);
443 void frame_adjust_title(ObFrame
*self
)
445 framerender_frame(self
);
448 void frame_adjust_icon(ObFrame
*self
)
450 framerender_frame(self
);
453 void frame_grab_client(ObFrame
*self
, ObClient
*client
)
455 self
->client
= client
;
457 /* reparent the client to the frame */
458 XReparentWindow(ob_display
, client
->window
, self
->plate
, 0, 0);
460 When reparenting the client window, it is usually not mapped yet, since
461 this occurs from a MapRequest. However, in the case where Openbox is
462 starting up, the window is already mapped, so we'll see unmap events for
463 it. There are 2 unmap events generated that we see, one with the 'event'
464 member set the root window, and one set to the client, but both get
465 handled and need to be ignored.
467 if (ob_state() == OB_STATE_STARTING
)
468 client
->ignore_unmaps
+= 2;
470 /* select the event mask on the client's parent (to receive config/map
471 req's) the ButtonPress is to catch clicks on the client border */
472 XSelectInput(ob_display
, self
->plate
, PLATE_EVENTMASK
);
474 /* map the client so it maps when the frame does */
475 XMapWindow(ob_display
, client
->window
);
477 frame_adjust_area(self
, TRUE
, TRUE
, FALSE
);
479 /* set all the windows for the frame in the window_map */
480 g_hash_table_insert(window_map
, &self
->window
, client
);
481 g_hash_table_insert(window_map
, &self
->plate
, client
);
482 g_hash_table_insert(window_map
, &self
->title
, client
);
483 g_hash_table_insert(window_map
, &self
->label
, client
);
484 g_hash_table_insert(window_map
, &self
->max
, client
);
485 g_hash_table_insert(window_map
, &self
->close
, client
);
486 g_hash_table_insert(window_map
, &self
->desk
, client
);
487 g_hash_table_insert(window_map
, &self
->shade
, client
);
488 g_hash_table_insert(window_map
, &self
->icon
, client
);
489 g_hash_table_insert(window_map
, &self
->iconify
, client
);
490 g_hash_table_insert(window_map
, &self
->handle
, client
);
491 g_hash_table_insert(window_map
, &self
->lgrip
, client
);
492 g_hash_table_insert(window_map
, &self
->rgrip
, client
);
493 g_hash_table_insert(window_map
, &self
->tlresize
, client
);
494 g_hash_table_insert(window_map
, &self
->trresize
, client
);
497 void frame_release_client(ObFrame
*self
, ObClient
*client
)
501 g_assert(self
->client
== client
);
503 /* check if the app has already reparented its window away */
504 if (XCheckTypedWindowEvent(ob_display
, client
->window
,
505 ReparentNotify
, &ev
)) {
506 XPutBackEvent(ob_display
, &ev
);
508 /* re-map the window since the unmanaging process unmaps it */
510 /* XXX ... um no it doesnt it unmaps its parent, the window itself
511 retains its mapped state, no?! XXX
512 XMapWindow(ob_display, client->window); */
514 /* according to the ICCCM - if the client doesn't reparent itself,
515 then we will reparent the window to root for them */
516 XReparentWindow(ob_display
, client
->window
,
517 RootWindow(ob_display
, ob_screen
),
522 /* remove all the windows for the frame from the window_map */
523 g_hash_table_remove(window_map
, &self
->window
);
524 g_hash_table_remove(window_map
, &self
->plate
);
525 g_hash_table_remove(window_map
, &self
->title
);
526 g_hash_table_remove(window_map
, &self
->label
);
527 g_hash_table_remove(window_map
, &self
->max
);
528 g_hash_table_remove(window_map
, &self
->close
);
529 g_hash_table_remove(window_map
, &self
->desk
);
530 g_hash_table_remove(window_map
, &self
->shade
);
531 g_hash_table_remove(window_map
, &self
->icon
);
532 g_hash_table_remove(window_map
, &self
->iconify
);
533 g_hash_table_remove(window_map
, &self
->handle
);
534 g_hash_table_remove(window_map
, &self
->lgrip
);
535 g_hash_table_remove(window_map
, &self
->rgrip
);
536 g_hash_table_remove(window_map
, &self
->tlresize
);
537 g_hash_table_remove(window_map
, &self
->trresize
);
539 ob_main_loop_timeout_remove_data(ob_main_loop
, flash_timeout
, self
);
544 static void layout_title(ObFrame
*self
)
548 gboolean n
, d
, i
, l
, m
, c
, s
;
550 n
= d
= i
= l
= m
= c
= s
= FALSE
;
552 /* figure out whats being shown, and the width of the label */
553 self
->label_width
= self
->width
- (ob_rr_theme
->padding
+ 1) * 2;
554 for (lc
= config_title_layout
; *lc
!= '\0'; ++lc
) {
557 if (n
) { *lc
= ' '; break; } /* rm duplicates */
559 self
->label_width
-= (ob_rr_theme
->button_size
+ 2 +
560 ob_rr_theme
->padding
+ 1);
563 if (d
) { *lc
= ' '; break; } /* rm duplicates */
565 self
->label_width
-= (ob_rr_theme
->button_size
+
566 ob_rr_theme
->padding
+ 1);
569 if (s
) { *lc
= ' '; break; } /* rm duplicates */
571 self
->label_width
-= (ob_rr_theme
->button_size
+
572 ob_rr_theme
->padding
+ 1);
575 if (i
) { *lc
= ' '; break; } /* rm duplicates */
577 self
->label_width
-= (ob_rr_theme
->button_size
+
578 ob_rr_theme
->padding
+ 1);
581 if (l
) { *lc
= ' '; break; } /* rm duplicates */
585 if (m
) { *lc
= ' '; break; } /* rm duplicates */
587 self
->label_width
-= (ob_rr_theme
->button_size
+
588 ob_rr_theme
->padding
+ 1);
591 if (c
) { *lc
= ' '; break; } /* rm duplicates */
593 self
->label_width
-= (ob_rr_theme
->button_size
+
594 ob_rr_theme
->padding
+ 1);
598 if (self
->label_width
< 1) self
->label_width
= 1;
600 XResizeWindow(ob_display
, self
->label
, self
->label_width
,
601 ob_rr_theme
->label_height
);
603 if (!n
) XUnmapWindow(ob_display
, self
->icon
);
604 if (!d
) XUnmapWindow(ob_display
, self
->desk
);
605 if (!s
) XUnmapWindow(ob_display
, self
->shade
);
606 if (!i
) XUnmapWindow(ob_display
, self
->iconify
);
607 if (!l
) XUnmapWindow(ob_display
, self
->label
);
608 if (!m
) XUnmapWindow(ob_display
, self
->max
);
609 if (!c
) XUnmapWindow(ob_display
, self
->close
);
611 x
= ob_rr_theme
->padding
+ 1;
612 for (lc
= config_title_layout
; *lc
!= '\0'; ++lc
) {
617 XMapWindow(ob_display
, self
->icon
);
618 XMoveWindow(ob_display
, self
->icon
, x
, ob_rr_theme
->padding
);
619 x
+= ob_rr_theme
->button_size
+ 2 + ob_rr_theme
->padding
+ 1;
624 XMapWindow(ob_display
, self
->desk
);
625 XMoveWindow(ob_display
, self
->desk
, x
, ob_rr_theme
->padding
+ 1);
626 x
+= ob_rr_theme
->button_size
+ ob_rr_theme
->padding
+ 1;
631 XMapWindow(ob_display
, self
->shade
);
632 XMoveWindow(ob_display
, self
->shade
, x
, ob_rr_theme
->padding
+ 1);
633 x
+= ob_rr_theme
->button_size
+ ob_rr_theme
->padding
+ 1;
638 XMapWindow(ob_display
, self
->iconify
);
639 XMoveWindow(ob_display
,self
->iconify
, x
, ob_rr_theme
->padding
+ 1);
640 x
+= ob_rr_theme
->button_size
+ ob_rr_theme
->padding
+ 1;
645 XMapWindow(ob_display
, self
->label
);
646 XMoveWindow(ob_display
, self
->label
, x
, ob_rr_theme
->padding
);
647 x
+= self
->label_width
+ ob_rr_theme
->padding
+ 1;
652 XMapWindow(ob_display
, self
->max
);
653 XMoveWindow(ob_display
, self
->max
, x
, ob_rr_theme
->padding
+ 1);
654 x
+= ob_rr_theme
->button_size
+ ob_rr_theme
->padding
+ 1;
659 XMapWindow(ob_display
, self
->close
);
660 XMoveWindow(ob_display
, self
->close
, x
, ob_rr_theme
->padding
+ 1);
661 x
+= ob_rr_theme
->button_size
+ ob_rr_theme
->padding
+ 1;
667 ObFrameContext
frame_context_from_string(const gchar
*name
)
669 if (!g_ascii_strcasecmp("Desktop", name
))
670 return OB_FRAME_CONTEXT_DESKTOP
;
671 else if (!g_ascii_strcasecmp("Client", name
))
672 return OB_FRAME_CONTEXT_CLIENT
;
673 else if (!g_ascii_strcasecmp("Titlebar", name
))
674 return OB_FRAME_CONTEXT_TITLEBAR
;
675 else if (!g_ascii_strcasecmp("Handle", name
))
676 return OB_FRAME_CONTEXT_HANDLE
;
677 else if (!g_ascii_strcasecmp("Frame", name
))
678 return OB_FRAME_CONTEXT_FRAME
;
679 else if (!g_ascii_strcasecmp("TLCorner", name
))
680 return OB_FRAME_CONTEXT_TLCORNER
;
681 else if (!g_ascii_strcasecmp("TRCorner", name
))
682 return OB_FRAME_CONTEXT_TRCORNER
;
683 else if (!g_ascii_strcasecmp("BLCorner", name
))
684 return OB_FRAME_CONTEXT_BLCORNER
;
685 else if (!g_ascii_strcasecmp("BRCorner", name
))
686 return OB_FRAME_CONTEXT_BRCORNER
;
687 else if (!g_ascii_strcasecmp("Maximize", name
))
688 return OB_FRAME_CONTEXT_MAXIMIZE
;
689 else if (!g_ascii_strcasecmp("AllDesktops", name
))
690 return OB_FRAME_CONTEXT_ALLDESKTOPS
;
691 else if (!g_ascii_strcasecmp("Shade", name
))
692 return OB_FRAME_CONTEXT_SHADE
;
693 else if (!g_ascii_strcasecmp("Iconify", name
))
694 return OB_FRAME_CONTEXT_ICONIFY
;
695 else if (!g_ascii_strcasecmp("Icon", name
))
696 return OB_FRAME_CONTEXT_ICON
;
697 else if (!g_ascii_strcasecmp("Close", name
))
698 return OB_FRAME_CONTEXT_CLOSE
;
699 else if (!g_ascii_strcasecmp("MoveResize", name
))
700 return OB_FRAME_CONTEXT_MOVE_RESIZE
;
701 return OB_FRAME_CONTEXT_NONE
;
704 ObFrameContext
frame_context(ObClient
*client
, Window win
)
708 if (moveresize_in_progress
)
709 return OB_FRAME_CONTEXT_MOVE_RESIZE
;
711 if (win
== RootWindow(ob_display
, ob_screen
))
712 return OB_FRAME_CONTEXT_DESKTOP
;
713 if (client
== NULL
) return OB_FRAME_CONTEXT_NONE
;
714 if (win
== client
->window
) {
715 /* conceptually, this is the desktop, as far as users are
717 if (client
->type
== OB_CLIENT_TYPE_DESKTOP
)
718 return OB_FRAME_CONTEXT_DESKTOP
;
719 return OB_FRAME_CONTEXT_CLIENT
;
722 self
= client
->frame
;
723 if (win
== self
->plate
) {
724 /* conceptually, this is the desktop, as far as users are
726 if (client
->type
== OB_CLIENT_TYPE_DESKTOP
)
727 return OB_FRAME_CONTEXT_DESKTOP
;
728 return OB_FRAME_CONTEXT_CLIENT
;
731 if (win
== self
->window
) return OB_FRAME_CONTEXT_FRAME
;
732 if (win
== self
->title
) return OB_FRAME_CONTEXT_TITLEBAR
;
733 if (win
== self
->label
) return OB_FRAME_CONTEXT_TITLEBAR
;
734 if (win
== self
->handle
) return OB_FRAME_CONTEXT_HANDLE
;
735 if (win
== self
->lgrip
) return OB_FRAME_CONTEXT_BLCORNER
;
736 if (win
== self
->rgrip
) return OB_FRAME_CONTEXT_BRCORNER
;
737 if (win
== self
->tlresize
) return OB_FRAME_CONTEXT_TLCORNER
;
738 if (win
== self
->trresize
) return OB_FRAME_CONTEXT_TRCORNER
;
739 if (win
== self
->max
) return OB_FRAME_CONTEXT_MAXIMIZE
;
740 if (win
== self
->iconify
) return OB_FRAME_CONTEXT_ICONIFY
;
741 if (win
== self
->close
) return OB_FRAME_CONTEXT_CLOSE
;
742 if (win
== self
->icon
) return OB_FRAME_CONTEXT_ICON
;
743 if (win
== self
->desk
) return OB_FRAME_CONTEXT_ALLDESKTOPS
;
744 if (win
== self
->shade
) return OB_FRAME_CONTEXT_SHADE
;
746 return OB_FRAME_CONTEXT_NONE
;
749 void frame_client_gravity(ObFrame
*self
, int *x
, int *y
)
752 switch (self
->client
->gravity
) {
754 case NorthWestGravity
:
755 case SouthWestGravity
:
762 *x
-= (self
->size
.left
+ self
->size
.right
) / 2;
765 case NorthEastGravity
:
766 case SouthEastGravity
:
768 *x
-= self
->size
.left
+ self
->size
.right
;
773 *x
-= self
->size
.left
;
778 switch (self
->client
->gravity
) {
780 case NorthWestGravity
:
781 case NorthEastGravity
:
788 *y
-= (self
->size
.top
+ self
->size
.bottom
) / 2;
791 case SouthWestGravity
:
792 case SouthEastGravity
:
794 *y
-= self
->size
.top
+ self
->size
.bottom
;
799 *y
-= self
->size
.top
;
804 void frame_frame_gravity(ObFrame
*self
, int *x
, int *y
)
807 switch (self
->client
->gravity
) {
809 case NorthWestGravity
:
811 case SouthWestGravity
:
816 *x
+= (self
->size
.left
+ self
->size
.right
) / 2;
818 case NorthEastGravity
:
820 case SouthEastGravity
:
821 *x
+= self
->size
.left
+ self
->size
.right
;
825 *x
+= self
->size
.left
;
830 switch (self
->client
->gravity
) {
832 case NorthWestGravity
:
834 case NorthEastGravity
:
839 *y
+= (self
->size
.top
+ self
->size
.bottom
) / 2;
841 case SouthWestGravity
:
843 case SouthEastGravity
:
844 *y
+= self
->size
.top
+ self
->size
.bottom
;
848 *y
+= self
->size
.top
;
853 static void flash_done(gpointer data
)
855 ObFrame
*self
= data
;
857 if (self
->focused
!= self
->flash_on
)
858 frame_adjust_focus(self
, self
->focused
);
861 static gboolean
flash_timeout(gpointer data
)
863 ObFrame
*self
= data
;
866 g_get_current_time(&now
);
867 if (now
.tv_sec
> self
->flash_end
.tv_sec
||
868 (now
.tv_sec
== self
->flash_end
.tv_sec
&&
869 now
.tv_usec
>= self
->flash_end
.tv_usec
))
870 self
->flashing
= FALSE
;
873 return FALSE
; /* we are done */
875 self
->flash_on
= !self
->flash_on
;
876 if (!self
->focused
) {
877 frame_adjust_focus(self
, self
->flash_on
);
878 self
->focused
= FALSE
;
881 return TRUE
; /* go again */
884 void frame_flash_start(ObFrame
*self
)
886 self
->flash_on
= self
->focused
;
889 ob_main_loop_timeout_add(ob_main_loop
,
890 G_USEC_PER_SEC
* 0.6,
894 g_get_current_time(&self
->flash_end
);
895 g_time_val_add(&self
->flash_end
, G_USEC_PER_SEC
* 5);
897 self
->flashing
= TRUE
;
900 void frame_flash_stop(ObFrame
*self
)
902 self
->flashing
= FALSE
;