From 925f968a6af7765f3a37e54eb80483fb87e74449 Mon Sep 17 00:00:00 2001
From: fluxgen <fluxgen>
Date: Mon, 8 Sep 2003 17:52:34 +0000
Subject: add iconbar mode

---
 src/IconbarTool.cc | 400 ++++++++++++++++++++++++++++++++++++++++++++---------
 src/IconbarTool.hh |  34 ++++-
 2 files changed, 363 insertions(+), 71 deletions(-)

diff --git a/src/IconbarTool.cc b/src/IconbarTool.cc
index f7f9954..fcaac39 100644
--- a/src/IconbarTool.cc
+++ b/src/IconbarTool.cc
@@ -20,31 +20,177 @@
 // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
 // DEALINGS IN THE SOFTWARE.
 
-// $Id: IconbarTool.cc,v 1.9 2003/08/18 11:13:32 fluxgen Exp $
+// $Id: IconbarTool.cc,v 1.10 2003/09/08 17:52:34 fluxgen Exp $
 
 #include "IconbarTool.hh"
 
 #include "Screen.hh"
-#include "ImageControl.hh"
 #include "IconbarTheme.hh"
 #include "Window.hh"
 #include "IconButton.hh"
 #include "Workspace.hh"
+#include "fluxbox.hh"
+
+
+#include "FbTk/Menu.hh"
+#include "FbTk/MenuItem.hh"
+#include "FbTk/RefCount.hh"
+#include "FbTk/SimpleCommand.hh"
+#include "FbTk/ImageControl.hh"
 
 #include <typeinfo>
+#include <string>
+#include <iterator>
+#include <iostream>
+using namespace std;
+
+template<>
+void FbTk::Resource<IconbarTool::Mode>::setFromString(const char *strval) {
+    if (strcasecmp(strval, "None") == 0) 
+        m_value = IconbarTool::NONE;
+    else if (strcasecmp(strval, "Icons") == 0) 
+        m_value = IconbarTool::ICONS;
+    else if (strcasecmp(strval, "WorkspaceIcons") == 0) 
+        m_value = IconbarTool::WORKSPACEICONS;
+    else if (strcasecmp(strval, "Workspace") == 0) 
+        m_value = IconbarTool::WORKSPACE;
+    else if (strcasecmp(strval, "AllWindows") == 0) 
+        m_value = IconbarTool::ALLWINDOWS;
+    else
+        setDefaultValue();
+}
+
+
+template<>
+string FbTk::Resource<IconbarTool::Mode>::getString() {
+
+    switch (m_value) {
+    case IconbarTool::NONE:
+        return string("None");
+        break;
+    case IconbarTool::ICONS:
+        return string("Icons");
+        break;
+    case IconbarTool::WORKSPACEICONS:
+        return string("WorkspaceIcons");
+        break;
+    case IconbarTool::WORKSPACE:
+        return string("Workspace");
+        break;
+    case IconbarTool::ALLWINDOWS:
+        return string("AllWindows");
+        break;
+    }
+    // default string
+    return string("Icons");
+}
+
+namespace {
+
+class ToolbarModeMenuItem : public FbTk::MenuItem {
+public:
+    ToolbarModeMenuItem(const char *label, IconbarTool &handler, 
+                        IconbarTool::Mode mode, 
+                        FbTk::RefCount<FbTk::Command> &cmd):
+        FbTk::MenuItem(label, cmd), m_handler(handler), m_mode(mode) {
+    }
+    bool isEnabled() const { return m_handler.mode() != m_mode; }
+    void click(int button, int time) {
+        m_handler.setMode(m_mode);
+        FbTk::MenuItem::click(button, time);
+    }
+
+private:
+    IconbarTool &m_handler;
+    IconbarTool::Mode m_mode;
+};
+
+void setupModeMenu(FbTk::Menu &menu, IconbarTool &handler) {
+    using namespace FbTk;
+
+    // TODO: nls
+    menu.setLabel("Iconbar Mode");
+
+    RefCount<Command> saverc_cmd(new SimpleCommand<Fluxbox>(
+                                                            *Fluxbox::instance(), 
+                                                            &Fluxbox::save_rc));
+    
+    //TODO: nls
+    menu.insert(new ToolbarModeMenuItem("None", handler, 
+                                        IconbarTool::NONE, saverc_cmd));
+    menu.insert(new ToolbarModeMenuItem("Icons", handler, 
+                                        IconbarTool::ICONS, saverc_cmd));
+    menu.insert(new ToolbarModeMenuItem("Workspace Icons", handler, 
+                                        IconbarTool::WORKSPACEICONS, saverc_cmd));
+    menu.insert(new ToolbarModeMenuItem("Workspace", handler, 
+                                        IconbarTool::WORKSPACE, saverc_cmd));
+    menu.insert(new ToolbarModeMenuItem("All Windows", handler, 
+                                        IconbarTool::ALLWINDOWS, saverc_cmd));
+    menu.update();
+}
+                
+inline bool checkAddWindow(IconbarTool::Mode mode, const FluxboxWindow &win) {
+
+    // just add the icons that are on the this workspace
+    switch (mode) {
+    case IconbarTool::NONE:
+        break;
+    case IconbarTool::ICONS:
+        if (win.isIconic())
+            return true;
+        break;
+    case IconbarTool::WORKSPACEICONS:
+        if(win.workspaceNumber() == win.screen().currentWorkspaceID() &&
+           win.isIconic())
+            return true;
+        break;
+    case IconbarTool::WORKSPACE:
+        if (win.workspaceNumber() == win.screen().currentWorkspaceID())
+            return true;
+        break;
+    case IconbarTool::ALLWINDOWS:
+        return true;
+        break;
+    }
+
+    return false;
+}
+
+void removeDuplicate(const IconbarTool::IconList &iconlist, std::list<FluxboxWindow *> &windowlist) {
+    IconbarTool::IconList::const_iterator win_it = iconlist.begin();
+    IconbarTool::IconList::const_iterator win_it_end = iconlist.end();
+    std::list<FluxboxWindow *>::iterator remove_it = windowlist.end();
+    for (; win_it != win_it_end; ++win_it)
+        remove_it = remove(windowlist.begin(), remove_it, &(*win_it)->win());
+
+    // remove already existing windows
+    windowlist.erase(remove_it, windowlist.end());
+
+}
+
+}; // end anonymous namespace
 
-IconbarTool::IconbarTool(const FbTk::FbWindow &parent, IconbarTheme &theme, BScreen &screen):
+IconbarTool::IconbarTool(const FbTk::FbWindow &parent, IconbarTheme &theme, BScreen &screen,
+                         FbTk::Menu &menu):
     ToolbarItem(ToolbarItem::RELATIVE),
     m_screen(screen),
     m_icon_container(parent),
     m_theme(theme),
     m_focused_pm(0),
     m_unfocused_pm(0),
-    m_empty_pm(0) {
+    m_empty_pm(0),
+    m_rc_mode(screen.resourceManager(), WORKSPACE,
+              screen.name() + ".iconbar.mode", screen.altName() + ".Iconbar.Mode"),
+    m_menu(*screen.menuTheme(), menu.screenNumber(), screen.imageControl()) {
+
+    // setup menu
+    setupModeMenu(m_menu, *this);
+    menu.insert(m_menu.label().c_str(), &m_menu);
 
     // setup signals
     theme.reconfigSig().attach(this);
     screen.clientListSig().attach(this);
+    screen.iconListSig().attach(this);
     screen.currentWorkspaceSig().attach(this);
 
     update(0);
@@ -88,6 +234,41 @@ void IconbarTool::hide() {
     m_icon_container.hide();
 }
 
+void IconbarTool::setMode(Mode mode) {
+    if (mode == *m_rc_mode)
+        return;
+
+    *m_rc_mode = mode;
+
+    // lock graphics update
+    m_icon_container.setUpdateLock(true);
+
+    deleteIcons();
+
+    // update mode
+    switch (*m_rc_mode) {
+    case NONE:
+        break;
+    case ICONS:
+    case WORKSPACEICONS:
+        updateIcons();
+        break;
+    case WORKSPACE:
+        updateWorkspace();
+        break;
+    case ALLWINDOWS:
+        updateAllWindows();
+        break;
+    };
+
+    // unlock graphics update
+    m_icon_container.setUpdateLock(false);
+    m_icon_container.update();
+    m_icon_container.showSubwindows();
+
+    renderTheme();
+}
+
 unsigned int IconbarTool::width() const {
     return m_icon_container.width();
 }
@@ -105,7 +286,14 @@ void IconbarTool::update(FbTk::Subject *subj) {
     if (m_screen.isShuttingdown())
         return;
 
-    // just focus signal?
+    if (mode() == NONE) {
+        if (typeid(*subj) == typeid(FbTk::Theme))
+            renderTheme();
+                
+        return;
+    }
+
+    // handle window signal
     if (subj != 0 && typeid(*subj) == typeid(FluxboxWindow::WinSubject)) {
         // we handle everything except die signal here
         FluxboxWindow::WinSubject *winsubj = static_cast<FluxboxWindow::WinSubject *>(subj);
@@ -113,83 +301,80 @@ void IconbarTool::update(FbTk::Subject *subj) {
             renderWindow(winsubj->win());
             return;
         } else if (subj == &(winsubj->win().workspaceSig())) {
+            // we can ignore this signal if we're in ALLWINDOWS mode
+            if (mode() == ALLWINDOWS)
+                return;
+
             // workspace changed for this window, and if it's not on current workspace we remove it
-            if (m_screen.currentWorkspaceID() != winsubj->win().workspaceNumber())
+            if (m_screen.currentWorkspaceID() != winsubj->win().workspaceNumber()) {
                 removeWindow(winsubj->win());
+                renderTheme();
+            }
             return;
-        } else { // die sig
+        } else if (subj == &(winsubj->win().dieSig())) { // die sig
             removeWindow(winsubj->win());
+            renderTheme();
             return; // we don't need to update the entire list
+        } else if (subj == &(winsubj->win().stateSig())) {
+            if (mode() == ICONS || mode() == WORKSPACEICONS) {
+                if (!winsubj->win().isIconic()) {
+                    removeWindow(winsubj->win());
+                    renderTheme();
+                }
+            } else {
+                if (winsubj->win().isIconic()) {
+                    removeWindow(winsubj->win());
+                    renderTheme();
+                }
+            }
+            return;
+        } else {
+            // signal not handled
+            return;
         }
     }
 
     bool remove_all = false; // if we should readd all windows    
 
-    if (subj != 0 && typeid(*subj) == typeid(BScreen::ScreenSubject)) {
+    if (subj != 0 && typeid(*subj) == typeid(BScreen::ScreenSubject) && mode() != ALLWINDOWS) {
         BScreen::ScreenSubject *screen_subj = static_cast<BScreen::ScreenSubject *>(subj);
-        if (&screen_subj->screen().currentWorkspaceSig() == screen_subj) {
+        // current workspace sig
+        if (&m_screen.currentWorkspaceSig() == screen_subj &&
+            mode() != ALLWINDOWS && mode() != ICONS) {
             remove_all = true; // remove and readd all windows
+        } else if (&m_screen.iconListSig() == screen_subj &&
+                   (mode() == ALLWINDOWS || mode() == ICONS)) {
+            remove_all = true;
         }
     }
 
-    // ok, we got some signal that we need to update our iconbar container
-
-    // get current workspace and all it's clients
-    Workspace &space = *m_screen.currentWorkspace();
-    // build a ItemList and add it (faster than adding single items)
-    Container::ItemList items;
-    Workspace::Windows itemlist(space.windowList());
-    // add icons to the itemlist
-    {
-        BScreen::Icons::iterator icon_it = m_screen.getIconList().begin();
-        BScreen::Icons::iterator icon_it_end = m_screen.getIconList().end();
-        for (; icon_it != icon_it_end; ++icon_it) {
-            // just add the icons that are on the this workspace
-            if ((*icon_it)->workspaceNumber() == m_screen.currentWorkspaceID())
-                itemlist.push_back(*icon_it);
-        }
-    }
-
-    // go through the current list and see if there're windows to be added
-    // (note: we dont need to check if there's one deleted since we're listening
-    //  to dieSig )
-    if (!remove_all) {
-        IconList::iterator win_it = m_icon_list.begin();
-        IconList::iterator win_it_end = m_icon_list.end();
-        Workspace::Windows::iterator remove_it = itemlist.end();
-        for (; win_it != win_it_end; ++win_it)
-            remove_it = remove(itemlist.begin(), remove_it, &(*win_it)->win());
-
-       itemlist.erase(remove_it, itemlist.end());
-       // we dont need to do anything
-       // since we dont have anything to add ...
-       if (itemlist.size() == 0) 
-           return;
+    // lock graphic update
+    m_icon_container.setUpdateLock(true);
 
-    } else {
+    if (remove_all)
         deleteIcons();
-    }
-
-    // ok, now we should have a list of icons that we need to add
-    Workspace::Windows::iterator it = itemlist.begin();
-    Workspace::Windows::iterator it_end = itemlist.end();
-    for (; it != it_end; ++it) {
-        
-        // we just want windows that has clients
-         if ((*it)->clientList().size() == 0)
-            continue;
 
-        IconButton *button = new IconButton(m_icon_container, m_theme.focusedText().font(), **it);
-        items.push_back(button);
-        m_icon_list.push_back(button);
-
-        (*it)->focusSig().attach(this);
-        (*it)->dieSig().attach(this);
-        (*it)->workspaceSig().attach(this);
+    // ok, we got some signal that we need to update our iconbar container
+    switch (mode()) {
+    case NONE:
+        return;
+        break;
+    case ICONS:        
+    case WORKSPACEICONS:
+        updateIcons();
+        break;
+    case WORKSPACE:
+        updateWorkspace();
+        break;
+    case ALLWINDOWS:
+        updateAllWindows();
+        break;
     }
 
+    // unlock container and update graphics
+    m_icon_container.setUpdateLock(false);
     m_icon_container.showSubwindows();
-    m_icon_container.insertItems(items);
+    m_icon_container.update();
 
     renderTheme();
 }
@@ -255,8 +440,6 @@ void IconbarTool::renderTheme() {
     IconList::iterator icon_it_end = m_icon_list.end();
     for (; icon_it != icon_it_end; ++icon_it)
         renderButton(*(*icon_it));
-
-
 }
 
 void IconbarTool::renderButton(IconButton &button) {
@@ -300,7 +483,6 @@ void IconbarTool::deleteIcons() {
 }
 
 void IconbarTool::removeWindow(FluxboxWindow &win) {
-
     // got window die signal, lets find and remove the window
     IconList::iterator it = m_icon_list.begin();
     IconList::iterator it_end = m_icon_list.end();
@@ -311,10 +493,94 @@ void IconbarTool::removeWindow(FluxboxWindow &win) {
     // did we find it?
     if (it == m_icon_list.end())
         return;
+    
+    win.focusSig().detach(this);
+    win.dieSig().detach(this);
+    win.workspaceSig().detach(this);
+    win.stateSig().detach(this);
+ 
 
     // remove from list and render theme again
-    delete *it;
-    m_icon_list.erase(it);
+    IconButton *button = *it;
+
     m_icon_container.removeItem(m_icon_container.find(*it));
-    renderTheme();
+    m_icon_list.erase(it);
+
+    delete button;
+
+}
+
+void IconbarTool::addWindow(FluxboxWindow &win) {
+    // we just want windows that has clients
+    if (win.clientList().size() == 0)
+        return;
+
+    IconButton *button = new IconButton(m_icon_container, m_theme.focusedText().font(), win);
+    m_icon_container.insertItem(button);    
+    m_icon_list.push_back(button);
+
+    // dont forget to detach signal in removeWindow
+    win.focusSig().attach(this);
+    win.dieSig().attach(this);
+    win.workspaceSig().attach(this);
+    win.stateSig().attach(this);
+}
+
+
+void IconbarTool::updateIcons() {
+    std::list<FluxboxWindow *> itemlist;
+    // add icons to the itemlist    
+    BScreen::Icons::iterator icon_it = m_screen.getIconList().begin();
+    BScreen::Icons::iterator icon_it_end = m_screen.getIconList().end();
+    for (; icon_it != icon_it_end; ++icon_it) {
+        if (mode() == ICONS)
+            itemlist.push_back(*icon_it);
+        else if (mode() == WORKSPACEICONS && (*icon_it)->workspaceNumber() == m_screen.currentWorkspaceID())
+            itemlist.push_back(*icon_it);
+    }
+    removeDuplicate(m_icon_list, itemlist);
+    addList(itemlist);    
 }
+
+void IconbarTool::updateWorkspace() {
+    std::list<FluxboxWindow *> itemlist;
+    Workspace &space = *m_screen.currentWorkspace();
+    Workspace::Windows::iterator it = space.windowList().begin();
+    Workspace::Windows::iterator it_end = space.windowList().end();
+    for (; it != it_end; ++it) {
+        if (checkAddWindow(mode(), **it))
+            itemlist.push_back(*it);
+    }    
+    removeDuplicate(m_icon_list, itemlist);
+    addList(itemlist);
+}
+
+
+void IconbarTool::updateAllWindows() {
+    std::list<FluxboxWindow *> full_list;
+    // for each workspace add clients to full list
+    BScreen::Workspaces::iterator workspace_it = m_screen.getWorkspacesList().begin();
+    BScreen::Workspaces::iterator workspace_it_end = m_screen.getWorkspacesList().end();
+    for (; workspace_it != workspace_it_end; ++workspace_it) {
+        full_list.insert(full_list.end(),
+                         (*workspace_it)->windowList().begin(),
+                         (*workspace_it)->windowList().end());
+    }
+    // add icons
+    full_list.insert(full_list.end(),
+                     m_screen.getIconList().begin(),
+                     m_screen.getIconList().end());
+
+    removeDuplicate(m_icon_list, full_list);
+    addList(full_list);
+}
+
+void IconbarTool::addList(std::list<FluxboxWindow *> &winlist) {
+    // ok, now we should have a list of icons that we need to add
+    std::list<FluxboxWindow *>::iterator it = winlist.begin();
+    std::list<FluxboxWindow *>::iterator it_end = winlist.end();
+    for (; it != it_end; ++it)
+        addWindow(**it);
+}
+
+
diff --git a/src/IconbarTool.hh b/src/IconbarTool.hh
index 6dc7bfa..a4cbdf2 100644
--- a/src/IconbarTool.hh
+++ b/src/IconbarTool.hh
@@ -20,7 +20,7 @@
 // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
 // DEALINGS IN THE SOFTWARE.
 
-// $Id: IconbarTool.hh,v 1.6 2003/08/18 11:13:32 fluxgen Exp $
+// $Id: IconbarTool.hh,v 1.7 2003/09/08 17:52:34 fluxgen Exp $
 
 #ifndef ICONBARTOOL_HH
 #define ICONBARTOOL_HH
@@ -29,6 +29,8 @@
 #include "Container.hh"
 
 #include "FbTk/Observer.hh"
+#include "FbTk/Resource.hh"
+#include "FbTk/Menu.hh"
 
 #include <X11/Xlib.h>
 
@@ -41,7 +43,12 @@ class FluxboxWindow;
 
 class IconbarTool: public ToolbarItem, public FbTk::Observer {
 public:
-    IconbarTool(const FbTk::FbWindow &parent, IconbarTheme &theme, BScreen &screen);
+    typedef std::list<IconButton *> IconList;
+
+    enum Mode {NONE, ICONS, WORKSPACEICONS, WORKSPACE, ALLWINDOWS};
+
+    IconbarTool(const FbTk::FbWindow &parent, IconbarTheme &theme, 
+                BScreen &screen, FbTk::Menu &menu);
     ~IconbarTool();
 
     void move(int x, int y);
@@ -52,11 +59,17 @@ public:
     void update(FbTk::Subject *subj);
     void show();
     void hide();
+
+    void setMode(Mode mode);
+
     unsigned int width() const;
     unsigned int height() const;
     unsigned int borderWidth() const;
 
+    Mode mode() const { return *m_rc_mode; }
+
 private:
+
     /// render single button that holds win
     void renderWindow(FluxboxWindow &win);
     /// render single button
@@ -65,8 +78,18 @@ private:
     void renderTheme();
     /// destroy all icons
     void deleteIcons();
-    /// remove a single window an render theme again
+    /// remove a single window
     void removeWindow(FluxboxWindow &win);
+    /// add a single window 
+    void addWindow(FluxboxWindow &win);
+    /// add icons to the list
+    void updateIcons();
+    /// add normal windows to the list
+    void updateWorkspace();
+    /// add all windows to the list
+    void updateAllWindows();
+    /// add a list of windows 
+    void addList(std::list<FluxboxWindow *> &winlist);
 
     BScreen &m_screen;
     Container m_icon_container;
@@ -75,8 +98,11 @@ private:
     Pixmap m_focused_pm, m_unfocused_pm;
     Pixmap m_empty_pm; ///< pixmap for empty container
 
-    typedef std::list<IconButton *> IconList;
+
     IconList m_icon_list;
+    FbTk::Resource<Mode> m_rc_mode;
+
+    FbTk::Menu m_menu;
 };
 
 #endif // ICONBARTOOL_HH
-- 
cgit v0.11.2