]> Dogcows Code - chaz/openbox/blob - engines/openbox/openbox.c
support parent relative titlebar elements
[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, Appearance *a);
126 static void render_max(ObFrame *self, Appearance *a);
127 static void render_icon(ObFrame *self, Appearance *a);
128 static void render_iconify(ObFrame *self, Appearance *a);
129 static void render_desk(ObFrame *self, Appearance *a);
130 static void render_close(ObFrame *self, Appearance *a);
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, 1);
180 a_focused_handle = appearance_new(Surface_Planar, 0);
181 a_unfocused_handle = appearance_new(Surface_Planar, 0);
182
183 return load();
184 }
185
186 void shutdown()
187 {
188 if (s_b_color != NULL) color_free(s_b_color);
189 if (s_cb_unfocused_color != NULL) color_free(s_cb_unfocused_color);
190 if (s_cb_focused_color != NULL) color_free(s_cb_focused_color);
191 if (s_title_unfocused_color != NULL) color_free(s_title_unfocused_color);
192 if (s_title_focused_color != NULL) color_free(s_title_focused_color);
193 if (s_titlebut_unfocused_color != NULL)
194 color_free(s_titlebut_unfocused_color);
195 if (s_titlebut_focused_color != NULL)
196 color_free(s_titlebut_focused_color);
197
198 if (s_max_mask != NULL) pixmap_mask_free(s_max_mask);
199 if (s_desk_mask != NULL) pixmap_mask_free(s_desk_mask);
200 if (s_icon_mask != NULL) pixmap_mask_free(s_icon_mask);
201 if (s_close_mask != NULL) pixmap_mask_free(s_close_mask);
202
203 if (s_winfont != NULL) font_close(s_winfont);
204
205 appearance_free(a_focused_unpressed_max);
206 appearance_free(a_focused_pressed_max);
207 appearance_free(a_unfocused_unpressed_max);
208 appearance_free(a_unfocused_pressed_max);
209 if (a_focused_unpressed_close != NULL)
210 appearance_free(a_focused_unpressed_close);
211 if (a_focused_pressed_close != NULL)
212 appearance_free(a_focused_pressed_close);
213 if (a_unfocused_unpressed_close != NULL)
214 appearance_free(a_unfocused_unpressed_close);
215 if (a_unfocused_pressed_close != NULL)
216 appearance_free(a_unfocused_pressed_close);
217 if (a_focused_unpressed_desk != NULL)
218 appearance_free(a_focused_unpressed_desk);
219 if (a_focused_pressed_desk != NULL)
220 appearance_free(a_focused_pressed_desk);
221 if (a_unfocused_unpressed_desk != NULL)
222 appearance_free(a_unfocused_unpressed_desk);
223 if (a_unfocused_pressed_desk != NULL)
224 appearance_free(a_unfocused_pressed_desk);
225 if (a_focused_unpressed_iconify != NULL)
226 appearance_free(a_focused_unpressed_iconify);
227 if (a_focused_pressed_iconify != NULL)
228 appearance_free(a_focused_pressed_iconify);
229 if (a_unfocused_unpressed_iconify != NULL)
230 appearance_free(a_unfocused_unpressed_iconify);
231 if (a_unfocused_pressed_iconify != NULL)
232 appearance_free(a_unfocused_pressed_iconify);
233 appearance_free(a_focused_grip);
234 appearance_free(a_unfocused_grip);
235 appearance_free(a_focused_title);
236 appearance_free(a_unfocused_title);
237 appearance_free(a_focused_label);
238 appearance_free(a_unfocused_label);
239 appearance_free(a_icon);
240 appearance_free(a_focused_handle);
241 appearance_free(a_unfocused_handle);
242 }
243
244 static Window createWindow(Window parent, unsigned long mask,
245 XSetWindowAttributes *attrib)
246 {
247 return XCreateWindow(ob_display, parent, 0, 0, 1, 1, 0,
248 render_depth, InputOutput, render_visual,
249 mask, attrib);
250
251 }
252
253 Frame *frame_new()
254 {
255 XSetWindowAttributes attrib;
256 unsigned long mask;
257 ObFrame *self;
258
259 self = g_new(ObFrame, 1);
260
261 self->frame.visible = FALSE;
262
263 /* create all of the decor windows */
264 mask = CWOverrideRedirect | CWEventMask;
265 attrib.event_mask = FRAME_EVENTMASK;
266 attrib.override_redirect = TRUE;
267 self->frame.window = createWindow(ob_root, mask, &attrib);
268
269 mask = 0;
270 self->frame.plate = createWindow(self->frame.window, mask, &attrib);
271
272 mask = CWEventMask;
273 attrib.event_mask = ELEMENT_EVENTMASK;
274 self->title = createWindow(self->frame.window, mask, &attrib);
275 self->label = createWindow(self->title, mask, &attrib);
276 self->max = createWindow(self->title, mask, &attrib);
277 self->close = createWindow(self->title, mask, &attrib);
278 self->desk = createWindow(self->title, mask, &attrib);
279 self->icon = createWindow(self->title, mask, &attrib);
280 self->iconify = createWindow(self->title, mask, &attrib);
281 self->handle = createWindow(self->frame.window, mask, &attrib);
282 mask |= CWCursor;
283 attrib.cursor = ob_cursors.ll_angle;
284 self->lgrip = createWindow(self->handle, mask, &attrib);
285 attrib.cursor = ob_cursors.lr_angle;
286 self->rgrip = createWindow(self->handle, mask, &attrib);
287
288 /* the other stuff is shown based on decor settings */
289 XMapWindow(ob_display, self->frame.plate);
290 XMapWindow(ob_display, self->lgrip);
291 XMapWindow(ob_display, self->rgrip);
292 XMapWindow(ob_display, self->label);
293
294 /* set colors/appearance/sizes for stuff that doesn't change */
295 XSetWindowBorder(ob_display, self->frame.window, s_b_color->pixel);
296 XSetWindowBorder(ob_display, self->label, s_b_color->pixel);
297 XSetWindowBorder(ob_display, self->rgrip, s_b_color->pixel);
298 XSetWindowBorder(ob_display, self->lgrip, s_b_color->pixel);
299
300 XResizeWindow(ob_display, self->max, BUTTON_SIZE, BUTTON_SIZE);
301 XResizeWindow(ob_display, self->iconify, BUTTON_SIZE, BUTTON_SIZE);
302 XResizeWindow(ob_display, self->icon, BUTTON_SIZE, BUTTON_SIZE);
303 XResizeWindow(ob_display, self->close, BUTTON_SIZE, BUTTON_SIZE);
304 XResizeWindow(ob_display, self->desk, BUTTON_SIZE, BUTTON_SIZE);
305 XResizeWindow(ob_display, self->lgrip, GRIP_WIDTH, s_handle_height);
306 XResizeWindow(ob_display, self->rgrip, GRIP_WIDTH, s_handle_height);
307
308 /* set up the dynamic appearances */
309 self->a_unfocused_title = appearance_copy(a_unfocused_title);
310 self->a_focused_title = appearance_copy(a_focused_title);
311 self->a_unfocused_label = appearance_copy(a_unfocused_label);
312 self->a_focused_label = appearance_copy(a_focused_label);
313 self->a_unfocused_handle = appearance_copy(a_unfocused_handle);
314 self->a_focused_handle = appearance_copy(a_focused_handle);
315 self->a_icon = appearance_copy(a_icon);
316
317 self->max_press = self->close_press = self->desk_press =
318 self->iconify_press = FALSE;
319
320 dispatch_register(Event_X_ButtonPress, (EventHandler)frame_mouse_press,
321 self);
322 dispatch_register(Event_X_ButtonRelease, (EventHandler)frame_mouse_release,
323 self);
324
325 return (Frame*)self;
326 }
327
328 static void frame_free(ObFrame *self)
329 {
330 appearance_free(self->a_unfocused_title);
331 appearance_free(self->a_focused_title);
332 appearance_free(self->a_unfocused_label);
333 appearance_free(self->a_focused_label);
334 appearance_free(self->a_unfocused_handle);
335 appearance_free(self->a_focused_handle);
336 appearance_free(self->a_icon);
337
338 XDestroyWindow(ob_display, self->frame.window);
339
340 dispatch_register(0, (EventHandler)frame_mouse_press, self);
341 dispatch_register(0, (EventHandler)frame_mouse_release, self);
342
343 g_free(self);
344 }
345
346 void frame_show(ObFrame *self)
347 {
348 if (!self->frame.visible) {
349 self->frame.visible = TRUE;
350 XMapWindow(ob_display, self->frame.window);
351 }
352 }
353
354 void frame_hide(ObFrame *self)
355 {
356 if (self->frame.visible) {
357 self->frame.visible = FALSE;
358 self->frame.client->ignore_unmaps++;
359 XUnmapWindow(ob_display, self->frame.window);
360 }
361 }
362
363 void frame_adjust_shape(ObFrame *self)
364 {
365 #ifdef SHAPE
366 int num;
367 XRectangle xrect[2];
368
369 if (!self->frame.client->shaped) {
370 /* clear the shape on the frame window */
371 XShapeCombineMask(ob_display, self->frame.window, ShapeBounding,
372 self->innersize.left,
373 self->innersize.top,
374 None, ShapeSet);
375 } else {
376 /* make the frame's shape match the clients */
377 XShapeCombineShape(ob_display, self->frame.window, ShapeBounding,
378 self->innersize.left,
379 self->innersize.top,
380 self->frame.client->window,
381 ShapeBounding, ShapeSet);
382
383 num = 0;
384 if (self->frame.client->decorations & Decor_Titlebar) {
385 xrect[0].x = -s_bevel;
386 xrect[0].y = -s_bevel;
387 xrect[0].width = self->width + self->bwidth * 2;
388 xrect[0].height = TITLE_HEIGHT +
389 self->bwidth * 2;
390 ++num;
391 }
392
393 if (self->frame.client->decorations & Decor_Handle) {
394 xrect[1].x = -s_bevel;
395 xrect[1].y = HANDLE_Y(self);
396 xrect[1].width = self->width + self->bwidth * 2;
397 xrect[1].height = s_handle_height +
398 self->bwidth * 2;
399 ++num;
400 }
401
402 XShapeCombineRectangles(ob_display, self->frame.window,
403 ShapeBounding, 0, 0, xrect, num,
404 ShapeUnion, Unsorted);
405 }
406 #endif
407 }
408
409 void frame_adjust_area(ObFrame *self, gboolean moved, gboolean resized)
410 {
411 if (resized) {
412 if (self->frame.client->decorations & Decor_Border) {
413 self->bwidth = s_bwidth;
414 self->cbwidth = s_cbwidth;
415 } else {
416 self->bwidth = self->cbwidth = 0;
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
474 if (resized) {
475 /* move and resize the plate */
476 XMoveResizeWindow(ob_display, self->frame.plate,
477 self->innersize.left - self->cbwidth,
478 self->innersize.top - self->cbwidth,
479 self->frame.client->area.width,
480 self->frame.client->area.height);
481 /* when the client has StaticGravity, it likes to move around. */
482 XMoveWindow(ob_display, self->frame.client->window, 0, 0);
483 }
484
485 if (resized) {
486 STRUT_SET(self->frame.size,
487 self->innersize.left + self->bwidth,
488 self->innersize.top + self->bwidth,
489 self->innersize.right + self->bwidth,
490 self->innersize.bottom + self->bwidth);
491 }
492
493 /* shading can change without being moved or resized */
494 RECT_SET_SIZE(self->frame.area,
495 self->frame.client->area.width +
496 self->frame.size.left + self->frame.size.right,
497 (self->frame.client->shaded ? TITLE_HEIGHT + self->bwidth*2:
498 self->frame.client->area.height +
499 self->frame.size.top + self->frame.size.bottom));
500
501 if (moved) {
502 /* find the new coordinates, done after setting the frame.size, for
503 frame_client_gravity. */
504 self->frame.area.x = self->frame.client->area.x;
505 self->frame.area.y = self->frame.client->area.y;
506 frame_client_gravity((Frame*)self,
507 &self->frame.area.x, &self->frame.area.y);
508 }
509
510 /* move and resize the top level frame.
511 shading can change without being moved or resized */
512 XMoveResizeWindow(ob_display, self->frame.window,
513 self->frame.area.x, self->frame.area.y,
514 self->width, self->frame.area.height - self->bwidth * 2);
515
516 if (resized) {
517 render(self);
518
519 frame_adjust_shape(self);
520 }
521 }
522
523 void frame_adjust_state(ObFrame *self)
524 {
525 render(self);
526 }
527
528 void frame_adjust_focus(ObFrame *self)
529 {
530 render(self);
531 }
532
533 void frame_adjust_title(ObFrame *self)
534 {
535 render(self);
536 }
537
538 void frame_adjust_icon(ObFrame *self)
539 {
540 render(self);
541 }
542
543 void frame_grab_client(ObFrame *self, Client *client)
544 {
545 self->frame.client = client;
546
547 /* reparent the client to the frame */
548 XReparentWindow(ob_display, client->window, self->frame.plate, 0, 0);
549 /*
550 When reparenting the client window, it is usually not mapped yet, since
551 this occurs from a MapRequest. However, in the case where Openbox is
552 starting up, the window is already mapped, so we'll see unmap events for
553 it. There are 2 unmap events generated that we see, one with the 'event'
554 member set the root window, and one set to the client, but both get
555 handled and need to be ignored.
556 */
557 if (ob_state == State_Starting)
558 client->ignore_unmaps += 2;
559
560 /* select the event mask on the client's parent (to receive config/map
561 req's) the ButtonPress is to catch clicks on the client border */
562 XSelectInput(ob_display, self->frame.plate, PLATE_EVENTMASK);
563
564 /* map the client so it maps when the frame does */
565 XMapWindow(ob_display, client->window);
566
567 frame_adjust_area(self, TRUE, TRUE);
568
569 /* set all the windows for the frame in the client_map */
570 g_hash_table_insert(client_map, &self->frame.window, client);
571 g_hash_table_insert(client_map, &self->frame.plate, client);
572 g_hash_table_insert(client_map, &self->title, client);
573 g_hash_table_insert(client_map, &self->label, client);
574 g_hash_table_insert(client_map, &self->max, client);
575 g_hash_table_insert(client_map, &self->close, client);
576 g_hash_table_insert(client_map, &self->desk, client);
577 g_hash_table_insert(client_map, &self->icon, client);
578 g_hash_table_insert(client_map, &self->iconify, client);
579 g_hash_table_insert(client_map, &self->handle, client);
580 g_hash_table_insert(client_map, &self->lgrip, client);
581 g_hash_table_insert(client_map, &self->rgrip, client);
582 }
583
584 void frame_release_client(ObFrame *self, Client *client)
585 {
586 XEvent ev;
587
588 g_assert(self->frame.client == client);
589
590 /* check if the app has already reparented its window away */
591 if (XCheckTypedWindowEvent(ob_display, client->window,
592 ReparentNotify, &ev)) {
593 XPutBackEvent(ob_display, &ev);
594 /* re-map the window since the unmanaging process unmaps it */
595 XMapWindow(ob_display, client->window);
596 } else {
597 /* according to the ICCCM - if the client doesn't reparent itself,
598 then we will reparent the window to root for them */
599 XReparentWindow(ob_display, client->window, ob_root,
600 client->area.x,
601 client->area.y);
602 }
603
604 /* remove all the windows for the frame from the client_map */
605 g_hash_table_remove(client_map, &self->frame.window);
606 g_hash_table_remove(client_map, &self->frame.plate);
607 g_hash_table_remove(client_map, &self->title);
608 g_hash_table_remove(client_map, &self->label);
609 g_hash_table_remove(client_map, &self->max);
610 g_hash_table_remove(client_map, &self->close);
611 g_hash_table_remove(client_map, &self->desk);
612 g_hash_table_remove(client_map, &self->icon);
613 g_hash_table_remove(client_map, &self->iconify);
614 g_hash_table_remove(client_map, &self->handle);
615 g_hash_table_remove(client_map, &self->lgrip);
616 g_hash_table_remove(client_map, &self->rgrip);
617
618 frame_free(self);
619 }
620
621 static void layout_title(ObFrame *self)
622 {
623 const char *lc;
624 int x;
625 gboolean n, d, i, l, m ,c;
626 ConfigValue layout;
627
628 n = d = i = l = m = c = FALSE;
629
630 if (!config_get("titlebar.layout", Config_String, &layout)) {
631 layout.string = "NDLIMC";
632 config_set("titlebar.layout", Config_String, layout);
633 }
634
635 /* figure out whats being shown, and the width of the label */
636 self->label_width = self->width - (s_bevel + 1) * 2;
637 for (lc = layout.string; *lc != '\0'; ++lc) {
638 switch (*lc) {
639 case 'N':
640 if (!(self->frame.client->decorations & Decor_Icon)) break;
641 n = TRUE;
642 self->label_width -= BUTTON_SIZE + s_bevel + 1;
643 break;
644 case 'D':
645 if (!(self->frame.client->decorations & Decor_AllDesktops)) break;
646 d = TRUE;
647 self->label_width -= BUTTON_SIZE + s_bevel + 1;
648 break;
649 case 'I':
650 if (!(self->frame.client->decorations & Decor_Iconify)) break;
651 i = TRUE;
652 self->label_width -= BUTTON_SIZE + s_bevel + 1;
653 break;
654 case 'L':
655 l = TRUE;
656 break;
657 case 'M':
658 if (!(self->frame.client->decorations & Decor_Maximize)) break;
659 m = TRUE;
660 self->label_width -= BUTTON_SIZE + s_bevel + 1;
661 break;
662 case 'C':
663 if (!(self->frame.client->decorations & Decor_Close)) break;
664 c = TRUE;
665 self->label_width -= BUTTON_SIZE + s_bevel + 1;
666 break;
667 }
668 }
669 if (self->label_width < 1) self->label_width = 1;
670
671 XResizeWindow(ob_display, self->label, self->label_width,
672 LABEL_HEIGHT);
673
674 if (!n) XUnmapWindow(ob_display, self->icon);
675 if (!d) XUnmapWindow(ob_display, self->desk);
676 if (!i) XUnmapWindow(ob_display, self->iconify);
677 if (!l) XUnmapWindow(ob_display, self->label);
678 if (!m) XUnmapWindow(ob_display, self->max);
679 if (!c) XUnmapWindow(ob_display, self->close);
680
681 x = s_bevel + 1;
682 for (lc = layout.string; *lc != '\0'; ++lc) {
683 switch (*lc) {
684 case 'N':
685 if (!n) break;
686 self->icon_x = x;
687 XMapWindow(ob_display, self->icon);
688 XMoveWindow(ob_display, self->icon, x, s_bevel + 1);
689 x += BUTTON_SIZE + s_bevel + 1;
690 break;
691 case 'D':
692 if (!d) break;
693 self->desk_x = x;
694 XMapWindow(ob_display, self->desk);
695 XMoveWindow(ob_display, self->desk, x, s_bevel + 1);
696 x += BUTTON_SIZE + s_bevel + 1;
697 break;
698 case 'I':
699 if (!i) break;
700 self->iconify_x = x;
701 XMapWindow(ob_display, self->iconify);
702 XMoveWindow(ob_display, self->iconify, x, s_bevel + 1);
703 x += BUTTON_SIZE + s_bevel + 1;
704 break;
705 case 'L':
706 if (!l) break;
707 self->label_x = x;
708 XMapWindow(ob_display, self->label);
709 XMoveWindow(ob_display, self->label, x, s_bevel);
710 x += self->label_width + s_bevel + 1;
711 break;
712 case 'M':
713 if (!m) break;
714 self->max_x = x;
715 XMapWindow(ob_display, self->max);
716 XMoveWindow(ob_display, self->max, x, s_bevel + 1);
717 x += BUTTON_SIZE + s_bevel + 1;
718 break;
719 case 'C':
720 if (!c) break;
721 self->close_x = x;
722 XMapWindow(ob_display, self->close);
723 XMoveWindow(ob_display, self->close, x, s_bevel + 1);
724 x += BUTTON_SIZE + s_bevel + 1;
725 break;
726 }
727 }
728 }
729
730 static void render(ObFrame *self)
731 {
732 if (client_focused(self->frame.client)) {
733 XSetWindowBorder(ob_display, self->frame.plate,
734 s_cb_focused_color->pixel);
735 } else {
736 XSetWindowBorder(ob_display, self->frame.plate,
737 s_cb_unfocused_color->pixel);
738 }
739
740 if (self->frame.client->decorations & Decor_Titlebar) {
741 Appearance *t, *l, *m, *n, *i, *d, *c;
742
743 t = (client_focused(self->frame.client) ?
744 self->a_focused_title : self->a_unfocused_title);
745 l = (client_focused(self->frame.client) ?
746 self->a_focused_label : self->a_unfocused_label);
747 m = (client_focused(self->frame.client) ?
748 ((self->max_press ||
749 self->frame.client->max_vert || self->frame.client->max_horz) ?
750 a_focused_pressed_max : a_focused_unpressed_max) :
751 ((self->max_press ||
752 self->frame.client->max_vert || self->frame.client->max_horz) ?
753 a_unfocused_pressed_max : a_unfocused_unpressed_max));
754 n = self->a_icon;
755 i = (client_focused(self->frame.client) ?
756 (self->iconify_press ?
757 a_focused_pressed_iconify : a_focused_unpressed_iconify) :
758 (self->iconify_press ?
759 a_unfocused_pressed_iconify : a_unfocused_unpressed_iconify));
760 d = (client_focused(self->frame.client) ?
761 (self->desk_press || self->frame.client->desktop == DESKTOP_ALL ?
762 a_focused_pressed_desk : a_focused_unpressed_desk) :
763 (self->desk_press || self->frame.client->desktop == DESKTOP_ALL ?
764 a_unfocused_pressed_desk : a_unfocused_unpressed_desk));
765 c = (client_focused(self->frame.client) ?
766 (self->close_press ?
767 a_focused_pressed_close : a_focused_unpressed_close) :
768 (self->close_press ?
769 a_unfocused_pressed_close : a_unfocused_unpressed_close));
770
771 paint(self->title, t, 0, 0, self->width, TITLE_HEIGHT);
772
773 /* set parents for any parent relative guys */
774 l->surface.data.planar.parent = t;
775 l->surface.data.planar.parentx = self->label_x;
776 l->surface.data.planar.parenty = s_bevel;
777
778 m->surface.data.planar.parent = t;
779 m->surface.data.planar.parentx = self->max_x;
780 m->surface.data.planar.parenty = s_bevel + 1;
781
782 n->surface.data.planar.parent = t;
783 n->surface.data.planar.parentx = self->icon_x;
784 n->surface.data.planar.parenty = s_bevel + 1;
785
786 i->surface.data.planar.parent = t;
787 i->surface.data.planar.parentx = self->iconify_x;
788 i->surface.data.planar.parenty = s_bevel + 1;
789
790 d->surface.data.planar.parent = t;
791 d->surface.data.planar.parentx = self->desk_x;
792 d->surface.data.planar.parenty = s_bevel + 1;
793
794 c->surface.data.planar.parent = t;
795 c->surface.data.planar.parentx = self->close_x;
796 c->surface.data.planar.parenty = s_bevel + 1;
797
798 render_label(self, l);
799 render_max(self, m);
800 render_icon(self, n);
801 render_iconify(self, i);
802 render_desk(self, d);
803 render_close(self, c);
804 }
805
806 if (self->frame.client->decorations & Decor_Handle) {
807 paint(self->handle, (client_focused(self->frame.client) ?
808 self->a_focused_handle :
809 self->a_unfocused_handle),
810 GRIP_WIDTH + self->bwidth, 0,
811 HANDLE_WIDTH(self), s_handle_height);
812 paint(self->lgrip, (client_focused(self->frame.client) ?
813 a_focused_grip :
814 a_unfocused_grip),
815 0, 0, GRIP_WIDTH, s_handle_height);
816 paint(self->rgrip, (client_focused(self->frame.client) ?
817 a_focused_grip :
818 a_unfocused_grip),
819 0, 0, GRIP_WIDTH, s_handle_height);
820 }
821 }
822
823 static void render_label(ObFrame *self, Appearance *a)
824 {
825 if (self->label_x < 0) return;
826
827
828 /* set the texture's text! */
829 a->texture[0].data.text.string = self->frame.client->title;
830 RECT_SET(a->texture[0].position, 0, 0, self->label_width, LABEL_HEIGHT);
831
832 paint(self->label, a, 0, 0, self->label_width, LABEL_HEIGHT);
833 }
834
835 static void render_icon(ObFrame *self, Appearance *a)
836 {
837 if (self->icon_x < 0) return;
838
839 if (self->frame.client->nicons) {
840 Icon *icon = client_icon(self->frame.client, BUTTON_SIZE, BUTTON_SIZE);
841 a->texture[0].type = RGBA;
842 a->texture[0].data.rgba.width = icon->width;
843 a->texture[0].data.rgba.height = icon->height;
844 a->texture[0].data.rgba.data = icon->data;
845 RECT_SET(self->a_icon->texture[0].position, 0, 0,
846 BUTTON_SIZE,BUTTON_SIZE);
847 } else
848 a->texture[0].type = NoTexture;
849
850 paint(self->icon, a, 0, 0, BUTTON_SIZE, BUTTON_SIZE);
851 }
852
853 static void render_max(ObFrame *self, Appearance *a)
854 {
855 if (self->max_x < 0) return;
856
857 RECT_SET(a->texture[0].position, 0, 0, BUTTON_SIZE,BUTTON_SIZE);
858 paint(self->max, a, 0, 0, BUTTON_SIZE, BUTTON_SIZE);
859 }
860
861 static void render_iconify(ObFrame *self, Appearance *a)
862 {
863 if (self->iconify_x < 0) return;
864
865 RECT_SET(a->texture[0].position, 0, 0, BUTTON_SIZE,BUTTON_SIZE);
866 paint(self->iconify, a, 0, 0, BUTTON_SIZE, BUTTON_SIZE);
867 }
868
869 static void render_desk(ObFrame *self, Appearance *a)
870 {
871 if (self->desk_x < 0) return;
872
873 RECT_SET(a->texture[0].position, 0, 0, BUTTON_SIZE,BUTTON_SIZE);
874 paint(self->desk, a, 0, 0, BUTTON_SIZE, BUTTON_SIZE);
875 }
876
877 static void render_close(ObFrame *self, Appearance *a)
878 {
879 if (self->close_x < 0) return;
880
881 RECT_SET(a->texture[0].position, 0, 0, BUTTON_SIZE,BUTTON_SIZE);
882 paint(self->close, a, 0, 0, BUTTON_SIZE, BUTTON_SIZE);
883 }
884
885 GQuark get_context(Client *client, Window win)
886 {
887 ObFrame *self;
888
889 if (win == ob_root) return g_quark_try_string("root");
890 if (client == NULL) return g_quark_try_string("none");
891 if (win == client->window) return g_quark_try_string("client");
892
893 self = (ObFrame*) client->frame;
894 if (win == self->frame.window) return g_quark_try_string("frame");
895 if (win == self->frame.plate) return g_quark_try_string("client");
896 if (win == self->title) return g_quark_try_string("titlebar");
897 if (win == self->label) return g_quark_try_string("titlebar");
898 if (win == self->handle) return g_quark_try_string("handle");
899 if (win == self->lgrip) return g_quark_try_string("blcorner");
900 if (win == self->rgrip) return g_quark_try_string("brcorner");
901 if (win == self->max) return g_quark_try_string("maximize");
902 if (win == self->iconify) return g_quark_try_string("iconify");
903 if (win == self->close) return g_quark_try_string("close");
904 if (win == self->icon) return g_quark_try_string("icon");
905 if (win == self->desk) return g_quark_try_string("alldesktops");
906
907 return g_quark_try_string("none");
908 }
909
910 static void frame_mouse_press(const ObEvent *e, ObFrame *self)
911 {
912 Window win = e->data.x.e->xbutton.window;
913 if (win == self->max) {
914 self->max_press = TRUE;
915 render(self);
916 } else if (win == self->close) {
917 self->close_press = TRUE;
918 render(self);
919 } else if (win == self->iconify) {
920 self->iconify_press = TRUE;
921 render(self);
922 } else if (win == self->desk) {
923 self->desk_press = TRUE;
924 render(self);
925 }
926 }
927
928 static void frame_mouse_release(const ObEvent *e, ObFrame *self)
929 {
930 Window win = e->data.x.e->xbutton.window;
931 if (win == self->max) {
932 self->max_press = FALSE;
933 render(self);
934 } else if (win == self->close) {
935 self->close_press = FALSE;
936 render(self);
937 } else if (win == self->iconify) {
938 self->iconify_press = FALSE;
939 render(self);
940 } else if (win == self->desk) {
941 self->desk_press = FALSE;
942 render(self);
943 }
944 }
This page took 0.081445 seconds and 4 git commands to generate.