1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 2 -*- */
2 /* GTK - The GIMP Toolkit
3 * Copyright (C) 2000 Red Hat, Inc.
4 *
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Library General Public
7 * License as published by the Free Software Foundation; either
8 * version 2 of the License, or (at your option) any later version.
9 *
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Library General Public License for more details.
14 *
15 * You should have received a copy of the GNU Library General Public
16 * License along with this library. If not, see <http://www.gnu.org/licenses/>.
17 */
18
19 /*
20 * Modified by the GTK+ Team and others 1997-2003. See the AUTHORS
21 * file for a list of people on the GTK+ Team. See the ChangeLog
22 * files for a list of changes. These files are distributed with
23 * GTK+ at ftp://ftp.gtk.org/pub/gtk/.
24 */
25
26 #include "config.h"
27
28 #include <string.h>
29
30 #include "gtkmessagedialog.h"
31 #include "gtkaccessible.h"
32 #include "gtkbuildable.h"
33 #include "gtklabel.h"
34 #include "gtkbox.h"
35 #include "gtkbbox.h"
36 #include "gtkimage.h"
37 #include "gtkintl.h"
38 #include "gtkprivate.h"
39 #include "gtktypebuiltins.h"
40
41 /**
42 * SECTION:gtkmessagedialog
43 * @Short_description: A convenient message window
44 * @Title: GtkMessageDialog
45 * @See_also:#GtkDialog
46 *
47 * #GtkMessageDialog presents a dialog with some message text. It’s simply a
48 * convenience widget; you could construct the equivalent of #GtkMessageDialog
49 * from #GtkDialog without too much effort, but #GtkMessageDialog saves typing.
50 *
51 * One difference from #GtkDialog is that #GtkMessageDialog sets the
52 * #GtkWindow:skip-taskbar-hint property to %TRUE, so that the dialog is hidden
53 * from the taskbar by default.
54 *
55 * The easiest way to do a modal message dialog is to use gtk_dialog_run(), though
56 * you can also pass in the %GTK_DIALOG_MODAL flag, gtk_dialog_run() automatically
57 * makes the dialog modal and waits for the user to respond to it. gtk_dialog_run()
58 * returns when any dialog button is clicked.
59 *
60 * An example for using a modal dialog:
61 * |[<!-- language="C" -->
62 * GtkDialogFlags flags = GTK_DIALOG_DESTROY_WITH_PARENT;
63 * dialog = gtk_message_dialog_new (parent_window,
64 * flags,
65 * GTK_MESSAGE_ERROR,
66 * GTK_BUTTONS_CLOSE,
67 * "Error reading “%s”: %s",
68 * filename,
69 * g_strerror (errno));
70 * gtk_dialog_run (GTK_DIALOG (dialog));
71 * gtk_widget_destroy (dialog);
72 * ]|
73 *
74 * You might do a non-modal #GtkMessageDialog as follows:
75 *
76 * An example for a non-modal dialog:
77 * |[<!-- language="C" -->
78 * GtkDialogFlags flags = GTK_DIALOG_DESTROY_WITH_PARENT;
79 * dialog = gtk_message_dialog_new (parent_window,
80 * flags,
81 * GTK_MESSAGE_ERROR,
82 * GTK_BUTTONS_CLOSE,
83 * "Error reading “%s”: %s",
84 * filename,
85 * g_strerror (errno));
86 *
87 * // Destroy the dialog when the user responds to it
88 * // (e.g. clicks a button)
89 *
90 * g_signal_connect_swapped (dialog, "response",
91 * G_CALLBACK (gtk_widget_destroy),
92 * dialog);
93 * ]|
94 *
95 * # GtkMessageDialog as GtkBuildable
96 *
97 * The GtkMessageDialog implementation of the GtkBuildable interface exposes
98 * the message area as an internal child with the name “message_area”.
99 */
100
101 struct _GtkMessageDialogPrivate
102 {
103 GtkWidget *image;
104 GtkWidget *label;
105 GtkWidget *message_area; /* vbox for the primary and secondary labels, and any extra content from the caller */
106 GtkWidget *secondary_label;
107
108 guint has_primary_markup : 1;
109 guint has_secondary_text : 1;
110 guint message_type : 3;
111 };
112
113 static void gtk_message_dialog_style_updated (GtkWidget *widget);
114
115 static void gtk_message_dialog_constructed (GObject *object);
116 static void gtk_message_dialog_set_property (GObject *object,
117 guint prop_id,
118 const GValue *value,
119 GParamSpec *pspec);
120 static void gtk_message_dialog_get_property (GObject *object,
121 guint prop_id,
122 GValue *value,
123 GParamSpec *pspec);
124 static void gtk_message_dialog_add_buttons (GtkMessageDialog *message_dialog,
125 GtkButtonsType buttons);
126 static void gtk_message_dialog_buildable_interface_init (GtkBuildableIface *iface);
127
128 enum {
129 PROP_0,
130 PROP_MESSAGE_TYPE,
131 PROP_BUTTONS,
132 PROP_TEXT,
133 PROP_USE_MARKUP,
134 PROP_SECONDARY_TEXT,
135 PROP_SECONDARY_USE_MARKUP,
136 PROP_IMAGE,
137 PROP_MESSAGE_AREA
138 };
139
140 G_DEFINE_TYPE_WITH_CODE (GtkMessageDialog, gtk_message_dialog, GTK_TYPE_DIALOG,
141 G_ADD_PRIVATE (GtkMessageDialog)
142 G_IMPLEMENT_INTERFACE (GTK_TYPE_BUILDABLE,
143 gtk_message_dialog_buildable_interface_init))
144
145 static GtkBuildableIface *parent_buildable_iface;
146
147 static void
gtk_message_dialog_buildable_interface_init(GtkBuildableIface * iface)148 gtk_message_dialog_buildable_interface_init (GtkBuildableIface *iface)
149 {
150 parent_buildable_iface = g_type_interface_peek_parent (iface);
151 iface->custom_tag_start = parent_buildable_iface->custom_tag_start;
152 iface->custom_finished = parent_buildable_iface->custom_finished;
153 }
154
155 static void
gtk_message_dialog_class_init(GtkMessageDialogClass * class)156 gtk_message_dialog_class_init (GtkMessageDialogClass *class)
157 {
158 GtkWidgetClass *widget_class;
159 GObjectClass *gobject_class;
160
161 widget_class = GTK_WIDGET_CLASS (class);
162 gobject_class = G_OBJECT_CLASS (class);
163
164 widget_class->style_updated = gtk_message_dialog_style_updated;
165
166 gtk_widget_class_set_accessible_role (widget_class, ATK_ROLE_ALERT);
167
168 gobject_class->constructed = gtk_message_dialog_constructed;
169 gobject_class->set_property = gtk_message_dialog_set_property;
170 gobject_class->get_property = gtk_message_dialog_get_property;
171
172 gtk_widget_class_install_style_property (widget_class,
173 g_param_spec_int ("message-border",
174 P_("label border"),
175 P_("Width of border around the label in the message dialog"),
176 0,
177 G_MAXINT,
178 12,
179 GTK_PARAM_READABLE));
180
181 /**
182 * GtkMessageDialog:message-type:
183 *
184 * The type of the message.
185 */
186 g_object_class_install_property (gobject_class,
187 PROP_MESSAGE_TYPE,
188 g_param_spec_enum ("message-type",
189 P_("Message Type"),
190 P_("The type of message"),
191 GTK_TYPE_MESSAGE_TYPE,
192 GTK_MESSAGE_INFO,
193 GTK_PARAM_READWRITE|G_PARAM_CONSTRUCT|G_PARAM_EXPLICIT_NOTIFY));
194 g_object_class_install_property (gobject_class,
195 PROP_BUTTONS,
196 g_param_spec_enum ("buttons",
197 P_("Message Buttons"),
198 P_("The buttons shown in the message dialog"),
199 GTK_TYPE_BUTTONS_TYPE,
200 GTK_BUTTONS_NONE,
201 GTK_PARAM_WRITABLE|G_PARAM_CONSTRUCT_ONLY));
202
203 /**
204 * GtkMessageDialog:text:
205 *
206 * The primary text of the message dialog. If the dialog has
207 * a secondary text, this will appear as the title.
208 *
209 * Since: 2.10
210 */
211 g_object_class_install_property (gobject_class,
212 PROP_TEXT,
213 g_param_spec_string ("text",
214 P_("Text"),
215 P_("The primary text of the message dialog"),
216 "",
217 GTK_PARAM_READWRITE));
218
219 /**
220 * GtkMessageDialog:use-markup:
221 *
222 * %TRUE if the primary text of the dialog includes Pango markup.
223 * See pango_parse_markup().
224 *
225 * Since: 2.10
226 */
227 g_object_class_install_property (gobject_class,
228 PROP_USE_MARKUP,
229 g_param_spec_boolean ("use-markup",
230 P_("Use Markup"),
231 P_("The primary text of the title includes Pango markup."),
232 FALSE,
233 GTK_PARAM_READWRITE|G_PARAM_EXPLICIT_NOTIFY));
234
235 /**
236 * GtkMessageDialog:secondary-text:
237 *
238 * The secondary text of the message dialog.
239 *
240 * Since: 2.10
241 */
242 g_object_class_install_property (gobject_class,
243 PROP_SECONDARY_TEXT,
244 g_param_spec_string ("secondary-text",
245 P_("Secondary Text"),
246 P_("The secondary text of the message dialog"),
247 NULL,
248 GTK_PARAM_READWRITE));
249
250 /**
251 * GtkMessageDialog:secondary-use-markup:
252 *
253 * %TRUE if the secondary text of the dialog includes Pango markup.
254 * See pango_parse_markup().
255 *
256 * Since: 2.10
257 */
258 g_object_class_install_property (gobject_class,
259 PROP_SECONDARY_USE_MARKUP,
260 g_param_spec_boolean ("secondary-use-markup",
261 P_("Use Markup in secondary"),
262 P_("The secondary text includes Pango markup."),
263 FALSE,
264 GTK_PARAM_READWRITE|G_PARAM_EXPLICIT_NOTIFY));
265
266 /**
267 * GtkMessageDialog:image:
268 *
269 * The image for this dialog.
270 *
271 * Since: 2.10
272 * Deprecated: 3.12: Use #GtkDialog to create dialogs with images
273 */
274 g_object_class_install_property (gobject_class,
275 PROP_IMAGE,
276 g_param_spec_object ("image",
277 P_("Image"),
278 P_("The image"),
279 GTK_TYPE_WIDGET,
280 GTK_PARAM_READWRITE|G_PARAM_DEPRECATED));
281
282 /**
283 * GtkMessageDialog:message-area:
284 *
285 * The #GtkBox that corresponds to the message area of this dialog. See
286 * gtk_message_dialog_get_message_area() for a detailed description of this
287 * area.
288 *
289 * Since: 2.22
290 */
291 g_object_class_install_property (gobject_class,
292 PROP_MESSAGE_AREA,
293 g_param_spec_object ("message-area",
294 P_("Message area"),
295 P_("GtkBox that holds the dialog's primary and secondary labels"),
296 GTK_TYPE_WIDGET,
297 GTK_PARAM_READABLE));
298
299 /* Setup Composite data */
300 gtk_widget_class_set_template_from_resource (widget_class, "/org/gtk/libgtk/ui/gtkmessagedialog.ui");
301 gtk_widget_class_bind_template_child_private (widget_class, GtkMessageDialog, label);
302 gtk_widget_class_bind_template_child_private (widget_class, GtkMessageDialog, secondary_label);
303 gtk_widget_class_bind_template_child_internal_private (widget_class, GtkMessageDialog, message_area);
304
305 gtk_widget_class_set_css_name (widget_class, "messagedialog");
306 }
307
308 static void
gtk_message_dialog_init(GtkMessageDialog * dialog)309 gtk_message_dialog_init (GtkMessageDialog *dialog)
310 {
311 GtkMessageDialogPrivate *priv;
312 GtkWidget *action_area;
313 GtkSettings *settings;
314 gboolean use_caret;
315
316 dialog->priv = gtk_message_dialog_get_instance_private (dialog);
317 priv = dialog->priv;
318
319 priv->has_primary_markup = FALSE;
320 priv->has_secondary_text = FALSE;
321 priv->has_primary_markup = FALSE;
322 priv->has_secondary_text = FALSE;
323 priv->message_type = GTK_MESSAGE_OTHER;
324
325 gtk_widget_init_template (GTK_WIDGET (dialog));
326 gtk_message_dialog_style_updated (GTK_WIDGET (dialog));
327 G_GNUC_BEGIN_IGNORE_DEPRECATIONS
328 action_area = gtk_dialog_get_action_area (GTK_DIALOG (dialog));
329 G_GNUC_END_IGNORE_DEPRECATIONS
330 gtk_button_box_set_layout (GTK_BUTTON_BOX (action_area), GTK_BUTTONBOX_EXPAND);
331
332 settings = gtk_widget_get_settings (GTK_WIDGET (dialog));
333 g_object_get (settings, "gtk-keynav-use-caret", &use_caret, NULL);
334 gtk_label_set_selectable (GTK_LABEL (priv->label), use_caret);
335 gtk_label_set_selectable (GTK_LABEL (priv->secondary_label), use_caret);
336 }
337
338 static void
setup_primary_label_font(GtkMessageDialog * dialog)339 setup_primary_label_font (GtkMessageDialog *dialog)
340 {
341 GtkMessageDialogPrivate *priv = dialog->priv;
342
343 if (!priv->has_primary_markup)
344 {
345 PangoAttrList *attributes;
346 PangoAttribute *attr;
347
348 attributes = pango_attr_list_new ();
349
350 attr = pango_attr_weight_new (PANGO_WEIGHT_BOLD);
351 pango_attr_list_insert (attributes, attr);
352
353 if (priv->has_secondary_text)
354 {
355 attr = pango_attr_scale_new (PANGO_SCALE_LARGE);
356 pango_attr_list_insert (attributes, attr);
357 }
358
359 gtk_label_set_attributes (GTK_LABEL (priv->label), attributes);
360 pango_attr_list_unref (attributes);
361 }
362 else
363 {
364 /* unset the font settings */
365 gtk_label_set_attributes (GTK_LABEL (priv->label), NULL);
366 }
367 }
368
369 static void
setup_type(GtkMessageDialog * dialog,GtkMessageType type)370 setup_type (GtkMessageDialog *dialog,
371 GtkMessageType type)
372 {
373 GtkMessageDialogPrivate *priv = dialog->priv;
374 const gchar *name = NULL;
375 AtkObject *atk_obj;
376
377 if (priv->message_type == type)
378 return;
379
380 priv->message_type = type;
381
382 switch (type)
383 {
384 case GTK_MESSAGE_INFO:
385 name = _("Information");
386 break;
387
388 case GTK_MESSAGE_QUESTION:
389 name = _("Question");
390 break;
391
392 case GTK_MESSAGE_WARNING:
393 name = _("Warning");
394 break;
395
396 case GTK_MESSAGE_ERROR:
397 name = _("Error");
398 break;
399
400 case GTK_MESSAGE_OTHER:
401 break;
402
403 default:
404 g_warning ("Unknown GtkMessageType %u", type);
405 break;
406 }
407
408 atk_obj = gtk_widget_get_accessible (GTK_WIDGET (dialog));
409 if (GTK_IS_ACCESSIBLE (atk_obj))
410 {
411 atk_object_set_role (atk_obj, ATK_ROLE_ALERT);
412 if (name)
413 atk_object_set_name (atk_obj, name);
414 }
415
416 g_object_notify (G_OBJECT (dialog), "message-type");
417 }
418
419 static void
update_title(GObject * dialog,GParamSpec * pspec,GtkWidget * label)420 update_title (GObject *dialog,
421 GParamSpec *pspec,
422 GtkWidget *label)
423 {
424 const gchar *title;
425
426 title = gtk_window_get_title (GTK_WINDOW (dialog));
427 gtk_label_set_label (GTK_LABEL (label), title);
428 gtk_widget_set_visible (label, title && title[0]);
429 }
430
431 static void
gtk_message_dialog_constructed(GObject * object)432 gtk_message_dialog_constructed (GObject *object)
433 {
434 GtkMessageDialog *dialog = GTK_MESSAGE_DIALOG (object);
435 gboolean use_header;
436
437 G_OBJECT_CLASS (gtk_message_dialog_parent_class)->constructed (object);
438
439 g_object_get (gtk_widget_get_settings (GTK_WIDGET (dialog)),
440 "gtk-dialogs-use-header", &use_header,
441 NULL);
442
443 if (use_header)
444 {
445 GtkWidget *box;
446 GtkWidget *label;
447
448 box = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0);
449 gtk_widget_show (box);
450 gtk_widget_set_size_request (box, -1, 16);
451 label = gtk_label_new ("");
452 gtk_widget_set_no_show_all (label, TRUE);
453 gtk_widget_set_margin_top (label, 6);
454 gtk_widget_set_margin_bottom (label, 6);
455 gtk_style_context_add_class (gtk_widget_get_style_context (label), "title");
456 gtk_box_set_center_widget (GTK_BOX (box), label);
457 g_signal_connect_object (dialog, "notify::title", G_CALLBACK (update_title), label, 0);
458
459 gtk_window_set_titlebar (GTK_WINDOW (dialog), box);
460 }
461 }
462
463 static void
gtk_message_dialog_set_property(GObject * object,guint prop_id,const GValue * value,GParamSpec * pspec)464 gtk_message_dialog_set_property (GObject *object,
465 guint prop_id,
466 const GValue *value,
467 GParamSpec *pspec)
468 {
469 GtkMessageDialog *dialog = GTK_MESSAGE_DIALOG (object);
470 GtkMessageDialogPrivate *priv = dialog->priv;
471
472 switch (prop_id)
473 {
474 case PROP_MESSAGE_TYPE:
475 setup_type (dialog, g_value_get_enum (value));
476 break;
477 case PROP_BUTTONS:
478 gtk_message_dialog_add_buttons (dialog, g_value_get_enum (value));
479 break;
480 case PROP_TEXT:
481 if (priv->has_primary_markup)
482 gtk_label_set_markup (GTK_LABEL (priv->label),
483 g_value_get_string (value));
484 else
485 gtk_label_set_text (GTK_LABEL (priv->label),
486 g_value_get_string (value));
487 break;
488 case PROP_USE_MARKUP:
489 if (priv->has_primary_markup != g_value_get_boolean (value))
490 {
491 priv->has_primary_markup = g_value_get_boolean (value);
492 gtk_label_set_use_markup (GTK_LABEL (priv->label), priv->has_primary_markup);
493 g_object_notify_by_pspec (object, pspec);
494 }
495 setup_primary_label_font (dialog);
496 break;
497 case PROP_SECONDARY_TEXT:
498 {
499 const gchar *txt = g_value_get_string (value);
500
501 if (gtk_label_get_use_markup (GTK_LABEL (priv->secondary_label)))
502 gtk_label_set_markup (GTK_LABEL (priv->secondary_label), txt);
503 else
504 gtk_label_set_text (GTK_LABEL (priv->secondary_label), txt);
505
506 if (txt)
507 {
508 priv->has_secondary_text = TRUE;
509 gtk_widget_show (priv->secondary_label);
510 }
511 else
512 {
513 priv->has_secondary_text = FALSE;
514 gtk_widget_hide (priv->secondary_label);
515 }
516 setup_primary_label_font (dialog);
517 }
518 break;
519 case PROP_SECONDARY_USE_MARKUP:
520 if (gtk_label_get_use_markup (GTK_LABEL (priv->secondary_label)) != g_value_get_boolean (value))
521 {
522 gtk_label_set_use_markup (GTK_LABEL (priv->secondary_label), g_value_get_boolean (value));
523 g_object_notify_by_pspec (object, pspec);
524 }
525 break;
526 case PROP_IMAGE:
527 G_GNUC_BEGIN_IGNORE_DEPRECATIONS
528 gtk_message_dialog_set_image (dialog, g_value_get_object (value));
529 G_GNUC_END_IGNORE_DEPRECATIONS
530 break;
531
532 default:
533 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
534 break;
535 }
536 }
537
538 static void
gtk_message_dialog_get_property(GObject * object,guint prop_id,GValue * value,GParamSpec * pspec)539 gtk_message_dialog_get_property (GObject *object,
540 guint prop_id,
541 GValue *value,
542 GParamSpec *pspec)
543 {
544 GtkMessageDialog *dialog = GTK_MESSAGE_DIALOG (object);
545 GtkMessageDialogPrivate *priv = dialog->priv;
546
547 switch (prop_id)
548 {
549 case PROP_MESSAGE_TYPE:
550 g_value_set_enum (value, (GtkMessageType) priv->message_type);
551 break;
552 case PROP_TEXT:
553 g_value_set_string (value, gtk_label_get_label (GTK_LABEL (priv->label)));
554 break;
555 case PROP_USE_MARKUP:
556 g_value_set_boolean (value, priv->has_primary_markup);
557 break;
558 case PROP_SECONDARY_TEXT:
559 if (priv->has_secondary_text)
560 g_value_set_string (value,
561 gtk_label_get_label (GTK_LABEL (priv->secondary_label)));
562 else
563 g_value_set_string (value, NULL);
564 break;
565 case PROP_SECONDARY_USE_MARKUP:
566 if (priv->has_secondary_text)
567 g_value_set_boolean (value,
568 gtk_label_get_use_markup (GTK_LABEL (priv->secondary_label)));
569 else
570 g_value_set_boolean (value, FALSE);
571 break;
572 case PROP_IMAGE:
573 g_value_set_object (value, priv->image);
574 break;
575 case PROP_MESSAGE_AREA:
576 g_value_set_object (value, priv->message_area);
577 break;
578 default:
579 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
580 break;
581 }
582 }
583
584 /**
585 * gtk_message_dialog_new:
586 * @parent: (allow-none): transient parent, or %NULL for none
587 * @flags: flags
588 * @type: type of message
589 * @buttons: set of buttons to use
590 * @message_format: (allow-none): printf()-style format string, or %NULL
591 * @...: arguments for @message_format
592 *
593 * Creates a new message dialog, which is a simple dialog with some text
594 * the user may want to see. When the user clicks a button a “response”
595 * signal is emitted with response IDs from #GtkResponseType. See
596 * #GtkDialog for more details.
597 *
598 * Returns: (transfer none): a new #GtkMessageDialog
599 */
600 GtkWidget*
gtk_message_dialog_new(GtkWindow * parent,GtkDialogFlags flags,GtkMessageType type,GtkButtonsType buttons,const gchar * message_format,...)601 gtk_message_dialog_new (GtkWindow *parent,
602 GtkDialogFlags flags,
603 GtkMessageType type,
604 GtkButtonsType buttons,
605 const gchar *message_format,
606 ...)
607 {
608 GtkWidget *widget;
609 GtkDialog *dialog;
610 gchar* msg = NULL;
611 va_list args;
612
613 g_return_val_if_fail (parent == NULL || GTK_IS_WINDOW (parent), NULL);
614
615 widget = g_object_new (GTK_TYPE_MESSAGE_DIALOG,
616 "use-header-bar", FALSE,
617 "message-type", type,
618 "buttons", buttons,
619 NULL);
620 dialog = GTK_DIALOG (widget);
621
622 if (message_format)
623 {
624 va_start (args, message_format);
625 msg = g_strdup_vprintf (message_format, args);
626 va_end (args);
627
628 gtk_label_set_text (GTK_LABEL (GTK_MESSAGE_DIALOG (widget)->priv->label), msg);
629
630 g_free (msg);
631 }
632
633 if (parent != NULL)
634 gtk_window_set_transient_for (GTK_WINDOW (widget), GTK_WINDOW (parent));
635
636 if (flags & GTK_DIALOG_MODAL)
637 gtk_window_set_modal (GTK_WINDOW (dialog), TRUE);
638
639 if (flags & GTK_DIALOG_DESTROY_WITH_PARENT)
640 gtk_window_set_destroy_with_parent (GTK_WINDOW (dialog), TRUE);
641
642 return widget;
643 }
644
645 /**
646 * gtk_message_dialog_new_with_markup:
647 * @parent: (allow-none): transient parent, or %NULL for none
648 * @flags: flags
649 * @type: type of message
650 * @buttons: set of buttons to use
651 * @message_format: (allow-none): printf()-style format string, or %NULL
652 * @...: arguments for @message_format
653 *
654 * Creates a new message dialog, which is a simple dialog with some text that
655 * is marked up with the [Pango text markup language][PangoMarkupFormat].
656 * When the user clicks a button a “response” signal is emitted with
657 * response IDs from #GtkResponseType. See #GtkDialog for more details.
658 *
659 * Special XML characters in the printf() arguments passed to this
660 * function will automatically be escaped as necessary.
661 * (See g_markup_printf_escaped() for how this is implemented.)
662 * Usually this is what you want, but if you have an existing
663 * Pango markup string that you want to use literally as the
664 * label, then you need to use gtk_message_dialog_set_markup()
665 * instead, since you can’t pass the markup string either
666 * as the format (it might contain “%” characters) or as a string
667 * argument.
668 * |[<!-- language="C" -->
669 * GtkWidget *dialog;
670 * GtkDialogFlags flags = GTK_DIALOG_DESTROY_WITH_PARENT;
671 * dialog = gtk_message_dialog_new (parent_window,
672 * flags,
673 * GTK_MESSAGE_ERROR,
674 * GTK_BUTTONS_CLOSE,
675 * NULL);
676 * gtk_message_dialog_set_markup (GTK_MESSAGE_DIALOG (dialog),
677 * markup);
678 * ]|
679 *
680 * Returns: a new #GtkMessageDialog
681 *
682 * Since: 2.4
683 **/
684 GtkWidget*
gtk_message_dialog_new_with_markup(GtkWindow * parent,GtkDialogFlags flags,GtkMessageType type,GtkButtonsType buttons,const gchar * message_format,...)685 gtk_message_dialog_new_with_markup (GtkWindow *parent,
686 GtkDialogFlags flags,
687 GtkMessageType type,
688 GtkButtonsType buttons,
689 const gchar *message_format,
690 ...)
691 {
692 GtkWidget *widget;
693 va_list args;
694 gchar *msg = NULL;
695
696 g_return_val_if_fail (parent == NULL || GTK_IS_WINDOW (parent), NULL);
697
698 widget = gtk_message_dialog_new (parent, flags, type, buttons, NULL);
699
700 if (message_format)
701 {
702 va_start (args, message_format);
703 msg = g_markup_vprintf_escaped (message_format, args);
704 va_end (args);
705
706 gtk_message_dialog_set_markup (GTK_MESSAGE_DIALOG (widget), msg);
707
708 g_free (msg);
709 }
710
711 return widget;
712 }
713
714 /**
715 * gtk_message_dialog_set_image:
716 * @dialog: a #GtkMessageDialog
717 * @image: the image
718 *
719 * Sets the dialog’s image to @image.
720 *
721 * Since: 2.10
722 * Deprecated: 3.12: Use #GtkDialog to create dialogs with images
723 **/
724 void
gtk_message_dialog_set_image(GtkMessageDialog * dialog,GtkWidget * image)725 gtk_message_dialog_set_image (GtkMessageDialog *dialog,
726 GtkWidget *image)
727 {
728 GtkMessageDialogPrivate *priv;
729 GtkWidget *parent;
730
731 g_return_if_fail (GTK_IS_MESSAGE_DIALOG (dialog));
732 g_return_if_fail (image == NULL || GTK_IS_WIDGET (image));
733
734 priv = dialog->priv;
735
736 if (priv->image)
737 gtk_widget_destroy (priv->image);
738
739 priv->image = image;
740
741 if (priv->image)
742 {
743 gtk_widget_set_halign (priv->image, GTK_ALIGN_CENTER);
744 gtk_widget_set_valign (priv->image, GTK_ALIGN_START);
745 parent = gtk_widget_get_parent (priv->message_area);
746 gtk_container_add (GTK_CONTAINER (parent), priv->image);
747 gtk_box_reorder_child (GTK_BOX (parent), priv->image, 0);
748 }
749
750 priv->message_type = GTK_MESSAGE_OTHER;
751
752 g_object_notify (G_OBJECT (dialog), "image");
753 g_object_notify (G_OBJECT (dialog), "message-type");
754 }
755
756 /**
757 * gtk_message_dialog_get_image:
758 * @dialog: a #GtkMessageDialog
759 *
760 * Gets the dialog’s image.
761 *
762 * Returns: (transfer none): the dialog’s image
763 *
764 * Since: 2.14
765 * Deprecated: 3.12: Use #GtkDialog for dialogs with images
766 **/
767 GtkWidget *
gtk_message_dialog_get_image(GtkMessageDialog * dialog)768 gtk_message_dialog_get_image (GtkMessageDialog *dialog)
769 {
770 g_return_val_if_fail (GTK_IS_MESSAGE_DIALOG (dialog), NULL);
771
772 return dialog->priv->image;
773 }
774
775 /**
776 * gtk_message_dialog_set_markup:
777 * @message_dialog: a #GtkMessageDialog
778 * @str: markup string (see [Pango markup format][PangoMarkupFormat])
779 *
780 * Sets the text of the message dialog to be @str, which is marked
781 * up with the [Pango text markup language][PangoMarkupFormat].
782 *
783 * Since: 2.4
784 **/
785 void
gtk_message_dialog_set_markup(GtkMessageDialog * message_dialog,const gchar * str)786 gtk_message_dialog_set_markup (GtkMessageDialog *message_dialog,
787 const gchar *str)
788 {
789 GtkMessageDialogPrivate *priv;
790
791 g_return_if_fail (GTK_IS_MESSAGE_DIALOG (message_dialog));
792
793 priv = message_dialog->priv;
794
795 priv->has_primary_markup = TRUE;
796 gtk_label_set_markup (GTK_LABEL (priv->label), str);
797 }
798
799 /**
800 * gtk_message_dialog_format_secondary_text:
801 * @message_dialog: a #GtkMessageDialog
802 * @message_format: (allow-none): printf()-style format string, or %NULL
803 * @...: arguments for @message_format
804 *
805 * Sets the secondary text of the message dialog to be @message_format
806 * (with printf()-style).
807 *
808 * Since: 2.6
809 */
810 void
gtk_message_dialog_format_secondary_text(GtkMessageDialog * message_dialog,const gchar * message_format,...)811 gtk_message_dialog_format_secondary_text (GtkMessageDialog *message_dialog,
812 const gchar *message_format,
813 ...)
814 {
815 va_list args;
816 gchar *msg = NULL;
817 GtkMessageDialogPrivate *priv;
818
819 g_return_if_fail (GTK_IS_MESSAGE_DIALOG (message_dialog));
820
821 priv = message_dialog->priv;
822
823 if (message_format)
824 {
825 priv->has_secondary_text = TRUE;
826
827 va_start (args, message_format);
828 msg = g_strdup_vprintf (message_format, args);
829 va_end (args);
830
831 gtk_widget_show (priv->secondary_label);
832 gtk_label_set_text (GTK_LABEL (priv->secondary_label), msg);
833
834 g_free (msg);
835 }
836 else
837 {
838 priv->has_secondary_text = FALSE;
839 gtk_widget_hide (priv->secondary_label);
840 }
841
842 setup_primary_label_font (message_dialog);
843 }
844
845 /**
846 * gtk_message_dialog_format_secondary_markup:
847 * @message_dialog: a #GtkMessageDialog
848 * @message_format: printf()-style markup string (see
849 [Pango markup format][PangoMarkupFormat]), or %NULL
850 * @...: arguments for @message_format
851 *
852 * Sets the secondary text of the message dialog to be @message_format (with
853 * printf()-style), which is marked up with the
854 * [Pango text markup language][PangoMarkupFormat].
855 *
856 * Due to an oversight, this function does not escape special XML characters
857 * like gtk_message_dialog_new_with_markup() does. Thus, if the arguments
858 * may contain special XML characters, you should use g_markup_printf_escaped()
859 * to escape it.
860
861 * |[<!-- language="C" -->
862 * gchar *msg;
863 *
864 * msg = g_markup_printf_escaped (message_format, ...);
865 * gtk_message_dialog_format_secondary_markup (message_dialog,
866 * "%s", msg);
867 * g_free (msg);
868 * ]|
869 *
870 * Since: 2.6
871 */
872 void
gtk_message_dialog_format_secondary_markup(GtkMessageDialog * message_dialog,const gchar * message_format,...)873 gtk_message_dialog_format_secondary_markup (GtkMessageDialog *message_dialog,
874 const gchar *message_format,
875 ...)
876 {
877 va_list args;
878 gchar *msg = NULL;
879 GtkMessageDialogPrivate *priv;
880
881 g_return_if_fail (GTK_IS_MESSAGE_DIALOG (message_dialog));
882
883 priv = message_dialog->priv;
884
885 if (message_format)
886 {
887 priv->has_secondary_text = TRUE;
888
889 va_start (args, message_format);
890 msg = g_strdup_vprintf (message_format, args);
891 va_end (args);
892
893 gtk_widget_show (priv->secondary_label);
894 gtk_label_set_markup (GTK_LABEL (priv->secondary_label), msg);
895
896 g_free (msg);
897 }
898 else
899 {
900 priv->has_secondary_text = FALSE;
901 gtk_widget_hide (priv->secondary_label);
902 }
903
904 setup_primary_label_font (message_dialog);
905 }
906
907 /**
908 * gtk_message_dialog_get_message_area:
909 * @message_dialog: a #GtkMessageDialog
910 *
911 * Returns the message area of the dialog. This is the box where the
912 * dialog’s primary and secondary labels are packed. You can add your
913 * own extra content to that box and it will appear below those labels.
914 * See gtk_dialog_get_content_area() for the corresponding
915 * function in the parent #GtkDialog.
916 *
917 * Returns: (transfer none): A #GtkBox corresponding to the
918 * “message area” in the @message_dialog.
919 *
920 * Since: 2.22
921 **/
922 GtkWidget *
gtk_message_dialog_get_message_area(GtkMessageDialog * message_dialog)923 gtk_message_dialog_get_message_area (GtkMessageDialog *message_dialog)
924 {
925 g_return_val_if_fail (GTK_IS_MESSAGE_DIALOG (message_dialog), NULL);
926
927 return message_dialog->priv->message_area;
928 }
929
930 static void
gtk_message_dialog_add_buttons(GtkMessageDialog * message_dialog,GtkButtonsType buttons)931 gtk_message_dialog_add_buttons (GtkMessageDialog* message_dialog,
932 GtkButtonsType buttons)
933 {
934 GtkDialog* dialog = GTK_DIALOG (message_dialog);
935
936 G_GNUC_BEGIN_IGNORE_DEPRECATIONS
937 switch (buttons)
938 {
939 case GTK_BUTTONS_NONE:
940 /* nothing */
941 break;
942
943 case GTK_BUTTONS_OK:
944 gtk_dialog_add_button (dialog, _("_OK"), GTK_RESPONSE_OK);
945 break;
946
947 case GTK_BUTTONS_CLOSE:
948 gtk_dialog_add_button (dialog, _("_Close"), GTK_RESPONSE_CLOSE);
949 break;
950
951 case GTK_BUTTONS_CANCEL:
952 gtk_dialog_add_button (dialog, _("_Cancel"), GTK_RESPONSE_CANCEL);
953 break;
954
955 case GTK_BUTTONS_YES_NO:
956 gtk_dialog_add_button (dialog, _("_No"), GTK_RESPONSE_NO);
957 gtk_dialog_add_button (dialog, _("_Yes"), GTK_RESPONSE_YES);
958 gtk_dialog_set_alternative_button_order (GTK_DIALOG (dialog),
959 GTK_RESPONSE_YES,
960 GTK_RESPONSE_NO,
961 -1);
962 break;
963
964 case GTK_BUTTONS_OK_CANCEL:
965 gtk_dialog_add_button (dialog, _("_Cancel"), GTK_RESPONSE_CANCEL);
966 gtk_dialog_add_button (dialog, _("_OK"), GTK_RESPONSE_OK);
967 gtk_dialog_set_alternative_button_order (GTK_DIALOG (dialog),
968 GTK_RESPONSE_OK,
969 GTK_RESPONSE_CANCEL,
970 -1);
971 break;
972
973 default:
974 g_warning ("Unknown GtkButtonsType");
975 break;
976 }
977 G_GNUC_END_IGNORE_DEPRECATIONS
978
979 g_object_notify (G_OBJECT (message_dialog), "buttons");
980 }
981
982 static void
gtk_message_dialog_style_updated(GtkWidget * widget)983 gtk_message_dialog_style_updated (GtkWidget *widget)
984 {
985 GtkMessageDialog *dialog = GTK_MESSAGE_DIALOG (widget);
986 GtkWidget *parent;
987 gint border_width;
988
989 parent = gtk_widget_get_parent (dialog->priv->message_area);
990
991 if (parent)
992 {
993 gtk_widget_style_get (widget, "message-border",
994 &border_width, NULL);
995
996 gtk_container_set_border_width (GTK_CONTAINER (parent),
997 MAX (0, border_width - 7));
998 }
999
1000 GTK_WIDGET_CLASS (gtk_message_dialog_parent_class)->style_updated (widget);
1001 }
1002