]> Dogcows Code - chaz/openbox/blob - src/screen.cc
add/lower work
[chaz/openbox] / src / screen.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 HAVE_STDIO_H
9 # include <stdio.h>
10 #endif // HAVE_STDIO_H
11
12 #ifdef HAVE_UNISTD_H
13 # include <sys/types.h>
14 # include <unistd.h>
15 #endif // HAVE_UNISTD_H
16
17 #include "gettext.h"
18 #define _(str) gettext(str)
19 }
20
21 #include "screen.hh"
22 #include "client.hh"
23 #include "openbox.hh"
24 #include "frame.hh"
25 #include "bindings.hh"
26 #include "python.hh"
27 #include "otk/display.hh"
28
29 #include <vector>
30
31 static bool running;
32 static int anotherWMRunning(Display *display, XErrorEvent *) {
33 printf(_("Another window manager already running on display %s.\n"),
34 DisplayString(display));
35 running = true;
36 return -1;
37 }
38
39
40 namespace ob {
41
42
43 OBScreen::OBScreen(int screen)
44 : _number(screen),
45 _root(screen)
46 {
47 assert(screen >= 0); assert(screen < ScreenCount(otk::OBDisplay::display));
48 _info = otk::OBDisplay::screenInfo(screen);
49
50 ::running = false;
51 XErrorHandler old = XSetErrorHandler(::anotherWMRunning);
52 XSelectInput(otk::OBDisplay::display, _info->rootWindow(),
53 OBScreen::event_mask);
54 XSync(otk::OBDisplay::display, false);
55 XSetErrorHandler(old);
56
57 _managed = !::running;
58 if (! _managed) return; // was unable to manage the screen
59
60 printf(_("Managing screen %d: visual 0x%lx, depth %d\n"),
61 _number, XVisualIDFromVisual(_info->visual()), _info->depth());
62
63 Openbox::instance->property()->set(_info->rootWindow(),
64 otk::OBProperty::openbox_pid,
65 otk::OBProperty::Atom_Cardinal,
66 (unsigned long) getpid());
67
68 // set the mouse cursor for the root window (the default cursor)
69 XDefineCursor(otk::OBDisplay::display, _info->rootWindow(),
70 Openbox::instance->cursors().session);
71
72 // initialize the shit that is used for all drawing on the screen
73 _image_control = new otk::BImageControl(Openbox::instance->timerManager(),
74 _info, true);
75 _image_control->installRootColormap();
76 _root_cmap_installed = True;
77
78 // initialize the screen's style
79 _style.setImageControl(_image_control);
80 std::string stylepath;
81 python_get_string("theme", &stylepath);
82 otk::Configuration sconfig(false);
83 sconfig.setFile(otk::expandTilde(stylepath));
84 if (!sconfig.load()) {
85 sconfig.setFile(otk::expandTilde(DEFAULTSTYLE));
86 if (!sconfig.load()) {
87 printf(_("Unable to load default style: %s. Aborting.\n"), DEFAULTSTYLE);
88 ::exit(1);
89 }
90 }
91 _style.load(sconfig);
92
93 // Set the netwm atoms for geomtery and viewport
94 unsigned long geometry[] = { _info->width(),
95 _info->height() };
96 Openbox::instance->property()->set(_info->rootWindow(),
97 otk::OBProperty::net_desktop_geometry,
98 otk::OBProperty::Atom_Cardinal,
99 geometry, 2);
100 unsigned long viewport[] = { 0, 0 };
101 Openbox::instance->property()->set(_info->rootWindow(),
102 otk::OBProperty::net_desktop_viewport,
103 otk::OBProperty::Atom_Cardinal,
104 viewport, 2);
105
106 // create the window which gets focus when no clients get it
107 XSetWindowAttributes attr;
108 attr.override_redirect = true;
109 _focuswindow = XCreateWindow(otk::OBDisplay::display, _info->rootWindow(),
110 -100, -100, 1, 1, 0, 0, InputOnly,
111 _info->visual(), CWOverrideRedirect, &attr);
112 XMapWindow(otk::OBDisplay::display, _focuswindow);
113
114 // these may be further updated if any pre-existing windows are found in
115 // the manageExising() function
116 setClientList(); // initialize the client lists, which will be empty
117 calcArea(); // initialize the available working area
118 }
119
120
121 OBScreen::~OBScreen()
122 {
123 if (! _managed) return;
124
125 // unmanage all windows
126 while (!clients.empty())
127 unmanageWindow(clients.front());
128
129 delete _image_control;
130 }
131
132
133 void OBScreen::manageExisting()
134 {
135 unsigned int i, j, nchild;
136 Window r, p, *children;
137 XQueryTree(otk::OBDisplay::display, _info->rootWindow(), &r, &p,
138 &children, &nchild);
139
140 // preen the window list of all icon windows... for better dockapp support
141 for (i = 0; i < nchild; i++) {
142 if (children[i] == None) continue;
143
144 XWMHints *wmhints = XGetWMHints(otk::OBDisplay::display,
145 children[i]);
146
147 if (wmhints) {
148 if ((wmhints->flags & IconWindowHint) &&
149 (wmhints->icon_window != children[i])) {
150 for (j = 0; j < nchild; j++) {
151 if (children[j] == wmhints->icon_window) {
152 children[j] = None;
153 break;
154 }
155 }
156 }
157
158 XFree(wmhints);
159 }
160 }
161
162 // manage shown windows
163 for (i = 0; i < nchild; ++i) {
164 if (children[i] == None)
165 continue;
166
167 XWindowAttributes attrib;
168 if (XGetWindowAttributes(otk::OBDisplay::display, children[i], &attrib)) {
169 if (attrib.override_redirect) continue;
170
171 if (attrib.map_state != IsUnmapped) {
172 manageWindow(children[i]);
173 }
174 }
175 }
176
177 XFree(children);
178 }
179
180
181 //! Adds a window's strut to the screen's list of reserved spaces
182 void OBScreen::addStrut(otk::Strut *strut)
183 {
184 _struts.push_back(strut);
185 }
186
187
188 //! Removes a window's strut from the screen's list of reserved spaces
189 void OBScreen::removeStrut(otk::Strut *strut)
190 {
191 _struts.remove(strut);
192 }
193
194
195 void OBScreen::calcArea()
196 {
197 otk::Rect old_area = _area;
198
199 /*
200 #ifdef XINERAMA
201 // reset to the full areas
202 if (isXineramaActive())
203 xineramaUsableArea = getXineramaAreas();
204 #endif // XINERAMA
205 */
206
207 /* these values represent offsets from the screen edge
208 * we look for the biggest offset on each edge and then apply them
209 * all at once
210 * do not be confused by the similarity to the names of Rect's members
211 */
212 unsigned int current_left = 0, current_right = 0, current_top = 0,
213 current_bottom = 0;
214
215 StrutList::const_iterator it = _struts.begin(), end = _struts.end();
216
217 for(; it != end; ++it) {
218 otk::Strut *strut = *it;
219 if (strut->left > current_left)
220 current_left = strut->left;
221 if (strut->top > current_top)
222 current_top = strut->top;
223 if (strut->right > current_right)
224 current_right = strut->right;
225 if (strut->bottom > current_bottom)
226 current_bottom = strut->bottom;
227 }
228
229 _area.setRect(current_left, current_top,
230 _info->width() - (current_left + current_right),
231 _info->height() - (current_top + current_bottom));
232
233 /*
234 #ifdef XINERAMA
235 if (isXineramaActive()) {
236 // keep each of the ximerama-defined areas inside the strut
237 RectList::iterator xit, xend = xineramaUsableArea.end();
238 for (xit = xineramaUsableArea.begin(); xit != xend; ++xit) {
239 if (xit->x() < usableArea.x()) {
240 xit->setX(usableArea.x());
241 xit->setWidth(xit->width() - usableArea.x());
242 }
243 if (xit->y() < usableArea.y()) {
244 xit->setY(usableArea.y());
245 xit->setHeight(xit->height() - usableArea.y());
246 }
247 if (xit->x() + xit->width() > usableArea.width())
248 xit->setWidth(usableArea.width() - xit->x());
249 if (xit->y() + xit->height() > usableArea.height())
250 xit->setHeight(usableArea.height() - xit->y());
251 }
252 }
253 #endif // XINERAMA
254 */
255
256 if (old_area != _area)
257 // XXX: re-maximize windows
258
259 setWorkArea();
260 }
261
262
263 void OBScreen::setClientList()
264 {
265 Window *windows;
266
267 // create an array of the window ids
268 if (clients.size() > 0) {
269 Window *win_it;
270
271 windows = new Window[clients.size()];
272 win_it = windows;
273 ClientList::const_iterator it = clients.begin();
274 const ClientList::const_iterator end = clients.end();
275 for (; it != end; ++it, ++win_it)
276 *win_it = (*it)->window();
277 } else
278 windows = (Window*) 0;
279
280 Openbox::instance->property()->set(_info->rootWindow(),
281 otk::OBProperty::net_client_list,
282 otk::OBProperty::Atom_Window,
283 windows, clients.size());
284
285 if (clients.size())
286 delete [] windows;
287
288 setStackingList();
289 }
290
291
292 void OBScreen::setStackingList()
293 {
294 // The below comment is wrong now hopefully :> but ill keep it here for
295 // reference anyways
296 /*
297 Get the stacking order from all of the workspaces.
298 We start with the current workspace so that the sticky windows will be
299 in the right order on the current workspace.
300 */
301 /*
302 Openbox::instance->property()->set(_info->getRootWindow(),
303 otk::OBProperty::net_client_list_stacking,
304 otk::OBProperty::Atom_Window,
305 _stacking, _stacking.size());
306 */
307 }
308
309
310 void OBScreen::setWorkArea() {
311 unsigned long area[] = { _area.x(), _area.y(),
312 _area.width(), _area.height() };
313 Openbox::instance->property()->set(_info->rootWindow(),
314 otk::OBProperty::net_workarea,
315 otk::OBProperty::Atom_Cardinal,
316 area, 4);
317 /*
318 if (workspacesList.size() > 0) {
319 unsigned long *dims = new unsigned long[4 * workspacesList.size()];
320 for (unsigned int i = 0, m = workspacesList.size(); i < m; ++i) {
321 // XXX: this could be different for each workspace
322 const otk::Rect &area = availableArea();
323 dims[(i * 4) + 0] = area.x();
324 dims[(i * 4) + 1] = area.y();
325 dims[(i * 4) + 2] = area.width();
326 dims[(i * 4) + 3] = area.height();
327 }
328 xatom->set(getRootWindow(), otk::OBProperty::net_workarea,
329 otk::OBProperty::Atom_Cardinal,
330 dims, 4 * workspacesList.size());
331 delete [] dims;
332 } else
333 xatom->set(getRootWindow(), otk::OBProperty::net_workarea,
334 otk::OBProperty::Atom_Cardinal, 0, 0);
335 */
336 }
337
338
339 void OBScreen::manageWindow(Window window)
340 {
341 OBClient *client = 0;
342 XWMHints *wmhint;
343 XSetWindowAttributes attrib_set;
344
345 // is the window a docking app
346 if ((wmhint = XGetWMHints(otk::OBDisplay::display, window))) {
347 if ((wmhint->flags & StateHint) &&
348 wmhint->initial_state == WithdrawnState) {
349 //slit->addClient(w); // XXX: make dock apps work!
350 XFree(wmhint);
351 return;
352 }
353 XFree(wmhint);
354 }
355
356 otk::OBDisplay::grab();
357
358 // choose the events we want to receive on the CLIENT window
359 attrib_set.event_mask = OBClient::event_mask;
360 attrib_set.do_not_propagate_mask = OBClient::no_propagate_mask;
361 XChangeWindowAttributes(otk::OBDisplay::display, window,
362 CWEventMask|CWDontPropagate, &attrib_set);
363
364 // create the OBClient class, which gets all of the hints on the window
365 client = new OBClient(_number, window);
366 // register for events
367 Openbox::instance->registerHandler(window, client);
368 // add to the wm's map
369 Openbox::instance->addClient(window, client);
370
371 // we dont want a border on the client
372 client->toggleClientBorder(false);
373
374 // specify that if we exit, the window should not be destroyed and should be
375 // reparented back to root automatically
376 XChangeSaveSet(otk::OBDisplay::display, window, SetModeInsert);
377
378 if (!client->positionRequested()) {
379 // XXX: position the window intelligenty
380 }
381
382 // create the decoration frame for the client window
383 client->frame = new OBFrame(client, &_style);
384
385 // add to the wm's map
386 Openbox::instance->addClient(client->frame->window(), client);
387 Openbox::instance->addClient(client->frame->plate(), client);
388 Openbox::instance->addClient(client->frame->titlebar(), client);
389 Openbox::instance->addClient(client->frame->label(), client);
390 Openbox::instance->addClient(client->frame->button_max(), client);
391 Openbox::instance->addClient(client->frame->button_iconify(), client);
392 Openbox::instance->addClient(client->frame->button_stick(), client);
393 Openbox::instance->addClient(client->frame->button_close(), client);
394 Openbox::instance->addClient(client->frame->handle(), client);
395 Openbox::instance->addClient(client->frame->grip_left(), client);
396 Openbox::instance->addClient(client->frame->grip_right(), client);
397
398 // XXX: if on the current desktop..
399 client->frame->show();
400
401 // XXX: handle any requested states such as shaded/maximized
402
403 otk::OBDisplay::ungrab();
404
405 // add to the screen's list
406 clients.push_back(client);
407 // this puts into the stacking order, then raises it
408 _stacking.push_back(client);
409 raise(client);
410 // update the root properties
411 setClientList();
412
413 Openbox::instance->bindings()->grabButtons(true, client);
414 }
415
416
417 void OBScreen::unmanageWindow(OBClient *client)
418 {
419 OBFrame *frame = client->frame;
420
421 Openbox::instance->bindings()->grabButtons(false, client);
422
423 // XXX: pass around focus if this window was focused
424
425 // remove from the wm's map
426 Openbox::instance->removeClient(client->window());
427 Openbox::instance->removeClient(frame->window());
428 Openbox::instance->removeClient(frame->plate());
429 Openbox::instance->removeClient(frame->titlebar());
430 Openbox::instance->removeClient(frame->label());
431 Openbox::instance->removeClient(frame->button_max());
432 Openbox::instance->removeClient(frame->button_iconify());
433 Openbox::instance->removeClient(frame->button_stick());
434 Openbox::instance->removeClient(frame->button_close());
435 Openbox::instance->removeClient(frame->handle());
436 Openbox::instance->removeClient(frame->grip_left());
437 Openbox::instance->removeClient(frame->grip_right());
438 // unregister for handling events
439 Openbox::instance->clearHandler(client->window());
440
441 // remove the window from our save set
442 XChangeSaveSet(otk::OBDisplay::display, client->window(), SetModeDelete);
443
444 // we dont want events no more
445 XSelectInput(otk::OBDisplay::display, client->window(), NoEventMask);
446
447 frame->hide();
448
449 // give the client its border back
450 client->toggleClientBorder(true);
451
452 delete client->frame;
453 client->frame = 0;
454
455 // remove from the screen's lists
456 _stacking.remove(client);
457 clients.remove(client);
458 delete client;
459
460 // update the root properties
461 setClientList();
462 }
463
464 void OBScreen::raise(OBClient *client)
465 {
466 const int layer = client->layer();
467 std::vector<Window> wins;
468
469 _stacking.remove(client);
470
471 // the stacking list is from highest to lowest
472
473 ClientList::iterator it = _stacking.begin(), end = _stacking.end();
474 // insert the windows above this window
475 for (; it != end; ++it) {
476 if ((*it)->layer() <= layer)
477 break;
478 wins.push_back((*it)->frame->window());
479 }
480 // insert our client
481 wins.push_back(client->frame->window());
482 _stacking.insert(it, client);
483 // insert the remaining below this window
484 for (; it != end; ++it)
485 wins.push_back((*it)->frame->window());
486
487 XRestackWindows(otk::OBDisplay::display, &wins[0], wins.size());
488 }
489
490 void OBScreen::lower(OBClient *client)
491 {
492 const int layer = client->layer();
493 std::vector<Window> wins;
494
495 _stacking.remove(client);
496
497 // the stacking list is from highest to lowest
498
499 ClientList::iterator it = _stacking.begin(), end = _stacking.end();
500 // insert the windows above this window
501 for (; it != end; ++it) {
502 if ((*it)->layer() < layer)
503 break;
504 wins.push_back((*it)->frame->window());
505 }
506 // insert our client
507 wins.push_back(client->frame->window());
508 _stacking.insert(it, client);
509 // insert the remaining below this window
510 for (; it != end; ++it)
511 wins.push_back((*it)->frame->window());
512
513 XRestackWindows(otk::OBDisplay::display, &wins[0], wins.size());
514 }
515
516 }
This page took 0.05666 seconds and 5 git commands to generate.