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 */
19 int ob_s_handle_height
;
22 /* style settings - colors */
23 color_rgb
*ob_s_b_color
;
24 color_rgb
*ob_s_cb_focused_color
;
25 color_rgb
*ob_s_cb_unfocused_color
;
26 color_rgb
*ob_s_title_focused_color
;
27 color_rgb
*ob_s_title_unfocused_color
;
28 color_rgb
*ob_s_titlebut_focused_color
;
29 color_rgb
*ob_s_titlebut_unfocused_color
;
30 /* style settings - fonts */
31 int ob_s_winfont_height
;
32 int ob_s_winfont_shadow
;
33 int ob_s_winfont_shadow_offset
;
35 /* style settings - masks */
36 pixmap_mask
*ob_s_max_mask
;
37 pixmap_mask
*ob_s_icon_mask
;
38 pixmap_mask
*ob_s_desk_mask
;
39 pixmap_mask
*ob_s_close_mask
;
41 /* global appearances */
42 Appearance
*ob_a_focused_unpressed_max
;
43 Appearance
*ob_a_focused_pressed_max
;
44 Appearance
*ob_a_unfocused_unpressed_max
;
45 Appearance
*ob_a_unfocused_pressed_max
;
46 Appearance
*ob_a_focused_unpressed_close
;
47 Appearance
*ob_a_focused_pressed_close
;
48 Appearance
*ob_a_unfocused_unpressed_close
;
49 Appearance
*ob_a_unfocused_pressed_close
;
50 Appearance
*ob_a_focused_unpressed_desk
;
51 Appearance
*ob_a_focused_pressed_desk
;
52 Appearance
*ob_a_unfocused_unpressed_desk
;
53 Appearance
*ob_a_unfocused_pressed_desk
;
54 Appearance
*ob_a_focused_unpressed_iconify
;
55 Appearance
*ob_a_focused_pressed_iconify
;
56 Appearance
*ob_a_unfocused_unpressed_iconify
;
57 Appearance
*ob_a_unfocused_pressed_iconify
;
58 Appearance
*ob_a_focused_grip
;
59 Appearance
*ob_a_unfocused_grip
;
60 Appearance
*ob_a_focused_title
;
61 Appearance
*ob_a_unfocused_title
;
62 Appearance
*ob_a_focused_label
;
63 Appearance
*ob_a_unfocused_label
;
64 Appearance
*ob_a_icon
; /* always parentrelative, so no focused/unfocused */
65 Appearance
*ob_a_focused_handle
;
66 Appearance
*ob_a_unfocused_handle
;
68 static void layout_title(ObFrame
*self
);
69 static void mouse_event(const ObEvent
*e
, ObFrame
*self
);
73 g_quark_from_string("none");
74 g_quark_from_string("root");
75 g_quark_from_string("client");
76 g_quark_from_string("titlebar");
77 g_quark_from_string("handle");
78 g_quark_from_string("frame");
79 g_quark_from_string("blcorner");
80 g_quark_from_string("brcorner");
81 g_quark_from_string("maximize");
82 g_quark_from_string("alldesktops");
83 g_quark_from_string("iconify");
84 g_quark_from_string("icon");
85 g_quark_from_string("close");
87 ob_s_b_color
= ob_s_cb_unfocused_color
= ob_s_cb_focused_color
=
88 ob_s_title_unfocused_color
= ob_s_title_focused_color
=
89 ob_s_titlebut_unfocused_color
= ob_s_titlebut_focused_color
= NULL
;
91 ob_s_max_mask
= ob_s_icon_mask
= ob_s_desk_mask
= ob_s_close_mask
= NULL
;
93 ob_a_focused_unpressed_max
= appearance_new(Surface_Planar
, 1);
94 ob_a_focused_pressed_max
= appearance_new(Surface_Planar
, 1);
95 ob_a_unfocused_unpressed_max
= appearance_new(Surface_Planar
, 1);
96 ob_a_unfocused_pressed_max
= appearance_new(Surface_Planar
, 1);
97 ob_a_focused_unpressed_close
= NULL
;
98 ob_a_focused_pressed_close
= NULL
;
99 ob_a_unfocused_unpressed_close
= NULL
;
100 ob_a_unfocused_pressed_close
= NULL
;
101 ob_a_focused_unpressed_desk
= NULL
;
102 ob_a_focused_pressed_desk
= NULL
;
103 ob_a_unfocused_unpressed_desk
= NULL
;
104 ob_a_unfocused_pressed_desk
= NULL
;
105 ob_a_focused_unpressed_iconify
= NULL
;
106 ob_a_focused_pressed_iconify
= NULL
;
107 ob_a_unfocused_unpressed_iconify
= NULL
;
108 ob_a_unfocused_pressed_iconify
= NULL
;
109 ob_a_focused_grip
= appearance_new(Surface_Planar
, 0);
110 ob_a_unfocused_grip
= appearance_new(Surface_Planar
, 0);
111 ob_a_focused_title
= appearance_new(Surface_Planar
, 0);
112 ob_a_unfocused_title
= appearance_new(Surface_Planar
, 0);
113 ob_a_focused_label
= appearance_new(Surface_Planar
, 1);
114 ob_a_unfocused_label
= appearance_new(Surface_Planar
, 1);
115 ob_a_icon
= appearance_new(Surface_Planar
, 1);
116 ob_a_focused_handle
= appearance_new(Surface_Planar
, 0);
117 ob_a_unfocused_handle
= appearance_new(Surface_Planar
, 0);
119 if (obtheme_load()) {
120 RECT_SET(ob_a_focused_pressed_desk
->area
, 0, 0,
121 BUTTON_SIZE
, BUTTON_SIZE
);
122 RECT_SET(ob_a_focused_unpressed_desk
->area
, 0, 0,
123 BUTTON_SIZE
, BUTTON_SIZE
);
124 RECT_SET(ob_a_unfocused_pressed_desk
->area
, 0, 0,
125 BUTTON_SIZE
, BUTTON_SIZE
);
126 RECT_SET(ob_a_unfocused_unpressed_desk
->area
, 0, 0,
127 BUTTON_SIZE
, BUTTON_SIZE
);
128 RECT_SET(ob_a_focused_pressed_iconify
->area
, 0, 0,
129 BUTTON_SIZE
, BUTTON_SIZE
);
130 RECT_SET(ob_a_focused_unpressed_iconify
->area
, 0, 0,
131 BUTTON_SIZE
, BUTTON_SIZE
);
132 RECT_SET(ob_a_unfocused_pressed_iconify
->area
, 0, 0,
133 BUTTON_SIZE
, BUTTON_SIZE
);
134 RECT_SET(ob_a_unfocused_unpressed_iconify
->area
, 0, 0,
135 BUTTON_SIZE
, BUTTON_SIZE
);
136 RECT_SET(ob_a_unfocused_unpressed_iconify
->area
, 0, 0,
137 BUTTON_SIZE
, BUTTON_SIZE
);
138 RECT_SET(ob_a_focused_pressed_max
->area
, 0, 0,
139 BUTTON_SIZE
, BUTTON_SIZE
);
140 RECT_SET(ob_a_focused_unpressed_max
->area
, 0, 0,
141 BUTTON_SIZE
, BUTTON_SIZE
);
142 RECT_SET(ob_a_unfocused_pressed_max
->area
, 0, 0,
143 BUTTON_SIZE
, BUTTON_SIZE
);
144 RECT_SET(ob_a_unfocused_unpressed_max
->area
, 0, 0,
145 BUTTON_SIZE
, BUTTON_SIZE
);
146 RECT_SET(ob_a_focused_pressed_close
->area
, 0, 0,
147 BUTTON_SIZE
, BUTTON_SIZE
);
148 RECT_SET(ob_a_focused_unpressed_close
->area
, 0, 0,
149 BUTTON_SIZE
, BUTTON_SIZE
);
150 RECT_SET(ob_a_unfocused_pressed_close
->area
, 0, 0,
151 BUTTON_SIZE
, BUTTON_SIZE
);
152 RECT_SET(ob_a_unfocused_unpressed_close
->area
, 0, 0,
153 BUTTON_SIZE
, BUTTON_SIZE
);
155 RECT_SET(ob_a_focused_grip
->area
, 0, 0,
156 GRIP_WIDTH
, ob_s_handle_height
);
157 RECT_SET(ob_a_unfocused_grip
->area
, 0, 0,
158 GRIP_WIDTH
, ob_s_handle_height
);
166 if (ob_s_b_color
!= NULL
) color_free(ob_s_b_color
);
167 if (ob_s_cb_unfocused_color
!= NULL
) color_free(ob_s_cb_unfocused_color
);
168 if (ob_s_cb_focused_color
!= NULL
) color_free(ob_s_cb_focused_color
);
169 if (ob_s_title_unfocused_color
!= NULL
) color_free(ob_s_title_unfocused_color
);
170 if (ob_s_title_focused_color
!= NULL
) color_free(ob_s_title_focused_color
);
171 if (ob_s_titlebut_unfocused_color
!= NULL
)
172 color_free(ob_s_titlebut_unfocused_color
);
173 if (ob_s_titlebut_focused_color
!= NULL
)
174 color_free(ob_s_titlebut_focused_color
);
176 if (ob_s_max_mask
!= NULL
) pixmap_mask_free(ob_s_max_mask
);
177 if (ob_s_desk_mask
!= NULL
) pixmap_mask_free(ob_s_desk_mask
);
178 if (ob_s_icon_mask
!= NULL
) pixmap_mask_free(ob_s_icon_mask
);
179 if (ob_s_close_mask
!= NULL
) pixmap_mask_free(ob_s_close_mask
);
181 if (ob_s_winfont
!= NULL
) font_close(ob_s_winfont
);
183 appearance_free(ob_a_focused_unpressed_max
);
184 appearance_free(ob_a_focused_pressed_max
);
185 appearance_free(ob_a_unfocused_unpressed_max
);
186 appearance_free(ob_a_unfocused_pressed_max
);
187 if (ob_a_focused_unpressed_close
!= NULL
)
188 appearance_free(ob_a_focused_unpressed_close
);
189 if (ob_a_focused_pressed_close
!= NULL
)
190 appearance_free(ob_a_focused_pressed_close
);
191 if (ob_a_unfocused_unpressed_close
!= NULL
)
192 appearance_free(ob_a_unfocused_unpressed_close
);
193 if (ob_a_unfocused_pressed_close
!= NULL
)
194 appearance_free(ob_a_unfocused_pressed_close
);
195 if (ob_a_focused_unpressed_desk
!= NULL
)
196 appearance_free(ob_a_focused_unpressed_desk
);
197 if (ob_a_focused_pressed_desk
!= NULL
)
198 appearance_free(ob_a_focused_pressed_desk
);
199 if (ob_a_unfocused_unpressed_desk
!= NULL
)
200 appearance_free(ob_a_unfocused_unpressed_desk
);
201 if (ob_a_unfocused_pressed_desk
!= NULL
)
202 appearance_free(ob_a_unfocused_pressed_desk
);
203 if (ob_a_focused_unpressed_iconify
!= NULL
)
204 appearance_free(ob_a_focused_unpressed_iconify
);
205 if (ob_a_focused_pressed_iconify
!= NULL
)
206 appearance_free(ob_a_focused_pressed_iconify
);
207 if (ob_a_unfocused_unpressed_iconify
!= NULL
)
208 appearance_free(ob_a_unfocused_unpressed_iconify
);
209 if (ob_a_unfocused_pressed_iconify
!= NULL
)
210 appearance_free(ob_a_unfocused_pressed_iconify
);
211 appearance_free(ob_a_focused_grip
);
212 appearance_free(ob_a_unfocused_grip
);
213 appearance_free(ob_a_focused_title
);
214 appearance_free(ob_a_unfocused_title
);
215 appearance_free(ob_a_focused_label
);
216 appearance_free(ob_a_unfocused_label
);
217 appearance_free(ob_a_icon
);
218 appearance_free(ob_a_focused_handle
);
219 appearance_free(ob_a_unfocused_handle
);
222 static Window
createWindow(Window parent
, unsigned long mask
,
223 XSetWindowAttributes
*attrib
)
225 return XCreateWindow(ob_display
, parent
, 0, 0, 1, 1, 0,
226 render_depth
, InputOutput
, render_visual
,
233 XSetWindowAttributes attrib
;
237 self
= g_new(ObFrame
, 1);
239 self
->frame
.visible
= FALSE
;
241 /* create all of the decor windows */
242 mask
= CWOverrideRedirect
| CWEventMask
;
243 attrib
.event_mask
= FRAME_EVENTMASK
;
244 attrib
.override_redirect
= TRUE
;
245 self
->frame
.window
= createWindow(ob_root
, mask
, &attrib
);
248 self
->frame
.plate
= createWindow(self
->frame
.window
, mask
, &attrib
);
251 attrib
.event_mask
= ELEMENT_EVENTMASK
;
252 self
->title
= createWindow(self
->frame
.window
, mask
, &attrib
);
253 self
->label
= createWindow(self
->title
, mask
, &attrib
);
254 self
->max
= createWindow(self
->title
, mask
, &attrib
);
255 self
->close
= createWindow(self
->title
, mask
, &attrib
);
256 self
->desk
= createWindow(self
->title
, mask
, &attrib
);
257 self
->icon
= createWindow(self
->title
, mask
, &attrib
);
258 self
->iconify
= createWindow(self
->title
, mask
, &attrib
);
259 self
->handle
= createWindow(self
->frame
.window
, mask
, &attrib
);
261 attrib
.cursor
= ob_cursors
.ll_angle
;
262 self
->lgrip
= createWindow(self
->handle
, mask
, &attrib
);
263 attrib
.cursor
= ob_cursors
.lr_angle
;
264 self
->rgrip
= createWindow(self
->handle
, mask
, &attrib
);
266 /* the other stuff is shown based on decor settings */
267 XMapWindow(ob_display
, self
->frame
.plate
);
268 XMapWindow(ob_display
, self
->lgrip
);
269 XMapWindow(ob_display
, self
->rgrip
);
270 XMapWindow(ob_display
, self
->label
);
272 /* set colors/appearance/sizes for stuff that doesn't change */
273 XSetWindowBorder(ob_display
, self
->frame
.window
, ob_s_b_color
->pixel
);
274 XSetWindowBorder(ob_display
, self
->label
, ob_s_b_color
->pixel
);
275 XSetWindowBorder(ob_display
, self
->rgrip
, ob_s_b_color
->pixel
);
276 XSetWindowBorder(ob_display
, self
->lgrip
, ob_s_b_color
->pixel
);
278 XResizeWindow(ob_display
, self
->max
, BUTTON_SIZE
, BUTTON_SIZE
);
279 XResizeWindow(ob_display
, self
->iconify
, BUTTON_SIZE
, BUTTON_SIZE
);
280 XResizeWindow(ob_display
, self
->icon
, BUTTON_SIZE
, BUTTON_SIZE
);
281 XResizeWindow(ob_display
, self
->close
, BUTTON_SIZE
, BUTTON_SIZE
);
282 XResizeWindow(ob_display
, self
->desk
, BUTTON_SIZE
, BUTTON_SIZE
);
283 XResizeWindow(ob_display
, self
->lgrip
, GRIP_WIDTH
, ob_s_handle_height
);
284 XResizeWindow(ob_display
, self
->rgrip
, GRIP_WIDTH
, ob_s_handle_height
);
286 /* set up the dynamic appearances */
287 self
->a_unfocused_title
= appearance_copy(ob_a_unfocused_title
);
288 self
->a_focused_title
= appearance_copy(ob_a_focused_title
);
289 self
->a_unfocused_label
= appearance_copy(ob_a_unfocused_label
);
290 self
->a_focused_label
= appearance_copy(ob_a_focused_label
);
291 self
->a_unfocused_handle
= appearance_copy(ob_a_unfocused_handle
);
292 self
->a_focused_handle
= appearance_copy(ob_a_focused_handle
);
293 self
->a_icon
= appearance_copy(ob_a_icon
);
295 self
->max_press
= self
->close_press
= self
->desk_press
=
296 self
->iconify_press
= FALSE
;
298 dispatch_register(Event_X_ButtonPress
| Event_X_ButtonRelease
,
299 (EventHandler
)mouse_event
, self
);
304 static void frame_free(ObFrame
*self
)
306 appearance_free(self
->a_unfocused_title
);
307 appearance_free(self
->a_focused_title
);
308 appearance_free(self
->a_unfocused_label
);
309 appearance_free(self
->a_focused_label
);
310 appearance_free(self
->a_unfocused_handle
);
311 appearance_free(self
->a_focused_handle
);
312 appearance_free(self
->a_icon
);
314 XDestroyWindow(ob_display
, self
->frame
.window
);
316 dispatch_register(0, (EventHandler
)mouse_event
, self
);
321 void frame_show(ObFrame
*self
)
323 if (!self
->frame
.visible
) {
324 self
->frame
.visible
= TRUE
;
325 XMapWindow(ob_display
, self
->frame
.window
);
329 void frame_hide(ObFrame
*self
)
331 if (self
->frame
.visible
) {
332 self
->frame
.visible
= FALSE
;
333 self
->frame
.client
->ignore_unmaps
++;
334 XUnmapWindow(ob_display
, self
->frame
.window
);
338 void frame_adjust_shape(ObFrame
*self
)
344 if (!self
->frame
.client
->shaped
) {
345 /* clear the shape on the frame window */
346 XShapeCombineMask(ob_display
, self
->frame
.window
, ShapeBounding
,
347 self
->innersize
.left
,
351 /* make the frame's shape match the clients */
352 XShapeCombineShape(ob_display
, self
->frame
.window
, ShapeBounding
,
353 self
->innersize
.left
,
355 self
->frame
.client
->window
,
356 ShapeBounding
, ShapeSet
);
359 if (self
->frame
.client
->decorations
& Decor_Titlebar
) {
360 xrect
[0].x
= -ob_s_bevel
;
361 xrect
[0].y
= -ob_s_bevel
;
362 xrect
[0].width
= self
->width
+ self
->bwidth
* 2;
363 xrect
[0].height
= TITLE_HEIGHT
+
368 if (self
->frame
.client
->decorations
& Decor_Handle
) {
369 xrect
[1].x
= -ob_s_bevel
;
370 xrect
[1].y
= HANDLE_Y(self
);
371 xrect
[1].width
= self
->width
+ self
->bwidth
* 2;
372 xrect
[1].height
= ob_s_handle_height
+
377 XShapeCombineRectangles(ob_display
, self
->frame
.window
,
378 ShapeBounding
, 0, 0, xrect
, num
,
379 ShapeUnion
, Unsorted
);
384 void frame_adjust_area(ObFrame
*self
, gboolean moved
, gboolean resized
)
387 if (self
->frame
.client
->decorations
& Decor_Border
) {
388 self
->bwidth
= ob_s_bwidth
;
389 self
->cbwidth
= ob_s_cbwidth
;
391 self
->bwidth
= self
->cbwidth
= 0;
393 STRUT_SET(self
->innersize
, self
->cbwidth
, self
->cbwidth
,
394 self
->cbwidth
, self
->cbwidth
);
395 self
->width
= self
->frame
.client
->area
.width
+ self
->cbwidth
* 2;
396 g_assert(self
->width
> 0);
398 /* set border widths */
399 XSetWindowBorderWidth(ob_display
, self
->frame
.plate
, self
->cbwidth
);
400 XSetWindowBorderWidth(ob_display
, self
->frame
.window
, self
->bwidth
);
401 XSetWindowBorderWidth(ob_display
, self
->title
, self
->bwidth
);
402 XSetWindowBorderWidth(ob_display
, self
->handle
, self
->bwidth
);
403 XSetWindowBorderWidth(ob_display
, self
->lgrip
, self
->bwidth
);
404 XSetWindowBorderWidth(ob_display
, self
->rgrip
, self
->bwidth
);
406 /* position/size and map/unmap all the windows */
408 /* they all default off, they're turned on in layout_title */
416 if (self
->frame
.client
->decorations
& Decor_Titlebar
) {
417 XMoveResizeWindow(ob_display
, self
->title
,
418 -self
->bwidth
, -self
->bwidth
,
419 self
->width
, TITLE_HEIGHT
);
420 self
->innersize
.top
+= TITLE_HEIGHT
+ self
->bwidth
;
421 XMapWindow(ob_display
, self
->title
);
423 RECT_SET(self
->a_focused_title
->area
, 0, 0,
424 self
->width
, TITLE_HEIGHT
);
425 RECT_SET(self
->a_unfocused_title
->area
, 0, 0,
426 self
->width
, TITLE_HEIGHT
);
428 /* layout the title bar elements */
431 XUnmapWindow(ob_display
, self
->title
);
432 /* make all the titlebar stuff not render */
433 self
->frame
.client
->decorations
&= ~(Decor_Icon
| Decor_Iconify
|
434 Decor_Maximize
| Decor_Close
|
438 if (self
->frame
.client
->decorations
& Decor_Handle
) {
439 XMoveResizeWindow(ob_display
, self
->handle
,
440 -self
->bwidth
, HANDLE_Y(self
),
441 self
->width
, ob_s_handle_height
);
442 XMoveWindow(ob_display
, self
->lgrip
,
443 -self
->bwidth
, -self
->bwidth
);
444 XMoveWindow(ob_display
, self
->rgrip
,
445 -self
->bwidth
+ self
->width
-
446 GRIP_WIDTH
, -self
->bwidth
);
447 self
->innersize
.bottom
+= ob_s_handle_height
+
449 XMapWindow(ob_display
, self
->handle
);
451 if (self
->a_focused_handle
->surface
.data
.planar
.grad
==
452 Background_ParentRelative
)
453 RECT_SET(self
->a_focused_handle
->area
, 0, 0,
454 self
->width
, ob_s_handle_height
);
456 RECT_SET(self
->a_focused_handle
->area
,
457 GRIP_WIDTH
+ self
->bwidth
, 0,
458 self
->width
- (GRIP_WIDTH
+ self
->bwidth
) * 2,
460 if (self
->a_unfocused_handle
->surface
.data
.planar
.grad
==
461 Background_ParentRelative
)
462 RECT_SET(self
->a_unfocused_handle
->area
, 0, 0,
463 self
->width
, ob_s_handle_height
);
465 RECT_SET(self
->a_unfocused_handle
->area
,
466 GRIP_WIDTH
+ self
->bwidth
, 0,
467 self
->width
- (GRIP_WIDTH
+ self
->bwidth
) * 2,
471 XUnmapWindow(ob_display
, self
->handle
);
475 /* move and resize the plate */
476 XMoveResizeWindow(ob_display
, self
->frame
.plate
,
477 self
->innersize
.left
- self
->cbwidth
,
478 self
->innersize
.top
- self
->cbwidth
,
479 self
->frame
.client
->area
.width
,
480 self
->frame
.client
->area
.height
);
481 /* when the client has StaticGravity, it likes to move around. */
482 XMoveWindow(ob_display
, self
->frame
.client
->window
, 0, 0);
486 STRUT_SET(self
->frame
.size
,
487 self
->innersize
.left
+ self
->bwidth
,
488 self
->innersize
.top
+ self
->bwidth
,
489 self
->innersize
.right
+ self
->bwidth
,
490 self
->innersize
.bottom
+ self
->bwidth
);
493 /* shading can change without being moved or resized */
494 RECT_SET_SIZE(self
->frame
.area
,
495 self
->frame
.client
->area
.width
+
496 self
->frame
.size
.left
+ self
->frame
.size
.right
,
497 (self
->frame
.client
->shaded
? TITLE_HEIGHT
+ self
->bwidth
*2:
498 self
->frame
.client
->area
.height
+
499 self
->frame
.size
.top
+ self
->frame
.size
.bottom
));
502 /* find the new coordinates, done after setting the frame.size, for
503 frame_client_gravity. */
504 self
->frame
.area
.x
= self
->frame
.client
->area
.x
;
505 self
->frame
.area
.y
= self
->frame
.client
->area
.y
;
506 frame_client_gravity((Frame
*)self
,
507 &self
->frame
.area
.x
, &self
->frame
.area
.y
);
510 /* move and resize the top level frame.
511 shading can change without being moved or resized */
512 XMoveResizeWindow(ob_display
, self
->frame
.window
,
513 self
->frame
.area
.x
, self
->frame
.area
.y
,
515 self
->frame
.area
.height
- self
->bwidth
* 2);
518 obrender_frame(self
);
520 frame_adjust_shape(self
);
524 void frame_adjust_state(ObFrame
*self
)
526 obrender_frame(self
);
529 void frame_adjust_focus(ObFrame
*self
)
531 obrender_frame(self
);
534 void frame_adjust_title(ObFrame
*self
)
536 obrender_frame(self
);
539 void frame_adjust_icon(ObFrame
*self
)
541 obrender_frame(self
);
544 void frame_grab_client(ObFrame
*self
, Client
*client
)
546 self
->frame
.client
= client
;
548 /* reparent the client to the frame */
549 XReparentWindow(ob_display
, client
->window
, self
->frame
.plate
, 0, 0);
551 When reparenting the client window, it is usually not mapped yet, since
552 this occurs from a MapRequest. However, in the case where Openbox is
553 starting up, the window is already mapped, so we'll see unmap events for
554 it. There are 2 unmap events generated that we see, one with the 'event'
555 member set the root window, and one set to the client, but both get
556 handled and need to be ignored.
558 if (ob_state
== State_Starting
)
559 client
->ignore_unmaps
+= 2;
561 /* select the event mask on the client's parent (to receive config/map
562 req's) the ButtonPress is to catch clicks on the client border */
563 XSelectInput(ob_display
, self
->frame
.plate
, PLATE_EVENTMASK
);
565 /* map the client so it maps when the frame does */
566 XMapWindow(ob_display
, client
->window
);
568 frame_adjust_area(self
, TRUE
, TRUE
);
570 /* set all the windows for the frame in the client_map */
571 g_hash_table_insert(client_map
, &self
->frame
.window
, client
);
572 g_hash_table_insert(client_map
, &self
->frame
.plate
, client
);
573 g_hash_table_insert(client_map
, &self
->title
, client
);
574 g_hash_table_insert(client_map
, &self
->label
, client
);
575 g_hash_table_insert(client_map
, &self
->max
, client
);
576 g_hash_table_insert(client_map
, &self
->close
, client
);
577 g_hash_table_insert(client_map
, &self
->desk
, client
);
578 g_hash_table_insert(client_map
, &self
->icon
, client
);
579 g_hash_table_insert(client_map
, &self
->iconify
, client
);
580 g_hash_table_insert(client_map
, &self
->handle
, client
);
581 g_hash_table_insert(client_map
, &self
->lgrip
, client
);
582 g_hash_table_insert(client_map
, &self
->rgrip
, client
);
585 void frame_release_client(ObFrame
*self
, Client
*client
)
589 g_assert(self
->frame
.client
== client
);
591 /* check if the app has already reparented its window away */
592 if (XCheckTypedWindowEvent(ob_display
, client
->window
,
593 ReparentNotify
, &ev
)) {
594 XPutBackEvent(ob_display
, &ev
);
595 /* re-map the window since the unmanaging process unmaps it */
596 XMapWindow(ob_display
, client
->window
);
598 /* according to the ICCCM - if the client doesn't reparent itself,
599 then we will reparent the window to root for them */
600 XReparentWindow(ob_display
, client
->window
, ob_root
,
605 /* remove all the windows for the frame from the client_map */
606 g_hash_table_remove(client_map
, &self
->frame
.window
);
607 g_hash_table_remove(client_map
, &self
->frame
.plate
);
608 g_hash_table_remove(client_map
, &self
->title
);
609 g_hash_table_remove(client_map
, &self
->label
);
610 g_hash_table_remove(client_map
, &self
->max
);
611 g_hash_table_remove(client_map
, &self
->close
);
612 g_hash_table_remove(client_map
, &self
->desk
);
613 g_hash_table_remove(client_map
, &self
->icon
);
614 g_hash_table_remove(client_map
, &self
->iconify
);
615 g_hash_table_remove(client_map
, &self
->handle
);
616 g_hash_table_remove(client_map
, &self
->lgrip
);
617 g_hash_table_remove(client_map
, &self
->rgrip
);
622 static void layout_title(ObFrame
*self
)
626 gboolean n
, d
, i
, l
, m
,c
;
629 n
= d
= i
= l
= m
= c
= FALSE
;
631 if (!config_get("titlebar.layout", Config_String
, &layout
)) {
632 layout
.string
= "NDLIMC";
633 config_set("titlebar.layout", Config_String
, layout
);
636 /* figure out whats being shown, and the width of the label */
637 self
->label_width
= self
->width
- (ob_s_bevel
+ 1) * 2;
638 for (lc
= layout
.string
; *lc
!= '\0'; ++lc
) {
641 if (!(self
->frame
.client
->decorations
& Decor_Icon
)) break;
642 if (n
) { *lc
= ' '; break; } /* rm duplicates */
644 self
->label_width
-= BUTTON_SIZE
+ ob_s_bevel
+ 1;
647 if (!(self
->frame
.client
->decorations
& Decor_AllDesktops
)) break;
648 if (d
) { *lc
= ' '; break; } /* rm duplicates */
650 self
->label_width
-= BUTTON_SIZE
+ ob_s_bevel
+ 1;
653 if (!(self
->frame
.client
->decorations
& Decor_Iconify
)) break;
654 if (i
) { *lc
= ' '; break; } /* rm duplicates */
656 self
->label_width
-= BUTTON_SIZE
+ ob_s_bevel
+ 1;
659 if (l
) { *lc
= ' '; break; } /* rm duplicates */
663 if (!(self
->frame
.client
->decorations
& Decor_Maximize
)) break;
664 if (m
) { *lc
= ' '; break; } /* rm duplicates */
666 self
->label_width
-= BUTTON_SIZE
+ ob_s_bevel
+ 1;
669 if (!(self
->frame
.client
->decorations
& Decor_Close
)) break;
670 if (c
) { *lc
= ' '; break; } /* rm duplicates */
672 self
->label_width
-= BUTTON_SIZE
+ ob_s_bevel
+ 1;
676 if (self
->label_width
< 1) self
->label_width
= 1;
678 XResizeWindow(ob_display
, self
->label
, self
->label_width
,
681 if (!n
) XUnmapWindow(ob_display
, self
->icon
);
682 if (!d
) XUnmapWindow(ob_display
, self
->desk
);
683 if (!i
) XUnmapWindow(ob_display
, self
->iconify
);
684 if (!l
) XUnmapWindow(ob_display
, self
->label
);
685 if (!m
) XUnmapWindow(ob_display
, self
->max
);
686 if (!c
) XUnmapWindow(ob_display
, self
->close
);
689 for (lc
= layout
.string
; *lc
!= '\0'; ++lc
) {
694 RECT_SET(self
->a_icon
->area
, 0, 0, BUTTON_SIZE
, BUTTON_SIZE
);
695 XMapWindow(ob_display
, self
->icon
);
696 XMoveWindow(ob_display
, self
->icon
, x
, ob_s_bevel
+ 1);
697 x
+= BUTTON_SIZE
+ ob_s_bevel
+ 1;
702 XMapWindow(ob_display
, self
->desk
);
703 XMoveWindow(ob_display
, self
->desk
, x
, ob_s_bevel
+ 1);
704 x
+= BUTTON_SIZE
+ ob_s_bevel
+ 1;
709 XMapWindow(ob_display
, self
->iconify
);
710 XMoveWindow(ob_display
, self
->iconify
, x
, ob_s_bevel
+ 1);
711 x
+= BUTTON_SIZE
+ ob_s_bevel
+ 1;
716 XMapWindow(ob_display
, self
->label
);
717 XMoveWindow(ob_display
, self
->label
, x
, ob_s_bevel
);
718 x
+= self
->label_width
+ ob_s_bevel
+ 1;
723 XMapWindow(ob_display
, self
->max
);
724 XMoveWindow(ob_display
, self
->max
, x
, ob_s_bevel
+ 1);
725 x
+= BUTTON_SIZE
+ ob_s_bevel
+ 1;
730 XMapWindow(ob_display
, self
->close
);
731 XMoveWindow(ob_display
, self
->close
, x
, ob_s_bevel
+ 1);
732 x
+= BUTTON_SIZE
+ ob_s_bevel
+ 1;
737 RECT_SET(self
->a_focused_label
->area
, 0, 0,
738 self
->label_width
, LABEL_HEIGHT
);
739 RECT_SET(self
->a_unfocused_label
->area
, 0, 0,
740 self
->label_width
, LABEL_HEIGHT
);
743 static void mouse_event(const ObEvent
*e
, ObFrame
*self
)
746 gboolean press
= e
->type
== Event_X_ButtonPress
;
748 win
= e
->data
.x
.e
->xbutton
.window
;
749 if (win
== self
->max
) {
750 self
->max_press
= press
;
751 obrender_frame(self
);
752 } else if (win
== self
->close
) {
753 self
->close_press
= press
;
754 obrender_frame(self
);
755 } else if (win
== self
->iconify
) {
756 self
->iconify_press
= press
;
757 obrender_frame(self
);
758 } else if (win
== self
->desk
) {
759 self
->desk_press
= press
;
760 obrender_frame(self
);
764 GQuark
get_context(Client
*client
, Window win
)
768 if (win
== ob_root
) return g_quark_try_string("root");
769 if (client
== NULL
) return g_quark_try_string("none");
770 if (win
== client
->window
) return g_quark_try_string("client");
772 self
= (ObFrame
*) client
->frame
;
773 if (win
== self
->frame
.window
) return g_quark_try_string("frame");
774 if (win
== self
->frame
.plate
) return g_quark_try_string("client");
775 if (win
== self
->title
) return g_quark_try_string("titlebar");
776 if (win
== self
->label
) return g_quark_try_string("titlebar");
777 if (win
== self
->handle
) return g_quark_try_string("handle");
778 if (win
== self
->lgrip
) return g_quark_try_string("blcorner");
779 if (win
== self
->rgrip
) return g_quark_try_string("brcorner");
780 if (win
== self
->max
) return g_quark_try_string("maximize");
781 if (win
== self
->iconify
) return g_quark_try_string("iconify");
782 if (win
== self
->close
) return g_quark_try_string("close");
783 if (win
== self
->icon
) return g_quark_try_string("icon");
784 if (win
== self
->desk
) return g_quark_try_string("alldesktops");
786 return g_quark_try_string("none");