? 122110.diff
? 122117-1.diff
? 122742.diff
? Keyboard.kbd
? automatic-scanning.xam
? direct-selection.xam
? dwell-selection.xam
? gok-word-complete-gobject-1.patch
? gok-word-complete-gobject-2.patch
? gok.desktop
? inverse-scanning.xam
? word-complete-refactor.patch
? docs/reference/gok-decl-list.txt
? docs/reference/gok-decl.txt
? docs/reference/gok-undocumented.txt
? docs/reference/gok-unused.txt
? docs/reference/gok.args
? docs/reference/gok.hierarchy
? docs/reference/gok.signals
? docs/reference/html
? docs/reference/html-build.stamp
? docs/reference/html.stamp
? docs/reference/scan-build.stamp
? docs/reference/sgml
? docs/reference/sgml-build.stamp
? docs/reference/sgml.stamp
? docs/reference/tmpl-build.stamp
? docs/reference/tmpl.stamp
? gok/gok-word-completion-changes.txt
? gok/keyboard-geometry
Index: ChangeLog
===================================================================
RCS file: /cvs/gnome/gok/ChangeLog,v
retrieving revision 1.297
diff -u -r1.297 ChangeLog
--- ChangeLog	29 Sep 2003 19:17:06 -0000	1.297
+++ ChangeLog	29 Sep 2003 21:44:29 -0000
@@ -1,3 +1,91 @@
+2003-09-30  Bill Haneman <billh@gnome.org>
+
+	* gok/gok-keyboard.h:
+	(gok_keyboard_clear_completion_keys): New;
+	Refactor clearing of completion keys into gok-keyboard, from gok-word-complete.c.
+	(gok_keyboard_get_alpha, gok_keyboard_get_alpha_by_frequency): New.
+	(gok_keyboard_add_predictions): New (see below).
+	
+	* gok/gok-keyboard.c:
+	(gok_keyboard_add_keys_from_charstrings): New method, allows
+	a gok compose keyboard to be built up from a UTF-8 string.
+	(gok_keyboard_compose_create): New method to create a compose keyboard
+	of a certain name.  Add logic to suppress word-completion keys if the currently
+	focussed AccessibleText object is a password entry field.
+	(gok_keyboard_get_alpha): New; Gets a compose keyboard whose characters are 
+	arranged in alphabetical order appropriate to the current locale.
+	(gok_keyboard_get_alpha_by_frequency): New; as above, but arranges 
+	keys according to character frequency in the current locale.
+	These two methods are localizable via exported strings (with an explanatory
+	notes for translators).
+	(gok_keyboard_get_core): Refactor to use gok_keyboard_compose_create().
+	(gok_keyboard_set_predictions): New; part of refactor which moved this
+	functionality (setting of word-prediction keys) from gok-word-complete 
+	to gok-keyboard.  GokWordComplete now only makes the predictions, it doesn't
+	manipulate the GokKeyboard.
+
+	* gok/gok-keyslotter.c:
+	(gok_keyslotter_on): Changed call from gok_wordcomplete_add_prediction_keys to 
+	gok_keyslotter_add_prediction_keys.
+
+	* gok/gok-output.c:
+	(gok_output_can_predict): New.
+	(gok_output_update_predictions): New, calls gok-keyboard methods to
+	update the prediction keys when a gok-output event occurs (for instance,
+	when GOK synthesizes a new key event).
+	(gok_output_send_to_system): Refactored to call gok_output_update_predictions
+	as appropriate.
+
+	* gok/gok-page-wordcomplete:
+	(gok_page_wordcomplete_apply):
+	Replaced calls to gok_wordcomplete_on with gok_keyslotter_on.
+
+	* gok/gok-scanner.c:
+	(gok_scanner_on_*): Added calls to gok_main_raise_window() when
+	input events occur.
+
+	* gok/gok-spy.h: Fixed C++-style comments(!)
+
+	* gok/gok-word-complete.h:
+	* gok/gok-word-complete.c:
+	GObject-ify, GokWordComplete is now a GType.
+	Almost all GokWordComplete methods were made virtual, and
+	there was a major refactor.  Some functionality was moved to
+	word-complete.c.
+	(gok_wordcomplete_open, gok_wordcomplete_close, gok_wordcomplete_reset): Made virtual.
+	(gok_wordcomplete_predict): Made virtual, now returns an array of strings.
+        No longer actually modifies the keyboard, that's done by the caller.
+	(gok_wordcomplete_process_and_predict): New convenience method.
+	(gok_wordcomplete_process_unichar) : New, process a new letter without making predictions.
+	(gok_wordcomplete_predict_string): New, predict the completion of a string passed in.
+        (gok_wordcomplete_add_new_word) : Made virtual.
+	(gok_wordcomplete_get_output): New, allows GokWordComplete to be more independent of
+	GokKeyboard, etc.  Should probably still move this method into gok-output.c though.
+	(gok_wordcomplete_get_default): New; get the current default word completion engine.
+	(gok_wordcomplete_clear_keys): Removed.
+	(gok_wordcomplete_unichar_is_backspace, gok_wordcomplete_unichar_is_delimiter): New.
+	(gok_wordcomplete_unichar_pop, gok_wordcomplete_unichar_push): New methods for internal
+	use and use by subclasses.
+	(gok_wordcomplete_unichar_get_category): Returns an enum indicating the effect the unichar
+	should have on the predictor state, i.e. normal, backspace, delimiter.
+	(gok_wordcomplete_process_unichar): handle a newly entered character, i.e. make it
+	alter the predictor's state machine appropriately.
+	(gok_wordcomplete_predict): Returns the predictions appropriate to the current
+	predictor's state.  Note that this is different from gok_wordcomplete_predict_string,
+	which is independent of the initial predictor state.
+	(gok_wordcomplete_get_word_part): Returns a string which is the substring "currently being
+	completed".
+
+	* gok/main.c:
+	(gok_main_raise_window) : New, refactors out repeated calls to gdk_window_raise().
+	
+	* gok/word-complete.h:
+	* gok/word-complete.c:
+	Convert to a vehicle for new subtype of GokWordComplete,  GokTrieWordComplete.
+	Made many publicly-exported methods private.
+	(WordCompletePredict):
+	Modify function sig to conform to GokWordComplete method prototype.
+
 2003-09-29  David Bolter <david.bolter@utoronto.ca>
 	
 	* configure.in: version 0.8.3
Index: gok.glade2
===================================================================
RCS file: /cvs/gnome/gok/gok.glade2,v
retrieving revision 1.10
diff -u -r1.10 gok.glade2
--- gok.glade2	28 Jun 2003 16:10:28 -0000	1.10
+++ gok.glade2	29 Sep 2003 21:44:40 -0000
@@ -1713,7 +1713,7 @@
 			  <signal name="toggled" handler="on_core_pointer_button_toggled" last_modification_time="Mon, 17 Feb 2003 22:57:51 GMT"/>
 			</widget>
 			<packing>
-			  <property name="padding">2</property>
+			  <property name="padding">0</property>
 			  <property name="expand">False</property>
 			  <property name="fill">False</property>
 			</packing>
@@ -1739,7 +1739,7 @@
 			      <signal name="toggled" handler="on_xinput_device_button_toggled" last_modification_time="Mon, 17 Feb 2003 22:59:01 GMT"/>
 			    </widget>
 			    <packing>
-			      <property name="padding">0</property>
+			      <property name="padding">1</property>
 			      <property name="expand">False</property>
 			      <property name="fill">False</property>
 			    </packing>
@@ -1804,7 +1804,7 @@
 			  <signal name="toggled" handler="on_joystick_button_toggled" last_modification_time="Mon, 17 Feb 2003 22:58:52 GMT"/>
 			</widget>
 			<packing>
-			  <property name="padding">0</property>
+			  <property name="padding">2</property>
 			  <property name="expand">False</property>
 			  <property name="fill">False</property>
 			</packing>
Index: gok/gok-key.c
===================================================================
RCS file: /cvs/gnome/gok/gok/gok-key.c,v
retrieving revision 1.70
diff -u -r1.70 gok-key.c
--- gok/gok-key.c	19 Sep 2003 13:58:18 -0000	1.70
+++ gok/gok-key.c	29 Sep 2003 21:44:44 -0000
@@ -378,7 +378,7 @@
   pKey = gok_key_new (prevKey, NULL, pKeyboard);
   numlock_mask = gok_key_get_numlock_mask (display);
   is_modifier = FALSE;
-  pKey->has_text = TRUE; /* TODO: handle non-textual keyboard keys! */
+  pKey->has_text = TRUE; /* TODO: handle non-textual keyboard key caps! */
   pKey->Top = row;
   pBounds = &pGeom->shapes[keyp->shape_ndx].bounds;
   pKey->Bottom = row + MAX (1, (pBounds->y2 - pBounds->y1)/(pBounds->x2 - pBounds->x1));
Index: gok/gok-keyboard.c
===================================================================
RCS file: /cvs/gnome/gok/gok/gok-keyboard.c,v
retrieving revision 1.99
diff -u -r1.99 gok-keyboard.c
--- gok/gok-keyboard.c	26 Sep 2003 12:02:58 -0000	1.99
+++ gok/gok-keyboard.c	29 Sep 2003 21:44:49 -0000
@@ -54,7 +54,10 @@
 #define NUM_INTERESTING_ROLES 5
 #define GOK_KEYBOARD_MAX_ROWS 24
 
-#define CORE_KEYBOARD "Keyboard"
+#define CORE_KEYBOARD N_("Keyboard")
+/*#define ALPHA_KEYBOARD N_("Keyboard") testing hack */
+#define ALPHA_KEYBOARD N_("Alpha")
+#define FREQ_KEYBOARD N_("Alpha-Frequency")
 
 #define GOK_KEYBOARD_DOCK_BORDERPIX 5
 
@@ -400,26 +403,133 @@
 	return m_XkbDisplay;
 }
 
+void
+gok_keyboard_clear_completion_keys (GokKeyboard *keyboard)
+{	
+	/* clear the current word predictions */
+	GokKey *pKey = keyboard->pKeyFirst;
+	while (pKey != NULL)
+	{
+		if (pKey->Type == KEYTYPE_WORDCOMPLETE)
+		{
+			gok_key_set_button_label (pKey, "");
+			gok_key_add_label (pKey, "", MODIFIER_NORMAL);
+			gok_key_set_output (pKey, 0, NULL, 0);
+		}
+		pKey = pKey->pKeyNext;
+	}
+}
+
+
 /**
-* gok_keyboard_get_core:
-*
-* Returns: a pointer to a #GokKeyboard representing the core system 
-* keyboard device, with the same row/column geometry and key symbols.
-**/
-GokKeyboard *
-gok_keyboard_get_core ()
+ * gok_keyboard_add_keys_from_charstrings:
+ *
+ *
+ **/
+static void
+gok_keyboard_add_keys_from_charstrings (GokKeyboard *pKeyboard, 
+					gchar *level0_string,
+					gchar *level1_string,
+					gchar *level2_string,
+					gchar *level3_string)
 {
-	GokKeyboard *pKeyboard;
+	GokKey *pKey = pKeyboard->pKeyFirst;
+	while (pKey->pKeyNext) 
+	{
+		pKey = pKey->pKeyNext;
+	}
+	if (level0_string)
+	{
+	        level0_string = g_utf8_strchr (level0_string, -1, '|');
+		if (level0_string) ++level0_string; /* works because '|' is one byte */
+	}
+
+	if (!(level0_string && g_utf8_validate (level0_string, -1, NULL)) || 
+	    (level1_string && !g_utf8_validate (level1_string, -1, NULL)) || 
+	    (level2_string && !g_utf8_validate (level2_string, -1, NULL)) || 
+	    (level3_string && !g_utf8_validate (level3_string, -1, NULL))) 
+	{
+		return;
+	}
+
+	if (*level1_string) 
+	{
+		gok_modifier_add ("shift");
+	        level1_string = g_utf8_strchr (level1_string, -1, '|');
+		if (level1_string) ++level1_string; /* works because '|' is one byte */
+	}
+	if (*level2_string)
+	{
+		gok_modifier_add ("level2");
+	        level2_string = g_utf8_strchr (level2_string, -1, '|');
+		if (level2_string) ++level2_string; /* works because '|' is one byte */
+	}
+	if (*level3_string)
+	{
+		gok_modifier_add ("level3");
+	        level3_string = g_utf8_strchr (level3_string, -1, '|');
+		if (level3_string) ++level3_string; /* works because '|' is one byte */
+	}
+
+	while (*level0_string)
+	{
+		gchar utf8_char[7];
+		pKey = gok_key_new (pKey, NULL, pKeyboard);
+		pKey->has_text = TRUE;
+		pKey->Type = KEYTYPE_NORMAL;
+		pKey->is_repeatable = TRUE;
+		pKey->Style = KEYSTYLE_NORMAL;
+		pKey->FontSize = -1;
+		pKey->FontSizeGroup = FONT_SIZE_GROUP_GLYPH;
+		utf8_char [g_unichar_to_utf8 (g_utf8_get_char (level0_string), utf8_char)] = '\0';
+		gok_keylabel_new (pKey, utf8_char, NULL);
+		pKey->pOutput = gok_output_new (OUTPUT_KEYSTRING, utf8_char, SPI_KEY_STRING);
+		/* FIXME: need this to work for other levels too! */
+		level0_string = g_utf8_find_next_char (level0_string, NULL);
+		if (*level1_string)
+		{
+			utf8_char [g_unichar_to_utf8 (g_utf8_get_char (level1_string), utf8_char)] = '\0';
+			gok_keylabel_new (pKey, utf8_char, "shift");
+			level1_string = g_utf8_find_next_char (level1_string, NULL);
+		}
+		if (*level2_string)
+		{
+			utf8_char [g_unichar_to_utf8 (g_utf8_get_char (level2_string), utf8_char)] = '\0';
+			gok_keylabel_new (pKey, utf8_char, "level2");
+			level2_string = g_utf8_find_next_char (level2_string, NULL);
+		}
+		if (*level3_string)
+		{
+			utf8_char [g_unichar_to_utf8 (g_utf8_get_char (level3_string), utf8_char)] = '\0';
+			gok_keylabel_new (pKey, utf8_char, "level3");
+			level3_string = g_utf8_find_next_char (level3_string, NULL);
+		}
+	}
+}
+
+/**
+ * gok_keyboard_compose_create:
+ *
+ * Creates a new compose (i.e. alphanumeric) keyboard with name
+ * @keyboard_name, including word-completion and 'back' keys if
+ * appropriate in the current GOK context/configuration.
+ **/
+static GokKeyboard*
+gok_keyboard_compose_create (gchar *keyboard_name)
+{
+	GokKeyboard *pKeyboard = gok_keyboard_new ();
 	GokKey *pKey;
-	gok_log_enter();
-	pKeyboard = gok_keyboard_new ();
-	gok_keyboard_set_name (pKeyboard, CORE_KEYBOARD);
+	Accessible *acc_with_text;
+	gok_keyboard_set_name (pKeyboard, _(keyboard_name));
 	pKeyboard->bRequiresLayout = FALSE;
 	pKeyboard->bLaidOut = TRUE;
-	pKeyboard->bSupportsWordCompletion = FALSE;
+	pKeyboard->bSupportsWordCompletion = TRUE;
 	pKeyboard->bSupportsCommandPrediction = FALSE;
-	if (!gok_main_get_login ()) {
-		pKeyboard->bSupportsWordCompletion = TRUE;
+
+	acc_with_text = gok_spy_get_accessibleWithText ();
+       
+	if (!gok_main_get_login ())
+	{
 		pKey = gok_key_new (NULL, NULL, pKeyboard);
 		pKey->Type = KEYTYPE_BRANCHBACK;
 		pKey->Style = KEYSTYLE_BRANCHBACK;
@@ -430,7 +540,134 @@
 		pKey->Left = 0;
 		pKey->Right = 1;
 		gok_keylabel_new (pKey, _("Back"), NULL);
+		if (acc_with_text && 
+		    (Accessible_getRole (acc_with_text) == SPI_ROLE_PASSWORD_TEXT))
+		{
+			pKeyboard->bSupportsWordCompletion = FALSE;
+		}
+
 	}
+	return pKeyboard;
+}
+
+
+/**
+ * gok_keyboard_get_alpha:
+ *
+ * Returns: a pointer to a #GokKeyboard which contains the current locale/LANG's
+ * alphabet in "sorted" (e.g. alphabetical) order.
+ **/
+GokKeyboard*
+gok_keyboard_get_alpha ()
+{
+	GokKeyboard *pKeyboard;
+	GokKey *pKey;
+	gok_log_enter();
+	pKeyboard = gok_keyboard_compose_create (ALPHA_KEYBOARD);
+	/*
+	 * Note to Translators: the following strings should contain your LANG/locale's 
+	 * alphabet or, in the case of LANGs with a very large glyph set, a set of
+	 * character-primitives which can be used to compose your language's character set.
+	 * Each string below corresponds to the characters associated with a particular
+	 * "shift level" in the XKB keyboard definition.
+	 * The prefix before the '|' character is just a context string and need not be
+	 * translated.
+	 *
+	 * For languages where 'case' is used, the first string should contain 
+	 * the lowercase alphabet, the second string the uppercase alphabet.  
+	 * Note that unless your locale clearly requires that digits and/or punctuation
+	 * precede alphabetic characters, we prefer that digits and punctuation are placed 
+	 * at the end of the string for GOK's purposes.
+	 * The third string is not used in the C locale but corresponds to a shift
+	 * level of '2' which is often associated with the AltGr key on physical keyboards.
+	 *
+	 * The order in which punctuation occurs is not critical, but if there is a 
+	 * "standard" layout for your locale's physical keyboards it is nice to place
+	 * the punctuation in the order in which it appears on physical keycaps.
+	 * For instance, since Shift-plus-digits for "1,2,3,4" on a US keyboard 
+	 * produce "!, \", 3, $", etc., it is convenient to list these punctuation marks
+	 * in the same order in the "level 1" string as we do below for the C locale.
+	 *
+	 * For languages
+	 * which use shift or level modifiers to select between different glyphs, the meaning
+	 * of 'level' above, and as interpreted by the X server, may be slightly different.
+	 * If you have questions or comments about the intent of this string please contact
+	 * billh@gnome.org or david.bolter@utoronto.ca for more information.
+	 *
+	 */
+	gok_keyboard_add_keys_from_charstrings (pKeyboard, 
+						_("level 0|abcdefghijklmnopqrstuvwxyz1234567890-=[];'#\\,./"),
+						_("level 1|ABCDEFGHIJKLMNOPQRSTUVWXYZ!\"3$%^&*()_+{}:@~<>?"),
+						_("level 2|"),
+						_("level 3|")); /* no level 2 or 3 in C locale */
+
+
+	pKeyboard->bRequiresLayout = TRUE;
+	pKeyboard->bLaidOut = FALSE;
+	gok_keyboard_count_rows_columns (pKeyboard);
+	gok_log ("created core keyboard with %d rows and %d columns\n",
+		 gok_keyboard_get_number_rows (pKeyboard), 
+		 gok_keyboard_get_number_columns (pKeyboard));
+	gok_log_leave();
+	return pKeyboard;
+}
+
+/**
+ * gok_keyboard_get_alpha_by_frequency:
+ *
+ * Returns: a pointer to a #GokKeyboard which contains the current locale/LANG's
+ * alphabet arranged with the most-frequently-occurring characters at the 
+ * upper left; reduces total user input effort when in scanning input modes.
+ **/
+GokKeyboard *
+gok_keyboard_get_alpha_by_frequency ()
+{
+	/* 
+	 * TODO: Lay out the keys according to scan-operations required, 
+	 *   instead of in the order in which they are added
+	 */
+	GokKeyboard *pKeyboard;
+	GokKey *pKey;
+	gok_log_enter();
+	pKeyboard = gok_keyboard_compose_create (ALPHA_KEYBOARD);
+	/*
+	 * Note to Translators: the following strings should contain your LANG/locale's 
+	 * alphabet or, in the case of LANGs with a very large glyph set, a set of
+	 * character-primitives which can be used to compose your language's character set. 
+	 * This string should contain all of the glyphs in the "level #|abcde..." strings
+	 * but they should appear in 'frequency order', that is, the most frequently occurring
+	 * characters in your locale should appear at the front of the list.
+	 * (Put digits after characters, and punctuation last).
+	 * If level 0 and level 1 refer to upper-and-lower-case in your locale, 
+	 * the characters in these two strings should occur in the same relative order.
+	 */
+	gok_keyboard_add_keys_from_charstrings (pKeyboard, 
+						_("level 0|etaonrishdlfcmugypwbvkxjqz`1234567890-=\\[];'<,./"),
+						_("level 1|ETAONRISHDLFCMUGYPWBVKXJQZ~!@#$%^&*()_+|{}:\"><>?"),
+						_("level 2|\0"),
+						_("level 3|\0")); /* no level 2 or 3 in C locale */
+	pKeyboard->bRequiresLayout = TRUE;
+	pKeyboard->bLaidOut = FALSE;
+	gok_keyboard_count_rows_columns (pKeyboard);
+	gok_log ("created core keyboard with %d rows and %d columns\n",
+		 gok_keyboard_get_number_rows (pKeyboard), 
+		 gok_keyboard_get_number_columns (pKeyboard));
+	gok_log_leave();
+	return pKeyboard;
+}
+
+/**
+* gok_keyboard_get_core:
+*
+* Returns: a pointer to a #GokKeyboard representing the core system 
+* keyboard device, with the same row/column geometry and key symbols.
+**/
+GokKeyboard *
+gok_keyboard_get_core ()
+{
+	GokKeyboard *pKeyboard;
+	gok_log_enter();
+	pKeyboard = gok_keyboard_compose_create (CORE_KEYBOARD);
 	gok_keyboard_add_keys_from_xkb_geom (pKeyboard, 
 					     gok_keyboard_get_xkb_desc ());
 	gok_keyboard_count_rows_columns (pKeyboard);
@@ -2750,6 +2987,7 @@
 	GokOutput OutputSpace;
 	GokKeyboard* pPredictedKeyboard;
 	GokKeyboard* pKeyboardTemp;
+	GokKeyboard* keyboard = gok_main_get_current_keyboard ();
 	GokKey* pKeyTemp;
 	
 	gok_log_enter();
@@ -2874,7 +3112,8 @@
 			gok_modifier_output_pre();
 			
 			/* send the key output to the system */
-			gok_output_send_to_system (gok_wordcomplete_get_output (pKey), 
+			gok_output_send_to_system (gok_wordcomplete_get_output (
+							   gok_wordcomplete_get_default (), pKey), 
 				FALSE);
 			
 			/* end the word with a 'space' */
@@ -2889,11 +3128,12 @@
 			
 			/* turn off any modifier keys that are not locked on */
 			gok_modifier_all_off();
-			gok_wordcomplete_increment_word_frequency (gok_key_get_label (pKey));
+			gok_wordcomplete_increment_word_frequency (gok_wordcomplete_get_default (), 
+								   gok_key_get_label (pKey));
 			
 			/* reset the word completor */
-			gok_wordcomplete_clear_keys();
-			gok_wordcomplete_end_word();
+			gok_wordcomplete_reset (gok_wordcomplete_get_default ());
+			gok_keyboard_clear_completion_keys (keyboard);
 			break;
 			
 		case KEYTYPE_BRANCHMENUITEMS:
@@ -3386,4 +3626,62 @@
 	else if (!strcmp (string, "taller"))
 		return GOK_RESIZE_TALLER;
 	return GOK_DIRECTION_NONE;
+}
+
+/* TODO: extend the list to allow command predictions as well */
+gint
+gok_keyboard_set_predictions (GokKeyboard *pKeyboard, gchar **list)
+{
+	GokKey* pKey;
+	gint count;
+	gint length;
+	int i;
+	gint statusPrediction = 0;
+	gchar* pWordsPredicted = NULL;
+	gchar* token = NULL;
+	gchar separators[] = " ,\t\n";
+	gchar *word_part;
+
+	/* clear the current word predictions */
+	gok_keyboard_clear_completion_keys (pKeyboard);
+
+	/* fill in the word completion keys */
+	count = 0;
+	pKey = pKeyboard->pKeyFirst;
+
+	for (i = 0; list && list[i]; ++i)
+	{
+		/* make sure we're not going over our maximum predictions */
+		count++;
+		if (count > gok_data_get_num_predictions())
+		{
+			break;
+		}
+		
+		/* get the next word completion key on the keyboard */
+		while (pKey != NULL)
+		{
+			if (pKey->Type == KEYTYPE_WORDCOMPLETE)
+			{
+				gok_key_set_button_label (pKey, list[i]);
+				gok_key_add_label (pKey, list[i], MODIFIER_NORMAL);
+								
+				pKey = pKey->pKeyNext;
+				break;
+			}
+			pKey = pKey->pKeyNext;
+		}
+		if (pKey == NULL)
+		{
+			break;
+		}
+	}
+	
+	/* change the font size for the word completion keys */
+	if (count > 0)
+	{
+		gok_keyboard_calculate_font_size_group (pKeyboard, FONT_SIZE_GROUP_WORDCOMPLETE, TRUE);
+	}
+	
+	return count;
 }
Index: gok/gok-keyboard.h
===================================================================
RCS file: /cvs/gnome/gok/gok/gok-keyboard.h,v
retrieving revision 1.39
diff -u -r1.39 gok-keyboard.h
--- gok/gok-keyboard.h	30 Jun 2003 12:43:22 -0000	1.39
+++ gok/gok-keyboard.h	29 Sep 2003 21:44:49 -0000
@@ -124,6 +124,8 @@
 GokKeyboard* gok_keyboard_new (void);
 GokKeyboard* gok_keyboard_read (gchar* Filename);
 GokKeyboard* gok_keyboard_get_core (void);
+GokKeyboard* gok_keyboard_get_alpha (void);
+GokKeyboard* gok_keyboard_get_alpha_by_frequency (void);
 Display*     gok_keyboard_get_display (void);
 void gok_keyboard_delete (GokKeyboard* pKeyboard, gboolean bForce);
 void gok_keyboard_delete_key (GokKey* pKey, GokKeyboard* pKeyboard);
@@ -182,6 +184,7 @@
 gint gok_keyboard_get_keyboards(void);
 GokKey *gok_keyboard_find_key_at (GokKeyboard *pKeyboard, gint x, gint y);
 GokKeyboardDirection gok_keyboard_parse_direction (const gchar *string);
+gint gok_keyboard_add_predictions (GokKeyboard *pKeyboard, gchar **list);
 
 #ifdef __cplusplus
 }
Index: gok/gok-keyslotter.c
===================================================================
RCS file: /cvs/gnome/gok/gok/gok-keyslotter.c,v
retrieving revision 1.4
diff -u -r1.4 gok-keyslotter.c
--- gok/gok-keyslotter.c	21 Apr 2003 15:29:10 -0000	1.4
+++ gok/gok-keyslotter.c	29 Sep 2003 21:44:50 -0000
@@ -73,7 +73,7 @@
 					pKeyboard->NumberRows += 1;
 					if (keytype == KEYTYPE_WORDCOMPLETE)
 					{
-						gok_wordcomplete_add_prediction_keys (pKeyboard);
+						gok_keyslotter_add_prediction_keys (pKeyboard, keytype);
 					}
 					else if (keytype == KEYTYPE_COMMANDPREDICT)
 					{
Index: gok/gok-output.c
===================================================================
RCS file: /cvs/gnome/gok/gok/gok-output.c,v
retrieving revision 1.17
diff -u -r1.17 gok-output.c
--- gok/gok-output.c	26 Sep 2003 12:27:30 -0000	1.17
+++ gok/gok-output.c	29 Sep 2003 21:44:50 -0000
@@ -1,4 +1,4 @@
-/* gok-output.h
+/* gok-output.c
 *
 * Copyright 2001,2002 Sun Microsystems, Inc.,
 * Copyright 2001,2002 University Of Toronto
@@ -31,6 +31,66 @@
 #include "gok-word-complete.h"
 #include "main.h"
 
+static gboolean
+gok_output_can_predict (void)
+{
+	GokKeyboard *kbd = gok_main_get_current_keyboard ();
+	return (kbd && !gok_main_get_login() && gok_data_get_wordcomplete () &&
+		gok_keyboard_get_supports_wordcomplete (kbd));
+}
+
+/**
+ * gok_output_update_predictions:
+ * Send new data to the predictor based on output type, and update the keyboard's prediction keys. 
+ **/
+static void
+gok_output_update_predictions (GokOutput    *output,
+			       gpointer      data)
+{
+	gunichar letter;
+	gchar *string;
+	gchar **prediction_list = NULL;
+
+	if (output) {
+		switch (output->Type) 
+		{
+		case OUTPUT_KEYCODE:
+		case OUTPUT_KEYSYM:
+			prediction_list = gok_wordcomplete_process_and_predict (gok_wordcomplete_get_default (),
+										(gunichar) data);
+			gok_keyboard_set_predictions (gok_main_get_current_keyboard (),
+						      prediction_list);
+			break;
+		case OUTPUT_KEYSTRING:
+			/* TODO: Test! */
+			string = (gchar *) data;
+			if (string && g_utf8_validate (string, -1, NULL)) 
+			{
+				while (string) 
+				{
+					if (prediction_list)
+					{
+						int i;
+						for (i = 0; prediction_list && prediction_list[i]; ++i)
+							g_free (prediction_list[i]);
+						g_free (prediction_list);
+					}
+					letter = g_utf8_get_char (string);
+					prediction_list = gok_wordcomplete_process_and_predict (
+						gok_wordcomplete_get_default (),
+						letter);
+					string = g_utf8_next_char (string);
+				}
+				gok_keyboard_set_predictions (gok_main_get_current_keyboard (), 
+							      prediction_list);
+			}
+			break;
+		default:
+			break;
+		}
+	}
+}
+
 gunichar gok_output_unichar_from_keysym (KeySym keysym)
 {
 	char *charstring;
@@ -211,9 +271,9 @@
 			SPI_generateKeyboardEvent ((long) keysym, NULL, SPI_KEY_SYM);
 
 			/* update the word prediction keys with the new output */
-			if (bWordCompletion && !gok_main_get_login()) {
-					gok_wordcomplete_predict (
-						gok_output_unichar_from_keysym (keysym));
+			if (bWordCompletion && gok_output_can_predict ()) {
+				gok_output_update_predictions (pOutput,
+							       (gpointer) gok_output_unichar_from_keysym (keysym));
 			}
 		}
 		else if (pOutput->Type == OUTPUT_KEYCODE)
@@ -225,8 +285,9 @@
 			gok_log ("pOutput->Flag = %d", (int) pOutput->Flag);
 
 			SPI_generateKeyboardEvent ((long) keycode, NULL, pOutput->Flag);
+
 			/* update the word prediction keys with the new output */
-			if (bWordCompletion && !gok_main_get_login() &&
+			if (bWordCompletion && gok_output_can_predict () &&
 			    !gok_key_modifier_for_keycode (
 				    gok_main_display (),
 				    gok_keyboard_get_xkb_desc (),
@@ -240,7 +301,8 @@
 				/* TODO: get the correct index from XKB */
 			        keysym = XKeycodeToKeysym (gok_main_display (), 
 							   keycode, index);
-				gok_wordcomplete_predict (gok_output_unichar_from_keysym (keysym));
+				gok_output_update_predictions (pOutput,
+							       (gpointer) gok_output_unichar_from_keysym (keysym));
 			}
 		}
 		else if (pOutput->Type == OUTPUT_KEYSTRING)
@@ -251,10 +313,10 @@
 			SPI_generateKeyboardEvent (0, pOutput->Name, SPI_KEY_STRING);
 
 			/* update the word prediction keys with the new output */
-			if (bWordCompletion == TRUE)
+			if (bWordCompletion == TRUE && gok_output_can_predict ())
 			{
-				/* TODO: allow word completion with substring insertion */
-				gok_wordcomplete_predict (0);
+				gok_output_update_predictions (pOutput,
+							       pOutput->Name);
 			}
 		}
 		else if (pOutput->Type == OUTPUT_EXEC)
Index: gok/gok-page-wordcomplete.c
===================================================================
RCS file: /cvs/gnome/gok/gok/gok-page-wordcomplete.c,v
retrieving revision 1.6
diff -u -r1.6 gok-page-wordcomplete.c
--- gok/gok-page-wordcomplete.c	11 Oct 2002 19:00:04 -0000	1.6
+++ gok/gok-page-wordcomplete.c	29 Sep 2003 21:44:51 -0000
@@ -116,14 +116,14 @@
 	{
 		bDataChanged = TRUE;
 		gok_data_set_wordcomplete (m_WordCompleteOnOff);
-		gok_wordcomplete_on (m_WordCompleteOnOff);
+		gok_keyslotter_on (m_WordCompleteOnOff, KEYTYPE_WORDCOMPLETE);
 	}
 
 	if (m_NumberPredictions != gok_data_get_num_predictions())
 	{
 		bDataChanged = TRUE;
 		gok_data_set_num_predictions (m_NumberPredictions);
-		gok_wordcomplete_change_number_predictions (m_NumberPredictions);
+		gok_keyslotter_change_number_predictions (m_NumberPredictions, KEYTYPE_WORDCOMPLETE);
 	}
 
 	return bDataChanged;
@@ -151,7 +151,7 @@
 		bDataChanged = TRUE;
 		m_WordCompleteOnOff = m_WordCompleteOnOffBackup;
 		gok_data_set_wordcomplete (m_WordCompleteOnOff);
-		gok_wordcomplete_on (m_WordCompleteOnOff);
+		gok_keyslotter_on (m_WordCompleteOnOff, KEYTYPE_WORDCOMPLETE);
 
 		pCheckboxOnOff = lookup_widget (m_pWindowSettings, "checkWordCompletion");
 		g_assert (pCheckboxOnOff != NULL);
@@ -164,7 +164,7 @@
 		bDataChanged = TRUE;
 		m_NumberPredictions = m_NumberPredictionsBackup;
 		gok_data_set_num_predictions (m_NumberPredictions);
-		gok_wordcomplete_change_number_predictions (m_NumberPredictions);
+		gok_keyslotter_change_number_predictions (m_NumberPredictions, KEYTYPE_WORDCOMPLETE);
 
 		pSpinNumberPredictions = lookup_widget (m_pWindowSettings, "spinNumberPredictions");
 		g_assert (pSpinNumberPredictions != NULL);
Index: gok/gok-predictor.c
===================================================================
RCS file: /cvs/gnome/gok/gok/gok-predictor.c,v
retrieving revision 1.5
diff -u -r1.5 gok-predictor.c
--- gok/gok-predictor.c	11 Oct 2002 19:00:04 -0000	1.5
+++ gok/gok-predictor.c	29 Sep 2003 21:44:51 -0000
@@ -173,7 +173,7 @@
 }
 
 /**
-* gok_wordcomplete_add_prediction_keys
+* gok_predictor_add_prediction_keys
 *
 * @pKeyboard: Pointer to the keyboard that gets the new prediction keys.
 *
Index: gok/gok-scanner.c
===================================================================
RCS file: /cvs/gnome/gok/gok/gok-scanner.c,v
retrieving revision 1.63
diff -u -r1.63 gok-scanner.c
--- gok/gok-scanner.c	29 Sep 2003 17:59:34 -0000	1.63
+++ gok/gok-scanner.c	29 Sep 2003 21:44:55 -0000
@@ -2147,6 +2147,7 @@
 {
 	m_pKeyEntered = pKey;
 
+	gok_main_raise_window ();
 	gok_scanner_timer_start_dwell();
 		
 	gok_scanner_perform_effects (m_pEffectsOnKeyEnter);
@@ -2416,6 +2417,7 @@
 **/
 void gok_scanner_on_switch1_down ()
 {
+	gok_main_raise_window ();
 	gok_scanner_perform_effects (m_pEffectsOnSwitch1Down);
 }
 
@@ -2436,6 +2438,7 @@
 **/
 void gok_scanner_on_switch2_down ()
 {
+	gok_main_raise_window ();
 	gok_scanner_perform_effects (m_pEffectsOnSwitch2Down);
 }
 
@@ -2456,6 +2459,7 @@
 **/
 void gok_scanner_on_switch3_down ()
 {
+	gok_main_raise_window ();
 	gok_scanner_perform_effects (m_pEffectsOnSwitch3Down);
 }
 
@@ -2476,6 +2480,7 @@
 **/
 void gok_scanner_on_switch4_down ()
 {
+	gok_main_raise_window ();
 	gok_scanner_perform_effects (m_pEffectsOnSwitch4Down);
 }
 
@@ -2496,6 +2501,7 @@
 **/
 void gok_scanner_on_switch5_down ()
 {
+	gok_main_raise_window ();
 	gok_scanner_perform_effects (m_pEffectsOnSwitch5Down);
 }
 
Index: gok/gok-scanner.h
===================================================================
RCS file: /cvs/gnome/gok/gok/gok-scanner.h,v
retrieving revision 1.30
diff -u -r1.30 gok-scanner.h
--- gok/gok-scanner.h	11 Sep 2003 17:45:00 -0000	1.30
+++ gok/gok-scanner.h	29 Sep 2003 21:44:55 -0000
@@ -268,4 +268,4 @@
 }
 #endif /* __cplusplus */
 
-#endif // #ifndef __GOKSCANNER_H__
+#endif /* #ifndef __GOKSCANNER_H__ */
Index: gok/gok-spy.c
===================================================================
RCS file: /cvs/gnome/gok/gok/gok-spy.c,v
retrieving revision 1.91
diff -u -r1.91 gok-spy.c
--- gok/gok-spy.c	28 Aug 2003 14:46:15 -0000	1.91
+++ gok/gok-spy.c	29 Sep 2003 21:44:58 -0000
@@ -1272,7 +1272,6 @@
 	EventNode* en; 
 	gok_log_enter();
 	gok_spy_accessible_ref(event->source);
-	
 	en = (EventNode*)g_malloc(sizeof(EventNode));
 	en->paccessible = event->source;
 	en->type = GOKSPY_FOCUS_EVENT;
Index: gok/gok-spy.h
===================================================================
RCS file: /cvs/gnome/gok/gok/gok-spy.h,v
retrieving revision 1.26
diff -u -r1.26 gok-spy.h
--- gok/gok-spy.h	21 Aug 2003 20:03:17 -0000	1.26
+++ gok/gok-spy.h	29 Sep 2003 21:44:58 -0000
@@ -49,7 +49,7 @@
 void gok_spy_close(void);       /* call this when shutting down */ 
 void gok_spy_stop (void);       /* call this first, as soon as you start shutting down */
  
-// listener support 
+/* listener support */
 void gok_spy_register_appchangelistener(AppChangeListener* callback); 
 void gok_spy_deregister_appchangelistener(AppChangeListener* callback); 
  
@@ -88,4 +88,4 @@
 } 
 #endif /* __cplusplus */ 
  
-#endif // #ifndef __GOKSPY_H__
+#endif /* #ifndef __GOKSPY_H__ */
Index: gok/gok-word-complete.c
===================================================================
RCS file: /cvs/gnome/gok/gok/gok-word-complete.c,v
retrieving revision 1.21
diff -u -r1.21 gok-word-complete.c
--- gok/gok-word-complete.c	21 Aug 2003 13:58:38 -0000	1.21
+++ gok/gok-word-complete.c	29 Sep 2003 21:44:59 -0000
@@ -22,7 +22,6 @@
 /*
 * To use this thing:
 * - Call "gok_wordcomplete_open". If it returns TRUE then you're ready to go.
-* - Call "gok_wordcomplete_on (TRUE)" to turn it on.
 * - Call "gok_wordcomplete_predict" to make the word predictions.
 * - Call "gok_wordcomplete_close" when you're done. 
 * - To add a word, call "gok_wordcomplete_add_new_word".
@@ -41,11 +40,66 @@
 #include "gok-data.h"
 #include "gok-keyboard.h"
 
+#include "word-complete.h" /* TODO: remove this when we make this class abstract */
 
-/* the word, or part word, that is getting completed */
-static gchar *word_part = NULL;
+static void gok_wordcomplete_finalize (GObject *obj);
+static void gok_wordcomplete_real_reset (GokWordComplete *complete);
+static gchar *gok_wordcomplete_real_process_unichar (GokWordComplete *complete, gunichar letter);
+static gchar *gok_wordcomplete_real_unichar_push (GokWordComplete *complete, gunichar letter);
+static gchar *gok_wordcomplete_real_unichar_pop (GokWordComplete *complete);
+static GokWordCompletionCharacterCategory gok_wordcomplete_real_unichar_get_category (
+	                                         GokWordComplete *complete, gunichar letter);
+static gchar **gok_wordcomplete_real_predict (GokWordComplete *complete, gint num_predictions);
+static gchar *gok_wordcomplete_real_get_word_part (GokWordComplete *complete);
 
-static GokOutput* m_pOutputListStart;
+
+struct _GokWordCompletePrivate 
+{
+        /* the word, or part word, that is getting completed */
+	gchar     *word_part;
+	GokOutput *last_output;
+};
+
+static GokWordComplete *default_wordcomplete_engine = NULL;
+
+GNOME_CLASS_BOILERPLATE (GokWordComplete, gok_wordcomplete, 
+			 GObject, G_TYPE_OBJECT)
+
+static void
+gok_wordcomplete_instance_init (GokWordComplete *complete)
+{
+	complete->priv = g_new0 (GokWordCompletePrivate, 1);
+	complete->priv->word_part = NULL;
+	complete->priv->last_output = NULL;
+}
+
+static void
+gok_wordcomplete_class_init (GokWordCompleteClass *klass)
+{
+	GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+
+	/* public methods */
+	gobject_class->finalize = gok_wordcomplete_finalize;
+	klass->reset = gok_wordcomplete_real_reset;
+	klass->process_unichar = gok_wordcomplete_real_process_unichar;
+	klass->predict = gok_wordcomplete_real_predict;
+
+	/* 'protected' methods, for use by subclasses/implementors only */
+	klass->unichar_get_category = gok_wordcomplete_real_unichar_get_category;
+	klass->unichar_push = gok_wordcomplete_real_unichar_push;
+	klass->unichar_pop = gok_wordcomplete_real_unichar_pop;
+	klass->get_word_part = gok_wordcomplete_real_get_word_part;
+}
+
+static void
+gok_wordcomplete_finalize (GObject *obj)
+{
+	GokWordComplete *complete = GOK_WORDCOMPLETE (obj);
+	gok_output_delete_all (complete->priv->last_output);
+	if (complete && complete->priv)
+		g_free (complete->priv);
+	G_OBJECT_CLASS (GOK_WORDCOMPLETE_GET_CLASS (obj))->finalize (obj);
+}
 
 /**
 * gok_wordcomplete_open
@@ -54,15 +108,14 @@
 *
 * returns: TRUE if it was opend OK, FALSE if not.
 **/
-gboolean gok_wordcomplete_open (gchar *directory)
+gboolean gok_wordcomplete_open (GokWordComplete *complete, gchar *directory)
 {
-	m_pOutputListStart = NULL;
+	GokWordCompleteClass *klass = GOK_WORDCOMPLETE_GET_CLASS (complete);
 	
-	gok_wordcomplete_end_word();
-	
-	gok_wordcomplete_on (gok_data_get_wordcomplete());
-	
-	return (WordCompleteOpen(directory));
+	if (klass->open)
+		return (* klass->open)(complete, directory);
+	else
+		return FALSE;
 }
 
 /**
@@ -72,243 +125,151 @@
 *
 * returns: void
 **/
-void gok_wordcomplete_close ()
+void gok_wordcomplete_close (GokWordComplete *complete)
 {
-	if (m_pOutputListStart == NULL)
-	{
-		gok_output_delete_all (m_pOutputListStart);
-	}
+	GokWordCompleteClass *klass = GOK_WORDCOMPLETE_GET_CLASS (complete);
 
-	WordCompleteClose();
+	if (klass->close)
+		(*klass->close) (complete);
 }
 
 /**
-* gok_wordcomplete_on
-* 
-* Turns on (or off) the word completor.
-* This adds (or removes) the word completion keys to every keyboard that supports 
-* word completion.
-*
-* returns: void.
-**/
-void gok_wordcomplete_on (gboolean bOnOff)
+ * gok_wordcomplete_unichar_push:
+ *
+ **/
+gchar *
+gok_wordcomplete_unichar_push (GokWordComplete *complete, gunichar letter)
 {
-	gok_log_enter();
-	gok_keyslotter_on(bOnOff, KEYTYPE_WORDCOMPLETE);
-	gok_log_leave();
+	GokWordCompleteClass *klass = GOK_WORDCOMPLETE_GET_CLASS (complete);
+
+	if (klass->unichar_push)
+		return (*klass->unichar_push) (complete, letter);
+	else
+		return NULL;
 }
 
 /**
-* gok_wordcomplete_change_number_predictions
-*
-* @Number: Number of prediction keys.
-*
-* Changes the number of word prediction keys displayed on the keyboard. This
-* should be called after the user has selected a new number from the settings
-* dialog.
-*
-* returns: void
-**/
-void gok_wordcomplete_change_number_predictions (int Number)
+ * gok_wordcomplete_unichar_pop:
+ *
+ **/
+gchar *
+gok_wordcomplete_unichar_pop (GokWordComplete *complete)
+{
+	GokWordCompleteClass *klass = GOK_WORDCOMPLETE_GET_CLASS (complete);
+
+	if (klass->unichar_pop)
+		return (*klass->unichar_pop) (complete);
+	else
+		return NULL;
+}
+
+
+
+/**
+ * gok_wordcomplete_unichar_get_category
+ *
+ **/
+GokWordCompletionCharacterCategory
+gok_wordcomplete_unichar_get_category (GokWordComplete *complete, gunichar letter)
 {
-	gok_keyslotter_change_number_predictions( Number, KEYTYPE_WORDCOMPLETE );
+	GokWordCompleteClass *klass = GOK_WORDCOMPLETE_GET_CLASS (complete);
+	
+	if (klass->unichar_get_category)
+		return (* klass->unichar_get_category)(complete, letter);
+	else
+		return GOK_WORDCOMPLETE_CHAR_TYPE_NORMAL;
 }
 
 /**
-* gok_wordcomplete_add_prediction_keys
-*
-* @pKeyboard: Pointer to the keyboard that gets the new prediction keys.
-*
-* Adds a row of prediction keys to the given keyboard.
+ * gok_wordcomplete_process_unichar:
+ *
+ **/
+gchar *
+gok_wordcomplete_process_unichar (GokWordComplete *complete, gunichar letter)
+{
+	GokWordCompleteClass *klass = GOK_WORDCOMPLETE_GET_CLASS (complete);
+	if (klass->process_unichar)
+		(* klass->process_unichar) (complete, letter);
+}
+
+/**
+ *
+ **/
+gchar *
+gok_wordcomplete_get_word_part (GokWordComplete *complete)
+{
+	GokWordCompleteClass *klass = GOK_WORDCOMPLETE_GET_CLASS (complete);
+	if (klass->get_word_part)
+		return (* klass->get_word_part) (complete);
+	else
+		return NULL;
+}
+
+/**
+* gok_wordcomplete_process_and_predict:
+* 
+* Makes a prediction based on the effect of @letter on the current prediction state machine.
 *
-* returns: TRUE if the prediction keys were added, FALSE if not.
+* returns: An 
+array of strings representing the predicted completions.
 **/
-gboolean gok_wordcomplete_add_prediction_keys (GokKeyboard* pKeyboard)
+gchar **
+gok_wordcomplete_process_and_predict (GokWordComplete *complete, const gunichar letter)
 {
-	return gok_keyslotter_add_prediction_keys (pKeyboard, KEYTYPE_WORDCOMPLETE);
+	return gok_wordcomplete_predict_string (complete, 
+						gok_wordcomplete_process_unichar (complete, letter),
+						gok_data_get_num_predictions ());
 }
 
 /**
-* gok_wordcomplete_predict
+* gok_wordcomplete_predict_string:
 * 
 * Makes a prediction. If the currently displayed keyboard is showing prediction
 * keys then they are filled in with the predictions.
 *
-* returns: The number of words predicted.
+* returns: An 
+array of strings representing the predicted completions.
 **/
-int gok_wordcomplete_predict (const gunichar letter)
+gchar **
+gok_wordcomplete_predict_string (GokWordComplete *complete, const gchar *string, gint num_predictions)
 {
-	GokKeyboard* pKeyboard;
-	GokKey* pKey;
-	gint count;
-	gint length;
-	gint statusPrediction = 0;
-	gchar* pWordsPredicted = NULL;
-	gchar* token = NULL;
-	gchar separators[] = " ,\t\n";
-
-	/* is word completion turned on? */
-	if (gok_data_get_wordcomplete() == FALSE)
-	{
-		return 0;
-	}
-	
-	/* get the currently displayed keyboard */
-	pKeyboard = gok_main_get_current_keyboard();
-	
-	/* does it support word completion? */
-	if (gok_keyboard_get_supports_wordcomplete (pKeyboard) == FALSE)
-	{
-		return 0;
-	}
-
-	/* clear the current word predictions */
-	gok_wordcomplete_clear_keys();
-
-	if (word_part)
-		length = g_utf8_strlen (word_part, -1);
+	GokWordCompleteClass *klass = GOK_WORDCOMPLETE_GET_CLASS (complete);
+	if (klass->predict_string)
+		return (* klass->predict_string) (complete, string, num_predictions);
 	else
-		length = 0;
-
-
-	/* is this character a backspace, delete/rubout, or replace-char? */
-	if ((letter == 0x08) || (letter == 0x7f) || (letter == 0xfffd)) 
-	{
-		if (length > 0) 
-		{
-			--length;
-			* g_utf8_offset_to_pointer (word_part, length) = '\0';
-		}
-	}
-	else	/* add the letter to the current part word, subject to conditions below */
-	{
-	        gchar *tmp, utf8char[7]; /* min 6, plus NULL */
-
-		/* 
-		 * Is this whitespace, empty, punctuation, or nonprintable? Also catches NULL/0 
-		 * we make exception for U+00a0 (nonbreak space) so 'words' containing 
-		 * space can be handled. 
-		 */
-		if (!g_unichar_validate (letter) ||  /* if invalid, */
-		    ((g_unichar_ispunct (letter) || !g_unichar_isgraph (letter)) /* or punct/non-graphical, */
-		     && (letter != 0x00a0)) || /* but not nbspace */
-		    (letter == 0x2f)) /* or if destructive backspace */
-		{
-			/* reset the part word */
-			gok_wordcomplete_end_word ();		
-			return 0;
-		}
-		
-		utf8char [g_unichar_to_utf8 (letter, utf8char)] = '\0';
-		if (word_part) 
-		{
-			tmp = g_strconcat (word_part, utf8char, NULL);
-			g_free (word_part);
-			word_part = tmp;
-		}
-		else
-		{
-			word_part = g_strdup (utf8char);
-		}
-	}
-
-	/* make the prediction */
-	if (word_part) {
-		statusPrediction = WordCompletePredict (word_part, 
-							gok_data_get_num_predictions(), 
-							&pWordsPredicted);
-	}
-	if (statusPrediction != 0)
-	{
-		return 0;
-	}
-	
-	/* fill in the word completion keys */
-	count = 0;
-	pKey = pKeyboard->pKeyFirst;
-	if (pWordsPredicted)
-		token = strtok (pWordsPredicted, separators);
-	while (token != NULL)
-	{
-		/* make sure we're not going over our maximum predictions */
-		count++;
-		if (count > gok_data_get_num_predictions())
-		{
-			break;
-		}
-		
-		/* get the next word completion key on the keyboard */
-		while (pKey != NULL)
-		{
-			if (pKey->Type == KEYTYPE_WORDCOMPLETE)
-			{
-				gok_key_set_button_label (pKey, token);
-				gok_key_add_label (pKey, token, MODIFIER_NORMAL);
-								
-				pKey = pKey->pKeyNext;
-				break;
-			}
-			pKey = pKey->pKeyNext;
-		}
-		if (pKey == NULL)
-		{
-			break;
-		}
-		
-		/* get the next word predicted */
-		token = strtok (NULL, separators);
-	}
-	
-	/* change the font size for the word completion keys */
-	if (count > 0)
-	{
-		gok_keyboard_calculate_font_size_group (pKeyboard, FONT_SIZE_GROUP_WORDCOMPLETE, TRUE);
-	}
-	
-	return count;
+		return NULL;
 }
 
 /**
-* gok_wordcomplete_end_word
+* gok_wordcomplete_predict
 * 
-* Resets the part word buffer.
+* Makes a prediction. If the currently displayed keyboard is showing prediction
+* keys then they are filled in with the predictions.
 *
-* returns: void
+* returns: An 
+array of strings representing the predicted completions.
 **/
-void gok_wordcomplete_end_word ()
+gchar **
+gok_wordcomplete_predict (GokWordComplete *complete, gint num_predictions)
 {
-	g_free (word_part);
-	word_part = NULL;
+	GokWordCompleteClass *klass = GOK_WORDCOMPLETE_GET_CLASS (complete);
+	if (klass->predict)
+		(* klass->predict) (complete, num_predictions);
 }
 
 /**
-* gok_wordcomplete_clear_keys
+* gok_wordcomplete_reset
 * 
-* Clears the word completion keys on the current keyboard.
-* (The keys are still displayed, they just have no label or output.)
+* Resets the part word buffer.
 *
 * returns: void
 **/
-void gok_wordcomplete_clear_keys ()
+void 
+gok_wordcomplete_reset (GokWordComplete *complete)
 {
-	GokKeyboard* pKeyboard;
-	GokKey* pKey;
-	
-	/* get the currently displayed keyboard */
-	pKeyboard = gok_main_get_current_keyboard();
-	
-	/* clear the current word predictions */
-	pKey = pKeyboard->pKeyFirst;
-	while (pKey != NULL)
-	{
-		if (pKey->Type == KEYTYPE_WORDCOMPLETE)
-		{
-			gok_key_set_button_label (pKey, "");
-			gok_key_add_label (pKey, "", MODIFIER_NORMAL);
-			gok_key_set_output (pKey, 0, NULL, 0);
-		}
-		pKey = pKey->pKeyNext;
-	}
+	GokWordCompleteClass *klass = GOK_WORDCOMPLETE_GET_CLASS (complete);
+	if (klass->reset)
+		(* klass->reset) (complete);
 }
 
 /**
@@ -318,9 +279,13 @@
 *
 * returns: TRUE if the word was added to the dictionary, FALSE if not.
 **/
-gboolean gok_wordcomplete_add_new_word (const gchar* pWord)
+gboolean gok_wordcomplete_add_new_word (GokWordComplete *complete, const gchar* pWord)
 {
-        return WordCompleteAddNewWord (pWord);
+	GokWordCompleteClass *klass = GOK_WORDCOMPLETE_GET_CLASS (complete);
+	if (*klass->add_new_word)
+		return (* klass->add_new_word)(complete, pWord);
+	else
+		return FALSE;
 }
 
 /**
@@ -330,9 +295,14 @@
 *
 * returns: TRUE if the word's frequency was incremented, FALSE if not.
 **/
-gboolean gok_wordcomplete_increment_word_frequency (const gchar* pWord)
+gboolean 
+gok_wordcomplete_increment_word_frequency (GokWordComplete *complete, const gchar* pWord)
 {
-	return WordCompleteIncrementFrequency (pWord);
+	GokWordCompleteClass *klass = GOK_WORDCOMPLETE_GET_CLASS (complete);
+	if (*klass->increment_word_frequency)
+		return (* klass->increment_word_frequency)(complete, pWord);
+	else
+		return FALSE;
 }
 
 /**
@@ -344,12 +314,12 @@
 *
 * returns: A pointer to the output.
 **/
-GokOutput* gok_wordcomplete_get_output (GokKey* pKey)
+GokOutput* 
+gok_wordcomplete_get_output (GokWordComplete *complete, GokKey* pKey)
 {
-	GokOutput* pOutputNew;
-	GokOutput* pOutputListEnd;
+	/* FIXME: does this belong in gok-output.c instead? */
 	gchar* LabelText;
-	
+	gchar *word_part = gok_wordcomplete_get_word_part (complete);
 	g_assert (pKey != NULL);
 
 	/* make sure this is a word completion key */
@@ -359,11 +329,6 @@
 		return NULL;
 	}
 	
-	if (m_pOutputListStart != NULL)
-	{
-		gok_output_delete_all (m_pOutputListStart);
-	}
-	
 	/* subtract the part word from the output */
 	LabelText = gok_key_get_label (pKey);
 	if (LabelText == NULL)
@@ -371,9 +336,6 @@
 		return NULL;
 	}
 	
-	m_pOutputListStart = NULL;
-	pOutputListEnd = NULL;
-
 	if (word_part && (g_utf8_strlen (word_part, -1) < g_utf8_strlen (LabelText, -1)))
 	{
 		gchar *cp;
@@ -385,17 +347,8 @@
 		/* sanity check: is our word_part found in our label? */
 		if (cp) {
 			gint offset = strlen (word_part); /* in bytes, not chars */
-			pOutputNew = gok_output_new (OUTPUT_KEYSTRING, cp + offset, SPI_KEY_STRING);
-			if (m_pOutputListStart == NULL)
-			{
-				m_pOutputListStart = pOutputNew;
-				pOutputListEnd = pOutputNew;
-			}
-			else
-			{
-				pOutputListEnd->pOutputNext = pOutputNew;
-				pOutputListEnd = pOutputNew;
-			}
+			if (complete->priv->last_output) gok_output_delete_all (complete->priv->last_output);
+			complete->priv->last_output = gok_output_new (OUTPUT_KEYSTRING, cp + offset, SPI_KEY_STRING);
 		}
 		else {
 			/* if not then we are doing a 'replace', handle that via EditableText. */
@@ -403,6 +356,140 @@
 		}
 	}
 
-	return m_pOutputListStart;
+	return complete->priv->last_output;
 }
 
+/**
+ * gok_wordcomplete_get_default:
+ *
+ * Returns the current default word completion engine.
+ **/
+GokWordComplete*
+gok_wordcomplete_get_default (void)
+{
+	if (default_wordcomplete_engine == NULL)
+		default_wordcomplete_engine = g_object_new (GOK_TYPE_TRIEWORDCOMPLETE, NULL);  
+        /* TODO: establish default subtype and create type - making the base class abstract */
+	return default_wordcomplete_engine;
+}
+
+/* private methods */
+static gboolean 
+gok_wordcomplete_unichar_is_backspace (GokWordComplete *complete, gunichar letter) 
+{
+	return ((letter == 0x08) || (letter == 0x7f) || (letter == 0xfffd));
+}
+
+static gboolean
+gok_wordcomplete_unichar_is_delimiter (GokWordComplete *complete, gunichar letter)
+{		
+/* 
+ * Is this whitespace, empty, punctuation, or nonprintable? Also catches NULL/0 
+ * we make exception for U+00a0 (nonbreak space) so 'words' containing 
+ * space can be handled. 
+ */
+	return (!g_unichar_validate (letter) ||  /* if invalid, */
+		((g_unichar_ispunct (letter) || !g_unichar_isgraph (letter)) /* or punct/non-graphical, */
+		 && (letter != 0x00a0)) || /* but not nbspace */
+		(letter == 0x2f)); /* or if destructive backspace */
+}
+
+/* implementations of GokWordCompleteClass methods */
+static void 
+gok_wordcomplete_real_reset (GokWordComplete *complete)
+{
+	g_free (complete->priv->word_part);
+	complete->priv->word_part = NULL;
+}
+
+static gchar *
+gok_wordcomplete_real_unichar_push (GokWordComplete *complete, gunichar letter)
+{
+	gchar *tmp, utf8char[7]; /* min 6, plus NULL */
+	gchar *word_part = NULL;
+
+	if (complete && complete->priv) 
+	{
+		word_part = gok_wordcomplete_get_word_part (complete);
+		utf8char [g_unichar_to_utf8 (letter, utf8char)] = '\0';
+		if (word_part) 
+		{
+			tmp = g_strconcat (word_part, utf8char, NULL);
+			g_free (word_part);
+			word_part = tmp;
+		}
+		else
+		{
+			word_part = g_strdup (utf8char);
+		}
+		complete->priv->word_part = word_part;
+	}
+	return word_part;
+}
+
+static gchar *
+gok_wordcomplete_real_unichar_pop (GokWordComplete *complete)
+{
+	gint length = strlen (complete->priv->word_part);
+	*g_utf8_offset_to_pointer (complete->priv->word_part, --length) = '\0';
+	return complete->priv->word_part;
+}
+
+/**
+ * gok_wordcomplete_real_unichar_get_category
+ *
+ **/
+static GokWordCompletionCharacterCategory
+gok_wordcomplete_real_unichar_get_category (GokWordComplete *complete, gunichar letter)
+{
+	if (gok_wordcomplete_unichar_is_backspace (complete, letter))
+		return GOK_WORDCOMPLETE_CHAR_TYPE_BACKSPACE;
+	else if (gok_wordcomplete_unichar_is_delimiter (complete, letter))
+		return GOK_WORDCOMPLETE_CHAR_TYPE_DELIMITER;
+	else
+		return GOK_WORDCOMPLETE_CHAR_TYPE_NORMAL;
+}
+
+static gchar *
+gok_wordcomplete_real_process_unichar (GokWordComplete *complete, gunichar letter)
+{
+	gchar *prefix = NULL;
+	switch (gok_wordcomplete_unichar_get_category (complete, letter))
+	{
+	case GOK_WORDCOMPLETE_CHAR_TYPE_BACKSPACE:
+		prefix = gok_wordcomplete_unichar_pop (complete);
+		break;
+	case GOK_WORDCOMPLETE_CHAR_TYPE_DELIMITER:
+		gok_wordcomplete_reset (complete);
+		break;
+	case GOK_WORDCOMPLETE_CHAR_TYPE_NORMAL:
+	default:
+		prefix = gok_wordcomplete_unichar_push (complete, letter);
+		break;
+	}
+	return prefix;
+}
+
+static gchar *
+gok_wordcomplete_real_get_word_part (GokWordComplete *complete)
+{
+	if (complete && complete->priv)
+		return complete->priv->word_part;
+	else
+		return NULL;
+}
+
+/**
+* gok_wordcomplete_real_predict
+* 
+* Makes a prediction. If the currently displayed keyboard is showing prediction
+* keys then they are filled in with the predictions.
+*
+* returns: An array of strings representing the predicted completions.
+**/
+gchar **
+gok_wordcomplete_real_predict (GokWordComplete *complete, gint num_predictions)
+{
+	return gok_wordcomplete_predict_string (complete, num_predictions, 
+						gok_wordcomplete_get_word_part (complete));
+}
Index: gok/gok-word-complete.h
===================================================================
RCS file: /cvs/gnome/gok/gok/gok-word-complete.h,v
retrieving revision 1.9
diff -u -r1.9 gok-word-complete.h
--- gok/gok-word-complete.h	12 Jun 2003 13:34:41 -0000	1.9
+++ gok/gok-word-complete.h	29 Sep 2003 21:44:59 -0000
@@ -23,26 +23,78 @@
 #define __GOKWORDCOMPLETE_H__
 
 #include "gok-keyboard.h"
-#include "word-complete.h"
 #include "gok-output.h"
 
 #ifdef __cplusplus
 extern "C" {
 #endif /* __cplusplus */
 
-gboolean gok_wordcomplete_open (gchar *directory);
-void gok_wordcomplete_close (void);
-void gok_wordcomplete_on (gboolean bTrueFalse);
-void gok_wordcomplete_change_number_predictions (int number);
-int gok_wordcomplete_predict (const gunichar letter);
-gboolean gok_wordcomplete_add_new_word (const char* pWord);
-gboolean gok_wordcomplete_add_prediction_keys (GokKeyboard* pKeyboard);
-GokOutput* gok_wordcomplete_get_output (GokKey* pKey);
-void gok_wordcomplete_clear_keys (void);
-void gok_wordcomplete_end_word (void);
+typedef enum {
+	GOK_WORDCOMPLETE_CHAR_TYPE_NORMAL,
+	GOK_WORDCOMPLETE_CHAR_TYPE_BACKSPACE,
+	GOK_WORDCOMPLETE_CHAR_TYPE_DELIMITER
+} GokWordCompletionCharacterCategory;
+
+#define GOK_TYPE_WORDCOMPLETE           (gok_wordcomplete_get_type ())
+#define GOK_WORDCOMPLETE(obj)           (G_TYPE_CHECK_INSTANCE_CAST ((obj), GOK_TYPE_WORDCOMPLETE, GokWordComplete))
+#define GOK_WORDCOMPLETE_CLASS(klass)  G_TYPE_CHECK_CLASS_CAST (klass, GOK_TYPE_WORDCOMPLETE, GokWordCompleteClass)
+#define GOK_IS_WORDCOMPLETE(obj)       G_TYPE_CHECK_INSTANCE_TYPE (obj, GOK_TYPE_WORDCOMPLETE)
+#define GOK_IS_WORDCOMPLETE_CLASS(klass)       G_TYPE_CHECK_CLASS_TYPE (klass, GOK_TYPE_WORDCOMPLETE)
+#define GOK_WORDCOMPLETE_GET_CLASS(obj)       (G_TYPE_INSTANCE_GET_CLASS ((obj), GOK_TYPE_WORDCOMPLETE, GokWordCompleteClass))
+
+typedef struct _GokWordComplete       GokWordComplete;
+typedef struct _GokWordCompleteClass  GokWordCompleteClass;
+typedef struct _GokWordCompletePrivate GokWordCompletePrivate;
+
+struct _GokWordComplete
+{
+	GObject parent;
+	GokWordCompletePrivate *priv;
+};
+
+struct _GokWordCompleteClass
+{
+	GObjectClass parent_class;
+
+	/* public */
+	gboolean  (* open)         (GokWordComplete *complete,
+				    const gchar *directory);
+	void      (* close)        (GokWordComplete *complete);
+	gchar*    (* process_unichar) (GokWordComplete *complete, gunichar letter);
+	void      (* reset)        (GokWordComplete *complete);
+	gchar**   (* predict)      (GokWordComplete *complete, gint num_predictions);
+	gchar**   (* predict_string) (GokWordComplete *complete, const gchar *utf8_string,
+				      gint num_predictions);
+	gboolean  (* add_new_word) (GokWordComplete *complete,
+				    const gchar *utf8_word);
+	gboolean  (* increment_word_frequency) (GokWordComplete *complete,
+						const gchar *word);
+
+	/* private use */
+	gchar*    (* unichar_pop) (GokWordComplete *complete);
+	gchar*    (* unichar_push) (GokWordComplete *complete, gunichar letter);
+	GokWordCompletionCharacterCategory (* unichar_get_category) (GokWordComplete *complete, gunichar letter);
+	gchar*    (* get_word_part) (GokWordComplete *complete);
+};
+
+gboolean gok_wordcomplete_open           (GokWordComplete *complete, gchar *directory);
+void     gok_wordcomplete_close          (GokWordComplete *complete);
+void     gok_wordcomplete_reset          (GokWordComplete *complete);
+gchar**  gok_wordcomplete_predict        (GokWordComplete *complete, gint num_predictions);
+gchar*   gok_wordcomplete_process_unichar(GokWordComplete *complete, const gunichar letter);
+gchar**  gok_wordcomplete_predict_string (GokWordComplete *complete, const gchar *string, 
+					  gint num_predictions);
+
+gboolean gok_wordcomplete_add_new_word   (GokWordComplete *complete, const char* word);
+
+/* TODO: move this to gok-output! */
+GokOutput* gok_wordcomplete_get_output   (GokWordComplete *complete, GokKey* key);
+
+GokWordComplete *gok_wordcomplete_get_default (void);
+gchar**  gok_wordcomplete_process_and_predict (GokWordComplete *complete, const gunichar letter);
 
 #ifdef __cplusplus
 }
 #endif /* __cplusplus */
 
-#endif // #ifndef __GOKWORDCOMPLETE_H__
+#endif /* #ifndef __GOKWORDCOMPLETE_H__ */
Index: gok/main.c
===================================================================
RCS file: /cvs/gnome/gok/gok/main.c,v
retrieving revision 1.111
diff -u -r1.111 main.c
--- gok/main.c	18 Sep 2003 16:01:52 -0000	1.111
+++ gok/main.c	29 Sep 2003 21:45:02 -0000
@@ -641,8 +641,7 @@
 		gok_scanner_start();
 	}
 
-	/* hack to make sure gok is not occluded - seems to be unstable*/
-	gdk_window_raise (m_pWindowMain->window);
+	gok_main_raise_window ();
 
 	gok_log_leave();	
 }
@@ -715,9 +714,8 @@
 
 	if (state == 0)
 	{
-		/* hack to make sure gok is not occluded - TODO: seems to be unstable*/
-		gdk_window_raise (m_pWindowMain->window);
-		
+		gok_main_raise_window ();
+
 		switch (button)
 		{
 			case 1:
@@ -769,6 +767,20 @@
 }
 
 /**
+ * gok_main_raise_window:
+ * hack to make sure gok is not occluded - TODO: seems to be unstable
+ *
+ **/
+void
+gok_main_raise_window (void)
+{
+	if (m_pWindowMain && m_pWindowMain->window) 
+	{
+		gdk_window_raise (m_pWindowMain->window);
+	}
+}
+
+/**
 * gok_main_mouse_button_listener
 * @button: Mouse button number that has changed state.
 * @state: State of the button.
@@ -784,8 +796,7 @@
 
 	if (state == 0)
 	{
-		/* hack to make sure gok is not occluded - TODO: seems to be unstable*/
-		gdk_window_raise (m_pWindowMain->window);
+		gok_main_raise_window ();
 
 		/* TODO: account for reversed button order, which is possible! 
 		 * i.e. leftbutton == 3, etc.
@@ -1126,8 +1137,7 @@
 	gok_scanner_stop();
 
 	/* raise the window as a precaution */
-	if (m_pWindowMain && m_pWindowMain->window)
-		gdk_window_raise (m_pWindowMain->window);
+	gok_main_raise_window ();
 
 	/* create new keys for dynamic keyboards */
 	if (pKeyboard->bDynamicallyCreated == TRUE)
@@ -1365,6 +1375,7 @@
 	/* create the default "core" keyboard (aka qwerty keyboard) */
 	if (gok_data_get_use_xkb_kbd ()) {
 		pKeyboard = pKeyboardFirst = gok_keyboard_get_core ();
+		/* pKeyboard = pKeyboardFirst = gok_keyboard_get_alpha_by_frequency (); *//* TESTING ONLY!!!! */
 		pKeyboard->pKeyboardPrevious = NULL;
 		pKeyboardPrevious = pKeyboard;
 	}
@@ -1476,7 +1487,8 @@
     }
     else
     {
-	if ( !(gok_wordcomplete_open (directory_name)) ) {
+	if ( !(gok_wordcomplete_open (gok_wordcomplete_get_default (),
+				      directory_name)) ) {
 	    gok_log_x ("Error initializing word completion");
 	}
 	
@@ -1841,7 +1853,7 @@
 	gok_action_close();
 	gok_feedback_close();
 	gok_control_button_callback_close();
-	gok_wordcomplete_close();
+	gok_wordcomplete_close(gok_wordcomplete_get_default ());
 	gok_predictor_close(m_pCommandPredictor);
 	
 	_exit(0);
Index: gok/main.h
===================================================================
RCS file: /cvs/gnome/gok/gok/main.h,v
retrieving revision 1.34
diff -u -r1.34 main.h
--- gok/main.h	15 Jul 2003 15:21:05 -0000	1.34
+++ gok/main.h	29 Sep 2003 21:45:02 -0000
@@ -36,6 +36,7 @@
 GtkWidget* gok_main_create_window (gboolean is_dock);
 void gok_main_set_cursor (GdkCursor *cursor);
 gint gok_main_open(gint argc, gchar *argv[]);
+void gok_main_raise_window (void);
 GokKeyboard *gok_main_keyboard_find_byname (const gchar* NameKeyboard);
 gboolean gok_main_display_scan (GokKeyboard* pKeyboard, char* NameKeyboard, KeyboardTypes keyboardType, KeyboardLayouts layoutType);
 gboolean gok_main_display_scan_previous (void);
Index: gok/word-complete.c
===================================================================
RCS file: /cvs/gnome/gok/gok/word-complete.c,v
retrieving revision 1.11
diff -u -r1.11 word-complete.c
--- gok/word-complete.c	30 Jun 2003 12:43:22 -0000	1.11
+++ gok/word-complete.c	29 Sep 2003 21:45:03 -0000
@@ -20,7 +20,7 @@
 *
 * To use this thing:
 * - Call "WordCompleteOpen". If it returns TRUE then you're ready to go.
-* - Call "WordCompletePredict" to make the word predictions.
+* - Call "WordCompletePredictString" to make the word predictions.
 * - Call "WordCompleteClose" when you're done. 
 * - To add a word, call "WordCompleteAddNewWord".
 *
@@ -32,6 +32,32 @@
 #include <ctype.h>
 #include "gok-log.h"
 
+/* private functions */
+static gchar    WordCompleteSaveDictionary     (void);
+static gint     WordCompleteSaveLoop           (Node* pDictLetter, gchar* pWord, FILE* pFile);
+static void     WordCompletePredictLoop        (const gchar* pWord, Node* pNode, gchar* pPrediction);
+static void     WordCompleteDeleteChildren     (Node* pNode);
+static gboolean WordCompleteAddWord            (GokWordComplete *complete, 
+						const gchar* pWord, gint priority, gint state);
+static Node*    WordCompleteAddLetter          (Node* pNode, gchar letter);
+static void     WordCompleteAddPrediction      (gchar* pWord, gint priority);
+
+/* implementations of GokWordCompleteClass virtual methods */
+static gboolean WordCompleteAddNewWord         (GokWordComplete *complete, const gchar* pWord);
+static gboolean WordCompleteIncrementFrequency (GokWordComplete *complete, const gchar *pWord);
+static gboolean WordCompleteOpen               (GokWordComplete *complete, const gchar *dictionary);
+static void     WordCompleteClose              (GokWordComplete *complete);
+static gchar**  WordCompletePredictString      (GokWordComplete *complete, const gchar* pWord, gint numberPredictions);
+
+/* a prediction */
+struct PredictNode
+{
+	gchar word[MAXWORDLENGTH];
+	gint priority;
+};
+
+typedef struct PredictNode Prediction;
+
 typedef enum 
 {
 	WORD_CASE_LOWER,
@@ -59,6 +85,29 @@
 /* The filename of the dictionary file */
 static gchar *dictionary_full_path;
 
+/* 
+ * This macro initializes GokTrieWordComplete with the GType system 
+ *   and defines ..._class_init and ..._instance_init functions 
+ */
+GNOME_CLASS_BOILERPLATE (GokTrieWordComplete, gok_trie_wordcomplete,
+			 GokWordComplete, GOK_TYPE_WORDCOMPLETE)
+
+static void
+gok_trie_wordcomplete_instance_init (GokTrieWordComplete *complete)
+{
+}
+
+static void
+gok_trie_wordcomplete_class_init (GokTrieWordCompleteClass *klass)
+{
+	GokWordCompleteClass *word_complete_class = (GokWordCompleteClass *) klass;
+	word_complete_class->open = WordCompleteOpen;
+	word_complete_class->close = WordCompleteClose;
+	word_complete_class->increment_word_frequency = WordCompleteIncrementFrequency;
+	word_complete_class->add_new_word = WordCompleteAddNewWord;
+	word_complete_class->predict_string = WordCompletePredictString;
+}
+
 /*
  * WordCompleteOpen
  *
@@ -73,7 +122,8 @@
  * field 3 - the word's state
  * Example: "the 500 2"
  */
-char WordCompleteOpen(const gchar *directory)
+static gboolean
+WordCompleteOpen(GokWordComplete *complete, const gchar *directory)
 {
 	FILE *pFile;
 	gchar buffer[100];/* will hold each line of the file */
@@ -88,6 +138,7 @@
 	{
 		/* calling "Open" after it's already been opened! */
 		gok_log_x ("Calling 'Open' after WordComplete is already open!\n");
+		gok_wordcomplete_reset (complete); /* reset, anyhow */
 		return TRUE;
 	}
 
@@ -101,6 +152,9 @@
 	m_FirstNode.pNextNode = NULL;
 	m_FirstNode.pFirstChildNode = NULL;
 
+	/* prepare the key slotter */
+	gok_keyslotter_on(gok_data_get_wordcomplete (), KEYTYPE_WORDCOMPLETE);
+
 	/* open the dictionary file */
 	dictionary_full_path = g_build_filename (directory, "dictionary.txt", NULL);
 	pFile = fopen (dictionary_full_path, "rt");
@@ -159,7 +213,7 @@
 		}
 
 		/* add it to the array of words */
-		WordCompleteAddWord (pWord, atoi (pPriority), atoi (pState));
+		WordCompleteAddWord (complete, pWord, atoi (pPriority), atoi (pState));
 	}
 
 	fclose (pFile);
@@ -174,7 +228,8 @@
  * Adds a word to the trie structure.
  * Returns TRUE if it was added, FALSE if not.
  */
-char WordCompleteAddWord (gchar* pWord, gint priority, gint state)
+static gboolean 
+WordCompleteAddWord (GokWordComplete *complete, const gchar* pWord, gint priority, gint state)
 {
 	/* this will eventually hold the final node (last letter) of the word */
 	Node* pNode;
@@ -215,7 +270,8 @@
  * FIXME: Not UTF-8 safe! letter should be a gunichar or 
  * utf-8 stringlet.
  */
-Node* WordCompleteAddLetter (Node* pNode, gchar letter)
+static Node* 
+WordCompleteAddLetter (Node* pNode, gchar letter)
 {
 	Node* pCurrentNode;
 	Node* pPreviousNode;
@@ -280,7 +336,8 @@
  * Call this when done using the predictor.
  * If this is not called then memory leaks will result!
  */
-void WordCompleteClose()
+static void 
+WordCompleteClose(GokWordComplete *complete)
 {
 	Node* pDictLetter;
 	Node* pLastLetter;
@@ -316,7 +373,8 @@
  * Deletes all the children of this node.
  * This is recursive so all the children's children are deleted too.
  */
-void WordCompleteDeleteChildren (Node* pParentNode)
+static void 
+WordCompleteDeleteChildren (Node* pParentNode)
 {
 	Node* pTempNode;
 	Node* pNode;
@@ -435,27 +493,21 @@
  * WordCompletePredict
  *
  * Makes word predictions based upon the part word given.
- * Returns an error code:
- * 0 - no error and at least one prediction has been made
- * 1 - no error but no predictions made
- * 2 - numberPredictions out of range
- * 3 - pWord is NULL
+ * Returns an array of strings which are the predictions, or NULL if no predictions were made.
  *
  * pWord - [in] the part word we want to complete
  * numberPredictions - [in] maximum number of predictions to return
- * pPredictions - [out] pointer to the string that holds the predictions
- *
- * Note: The char** "pPredictions" should NOT be freed by the caller.
- *
- * The predictions are returned as a string of words, separated by tabs.
- * Example: "the	there	then	thus"
- *
  */
-int WordCompletePredict (const gchar* pWord, gint numberPredictions, gchar** pPredictions)
+static gchar**
+WordCompletePredictString (GokWordComplete *complete, const gchar* pWord, gint numberPredictions)
 {
+	gchar **word_predict_list = NULL;
+
+	/* make the prediction */
+
 	gchar bufferLowercase[MAXWORDLENGTH + 1];
 	gint lengthWord;
-	gint count, x, y;
+	gint count, i, j;
 	gchar* pWordLowercase;
 	gchar buffer [MAXWORDLENGTH + 1];
 
@@ -470,19 +522,21 @@
 	/* validate the given values */
 	if (pWord == NULL)
 	{
-	  return 3;
+	  return NULL;
 	}
 
 	if ((numberPredictions < 1) ||
 	   (numberPredictions > MAXPREDICTIONS))
 	{
-	  return 2;
+	  return NULL;
 	}
 
+	word_predict_list = g_new0 (gchar *, numberPredictions);
+
 	/* initialize the array */
-	for (x = 0; x < MAXPREDICTIONS; x++)
+	for (i = 0; i < MAXPREDICTIONS; i++)
 	{
-	  m_Predictions[x].priority = 0;
+	  m_Predictions[i].priority = 0;
 	}
 
 	/* convert the given string to lowercase (cuz our dictionary is all lower case) */
@@ -514,17 +568,17 @@
 
 	/* look through our array of predictions and find the highest priority ones */
 	bMadePrediction = FALSE;
-	m_buffer[0] = 0;
-	for (x = 0; x < numberPredictions; x++)
+
+	for (i = 0; i < numberPredictions; i++)
 	{
 		highPriority = 0;
 		highPriorityIndex = -1;
-		for (y = 0; y < MAXPREDICTIONS; y++)
+		for (j = 0; j < MAXPREDICTIONS; j++)
 		{
-			if (m_Predictions[y].priority > highPriority)
+			if (m_Predictions[j].priority > highPriority)
 			{
-				highPriority = m_Predictions[y].priority;
-				highPriorityIndex = y;
+				highPriority = m_Predictions[j].priority;
+				highPriorityIndex = j;
 			}
 		}
 		if (highPriorityIndex == -1)
@@ -532,31 +586,23 @@
 		  break;
 		}
 
-		/* seperate the words by a tab character */
-		if (m_buffer[0] != 0)
-		{
-		  strcat (m_buffer, "\t");
-		}
-
 		/* add the prediction word to our buffer */
-		strcat (m_buffer, m_Predictions[highPriorityIndex].word);
+		word_predict_list[i] = strdup (m_Predictions[highPriorityIndex].word);
 		m_Predictions[highPriorityIndex].priority = 0;
 		bMadePrediction = TRUE;
 	}
 
-	/* return a pointer to our buffer that holds the string of predictions */
-	pPredictions[0] = m_buffer;
-
 	/* were there any predictions? */
 	if (bMadePrediction == FALSE)
 	{
-	  return 1; /* indicates no predictions made */
+		g_free (word_predict_list);
+ 	        return NULL; /* indicates no predictions made */
 	}
 
 	/* post-process the predictions to match the case of the input */
-	WordCompleteApplyCase (pWord, pPredictions, numberPredictions);
+	WordCompleteApplyCase (pWord, word_predict_list, numberPredictions);
 
-	return 0; /* predictions made! */
+	return word_predict_list; /* predictions made! */
 }
 
 /*
@@ -566,7 +612,8 @@
  * This function is recursive.
  * Each word is stored in an array by calling "AddPrediction".
  */
-void WordCompletePredictLoop (const gchar* pWordGiven, Node* pNode, gchar* pPrediction)
+static void 
+WordCompletePredictLoop (const gchar* pWordGiven, Node* pNode, gchar* pPrediction)
 {
 	if (pNode != NULL)
 	{
@@ -626,7 +673,8 @@
  * the predictions. After going through the entire trie, pick the highest
  * priority predictions from this array and return them to the caller.
  */
-void WordCompleteAddPrediction (gchar* pWord, gint priority)
+static void 
+WordCompleteAddPrediction (gchar* pWord, gint priority)
 {
     gint x;
     gint lowPriorityIndex;
@@ -672,11 +720,12 @@
  * WordCompleteAddNewWord
  *
  */
-char WordCompleteAddNewWord (gchar* pWord)
+static gboolean 
+WordCompleteAddNewWord (GokWordComplete *complete, const gchar* pWord)
 {
 	bWordCompleteModified = TRUE;
 
-	return WordCompleteAddWord (pWord, PRIORITY_NEWWORD, STATE_TEMPORARY);
+	return WordCompleteAddWord (complete, pWord, PRIORITY_NEWWORD, STATE_TEMPORARY);
 }
 
 static Node*
@@ -702,16 +751,14 @@
  * WordCompleteIncrementFrequency
  *
  */
-gboolean 
-WordCompleteIncrementFrequency (const gchar *pWord)
+static gboolean 
+WordCompleteIncrementFrequency (GokWordComplete *complete, const gchar *pWord)
 {
 	Node *node;
 	if (pWord) {
 		node = WordCompleteMatchingLeaf (&m_FirstNode, pWord);
-		fprintf (stderr, "node for %s: %p\n", pWord, node);
 		if (node && node->priority) {
 			++node->priority;
-			fprintf (stderr, "priority of %s is now %d\n", pWord, node->priority);
 			bWordCompleteModified = TRUE;
 			return TRUE;
 		}
@@ -725,7 +772,8 @@
  * Saves the entire dictionary to disk.
  * Returns TRUE if saved OK, FALSE if dictionary was not saved.
  */
-char WordCompleteSaveDictionary()
+static char 
+WordCompleteSaveDictionary()
 {
 	FILE* pFile;
 	Node* pNode;
@@ -768,7 +816,8 @@
  *
  * Recursive loop for saving all dictionary words to disk.
  */
-int WordCompleteSaveLoop (Node* pNode, gchar* pBuffer, FILE* pFile)
+static int 
+WordCompleteSaveLoop (Node* pNode, gchar* pBuffer, FILE* pFile)
 {
     gint lengthWord;
     Node* pLetter;
Index: gok/word-complete.h
===================================================================
RCS file: /cvs/gnome/gok/gok/word-complete.h,v
retrieving revision 1.7
diff -u -r1.7 word-complete.h
--- gok/word-complete.h	28 Feb 2003 16:11:09 -0000	1.7
+++ gok/word-complete.h	29 Sep 2003 21:45:03 -0000
@@ -32,6 +32,7 @@
 #include <stdio.h>
 #include <stdlib.h>
 #include <gtk/gtk.h>
+#include <gok/gok-word-complete.h>
 
 /* maximum length of a word in the dictionary */
 #define MAXWORDLENGTH 30
@@ -54,6 +55,26 @@
 #define TRUE    (!FALSE)
 #endif
 
+
+#define GOK_TYPE_TRIEWORDCOMPLETE           (gok_trie_wordcomplete_get_type ())
+#define GOK_TRIEWORDCOMPLETE(obj)           (G_TYPE_CHECK_INSTANCE_CAST ((obj), GOK_TYPE_TRIEWORDCOMPLETE, GokTrieWordComplete))
+#define GOK_TRIEWORDCOMPLETE_CLASS(klass)  G_TYPE_CHECK_CLASS_CAST (klass, GOK_TYPE_TRIEWORDCOMPLETE, GokTrieWordCompleteClass)
+#define GOK_IS_TRIEWORDCOMPLETE(obj)       G_TYPE_CHECK_INSTANCE_TYPE (obj, GOK_TYPE_TRIEWORDCOMPLETE)
+#define GOK_IS_TRIEWORDCOMPLETE_CLASS(klass)       G_TYPE_CHECK_CLASS_TYPE (klass, GOK_TYPE_TRIEWORDCOMPLETE)
+
+typedef struct _GokTrieWordComplete       GokTrieWordComplete;
+typedef struct _GokTrieWordCompleteClass  GokTrieWordCompleteClass;
+
+struct _GokTrieWordComplete
+{
+	GokWordComplete parent;
+};
+
+struct _GokTrieWordCompleteClass
+{
+	GokWordCompleteClass parent_class;
+};
+
 /* a node in the trie */
 struct NodeStruct
 {
@@ -65,27 +86,4 @@
 };
 typedef struct NodeStruct Node;
 
-/* a prediction */
-struct PredictNode
-{
-	gchar word[MAXWORDLENGTH];
-	gint priority;
-};
-typedef struct PredictNode Prediction;
-
-/* public functions */
-gchar WordCompleteOpen (const gchar *directory);
-void WordCompleteClose (void);
-gint WordCompletePredict (const gchar* pWord, gint numberPredictions, gchar** Predictions);
-gchar WordCompleteAddNewWord (gchar* pWord);
-
-/* private functions */
-gchar WordCompleteSaveDictionary (void);
-gint WordCompleteSaveLoop (Node* pDictLetter, gchar* pWord, FILE* pFile);
-void WordCompletePredictLoop (const gchar* pWord, Node* pNode, gchar* pPrediction);
-void WordCompleteDeleteChildren (Node* pNode);
-gchar WordCompleteAddWord (gchar* pWord, gint priority, gint state);
-Node* WordCompleteAddLetter (Node* pNode, gchar letter);
-void WordCompleteAddPrediction (gchar* pWord, gint priority);
-
-#endif // #ifndef __WORDCOMPLETE_H__
+#endif /* #ifndef __WORDCOMPLETE_H__ */
