4 #include "../../kernel/openbox.h"
5 #include "../../kernel/extensions.h"
6 #include "../../kernel/dispatch.h"
7 #include "../../kernel/config.h"
10 # include <sys/stat.h>
11 # include <sys/types.h>
16 #define PLATE_EVENTMASK (SubstructureRedirectMask | ButtonPressMask)
17 #define FRAME_EVENTMASK (EnterWindowMask | LeaveWindowMask)
18 #define ELEMENT_EVENTMASK (ButtonPressMask | ButtonReleaseMask | \
19 ButtonMotionMask | ExposureMask)
21 /* style settings - geometry */
23 int ob_s_handle_height
;
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
;
39 /* style settings - masks */
40 pixmap_mask
*ob_s_max_mask
;
41 pixmap_mask
*ob_s_icon_mask
;
42 pixmap_mask
*ob_s_desk_mask
;
43 pixmap_mask
*ob_s_close_mask
;
45 /* global appearances */
46 Appearance
*ob_a_focused_unpressed_max
;
47 Appearance
*ob_a_focused_pressed_max
;
48 Appearance
*ob_a_unfocused_unpressed_max
;
49 Appearance
*ob_a_unfocused_pressed_max
;
50 Appearance
*ob_a_focused_unpressed_close
;
51 Appearance
*ob_a_focused_pressed_close
;
52 Appearance
*ob_a_unfocused_unpressed_close
;
53 Appearance
*ob_a_unfocused_pressed_close
;
54 Appearance
*ob_a_focused_unpressed_desk
;
55 Appearance
*ob_a_focused_pressed_desk
;
56 Appearance
*ob_a_unfocused_unpressed_desk
;
57 Appearance
*ob_a_unfocused_pressed_desk
;
58 Appearance
*ob_a_focused_unpressed_iconify
;
59 Appearance
*ob_a_focused_pressed_iconify
;
60 Appearance
*ob_a_unfocused_unpressed_iconify
;
61 Appearance
*ob_a_unfocused_pressed_iconify
;
62 Appearance
*ob_a_focused_grip
;
63 Appearance
*ob_a_unfocused_grip
;
64 Appearance
*ob_a_focused_title
;
65 Appearance
*ob_a_unfocused_title
;
66 Appearance
*ob_a_focused_label
;
67 Appearance
*ob_a_unfocused_label
;
68 Appearance
*ob_a_icon
; /* always parentrelative, so no focused/unfocused */
69 Appearance
*ob_a_focused_handle
;
70 Appearance
*ob_a_unfocused_handle
;
72 static void layout_title(ObFrame
*self
);
73 static void mouse_event(const ObEvent
*e
, ObFrame
*self
);
79 g_quark_from_string("none");
80 g_quark_from_string("root");
81 g_quark_from_string("client");
82 g_quark_from_string("titlebar");
83 g_quark_from_string("handle");
84 g_quark_from_string("frame");
85 g_quark_from_string("blcorner");
86 g_quark_from_string("brcorner");
87 g_quark_from_string("maximize");
88 g_quark_from_string("alldesktops");
89 g_quark_from_string("iconify");
90 g_quark_from_string("icon");
91 g_quark_from_string("close");
93 /* create the ~/.openbox/themes/openbox dir */
94 path
= g_build_filename(g_get_home_dir(), ".openbox", "themes", "openbox",
96 mkdir(path
, (S_IRUSR
| S_IWUSR
| S_IXUSR
| S_IRGRP
| S_IWGRP
| S_IXGRP
|
97 S_IROTH
| S_IWOTH
| S_IXOTH
));
100 ob_s_b_color
= ob_s_cb_unfocused_color
= ob_s_cb_focused_color
=
101 ob_s_title_unfocused_color
= ob_s_title_focused_color
=
102 ob_s_titlebut_unfocused_color
= ob_s_titlebut_focused_color
= NULL
;
104 ob_s_max_mask
= ob_s_icon_mask
= ob_s_desk_mask
= ob_s_close_mask
= NULL
;
106 ob_a_focused_unpressed_max
= appearance_new(Surface_Planar
, 1);
107 ob_a_focused_pressed_max
= appearance_new(Surface_Planar
, 1);
108 ob_a_unfocused_unpressed_max
= appearance_new(Surface_Planar
, 1);
109 ob_a_unfocused_pressed_max
= appearance_new(Surface_Planar
, 1);
110 ob_a_focused_unpressed_close
= NULL
;
111 ob_a_focused_pressed_close
= NULL
;
112 ob_a_unfocused_unpressed_close
= NULL
;
113 ob_a_unfocused_pressed_close
= NULL
;
114 ob_a_focused_unpressed_desk
= NULL
;
115 ob_a_focused_pressed_desk
= NULL
;
116 ob_a_unfocused_unpressed_desk
= NULL
;
117 ob_a_unfocused_pressed_desk
= NULL
;
118 ob_a_focused_unpressed_iconify
= NULL
;
119 ob_a_focused_pressed_iconify
= NULL
;
120 ob_a_unfocused_unpressed_iconify
= NULL
;
121 ob_a_unfocused_pressed_iconify
= NULL
;
122 ob_a_focused_grip
= appearance_new(Surface_Planar
, 0);
123 ob_a_unfocused_grip
= appearance_new(Surface_Planar
, 0);
124 ob_a_focused_title
= appearance_new(Surface_Planar
, 0);
125 ob_a_unfocused_title
= appearance_new(Surface_Planar
, 0);
126 ob_a_focused_label
= appearance_new(Surface_Planar
, 1);
127 ob_a_unfocused_label
= appearance_new(Surface_Planar
, 1);
128 ob_a_icon
= appearance_new(Surface_Planar
, 1);
129 ob_a_focused_handle
= appearance_new(Surface_Planar
, 0);
130 ob_a_unfocused_handle
= appearance_new(Surface_Planar
, 0);
132 if (obtheme_load()) {
133 RECT_SET(ob_a_focused_pressed_desk
->area
, 0, 0,
134 BUTTON_SIZE
, BUTTON_SIZE
);
135 RECT_SET(ob_a_focused_unpressed_desk
->area
, 0, 0,
136 BUTTON_SIZE
, BUTTON_SIZE
);
137 RECT_SET(ob_a_unfocused_pressed_desk
->area
, 0, 0,
138 BUTTON_SIZE
, BUTTON_SIZE
);
139 RECT_SET(ob_a_unfocused_unpressed_desk
->area
, 0, 0,
140 BUTTON_SIZE
, BUTTON_SIZE
);
141 RECT_SET(ob_a_focused_pressed_iconify
->area
, 0, 0,
142 BUTTON_SIZE
, BUTTON_SIZE
);
143 RECT_SET(ob_a_focused_unpressed_iconify
->area
, 0, 0,
144 BUTTON_SIZE
, BUTTON_SIZE
);
145 RECT_SET(ob_a_unfocused_pressed_iconify
->area
, 0, 0,
146 BUTTON_SIZE
, BUTTON_SIZE
);
147 RECT_SET(ob_a_unfocused_unpressed_iconify
->area
, 0, 0,
148 BUTTON_SIZE
, BUTTON_SIZE
);
149 RECT_SET(ob_a_unfocused_unpressed_iconify
->area
, 0, 0,
150 BUTTON_SIZE
, BUTTON_SIZE
);
151 RECT_SET(ob_a_focused_pressed_max
->area
, 0, 0,
152 BUTTON_SIZE
, BUTTON_SIZE
);
153 RECT_SET(ob_a_focused_unpressed_max
->area
, 0, 0,
154 BUTTON_SIZE
, BUTTON_SIZE
);
155 RECT_SET(ob_a_unfocused_pressed_max
->area
, 0, 0,
156 BUTTON_SIZE
, BUTTON_SIZE
);
157 RECT_SET(ob_a_unfocused_unpressed_max
->area
, 0, 0,
158 BUTTON_SIZE
, BUTTON_SIZE
);
159 RECT_SET(ob_a_focused_pressed_close
->area
, 0, 0,
160 BUTTON_SIZE
, BUTTON_SIZE
);
161 RECT_SET(ob_a_focused_unpressed_close
->area
, 0, 0,
162 BUTTON_SIZE
, BUTTON_SIZE
);
163 RECT_SET(ob_a_unfocused_pressed_close
->area
, 0, 0,
164 BUTTON_SIZE
, BUTTON_SIZE
);
165 RECT_SET(ob_a_unfocused_unpressed_close
->area
, 0, 0,
166 BUTTON_SIZE
, BUTTON_SIZE
);
168 RECT_SET(ob_a_focused_grip
->area
, 0, 0,
169 GRIP_WIDTH
, ob_s_handle_height
);
170 RECT_SET(ob_a_unfocused_grip
->area
, 0, 0,
171 GRIP_WIDTH
, ob_s_handle_height
);
179 if (ob_s_b_color
!= NULL
) color_free(ob_s_b_color
);
180 if (ob_s_cb_unfocused_color
!= NULL
) color_free(ob_s_cb_unfocused_color
);
181 if (ob_s_cb_focused_color
!= NULL
) color_free(ob_s_cb_focused_color
);
182 if (ob_s_title_unfocused_color
!= NULL
) color_free(ob_s_title_unfocused_color
);
183 if (ob_s_title_focused_color
!= NULL
) color_free(ob_s_title_focused_color
);
184 if (ob_s_titlebut_unfocused_color
!= NULL
)
185 color_free(ob_s_titlebut_unfocused_color
);
186 if (ob_s_titlebut_focused_color
!= NULL
)
187 color_free(ob_s_titlebut_focused_color
);
189 if (ob_s_max_mask
!= NULL
) pixmap_mask_free(ob_s_max_mask
);
190 if (ob_s_desk_mask
!= NULL
) pixmap_mask_free(ob_s_desk_mask
);
191 if (ob_s_icon_mask
!= NULL
) pixmap_mask_free(ob_s_icon_mask
);
192 if (ob_s_close_mask
!= NULL
) pixmap_mask_free(ob_s_close_mask
);
194 if (ob_s_winfont
!= NULL
) font_close(ob_s_winfont
);
196 appearance_free(ob_a_focused_unpressed_max
);
197 appearance_free(ob_a_focused_pressed_max
);
198 appearance_free(ob_a_unfocused_unpressed_max
);
199 appearance_free(ob_a_unfocused_pressed_max
);
200 if (ob_a_focused_unpressed_close
!= NULL
)
201 appearance_free(ob_a_focused_unpressed_close
);
202 if (ob_a_focused_pressed_close
!= NULL
)
203 appearance_free(ob_a_focused_pressed_close
);
204 if (ob_a_unfocused_unpressed_close
!= NULL
)
205 appearance_free(ob_a_unfocused_unpressed_close
);
206 if (ob_a_unfocused_pressed_close
!= NULL
)
207 appearance_free(ob_a_unfocused_pressed_close
);
208 if (ob_a_focused_unpressed_desk
!= NULL
)
209 appearance_free(ob_a_focused_unpressed_desk
);
210 if (ob_a_focused_pressed_desk
!= NULL
)
211 appearance_free(ob_a_focused_pressed_desk
);
212 if (ob_a_unfocused_unpressed_desk
!= NULL
)
213 appearance_free(ob_a_unfocused_unpressed_desk
);
214 if (ob_a_unfocused_pressed_desk
!= NULL
)
215 appearance_free(ob_a_unfocused_pressed_desk
);
216 if (ob_a_focused_unpressed_iconify
!= NULL
)
217 appearance_free(ob_a_focused_unpressed_iconify
);
218 if (ob_a_focused_pressed_iconify
!= NULL
)
219 appearance_free(ob_a_focused_pressed_iconify
);
220 if (ob_a_unfocused_unpressed_iconify
!= NULL
)
221 appearance_free(ob_a_unfocused_unpressed_iconify
);
222 if (ob_a_unfocused_pressed_iconify
!= NULL
)
223 appearance_free(ob_a_unfocused_pressed_iconify
);
224 appearance_free(ob_a_focused_grip
);
225 appearance_free(ob_a_unfocused_grip
);
226 appearance_free(ob_a_focused_title
);
227 appearance_free(ob_a_unfocused_title
);
228 appearance_free(ob_a_focused_label
);
229 appearance_free(ob_a_unfocused_label
);
230 appearance_free(ob_a_icon
);
231 appearance_free(ob_a_focused_handle
);
232 appearance_free(ob_a_unfocused_handle
);
235 static Window
createWindow(Window parent
, unsigned long mask
,
236 XSetWindowAttributes
*attrib
)
238 return XCreateWindow(ob_display
, parent
, 0, 0, 1, 1, 0,
239 render_depth
, InputOutput
, render_visual
,
246 XSetWindowAttributes attrib
;
250 self
= g_new(ObFrame
, 1);
252 self
->frame
.visible
= FALSE
;
254 /* create all of the decor windows */
255 mask
= CWOverrideRedirect
| CWEventMask
;
256 attrib
.event_mask
= FRAME_EVENTMASK
;
257 attrib
.override_redirect
= TRUE
;
258 self
->frame
.window
= createWindow(ob_root
, mask
, &attrib
);
261 self
->frame
.plate
= createWindow(self
->frame
.window
, mask
, &attrib
);
264 attrib
.event_mask
= ELEMENT_EVENTMASK
;
265 self
->title
= createWindow(self
->frame
.window
, mask
, &attrib
);
266 self
->label
= createWindow(self
->title
, mask
, &attrib
);
267 self
->max
= createWindow(self
->title
, mask
, &attrib
);
268 self
->close
= createWindow(self
->title
, mask
, &attrib
);
269 self
->desk
= createWindow(self
->title
, mask
, &attrib
);
270 self
->icon
= createWindow(self
->title
, mask
, &attrib
);
271 self
->iconify
= createWindow(self
->title
, mask
, &attrib
);
272 self
->handle
= createWindow(self
->frame
.window
, mask
, &attrib
);
274 attrib
.cursor
= ob_cursors
.ll_angle
;
275 self
->lgrip
= createWindow(self
->handle
, mask
, &attrib
);
276 attrib
.cursor
= ob_cursors
.lr_angle
;
277 self
->rgrip
= createWindow(self
->handle
, mask
, &attrib
);
279 /* the other stuff is shown based on decor settings */
280 XMapWindow(ob_display
, self
->frame
.plate
);
281 XMapWindow(ob_display
, self
->lgrip
);
282 XMapWindow(ob_display
, self
->rgrip
);
283 XMapWindow(ob_display
, self
->label
);
285 /* set colors/appearance/sizes for stuff that doesn't change */
286 XSetWindowBorder(ob_display
, self
->frame
.window
, ob_s_b_color
->pixel
);
287 XSetWindowBorder(ob_display
, self
->label
, ob_s_b_color
->pixel
);
288 XSetWindowBorder(ob_display
, self
->rgrip
, ob_s_b_color
->pixel
);
289 XSetWindowBorder(ob_display
, self
->lgrip
, ob_s_b_color
->pixel
);
291 XResizeWindow(ob_display
, self
->max
, BUTTON_SIZE
, BUTTON_SIZE
);
292 XResizeWindow(ob_display
, self
->iconify
, BUTTON_SIZE
, BUTTON_SIZE
);
293 XResizeWindow(ob_display
, self
->icon
, BUTTON_SIZE
, BUTTON_SIZE
);
294 XResizeWindow(ob_display
, self
->close
, BUTTON_SIZE
, BUTTON_SIZE
);
295 XResizeWindow(ob_display
, self
->desk
, BUTTON_SIZE
, BUTTON_SIZE
);
296 XResizeWindow(ob_display
, self
->lgrip
, GRIP_WIDTH
, ob_s_handle_height
);
297 XResizeWindow(ob_display
, self
->rgrip
, GRIP_WIDTH
, ob_s_handle_height
);
299 /* set up the dynamic appearances */
300 self
->a_unfocused_title
= appearance_copy(ob_a_unfocused_title
);
301 self
->a_focused_title
= appearance_copy(ob_a_focused_title
);
302 self
->a_unfocused_label
= appearance_copy(ob_a_unfocused_label
);
303 self
->a_focused_label
= appearance_copy(ob_a_focused_label
);
304 self
->a_unfocused_handle
= appearance_copy(ob_a_unfocused_handle
);
305 self
->a_focused_handle
= appearance_copy(ob_a_focused_handle
);
306 self
->a_icon
= appearance_copy(ob_a_icon
);
308 self
->max_press
= self
->close_press
= self
->desk_press
=
309 self
->iconify_press
= FALSE
;
311 dispatch_register(Event_X_ButtonPress
| Event_X_ButtonRelease
,
312 (EventHandler
)mouse_event
, self
);
317 static void frame_free(ObFrame
*self
)
319 appearance_free(self
->a_unfocused_title
);
320 appearance_free(self
->a_focused_title
);
321 appearance_free(self
->a_unfocused_label
);
322 appearance_free(self
->a_focused_label
);
323 appearance_free(self
->a_unfocused_handle
);
324 appearance_free(self
->a_focused_handle
);
325 appearance_free(self
->a_icon
);
327 XDestroyWindow(ob_display
, self
->frame
.window
);
329 dispatch_register(0, (EventHandler
)mouse_event
, self
);
334 void frame_show(ObFrame
*self
)
336 if (!self
->frame
.visible
) {
337 self
->frame
.visible
= TRUE
;
338 XMapWindow(ob_display
, self
->frame
.window
);
342 void frame_hide(ObFrame
*self
)
344 if (self
->frame
.visible
) {
345 self
->frame
.visible
= FALSE
;
346 self
->frame
.client
->ignore_unmaps
++;
347 XUnmapWindow(ob_display
, self
->frame
.window
);
351 void frame_adjust_shape(ObFrame
*self
)
357 if (!self
->frame
.client
->shaped
) {
358 /* clear the shape on the frame window */
359 XShapeCombineMask(ob_display
, self
->frame
.window
, ShapeBounding
,
360 self
->innersize
.left
,
364 /* make the frame's shape match the clients */
365 XShapeCombineShape(ob_display
, self
->frame
.window
, ShapeBounding
,
366 self
->innersize
.left
,
368 self
->frame
.client
->window
,
369 ShapeBounding
, ShapeSet
);
372 if (self
->frame
.client
->decorations
& Decor_Titlebar
) {
373 xrect
[0].x
= -ob_s_bevel
;
374 xrect
[0].y
= -ob_s_bevel
;
375 xrect
[0].width
= self
->width
+ self
->bwidth
* 2;
376 xrect
[0].height
= TITLE_HEIGHT
+
381 if (self
->frame
.client
->decorations
& Decor_Handle
) {
382 xrect
[1].x
= -ob_s_bevel
;
383 xrect
[1].y
= HANDLE_Y(self
);
384 xrect
[1].width
= self
->width
+ self
->bwidth
* 2;
385 xrect
[1].height
= ob_s_handle_height
+
390 XShapeCombineRectangles(ob_display
, self
->frame
.window
,
391 ShapeBounding
, 0, 0, xrect
, num
,
392 ShapeUnion
, Unsorted
);
397 void frame_adjust_area(ObFrame
*self
, gboolean moved
, gboolean resized
)
400 if (self
->frame
.client
->decorations
& Decor_Border
) {
401 self
->bwidth
= ob_s_bwidth
;
402 self
->cbwidth
= ob_s_cbwidth
;
404 self
->bwidth
= self
->cbwidth
= 0;
406 STRUT_SET(self
->innersize
, self
->cbwidth
, self
->cbwidth
,
407 self
->cbwidth
, self
->cbwidth
);
408 self
->width
= self
->frame
.client
->area
.width
+ self
->cbwidth
* 2;
409 g_assert(self
->width
> 0);
411 /* set border widths */
412 XSetWindowBorderWidth(ob_display
, self
->frame
.plate
, self
->cbwidth
);
413 XSetWindowBorderWidth(ob_display
, self
->frame
.window
, self
->bwidth
);
414 XSetWindowBorderWidth(ob_display
, self
->title
, self
->bwidth
);
415 XSetWindowBorderWidth(ob_display
, self
->handle
, self
->bwidth
);
416 XSetWindowBorderWidth(ob_display
, self
->lgrip
, self
->bwidth
);
417 XSetWindowBorderWidth(ob_display
, self
->rgrip
, self
->bwidth
);
419 /* position/size and map/unmap all the windows */
421 /* they all default off, they're turned on in layout_title */
429 if (self
->frame
.client
->decorations
& Decor_Titlebar
) {
430 XMoveResizeWindow(ob_display
, self
->title
,
431 -self
->bwidth
, -self
->bwidth
,
432 self
->width
, TITLE_HEIGHT
);
433 self
->innersize
.top
+= TITLE_HEIGHT
+ self
->bwidth
;
434 XMapWindow(ob_display
, self
->title
);
436 RECT_SET(self
->a_focused_title
->area
, 0, 0,
437 self
->width
, TITLE_HEIGHT
);
438 RECT_SET(self
->a_unfocused_title
->area
, 0, 0,
439 self
->width
, TITLE_HEIGHT
);
441 /* layout the title bar elements */
444 XUnmapWindow(ob_display
, self
->title
);
445 /* make all the titlebar stuff not render */
446 self
->frame
.client
->decorations
&= ~(Decor_Icon
| Decor_Iconify
|
447 Decor_Maximize
| Decor_Close
|
451 if (self
->frame
.client
->decorations
& Decor_Handle
) {
452 XMoveResizeWindow(ob_display
, self
->handle
,
453 -self
->bwidth
, HANDLE_Y(self
),
454 self
->width
, ob_s_handle_height
);
455 XMoveWindow(ob_display
, self
->lgrip
,
456 -self
->bwidth
, -self
->bwidth
);
457 XMoveWindow(ob_display
, self
->rgrip
,
458 -self
->bwidth
+ self
->width
-
459 GRIP_WIDTH
, -self
->bwidth
);
460 self
->innersize
.bottom
+= ob_s_handle_height
+
462 XMapWindow(ob_display
, self
->handle
);
464 if (self
->a_focused_handle
->surface
.data
.planar
.grad
==
465 Background_ParentRelative
)
466 RECT_SET(self
->a_focused_handle
->area
, 0, 0,
467 self
->width
, ob_s_handle_height
);
469 RECT_SET(self
->a_focused_handle
->area
,
470 GRIP_WIDTH
+ self
->bwidth
, 0,
471 self
->width
- (GRIP_WIDTH
+ self
->bwidth
) * 2,
473 if (self
->a_unfocused_handle
->surface
.data
.planar
.grad
==
474 Background_ParentRelative
)
475 RECT_SET(self
->a_unfocused_handle
->area
, 0, 0,
476 self
->width
, ob_s_handle_height
);
478 RECT_SET(self
->a_unfocused_handle
->area
,
479 GRIP_WIDTH
+ self
->bwidth
, 0,
480 self
->width
- (GRIP_WIDTH
+ self
->bwidth
) * 2,
484 XUnmapWindow(ob_display
, self
->handle
);
488 /* move and resize the plate */
489 XMoveResizeWindow(ob_display
, self
->frame
.plate
,
490 self
->innersize
.left
- self
->cbwidth
,
491 self
->innersize
.top
- self
->cbwidth
,
492 self
->frame
.client
->area
.width
,
493 self
->frame
.client
->area
.height
);
494 /* when the client has StaticGravity, it likes to move around. */
495 XMoveWindow(ob_display
, self
->frame
.client
->window
, 0, 0);
499 STRUT_SET(self
->frame
.size
,
500 self
->innersize
.left
+ self
->bwidth
,
501 self
->innersize
.top
+ self
->bwidth
,
502 self
->innersize
.right
+ self
->bwidth
,
503 self
->innersize
.bottom
+ self
->bwidth
);
506 /* shading can change without being moved or resized */
507 RECT_SET_SIZE(self
->frame
.area
,
508 self
->frame
.client
->area
.width
+
509 self
->frame
.size
.left
+ self
->frame
.size
.right
,
510 (self
->frame
.client
->shaded
? TITLE_HEIGHT
+ self
->bwidth
*2:
511 self
->frame
.client
->area
.height
+
512 self
->frame
.size
.top
+ self
->frame
.size
.bottom
));
515 /* find the new coordinates, done after setting the frame.size, for
516 frame_client_gravity. */
517 self
->frame
.area
.x
= self
->frame
.client
->area
.x
;
518 self
->frame
.area
.y
= self
->frame
.client
->area
.y
;
519 frame_client_gravity((Frame
*)self
,
520 &self
->frame
.area
.x
, &self
->frame
.area
.y
);
523 /* move and resize the top level frame.
524 shading can change without being moved or resized */
525 XMoveResizeWindow(ob_display
, self
->frame
.window
,
526 self
->frame
.area
.x
, self
->frame
.area
.y
,
528 self
->frame
.area
.height
- self
->bwidth
* 2);
531 obrender_frame(self
);
533 frame_adjust_shape(self
);
537 void frame_adjust_state(ObFrame
*self
)
539 obrender_frame(self
);
542 void frame_adjust_focus(ObFrame
*self
)
544 obrender_frame(self
);
547 void frame_adjust_title(ObFrame
*self
)
549 obrender_frame(self
);
552 void frame_adjust_icon(ObFrame
*self
)
554 obrender_frame(self
);
557 void frame_grab_client(ObFrame
*self
, Client
*client
)
559 self
->frame
.client
= client
;
561 /* reparent the client to the frame */
562 XReparentWindow(ob_display
, client
->window
, self
->frame
.plate
, 0, 0);
564 When reparenting the client window, it is usually not mapped yet, since
565 this occurs from a MapRequest. However, in the case where Openbox is
566 starting up, the window is already mapped, so we'll see unmap events for
567 it. There are 2 unmap events generated that we see, one with the 'event'
568 member set the root window, and one set to the client, but both get
569 handled and need to be ignored.
571 if (ob_state
== State_Starting
)
572 client
->ignore_unmaps
+= 2;
574 /* select the event mask on the client's parent (to receive config/map
575 req's) the ButtonPress is to catch clicks on the client border */
576 XSelectInput(ob_display
, self
->frame
.plate
, PLATE_EVENTMASK
);
578 /* map the client so it maps when the frame does */
579 XMapWindow(ob_display
, client
->window
);
581 frame_adjust_area(self
, TRUE
, TRUE
);
583 /* set all the windows for the frame in the client_map */
584 g_hash_table_insert(client_map
, &self
->frame
.window
, client
);
585 g_hash_table_insert(client_map
, &self
->frame
.plate
, client
);
586 g_hash_table_insert(client_map
, &self
->title
, client
);
587 g_hash_table_insert(client_map
, &self
->label
, client
);
588 g_hash_table_insert(client_map
, &self
->max
, client
);
589 g_hash_table_insert(client_map
, &self
->close
, client
);
590 g_hash_table_insert(client_map
, &self
->desk
, client
);
591 g_hash_table_insert(client_map
, &self
->icon
, client
);
592 g_hash_table_insert(client_map
, &self
->iconify
, client
);
593 g_hash_table_insert(client_map
, &self
->handle
, client
);
594 g_hash_table_insert(client_map
, &self
->lgrip
, client
);
595 g_hash_table_insert(client_map
, &self
->rgrip
, client
);
598 void frame_release_client(ObFrame
*self
, Client
*client
)
602 g_assert(self
->frame
.client
== client
);
604 /* check if the app has already reparented its window away */
605 if (XCheckTypedWindowEvent(ob_display
, client
->window
,
606 ReparentNotify
, &ev
)) {
607 XPutBackEvent(ob_display
, &ev
);
608 /* re-map the window since the unmanaging process unmaps it */
609 XMapWindow(ob_display
, client
->window
);
611 /* according to the ICCCM - if the client doesn't reparent itself,
612 then we will reparent the window to root for them */
613 XReparentWindow(ob_display
, client
->window
, ob_root
,
618 /* remove all the windows for the frame from the client_map */
619 g_hash_table_remove(client_map
, &self
->frame
.window
);
620 g_hash_table_remove(client_map
, &self
->frame
.plate
);
621 g_hash_table_remove(client_map
, &self
->title
);
622 g_hash_table_remove(client_map
, &self
->label
);
623 g_hash_table_remove(client_map
, &self
->max
);
624 g_hash_table_remove(client_map
, &self
->close
);
625 g_hash_table_remove(client_map
, &self
->desk
);
626 g_hash_table_remove(client_map
, &self
->icon
);
627 g_hash_table_remove(client_map
, &self
->iconify
);
628 g_hash_table_remove(client_map
, &self
->handle
);
629 g_hash_table_remove(client_map
, &self
->lgrip
);
630 g_hash_table_remove(client_map
, &self
->rgrip
);
635 static void layout_title(ObFrame
*self
)
639 gboolean n
, d
, i
, l
, m
,c
;
642 n
= d
= i
= l
= m
= c
= FALSE
;
644 if (!config_get("titlebar.layout", Config_String
, &layout
)) {
645 layout
.string
= "NDLIMC";
646 config_set("titlebar.layout", Config_String
, layout
);
649 /* figure out whats being shown, and the width of the label */
650 self
->label_width
= self
->width
- (ob_s_bevel
+ 1) * 2;
651 for (lc
= layout
.string
; *lc
!= '\0'; ++lc
) {
654 if (!(self
->frame
.client
->decorations
& Decor_Icon
)) break;
655 if (n
) { *lc
= ' '; break; } /* rm duplicates */
657 self
->label_width
-= BUTTON_SIZE
+ ob_s_bevel
+ 1;
660 if (!(self
->frame
.client
->decorations
& Decor_AllDesktops
)) break;
661 if (d
) { *lc
= ' '; break; } /* rm duplicates */
663 self
->label_width
-= BUTTON_SIZE
+ ob_s_bevel
+ 1;
666 if (!(self
->frame
.client
->decorations
& Decor_Iconify
)) break;
667 if (i
) { *lc
= ' '; break; } /* rm duplicates */
669 self
->label_width
-= BUTTON_SIZE
+ ob_s_bevel
+ 1;
672 if (l
) { *lc
= ' '; break; } /* rm duplicates */
676 if (!(self
->frame
.client
->decorations
& Decor_Maximize
)) break;
677 if (m
) { *lc
= ' '; break; } /* rm duplicates */
679 self
->label_width
-= BUTTON_SIZE
+ ob_s_bevel
+ 1;
682 if (!(self
->frame
.client
->decorations
& Decor_Close
)) break;
683 if (c
) { *lc
= ' '; break; } /* rm duplicates */
685 self
->label_width
-= BUTTON_SIZE
+ ob_s_bevel
+ 1;
689 if (self
->label_width
< 1) self
->label_width
= 1;
691 XResizeWindow(ob_display
, self
->label
, self
->label_width
,
694 if (!n
) XUnmapWindow(ob_display
, self
->icon
);
695 if (!d
) XUnmapWindow(ob_display
, self
->desk
);
696 if (!i
) XUnmapWindow(ob_display
, self
->iconify
);
697 if (!l
) XUnmapWindow(ob_display
, self
->label
);
698 if (!m
) XUnmapWindow(ob_display
, self
->max
);
699 if (!c
) XUnmapWindow(ob_display
, self
->close
);
702 for (lc
= layout
.string
; *lc
!= '\0'; ++lc
) {
707 RECT_SET(self
->a_icon
->area
, 0, 0, BUTTON_SIZE
, BUTTON_SIZE
);
708 XMapWindow(ob_display
, self
->icon
);
709 XMoveWindow(ob_display
, self
->icon
, x
, ob_s_bevel
+ 1);
710 x
+= BUTTON_SIZE
+ ob_s_bevel
+ 1;
715 XMapWindow(ob_display
, self
->desk
);
716 XMoveWindow(ob_display
, self
->desk
, x
, ob_s_bevel
+ 1);
717 x
+= BUTTON_SIZE
+ ob_s_bevel
+ 1;
722 XMapWindow(ob_display
, self
->iconify
);
723 XMoveWindow(ob_display
, self
->iconify
, x
, ob_s_bevel
+ 1);
724 x
+= BUTTON_SIZE
+ ob_s_bevel
+ 1;
729 XMapWindow(ob_display
, self
->label
);
730 XMoveWindow(ob_display
, self
->label
, x
, ob_s_bevel
);
731 x
+= self
->label_width
+ ob_s_bevel
+ 1;
736 XMapWindow(ob_display
, self
->max
);
737 XMoveWindow(ob_display
, self
->max
, x
, ob_s_bevel
+ 1);
738 x
+= BUTTON_SIZE
+ ob_s_bevel
+ 1;
743 XMapWindow(ob_display
, self
->close
);
744 XMoveWindow(ob_display
, self
->close
, x
, ob_s_bevel
+ 1);
745 x
+= BUTTON_SIZE
+ ob_s_bevel
+ 1;
750 RECT_SET(self
->a_focused_label
->area
, 0, 0,
751 self
->label_width
, LABEL_HEIGHT
);
752 RECT_SET(self
->a_unfocused_label
->area
, 0, 0,
753 self
->label_width
, LABEL_HEIGHT
);
756 static void mouse_event(const ObEvent
*e
, ObFrame
*self
)
759 gboolean press
= e
->type
== Event_X_ButtonPress
;
761 win
= e
->data
.x
.e
->xbutton
.window
;
762 if (win
== self
->max
) {
763 self
->max_press
= press
;
764 obrender_frame(self
);
765 } else if (win
== self
->close
) {
766 self
->close_press
= press
;
767 obrender_frame(self
);
768 } else if (win
== self
->iconify
) {
769 self
->iconify_press
= press
;
770 obrender_frame(self
);
771 } else if (win
== self
->desk
) {
772 self
->desk_press
= press
;
773 obrender_frame(self
);
777 GQuark
get_context(Client
*client
, Window win
)
781 if (win
== ob_root
) return g_quark_try_string("root");
782 if (client
== NULL
) return g_quark_try_string("none");
783 if (win
== client
->window
) return g_quark_try_string("client");
785 self
= (ObFrame
*) client
->frame
;
786 if (win
== self
->frame
.window
) return g_quark_try_string("frame");
787 if (win
== self
->frame
.plate
) return g_quark_try_string("client");
788 if (win
== self
->title
) return g_quark_try_string("titlebar");
789 if (win
== self
->label
) return g_quark_try_string("titlebar");
790 if (win
== self
->handle
) return g_quark_try_string("handle");
791 if (win
== self
->lgrip
) return g_quark_try_string("blcorner");
792 if (win
== self
->rgrip
) return g_quark_try_string("brcorner");
793 if (win
== self
->max
) return g_quark_try_string("maximize");
794 if (win
== self
->iconify
) return g_quark_try_string("iconify");
795 if (win
== self
->close
) return g_quark_try_string("close");
796 if (win
== self
->icon
) return g_quark_try_string("icon");
797 if (win
== self
->desk
) return g_quark_try_string("alldesktops");
799 return g_quark_try_string("none");