1 // -*- mode: C++; indent-tabs-mode: nil; c-basic-offset: 2; -*-
4 # include "../config.h"
10 #endif // HAVE_STDIO_H
13 # include <sys/types.h>
15 #endif // HAVE_UNISTD_H
18 #define _(str) gettext(str)
25 #include "bindings.hh"
26 #include "otk/display.hh"
29 static int anotherWMRunning(Display *display, XErrorEvent *) {
30 printf(_("Another window manager already running on display %s.\n"),
31 DisplayString(display));
40 OBScreen::OBScreen(int screen)
44 assert(screen >= 0); assert(screen < ScreenCount(otk::OBDisplay::display));
45 _info = otk::OBDisplay::screenInfo(screen);
48 XErrorHandler old = XSetErrorHandler(::anotherWMRunning);
49 XSelectInput(otk::OBDisplay::display, _info->rootWindow(),
50 OBScreen::event_mask);
51 XSync(otk::OBDisplay::display, false);
52 XSetErrorHandler(old);
54 _managed = !::running;
55 if (! _managed) return; // was unable to manage the screen
57 printf(_("Managing screen %d: visual 0x%lx, depth %d\n"),
58 _number, XVisualIDFromVisual(_info->visual()), _info->depth());
60 Openbox::instance->property()->set(_info->rootWindow(),
61 otk::OBProperty::openbox_pid,
62 otk::OBProperty::Atom_Cardinal,
63 (unsigned long) getpid());
65 // set the mouse cursor for the root window (the default cursor)
66 XDefineCursor(otk::OBDisplay::display, _info->rootWindow(),
67 Openbox::instance->cursors().session);
69 // initialize the shit that is used for all drawing on the screen
70 _image_control = new otk::BImageControl(Openbox::instance->timerManager(),
72 _image_control->installRootColormap();
73 _root_cmap_installed = True;
75 // initialize the screen's style
76 _style.setImageControl(_image_control);
77 std::string stylepath;
78 Openbox::instance->getConfigString("theme", &stylepath);
79 otk::Configuration sconfig(false);
80 sconfig.setFile(otk::expandTilde(stylepath));
81 if (!sconfig.load()) {
82 sconfig.setFile(otk::expandTilde(DEFAULTSTYLE));
83 if (!sconfig.load()) {
84 printf(_("Unable to load default style: %s. Aborting.\n"), DEFAULTSTYLE);
90 // Set the netwm atoms for geomtery and viewport
91 unsigned long geometry[] = { _info->width(),
93 Openbox::instance->property()->set(_info->rootWindow(),
94 otk::OBProperty::net_desktop_geometry,
95 otk::OBProperty::Atom_Cardinal,
97 unsigned long viewport[] = { 0, 0 };
98 Openbox::instance->property()->set(_info->rootWindow(),
99 otk::OBProperty::net_desktop_viewport,
100 otk::OBProperty::Atom_Cardinal,
103 // create the window which gets focus when no clients get it
104 XSetWindowAttributes attr;
105 attr.override_redirect = true;
106 _focuswindow = XCreateWindow(otk::OBDisplay::display, _info->rootWindow(),
107 -100, -100, 1, 1, 0, 0, InputOnly,
108 _info->visual(), CWOverrideRedirect, &attr);
109 XMapWindow(otk::OBDisplay::display, _focuswindow);
111 // these may be further updated if any pre-existing windows are found in
112 // the manageExising() function
113 setClientList(); // initialize the client lists, which will be empty
114 calcArea(); // initialize the available working area
118 OBScreen::~OBScreen()
120 if (! _managed) return;
122 // unmanage all windows
123 while (!clients.empty())
124 unmanageWindow(clients.front());
126 delete _image_control;
130 void OBScreen::manageExisting()
132 unsigned int i, j, nchild;
133 Window r, p, *children;
134 XQueryTree(otk::OBDisplay::display, _info->rootWindow(), &r, &p,
137 // preen the window list of all icon windows... for better dockapp support
138 for (i = 0; i < nchild; i++) {
139 if (children[i] == None) continue;
141 XWMHints *wmhints = XGetWMHints(otk::OBDisplay::display,
145 if ((wmhints->flags & IconWindowHint) &&
146 (wmhints->icon_window != children[i])) {
147 for (j = 0; j < nchild; j++) {
148 if (children[j] == wmhints->icon_window) {
159 // manage shown windows
160 for (i = 0; i < nchild; ++i) {
161 if (children[i] == None)
164 XWindowAttributes attrib;
165 if (XGetWindowAttributes(otk::OBDisplay::display, children[i], &attrib)) {
166 if (attrib.override_redirect) continue;
168 if (attrib.map_state != IsUnmapped) {
169 manageWindow(children[i]);
178 //! Adds a window's strut to the screen's list of reserved spaces
179 void OBScreen::addStrut(otk::Strut *strut)
181 _struts.push_back(strut);
185 //! Removes a window's strut from the screen's list of reserved spaces
186 void OBScreen::removeStrut(otk::Strut *strut)
188 _struts.remove(strut);
192 void OBScreen::calcArea()
194 otk::Rect old_area = _area;
198 // reset to the full areas
199 if (isXineramaActive())
200 xineramaUsableArea = getXineramaAreas();
204 /* these values represent offsets from the screen edge
205 * we look for the biggest offset on each edge and then apply them
207 * do not be confused by the similarity to the names of Rect's members
209 unsigned int current_left = 0, current_right = 0, current_top = 0,
212 StrutList::const_iterator it = _struts.begin(), end = _struts.end();
214 for(; it != end; ++it) {
215 otk::Strut *strut = *it;
216 if (strut->left > current_left)
217 current_left = strut->left;
218 if (strut->top > current_top)
219 current_top = strut->top;
220 if (strut->right > current_right)
221 current_right = strut->right;
222 if (strut->bottom > current_bottom)
223 current_bottom = strut->bottom;
226 _area.setRect(current_left, current_top,
227 _info->width() - (current_left + current_right),
228 _info->height() - (current_top + current_bottom));
232 if (isXineramaActive()) {
233 // keep each of the ximerama-defined areas inside the strut
234 RectList::iterator xit, xend = xineramaUsableArea.end();
235 for (xit = xineramaUsableArea.begin(); xit != xend; ++xit) {
236 if (xit->x() < usableArea.x()) {
237 xit->setX(usableArea.x());
238 xit->setWidth(xit->width() - usableArea.x());
240 if (xit->y() < usableArea.y()) {
241 xit->setY(usableArea.y());
242 xit->setHeight(xit->height() - usableArea.y());
244 if (xit->x() + xit->width() > usableArea.width())
245 xit->setWidth(usableArea.width() - xit->x());
246 if (xit->y() + xit->height() > usableArea.height())
247 xit->setHeight(usableArea.height() - xit->y());
253 if (old_area != _area)
254 // XXX: re-maximize windows
260 void OBScreen::setClientList()
264 // create an array of the window ids
265 if (clients.size() > 0) {
268 windows = new Window[clients.size()];
270 ClientList::const_iterator it = clients.begin();
271 const ClientList::const_iterator end = clients.end();
272 for (; it != end; ++it, ++win_it)
273 *win_it = (*it)->window();
275 windows = (Window*) 0;
277 Openbox::instance->property()->set(_info->rootWindow(),
278 otk::OBProperty::net_client_list,
279 otk::OBProperty::Atom_Window,
280 windows, clients.size());
289 void OBScreen::setStackingList()
291 // The below comment is wrong now hopefully :> but ill keep it here for
294 Get the stacking order from all of the workspaces.
295 We start with the current workspace so that the sticky windows will be
296 in the right order on the current workspace.
299 Openbox::instance->property()->set(_info->getRootWindow(),
300 otk::OBProperty::net_client_list_stacking,
301 otk::OBProperty::Atom_Window,
302 _stacking, _stacking.size());
307 void OBScreen::setWorkArea() {
308 unsigned long area[] = { _area.x(), _area.y(),
309 _area.width(), _area.height() };
310 Openbox::instance->property()->set(_info->rootWindow(),
311 otk::OBProperty::net_workarea,
312 otk::OBProperty::Atom_Cardinal,
315 if (workspacesList.size() > 0) {
316 unsigned long *dims = new unsigned long[4 * workspacesList.size()];
317 for (unsigned int i = 0, m = workspacesList.size(); i < m; ++i) {
318 // XXX: this could be different for each workspace
319 const otk::Rect &area = availableArea();
320 dims[(i * 4) + 0] = area.x();
321 dims[(i * 4) + 1] = area.y();
322 dims[(i * 4) + 2] = area.width();
323 dims[(i * 4) + 3] = area.height();
325 xatom->set(getRootWindow(), otk::OBProperty::net_workarea,
326 otk::OBProperty::Atom_Cardinal,
327 dims, 4 * workspacesList.size());
330 xatom->set(getRootWindow(), otk::OBProperty::net_workarea,
331 otk::OBProperty::Atom_Cardinal, 0, 0);
336 void OBScreen::manageWindow(Window window)
338 OBClient *client = 0;
340 XSetWindowAttributes attrib_set;
342 // is the window a docking app
343 if ((wmhint = XGetWMHints(otk::OBDisplay::display, window))) {
344 if ((wmhint->flags & StateHint) &&
345 wmhint->initial_state == WithdrawnState) {
346 //slit->addClient(w); // XXX: make dock apps work!
353 otk::OBDisplay::grab();
355 // choose the events we want to receive on the CLIENT window
356 attrib_set.event_mask = OBClient::event_mask;
357 attrib_set.do_not_propagate_mask = OBClient::no_propagate_mask;
358 XChangeWindowAttributes(otk::OBDisplay::display, window,
359 CWEventMask|CWDontPropagate, &attrib_set);
361 // create the OBClient class, which gets all of the hints on the window
362 client = new OBClient(_number, window);
363 // register for events
364 Openbox::instance->registerHandler(window, client);
365 // add to the wm's map
366 Openbox::instance->addClient(window, client);
368 // we dont want a border on the client
369 client->toggleClientBorder(false);
371 // specify that if we exit, the window should not be destroyed and should be
372 // reparented back to root automatically
373 XChangeSaveSet(otk::OBDisplay::display, window, SetModeInsert);
375 if (!client->positionRequested()) {
376 // XXX: position the window intelligenty
379 // create the decoration frame for the client window
380 client->frame = new OBFrame(client, &_style);
382 // add to the wm's map
383 Openbox::instance->addClient(client->frame->window(), client);
384 Openbox::instance->addClient(client->frame->plate(), client);
385 Openbox::instance->addClient(client->frame->titlebar(), client);
386 Openbox::instance->addClient(client->frame->label(), client);
387 Openbox::instance->addClient(client->frame->button_max(), client);
388 Openbox::instance->addClient(client->frame->button_iconify(), client);
389 Openbox::instance->addClient(client->frame->button_stick(), client);
390 Openbox::instance->addClient(client->frame->button_close(), client);
391 Openbox::instance->addClient(client->frame->handle(), client);
392 Openbox::instance->addClient(client->frame->grip_left(), client);
393 Openbox::instance->addClient(client->frame->grip_right(), client);
395 // XXX: if on the current desktop..
396 client->frame->show();
398 // XXX: handle any requested states such as shaded/maximized
400 otk::OBDisplay::ungrab();
402 // add to the screen's list
403 clients.push_back(client);
404 // update the root properties
409 void OBScreen::unmanageWindow(OBClient *client)
411 OBFrame *frame = client->frame;
413 // XXX: pass around focus if this window was focused
415 // remove from the wm's map
416 Openbox::instance->removeClient(client->window());
417 Openbox::instance->removeClient(frame->window());
418 Openbox::instance->removeClient(frame->plate());
419 Openbox::instance->removeClient(frame->titlebar());
420 Openbox::instance->removeClient(frame->label());
421 Openbox::instance->removeClient(frame->button_max());
422 Openbox::instance->removeClient(frame->button_iconify());
423 Openbox::instance->removeClient(frame->button_stick());
424 Openbox::instance->removeClient(frame->button_close());
425 Openbox::instance->removeClient(frame->handle());
426 Openbox::instance->removeClient(frame->grip_left());
427 Openbox::instance->removeClient(frame->grip_right());
428 // unregister for handling events
429 Openbox::instance->clearHandler(client->window());
431 // remove the window from our save set
432 XChangeSaveSet(otk::OBDisplay::display, client->window(), SetModeDelete);
434 // we dont want events no more
435 XSelectInput(otk::OBDisplay::display, client->window(), NoEventMask);
439 // give the client its border back
440 client->toggleClientBorder(true);
442 delete client->frame;
445 // remove from the screen's list
446 clients.remove(client);
449 // update the root properties