4 #include "../../kernel/openbox.h"
5 #include "../../kernel/extensions.h"
6 #include "../../kernel/dispatch.h"
7 #include "../../kernel/config.h"
12 #define PLATE_EVENTMASK (SubstructureRedirectMask | ButtonPressMask)
13 #define FRAME_EVENTMASK (EnterWindowMask | LeaveWindowMask)
14 #define ELEMENT_EVENTMASK (ButtonPressMask | ButtonReleaseMask | \
15 ButtonMotionMask | ExposureMask)
17 /* style settings - geometry */
22 /* style settings - colors */
24 color_rgb
*s_cb_focused_color
;
25 color_rgb
*s_cb_unfocused_color
;
26 color_rgb
*s_title_focused_color
;
27 color_rgb
*s_title_unfocused_color
;
28 color_rgb
*s_titlebut_focused_color
;
29 color_rgb
*s_titlebut_unfocused_color
;
30 /* style settings - fonts */
33 int s_winfont_shadow_offset
;
35 /* style settings - masks */
36 pixmap_mask
*s_max_mask
;
37 pixmap_mask
*s_icon_mask
;
38 pixmap_mask
*s_desk_mask
;
39 pixmap_mask
*s_close_mask
;
41 /* global appearances */
42 Appearance
*a_focused_unpressed_max
;
43 Appearance
*a_focused_pressed_max
;
44 Appearance
*a_unfocused_unpressed_max
;
45 Appearance
*a_unfocused_pressed_max
;
46 Appearance
*a_focused_unpressed_close
;
47 Appearance
*a_focused_pressed_close
;
48 Appearance
*a_unfocused_unpressed_close
;
49 Appearance
*a_unfocused_pressed_close
;
50 Appearance
*a_focused_unpressed_desk
;
51 Appearance
*a_focused_pressed_desk
;
52 Appearance
*a_unfocused_unpressed_desk
;
53 Appearance
*a_unfocused_pressed_desk
;
54 Appearance
*a_focused_unpressed_iconify
;
55 Appearance
*a_focused_pressed_iconify
;
56 Appearance
*a_unfocused_unpressed_iconify
;
57 Appearance
*a_unfocused_pressed_iconify
;
58 Appearance
*a_focused_grip
;
59 Appearance
*a_unfocused_grip
;
60 Appearance
*a_focused_title
;
61 Appearance
*a_unfocused_title
;
62 Appearance
*a_focused_label
;
63 Appearance
*a_unfocused_label
;
64 Appearance
*a_icon
; /* always parentrelative, so no focused/unfocused */
65 Appearance
*a_focused_handle
;
66 Appearance
*a_unfocused_handle
;
68 static void layout_title(ObFrame
*self
);
69 static void frame_mouse_press(const ObEvent
*e
, ObFrame
*self
);
70 static void frame_mouse_release(const ObEvent
*e
, ObFrame
*self
);
74 g_quark_from_string("none");
75 g_quark_from_string("root");
76 g_quark_from_string("client");
77 g_quark_from_string("titlebar");
78 g_quark_from_string("handle");
79 g_quark_from_string("frame");
80 g_quark_from_string("blcorner");
81 g_quark_from_string("brcorner");
82 g_quark_from_string("maximize");
83 g_quark_from_string("alldesktops");
84 g_quark_from_string("iconify");
85 g_quark_from_string("icon");
86 g_quark_from_string("close");
88 s_b_color
= s_cb_unfocused_color
= s_cb_focused_color
=
89 s_title_unfocused_color
= s_title_focused_color
=
90 s_titlebut_unfocused_color
= s_titlebut_focused_color
= NULL
;
92 s_max_mask
= s_icon_mask
= s_desk_mask
= s_close_mask
= NULL
;
94 a_focused_unpressed_max
= appearance_new(Surface_Planar
, 1);
95 a_focused_pressed_max
= appearance_new(Surface_Planar
, 1);
96 a_unfocused_unpressed_max
= appearance_new(Surface_Planar
, 1);
97 a_unfocused_pressed_max
= appearance_new(Surface_Planar
, 1);
98 a_focused_unpressed_close
= NULL
;
99 a_focused_pressed_close
= NULL
;
100 a_unfocused_unpressed_close
= NULL
;
101 a_unfocused_pressed_close
= NULL
;
102 a_focused_unpressed_desk
= NULL
;
103 a_focused_pressed_desk
= NULL
;
104 a_unfocused_unpressed_desk
= NULL
;
105 a_unfocused_pressed_desk
= NULL
;
106 a_focused_unpressed_iconify
= NULL
;
107 a_focused_pressed_iconify
= NULL
;
108 a_unfocused_unpressed_iconify
= NULL
;
109 a_unfocused_pressed_iconify
= NULL
;
110 a_focused_grip
= appearance_new(Surface_Planar
, 0);
111 a_unfocused_grip
= appearance_new(Surface_Planar
, 0);
112 a_focused_title
= appearance_new(Surface_Planar
, 0);
113 a_unfocused_title
= appearance_new(Surface_Planar
, 0);
114 a_focused_label
= appearance_new(Surface_Planar
, 1);
115 a_unfocused_label
= appearance_new(Surface_Planar
, 1);
116 a_icon
= appearance_new(Surface_Planar
, 1);
117 a_focused_handle
= appearance_new(Surface_Planar
, 0);
118 a_unfocused_handle
= appearance_new(Surface_Planar
, 0);
121 RECT_SET(a_focused_pressed_desk
->area
, 0, 0,
122 BUTTON_SIZE
, BUTTON_SIZE
);
123 RECT_SET(a_focused_unpressed_desk
->area
, 0, 0,
124 BUTTON_SIZE
, BUTTON_SIZE
);
125 RECT_SET(a_unfocused_pressed_desk
->area
, 0, 0,
126 BUTTON_SIZE
, BUTTON_SIZE
);
127 RECT_SET(a_unfocused_unpressed_desk
->area
, 0, 0,
128 BUTTON_SIZE
, BUTTON_SIZE
);
129 RECT_SET(a_focused_pressed_iconify
->area
, 0, 0,
130 BUTTON_SIZE
, BUTTON_SIZE
);
131 RECT_SET(a_focused_unpressed_iconify
->area
, 0, 0,
132 BUTTON_SIZE
, BUTTON_SIZE
);
133 RECT_SET(a_unfocused_pressed_iconify
->area
, 0, 0,
134 BUTTON_SIZE
, BUTTON_SIZE
);
135 RECT_SET(a_unfocused_unpressed_iconify
->area
, 0, 0,
136 BUTTON_SIZE
, BUTTON_SIZE
);
137 RECT_SET(a_unfocused_unpressed_iconify
->area
, 0, 0,
138 BUTTON_SIZE
, BUTTON_SIZE
);
139 RECT_SET(a_focused_pressed_max
->area
, 0, 0,
140 BUTTON_SIZE
, BUTTON_SIZE
);
141 RECT_SET(a_focused_unpressed_max
->area
, 0, 0,
142 BUTTON_SIZE
, BUTTON_SIZE
);
143 RECT_SET(a_unfocused_pressed_max
->area
, 0, 0,
144 BUTTON_SIZE
, BUTTON_SIZE
);
145 RECT_SET(a_unfocused_unpressed_max
->area
, 0, 0,
146 BUTTON_SIZE
, BUTTON_SIZE
);
147 RECT_SET(a_focused_pressed_close
->area
, 0, 0,
148 BUTTON_SIZE
, BUTTON_SIZE
);
149 RECT_SET(a_focused_unpressed_close
->area
, 0, 0,
150 BUTTON_SIZE
, BUTTON_SIZE
);
151 RECT_SET(a_unfocused_pressed_close
->area
, 0, 0,
152 BUTTON_SIZE
, BUTTON_SIZE
);
153 RECT_SET(a_unfocused_unpressed_close
->area
, 0, 0,
154 BUTTON_SIZE
, BUTTON_SIZE
);
156 RECT_SET(a_focused_grip
->area
, 0, 0, GRIP_WIDTH
, s_handle_height
);
157 RECT_SET(a_unfocused_grip
->area
, 0, 0, GRIP_WIDTH
, s_handle_height
);
165 if (s_b_color
!= NULL
) color_free(s_b_color
);
166 if (s_cb_unfocused_color
!= NULL
) color_free(s_cb_unfocused_color
);
167 if (s_cb_focused_color
!= NULL
) color_free(s_cb_focused_color
);
168 if (s_title_unfocused_color
!= NULL
) color_free(s_title_unfocused_color
);
169 if (s_title_focused_color
!= NULL
) color_free(s_title_focused_color
);
170 if (s_titlebut_unfocused_color
!= NULL
)
171 color_free(s_titlebut_unfocused_color
);
172 if (s_titlebut_focused_color
!= NULL
)
173 color_free(s_titlebut_focused_color
);
175 if (s_max_mask
!= NULL
) pixmap_mask_free(s_max_mask
);
176 if (s_desk_mask
!= NULL
) pixmap_mask_free(s_desk_mask
);
177 if (s_icon_mask
!= NULL
) pixmap_mask_free(s_icon_mask
);
178 if (s_close_mask
!= NULL
) pixmap_mask_free(s_close_mask
);
180 if (s_winfont
!= NULL
) font_close(s_winfont
);
182 appearance_free(a_focused_unpressed_max
);
183 appearance_free(a_focused_pressed_max
);
184 appearance_free(a_unfocused_unpressed_max
);
185 appearance_free(a_unfocused_pressed_max
);
186 if (a_focused_unpressed_close
!= NULL
)
187 appearance_free(a_focused_unpressed_close
);
188 if (a_focused_pressed_close
!= NULL
)
189 appearance_free(a_focused_pressed_close
);
190 if (a_unfocused_unpressed_close
!= NULL
)
191 appearance_free(a_unfocused_unpressed_close
);
192 if (a_unfocused_pressed_close
!= NULL
)
193 appearance_free(a_unfocused_pressed_close
);
194 if (a_focused_unpressed_desk
!= NULL
)
195 appearance_free(a_focused_unpressed_desk
);
196 if (a_focused_pressed_desk
!= NULL
)
197 appearance_free(a_focused_pressed_desk
);
198 if (a_unfocused_unpressed_desk
!= NULL
)
199 appearance_free(a_unfocused_unpressed_desk
);
200 if (a_unfocused_pressed_desk
!= NULL
)
201 appearance_free(a_unfocused_pressed_desk
);
202 if (a_focused_unpressed_iconify
!= NULL
)
203 appearance_free(a_focused_unpressed_iconify
);
204 if (a_focused_pressed_iconify
!= NULL
)
205 appearance_free(a_focused_pressed_iconify
);
206 if (a_unfocused_unpressed_iconify
!= NULL
)
207 appearance_free(a_unfocused_unpressed_iconify
);
208 if (a_unfocused_pressed_iconify
!= NULL
)
209 appearance_free(a_unfocused_pressed_iconify
);
210 appearance_free(a_focused_grip
);
211 appearance_free(a_unfocused_grip
);
212 appearance_free(a_focused_title
);
213 appearance_free(a_unfocused_title
);
214 appearance_free(a_focused_label
);
215 appearance_free(a_unfocused_label
);
216 appearance_free(a_icon
);
217 appearance_free(a_focused_handle
);
218 appearance_free(a_unfocused_handle
);
221 static Window
createWindow(Window parent
, unsigned long mask
,
222 XSetWindowAttributes
*attrib
)
224 return XCreateWindow(ob_display
, parent
, 0, 0, 1, 1, 0,
225 render_depth
, InputOutput
, render_visual
,
232 XSetWindowAttributes attrib
;
236 self
= g_new(ObFrame
, 1);
238 self
->frame
.visible
= FALSE
;
240 /* create all of the decor windows */
241 mask
= CWOverrideRedirect
| CWEventMask
;
242 attrib
.event_mask
= FRAME_EVENTMASK
;
243 attrib
.override_redirect
= TRUE
;
244 self
->frame
.window
= createWindow(ob_root
, mask
, &attrib
);
247 self
->frame
.plate
= createWindow(self
->frame
.window
, mask
, &attrib
);
250 attrib
.event_mask
= ELEMENT_EVENTMASK
;
251 self
->title
= createWindow(self
->frame
.window
, mask
, &attrib
);
252 self
->label
= createWindow(self
->title
, mask
, &attrib
);
253 self
->max
= createWindow(self
->title
, mask
, &attrib
);
254 self
->close
= createWindow(self
->title
, mask
, &attrib
);
255 self
->desk
= createWindow(self
->title
, mask
, &attrib
);
256 self
->icon
= createWindow(self
->title
, mask
, &attrib
);
257 self
->iconify
= createWindow(self
->title
, mask
, &attrib
);
258 self
->handle
= createWindow(self
->frame
.window
, mask
, &attrib
);
260 attrib
.cursor
= ob_cursors
.ll_angle
;
261 self
->lgrip
= createWindow(self
->handle
, mask
, &attrib
);
262 attrib
.cursor
= ob_cursors
.lr_angle
;
263 self
->rgrip
= createWindow(self
->handle
, mask
, &attrib
);
265 /* the other stuff is shown based on decor settings */
266 XMapWindow(ob_display
, self
->frame
.plate
);
267 XMapWindow(ob_display
, self
->lgrip
);
268 XMapWindow(ob_display
, self
->rgrip
);
269 XMapWindow(ob_display
, self
->label
);
271 /* set colors/appearance/sizes for stuff that doesn't change */
272 XSetWindowBorder(ob_display
, self
->frame
.window
, s_b_color
->pixel
);
273 XSetWindowBorder(ob_display
, self
->label
, s_b_color
->pixel
);
274 XSetWindowBorder(ob_display
, self
->rgrip
, s_b_color
->pixel
);
275 XSetWindowBorder(ob_display
, self
->lgrip
, s_b_color
->pixel
);
277 XResizeWindow(ob_display
, self
->max
, BUTTON_SIZE
, BUTTON_SIZE
);
278 XResizeWindow(ob_display
, self
->iconify
, BUTTON_SIZE
, BUTTON_SIZE
);
279 XResizeWindow(ob_display
, self
->icon
, BUTTON_SIZE
, BUTTON_SIZE
);
280 XResizeWindow(ob_display
, self
->close
, BUTTON_SIZE
, BUTTON_SIZE
);
281 XResizeWindow(ob_display
, self
->desk
, BUTTON_SIZE
, BUTTON_SIZE
);
282 XResizeWindow(ob_display
, self
->lgrip
, GRIP_WIDTH
, s_handle_height
);
283 XResizeWindow(ob_display
, self
->rgrip
, GRIP_WIDTH
, s_handle_height
);
285 /* set up the dynamic appearances */
286 self
->a_unfocused_title
= appearance_copy(a_unfocused_title
);
287 self
->a_focused_title
= appearance_copy(a_focused_title
);
288 self
->a_unfocused_label
= appearance_copy(a_unfocused_label
);
289 self
->a_focused_label
= appearance_copy(a_focused_label
);
290 self
->a_unfocused_handle
= appearance_copy(a_unfocused_handle
);
291 self
->a_focused_handle
= appearance_copy(a_focused_handle
);
292 self
->a_icon
= appearance_copy(a_icon
);
294 self
->max_press
= self
->close_press
= self
->desk_press
=
295 self
->iconify_press
= FALSE
;
297 dispatch_register(Event_X_ButtonPress
, (EventHandler
)frame_mouse_press
,
299 dispatch_register(Event_X_ButtonRelease
, (EventHandler
)frame_mouse_release
,
305 static void frame_free(ObFrame
*self
)
307 appearance_free(self
->a_unfocused_title
);
308 appearance_free(self
->a_focused_title
);
309 appearance_free(self
->a_unfocused_label
);
310 appearance_free(self
->a_focused_label
);
311 appearance_free(self
->a_unfocused_handle
);
312 appearance_free(self
->a_focused_handle
);
313 appearance_free(self
->a_icon
);
315 XDestroyWindow(ob_display
, self
->frame
.window
);
317 dispatch_register(0, (EventHandler
)frame_mouse_press
, self
);
318 dispatch_register(0, (EventHandler
)frame_mouse_release
, self
);
323 void frame_show(ObFrame
*self
)
325 if (!self
->frame
.visible
) {
326 self
->frame
.visible
= TRUE
;
327 XMapWindow(ob_display
, self
->frame
.window
);
331 void frame_hide(ObFrame
*self
)
333 if (self
->frame
.visible
) {
334 self
->frame
.visible
= FALSE
;
335 self
->frame
.client
->ignore_unmaps
++;
336 XUnmapWindow(ob_display
, self
->frame
.window
);
340 void frame_adjust_shape(ObFrame
*self
)
346 if (!self
->frame
.client
->shaped
) {
347 /* clear the shape on the frame window */
348 XShapeCombineMask(ob_display
, self
->frame
.window
, ShapeBounding
,
349 self
->innersize
.left
,
353 /* make the frame's shape match the clients */
354 XShapeCombineShape(ob_display
, self
->frame
.window
, ShapeBounding
,
355 self
->innersize
.left
,
357 self
->frame
.client
->window
,
358 ShapeBounding
, ShapeSet
);
361 if (self
->frame
.client
->decorations
& Decor_Titlebar
) {
362 xrect
[0].x
= -s_bevel
;
363 xrect
[0].y
= -s_bevel
;
364 xrect
[0].width
= self
->width
+ self
->bwidth
* 2;
365 xrect
[0].height
= TITLE_HEIGHT
+
370 if (self
->frame
.client
->decorations
& Decor_Handle
) {
371 xrect
[1].x
= -s_bevel
;
372 xrect
[1].y
= HANDLE_Y(self
);
373 xrect
[1].width
= self
->width
+ self
->bwidth
* 2;
374 xrect
[1].height
= s_handle_height
+
379 XShapeCombineRectangles(ob_display
, self
->frame
.window
,
380 ShapeBounding
, 0, 0, xrect
, num
,
381 ShapeUnion
, Unsorted
);
386 void frame_adjust_area(ObFrame
*self
, gboolean moved
, gboolean resized
)
389 if (self
->frame
.client
->decorations
& Decor_Border
) {
390 self
->bwidth
= s_bwidth
;
391 self
->cbwidth
= s_cbwidth
;
393 self
->bwidth
= self
->cbwidth
= 0;
395 STRUT_SET(self
->innersize
, self
->cbwidth
, self
->cbwidth
,
396 self
->cbwidth
, self
->cbwidth
);
397 self
->width
= self
->frame
.client
->area
.width
+ self
->cbwidth
* 2;
398 g_assert(self
->width
> 0);
400 /* set border widths */
401 XSetWindowBorderWidth(ob_display
, self
->frame
.plate
, self
->cbwidth
);
402 XSetWindowBorderWidth(ob_display
, self
->frame
.window
, self
->bwidth
);
403 XSetWindowBorderWidth(ob_display
, self
->title
, self
->bwidth
);
404 XSetWindowBorderWidth(ob_display
, self
->handle
, self
->bwidth
);
405 XSetWindowBorderWidth(ob_display
, self
->lgrip
, self
->bwidth
);
406 XSetWindowBorderWidth(ob_display
, self
->rgrip
, self
->bwidth
);
408 /* position/size and map/unmap all the windows */
410 /* they all default off, they're turned on in layout_title */
418 if (self
->frame
.client
->decorations
& Decor_Titlebar
) {
419 XMoveResizeWindow(ob_display
, self
->title
,
420 -self
->bwidth
, -self
->bwidth
,
421 self
->width
, TITLE_HEIGHT
);
422 self
->innersize
.top
+= TITLE_HEIGHT
+ self
->bwidth
;
423 XMapWindow(ob_display
, self
->title
);
425 RECT_SET(self
->a_focused_title
->area
, 0, 0,
426 self
->width
, TITLE_HEIGHT
);
427 RECT_SET(self
->a_unfocused_title
->area
, 0, 0,
428 self
->width
, TITLE_HEIGHT
);
430 /* layout the title bar elements */
433 XUnmapWindow(ob_display
, self
->title
);
434 /* make all the titlebar stuff not render */
435 self
->frame
.client
->decorations
&= ~(Decor_Icon
| Decor_Iconify
|
436 Decor_Maximize
| Decor_Close
|
440 if (self
->frame
.client
->decorations
& Decor_Handle
) {
441 XMoveResizeWindow(ob_display
, self
->handle
,
442 -self
->bwidth
, HANDLE_Y(self
),
443 self
->width
, s_handle_height
);
444 XMoveWindow(ob_display
, self
->lgrip
,
445 -self
->bwidth
, -self
->bwidth
);
446 XMoveWindow(ob_display
, self
->rgrip
,
447 -self
->bwidth
+ self
->width
-
448 GRIP_WIDTH
, -self
->bwidth
);
449 self
->innersize
.bottom
+= s_handle_height
+
451 XMapWindow(ob_display
, self
->handle
);
453 if (self
->a_focused_handle
->surface
.data
.planar
.grad
==
454 Background_ParentRelative
)
455 RECT_SET(self
->a_focused_handle
->area
, 0, 0,
456 self
->width
, s_handle_height
);
458 RECT_SET(self
->a_focused_handle
->area
,
459 GRIP_WIDTH
+ self
->bwidth
, 0,
460 self
->width
- (GRIP_WIDTH
+ self
->bwidth
) * 2,
462 if (self
->a_unfocused_handle
->surface
.data
.planar
.grad
==
463 Background_ParentRelative
)
464 RECT_SET(self
->a_unfocused_handle
->area
, 0, 0,
465 self
->width
, s_handle_height
);
467 RECT_SET(self
->a_unfocused_handle
->area
,
468 GRIP_WIDTH
+ self
->bwidth
, 0,
469 self
->width
- (GRIP_WIDTH
+ self
->bwidth
) * 2,
473 XUnmapWindow(ob_display
, self
->handle
);
477 /* move and resize the plate */
478 XMoveResizeWindow(ob_display
, self
->frame
.plate
,
479 self
->innersize
.left
- self
->cbwidth
,
480 self
->innersize
.top
- self
->cbwidth
,
481 self
->frame
.client
->area
.width
,
482 self
->frame
.client
->area
.height
);
483 /* when the client has StaticGravity, it likes to move around. */
484 XMoveWindow(ob_display
, self
->frame
.client
->window
, 0, 0);
488 STRUT_SET(self
->frame
.size
,
489 self
->innersize
.left
+ self
->bwidth
,
490 self
->innersize
.top
+ self
->bwidth
,
491 self
->innersize
.right
+ self
->bwidth
,
492 self
->innersize
.bottom
+ self
->bwidth
);
495 /* shading can change without being moved or resized */
496 RECT_SET_SIZE(self
->frame
.area
,
497 self
->frame
.client
->area
.width
+
498 self
->frame
.size
.left
+ self
->frame
.size
.right
,
499 (self
->frame
.client
->shaded
? TITLE_HEIGHT
+ self
->bwidth
*2:
500 self
->frame
.client
->area
.height
+
501 self
->frame
.size
.top
+ self
->frame
.size
.bottom
));
504 /* find the new coordinates, done after setting the frame.size, for
505 frame_client_gravity. */
506 self
->frame
.area
.x
= self
->frame
.client
->area
.x
;
507 self
->frame
.area
.y
= self
->frame
.client
->area
.y
;
508 frame_client_gravity((Frame
*)self
,
509 &self
->frame
.area
.x
, &self
->frame
.area
.y
);
512 /* move and resize the top level frame.
513 shading can change without being moved or resized */
514 XMoveResizeWindow(ob_display
, self
->frame
.window
,
515 self
->frame
.area
.x
, self
->frame
.area
.y
,
517 self
->frame
.area
.height
- self
->bwidth
* 2);
522 frame_adjust_shape(self
);
526 void frame_adjust_state(ObFrame
*self
)
531 void frame_adjust_focus(ObFrame
*self
)
536 void frame_adjust_title(ObFrame
*self
)
541 void frame_adjust_icon(ObFrame
*self
)
546 void frame_grab_client(ObFrame
*self
, Client
*client
)
548 self
->frame
.client
= client
;
550 /* reparent the client to the frame */
551 XReparentWindow(ob_display
, client
->window
, self
->frame
.plate
, 0, 0);
553 When reparenting the client window, it is usually not mapped yet, since
554 this occurs from a MapRequest. However, in the case where Openbox is
555 starting up, the window is already mapped, so we'll see unmap events for
556 it. There are 2 unmap events generated that we see, one with the 'event'
557 member set the root window, and one set to the client, but both get
558 handled and need to be ignored.
560 if (ob_state
== State_Starting
)
561 client
->ignore_unmaps
+= 2;
563 /* select the event mask on the client's parent (to receive config/map
564 req's) the ButtonPress is to catch clicks on the client border */
565 XSelectInput(ob_display
, self
->frame
.plate
, PLATE_EVENTMASK
);
567 /* map the client so it maps when the frame does */
568 XMapWindow(ob_display
, client
->window
);
570 frame_adjust_area(self
, TRUE
, TRUE
);
572 /* set all the windows for the frame in the client_map */
573 g_hash_table_insert(client_map
, &self
->frame
.window
, client
);
574 g_hash_table_insert(client_map
, &self
->frame
.plate
, client
);
575 g_hash_table_insert(client_map
, &self
->title
, client
);
576 g_hash_table_insert(client_map
, &self
->label
, client
);
577 g_hash_table_insert(client_map
, &self
->max
, client
);
578 g_hash_table_insert(client_map
, &self
->close
, client
);
579 g_hash_table_insert(client_map
, &self
->desk
, client
);
580 g_hash_table_insert(client_map
, &self
->icon
, client
);
581 g_hash_table_insert(client_map
, &self
->iconify
, client
);
582 g_hash_table_insert(client_map
, &self
->handle
, client
);
583 g_hash_table_insert(client_map
, &self
->lgrip
, client
);
584 g_hash_table_insert(client_map
, &self
->rgrip
, client
);
587 void frame_release_client(ObFrame
*self
, Client
*client
)
591 g_assert(self
->frame
.client
== client
);
593 /* check if the app has already reparented its window away */
594 if (XCheckTypedWindowEvent(ob_display
, client
->window
,
595 ReparentNotify
, &ev
)) {
596 XPutBackEvent(ob_display
, &ev
);
597 /* re-map the window since the unmanaging process unmaps it */
598 XMapWindow(ob_display
, client
->window
);
600 /* according to the ICCCM - if the client doesn't reparent itself,
601 then we will reparent the window to root for them */
602 XReparentWindow(ob_display
, client
->window
, ob_root
,
607 /* remove all the windows for the frame from the client_map */
608 g_hash_table_remove(client_map
, &self
->frame
.window
);
609 g_hash_table_remove(client_map
, &self
->frame
.plate
);
610 g_hash_table_remove(client_map
, &self
->title
);
611 g_hash_table_remove(client_map
, &self
->label
);
612 g_hash_table_remove(client_map
, &self
->max
);
613 g_hash_table_remove(client_map
, &self
->close
);
614 g_hash_table_remove(client_map
, &self
->desk
);
615 g_hash_table_remove(client_map
, &self
->icon
);
616 g_hash_table_remove(client_map
, &self
->iconify
);
617 g_hash_table_remove(client_map
, &self
->handle
);
618 g_hash_table_remove(client_map
, &self
->lgrip
);
619 g_hash_table_remove(client_map
, &self
->rgrip
);
624 static void layout_title(ObFrame
*self
)
628 gboolean n
, d
, i
, l
, m
,c
;
631 n
= d
= i
= l
= m
= c
= FALSE
;
633 if (!config_get("titlebar.layout", Config_String
, &layout
)) {
634 layout
.string
= "NDLIMC";
635 config_set("titlebar.layout", Config_String
, layout
);
638 /* figure out whats being shown, and the width of the label */
639 self
->label_width
= self
->width
- (s_bevel
+ 1) * 2;
640 for (lc
= layout
.string
; *lc
!= '\0'; ++lc
) {
643 if (!(self
->frame
.client
->decorations
& Decor_Icon
)) break;
644 if (n
) { *lc
= ' '; break; } /* rm duplicates */
646 self
->label_width
-= BUTTON_SIZE
+ s_bevel
+ 1;
649 if (!(self
->frame
.client
->decorations
& Decor_AllDesktops
)) break;
650 if (d
) { *lc
= ' '; break; } /* rm duplicates */
652 self
->label_width
-= BUTTON_SIZE
+ s_bevel
+ 1;
655 if (!(self
->frame
.client
->decorations
& Decor_Iconify
)) break;
656 if (i
) { *lc
= ' '; break; } /* rm duplicates */
658 self
->label_width
-= BUTTON_SIZE
+ s_bevel
+ 1;
661 if (l
) { *lc
= ' '; break; } /* rm duplicates */
665 if (!(self
->frame
.client
->decorations
& Decor_Maximize
)) break;
666 if (m
) { *lc
= ' '; break; } /* rm duplicates */
668 self
->label_width
-= BUTTON_SIZE
+ s_bevel
+ 1;
671 if (!(self
->frame
.client
->decorations
& Decor_Close
)) break;
672 if (c
) { *lc
= ' '; break; } /* rm duplicates */
674 self
->label_width
-= BUTTON_SIZE
+ s_bevel
+ 1;
678 if (self
->label_width
< 1) self
->label_width
= 1;
680 XResizeWindow(ob_display
, self
->label
, self
->label_width
,
683 if (!n
) XUnmapWindow(ob_display
, self
->icon
);
684 if (!d
) XUnmapWindow(ob_display
, self
->desk
);
685 if (!i
) XUnmapWindow(ob_display
, self
->iconify
);
686 if (!l
) XUnmapWindow(ob_display
, self
->label
);
687 if (!m
) XUnmapWindow(ob_display
, self
->max
);
688 if (!c
) XUnmapWindow(ob_display
, self
->close
);
691 for (lc
= layout
.string
; *lc
!= '\0'; ++lc
) {
696 RECT_SET(self
->a_icon
->area
, 0, 0, BUTTON_SIZE
, BUTTON_SIZE
);
697 XMapWindow(ob_display
, self
->icon
);
698 XMoveWindow(ob_display
, self
->icon
, x
, s_bevel
+ 1);
699 x
+= BUTTON_SIZE
+ s_bevel
+ 1;
704 XMapWindow(ob_display
, self
->desk
);
705 XMoveWindow(ob_display
, self
->desk
, x
, s_bevel
+ 1);
706 x
+= BUTTON_SIZE
+ s_bevel
+ 1;
711 XMapWindow(ob_display
, self
->iconify
);
712 XMoveWindow(ob_display
, self
->iconify
, x
, s_bevel
+ 1);
713 x
+= BUTTON_SIZE
+ s_bevel
+ 1;
718 XMapWindow(ob_display
, self
->label
);
719 XMoveWindow(ob_display
, self
->label
, x
, s_bevel
);
720 x
+= self
->label_width
+ s_bevel
+ 1;
725 XMapWindow(ob_display
, self
->max
);
726 XMoveWindow(ob_display
, self
->max
, x
, s_bevel
+ 1);
727 x
+= BUTTON_SIZE
+ s_bevel
+ 1;
732 XMapWindow(ob_display
, self
->close
);
733 XMoveWindow(ob_display
, self
->close
, x
, s_bevel
+ 1);
734 x
+= BUTTON_SIZE
+ s_bevel
+ 1;
739 RECT_SET(self
->a_focused_label
->area
, 0, 0,
740 self
->label_width
, LABEL_HEIGHT
);
741 RECT_SET(self
->a_unfocused_label
->area
, 0, 0,
742 self
->label_width
, LABEL_HEIGHT
);
745 static void frame_mouse_press(const ObEvent
*e
, ObFrame
*self
)
747 Window win
= e
->data
.x
.e
->xbutton
.window
;
748 if (win
== self
->max
) {
749 self
->max_press
= TRUE
;
751 } else if (win
== self
->close
) {
752 self
->close_press
= TRUE
;
754 } else if (win
== self
->iconify
) {
755 self
->iconify_press
= TRUE
;
757 } else if (win
== self
->desk
) {
758 self
->desk_press
= TRUE
;
763 static void frame_mouse_release(const ObEvent
*e
, ObFrame
*self
)
765 Window win
= e
->data
.x
.e
->xbutton
.window
;
766 if (win
== self
->max
) {
767 self
->max_press
= FALSE
;
769 } else if (win
== self
->close
) {
770 self
->close_press
= FALSE
;
772 } else if (win
== self
->iconify
) {
773 self
->iconify_press
= FALSE
;
775 } else if (win
== self
->desk
) {
776 self
->desk_press
= FALSE
;