epist now based on the BaseDisplay.
authorDana Jansens <danakj@orodu.net>
Fri, 12 Jul 2002 16:29:59 +0000 (16:29 +0000)
committerDana Jansens <danakj@orodu.net>
Fri, 12 Jul 2002 16:29:59 +0000 (16:29 +0000)
has the ability to be multiscreen!

util/epist/Makefile.am
util/epist/epist.cc
util/epist/epist.hh
util/epist/main.cc [new file with mode: 0644]
util/epist/process.cc
util/epist/process.hh
util/epist/screen.cc [new file with mode: 0644]
util/epist/screen.hh [new file with mode: 0644]
util/epist/window.cc
util/epist/window.hh

index ee91b55..8d3f22c 100644 (file)
@@ -4,8 +4,11 @@ CPPFLAGS= @CPPFLAGS@ @DEBUG@
 
 bin_PROGRAMS =         epist
 
-epist_SOURCES =                epist.cc process.cc window.cc
-epist_LDADD =      ../../src/XAtom.o
+epist_SOURCES =                epist.cc process.cc window.cc screen.cc main.cc
+epist_LDADD =          ../../src/XAtom.o ../../src/BaseDisplay.o \
+                                       ../../src/Util.o ../../src/i18n.o \
+                                       ../../src/GCCache.o ../../src/Color.o ../../src/Texture.o \
+                                       ../../src/Timer.o ../../src/Image.o ../../src/ImageControl.o
 
 MAINTAINERCLEANFILES = Makefile.in
 
@@ -14,5 +17,12 @@ distclean-local:
 
 # local dependencies
 
-epist.o: epist.cc epist.hh process.hh
-process.o: process.cc process.hh /usr/include/X11/Xlib.h epist.hh
+epist.o: epist.cc epist.hh ../../src/BaseDisplay.hh ../../src/Timer.hh \
+  ../../src/Util.hh process.hh screen.hh window.hh ../../src/XAtom.hh
+main.o: main.cc epist.hh ../../src/BaseDisplay.hh ../../src/Timer.hh \
+  ../../src/Util.hh ../../src/i18n.hh ../../nls/blackbox-nls.hh
+process.o: process.cc
+screen.o: screen.cc ../../src/XAtom.hh screen.hh window.hh epist.hh \
+  ../../src/BaseDisplay.hh ../../src/Timer.hh ../../src/Util.hh
+window.o: window.cc window.hh epist.hh ../../src/BaseDisplay.hh \
+  ../../src/Timer.hh ../../src/Util.hh ../../src/XAtom.hh
index 63a3192..474d8fe 100644 (file)
@@ -30,10 +30,6 @@ extern "C" {
 #  include <unistd.h>
 #endif // HAVE_UNISTD_H
 
-#ifdef    HAVE_STDIO_H
-#  include <stdio.h>
-#endif // HAVE_STDIO_H
-
 #ifdef    HAVE_STDLIB_H
 #  include <stdlib.h>
 #endif // HAVE_STDLIB_H
@@ -42,9 +38,9 @@ extern "C" {
 #  include <signal.h>
 #endif // HAVE_SIGNAL_H
 
-#ifdef    HAVE_LIBGEN_H
+/*#ifdef    HAVE_LIBGEN_H
 #  include <libgen.h>
-#endif // HAVE_LIBGEN_H
+#endif // HAVE_LIBGEN_H*/
 }
 
 #include <iostream>
@@ -56,129 +52,93 @@ using std::string;
 
 #include "epist.hh"
 #include "process.hh"
+#include "screen.hh"
+#include "window.hh"
 #include "../../src/XAtom.hh"
 
-bool _shutdown = false;
-char **_argv;
-char *_display_name = 0;
-Display *_display = 0;
-Window _root = None;
-XAtom *_xatom;
+
+epist::epist(char **argv, char *dpy_name, char *rc_file)
+  : BaseDisplay(argv[0], dpy_name) {
+
+  _argv = argv;
+
+  if (rc_file)
+    _rc_file = rc_file;
+  else
+    _rc_file = expandTilde("~/.openbox/epistrc");
+
+  _xatom = new XAtom(getXDisplay());
+
+  screen *s = new screen(this, DefaultScreen(getXDisplay()));
+  if (s->managed())
+    _screens.push_back(s);
+  if (_screens.empty()) {
+    cout << "No compatible window manager found on any screens. Aborting.\n";
+    ::exit(1);
+  }
+}
+
+
+epist::~epist() {
+  delete _xatom;
+}
 
 
-#ifdef   HAVE_SIGACTION
-static void signalhandler(int sig)
-#else //  HAVE_SIGACTION
-static RETSIGTYPE signalhandler(int sig)
-#endif // HAVE_SIGACTION
-{
+bool epist::handleSignal(int sig) {
   switch (sig) {
-  case SIGSEGV:
-    cout << "epist: Segmentation fault. Aborting and dumping core.\n";
-    abort();
   case SIGHUP:
     cout << "epist: Restarting on request.\n";
     execvp(_argv[0], _argv);
     execvp(basename(_argv[0]), _argv);
+    return false;  // this should be unreachable
+
+  case SIGTERM:
+  case SIGINT:
+  case SIGPIPE:
+    shutdown();
+    return true;
   }
-  _shutdown = true;
 
-#ifndef   HAVE_SIGACTION
-  // assume broken, braindead sysv signal semantics
-  signal(sig, (RETSIGTYPE (*)(int)) signalhandler);
-#endif // HAVE_SIGACTION
+  return false;
 }
 
 
-void parseCommandLine(int argc, char **argv) {
-  _argv = argv;
+void epist::process_event(XEvent *e) {
+  Window root;
 
-  for (int i = 1; i < argc; ++i) {
-    if (string(argv[i]) == "-display") {
-      if (++i >= argc) {
-        cout << "error:: '-display' requires an argument\n";
-        exit(1);
-      }
-      _display_name = argv[i];
-
-      string dtmp = (string)"DISPLAY=" + _display_name;
-      if (putenv(const_cast<char*>(dtmp.c_str()))) {
-        cout << "warning: couldn't set environment variable 'DISPLAY'\n";
-        perror("putenv()");
-      }
+  if (e->xany.type == KeyPress)
+    root = e->xkey.root;
+  else
+    root = e->xany.window;
+  
+  ScreenList::const_iterator it, end = _screens.end();
+  for (it = _screens.begin(); it != end; ++it) {
+    if ((*it)->rootWindow() == root) {
+      (*it)->processEvent(*e);
+      return;
     }
   }
-}
 
+  // wasnt a root window, try for client windows
+  XWindow *w = findWindow(e->xany.window);
+  if (w) w->processEvent(*e);
+}
   
-bool findSupportingWM() {
-  Window support_win;
-  if (! _xatom->getValue(_root, XAtom::net_supporting_wm_check, XAtom::window,
-                         support_win) || support_win == None)
-    return false;
-
-  string title;
-  _xatom->getValue(support_win, XAtom::net_wm_name, XAtom::utf8, title);
-  cout << "Found compatible window manager: " << title << endl;
-  return true;
+
+void epist::addWindow(XWindow *window) {
+  _windows.insert(WindowLookupPair(window->window(), window));
 }
 
 
-int main(int argc, char **argv) {
-#ifdef    HAVE_SIGACTION
-  struct sigaction action;
-
-  action.sa_handler = signalhandler;
-  action.sa_mask = sigset_t();
-  action.sa_flags = SA_NOCLDSTOP | SA_NODEFER;
-
-  sigaction(SIGPIPE, &action, NULL);
-  sigaction(SIGSEGV, &action, NULL);
-  sigaction(SIGFPE, &action, NULL);
-  sigaction(SIGTERM, &action, NULL);
-  sigaction(SIGINT, &action, NULL);
-  sigaction(SIGHUP, &action, NULL);
-#else // !HAVE_SIGACTION
-  signal(SIGPIPE, (RETSIGTYPE (*)(int)) signalhandler);
-  signal(SIGSEGV, (RETSIGTYPE (*)(int)) signalhandler);
-  signal(SIGFPE, (RETSIGTYPE (*)(int)) signalhandler);
-  signal(SIGTERM, (RETSIGTYPE (*)(int)) signalhandler);
-  signal(SIGINT, (RETSIGTYPE (*)(int)) signalhandler);
-  signal(SIGHUP, (RETSIGTYPE (*)(int)) signalhandler);
-#endif // HAVE_SIGACTION
-
-  parseCommandLine(argc, argv);
-
-  _display = XOpenDisplay(_display_name);
-  if (! _display) {
-    cout << "Connection to X server '" << _display_name << "' failed.\n";
-    return 1;
-  }
-  _root = RootWindow(_display, DefaultScreen(_display));
-  _xatom = new XAtom(_display);
+void epist::removeWindow(XWindow *window) {
+  _windows.erase(window->window());
+}
 
-  XSelectInput(_display, _root, PropertyChangeMask);
 
-  // find a window manager supporting NETWM, waiting for it to load if we must
-  while (! (_shutdown || findSupportingWM()));
-  if (! _shutdown) {
-    updateClientList();
-    updateActiveWindow();
-  }
-  
-  while (! _shutdown) {
-    if (XPending(_display)) {
-      XEvent e;
-      XNextEvent(_display, &e);
-      processEvent(e);
-    } else {
-      usleep(300);
-    }
-  }
+XWindow *epist::findWindow(Window window) const {
+  WindowLookup::const_iterator it = _windows.find(window);
+  if (it != _windows.end())
+    return it->second;
 
-  XSelectInput(_display, _root, None);
-  delete _xatom;
-  XCloseDisplay(_display);
   return 0;
 }
index 2f5d739..061e1f4 100644 (file)
@@ -27,11 +27,40 @@ extern "C" {
 #include <X11/Xlib.h>
 }
 
+#include <string>
+#include <map>
+
+#include "../../src/BaseDisplay.hh"
+
 class XAtom;
+class screen;
+class XWindow;
+
+class epist : public BaseDisplay {
+private:
+  std::string     _rc_file;
+  XAtom          *_xatom;
+  char          **_argv;
+
+  typedef std::vector<screen *> ScreenList;
+  ScreenList      _screens;
+
+  typedef std::map<Window, XWindow*> WindowLookup;
+  typedef WindowLookup::value_type WindowLookupPair;
+  WindowLookup    _windows;
+
+  virtual void process_event(XEvent *e);
+  virtual bool handleSignal(int sig);
+
+public:
+  epist(char **argv, char *display_name, char *rc_file);
+  virtual ~epist();
+
+  inline XAtom *xatom() { return _xatom; }
 
-extern bool _shutdown;
-extern Display *_display;
-extern Window _root;
-extern XAtom *_xatom;
+  void addWindow(XWindow *window);
+  void removeWindow(XWindow *window);
+  XWindow *findWindow(Window window) const;
+};
 
 #endif // __epist_hh
diff --git a/util/epist/main.cc b/util/epist/main.cc
new file mode 100644 (file)
index 0000000..9c2b576
--- /dev/null
@@ -0,0 +1,82 @@
+// -*- mode: C++; indent-tabs-mode: nil; -*-
+// main.cc for Epistory - a key handler for NETWM/EWMH window managers.
+// Copyright (c) 2002 - 2002 Ben Jansens <ben at orodu.net>
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the "Software"),
+// to deal in the Software without restriction, including without limitation
+// the rights to use, copy, modify, merge, publish, distribute, sublicense,
+// and/or sell copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+// DEALINGS IN THE SOFTWARE.
+
+#ifdef    HAVE_CONFIG_H
+#  include "../../config.h"
+#endif // HAVE_CONFIG_H
+
+extern "C" {
+#ifdef    HAVE_UNISTD_H
+#  include <sys/types.h>
+#  include <unistd.h>
+#endif // HAVE_UNISTD_H
+
+#ifdef    HAVE_STDIO_H
+#  include <stdio.h>
+#endif // HAVE_STDIO_H
+
+#ifdef    HAVE_STDLIB_H
+#  include <stdlib.h>
+#endif // HAVE_STDLIB_H
+}
+
+#include <iostream>
+#include <string>
+
+using std::cout;
+using std::endl;
+using std::string;
+
+#include "epist.hh"
+#include "../../src/i18n.hh"
+
+I18n i18n;
+
+int main(int argc, char **argv) {
+  i18n.openCatalog("openbox.cat");
+
+  // parse the command line
+  char *display_name = 0;
+  char *rc_file = 0;
+
+  for (int i = 1; i < argc; ++i) {
+    if (string(argv[i]) == "-display") {
+      if (++i >= argc) {
+        fprintf(stderr, i18n(mainSet, mainDISPLAYRequiresArg,
+                             "error: '-display' requires an argument\n"));
+        exit(1);
+      }
+      display_name = argv[i];
+    } else if (string(argv[i]) == "-rc") {
+      if (++i >= argc) {
+        fprintf(stderr, i18n(mainSet, mainRCRequiresArg,
+                             "error: '-rc' requires an argument\n"));
+        exit(1);
+      }
+      rc_file = argv[i];
+    }
+  }
+  
+  epist ep(argv, display_name, rc_file);
+  ep.eventLoop();
+  return 0;
+}
index 7ff8696..e69de29 100644 (file)
@@ -1,181 +0,0 @@
-// -*- mode: C++; indent-tabs-mode: nil; -*-
-// process.cc for Epistory - a key handler for NETWM/EWMH window managers.
-// Copyright (c) 2002 - 2002 Ben Jansens <ben at orodu.net>
-//
-// Permission is hereby granted, free of charge, to any person obtaining a
-// copy of this software and associated documentation files (the "Software"),
-// to deal in the Software without restriction, including without limitation
-// the rights to use, copy, modify, merge, publish, distribute, sublicense,
-// and/or sell copies of the Software, and to permit persons to whom the
-// Software is furnished to do so, subject to the following conditions:
-//
-// The above copyright notice and this permission notice shall be included in
-// all copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
-// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
-// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
-// DEALINGS IN THE SOFTWARE.
-
-#include "process.hh"
-#include "epist.hh"
-#include "window.hh"
-
-#ifdef    HAVE_CONFIG_H
-#  include "../../config.h"
-#endif // HAVE_CONFIG_H
-
-#include <iostream>
-
-using std::cout;
-using std::endl;
-using std::hex;
-using std::dec;
-
-#include "../../src/XAtom.hh"
-
-WindowList _clients;
-WindowList::iterator _active = _clients.end();
-
-
-XWindow *findWindow(const XEvent &e) {
-  WindowList::iterator it, end = _clients.end();
-  for (it = _clients.begin(); it != end; ++it)
-    if (**it == e.xany.window)
-      break;
-  if(it == end)
-    return 0;
-  return *it;
-}
-
-
-void processEvent(const XEvent &e) {
-  XWindow *window = 0;
-  if (e.xany.window != _root) {
-    window = findWindow(e);  // find the window
-    assert(window); // we caught an event for a window we don't know about!?
-  }
-
-  switch (e.type) {
-  case PropertyNotify:
-    if (e.xany.window == _root) {
-      // root window
-      if (e.xproperty.atom == _xatom->getAtom(XAtom::net_active_window))
-        updateActiveWindow();
-      if (e.xproperty.atom == _xatom->getAtom(XAtom::net_client_list)) {
-        // catch any window unmaps first
-        XEvent ev;
-        if (XCheckTypedWindowEvent(_display, e.xany.window,
-                                   DestroyNotify, &ev) ||
-            XCheckTypedWindowEvent(_display, e.xany.window,
-                                   UnmapNotify, &ev)) {
-          processEvent(ev);
-        }
-        
-        updateClientList();
-      }
-    } else {
-      // a client window
-      if (e.xproperty.atom == _xatom->getAtom(XAtom::net_wm_state))
-        window->updateState();
-      else if (e.xproperty.atom == _xatom->getAtom(XAtom::net_wm_desktop))
-        window->updateDesktop();
-      else if (e.xproperty.atom == _xatom->getAtom(XAtom::net_wm_name) ||
-               e.xproperty.atom == _xatom->getAtom(XAtom::wm_name))
-        window->updateTitle();
-      else if (e.xproperty.atom == _xatom->getAtom(XAtom::wm_class))
-        window->updateClass();
-    }
-    break;
-  case DestroyNotify:
-  case UnmapNotify:
-    window->setUnmapped(true);
-    break;
-  }
-}
-
-
-// do we want to add this window to our list?
-bool doAddWindow(Window window) {
-  Atom type;
-  if (! _xatom->getValue(window, XAtom::net_wm_window_type, XAtom::atom,
-                         type))
-    return True;
-
-  if (type == _xatom->getAtom(XAtom::net_wm_window_type_dock) ||
-      type == _xatom->getAtom(XAtom::net_wm_window_type_menu))
-    return False;
-
-  return True;
-}
-
-
-void updateClientList() {
-  WindowList::iterator insert_point = _active;
-  if (insert_point != _clients.end())
-    ++insert_point; // get to the item client the focused client
-  
-  // get the client list from the root window
-  Window *rootclients = 0;
-  unsigned long num = (unsigned) -1;
-  if (! _xatom->getValue(_root, XAtom::net_client_list, XAtom::window, num,
-                         &rootclients)) {
-    while (! _clients.empty()) {
-      delete _clients.front();
-      _clients.erase(_clients.begin());
-    }
-    if (rootclients) delete [] rootclients;
-    return;
-  }
-  
-  WindowList::iterator it, end = _clients.end();
-  unsigned long i;
-  
-  // insert new clients after the active window
-  for (i = 0; i < num; ++i) {
-    for (it = _clients.begin(); it != end; ++it)
-      if (**it == rootclients[i])
-        break;
-    if (it == end) {  // didn't already exist
-      if (doAddWindow(rootclients[i])) {
-        cout << "Added window: 0x" << hex << rootclients[i] << dec << endl;
-        _clients.insert(insert_point, new XWindow(rootclients[i]));
-      }
-    }
-  }
-
-  // remove clients that no longer exist
-  for (it = _clients.begin(); it != end;) {
-    WindowList::iterator it2 = it++;
-    for (i = 0; i < num; ++i)
-      if (**it2 == rootclients[i])
-        break;
-    if (i == num)  { // no longer exists
-      cout << "Removed window: 0x" << hex << (*it2)->window() << dec << endl;
-      delete *it2;
-      _clients.erase(it2);
-    }
-  }
-
-  if (rootclients) delete [] rootclients;
-}
-
-
-void updateActiveWindow() {
-  Window a = None;
-  _xatom->getValue(_root, XAtom::net_active_window, XAtom::window, a);
-  
-  WindowList::iterator it, end = _clients.end();
-  for (it = _clients.begin(); it != end; ++it) {
-    if (**it == a)
-      break;
-  }
-  _active = it;
-
-  cout << "Active window is now: ";
-  if (_active == _clients.end()) cout << "None\n";
-  else cout << "0x" << hex << (*_active)->window() << dec << endl;
-}
index e8fd369..e69de29 100644 (file)
@@ -1,34 +0,0 @@
-// -*- mode: C++; indent-tabs-mode: nil; -*-
-// process.hh for Epistory - a key handler for NETWM/EWMH window managers.
-// Copyright (c) 2002 - 2002 Ben Jansens <ben at orodu.net>
-//
-// Permission is hereby granted, free of charge, to any person obtaining a
-// copy of this software and associated documentation files (the "Software"),
-// to deal in the Software without restriction, including without limitation
-// the rights to use, copy, modify, merge, publish, distribute, sublicense,
-// and/or sell copies of the Software, and to permit persons to whom the
-// Software is furnished to do so, subject to the following conditions:
-//
-// The above copyright notice and this permission notice shall be included in
-// all copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
-// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
-// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
-// DEALINGS IN THE SOFTWARE.
-
-#ifndef   __process_hh
-#define   __process_hh
-
-extern "C" {
-#include "X11/Xlib.h"
-}
-
-void processEvent(const XEvent &e);
-void updateClientList();
-void updateActiveWindow();
-
-#endif // __process_hh
diff --git a/util/epist/screen.cc b/util/epist/screen.cc
new file mode 100644 (file)
index 0000000..ad2b177
--- /dev/null
@@ -0,0 +1,240 @@
+// -*- mode: C++; indent-tabs-mode: nil; -*-
+// screen.cc for Epistory - a key handler for NETWM/EWMH window managers.
+// Copyright (c) 2002 - 2002 Ben Jansens <ben at orodu.net>
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the "Software"),
+// to deal in the Software without restriction, including without limitation
+// the rights to use, copy, modify, merge, publish, distribute, sublicense,
+// and/or sell copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+// DEALINGS IN THE SOFTWARE.
+
+#ifdef    HAVE_CONFIG_H
+#  include "../../config.h"
+#endif // HAVE_CONFIG_H
+
+extern "C" {
+#ifdef    HAVE_UNISTD_H
+#  include <sys/types.h>
+#  include <unistd.h>
+#endif // HAVE_UNISTD_H
+}
+
+#include <iostream>
+#include <string>
+
+using std::cout;
+using std::endl;
+using std::hex;
+using std::dec;
+using std::string;
+
+#include "../../src/XAtom.hh"
+#include "screen.hh"
+#include "epist.hh"
+
+
+screen::screen(epist *epist, int number) {
+  _epist = epist;
+  _xatom = _epist->xatom();
+  _number = number;
+  _active = _clients.end();
+  _root = RootWindow(_epist->getXDisplay(), _number);
+  
+  // find a window manager supporting NETWM, waiting for it to load if we must
+  int count = 20;  // try for 20 seconds
+  _managed = false;
+  while (! (_epist->doShutdown() || _managed || count <= 0)) {
+    if (! (_managed = findSupportingWM()))
+      usleep(1000);
+    --count;
+  }
+  if (_managed)
+    cout << "Found compatible window manager '" << _wm_name << "' for screen "
+      << _number << ".\n";
+  else {
+    cout << "Unable to find a compatible window manager for screen " <<
+      _number << ".\n";
+    return;
+  }
+  XSelectInput(_epist->getXDisplay(), _root, PropertyChangeMask);
+    
+  updateClientList();
+  updateActiveWindow();
+}
+
+
+screen::~screen() {
+  if (_managed)
+    XSelectInput(_epist->getXDisplay(), _root, None);
+}
+
+
+bool screen::findSupportingWM() {
+  Window support_win;
+  if (! _xatom->getValue(_root, XAtom::net_supporting_wm_check, XAtom::window,
+                         support_win) || support_win == None)
+    return false;
+
+  string title;
+  _xatom->getValue(support_win, XAtom::net_wm_name, XAtom::utf8, title);
+  _wm_name = title;
+  return true;
+}
+
+
+XWindow *screen::findWindow(const XEvent &e) const {
+  assert(_managed);
+
+  WindowList::const_iterator it, end = _clients.end();
+  for (it = _clients.begin(); it != end; ++it)
+    if (**it == e.xany.window)
+      break;
+  if(it == end)
+    return 0;
+  return *it;
+}
+
+
+void screen::processEvent(const XEvent &e) {
+  assert(_managed);
+  assert(e.xany.window == _root);
+
+  XWindow *window = 0;
+  if (e.xany.window != _root) {
+    window = findWindow(e);  // find the window
+    assert(window); // we caught an event for a window we don't know about!?
+  }
+
+  switch (e.type) {
+  case PropertyNotify:
+    // root window
+    if (e.xproperty.atom == _xatom->getAtom(XAtom::net_active_window))
+      updateActiveWindow();
+    if (e.xproperty.atom == _xatom->getAtom(XAtom::net_client_list)) {
+      // catch any window unmaps first
+      XEvent ev;
+      if (XCheckTypedWindowEvent(_epist->getXDisplay(), e.xany.window,
+                                 DestroyNotify, &ev) ||
+          XCheckTypedWindowEvent(_epist->getXDisplay(), e.xany.window,
+                                 UnmapNotify, &ev)) {
+        processEvent(ev);
+      }
+
+      updateClientList();
+    }
+    break;
+  case KeyPress:
+    break;
+  }
+}
+
+
+// do we want to add this window to our list?
+bool screen::doAddWindow(Window window) const {
+  assert(_managed);
+
+  Atom type;
+  if (! _xatom->getValue(window, XAtom::net_wm_window_type, XAtom::atom,
+                         type))
+    return True;
+
+  if (type == _xatom->getAtom(XAtom::net_wm_window_type_dock) ||
+      type == _xatom->getAtom(XAtom::net_wm_window_type_menu))
+    return False;
+
+  return True;
+}
+
+
+void screen::updateClientList() {
+  assert(_managed);
+
+  WindowList::iterator insert_point = _active;
+  if (insert_point != _clients.end())
+    ++insert_point; // get to the item client the focused client
+  
+  // get the client list from the root window
+  Window *rootclients = 0;
+  unsigned long num = (unsigned) -1;
+  if (! _xatom->getValue(_root, XAtom::net_client_list, XAtom::window, num,
+                         &rootclients)) {
+    while (! _clients.empty()) {
+      delete _clients.front();
+      _clients.erase(_clients.begin());
+    }
+    if (rootclients) delete [] rootclients;
+    return;
+  }
+  
+  WindowList::iterator it, end = _clients.end();
+  unsigned long i;
+  
+  // insert new clients after the active window
+  for (i = 0; i < num; ++i) {
+    for (it = _clients.begin(); it != end; ++it)
+      if (**it == rootclients[i])
+        break;
+    if (it == end) {  // didn't already exist
+      if (doAddWindow(rootclients[i])) {
+        cout << "Added window: 0x" << hex << rootclients[i] << dec << endl;
+        _clients.insert(insert_point, new XWindow(_epist, rootclients[i]));
+      }
+    }
+  }
+
+  // remove clients that no longer exist
+  for (it = _clients.begin(); it != end;) {
+    WindowList::iterator it2 = it++;
+    for (i = 0; i < num; ++i)
+      if (**it2 == rootclients[i])
+        break;
+    if (i == num)  { // no longer exists
+      cout << "Removed window: 0x" << hex << (*it2)->window() << dec << endl;
+      delete *it2;
+      _clients.erase(it2);
+    }
+  }
+
+  if (rootclients) delete [] rootclients;
+}
+
+
+void screen::updateActiveWindow() {
+  assert(_managed);
+
+  Window a = None;
+  _xatom->getValue(_root, XAtom::net_active_window, XAtom::window, a);
+  
+  WindowList::iterator it, end = _clients.end();
+  for (it = _clients.begin(); it != end; ++it) {
+    if (**it == a)
+      break;
+  }
+  _active = it;
+
+  cout << "Active window is now: ";
+  if (_active == _clients.end()) cout << "None\n";
+  else cout << "0x" << hex << (*_active)->window() << dec << endl;
+}
+
+/*
+ * use this when execing a command to have it on the right screen
+      string dtmp = (string)"DISPLAY=" + display_name;
+      if (putenv(const_cast<char*>(dtmp.c_str()))) {
+        cout << "warning: couldn't set environment variable 'DISPLAY'\n";
+        perror("putenv()");
+      }
+ */
diff --git a/util/epist/screen.hh b/util/epist/screen.hh
new file mode 100644 (file)
index 0000000..54551aa
--- /dev/null
@@ -0,0 +1,68 @@
+// -*- mode: C++; indent-tabs-mode: nil; -*-
+// screen.hh for Epistory - a key handler for NETWM/EWMH window managers.
+// Copyright (c) 2002 - 2002 Ben Jansens <ben at orodu.net>
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the "Software"),
+// to deal in the Software without restriction, including without limitation
+// the rights to use, copy, modify, merge, publish, distribute, sublicense,
+// and/or sell copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+// DEALINGS IN THE SOFTWARE.
+
+#ifndef   __screen_hh
+#define   __screen_hh
+
+extern "C" {
+#include "X11/Xlib.h"
+}
+
+#include <vector>
+
+#include "window.hh"
+
+class epist;
+class screen;
+class XAtom;
+
+class screen {
+  epist *_epist;
+  XAtom *_xatom;
+  int _number;
+  Window _root;
+
+  std::string _wm_name;
+  
+  WindowList _clients;
+  WindowList::iterator _active;
+
+  bool _managed;
+
+  XWindow *findWindow(const XEvent &e) const;
+  void updateClientList();
+  void updateActiveWindow();
+  bool doAddWindow(Window window) const;
+  bool findSupportingWM();
+
+public:
+  screen(epist *epist, int number);
+  virtual ~screen();
+  
+  inline Window rootWindow() const { return _root; }
+  inline bool managed() const { return _managed; }
+  
+  void processEvent(const XEvent &e);
+};
+
+#endif // __screen_hh
+
index 6208728..691dccd 100644 (file)
 #  include "../../config.h"
 #endif // HAVE_CONFIG_H
 
-#include "window.hh"
-#include "epist.hh"
-#include "../../src/XAtom.hh"
-
 #include <iostream>
 
 using std::cout;
@@ -35,20 +31,30 @@ using std::endl;
 using std::hex;
 using std::dec;
 
-XWindow::XWindow(Window window) : _window(window) {
+#include "window.hh"
+#include "epist.hh"
+#include "../../src/XAtom.hh"
+
+XWindow::XWindow(epist *epist, Window window)
+  : _epist(epist), _xatom(epist->xatom()), _window(window) {
+
   _unmapped = false;
 
-  XSelectInput(_display, _window, PropertyChangeMask | StructureNotifyMask);
+  XSelectInput(_epist->getXDisplay(), _window,
+               PropertyChangeMask | StructureNotifyMask);
   updateState();
   updateDesktop();
   updateTitle();
   updateClass();
+
+  _epist->addWindow(this);
 }
 
 
 XWindow::~XWindow() {
   if (! _unmapped)
-    XSelectInput(_display, _window, None);
+    XSelectInput(_epist->getXDisplay(), _window, None);
+  _epist->removeWindow(this);
 }
 
 
@@ -110,3 +116,27 @@ void XWindow::updateClass() {
   if (num > 0) _app_name = v[0];
   if (num > 1) _app_class = v[1];
 }
+
+
+void XWindow::processEvent(const XEvent &e) {
+  assert(e.xany.window == _window);
+
+  switch (e.type) {
+  case PropertyNotify:
+    // a client window
+    if (e.xproperty.atom == _xatom->getAtom(XAtom::net_wm_state))
+      updateState();
+    else if (e.xproperty.atom == _xatom->getAtom(XAtom::net_wm_desktop))
+      updateDesktop();
+    else if (e.xproperty.atom == _xatom->getAtom(XAtom::net_wm_name) ||
+             e.xproperty.atom == _xatom->getAtom(XAtom::wm_name))
+      updateTitle();
+    else if (e.xproperty.atom == _xatom->getAtom(XAtom::wm_class))
+      updateClass();
+    break;
+  case DestroyNotify:
+  case UnmapNotify:
+    _unmapped = true;
+    break;
+  }
+}
index c83f020..636e90b 100644 (file)
@@ -30,12 +30,16 @@ extern "C" {
 #include <list>
 #include <string>
 
+class epist;
 class XWindow;
+class XAtom;
 
 typedef std::list<XWindow *> WindowList;
 
 class XWindow {
 private:
+  epist *_epist;
+  XAtom *_xatom;
   Window _window;
   
   unsigned int _desktop;
@@ -51,8 +55,13 @@ private:
 
   bool _unmapped;
 
+  void updateState();
+  void updateDesktop();
+  void updateTitle();
+  void updateClass();
+
 public:
-  XWindow(Window window);
+  XWindow(epist *epist, Window window);
   virtual ~XWindow();
 
   inline Window window() const { return _window; }
@@ -67,12 +76,7 @@ public:
   inline bool maxVert() const { return _max_vert; }
   inline bool maxHorz() const { return _max_horz; }
 
-  inline void setUnmapped(bool u) { _unmapped = u; }
-
-  void updateState();
-  void updateDesktop();
-  void updateTitle();
-  void updateClass();
+  void processEvent(const XEvent &e);
 
   bool operator == (const XWindow &w) const { return w._window == _window; }
   bool operator == (const Window &w) const { return w == _window; }