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("S");
60 _label
.setText(_client
->title());
75 void OBFrame::setStyle(otk::Style
*style
)
79 otk::OtkWidget::setStyle(style
);
80 // set the grips' textures
81 _grip_left
.setTexture(style
->getGripFocus());
82 _grip_left
.setUnfocusTexture(style
->getGripUnfocus());
83 _grip_left
.setPressedFocusTexture(style
->getGripFocus());
84 _grip_left
.setPressedUnfocusTexture(style
->getGripUnfocus());
85 _grip_right
.setTexture(style
->getGripFocus());
86 _grip_right
.setUnfocusTexture(style
->getGripUnfocus());
87 _grip_right
.setPressedFocusTexture(style
->getGripFocus());
88 _grip_right
.setPressedUnfocusTexture(style
->getGripUnfocus());
90 _titlebar
.setTexture(style
->getTitleFocus());
91 _titlebar
.setUnfocusTexture(style
->getTitleUnfocus());
92 _handle
.setTexture(style
->getHandleFocus());
93 _handle
.setUnfocusTexture(style
->getHandleUnfocus());
95 // if a style was previously set, then 'replace' is true, cause we're
97 bool replace
= (_style
);
100 // XXX: do shit here whatever
101 // XXX: save the position based on gravity
106 // XXX: change when focus changes!
107 XSetWindowBorder(otk::OBDisplay::display
, _plate
.getWindow(),
108 _style
->getFrameFocus()->color().pixel());
110 XSetWindowBorder(otk::OBDisplay::display
, getWindow(),
111 _style
->getBorderColor()->pixel());
112 XSetWindowBorder(otk::OBDisplay::display
, _titlebar
.getWindow(),
113 _style
->getBorderColor()->pixel());
114 XSetWindowBorder(otk::OBDisplay::display
, _grip_left
.getWindow(),
115 _style
->getBorderColor()->pixel());
116 XSetWindowBorder(otk::OBDisplay::display
, _grip_right
.getWindow(),
117 _style
->getBorderColor()->pixel());
118 XSetWindowBorder(otk::OBDisplay::display
, _handle
.getWindow(),
119 _style
->getBorderColor()->pixel());
121 // if !replace, then adjust() will get called after the client is grabbed!
123 adjust(); // size/position everything
127 void OBFrame::adjust()
129 // XXX: only if not overridden or something!!! MORE LOGIC HERE!!
130 _decorations
= _client
->decorations();
131 _decorations
= 0xffffffff;
133 int width
; // the width of the whole frame
134 int bwidth
; // width to make borders
135 int cbwidth
; // width of the inner client border
137 if (_decorations
& OBClient::Decor_Border
) {
138 bwidth
= _style
->getBorderWidth();
139 cbwidth
= _style
->getFrameWidth();
141 bwidth
= cbwidth
= 0;
142 _size
.left
= _size
.top
= _size
.bottom
= _size
.right
= cbwidth
;
143 width
= _client
->area().width() + cbwidth
* 2;
145 XSetWindowBorderWidth(otk::OBDisplay::display
, _plate
.getWindow(), cbwidth
);
147 XSetWindowBorderWidth(otk::OBDisplay::display
, getWindow(), bwidth
);
148 XSetWindowBorderWidth(otk::OBDisplay::display
, _titlebar
.getWindow(),
150 XSetWindowBorderWidth(otk::OBDisplay::display
, _grip_left
.getWindow(),
152 XSetWindowBorderWidth(otk::OBDisplay::display
, _grip_right
.getWindow(),
154 XSetWindowBorderWidth(otk::OBDisplay::display
, _handle
.getWindow(), bwidth
);
156 if (_decorations
& OBClient::Decor_Titlebar
) {
157 // set the titlebar size
158 _titlebar
.setGeometry(-bwidth
,
161 (_style
->getFont().height() +
162 _style
->getBevelWidth() * 2));
163 _size
.top
+= _titlebar
.height() + bwidth
;
165 // set the label size
166 _label
.setGeometry(0, _style
->getBevelWidth(),
167 width
, _style
->getFont().height());
168 // set the buttons sizes
169 if (_decorations
& OBClient::Decor_Iconify
)
170 _button_iconify
.setGeometry(0, _style
->getBevelWidth() + 1,
172 _label
.height() - 2);
173 if (_decorations
& OBClient::Decor_Maximize
)
174 _button_max
.setGeometry(0, _style
->getBevelWidth() + 1,
176 _label
.height() - 2);
177 if (_decorations
& OBClient::Decor_Sticky
)
178 _button_stick
.setGeometry(0, _style
->getBevelWidth() + 1,
180 _label
.height() - 2);
181 if (_decorations
& OBClient::Decor_Close
)
182 _button_close
.setGeometry(0, _style
->getBevelWidth() + 1,
184 _label
.height() - 2);
186 // separation between titlebar elements
187 const int sep
= _style
->getBevelWidth() + 1;
189 std::string layout
= "SLIMC"; // XXX: get this from somewhere
190 // XXX: it is REQUIRED that by this point, the string only has one of each
191 // possible letter, all of the letters are valid, and L exists somewhere in
194 // the size of the label. this ASSUMES the layout has only buttons other
195 // that the ONE LABEL!!
196 // adds an extra sep so that there's a space on either side of the
197 // titlebar.. note: x = sep, below.
198 _label
.setWidth(width
- sep
* 2 -
199 (_button_iconify
.width() + sep
) * (layout
.size() - 1));
202 for (int i
= 0, len
= layout
.size(); i
< len
; ++i
) {
205 _button_iconify
.move(x
, _button_iconify
.getRect().y());
206 x
+= _button_iconify
.width();
209 _label
.move(x
, _label
.getRect().y());
213 _button_max
.move(x
, _button_max
.getRect().y());
214 x
+= _button_max
.width();
217 _button_stick
.move(x
, _button_stick
.getRect().y());
218 x
+= _button_stick
.width();
221 _button_close
.move(x
, _button_close
.getRect().y());
222 x
+= _button_close
.width();
225 assert(false); // the layout string is invalid!
231 if (_decorations
& OBClient::Decor_Handle
) {
232 _handle
.setGeometry(-bwidth
,
233 _size
.top
+ _client
->area().height() + cbwidth
,
234 width
, _style
->getHandleWidth());
235 _grip_left
.setGeometry(-bwidth
,
237 // XXX: get a Point class in otk and use that for
238 // the 'buttons size' since theyre all the same
239 _button_iconify
.width() * 2,
241 _grip_right
.setGeometry(((_handle
.getRect().right() + 1) -
242 _button_iconify
.width() * 2),
244 // XXX: get a Point class in otk and use that for
245 // the 'buttons size' since theyre all the same
246 _button_iconify
.width() * 2,
248 _size
.bottom
+= _handle
.height() + bwidth
;
252 // position/size all the windows
254 resize(_size
.left
+ _size
.right
+ _client
->area().width(),
255 _size
.top
+ _size
.bottom
+ _client
->area().height());
257 _plate
.setGeometry(_size
.left
- cbwidth
, _size
.top
- cbwidth
,
258 _client
->area().width(), _client
->area().height());
260 // map/unmap all the windows
261 if (_decorations
& OBClient::Decor_Titlebar
) {
263 if (_decorations
& OBClient::Decor_Iconify
)
264 _button_iconify
.show();
266 _button_iconify
.hide();
267 if (_decorations
& OBClient::Decor_Maximize
)
271 if (_decorations
& OBClient::Decor_Sticky
)
272 _button_stick
.show();
274 _button_stick
.hide();
275 if (_decorations
& OBClient::Decor_Close
)
276 _button_close
.show();
278 _button_close
.hide();
281 _titlebar
.hide(true);
284 if (_decorations
& OBClient::Decor_Handle
)
289 // XXX: more is gunna have to happen here
297 void OBFrame::adjustShape()
300 if (!_client
->shaped()) {
301 // clear the shape on the frame window
302 XShapeCombineMask(otk::OBDisplay::display
, getWindow(), ShapeBounding
,
307 // make the frame's shape match the clients
308 XShapeCombineShape(otk::OBDisplay::display
, getWindow(), ShapeBounding
,
311 _client
->window(), ShapeBounding
, ShapeSet
);
317 if (decorations & Decor_Titlebar) {
318 xrect[0].x = xrect[0].y = -frame.border_w;
319 xrect[0].width = frame.rect.width();
320 xrect[0].height = frame.title_h + (frame.border_w * 2);
324 if (decorations & Decor_Handle) {
325 xrect[1].x = -frame.border_w;
326 xrect[1].y = frame.rect.height() - frame.margin.bottom +
327 frame.mwm_border_w - frame.border_w;
328 xrect[1].width = frame.rect.width();
329 xrect[1].height = frame.handle_h + (frame.border_w * 2);
333 XShapeCombineRectangles(otk::OBDisplay::display
, getWindow(),
334 ShapeBounding
, 0, 0, xrect
, num
,
335 ShapeUnion
, Unsorted
);
341 void OBFrame::grabClient()
344 // select the event mask on the frame
345 //XSelectInput(otk::OBDisplay::display, _window, SubstructureRedirectMask);
347 // reparent the client to the frame
348 XReparentWindow(otk::OBDisplay::display
, _client
->window(),
349 _plate
.getWindow(), 0, 0);
350 _client
->ignore_unmaps
++;
352 // raise the client above the frame
353 //XRaiseWindow(otk::OBDisplay::display, _client->window());
354 // map the client so it maps when the frame does
355 XMapWindow(otk::OBDisplay::display
, _client
->window());
361 void OBFrame::releaseClient(bool remap
)
363 // check if the app has already reparented its window to the root window
365 if (XCheckTypedWindowEvent(otk::OBDisplay::display
, _client
->window(),
366 ReparentNotify
, &ev
)) {
367 remap
= true; // XXX: why do we remap the window if they already
368 // reparented to root?
370 // according to the ICCCM - if the client doesn't reparent to
371 // root, then we have to do it for them
372 XReparentWindow(otk::OBDisplay::display
, _client
->window(),
373 _screen
->getRootWindow(),
374 _client
->area().x(), _client
->area().y());
377 // if we want to remap the window, do so now
379 XMapWindow(otk::OBDisplay::display
, _client
->window());
383 Window
OBFrame::createChild(Window parent
, Cursor cursor
)
385 XSetWindowAttributes attrib_create
;
386 unsigned long create_mask
= CWBackPixmap
| CWBorderPixel
| CWEventMask
;
388 attrib_create
.background_pixmap
= None
;
389 attrib_create
.event_mask
= ButtonPressMask
| ButtonReleaseMask
|
390 ButtonMotionMask
| ExposureMask
;
393 create_mask
|= CWCursor
;
394 attrib_create
.cursor
= cursor
;
397 Window w
= XCreateWindow(otk::OBDisplay::display
, parent
, 0, 0, 1, 1, 0,
398 _screen
->getDepth(), InputOutput
,
399 _screen
->getVisual(), create_mask
, &attrib_create
);
404 Window
OBFrame::createFrame()
406 XSetWindowAttributes attrib_create
;
407 unsigned long create_mask
= CWBackPixmap
| CWBorderPixel
| CWColormap
|
408 CWOverrideRedirect
| CWEventMask
;
410 attrib_create
.background_pixmap
= None
;
411 attrib_create
.colormap
= _screen
->getColormap();
412 attrib_create
.override_redirect
= True
;
413 attrib_create
.event_mask
= EnterWindowMask
| LeaveWindowMask
| ButtonPress
;
415 We catch button presses because other wise they get passed down to the
416 root window, which will then cause root menus to show when you click the
420 return XCreateWindow(otk::OBDisplay::display
, _screen
->getRootWindow(),
422 _screen
->getDepth(), InputOutput
, _screen
->getVisual(),
423 create_mask
, &attrib_create
);