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