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