1 // -*- mode: C++; indent-tabs-mode: nil; c-basic-offset: 2; -*-
4 # include "../config.h"
9 #include <X11/extensions/shape.h>
16 #include "otk/display.hh"
19 #include <iostream> // TEMP
23 OBFrame::OBFrame(OBClient
*client
, otk::Style
*style
)
24 : otk::OtkWidget(Openbox::instance
, style
),
26 _screen(otk::OBDisplay::screenInfo(client
->screen())),
28 _button_close(&_titlebar
),
29 _button_iconify(&_titlebar
),
30 _button_max(&_titlebar
),
31 _button_stick(&_titlebar
),
35 _grip_right(&_handle
),
36 _decorations(client
->decorations())
42 _titlebar
.unmanaged();
43 _button_close
.unmanaged();
44 _button_iconify
.unmanaged();
45 _button_max
.unmanaged();
46 _button_stick
.unmanaged();
49 _grip_left
.unmanaged();
50 _grip_right
.unmanaged();
52 _button_close
.setText("X");
53 _button_iconify
.setText("I");
54 _button_max
.setText("M");
55 _button_stick
.setText("C");
56 _label
.setText(_client
->title());
71 void OBFrame::setStyle(otk::Style
*style
)
75 otk::OtkWidget::setStyle(style
);
76 // don't let grips change textures when they are pressed
77 _grip_left
.setPressedFocusTexture(_grip_left
.getTexture());
78 _grip_left
.setPressedUnfocusTexture(_grip_left
.getUnfocusTexture());
79 _grip_right
.setPressedFocusTexture(_grip_right
.getTexture());
80 _grip_right
.setPressedUnfocusTexture(_grip_right
.getUnfocusTexture());
82 // if a style was previously set, then 'replace' is true, cause we're
84 bool replace
= (_style
);
87 // XXX: do shit here whatever
88 // XXX: save the position based on gravity
93 XSetWindowBorder(otk::OBDisplay::display
, getWindow(),
94 _style
->getBorderColor()->pixel());
95 XSetWindowBorder(otk::OBDisplay::display
, _titlebar
.getWindow(),
96 _style
->getBorderColor()->pixel());
97 XSetWindowBorder(otk::OBDisplay::display
, _grip_left
.getWindow(),
98 _style
->getBorderColor()->pixel());
99 XSetWindowBorder(otk::OBDisplay::display
, _grip_right
.getWindow(),
100 _style
->getBorderColor()->pixel());
101 XSetWindowBorder(otk::OBDisplay::display
, _handle
.getWindow(),
102 _style
->getBorderColor()->pixel());
104 // if !replace, then adjust() will get called after the client is grabbed!
106 adjust(); // size/position everything
110 void OBFrame::adjust()
112 // XXX: only if not overridden or something!!! MORE LOGIC HERE!!
113 _decorations
= _client
->decorations();
114 _decorations
= 0xffffffff;
116 int width
; // the width of the client window and the border around it
117 int bwidth
; // width to make borders
119 if (_decorations
& OBClient::Decor_Border
) {
120 bwidth
= _style
->getBorderWidth();
121 _size
.left
= _size
.top
= _size
.bottom
= _size
.right
=
122 _style
->getFrameWidth();
123 width
= _client
->area().width() + _style
->getFrameWidth() * 2;
126 _size
.left
= _size
.top
= _size
.bottom
= _size
.right
= 0;
127 width
= _client
->area().width();
129 XSetWindowBorderWidth(otk::OBDisplay::display
, getWindow(), bwidth
);
130 XSetWindowBorderWidth(otk::OBDisplay::display
, _titlebar
.getWindow(),
132 XSetWindowBorderWidth(otk::OBDisplay::display
, _grip_left
.getWindow(),
134 XSetWindowBorderWidth(otk::OBDisplay::display
, _grip_right
.getWindow(),
136 XSetWindowBorderWidth(otk::OBDisplay::display
, _handle
.getWindow(), bwidth
);
138 if (_decorations
& OBClient::Decor_Titlebar
) {
139 // set the titlebar size
140 _titlebar
.setGeometry(-bwidth
,
143 (_style
->getFont().height() +
144 _style
->getBevelWidth() * 2));
145 _size
.top
+= _titlebar
.height() + bwidth
;
147 // set the label size
148 _label
.setGeometry(0, _style
->getBevelWidth(),
149 width
, _style
->getFont().height());
150 // set the buttons sizes
151 if (_decorations
& OBClient::Decor_Iconify
)
152 _button_iconify
.setGeometry(0, _style
->getBevelWidth() + 1,
154 _label
.height() - 2);
155 if (_decorations
& OBClient::Decor_Maximize
)
156 _button_max
.setGeometry(0, _style
->getBevelWidth() + 1,
158 _label
.height() - 2);
159 if (_decorations
& OBClient::Decor_Sticky
)
160 _button_stick
.setGeometry(0, _style
->getBevelWidth() + 1,
162 _label
.height() - 2);
163 if (_decorations
& OBClient::Decor_Close
)
164 _button_close
.setGeometry(0, _style
->getBevelWidth() + 1,
166 _label
.height() - 2);
168 // separation between titlebar elements
169 const int sep
= _style
->getBevelWidth() + 1;
171 std::string layout
= "SLIMC"; // XXX: get this from somewhere
172 // XXX: it is REQUIRED that by this point, the string only has one of each
173 // possible letter, all of the letters are valid, and L exists somewhere in
176 // the size of the label. this ASSUMES the layout has only buttons other
177 // that the ONE LABEL!!
178 // adds an extra sep so that there's a space on either side of the
179 // titlebar.. note: x = sep, below.
180 _label
.setWidth(_label
.width() -
181 ((_button_iconify
.width() + sep
) *
182 (layout
.size() - 1) + sep
* 2));
185 for (int i
= 0, len
= layout
.size(); i
< len
; ++i
) {
188 _button_iconify
.move(x
, _button_iconify
.getRect().y());
189 x
+= _button_iconify
.width();
192 _label
.move(x
, _label
.getRect().y());
196 _button_max
.move(x
, _button_max
.getRect().y());
197 x
+= _button_max
.width();
200 _button_stick
.move(x
, _button_stick
.getRect().y());
201 x
+= _button_stick
.width();
204 _button_close
.move(x
, _button_close
.getRect().y());
205 x
+= _button_close
.width();
208 assert(false); // the layout string is invalid!
214 if (_decorations
& OBClient::Decor_Handle
) {
215 _handle
.setGeometry(-bwidth
,
216 _size
.top
+ _client
->area().height() +
217 _style
->getFrameWidth(),
218 width
, _style
->getHandleWidth());
219 _grip_left
.setGeometry(-bwidth
,
221 // XXX: get a Point class in otk and use that for
222 // the 'buttons size' since theyre all the same
223 _button_iconify
.width() * 2,
225 _grip_right
.setGeometry(((_handle
.getRect().right() + 1) -
226 _button_iconify
.width() * 2),
228 // XXX: get a Point class in otk and use that for
229 // the 'buttons size' since theyre all the same
230 _button_iconify
.width() * 2,
232 _size
.bottom
+= _handle
.height() + bwidth
;
236 // position/size all the windows
238 resize(_size
.left
+ _size
.right
+ _client
->area().width(),
239 _size
.top
+ _size
.bottom
+ _client
->area().height());
241 XMoveWindow(otk::OBDisplay::display
, _client
->window(),
242 _size
.left
, _size
.top
);
244 // map/unmap all the windows
245 if (_decorations
& OBClient::Decor_Titlebar
) {
247 if (_decorations
& OBClient::Decor_Iconify
)
248 _button_iconify
.show();
250 _button_iconify
.hide();
251 if (_decorations
& OBClient::Decor_Maximize
)
255 if (_decorations
& OBClient::Decor_Sticky
)
256 _button_stick
.show();
258 _button_stick
.hide();
259 if (_decorations
& OBClient::Decor_Close
)
260 _button_close
.show();
262 _button_close
.hide();
265 _titlebar
.hide(true);
268 if (_decorations
& OBClient::Decor_Handle
)
273 // XXX: more is gunna have to happen here
281 void OBFrame::adjustShape()
284 if (!_client
->shaped()) {
285 // clear the shape on the frame window
286 XShapeCombineMask(otk::OBDisplay::display
, getWindow(), ShapeBounding
,
291 // make the frame's shape match the clients
292 XShapeCombineShape(otk::OBDisplay::display
, getWindow(), ShapeBounding
,
295 _client
->window(), ShapeBounding
, ShapeSet
);
301 if (decorations & Decor_Titlebar) {
302 xrect[0].x = xrect[0].y = -frame.border_w;
303 xrect[0].width = frame.rect.width();
304 xrect[0].height = frame.title_h + (frame.border_w * 2);
308 if (decorations & Decor_Handle) {
309 xrect[1].x = -frame.border_w;
310 xrect[1].y = frame.rect.height() - frame.margin.bottom +
311 frame.mwm_border_w - frame.border_w;
312 xrect[1].width = frame.rect.width();
313 xrect[1].height = frame.handle_h + (frame.border_w * 2);
317 XShapeCombineRectangles(otk::OBDisplay::display
, getWindow(),
318 ShapeBounding
, 0, 0, xrect
, num
,
319 ShapeUnion
, Unsorted
);
325 void OBFrame::grabClient()
328 // select the event mask on the frame
329 //XSelectInput(otk::OBDisplay::display, _window, SubstructureRedirectMask);
331 // reparent the client to the frame
332 XReparentWindow(otk::OBDisplay::display
, _client
->window(), getWindow(), 0, 0);
333 _client
->ignore_unmaps
++;
335 // raise the client above the frame
336 //XRaiseWindow(otk::OBDisplay::display, _client->window());
337 // map the client so it maps when the frame does
338 XMapWindow(otk::OBDisplay::display
, _client
->window());
344 void OBFrame::releaseClient(bool remap
)
346 // check if the app has already reparented its window to the root window
348 if (XCheckTypedWindowEvent(otk::OBDisplay::display
, _client
->window(),
349 ReparentNotify
, &ev
)) {
350 remap
= true; // XXX: why do we remap the window if they already
351 // reparented to root?
353 // according to the ICCCM - if the client doesn't reparent to
354 // root, then we have to do it for them
355 XReparentWindow(otk::OBDisplay::display
, _client
->window(),
356 _screen
->getRootWindow(),
357 _client
->area().x(), _client
->area().y());
360 // if we want to remap the window, do so now
362 XMapWindow(otk::OBDisplay::display
, _client
->window());
366 Window
OBFrame::createChild(Window parent
, Cursor cursor
)
368 XSetWindowAttributes attrib_create
;
369 unsigned long create_mask
= CWBackPixmap
| CWBorderPixel
| CWEventMask
;
371 attrib_create
.background_pixmap
= None
;
372 attrib_create
.event_mask
= ButtonPressMask
| ButtonReleaseMask
|
373 ButtonMotionMask
| ExposureMask
;
376 create_mask
|= CWCursor
;
377 attrib_create
.cursor
= cursor
;
380 Window w
= XCreateWindow(otk::OBDisplay::display
, parent
, 0, 0, 1, 1, 0,
381 _screen
->getDepth(), InputOutput
,
382 _screen
->getVisual(), create_mask
, &attrib_create
);
387 Window
OBFrame::createFrame()
389 XSetWindowAttributes attrib_create
;
390 unsigned long create_mask
= CWBackPixmap
| CWBorderPixel
| CWColormap
|
391 CWOverrideRedirect
| CWEventMask
;
393 attrib_create
.background_pixmap
= None
;
394 attrib_create
.colormap
= _screen
->getColormap();
395 attrib_create
.override_redirect
= True
;
396 attrib_create
.event_mask
= EnterWindowMask
| LeaveWindowMask
| ButtonPress
;
398 We catch button presses because other wise they get passed down to the
399 root window, which will then cause root menus to show when you click the
403 return XCreateWindow(otk::OBDisplay::display
, _screen
->getRootWindow(),
405 _screen
->getDepth(), InputOutput
, _screen
->getVisual(),
406 create_mask
, &attrib_create
);