blob: a98bb9c9e48d60b74923454dcf20fac5fcfcacb6 [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{
#include "maker-dialog.h"
#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);
#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;
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"));
chewing_Init(CHEWING_DATADIR, 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;
}
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_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){
ibus_engine_show_lookup_table(IBUS_ENGINE(self));
ibus_chewing_engine_set_status_flag(self,ENGINE_STATUS_SHOW_CANDIDATE);
}else{
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;
}
}
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 + MAX(zhuyin_item_written, 1);
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);
}
}
/*
* 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);
if (self->_priv->statusFlags & ENGINE_STATUS_NEED_COMMIT){
/* Force commit non-empty preedit buffer */
self_force_commit(self);
}
ibus_lookup_table_clear(self->table);
/* Save KBType type, becaue chewing_Reset() will reset it to default.
*/
int kbType=chewing_get_KBType(self->context);
chewing_Reset(self->context);
chewing_set_KBType(self->context,kbType);
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);
chewing_handle_Up(self->context);
self_update(self);
}
override (IBus:Engine) void
cursor_down(IBus:Engine *engine){
Self *self=SELF(engine);
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){
/* connections_list is not avail in init, so we put it here */
GList *connections_list=ibus_service_get_connections(IBUS_SERVICE(engine));
g_assert(connections_list);
g_assert(connections_list->data);
IBusConnection *iConnection=(IBusConnection *) connections_list->data;
self->config=ibus_config_new(iConnection);
self_load_setting(self);
}
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"
%}