[NUI] Change all CallingConvention to `Cdecl`
[platform/core/csapi/tizenfx.git] / src / Tizen.NUI / src / public / Common / PropertyNotification.cs
1 /*
2  * Copyright(c) 2019 Samsung Electronics Co., Ltd.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  *
16  */
17
18 using System;
19 using System.Runtime.InteropServices;
20 using System.ComponentModel;
21
22 namespace Tizen.NUI
23 {
24     ///<summary>
25     /// Issues a notification upon a condition of the property being met.
26     /// See PropertyCondition for available defined conditions.
27     ///</summary>
28     /// <since_tizen> 4 </since_tizen>
29     public class PropertyNotification : BaseHandle
30     {
31
32         private DaliEventHandler<object, NotifyEventArgs> propertyNotificationNotifyEventHandler;
33         private NotifyEventCallbackDelegate propertyNotificationNotifyEventCallback;
34
35         /// <summary>
36         /// Create a instance of PropertyNotification.
37         /// </summary>
38         /// <since_tizen> 4 </since_tizen>
39         public PropertyNotification() : this(Interop.PropertyNotification.NewPropertyNotification(), true)
40         {
41             if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve();
42         }
43
44         /// <summary>
45         /// Create a instance of PropertyNotification.
46         /// </summary>
47         /// <since_tizen> 4 </since_tizen>
48         public PropertyNotification(PropertyNotification handle) : this(Interop.PropertyNotification.NewPropertyNotification(PropertyNotification.getCPtr(handle)), true)
49         {
50             if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve();
51         }
52
53         internal PropertyNotification(global::System.IntPtr cPtr, bool cMemoryOwn) : base(cPtr, cMemoryOwn)
54         {
55         }
56
57         [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
58         private delegate void NotifyEventCallbackDelegate(IntPtr propertyNotification);
59
60         ///<summary>
61         /// Event for Notified signal which can be used to subscribe/unsubscribe the event handler
62         /// Notified signal is emitted when the notification upon a condition of the property being met, has occurred.
63         ///</summary>
64         /// <since_tizen> 4 </since_tizen>
65         public event DaliEventHandler<object, NotifyEventArgs> Notified
66         {
67             add
68             {
69                 if (propertyNotificationNotifyEventHandler == null)
70                 {
71                     propertyNotificationNotifyEventCallback = OnPropertyNotificationNotify;
72                     using PropertyNotifySignal signal = new PropertyNotifySignal(Interop.PropertyNotification.NotifySignal(SwigCPtr), false);
73                     signal?.Connect(propertyNotificationNotifyEventCallback);
74                 }
75                 propertyNotificationNotifyEventHandler += value;
76             }
77             remove
78             {
79                 propertyNotificationNotifyEventHandler -= value;
80                 if (propertyNotificationNotifyEventHandler == null)
81                 {
82                     using PropertyNotifySignal signal = new PropertyNotifySignal(Interop.PropertyNotification.NotifySignal(SwigCPtr), false);
83                     if (signal?.Empty() == false)
84                     {
85                         signal?.Disconnect(propertyNotificationNotifyEventCallback);
86                         if (signal?.Empty() == true)
87                         {
88                             propertyNotificationNotifyEventCallback = null;
89                         }
90                     }
91                 }
92             }
93         }
94
95         /// <summary>
96         /// Enumeration for description of how to check condition.
97         /// </summary>
98         /// <since_tizen> 3 </since_tizen>
99         public enum NotifyMode
100         {
101             /// <summary>
102             /// Don't notify, regardless of result of Condition
103             /// </summary>
104             /// <since_tizen> 3 </since_tizen>
105             Disabled,
106             /// <summary>
107             /// Notify whenever condition changes from false to true.
108             /// </summary>
109             /// <since_tizen> 3 </since_tizen>
110             NotifyOnTrue,
111             /// <summary>
112             /// Notify whenever condition changes from true to false.
113             /// </summary>
114             /// <since_tizen> 3 </since_tizen>
115             NotifyOnFalse,
116             /// <summary>
117             /// Notify whenever condition changes (false to true, and true to false)
118             /// </summary>
119             /// <since_tizen> 3 </since_tizen>
120             NotifyOnChanged
121         }
122
123         /// <summary>
124         /// Get property notification from Intptr.<br/>
125         /// This should be internal, do not use.
126         /// </summary>
127         /// <param name="cPtr">An object of IntPtr type.</param>
128         /// <returns>An object of the PropertyNotification type.</returns>
129         internal static PropertyNotification GetPropertyNotificationFromPtr(global::System.IntPtr cPtr)
130         {
131             PropertyNotification ret = new PropertyNotification(cPtr, false);
132             if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve();
133             return ret;
134         }
135
136         /// <summary>
137         /// Downcast a PropertyNotification instance.
138         /// </summary>
139         /// <param name="handle">Handle to an object of BaseHandle type.</param>
140         /// <returns>Handle to an object of the PropertyNotification type.</returns>
141         /// <exception cref="ArgumentNullException"> Thrown when handle is null. </exception>
142         /// <since_tizen> 4 </since_tizen>
143         public static PropertyNotification DownCast(BaseHandle handle)
144         {
145             if (null == handle)
146             {
147                 throw new ArgumentNullException(nameof(handle));
148             }
149             PropertyNotification ret = Registry.GetManagedBaseHandleFromNativePtr(handle) as PropertyNotification;
150             if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve();
151             return ret;
152         }
153
154         /// <summary>
155         /// Assign.
156         /// </summary>
157         /// <param name="rhs">A reference to the copied handle.</param>
158         /// <returns>A reference to this.</returns>
159         internal PropertyNotification Assign(PropertyNotification rhs)
160         {
161             PropertyNotification ret = new PropertyNotification(Interop.PropertyNotification.Assign(SwigCPtr, PropertyNotification.getCPtr(rhs)), false);
162             if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve();
163             return ret;
164         }
165
166         /// <summary>
167         /// Gets the condition of this notification.
168         /// </summary>
169         /// <returns>The condition is returned.</returns>
170         /// <since_tizen> 4 </since_tizen>
171         public PropertyCondition GetCondition()
172         {
173             PropertyCondition ret = new PropertyCondition(Interop.PropertyNotification.GetCondition(SwigCPtr), true);
174             if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve();
175             return ret;
176         }
177
178         /// <summary>
179         /// Gets the target handle that this notification is observing.
180         /// </summary>
181         /// <since_tizen> 4 </since_tizen>
182         public Animatable GetTarget()
183         {
184             //to fix memory leak issue, match the handle count with native side.
185             Animatable ret = this.GetInstanceSafely<Animatable>(Interop.PropertyNotification.GetTarget(SwigCPtr));
186             if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve();
187             return ret;
188         }
189
190         /// <summary>
191         /// Gets the target handle's property index that this notification.
192         /// </summary>
193         /// <returns>The target property index.</returns>
194         /// <since_tizen> 4 </since_tizen>
195         public int GetTargetProperty()
196         {
197             int ret = Interop.PropertyNotification.GetTargetProperty(SwigCPtr);
198             if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve();
199             return ret;
200         }
201
202         /// <summary>
203         /// Sets the Notification mode.
204         /// </summary>
205         /// <param name="mode">mode Notification mode (Default is PropertyNotification::NotifyOnTrue).</param>
206         /// <since_tizen> 4 </since_tizen>
207         public void SetNotifyMode(PropertyNotification.NotifyMode mode)
208         {
209             Interop.PropertyNotification.SetNotifyMode(SwigCPtr, (int)mode);
210             if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve();
211         }
212
213         /// <summary>
214         /// Retrieves the current Notification mode.
215         /// </summary>
216         /// <returns>Notification mode.</returns>
217         /// <since_tizen> 4 </since_tizen>
218         public PropertyNotification.NotifyMode GetNotifyMode()
219         {
220             PropertyNotification.NotifyMode ret = (PropertyNotification.NotifyMode)Interop.PropertyNotification.GetNotifyMode(SwigCPtr);
221             if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve();
222             return ret;
223         }
224
225         /// <summary>
226         /// Gets the result of the last condition check that caused a signal emit,
227         /// useful when using NotifyOnChanged mode and need to know what it changed to.
228         /// </summary>
229         /// <since_tizen> 4 </since_tizen>
230         public bool GetNotifyResult()
231         {
232             bool ret = Interop.PropertyNotification.GetNotifyResult(SwigCPtr);
233             if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve();
234             return ret;
235         }
236
237         /// <summary>
238         /// override it to clean-up your own resources.
239         /// </summary>
240         /// <param name="type"></param>
241         [EditorBrowsable(EditorBrowsableState.Never)]
242         protected override void Dispose(DisposeTypes type)
243         {
244             if (disposed)
245             {
246                 return;
247             }
248
249             if (type == DisposeTypes.Explicit)
250             {
251                 //Called by User
252                 //Release your own managed resources here.
253                 //You should release all of your own disposable objects here.
254             }
255
256             //Release your own unmanaged resources here.
257             //You should not access any managed member here except static instance.
258             //because the execution order of Finalizes is non-deterministic.
259
260             if (HasBody())
261             {
262                 if (propertyNotificationNotifyEventCallback != null)
263                 {
264                     using PropertyNotifySignal signal = new PropertyNotifySignal(Interop.PropertyNotification.NotifySignal(SwigCPtr), false);
265                     signal?.Disconnect(propertyNotificationNotifyEventCallback);
266                     propertyNotificationNotifyEventCallback = null;
267                 }
268             }
269             base.Dispose(type);
270         }
271
272         /// This will not be public opened.
273         [EditorBrowsable(EditorBrowsableState.Never)]
274         protected override void ReleaseSwigCPtr(System.Runtime.InteropServices.HandleRef swigCPtr)
275         {
276             Interop.PropertyNotification.DeletePropertyNotification(swigCPtr);
277         }
278
279         // Callback for PropertyNotification NotifySignal
280         private void OnPropertyNotificationNotify(IntPtr propertyNotification)
281         {
282             if (IsNativeHandleInvalid())
283             {
284                 if (this.Disposed)
285                 {
286                     if (propertyNotificationNotifyEventHandler != null)
287                     {
288                         var process = global::System.Diagnostics.Process.GetCurrentProcess();
289                         var processId = process?.Id ?? -1;
290                         var thread = global::System.Threading.Thread.CurrentThread.ManagedThreadId;
291                         var me = this.GetType().FullName;
292
293                         Tizen.Log.Error("NUI", $"Error! NUI's native dali object is already disposed. " +
294                             $"OR the native dali object handle of NUI becomes null! \n" +
295                             $" process:{processId} thread:{thread}, isDisposed:{this.Disposed}, isDisposeQueued:{this.IsDisposeQueued}, me:{me}\n");
296
297                         process?.Dispose();
298                     }
299                 }
300                 else
301                 {
302                     if (this.IsDisposeQueued)
303                     {
304                         var process = global::System.Diagnostics.Process.GetCurrentProcess();
305                         var processId = process?.Id ?? -1;
306                         var thread = global::System.Threading.Thread.CurrentThread.ManagedThreadId;
307                         var me = this.GetType().FullName;
308
309                         //in this case, this object is ready to be disposed waiting on DisposeQueue, so event callback should not be invoked!
310                         Tizen.Log.Error("NUI", "in this case, the View object is ready to be disposed waiting on DisposeQueue, so event callback should not be invoked! just return here! \n" +
311                             $"process:{processId} thread:{thread}, isDisposed:{this.Disposed}, isDisposeQueued:{this.IsDisposeQueued}, me:{me}\n");
312
313                         process?.Dispose();
314                         return;
315                     }
316                 }
317             }
318
319             if (propertyNotificationNotifyEventHandler != null)
320             {
321                 NotifyEventArgs e = new NotifyEventArgs();
322                 e.PropertyNotification = GetPropertyNotificationFromPtr(propertyNotification);
323
324                 //here we send all data to user event handlers
325                 propertyNotificationNotifyEventHandler(this, e);
326             }
327         }
328
329         ///<summary>
330         /// Event arguments that passed via Notify signal
331         ///</summary>
332         /// <since_tizen> 3 </since_tizen>
333         public class NotifyEventArgs : EventArgs
334         {
335             private PropertyNotification propertyNotification;
336
337             ///<summary>
338             /// PropertyNotification - is the PropertyNotification handle that has the notification properties.
339             ///</summary>
340             /// <since_tizen> 3 </since_tizen>
341             public PropertyNotification PropertyNotification
342             {
343                 get
344                 {
345                     return propertyNotification;
346                 }
347                 set
348                 {
349                     propertyNotification = value;
350                 }
351             }
352         }
353     }
354 }