2009-02-11 [colin] 3.7.0cvs59
authorColin Leroy <colin@colino.net>
Wed, 11 Feb 2009 20:05:41 +0000 (20:05 +0000)
committerColin Leroy <colin@colino.net>
Wed, 11 Feb 2009 20:05:41 +0000 (20:05 +0000)
* src/gtk/spell_entry.c
* src/gtk/spell_entry.h
Forgot to add files

ChangeLog
PATCHSETS
configure.ac
src/gtk/spell_entry.c [new file with mode: 0644]
src/gtk/spell_entry.h [new file with mode: 0644]

index e790691482b15445892f75abbcfe41b03c646ebc..2e215a0585d8b76d2495e608cfb9242f5f3cda9c 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,9 @@
+2009-02-11 [colin]     3.7.0cvs59
+
+       * src/gtk/spell_entry.c
+       * src/gtk/spell_entry.h
+               Forgot to add files
+
 2009-02-11 [colin]     3.7.0cvs58
 
        * src/compose.c
index 792fda286a72818b3e74197d128098e0d18e8cb1..5fc9433cd43d1ef2d39ab5792b0cd38e281f2cba 100644 (file)
--- a/PATCHSETS
+++ b/PATCHSETS
 ( cvs diff -u -r 1.39.2.16 -r 1.39.2.17 src/matcher.h;  ) > 3.7.0cvs56.patchset
 ( cvs diff -u -r 1.1.2.20 -r 1.1.2.21 src/printing.c;  cvs diff -u -r 1.9.2.48 -r 1.9.2.49 src/common/defs.h;  ) > 3.7.0cvs57.patchset
 ( cvs diff -u -r 1.382.2.498 -r 1.382.2.499 src/compose.c;  cvs diff -u -r 1.20.2.21 -r 1.20.2.22 src/gtk/Makefile.am;  cvs diff -u -r 1.9.2.64 -r 1.9.2.65 src/gtk/gtkaspell.c;  cvs diff -u -r 1.5.2.16 -r 1.5.2.17 src/gtk/gtkaspell.h;  ) > 3.7.0cvs58.patchset
+( diff -u /dev/null src/gtk/spell_entry.c;  diff -u /dev/null src/gtk/spell_entry.h;  ) > 3.7.0cvs59.patchset
index 91c518f0247d31d23b278b5eb7a8887f26793385..a6e4242de2dc40138c9f3111aa405fc69c728e9a 100644 (file)
@@ -11,7 +11,7 @@ MINOR_VERSION=7
 MICRO_VERSION=0
 INTERFACE_AGE=0
 BINARY_AGE=0
-EXTRA_VERSION=58
+EXTRA_VERSION=59
 EXTRA_RELEASE=
 EXTRA_GTK2_VERSION=
 
diff --git a/src/gtk/spell_entry.c b/src/gtk/spell_entry.c
new file mode 100644 (file)
index 0000000..b21e17d
--- /dev/null
@@ -0,0 +1,666 @@
+/*
+ * @file libsexy/sexy-icon-entry.c Entry widget
+ *
+ * @Copyright (C) 2004-2006 Christian Hammond.
+ * Some of this code is from gtkspell, Copyright (C) 2002 Evan Martin.
+ *
+ * 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 library 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.
+ *
+ * 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
+ */
+
+#ifdef HAVE_CONFIG_H
+#  include "config.h"
+#endif
+
+#ifdef USE_ENCHANT
+
+#include <glib.h>
+#include <glib/gi18n.h>
+
+#include <gdk/gdk.h>
+#include <gdk/gdkkeysyms.h>
+
+#include <string.h>
+#include <glib.h>
+#include <gtk/gtkwidget.h>
+#include <gtk/gtkentry.h>
+#include <gtk/gtkseparator.h>
+#include <gtk/gtkmenuitem.h>
+
+#include "spell_entry.h"
+#include "prefs_common.h"
+#include "codeconv.h"
+#include "defs.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);
+static gint claws_spell_entry_button_press     (GtkWidget *widget,
+                                                GdkEventButton *event);
+static gboolean claws_spell_entry_popup_menu   (GtkWidget *widget,
+                                                ClawsSpellEntry *entry);
+static void claws_spell_entry_populate_popup   (ClawsSpellEntry *entry,
+                                                GtkMenu *menu,
+                                                gpointer data);
+static void claws_spell_entry_changed          (GtkEditable *editable,
+                                                gpointer data);
+
+struct _ClawsSpellEntryPriv
+{
+       PangoAttrList        *attr_list;
+       gint                  mark_character;
+       gchar               **words;
+       gint                 *word_starts;
+       gint                 *word_ends;
+};
+
+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)); 
+
+
+static void claws_spell_entry_class_init(ClawsSpellEntryClass *klass)
+{
+       GObjectClass    *g_object_class;
+       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;
+       
+       g_type_class_add_private(g_object_class,
+                       sizeof(struct _ClawsSpellEntryPriv));
+}
+
+static void claws_spell_entry_init(ClawsSpellEntry *entry)
+{
+       entry->gtkaspell = NULL;
+       
+       entry->priv = g_new0(ClawsSpellEntryPriv, 1);
+       entry->priv->attr_list = pango_attr_list_new();
+                                        
+       g_signal_connect(G_OBJECT(entry), "popup-menu",
+                       G_CALLBACK(claws_spell_entry_popup_menu), entry);
+       g_signal_connect(G_OBJECT(entry), "populate-popup",
+                       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);
+}
+
+static void claws_spell_entry_destroy(GtkObject *object)
+{
+       GTK_OBJECT_CLASS(parent_class)->destroy(object);
+}
+
+GtkWidget *claws_spell_entry_new(void)
+{
+       return GTK_WIDGET( g_object_new(CLAWS_TYPE_SPELL_ENTRY, NULL) );
+}
+
+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);
+
+       entry->gtkaspell = gtkaspell;
+}
+
+static gint gtk_entry_find_position (GtkEntry *entry, gint x)
+{
+       PangoLayout *layout;
+       PangoLayoutLine *line;
+       const gchar *text;
+       gint cursor_index;
+       gint index;
+       gint pos;
+       gboolean trailing;
+
+       x = x + entry->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;
+
+       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;
+               } else {
+                       index = cursor_index;
+                       trailing = FALSE;
+               }
+       }
+
+       pos = g_utf8_pointer_to_offset (text, text + index);
+       pos += trailing;
+
+       return pos;
+}
+
+static void get_word_extents_from_position(ClawsSpellEntry *entry, gint *start,
+                                          gint *end, guint position)
+{
+       const gchar *text;
+       gint i, bytes_pos;
+
+       *start = -1;
+       *end = -1;
+
+       if (entry->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];
+                       return;
+               }
+       }
+}
+
+static gchar *get_word(ClawsSpellEntry *entry, const int start, const int end)
+{
+       const gchar *text;
+       gchar *word;
+       
+       if (start >= end)
+               return NULL;
+
+       text = gtk_entry_get_text(GTK_ENTRY(entry));
+       word = g_new0(gchar, end - start + 2);
+       g_strlcpy(word, text + start, end - start + 1);
+
+       return word;
+}
+
+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));
+
+       start_pos = entry->gtkaspell->start_pos;
+       end_pos = entry->gtkaspell->end_pos;
+               
+       cursor = gtk_editable_get_position(GTK_EDITABLE(entry));
+       /* 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;
+
+       gtk_editable_delete_text(GTK_EDITABLE(entry), start_pos, end_pos);
+       gtk_editable_insert_text(GTK_EDITABLE(entry), newword, strlen(newword),
+                                                        &start_pos);
+       gtk_editable_set_position(GTK_EDITABLE(entry), cursor);
+}
+
+
+static gboolean word_misspelled(ClawsSpellEntry *entry, int start, int end)
+{
+       gchar *word;
+       gboolean ret;
+
+       word = get_word(entry, start, end);
+       if (word == NULL)
+               return FALSE;
+               
+       ret = gtkaspell_misspelled_test(entry->gtkaspell, word);
+
+       g_free(word);
+       return ret;
+}
+
+static void entry_strsplit_utf8(GtkEntry *entry, gchar ***set, gint **starts, gint **ends)
+{
+       PangoLayout   *layout;
+       PangoLogAttr  *log_attrs;
+       const gchar   *text;
+       gint           n_attrs, n_strings, i, j;
+
+       layout = gtk_entry_get_layout(GTK_ENTRY(entry));
+       text = gtk_entry_get_text(GTK_ENTRY(entry));
+       pango_layout_get_log_attrs(layout, &log_attrs, &n_attrs);
+
+       /* Find how many words we have */
+       n_strings = 0;
+       for (i = 0; i < n_attrs; i++)
+               if (log_attrs[i].is_word_start)
+                       n_strings++;
+
+       *set    = g_new0(gchar *, n_strings + 1);
+       *starts = g_new0(gint, n_strings);
+       *ends   = g_new0(gint, n_strings);
+
+       /* Copy out strings */
+       for (i = 0, j = 0; i < n_attrs; i++) {
+               if (log_attrs[i].is_word_start) {
+                       gint cend, bytes;
+                       gchar *start;
+
+                       /* Find the end of this string */
+                       cend = i;
+                       while (!(log_attrs[cend].is_word_end))
+                               cend++;
+
+                       /* Copy sub-string */
+                       start = g_utf8_offset_to_pointer(text, i);
+                       bytes = (gint) (g_utf8_offset_to_pointer(text, cend) - start);
+                       (*set)[j]    = g_new0(gchar, bytes + 1);
+                       (*starts)[j] = (gint) (start - text);
+                       (*ends)[j]   = (gint) (start - text + bytes);
+                       g_utf8_strncpy((*set)[j], start, cend - i);
+
+                       /* Move on to the next word */
+                       j++;
+               }
+       }
+
+       g_free (log_attrs);
+}
+
+static void insert_misspelled_marker(ClawsSpellEntry *entry, guint start, guint end)
+{
+       guint16 red   = (guint16) (((gdouble)((prefs_common.misspelled_col & 
+                                       0xff0000) >> 16) / 255.0) * 65535.0);
+       guint16 green = (guint16) (((gdouble)((prefs_common.misspelled_col & 
+                                       0x00ff00) >> 8) / 255.0) * 65535.0);
+       guint16 blue  = (guint16) (((gdouble) (prefs_common.misspelled_col & 
+                                       0x0000ff) / 255.0) * 65535.0);
+       PangoAttribute *fcolor, *ucolor, *unline;
+       
+       if(prefs_common.misspelled_col != 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);
+       } else {
+               ucolor = pango_attr_underline_color_new (65535, 0, 0);
+               unline = pango_attr_underline_new (PANGO_UNDERLINE_ERROR);
+
+               ucolor->start_index = start;
+               unline->start_index = start;
+
+               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);
+       }
+}
+
+static gboolean check_word(ClawsSpellEntry *entry, int start, int end)
+{
+       GtkAspell *gtkaspell = entry->gtkaspell;
+       PangoAttrIterator *it;
+       gint s, e;
+       gboolean misspelled;
+       gchar *text = gtk_editable_get_chars(GTK_EDITABLE(entry), 0, -1);
+       gchar *word = NULL;
+
+       /* 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);
+       if (it == NULL)
+               return FALSE;
+       do {
+               pango_attr_iterator_range(it, &s, &e);
+               if (s == start) {
+                       GSList *attrs = pango_attr_iterator_get_attrs(it);
+                       g_slist_foreach(attrs, (GFunc) pango_attribute_destroy, NULL);
+                       g_slist_free(attrs);
+               }
+       } while (pango_attr_iterator_next(it));
+       pango_attr_iterator_destroy(it);
+
+       if ((misspelled = word_misspelled(entry, start, end))) {
+               insert_misspelled_marker(entry, start, end);
+       
+               word = get_word(entry, start, end);
+               strncpy(gtkaspell->theword, (gchar *)word, GTKASPELLWORDSIZE - 1);
+               gtkaspell->theword[GTKASPELLWORDSIZE - 1] = 0;
+               gtkaspell->start_pos  = g_utf8_pointer_to_offset(text, (text+start));
+               gtkaspell->end_pos    = g_utf8_pointer_to_offset(text, (text+end));
+               gtkaspell_free_suggestions_list(gtkaspell);
+               g_free(word);
+       }
+       
+       g_free(text);
+       
+       return misspelled;
+}
+
+void claws_spell_entry_recheck_all(ClawsSpellEntry *entry)
+{
+       GdkRectangle rect;
+       PangoLayout *layout;
+       int length, i;
+
+       g_return_if_fail(CLAWS_IS_SPELL_ENTRY(entry));
+       g_return_if_fail(entry->gtkaspell != NULL);
+
+       if (entry->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();
+
+       /* Loop through words */
+       for (i = 0; entry->priv->words[i]; i++) {
+               length = strlen(entry->priv->words[i]);
+               if (length == 0)
+                       continue;
+               check_word(entry, entry->priv->word_starts[i], entry->priv->word_ends[i]);
+       }
+
+       layout = gtk_entry_get_layout(GTK_ENTRY(entry));
+       pango_layout_set_attributes(layout, entry->priv->attr_list);
+
+       if (GTK_WIDGET_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);
+       }
+}
+
+static gint claws_spell_entry_expose(GtkWidget *widget, GdkEventExpose *event)
+{
+       ClawsSpellEntry *entry = CLAWS_SPELL_ENTRY(widget);
+       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);
+       }
+
+       return GTK_WIDGET_CLASS(parent_class)->expose_event (widget, event);
+}
+
+static gint claws_spell_entry_button_press(GtkWidget *widget, GdkEventButton *event)
+{
+       ClawsSpellEntry *entry = CLAWS_SPELL_ENTRY(widget);
+       GtkEntry *gtk_entry = GTK_ENTRY(widget);
+       gint pos;
+
+       pos = gtk_entry_find_position(gtk_entry, event->x);
+       entry->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));
+       return FALSE;
+}
+
+static void set_position(gpointer data, gint pos)
+{
+       gtk_editable_set_position(GTK_EDITABLE(data), pos);
+}
+
+static gboolean find_misspelled_cb(gpointer data, gboolean forward)
+{
+       ClawsSpellEntry *entry = (ClawsSpellEntry *)data;
+       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)
+               return FALSE;
+
+       gtkaspell->orig_pos = gtk_editable_get_position(GTK_EDITABLE(entry));
+       text = gtk_editable_get_chars(GTK_EDITABLE(entry), 0, -1);
+       cursor = g_utf8_offset_to_pointer(text, gtkaspell->orig_pos) - text;
+
+       if (gtk_editable_get_selection_bounds(GTK_EDITABLE(entry), &start, &end)) {
+               minpos = g_utf8_offset_to_pointer(text, start) - text;
+               maxpos = g_utf8_offset_to_pointer(text, end) - text;
+       } else {
+               minpos = forward ? cursor : 0;
+               maxpos = forward ? strlen(text)-1 : cursor;
+       }
+       g_free(text);
+
+       while(entry->priv->words[words_len])
+               words_len++;
+
+       if (forward) {
+               for(i=0; i < words_len; i++)
+                       if (entry->priv->word_ends[i] > minpos &&
+                           (misspelled = check_word(entry,
+                                       entry->priv->word_starts[i],
+                                       entry->priv->word_ends[i])))
+                               break;
+       } else {
+               for(i=words_len-1; i >= 0; i--)
+                       if (entry->priv->word_starts[i] < maxpos &&
+                           (misspelled = check_word(entry,
+                                       entry->priv->word_starts[i],
+                                       entry->priv->word_ends[i])))
+                               break;
+       }
+       
+       return misspelled;
+}
+
+static gboolean check_word_cb(gpointer data)
+{
+       ClawsSpellEntry *entry = (ClawsSpellEntry *)data;
+       gint start, end;
+       
+       get_word_extents_from_position(entry, &start, &end, entry->priv->mark_character);
+       return check_word(entry, start, end);
+}
+
+static void replace_word_cb(gpointer data, const gchar *newword)
+{
+       replace_word((ClawsSpellEntry *) data, newword);
+}
+
+static void set_menu_pos(GtkMenu *menu, gint *x, gint *y, 
+                        gboolean *push_in, gpointer data)
+{
+       ClawsSpellEntry *entry = (ClawsSpellEntry *) data;
+       GtkAspell *gtkaspell = entry->gtkaspell;
+       gint pango_offset, win_x, win_y, scr_x, scr_y, text_index, entry_x;
+       gchar *text;
+       GtkRequisition subject_rq;
+       PangoLayout *layout = gtk_entry_get_layout(GTK_ENTRY(entry));
+       PangoLayoutLine *line = pango_layout_get_lines(layout)->data;
+
+       gtk_widget_get_child_requisition(GTK_WIDGET(entry), &subject_rq);
+       
+       /* screen -> compose window coords */
+       gdk_window_get_origin(GTK_WIDGET(gtkaspell->parent_window)->window,
+                               &scr_x, &scr_y);
+
+       /* compose window -> subject entry coords */
+       gtk_widget_translate_coordinates(GTK_WIDGET(entry),
+                       gtkaspell->parent_window, 0, 0, &win_x, &win_y);
+
+       text = gtk_editable_get_chars(GTK_EDITABLE(entry), 0, -1);
+       text_index = g_utf8_offset_to_pointer(text, gtkaspell->end_pos) - text;
+       g_free(text);
+
+       pango_offset = gtk_entry_text_index_to_layout_index(GTK_ENTRY(entry),
+                                       text_index);
+       pango_layout_line_index_to_x(line, pango_offset, TRUE, &entry_x);
+
+       *x = scr_x + win_x + PANGO_PIXELS(entry_x) + 8;
+       *y = scr_y + win_y + subject_rq.height;
+}
+
+void claws_spell_entry_context_set(ClawsSpellEntry *entry)
+{
+       g_return_if_fail(CLAWS_IS_SPELL_ENTRY(entry));
+       g_return_if_fail(entry->gtkaspell != NULL);
+
+       entry->gtkaspell->ctx.set_position      = set_position;
+       entry->gtkaspell->ctx.set_menu_pos      = set_menu_pos;
+       entry->gtkaspell->ctx.find_misspelled   = find_misspelled_cb;
+       entry->gtkaspell->ctx.check_word        = check_word_cb;
+       entry->gtkaspell->ctx.replace_word      = replace_word_cb;
+        entry->gtkaspell->ctx.data             = (gpointer) entry;
+}
+
+static void claws_spell_entry_populate_popup(ClawsSpellEntry *entry, GtkMenu *menu,
+                                               gpointer data)
+{
+       GtkAspell *gtkaspell = entry->gtkaspell;
+       gint start, end;
+       gchar *word;
+       
+       if (gtkaspell == NULL)
+               return;
+       
+        get_word_extents_from_position(entry, &start, &end, entry->priv->mark_character);
+
+        if ((word = get_word(entry, start, end)) != NULL) {
+               strncpy(gtkaspell->theword, word, GTKASPELLWORDSIZE - 1);
+               g_free(word);
+       }
+
+        gtkaspell->misspelled = word_misspelled(entry, start, end);
+        
+        claws_spell_entry_context_set(entry);
+        gtkaspell_make_context_menu(menu, gtkaspell);
+}
+
+static void claws_spell_entry_changed(GtkEditable *editable, gpointer data)
+{
+       ClawsSpellEntry *entry = CLAWS_SPELL_ENTRY(editable);
+
+       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);
+       }
+       entry_strsplit_utf8(GTK_ENTRY(entry), &entry->priv->words, 
+                       &entry->priv->word_starts, &entry->priv->word_ends);
+       if(entry->gtkaspell->check_while_typing == TRUE)
+               claws_spell_entry_recheck_all(entry);
+}
+
+static void continue_check(gpointer *data)
+{
+       ClawsSpellEntry *entry = (ClawsSpellEntry *)data;
+       GtkAspell *gtkaspell = entry->gtkaspell;
+       gint pos = gtk_editable_get_position(GTK_EDITABLE(entry));
+       
+       if (gtkaspell->misspelled && pos < gtkaspell->end_check_pos)
+               gtkaspell->misspelled = gtkaspell_check_next_prev(gtkaspell, TRUE);
+       else
+               gtkaspell->continue_check = NULL;
+}
+
+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);
+       
+       if (!gtk_editable_get_selection_bounds(GTK_EDITABLE(entry), &start, &end)) {
+               text = gtk_editable_get_chars(GTK_EDITABLE(entry), 0, -1);      
+               
+               start = 0;
+               end = g_utf8_strlen(text, -1) - 1;
+               
+               g_free(text);
+       }
+
+       gtk_editable_set_position(GTK_EDITABLE(entry), start);
+       entry->gtkaspell->continue_check = continue_check;
+       entry->gtkaspell->end_check_pos  = end;
+
+       claws_spell_entry_context_set(entry);
+       entry->gtkaspell->misspelled = 
+                       gtkaspell_check_next_prev(entry->gtkaspell, TRUE);
+}
+
+void claws_spell_entry_check_backwards(ClawsSpellEntry *entry)
+{
+       g_return_if_fail(CLAWS_IS_SPELL_ENTRY(entry));
+       g_return_if_fail(entry->gtkaspell != NULL);
+       
+       entry->gtkaspell->continue_check = NULL;
+       claws_spell_entry_context_set(entry);
+       gtkaspell_check_next_prev(entry->gtkaspell, FALSE);
+}
+
+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);
+
+       entry->gtkaspell->continue_check = NULL;
+       claws_spell_entry_context_set(entry);
+       gtkaspell_check_next_prev(entry->gtkaspell, TRUE);
+}
+
+#endif  /* USE_ENCHANT */
diff --git a/src/gtk/spell_entry.h b/src/gtk/spell_entry.h
new file mode 100644 (file)
index 0000000..c2846f6
--- /dev/null
@@ -0,0 +1,89 @@
+/*
+ * @file libsexy/sexy-icon-entry.h Entry widget
+ *
+ * @Copyright (C) 2004-2006 Christian Hammond.
+ * Some of this code is from gtkspell, Copyright (C) 2002 Evan Martin.
+ *
+ * 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 library 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.
+ *
+ * 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) 2008 Pawel Pekala
+ */
+
+#ifndef __SPELL_ENTRY_H__
+#define __SPELL_ENTRY_H__
+
+#ifdef HAVE_CONFIG_H
+#  include "config.h"
+#endif
+
+#ifdef USE_ENCHANT
+
+G_BEGIN_DECLS
+
+typedef struct _ClawsSpellEntry ClawsSpellEntry;
+typedef struct _ClawsSpellEntryClass ClawsSpellEntryClass;
+typedef struct _ClawsSpellEntryPriv ClawsSpellEntryPriv;
+
+#include <gtk/gtkentry.h>
+#include <gtk/gtktextview.h>
+#include <gtk/gtkcombobox.h>
+#include "gtkaspell.h"
+
+#define CLAWS_TYPE_SPELL_ENTRY            (claws_spell_entry_get_type())
+#define CLAWS_SPELL_ENTRY(obj)            (G_TYPE_CHECK_INSTANCE_CAST((obj), CLAWS_TYPE_SPELL_ENTRY, ClawsSpellEntry))
+#define CLAWS_SPELL_ENTRY_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST((klass), CLAWS_TYPE_SPELL_ENTRY, ClawsSpellEntryClass))
+#define CLAWS_IS_SPELL_ENTRY(obj)         (G_TYPE_CHECK_INSTANCE_TYPE((obj), CLAWS_TYPE_SPELL_ENTRY))
+
+struct _ClawsSpellEntry
+{
+       GtkEntry parent_object;
+       
+       ClawsSpellEntryPriv *priv;
+       GtkAspell *gtkaspell;
+       
+       void (*gtk_reserved1)(void);
+       void (*gtk_reserved2)(void);
+       void (*gtk_reserved3)(void);
+       void (*gtk_reserved4)(void);
+};
+
+struct _ClawsSpellEntryClass
+{
+       GtkEntryClass parent_class;
+
+       void (*gtk_reserved1)(void);
+       void (*gtk_reserved2)(void);
+       void (*gtk_reserved3)(void);
+       void (*gtk_reserved4)(void);
+};
+
+GType          claws_spell_entry_get_type              (void);
+GtkWidget *    claws_spell_entry_new                   (void);
+void           claws_spell_entry_set_gtkaspell         (ClawsSpellEntry *entry,
+                                                        GtkAspell *gtkaspell);
+void           claws_spell_entry_recheck_all           (ClawsSpellEntry *entry);
+void           claws_spell_entry_check_all             (ClawsSpellEntry *entry);
+void           claws_spell_entry_context_set           (ClawsSpellEntry *entry);
+void           claws_spell_entry_check_backwards       (ClawsSpellEntry *entry);
+void           claws_spell_entry_check_forwards_go     (ClawsSpellEntry *entry);
+
+
+G_END_DECLS
+
+#endif  /* USE_ENCHANT */
+#endif /* __SPELL_ENTRY_H__ */