]> Dogcows Code - chaz/openbox/blob - src/frame.cc
make labels' parent relative actually work :>
[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 if (texture.parentRelative())
305 XSetWindowBackgroundPixmap(**otk::display, win, ParentRelative);
306 else {
307 otk::display->renderControl(screen)->drawBackground(*s, texture);
308 XSetWindowBackgroundPixmap(**otk::display, win, s->pixmap());
309 }
310 XClearWindow(**otk::display, win);
311 if (*surface) delete *surface;
312 if (freedata) s->freePixelData();
313 *surface = s;
314 }
315
316 void Frame::adjustSize()
317 {
318 _decorations = _client->decorations();
319 const otk::RenderStyle *style = otk::RenderStyle::style(_client->screen());
320
321 if (_decorations & Client::Decor_Border) {
322 geom.bwidth = style->frameBorderWidth();
323 geom.cbwidth = style->clientBorderWidth();
324 } else {
325 geom.bwidth = geom.cbwidth = 0;
326 }
327 _innersize.left = _innersize.top = _innersize.bottom = _innersize.right =
328 geom.cbwidth;
329 geom.width = _client->area().width() + geom.cbwidth * 2;
330 assert(geom.width > 0);
331
332 // set border widths
333 XSetWindowBorderWidth(**otk::display, _plate, geom.cbwidth);
334 XSetWindowBorderWidth(**otk::display, _frame, geom.bwidth);
335 XSetWindowBorderWidth(**otk::display, _title, geom.bwidth);
336 XSetWindowBorderWidth(**otk::display, _handle, geom.bwidth);
337 XSetWindowBorderWidth(**otk::display, _lgrip, geom.bwidth);
338 XSetWindowBorderWidth(**otk::display, _rgrip, geom.bwidth);
339
340 // position/size and map/unmap all the windows
341
342 if (_decorations & Client::Decor_Titlebar) {
343 XMoveResizeWindow(**otk::display, _title, -geom.bwidth, -geom.bwidth,
344 geom.width, geom.title_height());
345 _innersize.top += geom.title_height() + geom.bwidth;
346 XMapWindow(**otk::display, _title);
347
348 // layout the title bar elements
349 layoutTitle();
350 } else {
351 XUnmapWindow(**otk::display, _title);
352 // make all the titlebar stuff not render
353 _decorations &= ~(Client::Decor_Icon | Client::Decor_Iconify |
354 Client::Decor_Maximize | Client::Decor_Close |
355 Client::Decor_AllDesktops);
356 }
357
358 if (_decorations & Client::Decor_Handle) {
359 geom.handle_y = _innersize.top + _client->area().height() + geom.cbwidth;
360 XMoveResizeWindow(**otk::display, _handle, -geom.bwidth, geom.handle_y,
361 geom.width, geom.handle_height);
362 XMoveWindow(**otk::display, _lgrip, -geom.bwidth, -geom.bwidth);
363 XMoveWindow(**otk::display, _rgrip,
364 -geom.bwidth + geom.width - geom.grip_width(),
365 -geom.bwidth);
366 _innersize.bottom += geom.handle_height + geom.bwidth;
367 XMapWindow(**otk::display, _handle);
368 } else
369 XUnmapWindow(**otk::display, _handle);
370
371 XResizeWindow(**otk::display, _frame, geom.width,
372 (_client->shaded() ? geom.title_height() :
373 _innersize.top + _innersize.bottom +
374 _client->area().height()));
375
376 // do this in two steps because clients whose gravity is set to
377 // 'Static' don't end up getting moved at all with an XMoveResizeWindow
378 XMoveWindow(**otk::display, _plate, _innersize.left - geom.cbwidth,
379 _innersize.top - geom.cbwidth);
380 XResizeWindow(**otk::display, _plate, _client->area().width(),
381 _client->area().height());
382
383 _size.left = _innersize.left + geom.bwidth;
384 _size.right = _innersize.right + geom.bwidth;
385 _size.top = _innersize.top + geom.bwidth;
386 _size.bottom = _innersize.bottom + geom.bwidth;
387
388 _area = otk::Rect(_area.position(), otk::Size(_client->area().width() +
389 _size.left + _size.right,
390 _client->area().height() +
391 _size.top + _size.bottom));
392
393 // render all the elements
394 int screen = _client->screen();
395 bool focus = _client->focused();
396 if (_decorations & Client::Decor_Titlebar) {
397 render(screen, otk::Size(geom.width, geom.title_height()), _title,
398 &_title_sur, *(focus ? style->titlebarFocusBackground() :
399 style->titlebarUnfocusBackground()), false);
400
401 renderLabel();
402 renderMax();
403 renderDesk();
404 renderIconify();
405 renderIcon();
406 renderClose();
407 }
408
409 if (_decorations & Client::Decor_Handle) {
410 render(screen, otk::Size(geom.width, geom.handle_height), _handle,
411 &_handle_sur, *(focus ? style->handleFocusBackground() :
412 style->handleUnfocusBackground()));
413 render(screen, otk::Size(geom.grip_width(), geom.handle_height), _lgrip,
414 &_grip_sur, *(focus ? style->gripFocusBackground() :
415 style->gripUnfocusBackground()));
416 if ((focus ? style->gripFocusBackground() :
417 style->gripUnfocusBackground())->parentRelative())
418 XSetWindowBackgroundPixmap(**otk::display, _rgrip, ParentRelative);
419 else {
420 XSetWindowBackgroundPixmap(**otk::display, _rgrip, _grip_sur->pixmap());
421 }
422 XClearWindow(**otk::display, _rgrip);
423 }
424
425 XSetWindowBorder(**otk::display, _plate,
426 focus ? style->clientBorderFocusColor()->pixel() :
427 style->clientBorderUnfocusColor()->pixel());
428
429 adjustShape();
430 }
431
432 void Frame::renderLabel()
433 {
434 const otk::RenderStyle *style = otk::RenderStyle::style(_client->screen());
435 const otk::RenderControl *control =
436 otk::display->renderControl(_client->screen());
437 const otk::Font *font = style->labelFont();
438
439 otk::Surface *s = new otk::Surface(_client->screen(),
440 otk::Size(geom.label_width,
441 geom.label_height()));
442 const otk::RenderTexture *tx = (_client->focused() ?
443 style->labelFocusBackground() :
444 style->labelUnfocusBackground());
445 if (tx->parentRelative()) {
446 otk::pixel32 *dest = s->pixelData(), *src;
447 int w = _title_sur->size().width();
448
449 src = _title_sur->pixelData() + w * (geom.bevel + 1) + geom.title_x;
450
451 // get the background under the label
452 for (int y = 0; y < geom.button_size; ++y, src += w - geom.button_size)
453 for (int x = 0; x < geom.button_size; ++x, ++dest, ++src)
454 *dest = *src;
455 control->drawImage(*s, 0, 0, 0); // no image but draw the new background
456 } else
457 control->drawBackground(*s, *tx);
458
459 otk::ustring t = _client->title(); // the actual text to draw
460 int x = geom.bevel; // x coord for the text
461
462 if (x * 2 < geom.label_width) {
463 // find a string that will fit inside the area for text
464 otk::ustring::size_type text_len = t.size();
465 int length;
466 int maxsize = geom.label_width - geom.bevel * 2;
467
468 do {
469 t.resize(text_len);
470 length = font->measureString(t);// this returns an unsigned, so check < 0
471 if (length < 0) length = maxsize;// if the string's that long just adjust
472 } while (length > maxsize && text_len-- > 0);
473
474 // justify the text
475 switch (style->labelTextJustify()) {
476 case otk::RenderStyle::RightBottomJustify:
477 x += maxsize - length;
478 break;
479 case otk::RenderStyle::CenterJustify:
480 x += (maxsize - length) / 2;
481 break;
482 case otk::RenderStyle::LeftTopJustify:
483 break;
484 }
485
486 if (text_len > 0)
487 control->drawString(*s, *font, x, 0,
488 *(_client->focused() ? style->textFocusColor() :
489 style->textUnfocusColor()), t);
490 }
491
492 XSetWindowBackgroundPixmap(**otk::display, _label, s->pixmap());
493 XClearWindow(**otk::display, _label);
494 if (_label_sur) delete _label_sur;
495 s->freePixelData();
496 _label_sur = s;
497 }
498
499 static void renderButton(int screen, bool focus, bool press, Window win,
500 otk::Surface **sur, int butsize,
501 const otk::PixmapMask *mask, int xoffset, int yoffset,
502 otk::Surface *bgsurface)
503 {
504 const otk::RenderStyle *style = otk::RenderStyle::style(screen);
505 const otk::RenderControl *control = otk::display->renderControl(screen);
506 otk::Surface *s = new otk::Surface(screen, otk::Size(butsize, butsize));
507
508 const otk::RenderTexture *tx = (focus ?
509 (press ?
510 style->buttonPressFocusBackground() :
511 style->buttonUnpressFocusBackground()) :
512 (press ?
513 style->buttonPressUnfocusBackground() :
514 style->buttonUnpressUnfocusBackground()));
515 const otk::RenderColor *maskcolor = (focus ?
516 style->buttonFocusColor() :
517 style->buttonUnfocusColor());
518 if (tx->parentRelative()) {
519 otk::pixel32 *dest = s->pixelData(), *src;
520 int w = bgsurface->size().width();
521
522 src = bgsurface->pixelData() + w * yoffset + xoffset;
523
524 // get the background under the button
525 for (int y = 0; y < butsize; ++y, src += w - butsize)
526 for (int x = 0; x < butsize; ++x, ++dest, ++src)
527 *dest = *src;
528 control->drawImage(*s, 0, 0, 0); // no image but draw the new background
529 } else
530 control->drawBackground(*s, *tx);
531 control->drawMask(*s, *maskcolor, *mask);
532
533 XSetWindowBackgroundPixmap(**otk::display, win, s->pixmap());
534 XClearWindow(**otk::display, win);
535 if (*sur) delete *sur;
536 s->freePixelData();
537 *sur = s;
538 }
539
540 void Frame::renderMax()
541 {
542 if (!(_decorations & Client::Decor_Maximize)) return;
543 bool press = _max_press || _client->maxVert() || _client->maxHorz();
544 renderButton(_client->screen(), _client->focused(), press, _max,
545 &_max_sur, geom.button_size,
546 otk::RenderStyle::style(_client->screen())->maximizeMask(),
547 geom.max_x, (geom.bevel + 1), _title_sur);
548 }
549
550 void Frame::renderDesk()
551 {
552 if (!(_decorations & Client::Decor_AllDesktops)) return;
553 bool press = _desk_press || _client->desktop() == 0xffffffff;
554 renderButton(_client->screen(), _client->focused(), press, _desk,
555 &_desk_sur, geom.button_size,
556 otk::RenderStyle::style(_client->screen())->alldesktopsMask(),
557 geom.desktop_x, (geom.bevel + 1), _title_sur);
558 }
559
560 void Frame::renderIconify()
561 {
562 if (!(_decorations & Client::Decor_Iconify)) return;
563 renderButton(_client->screen(), _client->focused(), _iconify_press, _iconify,
564 &_iconify_sur, geom.button_size,
565 otk::RenderStyle::style(_client->screen())->iconifyMask(),
566 geom.iconify_x, (geom.bevel + 1), _title_sur);
567 }
568
569 void Frame::renderClose()
570 {
571 if (!(_decorations & Client::Decor_Close)) return;
572 renderButton(_client->screen(), _client->focused(), _close_press, _close,
573 &_close_sur, geom.button_size,
574 otk::RenderStyle::style(_client->screen())->closeMask(),
575 geom.close_x, (geom.bevel + 1), _title_sur);
576 }
577
578 void Frame::renderIcon()
579 {
580 if (!(_decorations & Client::Decor_Icon)) return;
581 const int screen = _client->screen();
582 const otk::RenderControl *control = otk::display->renderControl(screen);
583
584 otk::Surface *s = new otk::Surface(screen, otk::Size(geom.button_size,
585 geom.button_size));
586 otk::pixel32 *dest = s->pixelData(), *src;
587 int w = _title_sur->size().width();
588
589 src = _title_sur->pixelData() + w * (geom.bevel + 1) + geom.icon_x;
590
591 // get the background under the icon button
592 for (int y = 0; y < geom.button_size; ++y, src += w - geom.button_size)
593 for (int x = 0; x < geom.button_size; ++x, ++dest, ++src)
594 *dest = *src;
595 // draw the icon over it
596 const Icon *icon = _client->icon(otk::Size(geom.button_size,
597 geom.button_size));
598 control->drawImage(*s, icon->w, icon->h, icon->data);
599 if (!icon->data) {
600 Pixmap p = _client->pixmapIcon(), m = _client->pixmapIconMask();
601 if (p != None)
602 control->drawImage(*s, p, m);
603 }
604
605 XSetWindowBackgroundPixmap(**otk::display, _icon, s->pixmap());
606 XClearWindow(**otk::display, _icon);
607 if (_icon_sur) delete _icon_sur;
608 _icon_sur = s;
609 }
610
611 void Frame::layoutTitle()
612 {
613 // figure out whats being shown, and the width of the label
614 geom.label_width = geom.width - geom.bevel * 2;
615 bool n, d, i, t, m ,c;
616 n = d = i = t = m = c = false;
617 for (const char *l = _layout.c_str(); *l; ++l) {
618 switch (*l) {
619 case 'n':
620 case 'N':
621 if (!(_decorations & Client::Decor_Icon)) break;
622 n = true;
623 geom.label_width -= geom.button_size + geom.bevel;
624 break;
625 case 'd':
626 case 'D':
627 if (!(_decorations & Client::Decor_AllDesktops)) break;
628 d = true;
629 geom.label_width -= geom.button_size + geom.bevel;
630 break;
631 case 'i':
632 case 'I':
633 if (!(_decorations & Client::Decor_Iconify)) break;
634 i = true;
635 geom.label_width -= geom.button_size + geom.bevel;
636 break;
637 case 't':
638 case 'T':
639 t = true;
640 break;
641 case 'm':
642 case 'M':
643 if (!(_decorations & Client::Decor_Maximize)) break;
644 m = true;
645 geom.label_width -= geom.button_size + geom.bevel;
646 break;
647 case 'c':
648 case 'C':
649 if (!(_decorations & Client::Decor_Close)) break;
650 c = true;
651 geom.label_width -= geom.button_size + geom.bevel;
652 break;
653 }
654 }
655 if (geom.label_width < 1) geom.label_width = 1;
656
657 XResizeWindow(**otk::display, _label, geom.label_width, geom.font_height);
658
659 if (!n) {
660 _decorations &= ~Client::Decor_Icon;
661 XUnmapWindow(**otk::display, _icon);
662 }
663 if (!d) {
664 _decorations &= ~Client::Decor_AllDesktops;
665 XUnmapWindow(**otk::display, _desk);
666 }
667 if (!i) {
668 _decorations &= ~Client::Decor_Iconify;
669 XUnmapWindow(**otk::display, _iconify);
670 }
671 if (!t)
672 XUnmapWindow(**otk::display, _label);
673 if (!m) {
674 _decorations &= ~Client::Decor_Maximize;
675 XUnmapWindow(**otk::display, _max);
676 }
677 if (!c) {
678 _decorations &= ~Client::Decor_Close;
679 XUnmapWindow(**otk::display, _close);
680 }
681
682 int x = geom.bevel;
683 for (const char *lc = _layout.c_str(); *lc; ++lc) {
684 switch (*lc) {
685 case 'n':
686 case 'N':
687 if (!n) break;
688 geom.icon_x = x;
689 XMapWindow(**otk::display, _icon);
690 XMoveWindow(**otk::display, _icon, x, geom.bevel + 1);
691 x += geom.button_size + geom.bevel;
692 break;
693 case 'd':
694 case 'D':
695 if (!d) break;
696 geom.desktop_x = x;
697 XMapWindow(**otk::display, _desk);
698 XMoveWindow(**otk::display, _desk, x, geom.bevel + 1);
699 x += geom.button_size + geom.bevel;
700 break;
701 case 'i':
702 case 'I':
703 if (!i) break;
704 geom.iconify_x = x;
705 XMapWindow(**otk::display, _iconify);
706 XMoveWindow(**otk::display, _iconify, x, geom.bevel + 1);
707 x += geom.button_size + geom.bevel;
708 break;
709 case 't':
710 case 'T':
711 if (!t) break;
712 geom.title_x = x;
713 XMapWindow(**otk::display, _label);
714 XMoveWindow(**otk::display, _label, x, geom.bevel);
715 x += geom.label_width + geom.bevel;
716 break;
717 case 'm':
718 case 'M':
719 if (!m) break;
720 geom.max_x = x;
721 XMapWindow(**otk::display, _max);
722 XMoveWindow(**otk::display, _max, x, geom.bevel + 1);
723 x += geom.button_size + geom.bevel;
724 break;
725 case 'c':
726 case 'C':
727 if (!c) break;
728 geom.close_x = x;
729 XMapWindow(**otk::display, _close);
730 XMoveWindow(**otk::display, _close, x, geom.bevel + 1);
731 x += geom.button_size + geom.bevel;
732 break;
733 }
734 }
735 }
736
737 void Frame::adjustPosition()
738 {
739 int x, y;
740 x = _client->area().x();
741 y = _client->area().y();
742 clientGravity(x, y);
743 XMoveWindow(**otk::display, _frame, x, y);
744 _area = otk::Rect(otk::Point(x, y), _area.size());
745 }
746
747
748 void Frame::adjustShape()
749 {
750 #ifdef SHAPE
751 if (!_client->shaped()) {
752 // clear the shape on the frame window
753 XShapeCombineMask(**otk::display, _frame, ShapeBounding,
754 _innersize.left,
755 _innersize.top,
756 None, ShapeSet);
757 } else {
758 // make the frame's shape match the clients
759 XShapeCombineShape(**otk::display, _frame, ShapeBounding,
760 _innersize.left,
761 _innersize.top,
762 _client->window(), ShapeBounding, ShapeSet);
763
764 int num = 0;
765 XRectangle xrect[2];
766
767 if (_decorations & Client::Decor_Titlebar) {
768 xrect[0].x = -geom.bevel;
769 xrect[0].y = -geom.bevel;
770 xrect[0].width = geom.width + geom.bwidth * 2;
771 xrect[0].height = geom.title_height() + geom.bwidth * 2;
772 ++num;
773 }
774
775 if (_decorations & Client::Decor_Handle) {
776 xrect[1].x = -geom.bevel;
777 xrect[1].y = geom.handle_y;
778 xrect[1].width = geom.width + geom.bwidth * 2;
779 xrect[1].height = geom.handle_height + geom.bwidth * 2;
780 ++num;
781 }
782
783 XShapeCombineRectangles(**otk::display, _frame,
784 ShapeBounding, 0, 0, xrect, num,
785 ShapeUnion, Unsorted);
786 }
787 #endif // SHAPE
788 }
789
790 void Frame::adjustState()
791 {
792 renderDesk();
793 renderMax();
794 }
795
796 void Frame::adjustIcon()
797 {
798 renderIcon();
799 }
800
801 void Frame::grabClient()
802 {
803 // reparent the client to the frame
804 XReparentWindow(**otk::display, _client->window(), _plate, 0, 0);
805 /*
806 When reparenting the client window, it is usually not mapped yet, since
807 this occurs from a MapRequest. However, in the case where Openbox is
808 starting up, the window is already mapped, so we'll see unmap events for
809 it. There are 2 unmap events generated that we see, one with the 'event'
810 member set the root window, and one set to the client, but both get handled
811 and need to be ignored.
812 */
813 if (openbox->state() == Openbox::State_Starting)
814 _client->ignore_unmaps += 2;
815
816 // select the event mask on the client's parent (to receive config/map req's)
817 XSelectInput(**otk::display, _plate, SubstructureRedirectMask);
818
819 // map the client so it maps when the frame does
820 XMapWindow(**otk::display, _client->window());
821
822 adjustSize();
823 adjustPosition();
824 }
825
826
827 void Frame::releaseClient()
828 {
829 XEvent ev;
830
831 // check if the app has already reparented its window away
832 if (XCheckTypedWindowEvent(**otk::display, _client->window(),
833 ReparentNotify, &ev)) {
834 XPutBackEvent(**otk::display, &ev);
835 // re-map the window since the unmanaging process unmaps it
836 XMapWindow(**otk::display, _client->window());
837 } else {
838 // according to the ICCCM - if the client doesn't reparent itself, then we
839 // will reparent the window to root for them
840 XReparentWindow(**otk::display, _client->window(),
841 otk::display->screenInfo(_client->screen())->rootWindow(),
842 _client->area().x(), _client->area().y());
843 }
844 }
845
846
847 void Frame::clientGravity(int &x, int &y)
848 {
849 // horizontal
850 switch (_client->gravity()) {
851 default:
852 case NorthWestGravity:
853 case SouthWestGravity:
854 case WestGravity:
855 break;
856
857 case NorthGravity:
858 case SouthGravity:
859 case CenterGravity:
860 x -= (_size.left + _size.right) / 2;
861 break;
862
863 case NorthEastGravity:
864 case SouthEastGravity:
865 case EastGravity:
866 x -= _size.left + _size.right;
867 break;
868
869 case ForgetGravity:
870 case StaticGravity:
871 x -= _size.left;
872 break;
873 }
874
875 // vertical
876 switch (_client->gravity()) {
877 default:
878 case NorthWestGravity:
879 case NorthEastGravity:
880 case NorthGravity:
881 break;
882
883 case CenterGravity:
884 case EastGravity:
885 case WestGravity:
886 y -= (_size.top + _size.bottom) / 2;
887 break;
888
889 case SouthWestGravity:
890 case SouthEastGravity:
891 case SouthGravity:
892 y -= _size.top + _size.bottom;
893 break;
894
895 case ForgetGravity:
896 case StaticGravity:
897 y -= _size.top;
898 break;
899 }
900 }
901
902
903 void Frame::frameGravity(int &x, int &y)
904 {
905 // horizontal
906 switch (_client->gravity()) {
907 default:
908 case NorthWestGravity:
909 case WestGravity:
910 case SouthWestGravity:
911 break;
912 case NorthGravity:
913 case CenterGravity:
914 case SouthGravity:
915 x += (_size.left + _size.right) / 2;
916 break;
917 case NorthEastGravity:
918 case EastGravity:
919 case SouthEastGravity:
920 x += _size.left + _size.right;
921 break;
922 case StaticGravity:
923 case ForgetGravity:
924 x += _size.left;
925 break;
926 }
927
928 // vertical
929 switch (_client->gravity()) {
930 default:
931 case NorthWestGravity:
932 case WestGravity:
933 case SouthWestGravity:
934 break;
935 case NorthGravity:
936 case CenterGravity:
937 case SouthGravity:
938 y += (_size.top + _size.bottom) / 2;
939 break;
940 case NorthEastGravity:
941 case EastGravity:
942 case SouthEastGravity:
943 y += _size.top + _size.bottom;
944 break;
945 case StaticGravity:
946 case ForgetGravity:
947 y += _size.top;
948 break;
949 }
950 }
951
952
953 }
This page took 0.09203 seconds and 4 git commands to generate.