|
Packit Service |
fb6fa5 |
/*
|
|
Packit Service |
fb6fa5 |
* Copyright (c) 2006-2009 Openismus GmbH
|
|
Packit Service |
fb6fa5 |
*
|
|
Packit Service |
fb6fa5 |
* This library is free software; you can redistribute it and/or
|
|
Packit Service |
fb6fa5 |
* modify it under the terms of the GNU Lesser General Public
|
|
Packit Service |
fb6fa5 |
* License as published by the Free Software Foundation; either
|
|
Packit Service |
fb6fa5 |
* version 2 of the License, or (at your option) any later version.
|
|
Packit Service |
fb6fa5 |
*
|
|
Packit Service |
fb6fa5 |
* This library is distributed in the hope that it will be useful,
|
|
Packit Service |
fb6fa5 |
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
Packit Service |
fb6fa5 |
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
Packit Service |
fb6fa5 |
* Lesser General Public License for more details.
|
|
Packit Service |
fb6fa5 |
*
|
|
Packit Service |
fb6fa5 |
* You should have received a copy of the GNU Lesser General Public
|
|
Packit Service |
fb6fa5 |
* License along with this library; if not, write to the
|
|
Packit Service |
fb6fa5 |
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
|
|
Packit Service |
fb6fa5 |
* Boston, MA 02111-1307, USA.
|
|
Packit Service |
fb6fa5 |
*/
|
|
Packit Service |
fb6fa5 |
|
|
Packit Service |
fb6fa5 |
#include "gtkimcontextmultipress.h"
|
|
Packit Service |
fb6fa5 |
#include <string.h>
|
|
Packit Service |
fb6fa5 |
#include <gtk/gtk.h>
|
|
Packit Service |
fb6fa5 |
#include <gdk/gdkkeysyms.h>
|
|
Packit Service |
fb6fa5 |
#include <gtk/gtkimmodule.h>
|
|
Packit Service |
fb6fa5 |
#include <config.h>
|
|
Packit Service |
fb6fa5 |
|
|
Packit Service |
fb6fa5 |
#define AUTOMATIC_COMPOSE_TIMEOUT 1 /* seconds */
|
|
Packit Service |
fb6fa5 |
#define CONFIGURATION_FILENAME MULTIPRESS_CONFDIR G_DIR_SEPARATOR_S "im-multipress.conf"
|
|
Packit Service |
fb6fa5 |
|
|
Packit Service |
fb6fa5 |
/* This contains rows of characters that can be entered by pressing
|
|
Packit Service |
fb6fa5 |
* a particular key repeatedly. Each row has one key (such as GDK_a),
|
|
Packit Service |
fb6fa5 |
* and an array of character strings, such as "a".
|
|
Packit Service |
fb6fa5 |
*/
|
|
Packit Service |
fb6fa5 |
typedef struct
|
|
Packit Service |
fb6fa5 |
{
|
|
Packit Service |
fb6fa5 |
gchar **characters; /* array of strings */
|
|
Packit Service |
fb6fa5 |
gsize n_characters; /* number of strings in the array */
|
|
Packit Service |
fb6fa5 |
}
|
|
Packit Service |
fb6fa5 |
KeySequence;
|
|
Packit Service |
fb6fa5 |
|
|
Packit Service |
fb6fa5 |
static GObjectClass *im_context_multipress_parent_class = NULL;
|
|
Packit Service |
fb6fa5 |
static GType im_context_multipress_type = 0;
|
|
Packit Service |
fb6fa5 |
|
|
Packit Service |
fb6fa5 |
static void im_context_multipress_class_init (GtkImContextMultipressClass *klass);
|
|
Packit Service |
fb6fa5 |
static void im_context_multipress_init (GtkImContextMultipress *self);
|
|
Packit Service |
fb6fa5 |
static void im_context_multipress_finalize (GObject *obj);
|
|
Packit Service |
fb6fa5 |
|
|
Packit Service |
fb6fa5 |
static void load_config (GtkImContextMultipress *self);
|
|
Packit Service |
fb6fa5 |
|
|
Packit Service |
fb6fa5 |
static gboolean vfunc_filter_keypress (GtkIMContext *context,
|
|
Packit Service |
fb6fa5 |
GdkEventKey *event);
|
|
Packit Service |
fb6fa5 |
static void vfunc_reset (GtkIMContext *context);
|
|
Packit Service |
fb6fa5 |
static void vfunc_get_preedit_string (GtkIMContext *context,
|
|
Packit Service |
fb6fa5 |
gchar **str,
|
|
Packit Service |
fb6fa5 |
PangoAttrList **attrs,
|
|
Packit Service |
fb6fa5 |
gint *cursor_pos);
|
|
Packit Service |
fb6fa5 |
|
|
Packit Service |
fb6fa5 |
/* Notice that we have a *_register_type(GTypeModule*) function instead of a
|
|
Packit Service |
fb6fa5 |
* *_get_type() function, because we must use g_type_module_register_type(),
|
|
Packit Service |
fb6fa5 |
* providing the GTypeModule* that was provided to im_context_init(). That
|
|
Packit Service |
fb6fa5 |
* is also why we are not using G_DEFINE_TYPE().
|
|
Packit Service |
fb6fa5 |
*/
|
|
Packit Service |
fb6fa5 |
void
|
|
Packit Service |
fb6fa5 |
gtk_im_context_multipress_register_type (GTypeModule* type_module)
|
|
Packit Service |
fb6fa5 |
{
|
|
Packit Service |
fb6fa5 |
const GTypeInfo im_context_multipress_info =
|
|
Packit Service |
fb6fa5 |
{
|
|
Packit Service |
fb6fa5 |
sizeof (GtkImContextMultipressClass),
|
|
Packit Service |
fb6fa5 |
(GBaseInitFunc) NULL,
|
|
Packit Service |
fb6fa5 |
(GBaseFinalizeFunc) NULL,
|
|
Packit Service |
fb6fa5 |
(GClassInitFunc) &im_context_multipress_class_init,
|
|
Packit Service |
fb6fa5 |
NULL,
|
|
Packit Service |
fb6fa5 |
NULL,
|
|
Packit Service |
fb6fa5 |
sizeof (GtkImContextMultipress),
|
|
Packit Service |
fb6fa5 |
0,
|
|
Packit Service |
fb6fa5 |
(GInstanceInitFunc) &im_context_multipress_init,
|
|
Packit Service |
fb6fa5 |
0,
|
|
Packit Service |
fb6fa5 |
};
|
|
Packit Service |
fb6fa5 |
|
|
Packit Service |
fb6fa5 |
im_context_multipress_type =
|
|
Packit Service |
fb6fa5 |
g_type_module_register_type (type_module,
|
|
Packit Service |
fb6fa5 |
GTK_TYPE_IM_CONTEXT,
|
|
Packit Service |
fb6fa5 |
"GtkImContextMultipress",
|
|
Packit Service |
fb6fa5 |
&im_context_multipress_info, 0);
|
|
Packit Service |
fb6fa5 |
}
|
|
Packit Service |
fb6fa5 |
|
|
Packit Service |
fb6fa5 |
GType
|
|
Packit Service |
fb6fa5 |
gtk_im_context_multipress_get_type (void)
|
|
Packit Service |
fb6fa5 |
{
|
|
Packit Service |
fb6fa5 |
g_assert (im_context_multipress_type != 0);
|
|
Packit Service |
fb6fa5 |
|
|
Packit Service |
fb6fa5 |
return im_context_multipress_type;
|
|
Packit Service |
fb6fa5 |
}
|
|
Packit Service |
fb6fa5 |
|
|
Packit Service |
fb6fa5 |
static void
|
|
Packit Service |
fb6fa5 |
key_sequence_free (gpointer value)
|
|
Packit Service |
fb6fa5 |
{
|
|
Packit Service |
fb6fa5 |
KeySequence *seq = value;
|
|
Packit Service |
fb6fa5 |
|
|
Packit Service |
fb6fa5 |
if (seq != NULL)
|
|
Packit Service |
fb6fa5 |
{
|
|
Packit Service |
fb6fa5 |
g_strfreev (seq->characters);
|
|
Packit Service |
fb6fa5 |
g_slice_free (KeySequence, seq);
|
|
Packit Service |
fb6fa5 |
}
|
|
Packit Service |
fb6fa5 |
}
|
|
Packit Service |
fb6fa5 |
|
|
Packit Service |
fb6fa5 |
static void
|
|
Packit Service |
fb6fa5 |
im_context_multipress_class_init (GtkImContextMultipressClass *klass)
|
|
Packit Service |
fb6fa5 |
{
|
|
Packit Service |
fb6fa5 |
GtkIMContextClass *im_context_class;
|
|
Packit Service |
fb6fa5 |
|
|
Packit Service |
fb6fa5 |
/* Set this so we can use it later: */
|
|
Packit Service |
fb6fa5 |
im_context_multipress_parent_class = g_type_class_peek_parent (klass);
|
|
Packit Service |
fb6fa5 |
|
|
Packit Service |
fb6fa5 |
/* Specify our vfunc implementations: */
|
|
Packit Service |
fb6fa5 |
im_context_class = GTK_IM_CONTEXT_CLASS (klass);
|
|
Packit Service |
fb6fa5 |
im_context_class->filter_keypress = &vfunc_filter_keypress;
|
|
Packit Service |
fb6fa5 |
im_context_class->reset = &vfunc_reset;
|
|
Packit Service |
fb6fa5 |
im_context_class->get_preedit_string = &vfunc_get_preedit_string;
|
|
Packit Service |
fb6fa5 |
|
|
Packit Service |
fb6fa5 |
G_OBJECT_CLASS (klass)->finalize = &im_context_multipress_finalize;
|
|
Packit Service |
fb6fa5 |
}
|
|
Packit Service |
fb6fa5 |
|
|
Packit Service |
fb6fa5 |
static void
|
|
Packit Service |
fb6fa5 |
im_context_multipress_init (GtkImContextMultipress *self)
|
|
Packit Service |
fb6fa5 |
{
|
|
Packit Service |
fb6fa5 |
self->key_sequences = g_hash_table_new_full (&g_direct_hash, &g_direct_equal,
|
|
Packit Service |
fb6fa5 |
NULL, &key_sequence_free);
|
|
Packit Service |
fb6fa5 |
load_config (self);
|
|
Packit Service |
fb6fa5 |
}
|
|
Packit Service |
fb6fa5 |
|
|
Packit Service |
fb6fa5 |
static void
|
|
Packit Service |
fb6fa5 |
im_context_multipress_finalize (GObject *obj)
|
|
Packit Service |
fb6fa5 |
{
|
|
Packit Service |
fb6fa5 |
GtkImContextMultipress *self;
|
|
Packit Service |
fb6fa5 |
|
|
Packit Service |
fb6fa5 |
self = GTK_IM_CONTEXT_MULTIPRESS (obj);
|
|
Packit Service |
fb6fa5 |
|
|
Packit Service |
fb6fa5 |
/* Release the configuration data: */
|
|
Packit Service |
fb6fa5 |
if (self->key_sequences != NULL)
|
|
Packit Service |
fb6fa5 |
{
|
|
Packit Service |
fb6fa5 |
g_hash_table_destroy (self->key_sequences);
|
|
Packit Service |
fb6fa5 |
self->key_sequences = NULL;
|
|
Packit Service |
fb6fa5 |
}
|
|
Packit Service |
fb6fa5 |
|
|
Packit Service |
fb6fa5 |
(*im_context_multipress_parent_class->finalize) (obj);
|
|
Packit Service |
fb6fa5 |
}
|
|
Packit Service |
fb6fa5 |
|
|
Packit Service |
fb6fa5 |
|
|
Packit Service |
fb6fa5 |
GtkIMContext *
|
|
Packit Service |
fb6fa5 |
gtk_im_context_multipress_new (void)
|
|
Packit Service |
fb6fa5 |
{
|
|
Packit Service |
fb6fa5 |
return (GtkIMContext *)g_object_new (GTK_TYPE_IM_CONTEXT_MULTIPRESS, NULL);
|
|
Packit Service |
fb6fa5 |
}
|
|
Packit Service |
fb6fa5 |
|
|
Packit Service |
fb6fa5 |
static void
|
|
Packit Service |
fb6fa5 |
cancel_automatic_timeout_commit (GtkImContextMultipress *multipress_context)
|
|
Packit Service |
fb6fa5 |
{
|
|
Packit Service |
fb6fa5 |
if (multipress_context->timeout_id)
|
|
Packit Service |
fb6fa5 |
g_source_remove (multipress_context->timeout_id);
|
|
Packit Service |
fb6fa5 |
|
|
Packit Service |
fb6fa5 |
multipress_context->timeout_id = 0;
|
|
Packit Service |
fb6fa5 |
}
|
|
Packit Service |
fb6fa5 |
|
|
Packit Service |
fb6fa5 |
|
|
Packit Service |
fb6fa5 |
/* Clear the compose buffer, so we are ready to compose the next character.
|
|
Packit Service |
fb6fa5 |
*/
|
|
Packit Service |
fb6fa5 |
static void
|
|
Packit Service |
fb6fa5 |
clear_compose_buffer (GtkImContextMultipress *multipress_context)
|
|
Packit Service |
fb6fa5 |
{
|
|
Packit Service |
fb6fa5 |
multipress_context->key_last_entered = 0;
|
|
Packit Service |
fb6fa5 |
multipress_context->compose_count = 0;
|
|
Packit Service |
fb6fa5 |
|
|
Packit Service |
fb6fa5 |
cancel_automatic_timeout_commit (multipress_context);
|
|
Packit Service |
fb6fa5 |
|
|
Packit Service |
fb6fa5 |
if (multipress_context->tentative_match)
|
|
Packit Service |
fb6fa5 |
{
|
|
Packit Service |
fb6fa5 |
multipress_context->tentative_match = NULL;
|
|
Packit Service |
fb6fa5 |
g_signal_emit_by_name (multipress_context, "preedit-changed");
|
|
Packit Service |
fb6fa5 |
g_signal_emit_by_name (multipress_context, "preedit-end");
|
|
Packit Service |
fb6fa5 |
}
|
|
Packit Service |
fb6fa5 |
}
|
|
Packit Service |
fb6fa5 |
|
|
Packit Service |
fb6fa5 |
/* Finish composing, provide the character, and clear our compose buffer.
|
|
Packit Service |
fb6fa5 |
*/
|
|
Packit Service |
fb6fa5 |
static void
|
|
Packit Service |
fb6fa5 |
accept_character (GtkImContextMultipress *multipress_context, const gchar *characters)
|
|
Packit Service |
fb6fa5 |
{
|
|
Packit Service |
fb6fa5 |
/* Clear the compose buffer, so we are ready to compose the next character.
|
|
Packit Service |
fb6fa5 |
* Note that if we emit "preedit-changed" after "commit", there's a segfault/
|
|
Packit Service |
fb6fa5 |
* invalid-write with GtkTextView in gtk_text_layout_free_line_display(), when
|
|
Packit Service |
fb6fa5 |
* destroying a PangoLayout (this can also be avoided by not using any Pango
|
|
Packit Service |
fb6fa5 |
* attributes in get_preedit_string(). */
|
|
Packit Service |
fb6fa5 |
clear_compose_buffer (multipress_context);
|
|
Packit Service |
fb6fa5 |
|
|
Packit Service |
fb6fa5 |
/* Provide the character to GTK+ */
|
|
Packit Service |
fb6fa5 |
g_signal_emit_by_name (multipress_context, "commit", characters);
|
|
Packit Service |
fb6fa5 |
}
|
|
Packit Service |
fb6fa5 |
|
|
Packit Service |
fb6fa5 |
static gboolean
|
|
Packit Service |
fb6fa5 |
on_timeout (gpointer data)
|
|
Packit Service |
fb6fa5 |
{
|
|
Packit Service |
fb6fa5 |
GtkImContextMultipress *multipress_context;
|
|
Packit Service |
fb6fa5 |
|
|
Packit Service |
fb6fa5 |
GDK_THREADS_ENTER ();
|
|
Packit Service |
fb6fa5 |
|
|
Packit Service |
fb6fa5 |
multipress_context = GTK_IM_CONTEXT_MULTIPRESS (data);
|
|
Packit Service |
fb6fa5 |
|
|
Packit Service |
fb6fa5 |
/* A certain amount of time has passed, so we will assume that the user
|
|
Packit Service |
fb6fa5 |
* really wants the currently chosen character */
|
|
Packit Service |
fb6fa5 |
accept_character (multipress_context, multipress_context->tentative_match);
|
|
Packit Service |
fb6fa5 |
|
|
Packit Service |
fb6fa5 |
multipress_context->timeout_id = 0;
|
|
Packit Service |
fb6fa5 |
|
|
Packit Service |
fb6fa5 |
GDK_THREADS_LEAVE ();
|
|
Packit Service |
fb6fa5 |
|
|
Packit Service |
fb6fa5 |
return FALSE; /* don't call me again */
|
|
Packit Service |
fb6fa5 |
}
|
|
Packit Service |
fb6fa5 |
|
|
Packit Service |
fb6fa5 |
static gboolean
|
|
Packit Service |
fb6fa5 |
vfunc_filter_keypress (GtkIMContext *context, GdkEventKey *event)
|
|
Packit Service |
fb6fa5 |
{
|
|
Packit Service |
fb6fa5 |
GtkIMContextClass *parent;
|
|
Packit Service |
fb6fa5 |
GtkImContextMultipress *multipress_context;
|
|
Packit Service |
fb6fa5 |
|
|
Packit Service |
fb6fa5 |
multipress_context = GTK_IM_CONTEXT_MULTIPRESS (context);
|
|
Packit Service |
fb6fa5 |
|
|
Packit Service |
fb6fa5 |
if (event->type == GDK_KEY_PRESS)
|
|
Packit Service |
fb6fa5 |
{
|
|
Packit Service |
fb6fa5 |
KeySequence *possible;
|
|
Packit Service |
fb6fa5 |
|
|
Packit Service |
fb6fa5 |
/* Check whether the current key is the same as previously entered, because
|
|
Packit Service |
fb6fa5 |
* if it is not then we should accept the previous one, and start a new
|
|
Packit Service |
fb6fa5 |
* character. */
|
|
Packit Service |
fb6fa5 |
if (multipress_context->compose_count > 0
|
|
Packit Service |
fb6fa5 |
&& multipress_context->key_last_entered != event->keyval
|
|
Packit Service |
fb6fa5 |
&& multipress_context->tentative_match != NULL)
|
|
Packit Service |
fb6fa5 |
{
|
|
Packit Service |
fb6fa5 |
/* Accept the previously chosen character. This wipes
|
|
Packit Service |
fb6fa5 |
* the compose_count and key_last_entered. */
|
|
Packit Service |
fb6fa5 |
accept_character (multipress_context,
|
|
Packit Service |
fb6fa5 |
multipress_context->tentative_match);
|
|
Packit Service |
fb6fa5 |
}
|
|
Packit Service |
fb6fa5 |
|
|
Packit Service |
fb6fa5 |
/* Decide what character this key press would choose: */
|
|
Packit Service |
fb6fa5 |
possible = g_hash_table_lookup (multipress_context->key_sequences,
|
|
Packit Service |
fb6fa5 |
GUINT_TO_POINTER (event->keyval));
|
|
Packit Service |
fb6fa5 |
if (possible != NULL)
|
|
Packit Service |
fb6fa5 |
{
|
|
Packit Service |
fb6fa5 |
if (multipress_context->compose_count == 0)
|
|
Packit Service |
fb6fa5 |
g_signal_emit_by_name (multipress_context, "preedit-start");
|
|
Packit Service |
fb6fa5 |
|
|
Packit Service |
fb6fa5 |
/* Check whether we are at the end of a compose sequence, with no more
|
|
Packit Service |
fb6fa5 |
* possible characters. Cycle back to the start if necessary. */
|
|
Packit Service |
fb6fa5 |
if (multipress_context->compose_count >= possible->n_characters)
|
|
Packit Service |
fb6fa5 |
multipress_context->compose_count = 0;
|
|
Packit Service |
fb6fa5 |
|
|
Packit Service |
fb6fa5 |
/* Store the last key pressed in the compose sequence. */
|
|
Packit Service |
fb6fa5 |
multipress_context->key_last_entered = event->keyval;
|
|
Packit Service |
fb6fa5 |
|
|
Packit Service |
fb6fa5 |
/* Get the possible match for this number of presses of the key.
|
|
Packit Service |
fb6fa5 |
* compose_count starts at 1, so that 0 can mean not composing. */
|
|
Packit Service |
fb6fa5 |
multipress_context->tentative_match =
|
|
Packit Service |
fb6fa5 |
possible->characters[multipress_context->compose_count++];
|
|
Packit Service |
fb6fa5 |
|
|
Packit Service |
fb6fa5 |
/* Indicate the current possible character. This will cause our
|
|
Packit Service |
fb6fa5 |
* vfunc_get_preedit_string() vfunc to be called, which will provide
|
|
Packit Service |
fb6fa5 |
* the current possible character for the user to see. */
|
|
Packit Service |
fb6fa5 |
g_signal_emit_by_name (multipress_context, "preedit-changed");
|
|
Packit Service |
fb6fa5 |
|
|
Packit Service |
fb6fa5 |
/* Cancel any outstanding timeout, so we can start the timer again: */
|
|
Packit Service |
fb6fa5 |
cancel_automatic_timeout_commit (multipress_context);
|
|
Packit Service |
fb6fa5 |
|
|
Packit Service |
fb6fa5 |
/* Create a timeout that will cause the currently chosen character to
|
|
Packit Service |
fb6fa5 |
* be committed, if nothing happens for a certain amount of time: */
|
|
Packit Service |
fb6fa5 |
multipress_context->timeout_id =
|
|
Packit Service |
fb6fa5 |
g_timeout_add_seconds (AUTOMATIC_COMPOSE_TIMEOUT,
|
|
Packit Service |
fb6fa5 |
&on_timeout, multipress_context);
|
|
Packit Service |
fb6fa5 |
|
|
Packit Service |
fb6fa5 |
return TRUE; /* key handled */
|
|
Packit Service |
fb6fa5 |
}
|
|
Packit Service |
fb6fa5 |
else
|
|
Packit Service |
fb6fa5 |
{
|
|
Packit Service |
fb6fa5 |
guint32 keyval_uchar;
|
|
Packit Service |
fb6fa5 |
|
|
Packit Service |
fb6fa5 |
/* Just accept all other keypresses directly, but commit the
|
|
Packit Service |
fb6fa5 |
* current preedit content first. */
|
|
Packit Service |
fb6fa5 |
if (multipress_context->compose_count > 0
|
|
Packit Service |
fb6fa5 |
&& multipress_context->tentative_match != NULL)
|
|
Packit Service |
fb6fa5 |
{
|
|
Packit Service |
fb6fa5 |
accept_character (multipress_context,
|
|
Packit Service |
fb6fa5 |
multipress_context->tentative_match);
|
|
Packit Service |
fb6fa5 |
}
|
|
Packit Service |
fb6fa5 |
keyval_uchar = gdk_keyval_to_unicode (event->keyval);
|
|
Packit Service |
fb6fa5 |
|
|
Packit Service |
fb6fa5 |
/* Convert to a string for accept_character(). */
|
|
Packit Service |
fb6fa5 |
if (keyval_uchar != 0)
|
|
Packit Service |
fb6fa5 |
{
|
|
Packit Service |
fb6fa5 |
/* max length of UTF-8 sequence = 6 + 1 for NUL termination */
|
|
Packit Service |
fb6fa5 |
gchar keyval_utf8[7];
|
|
Packit Service |
fb6fa5 |
gint length;
|
|
Packit Service |
fb6fa5 |
|
|
Packit Service |
fb6fa5 |
length = g_unichar_to_utf8 (keyval_uchar, keyval_utf8);
|
|
Packit Service |
fb6fa5 |
keyval_utf8[length] = '\0';
|
|
Packit Service |
fb6fa5 |
|
|
Packit Service |
fb6fa5 |
accept_character (multipress_context, keyval_utf8);
|
|
Packit Service |
fb6fa5 |
|
|
Packit Service |
fb6fa5 |
return TRUE; /* key handled */
|
|
Packit Service |
fb6fa5 |
}
|
|
Packit Service |
fb6fa5 |
}
|
|
Packit Service |
fb6fa5 |
}
|
|
Packit Service |
fb6fa5 |
|
|
Packit Service |
fb6fa5 |
parent = (GtkIMContextClass *)im_context_multipress_parent_class;
|
|
Packit Service |
fb6fa5 |
|
|
Packit Service |
fb6fa5 |
/* The default implementation just returns FALSE, but it is generally
|
|
Packit Service |
fb6fa5 |
* a good idea to call the base class implementation: */
|
|
Packit Service |
fb6fa5 |
if (parent->filter_keypress)
|
|
Packit Service |
fb6fa5 |
return (*parent->filter_keypress) (context, event);
|
|
Packit Service |
fb6fa5 |
|
|
Packit Service |
fb6fa5 |
return FALSE;
|
|
Packit Service |
fb6fa5 |
}
|
|
Packit Service |
fb6fa5 |
|
|
Packit Service |
fb6fa5 |
static void
|
|
Packit Service |
fb6fa5 |
vfunc_reset (GtkIMContext *context)
|
|
Packit Service |
fb6fa5 |
{
|
|
Packit Service |
fb6fa5 |
clear_compose_buffer (GTK_IM_CONTEXT_MULTIPRESS (context));
|
|
Packit Service |
fb6fa5 |
}
|
|
Packit Service |
fb6fa5 |
|
|
Packit Service |
fb6fa5 |
static void
|
|
Packit Service |
fb6fa5 |
vfunc_get_preedit_string (GtkIMContext *context,
|
|
Packit Service |
fb6fa5 |
gchar **str,
|
|
Packit Service |
fb6fa5 |
PangoAttrList **attrs,
|
|
Packit Service |
fb6fa5 |
gint *cursor_pos)
|
|
Packit Service |
fb6fa5 |
{
|
|
Packit Service |
fb6fa5 |
gsize len_bytes = 0;
|
|
Packit Service |
fb6fa5 |
gsize len_utf8_chars = 0;
|
|
Packit Service |
fb6fa5 |
|
|
Packit Service |
fb6fa5 |
/* Show the user what character he will get if he accepts: */
|
|
Packit Service |
fb6fa5 |
if (str != NULL)
|
|
Packit Service |
fb6fa5 |
{
|
|
Packit Service |
fb6fa5 |
const gchar *match;
|
|
Packit Service |
fb6fa5 |
|
|
Packit Service |
fb6fa5 |
match = GTK_IM_CONTEXT_MULTIPRESS (context)->tentative_match;
|
|
Packit Service |
fb6fa5 |
|
|
Packit Service |
fb6fa5 |
if (match == NULL)
|
|
Packit Service |
fb6fa5 |
match = ""; /* *str must not be NUL */
|
|
Packit Service |
fb6fa5 |
|
|
Packit Service |
fb6fa5 |
len_bytes = strlen (match); /* byte count */
|
|
Packit Service |
fb6fa5 |
len_utf8_chars = g_utf8_strlen (match, len_bytes); /* character count */
|
|
Packit Service |
fb6fa5 |
|
|
Packit Service |
fb6fa5 |
*str = g_strndup (match, len_bytes);
|
|
Packit Service |
fb6fa5 |
}
|
|
Packit Service |
fb6fa5 |
|
|
Packit Service |
fb6fa5 |
/* Underline it, to show the user that he is in compose mode: */
|
|
Packit Service |
fb6fa5 |
if (attrs != NULL)
|
|
Packit Service |
fb6fa5 |
{
|
|
Packit Service |
fb6fa5 |
*attrs = pango_attr_list_new ();
|
|
Packit Service |
fb6fa5 |
|
|
Packit Service |
fb6fa5 |
if (len_bytes > 0)
|
|
Packit Service |
fb6fa5 |
{
|
|
Packit Service |
fb6fa5 |
PangoAttribute *attr;
|
|
Packit Service |
fb6fa5 |
|
|
Packit Service |
fb6fa5 |
attr = pango_attr_underline_new (PANGO_UNDERLINE_SINGLE);
|
|
Packit Service |
fb6fa5 |
attr->start_index = 0;
|
|
Packit Service |
fb6fa5 |
attr->end_index = len_bytes;
|
|
Packit Service |
fb6fa5 |
pango_attr_list_insert (*attrs, attr);
|
|
Packit Service |
fb6fa5 |
}
|
|
Packit Service |
fb6fa5 |
}
|
|
Packit Service |
fb6fa5 |
|
|
Packit Service |
fb6fa5 |
if (cursor_pos)
|
|
Packit Service |
fb6fa5 |
*cursor_pos = len_utf8_chars;
|
|
Packit Service |
fb6fa5 |
}
|
|
Packit Service |
fb6fa5 |
|
|
Packit Service |
fb6fa5 |
/* Open the configuration file and fill in the key_sequences hash table
|
|
Packit Service |
fb6fa5 |
* with key/character-list pairs taken from the [keys] group of the file.
|
|
Packit Service |
fb6fa5 |
*/
|
|
Packit Service |
fb6fa5 |
static void
|
|
Packit Service |
fb6fa5 |
load_config (GtkImContextMultipress *self)
|
|
Packit Service |
fb6fa5 |
{
|
|
Packit Service |
fb6fa5 |
GKeyFile *key_file;
|
|
Packit Service |
fb6fa5 |
GError *error = NULL;
|
|
Packit Service |
fb6fa5 |
gchar **keys;
|
|
Packit Service |
fb6fa5 |
gsize n_keys = 0;
|
|
Packit Service |
fb6fa5 |
gsize i;
|
|
Packit Service |
fb6fa5 |
|
|
Packit Service |
fb6fa5 |
key_file = g_key_file_new ();
|
|
Packit Service |
fb6fa5 |
|
|
Packit Service |
fb6fa5 |
if (!g_key_file_load_from_file (key_file, CONFIGURATION_FILENAME,
|
|
Packit Service |
fb6fa5 |
G_KEY_FILE_NONE, &error))
|
|
Packit Service |
fb6fa5 |
{
|
|
Packit Service |
fb6fa5 |
g_warning ("Error while trying to open the %s configuration file: %s",
|
|
Packit Service |
fb6fa5 |
CONFIGURATION_FILENAME, error->message);
|
|
Packit Service |
fb6fa5 |
g_error_free (error);
|
|
Packit Service |
fb6fa5 |
g_key_file_free (key_file);
|
|
Packit Service |
fb6fa5 |
return;
|
|
Packit Service |
fb6fa5 |
}
|
|
Packit Service |
fb6fa5 |
|
|
Packit Service |
fb6fa5 |
keys = g_key_file_get_keys (key_file, "keys", &n_keys, &error);
|
|
Packit Service |
fb6fa5 |
|
|
Packit Service |
fb6fa5 |
if (error != NULL)
|
|
Packit Service |
fb6fa5 |
{
|
|
Packit Service |
fb6fa5 |
g_warning ("Error while trying to read the %s configuration file: %s",
|
|
Packit Service |
fb6fa5 |
CONFIGURATION_FILENAME, error->message);
|
|
Packit Service |
fb6fa5 |
g_error_free (error);
|
|
Packit Service |
fb6fa5 |
g_key_file_free (key_file);
|
|
Packit Service |
fb6fa5 |
return;
|
|
Packit Service |
fb6fa5 |
}
|
|
Packit Service |
fb6fa5 |
|
|
Packit Service |
fb6fa5 |
for (i = 0; i < n_keys; ++i)
|
|
Packit Service |
fb6fa5 |
{
|
|
Packit Service |
fb6fa5 |
KeySequence *seq;
|
|
Packit Service |
fb6fa5 |
guint keyval;
|
|
Packit Service |
fb6fa5 |
|
|
Packit Service |
fb6fa5 |
keyval = gdk_keyval_from_name (keys[i]);
|
|
Packit Service |
fb6fa5 |
|
|
Packit Service |
fb6fa5 |
if (keyval == GDK_VoidSymbol)
|
|
Packit Service |
fb6fa5 |
{
|
|
Packit Service |
fb6fa5 |
g_warning ("Error while trying to read the %s configuration file: "
|
|
Packit Service |
fb6fa5 |
"invalid key name \"%s\"",
|
|
Packit Service |
fb6fa5 |
CONFIGURATION_FILENAME, keys[i]);
|
|
Packit Service |
fb6fa5 |
continue;
|
|
Packit Service |
fb6fa5 |
}
|
|
Packit Service |
fb6fa5 |
|
|
Packit Service |
fb6fa5 |
seq = g_slice_new (KeySequence);
|
|
Packit Service |
fb6fa5 |
seq->characters = g_key_file_get_string_list (key_file, "keys", keys[i],
|
|
Packit Service |
fb6fa5 |
&seq->n_characters, &error);
|
|
Packit Service |
fb6fa5 |
if (error != NULL)
|
|
Packit Service |
fb6fa5 |
{
|
|
Packit Service |
fb6fa5 |
g_warning ("Error while trying to read the %s configuration file: %s",
|
|
Packit Service |
fb6fa5 |
CONFIGURATION_FILENAME, error->message);
|
|
Packit Service |
fb6fa5 |
g_error_free (error);
|
|
Packit Service |
fb6fa5 |
error = NULL;
|
|
Packit Service |
fb6fa5 |
g_slice_free (KeySequence, seq);
|
|
Packit Service |
fb6fa5 |
continue;
|
|
Packit Service |
fb6fa5 |
}
|
|
Packit Service |
fb6fa5 |
|
|
Packit Service |
fb6fa5 |
/* Ownership of the KeySequence is taken over by the hash table */
|
|
Packit Service |
fb6fa5 |
g_hash_table_insert (self->key_sequences, GUINT_TO_POINTER (keyval), seq);
|
|
Packit Service |
fb6fa5 |
}
|
|
Packit Service |
fb6fa5 |
|
|
Packit Service |
fb6fa5 |
g_strfreev (keys);
|
|
Packit Service |
fb6fa5 |
g_key_file_free (key_file);
|
|
Packit Service |
fb6fa5 |
}
|