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