From 401f7bbd4d6a1a4b7a75b3416a892f5136d99b30 Mon Sep 17 00:00:00 2001 From: "Eunki, Hong" Date: Tue, 19 Nov 2024 11:28:46 +0900 Subject: [PATCH] Block native callback if view is disposed or disposing Signed-off-by: Eunki, Hong --- .../src/public/BaseComponents/ImageView.cs | 12 +++ .../public/BaseComponents/TextEditorEvent.cs | 54 ++++++++++ .../public/BaseComponents/TextFieldEvent.cs | 48 +++++++++ .../public/BaseComponents/TextLabelEvent.cs | 30 ++++++ .../src/public/BaseComponents/ViewEvent.cs | 102 ++++++++++++++++++ 5 files changed, 246 insertions(+) diff --git a/src/Tizen.NUI/src/public/BaseComponents/ImageView.cs b/src/Tizen.NUI/src/public/BaseComponents/ImageView.cs index eee70c3c20b..90023161c5a 100755 --- a/src/Tizen.NUI/src/public/BaseComponents/ImageView.cs +++ b/src/Tizen.NUI/src/public/BaseComponents/ImageView.cs @@ -2007,6 +2007,12 @@ protected override void ReleaseSwigCPtr(System.Runtime.InteropServices.HandleRef // Callback for View ResourceReady signal private void OnResourceReady(IntPtr data) { + if (Disposed || IsDisposeQueued) + { + // Ignore native callback if the view is disposed or queued for disposal. + return; + } + if (!CheckResourceReady()) { return; @@ -2381,6 +2387,12 @@ protected override bool CheckResourceReady() private void OnResourceLoaded(IntPtr view) { + if (Disposed || IsDisposeQueued) + { + // Ignore native callback if the view is disposed or queued for disposal. + return; + } + if (!CheckResourceReady()) { return; diff --git a/src/Tizen.NUI/src/public/BaseComponents/TextEditorEvent.cs b/src/Tizen.NUI/src/public/BaseComponents/TextEditorEvent.cs index dea6e2d8563..7e3b554943b 100755 --- a/src/Tizen.NUI/src/public/BaseComponents/TextEditorEvent.cs +++ b/src/Tizen.NUI/src/public/BaseComponents/TextEditorEvent.cs @@ -395,6 +395,12 @@ internal TextEditorSignal InputFilteredSignal() private void OnTextChanged(IntPtr textEditor) { + if (Disposed || IsDisposeQueued) + { + // Ignore native callback if the view is disposed or queued for disposal. + return; + } + if (textEditorTextChangedEventHandler != null && invokeTextChanged) { TextChangedEventArgs e = new TextChangedEventArgs(); @@ -408,18 +414,36 @@ private void OnTextChanged(IntPtr textEditor) private void OnSelectionStarted(IntPtr textEditor) { + if (Disposed || IsDisposeQueued) + { + // Ignore native callback if the view is disposed or queued for disposal. + return; + } + //no data to be sent to the user textEditorSelectionStartedEventHandler?.Invoke(this, EventArgs.Empty); } private void OnSelectionCleared(IntPtr textEditor) { + if (Disposed || IsDisposeQueued) + { + // Ignore native callback if the view is disposed or queued for disposal. + return; + } + //no data to be sent to the user textEditorSelectionClearedEventHandler?.Invoke(this, EventArgs.Empty); } private void OnScrollStateChanged(IntPtr textEditor, ScrollState state) { + if (Disposed || IsDisposeQueued) + { + // Ignore native callback if the view is disposed or queued for disposal. + return; + } + if (textEditorScrollStateChangedEventHandler != null) { ScrollStateChangedEventArgs e = new ScrollStateChangedEventArgs(); @@ -437,12 +461,24 @@ private void OnScrollStateChanged(IntPtr textEditor, ScrollState state) private void OnCursorPositionChanged(IntPtr textEditor, uint oldPosition) { + if (Disposed || IsDisposeQueued) + { + // Ignore native callback if the view is disposed or queued for disposal. + return; + } + // no data to be sent to the user, as in NUI there is no event provide old values. textEditorCursorPositionChangedEventHandler?.Invoke(this, EventArgs.Empty); } private void OnMaxLengthReached(IntPtr textEditor) { + if (Disposed || IsDisposeQueued) + { + // Ignore native callback if the view is disposed or queued for disposal. + return; + } + if (textEditorMaxLengthReachedEventHandler != null) { MaxLengthReachedEventArgs e = new MaxLengthReachedEventArgs(); @@ -456,6 +492,12 @@ private void OnMaxLengthReached(IntPtr textEditor) private void OnAnchorClicked(IntPtr textEditor, IntPtr href, uint hrefLength) { + if (Disposed || IsDisposeQueued) + { + // Ignore native callback if the view is disposed or queued for disposal. + return; + } + // Note: hrefLength is useful for get the length of a const char* (href) in dali-toolkit. // But NUI can get the length of string (href), so hrefLength is not necessary in NUI. AnchorClickedEventArgs e = new AnchorClickedEventArgs(); @@ -468,12 +510,24 @@ private void OnAnchorClicked(IntPtr textEditor, IntPtr href, uint hrefLength) private void OnSelectionChanged(IntPtr textEditor, uint oldStart, uint oldEnd) { + if (Disposed || IsDisposeQueued) + { + // Ignore native callback if the view is disposed or queued for disposal. + return; + } + // no data to be sent to the user, as in NUI there is no event provide old values. textEditorSelectionChangedEventHandler?.Invoke(this, EventArgs.Empty); } private void OnInputFiltered(IntPtr textEditor, InputFilterType type) { + if (Disposed || IsDisposeQueued) + { + // Ignore native callback if the view is disposed or queued for disposal. + return; + } + InputFilteredEventArgs e = new InputFilteredEventArgs(); // Populate all members of "e" (InputFilteredEventArgs) with real data diff --git a/src/Tizen.NUI/src/public/BaseComponents/TextFieldEvent.cs b/src/Tizen.NUI/src/public/BaseComponents/TextFieldEvent.cs index 54ad326ffbe..9d5ff072d75 100755 --- a/src/Tizen.NUI/src/public/BaseComponents/TextFieldEvent.cs +++ b/src/Tizen.NUI/src/public/BaseComponents/TextFieldEvent.cs @@ -350,18 +350,36 @@ internal TextFieldSignal InputFilteredSignal() private void OnSelectionStarted(IntPtr textField) { + if (Disposed || IsDisposeQueued) + { + // Ignore native callback if the view is disposed or queued for disposal. + return; + } + //no data to be sent to the user textFieldSelectionStartedEventHandler?.Invoke(this, EventArgs.Empty); } private void OnSelectionCleared(IntPtr textField) { + if (Disposed || IsDisposeQueued) + { + // Ignore native callback if the view is disposed or queued for disposal. + return; + } + //no data to be sent to the user textFieldSelectionClearedEventHandler?.Invoke(this, EventArgs.Empty); } private void OnTextChanged(IntPtr textField) { + if (Disposed || IsDisposeQueued) + { + // Ignore native callback if the view is disposed or queued for disposal. + return; + } + if (textFieldTextChangedEventHandler != null && invokeTextChanged) { TextChangedEventArgs e = new TextChangedEventArgs(); @@ -375,12 +393,24 @@ private void OnTextChanged(IntPtr textField) private void OnCursorPositionChanged(IntPtr textField, uint oldPosition) { + if (Disposed || IsDisposeQueued) + { + // Ignore native callback if the view is disposed or queued for disposal. + return; + } + // no data to be sent to the user, as in NUI there is no event provide old values. textFieldCursorPositionChangedEventHandler?.Invoke(this, EventArgs.Empty); } private void OnMaxLengthReached(IntPtr textField) { + if (Disposed || IsDisposeQueued) + { + // Ignore native callback if the view is disposed or queued for disposal. + return; + } + if (textFieldMaxLengthReachedEventHandler != null) { MaxLengthReachedEventArgs e = new MaxLengthReachedEventArgs(); @@ -394,6 +424,12 @@ private void OnMaxLengthReached(IntPtr textField) private void OnAnchorClicked(IntPtr textField, IntPtr href, uint hrefLength) { + if (Disposed || IsDisposeQueued) + { + // Ignore native callback if the view is disposed or queued for disposal. + return; + } + // Note: hrefLength is useful for get the length of a const char* (href) in dali-toolkit. // But NUI can get the length of string (href), so hrefLength is not necessary in NUI. AnchorClickedEventArgs e = new AnchorClickedEventArgs(); @@ -406,12 +442,24 @@ private void OnAnchorClicked(IntPtr textField, IntPtr href, uint hrefLength) private void OnSelectionChanged(IntPtr textField, uint oldStart, uint oldEnd) { + if (Disposed || IsDisposeQueued) + { + // Ignore native callback if the view is disposed or queued for disposal. + return; + } + // no data to be sent to the user, as in NUI there is no event provide old values. textFieldSelectionChangedEventHandler?.Invoke(this, EventArgs.Empty); } private void OnInputFiltered(IntPtr textField, InputFilterType type) { + if (Disposed || IsDisposeQueued) + { + // Ignore native callback if the view is disposed or queued for disposal. + return; + } + InputFilteredEventArgs e = new InputFilteredEventArgs(); // Populate all members of "e" (InputFilteredEventArgs) with real data diff --git a/src/Tizen.NUI/src/public/BaseComponents/TextLabelEvent.cs b/src/Tizen.NUI/src/public/BaseComponents/TextLabelEvent.cs index 4f98707499c..86ad557d528 100644 --- a/src/Tizen.NUI/src/public/BaseComponents/TextLabelEvent.cs +++ b/src/Tizen.NUI/src/public/BaseComponents/TextLabelEvent.cs @@ -90,6 +90,12 @@ public event EventHandler AsyncHeightForWidthCom private void OnAsyncHeightForWidthComputed(IntPtr textLabel, float width, float height) { + if (Disposed || IsDisposeQueued) + { + // Ignore native callback if the view is disposed or queued for disposal. + return; + } + AsyncTextSizeComputedEventArgs e = new AsyncTextSizeComputedEventArgs(width, height); if (textLabelAsyncHeightForWidthComputedEventHandler != null) @@ -128,6 +134,12 @@ public event EventHandler AsyncNaturalSizeComput private void OnAsyncNaturalSizeComputed(IntPtr textLabel, float width, float height) { + if (Disposed || IsDisposeQueued) + { + // Ignore native callback if the view is disposed or queued for disposal. + return; + } + AsyncTextSizeComputedEventArgs e = new AsyncTextSizeComputedEventArgs(width, height); if (textLabelAsyncNaturalSizeComputedEventHandler != null) @@ -166,6 +178,12 @@ public event EventHandler AsyncTextRendered private void OnAsyncTextRendered(IntPtr textLabel, float width, float height) { + if (Disposed || IsDisposeQueued) + { + // Ignore native callback if the view is disposed or queued for disposal. + return; + } + AsyncTextRenderedEventArgs e = new AsyncTextRenderedEventArgs(width, height); if (textLabelAsyncTextRenderedEventHandler != null) @@ -208,6 +226,12 @@ internal TextLabelSignal AnchorClickedSignal() private void OnAnchorClicked(IntPtr textLabel, IntPtr href, uint hrefLength) { + if (Disposed || IsDisposeQueued) + { + // Ignore native callback if the view is disposed or queued for disposal. + return; + } + // Note: hrefLength is useful for get the length of a const char* (href) in dali-toolkit. // But NUI can get the length of string (href), so hrefLength is not necessary in NUI. AnchorClickedEventArgs e = new AnchorClickedEventArgs(); @@ -253,6 +277,12 @@ internal TextLabelSignal TextFitChangedSignal() private void OnTextFitChanged(IntPtr textLabel) { + if (Disposed || IsDisposeQueued) + { + // Ignore native callback if the view is disposed or queued for disposal. + return; + } + // no data to be sent to the user, as in NUI there is no event provide old values. textLabelTextFitChangedEventHandler?.Invoke(this, EventArgs.Empty); } diff --git a/src/Tizen.NUI/src/public/BaseComponents/ViewEvent.cs b/src/Tizen.NUI/src/public/BaseComponents/ViewEvent.cs index a8f254e671c..d635edb9f84 100755 --- a/src/Tizen.NUI/src/public/BaseComponents/ViewEvent.cs +++ b/src/Tizen.NUI/src/public/BaseComponents/ViewEvent.cs @@ -751,6 +751,12 @@ private void OnBackgroundImageBorderChanged(int left, int right, int bottom, int private void OnKeyInputFocusGained(IntPtr view) { + if (Disposed || IsDisposeQueued) + { + // Ignore native callback if the view is disposed or queued for disposal. + return; + } + if (IsNativeHandleInvalid()) { if (this.Disposed) @@ -789,6 +795,12 @@ private void OnKeyInputFocusGained(IntPtr view) private void OnKeyInputFocusLost(IntPtr view) { + if (Disposed || IsDisposeQueued) + { + // Ignore native callback if the view is disposed or queued for disposal. + return; + } + if (IsNativeHandleInvalid()) { if (this.Disposed) @@ -827,6 +839,12 @@ private void OnKeyInputFocusLost(IntPtr view) private bool OnKeyEvent(IntPtr view, IntPtr keyEvent) { + if (Disposed || IsDisposeQueued) + { + // Ignore native callback if the view is disposed or queued for disposal. + return false; + } + if (keyEvent == global::System.IntPtr.Zero) { NUILog.Error("keyEvent should not be null!"); @@ -856,6 +874,12 @@ private bool OnKeyEvent(IntPtr view, IntPtr keyEvent) // Callback for View OnRelayout signal private void OnRelayout(IntPtr data) { + if (Disposed || IsDisposeQueued) + { + // Ignore native callback if the view is disposed or queued for disposal. + return; + } + if (onRelayoutEventHandler != null) { onRelayoutEventHandler(this, null); @@ -865,6 +889,12 @@ private void OnRelayout(IntPtr data) // Callback for View HitTestResultSignal private bool OnHitTestResult(IntPtr view, IntPtr touchData) { + if (Disposed || IsDisposeQueued) + { + // Ignore native callback if the view is disposed or queued for disposal. + return false; + } + if (touchData == global::System.IntPtr.Zero) { NUILog.Error("touchData should not be null!"); @@ -879,6 +909,12 @@ private bool OnHitTestResult(IntPtr view, IntPtr touchData) // Callback for View TouchSignal private bool OnInterceptTouch(IntPtr view, IntPtr touchData) { + if (Disposed || IsDisposeQueued) + { + // Ignore native callback if the view is disposed or queued for disposal. + return false; + } + if (touchData == global::System.IntPtr.Zero) { NUILog.Error("touchData should not be null!"); @@ -919,6 +955,12 @@ private bool OnInterceptTouch(IntPtr view, IntPtr touchData) // Callback for View TouchSignal private bool OnTouch(IntPtr view, IntPtr touchData) { + if (Disposed || IsDisposeQueued) + { + // Ignore native callback if the view is disposed or queued for disposal. + return false; + } + if (touchData == global::System.IntPtr.Zero) { NUILog.Error("touchData should not be null!"); @@ -970,6 +1012,12 @@ private bool OnTouch(IntPtr view, IntPtr touchData) // Callback for View Hover signal private bool OnHoverEvent(IntPtr view, IntPtr hoverEvent) { + if (Disposed || IsDisposeQueued) + { + // Ignore native callback if the view is disposed or queued for disposal. + return false; + } + if (hoverEvent == global::System.IntPtr.Zero) { NUILog.Error("hoverEvent should not be null!"); @@ -1004,6 +1052,12 @@ private bool OnHoverEvent(IntPtr view, IntPtr hoverEvent) // Callback for View InterceptWheel signal private bool OnInterceptWheel(IntPtr view, IntPtr wheelEvent) { + if (Disposed || IsDisposeQueued) + { + // Ignore native callback if the view is disposed or queued for disposal. + return false; + } + if (wheelEvent == global::System.IntPtr.Zero) { NUILog.Error("wheelEvent should not be null!"); @@ -1033,6 +1087,12 @@ private bool OnInterceptWheel(IntPtr view, IntPtr wheelEvent) // Callback for View Wheel signal private bool OnWheelEvent(IntPtr view, IntPtr wheelEvent) { + if (Disposed || IsDisposeQueued) + { + // Ignore native callback if the view is disposed or queued for disposal. + return false; + } + if (wheelEvent == global::System.IntPtr.Zero) { NUILog.Error("wheelEvent should not be null!"); @@ -1068,6 +1128,12 @@ private bool OnWheelEvent(IntPtr view, IntPtr wheelEvent) // Callback for View OnWindow signal private void OnWindow(IntPtr data) { + if (Disposed || IsDisposeQueued) + { + // Ignore native callback if the view is disposed or queued for disposal. + return; + } + if (onWindowEventHandler != null) { onWindowEventHandler(this, null); @@ -1077,6 +1143,12 @@ private void OnWindow(IntPtr data) // Callback for View OffWindow signal private void OffWindow(IntPtr data) { + if (Disposed || IsDisposeQueued) + { + // Ignore native callback if the view is disposed or queued for disposal. + return; + } + if (offWindowEventHandler != null) { offWindowEventHandler(this, null); @@ -1086,6 +1158,12 @@ private void OffWindow(IntPtr data) // Callback for View visibility change signal private void OnVisibilityChanged(IntPtr data, bool visibility, VisibilityChangeType type) { + if (Disposed || IsDisposeQueued) + { + // Ignore native callback if the view is disposed or queued for disposal. + return; + } + VisibilityChangedEventArgs e = new VisibilityChangedEventArgs(); IntPtr changedViewCPtr = Interop.Actor.GetVisiblityChangedActor(); if (changedViewCPtr != IntPtr.Zero) @@ -1112,6 +1190,12 @@ private void OnVisibilityChanged(IntPtr data, bool visibility, VisibilityChangeT // Callback for View aggregated visibility change signal private void OnAggregatedVisibilityChanged(IntPtr data, bool visibility) { + if (Disposed || IsDisposeQueued) + { + // Ignore native callback if the view is disposed or queued for disposal. + return; + } + AggregatedVisibilityChangedEventArgs e = new AggregatedVisibilityChangedEventArgs(); e.Visibility = visibility; @@ -1124,6 +1208,12 @@ private void OnAggregatedVisibilityChanged(IntPtr data, bool visibility) // Callback for View layout direction change signal private void OnLayoutDirectionChanged(IntPtr data, ViewLayoutDirectionType type) { + if (Disposed || IsDisposeQueued) + { + // Ignore native callback if the view is disposed or queued for disposal. + return; + } + LayoutDirectionChangedEventArgs e = new LayoutDirectionChangedEventArgs(); if (data != IntPtr.Zero) { @@ -1139,6 +1229,12 @@ private void OnLayoutDirectionChanged(IntPtr data, ViewLayoutDirectionType type) private void OnResourcesLoaded(IntPtr view) { + if (Disposed || IsDisposeQueued) + { + // Ignore native callback if the view is disposed or queued for disposal. + return; + } + if (!CheckResourceReady()) { return; @@ -1152,6 +1248,12 @@ private void OnResourcesLoaded(IntPtr view) private void OnBackgroundResourceLoaded(IntPtr view) { + if (Disposed || IsDisposeQueued) + { + // Ignore native callback if the view is disposed or queued for disposal. + return; + } + BackgroundResourceLoadedEventArgs e = new BackgroundResourceLoadedEventArgs(); e.Status = (ResourceLoadingStatusType)Interop.View.GetVisualResourceStatus(this.SwigCPtr, Property.BACKGROUND);