diff --git a/docs/changes.txt b/docs/changes.txt index 65a709bcf4..738638a7f6 100644 --- a/docs/changes.txt +++ b/docs/changes.txt @@ -565,6 +565,7 @@ All: - Adjust dates invalid due to DST consistently under all platforms in wxDateTime. - Allow using custom HTTP methods with wxHTTP (Kolya Kosenko). - Add wxFileName::SetPermissions() (Catalin Raceanu). +- Add specific wxFSW_WARNING_OVERFLOW warning type (Rob Bresalier). - Fix build with wxUSE_FFILE==0 (jroemmler). - Add wxDEPRECATED_MSG() and use it in a few places. - Return the old file descriptor/pointer from wx(F)File::Detach() (troelsk). diff --git a/include/wx/fswatcher.h b/include/wx/fswatcher.h index 2955407864..056780d348 100644 --- a/include/wx/fswatcher.h +++ b/include/wx/fswatcher.h @@ -66,6 +66,13 @@ enum wxFSWPathType wxFSWPath_Tree // Watch a directory and all its children recursively. }; +// Type of the warning for the events notifying about them. +enum wxFSWWarningType +{ + wxFSW_WARNING_NONE, + wxFSW_WARNING_GENERAL, + wxFSW_WARNING_OVERFLOW +}; /** * Event containing information about file system change. @@ -77,24 +84,36 @@ wxDECLARE_EXPORTED_EVENT(WXDLLIMPEXP_BASE, wxEVT_FSWATCHER, class WXDLLIMPEXP_BASE wxFileSystemWatcherEvent: public wxEvent { public: + // Constructor for any kind of events, also used as default ctor. wxFileSystemWatcherEvent(int changeType = 0, int watchid = wxID_ANY) : wxEvent(watchid, wxEVT_FSWATCHER), - m_changeType(changeType) + m_changeType(changeType), + m_warningType(wxFSW_WARNING_NONE) { } - wxFileSystemWatcherEvent(int changeType, const wxString& errorMsg, + // Constructor for the error or warning events. + wxFileSystemWatcherEvent(int changeType, + wxFSWWarningType warningType, + const wxString& errorMsg = wxString(), int watchid = wxID_ANY) : wxEvent(watchid, wxEVT_FSWATCHER), - m_changeType(changeType), m_errorMsg(errorMsg) + m_changeType(changeType), + m_warningType(warningType), + m_errorMsg(errorMsg) { } + // Constructor for the normal events carrying information about the changes. wxFileSystemWatcherEvent(int changeType, const wxFileName& path, const wxFileName& newPath, int watchid = wxID_ANY) : wxEvent(watchid, wxEVT_FSWATCHER), - m_changeType(changeType), m_path(path), m_newPath(newPath) + m_changeType(changeType), + m_warningType(wxFSW_WARNING_NONE), + m_path(path), + m_newPath(newPath) + { } @@ -146,6 +165,7 @@ public: evt->m_errorMsg = m_errorMsg.Clone(); evt->m_path = wxFileName(m_path.GetFullPath().Clone()); evt->m_newPath = wxFileName(m_newPath.GetFullPath().Clone()); + evt->m_warningType = m_warningType; return evt; } @@ -168,6 +188,11 @@ public: return m_errorMsg; } + wxFSWWarningType GetWarningType() const + { + return m_warningType; + } + /** * Returns a wxString describing an event useful for debugging or testing */ @@ -175,6 +200,7 @@ public: protected: int m_changeType; + wxFSWWarningType m_warningType; wxFileName m_path; wxFileName m_newPath; wxString m_errorMsg; diff --git a/interface/wx/fswatcher.h b/interface/wx/fswatcher.h index c89ae09c51..cd4cd29a6f 100644 --- a/interface/wx/fswatcher.h +++ b/interface/wx/fswatcher.h @@ -156,11 +156,15 @@ public: class wxFileSystemWatcherEvent : public wxEvent { public: - wxFileSystemWatcherEvent(int changeType = 0, int watchid = wxID_ANY); - wxFileSystemWatcherEvent(int changeType, const wxString& errorMsg, + wxFileSystemWatcherEvent(int changeType = 0, int watchid = wxID_ANY); wxFileSystemWatcherEvent(int changeType, - const wxFileName& path, const wxFileName& newPath, + wxFSWWarningType warningType, + const wxString& errorMsg, + int watchid = wxID_ANY); + wxFileSystemWatcherEvent(int changeType, + const wxFileName& path, + const wxFileName& newPath, int watchid = wxID_ANY); /** @@ -192,9 +196,22 @@ public: /** Return a description of the warning or error if this is an error event. + + This string may be empty if the exact reason for the error or the + warning is not known. */ wxString GetErrorDescription() const; + /** + Return the type of the warning if this event is a warning one. + + If this is not a warning event, i.e. if GetChangeType() doesn't include + ::wxFSW_EVENT_WARNING, returns ::wxFSW_WARNING_NONE. + + @since 3.0 + */ + wxFSWWarningType GetWarningType() const; + /** Returns a wxString describing an event, useful for logging, debugging or testing. @@ -294,3 +311,35 @@ enum wxFSWFlags wxFSW_EVENT_WARNING | wxFSW_EVENT_ERROR }; +/** + Possible warning types for the warning events generated by + wxFileSystemWatcher. + + @since 3.0 + */ +enum wxFSWWarningType +{ + /** + This is not a warning at all. + */ + wxFSW_WARNING_NONE, + + /** + A generic warning. + + Further information may be provided in the user-readable message + available from wxFileSystemWatcherEvent::GetErrorDescription() + */ + wxFSW_WARNING_GENERAL, + + /** + An overflow event. + + This warning indicates that some file system changes were not signaled + by any events, usually because there were too many of them and the + internally used queue has overflown. If such event is received it is + recommended to completely rescan the files or directories being + monitored. + */ + wxFSW_WARNING_OVERFLOW +}; diff --git a/src/common/fswatchercmn.cpp b/src/common/fswatchercmn.cpp index 1de2422183..66fb869e9c 100644 --- a/src/common/fswatchercmn.cpp +++ b/src/common/fswatchercmn.cpp @@ -65,6 +65,11 @@ IMPLEMENT_DYNAMIC_CLASS(wxFileSystemWatcherEvent, wxEvent); wxString wxFileSystemWatcherEvent::ToString() const { + if (IsError()) + { + return wxString::Format("FSW_EVT type=%d (%s) message='%s'", m_changeType, + GetFSWEventChangeTypeName(m_changeType), GetErrorDescription()); + } return wxString::Format("FSW_EVT type=%d (%s) path='%s'", m_changeType, GetFSWEventChangeTypeName(m_changeType), GetPath().GetFullPath()); } diff --git a/src/msw/fswatcher.cpp b/src/msw/fswatcher.cpp index 7546f03a48..d179f67155 100644 --- a/src/msw/fswatcher.cpp +++ b/src/msw/fswatcher.cpp @@ -231,6 +231,29 @@ bool wxIOCPThread::ReadEvents() if (!count && !watch && !overlapped) return false; + // if the thread got woken up but we got an empty packet it means that + // there was an overflow, too many events and not all could fit in + // the watch buffer. In this case, ReadDirectoryChangesW dumps the + // buffer. + if (!count && watch) + { + wxLogTrace(wxTRACE_FSWATCHER, "[iocp] Event queue overflowed: path=\"%s\"", + watch->GetPath()); + + if (watch->GetFlags() & wxFSW_EVENT_WARNING) + { + wxFileSystemWatcherEvent + overflowEvent(wxFSW_EVENT_WARNING, wxFSW_WARNING_OVERFLOW); + overflowEvent.SetPath(watch->GetPath()); + SendEvent(overflowEvent); + } + + // overflow is not a fatal error, we still want to get future events + // reissue the watch + (void) m_service->SetUpWatch(*watch); + return true; + } + // in case of spurious wakeup if (!count || !watch) return true; @@ -283,9 +306,10 @@ void wxIOCPThread::ProcessNativeEvents(wxVector& events) int flags = Native2WatcherFlags(nativeFlags); if (flags & wxFSW_EVENT_WARNING || flags & wxFSW_EVENT_ERROR) { - // TODO think about this...do we ever have any errors to report? - wxString errMsg = "Error occurred"; - wxFileSystemWatcherEvent event(flags, errMsg); + wxFileSystemWatcherEvent + event(flags, + flags & wxFSW_EVENT_ERROR ? wxFSW_WARNING_NONE + : wxFSW_WARNING_GENERAL); SendEvent(event); } // filter out ignored events and those not asked for. diff --git a/src/unix/fswatcher_inotify.cpp b/src/unix/fswatcher_inotify.cpp index 117a036d4e..694beecedf 100644 --- a/src/unix/fswatcher_inotify.cpp +++ b/src/unix/fswatcher_inotify.cpp @@ -256,6 +256,7 @@ protected: event ( wxFSW_EVENT_WARNING, + wxFSW_WARNING_GENERAL, wxString::Format ( _("Unexpected event for \"%s\": no " @@ -279,8 +280,19 @@ protected: // check out for error/warning condition if (flags & wxFSW_EVENT_WARNING || flags & wxFSW_EVENT_ERROR) { - wxString errMsg = GetErrorDescription(nativeFlags); - wxFileSystemWatcherEvent event(flags, errMsg); + wxFSWWarningType warningType; + if ( flags & wxFSW_EVENT_WARNING ) + { + warningType = nativeFlags & IN_Q_OVERFLOW + ? wxFSW_WARNING_OVERFLOW + : wxFSW_WARNING_GENERAL; + } + else // It's an error, not a warning. + { + warningType = wxFSW_WARNING_NONE; + } + + wxFileSystemWatcherEvent event(flags, warningType); SendEvent(event); return; } @@ -293,6 +305,7 @@ protected: event ( wxFSW_EVENT_WARNING, + wxFSW_WARNING_GENERAL, wxString::Format ( _("Invalid inotify event for \"%s\""), @@ -628,22 +641,6 @@ protected: return -1; } - /** - * Returns error description for specified inotify mask - */ - static const wxString GetErrorDescription(int flag) - { - switch ( flag ) - { - case IN_Q_OVERFLOW: - return _("Event queue overflowed"); - } - - // never reached - wxFAIL_MSG(wxString::Format("Unknown inotify event mask %u", flag)); - return wxEmptyString; - } - wxFSWSourceHandler* m_handler; // handler for inotify event source wxFSWatchEntryDescriptors m_watchMap; // inotify wd=>wxFSWatchEntry* map wxArrayInt m_staleDescriptors; // stores recently-removed watches