// IconbarTool.cc
// Copyright (c) 2003 Henrik Kinnunen (fluxgen at users.sourceforge.net)
//                and Simon Bowden    (rathnor at users.sourceforge.net)
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the "Software"),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
// and/or sell copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.

// $Id: IconbarTool.cc,v 1.32 2004/01/21 14:13:57 fluxgen Exp $

#include "IconbarTool.hh"

#include "Screen.hh"
#include "IconbarTheme.hh"
#include "Window.hh"
#include "IconButton.hh"
#include "Workspace.hh"
#include "fluxbox.hh"
#include "FbMenu.hh"
#include "BoolMenuItem.hh"
#include "CommandParser.hh"
#include "WinClient.hh"

#include "FbTk/Menu.hh"
#include "FbTk/MenuItem.hh"
#include "FbTk/RefCount.hh"
#include "FbTk/SimpleCommand.hh"
#include "FbTk/ImageControl.hh"
#include "FbTk/MacroCommand.hh"

#include <typeinfo>
#include <string>
#include <iterator>
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<>
void FbTk::Resource<Container::Alignment>::setDefaultValue() {
    m_value = Container::RELATIVE;
}

template<>
string FbTk::Resource<Container::Alignment>::getString() {
    switch (m_value) {
    case Container::LEFT:
        return string("Left");
    case Container::RIGHT:
        return string("Right");
    case Container::RELATIVE:
        return string("Relative");
    }
    return string("Left");
}

template<>
void FbTk::Resource<Container::Alignment>::setFromString(const char *str) {
    if (strcasecmp(str, "Left") == 0)
        m_value = Container::LEFT;
    else if (strcasecmp(str, "Right") == 0)
        m_value = Container::RIGHT;
    else if (strcasecmp(str, "RELATIVE") == 0)
        m_value = Container::RELATIVE;
    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;
};

class ToolbarAlignMenuItem: public FbTk::MenuItem {
public:
    ToolbarAlignMenuItem(const char *label, IconbarTool &handler, 
                        Container::Alignment mode, 
                        FbTk::RefCount<FbTk::Command> &cmd):
        FbTk::MenuItem(label, cmd), m_handler(handler), m_mode(mode) {
    }
    bool isEnabled() const { return m_handler.alignment() != m_mode; }
    void click(int button, int time) {
        m_handler.setAlignment(m_mode);
        FbTk::MenuItem::click(button, time);
    }

private:
    IconbarTool &m_handler;
    Container::Alignment 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.insert("---"); // separator line
    menu.insert(new ToolbarAlignMenuItem("Left", handler,
                                         Container::LEFT, saverc_cmd));
    menu.insert(new ToolbarAlignMenuItem("Relative", handler,
                                         Container::RELATIVE, saverc_cmd));
    menu.insert(new ToolbarAlignMenuItem("Right", handler,
                                         Container::RIGHT, saverc_cmd));
    menu.insert("---"); // separator line
    menu.update();
}
                
inline bool checkAddWindow(IconbarTool::Mode mode, const FluxboxWindow &win) {
    bool ret_val = false;
    // just add the icons that are on the this workspace
    switch (mode) {
    case IconbarTool::NONE:
        break;
    case IconbarTool::ICONS:
        if (win.isIconic())
            ret_val = true;
        break;
    case IconbarTool::WORKSPACEICONS:
        if(win.workspaceNumber() == win.screen().currentWorkspaceID() &&
           win.isIconic())
            ret_val = true;
        break;
    case IconbarTool::WORKSPACE:
        if (win.workspaceNumber() == win.screen().currentWorkspaceID())
            ret_val = true;
        break;
    case IconbarTool::ALLWINDOWS:
        ret_val = true;
        break;
    }

    if (win.isHidden())
        ret_val = false;

    return ret_val;
}

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,
                         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_focused_err_pm(0),
    m_unfocused_err_pm(0),
    m_empty_pm(0),
    m_rc_mode(screen.resourceManager(), WORKSPACE,
              screen.name() + ".iconbar.mode", screen.altName() + ".Iconbar.Mode"),
    m_rc_alignment(screen.resourceManager(), Container::LEFT,
                   screen.name() + ".iconbar.alignment", screen.altName() + ".Iconbar.Alignment"),
    m_rc_client_width(screen.resourceManager(), 70,
                   screen.name() + ".iconbar.clientWidth", screen.altName() + ".Iconbar.ClientWidth"),
    m_rc_use_pixmap(screen.resourceManager(), true,
                    screen.name() + ".iconbar.usePixmap", screen.altName() + ".Iconbar.UsePixmap"),
    m_menu(screen.menuTheme(), screen.imageControl(),
           *screen.layerManager().getLayer(Fluxbox::instance()->getMenuLayer())) {

    // setup mode menu
    setupModeMenu(m_menu, *this);

    using namespace FbTk;
    // setup use pixmap item to reconfig iconbar and save resource on click
    MacroCommand *save_and_reconfig = new MacroCommand();   
    RefCount<Command> reconfig(new SimpleCommand<IconbarTool>(*this, &IconbarTool::renderTheme));
    RefCount<Command> save(CommandParser::instance().parseLine("saverc"));
    save_and_reconfig->add(reconfig);
    save_and_reconfig->add(save);
    RefCount<Command> s_and_reconfig(save_and_reconfig);
    m_menu.insert(new BoolMenuItem("Show Pictures", *m_rc_use_pixmap, s_and_reconfig));
    m_menu.update();
    // must be internal menu, otherwise toolbar main menu tries to delete it.
    m_menu.setInternalMenu();

    // add iconbar menu to toolbar menu
    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);
    // setup focus timer
    FbTk::RefCount<FbTk::Command> timer_cmd(new FbTk::SimpleCommand<IconbarTool>(*this, &IconbarTool::timedRender));
    timeval to;
    to.tv_sec = 0;
    to.tv_usec = 1; // so it updates next event round
    m_focus_timer.setCommand(timer_cmd);
    m_focus_timer.setTimeout(to);
    m_focus_timer.fireOnce(true);

    update(0);
}

IconbarTool::~IconbarTool() {
    deleteIcons();

    // remove cached images
    if (m_focused_pm)
        m_screen.imageControl().removeImage(m_focused_pm);
    if (m_unfocused_pm)
        m_screen.imageControl().removeImage(m_unfocused_pm);
    if (m_focused_err_pm)
        m_screen.imageControl().removeImage(m_focused_err_pm);
    if (m_unfocused_err_pm)
        m_screen.imageControl().removeImage(m_unfocused_err_pm);
    if (m_empty_pm)
        m_screen.imageControl().removeImage(m_empty_pm);

}

void IconbarTool::move(int x, int y) {
    m_icon_container.move(x, y);
}

void IconbarTool::resize(unsigned int width, unsigned int height) {
    m_icon_container.resize(width, height);
    renderTheme();
}

void IconbarTool::moveResize(int x, int y,
                             unsigned int width, unsigned int height) {

    m_icon_container.moveResize(x, y, width, height);
    renderTheme();
}

void IconbarTool::show() {
    m_icon_container.show();
}

void IconbarTool::hide() {
    m_icon_container.hide();
}

void IconbarTool::setAlignment(Container::Alignment align) {
    *m_rc_alignment = align;
    update(0);
}

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 (mode) {
    case NONE: // nothing
        break;
    case ICONS: // all icons from all workspaces
    case WORKSPACEICONS: // all icons on current workspace
        updateIcons();
        break;
    case WORKSPACE: // all windows and all icons on current workspace
        updateWorkspace();
        break;
    case ALLWINDOWS: // all windows and all icons from all workspaces
        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();
}

unsigned int IconbarTool::height() const {
    return m_icon_container.height();
}

unsigned int IconbarTool::borderWidth() const {
    return m_icon_container.borderWidth();
}

void IconbarTool::update(FbTk::Subject *subj) {    
    // ignore updates if we're shutting down
    if (m_screen.isShuttingdown()) {
        m_screen.clientListSig().detach(this);
        m_screen.iconListSig().detach(this);
        m_screen.currentWorkspaceSig().detach(this);        
        if (!m_icon_list.empty())
            deleteIcons();
        return;
    }

    m_icon_container.setAlignment(*m_rc_alignment);
    // clamp to normal values
    if (*m_rc_client_width < 1)
        *m_rc_client_width = 10;
    else if (*m_rc_client_width > 400)
        *m_rc_client_width = 400;

    m_icon_container.setMaxSizePerClient(*m_rc_client_width);


    if (mode() == NONE) {
        if (subj != 0 && typeid(*subj) == typeid(IconbarTheme))
            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);
        if (subj == &(winsubj->win().focusSig())) {
            // start focus timer, so we can update without flicker
            m_focus_timer.start();

            //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()) {
                removeWindow(winsubj->win());
                renderTheme();
            }
            return;
        } 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 (!checkAddWindow(mode(), winsubj->win())) {
                removeWindow(winsubj->win());            
                renderTheme();
            }

            return;

        } else if (subj == &(winsubj->win().titleSig())) {
            renderWindow(winsubj->win());
            return;
        } else {
            // signal not handled
            return;
        }
    }

    bool remove_all = false; // if we should readd all windows    

    if (subj != 0 && typeid(*subj) == typeid(BScreen::ScreenSubject) && mode() != ALLWINDOWS) {
        BScreen::ScreenSubject *screen_subj = static_cast<BScreen::ScreenSubject *>(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 || mode() == WORKSPACE)) {
            remove_all = true;
            }*/
    }

    // lock graphic update
    m_icon_container.setUpdateLock(true);

    if (remove_all)
        deleteIcons();

    // 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.update();
    m_icon_container.showSubwindows();
    
    renderTheme();
}

IconButton *IconbarTool::findButton(FluxboxWindow &win) {

    IconList::iterator icon_it = m_icon_list.begin();
    IconList::iterator icon_it_end = m_icon_list.end();
    for (; icon_it != icon_it_end; ++icon_it) {
        if (&(*icon_it)->win() == &win)
            return *icon_it;
    }

    return 0;
}

void IconbarTool::renderWindow(FluxboxWindow &win) {
    IconButton *button = findButton(win);
    if (button == 0)
        return;
    renderButton(*button);
}


void IconbarTool::renderTheme() {

    // update button sizes before we get max width per client!
    IconList::iterator icon_it = m_icon_list.begin();
    const IconList::iterator icon_it_end = m_icon_list.end(); 
    for (; icon_it != icon_it_end; ++icon_it) {
        if ((*icon_it)->win().isFocused())
            (*icon_it)->setBorderWidth(m_theme.focusedBorder().width());
        else // unfocused
            (*icon_it)->setBorderWidth(m_theme.unfocusedBorder().width());
    }    
    
    Pixmap tmp = m_focused_pm;
    Pixmap err_tmp = m_focused_err_pm;
    unsigned int icon_width = m_icon_container.maxWidthPerClient();
    if (!m_theme.focusedTexture().usePixmap()) {
        m_focused_pm = 0;
        m_focused_err_pm = 0;
    } else {
        m_focused_pm = m_screen.imageControl().renderImage(icon_width,
                                                           m_icon_container.height(),
                                                           m_theme.focusedTexture());
        m_focused_err_pm = m_screen.imageControl().renderImage(icon_width+1,
                                                               m_icon_container.height(),
                                                               m_theme.focusedTexture());
    }
        
    if (tmp)
        m_screen.imageControl().removeImage(tmp);
    if (err_tmp)
        m_screen.imageControl().removeImage(err_tmp);

    tmp = m_unfocused_pm;
    err_tmp = m_unfocused_err_pm;
    
    if (!m_theme.unfocusedTexture().usePixmap()) {
        m_unfocused_pm = 0;
        m_unfocused_err_pm = 0;
    } else {
        m_unfocused_pm = m_screen.imageControl().renderImage(icon_width,
                                                             m_icon_container.height(),
                                                             m_theme.unfocusedTexture());
        m_unfocused_err_pm = m_screen.imageControl().renderImage(icon_width+1,
                                                             m_icon_container.height(),
                                                             m_theme.unfocusedTexture());
    }
    if (tmp)
        m_screen.imageControl().removeImage(tmp);
    if (err_tmp)
        m_screen.imageControl().removeImage(err_tmp);

    // if we dont have any icons then we should render empty texture
    tmp = m_empty_pm;
    if (!m_theme.emptyTexture().usePixmap()) {
        m_empty_pm = 0;
        m_icon_container.setBackgroundColor(m_theme.emptyTexture().color());
    } else {
        m_empty_pm = m_screen.imageControl().renderImage(m_icon_container.width(),
                                                         m_icon_container.height(),
                                                         m_theme.emptyTexture());
        m_icon_container.setBackgroundPixmap(m_empty_pm);
    }

    if (tmp)
        m_screen.imageControl().removeImage(tmp);

    m_icon_container.setBorderWidth(m_theme.border().width());
    m_icon_container.setBorderColor(m_theme.border().color());
    m_icon_container.setAlpha(m_theme.alpha());

    // update buttons
    icon_it = m_icon_list.begin();
    for (; icon_it != icon_it_end; ++icon_it)
        renderButton(*(*icon_it));
}

void IconbarTool::renderButton(IconButton &button) {

    button.setPixmap(*m_rc_use_pixmap);
    button.setAlpha(m_theme.alpha());

    // if we're rendering a button, there must be a back button.
    // The last button is always the regular width
    bool wider_button = (button.width() != m_icon_container.back()->width());

    if (button.win().isFocused()) { // focused texture
        m_icon_container.setSelected(m_icon_container.find(&button));
        button.setGC(m_theme.focusedText().textGC());     
        button.setFont(m_theme.focusedText().font());
        button.setJustify(m_theme.focusedText().justify());
        button.setBorderWidth(m_theme.focusedBorder().width());
        button.setBorderColor(m_theme.focusedBorder().color());

        if (!wider_button && m_focused_pm != 0)
            button.setBackgroundPixmap(m_focused_pm);
        else if (wider_button && m_focused_err_pm != 0)
            button.setBackgroundPixmap(m_focused_err_pm);
        else
            button.setBackgroundColor(m_theme.focusedTexture().color());            



    } else { // unfocused
        if (m_icon_container.selected() == &button)
            m_icon_container.setSelected(-1);

        button.setGC(m_theme.unfocusedText().textGC());
        button.setFont(m_theme.unfocusedText().font());
        button.setJustify(m_theme.unfocusedText().justify());
        button.setBorderWidth(m_theme.unfocusedBorder().width());
        button.setBorderColor(m_theme.unfocusedBorder().color());

        if (!wider_button && m_unfocused_pm != 0)
            button.setBackgroundPixmap(m_unfocused_pm);
        else if (wider_button && m_unfocused_err_pm != 0)
            button.setBackgroundPixmap(m_unfocused_err_pm);
        else
            button.setBackgroundColor(m_theme.unfocusedTexture().color());

    }

    button.clear();
    button.updateTransparent();
}

void IconbarTool::deleteIcons() {
    m_icon_container.removeAll();
    while (!m_icon_list.empty()) {
        delete m_icon_list.back();
        m_icon_list.pop_back();
    }
}

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();
    for (; it != it_end; ++it) {
        if (&(*it)->win() == &win)
            break;
    }
    // did we find it?
    if (it == m_icon_list.end())
        return;
    
    // detach from all signals
    win.focusSig().detach(this);
    win.dieSig().detach(this);
    win.workspaceSig().detach(this);
    win.stateSig().detach(this);
    win.titleSig().detach(this);


    // remove from list and render theme again
    IconButton *button = *it;

    m_icon_container.removeItem(m_icon_container.find(*it));
    m_icon_list.erase(it);

    delete button;

}

void IconbarTool::addWindow(FluxboxWindow &win) {
    // we just want windows that has clients
    if (win.clientList().empty())
        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);
    win.titleSig().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;
    // add current workspace windows
    Workspace &space = *m_screen.currentWorkspace();
    Workspace::Windows::iterator win_it = space.windowList().begin();
    Workspace::Windows::iterator win_it_end = space.windowList().end();
    for (; win_it != win_it_end; ++win_it) {
        if (checkAddWindow(mode(), **win_it))
            itemlist.push_back(*win_it);
    }    
    // add icons from current workspace
    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 ((*icon_it)->workspaceNumber() == m_screen.currentWorkspaceID())
            itemlist.push_back(*icon_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);
}

void IconbarTool::timedRender() {
    WinClient *client = Fluxbox::instance()->getFocusedWindow();
    if (client == 0 || client->fbwindow() == 0)
        return;

    IconButton *button = findButton(*client->fbwindow());
    IconButton *current_button = static_cast<IconButton *>(m_icon_container.selected());
    // if old window is the same as the new focused window then ignore this render
    // else render old client and new client
    if (button == current_button)
        return;
    if (button != 0)
        renderButton(*button);
    if (current_button != 0)
        renderButton(*current_button);

}