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