[NUI] Dispose queue incrementally
[platform/core/csapi/tizenfx.git] / src / Tizen.NUI / src / internal / Common / ProcessorController.cs
1 /*
2  * Copyright (c) 2021 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.Runtime.InteropServices;
19 using System;
20 using System.ComponentModel;
21
22 namespace Tizen.NUI
23 {
24     /// <summary>
25     /// Singleton class.
26     /// ProcessorController handles ProcessorCallbacks those are requested to be called for each end of event process.
27     /// If there are works those required to be called after all of the event process for the efficiency, add them ProcessorController.
28     /// The calling order is not guaranteed but ProcessorCallbackes of LayoutController those are added by using AddLayoutControllerProcessor,
29     /// are called after ordinaly ProcessCallbacks added by AddProcessor.
30     ///
31     /// The added callbacks will be called every time of event tick.
32     /// If the callback is not be wanted to be called anymore, remove it.
33     /// </summary>
34     internal sealed class ProcessorController : Disposable
35     {
36         private static ProcessorController instance = null;
37         private bool initialied = false;
38
39         private ProcessorController() : this(Interop.ProcessorController.New(), true)
40         {
41         }
42
43         internal ProcessorController(global::System.IntPtr cPtr, bool cMemoryOwn) : base(cPtr, cMemoryOwn)
44         {
45         }
46
47         [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
48         internal delegate void ProcessorEventHandler();
49
50         private ProcessorEventHandler processorCallback = null;
51
52         private uint onceEventIndex;
53         // Double buffered once event processing
54         private EventHandler[] internalProcessorOnceEvent;
55
56         public event EventHandler ProcessorOnceEvent
57         {
58             add
59             {
60                 internalProcessorOnceEvent[onceEventIndex] += value;
61             }
62             remove
63             {
64                 internalProcessorOnceEvent[onceEventIndex] -= value;
65             }
66         }
67         public event EventHandler ProcessorEvent;
68         public event EventHandler LayoutProcessorEvent;
69
70         public bool Initialized => initialied;
71
72         public static ProcessorController Instance
73         {
74             get
75             {
76                 if (instance == null)
77                 {
78                     instance = new ProcessorController();
79                 }
80                 return instance;
81             }
82         }
83
84         public void Initialize()
85         {
86             if (initialied == false)
87             {
88                 initialied = true;
89
90                 Interop.ProcessorController.Initialize(SwigCPtr);
91
92                 onceEventIndex = 0u;
93                 internalProcessorOnceEvent = new EventHandler[2];
94                 internalProcessorOnceEvent[0] = null;
95                 internalProcessorOnceEvent[1] = null;
96
97                 processorCallback = new ProcessorEventHandler(Process);
98                 Interop.ProcessorController.SetCallback(SwigCPtr, processorCallback);
99                 NDalicPINVOKE.ThrowExceptionIfExists();
100             }
101         }
102
103         public void Process()
104         {
105             // Let us add once event into 1 index during 0 event invoke
106             onceEventIndex = 1;
107             internalProcessorOnceEvent[0]?.Invoke(this, null);
108             internalProcessorOnceEvent[0] = null;
109
110             ProcessorEvent?.Invoke(this, null);
111             LayoutProcessorEvent?.Invoke(this, null);
112
113             // Let us add once event into 0 index during 1 event invoke
114             // Note : To avoid ImageView's properties mismatched problem,
115             // We need to invoke events now which attached during internalProcessorOnceEvent[0] and LayoutProcessor.
116             onceEventIndex = 0;
117             internalProcessorOnceEvent[1]?.Invoke(this, null);
118             internalProcessorOnceEvent[1] = null;
119         }
120
121         /// <summary>
122         /// Dispose ProcessorController.
123         /// </summary>
124         [EditorBrowsable(EditorBrowsableState.Never)]
125         protected override void Dispose(DisposeTypes type)
126         {
127             Interop.ProcessorController.RemoveCallback(SwigCPtr, processorCallback);
128             internalProcessorOnceEvent[0] = null;
129             internalProcessorOnceEvent[1] = null;
130             ProcessorEvent = null;
131             LayoutProcessorEvent = null;
132             GC.SuppressFinalize(this);
133
134             base.Dispose(type);
135         }
136
137         /// <summary>
138         /// Awake ProcessorController.
139         /// It will call ProcessController.processorCallback and ProcessController.processorPostCallback hardly.
140         /// </summary>
141         /// <note>
142         /// When event thread is not in idle state, This function will be ignored.
143         /// </note>
144         [EditorBrowsable(EditorBrowsableState.Never)]
145         public void Awake()
146         {
147             Interop.ProcessorController.Awake(SwigCPtr);
148             NDalicPINVOKE.ThrowExceptionIfExists();
149         }
150     } // class ProcessorController
151 } // namespace Tizen.NUI