1 /* -*- indent-tabs-mode: nil; tab-width: 4; c-basic-offset: 4; -*-
3 frame.c for the Openbox window manager
4 Copyright (c) 2006 Mikael Magnusson
5 Copyright (c) 2003-2007 Dana Jansens
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2 of the License, or
10 (at your option) any later version.
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 See the COPYING file for a copy of the GNU General Public License.
23 #include "extensions.h"
26 #include "framerender.h"
29 #include "moveresize.h"
30 #include "render/theme.h"
32 #define PLATE_EVENTMASK (SubstructureRedirectMask | ButtonPressMask | \
34 #define FRAME_EVENTMASK (EnterWindowMask | LeaveWindowMask | \
35 ButtonPressMask | ButtonReleaseMask)
36 #define ELEMENT_EVENTMASK (ButtonPressMask | ButtonReleaseMask | \
38 EnterWindowMask | LeaveWindowMask)
40 #define FRAME_HANDLE_Y(f) (f->innersize.top + f->client->area.height + \
43 static void layout_title(ObFrame *self);
44 static void flash_done(gpointer data);
45 static gboolean flash_timeout(gpointer data);
47 static void set_theme_statics(ObFrame *self);
48 static void free_theme_statics(ObFrame *self);
50 static Window createWindow(Window parent, Visual *visual,
51 gulong mask, XSetWindowAttributes *attrib)
53 return XCreateWindow(ob_display, parent, 0, 0, 1, 1, 0,
54 (visual ? 32 : RrDepth(ob_rr_inst)), InputOutput,
55 (visual ? visual : RrVisual(ob_rr_inst)),
60 static Visual *check_32bit_client(ObClient *c)
62 XWindowAttributes wattrib;
65 ret = XGetWindowAttributes(ob_display, c->window, &wattrib);
66 g_assert(ret != BadDrawable);
67 g_assert(ret != BadWindow);
69 if (wattrib.depth == 32)
70 return wattrib.visual;
74 ObFrame *frame_new(ObClient *client)
76 XSetWindowAttributes attrib;
81 self = g_new0(ObFrame, 1);
83 visual = check_32bit_client(client);
85 /* create the non-visible decor windows */
89 /* client has a 32-bit visual */
90 mask |= CWColormap | CWBackPixel | CWBorderPixel;
91 /* create a colormap with the visual */
92 self->colormap = attrib.colormap =
93 XCreateColormap(ob_display,
94 RootWindow(ob_display, ob_screen),
96 attrib.background_pixel = BlackPixel(ob_display, 0);
97 attrib.border_pixel = BlackPixel(ob_display, 0);
99 attrib.event_mask = FRAME_EVENTMASK;
100 self->window = createWindow(RootWindow(ob_display, ob_screen), visual,
103 attrib.event_mask = ELEMENT_EVENTMASK;
104 self->inner = createWindow(self->window, visual, mask, &attrib);
106 mask &= ~CWEventMask;
107 self->plate = createWindow(self->inner, visual, mask, &attrib);
109 /* create the visible decor windows */
113 /* client has a 32-bit visual */
114 mask |= CWColormap | CWBackPixel | CWBorderPixel;
115 attrib.colormap = RrColormap(ob_rr_inst);
117 attrib.event_mask = ELEMENT_EVENTMASK;
118 self->title = createWindow(self->window, NULL, mask, &attrib);
121 attrib.cursor = ob_cursor(OB_CURSOR_NORTHWEST);
122 self->tltresize = createWindow(self->title, NULL, mask, &attrib);
123 self->tllresize = createWindow(self->title, NULL, mask, &attrib);
124 attrib.cursor = ob_cursor(OB_CURSOR_NORTHEAST);
125 self->trtresize = createWindow(self->title, NULL, mask, &attrib);
126 self->trrresize = createWindow(self->title, NULL, mask, &attrib);
129 self->label = createWindow(self->title, NULL, mask, &attrib);
130 self->max = createWindow(self->title, NULL, mask, &attrib);
131 self->close = createWindow(self->title, NULL, mask, &attrib);
132 self->desk = createWindow(self->title, NULL, mask, &attrib);
133 self->shade = createWindow(self->title, NULL, mask, &attrib);
134 self->icon = createWindow(self->title, NULL, mask, &attrib);
135 self->iconify = createWindow(self->title, NULL, mask, &attrib);
136 self->handle = createWindow(self->window, NULL, mask, &attrib);
139 attrib.cursor = ob_cursor(OB_CURSOR_SOUTHWEST);
140 self->lgrip = createWindow(self->handle, NULL, mask, &attrib);
141 attrib.cursor = ob_cursor(OB_CURSOR_SOUTHEAST);
142 self->rgrip = createWindow(self->handle, NULL, mask, &attrib);
144 self->focused = FALSE;
146 /* the other stuff is shown based on decor settings */
147 XMapWindow(ob_display, self->plate);
148 XMapWindow(ob_display, self->inner);
149 XMapWindow(ob_display, self->lgrip);
150 XMapWindow(ob_display, self->rgrip);
151 XMapWindow(ob_display, self->label);
153 self->max_press = self->close_press = self->desk_press =
154 self->iconify_press = self->shade_press = FALSE;
155 self->max_hover = self->close_hover = self->desk_hover =
156 self->iconify_hover = self->shade_hover = FALSE;
158 set_theme_statics(self);
160 return (ObFrame*)self;
163 static void set_theme_statics(ObFrame *self)
165 /* set colors/appearance/sizes for stuff that doesn't change */
166 XSetWindowBorder(ob_display, self->window,
167 RrColorPixel(ob_rr_theme->frame_b_color));
168 XSetWindowBorder(ob_display, self->title,
169 RrColorPixel(ob_rr_theme->frame_b_color));
170 XSetWindowBorder(ob_display, self->handle,
171 RrColorPixel(ob_rr_theme->frame_b_color));
172 XSetWindowBorder(ob_display, self->rgrip,
173 RrColorPixel(ob_rr_theme->frame_b_color));
174 XSetWindowBorder(ob_display, self->lgrip,
175 RrColorPixel(ob_rr_theme->frame_b_color));
177 XResizeWindow(ob_display, self->max,
178 ob_rr_theme->button_size, ob_rr_theme->button_size);
179 XResizeWindow(ob_display, self->iconify,
180 ob_rr_theme->button_size, ob_rr_theme->button_size);
181 XResizeWindow(ob_display, self->icon,
182 ob_rr_theme->button_size + 2, ob_rr_theme->button_size + 2);
183 XResizeWindow(ob_display, self->close,
184 ob_rr_theme->button_size, ob_rr_theme->button_size);
185 XResizeWindow(ob_display, self->desk,
186 ob_rr_theme->button_size, ob_rr_theme->button_size);
187 XResizeWindow(ob_display, self->shade,
188 ob_rr_theme->button_size, ob_rr_theme->button_size);
189 if (ob_rr_theme->handle_height > 0) {
190 XResizeWindow(ob_display, self->lgrip,
191 ob_rr_theme->grip_width, ob_rr_theme->handle_height);
192 XResizeWindow(ob_display, self->rgrip,
193 ob_rr_theme->grip_width, ob_rr_theme->handle_height);
195 XResizeWindow(ob_display, self->tltresize,
196 ob_rr_theme->grip_width, ob_rr_theme->paddingy + 1);
197 XResizeWindow(ob_display, self->trtresize,
198 ob_rr_theme->grip_width, ob_rr_theme->paddingy + 1);
199 XResizeWindow(ob_display, self->tllresize,
200 ob_rr_theme->paddingx + 1, ob_rr_theme->title_height);
201 XResizeWindow(ob_display, self->trrresize,
202 ob_rr_theme->paddingx + 1, ob_rr_theme->title_height);
204 /* set up the dynamic appearances */
205 self->a_unfocused_title = RrAppearanceCopy(ob_rr_theme->a_unfocused_title);
206 self->a_focused_title = RrAppearanceCopy(ob_rr_theme->a_focused_title);
207 self->a_unfocused_label = RrAppearanceCopy(ob_rr_theme->a_unfocused_label);
208 self->a_focused_label = RrAppearanceCopy(ob_rr_theme->a_focused_label);
209 self->a_unfocused_handle =
210 RrAppearanceCopy(ob_rr_theme->a_unfocused_handle);
211 self->a_focused_handle = RrAppearanceCopy(ob_rr_theme->a_focused_handle);
212 self->a_icon = RrAppearanceCopy(ob_rr_theme->a_icon);
215 static void free_theme_statics(ObFrame *self)
217 RrAppearanceFree(self->a_unfocused_title);
218 RrAppearanceFree(self->a_focused_title);
219 RrAppearanceFree(self->a_unfocused_label);
220 RrAppearanceFree(self->a_focused_label);
221 RrAppearanceFree(self->a_unfocused_handle);
222 RrAppearanceFree(self->a_focused_handle);
223 RrAppearanceFree(self->a_icon);
226 static void frame_free(ObFrame *self)
228 free_theme_statics(self);
230 XDestroyWindow(ob_display, self->window);
232 XFreeColormap(ob_display, self->colormap);
237 void frame_show(ObFrame *self)
239 if (!self->visible) {
240 self->visible = TRUE;
241 XMapWindow(ob_display, self->client->window);
242 XMapWindow(ob_display, self->window);
246 void frame_hide(ObFrame *self)
249 self->visible = FALSE;
250 self->client->ignore_unmaps += 1;
251 /* we unmap the client itself so that we can get MapRequest
252 events, and because the ICCCM tells us to! */
253 XUnmapWindow(ob_display, self->window);
254 XUnmapWindow(ob_display, self->client->window);
258 void frame_adjust_theme(ObFrame *self)
260 free_theme_statics(self);
261 set_theme_statics(self);
264 void frame_adjust_shape(ObFrame *self)
270 if (!self->client->shaped) {
271 /* clear the shape on the frame window */
272 XShapeCombineMask(ob_display, self->window, ShapeBounding,
273 self->innersize.left,
277 /* make the frame's shape match the clients */
278 XShapeCombineShape(ob_display, self->window, ShapeBounding,
279 self->innersize.left,
281 self->client->window,
282 ShapeBounding, ShapeSet);
285 if (self->decorations & OB_FRAME_DECOR_TITLEBAR) {
286 xrect[0].x = -ob_rr_theme->fbwidth;
287 xrect[0].y = -ob_rr_theme->fbwidth;
288 xrect[0].width = self->width + self->rbwidth * 2;
289 xrect[0].height = ob_rr_theme->title_height +
294 if (self->decorations & OB_FRAME_DECOR_HANDLE) {
295 xrect[1].x = -ob_rr_theme->fbwidth;
296 xrect[1].y = FRAME_HANDLE_Y(self);
297 xrect[1].width = self->width + self->rbwidth * 2;
298 xrect[1].height = ob_rr_theme->handle_height +
303 XShapeCombineRectangles(ob_display, self->window,
304 ShapeBounding, 0, 0, xrect, num,
305 ShapeUnion, Unsorted);
310 void frame_adjust_area(ObFrame *self, gboolean moved,
311 gboolean resized, gboolean fake)
315 oldsize = self->size;
318 self->decorations = self->client->decorations;
319 self->max_horz = self->client->max_horz;
321 if (self->decorations & OB_FRAME_DECOR_BORDER) {
322 self->bwidth = ob_rr_theme->fbwidth;
323 self->cbwidth_x = ob_rr_theme->cbwidthx;
324 self->cbwidth_y = ob_rr_theme->cbwidthy;
326 self->bwidth = self->cbwidth_x = self->cbwidth_y = 0;
328 self->rbwidth = self->bwidth;
331 self->bwidth = self->cbwidth_x = 0;
333 STRUT_SET(self->innersize,
338 self->width = self->client->area.width + self->cbwidth_x * 2 -
339 (self->max_horz ? self->rbwidth * 2 : 0);
340 self->width = MAX(self->width, 1); /* no lower than 1 */
342 /* set border widths */
344 XSetWindowBorderWidth(ob_display, self->window, self->bwidth);
345 XSetWindowBorderWidth(ob_display, self->title, self->rbwidth);
346 XSetWindowBorderWidth(ob_display, self->handle, self->rbwidth);
347 XSetWindowBorderWidth(ob_display, self->lgrip, self->rbwidth);
348 XSetWindowBorderWidth(ob_display, self->rgrip, self->rbwidth);
351 if (self->decorations & OB_FRAME_DECOR_TITLEBAR)
352 self->innersize.top += ob_rr_theme->title_height + self->rbwidth +
353 (self->rbwidth - self->bwidth);
354 if (self->decorations & OB_FRAME_DECOR_HANDLE &&
355 ob_rr_theme->handle_height > 0)
356 self->innersize.bottom += ob_rr_theme->handle_height +
357 self->rbwidth + (self->rbwidth - self->bwidth);
359 /* they all default off, they're turned on in layout_title */
363 self->iconify_x = -1;
368 /* position/size and map/unmap all the windows */
371 if (self->decorations & OB_FRAME_DECOR_TITLEBAR) {
372 XMoveResizeWindow(ob_display, self->title,
373 -self->bwidth, -self->bwidth,
374 self->width, ob_rr_theme->title_height);
375 XMapWindow(ob_display, self->title);
377 if (self->decorations & OB_FRAME_DECOR_GRIPS) {
378 XMoveWindow(ob_display, self->tltresize, 0, 0);
379 XMoveWindow(ob_display, self->tllresize, 0, 0);
380 XMoveWindow(ob_display, self->trtresize,
381 self->width - ob_rr_theme->grip_width, 0);
382 XMoveWindow(ob_display, self->trrresize,
383 self->width - ob_rr_theme->paddingx - 1, 0);
384 XMapWindow(ob_display, self->tltresize);
385 XMapWindow(ob_display, self->tllresize);
386 XMapWindow(ob_display, self->trtresize);
387 XMapWindow(ob_display, self->trrresize);
389 XUnmapWindow(ob_display, self->tltresize);
390 XUnmapWindow(ob_display, self->tllresize);
391 XUnmapWindow(ob_display, self->trtresize);
392 XUnmapWindow(ob_display, self->trrresize);
395 XUnmapWindow(ob_display, self->title);
398 if (self->decorations & OB_FRAME_DECOR_TITLEBAR)
399 /* layout the title bar elements */
403 if (self->decorations & OB_FRAME_DECOR_HANDLE &&
404 ob_rr_theme->handle_height > 0)
406 XMoveResizeWindow(ob_display, self->handle,
407 -self->bwidth, FRAME_HANDLE_Y(self),
408 self->width, ob_rr_theme->handle_height);
409 XMapWindow(ob_display, self->handle);
411 if (self->decorations & OB_FRAME_DECOR_GRIPS) {
412 XMoveWindow(ob_display, self->lgrip,
413 -self->rbwidth, -self->rbwidth);
414 XMoveWindow(ob_display, self->rgrip,
415 -self->rbwidth + self->width -
416 ob_rr_theme->grip_width, -self->rbwidth);
417 XMapWindow(ob_display, self->lgrip);
418 XMapWindow(ob_display, self->rgrip);
420 XUnmapWindow(ob_display, self->lgrip);
421 XUnmapWindow(ob_display, self->rgrip);
424 XUnmapWindow(ob_display, self->handle);
426 /* move and resize the inner border window which contains the plate
428 XMoveResizeWindow(ob_display, self->inner,
429 self->innersize.left - self->cbwidth_x,
430 self->innersize.top - self->cbwidth_y,
431 self->client->area.width +
433 self->client->area.height +
434 self->cbwidth_y * 2);
437 XMoveWindow(ob_display, self->plate,
438 self->cbwidth_x, self->cbwidth_y);
440 /* when the client has StaticGravity, it likes to move around. */
441 XMoveWindow(ob_display, self->client->window, 0, 0);
444 STRUT_SET(self->size,
445 self->innersize.left + self->bwidth,
446 self->innersize.top + self->bwidth,
447 self->innersize.right + self->bwidth,
448 self->innersize.bottom + self->bwidth);
451 /* shading can change without being moved or resized */
452 RECT_SET_SIZE(self->area,
453 self->client->area.width +
454 self->size.left + self->size.right,
455 (self->client->shaded ?
456 ob_rr_theme->title_height + self->rbwidth * 2:
457 self->client->area.height +
458 self->size.top + self->size.bottom));
461 /* find the new coordinates, done after setting the frame.size, for
462 frame_client_gravity. */
463 self->area.x = self->client->area.x;
464 self->area.y = self->client->area.y;
465 frame_client_gravity(self, &self->area.x, &self->area.y);
469 /* move and resize the top level frame.
470 shading can change without being moved or resized */
471 XMoveResizeWindow(ob_display, self->window,
472 self->area.x, self->area.y,
473 self->area.width - self->bwidth * 2,
474 self->area.height - self->bwidth * 2);
477 framerender_frame(self);
478 frame_adjust_shape(self);
481 if (!STRUT_EQUAL(self->size, oldsize)) {
483 vals[0] = self->size.left;
484 vals[1] = self->size.right;
485 vals[2] = self->size.top;
486 vals[3] = self->size.bottom;
487 PROP_SETA32(self->client->window, net_frame_extents,
491 /* if this occurs while we are focus cycling, the indicator needs to
493 if (focus_cycle_target == self->client)
494 focus_cycle_draw_indicator();
496 if (resized && (self->decorations & OB_FRAME_DECOR_TITLEBAR))
497 XResizeWindow(ob_display, self->label, self->label_width,
498 ob_rr_theme->label_height);
501 void frame_adjust_state(ObFrame *self)
503 framerender_frame(self);
506 void frame_adjust_focus(ObFrame *self, gboolean hilite)
508 self->focused = hilite;
509 framerender_frame(self);
513 void frame_adjust_client_area(ObFrame *self)
515 /* resize the plate */
516 XResizeWindow(ob_display, self->plate,
517 self->client->area.width, self->client->area.height);
520 void frame_adjust_title(ObFrame *self)
522 framerender_frame(self);
525 void frame_adjust_icon(ObFrame *self)
527 framerender_frame(self);
530 void frame_grab_client(ObFrame *self, ObClient *client)
532 self->client = client;
534 /* reparent the client to the frame */
535 XReparentWindow(ob_display, client->window, self->plate, 0, 0);
537 When reparenting the client window, it is usually not mapped yet, since
538 this occurs from a MapRequest. However, in the case where Openbox is
539 starting up, the window is already mapped, so we'll see unmap events for
540 it. There are 2 unmap events generated that we see, one with the 'event'
541 member set the root window, and one set to the client, but both get
542 handled and need to be ignored.
544 if (ob_state() == OB_STATE_STARTING)
545 client->ignore_unmaps += 2;
547 /* select the event mask on the client's parent (to receive config/map
548 req's) the ButtonPress is to catch clicks on the client border */
549 XSelectInput(ob_display, self->plate, PLATE_EVENTMASK);
551 frame_adjust_area(self, TRUE, TRUE, FALSE);
553 /* map the client so it maps when the frame does */
554 XMapWindow(ob_display, client->window);
556 /* set all the windows for the frame in the window_map */
557 g_hash_table_insert(window_map, &self->window, client);
558 g_hash_table_insert(window_map, &self->plate, client);
559 g_hash_table_insert(window_map, &self->inner, client);
560 g_hash_table_insert(window_map, &self->title, client);
561 g_hash_table_insert(window_map, &self->label, client);
562 g_hash_table_insert(window_map, &self->max, client);
563 g_hash_table_insert(window_map, &self->close, client);
564 g_hash_table_insert(window_map, &self->desk, client);
565 g_hash_table_insert(window_map, &self->shade, client);
566 g_hash_table_insert(window_map, &self->icon, client);
567 g_hash_table_insert(window_map, &self->iconify, client);
568 g_hash_table_insert(window_map, &self->handle, client);
569 g_hash_table_insert(window_map, &self->lgrip, client);
570 g_hash_table_insert(window_map, &self->rgrip, client);
571 g_hash_table_insert(window_map, &self->tltresize, client);
572 g_hash_table_insert(window_map, &self->tllresize, client);
573 g_hash_table_insert(window_map, &self->trtresize, client);
574 g_hash_table_insert(window_map, &self->trrresize, client);
577 void frame_release_client(ObFrame *self, ObClient *client)
580 gboolean reparent = TRUE;
582 g_assert(self->client == client);
584 /* check if the app has already reparented its window away */
585 while (XCheckTypedWindowEvent(ob_display, client->window,
586 ReparentNotify, &ev))
588 /* This check makes sure we don't catch our own reparent action to
589 our frame window. This doesn't count as the app reparenting itself
592 Reparent events that are generated by us are just discarded here.
593 They are of no consequence to us anyhow.
595 if (ev.xreparent.parent != self->plate) {
597 XPutBackEvent(ob_display, &ev);
603 /* according to the ICCCM - if the client doesn't reparent itself,
604 then we will reparent the window to root for them */
605 XReparentWindow(ob_display, client->window,
606 RootWindow(ob_display, ob_screen),
611 /* remove all the windows for the frame from the window_map */
612 g_hash_table_remove(window_map, &self->window);
613 g_hash_table_remove(window_map, &self->plate);
614 g_hash_table_remove(window_map, &self->inner);
615 g_hash_table_remove(window_map, &self->title);
616 g_hash_table_remove(window_map, &self->label);
617 g_hash_table_remove(window_map, &self->max);
618 g_hash_table_remove(window_map, &self->close);
619 g_hash_table_remove(window_map, &self->desk);
620 g_hash_table_remove(window_map, &self->shade);
621 g_hash_table_remove(window_map, &self->icon);
622 g_hash_table_remove(window_map, &self->iconify);
623 g_hash_table_remove(window_map, &self->handle);
624 g_hash_table_remove(window_map, &self->lgrip);
625 g_hash_table_remove(window_map, &self->rgrip);
626 g_hash_table_remove(window_map, &self->tltresize);
627 g_hash_table_remove(window_map, &self->tllresize);
628 g_hash_table_remove(window_map, &self->trtresize);
629 g_hash_table_remove(window_map, &self->trrresize);
631 ob_main_loop_timeout_remove_data(ob_main_loop, flash_timeout, self, TRUE);
636 static void layout_title(ObFrame *self)
640 gboolean n, d, i, l, m, c, s;
642 n = d = i = l = m = c = s = FALSE;
644 /* figure out whats being shown, and the width of the label */
645 self->label_width = self->width - (ob_rr_theme->paddingx + 1) * 2;
646 for (lc = config_title_layout; *lc != '\0'; ++lc) {
649 if (n) { *lc = ' '; break; } /* rm duplicates */
651 self->label_width -= (ob_rr_theme->button_size + 2 +
652 ob_rr_theme->paddingx + 1);
655 if (d) { *lc = ' '; break; }
656 if (!(self->decorations & OB_FRAME_DECOR_ALLDESKTOPS)
657 && config_theme_hidedisabled)
660 self->label_width -= (ob_rr_theme->button_size +
661 ob_rr_theme->paddingx + 1);
664 if (s) { *lc = ' '; break; }
665 if (!(self->decorations & OB_FRAME_DECOR_SHADE)
666 && config_theme_hidedisabled)
669 self->label_width -= (ob_rr_theme->button_size +
670 ob_rr_theme->paddingx + 1);
673 if (i) { *lc = ' '; break; }
674 if (!(self->decorations & OB_FRAME_DECOR_ICONIFY)
675 && config_theme_hidedisabled)
678 self->label_width -= (ob_rr_theme->button_size +
679 ob_rr_theme->paddingx + 1);
682 if (l) { *lc = ' '; break; }
686 if (m) { *lc = ' '; break; }
687 if (!(self->decorations & OB_FRAME_DECOR_MAXIMIZE)
688 && config_theme_hidedisabled)
691 self->label_width -= (ob_rr_theme->button_size +
692 ob_rr_theme->paddingx + 1);
695 if (c) { *lc = ' '; break; }
696 if (!(self->decorations & OB_FRAME_DECOR_CLOSE)
697 && config_theme_hidedisabled)
700 self->label_width -= (ob_rr_theme->button_size +
701 ob_rr_theme->paddingx + 1);
705 if (self->label_width < 1) self->label_width = 1;
707 if (!n) XUnmapWindow(ob_display, self->icon);
708 if (!d) XUnmapWindow(ob_display, self->desk);
709 if (!s) XUnmapWindow(ob_display, self->shade);
710 if (!i) XUnmapWindow(ob_display, self->iconify);
711 if (!l) XUnmapWindow(ob_display, self->label);
712 if (!m) XUnmapWindow(ob_display, self->max);
713 if (!c) XUnmapWindow(ob_display, self->close);
715 x = ob_rr_theme->paddingx + 1;
716 for (lc = config_title_layout; *lc != '\0'; ++lc) {
721 XMapWindow(ob_display, self->icon);
722 XMoveWindow(ob_display, self->icon, x, ob_rr_theme->paddingy);
723 x += ob_rr_theme->button_size + 2 + ob_rr_theme->paddingx + 1;
728 XMapWindow(ob_display, self->desk);
729 XMoveWindow(ob_display, self->desk, x, ob_rr_theme->paddingy + 1);
730 x += ob_rr_theme->button_size + ob_rr_theme->paddingx + 1;
735 XMapWindow(ob_display, self->shade);
736 XMoveWindow(ob_display, self->shade, x, ob_rr_theme->paddingy + 1);
737 x += ob_rr_theme->button_size + ob_rr_theme->paddingx + 1;
742 XMapWindow(ob_display, self->iconify);
743 XMoveWindow(ob_display,self->iconify, x, ob_rr_theme->paddingy + 1);
744 x += ob_rr_theme->button_size + ob_rr_theme->paddingx + 1;
749 XMapWindow(ob_display, self->label);
750 XMoveWindow(ob_display, self->label, x, ob_rr_theme->paddingy);
751 x += self->label_width + ob_rr_theme->paddingx + 1;
756 XMapWindow(ob_display, self->max);
757 XMoveWindow(ob_display, self->max, x, ob_rr_theme->paddingy + 1);
758 x += ob_rr_theme->button_size + ob_rr_theme->paddingx + 1;
763 XMapWindow(ob_display, self->close);
764 XMoveWindow(ob_display, self->close, x, ob_rr_theme->paddingy + 1);
765 x += ob_rr_theme->button_size + ob_rr_theme->paddingx + 1;
771 ObFrameContext frame_context_from_string(const gchar *name)
773 if (!g_ascii_strcasecmp("Desktop", name))
774 return OB_FRAME_CONTEXT_DESKTOP;
775 else if (!g_ascii_strcasecmp("Client", name))
776 return OB_FRAME_CONTEXT_CLIENT;
777 else if (!g_ascii_strcasecmp("Titlebar", name))
778 return OB_FRAME_CONTEXT_TITLEBAR;
779 else if (!g_ascii_strcasecmp("Handle", name))
780 return OB_FRAME_CONTEXT_HANDLE;
781 else if (!g_ascii_strcasecmp("Frame", name))
782 return OB_FRAME_CONTEXT_FRAME;
783 else if (!g_ascii_strcasecmp("TLCorner", name))
784 return OB_FRAME_CONTEXT_TLCORNER;
785 else if (!g_ascii_strcasecmp("TRCorner", name))
786 return OB_FRAME_CONTEXT_TRCORNER;
787 else if (!g_ascii_strcasecmp("BLCorner", name))
788 return OB_FRAME_CONTEXT_BLCORNER;
789 else if (!g_ascii_strcasecmp("BRCorner", name))
790 return OB_FRAME_CONTEXT_BRCORNER;
791 else if (!g_ascii_strcasecmp("Maximize", name))
792 return OB_FRAME_CONTEXT_MAXIMIZE;
793 else if (!g_ascii_strcasecmp("AllDesktops", name))
794 return OB_FRAME_CONTEXT_ALLDESKTOPS;
795 else if (!g_ascii_strcasecmp("Shade", name))
796 return OB_FRAME_CONTEXT_SHADE;
797 else if (!g_ascii_strcasecmp("Iconify", name))
798 return OB_FRAME_CONTEXT_ICONIFY;
799 else if (!g_ascii_strcasecmp("Icon", name))
800 return OB_FRAME_CONTEXT_ICON;
801 else if (!g_ascii_strcasecmp("Close", name))
802 return OB_FRAME_CONTEXT_CLOSE;
803 else if (!g_ascii_strcasecmp("MoveResize", name))
804 return OB_FRAME_CONTEXT_MOVE_RESIZE;
805 return OB_FRAME_CONTEXT_NONE;
808 ObFrameContext frame_context(ObClient *client, Window win)
812 if (moveresize_in_progress)
813 return OB_FRAME_CONTEXT_MOVE_RESIZE;
815 if (win == RootWindow(ob_display, ob_screen))
816 return OB_FRAME_CONTEXT_DESKTOP;
817 if (client == NULL) return OB_FRAME_CONTEXT_NONE;
818 if (win == client->window) {
819 /* conceptually, this is the desktop, as far as users are
821 if (client->type == OB_CLIENT_TYPE_DESKTOP)
822 return OB_FRAME_CONTEXT_DESKTOP;
823 return OB_FRAME_CONTEXT_CLIENT;
826 self = client->frame;
827 if (win == self->plate) {
828 /* conceptually, this is the desktop, as far as users are
830 if (client->type == OB_CLIENT_TYPE_DESKTOP)
831 return OB_FRAME_CONTEXT_DESKTOP;
832 return OB_FRAME_CONTEXT_CLIENT;
835 if (win == self->window) return OB_FRAME_CONTEXT_FRAME;
836 if (win == self->inner) return OB_FRAME_CONTEXT_FRAME;
837 if (win == self->title) return OB_FRAME_CONTEXT_TITLEBAR;
838 if (win == self->label) return OB_FRAME_CONTEXT_TITLEBAR;
839 if (win == self->handle) return OB_FRAME_CONTEXT_HANDLE;
840 if (win == self->lgrip) return OB_FRAME_CONTEXT_BLCORNER;
841 if (win == self->rgrip) return OB_FRAME_CONTEXT_BRCORNER;
842 if (win == self->tltresize) return OB_FRAME_CONTEXT_TLCORNER;
843 if (win == self->tllresize) return OB_FRAME_CONTEXT_TLCORNER;
844 if (win == self->trtresize) return OB_FRAME_CONTEXT_TRCORNER;
845 if (win == self->trrresize) return OB_FRAME_CONTEXT_TRCORNER;
846 if (win == self->max) return OB_FRAME_CONTEXT_MAXIMIZE;
847 if (win == self->iconify) return OB_FRAME_CONTEXT_ICONIFY;
848 if (win == self->close) return OB_FRAME_CONTEXT_CLOSE;
849 if (win == self->icon) return OB_FRAME_CONTEXT_ICON;
850 if (win == self->desk) return OB_FRAME_CONTEXT_ALLDESKTOPS;
851 if (win == self->shade) return OB_FRAME_CONTEXT_SHADE;
853 return OB_FRAME_CONTEXT_NONE;
856 void frame_client_gravity(ObFrame *self, gint *x, gint *y)
859 switch (self->client->gravity) {
861 case NorthWestGravity:
862 case SouthWestGravity:
869 *x -= (self->size.left + self->size.right) / 2;
872 case NorthEastGravity:
873 case SouthEastGravity:
875 *x -= self->size.left + self->size.right;
880 *x -= self->size.left;
885 switch (self->client->gravity) {
887 case NorthWestGravity:
888 case NorthEastGravity:
895 *y -= (self->size.top + self->size.bottom) / 2;
898 case SouthWestGravity:
899 case SouthEastGravity:
901 *y -= self->size.top + self->size.bottom;
906 *y -= self->size.top;
911 void frame_frame_gravity(ObFrame *self, gint *x, gint *y)
914 switch (self->client->gravity) {
916 case NorthWestGravity:
918 case SouthWestGravity:
923 *x += (self->size.left + self->size.right) / 2;
925 case NorthEastGravity:
927 case SouthEastGravity:
928 *x += self->size.left + self->size.right;
932 *x += self->size.left;
937 switch (self->client->gravity) {
939 case NorthWestGravity:
941 case NorthEastGravity:
946 *y += (self->size.top + self->size.bottom) / 2;
948 case SouthWestGravity:
950 case SouthEastGravity:
951 *y += self->size.top + self->size.bottom;
955 *y += self->size.top;
960 static void flash_done(gpointer data)
962 ObFrame *self = data;
964 if (self->focused != self->flash_on)
965 frame_adjust_focus(self, self->focused);
968 static gboolean flash_timeout(gpointer data)
970 ObFrame *self = data;
973 g_get_current_time(&now);
974 if (now.tv_sec > self->flash_end.tv_sec ||
975 (now.tv_sec == self->flash_end.tv_sec &&
976 now.tv_usec >= self->flash_end.tv_usec))
977 self->flashing = FALSE;
980 return FALSE; /* we are done */
982 self->flash_on = !self->flash_on;
983 if (!self->focused) {
984 frame_adjust_focus(self, self->flash_on);
985 self->focused = FALSE;
988 return TRUE; /* go again */
991 void frame_flash_start(ObFrame *self)
993 self->flash_on = self->focused;
996 ob_main_loop_timeout_add(ob_main_loop,
997 G_USEC_PER_SEC * 0.6,
1002 g_get_current_time(&self->flash_end);
1003 g_time_val_add(&self->flash_end, G_USEC_PER_SEC * 5);
1005 self->flashing = TRUE;
1008 void frame_flash_stop(ObFrame *self)
1010 self->flashing = FALSE;