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