]> Dogcows Code - chaz/openbox/blobdiff - src/Workspace.cc
merged with 2_1-merged-to-HEAD-2002-09-30
[chaz/openbox] / src / Workspace.cc
index 90ca6ef3e38f0332c6cf43cd38bd2ca22d29aa34..67e191107ccb851cf01987cf28fcd77bcb5de1e6 100644 (file)
@@ -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,32 +78,44 @@ 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);
 
   stackingList.push_front(w);
-    
-  if (w->isNormal()) {
+
+  if (! sticky)
     w->setWorkspace(id);
-    w->setWindowNumber(windowList.size());
+  
+  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);
 
     clientmenu->insert(w->getTitle());
     clientmenu->update();
 
-    screen->updateNetizenWindowAdd(w->getClientWindow(), id);
-
-    if (id != screen->getCurrentWorkspaceID() &&
-        screen->doFocusNew()) {
-      /*
-         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 (! 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;
+      }
     }
   }
 
@@ -110,7 +126,7 @@ void Workspace::addWindow(BlackboxWindow *w, bool place) {
 }
 
 
-void Workspace::removeWindow(BlackboxWindow *w) {
+void Workspace::removeWindow(BlackboxWindow *w, bool sticky) {
   assert(w != 0);
 
   stackingList.remove(w);
@@ -119,32 +135,37 @@ void 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);
+    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;
+  if (i == 0) {
+    cascade_x = cascade_y = 0;
+#ifdef    XINERAMA
+    cascade_region = 0;
+#endif // XINERAMA
+  }
 }
 
 
@@ -193,12 +214,33 @@ 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) {
   BlackboxWindowList::iterator it = stackingList.begin();
   const BlackboxWindowList::iterator end = stackingList.end();
   for (; it != end; ++it) {
     BlackboxWindow *bw = *it;
-    if (! bw->isStuck())
+    // 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();
   }
 }
@@ -206,36 +248,36 @@ void Workspace::showAll(void) {
 
 void Workspace::hideAll(void) {
   // withdraw in reverse order to minimize the number of Expose events
-  BlackboxWindowList::reverse_iterator it = stackingList.rbegin();
-  const BlackboxWindowList::reverse_iterator end = stackingList.rend();
-  while (it != end) {
+
+  BlackboxWindowList lst(stackingList.rbegin(), stackingList.rend());
+
+  BlackboxWindowList::iterator it = lst.begin();
+  const BlackboxWindowList::iterator end = lst.end();
+  for (; it != end; ++it) {
     BlackboxWindow *bw = *it;
-    ++it; // withdraw removes the current item from the list so we need the next
-          // iterator before that happens
+    // 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;
 }
 
@@ -248,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);
     }
   }
 }
@@ -301,10 +343,8 @@ void Workspace::raiseWindow(BlackboxWindow *w) {
   if (win->isDesktop()) return;
 
   // walk up the transient_for's to the window that is not a transient
-  while (win->isTransient() && ! win->isDesktop()) {
-    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);
@@ -331,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() && ! win->isDesktop()) {
-    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);
@@ -367,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;
 }
 
@@ -401,6 +441,7 @@ BlackboxWindow* Workspace::getPrevWindowInList(BlackboxWindow *w) {
 
 
 BlackboxWindow* Workspace::getTopWindowOnStack(void) const {
+  assert(! stackingList.empty());
   return stackingList.front();
 }
 
@@ -422,10 +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)
-    if ((*it)->isNormal())
+    // 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());
@@ -490,9 +533,8 @@ void Workspace::setName(const string& new_name) {
 /*
  * Calculate free space available for window placement.
  */
-typedef std::vector<Rect> 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();
@@ -513,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);
   }
@@ -594,11 +636,24 @@ bool Workspace::smartPlacement(Rect& win) {
     RectList availableAreas = screen->allAvailableAreas();
     RectList::iterator it, end = availableAreas.end();
 
-    for (it = availableAreas.begin(); it != end; ++it)
+    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
-    spaces.push_back(screen->availableArea());
+  {
+    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(),
@@ -607,8 +662,12 @@ bool Workspace::smartPlacement(Rect& win) {
   for (; wit != end; ++wit) {
     const BlackboxWindow* const curr = *wit;
 
-    if (curr->isShaded() && screen->getPlaceIgnoreShaded()) continue;
-    if (curr->isMaximizedFull() && screen->getPlaceIgnoreMaximized()) 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(),
@@ -714,20 +773,41 @@ bool Workspace::underMousePlacement(Rect &win) {
 }
 
 
-bool Workspace::cascadePlacement(Rect &win) {
-  const Rect &availableArea = screen->availableArea();
+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 ((cascade_x > static_cast<signed>(availableArea.width() / 2)) ||
-      (cascade_y > static_cast<signed>(availableArea.height() / 2)))
-    cascade_x = cascade_y = 32;
+  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 == 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;
 }
 
@@ -748,14 +828,14 @@ void Workspace::placeWindow(BlackboxWindow *win) {
     break; // handled below
   } // switch
 
-  if (placed == False) {
-    cascadePlacement(new_win);
-    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));
 
-  // make sure the placement was valid
-  assert(screen->availableArea().contains(new_win));
+  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());
 }
This page took 0.032325 seconds and 4 git commands to generate.