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)
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 | \
28 EnterWindowMask | LeaveWindowMask)
30 /* style settings - geometry */
35 /* style settings - colors */
37 color_rgb
*s_cb_focused_color
;
38 color_rgb
*s_cb_unfocused_color
;
39 color_rgb
*s_title_focused_color
;
40 color_rgb
*s_title_unfocused_color
;
41 color_rgb
*s_titlebut_focused_color
;
42 color_rgb
*s_titlebut_unfocused_color
;
43 /* style settings - fonts */
46 int s_winfont_shadow_offset
;
48 /* style settings - masks */
49 pixmap_mask
*s_max_mask
;
50 pixmap_mask
*s_icon_mask
;
51 pixmap_mask
*s_desk_mask
;
52 pixmap_mask
*s_close_mask
;
54 /* global appearances */
55 Appearance
*a_focused_unpressed_max
;
56 Appearance
*a_focused_pressed_max
;
57 Appearance
*a_unfocused_unpressed_max
;
58 Appearance
*a_unfocused_pressed_max
;
59 Appearance
*a_focused_unpressed_close
;
60 Appearance
*a_focused_pressed_close
;
61 Appearance
*a_unfocused_unpressed_close
;
62 Appearance
*a_unfocused_pressed_close
;
63 Appearance
*a_focused_unpressed_desk
;
64 Appearance
*a_focused_pressed_desk
;
65 Appearance
*a_unfocused_unpressed_desk
;
66 Appearance
*a_unfocused_pressed_desk
;
67 Appearance
*a_focused_unpressed_iconify
;
68 Appearance
*a_focused_pressed_iconify
;
69 Appearance
*a_unfocused_unpressed_iconify
;
70 Appearance
*a_unfocused_pressed_iconify
;
71 Appearance
*a_focused_grip
;
72 Appearance
*a_unfocused_grip
;
73 Appearance
*a_focused_title
;
74 Appearance
*a_unfocused_title
;
75 Appearance
*a_focused_label
;
76 Appearance
*a_unfocused_label
;
77 Appearance
*a_icon
; /* always parentrelative, so no focused/unfocused */
78 Appearance
*a_focused_handle
;
79 Appearance
*a_unfocused_handle
;
81 typedef struct ObFrame
{
95 Appearance
*a_unfocused_title
;
96 Appearance
*a_focused_title
;
97 Appearance
*a_unfocused_label
;
98 Appearance
*a_focused_label
;
100 Appearance
*a_unfocused_handle
;
101 Appearance
*a_focused_handle
;
107 int width
; /* title and handle */
109 int icon_x
; /* x-position of the window icon button */
110 int label_x
; /* x-position of the window title */
111 int iconify_x
; /* x-position of the window iconify button */
112 int desk_x
; /* x-position of the window all-desktops button */
113 int max_x
; /* x-position of the window maximize button */
114 int close_x
; /* x-position of the window close button */
115 int bwidth
; /* border width */
116 int cbwidth
; /* client border width */
119 gboolean close_press
;
121 gboolean iconify_press
;
124 static void layout_title(ObFrame
*self
);
125 static void render(ObFrame
*self
);
126 static void render_label(ObFrame
*self
);
127 static void render_max(ObFrame
*self
);
128 static void render_icon(ObFrame
*self
);
129 static void render_iconify(ObFrame
*self
);
130 static void render_desk(ObFrame
*self
);
131 static void render_close(ObFrame
*self
);
133 static void frame_mouse_press(const ObEvent
*e
, ObFrame
*self
);
134 static void frame_mouse_release(const ObEvent
*e
, ObFrame
*self
);
138 g_quark_from_string("none");
139 g_quark_from_string("root");
140 g_quark_from_string("client");
141 g_quark_from_string("titlebar");
142 g_quark_from_string("handle");
143 g_quark_from_string("frame");
144 g_quark_from_string("blcorner");
145 g_quark_from_string("brcorner");
146 g_quark_from_string("maximize");
147 g_quark_from_string("alldesktops");
148 g_quark_from_string("iconify");
149 g_quark_from_string("icon");
150 g_quark_from_string("close");
152 s_b_color
= s_cb_unfocused_color
= s_cb_focused_color
=
153 s_title_unfocused_color
= s_title_focused_color
=
154 s_titlebut_unfocused_color
= s_titlebut_focused_color
= NULL
;
156 s_max_mask
= s_icon_mask
= s_desk_mask
= s_close_mask
= NULL
;
158 a_focused_unpressed_max
= appearance_new(Surface_Planar
, 1);
159 a_focused_pressed_max
= appearance_new(Surface_Planar
, 1);
160 a_unfocused_unpressed_max
= appearance_new(Surface_Planar
, 1);
161 a_unfocused_pressed_max
= appearance_new(Surface_Planar
, 1);
162 a_focused_unpressed_close
= NULL
;
163 a_focused_pressed_close
= NULL
;
164 a_unfocused_unpressed_close
= NULL
;
165 a_unfocused_pressed_close
= NULL
;
166 a_focused_unpressed_desk
= NULL
;
167 a_focused_pressed_desk
= NULL
;
168 a_unfocused_unpressed_desk
= NULL
;
169 a_unfocused_pressed_desk
= NULL
;
170 a_focused_unpressed_iconify
= NULL
;
171 a_focused_pressed_iconify
= NULL
;
172 a_unfocused_unpressed_iconify
= NULL
;
173 a_unfocused_pressed_iconify
= NULL
;
174 a_focused_grip
= appearance_new(Surface_Planar
, 0);
175 a_unfocused_grip
= appearance_new(Surface_Planar
, 0);
176 a_focused_title
= appearance_new(Surface_Planar
, 0);
177 a_unfocused_title
= appearance_new(Surface_Planar
, 0);
178 a_focused_label
= appearance_new(Surface_Planar
, 1);
179 a_unfocused_label
= appearance_new(Surface_Planar
, 1);
180 a_icon
= appearance_new(Surface_Planar
, 0);/*1);*/
181 a_focused_handle
= appearance_new(Surface_Planar
, 0);
182 a_unfocused_handle
= appearance_new(Surface_Planar
, 0);
189 if (s_b_color
!= NULL
) color_free(s_b_color
);
190 if (s_cb_unfocused_color
!= NULL
) color_free(s_cb_unfocused_color
);
191 if (s_cb_focused_color
!= NULL
) color_free(s_cb_focused_color
);
192 if (s_title_unfocused_color
!= NULL
) color_free(s_title_unfocused_color
);
193 if (s_title_focused_color
!= NULL
) color_free(s_title_focused_color
);
194 if (s_titlebut_unfocused_color
!= NULL
)
195 color_free(s_titlebut_unfocused_color
);
196 if (s_titlebut_focused_color
!= NULL
)
197 color_free(s_titlebut_focused_color
);
199 if (s_max_mask
!= NULL
) pixmap_mask_free(s_max_mask
);
200 if (s_desk_mask
!= NULL
) pixmap_mask_free(s_desk_mask
);
201 if (s_icon_mask
!= NULL
) pixmap_mask_free(s_icon_mask
);
202 if (s_close_mask
!= NULL
) pixmap_mask_free(s_close_mask
);
204 if (s_winfont
!= NULL
) font_close(s_winfont
);
206 appearance_free(a_focused_unpressed_max
);
207 appearance_free(a_focused_pressed_max
);
208 appearance_free(a_unfocused_unpressed_max
);
209 appearance_free(a_unfocused_pressed_max
);
210 if (a_focused_unpressed_close
!= NULL
)
211 appearance_free(a_focused_unpressed_close
);
212 if (a_focused_pressed_close
!= NULL
)
213 appearance_free(a_focused_pressed_close
);
214 if (a_unfocused_unpressed_close
!= NULL
)
215 appearance_free(a_unfocused_unpressed_close
);
216 if (a_unfocused_pressed_close
!= NULL
)
217 appearance_free(a_unfocused_pressed_close
);
218 if (a_focused_unpressed_desk
!= NULL
)
219 appearance_free(a_focused_unpressed_desk
);
220 if (a_focused_pressed_desk
!= NULL
)
221 appearance_free(a_focused_pressed_desk
);
222 if (a_unfocused_unpressed_desk
!= NULL
)
223 appearance_free(a_unfocused_unpressed_desk
);
224 if (a_unfocused_pressed_desk
!= NULL
)
225 appearance_free(a_unfocused_pressed_desk
);
226 if (a_focused_unpressed_iconify
!= NULL
)
227 appearance_free(a_focused_unpressed_iconify
);
228 if (a_focused_pressed_iconify
!= NULL
)
229 appearance_free(a_focused_pressed_iconify
);
230 if (a_unfocused_unpressed_iconify
!= NULL
)
231 appearance_free(a_unfocused_unpressed_iconify
);
232 if (a_unfocused_pressed_iconify
!= NULL
)
233 appearance_free(a_unfocused_pressed_iconify
);
234 appearance_free(a_focused_grip
);
235 appearance_free(a_unfocused_grip
);
236 appearance_free(a_focused_title
);
237 appearance_free(a_unfocused_title
);
238 appearance_free(a_focused_label
);
239 appearance_free(a_unfocused_label
);
240 appearance_free(a_icon
);
241 appearance_free(a_focused_handle
);
242 appearance_free(a_unfocused_handle
);
245 static Window
createWindow(Window parent
, unsigned long mask
,
246 XSetWindowAttributes
*attrib
)
248 return XCreateWindow(ob_display
, parent
, 0, 0, 1, 1, 0,
249 render_depth
, InputOutput
, render_visual
,
256 XSetWindowAttributes attrib
;
260 self
= g_new(ObFrame
, 1);
262 self
->frame
.visible
= FALSE
;
264 /* create all of the decor windows */
265 mask
= CWOverrideRedirect
| CWEventMask
;
266 attrib
.event_mask
= FRAME_EVENTMASK
;
267 attrib
.override_redirect
= TRUE
;
268 self
->frame
.window
= createWindow(ob_root
, mask
, &attrib
);
271 self
->frame
.plate
= createWindow(self
->frame
.window
, mask
, &attrib
);
274 attrib
.event_mask
= ELEMENT_EVENTMASK
;
275 self
->title
= createWindow(self
->frame
.window
, mask
, &attrib
);
276 self
->label
= createWindow(self
->title
, mask
, &attrib
);
277 self
->max
= createWindow(self
->title
, mask
, &attrib
);
278 self
->close
= createWindow(self
->title
, mask
, &attrib
);
279 self
->desk
= createWindow(self
->title
, mask
, &attrib
);
280 self
->icon
= createWindow(self
->title
, mask
, &attrib
);
281 self
->iconify
= createWindow(self
->title
, mask
, &attrib
);
282 self
->handle
= createWindow(self
->frame
.window
, mask
, &attrib
);
284 attrib
.cursor
= ob_cursors
.ll_angle
;
285 self
->lgrip
= createWindow(self
->handle
, mask
, &attrib
);
286 attrib
.cursor
= ob_cursors
.lr_angle
;
287 self
->rgrip
= createWindow(self
->handle
, mask
, &attrib
);
289 /* the other stuff is shown based on decor settings */
290 XMapWindow(ob_display
, self
->frame
.plate
);
291 XMapWindow(ob_display
, self
->lgrip
);
292 XMapWindow(ob_display
, self
->rgrip
);
293 XMapWindow(ob_display
, self
->label
);
295 /* set colors/appearance/sizes for stuff that doesn't change */
296 XSetWindowBorder(ob_display
, self
->frame
.window
, s_b_color
->pixel
);
297 XSetWindowBorder(ob_display
, self
->label
, s_b_color
->pixel
);
298 XSetWindowBorder(ob_display
, self
->rgrip
, s_b_color
->pixel
);
299 XSetWindowBorder(ob_display
, self
->lgrip
, s_b_color
->pixel
);
301 XResizeWindow(ob_display
, self
->max
, BUTTON_SIZE
, BUTTON_SIZE
);
302 XResizeWindow(ob_display
, self
->iconify
, BUTTON_SIZE
, BUTTON_SIZE
);
303 XResizeWindow(ob_display
, self
->icon
, BUTTON_SIZE
, BUTTON_SIZE
);
304 XResizeWindow(ob_display
, self
->close
, BUTTON_SIZE
, BUTTON_SIZE
);
305 XResizeWindow(ob_display
, self
->desk
, BUTTON_SIZE
, BUTTON_SIZE
);
306 XResizeWindow(ob_display
, self
->lgrip
, GRIP_WIDTH
, s_handle_height
);
307 XResizeWindow(ob_display
, self
->rgrip
, GRIP_WIDTH
, s_handle_height
);
309 /* set up the dynamic appearances */
310 self
->a_unfocused_title
= appearance_copy(a_unfocused_title
);
311 self
->a_focused_title
= appearance_copy(a_focused_title
);
312 self
->a_unfocused_label
= appearance_copy(a_unfocused_label
);
313 self
->a_focused_label
= appearance_copy(a_focused_label
);
314 self
->a_unfocused_handle
= appearance_copy(a_unfocused_handle
);
315 self
->a_focused_handle
= appearance_copy(a_focused_handle
);
316 self
->a_icon
= appearance_copy(a_icon
);
318 self
->max_press
= self
->close_press
= self
->desk_press
=
319 self
->iconify_press
= FALSE
;
321 dispatch_register(Event_X_ButtonPress
, (EventHandler
)frame_mouse_press
,
323 dispatch_register(Event_X_ButtonRelease
, (EventHandler
)frame_mouse_release
,
329 static void frame_free(ObFrame
*self
)
331 appearance_free(self
->a_unfocused_title
);
332 appearance_free(self
->a_focused_title
);
333 appearance_free(self
->a_unfocused_label
);
334 appearance_free(self
->a_focused_label
);
335 appearance_free(self
->a_unfocused_handle
);
336 appearance_free(self
->a_focused_handle
);
337 appearance_free(self
->a_icon
);
339 XDestroyWindow(ob_display
, self
->frame
.window
);
341 dispatch_register(0, (EventHandler
)frame_mouse_press
, self
);
342 dispatch_register(0, (EventHandler
)frame_mouse_release
, self
);
347 void frame_show(ObFrame
*self
)
349 if (!self
->frame
.visible
) {
350 self
->frame
.visible
= TRUE
;
351 XMapWindow(ob_display
, self
->frame
.window
);
355 void frame_hide(ObFrame
*self
)
357 if (self
->frame
.visible
) {
358 self
->frame
.visible
= FALSE
;
359 self
->frame
.client
->ignore_unmaps
++;
360 XUnmapWindow(ob_display
, self
->frame
.window
);
364 void frame_adjust_shape(ObFrame
*self
)
370 if (!self
->frame
.client
->shaped
) {
371 /* clear the shape on the frame window */
372 XShapeCombineMask(ob_display
, self
->frame
.window
, ShapeBounding
,
373 self
->innersize
.left
,
377 /* make the frame's shape match the clients */
378 XShapeCombineShape(ob_display
, self
->frame
.window
, ShapeBounding
,
379 self
->innersize
.left
,
381 self
->frame
.client
->window
,
382 ShapeBounding
, ShapeSet
);
385 if (self
->frame
.client
->decorations
& Decor_Titlebar
) {
386 xrect
[0].x
= -s_bevel
;
387 xrect
[0].y
= -s_bevel
;
388 xrect
[0].width
= self
->width
+ self
->bwidth
* 2;
389 xrect
[0].height
= TITLE_HEIGHT
+
394 if (self
->frame
.client
->decorations
& Decor_Handle
) {
395 xrect
[1].x
= -s_bevel
;
396 xrect
[1].y
= HANDLE_Y(self
);
397 xrect
[1].width
= self
->width
+ self
->bwidth
* 2;
398 xrect
[1].height
= s_handle_height
+
403 XShapeCombineRectangles(ob_display
, self
->frame
.window
,
404 ShapeBounding
, 0, 0, xrect
, num
,
405 ShapeUnion
, Unsorted
);
410 void frame_adjust_area(ObFrame
*self
)
412 if (self
->frame
.client
->decorations
& Decor_Border
) {
413 self
->bwidth
= s_bwidth
;
414 self
->cbwidth
= s_cbwidth
;
416 self
->bwidth
= self
->cbwidth
= 0;
418 STRUT_SET(self
->innersize
, self
->cbwidth
, self
->cbwidth
,
419 self
->cbwidth
, self
->cbwidth
);
420 self
->width
= self
->frame
.client
->area
.width
+ self
->cbwidth
* 2;
421 g_assert(self
->width
> 0);
423 /* set border widths */
424 XSetWindowBorderWidth(ob_display
, self
->frame
.plate
, self
->cbwidth
);
425 XSetWindowBorderWidth(ob_display
, self
->frame
.window
, self
->bwidth
);
426 XSetWindowBorderWidth(ob_display
, self
->title
, self
->bwidth
);
427 XSetWindowBorderWidth(ob_display
, self
->handle
, self
->bwidth
);
428 XSetWindowBorderWidth(ob_display
, self
->lgrip
, self
->bwidth
);
429 XSetWindowBorderWidth(ob_display
, self
->rgrip
, self
->bwidth
);
431 /* position/size and map/unmap all the windows */
433 /* they all default off, they're turned on in layout_title */
441 if (self
->frame
.client
->decorations
& Decor_Titlebar
) {
442 XMoveResizeWindow(ob_display
, self
->title
,
443 -self
->bwidth
, -self
->bwidth
,
444 self
->width
, TITLE_HEIGHT
);
445 self
->innersize
.top
+= TITLE_HEIGHT
+ self
->bwidth
;
446 XMapWindow(ob_display
, self
->title
);
448 /* layout the title bar elements */
451 XUnmapWindow(ob_display
, self
->title
);
452 /* make all the titlebar stuff not render */
453 self
->frame
.client
->decorations
&= ~(Decor_Icon
| Decor_Iconify
|
454 Decor_Maximize
| Decor_Close
|
458 if (self
->frame
.client
->decorations
& Decor_Handle
) {
459 XMoveResizeWindow(ob_display
, self
->handle
,
460 -self
->bwidth
, HANDLE_Y(self
),
461 self
->width
, s_handle_height
);
462 XMoveWindow(ob_display
, self
->lgrip
,
463 -self
->bwidth
, -self
->bwidth
);
464 XMoveWindow(ob_display
, self
->rgrip
,
465 -self
->bwidth
+ self
->width
-
466 GRIP_WIDTH
, -self
->bwidth
);
467 self
->innersize
.bottom
+= s_handle_height
+
469 XMapWindow(ob_display
, self
->handle
);
471 XUnmapWindow(ob_display
, self
->handle
);
473 /* find the new coordinates */
474 self
->frame
.area
.x
= self
->frame
.client
->area
.x
;
475 self
->frame
.area
.y
= self
->frame
.client
->area
.y
;
476 frame_client_gravity((Frame
*)self
,
477 &self
->frame
.area
.x
, &self
->frame
.area
.y
);
478 /* move and resize the top level frame */
479 XMoveResizeWindow(ob_display
, self
->frame
.window
,
480 self
->frame
.area
.x
, self
->frame
.area
.y
,
482 (self
->frame
.client
->shaded
? TITLE_HEIGHT
:
483 self
->innersize
.top
+ self
->innersize
.bottom
+
484 self
->frame
.client
->area
.height
));
486 /* move and resize the plate */
487 XMoveResizeWindow(ob_display
, self
->frame
.plate
,
488 self
->innersize
.left
- self
->cbwidth
,
489 self
->innersize
.top
- self
->cbwidth
,
490 self
->frame
.client
->area
.width
,
491 self
->frame
.client
->area
.height
);
492 /* when the client has StaticGravity, it likes to move around. */
493 XMoveWindow(ob_display
, self
->frame
.client
->window
, 0, 0);
495 STRUT_SET(self
->frame
.size
,
496 self
->innersize
.left
+ self
->bwidth
,
497 self
->innersize
.top
+ self
->bwidth
,
498 self
->innersize
.right
+ self
->bwidth
,
499 self
->innersize
.bottom
+ self
->bwidth
);
501 RECT_SET_SIZE(self
->frame
.area
,
502 self
->frame
.client
->area
.width
+
503 self
->frame
.size
.left
+ self
->frame
.size
.right
,
504 self
->frame
.client
->area
.height
+
505 self
->frame
.size
.top
+ self
->frame
.size
.bottom
);
509 frame_adjust_shape(self
);
512 void frame_adjust_state(ObFrame
*self
)
518 void frame_adjust_focus(ObFrame
*self
)
523 void frame_adjust_title(ObFrame
*self
)
528 void frame_adjust_icon(ObFrame
*self
)
533 void frame_grab_client(ObFrame
*self
, Client
*client
)
535 self
->frame
.client
= client
;
537 /* reparent the client to the frame */
538 XReparentWindow(ob_display
, client
->window
, self
->frame
.plate
, 0, 0);
540 When reparenting the client window, it is usually not mapped yet, since
541 this occurs from a MapRequest. However, in the case where Openbox is
542 starting up, the window is already mapped, so we'll see unmap events for
543 it. There are 2 unmap events generated that we see, one with the 'event'
544 member set the root window, and one set to the client, but both get
545 handled and need to be ignored.
547 if (ob_state
== State_Starting
)
548 client
->ignore_unmaps
+= 2;
550 /* select the event mask on the client's parent (to receive config/map
551 req's) the ButtonPress is to catch clicks on the client border */
552 XSelectInput(ob_display
, self
->frame
.plate
, PLATE_EVENTMASK
);
554 /* map the client so it maps when the frame does */
555 XMapWindow(ob_display
, client
->window
);
557 frame_adjust_area(self
);
559 /* set all the windows for the frame in the client_map */
560 g_hash_table_insert(client_map
, (gpointer
)self
->frame
.window
, client
);
561 g_hash_table_insert(client_map
, (gpointer
)self
->frame
.plate
, client
);
562 g_hash_table_insert(client_map
, (gpointer
)self
->title
, client
);
563 g_hash_table_insert(client_map
, (gpointer
)self
->label
, client
);
564 g_hash_table_insert(client_map
, (gpointer
)self
->max
, client
);
565 g_hash_table_insert(client_map
, (gpointer
)self
->close
, client
);
566 g_hash_table_insert(client_map
, (gpointer
)self
->desk
, client
);
567 g_hash_table_insert(client_map
, (gpointer
)self
->icon
, client
);
568 g_hash_table_insert(client_map
, (gpointer
)self
->iconify
, client
);
569 g_hash_table_insert(client_map
, (gpointer
)self
->handle
, client
);
570 g_hash_table_insert(client_map
, (gpointer
)self
->lgrip
, client
);
571 g_hash_table_insert(client_map
, (gpointer
)self
->rgrip
, client
);
574 void frame_release_client(ObFrame
*self
, Client
*client
)
578 g_assert(self
->frame
.client
== client
);
580 /* check if the app has already reparented its window away */
581 if (XCheckTypedWindowEvent(ob_display
, client
->window
,
582 ReparentNotify
, &ev
)) {
583 XPutBackEvent(ob_display
, &ev
);
584 /* re-map the window since the unmanaging process unmaps it */
585 XMapWindow(ob_display
, client
->window
);
587 /* according to the ICCCM - if the client doesn't reparent itself,
588 then we will reparent the window to root for them */
589 XReparentWindow(ob_display
, client
->window
, ob_root
,
594 /* remove all the windows for the frame from the client_map */
595 g_hash_table_remove(client_map
, &self
->frame
.window
);
596 g_hash_table_remove(client_map
, &self
->frame
.plate
);
597 g_hash_table_remove(client_map
, &self
->title
);
598 g_hash_table_remove(client_map
, &self
->label
);
599 g_hash_table_remove(client_map
, &self
->max
);
600 g_hash_table_remove(client_map
, &self
->close
);
601 g_hash_table_remove(client_map
, &self
->desk
);
602 g_hash_table_remove(client_map
, &self
->icon
);
603 g_hash_table_remove(client_map
, &self
->iconify
);
604 g_hash_table_remove(client_map
, &self
->handle
);
605 g_hash_table_remove(client_map
, &self
->lgrip
);
606 g_hash_table_remove(client_map
, &self
->rgrip
);
611 static void layout_title(ObFrame
*self
)
615 gboolean n
, d
, i
, l
, m
,c
;
618 n
= d
= i
= l
= m
= c
= FALSE
;
620 if (!config_get("titlebar.layout", Config_String
, &layout
)) {
621 layout
.string
= "NDLIMC";
622 config_set("titlebar.layout", Config_String
, layout
);
625 /* figure out whats being shown, and the width of the label */
626 self
->label_width
= self
->width
- (s_bevel
+ 1) * 2;
627 for (lc
= layout
.string
; *lc
!= '\0'; ++lc
) {
630 if (!(self
->frame
.client
->decorations
& Decor_Icon
)) break;
632 self
->label_width
-= BUTTON_SIZE
+ s_bevel
+ 1;
635 if (!(self
->frame
.client
->decorations
& Decor_AllDesktops
)) break;
637 self
->label_width
-= BUTTON_SIZE
+ s_bevel
+ 1;
640 if (!(self
->frame
.client
->decorations
& Decor_Iconify
)) break;
642 self
->label_width
-= BUTTON_SIZE
+ s_bevel
+ 1;
648 if (!(self
->frame
.client
->decorations
& Decor_Maximize
)) break;
650 self
->label_width
-= BUTTON_SIZE
+ s_bevel
+ 1;
653 if (!(self
->frame
.client
->decorations
& Decor_Close
)) break;
655 self
->label_width
-= BUTTON_SIZE
+ s_bevel
+ 1;
659 if (self
->label_width
< 1) self
->label_width
= 1;
661 XResizeWindow(ob_display
, self
->label
, self
->label_width
,
664 if (!n
) XUnmapWindow(ob_display
, self
->icon
);
665 if (!d
) XUnmapWindow(ob_display
, self
->desk
);
666 if (!i
) XUnmapWindow(ob_display
, self
->iconify
);
667 if (!l
) XUnmapWindow(ob_display
, self
->label
);
668 if (!m
) XUnmapWindow(ob_display
, self
->max
);
669 if (!c
) XUnmapWindow(ob_display
, self
->close
);
672 for (lc
= layout
.string
; *lc
!= '\0'; ++lc
) {
677 XMapWindow(ob_display
, self
->icon
);
678 XMoveWindow(ob_display
, self
->icon
, x
, s_bevel
+ 1);
679 x
+= BUTTON_SIZE
+ s_bevel
+ 1;
684 XMapWindow(ob_display
, self
->desk
);
685 XMoveWindow(ob_display
, self
->desk
, x
, s_bevel
+ 1);
686 x
+= BUTTON_SIZE
+ s_bevel
+ 1;
691 XMapWindow(ob_display
, self
->iconify
);
692 XMoveWindow(ob_display
, self
->iconify
, x
, s_bevel
+ 1);
693 x
+= BUTTON_SIZE
+ s_bevel
+ 1;
698 XMapWindow(ob_display
, self
->label
);
699 XMoveWindow(ob_display
, self
->label
, x
, s_bevel
);
700 x
+= self
->label_width
+ s_bevel
+ 1;
705 XMapWindow(ob_display
, self
->max
);
706 XMoveWindow(ob_display
, self
->max
, x
, s_bevel
+ 1);
707 x
+= BUTTON_SIZE
+ s_bevel
+ 1;
712 XMapWindow(ob_display
, self
->close
);
713 XMoveWindow(ob_display
, self
->close
, x
, s_bevel
+ 1);
714 x
+= BUTTON_SIZE
+ s_bevel
+ 1;
720 static void render(ObFrame
*self
)
722 if (client_focused(self
->frame
.client
)) {
723 XSetWindowBorder(ob_display
, self
->frame
.plate
,
724 s_cb_focused_color
->pixel
);
726 XSetWindowBorder(ob_display
, self
->frame
.plate
,
727 s_cb_unfocused_color
->pixel
);
730 if (self
->frame
.client
->decorations
& Decor_Titlebar
) {
731 paint(self
->title
, (client_focused(self
->frame
.client
) ?
732 self
->a_focused_title
:
733 self
->a_unfocused_title
),
734 0, 0, self
->width
, TITLE_HEIGHT
);
738 render_iconify(self
);
743 if (self
->frame
.client
->decorations
& Decor_Handle
) {
744 paint(self
->handle
, (client_focused(self
->frame
.client
) ?
745 self
->a_focused_handle
:
746 self
->a_unfocused_handle
),
747 GRIP_WIDTH
+ self
->bwidth
, 0,
748 HANDLE_WIDTH(self
), s_handle_height
);
749 paint(self
->lgrip
, (client_focused(self
->frame
.client
) ?
752 0, 0, GRIP_WIDTH
, s_handle_height
);
753 paint(self
->rgrip
, (client_focused(self
->frame
.client
) ?
756 0, 0, GRIP_WIDTH
, s_handle_height
);
760 static void render_label(ObFrame
*self
)
764 if (self
->label_x
< 0) return;
766 a
= (client_focused(self
->frame
.client
) ?
767 self
->a_focused_label
: self
->a_unfocused_label
);
769 /* set the texture's text! */
770 a
->texture
[0].data
.text
.string
= self
->frame
.client
->title
;
772 paint(self
->label
, a
, 0, 0, self
->label_width
, LABEL_HEIGHT
);
775 static void render_icon(ObFrame
*self
)
777 if (self
->icon_x
< 0) return;
779 /* XXX set the texture's icon picture! */
780 paint(self
->icon
, self
->a_icon
, 0, 0, BUTTON_SIZE
, BUTTON_SIZE
);
783 static void render_max(ObFrame
*self
)
785 gboolean press
= self
->max_press
||
786 self
->frame
.client
->max_vert
|| self
->frame
.client
->max_horz
;
788 if (self
->max_x
< 0) return;
790 paint(self
->max
, (client_focused(self
->frame
.client
) ?
792 a_focused_pressed_max
:
793 a_focused_unpressed_max
) :
795 a_unfocused_pressed_max
:
796 a_unfocused_unpressed_max
)),
797 0, 0, BUTTON_SIZE
, BUTTON_SIZE
);
800 static void render_iconify(ObFrame
*self
)
802 if (self
->iconify_x
< 0) return;
804 paint(self
->iconify
, (client_focused(self
->frame
.client
) ?
805 (self
->iconify_press
?
806 a_focused_pressed_iconify
:
807 a_focused_unpressed_iconify
) :
808 (self
->iconify_press
?
809 a_unfocused_pressed_iconify
:
810 a_unfocused_unpressed_iconify
)),
811 0, 0, BUTTON_SIZE
, BUTTON_SIZE
);
814 static void render_desk(ObFrame
*self
)
816 gboolean press
= self
->desk_press
||
817 self
->frame
.client
->desktop
== DESKTOP_ALL
;
819 if (self
->desk_x
< 0) return;
821 paint(self
->desk
, (client_focused(self
->frame
.client
) ?
823 a_focused_pressed_desk
:
824 a_focused_unpressed_desk
) :
826 a_unfocused_pressed_desk
:
827 a_unfocused_unpressed_desk
)),
828 0, 0, BUTTON_SIZE
, BUTTON_SIZE
);
831 static void render_close(ObFrame
*self
)
833 if (self
->close_x
< 0) return;
835 paint(self
->close
, (client_focused(self
->frame
.client
) ?
837 a_focused_pressed_close
:
838 a_focused_unpressed_close
) :
840 a_unfocused_pressed_close
:
841 a_unfocused_unpressed_close
)),
842 0, 0, BUTTON_SIZE
, BUTTON_SIZE
);
845 GQuark
get_context(Client
*client
, Window win
)
849 if (win
== ob_root
) return g_quark_try_string("root");
850 if (client
== NULL
) return g_quark_try_string("none");
851 if (win
== client
->window
) return g_quark_try_string("client");
853 self
= (ObFrame
*) client
->frame
;
854 if (win
== self
->frame
.window
) return g_quark_try_string("frame");
855 if (win
== self
->frame
.plate
) return g_quark_try_string("client");
856 if (win
== self
->title
) return g_quark_try_string("titlebar");
857 if (win
== self
->label
) return g_quark_try_string("titlebar");
858 if (win
== self
->handle
) return g_quark_try_string("handle");
859 if (win
== self
->lgrip
) return g_quark_try_string("blcorner");
860 if (win
== self
->rgrip
) return g_quark_try_string("brcorner");
861 if (win
== self
->max
) return g_quark_try_string("maximize");
862 if (win
== self
->iconify
) return g_quark_try_string("iconify");
863 if (win
== self
->close
) return g_quark_try_string("close");
864 if (win
== self
->icon
) return g_quark_try_string("icon");
865 if (win
== self
->desk
) return g_quark_try_string("alldesktops");
867 return g_quark_try_string("none");
870 static void frame_mouse_press(const ObEvent
*e
, ObFrame
*self
)
872 Window win
= e
->data
.x
.e
->xbutton
.window
;
873 if (win
== self
->max
) {
874 self
->max_press
= TRUE
;
876 } else if (win
== self
->close
) {
877 self
->close_press
= TRUE
;
879 } else if (win
== self
->iconify
) {
880 self
->iconify_press
= TRUE
;
881 render_iconify(self
);
882 } else if (win
== self
->desk
) {
883 self
->desk_press
= TRUE
;
888 static void frame_mouse_release(const ObEvent
*e
, ObFrame
*self
)
890 Window win
= e
->data
.x
.e
->xbutton
.window
;
891 if (win
== self
->max
) {
892 self
->max_press
= FALSE
;
894 } else if (win
== self
->close
) {
895 self
->close_press
= FALSE
;
897 } else if (win
== self
->iconify
) {
898 self
->iconify_press
= FALSE
;
899 render_iconify(self
);
900 } else if (win
== self
->desk
) {
901 self
->desk_press
= FALSE
;