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