1 /* GTK - The GIMP Toolkit
2 * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
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.
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.
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.
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/.
32 #include "gtkbutton.h"
33 #include "gtkdialog.h"
36 #include "gtkmarshalers.h"
40 #include "gtkbindings.h"
41 #include "gtkprivate.h"
42 #include "gtkbuildable.h"
46 * @Short_description: Create popup windows
48 * @See_also: #GtkVBox, #GtkWindow, #GtkButton
50 * Dialog boxes are a convenient way to prompt the user for a small amount
51 * of input, e.g. to display a message, ask a question, or anything else
52 * that does not require extensive effort on the user's part.
54 * GTK+ treats a dialog as a window split vertically. The top section is a
55 * #GtkVBox, and is where widgets such as a #GtkLabel or a #GtkEntry should
56 * be packed. The bottom area is known as the
57 * <structfield>action_area</structfield>. This is generally used for
58 * packing buttons into the dialog which may perform functions such as
59 * cancel, ok, or apply. The two areas are separated by a #GtkHSeparator.
61 * #GtkDialog boxes are created with a call to gtk_dialog_new() or
62 * gtk_dialog_new_with_buttons(). gtk_dialog_new_with_buttons() is
63 * recommended; it allows you to set the dialog title, some convenient flags,
64 * and add simple buttons.
66 * If 'dialog' is a newly created dialog, the two primary areas of the
67 * window can be accessed through gtk_dialog_get_content_area() and
68 * gtk_dialog_get_action_area(), as can be seen from the example below.
70 * A 'modal' dialog (that is, one which freezes the rest of the application
71 * from user input), can be created by calling gtk_window_set_modal() on the
72 * dialog. Use the GTK_WINDOW() macro to cast the widget returned from
73 * gtk_dialog_new() into a #GtkWindow. When using gtk_dialog_new_with_buttons()
74 * you can also pass the #GTK_DIALOG_MODAL flag to make a dialog modal.
76 * If you add buttons to #GtkDialog using gtk_dialog_new_with_buttons(),
77 * gtk_dialog_add_button(), gtk_dialog_add_buttons(), or
78 * gtk_dialog_add_action_widget(), clicking the button will emit a signal
79 * called #GtkDialog::response with a response ID that you specified. GTK+
80 * will never assign a meaning to positive response IDs; these are entirely
81 * user-defined. But for convenience, you can use the response IDs in the
82 * #GtkResponseType enumeration (these all have values less than zero). If
83 * a dialog receives a delete event, the #GtkDialog::response signal will
84 * be emitted with a response ID of #GTK_RESPONSE_DELETE_EVENT.
86 * If you want to block waiting for a dialog to return before returning
87 * control flow to your code, you can call gtk_dialog_run(). This function
88 * enters a recursive main loop and waits for the user to respond to the
89 * dialog, returning the response ID corresponding to the button the user
92 * For the simple dialog in the following example, in reality you'd probably
93 * use #GtkMessageDialog to save yourself some effort. But you'd need to
94 * create the dialog contents manually if you had more than a simple message
97 * <title>Simple GtkDialog usage</title>
99 * /* Function to open a dialog box displaying the message provided. */
101 * quick_message (gchar *message)
103 * GtkWidget *dialog, *label, *content_area;
105 * /* Create the widgets */
106 * dialog = gtk_dialog_new_with_buttons ("Message",
107 * main_application_window,
108 * GTK_DIALOG_DESTROY_WITH_PARENT,
112 * content_area = gtk_dialog_get_content_area (GTK_DIALOG (dialog));
113 * label = gtk_label_new (message);
115 * /* Ensure that the dialog box is destroyed when the user responds */
116 * g_signal_connect_swapped (dialog,
118 * G_CALLBACK (gtk_widget_destroy),
121 * /* Add the label, and show everything we've added to the dialog */
123 * gtk_container_add (GTK_CONTAINER (content_area), label);
124 * gtk_widget_show_all (dialog);
129 * <refsect2 id="GtkDialog-BUILDER-UI"><title>GtkDialog as GtkBuildable</title>
131 * The GtkDialog implementation of the #GtkBuildable interface exposes the
132 * @vbox and @action_area as internal children with the names "vbox" and
136 * GtkDialog supports a custom <action-widgets> element, which
137 * can contain multiple <action-widget> elements. The "response"
138 * attribute specifies a numeric response, and the content of the element
139 * is the id of widget (which should be a child of the dialogs @action_area).
142 * <title>A <structname>GtkDialog</structname> UI definition fragment.</title>
143 * <programlisting><![CDATA[
144 * <object class="GtkDialog" id="dialog1">
145 * <child internal-child="vbox">"
146 * <object class="GtkVBox" id="vbox">
147 * <child internal-child="action_area">
148 * <object class="GtkHButtonBox" id="button_box">
150 * <object class="GtkButton" id="button_cancel"/>
153 * <object class="GtkButton" id="button_ok"/>
160 * <action-widget response="3">button_ok</action-widget>
161 * <action-widget response="-5">button_cancel</action-widget>
164 * ]]></programlisting>
169 struct _GtkDialogPrivate
172 GtkWidget *action_area;
175 typedef struct _ResponseData ResponseData;
182 static void gtk_dialog_add_buttons_valist (GtkDialog *dialog,
183 const gchar *first_button_text,
186 static gboolean gtk_dialog_delete_event_handler (GtkWidget *widget,
189 static void gtk_dialog_style_updated (GtkWidget *widget);
190 static void gtk_dialog_map (GtkWidget *widget);
192 static void gtk_dialog_close (GtkDialog *dialog);
194 static ResponseData * get_response_data (GtkWidget *widget,
197 static void gtk_dialog_buildable_interface_init (GtkBuildableIface *iface);
198 static GObject * gtk_dialog_buildable_get_internal_child (GtkBuildable *buildable,
200 const gchar *childname);
201 static gboolean gtk_dialog_buildable_custom_tag_start (GtkBuildable *buildable,
204 const gchar *tagname,
205 GMarkupParser *parser,
207 static void gtk_dialog_buildable_custom_finished (GtkBuildable *buildable,
210 const gchar *tagname,
225 static guint dialog_signals[LAST_SIGNAL];
227 G_DEFINE_TYPE_WITH_CODE (GtkDialog, gtk_dialog, GTK_TYPE_WINDOW,
228 G_IMPLEMENT_INTERFACE (GTK_TYPE_BUILDABLE,
229 gtk_dialog_buildable_interface_init))
232 gtk_dialog_class_init (GtkDialogClass *class)
234 GObjectClass *gobject_class;
235 GtkWidgetClass *widget_class;
236 GtkBindingSet *binding_set;
238 gobject_class = G_OBJECT_CLASS (class);
239 widget_class = GTK_WIDGET_CLASS (class);
241 widget_class->map = gtk_dialog_map;
242 widget_class->style_updated = gtk_dialog_style_updated;
244 class->close = gtk_dialog_close;
246 g_type_class_add_private (gobject_class, sizeof (GtkDialogPrivate));
249 * GtkDialog::response:
250 * @dialog: the object on which the signal is emitted
251 * @response_id: the response ID
253 * Emitted when an action widget is clicked, the dialog receives a
254 * delete event, or the application programmer calls gtk_dialog_response().
255 * On a delete event, the response ID is #GTK_RESPONSE_DELETE_EVENT.
256 * Otherwise, it depends on which action widget was clicked.
258 dialog_signals[RESPONSE] =
259 g_signal_new (I_("response"),
260 G_OBJECT_CLASS_TYPE (class),
262 G_STRUCT_OFFSET (GtkDialogClass, response),
264 _gtk_marshal_VOID__INT,
271 * The ::close signal is a
272 * <link linkend="keybinding-signals">keybinding signal</link>
273 * which gets emitted when the user uses a keybinding to close
276 * The default binding for this signal is the Escape key.
278 dialog_signals[CLOSE] =
279 g_signal_new (I_("close"),
280 G_OBJECT_CLASS_TYPE (class),
281 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
282 G_STRUCT_OFFSET (GtkDialogClass, close),
284 _gtk_marshal_VOID__VOID,
287 gtk_widget_class_install_style_property (widget_class,
288 g_param_spec_int ("content-area-border",
289 P_("Content area border"),
290 P_("Width of border around the main dialog area"),
294 GTK_PARAM_READABLE));
296 * GtkDialog:content-area-spacing:
298 * The default spacing used between elements of the
299 * content area of the dialog, as returned by
300 * gtk_dialog_get_content_area(), unless gtk_box_set_spacing()
301 * was called on that widget directly.
305 gtk_widget_class_install_style_property (widget_class,
306 g_param_spec_int ("content-area-spacing",
307 P_("Content area spacing"),
308 P_("Spacing between elements of the main dialog area"),
312 GTK_PARAM_READABLE));
313 gtk_widget_class_install_style_property (widget_class,
314 g_param_spec_int ("button-spacing",
315 P_("Button spacing"),
316 P_("Spacing between buttons"),
320 GTK_PARAM_READABLE));
322 gtk_widget_class_install_style_property (widget_class,
323 g_param_spec_int ("action-area-border",
324 P_("Action area border"),
325 P_("Width of border around the button area at the bottom of the dialog"),
329 GTK_PARAM_READABLE));
331 binding_set = gtk_binding_set_by_class (class);
333 gtk_binding_entry_add_signal (binding_set, GDK_KEY_Escape, 0, "close", 0);
337 update_spacings (GtkDialog *dialog)
339 GtkDialogPrivate *priv = dialog->priv;
340 gint content_area_border;
341 gint content_area_spacing;
343 gint action_area_border;
345 gtk_widget_style_get (GTK_WIDGET (dialog),
346 "content-area-border", &content_area_border,
347 "content-area-spacing", &content_area_spacing,
348 "button-spacing", &button_spacing,
349 "action-area-border", &action_area_border,
352 gtk_container_set_border_width (GTK_CONTAINER (priv->vbox),
353 content_area_border);
354 if (!_gtk_box_get_spacing_set (GTK_BOX (priv->vbox)))
356 gtk_box_set_spacing (GTK_BOX (priv->vbox), content_area_spacing);
357 _gtk_box_set_spacing_set (GTK_BOX (priv->vbox), FALSE);
359 gtk_box_set_spacing (GTK_BOX (priv->action_area),
361 gtk_container_set_border_width (GTK_CONTAINER (priv->action_area),
366 gtk_dialog_init (GtkDialog *dialog)
368 GtkDialogPrivate *priv;
370 dialog->priv = G_TYPE_INSTANCE_GET_PRIVATE (dialog,
375 /* To avoid breaking old code that prevents destroy on delete event
376 * by connecting a handler, we have to have the FIRST signal
377 * connection on the dialog.
379 g_signal_connect (dialog,
381 G_CALLBACK (gtk_dialog_delete_event_handler),
384 priv->vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
385 gtk_container_add (GTK_CONTAINER (dialog), priv->vbox);
386 gtk_widget_show (priv->vbox);
388 priv->action_area = gtk_button_box_new (GTK_ORIENTATION_HORIZONTAL);
390 gtk_button_box_set_layout (GTK_BUTTON_BOX (priv->action_area),
393 gtk_box_pack_end (GTK_BOX (priv->vbox), priv->action_area,
395 gtk_widget_show (priv->action_area);
397 gtk_window_set_type_hint (GTK_WINDOW (dialog),
398 GDK_WINDOW_TYPE_HINT_DIALOG);
399 gtk_window_set_position (GTK_WINDOW (dialog), GTK_WIN_POS_CENTER_ON_PARENT);
402 static GtkBuildableIface *parent_buildable_iface;
405 gtk_dialog_buildable_interface_init (GtkBuildableIface *iface)
407 parent_buildable_iface = g_type_interface_peek_parent (iface);
408 iface->get_internal_child = gtk_dialog_buildable_get_internal_child;
409 iface->custom_tag_start = gtk_dialog_buildable_custom_tag_start;
410 iface->custom_finished = gtk_dialog_buildable_custom_finished;
414 gtk_dialog_buildable_get_internal_child (GtkBuildable *buildable,
416 const gchar *childname)
418 GtkDialogPrivate *priv = GTK_DIALOG (buildable)->priv;
420 if (strcmp (childname, "vbox") == 0)
421 return G_OBJECT (priv->vbox);
422 else if (strcmp (childname, "action_area") == 0)
423 return G_OBJECT (priv->action_area);
425 return parent_buildable_iface->get_internal_child (buildable,
431 gtk_dialog_delete_event_handler (GtkWidget *widget,
435 /* emit response signal */
436 gtk_dialog_response (GTK_DIALOG (widget), GTK_RESPONSE_DELETE_EVENT);
438 /* Do the destroy by default */
442 /* A far too tricky heuristic for getting the right initial
443 * focus widget if none was set. What we do is we focus the first
444 * widget in the tab chain, but if this results in the focus
445 * ending up on one of the response widgets _other_ than the
446 * default response, we focus the default response instead.
448 * Additionally, skip selectable labels when looking for the
449 * right initial focus widget.
452 gtk_dialog_map (GtkWidget *widget)
454 GtkWidget *default_widget, *focus;
455 GtkWindow *window = GTK_WINDOW (widget);
456 GtkDialog *dialog = GTK_DIALOG (widget);
457 GtkDialogPrivate *priv = dialog->priv;
459 GTK_WIDGET_CLASS (gtk_dialog_parent_class)->map (widget);
461 focus = gtk_window_get_focus (window);
464 GList *children, *tmp_list;
465 GtkWidget *first_focus = NULL;
469 g_signal_emit_by_name (window, "move_focus", GTK_DIR_TAB_FORWARD);
471 focus = gtk_window_get_focus (window);
472 if (GTK_IS_LABEL (focus) &&
473 !gtk_label_get_current_uri (GTK_LABEL (focus)))
474 gtk_label_select_region (GTK_LABEL (focus), 0, 0);
476 if (first_focus == NULL)
478 else if (first_focus == focus)
481 if (!GTK_IS_LABEL (focus))
486 tmp_list = children = gtk_container_get_children (GTK_CONTAINER (priv->action_area));
490 GtkWidget *child = tmp_list->data;
492 default_widget = gtk_window_get_default_widget (window);
493 if ((focus == NULL || child == focus) &&
494 child != default_widget &&
497 gtk_widget_grab_focus (default_widget);
501 tmp_list = tmp_list->next;
504 g_list_free (children);
509 gtk_dialog_style_updated (GtkWidget *widget)
511 update_spacings (GTK_DIALOG (widget));
515 dialog_find_button (GtkDialog *dialog,
518 GtkDialogPrivate *priv = dialog->priv;
519 GtkWidget *child = NULL;
520 GList *children, *tmp_list;
522 children = gtk_container_get_children (GTK_CONTAINER (priv->action_area));
524 for (tmp_list = children; tmp_list; tmp_list = tmp_list->next)
526 ResponseData *rd = get_response_data (tmp_list->data, FALSE);
528 if (rd && rd->response_id == response_id)
530 child = tmp_list->data;
535 g_list_free (children);
541 gtk_dialog_close (GtkDialog *dialog)
543 /* Synthesize delete_event to close dialog. */
545 GtkWidget *widget = GTK_WIDGET (dialog);
548 event = gdk_event_new (GDK_DELETE);
550 event->any.window = g_object_ref (gtk_widget_get_window (widget));
551 event->any.send_event = TRUE;
553 gtk_main_do_event (event);
554 gdk_event_free (event);
560 * Creates a new dialog box.
562 * Widgets should not be packed into this #GtkWindow
563 * directly, but into the @vbox and @action_area, as described above.
565 * Returns: the new dialog as a #GtkWidget
568 gtk_dialog_new (void)
570 return g_object_new (GTK_TYPE_DIALOG, NULL);
574 gtk_dialog_new_empty (const gchar *title,
576 GtkDialogFlags flags)
580 dialog = g_object_new (GTK_TYPE_DIALOG, NULL);
583 gtk_window_set_title (GTK_WINDOW (dialog), title);
586 gtk_window_set_transient_for (GTK_WINDOW (dialog), parent);
588 if (flags & GTK_DIALOG_MODAL)
589 gtk_window_set_modal (GTK_WINDOW (dialog), TRUE);
591 if (flags & GTK_DIALOG_DESTROY_WITH_PARENT)
592 gtk_window_set_destroy_with_parent (GTK_WINDOW (dialog), TRUE);
594 return GTK_WIDGET (dialog);
598 * gtk_dialog_new_with_buttons:
599 * @title: (allow-none): Title of the dialog, or %NULL
600 * @parent: (allow-none): Transient parent of the dialog, or %NULL
601 * @flags: from #GtkDialogFlags
602 * @first_button_text: (allow-none): stock ID or text to go in first button, or %NULL
603 * @Varargs: response ID for first button, then additional buttons, ending with %NULL
605 * Creates a new #GtkDialog with title @title (or %NULL for the default
606 * title; see gtk_window_set_title()) and transient parent @parent (or
607 * %NULL for none; see gtk_window_set_transient_for()). The @flags
608 * argument can be used to make the dialog modal (#GTK_DIALOG_MODAL)
609 * and/or to have it destroyed along with its transient parent
610 * (#GTK_DIALOG_DESTROY_WITH_PARENT). After @flags, button
611 * text/response ID pairs should be listed, with a %NULL pointer ending
612 * the list. Button text can be either a stock ID such as
613 * #GTK_STOCK_OK, or some arbitrary text. A response ID can be
614 * any positive number, or one of the values in the #GtkResponseType
615 * enumeration. If the user clicks one of these dialog buttons,
616 * #GtkDialog will emit the #GtkDialog::response signal with the corresponding
617 * response ID. If a #GtkDialog receives the #GtkWidget::delete-event signal,
618 * it will emit ::response with a response ID of #GTK_RESPONSE_DELETE_EVENT.
619 * However, destroying a dialog does not emit the ::response signal;
620 * so be careful relying on ::response when using the
621 * #GTK_DIALOG_DESTROY_WITH_PARENT flag. Buttons are from left to right,
622 * so the first button in the list will be the leftmost button in the dialog.
624 * Here's a simple example:
626 * GtkWidget *dialog = gtk_dialog_new_with_buttons ("My dialog",
628 * GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
630 * GTK_RESPONSE_ACCEPT,
632 * GTK_RESPONSE_REJECT,
636 * Return value: a new #GtkDialog
639 gtk_dialog_new_with_buttons (const gchar *title,
641 GtkDialogFlags flags,
642 const gchar *first_button_text,
648 dialog = GTK_DIALOG (gtk_dialog_new_empty (title, parent, flags));
650 va_start (args, first_button_text);
652 gtk_dialog_add_buttons_valist (dialog,
658 return GTK_WIDGET (dialog);
662 response_data_free (gpointer data)
664 g_slice_free (ResponseData, data);
668 get_response_data (GtkWidget *widget,
671 ResponseData *ad = g_object_get_data (G_OBJECT (widget),
672 "gtk-dialog-response-data");
674 if (ad == NULL && create)
676 ad = g_slice_new (ResponseData);
678 g_object_set_data_full (G_OBJECT (widget),
679 I_("gtk-dialog-response-data"),
688 action_widget_activated (GtkWidget *widget, GtkDialog *dialog)
692 response_id = gtk_dialog_get_response_for_widget (dialog, widget);
694 gtk_dialog_response (dialog, response_id);
698 * gtk_dialog_add_action_widget:
699 * @dialog: a #GtkDialog
700 * @child: an activatable widget
701 * @response_id: response ID for @child
703 * Adds an activatable widget to the action area of a #GtkDialog,
704 * connecting a signal handler that will emit the #GtkDialog::response
705 * signal on the dialog when the widget is activated. The widget is
706 * appended to the end of the dialog's action area. If you want to add a
707 * non-activatable widget, simply pack it into the @action_area field
708 * of the #GtkDialog struct.
711 gtk_dialog_add_action_widget (GtkDialog *dialog,
715 GtkDialogPrivate *priv;
719 g_return_if_fail (GTK_IS_DIALOG (dialog));
720 g_return_if_fail (GTK_IS_WIDGET (child));
724 ad = get_response_data (child, TRUE);
726 ad->response_id = response_id;
728 if (GTK_IS_BUTTON (child))
729 signal_id = g_signal_lookup ("clicked", GTK_TYPE_BUTTON);
731 signal_id = GTK_WIDGET_GET_CLASS (child)->activate_signal;
737 closure = g_cclosure_new_object (G_CALLBACK (action_widget_activated),
739 g_signal_connect_closure_by_id (child,
746 g_warning ("Only 'activatable' widgets can be packed into the action area of a GtkDialog");
748 gtk_box_pack_end (GTK_BOX (priv->action_area),
752 if (response_id == GTK_RESPONSE_HELP)
753 gtk_button_box_set_child_secondary (GTK_BUTTON_BOX (priv->action_area), child, TRUE);
757 * gtk_dialog_add_button:
758 * @dialog: a #GtkDialog
759 * @button_text: text of button, or stock ID
760 * @response_id: response ID for the button
762 * Adds a button with the given text (or a stock button, if @button_text is a
763 * stock ID) and sets things up so that clicking the button will emit the
764 * #GtkDialog::response signal with the given @response_id. The button is
765 * appended to the end of the dialog's action area. The button widget is
766 * returned, but usually you don't need it.
768 * Return value: (transfer none): the button widget that was added
771 gtk_dialog_add_button (GtkDialog *dialog,
772 const gchar *button_text,
777 g_return_val_if_fail (GTK_IS_DIALOG (dialog), NULL);
778 g_return_val_if_fail (button_text != NULL, NULL);
780 button = gtk_button_new_from_stock (button_text);
782 gtk_widget_set_can_default (button, TRUE);
784 gtk_widget_show (button);
786 gtk_dialog_add_action_widget (dialog,
794 gtk_dialog_add_buttons_valist (GtkDialog *dialog,
795 const gchar *first_button_text,
801 g_return_if_fail (GTK_IS_DIALOG (dialog));
803 if (first_button_text == NULL)
806 text = first_button_text;
807 response_id = va_arg (args, gint);
811 gtk_dialog_add_button (dialog, text, response_id);
813 text = va_arg (args, gchar*);
816 response_id = va_arg (args, int);
821 * gtk_dialog_add_buttons:
822 * @dialog: a #GtkDialog
823 * @first_button_text: button text or stock ID
824 * @Varargs: response ID for first button, then more text-response_id pairs
826 * Adds more buttons, same as calling gtk_dialog_add_button()
827 * repeatedly. The variable argument list should be %NULL-terminated
828 * as with gtk_dialog_new_with_buttons(). Each button must have both
829 * text and response ID.
832 gtk_dialog_add_buttons (GtkDialog *dialog,
833 const gchar *first_button_text,
838 va_start (args, first_button_text);
840 gtk_dialog_add_buttons_valist (dialog,
848 * gtk_dialog_set_response_sensitive:
849 * @dialog: a #GtkDialog
850 * @response_id: a response ID
851 * @setting: %TRUE for sensitive
853 * Calls <literal>gtk_widget_set_sensitive (widget, @setting)</literal>
854 * for each widget in the dialog's action area with the given @response_id.
855 * A convenient way to sensitize/desensitize dialog buttons.
858 gtk_dialog_set_response_sensitive (GtkDialog *dialog,
862 GtkDialogPrivate *priv;
866 g_return_if_fail (GTK_IS_DIALOG (dialog));
870 children = gtk_container_get_children (GTK_CONTAINER (priv->action_area));
873 while (tmp_list != NULL)
875 GtkWidget *widget = tmp_list->data;
876 ResponseData *rd = get_response_data (widget, FALSE);
878 if (rd && rd->response_id == response_id)
879 gtk_widget_set_sensitive (widget, setting);
881 tmp_list = g_list_next (tmp_list);
884 g_list_free (children);
888 * gtk_dialog_set_default_response:
889 * @dialog: a #GtkDialog
890 * @response_id: a response ID
892 * Sets the last widget in the dialog's action area with the given @response_id
893 * as the default widget for the dialog. Pressing "Enter" normally activates
894 * the default widget.
897 gtk_dialog_set_default_response (GtkDialog *dialog,
900 GtkDialogPrivate *priv;
904 g_return_if_fail (GTK_IS_DIALOG (dialog));
908 children = gtk_container_get_children (GTK_CONTAINER (priv->action_area));
911 while (tmp_list != NULL)
913 GtkWidget *widget = tmp_list->data;
914 ResponseData *rd = get_response_data (widget, FALSE);
916 if (rd && rd->response_id == response_id)
917 gtk_widget_grab_default (widget);
919 tmp_list = g_list_next (tmp_list);
922 g_list_free (children);
926 * gtk_dialog_response:
927 * @dialog: a #GtkDialog
928 * @response_id: response ID
930 * Emits the #GtkDialog::response signal with the given response ID.
931 * Used to indicate that the user has responded to the dialog in some way;
932 * typically either you or gtk_dialog_run() will be monitoring the
933 * ::response signal and take appropriate action.
936 gtk_dialog_response (GtkDialog *dialog,
939 g_return_if_fail (GTK_IS_DIALOG (dialog));
941 g_signal_emit (dialog,
942 dialog_signals[RESPONSE],
956 shutdown_loop (RunInfo *ri)
958 if (g_main_loop_is_running (ri->loop))
959 g_main_loop_quit (ri->loop);
963 run_unmap_handler (GtkDialog *dialog, gpointer data)
971 run_response_handler (GtkDialog *dialog,
979 ri->response_id = response_id;
985 run_delete_handler (GtkDialog *dialog,
993 return TRUE; /* Do not destroy */
997 run_destroy_handler (GtkDialog *dialog, gpointer data)
1001 /* shutdown_loop will be called by run_unmap_handler */
1003 ri->destroyed = TRUE;
1008 * @dialog: a #GtkDialog
1010 * Blocks in a recursive main loop until the @dialog either emits the
1011 * #GtkDialog::response signal, or is destroyed. If the dialog is
1012 * destroyed during the call to gtk_dialog_run(), gtk_dialog_run() returns
1013 * #GTK_RESPONSE_NONE. Otherwise, it returns the response ID from the
1014 * ::response signal emission.
1016 * Before entering the recursive main loop, gtk_dialog_run() calls
1017 * gtk_widget_show() on the dialog for you. Note that you still
1018 * need to show any children of the dialog yourself.
1020 * During gtk_dialog_run(), the default behavior of #GtkWidget::delete-event
1021 * is disabled; if the dialog receives ::delete_event, it will not be
1022 * destroyed as windows usually are, and gtk_dialog_run() will return
1023 * #GTK_RESPONSE_DELETE_EVENT. Also, during gtk_dialog_run() the dialog
1024 * will be modal. You can force gtk_dialog_run() to return at any time by
1025 * calling gtk_dialog_response() to emit the ::response signal. Destroying
1026 * the dialog during gtk_dialog_run() is a very bad idea, because your
1027 * post-run code won't know whether the dialog was destroyed or not.
1029 * After gtk_dialog_run() returns, you are responsible for hiding or
1030 * destroying the dialog if you wish to do so.
1032 * Typical usage of this function might be:
1034 * gint result = gtk_dialog_run (GTK_DIALOG (dialog));
1037 * case GTK_RESPONSE_ACCEPT:
1038 * do_application_specific_something ();
1041 * do_nothing_since_dialog_was_cancelled ();
1044 * gtk_widget_destroy (dialog);
1047 * Note that even though the recursive main loop gives the effect of a
1048 * modal dialog (it prevents the user from interacting with other
1049 * windows in the same window group while the dialog is run), callbacks
1050 * such as timeouts, IO channel watches, DND drops, etc, <emphasis>will</emphasis>
1051 * be triggered during a gtk_dialog_run() call.
1053 * Return value: response ID
1056 gtk_dialog_run (GtkDialog *dialog)
1058 RunInfo ri = { NULL, GTK_RESPONSE_NONE, NULL, FALSE };
1060 gulong response_handler;
1061 gulong unmap_handler;
1062 gulong destroy_handler;
1063 gulong delete_handler;
1065 g_return_val_if_fail (GTK_IS_DIALOG (dialog), -1);
1067 g_object_ref (dialog);
1069 was_modal = gtk_window_get_modal (GTK_WINDOW (dialog));
1071 gtk_window_set_modal (GTK_WINDOW (dialog), TRUE);
1073 if (!gtk_widget_get_visible (GTK_WIDGET (dialog)))
1074 gtk_widget_show (GTK_WIDGET (dialog));
1077 g_signal_connect (dialog,
1079 G_CALLBACK (run_response_handler),
1083 g_signal_connect (dialog,
1085 G_CALLBACK (run_unmap_handler),
1089 g_signal_connect (dialog,
1091 G_CALLBACK (run_delete_handler),
1095 g_signal_connect (dialog,
1097 G_CALLBACK (run_destroy_handler),
1100 ri.loop = g_main_loop_new (NULL, FALSE);
1102 GDK_THREADS_LEAVE ();
1103 g_main_loop_run (ri.loop);
1104 GDK_THREADS_ENTER ();
1106 g_main_loop_unref (ri.loop);
1113 gtk_window_set_modal (GTK_WINDOW(dialog), FALSE);
1115 g_signal_handler_disconnect (dialog, response_handler);
1116 g_signal_handler_disconnect (dialog, unmap_handler);
1117 g_signal_handler_disconnect (dialog, delete_handler);
1118 g_signal_handler_disconnect (dialog, destroy_handler);
1121 g_object_unref (dialog);
1123 return ri.response_id;
1127 * gtk_dialog_get_widget_for_response:
1128 * @dialog: a #GtkDialog
1129 * @response_id: the response ID used by the @dialog widget
1131 * Gets the widget button that uses the given response ID in the action area
1134 * Returns: (transfer none): the @widget button that uses the given
1135 * @response_id, or %NULL.
1140 gtk_dialog_get_widget_for_response (GtkDialog *dialog,
1143 GtkDialogPrivate *priv;
1147 g_return_val_if_fail (GTK_IS_DIALOG (dialog), NULL);
1149 priv = dialog->priv;
1151 children = gtk_container_get_children (GTK_CONTAINER (priv->action_area));
1153 tmp_list = children;
1154 while (tmp_list != NULL)
1156 GtkWidget *widget = tmp_list->data;
1157 ResponseData *rd = get_response_data (widget, FALSE);
1159 if (rd && rd->response_id == response_id)
1161 g_list_free (children);
1165 tmp_list = g_list_next (tmp_list);
1168 g_list_free (children);
1174 * gtk_dialog_get_response_for_widget:
1175 * @dialog: a #GtkDialog
1176 * @widget: a widget in the action area of @dialog
1178 * Gets the response id of a widget in the action area
1181 * Returns: the response id of @widget, or %GTK_RESPONSE_NONE
1182 * if @widget doesn't have a response id set.
1187 gtk_dialog_get_response_for_widget (GtkDialog *dialog,
1192 rd = get_response_data (widget, FALSE);
1194 return GTK_RESPONSE_NONE;
1196 return rd->response_id;
1200 * gtk_alternative_dialog_button_order:
1201 * @screen: (allow-none): a #GdkScreen, or %NULL to use the default screen
1203 * Returns %TRUE if dialogs are expected to use an alternative
1204 * button order on the screen @screen. See
1205 * gtk_dialog_set_alternative_button_order() for more details
1206 * about alternative button order.
1208 * If you need to use this function, you should probably connect
1209 * to the ::notify:gtk-alternative-button-order signal on the
1210 * #GtkSettings object associated to @screen, in order to be
1211 * notified if the button order setting changes.
1213 * Returns: Whether the alternative button order should be used
1218 gtk_alternative_dialog_button_order (GdkScreen *screen)
1220 GtkSettings *settings;
1224 settings = gtk_settings_get_for_screen (screen);
1226 settings = gtk_settings_get_default ();
1228 g_object_get (settings,
1229 "gtk-alternative-button-order", &result, NULL);
1235 gtk_dialog_set_alternative_button_order_valist (GtkDialog *dialog,
1236 gint first_response_id,
1239 GtkDialogPrivate *priv = dialog->priv;
1244 response_id = first_response_id;
1246 while (response_id != -1)
1248 /* reorder child with response_id to position */
1249 child = dialog_find_button (dialog, response_id);
1250 gtk_box_reorder_child (GTK_BOX (priv->action_area), child, position);
1252 response_id = va_arg (args, gint);
1258 * gtk_dialog_set_alternative_button_order:
1259 * @dialog: a #GtkDialog
1260 * @first_response_id: a response id used by one @dialog's buttons
1261 * @Varargs: a list of more response ids of @dialog's buttons, terminated by -1
1263 * Sets an alternative button order. If the
1264 * #GtkSettings:gtk-alternative-button-order setting is set to %TRUE,
1265 * the dialog buttons are reordered according to the order of the
1266 * response ids passed to this function.
1268 * By default, GTK+ dialogs use the button order advocated by the Gnome
1269 * <ulink url="http://library.gnome.org/devel/hig-book/stable/">Human
1270 * Interface Guidelines</ulink> with the affirmative button at the far
1271 * right, and the cancel button left of it. But the builtin GTK+ dialogs
1272 * and #GtkMessageDialog<!-- -->s do provide an alternative button order,
1273 * which is more suitable on some platforms, e.g. Windows.
1275 * Use this function after adding all the buttons to your dialog, as the
1276 * following example shows:
1278 * cancel_button = gtk_dialog_add_button (GTK_DIALOG (dialog),
1280 * GTK_RESPONSE_CANCEL);
1282 * ok_button = gtk_dialog_add_button (GTK_DIALOG (dialog),
1286 * gtk_widget_grab_default (ok_button);
1288 * help_button = gtk_dialog_add_button (GTK_DIALOG (dialog),
1290 * GTK_RESPONSE_HELP);
1292 * gtk_dialog_set_alternative_button_order (GTK_DIALOG (dialog),
1294 * GTK_RESPONSE_CANCEL,
1295 * GTK_RESPONSE_HELP,
1302 gtk_dialog_set_alternative_button_order (GtkDialog *dialog,
1303 gint first_response_id,
1309 g_return_if_fail (GTK_IS_DIALOG (dialog));
1311 screen = gtk_widget_get_screen (GTK_WIDGET (dialog));
1312 if (!gtk_alternative_dialog_button_order (screen))
1315 va_start (args, first_response_id);
1317 gtk_dialog_set_alternative_button_order_valist (dialog,
1323 * gtk_dialog_set_alternative_button_order_from_array:
1324 * @dialog: a #GtkDialog
1325 * @n_params: the number of response ids in @new_order
1326 * @new_order: (array length=n_params): an array of response ids of
1329 * Sets an alternative button order. If the
1330 * #GtkSettings:gtk-alternative-button-order setting is set to %TRUE,
1331 * the dialog buttons are reordered according to the order of the
1332 * response ids in @new_order.
1334 * See gtk_dialog_set_alternative_button_order() for more information.
1336 * This function is for use by language bindings.
1341 gtk_dialog_set_alternative_button_order_from_array (GtkDialog *dialog,
1345 GtkDialogPrivate *priv = dialog->priv;
1350 g_return_if_fail (GTK_IS_DIALOG (dialog));
1351 g_return_if_fail (new_order != NULL);
1353 screen = gtk_widget_get_screen (GTK_WIDGET (dialog));
1354 if (!gtk_alternative_dialog_button_order (screen))
1357 for (position = 0; position < n_params; position++)
1359 /* reorder child with response_id to position */
1360 child = dialog_find_button (dialog, new_order[position]);
1361 gtk_box_reorder_child (GTK_BOX (priv->action_area), child, position);
1372 GtkBuilder *builder;
1375 } ActionWidgetsSubParserData;
1378 attributes_start_element (GMarkupParseContext *context,
1379 const gchar *element_name,
1380 const gchar **names,
1381 const gchar **values,
1385 ActionWidgetsSubParserData *parser_data = (ActionWidgetsSubParserData*)user_data;
1388 if (strcmp (element_name, "action-widget") == 0)
1390 for (i = 0; names[i]; i++)
1391 if (strcmp (names[i], "response") == 0)
1392 parser_data->response = g_strdup (values[i]);
1394 else if (strcmp (element_name, "action-widgets") == 0)
1397 g_warning ("Unsupported tag for GtkDialog: %s\n", element_name);
1401 attributes_text_element (GMarkupParseContext *context,
1407 ActionWidgetsSubParserData *parser_data = (ActionWidgetsSubParserData*)user_data;
1408 ActionWidgetInfo *item;
1410 if (!parser_data->response)
1413 item = g_new (ActionWidgetInfo, 1);
1414 item->widget_name = g_strndup (text, text_len);
1415 item->response_id = parser_data->response;
1416 parser_data->items = g_slist_prepend (parser_data->items, item);
1417 parser_data->response = NULL;
1420 static const GMarkupParser attributes_parser =
1422 attributes_start_element,
1424 attributes_text_element,
1428 gtk_dialog_buildable_custom_tag_start (GtkBuildable *buildable,
1429 GtkBuilder *builder,
1431 const gchar *tagname,
1432 GMarkupParser *parser,
1435 ActionWidgetsSubParserData *parser_data;
1440 if (strcmp (tagname, "action-widgets") == 0)
1442 parser_data = g_slice_new0 (ActionWidgetsSubParserData);
1443 parser_data->dialog = GTK_DIALOG (buildable);
1444 parser_data->items = NULL;
1446 *parser = attributes_parser;
1447 *data = parser_data;
1451 return parent_buildable_iface->custom_tag_start (buildable, builder, child,
1452 tagname, parser, data);
1456 gtk_dialog_buildable_custom_finished (GtkBuildable *buildable,
1457 GtkBuilder *builder,
1459 const gchar *tagname,
1462 GtkDialog *dialog = GTK_DIALOG (buildable);
1463 GtkDialogPrivate *priv = dialog->priv;
1465 ActionWidgetsSubParserData *parser_data;
1470 if (strcmp (tagname, "action-widgets"))
1472 parent_buildable_iface->custom_finished (buildable, builder, child,
1473 tagname, user_data);
1477 parser_data = (ActionWidgetsSubParserData*)user_data;
1478 parser_data->items = g_slist_reverse (parser_data->items);
1480 for (l = parser_data->items; l; l = l->next)
1482 ActionWidgetInfo *item = l->data;
1484 object = gtk_builder_get_object (builder, item->widget_name);
1487 g_warning ("Unknown object %s specified in action-widgets of %s",
1489 gtk_buildable_get_name (GTK_BUILDABLE (buildable)));
1493 ad = get_response_data (GTK_WIDGET (object), TRUE);
1494 ad->response_id = g_ascii_strtoll (item->response_id, NULL, 10);
1496 if (GTK_IS_BUTTON (object))
1497 signal_id = g_signal_lookup ("clicked", GTK_TYPE_BUTTON);
1499 signal_id = GTK_WIDGET_GET_CLASS (object)->activate_signal;
1505 closure = g_cclosure_new_object (G_CALLBACK (action_widget_activated),
1507 g_signal_connect_closure_by_id (object,
1514 if (ad->response_id == GTK_RESPONSE_HELP)
1515 gtk_button_box_set_child_secondary (GTK_BUTTON_BOX (priv->action_area),
1516 GTK_WIDGET (object), TRUE);
1518 g_free (item->widget_name);
1519 g_free (item->response_id);
1522 g_slist_free (parser_data->items);
1523 g_slice_free (ActionWidgetsSubParserData, parser_data);
1527 * gtk_dialog_get_action_area:
1528 * @dialog: a #GtkDialog
1530 * Returns the action area of @dialog.
1532 * Returns: (transfer none): the action area.
1537 gtk_dialog_get_action_area (GtkDialog *dialog)
1539 g_return_val_if_fail (GTK_IS_DIALOG (dialog), NULL);
1541 return dialog->priv->action_area;
1545 * gtk_dialog_get_content_area:
1546 * @dialog: a #GtkDialog
1548 * Returns the content area of @dialog.
1550 * Returns: (transfer none): the content area #GtkBox.
1555 gtk_dialog_get_content_area (GtkDialog *dialog)
1557 g_return_val_if_fail (GTK_IS_DIALOG (dialog), NULL);
1559 return dialog->priv->vbox;