]> Dogcows Code - chaz/openbox/blob - src/frame.cc
put an S on the stick button
[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("S");
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 // 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());
89
90 _titlebar.setTexture(style->getTitleFocus());
91 _titlebar.setUnfocusTexture(style->getTitleUnfocus());
92 _handle.setTexture(style->getHandleFocus());
93 _handle.setUnfocusTexture(style->getHandleUnfocus());
94
95 // if a style was previously set, then 'replace' is true, cause we're
96 // replacing a style
97 bool replace = (_style);
98
99 if (replace) {
100 // XXX: do shit here whatever
101 // XXX: save the position based on gravity
102 }
103
104 _style = style;
105
106 // XXX: change when focus changes!
107 XSetWindowBorder(otk::OBDisplay::display, _plate.getWindow(),
108 _style->getFrameFocus()->color().pixel());
109
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());
120
121 // if !replace, then adjust() will get called after the client is grabbed!
122 if (replace)
123 adjust(); // size/position everything
124 }
125
126
127 void OBFrame::adjust()
128 {
129 // XXX: only if not overridden or something!!! MORE LOGIC HERE!!
130 _decorations = _client->decorations();
131 _decorations = 0xffffffff;
132
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
136
137 if (_decorations & OBClient::Decor_Border) {
138 bwidth = _style->getBorderWidth();
139 cbwidth = _style->getFrameWidth();
140 } else
141 bwidth = cbwidth = 0;
142 _size.left = _size.top = _size.bottom = _size.right = cbwidth;
143 width = _client->area().width() + cbwidth * 2;
144
145 XSetWindowBorderWidth(otk::OBDisplay::display, _plate.getWindow(), cbwidth);
146
147 XSetWindowBorderWidth(otk::OBDisplay::display, getWindow(), bwidth);
148 XSetWindowBorderWidth(otk::OBDisplay::display, _titlebar.getWindow(),
149 bwidth);
150 XSetWindowBorderWidth(otk::OBDisplay::display, _grip_left.getWindow(),
151 bwidth);
152 XSetWindowBorderWidth(otk::OBDisplay::display, _grip_right.getWindow(),
153 bwidth);
154 XSetWindowBorderWidth(otk::OBDisplay::display, _handle.getWindow(), bwidth);
155
156 if (_decorations & OBClient::Decor_Titlebar) {
157 // set the titlebar size
158 _titlebar.setGeometry(-bwidth,
159 -bwidth,
160 width,
161 (_style->getFont().height() +
162 _style->getBevelWidth() * 2));
163 _size.top += _titlebar.height() + bwidth;
164
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,
171 _label.height() - 2,
172 _label.height() - 2);
173 if (_decorations & OBClient::Decor_Maximize)
174 _button_max.setGeometry(0, _style->getBevelWidth() + 1,
175 _label.height() - 2,
176 _label.height() - 2);
177 if (_decorations & OBClient::Decor_Sticky)
178 _button_stick.setGeometry(0, _style->getBevelWidth() + 1,
179 _label.height() - 2,
180 _label.height() - 2);
181 if (_decorations & OBClient::Decor_Close)
182 _button_close.setGeometry(0, _style->getBevelWidth() + 1,
183 _label.height() - 2,
184 _label.height() - 2);
185
186 // separation between titlebar elements
187 const int sep = _style->getBevelWidth() + 1;
188
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
192 // the string!
193
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));
200
201 int x = sep;
202 for (int i = 0, len = layout.size(); i < len; ++i) {
203 switch (layout[i]) {
204 case 'I':
205 _button_iconify.move(x, _button_iconify.getRect().y());
206 x += _button_iconify.width();
207 break;
208 case 'L':
209 _label.move(x, _label.getRect().y());
210 x += _label.width();
211 break;
212 case 'M':
213 _button_max.move(x, _button_max.getRect().y());
214 x += _button_max.width();
215 break;
216 case 'S':
217 _button_stick.move(x, _button_stick.getRect().y());
218 x += _button_stick.width();
219 break;
220 case 'C':
221 _button_close.move(x, _button_close.getRect().y());
222 x += _button_close.width();
223 break;
224 default:
225 assert(false); // the layout string is invalid!
226 }
227 x += sep;
228 }
229 }
230
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,
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 _grip_right.setGeometry(((_handle.getRect().right() + 1) -
242 _button_iconify.width() * 2),
243 -bwidth,
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,
247 _handle.height());
248 _size.bottom += _handle.height() + bwidth;
249 }
250
251
252 // position/size all the windows
253
254 resize(_size.left + _size.right + _client->area().width(),
255 _size.top + _size.bottom + _client->area().height());
256
257 _plate.setGeometry(_size.left - cbwidth, _size.top - cbwidth,
258 _client->area().width(), _client->area().height());
259
260 // map/unmap all the windows
261 if (_decorations & OBClient::Decor_Titlebar) {
262 _label.show();
263 if (_decorations & OBClient::Decor_Iconify)
264 _button_iconify.show();
265 else
266 _button_iconify.hide();
267 if (_decorations & OBClient::Decor_Maximize)
268 _button_max.show();
269 else
270 _button_max.hide();
271 if (_decorations & OBClient::Decor_Sticky)
272 _button_stick.show();
273 else
274 _button_stick.hide();
275 if (_decorations & OBClient::Decor_Close)
276 _button_close.show();
277 else
278 _button_close.hide();
279 _titlebar.show();
280 } else {
281 _titlebar.hide(true);
282 }
283
284 if (_decorations & OBClient::Decor_Handle)
285 _handle.show(true);
286 else
287 _handle.hide(true);
288
289 // XXX: more is gunna have to happen here
290
291 adjustShape();
292
293 update();
294 }
295
296
297 void OBFrame::adjustShape()
298 {
299 #ifdef SHAPE
300 if (!_client->shaped()) {
301 // clear the shape on the frame window
302 XShapeCombineMask(otk::OBDisplay::display, getWindow(), ShapeBounding,
303 _size.left,
304 _size.top,
305 None, ShapeSet);
306 } else {
307 // make the frame's shape match the clients
308 XShapeCombineShape(otk::OBDisplay::display, getWindow(), ShapeBounding,
309 _size.left,
310 _size.top,
311 _client->window(), ShapeBounding, ShapeSet);
312
313 int num = 0;
314 XRectangle xrect[2];
315
316 /*
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);
321 ++num;
322 }
323
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);
330 ++num;
331 }*/
332
333 XShapeCombineRectangles(otk::OBDisplay::display, getWindow(),
334 ShapeBounding, 0, 0, xrect, num,
335 ShapeUnion, Unsorted);
336 }
337 #endif // SHAPE
338 }
339
340
341 void OBFrame::grabClient()
342 {
343
344 // select the event mask on the frame
345 //XSelectInput(otk::OBDisplay::display, _window, SubstructureRedirectMask);
346
347 // reparent the client to the frame
348 XReparentWindow(otk::OBDisplay::display, _client->window(),
349 _plate.getWindow(), 0, 0);
350 _client->ignore_unmaps++;
351
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());
356
357 adjust();
358 }
359
360
361 void OBFrame::releaseClient(bool remap)
362 {
363 // check if the app has already reparented its window to the root window
364 XEvent ev;
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?
369 } else {
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());
375 }
376
377 // if we want to remap the window, do so now
378 if (remap)
379 XMapWindow(otk::OBDisplay::display, _client->window());
380 }
381
382
383 Window OBFrame::createChild(Window parent, Cursor cursor)
384 {
385 XSetWindowAttributes attrib_create;
386 unsigned long create_mask = CWBackPixmap | CWBorderPixel | CWEventMask;
387
388 attrib_create.background_pixmap = None;
389 attrib_create.event_mask = ButtonPressMask | ButtonReleaseMask |
390 ButtonMotionMask | ExposureMask;
391
392 if (cursor) {
393 create_mask |= CWCursor;
394 attrib_create.cursor = cursor;
395 }
396
397 Window w = XCreateWindow(otk::OBDisplay::display, parent, 0, 0, 1, 1, 0,
398 _screen->getDepth(), InputOutput,
399 _screen->getVisual(), create_mask, &attrib_create);
400 return w;
401 }
402
403
404 Window OBFrame::createFrame()
405 {
406 XSetWindowAttributes attrib_create;
407 unsigned long create_mask = CWBackPixmap | CWBorderPixel | CWColormap |
408 CWOverrideRedirect | CWEventMask;
409
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;
414 /*
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
417 window's frame.
418 */
419
420 return XCreateWindow(otk::OBDisplay::display, _screen->getRootWindow(),
421 0, 0, 1, 1, 0,
422 _screen->getDepth(), InputOutput, _screen->getVisual(),
423 create_mask, &attrib_create);
424 }
425
426 }
This page took 0.050223 seconds and 4 git commands to generate.