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