/* * TilEm II * * Copyright (c) 2010-2011 Thibault Duponchelle * Copyright (c) 2010-2012 Benjamin Moody * * This program is free software: you can redistribute it and/or * modify it 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. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #ifdef HAVE_CONFIG_H #include #endif #include #include #include #include #include #include #include "gui.h" #include "files.h" #include "icons.h" #include "msgbox.h" /* CMD LINE OPTIONS */ static gchar* cl_romfile = NULL; static gchar* cl_skinfile = NULL; static gchar* cl_model = NULL; static gchar* cl_statefile = NULL; static gchar** cl_files_to_load = NULL; static gboolean cl_skinless_flag = FALSE; static gboolean cl_reset_flag = FALSE; static gchar* cl_getvar = NULL; static gchar* cl_macro_to_run = NULL; static gboolean cl_debug_flag = FALSE; static gboolean cl_normalspeed_flag = FALSE; static gboolean cl_fullspeed_flag = FALSE; static GOptionEntry entries[] = { { "rom", 'r', 0, G_OPTION_ARG_FILENAME, &cl_romfile, "The rom file to run", "FILE" }, { "skin", 'k', 0, G_OPTION_ARG_FILENAME, &cl_skinfile, "The skin file to use", "FILE" }, { "model", 'm', 0, G_OPTION_ARG_STRING, &cl_model, "The model to use", "NAME" }, { "state-file", 's', 0, G_OPTION_ARG_FILENAME, &cl_statefile, "The state-file to use", "FILE" }, { "without-skin", 'l', 0, G_OPTION_ARG_NONE, &cl_skinless_flag, "Start in skinless mode", NULL }, { "reset", 0, 0, G_OPTION_ARG_NONE, &cl_reset_flag, "Reset the calc at startup", NULL }, { "get-var", 0, 0, G_OPTION_ARG_STRING, &cl_getvar, "Get a var at startup", "FILE" }, { "play-macro", 'p', 0, G_OPTION_ARG_FILENAME, &cl_macro_to_run, "Run this macro at startup", "FILE" }, { "debug", 'd', 0, G_OPTION_ARG_NONE, &cl_debug_flag, "Launch debugger", NULL }, { "normal-speed", 0, 0, G_OPTION_ARG_NONE, &cl_normalspeed_flag, "Run at normal speed", NULL }, { "full-speed", 0, 0, G_OPTION_ARG_NONE, &cl_fullspeed_flag, "Run at maximum speed", NULL }, { G_OPTION_REMAINING, 0, 0, G_OPTION_ARG_FILENAME_ARRAY, &cl_files_to_load, NULL, "FILE" }, { 0, 0, 0, 0, 0, 0, 0 } }; /* ######### MAIN ######### */ /* Order of preference for automatic model selection. */ static const char model_search_order[] = { TILEM_CALC_TI81, TILEM_CALC_TI73, TILEM_CALC_TI82, TILEM_CALC_TI83, TILEM_CALC_TI76, TILEM_CALC_TI84P_SE, TILEM_CALC_TI84P, TILEM_CALC_TI83P_SE, TILEM_CALC_TI83P, TILEM_CALC_TI84P_NSPIRE, TILEM_CALC_TI85, TILEM_CALC_TI86, 0 }; /* Check if given calc model should be used for these file types. */ static gboolean check_file_types(int calc_model, const int *file_models, int nfiles) { /* Only choose a calc model if it supports all of the given file types, and at least one of the files is of the calc's "preferred" type. This means if we have a mixture of 82Ps and 83Ps, we can use either a TI-83 or TI-76.fr ROM image, but not a TI-83 Plus. */ gboolean preferred = FALSE; int i; calc_model = model_to_base_model(calc_model); for (i = 0; i < nfiles; i++) { if (file_models[i] == calc_model) preferred = TRUE; else if (!model_supports_file(calc_model, file_models[i])) return FALSE; } return preferred; } static void load_initial_rom(TilemCalcEmulator *emu, const char *cmdline_rom_name, const char *cmdline_state_name, char **cmdline_files, int model) { GError *err = NULL; char *modelname; int nfiles, *file_models, i; /* If a ROM file is specified on the command line, use that (and no other) */ if (cmdline_rom_name) { if (tilem_calc_emulator_load_state(emu, cmdline_rom_name, cmdline_state_name, model, &err)) return; else if (!err) exit(0); else { g_printerr("%s\n", err->message); exit(1); } } /* Choose model by file names */ if (!model && cmdline_files) { nfiles = g_strv_length(cmdline_files); file_models = g_new(int, nfiles); /* determine model for each filename */ for (i = 0; i < nfiles; i++) file_models[i] = file_to_model(cmdline_files[i]); /* iterate over all known models... */ for (i = 0; model_search_order[i]; i++) { model = model_search_order[i]; /* check if this model supports the named files */ if (!check_file_types(model, file_models, nfiles)) continue; /* try to load model, but no error message if no ROM is present in config */ if (tilem_calc_emulator_load_state(emu, NULL, NULL, model, &err)) { g_free(file_models); return; } else if (!err) exit(0); else if (!g_error_matches(err, TILEM_EMULATOR_ERROR, TILEM_EMULATOR_ERROR_NO_ROM)) { messagebox01(NULL, GTK_MESSAGE_ERROR, "Unable to load calculator state", "%s", err->message); } g_clear_error(&err); } g_free(file_models); model = 0; } /* If no model specified on command line (either explicitly or implicitly), then choose the most recently used model */ if (!model && !cmdline_files) { tilem_config_get("recent", "last_model/s", &modelname, NULL); if (modelname) model = name_to_model(modelname); } /* Try to load the most recently used ROM for chosen model */ if (model) { if (tilem_calc_emulator_load_state(emu, NULL, NULL, model, &err)) return; else if (!err) exit(0); else { messagebox01(NULL, GTK_MESSAGE_ERROR, "Unable to load calculator state", "%s", err->message); g_clear_error(&err); } } /* Prompt user for a ROM file */ while (!emu->calc) { if (!tilem_calc_emulator_prompt_open_rom(emu)) exit(0); } } int main(int argc, char **argv) { TilemCalcEmulator* emu; char *menurc_path; GOptionContext *context; GError *error = NULL; int model = 0; g_thread_init(NULL); gtk_init(&argc, &argv); set_program_path(argv[0]); g_set_application_name("TilEm"); menurc_path = get_shared_file_path("menurc", NULL); if (menurc_path) gtk_accel_map_load(menurc_path); g_free(menurc_path); init_custom_icons(); gtk_window_set_default_icon_name("tilem"); emu = tilem_calc_emulator_new(); context = g_option_context_new(NULL); g_option_context_add_main_entries(context, entries, NULL); g_option_context_add_group(context, gtk_get_option_group(TRUE)); if (!g_option_context_parse(context, &argc, &argv, &error)) { g_printerr("%s: %s\n", g_get_prgname(), error->message); exit (1); } if (cl_model) { model = name_to_model(cl_model); if (!model) { g_printerr("%s: unknown model %s\n", g_get_prgname(), cl_model); return 1; } } load_initial_rom(emu, cl_romfile, cl_statefile, cl_files_to_load, model); emu->ewin = tilem_emulator_window_new(emu); if (cl_skinless_flag) tilem_emulator_window_set_skin_disabled(emu->ewin, TRUE); else if (cl_skinfile) { tilem_emulator_window_set_skin(emu->ewin, cl_skinfile); tilem_emulator_window_set_skin_disabled(emu->ewin, FALSE); } gtk_widget_show(emu->ewin->window); ticables_library_init(); tifiles_library_init(); ticalcs_library_init(); if (cl_reset_flag) tilem_calc_emulator_reset(emu); if (cl_fullspeed_flag) tilem_calc_emulator_set_limit_speed(emu, FALSE); else if (cl_normalspeed_flag) tilem_calc_emulator_set_limit_speed(emu, TRUE); if (cl_files_to_load) load_files_cmdline(emu->ewin, cl_files_to_load); if (cl_macro_to_run) tilem_macro_load(emu, cl_macro_to_run); if (cl_getvar) tilem_link_receive_matching(emu, cl_getvar, "."); if (cl_debug_flag) launch_debugger(emu->ewin); else tilem_calc_emulator_run(emu); g_signal_connect(emu->ewin->window, "destroy", G_CALLBACK(gtk_main_quit), NULL); gtk_main(); tilem_calc_emulator_pause(emu); tilem_emulator_window_free(emu->ewin); tilem_calc_emulator_free(emu); menurc_path = get_config_file_path("menurc", NULL); gtk_accel_map_save(menurc_path); g_free(menurc_path); ticables_library_exit(); tifiles_library_exit(); ticalcs_library_exit(); return 0; }