mirror of
https://github.com/Gnucash/gnucash.git
synced 2025-02-25 18:55:30 -06:00
Bug #605802: Fix input of Japanese characters in register with SCIM, IIIMF and XIM
Patch by Yasuaki Taniguchi. Revised and extended version of r18638. The main functions are as follows: (1) synchronization of preedit string between the register window and sheet->entry, (2) application to pango attributes to preedit string in the register window, (3) include scroll offset patch (id=153514), (4) include preedit string rollback patch (id=153518), (5) fix formula and account cells input problem which Christian pointed out, (6) surpress quick-fill when preedit string exists, (7) fix Windows IME problem. (8) Fix quick-fill problem. git-svn-id: svn+ssh://svn.gnucash.org/repo/gnucash/trunk@18713 57a11ea4-9604-0410-9ed3-97b8803252fd
This commit is contained in:
parent
e1960b4103
commit
a9e2a574f0
@ -184,8 +184,10 @@ gnc_item_edit_draw_info (GncItemEdit *item_edit, int x, int y, TextDrawInfo *inf
|
||||
const gchar *text;
|
||||
PangoRectangle strong_pos;
|
||||
PangoAttribute *attr;
|
||||
PangoAttrList *attr_list;
|
||||
PangoAttrList *attr_list;
|
||||
GnucashSheet *sheet;
|
||||
|
||||
sheet = GNUCASH_SHEET (item_edit->sheet);
|
||||
style = item_edit->style;
|
||||
table = item_edit->sheet->table;
|
||||
|
||||
@ -233,6 +235,17 @@ gnc_item_edit_draw_info (GncItemEdit *item_edit, int x, int y, TextDrawInfo *inf
|
||||
|
||||
info->layout = gtk_widget_create_pango_layout (GTK_WIDGET (item_edit->sheet), text);
|
||||
|
||||
/* IMContext attributes*/
|
||||
if (sheet->preedit_length && sheet->preedit_attrs != NULL) {
|
||||
PangoAttrList *tmp_attrs = pango_attr_list_new ();
|
||||
pango_attr_list_splice (tmp_attrs, sheet->preedit_attrs,
|
||||
g_utf8_offset_to_pointer (text, sheet->preedit_start_position) - text ,
|
||||
g_utf8_offset_to_pointer (text, sheet->preedit_start_position + sheet->preedit_char_length) - text);
|
||||
pango_layout_set_attributes (info->layout, tmp_attrs);
|
||||
pango_attr_list_unref (tmp_attrs);
|
||||
}
|
||||
|
||||
|
||||
/* Selection */
|
||||
if (start_pos != end_pos)
|
||||
{
|
||||
@ -298,6 +311,18 @@ gnc_item_edit_draw_info (GncItemEdit *item_edit, int x, int y, TextDrawInfo *inf
|
||||
}
|
||||
|
||||
gnc_item_edit_update_offset (item_edit, info);
|
||||
|
||||
/* Calcurate IMContext aux window position */
|
||||
{
|
||||
gint xoff, yoff;
|
||||
GdkRectangle rect;
|
||||
rect = info->cursor_rect;
|
||||
gnome_canvas_get_scroll_offsets(GNOME_CANVAS(sheet), &xoff, &yoff);
|
||||
rect.x += (x - xoff + item_edit->x_offset);
|
||||
rect.y += (y - yoff);
|
||||
gtk_im_context_set_cursor_location (sheet->im_context, &rect);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -40,6 +40,7 @@
|
||||
#include "gnucash-style.h"
|
||||
#include "gnucash-header.h"
|
||||
#include "gnucash-item-edit.h"
|
||||
#include "split-register.h"
|
||||
#include "gnc-engine.h" // For debugging, e.g. ENTER(), LEAVE()
|
||||
|
||||
#define DEFAULT_REGISTER_HEIGHT 400
|
||||
@ -83,7 +84,19 @@ static void gnucash_sheet_deactivate_cursor_cell (GnucashSheet *sheet);
|
||||
static void gnucash_sheet_activate_cursor_cell (GnucashSheet *sheet,
|
||||
gboolean changed_cells);
|
||||
static void gnucash_sheet_stop_editing (GnucashSheet *sheet);
|
||||
|
||||
static void gnucash_sheet_im_context_reset (GnucashSheet *sheet);
|
||||
static void gnucash_sheet_commit_cb (GtkIMContext *context, const gchar *str,
|
||||
GnucashSheet *sheet);
|
||||
static void gnucash_sheet_preedit_changed_cb (GtkIMContext *context,
|
||||
GnucashSheet *sheet);
|
||||
static gboolean gnucash_sheet_retrieve_surrounding_cb (GtkIMContext *context,
|
||||
GnucashSheet *sheet);
|
||||
static gboolean gnucash_sheet_delete_surrounding_cb (GtkIMContext *context,
|
||||
gint offset,
|
||||
gint n_chars,
|
||||
GnucashSheet *sheet);
|
||||
static gboolean gnucash_sheet_check_direct_update_cell(GnucashSheet *sheet,
|
||||
const VirtualLocation virt_loc);
|
||||
|
||||
/** Implementation *****************************************************/
|
||||
|
||||
@ -191,15 +204,35 @@ gnucash_sheet_hide_editing_cursor (GnucashSheet *sheet)
|
||||
static void
|
||||
gnucash_sheet_stop_editing (GnucashSheet *sheet)
|
||||
{
|
||||
/* Rollback an uncommitted string if it exists *
|
||||
* *before* disconnecting signal handlers. */
|
||||
gnucash_sheet_im_context_reset(sheet);
|
||||
|
||||
if (sheet->insert_signal != 0)
|
||||
g_signal_handler_disconnect (G_OBJECT(sheet->entry),
|
||||
sheet->insert_signal);
|
||||
if (sheet->delete_signal != 0)
|
||||
g_signal_handler_disconnect (G_OBJECT(sheet->entry),
|
||||
sheet->delete_signal);
|
||||
|
||||
if (sheet->commit_signal != 0)
|
||||
g_signal_handler_disconnect (G_OBJECT(sheet->im_context),
|
||||
sheet->commit_signal);
|
||||
if (sheet->preedit_changed_signal != 0)
|
||||
g_signal_handler_disconnect (G_OBJECT(sheet->im_context),
|
||||
sheet->preedit_changed_signal);
|
||||
if (sheet->retrieve_surrounding_signal != 0)
|
||||
g_signal_handler_disconnect (G_OBJECT(sheet->im_context),
|
||||
sheet->retrieve_surrounding_signal);
|
||||
if (sheet->delete_surrounding_signal != 0)
|
||||
g_signal_handler_disconnect (G_OBJECT(sheet->im_context),
|
||||
sheet->delete_surrounding_signal);
|
||||
sheet->insert_signal = 0;
|
||||
sheet->delete_signal = 0;
|
||||
sheet->commit_signal = 0;
|
||||
sheet->preedit_changed_signal = 0;
|
||||
sheet->retrieve_surrounding_signal = 0;
|
||||
sheet->delete_surrounding_signal = 0;
|
||||
sheet->direct_update_cell = FALSE;
|
||||
|
||||
gnucash_sheet_hide_editing_cursor (sheet);
|
||||
|
||||
@ -270,11 +303,12 @@ gnucash_sheet_activate_cursor_cell (GnucashSheet *sheet,
|
||||
gnucash_sheet_redraw_block (sheet, virt_loc.vcell_loc);
|
||||
else
|
||||
{
|
||||
gnucash_sheet_im_context_reset(sheet);
|
||||
gnucash_sheet_start_editing_at_cursor (sheet);
|
||||
|
||||
gtk_editable_set_position (editable, cursor_pos);
|
||||
|
||||
gtk_editable_select_region (editable, start_sel, end_sel);
|
||||
sheet->direct_update_cell =
|
||||
gnucash_sheet_check_direct_update_cell (sheet, virt_loc);
|
||||
}
|
||||
|
||||
gtk_widget_grab_focus (GTK_WIDGET(sheet));
|
||||
@ -657,6 +691,10 @@ gnucash_sheet_finalize (GObject *object)
|
||||
if (G_OBJECT_CLASS (sheet_parent_class)->finalize)
|
||||
(*G_OBJECT_CLASS (sheet_parent_class)->finalize)(object);
|
||||
|
||||
/* Clean up IMContext and unref */
|
||||
gnucash_sheet_im_context_reset(sheet);
|
||||
g_object_unref (sheet->im_context);
|
||||
|
||||
/* This has to come after the parent destroy, so the item edit
|
||||
destruction can do its disconnects. */
|
||||
g_object_unref (sheet->entry);
|
||||
@ -674,6 +712,8 @@ gnucash_sheet_realize (GtkWidget *widget)
|
||||
window = widget->window;
|
||||
gdk_window_set_back_pixmap (GTK_LAYOUT (widget)->bin_window,
|
||||
NULL, FALSE);
|
||||
gtk_im_context_set_client_window( GNUCASH_SHEET (widget)->im_context,
|
||||
window);
|
||||
}
|
||||
|
||||
|
||||
@ -947,29 +987,63 @@ gnucash_sheet_insert_cb (GtkWidget *widget,
|
||||
{
|
||||
retval = old_text;
|
||||
|
||||
/* reset IMContext if disallowed chars and clear preedit*/
|
||||
gnucash_sheet_im_context_reset(sheet);
|
||||
/* the entry was disallowed, so we stop the insert signal */
|
||||
g_signal_stop_emission_by_name (G_OBJECT (sheet->entry),
|
||||
"insert_text");
|
||||
}
|
||||
if (*position < 0)
|
||||
*position = g_utf8_strlen(retval, -1);
|
||||
|
||||
/* sync cursor position and selection to preedit if it exists */
|
||||
if (sheet->preedit_length) {
|
||||
gtk_editable_set_position (editable,
|
||||
sheet->preedit_start_position
|
||||
+ sheet->preedit_cursor_position);
|
||||
}
|
||||
else if (*position < 0)
|
||||
*position = g_utf8_strlen(retval, -1);
|
||||
|
||||
#if GTK_ALLOWED_SELECTION_WITHIN_INSERT_SIGNAL
|
||||
gtk_editable_select_region (editable, start_sel, end_sel);
|
||||
#else
|
||||
{
|
||||
select_info *info;
|
||||
if (start_sel != end_sel) {
|
||||
info = g_malloc(sizeof(*info));
|
||||
info->editable = editable;
|
||||
info->start_sel = start_sel;
|
||||
info->end_sel = end_sel;
|
||||
g_timeout_add(/*ASAP*/ 1,
|
||||
(GSourceFunc)gnucash_sheet_select_data_cb,
|
||||
info);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
if (sheet->preedit_length
|
||||
&& sheet->preedit_selection_length != 0) {
|
||||
gtk_editable_select_region (editable,
|
||||
sheet->preedit_start_position
|
||||
+ sheet->preedit_char_length,
|
||||
sheet->preedit_start_position
|
||||
+ sheet->preedit_char_length
|
||||
+ sheet->preedit_selection_length);
|
||||
}
|
||||
else
|
||||
gtk_editable_select_region (editable, start_sel, end_sel);
|
||||
#else /* !GTK_ALLOWED_SELECTION_WITHIN_INSERT_SIGNAL */
|
||||
if (sheet->preedit_length
|
||||
&& sheet->preedit_selection_length != 0) {
|
||||
select_info *info;
|
||||
|
||||
info = g_malloc(sizeof(*info));
|
||||
info->editable = editable;
|
||||
info->start_sel = sheet->preedit_start_position
|
||||
+ sheet->preedit_char_length;
|
||||
info->end_sel = sheet->preedit_start_position
|
||||
+ sheet->preedit_char_length
|
||||
+ sheet->preedit_selection_length;
|
||||
g_timeout_add(/*ASAP*/ 1,
|
||||
(GSourceFunc)gnucash_sheet_select_data_cb,
|
||||
info);
|
||||
|
||||
} else if (start_sel != end_sel) {
|
||||
select_info *info;
|
||||
|
||||
info = g_malloc(sizeof(*info));
|
||||
info->editable = editable;
|
||||
info->start_sel = start_sel;
|
||||
info->end_sel = end_sel;
|
||||
g_timeout_add(/*ASAP*/ 1,
|
||||
(GSourceFunc)gnucash_sheet_select_data_cb,
|
||||
info);
|
||||
}
|
||||
#endif /* GTK_ALLOWED_SELECTION_WITHIN_INSERT_SIGNAL */
|
||||
|
||||
g_string_free (new_text_gs, TRUE);
|
||||
g_string_free (change_text_gs, TRUE);
|
||||
}
|
||||
@ -1070,9 +1144,27 @@ gnucash_sheet_delete_cb (GtkWidget *widget,
|
||||
"delete_text");
|
||||
}
|
||||
|
||||
gtk_editable_set_position (editable, cursor_position);
|
||||
if (start_sel != end_sel)
|
||||
gtk_editable_select_region(editable, start_sel, end_sel);
|
||||
|
||||
/* sync cursor position and selection to preedit if it exists */
|
||||
if (sheet->preedit_length) {
|
||||
gtk_editable_set_position (editable,
|
||||
sheet->preedit_start_position
|
||||
+ sheet->preedit_cursor_position);
|
||||
} else {
|
||||
gtk_editable_set_position (editable, cursor_position);
|
||||
}
|
||||
|
||||
if (sheet->preedit_length
|
||||
&& sheet->preedit_selection_length != 0) {
|
||||
gtk_editable_select_region (editable,
|
||||
sheet->preedit_start_position
|
||||
+ sheet->preedit_char_length,
|
||||
sheet->preedit_start_position
|
||||
+ sheet->preedit_char_length
|
||||
+ sheet->preedit_selection_length);
|
||||
}
|
||||
else if (start_sel != end_sel)
|
||||
gtk_editable_select_region (editable, start_sel, end_sel);
|
||||
|
||||
g_string_free (new_text_gs, TRUE);
|
||||
}
|
||||
@ -1136,7 +1228,12 @@ gnucash_sheet_focus_in_event (GtkWidget *widget, GdkEventFocus *event)
|
||||
(widget, event);
|
||||
|
||||
gnc_item_edit_focus_in (GNC_ITEM_EDIT(sheet->item_editor));
|
||||
gtk_im_context_focus_in(sheet->im_context);
|
||||
|
||||
#ifdef G_OS_WIN32
|
||||
gnucash_sheet_im_context_reset(sheet);
|
||||
#endif /* G_OS_WIN32 */
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
@ -1149,11 +1246,38 @@ gnucash_sheet_focus_out_event (GtkWidget *widget, GdkEventFocus *event)
|
||||
(*GTK_WIDGET_CLASS (sheet_parent_class)->focus_out_event)
|
||||
(widget, event);
|
||||
|
||||
gnc_item_edit_focus_out (GNC_ITEM_EDIT(sheet->item_editor));
|
||||
#ifdef G_OS_WIN32
|
||||
gnucash_sheet_im_context_reset(sheet);
|
||||
#endif /* G_OS_WIN32 */
|
||||
|
||||
gtk_im_context_focus_out (sheet->im_context);
|
||||
gnc_item_edit_focus_out (GNC_ITEM_EDIT(sheet->item_editor));
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gnucash_sheet_check_direct_update_cell(GnucashSheet *sheet,
|
||||
const VirtualLocation virt_loc)
|
||||
{
|
||||
const gchar *dupdate_list[] =
|
||||
{ /* From src/register/ledger-core/split-register.{h.c}
|
||||
src/register/ledger-core/split-register-layout.c */
|
||||
DATE_CELL,
|
||||
DDUE_CELL,
|
||||
NULL,
|
||||
};
|
||||
const gchar *cell_name;
|
||||
int i;
|
||||
|
||||
cell_name = gnc_table_get_cell_name (sheet->table, virt_loc);
|
||||
for (i=0; dupdate_list[i]; i++){
|
||||
if (gnc_cell_name_equal (cell_name,
|
||||
dupdate_list[i]))
|
||||
return TRUE;
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static void
|
||||
gnucash_sheet_start_editing_at_cursor (GnucashSheet *sheet)
|
||||
{
|
||||
@ -1184,8 +1308,26 @@ gnucash_sheet_start_editing_at_cursor (GnucashSheet *sheet)
|
||||
sheet->delete_signal =
|
||||
g_signal_connect(G_OBJECT(sheet->entry), "delete_text",
|
||||
G_CALLBACK(gnucash_sheet_delete_cb), sheet);
|
||||
|
||||
sheet->commit_signal =
|
||||
g_signal_connect (G_OBJECT (sheet->im_context), "commit",
|
||||
G_CALLBACK (gnucash_sheet_commit_cb), sheet);
|
||||
sheet->preedit_changed_signal =
|
||||
g_signal_connect (G_OBJECT (sheet->im_context), "preedit_changed",
|
||||
G_CALLBACK (gnucash_sheet_preedit_changed_cb),
|
||||
sheet);
|
||||
sheet->retrieve_surrounding_signal =
|
||||
g_signal_connect (G_OBJECT (sheet->im_context),
|
||||
"retrieve_surrounding",
|
||||
G_CALLBACK (gnucash_sheet_retrieve_surrounding_cb),
|
||||
sheet);
|
||||
sheet->delete_surrounding_signal =
|
||||
g_signal_connect (G_OBJECT (sheet->im_context), "delete_surrounding",
|
||||
G_CALLBACK (gnucash_sheet_delete_surrounding_cb),
|
||||
sheet);
|
||||
}
|
||||
|
||||
|
||||
static gboolean
|
||||
gnucash_motion_event (GtkWidget *widget, GdkEventMotion *event)
|
||||
{
|
||||
@ -1645,7 +1787,7 @@ gnucash_sheet_direct_event(GnucashSheet *sheet, GdkEvent *event)
|
||||
}
|
||||
|
||||
static gint
|
||||
gnucash_sheet_key_press_event (GtkWidget *widget, GdkEventKey *event)
|
||||
gnucash_sheet_key_press_event_internal (GtkWidget *widget, GdkEventKey *event)
|
||||
{
|
||||
Table *table;
|
||||
GnucashSheet *sheet;
|
||||
@ -1673,7 +1815,7 @@ gnucash_sheet_key_press_event (GtkWidget *widget, GdkEventKey *event)
|
||||
|
||||
/* Don't process any keystrokes where a modifier key (Alt,
|
||||
* Meta, etc.) is being held down. This should't include
|
||||
* MOD2, aka NUM LOCK. */
|
||||
* MOD2, aka NUM LOCK. */
|
||||
if (event->state & (GDK_MOD1_MASK | GDK_MOD3_MASK |
|
||||
GDK_MOD4_MASK | GDK_MOD5_MASK))
|
||||
pass_on = TRUE;
|
||||
@ -1771,8 +1913,17 @@ gnucash_sheet_key_press_event (GtkWidget *widget, GdkEventKey *event)
|
||||
}
|
||||
|
||||
/* Forward the keystroke to the input line */
|
||||
if (pass_on)
|
||||
return gtk_widget_event (sheet->entry, (GdkEvent *) event);
|
||||
if (pass_on) {
|
||||
GValue gval = {0,};
|
||||
gboolean result;
|
||||
g_value_init (&gval, G_TYPE_BOOLEAN);
|
||||
g_value_set_boolean (&gval, TRUE);
|
||||
g_object_set_property (G_OBJECT (sheet->entry), "editable", &gval);
|
||||
result = gtk_widget_event (sheet->entry, (GdkEvent *) event);
|
||||
g_value_set_boolean (&gval, FALSE);
|
||||
g_object_set_property (G_OBJECT (sheet->entry), "editable", &gval);
|
||||
return result;
|
||||
}
|
||||
|
||||
abort_move = gnc_table_traverse_update (table, cur_virt_loc,
|
||||
direction, &new_virt_loc);
|
||||
@ -1787,6 +1938,236 @@ gnucash_sheet_key_press_event (GtkWidget *widget, GdkEventKey *event)
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gint
|
||||
gnucash_sheet_key_press_event (GtkWidget *widget, GdkEventKey *event)
|
||||
{
|
||||
GnucashSheet *sheet;
|
||||
gint result;
|
||||
|
||||
g_return_val_if_fail(widget != NULL, TRUE);
|
||||
g_return_val_if_fail(GNUCASH_IS_SHEET(widget), TRUE);
|
||||
g_return_val_if_fail(event != NULL, TRUE);
|
||||
|
||||
sheet = GNUCASH_SHEET (widget);
|
||||
|
||||
if (gtk_im_context_filter_keypress (sheet->im_context, event)) {
|
||||
sheet->need_im_reset = TRUE;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
return gnucash_sheet_key_press_event_internal (widget, event);
|
||||
}
|
||||
|
||||
static gint
|
||||
gnucash_sheet_key_release_event(GtkWidget *widget, GdkEventKey *event)
|
||||
{
|
||||
GnucashSheet *sheet;
|
||||
|
||||
g_return_val_if_fail(widget != NULL, TRUE);
|
||||
g_return_val_if_fail(GNUCASH_IS_SHEET(widget), TRUE);
|
||||
g_return_val_if_fail(event != NULL, TRUE);
|
||||
|
||||
sheet = GNUCASH_SHEET (widget);
|
||||
|
||||
if(gtk_im_context_filter_keypress (sheet->im_context, event)){
|
||||
sheet->need_im_reset = TRUE;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static void
|
||||
gnucash_sheet_im_context_reset_flags(GnucashSheet *sheet)
|
||||
{
|
||||
sheet->preedit_length = 0;
|
||||
sheet->preedit_char_length = 0;
|
||||
sheet->preedit_start_position = -1;
|
||||
sheet->preedit_cursor_position = 0;
|
||||
sheet->preedit_selection_length = 0;
|
||||
}
|
||||
|
||||
static void
|
||||
gnucash_sheet_im_context_reset(GnucashSheet *sheet)
|
||||
{
|
||||
if (sheet->need_im_reset) {
|
||||
if (sheet->preedit_attrs) {
|
||||
pango_attr_list_unref (sheet->preedit_attrs);
|
||||
sheet->preedit_attrs = NULL;
|
||||
}
|
||||
gtk_im_context_reset (sheet->im_context);
|
||||
sheet->need_im_reset = FALSE;
|
||||
}
|
||||
gnucash_sheet_im_context_reset_flags(sheet);
|
||||
}
|
||||
|
||||
static void
|
||||
gnucash_sheet_commit_cb (GtkIMContext *context, const gchar *str,
|
||||
GnucashSheet *sheet)
|
||||
{
|
||||
GtkEditable *editable;
|
||||
gint tmp_pos, length, sel_start, sel_end;
|
||||
|
||||
g_return_if_fail(strlen(str) > 0);
|
||||
g_return_if_fail(sheet->editing == TRUE);
|
||||
|
||||
editable = GTK_EDITABLE (sheet->entry);
|
||||
|
||||
if(strlen(str) == 1 && sheet->direct_update_cell) {
|
||||
/* Reconstruct keyevent and direct update */
|
||||
GdkEvent *event;
|
||||
GdkEventKey *keyevent;
|
||||
gboolean result;
|
||||
|
||||
event = gdk_event_new (GDK_KEY_PRESS);
|
||||
keyevent = (GdkEventKey *) event;
|
||||
keyevent->keyval = gdk_unicode_to_keyval(str[0]);
|
||||
result = gnucash_sheet_direct_event(sheet, event);
|
||||
gdk_event_free(event);
|
||||
|
||||
if (result) {
|
||||
gnucash_sheet_im_context_reset_flags(sheet);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/* delete preedit string from editable*/
|
||||
if (sheet->preedit_length){
|
||||
g_signal_handler_block (G_OBJECT (sheet->entry),
|
||||
sheet->delete_signal);
|
||||
gtk_editable_delete_text (editable, sheet->preedit_start_position,
|
||||
sheet->preedit_start_position
|
||||
+ sheet->preedit_char_length);
|
||||
g_signal_handler_unblock (G_OBJECT (sheet->entry),
|
||||
sheet->delete_signal);
|
||||
}
|
||||
|
||||
if (gtk_editable_get_selection_bounds (editable, &sel_start, &sel_end)){
|
||||
if (sel_start != sel_end) {
|
||||
gtk_editable_delete_selection (editable);
|
||||
sheet->preedit_selection_length = 0;
|
||||
}
|
||||
}
|
||||
|
||||
tmp_pos = (sheet->preedit_start_position == -1)?
|
||||
gtk_editable_get_position (editable)
|
||||
:sheet->preedit_start_position;
|
||||
gtk_editable_insert_text (editable, str, strlen (str), &tmp_pos);
|
||||
gtk_editable_set_position (editable, tmp_pos);
|
||||
gnucash_sheet_im_context_reset_flags(sheet);
|
||||
}
|
||||
|
||||
static void
|
||||
gnucash_sheet_preedit_changed_cb (GtkIMContext *context, GnucashSheet *sheet)
|
||||
{
|
||||
gchar *preedit_string;
|
||||
GtkEditable *editable;
|
||||
|
||||
g_return_if_fail(context != NULL);
|
||||
g_return_if_fail(sheet->editing == TRUE);
|
||||
|
||||
editable = GTK_EDITABLE (sheet->entry);
|
||||
|
||||
/* save preedit start position and selection */
|
||||
if(sheet->preedit_length == 0) {
|
||||
int start_pos, end_pos;
|
||||
if ( gtk_editable_get_selection_bounds (editable, &start_pos, &end_pos)) {
|
||||
sheet->preedit_start_position = start_pos;
|
||||
sheet->preedit_selection_length = end_pos - start_pos;
|
||||
} else {
|
||||
sheet->preedit_start_position =
|
||||
gtk_editable_get_position (editable);
|
||||
}
|
||||
}
|
||||
#ifdef G_OS_WIN32
|
||||
else {/* sheet->preedit_length != 0 */
|
||||
/* On Windows, gtk_im_context_reset() in gnucash_sheet_key_press_event()
|
||||
* always returns FALSE because Windows IME handles key press at the
|
||||
* top level window. So sheet->need_im_reset = TRUE here. */
|
||||
sheet->need_im_reset = TRUE;
|
||||
}
|
||||
#endif /* G_OS_WIN32 */
|
||||
|
||||
if (sheet->preedit_attrs)
|
||||
pango_attr_list_unref (sheet->preedit_attrs);
|
||||
|
||||
gtk_im_context_get_preedit_string (sheet->im_context, &preedit_string,
|
||||
&sheet->preedit_attrs, &(sheet->preedit_cursor_position));
|
||||
|
||||
if (sheet->preedit_length){
|
||||
g_signal_handler_block (G_OBJECT (sheet->entry),
|
||||
sheet->delete_signal);
|
||||
gtk_editable_delete_text (editable, sheet->preedit_start_position,
|
||||
sheet->preedit_start_position
|
||||
+ sheet->preedit_char_length);
|
||||
g_signal_handler_unblock (G_OBJECT (sheet->entry),
|
||||
sheet->delete_signal);
|
||||
}
|
||||
|
||||
sheet->preedit_length = strlen (preedit_string);
|
||||
sheet->preedit_char_length = g_utf8_strlen(preedit_string, -1);
|
||||
|
||||
if (sheet->preedit_length) {
|
||||
int tmp_pos = sheet->preedit_start_position;
|
||||
g_signal_handler_block (G_OBJECT (sheet->entry),
|
||||
sheet->insert_signal);
|
||||
gtk_editable_insert_text (editable, preedit_string, sheet->preedit_length,
|
||||
&tmp_pos);
|
||||
g_signal_handler_unblock (G_OBJECT (sheet->entry),
|
||||
sheet->insert_signal);
|
||||
|
||||
gtk_editable_set_position (editable, sheet->preedit_start_position
|
||||
+ sheet->preedit_cursor_position);
|
||||
|
||||
if( sheet->preedit_selection_length != 0) {
|
||||
gtk_editable_select_region (editable,
|
||||
sheet->preedit_start_position
|
||||
+ sheet->preedit_char_length,
|
||||
sheet->preedit_start_position
|
||||
+ sheet->preedit_char_length
|
||||
+ sheet->preedit_selection_length);
|
||||
}
|
||||
} else {
|
||||
gnucash_sheet_im_context_reset_flags(sheet);
|
||||
}
|
||||
|
||||
g_free (preedit_string);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gnucash_sheet_retrieve_surrounding_cb (GtkIMContext *context, GnucashSheet *sheet)
|
||||
{
|
||||
GtkEditable *editable;
|
||||
gchar *surrounding;
|
||||
gint cur_pos;
|
||||
|
||||
editable = GTK_EDITABLE (sheet->entry);
|
||||
surrounding = gtk_editable_get_chars (editable, 0, -1);
|
||||
cur_pos = gtk_editable_get_position (editable);
|
||||
|
||||
gtk_im_context_set_surrounding (context,
|
||||
surrounding, strlen (surrounding),
|
||||
g_utf8_offset_to_pointer (surrounding, cur_pos) - surrounding);
|
||||
g_free (surrounding);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gnucash_sheet_delete_surrounding_cb (GtkIMContext *context, gint offset,
|
||||
gint n_chars, GnucashSheet *sheet)
|
||||
{
|
||||
GtkEditable *editable;
|
||||
gint cur_pos;
|
||||
|
||||
editable = GTK_EDITABLE (sheet->entry);
|
||||
cur_pos = gtk_editable_get_position (editable);
|
||||
|
||||
gtk_editable_delete_text (editable,
|
||||
cur_pos + offset,
|
||||
cur_pos + offset + n_chars);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
gnucash_sheet_goto_virt_loc (GnucashSheet *sheet, VirtualLocation virt_loc)
|
||||
@ -2237,6 +2618,11 @@ gnucash_sheet_selection_received (GtkWidget *widget,
|
||||
static void
|
||||
gnucash_sheet_realize_entry (GnucashSheet *sheet, GtkWidget *entry)
|
||||
{
|
||||
GValue gval = {0,};
|
||||
g_value_init (&gval, G_TYPE_BOOLEAN);
|
||||
g_value_set_boolean (&gval, FALSE);
|
||||
g_object_set_property (G_OBJECT (entry), "editable", &gval);
|
||||
|
||||
gtk_widget_realize (entry);
|
||||
}
|
||||
|
||||
@ -2368,6 +2754,7 @@ gnucash_sheet_class_init (GnucashSheetClass *class)
|
||||
widget_class->focus_out_event = gnucash_sheet_focus_out_event;
|
||||
|
||||
widget_class->key_press_event = gnucash_sheet_key_press_event;
|
||||
widget_class->key_release_event = gnucash_sheet_key_release_event;
|
||||
widget_class->button_press_event = gnucash_button_press_event;
|
||||
widget_class->button_release_event = gnucash_button_release_event;
|
||||
widget_class->motion_notify_event = gnucash_motion_event;
|
||||
@ -2412,6 +2799,21 @@ gnucash_sheet_init (GnucashSheet *sheet)
|
||||
sheet->blocks = g_table_new (sizeof (SheetBlock),
|
||||
gnucash_sheet_block_construct,
|
||||
gnucash_sheet_block_destroy, NULL);
|
||||
|
||||
/* setup IMContext */
|
||||
sheet->im_context = gtk_im_multicontext_new ();
|
||||
sheet->preedit_length = 0;
|
||||
sheet->preedit_char_length = 0;
|
||||
sheet->preedit_start_position = -1;
|
||||
sheet->preedit_cursor_position = 0;
|
||||
sheet->preedit_selection_length = 0;
|
||||
sheet->preedit_attrs = NULL;
|
||||
sheet->direct_update_cell = FALSE;
|
||||
sheet->need_im_reset = FALSE;
|
||||
sheet->commit_signal = 0;
|
||||
sheet->preedit_changed_signal = 0;
|
||||
sheet->retrieve_surrounding_signal = 0;
|
||||
sheet->delete_surrounding_signal = 0;
|
||||
}
|
||||
|
||||
|
||||
|
@ -126,6 +126,23 @@ typedef struct
|
||||
|
||||
GFunc moved_cb;
|
||||
gpointer moved_cb_data;
|
||||
|
||||
/* IMContext */
|
||||
GtkIMContext *im_context;
|
||||
gint preedit_length; /* num of bytes */
|
||||
gint preedit_char_length; /* num of chars in UTF-8 */
|
||||
gint preedit_start_position; /* save preedit start position *
|
||||
* combined with selection start */
|
||||
gint preedit_cursor_position; /* save preedit cursor position */
|
||||
gint preedit_selection_length;
|
||||
PangoAttrList *preedit_attrs;
|
||||
gboolean need_im_reset;
|
||||
gboolean direct_update_cell;
|
||||
guint commit_signal;
|
||||
guint preedit_changed_signal;
|
||||
guint retrieve_surrounding_signal;
|
||||
guint delete_surrounding_signal;
|
||||
|
||||
} GnucashSheet;
|
||||
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user