From 74a6005f2c98666f386df417201d1431b94e5ed2 Mon Sep 17 00:00:00 2001 From: Tamaranch <138-Tamaranch@users.noreply.gitlab.xfce.org> Date: Fri, 8 May 2020 17:24:33 +0200 Subject: [PATCH] Add gspell --- configure.ac.in | 18 ++++++ mousepad/Makefile.am | 2 + mousepad/mousepad-prefs-dialog.c | 6 ++ mousepad/mousepad-prefs-dialog.glade | 53 ++++++++++++++++ mousepad/mousepad-settings.h | 3 + mousepad/mousepad-util.c | 51 +++++++++++++++ mousepad/mousepad-util.h | 5 ++ mousepad/mousepad-view.c | 88 ++++++++++++++++++++++++++ mousepad/mousepad-view.h | 8 +++ mousepad/mousepad-window-ui.xml | 1 + mousepad/mousepad-window.c | 84 +++++++++++++++++++++++- mousepad/org.xfce.mousepad.gschema.xml | 7 ++ 12 files changed, 325 insertions(+), 1 deletion(-) diff --git a/configure.ac.in b/configure.ac.in index efdef10..a4a8d95 100644 --- a/configure.ac.in +++ b/configure.ac.in @@ -144,6 +144,23 @@ AS_IF([test "x$enable_dbus" = "xyes"], AC_DEFINE([HAVE_DBUS], [1], [Define if DBUS support is enabled]) ]) +dnl ************************ +dnl *** Check for gspell *** +dnl ************************ +AC_ARG_ENABLE([gspell], + [AS_HELP_STRING([--enable-gspell], + [Enable gspell support])], + [enable_gspell=$enableval], + [enable_gspell="no"]) + +AM_CONDITIONAL([HAVE_GSPELL], [test "x$enable_gspell" = "xyes"]) + +AS_IF([test "x$enable_gspell" = "xyes"], +[ + XDT_CHECK_PACKAGE([GSPELL], [gspell-1], [1.8.0]) + AC_DEFINE([HAVE_GSPELL], [1], [Define if gspell support is enabled]) +]) + dnl *********************************** dnl *** Check for debugging support *** dnl *********************************** @@ -180,6 +197,7 @@ echo echo "Build Configuration:" echo echo "* D-BUS support: $enable_dbus" +echo "* gspell support: $enable_gspell" echo "* Debug Support: $enable_debug" echo "* Use keyfile backend: $enable_keyfile_settings" echo "* Build with GTK+ 3: $enable_gtk3" diff --git a/mousepad/Makefile.am b/mousepad/Makefile.am index 81260c4..7d1640d 100644 --- a/mousepad/Makefile.am +++ b/mousepad/Makefile.am @@ -71,6 +71,7 @@ mousepad_CFLAGS = \ $(GTK_CFLAGS) \ $(GTHREAD_CFLAGS) \ $(GTKSOURCEVIEW_CFLAGS) \ + $(GSPELL_CFLAGS) \ $(PLATFORM_CFLAGS) \ $(XFCONF_CFLAGS) \ -DMOUSEPAD_GSETTINGS_SCHEMA_DIR=\""$(datadir)/glib-2.0/schemas"\" @@ -84,6 +85,7 @@ mousepad_LDADD = \ $(GTK_LIBS) \ $(GTHREAD_LIBS) \ $(GTKSOURCEVIEW_LIBS) \ + $(GSPELL_LIBS) \ $(XFCONF_LIBS) if HAVE_DBUS diff --git a/mousepad/mousepad-prefs-dialog.c b/mousepad/mousepad-prefs-dialog.c index 41b71e5..678d1e7 100644 --- a/mousepad/mousepad-prefs-dialog.c +++ b/mousepad/mousepad-prefs-dialog.c @@ -50,6 +50,9 @@ #define WID_TAB_MODE_COMBO "/prefs/editor/tab-mode-combo" #define WID_AUTO_INDENT_CHECK "/prefs/editor/auto-indent-check" #define WID_SMART_HOME_END_COMBO "/prefs/editor/smart-home-end-combo" +#if HAVE_GSPELL +#define WID_SPELL_CHECK_CHECK "/prefs/editor/spell-check-check" +#endif /* Window page */ #define WID_STATUSBAR_VISIBLE_CHECK "/prefs/window/general/show-statusbar-check" @@ -490,6 +493,9 @@ mousepad_prefs_dialog_init (MousepadPrefsDialog *self) /* Editor */ BIND_CHECKBOX (AUTO_INDENT); +#if HAVE_GSPELL + BIND_CHECKBOX (SPELL_CHECK); +#endif /* Window */ BIND_CHECKBOX (STATUSBAR_VISIBLE); diff --git a/mousepad/mousepad-prefs-dialog.glade b/mousepad/mousepad-prefs-dialog.glade index 7bd8064..a4bbd13 100644 --- a/mousepad/mousepad-prefs-dialog.glade +++ b/mousepad/mousepad-prefs-dialog.glade @@ -639,6 +639,59 @@ 1 + + + True + False + 0 + none + + + True + False + 6 + 6 + 12 + 6 + + + True + False + + + Enable spell check + True + True + False + True + + + 2 + 2 + 3 + GTK_FILL + GTK_FILL + + + + + + + + + True + False + <b>Spell Check</b> + True + + + + + False + True + 2 + + 1 diff --git a/mousepad/mousepad-settings.h b/mousepad/mousepad-settings.h index 4993045..29a2318 100644 --- a/mousepad/mousepad-settings.h +++ b/mousepad/mousepad-settings.h @@ -22,6 +22,9 @@ G_BEGIN_DECLS /* Setting names */ +#if HAVE_GSPELL +#define MOUSEPAD_SETTING_SPELL_CHECK "/preferences/view/spell-check" +#endif #define MOUSEPAD_SETTING_AUTO_INDENT "/preferences/view/auto-indent" #define MOUSEPAD_SETTING_FONT_NAME "/preferences/view/font-name" #define MOUSEPAD_SETTING_USE_DEFAULT_FONT "/preferences/view/use-default-monospace-font" diff --git a/mousepad/mousepad-util.c b/mousepad/mousepad-util.c index afdc640..a2c7d61 100644 --- a/mousepad/mousepad-util.c +++ b/mousepad/mousepad-util.c @@ -1164,3 +1164,54 @@ mousepad_util_container_move_children (GtkContainer *source, g_list_free (list); } + + + +#if HAVE_GSPELL +/* Subtract menu_2 from menu_1 if menu_2 != NULL, or menu items above the first separator otherwise */ +void +mousepad_util_menu_subtract (GtkMenu *menu_1, + GtkMenu *menu_2) +{ + GtkContainer *container_1, *container_2; + GList *list_1, *list_2, *iter_1, *iter_2; + const gchar *label; + + g_return_if_fail (GTK_IS_MENU (menu_1)); + + container_1 = GTK_CONTAINER (menu_1); + list_1 = gtk_container_get_children (container_1); + + if (menu_2 != NULL) + { + g_return_if_fail (GTK_IS_MENU (menu_2)); + container_2 = GTK_CONTAINER (menu_2); + list_2 = gtk_container_get_children (container_2); + for (iter_1 = list_1; iter_1 != NULL; iter_1 = g_list_next (iter_1)) + { + label = gtk_menu_item_get_label (iter_1->data); + for (iter_2 = list_2; iter_2 != NULL; iter_2 = g_list_next (iter_2)) + { + if (g_strcmp0 (label, gtk_menu_item_get_label (iter_2->data)) == 0) + { + gtk_container_remove (container_1, iter_1->data); + break; + } + } + } + g_list_free (list_2); + } + else + { + for (iter_1 = list_1; iter_1 != NULL; iter_1 = g_list_next (iter_1)) + { + label = gtk_menu_item_get_label (iter_1->data); + gtk_container_remove (container_1, iter_1->data); + if (g_strcmp0 (label, "") == 0) + break; + } + } + + g_list_free (list_1); +} +#endif diff --git a/mousepad/mousepad-util.h b/mousepad/mousepad-util.h index 679f6fb..536a594 100644 --- a/mousepad/mousepad-util.h +++ b/mousepad/mousepad-util.h @@ -123,6 +123,11 @@ gboolean mousepad_util_container_has_children (GtkContainer * void mousepad_util_container_clear (GtkContainer *container); +#if HAVE_GSPELL +void mousepad_util_menu_subtract (GtkMenu *menu_1, + GtkMenu *menu_2); +#endif + void mousepad_util_container_move_children (GtkContainer *source, GtkContainer *destination); diff --git a/mousepad/mousepad-view.c b/mousepad/mousepad-view.c index 802f116..ef5bf14 100644 --- a/mousepad/mousepad-view.c +++ b/mousepad/mousepad-view.c @@ -29,6 +29,10 @@ #include #endif +#if HAVE_GSPELL +#include +#endif + #include /* GTK+ 3 removed textview->im_context which is used for multi-selection and @@ -150,6 +154,13 @@ struct _MousepadView gchar *color_scheme; gboolean match_braces; + +#if HAVE_GSPELL + GspellTextView *gspell_view; + GspellChecker *gspell_checker; + GspellTextBuffer *gspell_buffer; + gboolean spell_check; +#endif }; @@ -162,6 +173,9 @@ enum PROP_SHOW_LINE_ENDINGS, PROP_COLOR_SCHEME, PROP_WORD_WRAP, +#if HAVE_GSPELL + PROP_SPELL_CHECK, +#endif PROP_MATCH_BRACES, NUM_PROPERTIES }; @@ -237,6 +251,17 @@ mousepad_view_class_init (MousepadViewClass *klass) FALSE, G_PARAM_READWRITE)); +#if HAVE_GSPELL + g_object_class_install_property ( + gobject_class, + PROP_SPELL_CHECK, + g_param_spec_boolean ("spell-check", + "SpellCheck", + "Whether to enable spell checking", + FALSE, + G_PARAM_READWRITE)); +#endif + g_object_class_install_property ( gobject_class, PROP_MATCH_BRACES, @@ -328,6 +353,9 @@ mousepad_view_init (MousepadView *view) #define BIND_(setting, prop) \ MOUSEPAD_SETTING_BIND (setting, view, prop, G_SETTINGS_BIND_DEFAULT) +#if HAVE_GSPELL + BIND_ (SPELL_CHECK, "spell-check"); +#endif BIND_ (AUTO_INDENT, "auto-indent"); BIND_ (FONT_NAME, "font-name"); BIND_ (SHOW_WHITESPACE, "show-whitespace"); @@ -373,6 +401,11 @@ mousepad_view_finalize (GObject *object) /* cleanup color scheme name */ g_free (view->color_scheme); +#if HAVE_GSPELL + if (G_LIKELY (view->gspell_checker != NULL)) + g_object_unref (view->gspell_checker); +#endif + (*G_OBJECT_CLASS (mousepad_view_parent_class)->finalize) (object); } @@ -403,6 +436,11 @@ mousepad_view_set_property (GObject *object, case PROP_WORD_WRAP: mousepad_view_set_word_wrap (view, g_value_get_boolean (value)); break; +#if HAVE_GSPELL + case PROP_SPELL_CHECK: + mousepad_view_set_spell_check (view, g_value_get_boolean (value), TRUE); + break; +#endif case PROP_MATCH_BRACES: mousepad_view_set_match_braces (view, g_value_get_boolean (value)); break; @@ -439,6 +477,11 @@ mousepad_view_get_property (GObject *object, case PROP_WORD_WRAP: g_value_set_boolean (value, mousepad_view_get_word_wrap (view)); break; +#if HAVE_GSPELL + case PROP_SPELL_CHECK: + g_value_set_boolean (value, mousepad_view_get_spell_check (view)); + break; +#endif case PROP_MATCH_BRACES: g_value_set_boolean (value, mousepad_view_get_match_braces (view)); break; @@ -2860,3 +2903,48 @@ mousepad_view_get_match_braces (MousepadView *view) return view->match_braces; } + + + +#if HAVE_GSPELL +void +mousepad_view_set_spell_check (MousepadView *view, + gboolean enabled, + gboolean external) +{ + g_return_if_fail (MOUSEPAD_IS_VIEW (view)); + + view->spell_check = enabled; + + /* Don't slow Mousepad when spell checking is disabled at startup */ + if (view->gspell_view == NULL && ! enabled) + return; + + /* The function call comes from the GUI (normal call), not from + * mousepad_window_menu_textview_shown to retrieve the gspell menu */ + if (external) + { + if (view->gspell_view == NULL) + { + view->gspell_view = gspell_text_view_get_from_gtk_text_view (GTK_TEXT_VIEW (view)); + view->gspell_checker = gspell_checker_new (NULL); + } + view->gspell_buffer = gspell_text_buffer_get_from_gtk_text_buffer ( + gtk_text_view_get_buffer (GTK_TEXT_VIEW (view))); + gspell_text_view_set_inline_spell_checking (view->gspell_view, enabled); + } + + gspell_text_buffer_set_spell_checker (view->gspell_buffer, enabled ? view->gspell_checker : NULL); + gspell_text_view_set_enable_language_menu (view->gspell_view, enabled); +} + + + +gboolean +mousepad_view_get_spell_check (MousepadView *view) +{ + g_return_val_if_fail (MOUSEPAD_IS_VIEW (view), FALSE); + + return view->spell_check; +} +#endif diff --git a/mousepad/mousepad-view.h b/mousepad/mousepad-view.h index 14c5fce..50d7a96 100644 --- a/mousepad/mousepad-view.h +++ b/mousepad/mousepad-view.h @@ -124,6 +124,14 @@ void mousepad_view_set_match_braces (MousepadView *view gboolean mousepad_view_get_match_braces (MousepadView *view); +#if HAVE_GSPELL +void mousepad_view_set_spell_check (MousepadView *view, + gboolean enabled, + gboolean external); + +gboolean mousepad_view_get_spell_check (MousepadView *view); +#endif + G_END_DECLS #endif /* !__MOUSEPAD_VIEW_H__ */ diff --git a/mousepad/mousepad-window-ui.xml b/mousepad/mousepad-window-ui.xml index 4eef0b3..38aef77 100644 --- a/mousepad/mousepad-window-ui.xml +++ b/mousepad/mousepad-window-ui.xml @@ -107,6 +107,7 @@ + diff --git a/mousepad/mousepad-window.c b/mousepad/mousepad-window.c index 3de3105..c3b5719 100644 --- a/mousepad/mousepad-window.c +++ b/mousepad/mousepad-window.c @@ -337,6 +337,8 @@ static void mousepad_window_action_statusbar (GtkToggle MousepadWindow *window); static void mousepad_window_action_fullscreen (GtkToggleAction *action, MousepadWindow *window); +static void mousepad_window_action_spell_check (GtkToggleAction *action, + MousepadWindow *window); static void mousepad_window_action_auto_indent (GtkToggleAction *action, MousepadWindow *window); static void mousepad_window_action_line_ending (GtkRadioAction *action, @@ -486,6 +488,7 @@ static const GtkToggleActionEntry toggle_action_entries[] = { "toolbar", NULL, N_("_Toolbar"), NULL, N_("Change the visibility of the toolbar"), G_CALLBACK (mousepad_window_action_toolbar), FALSE, }, { "statusbar", NULL, N_("St_atusbar"), NULL, N_("Change the visibility of the statusbar"), G_CALLBACK (mousepad_window_action_statusbar), FALSE, }, { "fullscreen", GTK_STOCK_FULLSCREEN, N_("_Fullscreen"), "F11", N_("Make the window fullscreen"), G_CALLBACK (mousepad_window_action_fullscreen), FALSE, }, + { "spell-check", NULL, N_("_Spell Check"), NULL, N_("Toggle spell check"), G_CALLBACK (mousepad_window_action_spell_check), FALSE, }, { "auto-indent", NULL, N_("_Auto Indent"), NULL, N_("Auto indent a new line"), G_CALLBACK (mousepad_window_action_auto_indent), FALSE, }, { "insert-spaces", NULL, N_("Insert _Spaces"), NULL, N_("Insert spaces when the tab button is pressed"), G_CALLBACK (mousepad_window_action_insert_spaces), FALSE, }, { "word-wrap", NULL, N_("_Word Wrap"), NULL, N_("Toggle breaking lines in between words"), G_CALLBACK (mousepad_window_action_word_wrap), FALSE, }, @@ -989,7 +992,7 @@ static void mousepad_window_init (MousepadWindow *window) { GtkAccelGroup *accel_group; - GtkWidget *item; + GtkWidget *item, *menu; /* initialize stuff */ window->save_geometry_timer_id = 0; @@ -1081,6 +1084,14 @@ mousepad_window_init (MousepadWindow *window) item, "visible", G_BINDING_DEFAULT | G_BINDING_SYNC_CREATE | G_BINDING_INVERT_BOOLEAN); +#if HAVE_GSPELL + /* prepend a separator as gspell menu delimiter */ + item = gtk_separator_menu_item_new (); + menu = gtk_ui_manager_get_widget (window->ui_manager, "/textview-menu"); + gtk_menu_shell_prepend (GTK_MENU_SHELL (menu), item); + gtk_widget_show (item); +#endif + /* update the window title when 'path-in-title' setting changes */ MOUSEPAD_SETTING_CONNECT_OBJECT (PATH_IN_TITLE, G_CALLBACK (mousepad_window_update_window_title), @@ -1113,6 +1124,12 @@ mousepad_window_init (MousepadWindow *window) G_CALLBACK (mousepad_window_update_document_actions), window, G_CONNECT_SWAPPED); +#if HAVE_GSPELL + MOUSEPAD_SETTING_CONNECT_OBJECT (SPELL_CHECK, + G_CALLBACK (mousepad_window_update_document_actions), + window, + G_CONNECT_SWAPPED); +#endif MOUSEPAD_SETTING_CONNECT_OBJECT (AUTO_INDENT, G_CALLBACK (mousepad_window_update_document_actions), window, @@ -2638,6 +2655,9 @@ mousepad_window_menu_textview_shown (GtkMenu *menu, MousepadWindow *window) { GtkWidget *our_menu; +#if HAVE_GSPELL + GtkWidget *temp_menu, *item; +#endif g_return_if_fail (MOUSEPAD_IS_WINDOW (window)); @@ -2647,8 +2667,38 @@ mousepad_window_menu_textview_shown (GtkMenu *menu, /* empty the original menu */ mousepad_util_container_clear (GTK_CONTAINER (menu)); +#if HAVE_GSPELL + /* retrieve the gspell menu by comparison: send the "populate-popup" signal with gspell + * enabled / disabled and subtract the resulting menus */ + if (mousepad_view_get_spell_check (window->active->textview)) + { + g_signal_emit (G_OBJECT (window->active->textview), + g_signal_lookup ("populate-popup", g_type_from_name ("GtkTextView")), 0, menu); + mousepad_view_set_spell_check (window->active->textview, FALSE, FALSE); + temp_menu = gtk_menu_new (); + g_signal_emit (G_OBJECT (window->active->textview), + g_signal_lookup ("populate-popup", g_type_from_name ("GtkTextView")), 0, temp_menu); + g_signal_connect (G_OBJECT (window->active->textview), "populate-popup", + G_CALLBACK (mousepad_window_menu_textview_popup), window); + mousepad_view_set_spell_check (window->active->textview, TRUE, FALSE); + mousepad_util_menu_subtract (GTK_MENU (menu), GTK_MENU (temp_menu)); + } + + item = gtk_separator_menu_item_new (); + gtk_menu_shell_append (GTK_MENU_SHELL (menu), item); + gtk_widget_show (item); +#endif + /* get the ui manager menu and move its children into the other menu */ our_menu = gtk_ui_manager_get_widget (window->ui_manager, "/textview-menu"); + +#if HAVE_GSPELL + /* remove the old gspell menu from the ui manager menu + * this must be done here (not in mousepad_window_menu_textview_deactivate()), because the new + * gspell menu must be added before to remove the old one, to not break the feature */ + mousepad_util_menu_subtract (GTK_MENU (our_menu), NULL); +#endif + mousepad_util_container_move_children (GTK_CONTAINER (our_menu), GTK_CONTAINER (menu)); } @@ -2682,6 +2732,12 @@ mousepad_window_menu_textview_popup (GtkTextView *textview, g_return_if_fail (MOUSEPAD_IS_WINDOW (window)); g_return_if_fail (MOUSEPAD_IS_DOCUMENT (window->active)); +#if HAVE_GSPELL + /* disconnect this signal while retrieving the gspell menu (see mousepad_window_menu_textview_shown) */ + if (mousepad_view_get_spell_check (MOUSEPAD_VIEW (textview))) + mousepad_disconnect_by_func (G_OBJECT (textview), mousepad_window_menu_textview_popup, window); +#endif + /* connect signal */ g_signal_connect (G_OBJECT (menu), "show", G_CALLBACK (mousepad_window_menu_textview_shown), window); g_signal_connect (G_OBJECT (menu), "deactivate", G_CALLBACK (mousepad_window_menu_textview_deactivate), window); @@ -2752,6 +2808,12 @@ mousepad_window_update_document_actions (MousepadWindow *window) action = gtk_action_group_get_action (window->action_group, "word-wrap"); gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action), active); +#if HAVE_GSPELL + active = MOUSEPAD_SETTING_GET_BOOLEAN (SPELL_CHECK); + action = gtk_action_group_get_action (window->action_group, "spell-check"); + gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action), active); +#endif + active = MOUSEPAD_SETTING_GET_BOOLEAN (AUTO_INDENT); action = gtk_action_group_get_action (window->action_group, "auto-indent"); gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action), active); @@ -5208,6 +5270,26 @@ mousepad_window_action_fullscreen (GtkToggleAction *action, +static void +mousepad_window_action_spell_check (GtkToggleAction *action, + MousepadWindow *window) +{ +#if HAVE_GSPELL + gboolean active; + + g_return_if_fail (MOUSEPAD_IS_WINDOW (window)); + g_return_if_fail (MOUSEPAD_IS_DOCUMENT (window->active)); + + /* get the current state */ + active = gtk_toggle_action_get_active (action); + + /* save as the last spell check mode */ + MOUSEPAD_SETTING_SET_BOOLEAN (SPELL_CHECK, active); +#endif +} + + + static void mousepad_window_action_auto_indent (GtkToggleAction *action, MousepadWindow *window) diff --git a/mousepad/org.xfce.mousepad.gschema.xml b/mousepad/org.xfce.mousepad.gschema.xml index 105a14a..4d929f1 100644 --- a/mousepad/org.xfce.mousepad.gschema.xml +++ b/mousepad/org.xfce.mousepad.gschema.xml @@ -48,6 +48,13 @@ + + false + Spell Check + + When true spell checking is enabled, when false it is not. + + false Auto-indentation -- 2.26.2