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