GnuCash  4.14+
gnc-gobject-utils.c
1 /*
2  * gnc-gobject-utils.h -- utility functions for working
3  * with GObjects
4  * Copyright (C) 2005 David Hampton <hampton@employees.org>
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 gnu@gnu.org
22  */
23 
24 #include <config.h>
25 
26 #include <stdio.h>
27 #include "gnc-gobject-utils.h"
28 #include <qoflog.h>
29 
30 #include <gtk/gtk.h> // For gtk_main_quit(). Can't get this to work with
31 // a g_source attached to the main glib context.
32 
33 static const QofLogModule log_module = G_LOG_DOMAIN;
34 
35 static void gnc_gobject_weak_cb (gpointer user_data, GObject *object);
36 
37 /************************************************************/
38 /* GObject Utilities */
39 /************************************************************/
40 
41 
50 static GHashTable*
51 gnc_gobject_tracking_table (void)
52 {
53  static GHashTable *singleton = NULL;
54 
55  if (!singleton)
56  {
57  singleton = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, NULL);
58  }
59  return singleton;
60 }
61 
62 
71 static void
72 gnc_gobject_dump_gobject (GObject *object, const gchar *name)
73 {
74  //printf("Enter %s: object %p, name %s\n", G_STRFUNC, object, name);
75  PINFO(" object %p, ref count %d", object, object->ref_count);
76  //printf("Leave %s:\n", G_STRFUNC);
77 }
78 
79 
86 static gboolean
87 gnc_gobject_dump_list (const gchar *name, GList *list, gpointer user_data)
88 {
89  //printf("Enter %s: name %s, list %p\n", G_STRFUNC, name, list);
90  PINFO(" %d %s", g_list_length(list), name);
91  g_list_foreach(list, (GFunc)gnc_gobject_dump_gobject, (gpointer)name);
92  //printf("Leave %s:\n", G_STRFUNC);
93  return TRUE;
94 }
95 
96 
103 void
105 {
106  GHashTable *table;
107 
108  //printf("Enter %s:\n", G_STRFUNC);
109  table = gnc_gobject_tracking_table();
110 
111  if (g_hash_table_size(table) > 0)
112  {
113  PINFO("The following objects remain alive:");
114  g_hash_table_foreach_remove(table, (GHRFunc)gnc_gobject_dump_list, NULL);
115  }
116  //printf("Leave %s:\n", G_STRFUNC);
117 }
118 
119 
122 void
123 gnc_gobject_tracking_remember (GObject *object, GObjectClass *klass)
124 {
125  GHashTable *table;
126  GList *list;
127  const gchar *name;
128 
129  g_return_if_fail(G_IS_OBJECT(object));
130 
131  /* Little dance here to handle startup conditions. During object
132  * initialization the object type changes as each parent class
133  * is initialized. The class passed to the initialization function
134  * is always the ultimate class of the object. */
135  if (klass == NULL)
136  klass = G_OBJECT_GET_CLASS(object);
137  name = g_type_name(G_TYPE_FROM_CLASS(klass));
138 
139  //printf("Enter %s: object %p of type %s\n", G_STRFUNC, object, name);
140  table = gnc_gobject_tracking_table();
141  list = g_hash_table_lookup(table, name);
142 
143  if (g_list_index(list, object) != -1)
144  {
145  g_critical("Object %p is already in list of %s", object, name);
146  //printf("Leave %s: already in list\n", G_STRFUNC);
147  return;
148  }
149 
150  list = g_list_append(list, object);
151  g_hash_table_insert(table, g_strdup(name), list);
152 
153  g_object_weak_ref(object, gnc_gobject_weak_cb, NULL);
154  //printf("Leave %s:\n", G_STRFUNC);
155 }
156 
157 
158 static gboolean
159 gnc_gobject_tracking_forget_internal (GObject *object)
160 {
161  GHashTable *table;
162  GList *list, *item;
163  const gchar *name;
164 
165  g_return_val_if_fail(G_IS_OBJECT(object), FALSE);
166 
167  name = G_OBJECT_TYPE_NAME(object);
168  //printf("Enter %s: object %p of type %s\n", G_STRFUNC, object, name);
169  table = gnc_gobject_tracking_table();
170  list = g_hash_table_lookup(table, name);
171  if (!list)
172  {
173  //printf("Leave %s: list for %s objects not found.\n", G_STRFUNC, name);
174  return FALSE;
175  }
176 
177  item = g_list_find(list, object);
178  if (!item)
179  {
180  //printf("Leave %s: object %p not in %s object list.\n", G_STRFUNC,
181  // object, name);
182  return FALSE;
183  }
184 
185  list = g_list_remove_link(list, item);
186  if (list)
187  {
188  g_hash_table_replace(table, g_strdup(name), list);
189  //printf("Leave %s: object removed.\n", G_STRFUNC);
190  }
191  else
192  {
193  g_hash_table_remove(table, name);
194  //printf("Leave %s: object and list removed.\n", G_STRFUNC);
195  }
196  return TRUE;
197 }
198 
199 
202 void
204 {
205  if (gnc_gobject_tracking_forget_internal(object))
206  g_object_weak_unref(object, gnc_gobject_weak_cb, NULL);
207 }
208 
209 
219 static void
220 gnc_gobject_weak_cb (gpointer user_data, GObject *object)
221 {
222  gnc_gobject_tracking_forget_internal(object);
223 }
224 
225 
228 const GList *
229 gnc_gobject_tracking_get_list (const gchar *name)
230 {
231  GHashTable *table;
232  GList *list;
233 
234  //printf("Enter %s: name %s\n", G_STRFUNC, name);
235  table = gnc_gobject_tracking_table();
236  list = g_hash_table_lookup(table, name);
237  //printf("Leave %s: list %p\n", G_STRFUNC, list);
238  return list;
239 }
const GList * gnc_gobject_tracking_get_list(const gchar *name)
Get a list of all known objects of a specified type.
void gnc_gobject_tracking_dump(void)
Dump the entire object tracking database via the g_log() family of functions.
#define G_LOG_DOMAIN
Functions providing the SX List as a plugin page.
#define PINFO(format, args...)
Print an informational note.
Definition: qoflog.h:256
void gnc_gobject_tracking_remember(GObject *object, GObjectClass *klass)
Tell gnucash to remember this object in the database.
void gnc_gobject_tracking_forget(GObject *object)
Tell gnucash to remember this object in the database.
Gobject helper routines.