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