[gnome-builder/wip/alexl/emacs-css-keys: 1/5] Add GbSourceViewMode



commit c497b5e65ca824b422d786543f642d7955fcd3f2
Author: Alexander Larsson <alexl redhat com>
Date:   Wed Feb 18 15:21:13 2015 +0100

    Add GbSourceViewMode
    
    This is an object representing some kind of modal keyboard state
    in the source view. It can be used to hang GtkBindingSet on the mode
    via CSS rules.
    
    Its kind of a hack which inherits from GtkWidget just to get at the
    GtkBindings code, but is not actually used as a widget.

 src/editor/gb-source-view-mode.c |  248 ++++++++++++++++++++++++++++++++++++++
 src/editor/gb-source-view-mode.h |   81 ++++++++++++
 src/gnome-builder.mk             |    2 +
 3 files changed, 331 insertions(+), 0 deletions(-)
---
diff --git a/src/editor/gb-source-view-mode.c b/src/editor/gb-source-view-mode.c
new file mode 100644
index 0000000..9d47adf
--- /dev/null
+++ b/src/editor/gb-source-view-mode.c
@@ -0,0 +1,248 @@
+/* gb-key-mode.c
+ *
+ * Copyright (C) 2015 Alexander Larsson <alexl redhat com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#define G_LOG_DOMAIN "keymode"
+
+#include <glib/gi18n.h>
+#include "gb-source-view-mode.h"
+
+struct _GbSourceViewModePrivate
+{
+  GtkWidget *view;
+  char *name;
+  GbSourceViewModeType type;
+};
+
+G_DEFINE_TYPE_WITH_PRIVATE (GbSourceViewMode, gb_source_view_mode, GTK_TYPE_WIDGET)
+
+static void
+gb_source_view_mode_finalize (GObject *object)
+{
+  GbSourceViewModePrivate *priv;
+
+  priv = GB_SOURCE_VIEW_MODE (object)->priv;
+
+  g_clear_object (&priv->view);
+  g_free (priv->name);
+
+  G_OBJECT_CLASS (gb_source_view_mode_parent_class)->finalize (object);
+}
+
+static void
+proxy_closure_marshal  (GClosure       *closure,
+                         GValue         *return_value,
+                         guint           n_param_values,
+                         const GValue   *param_values,
+                         gpointer        invocation_hint,
+                         gpointer        marshal_data)
+{
+  GbSourceViewMode *mode;
+  GbSourceViewModePrivate *priv;
+  GValue *param_copy;
+
+  mode = GB_SOURCE_VIEW_MODE (g_value_get_object (&param_values[0]));
+  priv = mode->priv;
+
+  param_copy = g_memdup (param_values, sizeof (GValue) * n_param_values);
+
+  param_copy[0].data[0].v_pointer = priv->view;
+  g_signal_emitv (param_copy,
+                  GPOINTER_TO_INT (closure->data),
+                  0,
+                  return_value);
+  g_free (param_copy);
+}
+
+static void
+proxy_all_action_signals (GType type)
+{
+  GClosure *proxy;
+  guint *signals;
+  guint n_signals, i;
+  GSignalQuery query;
+
+  signals = g_signal_list_ids (type, &n_signals);
+  for (i = 0; i < n_signals; i++)
+    {
+      g_signal_query (signals[i], &query);
+
+      if (query.signal_flags & G_SIGNAL_ACTION)
+        {
+          proxy = g_closure_new_simple (sizeof (GClosure), GINT_TO_POINTER (query.signal_id));
+          g_closure_set_meta_marshal (proxy, NULL, proxy_closure_marshal);
+          g_signal_newv (query.signal_name,
+                         GB_TYPE_SOURCE_VIEW_MODE,
+                         G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
+                         proxy,
+                         NULL, NULL, NULL,
+                         query.return_type,
+                         query.n_params,
+                         (GType *)query.param_types);
+        }
+    }
+}
+
+
+static void
+gb_source_view_mode_class_init (GbSourceViewModeClass *klass)
+{
+  GObjectClass *object_class = G_OBJECT_CLASS (klass);
+  GtkBindingSet *binding_set, *parent_binding_set;
+  GType type;
+
+  object_class->finalize = gb_source_view_mode_finalize;
+
+  /* Proxy all action signals from source view */
+  type = GB_TYPE_SOURCE_VIEW;
+  while (type != G_TYPE_INVALID && type != GTK_TYPE_WIDGET)
+    {
+      proxy_all_action_signals (type);
+      type = g_type_parent (type);
+    }
+
+  /* Add unbind all entries from parent classes (which is
+     really just the GtkWidget ones) so that we *only* add
+     stuff via modes. Any default ones are handled in the
+     normal fallback paths after mode elements are done. */
+  binding_set = gtk_binding_set_by_class (klass);
+
+  type = g_type_parent (GB_TYPE_SOURCE_VIEW_MODE);
+  while (type)
+    {
+      parent_binding_set = gtk_binding_set_find (g_type_name (type));
+      type = g_type_parent (type);
+
+      if (parent_binding_set)
+        {
+          GtkBindingEntry *entry = parent_binding_set->entries;
+
+          while (entry != NULL)
+            {
+              gtk_binding_entry_skip (binding_set, entry->keyval, entry->modifiers);
+              entry = entry->set_next;
+            }
+        }
+    }
+}
+
+static void
+gb_source_view_mode_init (GbSourceViewMode *mode)
+{
+  mode->priv = gb_source_view_mode_get_instance_private (mode);
+}
+
+void
+gb_source_view_mode_set_class (GbSourceViewMode *mode, const char *class)
+{
+  GtkStyleContext *context;
+
+  context = gtk_widget_get_style_context (GTK_WIDGET (mode));
+  gtk_style_context_add_class (context, class);
+}
+
+static gboolean
+is_modifier_key (GdkEventKey *event)
+{
+  static const guint modifier_keyvals[] = {
+    GDK_KEY_Shift_L, GDK_KEY_Shift_R, GDK_KEY_Shift_Lock,
+    GDK_KEY_Caps_Lock, GDK_KEY_ISO_Lock, GDK_KEY_Control_L,
+    GDK_KEY_Control_R, GDK_KEY_Meta_L, GDK_KEY_Meta_R,
+    GDK_KEY_Alt_L, GDK_KEY_Alt_R, GDK_KEY_Super_L, GDK_KEY_Super_R,
+    GDK_KEY_Hyper_L, GDK_KEY_Hyper_R, GDK_KEY_ISO_Level3_Shift,
+    GDK_KEY_ISO_Next_Group, GDK_KEY_ISO_Prev_Group,
+    GDK_KEY_ISO_First_Group, GDK_KEY_ISO_Last_Group,
+    GDK_KEY_Mode_switch, GDK_KEY_Num_Lock, GDK_KEY_Multi_key,
+    GDK_KEY_Scroll_Lock,
+    0
+  };
+  const guint *ac_val;
+
+  ac_val = modifier_keyvals;
+  while (*ac_val)
+    {
+      if (event->keyval == *ac_val++)
+        return TRUE;
+    }
+
+  return FALSE;
+}
+
+gboolean
+gb_source_view_mode_do_event (GbSourceViewMode *mode,
+                              GdkEventKey *event,
+                              gboolean *remove)
+{
+  GbSourceViewModePrivate *priv = mode->priv;
+  GtkStyleContext *context;
+  gboolean handled;
+
+  context = gtk_widget_get_style_context (GTK_WIDGET (mode));
+
+  gtk_style_context_save (context);
+
+  gtk_style_context_add_class (context, priv->name);
+
+  handled = gtk_bindings_activate_event (G_OBJECT (mode), event);
+
+  gtk_style_context_restore (context);
+
+  *remove = FALSE;
+  switch (priv->type)
+    {
+    default:
+    case GB_SOURCE_VIEW_MODE_TYPE_TRANSIENT:
+      if (handled)
+        {
+          *remove = TRUE;
+        }
+      else
+        {
+          if (!is_modifier_key (event))
+            {
+              gtk_widget_error_bell (priv->view);
+              handled = TRUE;
+              *remove = TRUE;
+            }
+        }
+      break;
+
+    case GB_SOURCE_VIEW_MODE_TYPE_PERMANENT:
+      break;
+
+    case GB_SOURCE_VIEW_MODE_TYPE_MODAL:
+      handled = TRUE;
+      break;
+    }
+
+  return handled;
+}
+
+GbSourceViewMode *
+gb_source_view_mode_new (GtkWidget *view,
+                         const char *name,
+                         GbSourceViewModeType type)
+{
+  GbSourceViewMode *mode;
+
+  mode = g_object_new (GB_TYPE_SOURCE_VIEW_MODE, NULL);
+  mode->priv->view = g_object_ref (view);
+  mode->priv->name = g_strdup (name);
+  mode->priv->type = type;
+
+  return g_object_ref_sink (mode);
+}
diff --git a/src/editor/gb-source-view-mode.h b/src/editor/gb-source-view-mode.h
new file mode 100644
index 0000000..3ab5d7c
--- /dev/null
+++ b/src/editor/gb-source-view-mode.h
@@ -0,0 +1,81 @@
+/* gb-key-mode.h
+ *
+ * Copyright (C) 2015 Alexander Larsson <alexl redhat com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef GB_SOURCE_VIEW_MODE_H
+#define GB_SOURCE_VIEW_MODE_H
+
+#include <gtk/gtk.h>
+#include "gb-source-view.h"
+#include "gb-types.h"
+
+G_BEGIN_DECLS
+
+#define GB_TYPE_SOURCE_VIEW_MODE            (gb_source_view_mode_get_type())
+#define GB_SOURCE_VIEW_MODE(obj)            (G_TYPE_CHECK_INSTANCE_CAST ((obj), GB_TYPE_SOURCE_VIEW_MODE, 
GbSourceViewMode))
+#define GB_SOURCE_VIEW_MODE_CONST(obj)      (G_TYPE_CHECK_INSTANCE_CAST ((obj), GB_TYPE_SOURCE_VIEW_MODE, 
GbSourceViewMode const))
+#define GB_SOURCE_VIEW_MODE_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST ((klass),  GB_TYPE_SOURCE_VIEW_MODE, 
GbSourceViewModeClass))
+#define GB_IS_SOURCE_VIEW_MODE(obj)         (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GB_TYPE_SOURCE_VIEW_MODE))
+#define GB_IS_SOURCE_VIEW_MODE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass),  GB_TYPE_SOURCE_VIEW_MODE))
+#define GB_SOURCE_VIEW_MODE_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS ((obj),  GB_TYPE_SOURCE_VIEW_MODE, 
GbSourceViewModeClass))
+
+typedef struct _GbSourceViewMode        GbSourceViewMode;
+typedef struct _GbSourceViewModeClass   GbSourceViewModeClass;
+typedef struct _GbSourceViewModePrivate GbSourceViewModePrivate;
+
+struct _GbSourceViewMode
+{
+  GtkWidget parent;
+
+  /*< private >*/
+  GbSourceViewModePrivate *priv;
+};
+
+struct _GbSourceViewModeClass
+{
+  GtkWidgetClass parent_class;
+
+};
+
+
+/**
+ * GbSourceViewModeType:
+ * @GB_SOURCE_VIEW_MODE_TRANSIENT: Transient
+ * @GB_SOURCE_VIEW_MODE_PERMANENT: Permanent
+ * @GB_SOURCE_VIEW_MODE_MODAL: Modal
+ *
+ * The type of keyboard mode.
+ *
+ */
+typedef enum {
+  GB_SOURCE_VIEW_MODE_TYPE_TRANSIENT,
+  GB_SOURCE_VIEW_MODE_TYPE_PERMANENT,
+  GB_SOURCE_VIEW_MODE_TYPE_MODAL
+} GbSourceViewModeType;
+
+GType    gb_source_view_mode_get_type (void);
+
+GbSourceViewMode *gb_source_view_mode_new      (GtkWidget            *view,
+                                                const char           *mode,
+                                                GbSourceViewModeType  type);
+gboolean          gb_source_view_mode_do_event (GbSourceViewMode     *mode,
+                                                GdkEventKey          *event,
+                                                gboolean             *remove);
+
+G_END_DECLS
+
+#endif /* GB_SOURCE_VIEW_MODE_H */
diff --git a/src/gnome-builder.mk b/src/gnome-builder.mk
index fb6844e..c3c5e85 100644
--- a/src/gnome-builder.mk
+++ b/src/gnome-builder.mk
@@ -97,6 +97,8 @@ libgnome_builder_la_SOURCES = \
        src/editor/gb-source-search-highlighter.h \
        src/editor/gb-source-view.c \
        src/editor/gb-source-view.h \
+       src/editor/gb-source-view-mode.c \
+       src/editor/gb-source-view-mode.h \
        src/emacs/gb-source-emacs.c \
        src/emacs/gb-source-emacs.h \
        src/fuzzy/fuzzy.c \


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]