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