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