Moved ProviderCollectionTest.cs from System assembly to System.Configuration.
[mono.git] / mcs / class / System / System.IO / FileSystemWatcher.cs
index f4d12e7e774215dc3f10d2d844232d02f998b197..88dd5d813dd7c34cdb0757f5046af06a671c75e8 100644 (file)
@@ -7,17 +7,42 @@
 //
 // Copyright (C) Tim Coleman, 2002 
 // (c) 2003 Ximian, Inc. (http://www.ximian.com)
-// (c) 2004 Novell, Inc. (http://www.novell.com)
+// Copyright (C) 2004, 2006 Novell, Inc (http://www.novell.com)
+//
+
+//
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to
+// permit persons to whom the Software is furnished to do so, subject to
+// the following conditions:
+// 
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+// 
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 //
 
-using System;
 using System.ComponentModel;
+using System.Diagnostics;
 using System.Runtime.CompilerServices;
 using System.Runtime.InteropServices;
+using System.Security.Permissions;
 using System.Threading;
 
 namespace System.IO {
        [DefaultEvent("Changed")]
+#if NET_2_0
+       [IODescription ("")]
+#endif
        public class FileSystemWatcher : Component, ISupportInitialize {
 
                #region Fields
@@ -30,11 +55,13 @@ namespace System.IO {
                string path;
                string fullpath;
                ISynchronizeInvoke synchronizingObject;
-               bool disposed;
                WaitForChangedResult lastData;
                bool waiting;
                SearchPattern2 pattern;
+               bool disposed;
+               string mangledFilter;
                static IFileWatcher watcher;
+               static object lockobj = new object ();
 
                #endregion // Fields
 
@@ -80,24 +107,55 @@ namespace System.IO {
                        InitWatcher ();
                }
 
+               [EnvironmentPermission (SecurityAction.Assert, Read="MONO_MANAGED_WATCHER")]
                void InitWatcher ()
                {
-                       lock (typeof (FileSystemWatcher)) {
+                       lock (lockobj) {
                                if (watcher != null)
                                        return;
 
-                               int mode = InternalSupportsFSW ();
+                               string managed = Environment.GetEnvironmentVariable ("MONO_MANAGED_WATCHER");
+                               int mode = 0;
+                               if (managed == null)
+                                       mode = InternalSupportsFSW ();
+                               
                                bool ok = false;
-                               if (mode == 2)
-                                       ok = FAMWatcher.GetInstance (out watcher);
-                               else if (mode == 1)
-                                       ok = WindowsWatcher.GetInstance (out watcher);
+                               switch (mode) {
+                               case 1: // windows
+                                       ok = DefaultWatcher.GetInstance (out watcher);
+                                       //ok = WindowsWatcher.GetInstance (out watcher);
+                                       break;
+                               case 2: // libfam
+                                       ok = FAMWatcher.GetInstance (out watcher, false);
+                                       break;
+                               case 3: // kevent
+                                       ok = KeventWatcher.GetInstance (out watcher);
+                                       break;
+                               case 4: // libgamin
+                                       ok = FAMWatcher.GetInstance (out watcher, true);
+                                       break;
+                               case 5: // inotify
+                                       ok = InotifyWatcher.GetInstance (out watcher, true);
+                                       break;
+                               }
+
+                               if (mode == 0 || !ok) {
+                                       if (String.Compare (managed, "disabled", true) == 0)
+                                               NullFileWatcher.GetInstance (out watcher);
+                                       else
+                                               DefaultWatcher.GetInstance (out watcher);
+                               }
 
-                               if (mode == 0 || !ok)
-                                       DefaultWatcher.GetInstance (out watcher);
+                               ShowWatcherInfo ();
                        }
                }
 
+               [Conditional ("DEBUG"), Conditional ("TRACE")]
+               void ShowWatcherInfo ()
+               {
+                       Console.WriteLine ("Watcher implementation: {0}", watcher != null ? watcher.GetType ().ToString () : "<none>");
+               }
+               
                #endregion // Constructors
 
                #region Properties
@@ -108,14 +166,26 @@ namespace System.IO {
                        set { waiting = value; }
                }
 
+               internal string MangledFilter {
+                       get {
+                               if (filter != "*.*")
+                                       return filter;
+
+                               if (mangledFilter != null)
+                                       return mangledFilter;
+
+                               string filterLocal = "*.*";
+                               if (!(watcher.GetType () == typeof (WindowsWatcher)))
+                                       filterLocal = "*";
+
+                               return filterLocal;
+                       }
+               }
+
                internal SearchPattern2 Pattern {
                        get {
                                if (pattern == null) {
-                                       string f = Filter;
-                                       if (f == "*.*" && !(watcher.GetType () == typeof (WindowsWatcher)))
-                                               f = "*";
-
-                                       pattern = new SearchPattern2 (f);
+                                       pattern = new SearchPattern2 (MangledFilter);
                                }
                                return pattern;
                        }
@@ -164,6 +234,7 @@ namespace System.IO {
                                if (filter != value) {
                                        filter = value;
                                        pattern = null;
+                                       mangledFilter = null;
                                }
                        }
                }
@@ -262,6 +333,9 @@ namespace System.IO {
 
                [DefaultValue(null)]
                [IODescription("The object used to marshal the event handler calls resulting from a directory change")]
+#if NET_2_0
+               [Browsable (false)]
+#endif
                public ISynchronizeInvoke SynchronizingObject {
                        get { return synchronizingObject; }
                        set { synchronizingObject = value; }
@@ -271,65 +345,83 @@ namespace System.IO {
 
                #region Methods
        
-               [MonoTODO]
                public void BeginInit ()
                {
-                       throw new NotImplementedException (); 
+                       // Not necessary in Mono
                }
 
                protected override void Dispose (bool disposing)
                {
-                       if (disposing) {
+                       if (!disposed) {
+                               disposed = true;
                                Stop ();
                        }
-                       disposed = true;
+
                        base.Dispose (disposing);
                }
 
-               [MonoTODO]
+               ~FileSystemWatcher ()
+               {
+                       disposed = true;
+                       Stop ();
+               }
+               
                public void EndInit ()
                {
-                       throw new NotImplementedException (); 
+                       // Not necessary in Mono
                }
 
-               private void RaiseEvent (Delegate ev, EventArgs arg)
+               enum EventType {
+                       FileSystemEvent,
+                       ErrorEvent,
+                       RenameEvent
+               }
+               private void RaiseEvent (Delegate ev, EventArgs arg, EventType evtype)
                {
                        if (ev == null)
                                return;
 
-                       object [] args = new object [] {this, arg};
-
                        if (synchronizingObject == null) {
-                               ev.DynamicInvoke (args);
+                               switch (evtype) {
+                               case EventType.RenameEvent:
+                                       ((RenamedEventHandler)ev).BeginInvoke (this, (RenamedEventArgs) arg, null, null);
+                                       break;
+                               case EventType.ErrorEvent:
+                                       ((ErrorEventHandler)ev).BeginInvoke (this, (ErrorEventArgs) arg, null, null);
+                                       break;
+                               case EventType.FileSystemEvent:
+                                       ((FileSystemEventHandler)ev).BeginInvoke (this, (FileSystemEventArgs) arg, null, null);
+                                       break;
+                               }
                                return;
                        }
                        
-                       synchronizingObject.BeginInvoke (ev, args);
+                       synchronizingObject.BeginInvoke (ev, new object [] {this, arg});
                }
 
                protected void OnChanged (FileSystemEventArgs e)
                {
-                       RaiseEvent (Changed, e);
+                       RaiseEvent (Changed, e, EventType.FileSystemEvent);
                }
 
                protected void OnCreated (FileSystemEventArgs e)
                {
-                       RaiseEvent (Created, e);
+                       RaiseEvent (Created, e, EventType.FileSystemEvent);
                }
 
                protected void OnDeleted (FileSystemEventArgs e)
                {
-                       RaiseEvent (Deleted, e);
+                       RaiseEvent (Deleted, e, EventType.FileSystemEvent);
                }
 
                protected void OnError (ErrorEventArgs e)
                {
-                       RaiseEvent (Error, e);
+                       RaiseEvent (Error, e, EventType.ErrorEvent);
                }
 
                protected void OnRenamed (RenamedEventArgs e)
                {
-                       RaiseEvent (Renamed, e);
+                       RaiseEvent (Renamed, e, EventType.RenameEvent);
                }
 
                public WaitForChangedResult WaitForChanged (WatcherChangeTypes changeType)
@@ -387,15 +479,13 @@ namespace System.IO {
                                }
                                lastData.OldName = filename;
                                lastData.ChangeType = WatcherChangeTypes.Renamed;
-                               renamed = new RenamedEventArgs (WatcherChangeTypes.Renamed, path, null, filename);
+                               renamed = new RenamedEventArgs (WatcherChangeTypes.Renamed, path, filename, "");
                                break;
                        case FileAction.RenamedNewName:
                                lastData.Name = filename;
                                lastData.ChangeType = WatcherChangeTypes.Renamed;
-                               if (renamed != null) {
-                                       renamed.SetName (filename);
-                               } else {
-                                       renamed = new RenamedEventArgs (WatcherChangeTypes.Renamed, path, filename, null);
+                               if (renamed == null) {
+                                       renamed = new RenamedEventArgs (WatcherChangeTypes.Renamed, path, "", filename);
                                }
                                OnRenamed (renamed);
                                renamed = null;
@@ -421,7 +511,6 @@ namespace System.IO {
                [IODescription("Occurs when a file/directory change matches the filter")]
                public event FileSystemEventHandler Changed;
 
-
                [IODescription("Occurs when a file/directory creation matches the filter")]
                public event FileSystemEventHandler Created;
 
@@ -439,23 +528,11 @@ namespace System.IO {
                /* 0 -> not supported   */
                /* 1 -> windows         */
                /* 2 -> FAM             */
+               /* 3 -> Kevent          */
+               /* 4 -> gamin           */
+               /* 5 -> inotify         */
                [MethodImplAttribute(MethodImplOptions.InternalCall)]
                static extern int InternalSupportsFSW ();
-               
-               /*[MethodImplAttribute(MethodImplOptions.InternalCall)]
-               static extern IntPtr InternalOpenDirectory (string path, IntPtr reserved);
-
-               [MethodImplAttribute(MethodImplOptions.InternalCall)]
-               static extern IntPtr InternalCloseDirectory (IntPtr handle);
-
-               [MethodImplAttribute(MethodImplOptions.InternalCall)]
-               static extern bool InternalReadDirectoryChanges (IntPtr handle,
-                                                                byte [] buffer,
-                                                                bool includeSubdirectories,
-                                                                NotifyFilters notifyFilter,
-                                                                out NativeOverlapped overlap,
-                                                                OverlappedHandler overlappedCallback);
-
-               */
        }
 }
+