]> Dogcows Code - chaz/openbox/blob - src/frame.cc
add \n's to the signal printfs
[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 "frame.hh"
14 #include "client.hh"
15 #include "otk/display.hh"
16
17 #include <string>
18
19 namespace ob {
20
21 OBFrame::OBFrame(const OBClient *client, const otk::Style *style)
22 : _client(client),
23 _screen(otk::OBDisplay::screenInfo(client->screen()))
24 {
25 assert(client);
26 assert(style);
27
28 _decorations = client->decorations();
29
30 _style = 0;
31 loadStyle(style);
32
33 // create the base frame parent window
34 _window = createFrame();
35 assert(_window);
36
37 // create all of the style element child windows
38 _titlebar = createChild(_window, 0);
39 assert(_titlebar);
40 _button_iconify = createChild(_titlebar, 0);
41 assert(_button_iconify);
42 _button_max = createChild(_titlebar, 0);
43 assert(_button_max);
44 _button_stick = createChild(_titlebar, 0);
45 assert(_button_stick);
46 _button_close = createChild(_titlebar, 0);
47 assert(_button_close);
48 _label = createChild(_titlebar, 0);
49 assert(_label);
50 XMapSubwindows(otk::OBDisplay::display, _titlebar);
51
52 _handle = createChild(_window, 0);
53 assert(_handle);
54 _grip_left = createChild(_handle, 0);
55 assert(_grip_left);
56 _grip_right = createChild(_handle, 0);
57 assert(_grip_right);
58 XMapSubwindows(otk::OBDisplay::display, _handle);
59
60 grabClient();
61 }
62
63
64 OBFrame::~OBFrame()
65 {
66 releaseClient(false);
67
68 XDestroyWindow(otk::OBDisplay::display, _titlebar);
69 XDestroyWindow(otk::OBDisplay::display, _button_iconify);
70 XDestroyWindow(otk::OBDisplay::display, _button_max);
71 XDestroyWindow(otk::OBDisplay::display, _button_stick);
72 XDestroyWindow(otk::OBDisplay::display, _button_close);
73 XDestroyWindow(otk::OBDisplay::display, _label);
74 XDestroyWindow(otk::OBDisplay::display, _handle);
75 XDestroyWindow(otk::OBDisplay::display, _grip_left);
76 XDestroyWindow(otk::OBDisplay::display, _grip_right);
77 }
78
79
80 void OBFrame::loadStyle(const otk::Style *style)
81 {
82 assert(style);
83
84 // if a style was previously set, then 'replace' is true, cause we're
85 // replacing a style
86 // NOTE: if this is false, then DO NOT DO SHIT WITH _window, it doesnt exist
87 bool replace = (_style);
88
89 if (replace) {
90 // XXX: do shit here whatever
91 }
92
93 _style = style;
94
95 if (replace) {
96 update();
97
98 XSetWindowBorderWidth(otk::OBDisplay::display, _window,
99 _style->getBorderWidth());
100
101 // XXX: make everything redraw
102 }
103 }
104
105
106 void OBFrame::update()
107 {
108 // XXX: only if not overridden or something!!! MORE LOGIC HERE!!
109 _decorations = _client->decorations();
110
111 int width; // the width of the client window and the border around it
112
113 if (_decorations & OBClient::Decor_Border) {
114 _size.left = _size.top = _size.bottom = _size.right =
115 _style->getBorderWidth() + _style->getFrameWidth();
116 width = _client->area().width() + _style->getFrameWidth() * 2;
117 } else {
118 _size.left = _size.top = _size.bottom = _size.right = 0;
119 width = _client->area().width();
120 }
121
122 if (_decorations & OBClient::Decor_Titlebar) {
123 _titlebar_area.setRect(0, 0, width,
124 (_style->getFont()->height() +
125 _style->getFrameWidth() * 2));
126 _size.top += _titlebar_area.height() + _style->getBorderWidth();
127
128 // set the label size
129 _label_area.setRect(0, _style->getBevelWidth(),
130 width, (_titlebar_area.height() -
131 _style->getBevelWidth() * 2));
132 // set the buttons sizes
133 if (_decorations & OBClient::Decor_Iconify)
134 _button_iconify_area.setRect(0, _style->getBevelWidth() + 1,
135 _label_area.height() - 2,
136 _label_area.height() - 2);
137 if (_decorations & OBClient::Decor_Maximize)
138 _button_max_area.setRect(0, _style->getBevelWidth() + 1,
139 _label_area.height() - 2,
140 _label_area.height() - 2);
141 if (_decorations & OBClient::Decor_Sticky)
142 _button_stick_area.setRect(0, _style->getBevelWidth() + 1,
143 _label_area.height() - 2,
144 _label_area.height() - 2);
145 if (_decorations & OBClient::Decor_Close)
146 _button_close_area.setRect(0, _style->getBevelWidth() + 1,
147 _label_area.height() - 2,
148 _label_area.height() - 2);
149
150 // separation between titlebar elements
151 const int sep = _style->getBevelWidth() + 1;
152
153 std::string layout = "ILMC"; // XXX: get this from somewhere
154 // XXX: it is REQUIRED that by this point, the string only has one of each
155 // possible letter, all of the letters are valid, and L exists somewhere in
156 // the string!
157
158 int x = sep;
159 for (int i = 0, len = layout.size(); i < len; ++i) {
160 otk::Rect *area;
161 switch (layout[i]) {
162 case 'I':
163 if (!(_decorations & OBClient::Decor_Iconify))
164 continue; // skip it
165 area = &_button_iconify_area;
166 break;
167 case 'L':
168 area = &_label_area;
169 break;
170 case 'M':
171 if (!(_decorations & OBClient::Decor_Maximize))
172 continue; // skip it
173 area = &_button_max_area;
174 break;
175 case 'S':
176 if (!(_decorations & OBClient::Decor_Sticky))
177 continue; // skip it
178 area = &_button_stick_area;
179 break;
180 case 'C':
181 if (!(_decorations & OBClient::Decor_Close))
182 continue; // skip it
183 area = &_button_close_area;
184 break;
185 default:
186 assert(false); // the layout string is invalid!
187 continue; // just to fuck with g++
188 }
189 area->setX(x);
190 x += sep + area->width();
191 }
192 }
193
194 if (_decorations & OBClient::Decor_Handle) {
195 _handle_area.setRect(0, _size.top + _client->area().height() +
196 _style->getBorderWidth(),
197 width, _style->getHandleWidth());
198 _grip_left_area.setRect(0,
199 _handle_area.y() + _handle_area.height() +
200 _style->getBorderWidth(),
201 // XXX: get a Point class in otk and use that for
202 // the 'buttons size' since theyre all the same
203 _button_iconify_area.width() * 2,
204 _handle_area.height());
205 _grip_right_area.setRect(((_handle_area.right() + 1) -
206 _button_iconify_area.width() * 2),
207 _handle_area.y() + _handle_area.height() +
208 _style->getBorderWidth(),
209 // XXX: get a Point class in otk and use that for
210 // the 'buttons size' since theyre all the same
211 _button_iconify_area.width() * 2,
212 _handle_area.height());
213 _size.bottom += _handle_area.height() + _style->getBorderWidth() * 2;
214 }
215
216
217 // position/size all the windows
218
219 XResizeWindow(otk::OBDisplay::display, _window,
220 _size.left + _size.right + _client->area().width(),
221 _size.top + _size.bottom + _client->area().height());
222
223 XMoveWindow(otk::OBDisplay::display, _client->window(),
224 _size.left, _size.top);
225
226 if (_decorations & OBClient::Decor_Titlebar) {
227 XMoveResizeWindow(otk::OBDisplay::display, _titlebar,
228 _titlebar_area.x(), _titlebar_area.y(),
229 _titlebar_area.width(), _titlebar_area.height());
230 XMoveResizeWindow(otk::OBDisplay::display, _label,
231 _label_area.x(), _label_area.y(),
232 _label_area.width(), _label_area.height());
233 if (_decorations & OBClient::Decor_Iconify)
234 XMoveResizeWindow(otk::OBDisplay::display, _button_iconify,
235 _button_iconify_area.x(), _button_iconify_area.y(),
236 _button_iconify_area.width(),
237 _button_iconify_area.height());
238 if (_decorations & OBClient::Decor_Maximize)
239 XMoveResizeWindow(otk::OBDisplay::display, _button_max,
240 _button_max_area.x(), _button_max_area.y(),
241 _button_max_area.width(),
242 _button_max_area.height());
243 if (_decorations & OBClient::Decor_Sticky)
244 XMoveResizeWindow(otk::OBDisplay::display, _button_stick,
245 _button_stick_area.x(), _button_stick_area.y(),
246 _button_stick_area.width(),
247 _button_stick_area.height());
248 if (_decorations & OBClient::Decor_Close)
249 XMoveResizeWindow(otk::OBDisplay::display, _button_close,
250 _button_close_area.x(), _button_close_area.y(),
251 _button_close_area.width(),
252 _button_close_area.height());
253 }
254
255 if (_decorations & OBClient::Decor_Handle) {
256 XMoveResizeWindow(otk::OBDisplay::display, _handle,
257 _handle_area.x(), _handle_area.y(),
258 _handle_area.width(), _handle_area.height());
259 XMoveResizeWindow(otk::OBDisplay::display, _grip_left,
260 _grip_left_area.x(), _grip_left_area.y(),
261 _grip_left_area.width(), _grip_left_area.height());
262 XMoveResizeWindow(otk::OBDisplay::display, _grip_right,
263 _grip_right_area.x(), _grip_right_area.y(),
264 _grip_right_area.width(), _grip_right_area.height());
265 }
266
267 // map/unmap all the windows
268 if (_decorations & OBClient::Decor_Titlebar) {
269 XMapWindow(otk::OBDisplay::display, _titlebar);
270 XSetWindowBorder(otk::OBDisplay::display, _titlebar,
271 _style->getBorderWidth());
272 XMapWindow(otk::OBDisplay::display, _label);
273 if (_decorations & OBClient::Decor_Iconify)
274 XMapWindow(otk::OBDisplay::display, _button_iconify);
275 else
276 XUnmapWindow(otk::OBDisplay::display, _button_iconify);
277 if (_decorations & OBClient::Decor_Maximize)
278 XMapWindow(otk::OBDisplay::display, _button_max);
279 else
280 XUnmapWindow(otk::OBDisplay::display, _button_max);
281 if (_decorations & OBClient::Decor_Sticky)
282 XMapWindow(otk::OBDisplay::display, _button_stick);
283 else
284 XUnmapWindow(otk::OBDisplay::display, _button_stick);
285 if (_decorations & OBClient::Decor_Close)
286 XMapWindow(otk::OBDisplay::display, _button_close);
287 else
288 XUnmapWindow(otk::OBDisplay::display, _button_close);
289 } else {
290 XUnmapWindow(otk::OBDisplay::display, _titlebar);
291 XUnmapWindow(otk::OBDisplay::display, _label);
292 XUnmapWindow(otk::OBDisplay::display, _button_iconify);
293 XUnmapWindow(otk::OBDisplay::display, _button_max);
294 XUnmapWindow(otk::OBDisplay::display, _button_stick);
295 XUnmapWindow(otk::OBDisplay::display, _button_close);
296 }
297
298 if (_decorations & OBClient::Decor_Handle) {
299 XMapWindow(otk::OBDisplay::display, _handle);
300 XSetWindowBorder(otk::OBDisplay::display, _handle,
301 _style->getBorderWidth());
302 XMapWindow(otk::OBDisplay::display, _grip_left);
303 XSetWindowBorder(otk::OBDisplay::display, _grip_left,
304 _style->getBorderWidth());
305 XMapWindow(otk::OBDisplay::display, _grip_right);
306 XSetWindowBorder(otk::OBDisplay::display, _grip_right,
307 _style->getBorderWidth());
308 } else {
309 XUnmapWindow(otk::OBDisplay::display, _handle);
310 XUnmapWindow(otk::OBDisplay::display, _grip_left);
311 XUnmapWindow(otk::OBDisplay::display, _grip_right);
312 }
313
314 // XXX: more is gunna have to happen here
315
316 updateShape();
317 }
318
319
320 void OBFrame::updateShape()
321 {
322 #ifdef SHAPE
323 if (!_client->shaped()) {
324 // clear the shape on the frame window
325 XShapeCombineMask(otk::OBDisplay::display, _window, ShapeBounding,
326 _size.left - 2,//frame.margin.left - frame.border_w,
327 _size.top - 2,//frame.margin.top - frame.border_w,
328 None, ShapeSet);
329 } else {
330 // make the frame's shape match the clients
331 XShapeCombineShape(otk::OBDisplay::display, _window, ShapeBounding,
332 _size.left - 2,
333 _size.top - 2,
334 _client->window(), ShapeBounding, ShapeSet);
335
336 int num = 0;
337 XRectangle xrect[2];
338
339 /*
340 if (decorations & Decor_Titlebar) {
341 xrect[0].x = xrect[0].y = -frame.border_w;
342 xrect[0].width = frame.rect.width();
343 xrect[0].height = frame.title_h + (frame.border_w * 2);
344 ++num;
345 }
346
347 if (decorations & Decor_Handle) {
348 xrect[1].x = -frame.border_w;
349 xrect[1].y = frame.rect.height() - frame.margin.bottom +
350 frame.mwm_border_w - frame.border_w;
351 xrect[1].width = frame.rect.width();
352 xrect[1].height = frame.handle_h + (frame.border_w * 2);
353 ++num;
354 }*/
355
356 XShapeCombineRectangles(otk::OBDisplay::display, _window,
357 ShapeBounding, 0, 0, xrect, num,
358 ShapeUnion, Unsorted);
359 }
360 #endif // SHAPE
361 }
362
363
364 void OBFrame::grabClient()
365 {
366
367 XGrabServer(otk::OBDisplay::display);
368
369 // select the event mask on the frame
370 XSelectInput(otk::OBDisplay::display, _window, SubstructureRedirectMask);
371
372 // reparent the client to the frame
373 XSelectInput(otk::OBDisplay::display, _client->window(),
374 OBClient::event_mask & ~StructureNotifyMask);
375 XReparentWindow(otk::OBDisplay::display, _client->window(), _window,
376 _size.left, _size.top);
377 XSelectInput(otk::OBDisplay::display, _client->window(),
378 OBClient::event_mask);
379
380 // raise the client above the frame
381 XRaiseWindow(otk::OBDisplay::display, _client->window());
382 // map the client so it maps when the frame does
383 XMapWindow(otk::OBDisplay::display, _client->window());
384
385 XUngrabServer(otk::OBDisplay::display);
386
387 update();
388 }
389
390
391 void OBFrame::releaseClient(bool remap)
392 {
393 // check if the app has already reparented its window to the root window
394 XEvent ev;
395 if (XCheckTypedWindowEvent(otk::OBDisplay::display, _client->window(),
396 ReparentNotify, &ev)) {
397 remap = true; // XXX: why do we remap the window if they already
398 // reparented to root?
399 } else {
400 // according to the ICCCM - if the client doesn't reparent to
401 // root, then we have to do it for them
402 XReparentWindow(otk::OBDisplay::display, _client->window(),
403 _screen->getRootWindow(),
404 _client->area().x(), _client->area().y());
405 }
406
407 // if we want to remap the window, do so now
408 if (remap)
409 XMapWindow(otk::OBDisplay::display, _client->window());
410 }
411
412
413 Window OBFrame::createChild(Window parent, Cursor cursor)
414 {
415 XSetWindowAttributes attrib_create;
416 unsigned long create_mask = CWBackPixmap | CWBorderPixel | CWEventMask;
417
418 attrib_create.background_pixmap = None;
419 attrib_create.event_mask = ButtonPressMask | ButtonReleaseMask |
420 ButtonMotionMask | ExposureMask;
421
422 if (cursor) {
423 create_mask |= CWCursor;
424 attrib_create.cursor = cursor;
425 }
426
427 return XCreateWindow(otk::OBDisplay::display, parent, 0, 0, 1, 1, 0,
428 _screen->getDepth(), InputOutput, _screen->getVisual(),
429 create_mask, &attrib_create);
430 }
431
432
433 Window OBFrame::createFrame()
434 {
435 XSetWindowAttributes attrib_create;
436 unsigned long create_mask = CWBackPixmap | CWBorderPixel | CWColormap |
437 CWOverrideRedirect | CWEventMask;
438
439 attrib_create.background_pixmap = None;
440 attrib_create.colormap = _screen->getColormap();
441 attrib_create.override_redirect = True;
442 attrib_create.event_mask = EnterWindowMask | LeaveWindowMask | ButtonPress;
443 /*
444 We catch button presses because other wise they get passed down to the
445 root window, which will then cause root menus to show when you click the
446 window's frame.
447 */
448
449 return XCreateWindow(otk::OBDisplay::display, _screen->getRootWindow(),
450 0, 0, 1, 1, _style->getBorderWidth(),
451 _screen->getDepth(), InputOutput, _screen->getVisual(),
452 create_mask, &attrib_create);
453 }
454
455 }
This page took 0.052113 seconds and 4 git commands to generate.