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