2 * Copyright (C) 2008 Tristan Van Berkom <tristan.van.berkom@gmail.com>
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Library General Public
6 * License as published by the Free Software Foundation; either
7 * version 2 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Library General Public License for more details.
14 * You should have received a copy of the GNU Library General Public
15 * License along with this library; if not, write to the
16 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17 * Boston, MA 02111-1307, USA.
21 * SECTION:gtkactivatable
22 * @Short_Description: An interface for activatable widgets
23 * @Title: GtkActivatable
25 * Activatable widgets can be connected to a #GtkAction and reflects
26 * the state of its action. A #GtkActivatable can also provide feedback
27 * through its action, as they are responsible for activating their
31 * <title>Implementing GtkActivatable</title>
33 * When extending a class that is already #GtkActivatable; it is only
34 * necessary to implement the #GtkActivatable->sync_action_properties()
35 * and #GtkActivatable->update() methods and chain up to the parent
36 * implementation, however when introducing
37 * a new #GtkActivatable class; the #GtkActivatable:related-action and
38 * #GtkActivatable:use-action-appearance properties need to be handled by
39 * the implementor. Handling these properties is mostly a matter of installing
40 * the action pointer and boolean flag on your instance, and calling
41 * gtk_activatable_do_set_related_action() and
42 * gtk_activatable_sync_action_properties() at the appropriate times.
45 * <title>A class fragment implementing #GtkActivatable</title>
46 * <programlisting><![CDATA[
51 * PROP_ACTIVATABLE_RELATED_ACTION,
52 * PROP_ACTIVATABLE_USE_ACTION_APPEARANCE
55 * struct _FooBarPrivate
61 * gboolean use_action_appearance;
66 * static void foo_bar_activatable_interface_init (GtkActivatableIface *iface);
67 * static void foo_bar_activatable_update (GtkActivatable *activatable,
69 * const gchar *property_name);
70 * static void foo_bar_activatable_sync_action_properties (GtkActivatable *activatable,
76 * foo_bar_class_init (FooBarClass *klass)
81 * g_object_class_override_property (gobject_class, PROP_ACTIVATABLE_RELATED_ACTION, "related-action");
82 * g_object_class_override_property (gobject_class, PROP_ACTIVATABLE_USE_ACTION_APPEARANCE, "use-action-appearance");
89 * foo_bar_activatable_interface_init (GtkActivatableIface *iface)
91 * iface->update = foo_bar_activatable_update;
92 * iface->sync_action_properties = foo_bar_activatable_sync_action_properties;
95 * ... Break the reference using gtk_activatable_do_set_related_action()...
98 * foo_bar_dispose (GObject *object)
100 * FooBar *bar = FOO_BAR (object);
101 * FooBarPrivate *priv = FOO_BAR_GET_PRIVATE (bar);
107 * gtk_activatable_do_set_related_action (GTK_ACTIVATABLE (bar), NULL);
108 * priv->action = NULL;
110 * G_OBJECT_CLASS (foo_bar_parent_class)->dispose (object);
113 * ... Handle the "related-action" and "use-action-appearance" properties ...
116 * foo_bar_set_property (GObject *object,
118 * const GValue *value,
121 * FooBar *bar = FOO_BAR (object);
122 * FooBarPrivate *priv = FOO_BAR_GET_PRIVATE (bar);
129 * case PROP_ACTIVATABLE_RELATED_ACTION:
130 * foo_bar_set_related_action (bar, g_value_get_object (value));
132 * case PROP_ACTIVATABLE_USE_ACTION_APPEARANCE:
133 * foo_bar_set_use_action_appearance (bar, g_value_get_boolean (value));
136 * G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
142 * foo_bar_get_property (GObject *object,
147 * FooBar *bar = FOO_BAR (object);
148 * FooBarPrivate *priv = FOO_BAR_GET_PRIVATE (bar);
155 * case PROP_ACTIVATABLE_RELATED_ACTION:
156 * g_value_set_object (value, priv->action);
158 * case PROP_ACTIVATABLE_USE_ACTION_APPEARANCE:
159 * g_value_set_boolean (value, priv->use_action_appearance);
162 * G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
169 * foo_bar_set_use_action_appearance (FooBar *bar,
170 * gboolean use_appearance)
172 * FooBarPrivate *priv = FOO_BAR_GET_PRIVATE (bar);
174 * if (priv->use_action_appearance != use_appearance)
176 * priv->use_action_appearance = use_appearance;
178 * gtk_activatable_sync_action_properties (GTK_ACTIVATABLE (bar), priv->action);
182 * ... call gtk_activatable_do_set_related_action() and then assign the action pointer,
183 * no need to reference the action here since gtk_activatable_do_set_related_action() already
184 * holds a reference here for you...
186 * foo_bar_set_related_action (FooBar *bar,
189 * FooBarPrivate *priv = FOO_BAR_GET_PRIVATE (bar);
191 * if (priv->action == action)
194 * gtk_activatable_do_set_related_action (GTK_ACTIVATABLE (bar), action);
196 * priv->action = action;
199 * ... Selectively reset and update activatable depending on the use-action-appearance property ...
201 * gtk_button_activatable_sync_action_properties (GtkActivatable *activatable,
204 * GtkButtonPrivate *priv = GTK_BUTTON_GET_PRIVATE (activatable);
209 * if (gtk_action_is_visible (action))
210 * gtk_widget_show (GTK_WIDGET (activatable));
212 * gtk_widget_hide (GTK_WIDGET (activatable));
214 * gtk_widget_set_sensitive (GTK_WIDGET (activatable), gtk_action_is_sensitive (action));
218 * if (priv->use_action_appearance)
220 * if (gtk_action_get_stock_id (action))
221 * foo_bar_set_stock (button, gtk_action_get_stock_id (action));
222 * else if (gtk_action_get_label (action))
223 * foo_bar_set_label (button, gtk_action_get_label (action));
231 * foo_bar_activatable_update (GtkActivatable *activatable,
233 * const gchar *property_name)
235 * FooBarPrivate *priv = FOO_BAR_GET_PRIVATE (activatable);
237 * if (strcmp (property_name, "visible") == 0)
239 * if (gtk_action_is_visible (action))
240 * gtk_widget_show (GTK_WIDGET (activatable));
242 * gtk_widget_hide (GTK_WIDGET (activatable));
244 * else if (strcmp (property_name, "sensitive") == 0)
245 * gtk_widget_set_sensitive (GTK_WIDGET (activatable), gtk_action_is_sensitive (action));
249 * if (!priv->use_action_appearance)
252 * if (strcmp (property_name, "stock-id") == 0)
253 * foo_bar_set_stock (button, gtk_action_get_stock_id (action));
254 * else if (strcmp (property_name, "label") == 0)
255 * foo_bar_set_label (button, gtk_action_get_label (action));
258 * }]]></programlisting>
264 #include "gtkactivatable.h"
265 #include "gtkactiongroup.h"
266 #include "gtktypeutils.h"
267 #include "gtkprivate.h"
271 static void gtk_activatable_class_init (gpointer g_iface);
274 gtk_activatable_get_type (void)
276 static GType activatable_type = 0;
278 if (!activatable_type) {
280 g_type_register_static_simple (G_TYPE_INTERFACE, I_("GtkActivatable"),
281 sizeof (GtkActivatableIface),
282 (GClassInitFunc) gtk_activatable_class_init,
285 g_type_interface_add_prerequisite (activatable_type, G_TYPE_OBJECT);
288 return activatable_type;
292 gtk_activatable_class_init (gpointer g_iface)
295 * GtkActivatable:related-action:
297 * The action that this activatable will activate and receive
298 * updates from for various states and possibly appearance.
300 * <note><para>#GtkActivatable implementors need to handle the this property and
301 * call gtk_activatable_do_set_related_action() when it changes.</para></note>
305 g_object_interface_install_property (g_iface,
306 g_param_spec_object ("related-action",
307 P_("Related Action"),
308 P_("The action this activatable will activate and receive updates from"),
310 GTK_PARAM_READWRITE));
313 * GtkActivatable:use-action-appearance:
315 * Whether this activatable should reset its layout
316 * and appearance when setting the related action or when
317 * the action changes appearance.
319 * See the #GtkAction documentation directly to find which properties
320 * should be ignored by the #GtkActivatable when this property is %FALSE.
322 * <note><para>#GtkActivatable implementors need to handle this property
323 * and call gtk_activatable_sync_action_properties() on the activatable
324 * widget when it changes.</para></note>
328 g_object_interface_install_property (g_iface,
329 g_param_spec_boolean ("use-action-appearance",
330 P_("Use Action Appearance"),
331 P_("Whether to use the related actions appearance properties"),
333 GTK_PARAM_READWRITE));
339 gtk_activatable_update (GtkActivatable *activatable,
341 const gchar *property_name)
343 GtkActivatableIface *iface;
345 g_return_if_fail (GTK_IS_ACTIVATABLE (activatable));
347 iface = GTK_ACTIVATABLE_GET_IFACE (activatable);
349 iface->update (activatable, action, property_name);
351 g_critical ("GtkActivatable->update() unimplemented for type %s",
352 g_type_name (G_OBJECT_TYPE (activatable)));
356 * gtk_activatable_sync_action_properties:
357 * @activatable: a #GtkActivatable
358 * @action: (allow-none): the related #GtkAction or %NULL
360 * This is called to update the activatable completely, this is called
361 * internally when the #GtkActivatable::related-action property is set
362 * or unset and by the implementing class when
363 * #GtkActivatable::use-action-appearance changes.
368 gtk_activatable_sync_action_properties (GtkActivatable *activatable,
371 GtkActivatableIface *iface;
373 g_return_if_fail (GTK_IS_ACTIVATABLE (activatable));
375 iface = GTK_ACTIVATABLE_GET_IFACE (activatable);
376 if (iface->sync_action_properties)
377 iface->sync_action_properties (activatable, action);
379 g_critical ("GtkActivatable->sync_action_properties() unimplemented for type %s",
380 g_type_name (G_OBJECT_TYPE (activatable)));
385 * gtk_activatable_set_related_action:
386 * @activatable: a #GtkActivatable
387 * @action: the #GtkAction to set
389 * Sets the related action on the @activatable object.
391 * <note><para>#GtkActivatable implementors need to handle the #GtkActivatable:related-action
392 * property and call gtk_activatable_do_set_related_action() when it changes.</para></note>
397 gtk_activatable_set_related_action (GtkActivatable *activatable,
400 g_return_if_fail (GTK_IS_ACTIVATABLE (activatable));
401 g_return_if_fail (action == NULL || GTK_IS_ACTION (action));
403 g_object_set (activatable, "related-action", action, NULL);
407 gtk_activatable_action_notify (GtkAction *action,
409 GtkActivatable *activatable)
411 gtk_activatable_update (activatable, action, pspec->name);
415 * gtk_activatable_do_set_related_action:
416 * @activatable: a #GtkActivatable
417 * @action: the #GtkAction to set
419 * This is a utility function for #GtkActivatable implementors.
421 * When implementing #GtkActivatable you must call this when
422 * handling changes of the #GtkActivatable:related-action, and
423 * you must also use this to break references in #GObject->dispose().
425 * This function adds a reference to the currently set related
426 * action for you, it also makes sure the #GtkActivatable->update()
427 * method is called when the related #GtkAction properties change
428 * and registers to the action's proxy list.
430 * <note><para>Be careful to call this before setting the local
431 * copy of the #GtkAction property, since this function uses
432 * gtk_activatable_get_action() to retrieve the previous action</para></note>
437 gtk_activatable_do_set_related_action (GtkActivatable *activatable,
440 GtkAction *prev_action;
442 prev_action = gtk_activatable_get_related_action (activatable);
444 if (prev_action != action)
448 g_signal_handlers_disconnect_by_func (prev_action, gtk_activatable_action_notify, activatable);
450 /* Check the type so that actions can be activatable too. */
451 if (GTK_IS_WIDGET (activatable))
452 _gtk_action_remove_from_proxy_list (prev_action, GTK_WIDGET (activatable));
454 /* Some apps are using the object data directly...
455 * so continue to set it for a bit longer
457 g_object_set_data (G_OBJECT (activatable), "gtk-action", NULL);
460 * We don't want prev_action to be activated
461 * during the sync_action_properties() call when syncing "active".
463 gtk_action_block_activate (prev_action);
466 /* Some applications rely on their proxy UI to be set up
467 * before they receive the ::connect-proxy signal, so we
468 * need to call sync_action_properties() before add_to_proxy_list().
470 gtk_activatable_sync_action_properties (activatable, action);
474 gtk_action_unblock_activate (prev_action);
475 g_object_unref (prev_action);
480 g_object_ref (action);
482 g_signal_connect (G_OBJECT (action), "notify", G_CALLBACK (gtk_activatable_action_notify), activatable);
484 if (GTK_IS_WIDGET (activatable))
485 _gtk_action_add_to_proxy_list (action, GTK_WIDGET (activatable));
487 g_object_set_data (G_OBJECT (activatable), "gtk-action", action);
493 * gtk_activatable_get_related_action:
494 * @activatable: a #GtkActivatable
496 * Gets the related #GtkAction for @activatable.
498 * Returns: the related #GtkAction if one is set.
503 gtk_activatable_get_related_action (GtkActivatable *activatable)
507 g_return_val_if_fail (GTK_IS_ACTIVATABLE (activatable), NULL);
509 g_object_get (activatable, "related-action", &action, NULL);
511 /* g_object_get() gives us a ref... */
513 g_object_unref (action);
519 * gtk_activatable_set_use_action_appearance:
520 * @activatable: a #GtkActivatable
521 * @use_appearance: whether to use the actions appearance
523 * Sets whether this activatable should reset its layout and appearance
524 * when setting the related action or when the action changes appearance
526 * <note><para>#GtkActivatable implementors need to handle the
527 * #GtkActivatable:use-action-appearance property and call
528 * gtk_activatable_sync_action_properties() to update @activatable
529 * if needed.</para></note>
534 gtk_activatable_set_use_action_appearance (GtkActivatable *activatable,
535 gboolean use_appearance)
537 g_object_set (activatable, "use-action-appearance", use_appearance, NULL);
541 * gtk_activatable_get_use_action_appearance:
542 * @activatable: a #GtkActivatable
544 * Gets whether this activatable should reset its layout
545 * and appearance when setting the related action or when
546 * the action changes appearance.
548 * Returns: whether @activatable uses its actions appearance.
553 gtk_activatable_get_use_action_appearance (GtkActivatable *activatable)
555 gboolean use_appearance;
557 g_object_get (activatable, "use-action-appearance", &use_appearance, NULL);
559 return use_appearance;