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