blob: ec34b054a007aaac7a4a9a069b05e2c4dd8a230d [file] [log] [blame]
requires 2.0.0
%alltop{
/*
* Copyright © 2009 Red Hat, Inc. All rights reserved.
* Copyright © 2009 Ding-Yi Chen <dchen at redhat.com>
*
* This file is part of the ibus-chewing Project.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include <stdlib.h>
#include <libintl.h>
#include <ibus.h>
#include <chewing.h>
#include <string.h>
#include <stdio.h>
#define GETTEXT_PACKAGE "gtk20"
#include <glib/gi18n.h>
#include <gtk/gtk.h>
#include <X11/extensions/XTest.h>
#include <X11/Xlib.h>
#include <ctype.h>
%}
enum CHEWING_KBTYPE{
INVALID=-1,
DEFAULT,
HSU,
IBM,
GIN_YIEH,
ETEN,
ETEN26,
DVORAK,
DVORAK_HSU,
DACHEN_CP26,
HAN_YU
} Chewing:KbType;
enum CHEWING_MODIFIER_SYNC{
DISABLE,
FROM_KEYBOARD,
FROM_IM
} Chewing:Modifier:Sync;
enum CHEWING_INPUT_STYLE{
IN_APPLICATION,
IN_CANDIDATE,
} Chewing:Input:Style;
/**
* ChewingInputMode:
* @BYPASS: Bypass the cursor movement keys.
* @EDITING: Forming Chinese character (in pre-edit buffer).
* @SELECTING: Selecting candidate. Immediately after character is formed.
* @SELECTING_DONE: A candidate is manually selected.
*
* Chewing input (key handling) mode.
* Note for EDITING_ENGLISH:
* It is possible that chewing status bar shows Chinese mode,
* yet still inputting English.
* This mode is for mix-typing English and Chinese.
*/
enum CHEWING_INPUT_MODE{
BYPASS,
EDITING,
SELECTING,
SELECTING_DONE
} Chewing:Input:Mode;
enum CHEWING_OUTPUT_CHARSET{
AUTO,
BIG5,
UTF8
} Chewing:Output:Charset;
/**
* ChewingFlag:
* @PLAIN_CHEWING: Plain chewing mode (non AI).
* @FORCE_LOWERCASE_ENGLISH: Force Lowercase even when CapsLock is on.
*/
enum CHEWING_FLAG{
PLAIN_ZHUYIN= 0x1,
FORCE_LOWERCASE_ENGLISH= 0x2,
NUMPAD_ALWAYS_NUMBER= 0x4,
EASY_SYMBOL_INPUT= 0x8,
} Chewing:Flag;
/**
* EngineStatus:
* @INITIALIZED: Engine is initialized.
*/
enum ENGINE_STATUS{
INITIALIZED= 0x1,
ENABLED= 0x2,
FOCUS_IN= 0x4,
SHOW_CANDIDATE= 0x8,
NEED_COMMIT= 0x10,
FORCE_COMMIT= 0x20,
} Engine:Status;
%h{
// Chromium change: Remove reference to maker-dialog, and stub in the required
// structures and enums here.
//#include "maker-dialog.h"
enum {
MAKER_DIALOG_PROPERTY_FLAG_INVISIBLE =0x1,
MAKER_DIALOG_PROPERTY_FLAG_INSENSITIVE =0x2,
MAKER_DIALOG_PROPERTY_FLAG_INEDITABLE =0x4,
MAKER_DIALOG_PROPERTY_FLAG_HAS_TRANSLATION =0x8,
MAKER_DIALOG_PROPERTY_FLAG_TRANSLATION_WITH_CONTEXT =0x10,
};
typedef guint MakerDialogPropertyFlags;
typedef struct _PropertyContext PropertyContext;
typedef GValue *(* CallbackGetFunc)(PropertyContext *ctx);
typedef void(* CallbackSetFunc)(PropertyContext *ctx, GValue *value);
typedef struct{
GType valueType;
gchar key[30];
gchar pageName[50];
gchar label[200];
gchar defaultValue[100];
const gchar **validValues;
gchar *translationContext;
gint min;
gint max;
CallbackGetFunc getFunc;
CallbackSetFunc setFunc;
MakerDialogPropertyFlags propertyFlags;
gint width;
gint height;
const gchar *tooltip;
gpointer userData;
} PropertySpec;
struct _PropertyContext{
PropertySpec *spec;
gpointer userData; //<! User data to be used in callback.
};
// END Chromium change
#define GCONF_KEY_PREFIX "/desktop/ibus/engine/Chewing/"
/* For easy symbol input work around */
#define EASY_SYMBOL_INPUT_WORK_AROUND
extern PropertySpec propSpecs[];
extern const gchar *page_labels[];
extern const gchar *button_labels[];
extern GtkResponseType button_responses[];
#define ZHUYIN_BUFFER_SIZE 12
#define ibus_chewing_engine_set_status_flag(cengine,f) cengine->_priv->statusFlags |= f
#define ibus_chewing_engine_clear_status_flag(cengine,f) cengine->_priv->statusFlags &= ~f
#ifdef IBUS_1_1
/*
* Dummy data structure for ibus 1.1 and early.
*/
typedef void IBusKeymap;
IBusKeymap *ibus_keymap_get(gchar *keymap_name);
#endif /* IBUS_1_1 */
#define G_DEBUG_MSG(level, msg, args...) if (level<=ibus_chewing_verbose) g_debug(msg, ##args)
%}
%privateheader{
gboolean ibus_chewing_engine_process_key_event(IBusEngine *engine,
guint keyval, guint modifiers);
void ibus_chewing_engine_candidate_clicked(IBusEngine *engine, guint index,
guint button, guint state);
void ibus_config_value_changed(IBusConfig *config, const gchar *section,
const gchar *name, GValue *value, gpointer userData);
#ifndef IBUS_1_1
gboolean ibus_chewing_engine_process_key_event_1_2(IBusEngine *engine,
guint keyval_ignore, guint keycode, guint modifiers);
#endif /* IBUS_1_1 */
%}
%{
extern gboolean ibus_chewing_verbose;
extern IBusConfig *iConfig;
#define IBUS_CHEWING_MAIN
#include "IBusChewingEngine-def.c"
#ifndef IBUS_1_3
IBusKeymap *ibus_keymap_get(gchar *keymap_name){
#ifdef IBUS_1_1
return NULL;
#endif /* IBUS_1_1 */
#ifdef IBUS_1_2
return ibus_keymap_new(keymap_name);
#endif /* IBUS_1_2 */
}
#endif /* IBUS_1_3 */
%}
class IBus:Chewing:Engine from IBus:Engine{
public ChewingContext *context=NULL
destroywith chewing_delete;
public Chewing:Modifier:Sync syncCapsLock_local=CHEWING_MODIFIER_SYNC_FROM_KEYBOARD;
//public GtkWidget *setting_dialog={
//GTK_WIDGET(maker_dialog_new_full(_("Setting"),3,page_labels,1,button_labels,button_responses))};
protected gint selKeys[MAX_SELKEY];
protected ChewingInputMode inputMode=CHEWING_INPUT_MODE_BYPASS;
/* Controlling flags */
protected ChewingFlag flags=0;
private guint statusFlags=0;
/* For easy symbol input work around */
private ChewingInputStyle inputStyle;
protected IBusLookupTable *table=NULL
destroywith ibus_lookup_table_clear;
protected guint tableCursor=0;
protected gboolean tableVisible=FALSE;
protected gulong handler_id = 0;
public IBusProperty *chieng_prop={
g_object_ref_sink (
ibus_property_new("chewing_chieng_prop",PROP_TYPE_NORMAL,
SELF_GET_CLASS(self)->chieng_prop_label_chi,
NULL, NULL, TRUE, TRUE,
PROP_STATE_UNCHECKED, NULL))
}
destroywith g_object_unref;
public IBusProperty *alnumSize_prop={
g_object_ref_sink (
ibus_property_new("chewing_alnumSize_prop",PROP_TYPE_NORMAL,
SELF_GET_CLASS(self)->alnumSize_prop_label_half,
NULL, NULL, TRUE, TRUE,
PROP_STATE_UNCHECKED, NULL))
}
destroywith g_object_unref;
public IBusProperty *settings_prop={
g_object_ref_sink (
ibus_property_new("chewing_settings_prop",PROP_TYPE_TOGGLE,
SELF_GET_CLASS(self)->settings_prop_label,
PKGDATADIR "/icons/settings.png", NULL, TRUE, TRUE,
PROP_STATE_UNCHECKED, NULL))
}
destroywith g_object_unref;
public IBusPropList *prop_list={ g_object_ref_sink (ibus_prop_list_new()) }
destroywith g_object_unref;
public IBusConfig *config=NULL;
protected IBusKeymap *keymap_us={ibus_keymap_get("us")};
private Display *pDisplay = {XOpenDisplay( NULL )}
destroywith XCloseDisplay;
private guint key_last=0;
private gchar zhuyin_latest[ZHUYIN_BUFFER_SIZE];
classwide IBusText *chieng_prop_label_chi={g_object_ref_sink(ibus_text_new_from_static_string(_("Chi")))};
classwide IBusText *chieng_prop_label_eng={g_object_ref_sink(ibus_text_new_from_static_string(_("Eng")))};
classwide IBusText *alnumSize_prop_label_full={g_object_ref_sink(ibus_text_new_from_static_string(_("Full")))};
classwide IBusText *alnumSize_prop_label_half={g_object_ref_sink(ibus_text_new_from_static_string(_("Half")))};
classwide IBusText *settings_prop_label={g_object_ref_sink(ibus_text_new_from_static_string(_("Settings")))};
classwide IBusText *emptyText={g_object_ref_sink(ibus_text_new_from_static_string(""))};
init (self) {
/* initialize the object here */
G_DEBUG_MSG(1,"[I1] init()");
if (!(self->_priv->statusFlags & ENGINE_STATUS_INITIALIZED)){
//maker_dialog_set_verbose_level(MAKER_DIALOG(self->setting_dialog),ibus_chewing_verbose);
gchar buf[100];
g_snprintf(buf,100,"%s/.chewing",getenv("HOME"));
// TODO(chromium): Set this back to CHEWING_DATADIR once it's fixed to the correct directory.
chewing_Init("/usr/share/chewing/", buf);
self->context=chewing_new();
chewing_set_ChiEngMode(self->context,CHINESE_MODE);
self->inputMode=CHEWING_INPUT_MODE_SELECTING_DONE;
/* init properties */
ibus_prop_list_append(self->prop_list,self->chieng_prop);
ibus_prop_list_append(self->prop_list,self->alnumSize_prop);
ibus_prop_list_append(self->prop_list,self->settings_prop);
ibus_chewing_engine_set_status_flag(self,ENGINE_STATUS_INITIALIZED);
}
}
class_init(klass){
#ifdef IBUS_1_1
ibus_engine_class->process_key_event = ibus_chewing_engine_process_key_event;
#else
ibus_engine_class->process_key_event = ibus_chewing_engine_process_key_event_1_2;
#endif /* IBUS_1_1 */
ibus_engine_class->candidate_clicked = ibus_chewing_engine_candidate_clicked;
}
override (G:Object) void
finalize (G:Object *gobject){
Self *self=SELF(gobject);
G_DEBUG_MSG(1,"[I1] finalize()");
if (self->config && self->handler_id) {
g_signal_handler_disconnect(self->config, self->handler_id);
}
}
private void load_setting(self){
#define BUFFER_SIZE_LOCAL 200
G_DEBUG_MSG(3,"[I3] load_setting()");
int i;
//gchar buf[BUFFER_SIZE_LOCAL];
PropertyContext context = {NULL, self};
for (i=0; propSpecs[i].valueType!=G_TYPE_INVALID;i++){
GValue gValue={0};
G_DEBUG_MSG(4,"[I4] load_setting(), i=%d",i);
if (ibus_chewing_config_get_value(self->config, "engine/Chewing",propSpecs[i].key, &gValue)){
// TODO: Read in the config on Chromium OS.
/*switch(propSpecs[i].valueType){
case G_TYPE_BOOLEAN:
buf[0]=(g_value_get_boolean(gValue))? '1' : '0';
buf[1]='\0';
break;
case G_TYPE_UINT:
g_snprintf(buf,BUFFER_SIZE_LOCAL,"%u",
g_value_get_uint(gValue));
break;
case G_TYPE_INT:
g_snprintf(buf,BUFFER_SIZE_LOCAL,"%d",
g_value_get_int(gValue));
break;
case G_TYPE_STRING:
g_strlcpy(buf,g_value_get_string(gValue), BUFFER_SIZE_LOCAL);
break;
default:
break;
}*/
}else{
g_warning("[WW] %s /desktop/ibus/engine/Chewing/%s, %s %s",
_("Warning: cannot load configure key"),
propSpecs[i].key,
(propSpecs[i].defaultValue)? _(" Use default value:") : _(" No default value, skipped.") ,
(propSpecs[i].defaultValue)? propSpecs[i].defaultValue : ""
);
if (propSpecs[i].defaultValue){
g_value_init(&gValue, propSpecs[i].valueType);
switch(propSpecs[i].valueType){
case G_TYPE_BOOLEAN:
g_value_set_boolean(&gValue, '0' == *(propSpecs[i].defaultValue) ? 0 : 1);
break;
case G_TYPE_UINT:
g_value_set_uint(&gValue, atoi(propSpecs[i].defaultValue));
break;
case G_TYPE_INT:
g_value_set_int(&gValue, atoi(propSpecs[i].defaultValue));
break;
case G_TYPE_STRING:
g_value_set_string(&gValue, propSpecs[i].defaultValue);
break;
default:
break;
}
//g_strlcpy(buf,propSpecs[i].defaultValue, BUFFER_SIZE_LOCAL);
}else{
continue;
}
}
/* Add property to dialog */
//maker_dialog_add_property(MAKER_DIALOG(self->setting_dialog),&propSpecs[i],buf,self);
//maker_dialog_apply_widget_value(MAKER_DIALOG(self->setting_dialog),propSpecs[i].key);
propSpecs[i].setFunc(&context, &gValue);
if (G_IS_VALUE(&gValue)) {
g_value_unset(&gValue);
}
}
//for (i=0; page_labels[i]!=NULL;i++){
//maker_dialog_align_labels(MAKER_DIALOG(self->setting_dialog),page_labels[i],1.0f, 0.5f);
//}
//gtk_widget_hide(self->setting_dialog);
#undef BUFFER_SIZE_LOCAL
}
protected void set_lookup_table_label(self,const gchar *labels){
int i,len=strlen(labels);
g_array_set_size(self->table->labels,0);
for(i=0;i<len;i++){
IBusText *text=ibus_text_new_from_unichar((gunichar) labels[i]);
ibus_lookup_table_append_label (self->table,text);
}
}
private gchar *make_preedit_string(self, glong *zhuyin_item_written_ptr){
gchar *buff_str=chewing_buffer_String(self->context);
G_DEBUG_MSG(4, "[I4] make_preedit_string(): chewing_buffer_String=%s ",
buff_str);
int chiSymbolCursor = chewing_cursor_Current(self->context);
int zhuyin_count;
int zhuyin_tone=-1;
gchar *zhuyin_str=chewing_zuin_String(self->context,&zhuyin_count);
*zhuyin_item_written_ptr= (glong) zhuyin_count;
G_DEBUG_MSG(5, "[I5] make_preedit_string(): chewing_zuin_String=%s count=%d inputMode=%d",
zhuyin_str,zhuyin_count,self->inputMode);
switch(self->inputMode){
case CHEWING_INPUT_MODE_EDITING:
g_strlcpy(self->_priv->zhuyin_latest,zhuyin_str,ZHUYIN_BUFFER_SIZE);
zhuyin_tone=0;
break;
case CHEWING_INPUT_MODE_SELECTING:
zhuyin_tone=get_tone(chewing_get_KBType(self->context),self->_priv->key_last);
add_tone(self->_priv->zhuyin_latest,zhuyin_tone);
if (zhuyin_tone>0 ){
if (self->flags & CHEWING_FLAG_PLAIN_ZHUYIN){
/* Open candidate selection window */
if (chewing_get_spaceAsSelection(self->context)){
chewing_handle_Space(self->context);
}else{
chewing_handle_Down(self->context);
}
}
}
break;
case CHEWING_INPUT_MODE_SELECTING_DONE:
self->_priv->zhuyin_latest[0]='\0';
zhuyin_tone=-1;
if (zhuyin_count)
self->inputMode=CHEWING_INPUT_MODE_EDITING;
break;
default:
/* BYPASS */
break;
}
gsize len=strlen(zhuyin_str)+strlen(buff_str);
gchar *preeditBuf=g_new(gchar, len+1);
preeditBuf[0]='\0';
if (chiSymbolCursor>0){
g_utf8_strncpy(preeditBuf, buff_str, chiSymbolCursor);
}
gsize zhuyin_start=strlen(preeditBuf);
/* Inserting zhuyinBuf */
if (zhuyin_count>0){
g_strlcat(preeditBuf,zhuyin_str,len+1);
}
/* Append rest chiSymbolBuf */
g_strlcat(preeditBuf,buff_str+zhuyin_start, len+1);
g_free(buff_str);
g_free(zhuyin_str);
G_DEBUG_MSG(4, "[I4] make_preedit_string(): return preedit=%s zhuyin_latest=%s zhuyin_tone=%d inputMode=%d",
preeditBuf, self->_priv->zhuyin_latest,zhuyin_tone,self->inputMode);
return preeditBuf;
}
private void show_lookup_table(self, gboolean isShow){
ibus_engine_update_lookup_table(IBUS_ENGINE(self),self->table,isShow);
if (isShow){
self->tableVisible = TRUE;
ibus_engine_show_lookup_table(IBUS_ENGINE(self));
ibus_chewing_engine_set_status_flag(self,ENGINE_STATUS_SHOW_CANDIDATE);
}else{
self->tableCursor = 0;
self->tableVisible = FALSE;
ibus_engine_hide_lookup_table(IBUS_ENGINE(self));
ibus_chewing_engine_clear_status_flag(self,ENGINE_STATUS_SHOW_CANDIDATE);
}
}
private void update_lookup_table(self){
if (!self->table){
self->table=ibus_lookup_table_new(1,0,TRUE,TRUE);
g_object_ref_sink(self->table);
}
ibus_lookup_table_clear(self->table);
int choicePerPage=chewing_cand_ChoicePerPage(self->context);
int i=0;
char *candidate=NULL;
IBusText *iText=NULL;
G_DEBUG_MSG(4,"[I4] update_lookup_table() TotalChoice=%d CurrentPage=%d",
chewing_cand_TotalChoice(self->context),chewing_cand_CurrentPage(self->context));
if (chewing_cand_TotalChoice(self->context) >0){
chewing_cand_Enumerate(self->context);
for(i=0;i<choicePerPage;i++){
if (chewing_cand_hasNext(self->context)){
candidate=chewing_cand_String(self->context);
iText=g_object_ref_sink(ibus_text_new_from_string (candidate));
ibus_lookup_table_append_candidate(self->table,iText);
g_free(candidate);
g_object_unref (iText);
}else{
break;
}
}
ibus_lookup_table_set_cursor_pos(self->table, self->tableCursor);
self_show_lookup_table(self, TRUE);
}else{
self_show_lookup_table(self, FALSE);
}
}
/* Apply IBusText attributes */
private IBusText *decorate_preedit(self, gchar *preeditBuf, gint *chiSymbolCursor, gint zhuyin_item_written){
IBusText *iText=g_object_ref_sink(ibus_text_new_from_string(preeditBuf));
*chiSymbolCursor = chewing_cursor_Current(self->context);
G_DEBUG_MSG(4,"[I4] decorate_preedit() chiSymbolCursor=%d preeditBuf=%s statusFlags=%x",
*chiSymbolCursor,preeditBuf, self->_priv->statusFlags);
g_free(preeditBuf);
gint cursorRight=0;
gint charLen=(gint) g_utf8_strlen(iText->text, -1);
switch(self->inputMode){
case CHEWING_INPUT_MODE_SELECTING:
cursorRight=*chiSymbolCursor + MAX(zhuyin_item_written, 1);
break;
case CHEWING_INPUT_MODE_EDITING:
case CHEWING_INPUT_MODE_SELECTING_DONE:
default: /* BYPASS */
cursorRight=*chiSymbolCursor + zhuyin_item_written;
break;
}
G_DEBUG_MSG(5,"[I5] decorate_preedit() charLen=%d cursorRight=%d", charLen, cursorRight);
if (*chiSymbolCursor< cursorRight){
ibus_text_append_attribute (iText, IBUS_ATTR_TYPE_FOREGROUND, 0x00ffffff,
*chiSymbolCursor, cursorRight);
ibus_text_append_attribute (iText, IBUS_ATTR_TYPE_BACKGROUND, 0x00000000,
*chiSymbolCursor, cursorRight);
}
IntervalType it;
chewing_interval_Enumerate(self->context);
while(chewing_interval_hasNext(self->context)){
chewing_interval_Get(self->context,&it);
G_DEBUG_MSG(6,"[I6] decorate_preedit() it.from=%d it.to=%d", it.from, it.to);
if (it.to-it.from >1){
ibus_text_append_attribute (iText, IBUS_ATTR_TYPE_UNDERLINE, IBUS_ATTR_UNDERLINE_DOUBLE,
it.from, it.to);
}
}
ibus_text_append_attribute (iText, IBUS_ATTR_TYPE_UNDERLINE, IBUS_ATTR_UNDERLINE_SINGLE,
0, -1);
return iText;
}
private void update_aux_string(self, IBusText *preeditIText){
G_DEBUG_MSG(4,"[I4] update_aux_string() statusFlags=%x", self->_priv->statusFlags);
IBusText *iText=NULL;
switch (self->_priv->inputStyle){
case CHEWING_INPUT_STYLE_IN_APPLICATION:
if (chewing_aux_Length(self->context)>0){
gchar *aux_string=chewing_aux_String(self->context);
iText=g_object_ref_sink(ibus_text_new_from_string (aux_string));
ibus_engine_update_auxiliary_text(IBUS_ENGINE(self),iText,TRUE);
g_object_unref (iText);
ibus_engine_show_auxiliary_text(IBUS_ENGINE(self));
g_free(aux_string);
}else{
ibus_engine_hide_auxiliary_text(IBUS_ENGINE(self));
}
break;
case CHEWING_INPUT_STYLE_IN_CANDIDATE:
ibus_engine_update_auxiliary_text(IBUS_ENGINE(self),preeditIText,TRUE);
ibus_engine_show_auxiliary_text(IBUS_ENGINE(self));
break;
}
}
private void update_preedit(self, IBusText *preeditIText,gint chiSymbolCursor){
G_DEBUG_MSG(5,"[I5] update_preedit() text=%s statusFlags=%x", preeditIText->text, self->_priv->statusFlags);
switch (self->_priv->inputStyle){
case CHEWING_INPUT_STYLE_IN_APPLICATION:
ibus_engine_update_preedit_text (IBUS_ENGINE(self),preeditIText, chiSymbolCursor, TRUE);
break;
case CHEWING_INPUT_STYLE_IN_CANDIDATE:
ibus_engine_update_preedit_text (IBUS_ENGINE(self),SELF_GET_CLASS(self)->emptyText, 0, TRUE);
break;
}
G_DEBUG_MSG(5,"[I5] update_preedit(): return");
}
protected gboolean update(self){
G_DEBUG_MSG(3,"[I3] update() statusFlags=%x", self->_priv->statusFlags);
self_determine_input_mode(self);
gint chiSymbolCursor;
glong zhuyin_item_written;
self_commit(self);
gchar *preeditBuf=self_make_preedit_string(self, &zhuyin_item_written);
IBusText *iText=self_decorate_preedit(self, preeditBuf, &chiSymbolCursor, zhuyin_item_written);
if (g_object_is_floating(iText)){
g_object_ref_sink(iText);
}
self_update_aux_string(self, iText);
self_update_preedit(self, iText, chiSymbolCursor);
g_object_unref (iText);
uint16 *phoneSeq=(chewing_get_phoneSeqLen(self->context)>0)? chewing_get_phoneSeq(self->context): NULL;
G_DEBUG_MSG(4,"[I4] update() inputMode=%d nPhoneSeq=%d statusFlags=%u",
self->inputMode,
chewing_get_phoneSeqLen(self->context),
self->_priv->statusFlags);
if (phoneSeq){
int i=0;
for(i=0;i<chewing_get_phoneSeqLen(self->context);i++){
G_DEBUG_MSG(5,"[I5] update() phoneSeq[%d]=%x",i,phoneSeq[i]);
}
free(phoneSeq);
}
self_update_lookup_table(self);
//self_commit(self);
gboolean ret=TRUE;
if (chewing_keystroke_CheckAbsorb(self->context)){
ret=TRUE;
}else if (chewing_keystroke_CheckIgnore(self->context)){
ret=FALSE;
}
G_DEBUG_MSG(4,"[I4] update() return %s",(ret)? "TRUE": "FALSE");
return ret;
}
protected void refresh_property(self,const gchar *prop_name){
G_DEBUG_MSG(2,"[I2] refresh_property(%s)",prop_name);
if (strcmp(prop_name,"chewing_chieng_prop")==0){
if (chewing_get_ChiEngMode(self->context)){
/* Chinese */
ibus_property_set_label(self->chieng_prop,SELF_GET_CLASS(self)->chieng_prop_label_chi);
}else{
/* English */
ibus_property_set_label(self->chieng_prop,SELF_GET_CLASS(self)->chieng_prop_label_eng);
}
ibus_engine_update_property(IBUS_ENGINE(self),self->chieng_prop);
}else if (strcmp(prop_name,"chewing_alnumSize_prop")==0){
if (chewing_get_ShapeMode(self->context)){
/* Full-Sized Shape */
ibus_property_set_label(self->alnumSize_prop,SELF_GET_CLASS(self)->alnumSize_prop_label_full);
}else{
/* Half-Sized Shape */
ibus_property_set_label(self->alnumSize_prop,SELF_GET_CLASS(self)->alnumSize_prop_label_half);
}
ibus_engine_update_property(IBUS_ENGINE(self),self->alnumSize_prop);
}
}
/**
* refresh_property_list:
* @self: this instances.
*
* Refresh the property list (language bar).
*/
public void refresh_property_list(self){
self_refresh_property(self,"chewing_chieng_prop");
self_refresh_property(self,"chewing_alnumSize_prop");
self_refresh_property(self,"chewing_settings_prop");
if (self->_priv->statusFlags & (ENGINE_STATUS_ENABLED | ENGINE_STATUS_FOCUS_IN)){
ibus_engine_register_properties(IBUS_ENGINE(self),self->prop_list);
IBUS_ENGINE_GET_CLASS(self)->property_show(IBUS_ENGINE(self),"chewing_chieng_prop");
IBUS_ENGINE_GET_CLASS(self)->property_show(IBUS_ENGINE(self),"chewing_alnumSize_prop");
IBUS_ENGINE_GET_CLASS(self)->property_show(IBUS_ENGINE(self),"chewing_settings_prop");
}
}
/**
* hide_property_list:
* @self: this instances.
*
* Hide the property list (language bar).
*/
public void hide_property_list(self){
IBUS_ENGINE_GET_CLASS(self)->property_hide(IBUS_ENGINE(self),"chewing_chieng_prop");
IBUS_ENGINE_GET_CLASS(self)->property_hide(IBUS_ENGINE(self),"chewing_alnumSize_prop");
IBUS_ENGINE_GET_CLASS(self)->property_hide(IBUS_ENGINE(self),"chewing_settings_prop");
}
/**
* save_config:
* @self: this instances.
* @key_suffix: key to be set.
* @returns: TRUE if successful, FALSE otherwise.
*
* Save the property value to disk.
*/
public gboolean save_config(self, const gchar *key_suffix){
G_DEBUG_MSG(1,"[I1] save_config(%s,-)",key_suffix);
// GValue gValue={0};
// TODO: Save the config on Chromium OS.
//maker_dialog_get_widget_value(MAKER_DIALOG(self->setting_dialog),key_suffix,&gValue);
//return ibus_config_set_value (self->config,"engine/Chewing",key_suffix,&gValue);
return TRUE;
}
/**
* save_config_all:
* @self: this instances.
* @key_suffix: key to be set.
* @returns: TRUE if all successful, FALSE otherwise.
*
* Save alll property values to disk.
*/
public gboolean save_config_all(self){
int i;
gboolean success=TRUE;
for(i=0;propSpecs[i].valueType!=G_TYPE_INVALID;i++){
if (!self_save_config(self,propSpecs[i].key)){
success=FALSE;
}
}
return success;
}
protected gboolean is_selectKey(self, guint keyval){
int j;
for (j=0;j< MAX_SELKEY;j++){
if (self->selKeys[j]==keyval){
return TRUE;
}
}
return FALSE;
}
protected void set_selKeys_string(self,const gchar* selKeys_str){
int j;
int len_min= MIN(strlen(selKeys_str), MAX_SELKEY);
for (j=0;j< len_min;j++){
self->selKeys[j]=(int) selKeys_str[j];
}
chewing_set_selKey(self->context, self->selKeys,len_min);
}
private IBusProperty* get_iBusProperty(self, const gchar *prop_name){
if (strcmp(prop_name,"chewing_chieng_prop")==0){
return self->chieng_prop;
}else if (strcmp(prop_name,"chewing_alnumSize_prop")==0){
return self->alnumSize_prop;
}else if (strcmp(prop_name,"chewing_settings_prop")==0){
return self->settings_prop;
}
G_DEBUG_MSG(2,"[I2] get_iBusProperty(%s): NULL is returned",prop_name);
return NULL;
}
protected void handle_Default(self, guint keyval, gboolean shiftPressed){
G_DEBUG_MSG(2,"[I2] handle_Default(-,%u) plainZhuyin=%s inputMode=%d",
keyval,(self->flags & CHEWING_FLAG_PLAIN_ZHUYIN)? "TRUE": "FALSE",self->inputMode);
ibus_chewing_engine_set_status_flag(self, ENGINE_STATUS_NEED_COMMIT);
#ifdef EASY_SYMBOL_INPUT_WORK_AROUND
if (self->flags & CHEWING_FLAG_EASY_SYMBOL_INPUT){
/* If shift is pressed, turn on the easySymbolInput, turn off
* otherwise
*/
chewing_set_easySymbolInput(self->context,(shiftPressed)? 1:0);
}
#endif
if (self->flags & CHEWING_FLAG_FORCE_LOWERCASE_ENGLISH){
if (isupper(keyval) && !shiftPressed){
keyval=tolower(keyval);
}else if (islower(keyval) && shiftPressed){
keyval=toupper(keyval);
}
}
chewing_handle_Default(self->context,keyval);
if (self->flags & CHEWING_FLAG_PLAIN_ZHUYIN){
if (self_is_selectKey(self,self->_priv->key_last) &&
self->inputMode==CHEWING_INPUT_MODE_SELECTING){
chewing_handle_Enter(self->context);
self->inputMode= CHEWING_INPUT_MODE_SELECTING_DONE;
}
}
}
protected void handle_candidate_clicked(self, guint index, guint button, guint state){
if (index >= chewing_get_candPerPage(self->context)) {
G_DEBUG_MSG(3,"[I3] handle_cadidate_clicked(-, %u, %u, %u) ... index out of range.", index, button, state);
return;
}
if (self->inputMode==CHEWING_INPUT_MODE_SELECTING_DONE){
int* keys = chewing_get_selKey(self->context);
if (!keys) {
G_DEBUG_MSG(3,"[I3] handle_cadidate_clicked(-, %u, %u, %u) ... No sel keys.", index, button, state);
return;
}
ibus_chewing_engine_set_status_flag(self, ENGINE_STATUS_NEED_COMMIT);
chewing_handle_Default(self->context, keys[index]);
chewing_free(keys);
self_update(self);
} else {
G_DEBUG_MSG(3,"[I3] handle_cadidate_clicked() ... Wrong mode: %u", self->inputMode);
}
}
protected void handle_config_value_changed(self, const gchar *section, const gchar *name, GValue *value){
int i;
PropertyContext context = {NULL, self};
G_DEBUG_MSG(4,"[I4] handle_config_value_changed(), section=%s, name=%s",section,name);
// Filter out config values that don't apply to chewing.
if (strcmp(section, "engine/Chewing")) {
return;
}
// Search through the property definitions to see if we use this value.
for (i=0; propSpecs[i].valueType!=G_TYPE_INVALID;i++){
if (0 == strcmp(propSpecs[i].key, name)){
// Call the assignment function associated with the config value.
propSpecs[i].setFunc(&context, value);
return;
}
}
}
protected int current_num_candidate(self){
if (chewing_cand_TotalChoice(self->context) >=
(chewing_cand_CurrentPage(self->context)+1) * chewing_cand_ChoicePerPage(self->context)) {
return chewing_cand_ChoicePerPage(self->context);
} else {
return chewing_cand_TotalChoice(self->context) % chewing_cand_ChoicePerPage(self->context);
}
}
protected void cursor_prev(self){
if (self->tableCursor > 0){
--self->tableCursor;
} else {
chewing_handle_Left(self->context);
self->tableCursor = self_current_num_candidate(self)-1;
}
}
protected void cursor_next(self){
if (self->tableCursor < self_current_num_candidate(self)-1){
++self->tableCursor;
} else {
chewing_handle_Right(self->context);
self->tableCursor = 0;
}
}
protected void cursor_select(self){
self_handle_candidate_clicked(self, self->tableCursor, 0, 0);
}
/*
* determine_input_mode:
*
* Determine input mode.
*/
private void determine_input_mode(self){
gint zhuyin_count=-1;
gchar *str_ptr=chewing_zuin_String(self->context,&zhuyin_count);
G_DEBUG_MSG(3, "[I3] determine_input_mode(): chewing_zuin_String=%s count=%d inputMode=%d",
str_ptr,zhuyin_count,self->inputMode);
int zhuyin_tone=-1;
if (zhuyin_count>0){
/* Incomplete Character*/
self->inputMode=CHEWING_INPUT_MODE_EDITING;
}else{
/* Character/Phrase is completed. */
if (self->inputMode==CHEWING_INPUT_MODE_EDITING){
/* In EDITING mode */
zhuyin_tone=get_tone(chewing_get_KBType(self->context),self->_priv->key_last);
if (zhuyin_tone>0 ){
if (self->flags & CHEWING_FLAG_PLAIN_ZHUYIN){
/* For plain zhuyin, Enter SELECTING mode */
self->inputMode=CHEWING_INPUT_MODE_SELECTING;
}else{
/* For normal zhuyin, Enter SELECTING mode */
self->inputMode=CHEWING_INPUT_MODE_SELECTING_DONE;
}
}
}else if (self->inputMode==CHEWING_INPUT_MODE_SELECTING_DONE){
/* In SELECTING_DONE mode */
/* One of selection keys is pressed */
}else{
/* In SELECTING mode */
}
}
if (chewing_buffer_Len(self->context)+ zhuyin_count==0){
/* If preedit buffer is empty, then enter BYPASS mode.*/
/* So cursor keys can be used freely. */
self->inputMode=CHEWING_INPUT_MODE_BYPASS;
self->_priv->zhuyin_latest[0]='\0';
}
g_free(str_ptr);
G_DEBUG_MSG(3, "[I3] determine_input_mode() return: zhuyin_latest=%s zhuyin_tone=%d inputMode=%d",
self->_priv->zhuyin_latest,zhuyin_tone,self->inputMode);
}
/* commit string */
protected gboolean commit(self){
gint commit=chewing_commit_Check(self->context);
G_DEBUG_MSG(2,"[I2] commit() %s statusFlags=%x", (commit) ? "TRUE": "FALSE", self->_priv->statusFlags);
if ((self->_priv->statusFlags & ENGINE_STATUS_NEED_COMMIT) && commit){
IBusText *iText=NULL;
gchar *commit_string=chewing_commit_String(self->context);
G_DEBUG_MSG(3,"[I3] commit() commit_string=%s", commit_string);
iText=g_object_ref_sink(ibus_text_new_from_string(commit_string));
ibus_engine_commit_text(IBUS_ENGINE(self),iText);
g_free(commit_string);
g_object_unref(iText);
if (!chewing_buffer_Check(self->context)){
/* Buffer is clean */
ibus_chewing_engine_clear_status_flag(self, ENGINE_STATUS_NEED_COMMIT | ENGINE_STATUS_FORCE_COMMIT );
}else if (self->_priv->statusFlags & ENGINE_STATUS_FORCE_COMMIT){
/* Flush the buffer */
chewing_handle_Enter(self->context);
commit_string=chewing_commit_String(self->context);
iText=g_object_ref_sink(ibus_text_new_from_string(commit_string));
ibus_engine_commit_text(IBUS_ENGINE(self),iText);
g_free(commit_string);
g_object_unref(iText);
ibus_chewing_engine_clear_status_flag(self, ENGINE_STATUS_FORCE_COMMIT );
}
}
return commit;
}
protected void force_commit(self){
G_DEBUG_MSG(3,"[I3] force_commit() buffer=%d, commit=%d statusFlags=%x",
chewing_buffer_Check(self->context),chewing_commit_Check(self->context), self->_priv->statusFlags);
/* Remove the incomplete zhuyin symbol */
if (self->inputMode==CHEWING_INPUT_MODE_EDITING)
chewing_handle_Esc(self->context);
if (chewing_buffer_Check(self->context)){
if (!chewing_commit_Check(self->context)){
/* Close candidate window */
if (self->_priv->statusFlags & ENGINE_STATUS_SHOW_CANDIDATE){
chewing_handle_Esc(self->context);
}
chewing_handle_Enter(self->context);
}
ibus_chewing_engine_set_status_flag(self, ENGINE_STATUS_NEED_COMMIT | ENGINE_STATUS_FORCE_COMMIT);
self_update(self);
}
}
/*============================================
* Overridden Parent (IBusEngine) methods
*/
override (IBus:Engine) void
reset(IBus:Engine *engine){
G_DEBUG_MSG(1,"[I1] reset");
Self *self=SELF(engine);
/* Always clean buffer */
chewing_handle_Esc(self->context);
ibus_chewing_engine_clear_status_flag(self, ENGINE_STATUS_NEED_COMMIT | ENGINE_STATUS_FORCE_COMMIT );
ibus_lookup_table_clear(self->table);
/* Save KBType type, ChiEng, and ShapeMode becaue chewing_Reset() will reset them to default.
*/
int kbType=chewing_get_KBType(self->context);
int ChiEngMode=chewing_get_ChiEngMode(self->context);
int ShapeMode=chewing_get_ShapeMode(self->context);
chewing_Reset(self->context);
chewing_set_KBType(self->context,kbType);
chewing_set_ChiEngMode(self->context,ChiEngMode);
chewing_set_ShapeMode(self->context,ShapeMode);
ibus_engine_hide_auxiliary_text(IBUS_ENGINE(engine));
ibus_engine_hide_lookup_table(IBUS_ENGINE(self));
}
override (IBus:Engine) void
page_up(IBus:Engine *engine){
Self *self=SELF(engine);
chewing_handle_PageUp(self->context);
self_update(self);
}
override (IBus:Engine) void
page_down(IBus:Engine *engine){
Self *self=SELF(engine);
chewing_handle_PageDown(self->context);
self_update(self);
}
override (IBus:Engine) void
cursor_up(IBus:Engine *engine){
Self *self=SELF(engine);
if (self->tableVisible){
self_cursor_prev(self);
self_update(self);
ibus_lookup_table_set_cursor_pos(self->table, self->tableCursor);
ibus_engine_update_lookup_table(IBUS_ENGINE(self),self->table,TRUE);
} else {
chewing_handle_Up(self->context);
self_update(self);
}
}
override (IBus:Engine) void
cursor_down(IBus:Engine *engine){
Self *self=SELF(engine);
if (self->tableVisible){
self_cursor_next(self);
self_update(self);
ibus_lookup_table_set_cursor_pos(self->table, self->tableCursor);
ibus_engine_update_lookup_table(IBUS_ENGINE(self),self->table,TRUE);
} else {
chewing_handle_Down(self->context);
self_update(self);
}
}
override (IBus:Engine) void
enable(IBus:Engine *engine){
G_DEBUG_MSG(2,"[I2] enable()");
Self *self=SELF(engine);
if (!self->config){
self->config=iConfig;
self_load_setting(self);
}
if (!self->handler_id) {
// Watch the ibus config service for config changes. If one of chewing's values
// changes, the local state needs to be updated to match.
self->handler_id = g_signal_connect(self->config, "value-changed",
G_CALLBACK(ibus_config_value_changed), self);
}
G_DEBUG_MSG(2,"[I2] enable() config = %p handler_id = %lu", self->config, self->handler_id);
self_refresh_property_list(self);
self->inputMode=CHEWING_INPUT_MODE_SELECTING_DONE;
ibus_chewing_engine_set_status_flag(self, ENGINE_STATUS_ENABLED);
}
override (IBus:Engine) void
disable(IBus:Engine *engine){
G_DEBUG_MSG(2,"[I2] disable()");
Self *self=SELF(engine);
self_force_commit(self);
self_hide_property_list(self);
self->inputMode=CHEWING_INPUT_MODE_BYPASS;
ibus_chewing_engine_clear_status_flag(self,ENGINE_STATUS_ENABLED);
}
override (IBus:Engine) void
focus_in(IBus:Engine *engine){
Self *self=SELF(engine);
/* Sync Caps_Lock and ChiEngMode */
guint modifiers=keyModifier_get(self->_priv->pDisplay);
gint caps_is_lock=(modifiers & IBUS_LOCK_MASK)!=0;
G_DEBUG_MSG(2,"[I2] focus_in(): statusFlags=%d ChiEng=%d IBUS_LOCK=%d",
self->_priv->statusFlags,
chewing_get_ChiEngMode(self->context),caps_is_lock);
if (chewing_get_ChiEngMode(self->context)==caps_is_lock){
/* Caps_lock and ChiEngMode does not agree each other */
switch(self->syncCapsLock_local){
case CHEWING_MODIFIER_SYNC_FROM_KEYBOARD:
chewing_set_ChiEngMode(self->context,!caps_is_lock);
break;
case CHEWING_MODIFIER_SYNC_FROM_IM:
/* fake event won't go through process_key_event */
key_send_fake_event(IBUS_Caps_Lock,self->_priv->pDisplay);
break;
default:
g_warning("Caps_lock and ChiEngMode does not agree each other!");
break;
}
}
self_refresh_property_list(self);
self_update(self);
ibus_chewing_engine_set_status_flag(self, ENGINE_STATUS_FOCUS_IN);
G_DEBUG_MSG(4,"[I4] focus_in(): return");
}
override (IBus:Engine) void
focus_out(IBus:Engine *engine){
Self *self=SELF(engine);
G_DEBUG_MSG(2,"[I2] focus_out(): statusFlags=%d",self->_priv->statusFlags);
self_force_commit(self);
ibus_chewing_engine_clear_status_flag(self, ENGINE_STATUS_FOCUS_IN);
G_DEBUG_MSG(5,"[I5] focus_out(): return");
}
override (IBus:Engine) void
property_activate(IBus:Engine *engine, const gchar *prop_name, guint prop_state){
G_DEBUG_MSG(2,"[I2] property_activate(-, %s, %u)", prop_name, prop_state);
Self *self=SELF(engine);
gboolean needRefresh=TRUE;
if (strcmp(prop_name,"chewing_chieng_prop")==0){
/* Toggle Chinese <-> English */
chewing_set_ChiEngMode(self->context, !chewing_get_ChiEngMode(self->context));
}else if (strcmp(prop_name,"chewing_alnumSize_prop")==0){
/* Toggle Full <-> Half */
chewing_set_ShapeMode(self->context, !chewing_get_ShapeMode(self->context));
//}else if (strcmp(prop_name,"chewing_settings_prop")==0){
// if (self->settings_prop->state==PROP_STATE_UNCHECKED){
// if (gtk_dialog_run(GTK_DIALOG(self->setting_dialog))==GTK_RESPONSE_OK){
// self_save_config_all(self);
// }
// gtk_widget_hide(self->setting_dialog);
// self->settings_prop->state=PROP_STATE_UNCHECKED;
// }
}else{
G_DEBUG_MSG(2,"[I2] property_activate(-, %s, %u) not recognized",prop_name, prop_state);
needRefresh=FALSE;
}
if (needRefresh)
self_refresh_property(self,prop_name);
}
override (IBus:Engine) void
property_show(IBus:Engine *engine, const gchar *prop_name){
G_DEBUG_MSG(2,"[I2] property_show(-, %s)",prop_name);
Self *self=SELF(engine);
IBusProperty *prop=self_get_iBusProperty(self, prop_name);
ibus_property_set_visible(prop,TRUE);
ibus_engine_update_property(engine,prop);
}
override (IBus:Engine) void
property_hide(IBus:Engine *engine, const gchar *prop_name){
G_DEBUG_MSG(2,"[I2] property_hide(-, %s)",prop_name);
Self *self=SELF(engine);
IBusProperty *prop=self_get_iBusProperty(self, prop_name);
ibus_property_set_visible(prop,FALSE);
ibus_engine_update_property(engine,prop);
}
}
%{
#include "IBusChewingEngine-keys.c"
%}