2020-03-15 13:49:50 +00:00
|
|
|
/*
|
|
|
|
* Copyright © 2018 Benjamin Otte
|
|
|
|
*
|
2020-03-19 15:57:02 +00:00
|
|
|
* SPDX-License-Identifier: LGPL-2.1-or-later
|
|
|
|
*
|
2020-03-15 13:49:50 +00:00
|
|
|
* 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>
|
|
|
|
*/
|
|
|
|
|
|
|
|
/**
|
|
|
|
* SECTION:gtkshortcuttrigger
|
|
|
|
* @Title: GtkShortcutTrigger
|
|
|
|
* @Short_description: Triggers to track if shortcuts should be activated
|
|
|
|
* @See_also: #GtkShortcut
|
|
|
|
*
|
|
|
|
* #GtkShortcutTrigger is the object used to track if a #GtkShortcut should be
|
|
|
|
* activated. For this purpose, gtk_shortcut_trigger_trigger() can be called
|
|
|
|
* on a #GdkEvent.
|
|
|
|
*
|
|
|
|
* #GtkShortcutTriggers contain functions that allow easy presentation to end
|
|
|
|
* users as well as being printed for debugging.
|
|
|
|
*
|
|
|
|
* All #GtkShortcutTriggers are immutable, you can only specify their properties
|
|
|
|
* during construction. If you want to change a trigger, you have to replace it
|
|
|
|
* with a new one.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include "config.h"
|
|
|
|
|
|
|
|
#include "gtkshortcuttrigger.h"
|
|
|
|
|
2018-08-13 03:45:12 +00:00
|
|
|
#include "gtkaccelgroupprivate.h"
|
2020-03-22 13:54:15 +00:00
|
|
|
#include "gtkprivate.h"
|
2020-03-19 15:57:02 +00:00
|
|
|
#include "gtkintl.h"
|
2020-03-15 13:49:50 +00:00
|
|
|
|
2020-03-19 15:57:02 +00:00
|
|
|
#define GTK_SHORTCUT_TRIGGER_HASH_NEVER 0u
|
|
|
|
#define GTK_SHORTCUT_TRIGGER_HASH_KEYVAL 1u
|
|
|
|
#define GTK_SHORTCUT_TRIGGER_HASH_MNEMONIC 2u
|
|
|
|
#define GTK_SHORTCUT_TRIGGER_HASH_ALTERNATIVE 3u
|
2020-03-15 13:49:50 +00:00
|
|
|
|
|
|
|
struct _GtkShortcutTrigger
|
|
|
|
{
|
2020-03-19 15:57:02 +00:00
|
|
|
GObject parent_instance;
|
2020-03-15 13:49:50 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
struct _GtkShortcutTriggerClass
|
|
|
|
{
|
2020-03-19 15:57:02 +00:00
|
|
|
GObjectClass parent_class;
|
2020-03-15 13:49:50 +00:00
|
|
|
|
2020-04-05 18:40:55 +00:00
|
|
|
GdkKeyMatch (* trigger) (GtkShortcutTrigger *trigger,
|
2018-08-16 01:59:24 +00:00
|
|
|
GdkEvent *event,
|
|
|
|
gboolean enable_mnemonics);
|
2018-08-20 07:18:59 +00:00
|
|
|
guint (* hash) (GtkShortcutTrigger *trigger);
|
|
|
|
int (* compare) (GtkShortcutTrigger *trigger1,
|
|
|
|
GtkShortcutTrigger *trigger2);
|
2020-03-15 13:49:50 +00:00
|
|
|
void (* print) (GtkShortcutTrigger *trigger,
|
|
|
|
GString *string);
|
2018-08-13 03:45:12 +00:00
|
|
|
gboolean (* print_label) (GtkShortcutTrigger *trigger,
|
|
|
|
GdkDisplay *display,
|
|
|
|
GString *string);
|
2020-03-15 13:49:50 +00:00
|
|
|
};
|
|
|
|
|
2020-03-19 15:57:02 +00:00
|
|
|
G_DEFINE_ABSTRACT_TYPE (GtkShortcutTrigger, gtk_shortcut_trigger, G_TYPE_OBJECT)
|
2020-03-15 13:49:50 +00:00
|
|
|
|
|
|
|
static void
|
2020-03-19 15:57:02 +00:00
|
|
|
gtk_shortcut_trigger_class_init (GtkShortcutTriggerClass *klass)
|
2020-03-15 13:49:50 +00:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2020-03-19 15:57:02 +00:00
|
|
|
static void
|
|
|
|
gtk_shortcut_trigger_init (GtkShortcutTrigger *self)
|
2020-03-15 13:49:50 +00:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* gtk_shortcut_trigger_trigger:
|
|
|
|
* @self: a #GtkShortcutTrigger
|
|
|
|
* @event: the event to check
|
2018-08-16 01:59:24 +00:00
|
|
|
* @enable_mnemonics: %TRUE if mnemonics should trigger. Usually the
|
|
|
|
* value of this property is determined by checking that the passed
|
|
|
|
* in @event is a Key event and has the right modifiers set.
|
2020-03-15 13:49:50 +00:00
|
|
|
*
|
2020-03-22 13:16:57 +00:00
|
|
|
* Checks if the given @event triggers @self.
|
2020-03-15 13:49:50 +00:00
|
|
|
*
|
2020-03-22 13:16:57 +00:00
|
|
|
* Returns: Whether the event triggered the shortcut
|
2020-03-15 13:49:50 +00:00
|
|
|
**/
|
2020-04-05 18:40:55 +00:00
|
|
|
GdkKeyMatch
|
2020-03-15 13:49:50 +00:00
|
|
|
gtk_shortcut_trigger_trigger (GtkShortcutTrigger *self,
|
2018-08-16 01:59:24 +00:00
|
|
|
GdkEvent *event,
|
|
|
|
gboolean enable_mnemonics)
|
2020-03-15 13:49:50 +00:00
|
|
|
{
|
2020-04-05 18:40:55 +00:00
|
|
|
g_return_val_if_fail (GTK_IS_SHORTCUT_TRIGGER (self), GDK_KEY_MATCH_NONE);
|
2020-03-15 13:49:50 +00:00
|
|
|
|
2020-03-19 15:57:02 +00:00
|
|
|
return GTK_SHORTCUT_TRIGGER_GET_CLASS (self)->trigger (self, event, enable_mnemonics);
|
2020-03-15 13:49:50 +00:00
|
|
|
}
|
|
|
|
|
2018-08-23 19:07:36 +00:00
|
|
|
/**
|
2020-03-19 15:57:02 +00:00
|
|
|
* gtk_shortcut_trigger_parse_string: (constructor)
|
2018-08-23 19:07:36 +00:00
|
|
|
* @string: the string to parse
|
|
|
|
*
|
|
|
|
* Tries to parse the given string into a trigger. On success,
|
|
|
|
* the parsed trigger is returned. When parsing failed, %NULL is
|
|
|
|
* returned.
|
|
|
|
*
|
2020-03-19 15:57:02 +00:00
|
|
|
* The accepted strings are:
|
2018-08-23 19:07:36 +00:00
|
|
|
*
|
2020-03-19 15:57:02 +00:00
|
|
|
* - `never`, for #GtkNeverTrigger
|
2020-04-04 15:38:47 +00:00
|
|
|
* - a string parsed by gtk_accelerator_parse(), for a #GtkKeyvalTrigger, e.g. `<Control>C`
|
|
|
|
* - underscore, followed by a single character, for MnemonicTrigger, e.g. `_l`
|
2020-03-26 16:58:55 +00:00
|
|
|
* - two valid trigger strings, separated by a `|` character, for a
|
2020-04-04 15:38:47 +00:00
|
|
|
* #GtkAlternativeTrigger: `<Control>q|<Control>w`
|
2020-03-19 15:57:02 +00:00
|
|
|
*
|
2020-03-26 17:11:25 +00:00
|
|
|
* Returns: (nullable) (transfer full): a new #GtkShortcutTrigger
|
|
|
|
* or %NULL on error
|
2020-03-19 15:57:02 +00:00
|
|
|
*/
|
2018-08-23 19:07:36 +00:00
|
|
|
GtkShortcutTrigger *
|
|
|
|
gtk_shortcut_trigger_parse_string (const char *string)
|
|
|
|
{
|
|
|
|
GdkModifierType modifiers;
|
|
|
|
guint keyval;
|
2020-03-26 16:58:55 +00:00
|
|
|
const char *sep;
|
2018-08-23 19:07:36 +00:00
|
|
|
|
|
|
|
g_return_val_if_fail (string != NULL, NULL);
|
|
|
|
|
2020-03-26 16:58:55 +00:00
|
|
|
if ((sep = strchr (string, '|')) != NULL)
|
|
|
|
{
|
|
|
|
char *frag_a = g_strndup (string, sep - string);
|
|
|
|
const char *frag_b = sep + 1;
|
|
|
|
GtkShortcutTrigger *t1, *t2;
|
|
|
|
|
|
|
|
/* empty first slot */
|
|
|
|
if (*frag_a == '\0')
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
/* empty second slot */
|
|
|
|
if (*frag_b == '\0')
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
t1 = gtk_shortcut_trigger_parse_string (frag_a);
|
|
|
|
if (t1 == NULL)
|
|
|
|
{
|
|
|
|
g_free (frag_a);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
t2 = gtk_shortcut_trigger_parse_string (frag_b);
|
|
|
|
if (t2 == NULL)
|
|
|
|
{
|
|
|
|
g_object_unref (t1);
|
|
|
|
g_free (frag_a);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
g_free (frag_a);
|
|
|
|
|
|
|
|
return gtk_alternative_trigger_new (t1, t2);
|
|
|
|
}
|
|
|
|
|
2020-03-19 15:57:02 +00:00
|
|
|
if (g_str_equal (string, "never"))
|
2020-03-26 17:11:25 +00:00
|
|
|
return g_object_ref (gtk_never_trigger_get ());
|
2020-03-19 15:57:02 +00:00
|
|
|
|
|
|
|
if (string[0] == '_')
|
|
|
|
{
|
2020-03-26 16:47:15 +00:00
|
|
|
keyval = gdk_keyval_from_name (string + 1);
|
|
|
|
if (keyval != GDK_KEY_VoidSymbol)
|
|
|
|
return gtk_mnemonic_trigger_new (gdk_keyval_to_lower (keyval));
|
2020-03-19 15:57:02 +00:00
|
|
|
}
|
|
|
|
|
2018-08-23 19:07:36 +00:00
|
|
|
if (gtk_accelerator_parse (string, &keyval, &modifiers))
|
|
|
|
return gtk_keyval_trigger_new (keyval, modifiers);
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2020-03-15 13:49:50 +00:00
|
|
|
/**
|
|
|
|
* gtk_shortcut_trigger_to_string:
|
|
|
|
* @self: a #GtkShortcutTrigger
|
|
|
|
*
|
|
|
|
* Prints the given trigger into a human-readable string.
|
2020-03-24 21:01:18 +00:00
|
|
|
* This is a small wrapper around gtk_shortcut_trigger_print()
|
2020-03-15 13:49:50 +00:00
|
|
|
* to help when debugging.
|
|
|
|
*
|
|
|
|
* Returns: (transfer full): a new string
|
2020-03-19 15:57:02 +00:00
|
|
|
*/
|
2020-03-15 13:49:50 +00:00
|
|
|
char *
|
|
|
|
gtk_shortcut_trigger_to_string (GtkShortcutTrigger *self)
|
|
|
|
{
|
|
|
|
GString *string;
|
|
|
|
|
|
|
|
g_return_val_if_fail (self != NULL, NULL);
|
|
|
|
|
|
|
|
string = g_string_new (NULL);
|
2020-03-19 15:57:02 +00:00
|
|
|
|
2020-03-15 13:49:50 +00:00
|
|
|
gtk_shortcut_trigger_print (self, string);
|
|
|
|
|
|
|
|
return g_string_free (string, FALSE);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* gtk_shortcut_trigger_print:
|
|
|
|
* @self: a #GtkShortcutTrigger
|
|
|
|
* @string: a #GString to print into
|
|
|
|
*
|
|
|
|
* Prints the given trigger 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.
|
2020-03-19 15:57:02 +00:00
|
|
|
*/
|
2020-03-15 13:49:50 +00:00
|
|
|
void
|
|
|
|
gtk_shortcut_trigger_print (GtkShortcutTrigger *self,
|
|
|
|
GString *string)
|
|
|
|
{
|
|
|
|
g_return_if_fail (GTK_IS_SHORTCUT_TRIGGER (self));
|
|
|
|
g_return_if_fail (string != NULL);
|
|
|
|
|
2020-03-19 15:57:02 +00:00
|
|
|
GTK_SHORTCUT_TRIGGER_GET_CLASS (self)->print (self, string);
|
2020-03-15 13:49:50 +00:00
|
|
|
}
|
|
|
|
|
2018-08-13 03:45:12 +00:00
|
|
|
/**
|
|
|
|
* gtk_shortcut_trigger_to_label:
|
|
|
|
* @self: a #GtkShortcutTrigger
|
|
|
|
* @display: #GdkDisplay to print for
|
|
|
|
*
|
|
|
|
* Gets textual representation for the given trigger. This
|
|
|
|
* function is returning a translated string for presentation
|
|
|
|
* to end users for example in menu items or in help texts.
|
|
|
|
*
|
|
|
|
* The @display in use may influence the resulting string in
|
|
|
|
* various forms, such as resolving hardware keycodes or by
|
|
|
|
* causing display-specific modifier names.
|
|
|
|
*
|
|
|
|
* The form of the representation may change at any time and is
|
|
|
|
* not guaranteed to stay identical.
|
|
|
|
*
|
|
|
|
* Returns: (transfer full): a new string
|
|
|
|
**/
|
|
|
|
char *
|
|
|
|
gtk_shortcut_trigger_to_label (GtkShortcutTrigger *self,
|
|
|
|
GdkDisplay *display)
|
|
|
|
{
|
|
|
|
GString *string;
|
|
|
|
|
|
|
|
g_return_val_if_fail (self != NULL, NULL);
|
|
|
|
|
|
|
|
string = g_string_new (NULL);
|
|
|
|
gtk_shortcut_trigger_print_label (self, display, string);
|
|
|
|
|
|
|
|
return g_string_free (string, FALSE);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* gtk_shortcut_trigger_print_label:
|
|
|
|
* @self: a #GtkShortcutTrigger
|
|
|
|
* @display: #GdkDisplay to print for
|
|
|
|
* @string: a #GString to print into
|
|
|
|
*
|
|
|
|
* Prints the given trigger into a string. This function is
|
|
|
|
* returning a translated string for presentation to end users
|
|
|
|
* for example in menu items or in help texts.
|
|
|
|
*
|
|
|
|
* The @display in use may influence the resulting string in
|
|
|
|
* various forms, such as resolving hardware keycodes or by
|
|
|
|
* causing display-specific modifier names.
|
|
|
|
*
|
|
|
|
* The form of the representation may change at any time and is
|
|
|
|
* not guaranteed to stay identical.
|
|
|
|
*
|
|
|
|
* Returns: %TRUE if something was printed or %FALSE if the
|
|
|
|
* trigger did not have a textual representation suitable
|
|
|
|
* for end users.
|
|
|
|
**/
|
|
|
|
gboolean
|
|
|
|
gtk_shortcut_trigger_print_label (GtkShortcutTrigger *self,
|
|
|
|
GdkDisplay *display,
|
|
|
|
GString *string)
|
|
|
|
{
|
|
|
|
g_return_val_if_fail (GTK_IS_SHORTCUT_TRIGGER (self), FALSE);
|
|
|
|
g_return_val_if_fail (GDK_IS_DISPLAY (display), FALSE);
|
|
|
|
g_return_val_if_fail (string != NULL, FALSE);
|
|
|
|
|
2020-03-19 15:57:02 +00:00
|
|
|
return GTK_SHORTCUT_TRIGGER_GET_CLASS (self)->print_label (self, display, string);
|
2018-08-13 03:45:12 +00:00
|
|
|
}
|
|
|
|
|
2018-08-20 07:18:59 +00:00
|
|
|
/**
|
|
|
|
* gtk_shortcut_trigger_hash:
|
|
|
|
* @trigger: (type GtkShortcutTrigger): a #GtkShortcutTrigger
|
|
|
|
*
|
|
|
|
* Generates a hash value for a #GtkShortcutTrigger.
|
|
|
|
*
|
|
|
|
* The output of this function is guaranteed to be the same for a given
|
|
|
|
* value only per-process. It may change between different processor
|
|
|
|
* architectures or even different versions of GTK. Do not use this
|
|
|
|
* function as a basis for building protocols or file formats.
|
|
|
|
*
|
|
|
|
* The types of @trigger is #gconstpointer only to allow use of this
|
|
|
|
* function with #GHashTable. They must each be a #GtkShortcutTrigger.
|
|
|
|
*
|
|
|
|
* Returns: a hash value corresponding to @trigger
|
|
|
|
**/
|
|
|
|
guint
|
|
|
|
gtk_shortcut_trigger_hash (gconstpointer trigger)
|
|
|
|
{
|
|
|
|
GtkShortcutTrigger *t = (GtkShortcutTrigger *) trigger;
|
|
|
|
|
2020-03-19 15:57:02 +00:00
|
|
|
g_return_val_if_fail (GTK_IS_SHORTCUT_TRIGGER (t), 0);
|
2018-08-20 07:18:59 +00:00
|
|
|
|
2020-03-19 15:57:02 +00:00
|
|
|
return GTK_SHORTCUT_TRIGGER_GET_CLASS (t)->hash (t);
|
2018-08-20 07:18:59 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* gtk_shortcut_trigger_equal:
|
|
|
|
* @trigger1: (type GtkShortcutTrigger): a #GtkShortcutTrigger
|
|
|
|
* @trigger2: (type GtkShortcutTrigger): a #GtkShortcutTrigger
|
|
|
|
*
|
|
|
|
* Checks if @trigger1 and @trigger2 trigger under the same conditions.
|
|
|
|
*
|
|
|
|
* The types of @one and @two are #gconstpointer only to allow use of this
|
|
|
|
* function with #GHashTable. They must each be a #GtkShortcutTrigger.
|
|
|
|
*
|
|
|
|
* Returns: %TRUE if @trigger1 and @trigger2 are equal
|
|
|
|
**/
|
|
|
|
gboolean
|
|
|
|
gtk_shortcut_trigger_equal (gconstpointer trigger1,
|
|
|
|
gconstpointer trigger2)
|
|
|
|
{
|
|
|
|
return gtk_shortcut_trigger_compare (trigger1, trigger2) == 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* gtk_shortcut_trigger_compare:
|
|
|
|
* @trigger1: (type GtkShortcutTrigger): a #GtkShortcutTrigger
|
|
|
|
* @trigger2: (type GtkShortcutTrigger): a #GtkShortcutTrigger
|
|
|
|
*
|
2020-03-24 21:01:18 +00:00
|
|
|
* The types of @trigger1 and @trigger2 are #gconstpointer only to allow
|
|
|
|
* use of this function as a #GCompareFunc. They must each be a
|
|
|
|
* #GtkShortcutTrigger.
|
2018-08-20 07:18:59 +00:00
|
|
|
*
|
|
|
|
* Returns: An integer less than, equal to, or greater than zero if
|
|
|
|
* @trigger1 is found, respectively, to be less than, to match,
|
|
|
|
* or be greater than @trigger2.
|
|
|
|
**/
|
|
|
|
gint
|
|
|
|
gtk_shortcut_trigger_compare (gconstpointer trigger1,
|
|
|
|
gconstpointer trigger2)
|
|
|
|
{
|
|
|
|
GtkShortcutTrigger *t1 = (GtkShortcutTrigger *) trigger1;
|
|
|
|
GtkShortcutTrigger *t2 = (GtkShortcutTrigger *) trigger2;
|
2020-03-19 15:57:02 +00:00
|
|
|
GType type1, type2;
|
2018-08-20 07:18:59 +00:00
|
|
|
|
2020-03-19 15:57:02 +00:00
|
|
|
g_return_val_if_fail (GTK_IS_SHORTCUT_TRIGGER (t1), -1);
|
|
|
|
g_return_val_if_fail (GTK_IS_SHORTCUT_TRIGGER (t2), 1);
|
2018-08-20 07:18:59 +00:00
|
|
|
|
2020-03-19 15:57:02 +00:00
|
|
|
type1 = G_OBJECT_TYPE (t1);
|
|
|
|
type2 = G_OBJECT_TYPE (t2);
|
2018-08-20 07:18:59 +00:00
|
|
|
|
2020-03-19 15:57:02 +00:00
|
|
|
if (type1 == type2)
|
|
|
|
{
|
|
|
|
return GTK_SHORTCUT_TRIGGER_GET_CLASS (t1)->compare (t1, t2);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{ /* never < keyval < mnemonic < alternative */
|
|
|
|
if (type1 == GTK_TYPE_NEVER_TRIGGER ||
|
|
|
|
type2 == GTK_TYPE_ALTERNATIVE_TRIGGER)
|
|
|
|
return -1;
|
|
|
|
if (type2 == GTK_TYPE_NEVER_TRIGGER ||
|
|
|
|
type1 == GTK_TYPE_ALTERNATIVE_TRIGGER)
|
|
|
|
return 1;
|
|
|
|
|
|
|
|
if (type1 == GTK_TYPE_KEYVAL_TRIGGER)
|
|
|
|
return -1;
|
|
|
|
else
|
|
|
|
return 1;
|
|
|
|
}
|
2018-08-20 07:18:59 +00:00
|
|
|
}
|
|
|
|
|
2020-03-15 13:49:50 +00:00
|
|
|
struct _GtkNeverTrigger
|
|
|
|
{
|
2020-03-19 15:57:02 +00:00
|
|
|
GtkShortcutTrigger parent_instance;
|
2020-03-15 13:49:50 +00:00
|
|
|
|
|
|
|
guint never;
|
|
|
|
GdkModifierType modifiers;
|
|
|
|
};
|
|
|
|
|
2020-03-19 15:57:02 +00:00
|
|
|
struct _GtkNeverTriggerClass
|
|
|
|
{
|
|
|
|
GtkShortcutTriggerClass parent_class;
|
|
|
|
};
|
|
|
|
|
|
|
|
G_DEFINE_TYPE (GtkNeverTrigger, gtk_never_trigger, GTK_TYPE_SHORTCUT_TRIGGER)
|
|
|
|
|
2020-05-18 07:41:47 +00:00
|
|
|
static void G_GNUC_NORETURN
|
2020-03-19 15:57:02 +00:00
|
|
|
gtk_never_trigger_finalize (GObject *gobject)
|
2020-03-15 13:49:50 +00:00
|
|
|
{
|
|
|
|
g_assert_not_reached ();
|
2020-03-19 15:57:02 +00:00
|
|
|
|
|
|
|
G_OBJECT_CLASS (gtk_never_trigger_parent_class)->finalize (gobject);
|
2020-03-15 13:49:50 +00:00
|
|
|
}
|
|
|
|
|
2020-04-05 18:40:55 +00:00
|
|
|
static GdkKeyMatch
|
2018-08-05 02:10:11 +00:00
|
|
|
gtk_never_trigger_trigger (GtkShortcutTrigger *trigger,
|
2018-08-16 01:59:24 +00:00
|
|
|
GdkEvent *event,
|
|
|
|
gboolean enable_mnemonics)
|
2020-03-15 13:49:50 +00:00
|
|
|
{
|
2020-04-05 18:40:55 +00:00
|
|
|
return GDK_KEY_MATCH_NONE;
|
2020-03-15 13:49:50 +00:00
|
|
|
}
|
|
|
|
|
2018-08-20 07:18:59 +00:00
|
|
|
static guint
|
|
|
|
gtk_never_trigger_hash (GtkShortcutTrigger *trigger)
|
|
|
|
{
|
2020-03-19 15:57:02 +00:00
|
|
|
return GTK_SHORTCUT_TRIGGER_HASH_NEVER;
|
2018-08-20 07:18:59 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
gtk_never_trigger_compare (GtkShortcutTrigger *trigger1,
|
|
|
|
GtkShortcutTrigger *trigger2)
|
|
|
|
{
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2020-03-15 13:49:50 +00:00
|
|
|
static void
|
2018-08-05 02:10:11 +00:00
|
|
|
gtk_never_trigger_print (GtkShortcutTrigger *trigger,
|
2020-03-15 13:49:50 +00:00
|
|
|
GString *string)
|
|
|
|
{
|
2020-03-26 16:58:55 +00:00
|
|
|
g_string_append (string, "never");
|
2020-03-15 13:49:50 +00:00
|
|
|
}
|
|
|
|
|
2018-08-13 03:45:12 +00:00
|
|
|
static gboolean
|
|
|
|
gtk_never_trigger_print_label (GtkShortcutTrigger *trigger,
|
|
|
|
GdkDisplay *display,
|
|
|
|
GString *string)
|
|
|
|
{
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
2020-03-19 15:57:02 +00:00
|
|
|
static void
|
|
|
|
gtk_never_trigger_class_init (GtkNeverTriggerClass *klass)
|
|
|
|
{
|
|
|
|
GtkShortcutTriggerClass *trigger_class = GTK_SHORTCUT_TRIGGER_CLASS (klass);
|
|
|
|
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
|
2020-03-15 13:49:50 +00:00
|
|
|
|
2020-03-19 15:57:02 +00:00
|
|
|
gobject_class->finalize = gtk_never_trigger_finalize;
|
|
|
|
|
|
|
|
trigger_class->trigger = gtk_never_trigger_trigger;
|
|
|
|
trigger_class->hash = gtk_never_trigger_hash;
|
|
|
|
trigger_class->compare = gtk_never_trigger_compare;
|
|
|
|
trigger_class->print = gtk_never_trigger_print;
|
|
|
|
trigger_class->print_label = gtk_never_trigger_print_label;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
gtk_never_trigger_init (GtkNeverTrigger *self)
|
|
|
|
{
|
|
|
|
}
|
2020-03-15 13:49:50 +00:00
|
|
|
|
|
|
|
/**
|
2018-08-05 02:10:11 +00:00
|
|
|
* gtk_never_trigger_get:
|
2020-03-15 13:49:50 +00:00
|
|
|
*
|
|
|
|
* Gets the never trigger. This is a singleton for a trigger
|
|
|
|
* that never triggers. Use this trigger instead of %NULL
|
|
|
|
* because it implements all virtual functions.
|
|
|
|
*
|
2020-03-19 15:57:02 +00:00
|
|
|
* Returns: (type GtkNeverTrigger) (transfer none): The never trigger
|
2020-03-15 13:49:50 +00:00
|
|
|
*/
|
|
|
|
GtkShortcutTrigger *
|
|
|
|
gtk_never_trigger_get (void)
|
|
|
|
{
|
2020-03-19 15:57:02 +00:00
|
|
|
static GtkShortcutTrigger *never = NULL;
|
2020-03-15 13:49:50 +00:00
|
|
|
|
2020-03-19 15:57:02 +00:00
|
|
|
if (G_UNLIKELY (never == NULL))
|
|
|
|
never = g_object_new (GTK_TYPE_NEVER_TRIGGER, NULL);
|
2020-03-15 13:49:50 +00:00
|
|
|
|
2020-03-19 15:57:02 +00:00
|
|
|
return never;
|
|
|
|
}
|
2020-03-15 13:49:50 +00:00
|
|
|
|
|
|
|
struct _GtkKeyvalTrigger
|
|
|
|
{
|
2020-03-19 15:57:02 +00:00
|
|
|
GtkShortcutTrigger parent_instance;
|
2020-03-15 13:49:50 +00:00
|
|
|
|
|
|
|
guint keyval;
|
|
|
|
GdkModifierType modifiers;
|
|
|
|
};
|
|
|
|
|
2020-03-19 15:57:02 +00:00
|
|
|
struct _GtkKeyvalTriggerClass
|
2020-03-15 13:49:50 +00:00
|
|
|
{
|
2020-03-19 15:57:02 +00:00
|
|
|
GtkShortcutTriggerClass parent_class;
|
|
|
|
};
|
|
|
|
|
|
|
|
G_DEFINE_TYPE (GtkKeyvalTrigger, gtk_keyval_trigger, GTK_TYPE_SHORTCUT_TRIGGER)
|
|
|
|
|
|
|
|
enum
|
|
|
|
{
|
|
|
|
KEYVAL_PROP_KEYVAL = 1,
|
|
|
|
KEYVAL_PROP_MODIFIERS,
|
|
|
|
KEYVAL_N_PROPS
|
|
|
|
};
|
|
|
|
|
|
|
|
static GParamSpec *keyval_props[KEYVAL_N_PROPS];
|
2020-03-15 13:49:50 +00:00
|
|
|
|
2020-04-05 18:40:55 +00:00
|
|
|
static GdkKeyMatch
|
2018-08-05 02:10:11 +00:00
|
|
|
gtk_keyval_trigger_trigger (GtkShortcutTrigger *trigger,
|
2018-08-16 01:59:24 +00:00
|
|
|
GdkEvent *event,
|
|
|
|
gboolean enable_mnemonics)
|
2020-03-15 13:49:50 +00:00
|
|
|
{
|
2020-03-19 15:57:02 +00:00
|
|
|
GtkKeyvalTrigger *self = GTK_KEYVAL_TRIGGER (trigger);
|
2020-03-15 13:49:50 +00:00
|
|
|
|
2020-04-06 23:16:41 +00:00
|
|
|
if (gdk_event_get_event_type (event) != GDK_KEY_PRESS)
|
|
|
|
return GDK_KEY_MATCH_NONE;
|
|
|
|
|
2020-04-05 18:40:55 +00:00
|
|
|
return gdk_key_event_matches (event, self->keyval, self->modifiers);
|
2020-03-15 13:49:50 +00:00
|
|
|
}
|
|
|
|
|
2018-08-20 07:18:59 +00:00
|
|
|
static guint
|
|
|
|
gtk_keyval_trigger_hash (GtkShortcutTrigger *trigger)
|
|
|
|
{
|
2020-03-19 15:57:02 +00:00
|
|
|
GtkKeyvalTrigger *self = GTK_KEYVAL_TRIGGER (trigger);
|
2018-08-20 07:18:59 +00:00
|
|
|
|
|
|
|
return (self->modifiers << 24)
|
|
|
|
| (self->modifiers >> 8)
|
|
|
|
| (self->keyval << 16)
|
2020-03-19 15:57:02 +00:00
|
|
|
| GTK_SHORTCUT_TRIGGER_HASH_KEYVAL;
|
2018-08-20 07:18:59 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
gtk_keyval_trigger_compare (GtkShortcutTrigger *trigger1,
|
|
|
|
GtkShortcutTrigger *trigger2)
|
|
|
|
{
|
2020-03-19 15:57:02 +00:00
|
|
|
GtkKeyvalTrigger *self1 = GTK_KEYVAL_TRIGGER (trigger1);
|
|
|
|
GtkKeyvalTrigger *self2 = GTK_KEYVAL_TRIGGER (trigger2);
|
2018-08-20 07:18:59 +00:00
|
|
|
|
|
|
|
if (self1->modifiers != self2->modifiers)
|
|
|
|
return self2->modifiers - self1->modifiers;
|
|
|
|
|
|
|
|
return self1->keyval - self2->keyval;
|
|
|
|
}
|
|
|
|
|
2020-03-15 13:49:50 +00:00
|
|
|
static void
|
2018-08-05 02:10:11 +00:00
|
|
|
gtk_keyval_trigger_print (GtkShortcutTrigger *trigger,
|
2020-03-15 13:49:50 +00:00
|
|
|
GString *string)
|
|
|
|
{
|
2020-03-19 15:57:02 +00:00
|
|
|
GtkKeyvalTrigger *self = GTK_KEYVAL_TRIGGER (trigger);
|
2020-03-15 13:49:50 +00:00
|
|
|
char *accelerator_name;
|
|
|
|
|
|
|
|
accelerator_name = gtk_accelerator_name (self->keyval, self->modifiers);
|
|
|
|
g_string_append (string, accelerator_name);
|
|
|
|
g_free (accelerator_name);
|
|
|
|
}
|
|
|
|
|
2018-08-13 03:45:12 +00:00
|
|
|
static gboolean
|
|
|
|
gtk_keyval_trigger_print_label (GtkShortcutTrigger *trigger,
|
|
|
|
GdkDisplay *display,
|
|
|
|
GString *string)
|
|
|
|
{
|
2020-03-19 15:57:02 +00:00
|
|
|
GtkKeyvalTrigger *self = GTK_KEYVAL_TRIGGER (trigger);
|
2018-08-13 03:45:12 +00:00
|
|
|
|
|
|
|
gtk_accelerator_print_label (string, self->keyval, self->modifiers);
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
2020-03-19 15:57:02 +00:00
|
|
|
static void
|
|
|
|
gtk_keyval_trigger_set_property (GObject *gobject,
|
|
|
|
guint prop_id,
|
|
|
|
const GValue *value,
|
|
|
|
GParamSpec *pspec)
|
|
|
|
{
|
|
|
|
GtkKeyvalTrigger *self = GTK_KEYVAL_TRIGGER (gobject);
|
|
|
|
|
|
|
|
switch (prop_id)
|
|
|
|
{
|
|
|
|
case KEYVAL_PROP_KEYVAL:
|
|
|
|
{
|
|
|
|
guint keyval = g_value_get_uint (value);
|
|
|
|
|
|
|
|
/* We store keyvals as lower key */
|
|
|
|
if (keyval == GDK_KEY_ISO_Left_Tab)
|
|
|
|
self->keyval = GDK_KEY_Tab;
|
|
|
|
else
|
|
|
|
self->keyval = gdk_keyval_to_lower (keyval);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case KEYVAL_PROP_MODIFIERS:
|
|
|
|
self->modifiers = g_value_get_flags (value);
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
gtk_keyval_trigger_get_property (GObject *gobject,
|
|
|
|
guint prop_id,
|
|
|
|
GValue *value,
|
|
|
|
GParamSpec *pspec)
|
|
|
|
{
|
|
|
|
GtkKeyvalTrigger *self = GTK_KEYVAL_TRIGGER (gobject);
|
|
|
|
|
|
|
|
switch (prop_id)
|
|
|
|
{
|
|
|
|
case KEYVAL_PROP_KEYVAL:
|
|
|
|
g_value_set_uint (value, self->keyval);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case KEYVAL_PROP_MODIFIERS:
|
|
|
|
g_value_set_flags (value, self->modifiers);
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
gtk_keyval_trigger_class_init (GtkKeyvalTriggerClass *klass)
|
|
|
|
{
|
|
|
|
GtkShortcutTriggerClass *trigger_class = GTK_SHORTCUT_TRIGGER_CLASS (klass);
|
|
|
|
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
|
|
|
|
|
|
|
|
gobject_class->set_property = gtk_keyval_trigger_set_property;
|
|
|
|
gobject_class->get_property = gtk_keyval_trigger_get_property;
|
|
|
|
|
|
|
|
trigger_class->trigger = gtk_keyval_trigger_trigger;
|
|
|
|
trigger_class->hash = gtk_keyval_trigger_hash;
|
|
|
|
trigger_class->compare = gtk_keyval_trigger_compare;
|
|
|
|
trigger_class->print = gtk_keyval_trigger_print;
|
|
|
|
trigger_class->print_label = gtk_keyval_trigger_print_label;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* GtkKeyvalTrigger:keyval:
|
|
|
|
*
|
|
|
|
* The key value for the trigger.
|
|
|
|
*/
|
|
|
|
keyval_props[KEYVAL_PROP_KEYVAL] =
|
|
|
|
g_param_spec_uint (I_("keyval"),
|
|
|
|
P_("Key value"),
|
|
|
|
P_("The key value for the trigger"),
|
|
|
|
0, G_MAXINT,
|
|
|
|
0,
|
|
|
|
G_PARAM_STATIC_STRINGS |
|
|
|
|
G_PARAM_CONSTRUCT_ONLY |
|
|
|
|
G_PARAM_READWRITE);
|
|
|
|
|
|
|
|
/**
|
|
|
|
* GtkKeyvalTrigger:modifiers:
|
|
|
|
*
|
|
|
|
* The key modifiers for the trigger.
|
|
|
|
*/
|
|
|
|
keyval_props[KEYVAL_PROP_MODIFIERS] =
|
|
|
|
g_param_spec_flags (I_("modifiers"),
|
|
|
|
P_("Modifiers"),
|
|
|
|
P_("The key modifiers for the trigger"),
|
|
|
|
GDK_TYPE_MODIFIER_TYPE,
|
|
|
|
0,
|
|
|
|
G_PARAM_STATIC_STRINGS |
|
|
|
|
G_PARAM_CONSTRUCT_ONLY |
|
|
|
|
G_PARAM_READWRITE);
|
|
|
|
|
|
|
|
g_object_class_install_properties (gobject_class, KEYVAL_N_PROPS, keyval_props);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
gtk_keyval_trigger_init (GtkKeyvalTrigger *self)
|
|
|
|
{
|
|
|
|
}
|
2020-03-15 13:49:50 +00:00
|
|
|
|
|
|
|
/**
|
2018-08-05 02:10:11 +00:00
|
|
|
* gtk_keyval_trigger_new:
|
2020-03-15 13:49:50 +00:00
|
|
|
* @keyval: The keyval to trigger for
|
|
|
|
* @modifiers: the modifiers that need to be present
|
|
|
|
*
|
|
|
|
* Creates a #GtkShortcutTrigger that will trigger whenever
|
|
|
|
* the key with the given @keyval and @modifiers is pressed.
|
|
|
|
*
|
|
|
|
* Returns: A new #GtkShortcutTrigger
|
|
|
|
*/
|
|
|
|
GtkShortcutTrigger *
|
|
|
|
gtk_keyval_trigger_new (guint keyval,
|
|
|
|
GdkModifierType modifiers)
|
|
|
|
{
|
2020-03-19 15:57:02 +00:00
|
|
|
return g_object_new (GTK_TYPE_KEYVAL_TRIGGER,
|
|
|
|
"keyval", keyval,
|
|
|
|
"modifiers", modifiers,
|
|
|
|
NULL);
|
2020-03-15 13:49:50 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* gtk_keyval_trigger_get_modifiers:
|
|
|
|
* @self: a keyval #GtkShortcutTrigger
|
|
|
|
*
|
|
|
|
* Gets the modifiers that must be present to succeed
|
|
|
|
* triggering @self.
|
|
|
|
*
|
|
|
|
* Returns: the modifiers
|
|
|
|
**/
|
|
|
|
GdkModifierType
|
2020-03-19 15:57:02 +00:00
|
|
|
gtk_keyval_trigger_get_modifiers (GtkKeyvalTrigger *self)
|
2020-03-15 13:49:50 +00:00
|
|
|
{
|
2020-03-19 15:57:02 +00:00
|
|
|
g_return_val_if_fail (GTK_IS_KEYVAL_TRIGGER (self), 0);
|
2020-03-15 13:49:50 +00:00
|
|
|
|
2020-03-19 15:57:02 +00:00
|
|
|
return self->modifiers;
|
2020-03-15 13:49:50 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* gtk_keyval_trigger_get_keyval:
|
|
|
|
* @self: a keyval #GtkShortcutTrigger
|
|
|
|
*
|
|
|
|
* Gets the keyval that must be pressed to succeed
|
|
|
|
* triggering @self.
|
|
|
|
*
|
|
|
|
* Returns: the keyval
|
|
|
|
**/
|
|
|
|
guint
|
2020-03-19 15:57:02 +00:00
|
|
|
gtk_keyval_trigger_get_keyval (GtkKeyvalTrigger *self)
|
2020-03-15 13:49:50 +00:00
|
|
|
{
|
2020-03-19 15:57:02 +00:00
|
|
|
g_return_val_if_fail (GTK_IS_KEYVAL_TRIGGER (self), 0);
|
2020-03-15 13:49:50 +00:00
|
|
|
|
2020-03-19 15:57:02 +00:00
|
|
|
return self->keyval;
|
2020-03-15 13:49:50 +00:00
|
|
|
}
|
2018-08-05 02:10:11 +00:00
|
|
|
|
2018-08-16 01:59:24 +00:00
|
|
|
/*** GTK_MNEMONIC_TRIGGER ***/
|
|
|
|
|
|
|
|
struct _GtkMnemonicTrigger
|
|
|
|
{
|
2020-03-19 15:57:02 +00:00
|
|
|
GtkShortcutTrigger parent_instance;
|
2018-08-16 01:59:24 +00:00
|
|
|
|
|
|
|
guint keyval;
|
|
|
|
};
|
|
|
|
|
2020-03-19 15:57:02 +00:00
|
|
|
struct _GtkMnemonicTriggerClass
|
2018-08-16 01:59:24 +00:00
|
|
|
{
|
2020-03-19 15:57:02 +00:00
|
|
|
GtkShortcutTriggerClass parent_class;
|
|
|
|
};
|
|
|
|
|
|
|
|
G_DEFINE_TYPE (GtkMnemonicTrigger, gtk_mnemonic_trigger, GTK_TYPE_SHORTCUT_TRIGGER)
|
|
|
|
|
|
|
|
enum
|
|
|
|
{
|
|
|
|
MNEMONIC_PROP_KEYVAL = 1,
|
|
|
|
MNEMONIC_N_PROPS
|
|
|
|
};
|
|
|
|
|
|
|
|
static GParamSpec *mnemonic_props[MNEMONIC_N_PROPS];
|
2018-08-16 01:59:24 +00:00
|
|
|
|
2020-04-05 18:40:55 +00:00
|
|
|
static GdkKeyMatch
|
2018-08-16 01:59:24 +00:00
|
|
|
gtk_mnemonic_trigger_trigger (GtkShortcutTrigger *trigger,
|
|
|
|
GdkEvent *event,
|
|
|
|
gboolean enable_mnemonics)
|
|
|
|
{
|
2020-03-19 15:57:02 +00:00
|
|
|
GtkMnemonicTrigger *self = GTK_MNEMONIC_TRIGGER (trigger);
|
2018-08-16 01:59:24 +00:00
|
|
|
guint keyval;
|
|
|
|
|
|
|
|
if (!enable_mnemonics)
|
2020-04-05 18:40:55 +00:00
|
|
|
return GDK_KEY_MATCH_NONE;
|
2018-08-16 01:59:24 +00:00
|
|
|
|
|
|
|
if (gdk_event_get_event_type (event) != GDK_KEY_PRESS)
|
2020-04-05 18:40:55 +00:00
|
|
|
return GDK_KEY_MATCH_NONE;
|
2018-08-16 01:59:24 +00:00
|
|
|
|
|
|
|
/* XXX: This needs to deal with groups */
|
|
|
|
keyval = gdk_key_event_get_keyval (event);
|
|
|
|
|
|
|
|
if (keyval == GDK_KEY_ISO_Left_Tab)
|
|
|
|
keyval = GDK_KEY_Tab;
|
|
|
|
else
|
|
|
|
keyval = gdk_keyval_to_lower (keyval);
|
|
|
|
|
2020-03-22 13:16:57 +00:00
|
|
|
if (keyval != self->keyval)
|
2020-04-05 18:40:55 +00:00
|
|
|
return GDK_KEY_MATCH_NONE;
|
2020-03-22 13:16:57 +00:00
|
|
|
|
2020-04-05 18:40:55 +00:00
|
|
|
return GDK_KEY_MATCH_EXACT;
|
2018-08-16 01:59:24 +00:00
|
|
|
}
|
|
|
|
|
2018-08-20 07:18:59 +00:00
|
|
|
static guint
|
|
|
|
gtk_mnemonic_trigger_hash (GtkShortcutTrigger *trigger)
|
|
|
|
{
|
2020-03-19 15:57:02 +00:00
|
|
|
GtkMnemonicTrigger *self = GTK_MNEMONIC_TRIGGER (trigger);
|
2018-08-20 07:18:59 +00:00
|
|
|
|
|
|
|
return (self->keyval << 8)
|
2020-03-19 15:57:02 +00:00
|
|
|
| GTK_SHORTCUT_TRIGGER_HASH_MNEMONIC;
|
2018-08-20 07:18:59 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
gtk_mnemonic_trigger_compare (GtkShortcutTrigger *trigger1,
|
|
|
|
GtkShortcutTrigger *trigger2)
|
|
|
|
{
|
2020-03-19 15:57:02 +00:00
|
|
|
GtkMnemonicTrigger *self1 = GTK_MNEMONIC_TRIGGER (trigger1);
|
|
|
|
GtkMnemonicTrigger *self2 = GTK_MNEMONIC_TRIGGER (trigger2);
|
2018-08-20 07:18:59 +00:00
|
|
|
|
|
|
|
return self1->keyval - self2->keyval;
|
|
|
|
}
|
|
|
|
|
2018-08-16 01:59:24 +00:00
|
|
|
static void
|
|
|
|
gtk_mnemonic_trigger_print (GtkShortcutTrigger *trigger,
|
|
|
|
GString *string)
|
|
|
|
{
|
2020-03-19 15:57:02 +00:00
|
|
|
GtkMnemonicTrigger *self = GTK_MNEMONIC_TRIGGER (trigger);
|
2018-08-16 01:59:24 +00:00
|
|
|
const char *keyval_str;
|
|
|
|
|
|
|
|
keyval_str = gdk_keyval_name (self->keyval);
|
|
|
|
if (keyval_str == NULL)
|
|
|
|
keyval_str = "???";
|
|
|
|
|
2020-03-16 02:10:39 +00:00
|
|
|
g_string_append (string, "<Mnemonic>");
|
2018-08-16 01:59:24 +00:00
|
|
|
g_string_append (string, keyval_str);
|
|
|
|
}
|
|
|
|
|
|
|
|
static gboolean
|
|
|
|
gtk_mnemonic_trigger_print_label (GtkShortcutTrigger *trigger,
|
|
|
|
GdkDisplay *display,
|
|
|
|
GString *string)
|
|
|
|
{
|
2020-03-19 15:57:02 +00:00
|
|
|
GtkMnemonicTrigger *self = GTK_MNEMONIC_TRIGGER (trigger);
|
2018-08-16 01:59:24 +00:00
|
|
|
const char *keyval_str;
|
|
|
|
|
|
|
|
keyval_str = gdk_keyval_name (self->keyval);
|
|
|
|
if (keyval_str == NULL)
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
g_string_append (string, keyval_str);
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
2020-03-19 15:57:02 +00:00
|
|
|
static void
|
|
|
|
gtk_mnemonic_trigger_set_property (GObject *gobject,
|
|
|
|
guint prop_id,
|
|
|
|
const GValue *value,
|
|
|
|
GParamSpec *pspec)
|
|
|
|
{
|
|
|
|
GtkMnemonicTrigger *self = GTK_MNEMONIC_TRIGGER (gobject);
|
|
|
|
|
|
|
|
switch (prop_id)
|
|
|
|
{
|
|
|
|
case MNEMONIC_PROP_KEYVAL:
|
|
|
|
{
|
|
|
|
guint keyval = g_value_get_uint (value);
|
|
|
|
|
|
|
|
/* We store keyvals as lower key */
|
|
|
|
if (keyval == GDK_KEY_ISO_Left_Tab)
|
|
|
|
self->keyval = GDK_KEY_Tab;
|
|
|
|
else
|
|
|
|
self->keyval = gdk_keyval_to_lower (keyval);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
gtk_mnemonic_trigger_get_property (GObject *gobject,
|
|
|
|
guint prop_id,
|
|
|
|
GValue *value,
|
|
|
|
GParamSpec *pspec)
|
|
|
|
{
|
|
|
|
GtkMnemonicTrigger *self = GTK_MNEMONIC_TRIGGER (gobject);
|
|
|
|
|
|
|
|
switch (prop_id)
|
|
|
|
{
|
|
|
|
case MNEMONIC_PROP_KEYVAL:
|
|
|
|
g_value_set_uint (value, self->keyval);
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
gtk_mnemonic_trigger_class_init (GtkMnemonicTriggerClass *klass)
|
|
|
|
{
|
|
|
|
GtkShortcutTriggerClass *trigger_class = GTK_SHORTCUT_TRIGGER_CLASS (klass);
|
|
|
|
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
|
|
|
|
|
|
|
|
gobject_class->set_property = gtk_mnemonic_trigger_set_property;
|
|
|
|
gobject_class->get_property = gtk_mnemonic_trigger_get_property;
|
|
|
|
|
|
|
|
trigger_class->trigger = gtk_mnemonic_trigger_trigger;
|
|
|
|
trigger_class->hash = gtk_mnemonic_trigger_hash;
|
|
|
|
trigger_class->compare = gtk_mnemonic_trigger_compare;
|
|
|
|
trigger_class->print = gtk_mnemonic_trigger_print;
|
|
|
|
trigger_class->print_label = gtk_mnemonic_trigger_print_label;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* GtkMnemonicTrigger:keyval:
|
|
|
|
*
|
|
|
|
* The key value for the trigger.
|
|
|
|
*/
|
|
|
|
mnemonic_props[KEYVAL_PROP_KEYVAL] =
|
|
|
|
g_param_spec_uint (I_("keyval"),
|
|
|
|
P_("Key value"),
|
|
|
|
P_("The key value for the trigger"),
|
|
|
|
0, G_MAXINT,
|
|
|
|
0,
|
|
|
|
G_PARAM_STATIC_STRINGS |
|
|
|
|
G_PARAM_CONSTRUCT_ONLY |
|
|
|
|
G_PARAM_READWRITE);
|
|
|
|
|
|
|
|
g_object_class_install_properties (gobject_class, MNEMONIC_N_PROPS, mnemonic_props);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
gtk_mnemonic_trigger_init (GtkMnemonicTrigger *self)
|
|
|
|
{
|
|
|
|
}
|
2018-08-16 01:59:24 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* gtk_mnemonic_trigger_new:
|
|
|
|
* @keyval: The keyval to trigger for
|
|
|
|
*
|
|
|
|
* Creates a #GtkShortcutTrigger that will trigger whenever the key with
|
|
|
|
* the given @keyval is pressed and mnemonics have been activated.
|
|
|
|
*
|
|
|
|
* Mnemonics are activated by calling code when a key event with the right
|
|
|
|
* modifiers is detected.
|
|
|
|
*
|
2020-03-19 15:57:02 +00:00
|
|
|
* Returns: (transfer full) (type GtkMnemonicTrigger): A new #GtkShortcutTrigger
|
2018-08-16 01:59:24 +00:00
|
|
|
*/
|
|
|
|
GtkShortcutTrigger *
|
|
|
|
gtk_mnemonic_trigger_new (guint keyval)
|
|
|
|
{
|
2020-03-19 15:57:02 +00:00
|
|
|
return g_object_new (GTK_TYPE_MNEMONIC_TRIGGER,
|
|
|
|
"keyval", keyval,
|
|
|
|
NULL);
|
2018-08-16 01:59:24 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* gtk_mnemonic_trigger_get_keyval:
|
2020-03-19 15:57:02 +00:00
|
|
|
* @self: a mnemonic #GtkShortcutTrigger
|
2018-08-16 01:59:24 +00:00
|
|
|
*
|
|
|
|
* Gets the keyval that must be pressed to succeed triggering @self.
|
|
|
|
*
|
|
|
|
* Returns: the keyval
|
|
|
|
**/
|
|
|
|
guint
|
2020-03-19 15:57:02 +00:00
|
|
|
gtk_mnemonic_trigger_get_keyval (GtkMnemonicTrigger *self)
|
2018-08-16 01:59:24 +00:00
|
|
|
{
|
2020-03-19 15:57:02 +00:00
|
|
|
g_return_val_if_fail (GTK_IS_MNEMONIC_TRIGGER (self), 0);
|
2018-08-16 01:59:24 +00:00
|
|
|
|
|
|
|
return self->keyval;
|
|
|
|
}
|
|
|
|
|
2018-08-05 02:10:11 +00:00
|
|
|
/*** GTK_ALTERNATIVE_TRIGGER ***/
|
|
|
|
|
|
|
|
struct _GtkAlternativeTrigger
|
|
|
|
{
|
2020-03-19 15:57:02 +00:00
|
|
|
GtkShortcutTrigger parent_instance;
|
2018-08-05 02:10:11 +00:00
|
|
|
|
|
|
|
GtkShortcutTrigger *first;
|
|
|
|
GtkShortcutTrigger *second;
|
|
|
|
};
|
|
|
|
|
2020-03-19 15:57:02 +00:00
|
|
|
struct _GtkAlternativeTriggerClass
|
|
|
|
{
|
|
|
|
GtkShortcutTriggerClass parent_class;
|
|
|
|
};
|
|
|
|
|
|
|
|
G_DEFINE_TYPE (GtkAlternativeTrigger, gtk_alternative_trigger, GTK_TYPE_SHORTCUT_TRIGGER)
|
|
|
|
|
|
|
|
enum
|
|
|
|
{
|
|
|
|
ALTERNATIVE_PROP_FIRST = 1,
|
|
|
|
ALTERNATIVE_PROP_SECOND,
|
|
|
|
ALTERNATIVE_N_PROPS
|
|
|
|
};
|
|
|
|
|
|
|
|
static GParamSpec *alternative_props[ALTERNATIVE_N_PROPS];
|
|
|
|
|
2018-08-05 02:10:11 +00:00
|
|
|
static void
|
2020-03-19 15:57:02 +00:00
|
|
|
gtk_alternative_trigger_dispose (GObject *gobject)
|
2018-08-05 02:10:11 +00:00
|
|
|
{
|
2020-03-19 15:57:02 +00:00
|
|
|
GtkAlternativeTrigger *self = GTK_ALTERNATIVE_TRIGGER (gobject);
|
|
|
|
|
|
|
|
g_clear_object (&self->first);
|
|
|
|
g_clear_object (&self->second);
|
2018-08-05 02:10:11 +00:00
|
|
|
|
2020-03-19 15:57:02 +00:00
|
|
|
G_OBJECT_CLASS (gtk_alternative_trigger_parent_class)->dispose (gobject);
|
2018-08-05 02:10:11 +00:00
|
|
|
}
|
|
|
|
|
2020-04-05 18:40:55 +00:00
|
|
|
static GdkKeyMatch
|
2018-08-05 02:10:11 +00:00
|
|
|
gtk_alternative_trigger_trigger (GtkShortcutTrigger *trigger,
|
2018-08-16 01:59:24 +00:00
|
|
|
GdkEvent *event,
|
|
|
|
gboolean enable_mnemonics)
|
2018-08-05 02:10:11 +00:00
|
|
|
{
|
2020-03-19 15:57:02 +00:00
|
|
|
GtkAlternativeTrigger *self = GTK_ALTERNATIVE_TRIGGER (trigger);
|
2018-08-05 02:10:11 +00:00
|
|
|
|
2020-03-22 13:16:57 +00:00
|
|
|
return MAX (gtk_shortcut_trigger_trigger (self->first, event, enable_mnemonics),
|
|
|
|
gtk_shortcut_trigger_trigger (self->second, event, enable_mnemonics));
|
2018-08-05 02:10:11 +00:00
|
|
|
}
|
|
|
|
|
2018-08-20 07:18:59 +00:00
|
|
|
static guint
|
|
|
|
gtk_alternative_trigger_hash (GtkShortcutTrigger *trigger)
|
|
|
|
{
|
2020-03-19 15:57:02 +00:00
|
|
|
GtkAlternativeTrigger *self = GTK_ALTERNATIVE_TRIGGER (trigger);
|
2018-08-20 07:18:59 +00:00
|
|
|
guint result;
|
|
|
|
|
|
|
|
result = gtk_shortcut_trigger_hash (self->first);
|
|
|
|
result <<= 5;
|
|
|
|
|
|
|
|
result |= gtk_shortcut_trigger_hash (self->second);
|
|
|
|
result <<= 5;
|
|
|
|
|
2020-03-19 15:57:02 +00:00
|
|
|
return result | GTK_SHORTCUT_TRIGGER_HASH_ALTERNATIVE;
|
2018-08-20 07:18:59 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
gtk_alternative_trigger_compare (GtkShortcutTrigger *trigger1,
|
|
|
|
GtkShortcutTrigger *trigger2)
|
|
|
|
{
|
2020-03-19 15:57:02 +00:00
|
|
|
GtkAlternativeTrigger *self1 = GTK_ALTERNATIVE_TRIGGER (trigger1);
|
|
|
|
GtkAlternativeTrigger *self2 = GTK_ALTERNATIVE_TRIGGER (trigger2);
|
2018-08-20 07:18:59 +00:00
|
|
|
int cmp;
|
|
|
|
|
|
|
|
cmp = gtk_shortcut_trigger_compare (self1->first, self2->first);
|
|
|
|
if (cmp != 0)
|
|
|
|
return cmp;
|
|
|
|
|
|
|
|
return gtk_shortcut_trigger_compare (self1->second, self2->second);
|
|
|
|
}
|
|
|
|
|
2018-08-05 02:10:11 +00:00
|
|
|
static void
|
|
|
|
gtk_alternative_trigger_print (GtkShortcutTrigger *trigger,
|
|
|
|
GString *string)
|
|
|
|
{
|
2020-03-19 15:57:02 +00:00
|
|
|
GtkAlternativeTrigger *self = GTK_ALTERNATIVE_TRIGGER (trigger);
|
2018-08-05 02:10:11 +00:00
|
|
|
|
|
|
|
gtk_shortcut_trigger_print (self->first, string);
|
2020-03-26 16:58:55 +00:00
|
|
|
g_string_append (string, "|");
|
2018-08-05 02:10:11 +00:00
|
|
|
gtk_shortcut_trigger_print (self->second, string);
|
|
|
|
}
|
|
|
|
|
2018-08-13 03:45:12 +00:00
|
|
|
static gboolean
|
|
|
|
gtk_alternative_trigger_print_label (GtkShortcutTrigger *trigger,
|
|
|
|
GdkDisplay *display,
|
|
|
|
GString *string)
|
|
|
|
{
|
2020-03-19 15:57:02 +00:00
|
|
|
GtkAlternativeTrigger *self = GTK_ALTERNATIVE_TRIGGER (trigger);
|
2018-08-13 03:45:12 +00:00
|
|
|
|
|
|
|
if (gtk_shortcut_trigger_print_label (self->first, display, string))
|
|
|
|
{
|
|
|
|
g_string_append (string, ", ");
|
|
|
|
if (!gtk_shortcut_trigger_print_label (self->second, display, string))
|
|
|
|
g_string_truncate (string, string->len - 2);
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
return gtk_shortcut_trigger_print_label (self->second, display, string);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-03-19 15:57:02 +00:00
|
|
|
static void
|
|
|
|
gtk_alternative_trigger_set_property (GObject *gobject,
|
|
|
|
guint prop_id,
|
|
|
|
const GValue *value,
|
|
|
|
GParamSpec *pspec)
|
|
|
|
{
|
|
|
|
GtkAlternativeTrigger *self = GTK_ALTERNATIVE_TRIGGER (gobject);
|
|
|
|
|
|
|
|
switch (prop_id)
|
|
|
|
{
|
|
|
|
case ALTERNATIVE_PROP_FIRST:
|
|
|
|
self->first = g_value_dup_object (value);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case ALTERNATIVE_PROP_SECOND:
|
|
|
|
self->second = g_value_dup_object (value);
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
gtk_alternative_trigger_get_property (GObject *gobject,
|
|
|
|
guint prop_id,
|
|
|
|
GValue *value,
|
|
|
|
GParamSpec *pspec)
|
|
|
|
{
|
|
|
|
GtkAlternativeTrigger *self = GTK_ALTERNATIVE_TRIGGER (gobject);
|
|
|
|
|
|
|
|
switch (prop_id)
|
|
|
|
{
|
|
|
|
case ALTERNATIVE_PROP_FIRST:
|
|
|
|
g_value_set_object (value, self->first);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case ALTERNATIVE_PROP_SECOND:
|
|
|
|
g_value_set_object (value, self->second);
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
gtk_alternative_trigger_constructed (GObject *gobject)
|
|
|
|
{
|
|
|
|
GtkAlternativeTrigger *self = GTK_ALTERNATIVE_TRIGGER (gobject);
|
|
|
|
|
|
|
|
if (self->first == NULL || self->second == NULL)
|
|
|
|
{
|
|
|
|
g_critical ("Invalid alternative trigger, disabling");
|
|
|
|
self->first = g_object_ref (gtk_never_trigger_get ());
|
|
|
|
self->second = g_object_ref (gtk_never_trigger_get ());
|
|
|
|
}
|
|
|
|
|
|
|
|
G_OBJECT_CLASS (gtk_alternative_trigger_parent_class)->constructed (gobject);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
gtk_alternative_trigger_class_init (GtkAlternativeTriggerClass *klass)
|
|
|
|
{
|
|
|
|
GtkShortcutTriggerClass *trigger_class = GTK_SHORTCUT_TRIGGER_CLASS (klass);
|
|
|
|
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
|
|
|
|
|
|
|
|
gobject_class->constructed = gtk_alternative_trigger_constructed;
|
|
|
|
gobject_class->set_property = gtk_alternative_trigger_set_property;
|
|
|
|
gobject_class->get_property = gtk_alternative_trigger_get_property;
|
|
|
|
gobject_class->dispose = gtk_alternative_trigger_dispose;
|
|
|
|
|
|
|
|
trigger_class->trigger = gtk_alternative_trigger_trigger;
|
|
|
|
trigger_class->hash = gtk_alternative_trigger_hash;
|
|
|
|
trigger_class->compare = gtk_alternative_trigger_compare;
|
|
|
|
trigger_class->print = gtk_alternative_trigger_print;
|
|
|
|
trigger_class->print_label = gtk_alternative_trigger_print_label;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* GtkAlternativeTrigger:first:
|
|
|
|
*
|
|
|
|
* The first #GtkShortcutTrigger to check.
|
|
|
|
*/
|
|
|
|
alternative_props[ALTERNATIVE_PROP_FIRST] =
|
|
|
|
g_param_spec_object (I_("first"),
|
|
|
|
P_("First"),
|
|
|
|
P_("The first trigger to check"),
|
|
|
|
GTK_TYPE_SHORTCUT_TRIGGER,
|
|
|
|
G_PARAM_STATIC_STRINGS |
|
|
|
|
G_PARAM_CONSTRUCT_ONLY |
|
|
|
|
G_PARAM_READWRITE);
|
|
|
|
/**
|
|
|
|
* GtkAlternativeTrigger:second:
|
|
|
|
*
|
|
|
|
* The second #GtkShortcutTrigger to check.
|
|
|
|
*/
|
|
|
|
alternative_props[ALTERNATIVE_PROP_SECOND] =
|
|
|
|
g_param_spec_object (I_("second"),
|
|
|
|
P_("Second"),
|
|
|
|
P_("The second trigger to check"),
|
|
|
|
GTK_TYPE_SHORTCUT_TRIGGER,
|
|
|
|
G_PARAM_STATIC_STRINGS |
|
|
|
|
G_PARAM_CONSTRUCT_ONLY |
|
|
|
|
G_PARAM_READWRITE);
|
|
|
|
|
|
|
|
g_object_class_install_properties (gobject_class, ALTERNATIVE_N_PROPS, alternative_props);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
gtk_alternative_trigger_init (GtkAlternativeTrigger *self)
|
|
|
|
{
|
|
|
|
}
|
2018-08-05 02:10:11 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* gtk_alternative_trigger_new:
|
|
|
|
* @first: (transfer full): The first trigger that may trigger
|
|
|
|
* @second: (transfer full): The second trigger that may trigger
|
|
|
|
*
|
|
|
|
* Creates a #GtkShortcutTrigger that will trigger whenever
|
|
|
|
* either of the two given triggers gets triggered.
|
|
|
|
*
|
|
|
|
* Note that nesting is allowed, so if you want more than two
|
|
|
|
* alternative, create a new alternative trigger for each option.
|
|
|
|
*
|
|
|
|
* Returns: a new #GtkShortcutTrigger
|
|
|
|
*/
|
|
|
|
GtkShortcutTrigger *
|
|
|
|
gtk_alternative_trigger_new (GtkShortcutTrigger *first,
|
|
|
|
GtkShortcutTrigger *second)
|
|
|
|
{
|
2020-03-19 15:57:02 +00:00
|
|
|
GtkShortcutTrigger *res;
|
2018-08-05 02:10:11 +00:00
|
|
|
|
|
|
|
g_return_val_if_fail (GTK_IS_SHORTCUT_TRIGGER (first), NULL);
|
|
|
|
g_return_val_if_fail (GTK_IS_SHORTCUT_TRIGGER (second), NULL);
|
|
|
|
|
2020-03-19 15:57:02 +00:00
|
|
|
res = g_object_new (GTK_TYPE_ALTERNATIVE_TRIGGER,
|
|
|
|
"first", first,
|
|
|
|
"second", second,
|
|
|
|
NULL);
|
2018-08-05 02:10:11 +00:00
|
|
|
|
2020-03-19 15:57:02 +00:00
|
|
|
g_object_unref (first);
|
|
|
|
g_object_unref (second);
|
2018-08-05 02:10:11 +00:00
|
|
|
|
2020-03-19 15:57:02 +00:00
|
|
|
return res;
|
2018-08-05 02:10:11 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* gtk_alternative_trigger_get_first:
|
|
|
|
* @self: an alternative #GtkShortcutTrigger
|
|
|
|
*
|
|
|
|
* Gets the first of the two alternative triggers that may
|
|
|
|
* trigger @self. gtk_alternative_trigger_get_second() will
|
|
|
|
* return the other one.
|
|
|
|
*
|
|
|
|
* Returns: (transfer none): the first alternative trigger
|
|
|
|
**/
|
|
|
|
GtkShortcutTrigger *
|
2020-03-19 15:57:02 +00:00
|
|
|
gtk_alternative_trigger_get_first (GtkAlternativeTrigger *self)
|
2018-08-05 02:10:11 +00:00
|
|
|
{
|
2020-03-19 15:57:02 +00:00
|
|
|
g_return_val_if_fail (GTK_IS_ALTERNATIVE_TRIGGER (self), NULL);
|
2018-08-05 02:10:11 +00:00
|
|
|
|
2020-03-19 15:57:02 +00:00
|
|
|
return self->first;
|
2018-08-05 02:10:11 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* gtk_alternative_trigger_get_second:
|
|
|
|
* @self: an alternative #GtkShortcutTrigger
|
|
|
|
*
|
|
|
|
* Gets the second of the two alternative triggers that may
|
|
|
|
* trigger @self. gtk_alternative_trigger_get_first() will
|
|
|
|
* return the other one.
|
|
|
|
*
|
|
|
|
* Returns: (transfer none): the second alternative trigger
|
|
|
|
**/
|
|
|
|
GtkShortcutTrigger *
|
2020-03-19 15:57:02 +00:00
|
|
|
gtk_alternative_trigger_get_second (GtkAlternativeTrigger *self)
|
2018-08-05 02:10:11 +00:00
|
|
|
{
|
2020-03-19 15:57:02 +00:00
|
|
|
g_return_val_if_fail (GTK_IS_ALTERNATIVE_TRIGGER (self), NULL);
|
2018-08-05 02:10:11 +00:00
|
|
|
|
2020-03-19 15:57:02 +00:00
|
|
|
return self->second;
|
2018-08-05 02:10:11 +00:00
|
|
|
}
|