return true;
     }
 
+    // Check whether any filespec matches the file's ext (if present)
+    bool MatchesFilespec(const wxFileName& fn, const wxString& filespec) const
+    {
+        return filespec.empty() || wxMatchWild(filespec, fn.GetFullName());
+    }
+
 protected:
     virtual bool DoAdd(wxSharedPtr<wxFSWatchEntry> watch) = 0;
 
 
         {
         }
 
-        // CHECK we choose which files to delegate to Add(), maybe we should pass
-        // all of them to Add() and let it choose? this is useful when adding a
-        // file to a dir that is already watched, then not only should we know
-        // about that, but Add() should also behave well then
-        virtual wxDirTraverseResult OnFile(const wxString& filename)
+        virtual wxDirTraverseResult OnFile(const wxString& WXUNUSED(filename))
         {
-            if ( m_watcher->AddAny(wxFileName::FileName(filename),
-                                   m_events, wxFSWPath_File) )
-            {
-                wxLogTrace(wxTRACE_FSWATCHER,
-                       "--- AddTree adding file '%s' ---", filename);
-            }
+            // There is no need to watch individual files as we watch the
+            // parent directory which will notify us about any changes in them.
             return wxDIR_CONTINUE;
         }
 
         virtual wxDirTraverseResult OnDir(const wxString& dirname)
         {
-            // We can't currently watch only the files with the given filespec
-            // in the subdirectories so we only watch subdirectories at all if
-            // we want to watch everything.
-            if ( m_filespec.empty() )
+            if ( m_watcher->AddAny(wxFileName::DirName(dirname),
+                                   m_events, wxFSWPath_Tree, m_filespec) )
             {
-                if ( m_watcher->AddAny(wxFileName::DirName(dirname),
-                                       m_events, wxFSWPath_Dir) )
-                {
-                    wxLogTrace(wxTRACE_FSWATCHER,
-                       "--- AddTree adding directory '%s' ---", dirname);
-                }
+                wxLogTrace(wxTRACE_FSWATCHER,
+                   "--- AddTree adding directory '%s' ---", dirname);
             }
             return wxDIR_CONTINUE;
         }
     dir.Traverse(traverser, filespec);
 
     // Add the path itself explicitly as Traverse() doesn't return it.
-    AddAny(path.GetPathWithSep(), events, wxFSWPath_Dir, filespec);
+    AddAny(path.GetPathWithSep(), events, wxFSWPath_Tree, filespec);
 
     return true;
 }
         {
         }
 
-        virtual wxDirTraverseResult OnFile(const wxString& filename)
+        virtual wxDirTraverseResult OnFile(const wxString& WXUNUSED(filename))
         {
-            m_watcher->Remove(wxFileName(filename));
+            // We never watch the individual files when watching the tree, so
+            // nothing to do here.
             return wxDIR_CONTINUE;
         }
 
         virtual wxDirTraverseResult OnDir(const wxString& dirname)
         {
-            // Currently the subdirectories would have been added only if there
-            // is no filespec.
-            //
-            // Notice that we still need to recurse into them even if we're
-            // using a filespec because they can contain files matching it.
-            if ( m_filespec.empty() )
-            {
-                m_watcher->Remove(wxFileName::DirName(dirname));
-            }
-
+            m_watcher->Remove(wxFileName::DirName(dirname));
             return wxDIR_CONTINUE;
         }
 
 
             // CHECK I heard that returned path can be either in short on long
             // form...need to account for that!
             wxFileName path = GetEventPath(*watch, e);
-            wxFileSystemWatcherEvent event(flags, path, path);
-            SendEvent(event);
+            // For files, check that it matches any filespec
+            if ( m_service->MatchesFilespec(path, watch->GetFilespec()) )
+            {
+                wxFileSystemWatcherEvent event(flags, path, path);
+                SendEvent(event);
+            }
         }
     }
 }
 
             {
                 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(it2);
                 delete &oldinevt;
         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);
+            }
         }
     }
 
             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;
 
 #ifndef __WINDOWS__
             // When there's no file mask, wxMSW sets a single watch
             // on the trunk which is implemented recursively.
-            // wxGTK always sets an additional watch for each file/subdir
-            treeitems += (subdirs*files) + subdirs + 1; // +1 for 'child'
+            // wxGTK always sets an additional watch for each subdir
+            treeitems += subdirs + 1; // +1 for 'child'
 #endif // __WINDOWS__
 
             // Store the initial count; there may already be some watches
             const int initial = m_watcher->GetWatchedPathsCount();
 
             // When we use a filter, both wxMSW and wxGTK implementations set
-            // an additional watch for each file/subdir. Test by passing *.txt
-            // We expect the dirs and the other 2 files to be skipped
-            const size_t treeitems = subdirs + 1;
+            // an additional watch for each subdir (+1 for the root dir itself
+            // and another +1 for "child").
+            const size_t treeitems = subdirs + 2;
             m_watcher->AddTree(dir, wxFSW_EVENT_ALL, "*.txt");
 
             const int plustree = m_watcher->GetWatchedPathsCount();