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