Fix target handle of SmartEvent&EvasObjectEvent correctly
[platform/core/csapi/tizenfx.git] / src / ElmSharp / ElmSharp / EvasObjectEvent.cs
1 /*
2  * Copyright (c) 2016 Samsung Electronics Co., Ltd All Rights Reserved
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 using System;
18 using System.Collections.Generic;
19 using System.ComponentModel;
20 using System.Linq;
21
22 namespace ElmSharp
23 {
24     public interface IInvalidatable : IDisposable
25     {
26         void MakeInvalidate();
27     }
28
29     public enum EvasObjectCallbackType
30     {
31         MouseIn,
32         MouseOut,
33         MouseDown,
34         MouseUp,
35         MouseMove,
36         MouseWheel,
37         MultiDown,
38         MultiUp,
39         MultiMove,
40         Free,
41         KeyDown,
42         KeyUp,
43         FocusIn,
44         FocusOut,
45         Show,
46         Hide,
47         Move,
48         Resize,
49         Restack,
50         Del,
51         Hold,
52         ChangedSizeHints,
53         ImagePreloaded,
54         CanvasFocusIn,
55         CanvasFocusOut,
56         RenderFlushPre,
57         RenderFlushPost,
58         CanvasObjectFocusIn,
59         CanvasObjectFocusOut,
60         ImageUnloaded,
61         RenderPre,
62         RenderPost,
63         ImageResize,
64         DeviceChanged,
65         AxisUpdate,
66         CanvasViewportResize
67     }
68
69     public class EvasObjectEvent<TEventArgs> : IInvalidatable where TEventArgs : EventArgs
70     {
71         public delegate TEventArgs SmartEventInfoParser(IntPtr data, IntPtr obj, IntPtr info);
72
73         private bool _disposed = false;
74         private EvasObject _sender;
75         private IntPtr _handle;
76         private readonly EvasObjectCallbackType _type;
77         private readonly SmartEventInfoParser _parser;
78         private readonly List<NativeCallback> _nativeCallbacks = new List<NativeCallback>();
79
80         public EvasObjectEvent(EvasObject sender, EvasObjectCallbackType type, SmartEventInfoParser parser) : this(sender, sender.Handle, type, parser)
81         {
82         }
83
84         [EditorBrowsableAttribute(EditorBrowsableState.Never)]
85         public EvasObjectEvent(EvasObject sender, IntPtr handle, EvasObjectCallbackType type, SmartEventInfoParser parser)
86         {
87             _sender = sender;
88             _handle = handle;
89             _type = type;
90             _parser = parser;
91             sender.AddToEventLifeTracker(this);
92         }
93
94         public EvasObjectEvent(EvasObject sender, EvasObjectCallbackType type) : this(sender, type, null)
95         {
96         }
97
98         ~EvasObjectEvent()
99         {
100             Dispose(false);
101         }
102
103         private struct NativeCallback
104         {
105             public Interop.Evas.EventCallback callback;
106             public EventHandler<TEventArgs> eventHandler;
107         }
108
109         public event EventHandler<TEventArgs> On
110         {
111             add
112             {
113                 if (_handle == IntPtr.Zero)
114                 {
115                     return;
116                 }
117                 EventHandler<TEventArgs> handler = value;
118                 var cb = new Interop.Evas.EventCallback((data, evas, obj, info) =>
119                 {
120                     TEventArgs ea = _parser == null ? (TEventArgs)EventArgs.Empty : _parser(data, obj, info);
121                     handler(_sender, ea);
122                 });
123                 _nativeCallbacks.Add(new NativeCallback { callback = cb, eventHandler = handler });
124                 int i = _nativeCallbacks.Count - 1;
125                 Interop.Evas.evas_object_event_callback_add(_handle, (Interop.Evas.ObjectCallbackType)_type, _nativeCallbacks[i].callback, IntPtr.Zero);
126             }
127
128             remove
129             {
130                 if (_handle == IntPtr.Zero)
131                 {
132                     return;
133                 }
134                 EventHandler<TEventArgs> handler = value;
135                 var callbacks = _nativeCallbacks.Where(cb => cb.eventHandler == handler);
136                 foreach (var cb in callbacks)
137                 {
138                     Interop.Evas.evas_object_event_callback_del(_handle, (Interop.Evas.ObjectCallbackType)_type, cb.callback);
139                 }
140             }
141         }
142
143         protected virtual void Dispose(bool disposing)
144         {
145             if (!_disposed)
146             {
147                 if (disposing)
148                 {
149                     // Place holder to dispose managed state (managed objects).
150                 }
151                 if (_handle != IntPtr.Zero)
152                 {
153                     foreach (var cb in _nativeCallbacks)
154                     {
155                         Interop.Evas.evas_object_event_callback_del(_handle, (Interop.Evas.ObjectCallbackType)_type, cb.callback);
156                     }
157                 }
158                 _nativeCallbacks.Clear();
159                 _disposed = true;
160             }
161         }
162
163         public void Dispose()
164         {
165             Dispose(true);
166             GC.SuppressFinalize(this);
167         }
168
169         public void MakeInvalidate()
170         {
171             _sender = null;
172             _handle = IntPtr.Zero;
173         }
174     }
175
176     public class EvasObjectEvent : IInvalidatable
177     {
178         private EvasObjectEvent<EventArgs> _evasObjectEvent;
179         private event EventHandler _handlers;
180         private bool _disposed = false;
181
182         public EvasObjectEvent(EvasObject sender, EvasObjectCallbackType type) : this(sender, sender.Handle, type)
183         {
184         }
185
186         [EditorBrowsableAttribute(EditorBrowsableState.Never)]
187         public EvasObjectEvent(EvasObject sender, IntPtr handle, EvasObjectCallbackType type)
188         {
189             _evasObjectEvent = new EvasObjectEvent<EventArgs>(sender, handle, type, null);
190         }
191
192         ~EvasObjectEvent()
193         {
194             Dispose(false);
195         }
196
197         public event EventHandler On
198         {
199             add
200             {
201                 if (_handlers == null)
202                 {
203                     _evasObjectEvent.On += SendEvent;
204                 }
205                 _handlers += value;
206             }
207
208             remove
209             {
210                 _handlers -= value;
211                 if (_handlers == null)
212                 {
213                     _evasObjectEvent.On -= SendEvent;
214                 }
215             }
216         }
217
218         private void SendEvent(object sender, EventArgs e)
219         {
220             _handlers?.Invoke(sender, e);
221         }
222
223         protected virtual void Dispose(bool disposing)
224         {
225             if (!_disposed)
226             {
227                 if (disposing)
228                 {
229                     _evasObjectEvent.Dispose();
230                 }
231                 _disposed = true;
232             }
233         }
234
235         public void Dispose()
236         {
237             Dispose(true);
238             GC.SuppressFinalize(this);
239         }
240
241         public void MakeInvalidate()
242         {
243             _evasObjectEvent.MakeInvalidate();
244         }
245     }
246 }