/*****************************************************************************/ /* Klavaro - a flexible touch typing tutor */ /* Copyright (C) 2005, 2006, 2007, 2008 Felipe Castro */ /* Copyright (C) 2009, 2010, 2011 Free Software Foundation */ /* */ /* This program is free software, licensed under the terms of the GNU */ /* General Public License as published by the Free Software Foundation, */ /* either version 3 of the License, or (at your option) any later version. */ /* You should have received a copy of the GNU General Public License */ /* along with this program. If not, see . */ /*****************************************************************************/ /* * Klavaro is a touch typing tutor and exercise program. * Copyright (C) 2007 - Felipe E. F. de Castro */ #include #include #include #include #include #include #include #include #include "auxiliar.h" #include "callbacks.h" #include "translation.h" #include "keyboard.h" #include "tutor.h" #include "accuracy.h" #include "top10.h" #include "main.h" /******************************************************************************* * Variables */ GtkBuilder *gui; gchar *KEYB_CUSTOM; gchar *KEYB_EDIT; gchar *OTHER_DEFAULT; static GKeyFile *preferences = NULL; static gboolean curl_ok; static struct { gchar *user; gchar *stats; gchar *data; gchar *score; } path; /******************************************************************************* * Interface functions */ gchar * main_path_user () { return (path.user); } gchar * main_path_stats () { return (path.stats); } gchar * main_path_data () { return (path.data); } gchar * main_path_score () { return (path.score); } gboolean main_curl_ok () { return (curl_ok); } gboolean main_preferences_exist (gchar * group, gchar * key) { return (g_key_file_has_key (preferences, group, key, NULL)); } void main_preferences_remove (gchar * group, gchar * key) { g_key_file_remove_key (preferences, group, key, NULL); } gchar * main_preferences_get_string (gchar * group, gchar * key) { return (g_key_file_get_string (preferences, group, key, NULL)); } void main_preferences_set_string (gchar * group, gchar * key, gchar * value) { g_key_file_set_string (preferences, group, key, value); } gint main_preferences_get_int (gchar * group, gchar * key) { return (g_key_file_get_integer (preferences, group, key, NULL)); } void main_preferences_set_int (gchar * group, gchar * key, gint value) { g_key_file_set_integer (preferences, group, key, value); } gboolean main_preferences_get_boolean (gchar * group, gchar * key) { return (g_key_file_get_boolean (preferences, group, key, NULL)); } void main_preferences_set_boolean (gchar * group, gchar * key, gboolean value) { g_key_file_set_boolean (preferences, group, key, value); } void main_preferences_save () { gchar *tmp_name; FILE *fh; /* * Save preferences */ assert_user_dir (); tmp_name = g_build_filename (main_path_user (), "preferences.ini", NULL); fh = (FILE *) g_fopen (tmp_name, "w"); if (fh == NULL) g_warning ("couldn't save your preferences at the user folder:\n %s", tmp_name); else { g_free (tmp_name); tmp_name = NULL; tmp_name = g_key_file_to_data (preferences, NULL, NULL); if (tmp_name != NULL) fputs (tmp_name, fh); else g_warning ("couldn't save your preferences at the user folder:\n %s", tmp_name); fclose (fh); } g_free (tmp_name); } /* * End of interface, start of private functions */ static void main_stats_relocate (gchar * fname) { gchar *old; gchar *new; g_assert (fname); old = g_build_filename (main_path_user (), fname, NULL); if (!g_file_test (old, G_FILE_TEST_IS_REGULAR)) { g_free (old); return; } new = g_build_filename (main_path_stats (), fname, NULL); if (g_rename (old, new) != 0) g_print ("Failed to relocate stats file.\n\tCheck your old file: %s\n\tNew location to be used:%s\n", old, new); else g_print ("File relocated.\n\tFrom: %s\n\tTo: %s\n", old, new); g_free (old); g_free (new); } /********************************************************************** * Initialize the value of the global variables */ static void main_initialize_global_variables () { gchar *tmp; gchar *path_score_old; gchar *fname; gint chr; FILE *fh; FILE *fh_from; FILE *fh_to; GDir *kscdir; /* Set the home user dir */ path.user = g_build_filename (g_get_user_config_dir (), "klavaro", NULL); if (!g_file_test (path.user, G_FILE_TEST_IS_DIR)) { if (g_mkdir_with_parents (path.user, DIR_PERM) == -1) g_error ("Sorry, not able to create the user config dir: %s", path.user); } /* Set the home user stats dir (update to new local/share dir) */ if (UNIX_OK) path.stats = g_build_filename (g_get_user_data_dir (), "klavaro", NULL); else path.stats = g_build_filename (g_get_user_config_dir (), "klavaro", NULL); if (!g_file_test (path.stats, G_FILE_TEST_IS_DIR)) { g_mkdir_with_parents (path.stats, DIR_PERM); main_stats_relocate ("stat_basic.txt"); main_stats_relocate ("stat_adapt.txt"); main_stats_relocate ("stat_velo.txt"); main_stats_relocate ("stat_fluid.txt"); main_stats_relocate ("scores_fluid.txt"); main_stats_relocate ("deviation_fluid.txt"); } /* Get a valid data path. * First searches the path at the source directory. */ path.data = g_build_filename ("..", "data", NULL); tmp = g_build_filename (path.data, "basic_lessons.txt", NULL); fh = (FILE *) g_fopen (tmp, "r"); if (fh == NULL) { g_free (path.data); g_free (tmp); path.data = g_build_filename (PACKAGE_DATA_DIR, PACKAGE, NULL); tmp = g_build_filename (path.data, "basic_lessons.txt", NULL); fh = (FILE *) g_fopen (tmp, "r"); } if (fh == NULL) g_error ("couldn't find a data file at the data path:\n %s", tmp); fclose (fh); g_free (tmp); /* Get a valid scoring path. * Updating from /var/games/klavaro to $XDG_USER_DATA_DIR/klavaro/ksc */ if (UNIX_OK) path_score_old = g_strdup ("/var/games/klavaro"); else path_score_old = g_build_filename ((g_get_system_data_dirs ())[0], PACKAGE, NULL); path.score = g_build_filename (path.stats, "ksc", NULL); if (!g_file_test (path.score, G_FILE_TEST_IS_DIR)) { g_mkdir_with_parents (path.score, DIR_PERM); kscdir = g_dir_open (path_score_old, 0, NULL); if (kscdir) { while ((fname = (gchar *) g_dir_read_name (kscdir))) { if (!g_str_has_suffix (fname, ".ksc")) continue; tmp = g_build_filename (path_score_old, fname, NULL); fh_from = g_fopen (tmp, "rb"); g_free (tmp); if (!fh_from) continue; tmp = g_build_filename (path.score, fname, NULL); fh_to = g_fopen (tmp, "wb"); g_free (tmp); if (!fh_to) { fclose (fh_from); continue; } // Copy from to while ((chr = getc (fh_from)) != EOF) putc (chr, fh_to); fclose (fh_from); fclose (fh_to); } g_dir_close (kscdir); } } //g_message (path.score); /* Retrieve initial or saved preferences */ preferences = g_key_file_new (); tmp = g_build_filename (main_path_user (), "preferences.ini", NULL); if (!g_file_test (tmp, G_FILE_TEST_EXISTS)) { g_free (tmp); tmp = g_strdup ("/etc/klavaro_preferences.ini"); } g_key_file_load_from_file (preferences, tmp, G_KEY_FILE_NONE, NULL); g_free (tmp); /* Other initializations */ trans_init_lang_name_code (); trans_init_language_env (); srand (time (0)); tutor_init_timers (); accur_init (); KEYB_CUSTOM = g_strdup (_("(Custom)")); KEYB_EDIT = g_strdup (_("(Edit custom)")); OTHER_DEFAULT = g_strdup (_("(Default)")); } static void main_gtkbuilder_translation_workaround () { gchar *lb; GSList *ls; GSList *it; GtkWidget *wg; ls = gtk_builder_get_objects (gui); it = ls; do { if (GTK_OBJECT_TYPE (it->data) == GTK_TYPE_LABEL) { lb = (gchar *) gtk_label_get_label (GTK_LABEL (it->data)); if (lb[0] != '\0') gtk_label_set_text_with_mnemonic (GTK_LABEL (it->data), _(lb)); } else if (GTK_OBJECT_TYPE (it->data) == GTK_TYPE_ENTRY) { lb = gtk_entry_get_icon_tooltip_text (GTK_ENTRY (it->data), GTK_ENTRY_ICON_SECONDARY); if (lb) { if (lb[0] != '\0') gtk_entry_set_icon_tooltip_text (GTK_ENTRY (it->data), GTK_ENTRY_ICON_SECONDARY, _(lb)); } } else if (GTK_OBJECT_TYPE (it->data) == GTK_TYPE_WINDOW) gtk_window_set_title (GTK_WINDOW (it->data), _(gtk_window_get_title (GTK_WINDOW (it->data)))); if (GTK_IS_WIDGET (it->data)) { wg = GTK_WIDGET (it->data); if (gtk_widget_get_has_tooltip (wg)) gtk_widget_set_tooltip_text (wg, _(gtk_widget_get_tooltip_text (wg))); } it = g_slist_next (it); } while (it); g_slist_free (ls); } /******************************************************************************* * Initialize some interface widgets */ static void main_window_init () { gchar *tmp; gchar *ttip; PangoAttrList *palist; /* Workaround to make GtkBuilder translate all text, on Windows :-( */ if (! UNIX_OK) main_gtkbuilder_translation_workaround (); /* Set the language */ trans_set_combo_language (); /* Set keyboard */ keyb_create_virtual_keys (); hints_init (); /* Set if speech is enabled */ callbacks_shield_set (TRUE); if (!main_preferences_exist ("interface", "speech")) main_preferences_set_boolean ("interface", "speech", TRUE); gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (get_wg ("checkbutton_speech")), main_preferences_get_boolean ("interface", "speech")); tmp = dngettext (PACKAGE, "Dictation mode (depends on this speech synthesizer: %s)", "Dictation mode (depends on one of these speech synthesizers: %s)", 1); ttip = g_strdup_printf (tmp, "Espeak"); gtk_widget_set_tooltip_text (get_wg ("checkbutton_speech"), ttip); callbacks_shield_set (FALSE); /* Set the initial keyboard to use */ keyb_set_combo_kbd ("combobox_kbd_country", "combobox_kbd_variant"); keyb_set_combo_kbd ("combobox_keyboard_country", "combobox_keyboard_variant"); /* Set window icons */ gtk_window_set_default_icon_name ("klavaro"); /* Set pixmaps */ set_pixmap ("image_fluid", "fluid.png"); set_pixmap ("image_keyboard", "key.png"); set_pixmap ("image_beep", "beep.png"); set_pixmap ("image_progress", "progress.png"); set_pixmap ("image_other", "other.png"); set_pixmap ("image_top10", "top10.png"); /* Set Top10 TreeViews and Combo */ top10_init (); /* Set big and bold labels */ pango_parse_markup ("----------------------------------------------------------------", -1, 0, &palist, NULL, NULL, NULL); gtk_label_set_attributes (GTK_LABEL (get_wg ("label_keyboard_title")), palist); gtk_label_set_attributes (GTK_LABEL (get_wg ("label_main_intro")), palist); gtk_label_set_attributes (GTK_LABEL (get_wg ("label_main_basic")), palist); gtk_label_set_attributes (GTK_LABEL (get_wg ("label_main_adapt")), palist); gtk_label_set_attributes (GTK_LABEL (get_wg ("label_main_velo")), palist); gtk_label_set_attributes (GTK_LABEL (get_wg ("label_main_fluid")), palist); /* Set main labels (for translation) */ tmp = g_strdup_printf ("0 - %s", _("Introduction")); gtk_label_set_text (GTK_LABEL (get_wg ("label_main_intro")), tmp); g_free (tmp); tmp = g_strdup_printf ("1 - %s", _("Basic course")); gtk_label_set_text (GTK_LABEL (get_wg ("label_main_basic")), tmp); g_free (tmp); tmp = g_strdup_printf ("2 - %s", _("Adaptability")); gtk_label_set_text (GTK_LABEL (get_wg ("label_main_adapt")), tmp); g_free (tmp); tmp = g_strdup_printf ("3 - %s", _("Speed")); gtk_label_set_text (GTK_LABEL (get_wg ("label_main_velo")), tmp); g_free (tmp); tmp = g_strdup_printf ("4 - %s", _("Fluidity")); gtk_label_set_text (GTK_LABEL (get_wg ("label_main_fluid")), tmp); g_free (tmp); /* Set version */ gtk_about_dialog_set_version (GTK_ABOUT_DIALOG (get_obj ("aboutdialog_klavaro")), VERSION); /* For remembering the window's position */ gtk_widget_show (get_wg ("window_main")); window_restore ("main"); /* Run last used module */ if (!main_preferences_exist ("interface", "autostart")) main_preferences_set_boolean ("interface", "autostart", FALSE); if (!main_preferences_exist ("interface", "exercise")) main_preferences_set_int ("interface", "exercise", 1); if (main_preferences_get_boolean ("interface", "autostart")) { switch (main_preferences_get_int ("interface", "exercise")) { case TT_BASIC: on_button_basic_clicked (NULL, NULL); break; case TT_ADAPT: on_button_adapt_clicked (NULL, NULL); break; case TT_VELO: on_button_velo_clicked (NULL, NULL); break; case TT_FLUID: on_button_fluid_clicked (NULL, NULL); break; } } } /******************************************************************************* * Main program */ int main (int argc, char *argv[]) { gchar *tmp; gboolean success = FALSE; gboolean show_version = FALSE; GOptionContext *opct; GOptionEntry option[] = { {"version", 'v', 0, G_OPTION_ARG_NONE, &show_version, "Versio", NULL}, {NULL} }; /* Localization */ #ifdef ENABLE_NLS bindtextdomain (GETTEXT_PACKAGE, PACKAGE_LOCALE_DIR); bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8"); textdomain (GETTEXT_PACKAGE); #endif /* Command-line arguments */ opct = g_option_context_new (""); g_option_context_set_translation_domain (opct, GETTEXT_PACKAGE); g_option_context_add_main_entries (opct, option, GETTEXT_PACKAGE); g_option_context_add_group (opct, gtk_get_option_group (TRUE)); g_option_context_parse (opct, &argc, &argv, NULL); if (show_version) { g_printf (VERSION"\n"); return 0; } curl_ok = curl_global_init (CURL_GLOBAL_WIN32) == CURLE_OK ? TRUE : FALSE; main_initialize_global_variables (); /* Here the locale is got. */ /* Create all the interface stuff */ gui = gtk_builder_new (); gtk_builder_set_translation_domain (gui, NULL); tmp = g_build_filename (main_path_data (), "klavaro.ui", NULL); if (g_file_test (tmp, G_FILE_TEST_IS_REGULAR)) success = gtk_builder_add_from_file (gui, tmp, NULL); else g_error ("GUI file not found. Aborting.\n %s", tmp); if (!success) g_error ("GUI file found but couldn't create the GUI. Aborting."); if (!g_module_supported ()) g_error ("GUI created but can't connect signals."); g_free (tmp); gtk_builder_connect_signals (gui, NULL); main_window_init (); /* and initialize its parameters */ gtk_main (); return 0; } /******************************************************************************* * Quit the application */ void main_window_pass_away () { main_preferences_save (); g_rmdir ("tmp/klavaro"); if (curl_ok) curl_global_cleanup (); g_print ("\nAdiaux!\n"); accur_close (); exit (0); }