GnuCash  2.6.99
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
gnc-gobject-utils.c
1 /*
2  * gnc-gobject-utils.h -- utility functions for working
3  * with GObjects
4  * Copyright (C) 2005 David Hampton <[email protected]>
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU General Public License as
8  * published by the Free Software Foundation; either version 2 of
9  * the License, or (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, contact:
18  *
19  * Free Software Foundation Voice: +1-617-542-5942
20  * 51 Franklin Street, Fifth Floor Fax: +1-617-542-2652
21  * Boston, MA 02110-1301, USA [email protected]
22  */
23 
24 #include "config.h"
25 
26 #include <stdio.h>
27 #include "gnc-gobject-utils.h"
28 
29 #include <gtk/gtk.h> // For gtk_main_quit(). Can't get this to work with
30 // a g_source attached to the main glib context.
31 
32 
33 static void gnc_gobject_weak_cb (gpointer user_data, GObject *object);
34 
35 /************************************************************/
36 /* GObject Utilities */
37 /************************************************************/
38 
39 
48 static GHashTable*
49 gnc_gobject_tracking_table (void)
50 {
51  static GHashTable *singleton = NULL;
52 
53  if (!singleton)
54  {
55  singleton = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, NULL);
56  }
57  return singleton;
58 }
59 
60 
69 static void
70 gnc_gobject_dump_gobject (GObject *object, const gchar *name)
71 {
72  //printf("Enter %s: object %p, name %s\n", G_STRFUNC, object, name);
73  g_message(" object %p, ref count %d", object, object->ref_count);
74  //printf("Leave %s:\n", G_STRFUNC);
75 }
76 
77 
84 static gboolean
85 gnc_gobject_dump_list (const gchar *name, GList *list, gpointer user_data)
86 {
87  //printf("Enter %s: name %s, list %p\n", G_STRFUNC, name, list);
88  g_message(" %d %s", g_list_length(list), name);
89  g_list_foreach(list, (GFunc)gnc_gobject_dump_gobject, (gpointer)name);
90  //printf("Leave %s:\n", G_STRFUNC);
91  return TRUE;
92 }
93 
94 
101 void
103 {
104  GHashTable *table;
105 
106  //printf("Enter %s:\n", G_STRFUNC);
107  table = gnc_gobject_tracking_table();
108 
109  if (g_hash_table_size(table) > 0)
110  {
111  g_message("The following objects remain alive:");
112  g_hash_table_foreach_remove(table, (GHRFunc)gnc_gobject_dump_list, NULL);
113  }
114  //printf("Leave %s:\n", G_STRFUNC);
115 }
116 
117 
120 void
121 gnc_gobject_tracking_remember (GObject *object, GObjectClass *klass)
122 {
123  GHashTable *table;
124  GList *list;
125  const gchar *name;
126 
127  g_return_if_fail(G_IS_OBJECT(object));
128 
129  /* Little dance here to handle startup conditions. During object
130  * initialization the object type changes as each each parent class
131  * is initialized. The class passed to the initialization function
132  * is always the ultimate class of the object. */
133  if (klass == NULL)
134  klass = G_OBJECT_GET_CLASS(object);
135  name = g_type_name(G_TYPE_FROM_CLASS(klass));
136 
137  //printf("Enter %s: object %p of type %s\n", G_STRFUNC, object, name);
138  table = gnc_gobject_tracking_table();
139  list = g_hash_table_lookup(table, name);
140 
141  if (g_list_index(list, object) != -1)
142  {
143  g_critical("Object %p is already in list of %s", object, name);
144  //printf("Leave %s: already in list\n", G_STRFUNC);
145  return;
146  }
147 
148  list = g_list_append(list, object);
149  g_hash_table_insert(table, g_strdup(name), list);
150 
151  g_object_weak_ref(object, gnc_gobject_weak_cb, NULL);
152  //printf("Leave %s:\n", G_STRFUNC);
153 }
154 
155 
156 static gboolean
157 gnc_gobject_tracking_forget_internal (GObject *object)
158 {
159  GHashTable *table;
160  GList *list, *item;
161  const gchar *name;
162 
163  g_return_val_if_fail(G_IS_OBJECT(object), FALSE);
164 
165  name = G_OBJECT_TYPE_NAME(object);
166  //printf("Enter %s: object %p of type %s\n", G_STRFUNC, object, name);
167  table = gnc_gobject_tracking_table();
168  list = g_hash_table_lookup(table, name);
169  if (!list)
170  {
171  //printf("Leave %s: list for %s objects not found.\n", G_STRFUNC, name);
172  return FALSE;
173  }
174 
175  item = g_list_find(list, object);
176  if (!item)
177  {
178  //printf("Leave %s: object %p not in %s object list.\n", G_STRFUNC,
179  // object, name);
180  return FALSE;
181  }
182 
183  list = g_list_remove_link(list, item);
184  if (list)
185  {
186  g_hash_table_replace(table, g_strdup(name), list);
187  //printf("Leave %s: object removed.\n", G_STRFUNC);
188  }
189  else
190  {
191  g_hash_table_remove(table, name);
192  //printf("Leave %s: object and list removed.\n", G_STRFUNC);
193  }
194  return TRUE;
195 }
196 
197 
200 void
202 {
203  if (gnc_gobject_tracking_forget_internal(object))
204  g_object_weak_unref(object, gnc_gobject_weak_cb, NULL);
205 }
206 
207 
217 static void
218 gnc_gobject_weak_cb (gpointer user_data, GObject *object)
219 {
220  gnc_gobject_tracking_forget_internal(object);
221 }
222 
223 
226 const GList *
227 gnc_gobject_tracking_get_list (const gchar *name)
228 {
229  GHashTable *table;
230  GList *list;
231 
232  //printf("Enter %s: name %s\n", G_STRFUNC, name);
233  table = gnc_gobject_tracking_table();
234  list = g_hash_table_lookup(table, name);
235  //printf("Leave %s: list %p\n", G_STRFUNC, list);
236  return list;
237 }
const GList * gnc_gobject_tracking_get_list(const gchar *name)
void gnc_gobject_tracking_dump(void)
void gnc_gobject_tracking_remember(GObject *object, GObjectClass *klass)
void gnc_gobject_tracking_forget(GObject *object)
Gobject helper routines.