]> Dogcows Code - chaz/openbox/blob - src/frame.cc
get the size of the label properly
[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 // the size of the label. this ASSUMES the layout has only buttons other
188 // that the ONE LABEL!!
189 // adds an extra sep so that there's a space on either side of the
190 // titlebar.. note: x = sep, below.
191 _label_area.setWidth(_label_area.width() -
192 ((_button_iconify_area.width() + sep) *
193 (layout.size() - 1) + sep));
194
195 int x = sep;
196 for (int i = 0, len = layout.size(); i < len; ++i) {
197 otk::Rect *area;
198 switch (layout[i]) {
199 case 'I':
200 if (!(_decorations & OBClient::Decor_Iconify))
201 continue; // skip it
202 area = &_button_iconify_area;
203 break;
204 case 'L':
205 area = &_label_area;
206 break;
207 case 'M':
208 if (!(_decorations & OBClient::Decor_Maximize))
209 continue; // skip it
210 area = &_button_max_area;
211 break;
212 case 'S':
213 if (!(_decorations & OBClient::Decor_Sticky))
214 continue; // skip it
215 area = &_button_stick_area;
216 break;
217 case 'C':
218 if (!(_decorations & OBClient::Decor_Close))
219 continue; // skip it
220 area = &_button_close_area;
221 break;
222 default:
223 assert(false); // the layout string is invalid!
224 continue; // just to fuck with g++
225 }
226 area->setX(x);
227 x += sep + area->width();
228 }
229 }
230
231 if (_decorations & OBClient::Decor_Handle) {
232 _handle_area.setRect(-_style->getBorderWidth(),
233 _size.top + _client->area().height() +
234 _style->getFrameWidth(),
235 width, _style->getHandleWidth());
236 _grip_left_area.setRect(-_style->getBorderWidth(),
237 -_style->getBorderWidth(),
238 // XXX: get a Point class in otk and use that for
239 // the 'buttons size' since theyre all the same
240 _button_iconify_area.width() * 2,
241 _handle_area.height());
242 _grip_right_area.setRect(((_handle_area.right() + 1) -
243 _button_iconify_area.width() * 2),
244 -_style->getBorderWidth(),
245 // XXX: get a Point class in otk and use that for
246 // the 'buttons size' since theyre all the same
247 _button_iconify_area.width() * 2,
248 _handle_area.height());
249 _size.bottom += _handle_area.height() + _style->getBorderWidth();
250 }
251
252
253 // position/size all the windows
254
255 XResizeWindow(otk::OBDisplay::display, _window,
256 _size.left + _size.right + _client->area().width(),
257 _size.top + _size.bottom + _client->area().height());
258
259 XMoveWindow(otk::OBDisplay::display, _client->window(),
260 _size.left, _size.top);
261
262 if (_decorations & OBClient::Decor_Titlebar) {
263 XMoveResizeWindow(otk::OBDisplay::display, _titlebar,
264 _titlebar_area.x(), _titlebar_area.y(),
265 _titlebar_area.width(), _titlebar_area.height());
266 XMoveResizeWindow(otk::OBDisplay::display, _label,
267 _label_area.x(), _label_area.y(),
268 _label_area.width(), _label_area.height());
269 if (_decorations & OBClient::Decor_Iconify)
270 XMoveResizeWindow(otk::OBDisplay::display, _button_iconify,
271 _button_iconify_area.x(), _button_iconify_area.y(),
272 _button_iconify_area.width(),
273 _button_iconify_area.height());
274 if (_decorations & OBClient::Decor_Maximize)
275 XMoveResizeWindow(otk::OBDisplay::display, _button_max,
276 _button_max_area.x(), _button_max_area.y(),
277 _button_max_area.width(),
278 _button_max_area.height());
279 if (_decorations & OBClient::Decor_Sticky)
280 XMoveResizeWindow(otk::OBDisplay::display, _button_stick,
281 _button_stick_area.x(), _button_stick_area.y(),
282 _button_stick_area.width(),
283 _button_stick_area.height());
284 if (_decorations & OBClient::Decor_Close)
285 XMoveResizeWindow(otk::OBDisplay::display, _button_close,
286 _button_close_area.x(), _button_close_area.y(),
287 _button_close_area.width(),
288 _button_close_area.height());
289 }
290
291 if (_decorations & OBClient::Decor_Handle) {
292 XMoveResizeWindow(otk::OBDisplay::display, _handle,
293 _handle_area.x(), _handle_area.y(),
294 _handle_area.width(), _handle_area.height());
295 XMoveResizeWindow(otk::OBDisplay::display, _grip_left,
296 _grip_left_area.x(), _grip_left_area.y(),
297 _grip_left_area.width(), _grip_left_area.height());
298 XMoveResizeWindow(otk::OBDisplay::display, _grip_right,
299 _grip_right_area.x(), _grip_right_area.y(),
300 _grip_right_area.width(), _grip_right_area.height());
301 }
302
303 // map/unmap all the windows
304 if (_decorations & OBClient::Decor_Titlebar) {
305 XMapWindow(otk::OBDisplay::display, _label);
306 if (_decorations & OBClient::Decor_Iconify)
307 XMapWindow(otk::OBDisplay::display, _button_iconify);
308 else
309 XUnmapWindow(otk::OBDisplay::display, _button_iconify);
310 if (_decorations & OBClient::Decor_Maximize)
311 XMapWindow(otk::OBDisplay::display, _button_max);
312 else
313 XUnmapWindow(otk::OBDisplay::display, _button_max);
314 if (_decorations & OBClient::Decor_Sticky)
315 XMapWindow(otk::OBDisplay::display, _button_stick);
316 else
317 XUnmapWindow(otk::OBDisplay::display, _button_stick);
318 if (_decorations & OBClient::Decor_Close)
319 XMapWindow(otk::OBDisplay::display, _button_close);
320 else
321 XUnmapWindow(otk::OBDisplay::display, _button_close);
322 XMapWindow(otk::OBDisplay::display, _titlebar);
323 } else {
324 XUnmapWindow(otk::OBDisplay::display, _titlebar);
325 XUnmapWindow(otk::OBDisplay::display, _label);
326 XUnmapWindow(otk::OBDisplay::display, _button_iconify);
327 XUnmapWindow(otk::OBDisplay::display, _button_max);
328 XUnmapWindow(otk::OBDisplay::display, _button_stick);
329 XUnmapWindow(otk::OBDisplay::display, _button_close);
330 }
331
332 if (_decorations & OBClient::Decor_Handle) {
333 XMapWindow(otk::OBDisplay::display, _grip_left);
334 XMapWindow(otk::OBDisplay::display, _grip_right);
335 XMapWindow(otk::OBDisplay::display, _handle);
336 } else {
337 XUnmapWindow(otk::OBDisplay::display, _handle);
338 XUnmapWindow(otk::OBDisplay::display, _grip_left);
339 XUnmapWindow(otk::OBDisplay::display, _grip_right);
340 }
341
342 // XXX: more is gunna have to happen here
343
344 updateShape();
345 }
346
347
348 void OBFrame::updateShape()
349 {
350 #ifdef SHAPE
351 if (!_client->shaped()) {
352 // clear the shape on the frame window
353 XShapeCombineMask(otk::OBDisplay::display, _window, ShapeBounding,
354 _size.left,
355 _size.top,
356 None, ShapeSet);
357 } else {
358 // make the frame's shape match the clients
359 XShapeCombineShape(otk::OBDisplay::display, _window, ShapeBounding,
360 _size.left,
361 _size.top,
362 _client->window(), ShapeBounding, ShapeSet);
363
364 int num = 0;
365 XRectangle xrect[2];
366
367 /*
368 if (decorations & Decor_Titlebar) {
369 xrect[0].x = xrect[0].y = -frame.border_w;
370 xrect[0].width = frame.rect.width();
371 xrect[0].height = frame.title_h + (frame.border_w * 2);
372 ++num;
373 }
374
375 if (decorations & Decor_Handle) {
376 xrect[1].x = -frame.border_w;
377 xrect[1].y = frame.rect.height() - frame.margin.bottom +
378 frame.mwm_border_w - frame.border_w;
379 xrect[1].width = frame.rect.width();
380 xrect[1].height = frame.handle_h + (frame.border_w * 2);
381 ++num;
382 }*/
383
384 XShapeCombineRectangles(otk::OBDisplay::display, _window,
385 ShapeBounding, 0, 0, xrect, num,
386 ShapeUnion, Unsorted);
387 }
388 #endif // SHAPE
389 }
390
391
392 void OBFrame::grabClient()
393 {
394
395 XGrabServer(otk::OBDisplay::display);
396
397 // select the event mask on the frame
398 XSelectInput(otk::OBDisplay::display, _window, SubstructureRedirectMask);
399
400 // reparent the client to the frame
401 XSelectInput(otk::OBDisplay::display, _client->window(),
402 OBClient::event_mask & ~StructureNotifyMask);
403 XReparentWindow(otk::OBDisplay::display, _client->window(), _window, 0, 0);
404 XSelectInput(otk::OBDisplay::display, _client->window(),
405 OBClient::event_mask);
406
407 // raise the client above the frame
408 XRaiseWindow(otk::OBDisplay::display, _client->window());
409 // map the client so it maps when the frame does
410 XMapWindow(otk::OBDisplay::display, _client->window());
411
412 XUngrabServer(otk::OBDisplay::display);
413
414 update();
415 }
416
417
418 void OBFrame::releaseClient(bool remap)
419 {
420 // check if the app has already reparented its window to the root window
421 XEvent ev;
422 if (XCheckTypedWindowEvent(otk::OBDisplay::display, _client->window(),
423 ReparentNotify, &ev)) {
424 remap = true; // XXX: why do we remap the window if they already
425 // reparented to root?
426 } else {
427 // according to the ICCCM - if the client doesn't reparent to
428 // root, then we have to do it for them
429 XReparentWindow(otk::OBDisplay::display, _client->window(),
430 _screen->getRootWindow(),
431 _client->area().x(), _client->area().y());
432 }
433
434 // if we want to remap the window, do so now
435 if (remap)
436 XMapWindow(otk::OBDisplay::display, _client->window());
437 }
438
439
440 Window OBFrame::createChild(Window parent, Cursor cursor)
441 {
442 XSetWindowAttributes attrib_create;
443 unsigned long create_mask = CWBackPixmap | CWBorderPixel | CWEventMask;
444
445 attrib_create.background_pixmap = None;
446 attrib_create.event_mask = ButtonPressMask | ButtonReleaseMask |
447 ButtonMotionMask | ExposureMask;
448
449 if (cursor) {
450 create_mask |= CWCursor;
451 attrib_create.cursor = cursor;
452 }
453
454 Window w = XCreateWindow(otk::OBDisplay::display, parent, 0, 0, 1, 1, 0,
455 _screen->getDepth(), InputOutput,
456 _screen->getVisual(), create_mask, &attrib_create);
457 XRaiseWindow(otk::OBDisplay::display, w); // raise above the parent
458 return w;
459 }
460
461
462 Window OBFrame::createFrame()
463 {
464 XSetWindowAttributes attrib_create;
465 unsigned long create_mask = CWBackPixmap | CWBorderPixel | CWColormap |
466 CWOverrideRedirect | CWEventMask;
467
468 attrib_create.background_pixmap = None;
469 attrib_create.colormap = _screen->getColormap();
470 attrib_create.override_redirect = True;
471 attrib_create.event_mask = EnterWindowMask | LeaveWindowMask | ButtonPress;
472 /*
473 We catch button presses because other wise they get passed down to the
474 root window, which will then cause root menus to show when you click the
475 window's frame.
476 */
477
478 return XCreateWindow(otk::OBDisplay::display, _screen->getRootWindow(),
479 0, 0, 1, 1, 0,
480 _screen->getDepth(), InputOutput, _screen->getVisual(),
481 create_mask, &attrib_create);
482 }
483
484 }
This page took 0.058121 seconds and 4 git commands to generate.