forked from AuroraMiddleware/gtk
a546ae32d7
Those property features don't seem to be in use anywhere. They are redundant since the docs cover the same information and more. They also created unnecessary translation work. Closes #4904
1242 lines
33 KiB
C
1242 lines
33 KiB
C
/*
|
|
* Copyright © 2018 Benjamin Otte
|
|
*
|
|
* This library 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.1 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
|
|
* 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, see <http://www.gnu.org/licenses/>.
|
|
*
|
|
* Authors: Benjamin Otte <otte@gnome.org>
|
|
*/
|
|
|
|
/**
|
|
* GtkShortcutAction:
|
|
*
|
|
* `GtkShortcutAction` encodes an action that can be triggered by a
|
|
* keyboard shortcut.
|
|
*
|
|
* `GtkShortcutActions` contain functions that allow easy presentation
|
|
* to end users as well as being printed for debugging.
|
|
*
|
|
* All `GtkShortcutActions` are immutable, you can only specify their
|
|
* properties during construction. If you want to change a action, you
|
|
* have to replace it with a new one. If you need to pass arguments to
|
|
* an action, these are specified by the higher-level `GtkShortcut` object.
|
|
*
|
|
* To activate a `GtkShortcutAction` manually, [method@Gtk.ShortcutAction.activate]
|
|
* can be called.
|
|
*
|
|
* GTK provides various actions:
|
|
*
|
|
* - [class@Gtk.MnemonicAction]: a shortcut action that calls
|
|
* gtk_widget_mnemonic_activate()
|
|
* - [class@Gtk.CallbackAction]: a shortcut action that invokes
|
|
* a given callback
|
|
* - [class@Gtk.SignalAction]: a shortcut action that emits a
|
|
* given signal
|
|
* - [class@Gtk.ActivateAction]: a shortcut action that calls
|
|
* gtk_widget_activate()
|
|
* - [class@Gtk.NamedAction]: a shortcut action that calls
|
|
* gtk_widget_activate_action()
|
|
* - [class@Gtk.NothingAction]: a shortcut action that does nothing
|
|
*/
|
|
|
|
#include "config.h"
|
|
|
|
#include "gtkshortcutactionprivate.h"
|
|
|
|
#include "gtkbuilder.h"
|
|
#include "gtkintl.h"
|
|
#include "gtkwidgetprivate.h"
|
|
#include "gtkdebug.h"
|
|
|
|
/* {{{ GtkShortcutAction */
|
|
|
|
struct _GtkShortcutAction
|
|
{
|
|
GObject parent_instance;
|
|
};
|
|
|
|
struct _GtkShortcutActionClass
|
|
{
|
|
GObjectClass parent_class;
|
|
|
|
gboolean (* activate) (GtkShortcutAction *action,
|
|
GtkShortcutActionFlags flags,
|
|
GtkWidget *widget,
|
|
GVariant *args);
|
|
void (* print) (GtkShortcutAction *action,
|
|
GString *string);
|
|
};
|
|
|
|
G_DEFINE_ABSTRACT_TYPE (GtkShortcutAction, gtk_shortcut_action, G_TYPE_OBJECT)
|
|
|
|
static void
|
|
gtk_shortcut_action_class_init (GtkShortcutActionClass *klass)
|
|
{
|
|
}
|
|
|
|
static void
|
|
gtk_shortcut_action_init (GtkShortcutAction *self)
|
|
{
|
|
}
|
|
|
|
/**
|
|
* gtk_shortcut_action_to_string:
|
|
* @self: a `GtkShortcutAction`
|
|
*
|
|
* Prints the given action into a human-readable string.
|
|
*
|
|
* This is a small wrapper around [method@Gtk.ShortcutAction.print]
|
|
* to help when debugging.
|
|
*
|
|
* Returns: (transfer full): a new string
|
|
*/
|
|
char *
|
|
gtk_shortcut_action_to_string (GtkShortcutAction *self)
|
|
{
|
|
GString *string;
|
|
|
|
g_return_val_if_fail (GTK_IS_SHORTCUT_ACTION (self), NULL);
|
|
|
|
string = g_string_new (NULL);
|
|
gtk_shortcut_action_print (self, string);
|
|
|
|
return g_string_free (string, FALSE);
|
|
}
|
|
|
|
/**
|
|
* gtk_shortcut_action_print:
|
|
* @self: a `GtkShortcutAction`
|
|
* @string: a `GString` to print into
|
|
*
|
|
* Prints the given action into a string for the developer.
|
|
*
|
|
* This is meant for debugging and logging.
|
|
*
|
|
* The form of the representation may change at any time and is
|
|
* not guaranteed to stay identical.
|
|
*/
|
|
void
|
|
gtk_shortcut_action_print (GtkShortcutAction *self,
|
|
GString *string)
|
|
{
|
|
g_return_if_fail (GTK_IS_SHORTCUT_ACTION (self));
|
|
g_return_if_fail (string != NULL);
|
|
|
|
GTK_SHORTCUT_ACTION_GET_CLASS (self)->print (self, string);
|
|
}
|
|
|
|
/**
|
|
* gtk_shortcut_action_activate:
|
|
* @self: a `GtkShortcutAction`
|
|
* @flags: flags to activate with
|
|
* @widget: Target of the activation
|
|
* @args: (nullable): arguments to pass
|
|
*
|
|
* Activates the action on the @widget with the given @args.
|
|
*
|
|
* Note that some actions ignore the passed in @flags, @widget or @args.
|
|
*
|
|
* Activation of an action can fail for various reasons. If the action
|
|
* is not supported by the @widget, if the @args don't match the action
|
|
* or if the activation otherwise had no effect, %FALSE will be returned.
|
|
*
|
|
* Returns: %TRUE if this action was activated successfully
|
|
*/
|
|
gboolean
|
|
gtk_shortcut_action_activate (GtkShortcutAction *self,
|
|
GtkShortcutActionFlags flags,
|
|
GtkWidget *widget,
|
|
GVariant *args)
|
|
{
|
|
g_return_val_if_fail (GTK_IS_SHORTCUT_ACTION (self), FALSE);
|
|
g_return_val_if_fail (GTK_IS_WIDGET (widget), FALSE);
|
|
|
|
GTK_NOTE (KEYBINDINGS, {
|
|
char *act = gtk_shortcut_action_to_string (self);
|
|
g_print ("Shortcut action activate on %s: %s\n", G_OBJECT_TYPE_NAME (widget), act);
|
|
g_free (act);
|
|
});
|
|
|
|
return GTK_SHORTCUT_ACTION_GET_CLASS (self)->activate (self, flags, widget, args);
|
|
}
|
|
|
|
static char *
|
|
string_is_function (const char *string,
|
|
const char *function_name)
|
|
{
|
|
gsize len;
|
|
|
|
if (!g_str_has_prefix (string, function_name))
|
|
return NULL;
|
|
string += strlen (function_name);
|
|
|
|
if (string[0] != '(')
|
|
return NULL;
|
|
string ++;
|
|
|
|
len = strlen (string);
|
|
if (len == 0 || string[len - 1] != ')')
|
|
return NULL;
|
|
|
|
return g_strndup (string, len - 1);
|
|
}
|
|
|
|
/**
|
|
* gtk_shortcut_action_parse_string: (constructor)
|
|
* @string: the string to parse
|
|
*
|
|
* Tries to parse the given string into an action.
|
|
*
|
|
* On success, the parsed action is returned. When parsing
|
|
* failed, %NULL is returned.
|
|
*
|
|
* The accepted strings are:
|
|
*
|
|
* - `nothing`, for `GtkNothingAction`
|
|
* - `activate`, for `GtkActivateAction`
|
|
* - `mnemonic-activate`, for `GtkMnemonicAction`
|
|
* - `action(NAME)`, for a `GtkNamedAction` for the action named `NAME`
|
|
* - `signal(NAME)`, for a `GtkSignalAction` for the signal `NAME`
|
|
*
|
|
* Returns: (nullable) (transfer full): a new `GtkShortcutAction`
|
|
*/
|
|
GtkShortcutAction *
|
|
gtk_shortcut_action_parse_string (const char *string)
|
|
{
|
|
GtkShortcutAction *result;
|
|
char *arg;
|
|
|
|
if (g_str_equal (string, "nothing"))
|
|
return g_object_ref (gtk_nothing_action_get ());
|
|
if (g_str_equal (string, "activate"))
|
|
return g_object_ref (gtk_activate_action_get ());
|
|
if (g_str_equal (string, "mnemonic-activate"))
|
|
return g_object_ref (gtk_mnemonic_action_get ());
|
|
|
|
if ((arg = string_is_function (string, "action")))
|
|
{
|
|
result = gtk_named_action_new (arg);
|
|
g_free (arg);
|
|
}
|
|
else if ((arg = string_is_function (string, "signal")))
|
|
{
|
|
result = gtk_signal_action_new (arg);
|
|
g_free (arg);
|
|
}
|
|
else
|
|
return NULL;
|
|
|
|
return result;
|
|
}
|
|
|
|
GtkShortcutAction *
|
|
gtk_shortcut_action_parse_builder (GtkBuilder *builder,
|
|
const char *string,
|
|
GError **error)
|
|
{
|
|
GtkShortcutAction *result;
|
|
|
|
result = gtk_shortcut_action_parse_string (string);
|
|
|
|
if (!result)
|
|
{
|
|
g_set_error (error,
|
|
GTK_BUILDER_ERROR, GTK_BUILDER_ERROR_INVALID_VALUE,
|
|
"String \"%s\" does not specify a GtkShortcutAction", string);
|
|
return NULL;
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
/* }}} */
|
|
|
|
/* {{{ GtkNothingAction */
|
|
|
|
struct _GtkNothingAction
|
|
{
|
|
GtkShortcutAction parent_instance;
|
|
};
|
|
|
|
struct _GtkNothingActionClass
|
|
{
|
|
GtkShortcutActionClass parent_class;
|
|
};
|
|
|
|
G_DEFINE_TYPE (GtkNothingAction, gtk_nothing_action, GTK_TYPE_SHORTCUT_ACTION)
|
|
|
|
static void G_GNUC_NORETURN
|
|
gtk_nothing_action_finalize (GObject *gobject)
|
|
{
|
|
g_assert_not_reached ();
|
|
|
|
G_OBJECT_CLASS (gtk_nothing_action_parent_class)->finalize (gobject);
|
|
}
|
|
|
|
static gboolean
|
|
gtk_nothing_action_activate (GtkShortcutAction *action,
|
|
GtkShortcutActionFlags flags,
|
|
GtkWidget *widget,
|
|
GVariant *args)
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
static void
|
|
gtk_nothing_action_print (GtkShortcutAction *action,
|
|
GString *string)
|
|
{
|
|
g_string_append (string, "nothing");
|
|
}
|
|
|
|
static void
|
|
gtk_nothing_action_class_init (GtkNothingActionClass *klass)
|
|
{
|
|
GtkShortcutActionClass *action_class = GTK_SHORTCUT_ACTION_CLASS (klass);
|
|
|
|
G_OBJECT_CLASS (klass)->finalize = gtk_nothing_action_finalize;
|
|
|
|
action_class->activate = gtk_nothing_action_activate;
|
|
action_class->print = gtk_nothing_action_print;
|
|
}
|
|
|
|
static void
|
|
gtk_nothing_action_init (GtkNothingAction *self)
|
|
{
|
|
}
|
|
|
|
/**
|
|
* gtk_nothing_action_get:
|
|
*
|
|
* Gets the nothing action.
|
|
*
|
|
* This is an action that does nothing and where
|
|
* activating it always fails.
|
|
*
|
|
* Returns: (transfer none) (type GtkNothingAction): The nothing action
|
|
*/
|
|
GtkShortcutAction *
|
|
gtk_nothing_action_get (void)
|
|
{
|
|
static GtkShortcutAction *nothing;
|
|
|
|
if (nothing == NULL)
|
|
nothing = g_object_new (GTK_TYPE_NOTHING_ACTION, NULL);
|
|
|
|
return nothing;
|
|
}
|
|
|
|
/* }}} */
|
|
|
|
/* {{{ GtkCallbackAction */
|
|
|
|
struct _GtkCallbackAction
|
|
{
|
|
GtkShortcutAction parent_instance;
|
|
|
|
GtkShortcutFunc callback;
|
|
gpointer user_data;
|
|
GDestroyNotify destroy_notify;
|
|
};
|
|
|
|
struct _GtkCallbackActionClass
|
|
{
|
|
GtkShortcutActionClass parent_class;
|
|
};
|
|
|
|
G_DEFINE_TYPE (GtkCallbackAction, gtk_callback_action, GTK_TYPE_SHORTCUT_ACTION)
|
|
|
|
static void
|
|
gtk_callback_action_finalize (GObject *gobject)
|
|
{
|
|
GtkCallbackAction *self = GTK_CALLBACK_ACTION (gobject);
|
|
|
|
if (self->destroy_notify != NULL)
|
|
self->destroy_notify (self->user_data);
|
|
|
|
G_OBJECT_CLASS (gtk_callback_action_parent_class)->finalize (gobject);
|
|
}
|
|
|
|
static gboolean
|
|
gtk_callback_action_activate (GtkShortcutAction *action,
|
|
GtkShortcutActionFlags flags,
|
|
GtkWidget *widget,
|
|
GVariant *args)
|
|
{
|
|
GtkCallbackAction *self = GTK_CALLBACK_ACTION (action);
|
|
|
|
return self->callback (widget, args, self->user_data);
|
|
}
|
|
|
|
static void
|
|
gtk_callback_action_print (GtkShortcutAction *action,
|
|
GString *string)
|
|
{
|
|
GtkCallbackAction *self = GTK_CALLBACK_ACTION (action);
|
|
|
|
g_string_append_printf (string, "callback<%p>", self->callback);
|
|
}
|
|
|
|
static void
|
|
gtk_callback_action_class_init (GtkCallbackActionClass *klass)
|
|
{
|
|
GtkShortcutActionClass *action_class = GTK_SHORTCUT_ACTION_CLASS (klass);
|
|
|
|
G_OBJECT_CLASS (klass)->finalize = gtk_callback_action_finalize;
|
|
|
|
action_class->activate = gtk_callback_action_activate;
|
|
action_class->print = gtk_callback_action_print;
|
|
}
|
|
|
|
static void
|
|
gtk_callback_action_init (GtkCallbackAction *self)
|
|
{
|
|
}
|
|
|
|
/**
|
|
* gtk_callback_action_new:
|
|
* @callback: (scope notified): the callback to call
|
|
* @data: (closure callback): the data to be passed to @callback
|
|
* @destroy: (destroy data): the function to be called when the
|
|
* callback action is finalized
|
|
*
|
|
* Create a custom action that calls the given @callback when
|
|
* activated.
|
|
*
|
|
* Returns: (transfer full) (type GtkCallbackAction): A new shortcut action
|
|
*/
|
|
GtkShortcutAction *
|
|
gtk_callback_action_new (GtkShortcutFunc callback,
|
|
gpointer data,
|
|
GDestroyNotify destroy)
|
|
{
|
|
GtkCallbackAction *self;
|
|
|
|
g_return_val_if_fail (callback != NULL, NULL);
|
|
|
|
self = g_object_new (GTK_TYPE_CALLBACK_ACTION, NULL);
|
|
|
|
self->callback = callback;
|
|
self->user_data = data;
|
|
self->destroy_notify = destroy;
|
|
|
|
return GTK_SHORTCUT_ACTION (self);
|
|
}
|
|
|
|
/* }}} */
|
|
|
|
/* {{{ GtkActivateAction */
|
|
|
|
struct _GtkActivateAction
|
|
{
|
|
GtkShortcutAction parent_instance;
|
|
};
|
|
|
|
struct _GtkActivateActionClass
|
|
{
|
|
GtkShortcutActionClass parent_class;
|
|
};
|
|
|
|
G_DEFINE_TYPE (GtkActivateAction, gtk_activate_action, GTK_TYPE_SHORTCUT_ACTION)
|
|
|
|
static void G_GNUC_NORETURN
|
|
gtk_activate_action_finalize (GObject *gobject)
|
|
{
|
|
g_assert_not_reached ();
|
|
|
|
G_OBJECT_CLASS (gtk_activate_action_parent_class)->finalize (gobject);
|
|
}
|
|
|
|
static gboolean
|
|
gtk_activate_action_activate (GtkShortcutAction *action,
|
|
GtkShortcutActionFlags flags,
|
|
GtkWidget *widget,
|
|
GVariant *args)
|
|
{
|
|
return gtk_widget_activate (widget);
|
|
}
|
|
|
|
static void
|
|
gtk_activate_action_print (GtkShortcutAction *action,
|
|
GString *string)
|
|
{
|
|
g_string_append (string, "activate");
|
|
}
|
|
|
|
static void
|
|
gtk_activate_action_class_init (GtkActivateActionClass *klass)
|
|
{
|
|
GtkShortcutActionClass *action_class = GTK_SHORTCUT_ACTION_CLASS (klass);
|
|
|
|
G_OBJECT_CLASS (klass)->finalize = gtk_activate_action_finalize;
|
|
|
|
action_class->activate = gtk_activate_action_activate;
|
|
action_class->print = gtk_activate_action_print;
|
|
}
|
|
|
|
static void
|
|
gtk_activate_action_init (GtkActivateAction *self)
|
|
{
|
|
}
|
|
|
|
/**
|
|
* gtk_activate_action_get:
|
|
*
|
|
* Gets the activate action.
|
|
*
|
|
* This is an action that calls gtk_widget_activate()
|
|
* on the given widget upon activation.
|
|
*
|
|
* Returns: (transfer none) (type GtkActivateAction): The activate action
|
|
*/
|
|
GtkShortcutAction *
|
|
gtk_activate_action_get (void)
|
|
{
|
|
static GtkShortcutAction *action;
|
|
|
|
if (action == NULL)
|
|
action = g_object_new (GTK_TYPE_ACTIVATE_ACTION, NULL);
|
|
|
|
return action;
|
|
}
|
|
|
|
/* }}} */
|
|
|
|
/* {{{ GtkMnemonicAction */
|
|
|
|
struct _GtkMnemonicAction
|
|
{
|
|
GtkShortcutAction parent_instance;
|
|
};
|
|
|
|
struct _GtkMnemonicActionClass
|
|
{
|
|
GtkShortcutActionClass parent_class;
|
|
};
|
|
|
|
G_DEFINE_TYPE (GtkMnemonicAction, gtk_mnemonic_action, GTK_TYPE_SHORTCUT_ACTION)
|
|
|
|
static void G_GNUC_NORETURN
|
|
gtk_mnemonic_action_finalize (GObject *gobject)
|
|
{
|
|
g_assert_not_reached ();
|
|
|
|
G_OBJECT_CLASS (gtk_mnemonic_action_parent_class)->finalize (gobject);
|
|
}
|
|
|
|
static gboolean
|
|
gtk_mnemonic_action_activate (GtkShortcutAction *action,
|
|
GtkShortcutActionFlags flags,
|
|
GtkWidget *widget,
|
|
GVariant *args)
|
|
{
|
|
return gtk_widget_mnemonic_activate (widget, flags & GTK_SHORTCUT_ACTION_EXCLUSIVE ? FALSE : TRUE);
|
|
}
|
|
|
|
static void
|
|
gtk_mnemonic_action_print (GtkShortcutAction *action,
|
|
GString *string)
|
|
{
|
|
g_string_append (string, "mnemonic-activate");
|
|
}
|
|
|
|
static void
|
|
gtk_mnemonic_action_class_init (GtkMnemonicActionClass *klass)
|
|
{
|
|
GtkShortcutActionClass *action_class = GTK_SHORTCUT_ACTION_CLASS (klass);
|
|
|
|
G_OBJECT_CLASS (klass)->finalize = gtk_mnemonic_action_finalize;
|
|
|
|
action_class->activate = gtk_mnemonic_action_activate;
|
|
action_class->print = gtk_mnemonic_action_print;
|
|
}
|
|
|
|
static void
|
|
gtk_mnemonic_action_init (GtkMnemonicAction *self)
|
|
{
|
|
}
|
|
|
|
/**
|
|
* gtk_mnemonic_action_get:
|
|
*
|
|
* Gets the mnemonic action.
|
|
*
|
|
* This is an action that calls gtk_widget_mnemonic_activate()
|
|
* on the given widget upon activation.
|
|
*
|
|
* Returns: (transfer none) (type GtkMnemonicAction): The mnemonic action
|
|
*/
|
|
GtkShortcutAction *
|
|
gtk_mnemonic_action_get (void)
|
|
{
|
|
static GtkShortcutAction *mnemonic;
|
|
|
|
if (G_UNLIKELY (mnemonic == NULL))
|
|
mnemonic = g_object_new (GTK_TYPE_MNEMONIC_ACTION, NULL);
|
|
|
|
return mnemonic;
|
|
}
|
|
|
|
/* }}} */
|
|
|
|
/* {{{ GtkSignalAction */
|
|
|
|
struct _GtkSignalAction
|
|
{
|
|
GtkShortcutAction parent_instance;
|
|
|
|
char *name;
|
|
};
|
|
|
|
struct _GtkSignalActionClass
|
|
{
|
|
GtkShortcutActionClass parent_class;
|
|
};
|
|
|
|
enum
|
|
{
|
|
SIGNAL_PROP_SIGNAL_NAME = 1,
|
|
SIGNAL_N_PROPS
|
|
};
|
|
|
|
static GParamSpec *signal_props[SIGNAL_N_PROPS];
|
|
|
|
G_DEFINE_TYPE (GtkSignalAction, gtk_signal_action, GTK_TYPE_SHORTCUT_ACTION)
|
|
|
|
static void
|
|
gtk_signal_action_finalize (GObject *gobject)
|
|
{
|
|
GtkSignalAction *self = GTK_SIGNAL_ACTION (gobject);
|
|
|
|
g_free (self->name);
|
|
|
|
G_OBJECT_CLASS (gtk_signal_action_parent_class)->finalize (gobject);
|
|
}
|
|
|
|
static gboolean
|
|
binding_compose_params (GtkWidget *widget,
|
|
GVariantIter *args,
|
|
GSignalQuery *query,
|
|
GValue **params_p)
|
|
{
|
|
GValue *params;
|
|
const GType *types;
|
|
guint i;
|
|
gboolean valid;
|
|
|
|
params = g_new0 (GValue, query->n_params + 1);
|
|
*params_p = params;
|
|
|
|
/* The instance we emit on is the first object in the array
|
|
*/
|
|
g_value_init (params, G_TYPE_OBJECT);
|
|
g_value_set_object (params, G_OBJECT (widget));
|
|
params++;
|
|
|
|
types = query->param_types;
|
|
valid = TRUE;
|
|
for (i = 1; i < query->n_params + 1 && valid; i++)
|
|
{
|
|
GValue tmp_value = G_VALUE_INIT;
|
|
GVariant *tmp_variant;
|
|
|
|
g_value_init (params, *types);
|
|
tmp_variant = g_variant_iter_next_value (args);
|
|
|
|
switch ((guint) g_variant_classify (tmp_variant))
|
|
{
|
|
case G_VARIANT_CLASS_BOOLEAN:
|
|
g_value_init (&tmp_value, G_TYPE_BOOLEAN);
|
|
g_value_set_boolean (&tmp_value, g_variant_get_boolean (tmp_variant));
|
|
break;
|
|
case G_VARIANT_CLASS_DOUBLE:
|
|
g_value_init (&tmp_value, G_TYPE_DOUBLE);
|
|
g_value_set_double (&tmp_value, g_variant_get_double (tmp_variant));
|
|
break;
|
|
case G_VARIANT_CLASS_INT32:
|
|
g_value_init (&tmp_value, G_TYPE_LONG);
|
|
g_value_set_long (&tmp_value, g_variant_get_int32 (tmp_variant));
|
|
break;
|
|
case G_VARIANT_CLASS_UINT32:
|
|
g_value_init (&tmp_value, G_TYPE_LONG);
|
|
g_value_set_long (&tmp_value, g_variant_get_uint32 (tmp_variant));
|
|
break;
|
|
case G_VARIANT_CLASS_INT64:
|
|
g_value_init (&tmp_value, G_TYPE_LONG);
|
|
g_value_set_long (&tmp_value, g_variant_get_int64 (tmp_variant));
|
|
break;
|
|
case G_VARIANT_CLASS_STRING:
|
|
/* gtk_rc_parse_flags/enum() has fancier parsing for this; we can't call
|
|
* that since we don't have a GParamSpec, so just do something simple
|
|
*/
|
|
if (G_TYPE_FUNDAMENTAL (*types) == G_TYPE_ENUM)
|
|
{
|
|
GEnumClass *class = G_ENUM_CLASS (g_type_class_ref (*types));
|
|
GEnumValue *enum_value;
|
|
const char *s = g_variant_get_string (tmp_variant, NULL);
|
|
|
|
valid = FALSE;
|
|
|
|
enum_value = g_enum_get_value_by_name (class, s);
|
|
if (!enum_value)
|
|
enum_value = g_enum_get_value_by_nick (class, s);
|
|
|
|
if (enum_value)
|
|
{
|
|
g_value_init (&tmp_value, *types);
|
|
g_value_set_enum (&tmp_value, enum_value->value);
|
|
valid = TRUE;
|
|
}
|
|
|
|
g_type_class_unref (class);
|
|
}
|
|
/* This is just a hack for compatibility with GTK 1.2 where a string
|
|
* could be used for a single flag value / without the support for multiple
|
|
* values in gtk_rc_parse_flags(), this isn't very useful.
|
|
*/
|
|
else if (G_TYPE_FUNDAMENTAL (*types) == G_TYPE_FLAGS)
|
|
{
|
|
GFlagsClass *class = G_FLAGS_CLASS (g_type_class_ref (*types));
|
|
GFlagsValue *flags_value;
|
|
const char *s = g_variant_get_string (tmp_variant, NULL);
|
|
|
|
valid = FALSE;
|
|
|
|
flags_value = g_flags_get_value_by_name (class, s);
|
|
if (!flags_value)
|
|
flags_value = g_flags_get_value_by_nick (class, s);
|
|
if (flags_value)
|
|
{
|
|
g_value_init (&tmp_value, *types);
|
|
g_value_set_flags (&tmp_value, flags_value->value);
|
|
valid = TRUE;
|
|
}
|
|
|
|
g_type_class_unref (class);
|
|
}
|
|
else
|
|
{
|
|
g_value_init (&tmp_value, G_TYPE_STRING);
|
|
g_value_set_static_string (&tmp_value, g_variant_get_string (tmp_variant, NULL));
|
|
}
|
|
break;
|
|
default:
|
|
valid = FALSE;
|
|
break;
|
|
}
|
|
|
|
if (valid)
|
|
{
|
|
if (!g_value_transform (&tmp_value, params))
|
|
valid = FALSE;
|
|
|
|
g_value_unset (&tmp_value);
|
|
}
|
|
|
|
g_variant_unref (tmp_variant);
|
|
types++;
|
|
params++;
|
|
}
|
|
|
|
if (!valid)
|
|
{
|
|
guint j;
|
|
|
|
for (j = 0; j < i; j++)
|
|
g_value_unset (&(*params_p)[j]);
|
|
|
|
g_free (*params_p);
|
|
*params_p = NULL;
|
|
}
|
|
|
|
return valid;
|
|
}
|
|
|
|
static gboolean
|
|
gtk_signal_action_emit_signal (GtkWidget *widget,
|
|
const char *signal,
|
|
GVariant *args,
|
|
gboolean *handled,
|
|
GError **error)
|
|
{
|
|
GSignalQuery query;
|
|
guint signal_id;
|
|
GValue *params = NULL;
|
|
GValue return_val = G_VALUE_INIT;
|
|
GVariantIter args_iter;
|
|
gsize n_args;
|
|
guint i;
|
|
|
|
*handled = FALSE;
|
|
|
|
signal_id = g_signal_lookup (signal, G_OBJECT_TYPE (widget));
|
|
if (!signal_id)
|
|
{
|
|
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
|
|
"Could not find signal \"%s\" in the '%s' class ancestry",
|
|
signal,
|
|
g_type_name (G_OBJECT_TYPE (widget)));
|
|
return FALSE;
|
|
}
|
|
|
|
g_signal_query (signal_id, &query);
|
|
if (args == NULL)
|
|
n_args = 0;
|
|
else if (g_variant_is_of_type (args, G_VARIANT_TYPE_TUPLE))
|
|
n_args = g_variant_iter_init (&args_iter, args);
|
|
else
|
|
{
|
|
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
|
|
"argument GVariant is not a tuple");
|
|
return FALSE;
|
|
}
|
|
if (query.n_params != n_args ||
|
|
(query.return_type != G_TYPE_NONE && query.return_type != G_TYPE_BOOLEAN) ||
|
|
!binding_compose_params (widget, &args_iter, &query, ¶ms))
|
|
{
|
|
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
|
|
"signature mismatch for signal \"%s\" in the '%s' class ancestry",
|
|
signal,
|
|
g_type_name (G_OBJECT_TYPE (widget)));
|
|
return FALSE;
|
|
}
|
|
else if (!(query.signal_flags & G_SIGNAL_ACTION))
|
|
{
|
|
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
|
|
"signal \"%s\" in the '%s' class ancestry cannot be used for action emissions",
|
|
signal,
|
|
g_type_name (G_OBJECT_TYPE (widget)));
|
|
return FALSE;
|
|
}
|
|
|
|
if (query.return_type == G_TYPE_BOOLEAN)
|
|
g_value_init (&return_val, G_TYPE_BOOLEAN);
|
|
|
|
g_signal_emitv (params, signal_id, 0, &return_val);
|
|
|
|
if (query.return_type == G_TYPE_BOOLEAN)
|
|
{
|
|
if (g_value_get_boolean (&return_val))
|
|
*handled = TRUE;
|
|
g_value_unset (&return_val);
|
|
}
|
|
else
|
|
*handled = TRUE;
|
|
|
|
if (params != NULL)
|
|
{
|
|
for (i = 0; i < query.n_params + 1; i++)
|
|
g_value_unset (¶ms[i]);
|
|
|
|
g_free (params);
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
static gboolean
|
|
gtk_signal_action_activate (GtkShortcutAction *action,
|
|
GtkShortcutActionFlags flags,
|
|
GtkWidget *widget,
|
|
GVariant *args)
|
|
{
|
|
GtkSignalAction *self = GTK_SIGNAL_ACTION (action);
|
|
GError *error = NULL;
|
|
gboolean handled;
|
|
|
|
if (!gtk_signal_action_emit_signal (widget,
|
|
self->name,
|
|
args,
|
|
&handled,
|
|
&error))
|
|
{
|
|
g_warning ("gtk_signal_action_activate(): %s",
|
|
error->message);
|
|
g_clear_error (&error);
|
|
return FALSE;
|
|
}
|
|
|
|
return handled;
|
|
}
|
|
|
|
static void
|
|
gtk_signal_action_print (GtkShortcutAction *action,
|
|
GString *string)
|
|
{
|
|
GtkSignalAction *self = GTK_SIGNAL_ACTION (action);
|
|
|
|
g_string_append_printf (string, "signal(%s)", self->name);
|
|
}
|
|
|
|
static void
|
|
gtk_signal_action_constructed (GObject *gobject)
|
|
{
|
|
GtkSignalAction *self G_GNUC_UNUSED = GTK_SIGNAL_ACTION (gobject);
|
|
|
|
g_assert (self->name != NULL && self->name[0] != '\0');
|
|
|
|
G_OBJECT_CLASS (gtk_signal_action_parent_class)->constructed (gobject);
|
|
}
|
|
|
|
static void
|
|
gtk_signal_action_set_property (GObject *gobject,
|
|
guint prop_id,
|
|
const GValue *value,
|
|
GParamSpec *pspec)
|
|
{
|
|
GtkSignalAction *self = GTK_SIGNAL_ACTION (gobject);
|
|
|
|
switch (prop_id)
|
|
{
|
|
case SIGNAL_PROP_SIGNAL_NAME:
|
|
self->name = g_value_dup_string (value);
|
|
break;
|
|
|
|
default:
|
|
G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec);
|
|
}
|
|
}
|
|
|
|
static void
|
|
gtk_signal_action_get_property (GObject *gobject,
|
|
guint prop_id,
|
|
GValue *value,
|
|
GParamSpec *pspec)
|
|
{
|
|
GtkSignalAction *self = GTK_SIGNAL_ACTION (gobject);
|
|
|
|
switch (prop_id)
|
|
{
|
|
case SIGNAL_PROP_SIGNAL_NAME:
|
|
g_value_set_string (value, self->name);
|
|
break;
|
|
|
|
default:
|
|
G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec);
|
|
}
|
|
}
|
|
|
|
static void
|
|
gtk_signal_action_class_init (GtkSignalActionClass *klass)
|
|
{
|
|
GtkShortcutActionClass *action_class = GTK_SHORTCUT_ACTION_CLASS (klass);
|
|
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
|
|
|
|
gobject_class->constructed = gtk_signal_action_constructed;
|
|
gobject_class->set_property = gtk_signal_action_set_property;
|
|
gobject_class->get_property = gtk_signal_action_get_property;
|
|
gobject_class->finalize = gtk_signal_action_finalize;
|
|
|
|
action_class->activate = gtk_signal_action_activate;
|
|
action_class->print = gtk_signal_action_print;
|
|
|
|
/**
|
|
* GtkSignalAction:signal-name: (attributes org.gtk.Property.get=gtk_signal_action_get_signal_name)
|
|
*
|
|
* The name of the signal to emit.
|
|
*/
|
|
signal_props[SIGNAL_PROP_SIGNAL_NAME] =
|
|
g_param_spec_string (I_("signal-name"), NULL, NULL,
|
|
NULL,
|
|
G_PARAM_STATIC_STRINGS |
|
|
G_PARAM_READWRITE |
|
|
G_PARAM_CONSTRUCT_ONLY);
|
|
|
|
g_object_class_install_properties (gobject_class, SIGNAL_N_PROPS, signal_props);
|
|
}
|
|
|
|
static void
|
|
gtk_signal_action_init (GtkSignalAction *self)
|
|
{
|
|
}
|
|
|
|
/**
|
|
* gtk_signal_action_new:
|
|
* @signal_name: name of the signal to emit
|
|
*
|
|
* Creates an action that when activated, emits the given action signal
|
|
* on the provided widget.
|
|
*
|
|
* It will also unpack the args into arguments passed to the signal.
|
|
*
|
|
* Returns: (transfer full) (type GtkSignalAction): a new `GtkShortcutAction`
|
|
*/
|
|
GtkShortcutAction *
|
|
gtk_signal_action_new (const char *signal_name)
|
|
{
|
|
g_return_val_if_fail (signal_name != NULL, NULL);
|
|
|
|
return g_object_new (GTK_TYPE_SIGNAL_ACTION,
|
|
"signal-name", signal_name,
|
|
NULL);
|
|
}
|
|
|
|
/**
|
|
* gtk_signal_action_get_signal_name: (attributes org.gtk.Method.get_property=signal-name)
|
|
* @self: a signal action
|
|
*
|
|
* Returns the name of the signal that will be emitted.
|
|
*
|
|
* Returns: (transfer none): the name of the signal to emit
|
|
*/
|
|
const char *
|
|
gtk_signal_action_get_signal_name (GtkSignalAction *self)
|
|
{
|
|
g_return_val_if_fail (GTK_IS_SIGNAL_ACTION (self), NULL);
|
|
|
|
return self->name;
|
|
}
|
|
|
|
/* }}} */
|
|
|
|
/* {{{ GtkNamedAction */
|
|
|
|
struct _GtkNamedAction
|
|
{
|
|
GtkShortcutAction parent_instance;
|
|
|
|
char *name;
|
|
};
|
|
|
|
struct _GtkNamedActionClass
|
|
{
|
|
GtkShortcutActionClass parent_class;
|
|
};
|
|
|
|
enum
|
|
{
|
|
NAMED_PROP_ACTION_NAME = 1,
|
|
NAMED_N_PROPS
|
|
};
|
|
|
|
static GParamSpec *named_props[NAMED_N_PROPS];
|
|
|
|
G_DEFINE_TYPE (GtkNamedAction, gtk_named_action, GTK_TYPE_SHORTCUT_ACTION)
|
|
|
|
static void
|
|
gtk_named_action_finalize (GObject *gobject)
|
|
{
|
|
GtkNamedAction *self = GTK_NAMED_ACTION (gobject);
|
|
|
|
g_free (self->name);
|
|
|
|
G_OBJECT_CLASS (gtk_named_action_parent_class)->finalize (gobject);
|
|
}
|
|
|
|
static gboolean
|
|
check_parameter_type (GVariant *args,
|
|
const GVariantType *parameter_type)
|
|
{
|
|
if (args)
|
|
{
|
|
if (parameter_type == NULL)
|
|
{
|
|
g_warning ("Trying to invoke action with arguments, but action has no parameter");
|
|
return FALSE;
|
|
}
|
|
|
|
if (!g_variant_is_of_type (args, parameter_type))
|
|
{
|
|
char *typestr = g_variant_type_dup_string (parameter_type);
|
|
char *targetstr = g_variant_print (args, TRUE);
|
|
g_warning ("Trying to invoke action with target '%s',"
|
|
" but action expects parameter with type '%s'", targetstr, typestr);
|
|
g_free (targetstr);
|
|
g_free (typestr);
|
|
return FALSE;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (parameter_type != NULL)
|
|
{
|
|
char *typestr = g_variant_type_dup_string (parameter_type);
|
|
g_warning ("Trying to invoke action without arguments,"
|
|
" but action expects parameter with type '%s'", typestr);
|
|
g_free (typestr);
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
static gboolean
|
|
gtk_named_action_activate (GtkShortcutAction *action,
|
|
GtkShortcutActionFlags flags,
|
|
GtkWidget *widget,
|
|
GVariant *args)
|
|
{
|
|
GtkNamedAction *self = GTK_NAMED_ACTION (action);
|
|
const GVariantType *parameter_type;
|
|
GtkActionMuxer *muxer;
|
|
gboolean enabled;
|
|
|
|
muxer = _gtk_widget_get_action_muxer (widget, FALSE);
|
|
if (muxer == NULL)
|
|
return FALSE;
|
|
|
|
if (!gtk_action_muxer_query_action (muxer, self->name,
|
|
&enabled, ¶meter_type,
|
|
NULL, NULL, NULL))
|
|
return FALSE;
|
|
|
|
if (!enabled)
|
|
return FALSE;
|
|
|
|
/* We found an action with the correct name and it's enabled.
|
|
* This is the action that we are going to try to invoke.
|
|
*
|
|
* There is still the possibility that the args don't
|
|
* match the expected parameter type. In that case, we will print
|
|
* a warning.
|
|
*/
|
|
if (!check_parameter_type (args, parameter_type))
|
|
return FALSE;
|
|
|
|
gtk_action_muxer_activate_action (muxer, self->name, args);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
static void
|
|
gtk_named_action_print (GtkShortcutAction *action,
|
|
GString *string)
|
|
{
|
|
GtkNamedAction *self = GTK_NAMED_ACTION (action);
|
|
|
|
g_string_append_printf (string, "action(%s)", self->name);
|
|
}
|
|
|
|
static void
|
|
gtk_named_action_set_property (GObject *gobject,
|
|
guint prop_id,
|
|
const GValue *value,
|
|
GParamSpec *pspec)
|
|
{
|
|
GtkNamedAction *self = GTK_NAMED_ACTION (gobject);
|
|
|
|
switch (prop_id)
|
|
{
|
|
case NAMED_PROP_ACTION_NAME:
|
|
self->name = g_value_dup_string (value);
|
|
break;
|
|
|
|
default:
|
|
G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec);
|
|
}
|
|
}
|
|
|
|
static void
|
|
gtk_named_action_get_property (GObject *gobject,
|
|
guint prop_id,
|
|
GValue *value,
|
|
GParamSpec *pspec)
|
|
{
|
|
GtkNamedAction *self = GTK_NAMED_ACTION (gobject);
|
|
|
|
switch (prop_id)
|
|
{
|
|
case NAMED_PROP_ACTION_NAME:
|
|
g_value_set_string (value, self->name);
|
|
break;
|
|
|
|
default:
|
|
G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec);
|
|
}
|
|
}
|
|
|
|
static void
|
|
gtk_named_action_constructed (GObject *gobject)
|
|
{
|
|
GtkNamedAction *self G_GNUC_UNUSED = GTK_NAMED_ACTION (gobject);
|
|
|
|
g_assert (self->name != NULL && self->name[0] != '\0');
|
|
|
|
G_OBJECT_CLASS (gtk_named_action_parent_class)->constructed (gobject);
|
|
}
|
|
|
|
static void
|
|
gtk_named_action_class_init (GtkNamedActionClass *klass)
|
|
{
|
|
GtkShortcutActionClass *action_class = GTK_SHORTCUT_ACTION_CLASS (klass);
|
|
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
|
|
|
|
gobject_class->constructed = gtk_named_action_constructed;
|
|
gobject_class->set_property = gtk_named_action_set_property;
|
|
gobject_class->get_property = gtk_named_action_get_property;
|
|
gobject_class->finalize = gtk_named_action_finalize;
|
|
|
|
action_class->activate = gtk_named_action_activate;
|
|
action_class->print = gtk_named_action_print;
|
|
|
|
/**
|
|
* GtkNamedAction:action-name: (attributes org.gtk.Property.get=gtk_named_action_get_action_name)
|
|
*
|
|
* The name of the action to activate.
|
|
*/
|
|
named_props[NAMED_PROP_ACTION_NAME] =
|
|
g_param_spec_string (I_("action-name"), NULL, NULL,
|
|
NULL,
|
|
G_PARAM_STATIC_STRINGS |
|
|
G_PARAM_READWRITE |
|
|
G_PARAM_CONSTRUCT_ONLY);
|
|
|
|
g_object_class_install_properties (gobject_class, NAMED_N_PROPS, named_props);
|
|
}
|
|
|
|
static void
|
|
gtk_named_action_init (GtkNamedAction *self)
|
|
{
|
|
}
|
|
|
|
/**
|
|
* gtk_named_action_new:
|
|
* @name: the detailed name of the action
|
|
*
|
|
* Creates an action that when activated, activates
|
|
* the named action on the widget.
|
|
*
|
|
* It also passes the given arguments to it.
|
|
*
|
|
* See [method@Gtk.Widget.insert_action_group] for
|
|
* how to add actions to widgets.
|
|
*
|
|
* Returns: (transfer full) (type GtkNamedAction): a new `GtkShortcutAction`
|
|
*/
|
|
GtkShortcutAction *
|
|
gtk_named_action_new (const char *name)
|
|
{
|
|
g_return_val_if_fail (name != NULL, NULL);
|
|
|
|
return g_object_new (GTK_TYPE_NAMED_ACTION,
|
|
"action-name", name,
|
|
NULL);
|
|
}
|
|
|
|
/**
|
|
* gtk_named_action_get_action_name: (attributes org.gtk.Method.get_property=action-name)
|
|
* @self: a named action
|
|
*
|
|
* Returns the name of the action that will be activated.
|
|
*
|
|
* Returns: the name of the action to activate
|
|
*/
|
|
const char *
|
|
gtk_named_action_get_action_name (GtkNamedAction *self)
|
|
{
|
|
g_return_val_if_fail (GTK_IS_NAMED_ACTION (self), NULL);
|
|
|
|
return self->name;
|
|
}
|