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