polybar-dwm/include/modules/meta/inotify_module.hpp
Patrick Ziegler abd96eb089
Enable module in start funcion (#2538)
Before it was enabled by default. That means if the constructor fails,
the destructor will complain that the module was not stopped before
deconstructing.

We can't just call stop if module creation fails because the module is
only partially initialized.
2021-10-15 10:33:10 +02:00

95 lines
2.4 KiB
C++

#pragma once
#include "components/builder.hpp"
#include "modules/meta/base.hpp"
POLYBAR_NS
namespace modules {
template <class Impl>
class inotify_module : public module<Impl> {
public:
using module<Impl>::module;
void start() override {
this->module<Impl>::start();
this->m_mainthread = thread(&inotify_module::runner, this);
}
protected:
void runner() {
this->m_log.trace("%s: Thread id = %i", this->name(), concurrency_util::thread_id(this_thread::get_id()));
try {
// Warm up module output before entering the loop
std::unique_lock<std::mutex> guard(this->m_updatelock);
CAST_MOD(Impl)->on_event(nullptr);
CAST_MOD(Impl)->broadcast();
guard.unlock();
while (this->running()) {
std::lock_guard<std::mutex> guard(this->m_updatelock);
CAST_MOD(Impl)->poll_events();
}
} catch (const module_error& err) {
CAST_MOD(Impl)->halt(err.what());
} catch (const std::exception& err) {
CAST_MOD(Impl)->halt(err.what());
}
}
void watch(string path, int mask = IN_ALL_EVENTS) {
this->m_log.trace("%s: Attach inotify at %s", this->name(), path);
m_watchlist.insert(make_pair(path, mask));
}
void idle() {
this->sleep(200ms);
}
void poll_events() {
vector<unique_ptr<inotify_watch>> watches;
try {
for (auto&& w : m_watchlist) {
watches.emplace_back(inotify_util::make_watch(w.first));
watches.back()->attach(w.second);
}
} catch (const system_error& e) {
watches.clear();
this->m_log.err("%s: Error while creating inotify watch (what: %s)", this->name(), e.what());
CAST_MOD(Impl)->sleep(0.1s);
return;
}
while (this->running()) {
for (auto&& w : watches) {
this->m_log.trace_x("%s: Poll inotify watch %s", this->name(), w->path());
if (w->poll(1000 / watches.size())) {
auto event = w->get_event();
for (auto&& w : watches) {
w->remove(true);
}
if (CAST_MOD(Impl)->on_event(event.get())) {
CAST_MOD(Impl)->broadcast();
}
CAST_MOD(Impl)->idle();
return;
}
if (!this->running())
break;
}
CAST_MOD(Impl)->idle();
}
}
private:
map<string, int> m_watchlist;
};
} // namespace modules
POLYBAR_NS_END