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