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