diff options
author | Huang Peng <shawn.p.huang@gmail.com> | 2008-08-16 12:51:47 +0800 |
---|---|---|
committer | Huang Peng <shawn.p.huang@gmail.com> | 2008-08-16 12:51:47 +0800 |
commit | 931f116d5fee25f22a48cf50b13323f3bd89180b (patch) | |
tree | 3bea5f8278717fd9552b008ffa21b01ef698da2f /client/gtk2/ibusimcontext.c | |
parent | 6a820938ed75a8c87ba223e248cba0d552bcb8b1 (diff) | |
download | ibus-931f116d5fee25f22a48cf50b13323f3bd89180b.tar.gz ibus-931f116d5fee25f22a48cf50b13323f3bd89180b.tar.xz ibus-931f116d5fee25f22a48cf50b13323f3bd89180b.zip |
WIP.
Diffstat (limited to 'client/gtk2/ibusimcontext.c')
-rw-r--r-- | client/gtk2/ibusimcontext.c | 534 |
1 files changed, 534 insertions, 0 deletions
diff --git a/client/gtk2/ibusimcontext.c b/client/gtk2/ibusimcontext.c new file mode 100644 index 0000000..1a14564 --- /dev/null +++ b/client/gtk2/ibusimcontext.c @@ -0,0 +1,534 @@ +/* vim:set et ts=4: */ +/* IBus - The Input Bus + * Copyright (C) 2008-2009 Huang Peng <shawn.p.huang@gmail.com> + * + * 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, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ +#include <gdk/gdkkeysyms.h> +#include <gdk/gdkx.h> +#include <sys/types.h> +#include <sys/socket.h> +#include <sys/time.h> +#include <sys/un.h> +#include "ibusimcontext.h" +#include "ibusimclient.h" + +/* IBusIMContextPriv */ +struct _IBusIMContextPrivate { + GtkIMContext *slave; + GdkWindow *client_window; + + /* enabled */ + gboolean enable; + gchar *ic; + + /* preedit status */ + gchar *preedit_string; + PangoAttrList *preedit_attrs; + gint preedit_cursor_pos; + gboolean preedit_visible; + + GdkRectangle cursor_area; + gboolean has_focus; +}; + + +/* functions prototype */ +static void ibus_im_context_class_init (IBusIMContextClass *klass); +static void ibus_im_context_init (IBusIMContext *obj); +static void ibus_im_context_finalize (GObject *obj); +static void ibus_im_context_reset (GtkIMContext *context); +static gboolean ibus_im_context_filter_keypress + (GtkIMContext *context, + GdkEventKey *key); +static void ibus_im_context_focus_in (GtkIMContext *context); +static void ibus_im_context_focus_out (GtkIMContext *context); +static void ibus_im_context_get_preedit_string + (GtkIMContext *context, + gchar **str, + PangoAttrList **attrs, + gint *cursor_pos); +static void ibus_im_context_set_client_window + (GtkIMContext *context, + GdkWindow *client); +static void ibus_im_context_set_cursor_location + (GtkIMContext *context, + GdkRectangle *area); +static void ibus_im_context_set_use_preedit + (GtkIMContext *context, + gboolean use_preedit); + +/* callback functions for slave context */ +static void _slave_commit_cb (GtkIMContext *slave, + gchar *string, + IBusIMContext *context); +static void _slave_preedit_changed_cb (GtkIMContext *slave, + IBusIMContext *context); +static void _slave_preedit_start_cb (GtkIMContext *slave, + IBusIMContext *context); +static void _slave_preedit_end_cb (GtkIMContext *slave, + IBusIMContext *context); +static void _slave_retrieve_surrounding_cb + (GtkIMContext *slave, + IBusIMContext *context); +static void _slave_delete_surrounding_cb + (GtkIMContext *slave, + gint arg1, + gint arg2, + IBusIMContext *context); + + + +static GType _ibus_type_im_context = 0; +static GtkIMContextClass *parent_class = NULL; + +void +ibus_im_context_register_type (GTypeModule *type_module) +{ + static const GTypeInfo ibus_im_context_info = { + sizeof (IBusIMContextClass), + (GBaseInitFunc) NULL, + (GBaseFinalizeFunc) NULL, + (GClassInitFunc) ibus_im_context_class_init, + NULL, /* class finialize */ + NULL, /* class data */ + sizeof (IBusIMContext), + 0, + (GInstanceInitFunc) ibus_im_context_init, + }; + + if (! _ibus_type_im_context ) { + if (type_module) { + _ibus_type_im_context = + g_type_module_register_type (type_module, + GTK_TYPE_IM_CONTEXT, + "IBusIMContext", + &ibus_im_context_info, + (GTypeFlags)0); + } + else { + _ibus_type_im_context = + g_type_register_static (GTK_TYPE_IM_CONTEXT, + "IBusIMContext", + &ibus_im_context_info, + (GTypeFlags)0); + } + } +} + +int +ibus_im_context_get_type (void) +{ + if (_ibus_type_im_context == 0) { + ibus_im_context_register_type (NULL); + } + + g_assert (_ibus_type_im_context != 0); + return _ibus_type_im_context; +} + +GtkIMContext * +ibus_im_context_new (void) +{ + IBusIMContext *obj; + + obj = IBUS_IM_CONTEXT(g_object_new (IBUS_TYPE_IM_CONTEXT, NULL)); + + return GTK_IM_CONTEXT(obj); +} + +static void +ibus_im_context_class_init (IBusIMContextClass *klass) +{ + GtkIMContextClass *im_context_class = GTK_IM_CONTEXT_CLASS (klass); + GObjectClass *gobject_class = G_OBJECT_CLASS (klass); + + parent_class = (GtkIMContextClass *) g_type_class_peek_parent (klass); + + g_type_class_add_private (klass, sizeof (IBusIMContextPrivate)); + + im_context_class->reset = ibus_im_context_reset; + im_context_class->focus_in = ibus_im_context_focus_in; + im_context_class->focus_out = ibus_im_context_focus_out; + im_context_class->filter_keypress = ibus_im_context_filter_keypress; + im_context_class->get_preedit_string = ibus_im_context_get_preedit_string; + im_context_class->set_client_window = ibus_im_context_set_client_window; + im_context_class->set_cursor_location = ibus_im_context_set_cursor_location; + im_context_class->set_use_preedit = ibus_im_context_set_use_preedit; + gobject_class->finalize = ibus_im_context_finalize; +} + +static void +ibus_im_context_init (IBusIMContext *obj) +{ + DEBUG_FUNCTION_IN; + + IBusIMContext *ibus = IBUS_IM_CONTEXT (obj); + IBusIMContextPrivate *priv = ibus->priv = + G_TYPE_INSTANCE_GET_PRIVATE (ibus, IBUS_TYPE_IM_CONTEXT, IBusIMContextPrivate); + + priv->client_window = NULL; + + // Init ibus status + priv->enable = FALSE; + + // Init preedit status + priv->preedit_string = NULL; + priv->preedit_attrs = NULL; + priv->preedit_cursor_pos = 0; + priv->preedit_visible = FALSE; + + // Init cursor area + priv->cursor_area.x = 0; + priv->cursor_area.y = 0; + priv->cursor_area.width = 0; + priv->cursor_area.height = 0; + + priv->has_focus = FALSE; + + + // Create slave im context + ibus->priv->slave = gtk_im_context_simple_new (); + g_signal_connect (ibus->priv->slave, + "commit", G_CALLBACK (_slave_commit_cb), obj); + g_signal_connect (ibus->priv->slave, + "preedit-start", G_CALLBACK (_slave_preedit_start_cb), obj); + g_signal_connect (ibus->priv->slave, + "preedit-end", G_CALLBACK (_slave_preedit_end_cb), obj); + g_signal_connect (ibus->priv->slave, + "preedit-changed", G_CALLBACK (_slave_preedit_changed_cb), obj); + g_signal_connect (ibus->priv->slave, + "retrieve-surrounding", G_CALLBACK (_slave_retrieve_surrounding_cb), obj); + g_signal_connect (ibus->priv->slave, + "delete-surrounding", G_CALLBACK (_slave_delete_surrounding_cb), obj); +} + +static void +ibus_im_context_finalize (GObject *obj) +{ + DEBUG_FUNCTION_IN; + + IBusIMContext *ibus = IBUS_IM_CONTEXT (obj); + IBusIMContextPrivate *priv = ibus->priv; + + ibus_im_client_release_im_context (_client, ibus); + + g_object_unref (priv->slave); + + if (priv->client_window) g_object_unref (priv->client_window); + // release preedit + if (priv->preedit_string) g_free (priv->preedit_string); + if (priv->preedit_attrs) pango_attr_list_unref (priv->preedit_attrs); + + G_OBJECT_CLASS(parent_class)->finalize (obj); +} + +static gboolean +ibus_im_context_filter_keypress (GtkIMContext *context, + GdkEventKey *event) +{ + DEBUG_FUNCTION_IN; + + IBusIMContext *ibus = IBUS_IM_CONTEXT (context); + IBusIMContextPrivate *priv = ibus->priv; + + if (ibus_im_client_filter_keypress (_client, ibus, event)) + return TRUE; + else + return gtk_im_context_filter_keypress (priv->slave, event); +} + +static void +ibus_im_context_focus_in (GtkIMContext *context) +{ + DEBUG_FUNCTION_IN; + + IBusIMContext *ibus = IBUS_IM_CONTEXT (context); + IBusIMContextPrivate *priv = ibus->priv; + + priv->has_focus = TRUE; + ibus_im_client_focus_in (_client, ibus); + gtk_im_context_focus_in (priv->slave); + + ibus_im_context_set_cursor_location(context, &priv->cursor_area); +} + +static void +ibus_im_context_focus_out (GtkIMContext *context) +{ + DEBUG_FUNCTION_IN; + + IBusIMContext *ibus = IBUS_IM_CONTEXT (context); + IBusIMContextPrivate *priv = ibus->priv; + + priv->has_focus = FALSE; + ibus_im_client_focus_out (_client, ibus); + gtk_im_context_focus_out (priv->slave); +} + +static void +ibus_im_context_reset (GtkIMContext *context) +{ + DEBUG_FUNCTION_IN; + + IBusIMContext *ibus = IBUS_IM_CONTEXT (context); + IBusIMContextPrivate *priv = ibus->priv; + + ibus_im_client_reset (_client, ibus); + gtk_im_context_reset (priv->slave); +} + + +static void +ibus_im_context_get_preedit_string (GtkIMContext *context, + gchar **str, + PangoAttrList **attrs, + gint *cursor_pos) +{ + DEBUG_FUNCTION_IN; + + IBusIMContext *ibus = IBUS_IM_CONTEXT (context); + IBusIMContextPrivate *priv = ibus->priv; + + if (priv->enable) { + if (priv->preedit_visible) { + if (str) { + *str = g_strdup (priv->preedit_string ? priv->preedit_string: ""); + } + + if (attrs) { + *attrs = priv->preedit_attrs ? + pango_attr_list_ref (priv->preedit_attrs): + pango_attr_list_new (); + } + + if (cursor_pos) { + *cursor_pos = priv->preedit_cursor_pos; + } + } + else { + if (str) *str = g_strdup (""); + if (attrs) *attrs = pango_attr_list_new (); + if (cursor_pos) *cursor_pos = 0; + } + } + else { + gtk_im_context_get_preedit_string (priv->slave, str, attrs, cursor_pos); + } +} + + +static void +ibus_im_context_set_client_window (GtkIMContext *context, GdkWindow *client) +{ + DEBUG_FUNCTION_IN; + + IBusIMContext *ibus = IBUS_IM_CONTEXT (context); + IBusIMContextPrivate *priv = ibus->priv; + + if (priv->client_window) + g_object_unref (priv->client_window); + if (client) + g_object_ref (client); + priv->client_window = client; + gtk_im_context_set_client_window (priv->slave, client); +} + +static void +ibus_im_context_set_cursor_location (GtkIMContext *context, GdkRectangle *area) +{ + DEBUG_FUNCTION_IN; + + IBusIMContext *ibus = IBUS_IM_CONTEXT (context); + IBusIMContextPrivate *priv = ibus->priv; + gint x, y; + + priv->cursor_area = *area; + + if(priv->client_window) { + gdk_window_get_origin (priv->client_window, &x, &y); + area->x += x; + area->y += y; + } + ibus_im_client_set_cursor_location (_client, ibus, area); + gtk_im_context_set_cursor_location (priv->slave, area); +} + +static void +ibus_im_context_set_use_preedit (GtkIMContext *context, gboolean use_preedit) +{ + DEBUG_FUNCTION_IN; + + IBusIMContext *ibus = IBUS_IM_CONTEXT (context); + IBusIMContextPrivate *priv = ibus->priv; + + ibus_im_client_set_use_preedit (_client, ibus, use_preedit); + gtk_im_context_set_use_preedit (priv->slave, use_preedit); +} + + +/* Callback functions for slave context */ +static void +_slave_commit_cb (GtkIMContext *slave, gchar *string, IBusIMContext *context) +{ + DEBUG_FUNCTION_IN; + + /* IBusIMContextPrivate *priv = context->priv; */ +#if 0 + if ((GtkIMContext *)context == CURRENT_CONTEXT && ibus_im_client_is_enabled (_client)) + return; +#endif + g_signal_emit_by_name (context, "commit", string); +} + +static void +_slave_preedit_changed_cb (GtkIMContext *slave, IBusIMContext *context) +{ + DEBUG_FUNCTION_IN; + IBusIMContextPrivate *priv = context->priv; + + if (priv->enable && priv->ic) + return; + + g_signal_emit_by_name (context, "preedit-changed"); +} + +static void +_slave_preedit_start_cb (GtkIMContext *slave, IBusIMContext *context) +{ + DEBUG_FUNCTION_IN; + IBusIMContextPrivate *priv = context->priv; + + if (priv->enable && priv->ic) + return; + g_signal_emit_by_name (context, "preedit-start"); +} + +static void +_slave_preedit_end_cb (GtkIMContext *slave, IBusIMContext *context) +{ + DEBUG_FUNCTION_IN; + IBusIMContextPrivate *priv = context->priv; + + if (priv->enable && priv->ic) + return; + g_signal_emit_by_name (context, "preedit-end"); +} + +static void +_slave_retrieve_surrounding_cb (GtkIMContext *slave, IBusIMContext *context) +{ + DEBUG_FUNCTION_IN; + IBusIMContextPrivate *priv = context->priv; + + if (priv->enable && priv->ic) + return; + g_signal_emit_by_name (context, "retrieve-surrounding"); +} + +static void +_slave_delete_surrounding_cb (GtkIMContext *slave, gint a1, gint a2, IBusIMContext *context) +{ + DEBUG_FUNCTION_IN; + IBusIMContextPrivate *priv = context->priv; + + if (priv->enable && priv->ic) + return; + g_signal_emit_by_name (context, "delete-surrounding", a1, a2); +} + +gchar * +ibus_im_context_get_ic (IBusIMContext *context) +{ + IBusIMContextPrivate *priv = context->priv; + return priv->ic; +} + +void +ibus_im_context_set_ic (IBusIMContext *context, const gchar *ic) +{ + IBusIMContextPrivate *priv = context->priv; + g_free (priv->ic); + + priv->ic = g_strdup (ic); + + if (priv->ic == NULL) { + priv->enable = FALSE; + } + else if (priv->has_focus) { + ibus_im_context_focus_in (GTK_IM_CONTEXT (context)); + } +} + +void +ibus_im_context_enable (IBusIMContext *context) +{ + IBusIMContextPrivate *priv = context->priv; + priv->enable = TRUE; +} + +void +ibus_im_context_disable (IBusIMContext *context) +{ + IBusIMContextPrivate *priv = context->priv; + priv->enable = FALSE; +} + + +void +ibus_im_context_commit_string (IBusIMContext *context, const gchar *string) +{ + g_signal_emit_by_name (context, "commit", string); +} + +void +ibus_im_context_update_preedit (IBusIMContext *context, const gchar *string, + PangoAttrList *attrs, gint cursor_pos, gboolean visible) +{ + IBusIMContextPrivate *priv = context->priv; + + priv->preedit_string = g_strdup (string); + priv->preedit_attrs = pango_attr_list_ref (attrs); + priv->preedit_cursor_pos = cursor_pos; + priv->preedit_visible = visible; + + g_signal_emit_by_name (context, "preedit-changed"); +} + +void +ibus_im_context_show_preedit (IBusIMContext *context) +{ + IBusIMContextPrivate *priv = context->priv; + if (priv->preedit_visible) + return; + + priv->preedit_visible = TRUE; + + g_signal_emit_by_name (context, "preedit-changed"); +} + +void +ibus_im_context_hide_preedit (IBusIMContext *context) +{ + IBusIMContextPrivate *priv = context->priv; + + if (!priv->preedit_visible) + return; + + priv->preedit_visible = FALSE; + + g_signal_emit_by_name (context, "preedit-changed"); +} |