]> Dogcows Code - chaz/openbox/blob - src/frame.cc
frames' subemelents are created and positioned and everything
[chaz/openbox] / src / frame.cc
1 // -*- mode: C++; indent-tabs-mode: nil; c-basic-offset: 2; -*-
2
3 #ifdef HAVE_CONFIG_H
4 # include "../config.h"
5 #endif
6
7 extern "C" {
8 #ifdef SHAPE
9 #include <X11/extensions/shape.h>
10 #endif // SHAPE
11 }
12
13 #include "frame.hh"
14 #include "client.hh"
15 #include "otk/display.hh"
16
17 #include <string>
18
19 namespace ob {
20
21 OBFrame::OBFrame(const OBClient *client, const otk::Style *style)
22 : _client(client),
23 _screen(otk::OBDisplay::screenInfo(client->screen()))
24 {
25 assert(client);
26 assert(style);
27
28 _decorations = client->decorations();
29
30 _style = 0;
31 loadStyle(style);
32
33 // create the base frame parent window
34 _window = createFrame();
35 assert(_window);
36
37 // create all of the style element child windows
38 _titlebar = createChild(_window, 0);
39 assert(_titlebar);
40 _button_iconify = createChild(_titlebar, 0);
41 assert(_button_iconify);
42 _button_max = createChild(_titlebar, 0);
43 assert(_button_max);
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);
49 assert(_label);
50 XMapSubwindows(otk::OBDisplay::display, _titlebar);
51
52 _handle = createChild(_window, 0);
53 assert(_handle);
54 _grip_left = createChild(_handle, 0);
55 assert(_grip_left);
56 _grip_right = createChild(_handle, 0);
57 assert(_grip_right);
58 XMapSubwindows(otk::OBDisplay::display, _handle);
59
60 grabClient();
61 }
62
63
64 OBFrame::~OBFrame()
65 {
66 releaseClient(false);
67
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);
77 }
78
79
80 void OBFrame::loadStyle(const otk::Style *style)
81 {
82 assert(style);
83
84 // if a style was previously set, then 'replace' is true, cause we're
85 // replacing a style
86 // NOTE: if this is false, then DO NOT DO SHIT WITH _window, it doesnt exist
87 bool replace = (_style);
88
89 if (replace) {
90 // XXX: do shit here whatever
91 }
92
93 _style = style;
94
95 if (replace) {
96 update();
97
98 XSetWindowBorderWidth(otk::OBDisplay::display, _window,
99 _style->getBorderWidth());
100
101 // XXX: make everything redraw
102 }
103 }
104
105
106 void OBFrame::update()
107 {
108 // XXX: only if not overridden or something!!! MORE LOGIC HERE!!
109 _decorations = _client->decorations();
110
111 int width; // the width of the client window and the border around it
112
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;
117 } else {
118 _size.left = _size.top = _size.bottom = _size.right = 0;
119 width = _client->area().width();
120 }
121
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();
127
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);
149
150 // separation between titlebar elements
151 const int sep = _style->getBevelWidth() + 1;
152
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
156 // the string!
157
158 int x = sep;
159 for (int i = 0, len = layout.size(); i < len; ++i) {
160 otk::Rect *area;
161 switch (layout[i]) {
162 case 'I':
163 if (!(_decorations & OBClient::Decor_Iconify))
164 continue; // skip it
165 area = &_button_iconify_area;
166 break;
167 case 'L':
168 area = &_label_area;
169 break;
170 case 'M':
171 if (!(_decorations & OBClient::Decor_Maximize))
172 continue; // skip it
173 area = &_button_max_area;
174 break;
175 case 'S':
176 if (!(_decorations & OBClient::Decor_Sticky))
177 continue; // skip it
178 area = &_button_stick_area;
179 break;
180 case 'C':
181 if (!(_decorations & OBClient::Decor_Close))
182 continue; // skip it
183 area = &_button_close_area;
184 break;
185 default:
186 assert(false); // the layout string is invalid!
187 continue; // just to fuck with g++
188 }
189 area->setX(x);
190 x += sep + area->width();
191 }
192 }
193
194 if (_decorations & OBClient::Decor_Handle) {
195 _handle_area.setRect(0, _size.top + _client->area().height(),
196 width, _style->getHandleWidth());
197 _grip_left_area.setRect(0,
198 _handle_area.y() + _handle_area.height(),
199 // XXX: get a Point class in otk and use that for
200 // the 'buttons size' since theyre all the same
201 _button_iconify_area.width() * 2,
202 _handle_area.height());
203 _grip_right_area.setRect(((_handle_area.right() + 1) -
204 _button_iconify_area.width() * 2),
205 _handle_area.y() + _handle_area.height(),
206 // XXX: get a Point class in otk and use that for
207 // the 'buttons size' since theyre all the same
208 _button_iconify_area.width() * 2,
209 _handle_area.height());
210 _size.bottom += _handle_area.height();
211 }
212
213
214 // position/size all the windows
215
216 XResizeWindow(otk::OBDisplay::display, _window,
217 _size.left + _size.right + _client->area().width(),
218 _size.top + _size.bottom + _client->area().height());
219
220 XMoveWindow(otk::OBDisplay::display, _client->window(),
221 _size.left, _size.top);
222
223 if (_decorations & OBClient::Decor_Titlebar) {
224 XMoveResizeWindow(otk::OBDisplay::display, _titlebar,
225 _titlebar_area.x(), _titlebar_area.y(),
226 _titlebar_area.width(), _titlebar_area.height());
227 XMoveResizeWindow(otk::OBDisplay::display, _label,
228 _label_area.x(), _label_area.y(),
229 _label_area.width(), _label_area.height());
230 if (_decorations & OBClient::Decor_Iconify)
231 XMoveResizeWindow(otk::OBDisplay::display, _button_iconify,
232 _button_iconify_area.x(), _button_iconify_area.y(),
233 _button_iconify_area.width(),
234 _button_iconify_area.height());
235 if (_decorations & OBClient::Decor_Maximize)
236 XMoveResizeWindow(otk::OBDisplay::display, _button_max,
237 _button_max_area.x(), _button_max_area.y(),
238 _button_max_area.width(),
239 _button_max_area.height());
240 if (_decorations & OBClient::Decor_Sticky)
241 XMoveResizeWindow(otk::OBDisplay::display, _button_stick,
242 _button_stick_area.x(), _button_stick_area.y(),
243 _button_stick_area.width(),
244 _button_stick_area.height());
245 if (_decorations & OBClient::Decor_Close)
246 XMoveResizeWindow(otk::OBDisplay::display, _button_close,
247 _button_close_area.x(), _button_close_area.y(),
248 _button_close_area.width(),
249 _button_close_area.height());
250 }
251
252 if (_decorations & OBClient::Decor_Handle) {
253 XMoveResizeWindow(otk::OBDisplay::display, _handle,
254 _handle_area.x(), _handle_area.y(),
255 _handle_area.width(), _handle_area.height());
256 XMoveResizeWindow(otk::OBDisplay::display, _grip_left,
257 _grip_left_area.x(), _grip_left_area.y(),
258 _grip_left_area.width(), _grip_left_area.height());
259 XMoveResizeWindow(otk::OBDisplay::display, _grip_right,
260 _grip_right_area.x(), _grip_right_area.y(),
261 _grip_right_area.width(), _grip_right_area.height());
262 }
263
264 // map/unmap all the windows
265 if (_decorations & OBClient::Decor_Titlebar) {
266 XMapWindow(otk::OBDisplay::display, _titlebar);
267 XMapWindow(otk::OBDisplay::display, _label);
268 if (_decorations & OBClient::Decor_Iconify)
269 XMapWindow(otk::OBDisplay::display, _button_iconify);
270 else
271 XUnmapWindow(otk::OBDisplay::display, _button_iconify);
272 if (_decorations & OBClient::Decor_Maximize)
273 XMapWindow(otk::OBDisplay::display, _button_max);
274 else
275 XUnmapWindow(otk::OBDisplay::display, _button_max);
276 if (_decorations & OBClient::Decor_Sticky)
277 XMapWindow(otk::OBDisplay::display, _button_stick);
278 else
279 XUnmapWindow(otk::OBDisplay::display, _button_stick);
280 if (_decorations & OBClient::Decor_Close)
281 XMapWindow(otk::OBDisplay::display, _button_close);
282 else
283 XUnmapWindow(otk::OBDisplay::display, _button_close);
284 } else {
285 XUnmapWindow(otk::OBDisplay::display, _titlebar);
286 XUnmapWindow(otk::OBDisplay::display, _label);
287 XUnmapWindow(otk::OBDisplay::display, _button_iconify);
288 XUnmapWindow(otk::OBDisplay::display, _button_max);
289 XUnmapWindow(otk::OBDisplay::display, _button_stick);
290 XUnmapWindow(otk::OBDisplay::display, _button_close);
291 }
292
293 if (_decorations & OBClient::Decor_Handle) {
294 XMapWindow(otk::OBDisplay::display, _handle);
295 XMapWindow(otk::OBDisplay::display, _grip_left);
296 XMapWindow(otk::OBDisplay::display, _grip_right);
297 } else {
298 XUnmapWindow(otk::OBDisplay::display, _handle);
299 XUnmapWindow(otk::OBDisplay::display, _grip_left);
300 XUnmapWindow(otk::OBDisplay::display, _grip_right);
301 }
302
303 // XXX: more is gunna have to happen here
304
305 updateShape();
306 }
307
308
309 void OBFrame::updateShape()
310 {
311 #ifdef SHAPE
312 if (!_client->shaped()) {
313 // clear the shape on the frame window
314 XShapeCombineMask(otk::OBDisplay::display, _window, ShapeBounding,
315 _size.left - 2,//frame.margin.left - frame.border_w,
316 _size.top - 2,//frame.margin.top - frame.border_w,
317 None, ShapeSet);
318 } else {
319 // make the frame's shape match the clients
320 XShapeCombineShape(otk::OBDisplay::display, _window, ShapeBounding,
321 _size.left - 2,
322 _size.top - 2,
323 _client->window(), ShapeBounding, ShapeSet);
324
325 int num = 0;
326 XRectangle xrect[2];
327
328 /*
329 if (decorations & Decor_Titlebar) {
330 xrect[0].x = xrect[0].y = -frame.border_w;
331 xrect[0].width = frame.rect.width();
332 xrect[0].height = frame.title_h + (frame.border_w * 2);
333 ++num;
334 }
335
336 if (decorations & Decor_Handle) {
337 xrect[1].x = -frame.border_w;
338 xrect[1].y = frame.rect.height() - frame.margin.bottom +
339 frame.mwm_border_w - frame.border_w;
340 xrect[1].width = frame.rect.width();
341 xrect[1].height = frame.handle_h + (frame.border_w * 2);
342 ++num;
343 }*/
344
345 XShapeCombineRectangles(otk::OBDisplay::display, _window,
346 ShapeBounding, 0, 0, xrect, num,
347 ShapeUnion, Unsorted);
348 }
349 #endif // SHAPE
350 }
351
352
353 void OBFrame::grabClient()
354 {
355
356 XGrabServer(otk::OBDisplay::display);
357
358 // select the event mask on the frame
359 XSelectInput(otk::OBDisplay::display, _window, SubstructureRedirectMask);
360
361 // reparent the client to the frame
362 XSelectInput(otk::OBDisplay::display, _client->window(),
363 OBClient::event_mask & ~StructureNotifyMask);
364 XReparentWindow(otk::OBDisplay::display, _client->window(), _window,
365 _size.left, _size.top);
366 XSelectInput(otk::OBDisplay::display, _client->window(),
367 OBClient::event_mask);
368
369 // raise the client above the frame
370 XRaiseWindow(otk::OBDisplay::display, _client->window());
371 // map the client so it maps when the frame does
372 XMapWindow(otk::OBDisplay::display, _client->window());
373
374 XUngrabServer(otk::OBDisplay::display);
375
376 update();
377 }
378
379
380 void OBFrame::releaseClient(bool remap)
381 {
382 // check if the app has already reparented its window to the root window
383 XEvent ev;
384 if (XCheckTypedWindowEvent(otk::OBDisplay::display, _client->window(),
385 ReparentNotify, &ev)) {
386 remap = true; // XXX: why do we remap the window if they already
387 // reparented to root?
388 } else {
389 // according to the ICCCM - if the client doesn't reparent to
390 // root, then we have to do it for them
391 XReparentWindow(otk::OBDisplay::display, _client->window(),
392 _screen->getRootWindow(),
393 _client->area().x(), _client->area().y());
394 }
395
396 // if we want to remap the window, do so now
397 if (remap)
398 XMapWindow(otk::OBDisplay::display, _client->window());
399 }
400
401
402 Window OBFrame::createChild(Window parent, Cursor cursor)
403 {
404 XSetWindowAttributes attrib_create;
405 unsigned long create_mask = CWBackPixmap | CWBorderPixel | CWEventMask;
406
407 attrib_create.background_pixmap = None;
408 attrib_create.event_mask = ButtonPressMask | ButtonReleaseMask |
409 ButtonMotionMask | ExposureMask;
410
411 if (cursor) {
412 create_mask |= CWCursor;
413 attrib_create.cursor = cursor;
414 }
415
416 return XCreateWindow(otk::OBDisplay::display, parent, 0, 0, 1, 1, 0,
417 _screen->getDepth(), InputOutput, _screen->getVisual(),
418 create_mask, &attrib_create);
419 }
420
421
422 Window OBFrame::createFrame()
423 {
424 XSetWindowAttributes attrib_create;
425 unsigned long create_mask = CWBackPixmap | CWBorderPixel | CWColormap |
426 CWOverrideRedirect | CWEventMask;
427
428 attrib_create.background_pixmap = None;
429 attrib_create.colormap = _screen->getColormap();
430 attrib_create.override_redirect = True;
431 attrib_create.event_mask = EnterWindowMask | LeaveWindowMask | ButtonPress;
432 /*
433 We catch button presses because other wise they get passed down to the
434 root window, which will then cause root menus to show when you click the
435 window's frame.
436 */
437
438 return XCreateWindow(otk::OBDisplay::display, _screen->getRootWindow(),
439 0, 0, 1, 1, _style->getBorderWidth(),
440 _screen->getDepth(), InputOutput, _screen->getVisual(),
441 create_mask, &attrib_create);
442 }
443
444 }
This page took 0.058546 seconds and 5 git commands to generate.