*
* @Copyright (C) 2004-2006 Christian Hammond.
* Some of this code is from gtkspell, Copyright (C) 2002 Evan Martin.
- * Adapted for Claws Mail (c) 2009-2011 Pawel Pekala and the Claws Mail team
+ * Adapted for Claws Mail (c) 2009-2012 Pawel Pekala and the Claws Mail team
*
* 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
#ifdef HAVE_CONFIG_H
# include "config.h"
+#include "claws-features.h"
#endif
#ifdef USE_ENCHANT
#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);
-#if !GTK_CHECK_VERSION(3, 0, 0)
static void claws_spell_entry_destroy (GtkObject *object);
static gint claws_spell_entry_expose (GtkWidget *widget,
GdkEventExpose *event);
-#else
-static void claws_spell_entry_destroy (GtkWidget *object);
-static gint claws_spell_entry_expose (GtkWidget *widget,
- cairo_t *cr);
-#endif
static gint claws_spell_entry_button_press (GtkWidget *widget,
GdkEventButton *event);
static gboolean claws_spell_entry_popup_menu (GtkWidget *widget,
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;
-#if !GTK_CHECK_VERSION(3, 0, 0)
- GtkObjectClass *gtk_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;
-
-#if !GTK_CHECK_VERSION(3, 0, 0)
gtk_object_class = GTK_OBJECT_CLASS(klass);
gtk_object_class->destroy = claws_spell_entry_destroy;
-#endif
widget_class = GTK_WIDGET_CLASS(klass);
widget_class->button_press_event = claws_spell_entry_button_press;
-#if !GTK_CHECK_VERSION(3, 0, 0)
widget_class->expose_event = claws_spell_entry_expose;
-#else
- widget_class->draw = claws_spell_entry_expose;
- widget_class->destroy = claws_spell_entry_destroy;
-#endif
-
+
+#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);
G_CALLBACK(claws_spell_entry_populate_popup), NULL);
g_signal_connect(G_OBJECT(entry), "changed",
G_CALLBACK(claws_spell_entry_changed), NULL);
+ g_signal_connect(G_OBJECT(entry), "preedit-changed",
+ G_CALLBACK(claws_spell_entry_preedit_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);
-}
-
-#if !GTK_CHECK_VERSION(3, 0, 0)
static void claws_spell_entry_destroy(GtkObject *object)
{
GTK_OBJECT_CLASS(parent_class)->destroy(object);
}
-#else
-static void claws_spell_entry_destroy(GtkWidget *object)
-{
- GTK_WIDGET_CLASS(parent_class)->destroy(object);
-}
-#endif
GtkWidget *claws_spell_entry_new(void)
{
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", ¤t_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;
{
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;
}
}
{
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;
/* 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),
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);
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;
/* 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 {
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;
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 (gtkut_widget_get_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);
}
}
-#if !GTK_CHECK_VERSION(3, 0, 0)
static gint claws_spell_entry_expose(GtkWidget *widget, GdkEventExpose *event)
-#else
-static gint claws_spell_entry_expose(GtkWidget *widget, cairo_t *cr)
-#endif
{
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);
}
-#if !GTK_CHECK_VERSION(3, 0, 0)
return GTK_WIDGET_CLASS(parent_class)->expose_event (widget, event);
-#else
- return GTK_WIDGET_CLASS(parent_class)->draw (widget, cr);
-#endif
}
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;
}
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));
}
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;
}
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);
}
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 */
gpointer data)
{
GtkAspell *gtkaspell = entry->gtkaspell;
+ ClawsSpellEntryPrivate *priv = CLAWS_SPELL_ENTRY_GET_PRIVATE(entry);
gint start, end;
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);
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;