/* a key mapping for the engine that converts keycode into keysym. the mapping is used only when use_sys_layout is FALSE. */
IBusKeymap *keymap;
/* private member */
+
+ /* cached surrounding text (see also IBusEnginePrivate and
+ IBusInputContextPrivate) */
+ IBusText *surrounding_text;
+ guint surrounding_cursor_pos;
};
struct _BusEngineProxyClass {
COMMIT_TEXT,
FORWARD_KEY_EVENT,
DELETE_SURROUNDING_TEXT,
+ REQUIRE_SURROUNDING_TEXT,
UPDATE_PREEDIT_TEXT,
SHOW_PREEDIT_TEXT,
HIDE_PREEDIT_TEXT,
static guint engine_signals[LAST_SIGNAL] = { 0 };
+static IBusText *text_empty = NULL;
+
/* functions prototype */
static void bus_engine_proxy_set_property (BusEngineProxy *engine,
guint prop_id,
G_TYPE_INT,
G_TYPE_UINT);
+ engine_signals[REQUIRE_SURROUNDING_TEXT] =
+ g_signal_new (I_("require-surrounding-text"),
+ G_TYPE_FROM_CLASS (class),
+ G_SIGNAL_RUN_LAST,
+ 0,
+ NULL, NULL,
+ bus_marshal_VOID__VOID,
+ G_TYPE_NONE,
+ 0);
+
engine_signals[UPDATE_PREEDIT_TEXT] =
g_signal_new (I_("update-preedit-text"),
G_TYPE_FROM_CLASS (class),
G_TYPE_NONE,
1,
IBUS_TYPE_PROPERTY);
+
+ text_empty = ibus_text_new_from_static_string ("");
+ g_object_ref_sink (text_empty);
}
static void
bus_engine_proxy_init (BusEngineProxy *engine)
{
+ engine->surrounding_text = g_object_ref_sink (text_empty);
+ engine->surrounding_cursor_pos = 0;
}
static void
engine->keymap = NULL;
}
+ if (engine->surrounding_text) {
+ g_object_unref (engine->surrounding_text);
+ engine->surrounding_text = NULL;
+ }
+
IBUS_PROXY_CLASS (bus_engine_proxy_parent_class)->destroy ((IBusProxy *)engine);
}
{ "PageDownLookupTable", PAGE_DOWN_LOOKUP_TABLE },
{ "CursorUpLookupTable", CURSOR_UP_LOOKUP_TABLE },
{ "CursorDownLookupTable", CURSOR_DOWN_LOOKUP_TABLE },
+ { "RequireSurroundingText", REQUIRE_SURROUNDING_TEXT },
};
gint i;
NULL);
}
+void bus_engine_proxy_set_surrounding_text (BusEngineProxy *engine,
+ IBusText *text,
+ guint cursor_pos)
+{
+ g_assert (BUS_IS_ENGINE_PROXY (engine));
+ g_assert (text != NULL);
+
+ if (!engine->surrounding_text ||
+ g_strcmp0 (text->text, engine->surrounding_text->text) != 0 ||
+ cursor_pos != engine->surrounding_cursor_pos) {
+ GVariant *variant = ibus_serializable_serialize ((IBusSerializable *)text);
+ if (engine->surrounding_text)
+ g_object_unref (engine->surrounding_text);
+ engine->surrounding_text = (IBusText *) g_object_ref_sink (text);
+ engine->surrounding_cursor_pos = cursor_pos;
+
+ g_dbus_proxy_call ((GDBusProxy *)engine,
+ "SetSurroundingText",
+ g_variant_new ("(vu)", variant, cursor_pos),
+ G_DBUS_CALL_FLAGS_NONE,
+ -1,
+ NULL,
+ NULL,
+ NULL);
+ }
+}
+
/* a macro to generate a function to call a nullary D-Bus method. */
#define DEFINE_FUNCTION(Name, name) \
void \
*/
gboolean bus_engine_proxy_is_enabled (BusEngineProxy *engine);
+/**
+ * bus_engine_proxy_set_surrounding_text:
+ *
+ * Call "SetSurroundingText" method of an engine asynchronously.
+ */
+void bus_engine_proxy_set_surrounding_text
+ (BusEngineProxy *engine,
+ IBusText *text,
+ guint cursor_pos);
+
+
G_END_DECLS
#endif
" <method name='GetEngine'>"
" <arg direction='out' type='v' name='desc' />"
" </method>"
+ " <method name='SetSurroundingText'>"
+ " <arg direction='in' type='v' name='text' />"
+ " <arg direction='in' type='u' name='cursor_pos' />"
+ " </method>"
+
/* signals */
" <signal name='CommitText'>"
" <arg type='v' name='text' />"
* 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,
+ GDBusMethodInvocation *invocation)
+{
+ GVariant *variant = NULL;
+ IBusText *text;
+ guint cursor_pos = 0;
+
+ g_variant_get (parameters, "(vu)", &variant, &cursor_pos);
+ text = IBUS_TEXT (ibus_serializable_deserialize (variant));
+ g_variant_unref (variant);
+
+ if ((context->capabilities & IBUS_CAP_SURROUNDING_TEXT) &&
+ context->has_focus && context->enabled && context->engine) {
+ bus_engine_proxy_set_surrounding_text (context->engine,
+ text,
+ cursor_pos);
+ }
+
+ if (g_object_is_floating (text))
+ g_object_unref (text);
+
+ g_dbus_method_invocation_return_value (invocation, NULL);
+}
+
+static void
bus_input_context_service_method_call (IBusService *service,
GDBusConnection *connection,
const gchar *sender,
{ "IsEnabled", _ic_is_enabled },
{ "SetEngine", _ic_set_engine },
{ "GetEngine", _ic_get_engine },
+ { "SetSurroundingText", _ic_set_surrounding_text},
};
gint i;
}
/**
+ * _engine_require_surrounding_text_cb:
+ *
+ * A function to be called when "require-surrounding-text" glib signal is sent to the engine object.
+ */
+static void
+_engine_require_surrounding_text_cb (BusEngineProxy *engine,
+ BusInputContext *context)
+{
+ g_assert (BUS_IS_ENGINE_PROXY (engine));
+ g_assert (BUS_IS_INPUT_CONTEXT (context));
+
+ g_assert (context->engine == engine);
+
+ if (!context->enabled)
+ return;
+
+ bus_input_context_emit_signal (context,
+ "RequireSurroundingText",
+ NULL,
+ NULL);
+}
+
+/**
* _engine_update_preedit_text_cb:
*
* A function to be called when "update-preedit-text" glib signal is sent to the engine object.
{ "commit-text", G_CALLBACK (_engine_commit_text_cb) },
{ "forward-key-event", G_CALLBACK (_engine_forward_key_event_cb) },
{ "delete-surrounding-text", G_CALLBACK (_engine_delete_surrounding_text_cb) },
+ { "require-surrounding-text", G_CALLBACK (_engine_require_surrounding_text_cb) },
{ "update-preedit-text", G_CALLBACK (_engine_update_preedit_text_cb) },
{ "show-preedit-text", G_CALLBACK (_engine_show_preedit_text_cb) },
{ "hide-preedit-text", G_CALLBACK (_engine_hide_preedit_text_cb) },
# include <config.h>
#endif
+#include <string.h>
#include <gtk/gtk.h>
#include <gdk/gdkkeysyms.h>
#include <ibus.h>
static void ibus_im_context_set_use_preedit
(GtkIMContext *context,
gboolean use_preedit);
+static void ibus_im_context_set_surrounding
+ (GtkIMContext *slave,
+ const gchar *text,
+ gint len,
+ gint cursor_index);
+
/* static methods*/
static void _create_input_context (IBusIMContext *context);
IBusIMContext *context);
static void _slave_preedit_end_cb (GtkIMContext *slave,
IBusIMContext *context);
-static void _slave_retrieve_surrounding_cb
+static gboolean _slave_retrieve_surrounding_cb
(GtkIMContext *slave,
- IBusIMContext *context);
-static void _slave_delete_surrounding_cb
+ IBusIMContext *context);
+static gboolean _slave_delete_surrounding_cb
(GtkIMContext *slave,
- gint offset_from_cursor,
- guint nchars,
- IBusIMContext *context);
+ gint offset_from_cursor,
+ guint nchars,
+ IBusIMContext *context);
+static void _request_surrounding_text (IBusIMContext *context,
+ gboolean force);
static void _create_fake_input_context (void);
}
+/* emit "retrieve-surrounding" glib signal of GtkIMContext, if
+ * context->caps has IBUS_CAP_SURROUNDING_TEXT and the current IBus
+ * engine needs surrounding-text.
+ *
+ * if "force" is TRUE, emit the signal regardless of whether the
+ * engine needs surrounding-text.
+ */
+static void
+_request_surrounding_text (IBusIMContext *context, gboolean force)
+{
+ if (context->enable &&
+ (context->caps & IBUS_CAP_SURROUNDING_TEXT) != 0 &&
+ (force ||
+ ibus_input_context_needs_surrounding_text (context->ibuscontext))) {
+ gboolean return_value;
+ IDEBUG ("requesting surrounding text");
+ g_signal_emit (context, _signal_retrieve_surrounding_id, 0,
+ &return_value);
+ }
+}
+
+
static gint
_key_snooper_cb (GtkWidget *widget,
GdkEventKey *event,
} while (0);
+ _request_surrounding_text (ibusimcontext, FALSE);
+
if (ibusimcontext != NULL) {
ibusimcontext->time = event->time;
}
im_context_class->set_client_window = ibus_im_context_set_client_window;
im_context_class->set_cursor_location = ibus_im_context_set_cursor_location;
im_context_class->set_use_preedit = ibus_im_context_set_use_preedit;
+ im_context_class->set_surrounding = ibus_im_context_set_surrounding;
gobject_class->finalize = ibus_im_context_finalize;
_signal_commit_id =
ibusimcontext->ibuscontext = NULL;
ibusimcontext->has_focus = FALSE;
ibusimcontext->time = GDK_CURRENT_TIME;
+#ifdef ENABLE_SURROUNDING
ibusimcontext->caps = IBUS_CAP_PREEDIT_TEXT | IBUS_CAP_FOCUS | IBUS_CAP_SURROUNDING_TEXT;
+#else
+ ibusimcontext->caps = IBUS_CAP_PREEDIT_TEXT | IBUS_CAP_FOCUS;
+#endif
// Create slave im context
if (ibusimcontext->client_window == NULL && event->window != NULL)
gtk_im_context_set_client_window ((GtkIMContext *)ibusimcontext, event->window);
+ _request_surrounding_text (ibusimcontext, FALSE);
+
if (ibusimcontext != NULL) {
ibusimcontext->time = event->time;
}
g_object_ref (context),
(GDestroyNotify) g_object_unref);
+ /* retrieve the initial surrounding-text (regardless of whether
+ * the current IBus engine needs surrounding-text) */
+ _request_surrounding_text (ibusimcontext, TRUE);
+
g_object_add_weak_pointer ((GObject *) context,
(gpointer *) &_focus_im_context);
_focus_im_context = context;
else {
ibusimcontext->caps &= ~IBUS_CAP_PREEDIT_TEXT;
}
- ibus_input_context_set_capabilities (ibusimcontext->ibuscontext, ibusimcontext->caps);
}
gtk_im_context_set_use_preedit (ibusimcontext->slave, use_preedit);
}
static void
+ibus_im_context_set_surrounding (GtkIMContext *context,
+ const gchar *text,
+ gint len,
+ gint cursor_index)
+{
+ g_return_if_fail (context != NULL);
+ g_return_if_fail (IBUS_IS_IM_CONTEXT (context));
+ g_return_if_fail (text != NULL);
+ g_return_if_fail (strlen (text) >= len);
+ g_return_if_fail (0 <= cursor_index && cursor_index <= len);
+
+ IBusIMContext *ibusimcontext = IBUS_IM_CONTEXT (context);
+
+ if (ibusimcontext->enable && ibusimcontext->ibuscontext) {
+ IBusText *ibustext;
+ guint cursor_pos;
+ gchar *p;
+
+ p = g_strndup (text, len);
+ cursor_pos = g_utf8_strlen (p, cursor_index);
+ ibustext = ibus_text_new_from_string (p);
+ g_free (p);
+ ibus_input_context_set_surrounding_text (ibusimcontext->ibuscontext,
+ ibustext,
+ cursor_pos);
+ }
+ gtk_im_context_set_surrounding (ibusimcontext->slave,
+ text,
+ len,
+ cursor_index);
+}
+
+static void
_bus_connected_cb (IBusBus *bus,
IBusIMContext *ibusimcontext)
{
IDEBUG ("%s", __FUNCTION__);
g_signal_emit (ibusimcontext, _signal_commit_id, 0, text->text);
+
+ _request_surrounding_text (ibusimcontext, FALSE);
}
static gboolean
ibusimcontext->preedit_visible = TRUE;
g_signal_emit (ibusimcontext, _signal_preedit_start_id, 0);
g_signal_emit (ibusimcontext, _signal_preedit_changed_id, 0);
+
+ _request_surrounding_text (ibusimcontext, FALSE);
}
static void
IDEBUG ("%s", __FUNCTION__);
ibusimcontext->enable = TRUE;
+
+ /* retrieve the initial surrounding-text (regardless of whether
+ * the current IBus engine needs surrounding-text) */
+ _request_surrounding_text (ibusimcontext, TRUE);
}
static void
g_signal_emit (ibusimcontext, _signal_preedit_end_id, 0);
}
-static void
+static gboolean
_slave_retrieve_surrounding_cb (GtkIMContext *slave,
IBusIMContext *ibusimcontext)
{
+ gboolean return_value;
+
if (ibusimcontext->enable && ibusimcontext->ibuscontext) {
- return;
+ return FALSE;
}
- g_signal_emit (ibusimcontext, _signal_retrieve_surrounding_id, 0);
+ g_signal_emit (ibusimcontext, _signal_retrieve_surrounding_id, 0,
+ &return_value);
+ return return_value;
}
-static void
+static gboolean
_slave_delete_surrounding_cb (GtkIMContext *slave,
gint offset_from_cursor,
guint nchars,
gboolean return_value;
if (ibusimcontext->enable && ibusimcontext->ibuscontext) {
- return;
+ return FALSE;
}
g_signal_emit (ibusimcontext, _signal_delete_surrounding_id, 0, offset_from_cursor, nchars, &return_value);
+ return return_value;
}
#ifdef OS_CHROMEOS
)
AC_SUBST(IBUS_ICON_KEYBOARD)
+# option for enable surrounding-text
+AC_ARG_ENABLE(surrounding-text,
+ AS_HELP_STRING([--enable-surrounding-text],
+ [Enable surrounding-text support]),
+ [enable_surrounding_text=$enableval],
+ [enable_surrounding_text=no]
+)
+if test x"$enable_surrounding_text" = x"yes"; then
+ AC_DEFINE(ENABLE_SURROUNDING, TRUE, [Enable surrounding-text support])
+else
+ enable_surrounding_text="no (disabled, use --enable-surrounding-text to enable)"
+fi
+
# check iso-codes
PKG_CHECK_MODULES(ISOCODES, [
iso-codes
Enable key snooper $enable_key_snooper
No snooper regexes "$NO_SNOOPER_APPS"
Panel icon "$IBUS_ICON_KEYBOARD"
+ Enable surrounding-text $enable_surrounding_text
])
def set_cursor_location(self, x, y, w, h):
pass
+ def set_surrounding_text(self, text, cursor_index):
+ pass
+
def set_capabilities(self, cap):
pass
def SetCursorLocation(self, x, y, w, h):
return self.__engine.set_cursor_location(x, y, w, h)
+ def SetSurroundingText(self, text, cursor_index):
+ return self.__engine.set_surrounding_text(text, cursor_index)
+
def SetCapabilities(self, caps):
return self.__engine.set_capabilities(caps)
@method(in_signature="iiii")
def SetCursorLocation(self, x, y, w, h): pass
+ @method(in_signature="vu")
+ def SetSurroundingText(self, text, cursor_index): pass
+
@method(in_signature="u")
def SetCapabilities(self, cap): pass
@method(in_signature="iiii")
def SetCursorLocation(self, x, y, w, h): pass
+ @method(in_signature="vu")
+ def SetSurroundingText(self, text, cursor_index): pass
+
@method()
def FocusIn(self): pass
*/
#include "ibusengine.h"
#include <stdarg.h>
+#include <string.h>
#include "ibusmarshalers.h"
#include "ibusinternal.h"
#include "ibusshare.h"
PROPERTY_SHOW,
PROPERTY_HIDE,
CANDIDATE_CLICKED,
+ SET_SURROUNDING_TEXT,
LAST_SIGNAL,
};
struct _IBusEnginePrivate {
gchar *engine_name;
GDBusConnection *connection;
+
+ /* cached surrounding text (see also IBusInputContextPrivate and
+ BusEngineProxy) */
+ IBusText *surrounding_text;
+ guint surrounding_cursor_pos;
};
static guint engine_signals[LAST_SIGNAL] = { 0 };
+static IBusText *text_empty = NULL;
+
/* functions prototype */
static void ibus_engine_destroy (IBusEngine *engine);
static void ibus_engine_set_property (IBusEngine *engine,
const gchar *prop_name);
static void ibus_engine_property_hide (IBusEngine *engine,
const gchar *prop_name);
+static void ibus_engine_set_surrounding_text
+ (IBusEngine *engine,
+ IBusText *text,
+ guint cursor_pos);
static void ibus_engine_emit_signal (IBusEngine *engine,
const gchar *signal_name,
GVariant *parameters);
" <method name='PageDown' />"
" <method name='CursorUp' />"
" <method name='CursorDown' />"
+ " <method name='SetSurroundingText'>"
+ " <arg direction='in' type='v' name='text' />"
+ " <arg direction='in' type='u' name='cursor_pos' />"
+ " </method>"
/* FIXME signals */
" <signal name='CommitText'>"
" <arg type='v' name='text' />"
class->property_hide = ibus_engine_property_hide;
class->set_cursor_location = ibus_engine_set_cursor_location;
class->set_capabilities = ibus_engine_set_capabilities;
+ class->set_surrounding_text = ibus_engine_set_surrounding_text;
/* install properties */
/**
G_TYPE_STRING);
g_type_class_add_private (class, sizeof (IBusEnginePrivate));
+
+ /**
+ * IBusEngine::set-surrounding-text:
+ * @engine: An IBusEngine.
+ *
+ * Emitted when a surrounding text is set.
+ * Implement the member function set_surrounding_text() in extended class to receive this signal.
+ *
+ * <note><para>Argument @user_data is ignored in this function.</para></note>
+ */
+ engine_signals[SET_SURROUNDING_TEXT] =
+ g_signal_new (I_("set-surrounding-text"),
+ G_TYPE_FROM_CLASS (gobject_class),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (IBusEngineClass, set_surrounding_text),
+ NULL, NULL,
+ _ibus_marshal_VOID__OBJECT_UINT,
+ G_TYPE_NONE,
+ 2,
+ G_TYPE_OBJECT,
+ G_TYPE_UINT);
+
+ text_empty = ibus_text_new_from_static_string ("");
+ g_object_ref_sink (text_empty);
}
static void
ibus_engine_init (IBusEngine *engine)
{
engine->priv = IBUS_ENGINE_GET_PRIVATE (engine);
+
+ engine->priv->surrounding_text = g_object_ref_sink (text_empty);
+ engine->priv->surrounding_cursor_pos = 0;
}
static void
g_free (engine->priv->engine_name);
engine->priv->engine_name = NULL;
+ if (engine->priv->surrounding_text) {
+ g_object_unref (engine->priv->surrounding_text);
+ engine->priv->surrounding_text = NULL;
+ }
+
IBUS_OBJECT_CLASS(ibus_engine_parent_class)->destroy (IBUS_OBJECT (engine));
}
return;
}
+ if (g_strcmp0 (method_name, "SetSurroundingText") == 0) {
+ GVariant *variant = NULL;
+ IBusText *text;
+ guint cursor_pos;
+
+ g_variant_get (parameters, "(vu)", &variant, &cursor_pos);
+ text = IBUS_TEXT (ibus_serializable_deserialize (variant));
+ g_variant_unref (variant);
+
+ g_signal_emit (engine, engine_signals[SET_SURROUNDING_TEXT],
+ 0,
+ text,
+ cursor_pos);
+ if (g_object_is_floating (text)) {
+ g_object_unref (text);
+ }
+ g_dbus_method_invocation_return_value (invocation, NULL);
+ return;
+ }
+
/* should not be reached */
g_return_if_reached ();
}
}
static void
+ibus_engine_set_surrounding_text (IBusEngine *engine,
+ IBusText *text,
+ guint cursor_pos)
+{
+ g_assert (IBUS_IS_ENGINE (engine));
+
+ IBusEnginePrivate *priv;
+
+ priv = IBUS_ENGINE_GET_PRIVATE (engine);
+
+ if (priv->surrounding_text) {
+ g_object_unref (priv->surrounding_text);
+ }
+
+ priv->surrounding_text = (IBusText *) g_object_ref_sink (text ? text : text_empty);
+ priv->surrounding_cursor_pos = cursor_pos;
+ // g_debug ("set-surrounding-text ('%s', %d)", text->text, cursor_pos);
+}
+
+static void
ibus_engine_emit_signal (IBusEngine *engine,
const gchar *signal_name,
GVariant *parameters)
gint offset_from_cursor,
guint nchars)
{
+ IBusEnginePrivate *priv;
+
g_return_if_fail (IBUS_IS_ENGINE (engine));
+ priv = IBUS_ENGINE_GET_PRIVATE (engine);
+
+ /* Update surrounding-text cache. This is necessary since some
+ engines call ibus_engine_get_surrounding_text() immediately
+ after ibus_engine_delete_surrounding_text(). */
+ if (priv->surrounding_text) {
+ IBusText *text;
+ glong cursor_pos, len;
+
+ cursor_pos = priv->surrounding_cursor_pos + offset_from_cursor;
+ len = ibus_text_get_length (priv->surrounding_text);
+ if (cursor_pos >= 0 && len - cursor_pos >= nchars) {
+ gunichar *ucs;
+
+ ucs = g_utf8_to_ucs4_fast (priv->surrounding_text->text,
+ -1,
+ NULL);
+ memmove (&ucs[cursor_pos],
+ &ucs[cursor_pos + nchars],
+ sizeof(gunichar) * (len - cursor_pos - nchars));
+ ucs[len - nchars] = 0;
+ text = ibus_text_new_from_ucs4 (ucs);
+ g_free (ucs);
+ priv->surrounding_cursor_pos = cursor_pos;
+ } else {
+ text = text_empty;
+ priv->surrounding_cursor_pos = 0;
+ }
+
+ g_object_unref (priv->surrounding_text);
+ priv->surrounding_text = g_object_ref_sink (text);
+ }
+
ibus_engine_emit_signal (engine,
"DeleteSurroundingText",
g_variant_new ("(iu)", offset_from_cursor, nchars));
}
void
+ibus_engine_get_surrounding_text (IBusEngine *engine,
+ IBusText **text,
+ guint *cursor_pos)
+{
+ IBusEnginePrivate *priv;
+
+ g_return_if_fail (IBUS_IS_ENGINE (engine));
+ g_return_if_fail (text != NULL);
+ g_return_if_fail (cursor_pos != NULL);
+
+ priv = IBUS_ENGINE_GET_PRIVATE (engine);
+
+ *text = g_object_ref (priv->surrounding_text);
+ *cursor_pos = priv->surrounding_cursor_pos;
+
+ /* tell the client that this engine will utilize surrounding-text
+ * feature, which causes periodical update. Note that the client
+ * should request the initial surrounding-text when the engine is
+ * enabled (see ibus_im_context_focus_in() and
+ * _ibus_context_enabled_cb() in client/gtk2/ibusimcontext.c). */
+ ibus_engine_emit_signal (engine,
+ "RequireSurroundingText",
+ NULL);
+
+ // g_debug ("get-surrounding-text ('%s', %d)", (*text)->text, *cursor_pos);
+}
+
+void
ibus_engine_register_properties (IBusEngine *engine,
IBusPropList *prop_list)
{
guint index,
guint button,
guint state);
+ void (* set_surrounding_text)
+ (IBusEngine *engine,
+ IBusText *text,
+ guint cursor_index);
/*< private >*/
/* padding */
- gpointer pdummy[8];
+ gpointer pdummy[7];
};
GType ibus_engine_get_type (void);
guint nchars);
/**
+ * ibus_engine_get_surrounding_text:
+ * @engine: An IBusEngine.
+ * @text: Location to store surrounding text.
+ * @cursor_pos: Cursor position in characters in @text.
+ *
+ * Get surrounding text.
+ *
+ * @see_also #IBusEngine::set-surrounding-text
+ */
+void ibus_engine_get_surrounding_text(IBusEngine *engine,
+ IBusText **text,
+ guint *cursor_pos);
+
+
+/**
* ibus_engine_get_name:
* @engine: An IBusEngine.
* @returns: Name of IBusEngine.
#include "ibuslookuptable.h"
#include "ibusproplist.h"
+#define IBUS_INPUT_CONTEXT_GET_PRIVATE(o) \
+ (G_TYPE_INSTANCE_GET_PRIVATE ((o), IBUS_TYPE_INPUT_CONTEXT, IBusInputContextPrivate))
+
enum {
ENABLED,
DISABLED,
LAST_SIGNAL,
};
+/* IBusInputContextPrivate */
+struct _IBusInputContextPrivate {
+ /* TRUE if the current engine needs surrounding text; FALSE otherwise */
+ gboolean needs_surrounding_text;
+
+ /* cached surrounding text (see also IBusEnginePrivate and
+ BusEngineProxy) */
+ IBusText *surrounding_text;
+ guint surrounding_cursor_pos;
+};
+
+typedef struct _IBusInputContextPrivate IBusInputContextPrivate;
+
static guint context_signals[LAST_SIGNAL] = { 0 };
+static IBusText *text_empty = NULL;
+
/* functions prototype */
+static void ibus_input_context_real_destroy (IBusProxy *context);
static void ibus_input_context_g_signal (GDBusProxy *proxy,
const gchar *sender_name,
const gchar *signal_name,
static void
ibus_input_context_class_init (IBusInputContextClass *class)
{
+ IBusProxyClass *ibus_proxy_class = IBUS_PROXY_CLASS (class);
GDBusProxyClass *g_dbus_proxy_class = G_DBUS_PROXY_CLASS (class);
+ g_type_class_add_private (class, sizeof (IBusInputContextPrivate));
+
+ ibus_proxy_class->destroy = ibus_input_context_real_destroy;
+
g_dbus_proxy_class->g_signal = ibus_input_context_g_signal;
/* install signals */
G_TYPE_NONE,
1,
IBUS_TYPE_PROPERTY);
+
+ text_empty = ibus_text_new_from_static_string ("");
+ g_object_ref_sink (text_empty);
}
static void
ibus_input_context_init (IBusInputContext *context)
{
+ IBusInputContextPrivate *priv;
+
+ priv = IBUS_INPUT_CONTEXT_GET_PRIVATE (context);
+ priv->surrounding_text = g_object_ref_sink (text_empty);
+ priv->surrounding_cursor_pos = 0;
+}
+
+static void
+ibus_input_context_real_destroy (IBusProxy *context)
+{
+ IBusInputContextPrivate *priv;
+ priv = IBUS_INPUT_CONTEXT_GET_PRIVATE (IBUS_INPUT_CONTEXT (context));
+
+ if (priv->surrounding_text) {
+ g_object_unref (priv->surrounding_text);
+ priv->surrounding_text = NULL;
+ }
+
+ IBUS_PROXY_CLASS(ibus_input_context_parent_class)->destroy (context);
}
static void
const gchar *signal_name;
guint signal_id;
} signals [] = {
- { "Enabled", ENABLED },
- { "Disabled", DISABLED },
{ "ShowPreeditText", SHOW_PREEDIT_TEXT },
{ "HidePreeditText", HIDE_PREEDIT_TEXT },
{ "ShowAuxiliaryText", SHOW_AUXILIARY_TEXT },
return;
}
+ IBusInputContextPrivate *priv;
+ priv = IBUS_INPUT_CONTEXT_GET_PRIVATE (IBUS_INPUT_CONTEXT (context));
+
+ if (g_strcmp0 (signal_name, "Enabled") == 0) {
+ priv->needs_surrounding_text = FALSE;
+ g_signal_emit (context, context_signals[ENABLED], 0);
+ return;
+ }
+
+ if (g_strcmp0 (signal_name, "Disabled") == 0) {
+ priv->needs_surrounding_text = FALSE;
+ g_signal_emit (context, context_signals[DISABLED], 0);
+ return;
+ }
+
+ if (g_strcmp0 (signal_name, "RequireSurroundingText") == 0) {
+ priv->needs_surrounding_text = TRUE;
+ return;
+ }
+
G_DBUS_PROXY_CLASS (ibus_input_context_parent_class)->g_signal (
proxy, sender_name, signal_name, parameters);
}
return TRUE;
}
+void
+ibus_input_context_set_surrounding_text (IBusInputContext *context,
+ IBusText *text,
+ guint32 cursor_pos)
+{
+ g_assert (IBUS_IS_INPUT_CONTEXT (context));
+ g_assert (IBUS_IS_TEXT (text));
+
+ IBusInputContextPrivate *priv;
+ priv = IBUS_INPUT_CONTEXT_GET_PRIVATE (context);
+
+ if (priv->surrounding_text == NULL ||
+ g_strcmp0 (text->text, priv->surrounding_text->text) != 0 ||
+ cursor_pos != priv->surrounding_cursor_pos) {
+ GVariant *variant = ibus_serializable_serialize ((IBusSerializable *)text);
+ if (priv->surrounding_text)
+ g_object_unref (priv->surrounding_text);
+ priv->surrounding_text = (IBusText *) g_object_ref_sink (text);
+ priv->surrounding_cursor_pos = cursor_pos;
+
+ g_dbus_proxy_call ((GDBusProxy *) context,
+ "SetSurroundingText", /* method_name */
+ g_variant_new ("(vu)", variant, cursor_pos), /* parameters */
+ G_DBUS_CALL_FLAGS_NONE, /* flags */
+ -1, /* timeout */
+ NULL, /* cancellable */
+ NULL, /* callback */
+ NULL /* user_data */
+ );
+ }
+}
+
+gboolean
+ibus_input_context_needs_surrounding_text (IBusInputContext *context)
+{
+ IBusInputContextPrivate *priv;
+ priv = IBUS_INPUT_CONTEXT_GET_PRIVATE (IBUS_INPUT_CONTEXT (context));
+ return priv->needs_surrounding_text;
+}
+
gboolean
ibus_input_context_is_enabled (IBusInputContext *context)
{
#include "ibusproxy.h"
#include "ibusenginedesc.h"
+#include "ibustext.h"
/*
* Type macros.
void ibus_input_context_set_engine (IBusInputContext *context,
const gchar *name);
+/**
+ * ibus_input_context_set_surrounding_text:
+ * @context: An #IBusInputContext.
+ * @text: An #IBusText surrounding the current cursor on the application.
+ * @cursor_po: Current cursor position in characters in @text.
+*/
+void ibus_input_context_set_surrounding_text
+ (IBusInputContext *context,
+ IBusText *text,
+ guint32 cursor_pos);
+
+/**
+ * ibus_input_context_needs_surrounding_text:
+ * @context: An #IBusInputContext.
+ * @returns: %TRUE if surrounding-text is needed by the current engine;
+ * %FALSE otherwise.
+ *
+ * Check whether the current engine requires surrounding-text.
+ */
+gboolean ibus_input_context_needs_surrounding_text
+ (IBusInputContext *context);
G_END_DECLS
#endif
VOID:UINT,UINT
VOID:INT,UINT
VOID:UINT,UINT,UINT
+VOID:OBJECT,UINT
VOID:OBJECT,UINT,BOOL
VOID:OBJECT,UINT,BOOL,UINT
VOID:OBJECT,BOOL