From 5d7043320da1378e7dd3b10f7e425f3b47455b28 Mon Sep 17 00:00:00 2001 From: markt Date: Mon, 12 Nov 2007 21:59:43 +0000 Subject: allow arbitrary window patterns in iconbar --- ChangeLog | 6 + data/init.in | 2 +- doc/asciidoc/fluxbox.txt | 13 +- src/ClientPattern.cc | 36 ++++- src/ClientPattern.hh | 6 + src/ColSmartPlacement.cc | 2 +- src/Ewmh.cc | 3 +- src/FbCommandFactory.cc | 39 ++--- src/FbCommands.cc | 18 +-- src/FbCommands.hh | 3 +- src/FbTk/Subject.cc | 24 ++-- src/FocusControl.cc | 127 +++++++---------- src/FocusControl.hh | 31 ++-- src/Focusable.hh | 2 +- src/FocusableList.cc | 293 ++++++++++++++++++++++++++++++++++++++ src/FocusableList.hh | 121 ++++++++++++++++ src/IconbarTool.cc | 315 +++++++++++++---------------------------- src/IconbarTool.hh | 38 ++--- src/Makefile.am | 2 +- src/MinOverlapPlacement.cc | 2 +- src/RowSmartPlacement.cc | 2 +- src/Screen.cc | 16 +-- src/Screen.hh | 3 + src/Window.cc | 6 +- src/WorkspaceCmd.cc | 16 +-- src/fluxbox.cc | 28 ++-- src/fluxbox.hh | 6 - util/fluxbox-update_configs.cc | 27 +++- 28 files changed, 724 insertions(+), 463 deletions(-) create mode 100644 src/FocusableList.cc create mode 100644 src/FocusableList.hh diff --git a/ChangeLog b/ChangeLog index 089264d..23e7751 100644 --- a/ChangeLog +++ b/ChangeLog @@ -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 diff --git a/data/init.in b/data/init.in index 10727c3..1fb45e1 100644 --- a/data/init.in +++ b/data/init.in @@ -31,4 +31,4 @@ session.colorsPerChannel: 4 session.doubleClickInterval: 250 session.cacheMax: 200 session.imageDither: True -session.configVersion: 4 +session.configVersion: 5 diff --git a/doc/asciidoc/fluxbox.txt b/doc/asciidoc/fluxbox.txt index 5e4cf07..a2f648e 100644 --- a/doc/asciidoc/fluxbox.txt +++ b/doc/asciidoc/fluxbox.txt @@ -779,15 +779,10 @@ session.screen0.toolbar.onhead: 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: - 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: + 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: This is also set in the Iconbar Mode menu. When set to True, this will diff --git a/src/ClientPattern.cc b/src/ClientPattern.cc index 9ee1848..d094e63 100644 --- a/src/ClientPattern.cc +++ b/src/ClientPattern.cc @@ -274,9 +274,19 @@ bool ClientPattern::match(const Focusable &win) const { 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]") { @@ -293,6 +303,26 @@ bool ClientPattern::match(const Focusable &win) const { 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 // The first argument is a regular expression, the second is the member // function that we wish to match against. diff --git a/src/ClientPattern.hh b/src/ClientPattern.hh index a6d1ede..b76aef8 100644 --- a/src/ClientPattern.hh +++ b/src/ClientPattern.hh @@ -62,6 +62,12 @@ public: /// 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 diff --git a/src/ColSmartPlacement.cc b/src/ColSmartPlacement.cc index bdffa41..0fbae68 100644 --- a/src/ColSmartPlacement.cc +++ b/src/ColSmartPlacement.cc @@ -33,7 +33,7 @@ bool ColSmartPlacement::placeWindow(const FluxboxWindow &win, int head, std::list windowlist; const std::list focusables = - win.screen().focusControl().focusedOrderWinList(); + win.screen().focusControl().focusedOrderWinList().clientList(); std::list::const_iterator foc_it = focusables.begin(), foc_it_end = focusables.end(); unsigned int workspace = win.workspaceNumber(); diff --git a/src/Ewmh.cc b/src/Ewmh.cc index 3e01e36..ee98944 100644 --- a/src/Ewmh.cc +++ b/src/Ewmh.cc @@ -345,7 +345,8 @@ void Ewmh::updateClientList(BScreen &screen) { if (screen.isShuttingdown()) return; - list creation_order_list = screen.focusControl().creationOrderList(); + list creation_order_list = + screen.focusControl().creationOrderList().clientList(); size_t num = creation_order_list.size(); Window *wl = FB_new_nothrow Window[num]; diff --git a/src/FbCommandFactory.cc b/src/FbCommandFactory.cc index d347878..72de740 100644 --- a/src/FbCommandFactory.cc +++ b/src/FbCommandFactory.cc @@ -24,6 +24,7 @@ #include "FbCommandFactory.hh" +#include "FocusableList.hh" #include "CurrentWindowCmd.hh" #include "FbCommands.hh" #include "Window.hh" @@ -59,26 +60,6 @@ static int getint(const char *str, int 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 args; - FbTk::StringUtil::stringtok(args, options); - vector::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 FbCommandFactory::FbCommandFactory() { @@ -522,29 +503,29 @@ FbTk::Command *FbCommandFactory::stringToCommand(const std::string &command, } 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 @@ FbTk::Command *FbCommandFactory::stringToCommand(const std::string &command, 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); diff --git a/src/FbCommands.cc b/src/FbCommands.cc index 698f2db..28c0a30 100644 --- a/src/FbCommands.cc +++ b/src/FbCommands.cc @@ -277,20 +277,12 @@ void ShowClientMenuCmd::execute() { 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(*it)); diff --git a/src/FbCommands.hh b/src/FbCommands.hh index c563899..c130050 100644 --- a/src/FbCommands.hh +++ b/src/FbCommands.hh @@ -31,6 +31,7 @@ #include "FbTk/RefCount.hh" #include "ClientMenu.hh" #include "ClientPattern.hh" +#include "FocusableList.hh" #include #include @@ -118,7 +119,7 @@ public: 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; diff --git a/src/FbTk/Subject.cc b/src/FbTk/Subject.cc index 08a211c..7ff80cf 100644 --- a/src/FbTk/Subject.cc +++ b/src/FbTk/Subject.cc @@ -58,16 +58,22 @@ void Subject::detach(Observer *obj) { } 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(); } } diff --git a/src/FocusControl.cc b/src/FocusControl.cc index 7bc1db4..ae5b5e3 100644 --- a/src/FocusControl.cc +++ b/src/FocusControl.cc @@ -78,15 +78,17 @@ FocusControl::FocusControl(BScreen &screen): 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 @@ void FocusControl::cycleFocus(const Focusables &window_list, } 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 @@ void FocusControl::cycleFocus(const Focusables &window_list, } -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::goToWindowNumber(const Focusables &winlist, int num, } 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); + m_focused_win_list.moveToBack(fbwin); - Focusables::iterator it = m_focused_list.begin(); - // use back to avoid an infinite loop - Focusables::iterator it_back = --m_focused_list.end(); - - while (it != it_back) { - if ((*it)->fbwindow() == fbwin) { - m_focused_list.push_back(*it); - it = m_focused_list.erase(it); - } else - ++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); + // 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); } - } - + void FocusControl::stopCyclingFocus() { // nothing to do if (m_cycling_list == 0) @@ -262,10 +246,10 @@ void FocusControl::stopCyclingFocus() { 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 *igno 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 @@ void FocusControl::setScreenFocusedWindow(WinClient &win_client) { // 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(*it); if (client && client->fbwindow()) client->fbwindow()->restore(client, true); @@ -582,7 +548,10 @@ void FocusControl::setFocusedWindow(WinClient *client) { } // 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 diff --git a/src/FocusControl.hh b/src/FocusControl.hh index 4e2ceab..84f0269 100644 --- a/src/FocusControl.hh +++ b/src/FocusControl.hh @@ -27,6 +27,7 @@ #include #include "FbTk/Resource.hh" +#include "FocusableList.hh" class ClientPattern; class WinClient; @@ -60,12 +61,6 @@ public: 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 @@ public: * @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 @@ public: 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 @@ public: 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 @@ private: // 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; diff --git a/src/Focusable.hh b/src/Focusable.hh index 3903e25..5a2f40c 100644 --- a/src/Focusable.hh +++ b/src/Focusable.hh @@ -19,7 +19,7 @@ // 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 diff --git a/src/FocusableList.cc b/src/FocusableList.cc new file mode 100644 index 0000000..8a5c8f7 --- /dev/null +++ b/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 + +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 args; + FbTk::StringUtil::stringtok(args, options); + vector::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(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(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 list = fbwin.clientList(); + std::list::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(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); +} diff --git a/src/FocusableList.hh b/src/FocusableList.hh new file mode 100644 index 0000000..7cca298 --- /dev/null +++ b/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 +#include + +class BScreen; +class Focusable; + +class FocusableList: public FbTk::Observer, private FbTk::NotCopyable { +public: + typedef std::list 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 m_pat; + const FocusableList *m_parent; + BScreen &m_screen; + std::list m_list; + + mutable FocusableListSubject m_ordersig, m_addsig, m_removesig, m_resetsig; +}; + +#endif // FOCUSABLELIST_HH diff --git a/src/IconbarTool.cc b/src/IconbarTool.cc index bbd867b..1a4e87c 100644 --- a/src/IconbarTool.cc +++ b/src/IconbarTool.cc @@ -38,6 +38,7 @@ #include "FocusControl.hh" #include "FbCommands.hh" #include "Layer.hh" +#include "STLUtil.hh" #include "FbTk/I18n.hh" #include "FbTk/Menu.hh" @@ -68,26 +69,6 @@ using std::endl; namespace FbTk { template<> -void FbTk::Resource::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::setDefaultValue() { m_value = Container::RELATIVE; } @@ -117,35 +98,6 @@ void FbTk::Resource::setFromString(const char *str) { setDefaultValue(); } -template<> -string FbTk::Resource::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 @@ namespace { class ToolbarModeMenuItem : public FbTk::MenuItem { public: ToolbarModeMenuItem(const FbTk::FbString &label, IconbarTool &handler, - IconbarTool::Mode mode, + string mode, FbTk::RefCount &cmd): FbTk::MenuItem(label, cmd), m_handler(handler), m_mode(mode) { } @@ -165,7 +117,7 @@ public: private: IconbarTool &m_handler; - IconbarTool::Mode m_mode; + string m_mode; }; class ToolbarAlignMenuItem: public FbTk::MenuItem { @@ -198,42 +150,42 @@ void setupModeMenu(FbTk::Menu &menu, IconbarTool &handler) { 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 @@ void setupModeMenu(FbTk::Menu &menu, IconbarTool &handler) { 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 RefCmd; class ShowMenu: public FbTk::Command { @@ -322,14 +254,16 @@ private: }; // 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 @@ IconbarTool::IconbarTool(const FbTk::FbWindow &parent, IconbarTheme &theme, BScr // 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 @@ void IconbarTool::setAlignment(Container::Alignment align) { 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 @@ unsigned int IconbarTool::borderWidth() const { 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 @@ void IconbarTool::update(FbTk::Subject *subj) { 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(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(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(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(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 @@ void IconbarTool::update(FbTk::Subject *subj) { 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; - 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 (button) + m_icon_container.removeItem(button); + else + button = makeButton(win); + if (!button) return; + + if (pos == -2) { + pos = 0; + list::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 @@ void IconbarTool::renderTheme() { 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::renderButton(IconButton &button, bool clear) { 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 = "<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 = "<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 ordered_list = - m_screen.focusControl().creationOrderWinList(); - list::iterator it = ordered_list.begin(); - list::iterator it_end = ordered_list.end(); + list::iterator it = m_winlist->clientList().begin(); + list::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_icon_container.setOrientation(orient); ToolbarItem::setOrientation(orient); diff --git a/src/IconbarTool.hh b/src/IconbarTool.hh index 323c714..e1bebe3 100644 --- a/src/IconbarTool.hh +++ b/src/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 -#include +#include class IconbarTheme; class BScreen; @@ -45,17 +46,7 @@ class Focusable; class IconbarTool: public ToolbarItem, public FbTk::Observer { public: - typedef std::list 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 IconMap; IconbarTool(const FbTk::FbWindow &parent, IconbarTheme &theme, BScreen &screen, FbTk::Menu &menu); @@ -70,14 +61,14 @@ public: 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 @@ public: 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 @@ private: 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 @@ private: FbTk::CachedPixmap m_empty_pm; ///< pixmap for empty container - IconList m_icon_list; - FbTk::Resource m_rc_mode; + std::auto_ptr m_winlist; + IconMap m_icons; + std::string m_mode; + FbTk::Resource m_rc_mode; FbTk::Resource m_rc_alignment; ///< alignment of buttons FbTk::Resource m_rc_client_width; ///< size of client button in LEFT/RIGHT mode FbTk::Resource m_rc_client_padding; ///< padding of the text diff --git a/src/Makefile.am b/src/Makefile.am index 9245097..3ecc610 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -151,7 +151,7 @@ fluxbox_SOURCES = AtomHandler.hh ArrowButton.hh ArrowButton.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} diff --git a/src/MinOverlapPlacement.cc b/src/MinOverlapPlacement.cc index ce7ff3c..874aea8 100644 --- a/src/MinOverlapPlacement.cc +++ b/src/MinOverlapPlacement.cc @@ -40,7 +40,7 @@ bool MinOverlapPlacement::placeWindow(const FluxboxWindow &win, int head, std::list windowlist; const std::list focusables = - win.screen().focusControl().focusedOrderWinList(); + win.screen().focusControl().focusedOrderWinList().clientList(); std::list::const_iterator foc_it = focusables.begin(), foc_it_end = focusables.end(); unsigned int workspace = win.workspaceNumber(); diff --git a/src/RowSmartPlacement.cc b/src/RowSmartPlacement.cc index 6457d59..5d1786c 100644 --- a/src/RowSmartPlacement.cc +++ b/src/RowSmartPlacement.cc @@ -33,7 +33,7 @@ bool RowSmartPlacement::placeWindow(const FluxboxWindow &win, int head, std::list windowlist; const std::list focusables = - win.screen().focusControl().focusedOrderWinList(); + win.screen().focusControl().focusedOrderWinList().clientList(); std::list::const_iterator foc_it = focusables.begin(), foc_it_end = focusables.end(); unsigned int workspace = win.workspaceNumber(); diff --git a/src/Screen.cc b/src/Screen.cc index e618216..a53792b 100644 --- a/src/Screen.cc +++ b/src/Screen.cc @@ -346,6 +346,7 @@ BScreen::BScreen(FbTk::ResourceManager &rm, 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 @@ void BScreen::cycleFocus(int options, const ClientPattern *pat, bool reverse) { } if (mods == 0) // can't stacked cycle unless there is a mod to grab - options |= FocusControl::CYCLELINEAR; - - 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(); - } + options |= FocusableList::STATIC_ORDER; + const FocusableList *win_list = + FocusableList::getListFromOptions(*this, options); focusControl().cycleFocus(*win_list, pat, reverse); } diff --git a/src/Screen.hh b/src/Screen.hh index f5641e2..953411c 100644 --- a/src/Screen.hh +++ b/src/Screen.hh @@ -222,6 +222,8 @@ public: FbTk::Subject &workspaceAreaSig() { return m_workspace_area_sig; } /// current workspace signal FbTk::Subject ¤tWorkspaceSig() { 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 @@ private: 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 diff --git a/src/Window.cc b/src/Window.cc index 898111d..903756a 100644 --- a/src/Window.cc +++ b/src/Window.cc @@ -1405,7 +1405,7 @@ void FluxboxWindow::iconify() { 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 @@ void FluxboxWindow::setState(unsigned long new_state, bool setting_up) { (*it)->show(); (*it)->setEventMask(PropertyChangeMask | StructureNotifyMask | FocusChangeMask | KeyPressMask); } - - saveBlackboxAttribs(); - //notify state changed - m_statesig.notify(); } bool FluxboxWindow::getState() { diff --git a/src/WorkspaceCmd.cc b/src/WorkspaceCmd.cc index a525078..79ceb40 100644 --- a/src/WorkspaceCmd.cc +++ b/src/WorkspaceCmd.cc @@ -49,7 +49,7 @@ void WindowListCmd::execute() { 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 WindowListCmd::execute() { 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 PrevWindowCmd::execute() { 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); } } diff --git a/src/fluxbox.cc b/src/fluxbox.cc index ddb09e2..3c30c14 100644 --- a/src/fluxbox.cc +++ b/src/fluxbox.cc @@ -514,6 +514,7 @@ void Fluxbox::initScreen(BScreen *screen) { // 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 @@ void Fluxbox::setupConfigFiles() { if (create_init) FbTk::FileUtil::copyFile(DEFAULT_INITFILE, init_file.c_str()); -#define CONFIG_VERSION 4 +#define CONFIG_VERSION 5 FbTk::Resource config_version(m_resourcemanager, 0, "session.configVersion", "Session.ConfigVersion"); if (*config_version < CONFIG_VERSION) { @@ -1191,6 +1192,14 @@ void Fluxbox::update(FbTk::Subject *changedsub) { 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) { @@ -1682,23 +1691,6 @@ bool Fluxbox::validateClient(const WinClient *client) const { 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) { AtomHandlerContainerIt it = m_atomhandler.begin(); AtomHandlerContainerIt it_end = m_atomhandler.end(); diff --git a/src/fluxbox.hh b/src/fluxbox.hh index 82ff76d..d5a48c6 100644 --- a/src/fluxbox.hh +++ b/src/fluxbox.hh @@ -162,12 +162,6 @@ public: /// 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); diff --git a/util/fluxbox-update_configs.cc b/util/fluxbox-update_configs.cc index cca82bd..89b355f 100644 --- a/util/fluxbox-update_configs.cc +++ b/util/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 rc_keyfile(rm, "~/.fluxbox/keys", @@ -214,6 +214,31 @@ int run_updates(int old_version, FbTk::ResourceManager rm) { 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 *rc_mode = + new FbTk::Resource(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; } -- cgit v0.11.2