From 46261a8284730a16d664fa89423fc5728ed284b4 Mon Sep 17 00:00:00 2001
From: Mathias Gumz <akira at fluxbox dot org>
Date: Fri, 18 Dec 2009 08:05:07 +0100
Subject: implemented 'MoveN' and 'ClickN' support in keys file.

the hardcoded 'OnTitlebar Mouse1 :Raise' (see Window.cc, FluxboxWindow::buttonPressEvent())
is disabled for now, should be added to fluxbox-update_configs
---
 ChangeLog                     |   4 ++
 doc/asciidoc/fluxbox-keys.txt |  22 ++++++---
 doc/fluxbox-keys.5.in         |  31 +++++++++---
 src/CurrentWindowCmd.cc       |  47 ++++++++++++++----
 src/FbTk/KeyUtil.cc           |  56 +++++++++++----------
 src/Keys.cc                   | 110 +++++++++++++++++++++++++-----------------
 src/Window.cc                 |  43 ++++++++++++++---
 src/Window.hh                 |   1 +
 8 files changed, 216 insertions(+), 98 deletions(-)

diff --git a/ChangeLog b/ChangeLog
index 3087640..cc9e8a9 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,6 +1,10 @@
  (Format: Year/Month/Day)
 Changes for 1.1.2
 
+*09/12/18:
+   * Implemented new 'MoveN' and 'ClickN' support for keys file (Mathias)
+     Keys.cc Window.cc/hh CurrentWindowCmd.cc FbTk/KeyUtil.cc
+
 *09/12/15:
    * Updated fluxbox-keys documentation, added 'Fullscreen' (thanx Paul Tagliamonte)
 
diff --git a/doc/asciidoc/fluxbox-keys.txt b/doc/asciidoc/fluxbox-keys.txt
index ed69a57..3f3431d 100644
--- a/doc/asciidoc/fluxbox-keys.txt
+++ b/doc/asciidoc/fluxbox-keys.txt
@@ -55,7 +55,7 @@ are most commonly used:
 where *Mod1* is the Alt key on the PC keyboard and *Mod4* is usually a key
 branded with a familiar company logo.
 
-There are also some special modifiers that refer to mouse button presses:::
+There are also some special modifiers that refer to mouse button events:::
 *OnDesktop*;;
 	The mouse cursor is over the desktop (root window), and not any
 	window.
@@ -84,13 +84,21 @@ the key, and see the name in the output. If you have some "special" keys that
 do not produce a key name in the output of *xev(1)*, you can just use the
 keycode (NOT the keysym!) in your keys file.
 
-Commands can also be bound to mouse button presses, for which the proper "key"
-name is *Mouse*'n' where 'n' is the number of the mouse button. For example,
-*Mouse1* is the primary button, and *Mouse4* / *Mouse5* are the scroll wheel
-events, in normal configurations. *xev(1)* can also be used to tell the button
-number.
+Commands can also be bound to mouse events ('N' denotes the number of the
+button, eg. '1' is the primary button, '4'/'5' are the wheel buttons):
+
+*MouseN*;;
+	The mouse button 'N' is pressed down and holded.
+*ClickN*;;
+	The mouse button 'N' is clicked (pressed and released with no
+	movement in between)
+*MoveN*;;
+	The mouse button 'N' is currently holded, the binded action is triggered
+	as often as the mouse moves.
+
+
+There are some special "keys" that let you bind events to non-keyboard events:
 
-There are some special "keys" that let you bind events to non-keyboard events:::
 *ChangeWorkspace*;;
 	Fires when the workspace changes. This can be used to change backgrounds or
 	do anything else you like when you switch to a new workspace. See the
diff --git a/doc/fluxbox-keys.5.in b/doc/fluxbox-keys.5.in
index 6e641f9..2b29891 100644
--- a/doc/fluxbox-keys.5.in
+++ b/doc/fluxbox-keys.5.in
@@ -2,12 +2,12 @@
 .\"     Title: fluxbox-keys
 .\"    Author: [see the "AUTHORS" section]
 .\" Generator: DocBook XSL Stylesheets v1.75.1 <http://docbook.sf.net/>
-.\"      Date: 12/14/2009
+.\"      Date: 12/17/2009
 .\"    Manual: Fluxbox Manual
 .\"    Source: fluxbox-keys.txt
 .\"  Language: English
 .\"
-.TH "FLUXBOX\-KEYS" "5" "12/14/2009" "fluxbox\-keys\&.txt" "Fluxbox Manual"
+.TH "FLUXBOX\-KEYS" "5" "12/17/2009" "fluxbox\-keys\&.txt" "Fluxbox Manual"
 .\" -----------------------------------------------------------------
 .\" * set default formatting
 .\" -----------------------------------------------------------------
@@ -53,7 +53,7 @@ You can get a list of possible modifiers by calling \(oqxmodmap \-pm\(cq\&. This
 .sp
 where \fBMod1\fR is the Alt key on the PC keyboard and \fBMod4\fR is usually a key branded with a familiar company logo\&.
 .PP
-There are also some special modifiers that refer to mouse button presses
+There are also some special modifiers that refer to mouse button events
 .RS 4
 .PP
 \fBOnDesktop\fR
@@ -90,10 +90,30 @@ You may specify a key by its key name (for example, \fBa\fR or \fBspace\fR) or b
 .sp
 If you don\(cqt know the name of a key, you can run \fBxev(1)\fR in a terminal, push the key, and see the name in the output\&. If you have some "special" keys that do not produce a key name in the output of \fBxev(1)\fR, you can just use the keycode (NOT the keysym!) in your keys file\&.
 .sp
-Commands can also be bound to mouse button presses, for which the proper "key" name is \fBMouse\fR\fIn\fR where \fIn\fR is the number of the mouse button\&. For example, \fBMouse1\fR is the primary button, and \fBMouse4\fR / \fBMouse5\fR are the scroll wheel events, in normal configurations\&. \fBxev(1)\fR can also be used to tell the button number\&.
+Commands can also be bound to mouse events (\fIN\fR denotes the number of the button, eg\&. \fI1\fR is the primary button, \fI4\fR/\fI5\fR are the wheel buttons):
 .PP
-There are some special "keys" that let you bind events to non\-keyboard events
+\fBMouseN\fR
 .RS 4
+The mouse button
+\fIN\fR
+is pressed down and holded\&.
+.RE
+.PP
+\fBClickN\fR
+.RS 4
+The mouse button
+\fIN\fR
+is clicked (pressed and released with no movement in between)
+.RE
+.PP
+\fBMoveN\fR
+.RS 4
+The mouse button
+\fIN\fR
+is currently holded, the binded action is triggered as often as the mouse moves\&.
+.RE
+.sp
+There are some special "keys" that let you bind events to non\-keyboard events:
 .PP
 \fBChangeWorkspace\fR
 .RS 4
@@ -101,7 +121,6 @@ Fires when the workspace changes\&. This can be used to change backgrounds or do
 \fBEXAMPLES\fR
 below for one idea\&.
 .RE
-.RE
 .if n \{\
 .sp
 .\}
diff --git a/src/CurrentWindowCmd.cc b/src/CurrentWindowCmd.cc
index b73de01..f896009 100644
--- a/src/CurrentWindowCmd.cc
+++ b/src/CurrentWindowCmd.cc
@@ -262,11 +262,26 @@ void GoToTabCmd::real_execute() {
 REGISTER_COMMAND(startmoving, StartMovingCmd, void);
 
 void StartMovingCmd::real_execute() {
+
+    int x;
+    int y;
     const XEvent &last = Fluxbox::instance()->lastEvent();
-    if (last.type == ButtonPress) {
-        const XButtonEvent &be = last.xbutton;
-        fbwindow().startMoving(be.x_root, be.y_root);
+    switch (last.type) {
+    case ButtonPress:
+        x = last.xbutton.x_root;
+        y = last.xbutton.y_root;
+        break;
+
+    case MotionNotify:
+        x = last.xmotion.x_root;
+        y = last.xmotion.y_root;
+        break;
+
+    default:
+        return;
     }
+
+    fbwindow().startMoving(x, y);
 }
 
 FbTk::Command<void> *StartResizingCmd::parse(const string &cmd, const string &args,
@@ -305,15 +320,27 @@ FbTk::Command<void> *StartResizingCmd::parse(const string &cmd, const string &ar
 REGISTER_COMMAND_PARSER(startresizing, StartResizingCmd::parse, void);
 
 void StartResizingCmd::real_execute() {
+
+    int x;
+    int y;
     const XEvent &last = Fluxbox::instance()->lastEvent();
-    if (last.type == ButtonPress) {
-        const XButtonEvent &be = last.xbutton;
-        int x = be.x_root - fbwindow().x()
-                - fbwindow().frame().window().borderWidth();
-        int y = be.y_root - fbwindow().y()
-                - fbwindow().frame().window().borderWidth();
-        fbwindow().startResizing(x, y, fbwindow().getResizeDirection(x, y, m_mode));
+    switch (last.type) {
+    case ButtonPress:
+        x = last.xbutton.x_root;
+        y = last.xbutton.y_root;
+        break;
+    case MotionNotify:
+        x = last.xmotion.x_root;
+        y = last.xmotion.y_root;
+        break;
+    default:
+        return;
     }
+
+    x -= fbwindow().x() - fbwindow().frame().window().borderWidth();
+    y -= fbwindow().y() - fbwindow().frame().window().borderWidth();
+
+    fbwindow().startResizing(x, y, fbwindow().getResizeDirection(x, y, m_mode));
 }
 
 REGISTER_COMMAND(starttabbing, StartTabbingCmd, void);
diff --git a/src/FbTk/KeyUtil.cc b/src/FbTk/KeyUtil.cc
index 0578b9c..6ffe2a2 100644
--- a/src/FbTk/KeyUtil.cc
+++ b/src/FbTk/KeyUtil.cc
@@ -42,16 +42,16 @@ struct t_modlist{
 };
 
 const struct t_modlist modlist[] = {
-    {"SHIFT", ShiftMask},
-    {"LOCK", LockMask},
-    {"CONTROL", ControlMask},
-    {"MOD1", Mod1Mask},
-    {"MOD2", Mod2Mask},
-    {"MOD3", Mod3Mask},
-    {"MOD4", Mod4Mask},
-    {"MOD5", Mod5Mask},
-    {"ALT", Mod1Mask},
-    {"CTRL", ControlMask},
+    {"shift", ShiftMask},
+    {"lock", LockMask},
+    {"control", ControlMask},
+    {"mod1", Mod1Mask},
+    {"mod2", Mod2Mask},
+    {"mod3", Mod3Mask},
+    {"mod4", Mod4Mask},
+    {"mod5", Mod5Mask},
+    {"alt", Mod1Mask},
+    {"ctrl", ControlMask},
     {0, 0}
 };
 
@@ -88,7 +88,7 @@ void KeyUtil::loadModmap() {
         XFreeModifiermap(m_modmap);
 
     m_modmap = XGetModifierMapping(App::instance()->display());
-    	
+
     // find modifiers and set them
     for (int i=0, realkey=0; i<8; ++i) {
         for (int key=0; key<m_modmap->max_keypermod; ++key, ++realkey) {
@@ -96,7 +96,7 @@ void KeyUtil::loadModmap() {
             if (m_modmap->modifiermap[realkey] == 0)
                 continue;
 
-            KeySym ks = XKeycodeToKeysym(App::instance()->display(), 
+            KeySym ks = XKeycodeToKeysym(App::instance()->display(),
                     m_modmap->modifiermap[realkey], 0);
 
             switch (ks) {
@@ -154,12 +154,18 @@ void KeyUtil::grabButton(unsigned int button, unsigned int mod, Window win,
 */
 
 unsigned int KeyUtil::getKey(const char *keystr) {
-    if (!keystr)
-        return 0;
-    KeySym sym = XStringToKeysym(keystr);
-    if (sym==NoSymbol)
-        return 0;
-    return XKeysymToKeycode(App::instance()->display(), sym);
+
+    KeyCode code = 0;
+
+    if (keystr) {
+
+        KeySym sym = XStringToKeysym(keystr);
+        if (sym != NoSymbol) {
+            code = XKeysymToKeycode(App::instance()->display(), sym);
+        }
+    }
+
+    return code;
 }
 
 
@@ -169,14 +175,14 @@ unsigned int KeyUtil::getKey(const char *keystr) {
 unsigned int KeyUtil::getModifier(const char *modstr) {
     if (!modstr)
         return 0;
-    
+
     // find mod mask string
     for (unsigned int i=0; modlist[i].str !=0; i++) {
-        if (modlist[i] == modstr)		
-            return modlist[i].mask;		
+        if (modlist[i] == modstr)
+            return modlist[i].mask;
     }
-	
-    return 0;	
+
+    return 0;
 }
 
 /// Ungrabs the keys
@@ -193,7 +199,7 @@ void KeyUtil::ungrabButtons(Window win) {
 unsigned int KeyUtil::keycodeToModmask(unsigned int keycode) {
     XModifierKeymap *modmap = instance().m_modmap;
 
-    if (!modmap) 
+    if (!modmap)
         return 0;
 
     // search through modmap for this keycode
@@ -204,7 +210,7 @@ unsigned int KeyUtil::keycodeToModmask(unsigned int keycode) {
             if (modmap->modifiermap[modmap->max_keypermod*mod + key] == keycode) {
                 return modlist[mod].mask;
             }
-        } 
+        }
     }
     // no luck
     return 0;
diff --git a/src/Keys.cc b/src/Keys.cc
index 0b8efe5..935d54b 100644
--- a/src/Keys.cc
+++ b/src/Keys.cc
@@ -106,6 +106,28 @@ using std::pair;
 
 using FbTk::STLUtil::destroyAndClearSecond;
 
+namespace {
+
+// candidate for FbTk::StringUtil ?
+int extractKeyFromString(const std::string& in, const char* start_pattern, unsigned int& key) {
+
+    int ret = 0;
+
+    if (strstr(in.c_str(), start_pattern) != 0) {
+
+        unsigned int tmp_key = 0;
+        if (FbTk::StringUtil::extractNumber(in.substr(strlen(start_pattern)), tmp_key)) {
+
+            key = tmp_key;
+            ret = 1;
+        }
+    }
+
+    return ret;
+}
+
+} // end of anonymouse namespace
+
 // helper class 'keytree'
 class Keys::t_key {
 public:
@@ -254,10 +276,12 @@ void Keys::grabWindow(Window win) {
         if ((win_it->second & Keys::GLOBAL) > 0 && (*it)->type == KeyPress)
             FbTk::KeyUtil::grabKey((*it)->key, (*it)->mod, win);
         // ON_DESKTOP buttons don't need to be grabbed
-        else if ((win_it->second & (*it)->context & ~Keys::ON_DESKTOP) > 0 &&
-                 (*it)->type == ButtonPress)
-            FbTk::KeyUtil::grabButton((*it)->key, (*it)->mod, win,
-                                      ButtonPressMask|ButtonReleaseMask);
+        else if ((win_it->second & (*it)->context & ~Keys::ON_DESKTOP) > 0) {
+
+            if ((*it)->type == ButtonPress || (*it)->type == ButtonRelease || (*it)->type == MotionNotify) {
+                FbTk::KeyUtil::grabButton((*it)->key, (*it)->mod, win, ButtonPressMask|ButtonReleaseMask|ButtonMotionMask);
+            }
+        }
     }
 }
 
@@ -363,85 +387,84 @@ bool Keys::addBinding(const string &linebuffer) {
     // for each argument
     for (; argc < val.size(); argc++) {
 
-        if (val[argc][0] != ':') { // parse key(s)
+        std::string arg = FbTk::StringUtil::toLower(val[argc]);
+
+        if (arg[0] != ':') { // parse key(s)
 
-            int tmpmod = FbTk::KeyUtil::getModifier(val[argc].c_str());
+            int tmpmod = FbTk::KeyUtil::getModifier(arg.c_str());
             if(tmpmod)
                 mod |= tmpmod; //If it's a modifier
-            else if (strcasecmp("ondesktop", val[argc].c_str()) == 0)
+            else if (arg == "ondesktop")
                 context |= ON_DESKTOP;
-            else if (strcasecmp("ontoolbar", val[argc].c_str()) == 0)
+            else if (arg == "ontoolbar")
                 context |= ON_TOOLBAR;
-            else if (strcasecmp("onwindow", val[argc].c_str()) == 0)
+            else if (arg == "onwindow")
                 context |= ON_WINDOW;
-            else if (strcasecmp("ontitlebar", val[argc].c_str()) == 0)
+            else if (arg == "ontitlebar")
                 context |= ON_TITLEBAR;
-            else if (strcasecmp("double", val[argc].c_str()) == 0)
+            else if (arg == "double")
                 isdouble = true;
-            else if (strcasecmp("NONE",val[argc].c_str())) {
-                // check if it's a mouse button
-                if (strcasecmp("focusin", val[argc].c_str()) == 0) {
+            else if (arg != "none") {
+                if (arg == "focusin") {
                     context = ON_WINDOW;
                     mod = key = 0;
                     type = FocusIn;
-                } else if (strcasecmp("focusout", val[argc].c_str()) == 0) {
+                } else if (arg == "focusout") {
                     context = ON_WINDOW;
                     mod = key = 0;
                     type = FocusOut;
-                } else if (strcasecmp("changeworkspace",
-                                      val[argc].c_str()) == 0) {
+                } else if (arg == "changeworkspace") {
                     context = ON_DESKTOP;
                     mod = key = 0;
                     type = FocusIn;
-                } else if (strcasecmp("mouseover", val[argc].c_str()) == 0) {
+                } else if (arg == "mouseover") {
                     type = EnterNotify;
                     if (!(context & (ON_WINDOW|ON_TOOLBAR)))
                         context |= ON_WINDOW;
                     key = 0;
-                } else if (strcasecmp("mouseout", val[argc].c_str()) == 0) {
+                } else if (arg == "mouseout") {
                     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) {
+
+                // check if it's a mouse button
+                } else if (extractKeyFromString(arg, "mouse", key)) {
                     type = ButtonPress;
-                    key = atoi(val[argc].substr(5,
-                                                val[argc].length()-5).c_str());
+
                     // fluxconf mangles things like OnWindow Mouse# to Mouse#ow
-                    if (strstr(val[argc].c_str(), "top"))
+                    if (strstr(arg.c_str(), "top"))
                         context = ON_DESKTOP;
-                    else if (strstr(val[argc].c_str(), "ebar"))
+                    else if (strstr(arg.c_str(), "ebar"))
                         context = ON_TITLEBAR;
-                    else if (strstr(val[argc].c_str(), "bar"))
+                    else if (strstr(arg.c_str(), "bar"))
                         context = ON_TOOLBAR;
-                    else if (strstr(val[argc].c_str(), "ow"))
+                    else if (strstr(arg.c_str(), "ow"))
                         context = ON_WINDOW;
+                } else if (extractKeyFromString(arg, "click", key)) {
+                    type = ButtonRelease;
+                } else if (extractKeyFromString(arg, "move", key)) {
+                    type = MotionNotify;
+
+                } else if (key = FbTk::KeyUtil::getKey(val[argc].c_str())) { // convert from string symbol
+                    type = KeyPress;
+
                 // keycode covers the following three two-byte cases:
                 // 0x       - hex
                 // +[1-9]   - number between +1 and +9
                 // numbers 10 and above
                 //
-                } else if (!val[argc].empty() && ((isdigit(val[argc][0]) &&
-                           (isdigit(val[argc][1]) || val[argc][1] == 'x')) ||
-                           (val[argc][0] == '+' && isdigit(val[argc][1])))) {
-
-                    key = strtoul(val[argc].c_str(), NULL, 0);
-                    type = KeyPress;
-
-                    if (errno == EINVAL || errno == ERANGE)
-                        key = 0;
-
-                } else { // convert from string symbol
-                    key = FbTk::KeyUtil::getKey(val[argc].c_str());
+                } else {
+					FbTk::StringUtil::extractNumber(arg, key);
                     type = KeyPress;
                 }
 
-                if (key == 0 && (type == KeyPress || type == ButtonPress))
+                if (key == 0 && (type == KeyPress || type == ButtonPress || type == ButtonRelease))
                     return false;
+
                 if (type != ButtonPress)
                     isdouble = false;
+
                 if (!first_new_key) {
                     first_new_keylist = current_key;
                     current_key = current_key->find(type, mod, key, context,
@@ -470,7 +493,7 @@ bool Keys::addBinding(const string &linebuffer) {
                 return false;
 
             const char *str = FbTk::StringUtil::strcasestr(linebuffer.c_str(),
-                    val[argc].c_str());
+                   val[argc].c_str());
             if (str) // +1 to skip ':'
                 current_key->m_command = FbTk::CommandParser<void>::instance().parse(str + 1);
 
@@ -504,10 +527,11 @@ bool Keys::doAction(int type, unsigned int mods, unsigned int key,
     bool isdouble = false;
 
     if (type == ButtonPress) {
-        if (time > last_button_time)
+        if (time > last_button_time) {
             double_click = (time - last_button_time <
                 Fluxbox::instance()->getDoubleClickInterval()) &&
                 last_button == key;
+        }
         last_button_time = time;
         last_button = key;
         isdouble = double_click;
diff --git a/src/Window.cc b/src/Window.cc
index c03447c..0fb674c 100644
--- a/src/Window.cc
+++ b/src/Window.cc
@@ -280,6 +280,7 @@ FluxboxWindow::FluxboxWindow(WinClient &client):
     m_button_grab_x(0), m_button_grab_y(0),
     m_last_move_x(0), m_last_move_y(0),
     m_last_resize_h(1), m_last_resize_w(1),
+    m_last_pressed_button(0),
     m_workspace_number(0),
     m_current_state(0),
     m_old_decoration_mask(0),
@@ -1073,7 +1074,6 @@ void FluxboxWindow::grabButtons() {
                 GrabModeSync, GrabModeSync, None, None);
     XUngrabButton(display, Button1, Mod1Mask|Mod2Mask|Mod3Mask,
                   frame().window().window());
-
 }
 
 
@@ -1478,7 +1478,7 @@ void FluxboxWindow::setFullscreenLayer() {
     FluxboxWindow *foc = FocusControl::focusedFbWindow();
     // if another window on the same head is focused, make sure we can see it
     if (isFocused() || !foc || &foc->screen() != &screen() ||
-        getOnHead() != foc->getOnHead() || 
+        getOnHead() != foc->getOnHead() ||
         (foc->winClient().isTransient() &&
          foc->winClient().transientFor()->fbwindow() == this)) {
         moveToLayer(::Layer::ABOVE_DOCK);
@@ -2370,13 +2370,16 @@ bool FluxboxWindow::isTyping() const {
 void FluxboxWindow::buttonPressEvent(XButtonEvent &be) {
     m_last_button_x = be.x_root;
     m_last_button_y = be.y_root;
+    m_last_pressed_button = be.button;
 
     bool onTitlebar =
         frame().insideTitlebar( be.window ) &&
         frame().handle().window() != be.window;
 
+#if 0 // disabled
     if (onTitlebar && be.button == 1)
         raise();
+#endif
 
     // check keys file first
     Keys *k = Fluxbox::instance()->keys();
@@ -2412,19 +2415,27 @@ void FluxboxWindow::buttonPressEvent(XButtonEvent &be) {
 
 void FluxboxWindow::buttonReleaseEvent(XButtonEvent &re) {
 
+    if (m_last_pressed_button == re.button) {
+        m_last_pressed_button = 0;
+    }
+
     if (isMoving())
         stopMoving();
     else if (isResizing())
         stopResizing();
     else if (m_attaching_tab)
         attachTo(re.x_root, re.y_root);
-    else
-        frame().tabcontainer().tryButtonReleaseEvent(re);
+    else if (!frame().tabcontainer().tryButtonReleaseEvent(re)) {
 
+        if (m_last_button_x == re.x_root && m_last_button_y == re.y_root) {
+            Fluxbox::instance()->keys()->doAction(re.type, re.state, re.button, Keys::ON_WINDOW, &winClient(), re.time);
+        }
+    }
 }
 
 
 void FluxboxWindow::motionNotifyEvent(XMotionEvent &me) {
+
     if (isMoving() && me.window == parent()) {
         me.window = frame().window().window();
     }
@@ -2452,6 +2463,13 @@ void FluxboxWindow::motionNotifyEvent(XMotionEvent &me) {
         }
     }
 
+
+    // in case someone put  MoveX :StartMoving etc into keys, we have
+    // to activate it before doing the actual motionNotify code
+    Fluxbox::instance()->keys()->doAction(me.type, me.state, m_last_pressed_button,
+                inside_titlebar ? Keys::ON_TITLEBAR : Keys::ON_WINDOW,
+                &winClient(), me.time);
+
     if (moving || ((me.state & Button1Mask) && functions.move &&
         inside_titlebar && !isResizing() && m_attaching_tab == 0)) {
 
@@ -2818,8 +2836,14 @@ void FluxboxWindow::setDecorationMask(unsigned int mask, bool apply) {
 }
 
 void FluxboxWindow::startMoving(int x, int y) {
-    if (s_num_grabs > 0)
+
+    if (isMoving()) {
+        return;
+    }
+
+    if (s_num_grabs > 0) {
         return;
+    }
 
     if (isMaximized() && screen().getMaxDisableMove())
         return;
@@ -3062,6 +3086,7 @@ void FluxboxWindow::doSnapping(int &orig_left, int &orig_top) {
 
 FluxboxWindow::ReferenceCorner FluxboxWindow::getResizeDirection(int x, int y,
         ResizeModel model) const {
+
     int cx = frame().width() / 2;
     int cy = frame().height() / 2;
     if (model == CENTERRESIZE)
@@ -3088,6 +3113,9 @@ FluxboxWindow::ReferenceCorner FluxboxWindow::getResizeDirection(int x, int y,
 
 void FluxboxWindow::startResizing(int x, int y, ReferenceCorner dir) {
 
+    if (isResizing())
+        return;
+
     if (s_num_grabs > 0 || isShaded() || isIconic() )
         return;
 
@@ -3550,7 +3578,7 @@ void FluxboxWindow::updateButtons() {
                     need_update = true;
             }
         }
-                
+
     }
 
     if (!need_update)
@@ -3680,6 +3708,7 @@ void FluxboxWindow::grabPointer(Window grab_window,
                                 Window confine_to,
                                 Cursor cursor,
                                 Time time) {
+
     XGrabPointer(FbTk::App::instance()->display(),
                  grab_window,
                  owner_events,
@@ -3870,7 +3899,7 @@ void FluxboxWindow::setWindowType(WindowState::WindowType type) {
      */
 }
 
-void FluxboxWindow::focusedWindowChanged(BScreen &screen, 
+void FluxboxWindow::focusedWindowChanged(BScreen &screen,
                                          FluxboxWindow *focused_win, WinClient* client) {
     if (focused_win) {
         setFullscreenLayer();
diff --git a/src/Window.hh b/src/Window.hh
index 92d20d7..9cefd55 100644
--- a/src/Window.hh
+++ b/src/Window.hh
@@ -547,6 +547,7 @@ private:
     int m_last_resize_x, m_last_resize_y; // handles last button press event for resize
     int m_last_move_x, m_last_move_y; // handles last pos for non opaque moving
     int m_last_resize_h, m_last_resize_w; // handles height/width for resize "window"
+    int m_last_pressed_button;
 
     timeval m_last_keypress_time;
 
-- 
cgit v0.11.2