]> Dogcows Code - chaz/openbox/blob - openbox/frame.c
best fit only one direction
[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 }
187
188 void frame_adjust_shape(ObFrame *self)
189 {
190 #ifdef SHAPE
191 int num;
192 XRectangle xrect[2];
193
194 if (!self->client->shaped) {
195 /* clear the shape on the frame window */
196 XShapeCombineMask(ob_display, self->window, ShapeBounding,
197 self->innersize.left,
198 self->innersize.top,
199 None, ShapeSet);
200 } else {
201 /* make the frame's shape match the clients */
202 XShapeCombineShape(ob_display, self->window, ShapeBounding,
203 self->innersize.left,
204 self->innersize.top,
205 self->client->window,
206 ShapeBounding, ShapeSet);
207
208 num = 0;
209 if (self->decorations & OB_FRAME_DECOR_TITLEBAR) {
210 xrect[0].x = -ob_rr_theme->bwidth;
211 xrect[0].y = -ob_rr_theme->bwidth;
212 xrect[0].width = self->width + self->rbwidth * 2;
213 xrect[0].height = ob_rr_theme->title_height +
214 self->bwidth * 2;
215 ++num;
216 }
217
218 if (self->decorations & OB_FRAME_DECOR_HANDLE) {
219 xrect[1].x = -ob_rr_theme->bwidth;
220 xrect[1].y = FRAME_HANDLE_Y(self);
221 xrect[1].width = self->width + self->rbwidth * 2;
222 xrect[1].height = ob_rr_theme->handle_height +
223 self->bwidth * 2;
224 ++num;
225 }
226
227 XShapeCombineRectangles(ob_display, self->window,
228 ShapeBounding, 0, 0, xrect, num,
229 ShapeUnion, Unsorted);
230 }
231 #endif
232 }
233
234 void frame_adjust_area(ObFrame *self, gboolean moved,
235 gboolean resized, gboolean fake)
236 {
237 if (resized) {
238 self->decorations = self->client->decorations;
239 self->max_horz = self->client->max_horz;
240
241 if (self->decorations & OB_FRAME_DECOR_BORDER) {
242 self->bwidth = ob_rr_theme->bwidth;
243 self->cbwidth_x = self->cbwidth_y = ob_rr_theme->cbwidth;
244 } else {
245 self->bwidth = self->cbwidth_x = self->cbwidth_y = 0;
246 }
247 self->rbwidth = self->bwidth;
248
249 if (self->max_horz)
250 self->bwidth = self->cbwidth_x = 0;
251
252 STRUT_SET(self->innersize,
253 self->cbwidth_x,
254 self->cbwidth_y,
255 self->cbwidth_x,
256 self->cbwidth_y);
257 self->width = self->client->area.width + self->cbwidth_x * 2 -
258 (self->max_horz ? self->rbwidth * 2 : 0);
259 self->width = MAX(self->width, 1); /* no lower than 1 */
260
261 /* set border widths */
262 if (!fake) {
263 XSetWindowBorderWidth(ob_display, self->window, self->bwidth);
264 XSetWindowBorderWidth(ob_display, self->title, self->rbwidth);
265 XSetWindowBorderWidth(ob_display, self->handle, self->rbwidth);
266 XSetWindowBorderWidth(ob_display, self->lgrip, self->rbwidth);
267 XSetWindowBorderWidth(ob_display, self->rgrip, self->rbwidth);
268 }
269
270 if (self->decorations & OB_FRAME_DECOR_TITLEBAR)
271 self->innersize.top += ob_rr_theme->title_height + self->rbwidth +
272 (self->rbwidth - self->bwidth);
273 if (self->decorations & OB_FRAME_DECOR_HANDLE &&
274 ob_rr_theme->show_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 ob_rr_theme->show_handle)
317 {
318 XMoveResizeWindow(ob_display, self->handle,
319 -self->bwidth, FRAME_HANDLE_Y(self),
320 self->width, ob_rr_theme->handle_height);
321 XMapWindow(ob_display, self->handle);
322
323 if (self->decorations & OB_FRAME_DECOR_GRIPS) {
324 XMoveWindow(ob_display, self->lgrip,
325 -self->rbwidth, -self->rbwidth);
326 XMoveWindow(ob_display, self->rgrip,
327 -self->rbwidth + self->width -
328 ob_rr_theme->grip_width, -self->rbwidth);
329 XMapWindow(ob_display, self->lgrip);
330 XMapWindow(ob_display, self->rgrip);
331 } else {
332 XUnmapWindow(ob_display, self->lgrip);
333 XUnmapWindow(ob_display, self->rgrip);
334 }
335
336 /* XXX make a subwindow with these dimentions?
337 ob_rr_theme->grip_width + self->bwidth, 0,
338 self->width - (ob_rr_theme->grip_width + self->bwidth) * 2,
339 ob_rr_theme->handle_height);
340 */
341 } else
342 XUnmapWindow(ob_display, self->handle);
343
344 /* move and resize the plate */
345 XMoveResizeWindow(ob_display, self->plate,
346 self->innersize.left - self->cbwidth_x,
347 self->innersize.top - self->cbwidth_y,
348 self->client->area.width + self->cbwidth_x * 2,
349 self->client->area.height + self->cbwidth_y * 2);
350 /* when the client has StaticGravity, it likes to move around. */
351 XMoveWindow(ob_display, self->client->window,
352 self->cbwidth_x, self->cbwidth_y);
353 }
354
355 STRUT_SET(self->size,
356 self->innersize.left + self->bwidth,
357 self->innersize.top + self->bwidth,
358 self->innersize.right + self->bwidth,
359 self->innersize.bottom + self->bwidth);
360 }
361
362 /* shading can change without being moved or resized */
363 RECT_SET_SIZE(self->area,
364 self->client->area.width +
365 self->size.left + self->size.right,
366 (self->client->shaded ?
367 ob_rr_theme->title_height + self->rbwidth * 2:
368 self->client->area.height +
369 self->size.top + self->size.bottom));
370
371 if (moved) {
372 /* find the new coordinates, done after setting the frame.size, for
373 frame_client_gravity. */
374 self->area.x = self->client->area.x;
375 self->area.y = self->client->area.y;
376 frame_client_gravity(self, &self->area.x, &self->area.y);
377 }
378
379 if (!fake) {
380 /* move and resize the top level frame.
381 shading can change without being moved or resized */
382 XMoveResizeWindow(ob_display, self->window,
383 self->area.x, self->area.y,
384 self->area.width - self->bwidth * 2,
385 self->area.height - self->bwidth * 2);
386
387 if (resized) {
388 framerender_frame(self);
389
390 frame_adjust_shape(self);
391 }
392 }
393 }
394
395 void frame_adjust_state(ObFrame *self)
396 {
397 framerender_frame(self);
398 }
399
400 void frame_adjust_focus(ObFrame *self, gboolean hilite)
401 {
402 self->focused = hilite;
403 framerender_frame(self);
404 }
405
406 void frame_adjust_title(ObFrame *self)
407 {
408 framerender_frame(self);
409 }
410
411 void frame_adjust_icon(ObFrame *self)
412 {
413 framerender_frame(self);
414 }
415
416 void frame_grab_client(ObFrame *self, ObClient *client)
417 {
418 self->client = client;
419
420 /* reparent the client to the frame */
421 XReparentWindow(ob_display, client->window, self->plate, 0, 0);
422 /*
423 When reparenting the client window, it is usually not mapped yet, since
424 this occurs from a MapRequest. However, in the case where Openbox is
425 starting up, the window is already mapped, so we'll see unmap events for
426 it. There are 2 unmap events generated that we see, one with the 'event'
427 member set the root window, and one set to the client, but both get
428 handled and need to be ignored.
429 */
430 if (ob_state() == OB_STATE_STARTING)
431 client->ignore_unmaps += 2;
432
433 /* select the event mask on the client's parent (to receive config/map
434 req's) the ButtonPress is to catch clicks on the client border */
435 XSelectInput(ob_display, self->plate, PLATE_EVENTMASK);
436
437 /* map the client so it maps when the frame does */
438 XMapWindow(ob_display, client->window);
439
440 frame_adjust_area(self, TRUE, TRUE, FALSE);
441
442 /* set all the windows for the frame in the window_map */
443 g_hash_table_insert(window_map, &self->window, client);
444 g_hash_table_insert(window_map, &self->plate, client);
445 g_hash_table_insert(window_map, &self->title, client);
446 g_hash_table_insert(window_map, &self->label, client);
447 g_hash_table_insert(window_map, &self->max, client);
448 g_hash_table_insert(window_map, &self->close, client);
449 g_hash_table_insert(window_map, &self->desk, client);
450 g_hash_table_insert(window_map, &self->shade, client);
451 g_hash_table_insert(window_map, &self->icon, client);
452 g_hash_table_insert(window_map, &self->iconify, client);
453 g_hash_table_insert(window_map, &self->handle, client);
454 g_hash_table_insert(window_map, &self->lgrip, client);
455 g_hash_table_insert(window_map, &self->rgrip, client);
456 g_hash_table_insert(window_map, &self->tlresize, client);
457 g_hash_table_insert(window_map, &self->trresize, client);
458 }
459
460 void frame_release_client(ObFrame *self, ObClient *client)
461 {
462 XEvent ev;
463
464 g_assert(self->client == client);
465
466 /* check if the app has already reparented its window away */
467 if (XCheckTypedWindowEvent(ob_display, client->window,
468 ReparentNotify, &ev)) {
469 XPutBackEvent(ob_display, &ev);
470
471 /* re-map the window since the unmanaging process unmaps it */
472
473 /* XXX ... um no it doesnt it unmaps its parent, the window itself
474 retains its mapped state, no?! XXX
475 XMapWindow(ob_display, client->window); */
476 } else {
477 /* according to the ICCCM - if the client doesn't reparent itself,
478 then we will reparent the window to root for them */
479 XReparentWindow(ob_display, client->window,
480 RootWindow(ob_display, ob_screen),
481 client->area.x,
482 client->area.y);
483 }
484
485 /* remove all the windows for the frame from the window_map */
486 g_hash_table_remove(window_map, &self->window);
487 g_hash_table_remove(window_map, &self->plate);
488 g_hash_table_remove(window_map, &self->title);
489 g_hash_table_remove(window_map, &self->label);
490 g_hash_table_remove(window_map, &self->max);
491 g_hash_table_remove(window_map, &self->close);
492 g_hash_table_remove(window_map, &self->desk);
493 g_hash_table_remove(window_map, &self->shade);
494 g_hash_table_remove(window_map, &self->icon);
495 g_hash_table_remove(window_map, &self->iconify);
496 g_hash_table_remove(window_map, &self->handle);
497 g_hash_table_remove(window_map, &self->lgrip);
498 g_hash_table_remove(window_map, &self->rgrip);
499 g_hash_table_remove(window_map, &self->tlresize);
500 g_hash_table_remove(window_map, &self->trresize);
501
502 ob_main_loop_timeout_remove_data(ob_main_loop, flash_timeout, self);
503
504 frame_free(self);
505 }
506
507 static void layout_title(ObFrame *self)
508 {
509 char *lc;
510 int x;
511 gboolean n, d, i, l, m, c, s;
512
513 n = d = i = l = m = c = s = FALSE;
514
515 /* figure out whats being shown, and the width of the label */
516 self->label_width = self->width - (ob_rr_theme->padding + 1) * 2;
517 for (lc = config_title_layout; *lc != '\0'; ++lc) {
518 switch (*lc) {
519 case 'N':
520 if (n) { *lc = ' '; break; } /* rm duplicates */
521 n = TRUE;
522 self->label_width -= (ob_rr_theme->button_size + 2 +
523 ob_rr_theme->padding + 1);
524 break;
525 case 'D':
526 if (d) { *lc = ' '; break; } /* rm duplicates */
527 d = TRUE;
528 self->label_width -= (ob_rr_theme->button_size +
529 ob_rr_theme->padding + 1);
530 break;
531 case 'S':
532 if (s) { *lc = ' '; break; } /* rm duplicates */
533 s = TRUE;
534 self->label_width -= (ob_rr_theme->button_size +
535 ob_rr_theme->padding + 1);
536 break;
537 case 'I':
538 if (i) { *lc = ' '; break; } /* rm duplicates */
539 i = TRUE;
540 self->label_width -= (ob_rr_theme->button_size +
541 ob_rr_theme->padding + 1);
542 break;
543 case 'L':
544 if (l) { *lc = ' '; break; } /* rm duplicates */
545 l = TRUE;
546 break;
547 case 'M':
548 if (m) { *lc = ' '; break; } /* rm duplicates */
549 m = TRUE;
550 self->label_width -= (ob_rr_theme->button_size +
551 ob_rr_theme->padding + 1);
552 break;
553 case 'C':
554 if (c) { *lc = ' '; break; } /* rm duplicates */
555 c = TRUE;
556 self->label_width -= (ob_rr_theme->button_size +
557 ob_rr_theme->padding + 1);
558 break;
559 }
560 }
561 if (self->label_width < 1) self->label_width = 1;
562
563 XResizeWindow(ob_display, self->label, self->label_width,
564 ob_rr_theme->label_height);
565
566 if (!n) XUnmapWindow(ob_display, self->icon);
567 if (!d) XUnmapWindow(ob_display, self->desk);
568 if (!s) XUnmapWindow(ob_display, self->shade);
569 if (!i) XUnmapWindow(ob_display, self->iconify);
570 if (!l) XUnmapWindow(ob_display, self->label);
571 if (!m) XUnmapWindow(ob_display, self->max);
572 if (!c) XUnmapWindow(ob_display, self->close);
573
574 x = ob_rr_theme->padding + 1;
575 for (lc = config_title_layout; *lc != '\0'; ++lc) {
576 switch (*lc) {
577 case 'N':
578 if (!n) break;
579 self->icon_x = x;
580 XMapWindow(ob_display, self->icon);
581 XMoveWindow(ob_display, self->icon, x, ob_rr_theme->padding);
582 x += ob_rr_theme->button_size + 2 + ob_rr_theme->padding + 1;
583 break;
584 case 'D':
585 if (!d) break;
586 self->desk_x = x;
587 XMapWindow(ob_display, self->desk);
588 XMoveWindow(ob_display, self->desk, x, ob_rr_theme->padding + 1);
589 x += ob_rr_theme->button_size + ob_rr_theme->padding + 1;
590 break;
591 case 'S':
592 if (!s) break;
593 self->shade_x = x;
594 XMapWindow(ob_display, self->shade);
595 XMoveWindow(ob_display, self->shade, x, ob_rr_theme->padding + 1);
596 x += ob_rr_theme->button_size + ob_rr_theme->padding + 1;
597 break;
598 case 'I':
599 if (!i) break;
600 self->iconify_x = x;
601 XMapWindow(ob_display, self->iconify);
602 XMoveWindow(ob_display,self->iconify, x, ob_rr_theme->padding + 1);
603 x += ob_rr_theme->button_size + ob_rr_theme->padding + 1;
604 break;
605 case 'L':
606 if (!l) break;
607 self->label_x = x;
608 XMapWindow(ob_display, self->label);
609 XMoveWindow(ob_display, self->label, x, ob_rr_theme->padding);
610 x += self->label_width + ob_rr_theme->padding + 1;
611 break;
612 case 'M':
613 if (!m) break;
614 self->max_x = x;
615 XMapWindow(ob_display, self->max);
616 XMoveWindow(ob_display, self->max, x, ob_rr_theme->padding + 1);
617 x += ob_rr_theme->button_size + ob_rr_theme->padding + 1;
618 break;
619 case 'C':
620 if (!c) break;
621 self->close_x = x;
622 XMapWindow(ob_display, self->close);
623 XMoveWindow(ob_display, self->close, x, ob_rr_theme->padding + 1);
624 x += ob_rr_theme->button_size + ob_rr_theme->padding + 1;
625 break;
626 }
627 }
628 }
629
630 ObFrameContext frame_context_from_string(char *name)
631 {
632 if (!g_ascii_strcasecmp("desktop", name))
633 return OB_FRAME_CONTEXT_DESKTOP;
634 else if (!g_ascii_strcasecmp("client", name))
635 return OB_FRAME_CONTEXT_CLIENT;
636 else if (!g_ascii_strcasecmp("titlebar", name))
637 return OB_FRAME_CONTEXT_TITLEBAR;
638 else if (!g_ascii_strcasecmp("handle", name))
639 return OB_FRAME_CONTEXT_HANDLE;
640 else if (!g_ascii_strcasecmp("frame", name))
641 return OB_FRAME_CONTEXT_FRAME;
642 else if (!g_ascii_strcasecmp("tlcorner", name))
643 return OB_FRAME_CONTEXT_TLCORNER;
644 else if (!g_ascii_strcasecmp("trcorner", name))
645 return OB_FRAME_CONTEXT_TRCORNER;
646 else if (!g_ascii_strcasecmp("blcorner", name))
647 return OB_FRAME_CONTEXT_BLCORNER;
648 else if (!g_ascii_strcasecmp("brcorner", name))
649 return OB_FRAME_CONTEXT_BRCORNER;
650 else if (!g_ascii_strcasecmp("maximize", name))
651 return OB_FRAME_CONTEXT_MAXIMIZE;
652 else if (!g_ascii_strcasecmp("alldesktops", name))
653 return OB_FRAME_CONTEXT_ALLDESKTOPS;
654 else if (!g_ascii_strcasecmp("shade", name))
655 return OB_FRAME_CONTEXT_SHADE;
656 else if (!g_ascii_strcasecmp("iconify", name))
657 return OB_FRAME_CONTEXT_ICONIFY;
658 else if (!g_ascii_strcasecmp("icon", name))
659 return OB_FRAME_CONTEXT_ICON;
660 else if (!g_ascii_strcasecmp("close", name))
661 return OB_FRAME_CONTEXT_CLOSE;
662 return OB_FRAME_CONTEXT_NONE;
663 }
664
665 ObFrameContext frame_context(ObClient *client, Window win)
666 {
667 ObFrame *self;
668
669 if (win == RootWindow(ob_display, ob_screen))
670 return OB_FRAME_CONTEXT_DESKTOP;
671 if (client == NULL) return OB_FRAME_CONTEXT_NONE;
672 if (win == client->window) {
673 /* conceptually, this is the desktop, as far as users are
674 concerned */
675 if (client->type == OB_CLIENT_TYPE_DESKTOP)
676 return OB_FRAME_CONTEXT_DESKTOP;
677 return OB_FRAME_CONTEXT_CLIENT;
678 }
679
680 self = client->frame;
681 if (win == self->plate) {
682 /* conceptually, this is the desktop, as far as users are
683 concerned */
684 if (client->type == OB_CLIENT_TYPE_DESKTOP)
685 return OB_FRAME_CONTEXT_DESKTOP;
686 return OB_FRAME_CONTEXT_CLIENT;
687 }
688
689 if (win == self->window) return OB_FRAME_CONTEXT_FRAME;
690 if (win == self->title) return OB_FRAME_CONTEXT_TITLEBAR;
691 if (win == self->label) return OB_FRAME_CONTEXT_TITLEBAR;
692 if (win == self->handle) return OB_FRAME_CONTEXT_HANDLE;
693 if (win == self->lgrip) return OB_FRAME_CONTEXT_BLCORNER;
694 if (win == self->rgrip) return OB_FRAME_CONTEXT_BRCORNER;
695 if (win == self->tlresize) return OB_FRAME_CONTEXT_TLCORNER;
696 if (win == self->trresize) return OB_FRAME_CONTEXT_TRCORNER;
697 if (win == self->max) return OB_FRAME_CONTEXT_MAXIMIZE;
698 if (win == self->iconify) return OB_FRAME_CONTEXT_ICONIFY;
699 if (win == self->close) return OB_FRAME_CONTEXT_CLOSE;
700 if (win == self->icon) return OB_FRAME_CONTEXT_ICON;
701 if (win == self->desk) return OB_FRAME_CONTEXT_ALLDESKTOPS;
702 if (win == self->shade) return OB_FRAME_CONTEXT_SHADE;
703
704 return OB_FRAME_CONTEXT_NONE;
705 }
706
707 void frame_client_gravity(ObFrame *self, int *x, int *y)
708 {
709 /* horizontal */
710 switch (self->client->gravity) {
711 default:
712 case NorthWestGravity:
713 case SouthWestGravity:
714 case WestGravity:
715 break;
716
717 case NorthGravity:
718 case SouthGravity:
719 case CenterGravity:
720 *x -= (self->size.left + self->size.right) / 2;
721 break;
722
723 case NorthEastGravity:
724 case SouthEastGravity:
725 case EastGravity:
726 *x -= self->size.left + self->size.right;
727 break;
728
729 case ForgetGravity:
730 case StaticGravity:
731 *x -= self->size.left;
732 break;
733 }
734
735 /* vertical */
736 switch (self->client->gravity) {
737 default:
738 case NorthWestGravity:
739 case NorthEastGravity:
740 case NorthGravity:
741 break;
742
743 case CenterGravity:
744 case EastGravity:
745 case WestGravity:
746 *y -= (self->size.top + self->size.bottom) / 2;
747 break;
748
749 case SouthWestGravity:
750 case SouthEastGravity:
751 case SouthGravity:
752 *y -= self->size.top + self->size.bottom;
753 break;
754
755 case ForgetGravity:
756 case StaticGravity:
757 *y -= self->size.top;
758 break;
759 }
760 }
761
762 void frame_frame_gravity(ObFrame *self, int *x, int *y)
763 {
764 /* horizontal */
765 switch (self->client->gravity) {
766 default:
767 case NorthWestGravity:
768 case WestGravity:
769 case SouthWestGravity:
770 break;
771 case NorthGravity:
772 case CenterGravity:
773 case SouthGravity:
774 *x += (self->size.left + self->size.right) / 2;
775 break;
776 case NorthEastGravity:
777 case EastGravity:
778 case SouthEastGravity:
779 *x += self->size.left + self->size.right;
780 break;
781 case StaticGravity:
782 case ForgetGravity:
783 *x += self->size.left;
784 break;
785 }
786
787 /* vertical */
788 switch (self->client->gravity) {
789 default:
790 case NorthWestGravity:
791 case NorthGravity:
792 case NorthEastGravity:
793 break;
794 case WestGravity:
795 case CenterGravity:
796 case EastGravity:
797 *y += (self->size.top + self->size.bottom) / 2;
798 break;
799 case SouthWestGravity:
800 case SouthGravity:
801 case SouthEastGravity:
802 *y += self->size.top + self->size.bottom;
803 break;
804 case StaticGravity:
805 case ForgetGravity:
806 *y += self->size.top;
807 break;
808 }
809 }
810
811 static void flash_done(gpointer data)
812 {
813 ObFrame *self = data;
814
815 if (self->focused != self->flash_on)
816 frame_adjust_focus(self, self->focused);
817 }
818
819 static gboolean flash_timeout(gpointer data)
820 {
821 ObFrame *self = data;
822 GTimeVal now;
823
824 g_get_current_time(&now);
825 if (now.tv_sec > self->flash_end.tv_sec ||
826 (now.tv_sec == self->flash_end.tv_sec &&
827 now.tv_usec >= self->flash_end.tv_usec))
828 self->flashing = FALSE;
829
830 if (!self->flashing)
831 return FALSE; /* we are done */
832
833 self->flash_on = !self->flash_on;
834 {
835 gboolean focused;
836
837 focused = self->focused; /* save the focused flag */
838 frame_adjust_focus(self, self->flash_on);
839 self->focused = focused;
840 }
841
842 return TRUE; /* go again */
843 }
844
845 void frame_flash_start(ObFrame *self)
846 {
847 self->flash_on = self->focused;
848
849 if (!self->flashing)
850 ob_main_loop_timeout_add(ob_main_loop,
851 G_USEC_PER_SEC * 0.75,
852 flash_timeout,
853 self,
854 flash_done);
855 g_get_current_time(&self->flash_end);
856 g_time_val_add(&self->flash_end, G_USEC_PER_SEC * 5);
857
858 self->flashing = TRUE;
859 }
860
861 void frame_flash_stop(ObFrame *self)
862 {
863 self->flashing = FALSE;
864 }
This page took 0.075048 seconds and 4 git commands to generate.