Notify engines of the content-type of input context
authorDaiki Ueno <ueno@unixuser.org>
Wed, 14 Aug 2013 11:29:45 +0000 (13:29 +0200)
committerDaiki Ueno <ueno@unixuser.org>
Wed, 14 Aug 2013 11:29:45 +0000 (13:29 +0200)
Add a new D-Bus method SetContentType to InputContext and Engine, to
notify engines of the content-type (primary purpose and hints) of
input context.  This is useful to implement intelligent features in
engines, such as automatic input-mode switch and text prediction.

The "purpose" and "hints" arguments are compatible with
GtkInputPurpose and GtkInputHints:
https://developer.gnome.org/gtk3/unstable/GtkEntry.html#GtkInputPurpose
https://developer.gnome.org/gtk3/unstable/GtkEntry.html#GtkInputHints

and the API is similar to the content_type event in the Wayland Input
Method Framework:
http://cgit.freedesktop.org/wayland/weston/tree/protocol/input-method.xml#n202

BUG=

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

bus/engineproxy.c
bus/engineproxy.h
bus/inputcontext.c
client/gtk2/ibusimcontext.c
src/ibusengine.c
src/ibusengine.h
src/ibusinputcontext.c
src/ibusinputcontext.h
src/ibustypes.h

index 200b89b..19c2861 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
@@ -642,8 +642,7 @@ bus_engine_proxy_new_internal (const gchar     *path,
     g_assert (IBUS_IS_ENGINE_DESC (desc));
     g_assert (G_IS_DBUS_CONNECTION (connection));
 
-    GDBusProxyFlags flags = G_DBUS_PROXY_FLAGS_DO_NOT_AUTO_START |
-                            G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES;
+    GDBusProxyFlags flags = G_DBUS_PROXY_FLAGS_DO_NOT_AUTO_START;
     BusEngineProxy *engine =
         (BusEngineProxy *) g_initable_new (BUS_TYPE_ENGINE_PROXY,
                                            NULL,
@@ -1134,6 +1133,39 @@ void bus_engine_proxy_set_surrounding_text (BusEngineProxy *engine,
     }
 }
 
+void
+bus_engine_proxy_set_content_type (BusEngineProxy *engine,
+                                   guint           purpose,
+                                   guint           hints)
+{
+    g_assert (BUS_IS_ENGINE_PROXY (engine));
+
+    GVariant *cached_content_type =
+        g_dbus_proxy_get_cached_property ((GDBusProxy *) engine,
+                                          "ContentType");
+    GVariant *content_type = g_variant_new ("(uu)", purpose, hints);
+
+    g_variant_ref_sink (content_type);
+    if (cached_content_type == NULL ||
+        !g_variant_equal (content_type, cached_content_type)) {
+        g_dbus_proxy_call ((GDBusProxy *) engine,
+                           "org.freedesktop.DBus.Properties.Set",
+                           g_variant_new ("(ssv)",
+                                          IBUS_INTERFACE_ENGINE,
+                                          "ContentType",
+                                          content_type),
+                           G_DBUS_CALL_FLAGS_NONE,
+                           -1,
+                           NULL,
+                           NULL,
+                           NULL);
+    }
+
+    if (cached_content_type != NULL)
+        g_variant_unref (cached_content_type);
+    g_variant_unref (content_type);
+}
+
 /* a macro to generate a function to call a nullary D-Bus method. */
 #define DEFINE_FUNCTION(Name, name)                         \
     void                                                    \
index 8fe025d..528e61b 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
@@ -49,7 +49,7 @@ G_BEGIN_DECLS
 typedef struct _BusEngineProxy BusEngineProxy;
 typedef struct _BusEngineProxyClass BusEngineProxyClass;
 
-GType            bus_engine_proxy_get_type          (void);
+GType           bus_engine_proxy_get_type    (void);
 
 /**
  * bus_engine_proxy_new:
@@ -59,196 +59,271 @@ GType            bus_engine_proxy_get_type          (void);
  * @callback: a function to be called when the method invocation is done.
  * @user_data: a pointer that will be passed to the callback.
  */
-void             bus_engine_proxy_new               (IBusEngineDesc        *desc,
-                                                     gint                   timeout,
-                                                     GCancellable          *cancellable,
-                                                     GAsyncReadyCallback    callback,
-                                                     gpointer               user_data);
+void            bus_engine_proxy_new         (IBusEngineDesc     *desc,
+                                              gint                timeout,
+                                              GCancellable       *cancellable,
+                                              GAsyncReadyCallback callback,
+                                              gpointer            user_data);
 
 /**
  * bus_engine_proxy_new_finish:
- * @returns: On success, return an engine object. On error, return NULL.
+ * @res: A #GAsyncResult.
+ * @error: Return location for error or %NULL.
+ * @returns: On success, return an engine object. On error, return %NULL.
  *
- * Get the result of bus_engine_proxy_new call. You have to call this function in the GAsyncReadyCallback function.
+ * Get the result of bus_engine_proxy_new() call. You have to call this
+ * function in the #GAsyncReadyCallback function.
  */
-BusEngineProxy  *bus_engine_proxy_new_finish        (GAsyncResult          *res,
-                                                     GError               **error);
+BusEngineProxy *bus_engine_proxy_new_finish  (GAsyncResult       *res,
+                                              GError            **error);
 
 /**
  * bus_engine_proxy_get_desc:
+ * @engine: A #BusEngineProxy.
  *
- * Get an IBusEngineDesc object associated with the engine.
+ * Get an #IBusEngineDesc object associated with the engine.
  */
-IBusEngineDesc  *bus_engine_proxy_get_desc          (BusEngineProxy        *engine);
+IBusEngineDesc *bus_engine_proxy_get_desc    (BusEngineProxy     *engine);
 
 /**
  * bus_engine_proxy_process_key_event:
- * @callback: a function to be called when the method invocation is done.
+ * @engine: A #BusEngineProxy.
+ * @keyval: Key symbol of the key press.
+ * @keycode: KeyCode of the key press.
+ * @state: Key modifier flags.
+ * @callback: A function to be called when the method invocation is done.
+ * @user_data: Data supplied to @callback.
  *
  * Call "ProcessKeyEvent" method of an engine asynchronously.
  */
-void             bus_engine_proxy_process_key_event (BusEngineProxy        *engine,
-                                                     guint                  keyval,
-                                                     guint                  keycode,
-                                                     guint                  state,
-                                                     GAsyncReadyCallback    callback,
-                                                     gpointer               user_data);
+void            bus_engine_proxy_process_key_event
+                                             (BusEngineProxy     *engine,
+                                              guint               keyval,
+                                              guint               keycode,
+                                              guint               state,
+                                              GAsyncReadyCallback callback,
+                                              gpointer            user_data);
 /**
  * bus_engine_proxy_set_cursor_location:
+ * @engine: A #BusEngineProxy.
+ * @x: X coordinate of the cursor.
+ * @y: Y coordinate of the cursor.
+ * @w: Width of the cursor.
+ * @h: Height of the cursor.
  *
- * Call "SetCursorLocation" method of an engine asynchronously. Unlike bus_engine_proxy_process_key_event, there's no way to know the
- * result of the method invocation. If the same coordinate is given twice or more, the function does nothing from the second time.
+ * Call "SetCursorLocation" method of an engine asynchronously. Unlike
+ * bus_engine_proxy_process_key_event(), there's no way to know the
+ * result of the method invocation. If the same coordinate is given
+ * twice or more, the function does nothing from the second time.
  */
-void             bus_engine_proxy_set_cursor_location
-                                                    (BusEngineProxy        *engine,
-                                                     gint                   x,
-                                                     gint                   y,
-                                                     gint                   w,
-                                                     gint                   h);
+void            bus_engine_proxy_set_cursor_location
+                                             (BusEngineProxy     *engine,
+                                              gint                x,
+                                              gint                y,
+                                              gint                w,
+                                              gint                h);
 /**
  * bus_engine_proxy_focus_in:
+ * @engine: A #BusEngineProxy.
  *
- * Call "FocusIn" method of an engine asynchronously. Do nothing if the engine already has a focus.
+ * Call "FocusIn" method of an engine asynchronously. Do nothing if
+ * the engine already has a focus.
  */
-void             bus_engine_proxy_focus_in          (BusEngineProxy        *engine);
+void            bus_engine_proxy_focus_in    (BusEngineProxy     *engine);
 
 /**
  * bus_engine_proxy_focus_out:
+ * @engine: A #BusEngineProxy.
  *
- * Call "FocusOut" method of an engine asynchronously. Do nothing if the engine does not have a focus.
+ * Call "FocusOut" method of an engine asynchronously. Do nothing if
+ * the engine does not have a focus.
  */
-void             bus_engine_proxy_focus_out         (BusEngineProxy        *engine);
+void            bus_engine_proxy_focus_out   (BusEngineProxy     *engine);
 
 /**
  * bus_engine_proxy_reset:
+ * @engine: A #BusEngineProxy.
  *
  * Call "Reset" method of an engine asynchronously.
  */
-void             bus_engine_proxy_reset             (BusEngineProxy        *engine);
+void            bus_engine_proxy_reset       (BusEngineProxy     *engine);
 
 /**
  * bus_engine_proxy_set_capabilities:
+ * @engine: A #BusEngineProxy.
+ * @caps: Capabilities flags of IBusEngine, see #IBusCapabilite.
  *
  * Call "SetCapabilities" method of an engine asynchronously.
  */
-void             bus_engine_proxy_set_capabilities  (BusEngineProxy        *engine,
-                                                     guint                  caps);
+void            bus_engine_proxy_set_capabilities
+                                             (BusEngineProxy     *engine,
+                                              guint               caps);
 /**
  * bus_engine_proxy_page_up:
+ * @engine: A #BusEngineProxy.
  *
  * Call "PageUp" method of an engine asynchronously.
  */
-void             bus_engine_proxy_page_up           (BusEngineProxy        *engine);
+void            bus_engine_proxy_page_up     (BusEngineProxy     *engine);
 
 /**
  * bus_engine_proxy_page_down:
+ * @engine: A #BusEngineProxy.
  *
  * Call "PageDown" method of an engine asynchronously.
  */
-void             bus_engine_proxy_page_down         (BusEngineProxy        *engine);
+void            bus_engine_proxy_page_down   (BusEngineProxy     *engine);
 
 /**
  * bus_engine_proxy_cursor_up:
+ * @engine: A #BusEngineProxy.
  *
  * Call "CursorUp" method of an engine asynchronously.
  */
-void             bus_engine_proxy_cursor_up         (BusEngineProxy        *engine);
+void            bus_engine_proxy_cursor_up   (BusEngineProxy     *engine);
 
 /**
  * bus_engine_proxy_cursor_down:
+ * @engine: A #BusEngineProxy.
  *
  * Call "CursorDown" method of an engine asynchronously.
  */
-void             bus_engine_proxy_cursor_down       (BusEngineProxy        *engine);
+void            bus_engine_proxy_cursor_down (BusEngineProxy     *engine);
 
 /**
  * bus_engine_proxy_candidate_clicked:
+ * @engine: A #BusEngineProxy.
+ * @index:  Index of candidate be clicked.
+ * @button: Mouse button.
+ * @state:  Keyboard state.
  *
  * Call "CandidateClicked" method of an engine asynchronously.
  */
-void             bus_engine_proxy_candidate_clicked (BusEngineProxy        *engine,
-                                                     guint                  index,
-                                                     guint                  button,
-                                                     guint                  state);
+void            bus_engine_proxy_candidate_clicked
+                                             (BusEngineProxy     *engine,
+                                              guint               index,
+                                              guint               button,
+                                              guint               state);
 /**
  * bus_engine_proxy_enable:
+ * @engine: A #BusEngineProxy.
  *
- * Call "Enable" method of an engine asynchronously. Do nothing if the engine is already enabled.
+ * Call "Enable" method of an engine asynchronously. Do nothing if the
+ * engine is already enabled.
  */
-void             bus_engine_proxy_enable            (BusEngineProxy        *engine);
+void            bus_engine_proxy_enable      (BusEngineProxy     *engine);
 
 /**
  * bus_engine_proxy_disable:
+ * @engine: A #BusEngineProxy.
  *
- * Call "Disable" method of an engine asynchronously. Do nothing if the engine is already disabled.
+ * Call "Disable" method of an engine asynchronously. Do nothing if
+ * the engine is already disabled.
  */
-void             bus_engine_proxy_disable           (BusEngineProxy        *engine);
+void            bus_engine_proxy_disable     (BusEngineProxy     *engine);
 
 /**
  * bus_engine_proxy_property_activate:
+ * @engine: A #BusEngineProxy.
+ * @name: Property name.
+ * @state: Property state.
  *
  * Call "PropertyActivate" method of an engine asynchronously.
  */
-void             bus_engine_proxy_property_activate (BusEngineProxy        *engine,
-                                                     const gchar           *prop_name,
-                                                     guint                  state);
+void            bus_engine_proxy_property_activate
+                                             (BusEngineProxy     *engine,
+                                              const gchar        *prop_name,
+                                              guint               state);
 /**
  * bus_engine_proxy_property_show:
+ * @engine: A #BusEngineProxy.
+ * @prop_name: Property name.
  *
  * Call "PropertyShow" method of an engine asynchronously.
  */
-void             bus_engine_proxy_property_show     (BusEngineProxy        *engine,
-                                                     const gchar           *prop_name);
+void            bus_engine_proxy_property_show
+                                             (BusEngineProxy     *engine,
+                                              const gchar        *prop_name);
 /**
  * bus_engine_proxy_property_hide:
+ * @engine: A #BusEngineProxy.
+ * @prop_name: Property name.
  *
  * Call "PropertyHide" method of an engine asynchronously.
  */
-void             bus_engine_proxy_property_hide     (BusEngineProxy *engine,
-                                                     const gchar    *prop_name);
+void            bus_engine_proxy_property_hide
+                                             (BusEngineProxy     *engine,
+                                              const gchar        *prop_name);
 /**
  * bus_engine_proxy_is_enabled:
- * @returns: TRUE if the engine is enabled.
+ * @engine: A #BusEngineProxy.
+ * @returns: %TRUE if the engine is enabled.
  */
-gboolean         bus_engine_proxy_is_enabled        (BusEngineProxy *engine);
+gboolean        bus_engine_proxy_is_enabled  (BusEngineProxy     *engine);
 
 /**
  * bus_engine_proxy_set_surrounding_text:
+ * @engine: A #BusEngineProxy.
+ * @text: The surrounding text.
+ * @cursor_pos: The cursor position on surrounding text.
+ * @anchor_pos: The anchor position on selection area.
  *
  * Call "SetSurroundingText" method of an engine asynchronously.
  */
-void             bus_engine_proxy_set_surrounding_text
-                                                    (BusEngineProxy *engine,
-                                                     IBusText       *text,
-                                                     guint           cursor_pos,
-                                                     guint           anchor_pos);
+void            bus_engine_proxy_set_surrounding_text
+                                             (BusEngineProxy     *engine,
+                                              IBusText           *text,
+                                              guint               cursor_pos,
+                                              guint               anchor_pos);
 
 /**
  * bus_engine_proxy_process_hand_writing_event:
+ * @engine: A #BusEngineProxy.
+ * @coordinates: A #GVariant containing an array of coordinates.
  *
- * Call "ProcessHandWritingEvent" method of an engine asynchronously. The type of the GVariant should be "(ad)".
- * See ibus_input_context_process_hand_writing_event for details.
+ * Call "ProcessHandWritingEvent" method of an engine
+ * asynchronously. The type of the GVariant should be "(ad)".  See
+ * ibus_input_context_process_hand_writing_event() for details.
  */
-void             bus_engine_proxy_process_hand_writing_event
-                                                    (BusEngineProxy        *engine,
-                                                     GVariant              *coordinates);
+void            bus_engine_proxy_process_hand_writing_event
+                                             (BusEngineProxy     *engine,
+                                              GVariant           *coordinates);
 
 /**
  * bus_engine_proxy_cancel_hand_writing:
+ * @engine: A #BusEngineProxy.
+ * @n_strokes: The number of strokes to be removed. 0 means "remove all".
  *
  * Call "CancelHandWriting" method of an engine asynchronously.
- * See ibus_input_context_cancel_hand_writing for details.
+ * See ibus_input_context_cancel_hand_writing() for details.
+ */
+void            bus_engine_proxy_cancel_hand_writing
+                                             (BusEngineProxy     *engine,
+                                              guint               n_strokes);
+
+/**
+ * bus_engine_proxy_set_content_type:
+ * @engine: A #BusEngineProxy.
+ * @purpose: Primary purpose of the input context, as an #IBusInputPurpose.
+ * @hints: Hints that augment @purpose, as an #IBusInputHints.
+ *
+ * Call "SetContentType" method of an engine asynchronously.
+ * See ibus_input_context_set_content_type() for details.
  */
-void             bus_engine_proxy_cancel_hand_writing
-                                                    (BusEngineProxy        *engine,
-                                                     guint                  n_strokes);
+void            bus_engine_proxy_set_content_type
+                                             (BusEngineProxy     *engine,
+                                              guint               purpose,
+                                              guint               hints);
 
 /**
  * bus_engine_proxy_get_properties:
+ * @engine: A #BusEngineProxy.
+ * @returns: An #IBusPropList.
  *
- * Get an IBusPropList object associated with the engine.
+ * Get an #IBusPropList object associated with the engine.
  */
-IBusPropList    *bus_engine_proxy_get_properties    (BusEngineProxy        *engine);
+IBusPropList   *bus_engine_proxy_get_properties
+                                             (BusEngineProxy     *engine);
 
 G_END_DECLS
 #endif
index d7ada6e..a2d1d52 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
@@ -89,6 +89,10 @@ struct _BusInputContext {
 
     /* incompleted set engine by desc request */
     SetEngineByDescData *data;
+
+    /* content-type (primary purpose and hints) */
+    guint    purpose;
+    guint    hints;
 };
 
 struct _BusInputContextClass {
@@ -132,69 +136,83 @@ typedef struct _BusInputContextPrivate BusInputContextPrivate;
 static guint    context_signals[LAST_SIGNAL] = { 0 };
 
 /* functions prototype */
-static void     bus_input_context_destroy       (BusInputContext        *context);
+static void     bus_input_context_destroy
+                                   (BusInputContext       *context);
 static void     bus_input_context_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_input_context_unset_engine  (BusInputContext        *context);
-static void     bus_input_context_commit_text   (BusInputContext        *context,
-                                                 IBusText               *text);
+                                   (IBusService           *service,
+                                    GDBusConnection       *connection,
+                                    const gchar           *sender,
+                                    const gchar           *object_path,
+                                    const gchar           *interface_name,
+                                    const gchar           *method_name,
+                                    GVariant              *parameters,
+                                    GDBusMethodInvocation *invocation);
+static gboolean bus_input_context_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_input_context_unset_engine
+                                   (BusInputContext       *context);
+static void     bus_input_context_commit_text
+                                   (BusInputContext       *context,
+                                    IBusText              *text);
 static void     bus_input_context_update_preedit_text
-                                                (BusInputContext        *context,
-                                                 IBusText               *text,
-                                                 guint                   cursor_pos,
-                                                 gboolean                visible,
-                                                 guint                   mode);
+                                   (BusInputContext       *context,
+                                    IBusText              *text,
+                                    guint                  cursor_pos,
+                                    gboolean               visible,
+                                    guint                  mode);
 static void     bus_input_context_show_preedit_text
-                                                (BusInputContext        *context);
+                                   (BusInputContext       *context);
 static void     bus_input_context_hide_preedit_text
-                                                (BusInputContext        *context);
+                                   (BusInputContext       *context);
 static void     bus_input_context_update_auxiliary_text
-                                                (BusInputContext        *context,
-                                                 IBusText               *text,
-                                                 gboolean                visible);
+                                   (BusInputContext       *context,
+                                    IBusText              *text,
+                                    gboolean               visible);
 static void     bus_input_context_show_auxiliary_text
-                                                (BusInputContext        *context);
+                                   (BusInputContext       *context);
 static void     bus_input_context_hide_auxiliary_text
-                                                (BusInputContext        *context);
+                                   (BusInputContext       *context);
 static void     bus_input_context_update_lookup_table
-                                                (BusInputContext        *context,
-                                                 IBusLookupTable        *table,
-                                                 gboolean                visible);
+                                   (BusInputContext       *context,
+                                    IBusLookupTable       *table,
+                                    gboolean               visible);
 static void     bus_input_context_show_lookup_table
-                                                (BusInputContext        *context);
+                                   (BusInputContext       *context);
 static void     bus_input_context_hide_lookup_table
-                                                (BusInputContext        *context);
+                                   (BusInputContext       *context);
 static void     bus_input_context_page_up_lookup_table
-                                                (BusInputContext        *context);
+                                   (BusInputContext       *context);
 static void     bus_input_context_page_down_lookup_table
-                                                (BusInputContext        *context);
+                                   (BusInputContext       *context);
 static void     bus_input_context_cursor_up_lookup_table
-                                                (BusInputContext        *context);
+                                   (BusInputContext       *context);
 static void     bus_input_context_cursor_down_lookup_table
-                                                (BusInputContext        *context);
+                                   (BusInputContext       *context);
 static void     bus_input_context_register_properties
-                                                (BusInputContext        *context,
-                                                 IBusPropList           *props);
+                                   (BusInputContext       *context,
+                                    IBusPropList          *props);
 static void     bus_input_context_update_property
-                                                (BusInputContext        *context,
-                                                 IBusProperty           *prop);
-static void     _engine_destroy_cb              (BusEngineProxy         *factory,
-                                                 BusInputContext        *context);
+                                   (BusInputContext       *context,
+                                    IBusProperty          *prop);
+static void     _engine_destroy_cb (BusEngineProxy        *factory,
+                                    BusInputContext       *context);
 
 static IBusText *text_empty = NULL;
 static IBusLookupTable *lookup_table_empty = NULL;
 static IBusPropList    *props_empty = NULL;
 
-/* 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.) */
+/* 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>"
     "  <interface name='org.freedesktop.IBus.InputContext'>"
@@ -277,6 +295,9 @@ static const gchar introspection_xml[] =
     "    <signal name='UpdateProperty'>"
     "      <arg type='v' name='prop' />"
     "    </signal>"
+
+    /* properties */
+    "    <property name='ContentType' type='(uu)' access='write' />"
     "  </interface>"
     "</node>";
 
@@ -316,7 +337,10 @@ bus_input_context_class_init (BusInputContextClass *class)
     ibus_object_class->destroy = (IBusObjectDestroyFunc) bus_input_context_destroy;
 
     /* override the parent class's implementation. */
-    IBUS_SERVICE_CLASS (class)->service_method_call = bus_input_context_service_method_call;
+    IBUS_SERVICE_CLASS (class)->service_method_call =
+        bus_input_context_service_method_call;
+    IBUS_SERVICE_CLASS (class)->service_set_property =
+        bus_input_context_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. 'FocusIn'.) */
     ibus_service_class_add_interfaces (IBUS_SERVICE_CLASS (class), introspection_xml);
 
@@ -607,14 +631,9 @@ bus_input_context_destroy (BusInputContext *context)
     IBUS_OBJECT_CLASS (bus_input_context_parent_class)->destroy (IBUS_OBJECT (context));
 }
 
-/**
- * bus_input_context_emit_signal:
- * @signal_name: The D-Bus signal name to emit which is in the introspection_xml.
- *
- * Emit the D-Bus signal.
- */
 static gboolean
-bus_input_context_emit_signal (BusInputContext *context,
+bus_input_context_send_signal (BusInputContext *context,
+                               const gchar     *interface_name,
                                const gchar     *signal_name,
                                GVariant        *parameters,
                                GError         **error)
@@ -623,7 +642,7 @@ bus_input_context_emit_signal (BusInputContext *context,
         return TRUE;
 
     GDBusMessage *message = g_dbus_message_new_signal (ibus_service_get_object_path ((IBusService *)context),
-                                                       "org.freedesktop.IBus.InputContext",
+                                                       interface_name,
                                                        signal_name);
     g_dbus_message_set_sender (message, "org.freedesktop.IBus");
     g_dbus_message_set_destination (message, bus_connection_get_unique_name (context->connection));
@@ -639,6 +658,58 @@ bus_input_context_emit_signal (BusInputContext *context,
 }
 
 /**
+ * bus_input_context_emit_signal:
+ * @signal_name: The D-Bus signal name to emit which is in the introspection_xml.
+ *
+ * Emit the D-Bus signal.
+ */
+static gboolean
+bus_input_context_emit_signal (BusInputContext *context,
+                               const gchar     *signal_name,
+                               GVariant        *parameters,
+                               GError         **error)
+{
+    if (context->connection == NULL)
+        return TRUE;
+
+    return bus_input_context_send_signal (context,
+                                          "org.freedesktop.IBus.InputContext",
+                                          signal_name,
+                                          parameters,
+                                          error);
+}
+
+/**
+ * bus_input_context_property_changed:
+ * @context: a #BusInputContext
+ * @property_name: The D-Bus property name which has changed
+ * @value: The new value of the property
+ *
+ * Emit the D-Bus "PropertiesChanged" signal for a property.
+ * Returns: %TRUE on success, %FALSE on failure
+ */
+static gboolean
+bus_input_context_property_changed (BusInputContext *context,
+                                    const gchar     *property_name,
+                                    GVariant        *value,
+                                    GError         **error)
+{
+    if (context->connection == NULL)
+        return TRUE;
+
+    GVariantBuilder *builder = g_variant_builder_new (G_VARIANT_TYPE_ARRAY);
+    g_variant_builder_add (builder, "{sv}", property_name, value);
+    return bus_input_context_send_signal (context,
+                                          "org.freedesktop.DBus.Properties",
+                                          "PropertiesChanged",
+                                          g_variant_new ("(sa{sv}as)",
+                                                         "org.freedesktop.IBus",
+                                                         builder,
+                                                         NULL),
+                                          error);
+}
+
+/**
  * _ic_process_key_event_reply_cb:
  *
  * A GAsyncReadyCallback function to be called when bus_engine_proxy_process_key_event() is finished.
@@ -948,11 +1019,6 @@ _ic_get_engine (BusInputContext       *context,
             g_variant_new ("(v)", ibus_serializable_serialize ((IBusSerializable *)desc)));
 }
 
-/**
- * bus_input_context_service_method_call:
- *
- * Handle a D-Bus method call whose destination and interface name are both "org.freedesktop.IBus.InputContext"
- */
 static void
 _ic_set_surrounding_text (BusInputContext       *context,
                           GVariant              *parameters,
@@ -985,6 +1051,11 @@ _ic_set_surrounding_text (BusInputContext       *context,
     g_dbus_method_invocation_return_value (invocation, NULL);
 }
 
+/**
+ * bus_input_context_service_method_call:
+ *
+ * Handle a D-Bus method call whose destination and interface name are both "org.freedesktop.IBus.InputContext"
+ */
 static void
 bus_input_context_service_method_call (IBusService            *service,
                                        GDBusConnection        *connection,
@@ -1024,7 +1095,7 @@ bus_input_context_service_method_call (IBusService            *service,
         { "PropertyActivate",  _ic_property_activate },
         { "SetEngine",         _ic_set_engine },
         { "GetEngine",         _ic_get_engine },
-        { "SetSurroundingText", _ic_set_surrounding_text},
+        { "SetSurroundingText", _ic_set_surrounding_text }
     };
 
     gint i;
@@ -1038,6 +1109,63 @@ bus_input_context_service_method_call (IBusService            *service,
     g_return_if_reached ();
 }
 
+static gboolean
+bus_input_context_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)
+{
+    if (g_strcmp0 (interface_name, IBUS_INTERFACE_INPUT_CONTEXT) != 0) {
+        return IBUS_SERVICE_CLASS (bus_input_context_parent_class)->
+            service_set_property (service,
+                                  connection,
+                                  sender,
+                                  object_path,
+                                  interface_name,
+                                  property_name,
+                                  value,
+                                  error);
+    }
+
+    if (g_strcmp0 (property_name, "ContentType") == 0) {
+        BusInputContext *context = (BusInputContext *) service;
+        guint purpose = 0;
+        guint hints = 0;
+
+        g_variant_get (value, "(uu)", &purpose, &hints);
+        if (purpose != context->purpose || hints != context->hints) {
+            GError *error;
+            gboolean retval;
+
+            context->purpose = purpose;
+            context->hints = hints;
+
+            if (context->has_focus && context->engine)
+                bus_engine_proxy_set_content_type (context->engine,
+                                                   purpose,
+                                                   hints);
+
+            error = NULL;
+            retval = bus_input_context_property_changed (context,
+                                                         "ContentType",
+                                                         value,
+                                                         &error);
+            if (!retval) {
+                g_warning ("Failed to emit PropertiesChanged signal: %s",
+                           error->message);
+                g_error_free (error);
+            }
+        }
+        return TRUE;
+    }
+
+    g_return_val_if_reached (FALSE);
+}
+
 gboolean
 bus_input_context_has_focus (BusInputContext *context)
 {
@@ -1066,6 +1194,7 @@ bus_input_context_focus_in (BusInputContext *context)
         bus_engine_proxy_enable (context->engine);
         bus_engine_proxy_set_capabilities (context->engine, context->capabilities);
         bus_engine_proxy_set_cursor_location (context->engine, context->x, context->y, context->w, context->h);
+        bus_engine_proxy_set_content_type (context->engine, context->purpose, context->hints);
     }
 
     if (context->capabilities & IBUS_CAP_FOCUS) {
@@ -1953,6 +2082,7 @@ bus_input_context_enable (BusInputContext *context)
     bus_engine_proxy_enable (context->engine);
     bus_engine_proxy_set_capabilities (context->engine, context->capabilities);
     bus_engine_proxy_set_cursor_location (context->engine, context->x, context->y, context->w, context->h);
+    bus_engine_proxy_set_content_type (context->engine, context->purpose, context->hints);
 }
 
 void
@@ -2057,6 +2187,7 @@ bus_input_context_set_engine (BusInputContext *context,
             bus_engine_proxy_enable (context->engine);
             bus_engine_proxy_set_capabilities (context->engine, context->capabilities);
             bus_engine_proxy_set_cursor_location (context->engine, context->x, context->y, context->w, context->h);
+            bus_engine_proxy_set_content_type (context->engine, context->purpose, context->hints);
         }
     }
     g_signal_emit (context,
index 340a645..5eb0414 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
@@ -95,6 +95,8 @@ static GtkWidget *_input_widget = NULL;
 static void     ibus_im_context_class_init  (IBusIMContextClass    *class);
 static void     ibus_im_context_class_fini  (IBusIMContextClass    *class);
 static void     ibus_im_context_init        (GObject               *obj);
+static void     ibus_im_context_notify      (GObject               *obj,
+                                             GParamSpec            *pspec);
 static void     ibus_im_context_finalize    (GObject               *obj);
 static void     ibus_im_context_reset       (GtkIMContext          *context);
 static gboolean ibus_im_context_filter_keypress
@@ -150,6 +152,7 @@ static gboolean _slave_delete_surrounding_cb
                                              IBusIMContext      *context);
 static void     _request_surrounding_text   (IBusIMContext      *context);
 static void     _create_fake_input_context  (void);
+static void     _set_content_type           (IBusIMContext      *context);
 
 
 
@@ -330,6 +333,26 @@ _request_surrounding_text (IBusIMContext *context)
     }
 }
 
+static void
+_set_content_type (IBusIMContext *context)
+{
+#if GTK_CHECK_VERSION (3, 6, 0)
+    if (context->ibuscontext != NULL) {
+        GtkInputPurpose purpose;
+        GtkInputHints hints;
+
+        g_object_get (G_OBJECT (context),
+                      "input-purpose", &purpose,
+                      "input-hints", &hints,
+                      NULL);
+
+        ibus_input_context_set_content_type (context->ibuscontext,
+                                             purpose,
+                                             hints);
+    }
+#endif
+}
+
 
 static gint
 _key_snooper_cb (GtkWidget   *widget,
@@ -499,6 +522,7 @@ ibus_im_context_class_init (IBusIMContextClass *class)
     im_context_class->set_cursor_location = ibus_im_context_set_cursor_location;
     im_context_class->set_use_preedit = ibus_im_context_set_use_preedit;
     im_context_class->set_surrounding = ibus_im_context_set_surrounding;
+    gobject_class->notify = ibus_im_context_notify;
     gobject_class->finalize = ibus_im_context_finalize;
 
     _signal_commit_id =
@@ -692,6 +716,18 @@ ibus_im_context_init (GObject *obj)
 }
 
 static void
+ibus_im_context_notify (GObject    *obj,
+                        GParamSpec *pspec)
+{
+    IDEBUG ("%s", __FUNCTION__);
+
+    if (g_strcmp0 (pspec->name, "input-purpose") == 0 ||
+        g_strcmp0 (pspec->name, "input-hints") == 0) {
+        _set_content_type (IBUS_IM_CONTEXT (obj));
+    }
+}
+
+static void
 ibus_im_context_finalize (GObject *obj)
 {
     IDEBUG ("%s", __FUNCTION__);
@@ -803,18 +839,6 @@ ibus_im_context_focus_in (GtkIMContext *context)
         return;
 
     /* don't set focus on password entry */
-#if GTK_CHECK_VERSION (3, 6, 0)
-    {
-        GtkInputPurpose purpose;
-
-        g_object_get (G_OBJECT (context),
-                      "input-purpose", &purpose,
-                      NULL);
-
-        if (purpose == GTK_INPUT_PURPOSE_PASSWORD)
-            return;
-    }
-#endif
     if (ibusimcontext->client_window != NULL) {
         GtkWidget *widget;
 
@@ -846,6 +870,8 @@ ibus_im_context_focus_in (GtkIMContext *context)
 
     gtk_im_context_focus_in (ibusimcontext->slave);
 
+    _set_content_type (ibusimcontext);
+
     /* set_cursor_location_internal() will get origin from X server,
      * it blocks UI. So delay it to idle callback. */
     gdk_threads_add_idle_full (G_PRIORITY_DEFAULT_IDLE,
index d1bbed7..6962949 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
@@ -49,6 +49,7 @@ enum {
     SET_SURROUNDING_TEXT,
     PROCESS_HAND_WRITING_EVENT,
     CANCEL_HAND_WRITING,
+    SET_CONTENT_TYPE,
     LAST_SIGNAL,
 };
 
@@ -68,6 +69,10 @@ struct _IBusEnginePrivate {
     IBusText *surrounding_text;
     guint surrounding_cursor_pos;
     guint selection_anchor_pos;
+
+    /* cached content-type */
+    guint content_purpose;
+    guint content_hints;
 };
 
 static guint            engine_signals[LAST_SIGNAL] = { 0 };
@@ -159,9 +164,17 @@ static void      ibus_engine_process_hand_writing_event
 static void      ibus_engine_cancel_hand_writing
                                              (IBusEngine         *engine,
                                               guint               n_strokes);
+static void      ibus_engine_set_content_type
+                                             (IBusEngine         *engine,
+                                              guint               purpose,
+                                              guint               hints);
 static void      ibus_engine_emit_signal     (IBusEngine         *engine,
                                               const gchar        *signal_name,
                                               GVariant           *parameters);
+static void      ibus_engine_dbus_property_changed
+                                             (IBusEngine         *engine,
+                                              const gchar        *property_name,
+                                              GVariant           *value);
 
 
 G_DEFINE_TYPE (IBusEngine, ibus_engine, IBUS_TYPE_SERVICE)
@@ -249,6 +262,8 @@ static const gchar introspection_xml[] =
     "      <arg type='u' name='keycode' />"
     "      <arg type='u' name='state' />"
     "    </signal>"
+    /* FIXME properties */
+    "    <property name='ContentType' type='(uu)' access='write' />"
     "  </interface>"
     "</node>";
 
@@ -289,6 +304,7 @@ ibus_engine_class_init (IBusEngineClass *class)
     class->process_hand_writing_event
                                 = ibus_engine_process_hand_writing_event;
     class->cancel_hand_writing  = ibus_engine_cancel_hand_writing;
+    class->set_content_type     = ibus_engine_set_content_type;
 
     /* install properties */
     /**
@@ -698,8 +714,6 @@ ibus_engine_class_init (IBusEngineClass *class)
             1,
             G_TYPE_UINT);
 
-    g_type_class_add_private (class, sizeof (IBusEnginePrivate));
-
     /**
      * IBusEngine::set-surrounding-text:
      * @engine: An IBusEngine.
@@ -727,6 +741,40 @@ ibus_engine_class_init (IBusEngineClass *class)
             G_TYPE_UINT,
             G_TYPE_UINT);
 
+    /**
+     * IBusEngine::set-content-type:
+     * @engine: An #IBusEngine.
+     * @purpose: Primary purpose of the input context, as an #IBusInputPurpose.
+     * @hints: Hints that augment @purpose, as an #IBusInputHints.
+     *
+     * Emitted when the client application content-type (primary
+     * purpose and hints) is set.  The engine could change the
+     * behavior according to the content-type.  Implement the member
+     * function set_content_type() in extended class to receive this
+     * signal.
+     *
+     * For example, if the client application wants to restrict input
+     * to numbers, this signal will be emitted with @purpose set to
+     * #IBUS_INPUT_PURPOSE_NUMBER, so the engine can switch the input
+     * mode to latin.
+     *
+     * <note><para>Argument @user_data is ignored in this
+     * function.</para></note>
+     */
+    engine_signals[SET_CONTENT_TYPE] =
+        g_signal_new (I_("set-content-type"),
+            G_TYPE_FROM_CLASS (gobject_class),
+            G_SIGNAL_RUN_LAST,
+            G_STRUCT_OFFSET (IBusEngineClass, set_content_type),
+            NULL, NULL,
+            _ibus_marshal_VOID__UINT_UINT,
+            G_TYPE_NONE,
+            2,
+            G_TYPE_UINT,
+            G_TYPE_UINT);
+
+    g_type_class_add_private (class, sizeof (IBusEnginePrivate));
+
     text_empty = ibus_text_new_from_static_string ("");
     g_object_ref_sink (text_empty);
 }
@@ -1004,15 +1052,43 @@ ibus_engine_service_set_property (IBusService        *service,
                                   GVariant           *value,
                                   GError            **error)
 {
-    return IBUS_SERVICE_CLASS (ibus_engine_parent_class)->
-                service_set_property (service,
-                                      connection,
-                                      sender,
-                                      object_path,
-                                      interface_name,
-                                      property_name,
-                                      value,
-                                      error);
+    IBusEngine *engine = IBUS_ENGINE (service);
+
+    if (g_strcmp0 (interface_name, IBUS_INTERFACE_ENGINE) != 0) {
+        return IBUS_SERVICE_CLASS (ibus_engine_parent_class)->
+            service_set_property (service,
+                                  connection,
+                                  sender,
+                                  object_path,
+                                  interface_name,
+                                  property_name,
+                                  value,
+                                  error);
+    }
+
+    if (g_strcmp0 (property_name, "ContentType") == 0) {
+        guint purpose = 0;
+        guint hints = 0;
+
+        g_variant_get (value, "(uu)", &purpose, &hints);
+        if (purpose != engine->priv->content_purpose ||
+            hints != engine->priv->content_hints) {
+            engine->priv->content_purpose = purpose;
+            engine->priv->content_hints = hints;
+
+            g_signal_emit (engine,
+                           engine_signals[SET_CONTENT_TYPE],
+                           0,
+                           purpose,
+                           hints);
+
+            ibus_engine_dbus_property_changed (engine, "ContentType", value);
+        }
+
+        return TRUE;
+    }
+
+    g_return_val_if_reached (FALSE);
 }
 
 static gboolean
@@ -1161,6 +1237,14 @@ ibus_engine_cancel_hand_writing (IBusEngine         *engine,
 }
 
 static void
+ibus_engine_set_content_type (IBusEngine *engine,
+                              guint       purpose,
+                              guint       hints)
+{
+    // g_debug ("set-content-type (%u %u)", purpose, hints);
+}
+
+static void
 ibus_engine_emit_signal (IBusEngine  *engine,
                          const gchar *signal_name,
                          GVariant    *parameters)
@@ -1173,6 +1257,52 @@ ibus_engine_emit_signal (IBusEngine  *engine,
                               NULL);
 }
 
+static void
+ibus_engine_dbus_property_changed (IBusEngine  *engine,
+                                   const gchar *property_name,
+                                   GVariant    *value)
+{
+    const gchar *object_path;
+    GDBusConnection *connection;
+    GDBusMessage *message;
+    GVariantBuilder *builder;
+    gboolean retval;
+    GError *error;
+
+    /* we cannot use ibus_service_emit_signal() here, since we need to
+       set sender of the signal so that GDBusProxy can properly track
+       the property change. */
+    object_path = ibus_service_get_object_path ((IBusService *)engine);
+    message = g_dbus_message_new_signal (object_path,
+                                         "org.freedesktop.DBus.Properties",
+                                         "PropertiesChanged");
+
+    g_dbus_message_set_sender (message, "org.freedesktop.IBus");
+
+    builder = g_variant_builder_new (G_VARIANT_TYPE_ARRAY);
+    g_variant_builder_add (builder, "{sv}", property_name, value);
+    g_dbus_message_set_body (message,
+                             g_variant_new ("(sa{sv}as)",
+                                            IBUS_INTERFACE_ENGINE,
+                                            builder,
+                                            NULL));
+
+    error = NULL;
+    connection = ibus_service_get_connection ((IBusService *)engine);
+    retval = g_dbus_connection_send_message (connection,
+                                             message,
+                                             G_DBUS_SEND_MESSAGE_FLAGS_NONE,
+                                             NULL,
+                                             &error);
+    if (!retval) {
+        g_warning ("Failed to emit PropertiesChanged signal: %s",
+                   error->message);
+        g_error_free (error);
+    }
+    g_object_unref (message);
+    return retval;
+}
+
 IBusEngine *
 ibus_engine_new (const gchar     *engine_name,
                  const gchar     *object_path,
@@ -1424,6 +1554,17 @@ ibus_engine_get_surrounding_text (IBusEngine   *engine,
 }
 
 void
+ibus_engine_get_content_type (IBusEngine *engine,
+                              guint      *purpose,
+                              guint      *hints)
+{
+    g_return_if_fail (IBUS_IS_ENGINE (engine));
+
+    *purpose = engine->priv->content_purpose;
+    *hints = engine->priv->content_hints;
+}
+
+void
 ibus_engine_register_properties (IBusEngine   *engine,
                                  IBusPropList *prop_list)
 {
index bae63d5..81b1d0e 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
@@ -73,6 +73,8 @@ typedef struct _IBusEnginePrivate IBusEnginePrivate;
  * @has_focus: Whether the engine has focus.
  * @cursor_area: Area of cursor.
  * @client_capabilities: IBusCapabilite (client capabilities) flags.
+ * @client_purpose: IBusInputPurpose (client input purpose).
+ * @client_hints: IBusInputHints (client input hints) flags.
  *
  * IBusEngine properties.
  */
@@ -148,10 +150,14 @@ struct _IBusEngineClass {
     void        (* cancel_hand_writing)
                                     (IBusEngine     *engine,
                                      guint           n_strokes);
+    void        (* set_content_type)
+                                    (IBusEngine     *engine,
+                                     guint           purpose,
+                                     guint           hints);
 
     /*< private >*/
     /* padding */
-    gpointer pdummy[5];
+    gpointer pdummy[4];
 };
 
 GType        ibus_engine_get_type       (void);
@@ -423,13 +429,28 @@ void ibus_engine_delete_surrounding_text(IBusEngine         *engine,
  * #IBusEngine::enable handler, with both @text and @cursor set to
  * %NULL.
  *
- * see_also #IBusEngine::set-surrounding-text
+ * See also: #IBusEngine::set-surrounding-text
  */
-void ibus_engine_get_surrounding_text(IBusEngine         *engine,
-                                      IBusText          **text,
-                                      guint              *cursor_pos,
-                                      guint              *anchor_pos);
+void ibus_engine_get_surrounding_text   (IBusEngine         *engine,
+                                         IBusText          **text,
+                                         guint              *cursor_pos,
+                                         guint              *anchor_pos);
+
 
+/**
+ * ibus_engine_get_content_type:
+ * @engine: An #IBusEngine.
+ * @purpose: (out) (allow-none): Primary purpose of the input context.
+ * @hints: (out) (allow-none): Hints that augument @purpose.
+ *
+ * Get content-type (primary purpose and hints) of the current input
+ * context.
+ *
+ * See also: #IBusEngine::set-content-type
+ */
+void ibus_engine_get_content_type       (IBusEngine         *engine,
+                                         guint              *purpose,
+                                         guint              *hints);
 
 /**
  * ibus_engine_get_name:
index ac7fffa..fb0c6e9 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
@@ -685,8 +685,7 @@ ibus_input_context_new (const gchar     *path,
 
     GInitable *initable;
 
-    GDBusProxyFlags flags = G_DBUS_PROXY_FLAGS_DO_NOT_AUTO_START |
-                            G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES;
+    GDBusProxyFlags flags = G_DBUS_PROXY_FLAGS_DO_NOT_AUTO_START;
 
     initable = g_initable_new (IBUS_TYPE_INPUT_CONTEXT,
                                cancellable,
@@ -714,8 +713,7 @@ ibus_input_context_new_async (const gchar         *path,
     g_assert (G_IS_DBUS_CONNECTION (connection));
     g_assert (callback != NULL);
 
-    GDBusProxyFlags flags = G_DBUS_PROXY_FLAGS_DO_NOT_AUTO_START |
-                            G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES;
+    GDBusProxyFlags flags = G_DBUS_PROXY_FLAGS_DO_NOT_AUTO_START;
 
     g_async_initable_new_async (IBUS_TYPE_INPUT_CONTEXT,
                                 G_PRIORITY_DEFAULT,
@@ -1058,6 +1056,40 @@ ibus_input_context_needs_surrounding_text (IBusInputContext *context)
 }
 
 void
+ibus_input_context_set_content_type (IBusInputContext *context,
+                                     guint             purpose,
+                                     guint             hints)
+{
+    g_assert (IBUS_IS_INPUT_CONTEXT (context));
+
+    GVariant *cached_content_type =
+        g_dbus_proxy_get_cached_property ((GDBusProxy *) context,
+                                          "ContentType");
+    GVariant *content_type = g_variant_new ("(uu)", purpose, hints);
+
+    g_variant_ref_sink (content_type);
+    if (cached_content_type == NULL ||
+        !g_variant_equal (content_type, cached_content_type)) {
+        g_dbus_proxy_call ((GDBusProxy *) context,
+                           "org.freedesktop.DBus.Properties.Set",
+                           g_variant_new ("(ssv)",
+                                          IBUS_INTERFACE_INPUT_CONTEXT,
+                                          "ContentType",
+                                          content_type),
+                           G_DBUS_CALL_FLAGS_NONE,
+                           -1,
+                           NULL, /* cancellable */
+                           NULL, /* callback */
+                           NULL  /* user_data */
+                           );
+    }
+
+    if (cached_content_type != NULL)
+        g_variant_unref (cached_content_type);
+    g_variant_unref (content_type);
+}
+
+void
 ibus_input_context_get_engine_async (IBusInputContext   *context,
                                      gint                timeout_msec,
                                      GCancellable       *cancellable,
index b87a7dc..0fd6ef8 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
@@ -448,5 +448,25 @@ void         ibus_input_context_set_surrounding_text
 gboolean     ibus_input_context_needs_surrounding_text
                                             (IBusInputContext   *context);
 
+/**
+ * ibus_input_context_set_content_type:
+ * @context: An #IBusInputContext.
+ * @purpose: Primary purpose of the input context, as an #IBusInputPurpose.
+ * @hints: Hints that augment @purpose, as an #IBusInputHints.
+ *
+ * Set content-type (primary purpose and hints) of the context.  This
+ * information is particularly useful to implement intelligent
+ * behavior in engines, such as automatic input-mode switch and text
+ * prediction.  For example, to restrict input to numbers, the client
+ * can call this function with @purpose set to
+ * #IBUS_INPUT_PURPOSE_NUMBER.
+ *
+ * See also: #IBusEngine::set-content-type
+ */
+void         ibus_input_context_set_content_type
+                                            (IBusInputContext   *context,
+                                             guint               purpose,
+                                             guint               hints);
+
 G_END_DECLS
 #endif
index d2abeab..6d30a86 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
@@ -228,5 +228,73 @@ struct _IBusRectangle {
  */
 typedef void (* IBusFreeFunc) (gpointer object);
 
+/**
+ * IBusInputPurpose:
+ * @IBUS_INPUT_PURPOSE_FREE_FORM: Allow any character
+ * @IBUS_INPUT_PURPOSE_ALPHA: Allow only alphabetic characters
+ * @IBUS_INPUT_PURPOSE_DIGITS: Allow only digits
+ * @IBUS_INPUT_PURPOSE_NUMBER: Edited field expects numbers
+ * @IBUS_INPUT_PURPOSE_PHONE: Edited field expects phone number
+ * @IBUS_INPUT_PURPOSE_URL: Edited field expects URL
+ * @IBUS_INPUT_PURPOSE_EMAIL: Edited field expects email address
+ * @IBUS_INPUT_PURPOSE_NAME: Edited field expects the name of a person
+ * @IBUS_INPUT_PURPOSE_PASSWORD: Like @IBUS_INPUT_PURPOSE_FREE_FORM,
+ * but characters are hidden
+ * @IBUS_INPUT_PURPOSE_PIN: Like @IBUS_INPUT_PURPOSE_DIGITS, but
+ * characters are hidden
+ *
+ * Describes primary purpose of the input context.  This information
+ * is particularly useful to implement intelligent behavior in
+ * engines, such as automatic input-mode switch and text prediction.
+ *
+ * This enumeration may be extended in the future; engines should
+ * interpret unknown values as 'free form'.
+ */
+typedef enum
+{
+  IBUS_INPUT_PURPOSE_FREE_FORM,
+  IBUS_INPUT_PURPOSE_ALPHA,
+  IBUS_INPUT_PURPOSE_DIGITS,
+  IBUS_INPUT_PURPOSE_NUMBER,
+  IBUS_INPUT_PURPOSE_PHONE,
+  IBUS_INPUT_PURPOSE_URL,
+  IBUS_INPUT_PURPOSE_EMAIL,
+  IBUS_INPUT_PURPOSE_NAME,
+  IBUS_INPUT_PURPOSE_PASSWORD,
+  IBUS_INPUT_PURPOSE_PIN
+} IBusInputPurpose;
+
+/**
+ * IBusInputHints:
+ * @IBUS_INPUT_HINT_NONE: No special behaviour suggested
+ * @IBUS_INPUT_HINT_SPELLCHECK: Suggest checking for typos
+ * @IBUS_INPUT_HINT_NO_SPELLCHECK: Suggest not checking for typos
+ * @IBUS_INPUT_HINT_WORD_COMPLETION: Suggest word completion
+ * @IBUS_INPUT_HINT_LOWERCASE: Suggest to convert all text to lowercase
+ * @IBUS_INPUT_HINT_UPPERCASE_CHARS: Suggest to capitalize all text
+ * @IBUS_INPUT_HINT_UPPERCASE_WORDS: Suggest to capitalize the first
+ *     character of each word
+ * @IBUS_INPUT_HINT_UPPERCASE_SENTENCES: Suggest to capitalize the
+ *     first word of each sentence
+ * @IBUS_INPUT_HINT_INHIBIT_OSK: Suggest to not show an onscreen keyboard
+ *     (e.g for a calculator that already has all the keys).
+ *
+ * Describes hints that might be taken into account by engines.  Note
+ * that engines may already tailor their behaviour according to the
+ * #IBusInputPurpose of the entry.
+ */
+typedef enum
+{
+  IBUS_INPUT_HINT_NONE                = 0,
+  IBUS_INPUT_HINT_SPELLCHECK          = 1 << 0,
+  IBUS_INPUT_HINT_NO_SPELLCHECK       = 1 << 1,
+  IBUS_INPUT_HINT_WORD_COMPLETION     = 1 << 2,
+  IBUS_INPUT_HINT_LOWERCASE           = 1 << 3,
+  IBUS_INPUT_HINT_UPPERCASE_CHARS     = 1 << 4,
+  IBUS_INPUT_HINT_UPPERCASE_WORDS     = 1 << 5,
+  IBUS_INPUT_HINT_UPPERCASE_SENTENCES = 1 << 6,
+  IBUS_INPUT_HINT_INHIBIT_OSK         = 1 << 7
+} IBusInputHints;
+
 #endif