From bb6906fa80c06fc23975d7520b3e8919423a29b4 Mon Sep 17 00:00:00 2001
From: markt <markt>
Date: Thu, 22 Nov 2007 20:21:47 +0000
Subject: added special FocusIn/Out MouseOver/Out ChangeWorkspace keys

---
 ChangeLog                 | 14 ++++++++++++++
 src/FbCommandFactory.cc   |  7 +++----
 src/FbTk/LogicCommands.hh |  8 ++++----
 src/FbWinFrame.cc         |  6 ++++--
 src/Keys.cc               | 33 +++++++++++++++++++++++++++++----
 src/Screen.cc             |  2 ++
 src/Toolbar.cc            | 11 ++++++++---
 src/Window.cc             | 26 ++++++++++++++++++++++++++
 8 files changed, 90 insertions(+), 17 deletions(-)

diff --git a/ChangeLog b/ChangeLog
index 0e38acf..5971f05 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,6 +1,20 @@
  (Format: Year/Month/Day)
 Changes for 1.0.1:
 *07/11/22:
+   * Added some new special keys to the keys file: FocusIn, FocusOut, MouseOver,
+     MouseOut, ChangeWorkspace (Mark)
+     - FocusIn/FocusOut correspond to a window gaining or losing focus, e.g. the
+       following will raise all xterms when one gains focus:
+       FocusIn :If {Matches (xterm)} {Raise (xterm)} {}
+     - MouseOver/MouseOut correspond to the mouse moving over the window or
+       toolbar (when used with OnToolbar) -- OnDesktop not yet supported, e.g.
+       the following will unshade a window when you move your mouse over it with
+       alt pressed:
+       Mod1 MouseOver :If {Matches (shaded=yes)} {Shade} {}
+     - ChangeWorkspace corresponds to the workspace being changed, e.g. the
+       following will set a different wallpaper for each workspace:
+       ChangeWorkspace :Exec fbsetbg ~/.fluxbox/bg$(xprop -root _NET_CURRENT_DESKTOP | awk '{print $3}').png
+     Keys.cc Window.cc Screen.cc Toolbar.cc
    * Added translations for zh_TW (thanks Wei-Lun Chao)
    * Fix division by 0 error when resize increments are set to 0 by an
      application, bug #1836182
diff --git a/src/FbCommandFactory.cc b/src/FbCommandFactory.cc
index 92099f2..8f5dcf8 100644
--- a/src/FbCommandFactory.cc
+++ b/src/FbCommandFactory.cc
@@ -809,17 +809,16 @@ FbTk::Command *FbCommandFactory::stringToCommand(const std::string &command,
         pos = err;
         err = FbTk::StringUtil::getStringBetween(cmd, arguments.c_str() + pos,
                                                  '{', '}', " \t\n", true);
-        if (err > 0)
-            t = CommandParser::instance().parseLine(cmd, trusted);
-        if (err == 0 || *t == 0)
+        if (err == 0)
             return 0;
+        t = CommandParser::instance().parseLine(cmd, trusted);
 
         pos += err;
         err = FbTk::StringUtil::getStringBetween(cmd, arguments.c_str() + pos,
                                                  '{', '}', " \t\n", true);
         if (err > 0)
             f = CommandParser::instance().parseLine(cmd, trusted);
-        if (err == 0 || *f == 0)
+        if (err == 0 || *t == 0 && *f == 0)
             return 0;
 
         return new FbTk::IfCommand(cond, t, f);
diff --git a/src/FbTk/LogicCommands.hh b/src/FbTk/LogicCommands.hh
index a94dad8..4f20864 100644
--- a/src/FbTk/LogicCommands.hh
+++ b/src/FbTk/LogicCommands.hh
@@ -38,10 +38,10 @@ public:
               RefCount<Command> &t, RefCount<Command> &f):
         m_cond(cond), m_t(t), m_f(f) { }
     void execute() {
-        if (m_cond->bool_execute())
-            m_t->execute();
-        else
-            m_f->execute();
+        if (m_cond->bool_execute()) {
+            if (*m_t) m_t->execute();
+        } else
+            if (*m_f) m_f->execute();
     }
 
 private:
diff --git a/src/FbWinFrame.cc b/src/FbWinFrame.cc
index 83610ea..f710416 100644
--- a/src/FbWinFrame.cc
+++ b/src/FbWinFrame.cc
@@ -55,7 +55,8 @@ FbWinFrame::FbWinFrame(BScreen &screen, FbWinFrameTheme &theme, FbTk::ImageContr
     m_imagectrl(imgctrl),
     m_window(theme.screenNum(), x, y, width, height,
              ButtonPressMask | ButtonReleaseMask |
-             ButtonMotionMask | EnterWindowMask, true),
+             ButtonMotionMask | EnterWindowMask |
+             LeaveWindowMask, true),
     m_layeritem(window(), layer),
     m_titlebar(m_window, 0, 0, 100, 16,
                ButtonPressMask | ButtonReleaseMask |
@@ -666,7 +667,8 @@ void FbWinFrame::setClientWindow(FbTk::FbWindow &win) {
                      FocusChangeMask | KeyPressMask);
 
     m_window.setEventMask(ButtonPressMask | ButtonReleaseMask |
-                          ButtonMotionMask | EnterWindowMask | SubstructureRedirectMask);
+                          ButtonMotionMask | EnterWindowMask |
+                          LeaveWindowMask | SubstructureRedirectMask);
 
     XFlush(win.display());
 
diff --git a/src/Keys.cc b/src/Keys.cc
index 2d26ab8..f3cd092 100644
--- a/src/Keys.cc
+++ b/src/Keys.cc
@@ -307,10 +307,35 @@ bool Keys::addBinding(const string &linebuffer) {
                 context |= ON_WINDOW;
             else if (strcasecmp("NONE",val[argc].c_str())) {
                 // check if it's a mouse button
-                if (!strcasecmp(val[argc].substr(0,5).c_str(), "mouse") &&
-                        val[argc].length() > 5) {
+                if (strcasecmp("focusin", val[argc].c_str()) == 0) {
+                    context = ON_WINDOW;
+                    mod = key = 0;
+                    type = FocusIn;
+                } else if (strcasecmp("focusout", val[argc].c_str()) == 0) {
+                    context = ON_WINDOW;
+                    mod = key = 0;
+                    type = FocusOut;
+                } else if (strcasecmp("changeworkspace",
+                                      val[argc].c_str()) == 0) {
+                    context = ON_DESKTOP;
+                    mod = key = 0;
+                    type = FocusIn;
+                } else if (strcasecmp("mouseover", val[argc].c_str()) == 0) {
+                    type = EnterNotify;
+                    if (!(context & (ON_WINDOW|ON_TOOLBAR)))
+                        context |= ON_WINDOW;
+                    key = 0;
+                } else if (strcasecmp("mouseout", val[argc].c_str()) == 0) {
+                    type = LeaveNotify;
+                    if (!(context & (ON_WINDOW|ON_TOOLBAR)))
+                        context |= ON_WINDOW;
+                    key = 0;
+                } else if (strcasecmp(val[argc].substr(0,5).c_str(),
+                                      "mouse") == 0 &&
+                           val[argc].length() > 5) {
                     type = ButtonPress;
-                    key = atoi(val[argc].substr(5,val[argc].length()-5).c_str());
+                    key = atoi(val[argc].substr(5,
+                                                val[argc].length()-5).c_str());
                 // keycode covers the following three two-byte cases:
                 // 0x       - hex
                 // +[1-9]   - number between +1 and +9
@@ -331,7 +356,7 @@ bool Keys::addBinding(const string &linebuffer) {
                     type = KeyPress;
                 }
 
-                if (key == 0)
+                if (key == 0 && (type == KeyPress || type == ButtonPress))
                     return false;
                 if (!first_new_key) {
                     first_new_keylist = current_key;
diff --git a/src/Screen.cc b/src/Screen.cc
index 0c26a70..155a113 100644
--- a/src/Screen.cc
+++ b/src/Screen.cc
@@ -1237,6 +1237,8 @@ void BScreen::changeWorkspaceID(unsigned int id, bool revert) {
 
     m_currentworkspace_sig.notify();
 
+    // do this after atom handlers, so scripts can access new workspace number
+    Fluxbox::instance()->keys()->doAction(FocusIn, 0, 0, Keys::ON_DESKTOP);
 }
 
 
diff --git a/src/Toolbar.cc b/src/Toolbar.cc
index 32925de..2694a4c 100644
--- a/src/Toolbar.cc
+++ b/src/Toolbar.cc
@@ -556,7 +556,9 @@ void Toolbar::buttonPressEvent(XButtonEvent &be) {
 
 }
 
-void Toolbar::enterNotifyEvent(XCrossingEvent &not_used) {
+void Toolbar::enterNotifyEvent(XCrossingEvent &ce) {
+    Fluxbox::instance()->keys()->doAction(ce.type, ce.state, 0,
+                                          Keys::ON_TOOLBAR);
     if (! doAutoHide()) {
         if (isHidden())
             toggleHidden();
@@ -573,13 +575,16 @@ void Toolbar::enterNotifyEvent(XCrossingEvent &not_used) {
 }
 
 void Toolbar::leaveNotifyEvent(XCrossingEvent &event) {
-    if (! doAutoHide())
-        return;
     // still inside?
     if (event.x_root > x() && event.x_root <= (int)(x() + width()) &&
         event.y_root > y() && event.y_root <= (int)(y() + height()))
         return;
 
+    Fluxbox::instance()->keys()->doAction(event.type, event.state, 0,
+                                          Keys::ON_TOOLBAR);
+    if (! doAutoHide())
+        return;
+
     if (isHidden()) {
         if (m_hide_timer.isTiming())
             m_hide_timer.stop();
diff --git a/src/Window.cc b/src/Window.cc
index 0fb8673..0db3b80 100644
--- a/src/Window.cc
+++ b/src/Window.cc
@@ -1930,6 +1930,9 @@ void FluxboxWindow::setFocusFlag(bool focus) {
         m_focussig.notify();
         if (m_client)
             m_client->focusSig().notify();
+        WindowCmd<void>::setClient(m_client);
+        Fluxbox::instance()->keys()->doAction(focus ? FocusIn : FocusOut, 0, 0,
+                                              Keys::ON_WINDOW);
     }
 }
 
@@ -2942,6 +2945,12 @@ void FluxboxWindow::enterNotifyEvent(XCrossingEvent &ev) {
         return;
     }
 
+    if (ev.window == frame().window()) {
+        WindowCmd<void>::setWindow(this);
+        Fluxbox::instance()->keys()->doAction(ev.type, ev.state, 0,
+                                              Keys::ON_WINDOW);
+    }
+
     WinClient *client = 0;
     if (screen().focusControl().isMouseTabFocus()) {
         // determine if we're in a label button (tab)
@@ -2984,6 +2993,23 @@ void FluxboxWindow::enterNotifyEvent(XCrossingEvent &ev) {
 }
 
 void FluxboxWindow::leaveNotifyEvent(XCrossingEvent &ev) {
+
+    // ignore grab activates, or if we're not visible
+    if (ev.mode == NotifyGrab || ev.mode == NotifyUngrab ||
+        !isVisible()) {
+        return;
+    }
+
+    // still inside?
+    if (ev.x_root > frame().x() && ev.y_root > frame().y() &&
+        ev.x_root <= (int)(frame().x() + frame().width()) &&
+        ev.y_root <= (int)(frame().y() + frame().height()))
+        return;
+
+    WindowCmd<void>::setWindow(this);
+    Fluxbox::instance()->keys()->doAction(ev.type, ev.state, 0,
+                                          Keys::ON_WINDOW);
+
     // I hope commenting this out is right - simon 21jul2003
     //if (ev.window == frame().window())
     //installColormap(false);
-- 
cgit v0.11.2