]> Dogcows Code - chaz/openbox/blob - src/frame.cc
handle map requests with the root window class
[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 _plate(this),
28 _titlebar(this),
29 _button_close(&_titlebar),
30 _button_iconify(&_titlebar),
31 _button_max(&_titlebar),
32 _button_stick(&_titlebar),
33 _label(&_titlebar),
34 _handle(this),
35 _grip_left(&_handle),
36 _grip_right(&_handle),
37 _decorations(client->decorations())
38 {
39 assert(client);
40 assert(style);
41
42 unmanaged();
43 _titlebar.unmanaged();
44 _button_close.unmanaged();
45 _button_iconify.unmanaged();
46 _button_max.unmanaged();
47 _button_stick.unmanaged();
48 _label.unmanaged();
49 _handle.unmanaged();
50 _grip_left.unmanaged();
51 _grip_right.unmanaged();
52 _plate.unmanaged();
53
54 _plate.show();
55
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());
61
62 _style = 0;
63 setStyle(style);
64
65 grabClient();
66 }
67
68
69 OBFrame::~OBFrame()
70 {
71 releaseClient(false);
72 }
73
74
75 void OBFrame::setStyle(otk::Style *style)
76 {
77 assert(style);
78
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());
85
86 // if a style was previously set, then 'replace' is true, cause we're
87 // replacing a style
88 bool replace = (_style);
89
90 if (replace) {
91 // XXX: do shit here whatever
92 // XXX: save the position based on gravity
93 }
94
95 _style = style;
96
97 // XXX: change when focus changes!
98 XSetWindowBorder(otk::OBDisplay::display, _plate.getWindow(),
99 _style->getFrameFocus()->color().pixel());
100
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());
111
112 // if !replace, then adjust() will get called after the client is grabbed!
113 if (replace)
114 adjust(); // size/position everything
115 }
116
117
118 void OBFrame::adjust()
119 {
120 // XXX: only if not overridden or something!!! MORE LOGIC HERE!!
121 _decorations = _client->decorations();
122 _decorations = 0xffffffff;
123
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
127
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;
134 } else {
135 bwidth = cbwidth = 0;
136 _size.left = _size.top = _size.bottom = _size.right = 0;
137 width = _client->area().width();
138 }
139 XSetWindowBorderWidth(otk::OBDisplay::display, _plate.getWindow(), cbwidth);
140
141 XSetWindowBorderWidth(otk::OBDisplay::display, getWindow(), bwidth);
142 XSetWindowBorderWidth(otk::OBDisplay::display, _titlebar.getWindow(),
143 bwidth);
144 XSetWindowBorderWidth(otk::OBDisplay::display, _grip_left.getWindow(),
145 bwidth);
146 XSetWindowBorderWidth(otk::OBDisplay::display, _grip_right.getWindow(),
147 bwidth);
148 XSetWindowBorderWidth(otk::OBDisplay::display, _handle.getWindow(), bwidth);
149
150 if (_decorations & OBClient::Decor_Titlebar) {
151 // set the titlebar size
152 _titlebar.setGeometry(-bwidth,
153 -bwidth,
154 width,
155 (_style->getFont().height() +
156 _style->getBevelWidth() * 2));
157 _size.top += _titlebar.height() + bwidth;
158
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,
165 _label.height() - 2,
166 _label.height() - 2);
167 if (_decorations & OBClient::Decor_Maximize)
168 _button_max.setGeometry(0, _style->getBevelWidth() + 1,
169 _label.height() - 2,
170 _label.height() - 2);
171 if (_decorations & OBClient::Decor_Sticky)
172 _button_stick.setGeometry(0, _style->getBevelWidth() + 1,
173 _label.height() - 2,
174 _label.height() - 2);
175 if (_decorations & OBClient::Decor_Close)
176 _button_close.setGeometry(0, _style->getBevelWidth() + 1,
177 _label.height() - 2,
178 _label.height() - 2);
179
180 // separation between titlebar elements
181 const int sep = _style->getBevelWidth() + 1;
182
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
186 // the string!
187
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));
195
196 int x = sep;
197 for (int i = 0, len = layout.size(); i < len; ++i) {
198 switch (layout[i]) {
199 case 'I':
200 _button_iconify.move(x, _button_iconify.getRect().y());
201 x += _button_iconify.width();
202 break;
203 case 'L':
204 _label.move(x, _label.getRect().y());
205 x += _label.width();
206 break;
207 case 'M':
208 _button_max.move(x, _button_max.getRect().y());
209 x += _button_max.width();
210 break;
211 case 'S':
212 _button_stick.move(x, _button_stick.getRect().y());
213 x += _button_stick.width();
214 break;
215 case 'C':
216 _button_close.move(x, _button_close.getRect().y());
217 x += _button_close.width();
218 break;
219 default:
220 assert(false); // the layout string is invalid!
221 }
222 x += sep;
223 }
224 }
225
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,
232 -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,
236 _handle.height());
237 _grip_right.setGeometry(((_handle.getRect().right() + 1) -
238 _button_iconify.width() * 2),
239 -bwidth,
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,
243 _handle.height());
244 _size.bottom += _handle.height() + bwidth;
245 }
246
247
248 // position/size all the windows
249
250 resize(_size.left + _size.right + _client->area().width(),
251 _size.top + _size.bottom + _client->area().height());
252
253 _plate.setGeometry(_size.left, _size.top, _client->area().width(),
254 _client->area().height());
255
256 // map/unmap all the windows
257 if (_decorations & OBClient::Decor_Titlebar) {
258 _label.show();
259 if (_decorations & OBClient::Decor_Iconify)
260 _button_iconify.show();
261 else
262 _button_iconify.hide();
263 if (_decorations & OBClient::Decor_Maximize)
264 _button_max.show();
265 else
266 _button_max.hide();
267 if (_decorations & OBClient::Decor_Sticky)
268 _button_stick.show();
269 else
270 _button_stick.hide();
271 if (_decorations & OBClient::Decor_Close)
272 _button_close.show();
273 else
274 _button_close.hide();
275 _titlebar.show();
276 } else {
277 _titlebar.hide(true);
278 }
279
280 if (_decorations & OBClient::Decor_Handle)
281 _handle.show(true);
282 else
283 _handle.hide(true);
284
285 // XXX: more is gunna have to happen here
286
287 adjustShape();
288
289 update();
290 }
291
292
293 void OBFrame::adjustShape()
294 {
295 #ifdef SHAPE
296 if (!_client->shaped()) {
297 // clear the shape on the frame window
298 XShapeCombineMask(otk::OBDisplay::display, getWindow(), ShapeBounding,
299 _size.left,
300 _size.top,
301 None, ShapeSet);
302 } else {
303 // make the frame's shape match the clients
304 XShapeCombineShape(otk::OBDisplay::display, getWindow(), ShapeBounding,
305 _size.left,
306 _size.top,
307 _client->window(), ShapeBounding, ShapeSet);
308
309 int num = 0;
310 XRectangle xrect[2];
311
312 /*
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);
317 ++num;
318 }
319
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);
326 ++num;
327 }*/
328
329 XShapeCombineRectangles(otk::OBDisplay::display, getWindow(),
330 ShapeBounding, 0, 0, xrect, num,
331 ShapeUnion, Unsorted);
332 }
333 #endif // SHAPE
334 }
335
336
337 void OBFrame::grabClient()
338 {
339
340 // select the event mask on the frame
341 //XSelectInput(otk::OBDisplay::display, _window, SubstructureRedirectMask);
342
343 // reparent the client to the frame
344 XReparentWindow(otk::OBDisplay::display, _client->window(),
345 _plate.getWindow(), 0, 0);
346 _client->ignore_unmaps++;
347
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());
352
353 adjust();
354 }
355
356
357 void OBFrame::releaseClient(bool remap)
358 {
359 // check if the app has already reparented its window to the root window
360 XEvent ev;
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?
365 } else {
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());
371 }
372
373 // if we want to remap the window, do so now
374 if (remap)
375 XMapWindow(otk::OBDisplay::display, _client->window());
376 }
377
378
379 Window OBFrame::createChild(Window parent, Cursor cursor)
380 {
381 XSetWindowAttributes attrib_create;
382 unsigned long create_mask = CWBackPixmap | CWBorderPixel | CWEventMask;
383
384 attrib_create.background_pixmap = None;
385 attrib_create.event_mask = ButtonPressMask | ButtonReleaseMask |
386 ButtonMotionMask | ExposureMask;
387
388 if (cursor) {
389 create_mask |= CWCursor;
390 attrib_create.cursor = cursor;
391 }
392
393 Window w = XCreateWindow(otk::OBDisplay::display, parent, 0, 0, 1, 1, 0,
394 _screen->getDepth(), InputOutput,
395 _screen->getVisual(), create_mask, &attrib_create);
396 return w;
397 }
398
399
400 Window OBFrame::createFrame()
401 {
402 XSetWindowAttributes attrib_create;
403 unsigned long create_mask = CWBackPixmap | CWBorderPixel | CWColormap |
404 CWOverrideRedirect | CWEventMask;
405
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;
410 /*
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
413 window's frame.
414 */
415
416 return XCreateWindow(otk::OBDisplay::display, _screen->getRootWindow(),
417 0, 0, 1, 1, 0,
418 _screen->getDepth(), InputOutput, _screen->getVisual(),
419 create_mask, &attrib_create);
420 }
421
422 }
This page took 0.053126 seconds and 5 git commands to generate.