1 /** \file resourcewidgetmanager.c
2 * \brief Module to manage resource widgets
3 *
4 * This module allows one to register resource-bound widgets to the manager,
5 * so the manager can then be invoked to either reset all widgets to their
6 * state when they were registered, or reset the widgets to the
7 * resource's default state.
8 *
9 * Example:
10 *
11 * \code{.c}
12 *
13 * // Resource manager instance
14 * static resource_manager_t manager;
15 *
16 * // Initialize manager
17 * vice_resource_widget_manager_init(&manager);
18 *
19 * // Create a resource widget ...
20 * GtkWidget *check = vice_resource_check_button_create("SomeResource");
21 * // and add it to the manager (we pass NULL for the custom method pointers
22 * // since the resource check button has its own default reset(), sync() and
23 * // factory() methods.
24 * // To override a default method, pass a function pointer instead of NULL.
25 * vice_resource_widget_manager_add_widget(&manager, check, NULL, NULL, NULL);
26 *
27 * // To reset the widgets registered with the manager we use:
28 * // (usually this function will be called from a "Reset" GtkButton)
29 * if (vice_resource_widget_manager_reset(&manager)) {
30 * g_print("OK\n");
31 * } else {
32 * g_print("oops\n");
33 * }
34 *
35 * // And finally, to clean up resources used by the manager we use:
36 * // (usually this function will be called from a dialog's/containing widget's
37 * // "destroy" event handler)
38 * vice_resource_widget_manager_exit(&manager);
39 * \endcode
40 *
41 * \author Bas Wassink <b.wassink@ziggo.nl>
42 */
43
44 /*
45 * This file is part of VICE, the Versatile Commodore Emulator.
46 * See README for copyright notice.
47 *
48 * This program is free software; you can redistribute it and/or modify
49 * it under the terms of the GNU General Public License as published by
50 * the Free Software Foundation; either version 2 of the License, or
51 * (at your option) any later version.
52 *
53 * This program is distributed in the hope that it will be useful,
54 * but WITHOUT ANY WARRANTY; without even the implied warranty of
55 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
56 * GNU General Public License for more details.
57 *
58 * You should have received a copy of the GNU General Public License
59 * along with this program; if not, write to the Free Software
60 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
61 * 02111-1307 USA.
62 */
63
64 #include "vice.h"
65
66 #include <gtk/gtk.h>
67
68 #include "basewidgets.h"
69 #include "debug_gtk3.h"
70 #include "lib.h"
71 #include "log.h"
72 #include "resourcehelpers.h"
73
74 #include "resourcewidgetmanager.h"
75
76
77 /** \brief Initial number of entries for widgets allocated
78 *
79 * Seems like a decent number, but should one register another widget, the
80 * list is simply doubled in size.
81 */
82 #define INITIAL_ENTRIES 64
83
84
85
86 /** \brief Initialize \a entry
87 *
88 * \param[in,out] entry resource widget entry
89 */
resource_widget_entry_init(resource_widget_entry_t * entry)90 static void resource_widget_entry_init(resource_widget_entry_t *entry)
91 {
92 entry->widget = NULL;
93 entry->resource = NULL;
94 entry->reset = NULL;
95 entry->factory = NULL;
96 entry->sync = NULL;
97 }
98
99
100 /** \brief Free members of \a entry
101 *
102 * \param[in] entry resource widget entry
103 */
resource_widget_entry_cleanup(resource_widget_entry_t * entry)104 static void resource_widget_entry_cleanup(resource_widget_entry_t *entry)
105 {
106 if (entry != NULL) {
107 if (entry->resource != NULL) {
108 lib_free(entry->resource);
109 }
110 }
111 }
112
113
114 /** \brief Initialize the resource widget manager
115 *
116 * Initializes \a manager to an empty state. Allocates a list of widget entry
117 * pointers which must be freed by vice_resource_widget_manager_exit().
118 *
119 * \param[in,out] manager resource widget manager
120 */
vice_resource_widget_manager_init(resource_widget_manager_t * manager)121 void vice_resource_widget_manager_init(resource_widget_manager_t *manager)
122 {
123 size_t i;
124 return;
125
126 manager->widget_list = lib_malloc(sizeof *(manager->widget_list)
127 * INITIAL_ENTRIES);
128 manager->widget_num = 0;
129 manager->widget_max = INITIAL_ENTRIES;
130 for (i = 0; i < INITIAL_ENTRIES; i++) {
131 manager->widget_list[i] = NULL;
132 }
133 }
134
135
136 /** \brief Clean up resources used by \a manager's members
137 *
138 * Doesn't free \a manager itself
139 *
140 * \param[in,out] manager resource widget manager instance
141 */
vice_resource_widget_manager_exit(resource_widget_manager_t * manager)142 void vice_resource_widget_manager_exit(resource_widget_manager_t *manager)
143 {
144 size_t i;
145 return;
146
147 if (manager->widget_list == NULL) {
148 debug_gtk3("Got NULL as widget list, shouldn't happen!");
149 return;
150 }
151
152 for (i = 0; i < manager->widget_num; i++) {
153 resource_widget_entry_cleanup(manager->widget_list[i]);
154 lib_free(manager->widget_list[i]);
155 }
156 lib_free(manager->widget_list);
157 }
158
159
160 /** \brief Add a widget to the resource widget manager
161 *
162 */
vice_resource_widget_manager_add_widget(resource_widget_manager_t * manager,GtkWidget * widget,const char * resource,gboolean (* reset)(GtkWidget *),gboolean (* factory)(GtkWidget *),gboolean (* sync)(GtkWidget *))163 void vice_resource_widget_manager_add_widget(
164 resource_widget_manager_t *manager,
165 GtkWidget *widget,
166 const char *resource,
167 gboolean (*reset)(GtkWidget *),
168 gboolean (*factory)(GtkWidget *),
169 gboolean (*sync)(GtkWidget *))
170 {
171 resource_widget_entry_t *entry;
172
173 return ;
174
175 /* do we need to resize the list? */
176 if (manager->widget_max == manager->widget_num) {
177 /* resize widget array */
178 manager->widget_list = lib_realloc(manager->widget_list,
179 sizeof *(manager->widget_list) * manager->widget_max * 2);
180 manager->widget_max *= 2;
181 }
182
183 /* create new entry */
184 entry = lib_malloc(sizeof *entry);
185 resource_widget_entry_init(entry);
186 entry->widget = widget;
187 if (resource != NULL) {
188 entry->resource = lib_stralloc(resource);
189 } else {
190 entry->resource = NULL;
191 }
192 entry->reset = reset;
193 entry->factory = factory;
194 entry->sync = sync;
195
196 /* store entry */
197 manager->widget_list[manager->widget_num++] = entry;
198 }
199
200
201 /** \brief Debug hook: dump information on \a manager on stdout
202 *
203 * \param[in] manager resource widget manager
204 */
vice_resource_widget_manager_dump(resource_widget_manager_t * manager)205 void vice_resource_widget_manager_dump(resource_widget_manager_t *manager)
206 {
207 size_t i;
208 return;
209
210 debug_gtk3("Resource Widget Manager: registered resources:");
211 for (i = 0; i < manager->widget_num; i++) {
212 resource_widget_entry_t *entry = manager->widget_list[i];
213
214 if (entry->resource == NULL) {
215 debug_gtk3(" standard widget: '%s'",
216 resource_widget_get_resource_name(entry->widget));
217 } else {
218 debug_gtk3(" custom widget : '%s'",
219 entry->resource);
220 }
221 }
222 }
223
224
225 /** \brief Reset all widgets registered with \a manager to their initial state
226 *
227 * Iterates the widgets registered with \a manager and executes their reset()
228 * method in order. It first tries to find the default reset() method of the
229 * resource widgets in gtk3/base/widgets, if that fails it tries to invoke the
230 * custom reset() method passed when calling
231 * vice_resource_widget_manager_add_widget(), and when that is NULL, it will
232 * return FALSE to indicate failure.
233 *
234 * \param[in] manager resource widget manager
235 *
236 * \return bool
237 */
vice_resource_widget_manager_reset(resource_widget_manager_t * manager)238 gboolean vice_resource_widget_manager_reset(resource_widget_manager_t *manager)
239 {
240 size_t i;
241
242 printf("Resource Widget Manager: registered resources:\n");
243 for (i = 0; i < manager->widget_num; i++) {
244 resource_widget_entry_t *entry = manager->widget_list[i];
245
246 #ifdef HAVE_DEBUG_GTK3UI
247 const char *resource;
248 if (entry->resource == NULL) {
249 resource = resource_widget_get_resource_name(entry->widget);
250 } else {
251 resource = entry->resource;
252 }
253 #endif
254
255 debug_gtk3("resetting resource '%s'", resource);
256 /* custom reset func? */
257 if (entry->reset != NULL) {
258 debug_gtk3("calling custom reset function");
259 entry->reset(entry->widget);
260 } else {
261 gboolean (*reset)(GtkWidget *) = NULL;
262 debug_gtk3("calling default reset function");
263 reset = g_object_get_data(G_OBJECT(entry->widget), "MethodReset");
264 if (reset != NULL) {
265 reset(entry->widget);
266 } else {
267 debug_gtk3("failed to find the reset method of the widget");
268 return FALSE;
269 }
270 }
271 }
272 return TRUE;
273 }
274
275
276 /** \brief Reset all widgets registered with \a manager to their factory state
277 *
278 * Iterates the widgets registered with \a manager and executes their factory()
279 * method in order. It first tries to find the default factory() method of the
280 * resource widgets in gtk3/base/widgets, if that fails it tries to invoke the
281 * custom factory() method passed when calling
282 * vice_resource_widget_manager_add_widget(), and when that is NULL, it will
283 * return FALSE to indicate failure.
284 *
285 * \param[in] manager resource widget manager
286 *
287 * \return bool
288 */
vice_resource_widget_manager_factory(resource_widget_manager_t * manager)289 gboolean vice_resource_widget_manager_factory(resource_widget_manager_t *manager)
290 {
291 size_t i;
292
293 printf("Resource Widget Manager: registered resources:\n");
294 for (i = 0; i < manager->widget_num; i++) {
295 resource_widget_entry_t *entry = manager->widget_list[i];
296
297 #ifdef HAVE_DEBUG_GTK3UI
298 const char *resource;
299 if (entry->resource == NULL) {
300 resource = resource_widget_get_resource_name(entry->widget);
301 } else {
302 resource = entry->resource;
303 }
304 #endif
305
306 debug_gtk3("resetting resource '%s' to factory value", resource);
307 /* custom reset func? */
308 if (entry->factory != NULL) {
309 debug_gtk3("calling custom factory function");
310 entry->reset(entry->widget);
311 } else {
312 gboolean (*factory)(GtkWidget *) = NULL;
313 debug_gtk3("calling default factory function");
314 factory = g_object_get_data(G_OBJECT(entry->widget),
315 "MethodFactory");
316 if (factory != NULL) {
317 factory(entry->widget);
318 } else {
319 debug_gtk3("failed to find the factory method of the widget");
320 return FALSE;
321 }
322 }
323 }
324 return TRUE;
325 }
326
327
328 /** \brief Apply all registered widget's values to their resources
329 *
330 * \param[in] manager resource widget manager
331 *
332 * \return bool
333 */
vice_resource_widget_manager_apply(resource_widget_manager_t * manager)334 gboolean vice_resource_widget_manager_apply(resource_widget_manager_t *manager)
335 {
336 size_t i;
337
338 printf("iterating widgets:\n");
339 for (i = 0; i < manager->widget_num; i++) {
340 resource_widget_entry_t *entry = manager->widget_list[i];
341 GtkWidget *widget = entry->widget;
342 if (resource_widget_get_auto_update(widget)) {
343 debug_gtk3("updating resource '%s'.", entry->resource);
344 }
345 }
346
347 return FALSE;
348 }
349
350