gtk: Add GtkEventControllerKey
This event controller is meant to replace usage from key-press/release-event handlers all through. Optionally it can be set a GtkIMContext, so interaction is carried by the controller.
This commit is contained in:
		@ -192,6 +192,7 @@ gtk_public_h_sources = 		\
 | 
			
		||||
	gtkenums.h		\
 | 
			
		||||
	gtkeventbox.h		\
 | 
			
		||||
	gtkeventcontroller.h	\
 | 
			
		||||
	gtkeventcontrollerkey.h	\
 | 
			
		||||
	gtkeventcontrollermotion.h	\
 | 
			
		||||
	gtkeventcontrollerscroll.h	\
 | 
			
		||||
	gtkexpander.h		\
 | 
			
		||||
@ -759,6 +760,7 @@ gtk_base_c_sources = 		\
 | 
			
		||||
	gtkentrycompletion.c	\
 | 
			
		||||
	gtkeventbox.c		\
 | 
			
		||||
	gtkeventcontroller.c	\
 | 
			
		||||
	gtkeventcontrollerkey.c	\
 | 
			
		||||
	gtkeventcontrollermotion.c	\
 | 
			
		||||
	gtkeventcontrollerscroll.c	\
 | 
			
		||||
	gtkexpander.c		\
 | 
			
		||||
 | 
			
		||||
@ -94,6 +94,7 @@
 | 
			
		||||
#include <gtk/gtkenums.h>
 | 
			
		||||
#include <gtk/gtkeventbox.h>
 | 
			
		||||
#include <gtk/gtkeventcontroller.h>
 | 
			
		||||
#include <gtk/gtkeventcontrollerkey.h>
 | 
			
		||||
#include <gtk/gtkeventcontrollermotion.h>
 | 
			
		||||
#include <gtk/gtkeventcontrollerscroll.h>
 | 
			
		||||
#include <gtk/gtkexpander.h>
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										217
									
								
								gtk/gtkeventcontrollerkey.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										217
									
								
								gtk/gtkeventcontrollerkey.c
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,217 @@
 | 
			
		||||
/* GTK - The GIMP Toolkit
 | 
			
		||||
 * Copyright (C) 2017, Red Hat, Inc.
 | 
			
		||||
 *
 | 
			
		||||
 * 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 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/>.
 | 
			
		||||
 *
 | 
			
		||||
 * Author(s): Carlos Garnacho <carlosg@gnome.org>
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include "config.h"
 | 
			
		||||
 | 
			
		||||
#include "gtkintl.h"
 | 
			
		||||
#include "gtkprivate.h"
 | 
			
		||||
#include "gtkwidget.h"
 | 
			
		||||
#include "gtkeventcontrollerprivate.h"
 | 
			
		||||
#include "gtkeventcontrollerkey.h"
 | 
			
		||||
#include "gtkbindings.h"
 | 
			
		||||
 | 
			
		||||
#include <gdk/gdk.h>
 | 
			
		||||
 | 
			
		||||
struct _GtkEventControllerKey
 | 
			
		||||
{
 | 
			
		||||
  GtkEventController parent_instance;
 | 
			
		||||
  GtkIMContext *im_context;
 | 
			
		||||
  GHashTable *pressed_keys;
 | 
			
		||||
 | 
			
		||||
  const GdkEvent *current_event;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct _GtkEventControllerKeyClass
 | 
			
		||||
{
 | 
			
		||||
  GtkEventControllerClass parent_class;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
enum {
 | 
			
		||||
  KEY_PRESSED,
 | 
			
		||||
  KEY_RELEASED,
 | 
			
		||||
  MODIFIERS,
 | 
			
		||||
  IM_UPDATE,
 | 
			
		||||
  N_SIGNALS
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static guint signals[N_SIGNALS] = { 0 };
 | 
			
		||||
 | 
			
		||||
G_DEFINE_TYPE (GtkEventControllerKey, gtk_event_controller_key,
 | 
			
		||||
               GTK_TYPE_EVENT_CONTROLLER)
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
gtk_event_controller_finalize (GObject *object)
 | 
			
		||||
{
 | 
			
		||||
  GtkEventControllerKey *key = GTK_EVENT_CONTROLLER_KEY (object);
 | 
			
		||||
 | 
			
		||||
  g_hash_table_destroy (key->pressed_keys);
 | 
			
		||||
  g_clear_object (&key->im_context);
 | 
			
		||||
 | 
			
		||||
  G_OBJECT_CLASS (gtk_event_controller_key_parent_class)->finalize (object);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static gboolean
 | 
			
		||||
gtk_event_controller_key_handle_event (GtkEventController *controller,
 | 
			
		||||
                                       const GdkEvent     *event)
 | 
			
		||||
{
 | 
			
		||||
  GtkEventControllerKey *key = GTK_EVENT_CONTROLLER_KEY (controller);
 | 
			
		||||
  GdkEventType event_type = gdk_event_get_event_type (event);
 | 
			
		||||
  gboolean handled;
 | 
			
		||||
  GdkModifierType state;
 | 
			
		||||
  guint16 keycode;
 | 
			
		||||
  guint keyval;
 | 
			
		||||
 | 
			
		||||
  if (event_type != GDK_KEY_PRESS && event_type != GDK_KEY_RELEASE)
 | 
			
		||||
    return FALSE;
 | 
			
		||||
 | 
			
		||||
  if (key->im_context &&
 | 
			
		||||
      gtk_im_context_filter_keypress (key->im_context, (GdkEventKey *) event))
 | 
			
		||||
    {
 | 
			
		||||
      g_signal_emit (controller, signals[IM_UPDATE], 0);
 | 
			
		||||
      return TRUE;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  if (!gdk_event_get_state (event, &state) || !event->key.is_modifier)
 | 
			
		||||
    return FALSE;
 | 
			
		||||
 | 
			
		||||
  key->current_event = event;
 | 
			
		||||
 | 
			
		||||
  if (event->key.is_modifier)
 | 
			
		||||
    {
 | 
			
		||||
      if (event_type == GDK_KEY_PRESS)
 | 
			
		||||
        g_signal_emit (controller, signals[MODIFIERS], 0, state, &handled);
 | 
			
		||||
      else
 | 
			
		||||
        handled = TRUE;
 | 
			
		||||
 | 
			
		||||
      if (handled == TRUE)
 | 
			
		||||
        {
 | 
			
		||||
          key->current_event = NULL;
 | 
			
		||||
          return TRUE;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  gdk_event_get_keycode (event, &keycode);
 | 
			
		||||
  gdk_event_get_keyval (event, &keyval);
 | 
			
		||||
 | 
			
		||||
  if (event_type == GDK_KEY_PRESS)
 | 
			
		||||
    {
 | 
			
		||||
      g_signal_emit (controller, signals[KEY_PRESSED], 0,
 | 
			
		||||
                     keyval, keycode, state, &handled);
 | 
			
		||||
      if (handled)
 | 
			
		||||
        g_hash_table_add (key->pressed_keys, GUINT_TO_POINTER (keyval));
 | 
			
		||||
    }
 | 
			
		||||
  else if (event_type == GDK_KEY_RELEASE)
 | 
			
		||||
    {
 | 
			
		||||
      g_signal_emit (controller, signals[KEY_RELEASED], 0,
 | 
			
		||||
                     keyval, keycode, state);
 | 
			
		||||
 | 
			
		||||
      handled = g_hash_table_lookup (key->pressed_keys, GUINT_TO_POINTER (keyval)) != NULL;
 | 
			
		||||
      g_hash_table_remove (key->pressed_keys, GUINT_TO_POINTER (keyval));
 | 
			
		||||
    }
 | 
			
		||||
  else
 | 
			
		||||
    handled = FALSE;
 | 
			
		||||
 | 
			
		||||
  key->current_event = NULL;
 | 
			
		||||
 | 
			
		||||
  return handled;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
gtk_event_controller_key_class_init (GtkEventControllerKeyClass *klass)
 | 
			
		||||
{
 | 
			
		||||
  GtkEventControllerClass *controller_class = GTK_EVENT_CONTROLLER_CLASS (klass);
 | 
			
		||||
  GObjectClass *object_class = G_OBJECT_CLASS (klass);
 | 
			
		||||
 | 
			
		||||
  object_class->finalize = gtk_event_controller_finalize;
 | 
			
		||||
  controller_class->handle_event = gtk_event_controller_key_handle_event;
 | 
			
		||||
 | 
			
		||||
  signals[KEY_PRESSED] =
 | 
			
		||||
    g_signal_new (I_("key-pressed"),
 | 
			
		||||
                  GTK_TYPE_EVENT_CONTROLLER_KEY,
 | 
			
		||||
                  G_SIGNAL_RUN_LAST,
 | 
			
		||||
                  0, _gtk_boolean_handled_accumulator, NULL, NULL,
 | 
			
		||||
                  G_TYPE_BOOLEAN, 3, G_TYPE_UINT, G_TYPE_UINT, GDK_TYPE_MODIFIER_TYPE);
 | 
			
		||||
  signals[KEY_RELEASED] =
 | 
			
		||||
    g_signal_new (I_("key-released"),
 | 
			
		||||
                  GTK_TYPE_EVENT_CONTROLLER_KEY,
 | 
			
		||||
                  G_SIGNAL_RUN_LAST,
 | 
			
		||||
                  0, NULL, NULL, NULL,
 | 
			
		||||
                  G_TYPE_NONE, 3, G_TYPE_UINT, G_TYPE_UINT, GDK_TYPE_MODIFIER_TYPE);
 | 
			
		||||
  signals[MODIFIERS] =
 | 
			
		||||
    g_signal_new (I_("modifiers"),
 | 
			
		||||
                  GTK_TYPE_EVENT_CONTROLLER_KEY,
 | 
			
		||||
                  G_SIGNAL_RUN_LAST,
 | 
			
		||||
                  0, NULL, NULL,
 | 
			
		||||
                  g_cclosure_marshal_BOOLEAN__FLAGS,
 | 
			
		||||
                  G_TYPE_BOOLEAN, 1, GDK_TYPE_MODIFIER_TYPE);
 | 
			
		||||
  signals[IM_UPDATE] =
 | 
			
		||||
    g_signal_new (I_("im-update"),
 | 
			
		||||
                  GTK_TYPE_EVENT_CONTROLLER_KEY,
 | 
			
		||||
                  G_SIGNAL_RUN_LAST,
 | 
			
		||||
                  0, NULL, NULL,
 | 
			
		||||
                  g_cclosure_marshal_VOID__VOID,
 | 
			
		||||
                  G_TYPE_NONE, 0);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
gtk_event_controller_key_init (GtkEventControllerKey *controller)
 | 
			
		||||
{
 | 
			
		||||
  controller->pressed_keys = g_hash_table_new (NULL, NULL);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
GtkEventController *
 | 
			
		||||
gtk_event_controller_key_new (GtkWidget *widget)
 | 
			
		||||
{
 | 
			
		||||
  g_return_val_if_fail (GTK_IS_WIDGET (widget), NULL);
 | 
			
		||||
 | 
			
		||||
  return g_object_new (GTK_TYPE_EVENT_CONTROLLER_KEY,
 | 
			
		||||
                       "widget", widget,
 | 
			
		||||
                       NULL);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void
 | 
			
		||||
gtk_event_controller_key_set_im_context (GtkEventControllerKey *controller,
 | 
			
		||||
                                         GtkIMContext          *im_context)
 | 
			
		||||
{
 | 
			
		||||
  g_return_if_fail (GTK_IS_EVENT_CONTROLLER_KEY (controller));
 | 
			
		||||
  g_return_if_fail (!im_context || GTK_IS_IM_CONTEXT (im_context));
 | 
			
		||||
 | 
			
		||||
  if (controller->im_context)
 | 
			
		||||
    gtk_im_context_reset (controller->im_context);
 | 
			
		||||
 | 
			
		||||
  g_set_object (&controller->im_context, im_context);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * gtk_event_controller_key_get_im_context:
 | 
			
		||||
 * @controller: a #GtkEventControllerKey
 | 
			
		||||
 *
 | 
			
		||||
 * Gets the IM context of a key controller.
 | 
			
		||||
 *
 | 
			
		||||
 * Returns: (transfer none): the IM context
 | 
			
		||||
 *
 | 
			
		||||
 * Since: 3.94
 | 
			
		||||
 **/
 | 
			
		||||
GtkIMContext *
 | 
			
		||||
gtk_event_controller_key_get_im_context (GtkEventControllerKey *controller)
 | 
			
		||||
{
 | 
			
		||||
  g_return_val_if_fail (GTK_IS_EVENT_CONTROLLER_KEY (controller), NULL);
 | 
			
		||||
 | 
			
		||||
  return controller->im_context;
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										57
									
								
								gtk/gtkeventcontrollerkey.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										57
									
								
								gtk/gtkeventcontrollerkey.h
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,57 @@
 | 
			
		||||
/* GTK - The GIMP Toolkit
 | 
			
		||||
 * Copyright (C) 2017, Red Hat, Inc.
 | 
			
		||||
 *
 | 
			
		||||
 * 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 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/>.
 | 
			
		||||
 *
 | 
			
		||||
 * Author(s): Carlos Garnacho <carlosg@gnome.org>
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#ifndef __GTK_EVENT_CONTROLLER_KEY_H__
 | 
			
		||||
#define __GTK_EVENT_CONTROLLER_KEY_H__
 | 
			
		||||
 | 
			
		||||
#if !defined (__GTK_H_INSIDE__) && !defined (GTK_COMPILATION)
 | 
			
		||||
#error "Only <gtk/gtk.h> can be included directly."
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#include <gdk/gdk.h>
 | 
			
		||||
#include <gtk/gtkeventcontroller.h>
 | 
			
		||||
#include <gtk/gtkimcontext.h>
 | 
			
		||||
 | 
			
		||||
G_BEGIN_DECLS
 | 
			
		||||
 | 
			
		||||
#define GTK_TYPE_EVENT_CONTROLLER_KEY         (gtk_event_controller_key_get_type ())
 | 
			
		||||
#define GTK_EVENT_CONTROLLER_KEY(o)           (G_TYPE_CHECK_INSTANCE_CAST ((o), GTK_TYPE_EVENT_CONTROLLER_KEY, GtkEventControllerKey))
 | 
			
		||||
#define GTK_EVENT_CONTROLLER_KEY_CLASS(k)     (G_TYPE_CHECK_CLASS_CAST ((k), GTK_TYPE_EVENT_CONTROLLER_KEY, GtkEventControllerKeyClass))
 | 
			
		||||
#define GTK_IS_EVENT_CONTROLLER_KEY(o)        (G_TYPE_CHECK_INSTANCE_TYPE ((o), GTK_TYPE_EVENT_CONTROLLER_KEY))
 | 
			
		||||
#define GTK_IS_EVENT_CONTROLLER_KEY_CLASS(k)  (G_TYPE_CHECK_CLASS_TYPE ((k), GTK_TYPE_EVENT_CONTROLLER_KEY))
 | 
			
		||||
#define GTK_EVENT_CONTROLLER_KEY_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), GTK_TYPE_EVENT_CONTROLLER_KEY, GtkEventControllerKeyClass))
 | 
			
		||||
 | 
			
		||||
typedef struct _GtkEventControllerKey GtkEventControllerKey;
 | 
			
		||||
typedef struct _GtkEventControllerKeyClass GtkEventControllerKeyClass;
 | 
			
		||||
 | 
			
		||||
GDK_AVAILABLE_IN_3_24
 | 
			
		||||
GType               gtk_event_controller_key_get_type  (void) G_GNUC_CONST;
 | 
			
		||||
 | 
			
		||||
GDK_AVAILABLE_IN_3_24
 | 
			
		||||
GtkEventController *gtk_event_controller_key_new (GtkWidget *widget);
 | 
			
		||||
 | 
			
		||||
GDK_AVAILABLE_IN_3_24
 | 
			
		||||
void                gtk_event_controller_key_set_im_context (GtkEventControllerKey *controller,
 | 
			
		||||
                                                             GtkIMContext          *im_context);
 | 
			
		||||
GDK_AVAILABLE_IN_3_24
 | 
			
		||||
GtkIMContext *      gtk_event_controller_key_get_im_context (GtkEventControllerKey *controller);
 | 
			
		||||
 | 
			
		||||
G_END_DECLS
 | 
			
		||||
 | 
			
		||||
#endif /* __GTK_EVENT_CONTROLLER_KEY_H__ */
 | 
			
		||||
@ -142,6 +142,9 @@ gtk/gtkentry.c
 | 
			
		||||
gtk/gtkentrycompletion.c
 | 
			
		||||
gtk/gtkeventbox.c
 | 
			
		||||
gtk/gtkeventcontroller.c
 | 
			
		||||
gtk/gtkeventcontrollerkey.c
 | 
			
		||||
gtk/gtkeventcontrollermotion.c
 | 
			
		||||
gtk/gtkeventcontrollerscroll.c
 | 
			
		||||
gtk/gtkexpander.c
 | 
			
		||||
gtk/gtkfilechooserbutton.c
 | 
			
		||||
gtk/gtkfilechooser.c
 | 
			
		||||
 | 
			
		||||
		Reference in New Issue
	
	Block a user