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