3 #include "extensions.h"
6 #define PLATE_EVENTMASK (SubstructureRedirectMask | ButtonPressMask)
7 #define FRAME_EVENTMASK (EnterWindowMask | LeaveWindowMask)
9 static Window
createWindow(Window parent
, unsigned long mask
,
10 XSetWindowAttributes
*attrib
)
12 /* XXX DONT USE THE DEFAULT SHIT */
13 return XCreateWindow(ob_display
, parent
, 0, 0, 1, 1, 0,
14 DefaultDepth(ob_display
, ob_screen
), InputOutput
,
15 DefaultVisual(ob_display
, ob_screen
),
20 Frame
*frame_new(Client
*client
)
22 XSetWindowAttributes attrib
;
26 self
= g_new(Frame
, 1);
28 self
->client
= client
;
29 self
->visible
= FALSE
;
31 /* create all of the decor windows */
32 mask
= CWOverrideRedirect
| CWEventMask
;
33 attrib
.event_mask
= FRAME_EVENTMASK
;
34 attrib
.override_redirect
= TRUE
;
35 self
->window
= createWindow(ob_root
, mask
, &attrib
);
38 self
->plate
= createWindow(self
->window
, mask
, &attrib
);
40 attrib
.event_mask
= (ButtonPressMask
| ButtonReleaseMask
|
41 ButtonMotionMask
| ExposureMask
);
42 self
->title
= createWindow(self
->window
, mask
, &attrib
);
43 self
->label
= createWindow(self
->title
, mask
, &attrib
);
44 self
->max
= createWindow(self
->title
, mask
, &attrib
);
45 self
->close
= createWindow(self
->title
, mask
, &attrib
);
46 self
->desk
= createWindow(self
->title
, mask
, &attrib
);
47 self
->icon
= createWindow(self
->title
, mask
, &attrib
);
48 self
->iconify
= createWindow(self
->title
, mask
, &attrib
);
49 self
->handle
= createWindow(self
->window
, mask
, &attrib
);
51 attrib
.cursor
= ob_cursors
.ll_angle
;
52 self
->lgrip
= createWindow(self
->handle
, mask
, &attrib
);
53 attrib
.cursor
= ob_cursors
.lr_angle
;
54 self
->rgrip
= createWindow(self
->handle
, mask
, &attrib
);
56 /* the other stuff is shown based on decor settings */
57 XMapWindow(ob_display
, self
->plate
);
58 XMapWindow(ob_display
, self
->lgrip
);
59 XMapWindow(ob_display
, self
->rgrip
);
60 XMapWindow(ob_display
, self
->label
);
63 /* XXX TEMPORARY OF COURSE!@&*(@! */
65 XSetWindowBackground(ob_display
, self
->title
, 0x3333aa);
66 XSetWindowBackground(ob_display
, self
->handle
, 0x3333aa);
67 XSetWindowBackground(ob_display
, self
->lgrip
, 0x2233aa);
68 XSetWindowBackground(ob_display
, self
->rgrip
, 0x2233aa);
70 XSetWindowBorder(ob_display
, self
->window
, 0);
71 XSetWindowBorder(ob_display
, self
->label
, 0);
72 XSetWindowBorder(ob_display
, self
->rgrip
, 0);
73 XSetWindowBorder(ob_display
, self
->lgrip
, 0);
74 XSetWindowBorder(ob_display
, self
->plate
, 0x771122);
76 /* XXX /TEMPORARY OF COURSE!@&*(@! */
78 /* set all the windows for the frame in the client_map */
79 g_hash_table_insert(client_map
, (gpointer
)self
->window
, self
->client
);
80 g_hash_table_insert(client_map
, (gpointer
)self
->plate
, self
->client
);
81 g_hash_table_insert(client_map
, (gpointer
)self
->title
, self
->client
);
82 g_hash_table_insert(client_map
, (gpointer
)self
->label
, self
->client
);
83 g_hash_table_insert(client_map
, (gpointer
)self
->max
, self
->client
);
84 g_hash_table_insert(client_map
, (gpointer
)self
->close
, self
->client
);
85 g_hash_table_insert(client_map
, (gpointer
)self
->desk
, self
->client
);
86 g_hash_table_insert(client_map
, (gpointer
)self
->icon
, self
->client
);
87 g_hash_table_insert(client_map
, (gpointer
)self
->iconify
, self
->client
);
88 g_hash_table_insert(client_map
, (gpointer
)self
->handle
, self
->client
);
89 g_hash_table_insert(client_map
, (gpointer
)self
->lgrip
, self
->client
);
90 g_hash_table_insert(client_map
, (gpointer
)self
->rgrip
, self
->client
);
95 void frame_free(Frame
*self
)
97 /* remove all the windows for the frame from the client_map */
98 g_hash_table_remove(client_map
, (gpointer
)self
->window
);
99 g_hash_table_remove(client_map
, (gpointer
)self
->plate
);
100 g_hash_table_remove(client_map
, (gpointer
)self
->title
);
101 g_hash_table_remove(client_map
, (gpointer
)self
->label
);
102 g_hash_table_remove(client_map
, (gpointer
)self
->max
);
103 g_hash_table_remove(client_map
, (gpointer
)self
->close
);
104 g_hash_table_remove(client_map
, (gpointer
)self
->desk
);
105 g_hash_table_remove(client_map
, (gpointer
)self
->icon
);
106 g_hash_table_remove(client_map
, (gpointer
)self
->iconify
);
107 g_hash_table_remove(client_map
, (gpointer
)self
->handle
);
108 g_hash_table_remove(client_map
, (gpointer
)self
->lgrip
);
109 g_hash_table_remove(client_map
, (gpointer
)self
->rgrip
);
111 XDestroyWindow(ob_display
, self
->window
);
116 void frame_grab_client(Frame
*self
)
118 /* reparent the client to the frame */
119 XReparentWindow(ob_display
, self
->client
->window
, self
->plate
, 0, 0);
121 When reparenting the client window, it is usually not mapped yet, since
122 this occurs from a MapRequest. However, in the case where Openbox is
123 starting up, the window is already mapped, so we'll see unmap events for
124 it. There are 2 unmap events generated that we see, one with the 'event'
125 member set the root window, and one set to the client, but both get
126 handled and need to be ignored.
128 if (ob_state
== State_Starting
)
129 self
->client
->ignore_unmaps
+= 2;
131 /* select the event mask on the client's parent (to receive config/map
132 req's) the ButtonPress is to catch clicks on the client border */
133 XSelectInput(ob_display
, self
->plate
, PLATE_EVENTMASK
);
135 /* map the client so it maps when the frame does */
136 XMapWindow(ob_display
, self
->client
->window
);
138 frame_adjust_size(self
);
139 frame_adjust_position(self
);
142 void frame_release_client(Frame
*self
)
146 /* check if the app has already reparented its window away */
147 if (XCheckTypedWindowEvent(ob_display
, self
->client
->window
,
148 ReparentNotify
, &ev
)) {
149 XPutBackEvent(ob_display
, &ev
);
150 /* re-map the window since the unmanaging process unmaps it */
151 XMapWindow(ob_display
, self
->client
->window
);
153 /* according to the ICCCM - if the client doesn't reparent itself,
154 then we will reparent the window to root for them */
155 XReparentWindow(ob_display
, self
->client
->window
, ob_root
,
156 self
->client
->area
.x
, self
->client
->area
.y
);
160 void frame_show(Frame
*self
)
162 if (!self
->visible
) {
163 self
->visible
= TRUE
;
164 XMapWindow(ob_display
, self
->window
);
165 LOGICALHOOK(WindowShow
, g_quark_try_string("client"), self
->client
);
169 void frame_hide(Frame
*self
)
172 self
->visible
= FALSE
;
173 self
->client
->ignore_unmaps
++;
174 XUnmapWindow(ob_display
, self
->window
);
175 LOGICALHOOK(WindowHide
, g_quark_try_string("client"), self
->client
);
179 void frame_adjust_size(Frame
*self
)
181 self
->decorations
= self
->client
->decorations
;
183 /* XXX set shit from the style */
184 self
->geom
.font_height
= 10;
185 self
->geom
.bevel
= 1;
186 self
->geom
.button_size
= self
->geom
.font_height
- 2;
187 self
->geom
.handle_height
= 2;
188 self
->geom
.grip_width
= self
->geom
.button_size
* 2;
189 XResizeWindow(ob_display
, self
->lgrip
, self
->geom
.grip_width
,
190 self
->geom
.handle_height
);
191 XResizeWindow(ob_display
, self
->rgrip
, self
->geom
.grip_width
,
192 self
->geom
.handle_height
);
197 if (self
->decorations
& Decor_Border
) {
198 self
->geom
.bwidth
= 1;/*XXX style->frameBorderWidth(); */
199 self
->geom
.cbwidth
= 1; /*XXX style->clientBorderWidth(); */
201 self
->geom
.bwidth
= self
->geom
.cbwidth
= 0;
203 STRUT_SET(self
->innersize
, self
->geom
.cbwidth
, self
->geom
.cbwidth
,
204 self
->geom
.cbwidth
, self
->geom
.cbwidth
);
205 self
->geom
.width
= self
->client
->area
.width
+ self
->geom
.cbwidth
* 2;
206 g_assert(self
->geom
.width
> 0);
208 /* set border widths */
209 XSetWindowBorderWidth(ob_display
, self
->plate
, self
->geom
.cbwidth
);
210 XSetWindowBorderWidth(ob_display
, self
->window
, self
->geom
.bwidth
);
211 XSetWindowBorderWidth(ob_display
, self
->title
, self
->geom
.bwidth
);
212 XSetWindowBorderWidth(ob_display
, self
->handle
, self
->geom
.bwidth
);
213 XSetWindowBorderWidth(ob_display
, self
->lgrip
, self
->geom
.bwidth
);
214 XSetWindowBorderWidth(ob_display
, self
->rgrip
, self
->geom
.bwidth
);
216 /* position/size and map/unmap all the windows */
218 if (self
->decorations
& Decor_Titlebar
) {
219 self
->geom
.title_height
= self
->geom
.font_height
+
220 self
->geom
.bevel
* 2;
221 XMoveResizeWindow(ob_display
, self
->title
,
222 -self
->geom
.bwidth
, -self
->geom
.bwidth
,
223 self
->geom
.width
, self
->geom
.title_height
);
224 self
->innersize
.top
+= self
->geom
.title_height
+ self
->geom
.bwidth
;
225 XMapWindow(ob_display
, self
->title
);
227 /* layout the title bar elements */
228 /*XXX layoutTitle(); */
230 XUnmapWindow(ob_display
, self
->title
);
231 /* make all the titlebar stuff not render */
232 self
->decorations
&= ~(Decor_Icon
| Decor_Iconify
|
233 Decor_Maximize
| Decor_Close
|
237 if (self
->decorations
& Decor_Handle
) {
238 self
->geom
.handle_y
= self
->innersize
.top
+
239 self
->client
->area
.height
+ self
->geom
.cbwidth
;
240 XMoveResizeWindow(ob_display
, self
->handle
,
241 -self
->geom
.bwidth
, self
->geom
.handle_y
,
242 self
->geom
.width
, self
->geom
.handle_height
);
243 XMoveWindow(ob_display
, self
->lgrip
,
244 -self
->geom
.bwidth
, -self
->geom
.bwidth
);
245 XMoveWindow(ob_display
, self
->rgrip
,
246 -self
->geom
.bwidth
+ self
->geom
.width
-
247 self
->geom
.grip_width
, -self
->geom
.bwidth
);
248 self
->innersize
.bottom
+= self
->geom
.handle_height
+
250 XMapWindow(ob_display
, self
->handle
);
252 XUnmapWindow(ob_display
, self
->handle
);
254 XResizeWindow(ob_display
, self
->window
, self
->geom
.width
,
255 (self
->client
->shaded
? self
->geom
.title_height
:
256 self
->innersize
.top
+ self
->innersize
.bottom
+
257 self
->client
->area
.height
));
259 /* do this in two steps because clients whose gravity is set to
260 'Static' don't end up getting moved at all with an XMoveResizeWindow */
261 XMoveWindow(ob_display
, self
->plate
,
262 self
->innersize
.left
- self
->geom
.cbwidth
,
263 self
->innersize
.top
- self
->geom
.cbwidth
);
264 XResizeWindow(ob_display
, self
->plate
, self
->client
->area
.width
,
265 self
->client
->area
.height
);
267 STRUT_SET(self
->size
,
268 self
->innersize
.left
+ self
->geom
.bwidth
,
269 self
->innersize
.right
+ self
->geom
.bwidth
,
270 self
->innersize
.top
+ self
->geom
.bwidth
,
271 self
->innersize
.bottom
+ self
->geom
.bwidth
);
273 RECT_SET_SIZE(self
->area
,
274 self
->client
->area
.width
+
275 self
->size
.left
+ self
->size
.right
,
276 self
->client
->area
.height
+
277 self
->size
.top
+ self
->size
.bottom
);
280 // render all the elements
281 int screen = _client->screen();
282 bool focus = _client->focused();
283 if (_decorations & Client::Decor_Titlebar) {
284 render(screen, otk::Size(geom.width, geom.title_height()), _title,
285 &_title_sur, *(focus ? style->titlebarFocusBackground() :
286 style->titlebarUnfocusBackground()), false);
296 if (_decorations & Client::Decor_Handle) {
297 render(screen, otk::Size(geom.width, geom.handle_height), _handle,
298 &_handle_sur, *(focus ? style->handleFocusBackground() :
299 style->handleUnfocusBackground()));
300 render(screen, otk::Size(geom.grip_width(), geom.handle_height), _lgrip,
301 &_grip_sur, *(focus ? style->gripFocusBackground() :
302 style->gripUnfocusBackground()));
303 if ((focus ? style->gripFocusBackground() :
304 style->gripUnfocusBackground())->parentRelative())
305 XSetWindowBackgroundPixmap(**otk::display, _rgrip, ParentRelative);
307 XSetWindowBackgroundPixmap(**otk::display, _rgrip, _grip_sur->pixmap());
309 XClearWindow(**otk::display, _rgrip);
312 XSetWindowBorder(**otk::display, _plate,
313 focus ? style->clientBorderFocusColor()->pixel() :
314 style->clientBorderUnfocusColor()->pixel());
318 frame_adjust_shape(self
);
321 void frame_adjust_position(Frame
*self
)
323 self
->area
.x
= self
->client
->area
.x
;
324 self
->area
.y
= self
->client
->area
.y
;
325 frame_client_gravity(self
, &self
->area
.x
, &self
->area
.y
);
326 XMoveWindow(ob_display
, self
->window
, self
->area
.x
, self
->area
.y
);
329 void frame_adjust_shape(Frame
*self
)
335 if (!self
->client
->shaped
) {
336 /* clear the shape on the frame window */
337 XShapeCombineMask(ob_display
, self
->window
, ShapeBounding
,
338 self
->innersize
.left
,
342 /* make the frame's shape match the clients */
343 XShapeCombineShape(ob_display
, self
->window
, ShapeBounding
,
344 self
->innersize
.left
,
346 self
->client
->window
, ShapeBounding
, ShapeSet
);
349 if (self
->decorations
& Decor_Titlebar
) {
350 xrect
[0].x
= -self
->geom
.bevel
;
351 xrect
[0].y
= -self
->geom
.bevel
;
352 xrect
[0].width
= self
->geom
.width
+ self
->geom
.bwidth
* 2;
353 xrect
[0].height
= self
->geom
.title_height
+
354 self
->geom
.bwidth
* 2;
358 if (self
->decorations
& Decor_Handle
) {
359 xrect
[1].x
= -self
->geom
.bevel
;
360 xrect
[1].y
= self
->geom
.handle_y
;
361 xrect
[1].width
= self
->geom
.width
+ self
->geom
.bwidth
* 2;
362 xrect
[1].height
= self
->geom
.handle_height
+
363 self
->geom
.bwidth
* 2;
367 XShapeCombineRectangles(ob_display
, self
->window
,
368 ShapeBounding
, 0, 0, xrect
, num
,
369 ShapeUnion
, Unsorted
);
374 void frame_client_gravity(Frame
*self
, int *x
, int *y
)
377 switch (self
->client
->gravity
) {
379 case NorthWestGravity
:
380 case SouthWestGravity
:
387 *x
-= (self
->size
.left
+ self
->size
.right
) / 2;
390 case NorthEastGravity
:
391 case SouthEastGravity
:
393 *x
-= self
->size
.left
+ self
->size
.right
;
398 *x
-= self
->size
.left
;
403 switch (self
->client
->gravity
) {
405 case NorthWestGravity
:
406 case NorthEastGravity
:
413 *y
-= (self
->size
.top
+ self
->size
.bottom
) / 2;
416 case SouthWestGravity
:
417 case SouthEastGravity
:
419 *y
-= self
->size
.top
+ self
->size
.bottom
;
424 *y
-= self
->size
.top
;
429 void frame_frame_gravity(Frame
*self
, int *x
, int *y
)
432 switch (self
->client
->gravity
) {
434 case NorthWestGravity
:
436 case SouthWestGravity
:
441 *x
+= (self
->size
.left
+ self
->size
.right
) / 2;
443 case NorthEastGravity
:
445 case SouthEastGravity
:
446 *x
+= self
->size
.left
+ self
->size
.right
;
450 x
+= self
->size
.left
;
455 switch (self
->client
->gravity
) {
457 case NorthWestGravity
:
459 case SouthWestGravity
:
464 *y
+= (self
->size
.top
+ self
->size
.bottom
) / 2;
466 case NorthEastGravity
:
468 case SouthEastGravity
:
469 *y
+= self
->size
.top
+ self
->size
.bottom
;
473 *y
+= self
->size
.top
;
478 void frame_adjust_state(Frame
*self
)
480 /* XXX do shit.. buttons? */
483 void frame_adjust_focus(Frame
*self
)
485 /* XXX optimizations later... */
486 frame_adjust_size(self
);
489 void frame_adjust_title(Frame
*self
)
491 /* XXX optimizations later... */
492 frame_adjust_size(self
);
495 void frame_adjust_icon(Frame
*self
)
497 /* XXX render icon */
500 GQuark
frame_get_context(Client
*client
, Window win
)
504 if (win
== ob_root
) return g_quark_try_string("root");
505 if (client
== NULL
) return g_quark_try_string("none");
506 if (win
== client
->window
) return g_quark_try_string("client");
508 self
= client
->frame
;
509 if (win
== self
->window
) return g_quark_try_string("frame");
510 if (win
== self
->plate
) return g_quark_try_string("frame");
511 if (win
== self
->title
) return g_quark_try_string("titlebar");
512 if (win
== self
->label
) return g_quark_try_string("titlebar");
513 if (win
== self
->handle
) return g_quark_try_string("handle");
514 if (win
== self
->lgrip
) return g_quark_try_string("blcorner");
515 if (win
== self
->rgrip
) return g_quark_try_string("brcorner");
517 return g_quark_try_string("none");
520 void frame_startup(void)
522 g_quark_from_string("none");
523 g_quark_from_string("root");
524 g_quark_from_string("client");
525 g_quark_from_string("titlebar");
526 g_quark_from_string("handle");
527 g_quark_from_string("frame");
528 g_quark_from_string("blcorner");
529 g_quark_from_string("brcorner");
530 g_quark_from_string("tlcorner");
531 g_quark_from_string("trcorner");
532 g_quark_from_string("foo");