1 /*
2 * TilEm II
3 *
4 * Copyright (c) 2010-2011 Thibault Duponchelle
5 * Copyright (c) 2010-2012 Benjamin Moody
6 *
7 * This program is free software: you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License as
9 * published by the Free Software Foundation, either version 3 of the
10 * License, or (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program. If not, see <http://www.gnu.org/licenses/>.
19 */
20
21 #ifdef HAVE_CONFIG_H
22 #include <config.h>
23 #endif
24
25 #include <stdio.h>
26 #include <stdlib.h>
27 #include <gtk/gtk.h>
28 #include <glib.h>
29 #include <ticalcs.h>
30 #include <tilem.h>
31
32 #include "gui.h"
33 #include "files.h"
34 #include "icons.h"
35 #include "msgbox.h"
36
37 /* CMD LINE OPTIONS */
38 static gchar* cl_romfile = NULL;
39 static gchar* cl_skinfile = NULL;
40 static gchar* cl_model = NULL;
41 static gchar* cl_statefile = NULL;
42 static gchar** cl_files_to_load = NULL;
43 static gboolean cl_skinless_flag = FALSE;
44 static gboolean cl_reset_flag = FALSE;
45 static gchar* cl_getvar = NULL;
46 static gchar* cl_macro_to_run = NULL;
47 static gboolean cl_debug_flag = FALSE;
48 static gboolean cl_normalspeed_flag = FALSE;
49 static gboolean cl_fullspeed_flag = FALSE;
50
51
52 static GOptionEntry entries[] =
53 {
54 { "rom", 'r', 0, G_OPTION_ARG_FILENAME, &cl_romfile, "The rom file to run", "FILE" },
55 { "skin", 'k', 0, G_OPTION_ARG_FILENAME, &cl_skinfile, "The skin file to use", "FILE" },
56 { "model", 'm', 0, G_OPTION_ARG_STRING, &cl_model, "The model to use", "NAME" },
57 { "state-file", 's', 0, G_OPTION_ARG_FILENAME, &cl_statefile, "The state-file to use", "FILE" },
58 { "without-skin", 'l', 0, G_OPTION_ARG_NONE, &cl_skinless_flag, "Start in skinless mode", NULL },
59 { "reset", 0, 0, G_OPTION_ARG_NONE, &cl_reset_flag, "Reset the calc at startup", NULL },
60 { "get-var", 0, 0, G_OPTION_ARG_STRING, &cl_getvar, "Get a var at startup", "FILE" },
61 { "play-macro", 'p', 0, G_OPTION_ARG_FILENAME, &cl_macro_to_run, "Run this macro at startup", "FILE" },
62 { "debug", 'd', 0, G_OPTION_ARG_NONE, &cl_debug_flag, "Launch debugger", NULL },
63 { "normal-speed", 0, 0, G_OPTION_ARG_NONE, &cl_normalspeed_flag, "Run at normal speed", NULL },
64 { "full-speed", 0, 0, G_OPTION_ARG_NONE, &cl_fullspeed_flag, "Run at maximum speed", NULL },
65 { G_OPTION_REMAINING, 0, 0, G_OPTION_ARG_FILENAME_ARRAY, &cl_files_to_load, NULL, "FILE" },
66 { 0, 0, 0, 0, 0, 0, 0 }
67 };
68
69
70 /* ######### MAIN ######### */
71
72 /* Order of preference for automatic model selection. */
73 static const char model_search_order[] =
74 { TILEM_CALC_TI81,
75 TILEM_CALC_TI73,
76 TILEM_CALC_TI82,
77 TILEM_CALC_TI83,
78 TILEM_CALC_TI76,
79 TILEM_CALC_TI84P_SE,
80 TILEM_CALC_TI84P,
81 TILEM_CALC_TI83P_SE,
82 TILEM_CALC_TI83P,
83 TILEM_CALC_TI84P_NSPIRE,
84 TILEM_CALC_TI85,
85 TILEM_CALC_TI86, 0 };
86
87 /* Check if given calc model should be used for these file types. */
check_file_types(int calc_model,const int * file_models,int nfiles)88 static gboolean check_file_types(int calc_model,
89 const int *file_models,
90 int nfiles)
91 {
92 /* Only choose a calc model if it supports all of the given
93 file types, and at least one of the files is of the calc's
94 "preferred" type. This means if we have a mixture of 82Ps
95 and 83Ps, we can use either a TI-83 or TI-76.fr ROM image,
96 but not a TI-83 Plus. */
97
98 gboolean preferred = FALSE;
99 int i;
100
101 calc_model = model_to_base_model(calc_model);
102
103 for (i = 0; i < nfiles; i++) {
104 if (file_models[i] == calc_model)
105 preferred = TRUE;
106 else if (!model_supports_file(calc_model, file_models[i]))
107 return FALSE;
108 }
109
110 return preferred;
111 }
112
load_initial_rom(TilemCalcEmulator * emu,const char * cmdline_rom_name,const char * cmdline_state_name,char ** cmdline_files,int model)113 static void load_initial_rom(TilemCalcEmulator *emu,
114 const char *cmdline_rom_name,
115 const char *cmdline_state_name,
116 char **cmdline_files,
117 int model)
118 {
119 GError *err = NULL;
120 char *modelname;
121 int nfiles, *file_models, i;
122
123 /* If a ROM file is specified on the command line, use that
124 (and no other) */
125
126 if (cmdline_rom_name) {
127 if (tilem_calc_emulator_load_state(emu, cmdline_rom_name,
128 cmdline_state_name,
129 model, &err))
130 return;
131 else if (!err)
132 exit(0);
133 else {
134 g_printerr("%s\n", err->message);
135 exit(1);
136 }
137 }
138
139 /* Choose model by file names */
140
141 if (!model && cmdline_files) {
142 nfiles = g_strv_length(cmdline_files);
143 file_models = g_new(int, nfiles);
144
145 /* determine model for each filename */
146 for (i = 0; i < nfiles; i++)
147 file_models[i] = file_to_model(cmdline_files[i]);
148
149 /* iterate over all known models... */
150 for (i = 0; model_search_order[i]; i++) {
151 model = model_search_order[i];
152
153 /* check if this model supports the named files */
154 if (!check_file_types(model, file_models, nfiles))
155 continue;
156
157 /* try to load model, but no error message if
158 no ROM is present in config */
159 if (tilem_calc_emulator_load_state(emu, NULL, NULL,
160 model, &err)) {
161 g_free(file_models);
162 return;
163 }
164 else if (!err)
165 exit(0);
166 else if (!g_error_matches(err, TILEM_EMULATOR_ERROR,
167 TILEM_EMULATOR_ERROR_NO_ROM)) {
168 messagebox01(NULL, GTK_MESSAGE_ERROR,
169 "Unable to load calculator state",
170 "%s", err->message);
171 }
172 g_clear_error(&err);
173 }
174
175 g_free(file_models);
176 model = 0;
177 }
178
179 /* If no model specified on command line (either explicitly or
180 implicitly), then choose the most recently used model */
181
182 if (!model && !cmdline_files) {
183 tilem_config_get("recent", "last_model/s", &modelname, NULL);
184 if (modelname)
185 model = name_to_model(modelname);
186 }
187
188 /* Try to load the most recently used ROM for chosen model */
189
190 if (model) {
191 if (tilem_calc_emulator_load_state(emu, NULL, NULL,
192 model, &err))
193 return;
194 else if (!err)
195 exit(0);
196 else {
197 messagebox01(NULL, GTK_MESSAGE_ERROR,
198 "Unable to load calculator state",
199 "%s", err->message);
200 g_clear_error(&err);
201 }
202 }
203
204 /* Prompt user for a ROM file */
205
206 while (!emu->calc) {
207 if (!tilem_calc_emulator_prompt_open_rom(emu))
208 exit(0);
209 }
210 }
211
main(int argc,char ** argv)212 int main(int argc, char **argv)
213 {
214 TilemCalcEmulator* emu;
215 char *menurc_path;
216 GOptionContext *context;
217 GError *error = NULL;
218 int model = 0;
219
220 g_thread_init(NULL);
221 gtk_init(&argc, &argv);
222 set_program_path(argv[0]);
223 g_set_application_name("TilEm");
224
225 menurc_path = get_shared_file_path("menurc", NULL);
226 if (menurc_path)
227 gtk_accel_map_load(menurc_path);
228 g_free(menurc_path);
229
230 init_custom_icons();
231 gtk_window_set_default_icon_name("tilem");
232
233 emu = tilem_calc_emulator_new();
234
235 context = g_option_context_new(NULL);
236 g_option_context_add_main_entries(context, entries, NULL);
237 g_option_context_add_group(context, gtk_get_option_group(TRUE));
238 if (!g_option_context_parse(context, &argc, &argv, &error))
239 {
240 g_printerr("%s: %s\n", g_get_prgname(), error->message);
241 exit (1);
242 }
243
244 if (cl_model) {
245 model = name_to_model(cl_model);
246 if (!model) {
247 g_printerr("%s: unknown model %s\n",
248 g_get_prgname(), cl_model);
249 return 1;
250 }
251 }
252
253 load_initial_rom(emu, cl_romfile, cl_statefile, cl_files_to_load, model);
254
255 emu->ewin = tilem_emulator_window_new(emu);
256
257 if (cl_skinless_flag)
258 tilem_emulator_window_set_skin_disabled(emu->ewin, TRUE);
259 else if (cl_skinfile) {
260 tilem_emulator_window_set_skin(emu->ewin, cl_skinfile);
261 tilem_emulator_window_set_skin_disabled(emu->ewin, FALSE);
262 }
263
264 gtk_widget_show(emu->ewin->window);
265
266 ticables_library_init();
267 tifiles_library_init();
268 ticalcs_library_init();
269
270 if (cl_reset_flag)
271 tilem_calc_emulator_reset(emu);
272
273 if (cl_fullspeed_flag)
274 tilem_calc_emulator_set_limit_speed(emu, FALSE);
275 else if (cl_normalspeed_flag)
276 tilem_calc_emulator_set_limit_speed(emu, TRUE);
277
278 if (cl_files_to_load)
279 load_files_cmdline(emu->ewin, cl_files_to_load);
280 if (cl_macro_to_run)
281 tilem_macro_load(emu, cl_macro_to_run);
282 if (cl_getvar)
283 tilem_link_receive_matching(emu, cl_getvar, ".");
284
285 if (cl_debug_flag)
286 launch_debugger(emu->ewin);
287 else
288 tilem_calc_emulator_run(emu);
289
290 g_signal_connect(emu->ewin->window, "destroy",
291 G_CALLBACK(gtk_main_quit), NULL);
292
293 gtk_main();
294
295 tilem_calc_emulator_pause(emu);
296
297 tilem_emulator_window_free(emu->ewin);
298 tilem_calc_emulator_free(emu);
299
300 menurc_path = get_config_file_path("menurc", NULL);
301 gtk_accel_map_save(menurc_path);
302 g_free(menurc_path);
303
304 ticables_library_exit();
305 tifiles_library_exit();
306 ticalcs_library_exit();
307
308 return 0;
309 }
310