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