remove all gtk3 conditionals
[claws.git] / src / gtk / spell_entry.c
index b21e17df9e842e013f825236124f1d24880732dc..44b91bcddb2681672188471a08392b25038d540b 100644 (file)
@@ -3,29 +3,26 @@
  *
  * @Copyright (C) 2004-2006 Christian Hammond.
  * Some of this code is from gtkspell, Copyright (C) 2002 Evan Martin.
+ * Adapted for Claws Mail (c) 2009-2012 Pawel Pekala and the Claws Mail team
  *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser 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 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 3 of the License, or
+ * (at your option) any later version.
  *
- * This library is distributed in the hope that it will be useful,
+ * 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
- * Lesser General Public License for more details.
+ * 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 Lesser General Public
- * License along with this library; if not, write to the
- * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- * Boston, MA  02111-1307, USA.
- */
-
-/* 
-   Adapted for Claws Mail (c) 2009 Pawel Pekala
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ * 
  */
 
 #ifdef HAVE_CONFIG_H
 #  include "config.h"
+#include "claws-features.h"
 #endif
 
 #ifdef USE_ENCHANT
 
 #include <string.h>
 #include <glib.h>
-#include <gtk/gtkwidget.h>
-#include <gtk/gtkentry.h>
-#include <gtk/gtkseparator.h>
-#include <gtk/gtkmenuitem.h>
+#include <gtk/gtk.h>
 
 #include "spell_entry.h"
 #include "prefs_common.h"
 #include "codeconv.h"
 #include "defs.h"
+#include "gtkutils.h"
 
 static void claws_spell_entry_init             (ClawsSpellEntry *entry);
-static void claws_spell_entry_editable_init    (GtkEditableClass *iface);
-static void claws_spell_entry_finalize         (GObject *object);
 static void claws_spell_entry_destroy          (GtkObject *object);
 static gint claws_spell_entry_expose           (GtkWidget *widget,
                                                 GdkEventExpose *event);
@@ -63,50 +56,66 @@ static void claws_spell_entry_populate_popup        (ClawsSpellEntry *entry,
                                                 gpointer data);
 static void claws_spell_entry_changed          (GtkEditable *editable,
                                                 gpointer data);
+static void claws_spell_entry_preedit_changed          (GtkEntry *entry,
+                                                gchar *preedit,
+                                                gpointer data);
 
-struct _ClawsSpellEntryPriv
+typedef struct
 {
        PangoAttrList        *attr_list;
        gint                  mark_character;
        gchar               **words;
        gint                 *word_starts;
        gint                 *word_ends;
-};
+       gint                  preedit_length;
+} ClawsSpellEntryPrivate;
 
-static GtkEntryClass *parent_class = NULL;
+#define CLAWS_SPELL_ENTRY_GET_PRIVATE(entry) \
+       G_TYPE_INSTANCE_GET_PRIVATE (entry, CLAWS_TYPE_SPELL_ENTRY, \
+                       ClawsSpellEntryPrivate)
 
+static GtkEntryClass *parent_class = NULL;
 
-G_DEFINE_TYPE_EXTENDED(ClawsSpellEntry, claws_spell_entry, GTK_TYPE_ENTRY, 0, G_IMPLEMENT_INTERFACE(GTK_TYPE_EDITABLE, claws_spell_entry_editable_init)); 
+#if !GLIB_CHECK_VERSION(2,58, 0)
+G_DEFINE_TYPE(ClawsSpellEntry, claws_spell_entry, GTK_TYPE_ENTRY)
+#else
+G_DEFINE_TYPE_WITH_CODE(ClawsSpellEntry, claws_spell_entry, GTK_TYPE_ENTRY,
+               G_ADD_PRIVATE(ClawsSpellEntry))
+#endif
 
 
 static void claws_spell_entry_class_init(ClawsSpellEntryClass *klass)
 {
+#if !GLIB_CHECK_VERSION(2,58, 0)
        GObjectClass    *g_object_class;
+#endif
        GtkObjectClass  *gtk_object_class;
        GtkWidgetClass  *widget_class;
        
        parent_class = g_type_class_peek_parent(klass);
        
-       g_object_class = G_OBJECT_CLASS(klass);
-       g_object_class->finalize = claws_spell_entry_finalize;
-       
        gtk_object_class = GTK_OBJECT_CLASS(klass);
        gtk_object_class->destroy = claws_spell_entry_destroy;
        
        widget_class = GTK_WIDGET_CLASS(klass);
-       widget_class->expose_event = claws_spell_entry_expose;
        widget_class->button_press_event = claws_spell_entry_button_press;
-       
+       widget_class->expose_event = claws_spell_entry_expose;
+
+#if !GLIB_CHECK_VERSION(2,58, 0)
+       g_object_class = G_OBJECT_CLASS(klass);
        g_type_class_add_private(g_object_class,
-                       sizeof(struct _ClawsSpellEntryPriv));
+                       sizeof(ClawsSpellEntryPrivate));
+#endif
 }
 
 static void claws_spell_entry_init(ClawsSpellEntry *entry)
 {
+       ClawsSpellEntryPrivate *priv = CLAWS_SPELL_ENTRY_GET_PRIVATE(entry);
+
        entry->gtkaspell = NULL;
        
-       entry->priv = g_new0(ClawsSpellEntryPriv, 1);
-       entry->priv->attr_list = pango_attr_list_new();
+       priv->attr_list = pango_attr_list_new();
+       priv->preedit_length = 0;
                                         
        g_signal_connect(G_OBJECT(entry), "popup-menu",
                        G_CALLBACK(claws_spell_entry_popup_menu), entry);
@@ -114,25 +123,8 @@ static void claws_spell_entry_init(ClawsSpellEntry *entry)
                        G_CALLBACK(claws_spell_entry_populate_popup), NULL);
        g_signal_connect(G_OBJECT(entry), "changed",
                        G_CALLBACK(claws_spell_entry_changed), NULL);
-}
-
-static void claws_spell_entry_editable_init (GtkEditableClass *iface) {}
-
-static void claws_spell_entry_finalize(GObject *object)
-{
-       ClawsSpellEntry *entry = CLAWS_SPELL_ENTRY(object);
-
-       if (entry->priv->attr_list)
-               pango_attr_list_unref(entry->priv->attr_list);
-       if (entry->priv->words)
-               g_strfreev(entry->priv->words);
-
-       g_free(entry->priv->word_starts);
-       g_free(entry->priv->word_ends);
-       g_free(entry->priv);
-       entry->priv = NULL;
-       
-       G_OBJECT_CLASS(parent_class)->finalize(object);
+       g_signal_connect(G_OBJECT(entry), "preedit-changed",
+                       G_CALLBACK(claws_spell_entry_preedit_changed), NULL);
 }
 
 static void claws_spell_entry_destroy(GtkObject *object)
@@ -147,34 +139,38 @@ GtkWidget *claws_spell_entry_new(void)
 
 void claws_spell_entry_set_gtkaspell(ClawsSpellEntry *entry, GtkAspell *gtkaspell)
 {
-       g_return_if_fail(CLAWS_IS_SPELL_ENTRY(entry));
-       g_return_if_fail(gtkaspell != NULL);
+       cm_return_if_fail(CLAWS_IS_SPELL_ENTRY(entry));
 
        entry->gtkaspell = gtkaspell;
 }
 
-static gint gtk_entry_find_position (GtkEntry *entry, gint x)
+static gint claws_spell_entry_find_position (ClawsSpellEntry *_entry, gint x)
 {
        PangoLayout *layout;
        PangoLayoutLine *line;
        const gchar *text;
        gint cursor_index;
        gint index;
-       gint pos;
+       gint pos, current_pos;
+       gint scroll_offset;
        gboolean trailing;
+       GtkEntry *entry = GTK_ENTRY(_entry);
+       ClawsSpellEntryPrivate *priv = CLAWS_SPELL_ENTRY_GET_PRIVATE(entry);
 
-       x = x + entry->scroll_offset;
+       g_object_get(entry, "scroll-offset", &scroll_offset, NULL);
+       x = x + scroll_offset;
 
        layout = gtk_entry_get_layout(entry);
        text = pango_layout_get_text(layout);
-       cursor_index = g_utf8_offset_to_pointer(text, entry->current_pos) - text;
+       g_object_get(entry, "cursor-position", &current_pos, NULL);
+       cursor_index = g_utf8_offset_to_pointer(text, current_pos) - text;
 
        line = pango_layout_get_lines(layout)->data;
        pango_layout_line_x_to_index(line, x * PANGO_SCALE, &index, &trailing);
 
-       if (index >= cursor_index && entry->preedit_length) {
-               if (index >= cursor_index + entry->preedit_length) {
-                       index -= entry->preedit_length;
+       if (index >= cursor_index && priv->preedit_length) {
+               if (index >= cursor_index + priv->preedit_length) {
+                       index -= priv->preedit_length;
                } else {
                        index = cursor_index;
                        trailing = FALSE;
@@ -192,21 +188,22 @@ static void get_word_extents_from_position(ClawsSpellEntry *entry, gint *start,
 {
        const gchar *text;
        gint i, bytes_pos;
+       ClawsSpellEntryPrivate *priv = CLAWS_SPELL_ENTRY_GET_PRIVATE(entry);
 
        *start = -1;
        *end = -1;
 
-       if (entry->priv->words == NULL)
+       if (priv->words == NULL)
                return;
 
        text = gtk_entry_get_text(GTK_ENTRY(entry));
        bytes_pos = (gint) (g_utf8_offset_to_pointer(text, position) - text);
 
-       for (i = 0; entry->priv->words[i]; i++) {
-               if (bytes_pos >= entry->priv->word_starts[i] &&
-                   bytes_pos <= entry->priv->word_ends[i]) {
-                       *start = entry->priv->word_starts[i];
-                       *end   = entry->priv->word_ends[i];
+       for (i = 0; priv->words[i]; i++) {
+               if (bytes_pos >= priv->word_starts[i] &&
+                   bytes_pos <= priv->word_ends[i]) {
+                       *start = priv->word_starts[i];
+                       *end   = priv->word_ends[i];
                        return;
                }
        }
@@ -231,6 +228,7 @@ static void replace_word(ClawsSpellEntry *entry, const gchar *newword)
 {
        gint cursor, start_pos, end_pos;
        const gchar *text = gtk_entry_get_text(GTK_ENTRY(entry));
+       ClawsSpellEntryPrivate *priv = CLAWS_SPELL_ENTRY_GET_PRIVATE(entry);
 
        start_pos = entry->gtkaspell->start_pos;
        end_pos = entry->gtkaspell->end_pos;
@@ -239,9 +237,9 @@ static void replace_word(ClawsSpellEntry *entry, const gchar *newword)
        /* is the cursor at the end? If so, restore it there */
        if (g_utf8_strlen(text, -1) == cursor)
                cursor = -1;
-       else if(cursor < entry->priv->mark_character ||
-               cursor > entry->priv->mark_character)
-                       cursor = entry->priv->mark_character;
+       else if(cursor < priv->mark_character ||
+               cursor > priv->mark_character)
+                       cursor = priv->mark_character;
 
        gtk_editable_delete_text(GTK_EDITABLE(entry), start_pos, end_pos);
        gtk_editable_insert_text(GTK_EDITABLE(entry), newword, strlen(newword),
@@ -256,7 +254,7 @@ static gboolean word_misspelled(ClawsSpellEntry *entry, int start, int end)
        gboolean ret;
 
        word = get_word(entry, start, end);
-       if (word == NULL)
+       if (word == NULL || g_unichar_isdigit(word[0]))
                return FALSE;
                
        ret = gtkaspell_misspelled_test(entry->gtkaspell, word);
@@ -265,6 +263,29 @@ static gboolean word_misspelled(ClawsSpellEntry *entry, int start, int end)
        return ret;
 }
 
+static gboolean is_word_end (GtkEntry *entry, const int offset)
+{
+       gchar *p = gtk_editable_get_chars(GTK_EDITABLE(entry), offset, offset+1);
+       gunichar ch;
+       
+       ch = g_utf8_get_char(p);
+       g_free(p);
+       
+       if (ch == '\0')
+               return TRUE;
+
+       if (ch == '\'') {
+               p = gtk_editable_get_chars(GTK_EDITABLE(entry), offset+1, offset+2);
+               ch = g_utf8_get_char(p);
+               g_free(p);
+               
+               return (g_unichar_isspace(ch) || g_unichar_ispunct(ch)
+                       || g_unichar_isdigit(ch));
+       }
+       
+       return (g_unichar_isspace(ch) || g_unichar_ispunct(ch));
+}
+
 static void entry_strsplit_utf8(GtkEntry *entry, gchar ***set, gint **starts, gint **ends)
 {
        PangoLayout   *layout;
@@ -294,7 +315,7 @@ static void entry_strsplit_utf8(GtkEntry *entry, gchar ***set, gint **starts, gi
 
                        /* Find the end of this string */
                        cend = i;
-                       while (!(log_attrs[cend].is_word_end))
+                       while (!is_word_end(entry, cend))
                                cend++;
 
                        /* Copy sub-string */
@@ -315,20 +336,21 @@ static void entry_strsplit_utf8(GtkEntry *entry, gchar ***set, gint **starts, gi
 
 static void insert_misspelled_marker(ClawsSpellEntry *entry, guint start, guint end)
 {
-       guint16 red   = (guint16) (((gdouble)((prefs_common.misspelled_col & 
+       ClawsSpellEntryPrivate *priv = CLAWS_SPELL_ENTRY_GET_PRIVATE(entry);
+       guint16 red   = (guint16) (((gdouble)((prefs_common.color[COL_MISSPELLED] &
                                        0xff0000) >> 16) / 255.0) * 65535.0);
-       guint16 green = (guint16) (((gdouble)((prefs_common.misspelled_col & 
+       guint16 green = (guint16) (((gdouble)((prefs_common.color[COL_MISSPELLED] &
                                        0x00ff00) >> 8) / 255.0) * 65535.0);
-       guint16 blue  = (guint16) (((gdouble) (prefs_common.misspelled_col & 
+       guint16 blue  = (guint16) (((gdouble) (prefs_common.color[COL_MISSPELLED] &
                                        0x0000ff) / 255.0) * 65535.0);
        PangoAttribute *fcolor, *ucolor, *unline;
        
-       if(prefs_common.misspelled_col != 0) {
+       if(prefs_common.color[COL_MISSPELLED] != 0) {
                fcolor = pango_attr_foreground_new(red, green, blue);
                fcolor->start_index = start;
                fcolor->end_index = end;
                
-               pango_attr_list_insert(entry->priv->attr_list, fcolor);
+               pango_attr_list_insert(priv->attr_list, fcolor);
        } else {
                ucolor = pango_attr_underline_color_new (65535, 0, 0);
                unline = pango_attr_underline_new (PANGO_UNDERLINE_ERROR);
@@ -339,14 +361,15 @@ static void insert_misspelled_marker(ClawsSpellEntry *entry, guint start, guint
                ucolor->end_index = end;
                unline->end_index = end;
 
-               pango_attr_list_insert (entry->priv->attr_list, ucolor);
-               pango_attr_list_insert (entry->priv->attr_list, unline);
+               pango_attr_list_insert (priv->attr_list, ucolor);
+               pango_attr_list_insert (priv->attr_list, unline);
        }
 }
 
 static gboolean check_word(ClawsSpellEntry *entry, int start, int end)
 {
        GtkAspell *gtkaspell = entry->gtkaspell;
+       ClawsSpellEntryPrivate *priv = CLAWS_SPELL_ENTRY_GET_PRIVATE(entry);
        PangoAttrIterator *it;
        gint s, e;
        gboolean misspelled;
@@ -355,7 +378,7 @@ static gboolean check_word(ClawsSpellEntry *entry, int start, int end)
 
        /* Check to see if we've got any attributes at this position.
         * If so, free them, since we'll readd it if the word is misspelled */
-       it = pango_attr_list_get_iterator(entry->priv->attr_list);
+       it = pango_attr_list_get_iterator(priv->attr_list);
        if (it == NULL)
                return FALSE;
        do {
@@ -387,48 +410,53 @@ static gboolean check_word(ClawsSpellEntry *entry, int start, int end)
 
 void claws_spell_entry_recheck_all(ClawsSpellEntry *entry)
 {
+       GtkAllocation allocation;
        GdkRectangle rect;
        PangoLayout *layout;
+       ClawsSpellEntryPrivate *priv = CLAWS_SPELL_ENTRY_GET_PRIVATE(entry);
        int length, i;
 
-       g_return_if_fail(CLAWS_IS_SPELL_ENTRY(entry));
-       g_return_if_fail(entry->gtkaspell != NULL);
+       cm_return_if_fail(CLAWS_IS_SPELL_ENTRY(entry));
+       cm_return_if_fail(entry->gtkaspell != NULL);
 
-       if (entry->priv->words == NULL)
+       if (priv->words == NULL)
                return;
 
        /* Remove all existing pango attributes.  These will get readded as we check */
-       pango_attr_list_unref(entry->priv->attr_list);
-       entry->priv->attr_list = pango_attr_list_new();
+       pango_attr_list_unref(priv->attr_list);
+       priv->attr_list = pango_attr_list_new();
 
        /* Loop through words */
-       for (i = 0; entry->priv->words[i]; i++) {
-               length = strlen(entry->priv->words[i]);
+       for (i = 0; priv->words[i]; i++) {
+               length = strlen(priv->words[i]);
                if (length == 0)
                        continue;
-               check_word(entry, entry->priv->word_starts[i], entry->priv->word_ends[i]);
+               check_word(entry, priv->word_starts[i], priv->word_ends[i]);
        }
 
        layout = gtk_entry_get_layout(GTK_ENTRY(entry));
-       pango_layout_set_attributes(layout, entry->priv->attr_list);
+       pango_layout_set_attributes(layout, priv->attr_list);
 
-       if (GTK_WIDGET_REALIZED(GTK_WIDGET(entry))) {
+       if (gtk_widget_get_realized(GTK_WIDGET(entry))) {
                rect.x = 0; rect.y = 0;
-               rect.width  = GTK_WIDGET(entry)->allocation.width;
-               rect.height = GTK_WIDGET(entry)->allocation.height;
-               gdk_window_invalidate_rect(GTK_WIDGET(entry)->window, &rect, TRUE);
+               gtk_widget_get_allocation(GTK_WIDGET(entry), &allocation);
+               rect.width  = allocation.width;
+               rect.height = allocation.height;
+               gdk_window_invalidate_rect(gtk_widget_get_window(GTK_WIDGET(entry)),
+                               &rect, TRUE);
        }
 }
 
 static gint claws_spell_entry_expose(GtkWidget *widget, GdkEventExpose *event)
 {
        ClawsSpellEntry *entry = CLAWS_SPELL_ENTRY(widget);
+       ClawsSpellEntryPrivate *priv = CLAWS_SPELL_ENTRY_GET_PRIVATE(entry);
        GtkEntry *gtk_entry = GTK_ENTRY(widget);
        PangoLayout *layout;
 
        if (entry->gtkaspell != NULL) {
                layout = gtk_entry_get_layout(gtk_entry);
-               pango_layout_set_attributes(layout, entry->priv->attr_list);
+               pango_layout_set_attributes(layout, priv->attr_list);
        }
 
        return GTK_WIDGET_CLASS(parent_class)->expose_event (widget, event);
@@ -437,18 +465,20 @@ static gint claws_spell_entry_expose(GtkWidget *widget, GdkEventExpose *event)
 static gint claws_spell_entry_button_press(GtkWidget *widget, GdkEventButton *event)
 {
        ClawsSpellEntry *entry = CLAWS_SPELL_ENTRY(widget);
-       GtkEntry *gtk_entry = GTK_ENTRY(widget);
+       ClawsSpellEntryPrivate *priv = CLAWS_SPELL_ENTRY_GET_PRIVATE(entry);
        gint pos;
 
-       pos = gtk_entry_find_position(gtk_entry, event->x);
-       entry->priv->mark_character = pos;
+       pos = claws_spell_entry_find_position(entry, event->x);
+       priv->mark_character = pos;
 
        return GTK_WIDGET_CLASS(parent_class)->button_press_event (widget, event);
 }
 
 static gboolean claws_spell_entry_popup_menu(GtkWidget *widget, ClawsSpellEntry *entry)
 {
-       entry->priv->mark_character = gtk_editable_get_position (GTK_EDITABLE (entry));
+       ClawsSpellEntryPrivate *priv = CLAWS_SPELL_ENTRY_GET_PRIVATE(entry);
+
+       priv->mark_character = gtk_editable_get_position (GTK_EDITABLE (entry));
        return FALSE;
 }
 
@@ -460,13 +490,14 @@ static void set_position(gpointer data, gint pos)
 static gboolean find_misspelled_cb(gpointer data, gboolean forward)
 {
        ClawsSpellEntry *entry = (ClawsSpellEntry *)data;
+       ClawsSpellEntryPrivate *priv = CLAWS_SPELL_ENTRY_GET_PRIVATE(entry);
        GtkAspell *gtkaspell = entry->gtkaspell;
        gboolean misspelled = FALSE;
        gint cursor, minpos, maxpos, i, words_len = 0;
        gint start, end;
        gchar *text;
        
-       if (entry->priv->words == NULL)
+       if (priv->words == NULL)
                return FALSE;
 
        gtkaspell->orig_pos = gtk_editable_get_position(GTK_EDITABLE(entry));
@@ -482,22 +513,22 @@ static gboolean find_misspelled_cb(gpointer data, gboolean forward)
        }
        g_free(text);
 
-       while(entry->priv->words[words_len])
+       while(priv->words[words_len])
                words_len++;
 
        if (forward) {
                for(i=0; i < words_len; i++)
-                       if (entry->priv->word_ends[i] > minpos &&
+                       if (priv->word_ends[i] > minpos &&
                            (misspelled = check_word(entry,
-                                       entry->priv->word_starts[i],
-                                       entry->priv->word_ends[i])))
+                                       priv->word_starts[i],
+                                       priv->word_ends[i])))
                                break;
        } else {
                for(i=words_len-1; i >= 0; i--)
-                       if (entry->priv->word_starts[i] < maxpos &&
+                       if (priv->word_starts[i] < maxpos &&
                            (misspelled = check_word(entry,
-                                       entry->priv->word_starts[i],
-                                       entry->priv->word_ends[i])))
+                                       priv->word_starts[i],
+                                       priv->word_ends[i])))
                                break;
        }
        
@@ -507,9 +538,10 @@ static gboolean find_misspelled_cb(gpointer data, gboolean forward)
 static gboolean check_word_cb(gpointer data)
 {
        ClawsSpellEntry *entry = (ClawsSpellEntry *)data;
+       ClawsSpellEntryPrivate *priv = CLAWS_SPELL_ENTRY_GET_PRIVATE(entry);
        gint start, end;
        
-       get_word_extents_from_position(entry, &start, &end, entry->priv->mark_character);
+       get_word_extents_from_position(entry, &start, &end, priv->mark_character);
        return check_word(entry, start, end);
 }
 
@@ -532,7 +564,7 @@ static void set_menu_pos(GtkMenu *menu, gint *x, gint *y,
        gtk_widget_get_child_requisition(GTK_WIDGET(entry), &subject_rq);
        
        /* screen -> compose window coords */
-       gdk_window_get_origin(GTK_WIDGET(gtkaspell->parent_window)->window,
+       gdk_window_get_origin(gtk_widget_get_window(GTK_WIDGET(gtkaspell->parent_window)),
                                &scr_x, &scr_y);
 
        /* compose window -> subject entry coords */
@@ -553,8 +585,8 @@ static void set_menu_pos(GtkMenu *menu, gint *x, gint *y,
 
 void claws_spell_entry_context_set(ClawsSpellEntry *entry)
 {
-       g_return_if_fail(CLAWS_IS_SPELL_ENTRY(entry));
-       g_return_if_fail(entry->gtkaspell != NULL);
+       cm_return_if_fail(CLAWS_IS_SPELL_ENTRY(entry));
+       cm_return_if_fail(entry->gtkaspell != NULL);
 
        entry->gtkaspell->ctx.set_position      = set_position;
        entry->gtkaspell->ctx.set_menu_pos      = set_menu_pos;
@@ -568,13 +600,14 @@ static void claws_spell_entry_populate_popup(ClawsSpellEntry *entry, GtkMenu *me
                                                gpointer data)
 {
        GtkAspell *gtkaspell = entry->gtkaspell;
+       ClawsSpellEntryPrivate *priv = CLAWS_SPELL_ENTRY_GET_PRIVATE(entry);
        gint start, end;
-       gchar *word;
+       gchar *word, *text;
        
        if (gtkaspell == NULL)
                return;
        
-        get_word_extents_from_position(entry, &start, &end, entry->priv->mark_character);
+        get_word_extents_from_position(entry, &start, &end, priv->mark_character);
 
         if ((word = get_word(entry, start, end)) != NULL) {
                strncpy(gtkaspell->theword, word, GTKASPELLWORDSIZE - 1);
@@ -582,7 +615,12 @@ static void claws_spell_entry_populate_popup(ClawsSpellEntry *entry, GtkMenu *me
        }
 
         gtkaspell->misspelled = word_misspelled(entry, start, end);
-        
+
+       text = gtk_editable_get_chars(GTK_EDITABLE(entry), 0, -1);
+       gtkaspell->start_pos  = g_utf8_pointer_to_offset(text, (text+start));
+       gtkaspell->end_pos    = g_utf8_pointer_to_offset(text, (text+end));
+       g_free(text);
+
         claws_spell_entry_context_set(entry);
         gtkaspell_make_context_menu(menu, gtkaspell);
 }
@@ -590,21 +628,32 @@ static void claws_spell_entry_populate_popup(ClawsSpellEntry *entry, GtkMenu *me
 static void claws_spell_entry_changed(GtkEditable *editable, gpointer data)
 {
        ClawsSpellEntry *entry = CLAWS_SPELL_ENTRY(editable);
+       ClawsSpellEntryPrivate *priv = CLAWS_SPELL_ENTRY_GET_PRIVATE(entry);
 
        if (entry->gtkaspell == NULL)
                return;
 
-       if (entry->priv->words) {
-               g_strfreev(entry->priv->words);
-               g_free(entry->priv->word_starts);
-               g_free(entry->priv->word_ends);
+       if (priv->words) {
+               g_strfreev(priv->words);
+               g_free(priv->word_starts);
+               g_free(priv->word_ends);
        }
-       entry_strsplit_utf8(GTK_ENTRY(entry), &entry->priv->words, 
-                       &entry->priv->word_starts, &entry->priv->word_ends);
+       entry_strsplit_utf8(GTK_ENTRY(entry), &priv->words, 
+                       &priv->word_starts, &priv->word_ends);
        if(entry->gtkaspell->check_while_typing == TRUE)
                claws_spell_entry_recheck_all(entry);
 }
 
+static void claws_spell_entry_preedit_changed          (GtkEntry *_entry,
+                                                gchar *preedit,
+                                                gpointer data)
+{
+       ClawsSpellEntry *entry = CLAWS_SPELL_ENTRY(_entry);
+       ClawsSpellEntryPrivate *priv = CLAWS_SPELL_ENTRY_GET_PRIVATE(entry);
+
+       priv->preedit_length = preedit != NULL ? strlen(preedit) : 0;
+}
+
 static void continue_check(gpointer *data)
 {
        ClawsSpellEntry *entry = (ClawsSpellEntry *)data;
@@ -622,8 +671,8 @@ void claws_spell_entry_check_all(ClawsSpellEntry *entry)
        gint start, end;
        gchar *text;
        
-       g_return_if_fail(CLAWS_IS_SPELL_ENTRY(entry));
-       g_return_if_fail(entry->gtkaspell != NULL);
+       cm_return_if_fail(CLAWS_IS_SPELL_ENTRY(entry));
+       cm_return_if_fail(entry->gtkaspell != NULL);
        
        if (!gtk_editable_get_selection_bounds(GTK_EDITABLE(entry), &start, &end)) {
                text = gtk_editable_get_chars(GTK_EDITABLE(entry), 0, -1);      
@@ -645,8 +694,8 @@ void claws_spell_entry_check_all(ClawsSpellEntry *entry)
 
 void claws_spell_entry_check_backwards(ClawsSpellEntry *entry)
 {
-       g_return_if_fail(CLAWS_IS_SPELL_ENTRY(entry));
-       g_return_if_fail(entry->gtkaspell != NULL);
+       cm_return_if_fail(CLAWS_IS_SPELL_ENTRY(entry));
+       cm_return_if_fail(entry->gtkaspell != NULL);
        
        entry->gtkaspell->continue_check = NULL;
        claws_spell_entry_context_set(entry);
@@ -655,8 +704,8 @@ void claws_spell_entry_check_backwards(ClawsSpellEntry *entry)
 
 void claws_spell_entry_check_forwards_go(ClawsSpellEntry *entry)
 {
-       g_return_if_fail(CLAWS_IS_SPELL_ENTRY(entry));
-       g_return_if_fail(entry->gtkaspell != NULL);
+       cm_return_if_fail(CLAWS_IS_SPELL_ENTRY(entry));
+       cm_return_if_fail(entry->gtkaspell != NULL);
 
        entry->gtkaspell->continue_check = NULL;
        claws_spell_entry_context_set(entry);