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