From 9c6ce2a8001ee62982853cf7475feeb6145ecf95 Mon Sep 17 00:00:00 2001 From: Dana Jansens Date: Sun, 10 Nov 2002 12:50:18 +0000 Subject: [PATCH] adding the new OBScreen class actually! --- src/screen.cc | 303 ++++++++++++++++++++++++++++++++++++++++++++++++++ src/screen.hh | 115 +++++++++++++++++++ 2 files changed, 418 insertions(+) create mode 100644 src/screen.cc create mode 100644 src/screen.hh diff --git a/src/screen.cc b/src/screen.cc new file mode 100644 index 00000000..37a38715 --- /dev/null +++ b/src/screen.cc @@ -0,0 +1,303 @@ +// -*- mode: C++; indent-tabs-mode: nil; c-basic-offset: 2; -*- + +#ifdef HAVE_CONFIG_H +# include "../config.h" +#endif + +extern "C" { +#include "gettext.h" +#define _(str) gettext(str) +} + +#include "screen.hh" +#include "client.hh" +#include "openbox.hh" +#include "otk/display.hh" + +static bool running; +static int anotherWMRunning(Display *display, XErrorEvent *) { + printf(_("Another window manager already running on display %s.\n"), + DisplayString(display)); + running = true; + return -1; +} + + +namespace ob { + + +OBScreen::OBScreen(int screen) + : _number(screen) +{ + assert(screen >= 0); assert(screen < ScreenCount(otk::OBDisplay::display)); + _info = otk::OBDisplay::screenInfo(screen); + + ::running = false; + XErrorHandler old = XSetErrorHandler(::anotherWMRunning); + XSelectInput(otk::OBDisplay::display, _info->getRootWindow(), + OBScreen::event_mask); + XSync(otk::OBDisplay::display, false); + XSetErrorHandler(old); + + _managed = !::running; + if (! _managed) return; // was unable to manage the screen + + printf(_("Managing screen %d: visual 0x%lx, depth %d\n"), + _number, XVisualIDFromVisual(_info->getVisual()), _info->getDepth()); + +#ifdef HAVE_GETPID + Openbox::instance->property()->set(_info->getRootWindow(), + otk::OBProperty::openbox_pid, + otk::OBProperty::Atom_Cardinal, + (unsigned long) getpid()); +#endif // HAVE_GETPID + + // set the mouse cursor for the root window (the default cursor) + XDefineCursor(otk::OBDisplay::display, _info->getRootWindow(), + Openbox::instance->cursors().session); + + _image_control = new otk::BImageControl(Openbox::instance->timerManager(), + _info, true); + _image_control->installRootColormap(); + _root_cmap_installed = True; + + + // Set the netwm atoms for geomtery and viewport + unsigned long geometry[] = { _size.x(), + _size.y() }; + Openbox::instance->property()->set(_info->getRootWindow(), + otk::OBProperty::net_desktop_geometry, + otk::OBProperty::Atom_Cardinal, + geometry, 2); + unsigned long viewport[] = { 0, 0 }; + Openbox::instance->property()->set(_info->getRootWindow(), + otk::OBProperty::net_desktop_viewport, + otk::OBProperty::Atom_Cardinal, + viewport, 2); + + // these may be further updated if any pre-existing windows are found in + // the manageExising() function + setClientList(); // initialize the client lists, which will be empty + calcArea(); // initialize the available working area + + manageExisting(); + + // XXX: "change to" the first workspace to initialize stuff +} + + +OBScreen::~OBScreen() +{ + if (! _managed) return; + + delete _image_control; +} + + +void OBScreen::manageExisting() +{ + unsigned int i, j, nchild; + Window r, p, *children; + XQueryTree(otk::OBDisplay::display, _info->getRootWindow(), &r, &p, + &children, &nchild); + + // preen the window list of all icon windows... for better dockapp support + for (i = 0; i < nchild; i++) { + if (children[i] == None) continue; + + XWMHints *wmhints = XGetWMHints(otk::OBDisplay::display, + children[i]); + + if (wmhints) { + if ((wmhints->flags & IconWindowHint) && + (wmhints->icon_window != children[i])) { + for (j = 0; j < nchild; j++) { + if (children[j] == wmhints->icon_window) { + children[j] = None; + break; + } + } + } + + XFree(wmhints); + } + } + + // manage shown windows + for (i = 0; i < nchild; ++i) { + if (children[i] == None) + continue; + + XWindowAttributes attrib; + if (XGetWindowAttributes(otk::OBDisplay::display, children[i], &attrib)) { + if (attrib.override_redirect) continue; + + if (attrib.map_state != IsUnmapped) { + // XXX: manageWindow(children[i]); + } + } + } + + XFree(children); +} + + +//! Adds a window's strut to the screen's list of reserved spaces +void OBScreen::addStrut(otk::Strut *strut) +{ + _struts.push_back(strut); +} + + +//! Removes a window's strut from the screen's list of reserved spaces +void OBScreen::removeStrut(otk::Strut *strut) +{ + _struts.remove(strut); +} + + +void OBScreen::calcArea() +{ + otk::Rect old_area = _area; + +/* +#ifdef XINERAMA + // reset to the full areas + if (isXineramaActive()) + xineramaUsableArea = getXineramaAreas(); +#endif // XINERAMA +*/ + + /* these values represent offsets from the screen edge + * we look for the biggest offset on each edge and then apply them + * all at once + * do not be confused by the similarity to the names of Rect's members + */ + unsigned int current_left = 0, current_right = 0, current_top = 0, + current_bottom = 0; + + StrutList::const_iterator it = _struts.begin(), end = _struts.end(); + + for(; it != end; ++it) { + otk::Strut *strut = *it; + if (strut->left > current_left) + current_left = strut->left; + if (strut->top > current_top) + current_top = strut->top; + if (strut->right > current_right) + current_right = strut->right; + if (strut->bottom > current_bottom) + current_bottom = strut->bottom; + } + + _area.setRect(current_left, current_top, + _info->getWidth() - (current_left + current_right), + _info->getHeight() - (current_top + current_bottom)); + +/* +#ifdef XINERAMA + if (isXineramaActive()) { + // keep each of the ximerama-defined areas inside the strut + RectList::iterator xit, xend = xineramaUsableArea.end(); + for (xit = xineramaUsableArea.begin(); xit != xend; ++xit) { + if (xit->x() < usableArea.x()) { + xit->setX(usableArea.x()); + xit->setWidth(xit->width() - usableArea.x()); + } + if (xit->y() < usableArea.y()) { + xit->setY(usableArea.y()); + xit->setHeight(xit->height() - usableArea.y()); + } + if (xit->x() + xit->width() > usableArea.width()) + xit->setWidth(usableArea.width() - xit->x()); + if (xit->y() + xit->height() > usableArea.height()) + xit->setHeight(usableArea.height() - xit->y()); + } + } +#endif // XINERAMA +*/ + + if (old_area != _area) + // XXX: re-maximize windows + + setWorkArea(); +} + + +void OBScreen::setClientList() +{ + Window *windows; + + // create an array of the window ids + if (_clients.size() > 0) { + Window *win_it; + + windows = new Window[_clients.size()]; + win_it = windows; + ClientList::const_iterator it = _clients.begin(); + const ClientList::const_iterator end = _clients.end(); + for (; it != end; ++it, ++win_it) + *win_it = (*it)->window(); + } else + windows = (Window*) 0; + + Openbox::instance->property()->set(_info->getRootWindow(), + otk::OBProperty::net_client_list, + otk::OBProperty::Atom_Window, + windows, _clients.size()); + + if (_clients.size()) + delete [] windows; + + setStackingList(); +} + + +void OBScreen::setStackingList() +{ + // The below comment is wrong now hopefully :> but ill keep it here for + // reference anyways + /* + Get the stacking order from all of the workspaces. + We start with the current workspace so that the sticky windows will be + in the right order on the current workspace. + */ + /* + Openbox::instance->property()->set(_info->getRootWindow(), + otk::OBProperty::net_client_list_stacking, + otk::OBProperty::Atom_Window, + _stacking, _stacking.size()); + */ +} + + +void OBScreen::setWorkArea() { + unsigned long area[] = { _area.x(), _area.y(), + _area.width(), _area.height() }; + Openbox::instance->property()->set(_info->getRootWindow(), + otk::OBProperty::net_workarea, + otk::OBProperty::Atom_Cardinal, + area, 4); + /* + if (workspacesList.size() > 0) { + unsigned long *dims = new unsigned long[4 * workspacesList.size()]; + for (unsigned int i = 0, m = workspacesList.size(); i < m; ++i) { + // XXX: this could be different for each workspace + const otk::Rect &area = availableArea(); + dims[(i * 4) + 0] = area.x(); + dims[(i * 4) + 1] = area.y(); + dims[(i * 4) + 2] = area.width(); + dims[(i * 4) + 3] = area.height(); + } + xatom->set(getRootWindow(), otk::OBProperty::net_workarea, + otk::OBProperty::Atom_Cardinal, + dims, 4 * workspacesList.size()); + delete [] dims; + } else + xatom->set(getRootWindow(), otk::OBProperty::net_workarea, + otk::OBProperty::Atom_Cardinal, 0, 0); + */ +} + + +} diff --git a/src/screen.hh b/src/screen.hh new file mode 100644 index 00000000..6068e04b --- /dev/null +++ b/src/screen.hh @@ -0,0 +1,115 @@ +// -*- mode: C++; indent-tabs-mode: nil; c-basic-offset: 2; -*- +#ifndef __screen_hh +#define __screen_hh + +/*! @file screen.hh + @brief OBScreen manages a single screen +*/ + +extern "C" { +#include +} + +#include "otk/image.hh" +#include "otk/strut.hh" +#include "otk/rect.hh" +#include "otk/point.hh" + +#include + +namespace ob { + +class OBClient; + +//! Manages a single screen +/*! +*/ +class OBScreen { +public: + //! Holds a list of OBClient objects + typedef std::vector ClientList; + //! Holds a list of otk::Strut objects + typedef std::list StrutList; + + static const unsigned long event_mask = ColormapChangeMask | + EnterWindowMask | + LeaveWindowMask | + PropertyChangeMask | + SubstructureNotifyMask | + SubstructureRedirectMask | + ButtonPressMask | + ButtonReleaseMask; + +private: + //! Was %Openbox able to manage the screen? + bool _managed; + + //! The number of the screen on the X server + int _number; + + //! Information about this screen + const otk::ScreenInfo *_info; + + //! The Image Control used for rendering on the screen + otk::BImageControl *_image_control; + + //! Is the root colormap currently installed? + bool _root_cmap_installed; + + //! The dimentions of the screen + otk::Point _size; + + //! All managed clients on the screen + ClientList _clients; + + //! Area usable for placement etc (total - struts) + otk::Rect _area; + + //! Areas of the screen reserved by applications + StrutList _struts; + + + //! Manage any pre-existing windows on the screen + void manageExisting(); + //! Calculate the OBScreen::_area member + void calcArea(); + //! Set the client list on the root window + /*! + Sets the _NET_CLIENT_LIST root window property.
+ Also calls OBScreen::updateStackingList. + */ + void setClientList(); + //! Set the client stacking list on the root window + /*! + Set the _NET_CLIENT_LIST_STACKING root window property. + */ + void setStackingList(); + //! Set the work area hint on the root window + /*! + Set the _NET_WORKAREA root window property. + */ + void setWorkArea(); + +public: + //! Constructs a new OBScreen object + OBScreen(int screen); + //! Destroys the OBScreen object + virtual ~OBScreen(); + + //! Returns the Image Control used for rendering on the screen + inline otk::BImageControl *imageControl() { return _image_control; } + //! Returns the dimentions of the screen + inline const otk::Point &size() const { return _size; } + //! Returns the area of the screen not reserved by applications' Struts + inline const otk::Rect &area() const { return _area; } + + //! Adds a window's strut to the screen's list of reserved spaces + void addStrut(otk::Strut *strut); + //! Removes a window's strut from the screen's list of reserved spaces + void removeStrut(otk::Strut *strut); + +}; + +} + +#endif// __screen_hh -- 2.39.2