diff options
-rw-r--r-- | ChangeLog | 2 | ||||
-rw-r--r-- | src/AtomHandler.hh | 2 | ||||
-rw-r--r-- | src/ClientPattern.cc | 16 | ||||
-rw-r--r-- | src/ClientPattern.hh | 3 | ||||
-rw-r--r-- | src/Remember.cc | 140 | ||||
-rw-r--r-- | src/Remember.hh | 13 | ||||
-rw-r--r-- | src/fluxbox.cc | 6 |
7 files changed, 159 insertions, 23 deletions
@@ -1,6 +1,8 @@ | |||
1 | (Format: Year/Month/Day) | 1 | (Format: Year/Month/Day) |
2 | Changes for 0.9.16: | 2 | Changes for 0.9.16: |
3 | *06/04/23: | 3 | *06/04/23: |
4 | * Reload the apps file on fluxbox reload (Simon) | ||
5 | Remember.hh/cc fluxbox.cc AtomHandler.hh ClientPattern.hh/cc | ||
4 | * Update documentation for Next/PrevWindow (Simon / thanks Jonas | 6 | * Update documentation for Next/PrevWindow (Simon / thanks Jonas |
5 | Koelker), sf.net patch #1474825 | 7 | Koelker), sf.net patch #1474825 |
6 | doc/asciidoc/fluxbox.txt | 8 | doc/asciidoc/fluxbox.txt |
diff --git a/src/AtomHandler.hh b/src/AtomHandler.hh index ca14d0e..b44d92f 100644 --- a/src/AtomHandler.hh +++ b/src/AtomHandler.hh | |||
@@ -59,6 +59,8 @@ public: | |||
59 | 59 | ||
60 | virtual bool propertyNotify(WinClient &winclient, Atom the_property) = 0; | 60 | virtual bool propertyNotify(WinClient &winclient, Atom the_property) = 0; |
61 | 61 | ||
62 | virtual void reconfigure() {} | ||
63 | |||
62 | /// should this object be updated or not? | 64 | /// should this object be updated or not? |
63 | bool update() const { return m_update; } | 65 | bool update() const { return m_update; } |
64 | protected: | 66 | protected: |
diff --git a/src/ClientPattern.cc b/src/ClientPattern.cc index 38d1602..d9469fa 100644 --- a/src/ClientPattern.cc +++ b/src/ClientPattern.cc | |||
@@ -257,3 +257,19 @@ std::string ClientPattern::getProperty(WinProperty prop, const WinClient &client | |||
257 | } | 257 | } |
258 | return client.getWMClassName(); | 258 | return client.getWMClassName(); |
259 | } | 259 | } |
260 | |||
261 | bool ClientPattern::equals(const ClientPattern &pat) const { | ||
262 | // we require the terms to be identical (order too) | ||
263 | Terms::const_iterator it = m_terms.begin(); | ||
264 | Terms::const_iterator it_end = m_terms.end(); | ||
265 | Terms::const_iterator other_it = pat.m_terms.begin(); | ||
266 | Terms::const_iterator other_it_end = pat.m_terms.end(); | ||
267 | for (; it != it_end, other_it != other_it_end; ++it, ++other_it) { | ||
268 | if ((*it)->orig != (*other_it)->orig) | ||
269 | return false; | ||
270 | } | ||
271 | if (it != it_end || other_it != other_it_end) | ||
272 | return false; | ||
273 | |||
274 | return true; | ||
275 | } | ||
diff --git a/src/ClientPattern.hh b/src/ClientPattern.hh index ee7ebc7..6db9c83 100644 --- a/src/ClientPattern.hh +++ b/src/ClientPattern.hh | |||
@@ -73,6 +73,9 @@ public: | |||
73 | return match(win); | 73 | return match(win); |
74 | } | 74 | } |
75 | 75 | ||
76 | // whether this pattern has identical matching criteria | ||
77 | bool equals(const ClientPattern &pat) const; | ||
78 | |||
76 | /** | 79 | /** |
77 | * If there are no terms, then there is assumed to be an error | 80 | * If there are no terms, then there is assumed to be an error |
78 | * the column of the error is stored in m_matchlimit | 81 | * the column of the error is stored in m_matchlimit |
diff --git a/src/Remember.cc b/src/Remember.cc index c134741..b90a252 100644 --- a/src/Remember.cc +++ b/src/Remember.cc | |||
@@ -36,6 +36,7 @@ | |||
36 | 36 | ||
37 | #include "FbTk/I18n.hh" | 37 | #include "FbTk/I18n.hh" |
38 | #include "FbTk/StringUtil.hh" | 38 | #include "FbTk/StringUtil.hh" |
39 | #include "FbTk/FileUtil.hh" | ||
39 | #include "FbTk/MenuItem.hh" | 40 | #include "FbTk/MenuItem.hh" |
40 | #include "FbTk/App.hh" | 41 | #include "FbTk/App.hh" |
41 | #include "FbTk/stringstream.hh" | 42 | #include "FbTk/stringstream.hh" |
@@ -230,13 +231,16 @@ Application::Application(bool grouped) | |||
230 | 231 | ||
231 | Remember *Remember::s_instance = 0; | 232 | Remember *Remember::s_instance = 0; |
232 | 233 | ||
233 | Remember::Remember() { | 234 | Remember::Remember(): |
235 | m_pats(new Patterns()), | ||
236 | m_last_timestamp(0) | ||
237 | { | ||
234 | if (s_instance != 0) | 238 | if (s_instance != 0) |
235 | throw string("Can not create more than one instance of Remember"); | 239 | throw string("Can not create more than one instance of Remember"); |
236 | 240 | ||
237 | s_instance = this; | 241 | s_instance = this; |
238 | enableUpdate(); | 242 | enableUpdate(); |
239 | load(); | 243 | reconfigure(); |
240 | } | 244 | } |
241 | 245 | ||
242 | Remember::~Remember() { | 246 | Remember::~Remember() { |
@@ -247,11 +251,11 @@ Remember::~Remember() { | |||
247 | // the client mapping shouldn't need cleaning | 251 | // the client mapping shouldn't need cleaning |
248 | Patterns::iterator it; | 252 | Patterns::iterator it; |
249 | std::set<Application *> all_apps; // no duplicates | 253 | std::set<Application *> all_apps; // no duplicates |
250 | while (!m_pats.empty()) { | 254 | while (!m_pats->empty()) { |
251 | it = m_pats.begin(); | 255 | it = m_pats->begin(); |
252 | delete it->first; // ClientPattern | 256 | delete it->first; // ClientPattern |
253 | all_apps.insert(it->second); // Application, not necessarily unique | 257 | all_apps.insert(it->second); // Application, not necessarily unique |
254 | m_pats.erase(it); | 258 | m_pats->erase(it); |
255 | } | 259 | } |
256 | 260 | ||
257 | std::set<Application *>::iterator ait = all_apps.begin(); // no duplicates | 261 | std::set<Application *>::iterator ait = all_apps.begin(); // no duplicates |
@@ -270,8 +274,8 @@ Application* Remember::find(WinClient &winclient) { | |||
270 | if (wc_it != m_clients.end()) | 274 | if (wc_it != m_clients.end()) |
271 | return wc_it->second; | 275 | return wc_it->second; |
272 | else { | 276 | else { |
273 | Patterns::iterator it = m_pats.begin(); | 277 | Patterns::iterator it = m_pats->begin(); |
274 | for (; it != m_pats.end(); it++) | 278 | for (; it != m_pats->end(); it++) |
275 | if (it->first->match(winclient)) { | 279 | if (it->first->match(winclient)) { |
276 | it->first->addMatch(); | 280 | it->first->addMatch(); |
277 | m_clients[&winclient] = it->second; | 281 | m_clients[&winclient] = it->second; |
@@ -289,7 +293,7 @@ Application * Remember::add(WinClient &winclient) { | |||
289 | p->addTerm(p->getProperty(ClientPattern::NAME, winclient), ClientPattern::NAME); | 293 | p->addTerm(p->getProperty(ClientPattern::NAME, winclient), ClientPattern::NAME); |
290 | m_clients[&winclient] = app; | 294 | m_clients[&winclient] = app; |
291 | p->addMatch(); | 295 | p->addMatch(); |
292 | m_pats.push_back(make_pair(p, app)); | 296 | m_pats->push_back(make_pair(p, app)); |
293 | return app; | 297 | return app; |
294 | } | 298 | } |
295 | 299 | ||
@@ -463,16 +467,66 @@ int Remember::parseApp(ifstream &file, Application &app, string *first_line) { | |||
463 | return row; | 467 | return row; |
464 | } | 468 | } |
465 | 469 | ||
466 | void Remember::load() { | 470 | /* |
471 | This function is used to search for old instances of the same pattern | ||
472 | (when reloading apps file). More than one pattern might match, but only | ||
473 | if the application is the same (also note that they'll be adjacent). | ||
474 | We REMOVE and delete any matching patterns from the old list, as they're | ||
475 | effectively moved into the new | ||
476 | */ | ||
477 | |||
478 | Application *Remember::findMatchingPatterns(ClientPattern *pat, Patterns *patlist, bool is_group) { | ||
479 | Patterns::iterator it = patlist->begin(); | ||
480 | Patterns::iterator it_end = patlist->end(); | ||
481 | for (; it != it_end; ++it) { | ||
482 | if (it->first->equals(*pat) && is_group == it->second->is_grouped) { | ||
483 | Application *ret = it->second; | ||
484 | |||
485 | // find any previous or subsequent matching ones and delete | ||
486 | |||
487 | // rewind | ||
488 | Patterns::iterator tmpit = it; | ||
489 | while (tmpit != patlist->begin()) { | ||
490 | --tmpit; | ||
491 | if (tmpit->second == ret) | ||
492 | it = tmpit; | ||
493 | else | ||
494 | break; | ||
495 | } | ||
496 | |||
497 | // forward | ||
498 | while (it != it_end && it->second == ret) { | ||
499 | tmpit = it; | ||
500 | ++it; | ||
501 | delete tmpit->first; | ||
502 | patlist->erase(tmpit); | ||
503 | } | ||
504 | return ret; | ||
505 | } | ||
506 | } | ||
467 | 507 | ||
508 | return 0; | ||
509 | } | ||
510 | |||
511 | |||
512 | void Remember::reconfigure() { | ||
468 | string apps_string = FbTk::StringUtil::expandFilename(Fluxbox::instance()->getAppsFilename()); | 513 | string apps_string = FbTk::StringUtil::expandFilename(Fluxbox::instance()->getAppsFilename()); |
469 | 514 | ||
515 | time_t timestamp = FbTk::FileUtil::getLastStatusChangeTimestamp(apps_string.c_str()); | ||
516 | if (m_last_timestamp > 0 && m_last_timestamp == timestamp) | ||
517 | return; | ||
518 | |||
470 | #ifdef DEBUG | 519 | #ifdef DEBUG |
471 | cerr<<__FILE__<<"("<<__FUNCTION__<<"): Loading apps file ["<<apps_string<<"]"<<endl; | 520 | cerr<<__FILE__<<"("<<__FUNCTION__<<"): Loading apps file ["<<apps_string<<"]"<<endl; |
472 | #endif // DEBUG | 521 | #endif // DEBUG |
473 | ifstream apps_file(apps_string.c_str()); | 522 | ifstream apps_file(apps_string.c_str()); |
474 | 523 | ||
524 | // we merge the old patterns with new ones | ||
525 | Patterns *old_pats = m_pats.release(); | ||
526 | m_pats.reset(new Patterns()); | ||
527 | |||
475 | if (!apps_file.fail()) { | 528 | if (!apps_file.fail()) { |
529 | m_last_timestamp = timestamp; | ||
476 | if (!apps_file.eof()) { | 530 | if (!apps_file.eof()) { |
477 | string line; | 531 | string line; |
478 | int row = 0; | 532 | int row = 0; |
@@ -494,8 +548,11 @@ void Remember::load() { | |||
494 | ClientPattern *pat = new ClientPattern(line.c_str() + pos); | 548 | ClientPattern *pat = new ClientPattern(line.c_str() + pos); |
495 | if (!in_group) { | 549 | if (!in_group) { |
496 | if ((err = pat->error()) == 0) { | 550 | if ((err = pat->error()) == 0) { |
497 | Application *app = new Application(false); | 551 | Application *app = findMatchingPatterns(pat, old_pats, false); |
498 | m_pats.push_back(make_pair(pat, app)); | 552 | if (!app) |
553 | app = new Application(false); | ||
554 | |||
555 | m_pats->push_back(make_pair(pat, app)); | ||
499 | row += parseApp(apps_file, *app); | 556 | row += parseApp(apps_file, *app); |
500 | } else { | 557 | } else { |
501 | cerr<<"Error reading apps file at line "<<row<<", column "<<(err+pos)<<"."<<endl; | 558 | cerr<<"Error reading apps file at line "<<row<<", column "<<(err+pos)<<"."<<endl; |
@@ -514,10 +571,21 @@ void Remember::load() { | |||
514 | in_group = true; | 571 | in_group = true; |
515 | } else if (in_group) { | 572 | } else if (in_group) { |
516 | // otherwise assume that it is the start of the attributes | 573 | // otherwise assume that it is the start of the attributes |
517 | Application *app = new Application(true); | 574 | Application *app = 0; |
575 | // search for a matching app | ||
576 | std::list<ClientPattern *>::iterator it = grouped_pats.begin(); | ||
577 | std::list<ClientPattern *>::iterator it_end = grouped_pats.end(); | ||
578 | while (!app && it != it_end) { | ||
579 | app = findMatchingPatterns(*it, old_pats, true); | ||
580 | ++it; | ||
581 | } | ||
582 | |||
583 | if (!app) | ||
584 | app = new Application(true); | ||
585 | |||
518 | while (!grouped_pats.empty()) { | 586 | while (!grouped_pats.empty()) { |
519 | // associate all the patterns with this app | 587 | // associate all the patterns with this app |
520 | m_pats.push_back(make_pair(grouped_pats.front(), app)); | 588 | m_pats->push_back(make_pair(grouped_pats.front(), app)); |
521 | grouped_pats.pop_front(); | 589 | grouped_pats.pop_front(); |
522 | } | 590 | } |
523 | 591 | ||
@@ -540,6 +608,40 @@ void Remember::load() { | |||
540 | } else { | 608 | } else { |
541 | cerr << "apps file failure" << endl; | 609 | cerr << "apps file failure" << endl; |
542 | } | 610 | } |
611 | |||
612 | // Clean up old state | ||
613 | // can't just delete old patterns list. Need to delete the | ||
614 | // patterns themselves, plus the applications! | ||
615 | |||
616 | Patterns::iterator it; | ||
617 | std::set<Application *> old_apps; // no duplicates | ||
618 | while (!old_pats->empty()) { | ||
619 | it = old_pats->begin(); | ||
620 | delete it->first; // ClientPattern | ||
621 | old_apps.insert(it->second); // Application, not necessarily unique | ||
622 | old_pats->erase(it); | ||
623 | } | ||
624 | |||
625 | // now remove any client entries for the old apps | ||
626 | Clients::iterator cit = m_clients.begin(); | ||
627 | Clients::iterator cit_end = m_clients.end(); | ||
628 | while (cit != cit_end) { | ||
629 | if (old_apps.find(cit->second) != old_apps.end()) { | ||
630 | Clients::iterator tmpit = cit; | ||
631 | ++cit; | ||
632 | m_clients.erase(tmpit); | ||
633 | } else { | ||
634 | ++cit; | ||
635 | } | ||
636 | } | ||
637 | |||
638 | std::set<Application *>::iterator ait = old_apps.begin(); // no duplicates | ||
639 | while (ait != old_apps.end()) { | ||
640 | delete (*ait); | ||
641 | ++ait; | ||
642 | } | ||
643 | |||
644 | delete old_pats; | ||
543 | } | 645 | } |
544 | 646 | ||
545 | void Remember::save() { | 647 | void Remember::save() { |
@@ -558,8 +660,8 @@ void Remember::save() { | |||
558 | apps_file<<"[startup] "<<(*sit)<<endl; | 660 | apps_file<<"[startup] "<<(*sit)<<endl; |
559 | } | 661 | } |
560 | 662 | ||
561 | Patterns::iterator it = m_pats.begin(); | 663 | Patterns::iterator it = m_pats->begin(); |
562 | Patterns::iterator it_end = m_pats.end(); | 664 | Patterns::iterator it_end = m_pats->end(); |
563 | 665 | ||
564 | std::set<Application *> grouped_apps; // no duplicates | 666 | std::set<Application *> grouped_apps; // no duplicates |
565 | 667 | ||
@@ -572,8 +674,8 @@ void Remember::save() { | |||
572 | grouped_apps.insert(&a); | 674 | grouped_apps.insert(&a); |
573 | // otherwise output this whole group | 675 | // otherwise output this whole group |
574 | apps_file << "[group]" << endl; | 676 | apps_file << "[group]" << endl; |
575 | Patterns::iterator git = m_pats.begin(); | 677 | Patterns::iterator git = m_pats->begin(); |
576 | Patterns::iterator git_end = m_pats.end(); | 678 | Patterns::iterator git_end = m_pats->end(); |
577 | for (; git != git_end; git++) { | 679 | for (; git != git_end; git++) { |
578 | if (git->second == &a) { | 680 | if (git->second == &a) { |
579 | apps_file << " [app]"<<git->first->toString()<<endl; | 681 | apps_file << " [app]"<<git->first->toString()<<endl; |
@@ -969,8 +1071,8 @@ void Remember::initForScreen(BScreen &screen) { | |||
969 | 1071 | ||
970 | void Remember::updateFrameClose(FluxboxWindow &win) { | 1072 | void Remember::updateFrameClose(FluxboxWindow &win) { |
971 | // scan all applications and remove this fbw if it is a recorded group | 1073 | // scan all applications and remove this fbw if it is a recorded group |
972 | Patterns::iterator it = m_pats.begin(); | 1074 | Patterns::iterator it = m_pats->begin(); |
973 | while (it != m_pats.end()) { | 1075 | while (it != m_pats->end()) { |
974 | if (&win == it->second->group) | 1076 | if (&win == it->second->group) |
975 | it->second->group = 0; | 1077 | it->second->group = 0; |
976 | ++it; | 1078 | ++it; |
diff --git a/src/Remember.hh b/src/Remember.hh index 2fa2dd1..42edca3 100644 --- a/src/Remember.hh +++ b/src/Remember.hh | |||
@@ -35,6 +35,7 @@ | |||
35 | #include <list> | 35 | #include <list> |
36 | #include <string> | 36 | #include <string> |
37 | #include <utility> | 37 | #include <utility> |
38 | #include <memory> | ||
38 | 39 | ||
39 | class FluxboxWindow; | 40 | class FluxboxWindow; |
40 | class BScreen; | 41 | class BScreen; |
@@ -193,7 +194,7 @@ public: | |||
193 | Application* find(WinClient &winclient); | 194 | Application* find(WinClient &winclient); |
194 | Application* add(WinClient &winclient); | 195 | Application* add(WinClient &winclient); |
195 | 196 | ||
196 | void load(); | 197 | void reconfigure(); // was load |
197 | void save(); | 198 | void save(); |
198 | 199 | ||
199 | bool isRemembered(WinClient &win, Attribute attrib); | 200 | bool isRemembered(WinClient &win, Attribute attrib); |
@@ -213,8 +214,6 @@ public: | |||
213 | // Functions we ignore (zero from AtomHandler) | 214 | // Functions we ignore (zero from AtomHandler) |
214 | // Leaving here in case they might be useful later | 215 | // Leaving here in case they might be useful later |
215 | 216 | ||
216 | |||
217 | |||
218 | void updateFocusedWindow(BScreen &, Window) { } | 217 | void updateFocusedWindow(BScreen &, Window) { } |
219 | void updateClientList(BScreen &screen) {} | 218 | void updateClientList(BScreen &screen) {} |
220 | void updateWorkspaceNames(BScreen &screen) {} | 219 | void updateWorkspaceNames(BScreen &screen) {} |
@@ -233,16 +232,22 @@ public: | |||
233 | bool propertyNotify(WinClient &winclient, Atom the_property) { return false; } | 232 | bool propertyNotify(WinClient &winclient, Atom the_property) { return false; } |
234 | 233 | ||
235 | static Remember &instance() { return *s_instance; } | 234 | static Remember &instance() { return *s_instance; } |
235 | |||
236 | private: | 236 | private: |
237 | 237 | ||
238 | // returns number of lines read | 238 | // returns number of lines read |
239 | // optionally can give a line to read before the first (lookahead line) | 239 | // optionally can give a line to read before the first (lookahead line) |
240 | int parseApp(std::ifstream &file, Application &app, std::string *first_line = 0); | 240 | int parseApp(std::ifstream &file, Application &app, std::string *first_line = 0); |
241 | Patterns m_pats; | 241 | |
242 | Application *findMatchingPatterns(ClientPattern *pat, Patterns *patlist, bool is_group); | ||
243 | |||
244 | std::auto_ptr<Patterns> m_pats; | ||
242 | Clients m_clients; | 245 | Clients m_clients; |
243 | 246 | ||
244 | Startups m_startups; | 247 | Startups m_startups; |
245 | static Remember *s_instance; | 248 | static Remember *s_instance; |
249 | |||
250 | time_t m_last_timestamp; | ||
246 | }; | 251 | }; |
247 | 252 | ||
248 | #endif // REMEMBER_HH | 253 | #endif // REMEMBER_HH |
diff --git a/src/fluxbox.cc b/src/fluxbox.cc index 62eef50..f5066b7 100644 --- a/src/fluxbox.cc +++ b/src/fluxbox.cc | |||
@@ -1678,6 +1678,12 @@ void Fluxbox::real_reconfigure() { | |||
1678 | //reconfigure keys | 1678 | //reconfigure keys |
1679 | m_key->reconfigure(StringUtil::expandFilename(*m_rc_keyfile).c_str()); | 1679 | m_key->reconfigure(StringUtil::expandFilename(*m_rc_keyfile).c_str()); |
1680 | 1680 | ||
1681 | // and atomhandlers | ||
1682 | for (AtomHandlerContainerIt it= m_atomhandler.begin(); | ||
1683 | it != m_atomhandler.end(); | ||
1684 | it++) { | ||
1685 | (*it).first->reconfigure(); | ||
1686 | } | ||
1681 | } | 1687 | } |
1682 | 1688 | ||
1683 | BScreen *Fluxbox::findScreen(int id) { | 1689 | BScreen *Fluxbox::findScreen(int id) { |