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); void remove(bool force = false);
bool poll(int wait_ms = 1000) const; bool poll(int wait_ms = 1000) const;
unique_ptr<inotify_event> get_event() const; unique_ptr<inotify_event> get_event() const;
bool await_match() const; unique_ptr<inotify_event> await_match() const;
const string path() const; const string path() const;
int get_file_descriptor() const; int get_file_descriptor() const;

View File

@ -246,7 +246,7 @@ void controller::read_events() {
if (m_confwatch) { if (m_confwatch) {
m_log.trace("controller: Attach config watch"); 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())); 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 // 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"); m_log.info("Configuration file changed");
g_terminate = 1; g_terminate = 1;
g_reload = 1; g_reload = 1;

View File

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