]> Dogcows Code - chaz/openbox/blob - src/frame.cc
more layout fixes for the decoration elements
[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 // create the base frame parent window
31 _window = createFrame();
32 assert(_window);
33
34 // create all of the style element child windows
35 _titlebar = createChild(_window, 0);
36 assert(_titlebar);
37 _button_iconify = createChild(_titlebar, 0);
38 assert(_button_iconify);
39 _button_max = createChild(_titlebar, 0);
40 assert(_button_max);
41 _button_stick = createChild(_titlebar, 0);
42 assert(_button_stick);
43 _button_close = createChild(_titlebar, 0);
44 assert(_button_close);
45 _label = createChild(_titlebar, 0);
46 assert(_label);
47 XMapSubwindows(otk::OBDisplay::display, _titlebar);
48
49 _handle = createChild(_window, 0);
50 assert(_handle);
51 _grip_left = createChild(_handle, 0);
52 assert(_grip_left);
53 _grip_right = createChild(_handle, 0);
54 assert(_grip_right);
55 XMapSubwindows(otk::OBDisplay::display, _handle);
56
57 _style = 0;
58 loadStyle(style);
59
60 grabClient();
61 }
62
63
64 OBFrame::~OBFrame()
65 {
66 XDestroyWindow(otk::OBDisplay::display, _button_iconify);
67 XDestroyWindow(otk::OBDisplay::display, _button_max);
68 XDestroyWindow(otk::OBDisplay::display, _button_stick);
69 XDestroyWindow(otk::OBDisplay::display, _button_close);
70 XDestroyWindow(otk::OBDisplay::display, _label);
71 XDestroyWindow(otk::OBDisplay::display, _titlebar);
72 XDestroyWindow(otk::OBDisplay::display, _grip_left);
73 XDestroyWindow(otk::OBDisplay::display, _grip_right);
74 XDestroyWindow(otk::OBDisplay::display, _handle);
75
76 releaseClient(false);
77
78 XDestroyWindow(otk::OBDisplay::display, _window);
79 }
80
81
82 void OBFrame::loadStyle(const otk::Style *style)
83 {
84 assert(style);
85
86 // if a style was previously set, then 'replace' is true, cause we're
87 // replacing a style
88 bool replace = (_style);
89
90 if (replace) {
91 // XXX: do shit here whatever
92 }
93
94 _style = style;
95
96 XSetWindowBorderWidth(otk::OBDisplay::display, _window,
97 _style->getBorderWidth());
98 XSetWindowBorder(otk::OBDisplay::display, _window,
99 _style->getBorderColor().pixel());
100 XSetWindowBorderWidth(otk::OBDisplay::display, _titlebar,
101 _style->getBorderWidth());
102 XSetWindowBorder(otk::OBDisplay::display, _titlebar,
103 _style->getBorderColor().pixel());
104 XSetWindowBorderWidth(otk::OBDisplay::display, _grip_left,
105 _style->getBorderWidth());
106 XSetWindowBorder(otk::OBDisplay::display, _grip_left,
107 _style->getBorderColor().pixel());
108 XSetWindowBorderWidth(otk::OBDisplay::display, _grip_right,
109 _style->getBorderWidth());
110 XSetWindowBorder(otk::OBDisplay::display, _grip_right,
111 _style->getBorderColor().pixel());
112 XSetWindowBorderWidth(otk::OBDisplay::display, _handle,
113 _style->getBorderWidth());
114 XSetWindowBorder(otk::OBDisplay::display, _handle,
115 _style->getBorderColor().pixel());
116
117 // XXX: if (focused)
118 XSetWindowBackground(otk::OBDisplay::display, _window,
119 _style->getFrameFocus().color().pixel());
120 // XXX: else
121 // XXX: XSetWindowBackground(otk::OBDisplay::display, _window,
122 // XXX: _style->getFrameUnfocus().color().pixel());
123
124 // if !replace, then update() will get called after the client is grabbed!
125 if (replace) {
126 update();
127
128 // XXX: make everything redraw
129 }
130 }
131
132
133 void OBFrame::update()
134 {
135 // XXX: only if not overridden or something!!! MORE LOGIC HERE!!
136 _decorations = _client->decorations();
137
138 int width; // the width of the client window and the border around it
139
140 if (_decorations & OBClient::Decor_Border) {
141 _size.left = _size.top = _size.bottom = _size.right =
142 _style->getFrameWidth();
143 width = _client->area().width() + _style->getFrameWidth() * 2;
144 } else {
145 _size.left = _size.top = _size.bottom = _size.right = 0;
146 width = _client->area().width();
147 }
148
149 if (_decorations & OBClient::Decor_Titlebar) {
150 // set the titlebar size
151 _titlebar_area.setRect(-_style->getBorderWidth(),
152 -_style->getBorderWidth(),
153 width,
154 (_style->getFont().height() +
155 _style->getBevelWidth() * 2));
156 _size.top += _titlebar_area.height() + _style->getBorderWidth();
157
158 // set the label size
159 _label_area.setRect(0, _style->getBevelWidth(),
160 width, _style->getFont().height());
161 // set the buttons sizes
162 if (_decorations & OBClient::Decor_Iconify)
163 _button_iconify_area.setRect(0, _style->getBevelWidth() + 1,
164 _label_area.height() - 2,
165 _label_area.height() - 2);
166 if (_decorations & OBClient::Decor_Maximize)
167 _button_max_area.setRect(0, _style->getBevelWidth() + 1,
168 _label_area.height() - 2,
169 _label_area.height() - 2);
170 if (_decorations & OBClient::Decor_Sticky)
171 _button_stick_area.setRect(0, _style->getBevelWidth() + 1,
172 _label_area.height() - 2,
173 _label_area.height() - 2);
174 if (_decorations & OBClient::Decor_Close)
175 _button_close_area.setRect(0, _style->getBevelWidth() + 1,
176 _label_area.height() - 2,
177 _label_area.height() - 2);
178
179 // separation between titlebar elements
180 const int sep = _style->getBevelWidth() + 1;
181
182 std::string layout = "ILMC"; // XXX: get this from somewhere
183 // XXX: it is REQUIRED that by this point, the string only has one of each
184 // possible letter, all of the letters are valid, and L exists somewhere in
185 // the string!
186
187 int x = sep;
188 for (int i = 0, len = layout.size(); i < len; ++i) {
189 otk::Rect *area;
190 switch (layout[i]) {
191 case 'I':
192 if (!(_decorations & OBClient::Decor_Iconify))
193 continue; // skip it
194 area = &_button_iconify_area;
195 break;
196 case 'L':
197 area = &_label_area;
198 break;
199 case 'M':
200 if (!(_decorations & OBClient::Decor_Maximize))
201 continue; // skip it
202 area = &_button_max_area;
203 break;
204 case 'S':
205 if (!(_decorations & OBClient::Decor_Sticky))
206 continue; // skip it
207 area = &_button_stick_area;
208 break;
209 case 'C':
210 if (!(_decorations & OBClient::Decor_Close))
211 continue; // skip it
212 area = &_button_close_area;
213 break;
214 default:
215 assert(false); // the layout string is invalid!
216 continue; // just to fuck with g++
217 }
218 area->setX(x);
219 if (layout[i] != 'L')
220 _label_area.setWidth(_label_area.width() - area->width());
221 x += sep + area->width();
222 }
223 }
224
225 if (_decorations & OBClient::Decor_Handle) {
226 _handle_area.setRect(-_style->getBorderWidth(),
227 _size.top + _client->area().height() +
228 _style->getFrameWidth(),
229 width, _style->getHandleWidth());
230 _grip_left_area.setRect(-_style->getBorderWidth(),
231 -_style->getBorderWidth(),
232 // XXX: get a Point class in otk and use that for
233 // the 'buttons size' since theyre all the same
234 _button_iconify_area.width() * 2,
235 _handle_area.height());
236 _grip_right_area.setRect(((_handle_area.right() + 1) -
237 _button_iconify_area.width() * 2),
238 -_style->getBorderWidth(),
239 // XXX: get a Point class in otk and use that for
240 // the 'buttons size' since theyre all the same
241 _button_iconify_area.width() * 2,
242 _handle_area.height());
243 _size.bottom += _handle_area.height() + _style->getBorderWidth();
244 }
245
246
247 // position/size all the windows
248
249 XResizeWindow(otk::OBDisplay::display, _window,
250 _size.left + _size.right + _client->area().width(),
251 _size.top + _size.bottom + _client->area().height());
252
253 XMoveWindow(otk::OBDisplay::display, _client->window(),
254 _size.left, _size.top);
255
256 if (_decorations & OBClient::Decor_Titlebar) {
257 XMoveResizeWindow(otk::OBDisplay::display, _titlebar,
258 _titlebar_area.x(), _titlebar_area.y(),
259 _titlebar_area.width(), _titlebar_area.height());
260 XMoveResizeWindow(otk::OBDisplay::display, _label,
261 _label_area.x(), _label_area.y(),
262 _label_area.width(), _label_area.height());
263 if (_decorations & OBClient::Decor_Iconify)
264 XMoveResizeWindow(otk::OBDisplay::display, _button_iconify,
265 _button_iconify_area.x(), _button_iconify_area.y(),
266 _button_iconify_area.width(),
267 _button_iconify_area.height());
268 if (_decorations & OBClient::Decor_Maximize)
269 XMoveResizeWindow(otk::OBDisplay::display, _button_max,
270 _button_max_area.x(), _button_max_area.y(),
271 _button_max_area.width(),
272 _button_max_area.height());
273 if (_decorations & OBClient::Decor_Sticky)
274 XMoveResizeWindow(otk::OBDisplay::display, _button_stick,
275 _button_stick_area.x(), _button_stick_area.y(),
276 _button_stick_area.width(),
277 _button_stick_area.height());
278 if (_decorations & OBClient::Decor_Close)
279 XMoveResizeWindow(otk::OBDisplay::display, _button_close,
280 _button_close_area.x(), _button_close_area.y(),
281 _button_close_area.width(),
282 _button_close_area.height());
283 }
284
285 if (_decorations & OBClient::Decor_Handle) {
286 XMoveResizeWindow(otk::OBDisplay::display, _handle,
287 _handle_area.x(), _handle_area.y(),
288 _handle_area.width(), _handle_area.height());
289 XMoveResizeWindow(otk::OBDisplay::display, _grip_left,
290 _grip_left_area.x(), _grip_left_area.y(),
291 _grip_left_area.width(), _grip_left_area.height());
292 XMoveResizeWindow(otk::OBDisplay::display, _grip_right,
293 _grip_right_area.x(), _grip_right_area.y(),
294 _grip_right_area.width(), _grip_right_area.height());
295 }
296
297 // map/unmap all the windows
298 if (_decorations & OBClient::Decor_Titlebar) {
299 XMapWindow(otk::OBDisplay::display, _label);
300 if (_decorations & OBClient::Decor_Iconify)
301 XMapWindow(otk::OBDisplay::display, _button_iconify);
302 else
303 XUnmapWindow(otk::OBDisplay::display, _button_iconify);
304 if (_decorations & OBClient::Decor_Maximize)
305 XMapWindow(otk::OBDisplay::display, _button_max);
306 else
307 XUnmapWindow(otk::OBDisplay::display, _button_max);
308 if (_decorations & OBClient::Decor_Sticky)
309 XMapWindow(otk::OBDisplay::display, _button_stick);
310 else
311 XUnmapWindow(otk::OBDisplay::display, _button_stick);
312 if (_decorations & OBClient::Decor_Close)
313 XMapWindow(otk::OBDisplay::display, _button_close);
314 else
315 XUnmapWindow(otk::OBDisplay::display, _button_close);
316 XMapWindow(otk::OBDisplay::display, _titlebar);
317 } else {
318 XUnmapWindow(otk::OBDisplay::display, _titlebar);
319 XUnmapWindow(otk::OBDisplay::display, _label);
320 XUnmapWindow(otk::OBDisplay::display, _button_iconify);
321 XUnmapWindow(otk::OBDisplay::display, _button_max);
322 XUnmapWindow(otk::OBDisplay::display, _button_stick);
323 XUnmapWindow(otk::OBDisplay::display, _button_close);
324 }
325
326 if (_decorations & OBClient::Decor_Handle) {
327 XMapWindow(otk::OBDisplay::display, _grip_left);
328 XMapWindow(otk::OBDisplay::display, _grip_right);
329 XMapWindow(otk::OBDisplay::display, _handle);
330 } else {
331 XUnmapWindow(otk::OBDisplay::display, _handle);
332 XUnmapWindow(otk::OBDisplay::display, _grip_left);
333 XUnmapWindow(otk::OBDisplay::display, _grip_right);
334 }
335
336 // XXX: more is gunna have to happen here
337
338 updateShape();
339 }
340
341
342 void OBFrame::updateShape()
343 {
344 #ifdef SHAPE
345 if (!_client->shaped()) {
346 // clear the shape on the frame window
347 XShapeCombineMask(otk::OBDisplay::display, _window, ShapeBounding,
348 _size.left,
349 _size.top,
350 None, ShapeSet);
351 } else {
352 // make the frame's shape match the clients
353 XShapeCombineShape(otk::OBDisplay::display, _window, ShapeBounding,
354 _size.left,
355 _size.top,
356 _client->window(), ShapeBounding, ShapeSet);
357
358 int num = 0;
359 XRectangle xrect[2];
360
361 /*
362 if (decorations & Decor_Titlebar) {
363 xrect[0].x = xrect[0].y = -frame.border_w;
364 xrect[0].width = frame.rect.width();
365 xrect[0].height = frame.title_h + (frame.border_w * 2);
366 ++num;
367 }
368
369 if (decorations & Decor_Handle) {
370 xrect[1].x = -frame.border_w;
371 xrect[1].y = frame.rect.height() - frame.margin.bottom +
372 frame.mwm_border_w - frame.border_w;
373 xrect[1].width = frame.rect.width();
374 xrect[1].height = frame.handle_h + (frame.border_w * 2);
375 ++num;
376 }*/
377
378 XShapeCombineRectangles(otk::OBDisplay::display, _window,
379 ShapeBounding, 0, 0, xrect, num,
380 ShapeUnion, Unsorted);
381 }
382 #endif // SHAPE
383 }
384
385
386 void OBFrame::grabClient()
387 {
388
389 XGrabServer(otk::OBDisplay::display);
390
391 // select the event mask on the frame
392 XSelectInput(otk::OBDisplay::display, _window, SubstructureRedirectMask);
393
394 // reparent the client to the frame
395 XSelectInput(otk::OBDisplay::display, _client->window(),
396 OBClient::event_mask & ~StructureNotifyMask);
397 XReparentWindow(otk::OBDisplay::display, _client->window(), _window, 0, 0);
398 XSelectInput(otk::OBDisplay::display, _client->window(),
399 OBClient::event_mask);
400
401 // raise the client above the frame
402 XRaiseWindow(otk::OBDisplay::display, _client->window());
403 // map the client so it maps when the frame does
404 XMapWindow(otk::OBDisplay::display, _client->window());
405
406 XUngrabServer(otk::OBDisplay::display);
407
408 update();
409 }
410
411
412 void OBFrame::releaseClient(bool remap)
413 {
414 // check if the app has already reparented its window to the root window
415 XEvent ev;
416 if (XCheckTypedWindowEvent(otk::OBDisplay::display, _client->window(),
417 ReparentNotify, &ev)) {
418 remap = true; // XXX: why do we remap the window if they already
419 // reparented to root?
420 } else {
421 // according to the ICCCM - if the client doesn't reparent to
422 // root, then we have to do it for them
423 XReparentWindow(otk::OBDisplay::display, _client->window(),
424 _screen->getRootWindow(),
425 _client->area().x(), _client->area().y());
426 }
427
428 // if we want to remap the window, do so now
429 if (remap)
430 XMapWindow(otk::OBDisplay::display, _client->window());
431 }
432
433
434 Window OBFrame::createChild(Window parent, Cursor cursor)
435 {
436 XSetWindowAttributes attrib_create;
437 unsigned long create_mask = CWBackPixmap | CWBorderPixel | CWEventMask;
438
439 attrib_create.background_pixmap = None;
440 attrib_create.event_mask = ButtonPressMask | ButtonReleaseMask |
441 ButtonMotionMask | ExposureMask;
442
443 if (cursor) {
444 create_mask |= CWCursor;
445 attrib_create.cursor = cursor;
446 }
447
448 Window w = XCreateWindow(otk::OBDisplay::display, parent, 0, 0, 1, 1, 0,
449 _screen->getDepth(), InputOutput,
450 _screen->getVisual(), create_mask, &attrib_create);
451 XRaiseWindow(otk::OBDisplay::display, w); // raise above the parent
452 return w;
453 }
454
455
456 Window OBFrame::createFrame()
457 {
458 XSetWindowAttributes attrib_create;
459 unsigned long create_mask = CWBackPixmap | CWBorderPixel | CWColormap |
460 CWOverrideRedirect | CWEventMask;
461
462 attrib_create.background_pixmap = None;
463 attrib_create.colormap = _screen->getColormap();
464 attrib_create.override_redirect = True;
465 attrib_create.event_mask = EnterWindowMask | LeaveWindowMask | ButtonPress;
466 /*
467 We catch button presses because other wise they get passed down to the
468 root window, which will then cause root menus to show when you click the
469 window's frame.
470 */
471
472 return XCreateWindow(otk::OBDisplay::display, _screen->getRootWindow(),
473 0, 0, 1, 1, 0,
474 _screen->getDepth(), InputOutput, _screen->getVisual(),
475 create_mask, &attrib_create);
476 }
477
478 }
This page took 0.05751 seconds and 4 git commands to generate.