4 #include "../../kernel/openbox.h"
5 #include "../../kernel/extensions.h"
6 #include "../../kernel/dispatch.h"
7 #include "../../kernel/config.h"
10 # include <sys/stat.h>
11 # include <sys/types.h>
16 #define PLATE_EVENTMASK (SubstructureRedirectMask | ButtonPressMask)
17 #define FRAME_EVENTMASK (EnterWindowMask | LeaveWindowMask | \
18 ButtonPressMask | ButtonReleaseMask)
19 #define ELEMENT_EVENTMASK (ButtonPressMask | ButtonReleaseMask | \
20 ButtonMotionMask | ExposureMask)
22 /* style settings - geometry */
24 int ob_s_handle_height;
27 /* style settings - colors */
28 color_rgb *ob_s_b_color;
29 color_rgb *ob_s_cb_focused_color;
30 color_rgb *ob_s_cb_unfocused_color;
31 color_rgb *ob_s_title_focused_color;
32 color_rgb *ob_s_title_unfocused_color;
33 color_rgb *ob_s_titlebut_focused_color;
34 color_rgb *ob_s_titlebut_unfocused_color;
35 /* style settings - fonts */
36 int ob_s_winfont_height;
37 int ob_s_winfont_shadow;
38 int ob_s_winfont_shadow_offset;
39 int ob_s_winfont_shadow_tint;
41 /* style settings - masks */
42 pixmap_mask *ob_s_max_set_mask;
43 pixmap_mask *ob_s_max_unset_mask;
44 pixmap_mask *ob_s_iconify_mask;
45 pixmap_mask *ob_s_desk_set_mask;
46 pixmap_mask *ob_s_desk_unset_mask;
47 pixmap_mask *ob_s_shade_set_mask;
48 pixmap_mask *ob_s_shade_unset_mask;
49 pixmap_mask *ob_s_close_mask;
51 /* global appearances */
52 Appearance *ob_a_focused_unpressed_max;
53 Appearance *ob_a_focused_pressed_max;
54 Appearance *ob_a_focused_pressed_set_max;
55 Appearance *ob_a_unfocused_unpressed_max;
56 Appearance *ob_a_unfocused_pressed_max;
57 Appearance *ob_a_unfocused_pressed_set_max;
58 Appearance *ob_a_focused_unpressed_close;
59 Appearance *ob_a_focused_pressed_close;
60 Appearance *ob_a_unfocused_unpressed_close;
61 Appearance *ob_a_unfocused_pressed_close;
62 Appearance *ob_a_focused_unpressed_desk;
63 Appearance *ob_a_focused_pressed_desk;
64 Appearance *ob_a_focused_pressed_set_desk;
65 Appearance *ob_a_unfocused_unpressed_desk;
66 Appearance *ob_a_unfocused_pressed_desk;
67 Appearance *ob_a_unfocused_pressed_set_desk;
68 Appearance *ob_a_focused_unpressed_shade;
69 Appearance *ob_a_focused_pressed_shade;
70 Appearance *ob_a_focused_pressed_set_shade;
71 Appearance *ob_a_unfocused_unpressed_shade;
72 Appearance *ob_a_unfocused_pressed_shade;
73 Appearance *ob_a_unfocused_pressed_set_shade;
74 Appearance *ob_a_focused_unpressed_iconify;
75 Appearance *ob_a_focused_pressed_iconify;
76 Appearance *ob_a_unfocused_unpressed_iconify;
77 Appearance *ob_a_unfocused_pressed_iconify;
78 Appearance *ob_a_focused_grip;
79 Appearance *ob_a_unfocused_grip;
80 Appearance *ob_a_focused_title;
81 Appearance *ob_a_unfocused_title;
82 Appearance *ob_a_focused_label;
83 Appearance *ob_a_unfocused_label;
84 Appearance *ob_a_icon; /* always parentrelative, so no focused/unfocused */
85 Appearance *ob_a_focused_handle;
86 Appearance *ob_a_unfocused_handle;
88 static void layout_title(ObFrame *self);
89 static void mouse_event(const ObEvent *e, ObFrame *self);
95 /* create the ~/.openbox/themes/openbox dir */
96 path = g_build_filename(g_get_home_dir(), ".openbox", "themes", "openbox",
98 mkdir(path, (S_IRUSR | S_IWUSR | S_IXUSR | S_IRGRP | S_IWGRP | S_IXGRP |
99 S_IROTH | S_IWOTH | S_IXOTH));
102 ob_s_b_color = ob_s_cb_unfocused_color = ob_s_cb_focused_color =
103 ob_s_title_unfocused_color = ob_s_title_focused_color =
104 ob_s_titlebut_unfocused_color = ob_s_titlebut_focused_color = NULL;
106 ob_s_max_set_mask = ob_s_max_unset_mask = NULL;
107 ob_s_desk_set_mask = ob_s_desk_unset_mask = NULL;
108 ob_s_shade_set_mask = ob_s_shade_unset_mask = NULL;
109 ob_s_iconify_mask = ob_s_close_mask = NULL;
111 ob_a_focused_unpressed_max = appearance_new(Surface_Planar, 1);
112 ob_a_focused_pressed_max = appearance_new(Surface_Planar, 1);
113 ob_a_focused_pressed_set_max = appearance_new(Surface_Planar, 1);
114 ob_a_unfocused_unpressed_max = appearance_new(Surface_Planar, 1);
115 ob_a_unfocused_pressed_max = appearance_new(Surface_Planar, 1);
116 ob_a_unfocused_pressed_set_max = appearance_new(Surface_Planar, 1);
117 ob_a_focused_unpressed_close = NULL;
118 ob_a_focused_pressed_close = NULL;
119 ob_a_unfocused_unpressed_close = NULL;
120 ob_a_unfocused_pressed_close = NULL;
121 ob_a_focused_unpressed_desk = NULL;
122 ob_a_focused_pressed_desk = NULL;
123 ob_a_focused_pressed_set_desk = NULL;
124 ob_a_unfocused_unpressed_desk = NULL;
125 ob_a_unfocused_pressed_desk = NULL;
126 ob_a_unfocused_pressed_set_desk = NULL;
127 ob_a_focused_unpressed_shade = NULL;
128 ob_a_focused_pressed_shade = NULL;
129 ob_a_focused_pressed_set_shade = NULL;
130 ob_a_unfocused_unpressed_shade = NULL;
131 ob_a_unfocused_pressed_shade = NULL;
132 ob_a_unfocused_pressed_set_shade = NULL;
133 ob_a_focused_unpressed_iconify = NULL;
134 ob_a_focused_pressed_iconify = NULL;
135 ob_a_unfocused_unpressed_iconify = NULL;
136 ob_a_unfocused_pressed_iconify = NULL;
137 ob_a_focused_grip = appearance_new(Surface_Planar, 0);
138 ob_a_unfocused_grip = appearance_new(Surface_Planar, 0);
139 ob_a_focused_title = appearance_new(Surface_Planar, 0);
140 ob_a_unfocused_title = appearance_new(Surface_Planar, 0);
141 ob_a_focused_label = appearance_new(Surface_Planar, 1);
142 ob_a_unfocused_label = appearance_new(Surface_Planar, 1);
143 ob_a_icon = appearance_new(Surface_Planar, 1);
144 ob_a_focused_handle = appearance_new(Surface_Planar, 0);
145 ob_a_unfocused_handle = appearance_new(Surface_Planar, 0);
147 if (obtheme_load()) {
148 RECT_SET(ob_a_focused_pressed_desk->area, 0, 0,
149 BUTTON_SIZE, BUTTON_SIZE);
150 RECT_SET(ob_a_focused_pressed_set_desk->area, 0, 0,
151 BUTTON_SIZE, BUTTON_SIZE);
152 RECT_SET(ob_a_focused_unpressed_desk->area, 0, 0,
153 BUTTON_SIZE, BUTTON_SIZE);
154 RECT_SET(ob_a_unfocused_pressed_desk->area, 0, 0,
155 BUTTON_SIZE, BUTTON_SIZE);
156 RECT_SET(ob_a_unfocused_pressed_set_desk->area, 0, 0,
157 BUTTON_SIZE, BUTTON_SIZE);
158 RECT_SET(ob_a_unfocused_unpressed_desk->area, 0, 0,
159 BUTTON_SIZE, BUTTON_SIZE);
160 RECT_SET(ob_a_focused_pressed_shade->area, 0, 0,
161 BUTTON_SIZE, BUTTON_SIZE);
162 RECT_SET(ob_a_focused_pressed_set_shade->area, 0, 0,
163 BUTTON_SIZE, BUTTON_SIZE);
164 RECT_SET(ob_a_focused_unpressed_shade->area, 0, 0,
165 BUTTON_SIZE, BUTTON_SIZE);
166 RECT_SET(ob_a_unfocused_pressed_shade->area, 0, 0,
167 BUTTON_SIZE, BUTTON_SIZE);
168 RECT_SET(ob_a_unfocused_pressed_set_shade->area, 0, 0,
169 BUTTON_SIZE, BUTTON_SIZE);
170 RECT_SET(ob_a_unfocused_unpressed_shade->area, 0, 0,
171 BUTTON_SIZE, BUTTON_SIZE);
172 RECT_SET(ob_a_focused_pressed_iconify->area, 0, 0,
173 BUTTON_SIZE, BUTTON_SIZE);
174 RECT_SET(ob_a_focused_unpressed_iconify->area, 0, 0,
175 BUTTON_SIZE, BUTTON_SIZE);
176 RECT_SET(ob_a_unfocused_pressed_iconify->area, 0, 0,
177 BUTTON_SIZE, BUTTON_SIZE);
178 RECT_SET(ob_a_unfocused_unpressed_iconify->area, 0, 0,
179 BUTTON_SIZE, BUTTON_SIZE);
180 RECT_SET(ob_a_unfocused_unpressed_iconify->area, 0, 0,
181 BUTTON_SIZE, BUTTON_SIZE);
182 RECT_SET(ob_a_focused_pressed_max->area, 0, 0,
183 BUTTON_SIZE, BUTTON_SIZE);
184 RECT_SET(ob_a_focused_pressed_set_max->area, 0, 0,
185 BUTTON_SIZE, BUTTON_SIZE);
186 RECT_SET(ob_a_focused_unpressed_max->area, 0, 0,
187 BUTTON_SIZE, BUTTON_SIZE);
188 RECT_SET(ob_a_unfocused_pressed_max->area, 0, 0,
189 BUTTON_SIZE, BUTTON_SIZE);
190 RECT_SET(ob_a_unfocused_pressed_set_max->area, 0, 0,
191 BUTTON_SIZE, BUTTON_SIZE);
192 RECT_SET(ob_a_unfocused_unpressed_max->area, 0, 0,
193 BUTTON_SIZE, BUTTON_SIZE);
194 RECT_SET(ob_a_focused_pressed_close->area, 0, 0,
195 BUTTON_SIZE, BUTTON_SIZE);
196 RECT_SET(ob_a_focused_unpressed_close->area, 0, 0,
197 BUTTON_SIZE, BUTTON_SIZE);
198 RECT_SET(ob_a_unfocused_pressed_close->area, 0, 0,
199 BUTTON_SIZE, BUTTON_SIZE);
200 RECT_SET(ob_a_unfocused_unpressed_close->area, 0, 0,
201 BUTTON_SIZE, BUTTON_SIZE);
203 RECT_SET(ob_a_focused_grip->area, 0, 0,
204 GRIP_WIDTH, ob_s_handle_height);
205 RECT_SET(ob_a_unfocused_grip->area, 0, 0,
206 GRIP_WIDTH, ob_s_handle_height);
214 if (ob_s_b_color != NULL) color_free(ob_s_b_color);
215 if (ob_s_cb_unfocused_color != NULL) color_free(ob_s_cb_unfocused_color);
216 if (ob_s_cb_focused_color != NULL) color_free(ob_s_cb_focused_color);
217 if (ob_s_title_unfocused_color != NULL) color_free(ob_s_title_unfocused_color);
218 if (ob_s_title_focused_color != NULL) color_free(ob_s_title_focused_color);
219 if (ob_s_titlebut_unfocused_color != NULL)
220 color_free(ob_s_titlebut_unfocused_color);
221 if (ob_s_titlebut_focused_color != NULL)
222 color_free(ob_s_titlebut_focused_color);
224 if (ob_s_max_set_mask != NULL)
225 pixmap_mask_free(ob_s_max_set_mask);
226 if (ob_s_max_unset_mask != NULL)
227 pixmap_mask_free(ob_s_max_unset_mask);
228 if (ob_s_desk_set_mask != NULL)
229 pixmap_mask_free(ob_s_desk_set_mask);
230 if (ob_s_desk_unset_mask != NULL)
231 pixmap_mask_free(ob_s_desk_unset_mask);
232 if (ob_s_shade_set_mask != NULL)
233 pixmap_mask_free(ob_s_shade_set_mask);
234 if (ob_s_shade_unset_mask != NULL)
235 pixmap_mask_free(ob_s_shade_unset_mask);
236 if (ob_s_iconify_mask != NULL)
237 pixmap_mask_free(ob_s_iconify_mask);
238 if (ob_s_close_mask != NULL)
239 pixmap_mask_free(ob_s_close_mask);
241 if (ob_s_winfont != NULL) font_close(ob_s_winfont);
243 appearance_free(ob_a_focused_unpressed_max);
244 appearance_free(ob_a_focused_pressed_max);
245 appearance_free(ob_a_focused_pressed_set_max);
246 appearance_free(ob_a_unfocused_unpressed_max);
247 appearance_free(ob_a_unfocused_pressed_max);
248 appearance_free(ob_a_unfocused_pressed_set_max);
249 if (ob_a_focused_unpressed_close != NULL)
250 appearance_free(ob_a_focused_unpressed_close);
251 if (ob_a_focused_pressed_close != NULL)
252 appearance_free(ob_a_focused_pressed_close);
253 if (ob_a_unfocused_unpressed_close != NULL)
254 appearance_free(ob_a_unfocused_unpressed_close);
255 if (ob_a_unfocused_pressed_close != NULL)
256 appearance_free(ob_a_unfocused_pressed_close);
257 if (ob_a_focused_unpressed_desk != NULL)
258 appearance_free(ob_a_focused_unpressed_desk);
259 if (ob_a_focused_pressed_desk != NULL)
260 appearance_free(ob_a_focused_pressed_desk);
261 if (ob_a_unfocused_unpressed_desk != NULL)
262 appearance_free(ob_a_unfocused_unpressed_desk);
263 if (ob_a_unfocused_pressed_desk != NULL)
264 appearance_free(ob_a_unfocused_pressed_desk);
265 if (ob_a_focused_unpressed_shade != NULL)
266 appearance_free(ob_a_focused_unpressed_shade);
267 if (ob_a_focused_pressed_shade != NULL)
268 appearance_free(ob_a_focused_pressed_shade);
269 if (ob_a_unfocused_unpressed_shade != NULL)
270 appearance_free(ob_a_unfocused_unpressed_shade);
271 if (ob_a_unfocused_pressed_shade != NULL)
272 appearance_free(ob_a_unfocused_pressed_shade);
273 if (ob_a_focused_unpressed_iconify != NULL)
274 appearance_free(ob_a_focused_unpressed_iconify);
275 if (ob_a_focused_pressed_iconify != NULL)
276 appearance_free(ob_a_focused_pressed_iconify);
277 if (ob_a_unfocused_unpressed_iconify != NULL)
278 appearance_free(ob_a_unfocused_unpressed_iconify);
279 if (ob_a_unfocused_pressed_iconify != NULL)
280 appearance_free(ob_a_unfocused_pressed_iconify);
281 appearance_free(ob_a_focused_grip);
282 appearance_free(ob_a_unfocused_grip);
283 appearance_free(ob_a_focused_title);
284 appearance_free(ob_a_unfocused_title);
285 appearance_free(ob_a_focused_label);
286 appearance_free(ob_a_unfocused_label);
287 appearance_free(ob_a_icon);
288 appearance_free(ob_a_focused_handle);
289 appearance_free(ob_a_unfocused_handle);
292 static Window createWindow(Window parent, unsigned long mask,
293 XSetWindowAttributes *attrib)
295 return XCreateWindow(ob_display, parent, 0, 0, 1, 1, 0,
296 render_depth, InputOutput, render_visual,
303 XSetWindowAttributes attrib;
307 self = g_new(ObFrame, 1);
309 self->frame.visible = FALSE;
311 /* create all of the decor windows */
312 mask = CWOverrideRedirect | CWEventMask;
313 attrib.event_mask = FRAME_EVENTMASK;
314 attrib.override_redirect = TRUE;
315 self->frame.window = createWindow(ob_root, mask, &attrib);
318 self->frame.plate = createWindow(self->frame.window, mask, &attrib);
321 attrib.event_mask = ELEMENT_EVENTMASK;
322 self->title = createWindow(self->frame.window, mask, &attrib);
323 self->label = createWindow(self->title, mask, &attrib);
324 self->max = createWindow(self->title, mask, &attrib);
325 self->close = createWindow(self->title, mask, &attrib);
326 self->desk = createWindow(self->title, mask, &attrib);
327 self->shade = createWindow(self->title, mask, &attrib);
328 self->icon = createWindow(self->title, mask, &attrib);
329 self->iconify = createWindow(self->title, mask, &attrib);
330 self->handle = createWindow(self->frame.window, mask, &attrib);
332 attrib.cursor = ob_cursors.ll_angle;
333 self->lgrip = createWindow(self->handle, mask, &attrib);
334 attrib.cursor = ob_cursors.lr_angle;
335 self->rgrip = createWindow(self->handle, mask, &attrib);
337 /* the other stuff is shown based on decor settings */
338 XMapWindow(ob_display, self->frame.plate);
339 XMapWindow(ob_display, self->lgrip);
340 XMapWindow(ob_display, self->rgrip);
341 XMapWindow(ob_display, self->label);
343 /* set colors/appearance/sizes for stuff that doesn't change */
344 XSetWindowBorder(ob_display, self->frame.window, ob_s_b_color->pixel);
345 XSetWindowBorder(ob_display, self->label, ob_s_b_color->pixel);
346 XSetWindowBorder(ob_display, self->rgrip, ob_s_b_color->pixel);
347 XSetWindowBorder(ob_display, self->lgrip, ob_s_b_color->pixel);
349 XResizeWindow(ob_display, self->max, BUTTON_SIZE, BUTTON_SIZE);
350 XResizeWindow(ob_display, self->iconify, BUTTON_SIZE, BUTTON_SIZE);
351 XResizeWindow(ob_display, self->icon, BUTTON_SIZE, BUTTON_SIZE);
352 XResizeWindow(ob_display, self->close, BUTTON_SIZE, BUTTON_SIZE);
353 XResizeWindow(ob_display, self->desk, BUTTON_SIZE, BUTTON_SIZE);
354 XResizeWindow(ob_display, self->shade, BUTTON_SIZE, BUTTON_SIZE);
355 XResizeWindow(ob_display, self->lgrip, GRIP_WIDTH, ob_s_handle_height);
356 XResizeWindow(ob_display, self->rgrip, GRIP_WIDTH, ob_s_handle_height);
358 /* set up the dynamic appearances */
359 self->a_unfocused_title = appearance_copy(ob_a_unfocused_title);
360 self->a_focused_title = appearance_copy(ob_a_focused_title);
361 self->a_unfocused_label = appearance_copy(ob_a_unfocused_label);
362 self->a_focused_label = appearance_copy(ob_a_focused_label);
363 self->a_unfocused_handle = appearance_copy(ob_a_unfocused_handle);
364 self->a_focused_handle = appearance_copy(ob_a_focused_handle);
365 self->a_icon = appearance_copy(ob_a_icon);
367 self->max_press = self->close_press = self->desk_press =
368 self->iconify_press = self->shade_press = FALSE;
370 dispatch_register(Event_X_ButtonPress | Event_X_ButtonRelease,
371 (EventHandler)mouse_event, self);
376 static void frame_free(ObFrame *self)
378 appearance_free(self->a_unfocused_title);
379 appearance_free(self->a_focused_title);
380 appearance_free(self->a_unfocused_label);
381 appearance_free(self->a_focused_label);
382 appearance_free(self->a_unfocused_handle);
383 appearance_free(self->a_focused_handle);
384 appearance_free(self->a_icon);
386 XDestroyWindow(ob_display, self->frame.window);
388 dispatch_register(0, (EventHandler)mouse_event, self);
393 void frame_show(ObFrame *self)
395 if (!self->frame.visible) {
396 self->frame.visible = TRUE;
397 XMapWindow(ob_display, self->frame.window);
401 void frame_hide(ObFrame *self)
403 if (self->frame.visible) {
404 self->frame.visible = FALSE;
405 self->frame.client->ignore_unmaps++;
406 XUnmapWindow(ob_display, self->frame.window);
410 void frame_adjust_shape(ObFrame *self)
416 if (!self->frame.client->shaped) {
417 /* clear the shape on the frame window */
418 XShapeCombineMask(ob_display, self->frame.window, ShapeBounding,
419 self->innersize.left,
423 /* make the frame's shape match the clients */
424 XShapeCombineShape(ob_display, self->frame.window, ShapeBounding,
425 self->innersize.left,
427 self->frame.client->window,
428 ShapeBounding, ShapeSet);
431 if (self->frame.client->decorations & Decor_Titlebar) {
432 xrect[0].x = -ob_s_bevel;
433 xrect[0].y = -ob_s_bevel;
434 xrect[0].width = self->width + self->bwidth * 2;
435 xrect[0].height = TITLE_HEIGHT +
440 if (self->frame.client->decorations & Decor_Handle) {
441 xrect[1].x = -ob_s_bevel;
442 xrect[1].y = HANDLE_Y(self);
443 xrect[1].width = self->width + self->bwidth * 2;
444 xrect[1].height = ob_s_handle_height +
449 XShapeCombineRectangles(ob_display, self->frame.window,
450 ShapeBounding, 0, 0, xrect, num,
451 ShapeUnion, Unsorted);
456 void frame_adjust_area(ObFrame *self, gboolean moved, gboolean resized)
459 if (self->frame.client->decorations & Decor_Border) {
460 self->bwidth = ob_s_bwidth;
461 self->cbwidth = ob_s_cbwidth;
463 self->bwidth = self->cbwidth = 0;
465 STRUT_SET(self->innersize, self->cbwidth, self->cbwidth,
466 self->cbwidth, self->cbwidth);
467 self->width = self->frame.client->area.width + self->cbwidth * 2;
468 g_assert(self->width > 0);
470 /* set border widths */
471 XSetWindowBorderWidth(ob_display, self->frame.plate, self->cbwidth);
472 XSetWindowBorderWidth(ob_display, self->frame.window, self->bwidth);
473 XSetWindowBorderWidth(ob_display, self->title, self->bwidth);
474 XSetWindowBorderWidth(ob_display, self->handle, self->bwidth);
475 XSetWindowBorderWidth(ob_display, self->lgrip, self->bwidth);
476 XSetWindowBorderWidth(ob_display, self->rgrip, self->bwidth);
478 /* position/size and map/unmap all the windows */
480 /* they all default off, they're turned on in layout_title */
484 self->iconify_x = -1;
489 if (self->frame.client->decorations & Decor_Titlebar) {
490 XMoveResizeWindow(ob_display, self->title,
491 -self->bwidth, -self->bwidth,
492 self->width, TITLE_HEIGHT);
493 self->innersize.top += TITLE_HEIGHT + self->bwidth;
494 XMapWindow(ob_display, self->title);
496 RECT_SET(self->a_focused_title->area, 0, 0,
497 self->width, TITLE_HEIGHT);
498 RECT_SET(self->a_unfocused_title->area, 0, 0,
499 self->width, TITLE_HEIGHT);
501 /* layout the title bar elements */
504 XUnmapWindow(ob_display, self->title);
506 if (self->frame.client->decorations & Decor_Handle) {
507 XMoveResizeWindow(ob_display, self->handle,
508 -self->bwidth, HANDLE_Y(self),
509 self->width, ob_s_handle_height);
510 XMoveWindow(ob_display, self->lgrip,
511 -self->bwidth, -self->bwidth);
512 XMoveWindow(ob_display, self->rgrip,
513 -self->bwidth + self->width -
514 GRIP_WIDTH, -self->bwidth);
515 self->innersize.bottom += ob_s_handle_height +
517 XMapWindow(ob_display, self->handle);
519 if (ob_a_focused_grip->surface.data.planar.grad ==
520 Background_ParentRelative)
521 RECT_SET(self->a_focused_handle->area, 0, 0,
522 self->width, ob_s_handle_height);
524 RECT_SET(self->a_focused_handle->area,
525 GRIP_WIDTH + self->bwidth, 0,
526 self->width - (GRIP_WIDTH + self->bwidth) * 2,
528 if (ob_a_unfocused_grip->surface.data.planar.grad ==
529 Background_ParentRelative)
530 RECT_SET(self->a_unfocused_handle->area, 0, 0,
531 self->width, ob_s_handle_height);
533 RECT_SET(self->a_unfocused_handle->area,
534 GRIP_WIDTH + self->bwidth, 0,
535 self->width - (GRIP_WIDTH + self->bwidth) * 2,
539 XUnmapWindow(ob_display, self->handle);
543 /* move and resize the plate */
544 XMoveResizeWindow(ob_display, self->frame.plate,
545 self->innersize.left - self->cbwidth,
546 self->innersize.top - self->cbwidth,
547 self->frame.client->area.width,
548 self->frame.client->area.height);
549 /* when the client has StaticGravity, it likes to move around. */
550 XMoveWindow(ob_display, self->frame.client->window, 0, 0);
554 STRUT_SET(self->frame.size,
555 self->innersize.left + self->bwidth,
556 self->innersize.top + self->bwidth,
557 self->innersize.right + self->bwidth,
558 self->innersize.bottom + self->bwidth);
561 /* shading can change without being moved or resized */
562 RECT_SET_SIZE(self->frame.area,
563 self->frame.client->area.width +
564 self->frame.size.left + self->frame.size.right,
565 (self->frame.client->shaded ? TITLE_HEIGHT + self->bwidth*2:
566 self->frame.client->area.height +
567 self->frame.size.top + self->frame.size.bottom));
570 /* find the new coordinates, done after setting the frame.size, for
571 frame_client_gravity. */
572 self->frame.area.x = self->frame.client->area.x;
573 self->frame.area.y = self->frame.client->area.y;
574 frame_client_gravity((Frame*)self,
575 &self->frame.area.x, &self->frame.area.y);
578 /* move and resize the top level frame.
579 shading can change without being moved or resized */
580 XMoveResizeWindow(ob_display, self->frame.window,
581 self->frame.area.x, self->frame.area.y,
583 self->frame.area.height - self->bwidth * 2);
586 obrender_frame(self);
588 frame_adjust_shape(self);
592 void frame_adjust_state(ObFrame *self)
594 obrender_frame(self);
597 void frame_adjust_focus(ObFrame *self)
599 obrender_frame(self);
602 void frame_adjust_title(ObFrame *self)
604 obrender_frame(self);
607 void frame_adjust_icon(ObFrame *self)
609 obrender_frame(self);
612 void frame_grab_client(ObFrame *self, Client *client)
614 self->frame.client = client;
616 /* reparent the client to the frame */
617 XReparentWindow(ob_display, client->window, self->frame.plate, 0, 0);
619 When reparenting the client window, it is usually not mapped yet, since
620 this occurs from a MapRequest. However, in the case where Openbox is
621 starting up, the window is already mapped, so we'll see unmap events for
622 it. There are 2 unmap events generated that we see, one with the 'event'
623 member set the root window, and one set to the client, but both get
624 handled and need to be ignored.
626 if (ob_state == State_Starting)
627 client->ignore_unmaps += 2;
629 /* select the event mask on the client's parent (to receive config/map
630 req's) the ButtonPress is to catch clicks on the client border */
631 XSelectInput(ob_display, self->frame.plate, PLATE_EVENTMASK);
633 /* map the client so it maps when the frame does */
634 XMapWindow(ob_display, client->window);
636 frame_adjust_area(self, TRUE, TRUE);
638 /* set all the windows for the frame in the client_map */
639 g_hash_table_insert(client_map, &self->frame.window, client);
640 g_hash_table_insert(client_map, &self->frame.plate, client);
641 g_hash_table_insert(client_map, &self->title, client);
642 g_hash_table_insert(client_map, &self->label, client);
643 g_hash_table_insert(client_map, &self->max, client);
644 g_hash_table_insert(client_map, &self->close, client);
645 g_hash_table_insert(client_map, &self->desk, client);
646 g_hash_table_insert(client_map, &self->shade, client);
647 g_hash_table_insert(client_map, &self->icon, client);
648 g_hash_table_insert(client_map, &self->iconify, client);
649 g_hash_table_insert(client_map, &self->handle, client);
650 g_hash_table_insert(client_map, &self->lgrip, client);
651 g_hash_table_insert(client_map, &self->rgrip, client);
654 void frame_release_client(ObFrame *self, Client *client)
658 g_assert(self->frame.client == client);
660 /* check if the app has already reparented its window away */
661 if (XCheckTypedWindowEvent(ob_display, client->window,
662 ReparentNotify, &ev)) {
663 XPutBackEvent(ob_display, &ev);
664 /* re-map the window since the unmanaging process unmaps it */
665 XMapWindow(ob_display, client->window);
667 /* according to the ICCCM - if the client doesn't reparent itself,
668 then we will reparent the window to root for them */
669 XReparentWindow(ob_display, client->window, ob_root,
674 /* remove all the windows for the frame from the client_map */
675 g_hash_table_remove(client_map, &self->frame.window);
676 g_hash_table_remove(client_map, &self->frame.plate);
677 g_hash_table_remove(client_map, &self->title);
678 g_hash_table_remove(client_map, &self->label);
679 g_hash_table_remove(client_map, &self->max);
680 g_hash_table_remove(client_map, &self->close);
681 g_hash_table_remove(client_map, &self->desk);
682 g_hash_table_remove(client_map, &self->shade);
683 g_hash_table_remove(client_map, &self->icon);
684 g_hash_table_remove(client_map, &self->iconify);
685 g_hash_table_remove(client_map, &self->handle);
686 g_hash_table_remove(client_map, &self->lgrip);
687 g_hash_table_remove(client_map, &self->rgrip);
692 static void layout_title(ObFrame *self)
696 gboolean n, d, i, l, m, c, s;
699 n = d = i = l = m = c = s = FALSE;
701 if (!config_get("titlebar.layout", Config_String, &layout))
702 g_assert_not_reached();
704 /* figure out whats being shown, and the width of the label */
705 self->label_width = self->width - (ob_s_bevel + 1) * 2;
706 for (lc = layout.string; *lc != '\0'; ++lc) {
709 if (!(self->frame.client->decorations & Decor_Icon)) break;
710 if (n) { *lc = ' '; break; } /* rm duplicates */
712 self->label_width -= BUTTON_SIZE + ob_s_bevel + 1;
715 if (!(self->frame.client->decorations & Decor_AllDesktops)) break;
716 if (d) { *lc = ' '; break; } /* rm duplicates */
718 self->label_width -= BUTTON_SIZE + ob_s_bevel + 1;
721 if (!(self->frame.client->decorations & Decor_Shade)) break;
722 if (s) { *lc = ' '; break; } /* rm duplicates */
724 self->label_width -= BUTTON_SIZE + ob_s_bevel + 1;
727 if (!(self->frame.client->decorations & Decor_Iconify)) break;
728 if (i) { *lc = ' '; break; } /* rm duplicates */
730 self->label_width -= BUTTON_SIZE + ob_s_bevel + 1;
733 if (l) { *lc = ' '; break; } /* rm duplicates */
737 if (!(self->frame.client->decorations & Decor_Maximize)) break;
738 if (m) { *lc = ' '; break; } /* rm duplicates */
740 self->label_width -= BUTTON_SIZE + ob_s_bevel + 1;
743 if (!(self->frame.client->decorations & Decor_Close)) break;
744 if (c) { *lc = ' '; break; } /* rm duplicates */
746 self->label_width -= BUTTON_SIZE + ob_s_bevel + 1;
750 if (self->label_width < 1) self->label_width = 1;
752 XResizeWindow(ob_display, self->label, self->label_width,
755 if (!n) XUnmapWindow(ob_display, self->icon);
756 if (!d) XUnmapWindow(ob_display, self->desk);
757 if (!s) XUnmapWindow(ob_display, self->shade);
758 if (!i) XUnmapWindow(ob_display, self->iconify);
759 if (!l) XUnmapWindow(ob_display, self->label);
760 if (!m) XUnmapWindow(ob_display, self->max);
761 if (!c) XUnmapWindow(ob_display, self->close);
764 for (lc = layout.string; *lc != '\0'; ++lc) {
769 RECT_SET(self->a_icon->area, 0, 0, BUTTON_SIZE, BUTTON_SIZE);
770 XMapWindow(ob_display, self->icon);
771 XMoveWindow(ob_display, self->icon, x, ob_s_bevel + 1);
772 x += BUTTON_SIZE + ob_s_bevel + 1;
777 XMapWindow(ob_display, self->desk);
778 XMoveWindow(ob_display, self->desk, x, ob_s_bevel + 1);
779 x += BUTTON_SIZE + ob_s_bevel + 1;
784 XMapWindow(ob_display, self->shade);
785 XMoveWindow(ob_display, self->shade, x, ob_s_bevel + 1);
786 x += BUTTON_SIZE + ob_s_bevel + 1;
791 XMapWindow(ob_display, self->iconify);
792 XMoveWindow(ob_display, self->iconify, x, ob_s_bevel + 1);
793 x += BUTTON_SIZE + ob_s_bevel + 1;
798 XMapWindow(ob_display, self->label);
799 XMoveWindow(ob_display, self->label, x, ob_s_bevel);
800 x += self->label_width + ob_s_bevel + 1;
805 XMapWindow(ob_display, self->max);
806 XMoveWindow(ob_display, self->max, x, ob_s_bevel + 1);
807 x += BUTTON_SIZE + ob_s_bevel + 1;
812 XMapWindow(ob_display, self->close);
813 XMoveWindow(ob_display, self->close, x, ob_s_bevel + 1);
814 x += BUTTON_SIZE + ob_s_bevel + 1;
819 RECT_SET(self->a_focused_label->area, 0, 0,
820 self->label_width, LABEL_HEIGHT);
821 RECT_SET(self->a_unfocused_label->area, 0, 0,
822 self->label_width, LABEL_HEIGHT);
825 static void mouse_event(const ObEvent *e, ObFrame *self)
828 gboolean press = e->type == Event_X_ButtonPress;
830 win = e->data.x.e->xbutton.window;
831 if (win == self->max) {
832 self->max_press = press;
833 obrender_frame(self);
834 } else if (win == self->close) {
835 self->close_press = press;
836 obrender_frame(self);
837 } else if (win == self->iconify) {
838 self->iconify_press = press;
839 obrender_frame(self);
840 } else if (win == self->desk) {
841 self->desk_press = press;
842 obrender_frame(self);
843 } else if (win == self->shade) {
844 self->shade_press = press;
845 obrender_frame(self);
849 Context get_context(Client *client, Window win)
853 if (win == ob_root) return Context_Root;
854 if (client == NULL) return Context_None;
855 if (win == client->window) return Context_Client;
857 self = (ObFrame*) client->frame;
858 if (win == self->frame.window) return Context_Frame;
859 if (win == self->frame.plate) return Context_Client;
860 if (win == self->title) return Context_Titlebar;
861 if (win == self->label) return Context_Titlebar;
862 if (win == self->handle) return Context_Handle;
863 if (win == self->lgrip) return Context_BLCorner;
864 if (win == self->rgrip) return Context_BRCorner;
865 if (win == self->max) return Context_Maximize;
866 if (win == self->iconify) return Context_Iconify;
867 if (win == self->close) return Context_Close;
868 if (win == self->icon) return Context_Icon;
869 if (win == self->desk) return Context_AllDesktops;
870 if (win == self->shade) return Context_Shade;