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