Implement embed_preedit_text.
authorfujiwarat <takao.fujiwara1@gmail.com>
Tue, 30 Apr 2013 12:46:02 +0000 (21:46 +0900)
committerfujiwarat <takao.fujiwara1@gmail.com>
Tue, 30 Apr 2013 12:46:02 +0000 (21:46 +0900)
BUG=http://code.google.com/p/ibus/issues/detail?id=1606

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

bus/ibusimpl.c
src/ibusbus.c
src/ibusbus.h
ui/gtk3/panel.vala

index 62185786abd42b8291a6ba40f0237aec0b621223..594216ab809977d5b85efccbd15ce6463e9f0d5a 100644 (file)
@@ -51,11 +51,13 @@ struct _BusIBusImpl {
     /* a fake input context for global engine support */
     BusInputContext *fake_context;
     
-    /* a list of engines that are started by a user (without the --ibus command line flag.) */
+    /* a list of engines that are started by a user (without the --ibus
+     * command line flag.) */
     GList *register_engine_list;
 
-    /* if TRUE, ibus-daemon uses a keysym translated by the system (i.e. XKB) as-is.
-     * otherwise, ibus-daemon itself converts keycode into keysym. */
+    /* if TRUE, ibus-daemon uses a keysym translated by the system
+     * (i.e. XKB) as-is. otherwise, ibus-daemon itself converts keycode
+     * into keysym. */
     gboolean use_sys_layout;
 
     gboolean embed_preedit_text;
@@ -65,7 +67,8 @@ struct _BusIBusImpl {
     BusInputContext *focused_context;
     BusPanelProxy   *panel;
 
-    /* a default keymap of ibus-daemon (usually "us") which is used only when use_sys_layout is FALSE. */
+    /* a default keymap of ibus-daemon (usually "us") which is used only
+     * when use_sys_layout is FALSE. */
     IBusKeymap      *keymap;
 
     gboolean use_global_engine;
@@ -92,45 +95,70 @@ static guint            _signals[LAST_SIGNAL] = { 0 };
 */
 
 /* functions prototype */
-static void      bus_ibus_impl_destroy           (BusIBusImpl        *ibus);
+static void      bus_ibus_impl_destroy  (BusIBusImpl        *ibus);
 static void      bus_ibus_impl_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 void     bus_ibus_impl_registry_changed  (BusIBusImpl        *ibus);
+                                        (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 *
+                bus_ibus_impl_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
+                bus_ibus_impl_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     bus_ibus_impl_registry_changed
+                                        (BusIBusImpl        *ibus);
 static void     bus_ibus_impl_global_engine_changed
-                                                (BusIBusImpl        *ibus);
+                                        (BusIBusImpl        *ibus);
 static void     bus_ibus_impl_set_context_engine_from_desc
-                                                (BusIBusImpl        *ibus,
-                                                 BusInputContext    *context,
-                                                 IBusEngineDesc     *desc);
+                                        (BusIBusImpl        *ibus,
+                                         BusInputContext    *context,
+                                         IBusEngineDesc     *desc);
 static BusInputContext
                *bus_ibus_impl_create_input_context
-                                                (BusIBusImpl        *ibus,
-                                                 BusConnection      *connection,
-                                                 const gchar        *client);
+                                        (BusIBusImpl        *ibus,
+                                         BusConnection      *connection,
+                                         const gchar        *client);
 static IBusEngineDesc
-               *bus_ibus_impl_get_engine_desc   (BusIBusImpl        *ibus,
-                                                 const gchar        *engine_name);
+               *bus_ibus_impl_get_engine_desc
+                                        (BusIBusImpl        *ibus,
+                                         const gchar        *engine_name);
 static void     bus_ibus_impl_set_focused_context
-                                                (BusIBusImpl        *ibus,
-                                                 BusInputContext    *context);
+                                        (BusIBusImpl        *ibus,
+                                         BusInputContext    *context);
 /* some callback functions */
-static void     _context_engine_changed_cb      (BusInputContext    *context,
-                                                 BusIBusImpl        *ibus);
-
-/* The interfaces available in this class, which consists of a list of methods this class implements and
- * a list of signals this class may emit. Method calls to the interface that are not defined in this XML
- * will be automatically rejected by the GDBus library (see src/ibusservice.c for details.) */
+static void     _context_engine_changed_cb
+                                        (BusInputContext    *context,
+                                         BusIBusImpl        *ibus);
+
+/* The interfaces available in this class, which consists of a list of
+ * methods this class implements and a list of signals this class may emit.
+ * Method calls to the interface that are not defined in this XML will 
+ * be automatically rejected by the GDBus library (see src/ibusservice.c
+ * for details.) */
 static const gchar introspection_xml[] =
     "<node>\n"
     "  <interface name='org.freedesktop.IBus'>\n"
+    "    <property name='EmbedPreeditText' type='b' access='readwrite' />\n"
     "    <method name='GetAddress'>\n"
     "      <arg direction='out' type='s' name='address' />\n"
     "    </method>\n"
@@ -193,12 +221,20 @@ G_DEFINE_TYPE (BusIBusImpl, bus_ibus_impl, IBUS_TYPE_SERVICE)
 static void
 bus_ibus_impl_class_init (BusIBusImplClass *class)
 {
-    IBUS_OBJECT_CLASS (class)->destroy = (IBusObjectDestroyFunc) bus_ibus_impl_destroy;
+    IBUS_OBJECT_CLASS (class)->destroy =
+            (IBusObjectDestroyFunc) bus_ibus_impl_destroy;
 
     /* override the parent class's implementation. */
-    IBUS_SERVICE_CLASS (class)->service_method_call = bus_ibus_impl_service_method_call;
-    /* register the xml so that bus_ibus_impl_service_method_call will be called on a method call defined in the xml (e.g. 'GetAddress'.) */
-    ibus_service_class_add_interfaces (IBUS_SERVICE_CLASS (class), introspection_xml);
+    IBUS_SERVICE_CLASS (class)->service_method_call =
+            bus_ibus_impl_service_method_call;
+    IBUS_SERVICE_CLASS (class)->service_get_property =
+            bus_ibus_impl_service_get_property;
+    IBUS_SERVICE_CLASS (class)->service_set_property =
+            bus_ibus_impl_service_set_property;
+    /* register the xml so that bus_ibus_impl_service_method_call will be
+     * called on a method call defined in the xml (e.g. 'GetAddress'.) */
+    ibus_service_class_add_interfaces (IBUS_SERVICE_CLASS (class),
+                                       introspection_xml);
 }
 
 /**
@@ -1277,10 +1313,50 @@ _ibus_preload_engines (BusIBusImpl           *ibus,
     g_dbus_method_invocation_return_value (invocation, NULL);
 }
 
+/**
+ * _ibus_get_embed_preedit_text:
+ *
+ * Implement the "EmbedPreeditText" method call of
+ * the org.freedesktop.IBus interface.
+ */
+static GVariant *
+_ibus_get_embed_preedit_text (BusIBusImpl     *ibus,
+                              GDBusConnection *connection,
+                              GError         **error)
+{
+    if (error) {
+        *error = NULL;
+    }
+
+    return g_variant_new_boolean (ibus->embed_preedit_text);
+}
+
+/**
+ * _ibus_set_embed_preedit_text:
+ *
+ * Implement the "EmbedPreeditText" method call of
+ * the org.freedesktop.IBus interface.
+ */
+static gboolean
+_ibus_set_embed_preedit_text (BusIBusImpl     *ibus,
+                              GDBusConnection *connection,
+                              GVariant        *value,
+                              GError         **error)
+{
+    if (error) {
+        *error = NULL;
+    }
+
+    ibus->embed_preedit_text = g_variant_get_boolean (value);
+
+    return TRUE;
+}
+
 /**
  * bus_ibus_impl_service_method_call:
  *
- * Handle a D-Bus method call whose destination and interface name are both "org.freedesktop.IBus"
+ * Handle a D-Bus method call whose destination and interface name are
+ * both "org.freedesktop.IBus"
  */
 static void
 bus_ibus_impl_service_method_call (IBusService           *service,
@@ -1294,7 +1370,8 @@ bus_ibus_impl_service_method_call (IBusService           *service,
 {
     if (g_strcmp0 (interface_name, "org.freedesktop.IBus") != 0) {
         IBUS_SERVICE_CLASS (bus_ibus_impl_parent_class)->service_method_call (
-                        service, connection, sender, object_path, interface_name, method_name,
+                        service, connection, sender, object_path,
+                        interface_name, method_name,
                         parameters, invocation);
         return;
     }
@@ -1325,13 +1402,164 @@ bus_ibus_impl_service_method_call (IBusService           *service,
     gint i;
     for (i = 0; i < G_N_ELEMENTS (methods); i++) {
         if (g_strcmp0 (methods[i].method_name, method_name) == 0) {
-            methods[i].method_callback ((BusIBusImpl *) service, parameters, invocation);
+            methods[i].method_callback ((BusIBusImpl *) service,
+                                        parameters,
+                                        invocation);
             return;
         }
     }
 
-    /* notreached - unknown method calls that are not in the introspection_xml should be handled by the GDBus library. */
-    g_return_if_reached ();
+    g_warning ("service_method_call received an unknown method: %s",
+               method_name ? method_name : "(null)");
+}
+
+/**
+ * bus_ibus_impl_service_get_property:
+ *
+ * Handle org.freedesktop.DBus.Properties.Get
+ */
+static GVariant *
+bus_ibus_impl_service_get_property (IBusService     *service,
+                                    GDBusConnection *connection,
+                                    const gchar     *sender,
+                                    const gchar     *object_path,
+                                    const gchar     *interface_name,
+                                    const gchar     *property_name,
+                                    GError         **error)
+{
+    gint i;
+
+    static const struct {
+        const gchar *method_name;
+        GVariant * (* method_callback) (BusIBusImpl *,
+                                        GDBusConnection *,
+                                        GError **);
+    } methods [] =  {
+        { "EmbedPreeditText",      _ibus_get_embed_preedit_text },
+    };
+
+    if (g_strcmp0 (interface_name, IBUS_INTERFACE_IBUS) != 0) {
+        return IBUS_SERVICE_CLASS (
+                bus_ibus_impl_parent_class)->service_get_property (
+                        service, connection, sender, object_path,
+                        interface_name, property_name,
+                        error);
+    }
+
+    for (i = 0; i < G_N_ELEMENTS (methods); i++) {
+        if (g_strcmp0 (methods[i].method_name, property_name) == 0) {
+            return methods[i].method_callback ((BusIBusImpl *) service,
+                                               connection,
+                                               error);
+        }
+    }
+
+    g_warning ("service_get_property received an unknown property: %s",
+               property_name ? property_name : "(null)");
+    return NULL;
+}
+
+static void
+_emit_properties_changed (BusIBusImpl     *service,
+                          GDBusConnection *connection,
+                          const gchar     *object_path,
+                          const gchar     *interface_name,
+                          const gchar     *property_name,
+                          GVariant        *value,
+                          gboolean         is_changed)
+{
+    GVariantBuilder *builder;
+    GVariantBuilder *invalidated_builder;
+    GError *error = NULL;
+
+    builder = g_variant_builder_new (G_VARIANT_TYPE_ARRAY);
+    invalidated_builder = g_variant_builder_new (G_VARIANT_TYPE ("as"));
+
+    if (is_changed) {
+        g_variant_builder_add (builder, "{sv}", property_name, value);
+    } else {
+        g_variant_builder_add (invalidated_builder, "s", property_name);
+    }
+
+    g_dbus_connection_emit_signal (connection,
+                                   NULL,
+                                   object_path,
+                                   "org.freedesktop.DBus.Properties",
+                                   "PropertiesChanged",
+                                   g_variant_new ("(sa{sv}as)",
+                                                  interface_name,
+                                                  builder,
+                                                  invalidated_builder),
+                                   &error);
+
+    if (error) {
+        g_warning ("Failed to emit property %s in %s.%s: %s",
+                   property_name,
+                   "org.freedesktop.DBus.Properties",
+                   "PropertiesChanged",
+                   error->message);
+        g_error_free (error);
+    }
+}
+
+/**
+ * bus_ibus_impl_service_set_property:
+ *
+ * Handle org.freedesktop.DBus.Properties.Set
+ */
+static gboolean
+bus_ibus_impl_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)
+{
+    gint i;
+
+    static const struct {
+        const gchar *method_name;
+        gboolean (* method_callback) (BusIBusImpl *,
+                                      GDBusConnection *,
+                                      GVariant *,
+                                      GError **);
+    } methods [] =  {
+        { "EmbedPreeditText",      _ibus_set_embed_preedit_text },
+    };
+
+    if (g_strcmp0 (interface_name, IBUS_INTERFACE_IBUS) != 0) {
+        return IBUS_SERVICE_CLASS (
+                bus_ibus_impl_parent_class)->service_set_property (
+                        service, connection, sender, object_path,
+                        interface_name, property_name,
+                        value, error);
+    }
+
+    for (i = 0; i < G_N_ELEMENTS (methods); i++) {
+        if (g_strcmp0 (methods[i].method_name, property_name) == 0) {
+            gboolean retval = methods[i].method_callback (
+                    (BusIBusImpl *) service,
+                    connection,
+                    value,
+                    error);
+
+            _emit_properties_changed ((BusIBusImpl *) service,
+                                      connection,
+                                      object_path,
+                                      interface_name,
+                                      property_name,
+                                      value,
+                                      retval);
+
+            return retval;
+        }
+    }
+
+    g_warning ("service_set_property received an unknown property: %s",
+               property_name ? property_name : "(null)");
+    return FALSE;
 }
 
 BusIBusImpl *
index 66a84866666d614c049ccbb4196af64900edcd8f..5fa03c3cf145783481c3795ff304f2023b9e5b8e 100644 (file)
@@ -2068,6 +2068,60 @@ ibus_bus_preload_engines_async_finish (IBusBus       *bus,
     return _async_finish_void (res, error);
 }
 
+GVariant *
+ibus_bus_get_ibus_property (IBusBus     *bus,
+                            const gchar *property_name)
+{
+    GVariant *result;
+    GVariant *retval = NULL;
+
+    g_return_val_if_fail (IBUS_IS_BUS (bus), NULL);
+    g_return_val_if_fail (property_name != NULL, NULL);
+
+    result = ibus_bus_call_sync (bus,
+                                 IBUS_SERVICE_IBUS,
+                                 IBUS_PATH_IBUS,
+                                 "org.freedesktop.DBus.Properties",
+                                 "Get",
+                                 g_variant_new ("(ss)",
+                                                IBUS_INTERFACE_IBUS,
+                                                property_name),
+                                 G_VARIANT_TYPE ("(v)"));
+
+    if (result) {
+        g_variant_get (result, "(v)", &retval);
+        g_variant_unref (result);
+    }
+
+    return retval;
+}
+
+void
+ibus_bus_set_ibus_property (IBusBus     *bus,
+                            const gchar *property_name,
+                            GVariant    *value)
+{
+    GVariant *result;
+
+    g_return_if_fail (IBUS_IS_BUS (bus));
+    g_return_if_fail (property_name != NULL);
+
+    result = ibus_bus_call_sync (bus,
+                                 IBUS_SERVICE_IBUS,
+                                 IBUS_PATH_IBUS,
+                                 "org.freedesktop.DBus.Properties",
+                                 "Set",
+                                 g_variant_new ("(ssv)",
+                                                IBUS_INTERFACE_IBUS,
+                                                property_name,
+                                                value),
+                                 NULL);
+
+    if (result) {
+        g_variant_unref (result);
+    }
+}
+
 static GVariant *
 ibus_bus_call_sync (IBusBus            *bus,
                     const gchar        *bus_name,
index 12883177e636217a37406fe2112169eab44427ce..6344337cfaa3f0de928572416777f41f757f7e7d 100644 (file)
@@ -1043,5 +1043,29 @@ gboolean     ibus_bus_preload_engines_async_finish
                                          GAsyncResult   *res,
                                          GError        **error);
 
+/**
+ * ibus_bus_get_ibus_property:
+ * @bus: An #IBusBus.
+ * @property_name: property name in org.freedesktop.DBus.Properties.Get
+ * @returns: (transfer full): The value in org.freedesktop.DBus.Properties.Get
+ *           The returned value must be freed with g_variant_unref().
+ *
+ * Get org.freedesktop.DBus.Properties.
+ */
+GVariant *   ibus_bus_get_ibus_property (IBusBus        *bus,
+                                         const gchar    *property_name);
+
+/**
+ * ibus_bus_set_ibus_property:
+ * @bus: An #IBusBus.
+ * @property_name: property name in org.freedesktop.DBus.Properties.Set
+ * @value: value in org.freedesktop.DBus.Properties.Set
+ *
+ * Set org.freedesktop.DBus.Properties.
+ */
+void         ibus_bus_set_ibus_property (IBusBus        *bus,
+                                         const gchar    *property_name,
+                                         GVariant       *value);
+
 G_END_DECLS
 #endif
index 0d7a5b2f116d2c8e3ba625ee1e0353509a90f871..8090a4289e4cbffcc114334f7808e7e534c79fc3 100644 (file)
@@ -282,6 +282,22 @@ class Panel : IBus.PanelService {
         m_use_system_keyboard_layout = var_use_system_kbd_layout.get_boolean();
     }
 
+    private void set_embed_preedit_text(Variant? variant) {
+        Variant var_embed_preedit = variant;
+
+        if (var_embed_preedit == null) {
+            var_embed_preedit = m_config.get_value("general",
+                                                   "embed_preedit_text");
+        }
+
+        if (var_embed_preedit == null) {
+            return;
+        }
+
+        m_bus.set_ibus_property("EmbedPreeditText",
+                                var_embed_preedit);
+    }
+
     public void set_config(IBus.Config config) {
         if (m_config != null) {
             m_config.value_changed.disconnect(config_value_changed_cb);
@@ -293,6 +309,7 @@ class Panel : IBus.PanelService {
         if (m_config != null) {
             m_config.value_changed.connect(config_value_changed_cb);
             m_config.watch("general", "preload_engines");
+            m_config.watch("general", "embed_preedit_text");
             m_config.watch("general", "engines_order");
             m_config.watch("general", "switcher_delay_time");
             m_config.watch("general", "use_system_keyboard_layout");
@@ -307,6 +324,7 @@ class Panel : IBus.PanelService {
             unbind_switch_shortcut();
             bind_switch_shortcut(null);
             set_switcher_delay_time(null);
+            set_embed_preedit_text(null);
         } else {
             update_engines(null, null);
         }
@@ -408,6 +426,11 @@ class Panel : IBus.PanelService {
             set_use_system_keyboard_layout(variant);
             return;
         }
+
+        if (section == "general" && name == "embed_preedit_text") {
+            set_embed_preedit_text(variant);
+            return;
+        }
     }
 
     private void handle_engine_switch(Gdk.Event event, bool revert) {