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