**********************************************************************/
using System;
+using System.Collections;
+using System.Collections.Generic;
using System.Runtime.InteropServices;
namespace VideoLAN.LibVLC
Destroy ();
return true;
}
-
};
/**
* @brief BaseObject: generic wrapper around a safe LibVLC handle.
* @ingroup Internals
- * This is the baseline for all managed LibVLC objects which wrap
- * an unmanaged LibVLC pointer, and provides exception handling.
+ *
+ * This is the baseline for all managed LibVLC objects. It wraps:
+ * - an unmanaged LibVLC pointer,
+ * - a native exception structure.
*/
public class BaseObject : IDisposable
{
handle = null;
}
};
+
+ internal class EventManagerHandle : NonNullHandle
+ {
+ protected override void Destroy ()
+ {
+ }
+ };
+
+
+ /**
+ * @brief EventingObject: wrapper around an eventing LibVLC handle.
+ * @ingroup Internals
+ *
+ * This is the base class for all managed LibVLC objects which do have an
+ * event manager.
+ */
+ public abstract class EventingObject : BaseObject
+ {
+ private Dictionary<Delegate, IntPtr> events;
+ /**< references to our unmanaged function pointers */
+
+ internal EventingObject () : base ()
+ {
+ events = new Dictionary<Delegate, IntPtr> ();
+ }
+
+ /**
+ * Releases unmanaged resources associated with the object.
+ * @param disposing true if the disposing the object explicitly,
+ * false if finalizing the object inside the GC.
+ */
+ protected override void Dispose (bool disposing)
+ {
+ events = null;
+ base.Dispose (disposing);
+ }
+
+ /**
+ * @return the unmanaged event manager for this object
+ */
+ internal abstract EventManagerHandle GetManager ();
+
+ /**
+ * Registers an event handler.
+ * @param type event type to register to
+ * @param callback callback to invoke when the event occurs
+ *
+ * @note
+ * For simplicity, we require distinct callbacks for each event type.
+ * This is hardly an issue since most events have different formats.
+ */
+ internal void Attach (EventType type, Delegate callback)
+ {
+ EventManagerHandle manager;
+ IntPtr cb = Marshal.GetFunctionPointerForDelegate (callback);
+ bool unref = false;
+
+ /* If things go wrong, we will leak the callback thunk... until
+ * this object is destroyed anyway. If we added the thunk _after_
+ * the critical section, the native code could try to jump to a
+ * non-existent address, which is much worse. */
+ events.Add (callback, cb);
+ try
+ {
+ handle.DangerousAddRef (ref unref);
+ manager = GetManager ();
+ LibVLC.EventAttach (manager, type, cb, IntPtr.Zero, ex);
+ }
+ finally
+ {
+ if (unref)
+ handle.DangerousRelease ();
+ }
+ Raise ();
+ }
+
+ internal void Detach (EventType type, Delegate callback)
+ {
+ EventManagerHandle manager;
+ IntPtr cb = events[callback];
+ bool unref = false;
+
+ try
+ {
+ handle.DangerousAddRef (ref unref);
+ manager = GetManager ();
+ LibVLC.EventDetach (manager, type, cb, IntPtr.Zero, ex);
+ }
+ finally
+ {
+ if (unref)
+ handle.DangerousRelease ();
+ }
+ Raise ();
+ events.Remove (callback);
+ }
+ };
};