]>
Dogcows Code - chaz/openbox/blob - src/frame.cc
1 // -*- mode: C++; indent-tabs-mode: nil; c-basic-offset: 2; -*-
4 # include "../config.h"
9 #include <X11/extensions/shape.h>
17 #include "bindings.hh"
18 #include "otk/display.hh"
24 const long Frame::event_mask
;
26 Frame::Frame(Client
*client
, otk::RenderStyle
*style
)
27 : otk::Widget(openbox
, style
, Horizontal
, 0, 1, true),
28 WidgetBase(WidgetBase::Type_Frame
),
30 _screen(otk::display
->screenInfo(client
->screen())),
31 _plate(this, WidgetBase::Type_Plate
),
32 _titlebar(this, WidgetBase::Type_Titlebar
),
33 _button_close(&_titlebar
, WidgetBase::Type_CloseButton
, client
),
34 _button_iconify(&_titlebar
, WidgetBase::Type_IconifyButton
, client
),
35 _button_max(&_titlebar
, WidgetBase::Type_MaximizeButton
, client
),
36 _button_alldesk(&_titlebar
, WidgetBase::Type_AllDesktopsButton
, client
),
37 _label(&_titlebar
, WidgetBase::Type_Label
),
38 _handle(this, WidgetBase::Type_Handle
),
39 _grip_left(&_handle
, WidgetBase::Type_LeftGrip
, client
),
40 _grip_right(&_handle
, WidgetBase::Type_RightGrip
, client
),
41 _decorations(client
->decorations())
46 XSelectInput(**otk::display
, _window
, Frame::event_mask
);
48 _grip_left
.setCursor(openbox
->cursors().ll_angle
);
49 _grip_right
.setCursor(openbox
->cursors().lr_angle
);
51 _label
.setText(_client
->title());
56 otk::Widget::unfocus(); // stuff starts out appearing focused in otk
58 _plate
.show(); // the other stuff is shown based on decor settings
67 void Frame::setTitle(const otk::ustring
&text
)
74 void Frame::setStyle(otk::RenderStyle
*style
)
78 // if a style was previously set, then 'replace' is true, cause we're
80 bool replace
= (_style
);
82 otk::Widget::setStyle(style
);
85 // XXX: do shit here whatever
90 setBorderColor(_style
->frameBorderColor());
92 // if !replace, then adjust() will get called after the client is grabbed!
94 // size/position everything
103 otk::Widget::focus();
108 void Frame::unfocus()
110 otk::Widget::unfocus();
117 // the party all happens in adjustSize
121 void Frame::adjustSize()
123 // XXX: only if not overridden or something!!! MORE LOGIC HERE!!
124 _decorations
= _client
->decorations();
126 // true/false for whether to show each element of the titlebar
127 bool tit_i
= false, tit_m
= false, tit_s
= false, tit_c
= false;
128 int width
; // the width of the client and its border
129 int bwidth
; // width to make borders
130 int cbwidth
; // width of the inner client border
131 int fontheight
= _style
->labelFont()->height(); // height of the font
132 int butsize
= fontheight
- 2; // width and height of the titlebar buttons
133 const int bevel
= _style
->bevelWidth();
135 if (_decorations
& Client::Decor_Border
) {
136 bwidth
= _style
->frameBorderWidth();
137 cbwidth
= _style
->clientBorderWidth();
139 bwidth
= cbwidth
= 0;
140 _innersize
.left
= _innersize
.top
= _innersize
.bottom
= _innersize
.right
=
142 width
= _client
->area().width() + cbwidth
* 2;
144 _plate
.setBorderWidth(cbwidth
);
146 setBorderWidth(bwidth
);
147 _titlebar
.setBorderWidth(bwidth
);
148 _grip_left
.setBorderWidth(bwidth
);
149 _grip_right
.setBorderWidth(bwidth
);
150 _handle
.setBorderWidth(bwidth
);
152 if (_decorations
& Client::Decor_Titlebar
) {
153 // set the titlebar size
154 _titlebar
.setGeometry(-bwidth
,
157 _style
->labelFont()->height() + (bevel
* 2));
158 _innersize
.top
+= _titlebar
.height() + bwidth
;
160 // set the label size
161 _label
.setGeometry(0, bevel
, width
, fontheight
);
162 // set the buttons sizes
163 if (_decorations
& Client::Decor_Iconify
)
164 _button_iconify
.setGeometry(0, bevel
+ 1, butsize
, butsize
);
165 if (_decorations
& Client::Decor_Maximize
)
166 _button_max
.setGeometry(0, bevel
+ 1, butsize
, butsize
);
167 if (_decorations
& Client::Decor_AllDesktops
)
168 _button_alldesk
.setGeometry(0, bevel
+ 1, butsize
, butsize
);
169 if (_decorations
& Client::Decor_Close
)
170 _button_close
.setGeometry(0, bevel
+ 1, butsize
, butsize
);
172 // separation between titlebar elements
173 const int sep
= bevel
+ 1;
176 if (!python_get_string("TITLEBAR_LAYOUT", &layout
))
179 // this code ensures that the string only has one of each possible
180 // letter, all of the letters are valid, and L exists somewhere in the
184 for (std::string::size_type i
= 0; i
< layout
.size(); ++i
) {
188 if (!tit_i
&& (_decorations
& Client::Decor_Iconify
)) {
202 if (!tit_m
&& (_decorations
& Client::Decor_Maximize
)) {
209 if (!tit_s
&& (_decorations
& Client::Decor_AllDesktops
)) {
216 if (!tit_c
&& (_decorations
& Client::Decor_Close
)) {
222 // if we get here then we don't want the letter, kill it
223 layout
.erase(i
--, 1);
228 // the size of the label. this ASSUMES the layout has only buttons other
229 // that the ONE LABEL!!
230 // adds an extra sep so that there's a space on either side of the
231 // titlebar.. note: x = sep, below.
232 int lwidth
= width
- sep
* 2 -
233 (butsize
+ sep
) * (layout
.size() - 1);
234 // quick sanity check for really small windows. if this is needed, its
235 // obviously not going to be displayed right...
236 // XXX: maybe we should make this look better somehow? constraints?
237 if (lwidth
<= 0) lwidth
= 1;
238 _label
.setWidth(lwidth
);
241 for (std::string::size_type i
= 0, len
= layout
.size(); i
< len
; ++i
) {
245 _button_iconify
.move(x
, _button_iconify
.rect().y());
246 x
+= _button_iconify
.width();
250 _label
.move(x
, _label
.rect().y());
255 _button_max
.move(x
, _button_max
.rect().y());
256 x
+= _button_max
.width();
260 _button_alldesk
.move(x
, _button_alldesk
.rect().y());
261 x
+= _button_alldesk
.width();
265 _button_close
.move(x
, _button_close
.rect().y());
266 x
+= _button_close
.width();
269 assert(false); // the layout string is invalid!
275 if (_decorations
& Client::Decor_Handle
) {
276 _handle
.setGeometry(-bwidth
,
277 _innersize
.top
+ _client
->area().height() + cbwidth
,
278 width
, _style
->handleWidth());
279 _grip_left
.setGeometry(-bwidth
,
283 _grip_right
.setGeometry(((_handle
.rect().right() + 1) -
288 _innersize
.bottom
+= _handle
.height() + bwidth
;
292 // position/size all the windows
294 if (_client
->shaded())
295 resize(_innersize
.left
+ _innersize
.right
+ _client
->area().width(),
298 resize(_innersize
.left
+ _innersize
.right
+ _client
->area().width(),
299 _innersize
.top
+ _innersize
.bottom
+ _client
->area().height());
301 _plate
.setGeometry(_innersize
.left
- cbwidth
, _innersize
.top
- cbwidth
,
302 _client
->area().width(), _client
->area().height());
304 // map/unmap all the windows
305 if (_decorations
& Client::Decor_Titlebar
) {
308 _button_iconify
.show();
310 _button_iconify
.hide();
316 _button_alldesk
.show();
318 _button_alldesk
.hide();
320 _button_close
.show();
322 _button_close
.hide();
325 _titlebar
.hide(true);
328 if (_decorations
& Client::Decor_Handle
)
333 _size
.left
= _innersize
.left
+ bwidth
;
334 _size
.right
= _innersize
.right
+ bwidth
;
335 _size
.top
= _innersize
.top
+ bwidth
;
336 _size
.bottom
= _innersize
.bottom
+ bwidth
;
344 void Frame::adjustPosition()
347 x
= _client
->area().x();
348 y
= _client
->area().y();
354 void Frame::adjustShape()
357 int bwidth
= (_decorations
& Client::Decor_Border
) ?
358 _style
->frameBorderWidth() : 0;
360 if (!_client
->shaped()) {
361 // clear the shape on the frame window
362 XShapeCombineMask(**otk::display
, _window
, ShapeBounding
,
367 // make the frame's shape match the clients
368 XShapeCombineShape(**otk::display
, _window
, ShapeBounding
,
371 _client
->window(), ShapeBounding
, ShapeSet
);
376 if (_decorations
& Client::Decor_Titlebar
) {
377 xrect
[0].x
= _titlebar
.rect().x();
378 xrect
[0].y
= _titlebar
.rect().y();
379 xrect
[0].width
= _titlebar
.width() + bwidth
* 2; // XXX: this is useless once the widget handles borders!
380 xrect
[0].height
= _titlebar
.height() + bwidth
* 2;
384 if (_decorations
& Client::Decor_Handle
) {
385 xrect
[1].x
= _handle
.rect().x();
386 xrect
[1].y
= _handle
.rect().y();
387 xrect
[1].width
= _handle
.width() + bwidth
* 2; // XXX: this is useless once the widget handles borders!
388 xrect
[1].height
= _handle
.height() + bwidth
* 2;
392 XShapeCombineRectangles(**otk::display
, window(),
393 ShapeBounding
, 0, 0, xrect
, num
,
394 ShapeUnion
, Unsorted
);
400 void Frame::adjustState()
402 _button_alldesk
.update();
403 _button_max
.update();
407 void Frame::grabClient()
409 // reparent the client to the frame
410 XReparentWindow(**otk::display
, _client
->window(), _plate
.window(), 0, 0);
412 When reparenting the client window, it is usually not mapped yet, since
413 this occurs from a MapRequest. However, in the case where Openbox is
414 starting up, the window is already mapped, so we'll see unmap events for
415 it. There are 2 unmap events generated that we see, one with the 'event'
416 member set the root window, and one set to the client, but both get handled
417 and need to be ignored.
419 if (openbox
->state() == Openbox::State_Starting
)
420 _client
->ignore_unmaps
+= 2;
422 // select the event mask on the client's parent (to receive config/map req's)
423 XSelectInput(**otk::display
, _plate
.window(), SubstructureRedirectMask
);
425 // map the client so it maps when the frame does
426 XMapWindow(**otk::display
, _client
->window());
433 void Frame::releaseClient()
437 // check if the app has already reparented its window away
438 if (XCheckTypedWindowEvent(**otk::display
, _client
->window(),
439 ReparentNotify
, &ev
)) {
440 XPutBackEvent(**otk::display
, &ev
);
441 // re-map the window since the unmanaging process unmaps it
442 XMapWindow(**otk::display
, _client
->window());
444 // according to the ICCCM - if the client doesn't reparent itself, then we
445 // will reparent the window to root for them
446 XReparentWindow(**otk::display
, _client
->window(),
447 _screen
->rootWindow(),
448 _client
->area().x(), _client
->area().y());
453 void Frame::clientGravity(int &x
, int &y
)
456 switch (_client
->gravity()) {
458 case NorthWestGravity
:
459 case SouthWestGravity
:
466 x
-= (_size
.left
+ _size
.right
) / 2;
469 case NorthEastGravity
:
470 case SouthEastGravity
:
472 x
-= _size
.left
+ _size
.right
;
482 switch (_client
->gravity()) {
484 case NorthWestGravity
:
485 case NorthEastGravity
:
492 y
-= (_size
.top
+ _size
.bottom
) / 2;
495 case SouthWestGravity
:
496 case SouthEastGravity
:
498 y
-= _size
.top
+ _size
.bottom
;
509 void Frame::frameGravity(int &x
, int &y
)
512 switch (_client
->gravity()) {
514 case NorthWestGravity
:
516 case SouthWestGravity
:
521 x
+= (_size
.left
+ _size
.right
) / 2;
523 case NorthEastGravity
:
525 case SouthEastGravity
:
526 x
+= _size
.left
+ _size
.right
;
535 switch (_client
->gravity()) {
537 case NorthWestGravity
:
539 case SouthWestGravity
:
544 y
+= (_size
.top
+ _size
.bottom
) / 2;
546 case NorthEastGravity
:
548 case SouthEastGravity
:
549 y
+= _size
.top
+ _size
.bottom
;
This page took 0.054923 seconds and 4 git commands to generate.