2 #include "../../kernel/openbox.h"
3 #include "../../kernel/screen.h"
4 #include "../../kernel/extensions.h"
5 #include "../../kernel/dispatch.h"
6 #include "../../kernel/themerc.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)
27 /* style settings - geometry */
32 /* style settings - colors */
34 color_rgb
*s_cb_focused_color
;
35 color_rgb
*s_cb_unfocused_color
;
36 color_rgb
*s_title_focused_color
;
37 color_rgb
*s_title_unfocused_color
;
38 color_rgb
*s_titlebut_focused_color
;
39 color_rgb
*s_titlebut_unfocused_color
;
40 /* style settings - fonts */
43 int s_winfont_shadow_offset
;
45 /* style settings - masks */
46 pixmap_mask
*s_max_mask
;
47 pixmap_mask
*s_icon_mask
;
48 pixmap_mask
*s_desk_mask
;
49 pixmap_mask
*s_close_mask
;
51 /* global appearances */
52 Appearance
*a_focused_unpressed_max
;
53 Appearance
*a_focused_pressed_max
;
54 Appearance
*a_unfocused_unpressed_max
;
55 Appearance
*a_unfocused_pressed_max
;
56 Appearance
*a_focused_unpressed_close
;
57 Appearance
*a_focused_pressed_close
;
58 Appearance
*a_unfocused_unpressed_close
;
59 Appearance
*a_unfocused_pressed_close
;
60 Appearance
*a_focused_unpressed_desk
;
61 Appearance
*a_focused_pressed_desk
;
62 Appearance
*a_unfocused_unpressed_desk
;
63 Appearance
*a_unfocused_pressed_desk
;
64 Appearance
*a_focused_unpressed_iconify
;
65 Appearance
*a_focused_pressed_iconify
;
66 Appearance
*a_unfocused_unpressed_iconify
;
67 Appearance
*a_unfocused_pressed_iconify
;
68 Appearance
*a_focused_grip
;
69 Appearance
*a_unfocused_grip
;
70 Appearance
*a_focused_title
;
71 Appearance
*a_unfocused_title
;
72 Appearance
*a_focused_label
;
73 Appearance
*a_unfocused_label
;
74 Appearance
*a_icon
; /* always parentrelative, so no focused/unfocused */
75 Appearance
*a_focused_handle
;
76 Appearance
*a_unfocused_handle
;
78 typedef struct ObFrame
{
92 Appearance
*a_unfocused_title
;
93 Appearance
*a_focused_title
;
94 Appearance
*a_unfocused_label
;
95 Appearance
*a_focused_label
;
97 Appearance
*a_unfocused_handle
;
98 Appearance
*a_focused_handle
;
104 int width
; /* title and handle */
106 int icon_x
; /* x-position of the window icon button */
107 int label_x
; /* x-position of the window title */
108 int iconify_x
; /* x-position of the window iconify button */
109 int desk_x
; /* x-position of the window all-desktops button */
110 int max_x
; /* x-position of the window maximize button */
111 int close_x
; /* x-position of the window close button */
112 int bwidth
; /* border width */
113 int cbwidth
; /* client border width */
116 gboolean close_press
;
118 gboolean iconify_press
;
121 static void layout_title(ObFrame
*self
);
122 static void render(ObFrame
*self
);
123 static void render_label(ObFrame
*self
);
124 static void render_max(ObFrame
*self
);
125 static void render_icon(ObFrame
*self
);
126 static void render_iconify(ObFrame
*self
);
127 static void render_desk(ObFrame
*self
);
128 static void render_close(ObFrame
*self
);
130 static void frame_mouse_press(const ObEvent
*e
, ObFrame
*self
);
131 static void frame_mouse_release(const ObEvent
*e
, ObFrame
*self
);
135 g_quark_from_string("none");
136 g_quark_from_string("root");
137 g_quark_from_string("client");
138 g_quark_from_string("titlebar");
139 g_quark_from_string("handle");
140 g_quark_from_string("frame");
141 g_quark_from_string("blcorner");
142 g_quark_from_string("brcorner");
143 g_quark_from_string("maximize");
144 g_quark_from_string("alldesktops");
145 g_quark_from_string("iconify");
146 g_quark_from_string("icon");
147 g_quark_from_string("close");
149 s_b_color
= s_cb_unfocused_color
= s_cb_focused_color
=
150 s_title_unfocused_color
= s_title_focused_color
=
151 s_titlebut_unfocused_color
= s_titlebut_focused_color
= NULL
;
153 s_max_mask
= s_icon_mask
= s_desk_mask
= s_close_mask
= NULL
;
155 a_focused_unpressed_max
= appearance_new(Surface_Planar
, 1);
156 a_focused_pressed_max
= appearance_new(Surface_Planar
, 1);
157 a_unfocused_unpressed_max
= appearance_new(Surface_Planar
, 1);
158 a_unfocused_pressed_max
= appearance_new(Surface_Planar
, 1);
159 a_focused_unpressed_close
= NULL
;
160 a_focused_pressed_close
= NULL
;
161 a_unfocused_unpressed_close
= NULL
;
162 a_unfocused_pressed_close
= NULL
;
163 a_focused_unpressed_desk
= NULL
;
164 a_focused_pressed_desk
= NULL
;
165 a_unfocused_unpressed_desk
= NULL
;
166 a_unfocused_pressed_desk
= NULL
;
167 a_focused_unpressed_iconify
= NULL
;
168 a_focused_pressed_iconify
= NULL
;
169 a_unfocused_unpressed_iconify
= NULL
;
170 a_unfocused_pressed_iconify
= NULL
;
171 a_focused_grip
= appearance_new(Surface_Planar
, 0);
172 a_unfocused_grip
= appearance_new(Surface_Planar
, 0);
173 a_focused_title
= appearance_new(Surface_Planar
, 0);
174 a_unfocused_title
= appearance_new(Surface_Planar
, 0);
175 a_focused_label
= appearance_new(Surface_Planar
, 1);
176 a_unfocused_label
= appearance_new(Surface_Planar
, 1);
177 a_icon
= appearance_new(Surface_Planar
, 0);//1);
178 a_focused_handle
= appearance_new(Surface_Planar
, 0);
179 a_unfocused_handle
= appearance_new(Surface_Planar
, 0);
186 if (s_b_color
!= NULL
) color_free(s_b_color
);
187 if (s_cb_unfocused_color
!= NULL
) color_free(s_cb_unfocused_color
);
188 if (s_cb_focused_color
!= NULL
) color_free(s_cb_focused_color
);
189 if (s_title_unfocused_color
!= NULL
) color_free(s_title_unfocused_color
);
190 if (s_title_focused_color
!= NULL
) color_free(s_title_focused_color
);
191 if (s_titlebut_unfocused_color
!= NULL
)
192 color_free(s_titlebut_unfocused_color
);
193 if (s_titlebut_focused_color
!= NULL
)
194 color_free(s_titlebut_focused_color
);
196 if (s_max_mask
!= NULL
) pixmap_mask_free(s_max_mask
);
197 if (s_desk_mask
!= NULL
) pixmap_mask_free(s_desk_mask
);
198 if (s_icon_mask
!= NULL
) pixmap_mask_free(s_icon_mask
);
199 if (s_close_mask
!= NULL
) pixmap_mask_free(s_close_mask
);
201 if (s_winfont
!= NULL
) font_close(s_winfont
);
203 appearance_free(a_focused_unpressed_max
);
204 appearance_free(a_focused_pressed_max
);
205 appearance_free(a_unfocused_unpressed_max
);
206 appearance_free(a_unfocused_pressed_max
);
207 if (a_focused_unpressed_close
!= NULL
)
208 appearance_free(a_focused_unpressed_close
);
209 if (a_focused_pressed_close
!= NULL
)
210 appearance_free(a_focused_pressed_close
);
211 if (a_unfocused_unpressed_close
!= NULL
)
212 appearance_free(a_unfocused_unpressed_close
);
213 if (a_unfocused_pressed_close
!= NULL
)
214 appearance_free(a_unfocused_pressed_close
);
215 if (a_focused_unpressed_desk
!= NULL
)
216 appearance_free(a_focused_unpressed_desk
);
217 if (a_focused_pressed_desk
!= NULL
)
218 appearance_free(a_focused_pressed_desk
);
219 if (a_unfocused_unpressed_desk
!= NULL
)
220 appearance_free(a_unfocused_unpressed_desk
);
221 if (a_unfocused_pressed_desk
!= NULL
)
222 appearance_free(a_unfocused_pressed_desk
);
223 if (a_focused_unpressed_iconify
!= NULL
)
224 appearance_free(a_focused_unpressed_iconify
);
225 if (a_focused_pressed_iconify
!= NULL
)
226 appearance_free(a_focused_pressed_iconify
);
227 if (a_unfocused_unpressed_iconify
!= NULL
)
228 appearance_free(a_unfocused_unpressed_iconify
);
229 if (a_unfocused_pressed_iconify
!= NULL
)
230 appearance_free(a_unfocused_pressed_iconify
);
231 appearance_free(a_focused_grip
);
232 appearance_free(a_unfocused_grip
);
233 appearance_free(a_focused_title
);
234 appearance_free(a_unfocused_title
);
235 appearance_free(a_focused_label
);
236 appearance_free(a_unfocused_label
);
237 appearance_free(a_icon
);
238 appearance_free(a_focused_handle
);
239 appearance_free(a_unfocused_handle
);
242 static Window
createWindow(Window parent
, unsigned long mask
,
243 XSetWindowAttributes
*attrib
)
245 return XCreateWindow(ob_display
, parent
, 0, 0, 1, 1, 0,
246 render_depth
, InputOutput
, render_visual
,
253 XSetWindowAttributes attrib
;
257 self
= g_new(ObFrame
, 1);
259 self
->frame
.visible
= FALSE
;
261 /* create all of the decor windows */
262 mask
= CWOverrideRedirect
| CWEventMask
;
263 attrib
.event_mask
= FRAME_EVENTMASK
;
264 attrib
.override_redirect
= TRUE
;
265 self
->frame
.window
= createWindow(ob_root
, mask
, &attrib
);
268 self
->frame
.plate
= createWindow(self
->frame
.window
, mask
, &attrib
);
271 attrib
.event_mask
= (ButtonPressMask
| ButtonReleaseMask
|
272 ButtonMotionMask
| ExposureMask
);
273 self
->title
= createWindow(self
->frame
.window
, mask
, &attrib
);
274 self
->label
= createWindow(self
->title
, mask
, &attrib
);
275 self
->max
= createWindow(self
->title
, mask
, &attrib
);
276 self
->close
= createWindow(self
->title
, mask
, &attrib
);
277 self
->desk
= createWindow(self
->title
, mask
, &attrib
);
278 self
->icon
= createWindow(self
->title
, mask
, &attrib
);
279 self
->iconify
= createWindow(self
->title
, mask
, &attrib
);
280 self
->handle
= createWindow(self
->frame
.window
, mask
, &attrib
);
282 attrib
.cursor
= ob_cursors
.ll_angle
;
283 self
->lgrip
= createWindow(self
->handle
, mask
, &attrib
);
284 attrib
.cursor
= ob_cursors
.lr_angle
;
285 self
->rgrip
= createWindow(self
->handle
, mask
, &attrib
);
287 /* the other stuff is shown based on decor settings */
288 XMapWindow(ob_display
, self
->frame
.plate
);
289 XMapWindow(ob_display
, self
->lgrip
);
290 XMapWindow(ob_display
, self
->rgrip
);
291 XMapWindow(ob_display
, self
->label
);
293 /* set colors/appearance/sizes for stuff that doesn't change */
294 XSetWindowBorder(ob_display
, self
->frame
.window
, s_b_color
->pixel
);
295 XSetWindowBorder(ob_display
, self
->label
, s_b_color
->pixel
);
296 XSetWindowBorder(ob_display
, self
->rgrip
, s_b_color
->pixel
);
297 XSetWindowBorder(ob_display
, self
->lgrip
, s_b_color
->pixel
);
299 XResizeWindow(ob_display
, self
->max
, BUTTON_SIZE
, BUTTON_SIZE
);
300 XResizeWindow(ob_display
, self
->iconify
, BUTTON_SIZE
, BUTTON_SIZE
);
301 XResizeWindow(ob_display
, self
->icon
, BUTTON_SIZE
, BUTTON_SIZE
);
302 XResizeWindow(ob_display
, self
->close
, BUTTON_SIZE
, BUTTON_SIZE
);
303 XResizeWindow(ob_display
, self
->desk
, BUTTON_SIZE
, BUTTON_SIZE
);
304 XResizeWindow(ob_display
, self
->lgrip
, GRIP_WIDTH
, s_handle_height
);
305 XResizeWindow(ob_display
, self
->rgrip
, GRIP_WIDTH
, s_handle_height
);
307 /* set up the dynamic appearances */
308 self
->a_unfocused_title
= appearance_copy(a_unfocused_title
);
309 self
->a_focused_title
= appearance_copy(a_focused_title
);
310 self
->a_unfocused_label
= appearance_copy(a_unfocused_label
);
311 self
->a_focused_label
= appearance_copy(a_focused_label
);
312 self
->a_unfocused_handle
= appearance_copy(a_unfocused_handle
);
313 self
->a_focused_handle
= appearance_copy(a_focused_handle
);
314 self
->a_icon
= appearance_copy(a_icon
);
316 self
->max_press
= self
->close_press
= self
->desk_press
=
317 self
->iconify_press
= FALSE
;
319 dispatch_register(Event_X_ButtonPress
, (EventHandler
)frame_mouse_press
,
321 dispatch_register(Event_X_ButtonRelease
, (EventHandler
)frame_mouse_release
,
327 static void frame_free(ObFrame
*self
)
329 appearance_free(self
->a_unfocused_title
);
330 appearance_free(self
->a_focused_title
);
331 appearance_free(self
->a_unfocused_label
);
332 appearance_free(self
->a_focused_label
);
333 appearance_free(self
->a_unfocused_handle
);
334 appearance_free(self
->a_focused_handle
);
335 appearance_free(self
->a_icon
);
337 XDestroyWindow(ob_display
, self
->frame
.window
);
339 dispatch_register(0, (EventHandler
)frame_mouse_press
, self
);
340 dispatch_register(0, (EventHandler
)frame_mouse_release
, self
);
345 void frame_show(ObFrame
*self
)
347 if (!self
->frame
.visible
) {
348 self
->frame
.visible
= TRUE
;
349 XMapWindow(ob_display
, self
->frame
.window
);
353 void frame_hide(ObFrame
*self
)
355 if (self
->frame
.visible
) {
356 self
->frame
.visible
= FALSE
;
357 self
->frame
.client
->ignore_unmaps
++;
358 XUnmapWindow(ob_display
, self
->frame
.window
);
362 void frame_adjust_shape(ObFrame
*self
)
368 if (!self
->frame
.client
->shaped
) {
369 /* clear the shape on the frame window */
370 XShapeCombineMask(ob_display
, self
->frame
.window
, ShapeBounding
,
371 self
->innersize
.left
,
375 /* make the frame's shape match the clients */
376 XShapeCombineShape(ob_display
, self
->frame
.window
, ShapeBounding
,
377 self
->innersize
.left
,
379 self
->frame
.client
->window
,
380 ShapeBounding
, ShapeSet
);
383 if (self
->frame
.client
->decorations
& Decor_Titlebar
) {
384 xrect
[0].x
= -s_bevel
;
385 xrect
[0].y
= -s_bevel
;
386 xrect
[0].width
= self
->width
+ self
->bwidth
* 2;
387 xrect
[0].height
= TITLE_HEIGHT
+
392 if (self
->frame
.client
->decorations
& Decor_Handle
) {
393 xrect
[1].x
= -s_bevel
;
394 xrect
[1].y
= HANDLE_Y(self
);
395 xrect
[1].width
= self
->width
+ self
->bwidth
* 2;
396 xrect
[1].height
= s_handle_height
+
401 XShapeCombineRectangles(ob_display
, self
->frame
.window
,
402 ShapeBounding
, 0, 0, xrect
, num
,
403 ShapeUnion
, Unsorted
);
408 void frame_adjust_size(ObFrame
*self
)
410 if (self
->frame
.client
->decorations
& Decor_Border
) {
411 self
->bwidth
= s_bwidth
;
412 self
->cbwidth
= s_cbwidth
;
414 self
->bwidth
= self
->cbwidth
= 0;
416 STRUT_SET(self
->innersize
, self
->cbwidth
, self
->cbwidth
,
417 self
->cbwidth
, self
->cbwidth
);
418 self
->width
= self
->frame
.client
->area
.width
+ self
->cbwidth
* 2;
419 g_assert(self
->width
> 0);
421 /* set border widths */
422 XSetWindowBorderWidth(ob_display
, self
->frame
.plate
, self
->cbwidth
);
423 XSetWindowBorderWidth(ob_display
, self
->frame
.window
, self
->bwidth
);
424 XSetWindowBorderWidth(ob_display
, self
->title
, self
->bwidth
);
425 XSetWindowBorderWidth(ob_display
, self
->handle
, self
->bwidth
);
426 XSetWindowBorderWidth(ob_display
, self
->lgrip
, self
->bwidth
);
427 XSetWindowBorderWidth(ob_display
, self
->rgrip
, self
->bwidth
);
429 /* position/size and map/unmap all the windows */
431 if (self
->frame
.client
->decorations
& Decor_Titlebar
) {
432 XMoveResizeWindow(ob_display
, self
->title
,
433 -self
->bwidth
, -self
->bwidth
,
434 self
->width
, TITLE_HEIGHT
);
435 self
->innersize
.top
+= TITLE_HEIGHT
+ self
->bwidth
;
436 XMapWindow(ob_display
, self
->title
);
438 /* layout the title bar elements */
441 XUnmapWindow(ob_display
, self
->title
);
442 /* make all the titlebar stuff not render */
443 self
->frame
.client
->decorations
&= ~(Decor_Icon
| Decor_Iconify
|
444 Decor_Maximize
| Decor_Close
|
448 if (self
->frame
.client
->decorations
& Decor_Handle
) {
449 XMoveResizeWindow(ob_display
, self
->handle
,
450 -self
->bwidth
, HANDLE_Y(self
),
451 self
->width
, s_handle_height
);
452 XMoveWindow(ob_display
, self
->lgrip
,
453 -self
->bwidth
, -self
->bwidth
);
454 XMoveWindow(ob_display
, self
->rgrip
,
455 -self
->bwidth
+ self
->width
-
456 GRIP_WIDTH
, -self
->bwidth
);
457 self
->innersize
.bottom
+= s_handle_height
+
459 XMapWindow(ob_display
, self
->handle
);
461 XUnmapWindow(ob_display
, self
->handle
);
463 XResizeWindow(ob_display
, self
->frame
.window
, self
->width
,
464 (self
->frame
.client
->shaded
? TITLE_HEIGHT
:
465 self
->innersize
.top
+ self
->innersize
.bottom
+
466 self
->frame
.client
->area
.height
));
468 /* do this in two steps because clients whose gravity is set to
469 'Static' don't end up getting moved at all with an XMoveResizeWindow */
470 XMoveWindow(ob_display
, self
->frame
.plate
,
471 self
->innersize
.left
- self
->cbwidth
,
472 self
->innersize
.top
- self
->cbwidth
);
473 XResizeWindow(ob_display
, self
->frame
.plate
,
474 self
->frame
.client
->area
.width
,
475 self
->frame
.client
->area
.height
);
477 STRUT_SET(self
->frame
.size
,
478 self
->innersize
.left
+ self
->bwidth
,
479 self
->innersize
.top
+ self
->bwidth
,
480 self
->innersize
.right
+ self
->bwidth
,
481 self
->innersize
.bottom
+ self
->bwidth
);
483 RECT_SET_SIZE(self
->frame
.area
,
484 self
->frame
.client
->area
.width
+
485 self
->frame
.size
.left
+ self
->frame
.size
.right
,
486 self
->frame
.client
->area
.height
+
487 self
->frame
.size
.top
+ self
->frame
.size
.bottom
);
491 frame_adjust_shape(self
);
494 void frame_adjust_position(ObFrame
*self
)
496 self
->frame
.area
.x
= self
->frame
.client
->area
.x
;
497 self
->frame
.area
.y
= self
->frame
.client
->area
.y
;
498 frame_client_gravity((Frame
*)self
,
499 &self
->frame
.area
.x
, &self
->frame
.area
.y
);
500 XMoveWindow(ob_display
, self
->frame
.window
,
501 self
->frame
.area
.x
, self
->frame
.area
.y
);
504 void frame_adjust_state(ObFrame
*self
)
510 void frame_adjust_focus(ObFrame
*self
)
515 void frame_adjust_title(ObFrame
*self
)
520 void frame_adjust_icon(ObFrame
*self
)
525 void frame_grab_client(ObFrame
*self
, Client
*client
)
527 self
->frame
.client
= client
;
529 /* reparent the client to the frame */
530 XReparentWindow(ob_display
, client
->window
, self
->frame
.plate
, 0, 0);
532 When reparenting the client window, it is usually not mapped yet, since
533 this occurs from a MapRequest. However, in the case where Openbox is
534 starting up, the window is already mapped, so we'll see unmap events for
535 it. There are 2 unmap events generated that we see, one with the 'event'
536 member set the root window, and one set to the client, but both get
537 handled and need to be ignored.
539 if (ob_state
== State_Starting
)
540 client
->ignore_unmaps
+= 2;
542 /* select the event mask on the client's parent (to receive config/map
543 req's) the ButtonPress is to catch clicks on the client border */
544 XSelectInput(ob_display
, self
->frame
.plate
, PLATE_EVENTMASK
);
546 /* map the client so it maps when the frame does */
547 XMapWindow(ob_display
, client
->window
);
549 frame_adjust_size(self
);
550 frame_adjust_position(self
);
552 /* set all the windows for the frame in the client_map */
553 g_hash_table_insert(client_map
, (gpointer
)self
->frame
.window
, client
);
554 g_hash_table_insert(client_map
, (gpointer
)self
->frame
.plate
, client
);
555 g_hash_table_insert(client_map
, (gpointer
)self
->title
, client
);
556 g_hash_table_insert(client_map
, (gpointer
)self
->label
, client
);
557 g_hash_table_insert(client_map
, (gpointer
)self
->max
, client
);
558 g_hash_table_insert(client_map
, (gpointer
)self
->close
, client
);
559 g_hash_table_insert(client_map
, (gpointer
)self
->desk
, client
);
560 g_hash_table_insert(client_map
, (gpointer
)self
->icon
, client
);
561 g_hash_table_insert(client_map
, (gpointer
)self
->iconify
, client
);
562 g_hash_table_insert(client_map
, (gpointer
)self
->handle
, client
);
563 g_hash_table_insert(client_map
, (gpointer
)self
->lgrip
, client
);
564 g_hash_table_insert(client_map
, (gpointer
)self
->rgrip
, client
);
567 void frame_release_client(ObFrame
*self
, Client
*client
)
571 g_assert(self
->frame
.client
== client
);
573 /* check if the app has already reparented its window away */
574 if (XCheckTypedWindowEvent(ob_display
, client
->window
,
575 ReparentNotify
, &ev
)) {
576 XPutBackEvent(ob_display
, &ev
);
577 /* re-map the window since the unmanaging process unmaps it */
578 XMapWindow(ob_display
, client
->window
);
580 /* according to the ICCCM - if the client doesn't reparent itself,
581 then we will reparent the window to root for them */
582 XReparentWindow(ob_display
, client
->window
, ob_root
,
587 /* remove all the windows for the frame from the client_map */
588 g_hash_table_remove(client_map
, (gpointer
)self
->frame
.window
);
589 g_hash_table_remove(client_map
, (gpointer
)self
->frame
.plate
);
590 g_hash_table_remove(client_map
, (gpointer
)self
->title
);
591 g_hash_table_remove(client_map
, (gpointer
)self
->label
);
592 g_hash_table_remove(client_map
, (gpointer
)self
->max
);
593 g_hash_table_remove(client_map
, (gpointer
)self
->close
);
594 g_hash_table_remove(client_map
, (gpointer
)self
->desk
);
595 g_hash_table_remove(client_map
, (gpointer
)self
->icon
);
596 g_hash_table_remove(client_map
, (gpointer
)self
->iconify
);
597 g_hash_table_remove(client_map
, (gpointer
)self
->handle
);
598 g_hash_table_remove(client_map
, (gpointer
)self
->lgrip
);
599 g_hash_table_remove(client_map
, (gpointer
)self
->rgrip
);
604 static void layout_title(ObFrame
*self
)
608 gboolean n
, d
, i
, l
, m
,c
;
610 n
= d
= i
= l
= m
= c
= FALSE
;
612 /* figure out whats being shown, and the width of the label */
613 self
->label_width
= self
->width
- (s_bevel
+ 1) * 2;
614 for (lc
= themerc_titlebar_layout
; *lc
!= '\0'; ++lc
) {
617 if (!(self
->frame
.client
->decorations
& Decor_Icon
)) break;
619 self
->label_width
-= BUTTON_SIZE
+ s_bevel
+ 1;
622 if (!(self
->frame
.client
->decorations
& Decor_AllDesktops
)) break;
624 self
->label_width
-= BUTTON_SIZE
+ s_bevel
+ 1;
627 if (!(self
->frame
.client
->decorations
& Decor_Iconify
)) break;
629 self
->label_width
-= BUTTON_SIZE
+ s_bevel
+ 1;
635 if (!(self
->frame
.client
->decorations
& Decor_Maximize
)) break;
637 self
->label_width
-= BUTTON_SIZE
+ s_bevel
+ 1;
640 if (!(self
->frame
.client
->decorations
& Decor_Close
)) break;
642 self
->label_width
-= BUTTON_SIZE
+ s_bevel
+ 1;
646 if (self
->label_width
< 1) self
->label_width
= 1;
648 XResizeWindow(ob_display
, self
->label
, self
->label_width
,
652 self
->frame
.client
->decorations
&= ~Decor_Icon
;
653 XUnmapWindow(ob_display
, self
->icon
);
657 self
->frame
.client
->decorations
&= ~Decor_AllDesktops
;
658 XUnmapWindow(ob_display
, self
->desk
);
662 self
->frame
.client
->decorations
&= ~Decor_Iconify
;
663 XUnmapWindow(ob_display
, self
->iconify
);
667 XUnmapWindow(ob_display
, self
->label
);
671 self
->frame
.client
->decorations
&= ~Decor_Maximize
;
672 XUnmapWindow(ob_display
, self
->max
);
676 self
->frame
.client
->decorations
&= ~Decor_Close
;
677 XUnmapWindow(ob_display
, self
->close
);
682 for (lc
= themerc_titlebar_layout
; *lc
!= '\0'; ++lc
) {
687 XMapWindow(ob_display
, self
->icon
);
688 XMoveWindow(ob_display
, self
->icon
, x
, s_bevel
+ 1);
689 x
+= BUTTON_SIZE
+ s_bevel
+ 1;
694 XMapWindow(ob_display
, self
->desk
);
695 XMoveWindow(ob_display
, self
->desk
, x
, s_bevel
+ 1);
696 x
+= BUTTON_SIZE
+ s_bevel
+ 1;
701 XMapWindow(ob_display
, self
->iconify
);
702 XMoveWindow(ob_display
, self
->iconify
, x
, s_bevel
+ 1);
703 x
+= BUTTON_SIZE
+ s_bevel
+ 1;
708 XMapWindow(ob_display
, self
->label
);
709 XMoveWindow(ob_display
, self
->label
, x
, s_bevel
);
710 x
+= self
->label_width
+ s_bevel
+ 1;
715 XMapWindow(ob_display
, self
->max
);
716 XMoveWindow(ob_display
, self
->max
, x
, s_bevel
+ 1);
717 x
+= BUTTON_SIZE
+ s_bevel
+ 1;
722 XMapWindow(ob_display
, self
->close
);
723 XMoveWindow(ob_display
, self
->close
, x
, s_bevel
+ 1);
724 x
+= BUTTON_SIZE
+ s_bevel
+ 1;
730 static void render(ObFrame
*self
)
732 if (self
->frame
.client
->focused
) {
733 XSetWindowBorder(ob_display
, self
->frame
.plate
,
734 s_cb_focused_color
->pixel
);
736 XSetWindowBorder(ob_display
, self
->frame
.plate
,
737 s_cb_unfocused_color
->pixel
);
740 if (self
->frame
.client
->decorations
& Decor_Titlebar
) {
741 paint(self
->title
, (self
->frame
.client
->focused
?
742 self
->a_focused_title
:
743 self
->a_unfocused_title
),
744 0, 0, self
->width
, TITLE_HEIGHT
);
748 render_iconify(self
);
753 if (self
->frame
.client
->decorations
& Decor_Handle
) {
754 paint(self
->handle
, (self
->frame
.client
->focused
?
755 self
->a_focused_handle
:
756 self
->a_unfocused_handle
),
757 GRIP_WIDTH
+ self
->bwidth
, 0,
758 HANDLE_WIDTH(self
), s_handle_height
);
759 paint(self
->lgrip
, (self
->frame
.client
->focused
?
762 0, 0, GRIP_WIDTH
, s_handle_height
);
763 paint(self
->rgrip
, (self
->frame
.client
->focused
?
766 0, 0, GRIP_WIDTH
, s_handle_height
);
770 static void render_label(ObFrame
*self
)
774 if (self
->label_x
< 0) return;
776 a
= (self
->frame
.client
->focused
?
777 self
->a_focused_label
: self
->a_unfocused_label
);
779 /* set the texture's text! */
780 a
->texture
[0].data
.text
.string
= self
->frame
.client
->title
;
782 paint(self
->label
, a
, 0, 0, self
->label_width
, LABEL_HEIGHT
);
785 static void render_icon(ObFrame
*self
)
787 if (self
->icon_x
< 0) return;
789 /* XXX set the texture's icon picture! */
790 paint(self
->icon
, self
->a_icon
, 0, 0, BUTTON_SIZE
, BUTTON_SIZE
);
793 static void render_max(ObFrame
*self
)
795 gboolean press
= self
->max_press
||
796 self
->frame
.client
->max_vert
|| self
->frame
.client
->max_horz
;
798 if (self
->max_x
< 0) return;
800 paint(self
->max
, (self
->frame
.client
->focused
?
802 a_focused_pressed_max
:
803 a_focused_unpressed_max
) :
805 a_unfocused_pressed_max
:
806 a_unfocused_unpressed_max
)),
807 0, 0, BUTTON_SIZE
, BUTTON_SIZE
);
810 static void render_iconify(ObFrame
*self
)
812 if (self
->iconify_x
< 0) return;
814 paint(self
->iconify
, (self
->frame
.client
->focused
?
815 (self
->iconify_press
?
816 a_focused_pressed_iconify
:
817 a_focused_unpressed_iconify
) :
818 (self
->iconify_press
?
819 a_unfocused_pressed_iconify
:
820 a_unfocused_unpressed_iconify
)),
821 0, 0, BUTTON_SIZE
, BUTTON_SIZE
);
824 static void render_desk(ObFrame
*self
)
826 gboolean press
= self
->desk_press
||
827 self
->frame
.client
->desktop
== DESKTOP_ALL
;
829 if (self
->desk_x
< 0) return;
831 paint(self
->desk
, (self
->frame
.client
->focused
?
833 a_focused_pressed_desk
:
834 a_focused_unpressed_desk
) :
836 a_unfocused_pressed_desk
:
837 a_unfocused_unpressed_desk
)),
838 0, 0, BUTTON_SIZE
, BUTTON_SIZE
);
841 static void render_close(ObFrame
*self
)
843 if (self
->close_x
< 0) return;
845 paint(self
->close
, (self
->frame
.client
->focused
?
847 a_focused_pressed_close
:
848 a_focused_unpressed_close
) :
850 a_unfocused_pressed_close
:
851 a_unfocused_unpressed_close
)),
852 0, 0, BUTTON_SIZE
, BUTTON_SIZE
);
855 GQuark
get_context(Client
*client
, Window win
)
859 if (win
== ob_root
) return g_quark_try_string("root");
860 if (client
== NULL
) return g_quark_try_string("none");
861 if (win
== client
->window
) return g_quark_try_string("client");
863 self
= (ObFrame
*) client
->frame
;
864 if (win
== self
->frame
.window
) return g_quark_try_string("frame");
865 if (win
== self
->frame
.plate
) return g_quark_try_string("client");
866 if (win
== self
->title
) return g_quark_try_string("titlebar");
867 if (win
== self
->label
) return g_quark_try_string("titlebar");
868 if (win
== self
->handle
) return g_quark_try_string("handle");
869 if (win
== self
->lgrip
) return g_quark_try_string("blcorner");
870 if (win
== self
->rgrip
) return g_quark_try_string("brcorner");
871 if (win
== self
->max
) return g_quark_try_string("maximize");
872 if (win
== self
->iconify
) return g_quark_try_string("iconify");
873 if (win
== self
->close
) return g_quark_try_string("close");
874 if (win
== self
->icon
) return g_quark_try_string("icon");
875 if (win
== self
->desk
) return g_quark_try_string("alldesktops");
877 return g_quark_try_string("none");
880 static void frame_mouse_press(const ObEvent
*e
, ObFrame
*self
)
882 Window win
= e
->data
.x
.e
->xbutton
.window
;
883 if (win
== self
->max
) {
884 self
->max_press
= TRUE
;
886 } else if (win
== self
->close
) {
887 self
->close_press
= TRUE
;
889 } else if (win
== self
->iconify
) {
890 self
->iconify_press
= TRUE
;
891 render_iconify(self
);
892 } else if (win
== self
->desk
) {
893 self
->desk_press
= TRUE
;
898 static void frame_mouse_release(const ObEvent
*e
, ObFrame
*self
)
900 Window win
= e
->data
.x
.e
->xbutton
.window
;
901 if (win
== self
->max
) {
902 self
->max_press
= FALSE
;
904 } else if (win
== self
->close
) {
905 self
->close_press
= FALSE
;
907 } else if (win
== self
->iconify
) {
908 self
->iconify_press
= FALSE
;
909 render_iconify(self
);
910 } else if (win
== self
->desk
) {
911 self
->desk_press
= FALSE
;