diff --git a/src/Makefile.am b/src/Makefile.am
index 5e44e4f..c16e26e 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -172,9 +172,6 @@ libmetacityinclude_HEADERS =			\
 metacity_theme_viewer_SOURCES=  \
 	ui/theme-viewer.c
 
-metacity_dialog_SOURCES= 	\
-	ui/metacity-dialog.c
-
 schema_bindings_SOURCES =       \
         core/schema-bindings.c			\
 	metacity.schemas.in.in
@@ -185,7 +182,6 @@ metacity.schemas.in: schema_bindings ${srcdir}/metacity.schemas.in.in
 	${builddir}/schema_bindings ${srcdir}/metacity.schemas.in.in ${builddir}/metacity.schemas.in
 
 bin_PROGRAMS=metacity metacity-theme-viewer
-libexec_PROGRAMS=metacity-dialog
 
 api_version = $(METACITY_MAJOR_VERSION).$(METACITY_MINOR_VERSION)
 
@@ -227,7 +223,6 @@ metacity_LDADD=@METACITY_LIBS@ libmetacity-private.la $(EFENCE)
 metacity_LDFLAGS=-export-dynamic
 
 metacity_theme_viewer_LDADD= @METACITY_LIBS@ libmetacity-private.la
-metacity_dialog_LDADD=@METACITY_LIBS@
 
 testboxes_SOURCES=include/util.h core/util.c include/boxes.h core/boxes.c core/testboxes.c
 testgradient_SOURCES=ui/gradient.h ui/gradient.c ui/testgradient.c
diff --git a/src/core/delete.c b/src/core/delete.c
index abd1fd2..6294423 100644
--- a/src/core/delete.c
+++ b/src/core/delete.c
@@ -55,227 +55,26 @@ delete_ping_reply_func (MetaDisplay *display,
   /* we do nothing */
 }
 
-static Window
-window_from_string (const char *str)
-{
-  char *end;
-  unsigned long l;
-
-  end = NULL;
-  
-  l = strtoul (str, &end, 16);
-
-  if (end == NULL || end == str)
-    {
-      meta_warning (_("Could not parse \"%s\" as an integer"),
-                    str);
-      return None;
-    }
-
-  if (*end != '\0')
-    {
-      meta_warning (_("Did not understand trailing characters \"%s\" in string \"%s\""),
-                    end, str);
-      return None;
-    }
-
-  return l;
-}
-
-static int
-pid_from_string (const char *str)
-{
-  char *end;
-  long l;
-
-  end = NULL;
-  
-  l = strtol (str, &end, 10);
-
-  if (end == NULL || end == str)
-    {
-      meta_warning (_("Could not parse \"%s\" as an integer"),
-                    str);
-      return None;
-    }
-
-  if (*end != '\0')
-    {
-      meta_warning (_("Did not understand trailing characters \"%s\" in string \"%s\""),
-                    end, str);
-      return None;
-    }
-
-  return l;
-}
-
 static gboolean
-parse_dialog_output (const char *str,
-                     int        *pid_out,
-                     Window     *win_out)
+delete_window_callback (gpointer w_p)
 {
-  char **split;
-
-  split = g_strsplit (str, "\n", 2);
-  if (split && split[0] && split[1])
-    {
-      g_strchomp (split[0]);
-      g_strchomp (split[1]);
-
-      *pid_out = pid_from_string (split[0]);
-      *win_out = window_from_string (split[1]);
-
-      g_strfreev (split);
-      
-      return TRUE;
-    }
-  else
-    {
-      g_strfreev (split);
-      meta_warning (_("Failed to parse message \"%s\" from dialog process\n"),
-                    str);
-      return FALSE;
-    }
-}
-
-static void
-search_and_destroy_window (int    pid,
-                           Window xwindow)
-{
-  /* Find the window with the given dialog PID,
-   * double check that it matches "xwindow", then
-   * kill the window.
-   */
-  GSList *tmp;
-  gboolean found = FALSE;
-  GSList *windows;
-
-  if (xwindow == None)
-    {
-      meta_topic (META_DEBUG_PING,
-                  "Window to destroy is None, doing nothing\n");
-      return;
-    }
-
-  windows = meta_display_list_windows (meta_get_display ());
-  tmp = windows;
-
-  while (tmp != NULL)
-    {
-      MetaWindow *w = tmp->data;
+  meta_window_kill ((MetaWindow*) w_p);
 
-      if (w->dialog_pid == pid)
-        {
-          if (w->xwindow != xwindow)
-            meta_topic (META_DEBUG_PING,
-                        "Dialog pid matches but not xwindow (0x%lx vs. 0x%lx)\n",
-                        w->xwindow, xwindow);
-          else
-            {
-              meta_window_kill (w);
-              found = TRUE;
-            }
-        }
-          
-      tmp = tmp->next;
-    }
-
-  g_slist_free (windows);
-  
-  if (!found)
-    meta_topic (META_DEBUG_PING,
-                "Did not find a window with dialog pid %d xwindow 0x%lx\n",
-                pid, xwindow);
+  return FALSE; /* don't do it again */
 }
 
 static void
-release_window_with_fd (int fd)
+sigchld_handler (MetaNexus *nexus, guint arg1, gpointer arg2, gpointer user_data)
 {
-  /* Find the window with the given dialog PID,
-   * double check that it matches "xwindow", then
-   * kill the window.
-   */
-  gboolean found = FALSE;
-  
-  GSList *windows = meta_display_list_windows (meta_get_display ());
-  GSList *tmp = windows;
+  MetaWindow *ours = (MetaWindow*) user_data;
 
-  while (tmp != NULL)
+  if (GPOINTER_TO_INT (arg2) == ours->dialog_pid)
     {
-      MetaWindow *w = tmp->data;
+      if (arg1 == 1 /* pressed "force quit" */)
+        g_idle_add (delete_window_callback, user_data);
 
-      if (w->dialog_pid >= 0 &&
-          w->dialog_pipe == fd)
-        {
-          meta_topic (META_DEBUG_PING,
-                      "Removing dialog with fd %d pid %d from window %s\n",
-                      fd, w->dialog_pid, w->desc);
-          meta_window_free_delete_dialog (w);
-          found = TRUE;
-        }
-       
-      tmp = tmp->next;
+      ours->dialog_pid = -1; /* forget it anyway */
     }
-
-  g_slist_free (windows);
-      
-  if (!found)
-    meta_topic (META_DEBUG_PING,
-                "Did not find a window with a dialog pipe %d\n",
-                fd);
-}
-
-static gboolean  
-io_from_ping_dialog (GIOChannel   *channel,
-                     GIOCondition  condition,
-                     gpointer      data)
-{  
-  meta_topic (META_DEBUG_PING,
-              "IO handler from ping dialog, condition = %x\n",
-              condition);
-  
-  if (condition & G_IO_IN)
-    {
-      char *str;
-      gsize len;
-      GError *err;
-
-      /* Go ahead and block for all data from child */
-      str = NULL;
-      len = 0;
-      err = NULL;
-      g_io_channel_read_to_end (channel,
-                                &str, &len,
-                                &err);
-      
-      if (err)
-        {
-          meta_warning (_("Error reading from dialog display process: %s\n"),
-                        err->message);
-          g_error_free (err);
-        }
-
-      meta_topic (META_DEBUG_PING,
-                  "Read %" G_GSIZE_FORMAT " bytes strlen %d \"%s\" from child\n",
-                  len, str ? (int) strlen (str) : 0, str ? str : "NULL");
-      
-      if (len > 0)
-        {
-          /* We're supposed to kill the given window */
-          int pid;
-          Window xwindow;
-
-          if (parse_dialog_output (str, &pid, &xwindow))
-            search_and_destroy_window (pid, xwindow);
-        }
-
-      g_free (str);
-    }
-
-  release_window_with_fd (g_io_channel_unix_get_fd (channel));
-  
-  /* Remove the callback */
-  return FALSE; 
 }
 
 static void
@@ -285,15 +84,9 @@ delete_ping_timeout_func (MetaDisplay *display,
                           void        *user_data)
 {
   MetaWindow *window = user_data;
-  GError *err;
-  int child_pid;
-  int outpipe;
-  char *argv[9];
-  char numbuf[32];
-  char timestampbuf[32];
-  char *window_id_str;
   char *window_title;
-  GIOChannel *channel;
+  gchar *window_content;
+  GPid dialog_pid;
   
   meta_topic (META_DEBUG_PING,
               "Got delete ping timeout for %s\n",
@@ -304,54 +97,32 @@ delete_ping_timeout_func (MetaDisplay *display,
       meta_window_present_delete_dialog (window, timestamp);
       return;
     }
-  
-  window_id_str = g_strdup_printf ("0x%lx", window->xwindow);
-  window_title = g_locale_from_utf8 (window->title, -1, NULL, NULL, NULL);
 
-  sprintf (numbuf, "%d", window->screen->number);
-  sprintf (timestampbuf, "%u", timestamp);
-  
-  argv[0] = METACITY_LIBEXECDIR"/metacity-dialog";
-  argv[1] = "--screen";
-  argv[2] = numbuf;
-  argv[3] = "--timestamp";
-  argv[4] = timestampbuf;
-  argv[5] = "--kill-window-question";
-  argv[6] = window_title;
-  argv[7] = window_id_str;
-  argv[8] = NULL;
-  
-  err = NULL;
-  if (!g_spawn_async_with_pipes ("/",
-                                 argv,
-                                 NULL,
-                                 0,
-                                 NULL, NULL,
-                                 &child_pid,
-                                 NULL,
-                                 &outpipe,
-                                 NULL,
-                                 &err))
-    {
-      meta_warning (_("Error launching metacity-dialog to ask about killing an application: %s\n"),
-                    err->message);
-      g_error_free (err);
-      goto out;
-    }
+  window_title = g_locale_from_utf8 (window->title, -1, NULL, NULL, NULL);
 
-  window->dialog_pid = child_pid;
-  window->dialog_pipe = outpipe;  
+  window_content = g_strdup_printf(
+      _("<big><b><tt>%s</tt> is not responding.</b></big>\n\n"
+      "<i>You may choose to wait a short while for it to "
+      "continue or force the application to quit entirely.</i>"),
+      window_title);
 
-  channel = g_io_channel_unix_new (window->dialog_pipe);
-  g_io_add_watch_full (channel, G_PRIORITY_DEFAULT,
-                       G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL,
-                       io_from_ping_dialog,
-                       NULL, NULL);
-  g_io_channel_unref (channel);
-  
- out:
   g_free (window_title);
-  g_free (window_id_str);
+
+  dialog_pid =
+    meta_show_dialog ("--question",
+                      window_content, 0,
+                      window->screen->number,
+                      _("_Wait"), _("_Force Quit"), window->xwindow,
+                      NULL, NULL);
+
+  g_free (window_content);
+
+  window->dialog_pid = dialog_pid;
+
+  g_signal_connect (sigchld_nexus, "sigchld",
+                    G_CALLBACK (sigchld_handler),
+                    window);
+
 }
 
 void
@@ -461,9 +232,7 @@ meta_window_free_delete_dialog (MetaWindow *window)
   if (window->dialog_pid >= 0)
     {
       kill (window->dialog_pid, 9);
-      close (window->dialog_pipe);
       window->dialog_pid = -1;
-      window->dialog_pipe = -1;
     }
 }
 
diff --git a/src/core/keybindings.c b/src/core/keybindings.c
index 0fe62e4..a99869f 100644
--- a/src/core/keybindings.c
+++ b/src/core/keybindings.c
@@ -2422,6 +2422,7 @@ error_on_command (int         command_index,
                         text,
                         NULL,
                         screen_number,
+                        NULL, NULL, 0,
                         NULL, NULL);
 
       g_free (text);
@@ -2433,6 +2434,7 @@ error_on_command (int         command_index,
                         message,
                         NULL,
                         screen_number,
+                        NULL, NULL, 0,
                         NULL, NULL);
     }
 }
diff --git a/src/core/main.c b/src/core/main.c
index 0fafeaf..52e3279 100644
--- a/src/core/main.c
+++ b/src/core/main.c
@@ -59,6 +59,7 @@
 
 #include <stdlib.h>
 #include <sys/types.h>
+#include <wait.h>
 #include <stdio.h>
 #include <string.h>
 #include <signal.h>
@@ -467,6 +468,29 @@ sigterm_handler (int signum)
 
   exit (meta_exit_code);
 }
+
+static guint sigchld_signal_id = 0;
+
+static void
+sigchld_handler (int signum, siginfo_t *info, void *context)
+{
+  int stat;
+
+  if (info->si_code == CLD_EXITED)
+    {
+      g_signal_emit (sigchld_nexus, sigchld_signal_id, 0,
+                     info->si_status,
+                     GINT_TO_POINTER (info->si_pid));
+    }
+
+  g_signal_handlers_disconnect_matched (sigchld_nexus,
+                                        G_SIGNAL_MATCH_DATA,
+                                        sigchld_signal_id,
+                                        0, NULL, NULL,
+                                        GINT_TO_POINTER (info->si_pid));
+
+  waitpid (info->si_pid, &stat, WNOHANG);
+}
     
 /**
  * This is where the story begins. It parses commandline options and
@@ -497,6 +521,8 @@ main (int argc, char **argv)
   
   if (setlocale (LC_ALL, "") == NULL)
     meta_warning ("Locale not understood by C library, internationalization will not work\n");
+
+  g_type_init ();
   
   sigemptyset (&empty_mask);
   act.sa_handler = SIG_IGN;
@@ -516,6 +542,24 @@ main (int argc, char **argv)
     g_printerr ("Failed to register SIGTERM handler: %s\n",
 		g_strerror (errno));
 
+  sigchld_nexus = g_object_new (META_TYPE_NEXUS, NULL);
+
+  sigchld_signal_id =
+    g_signal_new ("sigchld", META_TYPE_NEXUS,
+                  G_SIGNAL_RUN_LAST,
+                  0, NULL, NULL,
+                  g_cclosure_marshal_VOID__UINT_POINTER,
+                  G_TYPE_NONE,
+                  2,
+                  G_TYPE_UINT, G_TYPE_POINTER);
+  
+  act.sa_flags = SA_NOCLDSTOP | SA_SIGINFO;
+  act.sa_handler = SIG_DFL;
+  act.sa_sigaction = &sigchld_handler;
+  if (sigaction (SIGCHLD, &act, NULL) < 0)
+    g_printerr ("Failed to register SIGCHLD handler: %s\n",
+		g_strerror (errno));
+
   if (g_getenv ("METACITY_VERBOSE"))
     meta_set_verbose (TRUE);
   if (g_getenv ("METACITY_DEBUG"))
diff --git a/src/core/session.c b/src/core/session.c
index f261952..da2c59a 100644
--- a/src/core/session.c
+++ b/src/core/session.c
@@ -1737,13 +1737,6 @@ windows_cmp_by_title (MetaWindow *a,
   return g_utf8_collate (a->title, b->title);
 }
 
-typedef struct
-{
-  int child_pid;
-  int child_pipe;
-  gboolean shutdown;
-} LameClientsDialogData;
-
 static void
 finish_interact (gboolean shutdown)
 {
@@ -1755,63 +1748,26 @@ finish_interact (gboolean shutdown)
     }
 }
 
-static gboolean  
-io_from_warning_dialog (GIOChannel   *channel,
-                        GIOCondition  condition,
-                        gpointer      data)
+static void
+sigchld_handler (MetaNexus *nexus, guint arg1, gpointer arg2, gpointer user_data)
 {
-  LameClientsDialogData *d;
+  gboolean shutdown = GPOINTER_TO_INT (user_data);
 
-  d = data;
-  
-  meta_topic (META_DEBUG_PING,
-              "IO handler from lame clients dialog, condition = %x\n",
-              condition);
-  
-  if (condition & (G_IO_HUP | G_IO_NVAL | G_IO_ERR))
+  if (arg1 == 0) /* pressed "OK" */
     {
-      finish_interact (d->shutdown);
-
-      /* Remove the callback, freeing data */
-      return FALSE; 
-    }
-  else if (condition & G_IO_IN)
-    {
-      /* Check for EOF */
-      
-      char buf[16];
-      int ret;
- 
-      ret = read (d->child_pipe, buf, sizeof (buf));
-      if (ret == 0)
- 	{
- 	  finish_interact (d->shutdown);
- 	  return FALSE;
- 	}
+      finish_interact (shutdown);
     }
-
-  /* Keep callback installed */
-  return TRUE;
 }
 
 static void
 warn_about_lame_clients_and_finish_interact (gboolean shutdown)
 {
-  GSList *lame;
+  GSList *lame = NULL;
   GSList *windows;
-  char **argv;
-  int i;
+  GSList *lame_details = NULL;
   GSList *tmp;
-  int len;
-  int child_pid;
-  int child_pipe;
-  GError *err;
-  GIOChannel *channel;
-  LameClientsDialogData *d;
-  guint32 timestamp;
-  char timestampbuf[32];
-  
-  lame = NULL;
+  GSList *columns = NULL;
+  
   windows = meta_display_list_windows (meta_get_display ());
   tmp = windows;
   while (tmp != NULL)
@@ -1838,77 +1794,43 @@ warn_about_lame_clients_and_finish_interact (gboolean shutdown)
       finish_interact (shutdown);
       return;
     }
-  
-  lame = g_slist_sort (lame, (GCompareFunc) windows_cmp_by_title);
 
-  timestamp = meta_display_get_current_time_roundtrip (meta_get_display ());
-  sprintf (timestampbuf, "%u", timestamp);
+  columns = g_slist_prepend (columns, "Window");
+  columns = g_slist_prepend (columns, "Class");
 
-  len = g_slist_length (lame);
-  len *= 2; /* titles and also classes */
-  len += 2; /* --timestamp flag and actual timestamp */
-  len += 1; /* NULL term */
-  len += 2; /* metacity-dialog command and option */
-  
-  argv = g_new0 (char*, len);
-  
-  i = 0;
+  lame = g_slist_sort (lame, (GCompareFunc) windows_cmp_by_title);
 
-  argv[i] = METACITY_LIBEXECDIR"/metacity-dialog";
-  ++i;
-  argv[i] = "--timestamp";
-  ++i;
-  argv[i] = timestampbuf;
-  ++i;
-  argv[i] = "--warn-about-no-sm-support";
-  ++i;
-  
   tmp = lame;
   while (tmp != NULL)
     {
       MetaWindow *w = tmp->data;
 
-      argv[i] = w->title;
-      ++i;
-      argv[i] = w->res_class ? w->res_class : "";
-      ++i;
+      lame_details = g_slist_prepend (lame_details,
+                                      w->res_class ? w->res_class : "");
+      lame_details = g_slist_prepend (lame_details,
+                                      w->title);
 
       tmp = tmp->next;
     }
+  g_slist_free (lame);
 
-  child_pipe = -1;
-  child_pid = -1;
-  err = NULL;
-  if (!g_spawn_async_with_pipes ("/",
-                                 argv,
-                                 NULL,
-                                 0,
-                                 NULL, NULL,
-                                 &child_pid,
-                                 NULL,
-                                 &child_pipe,
-                                 NULL,
-                                 &err))
-    {
-      meta_warning (_("Error launching metacity-dialog to warn about apps that don't support session management: %s\n"),
-                    err->message);
-      g_error_free (err);
-    }
+  meta_show_dialog("--list",
+                   _("These windows do not support &quot;save current setup&quot; "
+                     "and will have to be restarted manually next time "
+                     "you log in."),
+                   "240",
+                   meta_screen_get_screen_number (meta_get_display()->active_screen),
+                   NULL, NULL,
+                   None,
+                   columns,
+                   lame_details);
 
-  g_free (argv);
-  g_slist_free (lame);
+  g_slist_free (lame_details);
+
+  g_signal_connect (sigchld_nexus, "sigchld",
+                    G_CALLBACK (sigchld_handler),
+                    GINT_TO_POINTER (shutdown));
 
-  d = g_new0 (LameClientsDialogData, 1);
-  d->child_pipe = child_pipe;
-  d->child_pid = child_pid;
-  d->shutdown = shutdown;
-  
-  channel = g_io_channel_unix_new (d->child_pipe);
-  g_io_add_watch_full (channel, G_PRIORITY_DEFAULT,
-                       G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL,
-                       io_from_warning_dialog,
-                       d, g_free);
-  g_io_channel_unref (channel);
 }
 
 #endif /* HAVE_SM */
diff --git a/src/core/util.c b/src/core/util.c
index bcfcb7f..299cd79 100644
--- a/src/core/util.c
+++ b/src/core/util.c
@@ -37,6 +37,8 @@
 #include <X11/Xlib.h>   /* must explicitly be included for Solaris; #326746 */
 #include <X11/Xutil.h>  /* Just for the definition of the various gravities */
 
+MetaNexus *sigchld_nexus;
+
 #ifdef HAVE_BACKTRACE
 #include <execinfo.h>
 void
@@ -538,35 +540,26 @@ meta_gravity_to_string (int gravity)
     }
 }
 
-void
+GPid
 meta_show_dialog (const char *type,
                   const char *message,
                   const char *timeout,
                   const gint screen_number,
-                  const char **columns,
-                  const char **entries)
+                  const char *ok_text,
+                  const char *cancel_text,
+                  const int transient_for,
+                  GSList *columns,
+                  GSList *entries)
 {
   GError *error = NULL;
   char *screen_number_text = g_strdup_printf("%d", screen_number);
-
-  /*
-  We want:
-  
-zenity --display X --screen S --title Metacity --error --text "There was an error running <tt>terminal</tt>:\n\nYour computer is on fire."
-  ** with no pipes
-  
-zenity --display X --screen S --title Metacity --question --text "<big><b><tt>%s</tt> is not responding.</b></big>\n\n<i>You may choose to wait a short while for it to continue or force the application to quit entirely.</i>"
-
-zenity --display X --screen S --title Metacity --list --timeout 240 --text "These windows do not support \"save current setup\" and will have to be restarted manually next time you log in." --column "Window" --column "Class" "Firefox" "foo" "Duke Nukem Forever" "bar"
-  */
-
-  const char **argvl;
+  GSList *tmp;
   int i=0;
   GPid child_pid;
-
-  argvl = g_malloc(sizeof (char*) *
-                   (9 + (timeout?2:0))
-                   );
+  const char **argvl = g_malloc(sizeof (char*) *
+                                (15 +
+                                 g_slist_length (columns)*2 +
+                                 g_slist_length (entries)));
 
   argvl[i++] = "zenity";
   argvl[i++] = type;
@@ -584,18 +577,54 @@ zenity --display X --screen S --title Metacity --list --timeout 240 --text "Thes
       argvl[i++] = timeout;
     }
 
+  if (ok_text)
+    {
+      argvl[i++] = "--ok-label";
+      argvl[i++] = ok_text;
+     }
+
+  if (cancel_text)
+    {
+      argvl[i++] = "--cancel-label";
+      argvl[i++] = cancel_text;
+    }
+  
+  tmp = columns;
+  while (tmp)
+    {
+      argvl[i++] = "--column";
+      argvl[i++] = tmp->data;
+      tmp = tmp->next;
+    }
+
+  tmp = entries;
+  while (tmp)
+    {
+      argvl[i++] = tmp->data;
+      tmp = tmp->next;
+    }
+    
   argvl[i] = NULL;
 
-  g_spawn_async_with_pipes (
-                            "/",
-                            (char**) argvl, /* ugh */
-                            NULL,
-                            G_SPAWN_SEARCH_PATH,
-                            NULL, NULL,
-                            &child_pid,
-                            NULL, NULL, NULL,
-                            &error
-                            );
+  if (transient_for)
+    {
+      gchar *env = g_strdup_printf("%d", transient_for);
+      setenv ("WINDOWID", env, 1);
+      g_free (env);
+    }
+
+  g_spawn_async (
+                 "/",
+                 (gchar**) argvl, /* ugh */
+                 NULL,
+                 G_SPAWN_SEARCH_PATH | G_SPAWN_DO_NOT_REAP_CHILD,
+                 NULL, NULL,
+                 &child_pid,
+                 &error
+                 );
+
+  if (transient_for)
+    unsetenv ("WINDOWID");
 
   g_free (argvl);
   g_free (screen_number_text);
@@ -605,6 +634,33 @@ zenity --display X --screen S --title Metacity --list --timeout 240 --text "Thes
       meta_warning ("%s\n", error->message);
       g_error_free (error);
     }
+
+  return child_pid;
+}
+
+GType
+meta_nexus_get_type (void)
+{
+  static GType nexus_type = 0;
+
+  if (!nexus_type)
+    {
+      static const GTypeInfo nexus_info =
+      {
+        sizeof (MetaNexusClass),
+	NULL, NULL, NULL, NULL, NULL,
+	sizeof (MetaNexus),
+	0,
+	NULL, NULL
+      };
+
+      nexus_type = g_type_register_static (G_TYPE_OBJECT,
+					   "MetaNexus",
+					   &nexus_info,
+					   0);
+    }
+
+  return nexus_type;
 }
 
 /* eof util.c */
diff --git a/src/core/window-private.h b/src/core/window-private.h
index fe688e9..3f3980c 100644
--- a/src/core/window-private.h
+++ b/src/core/window-private.h
@@ -354,7 +354,6 @@ struct _MetaWindow
   
   /* Current dialog open for this window */
   int dialog_pid;
-  int dialog_pipe;
 
   /* maintained by group.c */
   MetaGroup *group;
diff --git a/src/core/window.c b/src/core/window.c
index 2d389d6..b5a945f 100644
--- a/src/core/window.c
+++ b/src/core/window.c
@@ -601,7 +601,6 @@ meta_window_new_with_attrs (MetaDisplay       *display,
   window->constructing = TRUE;
 
   window->dialog_pid = -1;
-  window->dialog_pipe = -1;
 
   window->xwindow = xwindow;
 
diff --git a/src/include/util.h b/src/include/util.h
index 5041f5e..24b5a69 100644
--- a/src/include/util.h
+++ b/src/include/util.h
@@ -26,6 +26,7 @@
 #define META_UTIL_H
 
 #include <glib.h>
+#include <glib-object.h>
 
 gboolean meta_is_verbose  (void);
 void     meta_set_verbose (gboolean setting);
@@ -97,12 +98,15 @@ char* meta_g_utf8_strndup (const gchar *src, gsize n);
 
 void  meta_free_gslist_and_elements (GSList *list_to_deep_free);
 
-void meta_show_dialog (const char *type,
+GPid meta_show_dialog (const char *type,
                        const char *title,
                        const char *message,
                        gint timeout,
-                       const char **columns,
-                       const char **entries);
+                       const char *ok_text,
+                       const char *cancel_text,
+                       const int transient_for,
+                       GSList *columns,
+                       GSList *entries);
 
 /* To disable verbose mode, we make these functions into no-ops */
 #ifdef WITH_VERBOSE_MODE
@@ -127,6 +131,36 @@ void meta_show_dialog (const char *type,
 
 #endif /* !WITH_VERBOSE_MODE */
 
+#include <glib-object.h>
+
+#define META_TYPE_NEXUS            (meta_nexus_get_type ())
+#define META_NEXUS(obj)            (GTK_CHECK_CAST ((obj), META_TYPE_NEXUS, MetaNexus))
+#define META_NEXUS_CLASS(klass)    (GTK_CHECK_CLASS_CAST ((klass), META_TYPE_NEXUS, MetaNexusClass))
+#define META_IS_NEXUS(obj)         (GTK_CHECK_TYPE ((obj), META_TYPE_NEXUS))
+#define META_IS_NEXUS_CLASS(klass) (GTK_CHECK_CLASS_TYPE ((klass), META_TYPE_NEXUS))
+#define META_NEXUS_GET_CLASS(obj)  (GTK_CHECK_GET_CLASS ((obj), META_TYPE_NEXUS, MetaNexusClass))
+
+typedef struct _MetaNexus
+{
+  GObject parent_instance;
+} MetaNexus;
+
+typedef struct _MetaNexusClass
+{
+  GObjectClass parent_class;
+} MetaNexusClass;
+
+GType meta_nexus_get_type (void) G_GNUC_CONST;
+MetaNexus *meta_nexus_new ();
+
+/**
+ * An object which exists purely to attach signals to; this is to receive
+ * signals when a child process exits.  The signal is "sigchld" with no detail.
+ *
+ * \bug Eventually we should have a specialised type for objects like these.
+ */
+extern MetaNexus *sigchld_nexus;
+
 #endif /* META_UTIL_H */
 
 
diff --git a/src/ui/metacity-dialog.c b/src/ui/metacity-dialog.c
deleted file mode 100644
index d47a9b3..0000000
--- a/src/ui/metacity-dialog.c
+++ /dev/null
@@ -1,438 +0,0 @@
-/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
-
-/* Metacity dialog process */
-
-/* 
- * Copyright (C) 2001 Havoc Pennington
- * Copyright (C) 2004 Elijah Newren
- * 
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation; either version 2 of the
- * License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * General Public License for more details.
- * 
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
- * 02111-1307, USA.
- */
-
-#include <config.h>
-#include <gtk/gtk.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-
-#include <libintl.h>
-#define _(x) dgettext (GETTEXT_PACKAGE, x)
-#define N_(x) x
-
-#include <gdk/gdkx.h>
-#include <X11/Xatom.h>
-
-static Window
-window_from_string (const char *str)
-{
-  char *end;
-  unsigned long l;
-
-  end = NULL;
-  
-  l = strtoul (str, &end, 16);
-
-  if (end == NULL || end == str)
-    {
-      g_printerr (_("Could not parse \"%s\" as an integer"),
-                  str);
-      return None;
-    }
-
-  if (*end != '\0')
-    {
-      g_printerr (_("Did not understand trailing characters \"%s\" in string \"%s\""),
-                  end, str);
-      return None;
-    }
-
-  return l;
-}
-
-static void
-on_realize (GtkWidget *dialog,
-            void      *data)
-{
-  const char *parent_str = data;
-  Window xwindow;
-
-  xwindow = window_from_string (parent_str);
-
-  gdk_error_trap_push ();
-  XSetTransientForHint (gdk_display, GDK_WINDOW_XID (dialog->window),
-                        xwindow);
-  XSync (gdk_display, False);
-  gdk_error_trap_pop ();
-}
-
-static int
-kill_window_question (const char *window_name,
-                      const char *parent_str,
-                      guint32     timestamp)
-{
-  GtkWidget *dialog;
-  char *str, *tmp;
-
-  tmp = g_markup_escape_text (window_name, -1);
-  str = g_strdup_printf (_("\"%s\" is not responding."), tmp);
-  g_free (tmp);
-  dialog = gtk_message_dialog_new (NULL, 0,
-                                   GTK_MESSAGE_WARNING,
-                                   GTK_BUTTONS_NONE,
-                                   "<big><b>%s</b></big>\n\n<i>%s</i>",
-                                   str,
-                                   _("You may choose to wait a short while "
-                                   "for it to continue or force the application "
-                                   "to quit entirely."));
-  g_free (str);
-  gtk_window_set_icon_name (GTK_WINDOW (dialog), "stock_dialog-warning");
-
-  gtk_label_set_use_markup (GTK_LABEL (GTK_MESSAGE_DIALOG (dialog)->label), TRUE);
-  gtk_label_set_line_wrap (GTK_LABEL (GTK_MESSAGE_DIALOG (dialog)->label), TRUE);
-  
-  gtk_dialog_add_buttons (GTK_DIALOG (dialog),
-                          _("_Wait"),
-                          GTK_RESPONSE_REJECT,
-                          _("_Force Quit"),
-                          GTK_RESPONSE_ACCEPT,
-                          NULL);
-  
-  gtk_dialog_set_default_response (GTK_DIALOG (dialog), GTK_RESPONSE_REJECT);
-
-  g_signal_connect (G_OBJECT (dialog), "realize",
-                    G_CALLBACK (on_realize), (char*) parent_str);
-  
-  gtk_widget_realize (dialog);
-  gdk_x11_window_set_user_time (dialog->window, timestamp);
-
-  /* return our PID, then window ID that should be killed */
-  if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_ACCEPT)
-    g_print ("%d\n%s\n", (int) getpid (), parent_str);
-  else
-    g_print ("%d\n0x0\n", (int) getpid ());
-
-  return 0;
-}
-
-static char*
-latin1_to_utf8 (const char *text)
-{
-  GString *str;
-  const char *p;
-  
-  str = g_string_new ("");
-
-  p = text;
-  while (*p)
-    {
-      g_string_append_unichar (str, *p);
-      ++p;
-    }
-
-  return g_string_free (str, FALSE);
-}
-
-enum
-{
-  COLUMN_TITLE,
-  COLUMN_CLASS,
-  COLUMN_LAST
-};
-
-static GtkWidget*
-create_lame_apps_list (char **lame_apps)
-{
-  GtkTreeSelection *selection;
-  GtkCellRenderer *cell;
-  GtkWidget *tree_view;
-  GtkTreeViewColumn *column;
-  GtkListStore *model;
-  GtkTreeIter iter;
-  int i;
-  
-  model = gtk_list_store_new (COLUMN_LAST,
-                              G_TYPE_STRING,
-                              G_TYPE_STRING);
-  
-  tree_view = gtk_tree_view_new_with_model (GTK_TREE_MODEL (model));
-
-  g_object_unref (G_OBJECT (model));
-  
-  selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (tree_view));
-
-  gtk_tree_selection_set_mode (GTK_TREE_SELECTION (selection),
-			       GTK_SELECTION_NONE);
-
-  i = 0;
-  while (lame_apps[i])
-    {
-      char *s;
-      
-      gtk_list_store_append (model, &iter);
-
-      /* window class is latin-1 */
-      s = latin1_to_utf8 (lame_apps[i+1]);
-      
-      gtk_list_store_set (model,
-			  &iter,
-                          COLUMN_TITLE, lame_apps[i],
-                          COLUMN_CLASS, s,
-                          -1);
-
-      g_free (s);
-      
-      i += 2;
-    }
-  
-  cell = gtk_cell_renderer_text_new ();
-  
-  g_object_set (G_OBJECT (cell),
-                "xpad", 2,
-                NULL);
-  
-  column = gtk_tree_view_column_new_with_attributes (_("Title"),
-						     cell,
-						     "text", COLUMN_TITLE,
-						     NULL);
-
-  gtk_tree_view_column_set_sort_column_id (column, COLUMN_TITLE);
-  
-  gtk_tree_view_append_column (GTK_TREE_VIEW (tree_view),
-			       GTK_TREE_VIEW_COLUMN (column));
-
-  cell = gtk_cell_renderer_text_new ();
-  
-  column = gtk_tree_view_column_new_with_attributes (_("Class"),
-						     cell,
-						     "text", COLUMN_CLASS,
-						     NULL);
-
-  gtk_tree_view_column_set_sort_column_id (column, COLUMN_CLASS);
-  
-  gtk_tree_view_append_column (GTK_TREE_VIEW (tree_view),
-			       GTK_TREE_VIEW_COLUMN (column));
-
-  return tree_view;
-}
-
-static int
-warn_about_no_sm_support (char    **lame_apps,
-                          guint32   timestamp)
-{
-  GtkWidget *dialog;
-  GtkWidget *list;
-  GtkWidget *sw;
-  GtkWidget *button;
-      
-  dialog = gtk_message_dialog_new (NULL,
-                                   0,
-                                   GTK_MESSAGE_WARNING,
-                                   GTK_BUTTONS_NONE,
-                                   _("These windows do not support \"save current setup\" and will have to be restarted manually next time you log in."));
-  gtk_window_set_icon_name (GTK_WINDOW (dialog), "stock_dialog-warning");
-  
-  g_signal_connect (G_OBJECT (dialog),
-                    "response",
-                    G_CALLBACK (gtk_main_quit),
-                    NULL);
-
-  /* Wait 4 minutes then force quit, so we don't wait around all night */
-  g_timeout_add (4 * 60 * 1000, (GSourceFunc) gtk_main_quit, NULL);
-
-  button = gtk_dialog_add_button (GTK_DIALOG (dialog), GTK_STOCK_CLOSE, GTK_RESPONSE_CLOSE);
-  gtk_dialog_set_default_response(GTK_DIALOG(dialog), GTK_RESPONSE_CLOSE);
-  list = create_lame_apps_list (lame_apps);
-
-  sw = gtk_scrolled_window_new (NULL, NULL);
-  gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (sw),
-                                  GTK_POLICY_AUTOMATIC,
-                                  GTK_POLICY_AUTOMATIC);
-  gtk_container_set_border_width (GTK_CONTAINER (sw), 3);
-      
-  gtk_container_add (GTK_CONTAINER (sw), list);
-
-  /* sw as geometry widget */
-  gtk_window_set_geometry_hints (GTK_WINDOW (dialog),
-                                 sw, NULL, 0);
-
-  gtk_window_set_resizable (GTK_WINDOW(dialog), TRUE);
-
-  /* applies to geometry widget; try to avoid scrollbars,
-   * but don't make the window huge
-   */
-  gtk_window_set_default_size (GTK_WINDOW (dialog),
-                               400, 225);
-
-  gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dialog)->vbox),
-                      sw,
-                      TRUE, TRUE, 0);
-  
-  gtk_window_stick (GTK_WINDOW (dialog));
-
-  gtk_widget_realize (dialog);
-  gdk_x11_window_set_user_time (dialog->window, timestamp);
-
-  gtk_widget_grab_focus (button);
-  gtk_widget_show_all (dialog);
-
-  gtk_main ();
-  
-  return 0;
-}
-
-static int
-error_about_command (const char *gconf_key,
-                     const char *command,
-                     const char *error,
-                     guint32     timestamp)
-{
-  GtkWidget *dialog;
-
-  /* FIXME offer to change the value of the command's gconf key */
-
-  if (*command != '\0')
-    dialog = gtk_message_dialog_new (NULL, 0,
-                                     GTK_MESSAGE_ERROR,
-                                     GTK_BUTTONS_CLOSE,
-                                     _("There was an error running \"%s\":\n"
-                                       "%s."),
-                                     command, error);
-  else
-    dialog = gtk_message_dialog_new (NULL, 0,
-                                     GTK_MESSAGE_ERROR,
-                                     GTK_BUTTONS_CLOSE,
-                                     "%s", error);
-  gtk_window_set_icon_name (GTK_WINDOW (dialog), "stock_dialog-error");
-  
-  gtk_widget_realize (dialog);
-  gdk_x11_window_set_user_time (dialog->window, timestamp);
-
-  gtk_dialog_run (GTK_DIALOG (dialog));
-
-  gtk_widget_destroy (dialog);
-  
-  return 0;
-}
-
-static gchar *screen = NULL;
-static gchar *timestamp_string = NULL;
-static gboolean isset_kill_window_question = FALSE;
-static gboolean isset_warn_about_no_sm_support = FALSE;
-static gboolean isset_command_failed_error = FALSE;
-static gchar **remaining_args;
-
-static const GOptionEntry options[] = {
-  { "screen", 0, 0, G_OPTION_ARG_STRING, &screen, NULL, NULL},
-  { "timestamp", 0, 0, G_OPTION_ARG_STRING, &timestamp_string, NULL, NULL},
-  { "kill-window-question", 'k', 0, G_OPTION_ARG_NONE, 
-    &isset_kill_window_question, NULL, NULL},
-  { "warn-about-no-sm-support", 'w', 0, G_OPTION_ARG_NONE, 
-    &isset_warn_about_no_sm_support, NULL, NULL},
-  { "command-failed-error", 'c', 0, G_OPTION_ARG_NONE, 
-    &isset_command_failed_error, NULL, NULL},
-  { G_OPTION_REMAINING, 0, 0, G_OPTION_ARG_STRING_ARRAY, 
-    &remaining_args, NULL, NULL},
-  { NULL}
-};
-
-int
-main (int argc, char **argv)
-{
-  GOptionContext *ctx;
-  guint32 timestamp = 0;
-  gint num_args = 0;
-
-  bindtextdomain (GETTEXT_PACKAGE, METACITY_LOCALEDIR);
-  bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
-  textdomain (GETTEXT_PACKAGE);
-
-  gtk_init (&argc, &argv);
-
-  ctx = g_option_context_new ("- Dialogs for metacity. "
-                          "This program is intented for use by metacity only.");
-  g_option_context_add_main_entries (ctx, options, GETTEXT_PACKAGE);
-  g_option_context_parse (ctx, &argc, &argv, NULL);
-  g_option_context_free (ctx);
-    
-  if (timestamp_string != NULL)
-    {
-      timestamp = strtoul (timestamp_string, NULL, 10);
-    }
-
-  if (remaining_args != NULL)
-    {
-      num_args = g_strv_length (remaining_args);
-    }
-
-  if ((isset_kill_window_question && isset_warn_about_no_sm_support) ||
-      (isset_kill_window_question && isset_command_failed_error) ||
-      (isset_warn_about_no_sm_support && isset_command_failed_error) ||
-      timestamp == 0) 
-    {
-      g_printerr ("bad args to metacity-dialog\n");
-      return 1;
-    }
-
-  else if (isset_kill_window_question)
-    {
-      if (num_args < 2)
-        {
-          g_printerr ("bad args to metacity-dialog\n");
-          return 1;
-        } 
-      else 
-        {
-          return kill_window_question (remaining_args[0], 
-                          remaining_args[1], timestamp);
-        }
-    }
-
-  else if (isset_warn_about_no_sm_support)
-    {
-      /* argc must be even because we want title-class pairs */
-      if (num_args == 0 || (num_args % 2) != 0)
-        {
-          g_printerr ("bad args to metacity-dialog\n");
-          return 1;
-        } 
-      else 
-        {
-          return warn_about_no_sm_support (&remaining_args[0], timestamp);
-        }
-    }
-
-  else if (isset_command_failed_error)
-    {
-      /* the args are the gconf key of the failed command, the text of
-       * the command, and the error message
-       */
-      if (num_args != 3)
-        {
-          g_printerr ("bad args to metacity-dialog\n");
-          return 1;
-        } 
-      else 
-        {
-          return error_about_command (remaining_args[0], 
-                          remaining_args[1], remaining_args[2], timestamp);
-        }
-    }
-  else
-    {
-      g_printerr ("bad args to metacity-dialog\n");
-      return 1;
-    }
-}
