]> Dogcows Code - chaz/openbox/blob - engines/openbox/openbox.c
proper height for shaded windows
[chaz/openbox] / engines / openbox / openbox.c
1 #include "theme.h"
2 #include "../../kernel/openbox.h"
3 #include "../../kernel/screen.h"
4 #include "../../kernel/extensions.h"
5 #include "../../kernel/dispatch.h"
6 #include "../../kernel/config.h"
7 #include "../../kernel/frame.h"
8 #include "../../render/render.h"
9 #include "../../render/color.h"
10 #include "../../render/font.h"
11 #include "../../render/mask.h"
12
13 #include <X11/Xlib.h>
14 #include <glib.h>
15
16 #define LABEL_HEIGHT (s_winfont_height + 2)
17 #define TITLE_HEIGHT (LABEL_HEIGHT + s_bevel * 2)
18 #define HANDLE_Y(f) (f->innersize.top + f->frame.client->area.height + \
19 f->cbwidth)
20 #define BUTTON_SIZE (LABEL_HEIGHT - 2)
21 #define GRIP_WIDTH (BUTTON_SIZE * 2)
22 #define HANDLE_WIDTH(f) (f->width - (GRIP_WIDTH + f->bwidth) * 2)
23
24 #define PLATE_EVENTMASK (SubstructureRedirectMask | ButtonPressMask)
25 #define FRAME_EVENTMASK (EnterWindowMask | LeaveWindowMask)
26 #define ELEMENT_EVENTMASK (ButtonPressMask | ButtonReleaseMask | \
27 ButtonMotionMask | ExposureMask)
28
29 /* style settings - geometry */
30 int s_bevel;
31 int s_handle_height;
32 int s_bwidth;
33 int s_cbwidth;
34 /* style settings - colors */
35 color_rgb *s_b_color;
36 color_rgb *s_cb_focused_color;
37 color_rgb *s_cb_unfocused_color;
38 color_rgb *s_title_focused_color;
39 color_rgb *s_title_unfocused_color;
40 color_rgb *s_titlebut_focused_color;
41 color_rgb *s_titlebut_unfocused_color;
42 /* style settings - fonts */
43 int s_winfont_height;
44 int s_winfont_shadow;
45 int s_winfont_shadow_offset;
46 ObFont *s_winfont;
47 /* style settings - masks */
48 pixmap_mask *s_max_mask;
49 pixmap_mask *s_icon_mask;
50 pixmap_mask *s_desk_mask;
51 pixmap_mask *s_close_mask;
52
53 /* global appearances */
54 Appearance *a_focused_unpressed_max;
55 Appearance *a_focused_pressed_max;
56 Appearance *a_unfocused_unpressed_max;
57 Appearance *a_unfocused_pressed_max;
58 Appearance *a_focused_unpressed_close;
59 Appearance *a_focused_pressed_close;
60 Appearance *a_unfocused_unpressed_close;
61 Appearance *a_unfocused_pressed_close;
62 Appearance *a_focused_unpressed_desk;
63 Appearance *a_focused_pressed_desk;
64 Appearance *a_unfocused_unpressed_desk;
65 Appearance *a_unfocused_pressed_desk;
66 Appearance *a_focused_unpressed_iconify;
67 Appearance *a_focused_pressed_iconify;
68 Appearance *a_unfocused_unpressed_iconify;
69 Appearance *a_unfocused_pressed_iconify;
70 Appearance *a_focused_grip;
71 Appearance *a_unfocused_grip;
72 Appearance *a_focused_title;
73 Appearance *a_unfocused_title;
74 Appearance *a_focused_label;
75 Appearance *a_unfocused_label;
76 Appearance *a_icon; /* always parentrelative, so no focused/unfocused */
77 Appearance *a_focused_handle;
78 Appearance *a_unfocused_handle;
79
80 typedef struct ObFrame {
81 Frame frame;
82
83 Window title;
84 Window label;
85 Window max;
86 Window close;
87 Window desk;
88 Window icon;
89 Window iconify;
90 Window handle;
91 Window lgrip;
92 Window rgrip;
93
94 Appearance *a_unfocused_title;
95 Appearance *a_focused_title;
96 Appearance *a_unfocused_label;
97 Appearance *a_focused_label;
98 Appearance *a_icon;
99 Appearance *a_unfocused_handle;
100 Appearance *a_focused_handle;
101
102 Strut innersize;
103
104 GSList *clients;
105
106 int width; /* title and handle */
107 int label_width;
108 int icon_x; /* x-position of the window icon button */
109 int label_x; /* x-position of the window title */
110 int iconify_x; /* x-position of the window iconify button */
111 int desk_x; /* x-position of the window all-desktops button */
112 int max_x; /* x-position of the window maximize button */
113 int close_x; /* x-position of the window close button */
114 int bwidth; /* border width */
115 int cbwidth; /* client border width */
116
117 gboolean max_press;
118 gboolean close_press;
119 gboolean desk_press;
120 gboolean iconify_press;
121 } ObFrame;
122
123 static void layout_title(ObFrame *self);
124 static void render(ObFrame *self);
125 static void render_label(ObFrame *self);
126 static void render_max(ObFrame *self);
127 static void render_icon(ObFrame *self);
128 static void render_iconify(ObFrame *self);
129 static void render_desk(ObFrame *self);
130 static void render_close(ObFrame *self);
131
132 static void frame_mouse_press(const ObEvent *e, ObFrame *self);
133 static void frame_mouse_release(const ObEvent *e, ObFrame *self);
134
135 gboolean startup()
136 {
137 g_quark_from_string("none");
138 g_quark_from_string("root");
139 g_quark_from_string("client");
140 g_quark_from_string("titlebar");
141 g_quark_from_string("handle");
142 g_quark_from_string("frame");
143 g_quark_from_string("blcorner");
144 g_quark_from_string("brcorner");
145 g_quark_from_string("maximize");
146 g_quark_from_string("alldesktops");
147 g_quark_from_string("iconify");
148 g_quark_from_string("icon");
149 g_quark_from_string("close");
150
151 s_b_color = s_cb_unfocused_color = s_cb_focused_color =
152 s_title_unfocused_color = s_title_focused_color =
153 s_titlebut_unfocused_color = s_titlebut_focused_color = NULL;
154 s_winfont = NULL;
155 s_max_mask = s_icon_mask = s_desk_mask = s_close_mask = NULL;
156
157 a_focused_unpressed_max = appearance_new(Surface_Planar, 1);
158 a_focused_pressed_max = appearance_new(Surface_Planar, 1);
159 a_unfocused_unpressed_max = appearance_new(Surface_Planar, 1);
160 a_unfocused_pressed_max = appearance_new(Surface_Planar, 1);
161 a_focused_unpressed_close = NULL;
162 a_focused_pressed_close = NULL;
163 a_unfocused_unpressed_close = NULL;
164 a_unfocused_pressed_close = NULL;
165 a_focused_unpressed_desk = NULL;
166 a_focused_pressed_desk = NULL;
167 a_unfocused_unpressed_desk = NULL;
168 a_unfocused_pressed_desk = NULL;
169 a_focused_unpressed_iconify = NULL;
170 a_focused_pressed_iconify = NULL;
171 a_unfocused_unpressed_iconify = NULL;
172 a_unfocused_pressed_iconify = NULL;
173 a_focused_grip = appearance_new(Surface_Planar, 0);
174 a_unfocused_grip = appearance_new(Surface_Planar, 0);
175 a_focused_title = appearance_new(Surface_Planar, 0);
176 a_unfocused_title = appearance_new(Surface_Planar, 0);
177 a_focused_label = appearance_new(Surface_Planar, 1);
178 a_unfocused_label = appearance_new(Surface_Planar, 1);
179 a_icon = appearance_new(Surface_Planar, 0);/*1);*/
180 a_focused_handle = appearance_new(Surface_Planar, 0);
181 a_unfocused_handle = appearance_new(Surface_Planar, 0);
182
183 return load();
184 }
185
186 void shutdown()
187 {
188 if (s_b_color != NULL) color_free(s_b_color);
189 if (s_cb_unfocused_color != NULL) color_free(s_cb_unfocused_color);
190 if (s_cb_focused_color != NULL) color_free(s_cb_focused_color);
191 if (s_title_unfocused_color != NULL) color_free(s_title_unfocused_color);
192 if (s_title_focused_color != NULL) color_free(s_title_focused_color);
193 if (s_titlebut_unfocused_color != NULL)
194 color_free(s_titlebut_unfocused_color);
195 if (s_titlebut_focused_color != NULL)
196 color_free(s_titlebut_focused_color);
197
198 if (s_max_mask != NULL) pixmap_mask_free(s_max_mask);
199 if (s_desk_mask != NULL) pixmap_mask_free(s_desk_mask);
200 if (s_icon_mask != NULL) pixmap_mask_free(s_icon_mask);
201 if (s_close_mask != NULL) pixmap_mask_free(s_close_mask);
202
203 if (s_winfont != NULL) font_close(s_winfont);
204
205 appearance_free(a_focused_unpressed_max);
206 appearance_free(a_focused_pressed_max);
207 appearance_free(a_unfocused_unpressed_max);
208 appearance_free(a_unfocused_pressed_max);
209 if (a_focused_unpressed_close != NULL)
210 appearance_free(a_focused_unpressed_close);
211 if (a_focused_pressed_close != NULL)
212 appearance_free(a_focused_pressed_close);
213 if (a_unfocused_unpressed_close != NULL)
214 appearance_free(a_unfocused_unpressed_close);
215 if (a_unfocused_pressed_close != NULL)
216 appearance_free(a_unfocused_pressed_close);
217 if (a_focused_unpressed_desk != NULL)
218 appearance_free(a_focused_unpressed_desk);
219 if (a_focused_pressed_desk != NULL)
220 appearance_free(a_focused_pressed_desk);
221 if (a_unfocused_unpressed_desk != NULL)
222 appearance_free(a_unfocused_unpressed_desk);
223 if (a_unfocused_pressed_desk != NULL)
224 appearance_free(a_unfocused_pressed_desk);
225 if (a_focused_unpressed_iconify != NULL)
226 appearance_free(a_focused_unpressed_iconify);
227 if (a_focused_pressed_iconify != NULL)
228 appearance_free(a_focused_pressed_iconify);
229 if (a_unfocused_unpressed_iconify != NULL)
230 appearance_free(a_unfocused_unpressed_iconify);
231 if (a_unfocused_pressed_iconify != NULL)
232 appearance_free(a_unfocused_pressed_iconify);
233 appearance_free(a_focused_grip);
234 appearance_free(a_unfocused_grip);
235 appearance_free(a_focused_title);
236 appearance_free(a_unfocused_title);
237 appearance_free(a_focused_label);
238 appearance_free(a_unfocused_label);
239 appearance_free(a_icon);
240 appearance_free(a_focused_handle);
241 appearance_free(a_unfocused_handle);
242 }
243
244 static Window createWindow(Window parent, unsigned long mask,
245 XSetWindowAttributes *attrib)
246 {
247 return XCreateWindow(ob_display, parent, 0, 0, 1, 1, 0,
248 render_depth, InputOutput, render_visual,
249 mask, attrib);
250
251 }
252
253 Frame *frame_new()
254 {
255 XSetWindowAttributes attrib;
256 unsigned long mask;
257 ObFrame *self;
258
259 self = g_new(ObFrame, 1);
260
261 self->frame.visible = FALSE;
262
263 /* create all of the decor windows */
264 mask = CWOverrideRedirect | CWEventMask;
265 attrib.event_mask = FRAME_EVENTMASK;
266 attrib.override_redirect = TRUE;
267 self->frame.window = createWindow(ob_root, mask, &attrib);
268
269 mask = 0;
270 self->frame.plate = createWindow(self->frame.window, mask, &attrib);
271
272 mask = CWEventMask;
273 attrib.event_mask = ELEMENT_EVENTMASK;
274 self->title = createWindow(self->frame.window, mask, &attrib);
275 self->label = createWindow(self->title, mask, &attrib);
276 self->max = createWindow(self->title, mask, &attrib);
277 self->close = createWindow(self->title, mask, &attrib);
278 self->desk = createWindow(self->title, mask, &attrib);
279 self->icon = createWindow(self->title, mask, &attrib);
280 self->iconify = createWindow(self->title, mask, &attrib);
281 self->handle = createWindow(self->frame.window, mask, &attrib);
282 mask |= CWCursor;
283 attrib.cursor = ob_cursors.ll_angle;
284 self->lgrip = createWindow(self->handle, mask, &attrib);
285 attrib.cursor = ob_cursors.lr_angle;
286 self->rgrip = createWindow(self->handle, mask, &attrib);
287
288 /* the other stuff is shown based on decor settings */
289 XMapWindow(ob_display, self->frame.plate);
290 XMapWindow(ob_display, self->lgrip);
291 XMapWindow(ob_display, self->rgrip);
292 XMapWindow(ob_display, self->label);
293
294 /* set colors/appearance/sizes for stuff that doesn't change */
295 XSetWindowBorder(ob_display, self->frame.window, s_b_color->pixel);
296 XSetWindowBorder(ob_display, self->label, s_b_color->pixel);
297 XSetWindowBorder(ob_display, self->rgrip, s_b_color->pixel);
298 XSetWindowBorder(ob_display, self->lgrip, s_b_color->pixel);
299
300 XResizeWindow(ob_display, self->max, BUTTON_SIZE, BUTTON_SIZE);
301 XResizeWindow(ob_display, self->iconify, BUTTON_SIZE, BUTTON_SIZE);
302 XResizeWindow(ob_display, self->icon, BUTTON_SIZE, BUTTON_SIZE);
303 XResizeWindow(ob_display, self->close, BUTTON_SIZE, BUTTON_SIZE);
304 XResizeWindow(ob_display, self->desk, BUTTON_SIZE, BUTTON_SIZE);
305 XResizeWindow(ob_display, self->lgrip, GRIP_WIDTH, s_handle_height);
306 XResizeWindow(ob_display, self->rgrip, GRIP_WIDTH, s_handle_height);
307
308 /* set up the dynamic appearances */
309 self->a_unfocused_title = appearance_copy(a_unfocused_title);
310 self->a_focused_title = appearance_copy(a_focused_title);
311 self->a_unfocused_label = appearance_copy(a_unfocused_label);
312 self->a_focused_label = appearance_copy(a_focused_label);
313 self->a_unfocused_handle = appearance_copy(a_unfocused_handle);
314 self->a_focused_handle = appearance_copy(a_focused_handle);
315 self->a_icon = appearance_copy(a_icon);
316
317 self->max_press = self->close_press = self->desk_press =
318 self->iconify_press = FALSE;
319
320 dispatch_register(Event_X_ButtonPress, (EventHandler)frame_mouse_press,
321 self);
322 dispatch_register(Event_X_ButtonRelease, (EventHandler)frame_mouse_release,
323 self);
324
325 return (Frame*)self;
326 }
327
328 static void frame_free(ObFrame *self)
329 {
330 appearance_free(self->a_unfocused_title);
331 appearance_free(self->a_focused_title);
332 appearance_free(self->a_unfocused_label);
333 appearance_free(self->a_focused_label);
334 appearance_free(self->a_unfocused_handle);
335 appearance_free(self->a_focused_handle);
336 appearance_free(self->a_icon);
337
338 XDestroyWindow(ob_display, self->frame.window);
339
340 dispatch_register(0, (EventHandler)frame_mouse_press, self);
341 dispatch_register(0, (EventHandler)frame_mouse_release, self);
342
343 g_free(self);
344 }
345
346 void frame_show(ObFrame *self)
347 {
348 if (!self->frame.visible) {
349 self->frame.visible = TRUE;
350 XMapWindow(ob_display, self->frame.window);
351 }
352 }
353
354 void frame_hide(ObFrame *self)
355 {
356 if (self->frame.visible) {
357 self->frame.visible = FALSE;
358 self->frame.client->ignore_unmaps++;
359 XUnmapWindow(ob_display, self->frame.window);
360 }
361 }
362
363 void frame_adjust_shape(ObFrame *self)
364 {
365 #ifdef SHAPE
366 int num;
367 XRectangle xrect[2];
368
369 if (!self->frame.client->shaped) {
370 /* clear the shape on the frame window */
371 XShapeCombineMask(ob_display, self->frame.window, ShapeBounding,
372 self->innersize.left,
373 self->innersize.top,
374 None, ShapeSet);
375 } else {
376 /* make the frame's shape match the clients */
377 XShapeCombineShape(ob_display, self->frame.window, ShapeBounding,
378 self->innersize.left,
379 self->innersize.top,
380 self->frame.client->window,
381 ShapeBounding, ShapeSet);
382
383 num = 0;
384 if (self->frame.client->decorations & Decor_Titlebar) {
385 xrect[0].x = -s_bevel;
386 xrect[0].y = -s_bevel;
387 xrect[0].width = self->width + self->bwidth * 2;
388 xrect[0].height = TITLE_HEIGHT +
389 self->bwidth * 2;
390 ++num;
391 }
392
393 if (self->frame.client->decorations & Decor_Handle) {
394 xrect[1].x = -s_bevel;
395 xrect[1].y = HANDLE_Y(self);
396 xrect[1].width = self->width + self->bwidth * 2;
397 xrect[1].height = s_handle_height +
398 self->bwidth * 2;
399 ++num;
400 }
401
402 XShapeCombineRectangles(ob_display, self->frame.window,
403 ShapeBounding, 0, 0, xrect, num,
404 ShapeUnion, Unsorted);
405 }
406 #endif
407 }
408
409 void frame_adjust_area(ObFrame *self, gboolean moved, gboolean resized)
410 {
411 g_message("adjust_area: %d %d", moved, resized);
412 if (resized) {
413 if (self->frame.client->decorations & Decor_Border) {
414 self->bwidth = s_bwidth;
415 self->cbwidth = s_cbwidth;
416 } else {
417 self->bwidth = self->cbwidth = 0;
418 }
419 STRUT_SET(self->innersize, self->cbwidth, self->cbwidth,
420 self->cbwidth, self->cbwidth);
421 self->width = self->frame.client->area.width + self->cbwidth * 2;
422 g_assert(self->width > 0);
423
424 /* set border widths */
425 XSetWindowBorderWidth(ob_display, self->frame.plate, self->cbwidth);
426 XSetWindowBorderWidth(ob_display, self->frame.window, self->bwidth);
427 XSetWindowBorderWidth(ob_display, self->title, self->bwidth);
428 XSetWindowBorderWidth(ob_display, self->handle, self->bwidth);
429 XSetWindowBorderWidth(ob_display, self->lgrip, self->bwidth);
430 XSetWindowBorderWidth(ob_display, self->rgrip, self->bwidth);
431
432 /* position/size and map/unmap all the windows */
433
434 /* they all default off, they're turned on in layout_title */
435 self->icon_x = -1;
436 self->desk_x = -1;
437 self->icon_x = -1;
438 self->label_x = -1;
439 self->max_x = -1;
440 self->close_x = -1;
441
442 if (self->frame.client->decorations & Decor_Titlebar) {
443 XMoveResizeWindow(ob_display, self->title,
444 -self->bwidth, -self->bwidth,
445 self->width, TITLE_HEIGHT);
446 self->innersize.top += TITLE_HEIGHT + self->bwidth;
447 XMapWindow(ob_display, self->title);
448
449 /* layout the title bar elements */
450 layout_title(self);
451 } else {
452 XUnmapWindow(ob_display, self->title);
453 /* make all the titlebar stuff not render */
454 self->frame.client->decorations &= ~(Decor_Icon | Decor_Iconify |
455 Decor_Maximize | Decor_Close |
456 Decor_AllDesktops);
457 }
458
459 if (self->frame.client->decorations & Decor_Handle) {
460 XMoveResizeWindow(ob_display, self->handle,
461 -self->bwidth, HANDLE_Y(self),
462 self->width, s_handle_height);
463 XMoveWindow(ob_display, self->lgrip,
464 -self->bwidth, -self->bwidth);
465 XMoveWindow(ob_display, self->rgrip,
466 -self->bwidth + self->width -
467 GRIP_WIDTH, -self->bwidth);
468 self->innersize.bottom += s_handle_height +
469 self->bwidth;
470 XMapWindow(ob_display, self->handle);
471 } else
472 XUnmapWindow(ob_display, self->handle);
473 }
474
475 if (moved) {
476 /* find the new coordinates */
477 self->frame.area.x = self->frame.client->area.x;
478 self->frame.area.y = self->frame.client->area.y;
479 frame_client_gravity((Frame*)self,
480 &self->frame.area.x, &self->frame.area.y);
481 }
482
483 /* move and resize the top level frame.
484 shading can change without being moved or resized */
485 XMoveResizeWindow(ob_display, self->frame.window,
486 self->frame.area.x, self->frame.area.y,
487 self->width,
488 (self->frame.client->shaded ? TITLE_HEIGHT :
489 self->innersize.top + self->innersize.bottom +
490 self->frame.client->area.height));
491
492 if (resized) {
493 /* move and resize the plate */
494 XMoveResizeWindow(ob_display, self->frame.plate,
495 self->innersize.left - self->cbwidth,
496 self->innersize.top - self->cbwidth,
497 self->frame.client->area.width,
498 self->frame.client->area.height);
499 /* when the client has StaticGravity, it likes to move around. */
500 XMoveWindow(ob_display, self->frame.client->window, 0, 0);
501 }
502
503 if (resized) {
504 STRUT_SET(self->frame.size,
505 self->innersize.left + self->bwidth,
506 self->innersize.top + self->bwidth,
507 self->innersize.right + self->bwidth,
508 self->innersize.bottom + self->bwidth);
509 }
510
511 /* shading can change without being moved or resized */
512 RECT_SET_SIZE(self->frame.area,
513 self->frame.client->area.width +
514 self->frame.size.left + self->frame.size.right,
515 (self->frame.client->shaded ? TITLE_HEIGHT + self->bwidth*2:
516 self->frame.client->area.height +
517 self->frame.size.top + self->frame.size.bottom));
518
519 if (resized) {
520 render(self);
521
522 frame_adjust_shape(self);
523 }
524 }
525
526 void frame_adjust_state(ObFrame *self)
527 {
528 render_max(self);
529 render_desk(self);
530 }
531
532 void frame_adjust_focus(ObFrame *self)
533 {
534 render(self);
535 }
536
537 void frame_adjust_title(ObFrame *self)
538 {
539 render_label(self);
540 }
541
542 void frame_adjust_icon(ObFrame *self)
543 {
544 render_icon(self);
545 }
546
547 void frame_grab_client(ObFrame *self, Client *client)
548 {
549 self->frame.client = client;
550
551 /* reparent the client to the frame */
552 XReparentWindow(ob_display, client->window, self->frame.plate, 0, 0);
553 /*
554 When reparenting the client window, it is usually not mapped yet, since
555 this occurs from a MapRequest. However, in the case where Openbox is
556 starting up, the window is already mapped, so we'll see unmap events for
557 it. There are 2 unmap events generated that we see, one with the 'event'
558 member set the root window, and one set to the client, but both get
559 handled and need to be ignored.
560 */
561 if (ob_state == State_Starting)
562 client->ignore_unmaps += 2;
563
564 /* select the event mask on the client's parent (to receive config/map
565 req's) the ButtonPress is to catch clicks on the client border */
566 XSelectInput(ob_display, self->frame.plate, PLATE_EVENTMASK);
567
568 /* map the client so it maps when the frame does */
569 XMapWindow(ob_display, client->window);
570
571 frame_adjust_area(self, TRUE, TRUE);
572
573 /* set all the windows for the frame in the client_map */
574 g_hash_table_insert(client_map, (gpointer)self->frame.window, client);
575 g_hash_table_insert(client_map, (gpointer)self->frame.plate, client);
576 g_hash_table_insert(client_map, (gpointer)self->title, client);
577 g_hash_table_insert(client_map, (gpointer)self->label, client);
578 g_hash_table_insert(client_map, (gpointer)self->max, client);
579 g_hash_table_insert(client_map, (gpointer)self->close, client);
580 g_hash_table_insert(client_map, (gpointer)self->desk, client);
581 g_hash_table_insert(client_map, (gpointer)self->icon, client);
582 g_hash_table_insert(client_map, (gpointer)self->iconify, client);
583 g_hash_table_insert(client_map, (gpointer)self->handle, client);
584 g_hash_table_insert(client_map, (gpointer)self->lgrip, client);
585 g_hash_table_insert(client_map, (gpointer)self->rgrip, client);
586 }
587
588 void frame_release_client(ObFrame *self, Client *client)
589 {
590 XEvent ev;
591
592 g_assert(self->frame.client == client);
593
594 /* check if the app has already reparented its window away */
595 if (XCheckTypedWindowEvent(ob_display, client->window,
596 ReparentNotify, &ev)) {
597 XPutBackEvent(ob_display, &ev);
598 /* re-map the window since the unmanaging process unmaps it */
599 XMapWindow(ob_display, client->window);
600 } else {
601 /* according to the ICCCM - if the client doesn't reparent itself,
602 then we will reparent the window to root for them */
603 XReparentWindow(ob_display, client->window, ob_root,
604 client->area.x,
605 client->area.y);
606 }
607
608 /* remove all the windows for the frame from the client_map */
609 g_hash_table_remove(client_map, (gpointer)self->frame.window);
610 g_hash_table_remove(client_map, (gpointer)self->frame.plate);
611 g_hash_table_remove(client_map, (gpointer)self->title);
612 g_hash_table_remove(client_map, (gpointer)self->label);
613 g_hash_table_remove(client_map, (gpointer)self->max);
614 g_hash_table_remove(client_map, (gpointer)self->close);
615 g_hash_table_remove(client_map, (gpointer)self->desk);
616 g_hash_table_remove(client_map, (gpointer)self->icon);
617 g_hash_table_remove(client_map, (gpointer)self->iconify);
618 g_hash_table_remove(client_map, (gpointer)self->handle);
619 g_hash_table_remove(client_map, (gpointer)self->lgrip);
620 g_hash_table_remove(client_map, (gpointer)self->rgrip);
621
622 frame_free(self);
623 }
624
625 static void layout_title(ObFrame *self)
626 {
627 const char *lc;
628 int x;
629 gboolean n, d, i, l, m ,c;
630 ConfigValue layout;
631
632 n = d = i = l = m = c = FALSE;
633
634 if (!config_get("titlebar.layout", Config_String, &layout)) {
635 layout.string = "NDLIMC";
636 config_set("titlebar.layout", Config_String, layout);
637 }
638
639 /* figure out whats being shown, and the width of the label */
640 self->label_width = self->width - (s_bevel + 1) * 2;
641 for (lc = layout.string; *lc != '\0'; ++lc) {
642 switch (*lc) {
643 case 'N':
644 if (!(self->frame.client->decorations & Decor_Icon)) break;
645 n = TRUE;
646 self->label_width -= BUTTON_SIZE + s_bevel + 1;
647 break;
648 case 'D':
649 if (!(self->frame.client->decorations & Decor_AllDesktops)) break;
650 d = TRUE;
651 self->label_width -= BUTTON_SIZE + s_bevel + 1;
652 break;
653 case 'I':
654 if (!(self->frame.client->decorations & Decor_Iconify)) break;
655 i = TRUE;
656 self->label_width -= BUTTON_SIZE + s_bevel + 1;
657 break;
658 case 'L':
659 l = TRUE;
660 break;
661 case 'M':
662 if (!(self->frame.client->decorations & Decor_Maximize)) break;
663 m = TRUE;
664 self->label_width -= BUTTON_SIZE + s_bevel + 1;
665 break;
666 case 'C':
667 if (!(self->frame.client->decorations & Decor_Close)) break;
668 c = TRUE;
669 self->label_width -= BUTTON_SIZE + s_bevel + 1;
670 break;
671 }
672 }
673 if (self->label_width < 1) self->label_width = 1;
674
675 XResizeWindow(ob_display, self->label, self->label_width,
676 LABEL_HEIGHT);
677
678 if (!n) XUnmapWindow(ob_display, self->icon);
679 if (!d) XUnmapWindow(ob_display, self->desk);
680 if (!i) XUnmapWindow(ob_display, self->iconify);
681 if (!l) XUnmapWindow(ob_display, self->label);
682 if (!m) XUnmapWindow(ob_display, self->max);
683 if (!c) XUnmapWindow(ob_display, self->close);
684
685 x = s_bevel + 1;
686 for (lc = layout.string; *lc != '\0'; ++lc) {
687 switch (*lc) {
688 case 'N':
689 if (!n) break;
690 self->icon_x = x;
691 XMapWindow(ob_display, self->icon);
692 XMoveWindow(ob_display, self->icon, x, s_bevel + 1);
693 x += BUTTON_SIZE + s_bevel + 1;
694 break;
695 case 'D':
696 if (!d) break;
697 self->desk_x = x;
698 XMapWindow(ob_display, self->desk);
699 XMoveWindow(ob_display, self->desk, x, s_bevel + 1);
700 x += BUTTON_SIZE + s_bevel + 1;
701 break;
702 case 'I':
703 if (!i) break;
704 self->iconify_x = x;
705 XMapWindow(ob_display, self->iconify);
706 XMoveWindow(ob_display, self->iconify, x, s_bevel + 1);
707 x += BUTTON_SIZE + s_bevel + 1;
708 break;
709 case 'L':
710 if (!l) break;
711 self->label_x = x;
712 XMapWindow(ob_display, self->label);
713 XMoveWindow(ob_display, self->label, x, s_bevel);
714 x += self->label_width + s_bevel + 1;
715 break;
716 case 'M':
717 if (!m) break;
718 self->max_x = x;
719 XMapWindow(ob_display, self->max);
720 XMoveWindow(ob_display, self->max, x, s_bevel + 1);
721 x += BUTTON_SIZE + s_bevel + 1;
722 break;
723 case 'C':
724 if (!c) break;
725 self->close_x = x;
726 XMapWindow(ob_display, self->close);
727 XMoveWindow(ob_display, self->close, x, s_bevel + 1);
728 x += BUTTON_SIZE + s_bevel + 1;
729 break;
730 }
731 }
732 }
733
734 static void render(ObFrame *self)
735 {
736 if (client_focused(self->frame.client)) {
737 XSetWindowBorder(ob_display, self->frame.plate,
738 s_cb_focused_color->pixel);
739 } else {
740 XSetWindowBorder(ob_display, self->frame.plate,
741 s_cb_unfocused_color->pixel);
742 }
743
744 if (self->frame.client->decorations & Decor_Titlebar) {
745 paint(self->title, (client_focused(self->frame.client) ?
746 self->a_focused_title :
747 self->a_unfocused_title),
748 0, 0, self->width, TITLE_HEIGHT);
749 render_label(self);
750 render_max(self);
751 render_icon(self);
752 render_iconify(self);
753 render_desk(self);
754 render_close(self);
755 }
756
757 if (self->frame.client->decorations & Decor_Handle) {
758 paint(self->handle, (client_focused(self->frame.client) ?
759 self->a_focused_handle :
760 self->a_unfocused_handle),
761 GRIP_WIDTH + self->bwidth, 0,
762 HANDLE_WIDTH(self), s_handle_height);
763 paint(self->lgrip, (client_focused(self->frame.client) ?
764 a_focused_grip :
765 a_unfocused_grip),
766 0, 0, GRIP_WIDTH, s_handle_height);
767 paint(self->rgrip, (client_focused(self->frame.client) ?
768 a_focused_grip :
769 a_unfocused_grip),
770 0, 0, GRIP_WIDTH, s_handle_height);
771 }
772 }
773
774 static void render_label(ObFrame *self)
775 {
776 Appearance *a;
777
778 if (self->label_x < 0) return;
779
780 a = (client_focused(self->frame.client) ?
781 self->a_focused_label : self->a_unfocused_label);
782
783 /* set the texture's text! */
784 a->texture[0].data.text.string = self->frame.client->title;
785
786 paint(self->label, a, 0, 0, self->label_width, LABEL_HEIGHT);
787 }
788
789 static void render_icon(ObFrame *self)
790 {
791 if (self->icon_x < 0) return;
792
793 /* XXX set the texture's icon picture! */
794 paint(self->icon, self->a_icon, 0, 0, BUTTON_SIZE, BUTTON_SIZE);
795 }
796
797 static void render_max(ObFrame *self)
798 {
799 gboolean press = self->max_press ||
800 self->frame.client->max_vert || self->frame.client->max_horz;
801
802 if (self->max_x < 0) return;
803
804 paint(self->max, (client_focused(self->frame.client) ?
805 (press ?
806 a_focused_pressed_max :
807 a_focused_unpressed_max) :
808 (press ?
809 a_unfocused_pressed_max :
810 a_unfocused_unpressed_max)),
811 0, 0, BUTTON_SIZE, BUTTON_SIZE);
812 }
813
814 static void render_iconify(ObFrame *self)
815 {
816 if (self->iconify_x < 0) return;
817
818 paint(self->iconify, (client_focused(self->frame.client) ?
819 (self->iconify_press ?
820 a_focused_pressed_iconify :
821 a_focused_unpressed_iconify) :
822 (self->iconify_press ?
823 a_unfocused_pressed_iconify :
824 a_unfocused_unpressed_iconify)),
825 0, 0, BUTTON_SIZE, BUTTON_SIZE);
826 }
827
828 static void render_desk(ObFrame *self)
829 {
830 gboolean press = self->desk_press ||
831 self->frame.client->desktop == DESKTOP_ALL;
832
833 if (self->desk_x < 0) return;
834
835 paint(self->desk, (client_focused(self->frame.client) ?
836 (press ?
837 a_focused_pressed_desk :
838 a_focused_unpressed_desk) :
839 (press ?
840 a_unfocused_pressed_desk :
841 a_unfocused_unpressed_desk)),
842 0, 0, BUTTON_SIZE, BUTTON_SIZE);
843 }
844
845 static void render_close(ObFrame *self)
846 {
847 if (self->close_x < 0) return;
848
849 paint(self->close, (client_focused(self->frame.client) ?
850 (self->close_press ?
851 a_focused_pressed_close :
852 a_focused_unpressed_close) :
853 (self->close_press ?
854 a_unfocused_pressed_close :
855 a_unfocused_unpressed_close)),
856 0, 0, BUTTON_SIZE, BUTTON_SIZE);
857 }
858
859 GQuark get_context(Client *client, Window win)
860 {
861 ObFrame *self;
862
863 if (win == ob_root) return g_quark_try_string("root");
864 if (client == NULL) return g_quark_try_string("none");
865 if (win == client->window) return g_quark_try_string("client");
866
867 self = (ObFrame*) client->frame;
868 if (win == self->frame.window) return g_quark_try_string("frame");
869 if (win == self->frame.plate) return g_quark_try_string("client");
870 if (win == self->title) return g_quark_try_string("titlebar");
871 if (win == self->label) return g_quark_try_string("titlebar");
872 if (win == self->handle) return g_quark_try_string("handle");
873 if (win == self->lgrip) return g_quark_try_string("blcorner");
874 if (win == self->rgrip) return g_quark_try_string("brcorner");
875 if (win == self->max) return g_quark_try_string("maximize");
876 if (win == self->iconify) return g_quark_try_string("iconify");
877 if (win == self->close) return g_quark_try_string("close");
878 if (win == self->icon) return g_quark_try_string("icon");
879 if (win == self->desk) return g_quark_try_string("alldesktops");
880
881 return g_quark_try_string("none");
882 }
883
884 static void frame_mouse_press(const ObEvent *e, ObFrame *self)
885 {
886 Window win = e->data.x.e->xbutton.window;
887 if (win == self->max) {
888 self->max_press = TRUE;
889 render_max(self);
890 } else if (win == self->close) {
891 self->close_press = TRUE;
892 render_close(self);
893 } else if (win == self->iconify) {
894 self->iconify_press = TRUE;
895 render_iconify(self);
896 } else if (win == self->desk) {
897 self->desk_press = TRUE;
898 render_desk(self);
899 }
900 }
901
902 static void frame_mouse_release(const ObEvent *e, ObFrame *self)
903 {
904 Window win = e->data.x.e->xbutton.window;
905 if (win == self->max) {
906 self->max_press = FALSE;
907 render_max(self);
908 } else if (win == self->close) {
909 self->close_press = FALSE;
910 render_close(self);
911 } else if (win == self->iconify) {
912 self->iconify_press = FALSE;
913 render_iconify(self);
914 } else if (win == self->desk) {
915 self->desk_press = FALSE;
916 render_desk(self);
917 }
918 }
This page took 0.074551 seconds and 4 git commands to generate.