Separate ic.
authorHuang Peng <shawn.p.huang@gmail.com>
Wed, 16 Jul 2008 08:53:51 +0000 (16:53 +0800)
committerHuang Peng <shawn.p.huang@gmail.com>
Wed, 16 Jul 2008 08:53:51 +0000 (16:53 +0800)
gtk2/ibusim.c
gtk2/ibusimclient.c
gtk2/ibusimclient.h
gtk2/ibusimcontext.c
gtk2/ibusimcontext.h

index 2445fc1..12de459 100644 (file)
@@ -9,7 +9,7 @@
  *
  * 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
+ * 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
 #include <string.h>
 #include <stdio.h>
 #include "ibusimclient.h"
-#include "ibusimcontext.h"
 
 #define IBUS_LOCALDIR ""
 
 static const GtkIMContextInfo ibus_im_info = {
-       "ibus",
-       "The Input Bus",
-       "ibus",
-       IBUS_LOCALDIR,
-       ""
+    "ibus",
+    "The Input Bus",
+    "ibus",
+    IBUS_LOCALDIR,
+    ""
 };
 
 static const GtkIMContextInfo * info_list[] = {
-       &ibus_im_info
+    &ibus_im_info
 };
 
+IBusIMClient *_client = NULL;
+
 void
 im_module_init (GTypeModule *type_module)
 {
-       ibus_im_client_register_type(type_module);
-       ibus_im_context_register_type(type_module);
+    ibus_im_client_register_type(type_module);
+    ibus_im_context_register_type(type_module);
+
+    _client = ibus_im_client_new ();
 }
 
 void
 im_module_exit (void)
 {
+    g_object_unref (_client);
 }
 
 GtkIMContext *
 im_module_create (const gchar *context_id)
 {
-       if (strcmp (context_id, "ibus") == 0)
-               return ibus_im_context_new ();
-       return NULL;
+    if (strcmp (context_id, "ibus") == 0)
+        return ibus_im_client_create_im_context (_client);
+    return NULL;
 }
 
 void
 im_module_list (const GtkIMContextInfo ***contexts,
                 int                      *n_contexts)
 {
-       *contexts = info_list;
-       *n_contexts = G_N_ELEMENTS (info_list);
+    *contexts = info_list;
+    *n_contexts = G_N_ELEMENTS (info_list);
 }
 
index 3f93158..7d5e542 100644 (file)
@@ -52,38 +52,25 @@ struct _IBusIMClientPrivate {
 #ifdef HAVE_INOTIFY
     /* inotify */
     gint            inotify_wd;
-    GIOChannel      *inotify_channel;
+    GIOChannel     *inotify_channel;
     guint           inotify_source;
 #endif
 
-    DBusConnection  *ibus;
-    gboolean         enable;
+    DBusConnection *ibus;
 
-    GtkIMContext    *context;
-    gchar           *ic;
-
-    /* preedit status */
-    gchar           *preedit_string;
-    PangoAttrList   *preedit_attrs;
-    gint             preedit_cursor;
-    gboolean         preedit_show;
+    GHashTable     *ic_table;
+    GList          *contexts;
 };
 
 /* functions prototype */
-static void     ibus_im_client_class_init   (IBusIMClientClass    *klass);
-static void     ibus_im_client_init         (IBusIMClient         *client);
-static void     ibus_im_client_finalize     (GObject             *obj);
-
-static void     ibus_im_client_commit_string(IBusIMClient         *client,
-                                            const gchar         *string);
-static void     ibus_im_client_update_preedit
-                                           (IBusIMClient         *client,
-                                            const gchar         *string,
-                                            PangoAttrList       *attrs,
-                                            gint                cursor_pos,
-                                            gboolean            show);
-
-static void     ibus_im_client_sync_hotkeys (IBusIMClient         *client);
+static void     ibus_im_client_class_init   (IBusIMClientClass  *klass);
+static void     ibus_im_client_init         (IBusIMClient       *client);
+static void     ibus_im_client_finalize     (GObject            *obj);
+
+static const gchar *
+                _ibus_im_client_create_input_context
+                                            (IBusIMClient       *client);
+
 static gboolean _ibus_call_with_reply_and_block
                                            (DBusConnection      *connection,
                                             const gchar         *method,
@@ -103,25 +90,28 @@ static gboolean _dbus_call_with_reply_and_block
                                             const gchar         *path,
                                             const gchar         *iface,
                                             const char          *method,
-                                            int                first_arg_type,
+                                            int                 first_arg_type,
                                                                 ...);
+static GtkIMContext *
+                _ibus_client_ic_to_context (IBusIMClient        *client,
+                                            const gchar         *ic);
 
 /* callback functions */
 static DBusHandlerResult
                 _ibus_im_client_message_filter_cb
-                                            (DBusConnection      *connection,
-                                             DBusMessage         *message,
-                                             void                *user_data);
+                                           (DBusConnection      *connection,
+                                            DBusMessage         *message,
+                                            void                *user_data);
 
-static void     _dbus_name_owner_changed_cb (DBusGProxy          *proxy,
-                                             const gchar         *name,
-                                             const gchar         *old_name,
-                                             const gchar         *new_name,
-                                             IBusIMClient         *client);
+static void     _dbus_name_owner_changed_cb
+                                           (DBusGProxy          *proxy,
+                                            const gchar         *name,
+                                            const gchar         *old_name,
+                                            const gchar         *new_name,
+                                            IBusIMClient        *client);
 
 static GType                ibus_type_im_client = 0;
 static GtkObjectClass       *parent_class = NULL;
-static IBusIMClient          *_client = NULL;
 static gboolean             has_focus = FALSE;
 
 
@@ -157,21 +147,15 @@ ibus_im_client_register_type (GTypeModule *type_module)
     }
 }
 
-
 IBusIMClient *
-ibus_im_client_get_client (void)
+ibus_im_client_new (void)
 {
-    if (_client == NULL) {
-        _client = IBUS_IM_CLIENT(g_object_new (IBUS_TYPE_IM_CLIENT, NULL));
-        g_object_ref_sink (_client);
-    }
-    else {
-        g_object_ref (_client);
-    }
+    IBusIMClient *client;
 
-    return _client;
-}
+    client = IBUS_IM_CLIENT(g_object_new (IBUS_TYPE_IM_CLIENT, NULL));
 
+    return client;
+}
 
 static void
 ibus_im_client_class_init     (IBusIMClientClass *klass)
@@ -221,7 +205,6 @@ _ibus_im_client_reinit_imm (IBusIMClient *client)
         return;
     }
 
-    ibus_im_client_sync_hotkeys (client);
     g_debug ("new imm %s", dbus_g_proxy_get_bus_name (priv->imm));
 }
 #endif
@@ -289,45 +272,69 @@ _ibus_im_client_ibus_open (IBusIMClient *client)
         return;
     }
     dbus_connection_setup_with_g_main (priv->ibus, NULL);
-    const gchar *app_name = g_get_application_name ();
-    gchar *ic = NULL;
-    _ibus_call_with_reply_and_block (priv->ibus, "CreateInputContext",
-                DBUS_TYPE_STRING, &app_name,
-                DBUS_TYPE_INVALID,
-                DBUS_TYPE_STRING, &ic,
-                DBUS_TYPE_INVALID);
-    priv->ic = g_strdup (ic);
+
+    GList *p;
+    for (p = priv->contexts; p != NULL; p = g_list_next (p)) {
+        IBusIMContext *ctx = IBUS_IM_CONTEXT (p->data);
+        const gchar *ic = _ibus_im_client_create_input_context (client);
+        ibus_im_context_set_ic (ctx, ic);
+    }
 
 }
 
 static void
 _ibus_im_client_ibus_close (IBusIMClient *client)
 {
-    DBusError error;
-
     IBusIMClientPrivate *priv = client->priv;
 
+    GList *p;
+    for (p = priv->contexts; p != NULL; p = g_list_next (p)) {
+        IBusIMContext *ctx = IBUS_IM_CONTEXT (p->data);
+        ibus_im_context_set_ic (ctx, NULL);
+    }
+
+    g_hash_table_remove_all (priv->ic_table);
+
     if (priv->ibus) {
         dbus_connection_close (priv->ibus);
         dbus_connection_unref (priv->ibus);
         priv->ibus = NULL;
     }
+}
 
-    if (priv->preedit_string) {
-        g_free (priv->preedit_string);
-        priv->preedit_string = NULL;
-    }
+IBusIMContext *
+ibus_im_client_create_im_context (IBusIMClient *client)
+{
+    IBusIMContext *context;
+    IBusIMClientPrivate *priv = client->priv;
 
-    if (priv->preedit_attrs) {
-        pango_attr_list_unref (priv->preedit_attrs);
-        priv->preedit_attrs = NULL;
-    }
+    context = IBUS_IM_CONTEXT (ibus_im_context_new ());
+    priv->contexts = g_list_append (priv->contexts, context);
 
-    if (priv->context) {
-        g_signal_emit_by_name (priv->context, "preedit-changed");
+    const gchar *ic = _ibus_im_client_create_input_context (client);
+    ibus_im_context_set_ic (context, ic);
+    if (ic) {
+        g_hash_table_insert (priv->ic_table, (gpointer)g_strdup (ic), context);
     }
+    return context;
+}
+
+static const gchar *
+_ibus_im_client_create_input_context (IBusIMClient *client)
+{
+    IBusIMClientPrivate *priv = client->priv;
+
+    if (priv->ibus == NULL)
+        return NULL;
 
-    priv->enable = FALSE;
+    const gchar *app_name = g_get_application_name ();
+    gchar *ic = NULL;
+    _ibus_call_with_reply_and_block (priv->ibus, "CreateInputContext",
+                DBUS_TYPE_STRING, &app_name,
+                DBUS_TYPE_INVALID,
+                DBUS_TYPE_STRING, &ic,
+                DBUS_TYPE_INVALID);
+    return ic;
 }
 
 #ifdef HAVE_INOTIFY
@@ -385,12 +392,8 @@ ibus_im_client_init (IBusIMClient *obj)
     priv = G_TYPE_INSTANCE_GET_PRIVATE (client, IBUS_TYPE_IM_CLIENT, IBusIMClientPrivate);
     client->priv = priv;
 
-    priv->context = NULL;
-
-    priv->preedit_string = NULL;
-    priv->preedit_attrs = NULL;
-    priv->preedit_cursor = 0;
-    priv->enable = FALSE;
+    priv->ic_table = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
+    priv->contexts = NULL;
 
     watch_path = g_strdup_printf ("/tmp/ibus-%s", g_get_user_name ());
 
@@ -513,54 +516,31 @@ ibus_im_client_finalize (GObject *obj)
 }
 
 
-void
-ibus_im_client_set_im_context (IBusIMClient *client, GtkIMContext *context)
-{
-    IBusIMClientPrivate *priv = client->priv;
-    priv->context = context;
-}
-
-GtkIMContext *
-ibus_im_client_get_im_context (IBusIMClient *client)
-{
-    IBusIMClientPrivate *priv = client->priv;
-    return priv->context;
-}
-
 static void
-ibus_im_client_commit_string (IBusIMClient *client, const gchar *string)
+ibus_im_client_commit_string (IBusIMClient *client, const gchar *ic, const gchar *string)
 {
     IBusIMClientPrivate *priv = client->priv;
+    IBusIMContext *context = g_hash_table_lookup (priv->ic_table, (gpointer)ic);
 
-    if (priv->context) {
-        g_signal_emit_by_name (priv->context, "commit", string);
+    if (context == NULL) {
+        g_debug ("Can not find context assocate with ic(%s)", ic);
+        return;
     }
+    g_signal_emit_by_name (G_OBJECT (context), "commit", string);
 }
 
 static void
-ibus_im_client_update_preedit (IBusIMClient *client, const gchar *string,
+ibus_im_client_update_preedit (IBusIMClient *client, const gchar *ic, const gchar *string,
         PangoAttrList *attrs, gint cursor_pos, gboolean show)
 {
     IBusIMClientPrivate *priv = client->priv;
-    if (priv->preedit_string) {
-        g_free (priv->preedit_string);
-    }
-    priv->preedit_string =  g_strdup (string);
-
-    if (priv->preedit_attrs) {
-        pango_attr_list_unref (priv->preedit_attrs);
-    }
-
-    priv->preedit_attrs = attrs;
-    if (attrs) {
-        pango_attr_list_ref (priv->preedit_attrs);
-    }
+    IBusIMContext *context = g_hash_table_lookup (priv->ic_table, (gpointer)ic);
 
-    priv->preedit_cursor = cursor_pos;
-    priv->preedit_show = show;
-    if (priv->context) {
-        g_signal_emit_by_name (priv->context, "preedit-changed");
+    if (context == NULL) {
+        g_debug ("Can not find context assocate with ic(%s)", ic);
+        return;
     }
+    ibus_im_context_update_preedit (context, string, attrs, cursor_pos, show);
 }
 
 static void
@@ -580,11 +560,12 @@ _ibus_signal_commit_string_handler (DBusConnection *connection, DBusMessage *mes
         dbus_error_free (&error);
     }
     else {
-        if (g_strcmp0 (priv->ic, ic) != 0) {
-            g_warning ("ic is wrong!");
+        IBusIMContext *context = g_hash_table_lookup (priv->ic_table, (gpointer)ic);
+        if (context == NULL) {
+            g_debug ("Can not find context assocate with ic(%s)", ic);
             return;
         }
-        ibus_im_client_commit_string (client, string);
+        ibus_im_context_commit_string (context, string);
     }
 }
 
@@ -616,11 +597,6 @@ _ibus_signal_update_preedit_handler (DBusConnection *connection, DBusMessage *me
     dbus_message_iter_get_basic (&iter, &ic);
     dbus_message_iter_next (&iter);
 
-    if (g_strcmp0 (priv->ic, ic) != 0) {
-        g_warning ("ic is wrong!");
-        return;
-    }
-
     type = dbus_message_iter_get_arg_type (&iter);
     if (type != DBUS_TYPE_STRING) {
         g_warning ("The 2nd argument of UpdatePreedit signal must be a String");
@@ -717,7 +693,14 @@ _ibus_signal_update_preedit_handler (DBusConnection *connection, DBusMessage *me
     dbus_message_iter_get_basic (&iter, &show);
     dbus_message_iter_next (&iter);
 
-    ibus_im_client_update_preedit (client, string, attrs, cursor, show);
+    {
+        IBusIMContext *context = g_hash_table_lookup (priv->ic_table, (gpointer)ic);
+        if (context == NULL) {
+            g_debug ("Can not find context assocate with ic(%s)", ic);
+            return;
+        }
+        ibus_im_context_update_preedit (context, string, attrs, cursor, show);
+    }
     pango_attr_list_unref (attrs);
 
 }
@@ -765,7 +748,25 @@ static void
 _ibus_signal_enabled_handler (DBusConnection *connection, DBusMessage *message, IBusIMClient *client)
 {
     DEBUG_FUNCTION_IN;
-    client->priv->enable = TRUE;
+    /* Handle CommitString signal */
+    IBusIMClientPrivate *priv = client->priv;
+    DBusError error = {0};
+    gchar *ic = NULL;
+
+    if (!dbus_message_get_args (message, &error,
+            DBUS_TYPE_STRING, &ic,
+            DBUS_TYPE_INVALID)) {
+        g_warning ("%s", error.message);
+        dbus_error_free (&error);
+    }
+    else {
+        IBusIMContext *context = g_hash_table_lookup (priv->ic_table, (gpointer)ic);
+        if (context == NULL) {
+            g_debug ("Can not find context assocate with ic(%s)", ic);
+            return;
+        }
+        ibus_im_context_enable (context);
+    }
 }
 
 
@@ -773,8 +774,28 @@ static void
 _ibus_signal_disabled_handler (DBusConnection *connection, DBusMessage *message, IBusIMClient *client)
 {
     DEBUG_FUNCTION_IN;
-    client->priv->enable = FALSE;
+    /* Handle CommitString signal */
+    IBusIMClientPrivate *priv = client->priv;
+    DBusError error = {0};
+    gchar *ic = NULL;
+
+    if (!dbus_message_get_args (message, &error,
+            DBUS_TYPE_STRING, &ic,
+            DBUS_TYPE_INVALID)) {
+        g_warning ("%s", error.message);
+        dbus_error_free (&error);
+    }
+    else {
+        IBusIMContext *context = g_hash_table_lookup (priv->ic_table, (gpointer)ic);
+        if (context == NULL) {
+            g_debug ("Can not find context assocate with ic(%s)", ic);
+            return;
+        }
+        ibus_im_context_disable (context);
+    }
 }
+
+
 static DBusHandlerResult
 _ibus_im_client_message_filter_cb (DBusConnection *connection, DBusMessage *message, void *user_data)
 {
@@ -1048,9 +1069,11 @@ _ibus_filter_keypress_reply_cb (DBusPendingCall *pending, void *user_data)
 }
 
 gboolean
-ibus_im_client_filter_keypress (IBusIMClient *client, GdkEventKey *event)
+ibus_im_client_filter_keypress (IBusIMClient *client, IBusIMContext *context, GdkEventKey *event)
 {
     IBusIMClientPrivate *priv = client->priv;
+    gchar *ic = ibus_im_context_get_ic (context);
+    g_return_val_if_fail (ic != NULL, FALSE);
 
     guint state = event->state & GDK_MODIFIER_MASK;
     gboolean is_press = event->type == GDK_KEY_PRESS;
@@ -1065,7 +1088,7 @@ ibus_im_client_filter_keypress (IBusIMClient *client, GdkEventKey *event)
             _ibus_filter_keypress_reply_cb,
             gdk_event_copy ((GdkEvent *)event),
             (DBusFreeFunction)gdk_event_free,
-            DBUS_TYPE_STRING, &priv->ic,
+            DBUS_TYPE_STRING, &ic,
             DBUS_TYPE_UINT32, &event->keyval,
             DBUS_TYPE_BOOLEAN, &is_press,
             DBUS_TYPE_UINT32, &state,
@@ -1077,96 +1100,62 @@ ibus_im_client_filter_keypress (IBusIMClient *client, GdkEventKey *event)
 
 
 void
-ibus_im_client_focus_in (IBusIMClient *client)
+ibus_im_client_focus_in (IBusIMClient *client, IBusIMContext *context)
 {
     IBusIMClientPrivate *priv = client->priv;
+    gchar *ic = ibus_im_context_get_ic (context);
+    g_return_if_fail (ic != NULL);
+
     /* Call IBus FocusIn method */
-     _ibus_call_with_reply_and_block (client->priv->ibus,
+     _ibus_call_with_reply_and_block (priv->ibus,
             "FocusIn",
-            DBUS_TYPE_STRING, &priv->ic,
+            DBUS_TYPE_STRING, &ic,
             DBUS_TYPE_INVALID,
             DBUS_TYPE_INVALID);
 }
 
 void
-ibus_im_client_focus_out (IBusIMClient *client)
+ibus_im_client_focus_out (IBusIMClient *client, IBusIMContext *context)
 {
     IBusIMClientPrivate *priv = client->priv;
+    gchar *ic = ibus_im_context_get_ic (context);
+    g_return_if_fail (ic != NULL);
+
     /* Call IBus FocusOut method */
-    _ibus_call_with_reply_and_block (client->priv->ibus,
+    _ibus_call_with_reply_and_block (priv->ibus,
             "FocusOut",
-            DBUS_TYPE_STRING, &priv->ic,
+            DBUS_TYPE_STRING, &ic,
             DBUS_TYPE_INVALID,
             DBUS_TYPE_INVALID);
 
 }
 
 void
-ibus_im_client_reset (IBusIMClient *client)
+ibus_im_client_reset (IBusIMClient *client, IBusIMContext *context)
 {
     IBusIMClientPrivate *priv = client->priv;
+    gchar *ic = ibus_im_context_get_ic (context);
+    g_return_if_fail (ic != NULL);
+
     /* Call IBus Reset method */
-    _ibus_call_with_reply_and_block (client->priv->ibus,
+    _ibus_call_with_reply_and_block (priv->ibus,
             "Reset",
-            DBUS_TYPE_STRING, &priv->ic,
+            DBUS_TYPE_STRING, &ic,
             DBUS_TYPE_INVALID,
             DBUS_TYPE_INVALID);
 
 }
 
-
-gboolean
-ibus_im_client_get_preedit_string (
-    IBusIMClient *client,
-    gchar         **str,
-    PangoAttrList **attrs,
-    gint           *cursor_pos
-)
-{
-    IBusIMClientPrivate *priv = client->priv;
-
-    if (!priv->preedit_show) {
-        if (str) *str = g_strdup ("");
-        if (attrs) *attrs = pango_attr_list_new ();
-        if (cursor_pos) *cursor_pos = 0;
-        return TRUE;
-    }
-
-    if (str) {
-        *str = g_strdup (priv->preedit_string ? priv->preedit_string: "");
-    }
-
-    if (attrs) {
-        if (priv->preedit_attrs) {
-            *attrs = pango_attr_list_ref (priv->preedit_attrs);
-        }
-        else {
-            *attrs = pango_attr_list_new ();
-        }
-    }
-
-    if (cursor_pos) {
-        *cursor_pos = priv->preedit_cursor;
-    }
-
-    return TRUE;
-}
-
-
 void
-ibus_im_client_set_client_window  (IBusIMClient *client, GdkWindow *window)
-{
-    IBusIMClientPrivate *priv = client->priv;
-}
-
-void
-ibus_im_client_set_cursor_location (IBusIMClient *client, GdkRectangle *area)
+ibus_im_client_set_cursor_location (IBusIMClient *client, IBusIMContext *context, GdkRectangle *area)
 {
     IBusIMClientPrivate *priv = client->priv;
+    gchar *ic = ibus_im_context_get_ic (context);
+    g_return_if_fail (ic != NULL);
 
     _ibus_call_with_reply_and_block (client->priv->ibus,
             "SetCursorLocation",
-            DBUS_TYPE_STRING, &priv->ic,
+            DBUS_TYPE_STRING, &ic,
             DBUS_TYPE_INT32, &area->x,
             DBUS_TYPE_INT32, &area->y,
             DBUS_TYPE_INT32, &area->width,
@@ -1176,43 +1165,22 @@ ibus_im_client_set_cursor_location (IBusIMClient *client, GdkRectangle *area)
 }
 
 
-gboolean
-ibus_im_client_is_enabled (IBusIMClient *client)
-{
-    return (client->priv->ibus != NULL) && (client->priv->enable);
-}
-
-static void
-ibus_im_client_sync_hotkeys (IBusIMClient *client)
+void
+ibus_im_client_release_im_context (IBusIMClient *client, IBusIMContext *context)
 {
-    GError *error;
-    gchar **hotkeys = NULL;
-    gint i;
-
     IBusIMClientPrivate *priv = client->priv;
-#if 0
-    g_return_if_fail (priv->imm != NULL);
-
-    error = NULL;
-    if (!dbus_g_proxy_call (priv->imm, "get_hotkeys", &error,
-                            G_TYPE_INVALID,
-                            G_TYPE_STRV, &hotkeys,
-                            G_TYPE_INVALID)) {
-        if (error) {
-            g_warning ("%s", error->message);
-            g_error_free (error);
-        }
-        return;
-    }
+    gchar *ic = ibus_im_context_get_ic (context);
+    priv->contexts = g_list_remove (priv->contexts, context);
+    if (ic) {
+        g_hash_table_remove (priv->ic_table, ic);
+        _ibus_call_with_reply_and_block (priv->ibus, "ReleaseInputContext",
+                DBUS_TYPE_STRING, &ic,
+                DBUS_TYPE_INVALID,
+                DBUS_TYPE_INVALID);
 
-    for (i = 0; i < g_strv_length (hotkeys); i++) {
-        g_debug ("hotkeys[%d] = %s", i, hotkeys[i]);
     }
-    g_strfreev (hotkeys);
-#endif
 
 }
-
 /* Callback functions for slave context */
 #if 0
 static void
index 48489d2..9ae8a3e 100644 (file)
@@ -21,7 +21,7 @@
 #define __IBUS_IM_CLIENT_H_
 
 #include <gtk/gtk.h>
-
+#include "ibusimcontext.h"
 /*
  * Type macros.
  */
@@ -42,7 +42,7 @@
 
 #if 0
 #define DEBUG_FUNCTION_IN   g_debug("%s IN", __FUNCTION__);
-#define DEBUG_FUNCTION_OUT   g_debug("%s OUT", __FUNCTION__);
+#define DEBUG_FUNCTION_OUT  g_debug("%s OUT", __FUNCTION__);
 #else
 #define DEBUG_FUNCTION_IN
 #define DEBUG_FUNCTION_OUT
@@ -70,27 +70,29 @@ struct _IBusIMClientClass {
   /* class members */
 };
 
+extern IBusIMClient                *_client;
+
 GType           ibus_im_client_get_type          (void);
-IBusIMClient     *ibus_im_client_get_client       (void);
-void            ibus_im_client_register_type     (GTypeModule    *type_module);
+void            ibus_im_client_register_type     (GTypeModule     *type_module);
+IBusIMClient   *ibus_im_client_new               (void);
+IBusIMContext  *ibus_im_client_create_im_context (IBusIMClient    *client);
 void            ibus_im_client_shutdown          (void);
-void            ibus_im_client_focus_in          (IBusIMClient    *client);
-void            ibus_im_client_focus_out         (IBusIMClient    *client);
-void            ibus_im_client_set_im_context    (IBusIMClient    *client,
-                                                 GtkIMContext   *context);
-GtkIMContext   *ibus_im_client_get_im_context    (IBusIMClient    *client);
-void            ibus_im_client_reset             (IBusIMClient    *client);
+void            ibus_im_client_focus_in          (IBusIMClient    *client,
+                                                  IBusIMContext   *context);
+void            ibus_im_client_focus_out         (IBusIMClient    *client,
+                                                  IBusIMContext   *context);
+void            ibus_im_client_reset             (IBusIMClient    *client,
+                                                  IBusIMContext   *context);
 gboolean        ibus_im_client_filter_keypress   (IBusIMClient    *client,
-                                                 GdkEventKey    *key);
-gboolean        ibus_im_client_get_preedit_string
-                                                (IBusIMClient    *client,
-                                                 gchar          **str,
-                                                 PangoAttrList  **attrs,
-                                                 gint           *cursor_pos);
+                                                  IBusIMContext   *context,
+                                                  GdkEventKey     *key);
 void            ibus_im_client_set_cursor_location
-                                                (IBusIMClient    *client,
-                                                 GdkRectangle   *area);
+                                                 (IBusIMClient    *client,
+                                                  IBusIMContext   *context,
+                                                  GdkRectangle    *area);
 gboolean        ibus_im_client_is_enabled        (IBusIMClient    *client);
+void            ibus_im_client_release_im_context(IBusIMClient    *client,
+                                                  IBusIMContext   *context);
 
 
 G_END_DECLS
index 5b9c089..abf236b 100644 (file)
 #include "ibusimcontext.h"
 #include "ibusimclient.h"
 
-/* define GOBJECT macros */
-#define IBUS_TYPE_IM_CONTEXT             \
-    (_ibus_type_im_context)
-#define IBUS_IM_CONTEXT(obj)             \
-    (GTK_CHECK_CAST ((obj), IBUS_TYPE_IM_CONTEXT, IBusIMContext))
-#define IBUS_IM_CONTEXT_CLASS(klass)     \
-    (GTK_CHECK_CLASS_CAST ((klass), IBUS_TYPE_IM_CONTEXT, IBusIMContextClass))
-#define IBUS_IS_IM_CONTEXT(obj)          \
-    (GTK_CHECK_TYPE ((obj), IBUS_TYPE_IM_CONTEXT))
-#define IBUS_IS_IM_CONTEXT_CLASS(klass)  \
-    (GTK_CHECK_CLASS_TYPE ((klass), IBUS_TYPE_IM_CONTEXT))
-#define IBUS_IM_CONTEXT_GET_CLASS(obj)   \
-    (GTK_CHECK_GET_CLASS ((obj), IBUS_TYPE_IM_CONTEXT, IBusIMContextClass))
-
-#define CURRENT_CONTEXT (ibus_im_client_get_im_context (priv->client))
-
 /* IBusIMContextPriv */
 struct _IBusIMContextPrivate {
     GtkIMContext *slave;
-    IBusIMClient *client;
     GdkWindow *client_window;
+
+    /* enabled */
+    gboolean        enable;
+    gchar           *ic;
+
+    /* preedit status */
+    gchar           *preedit_string;
+    PangoAttrList   *preedit_attrs;
+    gint             preedit_cursor_pos;
+    gboolean         preedit_visible;
 };
 
 
@@ -93,7 +86,7 @@ static void     _slave_delete_surrounding_cb
 
 
 
-static GType                _ibus_type_im_context = 0;
+GType                _ibus_type_im_context = 0;
 static GtkIMContextClass    *parent_class = NULL;
 
 void
@@ -158,10 +151,20 @@ ibus_im_context_init     (IBusIMContext *obj)
 
     GError *error;
     IBusIMContext *ibus = IBUS_IM_CONTEXT (obj);
-    ibus->priv = G_TYPE_INSTANCE_GET_PRIVATE (ibus, IBUS_TYPE_IM_CONTEXT, IBusIMContextPrivate);
+    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;
 
-    ibus->priv->client = ibus_im_client_get_client ();
-    ibus->priv->client_window = NULL;
 
     // Create slave im context
     ibus->priv->slave = gtk_im_context_simple_new ();
@@ -187,13 +190,13 @@ ibus_im_context_finalize (GObject *obj)
     IBusIMContext *ibus = IBUS_IM_CONTEXT (obj);
     IBusIMContextPrivate *priv = ibus->priv;
 
-    if (GTK_IM_CONTEXT (ibus) == CURRENT_CONTEXT) {
-        ibus_im_client_focus_out (priv->client);
-        ibus_im_client_set_im_context (priv->client, NULL);
-    }
+    ibus_im_client_release_im_context (_client, ibus);
 
     g_object_unref (priv->slave);
-    g_object_unref (priv->client);
+
+    // 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);
 }
@@ -207,12 +210,10 @@ ibus_im_context_filter_keypress (GtkIMContext *context,
     IBusIMContext *ibus = IBUS_IM_CONTEXT (context);
     IBusIMContextPrivate *priv = ibus->priv;
 
-    if (context != CURRENT_CONTEXT)
-        return FALSE;
-
-    if (ibus_im_client_filter_keypress (priv->client, event))
+    if (ibus_im_client_filter_keypress (_client, ibus, event))
         return TRUE;
-    return gtk_im_context_filter_keypress (priv->slave, event);
+    else
+        return gtk_im_context_filter_keypress (priv->slave, event);
 }
 
 static void
@@ -223,12 +224,7 @@ ibus_im_context_focus_in (GtkIMContext *context)
     IBusIMContext *ibus = IBUS_IM_CONTEXT (context);
     IBusIMContextPrivate *priv = ibus->priv;
 
-    if (context != CURRENT_CONTEXT) {
-        ibus_im_client_focus_out (priv->client);
-        ibus_im_client_set_im_context (priv->client, context);
-    }
-
-    ibus_im_client_focus_in (priv->client);
+    ibus_im_client_focus_in (_client, ibus);
     gtk_im_context_focus_in (priv->slave);
 }
 
@@ -240,7 +236,7 @@ ibus_im_context_focus_out (GtkIMContext *context)
     IBusIMContext *ibus = IBUS_IM_CONTEXT (context);
     IBusIMContextPrivate *priv = ibus->priv;
 
-    ibus_im_client_focus_out (priv->client);
+    ibus_im_client_focus_out (_client, ibus);
     gtk_im_context_focus_out (priv->slave);
 }
 
@@ -252,9 +248,7 @@ ibus_im_context_reset (GtkIMContext *context)
     IBusIMContext *ibus = IBUS_IM_CONTEXT (context);
     IBusIMContextPrivate *priv = ibus->priv;
 
-    if (context == CURRENT_CONTEXT) {
-        ibus_im_client_reset (priv->client);
-    }
+    ibus_im_client_reset (_client, ibus);
     gtk_im_context_reset (priv->slave);
 }
 
@@ -270,12 +264,31 @@ ibus_im_context_get_preedit_string (GtkIMContext   *context,
     IBusIMContext *ibus = IBUS_IM_CONTEXT (context);
     IBusIMContextPrivate *priv = ibus->priv;
 
-    if (context == CURRENT_CONTEXT &&
-        ibus_im_client_is_enabled (priv->client)) {
-        ibus_im_client_get_preedit_string (priv->client, str, attrs, cursor_pos);
-        return;
+    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);
     }
-    gtk_im_context_get_preedit_string (ibus->priv->slave, str, attrs, cursor_pos);
 }
 
 
@@ -286,8 +299,9 @@ ibus_im_context_set_client_window  (GtkIMContext *context, GdkWindow *client)
 
     IBusIMContext *ibus = IBUS_IM_CONTEXT (context);
     IBusIMContextPrivate *priv = ibus->priv;
+
     priv->client_window = client;
-    gtk_im_context_set_client_window (ibus->priv->slave, client);
+    gtk_im_context_set_client_window (priv->slave, client);
 }
 
 static void
@@ -297,7 +311,8 @@ ibus_im_context_set_cursor_location (GtkIMContext *context, GdkRectangle *area)
 
     IBusIMContext *ibus = IBUS_IM_CONTEXT (context);
     IBusIMContextPrivate *priv = ibus->priv;
-    if (context == CURRENT_CONTEXT && ibus_im_client_is_enabled (priv->client)) {
+
+    if (priv->enable) {
         /* It is the focused context */
         gint x, y;
         if(priv->client_window) {
@@ -305,7 +320,7 @@ ibus_im_context_set_cursor_location (GtkIMContext *context, GdkRectangle *area)
             area->x += x;
             area->y += y;
         }
-        ibus_im_client_set_cursor_location (priv->client, area);
+        ibus_im_client_set_cursor_location (_client, ibus, area);
     }
     gtk_im_context_set_cursor_location (priv->slave, area);
 }
@@ -318,7 +333,7 @@ _slave_commit_cb (GtkIMContext *slave, gchar *string, IBusIMContext *context)
 
     IBusIMContextPrivate *priv = context->priv;
 #if 0
-    if ((GtkIMContext *)context == CURRENT_CONTEXT && ibus_im_client_is_enabled (priv->client))
+    if ((GtkIMContext *)context == CURRENT_CONTEXT && ibus_im_client_is_enabled (_client))
         return;
 #endif
     g_signal_emit_by_name (context, "commit", string);
@@ -329,8 +344,10 @@ _slave_preedit_changed_cb (GtkIMContext *slave, IBusIMContext *context)
 {
     DEBUG_FUNCTION_IN;
     IBusIMContextPrivate *priv = context->priv;
-    if ((GtkIMContext *)context == CURRENT_CONTEXT && ibus_im_client_is_enabled (priv->client))
+
+    if (priv->enable && priv->ic)
         return;
+
     g_signal_emit_by_name (context, "preedit-changed");
 }
 
@@ -339,7 +356,8 @@ _slave_preedit_start_cb (GtkIMContext *slave, IBusIMContext *context)
 {
     DEBUG_FUNCTION_IN;
     IBusIMContextPrivate *priv = context->priv;
-    if ((GtkIMContext *)context == CURRENT_CONTEXT && ibus_im_client_is_enabled (priv->client))
+
+    if (priv->enable && priv->ic)
         return;
     g_signal_emit_by_name (context, "preedit-start");
 }
@@ -349,7 +367,8 @@ _slave_preedit_end_cb (GtkIMContext *slave, IBusIMContext *context)
 {
     DEBUG_FUNCTION_IN;
     IBusIMContextPrivate *priv = context->priv;
-    if ((GtkIMContext *)context == CURRENT_CONTEXT && ibus_im_client_is_enabled (priv->client))
+
+    if (priv->enable && priv->ic)
         return;
     g_signal_emit_by_name (context, "preedit-end");
 }
@@ -359,7 +378,8 @@ _slave_retrieve_surrounding_cb (GtkIMContext *slave, IBusIMContext *context)
 {
     DEBUG_FUNCTION_IN;
     IBusIMContextPrivate *priv = context->priv;
-    if ((GtkIMContext *)context == CURRENT_CONTEXT && ibus_im_client_is_enabled (priv->client))
+
+    if (priv->enable && priv->ic)
         return;
     g_signal_emit_by_name (context, "retrieve-surrounding");
 }
@@ -369,8 +389,58 @@ _slave_delete_surrounding_cb (GtkIMContext *slave, gint a1, gint a2, IBusIMConte
 {
     DEBUG_FUNCTION_IN;
     IBusIMContextPrivate *priv = context->priv;
-    if ((GtkIMContext *)context == CURRENT_CONTEXT && ibus_im_client_is_enabled (priv->client))
+
+    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;
+    if (priv->ic) g_free (priv->ic);
+    priv->ic = g_strdup (ic);
+}
+
+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 show)
+{
+    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 = show;
+
+    g_signal_emit_by_name (context, "preedit-changed");
+}
index 074d1e6..9c6b5f2 100644 (file)
 /*
  * Type macros.
  */
+#define IBUS_TYPE_IM_CONTEXT             \
+    (_ibus_type_im_context)
+#define IBUS_IM_CONTEXT(obj)             \
+    (GTK_CHECK_CAST ((obj), IBUS_TYPE_IM_CONTEXT, IBusIMContext))
+#define IBUS_IM_CONTEXT_CLASS(klass)     \
+    (GTK_CHECK_CLASS_CAST ((klass), IBUS_TYPE_IM_CONTEXT, IBusIMContextClass))
+#define IBUS_IS_IM_CONTEXT(obj)          \
+    (GTK_CHECK_TYPE ((obj), IBUS_TYPE_IM_CONTEXT))
+#define IBUS_IS_IM_CONTEXT_CLASS(klass)  \
+    (GTK_CHECK_CLASS_TYPE ((klass), IBUS_TYPE_IM_CONTEXT))
+#define IBUS_IM_CONTEXT_GET_CLASS(obj)   \
+    (GTK_CHECK_GET_CLASS ((obj), IBUS_TYPE_IM_CONTEXT, IBusIMContextClass))
 
 G_BEGIN_DECLS
 typedef struct _IBusIMContext IBusIMContext;
@@ -42,10 +54,28 @@ struct _IBusIMContextClass {
   /* class members */
 };
 
-GtkIMContext *ibus_im_context_new (void);
-void ibus_im_context_register_type (GTypeModule *type_module);
-void ibus_im_context_shutdown (void);
+extern GType                _ibus_type_im_context;
 
+GtkIMContext
+        *ibus_im_context_new    (void);
+void    ibus_im_context_register_type
+                                (GTypeModule    *type_module);
+void    ibus_im_context_shutdown
+                                (void);
+gchar   *ibus_im_context_get_ic (IBusIMContext  *context);
+void    ibus_im_context_set_ic  (IBusIMContext  *context,
+                                 const gchar    *ic);
+void    ibus_im_context_enable  (IBusIMContext  *context);
+void    ibus_im_context_disable (IBusIMContext  *context);
+void    ibus_im_context_commit_string
+                                (IBusIMContext  *context,
+                                const gchar     *string);
+void    ibus_im_context_update_preedit
+                                (IBusIMContext  *context,
+                                const gchar     *string,
+                                PangoAttrList   *attrs,
+                                gint            cursor_pos,
+                                gboolean        show);
 G_END_DECLS
 #endif