]> git.saurik.com Git - wxWidgets.git/blobdiff - src/unix/fswatcher_inotify.cpp
Fixed interface typo breaking wxRibbonBar docs (from r72495).
[wxWidgets.git] / src / unix / fswatcher_inotify.cpp
index 229af98eee66685b107d8d8ed9f2b407ce8350c2..675d1168e352aa797859ab5af590f706b69fdbd2 100644 (file)
@@ -45,8 +45,8 @@ class wxFSWatcherImplUnix : public wxFSWatcherImpl
 public:
     wxFSWatcherImplUnix(wxFileSystemWatcherBase* watcher) :
         wxFSWatcherImpl(watcher),
-        m_loop(NULL),
-        m_source(NULL)
+        m_source(NULL),
+        m_ifd(-1)
     {
         m_handler = new wxFSWSourceHandler(this);
     }
@@ -65,42 +65,38 @@ public:
     bool Init()
     {
         wxCHECK_MSG( !IsOk(), false, "Inotify already initialized" );
-        wxCHECK_MSG( m_loop == NULL, false, "Event loop != NULL");
 
-        m_loop = (wxEventLoopBase::GetActive());
-        wxCHECK_MSG( m_loop, false, "File system watcher needs an active loop" );
+        wxEventLoopBase *loop = wxEventLoopBase::GetActive();
+        wxCHECK_MSG( loop, false, "File system watcher needs an event loop" );
 
-        int fd = inotify_init();
-        if (fd == -1)
+        m_ifd = inotify_init();
+        if ( m_ifd == -1 )
         {
             wxLogSysError( _("Unable to create inotify instance") );
             return false;
         }
 
-        int flags = wxEVENT_SOURCE_INPUT | wxEVENT_SOURCE_EXCEPTION;
-        m_source = static_cast<wxUnixEventLoopSource*>(
-                                   m_loop->CreateSource(fd, m_handler, flags));
-        return RegisterSource();
+        m_source = loop->AddSourceForFD
+                         (
+                          m_ifd,
+                          m_handler,
+                          wxEVENT_SOURCE_INPUT | wxEVENT_SOURCE_EXCEPTION
+                         );
+
+        return m_source != NULL;
     }
 
-    bool Close()
+    void Close()
     {
-        wxCHECK_MSG( IsOk(), false,
+        wxCHECK_RET( IsOk(),
                     "Inotify not initialized or invalid inotify descriptor" );
-        wxCHECK_MSG( m_loop, false,
-                    "m_loop shouldn't be null if inotify is initialized" );
 
-        // ignore errors
-        (void) UnregisterSource();
+        wxDELETE(m_source);
 
-        int ret = close(m_source->GetResource());
-        if (ret == -1)
+        if ( close(m_ifd) != 0 )
         {
             wxLogSysError( _("Unable to close inotify instance") );
         }
-        m_source->Invalidate();
-
-        return ret != -1;
     }
 
     virtual bool DoAdd(wxSharedPtr<wxFSWatchEntryUnix> watch)
@@ -143,6 +139,9 @@ public:
             wxFAIL_MSG( wxString::Format("Path %s is not watched",
                                           watch->GetPath()) );
         }
+        // Cache the wd in case any events arrive late
+        m_staleDescriptors.Add(watch->GetWatchDescriptor());
+
         watch->SetWatchDescriptor(-1);
         return true;
     }
@@ -193,39 +192,16 @@ public:
         return event_count;
     }
 
-    bool IsOk()
+    bool IsOk() const
     {
-        return m_source && m_source->IsOk();
+        return m_source != NULL;
     }
 
 protected:
-    bool RegisterSource()
-    {
-        wxCHECK_MSG( IsOk(), false,
-                    "Inotify not initialized or invalid inotify descriptor" );
-
-        bool ret = m_loop->AddSource(m_source);
-        return ret;
-    }
-
-    bool UnregisterSource()
-    {
-        wxCHECK_MSG( IsOk(), false,
-                    "Inotify not initialized or invalid inotify descriptor" );
-        wxCHECK_MSG( m_loop, false,
-                    "m_loop shouldn't be null if inotify is initialized" );
-
-        bool ret = m_loop->RemoveSource(m_source);
-        m_loop = NULL;
-        return ret;
-    }
-
     int DoAddInotify(wxFSWatchEntry* watch)
     {
         int flags = Watcher2NativeFlags(watch->GetFlags());
-        int wd = inotify_add_watch(m_source->GetResource(),
-                                   watch->GetPath().fn_str(),
-                                   flags);
+        int wd = inotify_add_watch(m_ifd, watch->GetPath().fn_str(), flags);
         // finally we can set watch descriptor
         watch->SetWatchDescriptor(wd);
         return wd;
@@ -233,8 +209,7 @@ protected:
 
     int DoRemoveInotify(wxFSWatchEntry* watch)
     {
-        return inotify_rm_watch(m_source->GetResource(),
-                                watch->GetWatchDescriptor());
+        return inotify_rm_watch(m_ifd, watch->GetWatchDescriptor());
     }
 
     void ProcessNativeEvent(const inotify_event& inevt)
@@ -245,13 +220,33 @@ protected:
         // will be already removed from our list at that time
         if (inevt.mask & IN_IGNORED)
         {
+            // It is now safe to remove it from the stale descriptors too, we
+            // won't get any more events for it.
+            m_staleDescriptors.Remove(inevt.wd);
+            wxLogTrace(wxTRACE_FSWATCHER,
+                       "Removed wd %i from the stale-wd cache", inevt.wd);
             return;
         }
 
         // get watch entry for this event
         wxFSWatchEntryDescriptors::iterator it = m_watchMap.find(inevt.wd);
-        wxCHECK_RET(it != m_watchMap.end(),
-                             "Watch descriptor not present in the watch map!");
+        if (it == m_watchMap.end())
+        {
+            // It's not in the map; check if was recently removed from it.
+            if (m_staleDescriptors.Index(inevt.wd) != wxNOT_FOUND)
+            {
+                wxLogTrace(wxTRACE_FSWATCHER,
+                           "Got an event for stale wd %i", inevt.wd);
+            }
+            else
+            {
+                wxFAIL_MSG("Event for unknown watch descriptor.");
+            }
+
+            // In any case, don't process this event: it's either for an
+            // already removed entry, or for a completely unknown one.
+            return;
+        }
 
         wxFSWatchEntry& watch = *(it->second);
         int nativeFlags = inevt.mask;
@@ -352,7 +347,7 @@ protected:
                     "Inotify not initialized or invalid inotify descriptor" );
 
         memset(buf, 0, size);
-        ssize_t left = read(m_source->GetResource(), buf, size);
+        ssize_t left = read(m_ifd, buf, size);
         if (left == -1)
         {
             wxLogSysError(_("Unable to read from inotify descriptor"));
@@ -372,9 +367,12 @@ protected:
         wxString mask = (inevt.mask & IN_ISDIR) ?
                         wxString::Format("IS_DIR | %u", inevt.mask & ~IN_ISDIR) :
                         wxString::Format("%u", inevt.mask);
+        const char* name = "";
+        if (inevt.len)
+            name = inevt.name;
         return wxString::Format("Event: wd=%d, mask=%s, cookie=%u, len=%u, "
                                 "name=%s", inevt.wd, mask, inevt.cookie,
-                                inevt.len, inevt.name);
+                                inevt.len, name);
     }
 
     static wxFileName GetEventPath(const wxFSWatchEntry& watch,
@@ -382,7 +380,7 @@ protected:
     {
         // only when dir is watched, we have non-empty e.name
         wxFileName path = watch.GetPath();
-        if (path.IsDir())
+        if (path.IsDir() && inevt.len)
         {
             path = wxFileName(path.GetPath(), inevt.name);
         }
@@ -450,9 +448,12 @@ protected:
 
     wxFSWSourceHandler* m_handler;        // handler for inotify event source
     wxFSWatchEntryDescriptors m_watchMap; // inotify wd=>wxFSWatchEntry* map
+    wxArrayInt m_staleDescriptors;        // stores recently-removed watches
     wxInotifyCookies m_cookies;           // map to track renames
-    wxEventLoopBase* m_loop;
-    wxUnixEventLoopSource* m_source;      // our event loop source
+    wxEventLoopSource* m_source;          // our event loop source
+
+    // file descriptor created by inotify_init()
+    int m_ifd;
 };