1 // -*- mode: C++; indent-tabs-mode: nil; c-basic-offset: 2; -*-
4 # include "../config.h"
9 #include <X11/extensions/shape.h>
15 #include "otk/display.hh"
21 OBFrame::OBFrame(const OBClient
*client
, const otk::Style
*style
)
23 _screen(otk::OBDisplay::screenInfo(client
->screen()))
28 _decorations
= client
->decorations();
33 // create the base frame parent window
34 _window
= createFrame();
37 // create all of the style element child windows
38 _titlebar
= createChild(_window
, 0);
40 _button_iconify
= createChild(_titlebar
, 0);
41 assert(_button_iconify
);
42 _button_max
= createChild(_titlebar
, 0);
44 _button_stick
= createChild(_titlebar
, 0);
45 assert(_button_stick
);
46 _button_close
= createChild(_titlebar
, 0);
47 assert(_button_close
);
48 _label
= createChild(_titlebar
, 0);
50 XMapSubwindows(otk::OBDisplay::display
, _titlebar
);
52 _handle
= createChild(_window
, 0);
54 _grip_left
= createChild(_handle
, 0);
56 _grip_right
= createChild(_handle
, 0);
58 XMapSubwindows(otk::OBDisplay::display
, _handle
);
68 XDestroyWindow(otk::OBDisplay::display
, _titlebar
);
69 XDestroyWindow(otk::OBDisplay::display
, _button_iconify
);
70 XDestroyWindow(otk::OBDisplay::display
, _button_max
);
71 XDestroyWindow(otk::OBDisplay::display
, _button_stick
);
72 XDestroyWindow(otk::OBDisplay::display
, _button_close
);
73 XDestroyWindow(otk::OBDisplay::display
, _label
);
74 XDestroyWindow(otk::OBDisplay::display
, _handle
);
75 XDestroyWindow(otk::OBDisplay::display
, _grip_left
);
76 XDestroyWindow(otk::OBDisplay::display
, _grip_right
);
80 void OBFrame::loadStyle(const otk::Style
*style
)
84 // if a style was previously set, then 'replace' is true, cause we're
86 // NOTE: if this is false, then DO NOT DO SHIT WITH _window, it doesnt exist
87 bool replace
= (_style
);
90 // XXX: do shit here whatever
98 XSetWindowBorderWidth(otk::OBDisplay::display
, _window
,
99 _style
->getBorderWidth());
101 // XXX: make everything redraw
106 void OBFrame::update()
108 // XXX: only if not overridden or something!!! MORE LOGIC HERE!!
109 _decorations
= _client
->decorations();
111 int width
; // the width of the client window and the border around it
113 if (_decorations
& OBClient::Decor_Border
) {
114 _size
.left
= _size
.top
= _size
.bottom
= _size
.right
=
115 _style
->getBorderWidth() + _style
->getFrameWidth();
116 width
= _client
->area().width() + _style
->getFrameWidth() * 2;
118 _size
.left
= _size
.top
= _size
.bottom
= _size
.right
= 0;
119 width
= _client
->area().width();
122 if (_decorations
& OBClient::Decor_Titlebar
) {
123 _titlebar_area
.setRect(0, 0, width
,
124 (_style
->getFont()->height() +
125 _style
->getFrameWidth() * 2));
126 _size
.top
+= _titlebar_area
.height() + _style
->getBorderWidth();
128 // set the label size
129 _label_area
.setRect(0, _style
->getBevelWidth(),
130 width
, (_titlebar_area
.height() -
131 _style
->getBevelWidth() * 2));
132 // set the buttons sizes
133 if (_decorations
& OBClient::Decor_Iconify
)
134 _button_iconify_area
.setRect(0, _style
->getBevelWidth() + 1,
135 _label_area
.height() - 2,
136 _label_area
.height() - 2);
137 if (_decorations
& OBClient::Decor_Maximize
)
138 _button_max_area
.setRect(0, _style
->getBevelWidth() + 1,
139 _label_area
.height() - 2,
140 _label_area
.height() - 2);
141 if (_decorations
& OBClient::Decor_Sticky
)
142 _button_stick_area
.setRect(0, _style
->getBevelWidth() + 1,
143 _label_area
.height() - 2,
144 _label_area
.height() - 2);
145 if (_decorations
& OBClient::Decor_Close
)
146 _button_close_area
.setRect(0, _style
->getBevelWidth() + 1,
147 _label_area
.height() - 2,
148 _label_area
.height() - 2);
150 // separation between titlebar elements
151 const int sep
= _style
->getBevelWidth() + 1;
153 std::string layout
= "ILMC"; // XXX: get this from somewhere
154 // XXX: it is REQUIRED that by this point, the string only has one of each
155 // possible letter, all of the letters are valid, and L exists somewhere in
159 for (int i
= 0, len
= layout
.size(); i
< len
; ++i
) {
163 if (!(_decorations
& OBClient::Decor_Iconify
))
165 area
= &_button_iconify_area
;
171 if (!(_decorations
& OBClient::Decor_Maximize
))
173 area
= &_button_max_area
;
176 if (!(_decorations
& OBClient::Decor_Sticky
))
178 area
= &_button_stick_area
;
181 if (!(_decorations
& OBClient::Decor_Close
))
183 area
= &_button_close_area
;
186 assert(false); // the layout string is invalid!
187 continue; // just to fuck with g++
190 x
+= sep
+ area
->width();
194 if (_decorations
& OBClient::Decor_Handle
) {
195 _handle_area
.setRect(0, _size
.top
+ _client
->area().height() +
196 _style
->getBorderWidth(),
197 width
, _style
->getHandleWidth());
198 _grip_left_area
.setRect(0,
199 _handle_area
.y() + _handle_area
.height() +
200 _style
->getBorderWidth(),
201 // XXX: get a Point class in otk and use that for
202 // the 'buttons size' since theyre all the same
203 _button_iconify_area
.width() * 2,
204 _handle_area
.height());
205 _grip_right_area
.setRect(((_handle_area
.right() + 1) -
206 _button_iconify_area
.width() * 2),
207 _handle_area
.y() + _handle_area
.height() +
208 _style
->getBorderWidth(),
209 // XXX: get a Point class in otk and use that for
210 // the 'buttons size' since theyre all the same
211 _button_iconify_area
.width() * 2,
212 _handle_area
.height());
213 _size
.bottom
+= _handle_area
.height() + _style
->getBorderWidth() * 2;
217 // position/size all the windows
219 XResizeWindow(otk::OBDisplay::display
, _window
,
220 _size
.left
+ _size
.right
+ _client
->area().width(),
221 _size
.top
+ _size
.bottom
+ _client
->area().height());
223 XMoveWindow(otk::OBDisplay::display
, _client
->window(),
224 _size
.left
, _size
.top
);
226 if (_decorations
& OBClient::Decor_Titlebar
) {
227 XMoveResizeWindow(otk::OBDisplay::display
, _titlebar
,
228 _titlebar_area
.x(), _titlebar_area
.y(),
229 _titlebar_area
.width(), _titlebar_area
.height());
230 XMoveResizeWindow(otk::OBDisplay::display
, _label
,
231 _label_area
.x(), _label_area
.y(),
232 _label_area
.width(), _label_area
.height());
233 if (_decorations
& OBClient::Decor_Iconify
)
234 XMoveResizeWindow(otk::OBDisplay::display
, _button_iconify
,
235 _button_iconify_area
.x(), _button_iconify_area
.y(),
236 _button_iconify_area
.width(),
237 _button_iconify_area
.height());
238 if (_decorations
& OBClient::Decor_Maximize
)
239 XMoveResizeWindow(otk::OBDisplay::display
, _button_max
,
240 _button_max_area
.x(), _button_max_area
.y(),
241 _button_max_area
.width(),
242 _button_max_area
.height());
243 if (_decorations
& OBClient::Decor_Sticky
)
244 XMoveResizeWindow(otk::OBDisplay::display
, _button_stick
,
245 _button_stick_area
.x(), _button_stick_area
.y(),
246 _button_stick_area
.width(),
247 _button_stick_area
.height());
248 if (_decorations
& OBClient::Decor_Close
)
249 XMoveResizeWindow(otk::OBDisplay::display
, _button_close
,
250 _button_close_area
.x(), _button_close_area
.y(),
251 _button_close_area
.width(),
252 _button_close_area
.height());
255 if (_decorations
& OBClient::Decor_Handle
) {
256 XMoveResizeWindow(otk::OBDisplay::display
, _handle
,
257 _handle_area
.x(), _handle_area
.y(),
258 _handle_area
.width(), _handle_area
.height());
259 XMoveResizeWindow(otk::OBDisplay::display
, _grip_left
,
260 _grip_left_area
.x(), _grip_left_area
.y(),
261 _grip_left_area
.width(), _grip_left_area
.height());
262 XMoveResizeWindow(otk::OBDisplay::display
, _grip_right
,
263 _grip_right_area
.x(), _grip_right_area
.y(),
264 _grip_right_area
.width(), _grip_right_area
.height());
267 // map/unmap all the windows
268 if (_decorations
& OBClient::Decor_Titlebar
) {
269 XMapWindow(otk::OBDisplay::display
, _titlebar
);
270 XMapWindow(otk::OBDisplay::display
, _label
);
271 if (_decorations
& OBClient::Decor_Iconify
)
272 XMapWindow(otk::OBDisplay::display
, _button_iconify
);
274 XUnmapWindow(otk::OBDisplay::display
, _button_iconify
);
275 if (_decorations
& OBClient::Decor_Maximize
)
276 XMapWindow(otk::OBDisplay::display
, _button_max
);
278 XUnmapWindow(otk::OBDisplay::display
, _button_max
);
279 if (_decorations
& OBClient::Decor_Sticky
)
280 XMapWindow(otk::OBDisplay::display
, _button_stick
);
282 XUnmapWindow(otk::OBDisplay::display
, _button_stick
);
283 if (_decorations
& OBClient::Decor_Close
)
284 XMapWindow(otk::OBDisplay::display
, _button_close
);
286 XUnmapWindow(otk::OBDisplay::display
, _button_close
);
288 XUnmapWindow(otk::OBDisplay::display
, _titlebar
);
289 XUnmapWindow(otk::OBDisplay::display
, _label
);
290 XUnmapWindow(otk::OBDisplay::display
, _button_iconify
);
291 XUnmapWindow(otk::OBDisplay::display
, _button_max
);
292 XUnmapWindow(otk::OBDisplay::display
, _button_stick
);
293 XUnmapWindow(otk::OBDisplay::display
, _button_close
);
296 if (_decorations
& OBClient::Decor_Handle
) {
297 XMapWindow(otk::OBDisplay::display
, _handle
);
298 XMapWindow(otk::OBDisplay::display
, _grip_left
);
299 XMapWindow(otk::OBDisplay::display
, _grip_right
);
301 XUnmapWindow(otk::OBDisplay::display
, _handle
);
302 XUnmapWindow(otk::OBDisplay::display
, _grip_left
);
303 XUnmapWindow(otk::OBDisplay::display
, _grip_right
);
306 // XXX: more is gunna have to happen here
312 void OBFrame::updateShape()
315 if (!_client
->shaped()) {
316 // clear the shape on the frame window
317 XShapeCombineMask(otk::OBDisplay::display
, _window
, ShapeBounding
,
318 _size
.left
- 2,//frame.margin.left - frame.border_w,
319 _size
.top
- 2,//frame.margin.top - frame.border_w,
322 // make the frame's shape match the clients
323 XShapeCombineShape(otk::OBDisplay::display
, _window
, ShapeBounding
,
326 _client
->window(), ShapeBounding
, ShapeSet
);
332 if (decorations & Decor_Titlebar) {
333 xrect[0].x = xrect[0].y = -frame.border_w;
334 xrect[0].width = frame.rect.width();
335 xrect[0].height = frame.title_h + (frame.border_w * 2);
339 if (decorations & Decor_Handle) {
340 xrect[1].x = -frame.border_w;
341 xrect[1].y = frame.rect.height() - frame.margin.bottom +
342 frame.mwm_border_w - frame.border_w;
343 xrect[1].width = frame.rect.width();
344 xrect[1].height = frame.handle_h + (frame.border_w * 2);
348 XShapeCombineRectangles(otk::OBDisplay::display
, _window
,
349 ShapeBounding
, 0, 0, xrect
, num
,
350 ShapeUnion
, Unsorted
);
356 void OBFrame::grabClient()
359 XGrabServer(otk::OBDisplay::display
);
361 // select the event mask on the frame
362 XSelectInput(otk::OBDisplay::display
, _window
, SubstructureRedirectMask
);
364 // reparent the client to the frame
365 XSelectInput(otk::OBDisplay::display
, _client
->window(),
366 OBClient::event_mask
& ~StructureNotifyMask
);
367 XReparentWindow(otk::OBDisplay::display
, _client
->window(), _window
,
368 _size
.left
, _size
.top
);
369 XSelectInput(otk::OBDisplay::display
, _client
->window(),
370 OBClient::event_mask
);
372 // raise the client above the frame
373 XRaiseWindow(otk::OBDisplay::display
, _client
->window());
374 // map the client so it maps when the frame does
375 XMapWindow(otk::OBDisplay::display
, _client
->window());
377 XUngrabServer(otk::OBDisplay::display
);
383 void OBFrame::releaseClient(bool remap
)
385 // check if the app has already reparented its window to the root window
387 if (XCheckTypedWindowEvent(otk::OBDisplay::display
, _client
->window(),
388 ReparentNotify
, &ev
)) {
389 remap
= true; // XXX: why do we remap the window if they already
390 // reparented to root?
392 // according to the ICCCM - if the client doesn't reparent to
393 // root, then we have to do it for them
394 XReparentWindow(otk::OBDisplay::display
, _client
->window(),
395 _screen
->getRootWindow(),
396 _client
->area().x(), _client
->area().y());
399 // if we want to remap the window, do so now
401 XMapWindow(otk::OBDisplay::display
, _client
->window());
405 Window
OBFrame::createChild(Window parent
, Cursor cursor
)
407 XSetWindowAttributes attrib_create
;
408 unsigned long create_mask
= CWBackPixmap
| CWBorderPixel
| CWEventMask
;
410 attrib_create
.background_pixmap
= None
;
411 attrib_create
.event_mask
= ButtonPressMask
| ButtonReleaseMask
|
412 ButtonMotionMask
| ExposureMask
;
415 create_mask
|= CWCursor
;
416 attrib_create
.cursor
= cursor
;
419 return XCreateWindow(otk::OBDisplay::display
, parent
, 0, 0, 1, 1, 0,
420 _screen
->getDepth(), InputOutput
, _screen
->getVisual(),
421 create_mask
, &attrib_create
);
425 Window
OBFrame::createFrame()
427 XSetWindowAttributes attrib_create
;
428 unsigned long create_mask
= CWBackPixmap
| CWBorderPixel
| CWColormap
|
429 CWOverrideRedirect
| CWEventMask
;
431 attrib_create
.background_pixmap
= None
;
432 attrib_create
.colormap
= _screen
->getColormap();
433 attrib_create
.override_redirect
= True
;
434 attrib_create
.event_mask
= EnterWindowMask
| LeaveWindowMask
| ButtonPress
;
436 We catch button presses because other wise they get passed down to the
437 root window, which will then cause root menus to show when you click the
441 return XCreateWindow(otk::OBDisplay::display
, _screen
->getRootWindow(),
442 0, 0, 1, 1, _style
->getBorderWidth(),
443 _screen
->getDepth(), InputOutput
, _screen
->getVisual(),
444 create_mask
, &attrib_create
);