From 0a14d911c64a8f6378665bf3e49b868b9175b51f Mon Sep 17 00:00:00 2001
From: Mark Tiefenbruck <mark@fluxbox.org>
Date: Thu, 20 Dec 2007 23:07:46 -0800
Subject: added key command StartTabbing

---
 ChangeLog                      |   3 +
 data/init.in                   |   2 +-
 data/keys                      |   3 +
 src/CurrentWindowCmd.cc        |  10 +++
 src/CurrentWindowCmd.hh        |   8 +++
 src/Window.cc                  | 149 ++++++++++++++++++++---------------------
 src/Window.hh                  |   2 +
 src/fluxbox.cc                 |   2 +-
 util/fluxbox-update_configs.cc |  13 ++++
 9 files changed, 114 insertions(+), 78 deletions(-)

diff --git a/ChangeLog b/ChangeLog
index 91975b2..3f39d79 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,8 @@
  (Format: Year/Month/Day)
 Changes for 1.0.1:
+*07/12/21:
+   * Added new key command :StartTabbing (Mark)
+     Window.cc/hh CurrentWindowCmd.cc/hh
 *07/12/20:
    * Added new key command :ForEach (or :Map) (Mark)
      - :ForEach {<command>} [{ [{<list opts>}] [<bool command>] }]
diff --git a/data/init.in b/data/init.in
index c0bb93a..86cfa08 100644
--- a/data/init.in
+++ b/data/init.in
@@ -30,4 +30,4 @@ session.colorsPerChannel:	4
 session.doubleClickInterval:	250
 session.cacheMax:	200
 session.imageDither:	True
-session.configVersion:	6
+session.configVersion:	7
diff --git a/data/keys b/data/keys
index a8c7cba..8b2a234 100644
--- a/data/keys
+++ b/data/keys
@@ -15,6 +15,9 @@ OnToolbar Mouse5 :PrevWorkspace
 OnWindow Mod1 Mouse1 :StartMoving
 OnWindow Mod1 Mouse3 :StartResizing
 
+# middle click a window's titlebar and drag to attach windows
+OnTitlebar Mouse2 :StartTabbing
+
 # double click on the titlebar to shade
 OnTitlebar Double Mouse1 :Shade
 
diff --git a/src/CurrentWindowCmd.cc b/src/CurrentWindowCmd.cc
index d7b05ab..072f3c5 100644
--- a/src/CurrentWindowCmd.cc
+++ b/src/CurrentWindowCmd.cc
@@ -313,6 +313,16 @@ void StartResizingCmd::real_execute() {
     }
 }
 
+REGISTER_OBJECT(starttabbing, StartTabbingCmd, Command);
+
+void StartTabbingCmd::real_execute() {
+    const XEvent &last = Fluxbox::instance()->lastEvent();
+    if (last.type == ButtonPress) {
+        const XButtonEvent &be = last.xbutton;
+        fbwindow().startTabbing(be);
+    }
+}
+
 FbTk::Command *MoveCmd::parse(const string &command, const string &args,
                               bool trusted) {
     FbTk_istringstream is(args.c_str());
diff --git a/src/CurrentWindowCmd.hh b/src/CurrentWindowCmd.hh
index 7ef1184..fdce8d6 100644
--- a/src/CurrentWindowCmd.hh
+++ b/src/CurrentWindowCmd.hh
@@ -159,6 +159,14 @@ private:
     const FluxboxWindow::ResizeModel m_mode;
 };
 
+// begin tabbing with mouse
+class StartTabbingCmd: public WindowHelperCmd {
+public:
+    StartTabbingCmd() { }
+protected:
+    void real_execute();
+};
+
 // move cmd, relative position
 class MoveCmd: public WindowHelperCmd {
 public:
diff --git a/src/Window.cc b/src/Window.cc
index c9ab1b2..d99d1c1 100644
--- a/src/Window.cc
+++ b/src/Window.cc
@@ -2611,11 +2611,10 @@ void FluxboxWindow::motionNotifyEvent(XMotionEvent &me) {
         me.window = frame().window().window();
     }
 
-    bool inside_titlebar = (frame().titlebar() == me.window
-                            || frame().label() == me.window
-                            || frame().tabcontainer() == me.window
-                            || frame().handle() == me.window
-                            || frame().window() == me.window);
+    bool inside_titlebar = frame().gripLeft().window() != me.window &&
+        frame().gripRight().window() != me.window &&
+        frame().clientArea().window() != me.window &&
+        frame().window() != me.window;
 
     if (Fluxbox::instance()->getIgnoreBorder() && m_attaching_tab == 0
         && !(isMoving() || isResizing())) {
@@ -2650,24 +2649,8 @@ void FluxboxWindow::motionNotifyEvent(XMotionEvent &me) {
             return;
     }
 
-    WinClient *client = 0;
-    if (!inside_titlebar) {
-        // determine if we're in titlebar
-        Client2ButtonMap::iterator it =
-            find_if(m_labelbuttons.begin(),
-                    m_labelbuttons.end(),
-                    Compose(bind2nd(equal_to<Window>(), me.window),
-                            Compose(mem_fun(&TextButton::window),
-                                    Select2nd<Client2ButtonMap::value_type>())));
-        if (it != m_labelbuttons.end()) {
-            inside_titlebar = true;
-            client = (*it).first;
-        }
-    }
-
-    if ((me.state & Button1Mask) && functions.move &&
-        inside_titlebar &&
-        !isResizing()) {
+    if (moving || (me.state & Button1Mask) && functions.move &&
+        inside_titlebar && !isResizing() && m_attaching_tab == 0) {
 
         if (! isMoving()) {
             startMoving(me.x_root, me.y_root);
@@ -2741,7 +2724,7 @@ void FluxboxWindow::motionNotifyEvent(XMotionEvent &me) {
 
             screen().showPosition(dx, dy);
         } // end if moving
-    } else if (functions.resize &&
+    } else if (resizing || m_attaching_tab == 0 && functions.resize &&
                (((me.state & Button1Mask) &&
                  (me.window == frame().gripRight() ||
                   me.window == frame().gripLeft())) ||
@@ -2833,61 +2816,25 @@ void FluxboxWindow::motionNotifyEvent(XMotionEvent &me) {
                 screen().showGeometry(gx, gy);
             }
         }
-    } else if (functions.tabable &&
-               (me.state & Button2Mask) && inside_titlebar && (client != 0 || m_attaching_tab != 0)) {
+    } else if (m_attaching_tab != 0) {
         //
         // drag'n'drop code for tabs
         //
-        FbTk::TextButton &active_button = *m_labelbuttons[(m_attaching_tab==0)?client:m_attaching_tab];
 
-        if (m_attaching_tab == 0) {
-            if (s_num_grabs > 0)
-                return;
-            // start drag'n'drop for tab
-            m_attaching_tab = client;
-            grabPointer(me.window, False, ButtonMotionMask |
-                        ButtonReleaseMask, GrabModeAsync, GrabModeAsync,
-                        None, frame(). theme().moveCursor(), CurrentTime);
-            // relative position on button
-            m_button_grab_x = me.x;
-            m_button_grab_y = me.y;
-            // last known root mouse position
-            m_last_move_x = me.x_root - me.x;
-            m_last_move_y = me.y_root - me.y;
-            // hijack extra vars for initial grab location
-            m_last_resize_x = me.x_root;
-            m_last_resize_y = me.y_root;
-
-            Fluxbox::instance()->grab();
-
-            parent().drawRectangle(screen().rootTheme().opGC(),
-                                   m_last_move_x, m_last_move_y,
-                                   active_button.width(),
-                                   active_button.height());
-
-            menu().hide();
-        } else {
-            // we already grabed and started to drag'n'drop tab
-            // so we update drag'n'drop-rectangle
-            int dx = me.x_root - m_button_grab_x, dy = me.y_root - m_button_grab_y;
-
-            //erase rectangle
-            parent().drawRectangle(screen().rootTheme().opGC(),
-                                   m_last_move_x, m_last_move_y,
-                                   active_button.width(),
-                                   active_button.height());
-
-
-            // redraw rectangle at new pos
-            m_last_move_x = dx;
-            m_last_move_y = dy;
-            parent().drawRectangle(screen().rootTheme().opGC(),
-                                   m_last_move_x, m_last_move_y,
-                                   active_button.width(),
-                                   active_button.height());
+        // we already grabed and started to drag'n'drop tab
+        // so we update drag'n'drop-rectangle
+        int dx = me.x_root - m_button_grab_x, dy = me.y_root - m_button_grab_y;
 
+        parent().drawRectangle(screen().rootTheme().opGC(),
+                               m_last_move_x, m_last_move_y,
+                               m_last_resize_w, m_last_resize_h);
+        parent().drawRectangle(screen().rootTheme().opGC(),
+                               dx, dy,
+                               m_last_resize_w, m_last_resize_h);
 
-        }
+        // change remembered position of rectangle
+        m_last_move_x = dx;
+        m_last_move_y = dy;
     }
 
 }
@@ -3116,7 +3063,7 @@ void FluxboxWindow::startMoving(int x, int y) {
     Fluxbox *fluxbox = Fluxbox::instance();
     // grabbing (and masking) on the root window allows us to
     // freely map and unmap the window we're moving.
-    grabPointer(screen().rootWindow().window(), False, Button1MotionMask |
+    grabPointer(screen().rootWindow().window(), False, ButtonMotionMask |
                 ButtonReleaseMask, GrabModeAsync, GrabModeAsync,
                 screen().rootWindow().window(), frame().theme().moveCursor(), CurrentTime);
 
@@ -3467,14 +3414,64 @@ void FluxboxWindow::stopResizing(bool interrupted) {
     ungrabPointer(CurrentTime);
 }
 
+void FluxboxWindow::startTabbing(const XButtonEvent &be) {
+
+    if (s_num_grabs > 0)
+        return;
+
+    m_attaching_tab = 0;
+    // determine if we're in titlebar
+    Client2ButtonMap::iterator it =
+        find_if(m_labelbuttons.begin(),
+                m_labelbuttons.end(),
+                Compose(bind2nd(equal_to<Window>(), be.window),
+                        Compose(mem_fun(&TextButton::window),
+                                Select2nd<Client2ButtonMap::value_type>())));
+    if (it != m_labelbuttons.end())
+        m_attaching_tab = it->first;
+
+    // start drag'n'drop for tab
+    grabPointer(be.window, False, ButtonMotionMask |
+                ButtonReleaseMask, GrabModeAsync, GrabModeAsync,
+                None, frame().theme().moveCursor(), CurrentTime);
+
+    // relative position on the button
+    m_button_grab_x = be.x;
+    m_button_grab_y = be.y;
+    // position of the button
+    m_last_move_x = be.x_root - be.x;
+    m_last_move_y = be.y_root - be.y;
+    // hijack extra vars for initial grab location
+    m_last_resize_x = be.x_root;
+    m_last_resize_y = be.y_root;
+
+    Fluxbox::instance()->grab();
+
+    if (m_attaching_tab) {
+        FbTk::TextButton &active_button = *m_labelbuttons[m_attaching_tab];
+        m_last_resize_w = active_button.width();
+        m_last_resize_h = active_button.height();
+    } else {
+        m_attaching_tab = m_client;
+        unsigned int bw = 2*frame().window().borderWidth()-1;
+        m_last_resize_w = frame().width() + bw;
+        m_last_resize_h = frame().height() + bw;
+    }
+
+    parent().drawRectangle(screen().rootTheme().opGC(),
+                           m_last_move_x, m_last_move_y,
+                           m_last_resize_w, m_last_resize_h);
+
+    menu().hide();
+}
+
 void FluxboxWindow::attachTo(int x, int y, bool interrupted) {
     if (m_attaching_tab == 0)
         return;
 
     parent().drawRectangle(screen().rootTheme().opGC(),
                            m_last_move_x, m_last_move_y,
-                           m_labelbuttons[m_attaching_tab]->width(),
-                           m_labelbuttons[m_attaching_tab]->height());
+                           m_last_resize_w, m_last_resize_h);
 
     ungrabPointer(CurrentTime);
 
diff --git a/src/Window.hh b/src/Window.hh
index 821e86a..66c6f2b 100644
--- a/src/Window.hh
+++ b/src/Window.hh
@@ -393,6 +393,8 @@ public:
     ResizeDirection getResizeDirection(int x, int y, ResizeModel model);
     /// stops the resizing
     void stopResizing(bool interrupted = false);
+    /// starts tabbing
+    void startTabbing(const XButtonEvent &be);
 
     /**
        @name accessors
diff --git a/src/fluxbox.cc b/src/fluxbox.cc
index 9deb39b..341fda8 100644
--- a/src/fluxbox.cc
+++ b/src/fluxbox.cc
@@ -643,7 +643,7 @@ void Fluxbox::setupConfigFiles() {
     if (create_init)
         FbTk::FileUtil::copyFile(DEFAULT_INITFILE, init_file.c_str());
 
-#define CONFIG_VERSION 6
+#define CONFIG_VERSION 7
     FbTk::Resource<int> config_version(m_resourcemanager, 0,
             "session.configVersion", "Session.ConfigVersion");
     if (*config_version < CONFIG_VERSION) {
diff --git a/util/fluxbox-update_configs.cc b/util/fluxbox-update_configs.cc
index 921530a..75be474 100644
--- a/util/fluxbox-update_configs.cc
+++ b/util/fluxbox-update_configs.cc
@@ -275,6 +275,19 @@ int run_updates(int old_version, FbTk::ResourceManager &rm) {
         new_version = 6;
     }
 
+    if (old_version < 7) { // added StartTabbing command
+        string whole_keyfile = read_file(keyfilename);
+        string new_keyfile = "";
+        // let's put our new keybindings first, so they're easy to find
+        new_keyfile += "# start tabbing windows together\n";
+        new_keyfile += "OnTitlebar Mouse2 :StartTabbing\n\n";
+        new_keyfile += whole_keyfile; // don't forget user's old keybindings
+
+        write_file(keyfilename, new_keyfile);
+
+        new_version = 7;
+    }
+
     return new_version;
 }
 
-- 
cgit v0.11.2