summaryrefslogtreecommitdiff
path: root/libnautilus
diff options
context:
space:
mode:
authorDarin Adler <darin@src.gnome.org>2001-03-29 01:39:07 +0000
committerDarin Adler <darin@src.gnome.org>2001-03-29 01:39:07 +0000
commit5df94af1979914c9d676764ad1d37cc7f2665520 (patch)
treeee3cbf871769300687fd81597ee1546465182005 /libnautilus
parent47601ce1d577e9f42e25fb35b62833d802c5f489 (diff)
downloadnautilus-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.c260
-rw-r--r--libnautilus/nautilus-bonobo-workarounds.h19
-rw-r--r--libnautilus/nautilus-view.c16
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;
}