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