X-Git-Url: https://git.brokenzipper.com/gitweb?a=blobdiff_plain;f=src%2FWorkspace.cc;h=91bc141958865f3d706091bd1ee215c4db1840d1;hb=12fcb33bfaa03b3c6245d15bfb1809f7facc857f;hp=c31b3efaa02b6dd9502de838461467fc22b242cd;hpb=424d476f7cd0ccc2def4f14119cd4fc3171d0159;p=chaz%2Fopenbox diff --git a/src/Workspace.cc b/src/Workspace.cc index c31b3efa..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,284 +21,347 @@ // 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" - #ifdef HAVE_STDIO_H # include #endif // HAVE_STDIO_H -#ifdef HAVE_STDLIB_H -# include -#endif // HAVE_STDLIB_H - -#ifdef STDC_HEADERS +#ifdef HAVE_STRING_H # include -#endif // STDC_HEADERS +#endif // HAVE_STRING_H +} + +#include +#include + +using std::string; + +#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" -#include -typedef vector rectList; -Workspace::Workspace(BScreen *scrn, int i) { +Workspace::Workspace(BScreen *scrn, unsigned int i) { screen = scrn; cascade_x = cascade_y = 32; id = i; - stackingList = new LinkedList; - windowList = new LinkedList; clientmenu = new Clientmenu(this); - lastfocus = (OpenboxWindow *) 0; + lastfocus = (BlackboxWindow *) 0; - name = (char *) 0; - char *tmp = screen->getNameOfWorkspace(id); - setName(tmp); + setName(screen->getNameOfWorkspace(id)); } -Workspace::~Workspace(void) { - delete stackingList; - delete windowList; - delete clientmenu; - - if (name) - delete [] name; -} - - -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); 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->isSloppyFocus()) { - 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()); - 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)); +} + + +void Workspace::updateFocusModel(void) { + std::for_each(windowList.begin(), windowList.end(), + std::mem_fun(&BlackboxWindow::updateFocusModel)); +} + - LinkedListIterator it(windowList); - for (OpenboxWindow *bw = it.current(); bw; it++, bw = it.current()) { - if (bw->validateClient()) - bw->reconfigure(); +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) { +void Workspace::sendWindowList(Netizen &n) { + BlackboxWindowList::iterator it = windowList.begin(), + end = windowList.end(); + for(; it != end; ++it) + n.sendWindowAdd((*it)->getClientWindow(), getID()); +} + + +unsigned int Workspace::getCount(void) const { + return windowList.size(); +} + + +bool Workspace::isCurrent(void) const { return (id == screen->getCurrentWorkspaceID()); } -Bool Workspace::isLastWindow(OpenboxWindow *w) { - return (w == windowList->last()); +bool Workspace::isLastWindow(const BlackboxWindow* const w) const { + return (w == windowList.back()); } void Workspace::setCurrent(void) { @@ -306,298 +369,260 @@ void Workspace::setCurrent(void) { } -void Workspace::setName(char *new_name) { - if (name) - delete [] name; - - if (new_name) { - name = bstrdup(new_name); +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(); } -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 OpenboxWindow &win, const rectList &spaces) { +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.getArea().Intersect(*siter)) { - //Check for space to the left of the window - if(win.getXFrame() > siter->x()) - result.push_back(Rect(siter->x(), siter->y(), - win.getXFrame() - siter->x() - 1, - siter->h())); - //Check for space above the window - if(win.getYFrame() > siter->y()) - result.push_back(Rect(siter->x(), siter->y(), - siter->w(), - win.getYFrame() - siter->y() - 1)); - //Check for space to the right of the window - if((win.getXFrame()+win.getWidth()) < - (siter->x()+siter->w())) - result.push_back(Rect(win.getXFrame() + win.getWidth() + 1, - siter->y(), - siter->x() + siter->w() - - win.getXFrame() - win.getWidth() - 1, - siter->h())); - //Check for space below the window - if((win.getYFrame()+win.getHeight()) < - (siter->y()+siter->h())) - result.push_back(Rect(siter->x(), - win.getYFrame() + win.getHeight() + 1, - siter->w(), - siter->y() + siter->h()- - win.getYFrame() - win.getHeight() - 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; } -//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; + +static bool rowRLBT(const Rect &first, const Rect &second) { + if (first.bottom() == second.bottom()) + return first.right() > second.right(); + return first.bottom() > second.bottom(); +} + +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(); +} + +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(); +} + +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(); +} + +static bool colRLBT(const Rect &first, const Rect &second) { + if (first.right() == second.right()) + return first.bottom() > second.bottom(); + return first.right() > second.right(); +} + + +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, spaces); - - //Find first space that fits the window - best = 0; - for (siter=spaces.begin(); siter!=spaces.end(); ++siter) { - if ((siter->w() >= win_size.w()) && - (siter->h() >= win_size.h())) - best = siter; + 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 != 0) - return new Point(best->origin()); - else - return new Point(200, 0); -} - -inline Point *Workspace::rowSmartPlacement(const Size &win_size, - const Rect &space){ - bool placed=false; - int test_x, test_y, place_x = 0, place_y = 0; - int start_pos = 0; - int change_y = - ((screen->getColPlacementDirection() == BScreen::TopBottom) ? 1 : -1); - int change_x = - ((screen->getRowPlacementDirection() == BScreen::LeftRight) ? 1 : -1); - int delta_x = 8, delta_y = 8; - LinkedListIterator it(windowList); - - test_y = (screen->getColPlacementDirection() == BScreen::TopBottom) ? - start_pos : screen->getHeight() - win_size.h() - start_pos; - - while(!placed && - ((screen->getColPlacementDirection() == BScreen::BottomTop) ? - test_y > 0 : test_y + win_size.h() < (signed) space.h())) { - test_x = (screen->getRowPlacementDirection() == BScreen::LeftRight) ? - start_pos : space.w() - win_size.w() - start_pos; - while (!placed && - ((screen->getRowPlacementDirection() == BScreen::RightLeft) ? - test_x > 0 : test_x + win_size.w() < (signed) space.w())) { - placed = true; - - it.reset(); - for (OpenboxWindow *curr = it.current(); placed && curr; - it++, curr = it.current()) { - int curr_w = curr->getWidth() + (screen->getBorderWidth() * 4); - int curr_h = - ((curr->isShaded()) ? curr->getTitleHeight() : curr->getHeight()) + - (screen->getBorderWidth() * 4); - - if (curr->getXFrame() < test_x + win_size.w() && - curr->getXFrame() + curr_w > test_x && - curr->getYFrame() < test_y + win_size.h() && - curr->getYFrame() + curr_h > test_y) { - placed = false; - } - } - - // Removed code for checking toolbar and slit - // The space passed in should not include either - - if (placed) { - place_x = test_x; - place_y = test_y; - - break; - } - - test_x += (change_x * delta_x); - } - - test_y += (change_y * delta_y); + 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); + } } - return new Point(place_x, place_y); -} - -void Workspace::placeWindow(OpenboxWindow *win) { - assert(win != NULL); - - Bool placed = False; - - const int win_w = win->getWidth() + (screen->getBorderWidth() * 4), - win_h = win->getHeight() + (screen->getBorderWidth() * 4), -#ifdef SLIT - slit_x = screen->getSlit()->getX() - screen->getBorderWidth(), - slit_y = screen->getSlit()->getY() - screen->getBorderWidth(), - slit_w = screen->getSlit()->getWidth() + - (screen->getBorderWidth() * 4), - slit_h = screen->getSlit()->getHeight() + - (screen->getBorderWidth() * 4), -#endif // SLIT - toolbar_x = screen->getToolbar()->getX() - screen->getBorderWidth(), - toolbar_y = screen->getToolbar()->getY() - screen->getBorderWidth(), - toolbar_w = screen->getToolbar()->getWidth() + - (screen->getBorderWidth() * 4), - toolbar_h = screen->getToolbar()->getHeight() + - (screen->getBorderWidth() * 4), - start_pos = 0, - change_y = - ((screen->getColPlacementDirection() == BScreen::TopBottom) ? 1 : -1), - change_x = - ((screen->getRowPlacementDirection() == BScreen::LeftRight) ? 1 : -1), - delta_x = 8, delta_y = 8; - - int test_x, test_y, place_x = 0, place_y = 0; - LinkedListIterator it(windowList); - - Rect space(0, 0, - screen->getWidth(), - screen->getHeight() - ); - Size window_size(win_w, win_h); - switch (screen->getPlacementPolicy()) { - case BScreen::BestFitPlacement: { - Point *spot = bestFitPlacement(window_size, space); - if (spot != NULL) { - place_x=spot->x(); - place_y=spot->y(); - delete spot; - placed=true; - } - break; + 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; } - case BScreen::RowSmartPlacement: { - Point *spot=rowSmartPlacement(window_size, space); - if (spot != NULL) { - place_x=spot->x(); - place_y=spot->y(); - delete spot; - placed=true; - } - break; + + 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()); + + // 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; +} - case BScreen::ColSmartPlacement: { - test_x = (screen->getRowPlacementDirection() == BScreen::LeftRight) ? - start_pos : screen->getWidth() - win_w - start_pos; - - while (!placed && - ((screen->getRowPlacementDirection() == BScreen::RightLeft) ? - test_x > 0 : test_x + win_w < (signed) screen->getWidth())) { - test_y = (screen->getColPlacementDirection() == BScreen::TopBottom) ? - start_pos : screen->getHeight() - win_h - start_pos; - - while (!placed && - ((screen->getColPlacementDirection() == BScreen::BottomTop) ? - test_y > 0 : test_y + win_h < (signed) screen->getHeight())) { - placed = True; - - it.reset(); - for (OpenboxWindow *curr = it.current(); placed && curr; - it++, curr = it.current()) { - if (curr->isMaximizedFull()) // fully maximized, ignore it - continue; - int curr_w = curr->getWidth() + (screen->getBorderWidth() * 4); - int curr_h = - ((curr->isShaded()) ? curr->getTitleHeight() : curr->getHeight()) + - (screen->getBorderWidth() * 4); - - if (curr->getXFrame() < test_x + win_w && - curr->getXFrame() + curr_w > test_x && - curr->getYFrame() < test_y + win_h && - curr->getYFrame() + curr_h > test_y) { - placed = False; - } - } - - if (placed && - (toolbar_x < test_x + win_w && - toolbar_x + toolbar_w > test_x && - toolbar_y < test_y + win_h && - toolbar_y + toolbar_h > test_y) -#ifdef SLIT - || - (slit_x < test_x + win_w && - slit_x + slit_w > test_x && - slit_y < test_y + win_h && - slit_y + slit_h > test_y) -#endif // SLIT - ) - placed = False; - - if (placed) { - place_x = test_x; - place_y = test_y; - - break; - } - - test_y += (change_y * delta_y); - } - - test_x += (change_x * delta_x); - } - break; +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; +} + + +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; + + if (cascade_x == 32) { + cascade_x += availableArea.x(); + cascade_y += availableArea.y(); } - } // switch - if (! placed) { - if (((unsigned) cascade_x > (screen->getWidth() / 2)) || - ((unsigned) cascade_y > (screen->getHeight() / 2))) - cascade_x = cascade_y = 32; + win.setPos(cascade_x, cascade_y); - place_x = cascade_x; - place_y = cascade_y; + 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: + case BScreen::ColSmartPlacement: + placed = smartPlacement(new_win, availableArea); + break; + case BScreen::UnderMousePlacement: + placed = underMousePlacement(new_win, availableArea); + default: + break; // handled below + } // switch - cascade_x += win->getTitleHeight(); - cascade_y += win->getTitleHeight(); + if (placed == False) { + cascadePlacement(new_win, availableArea); + cascade_x += win->getTitleHeight() + (screen->getBorderWidth() * 2); + cascade_y += win->getTitleHeight() + (screen->getBorderWidth() * 2); } - - if (place_x + win_w > (signed) screen->getWidth()) - place_x = (((signed) screen->getWidth()) - win_w) / 2; - if (place_y + win_h > (signed) screen->getHeight()) - place_y = (((signed) screen->getHeight()) - win_h) / 2; - win->configure(place_x, place_y, win->getWidth(), win->getHeight()); + 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()); }