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 gtk_stext_freeze(gtktext);
1108 origpos = gtk_editable_get_position(GTK_EDITABLE(gtktext));
1110 /* gtk_editable_set_position(GTK_EDITABLE(gtktext), 0);*/
1114 iswordsep(get_text_index_whar(gtkpspell, pos)))
1117 !iswordsep(get_text_index_whar(gtkpspell, pos)))
1120 check_at(gtkpspell, pos - 1);
1122 gtk_stext_thaw(gtktext);
1123 gtk_editable_set_position(GTK_EDITABLE(gtktext), origpos);
1124 gtk_stext_set_point(GTK_STEXT(gtktext), origpos);
1125 gtk_adjustment_set_value(gtktext->vadj, adj_value);
1126 /* gtk_editable_select_region(GTK_EDITABLE(gtktext), origpos, origpos);*/
1129 static void replace_with_supplied_word_cb(GtkWidget *w, GtkPspell *gtkpspell)
1131 unsigned char *newword;
1132 GdkEvent *e= (GdkEvent *) gtk_get_current_event();
1134 newword = gtk_editable_get_chars(GTK_EDITABLE(gtkpspell->replace_entry),
1137 if (strcmp(newword, gtkpspell->theword)) {
1138 replace_real_word(gtkpspell, newword);
1140 if ((e->type == GDK_KEY_PRESS &&
1141 ((GdkEventKey *) e)->state & GDK_MOD1_MASK)) {
1142 pspell_manager_store_replacement(gtkpspell->gtkpspeller->checker,
1143 gtkpspell->theword, -1,
1146 gtkpspell->replace_entry = NULL;
1151 set_point_continue(gtkpspell);
1155 static void replace_word_cb(GtkWidget *w, gpointer data)
1157 unsigned char *newword;
1158 GtkPspell *gtkpspell = (GtkPspell *) data;
1159 GdkEvent *e= (GdkEvent *) gtk_get_current_event();
1161 gtk_label_get(GTK_LABEL(GTK_BIN(w)->child), (gchar**) &newword);
1163 replace_real_word(gtkpspell, newword);
1165 if ((e->type == GDK_KEY_PRESS &&
1166 ((GdkEventKey *) e)->state & GDK_MOD1_MASK) ||
1167 (e->type == GDK_BUTTON_RELEASE &&
1168 ((GdkEventButton *) e)->state & GDK_MOD1_MASK)) {
1169 pspell_manager_store_replacement(gtkpspell->gtkpspeller->checker,
1170 gtkpspell->theword, -1,
1174 gtk_menu_shell_deactivate(GTK_MENU_SHELL(w->parent));
1176 set_point_continue(gtkpspell);
1179 static void replace_real_word(GtkPspell *gtkpspell, gchar *newword)
1181 int oldlen, newlen, wordlen;
1184 gint start = gtkpspell->start_pos;
1187 if (!newword) return;
1189 gtktext = gtkpspell->gtktext;
1191 gtk_stext_freeze(GTK_STEXT(gtktext));
1192 origpos = gtkpspell->orig_pos;
1194 oldlen = gtkpspell->end_pos - gtkpspell->start_pos;
1195 wordlen = strlen(gtkpspell->theword);
1197 newlen = strlen(newword); /* FIXME: multybyte characters? */
1199 gtk_signal_handler_block_by_func(GTK_OBJECT(gtktext),
1200 GTK_SIGNAL_FUNC(entry_insert_cb),
1202 gtk_signal_handler_block_by_func(GTK_OBJECT(gtktext),
1203 GTK_SIGNAL_FUNC(entry_delete_cb),
1206 gtk_signal_emit_by_name(GTK_OBJECT(gtktext), "delete-text",
1207 gtkpspell->start_pos, gtkpspell->end_pos);
1208 gtk_signal_emit_by_name(GTK_OBJECT(gtktext), "insert-text",
1209 newword, newlen, &start);
1211 gtk_signal_handler_unblock_by_func(GTK_OBJECT(gtktext),
1212 GTK_SIGNAL_FUNC(entry_insert_cb),
1214 gtk_signal_handler_unblock_by_func(GTK_OBJECT(gtktext),
1215 GTK_SIGNAL_FUNC(entry_delete_cb),
1218 /* Put the point and the position where we clicked with the mouse
1219 * It seems to be a hack, as I must thaw,freeze,thaw the widget
1220 * to let it update correctly the word insertion and then the
1221 * point & position position. If not, SEGV after the first replacement
1222 * If the new word ends before point, put the point at its end.
1225 if (origpos - gtkpspell->start_pos < oldlen &&
1226 origpos - gtkpspell->start_pos >= 0) {
1227 /* Original point was in the word.
1228 * Let it there unless point is going to be outside of the word
1230 if (origpos - gtkpspell->start_pos >= newlen) {
1231 pos = gtkpspell->start_pos + newlen;
1234 else if (origpos >= gtkpspell->end_pos) {
1235 /* move the position according to the change of length */
1236 pos = origpos + newlen - oldlen;
1239 gtkpspell->end_pos = gtkpspell->start_pos + strlen(newword); /* FIXME: multibyte characters? */
1241 gtk_stext_thaw(GTK_STEXT(gtktext));
1242 gtk_stext_freeze(GTK_STEXT(gtktext));
1244 if (GTK_STEXT(gtktext)->text_len < pos)
1245 pos = gtk_stext_get_length(GTK_STEXT(gtktext));
1247 gtkpspell->orig_pos = pos;
1249 gtk_editable_set_position(GTK_EDITABLE(gtktext), gtkpspell->orig_pos);
1250 gtk_stext_set_point(GTK_STEXT(gtktext),
1251 gtk_editable_get_position(GTK_EDITABLE(gtktext)));
1253 gtk_stext_thaw(GTK_STEXT(gtktext));
1256 /* Accept this word for this session */
1257 static void add_word_to_session_cb(GtkWidget *w, gpointer data)
1261 GtkPspell *gtkpspell = (GtkPspell *) data;
1262 gtktext = gtkpspell->gtktext;
1264 gtk_stext_freeze(GTK_STEXT(gtktext));
1266 pos = gtk_editable_get_position(GTK_EDITABLE(gtktext));
1268 pspell_manager_add_to_session(gtkpspell->gtkpspeller->checker,
1270 strlen(gtkpspell->theword));
1272 check_at(gtkpspell, gtkpspell->start_pos);
1274 gtk_stext_thaw(gtkpspell->gtktext);
1276 gtk_menu_shell_deactivate(GTK_MENU_SHELL(GTK_WIDGET(w)->parent));
1278 set_point_continue(gtkpspell);
1281 /* add_word_to_personal_cb() - add word to personal dict. */
1282 static void add_word_to_personal_cb(GtkWidget *w, gpointer data)
1284 GtkPspell *gtkpspell = (GtkPspell *) data;
1285 GtkSText *gtktext = gtkpspell->gtktext;
1287 gtk_stext_freeze(GTK_STEXT(gtktext));
1289 pspell_manager_add_to_personal(gtkpspell->gtkpspeller->checker,
1291 strlen(gtkpspell->theword));
1293 check_at(gtkpspell, gtkpspell->start_pos);
1295 gtk_stext_thaw(gtkpspell->gtktext);
1297 gtk_menu_shell_deactivate(GTK_MENU_SHELL(GTK_WIDGET(w)->parent));
1298 set_point_continue(gtkpspell);
1301 static void check_with_alternate_cb(GtkWidget *w, gpointer data)
1303 GtkPspell *gtkpspell = (GtkPspell *) data;
1306 gtk_menu_shell_deactivate(GTK_MENU_SHELL(GTK_WIDGET(w)->parent));
1308 use_alternate_dict(gtkpspell);
1309 misspelled = check_at(gtkpspell, gtkpspell->start_pos);
1311 if (!gtkpspell->continue_check) {
1313 gtkpspell->misspelled = misspelled;
1315 if (gtkpspell->misspelled) {
1317 misspelled_suggest(gtkpspell, gtkpspell->theword);
1319 gtk_stext_set_point(GTK_STEXT(gtkpspell->gtktext),
1320 gtkpspell->end_pos);
1321 gtk_editable_set_position(GTK_EDITABLE(gtkpspell->gtktext),
1322 gtkpspell->end_pos);
1324 gtk_menu_popup(make_sug_menu(gtkpspell), NULL, NULL,
1325 set_menu_pos, gtkpspell, 0,
1330 gtkpspell->orig_pos = gtkpspell->start_pos;
1332 set_point_continue(gtkpspell);
1335 static void replace_with_create_dialog_cb(GtkWidget *w, gpointer data)
1341 GtkWidget *ok_button;
1342 GtkWidget *cancel_button;
1345 GtkPspell *gtkpspell = (GtkPspell *) data;
1347 gdk_window_get_origin((GTK_WIDGET(w)->parent)->window, &xx, &yy);
1349 gtk_menu_shell_deactivate(GTK_MENU_SHELL(GTK_WIDGET(w)->parent));
1351 dialog = gtk_dialog_new();
1353 gtk_window_set_policy(GTK_WINDOW(dialog), FALSE, FALSE, FALSE);
1354 gtk_window_set_title(GTK_WINDOW(dialog),_("Replace unknown word"));
1355 gtk_widget_set_uposition(dialog, xx, yy);
1357 gtk_signal_connect_object(GTK_OBJECT(dialog), "destroy",
1358 GTK_SIGNAL_FUNC(gtk_widget_destroy),
1359 GTK_OBJECT(dialog));
1361 hbox = gtk_hbox_new(FALSE, 0);
1362 gtk_container_set_border_width(GTK_CONTAINER(hbox), 8);
1364 thelabel = g_strdup_printf(_("Replace \"%s\" with: "),
1365 gtkpspell->theword);
1366 label = gtk_label_new(thelabel);
1368 gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0);
1370 entry = gtk_entry_new();
1371 gtkpspell->replace_entry = entry;
1372 gtk_entry_set_text(GTK_ENTRY(entry), gtkpspell->theword);
1373 gtk_editable_select_region(GTK_EDITABLE(entry), 0, -1);
1374 gtk_signal_connect(GTK_OBJECT(entry), "activate",
1375 GTK_SIGNAL_FUNC(replace_with_supplied_word_cb),
1377 gtk_signal_connect_object(GTK_OBJECT(entry), "activate",
1378 GTK_SIGNAL_FUNC(gtk_widget_destroy),
1379 GTK_OBJECT(dialog));
1380 gtk_box_pack_start(GTK_BOX(hbox), entry, TRUE, TRUE, 0);
1382 gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog)->vbox), hbox, TRUE,
1384 if (!gtkpspell->gtkpspeller->ispell) {
1385 label = gtk_label_new(_("Holding down MOD1 key while pressing "
1386 "Enter\nwill learn from mistake.\n"));
1387 gtk_label_set_justify(GTK_LABEL(label), GTK_JUSTIFY_LEFT);
1388 gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.0);
1389 gtk_misc_set_padding(GTK_MISC(label), 8, 0);
1390 gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog)->vbox), label,
1394 hbox = gtk_hbox_new(TRUE, 0);
1396 ok_button = gtk_button_new_with_label(_("OK"));
1397 gtk_box_pack_start(GTK_BOX(hbox), ok_button, TRUE, TRUE, 8);
1398 gtk_signal_connect(GTK_OBJECT(ok_button), "clicked",
1399 GTK_SIGNAL_FUNC(replace_with_supplied_word_cb),
1401 gtk_signal_connect_object(GTK_OBJECT(ok_button), "clicked",
1402 GTK_SIGNAL_FUNC(gtk_widget_destroy),
1403 GTK_OBJECT(dialog));
1405 cancel_button = gtk_button_new_with_label(_("Cancel"));
1406 gtk_box_pack_start(GTK_BOX(hbox), cancel_button, TRUE, TRUE, 8);
1407 gtk_signal_connect_object(GTK_OBJECT(cancel_button), "clicked",
1408 GTK_SIGNAL_FUNC(gtk_widget_destroy),
1409 GTK_OBJECT(dialog));
1411 gtk_container_add(GTK_CONTAINER(GTK_DIALOG(dialog)->action_area), hbox);
1413 gtk_widget_grab_focus(entry);
1415 gtk_window_set_modal(GTK_WINDOW(dialog), TRUE);
1417 gtk_widget_show_all(dialog);
1420 void gtkpspell_uncheck_all(GtkPspell * gtkpspell)
1427 gtktext = gtkpspell->gtktext;
1429 adj_value = gtktext->vadj->value;
1431 gtk_stext_freeze(gtktext);
1433 origpos = gtk_editable_get_position(GTK_EDITABLE(gtktext));
1435 text = gtk_editable_get_chars(GTK_EDITABLE(gtktext), 0, -1);
1437 gtk_stext_set_point(gtktext, 0);
1438 gtk_stext_forward_delete(gtktext, gtk_stext_get_length(gtktext));
1439 gtk_stext_insert(gtktext, NULL, NULL, NULL, text, strlen(text));
1441 gtk_stext_thaw(gtktext);
1443 gtk_editable_set_position(GTK_EDITABLE(gtktext), origpos);
1444 gtk_stext_set_point(gtktext, origpos);
1445 gtk_adjustment_set_value(gtktext->vadj, adj_value);
1451 static void toggle_check_while_typing_cb(GtkWidget *w, gpointer data)
1453 GtkPspell *gtkpspell = (GtkPspell *) data;
1455 gtkpspell->check_while_typing = gtkpspell->check_while_typing == FALSE;
1457 if (!gtkpspell->check_while_typing)
1458 gtkpspell_uncheck_all(gtkpspell);
1460 if (gtkpspell->config_menu)
1461 populate_submenu(gtkpspell, gtkpspell->config_menu);
1464 static GSList *create_empty_dictionary_list(void)
1466 GSList *list = NULL;
1469 dict = g_new0(Dictionary, 1);
1470 dict->fullname = g_strdup(_("None"));
1471 dict->dictname = dict->fullname;
1472 dict->encoding = NULL;
1474 return g_slist_append(list, dict);
1477 /* gtkpspell_get_dictionary_list() - returns list of dictionary names */
1478 GSList *gtkpspell_get_dictionary_list(const gchar *pspell_path, gint refresh)
1481 gchar *dict_path, *tmp, *prevdir;
1482 gchar tmpname[BUFSIZE];
1487 if (!gtkpspellcheckers)
1488 gtkpspellcheckers = gtkpspell_checkers_new();
1490 if (gtkpspellcheckers->dictionary_list && !refresh)
1491 return gtkpspellcheckers->dictionary_list;
1493 gtkpspell_free_dictionary_list(gtkpspellcheckers->dictionary_list);
1498 #warning TODO: no directory change
1500 dict_path = g_strdup(pspell_path);
1501 prevdir = g_get_current_dir();
1502 if (chdir(dict_path) <0) {
1503 debug_print(_("Pspell: error when searching for dictionaries:\n%s\n"),
1507 gtkpspellcheckers->dictionary_list =
1508 create_empty_dictionary_list();
1510 return gtkpspellcheckers->dictionary_list;
1513 debug_print(_("Pspell: checking for dictionaries in %s\n"), dict_path);
1515 if (NULL != (dir = opendir("."))) {
1516 while (NULL != (ent = readdir(dir))) {
1517 /* search for pwli */
1518 if ((NULL != (tmp = strstr2(ent->d_name, ".pwli"))) &&
1520 g_snprintf(tmpname, BUFSIZE, "%s%s",
1521 G_DIR_SEPARATOR_S, ent->d_name);
1522 tmpname[MIN(tmp - ent->d_name + 1, BUFSIZE-1)] =
1524 dict = g_new0(Dictionary, 1);
1525 dict->fullname = g_strdup_printf("%s%s",
1528 dict->dictname = strrchr(dict->fullname,
1529 G_DIR_SEPARATOR) + 1;
1530 dict->encoding = NULL;
1531 debug_print(_("Pspell: found dictionary %s %s\n"),
1532 dict->fullname, dict->dictname);
1533 list = g_slist_insert_sorted(list, dict,
1534 (GCompareFunc) compare_dict);
1540 debug_print(_("Pspell: error when searching for dictionaries.\nNo dictionary found.\n(%s)"),
1542 list = create_empty_dictionary_list();
1546 debug_print(_("Pspell: error when searching for dictionaries.\nNo dictionary found.\n"));
1547 list = create_empty_dictionary_list();
1553 gtkpspellcheckers->dictionary_list = list;
1558 void gtkpspell_free_dictionary_list(GSList *list)
1562 for (walk = list; walk != NULL; walk = g_slist_next(walk))
1564 dict = (Dictionary *) walk->data;
1565 dictionary_delete(dict);
1570 GtkWidget *gtkpspell_dictionary_option_menu_new(const gchar *pspell_path)
1572 GSList *dict_list, *tmp;
1577 dict_list = gtkpspell_get_dictionary_list(pspell_path, TRUE);
1578 g_return_val_if_fail(dict_list, NULL);
1580 menu = gtk_menu_new();
1582 for (tmp = dict_list; tmp != NULL; tmp = g_slist_next(tmp)) {
1583 dict = (Dictionary *) tmp->data;
1584 item = gtk_menu_item_new_with_label(dict->dictname);
1585 gtk_object_set_data(GTK_OBJECT(item), "dict_name",
1588 gtk_menu_append(GTK_MENU(menu), item);
1589 gtk_widget_show(item);
1592 gtk_widget_show(menu);
1597 gchar *gtkpspell_get_dictionary_menu_active_item(GtkWidget *menu)
1599 GtkWidget *menuitem;
1600 gchar *dict_fullname;
1603 g_return_val_if_fail(GTK_IS_MENU(menu), NULL);
1605 menuitem = gtk_menu_get_active(GTK_MENU(menu));
1606 dict_fullname = (gchar *) gtk_object_get_data(GTK_OBJECT(menuitem),
1608 g_return_val_if_fail(dict_fullname, NULL);
1610 label = g_strdup(dict_fullname);
1616 GtkWidget *gtkpspell_sugmode_option_menu_new(gint sugmode)
1621 menu = gtk_menu_new();
1622 gtk_widget_show(menu);
1624 item = gtk_menu_item_new_with_label(_("Fast Mode"));
1625 gtk_widget_show(item);
1626 gtk_menu_append(GTK_MENU(menu), item);
1627 gtk_object_set_data(GTK_OBJECT(item), "sugmode",
1628 GINT_TO_POINTER(PSPELL_FASTMODE));
1630 item = gtk_menu_item_new_with_label(_("Normal Mode"));
1631 gtk_widget_show(item);
1632 gtk_menu_append(GTK_MENU(menu), item);
1633 gtk_object_set_data(GTK_OBJECT(item), "sugmode",
1634 GINT_TO_POINTER(PSPELL_NORMALMODE));
1636 item = gtk_menu_item_new_with_label(_("Bad Spellers Mode"));
1637 gtk_widget_show(item);
1638 gtk_menu_append(GTK_MENU(menu), item);
1639 gtk_object_set_data(GTK_OBJECT(item), "sugmode",
1640 GINT_TO_POINTER(PSPELL_BADSPELLERMODE));
1645 void gtkpspell_sugmode_option_menu_set(GtkOptionMenu *optmenu, gint sugmode)
1647 g_return_if_fail(GTK_IS_OPTION_MENU(optmenu));
1649 g_return_if_fail(sugmode == PSPELL_FASTMODE ||
1650 sugmode == PSPELL_NORMALMODE ||
1651 sugmode == PSPELL_BADSPELLERMODE);
1653 gtk_option_menu_set_history(GTK_OPTION_MENU(optmenu), sugmode - 1);
1656 gint gtkpspell_get_sugmode_from_option_menu(GtkOptionMenu *optmenu)
1661 g_return_val_if_fail(GTK_IS_OPTION_MENU(optmenu), -1);
1663 item = gtk_menu_get_active(GTK_MENU(gtk_option_menu_get_menu(optmenu)));
1665 sugmode = GPOINTER_TO_INT(gtk_object_get_data(GTK_OBJECT(item),
1671 static void use_alternate_dict(GtkPspell *gtkpspell)
1675 tmp = gtkpspell->gtkpspeller;
1676 gtkpspell->gtkpspeller = gtkpspell->alternate_speller;
1677 gtkpspell->alternate_speller = tmp;
1679 if (gtkpspell->config_menu)
1680 populate_submenu(gtkpspell, gtkpspell->config_menu);
1683 static void popup_menu(GtkPspell *gtkpspell, GdkEventButton *eb)
1687 gtktext = gtkpspell->gtktext;
1688 gtkpspell->orig_pos = gtk_editable_get_position(GTK_EDITABLE(gtktext));
1690 if (!(eb->state & GDK_SHIFT_MASK)) {
1691 if (check_at(gtkpspell, gtkpspell->orig_pos)) {
1693 gtk_editable_set_position(GTK_EDITABLE(gtktext),
1694 gtkpspell->orig_pos);
1695 gtk_stext_set_point(gtktext, gtkpspell->orig_pos);
1697 if (misspelled_suggest(gtkpspell, gtkpspell->theword)) {
1698 gtk_menu_popup(make_sug_menu(gtkpspell),
1699 NULL, NULL, NULL, NULL,
1700 eb->button, GDK_CURRENT_TIME);
1705 gtk_editable_set_position(GTK_EDITABLE(gtktext),
1706 gtkpspell->orig_pos);
1707 gtk_stext_set_point(gtktext, gtkpspell->orig_pos);
1711 gtk_menu_popup(make_config_menu(gtkpspell), NULL, NULL, NULL, NULL,
1712 eb->button, GDK_CURRENT_TIME);
1715 /* make_sug_menu() - Add menus to accept this word for this session
1716 * and to add it to personal dictionary
1718 static GtkMenu *make_sug_menu(GtkPspell *gtkpspell)
1720 GtkWidget *menu, *item;
1721 unsigned char *caption;
1723 GtkAccelGroup *accel;
1724 GList *l = gtkpspell->suggestions_list;
1726 gtktext = gtkpspell->gtktext;
1728 accel = gtk_accel_group_new();
1729 menu = gtk_menu_new();
1731 if (gtkpspell->sug_menu)
1732 gtk_widget_destroy(gtkpspell->sug_menu);
1734 gtkpspell->sug_menu = menu;
1736 gtk_signal_connect(GTK_OBJECT(menu), "cancel",
1737 GTK_SIGNAL_FUNC(cancel_menu_cb), gtkpspell);
1739 caption = g_strdup_printf(_("\"%s\" unknown in %s"),
1740 (unsigned char*) l->data,
1741 gtkpspell->gtkpspeller->dictionary->dictname);
1742 item = gtk_menu_item_new_with_label(caption);
1743 gtk_widget_show(item);
1744 gtk_menu_append(GTK_MENU(menu), item);
1745 gtk_misc_set_alignment(GTK_MISC(GTK_BIN(item)->child), 0.5, 0.5);
1748 item = gtk_menu_item_new();
1749 gtk_widget_show(item);
1750 gtk_menu_append(GTK_MENU(menu), item);
1752 item = gtk_menu_item_new_with_label(_("Accept in this session"));
1753 gtk_widget_show(item);
1754 gtk_menu_append(GTK_MENU(menu), item);
1755 gtk_signal_connect(GTK_OBJECT(item), "activate",
1756 GTK_SIGNAL_FUNC(add_word_to_session_cb),
1758 gtk_widget_add_accelerator(item, "activate", accel, GDK_space,
1760 GTK_ACCEL_LOCKED | GTK_ACCEL_VISIBLE);
1762 item = gtk_menu_item_new_with_label(_("Add to personal dictionary"));
1763 gtk_widget_show(item);
1764 gtk_menu_append(GTK_MENU(menu), item);
1765 gtk_signal_connect(GTK_OBJECT(item), "activate",
1766 GTK_SIGNAL_FUNC(add_word_to_personal_cb),
1768 gtk_widget_add_accelerator(item, "activate", accel, GDK_Return,
1770 GTK_ACCEL_LOCKED | GTK_ACCEL_VISIBLE);
1772 item = gtk_menu_item_new_with_label(_("Replace with..."));
1773 gtk_widget_show(item);
1774 gtk_menu_append(GTK_MENU(menu), item);
1775 gtk_signal_connect(GTK_OBJECT(item), "activate",
1776 GTK_SIGNAL_FUNC(replace_with_create_dialog_cb),
1778 gtk_widget_add_accelerator(item, "activate", accel, GDK_R, 0,
1779 GTK_ACCEL_LOCKED | GTK_ACCEL_VISIBLE);
1781 if (gtkpspell->use_alternate && gtkpspell->alternate_speller) {
1782 caption = g_strdup_printf(_("Check with %s"),
1783 gtkpspell->alternate_speller->dictionary->dictname);
1784 item = gtk_menu_item_new_with_label(caption);
1786 gtk_widget_show(item);
1787 gtk_menu_append(GTK_MENU(menu), item);
1788 gtk_signal_connect(GTK_OBJECT(item), "activate",
1789 GTK_SIGNAL_FUNC(check_with_alternate_cb),
1791 gtk_widget_add_accelerator(item, "activate", accel, GDK_X, 0,
1792 GTK_ACCEL_LOCKED | GTK_ACCEL_VISIBLE);
1795 item = gtk_menu_item_new();
1796 gtk_widget_show(item);
1797 gtk_menu_append(GTK_MENU(menu), item);
1801 item = gtk_menu_item_new_with_label(_("(no suggestions)"));
1802 gtk_widget_show(item);
1803 gtk_menu_append(GTK_MENU(menu), item);
1805 GtkWidget *curmenu = menu;
1809 if (l->data == NULL && l->next != NULL) {
1811 curmenu = gtk_menu_new();
1812 item = gtk_menu_item_new_with_label(_("Others..."));
1813 gtk_widget_show(item);
1814 gtk_menu_append(GTK_MENU(curmenu), item);
1815 gtk_menu_item_set_submenu(GTK_MENU_ITEM(item),
1819 } else if (count > MENUCOUNT) {
1822 item = gtk_menu_item_new_with_label(_("More..."));
1823 gtk_widget_show(item);
1824 gtk_menu_append(GTK_MENU(curmenu), item);
1826 curmenu = gtk_menu_new();
1827 gtk_menu_item_set_submenu(GTK_MENU_ITEM(item),
1831 item = gtk_menu_item_new_with_label((unsigned char*)l->data);
1832 gtk_widget_show(item);
1833 gtk_menu_append(GTK_MENU(curmenu), item);
1834 gtk_signal_connect(GTK_OBJECT(item), "activate",
1835 GTK_SIGNAL_FUNC(replace_word_cb),
1838 if (curmenu == menu && count < MENUCOUNT) {
1839 gtk_widget_add_accelerator(item, "activate",
1844 gtk_widget_add_accelerator(item, "activate",
1853 } while ((l = l->next) != NULL);
1856 gtk_accel_group_attach(accel, GTK_OBJECT(menu));
1857 gtk_accel_group_unref(accel);
1859 return GTK_MENU(menu);
1862 static void populate_submenu(GtkPspell *gtkpspell, GtkWidget *menu)
1864 GtkWidget *item, *submenu;
1866 GtkPspeller *gtkpspeller = gtkpspell->gtkpspeller;
1867 gint ispell = gtkpspeller->ispell;
1869 if (GTK_MENU_SHELL(menu)->children) {
1870 GList *amenu, *alist;
1871 for (amenu = (GTK_MENU_SHELL(menu)->children); amenu; ) {
1872 alist = amenu->next;
1873 gtk_widget_destroy(GTK_WIDGET(amenu->data));
1878 dictname = g_strdup_printf(_("Dictionary: %s"),
1879 gtkpspeller->dictionary->dictname);
1880 item = gtk_menu_item_new_with_label(dictname);
1881 gtk_misc_set_alignment(GTK_MISC(GTK_BIN(item)->child), 0.5, 0.5);
1883 gtk_widget_show(item);
1884 gtk_menu_append(GTK_MENU(menu), item);
1886 item = gtk_menu_item_new();
1887 gtk_widget_show(item);
1888 gtk_menu_append(GTK_MENU(menu), item);
1890 if (gtkpspell->use_alternate && gtkpspell->alternate_speller) {
1891 dictname = g_strdup_printf(_("Use alternate (%s)"),
1892 gtkpspell->alternate_speller->dictionary->dictname);
1893 item = gtk_menu_item_new_with_label(dictname);
1895 gtk_signal_connect(GTK_OBJECT(item), "activate",
1896 GTK_SIGNAL_FUNC(switch_to_alternate_cb),
1898 gtk_widget_show(item);
1899 gtk_menu_append(GTK_MENU(menu), item);
1900 item = gtk_menu_item_new();
1901 gtk_widget_show(item);
1902 gtk_menu_append(GTK_MENU(menu), item);
1905 item = gtk_check_menu_item_new_with_label(_("Fast Mode"));
1906 if (ispell || gtkpspell->gtkpspeller->sug_mode == PSPELL_FASTMODE)
1907 gtk_widget_set_sensitive(GTK_WIDGET(item),FALSE);
1908 if (!ispell && gtkpspell->gtkpspeller->sug_mode == PSPELL_FASTMODE)
1909 gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(item),TRUE);
1911 gtk_signal_connect(GTK_OBJECT(item), "activate",
1912 GTK_SIGNAL_FUNC(set_sug_mode_cb),
1914 gtk_widget_show(item);
1915 gtk_menu_append(GTK_MENU(menu), item);
1917 item = gtk_check_menu_item_new_with_label(_("Normal Mode"));
1918 if (ispell || gtkpspell->gtkpspeller->sug_mode == PSPELL_NORMALMODE)
1919 gtk_widget_set_sensitive(GTK_WIDGET(item), FALSE);
1920 if (!ispell && gtkpspell->gtkpspeller->sug_mode == PSPELL_NORMALMODE)
1921 gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(item), TRUE);
1923 gtk_signal_connect(GTK_OBJECT(item), "activate",
1924 GTK_SIGNAL_FUNC(set_sug_mode_cb),
1926 gtk_widget_show(item);
1927 gtk_menu_append(GTK_MENU(menu),item);
1929 item = gtk_check_menu_item_new_with_label(_("Bad Spellers Mode"));
1930 if (ispell || gtkpspell->gtkpspeller->sug_mode == PSPELL_BADSPELLERMODE)
1931 gtk_widget_set_sensitive(GTK_WIDGET(item), FALSE);
1932 if (!ispell && gtkpspell->gtkpspeller->sug_mode == PSPELL_BADSPELLERMODE)
1933 gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(item), TRUE);
1935 gtk_signal_connect(GTK_OBJECT(item), "activate",
1936 GTK_SIGNAL_FUNC(set_sug_mode_cb),
1938 gtk_widget_show(item);
1939 gtk_menu_append(GTK_MENU(menu), item);
1941 item = gtk_menu_item_new();
1942 gtk_widget_show(item);
1943 gtk_menu_append(GTK_MENU(menu), item);
1945 item = gtk_check_menu_item_new_with_label(_("Check while typing"));
1946 if (gtkpspell->check_while_typing)
1947 gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(item), TRUE);
1949 gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(item), FALSE);
1950 gtk_signal_connect(GTK_OBJECT(item), "activate",
1951 GTK_SIGNAL_FUNC(toggle_check_while_typing_cb),
1953 gtk_widget_show(item);
1954 gtk_menu_append(GTK_MENU(menu), item);
1956 item = gtk_menu_item_new();
1957 gtk_widget_show(item);
1958 gtk_menu_append(GTK_MENU(menu), item);
1960 submenu = gtk_menu_new();
1961 item = gtk_menu_item_new_with_label(_("Change dictionary"));
1962 gtk_menu_item_set_submenu(GTK_MENU_ITEM(item),submenu);
1963 gtk_widget_show(item);
1964 gtk_menu_append(GTK_MENU(menu), item);
1967 if (gtkpspellcheckers->dictionary_list == NULL)
1968 gtkpspell_get_dictionary_list(prefs_common.pspell_path, FALSE);
1970 GtkWidget * curmenu = submenu;
1974 tmp = gtkpspellcheckers->dictionary_list;
1976 for (tmp = gtkpspellcheckers->dictionary_list; tmp != NULL;
1977 tmp = g_slist_next(tmp)) {
1978 dict = (Dictionary *) tmp->data;
1979 item = gtk_check_menu_item_new_with_label(dict->dictname);
1980 gtk_object_set_data(GTK_OBJECT(item), "dict_name",
1982 if (strcmp2(dict->fullname,
1983 gtkpspell->gtkpspeller->dictionary->fullname))
1984 gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(item), FALSE);
1986 gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(item), TRUE);
1987 gtk_widget_set_sensitive(GTK_WIDGET(item),
1990 gtk_signal_connect(GTK_OBJECT(item), "activate",
1991 GTK_SIGNAL_FUNC(change_dict_cb),
1993 gtk_widget_show(item);
1994 gtk_menu_append(GTK_MENU(curmenu), item);
1998 if (count == MENUCOUNT) {
2001 newmenu = gtk_menu_new();
2002 item = gtk_menu_item_new_with_label(_("More..."));
2003 gtk_menu_item_set_submenu(GTK_MENU_ITEM(item),
2006 gtk_menu_append(GTK_MENU(curmenu), item);
2007 gtk_widget_show(item);
2015 static GtkMenu *make_config_menu(GtkPspell *gtkpspell)
2017 if (!gtkpspell->popup_config_menu)
2018 gtkpspell->popup_config_menu = gtk_menu_new();
2020 debug_print("Pspell: creating/using popup_config_menu %0x\n",
2021 (guint) gtkpspell->popup_config_menu);
2022 populate_submenu(gtkpspell, gtkpspell->popup_config_menu);
2024 return GTK_MENU(gtkpspell->popup_config_menu);
2027 void gtkpspell_populate_submenu(GtkPspell *gtkpspell, GtkWidget *menuitem)
2031 menu = GTK_WIDGET(GTK_MENU_ITEM(menuitem)->submenu);
2033 debug_print("Pspell: using config menu %0x\n",
2034 (guint) gtkpspell->popup_config_menu);
2035 populate_submenu(gtkpspell, menu);
2037 gtkpspell->config_menu = menu;
2041 static void set_menu_pos(GtkMenu *menu, gint *x, gint *y, gpointer data)
2043 GtkPspell *gtkpspell = (GtkPspell *) data;
2044 gint xx = 0, yy = 0;
2047 GtkSText *text = GTK_STEXT(gtkpspell->gtktext);
2050 gdk_window_get_origin(GTK_WIDGET(gtkpspell->gtktext)->window, &xx, &yy);
2052 sx = gdk_screen_width();
2053 sy = gdk_screen_height();
2055 gtk_widget_get_child_requisition(GTK_WIDGET(menu), &r);
2060 *x = gtkpspell->gtktext->cursor_pos_x + xx +
2061 gdk_char_width(GTK_WIDGET(text)->style->font, ' ');
2062 *y = gtkpspell->gtktext->cursor_pos_y + yy;
2068 gdk_string_height((GTK_WIDGET(gtkpspell->gtktext))->style->font,
2069 gtkpspell->theword);
2073 /* Menu call backs */
2075 static gboolean cancel_menu_cb(GtkMenuShell *w, gpointer data)
2077 GtkPspell *gtkpspell = (GtkPspell *) data;
2079 gtkpspell->continue_check = NULL;
2080 set_point_continue(gtkpspell);
2086 /* change_dict_cb() - Menu callback : change dict */
2087 static void change_dict_cb(GtkWidget *w, GtkPspell *gtkpspell)
2091 GtkPspeller *gtkpspeller;
2094 fullname = (gchar *) gtk_object_get_data(GTK_OBJECT(w), "dict_name");
2096 if (!strcmp2(fullname, _("None")))
2099 sug_mode = gtkpspell->default_sug_mode;
2101 dict = g_new0(Dictionary, 1);
2102 dict->fullname = g_strdup(fullname);
2103 dict->encoding = g_strdup(gtkpspell->gtkpspeller->dictionary->encoding);
2105 if (gtkpspell->use_alternate && gtkpspell->alternate_speller &&
2106 dict == gtkpspell->alternate_speller->dictionary) {
2107 use_alternate_dict(gtkpspell);
2108 dictionary_delete(dict);
2112 gtkpspeller = gtkpspeller_new(dict);
2116 message = g_strdup_printf(_("The spell checker could not change dictionary.\n%s"),
2117 gtkpspellcheckers->error_message);
2119 gtkpspell_alert_dialog(message);
2122 if (gtkpspell->use_alternate) {
2123 if (gtkpspell->alternate_speller)
2124 gtkpspeller_delete(gtkpspell->alternate_speller);
2125 gtkpspell->alternate_speller = gtkpspell->gtkpspeller;
2127 gtkpspeller_delete(gtkpspell->gtkpspeller);
2129 gtkpspell->gtkpspeller = gtkpspeller;
2130 gtkpspell_set_sug_mode(gtkpspell, sug_mode);
2133 dictionary_delete(dict);
2135 if (gtkpspell->config_menu)
2136 populate_submenu(gtkpspell, gtkpspell->config_menu);
2139 static void switch_to_alternate_cb(GtkWidget *w,
2142 GtkPspell *gtkpspell = (GtkPspell *) data;
2143 use_alternate_dict(gtkpspell);
2146 /* Misc. helper functions */
2148 static void set_point_continue(GtkPspell *gtkpspell)
2152 gtktext = gtkpspell->gtktext;
2154 gtk_stext_freeze(gtktext);
2155 gtk_editable_set_position(GTK_EDITABLE(gtktext),gtkpspell->orig_pos);
2156 gtk_stext_set_point(gtktext, gtkpspell->orig_pos);
2157 gtk_stext_thaw(gtktext);
2159 if (gtkpspell->continue_check)
2160 gtkpspell->continue_check((gpointer *) gtkpspell);
2163 static void allocate_color(GtkPspell *gtkpspell, gint rgbvalue)
2166 GdkColor *color = &(gtkpspell->highlight);
2168 gc = gtk_widget_get_colormap(GTK_WIDGET(gtkpspell->gtktext));
2170 if (gtkpspell->highlight.pixel)
2171 gdk_colormap_free_colors(gc, &(gtkpspell->highlight), 1);
2173 /* Shameless copy from Sylpheed's gtkutils.c */
2175 color->red = (int) (((gdouble)((rgbvalue & 0xff0000) >> 16) / 255.0)
2177 color->green = (int) (((gdouble)((rgbvalue & 0x00ff00) >> 8) / 255.0)
2179 color->blue = (int) (((gdouble) (rgbvalue & 0x0000ff) / 255.0)
2182 gdk_colormap_alloc_color(gc, &(gtkpspell->highlight), FALSE, TRUE);
2185 static void change_color(GtkPspell * gtkpspell,
2186 gint start, gint end,
2192 g_return_if_fail(start < end);
2194 gtktext = gtkpspell->gtktext;
2196 gtk_stext_freeze(gtktext);
2198 gtk_stext_set_point(gtktext, start);
2199 gtk_stext_forward_delete(gtktext, end - start);
2200 gtk_stext_insert(gtktext, NULL, color, NULL, newtext,
2203 gtk_stext_thaw(gtktext);
2206 /* convert_to_pspell_encoding () - converts ISO-8859-* strings to iso8859-*
2207 * as needed by pspell. Returns an allocated string.
2210 static guchar *convert_to_pspell_encoding (const guchar *encoding)
2212 guchar * pspell_encoding;
2214 if (strstr2(encoding, "ISO-8859-")) {
2215 pspell_encoding = g_strdup_printf("iso8859%s", encoding + 8);
2218 if (!strcmp2(encoding, "US-ASCII"))
2219 pspell_encoding = g_strdup("iso8859-1");
2221 pspell_encoding = g_strdup(encoding);
2224 return pspell_encoding;
2227 /* compare_dict () - compare 2 dict names */
2228 static gint compare_dict(Dictionary *a, Dictionary *b)
2230 guint aparts = 0, bparts = 0;
2233 for (i=0; i < strlen(a->dictname); i++)
2234 if (a->dictname[i] == '-')
2236 for (i=0; i < strlen(b->dictname); i++)
2237 if (b->dictname[i] == '-')
2240 if (aparts != bparts)
2241 return (aparts < bparts) ? -1 : +1;
2244 compare = strcmp2(a->dictname, b->dictname);
2246 compare = strcmp2(a->fullname, b->fullname);
2252 static void dictionary_delete(Dictionary *dict)
2254 g_free(dict->fullname);
2255 g_free(dict->encoding);
2259 static Dictionary *dictionary_dup(const Dictionary *dict)
2263 dict2 = g_new(Dictionary, 1);
2265 dict2->fullname = g_strdup(dict->fullname);
2266 dict2->dictname = dict->dictname - dict->fullname + dict2->fullname;
2267 dict2->encoding = g_strdup(dict->encoding);
2272 static void free_suggestions_list(GtkPspell *gtkpspell)
2276 for (list = gtkpspell->suggestions_list; list != NULL;
2282 gtkpspell->max_sug = -1;
2283 gtkpspell->suggestions_list = NULL;
2286 static void reset_theword_data(GtkPspell *gtkpspell)
2288 gtkpspell->start_pos = 0;
2289 gtkpspell->end_pos = 0;
2290 gtkpspell->theword[0] = 0;
2291 gtkpspell->max_sug = -1;
2293 free_suggestions_list(gtkpspell);
2296 static void free_checkers(gpointer elt, gpointer data)
2298 GtkPspeller *gtkpspeller = elt;
2300 g_return_if_fail(gtkpspeller);
2302 gtkpspeller_real_delete(gtkpspeller);
2305 static gint find_gtkpspeller(gconstpointer aa, gconstpointer bb)
2307 Dictionary *a = ((GtkPspeller *) aa)->dictionary;
2308 Dictionary *b = ((GtkPspeller *) bb)->dictionary;
2310 if (a && b && a->fullname && b->fullname &&
2311 strcmp(a->fullname, b->fullname) == 0 &&
2312 a->encoding && b->encoding)
2313 return strcmp(a->encoding, b->encoding);
2318 static void gtkpspell_alert_dialog(gchar *message)
2323 GtkWidget *ok_button;
2325 dialog = gtk_dialog_new();
2326 gtk_window_set_policy(GTK_WINDOW(dialog), FALSE, FALSE, FALSE);
2327 gtk_window_set_position(GTK_WINDOW(dialog),GTK_WIN_POS_MOUSE);
2328 gtk_signal_connect_object(GTK_OBJECT(dialog), "destroy",
2329 GTK_SIGNAL_FUNC(gtk_widget_destroy),
2330 GTK_OBJECT(dialog));
2332 label = gtk_label_new(message);
2333 gtk_misc_set_padding(GTK_MISC(label), 8, 8);
2335 gtk_container_add(GTK_CONTAINER(GTK_DIALOG(dialog)->vbox), label);
2337 hbox = gtk_hbox_new(FALSE, 0);
2339 ok_button = gtk_button_new_with_label(_("OK"));
2340 GTK_WIDGET_SET_FLAGS(ok_button, GTK_CAN_DEFAULT);
2341 gtk_box_pack_start(GTK_BOX(hbox), ok_button, TRUE, TRUE, 8);
2343 gtk_signal_connect_object(GTK_OBJECT(ok_button), "clicked",
2344 GTK_SIGNAL_FUNC(gtk_widget_destroy),
2345 GTK_OBJECT(dialog));
2346 gtk_container_add(GTK_CONTAINER(GTK_DIALOG(dialog)->action_area), hbox);
2348 gtk_widget_grab_default(ok_button);
2349 gtk_widget_grab_focus(ok_button);
2350 gtk_window_set_modal(GTK_WINDOW(dialog), TRUE);
2352 gtk_widget_show_all(dialog);