[PATCH] directional focus

Michael Leuchtenburg michael at slashhome.org
Thu Apr 3 00:20:08 EST 2003


Here's a patch to implement directional focus in epistrophy. It should
be applied to the openbox-2_3 revision. And yeah, I'll port it to ob3.
:)

BTW, the algorithm used in this is not optimal, but it's the same one
the direction.jl I have for sawfish uses. If you don't like it, feel
free to change it. And please tell me of any better algorithms you come
up with.

-- michael
-------------- next part --------------
Index: util/epist/parser.cc
===================================================================
RCS file: /cvs/cvsroot/openbox/util/epist/Attic/parser.cc,v
retrieving revision 1.9.8.2
diff -p -u -r1.9.8.2 parser.cc
--- util/epist/parser.cc	2002/12/31 22:52:06	1.9.8.2
+++ util/epist/parser.cc	2003/04/03 04:54:50
@@ -114,6 +114,10 @@ void parser::setAction(string act)
     { "prevwindowofclass", Action::prevWindowOfClass },
     { "nextwindowofclassonallworkspaces", Action::nextWindowOfClassOnAllWorkspaces },
     { "prevwindowofclassonallworkspaces", Action::prevWindowOfClassOnAllWorkspaces },
+    { "upWindow", Action::upWindow },
+    { "downWindow", Action::downWindow },
+    { "leftWindow", Action::leftWindow },
+    { "rightWindow", Action::rightWindow },
     { "changeworkspace", Action::changeWorkspace },
     { "nextworkspace", Action::nextWorkspace },
     { "prevworkspace", Action::prevWorkspace },
Index: util/epist/screen.cc
===================================================================
RCS file: /cvs/cvsroot/openbox/util/epist/Attic/screen.cc,v
retrieving revision 1.82.6.3
diff -p -u -r1.82.6.3 screen.cc
--- util/epist/screen.cc	2002/12/31 22:52:06	1.82.6.3
+++ util/epist/screen.cc	2003/04/03 04:54:50
@@ -246,6 +246,22 @@ void screen::handleKeypress(const XEvent
     cycleWindow(state, false, it->number() != 0 ? it->number(): 1,
                 false, true, true, it->string());
     return;
+  
+  case Action::upWindow:
+    cycleWindowDirectionally(state,up);
+    return;
+  
+  case Action::downWindow:
+    cycleWindowDirectionally(state,down);
+    return;
+  
+  case Action::leftWindow:
+    cycleWindowDirectionally(state, left);
+    return;
+  
+  case Action::rightWindow:
+    cycleWindowDirectionally(state, right);
+    return;
 
   case Action::changeWorkspace:
     changeWorkspace(it->number());
@@ -652,6 +668,96 @@ void screen::cycleWindow(unsigned int st
       // found a good window so break out of the while, and perhaps continue
       // with the for loop
       break;
+    }
+  }
+
+  // phew. we found the window, so focus it.
+  if (_stacked_cycling && state) {
+    if (!_cycling) {
+      // grab modifiers so we can intercept KeyReleases from them
+      grabModifiers();
+      _cycling = true;
+    }
+
+    // if the window is on another desktop, we can't use XSetInputFocus, since
+    // it doesn't imply a workspace change.
+    if (_stacked_raise || (t->desktop() != _active_desktop &&
+                           t->desktop() != 0xffffffff))
+      t->focus(); // raise
+    else
+      t->focus(false); // don't raise
+  }  
+  else {
+    t->focus();
+  }
+}
+
+/* 
+   optimally, if there is no currently active window, the directional cycling
+   commands would use the location of the mouse pointer as the base. However,
+   epistrophy doesn't know where the mouse pointer is, so we don't do that
+*/
+void screen::cycleWindowDirectionally(unsigned int state, direction dir)
+  
+{
+  assert(_managed);
+
+  if (_clients.empty()) return;
+  
+  WindowList::const_iterator current = _clients.begin(),
+    end = _clients.end();
+  
+  if (_active == current) {
+    current++;
+  }
+  XWindow *t = *current;
+  XWindow *c = 0;
+  XWindow *a = *_active;
+
+  int t_fitness;
+  int c_fitness;
+  
+  if (_active != end) {
+    if (dir == up || dir == down) {
+      t_fitness = abs(t->y() - a->y()) + 2 * abs(t->x() - a->x());
+    } else {
+      t_fitness = abs(t->x() - a->x()) + 2 * abs(t->y() - a->y());
+    }
+    while (++current != end) {
+      // determine if this window is invalid for cycling to
+      c = *current;
+      
+      if (current == _active) continue;
+      switch (dir) {
+      case up:
+        if (c->y() > a->y()) continue;
+	break;
+      case down:
+        if (c->y() < a->y()) continue;
+	break;
+      case left:
+        if (c->x() > a->x()) continue;
+	break;
+      case right:
+        if (c->x() < a->x()) continue;
+	break;
+      }
+      if (t->iconic()) continue;
+      if (t->getScreen() != this) continue;
+      if (! (t->desktop() == _active_desktop ||
+                              t->desktop() == 0xffffffff)) continue;
+      if (! t->canFocus()) continue;
+
+      if (dir == up || dir == down) {
+        c_fitness = abs(c->y() - a->y()) + 2 * abs(c->x() - a->x());
+      } else {
+        c_fitness = abs(c->x() - a->x()) + 2 * abs(c->y() - a->y());
+      }
+
+      if (c_fitness < t_fitness) {
+        t_fitness = c_fitness;
+        t = c;
+      }
     }
   }
 
Index: util/epist/screen.hh
===================================================================
RCS file: /cvs/cvsroot/openbox/util/epist/Attic/screen.hh,v
retrieving revision 1.18.8.2
diff -p -u -r1.18.8.2 screen.hh
--- util/epist/screen.hh	2002/12/31 22:52:06	1.18.8.2
+++ util/epist/screen.hh	2003/04/03 04:54:51
@@ -38,6 +38,8 @@ class screen;
 class XAtom;
 class ScreenInfo;
 
+typedef enum { left, right, up, down } direction;
+
 class screen {
   epist *_epist;
   XAtom *_xatom;
@@ -91,6 +93,7 @@ public:
                    const bool alldesktops = false,
                    const bool sameclass = false,
                    const std::string &classname = "");
+  void cycleWindowDirectionally(unsigned int state, direction dir);
   void cycleWorkspace(const bool forward, const int increment,
                       const bool loop = true) const;
   void changeWorkspace(const int num) const;


More information about the openbox mailing list