X-Git-Url: https://git.brokenzipper.com/gitweb?a=blobdiff_plain;f=src%2FWorkspace.cc;h=91bc141958865f3d706091bd1ee215c4db1840d1;hb=12fcb33bfaa03b3c6245d15bfb1809f7facc857f;hp=45dc2bc303c44a1f762680e835af5b711b907656;hpb=2809005ab0ab761a831f4353f2ff190a62d92794;p=chaz%2Fopenbox diff --git a/src/Workspace.cc b/src/Workspace.cc index 45dc2bc3..91bc1419 100644 --- a/src/Workspace.cc +++ b/src/Workspace.cc @@ -1,6 +1,6 @@ -// Workspace.cc for Openbox -// Copyright (c) 2002 - 2002 Ben Jansens (ben@orodu.net) -// Copyright (c) 2001 Sean 'Shaleh' Perry +// -*- mode: C++; indent-tabs-mode: nil; c-basic-offset: 2; -*- +// Workspace.cc for Blackbox - an X11 Window manager +// Copyright (c) 2001 - 2002 Sean 'Shaleh' Perry // Copyright (c) 1997 - 2000 Brad Hughes (bhughes@tcac.net) // // Permission is hereby granted, free of charge, to any person obtaining a @@ -21,642 +21,608 @@ // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER // DEALINGS IN THE SOFTWARE. -// stupid macros needed to access some functions in version 2 of the GNU C -// library -#ifndef _GNU_SOURCE -#define _GNU_SOURCE -#endif // _GNU_SOURCE - #ifdef HAVE_CONFIG_H # include "../config.h" #endif // HAVE_CONFIG_H +extern "C" { #include #include -#include "i18n.h" -#include "openbox.h" -#include "Clientmenu.h" -#include "Screen.h" -#include "Toolbar.h" -#include "Window.h" -#include "Workspace.h" - -#include "Windowmenu.h" -#include "Geometry.h" -#include "Util.h" - #ifdef HAVE_STDIO_H # include #endif // HAVE_STDIO_H -#ifdef HAVE_STDLIB_H -# include -#endif // HAVE_STDLIB_H - -#ifdef HAVE_STRING_H +#ifdef HAVE_STRING_H # include #endif // HAVE_STRING_H +} -#include -#include -typedef vector rectList; +#include +#include -Workspace::Workspace(BScreen &scrn, int i) : screen(scrn) { +using std::string; - cascade_x = cascade_y = 32; +#include "i18n.hh" +#include "blackbox.hh" +#include "Clientmenu.hh" +#include "Netizen.hh" +#include "Screen.hh" +#include "Toolbar.hh" +#include "Util.hh" +#include "Window.hh" +#include "Workspace.hh" +#include "Windowmenu.hh" - id = i; - stackingList = new LinkedList; - windowList = new LinkedList; - clientmenu = new Clientmenu(*this); +Workspace::Workspace(BScreen *scrn, unsigned int i) { + screen = scrn; - lastfocus = (OpenboxWindow *) 0; + cascade_x = cascade_y = 32; - name = (char *) 0; - char *tmp = screen.getNameOfWorkspace(id); - setName(tmp); -} + id = i; + clientmenu = new Clientmenu(this); -Workspace::~Workspace(void) { - delete stackingList; - delete windowList; - delete clientmenu; + lastfocus = (BlackboxWindow *) 0; - if (name) - delete [] name; + setName(screen->getNameOfWorkspace(id)); } -const int Workspace::addWindow(OpenboxWindow *w, Bool place) { - if (! w) return -1; +void Workspace::addWindow(BlackboxWindow *w, bool place) { + assert(w != 0); if (place) placeWindow(w); w->setWorkspace(id); - w->setWindowNumber(windowList->count()); + w->setWindowNumber(windowList.size()); - stackingList->insert(w, 0); - windowList->insert(w); + stackingList.push_front(w); + windowList.push_back(w); - clientmenu->insert((const char **) w->getTitle()); + clientmenu->insert(w->getTitle()); clientmenu->update(); - screen.updateNetizenWindowAdd(w->getClientWindow(), id); + screen->updateNetizenWindowAdd(w->getClientWindow(), id); raiseWindow(w); - - return w->getWindowNumber(); } -const int Workspace::removeWindow(OpenboxWindow *w) { - if (! w) return -1; +unsigned int Workspace::removeWindow(BlackboxWindow *w) { + assert(w != 0); - stackingList->remove(w); + stackingList.remove(w); - if (w->isFocused()) { - if (w->isTransient() && w->getTransientFor() && - w->getTransientFor()->isVisible()) { - w->getTransientFor()->setInputFocus(); - } else if (screen.sloppyFocus()) { - screen.getOpenbox().setFocusedWindow((OpenboxWindow *) 0); - } else { - OpenboxWindow *top = stackingList->first(); - if (! top || ! top->setInputFocus()) { - screen.getOpenbox().setFocusedWindow((OpenboxWindow *) 0); - XSetInputFocus(screen.getOpenbox().getXDisplay(), - screen.getToolbar()->getWindowID(), - RevertToParent, CurrentTime); - } - } + if (w->isFocused() && ! screen->getBlackbox()->doShutdown()) { + BlackboxWindow *newfocus = 0; + if (w->isTransient()) + newfocus = w->getTransientFor(); + if (! newfocus && ! stackingList.empty()) + newfocus = stackingList.front(); + if (! newfocus || ! newfocus->setInputFocus()) + screen->getBlackbox()->setFocusedWindow(0); } - + if (lastfocus == w) - lastfocus = (OpenboxWindow *) 0; + lastfocus = (BlackboxWindow *) 0; - windowList->remove(w->getWindowNumber()); + windowList.remove(w); clientmenu->remove(w->getWindowNumber()); clientmenu->update(); - screen.updateNetizenWindowDel(w->getClientWindow()); + screen->updateNetizenWindowDel(w->getClientWindow()); - LinkedListIterator it(windowList); - OpenboxWindow *bw = it.current(); - for (int i = 0; bw; it++, i++, bw = it.current()) - bw->setWindowNumber(i); + BlackboxWindowList::iterator it = windowList.begin(); + const BlackboxWindowList::iterator end = windowList.end(); + unsigned int i = 0; + for (; it != end; ++it, ++i) + (*it)->setWindowNumber(i); - return windowList->count(); + if (i == 0) + cascade_x = cascade_y = 32; + + return i; } void Workspace::showAll(void) { - LinkedListIterator it(stackingList); - for (OpenboxWindow *bw = it.current(); bw; it++, bw = it.current()) - bw->deiconify(False, False); + std::for_each(stackingList.begin(), stackingList.end(), + std::mem_fun(&BlackboxWindow::show)); } void Workspace::hideAll(void) { - LinkedList lst; + // withdraw in reverse order to minimize the number of Expose events - LinkedListIterator it(stackingList); - for (OpenboxWindow *bw = it.current(); bw; it++, bw = it.current()) - lst.insert(bw, 0); + BlackboxWindowList lst(stackingList.rbegin(), stackingList.rend()); - LinkedListIterator it2(&lst); - for (OpenboxWindow *bw = it2.current(); bw; it2++, bw = it2.current()) + BlackboxWindowList::iterator it = lst.begin(); + const BlackboxWindowList::iterator end = lst.end(); + for (; it != end; ++it) { + BlackboxWindow *bw = *it; if (! bw->isStuck()) bw->withdraw(); + } } void Workspace::removeAll(void) { - LinkedListIterator it(windowList); - for (OpenboxWindow *bw = it.current(); bw; it++, bw = it.current()) - bw->iconify(); + while (! windowList.empty()) + windowList.front()->iconify(); } -void Workspace::raiseWindow(OpenboxWindow *w) { - OpenboxWindow *win = (OpenboxWindow *) 0, *bottom = w; +/* + * returns the number of transients for win, plus the number of transients + * associated with each transient of win + */ +static int countTransients(const BlackboxWindow * const win) { + int ret = win->getTransients().size(); + if (ret > 0) { + BlackboxWindowList::const_iterator it, end = win->getTransients().end(); + for (it = win->getTransients().begin(); it != end; ++it) { + ret += countTransients(*it); + } + } + return ret; +} - while (bottom->isTransient() && bottom->getTransientFor()) - bottom = bottom->getTransientFor(); - int i = 1; - win = bottom; - while (win->hasTransient() && win->getTransient()) { - win = win->getTransient(); +/* + * 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().size() == 0) 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) { + *stack++ = (*it)->getFrameWindow(); + screen->updateNetizenWindowRaise((*it)->getClientWindow()); + + if (! (*it)->isIconic()) { + Workspace *wkspc = screen->getWorkspace((*it)->getWorkspaceNumber()); + wkspc->stackingList.remove((*it)); + wkspc->stackingList.push_front((*it)); + } + } - i++; + // put transients of win's transients in the stack + for (it = win->getTransients().begin(); it != end; ++it) { + raiseTransients(*it, stack); } +} - Window *nstack = new Window[i], *curr = nstack; - Workspace *wkspc; - win = bottom; - while (True) { - *(curr++) = win->getFrameWindow(); - screen.updateNetizenWindowRaise(win->getClientWindow()); +void Workspace::lowerTransients(const BlackboxWindow * const win, + StackVector::iterator &stack) { + if (win->getTransients().size() == 0) return; // nothing to do - if (! win->isIconic()) { - wkspc = screen.getWorkspace(win->getWorkspaceNumber()); - wkspc->stackingList->remove(win); - wkspc->stackingList->insert(win, 0); - } + // 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); + } - if (! win->hasTransient() || ! win->getTransient()) - break; + // put win's transients in the stack + for (it = win->getTransients().rbegin(); it != end; ++it) { + *stack++ = (*it)->getFrameWindow(); + screen->updateNetizenWindowLower((*it)->getClientWindow()); - win = win->getTransient(); + if (! (*it)->isIconic()) { + Workspace *wkspc = screen->getWorkspace((*it)->getWorkspaceNumber()); + wkspc->stackingList.remove((*it)); + wkspc->stackingList.push_back((*it)); + } } - screen.raiseWindows(nstack, i); - - delete [] nstack; } -void Workspace::lowerWindow(OpenboxWindow *w) { - OpenboxWindow *win = (OpenboxWindow *) 0, *bottom = w; +void Workspace::raiseWindow(BlackboxWindow *w) { + BlackboxWindow *win = w; - while (bottom->isTransient() && bottom->getTransientFor()) - bottom = bottom->getTransientFor(); + // walk up the transient_for's to the window that is not a transient + while (win->isTransient()) { + if (! win->getTransientFor()) break; + win = win->getTransientFor(); + } - int i = 1; - win = bottom; - while (win->hasTransient() && win->getTransient()) { - win = win->getTransient(); + // get the total window count (win and all transients) + unsigned int i = 1 + countTransients(win); - i++; + // stack the window with all transients above + StackVector stack_vector(i); + StackVector::iterator stack = stack_vector.begin(); + + *(stack++) = win->getFrameWindow(); + screen->updateNetizenWindowRaise(win->getClientWindow()); + if (! win->isIconic()) { + Workspace *wkspc = screen->getWorkspace(win->getWorkspaceNumber()); + wkspc->stackingList.remove(win); + wkspc->stackingList.push_front(win); } - Window *nstack = new Window[i], *curr = nstack; - Workspace *wkspc; + raiseTransients(win, stack); - while (True) { - *(curr++) = win->getFrameWindow(); - screen.updateNetizenWindowLower(win->getClientWindow()); + screen->raiseWindows(&stack_vector[0], stack_vector.size()); +} - if (! win->isIconic()) { - wkspc = screen.getWorkspace(win->getWorkspaceNumber()); - wkspc->stackingList->remove(win); - wkspc->stackingList->insert(win); - } - if (! win->getTransientFor()) - break; +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()) { + if (! win->getTransientFor()) break; win = win->getTransientFor(); } - screen.getOpenbox().grab(); + // 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(); - XLowerWindow(screen.getBaseDisplay().getXDisplay(), *nstack); - XRestackWindows(screen.getBaseDisplay().getXDisplay(), nstack, i); + lowerTransients(win, stack); - screen.getOpenbox().ungrab(); + *(stack++) = win->getFrameWindow(); + screen->updateNetizenWindowLower(win->getClientWindow()); + if (! win->isIconic()) { + Workspace *wkspc = screen->getWorkspace(win->getWorkspaceNumber()); + wkspc->stackingList.remove(win); + wkspc->stackingList.push_back(win); + } - delete [] nstack; + XLowerWindow(screen->getBaseDisplay()->getXDisplay(), stack_vector.front()); + XRestackWindows(screen->getBaseDisplay()->getXDisplay(), + &stack_vector[0], stack_vector.size()); } void Workspace::reconfigure(void) { clientmenu->reconfigure(); + std::for_each(windowList.begin(), windowList.end(), + std::mem_fun(&BlackboxWindow::reconfigure)); +} - LinkedListIterator it(windowList); - for (OpenboxWindow *bw = it.current(); bw; it++, bw = it.current()) { - if (bw->validateClient()) - bw->reconfigure(); + +void Workspace::updateFocusModel(void) { + std::for_each(windowList.begin(), windowList.end(), + std::mem_fun(&BlackboxWindow::updateFocusModel)); +} + + +BlackboxWindow *Workspace::getWindow(unsigned int index) { + if (index < windowList.size()) { + BlackboxWindowList::iterator it = windowList.begin(); + for(; index > 0; --index, ++it); /* increment to index */ + return *it; } + return 0; } -OpenboxWindow *Workspace::getWindow(int index) { - if ((index >= 0) && (index < windowList->count())) - return windowList->find(index); - else - 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; } -const int Workspace::getCount(void) { - return windowList->count(); +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); } -void Workspace::update(void) { - clientmenu->update(); - screen.getToolbar()->redrawWindowLabel(True); +BlackboxWindow* Workspace::getTopWindowOnStack(void) const { + return stackingList.front(); } -Bool Workspace::isCurrent(void) { - return (id == screen.getCurrentWorkspaceID()); +void Workspace::sendWindowList(Netizen &n) { + BlackboxWindowList::iterator it = windowList.begin(), + end = windowList.end(); + for(; it != end; ++it) + n.sendWindowAdd((*it)->getClientWindow(), getID()); } -Bool Workspace::isLastWindow(OpenboxWindow *w) { - return (w == windowList->last()); +unsigned int Workspace::getCount(void) const { + return windowList.size(); } -void Workspace::setCurrent(void) { - screen.changeWorkspaceID(id); + +bool Workspace::isCurrent(void) const { + return (id == screen->getCurrentWorkspaceID()); } -void Workspace::setName(char *new_name) { - if (name) - delete [] name; +bool Workspace::isLastWindow(const BlackboxWindow* const w) const { + return (w == windowList.back()); +} - if (new_name) { - name = bstrdup(new_name); +void Workspace::setCurrent(void) { + screen->changeWorkspaceID(id); +} + + +void Workspace::setName(const string& new_name) { + if (! new_name.empty()) { + name = new_name; } else { - name = new char[128]; - sprintf(name, i18n->getMessage(WorkspaceSet, WorkspaceDefaultNameFormat, - "Workspace %d"), id + 1); + string tmp =i18n(WorkspaceSet, WorkspaceDefaultNameFormat, "Workspace %d"); + assert(tmp.length() < 32); + char default_name[32]; + sprintf(default_name, tmp.c_str(), id + 1); + name = default_name; } - + clientmenu->setLabel(name); clientmenu->update(); - screen.saveWorkspaceNames(); + screen->saveWorkspaceNames(); } -void Workspace::shutdown(void) { - while (windowList->count()) { - windowList->first()->restore(); - delete windowList->first(); - } -} +/* + * Calculate free space available for window placement. + */ +typedef std::vector rectList; static rectList calcSpace(const Rect &win, const rectList &spaces) { + Rect isect, extra; rectList result; - rectList::const_iterator siter; - for(siter=spaces.begin(); siter!=spaces.end(); ++siter) { - if(win.Intersect(*siter)) { - //Check for space to the left of the window - if(win.origin().x() > siter->x()) - result.push_back(Rect(siter->x(), siter->y(), - win.origin().x() - siter->x() - 1, - siter->h())); - //Check for space above the window - if(win.origin().y() > siter->y()) - result.push_back(Rect(siter->x(), siter->y(), - siter->w(), - win.origin().y() - siter->y() - 1)); - //Check for space to the right of the window - if((win.origin().x()+win.size().w()) < - (siter->x()+siter->w())) - result.push_back(Rect(win.origin().x() + win.size().w() + 1, - siter->y(), - siter->x() + siter->w() - - win.origin().x() - win.size().w() - 1, - siter->h())); - //Check for space below the window - if((win.origin().y()+win.size().h()) < - (siter->y()+siter->h())) - result.push_back(Rect(siter->x(), - win.origin().y() + win.size().h() + 1, - siter->w(), - siter->y() + siter->h()- - win.origin().y() - win.size().h() - 1)); + rectList::const_iterator siter, end = spaces.end(); + for (siter = spaces.begin(); siter != end; ++siter) { + const Rect &curr = *siter; + if(! win.intersects(curr)) { + result.push_back(curr); + continue; } - else - result.push_back(*siter); + + /* 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() - 1, curr.bottom()); + if (extra.valid()) result.push_back(extra); + + // top + extra.setCoords(curr.left(), curr.top(), + curr.right(), isect.top() - 1); + if (extra.valid()) result.push_back(extra); + + // right + extra.setCoords(isect.right() + 1, curr.top(), + curr.right(), curr.bottom()); + if (extra.valid()) result.push_back(extra); + + // bottom + extra.setCoords(curr.left(), isect.bottom() + 1, + curr.right(), curr.bottom()); + if (extra.valid()) result.push_back(extra); } return result; } -bool incWidth(const Rect &first, const Rect &second) { - return first.x() < second.x(); +static bool rowRLBT(const Rect &first, const Rect &second) { + if (first.bottom() == second.bottom()) + return first.right() > second.right(); + return first.bottom() > second.bottom(); } - -bool decWidth(const Rect &first, const Rect &second) { - if (second.x() == first.x()) - return second.w() < first.w(); - return second.x() < first.x(); +static bool rowRLTB(const Rect &first, const Rect &second) { + if (first.y() == second.y()) + return first.right() > second.right(); + return first.y() < second.y(); } +static bool rowLRBT(const Rect &first, const Rect &second) { + if (first.bottom() == second.bottom()) + return first.x() < second.x(); + return first.bottom() > second.bottom(); +} -bool incHeight(const Rect &first, const Rect &second) { +static bool rowLRTB(const Rect &first, const Rect &second) { + if (first.y() == second.y()) + return first.x() < second.x(); return first.y() < second.y(); } +static bool colLRTB(const Rect &first, const Rect &second) { + if (first.x() == second.x()) + return first.y() < second.y(); + return first.x() < second.x(); +} -bool decHeight(const Rect &first, const Rect &second) { - if (second.y() == first.y()) - return second.h() < first.h(); - return second.y() < first.y(); +static bool colLRBT(const Rect &first, const Rect &second) { + if (first.x() == second.x()) + return first.bottom() > second.bottom(); + return first.x() < second.x(); } +static bool colRLTB(const Rect &first, const Rect &second) { + if (first.right() == second.right()) + return first.y() < second.y(); + return first.right() > second.right(); +} -//BestFitPlacement finds the smallest free space that fits the window -//to be placed. It currentl ignores whether placement is right to left or top -//to bottom. -Point *Workspace::bestFitPlacement(const Size &win_size, const Rect &space) { - const Rect *best; - rectList spaces; - LinkedListIterator it(windowList); - rectList::const_iterator siter; - spaces.push_back(space); //initially the entire screen is free - it.reset(); - - //Find Free Spaces - for (OpenboxWindow *cur=it.current(); cur!=NULL; it++, cur=it.current()) - spaces = calcSpace(cur->area().Inflate(screen.getBorderWidth() * 4), - spaces); - - //Sort the spaces by placement choice - if (screen.rowPlacementDirection() == BScreen::TopBottom) - sort(spaces.begin(), spaces.end(), decHeight); - else - sort(spaces.begin(), spaces.end(), incHeight); - if (screen.colPlacementDirection() == BScreen::TopBottom) - stable_sort(spaces.begin(), spaces.end(), incHeight); - else - stable_sort(spaces.begin(), spaces.end(), decHeight); - - //Find first space that fits the window - best = NULL; - for (siter=spaces.begin(); siter!=spaces.end(); ++siter) { - if ((siter->w() >= win_size.w()) && (siter->h() >= win_size.h())) { - if (best==NULL) - best = siter; - else if(siter->w()*siter->h()h()*best->w()) - best = siter; - } - } - if (best != NULL) { - Point *pt = new Point(best->origin()); - if (screen.colPlacementDirection() != BScreen::TopBottom) - pt->setY(pt->y() + (best->h() - win_size.h())); - if (screen.rowPlacementDirection() != BScreen::LeftRight) - pt->setX(pt->x() + (best->w() - win_size.w())); - return pt; - } else - return NULL; //fall back to cascade +static bool colRLBT(const Rect &first, const Rect &second) { + if (first.right() == second.right()) + return first.bottom() > second.bottom(); + return first.right() > second.right(); } -Point *Workspace::rowSmartPlacement(const Size &win_size, const Rect &space) { - const Rect *best; +bool Workspace::smartPlacement(Rect& win, const Rect& availableArea) { rectList spaces; - LinkedListIterator it(windowList); - rectList::const_iterator siter; - spaces.push_back(space); //initially the entire screen is free - it.reset(); - + spaces.push_back(availableArea); //initially the entire screen is free + //Find Free Spaces - for (OpenboxWindow *cur=it.current(); cur!=NULL; it++, cur=it.current()) - spaces = calcSpace(cur->area().Inflate(screen.getBorderWidth() * 4), - spaces); - - //Sort the spaces by placement choice - if (screen.colPlacementDirection() == BScreen::LeftRight) - sort(spaces.begin(), spaces.end(), incWidth); - else - sort(spaces.begin(), spaces.end(), decWidth); - if (screen.rowPlacementDirection() == BScreen::TopBottom) - stable_sort(spaces.begin(), spaces.end(), incHeight); - else - stable_sort(spaces.begin(), spaces.end(), decHeight); - - //Find first space that fits the window - best = NULL; - for (siter=spaces.begin(); siter!=spaces.end(); ++siter) - if ((siter->w() >= win_size.w()) && (siter->h() >= win_size.h())) { - best = siter; - break; - } + BlackboxWindowList::iterator wit = windowList.begin(), + end = windowList.end(); + Rect tmp; + for (; wit != end; ++wit) { + const BlackboxWindow* const curr = *wit; + tmp.setRect(curr->frameRect().x(), curr->frameRect().y(), + curr->frameRect().width() + screen->getBorderWidth(), + curr->frameRect().height() + screen->getBorderWidth()); + + spaces = calcSpace(tmp, spaces); + } - if (best != NULL) { - Point *pt = new Point(best->origin()); - if (screen.colPlacementDirection() != BScreen::TopBottom) - pt->setY(pt->y() + (best->h() - win_size.h())); - if (screen.rowPlacementDirection() != BScreen::LeftRight) - pt->setX(pt->x() + (best->w() - win_size.w())); - return pt; - } else - return NULL; //fall back to cascade -} + if (screen->getPlacementPolicy() == BScreen::RowSmartPlacement) { + if(screen->getRowPlacementDirection() == BScreen::LeftRight) { + if(screen->getColPlacementDirection() == BScreen::TopBottom) + sort(spaces.begin(), spaces.end(), rowLRTB); + else + sort(spaces.begin(), spaces.end(), rowLRBT); + } else { + if(screen->getColPlacementDirection() == BScreen::TopBottom) + sort(spaces.begin(), spaces.end(), rowRLTB); + else + sort(spaces.begin(), spaces.end(), rowRLBT); + } + } else { + if(screen->getColPlacementDirection() == BScreen::TopBottom) { + if(screen->getRowPlacementDirection() == BScreen::LeftRight) + sort(spaces.begin(), spaces.end(), colLRTB); + else + sort(spaces.begin(), spaces.end(), colRLTB); + } else { + if(screen->getRowPlacementDirection() == BScreen::LeftRight) + sort(spaces.begin(), spaces.end(), colLRBT); + else + sort(spaces.begin(), spaces.end(), colRLBT); + } + } -Point *Workspace::colSmartPlacement(const Size &win_size, const Rect &space) { - const Rect *best; - rectList spaces; - LinkedListIterator it(windowList); - rectList::const_iterator siter; - spaces.push_back(space); //initially the entire screen is free - it.reset(); - - //Find Free Spaces - for (OpenboxWindow *cur=it.current(); cur!=NULL; it++, cur=it.current()) - spaces = calcSpace(cur->area().Inflate(screen.getBorderWidth() * 4), - spaces); - - //Sort the spaces by placement choice - if (screen.rowPlacementDirection() == BScreen::LeftRight) - sort(spaces.begin(),spaces.end(),incWidth); - else - sort(spaces.begin(),spaces.end(),decWidth); - - //Find first space that fits the window - best = NULL; - for (siter=spaces.begin(); siter!=spaces.end(); ++siter) - if ((siter->w() >= win_size.w()) && (siter->h() >= win_size.h())) { - best = siter; + 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 (best != NULL) { - Point *pt = new Point(best->origin()); - if (screen.colPlacementDirection() != BScreen::TopBottom) - pt->setY(pt->y() + (best->h() - win_size.h())); - if (screen.rowPlacementDirection() != BScreen::LeftRight) - pt->setX(pt->x() + (best->w() - win_size.w())); - return pt; - } else - return NULL; //fall back to cascade -} + if (sit == spaces_end) + return False; + //set new position based on the empty space found + const Rect& where = *sit; + win.setX(where.x()); + win.setY(where.y()); -Point *const Workspace::cascadePlacement(const OpenboxWindow *const win){ - if (((unsigned) cascade_x > (screen.size().w() / 2)) || - ((unsigned) cascade_y > (screen.size().h() / 2))) - cascade_x = cascade_y = 32; + // 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; +} - cascade_x += win->getTitleHeight(); - cascade_y += win->getTitleHeight(); - return new Point(cascade_x, cascade_y); +bool Workspace::underMousePlacement(Rect &win, const Rect &availableArea) { + int x, y, rx, ry; + Window c, r; + unsigned int m; + XQueryPointer(screen->getBlackbox()->getXDisplay(), screen->getRootWindow(), + &r, &c, &rx, &ry, &x, &y, &m); + x = rx - win.width() / 2; + y = ry - win.height() / 2; + + if (x < availableArea.x()) + x = availableArea.x(); + if (y < availableArea.y()) + y = availableArea.y(); + if (x + win.width() > availableArea.x() + availableArea.width()) + x = availableArea.x() + availableArea.width() - win.width(); + if (y + win.height() > availableArea.y() + availableArea.height()) + y = availableArea.y() + availableArea.height() - win.height(); + + win.setX(x); + win.setY(y); + + return True; } -void Workspace::placeWindow(OpenboxWindow *win) { - ASSERT(win != NULL); - - // the following code is temporary and will be taken care of by Screen in the - // future (with the NETWM 'strut') - Rect space(0, 0, screen.size().w(), screen.size().h()); +bool Workspace::cascadePlacement(Rect &win, const Rect &availableArea) { + if ((cascade_x > static_cast(availableArea.width() / 2)) || + (cascade_y > static_cast(availableArea.height() / 2))) + cascade_x = cascade_y = 32; -#ifdef SLIT - Slit *slit = screen.getSlit(); - int slit_x = slit->autoHide() ? slit->hiddenOrigin().x() : slit->area().x(), - slit_y = slit->autoHide() ? slit->hiddenOrigin().y() : slit->area().y(); - Toolbar *toolbar = screen.getToolbar(); - int tbarh = screen.hideToolbar() ? 0 : - toolbar->getExposedHeight() + screen.getBorderWidth() * 2; - bool tbartop; - switch (toolbar->placement()) { - case Toolbar::TopLeft: - case Toolbar::TopCenter: - case Toolbar::TopRight: - tbartop = true; - break; - case Toolbar::BottomLeft: - case Toolbar::BottomCenter: - case Toolbar::BottomRight: - tbartop = false; - break; - default: - ASSERT(false); // unhandled placement - } - if ((slit->direction() == Slit::Horizontal && - (slit->placement() == Slit::TopLeft || - slit->placement() == Slit::TopRight)) || - slit->placement() == Slit::TopCenter) { - // exclude top - if (tbartop) - space.setH(space.h() - slit_y); - else - space.setH(space.h() - tbarh); - space.setY(space.y() + slit_y + slit->area().h() + - screen.getBorderWidth() * 2); - space.setH(space.h() - (slit_y + slit->area().h() + - screen.getBorderWidth() * 2)); - } else if ((slit->direction() == Slit::Vertical && - (slit->placement() == Slit::TopRight || - slit->placement() == Slit::BottomRight)) || - slit->placement() == Slit::CenterRight) { - // exclude right - space.setW(space.w() - (screen.size().w() - slit_x + - screen.getBorderWidth() * 2)); - if (tbartop) - space.setY(space.y() + tbarh); - space.setH(space.h() - tbarh); - } else if ((slit->direction() == Slit::Horizontal && - (slit->placement() == Slit::BottomLeft || - slit->placement() == Slit::BottomRight)) || - slit->placement() == Slit::BottomCenter) { - // exclude bottom - space.setH(space.h() - ((screen.size().h() - slit_y) > tbarh ? - screen.size().h() - slit_y : tbarh)); - } else {// if ((slit->direction() == Slit::Vertical && - // (slit->placement() == Slit::TopLeft || - // slit->placement() == Slit::BottomLeft)) || - // slit->placement() == Slit::CenterLeft) - // exclude left - space.setX(slit_x + slit->area().w() + - screen.getBorderWidth() * 2); - space.setW(space.w() - (slit_x + slit->area().w() + - screen.getBorderWidth() * 2)); - if (tbartop) - space.setY(space.y() + tbarh); - space.setH(space.h() - tbarh); - } -#else // !SLIT - Toolbar *toolbar = screen.getToolbar(); - int tbarh = screen.hideToolbar() ? 0 : - toolbar->getExposedHeight() + screen.getBorderWidth() * 2; - switch (toolbar->placement()) { - case Toolbar::TopLeft: - case Toolbar::TopCenter: - case Toolbar::TopRight: - space.setY(toolbar->getExposedHeight()); - space.setH(space.h() - toolbar->getExposedHeight()); - break; - case Toolbar::BottomLeft: - case Toolbar::BottomCenter: - case Toolbar::BottomRight: - space.setH(space.h() - tbarh); - break; - default: - ASSERT(false); // unhandled placement + if (cascade_x == 32) { + cascade_x += availableArea.x(); + cascade_y += availableArea.y(); } -#endif // SLIT - const Size window_size(win->area().w()+screen.getBorderWidth() * 4, - win->area().h()+screen.getBorderWidth() * 4); - Point *place = NULL; - LinkedListIterator it(windowList); + win.setPos(cascade_x, cascade_y); - switch (screen.placementPolicy()) { - case BScreen::BestFitPlacement: - place = bestFitPlacement(window_size, space); - break; + return True; +} + + +void Workspace::placeWindow(BlackboxWindow *win) { + Rect availableArea(screen->availableArea()), + new_win(availableArea.x(), availableArea.y(), + win->frameRect().width(), win->frameRect().height()); + bool placed = False; + + switch (screen->getPlacementPolicy()) { case BScreen::RowSmartPlacement: - place = rowSmartPlacement(window_size, space); - break; case BScreen::ColSmartPlacement: - place = colSmartPlacement(window_size, space); + placed = smartPlacement(new_win, availableArea); break; + case BScreen::UnderMousePlacement: + placed = underMousePlacement(new_win, availableArea); + default: + break; // handled below } // switch - if (place == NULL) - place = cascadePlacement(win); - - ASSERT(place != NULL); - if (place->x() + window_size.w() > (signed) screen.size().w()) - place->setX(((signed) screen.size().w() - window_size.w()) / 2); - if (place->y() + window_size.h() > (signed) screen.size().h()) - place->setY(((signed) screen.size().h() - window_size.h()) / 2); - - win->configure(place->x(), place->y(), win->area().w(), win->area().h()); - delete place; + if (placed == False) { + cascadePlacement(new_win, availableArea); + cascade_x += win->getTitleHeight() + (screen->getBorderWidth() * 2); + cascade_y += win->getTitleHeight() + (screen->getBorderWidth() * 2); + } + + if (new_win.right() > availableArea.right()) + new_win.setX(availableArea.left()); + if (new_win.bottom() > availableArea.bottom()) + new_win.setY(availableArea.top()); + win->configure(new_win.x(), new_win.y(), new_win.width(), new_win.height()); }