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_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
;
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
;
76 static void layout_title(ObFrame
*self
);
77 static void mouse_event(const ObEvent
*e
, ObFrame
*self
);
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");
97 /* create the ~/.openbox/themes/openbox dir */
98 path
= g_build_filename(g_get_home_dir(), ".openbox", "themes", "openbox",
100 mkdir(path
, (S_IRUSR
| S_IWUSR
| S_IXUSR
| S_IRGRP
| S_IWGRP
| S_IXGRP
|
101 S_IROTH
| S_IWOTH
| S_IXOTH
));
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
;
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
;
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);
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
);
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
);
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
);
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
);
213 if (ob_s_winfont
!= NULL
) font_close(ob_s_winfont
);
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
);
254 static Window
createWindow(Window parent
, unsigned long mask
,
255 XSetWindowAttributes
*attrib
)
257 return XCreateWindow(ob_display
, parent
, 0, 0, 1, 1, 0,
258 render_depth
, InputOutput
, render_visual
,
265 XSetWindowAttributes attrib
;
269 self
= g_new(ObFrame
, 1);
271 self
->frame
.visible
= FALSE
;
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
);
280 self
->frame
.plate
= createWindow(self
->frame
.window
, mask
, &attrib
);
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
);
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
);
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
);
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
);
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
);
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
);
327 self
->max_press
= self
->close_press
= self
->desk_press
=
328 self
->iconify_press
= FALSE
;
330 dispatch_register(Event_X_ButtonPress
| Event_X_ButtonRelease
,
331 (EventHandler
)mouse_event
, self
);
336 static void frame_free(ObFrame
*self
)
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
);
346 XDestroyWindow(ob_display
, self
->frame
.window
);
348 dispatch_register(0, (EventHandler
)mouse_event
, self
);
353 void frame_show(ObFrame
*self
)
355 if (!self
->frame
.visible
) {
356 self
->frame
.visible
= TRUE
;
357 XMapWindow(ob_display
, self
->frame
.window
);
361 void frame_hide(ObFrame
*self
)
363 if (self
->frame
.visible
) {
364 self
->frame
.visible
= FALSE
;
365 self
->frame
.client
->ignore_unmaps
++;
366 XUnmapWindow(ob_display
, self
->frame
.window
);
370 void frame_adjust_shape(ObFrame
*self
)
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
,
383 /* make the frame's shape match the clients */
384 XShapeCombineShape(ob_display
, self
->frame
.window
, ShapeBounding
,
385 self
->innersize
.left
,
387 self
->frame
.client
->window
,
388 ShapeBounding
, ShapeSet
);
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
+
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
+
409 XShapeCombineRectangles(ob_display
, self
->frame
.window
,
410 ShapeBounding
, 0, 0, xrect
, num
,
411 ShapeUnion
, Unsorted
);
416 void frame_adjust_area(ObFrame
*self
, gboolean moved
, gboolean resized
)
419 if (self
->frame
.client
->decorations
& Decor_Border
) {
420 self
->bwidth
= ob_s_bwidth
;
421 self
->cbwidth
= ob_s_cbwidth
;
423 self
->bwidth
= self
->cbwidth
= 0;
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);
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
);
438 /* position/size and map/unmap all the windows */
440 /* they all default off, they're turned on in layout_title */
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
);
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
);
460 /* layout the title bar elements */
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
|
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
+
481 XMapWindow(ob_display
, self
->handle
);
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
);
488 RECT_SET(self
->a_focused_handle
->area
,
489 GRIP_WIDTH
+ self
->bwidth
, 0,
490 self
->width
- (GRIP_WIDTH
+ self
->bwidth
) * 2,
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
);
497 RECT_SET(self
->a_unfocused_handle
->area
,
498 GRIP_WIDTH
+ self
->bwidth
, 0,
499 self
->width
- (GRIP_WIDTH
+ self
->bwidth
) * 2,
503 XUnmapWindow(ob_display
, self
->handle
);
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);
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
);
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
));
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
);
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
,
547 self
->frame
.area
.height
- self
->bwidth
* 2);
550 obrender_frame(self
);
552 frame_adjust_shape(self
);
556 void frame_adjust_state(ObFrame
*self
)
558 obrender_frame(self
);
561 void frame_adjust_focus(ObFrame
*self
)
563 obrender_frame(self
);
566 void frame_adjust_title(ObFrame
*self
)
568 obrender_frame(self
);
571 void frame_adjust_icon(ObFrame
*self
)
573 obrender_frame(self
);
576 void frame_grab_client(ObFrame
*self
, Client
*client
)
578 self
->frame
.client
= client
;
580 /* reparent the client to the frame */
581 XReparentWindow(ob_display
, client
->window
, self
->frame
.plate
, 0, 0);
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.
590 if (ob_state
== State_Starting
)
591 client
->ignore_unmaps
+= 2;
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
);
597 /* map the client so it maps when the frame does */
598 XMapWindow(ob_display
, client
->window
);
600 frame_adjust_area(self
, TRUE
, TRUE
);
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
);
617 void frame_release_client(ObFrame
*self
, Client
*client
)
621 g_assert(self
->frame
.client
== client
);
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
);
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
,
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
);
654 static void layout_title(ObFrame
*self
)
658 gboolean n
, d
, i
, l
, m
,c
;
661 n
= d
= i
= l
= m
= c
= FALSE
;
663 if (!config_get("titlebar.layout", Config_String
, &layout
)) {
664 layout
.string
= "NDLIMC";
665 config_set("titlebar.layout", Config_String
, layout
);
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
) {
673 if (!(self
->frame
.client
->decorations
& Decor_Icon
)) break;
674 if (n
) { *lc
= ' '; break; } /* rm duplicates */
676 self
->label_width
-= BUTTON_SIZE
+ ob_s_bevel
+ 1;
679 if (!(self
->frame
.client
->decorations
& Decor_AllDesktops
)) break;
680 if (d
) { *lc
= ' '; break; } /* rm duplicates */
682 self
->label_width
-= BUTTON_SIZE
+ ob_s_bevel
+ 1;
685 if (!(self
->frame
.client
->decorations
& Decor_Iconify
)) break;
686 if (i
) { *lc
= ' '; break; } /* rm duplicates */
688 self
->label_width
-= BUTTON_SIZE
+ ob_s_bevel
+ 1;
691 if (l
) { *lc
= ' '; break; } /* rm duplicates */
695 if (!(self
->frame
.client
->decorations
& Decor_Maximize
)) break;
696 if (m
) { *lc
= ' '; break; } /* rm duplicates */
698 self
->label_width
-= BUTTON_SIZE
+ ob_s_bevel
+ 1;
701 if (!(self
->frame
.client
->decorations
& Decor_Close
)) break;
702 if (c
) { *lc
= ' '; break; } /* rm duplicates */
704 self
->label_width
-= BUTTON_SIZE
+ ob_s_bevel
+ 1;
708 if (self
->label_width
< 1) self
->label_width
= 1;
710 XResizeWindow(ob_display
, self
->label
, self
->label_width
,
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
);
721 for (lc
= layout
.string
; *lc
!= '\0'; ++lc
) {
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;
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;
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;
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;
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;
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;
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
);
775 static void mouse_event(const ObEvent
*e
, ObFrame
*self
)
778 gboolean press
= e
->type
== Event_X_ButtonPress
;
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
);
796 GQuark
get_context(Client
*client
, Window win
)
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");
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");
818 return g_quark_try_string("none");