dialog patches



Hi,

I'm down to the dialog/window changes for uncommitted stuff in
GTK+. So here is a summary of the changes and the outstanding issues.

GtkWindow changes:

 - add GTK_WIN_POS_CENTER_ON_PARENT. Like GTK_WIN_POS_CENTER and
   GTK_WIN_POS_MOUSE, it's probably wrong to use this in normal
   desktop apps. The only reasonable desktop use of it I know of is in
   GnomeDialog, where the user can request that the WIN_POS be set.

   However, the window manager can easily produce POS_MOUSE,
   POS_CENTER, and POS_CENTER_ON_PARENT behavior, and this should
   be a window manager setting, not an application setting. If the 
   app sets anything it should be a semantic flag ("super-transient
   dialog", "toolbox") and not a position.

   So GtkDialog should be GTK_WIN_POS_NONE by default, and apps
   shouldn't change that. But GnomeDialog might want to change it,
   and for apps like AbiWord that insist on hardcoding this, at 
   least we'll be providing a non-broken way to do so instead
   of the hacks people use now. Also, there are probably 
   apps that can legitimately use the WIN_POS stuff, such as 
   kiosk apps. So I think we should have it.

 - add get_default_accel_group(); gets a default accel group; I think 
   everyone has agreed to this change.

 - adds a "destroy with parent" setting. If set, the window will 
   go away with its transient parent. Useful because most apps 
   are currently broken in this respect, because delete_event is 
   not masked off by a modal dialog, and so users can delete the
   parent window while a modal is up. With destroy_with_parent 
   the modal would go away at the same time. 

   We should probably consider whether this is a complete solution,
   and think about what the default should be, but I think it's 
   clearly a useful feature. Users can't easily add the feature
   themselves because set_transient_for isn't virtual or a signal.

GtkDialog changes:

 - Add a key press default handler; it first chains up to
   GtkWidget::key_press_event, if that returns FALSE and 
   the pressed key was Escape, it synthesizes a delete event.

 - Add a "response" signal. This is emitted when the user 
   responds to the dialog, with an integer ID for the response.
   By default, delete_event emits GTK_RESPONSE_NONE. Users
   can use their own enums for responses as well.

 - Add the concept of an "action widget." You pack an action 
   widget into the action area with a special packing function 
   (gtk_dialog_add_action_widget). Action widgets are associated
   with an integer response ID, and when the action widget is 
   activated a response signal is emitted.
  
   Question: should we s/action_widget/response_widget/g?

 - Convenience functions to add_buttons(); these take string 
   button names. If the string is a stock ID, then a stock 
   button is created, otherwise a button with the string 
   as label; the button is added as an action widget.

 - gtk_dialog_run() which blocks in a private main loop until response
   is emitted, delete_event occurs, or the dialog is destroyed.
   During gtk_dialog_run(), a handler is added to make delete_event
   not destroy the dialog. This provides the invariant that 
   after gtk_dialog_run() returns, the dialog will still be 
   undestroyed/unhidden, unless the app writer does something really 
   incorrect.

GtkMessageDialog new widget:

 This is a new widget which is a simple dialog with a stock image and
 a message. Wrap is enabled on the label. There are some standard sets
 of buttons you can have GTK+ add to the dialog for you.  The _new()
 function takes a printf-style format, so it's kind of handy to
 use. Basically this is the same widget as GnomeMessageBox. One
 notable difference is that destroy behavior is the same as GtkDialog,
 while GnomeMessageBox will destroy itself if a button is clicked.


Further rationale for GtkDialog stuff:

 There are two use cases we're envisioning for GtkDialog.

 A. Synchronous

  - create dialog with gtk_dialog_new() or new_with_buttons(),
    pack child widgets
  - int result = gtk_dialog_run (dialog)
  - switch (result) and take some action
  - destroy or hide the dialog
  - optionally, instead of destroy/hide, signal an error to the user
    and goto the gtk_dialog_run() step again

 B. Asynchronous

  - create dialog with gtk_dialog_new(), pack children
  - connect callbacks to delete_event, the "response" signal,
    and/or to widgets you're manually packed into the action area.
    The callbacks will be set up to destroy the dialog when
    appropriate.

 I've only implemented convenience stuff for case A. Case B is how
 things were done in GTK+ 1.2, and it's still somewhat unclear what 
 convenience features we want to add (probably stuff to avoid 
 connecting too many callbacks, such as HIDE_ON_DELETE_EVENT, 
 HIDE_ON_RESPONSE, blah blah).

 In case A, the behavior of gtk_dialog_run() is always a fun
 controversy. The behavior I've implemented is that gtk_dialog_run()
 will not affect the dialog; no destroys, no hides. You decide 
 what to do about that after gtk_dialog_run() returns. This makes
 code simple and clear, and it's easy to change whether the dialog 
 is destroyed depending on which button the user clicked, etc.

 It's somewhat odd that we turn off the default delete event behavior
 during gtk_dialog_run(). However, if we don't do this it makes coding
 a gtk_dialog_run() loop much more complicated (you have to hold a
 reference to the dialog, or install a delete handler, or something) 
 and people would likely end up double-destroying dialogs a lot.

 I recommend committing the current stuff, which covers use case A,
 and then discussing what to do about use case B as a separate issue.

 We do have an unfortunate constraint on possible API designs, which
 is that we can't have a delete_event default handler because it 
 would break current code that connects to delete_event and returns
 TRUE. So somewhat oddly, gtk_dialog_init() connects a delete_event
 callback to emit the response signal (and maybe later this could
 honor a flag such as HIDE_ON_DELETE, etc.)

Patches are appended.

Havoc
 
Index: ChangeLog
===================================================================
RCS file: /cvs/gnome/gtk+/ChangeLog,v
retrieving revision 1.1413
diff -u -u -r1.1413 ChangeLog
--- ChangeLog	2000/10/04 19:07:54	1.1413
+++ ChangeLog	2000/10/04 20:06:19
@@ -1,5 +1,58 @@
 2000-10-04  Havoc Pennington  <hp redhat com>
 
+	* gtk/testgtk.c (create_buttons): create some stock buttons
+	with the default accel group
+	(create_image): test some new GtkImage features
+	(make_message_dialog): test GtkMessageDialog
+
+        * gtk/gtkwindow.h, gtk/gtkwindow.c: Implement 
+	GTK_WIN_POS_CENTER_ON_PARENT. 
+	Add "destroy with parent" setting, which means the window goes
+	away with its transient parent.
+	(gtk_window_get_default_accel_group): get the default accel group
+	for the window.
+	(gtk_window_set_destroy_with_parent): set/unset destroy with
+	parent flag
+	(gtk_window_read_rcfiles): invalidate icon set caches
+	after reloading rcfiles	
+
+	* gtk/gtkenums.h (GtkWindowPosition): add
+	GTK_WIN_POS_CENTER_ON_PARENT, which centers a dialog 
+	on its parent window when the dialog is mapped for the first time.
+
+        * gtk/gtkmessagedialog.h, gtk/gtkmessagedialog.c: Add 
+	a simple message dialog class
+	
+	* gtk/gtkdialog.c (gtk_dialog_init): Connect delete event 
+	handler to emit response signal, and maybe later it would
+	honor a hide_on_delete flag - though that isn't there yet.
+	Set border width on the vbox to 2, so we get some padding.	
+	Use a button box for the action area.
+	(gtk_dialog_key_press): synthesize a delete event if Esc
+	is pressed and the GtkWidget key press handler didn't 
+	handle the escape key.
+	(gtk_dialog_new_with_buttons): new function creates a dialog
+	with some default buttons in it.
+	(gtk_dialog_add_action_widget): add an activatable widget
+	as a button in the dialog - you can also add a non-activatable
+	widget by accessing the action area directly.
+	(gtk_dialog_add_button): add a simple button - stock ID or 
+	label - to the action area
+	(gtk_dialog_response): emit response signal
+	(gtk_dialog_run): block waiting for the dialog, return 
+	the response. Override normal delete_event behavior, so that 
+	delete_event does nothing inside gtk_dialog_run().
+
+	* gtk/gtkdialog.h, gtk/gtkdialog.c: Add "response" signal
+	emitted when an action widget is clicked or the dialog gets
+	delete_event
+
+	* gtk/gtk.h: add gtkmessagedialog.h
+
+	* gtk/Makefile.am: add gtkmessagedialog.[hc]
+
+2000-10-04  Havoc Pennington  <hp redhat com>
+
 	* gtk/gtkstock.h, gtk/gtkstock.c, gtk/gtkiconfactory.h,
 	gtk/gtkiconfactory.c: Fix copyrights	
 
Index: gtk/Makefile.am
===================================================================
RCS file: /cvs/gnome/gtk+/gtk/Makefile.am,v
retrieving revision 1.122
diff -u -u -r1.122 Makefile.am
--- gtk/Makefile.am	2000/10/02 14:29:23	1.122
+++ gtk/Makefile.am	2000/10/04 20:06:19
@@ -116,6 +116,7 @@
 	gtkmenufactory.h	\
 	gtkmenuitem.h		\
 	gtkmenushell.h		\
+	gtkmessagedialog.h	\
 	gtkmisc.h		\
 	gtknotebook.h		\
 	gtkobject.h		\
@@ -267,6 +268,7 @@
 	gtkmenufactory.c	\
 	gtkmenuitem.c		\
 	gtkmenushell.c		\
+	gtkmessagedialog.c	\
 	gtkmisc.c		\
 	gtknotebook.c		\
 	gtkobject.c		\
Index: gtk/gtk.h
===================================================================
RCS file: /cvs/gnome/gtk+/gtk/gtk.h,v
retrieving revision 1.33
diff -u -u -r1.33 gtk.h
--- gtk/gtk.h	2000/09/26 20:22:13	1.33
+++ gtk/gtk.h	2000/10/04 20:06:19
@@ -93,6 +93,7 @@
 #include <gtk/gtkmenufactory.h>
 #include <gtk/gtkmenuitem.h>
 #include <gtk/gtkmenushell.h>
+#include <gtk/gtkmessagedialog.h>
 #include <gtk/gtkmisc.h>
 #include <gtk/gtknotebook.h>
 #include <gtk/gtkobject.h>
Index: gtk/gtkdialog.c
===================================================================
RCS file: /cvs/gnome/gtk+/gtk/gtkdialog.c,v
retrieving revision 1.11
diff -u -u -r1.11 gtkdialog.c
--- gtk/gtkdialog.c	2000/07/26 11:32:43	1.11
+++ gtk/gtkdialog.c	2000/10/04 20:06:19
@@ -26,15 +26,35 @@
 
 #include "gtkbutton.h"
 #include "gtkdialog.h"
-#include "gtkhbox.h"
+#include "gtkhbbox.h"
 #include "gtkhseparator.h"
 #include "gtkvbox.h"
+#include "gtksignal.h"
+#include "gdkkeysyms.h"
+#include "gtkmain.h"
 
-
 static void gtk_dialog_class_init (GtkDialogClass *klass);
 static void gtk_dialog_init       (GtkDialog      *dialog);
+static gint gtk_dialog_key_press  (GtkWidget      *widget,
+                                   GdkEventKey    *key);                                   
+
+static void gtk_dialog_add_buttons_valist (GtkDialog   *dialog,
+                                           const gchar *first_button_text,
+                                           va_list      args);
+
+static gint gtk_dialog_delete_event_handler (GtkWidget   *widget,
+                                             GdkEventAny *event,
+                                             gpointer     user_data);
+
 
+enum {
+  RESPONSE,
+  LAST_SIGNAL
+};
 
+static gpointer parent_class;
+static guint dialog_signals[LAST_SIGNAL];
+
 GtkType
 gtk_dialog_get_type (void)
 {
@@ -63,6 +83,26 @@
 static void
 gtk_dialog_class_init (GtkDialogClass *class)
 {
+  GtkObjectClass *object_class;
+  GtkWidgetClass *widget_class;
+  
+  object_class = (GtkObjectClass*) class;
+  widget_class = (GtkWidgetClass*) class;
+
+  parent_class = g_type_class_peek_parent (class);
+  
+  dialog_signals[RESPONSE] =
+    gtk_signal_new ("response",
+                    GTK_RUN_LAST,
+                    GTK_CLASS_TYPE (object_class),
+                    GTK_SIGNAL_OFFSET (GtkDialogClass, response),
+                    gtk_marshal_NONE__INT,
+		    GTK_TYPE_NONE, 1,
+                    GTK_TYPE_INT);
+
+  gtk_object_class_add_signals (object_class, dialog_signals, LAST_SIGNAL);
+
+  widget_class->key_press_event = gtk_dialog_key_press;
 }
 
 static void
@@ -70,13 +110,30 @@
 {
   GtkWidget *separator;
 
+  /* To avoid breaking old code that prevents destroy on delete event
+   * by connecting a handler, we have to have the FIRST signal
+   * connection on the dialog.
+   */
+  gtk_signal_connect (GTK_OBJECT (dialog),
+                      "delete_event",
+                      GTK_SIGNAL_FUNC (gtk_dialog_delete_event_handler),
+                      NULL);
+  
   dialog->vbox = gtk_vbox_new (FALSE, 0);
+
+  gtk_container_set_border_width (GTK_CONTAINER (dialog->vbox), 2);
+  
   gtk_container_add (GTK_CONTAINER (dialog), dialog->vbox);
   gtk_widget_show (dialog->vbox);
+
+  dialog->action_area = gtk_hbutton_box_new ();
 
-  dialog->action_area = gtk_hbox_new (TRUE, 5);
+  gtk_button_box_set_layout (GTK_BUTTON_BOX (dialog->action_area),
+                             GTK_BUTTONBOX_SPREAD);
+  
   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_box_pack_end (GTK_BOX (dialog->vbox), dialog->action_area,
+                    FALSE, TRUE, 0);
   gtk_widget_show (dialog->action_area);
 
   separator = gtk_hseparator_new ();
@@ -84,8 +141,361 @@
   gtk_widget_show (separator);
 }
 
+static gint
+gtk_dialog_delete_event_handler (GtkWidget   *widget,
+                                 GdkEventAny *event,
+                                 gpointer     user_data)
+{
+  /* emit response signal */
+  gtk_dialog_response (GTK_DIALOG (widget), GTK_RESPONSE_NONE);
+
+  /* Do the destroy by default */
+  return FALSE;
+}
+
+static gint
+gtk_dialog_key_press (GtkWidget   *widget,
+                      GdkEventKey *key)
+{
+  GdkEventAny event;
+
+  event.type = GDK_DELETE;
+  event.window = widget->window;
+  event.send_event = TRUE;
+
+  if (GTK_WIDGET_CLASS (parent_class)->key_press_event (widget, key))
+    return TRUE;
+
+  if (key->keyval != GDK_Escape)
+    return FALSE;
+
+  /* Synthesize delete_event on key press. */
+  g_object_ref (G_OBJECT (event.window));
+  
+  gtk_main_do_event ((GdkEvent*)&event);
+  
+  g_object_unref (G_OBJECT (event.window));
+
+  return TRUE;
+}
+
 GtkWidget*
 gtk_dialog_new (void)
 {
   return GTK_WIDGET (gtk_type_new (GTK_TYPE_DIALOG));
 }
+
+static GtkWidget*
+gtk_dialog_new_empty (const gchar     *title,
+                      GtkWindow       *parent,
+                      GtkDialogFlags   flags)
+{
+  GtkDialog *dialog;
+
+  dialog = GTK_DIALOG (g_object_new (GTK_TYPE_DIALOG, NULL));
+
+  if (title)
+    gtk_window_set_title (GTK_WINDOW (dialog), title);
+
+  if (parent)
+    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_DESTROY_WITH_PARENT)
+    gtk_window_set_destroy_with_parent (GTK_WINDOW (dialog), TRUE);
+
+  return GTK_WIDGET (dialog);
+}
+
+GtkWidget*
+gtk_dialog_new_with_buttons (const gchar    *title,
+                             GtkWindow      *parent,
+                             GtkDialogFlags  flags,
+                             const gchar    *first_button_text,
+                             ...)
+{
+  GtkDialog *dialog;
+  va_list args;
+  
+  dialog = GTK_DIALOG (gtk_dialog_new_empty (title, parent, flags));
+
+  va_start (args, first_button_text);
+
+  gtk_dialog_add_buttons_valist (dialog,
+                                 first_button_text,
+                                 args);
+  
+  va_end (args);
+
+  return GTK_WIDGET (dialog);
+}
+
+typedef struct _ResponseData ResponseData;
+
+struct _ResponseData
+{
+  gint response_id;
+};
+
+static ResponseData*
+get_response_data (GtkWidget *widget)
+{
+  ResponseData *ad = gtk_object_get_data (GTK_OBJECT (widget),
+                                          "gtk-dialog-response-data");
+
+  if (ad == NULL)
+    {
+      ad = g_new (ResponseData, 1);
+      
+      gtk_object_set_data_full (GTK_OBJECT (widget),
+                                "gtk-dialog-response-data",
+                                ad,
+                                g_free);
+    }
+
+  return ad;
+}
+
+static void
+action_widget_activated (GtkWidget *widget, GtkDialog *dialog)
+{
+  ResponseData *ad;
+  gint response_id;
+  
+  g_return_if_fail (GTK_IS_DIALOG (dialog));
+
+  response_id = GTK_RESPONSE_NONE;
+  
+  ad = get_response_data (widget);
+
+  g_assert (ad != NULL);
+  
+  response_id = ad->response_id;
+
+  gtk_dialog_response (dialog, response_id);
+}
+  
+void
+gtk_dialog_add_action_widget  (GtkDialog *dialog,
+                               GtkWidget *child,
+                               gint       response_id)
+{
+  ResponseData *ad;
+  
+  g_return_if_fail (GTK_IS_DIALOG (dialog));
+  g_return_if_fail (GTK_IS_WIDGET (child));
+
+  ad = get_response_data (child);
+
+  ad->response_id = response_id;
+
+  if (GTK_WIDGET_GET_CLASS (child)->activate_signal != 0)
+    {
+      const gchar* name =
+        gtk_signal_name (GTK_WIDGET_GET_CLASS (child)->activate_signal);
+
+      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");
+
+  gtk_box_pack_end (GTK_BOX (dialog->action_area),
+                    child,
+                    FALSE, TRUE, 5);  
+}
+
+void
+gtk_dialog_add_button (GtkDialog   *dialog,
+                       const gchar *button_text,
+                       gint         response_id)
+{
+  GtkWidget *button;
+  
+  g_return_if_fail (GTK_IS_DIALOG (dialog));
+  g_return_if_fail (button_text != NULL);
+
+  button = gtk_button_new_stock (button_text,
+                                 gtk_window_get_default_accel_group (GTK_WINDOW (dialog)));
+
+  gtk_widget_show (button);
+  
+  gtk_dialog_add_action_widget (dialog,
+                                button,
+                                response_id);
+}
+
+static void
+gtk_dialog_add_buttons_valist(GtkDialog      *dialog,
+                              const gchar    *first_button_text,
+                              va_list         args)
+{
+  const gchar* text;
+  gint response_id;
+
+  if (first_button_text == NULL)
+    return;
+  
+  text = first_button_text;
+  response_id = va_arg (args, gint);
+
+  while (text != NULL)
+    {
+      gtk_dialog_add_button (dialog, text, response_id);
+
+      text = va_arg (args, gchar*);
+      if (text == NULL)
+        break;
+      response_id = va_arg (args, int);
+    }
+}
+
+void
+gtk_dialog_add_buttons (GtkDialog   *dialog,
+                        const gchar *first_button_text,
+                        ...)
+{
+  
+  va_list args;
+
+  va_start (args, first_button_text);
+
+  gtk_dialog_add_buttons_valist (dialog,
+                                 first_button_text,
+                                 args);
+  
+  va_end (args);
+}
+
+void
+gtk_dialog_response (GtkDialog *dialog,
+                     gint       response_id)
+{
+  g_return_if_fail (dialog != NULL);
+  g_return_if_fail (GTK_IS_DIALOG (dialog));
+
+  gtk_signal_emit (GTK_OBJECT (dialog),
+                   dialog_signals[RESPONSE],
+                   response_id);
+}
+
+typedef struct
+{
+  GtkDialog *dialog;
+  gint response_id;
+  GMainLoop *loop;
+} RunInfo;
+
+static void
+shutdown_loop (RunInfo *ri)
+{
+  if (ri->loop != NULL)
+    {
+      g_main_quit (ri->loop);
+      g_main_destroy (ri->loop);
+      ri->loop = NULL;
+    }
+}
+
+static void
+run_destroy_handler (GtkDialog *dialog, gpointer data)
+{
+  RunInfo *ri = data;
+
+  shutdown_loop (ri);
+}
+
+static void
+run_response_handler (GtkDialog *dialog,
+                      gint response_id,
+                      gpointer data)
+{
+  RunInfo *ri;
+
+  ri = data;
+
+  ri->response_id = response_id;
+
+  shutdown_loop (ri);
+}
+
+static gint
+run_delete_handler (GtkDialog *dialog,
+                    GdkEventAny *event,
+                    gpointer data)
+{
+  RunInfo *ri = data;
+    
+  shutdown_loop (ri);
+
+  /* emit response signal */
+  gtk_dialog_response (dialog, GTK_RESPONSE_NONE);
+  
+  return TRUE; /* Do not destroy */
+}
+
+gint
+gtk_dialog_run (GtkDialog *dialog)
+{
+  RunInfo ri = { NULL, GTK_RESPONSE_NONE, NULL };
+  gboolean was_modal;
+  guint response_handler;
+  guint destroy_handler;
+  guint delete_handler;
+  
+  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);
+
+
+  response_handler =
+    gtk_signal_connect (GTK_OBJECT (dialog),
+                        "response",
+                        GTK_SIGNAL_FUNC (run_response_handler),
+                        &ri);
+  
+  destroy_handler =
+    gtk_signal_connect (GTK_OBJECT (dialog),
+                        "destroy",
+                        GTK_SIGNAL_FUNC (run_destroy_handler),
+                        &ri);
+  
+  delete_handler =
+    gtk_signal_connect (GTK_OBJECT (dialog),
+                        "delete_event",
+                        GTK_SIGNAL_FUNC (run_delete_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), destroy_handler);
+      gtk_signal_disconnect (GTK_OBJECT (dialog), response_handler);
+      gtk_signal_disconnect (GTK_OBJECT (dialog), delete_handler);
+    }
+
+  gtk_object_unref (GTK_OBJECT (dialog));
+
+  return ri.response_id;
+}
+
+
+
+
Index: gtk/gtkdialog.h
===================================================================
RCS file: /cvs/gnome/gtk+/gtk/gtkdialog.h,v
retrieving revision 1.8
diff -u -u -r1.8 gtkdialog.h
--- gtk/gtkdialog.h	2000/08/30 00:33:37	1.8
+++ gtk/gtkdialog.h	2000/10/04 20:06:19
@@ -36,7 +36,36 @@
 extern "C" {
 #endif /* __cplusplus */
 
+/* Parameters for dialog construction */
+typedef enum
+{
+  GTK_DIALOG_MODAL,              /* call gtk_window_set_modal (win, TRUE) */
+  GTK_DIALOG_DESTROY_WITH_PARENT /* call gtk_window_set_destroy_with_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 a response widget has no response_id,
+   * or the dialog gets destroyed with no response
+   */
+  GTK_RESPONSE_NONE = -1,
+  /* GTK won't return these unless you pass them in
+   * as the response for an action widget
+   */
+  GTK_RESPONSE_REJECT = -2,
+  GTK_RESPONSE_ACCEPT = -3
+} GtkResponseType;
 
+
 #define GTK_TYPE_DIALOG                  (gtk_dialog_get_type ())
 #define GTK_DIALOG(obj)                  (GTK_CHECK_CAST ((obj), GTK_TYPE_DIALOG, GtkDialog))
 #define GTK_DIALOG_CLASS(klass)          (GTK_CHECK_CLASS_CAST ((klass), GTK_TYPE_DIALOG, GtkDialogClass))
@@ -47,8 +76,6 @@
 
 typedef struct _GtkDialog        GtkDialog;
 typedef struct _GtkDialogClass   GtkDialogClass;
-typedef struct _GtkDialogButton  GtkDialogButton;
-
 
 struct _GtkDialog
 {
@@ -61,12 +88,38 @@
 struct _GtkDialogClass
 {
   GtkWindowClass parent_class;
+
+  void (* response) (GtkDialog *dialog, gint response_id);
 };
 
 
 GtkType    gtk_dialog_get_type (void) G_GNUC_CONST;
 GtkWidget* gtk_dialog_new      (void);
 
+GtkWidget* gtk_dialog_new_with_buttons (const gchar     *title,
+                                        GtkWindow       *parent,
+                                        GtkDialogFlags   flags,
+                                        const gchar     *first_button_text,
+                                        ...);
+
+void gtk_dialog_add_action_widget  (GtkDialog *dialog,
+                                    GtkWidget *widget,
+                                    gint       response_id);
+
+void gtk_dialog_add_button         (GtkDialog   *dialog,
+                                    const gchar *button_text,
+                                    gint         response_id);
+
+void gtk_dialog_add_buttons        (GtkDialog   *dialog,
+                                    const gchar *first_button_text,
+                                    ...);
+
+/* Emit response signal */
+void gtk_dialog_response           (GtkDialog *dialog,
+                                    gint       response_id);
+
+/* Returns response_id */
+gint gtk_dialog_run                (GtkDialog *dialog);
 
 #ifdef __cplusplus
 }
Index: gtk/gtkenums.h
===================================================================
RCS file: /cvs/gnome/gtk+/gtk/gtkenums.h,v
retrieving revision 1.29
diff -u -u -r1.29 gtkenums.h
--- gtk/gtkenums.h	2000/09/14 16:41:19	1.29
+++ gtk/gtkenums.h	2000/10/04 20:06:19
@@ -338,7 +338,8 @@
   GTK_WIN_POS_NONE,
   GTK_WIN_POS_CENTER,
   GTK_WIN_POS_MOUSE,
-  GTK_WIN_POS_CENTER_ALWAYS
+  GTK_WIN_POS_CENTER_ALWAYS,
+  GTK_WIN_POS_CENTER_ON_PARENT
 } GtkWindowPosition;
 
 /* Window types */
Index: gtk/gtkmessagedialog.c
===================================================================
RCS file: gtkmessagedialog.c
diff -N gtkmessagedialog.c
--- /dev/null	Tue May  5 16:32:27 1998
+++ gtkmessagedialog.c	Wed Oct  4 16:06:19 2000
@@ -0,0 +1,228 @@
+/* GTK - The GIMP Toolkit
+ * Copyright (C) 2000 Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+/*
+ * Modified by the GTK+ Team and others 1997-1999.  See the AUTHORS
+ * file for a list of people on the GTK+ Team.  See the ChangeLog
+ * files for a list of changes.  These files are distributed with
+ * GTK+ at ftp://ftp.gtk.org/pub/gtk/. 
+ */
+
+#include "gtkmessagedialog.h"
+#include "gtklabel.h"
+#include "gtkhbox.h"
+#include "gtkimage.h"
+#include "gtkstock.h"
+#include "gtkiconfactory.h"
+
+static void gtk_message_dialog_class_init (GtkMessageDialogClass *klass);
+static void gtk_message_dialog_init       (GtkMessageDialog      *dialog);
+
+
+GtkType
+gtk_message_dialog_get_type (void)
+{
+  static GtkType dialog_type = 0;
+
+  if (!dialog_type)
+    {
+      static const GtkTypeInfo dialog_info =
+      {
+	"GtkMessageDialog",
+	sizeof (GtkMessageDialog),
+	sizeof (GtkMessageDialogClass),
+	(GtkClassInitFunc) gtk_message_dialog_class_init,
+	(GtkObjectInitFunc) gtk_message_dialog_init,
+	/* reserved_1 */ NULL,
+        /* reserved_2 */ NULL,
+        (GtkClassInitFunc) NULL,
+      };
+
+      dialog_type = gtk_type_unique (GTK_TYPE_DIALOG, &dialog_info);
+    }
+
+  return dialog_type;
+}
+
+static void
+gtk_message_dialog_class_init (GtkMessageDialogClass *class)
+{
+}
+
+static void
+gtk_message_dialog_init (GtkMessageDialog *dialog)
+{
+  GtkWidget *hbox;
+  
+  dialog->label = gtk_label_new (NULL);
+  dialog->image = gtk_image_new_from_stock (NULL, GTK_ICON_SIZE_DIALOG);
+  
+  gtk_label_set_line_wrap (GTK_LABEL (dialog->label), TRUE);
+
+  hbox = gtk_hbox_new (FALSE, 10);
+
+  gtk_container_set_border_width (GTK_CONTAINER (hbox), 10);
+  
+  gtk_box_pack_start (GTK_BOX (hbox), dialog->image,
+                      FALSE, FALSE, 2);
+
+  gtk_box_pack_start (GTK_BOX (hbox), dialog->label,
+                      TRUE, TRUE, 2);
+
+  gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dialog)->vbox),
+                      hbox,
+                      FALSE, FALSE, 10);
+
+  gtk_widget_show_all (hbox);
+}
+
+static void
+setup_type(GtkMessageDialog *dialog, GtkMessageType type)
+{
+  /* Note: this function can be called more than once,
+   * and after showing the dialog, due to object args
+   */
+  
+  const gchar *stock_id = NULL;
+  GtkStockItem item;
+  
+  switch (type)
+    {
+    case GTK_MESSAGE_INFO:
+      stock_id = GTK_STOCK_DIALOG_INFO;
+      break;
+
+    case GTK_MESSAGE_QUESTION:
+      stock_id = GTK_STOCK_DIALOG_QUESTION;
+      break;
+
+    case GTK_MESSAGE_WARNING:
+      stock_id = GTK_STOCK_DIALOG_WARNING;
+      break;
+      
+    case GTK_MESSAGE_ERROR:
+      stock_id = GTK_STOCK_DIALOG_ERROR;
+      break;
+      
+    default:
+      g_warning ("Unknown GtkMessageType");
+      break;
+    }
+
+  if (stock_id == NULL)
+    stock_id = GTK_STOCK_DIALOG_INFO;
+
+  if (gtk_stock_lookup (stock_id, &item))
+    {
+      gtk_image_set_from_stock (GTK_IMAGE (dialog->image), stock_id,
+                                GTK_ICON_SIZE_DIALOG);
+      
+      gtk_window_set_title (GTK_WINDOW (dialog), item.label);
+    }
+  else
+    g_warning ("Stock dialog ID doesn't exist?");  
+}
+
+GtkWidget*
+gtk_message_dialog_new (GtkWindow     *parent,
+                        GtkDialogFlags flags,
+                        GtkMessageType type,
+                        GtkButtonsType buttons,
+                        const gchar   *message_format,
+                        ...)
+{
+  GtkWidget *widget;
+  GtkDialog *dialog;
+  gchar* msg;
+  va_list args;
+  
+  widget = GTK_WIDGET (gtk_type_new (GTK_TYPE_MESSAGE_DIALOG));
+  dialog = GTK_DIALOG (widget);
+
+  va_start (args, message_format);
+  msg = g_strdup_vprintf(message_format, args);
+  va_end (args);
+
+  gtk_label_set_text (GTK_LABEL (GTK_MESSAGE_DIALOG (widget)->label),
+                      msg);
+
+  g_free (msg);
+
+  if (parent != NULL)
+    gtk_window_set_transient_for (GTK_WINDOW (widget),
+                                  GTK_WINDOW (parent));
+  
+
+  if (flags & GTK_DIALOG_MODAL)
+    gtk_window_set_modal (GTK_WINDOW (dialog), TRUE);
+
+  if (flags & GTK_DIALOG_DESTROY_WITH_PARENT)
+    gtk_window_set_destroy_with_parent (GTK_WINDOW (dialog), TRUE);
+  
+  setup_type (GTK_MESSAGE_DIALOG (dialog), type);
+  
+  switch (buttons)
+    {
+    case GTK_BUTTONS_NONE:
+      /* nothing */
+      break;
+
+    case GTK_BUTTONS_OK:
+      gtk_dialog_add_button (dialog,
+                             GTK_STOCK_BUTTON_OK,
+                             GTK_RESPONSE_ACCEPT);
+      break;
+
+    case GTK_BUTTONS_CLOSE:
+      gtk_dialog_add_button (dialog,
+                             GTK_STOCK_BUTTON_CLOSE,
+                             GTK_RESPONSE_ACCEPT);
+      break;
+
+    case GTK_BUTTONS_CANCEL:
+      gtk_dialog_add_button (dialog,
+                             GTK_STOCK_BUTTON_CANCEL,
+                             GTK_RESPONSE_REJECT);
+      break;
+
+    case GTK_BUTTONS_YES_NO:
+      gtk_dialog_add_button (dialog,
+                             GTK_STOCK_BUTTON_YES,
+                             GTK_RESPONSE_ACCEPT);
+      gtk_dialog_add_button (dialog,
+                             GTK_STOCK_BUTTON_NO,
+                             GTK_RESPONSE_REJECT);
+      break;
+
+    case GTK_BUTTONS_OK_CANCEL:
+      gtk_dialog_add_button (dialog,
+                             GTK_STOCK_BUTTON_OK,
+                             GTK_RESPONSE_ACCEPT);
+      gtk_dialog_add_button (dialog,
+                             GTK_STOCK_BUTTON_CANCEL,
+                             GTK_RESPONSE_REJECT);
+      break;
+      
+    default:
+      g_warning ("Unknown GtkButtonsType");
+      break;
+    }
+
+  return widget;
+}
Index: gtk/gtkmessagedialog.h
===================================================================
RCS file: gtkmessagedialog.h
diff -N gtkmessagedialog.h
--- /dev/null	Tue May  5 16:32:27 1998
+++ gtkmessagedialog.h	Wed Oct  4 16:06:19 2000
@@ -0,0 +1,96 @@
+/* GTK - The GIMP Toolkit
+ * Copyright (C) 2000 Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+/*
+ * Modified by the GTK+ Team and others 1997-2000.  See the AUTHORS
+ * file for a list of people on the GTK+ Team.  See the ChangeLog
+ * files for a list of changes.  These files are distributed with
+ * GTK+ at ftp://ftp.gtk.org/pub/gtk/. 
+ */
+
+#ifndef __GTK_MESSAGE_DIALOG_H__
+#define __GTK_MESSAGE_DIALOG_H__
+
+#include <gtk/gtkdialog.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+typedef enum
+{
+  GTK_MESSAGE_INFO,
+  GTK_MESSAGE_WARNING,
+  GTK_MESSAGE_QUESTION,
+  GTK_MESSAGE_ERROR
+} GtkMessageType;
+
+typedef enum
+{
+  GTK_BUTTONS_NONE,
+  GTK_BUTTONS_OK,
+  GTK_BUTTONS_CLOSE,
+  GTK_BUTTONS_CANCEL,
+  GTK_BUTTONS_YES_NO,
+  GTK_BUTTONS_OK_CANCEL
+} GtkButtonsType;
+
+#define GTK_TYPE_MESSAGE_DIALOG                  (gtk_message_dialog_get_type ())
+#define GTK_MESSAGE_DIALOG(obj)                  (GTK_CHECK_CAST ((obj), GTK_TYPE_MESSAGE_DIALOG, GtkMessageDialog))
+#define GTK_MESSAGE_DIALOG_CLASS(klass)          (GTK_CHECK_CLASS_CAST ((klass), GTK_TYPE_MESSAGE_DIALOG, GtkMessageDialogClass))
+#define GTK_IS_MESSAGE_DIALOG(obj)               (GTK_CHECK_TYPE ((obj), GTK_TYPE_MESSAGE_DIALOG))
+#define GTK_IS_MESSAGE_DIALOG_CLASS(klass)       (GTK_CHECK_CLASS_TYPE ((klass), GTK_TYPE_MESSAGE_DIALOG))
+#define GTK_MESSAGE_DIALOG_GET_CLASS(obj)        (GTK_CHECK_GET_CLASS ((obj), GTK_TYPE_MESSAGE_DIALOG, GtkMessageDialogClass))
+
+
+typedef struct _GtkMessageDialog        GtkMessageDialog;
+typedef struct _GtkMessageDialogClass   GtkMessageDialogClass;
+
+struct _GtkMessageDialog
+{
+  GtkDialog parent_instance;
+
+  GtkWidget *image;
+  GtkWidget *label;
+};
+
+struct _GtkMessageDialogClass
+{
+  GtkDialogClass parent_class;
+
+  
+};
+
+GtkType    gtk_message_dialog_get_type (void);
+
+GtkWidget* gtk_message_dialog_new      (GtkWindow      *parent,
+                                        GtkDialogFlags  flags,
+                                        GtkMessageType  type,
+                                        GtkButtonsType  buttons,
+                                        const gchar    *message_format,
+                                        ...) G_GNUC_PRINTF (5, 6);
+ 
+
+
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif /* __GTK_MESSAGE_DIALOG_H__ */
Index: gtk/gtkwindow.c
===================================================================
RCS file: /cvs/gnome/gtk+/gtk/gtkwindow.c,v
retrieving revision 1.87
diff -u -u -r1.87 gtkwindow.c
--- gtk/gtkwindow.c	2000/09/03 05:49:33	1.87
+++ gtk/gtkwindow.c	2000/10/04 20:06:19
@@ -45,6 +45,7 @@
 #include "gtkwindow.h"
 #include "gtkbindings.h"
 #include "gtkmain.h"
+#include "gtkiconfactory.h"
 
 /* TODO: remove this define and assorted code in 1.3 and fix up the
  * real culprits.
@@ -65,7 +66,8 @@
   ARG_MODAL,
   ARG_WIN_POS,
   ARG_DEFAULT_WIDTH,
-  ARG_DEFAULT_HEIGHT
+  ARG_DEFAULT_HEIGHT,
+  ARG_DESTROY_WITH_PARENT
 };
 
 typedef struct {
@@ -225,6 +227,7 @@
   gtk_object_add_arg_type ("GtkWindow::window_position", GTK_TYPE_WINDOW_POSITION, GTK_ARG_READWRITE, ARG_WIN_POS);
   gtk_object_add_arg_type ("GtkWindow::default_width", GTK_TYPE_INT, GTK_ARG_READWRITE, ARG_DEFAULT_WIDTH);
   gtk_object_add_arg_type ("GtkWindow::default_height", GTK_TYPE_INT, GTK_ARG_READWRITE, ARG_DEFAULT_HEIGHT);
+  gtk_object_add_arg_type ("GtkWindow::destroy_with_parent", GTK_TYPE_BOOL, GTK_ARG_READWRITE, ARG_DESTROY_WITH_PARENT);
   
   window_signals[SET_FOCUS] =
     gtk_signal_new ("set_focus",
@@ -335,6 +338,9 @@
     case ARG_DEFAULT_HEIGHT:
       gtk_window_set_default_size (window, -2, GTK_VALUE_INT (*arg));
       break;
+    case ARG_DESTROY_WITH_PARENT:
+      gtk_window_set_destroy_with_parent (window, GTK_VALUE_BOOL (*arg));
+      break;
     default:
       break;
     }
@@ -387,6 +393,9 @@
       else
 	GTK_VALUE_INT (*arg) = info->height;
       break;
+    case ARG_DESTROY_WITH_PARENT:
+      GTK_VALUE_BOOL (*arg) = window->destroy_with_parent;
+      break;
     default:
       arg->type = GTK_TYPE_INVALID;
       break;
@@ -527,6 +536,29 @@
   gtk_accel_group_detach (accel_group, GTK_OBJECT (window));
 }
 
+GtkAccelGroup*
+gtk_window_get_default_accel_group (GtkWindow *window)
+{
+  GtkAccelGroup *group;
+  
+  g_return_val_if_fail (GTK_IS_WINDOW (window), NULL);
+
+  group = gtk_object_get_data (GTK_OBJECT (window),
+                               "gtk-accel-group");
+
+  if (group == NULL)
+    {
+      group = gtk_accel_group_new ();
+      gtk_window_add_accel_group (window, group);
+      gtk_object_set_data (GTK_OBJECT (window),
+                           "gtk-accel-group",
+                           group);
+      gtk_accel_group_unref (group);
+    }
+
+  return group;
+}
+
 void
 gtk_window_set_position (GtkWindow         *window,
 			 GtkWindowPosition  position)
@@ -688,6 +720,35 @@
 }
 
 static void
+parent_destroyed_callback (GtkWindow *parent, GtkWindow *child)
+{
+  gtk_widget_destroy (GTK_WIDGET (child));
+}
+
+static void
+connect_parent_destroyed (GtkWindow *window)
+{
+  if (window->transient_parent)
+    {
+      gtk_signal_connect (GTK_OBJECT (window->transient_parent),
+                          "destroy",
+                          GTK_SIGNAL_FUNC (parent_destroyed_callback),
+                          window);
+    }  
+}
+
+static void
+disconnect_parent_destroyed (GtkWindow *window)
+{
+  if (window->transient_parent)
+    {
+      gtk_signal_disconnect_by_func (GTK_OBJECT (window->transient_parent),
+                                     GTK_SIGNAL_FUNC (parent_destroyed_callback),
+                                     window);
+    }
+}
+
+static void
 gtk_window_transient_parent_realized (GtkWidget *parent,
 				      GtkWidget *window)
 {
@@ -719,6 +780,9 @@
 				     GTK_SIGNAL_FUNC (gtk_widget_destroyed),
 				     &window->transient_parent);
 
+      if (window->destroy_with_parent)
+        disconnect_parent_destroyed (window);
+      
       window->transient_parent = NULL;
     }
 }
@@ -727,8 +791,11 @@
 gtk_window_set_transient_for  (GtkWindow *window, 
 			       GtkWindow *parent)
 {
-  g_return_if_fail (window != 0);
+  g_return_if_fail (GTK_IS_WINDOW (window));
+  g_return_if_fail (parent == NULL || GTK_IS_WINDOW (parent));
+  g_return_if_fail (window != parent);
 
+    
   if (window->transient_parent)
     {
       if (GTK_WIDGET_REALIZED (window) && 
@@ -754,6 +821,9 @@
 			  GTK_SIGNAL_FUNC (gtk_window_transient_parent_unrealized),
 			  window);
 
+      if (window->destroy_with_parent)
+        connect_parent_destroyed (window);
+      
       if (GTK_WIDGET_REALIZED (window) &&
 	  GTK_WIDGET_REALIZED (parent))
 	gtk_window_transient_parent_realized (GTK_WIDGET (parent),
@@ -761,6 +831,31 @@
     }
 }
 
+void
+gtk_window_set_destroy_with_parent  (GtkWindow *window,
+                                     gboolean   setting)
+{
+  g_return_if_fail (GTK_IS_WINDOW (window));
+
+  if (window->destroy_with_parent == (setting != FALSE))
+    return;
+
+  if (window->destroy_with_parent)
+    {
+      g_assert (!setting);
+
+      disconnect_parent_destroyed (window);
+    }
+  else
+    {
+      g_assert (setting);
+
+      connect_parent_destroyed (window);
+    }
+  
+  window->destroy_with_parent = setting;
+}
+
 static void
 gtk_window_geometry_destroy (GtkWindowGeometryInfo *info)
 {
@@ -859,7 +954,7 @@
   window = GTK_WINDOW (object);
 
   if (window->transient_parent)
-    gtk_window_unset_transient_for (window);
+    gtk_window_set_transient_for (window, NULL);
 
   if (window->has_user_ref_count)
     {
@@ -1432,10 +1527,15 @@
        * of date, so we need to reset all our widgets. Our other
        * toplevel windows will also get the message, but by
        * then, the RC file will up to date, so we have to tell
-       * them now.
+       * them now. Also, we have to invalidate cached icons in
+       * icon sets so they get re-rendered.
        */
-      GList *list, *toplevels = gtk_window_list_toplevels ();
+      GList *list, *toplevels;
 
+      _gtk_icon_set_invalidate_caches ();
+      
+      toplevels = gtk_window_list_toplevels ();
+      
       for (list = toplevels; list; list = list->next)
 	{
 	  gtk_widget_reset_rc_styles (list->data);
@@ -2056,14 +2156,24 @@
 			       gint       *y)
 {
   GtkWidget *widget;
-
+  GtkWindowPosition pos;
+  GtkWidget *parent_widget;
+  
   widget = GTK_WIDGET (window);
 
   *x = -1;
   *y = -1;
+
+  parent_widget = (GtkWidget*) window->transient_parent;
   
-  switch (window->position)
-    {
+  pos = window->position;
+  if (pos == GTK_WIN_POS_CENTER_ON_PARENT &&
+      (parent_widget == NULL ||
+       !GTK_WIDGET_MAPPED (parent_widget)))
+    pos = GTK_WIN_POS_NONE;
+  
+  switch (pos)
+  {
     case GTK_WIN_POS_CENTER:
     case GTK_WIN_POS_CENTER_ALWAYS:
       if (window->use_uposition)
@@ -2075,6 +2185,19 @@
 	  *y = (screen_height - new_height) / 2;
 	}
       break;
+
+    case GTK_WIN_POS_CENTER_ON_PARENT:
+      if (window->use_uposition)
+        {
+          gint ox, oy;
+          gdk_window_get_origin (parent_widget->window,
+                                 &ox, &oy);
+                                 
+          *x = ox + (parent_widget->allocation.width - new_width) / 2;
+          *y = oy + (parent_widget->allocation.height - new_height) / 2;
+        }
+      break;
+
     case GTK_WIN_POS_MOUSE:
       if (window->use_uposition)
 	{
Index: gtk/gtkwindow.h
===================================================================
RCS file: /cvs/gnome/gtk+/gtk/gtkwindow.h,v
retrieving revision 1.23
diff -u -u -r1.23 gtkwindow.h
--- gtk/gtkwindow.h	2000/08/30 00:33:38	1.23
+++ gtk/gtkwindow.h	2000/10/04 20:06:19
@@ -79,6 +79,7 @@
    */
   guint use_uposition : 1;
   guint modal : 1;
+  guint destroy_with_parent : 1;
 };
 
 struct _GtkWindowClass
@@ -112,6 +113,8 @@
 
 void       gtk_window_set_transient_for        (GtkWindow           *window, 
 						GtkWindow           *parent);
+void       gtk_window_set_destroy_with_parent  (GtkWindow           *window,
+                                                gboolean             setting);
 void       gtk_window_set_geometry_hints       (GtkWindow           *window,
 						GtkWidget           *geometry_widget,
 						GdkGeometry         *geometry,
@@ -129,6 +132,8 @@
                                                 gboolean             modal);
 GList*	   gtk_window_list_toplevels	       (void);
 
+/* Get the "built-in" accel group (convenience thing) */
+GtkAccelGroup* gtk_window_get_default_accel_group (GtkWindow *window);
 
 /* --- internal functions --- */
 void       gtk_window_set_focus                (GtkWindow           *window,
Index: gtk/testgtk.c
===================================================================
RCS file: /cvs/gnome/gtk+/gtk/testgtk.c,v
retrieving revision 1.193
diff -u -u -r1.193 testgtk.c
--- gtk/testgtk.c	2000/09/07 18:07:57	1.193
+++ gtk/testgtk.c	2000/10/04 20:06:19
@@ -161,8 +161,12 @@
 
   if (!window)
     {
+      GtkAccelGroup *accel_group;
+      
       window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
 
+      accel_group = gtk_window_get_default_accel_group (GTK_WINDOW (window));
+      
       gtk_signal_connect (GTK_OBJECT (window), "destroy",
 			  GTK_SIGNAL_FUNC (gtk_widget_destroyed),
 			  &window);
@@ -180,15 +184,15 @@
       gtk_box_pack_start (GTK_BOX (box1), table, TRUE, TRUE, 0);
 
       button[0] = gtk_button_new_with_label ("button1");
-      button[1] = gtk_button_new_with_label ("button2");
+      button[1] = gtk_button_new_accel ("_button2", accel_group);
       button[2] = gtk_button_new_with_label ("button3");
-      button[3] = gtk_button_new_with_label ("button4");
+      button[3] = gtk_button_new_stock (GTK_STOCK_BUTTON_OK, NULL);
       button[4] = gtk_button_new_with_label ("button5");
       button[5] = gtk_button_new_with_label ("button6");
       button[6] = gtk_button_new_with_label ("button7");
-      button[7] = gtk_button_new_with_label ("button8");
+      button[7] = gtk_button_new_stock (GTK_STOCK_BUTTON_CLOSE, accel_group);
       button[8] = gtk_button_new_with_label ("button9");
-
+      
       gtk_signal_connect (GTK_OBJECT (button[0]), "clicked",
 			  GTK_SIGNAL_FUNC(button_window),
 			  button[1]);
@@ -2222,6 +2226,65 @@
 }
 
 /*
+ * GtkImage
+ */
+
+static void
+pack_image (GtkWidget *box,
+            const gchar *text,
+            GtkWidget *image)
+{
+  gtk_box_pack_start (GTK_BOX (box),
+                      gtk_label_new (text),
+                      FALSE, FALSE, 0);
+
+  gtk_box_pack_start (GTK_BOX (box),
+                      image,
+                      TRUE, TRUE, 0);  
+}
+
+static void
+create_image (void)
+{
+  static GtkWidget *window = NULL;
+  
+  if (window == NULL)
+    {
+      GtkWidget *vbox;
+      GdkPixmap *pixmap;
+      GdkBitmap *mask;
+        
+      window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
+      
+      gtk_signal_connect (GTK_OBJECT (window), "destroy",
+			  GTK_SIGNAL_FUNC(gtk_widget_destroyed),
+			  &window);
+
+      vbox = gtk_vbox_new (FALSE, 5);
+
+      gtk_container_add (GTK_CONTAINER (window), vbox);
+
+      pack_image (vbox, "Stock Warning Dialog",
+                  gtk_image_new_from_stock (GTK_STOCK_DIALOG_WARNING,
+                                            GTK_ICON_SIZE_DIALOG));
+
+      pixmap = gdk_pixmap_colormap_create_from_xpm_d (NULL,
+                                                      gtk_widget_get_colormap (window),
+                                                      &mask,
+                                                      NULL,
+                                                      openfile);
+      
+      pack_image (vbox, "Pixmap",
+                  gtk_image_new_from_pixmap (pixmap, mask));
+    }
+
+  if (!GTK_WIDGET_VISIBLE (window))
+    gtk_widget_show_all (window);
+  else
+    gtk_widget_destroy (window);
+}
+     
+/*
  * Menu demo
  */
 
@@ -2637,6 +2700,49 @@
 }
 
 /*
+ * GtkMessageDialog
+ */
+
+static void
+make_message_dialog (GtkWidget **dialog,
+                     GtkMessageType  type,
+                     GtkButtonsType  buttons)
+{
+  if (*dialog)
+    {
+      if (GTK_WIDGET_REALIZED (*dialog))
+        gdk_window_show ((*dialog)->window);
+
+      return;
+    }
+
+  *dialog = gtk_message_dialog_new (NULL, type, buttons, GTK_DIALOG_DESTROY_WITH_PARENT,
+                                    "This is a message dialog; it can wrap long lines. This is a long line. La la la. Look this line is wrapped. Blah blah blah blah blah blah.");
+
+
+  gtk_signal_connect (GTK_OBJECT (*dialog),
+                      "destroy",
+                      GTK_SIGNAL_FUNC (gtk_widget_destroyed),
+                      dialog);
+  
+  gtk_widget_show (*dialog);
+}
+
+static void
+create_message_dialog (void)
+{
+  static GtkWidget *info = NULL;
+  static GtkWidget *warning = NULL;
+  static GtkWidget *error = NULL;
+  static GtkWidget *question = NULL;
+
+  make_message_dialog (&info, GTK_MESSAGE_INFO, GTK_BUTTONS_OK);
+  make_message_dialog (&warning, GTK_MESSAGE_WARNING, GTK_BUTTONS_CLOSE);
+  make_message_dialog (&error, GTK_MESSAGE_ERROR, GTK_BUTTONS_OK_CANCEL);
+  make_message_dialog (&question, GTK_MESSAGE_QUESTION, GTK_BUTTONS_YES_NO);
+}
+
+/*
  * GtkScrolledWindow
  */
 
@@ -8624,11 +8730,13 @@
       { "font selection", create_font_selection },
       { "gamma curve", create_gamma_curve },
       { "handle box", create_handle_box },
+      { "image", create_image },
       { "item factory", create_item_factory },
       { "labels", create_labels },
       { "layout", create_layout },
       { "list", create_list },
       { "menus", create_menus },
+      { "message dialog", create_message_dialog },
       { "modal window", create_modal_window },
       { "notebook", create_notebook },
       { "panes", create_panes },
@@ -8770,8 +8878,6 @@
     gtk_rc_add_default_file ("testgtkrc");
 
   gtk_init (&argc, &argv);
-
-  gdk_rgb_init ();
 
   /* bindings test
    */
Index: gtk/testgtkrc
===================================================================
RCS file: /cvs/gnome/gtk+/gtk/testgtkrc,v
retrieving revision 1.37
diff -u -u -r1.37 testgtkrc
--- gtk/testgtkrc	2000/07/11 04:46:11	1.37
+++ gtk/testgtkrc	2000/10/04 20:06:19
@@ -29,6 +29,16 @@
   font_name = "Sans 12"
 }
 
+style "myicons"
+{
+  stock["gtk-dialog-warning"] = 
+    { 
+      { "3DRings.xpm", *, *, *} 
+    }
+}
+
+class "GtkImage" style "myicons"
+
 # common default
 class "GtkWidget" style "defaultfont"
 





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