Implement IME state per window.
authorfujiwarat <takao.fujiwara1@gmail.com>
Wed, 28 Aug 2013 04:10:46 +0000 (13:10 +0900)
committerfujiwarat <takao.fujiwara1@gmail.com>
Wed, 28 Aug 2013 04:10:46 +0000 (13:10 +0900)
BUG=http://code.google.com/p/ibus/issues/detail?id=1568
TEST=Disable global engine with ibus-setup.

Review URL: https://codereview.appspot.com/12957046

bus/ibusimpl.c
bus/panelproxy.c
bus/panelproxy.h
data/ibus.schemas.in
setup/setup.ui
src/ibuspanelservice.c
src/ibuspanelservice.h
ui/gtk3/panel.vala

index bd4e488..eec6da3 100644 (file)
@@ -826,7 +826,8 @@ _context_focus_out_cb (BusInputContext    *context,
 /**
  * _context_destroy_cb:
  *
- * A callback function to be called when the "destroy" signal is sent to the context.
+ * A callback function to be called when the "destroy" signal is sent to the
+ * context.
  */
 static void
 _context_destroy_cb (BusInputContext    *context,
@@ -835,9 +836,12 @@ _context_destroy_cb (BusInputContext    *context,
     g_assert (BUS_IS_IBUS_IMPL (ibus));
     g_assert (BUS_IS_INPUT_CONTEXT (context));
 
-    if (context == ibus->focused_context) {
+    if (context == ibus->focused_context)
         bus_ibus_impl_set_focused_context (ibus, NULL);
-    }
+
+    if (ibus->panel &&
+        bus_input_context_get_capabilities (context) & IBUS_CAP_FOCUS)
+        bus_panel_proxy_destroy_context (ibus->panel, context);
 
     ibus->contexts = g_list_remove (ibus->contexts, context);
     g_object_unref (context);
index 8099e88..d49f1e1 100644 (file)
@@ -1,8 +1,8 @@
 /* -*- mode: C; c-basic-offset: 4; indent-tabs-mode: nil; -*- */
 /* vim:set et sts=4: */
 /* ibus - The Input Bus
- * Copyright (C) 2008-2010 Peng Huang <shawn.p.huang@gmail.com>
- * Copyright (C) 2008-2010 Red Hat, Inc.
+ * Copyright (C) 2008-2013 Peng Huang <shawn.p.huang@gmail.com>
+ * Copyright (C) 2008-2013 Red Hat, Inc.
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
@@ -694,3 +694,23 @@ bus_panel_proxy_focus_out (BusPanelProxy    *panel,
     panel->focused_context = NULL;
 }
 
+void
+bus_panel_proxy_destroy_context (BusPanelProxy    *panel,
+                                 BusInputContext  *context)
+{
+    const gchar *path;
+
+    g_assert (BUS_IS_PANEL_PROXY (panel));
+    g_assert (BUS_IS_INPUT_CONTEXT (context));
+
+    g_object_ref_sink (context);
+    path = ibus_service_get_object_path ((IBusService *)context);
+
+    g_dbus_proxy_call ((GDBusProxy *)panel,
+                       "DestroyContext",
+                       g_variant_new ("(o)", path),
+                       G_DBUS_CALL_FLAGS_NONE,
+                       -1, NULL, NULL, NULL);
+
+    g_object_unref (context);
+}
index cc3183e..ff7e5ce 100644 (file)
@@ -1,8 +1,8 @@
 /* -*- mode: C; c-basic-offset: 4; indent-tabs-mode: nil; -*- */
 /* vim:set et sts=4: */
 /* ibus - The Input Bus
- * Copyright (C) 2008-2010 Peng Huang <shawn.p.huang@gmail.com>
- * Copyright (C) 2008-2010 Red Hat, Inc.
+ * Copyright (C) 2008-2013 Peng Huang <shawn.p.huang@gmail.com>
+ * Copyright (C) 2008-2013 Red Hat, Inc.
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
 #define BUS_PANEL_PROXY(obj)             \
     (G_TYPE_CHECK_INSTANCE_CAST ((obj), BUS_TYPE_PANEL_PROXY, BusPanelProxy))
 #define BUS_PANEL_PROXY_CLASS(klass)     \
-    (G_TYPE_CHECK_CLASS_CAST ((klass), BUS_TYPE_PANEL_PROXY, BusPanelProxyClass))
+    (G_TYPE_CHECK_CLASS_CAST ((klass),   \
+                              BUS_TYPE_PANEL_PROXY, \
+                              BusPanelProxyClass))
 #define BUS_IS_PANEL_PROXY(obj)          \
     (G_TYPE_CHECK_INSTANCE_TYPE ((obj), BUS_TYPE_PANEL_PROXY))
 #define BUS_IS_PANEL_PROXY_CLASS(klass)  \
     (G_TYPE_CHECK_CLASS_TYPE ((klass), BUS_TYPE_PANEL_PROXY))
 #define BUS_PANEL_PROXY_GET_CLASS(obj)   \
-    (G_TYPE_INSTANCE_GET_CLASS ((obj), BUS_TYPE_PANEL_PROXY, BusPanelProxyClass))
+    (G_TYPE_INSTANCE_GET_CLASS ((obj),   \
+                                BUS_TYPE_PANEL_PROXY, \
+                                BusPanelProxyClass))
 
 G_BEGIN_DECLS
 
 typedef struct _BusPanelProxy BusPanelProxy;
 typedef struct _BusPanelProxyClass BusPanelProxyClass;
 
-GType            bus_panel_proxy_get_type           (void);
-BusPanelProxy   *bus_panel_proxy_new                (BusConnection      *connection);
+GType            bus_panel_proxy_get_type      (void);
+BusPanelProxy   *bus_panel_proxy_new           (BusConnection     *connection);
 
 /* functions that invoke D-Bus methods of the panel component. */
-void             bus_panel_proxy_focus_in           (BusPanelProxy      *panel,
-                                                     BusInputContext    *context);
-void             bus_panel_proxy_focus_out          (BusPanelProxy      *panel,
-                                                     BusInputContext    *context);
+void             bus_panel_proxy_focus_in      (BusPanelProxy     *panel,
+                                                BusInputContext   *context);
+void             bus_panel_proxy_focus_out     (BusPanelProxy     *panel,
+                                                BusInputContext   *context);
+void             bus_panel_proxy_destroy_context
+                                               (BusPanelProxy     *panel,
+                                                BusInputContext   *context);
 void             bus_panel_proxy_set_cursor_location
-                                                    (BusPanelProxy      *panel,
-                                                     gint32              x,
-                                                     gint32              y,
-                                                     gint32              w,
-                                                     gint32              h);
-void             bus_panel_proxy_update_preedit_text(BusPanelProxy      *panel,
-                                                     IBusText           *text,
-                                                     guint               cursor_pos,
-                                                     gboolean            visible);
-void             bus_panel_proxy_show_preedit_text  (BusPanelProxy      *panel);
-void             bus_panel_proxy_hide_preedit_text  (BusPanelProxy      *panel);
+                                               (BusPanelProxy     *panel,
+                                                gint32             x,
+                                                gint32             y,
+                                                gint32             w,
+                                                gint32             h);
+void             bus_panel_proxy_update_preedit_text
+                                               (BusPanelProxy     *panel,
+                                                IBusText          *text,
+                                                guint              cursor_pos,
+                                                gboolean           visible);
+void             bus_panel_proxy_show_preedit_text
+                                               (BusPanelProxy     *panel);
+void             bus_panel_proxy_hide_preedit_text
+                                               (BusPanelProxy     *panel);
 void             bus_panel_proxy_update_auxiliary_text
-                                                    (BusPanelProxy      *panel,
-                                                     IBusText           *text,
-                                                     gboolean            visible);
-void             bus_panel_proxy_show_auxiliary_text(BusPanelProxy      *panel);
-void             bus_panel_proxy_hide_auxiliary_text(BusPanelProxy      *panel);
-void             bus_panel_proxy_update_lookup_table(BusPanelProxy      *panel,
-                                                     IBusLookupTable    *table,
-                                                     gboolean           visible);
-void             bus_panel_proxy_show_lookup_table  (BusPanelProxy      *panel);
-void             bus_panel_proxy_hide_lookup_table  (BusPanelProxy      *panel);
+                                               (BusPanelProxy     *panel,
+                                                IBusText          *text,
+                                                gboolean           visible);
+void             bus_panel_proxy_show_auxiliary_text
+                                               (BusPanelProxy     *panel);
+void             bus_panel_proxy_hide_auxiliary_text
+                                               (BusPanelProxy     *panel);
+void             bus_panel_proxy_update_lookup_table
+                                               (BusPanelProxy     *panel,
+                                                IBusLookupTable   *table,
+                                                gboolean           visible);
+void             bus_panel_proxy_show_lookup_table
+                                               (BusPanelProxy     *panel);
+void             bus_panel_proxy_hide_lookup_table
+                                               (BusPanelProxy     *panel);
 void             bus_panel_proxy_page_up_lookup_table
-                                                    (BusPanelProxy      *panel);
+                                               (BusPanelProxy     *panel);
 void             bus_panel_proxy_page_down_lookup_table
-                                                    (BusPanelProxy      *panel);
+                                               (BusPanelProxy     *panel);
 void             bus_panel_proxy_cursor_up_lookup_table
-                                                    (BusPanelProxy      *panel);
+                                               (BusPanelProxy     *panel);
 void             bus_panel_proxy_cursor_down_lookup_table
-                                                    (BusPanelProxy      *panel);
-void             bus_panel_proxy_register_properties(BusPanelProxy      *panel,
-                                                     IBusPropList       *prop_list);
-void             bus_panel_proxy_update_property    (BusPanelProxy      *panel,
-                                                     IBusProperty       *prop);
+                                               (BusPanelProxy     *panel);
+void             bus_panel_proxy_register_properties
+                                               (BusPanelProxy     *panel,
+                                                IBusPropList      *prop_list);
+void             bus_panel_proxy_update_property
+                                               (BusPanelProxy     *panel,
+                                                IBusProperty      *prop);
 G_END_DECLS
 #endif
 
index 9cfe83b..2779139 100644 (file)
       <applyto>/desktop/ibus/general/use_global_engine</applyto>
       <owner>ibus</owner>
       <type>bool</type>
-      <default>false</default>
+      <default>true</default>
       <locale name="C">
         <short>Use global input method</short>
            <long>Share the same input method among all applications</long>
index 2042263..1638abb 100644 (file)
@@ -1001,7 +1001,7 @@ You may use up/down buttons to change it.&lt;/i&gt;&lt;/small&gt;</property>
                     </child>
                     <child>
                       <object class="GtkFrame" id="frame5">
-                        <property name="no_show_all">True</property>
+                        <property name="visible">True</property>
                         <property name="can_focus">False</property>
                         <property name="label_xalign">0</property>
                         <property name="shadow_type">none</property>
index ac9c7c7..eadbf5e 100644 (file)
@@ -1,8 +1,8 @@
 /* -*- mode: C; c-basic-offset: 4; indent-tabs-mode: nil; -*- */
 /* vim:set et sts=4: */
 /* ibus - The Input Bus
- * Copyright (c) 2009, Google Inc. All rights reserved.
- * Copyright (C) 2010 Peng Huang <shawn.p.huang@gmail.com>
+ * Copyright (c) 2009-2013 Google Inc. All rights reserved.
+ * Copyright (C) 2010-2013 Peng Huang <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
@@ -48,6 +48,7 @@ enum {
     SHOW_PREEDIT_TEXT,
     START_SETUP,
     STATE_CHANGED,
+    DESTROY_CONTEXT,
     LAST_SIGNAL,
 };
 
@@ -58,62 +59,80 @@ enum {
 static guint            panel_signals[LAST_SIGNAL] = { 0 };
 
 /* functions prototype */
-static void      ibus_panel_service_set_property          (IBusPanelService       *panel,
-                                                           guint                   prop_id,
-                                                           const GValue           *value,
-                                                           GParamSpec             *pspec);
-static void      ibus_panel_service_get_property          (IBusPanelService       *panel,
-                                                           guint                   prop_id,
-                                                           GValue                 *value,
-                                                           GParamSpec             *pspec);
-static void      ibus_panel_service_real_destroy          (IBusPanelService       *panel);
-static void      ibus_panel_service_service_method_call   (IBusService            *service,
-                                                           GDBusConnection        *connection,
-                                                           const gchar            *sender,
-                                                           const gchar            *object_path,
-                                                           const gchar            *interface_name,
-                                                           const gchar            *method_name,
-                                                           GVariant               *parameters,
-                                                           GDBusMethodInvocation  *invocation);
-static GVariant *ibus_panel_service_service_get_property  (IBusService            *service,
-                                                           GDBusConnection        *connection,
-                                                           const gchar            *sender,
-                                                           const gchar            *object_path,
-                                                           const gchar            *interface_name,
-                                                           const gchar            *property_name,
-                                                           GError                **error);
-static gboolean  ibus_panel_service_service_set_property  (IBusService            *service,
-                                                           GDBusConnection        *connection,
-                                                           const gchar            *sender,
-                                                           const gchar            *object_path,
-                                                           const gchar            *interface_name,
-                                                           const gchar            *property_name,
-                                                           GVariant               *value,
-                                                           GError                **error);
-static void      ibus_panel_service_not_implemented       (IBusPanelService      *panel);
-static void      ibus_panel_service_focus_in              (IBusPanelService      *panel,
-                                                           const gchar           *input_context_path);
-static void      ibus_panel_service_focus_out             (IBusPanelService      *panel,
-                                                           const gchar           *input_context_path);
-static void      ibus_panel_service_register_properties   (IBusPanelService      *panel,
-                                                           IBusPropList          *prop_list);
-static void      ibus_panel_service_set_cursor_location   (IBusPanelService      *panel,
-                                                           gint                   x,
-                                                           gint                   y,
-                                                           gint                   w,
-                                                           gint                   h);
-static void      ibus_panel_service_update_auxiliary_text (IBusPanelService      *panel,
-                                                           IBusText              *text,
-                                                           gboolean               visible);
-static void      ibus_panel_service_update_lookup_table   (IBusPanelService      *panel,
-                                                           IBusLookupTable       *lookup_table,
-                                                           gboolean               visible);
-static void      ibus_panel_service_update_preedit_text   (IBusPanelService      *panel,
-                                                           IBusText              *text,
-                                                           guint                  cursor_pos,
-                                                           gboolean               visible);
-static void      ibus_panel_service_update_property       (IBusPanelService      *panel,
-                                                           IBusProperty          *prop);
+static void      ibus_panel_service_set_property
+                                   (IBusPanelService       *panel,
+                                    guint                   prop_id,
+                                    const GValue           *value,
+                                    GParamSpec             *pspec);
+static void      ibus_panel_service_get_property
+                                   (IBusPanelService       *panel,
+                                    guint                   prop_id,
+                                    GValue                 *value,
+                                    GParamSpec             *pspec);
+static void      ibus_panel_service_real_destroy
+                                   (IBusPanelService       *panel);
+static void      ibus_panel_service_service_method_call
+                                   (IBusService            *service,
+                                    GDBusConnection        *connection,
+                                    const gchar            *sender,
+                                    const gchar            *object_path,
+                                    const gchar            *interface_name,
+                                    const gchar            *method_name,
+                                    GVariant               *parameters,
+                                    GDBusMethodInvocation  *invocation);
+static GVariant *ibus_panel_service_service_get_property
+                                   (IBusService            *service,
+                                    GDBusConnection        *connection,
+                                    const gchar            *sender,
+                                    const gchar            *object_path,
+                                    const gchar            *interface_name,
+                                    const gchar            *property_name,
+                                    GError                **error);
+static gboolean  ibus_panel_service_service_set_property
+                                   (IBusService            *service,
+                                    GDBusConnection        *connection,
+                                    const gchar            *sender,
+                                    const gchar            *object_path,
+                                    const gchar            *interface_name,
+                                    const gchar            *property_name,
+                                    GVariant               *value,
+                                    GError                **error);
+static void      ibus_panel_service_not_implemented
+                                   (IBusPanelService       *panel);
+static void      ibus_panel_service_focus_in
+                                   (IBusPanelService       *panel,
+                                    const gchar            *input_context_path);
+static void      ibus_panel_service_focus_out
+                                   (IBusPanelService       *panel,
+                                    const gchar            *input_context_path);
+static void      ibus_panel_service_destroy_context
+                                   (IBusPanelService       *panel,
+                                    const gchar            *input_context_path);
+static void      ibus_panel_service_register_properties
+                                   (IBusPanelService       *panel,
+                                    IBusPropList           *prop_list);
+static void      ibus_panel_service_set_cursor_location
+                                   (IBusPanelService       *panel,
+                                    gint                    x,
+                                    gint                    y,
+                                    gint                    w,
+                                    gint                    h);
+static void      ibus_panel_service_update_auxiliary_text
+                                   (IBusPanelService       *panel,
+                                    IBusText               *text,
+                                    gboolean                visible);
+static void      ibus_panel_service_update_lookup_table
+                                   (IBusPanelService       *panel,
+                                    IBusLookupTable        *lookup_table,
+                                    gboolean                visible);
+static void      ibus_panel_service_update_preedit_text
+                                   (IBusPanelService       *panel,
+                                    IBusText               *text,
+                                    guint                   cursor_pos,
+                                    gboolean                visible);
+static void      ibus_panel_service_update_property
+                                   (IBusPanelService       *panel,
+                                    IBusProperty           *prop);
 
 G_DEFINE_TYPE (IBusPanelService, ibus_panel_service, IBUS_TYPE_SERVICE)
 
@@ -156,6 +175,9 @@ static const gchar introspection_xml[] =
     "    <method name='FocusOut'>"
     "      <arg direction='in'  type='o' name='ic' />"
     "    </method>"
+    "    <method name='DestroyContext'>"
+    "      <arg direction='in'  type='o' name='ic' />"
+    "    </method>"
     "    <method name='SetCursorLocation'>"
     "      <arg direction='in' type='i' name='x' />"
     "      <arg direction='in' type='i' name='y' />"
@@ -194,21 +216,30 @@ static void
 ibus_panel_service_class_init (IBusPanelServiceClass *class)
 {
     GObjectClass *gobject_class = G_OBJECT_CLASS (class);
-    ibus_panel_service_parent_class = IBUS_SERVICE_CLASS (g_type_class_peek_parent (class));
+    ibus_panel_service_parent_class =
+            IBUS_SERVICE_CLASS (g_type_class_peek_parent (class));
 
-    gobject_class->set_property = (GObjectSetPropertyFunc) ibus_panel_service_set_property;
-    gobject_class->get_property = (GObjectGetPropertyFunc) ibus_panel_service_get_property;
+    gobject_class->set_property =
+            (GObjectSetPropertyFunc) ibus_panel_service_set_property;
+    gobject_class->get_property =
+            (GObjectGetPropertyFunc) ibus_panel_service_get_property;
 
-    IBUS_OBJECT_CLASS (gobject_class)->destroy = (IBusObjectDestroyFunc) ibus_panel_service_real_destroy;
+    IBUS_OBJECT_CLASS (gobject_class)->destroy =
+            (IBusObjectDestroyFunc) ibus_panel_service_real_destroy;
 
-    IBUS_SERVICE_CLASS (class)->service_method_call  = ibus_panel_service_service_method_call;
-    IBUS_SERVICE_CLASS (class)->service_get_property = ibus_panel_service_service_get_property;
-    IBUS_SERVICE_CLASS (class)->service_set_property = ibus_panel_service_service_set_property;
+    IBUS_SERVICE_CLASS (class)->service_method_call  =
+            ibus_panel_service_service_method_call;
+    IBUS_SERVICE_CLASS (class)->service_get_property =
+            ibus_panel_service_service_get_property;
+    IBUS_SERVICE_CLASS (class)->service_set_property =
+            ibus_panel_service_service_set_property;
 
-    ibus_service_class_add_interfaces (IBUS_SERVICE_CLASS (class), introspection_xml);
+    ibus_service_class_add_interfaces (IBUS_SERVICE_CLASS (class),
+                                       introspection_xml);
 
     class->focus_in              = ibus_panel_service_focus_in;
     class->focus_out             = ibus_panel_service_focus_out;
+    class->destroy_context       = ibus_panel_service_destroy_context;
     class->register_properties   = ibus_panel_service_register_properties;
     class->set_cursor_location   = ibus_panel_service_set_cursor_location;
     class->update_lookup_table   = ibus_panel_service_update_lookup_table;
@@ -240,9 +271,11 @@ ibus_panel_service_class_init (IBusPanelServiceClass *class)
      * @visible: Whether the update is visible.
      *
      * Emitted when the client application get the update-preedit-text.
-     * Implement the member function update_preedit_text() in extended class to receive this signal.
+     * Implement the member function update_preedit_text() in extended class
+     * to receive this signal.
      *
-     * <note><para>Argument @user_data is ignored in this function.</para></note>
+     * <note><para>Argument @user_data is ignored in this function.</para>
+     * </note>
      */
     panel_signals[UPDATE_PREEDIT_TEXT] =
         g_signal_new (I_("update-preedit-text"),
@@ -263,9 +296,11 @@ ibus_panel_service_class_init (IBusPanelServiceClass *class)
      * @visible: Whether the update is visible.
      *
      * Emitted when the client application get the update-auxiliary-text.
-     * Implement the member function update_auxiliary_text() in extended class to receive this signal.
+     * Implement the member function update_auxiliary_text() in extended class
+     * to receive this signal.
      *
-     * <note><para>Argument @user_data is ignored in this function.</para></note>
+     * <note><para>Argument @user_data is ignored in this function.</para>
+     * </note>
      */
     panel_signals[UPDATE_AUXILIARY_TEXT] =
         g_signal_new (I_("update-auxiliary-text"),
@@ -285,9 +320,11 @@ ibus_panel_service_class_init (IBusPanelServiceClass *class)
      * @visible: Whether the update is visible.
      *
      * Emitted when the client application get the update-lookup-table.
-     * Implement the member function update_lookup_table() in extended class to receive this signal.
+     * Implement the member function update_lookup_table() in extended class
+     * to receive this signal.
      *
-     * <note><para>Argument @user_data is ignored in this function.</para></note>
+     * <note><para>Argument @user_data is ignored in this function.</para>
+     * </note>
      */
     panel_signals[UPDATE_LOOKUP_TABLE] =
         g_signal_new (I_("update-lookup-table"),
@@ -306,9 +343,11 @@ ibus_panel_service_class_init (IBusPanelServiceClass *class)
      * @input_context_path: Object path of InputContext.
      *
      * Emitted when the client application get the focus-in.
-     * Implement the member function focus_in() in extended class to receive this signal.
+     * Implement the member function focus_in() in extended class to receive
+     * this signal.
      *
-     * <note><para>Argument @user_data is ignored in this function.</para></note>
+     * <note><para>Argument @user_data is ignored in this function.</para>
+     * </note>
      */
     panel_signals[FOCUS_IN] =
         g_signal_new (I_("focus-in"),
@@ -326,9 +365,11 @@ ibus_panel_service_class_init (IBusPanelServiceClass *class)
      * @input_context_path: Object path of InputContext.
      *
      * Emitted when the client application get the focus-out.
-     * Implement the member function focus_out() in extended class to receive this signal.
+     * Implement the member function focus_out() in extended class to receive
+     * this signal.
      *
-     * <note><para>Argument @user_data is ignored in this function.</para></note>
+     * <note><para>Argument @user_data is ignored in this function.</para>
+     * </note>
      */
     panel_signals[FOCUS_OUT] =
         g_signal_new (I_("focus-out"),
@@ -346,9 +387,11 @@ ibus_panel_service_class_init (IBusPanelServiceClass *class)
      * @prop_list: An IBusPropList that contains properties.
      *
      * Emitted when the client application get the register-properties.
-     * Implement the member function register_properties() in extended class to receive this signal.
+     * Implement the member function register_properties() in extended class
+     * to receive this signal.
      *
-     * <note><para>Argument @user_data is ignored in this function.</para></note>
+     * <note><para>Argument @user_data is ignored in this function.</para>
+     * </note>
      */
     panel_signals[REGISTER_PROPERTIES] =
         g_signal_new (I_("register-properties"),
@@ -366,9 +409,11 @@ ibus_panel_service_class_init (IBusPanelServiceClass *class)
      * @prop: The IBusProperty to be updated.
      *
      * Emitted when the client application get the update-property.
-     * Implement the member function update_property() in extended class to receive this signal.
+     * Implement the member function update_property() in extended class to
+     * receive this signal.
      *
-     * <note><para>Argument @user_data is ignored in this function.</para></note>
+     * <note><para>Argument @user_data is ignored in this function.</para>
+     * </note>
      */
     panel_signals[UPDATE_PROPERTY] =
         g_signal_new (I_("update-property"),
@@ -389,9 +434,11 @@ ibus_panel_service_class_init (IBusPanelServiceClass *class)
      * @h: Height of the cursor.
      *
      * Emitted when the client application get the set-cursor-location.
-     * Implement the member function set_cursor_location() in extended class to receive this signal.
+     * Implement the member function set_cursor_location() in extended class
+     * to receive this signal.
      *
-     * <note><para>Argument @user_data is ignored in this function.</para></note>
+     * <note><para>Argument @user_data is ignored in this function.</para>
+     * </note>
      */
     panel_signals[SET_CURSOR_LOCATION] =
         g_signal_new (I_("set-cursor-location"),
@@ -411,9 +458,11 @@ ibus_panel_service_class_init (IBusPanelServiceClass *class)
      * IBusPanelService::cursor-up-lookup-table:
      *
      * Emitted when the client application get the cursor-up-lookup-table.
-     * Implement the member function cursor_up_lookup_table() in extended class to receive this signal.
+     * Implement the member function cursor_up_lookup_table() in extended
+     * class to receive this signal.
      *
-     * <note><para>Argument @user_data is ignored in this function.</para></note>
+     * <note><para>Argument @user_data is ignored in this function.</para>
+     * </note>
      */
     panel_signals[CURSOR_UP_LOOKUP_TABLE] =
         g_signal_new (I_("cursor-up-lookup-table"),
@@ -428,9 +477,11 @@ ibus_panel_service_class_init (IBusPanelServiceClass *class)
      * IBusPanelService::cursor-down-lookup-table:
      *
      * Emitted when the client application get the cursor-down-lookup-table.
-     * Implement the member function cursor_down_lookup_table() in extended class to receive this signal.
+     * Implement the member function cursor_down_lookup_table() in extended
+     * class to receive this signal.
      *
-     * <note><para>Argument @user_data is ignored in this function.</para></note>
+     * <note><para>Argument @user_data is ignored in this function.</para>
+     * </note>
      */
     panel_signals[CURSOR_DOWN_LOOKUP_TABLE] =
         g_signal_new (I_("cursor-down-lookup-table"),
@@ -445,9 +496,11 @@ ibus_panel_service_class_init (IBusPanelServiceClass *class)
      * IBusPanelService::hide-auxiliary-text:
      *
      * Emitted when the client application get the hide-auxiliary-text.
-     * Implement the member function hide_auxiliary_text() in extended class to receive this signal.
+     * Implement the member function hide_auxiliary_text() in extended class
+     * to receive this signal.
      *
-     * <note><para>Argument @user_data is ignored in this function.</para></note>
+     * <note><para>Argument @user_data is ignored in this function.</para>
+     * </note>
      */
     panel_signals[HIDE_AUXILIARY_TEXT] =
         g_signal_new (I_("hide-auxiliary-text"),
@@ -462,9 +515,11 @@ ibus_panel_service_class_init (IBusPanelServiceClass *class)
      * IBusPanelService::hide-language-bar:
      *
      * Emitted when the client application get the hide-language-bar.
-     * Implement the member function hide_language_bar() in extended class to receive this signal.
+     * Implement the member function hide_language_bar() in extended class to
+     * receive this signal.
      *
-     * <note><para>Argument @user_data is ignored in this function.</para></note>
+     * <note><para>Argument @user_data is ignored in this function.</para>
+     * </note>
      */
     panel_signals[HIDE_LANGUAGE_BAR] =
         g_signal_new (I_("hide-language-bar"),
@@ -479,9 +534,11 @@ ibus_panel_service_class_init (IBusPanelServiceClass *class)
      * IBusPanelService::hide-lookup-table:
      *
      * Emitted when the client application get the hide-lookup-table.
-     * Implement the member function hide_lookup_table() in extended class to receive this signal.
+     * Implement the member function hide_lookup_table() in extended class to
+     * receive this signal.
      *
-     * <note><para>Argument @user_data is ignored in this function.</para></note>
+     * <note><para>Argument @user_data is ignored in this function.</para>
+     * </note>
      */
     panel_signals[HIDE_LOOKUP_TABLE] =
         g_signal_new (I_("hide-lookup-table"),
@@ -496,9 +553,11 @@ ibus_panel_service_class_init (IBusPanelServiceClass *class)
      * IBusPanelService::hide-preedit-text:
      *
      * Emitted when the client application get the hide-preedit-text.
-     * Implement the member function hide_preedit_text() in extended class to receive this signal.
+     * Implement the member function hide_preedit_text() in extended class to
+     * receive this signal.
      *
-     * <note><para>Argument @user_data is ignored in this function.</para></note>
+     * <note><para>Argument @user_data is ignored in this function.</para>
+     * </note>
      */
     panel_signals[HIDE_PREEDIT_TEXT] =
         g_signal_new (I_("hide-preedit-text"),
@@ -513,9 +572,11 @@ ibus_panel_service_class_init (IBusPanelServiceClass *class)
      * IBusPanelService::page-up-lookup-table:
      *
      * Emitted when the client application get the page-up-lookup-table.
-     * Implement the member function page_up_lookup_table() in extended class to receive this signal.
+     * Implement the member function page_up_lookup_table() in extended class
+     * to receive this signal.
      *
-     * <note><para>Argument @user_data is ignored in this function.</para></note>
+     * <note><para>Argument @user_data is ignored in this function.</para>
+     * </note>
      */
     panel_signals[PAGE_UP_LOOKUP_TABLE] =
         g_signal_new (I_("page-up-lookup-table"),
@@ -530,9 +591,11 @@ ibus_panel_service_class_init (IBusPanelServiceClass *class)
      * IBusPanelService::page-down-lookup-table:
      *
      * Emitted when the client application get the page-down-lookup-table.
-     * Implement the member function page_down_lookup_table() in extended class to receive this signal.
+     * Implement the member function page_down_lookup_table() in extended
+     * class to receive this signal.
      *
-     * <note><para>Argument @user_data is ignored in this function.</para></note>
+     * <note><para>Argument @user_data is ignored in this function.</para>
+     * </note>
      */
     panel_signals[PAGE_DOWN_LOOKUP_TABLE] =
         g_signal_new (I_("page-down-lookup-table"),
@@ -547,9 +610,11 @@ ibus_panel_service_class_init (IBusPanelServiceClass *class)
      * IBusPanelService::reset:
      *
      * Emitted when the client application get the reset.
-     * Implement the member function reset() in extended class to receive this signal.
+     * Implement the member function reset() in extended class to receive this
+     * signal.
      *
-     * <note><para>Argument @user_data is ignored in this function.</para></note>
+     * <note><para>Argument @user_data is ignored in this function.</para>
+     * </note>
      */
     panel_signals[RESET] =
         g_signal_new (I_("reset"),
@@ -564,9 +629,11 @@ ibus_panel_service_class_init (IBusPanelServiceClass *class)
      * IBusPanelService::show-auxiliary-text:
      *
      * Emitted when the client application get the show-auxiliary-text.
-     * Implement the member function show_auxiliary_text() in extended class to receive this signal.
+     * Implement the member function show_auxiliary_text() in extended class
+     * to receive this signal.
      *
-     * <note><para>Argument @user_data is ignored in this function.</para></note>
+     * <note><para>Argument @user_data is ignored in this function.</para>
+     * </note>
      */
     panel_signals[SHOW_AUXILIARY_TEXT] =
         g_signal_new (I_("show-auxiliary-text"),
@@ -581,9 +648,11 @@ ibus_panel_service_class_init (IBusPanelServiceClass *class)
      * IBusPanelService::show-language-bar:
      *
      * Emitted when the client application get the show-language-bar.
-     * Implement the member function show_language_bar() in extended class to receive this signal.
+     * Implement the member function show_language_bar() in extended class to
+     * receive this signal.
      *
-     * <note><para>Argument @user_data is ignored in this function.</para></note>
+     * <note><para>Argument @user_data is ignored in this function.</para>
+     * </note>
      */
     panel_signals[SHOW_LANGUAGE_BAR] =
         g_signal_new (I_("show-language-bar"),
@@ -598,9 +667,11 @@ ibus_panel_service_class_init (IBusPanelServiceClass *class)
      * IBusPanelService::show-lookup-table:
      *
      * Emitted when the client application get the show-lookup-table.
-     * Implement the member function show_lookup_table() in extended class to receive this signal.
+     * Implement the member function show_lookup_table() in extended class to
+     * receive this signal.
      *
-     * <note><para>Argument @user_data is ignored in this function.</para></note>
+     * <note><para>Argument @user_data is ignored in this function.</para>
+     * </note>
      */
     panel_signals[SHOW_LOOKUP_TABLE] =
         g_signal_new (I_("show-lookup-table"),
@@ -615,9 +686,11 @@ ibus_panel_service_class_init (IBusPanelServiceClass *class)
      * IBusPanelService::show-preedit-text:
      *
      * Emitted when the client application get the show-preedit-text.
-     * Implement the member function show_preedit_text() in extended class to receive this signal.
+     * Implement the member function show_preedit_text() in extended class to
+     * receive this signal.
      *
-     * <note><para>Argument @user_data is ignored in this function.</para></note>
+     * <note><para>Argument @user_data is ignored in this function.</para>
+     * </note>
      */
     panel_signals[SHOW_PREEDIT_TEXT] =
         g_signal_new (I_("show-preedit-text"),
@@ -632,9 +705,11 @@ ibus_panel_service_class_init (IBusPanelServiceClass *class)
      * IBusPanelService::start-setup:
      *
      * Emitted when the client application get the start-setup.
-     * Implement the member function start_setup() in extended class to receive this signal.
+     * Implement the member function start_setup() in extended class to
+     * receive this signal.
      *
-     * <note><para>Argument @user_data is ignored in this function.</para></note>
+     * <note><para>Argument @user_data is ignored in this function.</para>
+     * </note>
      */
     panel_signals[START_SETUP] =
         g_signal_new (I_("start-setup"),
@@ -649,9 +724,11 @@ ibus_panel_service_class_init (IBusPanelServiceClass *class)
      * IBusPanelService::state-changed:
      *
      * Emitted when the client application get the state-changed.
-     * Implement the member function state_changed() in extended class to receive this signal.
+     * Implement the member function state_changed() in extended class to
+     * receive this signal.
      *
-     * <note><para>Argument @user_data is ignored in this function.</para></note>
+     * <note><para>Argument @user_data is ignored in this function.</para>
+     * </note>
      */
     panel_signals[STATE_CHANGED] =
         g_signal_new (I_("state-changed"),
@@ -661,6 +738,28 @@ ibus_panel_service_class_init (IBusPanelServiceClass *class)
             NULL, NULL,
             _ibus_marshal_VOID__VOID,
             G_TYPE_NONE, 0);
+
+    /**
+     * IBusPanelService::destroy-context:
+     * @input_context_path: Object path of InputContext.
+     *
+     * Emitted when the client application destroys.
+     * Implement the member function destroy_context() in extended class to
+     * receive this signal.
+     *
+     * <note><para>Argument @user_data is ignored in this function.</para>
+     * </note>
+     */
+    panel_signals[DESTROY_CONTEXT] =
+        g_signal_new (I_("destroy-context"),
+            G_TYPE_FROM_CLASS (gobject_class),
+            G_SIGNAL_RUN_LAST,
+            G_STRUCT_OFFSET (IBusPanelServiceClass, destroy_context),
+            NULL, NULL,
+            _ibus_marshal_VOID__STRING,
+            G_TYPE_NONE,
+            1,
+            G_TYPE_STRING);
 }
 
 static void
@@ -790,6 +889,14 @@ ibus_panel_service_service_method_call (IBusService           *service,
         return;
     }
 
+    if (g_strcmp0 (method_name, "DestroyContext") == 0) {
+        const gchar *path;
+        g_variant_get (parameters, "(&o)", &path);
+        g_signal_emit (panel, panel_signals[DESTROY_CONTEXT], 0, path);
+        g_dbus_method_invocation_return_value (invocation, NULL);
+        return;
+    }
+
     if (g_strcmp0 (method_name, "RegisterProperties") == 0) {
         GVariant *variant = g_variant_get_child_value (parameters, 0);
         IBusPropList *prop_list = IBUS_PROP_LIST (ibus_serializable_deserialize (variant));
@@ -918,6 +1025,13 @@ ibus_panel_service_focus_out (IBusPanelService    *panel,
 }
 
 static void
+ibus_panel_service_destroy_context (IBusPanelService    *panel,
+                                    const gchar         *input_context_path)
+{
+    ibus_panel_service_not_implemented(panel);
+}
+
+static void
 ibus_panel_service_register_properties (IBusPanelService *panel,
                                         IBusPropList     *prop_list)
 {
index 941df07..e88a3a7 100644 (file)
@@ -1,7 +1,7 @@
 /* -*- mode: C; c-basic-offset: 4; indent-tabs-mode: nil; -*- */
 /* vim:set et sts=4: */
 /* ibus - The Input Bus
- * Copyright (c) 2009, Google Inc. All rights reserved.
+ * Copyright (c) 2009-2013 Google Inc. All rights reserved.
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
@@ -76,9 +76,11 @@ struct _IBusPanelServiceClass {
 
     /* class members */
     void     (* focus_in)                  (IBusPanelService       *panel,
-                                            const gchar            *input_context_path);
+                                            const gchar
+                                                   *input_context_path);
     void     (* focus_out)                 (IBusPanelService       *panel,
-                                            const gchar            *input_context_path);
+                                            const gchar
+                                                   *input_context_path);
     void     (* register_properties)       (IBusPanelService       *panel,
                                             IBusPropList           *prop_list);
     void     (* set_cursor_location)       (IBusPanelService       *panel,
@@ -93,7 +95,7 @@ struct _IBusPanelServiceClass {
                                             IBusLookupTable        *lookup_table,
                                             gboolean                visible);
     void     (* update_preedit_text)       (IBusPanelService       *panel,
-                                            IBusText              *text,
+                                            IBusText               *text,
                                             guint                  cursor_pos,
                                             gboolean               visible);
     void     (* update_property)           (IBusPanelService       *panel,
@@ -113,10 +115,13 @@ struct _IBusPanelServiceClass {
     void     (* show_preedit_text)         (IBusPanelService       *panel);
     void     (* start_setup)               (IBusPanelService       *panel);
     void     (* state_changed)             (IBusPanelService       *panel);
+    void     (* destroy_context)           (IBusPanelService       *panel,
+                                            const gchar
+                                                   *input_context_path);
 
     /*< private >*/
     /* padding */
-    gpointer pdummy[8];  // We can add 8 pointers without breaking the ABI.
+    gpointer pdummy[7];  // We can add 8 pointers without breaking the ABI.
 };
 
 GType            ibus_panel_service_get_type  (void);
index 8e23bf9..e0cdf7d 100644 (file)
@@ -2,7 +2,7 @@
  *
  * ibus - The Input Bus
  *
- * Copyright(c) 2011 Peng Huang <shawn.p.huang@gmail.com>
+ * Copyright(c) 2011-2013 Peng Huang <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
@@ -43,8 +43,14 @@ class Panel : IBus.PanelService {
     private Gtk.Menu m_ime_menu;
     private Gtk.Menu m_sys_menu;
     private IBus.EngineDesc[] m_engines = {};
+    private GLib.HashTable<string, IBus.EngineDesc> m_engine_contexts =
+            new GLib.HashTable<string, IBus.EngineDesc>(GLib.str_hash,
+                                                        GLib.str_equal);
+    private string m_current_context_path = "";
+    private bool m_use_global_engine = true;
     private CandidatePanel m_candidate_panel;
     private Switcher m_switcher;
+    private bool m_switcher_is_running = false;
     private PropertyManager m_property_manager;
     private GLib.Pid m_setup_pid = 0;
     private Gtk.AboutDialog m_about_dialog;
@@ -120,6 +126,10 @@ class Panel : IBus.PanelService {
                 set_embed_preedit_text();
         });
 
+        m_settings_general.changed["use-global-engine"].connect((key) => {
+                set_use_global_engine();
+        });
+
         m_settings_hotkey.changed["triggers"].connect((key) => {
                 unbind_switch_shortcut();
                 bind_switch_shortcut();
@@ -290,6 +300,11 @@ class Panel : IBus.PanelService {
         m_bus.set_ibus_property("EmbedPreeditText", variant);
     }
 
+    private void set_use_global_engine() {
+        m_use_global_engine =
+                m_settings_general.get_boolean("use-global-engine");
+    }
+
     private int compare_versions(string version1, string version2) {
         string[] version1_list = version1.split(".");
         string[] version2_list = version2.split(".");
@@ -376,6 +391,7 @@ class Panel : IBus.PanelService {
         // Update m_use_system_keyboard_layout before update_engines()
         // is called.
         set_use_system_keyboard_layout();
+        set_use_global_engine();
         update_engines(m_settings_general.get_strv("preload-engines"),
                        m_settings_general.get_strv("engines-order"));
         unbind_switch_shortcut();
@@ -432,23 +448,41 @@ class Panel : IBus.PanelService {
         }
     }
 
-    private void switch_engine(int i, bool force = false) {
-        GLib.assert(i >= 0 && i < m_engines.length);
-
-        // Do not need switch
-        if (i == 0 && !force)
+    private void engine_contexts_insert(IBus.EngineDesc engine) {
+        if (m_use_global_engine)
             return;
 
-        IBus.EngineDesc engine = m_engines[i];
+        if (m_engine_contexts.size() >= 200) {
+            warning ("Contexts by windows are too much counted!");
+            m_engine_contexts.remove_all();
+        }
+
+        m_engine_contexts.replace(m_current_context_path, engine);
+    }
 
+    private void set_engine(IBus.EngineDesc engine) {
         if (!m_bus.set_global_engine(engine.get_name())) {
             warning("Switch engine to %s failed.", engine.get_name());
             return;
         }
+
         // set xkb layout
-        if (!m_use_system_keyboard_layout) {
+        if (!m_use_system_keyboard_layout)
             exec_setxkbmap(engine);
-        }
+
+        engine_contexts_insert(engine);
+    }
+
+    private void switch_engine(int i, bool force = false) {
+        GLib.assert(i >= 0 && i < m_engines.length);
+
+        // Do not need switch
+        if (i == 0 && !force)
+            return;
+
+        IBus.EngineDesc engine = m_engines[i];
+
+        set_engine(engine);
     }
 
     private void handle_engine_switch(Gdk.Event event, bool revert) {
@@ -471,7 +505,20 @@ class Panel : IBus.PanelService {
 
         if (pressed && m_switcher_delay_time >= 0) {
             int i = revert ? m_engines.length - 1 : 1;
+
+            /* The flag of m_switcher_is_running avoids the following problem:
+             *
+             * When an IME is chosen on m_switcher, focus_in() is called
+             * for the root window. If an engine is set in focus_in()
+             * during running m_switcher when m_use_global_engine is false,
+             * state_changed() is also called and m_engines[] is modified
+             * in state_changed() and m_switcher.run() returns the index
+             * for m_engines[] but m_engines[] was modified by state_changed()
+             * and the index is not correct. */
+            m_switcher_is_running = true;
             i = m_switcher.run(keyval, modifiers, event, m_engines, i);
+            m_switcher_is_running = false;
+
             if (i < 0) {
                 debug("switch cancelled");
             } else {
@@ -686,9 +733,68 @@ class Panel : IBus.PanelService {
     }
 
     public override void focus_in(string input_context_path) {
+        if (m_use_global_engine)
+            return;
+
+        /* Do not change the order of m_engines during running switcher. */
+        if (m_switcher_is_running)
+            return;
+
+        m_current_context_path = input_context_path;
+
+        var engine = m_engine_contexts[m_current_context_path];
+
+        if (engine == null) {
+            /* If engine == null, need to call set_engine(m_engines[0])
+             * here and update m_engine_contexts[] to avoid the
+             * following problem:
+             *
+             * If context1 is focused and does not set an engine and
+             * return here, the current engine1 is used for context1.
+             * When context2 is focused and switch engine1 to engine2,
+             * the current engine becomes engine2.
+             * And when context1 is focused again, context1 still
+             * does not set an engine and return here,
+             * engine2 is used for context2 instead of engine1. */
+            engine = m_engines.length > 0 ? m_engines[0] : null;
+
+            if (engine == null)
+                return;
+        } else {
+            bool in_engines = false;
+
+            foreach (var e in m_engines) {
+                if (engine.get_name() == e.get_name()) {
+                    in_engines = true;
+                    break;
+                }
+            }
+
+            /* The engine is deleted by ibus-setup before focus_in()
+             * is called. */
+            if (!in_engines)
+                return;
+        }
+
+        set_engine(engine);
     }
 
     public override void focus_out(string input_context_path) {
+        if (m_use_global_engine)
+            return;
+
+        /* Do not change the order of m_engines during running switcher. */
+        if (m_switcher_is_running)
+            return;
+
+        m_current_context_path = "";
+    }
+
+    public override void destroy_context(string input_context_path) {
+        if (m_use_global_engine)
+            return;
+
+        m_engine_contexts.remove(input_context_path);
     }
 
     public override void register_properties(IBus.PropList props) {
@@ -731,6 +837,10 @@ class Panel : IBus.PanelService {
     }
 
     public override void state_changed() {
+        /* Do not change the order of m_engines during running switcher. */
+        if (m_switcher_is_running)
+            return;
+
         var icon_name = "ibus-keyboard";
 
         var engine = m_bus.get_global_engine();