From 4c1a242968dff12e504f281224819b7cd3850a04 Mon Sep 17 00:00:00 2001
From: markt <markt>
Date: Sun, 4 Mar 2007 17:47:37 +0000
Subject: moved some code around (regarding event handling) in preparation for
 upcoming features

---
 src/FbTk/EventHandler.hh |  4 +--
 src/FbTk/EventManager.cc | 22 +++++++++++--
 src/FbTk/EventManager.hh |  7 ++++-
 src/FocusControl.cc      |  4 ++-
 src/Screen.cc            | 71 +++++++++++++++++++++++++++++++++++-------
 src/Screen.hh            | 16 ++++++++--
 src/WorkspaceCmd.cc      | 56 ++++-----------------------------
 src/fluxbox.cc           | 80 ------------------------------------------------
 src/fluxbox.hh           |  8 -----
 9 files changed, 110 insertions(+), 158 deletions(-)

diff --git a/src/FbTk/EventHandler.hh b/src/FbTk/EventHandler.hh
index 3d2e545..45c7a2a 100644
--- a/src/FbTk/EventHandler.hh
+++ b/src/FbTk/EventHandler.hh
@@ -54,11 +54,11 @@ public:
     virtual void exposeEvent(XExposeEvent &) { }
     virtual void motionNotifyEvent(XMotionEvent &) { }
     virtual void keyPressEvent(XKeyEvent &) { }
-#ifdef NOT_USED
     virtual void keyReleaseEvent(XKeyEvent &) { }
-#endif
     virtual void leaveNotifyEvent(XCrossingEvent &) { }
     virtual void enterNotifyEvent(XCrossingEvent &) { }
+
+    virtual void notifyUngrabKeyboard() { }
 };
 
 } // end namespace FbTk
diff --git a/src/FbTk/EventManager.cc b/src/FbTk/EventManager.cc
index 02259ac..fd26950 100644
--- a/src/FbTk/EventManager.cc
+++ b/src/FbTk/EventManager.cc
@@ -66,6 +66,26 @@ EventHandler *EventManager::find(Window win) {
     return m_eventhandlers[win];
 }
 
+bool EventManager::grabKeyboard(EventHandler &ev, Window win) {
+    if (m_grabbing_keyboard)
+        ungrabKeyboard();
+
+    int ret = XGrabKeyboard(App::instance()->display(), win, False,
+                            GrabModeAsync, GrabModeAsync, CurrentTime);
+
+    if (ret == Success) {
+        m_grabbing_keyboard = &ev;
+        return true;
+    }
+    return false;
+}
+
+void EventManager::ungrabKeyboard() {
+    XUngrabKeyboard(App::instance()->display(), CurrentTime);
+    if (m_grabbing_keyboard)
+        m_grabbing_keyboard->notifyUngrabKeyboard();
+    m_grabbing_keyboard = 0;
+}
 
 Window EventManager::getEventWindow(XEvent &ev) {
     // we only have cases for events that differ from xany
@@ -156,9 +176,7 @@ void EventManager::dispatch(Window win, XEvent &ev, bool parent) {
         evhand->keyPressEvent(ev.xkey);
     break;
     case KeyRelease:
-#ifdef NOT_USED
         evhand->keyReleaseEvent(ev.xkey);
-#endif
     break;
     case ButtonPress:
         evhand->buttonPressEvent(ev.xbutton);
diff --git a/src/FbTk/EventManager.hh b/src/FbTk/EventManager.hh
index 5bbaa00..149649b 100644
--- a/src/FbTk/EventManager.hh
+++ b/src/FbTk/EventManager.hh
@@ -43,6 +43,10 @@ public:
     void add(EventHandler &ev, Window win) { registerEventHandler(ev, win); }
     void remove(Window win) { unregisterEventHandler(win); }
 
+    bool grabKeyboard(EventHandler &ev, Window win);
+    void ungrabKeyboard();
+    EventHandler *grabbingKeyboard() { return m_grabbing_keyboard; }
+
     EventHandler *find(Window win);
 
     // Some events have the parent window as the xany.window
@@ -53,13 +57,14 @@ public:
     void unregisterEventHandler(Window win);
 
 private:
-    EventManager() { }
+    EventManager(): m_grabbing_keyboard(0) { }
     ~EventManager();
     void dispatch(Window win, XEvent &event, bool parent = false);
 
     typedef std::map<Window, EventHandler *> EventHandlerMap;
     EventHandlerMap m_eventhandlers;
     EventHandlerMap m_parent;
+    EventHandler *m_grabbing_keyboard;
 };
 
 } //end namespace FbTk
diff --git a/src/FocusControl.cc b/src/FocusControl.cc
index f4c8cdf..e494d8f 100644
--- a/src/FocusControl.cc
+++ b/src/FocusControl.cc
@@ -30,6 +30,8 @@
 #include "fluxbox.hh"
 #include "FbWinFrameTheme.hh"
 
+#include "FbTk/EventManager.hh"
+
 #include <string>
 #include <iostream>
 
@@ -82,7 +84,7 @@ bool doSkipWindow(const WinClient &winclient, int opts) {
 void FocusControl::cycleFocus(FocusedWindows *window_list, int opts, bool cycle_reverse) {
 
     if (!m_cycling_list) {
-        if (&m_screen == Fluxbox::instance()->watchingScreen())
+        if (&m_screen == FbTk::EventManager::instance()->grabbingKeyboard())
             // only set this when we're waiting for modifiers
             m_cycling_list = window_list;
         m_was_iconic = 0;
diff --git a/src/Screen.cc b/src/Screen.cc
index b676a8b..3dfe324 100644
--- a/src/Screen.cc
+++ b/src/Screen.cc
@@ -28,6 +28,7 @@
 #include "Screen.hh"
 
 #include "fluxbox.hh"
+#include "Keys.hh"
 #include "Window.hh"
 #include "Workspace.hh"
 #include "Netizen.hh"
@@ -364,6 +365,7 @@ BScreen::BScreen(FbTk::ResourceManager &rm,
     m_altname(altscreenname),
     m_focus_control(new FocusControl(*this)),
     m_placement_strategy(new ScreenPlacement(*this)),
+    m_cycling(false),
     m_xinerama_headinfo(0),
     m_restart(false),
     m_shutdown(false) {
@@ -416,7 +418,8 @@ BScreen::BScreen(FbTk::ResourceManager &rm,
             screenNumber(), XVisualIDFromVisual(rootWindow().visual()),
             rootWindow().depth());
 
-
+    FbTk::EventManager *evm = FbTk::EventManager::instance();
+    evm->add(*this, rootWindow());
     rootWindow().setCursor(XCreateFontCursor(disp, XC_left_ptr));
 
     // load this screens resources
@@ -538,6 +541,9 @@ BScreen::~BScreen() {
     if (! managed)
         return;
 
+    FbTk::EventManager *evm = FbTk::EventManager::instance();
+    evm->remove(rootWindow());
+
     if (m_rootmenu.get() != 0)
         m_rootmenu->removeAll();
 
@@ -780,6 +786,59 @@ void BScreen::update(FbTk::Subject *subj) {
 
 }
 
+void BScreen::keyPressEvent(XKeyEvent &ke) {
+    Fluxbox::instance()->keys()->doAction(ke.type, ke.state, ke.keycode);
+}
+
+void BScreen::keyReleaseEvent(XKeyEvent &ke) {
+    if (!m_cycling)
+        return;
+
+    unsigned int state = FbTk::KeyUtil::instance().cleanMods(ke.state);
+    state &= ~FbTk::KeyUtil::instance().keycodeToModmask(ke.keycode);
+
+    if (!state) // all modifiers were released
+        FbTk::EventManager::instance()->ungrabKeyboard();
+}
+
+void BScreen::buttonPressEvent(XButtonEvent &be) {
+    if (be.button == 1 && !isRootColormapInstalled())
+        imageControl().installRootColormap();
+
+    Keys *keys = Fluxbox::instance()->keys();
+    keys->doAction(be.type, be.state, be.button);
+}
+
+void BScreen::notifyUngrabKeyboard() {
+    m_cycling = false;
+    focusControl().stopCyclingFocus();
+}
+
+void BScreen::cycleFocus(int options, bool reverse) {
+    // get modifiers from event that causes this for focus order cycling
+    XEvent ev = Fluxbox::instance()->lastEvent();
+    unsigned int mods = 0;
+    if (ev.type == KeyPress)
+        mods = FbTk::KeyUtil::instance().cleanMods(ev.xkey.state);
+    else if (ev.type == ButtonPress)
+        mods = FbTk::KeyUtil::instance().cleanMods(ev.xbutton.state);
+
+    if (!m_cycling && mods) {
+        m_cycling = true;
+        FbTk::EventManager::instance()->grabKeyboard(*this, rootWindow().window());
+    }
+
+    if (mods == 0) // can't stacked cycle unless there is a mod to grab
+        options |= FocusControl::CYCLELINEAR;
+
+    FocusControl::FocusedWindows *win_list =
+        (options & FocusControl::CYCLELINEAR) ?
+            &focusControl().creationOrderList() :
+            &focusControl().focusedOrderList();
+
+    focusControl().cycleFocus(win_list, options, reverse);
+}
+
 FbTk::Menu *BScreen::createMenu(const string &label) {
     FbTk::Menu *menu = new FbMenu(menuTheme(),
                                   imageControl(),
@@ -2054,16 +2113,6 @@ void BScreen::renderPosWindow() {
 
 }
 
-
-
-
-/**
-   Called when a set of watched modifiers has been released
-*/
-void BScreen::notifyReleasedKeys() {
-    focusControl().stopCyclingFocus();
-}
-
 void BScreen::updateSize() {
     // force update geometry
     rootWindow().updateGeometry();
diff --git a/src/Screen.hh b/src/Screen.hh
index de1dc78..8694f6d 100644
--- a/src/Screen.hh
+++ b/src/Screen.hh
@@ -32,6 +32,8 @@
 #include "MenuTheme.hh"
 #include "PlacementStrategy.hh"
 
+#include "FbTk/EventHandler.hh"
+#include "FbTk/TypeAhead.hh"
 #include "FbTk/Resource.hh"
 #include "FbTk/Subject.hh"
 #include "FbTk/MultLayers.hh"
@@ -78,7 +80,8 @@ class Subject;
 /**
  Create workspaces, handles switching between workspaces and windows
  */
-class BScreen : public FbTk::Observer, private FbTk::NotCopyable {
+class BScreen: public FbTk::EventHandler, public FbTk::Observer,
+               private FbTk::NotCopyable {
 public:
     /// a window becomes active / focussed on a different workspace
     enum FollowModel { 
@@ -209,6 +212,13 @@ public:
 
     void update(FbTk::Subject *subj);
 
+    void keyPressEvent(XKeyEvent &ke);
+    void keyReleaseEvent(XKeyEvent &ke);
+    void buttonPressEvent(XButtonEvent &be);
+    void notifyUngrabKeyboard();
+
+    void cycleFocus(int opts, bool reverse);
+
     FbTk::Menu *createMenu(const std::string &label);
     FbTk::Menu *createToggleMenu(const std::string &label);
     void hideMenus();
@@ -294,8 +304,6 @@ public:
     void showGeometry(int width, int height);
     void hideGeometry();
 
-    void notifyReleasedKeys();
-
     void setLayer(FbTk::XLayerItem &item, int layernum);
     // remove? no, items are never removed from their layer until they die
 
@@ -477,6 +485,8 @@ private:
     typedef std::map<Window, WinClient *> Groupables;
     Groupables m_expecting_groups;
 
+    bool m_cycling;
+
     // Xinerama related private data
     bool m_xinerama_avail;
     int m_xinerama_num_heads;
diff --git a/src/WorkspaceCmd.cc b/src/WorkspaceCmd.cc
index 7d384aa..0cbf5b9 100644
--- a/src/WorkspaceCmd.cc
+++ b/src/WorkspaceCmd.cc
@@ -42,59 +42,15 @@
 #include <functional>
 
 void NextWindowCmd::execute() {
-    Fluxbox *fb = Fluxbox::instance();
-    BScreen *screen = fb->keyScreen();
-    if (screen != 0) {
-        // get modifiers from event that causes this for focus order cycling
-        unsigned int mods = 0;
-        XEvent ev = fb->lastEvent();
-        if (ev.type == KeyPress) {
-            mods = FbTk::KeyUtil::instance().cleanMods(ev.xkey.state);
-        } else if (ev.type == ButtonPress) {
-            mods = FbTk::KeyUtil::instance().cleanMods(ev.xbutton.state);
-        }
-        int options = m_option;
-        if (mods == 0) // can't stacked cycle unless there is a mod to grab
-            options |= FocusControl::CYCLELINEAR;
-        else
-            // set a watch for the release of exactly these modifiers
-            fb->watchKeyRelease(*screen, mods);
-
-        FocusControl::FocusedWindows *win_list =
-            (options & FocusControl::CYCLELINEAR) ?
-                &screen->focusControl().creationOrderList() :
-                &screen->focusControl().focusedOrderList();
-        
-        screen->focusControl().cycleFocus(win_list, m_option);
-    }
+    BScreen *screen = Fluxbox::instance()->keyScreen();
+    if (screen != 0)
+        screen->cycleFocus(m_option, false);
 }
 
 void PrevWindowCmd::execute() {
-    Fluxbox *fb = Fluxbox::instance();
-    BScreen *screen = fb->keyScreen();
-    if (screen != 0) {
-        // get modifiers from event that causes this for focus order cycling
-        unsigned int mods = 0;
-        XEvent ev = fb->lastEvent();
-        if (ev.type == KeyPress) {
-            mods = FbTk::KeyUtil::instance().cleanMods(ev.xkey.state);
-        } else if (ev.type == ButtonPress) {
-            mods = FbTk::KeyUtil::instance().cleanMods(ev.xbutton.state);
-        }
-        int options = m_option;
-        if (mods == 0) // can't stacked cycle unless there is a mod to grab
-            options |= FocusControl::CYCLELINEAR;
-        else
-            // set a watch for the release of exactly these modifiers
-            fb->watchKeyRelease(*screen, mods);
-
-        FocusControl::FocusedWindows *win_list =
-            (options & FocusControl::CYCLELINEAR) ?
-                &screen->focusControl().creationOrderList() :
-                &screen->focusControl().focusedOrderList();
-        
-        screen->focusControl().cycleFocus(win_list, m_option, true);
-    }
+    BScreen *screen = Fluxbox::instance()->keyScreen();
+    if (screen != 0)
+        screen->cycleFocus(m_option, true);
 }
 
 void DirFocusCmd::execute() {
diff --git a/src/fluxbox.cc b/src/fluxbox.cc
index c71e2f5..e4c68bf 100644
--- a/src/fluxbox.cc
+++ b/src/fluxbox.cc
@@ -228,7 +228,6 @@ Fluxbox::Fluxbox(int argc, char **argv, const char *dpy_name, const char *rcfile
       m_masked_window(0),
       m_mousescreen(0),
       m_keyscreen(0),
-      m_watching_screen(0), m_watch_keyrelease(0),
       m_last_time(0),
       m_masked(0),
       m_rc_file(rcfilename ? rcfilename : ""),
@@ -746,7 +745,6 @@ void Fluxbox::handleEvent(XEvent * const e) {
     switch (e->type) {
     case ButtonRelease:
     case ButtonPress:
-        handleButtonEvent(e->xbutton);
         break;
     case ConfigureRequest: {
 
@@ -894,7 +892,6 @@ void Fluxbox::handleEvent(XEvent * const e) {
         break;
     case KeyRelease:
     case KeyPress:
-        handleKeyEvent(e->xkey);
 	break;
     case ColormapNotify: {
         BScreen *screen = searchScreen(e->xcolormap.window);
@@ -958,20 +955,6 @@ void Fluxbox::handleEvent(XEvent * const e) {
     }
 }
 
-void Fluxbox::handleButtonEvent(XButtonEvent &be) {
-    m_last_time = be.time;
-
-    BScreen *screen = searchScreen(be.window);
-    if (be.type == ButtonRelease || !screen)
-        // no bindings for this type yet
-        return;
-
-    if (be.button == 1 && !screen->isRootColormapInstalled())
-        screen->imageControl().installRootColormap();
-
-    m_key->doAction(be.type, be.state, be.button);
-}
-
 void Fluxbox::handleUnmapNotify(XUnmapEvent &ue) {
 
     BScreen *screen = searchScreen(ue.event);
@@ -1092,47 +1075,6 @@ void Fluxbox::handleClientMessage(XClientMessageEvent &ce) {
     }
 }
 
-/**
- Handles KeyRelease and KeyPress events
-*/
-void Fluxbox::handleKeyEvent(XKeyEvent &ke) {
-
-    if (keyScreen() == 0 || mouseScreen() == 0)
-        return;
-
-    switch (ke.type) {
-    case KeyPress:
-        m_key->doAction(ke.type, ke.state, ke.keycode);
-        break;
-    case KeyRelease: {
-        // we ignore most key releases unless we need to use
-        // a release to stop something (e.g. window cycling).
-
-        // we notify if _all_ of the watched modifiers are released
-        if (m_watching_screen && m_watch_keyrelease) {
-            // mask the mod of the released key out
-            // won't mask anything if it isn't a mod
-            unsigned int state = FbTk::KeyUtil::instance().isolateModifierMask(ke.state);
-            state &= ~FbTk::KeyUtil::instance().keycodeToModmask(ke.keycode);
-
-            if ((m_watch_keyrelease & state) == 0) {
-
-                m_watching_screen->notifyReleasedKeys();
-                XUngrabKeyboard(FbTk::App::instance()->display(), CurrentTime);
-
-                // once they are released, we drop the watch
-                m_watching_screen = 0;
-                m_watch_keyrelease = 0;
-            }
-        }
-
-        break;
-    }
-    default:
-        break;
-    }
-}
-
 /// handle system signals
 void Fluxbox::handleSignal(int signum) {
     _FB_USES_NLS;
@@ -1810,28 +1752,6 @@ void Fluxbox::updateFocusedWindow(BScreen *screen, BScreen *old_screen) {
     }
 }
 
-void Fluxbox::watchKeyRelease(BScreen &screen, unsigned int mods) {
-
-    if (mods == 0) {
-        cerr<<"WARNING: attempt to grab without modifiers!"<<endl;
-        return;
-    }
-    // just make sure we are saving the mods with any other flags (xkb)
-    m_watch_keyrelease = FbTk::KeyUtil::instance().isolateModifierMask(mods);
-
-    if (m_watching_screen == &screen)
-        return;
-    if (m_watching_screen)
-        m_watching_screen->focusControl().stopCyclingFocus();
-    m_watching_screen = &screen;
-
-    // TODO: it's possible (and happens to me sometimes) for the mods to be
-    // released before we grab the keyboard -- not sure of a good way to fix it
-    XGrabKeyboard(FbTk::App::instance()->display(),
-                  screen.rootWindow().window(), True,
-                  GrabModeAsync, GrabModeAsync, CurrentTime);
-}
-
 void Fluxbox::updateFrameExtents(FluxboxWindow &win) {
     AtomHandlerContainerIt it = m_atomhandler.begin();
     AtomHandlerContainerIt it_end = m_atomhandler.end();
diff --git a/src/fluxbox.hh b/src/fluxbox.hh
index 5613caa..66fdff5 100644
--- a/src/fluxbox.hh
+++ b/src/fluxbox.hh
@@ -141,8 +141,6 @@ public:
     void maskWindowEvents(Window w, FluxboxWindow *bw)
         { m_masked = w; m_masked_window = bw; }
 
-    void watchKeyRelease(BScreen &screen, unsigned int mods);
-
     void shutdown();
     void load_rc(BScreen &scr);
     void saveStyleFilename(const char *val) { m_rc_stylefile = (val == 0 ? "" : val); }
@@ -203,8 +201,6 @@ public:
     BScreen *mouseScreen() { return m_mousescreen; }
     // screen of window that last key event (i.e. focused window) went to
     BScreen *keyScreen() { return m_keyscreen; }
-    // screen we are watching for modifier changes
-    BScreen *watchingScreen() { return m_watching_screen; }
     const XEvent &lastEvent() const { return m_last_event; }
 
     AttentionNoticeHandler &attentionHandler() { return m_attention_handler; }
@@ -228,10 +224,8 @@ private:
     void handleEvent(XEvent *xe);
 
     void setupConfigFiles();
-    void handleButtonEvent(XButtonEvent &be);
     void handleUnmapNotify(XUnmapEvent &ue);
     void handleClientMessage(XClientMessageEvent &ce);
-    void handleKeyEvent(XKeyEvent &ke);
 
     std::auto_ptr<FbAtoms> m_fbatoms;
 
@@ -272,8 +266,6 @@ private:
     FluxboxWindow *m_masked_window;
 
     BScreen *m_mousescreen, *m_keyscreen;
-    BScreen *m_watching_screen;
-    unsigned int m_watch_keyrelease;
 
     Atom m_fluxbox_pid;
 
-- 
cgit v0.11.2