[gnome-initial-setup/shell/4765: 292/362] Port Python keyboard detector to C
- From: Jasper St. Pierre <jstpierre src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gnome-initial-setup/shell/4765: 292/362] Port Python keyboard detector to C
- Date: Thu, 19 Mar 2015 01:45:37 +0000 (UTC)
commit 98c0b8662d8a82e2ca02227f2e1b7b3a21005704
Author: Philip Chimento <philip endlessm com>
Date: Thu Dec 4 14:35:09 2014 -0800
Port Python keyboard detector to C
This is a straightforward port to C of the keyboard detector code
from Ubuntu's installer; with the exception of "Cancel" and "Add" buttons
in the dialog box. When the detection heuristic has finished, the "Add"
button becomes active.
(Roddy, Philip)
[endlessm/eos-shell#3425]
gnome-initial-setup/pages/keyboard/Makefile.am | 3 +
gnome-initial-setup/pages/keyboard/cc-key-row.c | 62 ++++
gnome-initial-setup/pages/keyboard/cc-key-row.h | 58 ++++
.../pages/keyboard/cc-keyboard-detector.c | 230 +++++++++++++
.../pages/keyboard/cc-keyboard-detector.h | 58 ++++
.../pages/keyboard/cc-keyboard-query.c | 343 ++++++++++++++++++++
.../pages/keyboard/cc-keyboard-query.h | 66 ++++
.../pages/keyboard/keyboard-detector.ui | 98 ++++++
.../pages/keyboard/keyboard.gresource.xml | 1 +
9 files changed, 919 insertions(+), 0 deletions(-)
---
diff --git a/gnome-initial-setup/pages/keyboard/Makefile.am b/gnome-initial-setup/pages/keyboard/Makefile.am
index 1d8831d..28b3fbd 100644
--- a/gnome-initial-setup/pages/keyboard/Makefile.am
+++ b/gnome-initial-setup/pages/keyboard/Makefile.am
@@ -18,6 +18,9 @@ BUILT_SOURCES += keyboard-resources.c keyboard-resources.h
libgiskeyboard_la_SOURCES = \
cc-input-chooser.c cc-input-chooser.h \
cc-ibus-utils.c cc-ibus-utils.h \
+ cc-keyboard-detector.c cc-keyboard-detector.h \
+ cc-keyboard-query.c cc-keyboard-query.h \
+ cc-key-row.c cc-key-row.h \
gis-keyboard-page.c gis-keyboard-page.h \
$(BUILT_SOURCES)
diff --git a/gnome-initial-setup/pages/keyboard/cc-key-row.c b/gnome-initial-setup/pages/keyboard/cc-key-row.c
new file mode 100644
index 0000000..e36b7de
--- /dev/null
+++ b/gnome-initial-setup/pages/keyboard/cc-key-row.c
@@ -0,0 +1,62 @@
+/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
+
+/*
+ * Copyright (C) 2014 Endless Mobile, Inc.
+ *
+ * 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 2 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, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ */
+
+#include "cc-key-row.h"
+
+G_DEFINE_TYPE (CcKeyRow, cc_key_row, GTK_TYPE_BOX);
+
+static void
+cc_key_row_class_init (CcKeyRowClass *klass)
+{
+}
+
+static void
+cc_key_row_init (CcKeyRow *self)
+{
+ gtk_box_set_spacing (GTK_BOX (self), 24);
+}
+
+GtkWidget *
+cc_key_row_new (void)
+{
+ return g_object_new (CC_TYPE_KEY_ROW, NULL);
+}
+
+void
+cc_key_row_add_character (CcKeyRow *self,
+ const char *key_label)
+{
+ char *label_string = g_strdup_printf ("<big>%s</big>", key_label);
+ GtkWidget *label = gtk_label_new (label_string);
+ g_free (label_string);
+
+ gtk_label_set_use_markup (GTK_LABEL (label), TRUE);
+ gtk_box_pack_start (GTK_BOX (self), label, TRUE, TRUE, 0);
+ gtk_widget_show (label);
+}
+
+void
+cc_key_row_clear (CcKeyRow *self)
+{
+ GList *children = gtk_container_get_children (GTK_CONTAINER (self));
+ g_list_foreach (children, (GFunc) gtk_widget_destroy, NULL);
+ g_list_free (children);
+}
diff --git a/gnome-initial-setup/pages/keyboard/cc-key-row.h b/gnome-initial-setup/pages/keyboard/cc-key-row.h
new file mode 100644
index 0000000..c08f0c1
--- /dev/null
+++ b/gnome-initial-setup/pages/keyboard/cc-key-row.h
@@ -0,0 +1,58 @@
+/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
+
+/*
+ * Copyright (C) 2014 Endless Mobile, Inc.
+ *
+ * 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 2 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, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ */
+
+#ifndef CC_KEY_ROW_H
+#define CC_KEY_ROW_H
+
+#include <glib-object.h>
+#include <gtk/gtk.h>
+
+G_BEGIN_DECLS
+
+#define CC_TYPE_KEY_ROW cc_key_row_get_type()
+#define CC_KEY_ROW(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), CC_TYPE_KEY_ROW, CcKeyRow))
+#define CC_KEY_ROW_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), CC_TYPE_KEY_ROW, CcKeyRowClass))
+#define CC_IS_KEY_ROW(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), CC_TYPE_KEY_ROW))
+#define CC_IS_KEY_ROW_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), CC_TYPE_KEY_ROW))
+#define CC_KEY_ROW_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), CC_TYPE_KEY_ROW, CcKeyRowClass))
+
+typedef struct _CcKeyRow CcKeyRow;
+typedef struct _CcKeyRowClass CcKeyRowClass;
+
+struct _CcKeyRow
+{
+ GtkBox parent;
+};
+
+struct _CcKeyRowClass
+{
+ GtkBoxClass parent_class;
+};
+
+GType cc_key_row_get_type (void) G_GNUC_CONST;
+GtkWidget *cc_key_row_new (void);
+void cc_key_row_add_character (CcKeyRow *self,
+ const char *label);
+void cc_key_row_clear (CcKeyRow *self);
+
+G_END_DECLS
+
+#endif /* CC_KEY_ROW_H */
diff --git a/gnome-initial-setup/pages/keyboard/cc-keyboard-detector.c
b/gnome-initial-setup/pages/keyboard/cc-keyboard-detector.c
new file mode 100644
index 0000000..7993899
--- /dev/null
+++ b/gnome-initial-setup/pages/keyboard/cc-keyboard-detector.c
@@ -0,0 +1,230 @@
+/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
+
+/*
+ * Copyright (C) 2014 Endless Mobile, Inc.
+ *
+ * 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 2 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, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ */
+
+#include <config.h>
+#include <string.h>
+
+#include "cc-keyboard-detector.h"
+
+KeyboardDetector *
+keyboard_detector_new (void)
+{
+ GError *error = NULL;
+ GInputStream *istream;
+ KeyboardDetector *det = g_new0 (KeyboardDetector, 1);
+
+ det->current_step = -1;
+ istream = g_resources_open_stream ("/org/gnome/initial-setup/pc105.tree",
+ G_RESOURCE_LOOKUP_FLAGS_NONE, &error);
+ if (istream == NULL)
+ g_error ("Error loading keyboard detector tree: %s", error->message);
+ det->fp = g_data_input_stream_new (istream);
+ g_object_unref (istream);
+
+ det->keycodes = g_hash_table_new (NULL, NULL);
+ det->symbols = NULL;
+ det->present = -1;
+ det->not_present = -1;
+ det->result = NULL;
+
+ return det;
+}
+
+static void
+keyboard_detector_clear (KeyboardDetector *det)
+{
+ g_hash_table_remove_all (det->keycodes);
+ g_list_foreach (det->symbols, (GFunc) g_free, NULL);
+ g_clear_pointer (&det->symbols, g_list_free);
+ det->present = -1;
+ det->not_present = -1;
+ g_clear_pointer (&det->result, g_free);
+}
+
+void
+keyboard_detector_free (KeyboardDetector *det)
+{
+ keyboard_detector_clear (det);
+ g_object_unref (det->fp);
+ g_hash_table_destroy (det->keycodes);
+ g_free (det);
+}
+
+KeyboardDetectorStepType
+keyboard_detector_read_step (KeyboardDetector *det,
+ int step)
+{
+ char *line;
+ size_t len;
+
+ if (det->current_step != -1)
+ {
+ GList *valid_steps = g_hash_table_get_values (det->keycodes);
+ gboolean found = (g_list_find (valid_steps, GINT_TO_POINTER (step)) != NULL);
+ g_list_free (valid_steps);
+ if (!(found || step == det->present || step == det->not_present))
+ /* Invalid argument */
+ return ERROR;
+ if (det->result)
+ /* Already done */
+ return ERROR;
+ }
+
+ KeyboardDetectorStepType step_type = UNKNOWN;
+ keyboard_detector_clear (det);
+
+ while ((line = g_data_input_stream_read_line_utf8 (det->fp, &len, NULL, NULL)) != NULL)
+ {
+ if (g_str_has_prefix (line, "STEP "))
+ {
+ /* This line starts a new step. */
+ int new_step = atoi (line + 5);
+ g_free (line);
+ if (det->current_step == step)
+ {
+ det->current_step = new_step;
+ return step_type;
+ }
+ else
+ {
+ det->current_step = new_step;
+ }
+ }
+ else if (det->current_step != step)
+ {
+ g_free (line);
+ continue;
+ }
+ else if (g_str_has_prefix (line, "PRESS "))
+ {
+ /* Ask the user to press a character on the keyboard. */
+ if (step_type == UNKNOWN)
+ step_type = PRESS_KEY;
+ if (step_type != PRESS_KEY)
+ {
+ g_free (line);
+ return ERROR;
+ }
+ char *key_symbol = g_strdup (g_strstrip (line + 6));
+ g_free (line);
+ det->symbols = g_list_append (det->symbols, key_symbol);
+ }
+ else if (g_str_has_prefix (line, "CODE "))
+ {
+ /* Direct the evaluating code to process step ## next if the
+ * user has pressed a key which returned that keycode.
+ */
+ if (step_type != PRESS_KEY)
+ {
+ g_free (line);
+ return ERROR;
+ }
+ char *keycode = strtok (line + 5, " ");
+ char *s = strtok (NULL, " ");
+ int code = atoi (keycode);
+ int next_step = atoi (s);
+ g_free (line);
+ g_hash_table_insert (det->keycodes, GINT_TO_POINTER (code), GINT_TO_POINTER (next_step));
+ }
+ else if (g_str_has_prefix (line, "FIND "))
+ {
+ /* Ask the user whether that character is present on their
+ * keyboard.
+ */
+ if (step_type == UNKNOWN)
+ {
+ step_type = KEY_PRESENT;
+ }
+ else
+ {
+ g_free (line);
+ return ERROR;
+ }
+ char *key_symbol = g_strdup (g_strstrip (line + 5));
+ g_free (line);
+ det->symbols = g_list_prepend (det->symbols, key_symbol);
+ }
+ else if (g_str_has_prefix (line, "FINDP "))
+ {
+ /* Equivalent to FIND, except that the user is asked to consider
+ * only the primary symbols (i.e. Plain and Shift).
+ */
+ if (step_type == UNKNOWN)
+ {
+ step_type = KEY_PRESENT_P;
+ }
+ else
+ {
+ g_free (line);
+ return ERROR;
+ }
+ char *key_symbol = g_strdup (g_strstrip (line + 6));
+ g_free (line);
+ det->symbols = g_list_prepend (det->symbols, key_symbol);
+ }
+ else if (g_str_has_prefix (line, "YES "))
+ {
+ /* Direct the evaluating code to process step ## next if the
+ * user does have this key.
+ */
+ int next_step = atoi (g_strstrip (line + 4));
+ g_free (line);
+ if (step_type != KEY_PRESENT_P &&
+ step_type != KEY_PRESENT)
+ return ERROR;
+ det->present = next_step;
+ }
+ else if (g_str_has_prefix (line, "NO "))
+ {
+ /* Direct the evaluating code to process step ## next if the
+ * user does not have this key.
+ */
+ int next_step = atoi (g_strstrip (line + 3));
+ g_free (line);
+ if (step_type != KEY_PRESENT_P &&
+ step_type != KEY_PRESENT)
+ return ERROR;
+ det->not_present = next_step;
+ }
+ else if (g_str_has_prefix (line, "MAP "))
+ {
+ /* This step uniquely identifies a keymap. */
+ if (step_type == UNKNOWN)
+ step_type = RESULT;
+ det->result = g_strdup (g_strstrip (line + 4));
+ g_free (line);
+ /* The Ubuntu file uses colons to separate country codes from layout
+ * variants, and GnomeXkb requires plus signs.
+ */
+ char *colon_pointer = strchr (det->result, ':');
+ if (colon_pointer != NULL)
+ *colon_pointer = '+';
+ return step_type;
+ }
+ else {
+ g_free (line);
+ return ERROR;
+ }
+ }
+
+ /* The requested step was not found. */
+ return ERROR;
+}
diff --git a/gnome-initial-setup/pages/keyboard/cc-keyboard-detector.h
b/gnome-initial-setup/pages/keyboard/cc-keyboard-detector.h
new file mode 100644
index 0000000..9f490a5
--- /dev/null
+++ b/gnome-initial-setup/pages/keyboard/cc-keyboard-detector.h
@@ -0,0 +1,58 @@
+/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
+
+/*
+ * Copyright (C) 2014 Endless Mobile, Inc
+ *
+ * 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 2 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, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ */
+
+#ifndef CC_KEYBOARD_DETECTOR_H
+#define CC_KEYBOARD_DETECTOR_H
+
+#include <glib.h>
+#include <gio/gio.h>
+
+G_BEGIN_DECLS
+
+typedef enum {
+ UNKNOWN,
+ PRESS_KEY,
+ KEY_PRESENT,
+ KEY_PRESENT_P,
+ RESULT,
+ ERROR,
+} KeyboardDetectorStepType;
+
+typedef struct {
+ GHashTable *keycodes; /* GHashTable<int, int> */
+ GList *symbols; /* GList<char *>, strings owned by KeyboardDetector */
+ int present;
+ int not_present;
+ char *result;
+
+ /* Private */
+ int current_step;
+ GDataInputStream *fp;
+} KeyboardDetector;
+
+KeyboardDetector *keyboard_detector_new (void);
+void keyboard_detector_free (KeyboardDetector *det);
+KeyboardDetectorStepType keyboard_detector_read_step (KeyboardDetector *det,
+ int step);
+
+G_END_DECLS
+
+#endif /* CC_KEYBOARD_DETECTOR_H */
diff --git a/gnome-initial-setup/pages/keyboard/cc-keyboard-query.c
b/gnome-initial-setup/pages/keyboard/cc-keyboard-query.c
new file mode 100644
index 0000000..4bdfccb
--- /dev/null
+++ b/gnome-initial-setup/pages/keyboard/cc-keyboard-query.c
@@ -0,0 +1,343 @@
+/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
+
+/*
+ * Copyright (C) 2014 Endless Mobile, Inc.
+ *
+ * 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 2 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, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ */
+
+#include <config.h>
+#include <glib/gi18n.h>
+
+#include "cc-keyboard-detector.h"
+#include "cc-keyboard-query.h"
+#include "cc-key-row.h"
+
+typedef struct
+{
+ KeyboardDetector *det;
+ char *detected_id;
+ char *detected_display_name;
+
+ const char *press_string;
+ const char *present_string;
+
+ GtkWidget *vbox;
+ GtkWidget *heading;
+ GtkWidget *keyrow;
+ GtkWidget *buttons;
+ GtkWidget *add_button;
+
+ GnomeXkbInfo *xkb_data;
+} CcKeyboardQueryPrivate;
+
+G_DEFINE_TYPE_WITH_PRIVATE (CcKeyboardQuery, cc_keyboard_query, GTK_TYPE_DIALOG);
+
+enum {
+ LAYOUT_RESULT,
+ N_SIGNALS,
+};
+
+enum {
+ PROP_0,
+ XKB_DATA,
+ N_PROPS,
+};
+
+static guint cc_keyboard_query_signals[N_SIGNALS] = { 0, };
+static GParamSpec *cc_keyboard_query_props[N_PROPS] = { NULL, };
+
+static void
+process (CcKeyboardQuery *self,
+ KeyboardDetectorStepType result)
+{
+ CcKeyboardQueryPrivate *priv = cc_keyboard_query_get_instance_private (self);
+ GList *iter;
+
+ cc_key_row_clear (CC_KEY_ROW (priv->keyrow));
+ for (iter = priv->det->symbols; iter != NULL; iter = iter->next)
+ cc_key_row_add_character (CC_KEY_ROW (priv->keyrow), iter->data);
+
+ switch (result)
+ {
+ case PRESS_KEY:
+ gtk_label_set_label (GTK_LABEL (priv->heading), priv->press_string);
+ gtk_widget_hide (GTK_WIDGET (priv->buttons));
+ break;
+ case KEY_PRESENT:
+ case KEY_PRESENT_P:
+ gtk_label_set_label (GTK_LABEL (priv->heading), priv->present_string);
+ gtk_widget_show (GTK_WIDGET (priv->buttons));
+ break;
+ case RESULT:
+ g_signal_emit (self, cc_keyboard_query_signals[LAYOUT_RESULT], 0,
+ priv->det->result);
+ break;
+ case ERROR:
+ gtk_widget_hide (GTK_WIDGET (self));
+ break;
+ default:
+ g_assert_not_reached ();
+ }
+}
+
+static void
+have_key (GtkButton *button,
+ CcKeyboardQuery *self)
+{
+ CcKeyboardQueryPrivate *priv = cc_keyboard_query_get_instance_private (self);
+ KeyboardDetectorStepType result;
+
+ result = keyboard_detector_read_step (priv->det, priv->det->present);
+ process (self, result);
+}
+
+static void
+no_have_key (GtkButton *button,
+ CcKeyboardQuery *self)
+{
+ CcKeyboardQueryPrivate *priv = cc_keyboard_query_get_instance_private (self);
+ KeyboardDetectorStepType result;
+
+ result = keyboard_detector_read_step (priv->det, priv->det->not_present);
+ process (self, result);
+}
+
+static gboolean
+key_press_event (GtkWidget *widget,
+ GdkEventKey *event,
+ CcKeyboardQuery *self)
+{
+ CcKeyboardQueryPrivate *priv = cc_keyboard_query_get_instance_private (self);
+ KeyboardDetectorStepType result;
+ int code, new_step;
+ gpointer c;
+
+ /* FIXME need to account for possible remapping. Find the API to translate
+ * kernel keycodes to X keycodes (xkb).
+ * MIN_KEYCODE = 8
+ */
+
+ /* FIXME escape should close the window. */
+
+ code = event->hardware_keycode - 8;
+ if (code > 255)
+ return GDK_EVENT_PROPAGATE;
+ /* XKB doesn't support keycodes > 255. */
+
+ c = g_hash_table_lookup (priv->det->keycodes, GINT_TO_POINTER (code));
+ if (c == NULL)
+ return GDK_EVENT_PROPAGATE;
+
+ new_step = GPOINTER_TO_INT (c);
+ result = keyboard_detector_read_step (priv->det, new_step);
+ process (self, result);
+ return GDK_EVENT_STOP;
+}
+
+static void
+cc_keyboard_query_constructed (GObject *object)
+{
+ CcKeyboardQuery *self = CC_KEYBOARD_QUERY (object);
+ CcKeyboardQueryPrivate *priv = cc_keyboard_query_get_instance_private (self);
+
+ priv->keyrow = cc_key_row_new ();
+ gtk_box_pack_start (GTK_BOX (priv->vbox), priv->keyrow, FALSE, TRUE, 0);
+ gtk_box_reorder_child (GTK_BOX (priv->vbox), priv->keyrow, 1);
+
+ gtk_widget_hide (priv->buttons);
+
+ G_OBJECT_CLASS (cc_keyboard_query_parent_class)->constructed (object);
+}
+
+static void
+cc_keyboard_query_get_property (GObject *object,
+ guint id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ CcKeyboardQuery *self = CC_KEYBOARD_QUERY (object);
+ CcKeyboardQueryPrivate *priv = cc_keyboard_query_get_instance_private (self);
+
+ switch (id)
+ {
+ case XKB_DATA:
+ g_value_set_object (value, priv->xkb_data);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, id, pspec);
+ }
+}
+
+static void
+cc_keyboard_query_set_property (GObject *object,
+ guint id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ CcKeyboardQuery *self = CC_KEYBOARD_QUERY (object);
+ CcKeyboardQueryPrivate *priv = cc_keyboard_query_get_instance_private (self);
+
+ switch (id)
+ {
+ case XKB_DATA:
+ priv->xkb_data = g_value_dup_object (value);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, id, pspec);
+ }
+}
+
+static void
+cc_keyboard_query_dispose (GObject *object)
+{
+ CcKeyboardQuery *self = CC_KEYBOARD_QUERY (object);
+ CcKeyboardQueryPrivate *priv = cc_keyboard_query_get_instance_private (self);
+
+ g_clear_object (&priv->xkb_data);
+
+ G_OBJECT_CLASS (cc_keyboard_query_parent_class)->dispose (object);
+}
+
+static void
+cc_keyboard_query_finalize (GObject *object)
+{
+ CcKeyboardQuery *self = CC_KEYBOARD_QUERY (object);
+ CcKeyboardQueryPrivate *priv = cc_keyboard_query_get_instance_private (self);
+
+ g_clear_pointer (&priv->det, keyboard_detector_free);
+ g_clear_pointer (&priv->detected_id, g_free);
+ g_clear_pointer (&priv->detected_display_name, g_free);
+
+ G_OBJECT_CLASS (cc_keyboard_query_parent_class)->finalize (object);
+}
+
+/* Default handler for CcKeyboardQuery::layout-result */
+static void
+cc_keyboard_query_layout_result (CcKeyboardQuery *self,
+ const char *result)
+{
+ CcKeyboardQueryPrivate *priv = cc_keyboard_query_get_instance_private (self);
+ char *result_message;
+ const char *display_name = NULL;
+
+ priv->detected_id = g_strdup (result);
+ if (priv->xkb_data != NULL)
+ gnome_xkb_info_get_layout_info (priv->xkb_data, result, &display_name, NULL,
+ NULL, NULL);
+
+ priv->detected_display_name = g_strdup (display_name);
+ result_message = g_strdup_printf ("%s\n%s",
+ _("Your keyboard layout seems to be:"),
+ display_name ? display_name : result);
+ gtk_label_set_label (GTK_LABEL (priv->heading), result_message);
+ gtk_widget_hide (priv->buttons);
+ gtk_widget_hide (priv->keyrow);
+ gtk_widget_set_sensitive (priv->add_button, TRUE);
+
+ g_free (result_message);
+}
+
+static void
+cc_keyboard_query_class_init (CcKeyboardQueryClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+ GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
+
+ cc_keyboard_query_signals[LAYOUT_RESULT] =
+ g_signal_new ("layout-result", CC_TYPE_KEYBOARD_QUERY, G_SIGNAL_RUN_FIRST,
+ G_STRUCT_OFFSET (CcKeyboardQueryClass, layout_result),
+ NULL, NULL, g_cclosure_marshal_VOID__STRING, G_TYPE_NONE,
+ 1, G_TYPE_STRING);
+
+ cc_keyboard_query_props[XKB_DATA] =
+ g_param_spec_object ("xkb-data", "XKB data",
+ "X Keyboard info for looking up display names of keyboard layouts",
+ GNOME_TYPE_XKB_INFO,
+ G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS);
+
+ object_class->constructed = cc_keyboard_query_constructed;
+ object_class->get_property = cc_keyboard_query_get_property;
+ object_class->set_property = cc_keyboard_query_set_property;
+ object_class->dispose = cc_keyboard_query_dispose;
+ object_class->finalize = cc_keyboard_query_finalize;
+ g_object_class_install_properties (object_class, N_PROPS,
+ cc_keyboard_query_props);
+
+ gtk_widget_class_set_template_from_resource (widget_class,
+ "/org/gnome/initial-setup/keyboard-detector.ui");
+ gtk_widget_class_bind_template_child_private (widget_class, CcKeyboardQuery, vbox);
+ gtk_widget_class_bind_template_child_private (widget_class, CcKeyboardQuery, heading);
+ gtk_widget_class_bind_template_child_private (widget_class, CcKeyboardQuery, buttons);
+ gtk_widget_class_bind_template_child_private (widget_class, CcKeyboardQuery, add_button);
+ gtk_widget_class_bind_template_callback (widget_class, have_key);
+ gtk_widget_class_bind_template_callback (widget_class, no_have_key);
+ gtk_widget_class_bind_template_callback (widget_class, key_press_event);
+
+ klass->layout_result = cc_keyboard_query_layout_result;
+}
+
+static void
+cc_keyboard_query_init (CcKeyboardQuery *self)
+{
+ CcKeyboardQueryPrivate *priv = cc_keyboard_query_get_instance_private (self);
+
+ gtk_widget_init_template (GTK_WIDGET (self));
+
+ priv->press_string = _("Please press one of the following keys:");
+ priv->present_string = _("Is the following key present on your keyboard?");
+
+ priv->det = keyboard_detector_new ();
+}
+
+GtkWidget *
+cc_keyboard_query_new (GtkWindow *main_window,
+ GnomeXkbInfo *xkb_data)
+{
+ return g_object_new (CC_TYPE_KEYBOARD_QUERY,
+ "transient-for", main_window,
+ "xkb-data", xkb_data,
+ NULL);
+}
+
+void
+cc_keyboard_query_run (CcKeyboardQuery *self)
+{
+ CcKeyboardQueryPrivate *priv = cc_keyboard_query_get_instance_private (self);
+ KeyboardDetectorStepType result;
+
+ gtk_widget_show_all (GTK_WIDGET (self));
+ result = keyboard_detector_read_step (priv->det, 0);
+ process (self, result);
+}
+
+gboolean
+cc_keyboard_query_get_selected (CcKeyboardQuery *self,
+ gchar **id,
+ gchar **name)
+{
+ CcKeyboardQueryPrivate *priv = cc_keyboard_query_get_instance_private (self);
+
+ if (!priv->detected_id)
+ return FALSE;
+
+ if (id != NULL)
+ *id = g_strdup (priv->detected_id);
+ if (name != NULL)
+ *name = g_strdup (priv->detected_display_name);
+
+ return TRUE;
+}
diff --git a/gnome-initial-setup/pages/keyboard/cc-keyboard-query.h
b/gnome-initial-setup/pages/keyboard/cc-keyboard-query.h
new file mode 100644
index 0000000..1329af1
--- /dev/null
+++ b/gnome-initial-setup/pages/keyboard/cc-keyboard-query.h
@@ -0,0 +1,66 @@
+/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
+
+/*
+ * Copyright (C) 2014 Endless Mobile, Inc.
+ *
+ * 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 2 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, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ */
+
+#ifndef CC_KEYBOARD_QUERY_H
+#define CC_KEYBOARD_QUERY_H
+
+#include <glib-object.h>
+#include <gtk/gtk.h>
+
+#define GNOME_DESKTOP_USE_UNSTABLE_API
+#include <libgnome-desktop/gnome-xkb-info.h>
+
+G_BEGIN_DECLS
+
+#define CC_TYPE_KEYBOARD_QUERY cc_keyboard_query_get_type()
+#define CC_KEYBOARD_QUERY(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), CC_TYPE_KEYBOARD_QUERY, CcKeyboardQuery))
+#define CC_KEYBOARD_QUERY_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), CC_TYPE_KEYBOARD_QUERY,
CcKeyboardQueryClass))
+#define CC_IS_KEYBOARD_QUERY(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), CC_TYPE_KEYBOARD_QUERY))
+#define CC_IS_KEYBOARD_QUERY_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), CC_TYPE_KEYBOARD_QUERY))
+#define CC_KEYBOARD_QUERY_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), CC_TYPE_KEYBOARD_QUERY,
CcKeyboardQueryClass))
+
+typedef struct _CcKeyboardQuery CcKeyboardQuery;
+typedef struct _CcKeyboardQueryClass CcKeyboardQueryClass;
+
+struct _CcKeyboardQuery
+{
+ GtkDialog parent;
+};
+
+struct _CcKeyboardQueryClass
+{
+ GtkDialogClass parent_class;
+
+ /* signals */
+ void (*layout_result)(CcKeyboardQuery *, const char *);
+};
+
+GType cc_keyboard_query_get_type (void) G_GNUC_CONST;
+GtkWidget *cc_keyboard_query_new (GtkWindow *main_window,
+ GnomeXkbInfo *xkb_info);
+void cc_keyboard_query_run (CcKeyboardQuery *self);
+gboolean cc_keyboard_query_get_selected (CcKeyboardQuery *self,
+ char **id,
+ char **name);
+
+G_END_DECLS
+
+#endif /* CC_KEYBOARD_QUERY_H */
diff --git a/gnome-initial-setup/pages/keyboard/keyboard-detector.ui
b/gnome-initial-setup/pages/keyboard/keyboard-detector.ui
new file mode 100644
index 0000000..4276729
--- /dev/null
+++ b/gnome-initial-setup/pages/keyboard/keyboard-detector.ui
@@ -0,0 +1,98 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<interface>
+ <!-- interface-requires gtk+ 3.0 -->
+ <template class="CcKeyboardQuery" parent="GtkDialog">
+ <property name="title" translatable="yes">Detect Keyboard Layout...</property>
+ <property name="default_height">-1</property>
+ <property name="modal">True</property>
+ <property name="border-width">20</property>
+ <property name="destroy_with_parent">True</property>
+ <property name="resizable">False</property>
+ <signal name="key-press-event" handler="key_press_event"/>
+ <child internal-child="vbox">
+ <object class="GtkBox" id="vbox">
+ <property name="visible">True</property>
+ <property name="orientation">vertical</property>
+ <property name="spacing">10</property>
+ <child>
+ <object class="GtkLabel" id="heading">
+ <property name="visible">True</property>
+ <property name="xalign">0</property>
+ <property name="label" translatable="yes">Please press one of the following keys:</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkButtonBox" id="buttons">
+ <property name="visible">False</property>
+ <property name="spacing">12</property>
+ <property name="layout_style">start</property>
+ <property name="orientation">horizontal</property>
+ <child>
+ <object class="GtkButton" id="no_button">
+ <property name="visible">True</property>
+ <property name="label">gtk-no</property>
+ <property name="use_stock">True</property>
+ <signal name="clicked" handler="no_have_key"/>
+ </object>
+ <packing>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkButton" id="yes_button">
+ <property name="visible">True</property>
+ <property name="label">gtk-yes</property>
+ <property name="use_stock">True</property>
+ <signal name="clicked" handler="have_key"/>
+ </object>
+ <packing>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">2</property>
+ </packing>
+ </child>
+ <child internal-child="action_area">
+ <object class="GtkButtonBox" id="action_area">
+ <property name="visible">True</property>
+ <property name="orientation">horizontal</property>
+ <child>
+ <object class="GtkButton" id="cancel_button">
+ <property name="visible">True</property>
+ <property name="label">gtk-cancel</property>
+ <property name="use_stock">True</property>
+ <property name="use_underline" >True</property>
+ </object>
+ </child>
+ <child>
+ <object class="GtkButton" id="add_button">
+ <property name="visible">True</property>
+ <property name="sensitive">False</property>
+ <property name="label">gtk-add</property>
+ <property name="use_stock">True</property>
+ <property name="use_underline" >True</property>
+ </object>
+ </child>
+ </object>
+ </child>
+ </object>
+ </child>
+ <action-widgets>
+ <action-widget response="-5">add_button</action-widget>
+ <action-widget response="-6">cancel_button</action-widget>
+ </action-widgets>
+ </template>
+</interface>
diff --git a/gnome-initial-setup/pages/keyboard/keyboard.gresource.xml
b/gnome-initial-setup/pages/keyboard/keyboard.gresource.xml
index b3aaad6..db34d78 100644
--- a/gnome-initial-setup/pages/keyboard/keyboard.gresource.xml
+++ b/gnome-initial-setup/pages/keyboard/keyboard.gresource.xml
@@ -3,6 +3,7 @@
<gresource prefix="/org/gnome/initial-setup">
<file preprocess="xml-stripblanks">gis-keyboard-page.ui</file>
<file preprocess="xml-stripblanks">input-chooser.ui</file>
+ <file preprocess="xml-stripblanks">keyboard-detector.ui</file>
<file>pc105.tree</file>
</gresource>
</gresources>
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]