Merge remote-tracking branch 'origin/master' into tizen
[platform/core/csapi/tizenfx.git] / src / Tizen.Applications.ThemeManager / Tizen.Applications.ThemeManager / ThemeLoader.cs
1 /*
2  * Copyright (c) 2020 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.Runtime.InteropServices;
21
22 namespace Tizen.Applications.ThemeManager
23 {
24     /// <summary>
25     ///
26     /// </summary>
27     /// <since_tizen> 8 </since_tizen>
28     [EditorBrowsable(EditorBrowsableState.Never)]
29     public class ThemeLoader : IDisposable
30     {
31         private const string LogTag = "Tizen.Applications.ThemeManager";
32         private bool _disposed = false;
33         private event EventHandler<ThemeEventArgs> _changedEventHandler;
34         private Interop.ThemeManager.ThemeLoaderChangedCallback _callback;
35         private string _eventId;
36         private Theme _currentTheme = null;
37         internal IntPtr _loaderHandle = IntPtr.Zero;
38
39         /// <summary>
40         /// Creates ThemeLoader.
41         /// </summary>
42         /// <since_tizen> 8 </since_tizen>
43         /// <exception cref="OutOfMemoryException">Failed to create handle.</exception>
44         [EditorBrowsable(EditorBrowsableState.Never)]
45         public ThemeLoader()
46         {
47             Interop.ThemeManager.ErrorCode err = Interop.ThemeManager.LoaderCreate(out _loaderHandle);
48             if (err != Interop.ThemeManager.ErrorCode.None)
49             {
50                 throw Interop.ThemeManager.ThemeManagerErrorFactory.GetException(err, "Failed to create themeloader");
51             }
52
53             _callback = new Interop.ThemeManager.ThemeLoaderChangedCallback(OnThemeChanged);
54             err = Interop.ThemeManager.LoaderAddEvent(_loaderHandle, _callback, IntPtr.Zero, out _eventId);
55             if (err != Interop.ThemeManager.ErrorCode.None)
56             {
57                 throw Interop.ThemeManager.ThemeManagerErrorFactory.GetException(err, "Failed to add event");
58             }
59         }
60
61         private int OnThemeChanged(IntPtr handle, IntPtr userData)
62         {
63             _currentTheme = null;
64
65             Interop.ThemeManager.ErrorCode err = Interop.ThemeManager.ThemeClone(handle, out IntPtr cloned);
66             if (err != Interop.ThemeManager.ErrorCode.None)
67                 return -1;
68
69             _changedEventHandler?.Invoke(this, new ThemeEventArgs(new Theme(cloned)));
70             return 0;
71         }
72
73         /// <summary>
74         /// Adds or removes events for theme changed.
75         /// </summary>
76         /// <since_tizen> 8 </since_tizen>
77         /// <exception cref="ArgumentException">Thrown when failed because of an invalid argument.</exception>
78         /// <exception cref="OutOfMemoryException">Thrown when failed because of out of memory.</exception>
79         [EditorBrowsable(EditorBrowsableState.Never)]
80         public event EventHandler<ThemeEventArgs> ThemeChanged
81         {
82             add
83             {
84                 _changedEventHandler += value;
85
86             }
87             remove
88             {
89                 _changedEventHandler -= value;
90             }
91         }
92
93         /// <summary>
94         /// Sets current theme.
95         /// </summary>
96         /// <since_tizen> 8 </since_tizen>
97         /// <exception cref="ArgumentException">Thrown when failed because of an invalid argument.</exception>
98         [EditorBrowsable(EditorBrowsableState.Never)]
99         public Theme CurrentTheme
100         {
101             get
102             {
103                 if (_currentTheme != null && _currentTheme.Id.Length > 0)
104                     return _currentTheme;
105
106                 Interop.ThemeManager.ErrorCode err = Interop.ThemeManager.LoaderLoadCurrentTheme(_loaderHandle, out IntPtr _themeHandle);
107                 if (err != Interop.ThemeManager.ErrorCode.None)
108                 {
109                     throw Interop.ThemeManager.ThemeManagerErrorFactory.GetException(err, "Failed to load current theme");
110                 }
111
112                 _currentTheme = new Theme(_themeHandle);
113                 return _currentTheme;
114             }
115             set
116             {
117                 if (value == null)
118                     throw new ArgumentException("value is null");
119
120                 Interop.ThemeManager.ErrorCode err = Interop.ThemeManager.LoaderSetCurrentTheme(_loaderHandle, value.Id);
121                 if (err != Interop.ThemeManager.ErrorCode.None)
122                 {
123                     Log.Warn(LogTag, "Failed to set current. Err = " + err);
124                     throw Interop.ThemeManager.ThemeManagerErrorFactory.GetException(err, "Failed to set current theme");
125                 }
126
127                 if(_currentTheme != value)
128                     _currentTheme = value;
129             }
130         }
131
132         /// <summary>
133         /// Loads theme.
134         /// </summary>
135         /// <since_tizen> 8 </since_tizen>
136         /// <exception cref="ArgumentException">Thrown when failed because of an invalid argument.</exception>
137         [EditorBrowsable(EditorBrowsableState.Never)]
138         public Theme LoadTheme(string id)
139         {
140             IntPtr _themeHandle;
141
142             Interop.ThemeManager.ErrorCode err = Interop.ThemeManager.LoaderLoadTheme(_loaderHandle, id, out _themeHandle);
143             if (err != Interop.ThemeManager.ErrorCode.None)
144             {
145                 throw Interop.ThemeManager.ThemeManagerErrorFactory.GetException(err, "Failed to load theme");
146             }
147
148             return new Theme(_themeHandle);
149         }
150
151         /// <summary>
152         /// Gets bundle of theme IDs.
153         /// </summary>
154         /// <since_tizen> 8 </since_tizen>
155         /// <exception cref="ArgumentException">Thrown when failed because of an invalid argument.</exception>
156         /// <exception cref="OutOfMemoryException">Thrown when failed because of out of memory.</exception>
157         [EditorBrowsable(EditorBrowsableState.Never)]
158         public IEnumerable<string> QueryIds()
159         {
160             IntPtr ids;
161             string[] stringArray;
162             int count;
163
164             Interop.ThemeManager.ErrorCode err = Interop.ThemeManager.LoaderQueryId(_loaderHandle, out ids, out count);
165             if (err != Interop.ThemeManager.ErrorCode.None)
166             {
167                 throw Interop.ThemeManager.ThemeManagerErrorFactory.GetException(err, "Failed to query ids");
168             }
169
170             IntPtrToStringArray(ids, count, out stringArray);
171             return stringArray;
172         }
173
174         static void IntPtrToStringArray(IntPtr unmanagedArray, int size, out string[] managedArray)
175         {
176             managedArray = new string[size];
177             IntPtr[] IntPtrArray = new IntPtr[size];
178             Marshal.Copy(unmanagedArray, IntPtrArray, 0, size);
179             for (int iterator = 0; iterator < size; iterator++)
180             {
181                 managedArray[iterator] = Marshal.PtrToStringAnsi(IntPtrArray[iterator]);
182             }
183         }
184
185         /// <summary>
186         /// Releases all resources used by the ThemeLoader class.
187         /// </summary>
188         /// <since_tizen> 8 </since_tizen>
189         [EditorBrowsable(EditorBrowsableState.Never)]
190         public void Dispose()
191         {
192             Dispose(true);
193             GC.SuppressFinalize(this);
194         }
195
196         /// <summary>
197         /// Releases the unmanaged resources used by the ThemeLoader class specifying whether to perform a normal dispose operation.
198         /// </summary>
199         /// <param name="disposing">true for a normal dispose operation; false to finalize the handle.</param>
200         protected virtual void Dispose(bool disposing)
201         {
202             if (_disposed)
203                 return;
204
205             if (_loaderHandle != IntPtr.Zero)
206             {
207                 Interop.ThemeManager.ErrorCode err = Interop.ThemeManager.LoaderRemoveEvent(_loaderHandle, _eventId);
208                 if (err != Interop.ThemeManager.ErrorCode.None)
209                 {
210                     Log.Error(LogTag, "Failed to remove event");
211                 }
212
213                 Interop.ThemeManager.LoaderDestroy(_loaderHandle);
214                 _loaderHandle = IntPtr.Zero;
215             }
216
217             if (disposing && _currentTheme != null)
218                 _currentTheme.Dispose();
219
220             _disposed = true;
221         }
222     }
223 }