use rgba icons for clients
[openbox.git] / engines / openbox / openbox.c
blobf7113c877844bf546b6cb5834b928c547b517815
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"
13 #include <X11/Xlib.h>
14 #include <glib.h>
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)
24 #define PLATE_EVENTMASK (SubstructureRedirectMask | ButtonPressMask)
25 #define FRAME_EVENTMASK (EnterWindowMask | LeaveWindowMask)
26 #define ELEMENT_EVENTMASK (ButtonPressMask | ButtonReleaseMask | \
27 ButtonMotionMask | ExposureMask)
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;
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;
80 typedef struct ObFrame {
81 Frame frame;
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;
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;
102 Strut innersize;
104 GSList *clients;
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 */
117 gboolean max_press;
118 gboolean close_press;
119 gboolean desk_press;
120 gboolean iconify_press;
121 } ObFrame;
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);
132 static void frame_mouse_press(const ObEvent *e, ObFrame *self);
133 static void frame_mouse_release(const ObEvent *e, ObFrame *self);
135 gboolean startup()
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");
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;
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, 1);
180 a_focused_handle = appearance_new(Surface_Planar, 0);
181 a_unfocused_handle = appearance_new(Surface_Planar, 0);
183 return load();
186 void shutdown()
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);
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);
203 if (s_winfont != NULL) font_close(s_winfont);
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);
244 static Window createWindow(Window parent, unsigned long mask,
245 XSetWindowAttributes *attrib)
247 return XCreateWindow(ob_display, parent, 0, 0, 1, 1, 0,
248 render_depth, InputOutput, render_visual,
249 mask, attrib);
253 Frame *frame_new()
255 XSetWindowAttributes attrib;
256 unsigned long mask;
257 ObFrame *self;
259 self = g_new(ObFrame, 1);
261 self->frame.visible = FALSE;
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);
269 mask = 0;
270 self->frame.plate = createWindow(self->frame.window, mask, &attrib);
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);
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);
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);
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);
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);
317 self->max_press = self->close_press = self->desk_press =
318 self->iconify_press = FALSE;
320 dispatch_register(Event_X_ButtonPress, (EventHandler)frame_mouse_press,
321 self);
322 dispatch_register(Event_X_ButtonRelease, (EventHandler)frame_mouse_release,
323 self);
325 return (Frame*)self;
328 static void frame_free(ObFrame *self)
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);
338 XDestroyWindow(ob_display, self->frame.window);
340 dispatch_register(0, (EventHandler)frame_mouse_press, self);
341 dispatch_register(0, (EventHandler)frame_mouse_release, self);
343 g_free(self);
346 void frame_show(ObFrame *self)
348 if (!self->frame.visible) {
349 self->frame.visible = TRUE;
350 XMapWindow(ob_display, self->frame.window);
354 void frame_hide(ObFrame *self)
356 if (self->frame.visible) {
357 self->frame.visible = FALSE;
358 self->frame.client->ignore_unmaps++;
359 XUnmapWindow(ob_display, self->frame.window);
363 void frame_adjust_shape(ObFrame *self)
365 #ifdef SHAPE
366 int num;
367 XRectangle xrect[2];
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);
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;
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;
402 XShapeCombineRectangles(ob_display, self->frame.window,
403 ShapeBounding, 0, 0, xrect, num,
404 ShapeUnion, Unsorted);
406 #endif
409 void frame_adjust_area(ObFrame *self, gboolean moved, gboolean resized)
411 if (resized) {
412 if (self->frame.client->decorations & Decor_Border) {
413 self->bwidth = s_bwidth;
414 self->cbwidth = s_cbwidth;
415 } else {
416 self->bwidth = self->cbwidth = 0;
418 STRUT_SET(self->innersize, self->cbwidth, self->cbwidth,
419 self->cbwidth, self->cbwidth);
420 self->width = self->frame.client->area.width + self->cbwidth * 2;
421 g_assert(self->width > 0);
423 /* set border widths */
424 XSetWindowBorderWidth(ob_display, self->frame.plate, self->cbwidth);
425 XSetWindowBorderWidth(ob_display, self->frame.window, self->bwidth);
426 XSetWindowBorderWidth(ob_display, self->title, self->bwidth);
427 XSetWindowBorderWidth(ob_display, self->handle, self->bwidth);
428 XSetWindowBorderWidth(ob_display, self->lgrip, self->bwidth);
429 XSetWindowBorderWidth(ob_display, self->rgrip, self->bwidth);
431 /* position/size and map/unmap all the windows */
433 /* they all default off, they're turned on in layout_title */
434 self->icon_x = -1;
435 self->desk_x = -1;
436 self->icon_x = -1;
437 self->label_x = -1;
438 self->max_x = -1;
439 self->close_x = -1;
441 if (self->frame.client->decorations & Decor_Titlebar) {
442 XMoveResizeWindow(ob_display, self->title,
443 -self->bwidth, -self->bwidth,
444 self->width, TITLE_HEIGHT);
445 self->innersize.top += TITLE_HEIGHT + self->bwidth;
446 XMapWindow(ob_display, self->title);
448 /* layout the title bar elements */
449 layout_title(self);
450 } else {
451 XUnmapWindow(ob_display, self->title);
452 /* make all the titlebar stuff not render */
453 self->frame.client->decorations &= ~(Decor_Icon | Decor_Iconify |
454 Decor_Maximize | Decor_Close |
455 Decor_AllDesktops);
458 if (self->frame.client->decorations & Decor_Handle) {
459 XMoveResizeWindow(ob_display, self->handle,
460 -self->bwidth, HANDLE_Y(self),
461 self->width, s_handle_height);
462 XMoveWindow(ob_display, self->lgrip,
463 -self->bwidth, -self->bwidth);
464 XMoveWindow(ob_display, self->rgrip,
465 -self->bwidth + self->width -
466 GRIP_WIDTH, -self->bwidth);
467 self->innersize.bottom += s_handle_height +
468 self->bwidth;
469 XMapWindow(ob_display, self->handle);
470 } else
471 XUnmapWindow(ob_display, self->handle);
474 if (moved) {
475 /* find the new coordinates */
476 self->frame.area.x = self->frame.client->area.x;
477 self->frame.area.y = self->frame.client->area.y;
478 frame_client_gravity((Frame*)self,
479 &self->frame.area.x, &self->frame.area.y);
482 /* move and resize the top level frame.
483 shading can change without being moved or resized */
484 XMoveResizeWindow(ob_display, self->frame.window,
485 self->frame.area.x, self->frame.area.y,
486 self->width,
487 (self->frame.client->shaded ? TITLE_HEIGHT :
488 self->innersize.top + self->innersize.bottom +
489 self->frame.client->area.height));
491 if (resized) {
492 /* move and resize the plate */
493 XMoveResizeWindow(ob_display, self->frame.plate,
494 self->innersize.left - self->cbwidth,
495 self->innersize.top - self->cbwidth,
496 self->frame.client->area.width,
497 self->frame.client->area.height);
498 /* when the client has StaticGravity, it likes to move around. */
499 XMoveWindow(ob_display, self->frame.client->window, 0, 0);
502 if (resized) {
503 STRUT_SET(self->frame.size,
504 self->innersize.left + self->bwidth,
505 self->innersize.top + self->bwidth,
506 self->innersize.right + self->bwidth,
507 self->innersize.bottom + self->bwidth);
510 /* shading can change without being moved or resized */
511 RECT_SET_SIZE(self->frame.area,
512 self->frame.client->area.width +
513 self->frame.size.left + self->frame.size.right,
514 (self->frame.client->shaded ? TITLE_HEIGHT + self->bwidth*2:
515 self->frame.client->area.height +
516 self->frame.size.top + self->frame.size.bottom));
518 if (resized) {
519 render(self);
521 frame_adjust_shape(self);
525 void frame_adjust_state(ObFrame *self)
527 render_max(self);
528 render_desk(self);
531 void frame_adjust_focus(ObFrame *self)
533 render(self);
536 void frame_adjust_title(ObFrame *self)
538 render_label(self);
541 void frame_adjust_icon(ObFrame *self)
543 render_icon(self);
546 void frame_grab_client(ObFrame *self, Client *client)
548 self->frame.client = client;
550 /* reparent the client to the frame */
551 XReparentWindow(ob_display, client->window, self->frame.plate, 0, 0);
553 When reparenting the client window, it is usually not mapped yet, since
554 this occurs from a MapRequest. However, in the case where Openbox is
555 starting up, the window is already mapped, so we'll see unmap events for
556 it. There are 2 unmap events generated that we see, one with the 'event'
557 member set the root window, and one set to the client, but both get
558 handled and need to be ignored.
560 if (ob_state == State_Starting)
561 client->ignore_unmaps += 2;
563 /* select the event mask on the client's parent (to receive config/map
564 req's) the ButtonPress is to catch clicks on the client border */
565 XSelectInput(ob_display, self->frame.plate, PLATE_EVENTMASK);
567 /* map the client so it maps when the frame does */
568 XMapWindow(ob_display, client->window);
570 frame_adjust_area(self, TRUE, TRUE);
572 /* set all the windows for the frame in the client_map */
573 g_hash_table_insert(client_map, &self->frame.window, client);
574 g_hash_table_insert(client_map, &self->frame.plate, client);
575 g_hash_table_insert(client_map, &self->title, client);
576 g_hash_table_insert(client_map, &self->label, client);
577 g_hash_table_insert(client_map, &self->max, client);
578 g_hash_table_insert(client_map, &self->close, client);
579 g_hash_table_insert(client_map, &self->desk, client);
580 g_hash_table_insert(client_map, &self->icon, client);
581 g_hash_table_insert(client_map, &self->iconify, client);
582 g_hash_table_insert(client_map, &self->handle, client);
583 g_hash_table_insert(client_map, &self->lgrip, client);
584 g_hash_table_insert(client_map, &self->rgrip, client);
587 void frame_release_client(ObFrame *self, Client *client)
589 XEvent ev;
591 g_assert(self->frame.client == client);
593 /* check if the app has already reparented its window away */
594 if (XCheckTypedWindowEvent(ob_display, client->window,
595 ReparentNotify, &ev)) {
596 XPutBackEvent(ob_display, &ev);
597 /* re-map the window since the unmanaging process unmaps it */
598 XMapWindow(ob_display, client->window);
599 } else {
600 /* according to the ICCCM - if the client doesn't reparent itself,
601 then we will reparent the window to root for them */
602 XReparentWindow(ob_display, client->window, ob_root,
603 client->area.x,
604 client->area.y);
607 /* remove all the windows for the frame from the client_map */
608 g_hash_table_remove(client_map, &self->frame.window);
609 g_hash_table_remove(client_map, &self->frame.plate);
610 g_hash_table_remove(client_map, &self->title);
611 g_hash_table_remove(client_map, &self->label);
612 g_hash_table_remove(client_map, &self->max);
613 g_hash_table_remove(client_map, &self->close);
614 g_hash_table_remove(client_map, &self->desk);
615 g_hash_table_remove(client_map, &self->icon);
616 g_hash_table_remove(client_map, &self->iconify);
617 g_hash_table_remove(client_map, &self->handle);
618 g_hash_table_remove(client_map, &self->lgrip);
619 g_hash_table_remove(client_map, &self->rgrip);
621 frame_free(self);
624 static void layout_title(ObFrame *self)
626 const char *lc;
627 int x;
628 gboolean n, d, i, l, m ,c;
629 ConfigValue layout;
631 n = d = i = l = m = c = FALSE;
633 if (!config_get("titlebar.layout", Config_String, &layout)) {
634 layout.string = "NDLIMC";
635 config_set("titlebar.layout", Config_String, layout);
638 /* figure out whats being shown, and the width of the label */
639 self->label_width = self->width - (s_bevel + 1) * 2;
640 for (lc = layout.string; *lc != '\0'; ++lc) {
641 switch (*lc) {
642 case 'N':
643 if (!(self->frame.client->decorations & Decor_Icon)) break;
644 n = TRUE;
645 self->label_width -= BUTTON_SIZE + s_bevel + 1;
646 break;
647 case 'D':
648 if (!(self->frame.client->decorations & Decor_AllDesktops)) break;
649 d = TRUE;
650 self->label_width -= BUTTON_SIZE + s_bevel + 1;
651 break;
652 case 'I':
653 if (!(self->frame.client->decorations & Decor_Iconify)) break;
654 i = TRUE;
655 self->label_width -= BUTTON_SIZE + s_bevel + 1;
656 break;
657 case 'L':
658 l = TRUE;
659 break;
660 case 'M':
661 if (!(self->frame.client->decorations & Decor_Maximize)) break;
662 m = TRUE;
663 self->label_width -= BUTTON_SIZE + s_bevel + 1;
664 break;
665 case 'C':
666 if (!(self->frame.client->decorations & Decor_Close)) break;
667 c = TRUE;
668 self->label_width -= BUTTON_SIZE + s_bevel + 1;
669 break;
672 if (self->label_width < 1) self->label_width = 1;
674 XResizeWindow(ob_display, self->label, self->label_width,
675 LABEL_HEIGHT);
677 if (!n) XUnmapWindow(ob_display, self->icon);
678 if (!d) XUnmapWindow(ob_display, self->desk);
679 if (!i) XUnmapWindow(ob_display, self->iconify);
680 if (!l) XUnmapWindow(ob_display, self->label);
681 if (!m) XUnmapWindow(ob_display, self->max);
682 if (!c) XUnmapWindow(ob_display, self->close);
684 x = s_bevel + 1;
685 for (lc = layout.string; *lc != '\0'; ++lc) {
686 switch (*lc) {
687 case 'N':
688 if (!n) break;
689 self->icon_x = x;
690 XMapWindow(ob_display, self->icon);
691 XMoveWindow(ob_display, self->icon, x, s_bevel + 1);
692 x += BUTTON_SIZE + s_bevel + 1;
693 break;
694 case 'D':
695 if (!d) break;
696 self->desk_x = x;
697 XMapWindow(ob_display, self->desk);
698 XMoveWindow(ob_display, self->desk, x, s_bevel + 1);
699 x += BUTTON_SIZE + s_bevel + 1;
700 break;
701 case 'I':
702 if (!i) break;
703 self->iconify_x = x;
704 XMapWindow(ob_display, self->iconify);
705 XMoveWindow(ob_display, self->iconify, x, s_bevel + 1);
706 x += BUTTON_SIZE + s_bevel + 1;
707 break;
708 case 'L':
709 if (!l) break;
710 self->label_x = x;
711 XMapWindow(ob_display, self->label);
712 XMoveWindow(ob_display, self->label, x, s_bevel);
713 x += self->label_width + s_bevel + 1;
714 break;
715 case 'M':
716 if (!m) break;
717 self->max_x = x;
718 XMapWindow(ob_display, self->max);
719 XMoveWindow(ob_display, self->max, x, s_bevel + 1);
720 x += BUTTON_SIZE + s_bevel + 1;
721 break;
722 case 'C':
723 if (!c) break;
724 self->close_x = x;
725 XMapWindow(ob_display, self->close);
726 XMoveWindow(ob_display, self->close, x, s_bevel + 1);
727 x += BUTTON_SIZE + s_bevel + 1;
728 break;
733 static void render(ObFrame *self)
735 if (client_focused(self->frame.client)) {
736 XSetWindowBorder(ob_display, self->frame.plate,
737 s_cb_focused_color->pixel);
738 } else {
739 XSetWindowBorder(ob_display, self->frame.plate,
740 s_cb_unfocused_color->pixel);
743 if (self->frame.client->decorations & Decor_Titlebar) {
744 paint(self->title, (client_focused(self->frame.client) ?
745 self->a_focused_title :
746 self->a_unfocused_title),
747 0, 0, self->width, TITLE_HEIGHT);
748 render_label(self);
749 render_max(self);
750 render_icon(self);
751 render_iconify(self);
752 render_desk(self);
753 render_close(self);
756 if (self->frame.client->decorations & Decor_Handle) {
757 paint(self->handle, (client_focused(self->frame.client) ?
758 self->a_focused_handle :
759 self->a_unfocused_handle),
760 GRIP_WIDTH + self->bwidth, 0,
761 HANDLE_WIDTH(self), s_handle_height);
762 paint(self->lgrip, (client_focused(self->frame.client) ?
763 a_focused_grip :
764 a_unfocused_grip),
765 0, 0, GRIP_WIDTH, s_handle_height);
766 paint(self->rgrip, (client_focused(self->frame.client) ?
767 a_focused_grip :
768 a_unfocused_grip),
769 0, 0, GRIP_WIDTH, s_handle_height);
773 static void render_label(ObFrame *self)
775 Appearance *a;
777 if (self->label_x < 0) return;
779 a = (client_focused(self->frame.client) ?
780 self->a_focused_label : self->a_unfocused_label);
782 /* set the texture's text! */
783 a->texture[0].data.text.string = self->frame.client->title;
784 RECT_SET(a->texture[0].position, 0, 0, self->label_width, LABEL_HEIGHT);
786 paint(self->label, a, 0, 0, self->label_width, LABEL_HEIGHT);
789 static void render_icon(ObFrame *self)
791 if (self->icon_x < 0) return;
793 if (self->frame.client->nicons) {
794 Icon *icon = client_icon(self->frame.client, BUTTON_SIZE, BUTTON_SIZE);
795 self->a_icon->texture[0].type = RGBA;
796 self->a_icon->texture[0].data.rgba.width = icon->width;
797 self->a_icon->texture[0].data.rgba.height = icon->height;
798 self->a_icon->texture[0].data.rgba.data = icon->data;
799 RECT_SET(self->a_icon->texture[0].position, 0, 0,
800 BUTTON_SIZE,BUTTON_SIZE);
801 } else
802 self->a_icon->texture[0].type = NoTexture;
804 paint(self->icon, self->a_icon, 0, 0, BUTTON_SIZE, BUTTON_SIZE);
807 static void render_max(ObFrame *self)
809 Appearance *a;
811 gboolean press = self->max_press ||
812 self->frame.client->max_vert || self->frame.client->max_horz;
814 if (self->max_x < 0) return;
816 a = (client_focused(self->frame.client) ?
817 (press ? a_focused_pressed_max : a_focused_unpressed_max) :
818 (press ? a_unfocused_pressed_max : a_unfocused_unpressed_max));
819 RECT_SET(a->texture[0].position, 0, 0, BUTTON_SIZE,BUTTON_SIZE);
820 paint(self->max, a, 0, 0, BUTTON_SIZE, BUTTON_SIZE);
823 static void render_iconify(ObFrame *self)
825 Appearance *a;
827 if (self->iconify_x < 0) return;
829 a = (client_focused(self->frame.client) ?
830 (self->iconify_press ?
831 a_focused_pressed_iconify : a_focused_unpressed_iconify) :
832 (self->iconify_press ?
833 a_unfocused_pressed_iconify : a_unfocused_unpressed_iconify));
834 RECT_SET(a->texture[0].position, 0, 0, BUTTON_SIZE,BUTTON_SIZE);
835 paint(self->iconify, a, 0, 0, BUTTON_SIZE, BUTTON_SIZE);
838 static void render_desk(ObFrame *self)
840 Appearance *a;
842 gboolean press = self->desk_press ||
843 self->frame.client->desktop == DESKTOP_ALL;
845 if (self->desk_x < 0) return;
847 a = (client_focused(self->frame.client) ?
848 (press ? a_focused_pressed_desk : a_focused_unpressed_desk) :
849 (press ? a_unfocused_pressed_desk : a_unfocused_unpressed_desk));
850 RECT_SET(a->texture[0].position, 0, 0, BUTTON_SIZE,BUTTON_SIZE);
851 paint(self->desk, a, 0, 0, BUTTON_SIZE, BUTTON_SIZE);
854 static void render_close(ObFrame *self)
856 Appearance *a;
858 if (self->close_x < 0) return;
860 a = (client_focused(self->frame.client) ?
861 (self->close_press ?
862 a_focused_pressed_close : a_focused_unpressed_close) :
863 (self->close_press ?
864 a_unfocused_pressed_close : a_unfocused_unpressed_close));
865 RECT_SET(a->texture[0].position, 0, 0, BUTTON_SIZE,BUTTON_SIZE);
866 paint(self->close, a, 0, 0, BUTTON_SIZE, BUTTON_SIZE);
869 GQuark get_context(Client *client, Window win)
871 ObFrame *self;
873 if (win == ob_root) return g_quark_try_string("root");
874 if (client == NULL) return g_quark_try_string("none");
875 if (win == client->window) return g_quark_try_string("client");
877 self = (ObFrame*) client->frame;
878 if (win == self->frame.window) return g_quark_try_string("frame");
879 if (win == self->frame.plate) return g_quark_try_string("client");
880 if (win == self->title) return g_quark_try_string("titlebar");
881 if (win == self->label) return g_quark_try_string("titlebar");
882 if (win == self->handle) return g_quark_try_string("handle");
883 if (win == self->lgrip) return g_quark_try_string("blcorner");
884 if (win == self->rgrip) return g_quark_try_string("brcorner");
885 if (win == self->max) return g_quark_try_string("maximize");
886 if (win == self->iconify) return g_quark_try_string("iconify");
887 if (win == self->close) return g_quark_try_string("close");
888 if (win == self->icon) return g_quark_try_string("icon");
889 if (win == self->desk) return g_quark_try_string("alldesktops");
891 return g_quark_try_string("none");
894 static void frame_mouse_press(const ObEvent *e, ObFrame *self)
896 Window win = e->data.x.e->xbutton.window;
897 if (win == self->max) {
898 self->max_press = TRUE;
899 render_max(self);
900 } else if (win == self->close) {
901 self->close_press = TRUE;
902 render_close(self);
903 } else if (win == self->iconify) {
904 self->iconify_press = TRUE;
905 render_iconify(self);
906 } else if (win == self->desk) {
907 self->desk_press = TRUE;
908 render_desk(self);
912 static void frame_mouse_release(const ObEvent *e, ObFrame *self)
914 Window win = e->data.x.e->xbutton.window;
915 if (win == self->max) {
916 self->max_press = FALSE;
917 render_max(self);
918 } else if (win == self->close) {
919 self->close_press = FALSE;
920 render_close(self);
921 } else if (win == self->iconify) {
922 self->iconify_press = FALSE;
923 render_iconify(self);
924 } else if (win == self->desk) {
925 self->desk_press = FALSE;
926 render_desk(self);