]> Dogcows Code - chaz/openbox/blob - src/frame.cc
i dont know what i fixed but here it is
[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 whole frame
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 } else
132 bwidth = cbwidth = 0;
133 _size.left = _size.top = _size.bottom = _size.right = bwidth + cbwidth;
134 width = _client->area().width() + (bwidth + cbwidth) * 2;
135
136 XSetWindowBorderWidth(otk::OBDisplay::display, _plate.getWindow(), cbwidth);
137
138 XSetWindowBorderWidth(otk::OBDisplay::display, getWindow(), bwidth);
139 XSetWindowBorderWidth(otk::OBDisplay::display, _titlebar.getWindow(),
140 bwidth);
141 XSetWindowBorderWidth(otk::OBDisplay::display, _grip_left.getWindow(),
142 bwidth);
143 XSetWindowBorderWidth(otk::OBDisplay::display, _grip_right.getWindow(),
144 bwidth);
145 XSetWindowBorderWidth(otk::OBDisplay::display, _handle.getWindow(), bwidth);
146
147 if (_decorations & OBClient::Decor_Titlebar) {
148 // set the titlebar size
149 _titlebar.setGeometry(-bwidth,
150 -bwidth,
151 width,
152 (_style->getFont().height() +
153 _style->getBevelWidth() * 2));
154 _size.top += _titlebar.height() + bwidth;
155
156 // set the label size
157 _label.setGeometry(0, _style->getBevelWidth(),
158 width, _style->getFont().height());
159 // set the buttons sizes
160 if (_decorations & OBClient::Decor_Iconify)
161 _button_iconify.setGeometry(0, _style->getBevelWidth() + 1,
162 _label.height() - 2,
163 _label.height() - 2);
164 if (_decorations & OBClient::Decor_Maximize)
165 _button_max.setGeometry(0, _style->getBevelWidth() + 1,
166 _label.height() - 2,
167 _label.height() - 2);
168 if (_decorations & OBClient::Decor_Sticky)
169 _button_stick.setGeometry(0, _style->getBevelWidth() + 1,
170 _label.height() - 2,
171 _label.height() - 2);
172 if (_decorations & OBClient::Decor_Close)
173 _button_close.setGeometry(0, _style->getBevelWidth() + 1,
174 _label.height() - 2,
175 _label.height() - 2);
176
177 // separation between titlebar elements
178 const int sep = _style->getBevelWidth() + 1;
179
180 std::string layout = "SLIMC"; // XXX: get this from somewhere
181 // XXX: it is REQUIRED that by this point, the string only has one of each
182 // possible letter, all of the letters are valid, and L exists somewhere in
183 // the string!
184
185 // the size of the label. this ASSUMES the layout has only buttons other
186 // that the ONE LABEL!!
187 // adds an extra sep so that there's a space on either side of the
188 // titlebar.. note: x = sep, below.
189 _label.setWidth(_label.width() -
190 ((_button_iconify.width() + sep) *
191 (layout.size() - 1) + sep * 2));
192
193 int x = sep;
194 for (int i = 0, len = layout.size(); i < len; ++i) {
195 switch (layout[i]) {
196 case 'I':
197 _button_iconify.move(x, _button_iconify.getRect().y());
198 x += _button_iconify.width();
199 break;
200 case 'L':
201 _label.move(x, _label.getRect().y());
202 x += _label.width();
203 break;
204 case 'M':
205 _button_max.move(x, _button_max.getRect().y());
206 x += _button_max.width();
207 break;
208 case 'S':
209 _button_stick.move(x, _button_stick.getRect().y());
210 x += _button_stick.width();
211 break;
212 case 'C':
213 _button_close.move(x, _button_close.getRect().y());
214 x += _button_close.width();
215 break;
216 default:
217 assert(false); // the layout string is invalid!
218 }
219 x += sep;
220 }
221 }
222
223 if (_decorations & OBClient::Decor_Handle) {
224 _handle.setGeometry(-bwidth,
225 _size.top + _client->area().height() +
226 _style->getFrameWidth(),
227 width, _style->getHandleWidth());
228 _grip_left.setGeometry(-bwidth,
229 -bwidth,
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,
233 _handle.height());
234 _grip_right.setGeometry(((_handle.getRect().right() + 1) -
235 _button_iconify.width() * 2),
236 -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,
240 _handle.height());
241 _size.bottom += _handle.height() + bwidth;
242 }
243
244
245 // position/size all the windows
246
247 resize(_size.left + _size.right + _client->area().width(),
248 _size.top + _size.bottom + _client->area().height());
249
250 _plate.setGeometry(_size.left - cbwidth, _size.top - cbwidth,
251 _client->area().width(), _client->area().height());
252
253 // map/unmap all the windows
254 if (_decorations & OBClient::Decor_Titlebar) {
255 _label.show();
256 if (_decorations & OBClient::Decor_Iconify)
257 _button_iconify.show();
258 else
259 _button_iconify.hide();
260 if (_decorations & OBClient::Decor_Maximize)
261 _button_max.show();
262 else
263 _button_max.hide();
264 if (_decorations & OBClient::Decor_Sticky)
265 _button_stick.show();
266 else
267 _button_stick.hide();
268 if (_decorations & OBClient::Decor_Close)
269 _button_close.show();
270 else
271 _button_close.hide();
272 _titlebar.show();
273 } else {
274 _titlebar.hide(true);
275 }
276
277 if (_decorations & OBClient::Decor_Handle)
278 _handle.show(true);
279 else
280 _handle.hide(true);
281
282 // XXX: more is gunna have to happen here
283
284 adjustShape();
285
286 update();
287 }
288
289
290 void OBFrame::adjustShape()
291 {
292 #ifdef SHAPE
293 if (!_client->shaped()) {
294 // clear the shape on the frame window
295 XShapeCombineMask(otk::OBDisplay::display, getWindow(), ShapeBounding,
296 _size.left,
297 _size.top,
298 None, ShapeSet);
299 } else {
300 // make the frame's shape match the clients
301 XShapeCombineShape(otk::OBDisplay::display, getWindow(), ShapeBounding,
302 _size.left,
303 _size.top,
304 _client->window(), ShapeBounding, ShapeSet);
305
306 int num = 0;
307 XRectangle xrect[2];
308
309 /*
310 if (decorations & Decor_Titlebar) {
311 xrect[0].x = xrect[0].y = -frame.border_w;
312 xrect[0].width = frame.rect.width();
313 xrect[0].height = frame.title_h + (frame.border_w * 2);
314 ++num;
315 }
316
317 if (decorations & Decor_Handle) {
318 xrect[1].x = -frame.border_w;
319 xrect[1].y = frame.rect.height() - frame.margin.bottom +
320 frame.mwm_border_w - frame.border_w;
321 xrect[1].width = frame.rect.width();
322 xrect[1].height = frame.handle_h + (frame.border_w * 2);
323 ++num;
324 }*/
325
326 XShapeCombineRectangles(otk::OBDisplay::display, getWindow(),
327 ShapeBounding, 0, 0, xrect, num,
328 ShapeUnion, Unsorted);
329 }
330 #endif // SHAPE
331 }
332
333
334 void OBFrame::grabClient()
335 {
336
337 // select the event mask on the frame
338 //XSelectInput(otk::OBDisplay::display, _window, SubstructureRedirectMask);
339
340 // reparent the client to the frame
341 XReparentWindow(otk::OBDisplay::display, _client->window(),
342 _plate.getWindow(), 0, 0);
343 _client->ignore_unmaps++;
344
345 // raise the client above the frame
346 //XRaiseWindow(otk::OBDisplay::display, _client->window());
347 // map the client so it maps when the frame does
348 XMapWindow(otk::OBDisplay::display, _client->window());
349
350 adjust();
351 }
352
353
354 void OBFrame::releaseClient(bool remap)
355 {
356 // check if the app has already reparented its window to the root window
357 XEvent ev;
358 if (XCheckTypedWindowEvent(otk::OBDisplay::display, _client->window(),
359 ReparentNotify, &ev)) {
360 remap = true; // XXX: why do we remap the window if they already
361 // reparented to root?
362 } else {
363 // according to the ICCCM - if the client doesn't reparent to
364 // root, then we have to do it for them
365 XReparentWindow(otk::OBDisplay::display, _client->window(),
366 _screen->getRootWindow(),
367 _client->area().x(), _client->area().y());
368 }
369
370 // if we want to remap the window, do so now
371 if (remap)
372 XMapWindow(otk::OBDisplay::display, _client->window());
373 }
374
375
376 Window OBFrame::createChild(Window parent, Cursor cursor)
377 {
378 XSetWindowAttributes attrib_create;
379 unsigned long create_mask = CWBackPixmap | CWBorderPixel | CWEventMask;
380
381 attrib_create.background_pixmap = None;
382 attrib_create.event_mask = ButtonPressMask | ButtonReleaseMask |
383 ButtonMotionMask | ExposureMask;
384
385 if (cursor) {
386 create_mask |= CWCursor;
387 attrib_create.cursor = cursor;
388 }
389
390 Window w = XCreateWindow(otk::OBDisplay::display, parent, 0, 0, 1, 1, 0,
391 _screen->getDepth(), InputOutput,
392 _screen->getVisual(), create_mask, &attrib_create);
393 return w;
394 }
395
396
397 Window OBFrame::createFrame()
398 {
399 XSetWindowAttributes attrib_create;
400 unsigned long create_mask = CWBackPixmap | CWBorderPixel | CWColormap |
401 CWOverrideRedirect | CWEventMask;
402
403 attrib_create.background_pixmap = None;
404 attrib_create.colormap = _screen->getColormap();
405 attrib_create.override_redirect = True;
406 attrib_create.event_mask = EnterWindowMask | LeaveWindowMask | ButtonPress;
407 /*
408 We catch button presses because other wise they get passed down to the
409 root window, which will then cause root menus to show when you click the
410 window's frame.
411 */
412
413 return XCreateWindow(otk::OBDisplay::display, _screen->getRootWindow(),
414 0, 0, 1, 1, 0,
415 _screen->getDepth(), InputOutput, _screen->getVisual(),
416 create_mask, &attrib_create);
417 }
418
419 }
This page took 0.051602 seconds and 4 git commands to generate.