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