From 24a1e215d1f8d2ff1674847278a15336d4b671b6 Mon Sep 17 00:00:00 2001 From: Dana Jansens Date: Fri, 12 Jul 2002 16:29:59 +0000 Subject: [PATCH] epist now based on the BaseDisplay. has the ability to be multiscreen! --- util/epist/Makefile.am | 18 +++- util/epist/epist.cc | 170 +++++++++++------------------ util/epist/epist.hh | 37 ++++++- util/epist/main.cc | 82 ++++++++++++++ util/epist/process.cc | 181 ------------------------------- util/epist/process.hh | 34 ------ util/epist/screen.cc | 240 +++++++++++++++++++++++++++++++++++++++++ util/epist/screen.hh | 68 ++++++++++++ util/epist/window.cc | 44 ++++++-- util/epist/window.hh | 18 ++-- 10 files changed, 550 insertions(+), 342 deletions(-) create mode 100644 util/epist/main.cc create mode 100644 util/epist/screen.cc create mode 100644 util/epist/screen.hh diff --git a/util/epist/Makefile.am b/util/epist/Makefile.am index ee91b551..8d3f22c5 100644 --- a/util/epist/Makefile.am +++ b/util/epist/Makefile.am @@ -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 diff --git a/util/epist/epist.cc b/util/epist/epist.cc index 63a31920..474d8fe8 100644 --- a/util/epist/epist.cc +++ b/util/epist/epist.cc @@ -30,10 +30,6 @@ extern "C" { # include #endif // HAVE_UNISTD_H -#ifdef HAVE_STDIO_H -# include -#endif // HAVE_STDIO_H - #ifdef HAVE_STDLIB_H # include #endif // HAVE_STDLIB_H @@ -42,9 +38,9 @@ extern "C" { # include #endif // HAVE_SIGNAL_H -#ifdef HAVE_LIBGEN_H +/*#ifdef HAVE_LIBGEN_H # include -#endif // HAVE_LIBGEN_H +#endif // HAVE_LIBGEN_H*/ } #include @@ -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(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; } diff --git a/util/epist/epist.hh b/util/epist/epist.hh index 2f5d7399..061e1f4d 100644 --- a/util/epist/epist.hh +++ b/util/epist/epist.hh @@ -27,11 +27,40 @@ extern "C" { #include } +#include +#include + +#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 ScreenList; + ScreenList _screens; + + typedef std::map 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 index 00000000..9c2b576f --- /dev/null +++ b/util/epist/main.cc @@ -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 +// +// 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 +# include +#endif // HAVE_UNISTD_H + +#ifdef HAVE_STDIO_H +# include +#endif // HAVE_STDIO_H + +#ifdef HAVE_STDLIB_H +# include +#endif // HAVE_STDLIB_H +} + +#include +#include + +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; +} diff --git a/util/epist/process.cc b/util/epist/process.cc index 7ff86963..e69de29b 100644 --- a/util/epist/process.cc +++ b/util/epist/process.cc @@ -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 -// -// 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 - -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; -} diff --git a/util/epist/process.hh b/util/epist/process.hh index e8fd369d..e69de29b 100644 --- a/util/epist/process.hh +++ b/util/epist/process.hh @@ -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 -// -// 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 index 00000000..ad2b1772 --- /dev/null +++ b/util/epist/screen.cc @@ -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 +// +// 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 +# include +#endif // HAVE_UNISTD_H +} + +#include +#include + +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(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 index 00000000..54551aa3 --- /dev/null +++ b/util/epist/screen.hh @@ -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 +// +// 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 + +#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 + diff --git a/util/epist/window.cc b/util/epist/window.cc index 62087283..691dccd8 100644 --- a/util/epist/window.cc +++ b/util/epist/window.cc @@ -24,10 +24,6 @@ # include "../../config.h" #endif // HAVE_CONFIG_H -#include "window.hh" -#include "epist.hh" -#include "../../src/XAtom.hh" - #include 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; + } +} diff --git a/util/epist/window.hh b/util/epist/window.hh index c83f020c..636e90ba 100644 --- a/util/epist/window.hh +++ b/util/epist/window.hh @@ -30,12 +30,16 @@ extern "C" { #include #include +class epist; class XWindow; +class XAtom; typedef std::list 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; } -- 2.39.2