]> git.saurik.com Git - wxWidgets.git/blobdiff - src/unix/fswatcher_inotify.cpp
Add missing WXK constants for the control keys
[wxWidgets.git] / src / unix / fswatcher_inotify.cpp
index 675d1168e352aa797859ab5af590f706b69fdbd2..5bcc475698ef63bc3fb3f6c5329a4796619c2fe3 100644 (file)
@@ -222,9 +222,15 @@ protected:
         {
             // 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,
+            // However if we're here because a dir that we're still watching
+            // has just been deleted, its wd won't be on this list
+            const int pos = m_staleDescriptors.Index(inevt.wd);
+            if ( pos != wxNOT_FOUND )
+            {
+                m_staleDescriptors.RemoveAt(static_cast<size_t>(pos));
+                wxLogTrace(wxTRACE_FSWATCHER,
                        "Removed wd %i from the stale-wd cache", inevt.wd);
+            }
             return;
         }
 
@@ -265,11 +271,81 @@ protected:
         {
             return;
         }
+
+        // Creation
+        // We need do something here only if the original watch was recursive;
+        // we don't watch a child dir itself inside a non-tree watch.
+        // We watch only dirs explicitly, so we don't want file IN_CREATEs.
+        // Distinguish by whether nativeFlags contain IN_ISDIR
+        else if ((nativeFlags & IN_CREATE) &&
+                 (watch.GetType() == wxFSWPath_Tree) && (inevt.mask & IN_ISDIR))
+        {
+            wxFileName fn = GetEventPath(watch, inevt);
+            // Though it's a dir, fn treats it as a file. So:
+            fn.AssignDir(fn.GetFullPath());
+
+            if (m_watcher->AddAny(fn, wxFSW_EVENT_ALL,
+                                   wxFSWPath_Tree, watch.GetFilespec()))
+            {
+                // Tell the owner, in case it's interested
+                // If there's a filespec, assume he's not
+                if (watch.GetFilespec().empty())
+                {
+                    wxFileSystemWatcherEvent event(flags, fn, fn);
+                    SendEvent(event);
+                }
+            }
+        }
+
+        // Deletion
+        // We watch only dirs explicitly, so we don't want file IN_DELETEs.
+        // We obviously can't check using DirExists() as the object has been
+        // deleted; and nativeFlags here doesn't contain IN_ISDIR, even for
+        // a dir. Fortunately IN_DELETE_SELF doesn't happen for files. We need
+        // to do something here only inside a tree watch, or if it's the parent
+        // dir that's deleted. Otherwise let the parent dir cope
+        else if ((nativeFlags & IN_DELETE_SELF) &&
+                    ((watch.GetType() == wxFSWPath_Dir) ||
+                     (watch.GetType() == wxFSWPath_Tree)))
+        {
+            // We must remove the deleted directory from the map, so that
+            // DoRemoveInotify() isn't called on it in the future. Don't assert
+            // if the wd isn't found: repeated IN_DELETE_SELFs can occur
+            wxFileName fn = GetEventPath(watch, inevt);
+            wxString path(fn.GetPathWithSep());
+
+            if (m_watchMap.erase(inevt.wd) == 1)
+            {
+                // Delete from wxFileSystemWatcher
+                wxDynamicCast(m_watcher, wxInotifyFileSystemWatcher)->
+                                            OnDirDeleted(path);
+
+                // Now remove from our local list of watched items
+                wxFSWatchEntries::iterator wit =
+                                        m_watches.find(path);
+                if (wit != m_watches.end())
+                {
+                    m_watches.erase(wit);
+                }
+
+                // Cache the wd in case any events arrive late
+                m_staleDescriptors.Add(inevt.wd);
+            }
+
+            // Tell the owner, in case it's interested
+            // If there's a filespec, assume he's not
+            if (watch.GetFilespec().empty())
+            {
+                wxFileSystemWatcherEvent event(flags, fn, fn);
+                SendEvent(event);
+            }
+        }
+
         // renames
         else if (nativeFlags & IN_MOVE)
         {
-            wxInotifyCookies::iterator it = m_cookies.find(inevt.cookie);
-            if ( it == m_cookies.end() )
+            wxInotifyCookies::iterator it2 = m_cookies.find(inevt.cookie);
+            if ( it2 == m_cookies.end() )
             {
                 int size = sizeof(inevt) + inevt.len;
                 inotify_event* e = (inotify_event*) operator new (size);
@@ -280,22 +356,27 @@ protected:
             }
             else
             {
-                inotify_event& oldinevt = *(it->second);
+                inotify_event& oldinevt = *(it2->second);
 
-                wxFileSystemWatcherEvent event(flags);
-                if ( inevt.mask & IN_MOVED_FROM )
+                // Tell the owner, in case it's interested
+                // If there's a filespec, assume he's not
+                if ( watch.GetFilespec().empty() )
                 {
-                    event.SetPath(GetEventPath(watch, inevt));
-                    event.SetNewPath(GetEventPath(watch, oldinevt));
+                    wxFileSystemWatcherEvent event(flags);
+                    if ( inevt.mask & IN_MOVED_FROM )
+                    {
+                        event.SetPath(GetEventPath(watch, inevt));
+                        event.SetNewPath(GetEventPath(watch, oldinevt));
+                    }
+                    else
+                    {
+                        event.SetPath(GetEventPath(watch, oldinevt));
+                        event.SetNewPath(GetEventPath(watch, inevt));
+                    }
+                    SendEvent(event);
                 }
-                else
-                {
-                    event.SetPath(GetEventPath(watch, oldinevt));
-                    event.SetNewPath(GetEventPath(watch, inevt));
-                }
-                SendEvent(event);
 
-                m_cookies.erase(it);
+                m_cookies.erase(it2);
                 delete &oldinevt;
             }
         }
@@ -303,8 +384,12 @@ protected:
         else
         {
             wxFileName path = GetEventPath(watch, inevt);
-            wxFileSystemWatcherEvent event(flags, path, path);
-            SendEvent(event);
+            // For files, check that it matches any filespec
+            if ( MatchesFilespec(path, watch.GetFilespec()) )
+            {
+                wxFileSystemWatcherEvent event(flags, path, path);
+                SendEvent(event);
+            }
         }
     }
 
@@ -323,11 +408,18 @@ protected:
             wxCHECK_RET(wit != m_watchMap.end(),
                              "Watch descriptor not present in the watch map!");
 
+            // Tell the owner, in case it's interested
+            // If there's a filespec, assume he's not
             wxFSWatchEntry& watch = *(wit->second);
-            int flags = Native2WatcherFlags(inevt.mask);
-            wxFileName path = GetEventPath(watch, inevt);
-            wxFileSystemWatcherEvent event(flags, path, path);
-            SendEvent(event);
+            if ( watch.GetFilespec().empty() )
+            {
+                int flags = Native2WatcherFlags(inevt.mask);
+                wxFileName path = GetEventPath(watch, inevt);
+                {
+                    wxFileSystemWatcherEvent event(flags, path, path);
+                    SendEvent(event);
+                }
+            }
 
             m_cookies.erase(it);
             delete &inevt;
@@ -513,6 +605,19 @@ bool wxInotifyFileSystemWatcher::Init()
     return m_service->Init();
 }
 
+void wxInotifyFileSystemWatcher::OnDirDeleted(const wxString& path)
+{
+    if (!path.empty())
+    {
+        wxFSWatchInfoMap::iterator it = m_watches.find(path);
+        wxCHECK_RET(it != m_watches.end(),
+                    wxString::Format("Path '%s' is not watched", path));
+
+        // path has been deleted, so we must forget it whatever its refcount
+        m_watches.erase(it);
+    }
+}
+
 #endif // wxHAS_INOTIFY
 
 #endif // wxUSE_FSWATCHER