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