From 037bd174bfb107fef4657c949ce49c188090f3e7 Mon Sep 17 00:00:00 2001
From: rathnor <rathnor>
Date: Sun, 20 Jul 2003 18:05:40 +0000
Subject: fix focus and raising for transient windows in particular

---
 BUGS                   | 12 +++++----
 ChangeLog              |  3 +++
 src/FbTk/Menu.hh       |  3 +--
 src/FbTk/MultLayers.cc |  8 ++++--
 src/FbTk/MultLayers.hh |  8 +++++-
 src/FbTk/XLayer.cc     |  7 ++++-
 src/WinClient.cc       | 21 ++++++++++++---
 src/WinClient.hh       | 11 +++++---
 src/Window.cc          | 70 ++++++++++++++++++++++++++++++--------------------
 src/fluxbox.cc         | 12 +++++----
 10 files changed, 104 insertions(+), 51 deletions(-)

diff --git a/BUGS b/BUGS
index 0ceb3ac..8250bbd 100644
--- a/BUGS
+++ b/BUGS
@@ -14,14 +14,10 @@ BUGS:
   * After startup the font of the toolbar is to big; reload config works
     around this.
     => is this fixed now?? (as of ResourceManager changes)
+    => Don't think so, extra info = seems to happen for Multiple screens
 
   * Saving of number of workspaces on restart
 
-  * Multiple transients:
-    in openoffice - focus jumps between until user does something
-    in mozilla    - alt-tabbing does strange thigns with other transient
-                    layer-wise (other transient flashes)
-
   * gaim (0.64) crashes when remembering dimensions... is this a gaim
     bug?
 
@@ -78,6 +74,12 @@ Fixed bugs (or not-our-fault bugs):
     indicate the change until you point to another option.
     => Fixed
 
+  * Multiple transients:
+    in openoffice - focus jumps between until user does something
+    in mozilla    - alt-tabbing does strange thigns with other transient
+                    layer-wise (other transient flashes)
+    => fixed
+
 ------------------------------
 Core dumps and notes
 
diff --git a/ChangeLog b/ChangeLog
index 50bebe3..5622ba0 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,6 +1,9 @@
 (Format: Year/Month/Day)
 Changes for 0.9.5:
 *03/07/20:
+   * Fix aspects of focus and raising, including transients (Simon)
+     - fixes focus toggling with transients and sloppy focus
+     WinClient.hh/cc Window.cc fluxbox.cc MultLayers.hh/cc XLayer.hh/cc Menu.hh
    * Fix menu [re]drawing, particularly when selecting options (Simon)
      Menu.hh/cc
    * Fix disappearing Remember menu, plus titles of sub-window menus
diff --git a/src/FbTk/Menu.hh b/src/FbTk/Menu.hh
index 9ab69b4..fba7ae2 100644
--- a/src/FbTk/Menu.hh
+++ b/src/FbTk/Menu.hh
@@ -22,7 +22,7 @@
 // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
 // DEALINGS IN THE SOFTWARE.
 
-// $Id: Menu.hh,v 1.21 2003/07/20 10:41:56 rathnor Exp $
+// $Id: Menu.hh,v 1.22 2003/07/20 18:05:39 rathnor Exp $
 
 #ifndef	 FBTK_MENU_HH
 #define	 FBTK_MENU_HH
@@ -37,7 +37,6 @@
 #include "RefCount.hh"
 #include "Command.hh"
 #include "Observer.hh"
-#include "XLayerItem.hh"
 #include "FbPixmap.hh"
 #include "MenuTheme.hh"
 
diff --git a/src/FbTk/MultLayers.cc b/src/FbTk/MultLayers.cc
index fea4dae..9e3272b 100644
--- a/src/FbTk/MultLayers.cc
+++ b/src/FbTk/MultLayers.cc
@@ -20,7 +20,7 @@
 // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
 // DEALINGS IN THE SOFTWARE.
 
-// $Id: MultLayers.cc,v 1.6 2003/02/18 15:08:12 rathnor Exp $
+// $Id: MultLayers.cc,v 1.7 2003/07/20 18:05:39 rathnor Exp $
 
 #include "MultLayers.hh"
 #include "XLayer.hh"
@@ -32,7 +32,9 @@ using namespace std;
 
 using namespace FbTk;
 
-MultLayers::MultLayers(int numlayers) {
+MultLayers::MultLayers(int numlayers) :
+    m_lock(0) 
+{
     for (int i=0; i < numlayers; ++i) 
         m_layers.push_back(new XLayer(*this, i));
 }
@@ -150,6 +152,8 @@ void MultLayers::moveToLayer(XLayerItem &item, int layernum) {
 }
 
 void MultLayers::restack() {
+    if (!isUpdatable()) 
+        return;
 
     int layernum=0, winnum=0, size = this->size();
 
diff --git a/src/FbTk/MultLayers.hh b/src/FbTk/MultLayers.hh
index 5cfc731..29c80a8 100644
--- a/src/FbTk/MultLayers.hh
+++ b/src/FbTk/MultLayers.hh
@@ -20,7 +20,7 @@
 // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
 // DEALINGS IN THE SOFTWARE.
 
-// $Id: MultLayers.hh,v 1.5 2003/02/09 14:11:14 rathnor Exp $
+// $Id: MultLayers.hh,v 1.6 2003/07/20 18:05:40 rathnor Exp $
 
 #ifndef FBTK_MULTLAYERS_HH
 #define FBTK_MULTLAYERS_HH
@@ -59,9 +59,15 @@ public:
     XLayer *getLayer(size_t num);
     const XLayer *getLayer(size_t num) const;
 
+    inline bool isUpdatable() const { return m_lock == 0; }
+    inline void lock() { ++m_lock; }
+    inline void unlock() { if (--m_lock == 0) restack(); }
+
 private:
     std::vector<XLayer *> m_layers;
 
+    int m_lock;
+
 };
 
 };
diff --git a/src/FbTk/XLayer.cc b/src/FbTk/XLayer.cc
index 023a80d..8164444 100644
--- a/src/FbTk/XLayer.cc
+++ b/src/FbTk/XLayer.cc
@@ -20,7 +20,7 @@
 // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
 // DEALINGS IN THE SOFTWARE.
 
-// $Id: XLayer.cc,v 1.8 2003/04/15 23:20:31 rathnor Exp $
+// $Id: XLayer.cc,v 1.9 2003/07/20 18:05:40 rathnor Exp $
 
 #include "XLayer.hh"
 #include "XLayerItem.hh"
@@ -39,6 +39,9 @@ XLayer::~XLayer() {
 }
 
 void XLayer::restack() {
+    if (!m_manager.isUpdatable())
+        return;
+
     int num_windows = countWindows();
 
     // each LayerItem can contain several windows
@@ -78,6 +81,8 @@ int XLayer::countWindows() {
 
 // Stack all windows associated with 'item' below the 'above' item
 void XLayer::stackBelowItem(XLayerItem *item, XLayerItem *above) {
+    if (!m_manager.isUpdatable())
+        return;
 
     Window *winlist;
     size_t winnum, size, num = item->numWindows();
diff --git a/src/WinClient.cc b/src/WinClient.cc
index ddd3cd1..416dd63 100644
--- a/src/WinClient.cc
+++ b/src/WinClient.cc
@@ -19,7 +19,7 @@
 // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
 // DEALINGS IN THE SOFTWARE.
 
-// $Id: WinClient.cc,v 1.17 2003/07/10 11:58:13 fluxgen Exp $
+// $Id: WinClient.cc,v 1.18 2003/07/20 18:05:39 rathnor Exp $
 
 #include "WinClient.hh"
 
@@ -54,7 +54,7 @@ WinClient::WinClient(Window win, BScreen &screen, FluxboxWindow *fbwin):FbTk::Fb
                      wm_hint_flags(0),
                      send_focus_message(false),
                      m_win(fbwin),
-                     modal(false),
+                     m_modal(0),
                      m_title(""), m_icon_title(""),
                      m_class_name(""), m_instance_name(""),
                      m_blackbox_hint(0),
@@ -245,8 +245,9 @@ void WinClient::updateTransientInfo() {
         return;
 	
     if (win != None && m_win->screen().rootWindow() == win) {
-        modal = true;
-        return; // transient for root window...
+        // transient for root window... =  transient for group
+        // I don't think we are group-aware yet
+        return; 
     }
 
     FluxboxWindow *transient_win = Fluxbox::instance()->searchWindow(win);
@@ -514,3 +515,15 @@ bool WinClient::hasGroupLeftWindow() const {
     }
     return false;
 }
+
+void WinClient::addModal() {
+    ++m_modal;
+    if (transient_for)
+        transient_for->addModal();
+}
+
+void WinClient::removeModal() {
+    --m_modal;
+    if (transient_for)
+        transient_for->removeModal();
+}
diff --git a/src/WinClient.hh b/src/WinClient.hh
index c72208f..cedbdd7 100644
--- a/src/WinClient.hh
+++ b/src/WinClient.hh
@@ -19,7 +19,7 @@
 // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
 // DEALINGS IN THE SOFTWARE.
 
-// $Id: WinClient.hh,v 1.8 2003/06/23 14:16:05 rathnor Exp $
+// $Id: WinClient.hh,v 1.9 2003/07/20 18:05:39 rathnor Exp $
 
 #ifndef WINCLIENT_HH
 #define WINCLIENT_HH
@@ -70,7 +70,10 @@ public:
     TransientList &transientList() { return transients; }
     const TransientList &transientList() const { return transients; }
     bool isTransient() const { return transient_for != 0; }
-    bool isModal() const { return modal; }
+
+    bool isModal() const { return m_modal > 0; }
+    void addModal(); // some transient of ours (or us) is modal
+    void removeModal(); // some transient (or us) is no longer modal
 
     bool operator == (const FluxboxWindow &win) const {
         return (m_win == &win);
@@ -138,7 +141,9 @@ public:
     enum { F_NOINPUT = 0, F_PASSIVE, F_LOCALLYACTIVE, F_GLOBALLYACTIVE };
 
 private:
-    bool modal;
+    // number of transients which we are modal for
+    // or indicates that we are modal if don't have any transients
+    int m_modal;
 
     std::string m_title, m_icon_title;
     std::string m_class_name, m_instance_name;
diff --git a/src/Window.cc b/src/Window.cc
index bfb7dae..4e45370 100644
--- a/src/Window.cc
+++ b/src/Window.cc
@@ -22,7 +22,7 @@
 // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
 // DEALINGS IN THE SOFTWARE.
 
-// $Id: Window.cc,v 1.206 2003/07/20 08:12:36 rathnor Exp $
+// $Id: Window.cc,v 1.207 2003/07/20 18:05:39 rathnor Exp $
 
 #include "Window.hh"
 
@@ -145,6 +145,11 @@ void raiseFluxboxWindow(FluxboxWindow &win) {
     if (win.oplock) return;
     win.oplock = true;
 
+    // we need to lock actual restacking so that raising above active transient
+    // won't do anything nasty
+    if (!win.winClient().transientList().empty())
+        win.screen().layerManager().lock();
+
     if (!win.isIconic()) {
         win.screen().updateNetizenWindowRaise(win.clientWindow());
         win.layerItem().raise();
@@ -159,6 +164,9 @@ void raiseFluxboxWindow(FluxboxWindow &win) {
             raiseFluxboxWindow(*(*it)->fbwindow());
     }
     win.oplock = false;
+
+    if (!win.winClient().transientList().empty())
+        win.screen().layerManager().unlock();
 }
 
 /// lower window and do the same for each transient it holds
@@ -166,6 +174,11 @@ void lowerFluxboxWindow(FluxboxWindow &win) {
     if (win.oplock) return;
     win.oplock = true;
 
+    // we need to lock actual restacking so that raising above active transient
+    // won't do anything nasty
+    if (!win.winClient().transientList().empty())
+        win.screen().layerManager().lock();
+
     if (!win.isIconic()) {
         win.screen().updateNetizenWindowLower(win.clientWindow());
         win.layerItem().lower();
@@ -179,6 +192,8 @@ void lowerFluxboxWindow(FluxboxWindow &win) {
             lowerFluxboxWindow(*(*it)->fbwindow());
     }
     win.oplock = false;
+    if (!win.winClient().transientList().empty())
+        win.screen().layerManager().unlock();
 }
 
 /// raise window and do the same for each transient it holds
@@ -186,6 +201,9 @@ void tempRaiseFluxboxWindow(FluxboxWindow &win) {
     if (win.oplock) return;
     win.oplock = true;
 
+    if (!win.winClient().transientList().empty())
+        win.screen().layerManager().lock();
+
     if (!win.isIconic()) {
         // don't update netizen, as it is only temporary
         win.layerItem().tempRaise();
@@ -200,6 +218,10 @@ void tempRaiseFluxboxWindow(FluxboxWindow &win) {
             tempRaiseFluxboxWindow(*(*it)->fbwindow());
     }
     win.oplock = false;
+
+    if (!win.winClient().transientList().empty())
+        win.screen().layerManager().unlock();
+
 }
 
 class SetClientCmd:public FbTk::Command {
@@ -1107,8 +1129,6 @@ bool FluxboxWindow::setInputFocus() {
     if (! validateClient())
         return false;
 
-    bool ret = false;
-
     if (!m_client->transients.empty() && m_client->isModal()) {
         WinClient::TransientList::iterator it = m_client->transients.begin();
         WinClient::TransientList::iterator it_end = m_client->transients.end();
@@ -1116,30 +1136,19 @@ bool FluxboxWindow::setInputFocus() {
             if ((*it)->isModal())
                 return (*it)->fbwindow()->setCurrentClient(**it, true);
         }
+    } 
+    if (m_client->getFocusMode() == WinClient::F_LOCALLYACTIVE ||
+        m_client->getFocusMode() == WinClient::F_PASSIVE) {
+        m_client->setInputFocus(RevertToPointerRoot, CurrentTime);
     } else {
-        if (m_client->getFocusMode() == WinClient::F_LOCALLYACTIVE ||
-            m_client->getFocusMode() == WinClient::F_PASSIVE) {
-            m_client->setInputFocus(RevertToPointerRoot, CurrentTime);
-        } else {
-            return false;
-        }
-
-	screen().setFocusedWindow(*m_client);
-
-        Fluxbox::instance()->setFocusedWindow(this);
-
-        frame().setFocus(true);
-
-        m_client->sendFocus();
-
-        if ((screen().isSloppyFocus() || screen().isSemiSloppyFocus())
-            && screen().doAutoRaise())
-            m_timer.start();
-
-        ret = true;
+        return false;
     }
 
-    return ret;
+    if ((screen().isSloppyFocus() || screen().isSemiSloppyFocus())
+        && screen().doAutoRaise())
+        m_timer.start();
+
+    return true;
 }
 
 void FluxboxWindow::hide() {
@@ -1224,8 +1233,9 @@ void FluxboxWindow::deiconify(bool reassoc, bool do_raise) {
 
     frame().show();
 
-    if (was_iconic && screen().doFocusNew())
+    if (was_iconic && screen().doFocusNew()) {
         setInputFocus();
+    }
 
     if (focused != frame().focused())
         frame().setFocus(focused);
@@ -1579,9 +1589,11 @@ void FluxboxWindow::setFocusFlag(bool focus) {
     if (focused)
         gettimeofday(&m_last_focus_time, 0);
 
+    screen().setFocusedWindow(*m_client);
+    m_client->sendFocus();
     frame().setFocus(focus);
 
-    if ((screen().isSloppyFocus() || screen().isSemiSloppyFocus()) &&
+    if (!focused && (screen().isSloppyFocus() || screen().isSemiSloppyFocus()) &&
         screen().doAutoRaise())
         m_timer.stop();
 }
@@ -2042,8 +2054,9 @@ void FluxboxWindow::mapNotifyEvent(XMapEvent &ne) {
 
         setState(NormalState);		
 			
-        if (client->isTransient() || screen().doFocusNew())
+        if (client->isTransient() || screen().doFocusNew()) {
             setInputFocus();
+        }
         else
             setFocusFlag(false);			
 
@@ -2555,8 +2568,9 @@ void FluxboxWindow::enterNotifyEvent(XCrossingEvent &ev) {
             
             // if client is set, use setCurrent client, otherwise just setInputFocus
             if ((!sa.leave || sa.inferior) && 
-                ((client && setCurrentClient(*client, true)) || setInputFocus()))
+                ((client && setCurrentClient(*client, true)) || setInputFocus())) {
                 installColormap(True);
+            }
         }        
     }
 }
diff --git a/src/fluxbox.cc b/src/fluxbox.cc
index 027da76..b7a4d5b 100644
--- a/src/fluxbox.cc
+++ b/src/fluxbox.cc
@@ -22,7 +22,7 @@
 // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
 // DEALINGS IN THE SOFTWARE.
 
-// $Id: fluxbox.cc,v 1.171 2003/07/18 15:40:55 rathnor Exp $
+// $Id: fluxbox.cc,v 1.172 2003/07/20 18:05:39 rathnor Exp $
 
 #include "fluxbox.hh"
 
@@ -891,11 +891,13 @@ void Fluxbox::handleEvent(XEvent * const e) {
             break;
 
         FluxboxWindow *win = searchWindow(e->xfocus.window);
-        if (win && ! win->isFocused())
+        if (win && ! win->isFocused()) {
             setFocusedWindow(win);
+        }
 	
     } break;
     case FocusOut:{
+
         if (e->xfocus.mode == NotifyUngrab ||
             e->xfocus.detail == NotifyPointer)
             break;
@@ -904,8 +906,7 @@ void Fluxbox::handleEvent(XEvent * const e) {
 #ifdef DEBUG
             cerr<<__FILE__<<"("<<__FUNCTION__<<") Focus out is not a FluxboxWindow !!"<<endl;
 #endif // DEBUG
-            if (getFocusedWindow())
-                getFocusedWindow()->setInputFocus();
+
         }
     }
 	break;
@@ -1084,8 +1085,9 @@ void Fluxbox::handleClientMessage(XClientMessageEvent &ce) {
 				
     } else if (ce.message_type == m_fbatoms->getFluxboxChangeWindowFocusAtom()) {
         FluxboxWindow *win = searchWindow(ce.window);
-        if (win && win->isVisible() && win->setInputFocus())
+        if (win && win->isVisible() && win->setInputFocus()) {
             win->installColormap(true);
+        }
     } else if (ce.message_type == m_fbatoms->getFluxboxCycleWindowFocusAtom()) {
         BScreen *screen = searchScreen(ce.window);
 
-- 
cgit v0.11.2