diff --git a/src/core/filesystemwatcherinterface.h b/src/core/filesystemwatcherinterface.h index 877d790e8..efcacbfa4 100644 --- a/src/core/filesystemwatcherinterface.h +++ b/src/core/filesystemwatcherinterface.h @@ -27,7 +27,7 @@ class FileSystemWatcherInterface : public QObject { public: explicit FileSystemWatcherInterface(QObject* parent = nullptr); virtual void Init() {} - virtual void AddPath(const QString& path) = 0; + virtual bool AddPath(const QString& path) = 0; virtual void RemovePath(const QString& path) = 0; virtual void Clear() = 0; diff --git a/src/core/macfslistener.h b/src/core/macfslistener.h index 035af5bf7..1bdada50c 100644 --- a/src/core/macfslistener.h +++ b/src/core/macfslistener.h @@ -35,7 +35,7 @@ class MacFSListener : public FileSystemWatcherInterface { public: explicit MacFSListener(QObject* parent = nullptr); void Init(); - void AddPath(const QString& path); + bool AddPath(const QString& path); void RemovePath(const QString& path); void Clear(); diff --git a/src/core/macfslistener.mm b/src/core/macfslistener.mm index d9c44cc6b..a3a27cb95 100644 --- a/src/core/macfslistener.mm +++ b/src/core/macfslistener.mm @@ -52,10 +52,11 @@ void MacFSListener::EventStreamCallback( } } -void MacFSListener::AddPath(const QString& path) { +bool MacFSListener::AddPath(const QString& path) { Q_ASSERT(run_loop_); paths_.insert(path); UpdateStreamAsync(); + return true; } void MacFSListener::RemovePath(const QString& path) { diff --git a/src/core/qtfslistener.cpp b/src/core/qtfslistener.cpp index f98664994..7ba600118 100644 --- a/src/core/qtfslistener.cpp +++ b/src/core/qtfslistener.cpp @@ -27,7 +27,9 @@ QtFSListener::QtFSListener(QObject* parent) SIGNAL(PathChanged(const QString&))); } -void QtFSListener::AddPath(const QString& path) { watcher_.addPath(path); } +bool QtFSListener::AddPath(const QString& path) { + return watcher_.addPath(path); +} void QtFSListener::RemovePath(const QString& path) { watcher_.removePath(path); diff --git a/src/core/qtfslistener.h b/src/core/qtfslistener.h index 949c36eba..eeed5ad4d 100644 --- a/src/core/qtfslistener.h +++ b/src/core/qtfslistener.h @@ -28,7 +28,7 @@ class QtFSListener : public FileSystemWatcherInterface { Q_OBJECT public: explicit QtFSListener(QObject* parent); - virtual void AddPath(const QString& path); + virtual bool AddPath(const QString& path); virtual void RemovePath(const QString& path); virtual void Clear(); diff --git a/src/devices/filesystemdevice.cpp b/src/devices/filesystemdevice.cpp index 6e843ff6a..42134c455 100644 --- a/src/devices/filesystemdevice.cpp +++ b/src/devices/filesystemdevice.cpp @@ -64,6 +64,7 @@ FilesystemDevice::FilesystemDevice(const QUrl& url, DeviceLister* lister, connect(watcher_, SIGNAL(CompilationsNeedUpdating()), backend_.get(), SLOT(UpdateCompilations())); connect(watcher_, SIGNAL(ScanStarted(int)), SIGNAL(TaskStarted(int))); + connect(watcher_, &LibraryWatcher::Error, app, &Application::AddError); } void FilesystemDevice::Init() { diff --git a/src/library/library.cpp b/src/library/library.cpp index ac47bc067..da30dbeb2 100644 --- a/src/library/library.cpp +++ b/src/library/library.cpp @@ -161,6 +161,7 @@ void Library::Init() { backend_.get(), SLOT(AddOrUpdateSubdirs(SubdirectoryList))); connect(watcher_, SIGNAL(CompilationsNeedUpdating()), backend_.get(), SLOT(UpdateCompilations())); + connect(watcher_, &LibraryWatcher::Error, app_, &Application::AddError); connect(app_->playlist_manager(), SIGNAL(CurrentSongChanged(Song)), SLOT(CurrentSongChanged(Song))); connect(app_->player(), SIGNAL(Stopped()), SLOT(Stopped())); diff --git a/src/library/librarywatcher.cpp b/src/library/librarywatcher.cpp index 7a308f3af..ca3155d67 100644 --- a/src/library/librarywatcher.cpp +++ b/src/library/librarywatcher.cpp @@ -588,11 +588,34 @@ uint LibraryWatcher::GetMtimeForCue(const QString& cue_path) { } void LibraryWatcher::AddWatch(const Directory& dir, const QString& path) { - if (!QFile::exists(path)) return; + QFileInfo info(path); + if (!info.exists() || !info.isReadable()) return; connect(fs_watcher_, SIGNAL(PathChanged(const QString&)), this, SLOT(DirectoryChanged(const QString&)), Qt::UniqueConnection); - fs_watcher_->AddPath(path); + if (!fs_watcher_->AddPath(path)) { + // Since this may be a system error, don't spam the user. + static int errCount = 0; + if (errCount++ == 0) { +#ifdef Q_OS_LINUX + // The Linux implementation of QFileSystemWatcher utilizes inotify, so + // the limit in /proc/sys/fs/inotify/max_user_watches may be a problem + // in large libraries. + const char* fmt = + "Failed to watch %1\n" + "On a Linux system, this may be due to the inotify max_user_watches " + "limit.\n\n" + "This error will not be shown again during this session."; +#else + const char* fmt = + "Failed to watch %1 for unknown reasons.\n\n" + "This error will not be shown again during this session."; +#endif + emit Error(tr(fmt).arg(path)); + } + return; + } + subdir_mapping_[path] = dir; } diff --git a/src/library/librarywatcher.h b/src/library/librarywatcher.h index c598e97f0..848cc0a97 100644 --- a/src/library/librarywatcher.h +++ b/src/library/librarywatcher.h @@ -68,6 +68,8 @@ signals: void ScanStarted(int task_id); + void Error(const QString& message); + public slots: void ReloadSettings(); void AddDirectory(const Directory& dir, const SubdirectoryList& subdirs); diff --git a/src/widgets/errordialog.cpp b/src/widgets/errordialog.cpp index 3fd590840..ebebfb8a8 100644 --- a/src/widgets/errordialog.cpp +++ b/src/widgets/errordialog.cpp @@ -55,7 +55,7 @@ void ErrorDialog::UpdateContent() { QString html; for (const QString& message : current_messages_) { if (!html.isEmpty()) html += "