source: trunk/third/bonobo/bonobo/bonobo-running-context.c @ 16855

Revision 16855, 9.7 KB checked in by ghudson, 23 years ago (diff)
This commit was generated by cvs2svn to compensate for changes in r16854, which included commits to RCS files with non-trunk default branches.
Line 
1/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
2/**
3 * bonobo-running-context.c: A global running interface
4 *
5 * Author:
6 *      Michael Meeks (michael@helixcode.com)
7 *
8 * Copyright (C) 2000, Helix Code, Inc.
9 */
10#include <config.h>
11#include <stdio.h>
12#include <gtk/gtkmain.h>
13#include <gtk/gtksignal.h>
14
15#include <bonobo/bonobo-context.h>
16#include <bonobo/bonobo-exception.h>
17#include <bonobo/bonobo-event-source.h>
18#include <bonobo/bonobo-moniker-util.h>
19#include <bonobo/bonobo-running-context.h>
20
21#define PARENT_TYPE BONOBO_X_OBJECT_TYPE
22
23#ifdef BONOBO_OBJECT_DEBUG
24#       define BONOBO_RUNNING_HOOKS
25#endif
26
27/*
28 * NB. for a quicker debugging experience simply
29 * #define BONOBO_RUNNING_HOOKS
30 */
31
32typedef struct {
33        gboolean    emitted_last_unref;
34        GHashTable *objects;
35        GHashTable *keys;
36} BonoboRunningInfo;
37
38BonoboRunningInfo *bonobo_running_info = NULL;
39BonoboObject      *bonobo_running_context = NULL;
40BonoboEventSource *bonobo_running_event_source = NULL;
41
42enum {
43        LAST_UNREF,
44        LAST_SIGNAL
45};
46
47static guint signals [LAST_SIGNAL] = { 0 };
48
49static void
50key_free (gpointer name, gpointer dummy1, gpointer user_data)
51{
52        g_free (name);
53}
54
55#ifdef BONOBO_RUNNING_HOOKS
56static void
57bonobo_debug_print (char *name, char *fmt, ...)
58{
59        va_list args;
60           
61        va_start (args, fmt);
62       
63        printf ("[%06d]:%-15s ", getpid (), name);
64        vprintf (fmt, args);
65        printf ("\n");
66
67        va_end (args);
68}
69
70static void
71bonobo_ri_debug_foreach (gpointer key, gpointer value, gpointer user_data)
72{
73        CORBA_Object *o = value;
74       
75        bonobo_debug_print ("", "[%p]:CORBA_Object still running", o);
76               
77}
78#endif
79
80static void
81running_info_destroy (void)
82{
83        if (bonobo_running_info) {
84
85                BonoboRunningInfo *ri = bonobo_running_info;
86
87#ifdef BONOBO_RUNNING_HOOKS
88                bonobo_debug_print ("rinfo-start",
89                          "-------------------------------------------------");
90
91                bonobo_debug_print ("running-objects", "%d running objects",
92                                    g_hash_table_size (ri->objects));
93                g_hash_table_foreach (ri->objects,
94                                      bonobo_ri_debug_foreach, NULL);
95                bonobo_debug_print ("rinfo-end",
96                          "-------------------------------------------------");
97#endif
98                if (ri->objects)
99                        g_hash_table_destroy (ri->objects);
100                ri->objects = NULL;
101
102                if (ri->keys) {
103                        g_hash_table_foreach_remove (
104                                ri->keys, (GHRFunc) key_free, NULL);
105                        g_hash_table_destroy (ri->keys);
106                        ri->keys = NULL;
107                }
108                g_free (ri);
109        }
110        bonobo_running_info = NULL;
111
112        if (bonobo_running_context)
113                bonobo_object_unref (BONOBO_OBJECT (bonobo_running_context));
114        bonobo_running_context = NULL;
115        bonobo_running_event_source = NULL;
116}
117
118static void
119check_destroy (BonoboObject *object,
120               gpointer      dummy)
121{
122        bonobo_running_context = NULL;
123        bonobo_running_event_source = NULL;
124}
125
126static BonoboRunningInfo *
127get_running_info (gboolean create)
128{
129        if (!bonobo_running_info && create) {
130                bonobo_running_info = g_new (BonoboRunningInfo, 1);
131                bonobo_running_info->objects = g_hash_table_new (NULL, NULL);
132                bonobo_running_info->keys    = g_hash_table_new (g_str_hash, g_str_equal);
133                bonobo_running_info->emitted_last_unref = FALSE;
134
135                g_atexit (running_info_destroy);
136        }
137
138        return bonobo_running_info;
139}
140
141static void
142check_empty (void)
143{
144        BonoboRunningInfo *ri = get_running_info (FALSE);
145
146        if (!ri || !bonobo_running_context)
147                return;
148
149        if (!ri->emitted_last_unref &&
150            (g_hash_table_size (ri->objects) == 0) &&
151            (g_hash_table_size (ri->keys) == 0)) {
152
153                ri->emitted_last_unref = TRUE;
154
155                gtk_signal_emit (GTK_OBJECT (bonobo_running_context),
156                                 signals [LAST_UNREF]);
157
158                g_return_if_fail (bonobo_running_event_source != NULL);
159
160                bonobo_event_source_notify_listeners (
161                        bonobo_running_event_source,
162                        "bonobo:last_unref", NULL, NULL);
163        }
164}
165
166#ifndef bonobo_running_context_add_object
167void
168bonobo_running_context_add_object (CORBA_Object object)
169{
170#ifdef BONOBO_RUNNING_HOOKS
171        bonobo_running_context_trace_objects (object, "local", 0, 0);
172#else
173        BonoboRunningInfo *ri = get_running_info (TRUE);
174
175        g_hash_table_insert (ri->objects, object, object);
176#endif
177}
178#endif
179
180
181#ifndef bonobo_running_context_remove_object
182void
183bonobo_running_context_remove_object (CORBA_Object object)
184{
185#ifdef BONOBO_RUNNING_HOOKS
186        bonobo_running_context_trace_objects (object, "local", 0, 1);
187#else
188        BonoboRunningInfo *ri = get_running_info (FALSE);
189
190        if (ri) {
191                g_hash_table_remove (ri->objects, object);
192
193                check_empty ();
194        }
195#endif
196}
197#endif
198
199#ifndef bonobo_running_context_ignore_object
200void
201bonobo_running_context_ignore_object (CORBA_Object object)
202{
203#ifdef BONOBO_RUNNING_HOOKS
204        bonobo_running_context_trace_objects (object, "local", 0, 2);
205#else
206        BonoboRunningInfo *ri = get_running_info (FALSE);
207
208        if (ri) {
209                g_hash_table_remove (ri->objects, object);
210        }
211#endif
212}
213#endif
214
215void         
216bonobo_running_context_trace_objects (CORBA_Object object,
217                                      const char  *fn,
218                                      int          line,
219                                      int          mode)
220{
221        BonoboRunningInfo *ri = get_running_info (mode == 0);
222#ifdef BONOBO_RUNNING_HOOKS
223        char *cmode[] = {
224                "add_object",
225                "remove_object",
226                "ignore_object"         
227        };
228#endif
229        if (ri) {
230                switch (mode) {
231                case 0:
232                        g_hash_table_insert (ri->objects, object, object);
233                        break;
234                case 1:
235                        g_hash_table_remove (ri->objects, object);
236
237                        check_empty ();
238                        break;
239                case 2:
240                        g_hash_table_remove (ri->objects, object);
241                        break;
242                }
243#ifdef BONOBO_RUNNING_HOOKS
244                bonobo_debug_print (cmode [mode],
245                        "[%p]:CORBA_Object %d running objects at %s:%d",
246                        object, g_hash_table_size (ri->objects), fn, line);
247#endif
248        }
249}
250
251static void
252impl_Bonobo_RunningContext_addObject (PortableServer_Servant servant,
253                                      const CORBA_Object     object,
254                                      CORBA_Environment     *ev)
255{
256        bonobo_running_context_add_object (object);
257}
258
259static void
260impl_Bonobo_RunningContext_removeObject (PortableServer_Servant servant,
261                                         const CORBA_Object     object,
262                                         CORBA_Environment     *ev)
263{
264        bonobo_running_context_remove_object (object);
265}
266
267static void
268impl_Bonobo_RunningContext_addKey (PortableServer_Servant servant,
269                                   const CORBA_char      *key,
270                                   CORBA_Environment     *ev)
271{
272        char              *key_copy, *old_key;
273        BonoboRunningInfo *ri = get_running_info (TRUE);
274
275        old_key = g_hash_table_lookup (ri->keys, key);
276        if (old_key) {
277                g_free (old_key);
278                g_hash_table_remove (ri->keys, key);
279        }
280        key_copy = g_strdup (key);
281
282        g_hash_table_insert (ri->keys, key_copy, key_copy);
283}
284
285static void
286impl_Bonobo_RunningContext_removeKey (PortableServer_Servant servant,
287                                      const CORBA_char      *key,
288                                      CORBA_Environment     *ev)
289{
290        BonoboRunningInfo *ri = get_running_info (FALSE);
291        char              *old_key;
292
293        if (!ri)
294                return;
295
296        old_key = g_hash_table_lookup (ri->keys, key);
297        if (old_key)
298                g_free (old_key);
299        g_hash_table_remove (ri->keys, key);
300
301        check_empty ();
302}
303
304static void
305impl_Bonobo_RunningContext_atExitUnref (PortableServer_Servant servant,
306                                        const CORBA_Object     object,
307                                        CORBA_Environment     *ev)
308{
309        bonobo_running_context_at_exit_unref (object);
310}
311
312static void
313bonobo_running_context_class_init (BonoboRunningContextClass *klass)
314{
315        GtkObjectClass *object_class = (GtkObjectClass *) klass;
316        POA_Bonobo_RunningContext__epv *epv = &klass->epv;
317
318        ((BonoboRunningContextClass *)klass)->last_unref = NULL;
319
320        signals [LAST_UNREF] = gtk_signal_new (
321                "last_unref", GTK_RUN_FIRST, object_class->type,
322                GTK_SIGNAL_OFFSET (BonoboRunningContextClass, last_unref),
323                gtk_marshal_NONE__NONE, GTK_TYPE_NONE, 0);
324
325        gtk_object_class_add_signals (object_class, signals, LAST_SIGNAL);
326
327        epv->addObject     = impl_Bonobo_RunningContext_addObject;
328        epv->removeObject  = impl_Bonobo_RunningContext_removeObject;
329        epv->addKey        = impl_Bonobo_RunningContext_addKey;
330        epv->removeKey     = impl_Bonobo_RunningContext_removeKey;
331        epv->atExitUnref   = impl_Bonobo_RunningContext_atExitUnref;
332
333}
334
335static void
336bonobo_running_context_init (GtkObject *object)
337{
338        /* nothing to do */
339}
340
341BONOBO_X_TYPE_FUNC_FULL (BonoboRunningContext,
342                         Bonobo_RunningContext,
343                         PARENT_TYPE,
344                         bonobo_running_context);
345
346BonoboObject *
347bonobo_running_context_new (void)
348{
349        if (bonobo_running_context) {
350                bonobo_object_ref (bonobo_running_context);
351                return bonobo_running_context;
352        }
353
354        bonobo_running_context = gtk_type_new (bonobo_running_context_get_type ());
355
356        bonobo_running_event_source = bonobo_event_source_new ();
357        bonobo_running_context_ignore_object (
358                BONOBO_OBJREF (bonobo_running_event_source));
359        bonobo_event_source_ignore_listeners (bonobo_running_event_source);
360
361        bonobo_object_add_interface (BONOBO_OBJECT (bonobo_running_context),
362                                     BONOBO_OBJECT (bonobo_running_event_source));
363
364        gtk_signal_connect (GTK_OBJECT (bonobo_running_context), "destroy",
365                            (GtkSignalFunc) check_destroy, NULL);
366
367        return bonobo_running_context;
368}
369
370BonoboObject *
371bonobo_context_running_get (void)
372{
373        return bonobo_running_context_new ();
374}
375
376static void
377last_unref_cb (gpointer      context,
378               CORBA_Object  object)
379{
380        bonobo_object_release_unref (object, NULL);
381}
382
383void
384bonobo_running_context_at_exit_unref (CORBA_Object object)
385{
386        CORBA_Environment ev;
387        CORBA_Object obj_dup;
388
389        CORBA_exception_init (&ev);
390
391        obj_dup = CORBA_Object_duplicate (object, &ev);
392
393        bonobo_running_context_ignore_object (obj_dup);
394
395        if (bonobo_running_context)
396                gtk_signal_connect (GTK_OBJECT (bonobo_running_context),
397                                    "last_unref", last_unref_cb, obj_dup);
398       
399        CORBA_exception_free (&ev);
400}
401
402static void
403last_unref_exit_cb (gpointer      context,
404                    BonoboObject *object)
405{
406        bonobo_object_unref (object);
407        gtk_main_quit ();
408}
409
410void
411bonobo_running_context_auto_exit_unref (BonoboObject *object)
412{
413        g_return_if_fail (object != NULL);
414        g_return_if_fail (BONOBO_IS_OBJECT (object));
415
416        bonobo_running_context_ignore_object (BONOBO_OBJREF (object));
417
418        if (bonobo_running_context)
419                gtk_signal_connect (GTK_OBJECT (bonobo_running_context),
420                                    "last_unref", last_unref_exit_cb, object);
421
422}
423
Note: See TracBrowser for help on using the repository browser.