summaryrefslogtreecommitdiffstats
path: root/client/gtk2/ibusimcontext.c
diff options
context:
space:
mode:
authorHuang Peng <shawn.p.huang@gmail.com>2008-08-16 12:51:47 +0800
committerHuang Peng <shawn.p.huang@gmail.com>2008-08-16 12:51:47 +0800
commit931f116d5fee25f22a48cf50b13323f3bd89180b (patch)
tree3bea5f8278717fd9552b008ffa21b01ef698da2f /client/gtk2/ibusimcontext.c
parent6a820938ed75a8c87ba223e248cba0d552bcb8b1 (diff)
downloadibus-931f116d5fee25f22a48cf50b13323f3bd89180b.tar.gz
ibus-931f116d5fee25f22a48cf50b13323f3bd89180b.tar.xz
ibus-931f116d5fee25f22a48cf50b13323f3bd89180b.zip
WIP.
Diffstat (limited to 'client/gtk2/ibusimcontext.c')
-rw-r--r--client/gtk2/ibusimcontext.c534
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");
+}