From d266bf253acaac6aeb35055ec27fd15cfa268c2f Mon Sep 17 00:00:00 2001 From: "Eunki, Hong" Date: Wed, 18 Dec 2024 13:59:07 +0900 Subject: [PATCH] [NUI] Support RemoveIdle API for NUIApplication + Use unified idler callback Let we keep Idler callback list as membery of internal Application class, and allow to remove them during idler callback execute. TODO : How can we invoke System.Delegate? Signed-off-by: Eunki, Hong --- .../src/internal/Application/Application.cs | 354 +++++++++++------- .../internal/Application/NUICoreBackend.cs | 12 +- .../src/public/Application/NUIApplication.cs | 12 +- 3 files changed, 244 insertions(+), 134 deletions(-) diff --git a/src/Tizen.NUI/src/internal/Application/Application.cs b/src/Tizen.NUI/src/internal/Application/Application.cs index 4d775bc9579..5bb08bb60fd 100755 --- a/src/Tizen.NUI/src/internal/Application/Application.cs +++ b/src/Tizen.NUI/src/internal/Application/Application.cs @@ -1,5 +1,5 @@ /* - * Copyright(c) 2022 Samsung Electronics Co., Ltd. + * Copyright(c) 2024 Samsung Electronics Co., Ltd. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -363,6 +363,44 @@ internal override void OnParentResourcesChanged(IEnumerable idlerCallbackMap = null; + + private void RootIdlerCallback() + { + if (IsDisposedOrQueued) + { + return; + } + + if (idlerCallbackMap == null) + { + return; + } + + // Reset root idler callback as null now, since we could call AddIdle during delegate function invoke + rootIdlerCallback = null; + + // Copy key list of idler callback map + // (Since idler callback could change the dictionary itself during iteration, we need to make a copy of keys first) + var delegateList = idlerCallbackMap.Keys; + foreach (var func in delegateList) + { + // Remove delegate at map first, and then invoke it. + bool isValid = false; + if (idlerCallbackMap?.Remove(func, out isValid) ?? false) + { + if (isValid) + { + func(); + } + } + } + } + internal Application(global::System.IntPtr cPtr, bool cMemoryOwn) : base(cPtr, cMemoryOwn) { SetCurrentApplication(this); @@ -376,145 +414,148 @@ protected override void Dispose(DisposeTypes type) return; } - //Release your own unmanaged resources here. - //You should not access any managed member here except static instance. - //because the execution order of Finalizes is non-deterministic. - if (applicationInitEventCallbackDelegate != null) + if (type == DisposeTypes.Explicit) { - initSignal?.Disconnect(applicationInitEventCallbackDelegate); - initSignal?.Dispose(); - initSignal = null; - } + //Release your own unmanaged resources here. + //You should not access any managed member here except static instance. + //because the execution order of Finalizes is non-deterministic. + if (applicationInitEventCallbackDelegate != null) + { + initSignal?.Disconnect(applicationInitEventCallbackDelegate); + initSignal?.Dispose(); + initSignal = null; + } - if (applicationTerminateEventCallbackDelegate != null) - { - terminateSignal?.Disconnect(applicationTerminateEventCallbackDelegate); - terminateSignal?.Dispose(); - terminateSignal = null; - } + if (applicationTerminateEventCallbackDelegate != null) + { + terminateSignal?.Disconnect(applicationTerminateEventCallbackDelegate); + terminateSignal?.Dispose(); + terminateSignal = null; + } - if (applicationPauseEventCallbackDelegate != null) - { - pauseSignal?.Disconnect(applicationPauseEventCallbackDelegate); - pauseSignal?.Dispose(); - pauseSignal = null; - } + if (applicationPauseEventCallbackDelegate != null) + { + pauseSignal?.Disconnect(applicationPauseEventCallbackDelegate); + pauseSignal?.Dispose(); + pauseSignal = null; + } - if (applicationResumeEventCallbackDelegate != null) - { - resumeSignal?.Disconnect(applicationResumeEventCallbackDelegate); - resumeSignal?.Dispose(); - resumeSignal = null; - } + if (applicationResumeEventCallbackDelegate != null) + { + resumeSignal?.Disconnect(applicationResumeEventCallbackDelegate); + resumeSignal?.Dispose(); + resumeSignal = null; + } - if (applicationResetEventCallbackDelegate != null) - { - resetSignal?.Disconnect(applicationResetEventCallbackDelegate); - resetSignal?.Dispose(); - resetSignal = null; - } + if (applicationResetEventCallbackDelegate != null) + { + resetSignal?.Disconnect(applicationResetEventCallbackDelegate); + resetSignal?.Dispose(); + resetSignal = null; + } - if (applicationLanguageChangedEventCallbackDelegate != null) - { - languageChangedSignal?.Disconnect(applicationLanguageChangedEventCallbackDelegate); - languageChangedSignal?.Dispose(); - languageChangedSignal = null; - } + if (applicationLanguageChangedEventCallbackDelegate != null) + { + languageChangedSignal?.Disconnect(applicationLanguageChangedEventCallbackDelegate); + languageChangedSignal?.Dispose(); + languageChangedSignal = null; + } - if (applicationRegionChangedEventCallbackDelegate != null) - { - regionChangedSignal?.Disconnect(applicationRegionChangedEventCallbackDelegate); - regionChangedSignal?.Dispose(); - regionChangedSignal = null; - } + if (applicationRegionChangedEventCallbackDelegate != null) + { + regionChangedSignal?.Disconnect(applicationRegionChangedEventCallbackDelegate); + regionChangedSignal?.Dispose(); + regionChangedSignal = null; + } - if (applicationBatteryLowEventCallbackDelegate != null) - { - batteryLowSignal?.Disconnect(applicationBatteryLowEventCallbackDelegate); - batteryLowSignal?.Dispose(); - batteryLowSignal = null; - } + if (applicationBatteryLowEventCallbackDelegate != null) + { + batteryLowSignal?.Disconnect(applicationBatteryLowEventCallbackDelegate); + batteryLowSignal?.Dispose(); + batteryLowSignal = null; + } - if (applicationMemoryLowEventCallbackDelegate != null) - { - memoryLowSignal?.Disconnect(applicationMemoryLowEventCallbackDelegate); - memoryLowSignal?.Dispose(); - memoryLowSignal = null; - } + if (applicationMemoryLowEventCallbackDelegate != null) + { + memoryLowSignal?.Disconnect(applicationMemoryLowEventCallbackDelegate); + memoryLowSignal?.Dispose(); + memoryLowSignal = null; + } - if (applicationDeviceOrientationChangedEventCallback != null) - { - deviceOrientationChangedSignal?.Disconnect(applicationDeviceOrientationChangedEventCallback); - deviceOrientationChangedSignal?.Dispose(); - deviceOrientationChangedSignal = null; - } + if (applicationDeviceOrientationChangedEventCallback != null) + { + deviceOrientationChangedSignal?.Disconnect(applicationDeviceOrientationChangedEventCallback); + deviceOrientationChangedSignal?.Dispose(); + deviceOrientationChangedSignal = null; + } - if (applicationAppControlEventCallbackDelegate != null) - { - appControlSignal?.Disconnect(applicationAppControlEventCallbackDelegate); - appControlSignal?.Dispose(); - appControlSignal = null; - } + if (applicationAppControlEventCallbackDelegate != null) + { + appControlSignal?.Disconnect(applicationAppControlEventCallbackDelegate); + appControlSignal?.Dispose(); + appControlSignal = null; + } - //Task - if (applicationTaskInitEventCallbackDelegate != null) - { - taskInitSignal?.Disconnect(applicationTaskInitEventCallbackDelegate); - taskInitSignal?.Dispose(); - taskInitSignal = null; - } + //Task + if (applicationTaskInitEventCallbackDelegate != null) + { + taskInitSignal?.Disconnect(applicationTaskInitEventCallbackDelegate); + taskInitSignal?.Dispose(); + taskInitSignal = null; + } - if (applicationTaskTerminateEventCallbackDelegate != null) - { - taskTerminateSignal?.Disconnect(applicationTaskTerminateEventCallbackDelegate); - taskTerminateSignal?.Dispose(); - taskTerminateSignal = null; - } + if (applicationTaskTerminateEventCallbackDelegate != null) + { + taskTerminateSignal?.Disconnect(applicationTaskTerminateEventCallbackDelegate); + taskTerminateSignal?.Dispose(); + taskTerminateSignal = null; + } - if (applicationTaskLanguageChangedEventCallbackDelegate != null) - { - taskLanguageChangedSignal?.Disconnect(applicationTaskLanguageChangedEventCallbackDelegate); - taskLanguageChangedSignal?.Dispose(); - taskLanguageChangedSignal = null; - } + if (applicationTaskLanguageChangedEventCallbackDelegate != null) + { + taskLanguageChangedSignal?.Disconnect(applicationTaskLanguageChangedEventCallbackDelegate); + taskLanguageChangedSignal?.Dispose(); + taskLanguageChangedSignal = null; + } - if (applicationTaskRegionChangedEventCallbackDelegate != null) - { - taskRegionChangedSignal?.Disconnect(applicationTaskRegionChangedEventCallbackDelegate); - taskRegionChangedSignal?.Dispose(); - taskRegionChangedSignal = null; - } + if (applicationTaskRegionChangedEventCallbackDelegate != null) + { + taskRegionChangedSignal?.Disconnect(applicationTaskRegionChangedEventCallbackDelegate); + taskRegionChangedSignal?.Dispose(); + taskRegionChangedSignal = null; + } - if (applicationTaskBatteryLowEventCallbackDelegate != null) - { - taskBatteryLowSignal?.Disconnect(applicationTaskBatteryLowEventCallbackDelegate); - taskBatteryLowSignal?.Dispose(); - taskBatteryLowSignal = null; - } + if (applicationTaskBatteryLowEventCallbackDelegate != null) + { + taskBatteryLowSignal?.Disconnect(applicationTaskBatteryLowEventCallbackDelegate); + taskBatteryLowSignal?.Dispose(); + taskBatteryLowSignal = null; + } - if (applicationTaskMemoryLowEventCallbackDelegate != null) - { - taskMemoryLowSignal?.Disconnect(applicationTaskMemoryLowEventCallbackDelegate); - taskMemoryLowSignal?.Dispose(); - taskMemoryLowSignal = null; - } + if (applicationTaskMemoryLowEventCallbackDelegate != null) + { + taskMemoryLowSignal?.Disconnect(applicationTaskMemoryLowEventCallbackDelegate); + taskMemoryLowSignal?.Dispose(); + taskMemoryLowSignal = null; + } - if (applicationTaskDeviceOrientationChangedEventCallback != null) - { - taskDeviceOrientationChangedSignal?.Disconnect(applicationTaskDeviceOrientationChangedEventCallback); - taskDeviceOrientationChangedSignal?.Dispose(); - taskDeviceOrientationChangedSignal = null; - } + if (applicationTaskDeviceOrientationChangedEventCallback != null) + { + taskDeviceOrientationChangedSignal?.Disconnect(applicationTaskDeviceOrientationChangedEventCallback); + taskDeviceOrientationChangedSignal?.Dispose(); + taskDeviceOrientationChangedSignal = null; + } - if (applicationTaskAppControlEventCallbackDelegate != null) - { - taskAppControlSignal?.Disconnect(applicationTaskAppControlEventCallbackDelegate); - taskAppControlSignal?.Dispose(); - taskAppControlSignal = null; - } + if (applicationTaskAppControlEventCallbackDelegate != null) + { + taskAppControlSignal?.Disconnect(applicationTaskAppControlEventCallbackDelegate); + taskAppControlSignal?.Dispose(); + taskAppControlSignal = null; + } - window?.Dispose(); - window = null; + window?.Dispose(); + window = null; + } base.Dispose(type); } @@ -1721,13 +1762,69 @@ public static Application NewApplication(string[] args, string stylesheet, bool /// public bool AddIdle(System.Delegate func) { - System.IntPtr ip = System.Runtime.InteropServices.Marshal.GetFunctionPointerForDelegate(func); - System.IntPtr ip2 = Interop.Application.MakeCallback(new System.Runtime.InteropServices.HandleRef(this, ip)); + bool idlerAdded = false; // default value is false - bool ret = Interop.Application.AddIdle(SwigCPtr, new System.Runtime.InteropServices.HandleRef(this, ip2)); + // Register root idler callback for Tizen.NUI.Application + if (rootIdlerCallback == null) + { + rootIdlerCallback = RootIdlerCallback; + System.IntPtr ip = System.Runtime.InteropServices.Marshal.GetFunctionPointerForDelegate(rootIdlerCallback); + System.IntPtr ip2 = Interop.Application.MakeCallback(new System.Runtime.InteropServices.HandleRef(this, ip)); - if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve(); - return ret; + bool ret = Interop.Application.AddIdle(SwigCPtr, new System.Runtime.InteropServices.HandleRef(this, ip2)); + NDalicPINVOKE.ThrowExceptionIfExists(); + if (!ret) + { + rootIdlerCallback = null; + Tizen.Log.Error("NUI", $"[Error] failed to add idler {func}"); + return false; + } + } + + if (idlerCallbackMap == null) + { + idlerCallbackMap = new Dictionary(); + } + + if (idlerCallbackMap.TryGetValue(func, out bool isValid)) + { + idlerAdded = true; // success case + if (!isValid) + { + idlerCallbackMap[func] = true; + } + } + else if (idlerCallbackMap.TryAdd(func, true)) + { + idlerAdded = true; // success case + } + + if (!idlerAdded) + { + Tizen.Log.Error("NUI", $"[Error] failed to add idler {func}\n"); + } + + return idlerAdded; + } + + /// + /// Remove delegate what we added by AddIdle. + /// + /// The function to remove + [EditorBrowsable(EditorBrowsableState.Never)] + public void RemoveIdle(System.Delegate func) + { + if (idlerCallbackMap == null) + { + return; + } + if (idlerCallbackMap.TryGetValue(func, out bool isValid)) + { + if (isValid) + { + idlerCallbackMap[func] = false; + } + } } /** @@ -1925,13 +2022,6 @@ public void Quit() if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve(); } - internal bool AddIdle(SWIGTYPE_p_Dali__CallbackBase callback) - { - bool ret = Interop.Application.AddIdle(SwigCPtr, SWIGTYPE_p_Dali__CallbackBase.getCPtr(callback)); - if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve(); - return ret; - } - public Window GetWindow() { if (window != null) diff --git a/src/Tizen.NUI/src/internal/Application/NUICoreBackend.cs b/src/Tizen.NUI/src/internal/Application/NUICoreBackend.cs index e736eba1259..bc79963932b 100755 --- a/src/Tizen.NUI/src/internal/Application/NUICoreBackend.cs +++ b/src/Tizen.NUI/src/internal/Application/NUICoreBackend.cs @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018 Samsung Electronics Co., Ltd. + * Copyright (c) 2024 Samsung Electronics Co., Ltd. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -158,6 +158,16 @@ public bool AddIdle(System.Delegate func) return application.AddIdle(func); } + /// + /// Remove delegate what we added by AddIdle. + /// + /// The function to remove + [EditorBrowsable(EditorBrowsableState.Never)] + public void RemoveIdle(System.Delegate func) + { + application.RemoveIdle(func); + } + /// /// The Run application. /// diff --git a/src/Tizen.NUI/src/public/Application/NUIApplication.cs b/src/Tizen.NUI/src/public/Application/NUIApplication.cs index ac178056c5f..b63fab53542 100755 --- a/src/Tizen.NUI/src/public/Application/NUIApplication.cs +++ b/src/Tizen.NUI/src/public/Application/NUIApplication.cs @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021 Samsung Electronics Co., Ltd. + * Copyright (c) 2024 Samsung Electronics Co., Ltd. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -547,6 +547,16 @@ public bool AddIdle(System.Delegate func) return ((NUICoreBackend)this.Backend).AddIdle(func); } + /// + /// Remove delegate what we added by AddIdle. + /// + /// The function to remove + [EditorBrowsable(EditorBrowsableState.Never)] + public void RemoveIdle(System.Delegate func) + { + ((NUICoreBackend)this.Backend).RemoveIdle(func); + } + /// /// Flush render/update thread messages synchronously. ///