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