old bb shitz

This commit is contained in:
Dana Jansens 2003-01-11 19:19:14 +00:00
parent 8f8acc2493
commit 23c11a151a
2 changed files with 0 additions and 877 deletions

View file

@ -1,778 +0,0 @@
// -*- mode: C++; indent-tabs-mode: nil; c-basic-offset: 2; -*-
#ifdef HAVE_CONFIG_H
# include "../config.h"
#endif // HAVE_CONFIG_H
extern "C" {
#include <X11/Xlib.h>
#include <X11/Xatom.h>
#ifdef HAVE_STDIO_H
# include <stdio.h>
#endif // HAVE_STDIO_H
#ifdef HAVE_STRING_H
# include <string.h>
#endif // HAVE_STRING_H
}
#include <assert.h>
#include <functional>
#include <string>
using std::string;
#include "blackbox.hh"
#include "otk/font.hh"
#include "otk/display.hh"
#include "bbscreen.hh"
#include "otk/util.hh"
#include "bbwindow.hh"
#include "workspace.hh"
namespace ob {
Workspace::Workspace(BScreen *scrn, unsigned int i) {
screen = scrn;
xatom = screen->getBlackbox()->getXAtom();
cascade_x = cascade_y = 0;
#ifdef XINERAMA
cascade_region = 0;
#endif // XINERAMA
id = i;
lastfocus = (BlackboxWindow *) 0;
readName();
}
void Workspace::addWindow(BlackboxWindow *w, bool place, bool sticky) {
assert(w != 0);
if (place) placeWindow(w);
stackingList.push_front(w);
if (! sticky)
w->setWorkspace(id);
if (! w->isNormal()) {
if (! sticky) {
// just give it some number, else bad things happen as it is assumed to
// not be on a workspace
w->setWindowNumber(0);
}
} else {
if (! sticky)
w->setWindowNumber(windowList.size());
windowList.push_back(w);
if (screen->doFocusNew() || (w->isTransient() && w->getTransientFor() &&
w->getTransientFor()->isFocused())) {
if (id != screen->getCurrentWorkspaceID()) {
/*
not on the focused workspace, so the window is not going to get focus
but if the user wants new windows focused, then it should get focus
when this workspace does become focused.
*/
lastfocus = w;
}
}
}
if (! w->isDesktop())
raiseWindow(w);
else
lowerWindow(w);
}
void Workspace::removeWindow(BlackboxWindow *w, bool sticky) {
assert(w != 0);
stackingList.remove(w);
// pass focus to the next appropriate window
if ((w->isFocused() || w == lastfocus) &&
screen->getBlackbox()->state() != Openbox::State_Exiting) {
focusFallback(w);
}
if (! w->isNormal()) return;
BlackboxWindowList::iterator it, end = windowList.end();
int i;
for (i = 0, it = windowList.begin(); it != end; ++it, ++i)
if (*it == w)
break;
assert(it != end);
windowList.erase(it);
if (! sticky) {
BlackboxWindowList::iterator it = windowList.begin();
const BlackboxWindowList::iterator end = windowList.end();
unsigned int i = 0;
for (; it != end; ++it, ++i)
(*it)->setWindowNumber(i);
}
if (i == 0) {
cascade_x = cascade_y = 0;
#ifdef XINERAMA
cascade_region = 0;
#endif // XINERAMA
}
}
void Workspace::focusFallback(const BlackboxWindow *old_window) {
BlackboxWindow *newfocus = 0;
if (id == screen->getCurrentWorkspaceID()) {
// The window is on the visible workspace.
// if it's a transient, then try to focus its parent
if (old_window && old_window->isTransient()) {
newfocus = old_window->getTransientFor();
if (! newfocus ||
newfocus->isIconic() || // do not focus icons
newfocus->getWorkspaceNumber() != id || // or other workspaces
! newfocus->setInputFocus())
newfocus = 0;
}
if (! newfocus) {
BlackboxWindowList::iterator it = stackingList.begin(),
end = stackingList.end();
for (; it != end; ++it) {
BlackboxWindow *tmp = *it;
if (tmp && tmp->isNormal() && tmp->setInputFocus()) {
// we found our new focus target
newfocus = tmp;
break;
}
}
}
screen->getBlackbox()->setFocusedWindow(newfocus);
} else {
// The window is not on the visible workspace.
if (old_window && lastfocus == old_window) {
// The window was the last-focus target, so we need to replace it.
BlackboxWindow *win = (BlackboxWindow*) 0;
if (! stackingList.empty())
win = stackingList.front();
setLastFocusedWindow(win);
}
}
}
void Workspace::removeAll(void) {
while (! windowList.empty())
windowList.front()->iconify();
}
void Workspace::showAll(void) {
BlackboxWindowList::iterator it = stackingList.begin();
const BlackboxWindowList::iterator end = stackingList.end();
for (; it != end; ++it) {
BlackboxWindow *bw = *it;
// sticky windows arent unmapped on a workspace change so we don't have ot
// map them, but sometimes on a restart, another app can unmap our sticky
// windows, so we map on startup always
if (! bw->isStuck() ||
screen->getBlackbox()->state() == Openbox::State_Starting)
bw->show();
}
}
void Workspace::hideAll(void) {
// withdraw in reverse order to minimize the number of Expose events
BlackboxWindowList lst(stackingList.rbegin(), stackingList.rend());
BlackboxWindowList::iterator it = lst.begin();
const BlackboxWindowList::iterator end = lst.end();
for (; it != end; ++it) {
BlackboxWindow *bw = *it;
// don't hide sticky windows, or they'll end up flickering on a workspace
// change
if (! bw->isStuck())
bw->withdraw();
}
}
/*
* returns the number of transients for win, plus the number of transients
* associated with each transient of win
*/
static unsigned int countTransients(const BlackboxWindow * const win) {
BlackboxWindowList transients = win->getTransients();
if (transients.empty()) return 0;
unsigned int ret = transients.size();
BlackboxWindowList::const_iterator it = transients.begin(),
end = transients.end();
for (; it != end; ++it)
ret += countTransients(*it);
return ret;
}
/*
* puts the transients of win into the stack. windows are stacked above
* the window before it in the stackvector being iterated, meaning
* stack[0] is on bottom, stack[1] is above stack[0], stack[2] is above
* stack[1], etc...
*/
void Workspace::raiseTransients(const BlackboxWindow * const win,
StackVector::iterator &stack) {
if (win->getTransients().empty()) return; // nothing to do
// put win's transients in the stack
BlackboxWindowList::const_iterator it, end = win->getTransients().end();
for (it = win->getTransients().begin(); it != end; ++it) {
BlackboxWindow *w = *it;
*stack++ = w->getFrameWindow();
if (! w->isIconic()) {
Workspace *wkspc = screen->getWorkspace(w->getWorkspaceNumber());
wkspc->stackingList.remove(w);
wkspc->stackingList.push_front(w);
}
}
// put transients of win's transients in the stack
for (it = win->getTransients().begin(); it != end; ++it)
raiseTransients(*it, stack);
}
void Workspace::lowerTransients(const BlackboxWindow * const win,
StackVector::iterator &stack) {
if (win->getTransients().empty()) return; // nothing to do
// put transients of win's transients in the stack
BlackboxWindowList::const_reverse_iterator it,
end = win->getTransients().rend();
for (it = win->getTransients().rbegin(); it != end; ++it)
lowerTransients(*it, stack);
// put win's transients in the stack
for (it = win->getTransients().rbegin(); it != end; ++it) {
BlackboxWindow *w = *it;
*stack++ = w->getFrameWindow();
if (! w->isIconic()) {
Workspace *wkspc = screen->getWorkspace(w->getWorkspaceNumber());
wkspc->stackingList.remove(w);
wkspc->stackingList.push_back(w);
}
}
}
void Workspace::raiseWindow(BlackboxWindow *w) {
BlackboxWindow *win = w;
if (win->isDesktop()) return;
// walk up the transient_for's to the window that is not a transient
while (win->isTransient() && win->getTransientFor())
win = win->getTransientFor();
// get the total window count (win and all transients)
unsigned int i = 1 + countTransients(win);
// stack the window with all transients above
StackVector stack_vector(i);
StackVector::iterator stack = stack_vector.begin();
*(stack++) = win->getFrameWindow();
if (! (win->isIconic() || win->isDesktop())) {
Workspace *wkspc = screen->getWorkspace(win->getWorkspaceNumber());
wkspc->stackingList.remove(win);
wkspc->stackingList.push_front(win);
}
raiseTransients(win, stack);
screen->raiseWindows(&stack_vector[0], stack_vector.size());
}
void Workspace::lowerWindow(BlackboxWindow *w) {
BlackboxWindow *win = w;
// walk up the transient_for's to the window that is not a transient
while (win->isTransient() && win->getTransientFor())
win = win->getTransientFor();
// get the total window count (win and all transients)
unsigned int i = 1 + countTransients(win);
// stack the window with all transients above
StackVector stack_vector(i);
StackVector::iterator stack = stack_vector.begin();
lowerTransients(win, stack);
*(stack++) = win->getFrameWindow();
if (! (win->isIconic() || win->isDesktop())) {
Workspace *wkspc = screen->getWorkspace(win->getWorkspaceNumber());
wkspc->stackingList.remove(win);
wkspc->stackingList.push_back(win);
}
screen->lowerWindows(&stack_vector[0], stack_vector.size());
}
void Workspace::reconfigure(void) {
std::for_each(windowList.begin(), windowList.end(),
std::mem_fun(&BlackboxWindow::reconfigure));
}
BlackboxWindow *Workspace::getWindow(unsigned int index) {
if (index < windowList.size()) {
BlackboxWindowList::iterator it = windowList.begin();
while (index-- > 0) // increment to index
++it;
return *it;
}
return 0;
}
BlackboxWindow*
Workspace::getNextWindowInList(BlackboxWindow *w) {
BlackboxWindowList::iterator it = std::find(windowList.begin(),
windowList.end(),
w);
assert(it != windowList.end()); // window must be in list
++it; // next window
if (it == windowList.end())
return windowList.front(); // if we walked off the end, wrap around
return *it;
}
BlackboxWindow* Workspace::getPrevWindowInList(BlackboxWindow *w) {
BlackboxWindowList::iterator it = std::find(windowList.begin(),
windowList.end(),
w);
assert(it != windowList.end()); // window must be in list
if (it == windowList.begin())
return windowList.back(); // if we walked of the front, wrap around
return *(--it);
}
BlackboxWindow* Workspace::getTopWindowOnStack(void) const {
assert(! stackingList.empty());
return stackingList.front();
}
unsigned int Workspace::getCount(void) const {
return windowList.size();
}
void Workspace::appendStackOrder(BlackboxWindowList &stack_order) const {
BlackboxWindowList::const_reverse_iterator it = stackingList.rbegin();
const BlackboxWindowList::const_reverse_iterator end = stackingList.rend();
for (; it != end; ++it)
// don't add desktop wnidows, or sticky windows more than once
if (! ( (*it)->isDesktop() ||
((*it)->isStuck() && id != screen->getCurrentWorkspaceID())))
stack_order.push_back(*it);
}
bool Workspace::isCurrent(void) const {
return (id == screen->getCurrentWorkspaceID());
}
bool Workspace::isLastWindow(const BlackboxWindow *w) const {
return (w == windowList.back());
}
void Workspace::setCurrent(void) {
screen->changeWorkspaceID(id);
}
void Workspace::readName(void) {
otk::OBProperty::StringVect namesList;
unsigned long numnames = id + 1;
// attempt to get from the _NET_WM_DESKTOP_NAMES property
if (xatom->get(screen->getRootWindow(), otk::OBProperty::net_desktop_names,
otk::OBProperty::utf8, &numnames, &namesList) &&
namesList.size() > id) {
name = namesList[id];
} else {
/*
Use a default name. This doesn't actually change the class. That will
happen after the setName changes the root property, and that change
makes its way back to this function.
*/
string tmp = "Workspace %d";
assert(tmp.length() < 32);
char default_name[32];
sprintf(default_name, tmp.c_str(), id + 1);
setName(default_name); // save this into the _NET_WM_DESKTOP_NAMES property
}
}
void Workspace::setName(const string& new_name) {
// set the _NET_WM_DESKTOP_NAMES property with the new name
otk::OBProperty::StringVect namesList;
unsigned long numnames = (unsigned) -1;
if (xatom->get(screen->getRootWindow(),
otk::OBProperty::net_desktop_names,
otk::OBProperty::utf8, &numnames, &namesList) &&
namesList.size() > id)
namesList[id] = new_name;
else
namesList.push_back(new_name);
xatom->set(screen->getRootWindow(), otk::OBProperty::net_desktop_names,
otk::OBProperty::utf8, namesList);
}
/*
* Calculate free space available for window placement.
*/
Workspace::rectList Workspace::calcSpace(const otk::Rect &win,
const rectList &spaces) const {
otk::Rect isect, extra;
rectList result;
rectList::const_iterator siter, end = spaces.end();
for (siter = spaces.begin(); siter != end; ++siter) {
const otk::Rect &curr = *siter;
if(! win.intersects(curr)) {
result.push_back(curr);
continue;
}
/* Use an intersection of win and curr to determine the space around
* curr that we can use.
*
* NOTE: the spaces calculated can overlap.
*/
isect = curr & win;
// left
extra.setCoords(curr.left(), curr.top(),
isect.left() - screen->getSnapOffset(), curr.bottom());
if (extra.valid()) result.push_back(extra);
// top
extra.setCoords(curr.left(), curr.top(),
curr.right(), isect.top() - screen->getSnapOffset());
if (extra.valid()) result.push_back(extra);
// right
extra.setCoords(isect.right() + screen->getSnapOffset(), curr.top(),
curr.right(), curr.bottom());
if (extra.valid()) result.push_back(extra);
// bottom
extra.setCoords(curr.left(), isect.bottom() + screen->getSnapOffset(),
curr.right(), curr.bottom());
if (extra.valid()) result.push_back(extra);
}
return result;
}
static bool rowRLBT(const otk::Rect &first, const otk::Rect &second) {
if (first.bottom() == second.bottom())
return first.right() > second.right();
return first.bottom() > second.bottom();
}
static bool rowRLTB(const otk::Rect &first, const otk::Rect &second) {
if (first.y() == second.y())
return first.right() > second.right();
return first.y() < second.y();
}
static bool rowLRBT(const otk::Rect &first, const otk::Rect &second) {
if (first.bottom() == second.bottom())
return first.x() < second.x();
return first.bottom() > second.bottom();
}
static bool rowLRTB(const otk::Rect &first, const otk::Rect &second) {
if (first.y() == second.y())
return first.x() < second.x();
return first.y() < second.y();
}
static bool colLRTB(const otk::Rect &first, const otk::Rect &second) {
if (first.x() == second.x())
return first.y() < second.y();
return first.x() < second.x();
}
static bool colLRBT(const otk::Rect &first, const otk::Rect &second) {
if (first.x() == second.x())
return first.bottom() > second.bottom();
return first.x() < second.x();
}
static bool colRLTB(const otk::Rect &first, const otk::Rect &second) {
if (first.right() == second.right())
return first.y() < second.y();
return first.right() > second.right();
}
static bool colRLBT(const otk::Rect &first, const otk::Rect &second) {
if (first.right() == second.right())
return first.bottom() > second.bottom();
return first.right() > second.right();
}
bool Workspace::smartPlacement(otk::Rect& win) {
rectList spaces;
//initially the entire screen is free
#ifdef XINERAMA
if (screen->isXineramaActive() &&
screen->getBlackbox()->doXineramaPlacement()) {
RectList availableAreas = screen->allAvailableAreas();
RectList::iterator it, end = availableAreas.end();
for (it = availableAreas.begin(); it != end; ++it) {
Rect r = *it;
r.setRect(r.x() + screen->getSnapOffset(),
r.y() + screen->getSnapOffset(),
r.width() - screen->getSnapOffset(),
r.height() - screen->getSnapOffset());
spaces.push_back(*it);
}
} else
#endif // XINERAMA
{
otk::Rect r = screen->availableArea();
r.setRect(r.x() + screen->getSnapOffset(),
r.y() + screen->getSnapOffset(),
r.width() - screen->getSnapOffset(),
r.height() - screen->getSnapOffset());
spaces.push_back(r);
}
//Find Free Spaces
BlackboxWindowList::const_iterator wit = windowList.begin(),
end = windowList.end();
otk::Rect tmp;
for (; wit != end; ++wit) {
const BlackboxWindow* const curr = *wit;
// watch for shaded windows and full-maxed windows
if (curr->isShaded()) {
if (screen->getPlaceIgnoreShaded()) continue;
} else if (curr->isMaximizedFull()) {
if (screen->getPlaceIgnoreMaximized()) continue;
}
tmp.setRect(curr->frameRect().x(), curr->frameRect().y(),
curr->frameRect().width() + screen->getWindowStyle()->getBorderWidth(),
curr->frameRect().height() + screen->getWindowStyle()->getBorderWidth());
spaces = calcSpace(tmp, spaces);
}
if (screen->getPlacementPolicy() == BScreen::RowSmartPlacement) {
if(screen->getRowPlacementDirection() == BScreen::LeftRight) {
if(screen->getColPlacementDirection() == BScreen::TopBottom)
std::sort(spaces.begin(), spaces.end(), rowLRTB);
else
std::sort(spaces.begin(), spaces.end(), rowLRBT);
} else {
if(screen->getColPlacementDirection() == BScreen::TopBottom)
std::sort(spaces.begin(), spaces.end(), rowRLTB);
else
std::sort(spaces.begin(), spaces.end(), rowRLBT);
}
} else {
if(screen->getColPlacementDirection() == BScreen::TopBottom) {
if(screen->getRowPlacementDirection() == BScreen::LeftRight)
std::sort(spaces.begin(), spaces.end(), colLRTB);
else
std::sort(spaces.begin(), spaces.end(), colRLTB);
} else {
if(screen->getRowPlacementDirection() == BScreen::LeftRight)
std::sort(spaces.begin(), spaces.end(), colLRBT);
else
std::sort(spaces.begin(), spaces.end(), colRLBT);
}
}
rectList::const_iterator sit = spaces.begin(), spaces_end = spaces.end();
for(; sit != spaces_end; ++sit) {
if (sit->width() >= win.width() && sit->height() >= win.height())
break;
}
if (sit == spaces_end)
return False;
//set new position based on the empty space found
const otk::Rect& where = *sit;
win.setX(where.x());
win.setY(where.y());
// adjust the location() based on left/right and top/bottom placement
if (screen->getPlacementPolicy() == BScreen::RowSmartPlacement) {
if (screen->getRowPlacementDirection() == BScreen::RightLeft)
win.setX(where.right() - win.width());
if (screen->getColPlacementDirection() == BScreen::BottomTop)
win.setY(where.bottom() - win.height());
} else {
if (screen->getColPlacementDirection() == BScreen::BottomTop)
win.setY(win.y() + where.height() - win.height());
if (screen->getRowPlacementDirection() == BScreen::RightLeft)
win.setX(win.x() + where.width() - win.width());
}
return True;
}
bool Workspace::underMousePlacement(otk::Rect &win) {
int x, y, rx, ry;
Window c, r;
unsigned int m;
XQueryPointer(otk::OBDisplay::display, screen->getRootWindow(),
&r, &c, &rx, &ry, &x, &y, &m);
otk::Rect area;
#ifdef XINERAMA
if (screen->isXineramaActive() &&
screen->getBlackbox()->doXineramaPlacement()) {
RectList availableAreas = screen->allAvailableAreas();
RectList::iterator it, end = availableAreas.end();
for (it = availableAreas.begin(); it != end; ++it)
if (it->contains(rx, ry)) break;
assert(it != end); // the mouse isn't inside an area?
area = *it;
} else
#endif // XINERAMA
area = screen->availableArea();
x = rx - win.width() / 2;
y = ry - win.height() / 2;
if (x < area.x())
x = area.x();
if (y < area.y())
y = area.y();
if (x + win.width() > area.x() + area.width())
x = area.x() + area.width() - win.width();
if (y + win.height() > area.y() + area.height())
y = area.y() + area.height() - win.height();
win.setX(x);
win.setY(y);
return True;
}
bool Workspace::cascadePlacement(otk::Rect &win, const int offset) {
otk::Rect area;
#ifdef XINERAMA
if (screen->isXineramaActive() &&
screen->getBlackbox()->doXineramaPlacement()) {
area = screen->allAvailableAreas()[cascade_region];
} else
#endif // XINERAMA
area = screen->availableArea();
if ((static_cast<signed>(cascade_x + win.width()) > area.right() + 1) ||
(static_cast<signed>(cascade_y + win.height()) > area.bottom() + 1)) {
cascade_x = cascade_y = 0;
#ifdef XINERAMA
if (screen->isXineramaActive() &&
screen->getBlackbox()->doXineramaPlacement()) {
// go to the next xinerama region, and use its area
if (++cascade_region >= screen->allAvailableAreas().size())
cascade_region = 0;
area = screen->allAvailableAreas()[cascade_region];
}
#endif // XINERAMA
}
if (cascade_x == 0) {
cascade_x = area.x() + offset;
cascade_y = area.y() + offset;
}
win.setPos(cascade_x, cascade_y);
cascade_x += offset;
cascade_y += offset;
return True;
}
void Workspace::placeWindow(BlackboxWindow *win) {
otk::Rect new_win(0, 0, win->frameRect().width(), win->frameRect().height());
bool placed = False;
switch (screen->getPlacementPolicy()) {
case BScreen::RowSmartPlacement:
case BScreen::ColSmartPlacement:
placed = smartPlacement(new_win);
break;
case BScreen::UnderMousePlacement:
case BScreen::ClickMousePlacement:
placed = underMousePlacement(new_win);
default:
break; // handled below
} // switch
if (placed == False)
cascadePlacement(new_win, (win->getTitleHeight() +
screen->getWindowStyle()->getBorderWidth() * 2));
if (new_win.right() > screen->availableArea().right())
new_win.setX(screen->availableArea().left());
if (new_win.bottom() > screen->availableArea().bottom())
new_win.setY(screen->availableArea().top());
win->configure(new_win.x(), new_win.y(), new_win.width(), new_win.height());
}
}

View file

@ -1,99 +0,0 @@
// -*- mode: C++; indent-tabs-mode: nil; c-basic-offset: 2; -*-
#ifndef __Workspace_hh
#define __Workspace_hh
extern "C" {
#include <X11/Xlib.h>
}
#include <list>
#include <string>
#include <vector>
#include "otk/property.hh"
namespace ob {
class BScreen;
class Workspace;
class BlackboxWindow;
typedef std::list<BlackboxWindow*> BlackboxWindowList;
typedef std::vector<Window> StackVector;
class Workspace {
private:
BScreen *screen;
BlackboxWindow *lastfocus;
otk::OBProperty *xatom;
BlackboxWindowList stackingList, windowList;
std::string name;
unsigned int id;
unsigned int cascade_x, cascade_y;
#ifdef XINERAMA
unsigned int cascade_region;
#endif // XINERAMA
Workspace(const Workspace&);
Workspace& operator=(const Workspace&);
void raiseTransients(const BlackboxWindow * const win,
StackVector::iterator &stack);
void lowerTransients(const BlackboxWindow * const win,
StackVector::iterator &stack);
typedef std::vector<otk::Rect> rectList;
rectList calcSpace(const otk::Rect &win, const rectList &spaces) const;
void placeWindow(BlackboxWindow *win);
bool cascadePlacement(otk::Rect& win, const int offset);
bool smartPlacement(otk::Rect& win);
bool underMousePlacement(otk::Rect& win);
public:
Workspace(BScreen *scrn, unsigned int i = 0);
inline BScreen *getScreen(void) { return screen; }
inline BlackboxWindow *getLastFocusedWindow(void) { return lastfocus; }
inline const std::string& getName(void) const { return name; }
inline unsigned int getID(void) const { return id; }
inline void setLastFocusedWindow(BlackboxWindow *w) { lastfocus = w; }
inline const BlackboxWindowList& getStackingList() const
{ return stackingList; }
BlackboxWindow* getWindow(unsigned int index);
BlackboxWindow* getNextWindowInList(BlackboxWindow *w);
BlackboxWindow* getPrevWindowInList(BlackboxWindow *w);
BlackboxWindow* getTopWindowOnStack(void) const;
void focusFallback(const BlackboxWindow *old_window);
bool isCurrent(void) const;
bool isLastWindow(const BlackboxWindow* w) const;
void addWindow(BlackboxWindow *w, bool place = False, bool sticky = False);
void removeWindow(BlackboxWindow *w, bool sticky = False);
unsigned int getCount(void) const;
void appendStackOrder(BlackboxWindowList &stack_order) const;
void showAll(void);
void hideAll(void);
void removeAll(void);
void raiseWindow(BlackboxWindow *w);
void lowerWindow(BlackboxWindow *w);
void reconfigure(void);
void setCurrent(void);
void readName();
void setName(const std::string& new_name);
};
}
#endif // __Workspace_hh