Added Ecore_IMF module.

Added Ecore_IMF module. This module enables different input methods to be
used with Ecore. Input methods modules can be created using the Ecore_IMF
interface.
Added ecore_evas_window_get method to allow input methods to request
the window related to a given Ecore_Evas when available.


SVN revision: 32775
This commit is contained in:
andrunko 2007-11-19 18:27:11 +00:00 committed by andrunko
parent 23d39ab154
commit 502b766d66
20 changed files with 1341 additions and 62 deletions

View File

@ -16,6 +16,7 @@ MAINTAINERCLEANFILES = Makefile.in aclocal.m4 config.guess \
ecore-evas.pc \
ecore-fb.pc \
ecore-file.pc \
ecore-imf.pc \
ecore-ipc.pc \
ecore-job.pc \
ecore-txt.pc \
@ -36,6 +37,7 @@ EXTRA_DIST = AUTHORS COPYING COPYING-PLAIN ecore.c.in gendoc ecore.supp \
ecore-evas.pc.in \
ecore-fb.pc.in \
ecore-file.pc.in \
ecore-imf.pc.in \
ecore-ipc.pc.in \
ecore-job.pc.in \
ecore-txt.pc.in \
@ -73,6 +75,10 @@ if BUILD_ECORE_DESKTOP
pdesktop = ecore-desktop.pc
endif
if BUILD_ECORE_IMF
pimf = ecore-imf.pc
endif
if BUILD_ECORE_IPC
pipc = ecore-ipc.pc
endif
@ -105,5 +111,5 @@ endif
pkgconfigdir = $(libdir)/pkgconfig
pkgconfig_DATA = \
ecore.pc $(pcon) $(pconfig) $(pdfb) $(pevas) \
$(pfb) $(pfile) $(pdesktop) $(pipc) $(pjob) $(ptxt) \
$(pfb) $(pfile) $(pdesktop) $(pimf) $(pipc) $(pjob) $(ptxt) \
$(px) $(pwin32) $(psdl)

View File

@ -704,6 +704,9 @@ dnl ecore_desktop
ECORE_CHECK_MODULE([Desktop], [no], [$have_ecore_file],
[requirements_ecore_desktop="ecore-file"])
dnl ecore_imf
ECORE_CHECK_MODULE([IMF], [yes], [$have_evas])
dnl requirements
AC_SUBST(requirements_ecore_con)
AC_SUBST(requirements_ecore_config)
@ -738,6 +741,7 @@ ecore-directfb.pc
ecore-evas.pc
ecore-fb.pc
ecore-file.pc
ecore-imf.pc
ecore-ipc.pc
ecore-job.pc
ecore-txt.pc
@ -755,6 +759,7 @@ src/lib/ecore_fb/Makefile
src/lib/ecore_sdl/Makefile
src/lib/ecore_evas/Makefile
src/lib/ecore_con/Makefile
src/lib/ecore_imf/Makefile
src/lib/ecore_ipc/Makefile
src/lib/ecore_txt/Makefile
src/lib/ecore_config/Makefile
@ -799,6 +804,8 @@ echo " Ecore_Evas Buffer Support....: $have_ecore_evas_buffer"
echo " Ecore_File...................: $have_ecore_file (Inotify: $have_inotify) (Poll: $have_poll) (CURL: $have_curl)"
echo " Ecore_Desktop................: $have_ecore_desktop"
echo " Ecore_IMF....................: $have_ecore_imf"
echo
echo "Now type 'make' ('gmake' on some systems) to compile $PACKAGE."
echo

View File

@ -0,0 +1,11 @@
prefix=@prefix@
exec_prefix=@exec_prefix@
libdir=@libdir@
includedir=@includedir@
Name: ecore-imf
Description: E core library, IMF module
Requires: ecore evas
Version: @VERSION@
Libs: -L${libdir} -lecore_imf
Cflags: -I${includedir}

View File

@ -13,4 +13,5 @@ ecore_ipc \
ecore_evas \
ecore_config \
ecore_file \
ecore_desktop
ecore_desktop \
ecore_imf

View File

@ -232,6 +232,7 @@ EAPI void ecore_evas_sticky_set(Ecore_Evas *ee, int sticky);
EAPI int ecore_evas_sticky_get(Ecore_Evas *ee);
EAPI void ecore_evas_ignore_events_set(Ecore_Evas *ee, int ignore);
EAPI int ecore_evas_ignore_events_get(Ecore_Evas *ee);
EAPI void *ecore_evas_window_get(Ecore_Evas *ee);
#ifdef __cplusplus
}

View File

@ -1773,6 +1773,20 @@ ecore_evas_ignore_events_get(Ecore_Evas *ee)
return ee->ignore_events ? 1 : 0;
}
EAPI void *
ecore_evas_window_get(Ecore_Evas *ee)
{
if (!ECORE_MAGIC_CHECK(ee, ECORE_MAGIC_EVAS))
{
ECORE_MAGIC_FAIL(ee, ECORE_MAGIC_EVAS,
"ecore_evas_window_get");
return NULL;
}
if (ee->engine.func->fn_window_get) return ee->engine.func->fn_window_get(ee);
return NULL;
}
#ifndef _WIN32
/* fps debug calls - for debugging how much time your app actually spends */
/* rendering graphics... :) */

View File

@ -425,6 +425,7 @@ static const Ecore_Evas_Engine_Func _ecore_buffer_engine_func =
NULL,
NULL,
NULL,
NULL,
NULL
};
#endif

View File

@ -497,8 +497,19 @@ _ecore_evas_directfb_fullscreen_set(Ecore_Evas *ee, int on)
if(ee->func.fn_resize) ee->func.fn_resize(ee);
}
}
#endif
static void *
_ecore_evas_directfb_window_get(Ecore_Evas *ee)
{
#ifdef BUILD_ECORE_EVAS_DIRECTFB
return ee->engine.directfb.window;
#else
return 0;
#endif
}
#ifdef BUILD_ECORE_EVAS_DIRECTFB
static const Ecore_Evas_Engine_Func _ecore_directfb_engine_func =
{
_ecore_evas_directfb_free, /* free an ecore_evas */
@ -544,7 +555,8 @@ static const Ecore_Evas_Engine_Func _ecore_directfb_engine_func =
NULL, /* withdrawn */
NULL, /* sticky */
NULL, /* ignore events */
NULL /* alpha */
NULL, /* alpha */
_ecore_evas_directfb_window_get /* window_get */
};
#endif
@ -554,15 +566,9 @@ static const Ecore_Evas_Engine_Func _ecore_directfb_engine_func =
Ecore_DirectFB_Window *
ecore_evas_directfb_window_get(Ecore_Evas *ee)
{
#ifdef BUILD_ECORE_EVAS_DIRECTFB
return ee->engine.directfb.window;
#else
ee = NULL;
return NULL;
#endif
return (Ecore_DirectFB_Window *) _ecore_evas_directfb_window_get(ee);
}
EAPI Ecore_Evas *
ecore_evas_directfb_new(const char *disp_name, int windowed, int x, int y, int w, int h)
{

View File

@ -557,6 +557,7 @@ static const Ecore_Evas_Engine_Func _ecore_fb_engine_func =
_ecore_evas_fullscreen_set,
NULL,
NULL,
NULL,
NULL
};
#endif

View File

@ -124,6 +124,7 @@ struct _Ecore_Evas_Engine_Func
void (*fn_sticky_set) (Ecore_Evas *ee, int sticky);
void (*fn_ignore_events_set) (Ecore_Evas *ee, int ignore);
void (*fn_alpha_set) (Ecore_Evas *ee, int alpha);
void *(*fn_window_get) (Ecore_Evas *ee);
};
struct _Ecore_Evas_Engine

View File

@ -419,6 +419,7 @@ static const Ecore_Evas_Engine_Func _ecore_sdl_engine_func =
NULL,
NULL,
NULL,
NULL,
NULL
};
#endif

View File

@ -874,8 +874,19 @@ _ecore_evas_win32_fullscreen_set(Ecore_Evas *ee, int on)
/* else */
/* _ecore_evas_win32_state_update(ee); */
}
#endif
static void *
_ecore_evas_win32_window_get(Ecore_Evas *ee)
{
#ifdef BUILD_ECORE_WIN32
return ee->engine.win32.window;
#else
return NULL;
#endif /* BUILD_ECORE_WIN32 */
}
#ifdef BUILD_ECORE_WIN32
static const Ecore_Evas_Engine_Func _ecore_win32_engine_func =
{
_ecore_evas_win32_free,
@ -921,7 +932,8 @@ static const Ecore_Evas_Engine_Func _ecore_win32_engine_func =
NULL, /* _ecore_evas_x_withdrawn_set */
NULL, /* _ecore_evas_x_sticky_set */
NULL, /* _ecore_evas_x_ignore_events_set */
NULL /* _ecore_evas_x_alpha_set */
NULL, /* _ecore_evas_x_alpha_set */
_ecore_evas_win32_window_get
};
#endif /* BUILD_ECORE_WIN32 */
@ -1037,11 +1049,7 @@ ecore_evas_software_ddraw_new(Ecore_Win32_Window *parent,
EAPI Ecore_Win32_Window *
ecore_evas_software_ddraw_window_get(Ecore_Evas *ee)
{
#ifdef BUILD_ECORE_WIN32
return ee->engine.win32.window;
#else
return NULL;
#endif /* BUILD_ECORE_WIN32 */
return (Ecore_Win32_Window *) _ecore_evas_win32_window_get(ee);
}
EAPI Ecore_Evas *
@ -1154,9 +1162,5 @@ ecore_evas_direct3d_new(Ecore_Win32_Window *parent,
EAPI Ecore_Win32_Window *
ecore_evas_direct3d_window_get(Ecore_Evas *ee)
{
#ifdef BUILD_ECORE_WIN32
return ee->engine.win32.window;
#else
return NULL;
#endif /* BUILD_ECORE_WIN32 */
return (Ecore_Win32_Window *) _ecore_evas_win32_window_get(ee);
}

View File

@ -2026,6 +2026,16 @@ _ecore_evas_x_alpha_set(Ecore_Evas *ee, int alpha)
}
}
static void *
_ecore_evas_x_window_get(Ecore_Evas *ee)
{
#ifdef BUILD_ECORE_EVAS_X11
return (void *) ee->engine.x.win;
#else
return 0;
#endif
}
static void
_ecore_evas_x_show(Ecore_Evas *ee)
{
@ -2544,7 +2554,8 @@ static const Ecore_Evas_Engine_Func _ecore_x_engine_func =
_ecore_evas_x_withdrawn_set,
_ecore_evas_x_sticky_set,
_ecore_evas_x_ignore_events_set,
_ecore_evas_x_alpha_set
_ecore_evas_x_alpha_set,
_ecore_evas_x_window_get
};
#endif
@ -2819,11 +2830,7 @@ ecore_evas_software_x11_new(const char *disp_name, Ecore_X_Window parent,
EAPI Ecore_X_Window
ecore_evas_software_x11_window_get(Ecore_Evas *ee)
{
#ifdef BUILD_ECORE_EVAS_X11
return ee->engine.x.win;
#else
return 0;
#endif
return (Ecore_X_Window) _ecore_evas_x_window_get(ee);
}
/**
@ -2834,11 +2841,7 @@ ecore_evas_software_x11_window_get(Ecore_Evas *ee)
EAPI Ecore_X_Window
ecore_evas_software_x11_subwindow_get(Ecore_Evas *ee)
{
#ifdef BUILD_ECORE_EVAS_X11
return ee->engine.x.win;
#else
return 0;
#endif
return (Ecore_X_Window) _ecore_evas_x_window_get(ee);
}
/**
@ -3012,11 +3015,7 @@ ecore_evas_gl_x11_new(const char *disp_name, Ecore_X_Window parent,
EAPI Ecore_X_Window
ecore_evas_gl_x11_window_get(Ecore_Evas *ee)
{
#ifdef BUILD_ECORE_EVAS_X11
return ee->engine.x.win;
#else
return 0;
#endif
return (Ecore_X_Window) _ecore_evas_x_window_get(ee);
}
/**
@ -3027,11 +3026,7 @@ ecore_evas_gl_x11_window_get(Ecore_Evas *ee)
EAPI Ecore_X_Window
ecore_evas_gl_x11_subwindow_get(Ecore_Evas *ee)
{
#ifdef BUILD_ECORE_EVAS_X11
return ee->engine.x.win;
#else
return 0;
#endif
return (Ecore_X_Window) _ecore_evas_x_window_get(ee);
}
/**
@ -3264,11 +3259,7 @@ ecore_evas_xrender_x11_new(const char *disp_name, Ecore_X_Window parent,
EAPI Ecore_X_Window
ecore_evas_xrender_x11_window_get(Ecore_Evas *ee)
{
#ifdef BUILD_ECORE_EVAS_X11
return ee->engine.x.win;
#else
return 0;
#endif
return (Ecore_X_Window) _ecore_evas_x_window_get(ee);
}
/**
@ -3279,11 +3270,7 @@ ecore_evas_xrender_x11_window_get(Ecore_Evas *ee)
EAPI Ecore_X_Window
ecore_evas_xrender_x11_subwindow_get(Ecore_Evas *ee)
{
#ifdef BUILD_ECORE_EVAS_X11
return ee->engine.x.win;
#else
return 0;
#endif
return (Ecore_X_Window) _ecore_evas_x_window_get(ee);
}
/**
@ -3474,11 +3461,7 @@ ecore_evas_software_x11_16_new(const char *disp_name, Ecore_X_Window parent,
EAPI Ecore_X_Window
ecore_evas_software_x11_16_window_get(Ecore_Evas *ee)
{
#if BUILD_ECORE_EVAS_X11_16
return ee->engine.x.win;
#else
return 0;
#endif
return (Ecore_X_Window) _ecore_evas_x_window_get(ee);
}
/**
@ -3489,11 +3472,7 @@ ecore_evas_software_x11_16_window_get(Ecore_Evas *ee)
EAPI Ecore_X_Window
ecore_evas_software_x11_16_subwindow_get(Ecore_Evas *ee)
{
#if BUILD_ECORE_EVAS_X11_16
return ee->engine.x.win;
#else
return 0;
#endif
return (Ecore_X_Window) _ecore_evas_x_window_get(ee);
}
/**

View File

@ -0,0 +1,6 @@
.deps
.libs
Makefile
Makefile.in
*.lo
*.la

View File

@ -0,0 +1,162 @@
/*
* vim:ts=8:sw=3:sts=8:noexpandtab:cino=>5n-3f0^-2{2
*/
#ifndef _ECORE_IMF_H
#define _ECORE_IMF_H
#ifdef EAPI
#undef EAPI
#endif
#ifdef _MSC_VER
# ifdef BUILDING_DLL
# define EAPI __declspec(dllexport)
# else
# define EAPI __declspec(dllimport)
# endif
#else
# ifdef __GNUC__
# if __GNUC__ >= 4
# define EAPI __attribute__ ((visibility("default")))
# else
# define EAPI
# endif
# else
# define EAPI
# endif
#endif
#include <Ecore_Data.h>
#include <Evas.h>
#ifdef __cplusplus
extern "C" {
#endif
typedef struct _Ecore_IMF_Event_Preedit_Start Ecore_IMF_Event_Preedit_Start;
typedef struct _Ecore_IMF_Event_Preedit_End Ecore_IMF_Event_Preedit_End;
typedef struct _Ecore_IMF_Event_Preedit_Changed Ecore_IMF_Event_Preedit_Changed;
typedef struct _Ecore_IMF_Event_Commit Ecore_IMF_Event_Commit;
typedef struct _Ecore_IMF_Event_Delete_Surrounding Ecore_IMF_Event_Delete_Surrounding;
typedef struct _Ecore_IMF_Context Ecore_IMF_Context; /**< An Input Method Context */
typedef struct _Ecore_IMF_Context_Class Ecore_IMF_Context_Class; /**< An Input Method Context class */
typedef struct _Ecore_IMF_Context_Info Ecore_IMF_Context_Info; /**< An Input Method Context info */
EAPI extern int ECORE_IMF_EVENT_PREEDIT_START;
EAPI extern int ECORE_IMF_EVENT_PREEDIT_END;
EAPI extern int ECORE_IMF_EVENT_PREEDIT_CHANGED;
EAPI extern int ECORE_IMF_EVENT_COMMIT;
EAPI extern int ECORE_IMF_EVENT_DELETE_SURROUNDIND;
typedef enum
{
ECORE_IMF_INPUT_MODE_ALPHA = 1 << 0,
ECORE_IMF_INPUT_MODE_NUMERIC = 1 << 1,
ECORE_IMF_INPUT_MODE_SPECIAL = 1 << 2,
ECORE_IMF_INPUT_MODE_HEXA = 1 << 3,
ECORE_IMF_INPUT_MODE_TELE = 1 << 4,
ECORE_IMF_INPUT_MODE_FULL = (ECORE_IMF_INPUT_MODE_ALPHA | ECORE_IMF_INPUT_MODE_NUMERIC | ECORE_IMF_INPUT_MODE_SPECIAL),
ECORE_IMF_INPUT_MODE_INVISIBLE = 1 << 29,
ECORE_IMF_INPUT_MODE_AUTOCAP = 1 << 30
} Ecore_IMF_Input_Mode;
struct _Ecore_IMF_Event_Preedit_Start
{
Ecore_IMF_Context *ctx;
};
struct _Ecore_IMF_Event_Preedit_End
{
Ecore_IMF_Context *ctx;
};
struct _Ecore_IMF_Event_Preedit_Changed
{
Ecore_IMF_Context *ctx;
};
struct _Ecore_IMF_Event_Commit
{
Ecore_IMF_Context *ctx;
char *str;
};
struct _Ecore_IMF_Event_Delete_Surrounding
{
Ecore_IMF_Context *ctx;
int offset;
int n_chars;
};
struct _Ecore_IMF_Context_Class
{
void (*add) (Ecore_IMF_Context *ctx);
void (*del) (Ecore_IMF_Context *ctx);
void (*client_window_set) (Ecore_IMF_Context *ctx, void *window);
void (*show) (Ecore_IMF_Context *ctx);
void (*hide) (Ecore_IMF_Context *ctx);
void (*preedit_string_get) (Ecore_IMF_Context *ctx, char **str, int *cursor_pos);
void (*focus_in) (Ecore_IMF_Context *ctx);
void (*focus_out) (Ecore_IMF_Context *ctx);
void (*reset) (Ecore_IMF_Context *ctx);
void (*cursor_position_set) (Ecore_IMF_Context *ctx, int cursor_pos);
void (*use_preedit_set) (Ecore_IMF_Context *ctx, int use_preedit);
void (*input_mode_set) (Ecore_IMF_Context *ctx, Ecore_IMF_Input_Mode input_mode);
int (*filter_event) (Ecore_IMF_Context *ctx, Evas_Callback_Type type, void *event_info);
};
struct _Ecore_IMF_Context_Info
{
const char *id; /* ID */
const char *description; /* Human readable description */
const char *default_locales; /* Languages for which this context is the default, separated by : */
};
EAPI int ecore_imf_init(void);
EAPI int ecore_imf_shutdown(void);
EAPI Ecore_List *ecore_imf_context_available_ids_get(void);
EAPI const char *ecore_imf_context_default_id_get(void);
EAPI const Ecore_IMF_Context_Info *ecore_imf_context_info_by_id_get(const char *id);
EAPI Ecore_IMF_Context *ecore_imf_context_add(const char *id);
EAPI void ecore_imf_context_del(Ecore_IMF_Context *ctx);
EAPI void ecore_imf_context_client_window_set(Ecore_IMF_Context *ctx, void *window);
EAPI void ecore_imf_context_show(Ecore_IMF_Context *ctx);
EAPI void ecore_imf_context_hide(Ecore_IMF_Context *ctx);
EAPI void ecore_imf_context_preedit_string_get(Ecore_IMF_Context *ctx, char **str, int *cursor_pos);
EAPI void ecore_imf_context_focus_in(Ecore_IMF_Context *ctx);
EAPI void ecore_imf_context_focus_out(Ecore_IMF_Context *ctx);
EAPI void ecore_imf_context_reset(Ecore_IMF_Context *ctx);
EAPI void ecore_imf_context_cursor_position_set(Ecore_IMF_Context *ctx, int cursor_pos);
EAPI void ecore_imf_context_use_preedit_set(Ecore_IMF_Context *ctx, int use_preedit);
EAPI void ecore_imf_context_retrieve_surrounding_callback_set(Ecore_IMF_Context *ctx, int (*func)(void *data, Ecore_IMF_Context *ctx, char **text, int *cursor_pos), const void *data);
EAPI void ecore_imf_context_input_mode_set(Ecore_IMF_Context *ctx, Ecore_IMF_Input_Mode input_mode);
EAPI Ecore_IMF_Input_Mode ecore_imf_context_input_mode_get(Ecore_IMF_Context *ctx);
EAPI int ecore_imf_context_filter_event(Ecore_IMF_Context *ctx, Evas_Callback_Type type, void *event_info);
/* plugin specific functions */
EAPI Ecore_IMF_Context *ecore_imf_context_new(const Ecore_IMF_Context_Class *ctxc);
EAPI void ecore_imf_context_data_set(Ecore_IMF_Context *ctx, void *data);
EAPI void *ecore_imf_context_data_get(Ecore_IMF_Context *ctx);
EAPI int ecore_imf_context_surrounding_get(Ecore_IMF_Context *ctx, char **text, int *cursor_pos);
EAPI void ecore_imf_context_preedit_start_event_add(Ecore_IMF_Context *ctx);
EAPI void ecore_imf_context_preedit_end_event_add(Ecore_IMF_Context *ctx);
EAPI void ecore_imf_context_preedit_changed_event_add(Ecore_IMF_Context *ctx);
EAPI void ecore_imf_context_commit_event_add(Ecore_IMF_Context *ctx, const char *str);
EAPI void ecore_imf_context_delete_surrounding_event_add(Ecore_IMF_Context *ctx, int offset, int n_chars);
/* The following entry points must be exported by each input method module
*/
/*
* int imf_module_init (const Ecore_IMF_Context_Info **info);
* void imf_module_exit (void);
* Ecore_IMF_Context *imf_module_create (void);
*/
#ifdef __cplusplus
}
#endif
#endif

View File

@ -0,0 +1,31 @@
MAINTAINERCLEANFILES = Makefile.in
if BUILD_ECORE_IMF
AM_CPPFLAGS = \
-I$(top_srcdir)/src/lib/ecore \
-DPACKAGE_LIB_DIR=\"$(libdir)\" \
@EVAS_CFLAGS@
lib_LTLIBRARIES = libecore_imf.la
include_HEADERS = \
Ecore_IMF.h
libecore_imf_la_SOURCES = \
ecore_imf.c \
ecore_imf_context.c \
ecore_imf_module.c \
ecore_imf_private.h
libecore_imf_la_LIBADD = \
$(top_builddir)/src/lib/ecore/libecore.la \
@EVAS_LIBS@
libecore_imf_la_LDFLAGS = -version-info @version_info@
endif
EXTRA_DIST = \
Ecore_IMF.h \
ecore_imf.c \
ecore_imf_context.c \
ecore_imf_module.c \
ecore_imf_private.h

View File

@ -0,0 +1,64 @@
/*
* vim:ts=8:sw=3:sts=8:noexpandtab:cino=>5n-3f0^-2{2
*/
#include "config.h"
#include "Ecore_IMF.h"
EAPI int ECORE_IMF_EVENT_PREEDIT_START = 0;
EAPI int ECORE_IMF_EVENT_PREEDIT_END = 0;
EAPI int ECORE_IMF_EVENT_PREEDIT_CHANGED = 0;
EAPI int ECORE_IMF_EVENT_COMMIT = 0;
EAPI int ECORE_IMF_EVENT_RETRIEVE_SURROUNDIND = 0;
EAPI int ECORE_IMF_EVENT_DELETE_SURROUNDIND = 0;
static int init_count = 0;
/**
* @defgroup Ecore_IMF_Lib_Group Ecore Input Method Library Functions
*
* Utility functions that set up and shut down the Ecore Input Method
* library.
*/
/**
* Initialises the Ecore_IMF library.
* @return Number of times the library has been initialised without being
* shut down.
* @ingroup Ecore_IMF_Lib_Group
*/
EAPI int
ecore_imf_init(void)
{
if (++init_count != 1) return init_count;
ecore_init();
ecore_imf_module_init();
ECORE_IMF_EVENT_PREEDIT_START = ecore_event_type_new();
ECORE_IMF_EVENT_PREEDIT_END = ecore_event_type_new();
ECORE_IMF_EVENT_PREEDIT_CHANGED = ecore_event_type_new();
ECORE_IMF_EVENT_COMMIT = ecore_event_type_new();
ECORE_IMF_EVENT_RETRIEVE_SURROUNDIND = ecore_event_type_new();
ECORE_IMF_EVENT_DELETE_SURROUNDIND = ecore_event_type_new();
return init_count;
}
/**
* Shuts down the Ecore_IMF library.
* @return Number of times the library has been initialised without being
* shut down.
* @ingroup Ecore_IMF_Lib_Group
*/
EAPI int
ecore_imf_shutdown(void)
{
if (--init_count != 0) return init_count;
ecore_shutdown();
ecore_imf_module_shutdown();
return init_count;
}

View File

@ -0,0 +1,740 @@
/*
* vim:ts=8:sw=3:sts=8:noexpandtab:cino=>5n-3f0^-2{2
*/
#include <locale.h>
#include <stdlib.h>
#include "config.h"
#include "Ecore_IMF.h"
#include "ecore_imf_private.h"
/**
* @defgroup Ecore_IMF_Context_Group Ecore Input Method Context Functions
*
* Functions that operate on Ecore Input Method Context objects.
*/
/**
* Get the list of the available Input Method Context ids.
*
* Note that the caller is responsible for freeing the Ecore_List
* when finished with it. There is no need to finish the list strings.
*
* @return Return an Ecore_List of strings;
* on failure it returns NULL.
* @ingroup Ecore_IMF_Context_Group
*/
EAPI Ecore_List *
ecore_imf_context_available_ids_get(void)
{
return ecore_imf_module_context_ids_get();
}
/*
* Match @locale against @against.
*
* 'en_US' against 'en_US' => 4
* 'en_US' against 'en' => 3
* 'en', 'en_UK' against 'en_US' => 2
* all locales, against '*' => 1
*/
static int
_ecore_imf_context_match_locale(const char *locale, const char *against, int against_len)
{
if (strcmp(against, "*") == 0)
return 1;
if (strcasecmp(locale, against) == 0)
return 4;
if (strncasecmp(locale, against, 2) == 0)
return (against_len == 2) ? 3 : 2;
return 0;
}
/**
* Get the id of the default Input Method Context.
* The id may to used to create a new instance of an Input Method
* Context object.
*
* @return Return a string containing the id of the default Input
* Method Context; on failure it returns NULL.
* @ingroup Ecore_IMF_Context_Group
*/
EAPI const char *
ecore_imf_context_default_id_get(void)
{
const char *id;
Ecore_List *modules;
Ecore_IMF_Module *module;
char *locale;
char *tmp;
int best_goodness = 0;
id = getenv("ECORE_IMF_MODULE");
if (id && ecore_imf_module_get(id)) return id;
modules = ecore_imf_module_available_get();
if (!modules) return NULL;
locale = setlocale(LC_CTYPE, NULL);
if (!locale) return NULL;
locale = strdup(locale);
tmp = strchr(locale, '.');
if (tmp) *tmp = '\0';
tmp = strchr(locale, '@');
if (tmp) *tmp = '\0';
id = NULL;
ecore_list_first_goto(modules);
while ((module = ecore_list_next(modules)))
{
const char *p = module->info->default_locales;
while (p)
{
const char *q = strchr(p, ':');
int goodness = _ecore_imf_context_match_locale(locale, p, q ? q - p : strlen (p));
if (goodness > best_goodness)
{
id = module->info->id;
best_goodness = goodness;
}
p = q ? q + 1 : NULL;
}
}
ecore_list_destroy(modules);
free(locale);
return id;
}
/**
* Retrieve the info for the Input Method Context with @p id.
*
* @param id The Input Method Context id to query for.
* @return Return a #Ecore_IMF_Context_Info for the Input Method Context with @p id;
* on failure it returns NULL.
* @ingroup Ecore_IMF_Context_Group
*/
EAPI const Ecore_IMF_Context_Info *
ecore_imf_context_info_by_id_get(const char *id)
{
Ecore_IMF_Module *module;
if (!id) return NULL;
module = ecore_imf_module_get(id);
if (!module) return NULL;
return module->info;
}
/**
* Create a new Input Method Context defined by the given id.
*
* @param id The Input Method Context id.
* @return A newly allocated Input Method Context;
* on failure it returns NULL.
* @ingroup Ecore_IMF_Context_Group
*/
EAPI Ecore_IMF_Context *
ecore_imf_context_add(const char *id)
{
Ecore_IMF_Context *ctx;
if (!id) return NULL;
ctx = ecore_imf_module_context_create(id);
if (!ctx || !ctx->klass) return NULL;
if (ctx->klass->add) ctx->klass->add(ctx);
/* default use_preedit is 1, so let's make sure it's
* set on the immodule */
ecore_imf_context_use_preedit_set(ctx, 1);
/* default input_mode is ECORE_IMF_INPUT_MODE_FULL, so let's make sure it's
* set on the immodule */
ecore_imf_context_input_mode_set(ctx, ECORE_IMF_INPUT_MODE_FULL);
return ctx;
}
/**
* Delete the given Input Method Context and free its memory.
*
* @param ctx An #Ecore_IMF_Context.
* @ingroup Ecore_IMF_Context_Group
*/
EAPI void
ecore_imf_context_del(Ecore_IMF_Context *ctx)
{
if (!ECORE_MAGIC_CHECK(ctx, ECORE_MAGIC_CONTEXT))
{
ECORE_MAGIC_FAIL(ctx, ECORE_MAGIC_CONTEXT,
"ecore_imf_context_del");
return;
}
if (ctx->klass->del) ctx->klass->del(ctx);
ECORE_MAGIC_SET(ctx, ECORE_MAGIC_NONE);
free(ctx);
}
/**
* Set the client window for the Input Method Context; this is the
* window returned by ecore_evas_window_get() in which the input appears.
* This window is used in order to correctly position status windows, and may
* also be used for purposes internal to the Input Method Context.
*
* @param ctx An #Ecore_IMF_Context.
* @param window The client window. This may be NULL to indicate
* that the previous client window no longer exists.
* @ingroup Ecore_IMF_Context_Group
*/
EAPI void
ecore_imf_context_client_window_set(Ecore_IMF_Context *ctx, void *window)
{
if (!ECORE_MAGIC_CHECK(ctx, ECORE_MAGIC_CONTEXT))
{
ECORE_MAGIC_FAIL(ctx, ECORE_MAGIC_CONTEXT,
"ecore_imf_context_client_window_set");
return;
}
if (ctx->klass->client_window_set) ctx->klass->client_window_set(ctx, window);
}
/**
* Ask the Input Method Context to show itself.
*
* @param ctx An #Ecore_IMF_Context.
* @ingroup Ecore_IMF_Context_Group
*/
EAPI void
ecore_imf_context_show(Ecore_IMF_Context *ctx)
{
if (!ECORE_MAGIC_CHECK(ctx, ECORE_MAGIC_CONTEXT))
{
ECORE_MAGIC_FAIL(ctx, ECORE_MAGIC_CONTEXT,
"ecore_imf_context_show");
return;
}
if (ctx->klass->show) ctx->klass->show(ctx);
}
/**
* Ask the Input Method Context to hide itself.
*
* @param ctx An #Ecore_IMF_Context.
* @ingroup Ecore_IMF_Context_Group
*/
EAPI void
ecore_imf_context_hide(Ecore_IMF_Context *ctx)
{
if (!ECORE_MAGIC_CHECK(ctx, ECORE_MAGIC_CONTEXT))
{
ECORE_MAGIC_FAIL(ctx, ECORE_MAGIC_CONTEXT,
"ecore_imf_context_hide");
return;
}
if (ctx->klass->hide) ctx->klass->hide(ctx);
}
/*
* Retrieve the current preedit string and cursor position
* for the Input Method Context.
*
* @param ctx An #Ecore_IMF_Context.
* @param str Location to store the retrieved string. The
* string retrieved must be freed with free().
* @param cursor_pos Location to store position of cursor (in characters)
* within the preedit string.
* @ingroup Ecore_IMF_Context_Group
*/
EAPI void
ecore_imf_context_preedit_string_get(Ecore_IMF_Context *ctx, char **str, int *cursor_pos)
{
if (!ECORE_MAGIC_CHECK(ctx, ECORE_MAGIC_CONTEXT))
{
ECORE_MAGIC_FAIL(ctx, ECORE_MAGIC_CONTEXT,
"ecore_imf_context_preedit_string_get");
return;
}
if (ctx->klass->preedit_string_get)
ctx->klass->preedit_string_get(ctx, str, cursor_pos);
else
{
if (str) *str = strdup("");
if (cursor_pos) *cursor_pos = 0;
}
}
/**
* Notify the Input Method Context that the widget to which its
* correspond has gained focus.
*
* @param ctx An #Ecore_IMF_Context.
* @ingroup Ecore_IMF_Context_Group
*/
EAPI void
ecore_imf_context_focus_in(Ecore_IMF_Context *ctx)
{
if (!ECORE_MAGIC_CHECK(ctx, ECORE_MAGIC_CONTEXT))
{
ECORE_MAGIC_FAIL(ctx, ECORE_MAGIC_CONTEXT,
"ecore_imf_context_focus_in");
return;
}
if (ctx->klass->focus_in) ctx->klass->focus_in(ctx);
}
/**
* Notify the Input Method Context that the widget to which its
* correspond has lost focus.
*
* @param ctx An #Ecore_IMF_Context.
* @ingroup Ecore_IMF_Context_Group
*/
EAPI void
ecore_imf_context_focus_out(Ecore_IMF_Context *ctx)
{
if (!ECORE_MAGIC_CHECK(ctx, ECORE_MAGIC_CONTEXT))
{
ECORE_MAGIC_FAIL(ctx, ECORE_MAGIC_CONTEXT,
"ecore_imf_context_focus_out");
return;
}
if (ctx->klass->focus_out) ctx->klass->focus_out(ctx);
}
/**
* Notify the Input Method Context that a change such as a
* change in cursor position has been made. This will typically
* cause the Input Method Context to clear the preedit state.
*
* @param ctx An #Ecore_IMF_Context.
* @ingroup Ecore_IMF_Context_Group
*/
EAPI void
ecore_imf_context_reset(Ecore_IMF_Context *ctx)
{
if (!ECORE_MAGIC_CHECK(ctx, ECORE_MAGIC_CONTEXT))
{
ECORE_MAGIC_FAIL(ctx, ECORE_MAGIC_CONTEXT,
"ecore_imf_context_reset");
return;
}
if (ctx->klass->reset) ctx->klass->reset(ctx);
}
/**
* Notify the Input Method Context that a change in the cursor
* position has been made.
*
* @param ctx An #Ecore_IMF_Context.
* @param cursor_pos New cursor position in characters.
* @ingroup Ecore_IMF_Context_Group
*/
EAPI void
ecore_imf_context_cursor_position_set(Ecore_IMF_Context *ctx, int cursor_pos)
{
if (!ECORE_MAGIC_CHECK(ctx, ECORE_MAGIC_CONTEXT))
{
ECORE_MAGIC_FAIL(ctx, ECORE_MAGIC_CONTEXT,
"ecore_imf_context_cursor_position_set");
return;
}
if (ctx->klass->cursor_position_set) ctx->klass->cursor_position_set(ctx, cursor_pos);
}
/**
* Set whether the IM context should use the preedit string
* to display feedback. If @use_preedit is 0 (default
* is 1), then the IM context may use some other method to display
* feedback, such as displaying it in a child of the root window.
*
* @param ctx An #Ecore_IMF_Context.
* @param use_preedit Whether the IM context should use the preedit string.
* @ingroup Ecore_IMF_Context_Group
*/
EAPI void
ecore_imf_context_use_preedit_set(Ecore_IMF_Context *ctx, int use_preedit)
{
if (!ECORE_MAGIC_CHECK(ctx, ECORE_MAGIC_CONTEXT))
{
ECORE_MAGIC_FAIL(ctx, ECORE_MAGIC_CONTEXT,
"ecore_imf_context_use_preedit_set");
return;
}
if (ctx->klass->use_preedit_set) ctx->klass->use_preedit_set(ctx, use_preedit);
}
/**
* Set the callback to be used on get_surrounding request.
*
* This callback will be called when the Input Method Context
* module requests the surrounding context.
*
* @param ctx An #Ecore_IMF_Context.
* @param func The callback to be called.
* @param data The data pointer to be passed to @p func
* @ingroup Ecore_IMF_Context_Group
*/
EAPI void
ecore_imf_context_retrieve_surrounding_callback_set(Ecore_IMF_Context *ctx, int (*func)(void *data, Ecore_IMF_Context *ctx, char **text, int *cursor_pos), const void *data)
{
if (!ECORE_MAGIC_CHECK(ctx, ECORE_MAGIC_CONTEXT))
{
ECORE_MAGIC_FAIL(ctx, ECORE_MAGIC_CONTEXT,
"ecore_imf_context_retrieve_surrounding_callback_set");
return;
}
ctx->retrieve_surrounding_func = func;
ctx->retrieve_surrounding_data = (void *) data;
}
/**
* Set the input mode used by the Ecore Input Context.
*
* The input mode can be one of the input modes defined in
* #Ecore_IMF_Input_Mode. The default input mode is
* ECORE_IMF_INPUT_MODE_FULL.
*
* @param ctx An #Ecore_IMF_Context.
* @param input_mode The input mode to be used by @p ctx.
* @ingroup Ecore_IMF_Context_Group
*/
EAPI void
ecore_imf_context_input_mode_set(Ecore_IMF_Context *ctx, Ecore_IMF_Input_Mode input_mode)
{
if (!ECORE_MAGIC_CHECK(ctx, ECORE_MAGIC_CONTEXT))
{
ECORE_MAGIC_FAIL(ctx, ECORE_MAGIC_CONTEXT,
"ecore_imf_context_input_mode_set");
return;
}
if (ctx->klass->input_mode_set) ctx->klass->input_mode_set(ctx, input_mode);
ctx->input_mode = input_mode;
}
/**
* Get the input mode being used by the Ecore Input Context.
*
* See @ref ecore_imf_context_input_mode_set for more details.
*
* @param ctx An #Ecore_IMF_Context.
* @return The input mode being used by @p ctx.
* @ingroup Ecore_IMF_Context_Group
*/
EAPI Ecore_IMF_Input_Mode
ecore_imf_context_input_mode_get(Ecore_IMF_Context *ctx)
{
if (!ECORE_MAGIC_CHECK(ctx, ECORE_MAGIC_CONTEXT))
{
ECORE_MAGIC_FAIL(ctx, ECORE_MAGIC_CONTEXT,
"ecore_imf_context_input_mode_set");
return 0;
}
return ctx->input_mode;
}
/**
* Allow an Ecore Input Context to internally handle an event.
* If this function returns 1, then no further processing
* should be done for this event.
*
* Input methods must be able to accept all types of events (simply
* returning 0 if the event was not handled), but there is no
* obligation of any events to be submitted to this function.
*
* @param ctx An #Ecore_IMF_Context.
* @param type The type of event defined in #Evas_Callback_Type
* @param event_info The event itself; This should be one of
* Evas_Event_* types or NULL for some event types as
* EVAS_CALLBACK_SHOW/HIDE for example.
* @return 1 if the event was handled; otherwise 0.
* @ingroup Ecore_IMF_Context_Group
*/
EAPI int
ecore_imf_context_filter_event(Ecore_IMF_Context *ctx, Evas_Callback_Type type, void *event_info)
{
if (!ECORE_MAGIC_CHECK(ctx, ECORE_MAGIC_CONTEXT))
{
ECORE_MAGIC_FAIL(ctx, ECORE_MAGIC_CONTEXT,
"ecore_imf_context_filter_event");
return 0;
}
if (ctx->klass->filter_event) return ctx->klass->filter_event(ctx, type, event_info);
return 0;
}
/**
* @defgroup Ecore_IMF_Context_Module_Group Ecore Input Method Context Module Functions
*
* Functions that should be used by Ecore Input Method Context modules.
*/
/**
* Creates a new Input Method Context with klass specified by @p ctxc.
*
* This method should be used by modules implementing the Input
* Method Context interface.
*
* @param ctxc An #Ecore_IMF_Context_Class.
* @return A new #Ecore_IMF_Context; on failure it returns NULL.
* @ingroup Ecore_IMF_Context_Module_Group
*/
EAPI Ecore_IMF_Context *
ecore_imf_context_new(const Ecore_IMF_Context_Class *ctxc)
{
Ecore_IMF_Context *ctx;
if (!ctx) return NULL;
ctx = malloc(sizeof(Ecore_IMF_Context));
if (!ctx) return NULL;
ECORE_MAGIC_SET(ctx, ECORE_MAGIC_CONTEXT);
ctx->klass = ctxc;
ctx->data = NULL;
ctx->retrieve_surrounding_func = NULL;
ctx->retrieve_surrounding_data = NULL;
return ctx;
}
/**
* Set the Input Method Context specific data.
*
* Note that this method should be used by modules to set
* the Input Method Context specific data and it's not meant to
* be used by applications to store application specific data.
*
* @param ctx An #Ecore_IMF_Context.
* @param data The Input Method Context specific data.
* @return A new #Ecore_IMF_Context; on failure it returns NULL.
* @ingroup Ecore_IMF_Context_Module_Group
*/
EAPI void
ecore_imf_context_data_set(Ecore_IMF_Context *ctx, void *data)
{
if (!ECORE_MAGIC_CHECK(ctx, ECORE_MAGIC_CONTEXT))
{
ECORE_MAGIC_FAIL(ctx, ECORE_MAGIC_CONTEXT,
"ecore_imf_context_data_set");
return;
}
ctx->data = data;
}
/**
* Get the Input Method Context specific data.
*
* See @ref ecore_imf_context_data_set for more details.
*
* @param ctx An #Ecore_IMF_Context.
* @return The Input Method Context specific data.
* @ingroup Ecore_IMF_Context_Module_Group
*/
EAPI void *ecore_imf_context_data_get(Ecore_IMF_Context *ctx)
{
if (!ECORE_MAGIC_CHECK(ctx, ECORE_MAGIC_CONTEXT))
{
ECORE_MAGIC_FAIL(ctx, ECORE_MAGIC_CONTEXT,
"ecore_imf_context_data_get");
return;
}
return ctx->data;
}
/**
* Retrieve context around insertion point.
*
* This function is implemented by calling the
* Ecore_IMF_Context::retrieve_surrounding_func (
* set using #ecore_imf_context_retrieve_surrounding_callback_set).
*
* There is no obligation for a widget to respond to the
* ::retrieve_surrounding_func, so input methods must be prepared
* to function without context.
*
* @param ctx An #Ecore_IMF_Context.
* @param text Location to store a UTF-8 encoded string of text
* holding context around the insertion point.
* If the function returns 1, then you must free
* the result stored in this location with free().
* @param cursor_pos Location to store the position in characters of
* the insertion cursor within @text.
* @return 1 if surrounding text was provided; otherwise 0.
* @ingroup Ecore_IMF_Context_Module_Group
*/
EAPI int
ecore_imf_context_surrounding_get(Ecore_IMF_Context *ctx, char **text, int *cursor_pos)
{
int result = 0;
if (!ECORE_MAGIC_CHECK(ctx, ECORE_MAGIC_CONTEXT))
{
ECORE_MAGIC_FAIL(ctx, ECORE_MAGIC_CONTEXT,
"ecore_imf_context_surrounding_get");
return 0;
}
if (ctx->retrieve_surrounding_func)
{
result = ctx->retrieve_surrounding_func(ctx->retrieve_surrounding_data, ctx, text, cursor_pos);
if (!result)
{
if (text) *text = NULL;
if (cursor_pos) *cursor_pos = 0;
}
}
return result;
}
static void
_ecore_imf_event_free_preedit(void *data __UNUSED__, void *event)
{
free(event);
}
/**
* Adds ECORE_IMF_EVENT_PREEDIT_START to the event queue.
*
* @param ctx An #Ecore_IMF_Context.
* @ingroup Ecore_IMF_Context_Module_Group
*/
EAPI void
ecore_imf_context_preedit_start_event_add(Ecore_IMF_Context *ctx)
{
Ecore_IMF_Event_Commit *ev;
if (!ECORE_MAGIC_CHECK(ctx, ECORE_MAGIC_CONTEXT))
{
ECORE_MAGIC_FAIL(ctx, ECORE_MAGIC_CONTEXT,
"ecore_imf_context_preedit_start_event_add");
return;
}
ev = malloc(sizeof(Ecore_IMF_Event_Preedit_Start));
ev->ctx = ctx;
ecore_event_add(ECORE_IMF_EVENT_PREEDIT_START,
ev, _ecore_imf_event_free_preedit, NULL);
}
/**
* Adds ECORE_IMF_EVENT_PREEDIT_END to the event queue.
*
* @param ctx An #Ecore_IMF_Context.
* @ingroup Ecore_IMF_Context_Module_Group
*/
EAPI void
ecore_imf_context_preedit_end_event_add(Ecore_IMF_Context *ctx)
{
Ecore_IMF_Event_Commit *ev;
if (!ECORE_MAGIC_CHECK(ctx, ECORE_MAGIC_CONTEXT))
{
ECORE_MAGIC_FAIL(ctx, ECORE_MAGIC_CONTEXT,
"ecore_imf_context_preedit_end_event_add");
return;
}
ev = malloc(sizeof(Ecore_IMF_Event_Preedit_End));
ev->ctx = ctx;
ecore_event_add(ECORE_IMF_EVENT_PREEDIT_END,
ev, _ecore_imf_event_free_preedit, NULL);
}
/**
* Adds ECORE_IMF_EVENT_PREEDIT_CHANGED to the event queue.
*
* @param ctx An #Ecore_IMF_Context.
* @ingroup Ecore_IMF_Context_Module_Group
*/
EAPI void
ecore_imf_context_preedit_changed_event_add(Ecore_IMF_Context *ctx)
{
Ecore_IMF_Event_Commit *ev;
if (!ECORE_MAGIC_CHECK(ctx, ECORE_MAGIC_CONTEXT))
{
ECORE_MAGIC_FAIL(ctx, ECORE_MAGIC_CONTEXT,
"ecore_imf_context_preedit_changed_event_add");
return;
}
ev = malloc(sizeof(Ecore_IMF_Event_Preedit_Changed));
ev->ctx = ctx;
ecore_event_add(ECORE_IMF_EVENT_PREEDIT_CHANGED,
ev, _ecore_imf_event_free_preedit, NULL);
}
static void
_ecore_imf_event_free_commit(void *data __UNUSED__, void *event)
{
Ecore_IMF_Event_Commit *ev;
ev = event;
if (ev->str) free(ev->str);
free(ev);
}
/**
* Adds ECORE_IMF_EVENT_COMMIT to the event queue.
*
* @param ctx An #Ecore_IMF_Context.
* @param str The committed string.
* @ingroup Ecore_IMF_Context_Module_Group
*/
EAPI void
ecore_imf_context_commit_event_add(Ecore_IMF_Context *ctx, const char *str)
{
Ecore_IMF_Event_Commit *ev;
if (!ECORE_MAGIC_CHECK(ctx, ECORE_MAGIC_CONTEXT))
{
ECORE_MAGIC_FAIL(ctx, ECORE_MAGIC_CONTEXT,
"ecore_imf_context_commit_event_add");
return;
}
ev = malloc(sizeof(Ecore_IMF_Event_Commit));
ev->ctx = ctx;
ev->str = str ? strdup(str) : NULL;
ecore_event_add(ECORE_IMF_EVENT_COMMIT,
ev, _ecore_imf_event_free_commit, NULL);
}
static void
_ecore_imf_event_free_delete_surrounding(void *data __UNUSED__, void *event)
{
free(event);
}
/**
* Adds ECORE_IMF_EVENT_DELETE_SURROUNDIND to the event queue.
*
* @param ctx An #Ecore_IMF_Context.
* @param offset The start offset of surrounding to be deleted.
* @param n_chars The number of characters to be deleted.
* @ingroup Ecore_IMF_Context_Module_Group
*/
EAPI void
ecore_imf_context_delete_surrounding_event_add(Ecore_IMF_Context *ctx, int offset, int n_chars)
{
Ecore_IMF_Event_Delete_Surrounding *ev;
if (!ECORE_MAGIC_CHECK(ctx, ECORE_MAGIC_CONTEXT))
{
ECORE_MAGIC_FAIL(ctx, ECORE_MAGIC_CONTEXT,
"ecore_imf_context_delete_surrounding_event_add");
return;
}
ev = malloc(sizeof(Ecore_IMF_Event_Delete_Surrounding));
ev->ctx = ctx;
ev->offset = offset;
ev->n_chars = n_chars;
ecore_event_add(ECORE_IMF_EVENT_DELETE_SURROUNDIND,
ev, _ecore_imf_event_free_delete_surrounding, NULL);
}

View File

@ -0,0 +1,207 @@
/*
* vim:ts=8:sw=3:sts=8:noexpandtab:cino=>5n-3f0^-2{2
*/
#include <limits.h>
#include <stdio.h>
#include <stdlib.h>
#include "config.h"
#include "ecore_imf_private.h"
static void _ecore_imf_module_load_all(void);
static void _ecore_imf_module_append(Ecore_Plugin *plugin, const Ecore_IMF_Context_Info *info, Ecore_IMF_Context *(*imf_module_create)(void));
static void _ecore_imf_module_free(Ecore_IMF_Module *module);
static int _ecore_imf_modules_exists(const char *ctx_id);
static Ecore_Path_Group *ecore_imf_modules_path = NULL;
static Ecore_Hash *modules = NULL;
void
ecore_imf_module_init(void)
{
char pathname[PATH_MAX];
const char *homedir;
ecore_imf_modules_path = ecore_path_group_new();
snprintf(pathname, sizeof(pathname), "%s/ecore/immodules/",
PACKAGE_LIB_DIR);
ecore_path_group_add(ecore_imf_modules_path, pathname);
homedir = getenv("HOME");
if (homedir)
{
snprintf(pathname, sizeof(pathname), "%s/.ecore/immodules/",
homedir);
ecore_path_group_add(ecore_imf_modules_path, pathname);
}
modules = NULL;
_ecore_imf_module_load_all();
}
void
ecore_imf_module_shutdown(void)
{
if (modules)
{
ecore_hash_destroy(modules);
modules = NULL;
}
ecore_path_group_del(ecore_imf_modules_path);
ecore_imf_modules_path = NULL;
}
Ecore_List *
ecore_imf_module_available_get(void)
{
Ecore_List *values;
unsigned int i = 0;
if (!modules) return NULL;
/* ecore_hash_values() */
values = ecore_list_new();
while (i < ecore_prime_table[modules->size])
{
if (modules->buckets[i])
{
Ecore_Hash_Node *node;
for (node = modules->buckets[i]; node; node = node->next)
ecore_list_append(values, node->value);
}
i++;
}
ecore_list_first_goto(values);
return values;
}
Ecore_IMF_Module *
ecore_imf_module_get(const char *ctx_id)
{
if (!modules) return NULL;
return ecore_hash_get(modules, ctx_id);
}
Ecore_IMF_Context *
ecore_imf_module_context_create(const char *ctx_id)
{
Ecore_IMF_Module *module;
if (!modules) return NULL;
module = ecore_hash_get(modules, ctx_id);
if (module) return module->create();
return NULL;
}
Ecore_List *
ecore_imf_module_context_ids_get(void)
{
if (!modules) return NULL;
return ecore_hash_keys(modules);
}
static void
_ecore_imf_module_load_all(void)
{
Ecore_List *avail;
char *filename;
Ecore_Plugin *plugin;
const Ecore_IMF_Context_Info *info = NULL;
int (*imf_module_init)(const Ecore_IMF_Context_Info **info);
Ecore_IMF_Context *(*imf_module_create)(void);
Ecore_IMF_Module *module;
avail = ecore_plugin_available_get(ecore_imf_modules_path);
if (!avail) return;
ecore_list_first_goto(avail);
while (filename = ecore_list_next(avail))
{
plugin = ecore_plugin_load(ecore_imf_modules_path, filename, NULL);
if (!plugin)
{
fprintf(stderr, "** ecore_imf: Error loading input method plugin %s!\n",
filename);
continue;
}
imf_module_init = ecore_plugin_symbol_get(plugin, "imf_module_init");
if (!imf_module_init || !imf_module_init(&info) || !info)
{
fprintf(stderr, "** ecore_imf: Error initializing input method plugin %s! "
"'imf_module_init' is missing or failed to run!",
filename);
ecore_plugin_unload(plugin);
continue;
}
if (_ecore_imf_modules_exists(info->id))
{
fprintf(stderr, "** ecore_imf: Error loading input method plugin %s! "
"Plugin with id='%s' already exists!",
info->id);
ecore_plugin_unload(plugin);
continue;
}
imf_module_create = ecore_plugin_symbol_get(plugin, "imf_module_create");
if (!imf_module_create)
{
fprintf(stderr, "** ecore_imf: Error setting up input method plugin %s! "
"'imf_module_create' is missing!",
filename);
ecore_plugin_unload(plugin);
continue;
}
_ecore_imf_module_append(plugin, info, imf_module_create);
}
ecore_list_destroy(avail);
}
static void
_ecore_imf_module_append(Ecore_Plugin *plugin,
const Ecore_IMF_Context_Info *info,
Ecore_IMF_Context *(*imf_module_create)(void))
{
Ecore_IMF_Module *module;
if (!modules)
{
modules = ecore_hash_new(ecore_str_hash, ecore_str_compare);
ecore_hash_free_key_cb_set(modules, free);
ecore_hash_free_value_cb_set(modules, (Ecore_Free_Cb) _ecore_imf_module_free);
}
module = malloc(sizeof(Ecore_IMF_Module));
module->plugin = plugin;
module->info = info;
/* cache imf_module_create as it may be used several times */
module->create = imf_module_create;
ecore_hash_set(modules, strdup(info->id), module);
}
static void
_ecore_imf_module_free(Ecore_IMF_Module *module)
{
int (*imf_module_exit)(void);
imf_module_exit = ecore_plugin_symbol_get(module->plugin, "imf_module_exit");
if (imf_module_exit) imf_module_exit();
ecore_plugin_unload(module->plugin);
free(module);
}
static int
_ecore_imf_modules_exists(const char *ctx_id)
{
if (!modules) return 0;
return (ecore_hash_get(modules, ctx_id) != NULL);
}

View File

@ -0,0 +1,36 @@
#ifndef _ECORE_IMF_PRIVATE_H
#define _ECORE_IMF_PRIVATE_H
#include "Ecore_IMF.h"
#include "ecore_private.h"
#define ECORE_MAGIC_CONTEXT 0x56c1b39a
typedef struct _Ecore_IMF_Module Ecore_IMF_Module;
struct _Ecore_IMF_Context
{
ECORE_MAGIC;
const Ecore_IMF_Context_Class *klass;
void *data;
int input_mode;
int (*retrieve_surrounding_func)(void *data, Ecore_IMF_Context *ctx, char **text, int *cursor_pos);
void *retrieve_surrounding_data;
};
struct _Ecore_IMF_Module
{
Ecore_Plugin *plugin;
const Ecore_IMF_Context_Info *info;
Ecore_IMF_Context *(*create)(void);
};
void ecore_imf_module_init(void);
void ecore_imf_module_shutdown(void);
Ecore_List *ecore_imf_module_available_get(void);
Ecore_IMF_Module *ecore_imf_module_get(const char *ctx_id);
Ecore_IMF_Context *ecore_imf_module_context_create(const char *ctx_id);
Ecore_List *ecore_imf_module_context_ids_get(void);
#endif