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