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