fix: Ensure reloading when IN_IGNORED fired on config (#371)

This fixes a "bug" where polybar wouldn't reload on a configuration
file change on some configurations of vim, which don't actually issue
any IN_MODIFY events because they choose to move the file, replace it
with a new one, and then delete the file instead.

To work around this, we now also listen for IN_IGNORED which fires when
the file we are watching is destroyed. When this happens, we re-attach
the configuration file watcher to the new file and reload.
This commit is contained in:
Chase Geigle 2017-01-24 00:10:55 -06:00 committed by Michael Carlberg
parent b6661825ce
commit 47a2cce03d
3 changed files with 21 additions and 5 deletions

View File

@ -26,7 +26,7 @@ class inotify_watch {
void remove(bool force = false);
bool poll(int wait_ms = 1000) const;
unique_ptr<inotify_event> get_event() const;
bool await_match() const;
unique_ptr<inotify_event> await_match() const;
const string path() const;
int get_file_descriptor() const;

View File

@ -246,7 +246,7 @@ void controller::read_events() {
if (m_confwatch) {
m_log.trace("controller: Attach config watch");
m_confwatch->attach(IN_MODIFY);
m_confwatch->attach(IN_MODIFY | IN_IGNORED);
fds.emplace_back((fd_confwatch = m_confwatch->get_file_descriptor()));
}
@ -281,7 +281,22 @@ void controller::read_events() {
}
// Process event on the config inotify watch fd
if (fd_confwatch > -1 && FD_ISSET(fd_confwatch, &readfds) && m_confwatch->await_match()) {
unique_ptr<inotify_event> confevent;
if (fd_confwatch > -1 && FD_ISSET(fd_confwatch, &readfds) && (confevent = m_confwatch->await_match())) {
if (confevent->mask & IN_IGNORED) {
// IN_IGNORED: file was deleted or filesystem was unmounted
//
// This happens in some configurations of vim when a file is saved,
// since it is not actually issuing calls to write() but rather
// moves a file into the original's place after moving the original
// file to a different location (and subsequently deleting it).
//
// We need to re-attach the watch to the new file in this case.
fds.erase(std::remove_if(fds.begin(), fds.end(), [fd_confwatch](int fd) { return fd == fd_confwatch; }), fds.end());
m_confwatch = inotify_util::make_watch(m_confwatch->path());
m_confwatch->attach(IN_MODIFY | IN_IGNORED);
fds.emplace_back((fd_confwatch = m_confwatch->get_file_descriptor()));
}
m_log.info("Configuration file changed");
g_terminate = 1;
g_reload = 1;

View File

@ -98,8 +98,9 @@ unique_ptr<inotify_event> inotify_watch::get_event() const {
/**
* Wait for matching event
*/
bool inotify_watch::await_match() const {
return (get_event()->mask & m_mask) == m_mask;
unique_ptr<inotify_event> inotify_watch::await_match() const {
auto event = get_event();
return event->mask & m_mask ? std::move(event) : nullptr;
}
/**