1 /** \file uisnapshot.c
2 * \brief Snapshot dialogs and menu item handlers
3 *
4 * \author Bas Wassink <b.wassink@ziggo.nl>
5 */
6
7 /*
8 * This file is part of VICE, the Versatile Commodore Emulator.
9 * See README for copyright notice.
10 *
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
15 *
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
20 *
21 * You should have received a copy of the GNU General Public License
22 * along with this program; if not, write to the Free Software
23 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
24 * 02111-1307 USA.
25 *
26 */
27
28 #include "vice.h"
29
30 #include <gtk/gtk.h>
31 #include <stdlib.h>
32
33 #include "lib.h"
34 #include "util.h"
35 #include "archdep.h"
36 #include "basewidgets.h"
37 #include "widgethelpers.h"
38 #include "debug_gtk3.h"
39 #include "machine.h"
40 #include "resources.h"
41 #include "filechooserhelpers.h"
42 #include "openfiledialog.h"
43 #include "savefiledialog.h"
44 #include "selectdirectorydialog.h"
45 #include "basedialogs.h"
46 #include "interrupt.h"
47 #include "vsync.h"
48 #include "snapshot.h"
49 #include "vice-event.h"
50 #include "uistatusbar.h"
51 #include "ui.h"
52
53 #include "uisnapshot.h"
54
55
56 /*****************************************************************************
57 * Helper functions *
58 ****************************************************************************/
59
60
61 /** \brief Construct filename for quickload/quicksave snapshots
62 *
63 * \return filename for the quickload/save file, heap-allocated by VICE, so
64 * free after use with lib_free()
65 */
quicksnap_filename(void)66 static char *quicksnap_filename(void)
67 {
68 char *fname;
69 const char *mname;
70 char *cfg;
71
72 mname = machine_class == VICE_MACHINE_C64SC ? "c64sc" : machine_name;
73 cfg = archdep_user_config_path();
74 fname = util_concat(cfg, "/", mname, ".vsf", NULL);
75 #if 0
76 lib_free(cfg);
77 #endif
78 debug_gtk3("quicksnap_filename = %s.", fname);
79 return fname;
80 }
81
82
83 /** \brief Show dialog to save a snapshot
84 */
save_snapshot_dialog(void)85 static void save_snapshot_dialog(void)
86 {
87 GtkWidget *dialog;
88 GtkWidget *extra;
89 GtkWidget *roms_widget;
90 GtkWidget *disks_widget;
91 gint response_id;
92 int save_roms;
93 int save_disks;
94
95 dialog = gtk_file_chooser_dialog_new("Save snapshot file",
96 ui_get_active_window(),
97 GTK_FILE_CHOOSER_ACTION_SAVE,
98 "Save", GTK_RESPONSE_ACCEPT,
99 "Cancel", GTK_RESPONSE_CANCEL,
100 NULL);
101
102 gtk_file_chooser_add_filter(GTK_FILE_CHOOSER(dialog),
103 create_file_chooser_filter(file_chooser_filter_snapshot, FALSE));
104
105 /* create extras widget */
106 extra = gtk_grid_new();
107 gtk_grid_set_column_spacing(GTK_GRID(extra), 16);
108
109 disks_widget = gtk_check_button_new_with_label("Save attached disks");
110 roms_widget = gtk_check_button_new_with_label("Save attached ROMs");
111 gtk_grid_attach(GTK_GRID(extra), disks_widget, 0, 0, 1, 1);
112 gtk_grid_attach(GTK_GRID(extra), roms_widget, 1, 0, 1, 1);
113 gtk_widget_show_all(extra);
114
115 gtk_file_chooser_set_extra_widget(GTK_FILE_CHOOSER(dialog), extra);
116
117 response_id = gtk_dialog_run(GTK_DIALOG(dialog));
118 save_roms = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(roms_widget));
119 save_disks = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(disks_widget));
120
121 debug_gtk3("response_id = %d.", response_id);
122 debug_gtk3("save disks = %s.", save_disks ? "YES" : "NO");
123 debug_gtk3("save ROMs = %s.", save_roms ? "YES" : "NO");
124
125 if (response_id == GTK_RESPONSE_ACCEPT) {
126 gchar *filename;
127
128 filename = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(dialog));
129 if (filename != NULL) {
130 char *fname_copy;
131 char buffer[1024];
132
133 fname_copy = util_add_extension_const(filename, "vsf");
134
135 if (machine_write_snapshot(fname_copy, save_roms, save_disks, 0) < 0) {
136 snapshot_display_error();
137 g_snprintf(buffer, 1024, "Failed to save snapshot '%s'",
138 fname_copy);
139 } else {
140 debug_gtk3("Wrote snapshot file '%s'.", fname_copy);
141 g_snprintf(buffer, 1024, "Saved snapshot '%s'", fname_copy);
142 }
143 lib_free(fname_copy);
144 g_free(filename);
145 }
146 }
147 gtk_widget_destroy(dialog);
148 }
149
150
151 /*****************************************************************************
152 * CPU trap handlers *
153 ****************************************************************************/
154
155
156 /** \brief CPU trap handler for the load snapshot dialog
157 *
158 * \param[in] addr memory address (unused)
159 * \param[in] data unused
160 */
load_snapshot_trap(uint16_t addr,void * data)161 static void load_snapshot_trap(uint16_t addr, void *data)
162 {
163 const char *filters[] = { "*.vsf", NULL };
164 gchar *filename;
165 gchar buffer[1024];
166
167 vsync_suspend_speed_eval();
168
169 filename = vice_gtk3_open_file_dialog("Open snapshot file",
170 "Snapshot files", filters, NULL);
171 if (filename != NULL) {
172 /* load snapshot */
173 if (machine_read_snapshot(filename, 0) < 0) {
174 snapshot_display_error();
175 g_snprintf(buffer, 1024, "Failed to load snapshot '%s'", filename);
176 } else {
177 g_snprintf(buffer, 1024, "Loaded snapshot '%s'", filename);
178 }
179 g_free(filename);
180 }
181 }
182
183
184 /** \brief CPU trap handler to trigger the Save dialog
185 *
186 * \param[in] addr memory address (unused)
187 * \param[in] data unused
188 */
save_snapshot_trap(uint16_t addr,void * data)189 static void save_snapshot_trap(uint16_t addr, void *data)
190 {
191 vsync_suspend_speed_eval();
192 save_snapshot_dialog();
193 }
194
195
196 /** \brief CPU trap handler for the QuickLoad snapshot menu item
197 *
198 * \param[in] addr memory address (unused)
199 * \param[in] data quickload snapshot filename
200 */
quickload_snapshot_trap(uint16_t addr,void * data)201 static void quickload_snapshot_trap(uint16_t addr, void *data)
202 {
203 char *filename = (char *)data;
204
205 vsync_suspend_speed_eval();
206
207 debug_gtk3("Quickloading file '%s'.", filename);
208 if (machine_read_snapshot(filename, 0) < 0) {
209 snapshot_display_error();
210 }
211 lib_free(filename);
212 }
213
214
215 /** \brief CPU trap handler for the QuickSave snapshot menu item
216 *
217 * \param[in] addr memory address (unused)
218 * \param[in] data quicksave snapshot filename
219 */
quicksave_snapshot_trap(uint16_t addr,void * data)220 static void quicksave_snapshot_trap(uint16_t addr, void *data)
221 {
222 char *filename = (char *)data;
223
224 vsync_suspend_speed_eval();
225
226 debug_gtk3("Quicksaving file '%s'.", filename);
227 if (machine_write_snapshot(filename, TRUE, TRUE, 0) < 0) {
228 snapshot_display_error();
229 }
230 lib_free(filename);
231 }
232
233
234 /*****************************************************************************
235 * Public functions *
236 ****************************************************************************/
237
238
239 /** \brief Display UI to load a snapshot file
240 *
241 * \param[in] parent parent widget
242 * \param[in] user_data unused
243 */
uisnapshot_open_file(GtkWidget * parent,gpointer user_data)244 void uisnapshot_open_file(GtkWidget *parent, gpointer user_data)
245 {
246 if (!ui_emulation_is_paused()) {
247 interrupt_maincpu_trigger_trap(load_snapshot_trap, NULL);
248 } else {
249 load_snapshot_trap(0, NULL);
250 }
251 }
252
253
254 /** \brief Display UI to save a snapshot file
255 *
256 * \param[in] parent parent widget
257 * \param[in] user_data unused
258 */
uisnapshot_save_file(GtkWidget * parent,gpointer user_data)259 void uisnapshot_save_file(GtkWidget *parent, gpointer user_data)
260 {
261 if (!ui_emulation_is_paused()) {
262 interrupt_maincpu_trigger_trap(save_snapshot_trap, NULL);
263 } else {
264 save_snapshot_trap(0, NULL);
265 }
266 }
267
268
269 /** \brief Gtk event handler for the QuickLoad menu item
270 *
271 * \param[in] parent parent widget
272 * \param[in] user_data unused
273 */
uisnapshot_quickload_snapshot(GtkWidget * parent,gpointer user_data)274 void uisnapshot_quickload_snapshot(GtkWidget *parent, gpointer user_data)
275 {
276 char *fname = quicksnap_filename();
277
278 interrupt_maincpu_trigger_trap(quickload_snapshot_trap, (void *)fname);
279 }
280
281
282 /** \brief Gtk event handler for the QuickSave menu item
283 *
284 * \param[in] parent parent widget
285 * \param[in] user_data unused
286 */
uisnapshot_quicksave_snapshot(GtkWidget * parent,gpointer user_data)287 void uisnapshot_quicksave_snapshot(GtkWidget *parent, gpointer user_data)
288 {
289 char *fname = quicksnap_filename();
290
291 interrupt_maincpu_trigger_trap(quicksave_snapshot_trap, (void *)fname);
292 }
293
294
295 #if 0
296 /** \brief Gtk event handler for the "Select history directory" menu item
297 *
298 * \param[in] parent parent widget
299 * \param[in] user_data unused
300 */
301 void uisnapshot_history_select_dir(GtkWidget *parent, gpointer user_data)
302 {
303 char *filename;
304 const char *current;
305
306 if (resources_get_string("EventSnapshotDir", ¤t) < 0) {
307 debug_gtk3("failed to get current history directory, using NULL.");
308 current = NULL;
309 }
310
311 filename = vice_gtk3_select_directory_dialog("Select history directory",
312 NULL, TRUE, current);
313 if (filename != NULL) {
314 debug_gtk3("Setting EventSnapshotDir to '%s'.", filename);
315 if (resources_set_string("EventSnapshotDir", filename) < 0) {
316 vice_gtk3_message_error("VICE core error",
317 "Failed to set history directory.");
318 }
319 g_free(filename);
320 }
321 }
322 #endif
323
324
325 /** \brief Gtk event handler for the "Start recording events" menu item
326 *
327 * \param[in] parent parent widget
328 * \param[in] user_data unused
329 */
uisnapshot_history_record_start(GtkWidget * parent,gpointer user_data)330 void uisnapshot_history_record_start(GtkWidget *parent, gpointer user_data)
331 {
332 event_record_start();
333 }
334
335
336 /** \brief Gtk event handler for the "Stop recording events" menu item
337 *
338 * \param[in] parent parent widget
339 * \param[in] user_data unused
340 */
uisnapshot_history_record_stop(GtkWidget * parent,gpointer user_data)341 void uisnapshot_history_record_stop(GtkWidget *parent, gpointer user_data)
342 {
343 event_record_stop();
344 }
345
346
347 /** \brief Gtk event handler for the "Start playing back events" menu item
348 *
349 * \param[in] parent parent widget
350 * \param[in] user_data unused
351 */
uisnapshot_history_playback_start(GtkWidget * parent,gpointer user_data)352 void uisnapshot_history_playback_start(GtkWidget *parent, gpointer user_data)
353 {
354 event_playback_start();
355 }
356
357
358
359 /** \brief Gtk event handler for the "Stop playing back events" menu item
360 *
361 * \param[in] parent parent widget
362 * \param[in] user_data unused
363 */
uisnapshot_history_playback_stop(GtkWidget * parent,gpointer user_data)364 void uisnapshot_history_playback_stop(GtkWidget *parent, gpointer user_data)
365 {
366 event_playback_stop();
367 }
368
369
370 /** \brief Gtk event handler for the "Set recording milestone" menu item
371 *
372 * \param[in] parent parent widget
373 * \param[in] user_data unused
374 */
uisnapshot_history_milestone_set(GtkWidget * parent,gpointer user_data)375 void uisnapshot_history_milestone_set(GtkWidget *parent, gpointer user_data)
376 {
377 event_record_set_milestone();
378 }
379
380
381 /** \brief Gtk event handler for the "Return to milestone" menu item
382 *
383 * \param[in] parent parent widget
384 * \param[in] user_data unused
385 */
uisnapshot_history_milestone_reset(GtkWidget * parent,gpointer user_data)386 void uisnapshot_history_milestone_reset(GtkWidget *parent, gpointer user_data)
387 {
388 event_record_reset_milestone();
389 }
390