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 | |
---|
32 | typedef struct { |
---|
33 | gboolean emitted_last_unref; |
---|
34 | GHashTable *objects; |
---|
35 | GHashTable *keys; |
---|
36 | } BonoboRunningInfo; |
---|
37 | |
---|
38 | BonoboRunningInfo *bonobo_running_info = NULL; |
---|
39 | BonoboObject *bonobo_running_context = NULL; |
---|
40 | BonoboEventSource *bonobo_running_event_source = NULL; |
---|
41 | |
---|
42 | enum { |
---|
43 | LAST_UNREF, |
---|
44 | LAST_SIGNAL |
---|
45 | }; |
---|
46 | |
---|
47 | static guint signals [LAST_SIGNAL] = { 0 }; |
---|
48 | |
---|
49 | static void |
---|
50 | key_free (gpointer name, gpointer dummy1, gpointer user_data) |
---|
51 | { |
---|
52 | g_free (name); |
---|
53 | } |
---|
54 | |
---|
55 | #ifdef BONOBO_RUNNING_HOOKS |
---|
56 | static void |
---|
57 | bonobo_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 | |
---|
70 | static void |
---|
71 | bonobo_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 | |
---|
80 | static void |
---|
81 | running_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 | |
---|
118 | static void |
---|
119 | check_destroy (BonoboObject *object, |
---|
120 | gpointer dummy) |
---|
121 | { |
---|
122 | bonobo_running_context = NULL; |
---|
123 | bonobo_running_event_source = NULL; |
---|
124 | } |
---|
125 | |
---|
126 | static BonoboRunningInfo * |
---|
127 | get_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 | |
---|
141 | static void |
---|
142 | check_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 |
---|
167 | void |
---|
168 | bonobo_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 |
---|
182 | void |
---|
183 | bonobo_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 |
---|
200 | void |
---|
201 | bonobo_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 | |
---|
215 | void |
---|
216 | bonobo_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 | |
---|
251 | static void |
---|
252 | impl_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 | |
---|
259 | static void |
---|
260 | impl_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 | |
---|
267 | static void |
---|
268 | impl_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 | |
---|
285 | static void |
---|
286 | impl_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 | |
---|
304 | static void |
---|
305 | impl_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 | |
---|
312 | static void |
---|
313 | bonobo_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 | |
---|
335 | static void |
---|
336 | bonobo_running_context_init (GtkObject *object) |
---|
337 | { |
---|
338 | /* nothing to do */ |
---|
339 | } |
---|
340 | |
---|
341 | BONOBO_X_TYPE_FUNC_FULL (BonoboRunningContext, |
---|
342 | Bonobo_RunningContext, |
---|
343 | PARENT_TYPE, |
---|
344 | bonobo_running_context); |
---|
345 | |
---|
346 | BonoboObject * |
---|
347 | bonobo_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 | |
---|
370 | BonoboObject * |
---|
371 | bonobo_context_running_get (void) |
---|
372 | { |
---|
373 | return bonobo_running_context_new (); |
---|
374 | } |
---|
375 | |
---|
376 | static void |
---|
377 | last_unref_cb (gpointer context, |
---|
378 | CORBA_Object object) |
---|
379 | { |
---|
380 | bonobo_object_release_unref (object, NULL); |
---|
381 | } |
---|
382 | |
---|
383 | void |
---|
384 | bonobo_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 | |
---|
402 | static void |
---|
403 | last_unref_exit_cb (gpointer context, |
---|
404 | BonoboObject *object) |
---|
405 | { |
---|
406 | bonobo_object_unref (object); |
---|
407 | gtk_main_quit (); |
---|
408 | } |
---|
409 | |
---|
410 | void |
---|
411 | bonobo_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 | |
---|