/pidgin/main: e173a6f9a021: PidginWebView: spell checking dictio...

Tomasz Wasilczyk twasilczyk at pidgin.im
Sat Apr 26 07:23:47 EDT 2014


Changeset: e173a6f9a0212a144731a2d90ff12b7337d2c6d8
Author:	 Tomasz Wasilczyk <twasilczyk at pidgin.im>
Date:	 2014-04-26 13:23 +0200
Branch:	 default
URL: https://hg.pidgin.im/pidgin/main/rev/e173a6f9a021

Description:

PidginWebView: spell checking dictionary selection

diffstat:

 configure.ac        |   30 ++++++++++
 pidgin/Makefile.am  |    2 +
 pidgin/gtkwebview.c |  154 +++++++++++++++++++++++++++++++++++++++++++++++++++-
 3 files changed, 184 insertions(+), 2 deletions(-)

diffs (286 lines):

diff --git a/configure.ac b/configure.ac
--- a/configure.ac
+++ b/configure.ac
@@ -546,6 +546,10 @@ AC_ARG_ENABLE(gtkspell,
 	[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 @@ installed to compile Pidgin.  If you wan
 	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 XScreenSaver Extension.... : $e
 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
diff --git a/pidgin/Makefile.am b/pidgin/Makefile.am
--- a/pidgin/Makefile.am
+++ b/pidgin/Makefile.am
@@ -195,6 +195,7 @@ libpidgin_la_LDFLAGS = -export-dynamic -
 	-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 @@ AM_CPPFLAGS = \
 	-I$(top_srcdir)/libpurple/ \
 	-I$(top_builddir) \
 	-I$(top_srcdir) \
+	$(ENCHANT_CFLAGS) \
 	$(GLIB_CFLAGS) \
 	$(GCR_CFLAGS) \
 	$(GSTREAMER_CFLAGS) \
diff --git a/pidgin/gtkwebview.c b/pidgin/gtkwebview.c
--- a/pidgin/gtkwebview.c
+++ b/pidgin/gtkwebview.c
@@ -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 @@ typedef struct _PidginWebViewPriv {
 	/* WebKit inspector */
 	WebKitWebView *inspector_view;
 	GtkWindow *inspector_win;
+
+	/* helper scripts */
+	gboolean refresh_spell_installed;
 } PidginWebViewPriv;
 
 /******************************************************************************
@@ -130,6 +136,7 @@ static GRegex *empty_html_re = NULL;
 static GHashTable *globally_loaded_images = NULL;
 guint globally_loaded_images_refcnt = 0;
 
+static GList *spellcheck_languages = NULL;
 
 /******************************************************************************
  * Helpers
@@ -567,6 +574,84 @@ get_unicode_menu(WebKitWebView *webview)
 	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 @@ do_popup_menu(WebKitWebView *webview, in
 	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 @@ do_popup_menu(WebKitWebView *webview, in
 			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 @@ pidgin_webview_get_property(GObject *obj
 	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 @@ pidgin_webview_class_init(PidginWebViewC
 		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



More information about the Commits mailing list