]> Dogcows Code - chaz/openbox/blob - src/frame.cc
2a42327ad1dde5722a33e0620bbb63bc24e22b80
[chaz/openbox] / src / frame.cc
1 // -*- mode: C++; indent-tabs-mode: nil; c-basic-offset: 2; -*-
2
3 #ifdef HAVE_CONFIG_H
4 # include "../config.h"
5 #endif
6
7 extern "C" {
8 #ifdef SHAPE
9 #include <X11/extensions/shape.h>
10 #endif // SHAPE
11 }
12
13 #include "openbox.hh"
14 #include "frame.hh"
15 #include "client.hh"
16 #include "otk/display.hh"
17
18 #include <string>
19 #include <iostream> // TEMP
20
21 namespace ob {
22
23 OBFrame::OBFrame(OBClient *client, otk::Style *style)
24 : otk::OtkWidget(Openbox::instance, style),
25 _client(client),
26 _screen(otk::OBDisplay::screenInfo(client->screen())),
27 _titlebar(this),
28 _button_close(&_titlebar),
29 _button_iconify(&_titlebar),
30 _button_max(&_titlebar),
31 _button_stick(&_titlebar),
32 _label(&_titlebar),
33 _handle(this),
34 _grip_left(&_handle),
35 _grip_right(&_handle),
36 _decorations(client->decorations())
37 {
38 assert(client);
39 assert(style);
40
41 unmanaged();
42 _titlebar.unmanaged();
43 _button_close.unmanaged();
44 _button_iconify.unmanaged();
45 _button_max.unmanaged();
46 _button_stick.unmanaged();
47 _label.unmanaged();
48 _handle.unmanaged();
49 _grip_left.unmanaged();
50 _grip_right.unmanaged();
51
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());
57
58 _style = 0;
59 setStyle(style);
60
61 grabClient();
62 }
63
64
65 OBFrame::~OBFrame()
66 {
67 releaseClient(false);
68 }
69
70
71 void OBFrame::setStyle(otk::Style *style)
72 {
73 assert(style);
74
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());
81
82 // if a style was previously set, then 'replace' is true, cause we're
83 // replacing a style
84 bool replace = (_style);
85
86 if (replace) {
87 // XXX: do shit here whatever
88 // XXX: save the position based on gravity
89 }
90
91 _style = style;
92
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());
103
104 // if !replace, then adjust() will get called after the client is grabbed!
105 if (replace)
106 adjust(); // size/position everything
107 }
108
109
110 void OBFrame::adjust()
111 {
112 // XXX: only if not overridden or something!!! MORE LOGIC HERE!!
113 _decorations = _client->decorations();
114 _decorations = 0xffffffff;
115
116 int width; // the width of the client window and the border around it
117 int bwidth; // width to make borders
118
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;
124 } else {
125 bwidth = 0;
126 _size.left = _size.top = _size.bottom = _size.right = 0;
127 width = _client->area().width();
128 }
129 XSetWindowBorderWidth(otk::OBDisplay::display, getWindow(), bwidth);
130 XSetWindowBorderWidth(otk::OBDisplay::display, _titlebar.getWindow(),
131 bwidth);
132 XSetWindowBorderWidth(otk::OBDisplay::display, _grip_left.getWindow(),
133 bwidth);
134 XSetWindowBorderWidth(otk::OBDisplay::display, _grip_right.getWindow(),
135 bwidth);
136 XSetWindowBorderWidth(otk::OBDisplay::display, _handle.getWindow(), bwidth);
137
138 if (_decorations & OBClient::Decor_Titlebar) {
139 // set the titlebar size
140 _titlebar.setGeometry(-bwidth,
141 -bwidth,
142 width,
143 (_style->getFont().height() +
144 _style->getBevelWidth() * 2));
145 _size.top += _titlebar.height() + bwidth;
146
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,
153 _label.height() - 2,
154 _label.height() - 2);
155 if (_decorations & OBClient::Decor_Maximize)
156 _button_max.setGeometry(0, _style->getBevelWidth() + 1,
157 _label.height() - 2,
158 _label.height() - 2);
159 if (_decorations & OBClient::Decor_Sticky)
160 _button_stick.setGeometry(0, _style->getBevelWidth() + 1,
161 _label.height() - 2,
162 _label.height() - 2);
163 if (_decorations & OBClient::Decor_Close)
164 _button_close.setGeometry(0, _style->getBevelWidth() + 1,
165 _label.height() - 2,
166 _label.height() - 2);
167
168 // separation between titlebar elements
169 const int sep = _style->getBevelWidth() + 1;
170
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
174 // the string!
175
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));
183
184 int x = sep;
185 for (int i = 0, len = layout.size(); i < len; ++i) {
186 switch (layout[i]) {
187 case 'I':
188 _button_iconify.move(x, _button_iconify.getRect().y());
189 x += _button_iconify.width();
190 break;
191 case 'L':
192 _label.move(x, _label.getRect().y());
193 x += _label.width();
194 break;
195 case 'M':
196 _button_max.move(x, _button_max.getRect().y());
197 x += _button_max.width();
198 break;
199 case 'S':
200 _button_stick.move(x, _button_stick.getRect().y());
201 x += _button_stick.width();
202 break;
203 case 'C':
204 _button_close.move(x, _button_close.getRect().y());
205 x += _button_close.width();
206 break;
207 default:
208 assert(false); // the layout string is invalid!
209 }
210 x += sep;
211 }
212 }
213
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,
220 -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,
224 _handle.height());
225 _grip_right.setGeometry(((_handle.getRect().right() + 1) -
226 _button_iconify.width() * 2),
227 -bwidth,
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,
231 _handle.height());
232 _size.bottom += _handle.height() + bwidth;
233 }
234
235
236 // position/size all the windows
237
238 resize(_size.left + _size.right + _client->area().width(),
239 _size.top + _size.bottom + _client->area().height());
240
241 XMoveWindow(otk::OBDisplay::display, _client->window(),
242 _size.left, _size.top);
243
244 // map/unmap all the windows
245 if (_decorations & OBClient::Decor_Titlebar) {
246 _label.show();
247 if (_decorations & OBClient::Decor_Iconify)
248 _button_iconify.show();
249 else
250 _button_iconify.hide();
251 if (_decorations & OBClient::Decor_Maximize)
252 _button_max.show();
253 else
254 _button_max.hide();
255 if (_decorations & OBClient::Decor_Sticky)
256 _button_stick.show();
257 else
258 _button_stick.hide();
259 if (_decorations & OBClient::Decor_Close)
260 _button_close.show();
261 else
262 _button_close.hide();
263 _titlebar.show();
264 } else {
265 _titlebar.hide(true);
266 }
267
268 if (_decorations & OBClient::Decor_Handle)
269 _handle.show(true);
270 else
271 _handle.hide(true);
272
273 // XXX: more is gunna have to happen here
274
275 adjustShape();
276
277 update();
278 }
279
280
281 void OBFrame::adjustShape()
282 {
283 #ifdef SHAPE
284 if (!_client->shaped()) {
285 // clear the shape on the frame window
286 XShapeCombineMask(otk::OBDisplay::display, getWindow(), ShapeBounding,
287 _size.left,
288 _size.top,
289 None, ShapeSet);
290 } else {
291 // make the frame's shape match the clients
292 XShapeCombineShape(otk::OBDisplay::display, getWindow(), ShapeBounding,
293 _size.left,
294 _size.top,
295 _client->window(), ShapeBounding, ShapeSet);
296
297 int num = 0;
298 XRectangle xrect[2];
299
300 /*
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);
305 ++num;
306 }
307
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);
314 ++num;
315 }*/
316
317 XShapeCombineRectangles(otk::OBDisplay::display, getWindow(),
318 ShapeBounding, 0, 0, xrect, num,
319 ShapeUnion, Unsorted);
320 }
321 #endif // SHAPE
322 }
323
324
325 void OBFrame::grabClient()
326 {
327
328 // select the event mask on the frame
329 //XSelectInput(otk::OBDisplay::display, _window, SubstructureRedirectMask);
330
331 // reparent the client to the frame
332 XReparentWindow(otk::OBDisplay::display, _client->window(), getWindow(), 0, 0);
333 _client->ignore_unmaps++;
334
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());
339
340 adjust();
341 }
342
343
344 void OBFrame::releaseClient(bool remap)
345 {
346 // check if the app has already reparented its window to the root window
347 XEvent ev;
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?
352 } else {
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());
358 }
359
360 // if we want to remap the window, do so now
361 if (remap)
362 XMapWindow(otk::OBDisplay::display, _client->window());
363 }
364
365
366 Window OBFrame::createChild(Window parent, Cursor cursor)
367 {
368 XSetWindowAttributes attrib_create;
369 unsigned long create_mask = CWBackPixmap | CWBorderPixel | CWEventMask;
370
371 attrib_create.background_pixmap = None;
372 attrib_create.event_mask = ButtonPressMask | ButtonReleaseMask |
373 ButtonMotionMask | ExposureMask;
374
375 if (cursor) {
376 create_mask |= CWCursor;
377 attrib_create.cursor = cursor;
378 }
379
380 Window w = XCreateWindow(otk::OBDisplay::display, parent, 0, 0, 1, 1, 0,
381 _screen->getDepth(), InputOutput,
382 _screen->getVisual(), create_mask, &attrib_create);
383 return w;
384 }
385
386
387 Window OBFrame::createFrame()
388 {
389 XSetWindowAttributes attrib_create;
390 unsigned long create_mask = CWBackPixmap | CWBorderPixel | CWColormap |
391 CWOverrideRedirect | CWEventMask;
392
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;
397 /*
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
400 window's frame.
401 */
402
403 return XCreateWindow(otk::OBDisplay::display, _screen->getRootWindow(),
404 0, 0, 1, 1, 0,
405 _screen->getDepth(), InputOutput, _screen->getVisual(),
406 create_mask, &attrib_create);
407 }
408
409 }
This page took 0.057728 seconds and 4 git commands to generate.