]> Dogcows Code - chaz/openbox/blob - openbox/frame.c
Split RrPaint to RrPaint and RrPaintPixmap, so you can paint things other than window...
[chaz/openbox] / openbox / frame.c
1 /* -*- indent-tabs-mode: nil; tab-width: 4; c-basic-offset: 4; -*-
2
3 frame.c for the Openbox window manager
4 Copyright (c) 2006 Mikael Magnusson
5 Copyright (c) 2003 Ben Jansens
6
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.
11
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.
16
17 See the COPYING file for a copy of the GNU General Public License.
18 */
19
20 #include "frame.h"
21 #include "client.h"
22 #include "openbox.h"
23 #include "extensions.h"
24 #include "prop.h"
25 #include "config.h"
26 #include "framerender.h"
27 #include "mainloop.h"
28 #include "focus.h"
29 #include "moveresize.h"
30 #include "render/theme.h"
31
32 #define PLATE_EVENTMASK (SubstructureRedirectMask | ButtonPressMask)
33 #define FRAME_EVENTMASK (EnterWindowMask | LeaveWindowMask | \
34 ButtonPressMask | ButtonReleaseMask | \
35 VisibilityChangeMask)
36 #define ELEMENT_EVENTMASK (ButtonPressMask | ButtonReleaseMask | \
37 ButtonMotionMask | ExposureMask | \
38 EnterWindowMask | LeaveWindowMask)
39
40 #define FRAME_HANDLE_Y(f) (f->innersize.top + f->client->area.height + \
41 f->cbwidth_y)
42
43 static void layout_title(ObFrame *self);
44 static void flash_done(gpointer data);
45 static gboolean flash_timeout(gpointer data);
46
47 static void set_theme_statics(ObFrame *self);
48 static void free_theme_statics(ObFrame *self);
49
50 static Window createWindow(Window parent, Visual *visual,
51 gulong mask, XSetWindowAttributes *attrib)
52 {
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)),
56 mask, attrib);
57
58 }
59
60 static Visual *check_32bit_client(ObClient *c)
61 {
62 XWindowAttributes wattrib;
63 Status ret;
64
65 ret = XGetWindowAttributes(ob_display, c->window, &wattrib);
66 g_assert(ret != BadDrawable);
67 g_assert(ret != BadWindow);
68
69 if (wattrib.depth == 32)
70 return wattrib.visual;
71 return NULL;
72 }
73
74 ObFrame *frame_new(ObClient *client)
75 {
76 XSetWindowAttributes attrib;
77 gulong mask;
78 ObFrame *self;
79 Visual *visual;
80
81 self = g_new0(ObFrame, 1);
82
83 self->obscured = TRUE;
84
85 visual = check_32bit_client(client);
86
87 /* create the non-visible decor windows */
88
89 mask = CWEventMask;
90 if (visual) {
91 /* client has a 32-bit visual */
92 mask |= CWColormap | CWBackPixel | CWBorderPixel;
93 /* create a colormap with the visual */
94 self->colormap = attrib.colormap =
95 XCreateColormap(ob_display,
96 RootWindow(ob_display, ob_screen),
97 visual, AllocNone);
98 attrib.background_pixel = BlackPixel(ob_display, 0);
99 attrib.border_pixel = BlackPixel(ob_display, 0);
100 }
101 attrib.event_mask = FRAME_EVENTMASK;
102 self->window = createWindow(RootWindow(ob_display, ob_screen), visual,
103 mask, &attrib);
104 mask &= ~CWEventMask;
105 self->plate = createWindow(self->window, visual, mask, &attrib);
106
107 /* create the visible decor windows */
108
109 mask = CWEventMask;
110 if (visual) {
111 /* client has a 32-bit visual */
112 mask |= CWColormap | CWBackPixel | CWBorderPixel;
113 attrib.colormap = RrColormap(ob_rr_inst);
114 }
115 attrib.event_mask = ELEMENT_EVENTMASK;
116 self->title = createWindow(self->window, NULL, mask, &attrib);
117
118 mask |= CWCursor;
119 attrib.cursor = ob_cursor(OB_CURSOR_NORTHWEST);
120 self->tlresize = createWindow(self->title, NULL, mask, &attrib);
121 attrib.cursor = ob_cursor(OB_CURSOR_NORTHEAST);
122 self->trresize = createWindow(self->title, NULL, mask, &attrib);
123
124 mask &= ~CWCursor;
125 self->label = createWindow(self->title, NULL, mask, &attrib);
126 self->max = createWindow(self->title, NULL, mask, &attrib);
127 self->close = createWindow(self->title, NULL, mask, &attrib);
128 self->desk = createWindow(self->title, NULL, mask, &attrib);
129 self->shade = createWindow(self->title, NULL, mask, &attrib);
130 self->icon = createWindow(self->title, NULL, mask, &attrib);
131 self->iconify = createWindow(self->title, NULL, mask, &attrib);
132 self->handle = createWindow(self->window, NULL, mask, &attrib);
133
134 mask |= CWCursor;
135 attrib.cursor = ob_cursor(OB_CURSOR_SOUTHWEST);
136 self->lgrip = createWindow(self->handle, NULL, mask, &attrib);
137 attrib.cursor = ob_cursor(OB_CURSOR_SOUTHEAST);
138 self->rgrip = createWindow(self->handle, NULL, mask, &attrib);
139
140 self->focused = FALSE;
141
142 /* the other stuff is shown based on decor settings */
143 XMapWindow(ob_display, self->plate);
144 XMapWindow(ob_display, self->lgrip);
145 XMapWindow(ob_display, self->rgrip);
146 XMapWindow(ob_display, self->label);
147
148 self->max_press = self->close_press = self->desk_press =
149 self->iconify_press = self->shade_press = FALSE;
150 self->max_hover = self->close_hover = self->desk_hover =
151 self->iconify_hover = self->shade_hover = FALSE;
152
153 set_theme_statics(self);
154
155 return (ObFrame*)self;
156 }
157
158 static void set_theme_statics(ObFrame *self)
159 {
160 /* set colors/appearance/sizes for stuff that doesn't change */
161 XSetWindowBorder(ob_display, self->window,
162 RrColorPixel(ob_rr_theme->frame_b_color));
163 XSetWindowBorder(ob_display, self->title,
164 RrColorPixel(ob_rr_theme->frame_b_color));
165 XSetWindowBorder(ob_display, self->handle,
166 RrColorPixel(ob_rr_theme->frame_b_color));
167 XSetWindowBorder(ob_display, self->rgrip,
168 RrColorPixel(ob_rr_theme->frame_b_color));
169 XSetWindowBorder(ob_display, self->lgrip,
170 RrColorPixel(ob_rr_theme->frame_b_color));
171
172 XResizeWindow(ob_display, self->max,
173 ob_rr_theme->button_size, ob_rr_theme->button_size);
174 XResizeWindow(ob_display, self->iconify,
175 ob_rr_theme->button_size, ob_rr_theme->button_size);
176 XResizeWindow(ob_display, self->icon,
177 ob_rr_theme->button_size + 2, ob_rr_theme->button_size + 2);
178 XResizeWindow(ob_display, self->close,
179 ob_rr_theme->button_size, ob_rr_theme->button_size);
180 XResizeWindow(ob_display, self->desk,
181 ob_rr_theme->button_size, ob_rr_theme->button_size);
182 XResizeWindow(ob_display, self->shade,
183 ob_rr_theme->button_size, ob_rr_theme->button_size);
184 if (ob_rr_theme->handle_height > 0) {
185 XResizeWindow(ob_display, self->lgrip,
186 ob_rr_theme->grip_width, ob_rr_theme->handle_height);
187 XResizeWindow(ob_display, self->rgrip,
188 ob_rr_theme->grip_width, ob_rr_theme->handle_height);
189 }
190 XResizeWindow(ob_display, self->tlresize,
191 ob_rr_theme->grip_width, ob_rr_theme->top_grip_height);
192 XResizeWindow(ob_display, self->trresize,
193 ob_rr_theme->grip_width, ob_rr_theme->top_grip_height);
194
195 /* set up the dynamic appearances */
196 self->a_unfocused_title = RrAppearanceCopy(ob_rr_theme->a_unfocused_title);
197 self->a_focused_title = RrAppearanceCopy(ob_rr_theme->a_focused_title);
198 self->a_unfocused_label = RrAppearanceCopy(ob_rr_theme->a_unfocused_label);
199 self->a_focused_label = RrAppearanceCopy(ob_rr_theme->a_focused_label);
200 self->a_unfocused_handle =
201 RrAppearanceCopy(ob_rr_theme->a_unfocused_handle);
202 self->a_focused_handle = RrAppearanceCopy(ob_rr_theme->a_focused_handle);
203 self->a_icon = RrAppearanceCopy(ob_rr_theme->a_icon);
204 }
205
206 static void free_theme_statics(ObFrame *self)
207 {
208 RrAppearanceFree(self->a_unfocused_title);
209 RrAppearanceFree(self->a_focused_title);
210 RrAppearanceFree(self->a_unfocused_label);
211 RrAppearanceFree(self->a_focused_label);
212 RrAppearanceFree(self->a_unfocused_handle);
213 RrAppearanceFree(self->a_focused_handle);
214 RrAppearanceFree(self->a_icon);
215 }
216
217 static void frame_free(ObFrame *self)
218 {
219 free_theme_statics(self);
220
221 XDestroyWindow(ob_display, self->window);
222 if (self->colormap)
223 XFreeColormap(ob_display, self->colormap);
224
225 g_free(self);
226 }
227
228 void frame_show(ObFrame *self)
229 {
230 if (!self->visible) {
231 self->visible = TRUE;
232 XMapWindow(ob_display, self->client->window);
233 XMapWindow(ob_display, self->window);
234 }
235 }
236
237 void frame_hide(ObFrame *self)
238 {
239 if (self->visible) {
240 self->visible = FALSE;
241 self->client->ignore_unmaps += 2;
242 /* we unmap the client itself so that we can get MapRequest
243 events, and because the ICCCM tells us to! */
244 XUnmapWindow(ob_display, self->window);
245 XUnmapWindow(ob_display, self->client->window);
246 }
247 }
248
249 void frame_adjust_theme(ObFrame *self)
250 {
251 free_theme_statics(self);
252 set_theme_statics(self);
253 }
254
255 void frame_adjust_shape(ObFrame *self)
256 {
257 #ifdef SHAPE
258 gint num;
259 XRectangle xrect[2];
260
261 if (!self->client->shaped) {
262 /* clear the shape on the frame window */
263 XShapeCombineMask(ob_display, self->window, ShapeBounding,
264 self->innersize.left,
265 self->innersize.top,
266 None, ShapeSet);
267 } else {
268 /* make the frame's shape match the clients */
269 XShapeCombineShape(ob_display, self->window, ShapeBounding,
270 self->innersize.left,
271 self->innersize.top,
272 self->client->window,
273 ShapeBounding, ShapeSet);
274
275 num = 0;
276 if (self->decorations & OB_FRAME_DECOR_TITLEBAR) {
277 xrect[0].x = -ob_rr_theme->fbwidth;
278 xrect[0].y = -ob_rr_theme->fbwidth;
279 xrect[0].width = self->width + self->rbwidth * 2;
280 xrect[0].height = ob_rr_theme->title_height +
281 self->bwidth * 2;
282 ++num;
283 }
284
285 if (self->decorations & OB_FRAME_DECOR_HANDLE) {
286 xrect[1].x = -ob_rr_theme->fbwidth;
287 xrect[1].y = FRAME_HANDLE_Y(self);
288 xrect[1].width = self->width + self->rbwidth * 2;
289 xrect[1].height = ob_rr_theme->handle_height +
290 self->bwidth * 2;
291 ++num;
292 }
293
294 XShapeCombineRectangles(ob_display, self->window,
295 ShapeBounding, 0, 0, xrect, num,
296 ShapeUnion, Unsorted);
297 }
298 #endif
299 }
300
301 void frame_adjust_area(ObFrame *self, gboolean moved,
302 gboolean resized, gboolean fake)
303 {
304 Strut oldsize;
305
306 oldsize = self->size;
307
308 if (resized) {
309 self->decorations = self->client->decorations;
310 self->max_horz = self->client->max_horz;
311
312 if (self->decorations & OB_FRAME_DECOR_BORDER) {
313 self->bwidth = ob_rr_theme->fbwidth;
314 self->cbwidth_x = ob_rr_theme->cbwidthx;
315 self->cbwidth_y = ob_rr_theme->cbwidthy;
316 } else {
317 self->bwidth = self->cbwidth_x = self->cbwidth_y = 0;
318 }
319 self->rbwidth = self->bwidth;
320
321 if (self->max_horz)
322 self->bwidth = self->cbwidth_x = 0;
323
324 STRUT_SET(self->innersize,
325 self->cbwidth_x,
326 self->cbwidth_y,
327 self->cbwidth_x,
328 self->cbwidth_y);
329 self->width = self->client->area.width + self->cbwidth_x * 2 -
330 (self->max_horz ? self->rbwidth * 2 : 0);
331 self->width = MAX(self->width, 1); /* no lower than 1 */
332
333 /* set border widths */
334 if (!fake) {
335 XSetWindowBorderWidth(ob_display, self->window, self->bwidth);
336 XSetWindowBorderWidth(ob_display, self->title, self->rbwidth);
337 XSetWindowBorderWidth(ob_display, self->handle, self->rbwidth);
338 XSetWindowBorderWidth(ob_display, self->lgrip, self->rbwidth);
339 XSetWindowBorderWidth(ob_display, self->rgrip, self->rbwidth);
340 }
341
342 if (self->decorations & OB_FRAME_DECOR_TITLEBAR)
343 self->innersize.top += ob_rr_theme->title_height + self->rbwidth +
344 (self->rbwidth - self->bwidth);
345 if (self->decorations & OB_FRAME_DECOR_HANDLE &&
346 ob_rr_theme->handle_height > 0)
347 self->innersize.bottom += ob_rr_theme->handle_height +
348 self->rbwidth + (self->rbwidth - self->bwidth);
349
350 /* they all default off, they're turned on in layout_title */
351 self->icon_x = -1;
352 self->desk_x = -1;
353 self->shade_x = -1;
354 self->iconify_x = -1;
355 self->label_x = -1;
356 self->max_x = -1;
357 self->close_x = -1;
358
359 /* position/size and map/unmap all the windows */
360
361 if (!fake) {
362 if (self->decorations & OB_FRAME_DECOR_TITLEBAR) {
363 XMoveResizeWindow(ob_display, self->title,
364 -self->bwidth, -self->bwidth,
365 self->width, ob_rr_theme->title_height);
366 XMapWindow(ob_display, self->title);
367
368 if (self->decorations & OB_FRAME_DECOR_GRIPS) {
369 XMoveWindow(ob_display, self->tlresize, 0, 0);
370 XMoveWindow(ob_display, self->trresize,
371 self->width - ob_rr_theme->grip_width, 0);
372 XMapWindow(ob_display, self->tlresize);
373 XMapWindow(ob_display, self->trresize);
374 } else {
375 XUnmapWindow(ob_display, self->tlresize);
376 XUnmapWindow(ob_display, self->trresize);
377 }
378 } else
379 XUnmapWindow(ob_display, self->title);
380 }
381
382 if (self->decorations & OB_FRAME_DECOR_TITLEBAR)
383 /* layout the title bar elements */
384 layout_title(self);
385
386 if (!fake) {
387 if (self->decorations & OB_FRAME_DECOR_HANDLE &&
388 ob_rr_theme->handle_height > 0)
389 {
390 XMoveResizeWindow(ob_display, self->handle,
391 -self->bwidth, FRAME_HANDLE_Y(self),
392 self->width, ob_rr_theme->handle_height);
393 XMapWindow(ob_display, self->handle);
394
395 if (self->decorations & OB_FRAME_DECOR_GRIPS) {
396 XMoveWindow(ob_display, self->lgrip,
397 -self->rbwidth, -self->rbwidth);
398 XMoveWindow(ob_display, self->rgrip,
399 -self->rbwidth + self->width -
400 ob_rr_theme->grip_width, -self->rbwidth);
401 XMapWindow(ob_display, self->lgrip);
402 XMapWindow(ob_display, self->rgrip);
403 } else {
404 XUnmapWindow(ob_display, self->lgrip);
405 XUnmapWindow(ob_display, self->rgrip);
406 }
407 } else
408 XUnmapWindow(ob_display, self->handle);
409
410 /* move and resize the plate */
411 XMoveResizeWindow(ob_display, self->plate,
412 self->innersize.left - self->cbwidth_x,
413 self->innersize.top - self->cbwidth_y,
414 self->client->area.width + self->cbwidth_x * 2,
415 self->client->area.height + self->cbwidth_y * 2);
416 /* when the client has StaticGravity, it likes to move around. */
417 XMoveWindow(ob_display, self->client->window,
418 self->cbwidth_x, self->cbwidth_y);
419 }
420
421 STRUT_SET(self->size,
422 self->innersize.left + self->bwidth,
423 self->innersize.top + self->bwidth,
424 self->innersize.right + self->bwidth,
425 self->innersize.bottom + self->bwidth);
426 }
427
428 /* shading can change without being moved or resized */
429 RECT_SET_SIZE(self->area,
430 self->client->area.width +
431 self->size.left + self->size.right,
432 (self->client->shaded ?
433 ob_rr_theme->title_height + self->rbwidth * 2:
434 self->client->area.height +
435 self->size.top + self->size.bottom));
436
437 if (moved) {
438 /* find the new coordinates, done after setting the frame.size, for
439 frame_client_gravity. */
440 self->area.x = self->client->area.x;
441 self->area.y = self->client->area.y;
442 frame_client_gravity(self, &self->area.x, &self->area.y);
443 }
444
445 if (!fake) {
446 /* move and resize the top level frame.
447 shading can change without being moved or resized */
448 XMoveResizeWindow(ob_display, self->window,
449 self->area.x, self->area.y,
450 self->area.width - self->bwidth * 2,
451 self->area.height - self->bwidth * 2);
452
453 if (resized) {
454 framerender_frame(self);
455 frame_adjust_shape(self);
456 }
457
458 if (!STRUT_EQUAL(self->size, oldsize)) {
459 gulong vals[4];
460 vals[0] = self->size.left;
461 vals[1] = self->size.right;
462 vals[2] = self->size.top;
463 vals[3] = self->size.bottom;
464 PROP_SETA32(self->client->window, kde_net_wm_frame_strut,
465 cardinal, vals, 4);
466 }
467
468 /* if this occurs while we are focus cycling, the indicator needs to
469 match the changes */
470 if (focus_cycle_target == self->client)
471 focus_cycle_draw_indicator();
472 }
473 if (resized && (self->decorations & OB_FRAME_DECOR_TITLEBAR))
474 XResizeWindow(ob_display, self->label, self->label_width,
475 ob_rr_theme->label_height);
476 }
477
478 void frame_adjust_state(ObFrame *self)
479 {
480 framerender_frame(self);
481 }
482
483 void frame_adjust_focus(ObFrame *self, gboolean hilite)
484 {
485 self->focused = hilite;
486 framerender_frame(self);
487 }
488
489 void frame_adjust_title(ObFrame *self)
490 {
491 framerender_frame(self);
492 }
493
494 void frame_adjust_icon(ObFrame *self)
495 {
496 framerender_frame(self);
497 }
498
499 void frame_grab_client(ObFrame *self, ObClient *client)
500 {
501 self->client = client;
502
503 /* reparent the client to the frame */
504 XReparentWindow(ob_display, client->window, self->plate, 0, 0);
505 /*
506 When reparenting the client window, it is usually not mapped yet, since
507 this occurs from a MapRequest. However, in the case where Openbox is
508 starting up, the window is already mapped, so we'll see unmap events for
509 it. There are 2 unmap events generated that we see, one with the 'event'
510 member set the root window, and one set to the client, but both get
511 handled and need to be ignored.
512 */
513 if (ob_state() == OB_STATE_STARTING)
514 client->ignore_unmaps += 2;
515
516 /* select the event mask on the client's parent (to receive config/map
517 req's) the ButtonPress is to catch clicks on the client border */
518 XSelectInput(ob_display, self->plate, PLATE_EVENTMASK);
519
520 /* map the client so it maps when the frame does */
521 XMapWindow(ob_display, client->window);
522
523 frame_adjust_area(self, TRUE, TRUE, FALSE);
524
525 /* set all the windows for the frame in the window_map */
526 g_hash_table_insert(window_map, &self->window, client);
527 g_hash_table_insert(window_map, &self->plate, client);
528 g_hash_table_insert(window_map, &self->title, client);
529 g_hash_table_insert(window_map, &self->label, client);
530 g_hash_table_insert(window_map, &self->max, client);
531 g_hash_table_insert(window_map, &self->close, client);
532 g_hash_table_insert(window_map, &self->desk, client);
533 g_hash_table_insert(window_map, &self->shade, client);
534 g_hash_table_insert(window_map, &self->icon, client);
535 g_hash_table_insert(window_map, &self->iconify, client);
536 g_hash_table_insert(window_map, &self->handle, client);
537 g_hash_table_insert(window_map, &self->lgrip, client);
538 g_hash_table_insert(window_map, &self->rgrip, client);
539 g_hash_table_insert(window_map, &self->tlresize, client);
540 g_hash_table_insert(window_map, &self->trresize, client);
541 }
542
543 void frame_release_client(ObFrame *self, ObClient *client)
544 {
545 XEvent ev;
546 gboolean reparent = TRUE;
547
548 g_assert(self->client == client);
549
550 /* check if the app has already reparented its window away */
551 while (XCheckTypedWindowEvent(ob_display, client->window,
552 ReparentNotify, &ev))
553 {
554 /* This check makes sure we don't catch our own reparent action to
555 our frame window. This doesn't count as the app reparenting itself
556 away of course.
557
558 Reparent events that are generated by us are just discarded here.
559 They are of no consequence to us anyhow.
560 */
561 if (ev.xreparent.parent != self->plate) {
562 reparent = FALSE;
563 XPutBackEvent(ob_display, &ev);
564 break;
565 }
566 }
567
568 if (reparent) {
569 /* according to the ICCCM - if the client doesn't reparent itself,
570 then we will reparent the window to root for them */
571 XReparentWindow(ob_display, client->window,
572 RootWindow(ob_display, ob_screen),
573 client->area.x,
574 client->area.y);
575 }
576
577 /* remove all the windows for the frame from the window_map */
578 g_hash_table_remove(window_map, &self->window);
579 g_hash_table_remove(window_map, &self->plate);
580 g_hash_table_remove(window_map, &self->title);
581 g_hash_table_remove(window_map, &self->label);
582 g_hash_table_remove(window_map, &self->max);
583 g_hash_table_remove(window_map, &self->close);
584 g_hash_table_remove(window_map, &self->desk);
585 g_hash_table_remove(window_map, &self->shade);
586 g_hash_table_remove(window_map, &self->icon);
587 g_hash_table_remove(window_map, &self->iconify);
588 g_hash_table_remove(window_map, &self->handle);
589 g_hash_table_remove(window_map, &self->lgrip);
590 g_hash_table_remove(window_map, &self->rgrip);
591 g_hash_table_remove(window_map, &self->tlresize);
592 g_hash_table_remove(window_map, &self->trresize);
593
594 ob_main_loop_timeout_remove_data(ob_main_loop, flash_timeout, self, TRUE);
595
596 frame_free(self);
597 }
598
599 static void layout_title(ObFrame *self)
600 {
601 gchar *lc;
602 gint x;
603 gboolean n, d, i, l, m, c, s;
604
605 n = d = i = l = m = c = s = FALSE;
606
607 /* figure out whats being shown, and the width of the label */
608 self->label_width = self->width - (ob_rr_theme->paddingx + 1) * 2;
609 for (lc = config_title_layout; *lc != '\0'; ++lc) {
610 switch (*lc) {
611 case 'N':
612 if (n) { *lc = ' '; break; } /* rm duplicates */
613 n = TRUE;
614 self->label_width -= (ob_rr_theme->button_size + 2 +
615 ob_rr_theme->paddingx + 1);
616 break;
617 case 'D':
618 if (d) { *lc = ' '; break; }
619 if (!(self->decorations & OB_FRAME_DECOR_ALLDESKTOPS)
620 && config_theme_hidedisabled)
621 break;
622 d = TRUE;
623 self->label_width -= (ob_rr_theme->button_size +
624 ob_rr_theme->paddingx + 1);
625 break;
626 case 'S':
627 if (s) { *lc = ' '; break; }
628 if (!(self->decorations & OB_FRAME_DECOR_SHADE)
629 && config_theme_hidedisabled)
630 break;
631 s = TRUE;
632 self->label_width -= (ob_rr_theme->button_size +
633 ob_rr_theme->paddingx + 1);
634 break;
635 case 'I':
636 if (i) { *lc = ' '; break; }
637 if (!(self->decorations & OB_FRAME_DECOR_ICONIFY)
638 && config_theme_hidedisabled)
639 break;
640 i = TRUE;
641 self->label_width -= (ob_rr_theme->button_size +
642 ob_rr_theme->paddingx + 1);
643 break;
644 case 'L':
645 if (l) { *lc = ' '; break; }
646 l = TRUE;
647 break;
648 case 'M':
649 if (m) { *lc = ' '; break; }
650 if (!(self->decorations & OB_FRAME_DECOR_MAXIMIZE)
651 && config_theme_hidedisabled)
652 break;
653 m = TRUE;
654 self->label_width -= (ob_rr_theme->button_size +
655 ob_rr_theme->paddingx + 1);
656 break;
657 case 'C':
658 if (c) { *lc = ' '; break; }
659 if (!(self->decorations & OB_FRAME_DECOR_CLOSE)
660 && config_theme_hidedisabled)
661 break;
662 c = TRUE;
663 self->label_width -= (ob_rr_theme->button_size +
664 ob_rr_theme->paddingx + 1);
665 break;
666 }
667 }
668 if (self->label_width < 1) self->label_width = 1;
669
670 if (!n) XUnmapWindow(ob_display, self->icon);
671 if (!d) XUnmapWindow(ob_display, self->desk);
672 if (!s) XUnmapWindow(ob_display, self->shade);
673 if (!i) XUnmapWindow(ob_display, self->iconify);
674 if (!l) XUnmapWindow(ob_display, self->label);
675 if (!m) XUnmapWindow(ob_display, self->max);
676 if (!c) XUnmapWindow(ob_display, self->close);
677
678 x = ob_rr_theme->paddingx + 1;
679 for (lc = config_title_layout; *lc != '\0'; ++lc) {
680 switch (*lc) {
681 case 'N':
682 if (!n) break;
683 self->icon_x = x;
684 XMapWindow(ob_display, self->icon);
685 XMoveWindow(ob_display, self->icon, x, ob_rr_theme->paddingx);
686 x += ob_rr_theme->button_size + 2 + ob_rr_theme->paddingx + 1;
687 break;
688 case 'D':
689 if (!d) break;
690 self->desk_x = x;
691 XMapWindow(ob_display, self->desk);
692 XMoveWindow(ob_display, self->desk, x, ob_rr_theme->paddingx + 1);
693 x += ob_rr_theme->button_size + ob_rr_theme->paddingx + 1;
694 break;
695 case 'S':
696 if (!s) break;
697 self->shade_x = x;
698 XMapWindow(ob_display, self->shade);
699 XMoveWindow(ob_display, self->shade, x, ob_rr_theme->paddingx + 1);
700 x += ob_rr_theme->button_size + ob_rr_theme->paddingx + 1;
701 break;
702 case 'I':
703 if (!i) break;
704 self->iconify_x = x;
705 XMapWindow(ob_display, self->iconify);
706 XMoveWindow(ob_display,self->iconify, x, ob_rr_theme->paddingx + 1);
707 x += ob_rr_theme->button_size + ob_rr_theme->paddingx + 1;
708 break;
709 case 'L':
710 if (!l) break;
711 self->label_x = x;
712 XMapWindow(ob_display, self->label);
713 XMoveWindow(ob_display, self->label, x, ob_rr_theme->paddingx);
714 x += self->label_width + ob_rr_theme->paddingx + 1;
715 break;
716 case 'M':
717 if (!m) break;
718 self->max_x = x;
719 XMapWindow(ob_display, self->max);
720 XMoveWindow(ob_display, self->max, x, ob_rr_theme->paddingx + 1);
721 x += ob_rr_theme->button_size + ob_rr_theme->paddingx + 1;
722 break;
723 case 'C':
724 if (!c) break;
725 self->close_x = x;
726 XMapWindow(ob_display, self->close);
727 XMoveWindow(ob_display, self->close, x, ob_rr_theme->paddingx + 1);
728 x += ob_rr_theme->button_size + ob_rr_theme->paddingx + 1;
729 break;
730 }
731 }
732 }
733
734 ObFrameContext frame_context_from_string(const gchar *name)
735 {
736 if (!g_ascii_strcasecmp("Desktop", name))
737 return OB_FRAME_CONTEXT_DESKTOP;
738 else if (!g_ascii_strcasecmp("Client", name))
739 return OB_FRAME_CONTEXT_CLIENT;
740 else if (!g_ascii_strcasecmp("Titlebar", name))
741 return OB_FRAME_CONTEXT_TITLEBAR;
742 else if (!g_ascii_strcasecmp("Handle", name))
743 return OB_FRAME_CONTEXT_HANDLE;
744 else if (!g_ascii_strcasecmp("Frame", name))
745 return OB_FRAME_CONTEXT_FRAME;
746 else if (!g_ascii_strcasecmp("TLCorner", name))
747 return OB_FRAME_CONTEXT_TLCORNER;
748 else if (!g_ascii_strcasecmp("TRCorner", name))
749 return OB_FRAME_CONTEXT_TRCORNER;
750 else if (!g_ascii_strcasecmp("BLCorner", name))
751 return OB_FRAME_CONTEXT_BLCORNER;
752 else if (!g_ascii_strcasecmp("BRCorner", name))
753 return OB_FRAME_CONTEXT_BRCORNER;
754 else if (!g_ascii_strcasecmp("Maximize", name))
755 return OB_FRAME_CONTEXT_MAXIMIZE;
756 else if (!g_ascii_strcasecmp("AllDesktops", name))
757 return OB_FRAME_CONTEXT_ALLDESKTOPS;
758 else if (!g_ascii_strcasecmp("Shade", name))
759 return OB_FRAME_CONTEXT_SHADE;
760 else if (!g_ascii_strcasecmp("Iconify", name))
761 return OB_FRAME_CONTEXT_ICONIFY;
762 else if (!g_ascii_strcasecmp("Icon", name))
763 return OB_FRAME_CONTEXT_ICON;
764 else if (!g_ascii_strcasecmp("Close", name))
765 return OB_FRAME_CONTEXT_CLOSE;
766 else if (!g_ascii_strcasecmp("MoveResize", name))
767 return OB_FRAME_CONTEXT_MOVE_RESIZE;
768 return OB_FRAME_CONTEXT_NONE;
769 }
770
771 ObFrameContext frame_context(ObClient *client, Window win)
772 {
773 ObFrame *self;
774
775 if (moveresize_in_progress)
776 return OB_FRAME_CONTEXT_MOVE_RESIZE;
777
778 if (win == RootWindow(ob_display, ob_screen))
779 return OB_FRAME_CONTEXT_DESKTOP;
780 if (client == NULL) return OB_FRAME_CONTEXT_NONE;
781 if (win == client->window) {
782 /* conceptually, this is the desktop, as far as users are
783 concerned */
784 if (client->type == OB_CLIENT_TYPE_DESKTOP)
785 return OB_FRAME_CONTEXT_DESKTOP;
786 return OB_FRAME_CONTEXT_CLIENT;
787 }
788
789 self = client->frame;
790 if (win == self->plate) {
791 /* conceptually, this is the desktop, as far as users are
792 concerned */
793 if (client->type == OB_CLIENT_TYPE_DESKTOP)
794 return OB_FRAME_CONTEXT_DESKTOP;
795 return OB_FRAME_CONTEXT_CLIENT;
796 }
797
798 if (win == self->window) return OB_FRAME_CONTEXT_FRAME;
799 if (win == self->title) return OB_FRAME_CONTEXT_TITLEBAR;
800 if (win == self->label) return OB_FRAME_CONTEXT_TITLEBAR;
801 if (win == self->handle) return OB_FRAME_CONTEXT_HANDLE;
802 if (win == self->lgrip) return OB_FRAME_CONTEXT_BLCORNER;
803 if (win == self->rgrip) return OB_FRAME_CONTEXT_BRCORNER;
804 if (win == self->tlresize) return OB_FRAME_CONTEXT_TLCORNER;
805 if (win == self->trresize) return OB_FRAME_CONTEXT_TRCORNER;
806 if (win == self->max) return OB_FRAME_CONTEXT_MAXIMIZE;
807 if (win == self->iconify) return OB_FRAME_CONTEXT_ICONIFY;
808 if (win == self->close) return OB_FRAME_CONTEXT_CLOSE;
809 if (win == self->icon) return OB_FRAME_CONTEXT_ICON;
810 if (win == self->desk) return OB_FRAME_CONTEXT_ALLDESKTOPS;
811 if (win == self->shade) return OB_FRAME_CONTEXT_SHADE;
812
813 return OB_FRAME_CONTEXT_NONE;
814 }
815
816 void frame_client_gravity(ObFrame *self, gint *x, gint *y)
817 {
818 /* horizontal */
819 switch (self->client->gravity) {
820 default:
821 case NorthWestGravity:
822 case SouthWestGravity:
823 case WestGravity:
824 break;
825
826 case NorthGravity:
827 case SouthGravity:
828 case CenterGravity:
829 *x -= (self->size.left + self->size.right) / 2;
830 break;
831
832 case NorthEastGravity:
833 case SouthEastGravity:
834 case EastGravity:
835 *x -= self->size.left + self->size.right;
836 break;
837
838 case ForgetGravity:
839 case StaticGravity:
840 *x -= self->size.left;
841 break;
842 }
843
844 /* vertical */
845 switch (self->client->gravity) {
846 default:
847 case NorthWestGravity:
848 case NorthEastGravity:
849 case NorthGravity:
850 break;
851
852 case CenterGravity:
853 case EastGravity:
854 case WestGravity:
855 *y -= (self->size.top + self->size.bottom) / 2;
856 break;
857
858 case SouthWestGravity:
859 case SouthEastGravity:
860 case SouthGravity:
861 *y -= self->size.top + self->size.bottom;
862 break;
863
864 case ForgetGravity:
865 case StaticGravity:
866 *y -= self->size.top;
867 break;
868 }
869 }
870
871 void frame_frame_gravity(ObFrame *self, gint *x, gint *y)
872 {
873 /* horizontal */
874 switch (self->client->gravity) {
875 default:
876 case NorthWestGravity:
877 case WestGravity:
878 case SouthWestGravity:
879 break;
880 case NorthGravity:
881 case CenterGravity:
882 case SouthGravity:
883 *x += (self->size.left + self->size.right) / 2;
884 break;
885 case NorthEastGravity:
886 case EastGravity:
887 case SouthEastGravity:
888 *x += self->size.left + self->size.right;
889 break;
890 case StaticGravity:
891 case ForgetGravity:
892 *x += self->size.left;
893 break;
894 }
895
896 /* vertical */
897 switch (self->client->gravity) {
898 default:
899 case NorthWestGravity:
900 case NorthGravity:
901 case NorthEastGravity:
902 break;
903 case WestGravity:
904 case CenterGravity:
905 case EastGravity:
906 *y += (self->size.top + self->size.bottom) / 2;
907 break;
908 case SouthWestGravity:
909 case SouthGravity:
910 case SouthEastGravity:
911 *y += self->size.top + self->size.bottom;
912 break;
913 case StaticGravity:
914 case ForgetGravity:
915 *y += self->size.top;
916 break;
917 }
918 }
919
920 static void flash_done(gpointer data)
921 {
922 ObFrame *self = data;
923
924 if (self->focused != self->flash_on)
925 frame_adjust_focus(self, self->focused);
926 }
927
928 static gboolean flash_timeout(gpointer data)
929 {
930 ObFrame *self = data;
931 GTimeVal now;
932
933 g_get_current_time(&now);
934 if (now.tv_sec > self->flash_end.tv_sec ||
935 (now.tv_sec == self->flash_end.tv_sec &&
936 now.tv_usec >= self->flash_end.tv_usec))
937 self->flashing = FALSE;
938
939 if (!self->flashing)
940 return FALSE; /* we are done */
941
942 self->flash_on = !self->flash_on;
943 if (!self->focused) {
944 frame_adjust_focus(self, self->flash_on);
945 self->focused = FALSE;
946 }
947
948 return TRUE; /* go again */
949 }
950
951 void frame_flash_start(ObFrame *self)
952 {
953 self->flash_on = self->focused;
954
955 if (!self->flashing)
956 ob_main_loop_timeout_add(ob_main_loop,
957 G_USEC_PER_SEC * 0.6,
958 flash_timeout,
959 self,
960 flash_done);
961 g_get_current_time(&self->flash_end);
962 g_time_val_add(&self->flash_end, G_USEC_PER_SEC * 5);
963
964 self->flashing = TRUE;
965 }
966
967 void frame_flash_stop(ObFrame *self)
968 {
969 self->flashing = FALSE;
970 }
This page took 0.079825 seconds and 4 git commands to generate.