1 /* gtkpspell - a spell-checking addon for GtkText
2 * Copyright (c) 2000 Evan Martin.
3 * Copyright (c) 2002 Melvin Hadasht.
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2 of the License, or (at your option) any later version.
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this library; If not, write to the Free Software
17 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 * Stuphead: (C) 2000,2001 Grigroy Bakunov, Sergey Pinaev
21 * Adapted for Sylpheed (Claws) (c) 2001-2002 by Hiroyuki Yamamoto &
22 * The Sylpheed Claws Team.
23 * Adapted for pspell (c) 2001-2002 Melvin Hadasht
35 #include <sys/types.h>
48 #include <gtk/gtkoptionmenu.h>
49 #include <gtk/gtkmenu.h>
50 #include <gtk/gtkmenuitem.h>
51 #include <gdk/gdkkeysyms.h>
53 #include <pspell/pspell.h>
57 #include "prefs_common.h"
61 /* size of the text buffer used in various word-processing routines. */
64 /* number of suggestions to display on each menu. */
67 /* 'config' must be defined as a 'PspellConfig *' */
68 #define RETURN_FALSE_IF_CONFIG_ERROR() \
70 if (pspell_config_error_number(config) != 0) { \
71 gtkpspellcheckers->error_message = \
72 g_strdup(pspell_config_error_message(config)); \
77 #define CONFIG_REPLACE_RETURN_FALSE_IF_FAIL(option, value) \
79 pspell_config_replace(config, option, value); \
80 RETURN_FALSE_IF_CONFIG_ERROR(); \
83 GtkPspellCheckers *gtkpspellcheckers;
85 /* Error message storage */
86 static void gtkpspell_checkers_error_message (gchar *message);
89 static void entry_insert_cb (GtkSText *gtktext,
93 GtkPspell *gtkpspell);
94 static void entry_delete_cb (GtkSText *gtktext,
97 GtkPspell *gtkpspell);
98 static gint button_press_intercept_cb (GtkSText *gtktext,
100 GtkPspell *gtkpspell);
102 /* Checker creation */
103 static GtkPspeller* gtkpspeller_new (Dictionary *dict);
104 static GtkPspeller* gtkpspeller_real_new (Dictionary *dict);
105 static GtkPspeller* gtkpspeller_delete (GtkPspeller *gtkpspeller);
106 static GtkPspeller* gtkpspeller_real_delete (GtkPspeller *gtkpspeller);
108 /* Checker configuration */
109 static gint set_dictionary (PspellConfig *config,
111 static void set_sug_mode_cb (GtkMenuItem *w,
112 GtkPspell *gtkpspell);
113 static void set_real_sug_mode (GtkPspell *gtkpspell,
114 const char *themode);
116 /* Checker actions */
117 static gboolean check_at (GtkPspell *gtkpspell,
119 static gboolean check_next_prev (GtkPspell *gtkpspell,
121 static GList* misspelled_suggest (GtkPspell *gtkpspell,
123 static void add_word_to_session_cb (GtkWidget *w,
125 static void add_word_to_personal_cb (GtkWidget *w,
127 static void replace_with_create_dialog_cb (GtkWidget *w,
129 static void replace_with_supplied_word_cb (GtkWidget *w,
130 GtkPspell *gtkpspell);
131 static void replace_word_cb (GtkWidget *w,
133 static void replace_real_word (GtkPspell *gtkpspell,
135 static void check_with_alternate_cb (GtkWidget *w,
137 static void use_alternate_dict (GtkPspell *gtkpspell);
138 static void toggle_check_while_typing_cb (GtkWidget *w,
142 static void popup_menu (GtkPspell *gtkpspell,
144 static GtkMenu* make_sug_menu (GtkPspell *gtkpspell);
145 static void populate_submenu (GtkPspell *gtkpspell,
147 static GtkMenu* make_config_menu (GtkPspell *gtkpspell);
148 static void set_menu_pos (GtkMenu *menu,
152 /* Other menu callbacks */
153 static gboolean cancel_menu_cb (GtkMenuShell *w,
155 static void change_dict_cb (GtkWidget *w,
156 GtkPspell *gtkpspell);
157 static void switch_to_alternate_cb (GtkWidget *w,
160 /* Misc. helper functions */
161 static void set_point_continue (GtkPspell *gtkpspell);
162 static void continue_check (gpointer *gtkpspell);
163 static gboolean iswordsep (unsigned char c);
164 static guchar get_text_index_whar (GtkPspell *gtkpspell,
166 static gboolean get_word_from_pos (GtkPspell *gtkpspell,
172 static void allocate_color (GtkPspell *gtkpspell,
174 static void change_color (GtkPspell *gtkpspell,
179 static guchar* convert_to_pspell_encoding (const guchar *encoding);
180 static gint compare_dict (Dictionary *a,
182 static void dictionary_delete (Dictionary *dict);
183 static Dictionary *dictionary_dup (const Dictionary *dict);
184 static void free_suggestions_list (GtkPspell *gtkpspell);
185 static void reset_theword_data (GtkPspell *gtkpspell);
186 static void free_checkers (gpointer elt,
188 static gint find_gtkpspeller (gconstpointer aa,
190 static void gtkpspell_alert_dialog (gchar *message);
192 GtkPspellCheckers *gtkpspell_checkers_new()
194 GtkPspellCheckers *gtkpspellcheckers;
196 gtkpspellcheckers = g_new(GtkPspellCheckers, 1);
197 gtkpspellcheckers->checkers = NULL;
198 gtkpspellcheckers->dictionary_list = NULL;
199 gtkpspellcheckers->error_message = NULL;
201 return gtkpspellcheckers;
204 GtkPspellCheckers *gtkpspell_checkers_delete()
209 if (gtkpspellcheckers == NULL)
212 if ((checkers = gtkpspellcheckers->checkers) != NULL) {
213 debug_print(_("Pspell: number of running checkers to delete %d\n"),
214 g_slist_length(checkers));
216 g_slist_foreach(checkers, free_checkers, NULL);
217 g_slist_free(checkers);
220 if ((dict_list = gtkpspellcheckers->dictionary_list) != NULL) {
221 debug_print(_("Pspell: number of dictionaries to delete %d\n"),
222 g_slist_length(dict_list));
224 gtkpspell_free_dictionary_list(dict_list);
225 gtkpspellcheckers->dictionary_list = NULL;
228 g_free(gtkpspellcheckers->error_message);
233 static void gtkpspell_checkers_error_message (gchar *message)
236 if (gtkpspellcheckers->error_message) {
237 tmp = g_strdup_printf("%s\n%s",
238 gtkpspellcheckers->error_message, message);
240 g_free(gtkpspellcheckers->error_message);
241 gtkpspellcheckers->error_message = tmp;
243 gtkpspellcheckers->error_message = message;
246 void gtkpspell_checkers_reset_error(void)
248 g_return_if_fail(gtkpspellcheckers);
250 g_free(gtkpspellcheckers->error_message);
252 gtkpspellcheckers->error_message = NULL;
255 GtkPspell *gtkpspell_new(const gchar *dictionary,
256 const gchar *encoding,
257 gint misspelled_color,
258 gboolean check_while_typing,
259 gboolean use_alternate,
263 GtkPspell *gtkpspell;
264 GtkPspeller *gtkpspeller;
266 g_return_val_if_fail(gtktext, NULL);
268 dict = g_new0(Dictionary, 1);
269 dict->fullname = g_strdup(dictionary);
270 dict->encoding = g_strdup(encoding);
272 gtkpspeller = gtkpspeller_new(dict);
273 dictionary_delete(dict);
278 gtkpspell = g_new(GtkPspell, 1);
280 gtkpspell->gtkpspeller = gtkpspeller;
281 gtkpspell->alternate_speller = NULL;
282 gtkpspell->theword[0] = 0x00;
283 gtkpspell->start_pos = 0;
284 gtkpspell->end_pos = 0;
285 gtkpspell->orig_pos = -1;
286 gtkpspell->end_check_pos = -1;
287 gtkpspell->misspelled = -1;
288 gtkpspell->check_while_typing = check_while_typing;
289 gtkpspell->continue_check = NULL;
290 gtkpspell->config_menu = NULL;
291 gtkpspell->popup_config_menu = NULL;
292 gtkpspell->sug_menu = NULL;
293 gtkpspell->replace_entry = NULL;
294 gtkpspell->gtktext = gtktext;
295 gtkpspell->default_sug_mode = PSPELL_FASTMODE;
296 gtkpspell->max_sug = -1;
297 gtkpspell->suggestions_list = NULL;
298 gtkpspell->use_alternate = use_alternate;
300 allocate_color(gtkpspell, misspelled_color);
302 gtk_signal_connect_after(GTK_OBJECT(gtktext), "insert-text",
303 GTK_SIGNAL_FUNC(entry_insert_cb), gtkpspell);
304 gtk_signal_connect_after(GTK_OBJECT(gtktext), "delete-text",
305 GTK_SIGNAL_FUNC(entry_delete_cb), gtkpspell);
306 gtk_signal_connect(GTK_OBJECT(gtktext), "button-press-event",
307 GTK_SIGNAL_FUNC(button_press_intercept_cb), gtkpspell);
309 debug_print("Pspell: created gtkpspell %0x\n", (guint) gtkpspell);
314 void gtkpspell_delete(GtkPspell * gtkpspell)
316 GtkSText *gtktext = gtkpspell->gtktext;
318 gtk_signal_disconnect_by_func(GTK_OBJECT(gtktext),
319 GTK_SIGNAL_FUNC(entry_insert_cb),
321 gtk_signal_disconnect_by_func(GTK_OBJECT(gtktext),
322 GTK_SIGNAL_FUNC(entry_delete_cb),
324 gtk_signal_disconnect_by_func(GTK_OBJECT(gtktext),
325 GTK_SIGNAL_FUNC(button_press_intercept_cb),
328 gtkpspell_uncheck_all(gtkpspell);
330 gtkpspeller_delete(gtkpspell->gtkpspeller);
332 if (gtkpspell->use_alternate && gtkpspell->alternate_speller)
333 gtkpspeller_delete(gtkpspell->alternate_speller);
335 if (gtkpspell->sug_menu)
336 gtk_widget_destroy(gtkpspell->sug_menu);
338 if (gtkpspell->popup_config_menu)
339 gtk_widget_destroy(gtkpspell->popup_config_menu);
341 if (gtkpspell->config_menu)
342 gtk_widget_destroy(gtkpspell->config_menu);
344 if (gtkpspell->suggestions_list)
345 free_suggestions_list(gtkpspell);
347 debug_print("Pspell: deleting gtkpspell %0x\n", (guint) gtkpspell);
354 static void entry_insert_cb(GtkSText *gtktext,
358 GtkPspell *gtkpspell)
360 g_return_if_fail(gtkpspell->gtkpspeller->checker);
362 if (!gtkpspell->check_while_typing)
365 /* We must insert ourselves the character so the
366 * color of the inserted character is the default color.
367 * Never mess with set_insertion when frozen.
370 gtk_stext_freeze(gtktext);
371 gtk_stext_backward_delete(GTK_STEXT(gtktext), len);
372 gtk_stext_insert(GTK_STEXT(gtktext), NULL, NULL, NULL, newtext, len);
373 *ppos = gtk_stext_get_point(GTK_STEXT(gtktext));
375 if (iswordsep(newtext[0])) {
376 /* did we just end a word? */
378 check_at(gtkpspell, *ppos - 2);
380 /* did we just split a word? */
381 if (*ppos < gtk_stext_get_length(gtktext))
382 check_at(gtkpspell, *ppos + 1);
384 /* check as they type, *except* if they're typing at the end (the most
387 if (*ppos < gtk_stext_get_length(gtktext) &&
388 !iswordsep(get_text_index_whar(gtkpspell, *ppos))) {
389 check_at(gtkpspell, *ppos - 1);
393 gtk_stext_thaw(gtktext);
394 gtk_editable_set_position(GTK_EDITABLE(gtktext), *ppos);
397 static void entry_delete_cb(GtkSText *gtktext,
400 GtkPspell *gtkpspell)
404 g_return_if_fail(gtkpspell->gtkpspeller->checker);
406 if (!gtkpspell->check_while_typing)
409 origpos = gtk_editable_get_position(GTK_EDITABLE(gtktext));
411 check_at(gtkpspell, start - 1);
412 check_at(gtkpspell, start);
415 gtk_editable_set_position(GTK_EDITABLE(gtktext), origpos);
416 gtk_stext_set_point(gtktext, origpos);
417 /* this is to *UNDO* the selection, in case they were holding shift
418 * while hitting backspace. */
419 gtk_editable_select_region(GTK_EDITABLE(gtktext), origpos, origpos);
422 /* ok, this is pretty wacky:
423 * we need to let the right-mouse-click go through, so it moves the cursor,
424 * but we *can't* let it go through, because GtkText interprets rightclicks as
425 * weird selection modifiers.
427 * so what do we do? forge rightclicks as leftclicks, then popup the menu.
430 static gint button_press_intercept_cb(GtkSText *gtktext, GdkEvent *e, GtkPspell *gtkpspell)
435 g_return_val_if_fail(gtkpspell->gtkpspeller->checker, FALSE);
437 if (e->type != GDK_BUTTON_PRESS)
439 eb = (GdkEventButton*) e;
444 /* forge the leftclick */
447 gtk_signal_handler_block_by_func(GTK_OBJECT(gtktext),
448 GTK_SIGNAL_FUNC(button_press_intercept_cb),
450 gtk_signal_emit_by_name(GTK_OBJECT(gtktext), "button-press-event",
452 gtk_signal_handler_unblock_by_func(GTK_OBJECT(gtktext),
453 GTK_SIGNAL_FUNC(button_press_intercept_cb),
455 gtk_signal_emit_stop_by_name(GTK_OBJECT(gtktext), "button-press-event");
457 /* now do the menu wackiness */
458 popup_menu(gtkpspell, eb);
459 gtk_grab_remove(GTK_WIDGET(gtktext));
463 /* Checker creation */
464 static GtkPspeller *gtkpspeller_new(Dictionary *dictionary)
467 GtkPspeller *gtkpspeller = NULL;
472 g_return_val_if_fail(gtkpspellcheckers, NULL);
474 g_return_val_if_fail(dictionary, NULL);
476 if (dictionary->fullname == NULL)
477 gtkpspell_checkers_error_message(g_strdup(_("No dictionary selected.")));
479 g_return_val_if_fail(dictionary->fullname, NULL);
481 if (dictionary->dictname == NULL) {
484 tmp = strrchr(dictionary->fullname, G_DIR_SEPARATOR);
487 dictionary->dictname = dictionary->fullname;
489 dictionary->dictname = tmp + 1;
492 dict = dictionary_dup(dictionary);
494 ispell = (strstr2(dict->dictname, "-ispell") != NULL);
496 tmp = g_new0(GtkPspeller, 1);
497 tmp->dictionary = dict;
499 exist = g_slist_find_custom(gtkpspellcheckers->checkers, tmp,
504 if (exist && ispell) {
505 gtkpspeller = (GtkPspeller *) exist->data;
506 dictionary_delete(dict);
508 debug_print(_("Pspell: Using existing ispell checker %0x\n"),
511 if ((gtkpspeller = gtkpspeller_real_new(dict)) != NULL) {
512 gtkpspellcheckers->checkers =
513 g_slist_append(gtkpspellcheckers->checkers,
515 debug_print(_("Pspell: Created a new gtkpspeller %0x\n"),
518 dictionary_delete(dict);
519 debug_print(_("Pspell: Could not create spell checker.\n"));
523 debug_print(_("Pspell: number of existing checkers %d\n"),
524 g_slist_length(gtkpspellcheckers->checkers));
529 static GtkPspeller *gtkpspeller_real_new(Dictionary *dict)
531 GtkPspeller *gtkpspeller;
532 PspellConfig *config;
533 PspellCanHaveError *ret;
535 g_return_val_if_fail(gtkpspellcheckers, NULL);
536 g_return_val_if_fail(dict, NULL);
538 config = new_pspell_config();
540 if (!set_dictionary(config, dict))
543 ret = new_pspell_manager(config);
544 delete_pspell_config(config);
546 if (pspell_error_number(ret) != 0) {
547 gtkpspellcheckers->error_message = g_strdup(pspell_error_message(ret));
549 delete_pspell_can_have_error(ret);
554 gtkpspeller = g_new(GtkPspeller, 1);
556 gtkpspeller->dictionary = dict;
557 gtkpspeller->sug_mode = PSPELL_FASTMODE;
559 gtkpspeller->checker = to_pspell_manager(ret);
560 gtkpspeller->config = pspell_manager_config(gtkpspeller->checker);
561 gtkpspeller->ispell = (strstr2(dict->fullname, "-ispell") != NULL);
566 static GtkPspeller *gtkpspeller_delete(GtkPspeller *gtkpspeller)
568 g_return_val_if_fail(gtkpspellcheckers, NULL);
570 if (gtkpspeller->ispell)
571 debug_print(_("Pspell: Won't remove existing ispell checker %0x.\n"),
574 gtkpspellcheckers->checkers =
575 g_slist_remove(gtkpspellcheckers->checkers,
578 debug_print(_("Pspell: Deleting gtkpspeller %0x.\n"),
581 gtkpspeller_real_delete(gtkpspeller);
584 debug_print(_("Pspell: number of existing checkers %d\n"),
585 g_slist_length(gtkpspellcheckers->checkers));
590 static GtkPspeller *gtkpspeller_real_delete(GtkPspeller *gtkpspeller)
592 g_return_val_if_fail(gtkpspeller, NULL);
593 g_return_val_if_fail(gtkpspeller->checker, NULL);
595 pspell_manager_save_all_word_lists(gtkpspeller->checker);
597 delete_pspell_manager(gtkpspeller->checker);
599 dictionary_delete(gtkpspeller->dictionary);
601 debug_print(_("Pspell: gtkpspeller %0x deleted.\n"),
609 /*****************************************************************************/
610 /* Checker configuration */
612 static gboolean set_dictionary(PspellConfig *config, Dictionary *dict)
614 gchar *language = NULL;
615 gchar *spelling = NULL;
616 gchar *jargon = NULL;
617 gchar *module = NULL;
621 g_return_val_if_fail(config, FALSE);
622 g_return_val_if_fail(dict, FALSE);
624 strncpy(buf, dict->fullname, BUFSIZE-1);
625 buf[BUFSIZE-1] = 0x00;
627 buf[dict->dictname - dict->fullname] = 0x00;
629 CONFIG_REPLACE_RETURN_FALSE_IF_FAIL("rem-all-word-list-path", "");
630 debug_print(_("Pspell: removed all paths.\n"));
632 CONFIG_REPLACE_RETURN_FALSE_IF_FAIL("add-word-list-path", buf);
633 debug_print(_("Pspell: added path %s.\n"), buf);
635 strncpy(buf, dict->dictname, BUFSIZE-1);
638 if ((module = strrchr(buf, '-')) != NULL) {
641 if ((spelling = strchr(language, '-')) != NULL)
643 if (spelling != module) {
644 if ((end = strchr(spelling, '-')) != NULL) {
647 if (jargon != module)
648 if ((end = strchr(jargon, '-')) != NULL)
661 debug_print(_("Pspell: Language: %s, spelling: %s, jargon: %s, module: %s\n"),
662 language, spelling, jargon, module);
665 CONFIG_REPLACE_RETURN_FALSE_IF_FAIL("language-tag", language);
668 CONFIG_REPLACE_RETURN_FALSE_IF_FAIL("spelling", spelling);
671 CONFIG_REPLACE_RETURN_FALSE_IF_FAIL("jargon", jargon);
674 CONFIG_REPLACE_RETURN_FALSE_IF_FAIL("rem-all-module-search-order", "");
675 CONFIG_REPLACE_RETURN_FALSE_IF_FAIL("add-module-search-order", module);
678 if (dict->encoding) {
681 pspell_enc = convert_to_pspell_encoding (dict->encoding);
682 pspell_config_replace(config, "encoding", (const char *) pspell_enc);
685 RETURN_FALSE_IF_CONFIG_ERROR();
691 guchar *gtkpspell_get_dict(GtkPspell *gtkpspell)
694 g_return_val_if_fail(gtkpspell->gtkpspeller->config, NULL);
695 g_return_val_if_fail(gtkpspell->gtkpspeller->dictionary, NULL);
697 return g_strdup(gtkpspell->gtkpspeller->dictionary->dictname);
700 guchar *gtkpspell_get_path(GtkPspell *gtkpspell)
705 g_return_val_if_fail(gtkpspell->gtkpspeller->config, NULL);
706 g_return_val_if_fail(gtkpspell->gtkpspeller->dictionary, NULL);
708 dict = gtkpspell->gtkpspeller->dictionary;
709 path = g_strndup(dict->fullname, dict->dictname - dict->fullname);
714 /* set_sug_mode_cb() - Menu callback: Set the suggestion mode */
715 static void set_sug_mode_cb(GtkMenuItem *w, GtkPspell *gtkpspell)
719 if (gtkpspell->gtkpspeller->ispell) return;
721 gtk_label_get(GTK_LABEL(GTK_BIN(w)->child), (gchar **) &themode);
723 set_real_sug_mode(gtkpspell, themode);
725 if (gtkpspell->config_menu)
726 populate_submenu(gtkpspell, gtkpspell->config_menu);
729 static void set_real_sug_mode(GtkPspell *gtkpspell, const char *themode)
732 gint mode = PSPELL_FASTMODE;
734 g_return_if_fail(gtkpspell);
735 g_return_if_fail(gtkpspell->gtkpspeller);
736 g_return_if_fail(themode);
738 if (!strcmp(themode,_("Normal Mode")))
739 mode = PSPELL_NORMALMODE;
740 else if (!strcmp( themode,_("Bad Spellers Mode")))
741 mode = PSPELL_BADSPELLERMODE;
743 result = gtkpspell_set_sug_mode(gtkpspell, mode);
746 debug_print(_("Pspell: error while changing suggestion mode:%s\n"),
747 gtkpspellcheckers->error_message);
748 gtkpspell_checkers_reset_error();
752 /* gtkpspell_set_sug_mode() - Set the suggestion mode */
753 gboolean gtkpspell_set_sug_mode(GtkPspell *gtkpspell, gint themode)
755 PspellConfig *config;
757 g_return_val_if_fail(gtkpspell, FALSE);
758 g_return_val_if_fail(gtkpspell->gtkpspeller, FALSE);
759 g_return_val_if_fail(gtkpspell->gtkpspeller->config, FALSE);
761 debug_print("Pspell: setting sug mode of gtkpspeller %0x to %d\n",
762 (guint) gtkpspell->gtkpspeller, themode);
764 config = gtkpspell->gtkpspeller->config;
767 case PSPELL_FASTMODE:
768 CONFIG_REPLACE_RETURN_FALSE_IF_FAIL("sug-mode", "fast");
770 case PSPELL_NORMALMODE:
771 CONFIG_REPLACE_RETURN_FALSE_IF_FAIL("sug-mode", "normal");
773 case PSPELL_BADSPELLERMODE:
774 CONFIG_REPLACE_RETURN_FALSE_IF_FAIL("sug-mode",
778 gtkpspellcheckers->error_message =
779 g_strdup(_("Unknown suggestion mode."));
783 gtkpspell->gtkpspeller->sug_mode = themode;
784 gtkpspell->default_sug_mode = themode;
789 /* misspelled_suggest() - Create a suggestion list for word */
790 static GList *misspelled_suggest(GtkPspell *gtkpspell, guchar *word)
792 const guchar *newword;
794 const PspellWordList *suggestions;
795 PspellStringEmulation *elements;
797 g_return_val_if_fail(word, NULL);
799 if (!pspell_manager_check(gtkpspell->gtkpspeller->checker, word, -1)) {
800 free_suggestions_list(gtkpspell);
803 pspell_manager_suggest(gtkpspell->gtkpspeller->checker,
804 (const char *)word, -1);
805 elements = pspell_word_list_elements(suggestions);
806 list = g_list_append(list, g_strdup(word));
808 while ((newword = pspell_string_emulation_next(elements)) != NULL)
809 list = g_list_append(list, g_strdup(newword));
811 gtkpspell->max_sug = g_list_length(list) - 1;
812 gtkpspell->suggestions_list = list;
817 free_suggestions_list(gtkpspell);
822 /* misspelled_test() - Just test if word is correctly spelled */
823 static int misspelled_test(GtkPspell *gtkpspell, unsigned char *word)
825 return pspell_manager_check(gtkpspell->gtkpspeller->checker, word, -1) ?
830 static gboolean iswordsep(unsigned char c)
832 return !isalpha(c) && c != '\'';
835 static guchar get_text_index_whar(GtkPspell *gtkpspell, int pos)
840 text = gtk_editable_get_chars(GTK_EDITABLE(gtkpspell->gtktext), pos,
852 /* get_word_from_pos () - return the word pointed to. */
853 /* Handles correctly the quotes. */
854 static gboolean get_word_from_pos(GtkPspell *gtkpspell, gint pos,
855 unsigned char* buf, gint buflen,
856 gint *pstart, gint *pend)
859 /* TODO : when correcting a word into quotes, change the color of */
860 /* the quotes too, as may be they were highlighted before. To do */
861 /* this, we can use two others pointers that points to the whole */
862 /* word including quotes. */
870 gtktext = gtkpspell->gtktext;
871 if (iswordsep(get_text_index_whar(gtkpspell, pos)))
874 /* The apostrophe character is somtimes used for quotes
875 * So include it in the word only if it is not surrounded
876 * by other characters.
879 for (start = pos; start >= 0; --start) {
880 c = get_text_index_whar(gtkpspell, start);
883 if (!isalpha(get_text_index_whar(gtkpspell,
885 /* start_quote = TRUE; */
890 /* start_quote = TRUE; */
894 else if (!isalpha(c))
900 for (end = pos; end < gtk_stext_get_length(gtktext); end++) {
901 c = get_text_index_whar(gtkpspell, end);
903 if (end < gtk_stext_get_length(gtktext)) {
904 if (!isalpha(get_text_index_whar(gtkpspell,
906 /* end_quote = TRUE; */
911 /* end_quote = TRUE; */
925 if (end - start < buflen) {
926 for (pos = start; pos < end; pos++)
928 get_text_index_whar(gtkpspell, pos);
929 buf[pos - start] = 0;
937 static gboolean check_at(GtkPspell *gtkpspell, gint from_pos)
940 unsigned char buf[GTKPSPELLWORDSIZE];
943 g_return_val_if_fail(from_pos >= 0, FALSE);
945 gtktext = gtkpspell->gtktext;
947 if (!get_word_from_pos(gtkpspell, from_pos, buf, sizeof(buf),
951 if (misspelled_test(gtkpspell, buf)) {
952 strncpy(gtkpspell->theword, buf, GTKPSPELLWORDSIZE - 1);
953 gtkpspell->theword[GTKPSPELLWORDSIZE - 1] = 0;
954 gtkpspell->start_pos = start;
955 gtkpspell->end_pos = end;
956 free_suggestions_list(gtkpspell);
958 change_color(gtkpspell, start, end, buf, &(gtkpspell->highlight));
961 change_color(gtkpspell, start, end, buf, NULL);
966 static gboolean check_next_prev(GtkPspell *gtkpspell, gboolean forward)
975 maxpos = gtkpspell->end_check_pos;
983 pos = gtk_editable_get_position(GTK_EDITABLE(gtkpspell->gtktext));
984 gtkpspell->orig_pos = pos;
985 while (iswordsep(get_text_index_whar(gtkpspell, pos)) &&
986 pos > minpos && pos <= maxpos)
988 while (!(misspelled = check_at(gtkpspell, pos)) &&
989 pos > minpos && pos <= maxpos) {
991 while (!iswordsep(get_text_index_whar(gtkpspell, pos)) &&
992 pos > minpos && pos <= maxpos)
995 while (iswordsep(get_text_index_whar(gtkpspell, pos)) &&
996 pos > minpos && pos <= maxpos)
1000 misspelled_suggest(gtkpspell, gtkpspell->theword);
1003 gtkpspell->orig_pos = gtkpspell->end_pos;
1005 gtk_stext_set_point(GTK_STEXT(gtkpspell->gtktext),
1006 gtkpspell->end_pos);
1007 gtk_editable_set_position(GTK_EDITABLE(gtkpspell->gtktext),
1008 gtkpspell->end_pos);
1009 gtk_menu_popup(make_sug_menu(gtkpspell), NULL, NULL,
1010 set_menu_pos, gtkpspell, 0, GDK_CURRENT_TIME);
1012 reset_theword_data(gtkpspell);
1014 gtkpspell_alert_dialog(_("No misspelled word found."));
1015 gtk_stext_set_point(GTK_STEXT(gtkpspell->gtktext),
1016 gtkpspell->orig_pos);
1017 gtk_editable_set_position(GTK_EDITABLE(gtkpspell->gtktext),
1018 gtkpspell->orig_pos);
1025 void gtkpspell_check_backwards(GtkPspell *gtkpspell)
1027 gtkpspell->continue_check = NULL;
1028 gtkpspell->end_check_pos =
1029 gtk_stext_get_length(GTK_STEXT(gtkpspell->gtktext));
1030 check_next_prev(gtkpspell, FALSE);
1033 void gtkpspell_check_forwards_go(GtkPspell *gtkpspell)
1036 gtkpspell->continue_check = NULL;
1037 gtkpspell->end_check_pos
1038 = gtk_stext_get_length(GTK_STEXT(gtkpspell->gtktext));
1039 check_next_prev(gtkpspell, TRUE);
1042 void gtkpspell_check_all(GtkPspell *gtkpspell)
1047 g_return_if_fail(gtkpspell);
1048 g_return_if_fail(gtkpspell->gtktext);
1050 gtktext = (GtkWidget *) gtkpspell->gtktext;
1053 end = gtk_stext_get_length(GTK_STEXT(gtktext));
1055 if (GTK_EDITABLE(gtktext)->has_selection) {
1056 start = GTK_EDITABLE(gtktext)->selection_start_pos;
1057 end = GTK_EDITABLE(gtktext)->selection_end_pos;
1069 gtk_editable_set_position(GTK_EDITABLE(gtktext), start);
1070 gtk_stext_set_point(GTK_STEXT(gtktext), start);
1072 gtkpspell->continue_check = continue_check;
1073 gtkpspell->end_check_pos = end;
1075 gtkpspell->misspelled = check_next_prev(gtkpspell, TRUE);
1079 static void continue_check(gpointer *data)
1081 GtkPspell *gtkpspell = (GtkPspell *) data;
1082 gint pos = gtk_editable_get_position(GTK_EDITABLE(gtkpspell->gtktext));
1083 if (pos < gtkpspell->end_check_pos && gtkpspell->misspelled)
1084 gtkpspell->misspelled = check_next_prev(gtkpspell, TRUE);
1086 gtkpspell->continue_check = NULL;
1090 void gtkpspell_highlight_all(GtkPspell *gtkpspell)
1098 g_return_if_fail(gtkpspell->gtkpspeller->checker);
1100 gtktext = gtkpspell->gtktext;
1102 adj_value = gtktext->vadj->value;
1104 len = gtk_stext_get_length(gtktext);
1106 origpos = gtk_editable_get_position(GTK_EDITABLE(gtktext));
1108 /* gtk_editable_set_position(GTK_EDITABLE(gtktext), 0);*/
1112 iswordsep(get_text_index_whar(gtkpspell, pos)))
1115 !iswordsep(get_text_index_whar(gtkpspell, pos)))
1118 check_at(gtkpspell, pos - 1);
1120 gtk_editable_set_position(GTK_EDITABLE(gtktext), origpos);
1121 gtk_stext_set_point(GTK_STEXT(gtktext), origpos);
1122 gtk_adjustment_set_value(gtktext->vadj, adj_value);
1123 /* gtk_editable_select_region(GTK_EDITABLE(gtktext), origpos, origpos);*/
1126 static void replace_with_supplied_word_cb(GtkWidget *w, GtkPspell *gtkpspell)
1128 unsigned char *newword;
1129 GdkEvent *e= (GdkEvent *) gtk_get_current_event();
1131 newword = gtk_editable_get_chars(GTK_EDITABLE(gtkpspell->replace_entry),
1134 if (strcmp(newword, gtkpspell->theword)) {
1135 replace_real_word(gtkpspell, newword);
1137 if ((e->type == GDK_KEY_PRESS &&
1138 ((GdkEventKey *) e)->state & GDK_MOD1_MASK)) {
1139 pspell_manager_store_replacement(gtkpspell->gtkpspeller->checker,
1140 gtkpspell->theword, -1,
1143 gtkpspell->replace_entry = NULL;
1148 set_point_continue(gtkpspell);
1152 static void replace_word_cb(GtkWidget *w, gpointer data)
1154 unsigned char *newword;
1155 GtkPspell *gtkpspell = (GtkPspell *) data;
1156 GdkEvent *e= (GdkEvent *) gtk_get_current_event();
1158 gtk_label_get(GTK_LABEL(GTK_BIN(w)->child), (gchar**) &newword);
1160 replace_real_word(gtkpspell, newword);
1162 if ((e->type == GDK_KEY_PRESS &&
1163 ((GdkEventKey *) e)->state & GDK_MOD1_MASK) ||
1164 (e->type == GDK_BUTTON_RELEASE &&
1165 ((GdkEventButton *) e)->state & GDK_MOD1_MASK)) {
1166 pspell_manager_store_replacement(gtkpspell->gtkpspeller->checker,
1167 gtkpspell->theword, -1,
1171 gtk_menu_shell_deactivate(GTK_MENU_SHELL(w->parent));
1173 set_point_continue(gtkpspell);
1176 static void replace_real_word(GtkPspell *gtkpspell, gchar *newword)
1178 int oldlen, newlen, wordlen;
1181 gint start = gtkpspell->start_pos;
1184 if (!newword) return;
1186 gtktext = gtkpspell->gtktext;
1188 gtk_stext_freeze(GTK_STEXT(gtktext));
1189 origpos = gtkpspell->orig_pos;
1191 oldlen = gtkpspell->end_pos - gtkpspell->start_pos;
1192 wordlen = strlen(gtkpspell->theword);
1194 newlen = strlen(newword); /* FIXME: multybyte characters? */
1196 gtk_signal_handler_block_by_func(GTK_OBJECT(gtktext),
1197 GTK_SIGNAL_FUNC(entry_insert_cb),
1199 gtk_signal_handler_block_by_func(GTK_OBJECT(gtktext),
1200 GTK_SIGNAL_FUNC(entry_delete_cb),
1203 gtk_signal_emit_by_name(GTK_OBJECT(gtktext), "delete-text",
1204 gtkpspell->start_pos, gtkpspell->end_pos);
1205 gtk_signal_emit_by_name(GTK_OBJECT(gtktext), "insert-text",
1206 newword, newlen, &start);
1208 gtk_signal_handler_unblock_by_func(GTK_OBJECT(gtktext),
1209 GTK_SIGNAL_FUNC(entry_insert_cb),
1211 gtk_signal_handler_unblock_by_func(GTK_OBJECT(gtktext),
1212 GTK_SIGNAL_FUNC(entry_delete_cb),
1215 /* Put the point and the position where we clicked with the mouse
1216 * It seems to be a hack, as I must thaw,freeze,thaw the widget
1217 * to let it update correctly the word insertion and then the
1218 * point & position position. If not, SEGV after the first replacement
1219 * If the new word ends before point, put the point at its end.
1222 if (origpos - gtkpspell->start_pos < oldlen &&
1223 origpos - gtkpspell->start_pos >= 0) {
1224 /* Original point was in the word.
1225 * Let it there unless point is going to be outside of the word
1227 if (origpos - gtkpspell->start_pos >= newlen) {
1228 pos = gtkpspell->start_pos + newlen;
1231 else if (origpos >= gtkpspell->end_pos) {
1232 /* move the position according to the change of length */
1233 pos = origpos + newlen - oldlen;
1236 gtkpspell->end_pos = gtkpspell->start_pos + strlen(newword); /* FIXME: multibyte characters? */
1238 gtk_stext_thaw(GTK_STEXT(gtktext));
1239 gtk_stext_freeze(GTK_STEXT(gtktext));
1241 if (GTK_STEXT(gtktext)->text_len < pos)
1242 pos = gtk_stext_get_length(GTK_STEXT(gtktext));
1244 gtkpspell->orig_pos = pos;
1246 gtk_editable_set_position(GTK_EDITABLE(gtktext), gtkpspell->orig_pos);
1247 gtk_stext_set_point(GTK_STEXT(gtktext),
1248 gtk_editable_get_position(GTK_EDITABLE(gtktext)));
1250 gtk_stext_thaw(GTK_STEXT(gtktext));
1253 /* Accept this word for this session */
1254 static void add_word_to_session_cb(GtkWidget *w, gpointer data)
1258 GtkPspell *gtkpspell = (GtkPspell *) data;
1259 gtktext = gtkpspell->gtktext;
1261 gtk_stext_freeze(GTK_STEXT(gtktext));
1263 pos = gtk_editable_get_position(GTK_EDITABLE(gtktext));
1265 pspell_manager_add_to_session(gtkpspell->gtkpspeller->checker,
1267 strlen(gtkpspell->theword));
1269 check_at(gtkpspell, gtkpspell->start_pos);
1271 gtk_stext_thaw(gtkpspell->gtktext);
1273 gtk_menu_shell_deactivate(GTK_MENU_SHELL(GTK_WIDGET(w)->parent));
1275 set_point_continue(gtkpspell);
1278 /* add_word_to_personal_cb() - add word to personal dict. */
1279 static void add_word_to_personal_cb(GtkWidget *w, gpointer data)
1281 GtkPspell *gtkpspell = (GtkPspell *) data;
1282 GtkSText *gtktext = gtkpspell->gtktext;
1284 gtk_stext_freeze(GTK_STEXT(gtktext));
1286 pspell_manager_add_to_personal(gtkpspell->gtkpspeller->checker,
1288 strlen(gtkpspell->theword));
1290 check_at(gtkpspell, gtkpspell->start_pos);
1292 gtk_stext_thaw(gtkpspell->gtktext);
1294 gtk_menu_shell_deactivate(GTK_MENU_SHELL(GTK_WIDGET(w)->parent));
1295 set_point_continue(gtkpspell);
1298 static void check_with_alternate_cb(GtkWidget *w, gpointer data)
1300 GtkPspell *gtkpspell = (GtkPspell *) data;
1303 gtk_menu_shell_deactivate(GTK_MENU_SHELL(GTK_WIDGET(w)->parent));
1305 use_alternate_dict(gtkpspell);
1306 misspelled = check_at(gtkpspell, gtkpspell->start_pos);
1308 if (!gtkpspell->continue_check) {
1310 gtkpspell->misspelled = misspelled;
1312 if (gtkpspell->misspelled) {
1314 misspelled_suggest(gtkpspell, gtkpspell->theword);
1316 gtk_stext_set_point(GTK_STEXT(gtkpspell->gtktext),
1317 gtkpspell->end_pos);
1318 gtk_editable_set_position(GTK_EDITABLE(gtkpspell->gtktext),
1319 gtkpspell->end_pos);
1321 gtk_menu_popup(make_sug_menu(gtkpspell), NULL, NULL,
1322 set_menu_pos, gtkpspell, 0,
1327 gtkpspell->orig_pos = gtkpspell->start_pos;
1329 set_point_continue(gtkpspell);
1332 static void replace_with_create_dialog_cb(GtkWidget *w, gpointer data)
1338 GtkWidget *ok_button;
1339 GtkWidget *cancel_button;
1342 GtkPspell *gtkpspell = (GtkPspell *) data;
1344 gdk_window_get_origin((GTK_WIDGET(w)->parent)->window, &xx, &yy);
1346 gtk_menu_shell_deactivate(GTK_MENU_SHELL(GTK_WIDGET(w)->parent));
1348 dialog = gtk_dialog_new();
1350 gtk_window_set_policy(GTK_WINDOW(dialog), FALSE, FALSE, FALSE);
1351 gtk_window_set_title(GTK_WINDOW(dialog),_("Replace unknown word"));
1352 gtk_widget_set_uposition(dialog, xx, yy);
1354 gtk_signal_connect_object(GTK_OBJECT(dialog), "destroy",
1355 GTK_SIGNAL_FUNC(gtk_widget_destroy),
1356 GTK_OBJECT(dialog));
1358 hbox = gtk_hbox_new(FALSE, 0);
1359 gtk_container_set_border_width(GTK_CONTAINER(hbox), 8);
1361 thelabel = g_strdup_printf(_("Replace \"%s\" with: "),
1362 gtkpspell->theword);
1363 label = gtk_label_new(thelabel);
1365 gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0);
1367 entry = gtk_entry_new();
1368 gtkpspell->replace_entry = entry;
1369 gtk_entry_set_text(GTK_ENTRY(entry), gtkpspell->theword);
1370 gtk_editable_select_region(GTK_EDITABLE(entry), 0, -1);
1371 gtk_signal_connect(GTK_OBJECT(entry), "activate",
1372 GTK_SIGNAL_FUNC(replace_with_supplied_word_cb),
1374 gtk_signal_connect_object(GTK_OBJECT(entry), "activate",
1375 GTK_SIGNAL_FUNC(gtk_widget_destroy),
1376 GTK_OBJECT(dialog));
1377 gtk_box_pack_start(GTK_BOX(hbox), entry, TRUE, TRUE, 0);
1379 gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog)->vbox), hbox, TRUE,
1381 if (!gtkpspell->gtkpspeller->ispell) {
1382 label = gtk_label_new(_("Holding down MOD1 key while pressing "
1383 "Enter\nwill learn from mistake.\n"));
1384 gtk_label_set_justify(GTK_LABEL(label), GTK_JUSTIFY_LEFT);
1385 gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.0);
1386 gtk_misc_set_padding(GTK_MISC(label), 8, 0);
1387 gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog)->vbox), label,
1391 hbox = gtk_hbox_new(TRUE, 0);
1393 ok_button = gtk_button_new_with_label(_("OK"));
1394 gtk_box_pack_start(GTK_BOX(hbox), ok_button, TRUE, TRUE, 8);
1395 gtk_signal_connect(GTK_OBJECT(ok_button), "clicked",
1396 GTK_SIGNAL_FUNC(replace_with_supplied_word_cb),
1398 gtk_signal_connect_object(GTK_OBJECT(ok_button), "clicked",
1399 GTK_SIGNAL_FUNC(gtk_widget_destroy),
1400 GTK_OBJECT(dialog));
1402 cancel_button = gtk_button_new_with_label(_("Cancel"));
1403 gtk_box_pack_start(GTK_BOX(hbox), cancel_button, TRUE, TRUE, 8);
1404 gtk_signal_connect_object(GTK_OBJECT(cancel_button), "clicked",
1405 GTK_SIGNAL_FUNC(gtk_widget_destroy),
1406 GTK_OBJECT(dialog));
1408 gtk_container_add(GTK_CONTAINER(GTK_DIALOG(dialog)->action_area), hbox);
1410 gtk_widget_grab_focus(entry);
1412 gtk_window_set_modal(GTK_WINDOW(dialog), TRUE);
1414 gtk_widget_show_all(dialog);
1417 void gtkpspell_uncheck_all(GtkPspell * gtkpspell)
1424 gtktext = gtkpspell->gtktext;
1426 adj_value = gtktext->vadj->value;
1428 gtk_stext_freeze(gtktext);
1430 origpos = gtk_editable_get_position(GTK_EDITABLE(gtktext));
1432 text = gtk_editable_get_chars(GTK_EDITABLE(gtktext), 0, -1);
1434 gtk_stext_set_point(gtktext, 0);
1435 gtk_stext_forward_delete(gtktext, gtk_stext_get_length(gtktext));
1436 gtk_stext_insert(gtktext, NULL, NULL, NULL, text, strlen(text));
1438 gtk_stext_thaw(gtktext);
1440 gtk_editable_set_position(GTK_EDITABLE(gtktext), origpos);
1441 gtk_stext_set_point(gtktext, origpos);
1442 gtk_adjustment_set_value(gtktext->vadj, adj_value);
1448 static void toggle_check_while_typing_cb(GtkWidget *w, gpointer data)
1450 GtkPspell *gtkpspell = (GtkPspell *) data;
1452 gtkpspell->check_while_typing = gtkpspell->check_while_typing == FALSE;
1454 if (!gtkpspell->check_while_typing)
1455 gtkpspell_uncheck_all(gtkpspell);
1457 if (gtkpspell->config_menu)
1458 populate_submenu(gtkpspell, gtkpspell->config_menu);
1461 static GSList *create_empty_dictionary_list(void)
1463 GSList *list = NULL;
1466 dict = g_new0(Dictionary, 1);
1467 dict->fullname = g_strdup(_("None"));
1468 dict->dictname = dict->fullname;
1469 dict->encoding = NULL;
1471 return g_slist_append(list, dict);
1474 /* gtkpspell_get_dictionary_list() - returns list of dictionary names */
1475 GSList *gtkpspell_get_dictionary_list(const gchar *pspell_path, gint refresh)
1478 gchar *dict_path, *tmp, *prevdir;
1479 gchar tmpname[BUFSIZE];
1484 if (!gtkpspellcheckers)
1485 gtkpspellcheckers = gtkpspell_checkers_new();
1487 if (gtkpspellcheckers->dictionary_list && !refresh)
1488 return gtkpspellcheckers->dictionary_list;
1490 gtkpspell_free_dictionary_list(gtkpspellcheckers->dictionary_list);
1495 #warning TODO: no directory change
1497 dict_path = g_strdup(pspell_path);
1498 prevdir = g_get_current_dir();
1499 if (chdir(dict_path) <0) {
1500 debug_print(_("Pspell: error when searching for dictionaries:\n%s\n"),
1504 gtkpspellcheckers->dictionary_list =
1505 create_empty_dictionary_list();
1507 return gtkpspellcheckers->dictionary_list;
1510 debug_print(_("Pspell: checking for dictionaries in %s\n"), dict_path);
1512 if (NULL != (dir = opendir("."))) {
1513 while (NULL != (ent = readdir(dir))) {
1514 /* search for pwli */
1515 if ((NULL != (tmp = strstr2(ent->d_name, ".pwli"))) &&
1517 g_snprintf(tmpname, BUFSIZE, "%s%s",
1518 G_DIR_SEPARATOR_S, ent->d_name);
1519 tmpname[MIN(tmp - ent->d_name + 1, BUFSIZE-1)] =
1521 dict = g_new0(Dictionary, 1);
1522 dict->fullname = g_strdup_printf("%s%s",
1525 dict->dictname = strrchr(dict->fullname,
1526 G_DIR_SEPARATOR) + 1;
1527 dict->encoding = NULL;
1528 debug_print(_("Pspell: found dictionary %s %s\n"),
1529 dict->fullname, dict->dictname);
1530 list = g_slist_insert_sorted(list, dict,
1531 (GCompareFunc) compare_dict);
1537 debug_print(_("Pspell: error when searching for dictionaries.\nNo dictionary found.\n(%s)"),
1539 list = create_empty_dictionary_list();
1543 debug_print(_("Pspell: error when searching for dictionaries.\nNo dictionary found.\n"));
1544 list = create_empty_dictionary_list();
1550 gtkpspellcheckers->dictionary_list = list;
1555 void gtkpspell_free_dictionary_list(GSList *list)
1559 for (walk = list; walk != NULL; walk = g_slist_next(walk))
1561 dict = (Dictionary *) walk->data;
1562 dictionary_delete(dict);
1567 GtkWidget *gtkpspell_dictionary_option_menu_new(const gchar *pspell_path)
1569 GSList *dict_list, *tmp;
1574 dict_list = gtkpspell_get_dictionary_list(pspell_path, TRUE);
1575 g_return_val_if_fail(dict_list, NULL);
1577 menu = gtk_menu_new();
1579 for (tmp = dict_list; tmp != NULL; tmp = g_slist_next(tmp)) {
1580 dict = (Dictionary *) tmp->data;
1581 item = gtk_menu_item_new_with_label(dict->dictname);
1582 gtk_object_set_data(GTK_OBJECT(item), "dict_name",
1585 gtk_menu_append(GTK_MENU(menu), item);
1586 gtk_widget_show(item);
1589 gtk_widget_show(menu);
1594 gchar *gtkpspell_get_dictionary_menu_active_item(GtkWidget *menu)
1596 GtkWidget *menuitem;
1597 gchar *dict_fullname;
1600 g_return_val_if_fail(GTK_IS_MENU(menu), NULL);
1602 menuitem = gtk_menu_get_active(GTK_MENU(menu));
1603 dict_fullname = (gchar *) gtk_object_get_data(GTK_OBJECT(menuitem),
1605 g_return_val_if_fail(dict_fullname, NULL);
1607 label = g_strdup(dict_fullname);
1613 GtkWidget *gtkpspell_sugmode_option_menu_new(gint sugmode)
1618 menu = gtk_menu_new();
1619 gtk_widget_show(menu);
1621 item = gtk_menu_item_new_with_label(_("Fast Mode"));
1622 gtk_widget_show(item);
1623 gtk_menu_append(GTK_MENU(menu), item);
1624 gtk_object_set_data(GTK_OBJECT(item), "sugmode",
1625 GINT_TO_POINTER(PSPELL_FASTMODE));
1627 item = gtk_menu_item_new_with_label(_("Normal Mode"));
1628 gtk_widget_show(item);
1629 gtk_menu_append(GTK_MENU(menu), item);
1630 gtk_object_set_data(GTK_OBJECT(item), "sugmode",
1631 GINT_TO_POINTER(PSPELL_NORMALMODE));
1633 item = gtk_menu_item_new_with_label(_("Bad Spellers Mode"));
1634 gtk_widget_show(item);
1635 gtk_menu_append(GTK_MENU(menu), item);
1636 gtk_object_set_data(GTK_OBJECT(item), "sugmode",
1637 GINT_TO_POINTER(PSPELL_BADSPELLERMODE));
1642 void gtkpspell_sugmode_option_menu_set(GtkOptionMenu *optmenu, gint sugmode)
1644 g_return_if_fail(GTK_IS_OPTION_MENU(optmenu));
1646 g_return_if_fail(sugmode == PSPELL_FASTMODE ||
1647 sugmode == PSPELL_NORMALMODE ||
1648 sugmode == PSPELL_BADSPELLERMODE);
1650 gtk_option_menu_set_history(GTK_OPTION_MENU(optmenu), sugmode - 1);
1653 gint gtkpspell_get_sugmode_from_option_menu(GtkOptionMenu *optmenu)
1658 g_return_val_if_fail(GTK_IS_OPTION_MENU(optmenu), -1);
1660 item = gtk_menu_get_active(GTK_MENU(gtk_option_menu_get_menu(optmenu)));
1662 sugmode = GPOINTER_TO_INT(gtk_object_get_data(GTK_OBJECT(item),
1668 static void use_alternate_dict(GtkPspell *gtkpspell)
1672 tmp = gtkpspell->gtkpspeller;
1673 gtkpspell->gtkpspeller = gtkpspell->alternate_speller;
1674 gtkpspell->alternate_speller = tmp;
1676 if (gtkpspell->config_menu)
1677 populate_submenu(gtkpspell, gtkpspell->config_menu);
1680 static void popup_menu(GtkPspell *gtkpspell, GdkEventButton *eb)
1684 gtktext = gtkpspell->gtktext;
1685 gtkpspell->orig_pos = gtk_editable_get_position(GTK_EDITABLE(gtktext));
1687 if (!(eb->state & GDK_SHIFT_MASK)) {
1688 if (check_at(gtkpspell, gtkpspell->orig_pos)) {
1690 gtk_editable_set_position(GTK_EDITABLE(gtktext),
1691 gtkpspell->orig_pos);
1692 gtk_stext_set_point(gtktext, gtkpspell->orig_pos);
1694 if (misspelled_suggest(gtkpspell, gtkpspell->theword)) {
1695 gtk_menu_popup(make_sug_menu(gtkpspell),
1696 NULL, NULL, NULL, NULL,
1697 eb->button, GDK_CURRENT_TIME);
1702 gtk_editable_set_position(GTK_EDITABLE(gtktext),
1703 gtkpspell->orig_pos);
1704 gtk_stext_set_point(gtktext, gtkpspell->orig_pos);
1708 gtk_menu_popup(make_config_menu(gtkpspell), NULL, NULL, NULL, NULL,
1709 eb->button, GDK_CURRENT_TIME);
1712 /* make_sug_menu() - Add menus to accept this word for this session
1713 * and to add it to personal dictionary
1715 static GtkMenu *make_sug_menu(GtkPspell *gtkpspell)
1717 GtkWidget *menu, *item;
1718 unsigned char *caption;
1720 GtkAccelGroup *accel;
1721 GList *l = gtkpspell->suggestions_list;
1723 gtktext = gtkpspell->gtktext;
1725 accel = gtk_accel_group_new();
1726 menu = gtk_menu_new();
1728 if (gtkpspell->sug_menu)
1729 gtk_widget_destroy(gtkpspell->sug_menu);
1731 gtkpspell->sug_menu = menu;
1733 gtk_signal_connect(GTK_OBJECT(menu), "cancel",
1734 GTK_SIGNAL_FUNC(cancel_menu_cb), gtkpspell);
1736 caption = g_strdup_printf(_("\"%s\" unknown in %s"),
1737 (unsigned char*) l->data,
1738 gtkpspell->gtkpspeller->dictionary->dictname);
1739 item = gtk_menu_item_new_with_label(caption);
1740 gtk_widget_show(item);
1741 gtk_menu_append(GTK_MENU(menu), item);
1742 gtk_misc_set_alignment(GTK_MISC(GTK_BIN(item)->child), 0.5, 0.5);
1745 item = gtk_menu_item_new();
1746 gtk_widget_show(item);
1747 gtk_menu_append(GTK_MENU(menu), item);
1749 item = gtk_menu_item_new_with_label(_("Accept in this session"));
1750 gtk_widget_show(item);
1751 gtk_menu_append(GTK_MENU(menu), item);
1752 gtk_signal_connect(GTK_OBJECT(item), "activate",
1753 GTK_SIGNAL_FUNC(add_word_to_session_cb),
1755 gtk_widget_add_accelerator(item, "activate", accel, GDK_space,
1757 GTK_ACCEL_LOCKED | GTK_ACCEL_VISIBLE);
1759 item = gtk_menu_item_new_with_label(_("Add to personal dictionary"));
1760 gtk_widget_show(item);
1761 gtk_menu_append(GTK_MENU(menu), item);
1762 gtk_signal_connect(GTK_OBJECT(item), "activate",
1763 GTK_SIGNAL_FUNC(add_word_to_personal_cb),
1765 gtk_widget_add_accelerator(item, "activate", accel, GDK_Return,
1767 GTK_ACCEL_LOCKED | GTK_ACCEL_VISIBLE);
1769 item = gtk_menu_item_new_with_label(_("Replace with..."));
1770 gtk_widget_show(item);
1771 gtk_menu_append(GTK_MENU(menu), item);
1772 gtk_signal_connect(GTK_OBJECT(item), "activate",
1773 GTK_SIGNAL_FUNC(replace_with_create_dialog_cb),
1775 gtk_widget_add_accelerator(item, "activate", accel, GDK_R, 0,
1776 GTK_ACCEL_LOCKED | GTK_ACCEL_VISIBLE);
1778 if (gtkpspell->use_alternate && gtkpspell->alternate_speller) {
1779 caption = g_strdup_printf(_("Check with %s"),
1780 gtkpspell->alternate_speller->dictionary->dictname);
1781 item = gtk_menu_item_new_with_label(caption);
1783 gtk_widget_show(item);
1784 gtk_menu_append(GTK_MENU(menu), item);
1785 gtk_signal_connect(GTK_OBJECT(item), "activate",
1786 GTK_SIGNAL_FUNC(check_with_alternate_cb),
1788 gtk_widget_add_accelerator(item, "activate", accel, GDK_X, 0,
1789 GTK_ACCEL_LOCKED | GTK_ACCEL_VISIBLE);
1792 item = gtk_menu_item_new();
1793 gtk_widget_show(item);
1794 gtk_menu_append(GTK_MENU(menu), item);
1798 item = gtk_menu_item_new_with_label(_("(no suggestions)"));
1799 gtk_widget_show(item);
1800 gtk_menu_append(GTK_MENU(menu), item);
1802 GtkWidget *curmenu = menu;
1806 if (l->data == NULL && l->next != NULL) {
1808 curmenu = gtk_menu_new();
1809 item = gtk_menu_item_new_with_label(_("Others..."));
1810 gtk_widget_show(item);
1811 gtk_menu_append(GTK_MENU(curmenu), item);
1812 gtk_menu_item_set_submenu(GTK_MENU_ITEM(item),
1816 } else if (count > MENUCOUNT) {
1819 item = gtk_menu_item_new_with_label(_("More..."));
1820 gtk_widget_show(item);
1821 gtk_menu_append(GTK_MENU(curmenu), item);
1823 curmenu = gtk_menu_new();
1824 gtk_menu_item_set_submenu(GTK_MENU_ITEM(item),
1828 item = gtk_menu_item_new_with_label((unsigned char*)l->data);
1829 gtk_widget_show(item);
1830 gtk_menu_append(GTK_MENU(curmenu), item);
1831 gtk_signal_connect(GTK_OBJECT(item), "activate",
1832 GTK_SIGNAL_FUNC(replace_word_cb),
1835 if (curmenu == menu && count < MENUCOUNT) {
1836 gtk_widget_add_accelerator(item, "activate",
1841 gtk_widget_add_accelerator(item, "activate",
1850 } while ((l = l->next) != NULL);
1853 gtk_accel_group_attach(accel, GTK_OBJECT(menu));
1854 gtk_accel_group_unref(accel);
1856 return GTK_MENU(menu);
1859 static void populate_submenu(GtkPspell *gtkpspell, GtkWidget *menu)
1861 GtkWidget *item, *submenu;
1863 GtkPspeller *gtkpspeller = gtkpspell->gtkpspeller;
1864 gint ispell = gtkpspeller->ispell;
1866 if (GTK_MENU_SHELL(menu)->children) {
1867 GList *amenu, *alist;
1868 for (amenu = (GTK_MENU_SHELL(menu)->children); amenu; ) {
1869 alist = amenu->next;
1870 gtk_widget_destroy(GTK_WIDGET(amenu->data));
1875 dictname = g_strdup_printf(_("Dictionary: %s"),
1876 gtkpspeller->dictionary->dictname);
1877 item = gtk_menu_item_new_with_label(dictname);
1878 gtk_misc_set_alignment(GTK_MISC(GTK_BIN(item)->child), 0.5, 0.5);
1880 gtk_widget_show(item);
1881 gtk_menu_append(GTK_MENU(menu), item);
1883 item = gtk_menu_item_new();
1884 gtk_widget_show(item);
1885 gtk_menu_append(GTK_MENU(menu), item);
1887 if (gtkpspell->use_alternate && gtkpspell->alternate_speller) {
1888 dictname = g_strdup_printf(_("Use alternate (%s)"),
1889 gtkpspell->alternate_speller->dictionary->dictname);
1890 item = gtk_menu_item_new_with_label(dictname);
1892 gtk_signal_connect(GTK_OBJECT(item), "activate",
1893 GTK_SIGNAL_FUNC(switch_to_alternate_cb),
1895 gtk_widget_show(item);
1896 gtk_menu_append(GTK_MENU(menu), item);
1897 item = gtk_menu_item_new();
1898 gtk_widget_show(item);
1899 gtk_menu_append(GTK_MENU(menu), item);
1902 item = gtk_check_menu_item_new_with_label(_("Fast Mode"));
1903 if (ispell || gtkpspell->gtkpspeller->sug_mode == PSPELL_FASTMODE)
1904 gtk_widget_set_sensitive(GTK_WIDGET(item),FALSE);
1905 if (!ispell && gtkpspell->gtkpspeller->sug_mode == PSPELL_FASTMODE)
1906 gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(item),TRUE);
1908 gtk_signal_connect(GTK_OBJECT(item), "activate",
1909 GTK_SIGNAL_FUNC(set_sug_mode_cb),
1911 gtk_widget_show(item);
1912 gtk_menu_append(GTK_MENU(menu), item);
1914 item = gtk_check_menu_item_new_with_label(_("Normal Mode"));
1915 if (ispell || gtkpspell->gtkpspeller->sug_mode == PSPELL_NORMALMODE)
1916 gtk_widget_set_sensitive(GTK_WIDGET(item), FALSE);
1917 if (!ispell && gtkpspell->gtkpspeller->sug_mode == PSPELL_NORMALMODE)
1918 gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(item), TRUE);
1920 gtk_signal_connect(GTK_OBJECT(item), "activate",
1921 GTK_SIGNAL_FUNC(set_sug_mode_cb),
1923 gtk_widget_show(item);
1924 gtk_menu_append(GTK_MENU(menu),item);
1926 item = gtk_check_menu_item_new_with_label(_("Bad Spellers Mode"));
1927 if (ispell || gtkpspell->gtkpspeller->sug_mode == PSPELL_BADSPELLERMODE)
1928 gtk_widget_set_sensitive(GTK_WIDGET(item), FALSE);
1929 if (!ispell && gtkpspell->gtkpspeller->sug_mode == PSPELL_BADSPELLERMODE)
1930 gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(item), TRUE);
1932 gtk_signal_connect(GTK_OBJECT(item), "activate",
1933 GTK_SIGNAL_FUNC(set_sug_mode_cb),
1935 gtk_widget_show(item);
1936 gtk_menu_append(GTK_MENU(menu), item);
1938 item = gtk_menu_item_new();
1939 gtk_widget_show(item);
1940 gtk_menu_append(GTK_MENU(menu), item);
1942 item = gtk_check_menu_item_new_with_label(_("Check while typing"));
1943 if (gtkpspell->check_while_typing)
1944 gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(item), TRUE);
1946 gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(item), FALSE);
1947 gtk_signal_connect(GTK_OBJECT(item), "activate",
1948 GTK_SIGNAL_FUNC(toggle_check_while_typing_cb),
1950 gtk_widget_show(item);
1951 gtk_menu_append(GTK_MENU(menu), item);
1953 item = gtk_menu_item_new();
1954 gtk_widget_show(item);
1955 gtk_menu_append(GTK_MENU(menu), item);
1957 submenu = gtk_menu_new();
1958 item = gtk_menu_item_new_with_label(_("Change dictionary"));
1959 gtk_menu_item_set_submenu(GTK_MENU_ITEM(item),submenu);
1960 gtk_widget_show(item);
1961 gtk_menu_append(GTK_MENU(menu), item);
1964 if (gtkpspellcheckers->dictionary_list == NULL)
1965 gtkpspell_get_dictionary_list(prefs_common.pspell_path, FALSE);
1967 GtkWidget * curmenu = submenu;
1971 tmp = gtkpspellcheckers->dictionary_list;
1973 for (tmp = gtkpspellcheckers->dictionary_list; tmp != NULL;
1974 tmp = g_slist_next(tmp)) {
1975 dict = (Dictionary *) tmp->data;
1976 item = gtk_check_menu_item_new_with_label(dict->dictname);
1977 gtk_object_set_data(GTK_OBJECT(item), "dict_name",
1979 if (strcmp2(dict->fullname,
1980 gtkpspell->gtkpspeller->dictionary->fullname))
1981 gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(item), FALSE);
1983 gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(item), TRUE);
1984 gtk_widget_set_sensitive(GTK_WIDGET(item),
1987 gtk_signal_connect(GTK_OBJECT(item), "activate",
1988 GTK_SIGNAL_FUNC(change_dict_cb),
1990 gtk_widget_show(item);
1991 gtk_menu_append(GTK_MENU(curmenu), item);
1995 if (count == MENUCOUNT) {
1998 newmenu = gtk_menu_new();
1999 item = gtk_menu_item_new_with_label(_("More..."));
2000 gtk_menu_item_set_submenu(GTK_MENU_ITEM(item),
2003 gtk_menu_append(GTK_MENU(curmenu), item);
2004 gtk_widget_show(item);
2012 static GtkMenu *make_config_menu(GtkPspell *gtkpspell)
2014 if (!gtkpspell->popup_config_menu)
2015 gtkpspell->popup_config_menu = gtk_menu_new();
2017 debug_print("Pspell: creating/using popup_config_menu %0x\n",
2018 (guint) gtkpspell->popup_config_menu);
2019 populate_submenu(gtkpspell, gtkpspell->popup_config_menu);
2021 return GTK_MENU(gtkpspell->popup_config_menu);
2024 void gtkpspell_populate_submenu(GtkPspell *gtkpspell, GtkWidget *menuitem)
2028 menu = GTK_WIDGET(GTK_MENU_ITEM(menuitem)->submenu);
2030 debug_print("Pspell: using config menu %0x\n",
2031 (guint) gtkpspell->popup_config_menu);
2032 populate_submenu(gtkpspell, menu);
2034 gtkpspell->config_menu = menu;
2038 static void set_menu_pos(GtkMenu *menu, gint *x, gint *y, gpointer data)
2040 GtkPspell *gtkpspell = (GtkPspell *) data;
2041 gint xx = 0, yy = 0;
2044 GtkSText *text = GTK_STEXT(gtkpspell->gtktext);
2047 gdk_window_get_origin(GTK_WIDGET(gtkpspell->gtktext)->window, &xx, &yy);
2049 sx = gdk_screen_width();
2050 sy = gdk_screen_height();
2052 gtk_widget_get_child_requisition(GTK_WIDGET(menu), &r);
2057 *x = gtkpspell->gtktext->cursor_pos_x + xx +
2058 gdk_char_width(GTK_WIDGET(text)->style->font, ' ');
2059 *y = gtkpspell->gtktext->cursor_pos_y + yy;
2065 gdk_string_height((GTK_WIDGET(gtkpspell->gtktext))->style->font,
2066 gtkpspell->theword);
2070 /* Menu call backs */
2072 static gboolean cancel_menu_cb(GtkMenuShell *w, gpointer data)
2074 GtkPspell *gtkpspell = (GtkPspell *) data;
2076 gtkpspell->continue_check = NULL;
2077 set_point_continue(gtkpspell);
2083 /* change_dict_cb() - Menu callback : change dict */
2084 static void change_dict_cb(GtkWidget *w, GtkPspell *gtkpspell)
2088 GtkPspeller *gtkpspeller;
2091 fullname = (gchar *) gtk_object_get_data(GTK_OBJECT(w), "dict_name");
2093 if (!strcmp2(fullname, _("None")))
2096 sug_mode = gtkpspell->default_sug_mode;
2098 dict = g_new0(Dictionary, 1);
2099 dict->fullname = g_strdup(fullname);
2100 dict->encoding = g_strdup(gtkpspell->gtkpspeller->dictionary->encoding);
2102 if (gtkpspell->use_alternate && gtkpspell->alternate_speller &&
2103 dict == gtkpspell->alternate_speller->dictionary) {
2104 use_alternate_dict(gtkpspell);
2105 dictionary_delete(dict);
2109 gtkpspeller = gtkpspeller_new(dict);
2113 message = g_strdup_printf(_("The spell checker could not change dictionary.\n%s"),
2114 gtkpspellcheckers->error_message);
2116 gtkpspell_alert_dialog(message);
2119 if (gtkpspell->use_alternate) {
2120 if (gtkpspell->alternate_speller)
2121 gtkpspeller_delete(gtkpspell->alternate_speller);
2122 gtkpspell->alternate_speller = gtkpspell->gtkpspeller;
2124 gtkpspeller_delete(gtkpspell->gtkpspeller);
2126 gtkpspell->gtkpspeller = gtkpspeller;
2127 gtkpspell_set_sug_mode(gtkpspell, sug_mode);
2130 dictionary_delete(dict);
2132 if (gtkpspell->config_menu)
2133 populate_submenu(gtkpspell, gtkpspell->config_menu);
2136 static void switch_to_alternate_cb(GtkWidget *w,
2139 GtkPspell *gtkpspell = (GtkPspell *) data;
2140 use_alternate_dict(gtkpspell);
2143 /* Misc. helper functions */
2145 static void set_point_continue(GtkPspell *gtkpspell)
2149 gtktext = gtkpspell->gtktext;
2151 gtk_stext_freeze(gtktext);
2152 gtk_editable_set_position(GTK_EDITABLE(gtktext),gtkpspell->orig_pos);
2153 gtk_stext_set_point(gtktext, gtkpspell->orig_pos);
2154 gtk_stext_thaw(gtktext);
2156 if (gtkpspell->continue_check)
2157 gtkpspell->continue_check((gpointer *) gtkpspell);
2160 static void allocate_color(GtkPspell *gtkpspell, gint rgbvalue)
2163 GdkColor *color = &(gtkpspell->highlight);
2165 gc = gtk_widget_get_colormap(GTK_WIDGET(gtkpspell->gtktext));
2167 if (gtkpspell->highlight.pixel)
2168 gdk_colormap_free_colors(gc, &(gtkpspell->highlight), 1);
2170 /* Shameless copy from Sylpheed's gtkutils.c */
2172 color->red = (int) (((gdouble)((rgbvalue & 0xff0000) >> 16) / 255.0)
2174 color->green = (int) (((gdouble)((rgbvalue & 0x00ff00) >> 8) / 255.0)
2176 color->blue = (int) (((gdouble) (rgbvalue & 0x0000ff) / 255.0)
2179 gdk_colormap_alloc_color(gc, &(gtkpspell->highlight), FALSE, TRUE);
2182 static void change_color(GtkPspell * gtkpspell,
2183 gint start, gint end,
2189 g_return_if_fail(start < end);
2191 gtktext = gtkpspell->gtktext;
2193 gtk_stext_freeze(gtktext);
2195 gtk_stext_set_point(gtktext, start);
2196 gtk_stext_forward_delete(gtktext, end - start);
2197 gtk_stext_insert(gtktext, NULL, color, NULL, newtext,
2200 gtk_stext_thaw(gtktext);
2203 /* convert_to_pspell_encoding () - converts ISO-8859-* strings to iso8859-*
2204 * as needed by pspell. Returns an allocated string.
2207 static guchar *convert_to_pspell_encoding (const guchar *encoding)
2209 guchar * pspell_encoding;
2211 if (strstr2(encoding, "ISO-8859-")) {
2212 pspell_encoding = g_strdup_printf("iso8859%s", encoding + 8);
2215 if (!strcmp2(encoding, "US-ASCII"))
2216 pspell_encoding = g_strdup("iso8859-1");
2218 pspell_encoding = g_strdup(encoding);
2221 return pspell_encoding;
2224 /* compare_dict () - compare 2 dict names */
2225 static gint compare_dict(Dictionary *a, Dictionary *b)
2227 guint aparts = 0, bparts = 0;
2230 for (i=0; i < strlen(a->dictname); i++)
2231 if (a->dictname[i] == '-')
2233 for (i=0; i < strlen(b->dictname); i++)
2234 if (b->dictname[i] == '-')
2237 if (aparts != bparts)
2238 return (aparts < bparts) ? -1 : +1;
2241 compare = strcmp2(a->dictname, b->dictname);
2243 compare = strcmp2(a->fullname, b->fullname);
2249 static void dictionary_delete(Dictionary *dict)
2251 g_free(dict->fullname);
2252 g_free(dict->encoding);
2256 static Dictionary *dictionary_dup(const Dictionary *dict)
2260 dict2 = g_new(Dictionary, 1);
2262 dict2->fullname = g_strdup(dict->fullname);
2263 dict2->dictname = dict->dictname - dict->fullname + dict2->fullname;
2264 dict2->encoding = g_strdup(dict->encoding);
2269 static void free_suggestions_list(GtkPspell *gtkpspell)
2273 for (list = gtkpspell->suggestions_list; list != NULL;
2279 gtkpspell->max_sug = -1;
2280 gtkpspell->suggestions_list = NULL;
2283 static void reset_theword_data(GtkPspell *gtkpspell)
2285 gtkpspell->start_pos = 0;
2286 gtkpspell->end_pos = 0;
2287 gtkpspell->theword[0] = 0;
2288 gtkpspell->max_sug = -1;
2290 free_suggestions_list(gtkpspell);
2293 static void free_checkers(gpointer elt, gpointer data)
2295 GtkPspeller *gtkpspeller = elt;
2297 g_return_if_fail(gtkpspeller);
2299 gtkpspeller_real_delete(gtkpspeller);
2302 static gint find_gtkpspeller(gconstpointer aa, gconstpointer bb)
2304 Dictionary *a = ((GtkPspeller *) aa)->dictionary;
2305 Dictionary *b = ((GtkPspeller *) bb)->dictionary;
2307 if (a && b && a->fullname && b->fullname &&
2308 strcmp(a->fullname, b->fullname) == 0 &&
2309 a->encoding && b->encoding)
2310 return strcmp(a->encoding, b->encoding);
2315 static void gtkpspell_alert_dialog(gchar *message)
2320 GtkWidget *ok_button;
2322 dialog = gtk_dialog_new();
2323 gtk_window_set_policy(GTK_WINDOW(dialog), FALSE, FALSE, FALSE);
2324 gtk_window_set_position(GTK_WINDOW(dialog),GTK_WIN_POS_MOUSE);
2325 gtk_signal_connect_object(GTK_OBJECT(dialog), "destroy",
2326 GTK_SIGNAL_FUNC(gtk_widget_destroy),
2327 GTK_OBJECT(dialog));
2329 label = gtk_label_new(message);
2330 gtk_misc_set_padding(GTK_MISC(label), 8, 8);
2332 gtk_container_add(GTK_CONTAINER(GTK_DIALOG(dialog)->vbox), label);
2334 hbox = gtk_hbox_new(FALSE, 0);
2336 ok_button = gtk_button_new_with_label(_("OK"));
2337 GTK_WIDGET_SET_FLAGS(ok_button, GTK_CAN_DEFAULT);
2338 gtk_box_pack_start(GTK_BOX(hbox), ok_button, TRUE, TRUE, 8);
2340 gtk_signal_connect_object(GTK_OBJECT(ok_button), "clicked",
2341 GTK_SIGNAL_FUNC(gtk_widget_destroy),
2342 GTK_OBJECT(dialog));
2343 gtk_container_add(GTK_CONTAINER(GTK_DIALOG(dialog)->action_area), hbox);
2345 gtk_widget_grab_default(ok_button);
2346 gtk_widget_grab_focus(ok_button);
2347 gtk_window_set_modal(GTK_WINDOW(dialog), TRUE);
2349 gtk_widget_show_all(dialog);