Beispiel #1
0
 public override IntPtr AddNotificationCallback(IntPtr managedCollectionHandle, NotificationCallbackDelegate callback)
 {
     NativeException nativeException;
     var result = NativeMethods.add_notification_callback(this, managedCollectionHandle, callback, out nativeException);
     nativeException.ThrowIfNecessary();
     return result;
 }
Beispiel #2
0
        public void WhenSynchronizationContextExists_ShouldAutoRefresh()
        {
            AsyncContext.Run(async() =>
            {
                var tcs   = new TaskCompletionSource <ChangeSet>();
                var query = _realm.All <Person>();
                NotificationCallbackDelegate <Person> cb = (s, c, e) =>
                {
                    if (e != null)
                    {
                        tcs.TrySetException(e);
                    }
                    else if (c != null)
                    {
                        tcs.TrySetResult(c);
                    }
                };

                using (query.SubscribeForNotifications(cb))
                {
                    _realm.Write(() => _realm.Add(new Person()));

                    var changes = await tcs.Task.Timeout(2000);

                    Assert.That(changes, Is.Not.Null);
                    Assert.That(changes.InsertedIndices, Is.EquivalentTo(new int[] { 0 }));
                }
            });
        }
Beispiel #3
0
        /// <summary>
        /// Initializes a new instance of the <see cref="AudioEngine"/> class.
        /// </summary>
        /// <param name="creationFlags">The creation flags.</param>
        /// <param name="settings">Settings for this audio engine</param>
        public AudioEngine(CreationFlags creationFlags, AudioEngineSettings settings)
        {
            bool debug    = (creationFlags == CreationFlags.DebugMode);
            bool audition = (creationFlags == CreationFlags.AuditionMode);

            var debugRegistryKey = Registry.LocalMachine.OpenSubKey(DebugEngineRegistryKey);

            // If neither the debug nor audition flags are set, see if the debug registry key is set
            if (!debug && !audition && debugRegistryKey != null)
            {
                var value = debugRegistryKey.GetValue(DebugEngineRegistryValue);

                if (value is Int32 && ((int)value) != 0)
                {
                    debug = true;
                }

                debugRegistryKey.Close();
            }

            var selectedEngineCLSID = (debug) ? DebugEngineGuid : (audition) ? AuditionEngineGuid : EngineGuid;

            Utilities.CreateComInstance(selectedEngineCLSID, Utilities.CLSCTX.ClsctxInprocServer, Utilities.GetGuidFromType(typeof(AudioEngine)), this);

            unsafe
            {
                unmanagedDelegate        = new NotificationCallbackDelegate(NotificationCallbackDelegateImpl);
                unmanagedDelegatePointer = Marshal.GetFunctionPointerForDelegate(unmanagedDelegate);
            }

            // Initialize the engine
            PreInitialize(settings);
            Initialize(settings);
        }
Beispiel #4
0
        public override IntPtr AddNotificationCallback(IntPtr managedObjectHandle, NotificationCallbackDelegate callback)
        {
            var result = NativeMethods.add_notification_callback(this, managedObjectHandle, callback, out var nativeException);

            nativeException.ThrowIfNecessary();
            return(result);
        }
Beispiel #5
0
 private void UnsubscribeFromNotifications(NotificationCallbackDelegate <T> callback)
 {
     if (_callbacks.Remove(callback) &&
         _callbacks.Count == 0)
     {
         UnsubscribeFromNotifications();
     }
 }
Beispiel #6
0
 internal void RemoveCallback(NotificationCallbackDelegate callback)
 {
     if (_callbacks.Remove(callback) &&
         _callbacks.Count == 0)
     {
         UnsubscribeFromNotifications();
     }
 }
Beispiel #7
0
        public IntPtr AddNotificationCallback(IntPtr managedResultsHandle, NotificationCallbackDelegate callback)
        {
            NativeException nativeException;
            var             result = NativeMethods.add_notification_callback(this, managedResultsHandle, callback, out nativeException);

            nativeException.ThrowIfNecessary();
            return(result);
        }
Beispiel #8
0
        public IDisposable SubscribeForNotifications(NotificationCallbackDelegate <T> callback)
        {
            if (_callbacks.Count == 0)
            {
                SubscribeForNotifications();
            }

            _callbacks.Add(callback);

            return(new NotificationToken(this, callback));
        }
Beispiel #9
0
        public void ResultsShouldSendNotifications()
        {
            var       query   = _realm.All <Person>();
            ChangeSet changes = null;
            NotificationCallbackDelegate <Person> cb = (s, c, e) => changes = c;

            using (query.SubscribeForNotifications(cb))
            {
                _realm.Write(() => _realm.Add(new Person()));

                _realm.Refresh();
                Assert.That(changes, Is.Not.Null);
                Assert.That(changes.InsertedIndices, Is.EquivalentTo(new int[] { 0 }));
            }
        }
        public IDisposable SubscribeForNotifications(NotificationCallbackDelegate <T> callback)
        {
            if (_callbacks.Count == 0)
            {
                SubscribeForNotifications();
            }
            else if (_deliveredInitialNotification)
            {
                callback(this, null, null);
            }

            _callbacks.Add(callback);

            return(new NotificationToken(this, callback));
        }
Beispiel #11
0
        public void ListShouldSendNotifications()
        {
            var container = new OrderedContainer();

            _realm.Write(() => _realm.Add(container));
            ChangeSet changes = null;
            NotificationCallbackDelegate <OrderedObject> cb = (s, c, e) => changes = c;

            using (container.Items.SubscribeForNotifications(cb))
            {
                _realm.Write(() => container.Items.Add(new OrderedObject()));

                _realm.Refresh();
                Assert.That(changes, Is.Not.Null);
                Assert.That(changes.InsertedIndices, Is.EquivalentTo(new int[] { 0 }));
            }
        }
Beispiel #12
0
        public IDisposable SubscribeForNotifications(NotificationCallbackDelegate <T> callback)
        {
            Argument.NotNull(callback, nameof(callback));

            if (_callbacks.Count == 0)
            {
                SubscribeForNotifications();
            }
            else if (_deliveredInitialNotification)
            {
                callback(this, null, null);
            }

            _callbacks.Add(callback);

            return(NotificationToken.Create(callback, UnsubscribeFromNotifications));
        }
        public void ResultsShouldSendNotifications()
        {
            AsyncContext.Run(async delegate
            {
                var query         = _realm.All <Person>();
                ChangeSet changes = null;
                NotificationCallbackDelegate <Person> cb = (s, c, e) => changes = c;

                using (query.SubscribeForNotifications(cb))
                {
                    _realm.Write(() => _realm.Add(new Person()));

                    await Task.Delay(MillisecondsToWaitForCollectionNotification);
                    Assert.That(changes, Is.Not.Null);
                    Assert.That(changes.InsertedIndices, Is.EquivalentTo(new int[] { 0 }));
                }
            });
        }
        public void ListShouldSendNotifications()
        {
            AsyncContext.Run(async delegate
            {
                var container = new OrderedContainer();
                _realm.Write(() => _realm.Add(container));
                ChangeSet changes = null;
                NotificationCallbackDelegate <OrderedObject> cb = (s, c, e) => changes = c;

                using (container.Items.SubscribeForNotifications(cb))
                {
                    _realm.Write(() => container.Items.Add(new OrderedObject()));

                    await Task.Delay(MillisecondsToWaitForCollectionNotification);
                    Assert.That(changes, Is.Not.Null);
                    Assert.That(changes.InsertedIndices, Is.EquivalentTo(new int[] { 0 }));
                }
            });
        }
Beispiel #15
0
        /// <summary>
        /// Register a callback to be invoked each time this <see cref="T:Realms.IRealmCollection`1" /> changes.
        /// </summary>
        /// <remarks>
        /// <para>
        /// This adds osu! specific thread and managed state safety checks on top of <see cref="IRealmCollection{T}.SubscribeForNotifications"/>.
        /// </para>
        /// <para>
        /// The first callback will be invoked with the initial <see cref="T:Realms.IRealmCollection`1" /> after the asynchronous query completes,
        /// and then called again after each write transaction which changes either any of the objects in the collection, or
        /// which objects are in the collection. The <c>changes</c> parameter will
        /// be <c>null</c> the first time the callback is invoked with the initial results. For each call after that,
        /// it will contain information about which rows in the results were added, removed or modified.
        /// </para>
        /// <para>
        /// If a write transaction did not modify any objects in this <see cref="T:Realms.IRealmCollection`1" />, the callback is not invoked at all.
        /// If an error occurs the callback will be invoked with <c>null</c> for the <c>sender</c> parameter and a non-<c>null</c> <c>error</c>.
        /// Currently the only errors that can occur are when opening the <see cref="T:Realms.Realm" /> on the background worker thread.
        /// </para>
        /// <para>
        /// At the time when the block is called, the <see cref="T:Realms.IRealmCollection`1" /> object will be fully evaluated
        /// and up-to-date, and as long as you do not perform a write transaction on the same thread
        /// or explicitly call <see cref="M:Realms.Realm.Refresh" />, accessing it will never perform blocking work.
        /// </para>
        /// <para>
        /// Notifications are delivered via the standard event loop, and so can't be delivered while the event loop is blocked by other activity.
        /// When notifications can't be delivered instantly, multiple notifications may be coalesced into a single notification.
        /// This can include the notification with the initial collection.
        /// </para>
        /// </remarks>
        /// <param name="collection">The <see cref="IRealmCollection{T}"/> to observe for changes.</param>
        /// <param name="callback">The callback to be invoked with the updated <see cref="T:Realms.IRealmCollection`1" />.</param>
        /// <returns>
        /// A subscription token. It must be kept alive for as long as you want to receive change notifications.
        /// To stop receiving notifications, call <see cref="M:System.IDisposable.Dispose" />.
        ///
        /// May be null in the case the provided collection is not managed.
        /// </returns>
        /// <seealso cref="M:Realms.CollectionExtensions.SubscribeForNotifications``1(System.Collections.Generic.IList{``0},Realms.NotificationCallbackDelegate{``0})" />
        /// <seealso cref="M:Realms.CollectionExtensions.SubscribeForNotifications``1(System.Linq.IQueryable{``0},Realms.NotificationCallbackDelegate{``0})" />
        public static IDisposable?QueryAsyncWithNotifications <T>(this IRealmCollection <T> collection, NotificationCallbackDelegate <T> callback)
            where T : RealmObjectBase
        {
            if (!RealmAccess.CurrentThreadSubscriptionsAllowed)
            {
                throw new InvalidOperationException($"Make sure to call {nameof(RealmAccess)}.{nameof(RealmAccess.RegisterForNotifications)}");
            }

            return(collection.SubscribeForNotifications(callback));
        }
Beispiel #16
0
 public static extern IntPtr add_notification_callback(ResultsHandle results, IntPtr managedResultsHandle, NotificationCallbackDelegate callback, out NativeException ex);
 public static extern IntPtr add_notification_callback(DictionaryHandle handle, IntPtr managedDictionaryHandle, NotificationCallbackDelegate callback, out NativeException ex);
Beispiel #18
0
 public static extern IntPtr add_notification_callback(ListHandle listHandle, IntPtr managedListHandle, NotificationCallbackDelegate callback, out NativeException ex);
Beispiel #19
0
 public abstract NotificationTokenHandle AddNotificationCallback(IntPtr managedObjectHandle, NotificationCallbackDelegate callback);
Beispiel #20
0
 /// <summary>
 /// A convenience method that casts <see cref="IList{T}" /> to <see cref="IRealmCollection{T}"/> and subscribes for change notifications.
 /// </summary>
 /// <param name="list">The <see cref="IList{T}" /> to observe for changes.</param>
 /// <typeparam name="T">Type of the objects in the list.</typeparam>
 /// <seealso cref="IRealmCollection{T}.SubscribeForNotifications"/>
 /// <param name="callback">The callback to be invoked with the updated <see cref="IRealmCollection{T}" />.</param>
 /// <returns>
 /// A subscription token. It must be kept alive for as long as you want to receive change notifications.
 /// To stop receiving notifications, call <see cref="IDisposable.Dispose" />.
 /// </returns>
 public static IDisposable SubscribeForNotifications <T>(this IList <T> list, NotificationCallbackDelegate <T> callback)
 {
     RealmPCLHelpers.ThrowProxyShouldNeverBeUsed();
     return(null);
 }
Beispiel #21
0
 /// <summary>
 /// A convenience method that casts <see cref="IQueryable{T}"/> to <see cref="IRealmCollection{T}"/> and subscribes for change notifications.
 /// </summary>
 /// <param name="results">The <see cref="IQueryable{T}" /> to observe for changes.</param>
 /// <typeparam name="T">Type of the <see cref="RealmObject"/> in the results.</typeparam>
 /// <seealso cref="IRealmCollection{T}.SubscribeForNotifications"/>
 /// <param name="callback">The callback to be invoked with the updated <see cref="IRealmCollection{T}" />.</param>
 /// <returns>
 /// A subscription token. It must be kept alive for as long as you want to receive change notifications.
 /// To stop receiving notifications, call <see cref="IDisposable.Dispose" />.
 /// </returns>
 public static IDisposable SubscribeForNotifications <T>(this IQueryable <T> results, NotificationCallbackDelegate <T> callback) where T : RealmObject
 {
     RealmPCLHelpers.ThrowProxyShouldNeverBeUsed();
     return(null);
 }
 /// <summary>
 /// A convenience method that casts <see cref="IList{T}" /> to <see cref="IRealmCollection{T}"/> and subscribes for change notifications.
 /// </summary>
 /// <param name="list">The <see cref="IList{T}" /> to observe for changes.</param>
 /// <typeparam name="T">Type of the objects in the list.</typeparam>
 /// <seealso cref="IRealmCollection{T}.SubscribeForNotifications"/>
 /// <param name="callback">The callback to be invoked with the updated <see cref="IRealmCollection{T}" />.</param>
 /// <returns>
 /// A subscription token. It must be kept alive for as long as you want to receive change notifications.
 /// To stop receiving notifications, call <see cref="IDisposable.Dispose" />.
 /// </returns>
 public static IDisposable SubscribeForNotifications <T>(this IList <T> list, NotificationCallbackDelegate <T> callback)
 {
     return(list.AsRealmCollection().SubscribeForNotifications(callback));
 }
 /// <summary>
 /// A convenience method that casts <see cref="IQueryable{T}"/> to <see cref="IRealmCollection{T}"/> and subscribes for change notifications.
 /// </summary>
 /// <param name="results">The <see cref="IQueryable{T}" /> to observe for changes.</param>
 /// <typeparam name="T">Type of the <see cref="RealmObject"/> in the results.</typeparam>
 /// <seealso cref="IRealmCollection{T}.SubscribeForNotifications"/>
 /// <param name="callback">The callback to be invoked with the updated <see cref="IRealmCollection{T}" />.</param>
 /// <returns>
 /// A subscription token. It must be kept alive for as long as you want to receive change notifications.
 /// To stop receiving notifications, call <see cref="IDisposable.Dispose" />.
 /// </returns>
 public static IDisposable SubscribeForNotifications <T>(this IQueryable <T> results, NotificationCallbackDelegate <T> callback) where T : RealmObject
 {
     return(results.AsRealmCollection().SubscribeForNotifications(callback));
 }
 public static extern IntPtr add_notification_callback(ResultsHandle results, IntPtr managedResultsHandle, NotificationCallbackDelegate callback, out NativeException ex);
Beispiel #25
0
 /// <summary>
 /// A convenience method that casts <see cref="ISet{T}"/> to <see cref="IRealmCollection{T}"/> and subscribes for change notifications.
 /// </summary>
 /// <param name="set">The <see cref="ISet{T}"/> to observe for changes.</param>
 /// <typeparam name="T">Type of the elements in the set.</typeparam>
 /// <seealso cref="IRealmCollection{T}.SubscribeForNotifications"/>
 /// <param name="callback">The callback to be invoked with the updated <see cref="IRealmCollection{T}"/>.</param>
 /// <returns>
 /// A subscription token. It must be kept alive for as long as you want to receive change notifications.
 /// To stop receiving notifications, call <see cref="IDisposable.Dispose"/>.
 /// </returns>
 public static IDisposable SubscribeForNotifications <T>(this ISet <T> set, NotificationCallbackDelegate <T> callback) => set.AsRealmCollection().SubscribeForNotifications(callback);
Beispiel #26
0
        /// <summary>
        /// Initializes a new instance of the <see cref="AudioEngine"/> class.
        /// </summary>
        /// <param name="creationFlags">The creation flags.</param>
        /// <param name="settings">Settings for this audio engine</param>
        public AudioEngine(CreationFlags creationFlags, AudioEngineSettings settings)
        {
            bool debug = (creationFlags == CreationFlags.DebugMode);
            bool audition = (creationFlags == CreationFlags.AuditionMode);

            var debugRegistryKey = Registry.LocalMachine.OpenSubKey(DebugEngineRegistryKey);

            // If neither the debug nor audition flags are set, see if the debug registry key is set
            if (!debug && !audition && debugRegistryKey != null)
            {
                var value = debugRegistryKey.GetValue(DebugEngineRegistryValue);

                if (value is Int32 && ((int)value) != 0)
                    debug = true;

                debugRegistryKey.Close();
            }

            var selectedEngineCLSID = (debug) ? DebugEngineGuid : (audition) ? AuditionEngineGuid : EngineGuid;

            Utilities.CreateComInstance(selectedEngineCLSID, Utilities.CLSCTX.ClsctxInprocServer, Utilities.GetGuidFromType(typeof(AudioEngine)), this);

            unsafe
            {
                unmanagedDelegate = new NotificationCallbackDelegate(NotificationCallbackDelegateImpl);
                unmanagedDelegatePointer = Marshal.GetFunctionPointerForDelegate(unmanagedDelegate);
            }

            // Initialize the engine
            PreInitialize(settings);
            Initialize(settings);
        }
Beispiel #27
0
 public void Dispose()
 {
     _collection.UnsubscribeFromNotifications(_callback);
     _callback   = null;
     _collection = null;
 }
Beispiel #28
0
 /// <summary>
 /// A convenience method that casts <see cref="IQueryable{T}"/> to <see cref="IRealmCollection{T}"/> and subscribes for change notifications.
 /// </summary>
 /// <param name="dictionary">The <see cref="IDictionary{String, T}"/> to observe for changes.</param>
 /// <typeparam name="T">Type of the elements in the dictionary.</typeparam>
 /// <seealso cref="IRealmCollection{TValue}.SubscribeForNotifications"/>
 /// <param name="callback">The callback to be invoked with the updated <see cref="IRealmCollection{T}"/>.</param>
 /// <returns>
 /// A subscription token. It must be kept alive for as long as you want to receive change notifications.
 /// To stop receiving notifications, call <see cref="IDisposable.Dispose"/>.
 /// </returns>
 public static IDisposable SubscribeForNotifications <T>(this IDictionary <string, T> dictionary, NotificationCallbackDelegate <KeyValuePair <string, T> > callback)
 {
     return(dictionary.AsRealmCollection().SubscribeForNotifications(callback));
 }
Beispiel #29
0
        public static IDisposable?QueryAsyncWithNotifications <T>(this IRealmCollection <T> collection, NotificationCallbackDelegate <T> callback)
            where T : RealmObjectBase
        {
            // Subscriptions can only work on the main thread.
            if (!ThreadSafety.IsUpdateThread)
            {
                throw new InvalidOperationException("Cannot subscribe for realm notifications from a non-update thread.");
            }

            return(collection.SubscribeForNotifications(callback));
        }
Beispiel #30
0
 internal NotificationToken(RealmCollectionBase <T> collection, NotificationCallbackDelegate <T> callback)
 {
     _collection = collection;
     _callback   = callback;
 }
Beispiel #31
0
        /// <summary>
        /// A convenience method that casts <see cref="IList{T}"/> to <see cref="IRealmCollection{T}"/> and subscribes for change notifications.
        /// </summary>
        /// <remarks>
        /// This adds osu! specific thread and managed state safety checks on top of <see cref="IRealmCollection{T}.SubscribeForNotifications"/>.
        /// </remarks>
        /// <param name="list">The <see cref="IList{T}"/> to observe for changes.</param>
        /// <typeparam name="T">Type of the elements in the list.</typeparam>
        /// <seealso cref="IRealmCollection{T}.SubscribeForNotifications"/>
        /// <param name="callback">The callback to be invoked with the updated <see cref="IRealmCollection{T}"/>.</param>
        /// <returns>
        /// A subscription token. It must be kept alive for as long as you want to receive change notifications.
        /// To stop receiving notifications, call <see cref="IDisposable.Dispose"/>.
        ///
        /// May be null in the case the provided collection is not managed.
        /// </returns>
        public static IDisposable?QueryAsyncWithNotifications <T>(this IList <T> list, NotificationCallbackDelegate <T> callback)
            where T : RealmObjectBase
        {
            // Subscribing to non-managed instances doesn't work.
            // In this usage, the instance may be non-managed in tests.
            if (!(list is IRealmCollection <T> realmCollection))
            {
                return(null);
            }

            return(QueryAsyncWithNotifications(realmCollection, callback));
        }
Beispiel #32
0
        public IDisposable RegisterForNotifications <T>(Func <Realm, IQueryable <T> > query, NotificationCallbackDelegate <T> callback)
            where T : RealmObjectBase
        {
            if (!ThreadSafety.IsUpdateThread)
            {
                throw new InvalidOperationException(@$ "{nameof(RegisterForNotifications)} must be called from the update thread.");
            }

            lock (realmLock)
            {
                Func <Realm, IDisposable?> action = realm => query(realm).QueryAsyncWithNotifications(callback);

                // Store an action which is used when blocking to ensure consumers don't use results of a stale changeset firing.
                notificationsResetMap.Add(action, () => callback(new EmptyRealmSet <T>(), null, null));
                return(RegisterCustomSubscription(action));
            }
        }
Beispiel #33
0
        /// <summary>
        /// Subscribe to a realm collection and begin watching for asynchronous changes.
        /// </summary>
        /// <remarks>
        /// This adds osu! specific thread and managed state safety checks on top of <see cref="IRealmCollection{T}.SubscribeForNotifications"/>.
        ///
        /// In addition to the documented realm behaviour, we have the additional requirement of handling subscriptions over potential realm instance recycle.
        /// When this happens, callback events will be automatically fired:
        /// - On recycle start, a callback with an empty collection and <c>null</c> <see cref="ChangeSet"/> will be invoked.
        /// - On recycle end, a standard initial realm callback will arrive, with <c>null</c> <see cref="ChangeSet"/> and an up-to-date collection.
        /// </remarks>
        /// <param name="query">The <see cref="IQueryable{T}"/> to observe for changes.</param>
        /// <typeparam name="T">Type of the elements in the list.</typeparam>
        /// <param name="callback">The callback to be invoked with the updated <see cref="IRealmCollection{T}"/>.</param>
        /// <returns>
        /// A subscription token. It must be kept alive for as long as you want to receive change notifications.
        /// To stop receiving notifications, call <see cref="IDisposable.Dispose"/>.
        /// </returns>
        /// <seealso cref="IRealmCollection{T}.SubscribeForNotifications"/>
        public IDisposable RegisterForNotifications <T>(Func <Realm, IQueryable <T> > query, NotificationCallbackDelegate <T> callback)
            where T : RealmObjectBase
        {
            lock (realmLock)
            {
                Func <Realm, IDisposable?> action = realm => query(realm).QueryAsyncWithNotifications(callback);

                // Store an action which is used when blocking to ensure consumers don't use results of a stale changeset firing.
                notificationsResetMap.Add(action, () => callback(new EmptyRealmSet <T>(), null, null));
                return(RegisterCustomSubscription(action));
            }
        }
Beispiel #34
0
 public static extern IntPtr add_notification_callback(ListHandle listHandle, IntPtr managedListHandle, NotificationCallbackDelegate callback, out NativeException ex);
 public abstract IntPtr AddNotificationCallback(IntPtr managedCollectionHandle, NotificationCallbackDelegate callback);