all repos — fluxbox @ 53f869aa528c6fee86d382ff4cfe6dc1046093c7

custom fork of the fluxbox windowmanager

reload the apps file on flux reload
simonb simonb
commit

53f869aa528c6fee86d382ff4cfe6dc1046093c7

parent

39cacd1da802e4aa2cd4fdeacf0cf2b436d87dfa

M ChangeLogChangeLog

@@ -1,6 +1,8 @@

(Format: Year/Month/Day) Changes for 0.9.16: *06/04/23: + * Reload the apps file on fluxbox reload (Simon) + Remember.hh/cc fluxbox.cc AtomHandler.hh ClientPattern.hh/cc * Update documentation for Next/PrevWindow (Simon / thanks Jonas Koelker), sf.net patch #1474825 doc/asciidoc/fluxbox.txt
M src/AtomHandler.hhsrc/AtomHandler.hh

@@ -59,6 +59,8 @@ BScreen * screen, WinClient * const winclient) = 0;

virtual bool propertyNotify(WinClient &winclient, Atom the_property) = 0; + virtual void reconfigure() {} + /// should this object be updated or not? bool update() const { return m_update; } protected:
M src/ClientPattern.ccsrc/ClientPattern.cc

@@ -257,3 +257,19 @@ break;

} return client.getWMClassName(); } + +bool ClientPattern::equals(const ClientPattern &pat) const { + // we require the terms to be identical (order too) + Terms::const_iterator it = m_terms.begin(); + Terms::const_iterator it_end = m_terms.end(); + Terms::const_iterator other_it = pat.m_terms.begin(); + Terms::const_iterator other_it_end = pat.m_terms.end(); + for (; it != it_end, other_it != other_it_end; ++it, ++other_it) { + if ((*it)->orig != (*other_it)->orig) + return false; + } + if (it != it_end || other_it != other_it_end) + return false; + + return true; +}
M src/ClientPattern.hhsrc/ClientPattern.hh

@@ -73,6 +73,9 @@ inline bool operator == (const WinClient &win) const {

return match(win); } + // whether this pattern has identical matching criteria + bool equals(const ClientPattern &pat) const; + /** * If there are no terms, then there is assumed to be an error * the column of the error is stored in m_matchlimit
M src/Remember.ccsrc/Remember.cc

@@ -36,6 +36,7 @@ #include "Layer.hh"

#include "FbTk/I18n.hh" #include "FbTk/StringUtil.hh" +#include "FbTk/FileUtil.hh" #include "FbTk/MenuItem.hh" #include "FbTk/App.hh" #include "FbTk/stringstream.hh"

@@ -230,13 +231,16 @@ ************/

Remember *Remember::s_instance = 0; -Remember::Remember() { +Remember::Remember(): + m_pats(new Patterns()), + m_last_timestamp(0) +{ if (s_instance != 0) throw string("Can not create more than one instance of Remember"); s_instance = this; enableUpdate(); - load(); + reconfigure(); } Remember::~Remember() {

@@ -247,11 +251,11 @@ // the patterns free the "Application"s

// the client mapping shouldn't need cleaning Patterns::iterator it; std::set<Application *> all_apps; // no duplicates - while (!m_pats.empty()) { - it = m_pats.begin(); + while (!m_pats->empty()) { + it = m_pats->begin(); delete it->first; // ClientPattern all_apps.insert(it->second); // Application, not necessarily unique - m_pats.erase(it); + m_pats->erase(it); } std::set<Application *>::iterator ait = all_apps.begin(); // no duplicates

@@ -270,8 +274,8 @@ Clients::iterator wc_it = m_clients.find(&winclient);

if (wc_it != m_clients.end()) return wc_it->second; else { - Patterns::iterator it = m_pats.begin(); - for (; it != m_pats.end(); it++) + Patterns::iterator it = m_pats->begin(); + for (; it != m_pats->end(); it++) if (it->first->match(winclient)) { it->first->addMatch(); m_clients[&winclient] = it->second;

@@ -289,7 +293,7 @@ // by default, we match against the WMClass of a window.

p->addTerm(p->getProperty(ClientPattern::NAME, winclient), ClientPattern::NAME); m_clients[&winclient] = app; p->addMatch(); - m_pats.push_back(make_pair(p, app)); + m_pats->push_back(make_pair(p, app)); return app; }

@@ -463,16 +467,66 @@ }

return row; } -void Remember::load() { +/* + This function is used to search for old instances of the same pattern + (when reloading apps file). More than one pattern might match, but only + if the application is the same (also note that they'll be adjacent). + We REMOVE and delete any matching patterns from the old list, as they're + effectively moved into the new +*/ + +Application *Remember::findMatchingPatterns(ClientPattern *pat, Patterns *patlist, bool is_group) { + Patterns::iterator it = patlist->begin(); + Patterns::iterator it_end = patlist->end(); + for (; it != it_end; ++it) { + if (it->first->equals(*pat) && is_group == it->second->is_grouped) { + Application *ret = it->second; + // find any previous or subsequent matching ones and delete + + // rewind + Patterns::iterator tmpit = it; + while (tmpit != patlist->begin()) { + --tmpit; + if (tmpit->second == ret) + it = tmpit; + else + break; + } + + // forward + while (it != it_end && it->second == ret) { + tmpit = it; + ++it; + delete tmpit->first; + patlist->erase(tmpit); + } + return ret; + } + } + + return 0; +} + + +void Remember::reconfigure() { string apps_string = FbTk::StringUtil::expandFilename(Fluxbox::instance()->getAppsFilename()); + time_t timestamp = FbTk::FileUtil::getLastStatusChangeTimestamp(apps_string.c_str()); + if (m_last_timestamp > 0 && m_last_timestamp == timestamp) + return; + #ifdef DEBUG cerr<<__FILE__<<"("<<__FUNCTION__<<"): Loading apps file ["<<apps_string<<"]"<<endl; #endif // DEBUG ifstream apps_file(apps_string.c_str()); + // we merge the old patterns with new ones + Patterns *old_pats = m_pats.release(); + m_pats.reset(new Patterns()); + if (!apps_file.fail()) { + m_last_timestamp = timestamp; if (!apps_file.eof()) { string line; int row = 0;

@@ -494,8 +548,11 @@ if (pos > 0 && key == "app") {

ClientPattern *pat = new ClientPattern(line.c_str() + pos); if (!in_group) { if ((err = pat->error()) == 0) { - Application *app = new Application(false); - m_pats.push_back(make_pair(pat, app)); + Application *app = findMatchingPatterns(pat, old_pats, false); + if (!app) + app = new Application(false); + + m_pats->push_back(make_pair(pat, app)); row += parseApp(apps_file, *app); } else { cerr<<"Error reading apps file at line "<<row<<", column "<<(err+pos)<<"."<<endl;

@@ -514,10 +571,21 @@ } else if (pos > 0 && key == "group") {

in_group = true; } else if (in_group) { // otherwise assume that it is the start of the attributes - Application *app = new Application(true); + Application *app = 0; + // search for a matching app + std::list<ClientPattern *>::iterator it = grouped_pats.begin(); + std::list<ClientPattern *>::iterator it_end = grouped_pats.end(); + while (!app && it != it_end) { + app = findMatchingPatterns(*it, old_pats, true); + ++it; + } + + if (!app) + app = new Application(true); + while (!grouped_pats.empty()) { // associate all the patterns with this app - m_pats.push_back(make_pair(grouped_pats.front(), app)); + m_pats->push_back(make_pair(grouped_pats.front(), app)); grouped_pats.pop_front(); }

@@ -540,6 +608,40 @@ }

} else { cerr << "apps file failure" << endl; } + + // Clean up old state + // can't just delete old patterns list. Need to delete the + // patterns themselves, plus the applications! + + Patterns::iterator it; + std::set<Application *> old_apps; // no duplicates + while (!old_pats->empty()) { + it = old_pats->begin(); + delete it->first; // ClientPattern + old_apps.insert(it->second); // Application, not necessarily unique + old_pats->erase(it); + } + + // now remove any client entries for the old apps + Clients::iterator cit = m_clients.begin(); + Clients::iterator cit_end = m_clients.end(); + while (cit != cit_end) { + if (old_apps.find(cit->second) != old_apps.end()) { + Clients::iterator tmpit = cit; + ++cit; + m_clients.erase(tmpit); + } else { + ++cit; + } + } + + std::set<Application *>::iterator ait = old_apps.begin(); // no duplicates + while (ait != old_apps.end()) { + delete (*ait); + ++ait; + } + + delete old_pats; } void Remember::save() {

@@ -558,8 +660,8 @@ for (; sit != sit_end; ++sit) {

apps_file<<"[startup] "<<(*sit)<<endl; } - Patterns::iterator it = m_pats.begin(); - Patterns::iterator it_end = m_pats.end(); + Patterns::iterator it = m_pats->begin(); + Patterns::iterator it_end = m_pats->end(); std::set<Application *> grouped_apps; // no duplicates

@@ -572,8 +674,8 @@ continue;

grouped_apps.insert(&a); // otherwise output this whole group apps_file << "[group]" << endl; - Patterns::iterator git = m_pats.begin(); - Patterns::iterator git_end = m_pats.end(); + Patterns::iterator git = m_pats->begin(); + Patterns::iterator git_end = m_pats->end(); for (; git != git_end; git++) { if (git->second == &a) { apps_file << " [app]"<<git->first->toString()<<endl;

@@ -969,8 +1071,8 @@ }

void Remember::updateFrameClose(FluxboxWindow &win) { // scan all applications and remove this fbw if it is a recorded group - Patterns::iterator it = m_pats.begin(); - while (it != m_pats.end()) { + Patterns::iterator it = m_pats->begin(); + while (it != m_pats->end()) { if (&win == it->second->group) it->second->group = 0; ++it;
M src/Remember.hhsrc/Remember.hh

@@ -35,6 +35,7 @@ #include <map>

#include <list> #include <string> #include <utility> +#include <memory> class FluxboxWindow; class BScreen;

@@ -193,7 +194,7 @@

Application* find(WinClient &winclient); Application* add(WinClient &winclient); - void load(); + void reconfigure(); // was load void save(); bool isRemembered(WinClient &win, Attribute attrib);

@@ -213,8 +214,6 @@

// Functions we ignore (zero from AtomHandler) // Leaving here in case they might be useful later - - void updateFocusedWindow(BScreen &, Window) { } void updateClientList(BScreen &screen) {} void updateWorkspaceNames(BScreen &screen) {}

@@ -233,16 +232,22 @@ // ignore this

bool propertyNotify(WinClient &winclient, Atom the_property) { return false; } static Remember &instance() { return *s_instance; } + private: // returns number of lines read // optionally can give a line to read before the first (lookahead line) int parseApp(std::ifstream &file, Application &app, std::string *first_line = 0); - Patterns m_pats; + + Application *findMatchingPatterns(ClientPattern *pat, Patterns *patlist, bool is_group); + + std::auto_ptr<Patterns> m_pats; Clients m_clients; Startups m_startups; static Remember *s_instance; + + time_t m_last_timestamp; }; #endif // REMEMBER_HH
M src/fluxbox.ccsrc/fluxbox.cc

@@ -1678,6 +1678,12 @@

//reconfigure keys m_key->reconfigure(StringUtil::expandFilename(*m_rc_keyfile).c_str()); + // and atomhandlers + for (AtomHandlerContainerIt it= m_atomhandler.begin(); + it != m_atomhandler.end(); + it++) { + (*it).first->reconfigure(); + } } BScreen *Fluxbox::findScreen(int id) {