From dd8fcc8b7b4c2bccf90edf9b0acfa52e21f5d1ce Mon Sep 17 00:00:00 2001
From: Henrik Kinnunen <fluxgen@fluxbox.org>
Date: Fri, 26 Mar 2010 18:15:45 +0100
Subject: Changed title signal in Focusable to new signal system

---
 src/ClientMenu.cc    | 58 +++++++++++++++++++++++++++++++++++-----------------
 src/ClientMenu.hh    |  6 ++++++
 src/Ewmh.cc          |  8 ++++----
 src/Focusable.hh     | 17 ++++++++-------
 src/FocusableList.cc | 27 ++++++++++++++++++------
 src/FocusableList.hh |  6 ++++++
 src/IconButton.cc    | 49 ++++++++++++++++++++++++++++----------------
 src/IconButton.hh    |  6 ++++++
 src/WinButton.cc     |  7 +++++--
 src/WinButton.hh     |  4 +++-
 src/WinClient.cc     |  6 +++---
 src/Window.cc        | 34 ++++++++++++++++--------------
 src/Window.hh        |  3 +++
 13 files changed, 156 insertions(+), 75 deletions(-)

diff --git a/src/ClientMenu.cc b/src/ClientMenu.cc
index 71f322c..02df7e4 100644
--- a/src/ClientMenu.cc
+++ b/src/ClientMenu.cc
@@ -37,10 +37,13 @@ public:
     ClientMenuItem(Focusable &client, ClientMenu &menu):
         FbTk::MenuItem(client.title().c_str(), menu),
         m_client(client) {
-            client.titleSig().attach(&menu);
-            client.dieSig().attach(&menu);
-        }
-    ~ClientMenuItem() { m_client.titleSig().detach(menu()); }
+        m_signals.join(client.titleSig(),
+                       FbTk::MemFunSelectArg1(menu, &ClientMenu::titleChanged));
+        client.dieSig().attach(&menu);
+    }
+
+    ~ClientMenuItem() {
+    }
 
     void click(int button, int time, unsigned int mods) {
         FluxboxWindow *fbwin = m_client.fbwindow();
@@ -75,6 +78,7 @@ public:
 
 private:
     Focusable &m_client;
+    FbTk::SignalTracker m_signals;
 };
 
 } // end anonymous namespace
@@ -118,30 +122,46 @@ void ClientMenu::refreshMenu() {
     updateMenu();
 }
 
+namespace {
+
+ClientMenuItem* getMenuItem(ClientMenu& menu, Focusable& win) {
+    // find the corresponding menuitem
+    ClientMenuItem *cl_item = 0;
+    for (size_t i = 0; i < menu.numberOfItems(); i++) {
+        FbTk::MenuItem *item = menu.find(i);
+        if (item && typeid(*item) == typeid(ClientMenuItem)) {
+            cl_item = static_cast<ClientMenuItem *>(item);
+            if (cl_item->client() == &win)
+                break;
+        }
+    }
+
+    return cl_item;
+
+}
+
+} // anonymous
+
+void ClientMenu::titleChanged(Focusable& win) {
+    // find correct menu item
+    ClientMenuItem* cl_item = getMenuItem(*this, win);
+    if (cl_item)
+        FbTk::Menu::update(0);
+}
+
 void ClientMenu::update(FbTk::Subject *subj) {
     if (subj && typeid(*subj) == typeid(Focusable::FocusSubject)) {
 
         Focusable::FocusSubject *fsubj = static_cast<Focusable::FocusSubject *>(subj);
         Focusable &win = fsubj->win();
 
-        // find the corresponding menuitem
-        ClientMenuItem *cl_item = 0;
-        for (size_t i = 0; i < numberOfItems(); i++) {
-            FbTk::MenuItem *item = find(i);
-            if (item && typeid(*item) == typeid(ClientMenuItem)) {
-                cl_item = static_cast<ClientMenuItem *>(item);
-                if (cl_item->client() == &win)
-                    break;
-            }
-        }
+        // find correct menu item
+        ClientMenuItem* cl_item = getMenuItem(*this, win);
 
         // update accordingly
-        if (cl_item && fsubj == &win.dieSig())
+        if (cl_item && fsubj == &win.dieSig()) {
             remove(cl_item->getIndex());
-        else if (cl_item && fsubj == &win.titleSig())
-            // this could change the size of the menu, so do a full update
-            FbTk::Menu::update(subj);
-
+        }
     } else
         FbTk::Menu::update(subj);
 }
diff --git a/src/ClientMenu.hh b/src/ClientMenu.hh
index f0b6ce4..4b5cedb 100644
--- a/src/ClientMenu.hh
+++ b/src/ClientMenu.hh
@@ -28,6 +28,8 @@
 
 class BScreen;
 class FluxboxWindow;
+class Focusable;
+
 /**
  * A menu holding a set of client menus.
  * @see WorkspaceMenu
@@ -47,6 +49,10 @@ public:
 
     /// refresh the entire menu
     void refreshMenu();
+
+    /// Called when window title changed.
+    void titleChanged(Focusable& win);
+
 private:
 
     void updateClientList(BScreen& screen) {
diff --git a/src/Ewmh.cc b/src/Ewmh.cc
index 3b4ea51..eadea4b 100644
--- a/src/Ewmh.cc
+++ b/src/Ewmh.cc
@@ -164,7 +164,7 @@ void extractNetWmIcon(Atom net_wm_icon, WinClient& winclient) {
         if (width >= nr_icon_data) {
 
             fbdbg << "Ewmh.cc extractNetWmIcon found strange _NET_WM_ICON width (" 
-                << width << ") for " << winclient.title() << "\n";
+                  << width << ") for " << winclient.title() << "\n";
             break;
         }
 
@@ -172,7 +172,7 @@ void extractNetWmIcon(Atom net_wm_icon, WinClient& winclient) {
         if (height >= nr_icon_data) {
 
             fbdbg << "Ewmh.cc extractNetWmIcon found strange _NET_WM_ICON height (" 
-                << height << ") for " << winclient.title() << "\n";
+                  << height << ") for " << winclient.title() << "\n";
 
             break;
         }
@@ -180,7 +180,7 @@ void extractNetWmIcon(Atom net_wm_icon, WinClient& winclient) {
         // strange values stored in the NETWM_ICON
         if (i + width * height > nr_icon_data) {
             fbdbg << "Ewmh.cc extractNetWmIcon found strange _NET_WM_ICON dimensions (" 
-                << width << "x" << height << ")for " << winclient.title() << "\n";
+                  << width << "x" << height << ")for " << winclient.title() << "\n";
 
             break;
         }
@@ -1293,7 +1293,7 @@ bool Ewmh::propertyNotify(WinClient &winclient, Atom the_property) {
         if (!newtitle.empty())
             winclient.setTitle(newtitle);
         if (winclient.fbwindow())
-            winclient.fbwindow()->titleSig().notify();
+            winclient.fbwindow()->titleSig().emit(newtitle, *winclient.fbwindow());
         return true;
     } else if (the_property == m_net->wm_icon_name) {
         // we don't use icon title, since we don't show icons
diff --git a/src/Focusable.hh b/src/Focusable.hh
index 6108ed9..8434a97 100644
--- a/src/Focusable.hh
+++ b/src/Focusable.hh
@@ -42,9 +42,10 @@ public:
         m_screen(scr), m_fbwin(fbwin),
         m_instance_name("fluxbox"), m_class_name("fluxbox"),
         m_focused(false), m_attention_state(false),
-        m_titlesig(*this), m_diesig(*this),
+        m_diesig(*this),
         m_attentionsig(*this),
-        m_focussig() { }
+        m_focussig(),
+        m_titlesig() { }
     virtual ~Focusable() { }
 
     /**
@@ -116,10 +117,11 @@ public:
        @name signals
        @{
     */
-    // Used for both title and icon changes.
-    FbTk::Subject &titleSig() { return m_titlesig; }
-    // Used for both title and icon changes.
-    const FbTk::Subject &titleSig() const { return m_titlesig; }
+    typedef FbTk::Signal<void, const std::string&, Focusable&> TitleSignal;
+    /// Used for both title and icon changes.
+    TitleSignal &titleSig() { return m_titlesig; }
+    /// Used for both title and icon changes.
+    const TitleSignal &titleSig() const { return m_titlesig; }
     FbTk::Signal<void, Focusable&> &focusSig() { return m_focussig; }
     const FbTk::Signal<void, Focusable&> &focusSig() const { return m_focussig; }
     FbTk::Subject &dieSig() { return m_diesig; }
@@ -143,10 +145,11 @@ protected:
     FbTk::PixmapWithMask m_icon; //< icon pixmap with mask
 
     // state and hint signals
-    FocusSubject m_titlesig, m_diesig, m_attentionsig;
+    FocusSubject m_diesig, m_attentionsig;
 
 private:
     FbTk::Signal<void, Focusable&> m_focussig;
+    TitleSignal m_titlesig;
 };
 
 #endif // FOCUSABLE_HH
diff --git a/src/FocusableList.cc b/src/FocusableList.cc
index b2b0320..77e0a76 100644
--- a/src/FocusableList.cc
+++ b/src/FocusableList.cc
@@ -113,10 +113,9 @@ void FocusableList::update(FbTk::Subject *subj) {
     if (typeid(*subj) == typeid(Focusable::FocusSubject)) {
         Focusable::FocusSubject *fsubj =
             static_cast<Focusable::FocusSubject *>(subj);
-        if (fsubj == &fsubj->win().dieSig())
+        if (fsubj == &fsubj->win().dieSig()) {
             remove(fsubj->win());
-        else if (fsubj == &fsubj->win().titleSig())
-            checkUpdate(fsubj->win());
+        }
     }
     if (typeid(*subj) == typeid(FluxboxWindow::WinSubject)) {
         FluxboxWindow::WinSubject *fsubj =
@@ -244,17 +243,27 @@ void FocusableList::remove(Focusable &win) {
     bool contained = contains(win);
 
     detachSignals(win);
-    if (!contained)
+    if (!contained) {
         return;
+    }
     m_list.remove(&win);
     m_removesig.notify(&win);
 }
 
+void FocusableList::updateTitle(Focusable& win) {
+    checkUpdate(win);
+}
+
 void FocusableList::attachSignals(Focusable &win) {
     win.dieSig().attach(this);
     if (m_parent) {
         // attach various signals for matching
-        win.titleSig().attach(this);
+        if (m_signal_map.find(&win) == m_signal_map.end()) {
+            m_signal_map[&win] = join(win.titleSig(),
+                                      MemFunSelectArg1(*this,
+                                                       &FocusableList::updateTitle));
+        }
+
         FluxboxWindow *fbwin = win.fbwindow();
         if (!fbwin)
             return;
@@ -268,8 +277,14 @@ void FocusableList::attachSignals(Focusable &win) {
 void FocusableList::detachSignals(Focusable &win) {
     win.dieSig().detach(this);
     if (m_parent) {
+        // disconnect client
+        SignalMap::iterator sigIt = m_signal_map.find(&win);
+        if (sigIt != m_signal_map.end()) {
+            leave(sigIt->second);
+            m_signal_map.erase(sigIt);
+        }
+
         // detach various signals for matching
-        win.titleSig().detach(this);
         FluxboxWindow *fbwin = win.fbwindow();
         if (!fbwin)
             return;
diff --git a/src/FocusableList.hh b/src/FocusableList.hh
index 58ef9b6..1382da6 100644
--- a/src/FocusableList.hh
+++ b/src/FocusableList.hh
@@ -116,12 +116,18 @@ private:
     void attachChild(FocusableList &child) const;
     void workspaceChanged(BScreen &screen);
     void focusedWindowChanged(BScreen &screen, FluxboxWindow *win, WinClient *client);
+    /// Title has changed for a window
+    /// @param win The window that title changed for.
+    void updateTitle(Focusable& win);
+
     std::auto_ptr<ClientPattern> m_pat;
     const FocusableList *m_parent;
     BScreen &m_screen;
     std::list<Focusable *> m_list;
 
     mutable FocusableListSubject m_ordersig, m_addsig, m_removesig, m_resetsig;
+    typedef std::map<Focusable*, FbTk::SignalTracker::TrackID> SignalMap;
+    SignalMap m_signal_map;
 };
 
 #endif // FOCUSABLELIST_HH
diff --git a/src/IconButton.cc b/src/IconButton.cc
index ce89651..320918c 100644
--- a/src/IconButton.cc
+++ b/src/IconButton.cc
@@ -59,15 +59,18 @@ IconButton::IconButton(const FbTk::FbWindow &parent,
     m_theme(win, focused_theme, unfocused_theme),
     m_pm(win.screen().imageControl()) {
 
-    m_win.titleSig().attach(this);
+    m_signals.join(m_win.titleSig(),
+                   MemFunIgnoreArgs(*this, &IconButton::clientTitleChanged));
+
     m_signals.join(m_win.focusSig(),
                    MemFunIgnoreArgs(*this, &IconButton::reconfigAndClear));
+
     m_win.attentionSig().attach(this);
 
     FbTk::EventManager::instance()->add(*this, m_icon_window);
 
     reconfigTheme();
-    update(0);
+    refreshEverything(false);
 }
 
 IconButton::~IconButton() {
@@ -102,7 +105,7 @@ void IconButton::moveResize(int x, int y,
     if (m_icon_window.width() != FbTk::Button::width() ||
         m_icon_window.height() != FbTk::Button::height()) {
         reconfigTheme();
-        update(0); // update icon window
+        refreshEverything(false); // update icon window
     }
 }
 
@@ -111,7 +114,7 @@ void IconButton::resize(unsigned int width, unsigned int height) {
     if (m_icon_window.width() != FbTk::Button::width() ||
         m_icon_window.height() != FbTk::Button::height()) {
         reconfigTheme();
-        update(0); // update icon window
+        refreshEverything(false); // update icon window
     }
 }
 
@@ -140,7 +143,7 @@ void IconButton::clearArea(int x, int y,
 void IconButton::setPixmap(bool use) {
     if (m_use_pixmap != use) {
         m_use_pixmap = use;
-        update(0);
+        refreshEverything(false);
     }
 }
 
@@ -175,16 +178,7 @@ void IconButton::reconfigAndClear() {
     clear();
 }
 
-void IconButton::update(FbTk::Subject *subj) {
-    // if the window's focus state changed, we need to update the background
-    if (subj == &m_win.attentionSig()) {
-        reconfigAndClear();
-        return;
-    }
-
-    // we got signal that either title or
-    // icon pixmap was updated,
-    // so we refresh everything
+void IconButton::refreshEverything(bool setup) {
 
     Display *display = FbTk::App::instance()->display();
     int screen = m_win.screen().screenNumber();
@@ -242,17 +236,36 @@ void IconButton::update(FbTk::Subject *subj) {
 
 #endif // SHAPE
 
-    if (subj != 0) {
+    if (setup) {
         setupWindow();
     } else {
         m_icon_window.clear();
     }
 
+
+}
+
+void IconButton::clientTitleChanged() {
+    refreshEverything(true);
+
+    if (m_has_tooltip)
+        showTooltip();
+}
+
+void IconButton::update(FbTk::Subject *subj) {
+    // if the window's focus state changed, we need to update the background
+    if (subj == &m_win.attentionSig()) {
+        reconfigAndClear();
+        return;
+    }
+
+    // we got signal that either title or
+    // icon pixmap was updated,
+    // so we refresh everything
     // if the title was changed AND the mouse is over *this,
     // update the tooltip
-    if (subj == &m_win.titleSig() && m_has_tooltip)
-        showTooltip();
 
+    refreshEverything(subj != 0);
 }
 
 void IconButton::setupWindow() {
diff --git a/src/IconButton.hh b/src/IconButton.hh
index 5a6af0d..d1eb17e 100644
--- a/src/IconButton.hh
+++ b/src/IconButton.hh
@@ -73,6 +73,12 @@ private:
     void setupWindow();
     void showTooltip();
 
+    /// Refresh all pixmaps and windows
+    /// @param setup Wether to setup window again.
+    void refreshEverything(bool setup);
+    /// Called when client title changed.
+    void clientTitleChanged();
+
     Focusable &m_win;
     FbTk::FbWindow m_icon_window;
     FbTk::FbPixmap m_icon_pixmap;
diff --git a/src/WinButton.cc b/src/WinButton.cc
index d64034e..9ecbb9c 100644
--- a/src/WinButton.cc
+++ b/src/WinButton.cc
@@ -278,8 +278,7 @@ void WinButton::clear() {
     FbTk::Button::clear();
     drawType();
 }
-
-void WinButton::update(FbTk::Subject *subj) {
+void WinButton::updateAll() {
 
     // update the menu icon
     if (m_type == MENUICON && !m_listen_to.empty()) {
@@ -316,3 +315,7 @@ void WinButton::update(FbTk::Subject *subj) {
 
     clear();
 }
+
+void WinButton::update(FbTk::Subject *subj) {
+    updateAll();
+}
diff --git a/src/WinButton.hh b/src/WinButton.hh
index 7f40f1a..a116a15 100644
--- a/src/WinButton.hh
+++ b/src/WinButton.hh
@@ -25,6 +25,7 @@
 #include "FbTk/Button.hh"
 #include "FbTk/Observer.hh"
 #include "FbTk/FbPixmap.hh"
+#include "FbTk/Signal.hh"
 
 class FluxboxWindow;
 class WinButtonTheme;
@@ -35,7 +36,7 @@ template <class T> class ThemeProxy;
 }
 
 /// draws and handles basic window button graphic
-class WinButton:public FbTk::Button, public FbTk::Observer {
+class WinButton:public FbTk::Button, public FbTk::Observer, public FbTk::SignalTracker {
 public:
     /// draw type for the button
     enum Type {MAXIMIZE, MINIMIZE, SHADE, STICK, CLOSE, MENUICON};
@@ -57,6 +58,7 @@ public:
     /// override for redrawing
     void clear();
     void update(FbTk::Subject *subj);
+    void updateAll();
 private:
     void drawType();
     Type m_type; ///< the button type
diff --git a/src/WinClient.cc b/src/WinClient.cc
index 6ec15f3..7a10c12 100644
--- a/src/WinClient.cc
+++ b/src/WinClient.cc
@@ -341,13 +341,13 @@ void WinClient::updateTitle() {
         return;
 
     m_title = string(Xutil::getWMName(window()), 0, 512);
-    titleSig().notify();
+    titleSig().emit(m_title, *this);
 }
 
 void WinClient::setTitle(const FbTk::FbString &title) {
     m_title = title;
     m_title_override = true;
-    titleSig().notify();
+    titleSig().emit(m_title, *this);
 }
 
 void WinClient::setIcon(const FbTk::PixmapWithMask& pm) {
@@ -355,7 +355,7 @@ void WinClient::setIcon(const FbTk::PixmapWithMask& pm) {
     m_icon.pixmap().copy(pm.pixmap());
     m_icon.mask().copy(pm.mask());
     m_icon_override = true;
-    titleSig().notify();
+    titleSig().emit(m_title, *this);
 }
 
 void WinClient::setFluxboxWindow(FluxboxWindow *win) {
diff --git a/src/Window.cc b/src/Window.cc
index 34b5d0c..586dc7b 100644
--- a/src/Window.cc
+++ b/src/Window.cc
@@ -988,7 +988,7 @@ bool FluxboxWindow::setCurrentClient(WinClient &client, bool setinput) {
         button<<endl;
 
     if (old != &client) {
-        titleSig().notify();
+        titleSig().emit(title(), *this);
         frame().setFocusTitle(title());
         frame().setShapingClient(&client, false);
     }
@@ -2103,7 +2103,7 @@ void FluxboxWindow::propertyNotifyEvent(WinClient &client, Atom atom) {
 
     case XA_WM_HINTS:
         client.updateWMHints();
-        titleSig().notify();
+        titleSig().emit(title(), *this);
         // nothing uses this yet
         // hintSig().notify(); // notify listeners
         break;
@@ -2707,18 +2707,19 @@ void FluxboxWindow::leaveNotifyEvent(XCrossingEvent &ev) {
     //installColormap(false);
 }
 
-void FluxboxWindow::update(FbTk::Subject *subj) {
-    if (subj && typeid(*subj) == typeid(Focusable::FocusSubject)) {
-        Focusable::FocusSubject &fsubj =
-                static_cast<Focusable::FocusSubject &>(*subj);
-        Focusable &win = fsubj.win();
-
-        if (&fsubj == &win.titleSig() && &win == m_client) {
-            frame().setFocusTitle(win.title());
-            titleSig().notify();
-        }
+void FluxboxWindow::setTitle(const std::string& title, Focusable &client) {
+    // only update focus title for current client
+    if (&client != m_client) {
+        return;
+    }
 
-    } else if (subj == &m_theme.reconfigSig()) {
+    frame().setFocusTitle(title);
+    // relay title to others that display the focus title
+    titleSig().emit(title, *this);
+}
+
+void FluxboxWindow::update(FbTk::Subject *subj) {
+    if (subj == &m_theme.reconfigSig()) {
         frame().applyDecorations();
         sendConfigureNotify();
     } else if (m_initialized && subj == &m_frame.frameExtentSig()) {
@@ -3637,7 +3638,9 @@ void FluxboxWindow::updateButtons() {
                                        dir[i],
                                        frame().titlebar(),
                                        0, 0, 10, 10);
-                titleSig().attach(winbtn);
+                winbtn->join(titleSig(),
+                             FbTk::MemFunIgnoreArgs(*winbtn, &WinButton::updateAll));
+
                 winbtn->setOnClick(show_menu_cmd);
                 break;
             }
@@ -3709,7 +3712,8 @@ void FluxboxWindow::associateClient(WinClient &client) {
     evm.add(*this, btn->window()); // we take care of button events for this
     evm.add(*this, client.window());
     client.setFluxboxWindow(this);
-    client.titleSig().attach(this);
+    join(client.titleSig(),
+         FbTk::MemFun(*this, &FluxboxWindow::setTitle));
 }
 
 FluxboxWindow::ReferenceCorner FluxboxWindow::getCorner(string str) {
diff --git a/src/Window.hh b/src/Window.hh
index 9cefd55..a097ac6 100644
--- a/src/Window.hh
+++ b/src/Window.hh
@@ -474,6 +474,9 @@ public:
     bool oplock; ///< Used to help stop transient loops occurring by locking a window during certain operations
 
 private:
+    /// signal callback for title changes by clients
+    void setTitle(const std::string &title, Focusable &client);
+
     void setupWindow();
     void updateButtons();
 
-- 
cgit v0.11.2