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 */
112 /* client has a 32-bit visual */
113 mask |= CWColormap | CWBackPixel | CWBorderPixel;
114 attrib.colormap = RrColormap(ob_rr_inst);
116 attrib.event_mask = ELEMENT_EVENTMASK;
117 self->title = createWindow(self->window, NULL, mask, &attrib);
120 attrib.cursor = ob_cursor(OB_CURSOR_NORTHWEST);
121 self->tltresize = createWindow(self->title, NULL, mask, &attrib);
122 self->tllresize = createWindow(self->title, NULL, mask, &attrib);
123 attrib.cursor = ob_cursor(OB_CURSOR_NORTHEAST);
124 self->trtresize = createWindow(self->title, NULL, mask, &attrib);
125 self->trrresize = createWindow(self->title, NULL, mask, &attrib);
128 self->label = createWindow(self->title, NULL, mask, &attrib);
129 self->max = createWindow(self->title, NULL, mask, &attrib);
130 self->close = createWindow(self->title, NULL, mask, &attrib);
131 self->desk = createWindow(self->title, NULL, mask, &attrib);
132 self->shade = createWindow(self->title, NULL, mask, &attrib);
133 self->icon = createWindow(self->title, NULL, mask, &attrib);
134 self->iconify = createWindow(self->title, NULL, mask, &attrib);
135 self->handle = createWindow(self->window, NULL, mask, &attrib);
138 attrib.cursor = ob_cursor(OB_CURSOR_SOUTHWEST);
139 self->lgrip = createWindow(self->handle, NULL, mask, &attrib);
140 attrib.cursor = ob_cursor(OB_CURSOR_SOUTHEAST);
141 self->rgrip = createWindow(self->handle, NULL, mask, &attrib);
143 self->focused = FALSE;
145 /* the other stuff is shown based on decor settings */
146 XMapWindow(ob_display, self->plate);
147 XMapWindow(ob_display, self->inner);
148 XMapWindow(ob_display, self->lgrip);
149 XMapWindow(ob_display, self->rgrip);
150 XMapWindow(ob_display, self->label);
152 self->max_press = self->close_press = self->desk_press =
153 self->iconify_press = self->shade_press = FALSE;
154 self->max_hover = self->close_hover = self->desk_hover =
155 self->iconify_hover = self->shade_hover = FALSE;
157 set_theme_statics(self);
159 return (ObFrame*)self;
162 static void set_theme_statics(ObFrame *self)
164 /* set colors/appearance/sizes for stuff that doesn't change */
165 XSetWindowBorder(ob_display, self->window,
166 RrColorPixel(ob_rr_theme->frame_b_color));
167 XSetWindowBorder(ob_display, self->title,
168 RrColorPixel(ob_rr_theme->frame_b_color));
169 XSetWindowBorder(ob_display, self->handle,
170 RrColorPixel(ob_rr_theme->frame_b_color));
171 XSetWindowBorder(ob_display, self->rgrip,
172 RrColorPixel(ob_rr_theme->frame_b_color));
173 XSetWindowBorder(ob_display, self->lgrip,
174 RrColorPixel(ob_rr_theme->frame_b_color));
176 XResizeWindow(ob_display, self->max,
177 ob_rr_theme->button_size, ob_rr_theme->button_size);
178 XResizeWindow(ob_display, self->iconify,
179 ob_rr_theme->button_size, ob_rr_theme->button_size);
180 XResizeWindow(ob_display, self->icon,
181 ob_rr_theme->button_size + 2, ob_rr_theme->button_size + 2);
182 XResizeWindow(ob_display, self->close,
183 ob_rr_theme->button_size, ob_rr_theme->button_size);
184 XResizeWindow(ob_display, self->desk,
185 ob_rr_theme->button_size, ob_rr_theme->button_size);
186 XResizeWindow(ob_display, self->shade,
187 ob_rr_theme->button_size, ob_rr_theme->button_size);
188 if (ob_rr_theme->handle_height > 0) {
189 XResizeWindow(ob_display, self->lgrip,
190 ob_rr_theme->grip_width, ob_rr_theme->handle_height);
191 XResizeWindow(ob_display, self->rgrip,
192 ob_rr_theme->grip_width, ob_rr_theme->handle_height);
194 XResizeWindow(ob_display, self->tltresize,
195 ob_rr_theme->grip_width, ob_rr_theme->paddingy + 1);
196 XResizeWindow(ob_display, self->trtresize,
197 ob_rr_theme->grip_width, ob_rr_theme->paddingy + 1);
198 XResizeWindow(ob_display, self->tllresize,
199 ob_rr_theme->paddingx + 1, ob_rr_theme->title_height);
200 XResizeWindow(ob_display, self->trrresize,
201 ob_rr_theme->paddingx + 1, ob_rr_theme->title_height);
203 /* set up the dynamic appearances */
204 self->a_unfocused_title = RrAppearanceCopy(ob_rr_theme->a_unfocused_title);
205 self->a_focused_title = RrAppearanceCopy(ob_rr_theme->a_focused_title);
206 self->a_unfocused_label = RrAppearanceCopy(ob_rr_theme->a_unfocused_label);
207 self->a_focused_label = RrAppearanceCopy(ob_rr_theme->a_focused_label);
208 self->a_unfocused_handle =
209 RrAppearanceCopy(ob_rr_theme->a_unfocused_handle);
210 self->a_focused_handle = RrAppearanceCopy(ob_rr_theme->a_focused_handle);
211 self->a_icon = RrAppearanceCopy(ob_rr_theme->a_icon);
214 static void free_theme_statics(ObFrame *self)
216 RrAppearanceFree(self->a_unfocused_title);
217 RrAppearanceFree(self->a_focused_title);
218 RrAppearanceFree(self->a_unfocused_label);
219 RrAppearanceFree(self->a_focused_label);
220 RrAppearanceFree(self->a_unfocused_handle);
221 RrAppearanceFree(self->a_focused_handle);
222 RrAppearanceFree(self->a_icon);
225 static void frame_free(ObFrame *self)
227 free_theme_statics(self);
229 XDestroyWindow(ob_display, self->window);
231 XFreeColormap(ob_display, self->colormap);
236 void frame_show(ObFrame *self)
238 if (!self->visible) {
239 self->visible = TRUE;
240 XMapWindow(ob_display, self->client->window);
241 XMapWindow(ob_display, self->window);
245 void frame_hide(ObFrame *self)
248 self->visible = FALSE;
249 self->client->ignore_unmaps += 1;
250 /* we unmap the client itself so that we can get MapRequest
251 events, and because the ICCCM tells us to! */
252 XUnmapWindow(ob_display, self->window);
253 XUnmapWindow(ob_display, self->client->window);
257 void frame_adjust_theme(ObFrame *self)
259 free_theme_statics(self);
260 set_theme_statics(self);
263 void frame_adjust_shape(ObFrame *self)
269 if (!self->client->shaped) {
270 /* clear the shape on the frame window */
271 XShapeCombineMask(ob_display, self->window, ShapeBounding,
272 self->innersize.left,
276 /* make the frame's shape match the clients */
277 XShapeCombineShape(ob_display, self->window, ShapeBounding,
278 self->innersize.left,
280 self->client->window,
281 ShapeBounding, ShapeSet);
284 if (self->decorations & OB_FRAME_DECOR_TITLEBAR) {
285 xrect[0].x = -ob_rr_theme->fbwidth;
286 xrect[0].y = -ob_rr_theme->fbwidth;
287 xrect[0].width = self->width + self->rbwidth * 2;
288 xrect[0].height = ob_rr_theme->title_height +
293 if (self->decorations & OB_FRAME_DECOR_HANDLE) {
294 xrect[1].x = -ob_rr_theme->fbwidth;
295 xrect[1].y = FRAME_HANDLE_Y(self);
296 xrect[1].width = self->width + self->rbwidth * 2;
297 xrect[1].height = ob_rr_theme->handle_height +
302 XShapeCombineRectangles(ob_display, self->window,
303 ShapeBounding, 0, 0, xrect, num,
304 ShapeUnion, Unsorted);
309 void frame_adjust_area(ObFrame *self, gboolean moved,
310 gboolean resized, gboolean fake)
314 oldsize = self->size;
317 self->decorations = self->client->decorations;
318 self->max_horz = self->client->max_horz;
320 if (self->decorations & OB_FRAME_DECOR_BORDER) {
321 self->bwidth = ob_rr_theme->fbwidth;
322 self->cbwidth_x = ob_rr_theme->cbwidthx;
323 self->cbwidth_y = ob_rr_theme->cbwidthy;
325 self->bwidth = self->cbwidth_x = self->cbwidth_y = 0;
327 self->rbwidth = self->bwidth;
330 self->bwidth = self->cbwidth_x = 0;
332 STRUT_SET(self->innersize,
337 self->width = self->client->area.width + self->cbwidth_x * 2 -
338 (self->max_horz ? self->rbwidth * 2 : 0);
339 self->width = MAX(self->width, 1); /* no lower than 1 */
341 /* set border widths */
343 XSetWindowBorderWidth(ob_display, self->window, self->bwidth);
344 XSetWindowBorderWidth(ob_display, self->title, self->rbwidth);
345 XSetWindowBorderWidth(ob_display, self->handle, self->rbwidth);
346 XSetWindowBorderWidth(ob_display, self->lgrip, self->rbwidth);
347 XSetWindowBorderWidth(ob_display, self->rgrip, self->rbwidth);
350 if (self->decorations & OB_FRAME_DECOR_TITLEBAR)
351 self->innersize.top += ob_rr_theme->title_height + self->rbwidth +
352 (self->rbwidth - self->bwidth);
353 if (self->decorations & OB_FRAME_DECOR_HANDLE &&
354 ob_rr_theme->handle_height > 0)
355 self->innersize.bottom += ob_rr_theme->handle_height +
356 self->rbwidth + (self->rbwidth - self->bwidth);
358 /* they all default off, they're turned on in layout_title */
362 self->iconify_x = -1;
367 /* position/size and map/unmap all the windows */
370 if (self->decorations & OB_FRAME_DECOR_TITLEBAR) {
371 XMoveResizeWindow(ob_display, self->title,
372 -self->bwidth, -self->bwidth,
373 self->width, ob_rr_theme->title_height);
374 XMapWindow(ob_display, self->title);
376 if (self->decorations & OB_FRAME_DECOR_GRIPS) {
377 XMoveWindow(ob_display, self->tltresize, 0, 0);
378 XMoveWindow(ob_display, self->tllresize, 0, 0);
379 XMoveWindow(ob_display, self->trtresize,
380 self->width - ob_rr_theme->grip_width, 0);
381 XMoveWindow(ob_display, self->trrresize,
382 self->width - ob_rr_theme->paddingx - 1, 0);
383 XMapWindow(ob_display, self->tltresize);
384 XMapWindow(ob_display, self->tllresize);
385 XMapWindow(ob_display, self->trtresize);
386 XMapWindow(ob_display, self->trrresize);
388 XUnmapWindow(ob_display, self->tltresize);
389 XUnmapWindow(ob_display, self->tllresize);
390 XUnmapWindow(ob_display, self->trtresize);
391 XUnmapWindow(ob_display, self->trrresize);
394 XUnmapWindow(ob_display, self->title);
397 if (self->decorations & OB_FRAME_DECOR_TITLEBAR)
398 /* layout the title bar elements */
402 if (self->decorations & OB_FRAME_DECOR_HANDLE &&
403 ob_rr_theme->handle_height > 0)
405 XMoveResizeWindow(ob_display, self->handle,
406 -self->bwidth, FRAME_HANDLE_Y(self),
407 self->width, ob_rr_theme->handle_height);
408 XMapWindow(ob_display, self->handle);
410 if (self->decorations & OB_FRAME_DECOR_GRIPS) {
411 XMoveWindow(ob_display, self->lgrip,
412 -self->rbwidth, -self->rbwidth);
413 XMoveWindow(ob_display, self->rgrip,
414 -self->rbwidth + self->width -
415 ob_rr_theme->grip_width, -self->rbwidth);
416 XMapWindow(ob_display, self->lgrip);
417 XMapWindow(ob_display, self->rgrip);
419 XUnmapWindow(ob_display, self->lgrip);
420 XUnmapWindow(ob_display, self->rgrip);
423 XUnmapWindow(ob_display, self->handle);
425 /* move and resize the inner border window which contains the plate
427 XMoveResizeWindow(ob_display, self->inner,
428 self->innersize.left - self->cbwidth_x,
429 self->innersize.top - self->cbwidth_y,
430 self->client->area.width +
432 self->client->area.height +
433 self->cbwidth_y * 2);
436 XMoveWindow(ob_display, self->plate,
437 self->cbwidth_x, self->cbwidth_y);
439 /* when the client has StaticGravity, it likes to move around. */
440 XMoveWindow(ob_display, self->client->window, 0, 0);
443 STRUT_SET(self->size,
444 self->innersize.left + self->bwidth,
445 self->innersize.top + self->bwidth,
446 self->innersize.right + self->bwidth,
447 self->innersize.bottom + self->bwidth);
450 /* shading can change without being moved or resized */
451 RECT_SET_SIZE(self->area,
452 self->client->area.width +
453 self->size.left + self->size.right,
454 (self->client->shaded ?
455 ob_rr_theme->title_height + self->rbwidth * 2:
456 self->client->area.height +
457 self->size.top + self->size.bottom));
460 /* find the new coordinates, done after setting the frame.size, for
461 frame_client_gravity. */
462 self->area.x = self->client->area.x;
463 self->area.y = self->client->area.y;
464 frame_client_gravity(self, &self->area.x, &self->area.y);
468 /* move and resize the top level frame.
469 shading can change without being moved or resized */
470 XMoveResizeWindow(ob_display, self->window,
471 self->area.x, self->area.y,
472 self->area.width - self->bwidth * 2,
473 self->area.height - self->bwidth * 2);
476 framerender_frame(self);
477 frame_adjust_shape(self);
480 if (!STRUT_EQUAL(self->size, oldsize)) {
482 vals[0] = self->size.left;
483 vals[1] = self->size.right;
484 vals[2] = self->size.top;
485 vals[3] = self->size.bottom;
486 PROP_SETA32(self->client->window, net_frame_extents,
490 /* if this occurs while we are focus cycling, the indicator needs to
492 if (focus_cycle_target == self->client)
493 focus_cycle_draw_indicator();
495 if (resized && (self->decorations & OB_FRAME_DECOR_TITLEBAR))
496 XResizeWindow(ob_display, self->label, self->label_width,
497 ob_rr_theme->label_height);
500 void frame_adjust_state(ObFrame *self)
502 framerender_frame(self);
505 void frame_adjust_focus(ObFrame *self, gboolean hilite)
507 self->focused = hilite;
508 framerender_frame(self);
512 void frame_adjust_client_area(ObFrame *self)
514 /* resize the plate */
515 XResizeWindow(ob_display, self->plate,
516 self->client->area.width, self->client->area.height);
519 void frame_adjust_title(ObFrame *self)
521 framerender_frame(self);
524 void frame_adjust_icon(ObFrame *self)
526 framerender_frame(self);
529 void frame_grab_client(ObFrame *self, ObClient *client)
531 self->client = client;
533 /* reparent the client to the frame */
534 XReparentWindow(ob_display, client->window, self->plate, 0, 0);
536 When reparenting the client window, it is usually not mapped yet, since
537 this occurs from a MapRequest. However, in the case where Openbox is
538 starting up, the window is already mapped, so we'll see unmap events for
539 it. There are 2 unmap events generated that we see, one with the 'event'
540 member set the root window, and one set to the client, but both get
541 handled and need to be ignored.
543 if (ob_state() == OB_STATE_STARTING)
544 client->ignore_unmaps += 2;
546 /* select the event mask on the client's parent (to receive config/map
547 req's) the ButtonPress is to catch clicks on the client border */
548 XSelectInput(ob_display, self->plate, PLATE_EVENTMASK);
550 frame_adjust_area(self, TRUE, TRUE, FALSE);
552 /* map the client so it maps when the frame does */
553 XMapWindow(ob_display, client->window);
555 /* set all the windows for the frame in the window_map */
556 g_hash_table_insert(window_map, &self->window, client);
557 g_hash_table_insert(window_map, &self->plate, client);
558 g_hash_table_insert(window_map, &self->inner, client);
559 g_hash_table_insert(window_map, &self->title, client);
560 g_hash_table_insert(window_map, &self->label, client);
561 g_hash_table_insert(window_map, &self->max, client);
562 g_hash_table_insert(window_map, &self->close, client);
563 g_hash_table_insert(window_map, &self->desk, client);
564 g_hash_table_insert(window_map, &self->shade, client);
565 g_hash_table_insert(window_map, &self->icon, client);
566 g_hash_table_insert(window_map, &self->iconify, client);
567 g_hash_table_insert(window_map, &self->handle, client);
568 g_hash_table_insert(window_map, &self->lgrip, client);
569 g_hash_table_insert(window_map, &self->rgrip, client);
570 g_hash_table_insert(window_map, &self->tltresize, client);
571 g_hash_table_insert(window_map, &self->tllresize, client);
572 g_hash_table_insert(window_map, &self->trtresize, client);
573 g_hash_table_insert(window_map, &self->trrresize, client);
576 void frame_release_client(ObFrame *self, ObClient *client)
579 gboolean reparent = TRUE;
581 g_assert(self->client == client);
583 /* check if the app has already reparented its window away */
584 while (XCheckTypedWindowEvent(ob_display, client->window,
585 ReparentNotify, &ev))
587 /* This check makes sure we don't catch our own reparent action to
588 our frame window. This doesn't count as the app reparenting itself
591 Reparent events that are generated by us are just discarded here.
592 They are of no consequence to us anyhow.
594 if (ev.xreparent.parent != self->plate) {
596 XPutBackEvent(ob_display, &ev);
602 /* according to the ICCCM - if the client doesn't reparent itself,
603 then we will reparent the window to root for them */
604 XReparentWindow(ob_display, client->window,
605 RootWindow(ob_display, ob_screen),
610 /* remove all the windows for the frame from the window_map */
611 g_hash_table_remove(window_map, &self->window);
612 g_hash_table_remove(window_map, &self->plate);
613 g_hash_table_remove(window_map, &self->inner);
614 g_hash_table_remove(window_map, &self->title);
615 g_hash_table_remove(window_map, &self->label);
616 g_hash_table_remove(window_map, &self->max);
617 g_hash_table_remove(window_map, &self->close);
618 g_hash_table_remove(window_map, &self->desk);
619 g_hash_table_remove(window_map, &self->shade);
620 g_hash_table_remove(window_map, &self->icon);
621 g_hash_table_remove(window_map, &self->iconify);
622 g_hash_table_remove(window_map, &self->handle);
623 g_hash_table_remove(window_map, &self->lgrip);
624 g_hash_table_remove(window_map, &self->rgrip);
625 g_hash_table_remove(window_map, &self->tltresize);
626 g_hash_table_remove(window_map, &self->tllresize);
627 g_hash_table_remove(window_map, &self->trtresize);
628 g_hash_table_remove(window_map, &self->trrresize);
630 ob_main_loop_timeout_remove_data(ob_main_loop, flash_timeout, self, TRUE);
635 static void layout_title(ObFrame *self)
639 gboolean n, d, i, l, m, c, s;
641 n = d = i = l = m = c = s = FALSE;
643 /* figure out whats being shown, and the width of the label */
644 self->label_width = self->width - (ob_rr_theme->paddingx + 1) * 2;
645 for (lc = config_title_layout; *lc != '\0'; ++lc) {
648 if (n) { *lc = ' '; break; } /* rm duplicates */
650 self->label_width -= (ob_rr_theme->button_size + 2 +
651 ob_rr_theme->paddingx + 1);
654 if (d) { *lc = ' '; break; }
655 if (!(self->decorations & OB_FRAME_DECOR_ALLDESKTOPS)
656 && config_theme_hidedisabled)
659 self->label_width -= (ob_rr_theme->button_size +
660 ob_rr_theme->paddingx + 1);
663 if (s) { *lc = ' '; break; }
664 if (!(self->decorations & OB_FRAME_DECOR_SHADE)
665 && config_theme_hidedisabled)
668 self->label_width -= (ob_rr_theme->button_size +
669 ob_rr_theme->paddingx + 1);
672 if (i) { *lc = ' '; break; }
673 if (!(self->decorations & OB_FRAME_DECOR_ICONIFY)
674 && config_theme_hidedisabled)
677 self->label_width -= (ob_rr_theme->button_size +
678 ob_rr_theme->paddingx + 1);
681 if (l) { *lc = ' '; break; }
685 if (m) { *lc = ' '; break; }
686 if (!(self->decorations & OB_FRAME_DECOR_MAXIMIZE)
687 && config_theme_hidedisabled)
690 self->label_width -= (ob_rr_theme->button_size +
691 ob_rr_theme->paddingx + 1);
694 if (c) { *lc = ' '; break; }
695 if (!(self->decorations & OB_FRAME_DECOR_CLOSE)
696 && config_theme_hidedisabled)
699 self->label_width -= (ob_rr_theme->button_size +
700 ob_rr_theme->paddingx + 1);
704 if (self->label_width < 1) self->label_width = 1;
706 if (!n) XUnmapWindow(ob_display, self->icon);
707 if (!d) XUnmapWindow(ob_display, self->desk);
708 if (!s) XUnmapWindow(ob_display, self->shade);
709 if (!i) XUnmapWindow(ob_display, self->iconify);
710 if (!l) XUnmapWindow(ob_display, self->label);
711 if (!m) XUnmapWindow(ob_display, self->max);
712 if (!c) XUnmapWindow(ob_display, self->close);
714 x = ob_rr_theme->paddingx + 1;
715 for (lc = config_title_layout; *lc != '\0'; ++lc) {
720 XMapWindow(ob_display, self->icon);
721 XMoveWindow(ob_display, self->icon, x, ob_rr_theme->paddingy);
722 x += ob_rr_theme->button_size + 2 + ob_rr_theme->paddingx + 1;
727 XMapWindow(ob_display, self->desk);
728 XMoveWindow(ob_display, self->desk, x, ob_rr_theme->paddingy + 1);
729 x += ob_rr_theme->button_size + ob_rr_theme->paddingx + 1;
734 XMapWindow(ob_display, self->shade);
735 XMoveWindow(ob_display, self->shade, x, ob_rr_theme->paddingy + 1);
736 x += ob_rr_theme->button_size + ob_rr_theme->paddingx + 1;
741 XMapWindow(ob_display, self->iconify);
742 XMoveWindow(ob_display,self->iconify, x, ob_rr_theme->paddingy + 1);
743 x += ob_rr_theme->button_size + ob_rr_theme->paddingx + 1;
748 XMapWindow(ob_display, self->label);
749 XMoveWindow(ob_display, self->label, x, ob_rr_theme->paddingy);
750 x += self->label_width + ob_rr_theme->paddingx + 1;
755 XMapWindow(ob_display, self->max);
756 XMoveWindow(ob_display, self->max, x, ob_rr_theme->paddingy + 1);
757 x += ob_rr_theme->button_size + ob_rr_theme->paddingx + 1;
762 XMapWindow(ob_display, self->close);
763 XMoveWindow(ob_display, self->close, x, ob_rr_theme->paddingy + 1);
764 x += ob_rr_theme->button_size + ob_rr_theme->paddingx + 1;
770 ObFrameContext frame_context_from_string(const gchar *name)
772 if (!g_ascii_strcasecmp("Desktop", name))
773 return OB_FRAME_CONTEXT_DESKTOP;
774 else if (!g_ascii_strcasecmp("Client", name))
775 return OB_FRAME_CONTEXT_CLIENT;
776 else if (!g_ascii_strcasecmp("Titlebar", name))
777 return OB_FRAME_CONTEXT_TITLEBAR;
778 else if (!g_ascii_strcasecmp("Handle", name))
779 return OB_FRAME_CONTEXT_HANDLE;
780 else if (!g_ascii_strcasecmp("Frame", name))
781 return OB_FRAME_CONTEXT_FRAME;
782 else if (!g_ascii_strcasecmp("TLCorner", name))
783 return OB_FRAME_CONTEXT_TLCORNER;
784 else if (!g_ascii_strcasecmp("TRCorner", name))
785 return OB_FRAME_CONTEXT_TRCORNER;
786 else if (!g_ascii_strcasecmp("BLCorner", name))
787 return OB_FRAME_CONTEXT_BLCORNER;
788 else if (!g_ascii_strcasecmp("BRCorner", name))
789 return OB_FRAME_CONTEXT_BRCORNER;
790 else if (!g_ascii_strcasecmp("Maximize", name))
791 return OB_FRAME_CONTEXT_MAXIMIZE;
792 else if (!g_ascii_strcasecmp("AllDesktops", name))
793 return OB_FRAME_CONTEXT_ALLDESKTOPS;
794 else if (!g_ascii_strcasecmp("Shade", name))
795 return OB_FRAME_CONTEXT_SHADE;
796 else if (!g_ascii_strcasecmp("Iconify", name))
797 return OB_FRAME_CONTEXT_ICONIFY;
798 else if (!g_ascii_strcasecmp("Icon", name))
799 return OB_FRAME_CONTEXT_ICON;
800 else if (!g_ascii_strcasecmp("Close", name))
801 return OB_FRAME_CONTEXT_CLOSE;
802 else if (!g_ascii_strcasecmp("MoveResize", name))
803 return OB_FRAME_CONTEXT_MOVE_RESIZE;
804 return OB_FRAME_CONTEXT_NONE;
807 ObFrameContext frame_context(ObClient *client, Window win)
811 if (moveresize_in_progress)
812 return OB_FRAME_CONTEXT_MOVE_RESIZE;
814 if (win == RootWindow(ob_display, ob_screen))
815 return OB_FRAME_CONTEXT_DESKTOP;
816 if (client == NULL) return OB_FRAME_CONTEXT_NONE;
817 if (win == client->window) {
818 /* conceptually, this is the desktop, as far as users are
820 if (client->type == OB_CLIENT_TYPE_DESKTOP)
821 return OB_FRAME_CONTEXT_DESKTOP;
822 return OB_FRAME_CONTEXT_CLIENT;
825 self = client->frame;
826 if (win == self->plate) {
827 /* conceptually, this is the desktop, as far as users are
829 if (client->type == OB_CLIENT_TYPE_DESKTOP)
830 return OB_FRAME_CONTEXT_DESKTOP;
831 return OB_FRAME_CONTEXT_CLIENT;
834 if (win == self->window) return OB_FRAME_CONTEXT_FRAME;
835 if (win == self->inner) return OB_FRAME_CONTEXT_FRAME;
836 if (win == self->title) return OB_FRAME_CONTEXT_TITLEBAR;
837 if (win == self->label) return OB_FRAME_CONTEXT_TITLEBAR;
838 if (win == self->handle) return OB_FRAME_CONTEXT_HANDLE;
839 if (win == self->lgrip) return OB_FRAME_CONTEXT_BLCORNER;
840 if (win == self->rgrip) return OB_FRAME_CONTEXT_BRCORNER;
841 if (win == self->tltresize) return OB_FRAME_CONTEXT_TLCORNER;
842 if (win == self->tllresize) return OB_FRAME_CONTEXT_TLCORNER;
843 if (win == self->trtresize) return OB_FRAME_CONTEXT_TRCORNER;
844 if (win == self->trrresize) return OB_FRAME_CONTEXT_TRCORNER;
845 if (win == self->max) return OB_FRAME_CONTEXT_MAXIMIZE;
846 if (win == self->iconify) return OB_FRAME_CONTEXT_ICONIFY;
847 if (win == self->close) return OB_FRAME_CONTEXT_CLOSE;
848 if (win == self->icon) return OB_FRAME_CONTEXT_ICON;
849 if (win == self->desk) return OB_FRAME_CONTEXT_ALLDESKTOPS;
850 if (win == self->shade) return OB_FRAME_CONTEXT_SHADE;
852 return OB_FRAME_CONTEXT_NONE;
855 void frame_client_gravity(ObFrame *self, gint *x, gint *y)
858 switch (self->client->gravity) {
860 case NorthWestGravity:
861 case SouthWestGravity:
868 *x -= (self->size.left + self->size.right) / 2;
871 case NorthEastGravity:
872 case SouthEastGravity:
874 *x -= self->size.left + self->size.right;
879 *x -= self->size.left;
884 switch (self->client->gravity) {
886 case NorthWestGravity:
887 case NorthEastGravity:
894 *y -= (self->size.top + self->size.bottom) / 2;
897 case SouthWestGravity:
898 case SouthEastGravity:
900 *y -= self->size.top + self->size.bottom;
905 *y -= self->size.top;
910 void frame_frame_gravity(ObFrame *self, gint *x, gint *y)
913 switch (self->client->gravity) {
915 case NorthWestGravity:
917 case SouthWestGravity:
922 *x += (self->size.left + self->size.right) / 2;
924 case NorthEastGravity:
926 case SouthEastGravity:
927 *x += self->size.left + self->size.right;
931 *x += self->size.left;
936 switch (self->client->gravity) {
938 case NorthWestGravity:
940 case NorthEastGravity:
945 *y += (self->size.top + self->size.bottom) / 2;
947 case SouthWestGravity:
949 case SouthEastGravity:
950 *y += self->size.top + self->size.bottom;
954 *y += self->size.top;
959 static void flash_done(gpointer data)
961 ObFrame *self = data;
963 if (self->focused != self->flash_on)
964 frame_adjust_focus(self, self->focused);
967 static gboolean flash_timeout(gpointer data)
969 ObFrame *self = data;
972 g_get_current_time(&now);
973 if (now.tv_sec > self->flash_end.tv_sec ||
974 (now.tv_sec == self->flash_end.tv_sec &&
975 now.tv_usec >= self->flash_end.tv_usec))
976 self->flashing = FALSE;
979 return FALSE; /* we are done */
981 self->flash_on = !self->flash_on;
982 if (!self->focused) {
983 frame_adjust_focus(self, self->flash_on);
984 self->focused = FALSE;
987 return TRUE; /* go again */
990 void frame_flash_start(ObFrame *self)
992 self->flash_on = self->focused;
995 ob_main_loop_timeout_add(ob_main_loop,
996 G_USEC_PER_SEC * 0.6,
1001 g_get_current_time(&self->flash_end);
1002 g_time_val_add(&self->flash_end, G_USEC_PER_SEC * 5);
1004 self->flashing = TRUE;
1007 void frame_flash_stop(ObFrame *self)
1009 self->flashing = FALSE;