diff options
author | Suresh Chandrasekharan <suresh.chandrasekharan@sun.com> | 2003-10-15 02:20:18 +0800 |
---|---|---|
committer | Suresh Chandrasekharan <kcsuresh@src.gnome.org> | 2003-10-15 02:20:18 +0800 |
commit | 0517e6655c44fde264965dc7221f597471846cef (patch) | |
tree | c825bb39da5ad0ea86a782a80386a4f6d9d93fb8 /widgets | |
parent | a267d0a153a33621c6d51710d370ab2b90278b2b (diff) | |
download | gsoc2013-evolution-0517e6655c44fde264965dc7221f597471846cef.tar gsoc2013-evolution-0517e6655c44fde264965dc7221f597471846cef.tar.gz gsoc2013-evolution-0517e6655c44fde264965dc7221f597471846cef.tar.bz2 gsoc2013-evolution-0517e6655c44fde264965dc7221f597471846cef.tar.lz gsoc2013-evolution-0517e6655c44fde264965dc7221f597471846cef.tar.xz gsoc2013-evolution-0517e6655c44fde264965dc7221f597471846cef.tar.zst gsoc2013-evolution-0517e6655c44fde264965dc7221f597471846cef.zip |
Support for preedit in e-text widgets.
2003-10-14 Suresh Chandrasekharan <suresh.chandrasekharan@sun.com>
* Support for preedit in e-text widgets.
* gal/gal/e-text/e-text.c: Added e_text_preedit_changed_cb and
insert_preedit_text.
* Modified the following functions.
(e_text_draw) Calls insert_preedit_text also cursor pos @ the end of
text->selection_start + text->preedit_len
(e_text_event) Added hooks for preedit_cb
(e_text_init) Inits text->preedit_len
(e_text_retrieve_surrounding_cb) Removed printf
(e_text_delete_surrounding_cb) Correct params for
gtk_editable_delete_text to make it work.
* gal/gal/e-text/e-text.h: Added preedit_len in struct _EText
2003-09-25 Suresh Chandrasekharan <suresh.chandrasekharan@sun.com>
* Fix for "44222 task summary entry widget not i18ned". The following
files are changed.
* gal/gal/e-table/e-cell-text.c: Lots of changes for i18n
selection/input support. Added these functions for input method support.
(e_cell_text_preedit_changed_cb)
(e_cell_text_commit_cb)
(e_cell_text_retrieve_surrounding_cb)
(e_cell_text_delete_surrounding_cb)
(layout_with_preedit) This function inserts the preedit string
with the right attribs to the layout text.
(build_attr_list) Creates the PangoAttrList with bold/stikeout/underline
as applicable for the current ECellText.
The following functions are modified.
(ect_stop_editing): disconnect signal handlers when editing stops
(ect_draw): Changes for including the preedit only to the currently
selected row/col. Also display the cursor at the end of preedit text.
(ect_event): Connects the IM callbacks to the key press event.
Disconnect when not in editing mode. Also a special flag to see
when Enter key pressed in preedit mode, the text is committed only
not a new row is created. This woks in conjunction with the changes
made in the eti_event in e-table-item.c file and e-cell.h.
(ect_height): Changes due to parameters changing for generate_layout
(ect_enter_edit): Initialization of im_context for a cell text and
assoociated flags.
(ect_max_width): Changes due to parameters changing for
generate_layout.
(ect_max_width_by_row): Changes due to parameters changing for
generate_layout.
(ect_show_tooltip): Changes due to parameters changing for
generate_layout.
(e_cell_text_construct): check whether paramters are NULL.
(get_position_from_xy): Changes due to parameters changing for
generate_layout.
(_insert): Set the selection_start as the minimum of strlen(edit->text)
and selection_start. Used to correct the preedit_string length
which may have added to the selection_start.
(e_cell_text_view_command): When inserting, if in the preedit mode
do not delete the selection.
(_selection_get): Set utf8 data instead of string data.
(_selection_received): Take in UTF8_ATOM inaddition to
GDK_SELECTION_TYPE_STRING.
(e_cell_text_view_get_selection): Make utf8 data when acting as a
selection source.
* gal/e-table/e-cell-text.h : Included <gtk/gtkmenu.h>
* gal/e-table/e-cell.h: Added enum E_CELL_PREEDIT to ECellFlags
* gal/e-table/e-table-item.c: (eti_event) Changes for not committing
the edited text as a seperate row in preedit mode.
* gal/e-table/e-table.c: (table_canvas_focus_event_cb) To have
proper im_context focus for the ecanvas holding the e-table.
svn path=/trunk/; revision=22882
Diffstat (limited to 'widgets')
-rw-r--r-- | widgets/table/e-cell-text.c | 314 | ||||
-rw-r--r-- | widgets/table/e-cell-text.h | 2 | ||||
-rw-r--r-- | widgets/table/e-cell.h | 4 | ||||
-rw-r--r-- | widgets/table/e-table-item.c | 13 | ||||
-rw-r--r-- | widgets/table/e-table.c | 10 | ||||
-rw-r--r-- | widgets/text/e-text.c | 92 | ||||
-rw-r--r-- | widgets/text/e-text.h | 1 |
7 files changed, 376 insertions, 60 deletions
diff --git a/widgets/table/e-cell-text.c b/widgets/table/e-cell-text.c index 9151fcc26e..a4a8aa8085 100644 --- a/widgets/table/e-cell-text.c +++ b/widgets/table/e-cell-text.c @@ -96,6 +96,8 @@ static GdkAtom clipboard_atom = GDK_NONE; #define PARENT_TYPE e_cell_get_type () +#define UTF8_ATOM gdk_atom_intern ("UTF8_STRING", FALSE) + #define TEXT_PAD 4 typedef struct { @@ -177,6 +179,11 @@ struct _CellEdit { guint pointer_in : 1; guint default_cursor_shown : 1; + GtkIMContext *im_context; + gboolean need_im_reset; + gboolean im_context_signals_registered; + + guint16 preedit_length; /* length of preedit string, in bytes */ ECellActions actions; }; @@ -193,6 +200,13 @@ static gboolean _blink_scroll_timeout (gpointer data); static void ect_free_color (gchar *color_spec, GdkColor *color, GdkColormap *colormap); static GdkColor* e_cell_text_get_color (ECellTextView *cell_view, gchar *color_spec); +static void e_cell_text_preedit_changed_cb (GtkIMContext *context, ECellTextView *text_view); +static void e_cell_text_commit_cb (GtkIMContext *context, const gchar *str, ECellTextView *text_view); +static gboolean e_cell_text_retrieve_surrounding_cb (GtkIMContext *context, ECellTextView *text_view); +static gboolean e_cell_text_delete_surrounding_cb (GtkIMContext *context, gint offset, gint n_chars, ECellTextView *text_view); +static void _insert (ECellTextView *text_view, char *string, int value); +static void _delete_selection (ECellTextView *text_view); +static PangoAttrList* build_attr_list (ECellTextView *text_view, int row, int text_length); static ECellClass *parent_class; @@ -290,6 +304,11 @@ ect_stop_editing (ECellTextView *text_view, gboolean commit) g_timer_destroy (edit->timer); edit->timer = NULL; } + + g_signal_handlers_disconnect_matched ( + edit->im_context, + G_SIGNAL_MATCH_DATA, 0, 0, + NULL, NULL, text_view); if (edit->layout) g_object_unref (edit->layout); @@ -424,16 +443,16 @@ ect_free_color (gchar *color_spec, GdkColor *color, GdkColormap *colormap) } } -static PangoLayout * -build_layout (ECellTextView *text_view, int row, const char *text, gint width) + +static PangoAttrList* +build_attr_list (ECellTextView *text_view, int row, int text_length) { + ECellView *ecell_view = (ECellView *) text_view; ECellText *ect = E_CELL_TEXT (ecell_view->ecell); - PangoLayout *layout; + PangoAttrList *attrs = pango_attr_list_new (); gboolean bold, strikeout, underline; - layout = gtk_widget_create_pango_layout (GTK_WIDGET (((GnomeCanvasItem *)ecell_view->e_table_item_view)->canvas), text); - bold = ect->bold_column >= 0 && row >= 0 && e_table_model_value_at(ecell_view->e_table_model, ect->bold_column, row); @@ -445,33 +464,107 @@ build_layout (ECellTextView *text_view, int row, const char *text, gint width) e_table_model_value_at(ecell_view->e_table_model, ect->underline_column, row); if (bold || strikeout || underline) { - PangoAttrList *attrs; - int length = strlen (text); - attrs = pango_attr_list_new (); if (bold) { PangoAttribute *attr = pango_attr_weight_new (PANGO_WEIGHT_BOLD); attr->start_index = 0; - attr->end_index = length; + attr->end_index = text_length; pango_attr_list_insert_before (attrs, attr); } if (strikeout) { PangoAttribute *attr = pango_attr_strikethrough_new (TRUE); attr->start_index = 0; - attr->end_index = length; + attr->end_index = text_length; pango_attr_list_insert_before (attrs, attr); } if (underline) { PangoAttribute *attr = pango_attr_underline_new (TRUE); attr->start_index = 0; - attr->end_index = length; + attr->end_index = text_length; pango_attr_list_insert_before (attrs, attr); } - pango_layout_set_attributes (layout, attrs); - pango_attr_list_unref (attrs); } + return attrs; +} + +static PangoLayout * +layout_with_preedit (ECellTextView *text_view, int row, const char *text, gint width) +{ + ECellView *ecell_view = (ECellView *) text_view; + ECellText *ect = E_CELL_TEXT (ecell_view->ecell); + CellEdit *edit = text_view->edit; + PangoAttrList *attrs ; + PangoLayout *layout; + GString *tmp_string = g_string_new (NULL); + PangoAttrList *preedit_attrs = NULL; + gchar *preedit_string = NULL; + gint preedit_length = 0; + gint text_length = strlen (text); + gint mlen = MIN(edit->selection_start,text_length); + + + gtk_im_context_get_preedit_string (edit->im_context, + &preedit_string,&preedit_attrs, + NULL); + preedit_length = edit->preedit_length = strlen (preedit_string);; + + layout = edit->layout; + + g_string_prepend_len (tmp_string, text,text_length); + + if (preedit_length) { + + /* mlen is the text_length in bytes, not chars + * check whether we are not inserting into + * the middle of a utf8 character + */ + + if (mlen < text_length) { + if (!g_utf8_validate (text+mlen, -1, NULL)) { + gchar *tc; + tc = g_utf8_find_next_char (text+mlen,NULL); + if (tc) { + mlen = (gint) (tc - text); + } + } + } + + g_string_insert (tmp_string, mlen, preedit_string); + } + + pango_layout_set_text (layout, tmp_string->str, tmp_string->len); + + attrs = (PangoAttrList *) build_attr_list (text_view, row, text_length); + + if (preedit_length) + pango_attr_list_splice (attrs, preedit_attrs, mlen, preedit_length); + pango_layout_set_attributes (layout, attrs); + g_string_free (tmp_string, TRUE); + if (preedit_string) + g_free (preedit_string); + if (preedit_attrs) + pango_attr_list_unref (preedit_attrs); + pango_attr_list_unref (attrs); + return layout; +} + +static PangoLayout * +build_layout (ECellTextView *text_view, int row, const char *text, gint width) +{ + ECellView *ecell_view = (ECellView *) text_view; + ECellText *ect = E_CELL_TEXT (ecell_view->ecell); + PangoAttrList *attrs ; + PangoLayout *layout; + gboolean bold, strikeout, underline; + + layout = gtk_widget_create_pango_layout (GTK_WIDGET (((GnomeCanvasItem *)ecell_view->e_table_item_view)->canvas), text); + + attrs = (PangoAttrList *) build_attr_list (text_view, row, text ? strlen (text) : 0); + + pango_layout_set_attributes (layout, attrs); + pango_attr_list_unref (attrs); if (text_view->edit || width <= 0) return layout; @@ -533,6 +626,7 @@ generate_layout (ECellTextView *text_view, int model_col, int view_col, int row, return layout; } + static void draw_pango_rectangle (GdkDrawable *drawable, GdkGC *gc, int x1, int y1, PangoRectangle rect) { @@ -648,6 +742,10 @@ ect_draw (ECellView *ecell_view, GdkDrawable *drawable, layout = generate_layout (text_view, model_col, view_col, row, x2 - x1); + if (edit && edit->view_col == view_col && edit->row == row) { + layout = layout_with_preedit (text_view, row, edit->text ? edit->text : "?", x2 - x1); + } + gdk_draw_layout (drawable, text_view->gc, x_origin, y_origin, layout); @@ -713,7 +811,8 @@ ect_draw (ECellView *ecell_view, GdkDrawable *drawable, } else { if (edit->show_cursor) { PangoRectangle strong_pos, weak_pos; - pango_layout_get_cursor_pos (layout, edit->selection_start, &strong_pos, &weak_pos); + pango_layout_get_cursor_pos (layout, edit->selection_start + edit->preedit_length, &strong_pos, &weak_pos); + draw_pango_rectangle (drawable, text_view->gc, x_origin, y_origin, strong_pos); if (strong_pos.x != weak_pos.x || strong_pos.y != weak_pos.y || @@ -749,6 +848,7 @@ ect_get_bg_color(ECellView *ecell_view, int row) /* * Selects the entire string */ + static void ect_edit_select_all (ECellTextView *text_view) { @@ -774,8 +874,10 @@ static gint ect_event (ECellView *ecell_view, GdkEvent *event, int model_col, int view_col, int row, ECellFlags flags, ECellActions *actions) { ECellTextView *text_view = (ECellTextView *) ecell_view; + ECellText *ect = (ECellText *) ((ECellView *)text_view)->ecell; ETextEventProcessorEvent e_tep_event; gboolean edit_display = FALSE; + gint preedit_len; CellEdit *edit = text_view->edit; GtkWidget *canvas = GTK_WIDGET (text_view->canvas); gint return_val = 0; @@ -793,7 +895,70 @@ ect_event (ECellView *ecell_view, GdkEvent *event, int model_col, int view_col, case GDK_FOCUS_CHANGE: break; case GDK_KEY_PRESS: /* Fall Through */ + if (edit_display) { + if (edit->im_context && + !edit->im_context_signals_registered) { + + g_signal_connect (edit->im_context, + "preedit_changed", + G_CALLBACK (\ + e_cell_text_preedit_changed_cb), + text_view); + + g_signal_connect (edit->im_context, + "commit", + G_CALLBACK (\ + e_cell_text_commit_cb), + text_view); + + g_signal_connect (edit->im_context, + "retrieve_surrounding", + G_CALLBACK (\ + e_cell_text_retrieve_surrounding_cb), + text_view); + + g_signal_connect (edit->im_context, + "delete_surrounding", + G_CALLBACK (\ + e_cell_text_delete_surrounding_cb), + text_view); + + edit->im_context_signals_registered = TRUE; + } + + edit->show_cursor = FALSE; + + } else { + if (edit->im_context) { + g_signal_handlers_disconnect_matched ( + edit->im_context, + G_SIGNAL_MATCH_DATA, 0, 0, + NULL, NULL, edit); + edit->im_context_signals_registered = FALSE; + } + + ect_stop_editing (text_view, TRUE); + if (edit->timeout_id) { + g_source_remove(edit->timeout_id); + edit->timeout_id = 0; + } + } + return_val = TRUE; + /* Fallthrough */ case GDK_KEY_RELEASE: + preedit_len = edit->preedit_length; + if (edit_display && edit->im_context && + gtk_im_context_filter_keypress (\ + edit->im_context, + (GdkEventKey*)event)) { + + edit->need_im_reset = TRUE; + if (preedit_len && flags & E_CELL_PREEDIT) + return FALSE; + else + return TRUE; + } + if (event->key.keyval == GDK_Escape){ ect_cancel_edit (text_view); return_val = TRUE; @@ -829,12 +994,10 @@ ect_event (ECellView *ecell_view, GdkEvent *event, int model_col, int view_col, e_tep_event.key.length = 0; } #endif - _get_tep (edit); - edit->actions = 0; return_val = e_text_event_processor_handle_event (edit->tep, &e_tep_event); - *actions = edit->actions; - if (e_tep_event.key.string) g_free (e_tep_event.key.string); + if (e_tep_event.key.string) + g_free (e_tep_event.key.string); break; } } @@ -944,15 +1107,7 @@ ect_event (ECellView *ecell_view, GdkEvent *event, int model_col, int view_col, break; } - if (return_val) - return return_val; -#if 0 - if (GNOME_CANVAS_ITEM_CLASS(parent_class)->event) - return GNOME_CANVAS_ITEM_CLASS(parent_class)->event (item, event); -#endif - else - return 0; - + return return_val; } /* @@ -985,6 +1140,9 @@ ect_enter_edit (ECellView *ecell_view, int model_col, int view_col, int row) edit = g_new0 (CellEdit, 1); text_view->edit = edit; + edit->im_context = E_CANVAS (text_view->canvas)->im_context; + edit->need_im_reset = FALSE; + edit->im_context_signals_registered = FALSE; edit->view_col = -1; edit->model_col = -1; edit->row = -1; @@ -1045,7 +1203,6 @@ ect_enter_edit (ECellView *ecell_view, int model_col, int view_col, int row) } } #endif - ect_queue_redraw (text_view, view_col, row); return NULL; @@ -1566,6 +1723,77 @@ e_cell_text_class_init (GObjectClass *object_class) } } + +/* IM Context Callbacks */ + +static void +e_cell_text_preedit_changed_cb (GtkIMContext *context, + ECellTextView *tv) +{ + gchar *preedit_string; + gint cursor_pos; + CellEdit *edit=tv->edit; + gtk_im_context_get_preedit_string (edit->im_context, &preedit_string, + NULL, &cursor_pos); + + edit->preedit_length = strlen (preedit_string); + cursor_pos = CLAMP (cursor_pos, 0, g_utf8_strlen (preedit_string, -1)); + g_free (preedit_string); + ect_queue_redraw (tv, edit->view_col, edit->row); +} + +static void +e_cell_text_commit_cb (GtkIMContext *context, + const gchar *str, + ECellTextView *tv) +{ + CellEdit *edit = tv->edit; + ECellText *ect = (ECellText *) ((ECellView *)tv)->ecell; + ETextEventProcessorCommand command; + + if (g_utf8_validate (str, strlen (str), NULL)) { + command.action = E_TEP_INSERT; + command.position = E_TEP_SELECTION; + command.string = (gchar *)str; + command.value = strlen(str); + e_cell_text_view_command (edit->tep, &command, edit); + } + +} + +static gboolean +e_cell_text_retrieve_surrounding_cb (GtkIMContext *context, + ECellTextView *tv) +{ + int cur_pos = 0; + CellEdit *edit = tv->edit; + + cur_pos = g_utf8_pointer_to_offset (edit->text, edit->text + edit->selection_start); + + gtk_im_context_set_surrounding (context, + edit->text, + strlen (edit->text), + cur_pos + ); + + return TRUE; +} + +static gboolean +e_cell_text_delete_surrounding_cb (GtkIMContext *context, + gint offset, + gint n_chars, + ECellTextView *tv) +{ + CellEdit *edit = tv->edit; + + gtk_editable_delete_text (GTK_EDITABLE (edit), + edit->selection_end + offset, + edit->selection_end + offset + n_chars); + + return TRUE; +} + static void e_cell_text_init (ECellText *ect) { @@ -1595,7 +1823,10 @@ E_MAKE_TYPE(e_cell_text, "ECellText", ECellText, e_cell_text_class_init, e_cell_ ECell * e_cell_text_construct (ECellText *cell, const char *fontname, GtkJustification justify) { - cell->font_name = g_strdup (fontname); + if(!cell) + return E_CELL(NULL); + if(fontname) + cell->font_name = g_strdup (fontname); cell->justify = justify; return E_CELL(cell); } @@ -1645,6 +1876,7 @@ get_position_from_xy (CellEdit *edit, gint x, gint y) int index; int trailing; const char *text; + PangoLayout *layout = generate_layout (edit->text_view, edit->model_col, edit->view_col, edit->row, edit->cell_width); ECellTextView *text_view = edit->text_view; ECellText *ect = (ECellText *) ((ECellView *)text_view)->ecell; @@ -1932,6 +2164,8 @@ _insert (ECellTextView *text_view, char *string, int value) if (value <= 0) return; + edit->selection_start = MIN (strlen(edit->text), edit->selection_start); + temp = g_new (gchar, strlen (edit->text) + value + 1); strncpy (temp, edit->text, edit->selection_start); @@ -2052,7 +2286,7 @@ e_cell_text_view_command (ETextEventProcessor *tep, ETextEventProcessorCommand * break; case E_TEP_INSERT: - if (edit->selection_end != edit->selection_start) { + if (!edit->preedit_length && edit->selection_end != edit->selection_start) { _delete_selection (text_view); } _insert (text_view, command->string, command->value); @@ -2173,12 +2407,14 @@ _selection_get (GtkInvisible *invisible, { switch (info) { case E_SELECTION_PRIMARY: - gtk_selection_data_set (selection_data, GDK_SELECTION_TYPE_STRING, - 8, edit->primary_selection, edit->primary_length); + gtk_selection_data_set (selection_data, UTF8_ATOM, + 8, edit->primary_selection, + edit->primary_length); break; case E_SELECTION_CLIPBOARD: - gtk_selection_data_set (selection_data, GDK_SELECTION_TYPE_STRING, - 8, edit->clipboard_selection, edit->clipboard_length); + gtk_selection_data_set (selection_data, UTF8_ATOM, + 8, edit->clipboard_selection, + edit->clipboard_length); break; } } @@ -2191,7 +2427,9 @@ _selection_received (GtkInvisible *invisible, guint time, CellEdit *edit) { - if (selection_data->length < 0 || selection_data->type != GDK_SELECTION_TYPE_STRING) { + if (selection_data->length < 0 || + !(selection_data->type == UTF8_ATOM || + selection_data->type == GDK_SELECTION_TYPE_STRING)) { return; } else { ETextEventProcessorCommand command; @@ -2212,11 +2450,11 @@ static GtkWidget *e_cell_text_view_get_invisible (CellEdit *edit) gtk_selection_add_target (invisible, GDK_SELECTION_PRIMARY, - GDK_SELECTION_TYPE_STRING, + UTF8_ATOM, E_SELECTION_PRIMARY); gtk_selection_add_target (invisible, clipboard_atom, - GDK_SELECTION_TYPE_STRING, + UTF8_ATOM, E_SELECTION_CLIPBOARD); g_signal_connect (invisible, "selection_get", @@ -2273,7 +2511,7 @@ e_cell_text_view_get_selection (CellEdit *edit, GdkAtom selection, guint32 time) invisible = e_cell_text_view_get_invisible (edit); gtk_selection_convert (invisible, selection, - GDK_SELECTION_TYPE_STRING, + UTF8_ATOM, time); #endif } diff --git a/widgets/table/e-cell-text.h b/widgets/table/e-cell-text.h index 466fc54f1a..6c51f32fd8 100644 --- a/widgets/table/e-cell-text.h +++ b/widgets/table/e-cell-text.h @@ -36,7 +36,7 @@ #ifndef _E_CELL_TEXT_H_ #define _E_CELL_TEXT_H_ - +#include <gtk/gtkmenu.h> #include <libgnomecanvas/gnome-canvas.h> #include <gal/e-table/e-cell.h> diff --git a/widgets/table/e-cell.h b/widgets/table/e-cell.h index b6c4e01e71..2ba74c01f5 100644 --- a/widgets/table/e-cell.h +++ b/widgets/table/e-cell.h @@ -59,7 +59,9 @@ typedef enum { E_CELL_EDITING = 1 << 4, - E_CELL_CURSOR = 1 << 5 + E_CELL_CURSOR = 1 << 5, + + E_CELL_PREEDIT = 1 << 6 } ECellFlags; typedef enum { diff --git a/widgets/table/e-table-item.c b/widgets/table/e-table-item.c index 1015920e57..4acff10b2c 100644 --- a/widgets/table/e-table-item.c +++ b/widgets/table/e-table-item.c @@ -2703,18 +2703,17 @@ eti_event (GnomeCanvasItem *item, GdkEvent *e) case GDK_ISO_Enter: case GDK_3270_Enter: if (eti_editing (eti)){ - e_table_item_leave_edit_(eti); -#if 0 ecell_view = eti->cell_views [eti->editing_col]; return_val = eti_e_cell_event (eti, ecell_view, e, e->key.time, - view_to_model_col(eti, eti->editing_col), - eti->editing_col, eti->editing_row, E_CELL_EDITING | E_CELL_CURSOR); -#endif + view_to_model_col (eti, eti->editing_col), + eti->editing_col, eti->editing_row, E_CELL_EDITING | E_CELL_CURSOR | E_CELL_PREEDIT); + if (!return_val) + break; } g_signal_emit (eti, eti_signals [KEY_PRESS], 0, - model_to_view_row(eti, cursor_row), cursor_col, e, &return_val); + model_to_view_row (eti, cursor_row), cursor_col, e, &return_val); if (!return_val) - return_val = e_selection_model_key_press(E_SELECTION_MODEL (eti->selection), (GdkEventKey *) e); + return_val = e_selection_model_key_press (E_SELECTION_MODEL (eti->selection), (GdkEventKey *) e); break; default: diff --git a/widgets/table/e-table.c b/widgets/table/e-table.c index 6d0c4ee112..ffad7b3071 100644 --- a/widgets/table/e-table.c +++ b/widgets/table/e-table.c @@ -1102,14 +1102,20 @@ static gint table_canvas_focus_event_cb (GtkWidget *widget, GdkEventFocus *event, gpointer data) { GnomeCanvas *canvas; + ECanvas *ecanvas; ETable *etable; gtk_widget_queue_draw (widget); + canvas = GNOME_CANVAS (widget); + ecanvas = E_CANVAS (widget); - if (!event->in) + if (!event->in) { + gtk_im_context_focus_out(ecanvas->im_context); return TRUE; + } else { + gtk_im_context_focus_in(ecanvas->im_context); + } - canvas = GNOME_CANVAS (widget); etable = E_TABLE (data); if (!canvas->focused_item && etable->group) diff --git a/widgets/text/e-text.c b/widgets/text/e-text.c index bda5f46eac..d68198507c 100644 --- a/widgets/text/e-text.c +++ b/widgets/text/e-text.c @@ -142,6 +142,8 @@ static void e_text_update_primary_selection (EText *text); static void e_text_paste (EText *text, GdkAtom selection); static void e_text_insert(EText *text, const char *string); +static void reset_layout_attrs (EText *text); + /* GtkEditable Methods */ static void e_text_editable_do_insert_text (GtkEditable *editable, const gchar *text, @@ -167,6 +169,8 @@ static gint e_text_editable_get_position (GtkEditable *editable); static void e_text_commit_cb (GtkIMContext *context, const gchar *str, EText *text); +static void e_text_preedit_changed_cb (GtkIMContext *context, + EText *text); static gboolean e_text_retrieve_surrounding_cb (GtkIMContext *context, EText *text); static gboolean e_text_delete_surrounding_cb (GtkIMContext *context, @@ -282,6 +286,56 @@ e_text_dispose (GObject *object) } static void +insert_preedit_text (EText *text) +{ + PangoAttrList *attrs = NULL; + PangoAttrList *preedit_attrs = NULL; + gchar *preedit_string = NULL; + GString *tmp_string = g_string_new (NULL); + gint length = 0, cpos = 0, preedit_length = 0; + + if (text->layout == NULL || !GTK_IS_IM_CONTEXT (text->im_context)) + return; + + text->text = e_text_model_get_text(text->model); + length = strlen (text->text); + + g_string_prepend_len (tmp_string, text->text,length); + + attrs = pango_attr_list_new (); + + gtk_im_context_get_preedit_string (text->im_context, + &preedit_string, &preedit_attrs, + NULL); + + if (preedit_string && g_utf8_validate (preedit_string, -1, NULL)) + text->preedit_len = preedit_length = strlen (preedit_string); + else + text->preedit_len = preedit_length = 0; + + cpos = g_utf8_offset_to_pointer (text->text, text->selection_start) - text->text; + + if (preedit_length) + g_string_insert (tmp_string, cpos, preedit_string); + + reset_layout_attrs (text); + + pango_layout_set_text (text->layout, tmp_string->str, tmp_string->len); + if (preedit_length) + pango_attr_list_splice (attrs, preedit_attrs, cpos, preedit_length); + pango_layout_set_attributes (text->layout, attrs); + + if (preedit_string) + g_free (preedit_string); + if (preedit_attrs) + pango_attr_list_unref (preedit_attrs); + if (tmp_string) + g_string_free (tmp_string, TRUE); + if (attrs) + pango_attr_list_unref (attrs); +} + +static void reset_layout_attrs (EText *text) { PangoAttrList *attrs = NULL; @@ -1436,7 +1490,10 @@ e_text_draw (GnomeCanvasItem *item, GdkDrawable *drawable, } } - if (!text->text) + + insert_preedit_text (text); + + if (!pango_layout_get_text (text->layout)) return; if (text->stipple) @@ -1558,7 +1615,7 @@ e_text_draw (GnomeCanvasItem *item, GdkDrawable *drawable, PangoRectangle strong_pos, weak_pos; char *offs = g_utf8_offset_to_pointer (text->text, text->selection_start); - pango_layout_get_cursor_pos (text->layout, offs - text->text, &strong_pos, &weak_pos); + pango_layout_get_cursor_pos (text->layout, offs - text->text + text->preedit_len, &strong_pos, &weak_pos); draw_pango_rectangle (drawable, main_gc, xpos, ypos, strong_pos); if (strong_pos.x != weak_pos.x || strong_pos.y != weak_pos.y || @@ -2116,6 +2173,8 @@ e_text_event (GnomeCanvasItem *item, GdkEvent *event) if (!text->im_context_signals_registered) { g_signal_connect (text->im_context, "commit", G_CALLBACK (e_text_commit_cb), text); + g_signal_connect (text->im_context, "preedit_changed", + G_CALLBACK (e_text_preedit_changed_cb), text); g_signal_connect (text->im_context, "retrieve_surrounding", G_CALLBACK (e_text_retrieve_surrounding_cb), text); g_signal_connect (text->im_context, "delete_surrounding", @@ -3610,6 +3669,7 @@ e_text_init (EText *text) { text->model = e_text_model_new (); text->text = e_text_model_get_text (text->model); + text->preedit_len = 0; text->layout = NULL; text->revert = NULL; @@ -3712,6 +3772,7 @@ E_MAKE_TYPE (e_text, PARENT_TYPE) + /* IM Context Callbacks */ static void e_text_commit_cb (GtkIMContext *context, @@ -3722,16 +3783,28 @@ e_text_commit_cb (GtkIMContext *context, if (text->selection_end != text->selection_start) e_text_delete_selection (text); e_text_insert (text, str); - g_signal_emit (text, e_text_signals[E_TEXT_KEYPRESS], 0, - 0 /* XXX ugh */, 0 /* XXX ugh */); + g_signal_emit (text, e_text_signals[E_TEXT_KEYPRESS], 0, 0, 0); } } +static void +e_text_preedit_changed_cb (GtkIMContext *context, + EText *etext) +{ + gchar *preedit_string = NULL; + + gtk_im_context_get_preedit_string (context, &preedit_string, + NULL, NULL); + + etext->preedit_len = strlen (preedit_string); + + g_signal_emit (etext, e_text_signals[E_TEXT_KEYPRESS], 0, 0, 0); +} + static gboolean e_text_retrieve_surrounding_cb (GtkIMContext *context, EText *text) { - printf ("e_text_retrieve_surrounding_cb\n"); gtk_im_context_set_surrounding (context, text->text, strlen (text->text), @@ -3746,12 +3819,9 @@ e_text_delete_surrounding_cb (GtkIMContext *context, gint n_chars, EText *text) { - printf ("e_text_delete_surrounding_cb\n"); -#if 0 - gtk_editable_delete_text (GTK_EDITABLE (entry), - entry->current_pos + offset, - entry->current_pos + offset + n_chars); -#endif + gtk_editable_delete_text (GTK_EDITABLE (text), + text->selection_end + offset, + text->selection_end + offset + n_chars); return TRUE; } diff --git a/widgets/text/e-text.h b/widgets/text/e-text.h index 0832c5d699..4eb3fa830b 100644 --- a/widgets/text/e-text.h +++ b/widgets/text/e-text.h @@ -108,6 +108,7 @@ struct _EText { gint model_repos_signal_id; const gchar *text; /* Text to display --- from the ETextModel */ + gint preedit_len; /* preedit length to display */ PangoLayout *layout; int num_lines; /* Number of lines of text */ |