all repos — fluxbox @ 5d7043320da1378e7dd3b10f7e425f3b47455b28

custom fork of the fluxbox windowmanager

allow arbitrary window patterns in iconbar
markt markt
commit

5d7043320da1378e7dd3b10f7e425f3b47455b28

parent

807a1b557552e43dbdc169c1e7a3065a3f12aac7

M ChangeLogChangeLog

@@ -1,5 +1,11 @@

(Format: Year/Month/Day) Changes for 1.0.1: +*07/11/12: + * Allow arbitrary window patterns for the iconbar mode (Mark) + - Note: for now, if you match against the current head of a window, it will + not be updated as expected in the toolbar + ClientPattern.cc/hh FocusControl.cc/hh IconbarTool.cc/hh FbTk/Subject.cc + fluxbox.cc, added FocusableList.cc/hh *07/11/08: * Fix crash when cycling focus and window closes, bug #1787345 (Mark) FocusControl.cc
M data/init.indata/init.in

@@ -31,4 +31,4 @@ session.colorsPerChannel: 4

session.doubleClickInterval: 250 session.cacheMax: 200 session.imageDither: True -session.configVersion: 4 +session.configVersion: 5
M doc/asciidoc/fluxbox.txtdoc/asciidoc/fluxbox.txt

@@ -779,15 +779,10 @@ For those that use xinerama, users can set this value to the number of the

head where they would like to see the slit and toolbar, starting from 1. Setting this to 0 will ignore xinerama information. Default: 0 -session.screen0.iconbar.mode: <mode> - This value is set in the Iconbar Mode menu. The available options are:: - - All Windows - - Icons - - NoIcons - - None - - Workspace - - WorkspaceIcons - - WorkspaceNoIcons +session.screen0.iconbar.mode: <pattern> + This determines which windows will be displayed in the iconbar. Any window + pattern available to the Next/PrevWindow keybindings is acceptable. + Default: {static groups} (workspace) session.screen0.iconbar.usePixmap: <boolean> This is also set in the Iconbar Mode menu. When set to True, this will
M src/ClientPattern.ccsrc/ClientPattern.cc

@@ -274,9 +274,19 @@ Terms::const_iterator it_end = m_terms.end();

for (; it != it_end; ++it) { if ((*it)->orig == "[current]") { WinClient *focused = FocusControl::focusedWindow(); - if (!focused || !((*it)->negate ^ - (getProperty((*it)->prop, win) == - getProperty((*it)->prop, *focused)))) + if ((*it)->prop == WORKSPACE) { + char tmpstr[128]; + sprintf(tmpstr, "%d", win.screen().currentWorkspaceID()); + if (!(*it)->negate ^ (getProperty((*it)->prop, win) == tmpstr)) + return false; + } else if ((*it)->prop == WORKSPACENAME) { + const Workspace *w = win.screen().currentWorkspace(); + if (!w || (!(*it)->negate ^ + (getProperty((*it)->prop, win) == w->name()))) + return false; + } else if (!focused || (!(*it)->negate ^ + (getProperty((*it)->prop, win) == + getProperty((*it)->prop, *focused)))) return false; } else if ((*it)->prop == HEAD && (*it)->orig == "[mouse]") {

@@ -291,6 +301,26 @@ (*it)->regexp.match(getProperty((*it)->prop, win)))

return false; } return true; +} + +bool ClientPattern::dependsOnFocusedWindow() const { + Terms::const_iterator it = m_terms.begin(), it_end = m_terms.end(); + for (; it != it_end; ++it) { + if ((*it)->prop != WORKSPACE && (*it)->prop != WORKSPACENAME && + (*it)->orig == "[current]") + return true; + } + return false; +} + +bool ClientPattern::dependsOnCurrentWorkspace() const { + Terms::const_iterator it = m_terms.begin(), it_end = m_terms.end(); + for (; it != it_end; ++it) { + if (((*it)->prop == WORKSPACE || (*it)->prop == WORKSPACENAME) && + (*it)->orig == "[current]") + return true; + } + return false; } // add an expression to match against
M src/ClientPattern.hhsrc/ClientPattern.hh

@@ -62,6 +62,12 @@

/// Does this client match this pattern? bool match(const Focusable &win) const; + /// Does this pattern depend on the focused window? + bool dependsOnFocusedWindow() const; + + /// Does this pattern depend on the current workspace? + bool dependsOnCurrentWorkspace() const; + /** * Add an expression to match against * @param str is a regular expression
M src/ColSmartPlacement.ccsrc/ColSmartPlacement.cc

@@ -33,7 +33,7 @@ int &place_x, int &place_y) {

std::list<FluxboxWindow *> windowlist; const std::list<Focusable *> focusables = - win.screen().focusControl().focusedOrderWinList(); + win.screen().focusControl().focusedOrderWinList().clientList(); std::list<Focusable *>::const_iterator foc_it = focusables.begin(), foc_it_end = focusables.end(); unsigned int workspace = win.workspaceNumber();
M src/Ewmh.ccsrc/Ewmh.cc

@@ -345,7 +345,8 @@

if (screen.isShuttingdown()) return; - list<Focusable *> creation_order_list = screen.focusControl().creationOrderList(); + list<Focusable *> creation_order_list = + screen.focusControl().creationOrderList().clientList(); size_t num = creation_order_list.size(); Window *wl = FB_new_nothrow Window[num];
M src/FbCommandFactory.ccsrc/FbCommandFactory.cc

@@ -24,6 +24,7 @@ // $Id$

#include "FbCommandFactory.hh" +#include "FocusableList.hh" #include "CurrentWindowCmd.hh" #include "FbCommands.hh" #include "Window.hh"

@@ -57,26 +58,6 @@

static int getint(const char *str, int defaultvalue) { sscanf(str, "%d", &defaultvalue); return defaultvalue; -} - -void parseNextWindowArgs(const string &in, int &opts, string &pat) { - string options; - int err = FbTk::StringUtil::getStringBetween(options, in.c_str(), '{', '}'); - - // the rest of the string is a ClientPattern - pat = in.c_str() + err; - - // now parse the options - vector<string> args; - FbTk::StringUtil::stringtok(args, options); - vector<string>::iterator it = args.begin(), it_end = args.end(); - opts = 0; - for (; it != it_end; ++it) { - if (strcasecmp((*it).c_str(), "static") == 0) - opts |= FocusControl::CYCLELINEAR; - else if (strcasecmp((*it).c_str(), "groups") == 0) - opts |= FocusControl::CYCLEGROUPS; - } } }; // end anonymous namespace

@@ -522,29 +503,29 @@

} else if (command == "attach") { int opts; // not used string pat; - parseNextWindowArgs(arguments, opts, pat); + FocusableList::parseArgs(arguments, opts, pat); return new AttachCmd(pat); } else if (command == "nextwindow") { int opts; string pat; - parseNextWindowArgs(arguments, opts, pat); + FocusableList::parseArgs(arguments, opts, pat); return new NextWindowCmd(opts, pat); } else if (command == "nextgroup") { int opts; string pat; - parseNextWindowArgs(arguments, opts, pat); - opts |= FocusControl::CYCLEGROUPS; + FocusableList::parseArgs(arguments, opts, pat); + opts |= FocusableList::LIST_GROUPS; return new NextWindowCmd(opts, pat); } else if (command == "prevwindow") { int opts; string pat; - parseNextWindowArgs(arguments, opts, pat); + FocusableList::parseArgs(arguments, opts, pat); return new PrevWindowCmd(opts, pat); } else if (command == "prevgroup") { int opts; string pat; - parseNextWindowArgs(arguments, opts, pat); - opts |= FocusControl::CYCLEGROUPS; + FocusableList::parseArgs(arguments, opts, pat); + opts |= FocusableList::LIST_GROUPS; return new PrevWindowCmd(opts, pat); } else if (command == "gotowindow") { int num, opts;

@@ -554,12 +535,12 @@ iss >> num;

string::size_type pos = arguments.find_first_of("({"); if (pos != string::npos && pos != arguments.size()) args = arguments.c_str() + pos; - parseNextWindowArgs(args, opts, pat); + FocusableList::parseArgs(args, opts, pat); return new GoToWindowCmd(num, opts, pat); } else if (command == "clientmenu") { int opts; string pat; - parseNextWindowArgs(arguments, opts, pat); + FocusableList::parseArgs(arguments, opts, pat); return new ShowClientMenuCmd(opts, pat); } else if (command == "focusup") return new DirFocusCmd(FocusControl::FOCUSUP);
M src/FbCommands.ccsrc/FbCommands.cc

@@ -277,20 +277,12 @@ if (screen == 0)

return; // TODO: ClientMenu only accepts lists of FluxboxWindows for now - const FocusControl::Focusables *win_list = 0; -// if (m_option & FocusControl::CYCLEGROUPS) { - win_list = (m_option & FocusControl::CYCLELINEAR) ? - &screen->focusControl().creationOrderWinList() : - &screen->focusControl().focusedOrderWinList(); -/* } else { - win_list = (m_option & FocusControl::CYCLELINEAR) ? - &screen->focusControl().creationOrderList() : - &screen->focusControl().focusedOrderList(); - } */ - + // when that's fixed, use a FocusableList for m_list + const FocusableList *list = + FocusableList::getListFromOptions(*screen, m_option); m_list.clear(); - FocusControl::Focusables::const_iterator it = win_list->begin(), - it_end = win_list->end(); + FocusControl::Focusables::const_iterator it = list->clientList().begin(), + it_end = list->clientList().end(); for (; it != it_end; ++it) { if (typeid(**it) == typeid(FluxboxWindow) && m_pat.match(**it)) m_list.push_back(static_cast<FluxboxWindow *>(*it));
M src/FbCommands.hhsrc/FbCommands.hh

@@ -31,6 +31,7 @@

#include "FbTk/RefCount.hh" #include "ClientMenu.hh" #include "ClientPattern.hh" +#include "FocusableList.hh" #include <list> #include <string>

@@ -118,7 +119,7 @@

class ShowClientMenuCmd: public FbTk::Command { public: ShowClientMenuCmd(int option, std::string &pat): - m_option(option), m_pat(pat.c_str()) { } + m_option(option|FocusableList::LIST_GROUPS), m_pat(pat.c_str()) { } void execute(); private: const int m_option;
M src/FbTk/Subject.ccsrc/FbTk/Subject.cc

@@ -58,16 +58,22 @@ }

} void Subject::notify() { - m_notify_mode = true; - std::for_each(m_observerlist.begin(), m_observerlist.end(), - std::bind2nd(std::mem_fun(&Observer::update), this)); - m_notify_mode = false; + ObserverList::iterator it = m_observerlist.begin(), + it_end = m_observerlist.end(); + for (; it != it_end; ++it) { + m_notify_mode = true; + (*it)->update(this); + ObserverList::iterator d_it = m_dead_observers.begin(), + d_it_end = m_dead_observers.end(); + m_notify_mode = false; - // remove dead observers - if (!m_dead_observers.empty()) { - std::for_each(m_dead_observers.begin(), - m_dead_observers.end(), - std::bind1st(std::mem_fun(&Subject::detach), this)); + // there might be dead observers later in the list, so we must remove + // them now + for (; d_it != d_it_end; ++d_it) { + if (*d_it == *it) + --it; // don't invalidate our iterator + detach(*d_it); + } m_dead_observers.clear(); } }
M src/FocusControl.ccsrc/FocusControl.cc

@@ -78,15 +78,17 @@ screen.altName()+".TabFocusModel"),

m_focus_new(screen.resourceManager(), true, screen.name()+".focusNewWindows", screen.altName()+".FocusNewWindows"), + m_focused_list(screen), m_creation_order_list(screen), + m_focused_win_list(screen), m_creation_order_win_list(screen), m_cycling_list(0), m_was_iconic(false), m_cycling_last(0) { - m_cycling_window = m_focused_win_list.end(); + m_cycling_window = m_focused_list.clientList().end(); } -void FocusControl::cycleFocus(const Focusables &window_list, +void FocusControl::cycleFocus(const FocusableList &window_list, const ClientPattern *pat, bool cycle_reverse) { if (!m_cycling_list) {

@@ -98,8 +100,8 @@ m_cycling_last = 0;

} else if (m_cycling_list != &window_list) m_cycling_list = &window_list; - Focusables::const_iterator it_begin = window_list.begin(); - Focusables::const_iterator it_end = window_list.end(); + Focusables::const_iterator it_begin = window_list.clientList().begin(); + Focusables::const_iterator it_end = window_list.clientList().end(); // too many things can go wrong with remembering this m_cycling_window = find(it_begin, it_end, s_focused_window);

@@ -165,10 +167,10 @@ m_was_iconic = was_iconic;

} -void FocusControl::goToWindowNumber(const Focusables &winlist, int num, +void FocusControl::goToWindowNumber(const FocusableList &winlist, int num, const ClientPattern *pat) { - Focusables::const_iterator it = winlist.begin(); - Focusables::const_iterator it_end = winlist.end(); + Focusables::const_iterator it = winlist.clientList().begin(); + Focusables::const_iterator it_end = winlist.clientList().end(); for (; it != it_end && num; ++it) { if (!doSkipWindow(**it, pat) && (*it)->acceptsFocus()) { num > 0 ? --num : ++num;

@@ -182,61 +184,43 @@ }

} void FocusControl::addFocusBack(WinClient &client) { - m_focused_list.push_back(&client); - m_creation_order_list.push_back(&client); + m_focused_list.pushBack(client); + m_creation_order_list.pushBack(client); } void FocusControl::addFocusFront(WinClient &client) { - m_focused_list.push_front(&client); - m_creation_order_list.push_back(&client); + m_focused_list.pushFront(client); + m_creation_order_list.pushBack(client); } void FocusControl::addFocusWinBack(Focusable &win) { - m_focused_win_list.push_back(&win); - m_creation_order_win_list.push_back(&win); + m_focused_win_list.pushBack(win); + m_creation_order_win_list.pushBack(win); } void FocusControl::addFocusWinFront(Focusable &win) { - m_focused_win_list.push_front(&win); - m_creation_order_win_list.push_back(&win); + m_focused_win_list.pushFront(win); + m_creation_order_win_list.pushBack(win); } // move all clients in given window to back of focused list -void FocusControl::setFocusBack(FluxboxWindow *fbwin) { +void FocusControl::setFocusBack(FluxboxWindow &fbwin) { // do nothing if there are no windows open // don't change focus order while cycling if (m_focused_list.empty() || s_reverting) return; - // if the window isn't already in this list, we could accidentally add it - Focusables::iterator win_begin = m_focused_win_list.begin(), - win_end = m_focused_win_list.end(); - Focusables::iterator win_it = find(win_begin, win_end, fbwin); - if (win_it == win_end) - return; - - m_focused_win_list.erase(win_it); - m_focused_win_list.push_back(fbwin); - - Focusables::iterator it = m_focused_list.begin(); - // use back to avoid an infinite loop - Focusables::iterator it_back = --m_focused_list.end(); + m_focused_win_list.moveToBack(fbwin); - while (it != it_back) { - if ((*it)->fbwindow() == fbwin) { - m_focused_list.push_back(*it); - it = m_focused_list.erase(it); - } else - ++it; + // we need to move its clients to the back while preserving their order + Focusables list = m_focused_list.clientList(); + Focusables::iterator it = list.begin(), it_end = list.end(); + for (; it != it_end; ++it) { + if ((*it)->fbwindow() == &fbwin) + m_focused_list.moveToBack(**it); } - // move the last one, if necessary, in order to preserve focus order - if ((*it)->fbwindow() == fbwin) { - m_focused_list.push_back(*it); - m_focused_list.erase(it); - } +} -} - void FocusControl::stopCyclingFocus() { // nothing to do if (m_cycling_list == 0)

@@ -262,10 +246,10 @@ */

Focusable *FocusControl::lastFocusedWindow(int workspace) { if (m_focused_list.empty() || m_screen.isShuttingdown()) return 0; if (workspace < 0 || workspace >= (int) m_screen.numberOfWorkspaces()) - return m_focused_list.front(); + return m_focused_list.clientList().front(); - Focusables::iterator it = m_focused_list.begin(); - Focusables::iterator it_end = m_focused_list.end(); + Focusables::iterator it = m_focused_list.clientList().begin(); + Focusables::iterator it_end = m_focused_list.clientList().end(); for (; it != it_end; ++it) { if ((*it)->fbwindow() && ((((int)(*it)->fbwindow()->workspaceNumber()) == workspace ||

@@ -285,8 +269,8 @@ WinClient *FocusControl::lastFocusedWindow(FluxboxWindow &group, WinClient *ignore_client) {

if (m_focused_list.empty() || m_screen.isShuttingdown()) return 0; - Focusables::iterator it = m_focused_list.begin(); - Focusables::iterator it_end = m_focused_list.end(); + Focusables::iterator it = m_focused_list.clientList().begin(); + Focusables::iterator it_end = m_focused_list.clientList().end(); for (; it != it_end; ++it) { if (((*it)->fbwindow() == &group) && (*it) != ignore_client)

@@ -300,27 +284,9 @@

// raise newly focused window to the top of the focused list // don't change the order if we're cycling or shutting down if (!isCycling() && !m_screen.isShuttingdown() && !s_reverting) { - - // make sure client is in our list, or else we could end up adding it - Focusables::iterator it_begin = m_focused_list.begin(), - it_end = m_focused_list.end(); - Focusables::iterator it = find(it_begin, it_end, &win_client); - if (it == it_end) - return; - - m_focused_list.erase(it); - m_focused_list.push_front(&win_client); - - // also check the fbwindow - it_begin = m_focused_win_list.begin(); - it_end = m_focused_win_list.end(); - it = find(it_begin, it_end, win_client.fbwindow()); - - if (it != it_end) { - m_focused_win_list.erase(it); - m_focused_win_list.push_front(win_client.fbwindow()); - } - + m_focused_list.moveToFront(win_client); + if (win_client.fbwindow()) + m_focused_win_list.moveToFront(*win_client.fbwindow()); } }

@@ -435,15 +401,15 @@ void FocusControl::removeClient(WinClient &client) {

if (client.screen().isShuttingdown()) return; - if (m_cycling_list && m_cycling_window != m_cycling_list->end() && + if (isCycling() && m_cycling_window != m_cycling_list->clientList().end() && *m_cycling_window == &client) { - m_cycling_window = m_cycling_list->end(); + m_cycling_window = m_cycling_list->clientList().end(); stopCyclingFocus(); } else if (m_cycling_last == &client) m_cycling_last = 0; - m_focused_list.remove(&client); - m_creation_order_list.remove(&client); + m_focused_list.remove(client); + m_creation_order_list.remove(client); client.screen().clientListSig().notify(); }

@@ -451,21 +417,21 @@ void FocusControl::removeWindow(Focusable &win) {

if (win.screen().isShuttingdown()) return; - if (m_cycling_list && m_cycling_window != m_cycling_list->end() && + if (isCycling() && m_cycling_window != m_cycling_list->clientList().end() && *m_cycling_window == &win) { - m_cycling_window = m_cycling_list->end(); + m_cycling_window = m_cycling_list->clientList().end(); stopCyclingFocus(); } - m_focused_win_list.remove(&win); - m_creation_order_win_list.remove(&win); + m_focused_win_list.remove(win); + m_creation_order_win_list.remove(win); win.screen().clientListSig().notify(); } void FocusControl::shutdown() { // restore windows backwards so they get put back correctly on restart - Focusables::reverse_iterator it = m_focused_list.rbegin(); - for (; it != m_focused_list.rend(); ++it) { + Focusables::reverse_iterator it = m_focused_list.clientList().rbegin(); + for (; it != m_focused_list.clientList().rend(); ++it) { WinClient *client = dynamic_cast<WinClient *>(*it); if (client && client->fbwindow()) client->fbwindow()->restore(client, true);

@@ -582,7 +548,10 @@ s_focused_fbwindow = 0;

} // update AtomHandlers and/or other stuff... - Fluxbox::instance()->updateFocusedWindow(screen, old_screen); + if (screen) + screen->focusedWindowSig().notify(); + if (old_screen && screen != old_screen) + old_screen->focusedWindowSig().notify(); } ////////////////////// FocusControl RESOURCES
M src/FocusControl.hhsrc/FocusControl.hh

@@ -27,6 +27,7 @@

#include <list> #include "FbTk/Resource.hh" +#include "FocusableList.hh" class ClientPattern; class WinClient;

@@ -60,12 +61,6 @@ FOCUSLEFT, ///< window is left

FOCUSRIGHT ///< window is right }; - /// prevFocus/nextFocus option bits - enum { - CYCLEGROUPS = 0x01, //< cycle through groups - CYCLELINEAR = 0x08, ///< linear cycle - }; - explicit FocusControl(BScreen &screen); /// cycle previous focuable void prevFocus() { cycleFocus(m_focused_list, 0, true); }

@@ -77,10 +72,10 @@ * @param winlist the windowlist to cycle through

* @param pat pattern for matching focusables * @param reverse reverse the cycle order */ - void cycleFocus(const Focusables &winlist, const ClientPattern *pat = 0, + void cycleFocus(const FocusableList &winlist, const ClientPattern *pat = 0, bool reverse = false); - void goToWindowNumber(const Focusables &winlist, int num, + void goToWindowNumber(const FocusableList &winlist, int num, const ClientPattern *pat = 0); /// sets the focused window on a screen void setScreenFocusedWindow(WinClient &win_client);

@@ -108,7 +103,7 @@ /// Appends a client to the front of the focus list

void addFocusFront(WinClient &client); void addFocusWinBack(Focusable &win); void addFocusWinFront(Focusable &win); - void setFocusBack(FluxboxWindow *fbwin); + void setFocusBack(FluxboxWindow &fbwin); /// @return main focus model FocusModel focusModel() const { return *m_focus_model; } /// @return tab focus model

@@ -122,11 +117,11 @@

WinClient *lastFocusedWindow(FluxboxWindow &group, WinClient *ignore_client = 0); /// @return focus list in creation order - const Focusables &creationOrderList() const { return m_creation_order_list; } + const FocusableList &creationOrderList() const { return m_creation_order_list; } /// @return the focus list in focused order - const Focusables &focusedOrderList() const { return m_focused_list; } - const Focusables &creationOrderWinList() const { return m_creation_order_win_list; } - const Focusables &focusedOrderWinList() const { return m_focused_win_list; } + const FocusableList &focusedOrderList() const { return m_focused_list; } + const FocusableList &creationOrderWinList() const { return m_creation_order_win_list; } + const FocusableList &focusedOrderWinList() const { return m_focused_win_list; } /// remove client from focus list void removeClient(WinClient &client);

@@ -153,13 +148,13 @@ FbTk::Resource<bool> m_focus_new;

// This list keeps the order of window focusing for this screen // Screen global so it works for sticky windows too. - Focusables m_focused_list; - Focusables m_creation_order_list; - Focusables m_focused_win_list; - Focusables m_creation_order_win_list; + FocusableList m_focused_list; + FocusableList m_creation_order_list; + FocusableList m_focused_win_list; + FocusableList m_creation_order_win_list; Focusables::const_iterator m_cycling_window; - const Focusables *m_cycling_list; + const FocusableList *m_cycling_list; Focusable *m_was_iconic; WinClient *m_cycling_last;
M src/Focusable.hhsrc/Focusable.hh

@@ -19,7 +19,7 @@ // 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$ +// $Id: $ #ifndef FOCUSABLE_HH #define FOCUSABLE_HH
A src/FocusableList.cc

@@ -0,0 +1,293 @@

+// FocusableList.cc +// Copyright (c) 2007 Fluxbox Team (fluxgen at fluxbox dot org) +// +// 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: $ + +#include "FocusableList.hh" + +#include "Focusable.hh" +#include "FocusControl.hh" +#include "Screen.hh" +#include "WinClient.hh" +#include "Window.hh" + +#include "FbTk/StringUtil.hh" + +#include <vector> + +using std::string; +using std::vector; + +void FocusableList::parseArgs(const string &in, int &opts, string &pat) { + string options; + int err = FbTk::StringUtil::getStringBetween(options, in.c_str(), '{', '}'); + + // the rest of the string is a ClientPattern + pat = in.c_str() + err; + + // now parse the options + vector<string> args; + FbTk::StringUtil::stringtok(args, options); + vector<string>::iterator it = args.begin(), it_end = args.end(); + opts = 0; + for (; it != it_end; ++it) { + if (strcasecmp((*it).c_str(), "static") == 0) + opts |= STATIC_ORDER; + else if (strcasecmp((*it).c_str(), "groups") == 0) + opts |= LIST_GROUPS; + } +} + +const FocusableList *FocusableList::getListFromOptions(BScreen &scr, int opts) { + if (opts & LIST_GROUPS) + return (opts & STATIC_ORDER) ? + &scr.focusControl().creationOrderWinList() : + &scr.focusControl().focusedOrderWinList(); + return (opts & STATIC_ORDER) ? + &scr.focusControl().creationOrderList() : + &scr.focusControl().focusedOrderList(); +} + +FocusableList::FocusableList(BScreen &scr, const string pat): + m_pat(0), m_parent(0), m_screen(scr) { + + int options = 0; + string pattern; + parseArgs(pat, options, pattern); + m_parent = getListFromOptions(scr, options); + m_pat.reset(new ClientPattern(pattern.c_str())); + + init(); +} + +FocusableList::FocusableList(BScreen &scr, const FocusableList &parent, + const string pat): + m_pat(new ClientPattern(pat.c_str())), m_parent(&parent), m_screen(scr) { + + init(); +} + +void FocusableList::init() { + addMatching(); + m_parent->attachChild(*this); + + // TODO: can't handle (head=[mouse]) yet + if (m_pat->dependsOnCurrentWorkspace()) + m_screen.currentWorkspaceSig().attach(this); + if (m_pat->dependsOnFocusedWindow()) + m_screen.focusedWindowSig().attach(this); +} + +void FocusableList::update(FbTk::Subject *subj) { + if (subj == 0 || m_screen.isShuttingdown()) + return; + + if (typeid(*subj) == typeid(Focusable::FocusSubject)) { + Focusable::FocusSubject *fsubj = + static_cast<Focusable::FocusSubject *>(subj); + 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 = + static_cast<FluxboxWindow::WinSubject *>(subj); + // we only bind these for matching patterns, so skip finding out signal + FluxboxWindow &fbwin = fsubj->win(); + if (m_parent->contains(fbwin)) + checkUpdate(fbwin); + std::list<WinClient *> list = fbwin.clientList(); + std::list<WinClient *>::iterator it = list.begin(), it_end = list.end(); + for (; it != it_end; ++it) { + if (m_parent->contains(**it)) + checkUpdate(**it); + } + } + if (typeid(*subj) == typeid(FocusableListSubject)) { + FocusableListSubject *fsubj = + static_cast<FocusableListSubject *>(subj); + if (subj == &m_parent->addSig()) { + if (m_pat->match(*fsubj->win())) { + insertFromParent(*fsubj->win()); + m_addsig.notify(fsubj->win()); + } else // we still want to watch it, in case it changes to match + attachSignals(*fsubj->win()); + } else if (subj == &m_parent->removeSig()) + remove(*fsubj->win()); + else if (subj == &m_parent->resetSig()) + reset(); + else if (subj == &m_parent->orderSig()) { + Focusable *win = fsubj->win(); + if (!win || !contains(*win)) + return; + if (insertFromParent(*win)) + m_ordersig.notify(win); + } + } else if (subj == &m_screen.currentWorkspaceSig() || + subj == &m_screen.focusedWindowSig()) + reset(); +} + +void FocusableList::checkUpdate(Focusable &win) { + if (contains(win)) { + if (!m_pat->match(win)) { + m_list.remove(&win); + m_removesig.notify(&win); + } + } else if (m_pat->match(win)) { + insertFromParent(win); + m_addsig.notify(&win); + } +} + +// returns whether or not the window was moved +bool FocusableList::insertFromParent(Focusable &win) { + const Focusables list = m_parent->clientList(); + Focusables::const_iterator p_it = list.begin(), p_it_end = list.end(); + Focusables::iterator our_it = m_list.begin(), our_it_end = m_list.end(); + // walk through our list looking for corresponding entries in + // parent's list, until we find the window that moved + for (; our_it != our_it_end && p_it != p_it_end; p_it++) { + if (*p_it == &win) { + if (*our_it == &win) // win didn't move in our list + return false; + m_list.remove(&win); + m_list.insert(our_it, &win); + return true; + } + if (*p_it == *our_it) + ++our_it; + } + m_list.remove(&win); + m_list.push_back(&win); + return true; +} + +void FocusableList::addMatching() { + if (!m_parent) + return; + + const Focusables list = m_parent->clientList(); + Focusables::const_iterator it = list.begin(), it_end = list.end(); + for (; it != it_end; ++it) { + if (m_pat->match(**it)) + pushBack(**it); + else // we still want to watch it, in case it changes to match + attachSignals(**it); + } +} + +void FocusableList::pushFront(Focusable &win) { + m_list.push_front(&win); + attachSignals(win); + m_addsig.notify(&win); +} + +void FocusableList::pushBack(Focusable &win) { + m_list.push_back(&win); + attachSignals(win); + m_addsig.notify(&win); +} + +void FocusableList::moveToFront(Focusable &win) { + // if the window isn't already in this list, we could accidentally add it + if (!contains(win)) + return; + + m_list.remove(&win); + m_list.push_front(&win); + m_ordersig.notify(&win); +} + +void FocusableList::moveToBack(Focusable &win) { + // if the window isn't already in this list, we could accidentally add it + if (!contains(win)) + return; + + m_list.remove(&win); + m_list.push_back(&win); + m_ordersig.notify(&win); +} + +void FocusableList::remove(Focusable &win) { + // if the window isn't already in this list, we could send a bad signal + bool contained = contains(win); + + detachSignals(win); + if (!contained) + return; + m_list.remove(&win); + m_removesig.notify(&win); +} + +void FocusableList::attachSignals(Focusable &win) { + win.dieSig().attach(this); + if (m_parent) { + // attach various signals for matching + win.titleSig().attach(this); + FluxboxWindow *fbwin = win.fbwindow(); + if (!fbwin) + return; + fbwin->workspaceSig().attach(this); + fbwin->stateSig().attach(this); + fbwin->layerSig().attach(this); + // TODO: can't watch (head=...) yet + } +} + +void FocusableList::detachSignals(Focusable &win) { + win.dieSig().detach(this); + if (m_parent) { + // detach various signals for matching + win.titleSig().detach(this); + FluxboxWindow *fbwin = win.fbwindow(); + if (!fbwin) + return; + fbwin->workspaceSig().detach(this); + fbwin->stateSig().detach(this); + fbwin->layerSig().detach(this); + // TODO: can't watch (head=...) yet + } +} + +void FocusableList::reset() { + while (!m_list.empty()) { + detachSignals(*m_list.back()); + m_list.pop_back(); + } + if (m_parent) + addMatching(); + m_resetsig.notify(0); +} + +bool FocusableList::contains(const Focusable &win) const { + Focusables::const_iterator it = m_list.begin(), it_end = m_list.end(); + it = find(it, it_end, &win); + return (it != it_end); +} + +void FocusableList::attachChild(FocusableList &child) const { + m_addsig.attach(&child); + m_removesig.attach(&child); + m_resetsig.attach(&child); + m_ordersig.attach(&child); +}
A src/FocusableList.hh

@@ -0,0 +1,121 @@

+// FocusableList.hh +// Copyright (c) 2007 Fluxbox Team (fluxgen at fluxbox dot org) +// +// 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: $ + +#ifndef FOCUSABLELIST_HH +#define FOCUSABLELIST_HH + +#include "FbTk/NotCopyable.hh" +#include "FbTk/Observer.hh" +#include "FbTk/Subject.hh" + +#include "ClientPattern.hh" + +#include <list> +#include <string> + +class BScreen; +class Focusable; + +class FocusableList: public FbTk::Observer, private FbTk::NotCopyable { +public: + typedef std::list<Focusable *> Focusables; + + /// list option bits + enum { + LIST_GROUPS = 0x01, //< list groups instead of clients + STATIC_ORDER = 0x02, ///< use creation order instead of focused order + }; + + FocusableList(BScreen &scr): m_pat(0), m_parent(0), m_screen(scr) { } + FocusableList(BScreen &scr, const std::string pat); + FocusableList(BScreen &scr, const FocusableList &parent, + const std::string pat); + + static void parseArgs(const std::string &in, int &opts, std::string &out); + static const FocusableList *getListFromOptions(BScreen &scr, int opts); + + void update(FbTk::Subject *subj); + + /// functions for modifying the list contents + void pushFront(Focusable &win); + void pushBack(Focusable &win); + void moveToFront(Focusable &win); + void moveToBack(Focusable &win); + void remove(Focusable &win); + + /// accessor for list + Focusables &clientList() { return m_list; } + const Focusables &clientList() const { return m_list; } + + /// does the list contain any windows? + bool empty() const { return m_list.empty(); } + /// does the list contain the given window? + bool contains(const Focusable &win) const; + + /** + @name signals + @{ + */ + FbTk::Subject &orderSig() { return m_ordersig; } + const FbTk::Subject &orderSig() const { return m_ordersig; } + FbTk::Subject &addSig() { return m_addsig; } + const FbTk::Subject &addSig() const { return m_addsig; } + FbTk::Subject &removeSig() { return m_removesig; } + const FbTk::Subject &removeSig() const { return m_removesig; } + FbTk::Subject &resetSig() { return m_resetsig; } + const FbTk::Subject &resetSig() const { return m_resetsig; } + /** @} */ // end group signals + + /** + * Signaling object to attatch observers to. + */ + class FocusableListSubject: public FbTk::Subject { + public: + explicit FocusableListSubject(): m_win(0) { } + void notify(Focusable *win) { m_win = win; FbTk::Subject::notify(); } + /// @return context for this signal + Focusable *win() { return m_win; } + + private: + Focusable *m_win; + }; + +private: + void init(); + void addMatching(); + void checkUpdate(Focusable &win); + bool insertFromParent(Focusable &win); + void attachSignals(Focusable &win); + void detachSignals(Focusable &win); + void reset(); + void attachChild(FocusableList &child) const; + + 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; +}; + +#endif // FOCUSABLELIST_HH
M src/IconbarTool.ccsrc/IconbarTool.cc

@@ -38,6 +38,7 @@ #include "WinClient.hh"

#include "FocusControl.hh" #include "FbCommands.hh" #include "Layer.hh" +#include "STLUtil.hh" #include "FbTk/I18n.hh" #include "FbTk/Menu.hh"

@@ -68,26 +69,6 @@

namespace FbTk { 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, "NoIcons") == 0) - m_value = IconbarTool::NOICONS; - else if (strcasecmp(strval, "WorkspaceIcons") == 0) - m_value = IconbarTool::WORKSPACEICONS; - else if (strcasecmp(strval, "WorkspaceNoIcons") == 0) - m_value = IconbarTool::WORKSPACENOICONS; - 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; }

@@ -117,35 +98,6 @@ else

setDefaultValue(); } -template<> -string FbTk::Resource<IconbarTool::Mode>::getString() const { - - switch (m_value) { - case IconbarTool::NONE: - return string("None"); - break; - case IconbarTool::ICONS: - return string("Icons"); - break; - case IconbarTool::NOICONS: - return string("NoIcons"); - break; - case IconbarTool::WORKSPACEICONS: - return string("WorkspaceIcons"); - break; - case IconbarTool::WORKSPACENOICONS: - return string("WorkspaceNoIcons"); - break; - case IconbarTool::WORKSPACE: - return string("Workspace"); - break; - case IconbarTool::ALLWINDOWS: - return string("AllWindows"); - break; - } - // default string - return string("Icons"); -} } // end namespace FbTk namespace {

@@ -153,7 +105,7 @@

class ToolbarModeMenuItem : public FbTk::MenuItem { public: ToolbarModeMenuItem(const FbTk::FbString &label, IconbarTool &handler, - IconbarTool::Mode mode, + string mode, FbTk::RefCount<FbTk::Command> &cmd): FbTk::MenuItem(label, cmd), m_handler(handler), m_mode(mode) { }

@@ -165,7 +117,7 @@ }

private: IconbarTool &m_handler; - IconbarTool::Mode m_mode; + string m_mode; }; class ToolbarAlignMenuItem: public FbTk::MenuItem {

@@ -198,42 +150,42 @@

menu.insert(new ToolbarModeMenuItem(_FB_XTEXT(Toolbar, IconbarModeNone, "None", "No icons are shown in the iconbar"), handler, - IconbarTool::NONE, saverc_cmd)); + "none", saverc_cmd)); menu.insert(new ToolbarModeMenuItem( _FB_XTEXT(Toolbar, IconbarModeIcons, "Icons", "Iconified windows from all workspaces are shown"), handler, - IconbarTool::ICONS, saverc_cmd)); + "{static groups} (minimized=yes)", saverc_cmd)); menu.insert(new ToolbarModeMenuItem( _FB_XTEXT(Toolbar, IconbarModeNoIcons, "NoIcons", "No iconified windows from all workspaces are shown"), handler, - IconbarTool::NOICONS, saverc_cmd)); + "{static groups} (minimized=no)", saverc_cmd)); menu.insert(new ToolbarModeMenuItem( _FB_XTEXT(Toolbar, IconbarModeWorkspaceIcons, "WorkspaceIcons", "Iconified windows from this workspace are shown"), handler, - IconbarTool::WORKSPACEICONS, saverc_cmd)); + "{static groups} (minimized=yes) (workspace)", saverc_cmd)); menu.insert(new ToolbarModeMenuItem( _FB_XTEXT(Toolbar, IconbarModeWorkspaceNoIcons, "WorkspaceNoIcons", "No iconified windows from this workspace are shown"), handler, - IconbarTool::WORKSPACENOICONS, saverc_cmd)); + "{static groups} (minimized=no) (workspace)", saverc_cmd)); menu.insert(new ToolbarModeMenuItem( _FB_XTEXT(Toolbar, IconbarModeWorkspace, "Workspace", "Normal and iconified windows from this workspace are shown"), handler, - IconbarTool::WORKSPACE, saverc_cmd)); + "{static groups} (workspace)", saverc_cmd)); menu.insert(new ToolbarModeMenuItem( _FB_XTEXT(Toolbar, IconbarModeAllWindows, "All Windows", "All windows are shown"), handler, - IconbarTool::ALLWINDOWS, saverc_cmd)); + "{static groups}", saverc_cmd)); menu.insert(new FbTk::MenuSeparator());

@@ -257,26 +209,6 @@

menu.updateMenu(); } -inline bool checkAddWindow(IconbarTool::Mode mode, const FluxboxWindow &win) { - if (win.isIconHidden() || mode == IconbarTool::NONE) - return false; - - if ((mode == IconbarTool::ICONS || mode == IconbarTool::WORKSPACEICONS) && - !win.isIconic()) - return false; - - if ((mode == IconbarTool::NOICONS || mode == IconbarTool::WORKSPACENOICONS) - && win.isIconic()) - return false; - - if ((mode == IconbarTool::WORKSPACE || mode == IconbarTool::WORKSPACEICONS - || mode == IconbarTool::WORKSPACENOICONS) && - win.workspaceNumber() != win.screen().currentWorkspaceID()) - return false; - - return true; -} - typedef FbTk::RefCount<FbTk::Command> RefCmd; class ShowMenu: public FbTk::Command {

@@ -322,14 +254,16 @@ };

}; // end anonymous namespace -IconbarTool::IconbarTool(const FbTk::FbWindow &parent, IconbarTheme &theme, BScreen &screen, - FbTk::Menu &menu): +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_empty_pm( screen.imageControl() ), - m_rc_mode(screen.resourceManager(), WORKSPACE, + m_winlist(new FocusableList(screen)), + m_mode("none"), + m_rc_mode(screen.resourceManager(), "{static groups} (workspace)", screen.name() + ".iconbar.mode", screen.altName() + ".Iconbar.Mode"), m_rc_alignment(screen.resourceManager(), Container::LEFT, screen.name() + ".iconbar.alignment", screen.altName() + ".Iconbar.Alignment"),

@@ -365,10 +299,7 @@ menu.insert(m_menu.label(), &m_menu);

// setup signals theme.reconfigSig().attach(this); - screen.clientListSig().attach(this); - screen.iconListSig().attach(this); - screen.currentWorkspaceSig().attach(this); - + setMode(*m_rc_mode); } IconbarTool::~IconbarTool() {

@@ -405,20 +336,33 @@ update(0);

m_menu.reconfigure(); } -void IconbarTool::setMode(Mode mode) { - if (mode == *m_rc_mode) +void IconbarTool::setMode(string mode) { + if (mode == m_mode) return; - *m_rc_mode = mode; + *m_rc_mode = m_mode = mode; // lock graphics update m_icon_container.setUpdateLock(true); - deleteIcons(); - - // update mode - if (mode != NONE) - updateList(); + if (m_winlist.get()) { + m_winlist->addSig().detach(this); + m_winlist->removeSig().detach(this); + m_winlist->orderSig().detach(this); + m_winlist->resetSig().detach(this); + } + if (mode == "none") + m_winlist.reset(new FocusableList(m_screen)); + else + m_winlist.reset(new FocusableList(m_screen, + mode + " (iconhidden=no)")); + if (m_winlist.get()) { + m_winlist->addSig().attach(this); + m_winlist->removeSig().attach(this); + m_winlist->orderSig().attach(this); + m_winlist->resetSig().attach(this); + } + reset(); // unlock graphics update m_icon_container.setUpdateLock(false);

@@ -445,10 +389,7 @@

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()) + if (!m_icons.empty()) deleteIcons(); return; }

@@ -462,68 +403,26 @@ *m_rc_client_width = 400;

m_icon_container.setMaxSizePerClient(*m_rc_client_width); - - if (mode() == NONE) { - if (subj != 0 && typeid(*subj) == typeid(IconbarTheme)) - renderTheme(); + if (subj == &m_theme.reconfigSig()) { + setMode(*m_rc_mode); 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().workspaceSig())) { - // we can ignore this signal if we're in ALLWINDOWS mode - if (mode() == ALLWINDOWS || mode() == ICONS || mode() == NOICONS) - 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().stateSig())) { - if (!checkAddWindow(mode(), winsubj->win())) { - removeWindow(winsubj->win()); - renderTheme(); - } - return; - - } else { - // signal not handled - return; - } - } else if (subj != 0 && typeid(*subj) == typeid(Focusable::FocusSubject)) { - Focusable::FocusSubject *winsubj = static_cast<Focusable::FocusSubject *>(subj); - if (subj == &(winsubj->win().dieSig())) { // die sig - removeWindow(winsubj->win()); - renderTheme(); - return; // we don't need to update the entire list - } - } - - bool remove_all = false; // if we should readd all windows - - if (subj != 0 && typeid(*subj) == typeid(BScreen::ScreenSubject) && - mode() != ALLWINDOWS && mode() != ICONS && mode() != NOICONS) { - BScreen::ScreenSubject *screen_subj = static_cast<BScreen::ScreenSubject *>(subj); - // current workspace sig - if (&m_screen.currentWorkspaceSig() == screen_subj ) { - remove_all = true; // remove and readd all windows - } - - } - // 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 - updateList(); + if (typeid(*subj) == typeid(FocusableList::FocusableListSubject)) { + FocusableList::FocusableListSubject *fsubj = + static_cast<FocusableList::FocusableListSubject *>(subj); + if (subj == &m_winlist->addSig()) + insertWindow(*fsubj->win()); + else if (subj == &m_winlist->removeSig()) + removeWindow(*fsubj->win()); + else if (subj == &m_winlist->resetSig()) + reset(); + else if (subj == &m_winlist->orderSig()) + insertWindow(*fsubj->win()); + } // unlock container and update graphics m_icon_container.setUpdateLock(false);

@@ -540,25 +439,42 @@ // so text can end up behind program icons

renderTheme(); } -IconButton *IconbarTool::findButton(Focusable &win) { +void IconbarTool::insertWindow(Focusable &win, int pos) { + IconButton *button = 0; + + IconMap::iterator icon_it = m_icons.find(&win); + if (icon_it != m_icons.end()) + button = icon_it->second; + + if (button) + m_icon_container.removeItem(button); + else + button = makeButton(win); + if (!button) return; - 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; + if (pos == -2) { + pos = 0; + list<Focusable *>::iterator it = m_winlist->clientList().begin(), + it_end = m_winlist->clientList().end(); + for (; it != it_end && *it != &win; ++it) + pos++; } - return 0; + m_icon_container.insertItem(button, pos); +} + +void IconbarTool::reset() { + deleteIcons(); + updateList(); } void IconbarTool::updateSizing() { m_icon_container.setBorderWidth(m_theme.border().width()); - IconList::iterator icon_it = m_icon_list.begin(); - const IconList::iterator icon_it_end = m_icon_list.end(); + IconMap::iterator icon_it = m_icons.begin(); + const IconMap::iterator icon_it_end = m_icons.end(); for (; icon_it != icon_it_end; ++icon_it) - (*icon_it)->reconfigTheme(); + icon_it->second->reconfigTheme(); }

@@ -588,10 +504,10 @@

m_icon_container.setAlpha(m_alpha); // update buttons - IconList::iterator icon_it = m_icon_list.begin(); - const IconList::iterator icon_it_end = m_icon_list.end(); + IconMap::iterator icon_it = m_icons.begin(); + const IconMap::iterator icon_it_end = m_icons.end(); for (; icon_it != icon_it_end; ++icon_it) - renderButton(*(*icon_it)); + renderButton(*icon_it->second); }

@@ -606,49 +522,30 @@ }

void IconbarTool::deleteIcons() { m_icon_container.removeAll(); - while (!m_icon_list.empty()) { - delete m_icon_list.back(); - m_icon_list.pop_back(); - } + STLUtil::destroyAndClearSecond(m_icons); } void IconbarTool::removeWindow(Focusable &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()) { + IconMap::iterator it = m_icons.find(&win); + if (it == m_icons.end()) return; - } #ifdef DEBUG cerr<<"IconbarTool::"<<__FUNCTION__<<"( 0x"<<&win<<" title = "<<win.title()<<") found!"<<endl; #endif // DEBUG - // detach from all signals - win.dieSig().detach(this); - if (win.fbwindow()) { - win.fbwindow()->workspaceSig().detach(this); - win.fbwindow()->stateSig().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); - + IconButton *button = it->second; + m_icons.erase(it); + m_icon_container.removeItem(button); delete button; - } -void IconbarTool::addWindow(Focusable &win) { +IconButton *IconbarTool::makeButton(Focusable &win) { // we just want windows that have clients FluxboxWindow *fbwin = win.fbwindow(); - if (!fbwin || fbwin->clientList().empty() || fbwin->isIconHidden()) - return; + if (!fbwin || fbwin->clientList().empty()) + return 0; #ifdef DEBUG cerr<<"IconbarTool::addWindow(0x"<<&win<<" title = "<<win.title()<<")"<<endl; #endif // DEBUG

@@ -660,37 +557,19 @@ button->setOnClick(focus_cmd, 1);

button->setOnClick(menu_cmd, 3); renderButton(*button, false); // update the attributes, but don't clear it - m_icon_container.insertItem(button); - m_icon_list.push_back(button); - - // dont forget to detach signal in removeWindow - win.dieSig().attach(this); - fbwin->workspaceSig().attach(this); - fbwin->stateSig().attach(this); + m_icons[&win] = button; + return button; } void IconbarTool::updateList() { - list<Focusable *> ordered_list = - m_screen.focusControl().creationOrderWinList(); - list<Focusable *>::iterator it = ordered_list.begin(); - list<Focusable *>::iterator it_end = ordered_list.end(); + list<Focusable *>::iterator it = m_winlist->clientList().begin(); + list<Focusable *>::iterator it_end = m_winlist->clientList().end(); for (; it != it_end; ++it) { - if ((*it)->fbwindow() && checkAddWindow(mode(), *(*it)->fbwindow()) && - !checkDuplicate(**it)) - addWindow(**it); + if ((*it)->fbwindow()) + insertWindow(**it, -1); } renderTheme(); -} - -bool IconbarTool::checkDuplicate(Focusable &win) { - IconList::iterator it = m_icon_list.begin(); - IconList::iterator it_end = m_icon_list.end(); - for (; it != it_end; ++it) { - if (&win == &(*it)->win()) - return true; - } - return false; } void IconbarTool::setOrientation(FbTk::Orientation orient) {
M src/IconbarTool.hhsrc/IconbarTool.hh

@@ -28,6 +28,7 @@

#include "ToolbarItem.hh" #include "Container.hh" #include "FbMenu.hh" +#include "FocusableList.hh" #include "FbTk/CachedPixmap.hh" #include "FbTk/Observer.hh"

@@ -36,7 +37,7 @@ #include "FbTk/Menu.hh"

#include <X11/Xlib.h> -#include <list> +#include <map> class IconbarTheme; class BScreen;

@@ -45,17 +46,7 @@ class Focusable;

class IconbarTool: public ToolbarItem, public FbTk::Observer { public: - typedef std::list<IconButton *> IconList; - /// iconbar mode - enum Mode { - NONE, ///< no icons - ICONS, ///< all icons from all workspaces - NOICONS, ///< all noniconified windows from all workspaces - WORKSPACEICONS, ///< icons on current workspace - WORKSPACENOICONS, ///< non iconified workspaces on current workspaces - WORKSPACE, ///< all windows and all icons on current workspace - ALLWINDOWS ///< all windows and all icons from all workspaces - }; + typedef std::map<Focusable *, IconButton *> IconMap; IconbarTool(const FbTk::FbWindow &parent, IconbarTheme &theme, BScreen &screen, FbTk::Menu &menu);

@@ -70,14 +61,14 @@ void update(FbTk::Subject *subj);

void show(); void hide(); void setAlignment(Container::Alignment a); - void setMode(Mode mode); + void setMode(std::string mode); void parentMoved() { m_icon_container.parentMoved(); } unsigned int width() const; unsigned int height() const; unsigned int borderWidth() const; - Mode mode() const { return *m_rc_mode; } + std::string mode() const { return *m_rc_mode; } void setOrientation(FbTk::Orientation orient); Container::Alignment alignment() const { return m_icon_container.alignment(); }

@@ -85,9 +76,6 @@

const BScreen &screen() const { return m_screen; } private: - /// @return button associated with window - IconButton *findButton(Focusable &win); - void updateSizing(); /// render single button, and probably apply changes (clear)

@@ -99,14 +87,16 @@ void renderTheme();

void renderTheme(unsigned char alpha); /// destroy all icons void deleteIcons(); + /// add or move a single window + void insertWindow(Focusable &win, int pos = -2); /// remove a single window void removeWindow(Focusable &win); - /// add a single window - void addWindow(Focusable &win); + /// make a button for the window + IconButton *makeButton(Focusable &win); + /// remove all windows and add again + void reset(); /// add icons to the list void updateList(); - /// check if window is already in the list - bool checkDuplicate(Focusable &win); BScreen &m_screen; Container m_icon_container;

@@ -114,8 +104,10 @@ IconbarTheme &m_theme;

FbTk::CachedPixmap m_empty_pm; ///< pixmap for empty container - IconList m_icon_list; - FbTk::Resource<Mode> m_rc_mode; + std::auto_ptr<FocusableList> m_winlist; + IconMap m_icons; + std::string m_mode; + FbTk::Resource<std::string> m_rc_mode; FbTk::Resource<Container::Alignment> m_rc_alignment; ///< alignment of buttons FbTk::Resource<int> m_rc_client_width; ///< size of client button in LEFT/RIGHT mode FbTk::Resource<unsigned int> m_rc_client_padding; ///< padding of the text
M src/Makefile.amsrc/Makefile.am

@@ -151,7 +151,7 @@ AttentionNoticeHandler.hh AttentionNoticeHandler.cc \

IconButton.hh IconButton.cc \ IconbarTheme.hh IconbarTheme.cc \ STLUtil.hh \ - Focusable.hh \ + Focusable.hh FocusableList.hh FocusableList.cc \ ${newwmspec_SOURCE} ${gnome_SOURCE} \ ${REMEMBER_SOURCE} ${TOOLBAR_SOURCE}
M src/MinOverlapPlacement.ccsrc/MinOverlapPlacement.cc

@@ -40,7 +40,7 @@ int &place_x, int &place_y) {

std::list<FluxboxWindow *> windowlist; const std::list<Focusable *> focusables = - win.screen().focusControl().focusedOrderWinList(); + win.screen().focusControl().focusedOrderWinList().clientList(); std::list<Focusable *>::const_iterator foc_it = focusables.begin(), foc_it_end = focusables.end(); unsigned int workspace = win.workspaceNumber();
M src/RowSmartPlacement.ccsrc/RowSmartPlacement.cc

@@ -33,7 +33,7 @@ int &place_x, int &place_y) {

std::list<FluxboxWindow *> windowlist; const std::list<Focusable *> focusables = - win.screen().focusControl().focusedOrderWinList(); + win.screen().focusControl().focusedOrderWinList().clientList(); std::list<Focusable *>::const_iterator foc_it = focusables.begin(), foc_it_end = focusables.end(); unsigned int workspace = win.workspaceNumber();
M src/Screen.ccsrc/Screen.cc

@@ -346,6 +346,7 @@ m_workspacecount_sig(*this), // workspace count signal

m_workspacenames_sig(*this), // workspace names signal m_workspace_area_sig(*this), // workspace area signal m_currentworkspace_sig(*this), // current workspace signal + m_focusedwindow_sig(*this), // focused window signal m_reconfigure_sig(*this), // reconfigure signal m_resize_sig(*this), m_bg_change_sig(*this),

@@ -871,19 +872,10 @@ FbTk::EventManager::instance()->grabKeyboard(*this, rootWindow().window());

} if (mods == 0) // can't stacked cycle unless there is a mod to grab - options |= FocusControl::CYCLELINEAR; + options |= FocusableList::STATIC_ORDER; - const FocusControl::Focusables *win_list = 0; - if (options & FocusControl::CYCLEGROUPS) { - win_list = (options & FocusControl::CYCLELINEAR) ? - &focusControl().creationOrderWinList() : - &focusControl().focusedOrderWinList(); - } else { - win_list = (options & FocusControl::CYCLELINEAR) ? - &focusControl().creationOrderList() : - &focusControl().focusedOrderList(); - } - + const FocusableList *win_list = + FocusableList::getListFromOptions(*this, options); focusControl().cycleFocus(*win_list, pat, reverse); }
M src/Screen.hhsrc/Screen.hh

@@ -222,6 +222,8 @@ /// workspace area signal

FbTk::Subject &workspaceAreaSig() { return m_workspace_area_sig; } /// current workspace signal FbTk::Subject &currentWorkspaceSig() { return m_currentworkspace_sig; } + /// focused window signal + FbTk::Subject &focusedWindowSig() { return m_focusedwindow_sig; } /// reconfigure signal FbTk::Subject &reconfigureSig() { return m_reconfigure_sig; } FbTk::Subject &resizeSig() { return m_resize_sig; }

@@ -488,6 +490,7 @@ m_workspacecount_sig, ///< workspace count signal

m_workspacenames_sig, ///< workspace names signal m_workspace_area_sig, ///< workspace area changed signal m_currentworkspace_sig, ///< current workspace signal + m_focusedwindow_sig, ///< focused window signal m_reconfigure_sig, ///< reconfigure signal m_resize_sig, ///< resize signal m_bg_change_sig; ///< background change signal
M src/Window.ccsrc/Window.cc

@@ -1405,7 +1405,7 @@ iconic = true;

hide(true); - screen().focusControl().setFocusBack(this); + screen().focusControl().setFocusBack(*this); ClientList::iterator client_it = m_clientlist.begin(); const ClientList::iterator client_it_end = m_clientlist.end();

@@ -2038,10 +2038,6 @@ else if (new_state == NormalState)

(*it)->show(); (*it)->setEventMask(PropertyChangeMask | StructureNotifyMask | FocusChangeMask | KeyPressMask); } - - saveBlackboxAttribs(); - //notify state changed - m_statesig.notify(); } bool FluxboxWindow::getState() {
M src/WorkspaceCmd.ccsrc/WorkspaceCmd.cc

@@ -49,7 +49,7 @@ }

BScreen *screen = Fluxbox::instance()->keyScreen(); if (screen != 0) { - FocusControl::Focusables win_list(screen->focusControl().creationOrderWinList()); + FocusControl::Focusables win_list(screen->focusControl().creationOrderWinList().clientList()); FocusControl::Focusables::iterator it = win_list.begin(), it_end = win_list.end();

@@ -63,7 +63,7 @@

void AttachCmd::execute() { BScreen *screen = Fluxbox::instance()->keyScreen(); if (screen != 0) { - FocusControl::Focusables win_list(screen->focusControl().focusedOrderWinList()); + FocusControl::Focusables win_list(screen->focusControl().focusedOrderWinList().clientList()); FocusControl::Focusables::iterator it = win_list.begin(), it_end = win_list.end();

@@ -95,16 +95,8 @@

void GoToWindowCmd::execute() { BScreen *screen = Fluxbox::instance()->keyScreen(); if (screen != 0) { - const FocusControl::Focusables *win_list = 0; - if (m_option & FocusControl::CYCLEGROUPS) { - win_list = (m_option & FocusControl::CYCLELINEAR) ? - &screen->focusControl().creationOrderWinList() : - &screen->focusControl().focusedOrderWinList(); - } else { - win_list = (m_option & FocusControl::CYCLELINEAR) ? - &screen->focusControl().creationOrderList() : - &screen->focusControl().focusedOrderList(); - } + const FocusableList *win_list = + FocusableList::getListFromOptions(*screen, m_option); screen->focusControl().goToWindowNumber(*win_list, m_num, &m_pat); } }
M src/fluxbox.ccsrc/fluxbox.cc

@@ -514,6 +514,7 @@ screen->initWindows();

// attach screen signals to this screen->currentWorkspaceSig().attach(this); + screen->focusedWindowSig().attach(this); screen->workspaceCountSig().attach(this); screen->workspaceNamesSig().attach(this); screen->workspaceAreaSig().attach(this);

@@ -642,7 +643,7 @@ // copy init file

if (create_init) FbTk::FileUtil::copyFile(DEFAULT_INITFILE, init_file.c_str()); -#define CONFIG_VERSION 4 +#define CONFIG_VERSION 5 FbTk::Resource<int> config_version(m_resourcemanager, 0, "session.configVersion", "Session.ConfigVersion"); if (*config_version < CONFIG_VERSION) {

@@ -1191,6 +1192,14 @@ it != m_atomhandler.end(); ++it) {

if ((*it).first->update()) (*it).first->updateCurrentWorkspace(screen); } + } else if ((&(screen.focusedWindowSig())) == changedsub) { + for (AtomHandlerContainerIt it= m_atomhandler.begin(); + it != m_atomhandler.end(); it++) { + (*it).first->updateFocusedWindow(screen, + (FocusControl::focusedWindow() ? + FocusControl::focusedWindow()->window() : + 0)); + } } else if ((&(screen.workspaceAreaSig())) == changedsub) { for (AtomHandlerContainerIt it= m_atomhandler.begin(); it != m_atomhandler.end(); ++it) {

@@ -1680,23 +1689,6 @@ m_window_search.end(),

Compose(bind2nd(equal_to<WinClient *>(), client), Select2nd<WinClientMap::value_type>())); return it != m_window_search.end(); -} - -void Fluxbox::updateFocusedWindow(BScreen *screen, BScreen *old_screen) { - if (screen != 0) { - for (AtomHandlerContainerIt it= m_atomhandler.begin(); - it != m_atomhandler.end(); it++) { - (*it).first->updateFocusedWindow(*screen, (FocusControl::focusedWindow() ? - FocusControl::focusedWindow()->window() : - 0)); - } - } - - if (old_screen && old_screen != screen) { - for (AtomHandlerContainerIt it= m_atomhandler.begin(); - it != m_atomhandler.end(); it++) - (*it).first->updateFocusedWindow(*old_screen, 0); - } } void Fluxbox::updateFrameExtents(FluxboxWindow &win) {
M src/fluxbox.hhsrc/fluxbox.hh

@@ -162,12 +162,6 @@

/// handle any system signal sent to the application void handleSignal(int signum); void update(FbTk::Subject *changed); - /** - * Sends update signal to atomhandlers, - * @param screen the new screen - * @param old_screen the old screen if any, can be the same as new screen - */ - void updateFocusedWindow(BScreen *screen, BScreen *old_screen); /// todo, remove this. just temporary void updateFrameExtents(FluxboxWindow &win);
M util/fluxbox-update_configs.ccutil/fluxbox-update_configs.cc

@@ -64,7 +64,7 @@ string read_file(string filename);

void write_file(string filename, string &contents); void save_all_files(); -int run_updates(int old_version, FbTk::ResourceManager rm) { +int run_updates(int old_version, FbTk::ResourceManager &rm) { int new_version = old_version; FbTk::Resource<string> rc_keyfile(rm, "~/.fluxbox/keys",

@@ -212,6 +212,31 @@ new_keyfile += whole_keyfile; // don't forget user's old keybindings

write_file(keyfilename, new_keyfile); new_version = 4; + } + + if (old_version < 5) { // window patterns for iconbar + // this needs to survive after going out of scope + // it won't get freed, but that's ok + FbTk::Resource<string> *rc_mode = + new FbTk::Resource<string>(rm, "Workspace", + "session.screen0.iconbar.mode", + "Session.Screen0.Iconbar.Mode"); + if (strcasecmp((**rc_mode).c_str(), "None") == 0) + *rc_mode = "none"; + else if (strcasecmp((**rc_mode).c_str(), "Icons") == 0) + *rc_mode = "{static groups} (minimized=yes)"; + else if (strcasecmp((**rc_mode).c_str(), "NoIcons") == 0) + *rc_mode = "{static groups} (minimized=no)"; + else if (strcasecmp((**rc_mode).c_str(), "WorkspaceIcons") == 0) + *rc_mode = "{static groups} (minimized=yes) (workspace)"; + else if (strcasecmp((**rc_mode).c_str(), "WorkspaceNoIcons") == 0) + *rc_mode = "{static groups} (minimized=no) (workspace)"; + else if (strcasecmp((**rc_mode).c_str(), "AllWindows") == 0) + *rc_mode = "{static groups}"; + else + *rc_mode = "{static groups} (workspace)"; + + new_version = 5; } return new_version;