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
);
77 // if a style was previously set, then 'replace' is true, cause we're
79 bool replace
= (_style
);
82 // XXX: do shit here whatever
83 // XXX: save the position based on gravity
88 XSetWindowBorder(otk::OBDisplay::display
, getWindow(),
89 _style
->getBorderColor()->pixel());
90 XSetWindowBorder(otk::OBDisplay::display
, _titlebar
.getWindow(),
91 _style
->getBorderColor()->pixel());
92 XSetWindowBorder(otk::OBDisplay::display
, _grip_left
.getWindow(),
93 _style
->getBorderColor()->pixel());
94 XSetWindowBorder(otk::OBDisplay::display
, _grip_right
.getWindow(),
95 _style
->getBorderColor()->pixel());
96 XSetWindowBorder(otk::OBDisplay::display
, _handle
.getWindow(),
97 _style
->getBorderColor()->pixel());
100 XSetWindowBackground(otk::OBDisplay::display
, getWindow(),
101 _style
->getFrameFocus()->color().pixel());
103 // XXX: XSetWindowBackground(otk::OBDisplay::display, _window,
104 // XXX: _style->getFrameUnfocus().color().pixel());
106 // if !replace, then adjust() will get called after the client is grabbed!
108 adjust(); // size/position everything
112 void OBFrame::adjust()
114 // XXX: only if not overridden or something!!! MORE LOGIC HERE!!
115 _decorations
= _client
->decorations();
116 _decorations
= 0xffffffff;
118 int width
; // the width of the client window and the border around it
119 int bwidth
; // width to make borders
121 if (_decorations
& OBClient::Decor_Border
) {
122 bwidth
= _style
->getBorderWidth();
123 _size
.left
= _size
.top
= _size
.bottom
= _size
.right
=
124 _style
->getFrameWidth();
125 width
= _client
->area().width() + _style
->getFrameWidth() * 2;
128 _size
.left
= _size
.top
= _size
.bottom
= _size
.right
= 0;
129 width
= _client
->area().width();
131 XSetWindowBorderWidth(otk::OBDisplay::display
, getWindow(), bwidth
);
132 XSetWindowBorderWidth(otk::OBDisplay::display
, _titlebar
.getWindow(),
134 XSetWindowBorderWidth(otk::OBDisplay::display
, _grip_left
.getWindow(),
136 XSetWindowBorderWidth(otk::OBDisplay::display
, _grip_right
.getWindow(),
138 XSetWindowBorderWidth(otk::OBDisplay::display
, _handle
.getWindow(), bwidth
);
140 if (_decorations
& OBClient::Decor_Titlebar
) {
141 // set the titlebar size
142 _titlebar
.setGeometry(-bwidth
,
145 (_style
->getFont().height() +
146 _style
->getBevelWidth() * 2));
147 _size
.top
+= _titlebar
.height() + bwidth
;
149 // set the label size
150 _label
.setGeometry(0, _style
->getBevelWidth(),
151 width
, _style
->getFont().height());
152 // set the buttons sizes
153 if (_decorations
& OBClient::Decor_Iconify
)
154 _button_iconify
.setGeometry(0, _style
->getBevelWidth() + 1,
156 _label
.height() - 2);
157 if (_decorations
& OBClient::Decor_Maximize
)
158 _button_max
.setGeometry(0, _style
->getBevelWidth() + 1,
160 _label
.height() - 2);
161 if (_decorations
& OBClient::Decor_Sticky
)
162 _button_stick
.setGeometry(0, _style
->getBevelWidth() + 1,
164 _label
.height() - 2);
165 if (_decorations
& OBClient::Decor_Close
)
166 _button_close
.setGeometry(0, _style
->getBevelWidth() + 1,
168 _label
.height() - 2);
170 // separation between titlebar elements
171 const int sep
= _style
->getBevelWidth() + 1;
173 std::string layout
= "SLIMC"; // XXX: get this from somewhere
174 // XXX: it is REQUIRED that by this point, the string only has one of each
175 // possible letter, all of the letters are valid, and L exists somewhere in
178 // the size of the label. this ASSUMES the layout has only buttons other
179 // that the ONE LABEL!!
180 // adds an extra sep so that there's a space on either side of the
181 // titlebar.. note: x = sep, below.
182 _label
.setWidth(_label
.width() -
183 ((_button_iconify
.width() + sep
) *
184 (layout
.size() - 1) + sep
* 2));
187 for (int i
= 0, len
= layout
.size(); i
< len
; ++i
) {
190 _button_iconify
.move(x
, _button_iconify
.getRect().y());
191 x
+= _button_iconify
.width();
194 _label
.move(x
, _label
.getRect().y());
198 _button_max
.move(x
, _button_max
.getRect().y());
199 x
+= _button_max
.width();
202 _button_stick
.move(x
, _button_stick
.getRect().y());
203 x
+= _button_stick
.width();
206 _button_close
.move(x
, _button_close
.getRect().y());
207 x
+= _button_close
.width();
210 assert(false); // the layout string is invalid!
216 if (_decorations
& OBClient::Decor_Handle
) {
217 _handle
.setGeometry(-bwidth
,
218 _size
.top
+ _client
->area().height() +
219 _style
->getFrameWidth(),
220 width
, _style
->getHandleWidth());
221 _grip_left
.setGeometry(-bwidth
,
223 // XXX: get a Point class in otk and use that for
224 // the 'buttons size' since theyre all the same
225 _button_iconify
.width() * 2,
227 _grip_right
.setGeometry(((_handle
.getRect().right() + 1) -
228 _button_iconify
.width() * 2),
230 // XXX: get a Point class in otk and use that for
231 // the 'buttons size' since theyre all the same
232 _button_iconify
.width() * 2,
234 _size
.bottom
+= _handle
.height() + bwidth
;
238 // position/size all the windows
240 resize(_size
.left
+ _size
.right
+ _client
->area().width(),
241 _size
.top
+ _size
.bottom
+ _client
->area().height());
243 XMoveWindow(otk::OBDisplay::display
, _client
->window(),
244 _size
.left
, _size
.top
);
246 // map/unmap all the windows
247 if (_decorations
& OBClient::Decor_Titlebar
) {
249 if (_decorations
& OBClient::Decor_Iconify
)
250 _button_iconify
.show();
252 _button_iconify
.hide();
253 if (_decorations
& OBClient::Decor_Maximize
)
257 if (_decorations
& OBClient::Decor_Sticky
)
258 _button_stick
.show();
260 _button_stick
.hide();
261 if (_decorations
& OBClient::Decor_Close
)
262 _button_close
.show();
264 _button_close
.hide();
267 _titlebar
.hide(true);
270 if (_decorations
& OBClient::Decor_Handle
)
275 // XXX: more is gunna have to happen here
283 void OBFrame::adjustShape()
286 if (!_client
->shaped()) {
287 // clear the shape on the frame window
288 XShapeCombineMask(otk::OBDisplay::display
, getWindow(), ShapeBounding
,
293 // make the frame's shape match the clients
294 XShapeCombineShape(otk::OBDisplay::display
, getWindow(), ShapeBounding
,
297 _client
->window(), ShapeBounding
, ShapeSet
);
303 if (decorations & Decor_Titlebar) {
304 xrect[0].x = xrect[0].y = -frame.border_w;
305 xrect[0].width = frame.rect.width();
306 xrect[0].height = frame.title_h + (frame.border_w * 2);
310 if (decorations & Decor_Handle) {
311 xrect[1].x = -frame.border_w;
312 xrect[1].y = frame.rect.height() - frame.margin.bottom +
313 frame.mwm_border_w - frame.border_w;
314 xrect[1].width = frame.rect.width();
315 xrect[1].height = frame.handle_h + (frame.border_w * 2);
319 XShapeCombineRectangles(otk::OBDisplay::display
, getWindow(),
320 ShapeBounding
, 0, 0, xrect
, num
,
321 ShapeUnion
, Unsorted
);
327 void OBFrame::grabClient()
330 // select the event mask on the frame
331 //XSelectInput(otk::OBDisplay::display, _window, SubstructureRedirectMask);
333 // reparent the client to the frame
334 XReparentWindow(otk::OBDisplay::display
, _client
->window(), getWindow(), 0, 0);
335 _client
->ignore_unmaps
++;
337 // raise the client above the frame
338 //XRaiseWindow(otk::OBDisplay::display, _client->window());
339 // map the client so it maps when the frame does
340 XMapWindow(otk::OBDisplay::display
, _client
->window());
346 void OBFrame::releaseClient(bool remap
)
348 // check if the app has already reparented its window to the root window
350 if (XCheckTypedWindowEvent(otk::OBDisplay::display
, _client
->window(),
351 ReparentNotify
, &ev
)) {
352 remap
= true; // XXX: why do we remap the window if they already
353 // reparented to root?
355 // according to the ICCCM - if the client doesn't reparent to
356 // root, then we have to do it for them
357 XReparentWindow(otk::OBDisplay::display
, _client
->window(),
358 _screen
->getRootWindow(),
359 _client
->area().x(), _client
->area().y());
362 // if we want to remap the window, do so now
364 XMapWindow(otk::OBDisplay::display
, _client
->window());
368 Window
OBFrame::createChild(Window parent
, Cursor cursor
)
370 XSetWindowAttributes attrib_create
;
371 unsigned long create_mask
= CWBackPixmap
| CWBorderPixel
| CWEventMask
;
373 attrib_create
.background_pixmap
= None
;
374 attrib_create
.event_mask
= ButtonPressMask
| ButtonReleaseMask
|
375 ButtonMotionMask
| ExposureMask
;
378 create_mask
|= CWCursor
;
379 attrib_create
.cursor
= cursor
;
382 Window w
= XCreateWindow(otk::OBDisplay::display
, parent
, 0, 0, 1, 1, 0,
383 _screen
->getDepth(), InputOutput
,
384 _screen
->getVisual(), create_mask
, &attrib_create
);
389 Window
OBFrame::createFrame()
391 XSetWindowAttributes attrib_create
;
392 unsigned long create_mask
= CWBackPixmap
| CWBorderPixel
| CWColormap
|
393 CWOverrideRedirect
| CWEventMask
;
395 attrib_create
.background_pixmap
= None
;
396 attrib_create
.colormap
= _screen
->getColormap();
397 attrib_create
.override_redirect
= True
;
398 attrib_create
.event_mask
= EnterWindowMask
| LeaveWindowMask
| ButtonPress
;
400 We catch button presses because other wise they get passed down to the
401 root window, which will then cause root menus to show when you click the
405 return XCreateWindow(otk::OBDisplay::display
, _screen
->getRootWindow(),
407 _screen
->getDepth(), InputOutput
, _screen
->getVisual(),
408 create_mask
, &attrib_create
);