init
Some checks failed
Docker. / Ubuntu (push) Has been cancelled
User-agent updater. / User-agent (push) Failing after 15s
Lock Threads / lock (push) Failing after 10s
Waiting for answer. / waiting-for-answer (push) Failing after 22s
Needs user action. / needs-user-action (push) Failing after 8s
Can't reproduce. / cant-reproduce (push) Failing after 8s
Close stale issues and PRs / stale (push) Has been cancelled

This commit is contained in:
allhaileris
2026-02-16 15:50:16 +03:00
commit afb81b8278
13816 changed files with 3689732 additions and 0 deletions

View File

@@ -0,0 +1,130 @@
lib_LTLIBRARIES = libnimf.la
BUILT_SOURCES = \
nimf-enum-types.c \
nimf-enum-types-private.h \
nimf-marshalers.c \
nimf-marshalers-private.h \
nimf-message-enum-types-private.h \
nimf-message-enum-types.c \
$(NULL)
libnimf_la_SOURCES = \
nimf.h \
nimf-candidatable.c \
nimf-candidatable.h \
nimf-engine.c \
nimf-engine.h \
nimf-events.c \
nimf-events.h \
nimf-im.c \
nimf-im.h \
nimf-key-syms.h \
nimf-message.c \
nimf-message-private.h \
nimf-module.c \
nimf-module-private.h \
nimf-preeditable.c \
nimf-preeditable.h \
nimf-server.c \
nimf-server.h \
nimf-server-private.h \
nimf-service.c \
nimf-service.h \
nimf-service-ic.c \
nimf-service-ic.h \
nimf-service-ic-private.h \
nimf-types.c \
nimf-types.h \
nimf-utils.c \
nimf-utils.h \
nimf-utils-private.h \
$(BUILT_SOURCES) \
$(NULL)
libnimf_la_CFLAGS = \
$(EXTRA_CFLAGS) \
-I$(top_srcdir)/libnimf \
-DNIMF_COMPILATION \
-DG_LOG_DOMAIN=\"nimf\" \
-DNIMF_MODULE_DIR=\"$(libdir)/nimf/modules\" \
-DNIMF_SERVICE_MODULE_DIR=\"$(libdir)/nimf/modules/services\" \
$(LIBNIMF_DEPS_CFLAGS)
libnimf_la_LDFLAGS = -version-info $(LIBNIMF_LT_VERSION) $(LIBNIMF_DEPS_LIBS)
nimfincludedir = $(includedir)/nimf
nimfinclude_HEADERS = \
nimf.h \
nimf-candidatable.h \
nimf-engine.h \
nimf-events.h \
nimf-im.h \
nimf-key-syms.h \
nimf-preeditable.h \
nimf-server.h \
nimf-service.h \
nimf-service-ic.h \
nimf-types.h \
nimf-utils.h \
$(NULL)
nimf-marshalers-private.h: nimf-marshalers.list
$(AM_V_GEN) glib-genmarshal --prefix=nimf_cclosure_marshal \
--header nimf-marshalers.list \
> nimf-marshalers-private.h
nimf-marshalers.c: nimf-marshalers.list
$(AM_V_GEN) glib-genmarshal --prefix=nimf_cclosure_marshal \
--body nimf-marshalers.list \
> nimf-marshalers.c
nimf-enum-types-private.h: nimf-key-syms.h \
nimf-types.h \
nimf-enum-types-private.h.template
$(AM_V_GEN) glib-mkenums --identifier-prefix Nimf \
--template nimf-enum-types-private.h.template \
nimf-key-syms.h nimf-types.h \
> nimf-enum-types-private.h
nimf-enum-types.c: nimf-key-syms.h \
nimf-types.h \
nimf-enum-types.c.template
$(AM_V_GEN) glib-mkenums --identifier-prefix Nimf \
--template nimf-enum-types.c.template \
nimf-key-syms.h nimf-types.h \
> nimf-enum-types.c
nimf-message-enum-types-private.h: \
nimf-message-private.h \
nimf-message-enum-types-private.h.template
$(AM_V_GEN) glib-mkenums \
--identifier-prefix Nimf \
--template nimf-message-enum-types-private.h.template \
nimf-message-private.h > nimf-message-enum-types-private.h
nimf-message-enum-types.c: nimf-message.c nimf-enum-types.c.template
$(AM_V_GEN) glib-mkenums \
--identifier-prefix Nimf \
--template nimf-message-enum-types.c.template \
nimf-message-private.h > nimf-message-enum-types.c
pkgconfigdir = $(libdir)/pkgconfig
pkgconfig_DATA = nimf.pc
gsettings_SCHEMAS = org.nimf.gschema.xml
@GSETTINGS_RULES@
EXTRA_DIST = nimf.pc.in
install-data-hook:
rm -f $(DESTDIR)$(libdir)/libnimf.la
uninstall-hook:
-rm -f $(DESTDIR)$(libdir)/libnimf.so*
-rmdir -p $(DESTDIR)$(libdir)/nimf
-rmdir -p $(DESTDIR)$(nimfincludedir)
CLEANFILES = $(BUILT_SOURCES)
DISTCLEANFILES = Makefile.in

View File

@@ -0,0 +1,357 @@
/* -*- Mode: C; indent-tabs-mode: nil; c-basic-offset: 2; tab-width: 2 -*- */
/*
* nimf-candidatable.c
* This file is part of Nimf.
*
* Copyright (C) 2018,2019 Hodong Kim <cogniti@gmail.com>
*
* Nimf is free software: you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published
* by the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Nimf is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; If not, see <http://www.gnu.org/licenses/>.
*/
#include "nimf-candidatable.h"
G_DEFINE_INTERFACE (NimfCandidatable, nimf_candidatable, G_TYPE_OBJECT)
static void
nimf_candidatable_default_init (NimfCandidatableInterface *iface)
{
g_debug (G_STRLOC ": %s", G_STRFUNC);
}
/**
* nimf_candidatable_show:
* @candidatable: a #NimfCandidatable
* @target: a #NimfServiceIC
* @show_entry: %TRUE if the entry for auxiliary text should be shown
*/
void
nimf_candidatable_show (NimfCandidatable *candidatable,
NimfServiceIC *target,
gboolean show_entry)
{
g_debug (G_STRLOC ": %s", G_STRFUNC);
NimfCandidatableInterface *iface;
g_return_if_fail (NIMF_IS_CANDIDATABLE (candidatable));
iface = NIMF_CANDIDATABLE_GET_IFACE (candidatable);
if (iface->show)
iface->show (candidatable, target, show_entry);
}
/**
* nimf_candidatable_hide:
* @candidatable: a #NimfCandidatable
*
* Hides the candidatable
*/
void
nimf_candidatable_hide (NimfCandidatable *candidatable)
{
g_debug (G_STRLOC ": %s", G_STRFUNC);
NimfCandidatableInterface *iface;
g_return_if_fail (NIMF_IS_CANDIDATABLE (candidatable));
iface = NIMF_CANDIDATABLE_GET_IFACE (candidatable);
if (iface->hide)
iface->hide (candidatable);
}
/**
* nimf_candidatable_is_visible:
* @candidatable: a #NimfCandidatable
*
* Returns: %TRUE if the @candidatable is visible
*/
gboolean
nimf_candidatable_is_visible (NimfCandidatable *candidatable)
{
g_debug (G_STRLOC ": %s", G_STRFUNC);
NimfCandidatableInterface *iface;
g_return_val_if_fail (NIMF_IS_CANDIDATABLE (candidatable), FALSE);
iface = NIMF_CANDIDATABLE_GET_IFACE (candidatable);
if (iface->is_visible)
return iface->is_visible (candidatable);
return FALSE;
}
/**
* nimf_candidatable_clear:
* @candidatable: a #NimfCandidatable
* @target: a #NimfServiceIC
*
* Clears the contents of the candidatable
*/
void
nimf_candidatable_clear (NimfCandidatable *candidatable,
NimfServiceIC *target)
{
g_debug (G_STRLOC ": %s", G_STRFUNC);
NimfCandidatableInterface *iface;
g_return_if_fail (NIMF_IS_CANDIDATABLE (candidatable));
iface = NIMF_CANDIDATABLE_GET_IFACE (candidatable);
if (iface->clear)
iface->clear (candidatable, target);
}
/**
* nimf_candidatable_set_page_values:
* @candidatable: a #NimfCandidatable
* @target: a #NimfServiceIC
* @page_index: page index
* @n_pages: the number of pages
* @page_size: page size
*
* Sets page values.
*/
void
nimf_candidatable_set_page_values (NimfCandidatable *candidatable,
NimfServiceIC *target,
gint page_index,
gint n_pages,
gint page_size)
{
g_debug (G_STRLOC ": %s", G_STRFUNC);
NimfCandidatableInterface *iface;
g_return_if_fail (NIMF_IS_CANDIDATABLE (candidatable));
iface = NIMF_CANDIDATABLE_GET_IFACE (candidatable);
if (iface->set_page_values)
iface->set_page_values (candidatable,
target,
page_index,
n_pages,
page_size);
}
/**
* nimf_candidatable_append:
* @candidatable: a #NimfCandidatable
* @text1: text for the first column; @text1 must be non-%NULL.
* @text2: (nullable): text for the second column; @text2 allows %NULL.
*
* After appending a row, adds @text1 to the first column and @text2 to the
* second column.
*/
void
nimf_candidatable_append (NimfCandidatable *candidatable,
const gchar *text1,
const gchar *text2)
{
g_debug (G_STRLOC ": %s", G_STRFUNC);
NimfCandidatableInterface *iface;
g_return_if_fail (NIMF_IS_CANDIDATABLE (candidatable));
iface = NIMF_CANDIDATABLE_GET_IFACE (candidatable);
if (iface->append)
iface->append (candidatable, text1, text2);
}
/**
* nimf_candidatable_get_selected_index:
* @candidatable: a #NimfCandidatable
*
* Returns: index of the selected row
*/
gint
nimf_candidatable_get_selected_index (NimfCandidatable *candidatable)
{
g_debug (G_STRLOC ": %s", G_STRFUNC);
NimfCandidatableInterface *iface;
g_return_val_if_fail (NIMF_IS_CANDIDATABLE (candidatable), 0);
iface = NIMF_CANDIDATABLE_GET_IFACE (candidatable);
if (iface->get_selected_index)
return iface->get_selected_index (candidatable);
return 0;
}
/**
* nimf_candidatable_get_selected_text:
* @candidatable: a #NimfCandidatable
*
* Returns: text of the first column in the selected row
*/
gchar *
nimf_candidatable_get_selected_text (NimfCandidatable *candidatable)
{
g_debug (G_STRLOC ": %s", G_STRFUNC);
NimfCandidatableInterface *iface;
g_return_val_if_fail (NIMF_IS_CANDIDATABLE (candidatable), NULL);
iface = NIMF_CANDIDATABLE_GET_IFACE (candidatable);
if (iface->get_selected_text)
return iface->get_selected_text (candidatable);
return NULL;
}
/**
* nimf_candidatable_select_first_item_in_page:
* @candidatable: a #NimfCandidatable
*
* Selects the first item in the page.
*/
void
nimf_candidatable_select_first_item_in_page (NimfCandidatable *candidatable)
{
g_debug (G_STRLOC ": %s", G_STRFUNC);
NimfCandidatableInterface *iface;
g_return_if_fail (NIMF_IS_CANDIDATABLE (candidatable));
iface = NIMF_CANDIDATABLE_GET_IFACE (candidatable);
if (iface->select_first_item_in_page)
iface->select_first_item_in_page (candidatable);
}
/**
* nimf_candidatable_select_last_item_in_page:
* @candidatable: a #NimfCandidatable
*
* Selects the last item in the page.
*/
void
nimf_candidatable_select_last_item_in_page (NimfCandidatable *candidatable)
{
g_debug (G_STRLOC ": %s", G_STRFUNC);
NimfCandidatableInterface *iface;
g_return_if_fail (NIMF_IS_CANDIDATABLE (candidatable));
iface = NIMF_CANDIDATABLE_GET_IFACE (candidatable);
if (iface->select_last_item_in_page)
iface->select_last_item_in_page (candidatable);
}
/**
* nimf_candidatable_select_item_by_index_in_page:
* @candidatable: a #NimfCandidatable
* @index: a gint
*
* Selects an item by the index in the page.
*/
void
nimf_candidatable_select_item_by_index_in_page (NimfCandidatable *candidatable,
gint index)
{
g_debug (G_STRLOC ": %s", G_STRFUNC);
NimfCandidatableInterface *iface;
g_return_if_fail (NIMF_IS_CANDIDATABLE (candidatable));
iface = NIMF_CANDIDATABLE_GET_IFACE (candidatable);
if (iface->select_item_by_index_in_page)
iface->select_item_by_index_in_page (candidatable, index);
}
/**
* nimf_candidatable_select_previous_item:
* @candidatable: a #NimfCandidatable
*
* Selects the previous item.
*/
void
nimf_candidatable_select_previous_item (NimfCandidatable *candidatable)
{
g_debug (G_STRLOC ": %s", G_STRFUNC);
NimfCandidatableInterface *iface;
g_return_if_fail (NIMF_IS_CANDIDATABLE (candidatable));
iface = NIMF_CANDIDATABLE_GET_IFACE (candidatable);
if (iface->select_previous_item)
iface->select_previous_item (candidatable);
}
/**
* nimf_candidatable_select_next_item:
* @candidatable: a #NimfCandidatable
*
* Selects the next item.
*/
void
nimf_candidatable_select_next_item (NimfCandidatable *candidatable)
{
g_debug (G_STRLOC ": %s", G_STRFUNC);
NimfCandidatableInterface *iface;
g_return_if_fail (NIMF_IS_CANDIDATABLE (candidatable));
iface = NIMF_CANDIDATABLE_GET_IFACE (candidatable);
if (iface->select_next_item)
iface->select_next_item (candidatable);
}
/**
* nimf_candidatable_set_auxiliary_text:
* @candidatable: a #NimfCandidatable
* @text: text
* @cursor_pos: cursor position within @text
*
* Sets auxiliary text.
*/
void
nimf_candidatable_set_auxiliary_text (NimfCandidatable *candidatable,
const gchar *text,
gint cursor_pos)
{
g_debug (G_STRLOC ": %s", G_STRFUNC);
NimfCandidatableInterface *iface;
g_return_if_fail (NIMF_IS_CANDIDATABLE (candidatable));
iface = NIMF_CANDIDATABLE_GET_IFACE (candidatable);
if (iface->set_auxiliary_text)
iface->set_auxiliary_text (candidatable, text, cursor_pos);
}

View File

@@ -0,0 +1,128 @@
/* -*- Mode: C; indent-tabs-mode: nil; c-basic-offset: 2; tab-width: 2 -*- */
/*
* nimf-candidatable.h
* This file is part of Nimf.
*
* Copyright (C) 2018,2019 Hodong Kim <cogniti@gmail.com>
*
* Nimf is free software: you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published
* by the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Nimf is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __NIMF_CANDIDATABLE_H__
#define __NIMF_CANDIDATABLE_H__
#include <glib-object.h>
#include "nimf-service-ic.h"
G_BEGIN_DECLS
#define NIMF_TYPE_CANDIDATABLE nimf_candidatable_get_type ()
G_DECLARE_INTERFACE (NimfCandidatable, nimf_candidatable, NIMF, CANDIDATABLE, GObject)
#ifndef __GTK_DOC_IGNORE__
typedef struct _NimfServiceIC NimfServiceIC;
#endif
typedef struct _NimfCandidatable NimfCandidatable; /* dummy typedef */
typedef struct _NimfCandidatableInterface NimfCandidatableInterface;
/**
* NimfCandidatableInterface:
* @parent: The parent interface.
* @show: Shows the candidatable.
* @hide: Hides the candidatable.
* @is_visible: Determines whether the candidatable is visible.
* @clear: Clears the contents of the candidatable.
* @set_page_values: Sets page values.
* @append: Appends a new candidate.
* @get_selected_index: Gets the index of the selected candidatable.
* @get_selected_text: Gets the text of the selected candidatable.
* @select_first_item_in_page: Selects first item in page.
* @select_last_item_in_page: Selects last item in page.
* @select_item_by_index_in_page: Selects item in page with the index given as the argument.
* @select_previous_item: Selects previus item.
* @select_next_item: Selects a next item.
* @set_auxiliary_text: Selects auxiliary text.
*
* Provides an interface for candidate window.
*/
struct _NimfCandidatableInterface
{
GTypeInterface parent;
void (* show) (NimfCandidatable *candidatable,
NimfServiceIC *target,
gboolean show_entry);
void (* hide) (NimfCandidatable *candidatable);
gboolean (* is_visible) (NimfCandidatable *candidatable);
void (* clear) (NimfCandidatable *candidatable,
NimfServiceIC *target);
void (* set_page_values) (NimfCandidatable *candidatable,
NimfServiceIC *target,
gint page_index,
gint n_pages,
gint page_size);
void (* append) (NimfCandidatable *candidatable,
const gchar *item1,
const gchar *item2);
gint (* get_selected_index) (NimfCandidatable *candidatable);
gchar * (* get_selected_text) (NimfCandidatable *candidatable);
void (* select_first_item_in_page) (NimfCandidatable *candidatable);
void (* select_last_item_in_page) (NimfCandidatable *candidatable);
void (* select_item_by_index_in_page) (NimfCandidatable *candidatable,
gint index);
void (* select_previous_item) (NimfCandidatable *candidatable);
void (* select_next_item) (NimfCandidatable *candidatable);
void (* set_auxiliary_text) (NimfCandidatable *candidatable,
const gchar *text,
gint cursor_pos);
};
void nimf_candidatable_show (NimfCandidatable *candidatable,
NimfServiceIC *target,
gboolean show_entry);
void nimf_candidatable_hide (NimfCandidatable *candidatable);
gboolean nimf_candidatable_is_visible (NimfCandidatable *candidatable);
void nimf_candidatable_clear (NimfCandidatable *candidatable,
NimfServiceIC *target);
void nimf_candidatable_set_page_values (NimfCandidatable *candidatable,
NimfServiceIC *target,
gint page_index,
gint n_pages,
gint page_size);
void nimf_candidatable_append (NimfCandidatable *candidatable,
const gchar *text1,
const gchar *text2);
gint nimf_candidatable_get_selected_index
(NimfCandidatable *candidatable);
gchar *nimf_candidatable_get_selected_text
(NimfCandidatable *candidatable);
void nimf_candidatable_select_first_item_in_page
(NimfCandidatable *candidatable);
void nimf_candidatable_select_last_item_in_page
(NimfCandidatable *candidatable);
void nimf_candidatable_select_item_by_index_in_page
(NimfCandidatable *candidatable,
gint index);
void nimf_candidatable_select_previous_item
(NimfCandidatable *candidatable);
void nimf_candidatable_select_next_item
(NimfCandidatable *candidatable);
void nimf_candidatable_set_auxiliary_text
(NimfCandidatable *candidatable,
const gchar *text,
gint cursor_pos);
G_END_DECLS
#endif /* __NIMF_CANDIDATABLE_H__ */

View File

@@ -0,0 +1,430 @@
/* -*- Mode: C; indent-tabs-mode: nil; c-basic-offset: 2; tab-width: 2 -*- */
/*
* nimf-engine.c
* This file is part of Nimf.
*
* Copyright (C) 2015-2019 Hodong Kim <cogniti@gmail.com>
*
* Nimf is free software: you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published
* by the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Nimf is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; If not, see <http://www.gnu.org/licenses/>.
*/
#include "nimf-engine.h"
#include "nimf-server.h"
#include "nimf-server-private.h"
struct _NimfEnginePrivate
{
gchar *surrounding_text;
gint surrounding_cursor_index;
};
G_DEFINE_ABSTRACT_TYPE_WITH_PRIVATE (NimfEngine, nimf_engine, G_TYPE_OBJECT);
/**
* nimf_engine_reset:
* @engine: a #NimfEngine
* @ic: a #NimfServiceIC associated with @engine
*
* Resets the @engine.
*/
void nimf_engine_reset (NimfEngine *engine,
NimfServiceIC *ic)
{
g_debug (G_STRLOC ": %s", G_STRFUNC);
g_return_if_fail (NIMF_IS_ENGINE (engine));
NimfEngineClass *class = NIMF_ENGINE_GET_CLASS (engine);
if (class->reset)
class->reset (engine, ic);
}
/**
* nimf_engine_focus_in:
* @engine: a #NimfEngine
* @ic: a #NimfServiceIC associated with @engine
*
* Notifies the language engine that the caller has gained focus.
*/
void
nimf_engine_focus_in (NimfEngine *engine,
NimfServiceIC *ic)
{
g_debug (G_STRLOC ": %s", G_STRFUNC);
g_return_if_fail (NIMF_IS_ENGINE (engine));
NimfEngineClass *class = NIMF_ENGINE_GET_CLASS (engine);
if (class->focus_in)
class->focus_in (engine, ic);
}
/**
* nimf_engine_focus_out:
* @engine: a #NimfEngine
* @ic: a #NimfServiceIC associated with @engine
*
* Notifies the language engine that the caller has lost focus.
*/
void nimf_engine_focus_out (NimfEngine *engine,
NimfServiceIC *ic)
{
g_debug (G_STRLOC ": %s", G_STRFUNC);
g_return_if_fail (NIMF_IS_ENGINE (engine));
NimfEngineClass *class = NIMF_ENGINE_GET_CLASS (engine);
if (class->focus_out)
class->focus_out (engine, ic);
}
/**
* nimf_engine_filter_event:
* @engine: a #NimfEngine
* @ic: a #NimfServiceIC associated with @engine
* @event: a #NimfEvent
*
* Let the language engine handle the event.
*
* Returns: %TRUE if the language engine consumed the event.
*/
gboolean
nimf_engine_filter_event (NimfEngine *engine,
NimfServiceIC *ic,
NimfEvent *event)
{
g_debug (G_STRLOC ": %s", G_STRFUNC);
NimfEngineClass *class = NIMF_ENGINE_GET_CLASS (engine);
if (class->filter_event)
return class->filter_event (engine, ic, event);
else
return FALSE;
}
/**
* nimf_engine_set_surrounding:
* @engine: a #NimfEngine
* @text: surrounding text
* @len: the byte length of @text
* @cursor_index: the character index of the cursor within @text.
*
* Sets surrounding text in @engine. This function is expected to be
* called in response to nimf_engine_get_surrounding().
*/
void
nimf_engine_set_surrounding (NimfEngine *engine,
const char *text,
gint len,
gint cursor_index)
{
g_debug (G_STRLOC ": %s", G_STRFUNC);
g_return_if_fail (NIMF_IS_ENGINE (engine));
g_return_if_fail (text != NULL || len == 0);
g_free (engine->priv->surrounding_text);
engine->priv->surrounding_text = g_strndup (text, len);
engine->priv->surrounding_cursor_index = cursor_index;
}
/**
* nimf_engine_get_surrounding:
* @engine: a #NimfEngine
* @ic: a #NimfServiceIC associated with @engine
* @text: (out) (transfer full): location to store surrounding text
* @cursor_index: (out) (transfer full): location to store cursor index
*
* This function internally calls nimf_engine_emit_retrieve_surrounding().
* Gets surrounding text from the caller of nimf_im_set_surrounding(),
* if available.
*
* Returns: %TRUE if surrounding text is available
*/
gboolean
nimf_engine_get_surrounding (NimfEngine *engine,
NimfServiceIC *ic,
gchar **text,
gint *cursor_index)
{
g_debug (G_STRLOC ": %s", G_STRFUNC);
gboolean retval = nimf_engine_emit_retrieve_surrounding (engine, ic);
if (retval)
{
if (engine->priv->surrounding_text)
*text = g_strdup (engine->priv->surrounding_text);
else
*text = g_strdup ("");
*cursor_index = engine->priv->surrounding_cursor_index;
}
else
{
*text = NULL;
*cursor_index = 0;
}
return retval;
}
/**
* nimf_engine_set_method:
* @engine: a #NimfEngine
* @method_id: method id
*
* The engine may provide multiple input methods. Sets an input method by
* @method_id
*/
void
nimf_engine_set_method (NimfEngine *engine,
const gchar *method_id)
{
g_debug (G_STRLOC ": %s", G_STRFUNC);
NimfEngineClass *class = NIMF_ENGINE_GET_CLASS (engine);
if (class->set_method)
class->set_method (engine, method_id);
}
/**
* nimf_engine_emit_preedit_start:
* @engine: a #NimfEngine
* @ic: a #NimfServiceIC associated with @engine
*
* Emits the #NimfIM::preedit-start signal.
*/
void
nimf_engine_emit_preedit_start (NimfEngine *engine,
NimfServiceIC *ic)
{
g_debug (G_STRLOC ": %s", G_STRFUNC);
nimf_service_ic_emit_preedit_start (ic);
}
/**
* nimf_engine_emit_preedit_changed:
* @engine: a #NimfEngine
* @ic: a #NimfServiceIC associated with @engine
* @preedit_string: preedit string
* @attrs: #NimfPreeditAttr array
* @cursor_pos: cursor position within @preedit_string
*
* Emits the #NimfIM::preedit-changed signal.
*/
void
nimf_engine_emit_preedit_changed (NimfEngine *engine,
NimfServiceIC *ic,
const gchar *preedit_string,
NimfPreeditAttr **attrs,
gint cursor_pos)
{
g_debug (G_STRLOC ": %s", G_STRFUNC);
nimf_service_ic_emit_preedit_changed (ic, preedit_string, attrs, cursor_pos);
}
/**
* nimf_engine_emit_preedit_end:
* @engine: a #NimfEngine
* @ic: a #NimfServiceIC associated with @engine
*
* Emits the #NimfIM::preedit-end signal.
*/
void
nimf_engine_emit_preedit_end (NimfEngine *engine,
NimfServiceIC *ic)
{
g_debug (G_STRLOC ": %s", G_STRFUNC);
nimf_service_ic_emit_preedit_end (ic);
}
/**
* nimf_engine_emit_commit:
* @engine: a #NimfEngine
* @ic: a #NimfServiceIC associated with @engine
* @text: text to commit
*
* Emits the #NimfIM::commit signal.
*/
void
nimf_engine_emit_commit (NimfEngine *engine,
NimfServiceIC *ic,
const gchar *text)
{
g_debug (G_STRLOC ": %s", G_STRFUNC);
nimf_service_ic_emit_commit (ic, text);
}
/**
* nimf_engine_emit_delete_surrounding:
* @engine: a #NimfEngine
* @ic: a #NimfServiceIC associated with @engine
* @offset: the character offset from the cursor position of the text to be
* deleted. A negative value indicates a position before the cursor.
* @n_chars: the number of characters to be deleted
*
* Emits the #NimfIM::delete-surrounding signal.
*/
gboolean
nimf_engine_emit_delete_surrounding (NimfEngine *engine,
NimfServiceIC *ic,
gint offset,
gint n_chars)
{
g_debug (G_STRLOC ": %s", G_STRFUNC);
return nimf_service_ic_emit_delete_surrounding (ic, offset, n_chars);
}
/**
* nimf_engine_emit_retrieve_surrounding:
* @engine: a #NimfEngine
* @ic: a #NimfServiceIC associated with @engine
*
* Emits the #NimfIM::retrieve-surrounding signal.
*/
gboolean
nimf_engine_emit_retrieve_surrounding (NimfEngine *engine,
NimfServiceIC *ic)
{
g_debug (G_STRLOC ": %s", G_STRFUNC);
return nimf_service_ic_emit_retrieve_surrounding (ic);
}
/**
* nimf_engine_status_changed:
* @engine: a #NimfEngine
*
* Notifies that the status of the @engine has changed.
*/
void
nimf_engine_status_changed (NimfEngine *engine)
{
g_debug (G_STRLOC ": %s", G_STRFUNC);
g_signal_emit_by_name (nimf_server_get_default (), "engine-status-changed",
nimf_engine_get_id (engine),
nimf_engine_get_icon_name (engine));
}
/**
* nimf_engine_emit_beep:
* @engine: a #NimfEngine
* @ic: a #NimfServiceIC associated with @engine
*
* Emits the #NimfIM::beep signal.
*/
void
nimf_engine_emit_beep (NimfEngine *engine,
NimfServiceIC *ic)
{
g_debug (G_STRLOC ": %s", G_STRFUNC);
nimf_service_ic_emit_beep (ic);
}
static void
nimf_engine_init (NimfEngine *engine)
{
g_debug (G_STRLOC ": %s", G_STRFUNC);
engine->priv = nimf_engine_get_instance_private (engine);
}
static void
nimf_engine_finalize (GObject *object)
{
g_debug (G_STRLOC ": %s", G_STRFUNC);
NimfEngine *engine = NIMF_ENGINE (object);
g_free (engine->priv->surrounding_text);
G_OBJECT_CLASS (nimf_engine_parent_class)->finalize (object);
}
/**
* nimf_engine_get_id:
* @engine: #NimfEngine
*
* Returns: (transfer none): engine id
*/
const gchar *
nimf_engine_get_id (NimfEngine *engine)
{
g_debug (G_STRLOC ": %s", G_STRFUNC);
NimfEngineClass *class = NIMF_ENGINE_GET_CLASS (engine);
if (class->get_id)
return class->get_id (engine);
else
g_critical ("You should implement your_engine_get_id ()");
return NULL;
}
/**
* nimf_engine_get_candidatable:
* @engine: #NimfEngine
*
* Returns: (transfer none): a #NimfCandidatable
*/
NimfCandidatable *
nimf_engine_get_candidatable (NimfEngine *engine)
{
g_debug (G_STRLOC ": %s", G_STRFUNC);
return nimf_server_get_default ()->priv->candidatable;
}
/**
* nimf_engine_get_icon_name:
* @engine: #NimfEngine
*
* Returns: (transfer none): icon name
*/
const gchar *
nimf_engine_get_icon_name (NimfEngine *engine)
{
g_debug (G_STRLOC ": %s", G_STRFUNC);
NimfEngineClass *class = NIMF_ENGINE_GET_CLASS (engine);
if (class->get_icon_name)
return class->get_icon_name (engine);
else
g_critical ("You should implement your_engine_get_icon_name ()");
return NULL;
}
static void
nimf_engine_class_init (NimfEngineClass *class)
{
g_debug (G_STRLOC ": %s", G_STRFUNC);
G_OBJECT_CLASS (class)->finalize = nimf_engine_finalize;
}

View File

@@ -0,0 +1,151 @@
/* -*- Mode: C; indent-tabs-mode: nil; c-basic-offset: 2; tab-width: 2 -*- */
/*
* nimf-engine.h
* This file is part of Nimf.
*
* Copyright (C) 2015-2019 Hodong Kim <cogniti@gmail.com>
*
* Nimf is free software: you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published
* by the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Nimf is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __NIMF_ENGINE_H__
#define __NIMF_ENGINE_H__
#include <glib-object.h>
#include "nimf-events.h"
#include "nimf-service-ic.h"
#include "nimf-candidatable.h"
G_BEGIN_DECLS
#define NIMF_TYPE_ENGINE (nimf_engine_get_type ())
#define NIMF_ENGINE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NIMF_TYPE_ENGINE, NimfEngine))
#define NIMF_ENGINE_CLASS(class) (G_TYPE_CHECK_CLASS_CAST ((class), NIMF_TYPE_ENGINE, NimfEngineClass))
#define NIMF_IS_ENGINE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NIMF_TYPE_ENGINE))
#define NIMF_ENGINE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), NIMF_TYPE_ENGINE, NimfEngineClass))
#ifndef __GTK_DOC_IGNORE__
typedef struct _NimfServiceIC NimfServiceIC;
typedef struct _NimfCandidatable NimfCandidatable;
#endif
typedef struct _NimfEngine NimfEngine;
typedef struct _NimfEngineClass NimfEngineClass;
typedef struct _NimfEnginePrivate NimfEnginePrivate;
struct _NimfEngine
{
GObject parent_instance;
NimfEnginePrivate *priv;
};
/**
* NimfEngineClass:
* @filter_event: If the language engine consumes the event, returns %TRUE.
* @reset: Resets the language engine.
* @focus_in: Called via nimf_im_focus_in() when the caller has gained focus.
* @focus_out: Called via nimf_im_focus_out() when the caller has lost focus.
* @set_method: Sets the method in the language engine.
* @candidate_page_up: handler when candidate page up
* @candidate_page_down: handler when candidate page down
* @candidate_clicked: handler when candidate clicked
* @candidate_scrolled: handler when candidate scrolled
* @get_id: Gets the language engine id.
* @get_icon_name: Gets the language engine name.
*/
struct _NimfEngineClass
{
/*< private >*/
GObjectClass parent_class;
/*< public >*/
/* Virtual functions */
gboolean (* filter_event) (NimfEngine *engine,
NimfServiceIC *ic,
NimfEvent *event);
void (* reset) (NimfEngine *engine,
NimfServiceIC *ic);
void (* focus_in) (NimfEngine *engine,
NimfServiceIC *ic);
void (* focus_out) (NimfEngine *engine,
NimfServiceIC *ic);
void (* set_method) (NimfEngine *engine,
const gchar *method_id);
/* candidate */
gboolean (* candidate_page_up) (NimfEngine *engine,
NimfServiceIC *ic);
gboolean (* candidate_page_down) (NimfEngine *engine,
NimfServiceIC *ic);
void (* candidate_clicked) (NimfEngine *engine,
NimfServiceIC *ic,
gchar *text,
gint index);
void (* candidate_scrolled) (NimfEngine *engine,
NimfServiceIC *ic,
gdouble value);
/* info */
const gchar * (* get_id) (NimfEngine *engine);
const gchar * (* get_icon_name) (NimfEngine *engine);
};
GType nimf_engine_get_type (void) G_GNUC_CONST;
gboolean nimf_engine_filter_event (NimfEngine *engine,
NimfServiceIC *ic,
NimfEvent *event);
void nimf_engine_reset (NimfEngine *engine,
NimfServiceIC *ic);
void nimf_engine_focus_in (NimfEngine *engine,
NimfServiceIC *ic);
void nimf_engine_focus_out (NimfEngine *engine,
NimfServiceIC *ic);
void nimf_engine_set_surrounding (NimfEngine *engine,
const char *text,
gint len,
gint cursor_index);
gboolean nimf_engine_get_surrounding (NimfEngine *engine,
NimfServiceIC *ic,
gchar **text,
gint *cursor_index);
void nimf_engine_status_changed (NimfEngine *engine);
void nimf_engine_set_method (NimfEngine *engine,
const gchar *method_id);
/* signals */
void nimf_engine_emit_preedit_start (NimfEngine *engine,
NimfServiceIC *ic);
void nimf_engine_emit_preedit_changed (NimfEngine *engine,
NimfServiceIC *ic,
const gchar *preedit_string,
NimfPreeditAttr **attrs,
gint cursor_pos);
void nimf_engine_emit_preedit_end (NimfEngine *engine,
NimfServiceIC *ic);
void nimf_engine_emit_commit (NimfEngine *engine,
NimfServiceIC *ic,
gchar const *text);
gboolean nimf_engine_emit_retrieve_surrounding (NimfEngine *engine,
NimfServiceIC *ic);
gboolean nimf_engine_emit_delete_surrounding (NimfEngine *engine,
NimfServiceIC *ic,
gint offset,
gint n_chars);
void nimf_engine_emit_beep (NimfEngine *engine,
NimfServiceIC *ic);
/* info */
const gchar *nimf_engine_get_id (NimfEngine *engine);
const gchar *nimf_engine_get_icon_name (NimfEngine *engine);
/* candidate */
NimfCandidatable *nimf_engine_get_candidatable (NimfEngine *engine);
G_END_DECLS
#endif /* __NIMF_ENGINE_H__ */

View File

@@ -0,0 +1,41 @@
/*** BEGIN file-header ***/
/*
* This file is part of Nimf.
*
* Nimf is free software: you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published
* by the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Nimf is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __NIMF_ENUM_TYPES_H__
#define __NIMF_ENUM_TYPES_H__
#include <glib-object.h>
G_BEGIN_DECLS
/*** END file-header ***/
/*** BEGIN file-production ***/
/* enumerations from "@filename@" */
/*** END file-production ***/
/*** BEGIN value-header ***/
GType @enum_name@_get_type (void) G_GNUC_CONST;
#define @ENUMPREFIX@_TYPE_@ENUMSHORT@ (@enum_name@_get_type ())
/*** END value-header ***/
/*** BEGIN file-tail ***/
G_END_DECLS
#endif /* __NIMF_ENUM_TYPES_H__ */
/*** END file-tail ***/

View File

@@ -0,0 +1,55 @@
/*** BEGIN file-header ***/
/*
* This file is part of Nimf.
*
* Nimf is free software: you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published
* by the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Nimf is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; If not, see <http://www.gnu.org/licenses/>.
*/
#include "nimf-enum-types-private.h"
#include "nimf-key-syms.h"
#include "nimf-types.h"
/*** END file-header ***/
/*** BEGIN file-production ***/
/* enumerations from "@filename@" */
/*** END file-production ***/
/*** BEGIN value-header ***/
GType
@enum_name@_get_type (void)
{
static volatile gsize g_define_type_id__volatile = 0;
if (g_once_init_enter (&g_define_type_id__volatile))
{
static const G@Type@Value values[] = {
/*** END value-header ***/
/*** BEGIN value-production ***/
{ @VALUENAME@, "@VALUENAME@", "@valuenick@" },
/*** END value-production ***/
/*** BEGIN value-tail ***/
{ 0, NULL, NULL }
};
GType g_define_type_id =
g_@type@_register_static (g_intern_static_string ("@EnumName@"), values);
g_once_init_leave (&g_define_type_id__volatile, g_define_type_id);
}
return g_define_type_id__volatile;
}
/*** END value-tail ***/

View File

@@ -0,0 +1,163 @@
/* -*- Mode: C; indent-tabs-mode: nil; c-basic-offset: 2; tab-width: 2 -*- */
/*
* nimf-events.c
* This file is part of Nimf.
*
* Copyright (C) 2015-2019 Hodong Kim <cogniti@gmail.com>
*
* Nimf is free software: you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published
* by the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Nimf is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; If not, see <http://www.gnu.org/licenses/>.
*/
#include "nimf-events.h"
/**
* SECTION:nimf-events
* @title: Events
* @section_id: nimf-events
*/
/**
* nimf_event_keycode_to_qwerty_keyval:
* @event: a #NimfEvent
*
* Converts @event to qwerty keyval. Use only for PC keyboards.
*
* Returns: the #guint value
*/
guint
nimf_event_keycode_to_qwerty_keyval (const NimfEvent *event)
{
g_debug (G_STRLOC ": %s", G_STRFUNC);
guint keyval = 0;
gboolean is_shift = event->key.state & NIMF_SHIFT_MASK;
switch (event->key.hardware_keycode)
{
/* 20(-) ~ 21(=) */
case 20: keyval = is_shift ? '_' : '-'; break;
case 21: keyval = is_shift ? '+' : '='; break;
/* 24(q) ~ 35(]) */
case 24: keyval = is_shift ? 'Q' : 'q'; break;
case 25: keyval = is_shift ? 'W' : 'w'; break;
case 26: keyval = is_shift ? 'E' : 'e'; break;
case 27: keyval = is_shift ? 'R' : 'r'; break;
case 28: keyval = is_shift ? 'T' : 't'; break;
case 29: keyval = is_shift ? 'Y' : 'y'; break;
case 30: keyval = is_shift ? 'U' : 'u'; break;
case 31: keyval = is_shift ? 'I' : 'i'; break;
case 32: keyval = is_shift ? 'O' : 'o'; break;
case 33: keyval = is_shift ? 'P' : 'p'; break;
case 34: keyval = is_shift ? '{' : '['; break;
case 35: keyval = is_shift ? '}' : ']'; break;
/* 38(a) ~ 48(') */
case 38: keyval = is_shift ? 'A' : 'a'; break;
case 39: keyval = is_shift ? 'S' : 's'; break;
case 40: keyval = is_shift ? 'D' : 'd'; break;
case 41: keyval = is_shift ? 'F' : 'f'; break;
case 42: keyval = is_shift ? 'G' : 'g'; break;
case 43: keyval = is_shift ? 'H' : 'h'; break;
case 44: keyval = is_shift ? 'J' : 'j'; break;
case 45: keyval = is_shift ? 'K' : 'k'; break;
case 46: keyval = is_shift ? 'L' : 'l'; break;
case 47: keyval = is_shift ? ':' : ';'; break;
case 48: keyval = is_shift ? '"' : '\''; break;
/* 52(z) ~ 61(?) */
case 52: keyval = is_shift ? 'Z' : 'z'; break;
case 53: keyval = is_shift ? 'X' : 'x'; break;
case 54: keyval = is_shift ? 'C' : 'c'; break;
case 55: keyval = is_shift ? 'V' : 'v'; break;
case 56: keyval = is_shift ? 'B' : 'b'; break;
case 57: keyval = is_shift ? 'N' : 'n'; break;
case 58: keyval = is_shift ? 'M' : 'm'; break;
case 59: keyval = is_shift ? '<' : ','; break;
case 60: keyval = is_shift ? '>' : '.'; break;
case 61: keyval = is_shift ? '?' : '/'; break;
default: keyval = event->key.keyval; break;
}
return keyval;
}
/**
* nimf_event_matches:
* @event: a #NimfEvent
* @keys: a %NULL-terminated array of #NimfKey
*
* Checks if @event matches one of the @keys.
*
* Returns: #TRUE if a match was found.
*/
gboolean
nimf_event_matches (NimfEvent *event, const NimfKey **keys)
{
g_debug (G_STRLOC ": %s: event->key.state: %d", G_STRFUNC, event->key.state);
gint i;
/* Ignore NIMF_MOD2_MASK (Number),
* NIMF_LOCK_MASK (CapsLock),
* virtual modifiers
*/
guint mods_mask = NIMF_SHIFT_MASK |
NIMF_CONTROL_MASK |
NIMF_MOD1_MASK |
NIMF_MOD3_MASK |
NIMF_MOD4_MASK |
NIMF_MOD5_MASK;
for (i = 0; keys[i] != 0; i++)
{
if ((event->key.state & mods_mask) == (keys[i]->state & mods_mask) &&
event->key.keyval == keys[i]->keyval)
return TRUE;
}
return FALSE;
}
/**
* nimf_event_new:
* @type: a #NimfEventType
*
* Creates a new event of the given type. All fields are set to 0.
*
* Returns: a new #NimfEvent, which should be freed with nimf_event_free().
*/
NimfEvent *
nimf_event_new (NimfEventType type)
{
g_debug (G_STRLOC ": %s", G_STRFUNC);
NimfEvent *new_event = g_slice_new0 (NimfEvent);
new_event->type = type;
return new_event;
}
/**
* nimf_event_free:
* @event: a #NimfEvent
*
* Frees @event.
*/
void
nimf_event_free (NimfEvent *event)
{
g_debug (G_STRLOC ": %s", G_STRFUNC);
g_return_if_fail (event != NULL);
g_slice_free (NimfEvent, event);
}

View File

@@ -0,0 +1,88 @@
/* -*- Mode: C; indent-tabs-mode: nil; c-basic-offset: 2; tab-width: 2 -*- */
/*
* nimf-events.h
* This file is part of Nimf.
*
* Copyright (C) 2015-2019 Hodong Kim <cogniti@gmail.com>
*
* Nimf is free software: you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published
* by the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Nimf is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __NIMF_EVENTS_H__
#define __NIMF_EVENTS_H__
#include <glib-object.h>
#include "nimf-types.h"
G_BEGIN_DECLS
typedef struct _NimfEventKey NimfEventKey;
typedef union _NimfEvent NimfEvent;
/**
* NimfEventType:
* @NIMF_EVENT_NOTHING: a special code to indicate a null event.
* @NIMF_EVENT_KEY_PRESS: a key has been pressed.
* @NIMF_EVENT_KEY_RELEASE: a key has been released.
*/
typedef enum
{
NIMF_EVENT_NOTHING = -1,
NIMF_EVENT_KEY_PRESS = 0,
NIMF_EVENT_KEY_RELEASE = 1,
} NimfEventType;
/**
* NimfEventKey:
* @type: the type of the event (%NIMF_EVENT_KEY_PRESS or
* %NIMF_EVENT_KEY_RELEASE).
* @state: (type NimfModifierType): a bit-mask representing the state of
* the modifier keys (e.g. Control, Shift and Alt) and the pointer
* buttons. See #NimfModifierType.
* @keyval: the key that was pressed or released. See the
* `nimf-key-syms.h` header file for a complete list of Nimf key codes.
* @hardware_keycode: the raw code of the key that was pressed or released.
*
* Describes a key press or key release event.
*/
struct _NimfEventKey
{
NimfEventType type;
guint32 state;
guint32 keyval;
guint32 hardware_keycode;
};
/**
* NimfEvent:
* @type: a #NimfEventType
* @key: a #NimfEventKey
*
* A #NimfEvent contains a union.
*/
union _NimfEvent
{
NimfEventType type;
NimfEventKey key;
};
NimfEvent *nimf_event_new (NimfEventType type);
void nimf_event_free (NimfEvent *event);
gboolean nimf_event_matches (NimfEvent *event,
const NimfKey **keys);
guint nimf_event_keycode_to_qwerty_keyval (const NimfEvent *event);
G_END_DECLS
#endif /* __NIMF_EVENTS_H__ */

View File

@@ -0,0 +1,861 @@
/* -*- Mode: C; indent-tabs-mode: nil; c-basic-offset: 2; tab-width: 2 -*- */
/*
* nimf-im.c
* This file is part of Nimf.
*
* Copyright (C) 2015-2019 Hodong Kim <cogniti@gmail.com>
*
* Nimf is free software: you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published
* by the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Nimf is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; If not, see <http://www.gnu.org/licenses/>.
*/
#include "nimf-im.h"
#include <string.h>
#include "nimf-marshalers-private.h"
#include "nimf-message-private.h"
#include <errno.h>
#include <glib/gstdio.h>
#include <gio/gunixsocketaddress.h>
#include "nimf-utils.h"
#include <stdlib.h>
enum {
PREEDIT_START,
PREEDIT_END,
PREEDIT_CHANGED,
COMMIT,
RETRIEVE_SURROUNDING,
DELETE_SURROUNDING,
BEEP,
LAST_SIGNAL
};
static guint im_signals[LAST_SIGNAL] = { 0 };
static GMainContext *nimf_im_context = NULL;
static GSource *nimf_im_socket_source = NULL;
static GSource *nimf_im_default_source = NULL;
static GHashTable *nimf_im_table = NULL;
static NimfResult *nimf_im_result = NULL;
static GSocket *nimf_im_socket = NULL;
static gchar *nimf_im_socket_path = NULL;
struct _NimfIMPrivate
{
GObject parent_instance;
gchar *preedit_string;
NimfPreeditAttr **preedit_attrs;
gint cursor_pos;
guint16 id;
GFileMonitor *monitor;
uid_t uid;
gboolean created;
};
G_DEFINE_TYPE_WITH_PRIVATE (NimfIM, nimf_im, G_TYPE_OBJECT);
static uid_t
get_login_uid (void)
{
gchar *nptr;
gsize length;
uid_t uid;
if (!g_file_get_contents ("/proc/self/loginuid", &nptr, &length, NULL))
return -1;
errno = 0;
uid = strtol (nptr, NULL, 10);
if (errno)
return -1;
else
return uid;
}
static gboolean
nimf_im_is_connected ()
{
g_debug (G_STRLOC ": %s", G_STRFUNC);
return nimf_im_socket && g_socket_is_connected (nimf_im_socket);
}
static gboolean
on_incoming_message (GSocket *socket,
GIOCondition condition,
gpointer user_data)
{
g_debug (G_STRLOC ": %s: socket fd:%d", G_STRFUNC, g_socket_get_fd (socket));
nimf_message_unref (nimf_im_result->reply);
nimf_im_result->is_dispatched = TRUE;
if (condition & (G_IO_HUP | G_IO_ERR))
{
g_debug (G_STRLOC ": %s: G_IO_HUP | G_IO_ERR", G_STRFUNC);
/* Because two GSource is created over one socket,
* when G_IO_HUP | G_IO_ERR, callback can run two times.
* the following code avoid that callback runs two times. */
GSource *source = g_main_current_source ();
if (source == nimf_im_default_source)
g_source_destroy (nimf_im_socket_source);
else if (source == nimf_im_socket_source)
g_source_destroy (nimf_im_default_source);
if (!g_socket_is_closed (socket))
g_socket_close (socket, NULL);
nimf_im_result->reply = NULL;
gpointer im;
GHashTableIter iter;
g_hash_table_iter_init (&iter, nimf_im_table);
while (g_hash_table_iter_next (&iter, NULL, &im))
NIMF_IM (im)->priv->created = FALSE;
return G_SOURCE_REMOVE;
}
NimfMessage *message;
message = nimf_recv_message (socket);
nimf_im_result->reply = message;
gboolean retval;
if (G_UNLIKELY (message == NULL))
{
g_debug (G_STRLOC ": NULL message");
return G_SOURCE_CONTINUE;
}
NimfIM *im;
im = g_hash_table_lookup (nimf_im_table,
GUINT_TO_POINTER (message->header->icid));
switch (message->header->type)
{
/* signals */
case NIMF_MESSAGE_PREEDIT_START:
g_signal_emit (im, im_signals[PREEDIT_START], 0);
nimf_send_message (socket, im->priv->id, NIMF_MESSAGE_PREEDIT_START_REPLY,
NULL, 0, NULL);
break;
case NIMF_MESSAGE_PREEDIT_END:
g_signal_emit (im, im_signals[PREEDIT_END], 0);
nimf_send_message (socket, im->priv->id, NIMF_MESSAGE_PREEDIT_END_REPLY,
NULL, 0, NULL);
break;
case NIMF_MESSAGE_PREEDIT_CHANGED:
{
gint i;
g_free (im->priv->preedit_string);
im->priv->preedit_string = g_strndup (message->data,
message->header->data_len - 1 - sizeof (gint));
gint str_len = strlen (message->data);
gint n_attr = (message->header->data_len - str_len - 1 - sizeof (gint)) /
sizeof (NimfPreeditAttr);
nimf_preedit_attr_freev (im->priv->preedit_attrs);
im->priv->preedit_attrs = g_malloc0_n (n_attr + 1,
sizeof (NimfPreeditAttr *));
for (i = 0; i < n_attr; i++)
im->priv->preedit_attrs[i] = g_memdup (message->data + str_len + 1 + i * sizeof (NimfPreeditAttr),
sizeof (NimfPreeditAttr));
im->priv->preedit_attrs[n_attr] = NULL;
im->priv->cursor_pos = *(gint *) (message->data +
message->header->data_len - sizeof (gint));
g_signal_emit (im, im_signals[PREEDIT_CHANGED], 0);
nimf_send_message (socket, im->priv->id,
NIMF_MESSAGE_PREEDIT_CHANGED_REPLY, NULL, 0, NULL);
}
break;
case NIMF_MESSAGE_COMMIT:
nimf_message_ref (message);
g_signal_emit (im, im_signals[COMMIT], 0, (const gchar *) message->data);
nimf_message_unref (message);
nimf_send_message (socket, im->priv->id, NIMF_MESSAGE_COMMIT_REPLY,
NULL, 0, NULL);
break;
case NIMF_MESSAGE_RETRIEVE_SURROUNDING:
g_signal_emit (im, im_signals[RETRIEVE_SURROUNDING], 0, &retval);
nimf_send_message (socket, im->priv->id,
NIMF_MESSAGE_RETRIEVE_SURROUNDING_REPLY,
&retval, sizeof (gboolean), NULL);
break;
case NIMF_MESSAGE_DELETE_SURROUNDING:
nimf_message_ref (message);
g_signal_emit (im, im_signals[DELETE_SURROUNDING], 0,
((gint *) message->data)[0],
((gint *) message->data)[1], &retval);
nimf_message_unref (message);
nimf_send_message (socket, im->priv->id,
NIMF_MESSAGE_DELETE_SURROUNDING_REPLY,
&retval, sizeof (gboolean), NULL);
break;
case NIMF_MESSAGE_BEEP:
g_signal_emit (im, im_signals[BEEP], 0);
nimf_send_message (socket, im->priv->id, NIMF_MESSAGE_BEEP_REPLY,
NULL, 0, NULL);
break;
/* reply */
case NIMF_MESSAGE_CREATE_CONTEXT_REPLY:
case NIMF_MESSAGE_DESTROY_CONTEXT_REPLY:
case NIMF_MESSAGE_FILTER_EVENT_REPLY:
case NIMF_MESSAGE_RESET_REPLY:
case NIMF_MESSAGE_FOCUS_IN_REPLY:
case NIMF_MESSAGE_FOCUS_OUT_REPLY:
case NIMF_MESSAGE_SET_SURROUNDING_REPLY:
case NIMF_MESSAGE_SET_CURSOR_LOCATION_REPLY:
case NIMF_MESSAGE_SET_USE_PREEDIT_REPLY:
break;
default:
g_debug (G_STRLOC ": %s: Unknown message type: %d",
G_STRFUNC, message->header->type);
break;
}
return G_SOURCE_CONTINUE;
}
static void
nimf_im_connect (NimfIM *im)
{
GMutex mutex;
g_mutex_init (&mutex);
g_mutex_lock (&mutex);
g_debug (G_STRLOC ": %s", G_STRFUNC);
if (!nimf_im_is_connected ())
{
GSocketAddress *address;
GStatBuf info;
gint retry_limit = 4;
gint retry_count = 0;
GError *error = NULL;
if (nimf_im_socket)
{
if (nimf_im_socket_source)
{
g_source_destroy (nimf_im_socket_source);
g_source_unref (nimf_im_socket_source);
nimf_im_socket_source = NULL;
}
if (nimf_im_default_source)
{
g_source_destroy (nimf_im_default_source);
g_source_unref (nimf_im_default_source);
nimf_im_default_source = NULL;
}
g_object_unref (nimf_im_socket);
nimf_im_socket = NULL;
}
nimf_im_socket = g_socket_new (G_SOCKET_FAMILY_UNIX, G_SOCKET_TYPE_STREAM,
G_SOCKET_PROTOCOL_DEFAULT, NULL);
address = g_unix_socket_address_new_with_type (nimf_im_socket_path, -1,
G_UNIX_SOCKET_ADDRESS_PATH);
for (retry_count = 0; retry_count < retry_limit; retry_count++)
{
if (g_stat (nimf_im_socket_path, &info) == 0)
{
if (im->priv->uid == info.st_uid)
{
if (g_socket_connect (nimf_im_socket, address, NULL, &error))
{
break;
}
else
{
g_debug (G_STRLOC ": %s: %s", G_STRFUNC, error->message);
g_clear_error (&error);
}
}
else
{
g_debug (G_STRLOC ": %s: Can't authenticate", G_STRFUNC);
break;
}
}
g_debug ("Trying to execute nimf");
if (!g_spawn_command_line_sync ("nimf", NULL, NULL, NULL, &error))
{
g_debug ("Couldn't execute 'nimf': %s", error->message);
g_clear_error (&error);
break;
}
g_debug ("Waiting for 1 sec");
g_usleep (G_USEC_PER_SEC);
}
g_object_unref (address);
if (nimf_im_is_connected ())
{
/* when g_main_context_iteration(), iterate only socket */
nimf_im_socket_source = g_socket_create_source (nimf_im_socket, G_IO_IN, NULL);
g_source_set_can_recurse (nimf_im_socket_source, TRUE);
g_source_set_callback (nimf_im_socket_source,
(GSourceFunc) on_incoming_message, NULL, NULL);
g_source_attach (nimf_im_socket_source, nimf_im_context);
nimf_im_default_source = g_socket_create_source (nimf_im_socket, G_IO_IN, NULL);
g_source_set_can_recurse (nimf_im_default_source, TRUE);
g_source_set_callback (nimf_im_default_source,
(GSourceFunc) on_incoming_message, NULL, NULL);
g_source_attach (nimf_im_default_source, NULL);
}
else
{
g_debug (G_STRLOC ": %s: Couldn't connect to nimf server", G_STRFUNC);
}
}
g_mutex_unlock (&mutex);
}
static void
nimf_im_create_context (NimfIM *im)
{
g_debug (G_STRLOC ": %s", G_STRFUNC);
nimf_send_message (nimf_im_socket, im->priv->id,
NIMF_MESSAGE_CREATE_CONTEXT, NULL, 0, NULL);
nimf_result_iteration_until (nimf_im_result, nimf_im_context, im->priv->id,
NIMF_MESSAGE_CREATE_CONTEXT_REPLY);
im->priv->created = TRUE;
}
static void
on_changed (GFileMonitor *monitor,
GFile *file,
GFile *other_file,
GFileMonitorEvent event_type,
gpointer user_data)
{
g_debug (G_STRLOC ": %s", G_STRFUNC);
NimfIM *im = user_data;
if (event_type == G_FILE_MONITOR_EVENT_CREATED)
{
if (!nimf_im_is_connected ())
nimf_im_connect (im);
if (nimf_im_is_connected () && !im->priv->created)
nimf_im_create_context (im);
}
}
/**
* nimf_im_focus_out:
* @im: a #NimfIM
*
* Notifies the input method that the caller has lost focus.
*/
void
nimf_im_focus_out (NimfIM *im)
{
g_debug (G_STRLOC ": %s", G_STRFUNC);
if (!NIMF_IS_IM (im) || !nimf_im_is_connected ())
return;
nimf_send_message (nimf_im_socket, im->priv->id, NIMF_MESSAGE_FOCUS_OUT,
NULL, 0, NULL);
nimf_result_iteration_until (nimf_im_result, nimf_im_context, im->priv->id,
NIMF_MESSAGE_FOCUS_OUT_REPLY);
}
/**
* nimf_im_set_cursor_location:
* @im: a #NimfIM
* @area: new location
*
* Notifies the input method that a change in cursor position has been made. The
* location is the position of a window position in root window coordinates.
*/
void
nimf_im_set_cursor_location (NimfIM *im,
const NimfRectangle *area)
{
g_debug (G_STRLOC ": %s", G_STRFUNC);
if (!NIMF_IS_IM (im) || !nimf_im_is_connected ())
return;
nimf_send_message (nimf_im_socket, im->priv->id,
NIMF_MESSAGE_SET_CURSOR_LOCATION,
(gchar *) area, sizeof (NimfRectangle), NULL);
nimf_result_iteration_until (nimf_im_result, nimf_im_context, im->priv->id,
NIMF_MESSAGE_SET_CURSOR_LOCATION_REPLY);
}
/**
* nimf_im_set_use_preedit:
* @im: a #NimfIM
* @use_preedit: whether the input method should use an on-the-spot input style
*
* If @use_preedit is %FALSE (default is %TRUE), then the input method may use
* some other input styles, such as over-the-spot, off-the-spot or root-window.
*/
void
nimf_im_set_use_preedit (NimfIM *im,
gboolean use_preedit)
{
g_debug (G_STRLOC ": %s", G_STRFUNC);
if (!NIMF_IS_IM (im) || !nimf_im_is_connected ())
return;
nimf_send_message (nimf_im_socket, im->priv->id,
NIMF_MESSAGE_SET_USE_PREEDIT,
(gchar *) &use_preedit, sizeof (gboolean), NULL);
nimf_result_iteration_until (nimf_im_result, nimf_im_context, im->priv->id,
NIMF_MESSAGE_SET_USE_PREEDIT_REPLY);
}
/**
* nimf_im_set_surrounding:
* @im: a #NimfIM
* @text: surrounding text
* @len: the byte length of @text, or -1 if @text is nul-terminated.
* @cursor_index: the character index of the cursor within @text.
*
* Sets surrounding text to input method. This function is expected to be
* called in response to NimfIM::retrieve-surrounding which is emitted by
* nimf_engine_emit_retrieve_surrounding().
*/
void
nimf_im_set_surrounding (NimfIM *im,
const char *text,
gint len,
gint cursor_index)
{
g_debug (G_STRLOC ": %s", G_STRFUNC);
if (!NIMF_IS_IM (im) || !nimf_im_is_connected ())
return;
gchar *data = NULL;
gint str_len;
if (len == -1)
str_len = strlen (text);
else
str_len = len;
data = g_strndup (text, str_len);
data = g_realloc (data, str_len + 1 + 2 * sizeof (gint));
*(gint *) (data + str_len + 1) = len;
*(gint *) (data + str_len + 1 + sizeof (gint)) = cursor_index;
nimf_send_message (nimf_im_socket, im->priv->id,
NIMF_MESSAGE_SET_SURROUNDING,
data, str_len + 1 + 2 * sizeof (gint), g_free);
nimf_result_iteration_until (nimf_im_result, nimf_im_context, im->priv->id,
NIMF_MESSAGE_SET_SURROUNDING_REPLY);
}
/**
* nimf_im_focus_in:
* @im: a #NimfIM
*
* Notifies the input method that the caller has gained focus.
*/
void
nimf_im_focus_in (NimfIM *im)
{
g_debug (G_STRLOC ": %s", G_STRFUNC);
if (!NIMF_IS_IM (im) || !nimf_im_is_connected ())
return;
nimf_send_message (nimf_im_socket, im->priv->id,
NIMF_MESSAGE_FOCUS_IN, NULL, 0, NULL);
nimf_result_iteration_until (nimf_im_result, nimf_im_context, im->priv->id,
NIMF_MESSAGE_FOCUS_IN_REPLY);
}
/**
* nimf_im_get_preedit_string:
* @im: a #NimfIM
* @str: (out) (transfer full): location to store the retrieved
* string. The string retrieved must be freed with g_free().
* @attrs: (out) (transfer full): location to store the retrieved
* attribute array. When you are done with this array, you
* must free it with nimf_preedit_attr_freev().
* @cursor_pos: (out) (transfer full): location to store position of cursor (in
* characters) within the preedit string.
*
* Retrieve the current preedit string, an array of attributes to apply to the
* string and position of cursor within the preedit string from the input
* method.
*/
void
nimf_im_get_preedit_string (NimfIM *im,
gchar **str,
NimfPreeditAttr ***attrs,
gint *cursor_pos)
{
g_debug (G_STRLOC ":%s", G_STRFUNC);
if (!NIMF_IS_IM (im))
return;
if (str)
*str = g_strdup (im->priv->preedit_string);
if (attrs)
*attrs = nimf_preedit_attrs_copy (im->priv->preedit_attrs);
if (cursor_pos)
*cursor_pos = im->priv->cursor_pos;
}
/**
* nimf_im_reset:
* @im: a #NimfIM
*
* Reset the input method.
*/
void
nimf_im_reset (NimfIM *im)
{
g_debug (G_STRLOC ": %s", G_STRFUNC);
if (!NIMF_IS_IM (im) || !nimf_im_is_connected ())
return;
nimf_send_message (nimf_im_socket, im->priv->id,
NIMF_MESSAGE_RESET, NULL, 0, NULL);
nimf_result_iteration_until (nimf_im_result, nimf_im_context, im->priv->id,
NIMF_MESSAGE_RESET_REPLY);
}
/**
* nimf_im_filter_event:
* @im: a #NimfIM
* @event: a #NimfEvent
*
* Let the input method handle the @event.
*
* Returns: %TRUE if the input method handled the @event.
*/
gboolean
nimf_im_filter_event (NimfIM *im,
NimfEvent *event)
{
g_debug (G_STRLOC ":%s", G_STRFUNC);
if (!NIMF_IS_IM (im) || !nimf_im_is_connected ())
return FALSE;
nimf_send_message (nimf_im_socket, im->priv->id, NIMF_MESSAGE_FILTER_EVENT,
event, sizeof (NimfEvent), NULL);
nimf_result_iteration_until (nimf_im_result, nimf_im_context,
im->priv->id, NIMF_MESSAGE_FILTER_EVENT_REPLY);
if (nimf_im_result->reply &&
*(gboolean *) (nimf_im_result->reply->data))
return TRUE;
return FALSE;
}
/**
* nimf_im_new:
*
* Creates a new #NimfIM.
*
* Returns: a new #NimfIM
*/
NimfIM *
nimf_im_new ()
{
g_debug (G_STRLOC ": %s", G_STRFUNC);
return g_object_new (NIMF_TYPE_IM, NULL);
}
static void
nimf_im_init (NimfIM *im)
{
g_debug (G_STRLOC ": %s", G_STRFUNC);
im->priv = nimf_im_get_instance_private (im);
static guint16 next_id = 0;
guint16 id;
if ((im->priv->uid = get_login_uid ()) == (uid_t) -1)
im->priv->uid = getuid ();
if (!nimf_im_socket_path)
nimf_im_socket_path = nimf_get_socket_path ();
if (nimf_im_context == NULL)
nimf_im_context = g_main_context_new ();
else
g_main_context_ref (nimf_im_context);
if (nimf_im_result == NULL)
nimf_im_result = nimf_result_new ();
if (nimf_im_table == NULL)
nimf_im_table = g_hash_table_new_full (g_direct_hash, g_direct_equal,
NULL, NULL);
else
g_hash_table_ref (nimf_im_table);
if (im->priv->monitor == NULL)
{
GFile *file;
file = g_file_new_for_path (nimf_im_socket_path);
im->priv->monitor = g_file_monitor_file (file, G_FILE_MONITOR_NONE, NULL, NULL);
g_file_monitor_set_rate_limit (im->priv->monitor, G_PRIORITY_LOW);
g_signal_connect (im->priv->monitor, "changed", G_CALLBACK (on_changed), im);
g_object_unref (file);
}
do {
id = next_id++;
} while (id == 0 || g_hash_table_contains (nimf_im_table,
GUINT_TO_POINTER (id)));
im->priv->id = id;
g_hash_table_insert (nimf_im_table, GUINT_TO_POINTER (im->priv->id), im);
if (!nimf_im_is_connected ())
nimf_im_connect (im);
if (nimf_im_is_connected () && !im->priv->created)
nimf_im_create_context (im);
im->priv->preedit_string = g_strdup ("");
im->priv->preedit_attrs = g_malloc0_n (1, sizeof (NimfPreeditAttr *));
}
static void
nimf_im_finalize (GObject *object)
{
g_debug (G_STRLOC ": %s", G_STRFUNC);
NimfIM *im = NIMF_IM (object);
if (nimf_im_is_connected () && im->priv->created)
{
nimf_send_message (nimf_im_socket, im->priv->id,
NIMF_MESSAGE_DESTROY_CONTEXT, NULL, 0, NULL);
nimf_result_iteration_until (nimf_im_result, nimf_im_context, im->priv->id,
NIMF_MESSAGE_DESTROY_CONTEXT_REPLY);
}
g_hash_table_remove (nimf_im_table, GUINT_TO_POINTER (im->priv->id));
g_main_context_unref (nimf_im_context);
if (im->priv->monitor)
g_object_unref (im->priv->monitor);
if (g_hash_table_size (nimf_im_table) == 0)
{
g_hash_table_unref (nimf_im_table);
nimf_result_unref (nimf_im_result);
if (nimf_im_socket)
g_object_unref (nimf_im_socket);
if (nimf_im_socket_source)
g_source_destroy (nimf_im_socket_source);
if (nimf_im_socket_source)
g_source_unref (nimf_im_socket_source);
if (nimf_im_default_source)
g_source_destroy (nimf_im_default_source);
if (nimf_im_default_source)
g_source_unref (nimf_im_default_source);
g_free (nimf_im_socket_path);
nimf_im_socket = NULL;
nimf_im_socket_source = NULL;
nimf_im_default_source = NULL;
nimf_im_context = NULL;
nimf_im_result = NULL;
nimf_im_table = NULL;
nimf_im_socket_path = NULL;
}
g_free (im->priv->preedit_string);
nimf_preedit_attr_freev (im->priv->preedit_attrs);
G_OBJECT_CLASS (nimf_im_parent_class)->finalize (object);
}
static void
nimf_im_class_init (NimfIMClass *klass)
{
g_debug (G_STRLOC ": %s", G_STRFUNC);
GObjectClass *object_class = G_OBJECT_CLASS (klass);
object_class->finalize = nimf_im_finalize;
/**
* NimfIM::preedit-start:
* @im: a #NimfIM
*
* The #NimfIM::preedit-start signal is emitted when a new preediting
* sequence starts.
*/
im_signals[PREEDIT_START] =
g_signal_new (g_intern_static_string ("preedit-start"),
G_TYPE_FROM_CLASS (klass),
G_SIGNAL_RUN_LAST,
G_STRUCT_OFFSET (NimfIMClass, preedit_start),
NULL, NULL,
nimf_cclosure_marshal_VOID__VOID,
G_TYPE_NONE, 0);
/**
* NimfIM::preedit-end:
* @im: a #NimfIM
*
* The #NimfIM::preedit-end signal is emitted when a preediting sequence has
* been completed or canceled.
*/
im_signals[PREEDIT_END] =
g_signal_new (g_intern_static_string ("preedit-end"),
G_TYPE_FROM_CLASS (klass),
G_SIGNAL_RUN_LAST,
G_STRUCT_OFFSET (NimfIMClass, preedit_end),
NULL, NULL,
nimf_cclosure_marshal_VOID__VOID,
G_TYPE_NONE, 0);
/**
* NimfIM::preedit-changed:
* @im: a #NimfIM
*
* The #NimfIM::preedit-changed signal is emitted whenever the preedit
* sequence has been changed.
*/
im_signals[PREEDIT_CHANGED] =
g_signal_new (g_intern_static_string ("preedit-changed"),
G_TYPE_FROM_CLASS (klass),
G_SIGNAL_RUN_LAST,
G_STRUCT_OFFSET (NimfIMClass, preedit_changed),
NULL, NULL,
nimf_cclosure_marshal_VOID__VOID,
G_TYPE_NONE, 0);
/**
* NimfIM::commit:
* @im: a #NimfIM
* @text: text to commit
*
* The #NimfIM::commit signal is emitted when a complete input sequence has
* been entered by the user.
*/
im_signals[COMMIT] =
g_signal_new (g_intern_static_string ("commit"),
G_OBJECT_CLASS_TYPE (klass),
G_SIGNAL_RUN_LAST,
G_STRUCT_OFFSET (NimfIMClass, commit),
NULL, NULL,
nimf_cclosure_marshal_VOID__STRING,
G_TYPE_NONE, 1,
G_TYPE_STRING);
/**
* NimfIM::retrieve-surrounding:
* @im: a #NimfIM
*
* The #NimfIM::retrieve-surrounding signal is emitted when the input method
* requires the text surrounding the cursor. The callback should set the
* input method surrounding text by calling the nimf_im_set_surrounding()
* method.
*
* Returns: %TRUE if the signal was handled.
*/
im_signals[RETRIEVE_SURROUNDING] =
g_signal_new (g_intern_static_string ("retrieve-surrounding"),
G_TYPE_FROM_CLASS (klass),
G_SIGNAL_RUN_LAST,
G_STRUCT_OFFSET (NimfIMClass, retrieve_surrounding),
g_signal_accumulator_true_handled, NULL,
nimf_cclosure_marshal_BOOLEAN__VOID,
G_TYPE_BOOLEAN, 0);
/**
* NimfIM::delete-surrounding:
* @im: a #NimfIM
* @offset: the character offset from the cursor position of the text to be
* deleted. A negative value indicates a position before the cursor.
* @n_chars: the number of characters to be deleted
*
* The #NimfIM::delete-surrounding signal is emitted when the input method
* needs to delete all or part of the text surrounding the cursor.
*
* Returns: %TRUE if the signal was handled.
*/
im_signals[DELETE_SURROUNDING] =
g_signal_new (g_intern_static_string ("delete-surrounding"),
G_TYPE_FROM_CLASS (klass),
G_SIGNAL_RUN_LAST,
G_STRUCT_OFFSET (NimfIMClass, delete_surrounding),
g_signal_accumulator_true_handled, NULL,
nimf_cclosure_marshal_BOOLEAN__INT_INT,
G_TYPE_BOOLEAN, 2,
G_TYPE_INT,
G_TYPE_INT);
/**
* NimfIM::beep:
* @im: a #NimfIM
*
* The #NimfIM::beep signal is emitted when the input method needs to beep,
* if supported.
*/
im_signals[BEEP] =
g_signal_new (g_intern_static_string ("beep"),
G_TYPE_FROM_CLASS (klass),
G_SIGNAL_RUN_LAST,
G_STRUCT_OFFSET (NimfIMClass, beep),
NULL, NULL,
nimf_cclosure_marshal_VOID__VOID,
G_TYPE_NONE, 0);
}

View File

@@ -0,0 +1,91 @@
/* -*- Mode: C; indent-tabs-mode: nil; c-basic-offset: 2; tab-width: 2 -*- */
/*
* nimf-im.h
* This file is part of Nimf.
*
* Copyright (C) 2015-2019 Hodong Kim <cogniti@gmail.com>
*
* Nimf is free software: you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published
* by the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Nimf is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __NIMF_IM_H__
#define __NIMF_IM_H__
#if !defined (__NIMF_H_INSIDE__) && !defined (NIMF_COMPILATION)
#error "Only <nimf.h> can be included directly."
#endif
#include <glib-object.h>
#include "nimf-events.h"
#include "nimf-types.h"
G_BEGIN_DECLS
#define NIMF_TYPE_IM (nimf_im_get_type ())
#define NIMF_IM(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NIMF_TYPE_IM, NimfIM))
#define NIMF_IM_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), NIMF_TYPE_IM, NimfIMClass))
#define NIMF_IS_IM(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NIMF_TYPE_IM))
#define NIMF_IM_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), NIMF_TYPE_IM, NimfIMClass))
typedef struct _NimfIM NimfIM;
typedef struct _NimfIMClass NimfIMClass;
typedef struct _NimfIMPrivate NimfIMPrivate;
struct _NimfIM
{
GObject parent_instance;
NimfIMPrivate *priv;
};
struct _NimfIMClass
{
/*< private >*/
GObjectClass parent_class;
/*< public >*/
/* Signals */
void (*preedit_start) (NimfIM *im);
void (*preedit_end) (NimfIM *im);
void (*preedit_changed) (NimfIM *im);
void (*commit) (NimfIM *im, const gchar *text);
gboolean (*retrieve_surrounding) (NimfIM *im);
gboolean (*delete_surrounding) (NimfIM *im,
gint offset,
gint n_chars);
void (*beep) (NimfIM *im);
};
GType nimf_im_get_type (void) G_GNUC_CONST;
NimfIM *nimf_im_new (void);
void nimf_im_focus_in (NimfIM *im);
void nimf_im_focus_out (NimfIM *im);
void nimf_im_reset (NimfIM *im);
gboolean nimf_im_filter_event (NimfIM *im,
NimfEvent *event);
void nimf_im_get_preedit_string (NimfIM *im,
gchar **str,
NimfPreeditAttr ***attrs,
gint *cursor_pos);
void nimf_im_set_cursor_location (NimfIM *im,
const NimfRectangle *area);
void nimf_im_set_use_preedit (NimfIM *im,
gboolean use_preedit);
void nimf_im_set_surrounding (NimfIM *im,
const char *text,
gint len,
gint cursor_index);
G_END_DECLS
#endif /* __NIMF_IM_H__ */

View File

@@ -0,0 +1,418 @@
/* -*- Mode: C; indent-tabs-mode: nil; c-basic-offset: 2; tab-width: 2 -*- */
/*
* nimf-key-syms.h
* This file is part of Nimf.
*
* Copyright (C) 2015-2019 Hodong Kim <cogniti@gmail.com>
*
* Nimf is free software: you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published
* by the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Nimf is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __NIMF_KEY_SYMS_H__
#define __NIMF_KEY_SYMS_H__
#if !defined (__NIMF_H_INSIDE__) && !defined (NIMF_COMPILATION)
#error "Only <nimf.h> can be included directly."
#endif
#include <glib.h>
G_BEGIN_DECLS
/**
* SECTION:nimf-key-syms
* @title: Key symbols
* @section_id: nimf-key-syms
*/
/**
* NimfKeySym:
* @NIMF_KEY_space: space
* @NIMF_KEY_exclam: exclam
* @NIMF_KEY_quotedbl: quotedbl
* @NIMF_KEY_numbersign: numbersign
* @NIMF_KEY_dollar: dollar
* @NIMF_KEY_percent: percent
* @NIMF_KEY_ampersand: ampersand
* @NIMF_KEY_apostrophe: apostrophe
* @NIMF_KEY_parenleft: parenleft
* @NIMF_KEY_parenright: parenright
* @NIMF_KEY_asterisk: asterisk
* @NIMF_KEY_plus: plus
* @NIMF_KEY_comma: comma
* @NIMF_KEY_minus: minus
* @NIMF_KEY_period: period
* @NIMF_KEY_slash: slash
* @NIMF_KEY_0: 0
* @NIMF_KEY_1: 1
* @NIMF_KEY_2: 2
* @NIMF_KEY_3: 3
* @NIMF_KEY_4: 4
* @NIMF_KEY_5: 5
* @NIMF_KEY_6: 6
* @NIMF_KEY_7: 7
* @NIMF_KEY_8: 8
* @NIMF_KEY_9: 9
* @NIMF_KEY_colon: colon
* @NIMF_KEY_semicolon: semicolon
* @NIMF_KEY_less: less
* @NIMF_KEY_equal: equal
* @NIMF_KEY_greater: greater
* @NIMF_KEY_question: question
* @NIMF_KEY_at: at
* @NIMF_KEY_A: A
* @NIMF_KEY_B: B
* @NIMF_KEY_C: C
* @NIMF_KEY_D: D
* @NIMF_KEY_E: E
* @NIMF_KEY_F: F
* @NIMF_KEY_G: G
* @NIMF_KEY_H: H
* @NIMF_KEY_I: I
* @NIMF_KEY_J: J
* @NIMF_KEY_K: K
* @NIMF_KEY_L: L
* @NIMF_KEY_M: M
* @NIMF_KEY_N: N
* @NIMF_KEY_O: O
* @NIMF_KEY_P: P
* @NIMF_KEY_Q: Q
* @NIMF_KEY_R: R
* @NIMF_KEY_S: S
* @NIMF_KEY_T: T
* @NIMF_KEY_U: U
* @NIMF_KEY_V: V
* @NIMF_KEY_W: W
* @NIMF_KEY_X: X
* @NIMF_KEY_Y: Y
* @NIMF_KEY_Z: Z
* @NIMF_KEY_bracketleft: bracketleft
* @NIMF_KEY_backslash: backslash
* @NIMF_KEY_bracketright: bracketright
* @NIMF_KEY_asciicircum: asciicircum
* @NIMF_KEY_underscore: underscore
* @NIMF_KEY_grave: grave
* @NIMF_KEY_a: a
* @NIMF_KEY_b: b
* @NIMF_KEY_c: c
* @NIMF_KEY_d: d
* @NIMF_KEY_e: e
* @NIMF_KEY_f: f
* @NIMF_KEY_g: g
* @NIMF_KEY_h: h
* @NIMF_KEY_i: i
* @NIMF_KEY_j: j
* @NIMF_KEY_k: k
* @NIMF_KEY_l: l
* @NIMF_KEY_m: m
* @NIMF_KEY_n: n
* @NIMF_KEY_o: o
* @NIMF_KEY_p: p
* @NIMF_KEY_q: q
* @NIMF_KEY_r: r
* @NIMF_KEY_s: s
* @NIMF_KEY_t: t
* @NIMF_KEY_u: u
* @NIMF_KEY_v: v
* @NIMF_KEY_w: w
* @NIMF_KEY_x: x
* @NIMF_KEY_y: y
* @NIMF_KEY_z: z
* @NIMF_KEY_braceleft: braceleft
* @NIMF_KEY_bar: bar
* @NIMF_KEY_braceright: braceright
* @NIMF_KEY_asciitilde: asciitilde
* @NIMF_KEY_ISO_Level3_Shift: ISO_Level3_Shift
* @NIMF_KEY_ISO_Left_Tab: ISO_Left_Tab
* @NIMF_KEY_BackSpace: BackSpace
* @NIMF_KEY_Tab: Tab
* @NIMF_KEY_Return: Return
* @NIMF_KEY_Pause: Pause
* @NIMF_KEY_Scroll_Lock: Scroll_Lock
* @NIMF_KEY_Sys_Req: Sys_Req
* @NIMF_KEY_Escape: Escape
* @NIMF_KEY_Multi_key: Multi_key
* @NIMF_KEY_Kanji: Kanji
* @NIMF_KEY_Kana_Shift: Kana_Shift
* @NIMF_KEY_Hangul: Hangul
* @NIMF_KEY_Hangul_Hanja: Hangul_Hanja
* @NIMF_KEY_Home: Home
* @NIMF_KEY_Left: Left
* @NIMF_KEY_Up: Up
* @NIMF_KEY_Right: Right
* @NIMF_KEY_Down: Down
* @NIMF_KEY_Page_Up: Page_Up
* @NIMF_KEY_Page_Down: Page_Down
* @NIMF_KEY_End: End
* @NIMF_KEY_Print: Print
* @NIMF_KEY_Execute: Execut
* @NIMF_KEY_Insert: Insert
* @NIMF_KEY_Menu: Menu
* @NIMF_KEY_Break: Break
* @NIMF_KEY_KP_Enter: KP_Enter
* @NIMF_KEY_KP_Left: KP_Left
* @NIMF_KEY_KP_Up: KP_Up
* @NIMF_KEY_KP_Right: KP_Right
* @NIMF_KEY_KP_Down: KP_Down
* @NIMF_KEY_KP_Page_Up: KP_Page_Up
* @NIMF_KEY_KP_Page_Down: KP_Page_Down
* @NIMF_KEY_KP_Delete: KP_Delete
* @NIMF_KEY_KP_Multiply: KP_Multiply
* @NIMF_KEY_KP_Add: KP_Add
* @NIMF_KEY_KP_Subtract: KP_Subtract
* @NIMF_KEY_KP_Decimal: KP_Decimal
* @NIMF_KEY_KP_Divide: KP_Divide
* @NIMF_KEY_KP_0: KP_0
* @NIMF_KEY_KP_1: KP_1
* @NIMF_KEY_KP_2: KP_2
* @NIMF_KEY_KP_3: KP_3
* @NIMF_KEY_KP_4: KP_4
* @NIMF_KEY_KP_5: KP_5
* @NIMF_KEY_KP_6: KP_6
* @NIMF_KEY_KP_7: KP_7
* @NIMF_KEY_KP_8: KP_8
* @NIMF_KEY_KP_9: KP_9
* @NIMF_KEY_F1: F1
* @NIMF_KEY_F2: F2
* @NIMF_KEY_F3: F3
* @NIMF_KEY_F4: F4
* @NIMF_KEY_F5: F5
* @NIMF_KEY_F6: F6
* @NIMF_KEY_F7: F7
* @NIMF_KEY_F8: F8
* @NIMF_KEY_F9: F9
* @NIMF_KEY_F10: F10
* @NIMF_KEY_F11: F11
* @NIMF_KEY_F12: F12
* @NIMF_KEY_Shift_L: Shift_L
* @NIMF_KEY_Shift_R: Shift_R
* @NIMF_KEY_Control_L: Control_L
* @NIMF_KEY_Control_R: Control_R
* @NIMF_KEY_Caps_Lock: Caps_Lock
* @NIMF_KEY_Shift_Lock: Shift_Lock
* @NIMF_KEY_Meta_L: Meta_L
* @NIMF_KEY_Meta_R: Meta_R
* @NIMF_KEY_Alt_L: Alt_L
* @NIMF_KEY_Alt_R: Alt_R
* @NIMF_KEY_Super_L: Super_L
* @NIMF_KEY_Super_R: Super_R
* @NIMF_KEY_Delete: Delete
* @NIMF_KEY_VoidSymbol: VoidSymbol
* @NIMF_KEY_WakeUp: WakeUp
* @NIMF_KEY_WebCam: WebCam
* @NIMF_KEY_WLAN: WLAN
*/
typedef enum
{
NIMF_KEY_space = 0x020, /*< nick=space >*/
NIMF_KEY_exclam = 0x021, /*< nick=exclam >*/
NIMF_KEY_quotedbl = 0x022, /*< nick=quotedbl >*/
NIMF_KEY_numbersign = 0x023, /*< nick=numbersign >*/
NIMF_KEY_dollar = 0x024, /*< nick=dollar >*/
NIMF_KEY_percent = 0x025, /*< nick=percent >*/
NIMF_KEY_ampersand = 0x026, /*< nick=ampersand >*/
NIMF_KEY_apostrophe = 0x027, /*< nick=apostrophe >*/
NIMF_KEY_parenleft = 0x028, /*< nick=parenleft >*/
NIMF_KEY_parenright = 0x029, /*< nick=parenright >*/
NIMF_KEY_asterisk = 0x02a, /*< nick=asterisk >*/
NIMF_KEY_plus = 0x02b, /*< nick=plus >*/
NIMF_KEY_comma = 0x02c, /*< nick=comma >*/
NIMF_KEY_minus = 0x02d, /*< nick=minus >*/
NIMF_KEY_period = 0x02e, /*< nick=period >*/
NIMF_KEY_slash = 0x02f, /*< nick=slash >*/
NIMF_KEY_0 = 0x030, /*< nick=0 >*/
NIMF_KEY_1 = 0x031, /*< nick=1 >*/
NIMF_KEY_2 = 0x032, /*< nick=2 >*/
NIMF_KEY_3 = 0x033, /*< nick=3 >*/
NIMF_KEY_4 = 0x034, /*< nick=4 >*/
NIMF_KEY_5 = 0x035, /*< nick=5 >*/
NIMF_KEY_6 = 0x036, /*< nick=6 >*/
NIMF_KEY_7 = 0x037, /*< nick=7 >*/
NIMF_KEY_8 = 0x038, /*< nick=8 >*/
NIMF_KEY_9 = 0x039, /*< nick=9 >*/
NIMF_KEY_colon = 0x03a, /*< nick=colon >*/
NIMF_KEY_semicolon = 0x03b, /*< nick=semicolon >*/
NIMF_KEY_less = 0x03c, /*< nick=less >*/
NIMF_KEY_equal = 0x03d, /*< nick=equal >*/
NIMF_KEY_greater = 0x03e, /*< nick=greater >*/
NIMF_KEY_question = 0x03f, /*< nick=question >*/
NIMF_KEY_at = 0x040, /*< nick=at >*/
NIMF_KEY_A = 0x041, /*< nick=A >*/
NIMF_KEY_B = 0x042, /*< nick=B >*/
NIMF_KEY_C = 0x043, /*< nick=C >*/
NIMF_KEY_D = 0x044, /*< nick=D >*/
NIMF_KEY_E = 0x045, /*< nick=E >*/
NIMF_KEY_F = 0x046, /*< nick=F >*/
NIMF_KEY_G = 0x047, /*< nick=G >*/
NIMF_KEY_H = 0x048, /*< nick=H >*/
NIMF_KEY_I = 0x049, /*< nick=I >*/
NIMF_KEY_J = 0x04a, /*< nick=J >*/
NIMF_KEY_K = 0x04b, /*< nick=K >*/
NIMF_KEY_L = 0x04c, /*< nick=L >*/
NIMF_KEY_M = 0x04d, /*< nick=M >*/
NIMF_KEY_N = 0x04e, /*< nick=N >*/
NIMF_KEY_O = 0x04f, /*< nick=O >*/
NIMF_KEY_P = 0x050, /*< nick=P >*/
NIMF_KEY_Q = 0x051, /*< nick=Q >*/
NIMF_KEY_R = 0x052, /*< nick=R >*/
NIMF_KEY_S = 0x053, /*< nick=S >*/
NIMF_KEY_T = 0x054, /*< nick=T >*/
NIMF_KEY_U = 0x055, /*< nick=U >*/
NIMF_KEY_V = 0x056, /*< nick=V >*/
NIMF_KEY_W = 0x057, /*< nick=W >*/
NIMF_KEY_X = 0x058, /*< nick=X >*/
NIMF_KEY_Y = 0x059, /*< nick=Y >*/
NIMF_KEY_Z = 0x05a, /*< nick=Z >*/
NIMF_KEY_bracketleft = 0x05b, /*< nick=bracketleft >*/
NIMF_KEY_backslash = 0x05c, /*< nick=backslash >*/
NIMF_KEY_bracketright = 0x05d, /*< nick=bracketright >*/
NIMF_KEY_asciicircum = 0x05e, /*< nick=asciicircum >*/
NIMF_KEY_underscore = 0x05f, /*< nick=underscore >*/
NIMF_KEY_grave = 0x060, /*< nick=grave >*/
NIMF_KEY_a = 0x061, /*< nick=a >*/
NIMF_KEY_b = 0x062, /*< nick=b >*/
NIMF_KEY_c = 0x063, /*< nick=c >*/
NIMF_KEY_d = 0x064, /*< nick=d >*/
NIMF_KEY_e = 0x065, /*< nick=e >*/
NIMF_KEY_f = 0x066, /*< nick=f >*/
NIMF_KEY_g = 0x067, /*< nick=g >*/
NIMF_KEY_h = 0x068, /*< nick=h >*/
NIMF_KEY_i = 0x069, /*< nick=i >*/
NIMF_KEY_j = 0x06a, /*< nick=j >*/
NIMF_KEY_k = 0x06b, /*< nick=k >*/
NIMF_KEY_l = 0x06c, /*< nick=l >*/
NIMF_KEY_m = 0x06d, /*< nick=m >*/
NIMF_KEY_n = 0x06e, /*< nick=n >*/
NIMF_KEY_o = 0x06f, /*< nick=o >*/
NIMF_KEY_p = 0x070, /*< nick=p >*/
NIMF_KEY_q = 0x071, /*< nick=q >*/
NIMF_KEY_r = 0x072, /*< nick=r >*/
NIMF_KEY_s = 0x073, /*< nick=s >*/
NIMF_KEY_t = 0x074, /*< nick=t >*/
NIMF_KEY_u = 0x075, /*< nick=u >*/
NIMF_KEY_v = 0x076, /*< nick=v >*/
NIMF_KEY_w = 0x077, /*< nick=w >*/
NIMF_KEY_x = 0x078, /*< nick=x >*/
NIMF_KEY_y = 0x079, /*< nick=y >*/
NIMF_KEY_z = 0x07a, /*< nick=z >*/
NIMF_KEY_braceleft = 0x07b, /*< nick=braceleft >*/
NIMF_KEY_bar = 0x07c, /*< nick=bar >*/
NIMF_KEY_braceright = 0x07d, /*< nick=braceright >*/
NIMF_KEY_asciitilde = 0x07e, /*< nick=asciitilde >*/
NIMF_KEY_ISO_Level3_Shift = 0xfe03, /*< nick=ISO_Level3_Shift >*/
NIMF_KEY_ISO_Left_Tab = 0xfe20, /*< nick=ISO_Left_Tab >*/
NIMF_KEY_BackSpace = 0xff08, /*< nick=BackSpace >*/
NIMF_KEY_Tab = 0xff09, /*< nick=Tab >*/
NIMF_KEY_Return = 0xff0d, /*< nick=Return >*/
NIMF_KEY_Pause = 0xff13, /*< nick=Pause >*/
NIMF_KEY_Scroll_Lock = 0xff14, /*< nick=Scroll_Lock >*/
NIMF_KEY_Sys_Req = 0xff15, /*< nick=Sys_Req >*/
NIMF_KEY_Escape = 0xff1b, /*< nick=Escape >*/
NIMF_KEY_Multi_key = 0xff20, /*< nick=Multi_key >*/
NIMF_KEY_Kanji = 0xff21, /*< nick=Kanji >*/
NIMF_KEY_Kana_Shift = 0xff2e, /*< nick=Kana_Shift >*/
NIMF_KEY_Hangul = 0xff31, /*< nick=Hangul >*/
NIMF_KEY_Hangul_Hanja = 0xff34, /*< nick=Hangul_Hanja >*/
NIMF_KEY_Home = 0xff50, /*< nick=Home >*/
NIMF_KEY_Left = 0xff51, /*< nick=Left >*/
NIMF_KEY_Up = 0xff52, /*< nick=Up >*/
NIMF_KEY_Right = 0xff53, /*< nick=Right >*/
NIMF_KEY_Down = 0xff54, /*< nick=Down >*/
NIMF_KEY_Page_Up = 0xff55, /*< nick=Page_Up >*/
NIMF_KEY_Page_Down = 0xff56, /*< nick=Page_Down >*/
NIMF_KEY_End = 0xff57, /*< nick=End >*/
NIMF_KEY_Print = 0xff61, /*< nick=Print >*/
NIMF_KEY_Execute = 0xff62, /*< nick=Execut >*/
NIMF_KEY_Insert = 0xff63, /*< nick=Insert >*/
NIMF_KEY_Menu = 0xff67, /*< nick=Menu >*/
NIMF_KEY_Break = 0xff6b, /*< nick=Break >*/
NIMF_KEY_KP_Enter = 0xff8d, /*< nick=KP_Enter >*/
NIMF_KEY_KP_Left = 0xff96, /*< nick=KP_Left >*/
NIMF_KEY_KP_Up = 0xff97, /*< nick=KP_Up >*/
NIMF_KEY_KP_Right = 0xff98, /*< nick=KP_Right >*/
NIMF_KEY_KP_Down = 0xff99, /*< nick=KP_Down >*/
NIMF_KEY_KP_Page_Up = 0xff9a, /*< nick=KP_Page_Up >*/
NIMF_KEY_KP_Page_Down = 0xff9b, /*< nick=KP_Page_Down >*/
NIMF_KEY_KP_Delete = 0xff9f, /*< nick=KP_Delete >*/
NIMF_KEY_KP_Multiply = 0xffaa, /*< nick=KP_Multiply >*/
NIMF_KEY_KP_Add = 0xffab, /*< nick=KP_Add >*/
NIMF_KEY_KP_Subtract = 0xffad, /*< nick=KP_Subtract >*/
NIMF_KEY_KP_Decimal = 0xffae, /*< nick=KP_Decimal >*/
NIMF_KEY_KP_Divide = 0xffaf, /*< nick=KP_Divide >*/
NIMF_KEY_KP_0 = 0xffb0, /*< nick=KP_0 >*/
NIMF_KEY_KP_1 = 0xffb1, /*< nick=KP_1 >*/
NIMF_KEY_KP_2 = 0xffb2, /*< nick=KP_2 >*/
NIMF_KEY_KP_3 = 0xffb3, /*< nick=KP_3 >*/
NIMF_KEY_KP_4 = 0xffb4, /*< nick=KP_4 >*/
NIMF_KEY_KP_5 = 0xffb5, /*< nick=KP_5 >*/
NIMF_KEY_KP_6 = 0xffb6, /*< nick=KP_6 >*/
NIMF_KEY_KP_7 = 0xffb7, /*< nick=KP_7 >*/
NIMF_KEY_KP_8 = 0xffb8, /*< nick=KP_8 >*/
NIMF_KEY_KP_9 = 0xffb9, /*< nick=KP_9 >*/
NIMF_KEY_F1 = 0xffbe, /*< nick=F1 >*/
NIMF_KEY_F2 = 0xffbf, /*< nick=F2 >*/
NIMF_KEY_F3 = 0xffc0, /*< nick=F3 >*/
NIMF_KEY_F4 = 0xffc1, /*< nick=F4 >*/
NIMF_KEY_F5 = 0xffc2, /*< nick=F5 >*/
NIMF_KEY_F6 = 0xffc3, /*< nick=F6 >*/
NIMF_KEY_F7 = 0xffc4, /*< nick=F7 >*/
NIMF_KEY_F8 = 0xffc5, /*< nick=F8 >*/
NIMF_KEY_F9 = 0xffc6, /*< nick=F9 >*/
NIMF_KEY_F10 = 0xffc7, /*< nick=F10 >*/
NIMF_KEY_F11 = 0xffc8, /*< nick=F11 >*/
NIMF_KEY_F12 = 0xffc9, /*< nick=F12 >*/
NIMF_KEY_Shift_L = 0xffe1, /*< nick=Shift_L >*/
NIMF_KEY_Shift_R = 0xffe2, /*< nick=Shift_R >*/
NIMF_KEY_Control_L = 0xffe3, /*< nick=Control_L >*/
NIMF_KEY_Control_R = 0xffe4, /*< nick=Control_R >*/
NIMF_KEY_Caps_Lock = 0xffe5, /*< nick=Caps_Lock >*/
NIMF_KEY_Shift_Lock = 0xffe6, /*< nick=Shift_Lock >*/
NIMF_KEY_Meta_L = 0xffe7, /*< nick=Meta_L >*/
NIMF_KEY_Meta_R = 0xffe8, /*< nick=Meta_R >*/
NIMF_KEY_Alt_L = 0xffe9, /*< nick=Alt_L >*/
NIMF_KEY_Alt_R = 0xffea, /*< nick=Alt_R >*/
NIMF_KEY_Super_L = 0xffeb, /*< nick=Super_L >*/
NIMF_KEY_Super_R = 0xffec, /*< nick=Super_R >*/
NIMF_KEY_Delete = 0xffff, /*< nick=Delete >*/
NIMF_KEY_VoidSymbol = 0xffffff, /*< nick=VoidSymbol >*/
NIMF_KEY_WakeUp = 0x1008ff2b, /*< nick=WakeUp >*/
NIMF_KEY_WebCam = 0x1008ff8f, /*< nick=WebCam >*/
NIMF_KEY_WLAN = 0x1008ff95 /*< nick=WLAN >*/
} NimfKeySym;
G_END_DECLS
#endif /* __NIMF_KEY_SYMS_H__ */

View File

@@ -0,0 +1,5 @@
VOID:VOID
VOID:STRING
VOID:STRING,STRING
BOOLEAN:VOID
BOOLEAN:INT,INT

View File

@@ -0,0 +1,41 @@
/*** BEGIN file-header ***/
/*
* This file is part of Nimf.
*
* Nimf is free software: you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published
* by the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Nimf is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __NIMF_MESSAGE_ENUM_TYPES_H__
#define __NIMF_MESSAGE_ENUM_TYPES_H__
#include <glib-object.h>
G_BEGIN_DECLS
/*** END file-header ***/
/*** BEGIN file-production ***/
/* enumerations from "@filename@" */
/*** END file-production ***/
/*** BEGIN value-header ***/
GType @enum_name@_get_type (void) G_GNUC_CONST;
#define @ENUMPREFIX@_TYPE_@ENUMSHORT@ (@enum_name@_get_type ())
/*** END value-header ***/
/*** BEGIN file-tail ***/
G_END_DECLS
#endif /* __NIMF_MESSAGE_ENUM_TYPES_H__ */
/*** END file-tail ***/

View File

@@ -0,0 +1,54 @@
/*** BEGIN file-header ***/
/*
* This file is part of Nimf.
*
* Nimf is free software: you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published
* by the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Nimf is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; If not, see <http://www.gnu.org/licenses/>.
*/
#include "nimf-message-enum-types-private.h"
#include "nimf-message-private.h"
/*** END file-header ***/
/*** BEGIN file-production ***/
/* enumerations from "@filename@" */
/*** END file-production ***/
/*** BEGIN value-header ***/
GType
@enum_name@_get_type (void)
{
static volatile gsize g_define_type_id__volatile = 0;
if (g_once_init_enter (&g_define_type_id__volatile))
{
static const G@Type@Value values[] = {
/*** END value-header ***/
/*** BEGIN value-production ***/
{ @VALUENAME@, "@VALUENAME@", "@valuenick@" },
/*** END value-production ***/
/*** BEGIN value-tail ***/
{ 0, NULL, NULL }
};
GType g_define_type_id =
g_@type@_register_static (g_intern_static_string ("@EnumName@"), values);
g_once_init_leave (&g_define_type_id__volatile, g_define_type_id);
}
return g_define_type_id__volatile;
}
/*** END value-tail ***/

View File

@@ -0,0 +1,136 @@
/* -*- Mode: C; indent-tabs-mode: nil; c-basic-offset: 2; tab-width: 2 -*- */
/*
* nimf-message-private.h
* This file is part of Nimf.
*
* Copyright (C) 2015-2019 Hodong Kim <cogniti@gmail.com>
*
* Nimf is free software: you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published
* by the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Nimf is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __NIMF_MESSAGE_H__
#define __NIMF_MESSAGE_H__
#include <glib-object.h>
#include "nimf-events.h"
#include <gio/gio.h>
G_BEGIN_DECLS
typedef struct _NimfMessage NimfMessage;
typedef struct _NimfMessageHeader NimfMessageHeader;
typedef enum
{
NIMF_MESSAGE_NONE = 0,
/* im methods */
NIMF_MESSAGE_CREATE_CONTEXT,
NIMF_MESSAGE_CREATE_CONTEXT_REPLY,
NIMF_MESSAGE_DESTROY_CONTEXT,
NIMF_MESSAGE_DESTROY_CONTEXT_REPLY,
NIMF_MESSAGE_FILTER_EVENT,
NIMF_MESSAGE_FILTER_EVENT_REPLY,
NIMF_MESSAGE_RESET,
NIMF_MESSAGE_RESET_REPLY,
NIMF_MESSAGE_FOCUS_IN,
NIMF_MESSAGE_FOCUS_IN_REPLY,
NIMF_MESSAGE_FOCUS_OUT,
NIMF_MESSAGE_FOCUS_OUT_REPLY,
NIMF_MESSAGE_SET_SURROUNDING,
NIMF_MESSAGE_SET_SURROUNDING_REPLY,
NIMF_MESSAGE_SET_CURSOR_LOCATION,
NIMF_MESSAGE_SET_CURSOR_LOCATION_REPLY,
NIMF_MESSAGE_SET_USE_PREEDIT,
NIMF_MESSAGE_SET_USE_PREEDIT_REPLY,
/* context signals */
NIMF_MESSAGE_PREEDIT_START,
NIMF_MESSAGE_PREEDIT_START_REPLY,
NIMF_MESSAGE_PREEDIT_END,
NIMF_MESSAGE_PREEDIT_END_REPLY,
NIMF_MESSAGE_PREEDIT_CHANGED,
NIMF_MESSAGE_PREEDIT_CHANGED_REPLY,
NIMF_MESSAGE_COMMIT,
NIMF_MESSAGE_COMMIT_REPLY,
NIMF_MESSAGE_RETRIEVE_SURROUNDING,
NIMF_MESSAGE_RETRIEVE_SURROUNDING_REPLY,
NIMF_MESSAGE_DELETE_SURROUNDING,
NIMF_MESSAGE_DELETE_SURROUNDING_REPLY,
/* misc */
NIMF_MESSAGE_BEEP,
NIMF_MESSAGE_BEEP_REPLY,
} NimfMessageType;
struct _NimfMessageHeader
{
guint16 icid;
NimfMessageType type;
guint16 data_len;
};
struct _NimfMessage
{
NimfMessageHeader *header;
gchar *data;
GDestroyNotify data_destroy_func;
gint ref_count;
};
typedef struct _NimfResult NimfResult;
struct _NimfResult
{
gboolean is_dispatched;
NimfMessage *reply;
gint ref_count;
};
NimfMessage *nimf_message_new (void);
NimfMessage *nimf_message_new_full (NimfMessageType type,
guint16 im_id,
gpointer data,
guint16 data_len,
GDestroyNotify data_destroy_func);
NimfMessage *nimf_message_ref (NimfMessage *message);
void nimf_message_unref (NimfMessage *message);
const NimfMessageHeader *
nimf_message_get_header (NimfMessage *message);
guint16 nimf_message_get_header_size (void);
void nimf_message_set_body (NimfMessage *message,
gchar *data,
guint16 data_len,
GDestroyNotify data_destroy_func);
const gchar *nimf_message_get_body (NimfMessage *message);
guint16 nimf_message_get_body_size (NimfMessage *message);
const gchar *nimf_message_get_name (NimfMessage *message);
const gchar *nimf_message_get_name_by_type (NimfMessageType type);
NimfResult *nimf_result_new (void);
NimfResult *nimf_result_ref (NimfResult *result);
void nimf_result_unref (NimfResult *result);
void nimf_result_iteration_until (NimfResult *result,
GMainContext *main_context,
guint16 icid,
NimfMessageType type);
void nimf_send_message (GSocket *socket,
guint16 im_id,
NimfMessageType type,
gpointer data,
guint16 data_len,
GDestroyNotify data_destroy_func);
NimfMessage *nimf_recv_message (GSocket *socket);
G_END_DECLS
#endif /* __NIMF_MESSAGE_H__ */

View File

@@ -0,0 +1,352 @@
/* -*- Mode: C; indent-tabs-mode: nil; c-basic-offset: 2; tab-width: 2 -*- */
/*
* nimf-message.c
* This file is part of Nimf.
*
* Copyright (C) 2015-2019 Hodong Kim <cogniti@gmail.com>
*
* Nimf is free software: you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published
* by the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Nimf is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; If not, see <http://www.gnu.org/licenses/>.
*/
#include "nimf-message-private.h"
#include "nimf-types.h"
#include "nimf-message-enum-types-private.h"
#include <string.h>
NimfMessage *
nimf_message_new ()
{
g_debug (G_STRLOC ": %s", G_STRFUNC);
return nimf_message_new_full (NIMF_MESSAGE_NONE, 0, NULL, 0, NULL);
}
NimfMessage *
nimf_message_new_full (NimfMessageType type,
guint16 icid,
gpointer data,
guint16 data_len,
GDestroyNotify data_destroy_func)
{
g_debug (G_STRLOC ": %s", G_STRFUNC);
NimfMessage *message;
message = g_slice_new0 (NimfMessage);
message->header = g_slice_new0 (NimfMessageHeader);
message->header->icid = icid;
message->header->type = type;
message->header->data_len = data_len;
message->data = data;
message->data_destroy_func = data_destroy_func;
message->ref_count = 1;
return message;
}
NimfMessage *
nimf_message_ref (NimfMessage *message)
{
g_debug (G_STRLOC ": %s", G_STRFUNC);
g_return_val_if_fail (message != NULL, NULL);
g_atomic_int_inc (&message->ref_count);
return message;
}
void
nimf_message_unref (NimfMessage *message)
{
g_debug (G_STRLOC ": %s", G_STRFUNC);
if (G_UNLIKELY (message == NULL))
return;
if (g_atomic_int_dec_and_test (&message->ref_count))
{
g_slice_free (NimfMessageHeader, message->header);
if (message->data_destroy_func)
message->data_destroy_func (message->data);
g_slice_free (NimfMessage, message);
}
}
const NimfMessageHeader *
nimf_message_get_header (NimfMessage *message)
{
g_debug (G_STRLOC ": %s", G_STRFUNC);
return message->header;
}
guint16
nimf_message_get_header_size ()
{
g_debug (G_STRLOC ": %s", G_STRFUNC);
return sizeof (NimfMessageHeader);
}
void
nimf_message_set_body (NimfMessage *message,
gchar *data,
guint16 data_len,
GDestroyNotify data_destroy_func)
{
g_debug (G_STRLOC ": %s", G_STRFUNC);
message->data = data;
message->header->data_len = data_len;
message->data_destroy_func = data_destroy_func;
}
const gchar *
nimf_message_get_body (NimfMessage *message)
{
g_debug (G_STRLOC ": %s", G_STRFUNC);
return message->data;
}
guint16
nimf_message_get_body_size (NimfMessage *message)
{
g_debug (G_STRLOC ": %s", G_STRFUNC);
return message->header->data_len;
}
const gchar *nimf_message_get_name (NimfMessage *message)
{
g_debug (G_STRLOC ": %s", G_STRFUNC);
GEnumClass *enum_class = (GEnumClass *) g_type_class_ref (NIMF_TYPE_MESSAGE_TYPE);
GEnumValue *enum_value = g_enum_get_value (enum_class, message->header->type);
g_type_class_unref (enum_class);
return enum_value ? enum_value->value_name : NULL;
}
const gchar *nimf_message_get_name_by_type (NimfMessageType type)
{
g_debug (G_STRLOC ": %s", G_STRFUNC);
GEnumClass *enum_class = (GEnumClass *) g_type_class_ref (NIMF_TYPE_MESSAGE_TYPE);
GEnumValue *enum_value = g_enum_get_value (enum_class, type);
g_type_class_unref (enum_class);
return enum_value ? enum_value->value_name : NULL;
}
NimfResult *
nimf_result_new ()
{
g_debug (G_STRLOC ": %s", G_STRFUNC);
NimfResult *result;
result = g_slice_new0 (NimfResult);
result->ref_count = 1;
return result;
}
NimfResult *
nimf_result_ref (NimfResult *result)
{
g_debug (G_STRLOC ": %s", G_STRFUNC);
g_return_val_if_fail (result != NULL, NULL);
g_atomic_int_inc (&result->ref_count);
return result;
}
void
nimf_result_unref (NimfResult *result)
{
g_debug (G_STRLOC ": %s", G_STRFUNC);
if (G_UNLIKELY (result == NULL))
return;
if (g_atomic_int_dec_and_test (&result->ref_count))
{
if (result->reply)
g_slice_free (NimfMessage, result->reply);
g_slice_free (NimfResult, result);
}
}
void
nimf_result_iteration_until (NimfResult *result,
GMainContext *main_context,
guint16 icid,
NimfMessageType type)
{
g_debug (G_STRLOC ": %s", G_STRFUNC);
nimf_result_ref (result);
do {
result->is_dispatched = FALSE;
g_main_context_iteration (main_context, TRUE);
} while ((result->is_dispatched == FALSE) ||
(result->reply && ((result->reply->header->type != type) ||
(result->reply->header->icid != icid))));
if (G_UNLIKELY (result->is_dispatched == TRUE && result->reply == NULL))
g_debug (G_STRLOC ": %s: Can't receive %s",
G_STRFUNC, nimf_message_get_name_by_type (type));
/* This prevents not checking reply in the following iteration
* send commit (wait reply)
* recv reset
* send commit (wait reply)
* recv commit-reply (is_dispatched: TRUE)
* `result->is_dispatched = FALSE' prevents breaking loop
* send reset-reply
* recv commit-reply
*/
result->is_dispatched = FALSE;
nimf_result_unref (result);
}
void
nimf_send_message (GSocket *socket,
guint16 icid,
NimfMessageType type,
gpointer data,
guint16 data_len,
GDestroyNotify data_destroy_func)
{
g_debug (G_STRLOC ": %s: fd = %d", G_STRFUNC, g_socket_get_fd (socket));
NimfMessage *message;
GError *error = NULL;
gssize n_written;
GOutputVector vectors[2] = { { NULL, }, };
message = nimf_message_new_full (type, icid,
data, data_len, data_destroy_func);
vectors[0].buffer = nimf_message_get_header (message);
vectors[0].size = nimf_message_get_header_size ();
vectors[1].buffer = message->data;
vectors[1].size = message->header->data_len;
n_written = g_socket_send_message (socket, NULL, vectors,
message->header->data_len > 0 ? 2 : 1,
NULL, 0, 0, NULL, &error);
if (G_UNLIKELY (n_written != nimf_message_get_header_size () + message->header->data_len))
{
g_debug (G_STRLOC ": %s: n_written %"G_GSSIZE_FORMAT" differs from %d",
G_STRFUNC, n_written, nimf_message_get_header_size () + message->header->data_len);
if (error)
{
g_debug (G_STRLOC ": %s: %s", G_STRFUNC, error->message);
g_error_free (error);
}
nimf_message_unref (message);
return;
}
/* debug message */
const gchar *name = nimf_message_get_name (message);
if (name)
g_debug ("send: %s, icid: %d, fd: %d", name, icid, g_socket_get_fd(socket));
else
g_error (G_STRLOC ": unknown message type");
nimf_message_unref (message);
}
NimfMessage *nimf_recv_message (GSocket *socket)
{
g_debug (G_STRLOC ": %s", G_STRFUNC);
NimfMessage *message = nimf_message_new ();
GError *error = NULL;
gssize n_read = 0;
n_read = g_socket_receive (socket,
(gchar *) message->header,
nimf_message_get_header_size (),
NULL, &error);
if (G_UNLIKELY (n_read < nimf_message_get_header_size ()))
{
g_debug (G_STRLOC ": %s: received %"G_GSSIZE_FORMAT" less than %d",
G_STRFUNC, n_read, nimf_message_get_header_size ());
if (error)
{
g_debug (G_STRLOC ": %s: %s", G_STRFUNC, error->message);
g_error_free (error);
}
nimf_message_unref (message);
return NULL;
}
if (message->header->data_len > 0)
{
nimf_message_set_body (message,
g_malloc0 (message->header->data_len),
message->header->data_len,
g_free);
n_read = g_socket_receive (socket,
message->data,
message->header->data_len,
NULL, &error);
if (G_UNLIKELY (n_read < message->header->data_len))
{
g_debug (G_STRLOC ": %s: received %"G_GSSIZE_FORMAT" less than %d",
G_STRFUNC, n_read, message->header->data_len);
if (error)
{
g_debug (G_STRLOC ": %s: %s", G_STRFUNC, error->message);
g_error_free (error);
}
nimf_message_unref (message);
return NULL;
}
}
/* debug message */
const gchar *name = nimf_message_get_name (message);
if (name)
g_debug ("recv: %s, icid: %d, fd: %d", name, message->header->icid, g_socket_get_fd (socket));
else
g_error (G_STRLOC ": unknown message type");
return message;
}

View File

@@ -0,0 +1,64 @@
/* -*- Mode: C; indent-tabs-mode: nil; c-basic-offset: 2; tab-width: 2 -*- */
/*
* nimf-module-private.h
* This file is part of Nimf.
*
* Copyright (C) 2015-2019 Hodong Kim <cogniti@gmail.com>
*
* Nimf is free software: you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published
* by the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Nimf is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __NIMF_MODULE_H__
#define __NIMF_MODULE_H__
#if !defined (__NIMF_H_INSIDE__) && !defined (NIMF_COMPILATION)
#error "Only <nimf.h> can be included directly."
#endif
#include <glib-object.h>
#include <gmodule.h>
#include "nimf-engine.h"
G_BEGIN_DECLS
#define NIMF_TYPE_MODULE (nimf_module_get_type ())
#define NIMF_MODULE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NIMF_TYPE_MODULE, NimfModule))
#define NIMF_MODULE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), NIMF_TYPE_MODULE, NimfModuleClass))
#define NIMF_IS_MODULE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NIMF_TYPE_MODULE))
#define NIMF_IS_MODULE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), NIMF_TYPE_MODULE))
#define NIMF_MODULE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), NIMF_TYPE_MODULE, NimfModuleClass))
typedef struct _NimfModule NimfModule;
typedef struct _NimfModuleClass NimfModuleClass;
struct _NimfModule
{
GTypeModule parent_instance;
gchar *path;
GModule *library;
GType type;
};
struct _NimfModuleClass
{
GTypeModuleClass parent_class;
};
GType nimf_module_get_type (void) G_GNUC_CONST;
NimfModule *nimf_module_new (const gchar *path);
G_END_DECLS
#endif /* __NIMF_MODULE_H__ */

View File

@@ -0,0 +1,100 @@
/* -*- Mode: C; indent-tabs-mode: nil; c-basic-offset: 2; tab-width: 2 -*- */
/*
* nimf-module.c
* This file is part of Nimf.
*
* Copyright (C) 2015-2019 Hodong Kim <cogniti@gmail.com>
*
* Nimf is free software: you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published
* by the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Nimf is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; If not, see <http://www.gnu.org/licenses/>.
*/
#include "config.h"
#include "nimf-module-private.h"
#include <gio/gio.h>
G_DEFINE_TYPE (NimfModule, nimf_module, G_TYPE_TYPE_MODULE);
NimfModule *
nimf_module_new (const gchar *path)
{
g_debug (G_STRLOC ": %s", G_STRFUNC);
g_return_val_if_fail (path != NULL, NULL);
NimfModule *module = g_object_new (NIMF_TYPE_MODULE, NULL);
module->path = g_strdup (path);
return module;
}
static gboolean
nimf_module_load (GTypeModule *gmodule)
{
g_debug (G_STRLOC ": %s", G_STRFUNC);
NimfModule *module = NIMF_MODULE (gmodule);
void (* module_register_type) (GTypeModule *module);
GType (* module_get_type) (void);
module->library = g_module_open (module->path, G_MODULE_BIND_LAZY |
G_MODULE_BIND_LOCAL);
if (!module->library)
{
g_warning (G_STRLOC ": %s", g_module_error ());
return FALSE;
}
if (!g_module_symbol (module->library, "module_register_type",
(gpointer *) &module_register_type) ||
!g_module_symbol (module->library, "module_get_type",
(gpointer *) &module_get_type))
{
g_warning (G_STRLOC ": %s", g_module_error ());
g_module_close (module->library);
return FALSE;
}
module_register_type (gmodule);
module->type = module_get_type ();
return TRUE;
}
static void
nimf_module_unload (GTypeModule *gmodule)
{
g_debug (G_STRLOC ": %s", G_STRFUNC);
g_module_close (NIMF_MODULE (gmodule)->library);
}
static void
nimf_module_init (NimfModule *module)
{
g_debug (G_STRLOC ": %s", G_STRFUNC);
}
static void
nimf_module_class_init (NimfModuleClass *class)
{
g_debug (G_STRLOC ": %s", G_STRFUNC);
GTypeModuleClass *module_class = G_TYPE_MODULE_CLASS (class);
module_class->load = nimf_module_load;
module_class->unload = nimf_module_unload;
}

View File

@@ -0,0 +1,134 @@
/* -*- Mode: C; indent-tabs-mode: nil; c-basic-offset: 2; tab-width: 2 -*- */
/*
* nimf-preeditable.c
* This file is part of Nimf.
*
* Copyright (C) 2017-2019 Hodong Kim <cogniti@gmail.com>
*
* Nimf is free software: you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published
* by the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Nimf is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; If not, see <http://www.gnu.org/licenses/>.
*/
#include "nimf-preeditable.h"
G_DEFINE_INTERFACE (NimfPreeditable, nimf_preeditable, G_TYPE_OBJECT)
static void
nimf_preeditable_default_init (NimfPreeditableInterface *iface)
{
g_debug (G_STRLOC ": %s", G_STRFUNC);
}
/**
* nimf_preeditable_show:
* @preeditable: a #NimfPreeditable
*
* Shows @preeditable
*/
void
nimf_preeditable_show (NimfPreeditable *preeditable)
{
g_debug (G_STRLOC ": %s", G_STRFUNC);
g_return_if_fail (NIMF_IS_PREEDITABLE (preeditable));
NimfPreeditableInterface *iface = NIMF_PREEDITABLE_GET_IFACE (preeditable);
if (iface->show)
iface->show (preeditable);
}
/**
* nimf_preeditable_hide:
* @preeditable: a #NimfPreeditable
*
* Hides the @preeditable
*/
void
nimf_preeditable_hide (NimfPreeditable *preeditable)
{
g_debug (G_STRLOC ": %s", G_STRFUNC);
g_return_if_fail (NIMF_IS_PREEDITABLE (preeditable));
NimfPreeditableInterface *iface = NIMF_PREEDITABLE_GET_IFACE (preeditable);
if (iface->hide)
iface->hide (preeditable);
}
/**
* nimf_preeditable_is_visible:
* @preeditable: a #NimfPreeditable
*
* Returns: %TRUE if the @preeditable is visible
*/
gboolean
nimf_preeditable_is_visible (NimfPreeditable *preeditable)
{
g_debug (G_STRLOC ": %s", G_STRFUNC);
g_return_val_if_fail (NIMF_IS_PREEDITABLE (preeditable), FALSE);
NimfPreeditableInterface *iface = NIMF_PREEDITABLE_GET_IFACE (preeditable);
if (iface->is_visible)
return iface->is_visible (preeditable);
return FALSE;
}
/**
* nimf_preeditable_set_text:
* @preeditable: a #NimfPreeditable
* @text: text
* @cursor_pos: cursor position
*
* Sets @text to @preeditable.
*/
void
nimf_preeditable_set_text (NimfPreeditable *preeditable,
const gchar *text,
gint cursor_pos)
{
g_debug (G_STRLOC ": %s", G_STRFUNC);
g_return_if_fail (NIMF_IS_PREEDITABLE (preeditable));
NimfPreeditableInterface *iface = NIMF_PREEDITABLE_GET_IFACE (preeditable);
if (iface->set_text)
iface->set_text (preeditable, text, cursor_pos);
}
/**
* nimf_preeditable_set_cursor_location:
* @preeditable: a #NimfPreeditable
* @area: a #NimfRectangle
*
* Notifies the @preeditable that a change in cursor position has been made.
* The location is the position of a window position in root window coordinates.
*/
void
nimf_preeditable_set_cursor_location (NimfPreeditable *preeditable,
const NimfRectangle *area)
{
g_debug (G_STRLOC ": %s", G_STRFUNC);
g_return_if_fail (NIMF_IS_PREEDITABLE (preeditable));
NimfPreeditableInterface *iface = NIMF_PREEDITABLE_GET_IFACE (preeditable);
if (iface->set_cursor_location)
iface->set_cursor_location (preeditable, area);
}

View File

@@ -0,0 +1,71 @@
/* -*- Mode: C; indent-tabs-mode: nil; c-basic-offset: 2; tab-width: 2 -*- */
/*
* nimf-preeditable.h
* This file is part of Nimf.
*
* Copyright (C) 2017-2019 Hodong Kim <cogniti@gmail.com>
*
* Nimf is free software: you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published
* by the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Nimf is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __NIMF_PREEDITABLE_H__
#define __NIMF_PREEDITABLE_H__
#include <glib-object.h>
#include "nimf-types.h"
G_BEGIN_DECLS
#define NIMF_TYPE_PREEDITABLE nimf_preeditable_get_type ()
G_DECLARE_INTERFACE (NimfPreeditable, nimf_preeditable, NIMF, PREEDITABLE, GObject)
/**
* NimfPreeditableInterface:
* @parent: The parent interface.
* @show: Shows the preeditable.
* @hide: Hides the preeditable.
* @is_visible: Checks if the preeditable is visible.
* @set_text: Sets the text in the preeditable to the given value, replacing
* the current contents.
* @set_cursor_location: Sets the cursor position.
*
* Provides an interface for preedit gadget.
*/
struct _NimfPreeditableInterface
{
GTypeInterface parent;
void (* show) (NimfPreeditable *preeditable);
void (* hide) (NimfPreeditable *preeditable);
gboolean (* is_visible) (NimfPreeditable *preeditable);
void (* set_text) (NimfPreeditable *preeditable,
const gchar *text,
gint cursor_pos);
void (* set_cursor_location) (NimfPreeditable *preeditable,
const NimfRectangle *area);
};
void nimf_preeditable_show (NimfPreeditable *preeditable);
void nimf_preeditable_hide (NimfPreeditable *preeditable);
gboolean nimf_preeditable_is_visible (NimfPreeditable *preeditable);
void nimf_preeditable_set_text (NimfPreeditable *preeditable,
const gchar *text,
gint cursor_pos);
void nimf_preeditable_set_cursor_location (NimfPreeditable *preeditable,
const NimfRectangle *area);
G_END_DECLS
#endif /* __NIMF_PREEDITABLE_H__ */

View File

@@ -0,0 +1,63 @@
/* -*- Mode: C; indent-tabs-mode: nil; c-basic-offset: 2; tab-width: 2 -*- */
/*
* nimf-server-private.h
* This file is part of Nimf.
*
* Copyright (C) 2015-2019 Hodong Kim <cogniti@gmail.com>
*
* Nimf is free software: you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published
* by the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Nimf is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __NIMF_SERVER_PRIVATE_H__
#define __NIMF_SERVER_PRIVATE_H__
#include "nimf-server.h"
#include "nimf-service-ic.h"
G_BEGIN_DECLS
struct _NimfServerPrivate
{
GHashTable *modules;
GHashTable *services;
GList *engines;
NimfServiceIC *last_focused_im;
const gchar *last_focused_service;
GSettings *settings;
NimfKey **hotkeys;
GHashTable *shortcuts;
gboolean use_singleton;
GPtrArray *ics;
/* facilities */
NimfCandidatable *candidatable;
NimfPreeditable *preeditable;
};
typedef struct {
GSettings *settings;
NimfKey **to_lang;
NimfKey **to_sys;
} NimfShortcut;
G_END_DECLS
NimfEngine *nimf_server_get_default_engine (NimfServer *server);
NimfEngine *nimf_server_get_next_engine (NimfServer *server,
NimfEngine *engine);
NimfEngine *nimf_server_get_engine_by_id (NimfServer *server,
const gchar *engine_id);
gboolean nimf_server_start (NimfServer *server);
#endif /* __NIMF_SERVER_PRIVATE_H__ */

View File

@@ -0,0 +1,826 @@
/* -*- Mode: C; indent-tabs-mode: nil; c-basic-offset: 2; tab-width: 2 -*- */
/*
* nimf-server.c
* This file is part of Nimf.
*
* Copyright (C) 2015-2019 Hodong Kim <cogniti@gmail.com>
*
* Nimf is free software: you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published
* by the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Nimf is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; If not, see <http://www.gnu.org/licenses/>.
*/
#include <glib.h>
#include <glib-object.h>
#include "nimf-server.h"
#include "nimf-server-private.h"
#include "nimf-service.h"
#include <glib/gstdio.h>
#include "nimf-marshalers-private.h"
#include "nimf-module-private.h"
#include <string.h>
#include "nimf-service-ic-private.h"
enum {
ENGINE_CHANGED,
ENGINE_STATUS_CHANGED,
ENGINE_LOADED,
ENGINE_UNLOADED,
LAST_SIGNAL
};
static guint nimf_server_signals[LAST_SIGNAL] = { 0 };
static NimfServer *_nimf_server_ = NULL;
G_DEFINE_TYPE_WITH_PRIVATE (NimfServer, nimf_server, G_TYPE_OBJECT);
static gint
on_comparing_engine_with_id (NimfEngine *engine, const gchar *engine_id)
{
g_debug (G_STRLOC ": %s", G_STRFUNC);
return g_strcmp0 (nimf_engine_get_id (engine), engine_id);
}
NimfEngine *
nimf_server_get_engine_by_id (NimfServer *server,
const gchar *engine_id)
{
g_debug (G_STRLOC ": %s", G_STRFUNC);
GList *list;
list = g_list_find_custom (server->priv->engines, engine_id,
(GCompareFunc) on_comparing_engine_with_id);
if (list)
return list->data;
return NULL;
}
NimfEngine *
nimf_server_get_next_engine (NimfServer *server, NimfEngine *engine)
{
g_debug (G_STRLOC ": %s", G_STRFUNC);
GList *list;
list = g_list_find (server->priv->engines, engine);
if (list == NULL)
list = g_list_find_custom (server->priv->engines, nimf_engine_get_id (engine),
(GCompareFunc) on_comparing_engine_with_id);
list = g_list_next (list);
if (list == NULL)
list = server->priv->engines;
return list->data;
}
NimfEngine *
nimf_server_get_default_engine (NimfServer *server)
{
g_debug (G_STRLOC ": %s", G_STRFUNC);
GSettings *settings;
gchar *engine_id;
NimfEngine *engine;
settings = g_settings_new ("org.nimf.engines");
engine_id = g_settings_get_string (settings, "default-engine");
engine = nimf_server_get_engine_by_id (server, engine_id);
if (G_UNLIKELY (engine == NULL))
{
g_settings_reset (settings, "default-engine");
g_free (engine_id);
engine_id = g_settings_get_string (settings, "default-engine");
engine = nimf_server_get_engine_by_id (server, engine_id);
}
g_free (engine_id);
g_object_unref (settings);
return engine;
}
/**
* nimf_server_get_default:
*
* Returns the default #NimfServer instance.
*
* If there is no default server then %NULL is returned.
*
* Returns: (transfer none): the default server, or %NULL if server is not
* running
*/
NimfServer *
nimf_server_get_default ()
{
g_debug (G_STRLOC ": %s", G_STRFUNC);
return _nimf_server_;
}
/**
* nimf_server_get_preeditable:
* @server: a #NimfServer
*
* Returns the #NimfPreeditable instance.
*
* If there is no default preeditable then %NULL is returned.
*
* Returns: (transfer none): a #NimfPreeditable, or %NULL
*/
NimfPreeditable *
nimf_server_get_preeditable (NimfServer *server)
{
g_debug (G_STRLOC ": %s", G_STRFUNC);
return server->priv->preeditable;
}
static void
on_changed_hotkeys (GSettings *settings,
gchar *key,
NimfServer *server)
{
g_debug (G_STRLOC ": %s", G_STRFUNC);
gchar **keys = g_settings_get_strv (settings, key);
nimf_key_freev (server->priv->hotkeys);
server->priv->hotkeys = nimf_key_newv ((const gchar **) keys);
g_strfreev (keys);
}
static void
on_use_singleton (GSettings *settings,
gchar *key,
NimfServer *server)
{
g_debug (G_STRLOC ": %s", G_STRFUNC);
server->priv->use_singleton = g_settings_get_boolean (server->priv->settings,
"use-singleton");
}
static void
on_changed_shortcuts (GSettings *settings,
gchar *key,
NimfServer *server)
{
g_debug (G_STRLOC ": %s", G_STRFUNC);
NimfShortcut *shortcut;
const gchar *engine_id;
gchar *schema_id;
g_object_get (settings, "schema-id", &schema_id, NULL);
engine_id = schema_id + strlen ("org.nimf.engines.");
shortcut = g_hash_table_lookup (server->priv->shortcuts, engine_id);
if (g_strcmp0 (key, "shortcuts-to-lang") == 0)
{
gchar **keys;
keys = g_settings_get_strv (settings, key);
shortcut->to_lang = nimf_key_newv ((const gchar **) keys);
g_strfreev (keys);
}
else if (g_strcmp0 (key, "shortcuts-to-sys") == 0)
{
gchar **keys;
keys = g_settings_get_strv (settings, key);
shortcut->to_sys = nimf_key_newv ((const gchar **) keys);
g_strfreev (keys);
}
g_free (schema_id);
}
static NimfShortcut *
nimf_server_shortcut_new (NimfServer *server,
GSettings *settings)
{
g_debug (G_STRLOC ": %s", G_STRFUNC);
GSettingsSchemaSource *source;
GSettingsSchema *schema;
NimfShortcut *shortcut;
gchar *schema_id;
g_object_get (settings, "schema-id", &schema_id, NULL);
source = g_settings_schema_source_get_default ();
schema = g_settings_schema_source_lookup (source, schema_id, TRUE);
shortcut = g_slice_new0 (NimfShortcut);
if (g_settings_schema_has_key (schema, "shortcuts-to-lang"))
{
gchar **to_lang;
to_lang = g_settings_get_strv (settings, "shortcuts-to-lang");
shortcut->to_lang = nimf_key_newv ((const gchar **) to_lang);
g_signal_connect (settings, "changed::shortcuts-to-lang",
G_CALLBACK (on_changed_shortcuts), server);
g_strfreev (to_lang);
}
if (g_settings_schema_has_key (schema, "shortcuts-to-sys"))
{
gchar **to_sys;
to_sys = g_settings_get_strv (settings, "shortcuts-to-sys");
shortcut->to_sys = nimf_key_newv ((const gchar **) to_sys);
g_signal_connect (settings, "changed::shortcuts-to-sys",
G_CALLBACK (on_changed_shortcuts), server);
g_strfreev (to_sys);
}
shortcut->settings = settings;
g_free (schema_id);
g_settings_schema_unref (schema);
return shortcut;
}
static void
nimf_server_shortcut_free (NimfShortcut *shortcut)
{
g_debug (G_STRLOC ": %s", G_STRFUNC);
if (shortcut->settings)
g_object_unref (shortcut->settings);
if (shortcut->to_lang)
nimf_key_freev (shortcut->to_lang);
if (shortcut->to_sys)
nimf_key_freev (shortcut->to_sys);
g_slice_free (NimfShortcut, shortcut);
}
static void
nimf_server_init (NimfServer *server)
{
g_debug (G_STRLOC ": %s", G_STRFUNC);
_nimf_server_ = server;
server->priv = nimf_server_get_instance_private (server);
server->priv->ics = g_ptr_array_new ();
server->priv->settings = g_settings_new ("org.nimf");
server->priv->use_singleton = g_settings_get_boolean (server->priv->settings,
"use-singleton");
server->priv->shortcuts =
g_hash_table_new_full (g_str_hash, g_str_equal, g_free,
(GDestroyNotify) nimf_server_shortcut_free);
gchar **hotkeys = g_settings_get_strv (server->priv->settings, "hotkeys");
server->priv->hotkeys = nimf_key_newv ((const gchar **) hotkeys);
g_strfreev (hotkeys);
server->priv->modules = g_hash_table_new_full (g_str_hash, g_str_equal,
g_free, NULL);
server->priv->services = g_hash_table_new_full (g_str_hash, g_str_equal,
g_free, g_object_unref);
}
static void
nimf_server_finalize (GObject *object)
{
g_debug (G_STRLOC ": %s", G_STRFUNC);
NimfServer *server = NIMF_SERVER (object);
GHashTableIter iter;
gpointer service;
g_ptr_array_free (server->priv->ics, FALSE);
g_hash_table_iter_init (&iter, server->priv->services);
while (g_hash_table_iter_next (&iter, NULL, &service))
nimf_service_stop (NIMF_SERVICE (service));
g_hash_table_unref (server->priv->modules);
g_hash_table_unref (server->priv->services);
if (server->priv->engines)
{
g_list_free_full (server->priv->engines, g_object_unref);
server->priv->engines = NULL;
}
g_object_unref (server->priv->settings);
g_hash_table_unref (server->priv->shortcuts);
nimf_key_freev (server->priv->hotkeys);
G_OBJECT_CLASS (nimf_server_parent_class)->finalize (object);
}
static void
nimf_server_class_init (NimfServerClass *class)
{
g_debug (G_STRLOC ": %s", G_STRFUNC);
G_OBJECT_CLASS (class)->finalize = nimf_server_finalize;
/**
* NimfServer::engine-changed:
* @server: a #NimfServer
* @engine_id: engine id
* @icon_name: icon name
*
* The #NimfServer::engine-changed signal is emitted when the engine is
* changed.
*/
nimf_server_signals[ENGINE_CHANGED] =
g_signal_new (g_intern_static_string ("engine-changed"),
G_TYPE_FROM_CLASS (class),
G_SIGNAL_RUN_LAST,
G_STRUCT_OFFSET (NimfServerClass, engine_changed),
NULL, NULL,
nimf_cclosure_marshal_VOID__STRING_STRING,
G_TYPE_NONE, 2,
G_TYPE_STRING,
G_TYPE_STRING);
/**
* NimfServer::engine-status-changed:
* @server: a #NimfServer
* @engine_id: engine id
* @icon_name: icon name
*
* The #NimfServer::engine-status-changed signal is emitted when the engine
* status is changed.
*/
nimf_server_signals[ENGINE_STATUS_CHANGED] =
g_signal_new (g_intern_static_string ("engine-status-changed"),
G_TYPE_FROM_CLASS (class),
G_SIGNAL_RUN_LAST,
G_STRUCT_OFFSET (NimfServerClass, engine_status_changed),
NULL, NULL,
nimf_cclosure_marshal_VOID__STRING_STRING,
G_TYPE_NONE, 2,
G_TYPE_STRING,
G_TYPE_STRING);
/**
* NimfServer::engine-loaded:
* @server: a #NimfServer
* @engine_id: engine id
*
* The #NimfServer::engine-loaded signal is emitted when the engine is loaded.
*/
nimf_server_signals[ENGINE_LOADED] =
g_signal_new (g_intern_static_string ("engine-loaded"),
G_TYPE_FROM_CLASS (class),
G_SIGNAL_RUN_LAST,
G_STRUCT_OFFSET (NimfServerClass, engine_loaded),
NULL, NULL,
nimf_cclosure_marshal_VOID__STRING,
G_TYPE_NONE, 1,
G_TYPE_STRING);
/**
* NimfServer::engine-unloaded:
* @server: a #NimfServer
* @engine_id: engine id
*
* The #NimfServer::engine-unloaded signal is emitted when the engine is
* unloaded.
*/
nimf_server_signals[ENGINE_UNLOADED] =
g_signal_new (g_intern_static_string ("engine-unloaded"),
G_TYPE_FROM_CLASS (class),
G_SIGNAL_RUN_LAST,
G_STRUCT_OFFSET (NimfServerClass, engine_unloaded),
NULL, NULL,
nimf_cclosure_marshal_VOID__STRING,
G_TYPE_NONE, 1,
G_TYPE_STRING);
}
/**
* nimf_server_change_engine_by_id:
* @server: a #NimfServer
* @engine_id: engine id
*
* Changes the last focused engine to the engine with the given ID.
*/
void
nimf_server_change_engine_by_id (NimfServer *server,
const gchar *engine_id)
{
g_debug (G_STRLOC ": %s", G_STRFUNC);
GHashTableIter iter;
gpointer service;
g_hash_table_iter_init (&iter, server->priv->services);
while (g_hash_table_iter_next (&iter, NULL, &service))
{
if (!g_strcmp0 (server->priv->last_focused_service,
nimf_service_get_id (service)))
nimf_service_change_engine_by_id (service, engine_id);
}
}
/**
* nimf_server_change_engine:
* @server: a #NimfServer
* @engine_id: engine id
* @method_id: method id
*/
void
nimf_server_change_engine (NimfServer *server,
const gchar *engine_id,
const gchar *method_id)
{
g_debug (G_STRLOC ": %s", G_STRFUNC);
GHashTableIter iter;
gpointer service;
g_hash_table_iter_init (&iter, server->priv->services);
while (g_hash_table_iter_next (&iter, NULL, &service))
{
if (!g_strcmp0 (server->priv->last_focused_service,
nimf_service_get_id (service)))
nimf_service_change_engine (service, engine_id, method_id);
}
}
static gint
on_comparison (gconstpointer engine_id_a,
gconstpointer engine_id_b)
{
g_debug (G_STRLOC ": %s", G_STRFUNC);
GSettings *settings_a;
GSettings *settings_b;
gchar *schema_id_a;
gchar *schema_id_b;
gchar *schema_name_a;
gchar *schema_name_b;
gint retval;
schema_id_a = g_strdup_printf ("org.nimf.engines.%s", *(gchar **) engine_id_a);
schema_id_b = g_strdup_printf ("org.nimf.engines.%s", *(gchar **) engine_id_b);
settings_a = g_settings_new (schema_id_a);
settings_b = g_settings_new (schema_id_b);
schema_name_a = g_settings_get_string (settings_a, "hidden-schema-name");
schema_name_b = g_settings_get_string (settings_b, "hidden-schema-name");
retval = g_utf8_collate (schema_name_a, schema_name_b);
g_free (schema_name_a);
g_free (schema_name_b);
g_free (schema_id_a);
g_free (schema_id_b);
g_object_unref (settings_a);
g_object_unref (settings_b);
return retval;
}
/**
* nimf_server_get_loaded_engine_ids:
* @server: a #NimfServer
*
* The array is %NULL-terminated.
*
* Returns: (transfer full): a new %NULL-terminated engine id array
*/
gchar **nimf_server_get_loaded_engine_ids (NimfServer *server)
{
g_debug (G_STRLOC ": %s", G_STRFUNC);
GList *list;
const gchar *engine_id;
GPtrArray *array = g_ptr_array_new ();
for (list = server->priv->engines; list != NULL; list = list->next)
{
engine_id = nimf_engine_get_id (list->data);
g_ptr_array_add (array, g_strdup (engine_id));
}
g_ptr_array_sort (array, on_comparison);
g_ptr_array_add (array, NULL);
return (gchar **) g_ptr_array_free (array, FALSE);
}
NimfServiceIC *
nimf_server_get_last_focused_im (NimfServer *server)
{
g_debug (G_STRLOC ": %s", G_STRFUNC);
return server->priv->last_focused_im;
}
void
nimf_server_set_last_focused_im (NimfServer *server,
NimfServiceIC *im)
{
g_debug (G_STRLOC ": %s", G_STRFUNC);
server->priv->last_focused_im = im;
}
static void
nimf_server_load_service (NimfServer *server,
const gchar *path)
{
g_debug (G_STRLOC ": %s", G_STRFUNC);
NimfModule *module;
NimfService *service;
module = nimf_module_new (path);
if (!g_type_module_use (G_TYPE_MODULE (module)))
{
g_warning (G_STRLOC ":" "Failed to load module: %s", path);
g_object_unref (module);
return;
}
service = g_object_new (module->type, NULL);
g_hash_table_insert (server->priv->services,
g_strdup (nimf_service_get_id (service)), service);
g_type_module_unuse (G_TYPE_MODULE (module));
}
static void
nimf_server_load_services (NimfServer *server)
{
g_debug (G_STRLOC ": %s", G_STRFUNC);
GDir *dir;
GError *error = NULL;
const gchar *filename;
gchar *path;
dir = g_dir_open (NIMF_SERVICE_MODULE_DIR, 0, &error);
if (error)
{
g_warning (G_STRLOC ": %s: %s", G_STRFUNC, error->message);
g_clear_error (&error);
return;
}
while ((filename = g_dir_read_name (dir)))
{
path = g_build_path (G_DIR_SEPARATOR_S, NIMF_SERVICE_MODULE_DIR, filename, NULL);
nimf_server_load_service (server, path);
g_free (path);
}
g_dir_close (dir);
}
static void
nimf_server_load_engines (NimfServer *server)
{
g_debug (G_STRLOC ": %s", G_STRFUNC);
GSettingsSchemaSource *source; /* do not free */
gchar **schema_ids;
GPtrArray *engine_ids;
gchar **active_engines;
gint i;
engine_ids = g_ptr_array_new ();
source = g_settings_schema_source_get_default ();
g_settings_schema_source_list_schemas (source, TRUE, &schema_ids, NULL);
for (i = 0; schema_ids[i] != NULL; i++)
{
if (g_str_has_prefix (schema_ids[i], "org.nimf.engines."))
{
GSettingsSchema *schema;
GSettings *settings;
const gchar *engine_id;
gboolean active = TRUE;
engine_id = schema_ids[i] + strlen ("org.nimf.engines.");
schema = g_settings_schema_source_lookup (source, schema_ids[i], TRUE);
settings = g_settings_new (schema_ids[i]);
if (g_settings_schema_has_key (schema, "active-engine"))
active = g_settings_get_boolean (settings, "active-engine");
if (active)
{
NimfModule *module;
NimfEngine *engine;
gchar *path;
path = g_module_build_path (NIMF_MODULE_DIR, engine_id);
module = nimf_module_new (path);
if (!g_type_module_use (G_TYPE_MODULE (module)))
{
g_warning (G_STRLOC ": Failed to load module: %s", path);
g_object_unref (module);
g_free (path);
g_object_unref (settings);
g_settings_schema_unref (schema);
continue;
}
g_hash_table_insert (server->priv->modules, g_strdup (engine_id), module);
engine = g_object_new (module->type, NULL);
g_type_module_unuse (G_TYPE_MODULE (module));
server->priv->engines = g_list_prepend (server->priv->engines, engine);
g_ptr_array_add (engine_ids, g_strdup (engine_id));
if (g_settings_schema_has_key (schema, "shortcuts-to-lang"))
g_hash_table_insert (server->priv->shortcuts, g_strdup (engine_id),
nimf_server_shortcut_new (server, settings));
g_free (path);
}
g_settings_schema_unref (schema);
}
}
g_strfreev (schema_ids);
g_ptr_array_add (engine_ids, NULL);
active_engines = (gchar **) g_ptr_array_free (engine_ids, FALSE);
g_settings_set_strv (server->priv->settings, "hidden-active-engines",
(const gchar *const *) active_engines);
g_strfreev (active_engines);
}
static void
on_changed_active_engines (GSettings *settings,
gchar *key,
NimfServer *server)
{
g_debug (G_STRLOC ": %s", G_STRFUNC);
GSettingsSchemaSource *source;
gchar **engine_ids;
gint i;
source = g_settings_schema_source_get_default ();
engine_ids = g_settings_get_strv (settings, key);
for (i = 0; engine_ids[i]; i++)
{
if (!nimf_server_get_engine_by_id (server, engine_ids[i]))
{
GSettingsSchema *schema;
gchar *schema_id;
NimfEngine *engine;
NimfServer *server = nimf_server_get_default ();
NimfModule *module = g_hash_table_lookup (server->priv->modules, engine_ids[i]);
gint index;
if (!module)
{
gchar *path;
path = g_module_build_path (NIMF_MODULE_DIR, engine_ids[i]);
module = nimf_module_new (path);
if (!g_type_module_use (G_TYPE_MODULE (module)))
{
g_warning (G_STRLOC ": Failed to load module: %s", path);
g_object_unref (module);
g_free (path);
return;
}
g_free (path);
g_hash_table_insert (server->priv->modules, g_strdup (engine_ids[i]), module);
}
g_type_module_use (G_TYPE_MODULE (module));
engine = g_object_new (module->type, NULL);
g_type_module_unuse (G_TYPE_MODULE (module));
server->priv->engines = g_list_prepend (server->priv->engines, engine);
for (index = 0; index < server->priv->ics->len; index++)
{
NimfServiceIC *ic = g_ptr_array_index (server->priv->ics, index);
nimf_service_ic_load_engine (ic, engine_ids[i], server);
}
schema_id = g_strdup_printf ("org.nimf.engines.%s", engine_ids[i]);
schema = g_settings_schema_source_lookup (source, schema_id, TRUE);
if (g_settings_schema_has_key (schema, "shortcuts-to-lang"))
g_hash_table_insert (server->priv->shortcuts, g_strdup (engine_ids[i]),
nimf_server_shortcut_new (server, g_settings_new (schema_id)));
g_signal_emit (server, nimf_server_signals[ENGINE_LOADED], 0, engine_ids[i]);
g_free (schema_id);
g_settings_schema_unref (schema);
}
}
GList *l = server->priv->engines;
while (l != NULL)
{
const gchar *engine_id = nimf_engine_get_id (l->data);
GList *next = l->next;
if (g_strcmp0 (engine_id, "nimf-system-keyboard") &&
!g_strv_contains ((const gchar * const *) engine_ids, engine_id))
{
NimfEngine *engine = l->data;
gint index;
g_hash_table_remove (server->priv->shortcuts, engine_id);
server->priv->engines = g_list_delete_link (server->priv->engines, l);
for (index = 0; index < server->priv->ics->len; index++)
{
NimfServiceIC *ic = g_ptr_array_index (server->priv->ics, index);
nimf_service_ic_unload_engine (ic, engine_id, engine, server);
}
g_signal_emit (server, nimf_server_signals[ENGINE_UNLOADED], 0, engine_id);
g_object_unref (engine);
}
l = next;
}
g_strfreev (engine_ids);
}
gboolean
nimf_server_start (NimfServer *server)
{
g_debug (G_STRLOC ": %s", G_STRFUNC);
g_return_val_if_fail (NIMF_IS_SERVER (server), FALSE);
nimf_server_load_services (server);
server->priv->candidatable = g_hash_table_lookup (server->priv->services,
"nimf-candidate");
server->priv->preeditable = g_hash_table_lookup (server->priv->services,
"nimf-preedit-window");
nimf_service_start (NIMF_SERVICE (server->priv->candidatable));
nimf_service_start (NIMF_SERVICE (server->priv->preeditable));
nimf_server_load_engines (server);
GHashTableIter iter;
gpointer service;
g_hash_table_iter_init (&iter, server->priv->services);
while (g_hash_table_iter_next (&iter, NULL, &service))
{
if (!g_strcmp0 (nimf_service_get_id (NIMF_SERVICE (service)), "nimf-candidate"))
continue;
else if (!g_strcmp0 (nimf_service_get_id (NIMF_SERVICE (service)), "nimf-preedit-window"))
continue;
if (!nimf_service_start (NIMF_SERVICE (service)))
g_hash_table_iter_remove (&iter);
}
g_signal_connect (server->priv->settings, "changed::hotkeys",
G_CALLBACK (on_changed_hotkeys), server);
g_signal_connect (server->priv->settings, "changed::use-singleton",
G_CALLBACK (on_use_singleton), server);
g_signal_connect (server->priv->settings, "changed::hidden-active-engines",
G_CALLBACK (on_changed_active_engines), server);
return TRUE;
}

View File

@@ -0,0 +1,78 @@
/* -*- Mode: C; indent-tabs-mode: nil; c-basic-offset: 2; tab-width: 2 -*- */
/*
* nimf-server.h
* This file is part of Nimf.
*
* Copyright (C) 2015-2019 Hodong Kim <cogniti@gmail.com>
*
* Nimf is free software: you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published
* by the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Nimf is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __NIMF_SERVER_H__
#define __NIMF_SERVER_H__
#include <glib-object.h>
#include <gio/gio.h>
#include "nimf-preeditable.h"
G_BEGIN_DECLS
#define NIMF_TYPE_SERVER (nimf_server_get_type ())
#define NIMF_SERVER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NIMF_TYPE_SERVER, NimfServer))
#define NIMF_SERVER_CLASS(class) (G_TYPE_CHECK_CLASS_CAST ((class), NIMF_TYPE_SERVER, NimfServerClass))
#define NIMF_IS_SERVER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NIMF_TYPE_SERVER))
#define NIMF_SERVER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), NIMF_TYPE_SERVER, NimfServerClass))
typedef struct _NimfServer NimfServer;
typedef struct _NimfServerClass NimfServerClass;
typedef struct _NimfServerPrivate NimfServerPrivate;
struct _NimfServer
{
GObject parent_instance;
NimfServerPrivate *priv;
};
struct _NimfServerClass
{
/*< private >*/
GObjectClass parent_class;
/*< public >*/
/* Signals */
void (* engine_changed) (NimfServer *server,
const gchar *engine_id,
const gchar *icon_name);
void (* engine_status_changed) (NimfServer *server,
const gchar *engine_id,
const gchar *icon_name);
void (* engine_loaded) (NimfServer *server,
const gchar *engine_id);
void (* engine_unloaded) (NimfServer *server,
const gchar *engine_id);
};
GType nimf_server_get_type (void) G_GNUC_CONST;
void nimf_server_change_engine_by_id (NimfServer *server,
const gchar *engine_id);
void nimf_server_change_engine (NimfServer *server,
const gchar *engine_id,
const gchar *method_id);
gchar **nimf_server_get_loaded_engine_ids (NimfServer *server);
NimfServer *nimf_server_get_default (void);
NimfPreeditable *nimf_server_get_preeditable (NimfServer *server);
G_END_DECLS
#endif /* __NIMF_SERVER_H__ */

View File

@@ -0,0 +1,41 @@
/* -*- Mode: C; indent-tabs-mode: nil; c-basic-offset: 2; tab-width: 2 -*- */
/*
* nimf-service-ic-private.h
* This file is part of Nimf.
*
* Copyright (C) 2019 Hodong Kim <cogniti@gmail.com>
*
* Nimf is free software: you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published
* by the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Nimf is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __NIMF_SERVICE_IC_PRIVATE_H__
#define __NIMF_SERVICE_IC_PRIVATE_H__
#include "nimf-service-ic.h"
G_BEGIN_DECLS
extern void
nimf_service_ic_load_engine (NimfServiceIC *ic,
const gchar *engine_id,
NimfServer *server);
extern void
nimf_service_ic_unload_engine (NimfServiceIC *ic,
const gchar *engine_id,
NimfEngine *signleton_engine_to_be_deleted,
NimfServer *server);
G_END_DECLS
#endif /* __NIMF_SERVICE_IC_PRIVATE_H__ */

View File

@@ -0,0 +1,858 @@
/* -*- Mode: C; indent-tabs-mode: nil; c-basic-offset: 2; tab-width: 2 -*- */
/*
* nimf-service-ic.c
* This file is part of Nimf.
*
* Copyright (C) 2015-2019 Hodong Kim <cogniti@gmail.com>
*
* Nimf is free software: you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published
* by the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Nimf is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; If not, see <http://www.gnu.org/licenses/>.
*/
#include "nimf-service-ic.h"
#include "nimf-module-private.h"
#include <string.h>
#include "nimf-preeditable.h"
#include "nimf-key-syms.h"
#include "nimf-server-private.h"
#include "nimf-server.h"
#include "nimf-service.h"
struct _NimfServiceICPrivate
{
NimfEngine *engine;
GList *engines;
gboolean use_preedit;
NimfRectangle *cursor_area;
/* preedit */
NimfPreeditState preedit_state;
gchar *preedit_string;
NimfPreeditAttr **preedit_attrs;
gint preedit_cursor_pos;
};
G_DEFINE_ABSTRACT_TYPE_WITH_PRIVATE (NimfServiceIC, nimf_service_ic, G_TYPE_OBJECT);
/**
* nimf_service_ic_emit_preedit_start:
* @ic: a #NimfServiceIC
*
* Emits a #NimfIM::preedit-start signal.
*/
void nimf_service_ic_emit_preedit_start (NimfServiceIC *ic)
{
g_debug (G_STRLOC ": %s", G_STRFUNC);
if (G_UNLIKELY (!ic))
return;
ic->priv->preedit_state = NIMF_PREEDIT_STATE_START;
NimfServiceICClass *class = NIMF_SERVICE_IC_GET_CLASS (ic);
if (class->emit_preedit_start && ic->priv->use_preedit)
class->emit_preedit_start (ic);
}
/**
* nimf_service_ic_emit_preedit_changed:
* @ic: a #NimfServiceIC
* @preedit_string: preedit string
* @attrs: an array of #NimfPreeditAttr
* @cursor_pos: cursor position
*
* Emits a #NimfIM::preedit-changed signal.
*/
void
nimf_service_ic_emit_preedit_changed (NimfServiceIC *ic,
const gchar *preedit_string,
NimfPreeditAttr **attrs,
gint cursor_pos)
{
g_debug (G_STRLOC ": %s", G_STRFUNC);
if (G_UNLIKELY (!ic))
return;
g_free (ic->priv->preedit_string);
nimf_preedit_attr_freev (ic->priv->preedit_attrs);
ic->priv->preedit_string = g_strdup (preedit_string);
ic->priv->preedit_attrs = nimf_preedit_attrs_copy (attrs);
ic->priv->preedit_cursor_pos = cursor_pos;
NimfServiceICClass *class = NIMF_SERVICE_IC_GET_CLASS (ic);
NimfServer *server = nimf_server_get_default ();
if (class->emit_preedit_changed && ic->priv->use_preedit)
class->emit_preedit_changed (ic, preedit_string, attrs, cursor_pos);
if (!ic->priv->use_preedit &&
!nimf_candidatable_is_visible (server->priv->candidatable) &&
strlen (preedit_string))
{
nimf_preeditable_set_text (server->priv->preeditable,
preedit_string, cursor_pos);
nimf_preeditable_show (server->priv->preeditable);
}
else
{
nimf_preeditable_hide (server->priv->preeditable);
}
}
/**
* nimf_service_ic_emit_preedit_end:
* @ic: a #NimfServiceIC
*
* Emits a #NimfIM::preedit-end signal.
*/
void
nimf_service_ic_emit_preedit_end (NimfServiceIC *ic)
{
g_debug (G_STRLOC ": %s", G_STRFUNC);
if (G_UNLIKELY (!ic))
return;
ic->priv->preedit_state = NIMF_PREEDIT_STATE_END;
NimfServiceICClass *class = NIMF_SERVICE_IC_GET_CLASS (ic);
NimfServer *server = nimf_server_get_default ();
if (class->emit_preedit_end && ic->priv->use_preedit)
class->emit_preedit_end (ic);
if (!ic->priv->use_preedit)
nimf_preeditable_hide (server->priv->preeditable);
}
/**
* nimf_service_ic_emit_commit:
* @ic: a #NimfServiceIC
* @text: text to commit
*
* Emits a #NimfIM::commit signal.
*/
void
nimf_service_ic_emit_commit (NimfServiceIC *ic,
const gchar *text)
{
g_debug (G_STRLOC ": %s", G_STRFUNC);
if (G_UNLIKELY (!ic))
return;
NimfServiceICClass *class = NIMF_SERVICE_IC_GET_CLASS (ic);
if (class->emit_commit)
class->emit_commit (ic, text);
}
/**
* nimf_service_ic_emit_retrieve_surrounding:
* @ic: a #NimfServiceIC
*
* Emits a #NimfIM::retrieve-surrounding signal.
*/
gboolean
nimf_service_ic_emit_retrieve_surrounding (NimfServiceIC *ic)
{
g_debug (G_STRLOC ": %s", G_STRFUNC);
if (G_UNLIKELY (!ic))
return FALSE;
NimfServiceICClass *class = NIMF_SERVICE_IC_GET_CLASS (ic);
if (class->emit_retrieve_surrounding)
return class->emit_retrieve_surrounding (ic);
else
return FALSE;
}
/**
* nimf_service_ic_emit_delete_surrounding:
* @ic: a #NimfServiceIC
* @offset: the character offset from the cursor position of the text to be
* deleted. A negative value indicates a position before the cursor.
* @n_chars: the number of characters to be deleted
*
* Emits a #NimfIM::delete-surrounding signal.
*
* Returns: %TRUE if the signal was handled.
*/
gboolean
nimf_service_ic_emit_delete_surrounding (NimfServiceIC *ic,
gint offset,
gint n_chars)
{
g_debug (G_STRLOC ": %s", G_STRFUNC);
if (G_UNLIKELY (!ic))
return FALSE;
NimfServiceICClass *class = NIMF_SERVICE_IC_GET_CLASS (ic);
if (class->emit_delete_surrounding)
return class->emit_delete_surrounding (ic, offset, n_chars);
else
return FALSE;
}
/**
* nimf_service_ic_engine_changed:
* @ic: a #NimfServiceIC
* @engine_id: engine id
* @name: name
*/
void
nimf_service_ic_engine_changed (NimfServiceIC *ic,
const gchar *engine_id,
const gchar *name)
{
g_debug (G_STRLOC ": %s", G_STRFUNC);
if (G_UNLIKELY (!ic))
return;
NimfServer *server = nimf_server_get_default ();
g_signal_emit_by_name (server, "engine-changed", engine_id, name);
}
/**
* nimf_service_ic_emit_beep:
* @ic: a #NimfServiceIC
*
* Emits a #NimfIM::beep signal.
*/
void
nimf_service_ic_emit_beep (NimfServiceIC *ic)
{
g_debug (G_STRLOC ": %s", G_STRFUNC);
if (G_UNLIKELY (!ic))
return;
NimfServiceICClass *class = NIMF_SERVICE_IC_GET_CLASS (ic);
if (class->emit_beep)
class->emit_beep (ic);
}
/**
* nimf_service_ic_focus_in:
* @ic: a #NimfServiceIC
*/
void
nimf_service_ic_focus_in (NimfServiceIC *ic)
{
g_return_if_fail (ic != NULL);
g_debug (G_STRLOC ": %s", G_STRFUNC);
if (G_UNLIKELY (ic->priv->engine == NULL))
return;
NimfServer *server = nimf_server_get_default ();
nimf_engine_focus_in (ic->priv->engine, ic);
server->priv->last_focused_im = ic;
server->priv->last_focused_service = nimf_service_ic_get_service_id (ic);
nimf_service_ic_engine_changed (ic, nimf_engine_get_id (ic->priv->engine),
nimf_engine_get_icon_name (ic->priv->engine));
}
/**
* nimf_service_ic_focus_out:
* @ic: a #NimfServiceIC
*/
void
nimf_service_ic_focus_out (NimfServiceIC *ic)
{
g_return_if_fail (ic != NULL);
g_debug (G_STRLOC ": %s", G_STRFUNC);
if (G_UNLIKELY (ic->priv->engine == NULL))
return;
NimfServer *server = nimf_server_get_default ();
nimf_engine_focus_out (ic->priv->engine, ic);
if (server->priv->last_focused_im == ic)
nimf_service_ic_engine_changed (ic, NULL, "nimf-focus-out");
nimf_preeditable_hide (server->priv->preeditable);
}
static gint
on_comparing_engine_with_id (NimfEngine *engine, const gchar *id)
{
g_debug (G_STRLOC ": %s", G_STRFUNC);
return g_strcmp0 (nimf_engine_get_id (engine), id);
}
static GList *
nimf_service_ic_load_engines (NimfServiceIC *ic)
{
g_debug (G_STRLOC ": %s", G_STRFUNC);
GList *engines = NULL;
NimfServer *server;
GList *l;
server = nimf_server_get_default ();
for (l = server->priv->engines; l != NULL; l = l->next)
{
NimfModule *module;
const gchar *engine_id;
engine_id = nimf_engine_get_id (NIMF_ENGINE (l->data));
module = g_hash_table_lookup (server->priv->modules, engine_id);
engines = g_list_prepend (engines, g_object_new (module->type, NULL));
}
return engines;
}
static NimfEngine *
nimf_service_ic_get_engine_by_id (NimfServiceIC *ic, const gchar *engine_id)
{
g_debug (G_STRLOC ": %s", G_STRFUNC);
GList *list;
if (ic->priv->engines == NULL)
ic->priv->engines = nimf_service_ic_load_engines (ic);
list = g_list_find_custom (ic->priv->engines, engine_id,
(GCompareFunc) on_comparing_engine_with_id);
if (list)
return list->data;
return NULL;
}
static NimfEngine *
nimf_service_ic_get_next_engine (NimfServiceIC *ic, NimfEngine *engine)
{
g_debug (G_STRLOC ": %s", G_STRFUNC);
GList *list;
if (ic->priv->engines == NULL)
ic->priv->engines = nimf_service_ic_load_engines (ic);
list = g_list_find (ic->priv->engines, engine);
if (list == NULL)
list = g_list_find_custom (ic->priv->engines, nimf_engine_get_id (engine),
(GCompareFunc) on_comparing_engine_with_id);
list = g_list_next (list);
if (list == NULL)
list = ic->priv->engines;
return list->data;
}
/**
* nimf_service_ic_filter_event:
* @ic: a #NimfServiceIC
* @event: a #NimfEvent
*
* Returns: TRUE if the event is consumed.
*/
gboolean
nimf_service_ic_filter_event (NimfServiceIC *ic,
NimfEvent *event)
{
g_debug (G_STRLOC ": %s", G_STRFUNC);
g_return_val_if_fail (ic != NULL, FALSE);
if (G_UNLIKELY (ic->priv->engine == NULL))
return FALSE;
GHashTableIter iter;
NimfShortcut *shortcut;
gpointer engine_id;
const gchar *engine_id0 = nimf_engine_get_id (ic->priv->engine);
NimfServer *server = nimf_server_get_default ();
g_hash_table_iter_init (&iter, server->priv->shortcuts);
while (g_hash_table_iter_next (&iter, &engine_id, (gpointer) &shortcut))
{
if ((shortcut->to_lang &&
nimf_event_matches (event, (const NimfKey **) shortcut->to_lang) &&
g_strcmp0 (engine_id0, engine_id)))
{
if (event->key.type == NIMF_EVENT_KEY_PRESS)
{
nimf_service_ic_reset (ic);
nimf_service_ic_change_engine_by_id (ic, engine_id);
}
if (event->key.keyval == NIMF_KEY_Escape)
return FALSE;
return TRUE;
}
if ((shortcut->to_sys &&
nimf_event_matches (event, (const NimfKey **) shortcut->to_sys) &&
!g_strcmp0 (engine_id0, engine_id)))
{
if (event->key.type == NIMF_EVENT_KEY_PRESS)
{
nimf_service_ic_reset (ic);
nimf_service_ic_change_engine_by_id (ic, "nimf-system-keyboard");
}
if (event->key.keyval == NIMF_KEY_Escape)
return FALSE;
return TRUE;
}
}
if (nimf_event_matches (event, (const NimfKey **) server->priv->hotkeys))
{
if (event->key.type == NIMF_EVENT_KEY_PRESS)
{
nimf_service_ic_reset (ic);
if (server->priv->use_singleton)
ic->priv->engine = nimf_server_get_next_engine (server, ic->priv->engine);
else
ic->priv->engine = nimf_service_ic_get_next_engine (ic, ic->priv->engine);
nimf_service_ic_engine_changed (ic, nimf_engine_get_id (ic->priv->engine),
nimf_engine_get_icon_name (ic->priv->engine));
}
return TRUE;
}
return nimf_engine_filter_event (ic->priv->engine, ic, event);
}
/**
* nimf_service_ic_set_surrounding:
* @ic: a #NimfServiceIC
* @text: text
* @len: length
* @cursor_index: cursor index
*/
void
nimf_service_ic_set_surrounding (NimfServiceIC *ic,
const char *text,
gint len,
gint cursor_index)
{
g_debug (G_STRLOC ": %s", G_STRFUNC);
g_return_if_fail (ic != NULL);
if (G_UNLIKELY (ic->priv->engine == NULL))
return;
nimf_engine_set_surrounding (ic->priv->engine, text, len, cursor_index);
}
/**
* nimf_service_ic_set_use_preedit:
* @ic: a #NimfServiceIC
* @use_preedit: whether the input method should use an on-the-spot input style
*
* If @use_preedit is %FALSE (default is %TRUE), then the input method may use
* some other input styles, such as over-the-spot, off-the-spot or root-window.
*/
void
nimf_service_ic_set_use_preedit (NimfServiceIC *ic,
gboolean use_preedit)
{
g_debug (G_STRLOC ": %s: %d", G_STRFUNC, use_preedit);
g_return_if_fail (ic != NULL);
if (ic->priv->use_preedit == TRUE && use_preedit == FALSE)
{
ic->priv->use_preedit = FALSE;
if (ic->priv->preedit_state == NIMF_PREEDIT_STATE_START)
{
nimf_service_ic_emit_preedit_changed (ic, ic->priv->preedit_string,
ic->priv->preedit_attrs,
ic->priv->preedit_cursor_pos);
nimf_service_ic_emit_preedit_end (ic);
}
}
else if (ic->priv->use_preedit == FALSE && use_preedit == TRUE)
{
ic->priv->use_preedit = TRUE;
if (ic->priv->preedit_string[0] != 0)
{
nimf_service_ic_emit_preedit_start (ic);
nimf_service_ic_emit_preedit_changed (ic, ic->priv->preedit_string,
ic->priv->preedit_attrs,
ic->priv->preedit_cursor_pos);
}
}
}
/**
* nimf_service_ic_get_use_preedit:
* @ic: a #NimfServiceIC
*
* Returns: TRUE if an on-the-spot input style is used
*/
gboolean
nimf_service_ic_get_use_preedit (NimfServiceIC *ic)
{
g_debug (G_STRLOC ": %s", G_STRFUNC);
return ic->priv->use_preedit;
}
/**
* nimf_service_ic_set_cursor_location:
* @ic: a #NimfServiceIC
* @area: a #NimfRectangle
*
* Notifies the service @ic that a change in cursor position has been made. The
* location is the position of a window position in root window coordinates.
*/
void
nimf_service_ic_set_cursor_location (NimfServiceIC *ic,
const NimfRectangle *area)
{
g_debug (G_STRLOC ": %s", G_STRFUNC);
g_return_if_fail (ic != NULL);
if (G_UNLIKELY (ic->priv->engine == NULL))
return;
NimfServer *server = nimf_server_get_default ();
*ic->priv->cursor_area = *area;
if (!ic->priv->use_preedit)
nimf_preeditable_set_cursor_location (server->priv->preeditable, area);
}
/**
* nimf_service_ic_get_cursor_location:
* @ic: a #NimfServiceIC
*
* Returns: (transfer none): a #NimfRectangle
*/
const NimfRectangle *
nimf_service_ic_get_cursor_location (NimfServiceIC *ic)
{
g_debug (G_STRLOC ": %s", G_STRFUNC);
return ic->priv->cursor_area;
}
/**
* nimf_service_ic_reset:
* @ic: a #NimfServiceIC
*/
void
nimf_service_ic_reset (NimfServiceIC *ic)
{
g_debug (G_STRLOC ": %s", G_STRFUNC);
g_return_if_fail (ic != NULL);
if (G_LIKELY (ic->priv->engine))
nimf_engine_reset (ic->priv->engine, ic);
}
/**
* nimf_service_ic_change_engine_by_id:
* @ic: a #NimfServiceIC
* @engine_id: engine id
*
* Changes the engine by engine id.
*/
void
nimf_service_ic_change_engine_by_id (NimfServiceIC *ic,
const gchar *engine_id)
{
g_debug (G_STRLOC ": %s", G_STRFUNC);
NimfEngine *engine;
NimfServer *server = nimf_server_get_default ();
if (server->priv->use_singleton)
engine = nimf_server_get_engine_by_id (server, engine_id);
else
engine = nimf_service_ic_get_engine_by_id (ic, engine_id);
g_return_if_fail (engine != NULL);
ic->priv->engine = engine;
nimf_service_ic_engine_changed (ic, engine_id,
nimf_engine_get_icon_name (ic->priv->engine));
}
/**
* nimf_service_ic_change_engine:
* @ic: a #NimfServiceIC
* @engine_id: engine id
* @method_id: method id
*
* Changes the engine by engine id and method id.
*/
void
nimf_service_ic_change_engine (NimfServiceIC *ic,
const gchar *engine_id,
const gchar *method_id)
{
g_debug (G_STRLOC ": %s", G_STRFUNC);
NimfEngine *engine;
NimfServer *server = nimf_server_get_default ();
if (server->priv->use_singleton)
engine = nimf_server_get_engine_by_id (server, engine_id);
else
engine = nimf_service_ic_get_engine_by_id (ic, engine_id);
g_return_if_fail (engine != NULL);
ic->priv->engine = engine;
nimf_engine_set_method (engine, method_id);
nimf_service_ic_engine_changed (ic, engine_id,
nimf_engine_get_icon_name (ic->priv->engine));
}
/**
* nimf_service_ic_get_service_id:
* @ic: a #NimfServiceIC
*
* Returns: (transfer none): a service id
*/
const gchar *
nimf_service_ic_get_service_id (NimfServiceIC *ic)
{
g_debug (G_STRLOC ": %s", G_STRFUNC);
NimfServiceICClass *class = NIMF_SERVICE_IC_GET_CLASS (ic);
if (class->get_service_id)
{
return class->get_service_id (ic);
}
else
{
g_critical (G_STRLOC ": %s: You should implement your_get_service_id ()",
G_STRFUNC);
return NULL;
}
}
/**
* nimf_service_ic_get_engine:
* @ic: a #NimfServiceIC
*
* Returns the associated #NimfEngine instance.
*
* Returns: (transfer none): the engine instance
*/
NimfEngine *
nimf_service_ic_get_engine (NimfServiceIC *ic)
{
g_debug (G_STRLOC ": %s", G_STRFUNC);
return ic->priv->engine;
}
static NimfEngine *
nimf_service_ic_get_default_engine (NimfServiceIC *ic)
{
g_debug (G_STRLOC ": %s", G_STRFUNC);
GSettings *settings;
gchar *engine_id;
NimfEngine *engine;
settings = g_settings_new ("org.nimf.engines");
engine_id = g_settings_get_string (settings, "default-engine");
engine = nimf_service_ic_get_engine_by_id (ic, engine_id);
if (G_UNLIKELY (engine == NULL))
{
g_settings_reset (settings, "default-engine");
g_free (engine_id);
engine_id = g_settings_get_string (settings, "default-engine");
engine = nimf_service_ic_get_engine_by_id (ic, engine_id);
}
g_free (engine_id);
g_object_unref (settings);
return engine;
}
static void
nimf_service_ic_init (NimfServiceIC *ic)
{
g_debug (G_STRLOC ": %s", G_STRFUNC);
ic->priv = nimf_service_ic_get_instance_private (ic);
ic->priv->cursor_area = g_slice_new0 (NimfRectangle);
}
void
nimf_service_ic_load_engine (NimfServiceIC *ic,
const gchar *engine_id,
NimfServer *server)
{
g_debug (G_STRLOC ": %s", G_STRFUNC);
if (ic->priv->engines)
{
if (server->priv->use_singleton)
{
NimfServer *server = nimf_server_get_default ();
if (g_list_find (server->priv->engines, ic->priv->engine) == NULL)
{
const gchar *id = nimf_engine_get_id (ic->priv->engine);
ic->priv->engine = nimf_server_get_engine_by_id (server, id);
}
g_list_free_full (ic->priv->engines, g_object_unref);
ic->priv->engines = NULL;
}
else
{
NimfModule *module;
NimfEngine *engine;
module = g_hash_table_lookup (server->priv->modules, engine_id);
engine = g_object_new (module->type, NULL);
ic->priv->engines = g_list_prepend (ic->priv->engines, engine);
}
}
}
void
nimf_service_ic_unload_engine (NimfServiceIC *ic,
const gchar *engine_id,
NimfEngine *signleton_engine_to_be_deleted,
NimfServer *server)
{
g_debug (G_STRLOC ": %s", G_STRFUNC);
if (ic->priv->engines)
{
GList *list;
list = g_list_find_custom (ic->priv->engines, engine_id,
(GCompareFunc) on_comparing_engine_with_id);
if (list)
{
if (ic->priv->engine == list->data)
{
if (server->priv->use_singleton)
ic->priv->engine = nimf_server_get_default_engine (server);
else
ic->priv->engine = nimf_service_ic_get_default_engine (ic);
}
g_object_unref (list->data);
ic->priv->engines = g_list_delete_link (ic->priv->engines, list);
}
}
else
{
if (ic->priv->engine == signleton_engine_to_be_deleted)
{
if (server->priv->use_singleton)
ic->priv->engine = nimf_server_get_default_engine (server);
else
ic->priv->engine = nimf_service_ic_get_default_engine (ic);
}
}
}
static void
nimf_service_ic_constructed (GObject *object)
{
g_debug (G_STRLOC ": %s", G_STRFUNC);
NimfServiceIC *ic = NIMF_SERVICE_IC (object);
NimfServer *server = nimf_server_get_default ();
ic->priv->use_preedit = TRUE;
ic->priv->preedit_state = NIMF_PREEDIT_STATE_END;
if (server->priv->use_singleton)
{
ic->priv->engine = nimf_server_get_default_engine (server);
}
else
{
ic->priv->engines = nimf_service_ic_load_engines (ic);
ic->priv->engine = nimf_service_ic_get_default_engine (ic);
}
ic->priv->preedit_string = g_strdup ("");
ic->priv->preedit_attrs = g_malloc0_n (1, sizeof (NimfPreeditAttr *));
ic->priv->preedit_attrs[0] = NULL;
ic->priv->preedit_cursor_pos = 0;
g_ptr_array_add (server->priv->ics, ic);
}
static void
nimf_service_ic_finalize (GObject *object)
{
g_debug (G_STRLOC ": %s", G_STRFUNC);
NimfServiceIC *ic = NIMF_SERVICE_IC (object);
NimfServer *server = nimf_server_get_default ();
g_ptr_array_remove_fast (server->priv->ics, ic);
if (ic->priv->engines)
g_list_free_full (ic->priv->engines, g_object_unref);
g_free (ic->priv->preedit_string);
nimf_preedit_attr_freev (ic->priv->preedit_attrs);
g_slice_free (NimfRectangle, ic->priv->cursor_area);
G_OBJECT_CLASS (nimf_service_ic_parent_class)->finalize (object);
}
static void
nimf_service_ic_class_init (NimfServiceICClass *class)
{
g_debug (G_STRLOC ": %s", G_STRFUNC);
GObjectClass *object_class = G_OBJECT_CLASS (class);
object_class->finalize = nimf_service_ic_finalize;
object_class->constructed = nimf_service_ic_constructed;
}

View File

@@ -0,0 +1,119 @@
/* -*- Mode: C; indent-tabs-mode: nil; c-basic-offset: 2; tab-width: 2 -*- */
/*
* nimf-service-ic.h
* This file is part of Nimf.
*
* Copyright (C) 2015-2019 Hodong Kim <cogniti@gmail.com>
*
* Nimf is free software: you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published
* by the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Nimf is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __NIMF_SERVICE_IC_H__
#define __NIMF_SERVICE_IC_H__
#include <glib.h>
#include "nimf-types.h"
#include "nimf-events.h"
#include "nimf-engine.h"
G_BEGIN_DECLS
#define NIMF_TYPE_SERVICE_IC (nimf_service_ic_get_type ())
#define NIMF_SERVICE_IC(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NIMF_TYPE_SERVICE_IC, NimfServiceIC))
#define NIMF_SERVICE_IC_CLASS(class) (G_TYPE_CHECK_CLASS_CAST ((class), NIMF_TYPE_SERVICE_IC, NimfServiceICClass))
#define NIMF_IS_SERVICE_IC(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NIMF_TYPE_SERVICE_IC))
#define NIMF_SERVICE_IC_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), NIMF_TYPE_SERVICE_IC, NimfServiceICClass))
#ifndef __GTK_DOC_IGNORE__
typedef struct _NimfEngine NimfEngine;
#endif
typedef struct _NimfServiceIC NimfServiceIC;
typedef struct _NimfServiceICClass NimfServiceICClass;
typedef struct _NimfServiceICPrivate NimfServiceICPrivate;
struct _NimfServiceICClass
{
/*< private >*/
GObjectClass parent_class;
/*< public >*/
/* Virtual functions */
const gchar * (* get_service_id) (NimfServiceIC *ic);
void (* emit_commit) (NimfServiceIC *ic,
const gchar *text);
void (* emit_preedit_start) (NimfServiceIC *ic);
void (* emit_preedit_changed) (NimfServiceIC *ic,
const gchar *preedit_string,
NimfPreeditAttr **attrs,
gint cursor_pos);
void (* emit_preedit_end) (NimfServiceIC *ic);
gboolean (* emit_retrieve_surrounding) (NimfServiceIC *ic);
gboolean (* emit_delete_surrounding) (NimfServiceIC *ic,
gint offset,
gint n_chars);
void (* emit_beep) (NimfServiceIC *ic);
};
struct _NimfServiceIC
{
GObject parent_instance;
NimfServiceICPrivate *priv;
};
GType nimf_service_ic_get_type (void) G_GNUC_CONST;
void nimf_service_ic_focus_in (NimfServiceIC *ic);
void nimf_service_ic_focus_out (NimfServiceIC *ic);
gboolean nimf_service_ic_filter_event (NimfServiceIC *ic,
NimfEvent *event);
void nimf_service_ic_set_surrounding (NimfServiceIC *ic,
const char *text,
gint len,
gint cursor_index);
void nimf_service_ic_set_use_preedit (NimfServiceIC *ic,
gboolean use_preedit);
gboolean nimf_service_ic_get_use_preedit (NimfServiceIC *ic);
void nimf_service_ic_set_cursor_location (NimfServiceIC *ic,
const NimfRectangle *area);
const NimfRectangle *
nimf_service_ic_get_cursor_location (NimfServiceIC *ic);
void nimf_service_ic_reset (NimfServiceIC *ic);
void nimf_service_ic_change_engine_by_id (NimfServiceIC *ic,
const gchar *engine_id);
void nimf_service_ic_change_engine (NimfServiceIC *ic,
const gchar *engine_id,
const gchar *method_id);
void nimf_service_ic_engine_changed (NimfServiceIC *ic,
const gchar *engine_id,
const gchar *name);
NimfEngine *nimf_service_ic_get_engine (NimfServiceIC *ic);
const gchar *nimf_service_ic_get_service_id (NimfServiceIC *ic);
/* signals */
void nimf_service_ic_emit_preedit_start (NimfServiceIC *ic);
void nimf_service_ic_emit_preedit_changed (NimfServiceIC *ic,
const gchar *preedit_string,
NimfPreeditAttr **attrs,
gint cursor_pos);
void nimf_service_ic_emit_preedit_end (NimfServiceIC *ic);
void nimf_service_ic_emit_commit (NimfServiceIC *ic,
const gchar *text);
gboolean nimf_service_ic_emit_retrieve_surrounding (NimfServiceIC *ic);
gboolean nimf_service_ic_emit_delete_surrounding (NimfServiceIC *ic,
gint offset,
gint n_chars);
void nimf_service_ic_emit_beep (NimfServiceIC *ic);
G_END_DECLS
#endif /* __NIMF_SERVICE_IC_H__ */

View File

@@ -0,0 +1,172 @@
/* -*- Mode: C; indent-tabs-mode: nil; c-basic-offset: 2; tab-width: 2 -*- */
/*
* nimf-service.c
* This file is part of Nimf.
*
* Copyright (C) 2017-2019 Hodong Kim <cogniti@gmail.com>
*
* Nimf is free software: you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published
* by the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Nimf is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; If not, see <http://www.gnu.org/licenses/>.
*/
#include "nimf-service.h"
G_DEFINE_ABSTRACT_TYPE (NimfService, nimf_service, G_TYPE_OBJECT);
enum
{
PROP_0,
PROP_SERVER
};
static void
nimf_service_init (NimfService *service)
{
g_debug (G_STRLOC ": %s", G_STRFUNC);
}
static void
nimf_service_finalize (GObject *object)
{
g_debug (G_STRLOC ": %s", G_STRFUNC);
G_OBJECT_CLASS (nimf_service_parent_class)->finalize (object);
}
/**
* nimf_service_get_id:
* @service: a #NimfService
*
* Gets the ID of a @service.
*
* Returns: the ID of a service
*/
const gchar *
nimf_service_get_id (NimfService *service)
{
g_debug (G_STRLOC ": %s", G_STRFUNC);
NimfServiceClass *class = NIMF_SERVICE_GET_CLASS (service);
if (class->get_id (service))
return class->get_id (service);
else
g_error (G_STRLOC ": %s: You should implement your_service_get_id ()",
G_STRFUNC);
return NULL;
}
/**
* nimf_service_start:
* @service: a #NimfService
*
* Starts @service.
*
* Returns: %TRUE if a service is started.
*/
gboolean
nimf_service_start (NimfService *service)
{
g_debug (G_STRLOC ": %s", G_STRFUNC);
NimfServiceClass *class = NIMF_SERVICE_GET_CLASS (service);
if (class->start)
return class->start (service);
else
return FALSE;
}
/**
* nimf_service_stop:
* @service: a #NimfService
*
* Stops a @service.
*/
void
nimf_service_stop (NimfService *service)
{
g_debug (G_STRLOC ": %s", G_STRFUNC);
NimfServiceClass *class = NIMF_SERVICE_GET_CLASS (service);
if (class->stop)
class->stop (service);
}
/**
* nimf_service_is_active:
* @service: a #NimfService
*
* Returns: %TRUE if a service is active
*/
gboolean
nimf_service_is_active (NimfService *service)
{
g_debug (G_STRLOC ": %s", G_STRFUNC);
NimfServiceClass *class = NIMF_SERVICE_GET_CLASS (service);
if (class->is_active (service))
return class->is_active (service);
else
g_error (G_STRLOC ": %s: You should implement your_service_is_active ()",
G_STRFUNC);
return FALSE;
}
/**
* nimf_service_change_engine_by_id:
* @service: a #NimfService
* @engine_id: engine id
*/
void
nimf_service_change_engine_by_id (NimfService *service,
const gchar *engine_id)
{
g_debug (G_STRLOC ": %s", G_STRFUNC);
NimfServiceClass *class = NIMF_SERVICE_GET_CLASS (service);
if (class->change_engine_by_id)
class->change_engine_by_id (service, engine_id);
}
/**
* nimf_service_change_engine:
* @service: a #NimfService
* @engine_id: engine id
* @method_id: method id
*/
void
nimf_service_change_engine (NimfService *service,
const gchar *engine_id,
const gchar *method_id)
{
g_debug (G_STRLOC ": %s", G_STRFUNC);
NimfServiceClass *class = NIMF_SERVICE_GET_CLASS (service);
if (class->change_engine_by_id)
class->change_engine (service, engine_id, method_id);
}
static void
nimf_service_class_init (NimfServiceClass *class)
{
g_debug (G_STRLOC ": %s", G_STRFUNC);
G_OBJECT_CLASS (class)->finalize = nimf_service_finalize;
}

View File

@@ -0,0 +1,87 @@
/* -*- Mode: C; indent-tabs-mode: nil; c-basic-offset: 2; tab-width: 2 -*- */
/*
* nimf-service.h
* This file is part of Nimf.
*
* Copyright (C) 2017-2019 Hodong Kim <cogniti@gmail.com>
*
* Nimf is free software: you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published
* by the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Nimf is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __NIMF_SERVICE_H__
#define __NIMF_SERVICE_H__
#if !defined (__NIMF_H_INSIDE__) && !defined (NIMF_COMPILATION)
#error "Only <nimf.h> can be included directly."
#endif
#include <glib-object.h>
G_BEGIN_DECLS
#define NIMF_TYPE_SERVICE (nimf_service_get_type ())
#define NIMF_SERVICE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NIMF_TYPE_SERVICE, NimfService))
#define NIMF_SERVICE_CLASS(class) (G_TYPE_CHECK_CLASS_CAST ((class), NIMF_TYPE_SERVICE, NimfServiceClass))
#define NIMF_IS_SERVICE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NIMF_TYPE_SERVICE))
#define NIMF_SERVICE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), NIMF_TYPE_SERVICE, NimfServiceClass))
typedef struct _NimfService NimfService;
typedef struct _NimfServiceClass NimfServiceClass;
struct _NimfService
{
GObject parent_instance;
};
/**
* NimfServiceClass:
* @get_id: Returns a service id.
* @start: Starts a service.
* @stop: Stops a service.
* @is_active: Whether a service is active or not
* @change_engine_by_id: Changes an engine by engine id.
* @change_engine: Changes an engine with engine id and method id.
*/
struct _NimfServiceClass
{
/*< private >*/
GObjectClass parent_class;
/*< public >*/
/* Virtual functions */
const gchar * (* get_id) (NimfService *service);
gboolean (* start) (NimfService *service);
void (* stop) (NimfService *service);
gboolean (* is_active) (NimfService *service);
void (* change_engine_by_id) (NimfService *service,
const gchar *engine_id);
void (* change_engine) (NimfService *service,
const gchar *engine_id,
const gchar *method_id);
};
GType nimf_service_get_type (void) G_GNUC_CONST;
gboolean nimf_service_start (NimfService *service);
void nimf_service_stop (NimfService *service);
gboolean nimf_service_is_active (NimfService *service);
const gchar *nimf_service_get_id (NimfService *service);
void nimf_service_change_engine_by_id (NimfService *service,
const gchar *engine_id);
void nimf_service_change_engine (NimfService *service,
const gchar *engine_id,
const gchar *method_id);
G_END_DECLS
#endif /* __NIMF_SERVICE_H__ */

View File

@@ -0,0 +1,297 @@
/* -*- Mode: C; indent-tabs-mode: nil; c-basic-offset: 2; tab-width: 2 -*- */
/*
* nimf-types.c
* This file is part of Nimf.
*
* Copyright (C) 2015-2019 Hodong Kim <cogniti@gmail.com>
*
* Nimf is free software: you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published
* by the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Nimf is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; If not, see <http://www.gnu.org/licenses/>.
*/
#include "nimf-types.h"
#include "nimf-enum-types-private.h"
/**
* SECTION:nimf-types
* @title: Types
* @section_id: nimf-types
*/
/**
* nimf_key_new:
*
* Creates a new #NimfKey. All fields are set to 0.
*
* Return: a new #NimfKey, which should be freed with nimf_key_free().
*/
NimfKey *
nimf_key_new ()
{
g_debug (G_STRLOC ": %s", G_STRFUNC);
return g_slice_new0 (NimfKey);
}
/**
* nimf_key_new_from_nicks:
* @nicks: an array of gchar
*
* Return: a new #NimfKey, which should be freed with nimf_key_free().
*/
NimfKey *
nimf_key_new_from_nicks (const gchar **nicks)
{
g_debug (G_STRLOC ": %s", G_STRFUNC);
NimfKey *key = g_slice_new0 (NimfKey);
GEnumValue *enum_value; /* Do not free */
GFlagsValue *flags_value; /* Do not free */
GFlagsClass *flags_class = g_type_class_ref (NIMF_TYPE_MODIFIER_TYPE);
GEnumClass *enum_class = g_type_class_ref (NIMF_TYPE_KEY_SYM);
gint i;
for (i = 0; nicks[i] != NULL; i++)
{
if (g_str_has_prefix (nicks[i], "<"))
{
flags_value = g_flags_get_value_by_nick (flags_class, nicks[i]);
if (flags_value)
key->state |= flags_value->value;
else
g_warning ("NimfModifierType doesn't have a member with that nickname: %s", nicks[i]);
}
else
{
enum_value = g_enum_get_value_by_nick (enum_class, nicks[i]);
if (enum_value)
key->keyval = enum_value->value;
else
g_warning ("NimfKeySym doesn't have a member with that nickname: %s", nicks[i]);
}
}
g_type_class_unref (flags_class);
g_type_class_unref (enum_class);
return key;
}
/**
* nimf_key_newv:
* @keys: an array of gchar
*
* Creates a new array of #NimfKey.
*
* Returns: a new array of #NimfKey, which should be freed with
* nimf_key_freev().
*/
NimfKey **
nimf_key_newv (const gchar **keys)
{
NimfKey **nimf_keys = g_malloc0_n (1, sizeof (NimfKey *));
gint i;
for (i = 0; keys[i] != NULL; i++)
{
gchar **nicks = g_strsplit (keys[i], " ", -1);
NimfKey *key = nimf_key_new_from_nicks ((const gchar **) nicks);
g_strfreev (nicks);
nimf_keys = g_realloc_n (nimf_keys, sizeof (NimfKey *), i + 2);
nimf_keys[i] = key;
nimf_keys[i + 1] = NULL;
}
return nimf_keys;
}
/**
* nimf_key_freev:
* @keys: an array of #NimfKey
*
* Frees an array of @keys
*/
void
nimf_key_freev (NimfKey **keys)
{
g_debug (G_STRLOC ": %s", G_STRFUNC);
if (keys)
{
int i;
for (i = 0; keys[i] != NULL; i++)
nimf_key_free (keys[i]);
g_free (keys);
}
}
/**
* nimf_key_free:
* @key: a #NimfKey
*
* Frees a @key
*/
void
nimf_key_free (NimfKey *key)
{
g_debug (G_STRLOC ": %s", G_STRFUNC);
g_return_if_fail (key != NULL);
g_slice_free (NimfKey, key);
}
/**
* nimf_preedit_attr_new:
* @type: a #NimfPreeditAttrType
* @start_index: start index in characters
* @end_index: end index in characters; The character at this index is not
* included.
*
* Returns: a new #NimfPreeditAttr, which should be freed with
* nimf_preedit_attr_free().
*/
NimfPreeditAttr *
nimf_preedit_attr_new (NimfPreeditAttrType type,
guint start_index,
guint end_index)
{
g_debug (G_STRLOC ": %s", G_STRFUNC);
NimfPreeditAttr *attr;
attr = g_new (NimfPreeditAttr, 1);
attr->type = type;
attr->start_index = start_index;
attr->end_index = end_index;
return attr;
}
/**
* nimf_preedit_attrs_copy:
* @attrs: an array of #NimfPreeditAttr
*
* Returns: a new array of #NimfPreeditAttr, which should be freed with
* nimf_preedit_attr_freev().
*/
NimfPreeditAttr **
nimf_preedit_attrs_copy (NimfPreeditAttr **attrs)
{
g_debug (G_STRLOC ": %s", G_STRFUNC);
NimfPreeditAttr **preedit_attrs;
gint i;
g_return_val_if_fail (attrs, NULL);
preedit_attrs = g_malloc0_n (1, sizeof (NimfPreeditAttr *));
for (i = 0; attrs[i] != NULL; i++)
{
preedit_attrs = g_realloc_n (preedit_attrs, 1 + i + 1, sizeof (NimfPreeditAttr *));
preedit_attrs[i] = g_memdup (attrs[i], sizeof (NimfPreeditAttr));
preedit_attrs[i + 1] = NULL;
}
return preedit_attrs;
}
/**
* nimf_preedit_attr_free:
* @attr: a #NimfPreeditAttr
*
* Frees a @attr
*/
void
nimf_preedit_attr_free (NimfPreeditAttr *attr)
{
g_debug (G_STRLOC ": %s", G_STRFUNC);
g_free (attr);
}
/**
* nimf_preedit_attr_freev:
* @attrs: an array of #NimfPreeditAttr
*
* Frees an array of @attrs
*/
void
nimf_preedit_attr_freev (NimfPreeditAttr **attrs)
{
g_debug (G_STRLOC ": %s", G_STRFUNC);
if (attrs)
{
int i;
for (i = 0; attrs[i] != NULL; i++)
nimf_preedit_attr_free (attrs[i]);
g_free (attrs);
}
}
/**
* nimf_method_info_new:
*
* Returns: a new #NimfMethodInfo, which should be freed with
* nimf_method_info_free().
*/
NimfMethodInfo *
nimf_method_info_new ()
{
g_debug (G_STRLOC ": %s", G_STRFUNC);
return g_slice_new0 (NimfMethodInfo);
}
/**
* nimf_method_info_free:
* @info: a #NimfMethodInfo
*
* Frees an @info.
*/
void
nimf_method_info_free (NimfMethodInfo *info)
{
g_debug (G_STRLOC ": %s", G_STRFUNC);
if (info)
g_slice_free (NimfMethodInfo, info);
}
/**
* nimf_method_info_freev:
* @infos: an array of #NimfMethodInfo
*
* Frees an array of @infos.
*/
void
nimf_method_info_freev (NimfMethodInfo **infos)
{
g_debug (G_STRLOC ": %s", G_STRFUNC);
if (infos)
{
int i;
for (i = 0; infos[i]; i++)
nimf_method_info_free (infos[i]);
g_free (infos);
}
}

View File

@@ -0,0 +1,210 @@
/* -*- Mode: C; indent-tabs-mode: nil; c-basic-offset: 2; tab-width: 2 -*- */
/*
* nimf-types.h
* This file is part of Nimf.
*
* Copyright (C) 2015-2019 Hodong Kim <cogniti@gmail.com>
*
* Nimf is free software: you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published
* by the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Nimf is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __NIMF_TYPES_H__
#define __NIMF_TYPES_H__
#include <glib-object.h>
G_BEGIN_DECLS
/* copied from GdkModifierType in gdktypes.h for compatibility */
/**
* NimfModifierType:
* @NIMF_SHIFT_MASK: the Shift key.
* @NIMF_LOCK_MASK: a Lock key (depending on the modifier mapping of the
* X server this may either be CapsLock or ShiftLock).
* @NIMF_CONTROL_MASK: the Control key.
* @NIMF_MOD1_MASK: the fourth modifier key (it depends on the modifier
* mapping of the X server which key is interpreted as this modifier, but
* normally it is the Alt key).
* @NIMF_MOD2_MASK: the fifth modifier key (it depends on the modifier
* mapping of the X server which key is interpreted as this modifier).
* @NIMF_MOD3_MASK: the sixth modifier key (it depends on the modifier
* mapping of the X server which key is interpreted as this modifier).
* @NIMF_MOD4_MASK: the seventh modifier key (it depends on the modifier
* mapping of the X server which key is interpreted as this modifier).
* @NIMF_MOD5_MASK: the eighth modifier key (it depends on the modifier
* mapping of the X server which key is interpreted as this modifier).
* @NIMF_BUTTON1_MASK: the first mouse button.
* @NIMF_BUTTON2_MASK: the second mouse button.
* @NIMF_BUTTON3_MASK: the third mouse button.
* @NIMF_BUTTON4_MASK: the fourth mouse button.
* @NIMF_BUTTON5_MASK: the fifth mouse button.
* @NIMF_MODIFIER_RESERVED_13_MASK: A reserved bit flag; do not use in your own code
* @NIMF_MODIFIER_RESERVED_14_MASK: A reserved bit flag; do not use in your own code
* @NIMF_MODIFIER_RESERVED_15_MASK: A reserved bit flag; do not use in your own code
* @NIMF_MODIFIER_RESERVED_16_MASK: A reserved bit flag; do not use in your own code
* @NIMF_MODIFIER_RESERVED_17_MASK: A reserved bit flag; do not use in your own code
* @NIMF_MODIFIER_RESERVED_18_MASK: A reserved bit flag; do not use in your own code
* @NIMF_MODIFIER_RESERVED_19_MASK: A reserved bit flag; do not use in your own code
* @NIMF_MODIFIER_RESERVED_20_MASK: A reserved bit flag; do not use in your own code
* @NIMF_MODIFIER_RESERVED_21_MASK: A reserved bit flag; do not use in your own code
* @NIMF_MODIFIER_RESERVED_22_MASK: A reserved bit flag; do not use in your own code
* @NIMF_MODIFIER_RESERVED_23_MASK: A reserved bit flag; do not use in your own code
* @NIMF_MODIFIER_RESERVED_24_MASK: A reserved bit flag; do not use in your own code
* @NIMF_MODIFIER_RESERVED_25_MASK: A reserved bit flag; do not use in your own code
* @NIMF_SUPER_MASK: the Super modifier.
* @NIMF_HYPER_MASK: the Hyper modifier.
* @NIMF_META_MASK: the Meta modifier.
* @NIMF_MODIFIER_RESERVED_29_MASK: A reserved bit flag; do not use in your own code
* @NIMF_RELEASE_MASK: exists because of compatibility.
* @NIMF_MODIFIER_MASK: a mask covering all modifier types.
*
* A set of bit-flags to indicate the state of modifier keys and mouse buttons
* in various event types. Typical modifier keys are Shift, Control, Meta,
* Super, Hyper, Alt, Compose, Apple, CapsLock or ShiftLock.
*/
typedef enum
{
NIMF_SHIFT_MASK = 1 << 0, /*< nick=<Shift> >*/
NIMF_LOCK_MASK = 1 << 1, /*< nick=<Lock> >*/
NIMF_CONTROL_MASK = 1 << 2, /*< nick=<Control> >*/
NIMF_MOD1_MASK = 1 << 3, /*< nick=<Mod1> >*/
NIMF_MOD2_MASK = 1 << 4, /*< nick=<Mod2> >*/
NIMF_MOD3_MASK = 1 << 5, /*< nick=<Mod3> >*/
NIMF_MOD4_MASK = 1 << 6, /*< nick=<Mod4> >*/
NIMF_MOD5_MASK = 1 << 7, /*< nick=<Mod5> >*/
NIMF_BUTTON1_MASK = 1 << 8, /*< nick=<Button1> >*/
NIMF_BUTTON2_MASK = 1 << 9, /*< nick=<Button2> >*/
NIMF_BUTTON3_MASK = 1 << 10, /*< nick=<Button3> >*/
NIMF_BUTTON4_MASK = 1 << 11, /*< nick=<Button4> >*/
NIMF_BUTTON5_MASK = 1 << 12, /*< nick=<Button5> >*/
NIMF_MODIFIER_RESERVED_13_MASK = 1 << 13,
NIMF_MODIFIER_RESERVED_14_MASK = 1 << 14,
NIMF_MODIFIER_RESERVED_15_MASK = 1 << 15,
NIMF_MODIFIER_RESERVED_16_MASK = 1 << 16,
NIMF_MODIFIER_RESERVED_17_MASK = 1 << 17,
NIMF_MODIFIER_RESERVED_18_MASK = 1 << 18,
NIMF_MODIFIER_RESERVED_19_MASK = 1 << 19,
NIMF_MODIFIER_RESERVED_20_MASK = 1 << 20,
NIMF_MODIFIER_RESERVED_21_MASK = 1 << 21,
NIMF_MODIFIER_RESERVED_22_MASK = 1 << 22,
NIMF_MODIFIER_RESERVED_23_MASK = 1 << 23,
NIMF_MODIFIER_RESERVED_24_MASK = 1 << 24,
NIMF_MODIFIER_RESERVED_25_MASK = 1 << 25,
NIMF_SUPER_MASK = 1 << 26, /*< nick=<Super> >*/
NIMF_HYPER_MASK = 1 << 27, /*< nick=<Hyper> >*/
NIMF_META_MASK = 1 << 28, /*< nick=<Meta> >*/
NIMF_MODIFIER_RESERVED_29_MASK = 1 << 29,
NIMF_RELEASE_MASK = 1 << 30, /*< nick=<Release> >*/
/* Combination of NIMF_SHIFT_MASK..NIMF_BUTTON5_MASK + NIMF_SUPER_MASK
+ NIMF_HYPER_MASK + NIMF_META_MASK + NIMF_RELEASE_MASK */
NIMF_MODIFIER_MASK = 0x5c001fff
} NimfModifierType;
/**
* NimfRectangle:
* @x: x
* @y: y
* @width: width
* @height: height
*
* Defines the position and size of a rectangle.
*/
typedef struct {
int x, y;
int width, height;
} NimfRectangle;
/**
* NimfKey:
* @state: a bit-mask representing the state of the modifier keys
* @keyval: the key that was pressed or released.
*/
typedef struct {
guint32 state;
guint32 keyval;
} NimfKey;
/**
* NimfPreeditState:
* @NIMF_PREEDIT_STATE_START: presents preedit-start state.
* @NIMF_PREEDIT_STATE_END: presents preedit-end state.
*/
typedef enum
{
NIMF_PREEDIT_STATE_START = 1,
NIMF_PREEDIT_STATE_END = 0
} NimfPreeditState;
/**
* NimfPreeditAttrType:
* @NIMF_PREEDIT_ATTR_UNDERLINE: whether the text has an underline
* @NIMF_PREEDIT_ATTR_HIGHLIGHT: whether the text has a highlight
*/
typedef enum
{
NIMF_PREEDIT_ATTR_UNDERLINE,
NIMF_PREEDIT_ATTR_HIGHLIGHT
} NimfPreeditAttrType;
/**
* NimfPreeditAttr:
* @type: a #NimfPreeditAttrType
* @start_index: the start index of the range (in characters).
* @end_index: end index of the range (in characters). The character at this
* index is not included in the range.
*/
typedef struct {
NimfPreeditAttrType type;
guint start_index; /* in characters */
guint end_index; /* in characters. The character at this index is not included */
} NimfPreeditAttr;
/**
* NimfMethodInfo:
* @method_id: method id of the engine
* @label: human readable label
* @group: human readable group name
*/
typedef struct
{
gchar *method_id; /* method id */
gchar *label; /* Human readable label */
gchar *group; /* Human readable group name */
} NimfMethodInfo;
NimfKey *nimf_key_new (void);
NimfKey *nimf_key_new_from_nicks (const gchar **nicks);
void nimf_key_free (NimfKey *key);
NimfKey **nimf_key_newv (const gchar **keys);
void nimf_key_freev (NimfKey **keys);
NimfPreeditAttr *nimf_preedit_attr_new (NimfPreeditAttrType type,
guint start_index,
guint end_index);
NimfPreeditAttr **nimf_preedit_attrs_copy (NimfPreeditAttr **attrs);
void nimf_preedit_attr_free (NimfPreeditAttr *attr);
void nimf_preedit_attr_freev (NimfPreeditAttr **attrs);
NimfMethodInfo *nimf_method_info_new (void);
void nimf_method_info_free (NimfMethodInfo *info);
void nimf_method_info_freev (NimfMethodInfo **infos);
G_END_DECLS
#endif /* __NIMF_TYPES_H__ */

View File

@@ -0,0 +1,33 @@
/* -*- Mode: C; indent-tabs-mode: nil; c-basic-offset: 2; tab-width: 2 -*- */
/*
* nimf-utils-private.h
* This file is part of Nimf.
*
* Copyright (C) 2019 Hodong Kim <cogniti@gmail.com>
*
* Nimf is free software: you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published
* by the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Nimf is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __NIMF_UTILS_PRIVATE_H__
#define __NIMF_UTILS_PRIVATE_H__
#include <glib.h>
G_BEGIN_DECLS
gboolean gnome_is_running (void);
gboolean gnome_xkb_is_available (void);
G_END_DECLS
#endif /* __NIMF_UTILS_PRIVATE_H__ */

View File

@@ -0,0 +1,116 @@
/* -*- Mode: C; indent-tabs-mode: nil; c-basic-offset: 2; tab-width: 2 -*- */
/*
* nimf-utils.c
* This file is part of Nimf.
*
* Copyright (C) 2015-2019 Hodong Kim <cogniti@gmail.com>
*
* Nimf is free software: you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published
* by the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Nimf is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; If not, see <http://www.gnu.org/licenses/>.
*/
#include "nimf-utils.h"
#include "nimf-enum-types-private.h"
#include <gio/gio.h>
/**
* SECTION:nimf-utils
* @title: Utility Functions
* @section_id: nimf-utils
*/
/**
* nimf_keyval_to_keysym_name:
* @keyval: a keyval
*
* Returns: keysym name
*/
const gchar *
nimf_keyval_to_keysym_name (guint keyval)
{
GEnumClass *enum_class = (GEnumClass *) g_type_class_ref (NIMF_TYPE_KEY_SYM);
GEnumValue *enum_value = g_enum_get_value (enum_class, keyval);
g_type_class_unref (enum_class);
return enum_value ? enum_value->value_nick : NULL;
}
/**
* nimf_get_socket_path:
*
* Returns: nimf socket path, which should be freed with g_free()
*/
gchar *
nimf_get_socket_path ()
{
g_debug (G_STRLOC ": %s", G_STRFUNC);
return g_strconcat (g_get_user_runtime_dir (), "/nimf/socket", NULL);
}
/* private */
gboolean
gnome_xkb_is_available ()
{
g_debug (G_STRLOC ": %s", G_STRFUNC);
GSettingsSchema *schema;
GSettingsSchemaSource *source = g_settings_schema_source_get_default ();
gboolean retval;
schema = g_settings_schema_source_lookup (source,
"org.gnome.desktop.input-sources",
TRUE);
if (!schema)
return FALSE;
retval = g_settings_schema_has_key (schema, "xkb-options");
g_settings_schema_unref (schema);
return retval;
}
gboolean
gnome_is_running ()
{
g_debug (G_STRLOC ": %s", G_STRFUNC);
const gchar *desktop;
gboolean retval = FALSE;
if ((desktop = g_getenv ("XDG_SESSION_DESKTOP")))
{
gchar *s1;
if ((s1 = g_ascii_strdown (desktop, -1)))
retval = !!g_strrstr (s1, "gnome");
g_free (s1);
}
if (retval)
return TRUE;
if ((desktop = g_getenv ("XDG_CURRENT_DESKTOP")))
{
gchar *s2;
if ((s2 = g_ascii_strdown (desktop, -1)))
retval = !!g_strrstr (s2, "gnome");
g_free (s2);
}
return retval;
}

View File

@@ -0,0 +1,34 @@
/* -*- Mode: C; indent-tabs-mode: nil; c-basic-offset: 2; tab-width: 2 -*- */
/*
* nimf-utils.h
* This file is part of Nimf.
*
* Copyright (C) 2015-2019 Hodong Kim <cogniti@gmail.com>
*
* Nimf is free software: you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published
* by the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Nimf is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __NIMF_UTILS_H__
#define __NIMF_UTILS_H__
#include <glib-object.h>
G_BEGIN_DECLS
const gchar *nimf_keyval_to_keysym_name (guint keyval);
gchar *nimf_get_socket_path (void);
G_END_DECLS
#endif /* __NIMF_UTILS_H__ */

41
Telegram/ThirdParty/nimf/libnimf/nimf.h vendored Normal file
View File

@@ -0,0 +1,41 @@
/* -*- Mode: C; indent-tabs-mode: nil; c-basic-offset: 2; tab-width: 2 -*- */
/*
* nimf.h
* This file is part of Nimf.
*
* Copyright (C) 2015-2019 Hodong Kim <cogniti@gmail.com>
*
* Nimf is free software: you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published
* by the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Nimf is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __NIMF_H__
#define __NIMF_H__
#define __NIMF_H_INSIDE__
#include "nimf-candidatable.h"
#include "nimf-engine.h"
#include "nimf-events.h"
#include "nimf-im.h"
#include "nimf-key-syms.h"
#include "nimf-preeditable.h"
#include "nimf-server.h"
#include "nimf-service.h"
#include "nimf-service-ic.h"
#include "nimf-types.h"
#include "nimf-utils.h"
#undef __NIMF_H_INSIDE__
#endif /* __NIMF_H__ */

View File

@@ -0,0 +1,11 @@
prefix=@prefix@
exec_prefix=@exec_prefix@
libdir=@libdir@
includedir=@includedir@
Name: Nimf
Description: Nimf Input Method Framework Library
Version: @VERSION@
Requires: @LIBNIMF_REQUIRES@
Libs: -L${libdir} -lnimf
Cflags: -I${includedir}/nimf

View File

@@ -0,0 +1,67 @@
<?xml version="1.0" encoding="UTF-8"?>
<schemalist>
<schema id="org.nimf" path="/org/nimf/" gettext-domain="nimf">
<child schema="org.nimf.services" name="services"/>
<child schema="org.nimf.clients" name="clients"/>
<child schema="org.nimf.engines" name="engines"/>
<key type="s" name="hidden-schema-name">
<default l10n="messages">'Nimf'</default>
<summary>schema name for nimf-settings</summary>
<description>This key is intended for nimf-settings.</description>
</key>
<key type="as" name="hotkeys">
<default>['&lt;Control&gt; space']</default>
<summary>Hotkeys for rotating input method engines</summary>
<description>Hotkeys for rotating input method engines</description>
</key>
<key type="as" name="hidden-active-engines">
<default>['']</default>
<summary>active engines</summary>
<description>DO NOT EDIT MANUALLY</description>
</key>
<key type="b" name="use-singleton">
<default>true</default>
<summary>Use singleton mode</summary>
<description>Create one instance per language engine.
Singleton mode reduces memory usage.</description>
</key>
<key type="b" name="setup-environment-variables">
<default>true</default>
<summary>Setup environment variables</summary>
<description>Turning on this option will create a
$HOME/.config/environment.d/50-input.conf link file, and will add
"export $(/usr/lib/systemd/user-environment-generators/30-systemd-environment-d-generator)"
to the .xprofile once, while turning off this option will delete the link file.
Turn off this option to use other input methods such as ibus, fcitx, etc.
When this option is turned on or off, file operations are performed immediately.
But the effect will appear after you login again.
</description>
</key>
</schema>
<schema id="org.nimf.services" path="/org/nimf/services/" gettext-domain="nimf">
<key type="s" name="hidden-schema-name">
<default l10n="messages">'Services'</default>
<summary>schema name for nimf-settings</summary>
<description>This key is intended for nimf-settings.</description>
</key>
</schema>
<schema id="org.nimf.clients" path="/org/nimf/clients/" gettext-domain="nimf">
<key type="s" name="hidden-schema-name">
<default l10n="messages">'Clients'</default>
<summary>schema name for nimf-settings</summary>
<description>This key is intended for nimf-settings.</description>
</key>
</schema>
<schema id="org.nimf.engines" path="/org/nimf/engines/" gettext-domain="nimf">
<key type="s" name="hidden-schema-name">
<default l10n="messages">'Language engines'</default>
<summary>schema name for nimf-settings</summary>
<description>This key is intended for nimf-settings.</description>
</key>
<key type="s" name="default-engine">
<default>'nimf-system-keyboard'</default>
<summary>Default language engine</summary>
<description>Default language engine on startup</description>
</key>
</schema>
</schemalist>