Sat, 26 Apr 2014 13:23:38 +0200
PidginWebView: spell checking dictionary selection
| configure.ac | file | annotate | diff | comparison | revisions | |
| pidgin/Makefile.am | file | annotate | diff | comparison | revisions | |
| pidgin/gtkwebview.c | file | annotate | diff | comparison | revisions |
--- a/configure.ac Fri Apr 25 23:35:37 2014 +0200 +++ b/configure.ac Sat Apr 26 13:23:38 2014 +0200 @@ -546,6 +546,10 @@ [AS_HELP_STRING([--disable-gtkspell], [compile without GtkSpell automatic spell checking])], enable_gtkspell="$enableval", enable_gtkspell="yes") +AC_ARG_ENABLE(enchant, + [AS_HELP_STRING([--disable-enchant], + [compile without Enchant spell checking support])], + enable_enchant="$enableval", enable_enchant="yes") AC_ARG_ENABLE(gevolution, [AS_HELP_STRING([--enable-gevolution], [compile with the Evolution plugin])], @@ -647,6 +651,31 @@ AC_SUBST(WEBKIT_PC_MODULE) dnl ####################################################################### + dnl # Check if we should compile with enchant support + dnl ####################################################################### + dnl We need enchant for spell checking dictionary enumeration, + dnl because webkit1 doesn't have this. + use_enchant=no + if test "x$enable_enchant" = "xyes" ; then + use_enchant=yes + PKG_CHECK_MODULES(ENCHANT, enchant, , [ + AC_MSG_RESULT(no) + use_enchant=no + ]) + if test "x$force_deps" = "xyes" -a "x$use_enchant" = "xno"; then + AC_MSG_ERROR([ +Enchant development headers not found. +Use --disable-enchant if you do not need it. +]) + fi + if test "x$use_enchant" = "xyes" ; then + AC_DEFINE(USE_ENCHANT, 1, [Define if we're using enchant]) + AC_SUBST(ENCHANT_CFLAGS) + AC_SUBST(ENCHANT_LIBS) + fi + fi + + dnl ####################################################################### dnl # Check if we should compile with X support dnl ####################################################################### if test "x$with_x" = "xyes" ; then @@ -3217,6 +3246,7 @@ echo Use X Session Management...... : $enable_sm echo Use startup notification...... : $enable_startup_notification echo Build with GtkSpell support... : $enable_gtkspell +echo Build with Enchant support.... : $use_enchant echo Build with GCR widgets........ : $enable_gcr echo Build Unity integration plugin.: $enable_unity echo
--- a/pidgin/Makefile.am Fri Apr 25 23:35:37 2014 +0200 +++ b/pidgin/Makefile.am Sat Apr 26 13:23:38 2014 +0200 @@ -195,6 +195,7 @@ -version-info $(PURPLE_LT_VERSION_INFO) $(LIBPIDGIN_WIN32RES_LDFLAGS) libpidgin_la_LIBADD = \ @LIBOBJS@ \ + $(ENCHANT_LIBS) \ $(GLIB_LIBS) \ $(GCR_LIBS) \ $(DBUS_LIBS) \ @@ -225,6 +226,7 @@ -I$(top_srcdir)/libpurple/ \ -I$(top_builddir) \ -I$(top_srcdir) \ + $(ENCHANT_CFLAGS) \ $(GLIB_CFLAGS) \ $(GCR_CFLAGS) \ $(GSTREAMER_CFLAGS) \
--- a/pidgin/gtkwebview.c Fri Apr 25 23:35:37 2014 +0200 +++ b/pidgin/gtkwebview.c Sat Apr 26 13:23:38 2014 +0200 @@ -28,6 +28,9 @@ #include "pidginstock.h" #include <gdk/gdkkeysyms.h> +#ifdef USE_ENCHANT +#include <enchant.h> +#endif #include "gtkutils.h" #include "gtksmiley-manager.h" @@ -111,6 +114,9 @@ /* WebKit inspector */ WebKitWebView *inspector_view; GtkWindow *inspector_win; + + /* helper scripts */ + gboolean refresh_spell_installed; } PidginWebViewPriv; /****************************************************************************** @@ -130,6 +136,7 @@ static GHashTable *globally_loaded_images = NULL; guint globally_loaded_images_refcnt = 0; +static GList *spellcheck_languages = NULL; /****************************************************************************** * Helpers @@ -567,6 +574,84 @@ return menuitem; } +#ifdef USE_ENCHANT + +static void +webview_refresh_spellcheck(WebKitWebView *webview) +{ + PidginWebViewPriv *priv = PIDGIN_WEBVIEW_GET_PRIVATE(webview); + static const gchar jsfunc[] = + "var pidgin_refresh_spellcheck = function() {" + "var selection = window.getSelection();" + "var originalSelection = selection.getRangeAt(0);" + "for (var i = 0; i < 5; i++)" + "selection.modify('move', 'backward', 'line');" + "for (i = 0; i < 100; i++)" + "selection.modify('move', 'forward', 'word');" + "selection.removeAllRanges();" + "selection.addRange(originalSelection);" + "};"; + + if (!priv->refresh_spell_installed) { + priv->refresh_spell_installed = TRUE; + webkit_web_view_execute_script(webview, jsfunc); + } + + webkit_web_view_execute_script(webview, "pidgin_refresh_spellcheck()"); +} + +static void +webview_lang_select(GtkMenuItem *item, const gchar *lang) +{ + WebKitWebView *webview = g_object_get_data(G_OBJECT(item), "gtkwebview"); + WebKitWebSettings *settings; + + g_return_if_fail(lang != NULL); + g_return_if_fail(webview != NULL); + + settings = webkit_web_view_get_settings(webview); + g_object_set(G_OBJECT(settings), + "spell-checking-languages", lang, NULL); + webview_refresh_spellcheck(webview); +} + +static GtkWidget * +get_spelldict_menu(WebKitWebView *webview) +{ + GtkWidget *menuitem; + GtkWidget *menu; + GList *it; + + if (spellcheck_languages == NULL) + return NULL; + + menuitem = gtk_image_menu_item_new_with_mnemonic(_("_Language")); + menu = gtk_menu_new(); + gtk_menu_item_set_submenu(GTK_MENU_ITEM(menuitem), menu); + for (it = spellcheck_languages; it; it = g_list_next(it)) { + GtkWidget *item; + const gchar *lang = it->data; + + /* we could convert lang id to name here */ + item = gtk_menu_item_new_with_label(lang); + g_object_set_data(G_OBJECT(item), "gtkwebview", webview); + g_signal_connect(item, "activate", + G_CALLBACK(webview_lang_select), (gpointer)lang); + gtk_widget_show(item); + gtk_menu_shell_append(GTK_MENU_SHELL(menu), item); + } + + return menuitem; +} + +#else +static GtkWidget * +get_spelldict_menu(WebKitWebView *webview) +{ + return NULL; +} +#endif + static void webview_image_saved(GtkWidget *dialog, gint response, gpointer _unused) { @@ -816,8 +901,9 @@ if (webkit_web_view_get_editable(webview)) { GtkWidget *im = get_input_methods_menu(webview); GtkWidget *unicode = get_unicode_menu(webview); - - if (im || unicode) + GtkWidget *spelldict = get_spelldict_menu(webview); + + if (im || unicode || spelldict) pidgin_separator(menu); if (im) { @@ -829,6 +915,11 @@ gtk_menu_shell_append(GTK_MENU_SHELL(menu), unicode); gtk_widget_show(unicode); } + + if (spelldict) { + gtk_menu_shell_append(GTK_MENU_SHELL(menu), spelldict); + gtk_widget_show(spelldict); + } } g_signal_emit_by_name(G_OBJECT(webview), "populate-popup", menu); @@ -1159,6 +1250,61 @@ G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec); } +#ifdef USE_ENCHANT + +static void +fill_spellcheck_dicts_cb(const gchar *lang_tag, const gchar *provider_name, + const gchar *provider_desc, const gchar *provider_file, + void *_unused) +{ + gboolean is_dialect; + GList *it; + + /* It's not super efficient, but even with large number of installed + * dictionaries (100?) it won't hurt us. */ + + is_dialect = (strchr(lang_tag, '_') != NULL); + + if (is_dialect) { + for (it = spellcheck_languages; it; it = g_list_next(it)) { + gchar *it_lang = it->data; + + if (purple_str_has_prefix(lang_tag, it_lang)) + return; + } + } else { + GList *next; + for (it = spellcheck_languages; it; it = next) { + gchar *it_lang = it->data; + next = g_list_next(it); + + if (!purple_str_has_prefix(it_lang, lang_tag)) + continue; + + g_free(it_lang); + spellcheck_languages = + g_list_delete_link(spellcheck_languages, it); + } + } + + spellcheck_languages = g_list_prepend(spellcheck_languages, + g_strdup(lang_tag)); +} + +static void +fill_spellcheck_dicts(void) +{ + EnchantBroker *eb; + + eb = enchant_broker_init(); + enchant_broker_list_dicts(eb, fill_spellcheck_dicts_cb, NULL); + enchant_broker_free(eb); + spellcheck_languages = g_list_sort(spellcheck_languages, + (GCompareFunc)strcmp); +} + +#endif + static void pidgin_webview_class_init(PidginWebViewClass *klass, gpointer userdata) { @@ -1267,6 +1413,10 @@ G_REGEX_DOTALL | G_REGEX_OPTIMIZE, 0, NULL); empty_html_re = g_regex_new("<(?!img)[^>]*>", G_REGEX_DOTALL | G_REGEX_OPTIMIZE, 0, NULL); + +#ifdef USE_ENCHANT + fill_spellcheck_dicts(); +#endif } static void