gtkmessagedialog.c 30.5 KB
Newer Older
1
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 2 -*- */
Cody Russell's avatar
Cody Russell committed
2
/* GTK - The GIMP Toolkit
3 4 5 6 7 8 9 10 11 12 13 14 15
 * Copyright (C) 2000 Red Hat, Inc.
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Library General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Library General Public License for more details.
 *
 * You should have received a copy of the GNU Library General Public
Javier Jardón's avatar
Javier Jardón committed
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 22 23 24 25
 * file for a list of people on the GTK+ Team.  See the ChangeLog
 * files for a list of changes.  These files are distributed with
 * GTK+ at ftp://ftp.gtk.org/pub/gtk/. 
 */

26
#include "config.h"
27

28 29
#include <string.h>

30
#include "gtkmessagedialog.h"
Matthias Clasen's avatar
Matthias Clasen committed
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 43 44 45 46
/**
 * SECTION:gtkmessagedialog
 * @Short_description: A convenient message window
 * @Title: GtkMessageDialog
 * @See_also:#GtkDialog
 *
47
 * #GtkMessageDialog presents a dialog with some message text. It’s simply a
48 49 50
 * convenience widget; you could construct the equivalent of #GtkMessageDialog
 * from #GtkDialog without too much effort, but #GtkMessageDialog saves typing.
 *
51 52 53 54
 * One difference from #GtkDialog is that #GtkMessageDialog sets the
 * #GtkWindow:skip-taskbar-hint property to %TRUE, so that the dialog is hidden
 * from the taskbar by default.
 *
55 56 57 58
 * The easiest way to do a modal message dialog is to use gtk_dialog_run(), though
 * you can also pass in the %GTK_DIALOG_MODAL flag, gtk_dialog_run() automatically
 * makes the dialog modal and waits for the user to respond to it. gtk_dialog_run()
 * returns when any dialog button is clicked.
59 60
 *
 * An example for using a modal dialog:
61
 * |[<!-- language="C" -->
62 63 64
 *  GtkDialogFlags flags = GTK_DIALOG_DESTROY_WITH_PARENT;
 *  dialog = gtk_message_dialog_new (parent_window,
 *                                   flags,
65 66
 *                                   GTK_MESSAGE_ERROR,
 *                                   GTK_BUTTONS_CLOSE,
67 68 69
 *                                   "Error reading “%s”: %s",
 *                                   filename,
 *                                   g_strerror (errno));
70 71
 *  gtk_dialog_run (GTK_DIALOG (dialog));
 *  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 79 80
 *  GtkDialogFlags flags = GTK_DIALOG_DESTROY_WITH_PARENT;
 *  dialog = gtk_message_dialog_new (parent_window,
 *                                   flags,
81 82
 *                                   GTK_MESSAGE_ERROR,
 *                                   GTK_BUTTONS_CLOSE,
83 84 85 86
 *                                   "Error reading “%s”: %s",
 *                                   filename,
 *                                   g_strerror (errno));
 *
87 88
 *  // Destroy the dialog when the user responds to it
 *  // (e.g. clicks a button)
89 90 91 92
 *
 *  g_signal_connect_swapped (dialog, "response",
 *                            G_CALLBACK (gtk_widget_destroy),
 *                            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 104 105 106 107 108 109 110
  GtkWidget     *image;
  GtkWidget     *label;
  GtkWidget     *message_area; /* vbox for the primary and secondary labels, and any extra content from the caller */
  GtkWidget     *secondary_label;

  guint          has_primary_markup : 1;
  guint          has_secondary_text : 1;
  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 117 118 119 120 121 122 123 124 125
static void gtk_message_dialog_set_property (GObject          *object,
					     guint             prop_id,
					     const GValue     *value,
					     GParamSpec       *pspec);
static void gtk_message_dialog_get_property (GObject          *object,
					     guint             prop_id,
					     GValue           *value,
					     GParamSpec       *pspec);
static void gtk_message_dialog_add_buttons  (GtkMessageDialog *message_dialog,
					     GtkButtonsType    buttons);
126
static void      gtk_message_dialog_buildable_interface_init     (GtkBuildableIface *iface);
127 128 129 130

enum {
  PROP_0,
  PROP_MESSAGE_TYPE,
131 132 133 134
  PROP_BUTTONS,
  PROP_TEXT,
  PROP_USE_MARKUP,
  PROP_SECONDARY_TEXT,
Matthias Clasen's avatar
Matthias Clasen committed
135
  PROP_SECONDARY_USE_MARKUP,
136 137
  PROP_IMAGE,
  PROP_MESSAGE_AREA
138 139
};

140
G_DEFINE_TYPE_WITH_CODE (GtkMessageDialog, gtk_message_dialog, GTK_TYPE_DIALOG,
141
                         G_ADD_PRIVATE (GtkMessageDialog)
142 143 144 145 146 147 148 149 150 151 152 153 154
                         G_IMPLEMENT_INTERFACE (GTK_TYPE_BUILDABLE,
                                                gtk_message_dialog_buildable_interface_init))

static GtkBuildableIface *parent_buildable_iface;

static void
gtk_message_dialog_buildable_interface_init (GtkBuildableIface *iface)
{
  parent_buildable_iface = g_type_interface_peek_parent (iface);
  iface->custom_tag_start = parent_buildable_iface->custom_tag_start;
  iface->custom_finished = parent_buildable_iface->custom_finished;
}

155 156 157
static void
gtk_message_dialog_class_init (GtkMessageDialogClass *class)
{
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 167
  gtk_widget_class_set_accessible_role (widget_class, ATK_ROLE_ALERT);

168
  gobject_class->constructed = gtk_message_dialog_constructed;
169 170
  gobject_class->set_property = gtk_message_dialog_set_property;
  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 175
                                                             P_("label border"),
                                                             P_("Width of border around the label in the message dialog"),
176 177
                                                             0,
                                                             G_MAXINT,
178
                                                             12,
179
                                                             GTK_PARAM_READABLE));
180

Matthias Clasen's avatar
Matthias Clasen committed
181 182 183
  /**
   * GtkMessageDialog:message-type:
   *
184
   * The type of the message.
Matthias Clasen's avatar
Matthias Clasen committed
185
   */
186 187
  g_object_class_install_property (gobject_class,
                                   PROP_MESSAGE_TYPE,
188
                                   g_param_spec_enum ("message-type",
189 190
						      P_("Message Type"),
						      P_("The type of message"),
191 192
						      GTK_TYPE_MESSAGE_TYPE,
                                                      GTK_MESSAGE_INFO,
193
                                                      GTK_PARAM_READWRITE|G_PARAM_CONSTRUCT|G_PARAM_EXPLICIT_NOTIFY));
194 195 196
  g_object_class_install_property (gobject_class,
                                   PROP_BUTTONS,
                                   g_param_spec_enum ("buttons",
197 198
						      P_("Message Buttons"),
						      P_("The buttons shown in the message dialog"),
199 200
						      GTK_TYPE_BUTTONS_TYPE,
                                                      GTK_BUTTONS_NONE,
201
                                                      GTK_PARAM_WRITABLE|G_PARAM_CONSTRUCT_ONLY));
202 203 204 205 206 207 208 209 210 211 212 213 214 215

  /**
   * GtkMessageDialog:text:
   * 
   * The primary text of the message dialog. If the dialog has 
   * a secondary text, this will appear as the title.
   *
   * Since: 2.10
   */
  g_object_class_install_property (gobject_class,
                                   PROP_TEXT,
                                   g_param_spec_string ("text",
                                                        P_("Text"),
                                                        P_("The primary text of the message dialog"),
216
                                                        "",
217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232
                                                        GTK_PARAM_READWRITE));

  /**
   * GtkMessageDialog:use-markup:
   * 
   * %TRUE if the primary text of the dialog includes Pango markup. 
   * See pango_parse_markup(). 
   *
   * Since: 2.10
   */
  g_object_class_install_property (gobject_class,
				   PROP_USE_MARKUP,
				   g_param_spec_boolean ("use-markup",
							 P_("Use Markup"),
							 P_("The primary text of the title includes Pango markup."),
							 FALSE,
233
							 GTK_PARAM_READWRITE|G_PARAM_EXPLICIT_NOTIFY));
234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263
  
  /**
   * GtkMessageDialog:secondary-text:
   * 
   * The secondary text of the message dialog. 
   *
   * Since: 2.10
   */
  g_object_class_install_property (gobject_class,
                                   PROP_SECONDARY_TEXT,
                                   g_param_spec_string ("secondary-text",
                                                        P_("Secondary Text"),
                                                        P_("The secondary text of the message dialog"),
                                                        NULL,
                                                        GTK_PARAM_READWRITE));

  /**
   * GtkMessageDialog:secondary-use-markup:
   * 
   * %TRUE if the secondary text of the dialog includes Pango markup. 
   * See pango_parse_markup(). 
   *
   * Since: 2.10
   */
  g_object_class_install_property (gobject_class,
				   PROP_SECONDARY_USE_MARKUP,
				   g_param_spec_boolean ("secondary-use-markup",
							 P_("Use Markup in secondary"),
							 P_("The secondary text includes Pango markup."),
							 FALSE,
264
							 GTK_PARAM_READWRITE|G_PARAM_EXPLICIT_NOTIFY));
265

Matthias Clasen's avatar
Matthias Clasen committed
266 267
  /**
   * GtkMessageDialog:image:
268
   *
Matthias Clasen's avatar
Matthias Clasen committed
269 270 271
   * The image for this dialog.
   *
   * Since: 2.10
272
   * Deprecated: 3.12: Use #GtkDialog to create dialogs with images
Matthias Clasen's avatar
Matthias Clasen committed
273 274 275 276 277 278 279
   */
  g_object_class_install_property (gobject_class,
                                   PROP_IMAGE,
                                   g_param_spec_object ("image",
                                                        P_("Image"),
                                                        P_("The image"),
                                                        GTK_TYPE_WIDGET,
280
                                                        GTK_PARAM_READWRITE|G_PARAM_DEPRECATED));
Matthias Clasen's avatar
Matthias Clasen committed
281

282
  /**
283
   * GtkMessageDialog:message-area:
284
   *
285
   * The #GtkBox that corresponds to the message area of this dialog.  See
286 287 288 289 290 291 292 293 294 295 296 297 298
   * gtk_message_dialog_get_message_area() for a detailed description of this
   * area.
   *
   * Since: 2.22
   */
  g_object_class_install_property (gobject_class,
				   PROP_MESSAGE_AREA,
				   g_param_spec_object ("message-area",
							P_("Message area"),
							P_("GtkVBox that holds the dialog's primary and secondary labels"),
							GTK_TYPE_WIDGET,
							GTK_PARAM_READABLE));

299
  /* Setup Composite data */
300
  gtk_widget_class_set_template_from_resource (widget_class, "/org/gtk/libgtk/ui/gtkmessagedialog.ui");
301 302 303
  gtk_widget_class_bind_template_child_private (widget_class, GtkMessageDialog, label);
  gtk_widget_class_bind_template_child_private (widget_class, GtkMessageDialog, secondary_label);
  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 309 310
}

static void
gtk_message_dialog_init (GtkMessageDialog *dialog)
{
311
  GtkMessageDialogPrivate *priv;
312
  GtkWidget *action_area;
313

314
  dialog->priv = gtk_message_dialog_get_instance_private (dialog);
315
  priv = dialog->priv;
316

317 318
  priv->has_primary_markup = FALSE;
  priv->has_secondary_text = FALSE;
319 320
  priv->has_primary_markup = FALSE;
  priv->has_secondary_text = FALSE;
321
  priv->message_type = GTK_MESSAGE_OTHER;
322

323
  gtk_widget_init_template (GTK_WIDGET (dialog));
324
  gtk_message_dialog_style_updated (GTK_WIDGET (dialog));
325 326 327 328
G_GNUC_BEGIN_IGNORE_DEPRECATIONS
  action_area = gtk_dialog_get_action_area (GTK_DIALOG (dialog));
G_GNUC_END_IGNORE_DEPRECATIONS
  gtk_button_box_set_layout (GTK_BUTTON_BOX (action_area), GTK_BUTTONBOX_EXPAND);
329 330
}

331 332 333
static void
setup_primary_label_font (GtkMessageDialog *dialog)
{
334
  GtkMessageDialogPrivate *priv = dialog->priv;
335

336
  if (!priv->has_primary_markup)
337
    {
338 339 340 341 342 343 344 345
      PangoAttrList *attributes;
      PangoAttribute *attr;

      attributes = pango_attr_list_new ();

      attr = pango_attr_weight_new (PANGO_WEIGHT_BOLD);
      pango_attr_list_insert (attributes, attr);

346 347 348 349 350
      if (priv->has_secondary_text)
        {
          attr = pango_attr_scale_new (PANGO_SCALE_LARGE);
          pango_attr_list_insert (attributes, attr);
        }
351 352 353 354 355 356 357 358

      gtk_label_set_attributes (GTK_LABEL (priv->label), attributes);
      pango_attr_list_unref (attributes);
    }
  else
    {
      /* unset the font settings */
      gtk_label_set_attributes (GTK_LABEL (priv->label), NULL);
359 360 361
    }
}

362 363 364 365
static void
setup_type (GtkMessageDialog *dialog,
	    GtkMessageType    type)
{
366
  GtkMessageDialogPrivate *priv = dialog->priv;
367
  const gchar *name = NULL;
Matthias Clasen's avatar
Matthias Clasen committed
368
  AtkObject *atk_obj;
369

370 371 372
  if (priv->message_type == type)
    return;

Matthias Clasen's avatar
Matthias Clasen committed
373 374
  priv->message_type = type;

375 376 377
  switch (type)
    {
    case GTK_MESSAGE_INFO:
378
      name = _("Information");
379 380 381
      break;

    case GTK_MESSAGE_QUESTION:
382
      name = _("Question");
383 384 385
      break;

    case GTK_MESSAGE_WARNING:
386
      name = _("Warning");
387
      break;
388

389
    case GTK_MESSAGE_ERROR:
390
      name = _("Error");
391
      break;
392

Matthias Clasen's avatar
Matthias Clasen committed
393 394 395
    case GTK_MESSAGE_OTHER:
      break;

396
    default:
397
      g_warning ("Unknown GtkMessageType %u", type);
398 399 400
      break;
    }

Matthias Clasen's avatar
Matthias Clasen committed
401 402 403 404
  atk_obj = gtk_widget_get_accessible (GTK_WIDGET (dialog));
  if (GTK_IS_ACCESSIBLE (atk_obj))
    {
      atk_object_set_role (atk_obj, ATK_ROLE_ALERT);
405 406
      if (name)
        atk_object_set_name (atk_obj, name);
Matthias Clasen's avatar
Matthias Clasen committed
407
    }
408 409

  g_object_notify (G_OBJECT (dialog), "message-type");
410 411
}

412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454
static void
update_title (GObject    *dialog,
              GParamSpec *pspec,
              GtkWidget  *label)
{
  const gchar *title;

  title = gtk_window_get_title (GTK_WINDOW (dialog));
  gtk_label_set_label (GTK_LABEL (label), title);
  gtk_widget_set_visible (label, title && title[0]);
}

static void
gtk_message_dialog_constructed (GObject *object)
{
  GtkMessageDialog *dialog = GTK_MESSAGE_DIALOG (object);
  gboolean use_header;

  G_OBJECT_CLASS (gtk_message_dialog_parent_class)->constructed (object);

  g_object_get (gtk_widget_get_settings (GTK_WIDGET (dialog)),
                "gtk-dialogs-use-header", &use_header,
                NULL);

  if (use_header)
    {
      GtkWidget *box;
      GtkWidget *label;

      box = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0);
      gtk_widget_show (box);
      gtk_widget_set_size_request (box, -1, 16);
      label = gtk_label_new ("");
      gtk_widget_set_margin_top (label, 6);
      gtk_widget_set_margin_bottom (label, 6);
      gtk_style_context_add_class (gtk_widget_get_style_context (label), "title");
      gtk_box_set_center_widget (GTK_BOX (box), label);
      g_signal_connect_object (dialog, "notify::title", G_CALLBACK (update_title), label, 0);

      gtk_window_set_titlebar (GTK_WINDOW (dialog), box);
    }
}

455 456 457 458 459 460
static void 
gtk_message_dialog_set_property (GObject      *object,
				 guint         prop_id,
				 const GValue *value,
				 GParamSpec   *pspec)
{
461
  GtkMessageDialog *dialog = GTK_MESSAGE_DIALOG (object);
462
  GtkMessageDialogPrivate *priv = dialog->priv;
463

464 465 466 467 468 469 470 471
  switch (prop_id)
    {
    case PROP_MESSAGE_TYPE:
      setup_type (dialog, g_value_get_enum (value));
      break;
    case PROP_BUTTONS:
      gtk_message_dialog_add_buttons (dialog, g_value_get_enum (value));
      break;
472 473
    case PROP_TEXT:
      if (priv->has_primary_markup)
474
	gtk_label_set_markup (GTK_LABEL (priv->label),
475 476
			      g_value_get_string (value));
      else
477
	gtk_label_set_text (GTK_LABEL (priv->label),
478 479 480
			    g_value_get_string (value));
      break;
    case PROP_USE_MARKUP:
481 482 483 484 485 486 487
      if (priv->has_primary_markup != g_value_get_boolean (value))
        {
          priv->has_primary_markup = g_value_get_boolean (value);
          gtk_label_set_use_markup (GTK_LABEL (priv->label), priv->has_primary_markup);
          g_object_notify_by_pspec (object, pspec);
        }
        setup_primary_label_font (dialog);
488 489 490 491
      break;
    case PROP_SECONDARY_TEXT:
      {
	const gchar *txt = g_value_get_string (value);
492

493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511
	if (gtk_label_get_use_markup (GTK_LABEL (priv->secondary_label)))
	  gtk_label_set_markup (GTK_LABEL (priv->secondary_label), txt);
	else
	  gtk_label_set_text (GTK_LABEL (priv->secondary_label), txt);

	if (txt)
	  {
	    priv->has_secondary_text = TRUE;
	    gtk_widget_show (priv->secondary_label);
	  }
	else
	  {
	    priv->has_secondary_text = FALSE;
	    gtk_widget_hide (priv->secondary_label);
	  }
	setup_primary_label_font (dialog);
      }
      break;
    case PROP_SECONDARY_USE_MARKUP:
512 513 514 515 516
      if (gtk_label_get_use_markup (GTK_LABEL (priv->secondary_label)) != g_value_get_boolean (value))
        {
          gtk_label_set_use_markup (GTK_LABEL (priv->secondary_label), g_value_get_boolean (value));
          g_object_notify_by_pspec (object, pspec);
        }
517
      break;
Matthias Clasen's avatar
Matthias Clasen committed
518
    case PROP_IMAGE:
519
G_GNUC_BEGIN_IGNORE_DEPRECATIONS
520
      gtk_message_dialog_set_image (dialog, g_value_get_object (value));
521
G_GNUC_END_IGNORE_DEPRECATIONS
Matthias Clasen's avatar
Matthias Clasen committed
522 523
      break;

524 525 526 527 528 529 530 531 532 533 534 535
    default:
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
      break;
    }
}

static void 
gtk_message_dialog_get_property (GObject     *object,
				 guint        prop_id,
				 GValue      *value,
				 GParamSpec  *pspec)
{
536
  GtkMessageDialog *dialog = GTK_MESSAGE_DIALOG (object);
537
  GtkMessageDialogPrivate *priv = dialog->priv;
538

539 540 541
  switch (prop_id)
    {
    case PROP_MESSAGE_TYPE:
Matthias Clasen's avatar
Matthias Clasen committed
542
      g_value_set_enum (value, (GtkMessageType) priv->message_type);
543
      break;
544
    case PROP_TEXT:
545
      g_value_set_string (value, gtk_label_get_label (GTK_LABEL (priv->label)));
546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563
      break;
    case PROP_USE_MARKUP:
      g_value_set_boolean (value, priv->has_primary_markup);
      break;
    case PROP_SECONDARY_TEXT:
      if (priv->has_secondary_text)
      g_value_set_string (value, 
			  gtk_label_get_label (GTK_LABEL (priv->secondary_label)));
      else
	g_value_set_string (value, NULL);
      break;
    case PROP_SECONDARY_USE_MARKUP:
      if (priv->has_secondary_text)
	g_value_set_boolean (value, 
			     gtk_label_get_use_markup (GTK_LABEL (priv->secondary_label)));
      else
	g_value_set_boolean (value, FALSE);
      break;
Matthias Clasen's avatar
Matthias Clasen committed
564
    case PROP_IMAGE:
565
      g_value_set_object (value, priv->image);
Matthias Clasen's avatar
Matthias Clasen committed
566
      break;
567 568 569
    case PROP_MESSAGE_AREA:
      g_value_set_object (value, priv->message_area);
      break;
570 571 572 573 574 575
    default:
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
      break;
    }
}

576 577
/**
 * gtk_message_dialog_new:
578
 * @parent: (allow-none): transient parent, or %NULL for none
579 580 581
 * @flags: flags
 * @type: type of message
 * @buttons: set of buttons to use
582
 * @message_format: (allow-none): printf()-style format string, or %NULL
Matthias Clasen's avatar
Matthias Clasen committed
583
 * @...: arguments for @message_format
584
 *
585 586
 * Creates a new message dialog, which is a simple dialog with some text
 * the user may want to see. When the user clicks a button a “response”
587 588
 * signal is emitted with response IDs from #GtkResponseType. See
 * #GtkDialog for more details.
589
 *
590
 * Returns: (transfer none): a new #GtkMessageDialog
Matthias Clasen's avatar
Matthias Clasen committed
591
 */
592 593 594 595 596 597 598 599 600 601
GtkWidget*
gtk_message_dialog_new (GtkWindow     *parent,
                        GtkDialogFlags flags,
                        GtkMessageType type,
                        GtkButtonsType buttons,
                        const gchar   *message_format,
                        ...)
{
  GtkWidget *widget;
  GtkDialog *dialog;
602
  gchar* msg = NULL;
603
  va_list args;
604 605 606

  g_return_val_if_fail (parent == NULL || GTK_IS_WINDOW (parent), NULL);

Manish Singh's avatar
Manish Singh committed
607
  widget = g_object_new (GTK_TYPE_MESSAGE_DIALOG,
608
                         "use-header-bar", FALSE,
609
			 "message-type", type,
Manish Singh's avatar
Manish Singh committed
610 611
			 "buttons", buttons,
			 NULL);
612 613 614 615 616
  dialog = GTK_DIALOG (widget);

  if (message_format)
    {
      va_start (args, message_format);
Manish Singh's avatar
Manish Singh committed
617
      msg = g_strdup_vprintf (message_format, args);
618
      va_end (args);
619

620
      gtk_label_set_text (GTK_LABEL (GTK_MESSAGE_DIALOG (widget)->priv->label), msg);
621

622 623 624 625
      g_free (msg);
    }

  if (parent != NULL)
626
    gtk_window_set_transient_for (GTK_WINDOW (widget), GTK_WINDOW (parent));
627 628 629 630 631 632
  
  if (flags & GTK_DIALOG_MODAL)
    gtk_window_set_modal (GTK_WINDOW (dialog), TRUE);

  if (flags & GTK_DIALOG_DESTROY_WITH_PARENT)
    gtk_window_set_destroy_with_parent (GTK_WINDOW (dialog), TRUE);
633

634 635 636
  return widget;
}

637 638
/**
 * gtk_message_dialog_new_with_markup:
Matthias Clasen's avatar
Matthias Clasen committed
639
 * @parent: (allow-none): transient parent, or %NULL for none
640 641 642
 * @flags: flags
 * @type: type of message
 * @buttons: set of buttons to use
643
 * @message_format: (allow-none): printf()-style format string, or %NULL
Matthias Clasen's avatar
Matthias Clasen committed
644 645
 * @...: arguments for @message_format
 *
646
 * Creates a new message dialog, which is a simple dialog with some text that
647
 * is marked up with the [Pango text markup language][PangoMarkupFormat].
648
 * When the user clicks a button a “response” signal is emitted with
649 650
 * response IDs from #GtkResponseType. See #GtkDialog for more details.
 *
651 652 653 654 655 656
 * Special XML characters in the printf() arguments passed to this
 * function will automatically be escaped as necessary.
 * (See g_markup_printf_escaped() for how this is implemented.)
 * Usually this is what you want, but if you have an existing
 * Pango markup string that you want to use literally as the
 * label, then you need to use gtk_message_dialog_set_markup()
657
 * instead, since you can’t pass the markup string either
658
 * as the format (it might contain “%” characters) or as a string
659
 * argument.
660
 * |[<!-- language="C" -->
661
 *  GtkWidget *dialog;
662 663 664
 *  GtkDialogFlags flags = GTK_DIALOG_DESTROY_WITH_PARENT;
 *  dialog = gtk_message_dialog_new (parent_window,
 *                                   flags,
665
 *                                   GTK_MESSAGE_ERROR,
666
 *                                   GTK_BUTTONS_CLOSE,
667 668 669
 *                                   NULL);
 *  gtk_message_dialog_set_markup (GTK_MESSAGE_DIALOG (dialog),
 *                                 markup);
Matthias Clasen's avatar
Matthias Clasen committed
670
 * ]|
671
 * 
672
 * Returns: a new #GtkMessageDialog
673 674 675 676 677 678 679 680 681 682 683 684 685
 *
 * Since: 2.4
 **/
GtkWidget*
gtk_message_dialog_new_with_markup (GtkWindow     *parent,
                                    GtkDialogFlags flags,
                                    GtkMessageType type,
                                    GtkButtonsType buttons,
                                    const gchar   *message_format,
                                    ...)
{
  GtkWidget *widget;
  va_list args;
686
  gchar *msg = NULL;
687 688 689

  g_return_val_if_fail (parent == NULL || GTK_IS_WINDOW (parent), NULL);

690
  widget = gtk_message_dialog_new (parent, flags, type, buttons, NULL);
691 692 693 694

  if (message_format)
    {
      va_start (args, message_format);
695
      msg = g_markup_vprintf_escaped (message_format, args);
696 697
      va_end (args);

698
      gtk_message_dialog_set_markup (GTK_MESSAGE_DIALOG (widget), msg);
699 700 701 702 703 704 705

      g_free (msg);
    }

  return widget;
}

Matthias Clasen's avatar
Matthias Clasen committed
706 707 708 709 710
/**
 * gtk_message_dialog_set_image:
 * @dialog: a #GtkMessageDialog
 * @image: the image
 * 
711
 * Sets the dialog’s image to @image.
Matthias Clasen's avatar
Matthias Clasen committed
712 713
 *
 * Since: 2.10
714
 * Deprecated: 3.12: Use #GtkDialog to create dialogs with images
Matthias Clasen's avatar
Matthias Clasen committed
715 716 717 718 719
 **/
void
gtk_message_dialog_set_image (GtkMessageDialog *dialog,
			      GtkWidget        *image)
{
720
  GtkMessageDialogPrivate *priv;
Matthias Clasen's avatar
Matthias Clasen committed
721 722 723
  GtkWidget *parent;

  g_return_if_fail (GTK_IS_MESSAGE_DIALOG (dialog));
724 725
  g_return_if_fail (image == NULL || GTK_IS_WIDGET (image));

726
  priv = dialog->priv;
727 728 729
  
  if (priv->image)
    gtk_widget_destroy (priv->image);
730

731 732 733 734 735 736 737 738 739
  priv->image = image;
 
  if (priv->image)
    { 
      gtk_widget_set_halign (priv->image, GTK_ALIGN_CENTER);
      gtk_widget_set_valign (priv->image, GTK_ALIGN_START);
      parent = gtk_widget_get_parent (priv->message_area);
      gtk_container_add (GTK_CONTAINER (parent), priv->image);
      gtk_box_reorder_child (GTK_BOX (parent), priv->image, 0);
740
    }
Matthias Clasen's avatar
Matthias Clasen committed
741 742

  priv->message_type = GTK_MESSAGE_OTHER;
743

Matthias Clasen's avatar
Matthias Clasen committed
744
  g_object_notify (G_OBJECT (dialog), "image");
745
  g_object_notify (G_OBJECT (dialog), "message-type");
Matthias Clasen's avatar
Matthias Clasen committed
746 747
}

748 749 750 751
/**
 * gtk_message_dialog_get_image:
 * @dialog: a #GtkMessageDialog
 *
752
 * Gets the dialog’s image.
Matthias Clasen's avatar
Matthias Clasen committed
753
 *
754
 * Returns: (transfer none): the dialog’s image
755 756
 *
 * Since: 2.14
757
 * Deprecated: 3.12: Use #GtkDialog for dialogs with images
758 759 760 761
 **/
GtkWidget *
gtk_message_dialog_get_image (GtkMessageDialog *dialog)
{
762
  g_return_val_if_fail (GTK_IS_MESSAGE_DIALOG (dialog), NULL);
763

764
  return dialog->priv->image;
765 766
}

767 768 769
/**
 * gtk_message_dialog_set_markup:
 * @message_dialog: a #GtkMessageDialog
770
 * @str: markup string (see [Pango markup format][PangoMarkupFormat])
771 772
 * 
 * Sets the text of the message dialog to be @str, which is marked
773
 * up with the [Pango text markup language][PangoMarkupFormat].
774 775 776 777 778
 *
 * Since: 2.4
 **/
void
gtk_message_dialog_set_markup (GtkMessageDialog *message_dialog,
779
                               const gchar      *str)
780
{
781
  GtkMessageDialogPrivate *priv;
782

783
  g_return_if_fail (GTK_IS_MESSAGE_DIALOG (message_dialog));
784

785 786
  priv = message_dialog->priv;

787
  priv->has_primary_markup = TRUE;
788
  gtk_label_set_markup (GTK_LABEL (priv->label), str);
789 790
}

791 792 793
/**
 * gtk_message_dialog_format_secondary_text:
 * @message_dialog: a #GtkMessageDialog
794
 * @message_format: (allow-none): printf()-style format string, or %NULL
Matthias Clasen's avatar
Matthias Clasen committed
795 796 797
 * @...: arguments for @message_format
 *
 * Sets the secondary text of the message dialog to be @message_format
798 799 800
 * (with printf()-style).
 *
 * Since: 2.6
Matthias Clasen's avatar
Matthias Clasen committed
801
 */
802 803 804 805 806 807 808
void
gtk_message_dialog_format_secondary_text (GtkMessageDialog *message_dialog,
                                          const gchar      *message_format,
                                          ...)
{
  va_list args;
  gchar *msg = NULL;
809
  GtkMessageDialogPrivate *priv;
810 811 812

  g_return_if_fail (GTK_IS_MESSAGE_DIALOG (message_dialog));

813
  priv = message_dialog->priv;
814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839

  if (message_format)
    {
      priv->has_secondary_text = TRUE;

      va_start (args, message_format);
      msg = g_strdup_vprintf (message_format, args);
      va_end (args);

      gtk_widget_show (priv->secondary_label);
      gtk_label_set_text (GTK_LABEL (priv->secondary_label), msg);

      g_free (msg);
    }
  else
    {
      priv->has_secondary_text = FALSE;
      gtk_widget_hide (priv->secondary_label);
    }

  setup_primary_label_font (message_dialog);
}

/**
 * gtk_message_dialog_format_secondary_markup:
 * @message_dialog: a #GtkMessageDialog
Matthias Clasen's avatar
Matthias Clasen committed
840
 * @message_format: printf()-style markup string (see
841
     [Pango markup format][PangoMarkupFormat]), or %NULL
Matthias Clasen's avatar
Matthias Clasen committed
842 843 844 845
 * @...: arguments for @message_format
 *
 * Sets the secondary text of the message dialog to be @message_format (with
 * printf()-style), which is marked up with the
846
 * [Pango text markup language][PangoMarkupFormat].
847
 *
848
 * Due to an oversight, this function does not escape special XML characters
Matthias Clasen's avatar
Matthias Clasen committed
849
 * like gtk_message_dialog_new_with_markup() does. Thus, if the arguments
850 851
 * may contain special XML characters, you should use g_markup_printf_escaped()
 * to escape it.
Matthias Clasen's avatar
Matthias Clasen committed
852

853
 * |[<!-- language="C" -->
854
 * gchar *msg;
Matthias Clasen's avatar
Matthias Clasen committed
855
 *
856
 * msg = g_markup_printf_escaped (message_format, ...);
857 858
 * gtk_message_dialog_format_secondary_markup (message_dialog,
 *                                             "%s", msg);
859
 * g_free (msg);
860
 * ]|
861
 *
862
 * Since: 2.6
Matthias Clasen's avatar
Matthias Clasen committed
863
 */
864 865 866 867 868 869 870
void
gtk_message_dialog_format_secondary_markup (GtkMessageDialog *message_dialog,
                                            const gchar      *message_format,
                                            ...)
{
  va_list args;
  gchar *msg = NULL;
871
  GtkMessageDialogPrivate *priv;
872 873 874

  g_return_if_fail (GTK_IS_MESSAGE_DIALOG (message_dialog));

875
  priv = message_dialog->priv;
876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898

  if (message_format)
    {
      priv->has_secondary_text = TRUE;

      va_start (args, message_format);
      msg = g_strdup_vprintf (message_format, args);
      va_end (args);

      gtk_widget_show (priv->secondary_label);
      gtk_label_set_markup (GTK_LABEL (priv->secondary_label), msg);

      g_free (msg);
    }
  else
    {
      priv->has_secondary_text = FALSE;
      gtk_widget_hide (priv->secondary_label);
    }

  setup_primary_label_font (message_dialog);
}

899 900 901 902
/**
 * gtk_message_dialog_get_message_area:
 * @message_dialog: a #GtkMessageDialog
 *
903
 * Returns the message area of the dialog. This is the box where the
904
 * dialog’s primary and secondary labels are packed. You can add your
905 906
 * own extra content to that box and it will appear below those labels.
 * See gtk_dialog_get_content_area() for the corresponding
907 908
 * function in the parent #GtkDialog.
 *
909
 * Returns: (transfer none): A #GtkVBox corresponding to the
910
 *     “message area” in the @message_dialog.
911 912 913 914 915 916 917 918
 *
 * Since: 2.22
 **/
GtkWidget *
gtk_message_dialog_get_message_area (GtkMessageDialog *message_dialog)
{
  g_return_val_if_fail (GTK_IS_MESSAGE_DIALOG (message_dialog), NULL);

919
  return message_dialog->priv->message_area;
920 921
}

922 923 924 925 926 927
static void
gtk_message_dialog_add_buttons (GtkMessageDialog* message_dialog,
				GtkButtonsType buttons)
{
  GtkDialog* dialog = GTK_DIALOG (message_dialog);

928
G_GNUC_BEGIN_IGNORE_DEPRECATIONS
929 930 931 932 933 934 935
  switch (buttons)
    {
    case GTK_BUTTONS_NONE:
      /* nothing */
      break;

    case GTK_BUTTONS_OK:
936
      gtk_dialog_add_button (dialog, _("_OK"), GTK_RESPONSE_OK);
937 938 939
      break;

    case GTK_BUTTONS_CLOSE:
940
      gtk_dialog_add_button (dialog, _("_Close"), GTK_RESPONSE_CLOSE);
941 942 943
      break;

    case GTK_BUTTONS_CANCEL:
944
      gtk_dialog_add_button (dialog, _("_Cancel"), GTK_RESPONSE_CANCEL);
945 946 947
      break;

    case GTK_BUTTONS_YES_NO:
948 949
      gtk_dialog_add_button (dialog, _("_No"), GTK_RESPONSE_NO);
      gtk_dialog_add_button (dialog, _("_Yes"), GTK_RESPONSE_YES);
950 951 952 953
      gtk_dialog_set_alternative_button_order (GTK_DIALOG (dialog),
					       GTK_RESPONSE_YES,
					       GTK_RESPONSE_NO,
					       -1);
954 955 956
      break;

    case GTK_BUTTONS_OK_CANCEL:
957 958
      gtk_dialog_add_button (dialog, _("_Cancel"), GTK_RESPONSE_CANCEL);
      gtk_dialog_add_button (dialog, _("_OK"), GTK_RESPONSE_OK);
959 960 961 962
      gtk_dialog_set_alternative_button_order (GTK_DIALOG (dialog),
					       GTK_RESPONSE_OK,
					       GTK_RESPONSE_CANCEL,
					       -1);
963 964 965 966 967
      break;
      
    default:
      g_warning ("Unknown GtkButtonsType");
      break;
968
    } 
969
G_GNUC_END_IGNORE_DEPRECATIONS
970 971

  g_object_notify (G_OBJECT (message_dialog), "buttons");
972
}
973 974

static void
975
gtk_message_dialog_style_updated (GtkWidget *widget)
976
{
977 978 979
  GtkMessageDialog *dialog = GTK_MESSAGE_DIALOG (widget);
  GtkWidget *parent;
  gint border_width;
980

981
  parent = gtk_widget_get_parent (dialog->priv->message_area);
982 983 984

  if (parent)
    {
985
      gtk_widget_style_get (widget, "message-border",
986
                            &border_width, NULL);
987

988
      gtk_container_set_border_width (GTK_CONTAINER (parent),
989
                                      MAX (0, border_width - 7));
990 991
    }

992
  GTK_WIDGET_CLASS (gtk_message_dialog_parent_class)->style_updated (widget);
993
}