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
)
411 if (self
->frame
.client
->decorations
& Decor_Border
) {
412 self
->bwidth
= s_bwidth
;
413 self
->cbwidth
= s_cbwidth
;
415 self
->bwidth
= self
->cbwidth
= 0;
417 STRUT_SET(self
->innersize
, self
->cbwidth
, self
->cbwidth
,
418 self
->cbwidth
, self
->cbwidth
);
419 self
->width
= self
->frame
.client
->area
.width
+ self
->cbwidth
* 2;
420 g_assert(self
->width
> 0);
422 /* set border widths */
423 XSetWindowBorderWidth(ob_display
, self
->frame
.plate
, self
->cbwidth
);
424 XSetWindowBorderWidth(ob_display
, self
->frame
.window
, self
->bwidth
);
425 XSetWindowBorderWidth(ob_display
, self
->title
, self
->bwidth
);
426 XSetWindowBorderWidth(ob_display
, self
->handle
, self
->bwidth
);
427 XSetWindowBorderWidth(ob_display
, self
->lgrip
, self
->bwidth
);
428 XSetWindowBorderWidth(ob_display
, self
->rgrip
, self
->bwidth
);
430 /* position/size and map/unmap all the windows */
432 /* they all default off, they're turned on in layout_title */
440 if (self
->frame
.client
->decorations
& Decor_Titlebar
) {
441 XMoveResizeWindow(ob_display
, self
->title
,
442 -self
->bwidth
, -self
->bwidth
,
443 self
->width
, TITLE_HEIGHT
);
444 self
->innersize
.top
+= TITLE_HEIGHT
+ self
->bwidth
;
445 XMapWindow(ob_display
, self
->title
);
447 /* layout the title bar elements */
450 XUnmapWindow(ob_display
, self
->title
);
451 /* make all the titlebar stuff not render */
452 self
->frame
.client
->decorations
&= ~(Decor_Icon
| Decor_Iconify
|
453 Decor_Maximize
| Decor_Close
|
457 if (self
->frame
.client
->decorations
& Decor_Handle
) {
458 XMoveResizeWindow(ob_display
, self
->handle
,
459 -self
->bwidth
, HANDLE_Y(self
),
460 self
->width
, s_handle_height
);
461 XMoveWindow(ob_display
, self
->lgrip
,
462 -self
->bwidth
, -self
->bwidth
);
463 XMoveWindow(ob_display
, self
->rgrip
,
464 -self
->bwidth
+ self
->width
-
465 GRIP_WIDTH
, -self
->bwidth
);
466 self
->innersize
.bottom
+= s_handle_height
+
468 XMapWindow(ob_display
, self
->handle
);
470 XUnmapWindow(ob_display
, self
->handle
);
472 /* find the new coordinates */
473 self
->frame
.area
.x
= self
->frame
.client
->area
.x
;
474 self
->frame
.area
.y
= self
->frame
.client
->area
.y
;
475 frame_client_gravity((Frame
*)self
,
476 &self
->frame
.area
.x
, &self
->frame
.area
.y
);
477 /* move and resize the top level frame */
478 XMoveResizeWindow(ob_display
, self
->frame
.window
,
479 self
->frame
.area
.x
, self
->frame
.area
.y
,
481 (self
->frame
.client
->shaded
? TITLE_HEIGHT
:
482 self
->innersize
.top
+ self
->innersize
.bottom
+
483 self
->frame
.client
->area
.height
));
485 /* move and resize the plate */
486 XMoveResizeWindow(ob_display
, self
->frame
.plate
,
487 self
->innersize
.left
- self
->cbwidth
,
488 self
->innersize
.top
- self
->cbwidth
,
489 self
->frame
.client
->area
.width
,
490 self
->frame
.client
->area
.height
);
491 /* when the client has StaticGravity, it likes to move around. */
492 XMoveWindow(ob_display
, self
->frame
.client
->window
, 0, 0);
494 STRUT_SET(self
->frame
.size
,
495 self
->innersize
.left
+ self
->bwidth
,
496 self
->innersize
.top
+ self
->bwidth
,
497 self
->innersize
.right
+ self
->bwidth
,
498 self
->innersize
.bottom
+ self
->bwidth
);
500 RECT_SET_SIZE(self
->frame
.area
,
501 self
->frame
.client
->area
.width
+
502 self
->frame
.size
.left
+ self
->frame
.size
.right
,
503 self
->frame
.client
->area
.height
+
504 self
->frame
.size
.top
+ self
->frame
.size
.bottom
);
508 frame_adjust_shape(self
);
511 void frame_adjust_state(ObFrame
*self
)
517 void frame_adjust_focus(ObFrame
*self
)
522 void frame_adjust_title(ObFrame
*self
)
527 void frame_adjust_icon(ObFrame
*self
)
532 void frame_grab_client(ObFrame
*self
, Client
*client
)
534 self
->frame
.client
= client
;
536 /* reparent the client to the frame */
537 XReparentWindow(ob_display
, client
->window
, self
->frame
.plate
, 0, 0);
539 When reparenting the client window, it is usually not mapped yet, since
540 this occurs from a MapRequest. However, in the case where Openbox is
541 starting up, the window is already mapped, so we'll see unmap events for
542 it. There are 2 unmap events generated that we see, one with the 'event'
543 member set the root window, and one set to the client, but both get
544 handled and need to be ignored.
546 if (ob_state
== State_Starting
)
547 client
->ignore_unmaps
+= 2;
549 /* select the event mask on the client's parent (to receive config/map
550 req's) the ButtonPress is to catch clicks on the client border */
551 XSelectInput(ob_display
, self
->frame
.plate
, PLATE_EVENTMASK
);
553 /* map the client so it maps when the frame does */
554 XMapWindow(ob_display
, client
->window
);
556 frame_adjust_area(self
);
558 /* set all the windows for the frame in the client_map */
559 g_hash_table_insert(client_map
, (gpointer
)self
->frame
.window
, client
);
560 g_hash_table_insert(client_map
, (gpointer
)self
->frame
.plate
, client
);
561 g_hash_table_insert(client_map
, (gpointer
)self
->title
, client
);
562 g_hash_table_insert(client_map
, (gpointer
)self
->label
, client
);
563 g_hash_table_insert(client_map
, (gpointer
)self
->max
, client
);
564 g_hash_table_insert(client_map
, (gpointer
)self
->close
, client
);
565 g_hash_table_insert(client_map
, (gpointer
)self
->desk
, client
);
566 g_hash_table_insert(client_map
, (gpointer
)self
->icon
, client
);
567 g_hash_table_insert(client_map
, (gpointer
)self
->iconify
, client
);
568 g_hash_table_insert(client_map
, (gpointer
)self
->handle
, client
);
569 g_hash_table_insert(client_map
, (gpointer
)self
->lgrip
, client
);
570 g_hash_table_insert(client_map
, (gpointer
)self
->rgrip
, client
);
573 void frame_release_client(ObFrame
*self
, Client
*client
)
577 g_assert(self
->frame
.client
== client
);
579 /* check if the app has already reparented its window away */
580 if (XCheckTypedWindowEvent(ob_display
, client
->window
,
581 ReparentNotify
, &ev
)) {
582 XPutBackEvent(ob_display
, &ev
);
583 /* re-map the window since the unmanaging process unmaps it */
584 XMapWindow(ob_display
, client
->window
);
586 /* according to the ICCCM - if the client doesn't reparent itself,
587 then we will reparent the window to root for them */
588 XReparentWindow(ob_display
, client
->window
, ob_root
,
593 /* remove all the windows for the frame from the client_map */
594 g_hash_table_remove(client_map
, (gpointer
)self
->frame
.window
);
595 g_hash_table_remove(client_map
, (gpointer
)self
->frame
.plate
);
596 g_hash_table_remove(client_map
, (gpointer
)self
->title
);
597 g_hash_table_remove(client_map
, (gpointer
)self
->label
);
598 g_hash_table_remove(client_map
, (gpointer
)self
->max
);
599 g_hash_table_remove(client_map
, (gpointer
)self
->close
);
600 g_hash_table_remove(client_map
, (gpointer
)self
->desk
);
601 g_hash_table_remove(client_map
, (gpointer
)self
->icon
);
602 g_hash_table_remove(client_map
, (gpointer
)self
->iconify
);
603 g_hash_table_remove(client_map
, (gpointer
)self
->handle
);
604 g_hash_table_remove(client_map
, (gpointer
)self
->lgrip
);
605 g_hash_table_remove(client_map
, (gpointer
)self
->rgrip
);
610 static void layout_title(ObFrame
*self
)
614 gboolean n
, d
, i
, l
, m
,c
;
617 n
= d
= i
= l
= m
= c
= FALSE
;
619 if (!config_get("titlebar.layout", Config_String
, &layout
)) {
620 layout
.string
= "NDLIMC";
621 config_set("titlebar.layout", Config_String
, layout
);
624 /* figure out whats being shown, and the width of the label */
625 self
->label_width
= self
->width
- (s_bevel
+ 1) * 2;
626 for (lc
= layout
.string
; *lc
!= '\0'; ++lc
) {
629 if (!(self
->frame
.client
->decorations
& Decor_Icon
)) break;
631 self
->label_width
-= BUTTON_SIZE
+ s_bevel
+ 1;
634 if (!(self
->frame
.client
->decorations
& Decor_AllDesktops
)) break;
636 self
->label_width
-= BUTTON_SIZE
+ s_bevel
+ 1;
639 if (!(self
->frame
.client
->decorations
& Decor_Iconify
)) break;
641 self
->label_width
-= BUTTON_SIZE
+ s_bevel
+ 1;
647 if (!(self
->frame
.client
->decorations
& Decor_Maximize
)) break;
649 self
->label_width
-= BUTTON_SIZE
+ s_bevel
+ 1;
652 if (!(self
->frame
.client
->decorations
& Decor_Close
)) break;
654 self
->label_width
-= BUTTON_SIZE
+ s_bevel
+ 1;
658 if (self
->label_width
< 1) self
->label_width
= 1;
660 XResizeWindow(ob_display
, self
->label
, self
->label_width
,
663 if (!n
) XUnmapWindow(ob_display
, self
->icon
);
664 if (!d
) XUnmapWindow(ob_display
, self
->desk
);
665 if (!i
) XUnmapWindow(ob_display
, self
->iconify
);
666 if (!l
) XUnmapWindow(ob_display
, self
->label
);
667 if (!m
) XUnmapWindow(ob_display
, self
->max
);
668 if (!c
) XUnmapWindow(ob_display
, self
->close
);
671 for (lc
= layout
.string
; *lc
!= '\0'; ++lc
) {
676 XMapWindow(ob_display
, self
->icon
);
677 XMoveWindow(ob_display
, self
->icon
, x
, s_bevel
+ 1);
678 x
+= BUTTON_SIZE
+ s_bevel
+ 1;
683 XMapWindow(ob_display
, self
->desk
);
684 XMoveWindow(ob_display
, self
->desk
, x
, s_bevel
+ 1);
685 x
+= BUTTON_SIZE
+ s_bevel
+ 1;
690 XMapWindow(ob_display
, self
->iconify
);
691 XMoveWindow(ob_display
, self
->iconify
, x
, s_bevel
+ 1);
692 x
+= BUTTON_SIZE
+ s_bevel
+ 1;
697 XMapWindow(ob_display
, self
->label
);
698 XMoveWindow(ob_display
, self
->label
, x
, s_bevel
);
699 x
+= self
->label_width
+ s_bevel
+ 1;
704 XMapWindow(ob_display
, self
->max
);
705 XMoveWindow(ob_display
, self
->max
, x
, s_bevel
+ 1);
706 x
+= BUTTON_SIZE
+ s_bevel
+ 1;
711 XMapWindow(ob_display
, self
->close
);
712 XMoveWindow(ob_display
, self
->close
, x
, s_bevel
+ 1);
713 x
+= BUTTON_SIZE
+ s_bevel
+ 1;
719 static void render(ObFrame
*self
)
721 if (client_focused(self
->frame
.client
)) {
722 XSetWindowBorder(ob_display
, self
->frame
.plate
,
723 s_cb_focused_color
->pixel
);
725 XSetWindowBorder(ob_display
, self
->frame
.plate
,
726 s_cb_unfocused_color
->pixel
);
729 if (self
->frame
.client
->decorations
& Decor_Titlebar
) {
730 paint(self
->title
, (client_focused(self
->frame
.client
) ?
731 self
->a_focused_title
:
732 self
->a_unfocused_title
),
733 0, 0, self
->width
, TITLE_HEIGHT
);
737 render_iconify(self
);
742 if (self
->frame
.client
->decorations
& Decor_Handle
) {
743 paint(self
->handle
, (client_focused(self
->frame
.client
) ?
744 self
->a_focused_handle
:
745 self
->a_unfocused_handle
),
746 GRIP_WIDTH
+ self
->bwidth
, 0,
747 HANDLE_WIDTH(self
), s_handle_height
);
748 paint(self
->lgrip
, (client_focused(self
->frame
.client
) ?
751 0, 0, GRIP_WIDTH
, s_handle_height
);
752 paint(self
->rgrip
, (client_focused(self
->frame
.client
) ?
755 0, 0, GRIP_WIDTH
, s_handle_height
);
759 static void render_label(ObFrame
*self
)
763 if (self
->label_x
< 0) return;
765 a
= (client_focused(self
->frame
.client
) ?
766 self
->a_focused_label
: self
->a_unfocused_label
);
768 /* set the texture's text! */
769 a
->texture
[0].data
.text
.string
= self
->frame
.client
->title
;
771 paint(self
->label
, a
, 0, 0, self
->label_width
, LABEL_HEIGHT
);
774 static void render_icon(ObFrame
*self
)
776 if (self
->icon_x
< 0) return;
778 /* XXX set the texture's icon picture! */
779 paint(self
->icon
, self
->a_icon
, 0, 0, BUTTON_SIZE
, BUTTON_SIZE
);
782 static void render_max(ObFrame
*self
)
784 gboolean press
= self
->max_press
||
785 self
->frame
.client
->max_vert
|| self
->frame
.client
->max_horz
;
787 if (self
->max_x
< 0) return;
789 paint(self
->max
, (client_focused(self
->frame
.client
) ?
791 a_focused_pressed_max
:
792 a_focused_unpressed_max
) :
794 a_unfocused_pressed_max
:
795 a_unfocused_unpressed_max
)),
796 0, 0, BUTTON_SIZE
, BUTTON_SIZE
);
799 static void render_iconify(ObFrame
*self
)
801 if (self
->iconify_x
< 0) return;
803 paint(self
->iconify
, (client_focused(self
->frame
.client
) ?
804 (self
->iconify_press
?
805 a_focused_pressed_iconify
:
806 a_focused_unpressed_iconify
) :
807 (self
->iconify_press
?
808 a_unfocused_pressed_iconify
:
809 a_unfocused_unpressed_iconify
)),
810 0, 0, BUTTON_SIZE
, BUTTON_SIZE
);
813 static void render_desk(ObFrame
*self
)
815 gboolean press
= self
->desk_press
||
816 self
->frame
.client
->desktop
== DESKTOP_ALL
;
818 if (self
->desk_x
< 0) return;
820 paint(self
->desk
, (client_focused(self
->frame
.client
) ?
822 a_focused_pressed_desk
:
823 a_focused_unpressed_desk
) :
825 a_unfocused_pressed_desk
:
826 a_unfocused_unpressed_desk
)),
827 0, 0, BUTTON_SIZE
, BUTTON_SIZE
);
830 static void render_close(ObFrame
*self
)
832 if (self
->close_x
< 0) return;
834 paint(self
->close
, (client_focused(self
->frame
.client
) ?
836 a_focused_pressed_close
:
837 a_focused_unpressed_close
) :
839 a_unfocused_pressed_close
:
840 a_unfocused_unpressed_close
)),
841 0, 0, BUTTON_SIZE
, BUTTON_SIZE
);
844 GQuark
get_context(Client
*client
, Window win
)
848 if (win
== ob_root
) return g_quark_try_string("root");
849 if (client
== NULL
) return g_quark_try_string("none");
850 if (win
== client
->window
) return g_quark_try_string("client");
852 self
= (ObFrame
*) client
->frame
;
853 if (win
== self
->frame
.window
) return g_quark_try_string("frame");
854 if (win
== self
->frame
.plate
) return g_quark_try_string("client");
855 if (win
== self
->title
) return g_quark_try_string("titlebar");
856 if (win
== self
->label
) return g_quark_try_string("titlebar");
857 if (win
== self
->handle
) return g_quark_try_string("handle");
858 if (win
== self
->lgrip
) return g_quark_try_string("blcorner");
859 if (win
== self
->rgrip
) return g_quark_try_string("brcorner");
860 if (win
== self
->max
) return g_quark_try_string("maximize");
861 if (win
== self
->iconify
) return g_quark_try_string("iconify");
862 if (win
== self
->close
) return g_quark_try_string("close");
863 if (win
== self
->icon
) return g_quark_try_string("icon");
864 if (win
== self
->desk
) return g_quark_try_string("alldesktops");
866 return g_quark_try_string("none");
869 static void frame_mouse_press(const ObEvent
*e
, ObFrame
*self
)
871 Window win
= e
->data
.x
.e
->xbutton
.window
;
872 if (win
== self
->max
) {
873 self
->max_press
= TRUE
;
875 } else if (win
== self
->close
) {
876 self
->close_press
= TRUE
;
878 } else if (win
== self
->iconify
) {
879 self
->iconify_press
= TRUE
;
880 render_iconify(self
);
881 } else if (win
== self
->desk
) {
882 self
->desk_press
= TRUE
;
887 static void frame_mouse_release(const ObEvent
*e
, ObFrame
*self
)
889 Window win
= e
->data
.x
.e
->xbutton
.window
;
890 if (win
== self
->max
) {
891 self
->max_press
= FALSE
;
893 } else if (win
== self
->close
) {
894 self
->close_press
= FALSE
;
896 } else if (win
== self
->iconify
) {
897 self
->iconify_press
= FALSE
;
898 render_iconify(self
);
899 } else if (win
== self
->desk
) {
900 self
->desk_press
= FALSE
;