Skip to content

Commit

Permalink
[NUI] Make InputMethodContext's signal callbacks not collected
Browse files Browse the repository at this point in the history
This PR makes InputMethodContext's signal callbacks not collected before
native InputMethodContext gone.

Unlike other classes, InputMethodContext's callbacks are not removed
from the static dictionary until it is disposed.
Because eventReceivedEventCallback is called from unmanaged code
although it is disconnected.
  • Loading branch information
Jaehyun-Cho authored and jaehyun0cho committed Feb 7, 2025
1 parent f043fc7 commit 50db232
Showing 1 changed file with 53 additions and 9 deletions.
62 changes: 53 additions & 9 deletions src/Tizen.NUI/src/public/Input/InputMethodContext.cs
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ public event EventHandler<ActivatedEventArgs> Activated
{
if (activatedEventHandler == null)
{
activatedEventCallback = OnActivated;
CreateSafeCallback(OnActivated, out activatedEventCallback);
ActivatedSignal().Connect(activatedEventCallback);
}

Expand All @@ -90,6 +90,7 @@ public event EventHandler<ActivatedEventArgs> Activated
if (activatedEventHandler == null && activatedEventCallback != null)
{
ActivatedSignal().Disconnect(activatedEventCallback);
ReleaseSafeCallback(ref activatedEventCallback);
}
}
}
Expand All @@ -104,7 +105,7 @@ public event EventHandlerWithReturnType<object, EventReceivedEventArgs, Callback
{
if (eventReceivedEventHandler == null)
{
eventReceivedEventCallback = OnEventReceived;
CreateSafeCallback(OnEventReceived, out eventReceivedEventCallback);
EventReceivedSignal().Connect(eventReceivedEventCallback);
}

Expand All @@ -117,6 +118,7 @@ public event EventHandlerWithReturnType<object, EventReceivedEventArgs, Callback
if (eventReceivedEventHandler == null && eventReceivedEventCallback != null)
{
EventReceivedSignal().Disconnect(eventReceivedEventCallback);
ReleaseSafeCallback(ref eventReceivedEventCallback);
}
}
}
Expand All @@ -131,7 +133,7 @@ public event EventHandler<StatusChangedEventArgs> StatusChanged
{
if (statusChangedEventHandler == null)
{
statusChangedEventCallback = OnStatusChanged;
CreateSafeCallback(OnStatusChanged, out statusChangedEventCallback);
StatusChangedSignal().Connect(statusChangedEventCallback);
}

Expand All @@ -144,6 +146,7 @@ public event EventHandler<StatusChangedEventArgs> StatusChanged
if (statusChangedEventHandler == null && statusChangedEventCallback != null)
{
StatusChangedSignal().Disconnect(statusChangedEventCallback);
ReleaseSafeCallback(ref statusChangedEventCallback);
}
}
}
Expand All @@ -158,7 +161,7 @@ public event EventHandler<ResizedEventArgs> Resized
{
if (resizedEventHandler == null)
{
resizedEventCallback = OnResized;
CreateSafeCallback(OnResized, out resizedEventCallback);
ResizedSignal().Connect(resizedEventCallback);
}

Expand All @@ -171,6 +174,7 @@ public event EventHandler<ResizedEventArgs> Resized
if (resizedEventHandler == null && resizedEventCallback != null)
{
ResizedSignal().Disconnect(resizedEventCallback);
ReleaseSafeCallback(ref resizedEventCallback);
}
}
}
Expand All @@ -185,7 +189,7 @@ public event EventHandler<LanguageChangedEventArgs> LanguageChanged
{
if (languageChangedEventHandler == null)
{
languageChangedEventCallback = OnLanguageChanged;
CreateSafeCallback(OnLanguageChanged, out languageChangedEventCallback);
LanguageChangedSignal().Connect(languageChangedEventCallback);
}

Expand All @@ -198,6 +202,7 @@ public event EventHandler<LanguageChangedEventArgs> LanguageChanged
if (languageChangedEventHandler == null && languageChangedEventCallback != null)
{
LanguageChangedSignal().Disconnect(languageChangedEventCallback);
ReleaseSafeCallback(ref languageChangedEventCallback);
}
}
}
Expand All @@ -212,7 +217,7 @@ public event EventHandler<KeyboardTypeChangedEventArgs> KeyboardTypeChanged
{
if (keyboardTypeChangedEventHandler == null)
{
keyboardTypeChangedEventCallback = OnKeyboardTypeChanged;
CreateSafeCallback(OnKeyboardTypeChanged, out keyboardTypeChangedEventCallback);
KeyboardTypeChangedSignal().Connect(keyboardTypeChangedEventCallback);
}

Expand All @@ -225,6 +230,7 @@ public event EventHandler<KeyboardTypeChangedEventArgs> KeyboardTypeChanged
if (keyboardTypeChangedEventHandler == null && keyboardTypeChangedEventCallback != null)
{
KeyboardTypeChangedSignal().Disconnect(keyboardTypeChangedEventCallback);
ReleaseSafeCallback(ref keyboardTypeChangedEventCallback);
}
}
}
Expand All @@ -240,7 +246,7 @@ public event EventHandler<ContentReceivedEventArgs> ContentReceived
{
if (contentReceivedEventHandler == null)
{
contentReceivedEventCallback = OnContentReceived;
CreateSafeCallback(OnContentReceived, out contentReceivedEventCallback);
ContentReceivedSignal().Connect(contentReceivedEventCallback);
}

Expand All @@ -253,6 +259,7 @@ public event EventHandler<ContentReceivedEventArgs> ContentReceived
if (contentReceivedEventHandler == null && contentReceivedEventCallback != null)
{
ContentReceivedSignal().Disconnect(contentReceivedEventCallback);
ReleaseSafeCallback(ref contentReceivedEventCallback);
}
}
}
Expand Down Expand Up @@ -880,42 +887,63 @@ protected override void Dispose(DisposeTypes type)
//You should not access any managed member here except static instance
//because the execution order of Finalizes is non-deterministic.

if (type == DisposeTypes.Explicit)
{
DisconnectNativeSignals();
}

base.Dispose(type);
}

private void DisconnectNativeSignals()
{
if (HasBody() == false)
{
NUILog.Debug($"[Dispose] DisConnectFromSignals() No native body! No need to Disconnect Signals!");
return;
}

if (activatedEventCallback != null)
{
ActivatedSignal().Disconnect(activatedEventCallback);
activatedEventCallback = null;
}

if (eventReceivedEventCallback != null)
{
EventReceivedSignal().Disconnect(eventReceivedEventCallback);
eventReceivedEventCallback = null;
}

if (statusChangedEventCallback != null)
{
StatusChangedSignal().Disconnect(statusChangedEventCallback);
statusChangedEventCallback = null;
}

if (resizedEventCallback != null)
{
ResizedSignal().Disconnect(resizedEventCallback);
resizedEventCallback = null;
}

if (languageChangedEventCallback != null)
{
LanguageChangedSignal().Disconnect(languageChangedEventCallback);
languageChangedEventCallback = null;
}

if (keyboardTypeChangedEventCallback != null)
{
KeyboardTypeChangedSignal().Disconnect(keyboardTypeChangedEventCallback);
keyboardTypeChangedEventCallback = null;
}

if (contentReceivedEventCallback != null)
{
ContentReceivedSignal().Disconnect(contentReceivedEventCallback);
contentReceivedEventCallback = null;
}

base.Dispose(type);
}

/// This will not be public opened.
Expand Down Expand Up @@ -1070,6 +1098,22 @@ private void OnContentReceived(string content, string description, string mimeTy
}
}

void CreateSafeCallback<T>(T method, out T safeCallback) where T : Delegate
{
AddToNativeHolder(method);
safeCallback = method;
}

void ReleaseSafeCallback<T>(ref T safeCallback) where T : Delegate
{
System.Diagnostics.Debug.Assert(safeCallback != null);
// FIXME: If eventReceivedEventCallback is removed from nativeholder,
// then it is called from unmanaged code although it is disconnected.
// So the callbacks are not removed from nativeholder until dispose.
// RemoveFromNativeHolder(safeCallback);
safeCallback = null;
}

/// <summary>
/// This structure is used to pass on data from the IMF regarding predictive text.
/// </summary>
Expand Down

0 comments on commit 50db232

Please sign in to comment.