]> Pileus Git - ~andy/gtk/blob - gtk/gtkdialog.c
9a01b42778676719f725a49db767e4fe4548d81f
[~andy/gtk] / gtk / gtkdialog.c
1 /* GTK - The GTK+ Toolkit
2  * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Lesser General Public
6  * License as published by the Free Software Foundation; either
7  * version 2 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public
15  * License along with this library; if not, write to the
16  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17  * Boston, MA 02111-1307, USA.
18  */
19
20 /*
21  * Modified by the GTK+ Team and others 1997-2000.  See the AUTHORS
22  * file for a list of people on the GTK+ Team.  See the ChangeLog
23  * files for a list of changes.  These files are distributed with
24  * GTK+ at ftp://ftp.gtk.org/pub/gtk/. 
25  */
26
27 #include <stdlib.h>
28 #include <string.h>
29 #include "config.h"
30 #include "gtkbutton.h"
31 #include "gtkdialog.h"
32 #include "gtkhbbox.h"
33 #include "gtklabel.h"
34 #include "gtkhseparator.h"
35 #include "gtkmarshalers.h"
36 #include "gtkvbox.h"
37 #include "gdkkeysyms.h"
38 #include "gtkmain.h"
39 #include "gtkintl.h"
40 #include "gtkbindings.h"
41 #include "gtkprivate.h"
42 #include "gtkbuildable.h"
43 #include "gtkalias.h"
44
45 #define GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), GTK_TYPE_DIALOG, GtkDialogPrivate))
46
47 typedef struct {
48   guint ignore_separator : 1;
49 } GtkDialogPrivate;
50
51 typedef struct _ResponseData ResponseData;
52
53 struct _ResponseData
54 {
55   gint response_id;
56 };
57
58 static void gtk_dialog_add_buttons_valist (GtkDialog   *dialog,
59                                            const gchar *first_button_text,
60                                            va_list      args);
61
62 static gint gtk_dialog_delete_event_handler (GtkWidget   *widget,
63                                              GdkEventAny *event,
64                                              gpointer     user_data);
65
66 static void gtk_dialog_set_property      (GObject          *object,
67                                           guint             prop_id,
68                                           const GValue     *value,
69                                           GParamSpec       *pspec);
70 static void gtk_dialog_get_property      (GObject          *object,
71                                           guint             prop_id,
72                                           GValue           *value,
73                                           GParamSpec       *pspec);
74 static void gtk_dialog_style_set         (GtkWidget        *widget,
75                                           GtkStyle         *prev_style);
76 static void gtk_dialog_map               (GtkWidget        *widget);
77
78 static void gtk_dialog_close             (GtkDialog        *dialog);
79
80 static ResponseData* get_response_data   (GtkWidget        *widget,
81                                           gboolean          create);
82 static void gtk_dialog_buildable_interface_init     (GtkBuildableIface *iface);
83 static GObject * gtk_dialog_buildable_get_internal_child (GtkBuildable *buildable,
84                                                      GtkBuilder   *builder,
85                                                      const gchar  *childname);
86 static gboolean gtk_dialog_buildable_custom_tag_start (GtkBuildable  *buildable,
87                                                        GtkBuilder    *builder,
88                                                        GObject       *child,
89                                                        const gchar   *tagname,
90                                                        GMarkupParser *parser,
91                                                        gpointer      *data);
92 static void gtk_dialog_buildable_custom_finished (GtkBuildable *buildable,
93                                                   GtkBuilder   *builder,
94                                                   GObject       *child,
95                                                   const gchar   *tagname,
96                                                   gpointer      user_data);
97
98
99 enum {
100   PROP_0,
101   PROP_HAS_SEPARATOR
102 };
103
104 enum {
105   RESPONSE,
106   CLOSE,
107   LAST_SIGNAL
108 };
109
110 static guint dialog_signals[LAST_SIGNAL];
111
112 G_DEFINE_TYPE_WITH_CODE (GtkDialog, gtk_dialog, GTK_TYPE_WINDOW,
113                          G_IMPLEMENT_INTERFACE (GTK_TYPE_BUILDABLE,
114                                                 gtk_dialog_buildable_interface_init))
115
116 static void
117 gtk_dialog_class_init (GtkDialogClass *class)
118 {
119   GObjectClass *gobject_class;
120   GtkWidgetClass *widget_class;
121   GtkBindingSet *binding_set;
122   
123   gobject_class = G_OBJECT_CLASS (class);
124   widget_class = GTK_WIDGET_CLASS (class);
125   
126   gobject_class->set_property = gtk_dialog_set_property;
127   gobject_class->get_property = gtk_dialog_get_property;
128   
129   widget_class->map = gtk_dialog_map;
130   widget_class->style_set = gtk_dialog_style_set;
131
132   class->close = gtk_dialog_close;
133   
134   g_type_class_add_private (gobject_class, sizeof (GtkDialogPrivate));
135
136   /**
137    * GtkDialog:has-separator:
138    *
139    * When %TRUE, the dialog has a separator bar above its buttons.
140    */
141   g_object_class_install_property (gobject_class,
142                                    PROP_HAS_SEPARATOR,
143                                    g_param_spec_boolean ("has-separator",
144                                                          P_("Has separator"),
145                                                          P_("The dialog has a separator bar above its buttons"),
146                                                          TRUE,
147                                                          GTK_PARAM_READWRITE));
148
149   /**
150    * GtkDialog::response:
151    * @dialog: the object on which the signal is emitted
152    * @response_id: the response ID
153    * 
154    * Emitted when an action widget is clicked, the dialog receives a 
155    * delete event, or the application programmer calls gtk_dialog_response(). 
156    * On a delete event, the response ID is #GTK_RESPONSE_DELETE_EVENT. 
157    * Otherwise, it depends on which action widget was clicked.
158    */
159   dialog_signals[RESPONSE] =
160     g_signal_new (I_("response"),
161                   G_OBJECT_CLASS_TYPE (class),
162                   G_SIGNAL_RUN_LAST,
163                   G_STRUCT_OFFSET (GtkDialogClass, response),
164                   NULL, NULL,
165                   _gtk_marshal_NONE__INT,
166                   G_TYPE_NONE, 1,
167                   G_TYPE_INT);
168
169   /**
170    * GtkDialog::close:
171    *
172    * The ::close signal is a 
173    * <link linkend="keybinding-signals">keybinding signal</link>
174    * which getrs emitted when the user uses a keybinding to close
175    * the dialog.
176    *
177    * The default binding for this signal is the Escape key.
178    */ 
179   dialog_signals[CLOSE] =
180     g_signal_new (I_("close"),
181                   G_OBJECT_CLASS_TYPE (class),
182                   G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
183                   G_STRUCT_OFFSET (GtkDialogClass, close),
184                   NULL, NULL,
185                   _gtk_marshal_NONE__NONE,
186                   G_TYPE_NONE, 0);
187   
188   gtk_widget_class_install_style_property (widget_class,
189                                            g_param_spec_int ("content-area-border",
190                                                              P_("Content area border"),
191                                                              P_("Width of border around the main dialog area"),
192                                                              0,
193                                                              G_MAXINT,
194                                                              2,
195                                                              GTK_PARAM_READABLE));
196   gtk_widget_class_install_style_property (widget_class,
197                                            g_param_spec_int ("button-spacing",
198                                                              P_("Button spacing"),
199                                                              P_("Spacing between buttons"),
200                                                              0,
201                                                              G_MAXINT,
202                                                              6,
203                                                              GTK_PARAM_READABLE));
204   
205   gtk_widget_class_install_style_property (widget_class,
206                                            g_param_spec_int ("action-area-border",
207                                                              P_("Action area border"),
208                                                              P_("Width of border around the button area at the bottom of the dialog"),
209                                                              0,
210                                                              G_MAXINT,
211                                                              5,
212                                                              GTK_PARAM_READABLE));
213
214   binding_set = gtk_binding_set_by_class (class);
215   
216   gtk_binding_entry_add_signal (binding_set, GDK_Escape, 0, "close", 0);
217 }
218
219 static void
220 update_spacings (GtkDialog *dialog)
221 {
222   GtkWidget *widget;
223   gint content_area_border;
224   gint button_spacing;
225   gint action_area_border;
226   
227   widget = GTK_WIDGET (dialog);
228
229   gtk_widget_style_get (widget,
230                         "content-area-border", &content_area_border,
231                         "button-spacing", &button_spacing,
232                         "action-area-border", &action_area_border,
233                         NULL);
234
235   gtk_container_set_border_width (GTK_CONTAINER (dialog->vbox),
236                                   content_area_border);
237   gtk_box_set_spacing (GTK_BOX (dialog->action_area),
238                        button_spacing);
239   gtk_container_set_border_width (GTK_CONTAINER (dialog->action_area),
240                                   action_area_border);
241 }
242
243 static void
244 gtk_dialog_init (GtkDialog *dialog)
245 {
246   GtkDialogPrivate *priv;
247
248   priv = GET_PRIVATE (dialog);
249   priv->ignore_separator = FALSE;
250
251   /* To avoid breaking old code that prevents destroy on delete event
252    * by connecting a handler, we have to have the FIRST signal
253    * connection on the dialog.
254    */
255   g_signal_connect (dialog,
256                     "delete_event",
257                     G_CALLBACK (gtk_dialog_delete_event_handler),
258                     NULL);
259
260   dialog->vbox = gtk_vbox_new (FALSE, 0);
261
262   gtk_container_add (GTK_CONTAINER (dialog), dialog->vbox);
263   gtk_widget_show (dialog->vbox);
264
265   dialog->action_area = gtk_hbutton_box_new ();
266
267   gtk_button_box_set_layout (GTK_BUTTON_BOX (dialog->action_area),
268                              GTK_BUTTONBOX_END);
269
270   gtk_box_pack_end (GTK_BOX (dialog->vbox), dialog->action_area,
271                     FALSE, TRUE, 0);
272   gtk_widget_show (dialog->action_area);
273
274   dialog->separator = gtk_hseparator_new ();
275   gtk_box_pack_end (GTK_BOX (dialog->vbox), dialog->separator, FALSE, TRUE, 0);
276   gtk_widget_show (dialog->separator);
277
278   gtk_window_set_type_hint (GTK_WINDOW (dialog),
279                             GDK_WINDOW_TYPE_HINT_DIALOG);
280   gtk_window_set_position (GTK_WINDOW (dialog), GTK_WIN_POS_CENTER_ON_PARENT);
281 }
282
283 static GtkBuildableIface *parent_buildable_iface;
284
285 static void
286 gtk_dialog_buildable_interface_init (GtkBuildableIface *iface)
287 {
288   parent_buildable_iface = g_type_interface_peek_parent (iface);
289   iface->get_internal_child = gtk_dialog_buildable_get_internal_child;
290   iface->custom_tag_start = gtk_dialog_buildable_custom_tag_start;
291   iface->custom_finished = gtk_dialog_buildable_custom_finished;
292 }
293
294 static GObject *
295 gtk_dialog_buildable_get_internal_child (GtkBuildable *buildable,
296                                          GtkBuilder   *builder,
297                                          const gchar  *childname)
298 {
299     if (strcmp (childname, "vbox") == 0)
300       return G_OBJECT (GTK_DIALOG (buildable)->vbox);
301     else if (strcmp (childname, "action_area") == 0)
302       return G_OBJECT (GTK_DIALOG (buildable)->action_area);
303
304     return parent_buildable_iface->get_internal_child (buildable,
305                                                        builder,
306                                                        childname);
307 }
308
309 static void 
310 gtk_dialog_set_property (GObject      *object,
311                          guint         prop_id,
312                          const GValue *value,
313                          GParamSpec   *pspec)
314 {
315   GtkDialog *dialog;
316   
317   dialog = GTK_DIALOG (object);
318   
319   switch (prop_id)
320     {
321     case PROP_HAS_SEPARATOR:
322       gtk_dialog_set_has_separator (dialog, g_value_get_boolean (value));
323       break;
324
325     default:
326       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
327       break;
328     }
329 }
330
331 static void 
332 gtk_dialog_get_property (GObject     *object,
333                          guint        prop_id,
334                          GValue      *value,
335                          GParamSpec  *pspec)
336 {
337   GtkDialog *dialog;
338   
339   dialog = GTK_DIALOG (object);
340   
341   switch (prop_id)
342     {
343     case PROP_HAS_SEPARATOR:
344       g_value_set_boolean (value, dialog->separator != NULL);
345       break;
346
347     default:
348       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
349       break;
350     }
351 }
352
353 static gint
354 gtk_dialog_delete_event_handler (GtkWidget   *widget,
355                                  GdkEventAny *event,
356                                  gpointer     user_data)
357 {
358   /* emit response signal */
359   gtk_dialog_response (GTK_DIALOG (widget), GTK_RESPONSE_DELETE_EVENT);
360
361   /* Do the destroy by default */
362   return FALSE;
363 }
364
365 /* A far too tricky heuristic for getting the right initial
366  * focus widget if none was set. What we do is we focus the first
367  * widget in the tab chain, but if this results in the focus
368  * ending up on one of the response widgets _other_ than the
369  * default response, we focus the default response instead.
370  *
371  * Additionally, skip selectable labels when looking for the
372  * right initial focus widget.
373  */
374 static void
375 gtk_dialog_map (GtkWidget *widget)
376 {
377   GtkWindow *window = GTK_WINDOW (widget);
378   GtkDialog *dialog = GTK_DIALOG (widget);
379   
380   GTK_WIDGET_CLASS (gtk_dialog_parent_class)->map (widget);
381
382   if (!window->focus_widget)
383     {
384       GList *children, *tmp_list;
385       GtkWidget *first_focus = NULL;
386       
387       do 
388         {
389           g_signal_emit_by_name (window, "move_focus", GTK_DIR_TAB_FORWARD);
390
391           if (first_focus == NULL)
392             first_focus = window->focus_widget;
393           else if (first_focus == window->focus_widget)
394             break;
395
396           if (!GTK_IS_LABEL (window->focus_widget))
397             break;
398           else
399             gtk_label_select_region (GTK_LABEL (window->focus_widget), 0, 0);
400         }
401       while (TRUE);
402
403       tmp_list = children = gtk_container_get_children (GTK_CONTAINER (dialog->action_area));
404       
405       while (tmp_list)
406         {
407           GtkWidget *child = tmp_list->data;
408           
409           if ((window->focus_widget == NULL || 
410                child == window->focus_widget) && 
411               child != window->default_widget &&
412               window->default_widget)
413             {
414               gtk_widget_grab_focus (window->default_widget);
415               break;
416             }
417           
418           tmp_list = tmp_list->next;
419         }
420       
421       g_list_free (children);
422     }
423 }
424
425 static void
426 gtk_dialog_style_set (GtkWidget *widget,
427                       GtkStyle  *prev_style)
428 {
429   update_spacings (GTK_DIALOG (widget));
430 }
431
432 static GtkWidget *
433 dialog_find_button (GtkDialog *dialog,
434                     gint       response_id)
435 {
436   GList *children, *tmp_list;
437   GtkWidget *child = NULL;
438       
439   children = gtk_container_get_children (GTK_CONTAINER (dialog->action_area));
440
441   for (tmp_list = children; tmp_list; tmp_list = tmp_list->next)
442     {
443       ResponseData *rd = get_response_data (tmp_list->data, FALSE);
444       
445       if (rd && rd->response_id == response_id)
446         {
447           child = tmp_list->data;
448           break;
449         }
450     }
451
452   g_list_free (children);
453
454   return child;
455 }
456
457 static void
458 gtk_dialog_close (GtkDialog *dialog)
459 {
460   /* Synthesize delete_event to close dialog. */
461   
462   GtkWidget *widget = GTK_WIDGET (dialog);
463   GdkEvent *event;
464
465   event = gdk_event_new (GDK_DELETE);
466   
467   event->any.window = g_object_ref (widget->window);
468   event->any.send_event = TRUE;
469   
470   gtk_main_do_event (event);
471   gdk_event_free (event);
472 }
473
474 GtkWidget*
475 gtk_dialog_new (void)
476 {
477   return g_object_new (GTK_TYPE_DIALOG, NULL);
478 }
479
480 static GtkWidget*
481 gtk_dialog_new_empty (const gchar     *title,
482                       GtkWindow       *parent,
483                       GtkDialogFlags   flags)
484 {
485   GtkDialog *dialog;
486
487   dialog = g_object_new (GTK_TYPE_DIALOG, NULL);
488
489   if (title)
490     gtk_window_set_title (GTK_WINDOW (dialog), title);
491
492   if (parent)
493     gtk_window_set_transient_for (GTK_WINDOW (dialog), parent);
494
495   if (flags & GTK_DIALOG_MODAL)
496     gtk_window_set_modal (GTK_WINDOW (dialog), TRUE);
497   
498   if (flags & GTK_DIALOG_DESTROY_WITH_PARENT)
499     gtk_window_set_destroy_with_parent (GTK_WINDOW (dialog), TRUE);
500
501   if (flags & GTK_DIALOG_NO_SEPARATOR)
502     gtk_dialog_set_has_separator (dialog, FALSE);
503   
504   return GTK_WIDGET (dialog);
505 }
506
507 /**
508  * gtk_dialog_new_with_buttons:
509  * @title: Title of the dialog, or %NULL
510  * @parent: Transient parent of the dialog, or %NULL
511  * @flags: from #GtkDialogFlags
512  * @first_button_text: stock ID or text to go in first button, or %NULL
513  * @Varargs: response ID for first button, then additional buttons, ending with %NULL
514  * 
515  * Creates a new #GtkDialog with title @title (or %NULL for the default
516  * title; see gtk_window_set_title()) and transient parent @parent (or
517  * %NULL for none; see gtk_window_set_transient_for()). The @flags
518  * argument can be used to make the dialog modal (#GTK_DIALOG_MODAL)
519  * and/or to have it destroyed along with its transient parent
520  * (#GTK_DIALOG_DESTROY_WITH_PARENT). After @flags, button
521  * text/response ID pairs should be listed, with a %NULL pointer ending
522  * the list. Button text can be either a stock ID such as
523  * #GTK_STOCK_OK, or some arbitrary text. A response ID can be
524  * any positive number, or one of the values in the #GtkResponseType
525  * enumeration. If the user clicks one of these dialog buttons,
526  * #GtkDialog will emit the #GtkDialog::response signal with the corresponding
527  * response ID. If a #GtkDialog receives the #GtkWidget::delete-event signal, 
528  * it will emit ::response with a response ID of #GTK_RESPONSE_DELETE_EVENT.
529  * However, destroying a dialog does not emit the ::response signal;
530  * so be careful relying on ::response when using the 
531  * #GTK_DIALOG_DESTROY_WITH_PARENT flag. Buttons are from left to right,
532  * so the first button in the list will be the leftmost button in the dialog.
533  *
534  * Here's a simple example:
535  * |[
536  *  GtkWidget *dialog = gtk_dialog_new_with_buttons ("My dialog",
537  *                                                   main_app_window,
538  *                                                   GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
539  *                                                   GTK_STOCK_OK,
540  *                                                   GTK_RESPONSE_ACCEPT,
541  *                                                   GTK_STOCK_CANCEL,
542  *                                                   GTK_RESPONSE_REJECT,
543  *                                                   NULL);
544  * ]|
545  * 
546  * Return value: a new #GtkDialog
547  **/
548 GtkWidget*
549 gtk_dialog_new_with_buttons (const gchar    *title,
550                              GtkWindow      *parent,
551                              GtkDialogFlags  flags,
552                              const gchar    *first_button_text,
553                              ...)
554 {
555   GtkDialog *dialog;
556   va_list args;
557   
558   dialog = GTK_DIALOG (gtk_dialog_new_empty (title, parent, flags));
559
560   va_start (args, first_button_text);
561
562   gtk_dialog_add_buttons_valist (dialog,
563                                  first_button_text,
564                                  args);
565   
566   va_end (args);
567
568   return GTK_WIDGET (dialog);
569 }
570
571 static void 
572 response_data_free (gpointer data)
573 {
574   g_slice_free (ResponseData, data);
575 }
576
577 static ResponseData*
578 get_response_data (GtkWidget *widget,
579                    gboolean   create)
580 {
581   ResponseData *ad = g_object_get_data (G_OBJECT (widget),
582                                         "gtk-dialog-response-data");
583
584   if (ad == NULL && create)
585     {
586       ad = g_slice_new (ResponseData);
587       
588       g_object_set_data_full (G_OBJECT (widget),
589                               I_("gtk-dialog-response-data"),
590                               ad,
591                               response_data_free);
592     }
593
594   return ad;
595 }
596
597 static void
598 action_widget_activated (GtkWidget *widget, GtkDialog *dialog)
599 {
600   gint response_id;
601   
602   response_id = gtk_dialog_get_response_for_widget (dialog, widget);
603
604   gtk_dialog_response (dialog, response_id);
605 }
606
607 /**
608  * gtk_dialog_add_action_widget:
609  * @dialog: a #GtkDialog
610  * @child: an activatable widget
611  * @response_id: response ID for @child
612  * 
613  * Adds an activatable widget to the action area of a #GtkDialog,
614  * connecting a signal handler that will emit the #GtkDialog::response 
615  * signal on the dialog when the widget is activated. The widget is 
616  * appended to the end of the dialog's action area. If you want to add a
617  * non-activatable widget, simply pack it into the @action_area field 
618  * of the #GtkDialog struct.
619  **/
620 void
621 gtk_dialog_add_action_widget (GtkDialog *dialog,
622                               GtkWidget *child,
623                               gint       response_id)
624 {
625   ResponseData *ad;
626   guint signal_id;
627   
628   g_return_if_fail (GTK_IS_DIALOG (dialog));
629   g_return_if_fail (GTK_IS_WIDGET (child));
630
631   ad = get_response_data (child, TRUE);
632
633   ad->response_id = response_id;
634
635   if (GTK_IS_BUTTON (child))
636     signal_id = g_signal_lookup ("clicked", GTK_TYPE_BUTTON);
637   else
638     signal_id = GTK_WIDGET_GET_CLASS (child)->activate_signal;
639
640   if (signal_id)
641     {
642       GClosure *closure;
643
644       closure = g_cclosure_new_object (G_CALLBACK (action_widget_activated),
645                                        G_OBJECT (dialog));
646       g_signal_connect_closure_by_id (child,
647                                       signal_id,
648                                       0,
649                                       closure,
650                                       FALSE);
651     }
652   else
653     g_warning ("Only 'activatable' widgets can be packed into the action area of a GtkDialog");
654
655   gtk_box_pack_end (GTK_BOX (dialog->action_area),
656                     child,
657                     FALSE, TRUE, 0);
658   
659   if (response_id == GTK_RESPONSE_HELP)
660     gtk_button_box_set_child_secondary (GTK_BUTTON_BOX (dialog->action_area), child, TRUE);
661 }
662
663 /**
664  * gtk_dialog_add_button:
665  * @dialog: a #GtkDialog
666  * @button_text: text of button, or stock ID
667  * @response_id: response ID for the button
668  * 
669  * Adds a button with the given text (or a stock button, if @button_text is a
670  * stock ID) and sets things up so that clicking the button will emit the
671  * #GtkDialog::response signal with the given @response_id. The button is 
672  * appended to the end of the dialog's action area. The button widget is 
673  * returned, but usually you don't need it.
674  *
675  * Return value: the button widget that was added
676  **/
677 GtkWidget*
678 gtk_dialog_add_button (GtkDialog   *dialog,
679                        const gchar *button_text,
680                        gint         response_id)
681 {
682   GtkWidget *button;
683   
684   g_return_val_if_fail (GTK_IS_DIALOG (dialog), NULL);
685   g_return_val_if_fail (button_text != NULL, NULL);
686
687   button = gtk_button_new_from_stock (button_text);
688
689   GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT);
690   
691   gtk_widget_show (button);
692   
693   gtk_dialog_add_action_widget (dialog,
694                                 button,
695                                 response_id);
696
697   return button;
698 }
699
700 static void
701 gtk_dialog_add_buttons_valist (GtkDialog      *dialog,
702                                const gchar    *first_button_text,
703                                va_list         args)
704 {
705   const gchar* text;
706   gint response_id;
707
708   g_return_if_fail (GTK_IS_DIALOG (dialog));
709   
710   if (first_button_text == NULL)
711     return;
712   
713   text = first_button_text;
714   response_id = va_arg (args, gint);
715
716   while (text != NULL)
717     {
718       gtk_dialog_add_button (dialog, text, response_id);
719
720       text = va_arg (args, gchar*);
721       if (text == NULL)
722         break;
723       response_id = va_arg (args, int);
724     }
725 }
726
727 /**
728  * gtk_dialog_add_buttons:
729  * @dialog: a #GtkDialog
730  * @first_button_text: button text or stock ID
731  * @Varargs: response ID for first button, then more text-response_id pairs
732  * 
733  * Adds more buttons, same as calling gtk_dialog_add_button()
734  * repeatedly.  The variable argument list should be %NULL-terminated
735  * as with gtk_dialog_new_with_buttons(). Each button must have both
736  * text and response ID.
737  **/
738 void
739 gtk_dialog_add_buttons (GtkDialog   *dialog,
740                         const gchar *first_button_text,
741                         ...)
742 {  
743   va_list args;
744
745   va_start (args, first_button_text);
746
747   gtk_dialog_add_buttons_valist (dialog,
748                                  first_button_text,
749                                  args);
750   
751   va_end (args);
752 }
753
754 /**
755  * gtk_dialog_set_response_sensitive:
756  * @dialog: a #GtkDialog
757  * @response_id: a response ID
758  * @setting: %TRUE for sensitive
759  *
760  * Calls <literal>gtk_widget_set_sensitive (widget, @setting)</literal> 
761  * for each widget in the dialog's action area with the given @response_id.
762  * A convenient way to sensitize/desensitize dialog buttons.
763  **/
764 void
765 gtk_dialog_set_response_sensitive (GtkDialog *dialog,
766                                    gint       response_id,
767                                    gboolean   setting)
768 {
769   GList *children;
770   GList *tmp_list;
771
772   g_return_if_fail (GTK_IS_DIALOG (dialog));
773
774   children = gtk_container_get_children (GTK_CONTAINER (dialog->action_area));
775
776   tmp_list = children;
777   while (tmp_list != NULL)
778     {
779       GtkWidget *widget = tmp_list->data;
780       ResponseData *rd = get_response_data (widget, FALSE);
781
782       if (rd && rd->response_id == response_id)
783         gtk_widget_set_sensitive (widget, setting);
784
785       tmp_list = g_list_next (tmp_list);
786     }
787
788   g_list_free (children);
789 }
790
791 /**
792  * gtk_dialog_set_default_response:
793  * @dialog: a #GtkDialog
794  * @response_id: a response ID
795  * 
796  * Sets the last widget in the dialog's action area with the given @response_id
797  * as the default widget for the dialog. Pressing "Enter" normally activates
798  * the default widget.
799  **/
800 void
801 gtk_dialog_set_default_response (GtkDialog *dialog,
802                                  gint       response_id)
803 {
804   GList *children;
805   GList *tmp_list;
806
807   g_return_if_fail (GTK_IS_DIALOG (dialog));
808
809   children = gtk_container_get_children (GTK_CONTAINER (dialog->action_area));
810
811   tmp_list = children;
812   while (tmp_list != NULL)
813     {
814       GtkWidget *widget = tmp_list->data;
815       ResponseData *rd = get_response_data (widget, FALSE);
816
817       if (rd && rd->response_id == response_id)
818         gtk_widget_grab_default (widget);
819             
820       tmp_list = g_list_next (tmp_list);
821     }
822
823   g_list_free (children);
824 }
825
826 /**
827  * gtk_dialog_set_has_separator:
828  * @dialog: a #GtkDialog
829  * @setting: %TRUE to have a separator
830  *
831  * Sets whether the dialog has a separator above the buttons.
832  * %TRUE by default.
833  **/
834 void
835 gtk_dialog_set_has_separator (GtkDialog *dialog,
836                               gboolean   setting)
837 {
838   GtkDialogPrivate *priv;
839
840   g_return_if_fail (GTK_IS_DIALOG (dialog));
841
842   priv = GET_PRIVATE (dialog);
843
844   /* this might fail if we get called before _init() somehow */
845   g_assert (dialog->vbox != NULL);
846
847   if (priv->ignore_separator)
848     {
849       g_warning ("Ignoring the separator setting");
850       return;
851     }
852   
853   if (setting && dialog->separator == NULL)
854     {
855       dialog->separator = gtk_hseparator_new ();
856       gtk_box_pack_end (GTK_BOX (dialog->vbox), dialog->separator, FALSE, TRUE, 0);
857
858       /* The app programmer could screw this up, but, their own fault.
859        * Moves the separator just above the action area.
860        */
861       gtk_box_reorder_child (GTK_BOX (dialog->vbox), dialog->separator, 1);
862       gtk_widget_show (dialog->separator);
863     }
864   else if (!setting && dialog->separator != NULL)
865     {
866       gtk_widget_destroy (dialog->separator);
867       dialog->separator = NULL;
868     }
869
870   g_object_notify (G_OBJECT (dialog), "has-separator");
871 }
872
873 /**
874  * gtk_dialog_get_has_separator:
875  * @dialog: a #GtkDialog
876  * 
877  * Accessor for whether the dialog has a separator.
878  * 
879  * Return value: %TRUE if the dialog has a separator
880  **/
881 gboolean
882 gtk_dialog_get_has_separator (GtkDialog *dialog)
883 {
884   g_return_val_if_fail (GTK_IS_DIALOG (dialog), FALSE);
885
886   return dialog->separator != NULL;
887 }
888
889 /**
890  * gtk_dialog_response:
891  * @dialog: a #GtkDialog
892  * @response_id: response ID 
893  * 
894  * Emits the #GtkDialog::response signal with the given response ID. 
895  * Used to indicate that the user has responded to the dialog in some way;
896  * typically either you or gtk_dialog_run() will be monitoring the
897  * ::response signal and take appropriate action.
898  **/
899 void
900 gtk_dialog_response (GtkDialog *dialog,
901                      gint       response_id)
902 {
903   g_return_if_fail (GTK_IS_DIALOG (dialog));
904
905   g_signal_emit (dialog,
906                  dialog_signals[RESPONSE],
907                  0,
908                  response_id);
909 }
910
911 typedef struct
912 {
913   GtkDialog *dialog;
914   gint response_id;
915   GMainLoop *loop;
916   gboolean destroyed;
917 } RunInfo;
918
919 static void
920 shutdown_loop (RunInfo *ri)
921 {
922   if (g_main_loop_is_running (ri->loop))
923     g_main_loop_quit (ri->loop);
924 }
925
926 static void
927 run_unmap_handler (GtkDialog *dialog, gpointer data)
928 {
929   RunInfo *ri = data;
930
931   shutdown_loop (ri);
932 }
933
934 static void
935 run_response_handler (GtkDialog *dialog,
936                       gint response_id,
937                       gpointer data)
938 {
939   RunInfo *ri;
940
941   ri = data;
942
943   ri->response_id = response_id;
944
945   shutdown_loop (ri);
946 }
947
948 static gint
949 run_delete_handler (GtkDialog *dialog,
950                     GdkEventAny *event,
951                     gpointer data)
952 {
953   RunInfo *ri = data;
954     
955   shutdown_loop (ri);
956   
957   return TRUE; /* Do not destroy */
958 }
959
960 static void
961 run_destroy_handler (GtkDialog *dialog, gpointer data)
962 {
963   RunInfo *ri = data;
964
965   /* shutdown_loop will be called by run_unmap_handler */
966   
967   ri->destroyed = TRUE;
968 }
969
970 /**
971  * gtk_dialog_run:
972  * @dialog: a #GtkDialog
973  * 
974  * Blocks in a recursive main loop until the @dialog either emits the
975  * #GtkDialog::response signal, or is destroyed. If the dialog is 
976  * destroyed during the call to gtk_dialog_run(), gtk_dialog_run() returns 
977  * #GTK_RESPONSE_NONE. Otherwise, it returns the response ID from the 
978  * ::response signal emission.
979  *
980  * Before entering the recursive main loop, gtk_dialog_run() calls
981  * gtk_widget_show() on the dialog for you. Note that you still
982  * need to show any children of the dialog yourself.
983  *
984  * During gtk_dialog_run(), the default behavior of #GtkWidget::delete-event 
985  * is disabled; if the dialog receives ::delete_event, it will not be
986  * destroyed as windows usually are, and gtk_dialog_run() will return
987  * #GTK_RESPONSE_DELETE_EVENT. Also, during gtk_dialog_run() the dialog 
988  * will be modal. You can force gtk_dialog_run() to return at any time by
989  * calling gtk_dialog_response() to emit the ::response signal. Destroying 
990  * the dialog during gtk_dialog_run() is a very bad idea, because your 
991  * post-run code won't know whether the dialog was destroyed or not.
992  *
993  * After gtk_dialog_run() returns, you are responsible for hiding or
994  * destroying the dialog if you wish to do so.
995  *
996  * Typical usage of this function might be:
997  * |[
998  *   gint result = gtk_dialog_run (GTK_DIALOG (dialog));
999  *   switch (result)
1000  *     {
1001  *       case GTK_RESPONSE_ACCEPT:
1002  *          do_application_specific_something ();
1003  *          break;
1004  *       default:
1005  *          do_nothing_since_dialog_was_cancelled ();
1006  *          break;
1007  *     }
1008  *   gtk_widget_destroy (dialog);
1009  * ]|
1010  * 
1011  * Note that even though the recursive main loop gives the effect of a
1012  * modal dialog (it prevents the user from interacting with other 
1013  * windows in the same window group while the dialog is run), callbacks 
1014  * such as timeouts, IO channel watches, DND drops, etc, <emphasis>will</emphasis> 
1015  * be triggered during a gtk_dialog_run() call.
1016  * 
1017  * Return value: response ID
1018  **/
1019 gint
1020 gtk_dialog_run (GtkDialog *dialog)
1021 {
1022   RunInfo ri = { NULL, GTK_RESPONSE_NONE, NULL, FALSE };
1023   gboolean was_modal;
1024   gulong response_handler;
1025   gulong unmap_handler;
1026   gulong destroy_handler;
1027   gulong delete_handler;
1028   
1029   g_return_val_if_fail (GTK_IS_DIALOG (dialog), -1);
1030
1031   g_object_ref (dialog);
1032
1033   was_modal = GTK_WINDOW (dialog)->modal;
1034   if (!was_modal)
1035     gtk_window_set_modal (GTK_WINDOW (dialog), TRUE);
1036
1037   if (!GTK_WIDGET_VISIBLE (dialog))
1038     gtk_widget_show (GTK_WIDGET (dialog));
1039   
1040   response_handler =
1041     g_signal_connect (dialog,
1042                       "response",
1043                       G_CALLBACK (run_response_handler),
1044                       &ri);
1045   
1046   unmap_handler =
1047     g_signal_connect (dialog,
1048                       "unmap",
1049                       G_CALLBACK (run_unmap_handler),
1050                       &ri);
1051   
1052   delete_handler =
1053     g_signal_connect (dialog,
1054                       "delete-event",
1055                       G_CALLBACK (run_delete_handler),
1056                       &ri);
1057   
1058   destroy_handler =
1059     g_signal_connect (dialog,
1060                       "destroy",
1061                       G_CALLBACK (run_destroy_handler),
1062                       &ri);
1063   
1064   ri.loop = g_main_loop_new (NULL, FALSE);
1065
1066   GDK_THREADS_LEAVE ();  
1067   g_main_loop_run (ri.loop);
1068   GDK_THREADS_ENTER ();  
1069
1070   g_main_loop_unref (ri.loop);
1071
1072   ri.loop = NULL;
1073   
1074   if (!ri.destroyed)
1075     {
1076       if (!was_modal)
1077         gtk_window_set_modal (GTK_WINDOW(dialog), FALSE);
1078       
1079       g_signal_handler_disconnect (dialog, response_handler);
1080       g_signal_handler_disconnect (dialog, unmap_handler);
1081       g_signal_handler_disconnect (dialog, delete_handler);
1082       g_signal_handler_disconnect (dialog, destroy_handler);
1083     }
1084
1085   g_object_unref (dialog);
1086
1087   return ri.response_id;
1088 }
1089
1090 void
1091 _gtk_dialog_set_ignore_separator (GtkDialog *dialog,
1092                                   gboolean   ignore_separator)
1093 {
1094   GtkDialogPrivate *priv;
1095
1096   priv = GET_PRIVATE (dialog);
1097   priv->ignore_separator = ignore_separator;
1098 }
1099
1100 /**
1101  * gtk_dialog_get_response_for_widget:
1102  * @dialog: a #GtkDialog
1103  * @widget: a widget in the action area of @dialog
1104  *
1105  * Gets the response id of a widget in the action area
1106  * of a dialog.
1107  *
1108  * Returns: the response id of @widget, or %GTK_RESPONSE_NONE
1109  *  if @widget doesn't have a response id set.
1110  *
1111  * Since: 2.8
1112  */
1113 gint
1114 gtk_dialog_get_response_for_widget (GtkDialog *dialog,
1115                                     GtkWidget *widget)
1116 {
1117   ResponseData *rd;
1118
1119   rd = get_response_data (widget, FALSE);
1120   if (!rd)
1121     return GTK_RESPONSE_NONE;
1122   else
1123     return rd->response_id;
1124 }
1125
1126 /**
1127  * gtk_alternative_dialog_button_order:
1128  * @screen: a #GdkScreen, or %NULL to use the default screen
1129  *
1130  * Returns %TRUE if dialogs are expected to use an alternative
1131  * button order on the screen @screen. See 
1132  * gtk_dialog_set_alternative_button_order() for more details
1133  * about alternative button order. 
1134  *
1135  * If you need to use this function, you should probably connect
1136  * to the ::notify:gtk-alternative-button-order signal on the
1137  * #GtkSettings object associated to @screen, in order to be 
1138  * notified if the button order setting changes.
1139  *
1140  * Returns: Whether the alternative button order should be used
1141  *
1142  * Since: 2.6
1143  */
1144 gboolean 
1145 gtk_alternative_dialog_button_order (GdkScreen *screen)
1146 {
1147   GtkSettings *settings;
1148   gboolean result;
1149
1150   if (screen)
1151     settings = gtk_settings_get_for_screen (screen);
1152   else
1153     settings = gtk_settings_get_default ();
1154   
1155   g_object_get (settings,
1156                 "gtk-alternative-button-order", &result, NULL);
1157
1158   return result;
1159 }
1160
1161 static void
1162 gtk_dialog_set_alternative_button_order_valist (GtkDialog *dialog,
1163                                                 gint       first_response_id,
1164                                                 va_list    args)
1165 {
1166   GtkWidget *child;
1167   gint response_id;
1168   gint position;
1169
1170   response_id = first_response_id;
1171   position = 0;
1172   while (response_id != -1)
1173     {
1174       /* reorder child with response_id to position */
1175       child = dialog_find_button (dialog, response_id);
1176       gtk_box_reorder_child (GTK_BOX (dialog->action_area), child, position);
1177
1178       response_id = va_arg (args, gint);
1179       position++;
1180     }
1181 }
1182
1183 /**
1184  * gtk_dialog_set_alternative_button_order:
1185  * @dialog: a #GtkDialog
1186  * @first_response_id: a response id used by one @dialog's buttons
1187  * @Varargs: a list of more response ids of @dialog's buttons, terminated by -1
1188  *
1189  * Sets an alternative button order. If the 
1190  * #GtkSettings:gtk-alternative-button-order setting is set to %TRUE, 
1191  * the dialog buttons are reordered according to the order of the 
1192  * response ids passed to this function.
1193  *
1194  * By default, GTK+ dialogs use the button order advocated by the Gnome 
1195  * <ulink url="http://developer.gnome.org/projects/gup/hig/2.0/">Human 
1196  * Interface Guidelines</ulink> with the affirmative button at the far 
1197  * right, and the cancel button left of it. But the builtin GTK+ dialogs
1198  * and #GtkMessageDialog<!-- -->s do provide an alternative button order,
1199  * which is more suitable on some platforms, e.g. Windows.
1200  *
1201  * Use this function after adding all the buttons to your dialog, as the 
1202  * following example shows:
1203  * |[
1204  * cancel_button = gtk_dialog_add_button (GTK_DIALOG (dialog),
1205  *                                        GTK_STOCK_CANCEL,
1206  *                                        GTK_RESPONSE_CANCEL);
1207  *  
1208  * ok_button = gtk_dialog_add_button (GTK_DIALOG (dialog),
1209  *                                    GTK_STOCK_OK,
1210  *                                    GTK_RESPONSE_OK);
1211  *   
1212  * gtk_widget_grab_default (ok_button);
1213  *   
1214  * help_button = gtk_dialog_add_button (GTK_DIALOG (dialog),
1215  *                                      GTK_STOCK_HELP,
1216  *                                      GTK_RESPONSE_HELP);
1217  *  
1218  * gtk_dialog_set_alternative_button_order (GTK_DIALOG (dialog),
1219  *                                          GTK_RESPONSE_OK,
1220  *                                          GTK_RESPONSE_CANCEL,
1221  *                                          GTK_RESPONSE_HELP,
1222  *                                          -1);
1223  * ]|
1224  * 
1225  * Since: 2.6
1226  */
1227 void 
1228 gtk_dialog_set_alternative_button_order (GtkDialog *dialog,
1229                                          gint       first_response_id,
1230                                          ...)
1231 {
1232   GdkScreen *screen;
1233   va_list args;
1234   
1235   g_return_if_fail (GTK_IS_DIALOG (dialog));
1236
1237   screen = gtk_widget_get_screen (GTK_WIDGET (dialog));
1238   if (!gtk_alternative_dialog_button_order (screen))
1239       return;
1240
1241   va_start (args, first_response_id);
1242
1243   gtk_dialog_set_alternative_button_order_valist (dialog,
1244                                                   first_response_id,
1245                                                   args);
1246   va_end (args);
1247 }
1248 /**
1249  * gtk_dialog_set_alternative_button_order_from_array:
1250  * @dialog: a #GtkDialog
1251  * @n_params: the number of response ids in @new_order
1252  * @new_order: an array of response ids of @dialog's buttons
1253  *
1254  * Sets an alternative button order. If the 
1255  * #GtkSettings:gtk-alternative-button-order setting is set to %TRUE, 
1256  * the dialog buttons are reordered according to the order of the 
1257  * response ids in @new_order.
1258  *
1259  * See gtk_dialog_set_alternative_button_order() for more information.
1260  *
1261  * This function is for use by language bindings.
1262  * 
1263  * Since: 2.6
1264  */
1265 void 
1266 gtk_dialog_set_alternative_button_order_from_array (GtkDialog *dialog,
1267                                                     gint       n_params,
1268                                                     gint      *new_order)
1269 {
1270   GdkScreen *screen;
1271   GtkWidget *child;
1272   gint position;
1273
1274   g_return_if_fail (GTK_IS_DIALOG (dialog));
1275   g_return_if_fail (new_order != NULL);
1276
1277   screen = gtk_widget_get_screen (GTK_WIDGET (dialog));
1278   if (!gtk_alternative_dialog_button_order (screen))
1279       return;
1280
1281   for (position = 0; position < n_params; position++)
1282   {
1283       /* reorder child with response_id to position */
1284       child = dialog_find_button (dialog, new_order[position]);
1285       gtk_box_reorder_child (GTK_BOX (dialog->action_area), child, position);
1286     }
1287 }
1288
1289 typedef struct {
1290   gchar *widget_name;
1291   gchar *response_id;
1292 } ActionWidgetInfo;
1293
1294 typedef struct {
1295   GtkDialog *dialog;
1296   GtkBuilder *builder;
1297   GSList *items;
1298   gchar *response;
1299 } ActionWidgetsSubParserData;
1300
1301 static void
1302 attributes_start_element (GMarkupParseContext *context,
1303                           const gchar         *element_name,
1304                           const gchar        **names,
1305                           const gchar        **values,
1306                           gpointer             user_data,
1307                           GError             **error)
1308 {
1309   ActionWidgetsSubParserData *parser_data = (ActionWidgetsSubParserData*)user_data;
1310   guint i;
1311
1312   if (strcmp (element_name, "action-widget") == 0)
1313     for (i = 0; names[i]; i++)
1314       if (strcmp (names[i], "response") == 0)
1315         parser_data->response = g_strdup (values[i]);
1316   else if (strcmp (element_name, "action-widgets") == 0)
1317     return;
1318   else
1319     g_warning ("Unsupported tag for GtkDialog: %s\n", element_name);
1320 }
1321
1322 static void
1323 attributes_text_element (GMarkupParseContext *context,
1324                          const gchar         *text,
1325                          gsize                text_len,
1326                          gpointer             user_data,
1327                          GError             **error)
1328 {
1329   ActionWidgetsSubParserData *parser_data = (ActionWidgetsSubParserData*)user_data;
1330   ActionWidgetInfo *item;
1331
1332   if (!parser_data->response)
1333     return;
1334
1335   item = g_new (ActionWidgetInfo, 1);
1336   item->widget_name = g_strndup (text, text_len);
1337   item->response_id = parser_data->response;
1338   parser_data->items = g_slist_prepend (parser_data->items, item);
1339   parser_data->response = NULL;
1340 }
1341
1342 static const GMarkupParser attributes_parser =
1343   {
1344     attributes_start_element,
1345     NULL,
1346     attributes_text_element,
1347   };
1348
1349 gboolean
1350 gtk_dialog_buildable_custom_tag_start (GtkBuildable  *buildable,
1351                                        GtkBuilder    *builder,
1352                                        GObject       *child,
1353                                        const gchar   *tagname,
1354                                        GMarkupParser *parser,
1355                                        gpointer      *data)
1356 {
1357   ActionWidgetsSubParserData *parser_data;
1358
1359   if (child)
1360     return FALSE;
1361
1362   if (strcmp (tagname, "action-widgets") == 0)
1363     {
1364       parser_data = g_slice_new0 (ActionWidgetsSubParserData);
1365       parser_data->dialog = GTK_DIALOG (buildable);
1366       parser_data->items = NULL;
1367
1368       *parser = attributes_parser;
1369       *data = parser_data;
1370       return TRUE;
1371     }
1372
1373   return parent_buildable_iface->custom_tag_start (buildable, builder, child,
1374                                                    tagname, parser, data);
1375 }
1376
1377 static void
1378 gtk_dialog_buildable_custom_finished (GtkBuildable *buildable,
1379                                       GtkBuilder   *builder,
1380                                       GObject      *child,
1381                                       const gchar  *tagname,
1382                                       gpointer      user_data)
1383 {
1384   GSList *l;
1385   ActionWidgetsSubParserData *parser_data;
1386   GObject *object;
1387   GtkDialog *dialog;
1388   ResponseData *ad;
1389   guint signal_id;
1390   
1391   if (strcmp (tagname, "action-widgets"))
1392     {
1393     parent_buildable_iface->custom_finished (buildable, builder, child,
1394                                              tagname, user_data);
1395     return;
1396     }
1397
1398   dialog = GTK_DIALOG (buildable);
1399   parser_data = (ActionWidgetsSubParserData*)user_data;
1400   parser_data->items = g_slist_reverse (parser_data->items);
1401
1402   for (l = parser_data->items; l; l = l->next)
1403     {
1404       ActionWidgetInfo *item = l->data;
1405
1406       object = gtk_builder_get_object (builder, item->widget_name);
1407       if (!object)
1408         {
1409           g_warning ("Unknown object %s specified in action-widgets of %s",
1410                      item->widget_name,
1411                      gtk_buildable_get_name (GTK_BUILDABLE (buildable)));
1412           continue;
1413         }
1414
1415       ad = get_response_data (GTK_WIDGET (object), TRUE);
1416       ad->response_id = atoi (item->response_id);
1417
1418       if (GTK_IS_BUTTON (object))
1419         signal_id = g_signal_lookup ("clicked", GTK_TYPE_BUTTON);
1420       else
1421         signal_id = GTK_WIDGET_GET_CLASS (object)->activate_signal;
1422       
1423       if (signal_id)
1424         {
1425           GClosure *closure;
1426           
1427           closure = g_cclosure_new_object (G_CALLBACK (action_widget_activated),
1428                                            G_OBJECT (dialog));
1429           g_signal_connect_closure_by_id (object,
1430                                           signal_id,
1431                                           0,
1432                                           closure,
1433                                           FALSE);
1434         }
1435
1436       if (ad->response_id == GTK_RESPONSE_HELP)
1437         gtk_button_box_set_child_secondary (GTK_BUTTON_BOX (dialog->action_area),
1438                                             GTK_WIDGET (object), TRUE);
1439
1440       g_free (item->widget_name);
1441       g_free (item->response_id);
1442       g_free (item);
1443     }
1444   g_slist_free (parser_data->items);
1445   g_slice_free (ActionWidgetsSubParserData, parser_data);
1446 }
1447
1448 /**
1449  * gtk_dialog_get_action_area:
1450  * @dialog: a #GtkDialog
1451  *
1452  * Returns the action area of @dialog.
1453  *
1454  * Returns: the action area.
1455  *
1456  * Since: 2.14
1457  **/
1458 GtkWidget *
1459 gtk_dialog_get_action_area (GtkDialog *dialog)
1460 {
1461   g_return_val_if_fail (GTK_IS_DIALOG (dialog), NULL);
1462
1463   return dialog->action_area;
1464 }
1465
1466 /**
1467  * gtk_dialog_get_content_area:
1468  * @dialog: a #GtkDialog
1469  *
1470  * Returns the content area of @dialog.
1471  *
1472  * Returns: the content area #GtkVBox.
1473  *
1474  * Since: 2.14
1475  **/
1476 GtkWidget *
1477 gtk_dialog_get_content_area (GtkDialog *dialog)
1478 {
1479   g_return_val_if_fail (GTK_IS_DIALOG (dialog), NULL);
1480
1481   return dialog->vbox;
1482 }
1483
1484 #define __GTK_DIALOG_C__
1485 #include "gtkaliasdef.c"