]> Dogcows Code - chaz/openbox/blob - engines/openbox/obengine.c
f98bb36c526b91a0e839e71cf31669e30138510e
[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 #ifdef HAVE_SYS_STAT_H
10 # include <sys/stat.h>
11 # include <sys/types.h>
12 #endif
13 #include <X11/Xlib.h>
14 #include <glib.h>
15
16 #define PLATE_EVENTMASK (SubstructureRedirectMask | ButtonPressMask)
17 #define FRAME_EVENTMASK (EnterWindowMask | LeaveWindowMask | \
18 ButtonPressMask | ButtonReleaseMask)
19 #define ELEMENT_EVENTMASK (ButtonPressMask | ButtonReleaseMask | \
20 ButtonMotionMask | ExposureMask)
21
22 /* style settings - geometry */
23 int ob_s_bevel;
24 int ob_s_handle_height;
25 int ob_s_bwidth;
26 int ob_s_cbwidth;
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;
40 ObFont *ob_s_winfont;
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;
50
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;
87
88 static void layout_title(ObFrame *self);
89 static void mouse_event(const ObEvent *e, ObFrame *self);
90
91 gboolean startup()
92 {
93 char *path;
94
95 g_quark_from_string("none");
96 g_quark_from_string("root");
97 g_quark_from_string("client");
98 g_quark_from_string("titlebar");
99 g_quark_from_string("handle");
100 g_quark_from_string("frame");
101 g_quark_from_string("blcorner");
102 g_quark_from_string("brcorner");
103 g_quark_from_string("maximize");
104 g_quark_from_string("alldesktops");
105 g_quark_from_string("shade");
106 g_quark_from_string("iconify");
107 g_quark_from_string("icon");
108 g_quark_from_string("close");
109
110 /* create the ~/.openbox/themes/openbox dir */
111 path = g_build_filename(g_get_home_dir(), ".openbox", "themes", "openbox",
112 NULL);
113 mkdir(path, (S_IRUSR | S_IWUSR | S_IXUSR | S_IRGRP | S_IWGRP | S_IXGRP |
114 S_IROTH | S_IWOTH | S_IXOTH));
115 g_free(path);
116
117 ob_s_b_color = ob_s_cb_unfocused_color = ob_s_cb_focused_color =
118 ob_s_title_unfocused_color = ob_s_title_focused_color =
119 ob_s_titlebut_unfocused_color = ob_s_titlebut_focused_color = NULL;
120 ob_s_winfont = NULL;
121 ob_s_max_set_mask = ob_s_max_unset_mask = NULL;
122 ob_s_desk_set_mask = ob_s_desk_unset_mask = NULL;
123 ob_s_shade_set_mask = ob_s_shade_unset_mask = NULL;
124 ob_s_iconify_mask = ob_s_close_mask = NULL;
125
126 ob_a_focused_unpressed_max = appearance_new(Surface_Planar, 1);
127 ob_a_focused_pressed_max = appearance_new(Surface_Planar, 1);
128 ob_a_focused_pressed_set_max = appearance_new(Surface_Planar, 1);
129 ob_a_unfocused_unpressed_max = appearance_new(Surface_Planar, 1);
130 ob_a_unfocused_pressed_max = appearance_new(Surface_Planar, 1);
131 ob_a_unfocused_pressed_set_max = appearance_new(Surface_Planar, 1);
132 ob_a_focused_unpressed_close = NULL;
133 ob_a_focused_pressed_close = NULL;
134 ob_a_unfocused_unpressed_close = NULL;
135 ob_a_unfocused_pressed_close = NULL;
136 ob_a_focused_unpressed_desk = NULL;
137 ob_a_focused_pressed_desk = NULL;
138 ob_a_focused_pressed_set_desk = NULL;
139 ob_a_unfocused_unpressed_desk = NULL;
140 ob_a_unfocused_pressed_desk = NULL;
141 ob_a_unfocused_pressed_set_desk = NULL;
142 ob_a_focused_unpressed_shade = NULL;
143 ob_a_focused_pressed_shade = NULL;
144 ob_a_focused_pressed_set_shade = NULL;
145 ob_a_unfocused_unpressed_shade = NULL;
146 ob_a_unfocused_pressed_shade = NULL;
147 ob_a_unfocused_pressed_set_shade = NULL;
148 ob_a_focused_unpressed_iconify = NULL;
149 ob_a_focused_pressed_iconify = NULL;
150 ob_a_unfocused_unpressed_iconify = NULL;
151 ob_a_unfocused_pressed_iconify = NULL;
152 ob_a_focused_grip = appearance_new(Surface_Planar, 0);
153 ob_a_unfocused_grip = appearance_new(Surface_Planar, 0);
154 ob_a_focused_title = appearance_new(Surface_Planar, 0);
155 ob_a_unfocused_title = appearance_new(Surface_Planar, 0);
156 ob_a_focused_label = appearance_new(Surface_Planar, 1);
157 ob_a_unfocused_label = appearance_new(Surface_Planar, 1);
158 ob_a_icon = appearance_new(Surface_Planar, 1);
159 ob_a_focused_handle = appearance_new(Surface_Planar, 0);
160 ob_a_unfocused_handle = appearance_new(Surface_Planar, 0);
161
162 if (obtheme_load()) {
163 RECT_SET(ob_a_focused_pressed_desk->area, 0, 0,
164 BUTTON_SIZE, BUTTON_SIZE);
165 RECT_SET(ob_a_focused_pressed_set_desk->area, 0, 0,
166 BUTTON_SIZE, BUTTON_SIZE);
167 RECT_SET(ob_a_focused_unpressed_desk->area, 0, 0,
168 BUTTON_SIZE, BUTTON_SIZE);
169 RECT_SET(ob_a_unfocused_pressed_desk->area, 0, 0,
170 BUTTON_SIZE, BUTTON_SIZE);
171 RECT_SET(ob_a_unfocused_pressed_set_desk->area, 0, 0,
172 BUTTON_SIZE, BUTTON_SIZE);
173 RECT_SET(ob_a_unfocused_unpressed_desk->area, 0, 0,
174 BUTTON_SIZE, BUTTON_SIZE);
175 RECT_SET(ob_a_focused_pressed_shade->area, 0, 0,
176 BUTTON_SIZE, BUTTON_SIZE);
177 RECT_SET(ob_a_focused_pressed_set_shade->area, 0, 0,
178 BUTTON_SIZE, BUTTON_SIZE);
179 RECT_SET(ob_a_focused_unpressed_shade->area, 0, 0,
180 BUTTON_SIZE, BUTTON_SIZE);
181 RECT_SET(ob_a_unfocused_pressed_shade->area, 0, 0,
182 BUTTON_SIZE, BUTTON_SIZE);
183 RECT_SET(ob_a_unfocused_pressed_set_shade->area, 0, 0,
184 BUTTON_SIZE, BUTTON_SIZE);
185 RECT_SET(ob_a_unfocused_unpressed_shade->area, 0, 0,
186 BUTTON_SIZE, BUTTON_SIZE);
187 RECT_SET(ob_a_focused_pressed_iconify->area, 0, 0,
188 BUTTON_SIZE, BUTTON_SIZE);
189 RECT_SET(ob_a_focused_unpressed_iconify->area, 0, 0,
190 BUTTON_SIZE, BUTTON_SIZE);
191 RECT_SET(ob_a_unfocused_pressed_iconify->area, 0, 0,
192 BUTTON_SIZE, BUTTON_SIZE);
193 RECT_SET(ob_a_unfocused_unpressed_iconify->area, 0, 0,
194 BUTTON_SIZE, BUTTON_SIZE);
195 RECT_SET(ob_a_unfocused_unpressed_iconify->area, 0, 0,
196 BUTTON_SIZE, BUTTON_SIZE);
197 RECT_SET(ob_a_focused_pressed_max->area, 0, 0,
198 BUTTON_SIZE, BUTTON_SIZE);
199 RECT_SET(ob_a_focused_pressed_set_max->area, 0, 0,
200 BUTTON_SIZE, BUTTON_SIZE);
201 RECT_SET(ob_a_focused_unpressed_max->area, 0, 0,
202 BUTTON_SIZE, BUTTON_SIZE);
203 RECT_SET(ob_a_unfocused_pressed_max->area, 0, 0,
204 BUTTON_SIZE, BUTTON_SIZE);
205 RECT_SET(ob_a_unfocused_pressed_set_max->area, 0, 0,
206 BUTTON_SIZE, BUTTON_SIZE);
207 RECT_SET(ob_a_unfocused_unpressed_max->area, 0, 0,
208 BUTTON_SIZE, BUTTON_SIZE);
209 RECT_SET(ob_a_focused_pressed_close->area, 0, 0,
210 BUTTON_SIZE, BUTTON_SIZE);
211 RECT_SET(ob_a_focused_unpressed_close->area, 0, 0,
212 BUTTON_SIZE, BUTTON_SIZE);
213 RECT_SET(ob_a_unfocused_pressed_close->area, 0, 0,
214 BUTTON_SIZE, BUTTON_SIZE);
215 RECT_SET(ob_a_unfocused_unpressed_close->area, 0, 0,
216 BUTTON_SIZE, BUTTON_SIZE);
217
218 RECT_SET(ob_a_focused_grip->area, 0, 0,
219 GRIP_WIDTH, ob_s_handle_height);
220 RECT_SET(ob_a_unfocused_grip->area, 0, 0,
221 GRIP_WIDTH, ob_s_handle_height);
222 return TRUE;
223 } else
224 return FALSE;
225 }
226
227 void shutdown()
228 {
229 if (ob_s_b_color != NULL) color_free(ob_s_b_color);
230 if (ob_s_cb_unfocused_color != NULL) color_free(ob_s_cb_unfocused_color);
231 if (ob_s_cb_focused_color != NULL) color_free(ob_s_cb_focused_color);
232 if (ob_s_title_unfocused_color != NULL) color_free(ob_s_title_unfocused_color);
233 if (ob_s_title_focused_color != NULL) color_free(ob_s_title_focused_color);
234 if (ob_s_titlebut_unfocused_color != NULL)
235 color_free(ob_s_titlebut_unfocused_color);
236 if (ob_s_titlebut_focused_color != NULL)
237 color_free(ob_s_titlebut_focused_color);
238
239 if (ob_s_max_set_mask != NULL)
240 pixmap_mask_free(ob_s_max_set_mask);
241 if (ob_s_max_unset_mask != NULL)
242 pixmap_mask_free(ob_s_max_unset_mask);
243 if (ob_s_desk_set_mask != NULL)
244 pixmap_mask_free(ob_s_desk_set_mask);
245 if (ob_s_desk_unset_mask != NULL)
246 pixmap_mask_free(ob_s_desk_unset_mask);
247 if (ob_s_shade_set_mask != NULL)
248 pixmap_mask_free(ob_s_shade_set_mask);
249 if (ob_s_shade_unset_mask != NULL)
250 pixmap_mask_free(ob_s_shade_unset_mask);
251 if (ob_s_iconify_mask != NULL)
252 pixmap_mask_free(ob_s_iconify_mask);
253 if (ob_s_close_mask != NULL)
254 pixmap_mask_free(ob_s_close_mask);
255
256 if (ob_s_winfont != NULL) font_close(ob_s_winfont);
257
258 appearance_free(ob_a_focused_unpressed_max);
259 appearance_free(ob_a_focused_pressed_max);
260 appearance_free(ob_a_focused_pressed_set_max);
261 appearance_free(ob_a_unfocused_unpressed_max);
262 appearance_free(ob_a_unfocused_pressed_max);
263 appearance_free(ob_a_unfocused_pressed_set_max);
264 if (ob_a_focused_unpressed_close != NULL)
265 appearance_free(ob_a_focused_unpressed_close);
266 if (ob_a_focused_pressed_close != NULL)
267 appearance_free(ob_a_focused_pressed_close);
268 if (ob_a_unfocused_unpressed_close != NULL)
269 appearance_free(ob_a_unfocused_unpressed_close);
270 if (ob_a_unfocused_pressed_close != NULL)
271 appearance_free(ob_a_unfocused_pressed_close);
272 if (ob_a_focused_unpressed_desk != NULL)
273 appearance_free(ob_a_focused_unpressed_desk);
274 if (ob_a_focused_pressed_desk != NULL)
275 appearance_free(ob_a_focused_pressed_desk);
276 if (ob_a_unfocused_unpressed_desk != NULL)
277 appearance_free(ob_a_unfocused_unpressed_desk);
278 if (ob_a_unfocused_pressed_desk != NULL)
279 appearance_free(ob_a_unfocused_pressed_desk);
280 if (ob_a_focused_unpressed_shade != NULL)
281 appearance_free(ob_a_focused_unpressed_shade);
282 if (ob_a_focused_pressed_shade != NULL)
283 appearance_free(ob_a_focused_pressed_shade);
284 if (ob_a_unfocused_unpressed_shade != NULL)
285 appearance_free(ob_a_unfocused_unpressed_shade);
286 if (ob_a_unfocused_pressed_shade != NULL)
287 appearance_free(ob_a_unfocused_pressed_shade);
288 if (ob_a_focused_unpressed_iconify != NULL)
289 appearance_free(ob_a_focused_unpressed_iconify);
290 if (ob_a_focused_pressed_iconify != NULL)
291 appearance_free(ob_a_focused_pressed_iconify);
292 if (ob_a_unfocused_unpressed_iconify != NULL)
293 appearance_free(ob_a_unfocused_unpressed_iconify);
294 if (ob_a_unfocused_pressed_iconify != NULL)
295 appearance_free(ob_a_unfocused_pressed_iconify);
296 appearance_free(ob_a_focused_grip);
297 appearance_free(ob_a_unfocused_grip);
298 appearance_free(ob_a_focused_title);
299 appearance_free(ob_a_unfocused_title);
300 appearance_free(ob_a_focused_label);
301 appearance_free(ob_a_unfocused_label);
302 appearance_free(ob_a_icon);
303 appearance_free(ob_a_focused_handle);
304 appearance_free(ob_a_unfocused_handle);
305 }
306
307 static Window createWindow(Window parent, unsigned long mask,
308 XSetWindowAttributes *attrib)
309 {
310 return XCreateWindow(ob_display, parent, 0, 0, 1, 1, 0,
311 render_depth, InputOutput, render_visual,
312 mask, attrib);
313
314 }
315
316 Frame *frame_new()
317 {
318 XSetWindowAttributes attrib;
319 unsigned long mask;
320 ObFrame *self;
321
322 self = g_new(ObFrame, 1);
323
324 self->frame.visible = FALSE;
325
326 /* create all of the decor windows */
327 mask = CWOverrideRedirect | CWEventMask;
328 attrib.event_mask = FRAME_EVENTMASK;
329 attrib.override_redirect = TRUE;
330 self->frame.window = createWindow(ob_root, mask, &attrib);
331
332 mask = 0;
333 self->frame.plate = createWindow(self->frame.window, mask, &attrib);
334
335 mask = CWEventMask;
336 attrib.event_mask = ELEMENT_EVENTMASK;
337 self->title = createWindow(self->frame.window, mask, &attrib);
338 self->label = createWindow(self->title, mask, &attrib);
339 self->max = createWindow(self->title, mask, &attrib);
340 self->close = createWindow(self->title, mask, &attrib);
341 self->desk = createWindow(self->title, mask, &attrib);
342 self->shade = createWindow(self->title, mask, &attrib);
343 self->icon = createWindow(self->title, mask, &attrib);
344 self->iconify = createWindow(self->title, mask, &attrib);
345 self->handle = createWindow(self->frame.window, mask, &attrib);
346 mask |= CWCursor;
347 attrib.cursor = ob_cursors.ll_angle;
348 self->lgrip = createWindow(self->handle, mask, &attrib);
349 attrib.cursor = ob_cursors.lr_angle;
350 self->rgrip = createWindow(self->handle, mask, &attrib);
351
352 /* the other stuff is shown based on decor settings */
353 XMapWindow(ob_display, self->frame.plate);
354 XMapWindow(ob_display, self->lgrip);
355 XMapWindow(ob_display, self->rgrip);
356 XMapWindow(ob_display, self->label);
357
358 /* set colors/appearance/sizes for stuff that doesn't change */
359 XSetWindowBorder(ob_display, self->frame.window, ob_s_b_color->pixel);
360 XSetWindowBorder(ob_display, self->label, ob_s_b_color->pixel);
361 XSetWindowBorder(ob_display, self->rgrip, ob_s_b_color->pixel);
362 XSetWindowBorder(ob_display, self->lgrip, ob_s_b_color->pixel);
363
364 XResizeWindow(ob_display, self->max, BUTTON_SIZE, BUTTON_SIZE);
365 XResizeWindow(ob_display, self->iconify, BUTTON_SIZE, BUTTON_SIZE);
366 XResizeWindow(ob_display, self->icon, BUTTON_SIZE, BUTTON_SIZE);
367 XResizeWindow(ob_display, self->close, BUTTON_SIZE, BUTTON_SIZE);
368 XResizeWindow(ob_display, self->desk, BUTTON_SIZE, BUTTON_SIZE);
369 XResizeWindow(ob_display, self->shade, BUTTON_SIZE, BUTTON_SIZE);
370 XResizeWindow(ob_display, self->lgrip, GRIP_WIDTH, ob_s_handle_height);
371 XResizeWindow(ob_display, self->rgrip, GRIP_WIDTH, ob_s_handle_height);
372
373 /* set up the dynamic appearances */
374 self->a_unfocused_title = appearance_copy(ob_a_unfocused_title);
375 self->a_focused_title = appearance_copy(ob_a_focused_title);
376 self->a_unfocused_label = appearance_copy(ob_a_unfocused_label);
377 self->a_focused_label = appearance_copy(ob_a_focused_label);
378 self->a_unfocused_handle = appearance_copy(ob_a_unfocused_handle);
379 self->a_focused_handle = appearance_copy(ob_a_focused_handle);
380 self->a_icon = appearance_copy(ob_a_icon);
381
382 self->max_press = self->close_press = self->desk_press =
383 self->iconify_press = self->shade_press = FALSE;
384
385 dispatch_register(Event_X_ButtonPress | Event_X_ButtonRelease,
386 (EventHandler)mouse_event, self);
387
388 return (Frame*)self;
389 }
390
391 static void frame_free(ObFrame *self)
392 {
393 appearance_free(self->a_unfocused_title);
394 appearance_free(self->a_focused_title);
395 appearance_free(self->a_unfocused_label);
396 appearance_free(self->a_focused_label);
397 appearance_free(self->a_unfocused_handle);
398 appearance_free(self->a_focused_handle);
399 appearance_free(self->a_icon);
400
401 XDestroyWindow(ob_display, self->frame.window);
402
403 dispatch_register(0, (EventHandler)mouse_event, self);
404
405 g_free(self);
406 }
407
408 void frame_show(ObFrame *self)
409 {
410 if (!self->frame.visible) {
411 self->frame.visible = TRUE;
412 XMapWindow(ob_display, self->frame.window);
413 }
414 }
415
416 void frame_hide(ObFrame *self)
417 {
418 if (self->frame.visible) {
419 self->frame.visible = FALSE;
420 self->frame.client->ignore_unmaps++;
421 XUnmapWindow(ob_display, self->frame.window);
422 }
423 }
424
425 void frame_adjust_shape(ObFrame *self)
426 {
427 #ifdef SHAPE
428 int num;
429 XRectangle xrect[2];
430
431 if (!self->frame.client->shaped) {
432 /* clear the shape on the frame window */
433 XShapeCombineMask(ob_display, self->frame.window, ShapeBounding,
434 self->innersize.left,
435 self->innersize.top,
436 None, ShapeSet);
437 } else {
438 /* make the frame's shape match the clients */
439 XShapeCombineShape(ob_display, self->frame.window, ShapeBounding,
440 self->innersize.left,
441 self->innersize.top,
442 self->frame.client->window,
443 ShapeBounding, ShapeSet);
444
445 num = 0;
446 if (self->frame.client->decorations & Decor_Titlebar) {
447 xrect[0].x = -ob_s_bevel;
448 xrect[0].y = -ob_s_bevel;
449 xrect[0].width = self->width + self->bwidth * 2;
450 xrect[0].height = TITLE_HEIGHT +
451 self->bwidth * 2;
452 ++num;
453 }
454
455 if (self->frame.client->decorations & Decor_Handle) {
456 xrect[1].x = -ob_s_bevel;
457 xrect[1].y = HANDLE_Y(self);
458 xrect[1].width = self->width + self->bwidth * 2;
459 xrect[1].height = ob_s_handle_height +
460 self->bwidth * 2;
461 ++num;
462 }
463
464 XShapeCombineRectangles(ob_display, self->frame.window,
465 ShapeBounding, 0, 0, xrect, num,
466 ShapeUnion, Unsorted);
467 }
468 #endif
469 }
470
471 void frame_adjust_area(ObFrame *self, gboolean moved, gboolean resized)
472 {
473 if (resized) {
474 if (self->frame.client->decorations & Decor_Border) {
475 self->bwidth = ob_s_bwidth;
476 self->cbwidth = ob_s_cbwidth;
477 } else {
478 self->bwidth = self->cbwidth = 0;
479 }
480 STRUT_SET(self->innersize, self->cbwidth, self->cbwidth,
481 self->cbwidth, self->cbwidth);
482 self->width = self->frame.client->area.width + self->cbwidth * 2;
483 g_assert(self->width > 0);
484
485 /* set border widths */
486 XSetWindowBorderWidth(ob_display, self->frame.plate, self->cbwidth);
487 XSetWindowBorderWidth(ob_display, self->frame.window, self->bwidth);
488 XSetWindowBorderWidth(ob_display, self->title, self->bwidth);
489 XSetWindowBorderWidth(ob_display, self->handle, self->bwidth);
490 XSetWindowBorderWidth(ob_display, self->lgrip, self->bwidth);
491 XSetWindowBorderWidth(ob_display, self->rgrip, self->bwidth);
492
493 /* position/size and map/unmap all the windows */
494
495 /* they all default off, they're turned on in layout_title */
496 self->icon_x = -1;
497 self->desk_x = -1;
498 self->shade_x = -1;
499 self->iconify_x = -1;
500 self->label_x = -1;
501 self->max_x = -1;
502 self->close_x = -1;
503
504 if (self->frame.client->decorations & Decor_Titlebar) {
505 XMoveResizeWindow(ob_display, self->title,
506 -self->bwidth, -self->bwidth,
507 self->width, TITLE_HEIGHT);
508 self->innersize.top += TITLE_HEIGHT + self->bwidth;
509 XMapWindow(ob_display, self->title);
510
511 RECT_SET(self->a_focused_title->area, 0, 0,
512 self->width, TITLE_HEIGHT);
513 RECT_SET(self->a_unfocused_title->area, 0, 0,
514 self->width, TITLE_HEIGHT);
515
516 /* layout the title bar elements */
517 layout_title(self);
518 } else
519 XUnmapWindow(ob_display, self->title);
520
521 if (self->frame.client->decorations & Decor_Handle) {
522 XMoveResizeWindow(ob_display, self->handle,
523 -self->bwidth, HANDLE_Y(self),
524 self->width, ob_s_handle_height);
525 XMoveWindow(ob_display, self->lgrip,
526 -self->bwidth, -self->bwidth);
527 XMoveWindow(ob_display, self->rgrip,
528 -self->bwidth + self->width -
529 GRIP_WIDTH, -self->bwidth);
530 self->innersize.bottom += ob_s_handle_height +
531 self->bwidth;
532 XMapWindow(ob_display, self->handle);
533
534 if (ob_a_focused_grip->surface.data.planar.grad ==
535 Background_ParentRelative)
536 RECT_SET(self->a_focused_handle->area, 0, 0,
537 self->width, ob_s_handle_height);
538 else
539 RECT_SET(self->a_focused_handle->area,
540 GRIP_WIDTH + self->bwidth, 0,
541 self->width - (GRIP_WIDTH + self->bwidth) * 2,
542 ob_s_handle_height);
543 if (ob_a_unfocused_grip->surface.data.planar.grad ==
544 Background_ParentRelative)
545 RECT_SET(self->a_unfocused_handle->area, 0, 0,
546 self->width, ob_s_handle_height);
547 else
548 RECT_SET(self->a_unfocused_handle->area,
549 GRIP_WIDTH + self->bwidth, 0,
550 self->width - (GRIP_WIDTH + self->bwidth) * 2,
551 ob_s_handle_height);
552
553 } else
554 XUnmapWindow(ob_display, self->handle);
555 }
556
557 if (resized) {
558 /* move and resize the plate */
559 XMoveResizeWindow(ob_display, self->frame.plate,
560 self->innersize.left - self->cbwidth,
561 self->innersize.top - self->cbwidth,
562 self->frame.client->area.width,
563 self->frame.client->area.height);
564 /* when the client has StaticGravity, it likes to move around. */
565 XMoveWindow(ob_display, self->frame.client->window, 0, 0);
566 }
567
568 if (resized) {
569 STRUT_SET(self->frame.size,
570 self->innersize.left + self->bwidth,
571 self->innersize.top + self->bwidth,
572 self->innersize.right + self->bwidth,
573 self->innersize.bottom + self->bwidth);
574 }
575
576 /* shading can change without being moved or resized */
577 RECT_SET_SIZE(self->frame.area,
578 self->frame.client->area.width +
579 self->frame.size.left + self->frame.size.right,
580 (self->frame.client->shaded ? TITLE_HEIGHT + self->bwidth*2:
581 self->frame.client->area.height +
582 self->frame.size.top + self->frame.size.bottom));
583
584 if (moved) {
585 /* find the new coordinates, done after setting the frame.size, for
586 frame_client_gravity. */
587 self->frame.area.x = self->frame.client->area.x;
588 self->frame.area.y = self->frame.client->area.y;
589 frame_client_gravity((Frame*)self,
590 &self->frame.area.x, &self->frame.area.y);
591 }
592
593 /* move and resize the top level frame.
594 shading can change without being moved or resized */
595 XMoveResizeWindow(ob_display, self->frame.window,
596 self->frame.area.x, self->frame.area.y,
597 self->width,
598 self->frame.area.height - self->bwidth * 2);
599
600 if (resized) {
601 obrender_frame(self);
602
603 frame_adjust_shape(self);
604 }
605 }
606
607 void frame_adjust_state(ObFrame *self)
608 {
609 obrender_frame(self);
610 }
611
612 void frame_adjust_focus(ObFrame *self)
613 {
614 obrender_frame(self);
615 }
616
617 void frame_adjust_title(ObFrame *self)
618 {
619 obrender_frame(self);
620 }
621
622 void frame_adjust_icon(ObFrame *self)
623 {
624 obrender_frame(self);
625 }
626
627 void frame_grab_client(ObFrame *self, Client *client)
628 {
629 self->frame.client = client;
630
631 /* reparent the client to the frame */
632 XReparentWindow(ob_display, client->window, self->frame.plate, 0, 0);
633 /*
634 When reparenting the client window, it is usually not mapped yet, since
635 this occurs from a MapRequest. However, in the case where Openbox is
636 starting up, the window is already mapped, so we'll see unmap events for
637 it. There are 2 unmap events generated that we see, one with the 'event'
638 member set the root window, and one set to the client, but both get
639 handled and need to be ignored.
640 */
641 if (ob_state == State_Starting)
642 client->ignore_unmaps += 2;
643
644 /* select the event mask on the client's parent (to receive config/map
645 req's) the ButtonPress is to catch clicks on the client border */
646 XSelectInput(ob_display, self->frame.plate, PLATE_EVENTMASK);
647
648 /* map the client so it maps when the frame does */
649 XMapWindow(ob_display, client->window);
650
651 frame_adjust_area(self, TRUE, TRUE);
652
653 /* set all the windows for the frame in the client_map */
654 g_hash_table_insert(client_map, &self->frame.window, client);
655 g_hash_table_insert(client_map, &self->frame.plate, client);
656 g_hash_table_insert(client_map, &self->title, client);
657 g_hash_table_insert(client_map, &self->label, client);
658 g_hash_table_insert(client_map, &self->max, client);
659 g_hash_table_insert(client_map, &self->close, client);
660 g_hash_table_insert(client_map, &self->desk, client);
661 g_hash_table_insert(client_map, &self->shade, client);
662 g_hash_table_insert(client_map, &self->icon, client);
663 g_hash_table_insert(client_map, &self->iconify, client);
664 g_hash_table_insert(client_map, &self->handle, client);
665 g_hash_table_insert(client_map, &self->lgrip, client);
666 g_hash_table_insert(client_map, &self->rgrip, client);
667 }
668
669 void frame_release_client(ObFrame *self, Client *client)
670 {
671 XEvent ev;
672
673 g_assert(self->frame.client == client);
674
675 /* check if the app has already reparented its window away */
676 if (XCheckTypedWindowEvent(ob_display, client->window,
677 ReparentNotify, &ev)) {
678 XPutBackEvent(ob_display, &ev);
679 /* re-map the window since the unmanaging process unmaps it */
680 XMapWindow(ob_display, client->window);
681 } else {
682 /* according to the ICCCM - if the client doesn't reparent itself,
683 then we will reparent the window to root for them */
684 XReparentWindow(ob_display, client->window, ob_root,
685 client->area.x,
686 client->area.y);
687 }
688
689 /* remove all the windows for the frame from the client_map */
690 g_hash_table_remove(client_map, &self->frame.window);
691 g_hash_table_remove(client_map, &self->frame.plate);
692 g_hash_table_remove(client_map, &self->title);
693 g_hash_table_remove(client_map, &self->label);
694 g_hash_table_remove(client_map, &self->max);
695 g_hash_table_remove(client_map, &self->close);
696 g_hash_table_remove(client_map, &self->desk);
697 g_hash_table_remove(client_map, &self->shade);
698 g_hash_table_remove(client_map, &self->icon);
699 g_hash_table_remove(client_map, &self->iconify);
700 g_hash_table_remove(client_map, &self->handle);
701 g_hash_table_remove(client_map, &self->lgrip);
702 g_hash_table_remove(client_map, &self->rgrip);
703
704 frame_free(self);
705 }
706
707 static void layout_title(ObFrame *self)
708 {
709 char *lc;
710 int x;
711 gboolean n, d, i, l, m, c, s;
712 ConfigValue layout;
713
714 n = d = i = l = m = c = s = FALSE;
715
716 if (!config_get("titlebar.layout", Config_String, &layout))
717 g_assert_not_reached();
718
719 /* figure out whats being shown, and the width of the label */
720 self->label_width = self->width - (ob_s_bevel + 1) * 2;
721 for (lc = layout.string; *lc != '\0'; ++lc) {
722 switch (*lc) {
723 case 'N':
724 if (!(self->frame.client->decorations & Decor_Icon)) break;
725 if (n) { *lc = ' '; break; } /* rm duplicates */
726 n = TRUE;
727 self->label_width -= BUTTON_SIZE + ob_s_bevel + 1;
728 break;
729 case 'D':
730 if (!(self->frame.client->decorations & Decor_AllDesktops)) break;
731 if (d) { *lc = ' '; break; } /* rm duplicates */
732 d = TRUE;
733 self->label_width -= BUTTON_SIZE + ob_s_bevel + 1;
734 break;
735 case 'S':
736 if (!(self->frame.client->decorations & Decor_Shade)) break;
737 if (s) { *lc = ' '; break; } /* rm duplicates */
738 s = TRUE;
739 self->label_width -= BUTTON_SIZE + ob_s_bevel + 1;
740 break;
741 case 'I':
742 if (!(self->frame.client->decorations & Decor_Iconify)) break;
743 if (i) { *lc = ' '; break; } /* rm duplicates */
744 i = TRUE;
745 self->label_width -= BUTTON_SIZE + ob_s_bevel + 1;
746 break;
747 case 'L':
748 if (l) { *lc = ' '; break; } /* rm duplicates */
749 l = TRUE;
750 break;
751 case 'M':
752 if (!(self->frame.client->decorations & Decor_Maximize)) break;
753 if (m) { *lc = ' '; break; } /* rm duplicates */
754 m = TRUE;
755 self->label_width -= BUTTON_SIZE + ob_s_bevel + 1;
756 break;
757 case 'C':
758 if (!(self->frame.client->decorations & Decor_Close)) break;
759 if (c) { *lc = ' '; break; } /* rm duplicates */
760 c = TRUE;
761 self->label_width -= BUTTON_SIZE + ob_s_bevel + 1;
762 break;
763 }
764 }
765 if (self->label_width < 1) self->label_width = 1;
766
767 XResizeWindow(ob_display, self->label, self->label_width,
768 LABEL_HEIGHT);
769
770 if (!n) XUnmapWindow(ob_display, self->icon);
771 if (!d) XUnmapWindow(ob_display, self->desk);
772 if (!s) XUnmapWindow(ob_display, self->shade);
773 if (!i) XUnmapWindow(ob_display, self->iconify);
774 if (!l) XUnmapWindow(ob_display, self->label);
775 if (!m) XUnmapWindow(ob_display, self->max);
776 if (!c) XUnmapWindow(ob_display, self->close);
777
778 x = ob_s_bevel + 1;
779 for (lc = layout.string; *lc != '\0'; ++lc) {
780 switch (*lc) {
781 case 'N':
782 if (!n) break;
783 self->icon_x = x;
784 RECT_SET(self->a_icon->area, 0, 0, BUTTON_SIZE, BUTTON_SIZE);
785 XMapWindow(ob_display, self->icon);
786 XMoveWindow(ob_display, self->icon, x, ob_s_bevel + 1);
787 x += BUTTON_SIZE + ob_s_bevel + 1;
788 break;
789 case 'D':
790 if (!d) break;
791 self->desk_x = x;
792 XMapWindow(ob_display, self->desk);
793 XMoveWindow(ob_display, self->desk, x, ob_s_bevel + 1);
794 x += BUTTON_SIZE + ob_s_bevel + 1;
795 break;
796 case 'S':
797 if (!s) break;
798 self->shade_x = x;
799 XMapWindow(ob_display, self->shade);
800 XMoveWindow(ob_display, self->shade, x, ob_s_bevel + 1);
801 x += BUTTON_SIZE + ob_s_bevel + 1;
802 break;
803 case 'I':
804 if (!i) break;
805 self->iconify_x = x;
806 XMapWindow(ob_display, self->iconify);
807 XMoveWindow(ob_display, self->iconify, x, ob_s_bevel + 1);
808 x += BUTTON_SIZE + ob_s_bevel + 1;
809 break;
810 case 'L':
811 if (!l) break;
812 self->label_x = x;
813 XMapWindow(ob_display, self->label);
814 XMoveWindow(ob_display, self->label, x, ob_s_bevel);
815 x += self->label_width + ob_s_bevel + 1;
816 break;
817 case 'M':
818 if (!m) break;
819 self->max_x = x;
820 XMapWindow(ob_display, self->max);
821 XMoveWindow(ob_display, self->max, x, ob_s_bevel + 1);
822 x += BUTTON_SIZE + ob_s_bevel + 1;
823 break;
824 case 'C':
825 if (!c) break;
826 self->close_x = x;
827 XMapWindow(ob_display, self->close);
828 XMoveWindow(ob_display, self->close, x, ob_s_bevel + 1);
829 x += BUTTON_SIZE + ob_s_bevel + 1;
830 break;
831 }
832 }
833
834 RECT_SET(self->a_focused_label->area, 0, 0,
835 self->label_width, LABEL_HEIGHT);
836 RECT_SET(self->a_unfocused_label->area, 0, 0,
837 self->label_width, LABEL_HEIGHT);
838 }
839
840 static void mouse_event(const ObEvent *e, ObFrame *self)
841 {
842 Window win;
843 gboolean press = e->type == Event_X_ButtonPress;
844
845 win = e->data.x.e->xbutton.window;
846 if (win == self->max) {
847 self->max_press = press;
848 obrender_frame(self);
849 } else if (win == self->close) {
850 self->close_press = press;
851 obrender_frame(self);
852 } else if (win == self->iconify) {
853 self->iconify_press = press;
854 obrender_frame(self);
855 } else if (win == self->desk) {
856 self->desk_press = press;
857 obrender_frame(self);
858 } else if (win == self->shade) {
859 self->shade_press = press;
860 obrender_frame(self);
861 }
862 }
863
864 GQuark get_context(Client *client, Window win)
865 {
866 ObFrame *self;
867
868 if (win == ob_root) return g_quark_try_string("root");
869 if (client == NULL) return g_quark_try_string("none");
870 if (win == client->window) return g_quark_try_string("client");
871
872 self = (ObFrame*) client->frame;
873 if (win == self->frame.window) return g_quark_try_string("frame");
874 if (win == self->frame.plate) return g_quark_try_string("client");
875 if (win == self->title) return g_quark_try_string("titlebar");
876 if (win == self->label) return g_quark_try_string("titlebar");
877 if (win == self->handle) return g_quark_try_string("handle");
878 if (win == self->lgrip) return g_quark_try_string("blcorner");
879 if (win == self->rgrip) return g_quark_try_string("brcorner");
880 if (win == self->max) return g_quark_try_string("maximize");
881 if (win == self->iconify) return g_quark_try_string("iconify");
882 if (win == self->close) return g_quark_try_string("close");
883 if (win == self->icon) return g_quark_try_string("icon");
884 if (win == self->desk) return g_quark_try_string("alldesktops");
885 if (win == self->shade) return g_quark_try_string("shade");
886
887 return g_quark_try_string("none");
888 }
This page took 0.074549 seconds and 3 git commands to generate.