diff options
author | Darin Adler <darin@src.gnome.org> | 2001-03-29 01:39:07 +0000 |
---|---|---|
committer | Darin Adler <darin@src.gnome.org> | 2001-03-29 01:39:07 +0000 |
commit | 5df94af1979914c9d676764ad1d37cc7f2665520 (patch) | |
tree | ee3cbf871769300687fd81597ee1546465182005 /libnautilus | |
parent | 47601ce1d577e9f42e25fb35b62833d802c5f489 (diff) | |
download | nautilus-5df94af1979914c9d676764ad1d37cc7f2665520.tar.gz |
reviewed by: John Sullivan <sullivan@eazel.com>
A change to reduce the number of orphaned processes when Nautilus
is not terminated cleanly. This is an architecture problem, and
this hack only partly addresses it.
Add code to NautilusViewFrame, NautilusView, and NautilusThrobber
to destroy components when the corresponding widgets are
destroyed. Since X destroys windows when processes go away, this
tells us immediately when processes disappear. This does not help
in the case where Nautilus happens to die after creating a
component, but before attaching the widget to its parent.
This is not a complete solution to the orphaned processes problem
because of 2 other categories of orphaned processes:
1) the adapter factory
2) non-NautilusView components, which won't get the advantage
of this fix because it's in Nautilus (a fix could go into
Bonobo, or into each component)
* libnautilus/nautilus-bonobo-workarounds.h:
* libnautilus/nautilus-bonobo-workarounds.c:
(set_gone_flag), (nautilus_bonobo_object_force_destroy),
(object_is_gone), (remote_check_data_free),
(remote_check_timed_callback), (remote_check_destroy_callback),
(nautilus_bonobo_object_call_when_remote_object_disappears),
(force_destroy_cover),
(nautilus_bonobo_object_force_destroy_when_owner_disappears):
New code, implementing the machinery to notice when remote objects
go away and to self-destruct when they do. Also code that does the
timeout that used to be in NautilusViewFrame.
* libnautilus/nautilus-view.c: (widget_destroyed_callback),
(nautilus_view_construct_from_bonobo_control): Connect to the
widget's destroy signal, and self-destruct when it happens.
* components/throbber/nautilus-throbber.c:
(nautilus_throbber_destroy), (null_pointer_callback),
(nautilus_throbber_initialize): Destroy the BonoboControl when the
throbber (a widget) is destroyed. Requires noticing when the
control goes away (the old code just had a stale pointer to it).
* src/nautilus-view-frame.c: (destroy_view),
(nautilus_view_frame_destroy), (view_frame_failed_callback),
(queue_view_frame_failed), (view_frame_failed_cover),
(check_socket_gone_idle_callback), (check_socket_gone_callback),
(attach_view): Use the new machinery instead of doing it
ourselves, but sadly had to add some fairly complex code to catch
the case where the socket is destroyed because the plug is gone.
Diffstat (limited to 'libnautilus')
-rw-r--r-- | libnautilus/nautilus-bonobo-workarounds.c | 260 | ||||
-rw-r--r-- | libnautilus/nautilus-bonobo-workarounds.h | 19 | ||||
-rw-r--r-- | libnautilus/nautilus-view.c | 16 |
3 files changed, 291 insertions, 4 deletions
diff --git a/libnautilus/nautilus-bonobo-workarounds.c b/libnautilus/nautilus-bonobo-workarounds.c index 5e1c48308..5655ac4ad 100644 --- a/libnautilus/nautilus-bonobo-workarounds.c +++ b/libnautilus/nautilus-bonobo-workarounds.c @@ -3,7 +3,7 @@ /* * libnautilus: A library for nautilus view implementations. * - * Copyright (C) 2000 Eazel, Inc. + * Copyright (C) 2000, 2001 Eazel, Inc. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public @@ -27,6 +27,31 @@ #include "nautilus-bonobo-workarounds.h" #include <bonobo/bonobo-stream.h> +#include <gtk/gtkmain.h> +#include <gtk/gtksignal.h> + +/* FIXME bugzilla.eazel.com 2456: Is a hard-coded 20 seconds wait to + * detect that a remote object's process is hung acceptable? Can a + * component that is working still take 20 seconds to respond? + */ +/* in milliseconds */ +#define REMOTE_CHECK_TIME_INTERVAL 20000 +#define REMOTE_CHECK_DATA_KEY "nautilus-bonobo-workarounds/RemoteCheckData" + +typedef struct { + BonoboObject *object; + Bonobo_Unknown remote_object; + guint timeout_id; + guint destroy_handler_id; + NautilusBonoboObjectCallback function; + gpointer callback_data; +} RemoteCheckData; + +typedef struct { + BonoboObject *object; + guint idle_id; + guint destroy_handler_id; +} IdleDestroyData; POA_Bonobo_Unknown__epv * nautilus_bonobo_object_get_epv (void) @@ -63,3 +88,236 @@ nautilus_bonobo_stream_get_epv (void) return &bonobo_stream_epv; } + +static void +set_gone_flag (GtkObject *object, + gpointer callback_data) +{ + gboolean *gone_flag; + + gone_flag = callback_data; + *gone_flag = TRUE; +} + +/* The following is the most evil function in the world. But on the + * other hand, it works and prevents us from having tons of lingering + * processes when Nautilus crashes. + */ +void +nautilus_bonobo_object_force_destroy (BonoboObject *object) +{ + gboolean gone; + + if (object == NULL) { + return; + } + + g_return_if_fail (BONOBO_IS_OBJECT (object)); + g_return_if_fail (!GTK_OBJECT_DESTROYED (object)); + + gone = FALSE; + gtk_signal_connect (GTK_OBJECT (object), "destroy", + set_gone_flag, &gone); + do { + bonobo_object_unref (object); + } while (!gone); +} + +static gboolean +destroy_at_idle_callback (gpointer callback_data) +{ + IdleDestroyData *data; + + data = callback_data; + g_assert (BONOBO_IS_OBJECT (data->object)); + + gtk_signal_disconnect (GTK_OBJECT (data->object), + data->destroy_handler_id); + nautilus_bonobo_object_force_destroy (data->object); + g_free (data); + return FALSE; +} + +static void +destroyed_before_idle_callback (GtkObject *object, + gpointer callback_data) +{ + IdleDestroyData *data; + + data = callback_data; + g_assert (data->object == BONOBO_OBJECT (object)); + + gtk_idle_remove (data->idle_id); + g_free (data); +} + +void +nautilus_bonobo_object_force_destroy_at_idle (BonoboObject *object) +{ + IdleDestroyData *data; + + if (object == NULL) { + return; + } + + data = g_new (IdleDestroyData, 1); + data->object = object; + data->idle_id = gtk_idle_add + (destroy_at_idle_callback, data); + data->destroy_handler_id = gtk_signal_connect + (GTK_OBJECT (object), "destroy", + destroyed_before_idle_callback, data); +} + +/* Same as bonobo_unknown_ping, but this one works. */ +static gboolean +object_is_gone (Bonobo_Unknown object) +{ + CORBA_Environment ev; + gboolean gone; + + CORBA_exception_init (&ev); + gone = CORBA_Object_non_existent (object, &ev); + if (ev._major != CORBA_NO_EXCEPTION) { + gone = TRUE; + } + CORBA_exception_free (&ev); + + return gone; +} + +static void +remote_check_data_free (RemoteCheckData *data) +{ + CORBA_Environment ev; + + if (data == NULL) { + return; + } + + gtk_object_remove_data (GTK_OBJECT (data->object), REMOTE_CHECK_DATA_KEY); + + CORBA_exception_init (&ev); + CORBA_Object_release (data->remote_object, &ev); + CORBA_exception_free (&ev); + + if (data->timeout_id != 0) { + g_source_remove (data->timeout_id); + } + + if (data->destroy_handler_id != 0) { + gtk_signal_disconnect (GTK_OBJECT (data->object), + data->destroy_handler_id); + } + + g_free (data); +} + +static gboolean +remote_check_timed_callback (gpointer callback_data) +{ + RemoteCheckData *data; + BonoboObject *object; + NautilusBonoboObjectCallback function; + gpointer function_data; + + data = callback_data; + g_assert (BONOBO_IS_OBJECT (data->object)); + g_assert (!GTK_OBJECT_DESTROYED (data->object)); + g_assert (data->remote_object != CORBA_OBJECT_NIL); + g_assert (data->timeout_id != 0); + g_assert (data->destroy_handler_id != 0); + g_assert (data->function != NULL); + + if (!object_is_gone (data->remote_object)) { + return TRUE; + } + + object = data->object; + function = data->function; + function_data = data->callback_data; + + data->timeout_id = 0; + remote_check_data_free (data); + + (* function) (object, function_data); + + return FALSE; +} + +static void +remote_check_destroy_callback (GtkObject *object, + gpointer callback_data) +{ + RemoteCheckData *data; + + g_assert (BONOBO_IS_OBJECT (object)); + + data = callback_data; + g_assert (data->object == BONOBO_OBJECT (object)); + g_assert (data->remote_object != CORBA_OBJECT_NIL); + g_assert (data->timeout_id != 0); + g_assert (data->destroy_handler_id != 0); + g_assert (data->function != NULL); + + remote_check_data_free (data); +} + +void +nautilus_bonobo_object_call_when_remote_object_disappears (BonoboObject *object, + Bonobo_Unknown remote_object, + NautilusBonoboObjectCallback function, + gpointer callback_data) +{ + RemoteCheckData *data; + CORBA_Environment ev; + + g_return_if_fail (BONOBO_IS_OBJECT (object)); + + data = gtk_object_get_data (GTK_OBJECT (object), REMOTE_CHECK_DATA_KEY); + + if (GTK_OBJECT_DESTROYED (object) + || remote_object == CORBA_OBJECT_NIL + || function == NULL) { + remote_check_data_free (data); + return; + } + + if (data == NULL) { + data = g_new0 (RemoteCheckData, 1); + data->object = object; + } + CORBA_exception_init (&ev); + data->remote_object = CORBA_Object_duplicate (remote_object, &ev); + CORBA_exception_free (&ev); + data->function = function; + data->callback_data = callback_data; + + if (data->timeout_id == 0) { + data->timeout_id = g_timeout_add + (REMOTE_CHECK_TIME_INTERVAL, + remote_check_timed_callback, data); + } + if (data->destroy_handler_id == 0) { + data->destroy_handler_id = gtk_signal_connect + (GTK_OBJECT (object), "destroy", + remote_check_destroy_callback, data); + } + + gtk_object_set_data (GTK_OBJECT (object), REMOTE_CHECK_DATA_KEY, data); +} + +static void +force_destroy_cover (BonoboObject *object, + gpointer callback_data) +{ + nautilus_bonobo_object_force_destroy (object); +} + +void +nautilus_bonobo_object_force_destroy_when_owner_disappears (BonoboObject *object, + Bonobo_Unknown owner) +{ + nautilus_bonobo_object_call_when_remote_object_disappears + (object, owner, force_destroy_cover, NULL); +} diff --git a/libnautilus/nautilus-bonobo-workarounds.h b/libnautilus/nautilus-bonobo-workarounds.h index 134058319..a0282959a 100644 --- a/libnautilus/nautilus-bonobo-workarounds.h +++ b/libnautilus/nautilus-bonobo-workarounds.h @@ -3,7 +3,7 @@ /* * libnautilus: A library for nautilus view implementations. * - * Copyright (C) 2000 Eazel, Inc. + * Copyright (C) 2000, 2001 Eazel, Inc. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public @@ -28,8 +28,21 @@ #include <bonobo/bonobo-object.h> +typedef void (* NautilusBonoboObjectCallback) (BonoboObject *object, + gpointer callback_data); + /* Gets a single global one. */ -POA_Bonobo_Unknown__epv *nautilus_bonobo_object_get_epv (void); -POA_Bonobo_Stream__epv * nautilus_bonobo_stream_get_epv (void); +POA_Bonobo_Unknown__epv *nautilus_bonobo_object_get_epv (void); +POA_Bonobo_Stream__epv * nautilus_bonobo_stream_get_epv (void); + +/* Bonobo will address this problem some day. */ +void nautilus_bonobo_object_force_destroy (BonoboObject *object); +void nautilus_bonobo_object_force_destroy_at_idle (BonoboObject *object); +void nautilus_bonobo_object_call_when_remote_object_disappears (BonoboObject *object, + Bonobo_Unknown remote_object, + NautilusBonoboObjectCallback function, + gpointer callback_data); +void nautilus_bonobo_object_force_destroy_when_owner_disappears (BonoboObject *object, + Bonobo_Unknown owner); #endif /* NAUTILUS_BONOBO_WORKAROUNDS_H */ diff --git a/libnautilus/nautilus-view.c b/libnautilus/nautilus-view.c index 55c9089ff..8ab81c733 100644 --- a/libnautilus/nautilus-view.c +++ b/libnautilus/nautilus-view.c @@ -437,10 +437,21 @@ nautilus_view_construct (NautilusView *view, (view, bonobo_control_new (widget)); } +static void +widget_destroyed_callback (GtkWidget *widget, + gpointer callback_data) +{ + g_assert (NAUTILUS_IS_VIEW (callback_data)); + + nautilus_bonobo_object_force_destroy_at_idle (BONOBO_OBJECT (callback_data)); +} + NautilusView * nautilus_view_construct_from_bonobo_control (NautilusView *view, BonoboControl *control) { + GtkWidget *widget; + g_return_val_if_fail (NAUTILUS_IS_VIEW (view), NULL); g_return_val_if_fail (BONOBO_IS_CONTROL (control), NULL); @@ -448,6 +459,11 @@ nautilus_view_construct_from_bonobo_control (NautilusView *view, bonobo_object_add_interface (BONOBO_OBJECT (view), BONOBO_OBJECT (control)); nautilus_undo_set_up_bonobo_control (control); + widget = bonobo_control_get_widget (control); + gtk_signal_connect_while_alive (GTK_OBJECT (widget), "destroy", + widget_destroyed_callback, view, + GTK_OBJECT (view)); + return view; } |