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