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
  if (gtk_action_get_sensitive (action))
630
    _gtk_action_sync_sensitive (action);
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
  if (gtk_action_get_visible (action))
695
    _gtk_action_sync_visible (action);
696 697 698 699 700 701 702 703 704 705 706 707
}

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

713 714
  g_return_if_fail (GTK_IS_ACTION_GROUP (action_group));

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

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

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

728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745
/**
 * 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);

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

750 751 752 753 754 755
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
756 757 758 759
      GtkActionGroupPrivate *private;

      private = GTK_ACTION_GROUP_GET_PRIVATE (action_group);

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

  return TRUE;
}

769 770 771 772 773
/**
 * gtk_action_group_add_action:
 * @action_group: the action group
 * @action: an action
 *
774 775 776 777 778 779
 * 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>.
780 781 782 783 784 785 786
 *
 * Since: 2.4
 */
void
gtk_action_group_add_action (GtkActionGroup *action_group,
			     GtkAction      *action)
{
Tim Janik's avatar
Tim Janik committed
787
  GtkActionGroupPrivate *private;
788 789
  const gchar *name;

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

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

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

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

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

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

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

  if (accelerator)
845
    {
Matthias Clasen's avatar
Matthias Clasen committed
846 847 848 849 850 851 852 853 854
      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);
	}
855
    }
856
  else 
857
    {
858 859 860 861 862 863 864 865 866 867 868 869
      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);
870 871 872
    }

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

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

  g_free (accel_path);
879 880
}

881
/**
Matthias Clasen's avatar
Matthias Clasen committed
882
 * gtk_action_group_remove_action:
883 884 885 886 887 888 889 890 891 892 893
 * @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
894
  GtkActionGroupPrivate *private;
895 896
  const gchar *name;

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

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

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

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

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
931
  GtkActionGroupPrivate *private;
932
  GList *actions = NULL;
Tim Janik's avatar
Tim Janik committed
933

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

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

  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
949
 * @user_data: data to pass to the action callbacks
950
 *
951 952
 * 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
953 954 955 956
 *
 * 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>.  
957 958 959 960
 * 
 * Since: 2.4
 */
void
961 962 963 964
gtk_action_group_add_actions (GtkActionGroup       *action_group,
			      const GtkActionEntry *entries,
			      guint                 n_entries,
			      gpointer              user_data)
965 966 967 968 969 970
{
  gtk_action_group_add_actions_full (action_group, 
				     entries, n_entries, 
				     user_data, NULL);
}

971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986
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)
    {
987 988 989
      if (shared_data->destroy)
	shared_data->destroy (shared_data->data);

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

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

/**
 * 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
1009 1010 1011 1012 1013
gtk_action_group_add_actions_full (GtkActionGroup       *action_group,
				   const GtkActionEntry *entries,
				   guint                 n_entries,
				   gpointer              user_data,
				   GDestroyNotify        destroy)
1014
{
1015 1016 1017 1018

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

1022
  g_return_if_fail (GTK_IS_ACTION_GROUP (action_group));
1023

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

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

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

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

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

1046 1047
      if (entries[i].stock_id) 
	{
1048 1049 1050
	  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))
1051 1052 1053
	    g_object_set (action, "icon-name", entries[i].stock_id, NULL);
	}
	  
1054
      if (entries[i].callback)
1055 1056 1057 1058 1059 1060 1061
	{
	  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++;
1062

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

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

/**
 * 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
1092 1093 1094 1095
gtk_action_group_add_toggle_actions (GtkActionGroup             *action_group,
				     const GtkToggleActionEntry *entries,
				     guint                       n_entries,
				     gpointer                    user_data)
1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116
{
  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
1117 1118 1119 1120 1121
gtk_action_group_add_toggle_actions_full (GtkActionGroup             *action_group,
					  const GtkToggleActionEntry *entries,
					  guint                       n_entries,
					  gpointer                    user_data,
					  GDestroyNotify              destroy)
1122
{
1123 1124 1125
  /* Keep this in sync with the other 
   * gtk_action_group_add_..._actions_full() functions.
   */
1126
  guint i;
1127
  SharedData *shared_data;
1128 1129 1130

  g_return_if_fail (GTK_IS_ACTION_GROUP (action_group));

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

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

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

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

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

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

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

1163
      if (entries[i].callback)
1164 1165 1166 1167 1168 1169 1170
	{
	  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++;
1171

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

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

/**
 * gtk_action_group_add_radio_actions:
 * @action_group: the action group
 * @entries: an array of radio action descriptions
 * @n_entries: the number of entries
1189 1190
 * @value: the value of the action to activate initially, or -1 if
 *   no action should be activated
1191 1192 1193
 * @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
1194 1195 1196
 * This is a convenience routine to create a group of radio actions and
 * add them to the action group. 
 *
1197 1198
 * 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
1199
 * <literal>&lt;Actions&gt;/<replaceable>group-name</replaceable>/<replaceable>action-name</replaceable></literal>.  
1200 1201 1202 1203
 * 
 * Since: 2.4
 **/
void            
1204 1205 1206 1207 1208 1209
gtk_action_group_add_radio_actions (GtkActionGroup            *action_group,
				    const GtkRadioActionEntry *entries,
				    guint                      n_entries,
				    gint                       value,
				    GCallback                  on_change,
				    gpointer                   user_data)
1210 1211 1212
{
  gtk_action_group_add_radio_actions_full (action_group, 
					   entries, n_entries, 
1213
					   value,
1214 1215 1216
					   on_change, user_data, NULL);
}

Matthias Clasen's avatar
Matthias Clasen committed
1217 1218 1219 1220 1221
/**
 * 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
1222 1223
 * @value: the value of the action to activate initially, or -1 if
 *   no action should be activated
Matthias Clasen's avatar
Matthias Clasen committed
1224 1225 1226 1227 1228 1229 1230 1231 1232
 * @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
 **/
1233
void            
1234 1235 1236 1237 1238 1239 1240
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)
1241
{
1242 1243 1244
  /* Keep this in sync with the other 
   * gtk_action_group_add_..._actions_full() functions.
   */
1245
  guint i;
1246
  GSList *group = NULL;
1247
  GtkRadioAction *first_action = NULL;
1248 1249 1250 1251 1252

  g_return_if_fail (GTK_IS_ACTION_GROUP (action_group));

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

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

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

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

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

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

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

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

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

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

/**
 * gtk_action_group_set_translate_func:
 * @action_group: a #GtkActionGroup
 * @func: a #GtkTranslateFunc
 * @data: data to be passed to @func and @notify
1303
 * @notify: a #GDestroyNotify function to be called when @action_group is
1304
 *   destroyed and when the translation function is changed again
1305
 *
1306 1307 1308 1309 1310 1311 1312 1313 1314
 * 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
1315 1316 1317
gtk_action_group_set_translate_func (GtkActionGroup   *action_group,
				     GtkTranslateFunc  func,
				     gpointer          data,
1318
				     GDestroyNotify    notify)
1319
{
Tim Janik's avatar
Tim Janik committed
1320 1321
  GtkActionGroupPrivate *private;

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

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

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

/**
 * gtk_action_group_set_translation_domain:
 * @action_group: a #GtkActionGroup
1348
 * @domain: the translation domain to use for g_dgettext() calls
1349
 * 
1350
 * Sets the translation domain and uses g_dgettext() for translating the 
1351
 * @label and @tooltip of #GtkActionEntry<!-- -->s added by 
1352
 * gtk_action_group_add_actions().
1353 1354 1355 1356 1357 1358 1359 1360 1361 1362 1363 1364 1365
 *
 * 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, 
1366
				       (GtkTranslateFunc)dgettext_swapped,
1367 1368 1369
				       g_strdup (domain),
				       g_free);
} 
1370

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

/**
 * 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
1388
  GtkActionGroupPrivate *private;
1389 1390 1391 1392 1393
  GtkTranslateFunc translate_func;
  gpointer translate_data;
  
  g_return_val_if_fail (GTK_IS_ACTION_GROUP (action_group), string);
  
1394 1395 1396
  if (string == NULL)
    return NULL;

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

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

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 1435
/* 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,
1436
				      GtkAction      *action)
1437 1438 1439
{
  g_signal_emit (action_group, action_group_signals[POST_ACTIVATE], 0, action);
}
1440 1441 1442

#define __GTK_ACTION_GROUP_C__
#include "gtkaliasdef.c"