gtkactiongroup.c 39.3 KB
Newer Older
1
/*
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 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
 * Copyright (C) 1998, 1999 Red Hat, Inc.
 * All rights reserved.
 *
 * 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
 * License along with the Gnome Library; see the file COPYING.LIB.  If not,
 * write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
 * Boston, MA 02111-1307, USA.
 */

/*
 * Author: James Henstridge <james@daa.com.au>
 *
 * Modified by the GTK+ Team and others 2003.  See the AUTHORS
 * 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/. 
 */

31
#include "config.h"
32
#include <string.h>
33 34

#include "gtkactiongroup.h"
35
#include "gtkbuildable.h"
36
#include "gtkiconfactory.h"
Matthias Clasen's avatar
Matthias Clasen committed
37
#include "gtkicontheme.h"
38
#include "gtkstock.h"
39 40 41
#include "gtktoggleaction.h"
#include "gtkradioaction.h"
#include "gtkaccelmap.h"
42
#include "gtkmarshalers.h"
43
#include "gtkbuilderprivate.h"
44
#include "gtkprivate.h"
45
#include "gtkintl.h"
46
#include "gtkalias.h"
47 48 49 50 51

#define GTK_ACTION_GROUP_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), GTK_TYPE_ACTION_GROUP, GtkActionGroupPrivate))

struct _GtkActionGroupPrivate 
{
52
  gchar           *name;
53 54
  gboolean	   sensitive;
  gboolean	   visible;
55 56 57 58
  GHashTable      *actions;

  GtkTranslateFunc translate_func;
  gpointer         translate_data;
59
  GDestroyNotify   translate_notify;
60 61
};

62 63 64 65 66 67 68 69 70
enum 
{
  CONNECT_PROXY,
  DISCONNECT_PROXY,
  PRE_ACTIVATE,
  POST_ACTIVATE,
  LAST_SIGNAL
};

71 72 73
enum 
{
  PROP_0,
74 75 76
  PROP_NAME,
  PROP_SENSITIVE,
  PROP_VISIBLE
77 78
};

79 80 81
static void       gtk_action_group_init            (GtkActionGroup      *self);
static void       gtk_action_group_class_init      (GtkActionGroupClass *class);
static void       gtk_action_group_finalize        (GObject             *object);
82 83 84 85 86 87 88 89
static void       gtk_action_group_set_property    (GObject             *object,
						    guint                prop_id,
						    const GValue        *value,
						    GParamSpec          *pspec);
static void       gtk_action_group_get_property    (GObject             *object,
						    guint                prop_id,
						    GValue              *value,
						    GParamSpec          *pspec);
90 91 92
static GtkAction *gtk_action_group_real_get_action (GtkActionGroup      *self,
						    const gchar         *name);

93 94
/* GtkBuildable */
static void gtk_action_group_buildable_init (GtkBuildableIface *iface);
95 96 97 98
static void gtk_action_group_buildable_add_child (GtkBuildable  *buildable,
						  GtkBuilder    *builder,
						  GObject       *child,
						  const gchar   *type);
99 100 101
static void gtk_action_group_buildable_set_name (GtkBuildable *buildable,
						 const gchar  *name);
static const gchar* gtk_action_group_buildable_get_name (GtkBuildable *buildable);
102 103 104 105 106 107 108 109 110 111 112
static gboolean gtk_action_group_buildable_custom_tag_start (GtkBuildable     *buildable,
							     GtkBuilder       *builder,
							     GObject          *child,
							     const gchar      *tagname,
							     GMarkupParser    *parser,
							     gpointer         *data);
static void gtk_action_group_buildable_custom_tag_end (GtkBuildable *buildable,
						       GtkBuilder   *builder,
						       GObject      *child,
						       const gchar  *tagname,
						       gpointer     *user_data);
113 114 115 116 117 118 119 120

GType
gtk_action_group_get_type (void)
{
  static GType type = 0;

  if (!type)
    {
121
      const GTypeInfo type_info =
122 123 124 125 126 127 128 129 130 131 132 133
      {
        sizeof (GtkActionGroupClass),
	NULL,           /* base_init */
        NULL,           /* base_finalize */
        (GClassInitFunc) gtk_action_group_class_init,
        NULL,           /* class_finalize */
        NULL,           /* class_data */
        sizeof (GtkActionGroup),
        0, /* n_preallocs */
        (GInstanceInitFunc) gtk_action_group_init,
      };

134 135 136 137 138 139 140
      static const GInterfaceInfo buildable_info =
      {
	(GInterfaceInitFunc) gtk_action_group_buildable_init,
	NULL,
	NULL
      };

141
      type = g_type_register_static (G_TYPE_OBJECT, I_("GtkActionGroup"),
142 143
				     &type_info, 0);

144 145 146 147
      g_type_add_interface_static (type,
				   GTK_TYPE_BUILDABLE,
				   &buildable_info);
    }
148 149 150 151
  return type;
}

static GObjectClass *parent_class = NULL;
152
static guint         action_group_signals[LAST_SIGNAL] = { 0 };
153 154 155 156 157 158 159 160 161 162

static void
gtk_action_group_class_init (GtkActionGroupClass *klass)
{
  GObjectClass *gobject_class;

  gobject_class = G_OBJECT_CLASS (klass);
  parent_class = g_type_class_peek_parent (klass);

  gobject_class->finalize = gtk_action_group_finalize;
163 164
  gobject_class->set_property = gtk_action_group_set_property;
  gobject_class->get_property = gtk_action_group_get_property;
165 166
  klass->get_action = gtk_action_group_real_get_action;

167 168 169
  g_object_class_install_property (gobject_class,
				   PROP_NAME,
				   g_param_spec_string ("name",
170 171
							P_("Name"),
							P_("A name for the action group."),
172
							NULL,
173
							GTK_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
174 175 176
  g_object_class_install_property (gobject_class,
				   PROP_SENSITIVE,
				   g_param_spec_boolean ("sensitive",
177 178
							 P_("Sensitive"),
							 P_("Whether the action group is enabled."),
179
							 TRUE,
180
							 GTK_PARAM_READWRITE));
181 182 183
  g_object_class_install_property (gobject_class,
				   PROP_VISIBLE,
				   g_param_spec_boolean ("visible",
184 185
							 P_("Visible"),
							 P_("Whether the action group is visible."),
186
							 TRUE,
187
							 GTK_PARAM_READWRITE));
188 189

  /**
190
   * GtkActionGroup::connect-proxy:
191 192 193 194
   * @action_group: the group
   * @action: the action
   * @proxy: the proxy
   *
195
   * The ::connect-proxy signal is emitted after connecting a proxy to 
196 197 198 199 200 201 202 203 204 205 206 207 208 209
   * an action in the group. Note that the proxy may have been connected 
   * to a different action before.
   *
   * This is intended for simple customizations for which a custom action
   * class would be too clumsy, e.g. showing tooltips for menuitems in the
   * statusbar.
   *
   * #GtkUIManager proxies the signal and provides global notification 
   * just before any action is connected to a proxy, which is probably more
   * convenient to use.
   *
   * Since: 2.4
   */
  action_group_signals[CONNECT_PROXY] =
210
    g_signal_new (I_("connect-proxy"),
211 212 213 214 215 216 217
		  G_OBJECT_CLASS_TYPE (klass),
		  0, 0, NULL, NULL,
		  _gtk_marshal_VOID__OBJECT_OBJECT,
		  G_TYPE_NONE, 2,
		  GTK_TYPE_ACTION, GTK_TYPE_WIDGET);

  /**
218
   * GtkActionGroup::disconnect-proxy:
219 220 221 222
   * @action_group: the group
   * @action: the action
   * @proxy: the proxy
   *
223
   * The ::disconnect-proxy signal is emitted after disconnecting a proxy 
224 225 226 227 228 229 230 231 232
   * from an action in the group. 
   *
   * #GtkUIManager proxies the signal and provides global notification 
   * just before any action is connected to a proxy, which is probably more
   * convenient to use.
   *
   * Since: 2.4
   */
  action_group_signals[DISCONNECT_PROXY] =
233
    g_signal_new (I_("disconnect-proxy"),
234 235 236 237 238 239 240
		  G_OBJECT_CLASS_TYPE (klass),
		  0, 0, NULL, NULL,
		  _gtk_marshal_VOID__OBJECT_OBJECT,
		  G_TYPE_NONE, 2, 
		  GTK_TYPE_ACTION, GTK_TYPE_WIDGET);

  /**
241
   * GtkActionGroup::pre-activate:
242 243 244
   * @action_group: the group
   * @action: the action
   *
245
   * The ::pre-activate signal is emitted just before the @action in the
246 247 248 249 250 251 252 253
   * @action_group is activated
   *
   * This is intended for #GtkUIManager to proxy the signal and provide global
   * notification just before any action is activated.
   *
   * Since: 2.4
   */
  action_group_signals[PRE_ACTIVATE] =
254
    g_signal_new (I_("pre-activate"),
255 256 257 258 259 260 261
		  G_OBJECT_CLASS_TYPE (klass),
		  0, 0, NULL, NULL,
		  _gtk_marshal_VOID__OBJECT,
		  G_TYPE_NONE, 1, 
		  GTK_TYPE_ACTION);

  /**
262
   * GtkActionGroup::post-activate:
263 264 265
   * @action_group: the group
   * @action: the action
   *
266
   * The ::post-activate signal is emitted just after the @action in the
267 268 269 270 271 272 273 274
   * @action_group is activated
   *
   * This is intended for #GtkUIManager to proxy the signal and provide global
   * notification just after any action is activated.
   *
   * Since: 2.4
   */
  action_group_signals[POST_ACTIVATE] =
275
    g_signal_new (I_("post-activate"),
276 277 278 279 280 281
		  G_OBJECT_CLASS_TYPE (klass),
		  0, 0, NULL, NULL,
		  _gtk_marshal_VOID__OBJECT,
		  G_TYPE_NONE, 1, 
		  GTK_TYPE_ACTION);

282 283 284
  g_type_class_add_private (gobject_class, sizeof (GtkActionGroupPrivate));
}

Matthias Clasen's avatar
Matthias Clasen committed
285 286 287 288

static void 
remove_action (GtkAction *action) 
{
289
  g_object_set (action, I_("action-group"), NULL, NULL);
Matthias Clasen's avatar
Matthias Clasen committed
290 291 292
  g_object_unref (action);
}

293 294 295
static void
gtk_action_group_init (GtkActionGroup *self)
{
Tim Janik's avatar
Tim Janik committed
296 297 298 299 300 301 302 303 304 305 306 307 308
  GtkActionGroupPrivate *private;

  private = GTK_ACTION_GROUP_GET_PRIVATE (self);

  private->name = NULL;
  private->sensitive = TRUE;
  private->visible = TRUE;
  private->actions = g_hash_table_new_full (g_str_hash, g_str_equal,
                                            NULL,
                                            (GDestroyNotify) remove_action);
  private->translate_func = NULL;
  private->translate_data = NULL;
  private->translate_notify = NULL;
309 310
}

311 312 313
static void
gtk_action_group_buildable_init (GtkBuildableIface *iface)
{
314
  iface->add_child = gtk_action_group_buildable_add_child;
315 316
  iface->set_name = gtk_action_group_buildable_set_name;
  iface->get_name = gtk_action_group_buildable_get_name;
317 318
  iface->custom_tag_start = gtk_action_group_buildable_custom_tag_start;
  iface->custom_tag_end = gtk_action_group_buildable_custom_tag_end;
319 320 321
}

static void
322 323 324 325
gtk_action_group_buildable_add_child (GtkBuildable  *buildable,
				      GtkBuilder    *builder,
				      GObject       *child,
				      const gchar   *type)
326
{
327 328
  gtk_action_group_add_action_with_accel (GTK_ACTION_GROUP (buildable),
					  GTK_ACTION (child), NULL);
329 330 331 332 333 334 335
}

static void
gtk_action_group_buildable_set_name (GtkBuildable *buildable,
				     const gchar  *name)
{
  GtkActionGroup *self = GTK_ACTION_GROUP (buildable);
Tim Janik's avatar
Tim Janik committed
336 337 338
  GtkActionGroupPrivate *private = GTK_ACTION_GROUP_GET_PRIVATE (self);

  private->name = g_strdup (name);
339 340 341 342 343 344
}

static const gchar *
gtk_action_group_buildable_get_name (GtkBuildable *buildable)
{
  GtkActionGroup *self = GTK_ACTION_GROUP (buildable);
Tim Janik's avatar
Tim Janik committed
345 346
  GtkActionGroupPrivate *private = GTK_ACTION_GROUP_GET_PRIVATE (self);
  return private->name;
347 348
}

349
typedef struct {
350 351 352
  GObject         *child;
  guint            key;
  GdkModifierType  modifiers;
353 354 355 356 357 358 359 360 361 362 363 364
} AcceleratorParserData;

static void
accelerator_start_element (GMarkupParseContext *context,
			   const gchar         *element_name,
			   const gchar        **names,
			   const gchar        **values,
			   gpointer             user_data,
			   GError             **error)
{
  gint i;
  guint key = 0;
365
  GdkModifierType modifiers = 0;
366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390
  AcceleratorParserData *parser_data = (AcceleratorParserData*)user_data;

  if (strcmp (element_name, "accelerator") != 0)
    g_warning ("Unknown <accelerator> tag: %s", element_name);

  for (i = 0; names[i]; i++)
    {
      if (strcmp (names[i], "key") == 0)
	key = gdk_keyval_from_name (values[i]);
      else if (strcmp (names[i], "modifiers") == 0)
	{
	  if (!_gtk_builder_flags_from_string (GDK_TYPE_MODIFIER_TYPE,
					       values[i],
					       &modifiers,
					       error))
	      return;
	}
    }

  if (key == 0)
    {
      g_warning ("<accelerator> requires a key attribute");
      return;
    }
  parser_data->key = key;
391
  parser_data->modifiers = modifiers;
392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432
}

static const GMarkupParser accelerator_parser =
  {
    accelerator_start_element
  };

static gboolean
gtk_action_group_buildable_custom_tag_start (GtkBuildable     *buildable,
					     GtkBuilder       *builder,
					     GObject          *child,
					     const gchar      *tagname,
					     GMarkupParser    *parser,
					     gpointer         *user_data)
{
  AcceleratorParserData *parser_data;

  if (child && strcmp (tagname, "accelerator") == 0)
    {
      parser_data = g_slice_new0 (AcceleratorParserData);
      parser_data->child = child;
      *user_data = parser_data;
      *parser = accelerator_parser;

      return TRUE;
    }
  return FALSE;
}

static void
gtk_action_group_buildable_custom_tag_end (GtkBuildable *buildable,
					   GtkBuilder   *builder,
					   GObject      *child,
					   const gchar  *tagname,
					   gpointer     *user_data)
{
  AcceleratorParserData *data;
  
  if (strcmp (tagname, "accelerator") == 0)
    {
      GtkActionGroup *action_group;
Tim Janik's avatar
Tim Janik committed
433
      GtkActionGroupPrivate *private;
434 435 436 437 438
      GtkAction *action;
      gchar *accel_path;
      
      data = (AcceleratorParserData*)user_data;
      action_group = GTK_ACTION_GROUP (buildable);
Tim Janik's avatar
Tim Janik committed
439
      private = GTK_ACTION_GROUP_GET_PRIVATE (action_group);
440 441 442
      action = GTK_ACTION (child);
	
      accel_path = g_strconcat ("<Actions>/",
Tim Janik's avatar
Tim Janik committed
443
				private->name, "/",
444 445 446 447 448 449 450 451 452 453 454 455 456 457
				gtk_action_get_name (action), NULL);

      if (gtk_accel_map_lookup_entry (accel_path, NULL))
	gtk_accel_map_change_entry (accel_path, data->key, data->modifiers, TRUE);
      else
	gtk_accel_map_add_entry (accel_path, data->key, data->modifiers);

      gtk_action_set_accel_path (action, accel_path);
      
      g_free (accel_path);
      g_slice_free (AcceleratorParserData, data);
    }
}

458 459
/**
 * gtk_action_group_new:
Matthias Clasen's avatar
Matthias Clasen committed
460
 * @name: the name of the action group.
461
 *
Matthias Clasen's avatar
Matthias Clasen committed
462 463 464
 * Creates a new #GtkActionGroup object. The name of the action group
 * is used when associating <link linkend="Action-Accel">keybindings</link> 
 * with the actions.
465 466 467 468 469 470 471 472 473
 *
 * Returns: the new #GtkActionGroup
 *
 * Since: 2.4
 */
GtkActionGroup *
gtk_action_group_new (const gchar *name)
{
  GtkActionGroup *self;
Tim Janik's avatar
Tim Janik committed
474
  GtkActionGroupPrivate *private;
475 476

  self = g_object_new (GTK_TYPE_ACTION_GROUP, NULL);
Tim Janik's avatar
Tim Janik committed
477 478
  private = GTK_ACTION_GROUP_GET_PRIVATE (self);
  private->name = g_strdup (name);
479 480 481 482 483 484 485 486

  return self;
}

static void
gtk_action_group_finalize (GObject *object)
{
  GtkActionGroup *self;
Tim Janik's avatar
Tim Janik committed
487
  GtkActionGroupPrivate *private;
488 489

  self = GTK_ACTION_GROUP (object);
Tim Janik's avatar
Tim Janik committed
490
  private = GTK_ACTION_GROUP_GET_PRIVATE (self);
491

Tim Janik's avatar
Tim Janik committed
492 493
  g_free (private->name);
  private->name = NULL;
494

Tim Janik's avatar
Tim Janik committed
495 496
  g_hash_table_destroy (private->actions);
  private->actions = NULL;
497

Tim Janik's avatar
Tim Janik committed
498 499
  if (private->translate_notify)
    private->translate_notify (private->translate_data);
500

501
  parent_class->finalize (object);
502 503
}

504 505 506 507 508 509 510
static void
gtk_action_group_set_property (GObject         *object,
			       guint            prop_id,
			       const GValue    *value,
			       GParamSpec      *pspec)
{
  GtkActionGroup *self;
Tim Janik's avatar
Tim Janik committed
511
  GtkActionGroupPrivate *private;
512 513 514
  gchar *tmp;
  
  self = GTK_ACTION_GROUP (object);
Tim Janik's avatar
Tim Janik committed
515
  private = GTK_ACTION_GROUP_GET_PRIVATE (self);
516 517 518 519

  switch (prop_id)
    {
    case PROP_NAME:
Tim Janik's avatar
Tim Janik committed
520 521
      tmp = private->name;
      private->name = g_value_dup_string (value);
522 523
      g_free (tmp);
      break;
524 525 526 527 528 529
    case PROP_SENSITIVE:
      gtk_action_group_set_sensitive (self, g_value_get_boolean (value));
      break;
    case PROP_VISIBLE:
      gtk_action_group_set_visible (self, g_value_get_boolean (value));
      break;
530 531 532 533 534 535 536 537 538 539 540 541 542
    default:
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
      break;
    }
}

static void
gtk_action_group_get_property (GObject    *object,
			       guint       prop_id,
			       GValue     *value,
			       GParamSpec *pspec)
{
  GtkActionGroup *self;
Tim Janik's avatar
Tim Janik committed
543
  GtkActionGroupPrivate *private;
544 545
  
  self = GTK_ACTION_GROUP (object);
Tim Janik's avatar
Tim Janik committed
546
  private = GTK_ACTION_GROUP_GET_PRIVATE (self);
547 548 549 550

  switch (prop_id)
    {
    case PROP_NAME:
Tim Janik's avatar
Tim Janik committed
551
      g_value_set_string (value, private->name);
552
      break;
553
    case PROP_SENSITIVE:
Tim Janik's avatar
Tim Janik committed
554
      g_value_set_boolean (value, private->sensitive);
555 556
      break;
    case PROP_VISIBLE:
Tim Janik's avatar
Tim Janik committed
557
      g_value_set_boolean (value, private->visible);
558
      break;
559 560 561 562 563 564
    default:
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
      break;
    }
}

565 566 567 568
static GtkAction *
gtk_action_group_real_get_action (GtkActionGroup *self,
				  const gchar    *action_name)
{
Tim Janik's avatar
Tim Janik committed
569 570 571 572 573
  GtkActionGroupPrivate *private;

  private = GTK_ACTION_GROUP_GET_PRIVATE (self);

  return g_hash_table_lookup (private->actions, action_name);
574 575 576 577 578 579 580 581 582 583 584 585
}

/**
 * gtk_action_group_get_name:
 * @action_group: the action group
 *
 * Gets the name of the action group.
 *
 * Returns: the name of the action group.
 * 
 * Since: 2.4
 */
586
G_CONST_RETURN gchar *
587 588
gtk_action_group_get_name (GtkActionGroup *action_group)
{
Tim Janik's avatar
Tim Janik committed
589 590
  GtkActionGroupPrivate *private;

591 592
  g_return_val_if_fail (GTK_IS_ACTION_GROUP (action_group), NULL);

Tim Janik's avatar
Tim Janik committed
593 594 595
  private = GTK_ACTION_GROUP_GET_PRIVATE (action_group);

  return private->name;
596 597
}

598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613
/**
 * gtk_action_group_get_sensitive:
 * @action_group: the action group
 *
 * Returns %TRUE if the group is sensitive.  The constituent actions
 * can only be logically sensitive (see gtk_action_is_sensitive()) if
 * they are sensitive (see gtk_action_get_sensitive()) and their group
 * is sensitive.
 * 
 * Return value: %TRUE if the group is sensitive.
 *
 * Since: 2.4
 */
gboolean
gtk_action_group_get_sensitive (GtkActionGroup *action_group)
{
Tim Janik's avatar
Tim Janik committed
614 615
  GtkActionGroupPrivate *private;

616 617
  g_return_val_if_fail (GTK_IS_ACTION_GROUP (action_group), FALSE);

Tim Janik's avatar
Tim Janik committed
618 619 620
  private = GTK_ACTION_GROUP_GET_PRIVATE (action_group);

  return private->sensitive;
621 622 623
}

static void
624 625
cb_set_action_sensitivity (const gchar *name, 
			   GtkAction   *action)
626
{
627 628
  /* Minor optimization, the action_groups state only affects actions 
   * that are themselves sensitive */
629 630
  g_object_notify (G_OBJECT (action), "sensitive");

631 632 633 634 635 636 637 638 639 640 641 642
}

/**
 * gtk_action_group_set_sensitive:
 * @action_group: the action group
 * @sensitive: new sensitivity
 *
 * Changes the sensitivity of @action_group
 * 
 * Since: 2.4
 */
void
643 644
gtk_action_group_set_sensitive (GtkActionGroup *action_group, 
				gboolean        sensitive)
645
{
Tim Janik's avatar
Tim Janik committed
646 647
  GtkActionGroupPrivate *private;

648 649
  g_return_if_fail (GTK_IS_ACTION_GROUP (action_group));

Tim Janik's avatar
Tim Janik committed
650
  private = GTK_ACTION_GROUP_GET_PRIVATE (action_group);
651 652
  sensitive = sensitive != FALSE;

Tim Janik's avatar
Tim Janik committed
653
  if (private->sensitive != sensitive)
654
    {
Tim Janik's avatar
Tim Janik committed
655 656
      private->sensitive = sensitive;
      g_hash_table_foreach (private->actions, 
657
			    (GHFunc) cb_set_action_sensitivity, NULL);
658 659

      g_object_notify (G_OBJECT (action_group), "sensitive");
660 661 662 663 664 665 666 667 668 669 670 671
    }
}

/**
 * gtk_action_group_get_visible:
 * @action_group: the action group
 *
 * Returns %TRUE if the group is visible.  The constituent actions
 * can only be logically visible (see gtk_action_is_visible()) if
 * they are visible (see gtk_action_get_visible()) and their group
 * is visible.
 * 
672
 * Return value: %TRUE if the group is visible.
673 674 675 676 677 678
 * 
 * Since: 2.4
 */
gboolean
gtk_action_group_get_visible (GtkActionGroup *action_group)
{
Tim Janik's avatar
Tim Janik committed
679 680
  GtkActionGroupPrivate *private;

681 682
  g_return_val_if_fail (GTK_IS_ACTION_GROUP (action_group), FALSE);

Tim Janik's avatar
Tim Janik committed
683 684 685
  private = GTK_ACTION_GROUP_GET_PRIVATE (action_group);

  return private->visible;
686 687 688
}

static void
689 690
cb_set_action_visiblity (const gchar *name, 
			 GtkAction   *action)
691
{
692 693
  /* Minor optimization, the action_groups state only affects actions 
   * that are themselves visible */
694
  g_object_notify (G_OBJECT (action), "visible");
695 696 697 698 699 700 701 702 703 704 705 706
}

/**
 * gtk_action_group_set_visible:
 * @action_group: the action group
 * @visible: new visiblity
 *
 * Changes the visible of @action_group.
 * 
 * Since: 2.4
 */
void
707 708
gtk_action_group_set_visible (GtkActionGroup *action_group, 
			      gboolean        visible)
709
{
Tim Janik's avatar
Tim Janik committed
710 711
  GtkActionGroupPrivate *private;

712 713
  g_return_if_fail (GTK_IS_ACTION_GROUP (action_group));

Tim Janik's avatar
Tim Janik committed
714
  private = GTK_ACTION_GROUP_GET_PRIVATE (action_group);
715 716
  visible = visible != FALSE;

Tim Janik's avatar
Tim Janik committed
717
  if (private->visible != visible)
718
    {
Tim Janik's avatar
Tim Janik committed
719 720
      private->visible = visible;
      g_hash_table_foreach (private->actions, 
721
			    (GHFunc) cb_set_action_visiblity, NULL);
722 723

      g_object_notify (G_OBJECT (action_group), "visible");
724 725 726
    }
}

727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744
/**
 * gtk_action_group_get_action:
 * @action_group: the action group
 * @action_name: the name of the action
 *
 * Looks up an action in the action group by name.
 *
 * Returns: the action, or %NULL if no action by that name exists
 *
 * Since: 2.4
 */
GtkAction *
gtk_action_group_get_action (GtkActionGroup *action_group,
			     const gchar    *action_name)
{
  g_return_val_if_fail (GTK_IS_ACTION_GROUP (action_group), NULL);
  g_return_val_if_fail (GTK_ACTION_GROUP_GET_CLASS (action_group)->get_action != NULL, NULL);

745 746
  return GTK_ACTION_GROUP_GET_CLASS (action_group)->get_action (action_group,
                                                                action_name);
747 748
}

749 750 751 752 753 754
static gboolean
check_unique_action (GtkActionGroup *action_group,
	             const gchar    *action_name)
{
  if (gtk_action_group_get_action (action_group, action_name) != NULL)
    {
Tim Janik's avatar
Tim Janik committed
755 756 757 758
      GtkActionGroupPrivate *private;

      private = GTK_ACTION_GROUP_GET_PRIVATE (action_group);

759 760
      g_warning ("Refusing to add non-unique action '%s' to action group '%s'",
	 	 action_name,
Tim Janik's avatar
Tim Janik committed
761
		 private->name);
762 763 764 765 766 767
      return FALSE;
    }

  return TRUE;
}

768 769 770 771 772
/**
 * gtk_action_group_add_action:
 * @action_group: the action group
 * @action: an action
 *
773 774 775 776 777 778
 * Adds an action object to the action group. Note that this function
 * does not set up the accel path of the action, which can lead to problems
 * if a user tries to modify the accelerator of a menuitem associated with
 * the action. Therefore you must either set the accel path yourself with
 * gtk_action_set_accel_path(), or use 
 * <literal>gtk_action_group_add_action_with_accel (..., NULL)</literal>.
779 780 781 782 783 784 785
 *
 * Since: 2.4
 */
void
gtk_action_group_add_action (GtkActionGroup *action_group,
			     GtkAction      *action)
{
Tim Janik's avatar
Tim Janik committed
786
  GtkActionGroupPrivate *private;
787 788
  const gchar *name;

789 790
  g_return_if_fail (GTK_IS_ACTION_GROUP (action_group));
  g_return_if_fail (GTK_IS_ACTION (action));
791 792 793

  name = gtk_action_get_name (action);
  g_return_if_fail (name != NULL);
794
  
795
  if (!check_unique_action (action_group, name))
796
    return;
797

Tim Janik's avatar
Tim Janik committed
798 799 800
  private = GTK_ACTION_GROUP_GET_PRIVATE (action_group);

  g_hash_table_insert (private->actions, 
801
		       (gpointer) name,
802
                       g_object_ref (action));
803
  g_object_set (action, I_("action-group"), action_group, NULL);
804 805
}

806 807
/**
 * gtk_action_group_add_action_with_accel:
808 809
 * @action_group: the action group 
 * @action: the action to add 
810
 * @accelerator: the accelerator for the action, in
Matthias Clasen's avatar
Matthias Clasen committed
811 812
 *   the format understood by gtk_accelerator_parse(), or "" for no accelerator, or 
 *   %NULL to use the stock accelerator 
813 814 815
 *
 * Adds an action object to the action group and sets up the accelerator.
 *
816
 * If @accelerator is %NULL, attempts to use the accelerator associated 
Matthias Clasen's avatar
Matthias Clasen committed
817
 * with the stock_id of the action. 
818
 *
819 820 821
 * Accel paths are set to
 * <literal>&lt;Actions&gt;/<replaceable>group-name</replaceable>/<replaceable>action-name</replaceable></literal>.
 *
822 823 824 825
 * Since: 2.4
 */
void
gtk_action_group_add_action_with_accel (GtkActionGroup *action_group,
826 827
					GtkAction      *action,
					const gchar    *accelerator)
828
{
Tim Janik's avatar
Tim Janik committed
829
  GtkActionGroupPrivate *private;
830 831 832
  gchar *accel_path;
  guint  accel_key = 0;
  GdkModifierType accel_mods;
833
  const gchar *name;
834

835 836
  name = gtk_action_get_name (action);
  if (!check_unique_action (action_group, name))
837
    return;
838

Tim Janik's avatar
Tim Janik committed
839
  private = GTK_ACTION_GROUP_GET_PRIVATE (action_group);
840
  accel_path = g_strconcat ("<Actions>/",
Tim Janik's avatar
Tim Janik committed
841
			    private->name, "/", name, NULL);
842 843

  if (accelerator)
844
    {
Matthias Clasen's avatar
Matthias Clasen committed
845 846 847 848 849 850 851 852 853
      if (accelerator[0] == 0) 
	accel_key = 0;
      else
	{
	  gtk_accelerator_parse (accelerator, &accel_key, &accel_mods);
	  if (accel_key == 0)
	    g_warning ("Unable to parse accelerator '%s' for action '%s'",
		       accelerator, name);
	}
854
    }
855
  else 
856
    {
857 858 859 860 861 862 863 864 865 866 867 868
      gchar *stock_id;
      GtkStockItem stock_item;

      g_object_get (action, "stock-id", &stock_id, NULL);

      if (stock_id && gtk_stock_lookup (stock_id, &stock_item))
        {
          accel_key = stock_item.keyval;
          accel_mods = stock_item.modifier;
	}

      g_free (stock_id);
869 870 871
    }

  if (accel_key)
Matthias Clasen's avatar
Matthias Clasen committed
872
    gtk_accel_map_add_entry (accel_path, accel_key, accel_mods);
873 874 875

  gtk_action_set_accel_path (action, accel_path);
  gtk_action_group_add_action (action_group, action);
876 877

  g_free (accel_path);
878 879
}

880
/**
Matthias Clasen's avatar
Matthias Clasen committed
881
 * gtk_action_group_remove_action:
882 883 884 885 886 887 888 889 890 891 892
 * @action_group: the action group
 * @action: an action
 *
 * Removes an action object from the action group.
 *
 * Since: 2.4
 */
void
gtk_action_group_remove_action (GtkActionGroup *action_group,
				GtkAction      *action)
{
Tim Janik's avatar
Tim Janik committed
893
  GtkActionGroupPrivate *private;
894 895
  const gchar *name;

896 897 898
  g_return_if_fail (GTK_IS_ACTION_GROUP (action_group));
  g_return_if_fail (GTK_IS_ACTION (action));

899 900 901
  name = gtk_action_get_name (action);
  g_return_if_fail (name != NULL);

Tim Janik's avatar
Tim Janik committed
902 903 904
  private = GTK_ACTION_GROUP_GET_PRIVATE (action_group);

  g_hash_table_remove (private->actions, name);
905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929
}

static void
add_single_action (gpointer key, 
		   gpointer value, 
		   gpointer user_data)
{
  GList **list = user_data;

  *list = g_list_prepend (*list, value);
}

/**
 * gtk_action_group_list_actions:
 * @action_group: the action group
 *
 * Lists the actions in the action group.
 *
 * Returns: an allocated list of the action objects in the action group
 * 
 * Since: 2.4
 */
GList *
gtk_action_group_list_actions (GtkActionGroup *action_group)
{
Tim Janik's avatar
Tim Janik committed
930
  GtkActionGroupPrivate *private;
931
  GList *actions = NULL;
Tim Janik's avatar
Tim Janik committed
932

933
  g_return_val_if_fail (GTK_IS_ACTION_GROUP (action_group), NULL);
Tim Janik's avatar
Tim Janik committed
934 935

  private = GTK_ACTION_GROUP_GET_PRIVATE (action_group);
936
  
Tim Janik's avatar
Tim Janik committed
937
  g_hash_table_foreach (private->actions, add_single_action, &actions);
938 939 940 941 942 943 944 945 946 947

  return g_list_reverse (actions);
}


/**
 * gtk_action_group_add_actions:
 * @action_group: the action group
 * @entries: an array of action descriptions
 * @n_entries: the number of entries
948
 * @user_data: data to pass to the action callbacks
949
 *
950 951
 * This is a convenience function to create a number of actions and add them 
 * to the action group.
Matthias Clasen's avatar
Matthias Clasen committed
952 953 954 955
 *
 * The "activate" signals of the actions are connected to the callbacks and 
 * their accel paths are set to 
 * <literal>&lt;Actions&gt;/<replaceable>group-name</replaceable>/<replaceable>action-name</replaceable></literal>.  
956 957 958 959
 * 
 * Since: 2.4
 */
void
960 961 962 963
gtk_action_group_add_actions (GtkActionGroup       *action_group,
			      const GtkActionEntry *entries,
			      guint                 n_entries,
			      gpointer              user_data)
964 965 966 967 968 969
{
  gtk_action_group_add_actions_full (action_group, 
				     entries, n_entries, 
				     user_data, NULL);
}

970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985
typedef struct _SharedData  SharedData;

struct _SharedData {
  guint          ref_count;
  gpointer       data;
  GDestroyNotify destroy;
};

static void
shared_data_unref (gpointer data)
{
  SharedData *shared_data = (SharedData *)data;

  shared_data->ref_count--;
  if (shared_data->ref_count == 0)
    {
986 987 988
      if (shared_data->destroy)
	shared_data->destroy (shared_data->data);

989
      g_slice_free (SharedData, shared_data);
990 991 992
    }
}

993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007

/**
 * gtk_action_group_add_actions_full:
 * @action_group: the action group
 * @entries: an array of action descriptions
 * @n_entries: the number of entries
 * @user_data: data to pass to the action callbacks
 * @destroy: destroy notification callback for @user_data
 *
 * This variant of gtk_action_group_add_actions() adds a #GDestroyNotify
 * callback for @user_data. 
 * 
 * Since: 2.4
 */
void
1008 1009 1010 1011 1012
gtk_action_group_add_actions_full (GtkActionGroup       *action_group,
				   const GtkActionEntry *entries,
				   guint                 n_entries,
				   gpointer              user_data,
				   GDestroyNotify        destroy)
1013
{
1014 1015 1016 1017

  /* Keep this in sync with the other 
   * gtk_action_group_add_..._actions_full() functions.
   */
1018
  guint i;
1019
  SharedData *shared_data;
1020

1021
  g_return_if_fail (GTK_IS_ACTION_GROUP (action_group));
1022

1023
  shared_data = g_slice_new0 (SharedData);
1024 1025 1026 1027
  shared_data->ref_count = 1;
  shared_data->data = user_data;
  shared_data->destroy = destroy;

1028 1029 1030
  for (i = 0; i < n_entries; i++)
    {
      GtkAction *action;
1031 1032
      const gchar *label;
      const gchar *tooltip;
1033

1034 1035 1036
      if (!check_unique_action (action_group, entries[i].name))
        continue;

1037 1038
      label = gtk_action_group_translate_string (action_group, entries[i].label);
      tooltip = gtk_action_group_translate_string (action_group, entries[i].tooltip);
1039

1040 1041 1042
      action = gtk_action_new (entries[i].name,
			       label,
			       tooltip,
1043
			       NULL);
1044

1045 1046
      if (entries[i].stock_id) 
	{
1047 1048 1049
	  g_object_set (action, "stock-id", entries[i].stock_id, NULL);
	  if (gtk_icon_theme_has_icon (gtk_icon_theme_get_default (), 
				       entries[i].stock_id))
1050 1051 1052
	    g_object_set (action, "icon-name", entries[i].stock_id, NULL);
	}
	  
1053
      if (entries[i].callback)
1054 1055 1056 1057 1058 1059 1060
	{
	  GClosure *closure;

	  closure = g_cclosure_new (entries[i].callback, user_data, NULL);
	  g_closure_add_finalize_notifier (closure, shared_data, 
					   (GClosureNotify)shared_data_unref);
	  shared_data->ref_count++;
1061

1062 1063 1064
	  g_signal_connect_closure (action, "activate", closure, FALSE);
	}
	  
1065 1066 1067
      gtk_action_group_add_action_with_accel (action_group, 
					      action,
					      entries[i].accelerator);
1068 1069
      g_object_unref (action);
    }
1070 1071

  shared_data_unref (shared_data);
1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090
}

/**
 * gtk_action_group_add_toggle_actions:
 * @action_group: the action group
 * @entries: an array of toggle action descriptions
 * @n_entries: the number of entries
 * @user_data: data to pass to the action callbacks
 *
 * This is a convenience function to create a number of toggle actions and add them 
 * to the action group.
 *
 * The "activate" signals of the actions are connected to the callbacks and 
 * their accel paths are set to 
 * <literal>&lt;Actions&gt;/<replaceable>group-name</replaceable>/<replaceable>action-name</replaceable></literal>.  
 * 
 * Since: 2.4
 */
void
1091 1092 1093 1094
gtk_action_group_add_toggle_actions (GtkActionGroup             *action_group,
				     const GtkToggleActionEntry *entries,
				     guint                       n_entries,
				     gpointer                    user_data)
1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115
{
  gtk_action_group_add_toggle_actions_full (action_group, 
					    entries, n_entries, 
					    user_data, NULL);
}


/**
 * gtk_action_group_add_toggle_actions_full:
 * @action_group: the action group
 * @entries: an array of toggle action descriptions
 * @n_entries: the number of entries
 * @user_data: data to pass to the action callbacks
 * @destroy: destroy notification callback for @user_data
 *
 * This variant of gtk_action_group_add_toggle_actions() adds a 
 * #GDestroyNotify callback for @user_data. 
 * 
 * Since: 2.4
 */
void
1116 1117 1118 1119 1120
gtk_action_group_add_toggle_actions_full (GtkActionGroup             *action_group,
					  const GtkToggleActionEntry *entries,
					  guint                       n_entries,
					  gpointer                    user_data,
					  GDestroyNotify              destroy)
1121
{
1122 1123 1124
  /* Keep this in sync with the other 
   * gtk_action_group_add_..._actions_full() functions.
   */
1125
  guint i;
1126
  SharedData *shared_data;
1127 1128 1129

  g_return_if_fail (GTK_IS_ACTION_GROUP (action_group));

1130
  shared_data = g_slice_new0 (SharedData);
1131 1132 1133 1134
  shared_data->ref_count = 1;
  shared_data->data = user_data;
  shared_data->destroy = destroy;

1135 1136
  for (i = 0; i < n_entries; i++)
    {
1137
      GtkToggleAction *action;
1138 1139
      const gchar *label;
      const gchar *tooltip;
1140

1141 1142 1143
      if (!check_unique_action (action_group, entries[i].name))
        continue;

1144 1145
      label = gtk_action_group_translate_string (action_group, entries[i].label);
      tooltip = gtk_action_group_translate_string (action_group, entries[i].tooltip);
1146

1147 1148 1149
      action = gtk_toggle_action_new (entries[i].name,
				      label,
				      tooltip,
1150 1151 1152 1153
				      NULL);

      if (entries[i].stock_id) 
	{
1154
	  if (gtk_icon_factory_lookup_default (entries[i].stock_id))
1155 1156 1157 1158
	    g_object_set (action, "stock-id", entries[i].stock_id, NULL);
	  else
	    g_object_set (action, "icon-name", entries[i].stock_id, NULL);
	}
1159

1160
      gtk_toggle_action_set_active (action, entries[i].is_active);
1161

1162
      if (entries[i].callback)
1163 1164 1165 1166 1167 1168 1169
	{
	  GClosure *closure;

	  closure = g_cclosure_new (entries[i].callback, user_data, NULL);
	  g_closure_add_finalize_notifier (closure, shared_data, 
					   (GClosureNotify)shared_data_unref);
	  shared_data->ref_count++;
1170

1171 1172 1173
	  g_signal_connect_closure (action, "activate", closure, FALSE);
	}
	  
1174
      gtk_action_group_add_action_with_accel (action_group, 
1175
					      GTK_ACTION (action),
1176
					      entries[i].accelerator);
1177 1178
      g_object_unref (action);
    }
1179

1180
  shared_data_unref (shared_data);
1181 1182 1183 1184 1185 1186 1187
}

/**
 * gtk_action_group_add_radio_actions:
 * @action_group: the action group
 * @entries: an array of radio action descriptions
 * @n_entries: the number of entries
1188 1189
 * @value: the value of the action to activate initially, or -1 if
 *   no action should be activated
1190 1191 1192
 * @on_change: the callback to connect to the changed signal
 * @user_data: data to pass to the action callbacks
 * 
Matthias Clasen's avatar
Matthias Clasen committed
1193 1194 1195
 * This is a convenience routine to create a group of radio actions and
 * add them to the action group. 
 *
1196 1197
 * The "changed" signal of the first radio action is connected to the 
 * @on_change callback and the accel paths of the actions are set to 
Matthias Clasen's avatar
Matthias Clasen committed
1198
 * <literal>&lt;Actions&gt;/<replaceable>group-name</replaceable>/<replaceable>action-name</replaceable></literal>.  
1199 1200 1201 1202
 * 
 * Since: 2.4
 **/
void            
1203 1204 1205 1206 1207 1208
gtk_action_group_add_radio_actions (GtkActionGroup            *action_group,
				    const GtkRadioActionEntry *entries,
				    guint                      n_entries,
				    gint                       value,
				    GCallback                  on_change,
				    gpointer                   user_data)
1209 1210 1211
{
  gtk_action_group_add_radio_actions_full (action_group, 
					   entries, n_entries, 
1212
					   value,
1213 1214 1215
					   on_change, user_data, NULL);
}

Matthias Clasen's avatar
Matthias Clasen committed
1216 1217 1218 1219 1220
/**
 * gtk_action_group_add_radio_actions_full:
 * @action_group: the action group
 * @entries: an array of radio action descriptions
 * @n_entries: the number of entries
1221 1222
 * @value: the value of the action to activate initially, or -1 if
 *   no action should be activated
Matthias Clasen's avatar
Matthias Clasen committed
1223 1224 1225 1226 1227 1228 1229 1230 1231
 * @on_change: the callback to connect to the changed signal
 * @user_data: data to pass to the action callbacks
 * @destroy: destroy notification callback for @user_data
 *
 * This variant of gtk_action_group_add_radio_actions() adds a 
 * #GDestroyNotify callback for @user_data. 
 * 
 * Since: 2.4
 **/
1232
void            
1233 1234 1235 1236 1237 1238 1239
gtk_action_group_add_radio_actions_full (GtkActionGroup            *action_group,
					 const GtkRadioActionEntry *entries,
					 guint                      n_entries,
					 gint                       value,
					 GCallback                  on_change,
					 gpointer                   user_data,
					 GDestroyNotify             destroy)
1240
{
1241 1242 1243
  /* Keep this in sync with the other 
   * gtk_action_group_add_..._actions_full() functions.
   */
1244
  guint i;
1245
  GSList *group = NULL;
1246
  GtkRadioAction *first_action = NULL;
1247 1248 1249 1250 1251

  g_return_if_fail (GTK_IS_ACTION_GROUP (action_group));

  for (i = 0; i < n_entries; i++)
    {
1252
      GtkRadioAction *action;
1253 1254
      const gchar *label;
      const gchar *tooltip; 
1255

1256 1257 1258
      if (!check_unique_action (action_group, entries[i].name))
        continue;

1259 1260
      label = gtk_action_group_translate_string (action_group, entries[i].label);
      tooltip = gtk_action_group_translate_string (action_group, entries[i].tooltip);
1261

1262 1263 1264
      action = gtk_radio_action_new (entries[i].name,
				     label,
				     tooltip,
1265
				     NULL,
1266
				     entries[i].value);
1267

1268 1269
      if (entries[i].stock_id) 
	{
1270
	  if (gtk_icon_factory_lookup_default (entries[i].stock_id))
1271 1272 1273 1274 1275
	    g_object_set (action, "stock-id", entries[i].stock_id, NULL);
	  else
	    g_object_set (action, "icon-name", entries[i].stock_id, NULL);
	}

1276
      if (i == 0) 
1277 1278
	first_action = action;

1279 1280
      gtk_radio_action_set_group (action, group);
      group = gtk_radio_action_get_group (action);
1281

1282
      if (value == entries[i].value)
1283
	gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action), TRUE);
1284

1285
      gtk_action_group_add_action_with_accel (action_group, 
1286
					      GTK_ACTION (action),
1287
					      entries[i].accelerator);
1288 1289
      g_object_unref (action);
    }
1290

1291
  if (on_change && first_action)
1292 1293 1294
    g_signal_connect_data (first_action, "changed",
			   on_change, user_data, 
			   (GClosureNotify)destroy, 0);
1295
}
1296 1297 1298 1299 1300 1301

/**
 * gtk_action_group_set_translate_func:
 * @action_group: a #GtkActionGroup
 * @func: a #GtkTranslateFunc
 * @data: data to be passed to @func and @notify
1302
 * @notify: a #GDestroyNotify function to be called when @action_group is
1303
 *   destroyed and when the translation function is changed again
1304
 *
1305 1306 1307 1308 1309 1310 1311 1312 1313
 * Sets a function to be used for translating the @label and @tooltip of 
 * #GtkActionGroupEntry<!-- -->s added by gtk_action_group_add_actions().
 *
 * If you're using gettext(), it is enough to set the translation domain
 * with gtk_action_group_set_translation_domain().
 *
 * Since: 2.4 
 **/
void
1314 1315 1316
gtk_action_group_set_translate_func (GtkActionGroup   *action_group,
				     GtkTranslateFunc  func,
				     gpointer          data,
1317
				     GDestroyNotify    notify)
1318
{
Tim Janik's avatar
Tim Janik committed
1319 1320
  GtkActionGroupPrivate *private;

1321 1322
  g_return_if_fail (GTK_IS_ACTION_GROUP (action_group));
  
Tim Janik's avatar
Tim Janik committed
1323 1324 1325 1326
  private = GTK_ACTION_GROUP_GET_PRIVATE (action_group);

  if (private->translate_notify)
    private->translate_notify (private->translate_data);
1327
      
Tim Janik's avatar
Tim Janik committed
1328 1329 1330
  private->translate_func = func;
  private->translate_data = data;
  private->translate_notify = notify;
1331 1332 1333 1334 1335 1336
}

static gchar *
dgettext_swapped (const gchar *msgid, 
		  const gchar *domainname)
{
1337
  /* Pass through g_dgettext if and only if msgid is nonempty. */
1338
  if (msgid && *msgid) 
1339
    return (gchar*) g_dgettext (domainname, msgid); 
1340 1341
  else
    return (gchar*) msgid;
1342 1343 1344 1345 1346
}

/**
 * gtk_action_group_set_translation_domain:
 * @action_group: a #GtkActionGroup
1347
 * @domain: the translation domain to use for g_dgettext() calls
1348
 * 
1349
 * Sets the translation domain and uses g_dgettext() for translating the 
1350
 * @label and @tooltip of #GtkActionEntry<!-- -->s added by 
1351
 * gtk_action_group_add_actions().
1352 1353 1354 1355 1356 1357 1358 1359 1360 1361 1362 1363 1364
 *
 * If you're not using gettext() for localization, see 
 * gtk_action_group_set_translate_func().
 *
 * Since: 2.4
 **/
void 
gtk_action_group_set_translation_domain (GtkActionGroup *action_group,
					 const gchar    *domain)
{
  g_return_if_fail (GTK_IS_ACTION_GROUP (action_group));

  gtk_action_group_set_translate_func (action_group, 
1365
				       (GtkTranslateFunc)dgettext_swapped,
1366 1367 1368
				       g_strdup (domain),
				       g_free);
} 
1369

1370 1371 1372 1373 1374 1375 1376 1377 1378 1379 1380 1381 1382 1383 1384 1385 1386

/**
 * gtk_action_group_translate_string:
 * @action_group: a #GtkActionGroup
 * @string: a string
 *
 * Translates a string using the specified translate_func(). This
 * is mainly intended for language bindings.
 *
 * Returns: the translation of @string
 *
 * Since: 2.6
 **/
G_CONST_RETURN gchar *
gtk_action_group_translate_string (GtkActionGroup *action_group,
				   const gchar    *string)
{
Tim Janik's avatar
Tim Janik committed
1387
  GtkActionGroupPrivate *private;
1388 1389 1390 1391 1392
  GtkTranslateFunc translate_func;
  gpointer translate_data;
  
  g_return_val_if_fail (GTK_IS_ACTION_GROUP (action_group), string);
  
1393 1394 1395
  if (string == NULL)
    return NULL;

Tim Janik's avatar
Tim Janik committed
1396 1397 1398 1399
  private = GTK_ACTION_GROUP_GET_PRIVATE (action_group);

  translate_func = private->translate_func;
  translate_data = private->translate_data;
1400 1401 1402 1403 1404 1405 1406
  
  if (translate_func)
    return translate_func (string, translate_data);
  else
    return string;
}

1407 1408 1409 1410 1411 1412 1413 1414 1415 1416 1417 1418 1419 1420 1421 1422 1423 1424 1425 1426 1427 1428 1429 1430 1431 1432 1433 1434
/* Protected for use by GtkAction */
void
_gtk_action_group_emit_connect_proxy  (GtkActionGroup *action_group,
                                       GtkAction      *action,
                                       GtkWidget      *proxy)
{
  g_signal_emit (action_group, action_group_signals[CONNECT_PROXY], 0, 
                 action, proxy);
}

void
_gtk_action_group_emit_disconnect_proxy  (GtkActionGroup *action_group,
                                          GtkAction      *action,
                                          GtkWidget      *proxy)
{
  g_signal_emit (action_group, action_group_signals[DISCONNECT_PROXY], 0, 
                 action, proxy);
}

void
_gtk_action_group_emit_pre_activate  (GtkActionGroup *action_group,
				      GtkAction      *action)
{
  g_signal_emit (action_group, action_group_signals[PRE_ACTIVATE], 0, action);
}

void
_gtk_action_group_emit_post_activate (GtkActionGroup *action_group,
1435
				      GtkAction      *action)
1436 1437 1438
{
  g_signal_emit (action_group, action_group_signals[POST_ACTIVATE], 0, action);
}
1439 1440 1441

#define __GTK_ACTION_GROUP_C__
#include "gtkaliasdef.c"