remove all gtk3 conditionals
[claws.git] / src / gtk / spell_entry.c
index 1d6dbb57f788a9cfeca28e2cf1e69942d974bfbc..44b91bcddb2681672188471a08392b25038d540b 100644 (file)
@@ -3,7 +3,7 @@
  *
  * @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
@@ -22,6 +22,7 @@
 
 #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,
@@ -63,59 +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;
-#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);
@@ -123,38 +123,14 @@ 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);
+       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)
 {
@@ -168,28 +144,33 @@ void claws_spell_entry_set_gtkaspell(ClawsSpellEntry *entry, GtkAspell *gtkaspel
        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;
@@ -207,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;
                }
        }
@@ -246,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;
@@ -254,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),
@@ -353,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);
@@ -377,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;
@@ -393,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 {
@@ -425,76 +410,75 @@ 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;
 
        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;
 }
 
@@ -506,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));
@@ -528,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;
        }
        
@@ -553,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);
 }
 
@@ -578,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 */
@@ -614,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, *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);
@@ -641,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;