1 /*
2 * gedit-spell-plugin.c
3 *
4 * Copyright (C) 2002-2005 Paolo Maggi
5 * Copyright (C) 2015-2016 Sébastien Wilmet
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2, or (at your option)
10 * any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, see <http://www.gnu.org/licenses/>.
19 */
20
21 #include "gedit-spell-plugin.h"
22
23 #include <glib/gi18n.h>
24 #include <gedit/gedit-debug.h>
25 #include <gedit/gedit-app.h>
26 #include <gedit/gedit-window.h>
27 #include <gedit/gedit-window-activatable.h>
28 #include <gspell/gspell.h>
29 #include <libpeas-gtk/peas-gtk-configurable.h>
30
31 #include "gedit-spell-app-activatable.h"
32
33 #define GEDIT_METADATA_ATTRIBUTE_SPELL_LANGUAGE "gedit-spell-language"
34 #define GEDIT_METADATA_ATTRIBUTE_SPELL_ENABLED "gedit-spell-enabled"
35
36 #define SPELL_ENABLED_STR "1"
37 #define SPELL_BASE_SETTINGS "org.gnome.gedit.plugins.spell"
38 #define SETTINGS_KEY_HIGHLIGHT_MISSPELLED "highlight-misspelled"
39
40 static void gedit_window_activatable_iface_init (GeditWindowActivatableInterface *iface);
41 static void peas_gtk_configurable_iface_init (PeasGtkConfigurableInterface *iface);
42
43 struct _GeditSpellPluginPrivate
44 {
45 GeditWindow *window;
46 GSettings *settings;
47 };
48
49 enum
50 {
51 PROP_0,
52 PROP_WINDOW
53 };
54
55 typedef struct _SpellConfigureWidget SpellConfigureWidget;
56
57 struct _SpellConfigureWidget
58 {
59 GtkWidget *content;
60 GtkWidget *highlight_button;
61
62 GSettings *settings;
63 };
64
65 G_DEFINE_DYNAMIC_TYPE_EXTENDED (GeditSpellPlugin,
66 gedit_spell_plugin,
67 PEAS_TYPE_EXTENSION_BASE,
68 0,
69 G_IMPLEMENT_INTERFACE_DYNAMIC (GEDIT_TYPE_WINDOW_ACTIVATABLE,
70 gedit_window_activatable_iface_init)
71 G_IMPLEMENT_INTERFACE_DYNAMIC (PEAS_GTK_TYPE_CONFIGURABLE,
72 peas_gtk_configurable_iface_init)
73 G_ADD_PRIVATE_DYNAMIC (GeditSpellPlugin))
74
75 static void
gedit_spell_plugin_set_property(GObject * object,guint prop_id,const GValue * value,GParamSpec * pspec)76 gedit_spell_plugin_set_property (GObject *object,
77 guint prop_id,
78 const GValue *value,
79 GParamSpec *pspec)
80 {
81 GeditSpellPlugin *plugin = GEDIT_SPELL_PLUGIN (object);
82
83 switch (prop_id)
84 {
85 case PROP_WINDOW:
86 plugin->priv->window = GEDIT_WINDOW (g_value_dup_object (value));
87 break;
88
89 default:
90 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
91 break;
92 }
93 }
94
95 static void
gedit_spell_plugin_get_property(GObject * object,guint prop_id,GValue * value,GParamSpec * pspec)96 gedit_spell_plugin_get_property (GObject *object,
97 guint prop_id,
98 GValue *value,
99 GParamSpec *pspec)
100 {
101 GeditSpellPlugin *plugin = GEDIT_SPELL_PLUGIN (object);
102
103 switch (prop_id)
104 {
105 case PROP_WINDOW:
106 g_value_set_object (value, plugin->priv->window);
107 break;
108
109 default:
110 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
111 break;
112 }
113 }
114
115 static void
gedit_spell_plugin_dispose(GObject * object)116 gedit_spell_plugin_dispose (GObject *object)
117 {
118 GeditSpellPlugin *plugin = GEDIT_SPELL_PLUGIN (object);
119
120 gedit_debug_message (DEBUG_PLUGINS, "GeditSpellPlugin disposing");
121
122 g_clear_object (&plugin->priv->window);
123 g_clear_object (&plugin->priv->settings);
124
125 G_OBJECT_CLASS (gedit_spell_plugin_parent_class)->dispose (object);
126 }
127
128 static void
gedit_spell_plugin_class_init(GeditSpellPluginClass * klass)129 gedit_spell_plugin_class_init (GeditSpellPluginClass *klass)
130 {
131 GObjectClass *object_class = G_OBJECT_CLASS (klass);
132
133 object_class->set_property = gedit_spell_plugin_set_property;
134 object_class->get_property = gedit_spell_plugin_get_property;
135 object_class->dispose = gedit_spell_plugin_dispose;
136
137 g_object_class_override_property (object_class, PROP_WINDOW, "window");
138 }
139
140 static void
gedit_spell_plugin_class_finalize(GeditSpellPluginClass * klass)141 gedit_spell_plugin_class_finalize (GeditSpellPluginClass *klass)
142 {
143 }
144
145 static void
gedit_spell_plugin_init(GeditSpellPlugin * plugin)146 gedit_spell_plugin_init (GeditSpellPlugin *plugin)
147 {
148 gedit_debug_message (DEBUG_PLUGINS, "GeditSpellPlugin initializing");
149
150 plugin->priv = gedit_spell_plugin_get_instance_private (plugin);
151 plugin->priv->settings = g_settings_new (SPELL_BASE_SETTINGS);
152 }
153
154 static GspellChecker *
get_spell_checker(GeditDocument * doc)155 get_spell_checker (GeditDocument *doc)
156 {
157 GspellTextBuffer *gspell_buffer;
158
159 gspell_buffer = gspell_text_buffer_get_from_gtk_text_buffer (GTK_TEXT_BUFFER (doc));
160 return gspell_text_buffer_get_spell_checker (gspell_buffer);
161 }
162
163 static const GspellLanguage *
get_language_from_metadata(GeditDocument * doc)164 get_language_from_metadata (GeditDocument *doc)
165 {
166 const GspellLanguage *lang = NULL;
167 gchar *language_code = NULL;
168
169 language_code = gedit_document_get_metadata (doc, GEDIT_METADATA_ATTRIBUTE_SPELL_LANGUAGE);
170
171 if (language_code != NULL)
172 {
173 lang = gspell_language_lookup (language_code);
174 g_free (language_code);
175 }
176
177 return lang;
178 }
179
180 static void
check_spell_cb(GSimpleAction * action,GVariant * parameter,gpointer data)181 check_spell_cb (GSimpleAction *action,
182 GVariant *parameter,
183 gpointer data)
184 {
185 GeditSpellPlugin *plugin = GEDIT_SPELL_PLUGIN (data);
186 GeditSpellPluginPrivate *priv;
187 GeditView *view;
188 GspellNavigator *navigator;
189 GtkWidget *dialog;
190
191 gedit_debug (DEBUG_PLUGINS);
192
193 priv = plugin->priv;
194
195 view = gedit_window_get_active_view (priv->window);
196 g_return_if_fail (view != NULL);
197
198 navigator = gspell_navigator_text_view_new (GTK_TEXT_VIEW (view));
199 dialog = gspell_checker_dialog_new (GTK_WINDOW (priv->window), navigator);
200
201 gtk_widget_show (dialog);
202 }
203
204 static void
language_dialog_response_cb(GtkDialog * dialog,gint response_id,gpointer user_data)205 language_dialog_response_cb (GtkDialog *dialog,
206 gint response_id,
207 gpointer user_data)
208 {
209 if (response_id == GTK_RESPONSE_HELP)
210 {
211 gedit_app_show_help (GEDIT_APP (g_application_get_default ()),
212 GTK_WINDOW (dialog),
213 NULL,
214 "gedit-spellcheck");
215 return;
216 }
217
218 gtk_widget_destroy (GTK_WIDGET (dialog));
219 }
220
221 static void
set_language_cb(GSimpleAction * action,GVariant * parameter,gpointer data)222 set_language_cb (GSimpleAction *action,
223 GVariant *parameter,
224 gpointer data)
225 {
226 GeditSpellPlugin *plugin = GEDIT_SPELL_PLUGIN (data);
227 GeditSpellPluginPrivate *priv;
228 GeditDocument *doc;
229 GspellChecker *checker;
230 const GspellLanguage *lang;
231 GtkWidget *dialog;
232 GtkWindowGroup *window_group;
233
234 gedit_debug (DEBUG_PLUGINS);
235
236 priv = plugin->priv;
237
238 doc = gedit_window_get_active_document (priv->window);
239 g_return_if_fail (doc != NULL);
240
241 checker = get_spell_checker (doc);
242 g_return_if_fail (checker != NULL);
243
244 lang = gspell_checker_get_language (checker);
245
246 dialog = gspell_language_chooser_dialog_new (GTK_WINDOW (priv->window),
247 lang,
248 GTK_DIALOG_MODAL |
249 GTK_DIALOG_DESTROY_WITH_PARENT);
250
251 g_object_bind_property (dialog, "language",
252 checker, "language",
253 G_BINDING_DEFAULT);
254
255 window_group = gedit_window_get_group (priv->window);
256
257 gtk_window_group_add_window (window_group, GTK_WINDOW (dialog));
258
259 gtk_dialog_add_button (GTK_DIALOG (dialog),
260 _("_Help"),
261 GTK_RESPONSE_HELP);
262
263 g_signal_connect (dialog,
264 "response",
265 G_CALLBACK (language_dialog_response_cb),
266 NULL);
267
268 gtk_widget_show (dialog);
269 }
270
271 static void
inline_checker_activate_cb(GSimpleAction * action,GVariant * parameter,gpointer data)272 inline_checker_activate_cb (GSimpleAction *action,
273 GVariant *parameter,
274 gpointer data)
275 {
276 GeditSpellPlugin *plugin = GEDIT_SPELL_PLUGIN (data);
277 GeditSpellPluginPrivate *priv = plugin->priv;
278 GVariant *state;
279 gboolean active;
280 GeditView *view;
281
282 gedit_debug (DEBUG_PLUGINS);
283
284 state = g_action_get_state (G_ACTION (action));
285 g_return_if_fail (state != NULL);
286
287 active = g_variant_get_boolean (state);
288 g_variant_unref (state);
289
290 /* We must toggle ourself the value. */
291 active = !active;
292 g_action_change_state (G_ACTION (action), g_variant_new_boolean (active));
293
294 view = gedit_window_get_active_view (priv->window);
295 if (view != NULL)
296 {
297 GeditDocument *doc;
298
299 doc = GEDIT_DOCUMENT (gtk_text_view_get_buffer (GTK_TEXT_VIEW (view)));
300
301 /* Set metadata in the "activate" handler, not in "change-state"
302 * because "change-state" is called every time the state
303 * changes, not specifically when the user has changed the state
304 * herself. For example "change-state" is called to initialize
305 * the sate to the default value specified in the GActionEntry.
306 */
307 gedit_document_set_metadata (doc,
308 GEDIT_METADATA_ATTRIBUTE_SPELL_ENABLED,
309 active ? SPELL_ENABLED_STR : NULL,
310 NULL);
311 }
312 }
313
314 static void
inline_checker_change_state_cb(GSimpleAction * action,GVariant * state,gpointer data)315 inline_checker_change_state_cb (GSimpleAction *action,
316 GVariant *state,
317 gpointer data)
318 {
319 GeditSpellPlugin *plugin = GEDIT_SPELL_PLUGIN (data);
320 GeditSpellPluginPrivate *priv = plugin->priv;
321 GeditView *view;
322 gboolean active;
323
324 gedit_debug (DEBUG_PLUGINS);
325
326 active = g_variant_get_boolean (state);
327
328 gedit_debug_message (DEBUG_PLUGINS, active ? "Inline Checker activated" : "Inline Checker deactivated");
329
330 view = gedit_window_get_active_view (priv->window);
331 if (view != NULL)
332 {
333 GspellTextView *gspell_view;
334
335 gspell_view = gspell_text_view_get_from_gtk_text_view (GTK_TEXT_VIEW (view));
336 gspell_text_view_set_inline_spell_checking (gspell_view, active);
337
338 g_simple_action_set_state (action, g_variant_new_boolean (active));
339 }
340 }
341
342 static void
update_ui(GeditSpellPlugin * plugin)343 update_ui (GeditSpellPlugin *plugin)
344 {
345 GeditSpellPluginPrivate *priv;
346 GeditTab *tab;
347 GeditView *view = NULL;
348 gboolean editable_view;
349 GAction *check_spell_action;
350 GAction *config_spell_action;
351 GAction *inline_checker_action;
352
353 gedit_debug (DEBUG_PLUGINS);
354
355 priv = plugin->priv;
356
357 tab = gedit_window_get_active_tab (priv->window);
358 if (tab != NULL)
359 {
360 view = gedit_tab_get_view (tab);
361 }
362
363 editable_view = (view != NULL) && gtk_text_view_get_editable (GTK_TEXT_VIEW (view));
364
365 check_spell_action = g_action_map_lookup_action (G_ACTION_MAP (priv->window),
366 "check-spell");
367 g_simple_action_set_enabled (G_SIMPLE_ACTION (check_spell_action),
368 editable_view);
369
370 config_spell_action = g_action_map_lookup_action (G_ACTION_MAP (priv->window),
371 "config-spell");
372 g_simple_action_set_enabled (G_SIMPLE_ACTION (config_spell_action),
373 editable_view);
374
375 inline_checker_action = g_action_map_lookup_action (G_ACTION_MAP (priv->window),
376 "inline-spell-checker");
377 g_simple_action_set_enabled (G_SIMPLE_ACTION (inline_checker_action),
378 editable_view);
379
380 /* Update only on normal state to avoid garbage changes during e.g. file
381 * loading.
382 */
383 if (tab != NULL &&
384 gedit_tab_get_state (tab) == GEDIT_TAB_STATE_NORMAL)
385 {
386 GspellTextView *gspell_view;
387 gboolean inline_checking_enabled;
388
389 gspell_view = gspell_text_view_get_from_gtk_text_view (GTK_TEXT_VIEW (view));
390 inline_checking_enabled = gspell_text_view_get_inline_spell_checking (gspell_view);
391
392 g_action_change_state (inline_checker_action,
393 g_variant_new_boolean (inline_checking_enabled));
394 }
395 }
396
397 static void
setup_inline_checker_from_metadata(GeditSpellPlugin * plugin,GeditView * view)398 setup_inline_checker_from_metadata (GeditSpellPlugin *plugin,
399 GeditView *view)
400 {
401 GeditDocument *doc;
402 gboolean enabled;
403 gchar *enabled_str;
404 GspellTextView *gspell_view;
405 GeditView *active_view;
406
407 doc = GEDIT_DOCUMENT (gtk_text_view_get_buffer (GTK_TEXT_VIEW (view)));
408
409 enabled = g_settings_get_boolean(plugin->priv->settings, SETTINGS_KEY_HIGHLIGHT_MISSPELLED);
410 enabled_str = gedit_document_get_metadata (doc, GEDIT_METADATA_ATTRIBUTE_SPELL_ENABLED);
411 if (enabled_str != NULL)
412 {
413 enabled = g_str_equal (enabled_str, SPELL_ENABLED_STR);
414 g_free (enabled_str);
415 }
416
417 gspell_view = gspell_text_view_get_from_gtk_text_view (GTK_TEXT_VIEW (view));
418 gspell_text_view_set_inline_spell_checking (gspell_view, enabled);
419
420 /* In case that the view is the active one we mark the spell action */
421 active_view = gedit_window_get_active_view (plugin->priv->window);
422
423 if (active_view == view)
424 {
425 GAction *action;
426
427 action = g_action_map_lookup_action (G_ACTION_MAP (plugin->priv->window),
428 "inline-spell-checker");
429 g_action_change_state (action, g_variant_new_boolean (enabled));
430 }
431 }
432
433 static void
language_notify_cb(GspellChecker * checker,GParamSpec * pspec,GeditDocument * doc)434 language_notify_cb (GspellChecker *checker,
435 GParamSpec *pspec,
436 GeditDocument *doc)
437 {
438 const GspellLanguage *lang;
439 const gchar *language_code;
440
441 g_return_if_fail (GEDIT_IS_DOCUMENT (doc));
442
443 lang = gspell_checker_get_language (checker);
444 g_return_if_fail (lang != NULL);
445
446 language_code = gspell_language_get_code (lang);
447 g_return_if_fail (language_code != NULL);
448
449 gedit_document_set_metadata (doc,
450 GEDIT_METADATA_ATTRIBUTE_SPELL_LANGUAGE, language_code,
451 NULL);
452 }
453
454 static void
on_document_loaded(GeditDocument * doc,GeditSpellPlugin * plugin)455 on_document_loaded (GeditDocument *doc,
456 GeditSpellPlugin *plugin)
457 {
458 GspellChecker *checker;
459 GeditTab *tab;
460 GeditView *view;
461
462 checker = get_spell_checker (doc);
463
464 if (checker != NULL)
465 {
466 const GspellLanguage *lang;
467
468 lang = get_language_from_metadata (doc);
469
470 if (lang != NULL)
471 {
472 g_signal_handlers_block_by_func (checker, language_notify_cb, doc);
473 gspell_checker_set_language (checker, lang);
474 g_signal_handlers_unblock_by_func (checker, language_notify_cb, doc);
475 }
476 }
477
478 tab = gedit_tab_get_from_document (doc);
479 view = gedit_tab_get_view (tab);
480 setup_inline_checker_from_metadata (plugin, view);
481 }
482
483 static void
on_document_saved(GeditDocument * doc,gpointer user_data)484 on_document_saved (GeditDocument *doc,
485 gpointer user_data)
486 {
487 GeditTab *tab;
488 GeditView *view;
489 GspellChecker *checker;
490 const gchar *language_code = NULL;
491 GspellTextView *gspell_view;
492 gboolean inline_checking_enabled;
493
494 /* Make sure to save the metadata here too */
495
496 checker = get_spell_checker (doc);
497
498 if (checker != NULL)
499 {
500 const GspellLanguage *lang;
501
502 lang = gspell_checker_get_language (checker);
503 if (lang != NULL)
504 {
505 language_code = gspell_language_get_code (lang);
506 }
507 }
508
509 tab = gedit_tab_get_from_document (doc);
510 view = gedit_tab_get_view (tab);
511
512 gspell_view = gspell_text_view_get_from_gtk_text_view (GTK_TEXT_VIEW (view));
513 inline_checking_enabled = gspell_text_view_get_inline_spell_checking (gspell_view);
514
515 gedit_document_set_metadata (doc,
516 GEDIT_METADATA_ATTRIBUTE_SPELL_ENABLED,
517 inline_checking_enabled ? SPELL_ENABLED_STR : NULL,
518 GEDIT_METADATA_ATTRIBUTE_SPELL_LANGUAGE,
519 language_code,
520 NULL);
521 }
522
523 static void
activate_spell_checking_in_view(GeditSpellPlugin * plugin,GeditView * view)524 activate_spell_checking_in_view (GeditSpellPlugin *plugin,
525 GeditView *view)
526 {
527 GeditDocument *doc;
528
529 doc = GEDIT_DOCUMENT (gtk_text_view_get_buffer (GTK_TEXT_VIEW (view)));
530
531 /* It is possible that a GspellChecker has already been set, for example
532 * if a GeditTab has moved to another window.
533 */
534 if (get_spell_checker (doc) == NULL)
535 {
536 const GspellLanguage *lang;
537 GspellChecker *checker;
538 GspellTextBuffer *gspell_buffer;
539
540 lang = get_language_from_metadata (doc);
541 checker = gspell_checker_new (lang);
542
543 g_signal_connect_object (checker,
544 "notify::language",
545 G_CALLBACK (language_notify_cb),
546 doc,
547 0);
548
549 gspell_buffer = gspell_text_buffer_get_from_gtk_text_buffer (GTK_TEXT_BUFFER (doc));
550 gspell_text_buffer_set_spell_checker (gspell_buffer, checker);
551 g_object_unref (checker);
552
553 setup_inline_checker_from_metadata (plugin, view);
554 }
555
556 g_signal_connect_object (doc,
557 "loaded",
558 G_CALLBACK (on_document_loaded),
559 plugin,
560 0);
561
562 g_signal_connect_object (doc,
563 "saved",
564 G_CALLBACK (on_document_saved),
565 plugin,
566 0);
567 }
568
569 static void
disconnect_view(GeditSpellPlugin * plugin,GeditView * view)570 disconnect_view (GeditSpellPlugin *plugin,
571 GeditView *view)
572 {
573 GtkTextBuffer *buffer;
574
575 buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (view));
576
577 /* It should still be the same buffer as the one where the signal
578 * handlers were connected. If not, we assume that the old buffer is
579 * finalized. And it is anyway safe to call
580 * g_signal_handlers_disconnect_by_func() if no signal handlers are
581 * found.
582 */
583 g_signal_handlers_disconnect_by_func (buffer, on_document_loaded, plugin);
584 g_signal_handlers_disconnect_by_func (buffer, on_document_saved, plugin);
585 }
586
587 static void
deactivate_spell_checking_in_view(GeditSpellPlugin * plugin,GeditView * view)588 deactivate_spell_checking_in_view (GeditSpellPlugin *plugin,
589 GeditView *view)
590 {
591 GtkTextBuffer *gtk_buffer;
592 GspellTextBuffer *gspell_buffer;
593 GspellTextView *gspell_view;
594
595 disconnect_view (plugin, view);
596
597 gtk_buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (view));
598 gspell_buffer = gspell_text_buffer_get_from_gtk_text_buffer (gtk_buffer);
599 gspell_text_buffer_set_spell_checker (gspell_buffer, NULL);
600
601 gspell_view = gspell_text_view_get_from_gtk_text_view (GTK_TEXT_VIEW (view));
602 gspell_text_view_set_inline_spell_checking (gspell_view, FALSE);
603 }
604
605 static void
tab_added_cb(GeditWindow * window,GeditTab * tab,GeditSpellPlugin * plugin)606 tab_added_cb (GeditWindow *window,
607 GeditTab *tab,
608 GeditSpellPlugin *plugin)
609 {
610 activate_spell_checking_in_view (plugin, gedit_tab_get_view (tab));
611 }
612
613 static void
tab_removed_cb(GeditWindow * window,GeditTab * tab,GeditSpellPlugin * plugin)614 tab_removed_cb (GeditWindow *window,
615 GeditTab *tab,
616 GeditSpellPlugin *plugin)
617 {
618 /* Don't deactivate completely the spell checking in @tab, since the tab
619 * can be moved to another window and we don't want to loose the spell
620 * checking settings (they are not saved in metadata for unsaved
621 * documents).
622 */
623 disconnect_view (plugin, gedit_tab_get_view (tab));
624 }
625
626 static void
gedit_spell_plugin_activate(GeditWindowActivatable * activatable)627 gedit_spell_plugin_activate (GeditWindowActivatable *activatable)
628 {
629 GeditSpellPlugin *plugin;
630 GeditSpellPluginPrivate *priv;
631 GList *views;
632 GList *l;
633
634 const GActionEntry action_entries[] =
635 {
636 { "check-spell", check_spell_cb },
637 { "config-spell", set_language_cb },
638 { "inline-spell-checker",
639 inline_checker_activate_cb,
640 NULL,
641 "false",
642 inline_checker_change_state_cb }
643 };
644
645 gedit_debug (DEBUG_PLUGINS);
646
647 plugin = GEDIT_SPELL_PLUGIN (activatable);
648 priv = plugin->priv;
649
650 g_action_map_add_action_entries (G_ACTION_MAP (priv->window),
651 action_entries,
652 G_N_ELEMENTS (action_entries),
653 activatable);
654
655 update_ui (plugin);
656
657 views = gedit_window_get_views (priv->window);
658 for (l = views; l != NULL; l = l->next)
659 {
660 activate_spell_checking_in_view (plugin, GEDIT_VIEW (l->data));
661 }
662
663 g_signal_connect (priv->window,
664 "tab-added",
665 G_CALLBACK (tab_added_cb),
666 activatable);
667
668 g_signal_connect (priv->window,
669 "tab-removed",
670 G_CALLBACK (tab_removed_cb),
671 activatable);
672 }
673
674 static void
gedit_spell_plugin_deactivate(GeditWindowActivatable * activatable)675 gedit_spell_plugin_deactivate (GeditWindowActivatable *activatable)
676 {
677 GeditSpellPlugin *plugin;
678 GeditSpellPluginPrivate *priv;
679 GList *views;
680 GList *l;
681
682 gedit_debug (DEBUG_PLUGINS);
683
684 plugin = GEDIT_SPELL_PLUGIN (activatable);
685 priv = plugin->priv;
686
687 g_action_map_remove_action (G_ACTION_MAP (priv->window), "check-spell");
688 g_action_map_remove_action (G_ACTION_MAP (priv->window), "config-spell");
689 g_action_map_remove_action (G_ACTION_MAP (priv->window), "inline-spell-checker");
690
691 g_signal_handlers_disconnect_by_func (priv->window, tab_added_cb, activatable);
692 g_signal_handlers_disconnect_by_func (priv->window, tab_removed_cb, activatable);
693
694 views = gedit_window_get_views (priv->window);
695 for (l = views; l != NULL; l = l->next)
696 {
697 deactivate_spell_checking_in_view (plugin, GEDIT_VIEW (l->data));
698 }
699 }
700
701 static void
gedit_spell_plugin_update_state(GeditWindowActivatable * activatable)702 gedit_spell_plugin_update_state (GeditWindowActivatable *activatable)
703 {
704 gedit_debug (DEBUG_PLUGINS);
705
706 update_ui (GEDIT_SPELL_PLUGIN (activatable));
707 }
708
709 static void
gedit_window_activatable_iface_init(GeditWindowActivatableInterface * iface)710 gedit_window_activatable_iface_init (GeditWindowActivatableInterface *iface)
711 {
712 iface->activate = gedit_spell_plugin_activate;
713 iface->deactivate = gedit_spell_plugin_deactivate;
714 iface->update_state = gedit_spell_plugin_update_state;
715 }
716
717 G_MODULE_EXPORT void
peas_register_types(PeasObjectModule * module)718 peas_register_types (PeasObjectModule *module)
719 {
720 gedit_spell_plugin_register_type (G_TYPE_MODULE (module));
721 gedit_spell_app_activatable_register (G_TYPE_MODULE (module));
722
723 peas_object_module_register_extension_type (module,
724 GEDIT_TYPE_WINDOW_ACTIVATABLE,
725 GEDIT_TYPE_SPELL_PLUGIN);
726 peas_object_module_register_extension_type (module,
727 PEAS_GTK_TYPE_CONFIGURABLE,
728 GEDIT_TYPE_SPELL_PLUGIN);
729 }
730
731 static void
highlight_button_toggled(GtkToggleButton * button,SpellConfigureWidget * widget)732 highlight_button_toggled (GtkToggleButton *button,
733 SpellConfigureWidget *widget)
734 {
735 gboolean status = gtk_toggle_button_get_active (button);
736 g_settings_set_boolean(widget->settings, SETTINGS_KEY_HIGHLIGHT_MISSPELLED, status);
737 }
738
739 static void
configure_widget_destroyed(GtkWidget * widget,gpointer data)740 configure_widget_destroyed (GtkWidget *widget,
741 gpointer data)
742 {
743 SpellConfigureWidget *conf_widget = (SpellConfigureWidget *)data;
744
745 gedit_debug (DEBUG_PLUGINS);
746
747 g_object_unref (conf_widget->settings);
748 g_slice_free (SpellConfigureWidget, data);
749
750 gedit_debug_message (DEBUG_PLUGINS, "END");
751 }
752
753 static SpellConfigureWidget *
get_configure_widget(GeditSpellPlugin * plugin)754 get_configure_widget (GeditSpellPlugin *plugin)
755 {
756 SpellConfigureWidget *widget;
757 GtkBuilder *builder;
758 gchar *root_objects[] = {
759 "spell_dialog_content",
760 NULL
761 };
762
763 gedit_debug (DEBUG_PLUGINS);
764
765 widget = g_slice_new (SpellConfigureWidget);
766 widget->settings = g_object_ref (plugin->priv->settings);
767
768 builder = gtk_builder_new ();
769 gtk_builder_add_objects_from_resource (builder, "/org/gnome/gedit/plugins/spell/ui/gedit-spell-setup-dialog.ui",
770 root_objects, NULL);
771 widget->content = GTK_WIDGET (gtk_builder_get_object (builder, "spell_dialog_content"));
772 g_object_ref (widget->content);
773
774 widget->highlight_button = GTK_WIDGET (gtk_builder_get_object (builder, "highlight_button"));
775 g_object_unref (builder);
776
777 gboolean status = g_settings_get_boolean(widget->settings, SETTINGS_KEY_HIGHLIGHT_MISSPELLED);
778 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (widget->highlight_button), status);
779
780 g_signal_connect (widget->highlight_button,
781 "toggled",
782 G_CALLBACK (highlight_button_toggled),
783 widget);
784
785 g_signal_connect (widget->content,
786 "destroy",
787 G_CALLBACK (configure_widget_destroyed),
788 widget);
789
790 return widget;
791 }
792
793
794 static GtkWidget *
gedit_spell_plugin_create_configure_widget(PeasGtkConfigurable * configurable)795 gedit_spell_plugin_create_configure_widget (PeasGtkConfigurable *configurable)
796 {
797 SpellConfigureWidget *widget;
798
799 widget = get_configure_widget (GEDIT_SPELL_PLUGIN (configurable));
800
801 return widget->content;
802 }
803
804 static void
peas_gtk_configurable_iface_init(PeasGtkConfigurableInterface * iface)805 peas_gtk_configurable_iface_init (PeasGtkConfigurableInterface *iface)
806 {
807 iface->create_configure_widget = gedit_spell_plugin_create_configure_widget;
808 }
809
810 /* ex:set ts=8 noet: */
811