2 #include "../../kernel/openbox.h"
3 #include "../../kernel/screen.h"
4 #include "../../kernel/extensions.h"
5 #include "../../kernel/dispatch.h"
6 #include "../../kernel/config.h"
7 #include "../../kernel/frame.h"
8 #include "../../render/render.h"
9 #include "../../render/color.h"
10 #include "../../render/font.h"
11 #include "../../render/mask.h"
16 #define LABEL_HEIGHT (s_winfont_height + 2)
17 #define TITLE_HEIGHT (LABEL_HEIGHT + s_bevel * 2)
18 #define HANDLE_Y(f) (f->innersize.top + f->frame.client->area.height + \
20 #define BUTTON_SIZE (LABEL_HEIGHT - 2)
21 #define GRIP_WIDTH (BUTTON_SIZE * 2)
23 #define PLATE_EVENTMASK (SubstructureRedirectMask | ButtonPressMask)
24 #define FRAME_EVENTMASK (EnterWindowMask | LeaveWindowMask)
25 #define ELEMENT_EVENTMASK (ButtonPressMask | ButtonReleaseMask | \
26 ButtonMotionMask | ExposureMask)
28 /* style settings - geometry */
33 /* style settings - colors */
35 color_rgb
*s_cb_focused_color
;
36 color_rgb
*s_cb_unfocused_color
;
37 color_rgb
*s_title_focused_color
;
38 color_rgb
*s_title_unfocused_color
;
39 color_rgb
*s_titlebut_focused_color
;
40 color_rgb
*s_titlebut_unfocused_color
;
41 /* style settings - fonts */
44 int s_winfont_shadow_offset
;
46 /* style settings - masks */
47 pixmap_mask
*s_max_mask
;
48 pixmap_mask
*s_icon_mask
;
49 pixmap_mask
*s_desk_mask
;
50 pixmap_mask
*s_close_mask
;
52 /* global appearances */
53 Appearance
*a_focused_unpressed_max
;
54 Appearance
*a_focused_pressed_max
;
55 Appearance
*a_unfocused_unpressed_max
;
56 Appearance
*a_unfocused_pressed_max
;
57 Appearance
*a_focused_unpressed_close
;
58 Appearance
*a_focused_pressed_close
;
59 Appearance
*a_unfocused_unpressed_close
;
60 Appearance
*a_unfocused_pressed_close
;
61 Appearance
*a_focused_unpressed_desk
;
62 Appearance
*a_focused_pressed_desk
;
63 Appearance
*a_unfocused_unpressed_desk
;
64 Appearance
*a_unfocused_pressed_desk
;
65 Appearance
*a_focused_unpressed_iconify
;
66 Appearance
*a_focused_pressed_iconify
;
67 Appearance
*a_unfocused_unpressed_iconify
;
68 Appearance
*a_unfocused_pressed_iconify
;
69 Appearance
*a_focused_grip
;
70 Appearance
*a_unfocused_grip
;
71 Appearance
*a_focused_title
;
72 Appearance
*a_unfocused_title
;
73 Appearance
*a_focused_label
;
74 Appearance
*a_unfocused_label
;
75 Appearance
*a_icon
; /* always parentrelative, so no focused/unfocused */
76 Appearance
*a_focused_handle
;
77 Appearance
*a_unfocused_handle
;
79 typedef struct ObFrame
{
93 Appearance
*a_unfocused_title
;
94 Appearance
*a_focused_title
;
95 Appearance
*a_unfocused_label
;
96 Appearance
*a_focused_label
;
98 Appearance
*a_unfocused_handle
;
99 Appearance
*a_focused_handle
;
105 int width
; /* title and handle */
107 int icon_x
; /* x-position of the window icon button */
108 int label_x
; /* x-position of the window title */
109 int iconify_x
; /* x-position of the window iconify button */
110 int desk_x
; /* x-position of the window all-desktops button */
111 int max_x
; /* x-position of the window maximize button */
112 int close_x
; /* x-position of the window close button */
113 int bwidth
; /* border width */
114 int cbwidth
; /* client border width */
117 gboolean close_press
;
119 gboolean iconify_press
;
122 static void layout_title(ObFrame
*self
);
123 static void render(ObFrame
*self
);
124 static void render_label(ObFrame
*self
, Appearance
*a
);
125 static void render_max(ObFrame
*self
, Appearance
*a
);
126 static void render_icon(ObFrame
*self
, Appearance
*a
);
127 static void render_iconify(ObFrame
*self
, Appearance
*a
);
128 static void render_desk(ObFrame
*self
, Appearance
*a
);
129 static void render_close(ObFrame
*self
, Appearance
*a
);
131 static void frame_mouse_press(const ObEvent
*e
, ObFrame
*self
);
132 static void frame_mouse_release(const ObEvent
*e
, ObFrame
*self
);
136 g_quark_from_string("none");
137 g_quark_from_string("root");
138 g_quark_from_string("client");
139 g_quark_from_string("titlebar");
140 g_quark_from_string("handle");
141 g_quark_from_string("frame");
142 g_quark_from_string("blcorner");
143 g_quark_from_string("brcorner");
144 g_quark_from_string("maximize");
145 g_quark_from_string("alldesktops");
146 g_quark_from_string("iconify");
147 g_quark_from_string("icon");
148 g_quark_from_string("close");
150 s_b_color
= s_cb_unfocused_color
= s_cb_focused_color
=
151 s_title_unfocused_color
= s_title_focused_color
=
152 s_titlebut_unfocused_color
= s_titlebut_focused_color
= NULL
;
154 s_max_mask
= s_icon_mask
= s_desk_mask
= s_close_mask
= NULL
;
156 a_focused_unpressed_max
= appearance_new(Surface_Planar
, 1);
157 a_focused_pressed_max
= appearance_new(Surface_Planar
, 1);
158 a_unfocused_unpressed_max
= appearance_new(Surface_Planar
, 1);
159 a_unfocused_pressed_max
= appearance_new(Surface_Planar
, 1);
160 a_focused_unpressed_close
= NULL
;
161 a_focused_pressed_close
= NULL
;
162 a_unfocused_unpressed_close
= NULL
;
163 a_unfocused_pressed_close
= NULL
;
164 a_focused_unpressed_desk
= NULL
;
165 a_focused_pressed_desk
= NULL
;
166 a_unfocused_unpressed_desk
= NULL
;
167 a_unfocused_pressed_desk
= NULL
;
168 a_focused_unpressed_iconify
= NULL
;
169 a_focused_pressed_iconify
= NULL
;
170 a_unfocused_unpressed_iconify
= NULL
;
171 a_unfocused_pressed_iconify
= NULL
;
172 a_focused_grip
= appearance_new(Surface_Planar
, 0);
173 a_unfocused_grip
= appearance_new(Surface_Planar
, 0);
174 a_focused_title
= appearance_new(Surface_Planar
, 0);
175 a_unfocused_title
= appearance_new(Surface_Planar
, 0);
176 a_focused_label
= appearance_new(Surface_Planar
, 1);
177 a_unfocused_label
= appearance_new(Surface_Planar
, 1);
178 a_icon
= appearance_new(Surface_Planar
, 1);
179 a_focused_handle
= appearance_new(Surface_Planar
, 0);
180 a_unfocused_handle
= appearance_new(Surface_Planar
, 0);
183 RECT_SET(a_focused_pressed_desk
->area
, 0, 0,
184 BUTTON_SIZE
, BUTTON_SIZE
);
185 RECT_SET(a_focused_unpressed_desk
->area
, 0, 0,
186 BUTTON_SIZE
, BUTTON_SIZE
);
187 RECT_SET(a_unfocused_pressed_desk
->area
, 0, 0,
188 BUTTON_SIZE
, BUTTON_SIZE
);
189 RECT_SET(a_unfocused_unpressed_desk
->area
, 0, 0,
190 BUTTON_SIZE
, BUTTON_SIZE
);
191 RECT_SET(a_focused_pressed_iconify
->area
, 0, 0,
192 BUTTON_SIZE
, BUTTON_SIZE
);
193 RECT_SET(a_focused_unpressed_iconify
->area
, 0, 0,
194 BUTTON_SIZE
, BUTTON_SIZE
);
195 RECT_SET(a_unfocused_pressed_iconify
->area
, 0, 0,
196 BUTTON_SIZE
, BUTTON_SIZE
);
197 RECT_SET(a_unfocused_unpressed_iconify
->area
, 0, 0,
198 BUTTON_SIZE
, BUTTON_SIZE
);
199 RECT_SET(a_unfocused_unpressed_iconify
->area
, 0, 0,
200 BUTTON_SIZE
, BUTTON_SIZE
);
201 RECT_SET(a_focused_pressed_max
->area
, 0, 0,
202 BUTTON_SIZE
, BUTTON_SIZE
);
203 RECT_SET(a_focused_unpressed_max
->area
, 0, 0,
204 BUTTON_SIZE
, BUTTON_SIZE
);
205 RECT_SET(a_unfocused_pressed_max
->area
, 0, 0,
206 BUTTON_SIZE
, BUTTON_SIZE
);
207 RECT_SET(a_unfocused_unpressed_max
->area
, 0, 0,
208 BUTTON_SIZE
, BUTTON_SIZE
);
209 RECT_SET(a_focused_pressed_close
->area
, 0, 0,
210 BUTTON_SIZE
, BUTTON_SIZE
);
211 RECT_SET(a_focused_unpressed_close
->area
, 0, 0,
212 BUTTON_SIZE
, BUTTON_SIZE
);
213 RECT_SET(a_unfocused_pressed_close
->area
, 0, 0,
214 BUTTON_SIZE
, BUTTON_SIZE
);
215 RECT_SET(a_unfocused_unpressed_close
->area
, 0, 0,
216 BUTTON_SIZE
, BUTTON_SIZE
);
218 RECT_SET(a_focused_grip
->area
, 0, 0, GRIP_WIDTH
, s_handle_height
);
219 RECT_SET(a_unfocused_grip
->area
, 0, 0, GRIP_WIDTH
, s_handle_height
);
227 if (s_b_color
!= NULL
) color_free(s_b_color
);
228 if (s_cb_unfocused_color
!= NULL
) color_free(s_cb_unfocused_color
);
229 if (s_cb_focused_color
!= NULL
) color_free(s_cb_focused_color
);
230 if (s_title_unfocused_color
!= NULL
) color_free(s_title_unfocused_color
);
231 if (s_title_focused_color
!= NULL
) color_free(s_title_focused_color
);
232 if (s_titlebut_unfocused_color
!= NULL
)
233 color_free(s_titlebut_unfocused_color
);
234 if (s_titlebut_focused_color
!= NULL
)
235 color_free(s_titlebut_focused_color
);
237 if (s_max_mask
!= NULL
) pixmap_mask_free(s_max_mask
);
238 if (s_desk_mask
!= NULL
) pixmap_mask_free(s_desk_mask
);
239 if (s_icon_mask
!= NULL
) pixmap_mask_free(s_icon_mask
);
240 if (s_close_mask
!= NULL
) pixmap_mask_free(s_close_mask
);
242 if (s_winfont
!= NULL
) font_close(s_winfont
);
244 appearance_free(a_focused_unpressed_max
);
245 appearance_free(a_focused_pressed_max
);
246 appearance_free(a_unfocused_unpressed_max
);
247 appearance_free(a_unfocused_pressed_max
);
248 if (a_focused_unpressed_close
!= NULL
)
249 appearance_free(a_focused_unpressed_close
);
250 if (a_focused_pressed_close
!= NULL
)
251 appearance_free(a_focused_pressed_close
);
252 if (a_unfocused_unpressed_close
!= NULL
)
253 appearance_free(a_unfocused_unpressed_close
);
254 if (a_unfocused_pressed_close
!= NULL
)
255 appearance_free(a_unfocused_pressed_close
);
256 if (a_focused_unpressed_desk
!= NULL
)
257 appearance_free(a_focused_unpressed_desk
);
258 if (a_focused_pressed_desk
!= NULL
)
259 appearance_free(a_focused_pressed_desk
);
260 if (a_unfocused_unpressed_desk
!= NULL
)
261 appearance_free(a_unfocused_unpressed_desk
);
262 if (a_unfocused_pressed_desk
!= NULL
)
263 appearance_free(a_unfocused_pressed_desk
);
264 if (a_focused_unpressed_iconify
!= NULL
)
265 appearance_free(a_focused_unpressed_iconify
);
266 if (a_focused_pressed_iconify
!= NULL
)
267 appearance_free(a_focused_pressed_iconify
);
268 if (a_unfocused_unpressed_iconify
!= NULL
)
269 appearance_free(a_unfocused_unpressed_iconify
);
270 if (a_unfocused_pressed_iconify
!= NULL
)
271 appearance_free(a_unfocused_pressed_iconify
);
272 appearance_free(a_focused_grip
);
273 appearance_free(a_unfocused_grip
);
274 appearance_free(a_focused_title
);
275 appearance_free(a_unfocused_title
);
276 appearance_free(a_focused_label
);
277 appearance_free(a_unfocused_label
);
278 appearance_free(a_icon
);
279 appearance_free(a_focused_handle
);
280 appearance_free(a_unfocused_handle
);
283 static Window
createWindow(Window parent
, unsigned long mask
,
284 XSetWindowAttributes
*attrib
)
286 return XCreateWindow(ob_display
, parent
, 0, 0, 1, 1, 0,
287 render_depth
, InputOutput
, render_visual
,
294 XSetWindowAttributes attrib
;
298 self
= g_new(ObFrame
, 1);
300 self
->frame
.visible
= FALSE
;
302 /* create all of the decor windows */
303 mask
= CWOverrideRedirect
| CWEventMask
;
304 attrib
.event_mask
= FRAME_EVENTMASK
;
305 attrib
.override_redirect
= TRUE
;
306 self
->frame
.window
= createWindow(ob_root
, mask
, &attrib
);
309 self
->frame
.plate
= createWindow(self
->frame
.window
, mask
, &attrib
);
312 attrib
.event_mask
= ELEMENT_EVENTMASK
;
313 self
->title
= createWindow(self
->frame
.window
, mask
, &attrib
);
314 self
->label
= createWindow(self
->title
, mask
, &attrib
);
315 self
->max
= createWindow(self
->title
, mask
, &attrib
);
316 self
->close
= createWindow(self
->title
, mask
, &attrib
);
317 self
->desk
= createWindow(self
->title
, mask
, &attrib
);
318 self
->icon
= createWindow(self
->title
, mask
, &attrib
);
319 self
->iconify
= createWindow(self
->title
, mask
, &attrib
);
320 self
->handle
= createWindow(self
->frame
.window
, mask
, &attrib
);
322 attrib
.cursor
= ob_cursors
.ll_angle
;
323 self
->lgrip
= createWindow(self
->handle
, mask
, &attrib
);
324 attrib
.cursor
= ob_cursors
.lr_angle
;
325 self
->rgrip
= createWindow(self
->handle
, mask
, &attrib
);
327 /* the other stuff is shown based on decor settings */
328 XMapWindow(ob_display
, self
->frame
.plate
);
329 XMapWindow(ob_display
, self
->lgrip
);
330 XMapWindow(ob_display
, self
->rgrip
);
331 XMapWindow(ob_display
, self
->label
);
333 /* set colors/appearance/sizes for stuff that doesn't change */
334 XSetWindowBorder(ob_display
, self
->frame
.window
, s_b_color
->pixel
);
335 XSetWindowBorder(ob_display
, self
->label
, s_b_color
->pixel
);
336 XSetWindowBorder(ob_display
, self
->rgrip
, s_b_color
->pixel
);
337 XSetWindowBorder(ob_display
, self
->lgrip
, s_b_color
->pixel
);
339 XResizeWindow(ob_display
, self
->max
, BUTTON_SIZE
, BUTTON_SIZE
);
340 XResizeWindow(ob_display
, self
->iconify
, BUTTON_SIZE
, BUTTON_SIZE
);
341 XResizeWindow(ob_display
, self
->icon
, BUTTON_SIZE
, BUTTON_SIZE
);
342 XResizeWindow(ob_display
, self
->close
, BUTTON_SIZE
, BUTTON_SIZE
);
343 XResizeWindow(ob_display
, self
->desk
, BUTTON_SIZE
, BUTTON_SIZE
);
344 XResizeWindow(ob_display
, self
->lgrip
, GRIP_WIDTH
, s_handle_height
);
345 XResizeWindow(ob_display
, self
->rgrip
, GRIP_WIDTH
, s_handle_height
);
347 /* set up the dynamic appearances */
348 self
->a_unfocused_title
= appearance_copy(a_unfocused_title
);
349 self
->a_focused_title
= appearance_copy(a_focused_title
);
350 self
->a_unfocused_label
= appearance_copy(a_unfocused_label
);
351 self
->a_focused_label
= appearance_copy(a_focused_label
);
352 self
->a_unfocused_handle
= appearance_copy(a_unfocused_handle
);
353 self
->a_focused_handle
= appearance_copy(a_focused_handle
);
354 self
->a_icon
= appearance_copy(a_icon
);
356 self
->max_press
= self
->close_press
= self
->desk_press
=
357 self
->iconify_press
= FALSE
;
359 dispatch_register(Event_X_ButtonPress
, (EventHandler
)frame_mouse_press
,
361 dispatch_register(Event_X_ButtonRelease
, (EventHandler
)frame_mouse_release
,
367 static void frame_free(ObFrame
*self
)
369 appearance_free(self
->a_unfocused_title
);
370 appearance_free(self
->a_focused_title
);
371 appearance_free(self
->a_unfocused_label
);
372 appearance_free(self
->a_focused_label
);
373 appearance_free(self
->a_unfocused_handle
);
374 appearance_free(self
->a_focused_handle
);
375 appearance_free(self
->a_icon
);
377 XDestroyWindow(ob_display
, self
->frame
.window
);
379 dispatch_register(0, (EventHandler
)frame_mouse_press
, self
);
380 dispatch_register(0, (EventHandler
)frame_mouse_release
, self
);
385 void frame_show(ObFrame
*self
)
387 if (!self
->frame
.visible
) {
388 self
->frame
.visible
= TRUE
;
389 XMapWindow(ob_display
, self
->frame
.window
);
393 void frame_hide(ObFrame
*self
)
395 if (self
->frame
.visible
) {
396 self
->frame
.visible
= FALSE
;
397 self
->frame
.client
->ignore_unmaps
++;
398 XUnmapWindow(ob_display
, self
->frame
.window
);
402 void frame_adjust_shape(ObFrame
*self
)
408 if (!self
->frame
.client
->shaped
) {
409 /* clear the shape on the frame window */
410 XShapeCombineMask(ob_display
, self
->frame
.window
, ShapeBounding
,
411 self
->innersize
.left
,
415 /* make the frame's shape match the clients */
416 XShapeCombineShape(ob_display
, self
->frame
.window
, ShapeBounding
,
417 self
->innersize
.left
,
419 self
->frame
.client
->window
,
420 ShapeBounding
, ShapeSet
);
423 if (self
->frame
.client
->decorations
& Decor_Titlebar
) {
424 xrect
[0].x
= -s_bevel
;
425 xrect
[0].y
= -s_bevel
;
426 xrect
[0].width
= self
->width
+ self
->bwidth
* 2;
427 xrect
[0].height
= TITLE_HEIGHT
+
432 if (self
->frame
.client
->decorations
& Decor_Handle
) {
433 xrect
[1].x
= -s_bevel
;
434 xrect
[1].y
= HANDLE_Y(self
);
435 xrect
[1].width
= self
->width
+ self
->bwidth
* 2;
436 xrect
[1].height
= s_handle_height
+
441 XShapeCombineRectangles(ob_display
, self
->frame
.window
,
442 ShapeBounding
, 0, 0, xrect
, num
,
443 ShapeUnion
, Unsorted
);
448 void frame_adjust_area(ObFrame
*self
, gboolean moved
, gboolean resized
)
451 if (self
->frame
.client
->decorations
& Decor_Border
) {
452 self
->bwidth
= s_bwidth
;
453 self
->cbwidth
= s_cbwidth
;
455 self
->bwidth
= self
->cbwidth
= 0;
457 STRUT_SET(self
->innersize
, self
->cbwidth
, self
->cbwidth
,
458 self
->cbwidth
, self
->cbwidth
);
459 self
->width
= self
->frame
.client
->area
.width
+ self
->cbwidth
* 2;
460 g_assert(self
->width
> 0);
462 /* set border widths */
463 XSetWindowBorderWidth(ob_display
, self
->frame
.plate
, self
->cbwidth
);
464 XSetWindowBorderWidth(ob_display
, self
->frame
.window
, self
->bwidth
);
465 XSetWindowBorderWidth(ob_display
, self
->title
, self
->bwidth
);
466 XSetWindowBorderWidth(ob_display
, self
->handle
, self
->bwidth
);
467 XSetWindowBorderWidth(ob_display
, self
->lgrip
, self
->bwidth
);
468 XSetWindowBorderWidth(ob_display
, self
->rgrip
, self
->bwidth
);
470 /* position/size and map/unmap all the windows */
472 /* they all default off, they're turned on in layout_title */
480 if (self
->frame
.client
->decorations
& Decor_Titlebar
) {
481 XMoveResizeWindow(ob_display
, self
->title
,
482 -self
->bwidth
, -self
->bwidth
,
483 self
->width
, TITLE_HEIGHT
);
484 self
->innersize
.top
+= TITLE_HEIGHT
+ self
->bwidth
;
485 XMapWindow(ob_display
, self
->title
);
487 RECT_SET(self
->a_focused_title
->area
, 0, 0,
488 self
->width
, TITLE_HEIGHT
);
489 RECT_SET(self
->a_unfocused_title
->area
, 0, 0,
490 self
->width
, TITLE_HEIGHT
);
492 /* layout the title bar elements */
495 XUnmapWindow(ob_display
, self
->title
);
496 /* make all the titlebar stuff not render */
497 self
->frame
.client
->decorations
&= ~(Decor_Icon
| Decor_Iconify
|
498 Decor_Maximize
| Decor_Close
|
502 if (self
->frame
.client
->decorations
& Decor_Handle
) {
503 XMoveResizeWindow(ob_display
, self
->handle
,
504 -self
->bwidth
, HANDLE_Y(self
),
505 self
->width
, s_handle_height
);
506 XMoveWindow(ob_display
, self
->lgrip
,
507 -self
->bwidth
, -self
->bwidth
);
508 XMoveWindow(ob_display
, self
->rgrip
,
509 -self
->bwidth
+ self
->width
-
510 GRIP_WIDTH
, -self
->bwidth
);
511 self
->innersize
.bottom
+= s_handle_height
+
513 XMapWindow(ob_display
, self
->handle
);
515 if (self
->a_focused_handle
->surface
.data
.planar
.grad
==
516 Background_ParentRelative
)
517 RECT_SET(self
->a_focused_handle
->area
, 0, 0,
518 self
->width
, s_handle_height
);
520 RECT_SET(self
->a_focused_handle
->area
,
521 GRIP_WIDTH
+ self
->bwidth
, 0,
522 self
->width
- (GRIP_WIDTH
+ self
->bwidth
) * 2,
524 if (self
->a_unfocused_handle
->surface
.data
.planar
.grad
==
525 Background_ParentRelative
)
526 RECT_SET(self
->a_unfocused_handle
->area
, 0, 0,
527 self
->width
, s_handle_height
);
529 RECT_SET(self
->a_unfocused_handle
->area
,
530 GRIP_WIDTH
+ self
->bwidth
, 0,
531 self
->width
- (GRIP_WIDTH
+ self
->bwidth
) * 2,
535 XUnmapWindow(ob_display
, self
->handle
);
539 /* move and resize the plate */
540 XMoveResizeWindow(ob_display
, self
->frame
.plate
,
541 self
->innersize
.left
- self
->cbwidth
,
542 self
->innersize
.top
- self
->cbwidth
,
543 self
->frame
.client
->area
.width
,
544 self
->frame
.client
->area
.height
);
545 /* when the client has StaticGravity, it likes to move around. */
546 XMoveWindow(ob_display
, self
->frame
.client
->window
, 0, 0);
550 STRUT_SET(self
->frame
.size
,
551 self
->innersize
.left
+ self
->bwidth
,
552 self
->innersize
.top
+ self
->bwidth
,
553 self
->innersize
.right
+ self
->bwidth
,
554 self
->innersize
.bottom
+ self
->bwidth
);
557 /* shading can change without being moved or resized */
558 RECT_SET_SIZE(self
->frame
.area
,
559 self
->frame
.client
->area
.width
+
560 self
->frame
.size
.left
+ self
->frame
.size
.right
,
561 (self
->frame
.client
->shaded
? TITLE_HEIGHT
+ self
->bwidth
*2:
562 self
->frame
.client
->area
.height
+
563 self
->frame
.size
.top
+ self
->frame
.size
.bottom
));
566 /* find the new coordinates, done after setting the frame.size, for
567 frame_client_gravity. */
568 self
->frame
.area
.x
= self
->frame
.client
->area
.x
;
569 self
->frame
.area
.y
= self
->frame
.client
->area
.y
;
570 frame_client_gravity((Frame
*)self
,
571 &self
->frame
.area
.x
, &self
->frame
.area
.y
);
574 /* move and resize the top level frame.
575 shading can change without being moved or resized */
576 XMoveResizeWindow(ob_display
, self
->frame
.window
,
577 self
->frame
.area
.x
, self
->frame
.area
.y
,
579 self
->frame
.area
.height
- self
->bwidth
* 2);
584 frame_adjust_shape(self
);
588 void frame_adjust_state(ObFrame
*self
)
593 void frame_adjust_focus(ObFrame
*self
)
598 void frame_adjust_title(ObFrame
*self
)
603 void frame_adjust_icon(ObFrame
*self
)
608 void frame_grab_client(ObFrame
*self
, Client
*client
)
610 self
->frame
.client
= client
;
612 /* reparent the client to the frame */
613 XReparentWindow(ob_display
, client
->window
, self
->frame
.plate
, 0, 0);
615 When reparenting the client window, it is usually not mapped yet, since
616 this occurs from a MapRequest. However, in the case where Openbox is
617 starting up, the window is already mapped, so we'll see unmap events for
618 it. There are 2 unmap events generated that we see, one with the 'event'
619 member set the root window, and one set to the client, but both get
620 handled and need to be ignored.
622 if (ob_state
== State_Starting
)
623 client
->ignore_unmaps
+= 2;
625 /* select the event mask on the client's parent (to receive config/map
626 req's) the ButtonPress is to catch clicks on the client border */
627 XSelectInput(ob_display
, self
->frame
.plate
, PLATE_EVENTMASK
);
629 /* map the client so it maps when the frame does */
630 XMapWindow(ob_display
, client
->window
);
632 frame_adjust_area(self
, TRUE
, TRUE
);
634 /* set all the windows for the frame in the client_map */
635 g_hash_table_insert(client_map
, &self
->frame
.window
, client
);
636 g_hash_table_insert(client_map
, &self
->frame
.plate
, client
);
637 g_hash_table_insert(client_map
, &self
->title
, client
);
638 g_hash_table_insert(client_map
, &self
->label
, client
);
639 g_hash_table_insert(client_map
, &self
->max
, client
);
640 g_hash_table_insert(client_map
, &self
->close
, client
);
641 g_hash_table_insert(client_map
, &self
->desk
, client
);
642 g_hash_table_insert(client_map
, &self
->icon
, client
);
643 g_hash_table_insert(client_map
, &self
->iconify
, client
);
644 g_hash_table_insert(client_map
, &self
->handle
, client
);
645 g_hash_table_insert(client_map
, &self
->lgrip
, client
);
646 g_hash_table_insert(client_map
, &self
->rgrip
, client
);
649 void frame_release_client(ObFrame
*self
, Client
*client
)
653 g_assert(self
->frame
.client
== client
);
655 /* check if the app has already reparented its window away */
656 if (XCheckTypedWindowEvent(ob_display
, client
->window
,
657 ReparentNotify
, &ev
)) {
658 XPutBackEvent(ob_display
, &ev
);
659 /* re-map the window since the unmanaging process unmaps it */
660 XMapWindow(ob_display
, client
->window
);
662 /* according to the ICCCM - if the client doesn't reparent itself,
663 then we will reparent the window to root for them */
664 XReparentWindow(ob_display
, client
->window
, ob_root
,
669 /* remove all the windows for the frame from the client_map */
670 g_hash_table_remove(client_map
, &self
->frame
.window
);
671 g_hash_table_remove(client_map
, &self
->frame
.plate
);
672 g_hash_table_remove(client_map
, &self
->title
);
673 g_hash_table_remove(client_map
, &self
->label
);
674 g_hash_table_remove(client_map
, &self
->max
);
675 g_hash_table_remove(client_map
, &self
->close
);
676 g_hash_table_remove(client_map
, &self
->desk
);
677 g_hash_table_remove(client_map
, &self
->icon
);
678 g_hash_table_remove(client_map
, &self
->iconify
);
679 g_hash_table_remove(client_map
, &self
->handle
);
680 g_hash_table_remove(client_map
, &self
->lgrip
);
681 g_hash_table_remove(client_map
, &self
->rgrip
);
686 static void layout_title(ObFrame
*self
)
690 gboolean n
, d
, i
, l
, m
,c
;
693 n
= d
= i
= l
= m
= c
= FALSE
;
695 if (!config_get("titlebar.layout", Config_String
, &layout
)) {
696 layout
.string
= "NDLIMC";
697 config_set("titlebar.layout", Config_String
, layout
);
700 /* figure out whats being shown, and the width of the label */
701 self
->label_width
= self
->width
- (s_bevel
+ 1) * 2;
702 for (lc
= layout
.string
; *lc
!= '\0'; ++lc
) {
705 if (!(self
->frame
.client
->decorations
& Decor_Icon
)) break;
706 if (n
) { *lc
= ' '; break; } /* rm duplicates */
708 self
->label_width
-= BUTTON_SIZE
+ s_bevel
+ 1;
711 if (!(self
->frame
.client
->decorations
& Decor_AllDesktops
)) break;
712 if (d
) { *lc
= ' '; break; } /* rm duplicates */
714 self
->label_width
-= BUTTON_SIZE
+ s_bevel
+ 1;
717 if (!(self
->frame
.client
->decorations
& Decor_Iconify
)) break;
718 if (i
) { *lc
= ' '; break; } /* rm duplicates */
720 self
->label_width
-= BUTTON_SIZE
+ s_bevel
+ 1;
723 if (l
) { *lc
= ' '; break; } /* rm duplicates */
727 if (!(self
->frame
.client
->decorations
& Decor_Maximize
)) break;
728 if (m
) { *lc
= ' '; break; } /* rm duplicates */
730 self
->label_width
-= BUTTON_SIZE
+ s_bevel
+ 1;
733 if (!(self
->frame
.client
->decorations
& Decor_Close
)) break;
734 if (c
) { *lc
= ' '; break; } /* rm duplicates */
736 self
->label_width
-= BUTTON_SIZE
+ s_bevel
+ 1;
740 if (self
->label_width
< 1) self
->label_width
= 1;
742 XResizeWindow(ob_display
, self
->label
, self
->label_width
,
745 if (!n
) XUnmapWindow(ob_display
, self
->icon
);
746 if (!d
) XUnmapWindow(ob_display
, self
->desk
);
747 if (!i
) XUnmapWindow(ob_display
, self
->iconify
);
748 if (!l
) XUnmapWindow(ob_display
, self
->label
);
749 if (!m
) XUnmapWindow(ob_display
, self
->max
);
750 if (!c
) XUnmapWindow(ob_display
, self
->close
);
753 for (lc
= layout
.string
; *lc
!= '\0'; ++lc
) {
758 RECT_SET(self
->a_icon
->area
, 0, 0, BUTTON_SIZE
, BUTTON_SIZE
);
759 XMapWindow(ob_display
, self
->icon
);
760 XMoveWindow(ob_display
, self
->icon
, x
, s_bevel
+ 1);
761 x
+= BUTTON_SIZE
+ s_bevel
+ 1;
766 XMapWindow(ob_display
, self
->desk
);
767 XMoveWindow(ob_display
, self
->desk
, x
, s_bevel
+ 1);
768 x
+= BUTTON_SIZE
+ s_bevel
+ 1;
773 XMapWindow(ob_display
, self
->iconify
);
774 XMoveWindow(ob_display
, self
->iconify
, x
, s_bevel
+ 1);
775 x
+= BUTTON_SIZE
+ s_bevel
+ 1;
780 XMapWindow(ob_display
, self
->label
);
781 XMoveWindow(ob_display
, self
->label
, x
, s_bevel
);
782 x
+= self
->label_width
+ s_bevel
+ 1;
787 XMapWindow(ob_display
, self
->max
);
788 XMoveWindow(ob_display
, self
->max
, x
, s_bevel
+ 1);
789 x
+= BUTTON_SIZE
+ s_bevel
+ 1;
794 XMapWindow(ob_display
, self
->close
);
795 XMoveWindow(ob_display
, self
->close
, x
, s_bevel
+ 1);
796 x
+= BUTTON_SIZE
+ s_bevel
+ 1;
801 RECT_SET(self
->a_focused_label
->area
, 0, 0,
802 self
->label_width
, LABEL_HEIGHT
);
803 RECT_SET(self
->a_unfocused_label
->area
, 0, 0,
804 self
->label_width
, LABEL_HEIGHT
);
807 static void render(ObFrame
*self
)
809 if (client_focused(self
->frame
.client
)) {
810 XSetWindowBorder(ob_display
, self
->frame
.plate
,
811 s_cb_focused_color
->pixel
);
813 XSetWindowBorder(ob_display
, self
->frame
.plate
,
814 s_cb_unfocused_color
->pixel
);
817 if (self
->frame
.client
->decorations
& Decor_Titlebar
) {
818 Appearance
*t
, *l
, *m
, *n
, *i
, *d
, *c
;
820 t
= (client_focused(self
->frame
.client
) ?
821 self
->a_focused_title
: self
->a_unfocused_title
);
822 l
= (client_focused(self
->frame
.client
) ?
823 self
->a_focused_label
: self
->a_unfocused_label
);
824 m
= (client_focused(self
->frame
.client
) ?
826 self
->frame
.client
->max_vert
|| self
->frame
.client
->max_horz
) ?
827 a_focused_pressed_max
: a_focused_unpressed_max
) :
829 self
->frame
.client
->max_vert
|| self
->frame
.client
->max_horz
) ?
830 a_unfocused_pressed_max
: a_unfocused_unpressed_max
));
832 i
= (client_focused(self
->frame
.client
) ?
833 (self
->iconify_press
?
834 a_focused_pressed_iconify
: a_focused_unpressed_iconify
) :
835 (self
->iconify_press
?
836 a_unfocused_pressed_iconify
: a_unfocused_unpressed_iconify
));
837 d
= (client_focused(self
->frame
.client
) ?
838 (self
->desk_press
|| self
->frame
.client
->desktop
== DESKTOP_ALL
?
839 a_focused_pressed_desk
: a_focused_unpressed_desk
) :
840 (self
->desk_press
|| self
->frame
.client
->desktop
== DESKTOP_ALL
?
841 a_unfocused_pressed_desk
: a_unfocused_unpressed_desk
));
842 c
= (client_focused(self
->frame
.client
) ?
844 a_focused_pressed_close
: a_focused_unpressed_close
) :
846 a_unfocused_pressed_close
: a_unfocused_unpressed_close
));
848 paint(self
->title
, t
);
850 /* set parents for any parent relative guys */
851 l
->surface
.data
.planar
.parent
= t
;
852 l
->surface
.data
.planar
.parentx
= self
->label_x
;
853 l
->surface
.data
.planar
.parenty
= s_bevel
;
855 m
->surface
.data
.planar
.parent
= t
;
856 m
->surface
.data
.planar
.parentx
= self
->max_x
;
857 m
->surface
.data
.planar
.parenty
= s_bevel
+ 1;
859 n
->surface
.data
.planar
.parent
= t
;
860 n
->surface
.data
.planar
.parentx
= self
->icon_x
;
861 n
->surface
.data
.planar
.parenty
= s_bevel
+ 1;
863 i
->surface
.data
.planar
.parent
= t
;
864 i
->surface
.data
.planar
.parentx
= self
->iconify_x
;
865 i
->surface
.data
.planar
.parenty
= s_bevel
+ 1;
867 d
->surface
.data
.planar
.parent
= t
;
868 d
->surface
.data
.planar
.parentx
= self
->desk_x
;
869 d
->surface
.data
.planar
.parenty
= s_bevel
+ 1;
871 c
->surface
.data
.planar
.parent
= t
;
872 c
->surface
.data
.planar
.parentx
= self
->close_x
;
873 c
->surface
.data
.planar
.parenty
= s_bevel
+ 1;
875 render_label(self
, l
);
877 render_icon(self
, n
);
878 render_iconify(self
, i
);
879 render_desk(self
, d
);
880 render_close(self
, c
);
883 if (self
->frame
.client
->decorations
& Decor_Handle
) {
886 h
= (client_focused(self
->frame
.client
) ?
887 self
->a_focused_handle
: self
->a_unfocused_handle
);
888 g
= (client_focused(self
->frame
.client
) ?
889 a_focused_grip
: a_unfocused_grip
);
891 if (g
->surface
.data
.planar
.grad
== Background_ParentRelative
) {
892 g
->surface
.data
.planar
.parent
= h
;
893 paint(self
->handle
, h
);
895 paint(self
->handle
, h
);
897 g
->surface
.data
.planar
.parentx
= 0;
898 g
->surface
.data
.planar
.parenty
= 0;
900 paint(self
->lgrip
, g
);
902 g
->surface
.data
.planar
.parentx
= self
->width
- GRIP_WIDTH
;
903 g
->surface
.data
.planar
.parenty
= 0;
905 paint(self
->rgrip
, g
);
909 static void render_label(ObFrame
*self
, Appearance
*a
)
911 if (self
->label_x
< 0) return;
914 /* set the texture's text! */
915 a
->texture
[0].data
.text
.string
= self
->frame
.client
->title
;
916 RECT_SET(a
->texture
[0].position
, 0, 0, self
->label_width
, LABEL_HEIGHT
);
918 paint(self
->label
, a
);
921 static void render_icon(ObFrame
*self
, Appearance
*a
)
923 if (self
->icon_x
< 0) return;
925 if (self
->frame
.client
->nicons
) {
926 Icon
*icon
= client_icon(self
->frame
.client
, BUTTON_SIZE
, BUTTON_SIZE
);
927 a
->texture
[0].type
= RGBA
;
928 a
->texture
[0].data
.rgba
.width
= icon
->width
;
929 a
->texture
[0].data
.rgba
.height
= icon
->height
;
930 a
->texture
[0].data
.rgba
.data
= icon
->data
;
931 RECT_SET(self
->a_icon
->texture
[0].position
, 0, 0,
932 BUTTON_SIZE
,BUTTON_SIZE
);
934 a
->texture
[0].type
= NoTexture
;
936 paint(self
->icon
, a
);
939 static void render_max(ObFrame
*self
, Appearance
*a
)
941 if (self
->max_x
< 0) return;
943 RECT_SET(a
->texture
[0].position
, 0, 0, BUTTON_SIZE
,BUTTON_SIZE
);
947 static void render_iconify(ObFrame
*self
, Appearance
*a
)
949 if (self
->iconify_x
< 0) return;
951 RECT_SET(a
->texture
[0].position
, 0, 0, BUTTON_SIZE
,BUTTON_SIZE
);
952 paint(self
->iconify
, a
);
955 static void render_desk(ObFrame
*self
, Appearance
*a
)
957 if (self
->desk_x
< 0) return;
959 RECT_SET(a
->texture
[0].position
, 0, 0, BUTTON_SIZE
,BUTTON_SIZE
);
960 paint(self
->desk
, a
);
963 static void render_close(ObFrame
*self
, Appearance
*a
)
965 if (self
->close_x
< 0) return;
967 RECT_SET(a
->texture
[0].position
, 0, 0, BUTTON_SIZE
,BUTTON_SIZE
);
968 paint(self
->close
, a
);
971 GQuark
get_context(Client
*client
, Window win
)
975 if (win
== ob_root
) return g_quark_try_string("root");
976 if (client
== NULL
) return g_quark_try_string("none");
977 if (win
== client
->window
) return g_quark_try_string("client");
979 self
= (ObFrame
*) client
->frame
;
980 if (win
== self
->frame
.window
) return g_quark_try_string("frame");
981 if (win
== self
->frame
.plate
) return g_quark_try_string("client");
982 if (win
== self
->title
) return g_quark_try_string("titlebar");
983 if (win
== self
->label
) return g_quark_try_string("titlebar");
984 if (win
== self
->handle
) return g_quark_try_string("handle");
985 if (win
== self
->lgrip
) return g_quark_try_string("blcorner");
986 if (win
== self
->rgrip
) return g_quark_try_string("brcorner");
987 if (win
== self
->max
) return g_quark_try_string("maximize");
988 if (win
== self
->iconify
) return g_quark_try_string("iconify");
989 if (win
== self
->close
) return g_quark_try_string("close");
990 if (win
== self
->icon
) return g_quark_try_string("icon");
991 if (win
== self
->desk
) return g_quark_try_string("alldesktops");
993 return g_quark_try_string("none");
996 static void frame_mouse_press(const ObEvent
*e
, ObFrame
*self
)
998 Window win
= e
->data
.x
.e
->xbutton
.window
;
999 if (win
== self
->max
) {
1000 self
->max_press
= TRUE
;
1002 } else if (win
== self
->close
) {
1003 self
->close_press
= TRUE
;
1005 } else if (win
== self
->iconify
) {
1006 self
->iconify_press
= TRUE
;
1008 } else if (win
== self
->desk
) {
1009 self
->desk_press
= TRUE
;
1014 static void frame_mouse_release(const ObEvent
*e
, ObFrame
*self
)
1016 Window win
= e
->data
.x
.e
->xbutton
.window
;
1017 if (win
== self
->max
) {
1018 self
->max_press
= FALSE
;
1020 } else if (win
== self
->close
) {
1021 self
->close_press
= FALSE
;
1023 } else if (win
== self
->iconify
) {
1024 self
->iconify_press
= FALSE
;
1026 } else if (win
== self
->desk
) {
1027 self
->desk_press
= FALSE
;