diff options
Diffstat (limited to 'src/Remember.cc')
-rw-r--r-- | src/Remember.cc | 140 |
1 files changed, 121 insertions, 19 deletions
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; |