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 | |
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.
-rw-r--r-- | ChangeLog | 53 | ||||
-rw-r--r-- | components/throbber/nautilus-throbber.c | 33 | ||||
-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 | ||||
-rw-r--r-- | src/nautilus-view-frame.c | 151 |
6 files changed, 460 insertions, 72 deletions
@@ -1,3 +1,56 @@ +2001-03-28 Darin Adler <darin@eazel.com> + + 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. + 2001-03-28 Robey Pointer <robey@eazel.com> * components/services/install/command-line/eazel-test-softcat.c: diff --git a/components/throbber/nautilus-throbber.c b/components/throbber/nautilus-throbber.c index cdc636f2a..abf494526 100644 --- a/components/throbber/nautilus-throbber.c +++ b/components/throbber/nautilus-throbber.c @@ -28,25 +28,22 @@ #include <config.h> #include "nautilus-throbber.h" -#include <libgnome/gnome-defs.h> -#include <bonobo.h> - -#include <math.h> -#include <gnome.h> -#include <gdk/gdk.h> #include <gdk-pixbuf/gdk-pixbuf.h> -#include <gtk/gtksignal.h> #include <gtk/gtkmenu.h> #include <gtk/gtkmenuitem.h> +#include <gtk/gtksignal.h> +#include <libgnome/gnome-defs.h> #include <libgnome/gnome-util.h> #include <libgnomeui/gnome-pixmap.h> -#include <libnautilus-extensions/nautilus-gtk-macros.h> -#include <libnautilus-extensions/nautilus-gtk-extensions.h> +#include <libnautilus-extensions/nautilus-file-utilities.h> #include <libnautilus-extensions/nautilus-glib-extensions.h> #include <libnautilus-extensions/nautilus-global-preferences.h> +#include <libnautilus-extensions/nautilus-gtk-extensions.h> +#include <libnautilus-extensions/nautilus-gtk-macros.h> #include <libnautilus-extensions/nautilus-icon-factory.h> -#include <libnautilus-extensions/nautilus-file-utilities.h> #include <libnautilus-extensions/nautilus-theme.h> +#include <libnautilus/nautilus-bonobo-workarounds.h> +#include <math.h> #define THROBBER_DEFAULT_TIMEOUT 100 /* Milliseconds Per Frame */ @@ -188,6 +185,8 @@ static void nautilus_throbber_destroy (GtkObject *object) { NautilusThrobber *throbber = NAUTILUS_THROBBER (object); + + nautilus_bonobo_object_force_destroy_at_idle (throbber->details->control); nautilus_throbber_remove_update_callback (throbber); nautilus_throbber_unload_images (throbber); @@ -247,6 +246,13 @@ get_throbber_dimensions (NautilusThrobber *throbber, int *throbber_width, int* t *throbber_height = current_height; } +static void +null_pointer_callback (GtkObject *object, + gpointer callback_data) +{ + * (gpointer *) callback_data = NULL; +} + /* initialize the throbber */ static void nautilus_throbber_initialize (NautilusThrobber *throbber) @@ -277,7 +283,12 @@ nautilus_throbber_initialize (NautilusThrobber *throbber) } /* make the bonobo control */ - throbber->details->control = (BonoboObject*) bonobo_control_new (widget); + throbber->details->control = BONOBO_OBJECT (bonobo_control_new (widget)); + gtk_signal_connect_while_alive (GTK_OBJECT (throbber->details->control), + "destroy", + null_pointer_callback, + &throbber->details->control, + GTK_OBJECT (throbber)); /* attach a property bag with the configure property */ throbber->details->property_bag = bonobo_property_bag_new (get_bonobo_properties, 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; } diff --git a/src/nautilus-view-frame.c b/src/nautilus-view-frame.c index 92b9155ad..209ca3a66 100644 --- a/src/nautilus-view-frame.c +++ b/src/nautilus-view-frame.c @@ -37,22 +37,16 @@ #include "nautilus-window.h" #include <bonobo/bonobo-zoomable-frame.h> #include <bonobo/bonobo-zoomable.h> -#include <gtk/gtksignal.h> #include <gtk/gtkmain.h> +#include <gtk/gtksignal.h> #include <libnautilus-extensions/nautilus-bonobo-extensions.h> #include <libnautilus-extensions/nautilus-gtk-extensions.h> #include <libnautilus-extensions/nautilus-gtk-macros.h> #include <libnautilus-extensions/nautilus-undo-manager.h> +#include <libnautilus/nautilus-bonobo-workarounds.h> #include <libnautilus/nautilus-idle-queue.h> #include <libnautilus/nautilus-view.h> -/* FIXME bugzilla.eazel.com 2456: Is a hard-coded 12 seconds wait to - * detect that a view is gone acceptable? Can a component that is - * working still take 12 seconds to respond? - */ -/* Milliseconds */ -#define VIEW_RESPONSE_TIMEOUT 12000 - enum { CHANGE_SELECTION, CHANGE_STATUS, @@ -101,13 +95,12 @@ struct NautilusViewFrameDetails { BonoboUIContainer *ui_container; NautilusUndoManager *undo_manager; - guint check_if_view_is_gone_timeout_id; - NautilusBonoboActivationHandle *activation_handle; NautilusIdleQueue *idle_queue; - guint view_frame_failed_id; + guint failed_idle_id; + guint socket_gone_idle_id; }; static void nautilus_view_frame_initialize (NautilusViewFrame *view); @@ -339,6 +332,8 @@ destroy_view (NautilusViewFrame *view) bonobo_object_release_unref (view->details->view, NULL); view->details->view = CORBA_OBJECT_NIL; + nautilus_bonobo_object_call_when_remote_object_disappears + (view->details->view_frame, CORBA_OBJECT_NIL, NULL, NULL); bonobo_object_unref (view->details->view_frame); view->details->view_frame = NULL; view->details->control_frame = NULL; @@ -349,11 +344,6 @@ destroy_view (NautilusViewFrame *view) } bonobo_object_unref (BONOBO_OBJECT (view->details->ui_container)); view->details->ui_container = NULL; - - if (view->details->check_if_view_is_gone_timeout_id != 0) { - g_source_remove (view->details->check_if_view_is_gone_timeout_id); - view->details->check_if_view_is_gone_timeout_id = 0; - } } static void @@ -368,9 +358,13 @@ nautilus_view_frame_destroy (GtkObject *object) nautilus_idle_queue_destroy (view->details->idle_queue); - if (view->details->view_frame_failed_id != 0) { - gtk_idle_remove (view->details->view_frame_failed_id); - view->details->view_frame_failed_id = 0; + if (view->details->failed_idle_id != 0) { + gtk_idle_remove (view->details->failed_idle_id); + view->details->failed_idle_id = 0; + } + if (view->details->socket_gone_idle_id != 0) { + gtk_idle_remove (view->details->socket_gone_idle_id); + view->details->socket_gone_idle_id = 0; } /* It's good to be in "failed" state while shutting down @@ -581,31 +575,6 @@ nautilus_view_frame_new (BonoboUIContainer *ui_container, return view_frame; } -static gboolean -check_if_view_is_gone (gpointer callback_data) -{ - NautilusViewFrame *view; - CORBA_Environment ev; - gboolean view_is_gone; - - view = NAUTILUS_VIEW_FRAME (callback_data); - - CORBA_exception_init (&ev); - view_is_gone = CORBA_Object_non_existent (view->details->view, &ev); - if (ev._major != CORBA_NO_EXCEPTION) { - view_is_gone = TRUE; - } - CORBA_exception_free (&ev); - - if (!view_is_gone) { - return TRUE; - } - - view->details->check_if_view_is_gone_timeout_id = 0; - view_frame_failed (view); - return FALSE; -} - static void emit_zoom_parameters_changed_callback (gpointer data, gpointer callback_data) @@ -701,16 +670,13 @@ create_corba_objects (NautilusViewFrame *view) static gboolean -view_frame_failed_callback (gpointer data) +view_frame_failed_callback (gpointer callback_data) { - NautilusViewFrame *view = data; - - g_assert (NAUTILUS_IS_VIEW_FRAME (view)); - - view->details->view_frame_failed_id = 0; + NautilusViewFrame *view; + view = NAUTILUS_VIEW_FRAME (callback_data); + view->details->failed_idle_id = 0; view_frame_failed (view); - return FALSE; } @@ -719,12 +685,74 @@ queue_view_frame_failed (NautilusViewFrame *view) { g_assert (NAUTILUS_IS_VIEW_FRAME (view)); - if (view->details->view_frame_failed_id == 0) - view->details->view_frame_failed_id = + if (view->details->failed_idle_id == 0) + view->details->failed_idle_id = gtk_idle_add (view_frame_failed_callback, view); } static void +view_frame_failed_cover (BonoboObject *object, + gpointer callback_data) +{ + view_frame_failed (NAUTILUS_VIEW_FRAME (callback_data)); +} + +static gboolean +check_socket_gone_idle_callback (gpointer callback_data) +{ + NautilusViewFrame *frame; + GtkWidget *widget; + GList *children; + + frame = NAUTILUS_VIEW_FRAME (callback_data); + + frame->details->socket_gone_idle_id = 0; + + widget = bonobo_control_frame_get_widget (frame->details->control_frame); + + /* This relies on details of the BonoboControlFrame + * implementation, specifically that's there's one level of + * hierarchy between the widget returned by get_widget and the + * actual plug. + */ + children = gtk_container_children (GTK_CONTAINER (widget)); + g_list_free (children); + + /* If there's nothing inside the widget at all, that means + * that the socket went away because the remote plug went away. + */ + if (children == NULL) { + view_frame_failed (frame); + } + + return FALSE; +} + +static void +check_socket_gone_callback (GtkContainer *container, + GtkWidget *widget, + gpointer callback_data) +{ + NautilusViewFrame *frame; + + frame = NAUTILUS_VIEW_FRAME (callback_data); + + /* There are two times the socket will be destroyed in Bonobo. + * One is when a local control decides to not use the socket. + * The other is when the remote plug goes away. The way to + * tell these apart is to wait until idle time. At idle time, + * if there's nothing in the container, then that means the + * real socket went away. If it was just the local control + * deciding not to use the socket, there will be another + * widget in there. + */ + if (frame->details->socket_gone_idle_id == 0) { + frame->details->socket_gone_idle_id = gtk_idle_add + (check_socket_gone_idle_callback, callback_data); + } +} + +static void attach_view (NautilusViewFrame *view, BonoboObjectClient *client) { @@ -745,6 +773,8 @@ attach_view (NautilusViewFrame *view, create_corba_objects (view); + widget = bonobo_control_frame_get_widget (view->details->control_frame); + gtk_signal_connect_object_while_alive (GTK_OBJECT (view->details->view_frame), "destroy", @@ -759,6 +789,12 @@ attach_view (NautilusViewFrame *view, "system_exception", queue_view_frame_failed, GTK_OBJECT (view)); + gtk_signal_connect_while_alive + (GTK_OBJECT (widget), + "remove", + check_socket_gone_callback, view, + GTK_OBJECT (view)); + if (view->details->zoomable_frame != NULL) { gtk_signal_connect_object_while_alive (GTK_OBJECT (view->details->zoomable_frame), @@ -777,15 +813,16 @@ attach_view (NautilusViewFrame *view, GTK_OBJECT (view)); } - widget = bonobo_control_frame_get_widget (view->details->control_frame); gtk_widget_show (widget); gtk_container_add (GTK_CONTAINER (view), widget); view_frame_activated (view); - g_assert (view->details->check_if_view_is_gone_timeout_id == 0); - view->details->check_if_view_is_gone_timeout_id - = g_timeout_add (VIEW_RESPONSE_TIMEOUT, check_if_view_is_gone, view); + nautilus_bonobo_object_call_when_remote_object_disappears + (view->details->view_frame, + view->details->view, + view_frame_failed_cover, + view); } static void |