]> Dogcows Code - chaz/openbox/blob - engines/openbox/openbox.c
8979e8b4f19b075a756545057819e0da0d14b88c
[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 /* 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;
440
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);
447
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);
456 }
457
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);
472
473 /* find the new coordinates */
474 self->frame.area.x = self->frame.client->area.x;
475 self->frame.area.y = self->frame.client->area.y;
476 frame_client_gravity((Frame*)self,
477 &self->frame.area.x, &self->frame.area.y);
478 /* move and resize the top level frame */
479 XMoveResizeWindow(ob_display, self->frame.window,
480 self->frame.area.x, self->frame.area.y,
481 self->width,
482 (self->frame.client->shaded ? TITLE_HEIGHT :
483 self->innersize.top + self->innersize.bottom +
484 self->frame.client->area.height));
485
486 /* move and resize the plate */
487 XMoveResizeWindow(ob_display, self->frame.plate,
488 self->innersize.left - self->cbwidth,
489 self->innersize.top - self->cbwidth,
490 self->frame.client->area.width,
491 self->frame.client->area.height);
492 /* when the client has StaticGravity, it likes to move around. */
493 XMoveWindow(ob_display, self->frame.client->window, 0, 0);
494
495 STRUT_SET(self->frame.size,
496 self->innersize.left + self->bwidth,
497 self->innersize.top + self->bwidth,
498 self->innersize.right + self->bwidth,
499 self->innersize.bottom + self->bwidth);
500
501 RECT_SET_SIZE(self->frame.area,
502 self->frame.client->area.width +
503 self->frame.size.left + self->frame.size.right,
504 self->frame.client->area.height +
505 self->frame.size.top + self->frame.size.bottom);
506
507 render(self);
508
509 frame_adjust_shape(self);
510 }
511
512 void frame_adjust_state(ObFrame *self)
513 {
514 render_max(self);
515 render_desk(self);
516 }
517
518 void frame_adjust_focus(ObFrame *self)
519 {
520 render(self);
521 }
522
523 void frame_adjust_title(ObFrame *self)
524 {
525 render_label(self);
526 }
527
528 void frame_adjust_icon(ObFrame *self)
529 {
530 render_icon(self);
531 }
532
533 void frame_grab_client(ObFrame *self, Client *client)
534 {
535 self->frame.client = client;
536
537 /* reparent the client to the frame */
538 XReparentWindow(ob_display, client->window, self->frame.plate, 0, 0);
539 /*
540 When reparenting the client window, it is usually not mapped yet, since
541 this occurs from a MapRequest. However, in the case where Openbox is
542 starting up, the window is already mapped, so we'll see unmap events for
543 it. There are 2 unmap events generated that we see, one with the 'event'
544 member set the root window, and one set to the client, but both get
545 handled and need to be ignored.
546 */
547 if (ob_state == State_Starting)
548 client->ignore_unmaps += 2;
549
550 /* select the event mask on the client's parent (to receive config/map
551 req's) the ButtonPress is to catch clicks on the client border */
552 XSelectInput(ob_display, self->frame.plate, PLATE_EVENTMASK);
553
554 /* map the client so it maps when the frame does */
555 XMapWindow(ob_display, client->window);
556
557 frame_adjust_area(self);
558
559 /* set all the windows for the frame in the client_map */
560 g_hash_table_insert(client_map, (gpointer)self->frame.window, client);
561 g_hash_table_insert(client_map, (gpointer)self->frame.plate, client);
562 g_hash_table_insert(client_map, (gpointer)self->title, client);
563 g_hash_table_insert(client_map, (gpointer)self->label, client);
564 g_hash_table_insert(client_map, (gpointer)self->max, client);
565 g_hash_table_insert(client_map, (gpointer)self->close, client);
566 g_hash_table_insert(client_map, (gpointer)self->desk, client);
567 g_hash_table_insert(client_map, (gpointer)self->icon, client);
568 g_hash_table_insert(client_map, (gpointer)self->iconify, client);
569 g_hash_table_insert(client_map, (gpointer)self->handle, client);
570 g_hash_table_insert(client_map, (gpointer)self->lgrip, client);
571 g_hash_table_insert(client_map, (gpointer)self->rgrip, client);
572 }
573
574 void frame_release_client(ObFrame *self, Client *client)
575 {
576 XEvent ev;
577
578 g_assert(self->frame.client == client);
579
580 /* check if the app has already reparented its window away */
581 if (XCheckTypedWindowEvent(ob_display, client->window,
582 ReparentNotify, &ev)) {
583 XPutBackEvent(ob_display, &ev);
584 /* re-map the window since the unmanaging process unmaps it */
585 XMapWindow(ob_display, client->window);
586 } else {
587 /* according to the ICCCM - if the client doesn't reparent itself,
588 then we will reparent the window to root for them */
589 XReparentWindow(ob_display, client->window, ob_root,
590 client->area.x,
591 client->area.y);
592 }
593
594 /* remove all the windows for the frame from the client_map */
595 g_hash_table_remove(client_map, &self->frame.window);
596 g_hash_table_remove(client_map, &self->frame.plate);
597 g_hash_table_remove(client_map, &self->title);
598 g_hash_table_remove(client_map, &self->label);
599 g_hash_table_remove(client_map, &self->max);
600 g_hash_table_remove(client_map, &self->close);
601 g_hash_table_remove(client_map, &self->desk);
602 g_hash_table_remove(client_map, &self->icon);
603 g_hash_table_remove(client_map, &self->iconify);
604 g_hash_table_remove(client_map, &self->handle);
605 g_hash_table_remove(client_map, &self->lgrip);
606 g_hash_table_remove(client_map, &self->rgrip);
607
608 frame_free(self);
609 }
610
611 static void layout_title(ObFrame *self)
612 {
613 const char *lc;
614 int x;
615 gboolean n, d, i, l, m ,c;
616 ConfigValue layout;
617
618 n = d = i = l = m = c = FALSE;
619
620 if (!config_get("titlebar.layout", Config_String, &layout)) {
621 layout.string = "NDLIMC";
622 config_set("titlebar.layout", Config_String, layout);
623 }
624
625 /* figure out whats being shown, and the width of the label */
626 self->label_width = self->width - (s_bevel + 1) * 2;
627 for (lc = layout.string; *lc != '\0'; ++lc) {
628 switch (*lc) {
629 case 'N':
630 if (!(self->frame.client->decorations & Decor_Icon)) break;
631 n = TRUE;
632 self->label_width -= BUTTON_SIZE + s_bevel + 1;
633 break;
634 case 'D':
635 if (!(self->frame.client->decorations & Decor_AllDesktops)) break;
636 d = TRUE;
637 self->label_width -= BUTTON_SIZE + s_bevel + 1;
638 break;
639 case 'I':
640 if (!(self->frame.client->decorations & Decor_Iconify)) break;
641 i = TRUE;
642 self->label_width -= BUTTON_SIZE + s_bevel + 1;
643 break;
644 case 'L':
645 l = TRUE;
646 break;
647 case 'M':
648 if (!(self->frame.client->decorations & Decor_Maximize)) break;
649 m = TRUE;
650 self->label_width -= BUTTON_SIZE + s_bevel + 1;
651 break;
652 case 'C':
653 if (!(self->frame.client->decorations & Decor_Close)) break;
654 c = TRUE;
655 self->label_width -= BUTTON_SIZE + s_bevel + 1;
656 break;
657 }
658 }
659 if (self->label_width < 1) self->label_width = 1;
660
661 XResizeWindow(ob_display, self->label, self->label_width,
662 LABEL_HEIGHT);
663
664 if (!n) XUnmapWindow(ob_display, self->icon);
665 if (!d) XUnmapWindow(ob_display, self->desk);
666 if (!i) XUnmapWindow(ob_display, self->iconify);
667 if (!l) XUnmapWindow(ob_display, self->label);
668 if (!m) XUnmapWindow(ob_display, self->max);
669 if (!c) XUnmapWindow(ob_display, self->close);
670
671 x = s_bevel + 1;
672 for (lc = layout.string; *lc != '\0'; ++lc) {
673 switch (*lc) {
674 case 'N':
675 if (!n) break;
676 self->icon_x = x;
677 XMapWindow(ob_display, self->icon);
678 XMoveWindow(ob_display, self->icon, x, s_bevel + 1);
679 x += BUTTON_SIZE + s_bevel + 1;
680 break;
681 case 'D':
682 if (!d) break;
683 self->desk_x = x;
684 XMapWindow(ob_display, self->desk);
685 XMoveWindow(ob_display, self->desk, x, s_bevel + 1);
686 x += BUTTON_SIZE + s_bevel + 1;
687 break;
688 case 'I':
689 if (!i) break;
690 self->iconify_x = x;
691 XMapWindow(ob_display, self->iconify);
692 XMoveWindow(ob_display, self->iconify, x, s_bevel + 1);
693 x += BUTTON_SIZE + s_bevel + 1;
694 break;
695 case 'L':
696 if (!l) break;
697 self->label_x = x;
698 XMapWindow(ob_display, self->label);
699 XMoveWindow(ob_display, self->label, x, s_bevel);
700 x += self->label_width + s_bevel + 1;
701 break;
702 case 'M':
703 if (!m) break;
704 self->max_x = x;
705 XMapWindow(ob_display, self->max);
706 XMoveWindow(ob_display, self->max, x, s_bevel + 1);
707 x += BUTTON_SIZE + s_bevel + 1;
708 break;
709 case 'C':
710 if (!c) break;
711 self->close_x = x;
712 XMapWindow(ob_display, self->close);
713 XMoveWindow(ob_display, self->close, x, s_bevel + 1);
714 x += BUTTON_SIZE + s_bevel + 1;
715 break;
716 }
717 }
718 }
719
720 static void render(ObFrame *self)
721 {
722 if (client_focused(self->frame.client)) {
723 XSetWindowBorder(ob_display, self->frame.plate,
724 s_cb_focused_color->pixel);
725 } else {
726 XSetWindowBorder(ob_display, self->frame.plate,
727 s_cb_unfocused_color->pixel);
728 }
729
730 if (self->frame.client->decorations & Decor_Titlebar) {
731 paint(self->title, (client_focused(self->frame.client) ?
732 self->a_focused_title :
733 self->a_unfocused_title),
734 0, 0, self->width, TITLE_HEIGHT);
735 render_label(self);
736 render_max(self);
737 render_icon(self);
738 render_iconify(self);
739 render_desk(self);
740 render_close(self);
741 }
742
743 if (self->frame.client->decorations & Decor_Handle) {
744 paint(self->handle, (client_focused(self->frame.client) ?
745 self->a_focused_handle :
746 self->a_unfocused_handle),
747 GRIP_WIDTH + self->bwidth, 0,
748 HANDLE_WIDTH(self), s_handle_height);
749 paint(self->lgrip, (client_focused(self->frame.client) ?
750 a_focused_grip :
751 a_unfocused_grip),
752 0, 0, GRIP_WIDTH, s_handle_height);
753 paint(self->rgrip, (client_focused(self->frame.client) ?
754 a_focused_grip :
755 a_unfocused_grip),
756 0, 0, GRIP_WIDTH, s_handle_height);
757 }
758 }
759
760 static void render_label(ObFrame *self)
761 {
762 Appearance *a;
763
764 if (self->label_x < 0) return;
765
766 a = (client_focused(self->frame.client) ?
767 self->a_focused_label : self->a_unfocused_label);
768
769 /* set the texture's text! */
770 a->texture[0].data.text.string = self->frame.client->title;
771
772 paint(self->label, a, 0, 0, self->label_width, LABEL_HEIGHT);
773 }
774
775 static void render_icon(ObFrame *self)
776 {
777 if (self->icon_x < 0) return;
778
779 /* XXX set the texture's icon picture! */
780 paint(self->icon, self->a_icon, 0, 0, BUTTON_SIZE, BUTTON_SIZE);
781 }
782
783 static void render_max(ObFrame *self)
784 {
785 gboolean press = self->max_press ||
786 self->frame.client->max_vert || self->frame.client->max_horz;
787
788 if (self->max_x < 0) return;
789
790 paint(self->max, (client_focused(self->frame.client) ?
791 (press ?
792 a_focused_pressed_max :
793 a_focused_unpressed_max) :
794 (press ?
795 a_unfocused_pressed_max :
796 a_unfocused_unpressed_max)),
797 0, 0, BUTTON_SIZE, BUTTON_SIZE);
798 }
799
800 static void render_iconify(ObFrame *self)
801 {
802 if (self->iconify_x < 0) return;
803
804 paint(self->iconify, (client_focused(self->frame.client) ?
805 (self->iconify_press ?
806 a_focused_pressed_iconify :
807 a_focused_unpressed_iconify) :
808 (self->iconify_press ?
809 a_unfocused_pressed_iconify :
810 a_unfocused_unpressed_iconify)),
811 0, 0, BUTTON_SIZE, BUTTON_SIZE);
812 }
813
814 static void render_desk(ObFrame *self)
815 {
816 gboolean press = self->desk_press ||
817 self->frame.client->desktop == DESKTOP_ALL;
818
819 if (self->desk_x < 0) return;
820
821 paint(self->desk, (client_focused(self->frame.client) ?
822 (press ?
823 a_focused_pressed_desk :
824 a_focused_unpressed_desk) :
825 (press ?
826 a_unfocused_pressed_desk :
827 a_unfocused_unpressed_desk)),
828 0, 0, BUTTON_SIZE, BUTTON_SIZE);
829 }
830
831 static void render_close(ObFrame *self)
832 {
833 if (self->close_x < 0) return;
834
835 paint(self->close, (client_focused(self->frame.client) ?
836 (self->close_press ?
837 a_focused_pressed_close :
838 a_focused_unpressed_close) :
839 (self->close_press ?
840 a_unfocused_pressed_close :
841 a_unfocused_unpressed_close)),
842 0, 0, BUTTON_SIZE, BUTTON_SIZE);
843 }
844
845 GQuark get_context(Client *client, Window win)
846 {
847 ObFrame *self;
848
849 if (win == ob_root) return g_quark_try_string("root");
850 if (client == NULL) return g_quark_try_string("none");
851 if (win == client->window) return g_quark_try_string("client");
852
853 self = (ObFrame*) client->frame;
854 if (win == self->frame.window) return g_quark_try_string("frame");
855 if (win == self->frame.plate) return g_quark_try_string("client");
856 if (win == self->title) return g_quark_try_string("titlebar");
857 if (win == self->label) return g_quark_try_string("titlebar");
858 if (win == self->handle) return g_quark_try_string("handle");
859 if (win == self->lgrip) return g_quark_try_string("blcorner");
860 if (win == self->rgrip) return g_quark_try_string("brcorner");
861 if (win == self->max) return g_quark_try_string("maximize");
862 if (win == self->iconify) return g_quark_try_string("iconify");
863 if (win == self->close) return g_quark_try_string("close");
864 if (win == self->icon) return g_quark_try_string("icon");
865 if (win == self->desk) return g_quark_try_string("alldesktops");
866
867 return g_quark_try_string("none");
868 }
869
870 static void frame_mouse_press(const ObEvent *e, ObFrame *self)
871 {
872 Window win = e->data.x.e->xbutton.window;
873 if (win == self->max) {
874 self->max_press = TRUE;
875 render_max(self);
876 } else if (win == self->close) {
877 self->close_press = TRUE;
878 render_close(self);
879 } else if (win == self->iconify) {
880 self->iconify_press = TRUE;
881 render_iconify(self);
882 } else if (win == self->desk) {
883 self->desk_press = TRUE;
884 render_desk(self);
885 }
886 }
887
888 static void frame_mouse_release(const ObEvent *e, ObFrame *self)
889 {
890 Window win = e->data.x.e->xbutton.window;
891 if (win == self->max) {
892 self->max_press = FALSE;
893 render_max(self);
894 } else if (win == self->close) {
895 self->close_press = FALSE;
896 render_close(self);
897 } else if (win == self->iconify) {
898 self->iconify_press = FALSE;
899 render_iconify(self);
900 } else if (win == self->desk) {
901 self->desk_press = FALSE;
902 render_desk(self);
903 }
904 }
This page took 0.076179 seconds and 3 git commands to generate.