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())),
29 _button_close(&_titlebar
),
30 _button_iconify(&_titlebar
),
31 _button_max(&_titlebar
),
32 _button_stick(&_titlebar
),
36 _grip_right(&_handle
),
37 _decorations(client
->decorations())
43 _titlebar
.unmanaged();
44 _button_close
.unmanaged();
45 _button_iconify
.unmanaged();
46 _button_max
.unmanaged();
47 _button_stick
.unmanaged();
50 _grip_left
.unmanaged();
51 _grip_right
.unmanaged();
56 _button_close
.setText("X");
57 _button_iconify
.setText("I");
58 _button_max
.setText("M");
59 _button_stick
.setText("C");
60 _label
.setText(_client
->title());
75 void OBFrame::setStyle(otk::Style
*style
)
79 otk::OtkWidget::setStyle(style
);
80 // don't let grips change textures when they are pressed
81 _grip_left
.setPressedFocusTexture(_grip_left
.getTexture());
82 _grip_left
.setPressedUnfocusTexture(_grip_left
.getUnfocusTexture());
83 _grip_right
.setPressedFocusTexture(_grip_right
.getTexture());
84 _grip_right
.setPressedUnfocusTexture(_grip_right
.getUnfocusTexture());
86 // if a style was previously set, then 'replace' is true, cause we're
88 bool replace
= (_style
);
91 // XXX: do shit here whatever
92 // XXX: save the position based on gravity
97 // XXX: change when focus changes!
98 XSetWindowBorder(otk::OBDisplay::display
, _plate
.getWindow(),
99 _style
->getFrameFocus()->color().pixel());
101 XSetWindowBorder(otk::OBDisplay::display
, getWindow(),
102 _style
->getBorderColor()->pixel());
103 XSetWindowBorder(otk::OBDisplay::display
, _titlebar
.getWindow(),
104 _style
->getBorderColor()->pixel());
105 XSetWindowBorder(otk::OBDisplay::display
, _grip_left
.getWindow(),
106 _style
->getBorderColor()->pixel());
107 XSetWindowBorder(otk::OBDisplay::display
, _grip_right
.getWindow(),
108 _style
->getBorderColor()->pixel());
109 XSetWindowBorder(otk::OBDisplay::display
, _handle
.getWindow(),
110 _style
->getBorderColor()->pixel());
112 // if !replace, then adjust() will get called after the client is grabbed!
114 adjust(); // size/position everything
118 void OBFrame::adjust()
120 // XXX: only if not overridden or something!!! MORE LOGIC HERE!!
121 _decorations
= _client
->decorations();
122 _decorations
= 0xffffffff;
124 int width
; // the width of the client window and the border around it
125 int bwidth
; // width to make borders
126 int cbwidth
; // width of the inner client border
128 if (_decorations
& OBClient::Decor_Border
) {
129 bwidth
= _style
->getBorderWidth();
130 cbwidth
= _style
->getFrameWidth();
131 _size
.left
= _size
.top
= _size
.bottom
= _size
.right
=
132 _style
->getFrameWidth();
133 width
= _client
->area().width() + _style
->getFrameWidth() * 2;
135 bwidth
= cbwidth
= 0;
136 _size
.left
= _size
.top
= _size
.bottom
= _size
.right
= 0;
137 width
= _client
->area().width();
139 XSetWindowBorderWidth(otk::OBDisplay::display
, _plate
.getWindow(), cbwidth
);
141 XSetWindowBorderWidth(otk::OBDisplay::display
, getWindow(), bwidth
);
142 XSetWindowBorderWidth(otk::OBDisplay::display
, _titlebar
.getWindow(),
144 XSetWindowBorderWidth(otk::OBDisplay::display
, _grip_left
.getWindow(),
146 XSetWindowBorderWidth(otk::OBDisplay::display
, _grip_right
.getWindow(),
148 XSetWindowBorderWidth(otk::OBDisplay::display
, _handle
.getWindow(), bwidth
);
150 if (_decorations
& OBClient::Decor_Titlebar
) {
151 // set the titlebar size
152 _titlebar
.setGeometry(-bwidth
,
155 (_style
->getFont().height() +
156 _style
->getBevelWidth() * 2));
157 _size
.top
+= _titlebar
.height() + bwidth
;
159 // set the label size
160 _label
.setGeometry(0, _style
->getBevelWidth(),
161 width
, _style
->getFont().height());
162 // set the buttons sizes
163 if (_decorations
& OBClient::Decor_Iconify
)
164 _button_iconify
.setGeometry(0, _style
->getBevelWidth() + 1,
166 _label
.height() - 2);
167 if (_decorations
& OBClient::Decor_Maximize
)
168 _button_max
.setGeometry(0, _style
->getBevelWidth() + 1,
170 _label
.height() - 2);
171 if (_decorations
& OBClient::Decor_Sticky
)
172 _button_stick
.setGeometry(0, _style
->getBevelWidth() + 1,
174 _label
.height() - 2);
175 if (_decorations
& OBClient::Decor_Close
)
176 _button_close
.setGeometry(0, _style
->getBevelWidth() + 1,
178 _label
.height() - 2);
180 // separation between titlebar elements
181 const int sep
= _style
->getBevelWidth() + 1;
183 std::string layout
= "SLIMC"; // XXX: get this from somewhere
184 // XXX: it is REQUIRED that by this point, the string only has one of each
185 // possible letter, all of the letters are valid, and L exists somewhere in
188 // the size of the label. this ASSUMES the layout has only buttons other
189 // that the ONE LABEL!!
190 // adds an extra sep so that there's a space on either side of the
191 // titlebar.. note: x = sep, below.
192 _label
.setWidth(_label
.width() -
193 ((_button_iconify
.width() + sep
) *
194 (layout
.size() - 1) + sep
* 2));
197 for (int i
= 0, len
= layout
.size(); i
< len
; ++i
) {
200 _button_iconify
.move(x
, _button_iconify
.getRect().y());
201 x
+= _button_iconify
.width();
204 _label
.move(x
, _label
.getRect().y());
208 _button_max
.move(x
, _button_max
.getRect().y());
209 x
+= _button_max
.width();
212 _button_stick
.move(x
, _button_stick
.getRect().y());
213 x
+= _button_stick
.width();
216 _button_close
.move(x
, _button_close
.getRect().y());
217 x
+= _button_close
.width();
220 assert(false); // the layout string is invalid!
226 if (_decorations
& OBClient::Decor_Handle
) {
227 _handle
.setGeometry(-bwidth
,
228 _size
.top
+ _client
->area().height() +
229 _style
->getFrameWidth(),
230 width
, _style
->getHandleWidth());
231 _grip_left
.setGeometry(-bwidth
,
233 // XXX: get a Point class in otk and use that for
234 // the 'buttons size' since theyre all the same
235 _button_iconify
.width() * 2,
237 _grip_right
.setGeometry(((_handle
.getRect().right() + 1) -
238 _button_iconify
.width() * 2),
240 // XXX: get a Point class in otk and use that for
241 // the 'buttons size' since theyre all the same
242 _button_iconify
.width() * 2,
244 _size
.bottom
+= _handle
.height() + bwidth
;
248 // position/size all the windows
250 resize(_size
.left
+ _size
.right
+ _client
->area().width(),
251 _size
.top
+ _size
.bottom
+ _client
->area().height());
253 _plate
.setGeometry(_size
.left
, _size
.top
, _client
->area().width(),
254 _client
->area().height());
256 // map/unmap all the windows
257 if (_decorations
& OBClient::Decor_Titlebar
) {
259 if (_decorations
& OBClient::Decor_Iconify
)
260 _button_iconify
.show();
262 _button_iconify
.hide();
263 if (_decorations
& OBClient::Decor_Maximize
)
267 if (_decorations
& OBClient::Decor_Sticky
)
268 _button_stick
.show();
270 _button_stick
.hide();
271 if (_decorations
& OBClient::Decor_Close
)
272 _button_close
.show();
274 _button_close
.hide();
277 _titlebar
.hide(true);
280 if (_decorations
& OBClient::Decor_Handle
)
285 // XXX: more is gunna have to happen here
293 void OBFrame::adjustShape()
296 if (!_client
->shaped()) {
297 // clear the shape on the frame window
298 XShapeCombineMask(otk::OBDisplay::display
, getWindow(), ShapeBounding
,
303 // make the frame's shape match the clients
304 XShapeCombineShape(otk::OBDisplay::display
, getWindow(), ShapeBounding
,
307 _client
->window(), ShapeBounding
, ShapeSet
);
313 if (decorations & Decor_Titlebar) {
314 xrect[0].x = xrect[0].y = -frame.border_w;
315 xrect[0].width = frame.rect.width();
316 xrect[0].height = frame.title_h + (frame.border_w * 2);
320 if (decorations & Decor_Handle) {
321 xrect[1].x = -frame.border_w;
322 xrect[1].y = frame.rect.height() - frame.margin.bottom +
323 frame.mwm_border_w - frame.border_w;
324 xrect[1].width = frame.rect.width();
325 xrect[1].height = frame.handle_h + (frame.border_w * 2);
329 XShapeCombineRectangles(otk::OBDisplay::display
, getWindow(),
330 ShapeBounding
, 0, 0, xrect
, num
,
331 ShapeUnion
, Unsorted
);
337 void OBFrame::grabClient()
340 // select the event mask on the frame
341 //XSelectInput(otk::OBDisplay::display, _window, SubstructureRedirectMask);
343 // reparent the client to the frame
344 XReparentWindow(otk::OBDisplay::display
, _client
->window(),
345 _plate
.getWindow(), 0, 0);
346 _client
->ignore_unmaps
++;
348 // raise the client above the frame
349 //XRaiseWindow(otk::OBDisplay::display, _client->window());
350 // map the client so it maps when the frame does
351 XMapWindow(otk::OBDisplay::display
, _client
->window());
357 void OBFrame::releaseClient(bool remap
)
359 // check if the app has already reparented its window to the root window
361 if (XCheckTypedWindowEvent(otk::OBDisplay::display
, _client
->window(),
362 ReparentNotify
, &ev
)) {
363 remap
= true; // XXX: why do we remap the window if they already
364 // reparented to root?
366 // according to the ICCCM - if the client doesn't reparent to
367 // root, then we have to do it for them
368 XReparentWindow(otk::OBDisplay::display
, _client
->window(),
369 _screen
->getRootWindow(),
370 _client
->area().x(), _client
->area().y());
373 // if we want to remap the window, do so now
375 XMapWindow(otk::OBDisplay::display
, _client
->window());
379 Window
OBFrame::createChild(Window parent
, Cursor cursor
)
381 XSetWindowAttributes attrib_create
;
382 unsigned long create_mask
= CWBackPixmap
| CWBorderPixel
| CWEventMask
;
384 attrib_create
.background_pixmap
= None
;
385 attrib_create
.event_mask
= ButtonPressMask
| ButtonReleaseMask
|
386 ButtonMotionMask
| ExposureMask
;
389 create_mask
|= CWCursor
;
390 attrib_create
.cursor
= cursor
;
393 Window w
= XCreateWindow(otk::OBDisplay::display
, parent
, 0, 0, 1, 1, 0,
394 _screen
->getDepth(), InputOutput
,
395 _screen
->getVisual(), create_mask
, &attrib_create
);
400 Window
OBFrame::createFrame()
402 XSetWindowAttributes attrib_create
;
403 unsigned long create_mask
= CWBackPixmap
| CWBorderPixel
| CWColormap
|
404 CWOverrideRedirect
| CWEventMask
;
406 attrib_create
.background_pixmap
= None
;
407 attrib_create
.colormap
= _screen
->getColormap();
408 attrib_create
.override_redirect
= True
;
409 attrib_create
.event_mask
= EnterWindowMask
| LeaveWindowMask
| ButtonPress
;
411 We catch button presses because other wise they get passed down to the
412 root window, which will then cause root menus to show when you click the
416 return XCreateWindow(otk::OBDisplay::display
, _screen
->getRootWindow(),
418 _screen
->getDepth(), InputOutput
, _screen
->getVisual(),
419 create_mask
, &attrib_create
);