]>
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::Style
*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
),
34 _button_iconify(&_titlebar
, WidgetBase::Type_IconifyButton
),
35 _button_max(&_titlebar
, WidgetBase::Type_MaximizeButton
),
36 _button_stick(&_titlebar
, WidgetBase::Type_StickyButton
),
37 _label(&_titlebar
, WidgetBase::Type_Label
),
38 _handle(this, WidgetBase::Type_Handle
),
39 _grip_left(&_handle
, WidgetBase::Type_LeftGrip
),
40 _grip_right(&_handle
, WidgetBase::Type_RightGrip
),
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::Style
*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
->getBorderColor());
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 butsize
=0; // width and height of the titlebar buttons
132 const int bevel
= _style
->getBevelWidth();
134 if (_decorations
& Client::Decor_Border
) {
135 bwidth
= _style
->getBorderWidth();
136 cbwidth
= _style
->getFrameWidth();
138 bwidth
= cbwidth
= 0;
139 _innersize
.left
= _innersize
.top
= _innersize
.bottom
= _innersize
.right
=
141 width
= _client
->area().width() + cbwidth
* 2;
143 _plate
.setBorderWidth(cbwidth
);
145 setBorderWidth(bwidth
);
146 _titlebar
.setBorderWidth(bwidth
);
147 _grip_left
.setBorderWidth(bwidth
);
148 _grip_right
.setBorderWidth(bwidth
);
149 _handle
.setBorderWidth(bwidth
);
151 if (_decorations
& Client::Decor_Titlebar
) {
152 // set the titlebar size
153 _titlebar
.setGeometry(-bwidth
,
156 _style
->getFont()->height() + bevel
* 2);
157 _innersize
.top
+= _titlebar
.height() + bwidth
;
159 // set the label size
160 _label
.setGeometry(0, bevel
, width
, _style
->getFont()->height());
161 // set the buttons sizes
162 butsize
= _label
.height() - 2;
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_Sticky
)
168 _button_stick
.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_Sticky
)) {
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_stick
.move(x
, _button_stick
.rect().y());
261 x
+= _button_stick
.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
->getHandleWidth());
279 _grip_left
.setGeometry(-bwidth
,
281 // XXX: get a Point class in otk and use that for
282 // the 'buttons size' since theyre all the same
285 _grip_right
.setGeometry(((_handle
.rect().right() + 1) -
288 // XXX: get a Point class in otk and use that for
289 // the 'buttons size' since theyre all the same
292 _innersize
.bottom
+= _handle
.height() + bwidth
;
296 // position/size all the windows
298 if (_client
->shaded())
299 resize(_innersize
.left
+ _innersize
.right
+ _client
->area().width(),
302 resize(_innersize
.left
+ _innersize
.right
+ _client
->area().width(),
303 _innersize
.top
+ _innersize
.bottom
+ _client
->area().height());
305 _plate
.setGeometry(_innersize
.left
- cbwidth
, _innersize
.top
- cbwidth
,
306 _client
->area().width(), _client
->area().height());
308 // map/unmap all the windows
309 if (_decorations
& Client::Decor_Titlebar
) {
312 _button_iconify
.show();
314 _button_iconify
.hide();
320 _button_stick
.show();
322 _button_stick
.hide();
324 _button_close
.show();
326 _button_close
.hide();
329 _titlebar
.hide(true);
332 if (_decorations
& Client::Decor_Handle
)
337 _size
.left
= _innersize
.left
+ bwidth
;
338 _size
.right
= _innersize
.right
+ bwidth
;
339 _size
.top
= _innersize
.top
+ bwidth
;
340 _size
.bottom
= _innersize
.bottom
+ bwidth
;
348 void Frame::adjustPosition()
356 void Frame::adjustShape()
359 int bwidth
= (_decorations
& Client::Decor_Border
) ?
360 _style
->getBorderWidth() : 0;
362 if (!_client
->shaped()) {
363 // clear the shape on the frame window
364 XShapeCombineMask(**otk::display
, _window
, ShapeBounding
,
369 // make the frame's shape match the clients
370 XShapeCombineShape(**otk::display
, _window
, ShapeBounding
,
373 _client
->window(), ShapeBounding
, ShapeSet
);
378 if (_decorations
& Client::Decor_Titlebar
) {
379 xrect
[0].x
= _titlebar
.rect().x();
380 xrect
[0].y
= _titlebar
.rect().y();
381 xrect
[0].width
= _titlebar
.width() + bwidth
* 2; // XXX: this is useless once the widget handles borders!
382 xrect
[0].height
= _titlebar
.height() + bwidth
* 2;
386 if (_decorations
& Client::Decor_Handle
) {
387 xrect
[1].x
= _handle
.rect().x();
388 xrect
[1].y
= _handle
.rect().y();
389 xrect
[1].width
= _handle
.width() + bwidth
* 2; // XXX: this is useless once the widget handles borders!
390 xrect
[1].height
= _handle
.height() + bwidth
* 2;
394 XShapeCombineRectangles(**otk::display
, window(),
395 ShapeBounding
, 0, 0, xrect
, num
,
396 ShapeUnion
, Unsorted
);
402 void Frame::grabClient()
404 // reparent the client to the frame
405 XReparentWindow(**otk::display
, _client
->window(),
406 _plate
.window(), 0, 0);
408 When reparenting the client window, it is usually not mapped yet, since
409 this occurs from a MapRequest. However, in the case where Openbox is
410 starting up, the window is already mapped, so we'll see unmap events for
411 it. There are 2 unmap events generated that we see, one with the 'event'
412 member set the root window, and one set to the client, but both get handled
413 and need to be ignored.
415 if (openbox
->state() == Openbox::State_Starting
)
416 _client
->ignore_unmaps
+= 2;
418 // select the event mask on the client's parent (to receive config req's)
419 XSelectInput(**otk::display
, _plate
.window(),
420 SubstructureRedirectMask
);
422 // map the client so it maps when the frame does
423 XMapWindow(**otk::display
, _client
->window());
430 void Frame::releaseClient()
434 // check if the app has already reparented its window away
435 if (XCheckTypedWindowEvent(**otk::display
, _client
->window(),
436 ReparentNotify
, &ev
)) {
437 XPutBackEvent(**otk::display
, &ev
);
438 // re-map the window since the unmanaging process unmaps it
439 XMapWindow(**otk::display
, _client
->window());
441 // according to the ICCCM - if the client doesn't reparent itself, then we
442 // will reparent the window to root for them
443 XReparentWindow(**otk::display
, _client
->window(),
444 _screen
->rootWindow(),
445 _client
->area().x(), _client
->area().y());
450 void Frame::clientGravity(int &x
, int &y
)
452 x
= _client
->area().x();
453 y
= _client
->area().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
)
515 switch (_client
->gravity()) {
517 case NorthWestGravity
:
519 case SouthWestGravity
:
524 x
+= (_size
.left
+ _size
.right
) / 2;
526 case NorthEastGravity
:
528 case SouthEastGravity
:
529 x
+= _size
.left
+ _size
.right
;
538 switch (_client
->gravity()) {
540 case NorthWestGravity
:
542 case SouthWestGravity
:
547 y
+= (_size
.top
+ _size
.bottom
) / 2;
549 case NorthEastGravity
:
551 case SouthEastGravity
:
552 y
+= _size
.top
+ _size
.bottom
;
This page took 0.06055 seconds and 4 git commands to generate.