dialog iteration




Hi,

Another go based on Tim's ideas, please comment.

Notable features: 
 - set_transient_for virtualized in GtkWindow, so GtkDialog 
   can override it to destroy the dialog along with 
   the transient parent
 - new GtkDialog is totally compatible with old GtkDialog
   (except that it gets destroyed along with transient parent)
 - I didn't support hide-instead-of-destroy-on-close because 
   this makes things a good bit harder to understand, in 
   my experience trying to explain GnomeDialog, and also 
   requires delete_event behavior inconsistent with GtkWindow. 
   If this is added I think the "close" signal should go in 
   GtkWindow to keep things consistent, and the "hide on close" 
   flag should be honored in gtkmain.c for delete_event
 - I didn't support a "center over parent window" flag 
   because I don't think this should be programmer-configurable.
   However GTK might do it automatically when the transient 
   parent is set.

Object arguments aren't implemented yet, I'll do that and also inline
docs once the design is final.

Patch appended, you may want to skip to "Index: gtkdialog.h" because
diff put the implementation first.

Havoc


Index: gtkdialog.c
===================================================================
RCS file: /cvs/gnome/gtk+/gtk/gtkdialog.c,v
retrieving revision 1.10
diff -u -u -r1.10 gtkdialog.c
--- gtkdialog.c	1999/02/24 07:34:16	1.10
+++ gtkdialog.c	2000/03/26 19:10:49
@@ -26,14 +26,41 @@
 
 #include "gtkbutton.h"
 #include "gtkdialog.h"
-#include "gtkhbox.h"
+#include "gtkhbbox.h"
 #include "gtkhseparator.h"
 #include "gtkvbox.h"
+#include "gtksignal.h"
 
 
-static void gtk_dialog_class_init (GtkDialogClass *klass);
-static void gtk_dialog_init       (GtkDialog      *dialog);
+static void gtk_dialog_class_init        (GtkDialogClass *klass);
+static void gtk_dialog_init              (GtkDialog      *dialog);
+static void gtk_dialog_destroy           (GtkObject      *object);
+static void gtk_dialog_set_transient_for (GtkWindow      *window,
+                                          GtkWindow      *parent);
+
+static void gtk_dialog_parent_destroyed  (GtkWindow      *parent,
+                                          GtkDialog      *dialog);
+
+static void action_area_add_handler      (GtkWidget      *action_area,
+                                          GtkWidget      *child,
+                                          GtkDialog      *dialog);
+
+static void action_area_remove_handler   (GtkWidget      *action_area,
+                                          GtkWidget      *child,
+                                          GtkDialog      *dialog);
+
+static void gtk_dialog_add_buttons_valist(GtkDialog      *dialog,
+                                          const gchar    *first_button_name,
+                                          gint            first_action_id,
+                                          va_list         args);
+
+enum {
+  ACTION,
+  LAST_SIGNAL
+};
 
+static GtkWindowClass *parent_class;
+static guint dialog_signals[LAST_SIGNAL];
 
 GtkType
 gtk_dialog_get_type (void)
@@ -63,6 +90,30 @@
 static void
 gtk_dialog_class_init (GtkDialogClass *class)
 {
+  GtkObjectClass *object_class;
+  GtkWidgetClass *widget_class;
+  GtkWindowClass *window_class;
+  
+  parent_class = gtk_type_class (gtk_window_get_type ());
+
+  object_class = (GtkObjectClass*) class;
+  widget_class = (GtkWidgetClass*) class;
+  window_class = (GtkWindowClass*) class;
+
+  dialog_signals[ACTION] =
+    gtk_signal_new ("action",
+                    GTK_RUN_LAST,
+                    object_class->type,
+                    GTK_SIGNAL_OFFSET (GtkDialogClass, action),
+                    gtk_marshal_NONE__INT,
+		    GTK_TYPE_NONE, 1,
+                    GTK_TYPE_INT);
+
+  gtk_object_class_add_signals (object_class, dialog_signals, LAST_SIGNAL);
+
+  object_class->destroy = gtk_dialog_destroy;
+  
+  window_class->set_transient_for = gtk_dialog_set_transient_for;
 }
 
 static void
@@ -74,7 +125,7 @@
   gtk_container_add (GTK_CONTAINER (dialog), dialog->vbox);
   gtk_widget_show (dialog->vbox);
 
-  dialog->action_area = gtk_hbox_new (TRUE, 5);
+  dialog->action_area = gtk_hbutton_box_new ();
   gtk_container_set_border_width (GTK_CONTAINER (dialog->action_area), 10);
   gtk_box_pack_end (GTK_BOX (dialog->vbox), dialog->action_area, FALSE, TRUE, 0);
   gtk_widget_show (dialog->action_area);
@@ -82,10 +133,415 @@
   separator = gtk_hseparator_new ();
   gtk_box_pack_end (GTK_BOX (dialog->vbox), separator, FALSE, TRUE, 0);
   gtk_widget_show (separator);
+
+
+  gtk_signal_connect_while_alive (GTK_OBJECT (dialog->action_area),
+                                  "add",
+                                  GTK_SIGNAL_FUNC (action_area_add_handler),
+                                  dialog,
+                                  GTK_OBJECT (dialog));
+
+  gtk_signal_connect_while_alive (GTK_OBJECT (dialog->action_area),
+                                  "remove",
+                                  GTK_SIGNAL_FUNC (action_area_remove_handler),
+                                  dialog,
+                                  GTK_OBJECT (dialog));
 }
 
 GtkWidget*
 gtk_dialog_new (void)
 {
   return GTK_WIDGET (gtk_type_new (GTK_TYPE_DIALOG));
+}
+
+GtkWidget*
+gtk_dialog_new_empty (const gchar *title,
+                      GtkWindow   *parent,
+                      GtkDialogFlags flags,
+                      GtkWidget  **zero_on_destroy)
+{
+  GtkWidget *widget;
+  GtkDialog *dialog;
+  
+  widget = gtk_dialog_new ();
+
+  dialog = GTK_DIALOG (widget);
+
+  if (title != NULL)
+    gtk_window_set_title (GTK_WINDOW (dialog), title);
+  
+  if (parent != NULL)
+    gtk_window_set_transient_for (GTK_WINDOW (dialog), parent);
+
+  if (flags & GTK_DIALOG_MODAL)
+    gtk_window_set_modal (GTK_WINDOW (dialog), TRUE);
+  
+  if (flags & GTK_DIALOG_OUTLAST_PARENT)
+    gtk_dialog_set_outlast_parent (dialog, TRUE);
+
+  if (zero_on_destroy)
+    gtk_signal_connect (GTK_OBJECT (dialog),
+                        "destroy",
+                        GTK_SIGNAL_FUNC (gtk_widget_destroyed),
+                        zero_on_destroy);
+  
+  return widget;
+}
+
+GtkWidget*
+gtk_dialog_new_with_buttons (const gchar     *title,
+                             GtkWindow       *parent,
+                             GtkDialogFlags   flags,
+                             GtkWidget      **zero_on_destroy,
+                             const gchar *first_button_text,
+                             gint         first_action_id,
+                             ...)
+{
+  GtkWidget *widget;
+  va_list args;
+  
+  widget = gtk_dialog_new_empty (title, parent, flags, zero_on_destroy);
+
+  va_start (args, first_action_id);
+
+  gtk_dialog_add_buttons_valist (GTK_DIALOG (widget),
+                                 first_button_text, first_action_id,
+                                 args);
+  
+  va_end (args);
+
+  return widget;
+}
+
+static void
+gtk_dialog_destroy (GtkObject *object)
+{
+  GtkDialog *dialog;
+
+  dialog = GTK_DIALOG (object);
+  
+  if (dialog->parent_destroy_handler != 0)
+    {
+      gtk_signal_disconnect (GTK_OBJECT (GTK_WINDOW (dialog)->transient_parent),
+                             dialog->parent_destroy_handler);
+      
+      dialog->parent_destroy_handler = 0;
+    }
+}
+  
+static void
+gtk_dialog_set_transient_for (GtkWindow *window,
+                              GtkWindow *parent)
+{
+  GtkDialog *dialog;
+
+  dialog = GTK_DIALOG (window);
+
+  if (dialog->parent_destroy_handler != 0)
+    {
+      /* we are supposed to remove our handler if the
+         transient parent is destroyed. */
+      g_assert (window->transient_parent != NULL);
+      gtk_signal_disconnect (GTK_OBJECT (window->transient_parent),
+                             dialog->parent_destroy_handler);
+
+      dialog->parent_destroy_handler = 0;
+    }
+  
+  (* parent_class->set_transient_for) (window, parent);
+
+  g_assert (window->transient_parent == parent);
+  
+  if (window->transient_parent != NULL)
+    {
+      dialog->parent_destroy_handler =
+        gtk_signal_connect (GTK_OBJECT (window->transient_parent),
+                            "destroy",
+                            GTK_SIGNAL_FUNC (gtk_dialog_parent_destroyed),
+                            dialog);
+    }
+}
+
+static void
+gtk_dialog_parent_destroyed  (GtkWindow      *parent,
+                              GtkDialog      *dialog)
+{
+  g_return_if_fail (GTK_IS_DIALOG (dialog));
+  g_return_if_fail (dialog->parent_destroy_handler != 0);
+
+  /* The parent destroy handler will of course be destroyed
+     along with the parent. */
+  dialog->parent_destroy_handler = 0;
+
+  if (!dialog->outlast_parent)
+    gtk_widget_destroy (GTK_WIDGET (dialog));
+}
+
+void
+gtk_dialog_action (GtkDialog *dialog,
+                   gint action_id)
+{
+  g_return_if_fail (dialog != NULL);
+  g_return_if_fail (GTK_IS_DIALOG (dialog));
+
+  gtk_signal_emit (GTK_OBJECT (dialog),
+                   dialog_signals[ACTION],
+                   action_id);
+}
+
+void
+gtk_dialog_set_outlast_parent (GtkDialog *dialog,
+                               gboolean setting)
+{
+  g_return_if_fail (dialog != NULL);
+  g_return_if_fail (GTK_IS_DIALOG (dialog));
+  
+  dialog->outlast_parent = setting != FALSE;
+}
+
+typedef struct {
+  gint action_id;
+  gboolean destroy_on_activate;
+} ActionData;
+
+static void
+action_widget_activated (GtkWidget *widget,
+                         GtkDialog *dialog)
+{
+  ActionData *ad;
+  gint action_id;
+  gboolean destroy_on_activate;
+  
+  g_return_if_fail (dialog != NULL);
+  g_return_if_fail (GTK_IS_DIALOG (dialog));
+
+  action_id = GTK_ACTION_NONE;
+  destroy_on_activate = FALSE;
+  
+  ad = gtk_object_get_data (GTK_OBJECT (widget),
+                            "__gtk_dialog_action_data");
+
+  if (ad != NULL)
+    {
+      action_id = ad->action_id;
+      destroy_on_activate = ad->destroy_on_activate;
+    }
+
+  gtk_dialog_action (dialog, action_id);
+
+  if (destroy_on_activate)
+    gtk_widget_destroy (GTK_WIDGET (dialog));
+}
+
+static void
+action_area_add_handler (GtkWidget *action_area,
+                         GtkWidget *child,
+                         GtkDialog *dialog)
+{
+  g_return_if_fail (dialog != NULL);
+  g_return_if_fail (GTK_IS_DIALOG (dialog));
+
+  if (GTK_WIDGET_CLASS (GTK_OBJECT (child)->klass)->activate_signal != 0)
+    {
+      const gchar* name =
+        gtk_signal_name (GTK_WIDGET_CLASS (GTK_OBJECT (child)->klass)->activate_signal != 0);
+
+      gtk_signal_connect_while_alive (GTK_OBJECT (child),
+                                      name,
+                                      GTK_SIGNAL_FUNC (action_widget_activated),
+                                      dialog,
+                                      GTK_OBJECT (dialog));
+    }
+  else
+    g_warning ("Only 'activatable' widgets can be packed into the action area of a GtkDialog");
+}
+
+static void
+action_area_remove_handler (GtkWidget *action_area,
+                            GtkWidget *child,
+                            GtkDialog *dialog)
+{
+  g_return_if_fail (dialog != NULL);
+  g_return_if_fail (GTK_IS_DIALOG (dialog));
+  
+  gtk_signal_disconnect_by_func (GTK_OBJECT (action_area),
+                                 GTK_SIGNAL_FUNC (action_widget_activated),
+                                 dialog);
+  
+  gtk_object_set_data (GTK_OBJECT (dialog),
+                       "__gtk_dialog_action_data",
+                       NULL);
+}
+
+void
+gtk_dialog_add_action_widget  (GtkDialog *dialog,
+                               GtkWidget *widget,
+                               gint       action_id,
+                               gboolean   destroy_on_activate)
+{
+  ActionData* ad;
+  
+  g_return_if_fail (dialog != NULL);
+  g_return_if_fail (GTK_IS_DIALOG (dialog));
+  g_return_if_fail (widget != NULL);
+
+  ad = g_new (ActionData, 1);
+  ad->action_id = action_id;
+  ad->destroy_on_activate = destroy_on_activate;
+
+  gtk_object_set_data_full (GTK_OBJECT (widget),
+                            "__gtk_dialog_action_data",
+                            ad,
+                            g_free);
+  
+  gtk_box_pack_end (GTK_BOX (dialog->action_area),
+                    widget,
+                    FALSE, TRUE, 5);
+
+}
+
+void
+gtk_dialog_add_button (GtkDialog   *dialog,
+                       const gchar *button_text,
+                       gint         action_id)
+{
+  g_return_if_fail (dialog != NULL);
+  g_return_if_fail (GTK_IS_DIALOG (dialog));
+  g_return_if_fail (button_text != NULL);
+
+  /* FIXME when/if we have a stock icon/text facility, we want to
+     check whether button_text is a stock reference. */
+  
+  gtk_dialog_add_action_widget (dialog,
+                                gtk_button_new_with_label (button_text),
+                                action_id,
+                                TRUE);
+}
+
+static void
+gtk_dialog_add_buttons_valist(GtkDialog      *dialog,
+                              const gchar    *first_button_text,
+                              gint            first_action_id,
+                              va_list         args)
+{
+  const gchar* text;
+  gint action_id;
+
+  text = first_button_text;
+  action_id = first_action_id;
+
+  while (text != NULL)
+    {
+      gtk_dialog_add_button (dialog, text, action_id);
+
+      text = va_arg (args, gchar*);
+      if (text == NULL)
+        break;
+      action_id = va_arg (args, int);
+    }
+}
+
+void
+gtk_dialog_add_buttons (GtkDialog   *dialog,
+                        const gchar *first_button_text,
+                        gint         first_action_id,
+                        ...)
+{
+  
+  va_list args;
+
+  va_start (args, first_action_id);
+
+  gtk_dialog_add_buttons_valist (dialog,
+                                 first_button_text, first_action_id,
+                                 args);
+  
+  va_end (args);
+}
+
+typedef struct {
+  GtkDialog *dialog;
+  gint action_id;
+  GMainLoop *loop;
+  gint action_handler;
+  gint destroy_handler;
+} RunInfo;
+
+static void
+run_destroy_handler (GtkDialog *dialog, gpointer data)
+{
+  RunInfo *ri;
+
+  ri = data;
+
+  if (ri->loop != NULL)
+    {
+      g_main_quit (ri->loop);
+      g_main_destroy (ri->loop);
+      ri->loop = NULL;
+    }
+}
+
+static void
+run_action_handler (GtkDialog *dialog,
+                    gint action_id,
+                    gpointer data)
+{
+  RunInfo *ri;
+
+  ri = data;
+
+  ri->action_id = action_id;
+
+  g_main_quit (ri->loop);
+  g_main_destroy (ri->loop);
+  ri->loop = NULL;
+}
+
+gint
+gtk_dialog_run (GtkDialog *dialog)
+{
+  RunInfo ri = { NULL, GTK_ACTION_NONE, NULL, 0, 0 };
+  gboolean was_modal;
+  
+  g_return_val_if_fail (dialog != NULL, -1);
+  g_return_val_if_fail (GTK_IS_DIALOG (dialog), -1);
+
+  gtk_object_ref (GTK_OBJECT (dialog));
+  
+  was_modal = GTK_WINDOW (dialog)->modal;
+  if (!was_modal)
+    gtk_window_set_modal(GTK_WINDOW (dialog),TRUE);
+
+
+  ri.action_handler =
+    gtk_signal_connect (GTK_OBJECT (dialog),
+                        "action",
+                        GTK_SIGNAL_FUNC (run_action_handler),
+                        &ri);
+
+  ri.destroy_handler =
+    gtk_signal_connect (GTK_OBJECT (dialog),
+                        "destroy",
+                        GTK_SIGNAL_FUNC (run_destroy_handler),
+                        &ri);
+
+  ri.loop = g_main_new(FALSE);
+
+  g_main_run(ri.loop);
+  
+  g_assert(ri.loop == NULL);
+  
+  if (!GTK_OBJECT_DESTROYED (dialog))
+    {
+      if (!was_modal)
+        gtk_window_set_modal(GTK_WINDOW(dialog), FALSE);
+      
+      gtk_signal_disconnect (GTK_OBJECT (dialog), ri.destroy_handler);
+      gtk_signal_disconnect (GTK_OBJECT (dialog), ri.action_handler);
+    }
+
+  gtk_object_unref (GTK_OBJECT (dialog));
+
+  return ri.action_id;
 }
Index: gtkdialog.h
===================================================================
RCS file: /cvs/gnome/gtk+/gtk/gtkdialog.h,v
retrieving revision 1.6
diff -u -u -r1.6 gtkdialog.h
--- gtkdialog.h	2000/02/13 08:16:47	1.6
+++ gtkdialog.h	2000/03/26 19:10:49
@@ -36,6 +36,33 @@
 extern "C" {
 #endif /* __cplusplus */
 
+/* Parameters for dialog construction */
+typedef enum
+{
+  GTK_DIALOG_MODAL,         /* call gtk_window_set_modal(win, TRUE) */
+  GTK_DIALOG_OUTLAST_PARENT /* don't destroy the dialog along with its
+                               parent */
+} GtkDialogFlags;
+
+/* Convenience enum to use for action_id's.  Positive values are
+   totally user-interpreted. GTK will sometimes return GTK_ACTION_NONE
+   if no action_id is available.
+
+   Typical usage is:
+      if (gtk_dialog_run(dialog) == GTK_ACTION_ACCEPT)
+        blah();
+        
+*/
+typedef enum
+{
+  /* GTK returns this if an action widget has no action_id,
+     or the dialog gets destroyed with no action */
+  GTK_ACTION_NONE = 0,
+  /* GTK won't return these unless you pass them in
+     as the action for an action widget */
+  GTK_ACTION_REJECT = 1,
+  GTK_ACTION_ACCEPT = 2
+} GtkActionType;
 
 #define GTK_TYPE_DIALOG                  (gtk_dialog_get_type ())
 #define GTK_DIALOG(obj)                  (GTK_CHECK_CAST ((obj), GTK_TYPE_DIALOG, GtkDialog))
@@ -44,29 +71,70 @@
 #define GTK_IS_DIALOG_CLASS(klass)       (GTK_CHECK_CLASS_TYPE ((klass), GTK_TYPE_DIALOG))
 #define GTK_DIALOG_GET_CLASS(obj)        (GTK_CHECK_GET_CLASS ((obj), GTK_TYPE_DIALOG, GtkDialogClass))
 
-
 typedef struct _GtkDialog        GtkDialog;
 typedef struct _GtkDialogClass   GtkDialogClass;
-typedef struct _GtkDialogButton  GtkDialogButton;
-
 
 struct _GtkDialog
 {
   GtkWindow window;
 
+  /*< public >*/
+  
   GtkWidget *vbox;
   GtkWidget *action_area;
+
+  /*< private >*/
+  gboolean outlast_parent;
+  guint parent_destroy_handler;
 };
 
 struct _GtkDialogClass
 {
   GtkWindowClass parent_class;
+
+  void (* action) (GtkDialog *dialog, gint action_id);
 };
 
 
 GtkType    gtk_dialog_get_type (void);
 GtkWidget* gtk_dialog_new      (void);
 
+GtkWidget* gtk_dialog_new_empty        (const gchar     *title,
+                                        GtkWindow       *parent,
+                                        GtkDialogFlags   flags,
+                                        GtkWidget      **zero_on_destroy);
+GtkWidget* gtk_dialog_new_with_buttons (const gchar     *title,
+                                        GtkWindow       *parent,
+                                        GtkDialogFlags   flags,
+                                        GtkWidget      **zero_on_destroy,
+                                        const gchar *first_button_text,
+                                        gint         first_action_id,
+                                        ...);
+
+void gtk_dialog_add_action_widget  (GtkDialog *dialog,
+                                    GtkWidget *widget,
+                                    gint       action_id,
+                                    gboolean   destroy_on_activate);
+
+/* for these, destroy_on_activate defaults to TRUE */
+void gtk_dialog_add_button         (GtkDialog   *dialog,
+                                    const gchar *button_text,
+                                    gint         action_id);
+
+void gtk_dialog_add_buttons        (GtkDialog   *dialog,
+                                    const gchar *first_button_text,
+                                    gint         first_action_id,
+                                    ...);
+
+/* Emit action signal */
+void gtk_dialog_action             (GtkDialog *dialog,
+                                    gint       action_id);
+
+void gtk_dialog_set_outlast_parent (GtkDialog *dialog,
+                                    gboolean   setting);
+
+/* Returns action_id */
+gint gtk_dialog_run                (GtkDialog *dialog);
 
 #ifdef __cplusplus
 }
Index: gtkwindow.c
===================================================================
RCS file: /cvs/gnome/gtk+/gtk/gtkwindow.c,v
retrieving revision 1.79
diff -u -u -r1.79 gtkwindow.c
--- gtkwindow.c	1999/12/11 23:04:55	1.79
+++ gtkwindow.c	2000/03/26 19:10:54
@@ -49,6 +49,7 @@
 
 enum {
   SET_FOCUS,
+  SET_TRANSIENT_FOR,
   LAST_SIGNAL
 };
 enum {
@@ -122,6 +123,8 @@
 static void gtk_window_check_resize       (GtkContainer      *container);
 static void gtk_window_real_set_focus     (GtkWindow         *window,
 					   GtkWidget         *focus);
+static void gtk_window_real_set_transient_for (GtkWindow      *window,
+                                               GtkWindow      *parent);
 
 static void gtk_window_move_resize        (GtkWindow         *window);
 static gboolean gtk_window_compare_hints  (GdkGeometry       *geometry_a,
@@ -226,6 +229,15 @@
 		    GTK_TYPE_NONE, 1,
                     GTK_TYPE_WIDGET);
 
+  window_signals[SET_TRANSIENT_FOR] =
+    gtk_signal_new ("set_transient_for",
+                    GTK_RUN_LAST,
+                    object_class->type,
+                    GTK_SIGNAL_OFFSET (GtkWindowClass, set_transient_for),
+                    gtk_marshal_NONE__POINTER,
+		    GTK_TYPE_NONE, 1,
+                    GTK_TYPE_WIDGET);
+  
   gtk_object_class_add_signals (object_class, window_signals, LAST_SIGNAL);
 
   object_class->set_arg = gtk_window_set_arg;
@@ -256,6 +268,7 @@
   container_class->check_resize = gtk_window_check_resize;
 
   klass->set_focus = gtk_window_real_set_focus;
+  klass->set_transient_for = gtk_window_real_set_transient_for;
 }
 
 static void
@@ -702,38 +715,15 @@
 gtk_window_set_transient_for  (GtkWindow *window, 
 			       GtkWindow *parent)
 {
-  g_return_if_fail (window != 0);
-
-  if (window->transient_parent)
-    {
-      if (GTK_WIDGET_REALIZED (window) && 
-	  GTK_WIDGET_REALIZED (window->transient_parent) && 
-	  (!parent || !GTK_WIDGET_REALIZED (parent)))
-	gtk_window_transient_parent_unrealized (GTK_WIDGET (window->transient_parent),
-						GTK_WIDGET (window));
-
-      gtk_window_unset_transient_for (window);
-    }
-
-  window->transient_parent = parent;
-
-  if (parent)
-    {
-      gtk_signal_connect (GTK_OBJECT (parent), "destroy",
-			  GTK_SIGNAL_FUNC (gtk_widget_destroyed),
-			  &window->transient_parent);
-      gtk_signal_connect (GTK_OBJECT (parent), "realize",
-			  GTK_SIGNAL_FUNC (gtk_window_transient_parent_realized),
-			  window);
-      gtk_signal_connect (GTK_OBJECT (parent), "unrealize",
-			  GTK_SIGNAL_FUNC (gtk_window_transient_parent_unrealized),
-			  window);
-
-      if (GTK_WIDGET_REALIZED (window) &&
-	  GTK_WIDGET_REALIZED (parent))
-	gtk_window_transient_parent_realized (GTK_WIDGET (parent),
-					      GTK_WIDGET (window));
-    }
+  g_return_if_fail (window != NULL);
+  g_return_if_fail (parent != NULL);
+  g_return_if_fail (GTK_IS_WINDOW (window));
+  g_return_if_fail (GTK_IS_WINDOW (parent));
+  g_return_if_fail (window != parent);
+  
+  gtk_signal_emit (GTK_OBJECT (window),
+                   window_signals[SET_TRANSIENT_FOR],
+                   parent);
 }
 
 static void
@@ -1512,6 +1502,48 @@
   if (window->default_widget &&
       (def_flags != GTK_WIDGET_FLAGS (window->default_widget)))
     gtk_widget_queue_draw (window->default_widget);
+}
+
+static void
+gtk_window_real_set_transient_for (GtkWindow *window,
+                                   GtkWindow *parent)
+{
+  g_return_if_fail (window != NULL);
+  g_return_if_fail (parent != NULL);
+  g_return_if_fail (GTK_IS_WINDOW (window));
+  g_return_if_fail (GTK_IS_WINDOW (parent));
+  g_return_if_fail (window != parent);
+  
+  if (window->transient_parent)
+    {
+      if (GTK_WIDGET_REALIZED (window) && 
+	  GTK_WIDGET_REALIZED (window->transient_parent) && 
+	  (!parent || !GTK_WIDGET_REALIZED (parent)))
+	gtk_window_transient_parent_unrealized (GTK_WIDGET (window->transient_parent),
+						GTK_WIDGET (window));
+
+      gtk_window_unset_transient_for (window);
+    }
+
+  window->transient_parent = parent;
+
+  if (parent)
+    {
+      gtk_signal_connect (GTK_OBJECT (parent), "destroy",
+			  GTK_SIGNAL_FUNC (gtk_widget_destroyed),
+			  &window->transient_parent);
+      gtk_signal_connect (GTK_OBJECT (parent), "realize",
+			  GTK_SIGNAL_FUNC (gtk_window_transient_parent_realized),
+			  window);
+      gtk_signal_connect (GTK_OBJECT (parent), "unrealize",
+			  GTK_SIGNAL_FUNC (gtk_window_transient_parent_unrealized),
+			  window);
+
+      if (GTK_WIDGET_REALIZED (window) &&
+	  GTK_WIDGET_REALIZED (parent))
+	gtk_window_transient_parent_realized (GTK_WIDGET (parent),
+					      GTK_WIDGET (window));
+    }
 }
 
 /*********************************
Index: gtkwindow.h
===================================================================
RCS file: /cvs/gnome/gtk+/gtk/gtkwindow.h,v
retrieving revision 1.20
diff -u -u -r1.20 gtkwindow.h
--- gtkwindow.h	2000/02/13 08:16:48	1.20
+++ gtkwindow.h	2000/03/26 19:10:54
@@ -86,6 +86,9 @@
 
   void (* set_focus)   (GtkWindow *window,
 			GtkWidget *focus);
+
+  void (* set_transient_for) (GtkWindow *window,
+                              GtkWindow *parent);
 };
 
 



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]