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)
22 #define HANDLE_WIDTH(f) (f->width - (GRIP_WIDTH + f->bwidth) * 2)
24 #define PLATE_EVENTMASK (SubstructureRedirectMask | ButtonPressMask)
25 #define FRAME_EVENTMASK (EnterWindowMask | LeaveWindowMask)
26 #define ELEMENT_EVENTMASK (ButtonPressMask | ButtonReleaseMask | \
27 ButtonMotionMask | ExposureMask)
29 /* style settings - geometry */
34 /* style settings - colors */
36 color_rgb
*s_cb_focused_color
;
37 color_rgb
*s_cb_unfocused_color
;
38 color_rgb
*s_title_focused_color
;
39 color_rgb
*s_title_unfocused_color
;
40 color_rgb
*s_titlebut_focused_color
;
41 color_rgb
*s_titlebut_unfocused_color
;
42 /* style settings - fonts */
45 int s_winfont_shadow_offset
;
47 /* style settings - masks */
48 pixmap_mask
*s_max_mask
;
49 pixmap_mask
*s_icon_mask
;
50 pixmap_mask
*s_desk_mask
;
51 pixmap_mask
*s_close_mask
;
53 /* global appearances */
54 Appearance
*a_focused_unpressed_max
;
55 Appearance
*a_focused_pressed_max
;
56 Appearance
*a_unfocused_unpressed_max
;
57 Appearance
*a_unfocused_pressed_max
;
58 Appearance
*a_focused_unpressed_close
;
59 Appearance
*a_focused_pressed_close
;
60 Appearance
*a_unfocused_unpressed_close
;
61 Appearance
*a_unfocused_pressed_close
;
62 Appearance
*a_focused_unpressed_desk
;
63 Appearance
*a_focused_pressed_desk
;
64 Appearance
*a_unfocused_unpressed_desk
;
65 Appearance
*a_unfocused_pressed_desk
;
66 Appearance
*a_focused_unpressed_iconify
;
67 Appearance
*a_focused_pressed_iconify
;
68 Appearance
*a_unfocused_unpressed_iconify
;
69 Appearance
*a_unfocused_pressed_iconify
;
70 Appearance
*a_focused_grip
;
71 Appearance
*a_unfocused_grip
;
72 Appearance
*a_focused_title
;
73 Appearance
*a_unfocused_title
;
74 Appearance
*a_focused_label
;
75 Appearance
*a_unfocused_label
;
76 Appearance
*a_icon
; /* always parentrelative, so no focused/unfocused */
77 Appearance
*a_focused_handle
;
78 Appearance
*a_unfocused_handle
;
80 typedef struct ObFrame
{
94 Appearance
*a_unfocused_title
;
95 Appearance
*a_focused_title
;
96 Appearance
*a_unfocused_label
;
97 Appearance
*a_focused_label
;
99 Appearance
*a_unfocused_handle
;
100 Appearance
*a_focused_handle
;
106 int width
; /* title and handle */
108 int icon_x
; /* x-position of the window icon button */
109 int label_x
; /* x-position of the window title */
110 int iconify_x
; /* x-position of the window iconify button */
111 int desk_x
; /* x-position of the window all-desktops button */
112 int max_x
; /* x-position of the window maximize button */
113 int close_x
; /* x-position of the window close button */
114 int bwidth
; /* border width */
115 int cbwidth
; /* client border width */
118 gboolean close_press
;
120 gboolean iconify_press
;
123 static void layout_title(ObFrame
*self
);
124 static void render(ObFrame
*self
);
125 static void render_label(ObFrame
*self
);
126 static void render_max(ObFrame
*self
);
127 static void render_icon(ObFrame
*self
);
128 static void render_iconify(ObFrame
*self
);
129 static void render_desk(ObFrame
*self
);
130 static void render_close(ObFrame
*self
);
132 static void frame_mouse_press(const ObEvent
*e
, ObFrame
*self
);
133 static void frame_mouse_release(const ObEvent
*e
, ObFrame
*self
);
137 g_quark_from_string("none");
138 g_quark_from_string("root");
139 g_quark_from_string("client");
140 g_quark_from_string("titlebar");
141 g_quark_from_string("handle");
142 g_quark_from_string("frame");
143 g_quark_from_string("blcorner");
144 g_quark_from_string("brcorner");
145 g_quark_from_string("maximize");
146 g_quark_from_string("alldesktops");
147 g_quark_from_string("iconify");
148 g_quark_from_string("icon");
149 g_quark_from_string("close");
151 s_b_color
= s_cb_unfocused_color
= s_cb_focused_color
=
152 s_title_unfocused_color
= s_title_focused_color
=
153 s_titlebut_unfocused_color
= s_titlebut_focused_color
= NULL
;
155 s_max_mask
= s_icon_mask
= s_desk_mask
= s_close_mask
= NULL
;
157 a_focused_unpressed_max
= appearance_new(Surface_Planar
, 1);
158 a_focused_pressed_max
= appearance_new(Surface_Planar
, 1);
159 a_unfocused_unpressed_max
= appearance_new(Surface_Planar
, 1);
160 a_unfocused_pressed_max
= appearance_new(Surface_Planar
, 1);
161 a_focused_unpressed_close
= NULL
;
162 a_focused_pressed_close
= NULL
;
163 a_unfocused_unpressed_close
= NULL
;
164 a_unfocused_pressed_close
= NULL
;
165 a_focused_unpressed_desk
= NULL
;
166 a_focused_pressed_desk
= NULL
;
167 a_unfocused_unpressed_desk
= NULL
;
168 a_unfocused_pressed_desk
= NULL
;
169 a_focused_unpressed_iconify
= NULL
;
170 a_focused_pressed_iconify
= NULL
;
171 a_unfocused_unpressed_iconify
= NULL
;
172 a_unfocused_pressed_iconify
= NULL
;
173 a_focused_grip
= appearance_new(Surface_Planar
, 0);
174 a_unfocused_grip
= appearance_new(Surface_Planar
, 0);
175 a_focused_title
= appearance_new(Surface_Planar
, 0);
176 a_unfocused_title
= appearance_new(Surface_Planar
, 0);
177 a_focused_label
= appearance_new(Surface_Planar
, 1);
178 a_unfocused_label
= appearance_new(Surface_Planar
, 1);
179 a_icon
= appearance_new(Surface_Planar
, 0);/*1);*/
180 a_focused_handle
= appearance_new(Surface_Planar
, 0);
181 a_unfocused_handle
= appearance_new(Surface_Planar
, 0);
188 if (s_b_color
!= NULL
) color_free(s_b_color
);
189 if (s_cb_unfocused_color
!= NULL
) color_free(s_cb_unfocused_color
);
190 if (s_cb_focused_color
!= NULL
) color_free(s_cb_focused_color
);
191 if (s_title_unfocused_color
!= NULL
) color_free(s_title_unfocused_color
);
192 if (s_title_focused_color
!= NULL
) color_free(s_title_focused_color
);
193 if (s_titlebut_unfocused_color
!= NULL
)
194 color_free(s_titlebut_unfocused_color
);
195 if (s_titlebut_focused_color
!= NULL
)
196 color_free(s_titlebut_focused_color
);
198 if (s_max_mask
!= NULL
) pixmap_mask_free(s_max_mask
);
199 if (s_desk_mask
!= NULL
) pixmap_mask_free(s_desk_mask
);
200 if (s_icon_mask
!= NULL
) pixmap_mask_free(s_icon_mask
);
201 if (s_close_mask
!= NULL
) pixmap_mask_free(s_close_mask
);
203 if (s_winfont
!= NULL
) font_close(s_winfont
);
205 appearance_free(a_focused_unpressed_max
);
206 appearance_free(a_focused_pressed_max
);
207 appearance_free(a_unfocused_unpressed_max
);
208 appearance_free(a_unfocused_pressed_max
);
209 if (a_focused_unpressed_close
!= NULL
)
210 appearance_free(a_focused_unpressed_close
);
211 if (a_focused_pressed_close
!= NULL
)
212 appearance_free(a_focused_pressed_close
);
213 if (a_unfocused_unpressed_close
!= NULL
)
214 appearance_free(a_unfocused_unpressed_close
);
215 if (a_unfocused_pressed_close
!= NULL
)
216 appearance_free(a_unfocused_pressed_close
);
217 if (a_focused_unpressed_desk
!= NULL
)
218 appearance_free(a_focused_unpressed_desk
);
219 if (a_focused_pressed_desk
!= NULL
)
220 appearance_free(a_focused_pressed_desk
);
221 if (a_unfocused_unpressed_desk
!= NULL
)
222 appearance_free(a_unfocused_unpressed_desk
);
223 if (a_unfocused_pressed_desk
!= NULL
)
224 appearance_free(a_unfocused_pressed_desk
);
225 if (a_focused_unpressed_iconify
!= NULL
)
226 appearance_free(a_focused_unpressed_iconify
);
227 if (a_focused_pressed_iconify
!= NULL
)
228 appearance_free(a_focused_pressed_iconify
);
229 if (a_unfocused_unpressed_iconify
!= NULL
)
230 appearance_free(a_unfocused_unpressed_iconify
);
231 if (a_unfocused_pressed_iconify
!= NULL
)
232 appearance_free(a_unfocused_pressed_iconify
);
233 appearance_free(a_focused_grip
);
234 appearance_free(a_unfocused_grip
);
235 appearance_free(a_focused_title
);
236 appearance_free(a_unfocused_title
);
237 appearance_free(a_focused_label
);
238 appearance_free(a_unfocused_label
);
239 appearance_free(a_icon
);
240 appearance_free(a_focused_handle
);
241 appearance_free(a_unfocused_handle
);
244 static Window
createWindow(Window parent
, unsigned long mask
,
245 XSetWindowAttributes
*attrib
)
247 return XCreateWindow(ob_display
, parent
, 0, 0, 1, 1, 0,
248 render_depth
, InputOutput
, render_visual
,
255 XSetWindowAttributes attrib
;
259 self
= g_new(ObFrame
, 1);
261 self
->frame
.visible
= FALSE
;
263 /* create all of the decor windows */
264 mask
= CWOverrideRedirect
| CWEventMask
;
265 attrib
.event_mask
= FRAME_EVENTMASK
;
266 attrib
.override_redirect
= TRUE
;
267 self
->frame
.window
= createWindow(ob_root
, mask
, &attrib
);
270 self
->frame
.plate
= createWindow(self
->frame
.window
, mask
, &attrib
);
273 attrib
.event_mask
= ELEMENT_EVENTMASK
;
274 self
->title
= createWindow(self
->frame
.window
, mask
, &attrib
);
275 self
->label
= createWindow(self
->title
, mask
, &attrib
);
276 self
->max
= createWindow(self
->title
, mask
, &attrib
);
277 self
->close
= createWindow(self
->title
, mask
, &attrib
);
278 self
->desk
= createWindow(self
->title
, mask
, &attrib
);
279 self
->icon
= createWindow(self
->title
, mask
, &attrib
);
280 self
->iconify
= createWindow(self
->title
, mask
, &attrib
);
281 self
->handle
= createWindow(self
->frame
.window
, mask
, &attrib
);
283 attrib
.cursor
= ob_cursors
.ll_angle
;
284 self
->lgrip
= createWindow(self
->handle
, mask
, &attrib
);
285 attrib
.cursor
= ob_cursors
.lr_angle
;
286 self
->rgrip
= createWindow(self
->handle
, mask
, &attrib
);
288 /* the other stuff is shown based on decor settings */
289 XMapWindow(ob_display
, self
->frame
.plate
);
290 XMapWindow(ob_display
, self
->lgrip
);
291 XMapWindow(ob_display
, self
->rgrip
);
292 XMapWindow(ob_display
, self
->label
);
294 /* set colors/appearance/sizes for stuff that doesn't change */
295 XSetWindowBorder(ob_display
, self
->frame
.window
, s_b_color
->pixel
);
296 XSetWindowBorder(ob_display
, self
->label
, s_b_color
->pixel
);
297 XSetWindowBorder(ob_display
, self
->rgrip
, s_b_color
->pixel
);
298 XSetWindowBorder(ob_display
, self
->lgrip
, s_b_color
->pixel
);
300 XResizeWindow(ob_display
, self
->max
, BUTTON_SIZE
, BUTTON_SIZE
);
301 XResizeWindow(ob_display
, self
->iconify
, BUTTON_SIZE
, BUTTON_SIZE
);
302 XResizeWindow(ob_display
, self
->icon
, BUTTON_SIZE
, BUTTON_SIZE
);
303 XResizeWindow(ob_display
, self
->close
, BUTTON_SIZE
, BUTTON_SIZE
);
304 XResizeWindow(ob_display
, self
->desk
, BUTTON_SIZE
, BUTTON_SIZE
);
305 XResizeWindow(ob_display
, self
->lgrip
, GRIP_WIDTH
, s_handle_height
);
306 XResizeWindow(ob_display
, self
->rgrip
, GRIP_WIDTH
, s_handle_height
);
308 /* set up the dynamic appearances */
309 self
->a_unfocused_title
= appearance_copy(a_unfocused_title
);
310 self
->a_focused_title
= appearance_copy(a_focused_title
);
311 self
->a_unfocused_label
= appearance_copy(a_unfocused_label
);
312 self
->a_focused_label
= appearance_copy(a_focused_label
);
313 self
->a_unfocused_handle
= appearance_copy(a_unfocused_handle
);
314 self
->a_focused_handle
= appearance_copy(a_focused_handle
);
315 self
->a_icon
= appearance_copy(a_icon
);
317 self
->max_press
= self
->close_press
= self
->desk_press
=
318 self
->iconify_press
= FALSE
;
320 dispatch_register(Event_X_ButtonPress
, (EventHandler
)frame_mouse_press
,
322 dispatch_register(Event_X_ButtonRelease
, (EventHandler
)frame_mouse_release
,
328 static void frame_free(ObFrame
*self
)
330 appearance_free(self
->a_unfocused_title
);
331 appearance_free(self
->a_focused_title
);
332 appearance_free(self
->a_unfocused_label
);
333 appearance_free(self
->a_focused_label
);
334 appearance_free(self
->a_unfocused_handle
);
335 appearance_free(self
->a_focused_handle
);
336 appearance_free(self
->a_icon
);
338 XDestroyWindow(ob_display
, self
->frame
.window
);
340 dispatch_register(0, (EventHandler
)frame_mouse_press
, self
);
341 dispatch_register(0, (EventHandler
)frame_mouse_release
, self
);
346 void frame_show(ObFrame
*self
)
348 if (!self
->frame
.visible
) {
349 self
->frame
.visible
= TRUE
;
350 XMapWindow(ob_display
, self
->frame
.window
);
354 void frame_hide(ObFrame
*self
)
356 if (self
->frame
.visible
) {
357 self
->frame
.visible
= FALSE
;
358 self
->frame
.client
->ignore_unmaps
++;
359 XUnmapWindow(ob_display
, self
->frame
.window
);
363 void frame_adjust_shape(ObFrame
*self
)
369 if (!self
->frame
.client
->shaped
) {
370 /* clear the shape on the frame window */
371 XShapeCombineMask(ob_display
, self
->frame
.window
, ShapeBounding
,
372 self
->innersize
.left
,
376 /* make the frame's shape match the clients */
377 XShapeCombineShape(ob_display
, self
->frame
.window
, ShapeBounding
,
378 self
->innersize
.left
,
380 self
->frame
.client
->window
,
381 ShapeBounding
, ShapeSet
);
384 if (self
->frame
.client
->decorations
& Decor_Titlebar
) {
385 xrect
[0].x
= -s_bevel
;
386 xrect
[0].y
= -s_bevel
;
387 xrect
[0].width
= self
->width
+ self
->bwidth
* 2;
388 xrect
[0].height
= TITLE_HEIGHT
+
393 if (self
->frame
.client
->decorations
& Decor_Handle
) {
394 xrect
[1].x
= -s_bevel
;
395 xrect
[1].y
= HANDLE_Y(self
);
396 xrect
[1].width
= self
->width
+ self
->bwidth
* 2;
397 xrect
[1].height
= s_handle_height
+
402 XShapeCombineRectangles(ob_display
, self
->frame
.window
,
403 ShapeBounding
, 0, 0, xrect
, num
,
404 ShapeUnion
, Unsorted
);
409 void frame_adjust_area(ObFrame
*self
, gboolean moved
, gboolean resized
)
411 g_message("adjust_area: %d %d", moved
, resized
);
413 if (self
->frame
.client
->decorations
& Decor_Border
) {
414 self
->bwidth
= s_bwidth
;
415 self
->cbwidth
= s_cbwidth
;
417 self
->bwidth
= self
->cbwidth
= 0;
419 STRUT_SET(self
->innersize
, self
->cbwidth
, self
->cbwidth
,
420 self
->cbwidth
, self
->cbwidth
);
421 self
->width
= self
->frame
.client
->area
.width
+ self
->cbwidth
* 2;
422 g_assert(self
->width
> 0);
424 /* set border widths */
425 XSetWindowBorderWidth(ob_display
, self
->frame
.plate
, self
->cbwidth
);
426 XSetWindowBorderWidth(ob_display
, self
->frame
.window
, self
->bwidth
);
427 XSetWindowBorderWidth(ob_display
, self
->title
, self
->bwidth
);
428 XSetWindowBorderWidth(ob_display
, self
->handle
, self
->bwidth
);
429 XSetWindowBorderWidth(ob_display
, self
->lgrip
, self
->bwidth
);
430 XSetWindowBorderWidth(ob_display
, self
->rgrip
, self
->bwidth
);
432 /* position/size and map/unmap all the windows */
434 /* they all default off, they're turned on in layout_title */
442 if (self
->frame
.client
->decorations
& Decor_Titlebar
) {
443 XMoveResizeWindow(ob_display
, self
->title
,
444 -self
->bwidth
, -self
->bwidth
,
445 self
->width
, TITLE_HEIGHT
);
446 self
->innersize
.top
+= TITLE_HEIGHT
+ self
->bwidth
;
447 XMapWindow(ob_display
, self
->title
);
449 /* layout the title bar elements */
452 XUnmapWindow(ob_display
, self
->title
);
453 /* make all the titlebar stuff not render */
454 self
->frame
.client
->decorations
&= ~(Decor_Icon
| Decor_Iconify
|
455 Decor_Maximize
| Decor_Close
|
459 if (self
->frame
.client
->decorations
& Decor_Handle
) {
460 XMoveResizeWindow(ob_display
, self
->handle
,
461 -self
->bwidth
, HANDLE_Y(self
),
462 self
->width
, s_handle_height
);
463 XMoveWindow(ob_display
, self
->lgrip
,
464 -self
->bwidth
, -self
->bwidth
);
465 XMoveWindow(ob_display
, self
->rgrip
,
466 -self
->bwidth
+ self
->width
-
467 GRIP_WIDTH
, -self
->bwidth
);
468 self
->innersize
.bottom
+= s_handle_height
+
470 XMapWindow(ob_display
, self
->handle
);
472 XUnmapWindow(ob_display
, self
->handle
);
476 /* find the new coordinates */
477 self
->frame
.area
.x
= self
->frame
.client
->area
.x
;
478 self
->frame
.area
.y
= self
->frame
.client
->area
.y
;
479 frame_client_gravity((Frame
*)self
,
480 &self
->frame
.area
.x
, &self
->frame
.area
.y
);
483 /* move and resize the top level frame.
484 shading can change without being moved or resized */
485 XMoveResizeWindow(ob_display
, self
->frame
.window
,
486 self
->frame
.area
.x
, self
->frame
.area
.y
,
488 (self
->frame
.client
->shaded
? TITLE_HEIGHT
:
489 self
->innersize
.top
+ self
->innersize
.bottom
+
490 self
->frame
.client
->area
.height
));
493 /* move and resize the plate */
494 XMoveResizeWindow(ob_display
, self
->frame
.plate
,
495 self
->innersize
.left
- self
->cbwidth
,
496 self
->innersize
.top
- self
->cbwidth
,
497 self
->frame
.client
->area
.width
,
498 self
->frame
.client
->area
.height
);
499 /* when the client has StaticGravity, it likes to move around. */
500 XMoveWindow(ob_display
, self
->frame
.client
->window
, 0, 0);
504 STRUT_SET(self
->frame
.size
,
505 self
->innersize
.left
+ self
->bwidth
,
506 self
->innersize
.top
+ self
->bwidth
,
507 self
->innersize
.right
+ self
->bwidth
,
508 self
->innersize
.bottom
+ self
->bwidth
);
511 /* shading can change without being moved or resized */
512 RECT_SET_SIZE(self
->frame
.area
,
513 self
->frame
.client
->area
.width
+
514 self
->frame
.size
.left
+ self
->frame
.size
.right
,
515 (self
->frame
.client
->shaded
? TITLE_HEIGHT
+ self
->bwidth
*2:
516 self
->frame
.client
->area
.height
+
517 self
->frame
.size
.top
+ self
->frame
.size
.bottom
));
522 frame_adjust_shape(self
);
526 void frame_adjust_state(ObFrame
*self
)
532 void frame_adjust_focus(ObFrame
*self
)
537 void frame_adjust_title(ObFrame
*self
)
542 void frame_adjust_icon(ObFrame
*self
)
547 void frame_grab_client(ObFrame
*self
, Client
*client
)
549 self
->frame
.client
= client
;
551 /* reparent the client to the frame */
552 XReparentWindow(ob_display
, client
->window
, self
->frame
.plate
, 0, 0);
554 When reparenting the client window, it is usually not mapped yet, since
555 this occurs from a MapRequest. However, in the case where Openbox is
556 starting up, the window is already mapped, so we'll see unmap events for
557 it. There are 2 unmap events generated that we see, one with the 'event'
558 member set the root window, and one set to the client, but both get
559 handled and need to be ignored.
561 if (ob_state
== State_Starting
)
562 client
->ignore_unmaps
+= 2;
564 /* select the event mask on the client's parent (to receive config/map
565 req's) the ButtonPress is to catch clicks on the client border */
566 XSelectInput(ob_display
, self
->frame
.plate
, PLATE_EVENTMASK
);
568 /* map the client so it maps when the frame does */
569 XMapWindow(ob_display
, client
->window
);
571 frame_adjust_area(self
, TRUE
, TRUE
);
573 /* set all the windows for the frame in the client_map */
574 g_hash_table_insert(client_map
, (gpointer
)self
->frame
.window
, client
);
575 g_hash_table_insert(client_map
, (gpointer
)self
->frame
.plate
, client
);
576 g_hash_table_insert(client_map
, (gpointer
)self
->title
, client
);
577 g_hash_table_insert(client_map
, (gpointer
)self
->label
, client
);
578 g_hash_table_insert(client_map
, (gpointer
)self
->max
, client
);
579 g_hash_table_insert(client_map
, (gpointer
)self
->close
, client
);
580 g_hash_table_insert(client_map
, (gpointer
)self
->desk
, client
);
581 g_hash_table_insert(client_map
, (gpointer
)self
->icon
, client
);
582 g_hash_table_insert(client_map
, (gpointer
)self
->iconify
, client
);
583 g_hash_table_insert(client_map
, (gpointer
)self
->handle
, client
);
584 g_hash_table_insert(client_map
, (gpointer
)self
->lgrip
, client
);
585 g_hash_table_insert(client_map
, (gpointer
)self
->rgrip
, client
);
588 void frame_release_client(ObFrame
*self
, Client
*client
)
592 g_assert(self
->frame
.client
== client
);
594 /* check if the app has already reparented its window away */
595 if (XCheckTypedWindowEvent(ob_display
, client
->window
,
596 ReparentNotify
, &ev
)) {
597 XPutBackEvent(ob_display
, &ev
);
598 /* re-map the window since the unmanaging process unmaps it */
599 XMapWindow(ob_display
, client
->window
);
601 /* according to the ICCCM - if the client doesn't reparent itself,
602 then we will reparent the window to root for them */
603 XReparentWindow(ob_display
, client
->window
, ob_root
,
608 /* remove all the windows for the frame from the client_map */
609 g_hash_table_remove(client_map
, (gpointer
)self
->frame
.window
);
610 g_hash_table_remove(client_map
, (gpointer
)self
->frame
.plate
);
611 g_hash_table_remove(client_map
, (gpointer
)self
->title
);
612 g_hash_table_remove(client_map
, (gpointer
)self
->label
);
613 g_hash_table_remove(client_map
, (gpointer
)self
->max
);
614 g_hash_table_remove(client_map
, (gpointer
)self
->close
);
615 g_hash_table_remove(client_map
, (gpointer
)self
->desk
);
616 g_hash_table_remove(client_map
, (gpointer
)self
->icon
);
617 g_hash_table_remove(client_map
, (gpointer
)self
->iconify
);
618 g_hash_table_remove(client_map
, (gpointer
)self
->handle
);
619 g_hash_table_remove(client_map
, (gpointer
)self
->lgrip
);
620 g_hash_table_remove(client_map
, (gpointer
)self
->rgrip
);
625 static void layout_title(ObFrame
*self
)
629 gboolean n
, d
, i
, l
, m
,c
;
632 n
= d
= i
= l
= m
= c
= FALSE
;
634 if (!config_get("titlebar.layout", Config_String
, &layout
)) {
635 layout
.string
= "NDLIMC";
636 config_set("titlebar.layout", Config_String
, layout
);
639 /* figure out whats being shown, and the width of the label */
640 self
->label_width
= self
->width
- (s_bevel
+ 1) * 2;
641 for (lc
= layout
.string
; *lc
!= '\0'; ++lc
) {
644 if (!(self
->frame
.client
->decorations
& Decor_Icon
)) break;
646 self
->label_width
-= BUTTON_SIZE
+ s_bevel
+ 1;
649 if (!(self
->frame
.client
->decorations
& Decor_AllDesktops
)) break;
651 self
->label_width
-= BUTTON_SIZE
+ s_bevel
+ 1;
654 if (!(self
->frame
.client
->decorations
& Decor_Iconify
)) break;
656 self
->label_width
-= BUTTON_SIZE
+ s_bevel
+ 1;
662 if (!(self
->frame
.client
->decorations
& Decor_Maximize
)) break;
664 self
->label_width
-= BUTTON_SIZE
+ s_bevel
+ 1;
667 if (!(self
->frame
.client
->decorations
& Decor_Close
)) break;
669 self
->label_width
-= BUTTON_SIZE
+ s_bevel
+ 1;
673 if (self
->label_width
< 1) self
->label_width
= 1;
675 XResizeWindow(ob_display
, self
->label
, self
->label_width
,
678 if (!n
) XUnmapWindow(ob_display
, self
->icon
);
679 if (!d
) XUnmapWindow(ob_display
, self
->desk
);
680 if (!i
) XUnmapWindow(ob_display
, self
->iconify
);
681 if (!l
) XUnmapWindow(ob_display
, self
->label
);
682 if (!m
) XUnmapWindow(ob_display
, self
->max
);
683 if (!c
) XUnmapWindow(ob_display
, self
->close
);
686 for (lc
= layout
.string
; *lc
!= '\0'; ++lc
) {
691 XMapWindow(ob_display
, self
->icon
);
692 XMoveWindow(ob_display
, self
->icon
, x
, s_bevel
+ 1);
693 x
+= BUTTON_SIZE
+ s_bevel
+ 1;
698 XMapWindow(ob_display
, self
->desk
);
699 XMoveWindow(ob_display
, self
->desk
, x
, s_bevel
+ 1);
700 x
+= BUTTON_SIZE
+ s_bevel
+ 1;
705 XMapWindow(ob_display
, self
->iconify
);
706 XMoveWindow(ob_display
, self
->iconify
, x
, s_bevel
+ 1);
707 x
+= BUTTON_SIZE
+ s_bevel
+ 1;
712 XMapWindow(ob_display
, self
->label
);
713 XMoveWindow(ob_display
, self
->label
, x
, s_bevel
);
714 x
+= self
->label_width
+ s_bevel
+ 1;
719 XMapWindow(ob_display
, self
->max
);
720 XMoveWindow(ob_display
, self
->max
, x
, s_bevel
+ 1);
721 x
+= BUTTON_SIZE
+ s_bevel
+ 1;
726 XMapWindow(ob_display
, self
->close
);
727 XMoveWindow(ob_display
, self
->close
, x
, s_bevel
+ 1);
728 x
+= BUTTON_SIZE
+ s_bevel
+ 1;
734 static void render(ObFrame
*self
)
736 if (client_focused(self
->frame
.client
)) {
737 XSetWindowBorder(ob_display
, self
->frame
.plate
,
738 s_cb_focused_color
->pixel
);
740 XSetWindowBorder(ob_display
, self
->frame
.plate
,
741 s_cb_unfocused_color
->pixel
);
744 if (self
->frame
.client
->decorations
& Decor_Titlebar
) {
745 paint(self
->title
, (client_focused(self
->frame
.client
) ?
746 self
->a_focused_title
:
747 self
->a_unfocused_title
),
748 0, 0, self
->width
, TITLE_HEIGHT
);
752 render_iconify(self
);
757 if (self
->frame
.client
->decorations
& Decor_Handle
) {
758 paint(self
->handle
, (client_focused(self
->frame
.client
) ?
759 self
->a_focused_handle
:
760 self
->a_unfocused_handle
),
761 GRIP_WIDTH
+ self
->bwidth
, 0,
762 HANDLE_WIDTH(self
), s_handle_height
);
763 paint(self
->lgrip
, (client_focused(self
->frame
.client
) ?
766 0, 0, GRIP_WIDTH
, s_handle_height
);
767 paint(self
->rgrip
, (client_focused(self
->frame
.client
) ?
770 0, 0, GRIP_WIDTH
, s_handle_height
);
774 static void render_label(ObFrame
*self
)
778 if (self
->label_x
< 0) return;
780 a
= (client_focused(self
->frame
.client
) ?
781 self
->a_focused_label
: self
->a_unfocused_label
);
783 /* set the texture's text! */
784 a
->texture
[0].data
.text
.string
= self
->frame
.client
->title
;
786 paint(self
->label
, a
, 0, 0, self
->label_width
, LABEL_HEIGHT
);
789 static void render_icon(ObFrame
*self
)
791 if (self
->icon_x
< 0) return;
793 /* XXX set the texture's icon picture! */
794 paint(self
->icon
, self
->a_icon
, 0, 0, BUTTON_SIZE
, BUTTON_SIZE
);
797 static void render_max(ObFrame
*self
)
799 gboolean press
= self
->max_press
||
800 self
->frame
.client
->max_vert
|| self
->frame
.client
->max_horz
;
802 if (self
->max_x
< 0) return;
804 paint(self
->max
, (client_focused(self
->frame
.client
) ?
806 a_focused_pressed_max
:
807 a_focused_unpressed_max
) :
809 a_unfocused_pressed_max
:
810 a_unfocused_unpressed_max
)),
811 0, 0, BUTTON_SIZE
, BUTTON_SIZE
);
814 static void render_iconify(ObFrame
*self
)
816 if (self
->iconify_x
< 0) return;
818 paint(self
->iconify
, (client_focused(self
->frame
.client
) ?
819 (self
->iconify_press
?
820 a_focused_pressed_iconify
:
821 a_focused_unpressed_iconify
) :
822 (self
->iconify_press
?
823 a_unfocused_pressed_iconify
:
824 a_unfocused_unpressed_iconify
)),
825 0, 0, BUTTON_SIZE
, BUTTON_SIZE
);
828 static void render_desk(ObFrame
*self
)
830 gboolean press
= self
->desk_press
||
831 self
->frame
.client
->desktop
== DESKTOP_ALL
;
833 if (self
->desk_x
< 0) return;
835 paint(self
->desk
, (client_focused(self
->frame
.client
) ?
837 a_focused_pressed_desk
:
838 a_focused_unpressed_desk
) :
840 a_unfocused_pressed_desk
:
841 a_unfocused_unpressed_desk
)),
842 0, 0, BUTTON_SIZE
, BUTTON_SIZE
);
845 static void render_close(ObFrame
*self
)
847 if (self
->close_x
< 0) return;
849 paint(self
->close
, (client_focused(self
->frame
.client
) ?
851 a_focused_pressed_close
:
852 a_focused_unpressed_close
) :
854 a_unfocused_pressed_close
:
855 a_unfocused_unpressed_close
)),
856 0, 0, BUTTON_SIZE
, BUTTON_SIZE
);
859 GQuark
get_context(Client
*client
, Window win
)
863 if (win
== ob_root
) return g_quark_try_string("root");
864 if (client
== NULL
) return g_quark_try_string("none");
865 if (win
== client
->window
) return g_quark_try_string("client");
867 self
= (ObFrame
*) client
->frame
;
868 if (win
== self
->frame
.window
) return g_quark_try_string("frame");
869 if (win
== self
->frame
.plate
) return g_quark_try_string("client");
870 if (win
== self
->title
) return g_quark_try_string("titlebar");
871 if (win
== self
->label
) return g_quark_try_string("titlebar");
872 if (win
== self
->handle
) return g_quark_try_string("handle");
873 if (win
== self
->lgrip
) return g_quark_try_string("blcorner");
874 if (win
== self
->rgrip
) return g_quark_try_string("brcorner");
875 if (win
== self
->max
) return g_quark_try_string("maximize");
876 if (win
== self
->iconify
) return g_quark_try_string("iconify");
877 if (win
== self
->close
) return g_quark_try_string("close");
878 if (win
== self
->icon
) return g_quark_try_string("icon");
879 if (win
== self
->desk
) return g_quark_try_string("alldesktops");
881 return g_quark_try_string("none");
884 static void frame_mouse_press(const ObEvent
*e
, ObFrame
*self
)
886 Window win
= e
->data
.x
.e
->xbutton
.window
;
887 if (win
== self
->max
) {
888 self
->max_press
= TRUE
;
890 } else if (win
== self
->close
) {
891 self
->close_press
= TRUE
;
893 } else if (win
== self
->iconify
) {
894 self
->iconify_press
= TRUE
;
895 render_iconify(self
);
896 } else if (win
== self
->desk
) {
897 self
->desk_press
= TRUE
;
902 static void frame_mouse_release(const ObEvent
*e
, ObFrame
*self
)
904 Window win
= e
->data
.x
.e
->xbutton
.window
;
905 if (win
== self
->max
) {
906 self
->max_press
= FALSE
;
908 } else if (win
== self
->close
) {
909 self
->close_press
= FALSE
;
911 } else if (win
== self
->iconify
) {
912 self
->iconify_press
= FALSE
;
913 render_iconify(self
);
914 } else if (win
== self
->desk
) {
915 self
->desk_press
= FALSE
;