gtkaction.c 55.4 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
 * 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
Javier Jardón's avatar
Javier Jardón committed
17
 * License along with this library. If not, see <http://www.gnu.org/licenses/>.
18 19 20 21 22 23 24 25 26 27 28
 */

/*
 * 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/. 
 */

29 30
/**
 * SECTION:gtkaction
31
 * @Short_description: A deprecated action which can be triggered by a menu or toolbar item
32
 * @Title: GtkAction
33
 * @See_also: #GtkActionGroup, #GtkUIManager, #GtkActivatable
34
 *
William Jon McCann's avatar
William Jon McCann committed
35 36 37
 * > In GTK+ 3.10, GtkAction has been deprecated. Use #GAction
 * > instead, and associate actions with #GtkActionable widgets. Use
 * > #GMenuModel for creating menus with gtk_menu_new_from_model().
38
 *
39 40 41 42 43 44 45
 * Actions represent operations that the user can be perform, along with
 * some information how it should be presented in the interface. Each action
 * provides methods to create icons, menu items and toolbar items
 * representing itself.
 *
 * As well as the callback that is called when the action gets activated,
 * the following also gets associated with the action:
46 47 48 49 50 51 52 53 54 55 56 57 58 59
 *
 * - a name (not translated, for path lookup)
 *
 * - a label (translated, for display)
 *
 * - an accelerator
 *
 * - whether label indicates a stock id
 *
 * - a tooltip (optional, translated)
 *
 * - a toolbar label (optional, shorter than label)
 *
 *
60
 * The action will also have some state information:
61 62 63 64 65
 *
 * - visible (shown/hidden)
 *
 * - sensitive (enabled/disabled)
 *
66 67 68
 * Apart from regular actions, there are <link linkend="GtkToggleAction">toggle
 * actions</link>, which can be toggled between two states and <link
 * linkend="GtkRadioAction">radio actions</link>, of which only one in a group
William Jon McCann's avatar
William Jon McCann committed
69
 * can be in the “active” state. Other actions can be implemented as #GtkAction
70 71
 * subclasses.
 *
72 73 74 75 76 77 78 79 80 81
 * Each action can have one or more proxy widgets. To act as an action proxy,
 * widget needs to implement #GtkActivatable interface. Proxies mirror the state
 * of the action and should change when the action's state changes. Properties
 * that are always mirrored by proxies are #GtkAction:sensitive and
 * #GtkAction:visible. #GtkAction:gicon, #GtkAction:icon-name, #GtkAction:label,
 * #GtkAction:short-label and #GtkAction:stock-id properties are only mirorred
 * if proxy widget has #GtkActivatable:use-action-appearance property set to
 * %TRUE.
 *
 * When the proxy is activated, it should activate its action.
82 83
 */

84
#include "config.h"
85

86 87
#define GDK_DISABLE_DEPRECATION_WARNINGS

88
#include "gtkaction.h"
89
#include "gtkactiongroup.h"
Matthias Clasen's avatar
Matthias Clasen committed
90
#include "gtkaccellabel.h"
91
#include "gtkbutton.h"
Matthias Clasen's avatar
Matthias Clasen committed
92
#include "gtkiconfactory.h"
93
#include "gtkimage.h"
Matthias Clasen's avatar
Matthias Clasen committed
94
#include "gtkimagemenuitem.h"
95
#include "gtkintl.h"
Matthias Clasen's avatar
Matthias Clasen committed
96
#include "gtklabel.h"
97
#include "gtkmarshalers.h"
Matthias Clasen's avatar
Matthias Clasen committed
98 99
#include "gtkmenuitem.h"
#include "gtkstock.h"
100
#include "gtktearoffmenuitem.h"
Matthias Clasen's avatar
Matthias Clasen committed
101 102
#include "gtktoolbutton.h"
#include "gtktoolbar.h"
103
#include "gtkprivate.h"
Johan Dahlin's avatar
Johan Dahlin committed
104
#include "gtkbuildable.h"
105
#include "gtkactivatable.h"
106 107 108 109


struct _GtkActionPrivate 
{
110
  const gchar *name; /* interned */
111 112 113
  gchar *label;
  gchar *short_label;
  gchar *tooltip;
114 115
  gchar *stock_id; /* stock icon */
  gchar *icon_name; /* themed icon */
116
  GIcon *gicon;
117

118 119 120 121
  guint sensitive          : 1;
  guint visible            : 1;
  guint label_set          : 1; /* these two used so we can set label */
  guint short_label_set    : 1; /* based on stock id */
122 123
  guint visible_horizontal : 1;
  guint visible_vertical   : 1;
124 125 126
  guint is_important       : 1;
  guint hide_if_empty      : 1;
  guint visible_overflown  : 1;
127
  guint always_show_image  : 1;
128 129
  guint recursion_guard    : 1;
  guint activate_blocked   : 1;
130 131

  /* accelerator */
132 133 134 135
  guint          accel_count;
  GtkAccelGroup *accel_group;
  GClosure      *accel_closure;
  GQuark         accel_quark;
136

137 138
  GtkActionGroup *action_group;

139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156
  /* list of proxy widgets */
  GSList *proxies;
};

enum 
{
  ACTIVATE,
  LAST_SIGNAL
};

enum 
{
  PROP_0,
  PROP_NAME,
  PROP_LABEL,
  PROP_SHORT_LABEL,
  PROP_TOOLTIP,
  PROP_STOCK_ID,
157
  PROP_ICON_NAME,
158
  PROP_GICON,
159 160
  PROP_VISIBLE_HORIZONTAL,
  PROP_VISIBLE_VERTICAL,
161
  PROP_VISIBLE_OVERFLOWN,
162
  PROP_IS_IMPORTANT,
163
  PROP_HIDE_IF_EMPTY,
164
  PROP_SENSITIVE,
165
  PROP_VISIBLE,
166 167
  PROP_ACTION_GROUP,
  PROP_ALWAYS_SHOW_IMAGE
168 169
};

Johan Dahlin's avatar
Johan Dahlin committed
170 171 172 173 174 175 176
/* GtkBuildable */
static void gtk_action_buildable_init             (GtkBuildableIface *iface);
static void gtk_action_buildable_set_name         (GtkBuildable *buildable,
						   const gchar  *name);
static const gchar* gtk_action_buildable_get_name (GtkBuildable *buildable);

G_DEFINE_TYPE_WITH_CODE (GtkAction, gtk_action, G_TYPE_OBJECT,
177
                         G_ADD_PRIVATE (GtkAction)
Johan Dahlin's avatar
Johan Dahlin committed
178 179 180
			 G_IMPLEMENT_INTERFACE (GTK_TYPE_BUILDABLE,
						gtk_action_buildable_init))

181 182 183 184 185 186 187 188 189
static void gtk_action_finalize     (GObject *object);
static void gtk_action_set_property (GObject         *object,
				     guint            prop_id,
				     const GValue    *value,
				     GParamSpec      *pspec);
static void gtk_action_get_property (GObject         *object,
				     guint            prop_id,
				     GValue          *value,
				     GParamSpec      *pspec);
190
static void gtk_action_set_action_group (GtkAction	*action,
191
					 GtkActionGroup *action_group);
192 193 194

static GtkWidget *create_menu_item    (GtkAction *action);
static GtkWidget *create_tool_item    (GtkAction *action);
195 196
static void       connect_proxy       (GtkAction *action,
				       GtkWidget *proxy);
197 198
static void       disconnect_proxy    (GtkAction *action,
				       GtkWidget *proxy);
199
 
200 201 202 203 204 205
static void       closure_accel_activate (GClosure     *closure,
					  GValue       *return_value,
					  guint         n_param_values,
					  const GValue *param_values,
					  gpointer      invocation_hint,
					  gpointer      marshal_data);
206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222

static guint         action_signals[LAST_SIGNAL] = { 0 };


static void
gtk_action_class_init (GtkActionClass *klass)
{
  GObjectClass *gobject_class;

  gobject_class = G_OBJECT_CLASS (klass);

  gobject_class->finalize     = gtk_action_finalize;
  gobject_class->set_property = gtk_action_set_property;
  gobject_class->get_property = gtk_action_get_property;

  klass->activate = NULL;

223 224 225
  klass->create_menu_item  = create_menu_item;
  klass->create_tool_item  = create_tool_item;
  klass->create_menu       = NULL;
226
  G_GNUC_BEGIN_IGNORE_DEPRECATIONS;
227
  klass->menu_item_type    = GTK_TYPE_IMAGE_MENU_ITEM;
228
  G_GNUC_END_IGNORE_DEPRECATIONS;
229
  klass->toolbar_item_type = GTK_TYPE_TOOL_BUTTON;
230 231
  klass->connect_proxy    = connect_proxy;
  klass->disconnect_proxy = disconnect_proxy;
232

233 234 235 236 237
  /**
   * GtkAction:name:
   *
   * A unique name for the action.
   *
William Jon McCann's avatar
William Jon McCann committed
238
   * Deprecated: 3.10: Use #GAction:name instead
239
   */
240 241 242
  g_object_class_install_property (gobject_class,
				   PROP_NAME,
				   g_param_spec_string ("name",
243 244
							P_("Name"),
							P_("A unique name for the action."),
245
							NULL,
246 247
							GTK_PARAM_READWRITE | 
							G_PARAM_CONSTRUCT_ONLY));
248 249 250 251 252 253 254

  /**
   * GtkAction:label:
   *
   * The label used for menu items and buttons that activate
   * this action. If the label is %NULL, GTK+ uses the stock 
   * label specified via the stock-id property.
255 256 257
   *
   * This is an appearance property and thus only applies if 
   * #GtkActivatable:use-action-appearance is %TRUE.
258
   *
259
   * Deprecated: 3.10: Use the "label" attribute on #GMenuItem instead
260
   */
261 262 263
  g_object_class_install_property (gobject_class,
				   PROP_LABEL,
				   g_param_spec_string ("label",
264
							P_("Label"),
265 266
							P_("The label used for menu items and buttons "
							   "that activate this action."),
267
							NULL,
Matthias Clasen's avatar
Matthias Clasen committed
268
							GTK_PARAM_READWRITE));
269 270 271 272 273

  /**
   * GtkAction:short-label:
   *
   * A shorter label that may be used on toolbar buttons.
274 275 276
   *
   * This is an appearance property and thus only applies if 
   * #GtkActivatable:use-action-appearance is %TRUE.
277
   *
278 279
   * Deprecated: 3.10: There is no corresponding replacement when using
   * #GAction
280
   */
281 282
  g_object_class_install_property (gobject_class,
				   PROP_SHORT_LABEL,
283
				   g_param_spec_string ("short-label",
284 285
							P_("Short label"),
							P_("A shorter label that may be used on toolbar buttons."),
286
							NULL,
Matthias Clasen's avatar
Matthias Clasen committed
287
							GTK_PARAM_READWRITE));
288 289


290 291 292 293 294
  /**
   * GtkAction:tooltip:
   *
   * A tooltip for this action.
   *
295
   * Deprecated: 3.10: Use gtk_widget_set_tooltip_text() instead
296
   */
297 298 299
  g_object_class_install_property (gobject_class,
				   PROP_TOOLTIP,
				   g_param_spec_string ("tooltip",
300 301
							P_("Tooltip"),
							P_("A tooltip for this action."),
302
							NULL,
Matthias Clasen's avatar
Matthias Clasen committed
303
							GTK_PARAM_READWRITE));
304 305 306 307 308

  /**
   * GtkAction:stock-id:
   *
   * The stock icon displayed in widgets representing this action.
309 310 311
   *
   * This is an appearance property and thus only applies if 
   * #GtkActivatable:use-action-appearance is %TRUE.
312
   *
313 314
   * Deprecated: 3.10: There is no corresponding replacement when using
   * #GAction
315
   */
316 317
  g_object_class_install_property (gobject_class,
				   PROP_STOCK_ID,
318
				   g_param_spec_string ("stock-id",
319
							P_("Stock Icon"),
320 321
							P_("The stock icon displayed in widgets representing "
							   "this action."),
322
							NULL,
Matthias Clasen's avatar
Matthias Clasen committed
323
							GTK_PARAM_READWRITE));
324 325 326 327 328 329 330 331
  /**
   * GtkAction:gicon:
   *
   * The #GIcon displayed in the #GtkAction.
   *
   * Note that the stock icon is preferred, if the #GtkAction:stock-id 
   * property holds the id of an existing stock icon.
   *
332 333 334
   * This is an appearance property and thus only applies if 
   * #GtkActivatable:use-action-appearance is %TRUE.
   *
335
   * Since: 2.16
336
   *
337
   * Deprecated: 3.10: Use the "icon" attribute on a #GMenuItem instead
338 339 340 341 342 343 344
   */
  g_object_class_install_property (gobject_class,
				   PROP_GICON,
				   g_param_spec_object ("gicon",
							P_("GIcon"),
							P_("The GIcon being displayed"),
							G_TYPE_ICON,
Matthias Clasen's avatar
Matthias Clasen committed
345
 							GTK_PARAM_READWRITE));							
346
  /**
347
   * GtkAction:icon-name:
348 349
   *
   * The name of the icon from the icon theme. 
350 351 352 353
   * 
   * Note that the stock icon is preferred, if the #GtkAction:stock-id 
   * property holds the id of an existing stock icon, and the #GIcon is
   * preferred if the #GtkAction:gicon property is set. 
354
   *
355 356 357
   * This is an appearance property and thus only applies if 
   * #GtkActivatable:use-action-appearance is %TRUE.
   *
358
   * Since: 2.10
359
   *
360
   * Deprecated: 3.10: Use the "icon" attribute on a #GMenuItem instead
361 362 363 364 365 366 367
   */
  g_object_class_install_property (gobject_class,
				   PROP_ICON_NAME,
				   g_param_spec_string ("icon-name",
							P_("Icon Name"),
							P_("The name of the icon from the icon theme"),
							NULL,
Matthias Clasen's avatar
Matthias Clasen committed
368
 							GTK_PARAM_READWRITE));
369

370 371 372 373 374
  /**
   * GtkAction:visible-horizontal:
   *
   * Whether the toolbar item is visible when the toolbar is in a horizontal orientation.
   *
375 376
   * Deprecated: 3.10: There is no corresponding replacement when using
   * #GAction
377
   */
378 379
  g_object_class_install_property (gobject_class,
				   PROP_VISIBLE_HORIZONTAL,
380
				   g_param_spec_boolean ("visible-horizontal",
381
							 P_("Visible when horizontal"),
382 383 384
							 P_("Whether the toolbar item is visible when the toolbar "
							    "is in a horizontal orientation."),
							 TRUE,
Matthias Clasen's avatar
Matthias Clasen committed
385
							 GTK_PARAM_READWRITE));
386 387 388 389 390 391 392
  /**
   * GtkAction:visible-overflown:
   *
   * When %TRUE, toolitem proxies for this action are represented in the 
   * toolbar overflow menu.
   *
   * Since: 2.6
393
   *
394 395
   * Deprecated: 3.10: There is no corresponding replacement when using
   * #GAction
396 397 398
   */
  g_object_class_install_property (gobject_class,
				   PROP_VISIBLE_OVERFLOWN,
399
				   g_param_spec_boolean ("visible-overflown",
400 401 402
							 P_("Visible when overflown"),
							 P_("When TRUE, toolitem proxies for this action "
							    "are represented in the toolbar overflow menu."),
403
							 TRUE,
Matthias Clasen's avatar
Matthias Clasen committed
404
							 GTK_PARAM_READWRITE));
405 406 407 408 409 410

  /**
   * GtkAction:visible-vertical:
   *
   * Whether the toolbar item is visible when the toolbar is in a vertical orientation.
   *
411 412
   * Deprecated: 3.10: There is no corresponding replacement when using
   * #GAction
413
   */
414 415
  g_object_class_install_property (gobject_class,
				   PROP_VISIBLE_VERTICAL,
416
				   g_param_spec_boolean ("visible-vertical",
417
							 P_("Visible when vertical"),
418 419
							 P_("Whether the toolbar item is visible when the toolbar "
							    "is in a vertical orientation."),
420
							 TRUE,
Matthias Clasen's avatar
Matthias Clasen committed
421
							 GTK_PARAM_READWRITE));
422 423 424 425 426 427
  /**
   * GtkAction:is-important:
   *
   * Whether the action is considered important. When TRUE, toolitem
   * proxies for this action show text in GTK_TOOLBAR_BOTH_HORIZ mode.
   *
428 429
   * Deprecated: 3.10: There is no corresponding replacement when using
   * #GAction
430
   */
431 432
  g_object_class_install_property (gobject_class,
				   PROP_IS_IMPORTANT,
433
				   g_param_spec_boolean ("is-important",
434
							 P_("Is important"),
435 436 437
							 P_("Whether the action is considered important. "
							    "When TRUE, toolitem proxies for this action "
							    "show text in GTK_TOOLBAR_BOTH_HORIZ mode."),
438
							 FALSE,
Matthias Clasen's avatar
Matthias Clasen committed
439
							 GTK_PARAM_READWRITE));
440 441 442 443 444
  /**
   * GtkAction:hide-if-empty:
   *
   * When TRUE, empty menu proxies for this action are hidden.
   *
445 446
   * Deprecated: 3.10: There is no corresponding replacement when using
   * #GAction
447
   */
448 449
  g_object_class_install_property (gobject_class,
				   PROP_HIDE_IF_EMPTY,
450
				   g_param_spec_boolean ("hide-if-empty",
451 452
							 P_("Hide if empty"),
							 P_("When TRUE, empty menu proxies for this action are hidden."),
453
							 TRUE,
Matthias Clasen's avatar
Matthias Clasen committed
454
							 GTK_PARAM_READWRITE));
455 456 457 458 459
  /**
   * GtkAction:sensitive:
   *
   * Whether the action is enabled.
   *
William Jon McCann's avatar
William Jon McCann committed
460
   * Deprecated: 3.10: Use #GAction:enabled and #GSimpleAction:enabled
461
   * instead
462
   */
463 464 465
  g_object_class_install_property (gobject_class,
				   PROP_SENSITIVE,
				   g_param_spec_boolean ("sensitive",
466 467
							 P_("Sensitive"),
							 P_("Whether the action is enabled."),
468
							 TRUE,
Matthias Clasen's avatar
Matthias Clasen committed
469
							 GTK_PARAM_READWRITE));
470 471 472 473 474
  /**
   * GtkAction:visible:
   *
   * Whether the action is visible.
   *
475 476
   * Deprecated: 3.10: There is no corresponding replacement when using
   * #GAction
477
   */
478 479 480
  g_object_class_install_property (gobject_class,
				   PROP_VISIBLE,
				   g_param_spec_boolean ("visible",
481 482
							 P_("Visible"),
							 P_("Whether the action is visible."),
483
							 TRUE,
Matthias Clasen's avatar
Matthias Clasen committed
484
							 GTK_PARAM_READWRITE));
485 486 487 488 489 490
  /**
   * GtkAction:action-group:
   *
   * The GtkActionGroup this GtkAction is associated with, or NULL
   * (for internal use).
   *
491 492
   * Deprecated: 3.10: Lookup the #GAction using g_action_map_lookup_action()
   * instead
493
   */
494 495
  g_object_class_install_property (gobject_class,
				   PROP_ACTION_GROUP,
496
				   g_param_spec_object ("action-group",
497 498
							 P_("Action Group"),
							 P_("The GtkActionGroup this GtkAction is associated with, or NULL (for internal use)."),
499
							 GTK_TYPE_ACTION_GROUP,
500
							 GTK_PARAM_READWRITE));
501

502 503 504
  /**
   * GtkAction:always-show-image:
   *
505 506
   * If %TRUE, the action's menu item proxies will ignore the #GtkSettings:gtk-menu-images 
   * setting and always show their image, if available.
507 508 509 510 511
   *
   * Use this property if the menu item would be useless or hard to use
   * without their image. 
   *
   * Since: 2.20
512
   *
513 514
   * Deprecated: 3.10: There is no corresponding replacement when using
   * #GAction
515 516 517 518 519 520 521 522 523
   **/
  g_object_class_install_property (gobject_class,
                                   PROP_ALWAYS_SHOW_IMAGE,
                                   g_param_spec_boolean ("always-show-image",
                                                         P_("Always show image"),
                                                         P_("Whether the image will always be shown"),
                                                         FALSE,
                                                         GTK_PARAM_READWRITE | G_PARAM_CONSTRUCT));

Matthias Clasen's avatar
Matthias Clasen committed
524 525 526 527 528 529 530
  /**
   * GtkAction::activate:
   * @action: the #GtkAction
   *
   * The "activate" signal is emitted when the action is activated.
   *
   * Since: 2.4
531
   *
532
   * Deprecated: 3.10: Use #GSimpleAction::activate instead
Matthias Clasen's avatar
Matthias Clasen committed
533
   */
534
  action_signals[ACTIVATE] =
Matthias Clasen's avatar
Matthias Clasen committed
535
    g_signal_new (I_("activate"),
536 537 538 539 540 541 542 543 544 545 546
		  G_OBJECT_CLASS_TYPE (klass),
		  G_SIGNAL_RUN_FIRST | G_SIGNAL_NO_RECURSE,
		  G_STRUCT_OFFSET (GtkActionClass, activate),  NULL, NULL,
		  g_cclosure_marshal_VOID__VOID,
		  G_TYPE_NONE, 0);
}


static void
gtk_action_init (GtkAction *action)
{
547
  action->private_data = gtk_action_get_instance_private (action);
548 549 550 551 552 553

  action->private_data->name = NULL;
  action->private_data->label = NULL;
  action->private_data->short_label = NULL;
  action->private_data->tooltip = NULL;
  action->private_data->stock_id = NULL;
554
  action->private_data->icon_name = NULL;
555 556
  action->private_data->visible_horizontal = TRUE;
  action->private_data->visible_vertical   = TRUE;
557
  action->private_data->visible_overflown  = TRUE;
558
  action->private_data->is_important = FALSE;
559
  action->private_data->hide_if_empty = TRUE;
560
  action->private_data->always_show_image = FALSE;
561
  action->private_data->activate_blocked = FALSE;
562 563 564 565 566 567 568

  action->private_data->sensitive = TRUE;
  action->private_data->visible = TRUE;

  action->private_data->label_set = FALSE;
  action->private_data->short_label_set = FALSE;

569
  action->private_data->accel_count = 0;
570 571
  action->private_data->accel_group = NULL;
  action->private_data->accel_quark = 0;
572 573 574 575 576 577 578
  action->private_data->accel_closure = 
    g_closure_new_object (sizeof (GClosure), G_OBJECT (action));
  g_closure_set_marshal (action->private_data->accel_closure, 
			 closure_accel_activate);
  g_closure_ref (action->private_data->accel_closure);
  g_closure_sink (action->private_data->accel_closure);

579 580
  action->private_data->action_group = NULL;

581
  action->private_data->proxies = NULL;
582
  action->private_data->gicon = NULL;  
583 584
}

Johan Dahlin's avatar
Johan Dahlin committed
585 586 587 588 589 590 591 592 593 594 595 596 597
static void
gtk_action_buildable_init (GtkBuildableIface *iface)
{
  iface->set_name = gtk_action_buildable_set_name;
  iface->get_name = gtk_action_buildable_get_name;
}

static void
gtk_action_buildable_set_name (GtkBuildable *buildable,
			       const gchar  *name)
{
  GtkAction *action = GTK_ACTION (buildable);

598
  action->private_data->name = g_intern_string (name);
Johan Dahlin's avatar
Johan Dahlin committed
599 600 601 602 603 604 605 606 607 608
}

static const gchar *
gtk_action_buildable_get_name (GtkBuildable *buildable)
{
  GtkAction *action = GTK_ACTION (buildable);

  return action->private_data->name;
}

609 610 611
/**
 * gtk_action_new:
 * @name: A unique name for the action
612 613
 * @label: (allow-none): the label displayed in menu items and on buttons,
 *         or %NULL
Johan Dahlin's avatar
Johan Dahlin committed
614
 * @tooltip: (allow-none): a tooltip for the action, or %NULL
615 616
 * @stock_id: (allow-none): the stock icon to display in widgets representing
 *            the action, or %NULL
617 618 619 620
 *
 * Creates a new #GtkAction object. To add the action to a
 * #GtkActionGroup and set the accelerator for the action,
 * call gtk_action_group_add_action_with_accel().
Matthias Clasen's avatar
Matthias Clasen committed
621
 * See <xref linkend="XML-UI"/> for information on allowed action
622
 * names.
623 624 625 626
 *
 * Return value: a new #GtkAction
 *
 * Since: 2.4
627
 *
628 629
 * Deprecated: 3.10: Use #GAction instead, associating it to a widget with
 * #GtkActionable or creating a #GtkMenu with gtk_menu_new_from_model()
630 631 632 633 634 635 636
 */
GtkAction *
gtk_action_new (const gchar *name,
		const gchar *label,
		const gchar *tooltip,
		const gchar *stock_id)
{
637 638 639 640 641 642 643 644
  g_return_val_if_fail (name != NULL, NULL);

  return g_object_new (GTK_TYPE_ACTION,
                       "name", name,
		       "label", label,
		       "tooltip", tooltip,
		       "stock-id", stock_id,
		       NULL);
645 646
}

647 648 649 650 651 652 653 654 655 656
static void
gtk_action_finalize (GObject *object)
{
  GtkAction *action;
  action = GTK_ACTION (object);

  g_free (action->private_data->label);
  g_free (action->private_data->short_label);
  g_free (action->private_data->tooltip);
  g_free (action->private_data->stock_id);
657
  g_free (action->private_data->icon_name);
658 659 660
  
  if (action->private_data->gicon)
    g_object_unref (action->private_data->gicon);
661

662
  g_closure_unref (action->private_data->accel_closure);
663 664
  if (action->private_data->accel_group)
    g_object_unref (action->private_data->accel_group);
665

Matthias Clasen's avatar
Matthias Clasen committed
666
  G_OBJECT_CLASS (gtk_action_parent_class)->finalize (object);  
667 668 669 670 671 672 673 674 675 676 677 678 679 680 681
}

static void
gtk_action_set_property (GObject         *object,
			 guint            prop_id,
			 const GValue    *value,
			 GParamSpec      *pspec)
{
  GtkAction *action;
  
  action = GTK_ACTION (object);

  switch (prop_id)
    {
    case PROP_NAME:
682
      action->private_data->name = g_intern_string (g_value_get_string (value));
683 684
      break;
    case PROP_LABEL:
685
      gtk_action_set_label (action, g_value_get_string (value));
686 687
      break;
    case PROP_SHORT_LABEL:
688
      gtk_action_set_short_label (action, g_value_get_string (value));
689 690
      break;
    case PROP_TOOLTIP:
691
      gtk_action_set_tooltip (action, g_value_get_string (value));
692 693
      break;
    case PROP_STOCK_ID:
694
      gtk_action_set_stock_id (action, g_value_get_string (value));
695
      break;
696 697 698
    case PROP_GICON:
      gtk_action_set_gicon (action, g_value_get_object (value));
      break;
699 700 701
    case PROP_ICON_NAME:
      gtk_action_set_icon_name (action, g_value_get_string (value));
      break;
702
    case PROP_VISIBLE_HORIZONTAL:
703
      gtk_action_set_visible_horizontal (action, g_value_get_boolean (value));
704 705
      break;
    case PROP_VISIBLE_VERTICAL:
706
      gtk_action_set_visible_vertical (action, g_value_get_boolean (value));
707
      break;
708 709 710
    case PROP_VISIBLE_OVERFLOWN:
      action->private_data->visible_overflown = g_value_get_boolean (value);
      break;
711
    case PROP_IS_IMPORTANT:
712
      gtk_action_set_is_important (action, g_value_get_boolean (value));
713
      break;
714 715 716
    case PROP_HIDE_IF_EMPTY:
      action->private_data->hide_if_empty = g_value_get_boolean (value);
      break;
717
    case PROP_SENSITIVE:
718
      gtk_action_set_sensitive (action, g_value_get_boolean (value));
719 720
      break;
    case PROP_VISIBLE:
721
      gtk_action_set_visible (action, g_value_get_boolean (value));
722
      break;
723 724 725
    case PROP_ACTION_GROUP:
      gtk_action_set_action_group (action, g_value_get_object (value));
      break;
726 727 728
    case PROP_ALWAYS_SHOW_IMAGE:
      gtk_action_set_always_show_image (action, g_value_get_boolean (value));
      break;
729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747
    default:
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
      break;
    }
}

static void
gtk_action_get_property (GObject    *object,
			 guint       prop_id,
			 GValue     *value,
			 GParamSpec *pspec)
{
  GtkAction *action;

  action = GTK_ACTION (object);

  switch (prop_id)
    {
    case PROP_NAME:
748
      g_value_set_static_string (value, action->private_data->name);
749 750 751 752 753 754 755 756 757 758 759 760 761
      break;
    case PROP_LABEL:
      g_value_set_string (value, action->private_data->label);
      break;
    case PROP_SHORT_LABEL:
      g_value_set_string (value, action->private_data->short_label);
      break;
    case PROP_TOOLTIP:
      g_value_set_string (value, action->private_data->tooltip);
      break;
    case PROP_STOCK_ID:
      g_value_set_string (value, action->private_data->stock_id);
      break;
762 763 764
    case PROP_ICON_NAME:
      g_value_set_string (value, action->private_data->icon_name);
      break;
765 766 767
    case PROP_GICON:
      g_value_set_object (value, action->private_data->gicon);
      break;
768 769 770 771 772 773
    case PROP_VISIBLE_HORIZONTAL:
      g_value_set_boolean (value, action->private_data->visible_horizontal);
      break;
    case PROP_VISIBLE_VERTICAL:
      g_value_set_boolean (value, action->private_data->visible_vertical);
      break;
774 775 776
    case PROP_VISIBLE_OVERFLOWN:
      g_value_set_boolean (value, action->private_data->visible_overflown);
      break;
777 778 779
    case PROP_IS_IMPORTANT:
      g_value_set_boolean (value, action->private_data->is_important);
      break;
780 781 782
    case PROP_HIDE_IF_EMPTY:
      g_value_set_boolean (value, action->private_data->hide_if_empty);
      break;
783 784 785 786 787 788
    case PROP_SENSITIVE:
      g_value_set_boolean (value, action->private_data->sensitive);
      break;
    case PROP_VISIBLE:
      g_value_set_boolean (value, action->private_data->visible);
      break;
789 790 791
    case PROP_ACTION_GROUP:
      g_value_set_object (value, action->private_data->action_group);
      break;
792 793 794
    case PROP_ALWAYS_SHOW_IMAGE:
      g_value_set_boolean (value, action->private_data->always_show_image);
      break;
795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821
    default:
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
      break;
    }
}

static GtkWidget *
create_menu_item (GtkAction *action)
{
  GType menu_item_type;

  menu_item_type = GTK_ACTION_GET_CLASS (action)->menu_item_type;

  return g_object_new (menu_item_type, NULL);
}

static GtkWidget *
create_tool_item (GtkAction *action)
{
  GType toolbar_item_type;

  toolbar_item_type = GTK_ACTION_GET_CLASS (action)->toolbar_item_type;

  return g_object_new (toolbar_item_type, NULL);
}

static void
822 823
remove_proxy (GtkAction *action,
	      GtkWidget *proxy)
824
{
825
  g_object_unref (proxy);
826
  action->private_data->proxies = g_slist_remove (action->private_data->proxies, proxy);
827 828
}

829 830 831 832 833 834
static void
connect_proxy (GtkAction *action,
	       GtkWidget *proxy)
{
  action->private_data->proxies = g_slist_prepend (action->private_data->proxies, proxy);

835 836
  g_object_ref_sink (proxy);

837 838 839 840 841 842 843 844 845 846 847 848 849 850 851
  if (action->private_data->action_group)
    _gtk_action_group_emit_connect_proxy (action->private_data->action_group, action, proxy);

}

static void
disconnect_proxy (GtkAction *action,
		  GtkWidget *proxy)
{
  remove_proxy (action, proxy);

  if (action->private_data->action_group)
    _gtk_action_group_emit_disconnect_proxy (action->private_data->action_group, action, proxy);
}

852 853
/**
 * _gtk_action_sync_menu_visible:
Johan Dahlin's avatar
Johan Dahlin committed
854
 * @action: (allow-none): a #GtkAction, or %NULL to determine the action from @proxy
855 856 857 858 859
 * @proxy: a proxy menu item
 * @empty: whether the submenu attached to @proxy is empty
 * 
 * Updates the visibility of @proxy from the visibility of @action
 * according to the following rules:
860 861 862

 * - if @action is invisible, @proxy is too
 *
William Jon McCann's avatar
William Jon McCann committed
863
 * - if @empty is %TRUE, hide @proxy unless the “hide-if-empty”
864
 *   property of @action indicates otherwise
865
 *
866
 * This function is used in the implementation of #GtkUIManager.
867 868
 *
 * Deprecated: 3.10
869 870 871 872 873 874
 **/
void
_gtk_action_sync_menu_visible (GtkAction *action,
			       GtkWidget *proxy,
			       gboolean   empty)
{
875 876
  gboolean visible = TRUE;
  gboolean hide_if_empty = TRUE;
877 878 879

  g_return_if_fail (GTK_IS_MENU_ITEM (proxy));
  g_return_if_fail (action == NULL || GTK_IS_ACTION (action));
880

881
  if (action == NULL)
882
    action = gtk_activatable_get_related_action (GTK_ACTIVATABLE (proxy));
883

884 885 886 887 888 889
  if (action)
    {
      /* a GtkMenu for a <popup/> doesn't have to have an action */
      visible = gtk_action_is_visible (action);
      hide_if_empty = action->private_data->hide_if_empty;
    }
890

891 892 893 894
  if (visible && !(empty && hide_if_empty))
    gtk_widget_show (proxy);
  else
    gtk_widget_hide (proxy);
895 896
}

897 898 899
void
_gtk_action_emit_activate (GtkAction *action)
{
900 901
  GtkActionGroup *group = action->private_data->action_group;

902
  if (group != NULL)
Matthias Clasen's avatar
Matthias Clasen committed
903
    {
904
      g_object_ref (action);
Matthias Clasen's avatar
Matthias Clasen committed
905 906 907
      g_object_ref (group);
      _gtk_action_group_emit_pre_activate (group, action);
    }
908

909
  g_signal_emit (action, action_signals[ACTIVATE], 0);
910

911
  if (group != NULL)
Matthias Clasen's avatar
Matthias Clasen committed
912 913 914
    {
      _gtk_action_group_emit_post_activate (group, action);
      g_object_unref (group);
915
      g_object_unref (action);
Matthias Clasen's avatar
Matthias Clasen committed
916
    }
917 918
}

919 920 921 922
/**
 * gtk_action_activate:
 * @action: the action object
 *
William Jon McCann's avatar
William Jon McCann committed
923
 * Emits the “activate” signal on the specified action, if it isn't
924 925
 * insensitive. This gets called by the proxy widgets when they get 
 * activated.
926 927 928 929
 *
 * It can also be used to manually activate an action.
 *
 * Since: 2.4
930
 *
931
 * Deprecated: 3.10: Use g_action_group_activate_action() on a #GAction instead
932 933 934 935
 */
void
gtk_action_activate (GtkAction *action)
{
936 937
  g_return_if_fail (GTK_IS_ACTION (action));
  
938 939 940 941
  if (action->private_data->activate_blocked)
    return;

  if (gtk_action_is_sensitive (action))
942
    _gtk_action_emit_activate (action);
943 944
}

945 946
/**
 * gtk_action_block_activate:
Matthias Clasen's avatar
2.15.3  
Matthias Clasen committed
947
 * @action: a #GtkAction
948 949 950 951 952 953 954
 *
 * Disable activation signals from the action 
 *
 * This is needed when updating the state of your proxy
 * #GtkActivatable widget could result in calling gtk_action_activate(),
 * this is a convenience function to avoid recursing in those
 * cases (updating toggle state for instance).
Matthias Clasen's avatar
2.15.3  
Matthias Clasen committed
955 956
 *
 * Since: 2.16
957
 *
958 959
 * Deprecated: 3.10: Use g_simple_action_set_enabled() to disable the
 * #GSimpleAction instead
960 961 962 963 964 965 966 967 968 969 970
 */
void
gtk_action_block_activate (GtkAction *action)
{
  g_return_if_fail (GTK_IS_ACTION (action));

  action->private_data->activate_blocked = TRUE;
}

/**
 * gtk_action_unblock_activate:
Matthias Clasen's avatar
2.15.3  
Matthias Clasen committed
971
 * @action: a #GtkAction
972 973
 *
 * Reenable activation signals from the action 
Matthias Clasen's avatar
2.15.3  
Matthias Clasen committed
974 975
 *
 * Since: 2.16
976
 *
977 978
 * Deprecated: 3.10: Use g_simple_action_set_enabled() to enable the
 * #GSimpleAction instead
979 980 981 982 983 984 985 986 987
 */
void
gtk_action_unblock_activate (GtkAction *action)
{
  g_return_if_fail (GTK_IS_ACTION (action));

  action->private_data->activate_blocked = FALSE;
}

988 989 990
/**
 * gtk_action_create_icon:
 * @action: the action object
991
 * @icon_size: (type int): the size of the icon that should be created.
992 993 994 995
 *
 * This function is intended for use by action implementations to
 * create icons displayed in the proxy widgets.
 *
996
 * Returns: (transfer none): a widget that displays the icon for this action.
997 998
 *
 * Since: 2.4
999
 *
1000 1001
 * Deprecated: 3.10: Use g_menu_item_set_icon() to set an icon on a #GMenuItem,
 * or gtk_container_add() to add a #GtkImage to a #GtkButton
1002 1003 1004 1005
 */
GtkWidget *
gtk_action_create_icon (GtkAction *action, GtkIconSize icon_size)
{
1006 1007
  GtkWidget *widget = NULL;

1008 1009
  g_return_val_if_fail (GTK_IS_ACTION (action), NULL);

1010 1011
  G_GNUC_BEGIN_IGNORE_DEPRECATIONS;

1012 1013
  if (action->private_data->stock_id &&
      gtk_icon_factory_lookup_default (action->private_data->stock_id))
1014
    widget = gtk_image_new_from_stock (action->private_data->stock_id, icon_size);
1015
  else if (action->private_data->gicon)
1016
    widget = gtk_image_new_from_gicon (action->private_data->gicon, icon_size);
1017
  else if (action->private_data->icon_name)
1018 1019 1020 1021 1022
    widget = gtk_image_new_from_icon_name (action->private_data->icon_name, icon_size);

  G_GNUC_END_IGNORE_DEPRECATIONS;

  return widget;
1023 1024 1025 1026 1027 1028 1029 1030
}

/**
 * gtk_action_create_menu_item:
 * @action: the action object
 *
 * Creates a menu item widget that proxies for the given action.
 *
1031
 * Returns: (transfer none): a menu item connected to the action.
1032 1033
 *
 * Since: 2.4
1034
 *
1035 1036
 * Deprecated: 3.10: Use g_menu_item_new() and associate it with a #GAction
 * instead.
1037 1038 1039 1040 1041 1042 1043 1044
 */
GtkWidget *
gtk_action_create_menu_item (GtkAction *action)
{
  GtkWidget *menu_item;

  g_return_val_if_fail (GTK_IS_ACTION (action), NULL);

1045
  menu_item = GTK_ACTION_GET_CLASS (action)->create_menu_item (action);
1046

1047 1048
  gtk_activatable_set_use_action_appearance (GTK_ACTIVATABLE (menu_item), TRUE);
  gtk_activatable_set_related_action (GTK_ACTIVATABLE (menu_item), action);
1049 1050 1051 1052 1053 1054 1055 1056 1057 1058

  return menu_item;
}

/**
 * gtk_action_create_tool_item:
 * @action: the action object
 *
 * Creates a toolbar item widget that proxies for the given action.
 *