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