forked from AuroraMiddleware/gtk
Add new GtkActionable interface
This is the interface for GtkWidgets that can be associated with an action on a GtkAppicationWindow or associated GtkApplication. It essentially features 'action-name' and 'action-target' properties with some associated convenience API. This interface is implemented by GtkButton and GtkToolButton. https://bugzilla.gnome.org/show_bug.cgi?id=667394
This commit is contained in:
parent
a3629592d3
commit
88ec007b98
@ -172,6 +172,7 @@ gtk_public_h_sources = \
|
||||
gtkaccellabel.h \
|
||||
gtkaccelmap.h \
|
||||
gtkaccessible.h \
|
||||
gtkactionable.h \
|
||||
gtkaction.h \
|
||||
gtkactiongroup.h \
|
||||
gtkactivatable.h \
|
||||
@ -392,6 +393,7 @@ gtk_private_type_h_sources = \
|
||||
# GTK+ header files that don't get installed
|
||||
gtk_private_h_sources = \
|
||||
gactionmuxer.h \
|
||||
gsimpleactionobserver.h \
|
||||
gactionobserver.h \
|
||||
gactionobservable.h \
|
||||
gtkapplicationprivate.h \
|
||||
@ -512,8 +514,10 @@ deprecated_c_sources = \
|
||||
gtk_base_c_sources = \
|
||||
$(deprecated_c_sources) \
|
||||
gactionmuxer.c \
|
||||
gsimpleactionobserver.c \
|
||||
gactionobserver.c \
|
||||
gactionobservable.c \
|
||||
gtkactionable.c \
|
||||
gtkquery.c \
|
||||
gtksearchengine.c \
|
||||
gtksearchenginesimple.c \
|
||||
|
288
gtk/gsimpleactionobserver.c
Normal file
288
gtk/gsimpleactionobserver.c
Normal file
@ -0,0 +1,288 @@
|
||||
/*
|
||||
* Copyright © 2012 Canonical Limited
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as
|
||||
* published by the Free Software Foundation; either version 2 of the
|
||||
* licence 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
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307,
|
||||
* USA.
|
||||
*
|
||||
* Authors: Ryan Lortie <desrt@desrt.ca>
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "gsimpleactionobserver.h"
|
||||
#include "gactionobservable.h"
|
||||
|
||||
typedef GObjectClass GSimpleActionObserverClass;
|
||||
struct _GSimpleActionObserver
|
||||
{
|
||||
GObject parent_instance;
|
||||
|
||||
GActionGroup *action_group;
|
||||
gchar *action_name;
|
||||
GVariant *target;
|
||||
|
||||
gboolean can_activate;
|
||||
gboolean active;
|
||||
gboolean enabled;
|
||||
|
||||
gint reporting;
|
||||
};
|
||||
|
||||
static void g_simple_action_observer_init_iface (GActionObserverInterface *iface);
|
||||
G_DEFINE_TYPE_WITH_CODE (GSimpleActionObserver, g_simple_action_observer, G_TYPE_OBJECT,
|
||||
G_IMPLEMENT_INTERFACE (G_TYPE_ACTION_OBSERVER, g_simple_action_observer_init_iface));
|
||||
|
||||
enum
|
||||
{
|
||||
PROP_0,
|
||||
PROP_ACTIVE,
|
||||
PROP_ENABLED,
|
||||
N_PROPS
|
||||
};
|
||||
|
||||
static GParamSpec *g_simple_action_observer_pspecs[N_PROPS];
|
||||
|
||||
static void
|
||||
g_simple_action_observer_action_added (GActionObserver *g_observer,
|
||||
GActionObservable *observable,
|
||||
const gchar *action_name,
|
||||
const GVariantType *parameter_type,
|
||||
gboolean enabled,
|
||||
GVariant *state)
|
||||
{
|
||||
GSimpleActionObserver *observer = G_SIMPLE_ACTION_OBSERVER (g_observer);
|
||||
gboolean active;
|
||||
|
||||
/* we can only activate if we have the correct type of parameter */
|
||||
observer->can_activate = (observer->target == NULL && parameter_type == NULL) ||
|
||||
(observer->target != NULL && parameter_type != NULL &&
|
||||
g_variant_is_of_type (observer->target, parameter_type));
|
||||
|
||||
if (observer->can_activate)
|
||||
{
|
||||
if (observer->target != NULL && state != NULL)
|
||||
active = g_variant_equal (state, observer->target);
|
||||
|
||||
else if (state != NULL && g_variant_is_of_type (state, G_VARIANT_TYPE_BOOLEAN))
|
||||
active = g_variant_get_boolean (state);
|
||||
|
||||
else
|
||||
active = FALSE;
|
||||
|
||||
if (active != observer->active)
|
||||
{
|
||||
observer->active = active;
|
||||
observer->reporting++;
|
||||
g_object_notify_by_pspec (G_OBJECT (observer), g_simple_action_observer_pspecs[PROP_ACTIVE]);
|
||||
observer->reporting--;
|
||||
}
|
||||
|
||||
if (enabled != observer->enabled)
|
||||
{
|
||||
observer->enabled = enabled;
|
||||
g_object_notify_by_pspec (G_OBJECT (observer), g_simple_action_observer_pspecs[PROP_ENABLED]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
g_simple_action_observer_action_enabled_changed (GActionObserver *g_observer,
|
||||
GActionObservable *observable,
|
||||
const gchar *action_name,
|
||||
gboolean enabled)
|
||||
{
|
||||
GSimpleActionObserver *observer = G_SIMPLE_ACTION_OBSERVER (g_observer);
|
||||
|
||||
if (!observer->can_activate)
|
||||
return;
|
||||
|
||||
if (enabled != observer->enabled)
|
||||
{
|
||||
observer->enabled = enabled;
|
||||
g_object_notify_by_pspec (G_OBJECT (observer), g_simple_action_observer_pspecs[PROP_ENABLED]);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
g_simple_action_observer_action_state_changed (GActionObserver *g_observer,
|
||||
GActionObservable *observable,
|
||||
const gchar *action_name,
|
||||
GVariant *state)
|
||||
{
|
||||
GSimpleActionObserver *observer = G_SIMPLE_ACTION_OBSERVER (g_observer);
|
||||
gboolean active = FALSE;
|
||||
|
||||
if (!observer->can_activate)
|
||||
return;
|
||||
|
||||
if (observer->target)
|
||||
active = g_variant_equal (state, observer->target);
|
||||
|
||||
else if (g_variant_is_of_type (state, G_VARIANT_TYPE_BOOLEAN))
|
||||
active = g_variant_get_boolean (state);
|
||||
|
||||
if (active != observer->active)
|
||||
{
|
||||
observer->active = active;
|
||||
observer->reporting++;
|
||||
g_object_notify_by_pspec (G_OBJECT (observer), g_simple_action_observer_pspecs[PROP_ACTIVE]);
|
||||
observer->reporting--;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
g_simple_action_observer_action_removed (GActionObserver *g_observer,
|
||||
GActionObservable *observable,
|
||||
const gchar *action_name)
|
||||
{
|
||||
GSimpleActionObserver *observer = G_SIMPLE_ACTION_OBSERVER (g_observer);
|
||||
|
||||
if (!observer->can_activate)
|
||||
return;
|
||||
|
||||
observer->can_activate = FALSE;
|
||||
|
||||
if (observer->active)
|
||||
{
|
||||
observer->active = FALSE;
|
||||
observer->reporting++;
|
||||
g_object_notify_by_pspec (G_OBJECT (observer), g_simple_action_observer_pspecs[PROP_ACTIVE]);
|
||||
observer->reporting--;
|
||||
}
|
||||
|
||||
if (observer->enabled)
|
||||
{
|
||||
observer->enabled = FALSE;
|
||||
g_object_notify_by_pspec (G_OBJECT (observer), g_simple_action_observer_pspecs[PROP_ENABLED]);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
g_simple_action_observer_get_property (GObject *object, guint prop_id,
|
||||
GValue *value, GParamSpec *pspec)
|
||||
{
|
||||
GSimpleActionObserver *observer = G_SIMPLE_ACTION_OBSERVER (object);
|
||||
|
||||
switch (prop_id)
|
||||
{
|
||||
case PROP_ACTIVE:
|
||||
g_value_set_boolean (value, observer->active);
|
||||
break;
|
||||
|
||||
case PROP_ENABLED:
|
||||
g_value_set_boolean (value, observer->enabled);
|
||||
break;
|
||||
|
||||
default:
|
||||
g_assert_not_reached ();
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
g_simple_action_observer_finalize (GObject *object)
|
||||
{
|
||||
GSimpleActionObserver *observer = G_SIMPLE_ACTION_OBSERVER (object);
|
||||
|
||||
g_object_unref (observer->action_group);
|
||||
g_free (observer->action_name);
|
||||
|
||||
if (observer->target)
|
||||
g_variant_unref (observer->target);
|
||||
|
||||
G_OBJECT_CLASS (g_simple_action_observer_parent_class)
|
||||
->finalize (object);
|
||||
}
|
||||
|
||||
static void
|
||||
g_simple_action_observer_init (GSimpleActionObserver *observer)
|
||||
{
|
||||
}
|
||||
|
||||
static void
|
||||
g_simple_action_observer_init_iface (GActionObserverInterface *iface)
|
||||
{
|
||||
iface->action_added = g_simple_action_observer_action_added;
|
||||
iface->action_enabled_changed = g_simple_action_observer_action_enabled_changed;
|
||||
iface->action_state_changed = g_simple_action_observer_action_state_changed;
|
||||
iface->action_removed = g_simple_action_observer_action_removed;
|
||||
}
|
||||
|
||||
static void
|
||||
g_simple_action_observer_class_init (GObjectClass *class)
|
||||
{
|
||||
class->get_property = g_simple_action_observer_get_property;
|
||||
class->finalize = g_simple_action_observer_finalize;
|
||||
|
||||
g_simple_action_observer_pspecs[PROP_ACTIVE] = g_param_spec_boolean ("active", "active", "active", FALSE,
|
||||
G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
|
||||
g_simple_action_observer_pspecs[PROP_ENABLED] = g_param_spec_boolean ("enabled", "enabled", "enabled", FALSE,
|
||||
G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
|
||||
g_object_class_install_properties (class, N_PROPS, g_simple_action_observer_pspecs);
|
||||
}
|
||||
|
||||
GSimpleActionObserver *
|
||||
g_simple_action_observer_new (GActionObservable *observable,
|
||||
const gchar *action_name,
|
||||
GVariant *target)
|
||||
{
|
||||
GSimpleActionObserver *observer;
|
||||
const GVariantType *type;
|
||||
gboolean enabled;
|
||||
GVariant *state;
|
||||
|
||||
observer = g_object_new (G_TYPE_SIMPLE_ACTION_OBSERVER, NULL);
|
||||
observer->action_group = g_object_ref (observable);
|
||||
observer->action_name = g_strdup (action_name);
|
||||
if (target)
|
||||
observer->target = g_variant_ref_sink (target);
|
||||
|
||||
g_action_observable_register_observer (observable, action_name, G_ACTION_OBSERVER (observer));
|
||||
|
||||
if (g_action_group_query_action (observer->action_group, action_name, &enabled, &type, NULL, NULL, &state))
|
||||
{
|
||||
g_simple_action_observer_action_added (G_ACTION_OBSERVER (observer), observable,
|
||||
action_name, type, enabled, state);
|
||||
if (state)
|
||||
g_variant_unref (state);
|
||||
}
|
||||
|
||||
return observer;
|
||||
}
|
||||
|
||||
void
|
||||
g_simple_action_observer_activate (GSimpleActionObserver *observer)
|
||||
{
|
||||
g_return_if_fail (G_IS_SIMPLE_ACTION_OBSERVER (observer));
|
||||
|
||||
if (observer->can_activate && !observer->reporting)
|
||||
g_action_group_activate_action (G_ACTION_GROUP (observer->action_group),
|
||||
observer->action_name, observer->target);
|
||||
}
|
||||
|
||||
gboolean
|
||||
g_simple_action_observer_get_active (GSimpleActionObserver *observer)
|
||||
{
|
||||
g_return_val_if_fail (G_IS_SIMPLE_ACTION_OBSERVER (observer), FALSE);
|
||||
|
||||
return observer->active;
|
||||
}
|
||||
|
||||
gboolean
|
||||
g_simple_action_observer_get_enabled (GSimpleActionObserver *observer)
|
||||
{
|
||||
g_return_val_if_fail (G_IS_SIMPLE_ACTION_OBSERVER (observer), FALSE);
|
||||
|
||||
return observer->enabled;
|
||||
}
|
53
gtk/gsimpleactionobserver.h
Normal file
53
gtk/gsimpleactionobserver.h
Normal file
@ -0,0 +1,53 @@
|
||||
/*
|
||||
* Copyright © 2012 Canonical Limited
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as
|
||||
* published by the Free Software Foundation; either version 2 of the
|
||||
* licence 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
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307,
|
||||
* USA.
|
||||
*
|
||||
* Authors: Ryan Lortie <desrt@desrt.ca>
|
||||
*/
|
||||
|
||||
#ifndef __G_SIMPLE_ACTION_OBSERVER_H__
|
||||
#define __G_SIMPLE_ACTION_OBSERVER_H__
|
||||
|
||||
#include "gactionobserver.h"
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#define G_TYPE_SIMPLE_ACTION_OBSERVER (g_simple_action_observer_get_type ())
|
||||
#define G_SIMPLE_ACTION_OBSERVER(inst) (G_TYPE_CHECK_INSTANCE_CAST ((inst), \
|
||||
G_TYPE_SIMPLE_ACTION_OBSERVER, \
|
||||
GSimpleActionObserver))
|
||||
#define G_IS_SIMPLE_ACTION_OBSERVER(inst) (G_TYPE_CHECK_INSTANCE_TYPE ((inst), \
|
||||
G_TYPE_SIMPLE_ACTION_OBSERVER))
|
||||
|
||||
typedef struct _GSimpleActionObserver GSimpleActionObserver;
|
||||
|
||||
G_GNUC_INTERNAL
|
||||
GType g_simple_action_observer_get_type (void);
|
||||
G_GNUC_INTERNAL
|
||||
GSimpleActionObserver * g_simple_action_observer_new (GActionObservable *observable,
|
||||
const gchar *action_name,
|
||||
GVariant *target);
|
||||
G_GNUC_INTERNAL
|
||||
void g_simple_action_observer_activate (GSimpleActionObserver *observer);
|
||||
G_GNUC_INTERNAL
|
||||
gboolean g_simple_action_observer_get_active (GSimpleActionObserver *observer);
|
||||
G_GNUC_INTERNAL
|
||||
gboolean g_simple_action_observer_get_enabled (GSimpleActionObserver *observer);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __G_SIMPLE_ACTION_OBSERVER_H__ */
|
@ -36,6 +36,7 @@
|
||||
#include <gtk/gtkaccelmap.h>
|
||||
#include <gtk/gtkaccessible.h>
|
||||
#include <gtk/gtkaction.h>
|
||||
#include <gtk/gtkactionable.h>
|
||||
#include <gtk/gtkactiongroup.h>
|
||||
#include <gtk/gtkactivatable.h>
|
||||
#include <gtk/gtkadjustment.h>
|
||||
|
117
gtk/gtkactionable.c
Normal file
117
gtk/gtkactionable.c
Normal file
@ -0,0 +1,117 @@
|
||||
/*
|
||||
* Copyright © 2012 Canonical Limited
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as
|
||||
* published by the Free Software Foundation; either version 2 of the
|
||||
* licence 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
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307,
|
||||
* USA.
|
||||
*
|
||||
* Authors: Ryan Lortie <desrt@desrt.ca>
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "gtkactionable.h"
|
||||
|
||||
#include "gtkwidget.h"
|
||||
#include "gtkintl.h"
|
||||
|
||||
G_DEFINE_INTERFACE (GtkActionable, gtk_actionable, GTK_TYPE_WIDGET)
|
||||
|
||||
static void
|
||||
gtk_actionable_default_init (GtkActionableInterface *iface)
|
||||
{
|
||||
g_object_interface_install_property (iface,
|
||||
g_param_spec_string ("action-name", P_("action name"),
|
||||
P_("The name of the associated action, like 'app.quit'"),
|
||||
NULL, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
|
||||
|
||||
g_object_interface_install_property (iface,
|
||||
g_param_spec_variant ("action-target", P_("action target value"),
|
||||
P_("The parameter for action invocations"),
|
||||
G_VARIANT_TYPE_ANY, NULL, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
|
||||
}
|
||||
|
||||
const gchar *
|
||||
gtk_actionable_get_action_name (GtkActionable *actionable)
|
||||
{
|
||||
g_return_val_if_fail (GTK_IS_ACTIONABLE (actionable), NULL);
|
||||
|
||||
return GTK_ACTIONABLE_GET_IFACE (actionable)
|
||||
->get_action_name (actionable);
|
||||
}
|
||||
|
||||
void
|
||||
gtk_actionable_set_action_name (GtkActionable *actionable,
|
||||
const gchar *action_name)
|
||||
{
|
||||
g_return_if_fail (GTK_IS_ACTIONABLE (actionable));
|
||||
|
||||
GTK_ACTIONABLE_GET_IFACE (actionable)
|
||||
->set_action_name (actionable, action_name);
|
||||
}
|
||||
|
||||
GVariant *
|
||||
gtk_actionable_get_action_target_value (GtkActionable *actionable)
|
||||
{
|
||||
g_return_val_if_fail (GTK_IS_ACTIONABLE (actionable), NULL);
|
||||
|
||||
return GTK_ACTIONABLE_GET_IFACE (actionable)
|
||||
->get_action_target_value (actionable);
|
||||
}
|
||||
|
||||
void
|
||||
gtk_actionable_set_action_target_value (GtkActionable *actionable,
|
||||
GVariant *target_value)
|
||||
{
|
||||
g_return_if_fail (GTK_IS_ACTIONABLE (actionable));
|
||||
|
||||
GTK_ACTIONABLE_GET_IFACE (actionable)
|
||||
->set_action_target_value (actionable, target_value);
|
||||
}
|
||||
|
||||
void
|
||||
gtk_actionable_set_action_target (GtkActionable *actionable,
|
||||
const gchar *format_string,
|
||||
...)
|
||||
{
|
||||
va_list ap;
|
||||
|
||||
va_start (ap, format_string);
|
||||
gtk_actionable_set_action_target_value (actionable, g_variant_new_va (format_string, NULL, &ap));
|
||||
va_end (ap);
|
||||
}
|
||||
|
||||
void
|
||||
gtk_actionable_set_detailed_action_name (GtkActionable *actionable,
|
||||
const gchar *detailed_action_name)
|
||||
{
|
||||
gchar **parts;
|
||||
|
||||
g_return_if_fail (GTK_IS_ACTIONABLE (actionable));
|
||||
|
||||
if (detailed_action_name == NULL)
|
||||
{
|
||||
gtk_actionable_set_action_name (actionable, NULL);
|
||||
gtk_actionable_set_action_target_value (actionable, NULL);
|
||||
return;
|
||||
}
|
||||
|
||||
parts = g_strsplit (detailed_action_name, "::", 2);
|
||||
gtk_actionable_set_action_name (actionable, parts[0]);
|
||||
if (parts[0] && parts[1])
|
||||
gtk_actionable_set_action_target (actionable, "s", parts[1]);
|
||||
else
|
||||
gtk_actionable_set_action_target_value (actionable, NULL);
|
||||
g_strfreev (parts);
|
||||
}
|
71
gtk/gtkactionable.h
Normal file
71
gtk/gtkactionable.h
Normal file
@ -0,0 +1,71 @@
|
||||
/*
|
||||
* Copyright © 2012 Canonical Limited
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as
|
||||
* published by the Free Software Foundation; either version 2 of the
|
||||
* licence 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
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307,
|
||||
* USA.
|
||||
*
|
||||
* Authors: Ryan Lortie <desrt@desrt.ca>
|
||||
*/
|
||||
|
||||
#ifndef __GTK_ACTIONABLE_H__
|
||||
#define __GTK_ACTIONABLE_H__
|
||||
|
||||
#include <glib-object.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#define GTK_TYPE_ACTIONABLE (gtk_actionable_get_type ())
|
||||
#define GTK_ACTIONABLE(inst) (G_TYPE_CHECK_INSTANCE_CAST ((inst), \
|
||||
GTK_TYPE_ACTIONABLE, GtkActionable))
|
||||
#define GTK_IS_ACTIONABLE(inst) (G_TYPE_CHECK_INSTANCE_TYPE ((inst), \
|
||||
GTK_TYPE_ACTIONABLE))
|
||||
#define GTK_ACTIONABLE_GET_IFACE(inst) (G_TYPE_INSTANCE_GET_INTERFACE ((inst), \
|
||||
GTK_TYPE_ACTIONABLE, GtkActionableInterface))
|
||||
|
||||
typedef struct _GtkActionableInterface GtkActionableInterface;
|
||||
typedef struct _GtkActionable GtkActionable;
|
||||
|
||||
struct _GtkActionableInterface
|
||||
{
|
||||
GTypeInterface g_iface;
|
||||
|
||||
const gchar * (* get_action_name) (GtkActionable *actionable);
|
||||
void (* set_action_name) (GtkActionable *actionable,
|
||||
const gchar *action_name);
|
||||
GVariant * (* get_action_target_value) (GtkActionable *actionable);
|
||||
void (* set_action_target_value) (GtkActionable *actionable,
|
||||
GVariant *action_target_value);
|
||||
};
|
||||
|
||||
GType gtk_actionable_get_type (void) G_GNUC_CONST;
|
||||
|
||||
const gchar * gtk_actionable_get_action_name (GtkActionable *actionable);
|
||||
void gtk_actionable_set_action_name (GtkActionable *actionable,
|
||||
const gchar *action_name);
|
||||
|
||||
GVariant * gtk_actionable_get_action_target_value (GtkActionable *actionable);
|
||||
void gtk_actionable_set_action_target_value (GtkActionable *actionable,
|
||||
GVariant *target_value);
|
||||
|
||||
void gtk_actionable_set_action_target (GtkActionable *actionable,
|
||||
const gchar *format_string,
|
||||
...);
|
||||
|
||||
void gtk_actionable_set_detailed_action_name (GtkActionable *actionable,
|
||||
const gchar *detailed_action_name);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __GTK_ACTIONABLE_H__ */
|
@ -23,6 +23,7 @@
|
||||
#ifndef __GTK_APPLICATION_PRIVATE_H__
|
||||
#define __GTK_APPLICATION_PRIVATE_H__
|
||||
|
||||
#include "gsimpleactionobserver.h"
|
||||
#include "gtkapplicationwindow.h"
|
||||
|
||||
G_GNUC_INTERNAL
|
||||
@ -33,4 +34,9 @@ gboolean gtk_application_window_publish (GtkAppl
|
||||
G_GNUC_INTERNAL
|
||||
void gtk_application_window_unpublish (GtkApplicationWindow *window);
|
||||
|
||||
G_GNUC_INTERNAL
|
||||
GSimpleActionObserver * gtk_application_window_get_observer (GtkApplicationWindow *window,
|
||||
const gchar *action_name,
|
||||
GVariant *target);
|
||||
|
||||
#endif /* __GTK_APPLICATION_PRIVATE_H__ */
|
||||
|
@ -182,6 +182,7 @@ struct _GtkApplicationWindowPrivate
|
||||
{
|
||||
GSimpleActionGroup *actions;
|
||||
GActionObservable *muxer;
|
||||
gboolean muxer_initialised;
|
||||
GtkWidget *menubar;
|
||||
GtkAccelGroup *accels;
|
||||
GSList *accel_closures;
|
||||
@ -671,14 +672,11 @@ gtk_application_window_real_realize (GtkWidget *widget)
|
||||
g_signal_connect (settings, "notify::gtk-shell-shows-menubar",
|
||||
G_CALLBACK (gtk_application_window_shell_shows_menubar_changed), window);
|
||||
|
||||
if (window->priv->muxer == NULL)
|
||||
if (!window->priv->muxer_initialised)
|
||||
{
|
||||
GActionMuxer *muxer;
|
||||
|
||||
muxer = g_action_muxer_new ();
|
||||
g_action_muxer_insert (muxer, "app", G_ACTION_GROUP (application));
|
||||
g_action_muxer_insert (muxer, "win", G_ACTION_GROUP (window));
|
||||
window->priv->muxer = G_ACTION_OBSERVABLE (muxer);
|
||||
g_action_muxer_insert (G_ACTION_MUXER (window->priv->muxer), "app", G_ACTION_GROUP (application));
|
||||
g_action_muxer_insert (G_ACTION_MUXER (window->priv->muxer), "win", G_ACTION_GROUP (window));
|
||||
window->priv->muxer_initialised = TRUE;
|
||||
}
|
||||
|
||||
gtk_application_window_update_shell_shows_app_menu (window, settings);
|
||||
@ -875,6 +873,8 @@ gtk_application_window_init (GtkApplicationWindow *window)
|
||||
G_CALLBACK (g_action_group_action_state_changed), window);
|
||||
g_signal_connect_swapped (window->priv->actions, "action-removed",
|
||||
G_CALLBACK (g_action_group_action_removed), window);
|
||||
|
||||
window->priv->muxer = G_ACTION_OBSERVABLE (g_action_muxer_new ());
|
||||
}
|
||||
|
||||
static void
|
||||
@ -982,3 +982,13 @@ gtk_application_window_set_show_menubar (GtkApplicationWindow *window,
|
||||
g_object_notify_by_pspec (G_OBJECT (window), gtk_application_window_properties[PROP_SHOW_MENUBAR]);
|
||||
}
|
||||
}
|
||||
|
||||
GSimpleActionObserver *
|
||||
gtk_application_window_get_observer (GtkApplicationWindow *window,
|
||||
const gchar *action_name,
|
||||
GVariant *target)
|
||||
{
|
||||
g_return_val_if_fail (GTK_IS_APPLICATION_WINDOW (window), NULL);
|
||||
|
||||
return g_simple_action_observer_new (window->priv->muxer, action_name, target);
|
||||
}
|
||||
|
161
gtk/gtkbutton.c
161
gtk/gtkbutton.c
@ -58,7 +58,8 @@
|
||||
#include "gtkprivate.h"
|
||||
#include "gtkintl.h"
|
||||
#include "a11y/gtkbuttonaccessible.h"
|
||||
|
||||
#include "gtkapplicationprivate.h"
|
||||
#include "gtkactionable.h"
|
||||
|
||||
static const GtkBorder default_default_border = { 1, 1, 1, 1 };
|
||||
static const GtkBorder default_default_outside_border = { 0, 0, 0, 0 };
|
||||
@ -90,6 +91,8 @@ enum {
|
||||
PROP_XALIGN,
|
||||
PROP_YALIGN,
|
||||
PROP_IMAGE_POSITION,
|
||||
PROP_ACTION_NAME,
|
||||
PROP_ACTION_TARGET,
|
||||
|
||||
/* activatable properties */
|
||||
PROP_ACTIVATABLE_RELATED_ACTION,
|
||||
@ -147,8 +150,11 @@ static void gtk_button_state_changed (GtkWidget *widget,
|
||||
GtkStateType previous_state);
|
||||
static void gtk_button_grab_notify (GtkWidget *widget,
|
||||
gboolean was_grabbed);
|
||||
static void gtk_button_hierarchy_changed (GtkWidget *widget,
|
||||
GtkWidget *previous_toplevel);
|
||||
|
||||
|
||||
static void gtk_button_actionable_iface_init (GtkActionableInterface *iface);
|
||||
static void gtk_button_activatable_interface_init(GtkActivatableIface *iface);
|
||||
static void gtk_button_update (GtkActivatable *activatable,
|
||||
GtkAction *action,
|
||||
@ -170,6 +176,7 @@ static void gtk_button_get_preferred_height (GtkWidget *widget,
|
||||
static guint button_signals[LAST_SIGNAL] = { 0 };
|
||||
|
||||
G_DEFINE_TYPE_WITH_CODE (GtkButton, gtk_button, GTK_TYPE_BIN,
|
||||
G_IMPLEMENT_INTERFACE (GTK_TYPE_ACTIONABLE, gtk_button_actionable_iface_init)
|
||||
G_IMPLEMENT_INTERFACE (GTK_TYPE_ACTIVATABLE,
|
||||
gtk_button_activatable_interface_init))
|
||||
|
||||
@ -208,6 +215,7 @@ gtk_button_class_init (GtkButtonClass *klass)
|
||||
widget_class->leave_notify_event = gtk_button_leave_notify;
|
||||
widget_class->state_changed = gtk_button_state_changed;
|
||||
widget_class->grab_notify = gtk_button_grab_notify;
|
||||
widget_class->hierarchy_changed = gtk_button_hierarchy_changed;
|
||||
|
||||
container_class->child_type = gtk_button_child_type;
|
||||
container_class->add = gtk_button_add;
|
||||
@ -330,6 +338,9 @@ gtk_button_class_init (GtkButtonClass *klass)
|
||||
GTK_POS_LEFT,
|
||||
GTK_PARAM_READWRITE));
|
||||
|
||||
g_object_class_override_property (gobject_class, PROP_ACTION_NAME, "action-name");
|
||||
g_object_class_override_property (gobject_class, PROP_ACTION_TARGET, "action-target");
|
||||
|
||||
g_object_class_override_property (gobject_class, PROP_ACTIVATABLE_RELATED_ACTION, "related-action");
|
||||
g_object_class_override_property (gobject_class, PROP_ACTIVATABLE_USE_ACTION_APPEARANCE, "use-action-appearance");
|
||||
|
||||
@ -584,6 +595,12 @@ gtk_button_destroy (GtkWidget *widget)
|
||||
priv->label_text = NULL;
|
||||
}
|
||||
|
||||
if (priv->action_name)
|
||||
{
|
||||
g_free (priv->action_name);
|
||||
priv->action_name = NULL;
|
||||
}
|
||||
|
||||
GTK_WIDGET_CLASS (gtk_button_parent_class)->destroy (widget);
|
||||
}
|
||||
|
||||
@ -666,6 +683,8 @@ gtk_button_dispose (GObject *object)
|
||||
GtkButton *button = GTK_BUTTON (object);
|
||||
GtkButtonPrivate *priv = button->priv;
|
||||
|
||||
g_clear_object (&priv->action_observer);
|
||||
|
||||
if (priv->action)
|
||||
{
|
||||
gtk_activatable_do_set_related_action (GTK_ACTIVATABLE (button), NULL);
|
||||
@ -674,6 +693,83 @@ gtk_button_dispose (GObject *object)
|
||||
G_OBJECT_CLASS (gtk_button_parent_class)->dispose (object);
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_button_update_action_observer (GtkButton *button)
|
||||
{
|
||||
GtkWidget *window;
|
||||
|
||||
g_signal_handlers_disconnect_by_func (button, gtk_real_button_clicked, NULL);
|
||||
|
||||
/* we are the only owner so this will clear all the signals */
|
||||
g_clear_object (&button->priv->action_observer);
|
||||
|
||||
window = gtk_widget_get_toplevel (GTK_WIDGET (button));
|
||||
|
||||
if (GTK_IS_APPLICATION_WINDOW (window) && button->priv->action_name)
|
||||
{
|
||||
GSimpleActionObserver *observer;
|
||||
|
||||
observer = gtk_application_window_get_observer (GTK_APPLICATION_WINDOW (window),
|
||||
button->priv->action_name,
|
||||
button->priv->action_target);
|
||||
|
||||
_gtk_button_set_depressed (button, g_simple_action_observer_get_active (observer));
|
||||
|
||||
if (g_object_class_find_property (G_OBJECT_GET_CLASS (button), "active"))
|
||||
g_object_bind_property (observer, "active", button, "active", G_BINDING_SYNC_CREATE);
|
||||
g_object_bind_property (observer, "enabled", button, "sensitive", G_BINDING_SYNC_CREATE);
|
||||
|
||||
button->priv->action_observer = observer;
|
||||
|
||||
g_signal_connect_after (button, "clicked", G_CALLBACK (gtk_real_button_clicked), NULL);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_button_set_action_name (GtkActionable *actionable,
|
||||
const gchar *action_name)
|
||||
{
|
||||
GtkButton *button = GTK_BUTTON (actionable);
|
||||
|
||||
g_return_if_fail (GTK_IS_BUTTON (button));
|
||||
|
||||
if (g_strcmp0 (action_name, button->priv->action_name) != 0)
|
||||
{
|
||||
g_free (button->priv->action_name);
|
||||
button->priv->action_name = g_strdup (action_name);
|
||||
|
||||
gtk_button_update_action_observer (button);
|
||||
|
||||
g_object_notify (G_OBJECT (button), "action-name");
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_button_set_action_target_value (GtkActionable *actionable,
|
||||
GVariant *action_target)
|
||||
{
|
||||
GtkButton *button = GTK_BUTTON (actionable);
|
||||
|
||||
g_return_if_fail (GTK_IS_BUTTON (button));
|
||||
|
||||
if (action_target != button->priv->action_target &&
|
||||
(!action_target || !button->priv->action_target ||
|
||||
!g_variant_equal (action_target, button->priv->action_target)))
|
||||
{
|
||||
if (button->priv->action_target)
|
||||
g_variant_unref (button->priv->action_target);
|
||||
|
||||
button->priv->action_target = NULL;
|
||||
|
||||
if (action_target)
|
||||
button->priv->action_target = g_variant_ref_sink (action_target);
|
||||
|
||||
gtk_button_update_action_observer (button);
|
||||
|
||||
g_object_notify (G_OBJECT (button), "action-target");
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_button_set_property (GObject *object,
|
||||
guint prop_id,
|
||||
@ -718,6 +814,12 @@ gtk_button_set_property (GObject *object,
|
||||
case PROP_ACTIVATABLE_USE_ACTION_APPEARANCE:
|
||||
gtk_button_set_use_action_appearance (button, g_value_get_boolean (value));
|
||||
break;
|
||||
case PROP_ACTION_NAME:
|
||||
gtk_button_set_action_name (GTK_ACTIONABLE (button), g_value_get_string (value));
|
||||
break;
|
||||
case PROP_ACTION_TARGET:
|
||||
gtk_button_set_action_target_value (GTK_ACTIONABLE (button), g_value_get_variant (value));
|
||||
break;
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
break;
|
||||
@ -768,12 +870,43 @@ gtk_button_get_property (GObject *object,
|
||||
case PROP_ACTIVATABLE_USE_ACTION_APPEARANCE:
|
||||
g_value_set_boolean (value, priv->use_action_appearance);
|
||||
break;
|
||||
case PROP_ACTION_NAME:
|
||||
g_value_set_string (value, priv->action_name);
|
||||
break;
|
||||
case PROP_ACTION_TARGET:
|
||||
g_value_set_variant (value, priv->action_target);
|
||||
break;
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static const gchar *
|
||||
gtk_button_get_action_name (GtkActionable *actionable)
|
||||
{
|
||||
GtkButton *button = GTK_BUTTON (actionable);
|
||||
|
||||
return button->priv->action_name;
|
||||
}
|
||||
|
||||
static GVariant *
|
||||
gtk_button_get_action_target_value (GtkActionable *actionable)
|
||||
{
|
||||
GtkButton *button = GTK_BUTTON (actionable);
|
||||
|
||||
return button->priv->action_target;
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_button_actionable_iface_init (GtkActionableInterface *iface)
|
||||
{
|
||||
iface->get_action_name = gtk_button_get_action_name;
|
||||
iface->set_action_name = gtk_button_set_action_name;
|
||||
iface->get_action_target_value = gtk_button_get_action_target_value;
|
||||
iface->set_action_target_value = gtk_button_set_action_target_value;
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_button_activatable_interface_init (GtkActivatableIface *iface)
|
||||
{
|
||||
@ -1822,6 +1955,9 @@ gtk_real_button_clicked (GtkButton *button)
|
||||
{
|
||||
GtkButtonPrivate *priv = button->priv;
|
||||
|
||||
if (priv->action_observer)
|
||||
g_simple_action_observer_activate (priv->action_observer);
|
||||
|
||||
if (priv->action)
|
||||
gtk_action_activate (priv->action);
|
||||
}
|
||||
@ -2416,6 +2552,28 @@ gtk_button_grab_notify (GtkWidget *widget,
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_button_hierarchy_changed (GtkWidget *widget,
|
||||
GtkWidget *previous_toplevel)
|
||||
{
|
||||
GtkButton *button = GTK_BUTTON (widget);
|
||||
GtkWidgetClass *parent_class;
|
||||
|
||||
parent_class = GTK_WIDGET_CLASS (gtk_button_parent_class);
|
||||
if (parent_class->hierarchy_changed)
|
||||
parent_class->hierarchy_changed (widget, previous_toplevel);
|
||||
|
||||
if (button->priv->action_name)
|
||||
{
|
||||
GtkWidget *toplevel;
|
||||
|
||||
toplevel = gtk_widget_get_toplevel (widget);
|
||||
|
||||
if (toplevel != previous_toplevel)
|
||||
gtk_button_update_action_observer (button);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* gtk_button_set_image:
|
||||
* @button: a #GtkButton
|
||||
@ -2525,7 +2683,6 @@ gtk_button_get_image_position (GtkButton *button)
|
||||
return button->priv->image_position;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* gtk_button_get_event_window:
|
||||
* @button: a #GtkButton
|
||||
|
@ -19,6 +19,7 @@
|
||||
#ifndef __GTK_BUTTON_PRIVATE_H__
|
||||
#define __GTK_BUTTON_PRIVATE_H__
|
||||
|
||||
#include "gsimpleactionobserver.h"
|
||||
#include "gtkaction.h"
|
||||
|
||||
G_BEGIN_DECLS
|
||||
@ -29,6 +30,10 @@ struct _GtkButtonPrivate
|
||||
GtkAction *action;
|
||||
GtkWidget *image;
|
||||
|
||||
gchar *action_name;
|
||||
GVariant *action_target;
|
||||
GSimpleActionObserver *action_observer;
|
||||
|
||||
GdkDevice *grab_keyboard;
|
||||
GdkWindow *event_window;
|
||||
|
||||
|
@ -32,6 +32,7 @@
|
||||
#include "gtkintl.h"
|
||||
#include "gtktoolbar.h"
|
||||
#include "gtkactivatable.h"
|
||||
#include "gtkactionable.h"
|
||||
#include "gtkprivate.h"
|
||||
|
||||
#include <string.h>
|
||||
@ -81,7 +82,9 @@ enum {
|
||||
PROP_LABEL_WIDGET,
|
||||
PROP_STOCK_ID,
|
||||
PROP_ICON_NAME,
|
||||
PROP_ICON_WIDGET
|
||||
PROP_ICON_WIDGET,
|
||||
PROP_ACTION_NAME,
|
||||
PROP_ACTION_TARGET
|
||||
};
|
||||
|
||||
static void gtk_tool_button_init (GtkToolButton *button,
|
||||
@ -107,6 +110,7 @@ static void gtk_tool_button_style_updated (GtkWidget *widget);
|
||||
|
||||
static void gtk_tool_button_construct_contents (GtkToolItem *tool_item);
|
||||
|
||||
static void gtk_tool_button_actionable_iface_init (GtkActionableInterface *iface);
|
||||
static void gtk_tool_button_activatable_interface_init (GtkActivatableIface *iface);
|
||||
static void gtk_tool_button_update (GtkActivatable *activatable,
|
||||
GtkAction *action,
|
||||
@ -135,7 +139,6 @@ static GObjectClass *parent_class = NULL;
|
||||
static GtkActivatableIface *parent_activatable_iface;
|
||||
static guint toolbutton_signals[LAST_SIGNAL] = { 0 };
|
||||
|
||||
|
||||
GType
|
||||
gtk_tool_button_get_type (void)
|
||||
{
|
||||
@ -143,6 +146,12 @@ gtk_tool_button_get_type (void)
|
||||
|
||||
if (!type)
|
||||
{
|
||||
const GInterfaceInfo actionable_info =
|
||||
{
|
||||
(GInterfaceInitFunc) gtk_tool_button_actionable_iface_init,
|
||||
(GInterfaceFinalizeFunc) NULL,
|
||||
NULL
|
||||
};
|
||||
const GInterfaceInfo activatable_info =
|
||||
{
|
||||
(GInterfaceInitFunc) gtk_tool_button_activatable_interface_init,
|
||||
@ -158,6 +167,7 @@ gtk_tool_button_get_type (void)
|
||||
(GInstanceInitFunc) gtk_tool_button_init,
|
||||
0);
|
||||
|
||||
g_type_add_interface_static (type, GTK_TYPE_ACTIONABLE, &actionable_info);
|
||||
g_type_add_interface_static (type, GTK_TYPE_ACTIVATABLE,
|
||||
&activatable_info);
|
||||
}
|
||||
@ -278,6 +288,9 @@ gtk_tool_button_class_init (GtkToolButtonClass *klass)
|
||||
GTK_TYPE_WIDGET,
|
||||
GTK_PARAM_READWRITE));
|
||||
|
||||
g_object_class_override_property (object_class, PROP_ACTION_NAME, "action-name");
|
||||
g_object_class_override_property (object_class, PROP_ACTION_TARGET, "action-target");
|
||||
|
||||
/**
|
||||
* GtkButton:icon-spacing:
|
||||
*
|
||||
@ -612,6 +625,12 @@ gtk_tool_button_set_property (GObject *object,
|
||||
case PROP_ICON_WIDGET:
|
||||
gtk_tool_button_set_icon_widget (button, g_value_get_object (value));
|
||||
break;
|
||||
case PROP_ACTION_NAME:
|
||||
g_object_set_property (G_OBJECT (button->priv->button), "action-name", value);
|
||||
break;
|
||||
case PROP_ACTION_TARGET:
|
||||
g_object_set_property (G_OBJECT (button->priv->button), "action-target", value);
|
||||
break;
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
break;
|
||||
@ -660,12 +679,61 @@ gtk_tool_button_get_property (GObject *object,
|
||||
case PROP_ICON_WIDGET:
|
||||
g_value_set_object (value, button->priv->icon_widget);
|
||||
break;
|
||||
case PROP_ACTION_NAME:
|
||||
g_object_get_property (G_OBJECT (button->priv->button), "action-name", value);
|
||||
break;
|
||||
case PROP_ACTION_TARGET:
|
||||
g_object_get_property (G_OBJECT (button->priv->button), "action-target", value);
|
||||
break;
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static const gchar *
|
||||
gtk_tool_button_get_action_name (GtkActionable *actionable)
|
||||
{
|
||||
GtkToolButton *button = GTK_TOOL_BUTTON (actionable);
|
||||
|
||||
return gtk_actionable_get_action_name (GTK_ACTIONABLE (button->priv->button));
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_tool_button_set_action_name (GtkActionable *actionable,
|
||||
const gchar *action_name)
|
||||
{
|
||||
GtkToolButton *button = GTK_TOOL_BUTTON (actionable);
|
||||
|
||||
gtk_actionable_set_action_name (GTK_ACTIONABLE (button->priv->button), action_name);
|
||||
}
|
||||
|
||||
static GVariant *
|
||||
gtk_tool_button_get_action_target_value (GtkActionable *actionable)
|
||||
{
|
||||
GtkToolButton *button = GTK_TOOL_BUTTON (actionable);
|
||||
|
||||
return gtk_actionable_get_action_target_value (GTK_ACTIONABLE (button->priv->button));
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_tool_button_set_action_target_value (GtkActionable *actionable,
|
||||
GVariant *action_target)
|
||||
{
|
||||
GtkToolButton *button = GTK_TOOL_BUTTON (actionable);
|
||||
|
||||
gtk_actionable_set_action_target_value (GTK_ACTIONABLE (button->priv->button), action_target);
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_tool_button_actionable_iface_init (GtkActionableInterface *iface)
|
||||
{
|
||||
iface->get_action_name = gtk_tool_button_get_action_name;
|
||||
iface->set_action_name = gtk_tool_button_set_action_name;
|
||||
iface->get_action_target_value = gtk_tool_button_get_action_target_value;
|
||||
iface->set_action_target_value = gtk_tool_button_set_action_target_value;
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_tool_button_finalize (GObject *object)
|
||||
{
|
||||
|
Loading…
Reference in New Issue
Block a user