X-Git-Url: https://git.dogcows.com/gitweb?a=blobdiff_plain;f=src%2FWorkspace.cc;h=67e191107ccb851cf01987cf28fcd77bcb5de1e6;hb=72a2e98738d87b89620bafd15141690aa4be8fab;hp=88280a1d32eaeb9260069d4e816d742c879c4129;hpb=90dbcb271c5e6d7ca73c19a519b93885b833db0a;p=chaz%2Fopenbox diff --git a/src/Workspace.cc b/src/Workspace.cc index 88280a1d..67e19110 100644 --- a/src/Workspace.cc +++ b/src/Workspace.cc @@ -48,6 +48,7 @@ using std::string; #include "i18n.hh" #include "blackbox.hh" #include "Clientmenu.hh" +#include "Font.hh" #include "Netizen.hh" #include "Screen.hh" #include "Toolbar.hh" @@ -62,7 +63,10 @@ Workspace::Workspace(BScreen *scrn, unsigned int i) { screen = scrn; xatom = screen->getBlackbox()->getXAtom(); - cascade_x = cascade_y = 32; + cascade_x = cascade_y = 0; +#ifdef XINERAMA + cascade_region = 0; +#endif // XINERAMA id = i; @@ -74,27 +78,55 @@ Workspace::Workspace(BScreen *scrn, unsigned int i) { } -void Workspace::addWindow(BlackboxWindow *w, bool place) { +void Workspace::addWindow(BlackboxWindow *w, bool place, bool sticky) { assert(w != 0); if (place) placeWindow(w); - w->setWorkspace(id); - w->setWindowNumber(windowList.size()); - stackingList.push_front(w); - windowList.push_back(w); - clientmenu->insert(w->getTitle()); - clientmenu->update(); + 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()); - screen->updateNetizenWindowAdd(w->getClientWindow(), id); + windowList.push_back(w); - raiseWindow(w); + clientmenu->insert(w->getTitle()); + clientmenu->update(); + + if (! sticky) + screen->updateNetizenWindowAdd(w->getClientWindow(), id); + + 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); } -unsigned int Workspace::removeWindow(BlackboxWindow *w) { +void Workspace::removeWindow(BlackboxWindow *w, bool sticky) { assert(w != 0); stackingList.remove(w); @@ -103,32 +135,37 @@ unsigned int Workspace::removeWindow(BlackboxWindow *w) { if ((w->isFocused() || w == lastfocus) && ! screen->getBlackbox()->doShutdown()) { focusFallback(w); - - // if the window is sticky, then it needs to be removed on all other - // workspaces too! - if (w->isStuck()) { - for (unsigned int i = 0; i < screen->getWorkspaceCount(); ++i) - if (i != id) - screen->getWorkspace(i)->focusFallback(w); - } } + + if (! w->isNormal()) return; - windowList.remove(w); - clientmenu->remove(w->getWindowNumber()); + 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); + clientmenu->remove(i); clientmenu->update(); - screen->updateNetizenWindowDel(w->getClientWindow()); + if (! sticky) { + screen->updateNetizenWindowDel(w->getClientWindow()); - 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 = 32; + BlackboxWindowList::iterator it = windowList.begin(); + const BlackboxWindowList::iterator end = windowList.end(); + unsigned int i = 0; + for (; it != end; ++it, ++i) + (*it)->setWindowNumber(i); + } - return i; + if (i == 0) { + cascade_x = cascade_y = 0; +#ifdef XINERAMA + cascade_region = 0; +#endif // XINERAMA + } } @@ -154,7 +191,7 @@ void Workspace::focusFallback(const BlackboxWindow *old_window) { end = stackingList.end(); for (; it != end; ++it) { BlackboxWindow *tmp = *it; - if (tmp && tmp->setInputFocus()) { + if (tmp && tmp->isNormal() && tmp->setInputFocus()) { // we found our new focus target newfocus = tmp; break; @@ -177,9 +214,35 @@ void Workspace::focusFallback(const BlackboxWindow *old_window) { } +void Workspace::setFocused(const BlackboxWindow *w, bool focused) { + BlackboxWindowList::iterator it, end = windowList.end(); + int i; + for (i = 0, it = windowList.begin(); it != end; ++it, ++i) + if (*it == w) + break; + // if its == end, then a window thats not in the windowList + // got focused, such as a !isNormal() window. + if (it != end) + clientmenu->setItemSelected(i, focused); +} + + +void Workspace::removeAll(void) { + while (! windowList.empty()) + windowList.front()->iconify(); +} + void Workspace::showAll(void) { - std::for_each(stackingList.begin(), stackingList.end(), - std::mem_fun(&BlackboxWindow::show)); + 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()->isStartup()) + bw->show(); + } } @@ -192,30 +255,29 @@ void Workspace::hideAll(void) { 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(); } } -void Workspace::removeAll(void) { - while (! windowList.empty()) - windowList.front()->iconify(); -} - /* * 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); - } - } +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; } @@ -228,48 +290,48 @@ static int countTransients(const BlackboxWindow * const win) { */ void Workspace::raiseTransients(const BlackboxWindow * const win, StackVector::iterator &stack) { - if (win->getTransients().size() == 0) return; // nothing to do + 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) { - *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)); + BlackboxWindow *w = *it; + *stack++ = w->getFrameWindow(); + screen->updateNetizenWindowRaise(w->getClientWindow()); + + 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) { + for (it = win->getTransients().begin(); it != end; ++it) raiseTransients(*it, stack); - } } void Workspace::lowerTransients(const BlackboxWindow * const win, StackVector::iterator &stack) { - if (win->getTransients().size() == 0) return; // nothing to do + 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) { + 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) { - *stack++ = (*it)->getFrameWindow(); - screen->updateNetizenWindowLower((*it)->getClientWindow()); - - if (! (*it)->isIconic()) { - Workspace *wkspc = screen->getWorkspace((*it)->getWorkspaceNumber()); - wkspc->stackingList.remove((*it)); - wkspc->stackingList.push_back((*it)); + BlackboxWindow *w = *it; + *stack++ = w->getFrameWindow(); + screen->updateNetizenWindowLower(w->getClientWindow()); + + if (! w->isIconic()) { + Workspace *wkspc = screen->getWorkspace(w->getWorkspaceNumber()); + wkspc->stackingList.remove(w); + wkspc->stackingList.push_back(w); } } } @@ -278,11 +340,11 @@ void Workspace::lowerTransients(const BlackboxWindow * const win, 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()) { - if (! win->getTransientFor()) break; + while (win->isTransient() && win->getTransientFor()) win = win->getTransientFor(); - } // get the total window count (win and all transients) unsigned int i = 1 + countTransients(win); @@ -293,7 +355,7 @@ void Workspace::raiseWindow(BlackboxWindow *w) { *(stack++) = win->getFrameWindow(); screen->updateNetizenWindowRaise(win->getClientWindow()); - if (! win->isIconic()) { + if (! (win->isIconic() || win->isDesktop())) { Workspace *wkspc = screen->getWorkspace(win->getWorkspaceNumber()); wkspc->stackingList.remove(win); wkspc->stackingList.push_front(win); @@ -309,10 +371,8 @@ 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; + while (win->isTransient() && win->getTransientFor()) win = win->getTransientFor(); - } // get the total window count (win and all transients) unsigned int i = 1 + countTransients(win); @@ -325,7 +385,7 @@ void Workspace::lowerWindow(BlackboxWindow *w) { *(stack++) = win->getFrameWindow(); screen->updateNetizenWindowLower(win->getClientWindow()); - if (! win->isIconic()) { + if (! (win->isIconic() || win->isDesktop())) { Workspace *wkspc = screen->getWorkspace(win->getWorkspaceNumber()); wkspc->stackingList.remove(win); wkspc->stackingList.push_back(win); @@ -345,9 +405,11 @@ void Workspace::reconfigure(void) { BlackboxWindow *Workspace::getWindow(unsigned int index) { if (index < windowList.size()) { BlackboxWindowList::iterator it = windowList.begin(); - for(; index > 0; --index, ++it); /* increment to index */ + while (index-- > 0) // increment to index + ++it; return *it; } + return 0; } @@ -379,6 +441,7 @@ BlackboxWindow* Workspace::getPrevWindowInList(BlackboxWindow *w) { BlackboxWindow* Workspace::getTopWindowOnStack(void) const { + assert(! stackingList.empty()); return stackingList.front(); } @@ -400,9 +463,12 @@ 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) - stack_order.push_back(*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()); @@ -467,9 +533,8 @@ void Workspace::setName(const string& new_name) { /* * Calculate free space available for window placement. */ -typedef std::vector rectList; - -static rectList calcSpace(const Rect &win, const rectList &spaces) { +Workspace::rectList Workspace::calcSpace(const Rect &win, + const rectList &spaces) const { Rect isect, extra; rectList result; rectList::const_iterator siter, end = spaces.end(); @@ -490,21 +555,21 @@ static rectList calcSpace(const Rect &win, const rectList &spaces) { // left extra.setCoords(curr.left(), curr.top(), - isect.left() - 1, curr.bottom()); + isect.left() - screen->getSnapOffset(), curr.bottom()); if (extra.valid()) result.push_back(extra); // top extra.setCoords(curr.left(), curr.top(), - curr.right(), isect.top() - 1); + curr.right(), isect.top() - screen->getSnapOffset()); if (extra.valid()) result.push_back(extra); // right - extra.setCoords(isect.right() + 1, curr.top(), + 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() + 1, + extra.setCoords(curr.left(), isect.bottom() + screen->getSnapOffset(), curr.right(), curr.bottom()); if (extra.valid()) result.push_back(extra); } @@ -561,9 +626,34 @@ static bool colRLBT(const Rect &first, const Rect &second) { } -bool Workspace::smartPlacement(Rect& win, const Rect& availableArea) { +bool Workspace::smartPlacement(Rect& win) { rectList spaces; - spaces.push_back(availableArea); //initially the entire screen is free + + //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 + { + 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(), @@ -572,7 +662,12 @@ bool Workspace::smartPlacement(Rect& win, const Rect& availableArea) { for (; wit != end; ++wit) { const BlackboxWindow* const curr = *wit; - if (curr->isShaded()) continue; + // 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->getBorderWidth(), @@ -637,23 +732,39 @@ bool Workspace::smartPlacement(Rect& win, const Rect& availableArea) { } -bool Workspace::underMousePlacement(Rect &win, const Rect &availableArea) { +bool Workspace::underMousePlacement(Rect &win) { int x, y, rx, ry; Window c, r; unsigned int m; XQueryPointer(screen->getBlackbox()->getXDisplay(), screen->getRootWindow(), &r, &c, &rx, &ry, &x, &y, &m); + + 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 < 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(); + 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); @@ -662,48 +773,69 @@ bool Workspace::underMousePlacement(Rect &win, const Rect &availableArea) { } -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; +bool Workspace::cascadePlacement(Rect &win, const int offset) { + Rect area; + +#ifdef XINERAMA + if (screen->isXineramaActive() && + screen->getBlackbox()->doXineramaPlacement()) { + area = screen->allAvailableAreas()[cascade_region]; + } else +#endif // XINERAMA + area = screen->availableArea(); + + if ((static_cast(cascade_x + win.width()) > area.right() + 1) || + (static_cast(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 == 32) { - cascade_x += availableArea.x(); - cascade_y += availableArea.y(); + 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) { - Rect availableArea(screen->availableArea()), - new_win(availableArea.x(), availableArea.y(), - win->frameRect().width(), win->frameRect().height()); + 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, availableArea); + placed = smartPlacement(new_win); break; case BScreen::UnderMousePlacement: - placed = underMousePlacement(new_win, availableArea); + case BScreen::ClickMousePlacement: + placed = underMousePlacement(new_win); default: break; // handled below } // switch - if (placed == False) { - cascadePlacement(new_win, availableArea); - cascade_x += win->getTitleHeight() + (screen->getBorderWidth() * 2); - cascade_y += win->getTitleHeight() + (screen->getBorderWidth() * 2); - } + if (placed == False) + cascadePlacement(new_win, (win->getTitleHeight() + + screen->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()); - 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()); }