]> Dogcows Code - chaz/openbox/blob - src/frame.cc
add a Config class with config data from the scripts.
[chaz/openbox] / src / frame.cc
1 // -*- mode: C++; indent-tabs-mode: nil; c-basic-offset: 2; -*-
2
3 #include "config.h"
4
5 extern "C" {
6 #ifdef SHAPE
7 #include <X11/extensions/shape.h>
8 #endif // SHAPE
9 }
10
11 #include "frame.hh"
12 #include "openbox.hh"
13 #include "otk/display.hh"
14 #include "otk/surface.hh"
15
16 #include <string>
17 #include <cassert>
18
19 namespace ob {
20
21 const long Frame::event_mask;
22
23 Window createWindow(const otk::ScreenInfo *info, Window parent,
24 unsigned long mask, XSetWindowAttributes *attrib)
25 {
26 return XCreateWindow(**otk::display, parent, 0, 0, 1, 1, 0,
27 info->depth(), InputOutput, info->visual(),
28 mask, attrib);
29
30 }
31
32 Frame::Frame(Client *client)
33 : _client(client),
34 _visible(false),
35 _plate(0),
36 _title(0),
37 _label(0),
38 _handle(0),
39 _lgrip(0),
40 _rgrip(0),
41 _max(0),
42 _desk(0),
43 _iconify(0),
44 _icon(0),
45 _close(0),
46 _frame_sur(0),
47 _title_sur(0),
48 _label_sur(0),
49 _handle_sur(0),
50 _grip_sur(0),
51 _max_sur(0),
52 _desk_sur(0),
53 _iconify_sur(0),
54 _icon_sur(0),
55 _close_sur(0),
56 _max_press(false),
57 _desk_press(false),
58 _iconify_press(false),
59 _icon_press(false),
60 _close_press(false),
61 _press_button(0)
62 {
63 assert(client);
64
65 XSetWindowAttributes attrib;
66 unsigned long mask;
67 const otk::ScreenInfo *info = otk::display->screenInfo(client->screen());
68
69 // create all of the decor windows (except title bar buttons)
70 mask = CWOverrideRedirect | CWEventMask;
71 attrib.event_mask = Frame::event_mask;
72 attrib.override_redirect = true;
73 _frame = createWindow(info, info->rootWindow(), mask, &attrib);
74
75 mask = 0;
76 _plate = createWindow(info, _frame, mask, &attrib);
77 mask = CWEventMask;
78 attrib.event_mask = (ButtonPressMask | ButtonReleaseMask | ButtonMotionMask |
79 ExposureMask);
80 _title = createWindow(info, _frame, mask, &attrib);
81 _label = createWindow(info, _title, mask, &attrib);
82 _max = createWindow(info, _title, mask, &attrib);
83 _close = createWindow(info, _title, mask, &attrib);
84 _desk = createWindow(info, _title, mask, &attrib);
85 _icon = createWindow(info, _title, mask, &attrib);
86 _iconify = createWindow(info, _title, mask, &attrib);
87 _handle = createWindow(info, _frame, mask, &attrib);
88 mask |= CWCursor;
89 attrib.cursor = openbox->cursors().ll_angle;
90 _lgrip = createWindow(info, _handle, mask, &attrib);
91 attrib.cursor = openbox->cursors().lr_angle;
92 _rgrip = createWindow(info, _handle, mask, &attrib);
93
94 // the other stuff is shown based on decor settings
95 XMapWindow(**otk::display, _plate);
96 XMapWindow(**otk::display, _lgrip);
97 XMapWindow(**otk::display, _rgrip);
98 XMapWindow(**otk::display, _label);
99
100 applyStyle(*otk::RenderStyle::style(_client->screen()));
101
102 _layout = openbox->screen(_client->screen())->config().titlebar_layout;
103
104 // register all of the windows with the event dispatcher
105 Window *w = allWindows();
106 for (unsigned int i = 0; w[i]; ++i)
107 openbox->registerHandler(w[i], this);
108 delete [] w;
109 }
110
111 Frame::~Frame()
112 {
113 // unregister all of the windows with the event dispatcher
114 Window *w = allWindows();
115 for (unsigned int i = 0; w[i]; ++i)
116 openbox->clearHandler(w[i]);
117 delete [] w;
118
119 XDestroyWindow(**otk::display, _rgrip);
120 XDestroyWindow(**otk::display, _lgrip);
121 XDestroyWindow(**otk::display, _handle);
122 XDestroyWindow(**otk::display, _max);
123 XDestroyWindow(**otk::display, _icon);
124 XDestroyWindow(**otk::display, _iconify);
125 XDestroyWindow(**otk::display, _desk);
126 XDestroyWindow(**otk::display, _close);
127 XDestroyWindow(**otk::display, _label);
128 XDestroyWindow(**otk::display, _title);
129 XDestroyWindow(**otk::display, _frame);
130
131 if (_frame_sur) delete _frame_sur;
132 if (_title_sur) delete _title_sur;
133 if (_label_sur) delete _label_sur;
134 if (_handle_sur) delete _handle_sur;
135 if (_grip_sur) delete _grip_sur;
136 if (_max_sur) delete _max_sur;
137 if (_desk_sur) delete _desk_sur;
138 if (_iconify_sur) delete _iconify_sur;
139 if (_icon_sur) delete _icon_sur;
140 if (_close_sur) delete _close_sur;
141 }
142
143 void Frame::show()
144 {
145 if (!_visible) {
146 _visible = true;
147 XMapWindow(**otk::display, _frame);
148 }
149 }
150
151 void Frame::hide()
152 {
153 if (_visible) {
154 _visible = false;
155 XUnmapWindow(**otk::display, _frame);
156 }
157 }
158
159 void Frame::buttonPressHandler(const XButtonEvent &e)
160 {
161 if (_press_button) return;
162 _press_button = e.button;
163
164 if (e.window == _max) {
165 _max_press = true;
166 renderMax();
167 }
168 if (e.window == _close) {
169 _close_press = true;
170 renderClose();
171 }
172 if (e.window == _desk) {
173 _desk_press = true;
174 renderDesk();
175 }
176 if (e.window == _iconify) {
177 _iconify_press = true;
178 renderIconify();
179 }
180 if (e.window == _icon) {
181 _icon_press = true;
182 renderIcon();
183 }
184 }
185
186 void Frame::buttonReleaseHandler(const XButtonEvent &e)
187 {
188 if (e.button != _press_button) return;
189 _press_button = 0;
190
191 if (e.window == _max) {
192 _max_press = false;
193 renderMax();
194 }
195 if (e.window == _close) {
196 _close_press = false;
197 renderClose();
198 }
199 if (e.window == _desk) {
200 _desk_press = false;
201 renderDesk();
202 }
203 if (e.window == _iconify) {
204 _iconify_press = false;
205 renderIconify();
206 }
207 if (e.window == _icon) {
208 _icon_press = false;
209 renderIcon();
210 }
211 }
212
213 MouseContext::MC Frame::mouseContext(Window win) const
214 {
215 if (win == _frame) return MouseContext::Frame;
216 if (win == _title ||
217 win == _label) return MouseContext::Titlebar;
218 if (win == _handle) return MouseContext::Handle;
219 if (win == _plate) return MouseContext::Window;
220 if (win == _lgrip ||
221 win == _rgrip) return MouseContext::Grip;
222 if (win == _max) return MouseContext::MaximizeButton;
223 if (win == _close) return MouseContext::CloseButton;
224 if (win == _desk) return MouseContext::AllDesktopsButton;
225 if (win == _iconify)return MouseContext::IconifyButton;
226 if (win == _icon) return MouseContext::IconButton;
227 return (MouseContext::MC) -1;
228 }
229
230 Window *Frame::allWindows() const
231 {
232 Window *w = new Window[12 + 1];
233 unsigned int i = 0;
234 w[i++] = _frame;
235 w[i++] = _plate;
236 w[i++] = _title;
237 w[i++] = _label;
238 w[i++] = _handle;
239 w[i++] = _lgrip;
240 w[i++] = _rgrip;
241 w[i++] = _max;
242 w[i++] = _desk;
243 w[i++] = _close;
244 w[i++] = _icon;
245 w[i++] = _iconify;
246 w[i] = 0;
247 return w;
248 }
249
250 void Frame::applyStyle(const otk::RenderStyle &style)
251 {
252 // set static border colors
253 XSetWindowBorder(**otk::display, _frame, style.frameBorderColor()->pixel());
254 XSetWindowBorder(**otk::display, _title, style.frameBorderColor()->pixel());
255 XSetWindowBorder(**otk::display, _handle, style.frameBorderColor()->pixel());
256 XSetWindowBorder(**otk::display, _lgrip, style.frameBorderColor()->pixel());
257 XSetWindowBorder(**otk::display, _rgrip, style.frameBorderColor()->pixel());
258
259 // size all the fixed-size elements
260 geom.font_height = style.labelFont()->height();
261 if (geom.font_height < 1) geom.font_height = 1;
262 geom.button_size = geom.font_height - 2;
263 if (geom.button_size < 1) geom.button_size = 1;
264 geom.handle_height = style.handleWidth();
265 if (geom.handle_height < 1) geom.handle_height = 1;
266 geom.bevel = style.bevelWidth();
267
268 XResizeWindow(**otk::display, _lgrip, geom.grip_width(), geom.handle_height);
269 XResizeWindow(**otk::display, _rgrip, geom.grip_width(), geom.handle_height);
270
271 XResizeWindow(**otk::display, _max, geom.button_size, geom.button_size);
272 XResizeWindow(**otk::display, _close, geom.button_size, geom.button_size);
273 XResizeWindow(**otk::display, _desk, geom.button_size, geom.button_size);
274 XResizeWindow(**otk::display, _iconify, geom.button_size, geom.button_size);
275 XResizeWindow(**otk::display, _icon, geom.button_size, geom.button_size);
276 }
277
278 void Frame::styleChanged(const otk::RenderStyle &style)
279 {
280 applyStyle(style);
281
282 // size/position everything
283 adjustSize();
284 adjustPosition();
285 }
286
287 void Frame::adjustFocus()
288 {
289 // XXX optimizations later...
290 adjustSize();
291 }
292
293 void Frame::adjustTitle()
294 {
295 // XXX optimizations later...
296 adjustSize();
297 }
298
299 static void render(int screen, const otk::Size &size, Window win,
300 otk::Surface **surface,
301 const otk::RenderTexture &texture, bool freedata=true)
302 {
303 otk::Surface *s = new otk::Surface(screen, size);
304 otk::display->renderControl(screen)->drawBackground(*s, texture);
305 XSetWindowBackgroundPixmap(**otk::display, win, s->pixmap());
306 XClearWindow(**otk::display, win);
307 if (*surface) delete *surface;
308 if (freedata) s->freePixelData();
309 *surface = s;
310 }
311
312 void Frame::adjustSize()
313 {
314 _decorations = _client->decorations();
315 const otk::RenderStyle *style = otk::RenderStyle::style(_client->screen());
316
317 if (_decorations & Client::Decor_Border) {
318 geom.bwidth = style->frameBorderWidth();
319 geom.cbwidth = style->clientBorderWidth();
320 } else {
321 geom.bwidth = geom.cbwidth = 0;
322 }
323 _innersize.left = _innersize.top = _innersize.bottom = _innersize.right =
324 geom.cbwidth;
325 geom.width = _client->area().width() + geom.cbwidth * 2;
326 assert(geom.width > 0);
327
328 // set border widths
329 XSetWindowBorderWidth(**otk::display, _plate, geom.cbwidth);
330 XSetWindowBorderWidth(**otk::display, _frame, geom.bwidth);
331 XSetWindowBorderWidth(**otk::display, _title, geom.bwidth);
332 XSetWindowBorderWidth(**otk::display, _handle, geom.bwidth);
333 XSetWindowBorderWidth(**otk::display, _lgrip, geom.bwidth);
334 XSetWindowBorderWidth(**otk::display, _rgrip, geom.bwidth);
335
336 // position/size and map/unmap all the windows
337
338 if (_decorations & Client::Decor_Titlebar) {
339 XMoveResizeWindow(**otk::display, _title, -geom.bwidth, -geom.bwidth,
340 geom.width, geom.title_height());
341 _innersize.top += geom.title_height() + geom.bwidth;
342 XMapWindow(**otk::display, _title);
343
344 // layout the title bar elements
345 layoutTitle();
346 } else {
347 XUnmapWindow(**otk::display, _title);
348 // make all the titlebar stuff not render
349 _decorations &= ~(Client::Decor_Icon | Client::Decor_Iconify |
350 Client::Decor_Maximize | Client::Decor_Close |
351 Client::Decor_AllDesktops);
352 }
353
354 if (_decorations & Client::Decor_Handle) {
355 geom.handle_y = _innersize.top + _client->area().height() + geom.cbwidth;
356 XMoveResizeWindow(**otk::display, _handle, -geom.bwidth, geom.handle_y,
357 geom.width, geom.handle_height);
358 XMoveWindow(**otk::display, _lgrip, -geom.bwidth, -geom.bwidth);
359 XMoveWindow(**otk::display, _rgrip,
360 -geom.bwidth + geom.width - geom.grip_width(),
361 -geom.bwidth);
362 _innersize.bottom += geom.handle_height + geom.bwidth;
363 XMapWindow(**otk::display, _handle);
364 } else
365 XUnmapWindow(**otk::display, _handle);
366
367 XResizeWindow(**otk::display, _frame, geom.width,
368 (_client->shaded() ? geom.title_height() :
369 _innersize.top + _innersize.bottom +
370 _client->area().height()));
371
372 // do this in two steps because clients whose gravity is set to
373 // 'Static' don't end up getting moved at all with an XMoveResizeWindow
374 XMoveWindow(**otk::display, _plate, _innersize.left - geom.cbwidth,
375 _innersize.top - geom.cbwidth);
376 XResizeWindow(**otk::display, _plate, _client->area().width(),
377 _client->area().height());
378
379 _size.left = _innersize.left + geom.bwidth;
380 _size.right = _innersize.right + geom.bwidth;
381 _size.top = _innersize.top + geom.bwidth;
382 _size.bottom = _innersize.bottom + geom.bwidth;
383
384 _area = otk::Rect(_area.position(), otk::Size(_client->area().width() +
385 _size.left + _size.right,
386 _client->area().height() +
387 _size.top + _size.bottom));
388
389 // render all the elements
390 int screen = _client->screen();
391 bool focus = _client->focused();
392 if (_decorations & Client::Decor_Titlebar) {
393 render(screen, otk::Size(geom.width, geom.title_height()), _title,
394 &_title_sur, *(focus ? style->titlebarFocusBackground() :
395 style->titlebarUnfocusBackground()), false);
396
397 renderLabel();
398 renderMax();
399 renderDesk();
400 renderIconify();
401 renderIcon();
402 renderClose();
403 }
404
405 if (_decorations & Client::Decor_Handle) {
406 render(screen, otk::Size(geom.width, geom.handle_height), _handle,
407 &_handle_sur, *(focus ? style->handleFocusBackground() :
408 style->handleUnfocusBackground()));
409 render(screen, otk::Size(geom.grip_width(), geom.handle_height), _lgrip,
410 &_grip_sur, *(focus ? style->gripFocusBackground() :
411 style->gripUnfocusBackground()));
412 XSetWindowBackgroundPixmap(**otk::display, _rgrip, _grip_sur->pixmap());
413 XClearWindow(**otk::display, _rgrip);
414 }
415
416 XSetWindowBorder(**otk::display, _plate,
417 focus ? style->clientBorderFocusColor()->pixel() :
418 style->clientBorderUnfocusColor()->pixel());
419
420 adjustShape();
421 }
422
423 void Frame::renderLabel()
424 {
425 const otk::RenderStyle *style = otk::RenderStyle::style(_client->screen());
426 const otk::RenderControl *control =
427 otk::display->renderControl(_client->screen());
428 const otk::Font *font = style->labelFont();
429
430 otk::Surface *s = new otk::Surface(_client->screen(),
431 otk::Size(geom.label_width,
432 geom.label_height()));
433 control->drawBackground(*s, *(_client->focused() ?
434 style->labelFocusBackground() :
435 style->labelUnfocusBackground()));
436
437 otk::ustring t = _client->title(); // the actual text to draw
438 int x = geom.bevel; // x coord for the text
439
440 if (x * 2 > geom.label_width) return; // no room at all
441
442 // find a string that will fit inside the area for text
443 otk::ustring::size_type text_len = t.size();
444 int length;
445 int maxsize = geom.label_width - geom.bevel * 2;
446
447 do {
448 t.resize(text_len);
449 length = font->measureString(t); // this returns an unsigned, so check < 0
450 if (length < 0) length = maxsize; // if the string's that long just adjust
451 } while (length > maxsize && text_len-- > 0);
452
453 if (text_len <= 0) return; // won't fit anything
454
455 // justify the text
456 switch (style->labelTextJustify()) {
457 case otk::RenderStyle::RightBottomJustify:
458 x += maxsize - length;
459 break;
460 case otk::RenderStyle::CenterJustify:
461 x += (maxsize - length) / 2;
462 break;
463 case otk::RenderStyle::LeftTopJustify:
464 break;
465 }
466
467 control->drawString(*s, *font, x, 0,
468 *(_client->focused() ? style->textFocusColor() :
469 style->textUnfocusColor()), t);
470
471 XSetWindowBackgroundPixmap(**otk::display, _label, s->pixmap());
472 XClearWindow(**otk::display, _label);
473 if (_label_sur) delete _label_sur;
474 s->freePixelData();
475 _label_sur = s;
476 }
477
478 static void renderButton(int screen, bool focus, bool press, Window win,
479 otk::Surface **sur, int butsize,
480 const otk::PixmapMask *mask)
481 {
482 const otk::RenderStyle *style = otk::RenderStyle::style(screen);
483 const otk::RenderControl *control = otk::display->renderControl(screen);
484 otk::Surface *s = new otk::Surface(screen, otk::Size(butsize, butsize));
485
486 const otk::RenderTexture *tx = (focus ?
487 (press ?
488 style->buttonPressFocusBackground() :
489 style->buttonUnpressFocusBackground()) :
490 (press ?
491 style->buttonPressUnfocusBackground() :
492 style->buttonUnpressUnfocusBackground()));
493 const otk::RenderColor *maskcolor = (focus ?
494 style->buttonFocusColor() :
495 style->buttonUnfocusColor());
496 control->drawBackground(*s, *tx);
497 control->drawMask(*s, *maskcolor, *mask);
498
499 XSetWindowBackgroundPixmap(**otk::display, win, s->pixmap());
500 XClearWindow(**otk::display, win);
501 if (*sur) delete *sur;
502 s->freePixelData();
503 *sur = s;
504 }
505
506 void Frame::renderMax()
507 {
508 if (!(_decorations & Client::Decor_Maximize)) return;
509 bool press = _max_press || _client->maxVert() || _client->maxHorz();
510 renderButton(_client->screen(), _client->focused(), press, _max,
511 &_max_sur, geom.button_size,
512 otk::RenderStyle::style(_client->screen())->maximizeMask());
513 }
514
515 void Frame::renderDesk()
516 {
517 if (!(_decorations & Client::Decor_AllDesktops)) return;
518 bool press = _desk_press || _client->desktop() == 0xffffffff;
519 renderButton(_client->screen(), _client->focused(), press, _desk,
520 &_desk_sur, geom.button_size,
521 otk::RenderStyle::style(_client->screen())->alldesktopsMask());
522 }
523
524 void Frame::renderIconify()
525 {
526 if (!(_decorations & Client::Decor_Iconify)) return;
527 renderButton(_client->screen(), _client->focused(), _iconify_press, _iconify,
528 &_iconify_sur, geom.button_size,
529 otk::RenderStyle::style(_client->screen())->iconifyMask());
530 }
531
532 void Frame::renderClose()
533 {
534 if (!(_decorations & Client::Decor_Close)) return;
535 renderButton(_client->screen(), _client->focused(), _close_press, _close,
536 &_close_sur, geom.button_size,
537 otk::RenderStyle::style(_client->screen())->closeMask());
538 }
539
540 void Frame::renderIcon()
541 {
542 if (!(_decorations & Client::Decor_Icon)) return;
543 const int screen = _client->screen();
544 const otk::RenderControl *control = otk::display->renderControl(screen);
545
546 otk::Surface *s = new otk::Surface(screen, otk::Size(geom.button_size,
547 geom.button_size));
548 otk::pixel32 *dest = s->pixelData(), *src;
549 int w = _title_sur->size().width();
550
551 src = _title_sur->pixelData() + w * (geom.bevel + 1) + geom.icon_x;
552
553 // get the background under the icon button
554 for (int y = 0; y < geom.button_size; ++y, src += w - geom.button_size)
555 for (int x = 0; x < geom.button_size; ++x, ++dest, ++src)
556 *dest = *src;
557 // draw the icon over it
558 const Icon *icon = _client->icon(otk::Size(geom.button_size,
559 geom.button_size));
560 control->drawImage(*s, icon->w, icon->h, icon->data);
561
562 XSetWindowBackgroundPixmap(**otk::display, _icon, s->pixmap());
563 XClearWindow(**otk::display, _icon);
564 if (_icon_sur) delete _icon_sur;
565 _icon_sur = s;
566 }
567
568 void Frame::layoutTitle()
569 {
570 // figure out whats being shown, and the width of the label
571 geom.label_width = geom.width - geom.bevel * 2;
572 bool n, d, i, t, m ,c;
573 n = d = i = t = m = c = false;
574 for (const char *l = _layout.c_str(); *l; ++l) {
575 switch (*l) {
576 case 'n':
577 case 'N':
578 if (!(_decorations & Client::Decor_Icon)) break;
579 n = true;
580 geom.label_width -= geom.button_size + geom.bevel;
581 break;
582 case 'd':
583 case 'D':
584 if (!(_decorations & Client::Decor_AllDesktops)) break;
585 d = true;
586 geom.label_width -= geom.button_size + geom.bevel;
587 break;
588 case 'i':
589 case 'I':
590 if (!(_decorations & Client::Decor_Iconify)) break;
591 i = true;
592 geom.label_width -= geom.button_size + geom.bevel;
593 break;
594 case 't':
595 case 'T':
596 t = true;
597 break;
598 case 'm':
599 case 'M':
600 if (!(_decorations & Client::Decor_Maximize)) break;
601 m = true;
602 geom.label_width -= geom.button_size + geom.bevel;
603 break;
604 case 'c':
605 case 'C':
606 if (!(_decorations & Client::Decor_Close)) break;
607 c = true;
608 geom.label_width -= geom.button_size + geom.bevel;
609 break;
610 }
611 }
612 if (geom.label_width < 1) geom.label_width = 1;
613
614 XResizeWindow(**otk::display, _label, geom.label_width, geom.font_height);
615
616 if (!n) {
617 _decorations &= ~Client::Decor_Icon;
618 XUnmapWindow(**otk::display, _icon);
619 }
620 if (!d) {
621 _decorations &= ~Client::Decor_AllDesktops;
622 XUnmapWindow(**otk::display, _desk);
623 }
624 if (!i) {
625 _decorations &= ~Client::Decor_Iconify;
626 XUnmapWindow(**otk::display, _iconify);
627 }
628 if (!t)
629 XUnmapWindow(**otk::display, _label);
630 if (!m) {
631 _decorations &= ~Client::Decor_Maximize;
632 XUnmapWindow(**otk::display, _max);
633 }
634 if (!c) {
635 _decorations &= ~Client::Decor_Close;
636 XUnmapWindow(**otk::display, _close);
637 }
638
639 int x = geom.bevel;
640 for (const char *lc = _layout.c_str(); *lc; ++lc) {
641 switch (*lc) {
642 case 'n':
643 case 'N':
644 if (!n) break;
645 geom.icon_x = x;
646 XMapWindow(**otk::display, _icon);
647 XMoveWindow(**otk::display, _icon, x, geom.bevel + 1);
648 x += geom.button_size;
649 break;
650 case 'd':
651 case 'D':
652 if (!d) break;
653 XMapWindow(**otk::display, _desk);
654 XMoveWindow(**otk::display, _desk, x, geom.bevel + 1);
655 x += geom.button_size;
656 break;
657 case 'i':
658 case 'I':
659 if (!i) break;
660 XMapWindow(**otk::display, _iconify);
661 XMoveWindow(**otk::display, _iconify, x, geom.bevel + 1);
662 x += geom.button_size;
663 break;
664 case 't':
665 case 'T':
666 if (!t) break;
667 XMapWindow(**otk::display, _label);
668 XMoveWindow(**otk::display, _label, x, geom.bevel);
669 x += geom.label_width;
670 break;
671 case 'm':
672 case 'M':
673 if (!m) break;
674 XMapWindow(**otk::display, _max);
675 XMoveWindow(**otk::display, _max, x, geom.bevel + 1);
676 x += geom.button_size;
677 break;
678 case 'c':
679 case 'C':
680 if (!c) break;
681 XMapWindow(**otk::display, _close);
682 XMoveWindow(**otk::display, _close, x, geom.bevel + 1);
683 x += geom.button_size;
684 break;
685 }
686 x += geom.bevel;
687 }
688 }
689
690 void Frame::adjustPosition()
691 {
692 int x, y;
693 x = _client->area().x();
694 y = _client->area().y();
695 clientGravity(x, y);
696 XMoveWindow(**otk::display, _frame, x, y);
697 _area = otk::Rect(otk::Point(x, y), _area.size());
698 }
699
700
701 void Frame::adjustShape()
702 {
703 #ifdef SHAPE
704 if (!_client->shaped()) {
705 // clear the shape on the frame window
706 XShapeCombineMask(**otk::display, _frame, ShapeBounding,
707 _innersize.left,
708 _innersize.top,
709 None, ShapeSet);
710 } else {
711 // make the frame's shape match the clients
712 XShapeCombineShape(**otk::display, _frame, ShapeBounding,
713 _innersize.left,
714 _innersize.top,
715 _client->window(), ShapeBounding, ShapeSet);
716
717 int num = 0;
718 XRectangle xrect[2];
719
720 if (_decorations & Client::Decor_Titlebar) {
721 xrect[0].x = -geom.bevel;
722 xrect[0].y = -geom.bevel;
723 xrect[0].width = geom.width + geom.bwidth * 2;
724 xrect[0].height = geom.title_height() + geom.bwidth * 2;
725 ++num;
726 }
727
728 if (_decorations & Client::Decor_Handle) {
729 xrect[1].x = -geom.bevel;
730 xrect[1].y = geom.handle_y;
731 xrect[1].width = geom.width + geom.bwidth * 2;
732 xrect[1].height = geom.handle_height + geom.bwidth * 2;
733 ++num;
734 }
735
736 XShapeCombineRectangles(**otk::display, _frame,
737 ShapeBounding, 0, 0, xrect, num,
738 ShapeUnion, Unsorted);
739 }
740 #endif // SHAPE
741 }
742
743 void Frame::adjustState()
744 {
745 renderDesk();
746 renderMax();
747 }
748
749 void Frame::adjustIcon()
750 {
751 renderIcon();
752 }
753
754 void Frame::grabClient()
755 {
756 // reparent the client to the frame
757 XReparentWindow(**otk::display, _client->window(), _plate, 0, 0);
758 /*
759 When reparenting the client window, it is usually not mapped yet, since
760 this occurs from a MapRequest. However, in the case where Openbox is
761 starting up, the window is already mapped, so we'll see unmap events for
762 it. There are 2 unmap events generated that we see, one with the 'event'
763 member set the root window, and one set to the client, but both get handled
764 and need to be ignored.
765 */
766 if (openbox->state() == Openbox::State_Starting)
767 _client->ignore_unmaps += 2;
768
769 // select the event mask on the client's parent (to receive config/map req's)
770 XSelectInput(**otk::display, _plate, SubstructureRedirectMask);
771
772 // map the client so it maps when the frame does
773 XMapWindow(**otk::display, _client->window());
774
775 adjustSize();
776 adjustPosition();
777 }
778
779
780 void Frame::releaseClient()
781 {
782 XEvent ev;
783
784 // check if the app has already reparented its window away
785 if (XCheckTypedWindowEvent(**otk::display, _client->window(),
786 ReparentNotify, &ev)) {
787 XPutBackEvent(**otk::display, &ev);
788 // re-map the window since the unmanaging process unmaps it
789 XMapWindow(**otk::display, _client->window());
790 } else {
791 // according to the ICCCM - if the client doesn't reparent itself, then we
792 // will reparent the window to root for them
793 XReparentWindow(**otk::display, _client->window(),
794 otk::display->screenInfo(_client->screen())->rootWindow(),
795 _client->area().x(), _client->area().y());
796 }
797 }
798
799
800 void Frame::clientGravity(int &x, int &y)
801 {
802 // horizontal
803 switch (_client->gravity()) {
804 default:
805 case NorthWestGravity:
806 case SouthWestGravity:
807 case WestGravity:
808 break;
809
810 case NorthGravity:
811 case SouthGravity:
812 case CenterGravity:
813 x -= (_size.left + _size.right) / 2;
814 break;
815
816 case NorthEastGravity:
817 case SouthEastGravity:
818 case EastGravity:
819 x -= _size.left + _size.right;
820 break;
821
822 case ForgetGravity:
823 case StaticGravity:
824 x -= _size.left;
825 break;
826 }
827
828 // vertical
829 switch (_client->gravity()) {
830 default:
831 case NorthWestGravity:
832 case NorthEastGravity:
833 case NorthGravity:
834 break;
835
836 case CenterGravity:
837 case EastGravity:
838 case WestGravity:
839 y -= (_size.top + _size.bottom) / 2;
840 break;
841
842 case SouthWestGravity:
843 case SouthEastGravity:
844 case SouthGravity:
845 y -= _size.top + _size.bottom;
846 break;
847
848 case ForgetGravity:
849 case StaticGravity:
850 y -= _size.top;
851 break;
852 }
853 }
854
855
856 void Frame::frameGravity(int &x, int &y)
857 {
858 // horizontal
859 switch (_client->gravity()) {
860 default:
861 case NorthWestGravity:
862 case WestGravity:
863 case SouthWestGravity:
864 break;
865 case NorthGravity:
866 case CenterGravity:
867 case SouthGravity:
868 x += (_size.left + _size.right) / 2;
869 break;
870 case NorthEastGravity:
871 case EastGravity:
872 case SouthEastGravity:
873 x += _size.left + _size.right;
874 break;
875 case StaticGravity:
876 case ForgetGravity:
877 x += _size.left;
878 break;
879 }
880
881 // vertical
882 switch (_client->gravity()) {
883 default:
884 case NorthWestGravity:
885 case WestGravity:
886 case SouthWestGravity:
887 break;
888 case NorthGravity:
889 case CenterGravity:
890 case SouthGravity:
891 y += (_size.top + _size.bottom) / 2;
892 break;
893 case NorthEastGravity:
894 case EastGravity:
895 case SouthEastGravity:
896 y += _size.top + _size.bottom;
897 break;
898 case StaticGravity:
899 case ForgetGravity:
900 y += _size.top;
901 break;
902 }
903 }
904
905
906 }
This page took 0.076716 seconds and 5 git commands to generate.