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