1 /** \file   uimachinemenu.c
2  * \brief   Native GTK3 menus for machine emulators (not vsid)
3  *
4  * \author  Marcus Sutton <loggedoubt@gmail.com>
5  * \author  Bas Wassink <b.wassink@ziggo.nl>
6  */
7 
8 /*
9  * $VICERES WarpMode        all
10  * $VICERES KeySetEnable    -vsid
11  * $VICERES Mouse           -vsid
12  * $VICERES DtvBlitterLog   x64dtv
13  * $VICERES DtvDMALog       x64dtv
14  * $VICERES DtvFlashLog     x64dtv
15  */
16 
17 /*
18  * This file is part of VICE, the Versatile Commodore Emulator.
19  * See README for copyright notice.
20  *
21  *  This program is free software; you can redistribute it and/or modify
22  *  it under the terms of the GNU General Public License as published by
23  *  the Free Software Foundation; either version 2 of the License, or
24  *  (at your option) any later version.
25  *
26  *  This program is distributed in the hope that it will be useful,
27  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
28  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
29  *  GNU General Public License for more details.
30  *
31  *  You should have received a copy of the GNU General Public License
32  *  along with this program; if not, write to the Free Software
33  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
34  *  02111-1307  USA.
35  *
36  */
37 
38 
39 #include "vice.h"
40 
41 #include <stdlib.h>
42 #include <gtk/gtk.h>
43 
44 #include "vice_gtk3.h"
45 #include "archdep.h"
46 #include "debug_gtk3.h"
47 #include "datasette.h"
48 #include "debug.h"
49 #include "machine.h"
50 #include "resources.h"
51 #include "ui.h"
52 #include "uiabout.h"
53 #include "uicart.h"
54 #include "uicmdline.h"
55 #include "uicommands.h"
56 #include "uicompiletimefeatures.h"
57 #include "uidatasette.h"
58 #include "uidebug.h"
59 #include "uidiskattach.h"
60 #include "uiedit.h"
61 #include "uifliplist.h"
62 #include "uimachinemenu.h"
63 #include "uimedia.h"
64 #include "uimenu.h"
65 #include "uimonarch.h"
66 #include "uidiskcreate.h"
67 #include "uitapecreate.h"
68 
69 #ifdef HAVE_NETWORK
70 # include "uinetplay.h"
71 # include "uinetplay_new.h"
72 #endif
73 
74 #include "uisettings.h"
75 #include "uismartattach.h"
76 #include "uisnapshot.h"
77 #include "uitapeattach.h"
78 
79 /*
80  * The following are translation unit local so we can create functions that
81  * modify menu contents or even functions that alter the top bar itself.
82  */
83 
84 
85 /** \brief  Main menu bar widget
86  *
87  * Contains the submenus on the menu main bar
88  *
89  * This one lives until ui_exit() or thereabouts
90  */
91 static GtkWidget *main_menu_bar = NULL;
92 
93 
94 /** \brief  File submenu
95  */
96 static GtkWidget *file_submenu = NULL;
97 
98 
99 /** \brief  Edit submenu
100  */
101 static GtkWidget *edit_submenu = NULL;
102 
103 
104 /** \brief  Snapshot submenu
105  */
106 static GtkWidget *snapshot_submenu = NULL;
107 
108 
109 /** \brief  Settings submenu
110  */
111 static GtkWidget *settings_submenu = NULL;
112 
113 
114 #ifdef DEBUG
115 /** \brief  Debug submenu, only available when --enable-debug was specified
116  */
117 static GtkWidget *debug_submenu = NULL;
118 #endif
119 
120 
121 /** \brief  Help submenu
122  */
123 static GtkWidget *help_submenu = NULL;
124 
125 
126 /** \brief  Load settings from default file
127  *
128  * \param[in]   widget  menu item triggering the event (ignored)
129  * \param[in]   data    extra even data (ignored)
130  */
settings_load_callback(GtkWidget * widget,gpointer data)131 static void settings_load_callback(GtkWidget *widget, gpointer data)
132 {
133     if (resources_load(NULL) != 0) {
134         vice_gtk3_message_error("VICE core error",
135                 "Failed to load default settings file");
136     }
137 }
138 
139 
140 /** \brief  Load settings from user-specified file
141  *
142  * \param[in]   widget  menu item triggering the event (ignored)
143  * \param[in]   data    extra even data (ignored)
144  */
settings_load_custom_callback(GtkWidget * widget,gpointer data)145 static void settings_load_custom_callback(GtkWidget *widget, gpointer data)
146 {
147     gchar *filename = vice_gtk3_open_file_dialog("Load settings file",
148             NULL, NULL, NULL);
149     if (filename!= NULL) {
150         if (resources_load(filename) != 0) {
151             vice_gtk3_message_error("VICE core error",
152                     "Failed to load settings from '%s'", filename);
153         }
154     }
155 }
156 
157 
158 /** \brief  Save settings to default file
159  *
160  * \param[in]   widget  menu item triggering the event (ignored)
161  * \param[in]   data    extra even data (ignored)
162  */
settings_save_callback(GtkWidget * widget,gpointer data)163 static void settings_save_callback(GtkWidget *widget, gpointer data)
164 {
165     if (resources_save(NULL) != 0) {
166         vice_gtk3_message_error("VICE core error",
167                 "Failed to save default settings file");
168     }
169 }
170 
171 
172 /** \brief  Save settings to user-specified file
173  *
174  * \param[in]   widget  menu item triggering the event (ignored)
175  * \param[in]   data    extra even data (ignored)
176  */
settings_save_custom_callback(GtkWidget * widget,gpointer data)177 static void settings_save_custom_callback(GtkWidget *widget, gpointer data)
178 {
179     gchar *filename = vice_gtk3_save_file_dialog("Save settings as ...",
180             NULL, TRUE, NULL);
181     if (filename!= NULL) {
182         if (resources_save(filename) != 0) {
183             vice_gtk3_message_error("VICE core error",
184                     "Failed to save settings as '%s'", filename);
185         }
186         g_free(filename);
187     }
188 }
189 
190 
191 
192 /** \brief  File->Detach disk submenu
193  */
194 static ui_menu_item_t detach_submenu[] = {
195     { "Drive #8", UI_MENU_TYPE_ITEM_ACTION,
196         "detach-drive8", ui_disk_detach_callback, GINT_TO_POINTER(8),
197         0, 0 },
198     { "Drive #9", UI_MENU_TYPE_ITEM_ACTION,
199         "detach-drive9", ui_disk_detach_callback, GINT_TO_POINTER(9),
200         0, 0 },
201     { "Drive #10", UI_MENU_TYPE_ITEM_ACTION,
202         "detach-drive10", ui_disk_detach_callback, GINT_TO_POINTER(10),
203         0, 0 },
204     { "Drive #11", UI_MENU_TYPE_ITEM_ACTION,
205         "detach-drive11", ui_disk_detach_callback, GINT_TO_POINTER(11),
206         0, 0 },
207 
208     { "Detach all", UI_MENU_TYPE_ITEM_ACTION,
209         "detach-all", ui_disk_detach_all_callback, NULL,
210         0, 0 },
211 
212     UI_MENU_TERMINATOR
213 };
214 
215 
216 /** \brief  File->Attach disk submenu
217  */
218 static ui_menu_item_t attach_submenu[] = {
219     { "Drive #8", UI_MENU_TYPE_ITEM_ACTION,
220         "attach-drive8", ui_disk_attach_callback, GINT_TO_POINTER(8),
221         GDK_KEY_8, VICE_MOD_MASK },
222     { "Drive #9", UI_MENU_TYPE_ITEM_ACTION,
223         "attach-drive9", ui_disk_attach_callback, GINT_TO_POINTER(9),
224         GDK_KEY_9, VICE_MOD_MASK },
225     { "Drive #10", UI_MENU_TYPE_ITEM_ACTION,
226         "attach-drive10", ui_disk_attach_callback, GINT_TO_POINTER(10),
227         GDK_KEY_0, VICE_MOD_MASK },
228     { "Drive #11", UI_MENU_TYPE_ITEM_ACTION,
229         "attach-drive11", ui_disk_attach_callback, GINT_TO_POINTER(11),
230         GDK_KEY_1, VICE_MOD_MASK },
231 
232     UI_MENU_TERMINATOR
233 };
234 
235 
236 
237 /** \brief  File->Flip list submenu
238  */
239 static ui_menu_item_t fliplist_submenu[] = {
240     { "Add current image (Unit #8)", UI_MENU_TYPE_ITEM_ACTION,
241         "fliplist-add", ui_fliplist_add_current_cb, GINT_TO_POINTER(8),
242         GDK_KEY_I, VICE_MOD_MASK },
243     { "Remove current image (Unit #8)", UI_MENU_TYPE_ITEM_ACTION,
244        "fliplist-remove", ui_fliplist_remove_current_cb, GINT_TO_POINTER(8),
245         GDK_KEY_K, VICE_MOD_MASK },
246     { "Attach next image (Unit #8)", UI_MENU_TYPE_ITEM_ACTION,
247         "fliplist-next", ui_fliplist_next_cb, GINT_TO_POINTER(8),
248         GDK_KEY_N, VICE_MOD_MASK },
249     { "Attach previous image (Unit #8)", UI_MENU_TYPE_ITEM_ACTION,
250         "fliplist-prev", ui_fliplist_prev_cb, GINT_TO_POINTER(8),
251         GDK_KEY_N, VICE_MOD_MASK | GDK_SHIFT_MASK },
252     { "Load flip list file...", UI_MENU_TYPE_ITEM_ACTION,
253         "fliplist-load", ui_fliplist_load_callback, GINT_TO_POINTER(8),
254         0, 0 },
255     { "Save flip list file...", UI_MENU_TYPE_ITEM_ACTION,
256         "fliplist-save", ui_fliplist_save_callback, GINT_TO_POINTER(8),
257         0, 0 },
258 
259     UI_MENU_TERMINATOR
260 };
261 
262 /** \brief  File->Datasette control submenu
263  */
264 
265 static ui_menu_item_t datasette_control_submenu[] = {
266     { "Stop", UI_MENU_TYPE_ITEM_ACTION,
267         "tape-stop", ui_datasette_tape_action_cb, GINT_TO_POINTER(DATASETTE_CONTROL_STOP),
268         0, 0 },
269     { "Start", UI_MENU_TYPE_ITEM_ACTION,
270         "tape-start", ui_datasette_tape_action_cb, GINT_TO_POINTER(DATASETTE_CONTROL_START),
271         0, 0 },
272     { "Forward", UI_MENU_TYPE_ITEM_ACTION,
273         "tape-ff", ui_datasette_tape_action_cb, GINT_TO_POINTER(DATASETTE_CONTROL_FORWARD),
274         0, 0 },
275     { "Rewind", UI_MENU_TYPE_ITEM_ACTION,
276         "tape-rew", ui_datasette_tape_action_cb, GINT_TO_POINTER(DATASETTE_CONTROL_REWIND),
277         0, 0 },
278     { "Record", UI_MENU_TYPE_ITEM_ACTION,
279         "tape-record", ui_datasette_tape_action_cb, GINT_TO_POINTER(DATASETTE_CONTROL_RECORD),
280         0, 0 },
281     { "Reset", UI_MENU_TYPE_ITEM_ACTION,
282         "tape-reset", ui_datasette_tape_action_cb, GINT_TO_POINTER(DATASETTE_CONTROL_RESET),
283         0, 0 },
284     { "Reset Counter", UI_MENU_TYPE_ITEM_ACTION,
285         "tape-counter", ui_datasette_tape_action_cb, GINT_TO_POINTER(DATASETTE_CONTROL_RESET_COUNTER),
286         0, 0 },
287     UI_MENU_TERMINATOR
288 };
289 
290 #if 0
291 /** \brief  'File->Cartridge attach' submenu
292  */
293 static ui_menu_item_t cart_attach_submenu[] = {
294     { "Smart attach cart image ... ", UI_MENU_TYPE_ITEM_ACTION,
295         "attach-cart", (void *)uicart_smart_attach_dialog, NULL,
296         GDK_KEY_C, VICE_MOD_MASK },
297     UI_MENU_TERMINATOR
298 };
299 #endif
300 
301 
302 /** \brief  File->Reset submenu
303  */
304 static ui_menu_item_t reset_submenu[] = {
305     { "Soft reset", UI_MENU_TYPE_ITEM_ACTION,
306         "reset-soft", ui_machine_reset_callback, GINT_TO_POINTER(MACHINE_RESET_MODE_SOFT),
307         GDK_KEY_F9, VICE_MOD_MASK },
308     { "Hard reset", UI_MENU_TYPE_ITEM_ACTION,
309         "reset-hard", ui_machine_reset_callback, GINT_TO_POINTER(MACHINE_RESET_MODE_HARD),
310         GDK_KEY_F12, VICE_MOD_MASK },
311 
312     UI_MENU_SEPARATOR,
313 
314     { "Reset drive #8", UI_MENU_TYPE_ITEM_ACTION,
315         "reset-drive8", ui_drive_reset_callback, GINT_TO_POINTER(8),
316         0, 0 },
317     { "Reset drive #9", UI_MENU_TYPE_ITEM_ACTION,
318         "reset-drive9", ui_drive_reset_callback, GINT_TO_POINTER(9),
319         0, 0 },
320     { "Reset drive #10", UI_MENU_TYPE_ITEM_ACTION,
321         "reset-drive10", ui_drive_reset_callback, GINT_TO_POINTER(10),
322         0, 0 },
323     { "Reset drive #11", UI_MENU_TYPE_ITEM_ACTION,
324         "reset-drive11", ui_drive_reset_callback, GINT_TO_POINTER(11),
325         0, 0 },
326 
327     UI_MENU_TERMINATOR
328 };
329 
330 
331 /** \brief  'File' menu - head section
332  */
333 static ui_menu_item_t file_menu_head[] = {
334     { "Smart attach disk/tape ...", UI_MENU_TYPE_ITEM_ACTION,
335         "smart-attach", ui_smart_attach_callback, NULL,
336         GDK_KEY_A, VICE_MOD_MASK },
337 
338     UI_MENU_SEPARATOR,
339 
340     /* disk */
341     { "Attach disk image", UI_MENU_TYPE_SUBMENU,
342         NULL, NULL, attach_submenu,
343         GDK_KEY_8, VICE_MOD_MASK },
344     { "Create and attach an empty disk image ...", UI_MENU_TYPE_ITEM_ACTION,
345         "create-disk", uidiskcreate_dialog_show, GINT_TO_POINTER(8),
346         0, 0 },
347     { "Detach disk image", UI_MENU_TYPE_SUBMENU,
348         NULL, NULL, detach_submenu,
349         0, 0 },
350     { "Flip list", UI_MENU_TYPE_SUBMENU,
351         NULL, NULL, fliplist_submenu,
352         0, 0 },
353 
354     UI_MENU_SEPARATOR,
355 
356     UI_MENU_TERMINATOR
357 };
358 
359 
360 /** \brief  'File' menu - tape section pointer
361  *
362  * Set by ...
363  */
364 static ui_menu_item_t *file_menu_tape_section = NULL;
365 
366 
367 /** \brief  'File' menu - tape section
368  */
369 static ui_menu_item_t file_menu_tape[] = {
370     { "Attach tape image ...", UI_MENU_TYPE_ITEM_ACTION,
371         "attach-tape", ui_tape_attach_callback, NULL,
372         GDK_KEY_T, VICE_MOD_MASK },
373     { "Create and attach an empty tape image ...", UI_MENU_TYPE_ITEM_ACTION,
374         "create-tape", uitapecreate_dialog_show, NULL,
375         0, 0 },
376     { "Detach tape image", UI_MENU_TYPE_ITEM_ACTION,
377         "detach-tape", ui_tape_detach_callback, NULL,
378         0, 0 },
379     { "Datasette controls", UI_MENU_TYPE_SUBMENU,
380         NULL, NULL, datasette_control_submenu,
381         0, 0 },
382 
383     UI_MENU_SEPARATOR,
384 
385     UI_MENU_TERMINATOR
386 };
387 
388 
389 /** \brief  'File' menu - tail section
390  */
391 static ui_menu_item_t file_menu_tail[] = {
392     /* cart */
393     { "Attach cartridge image ...", UI_MENU_TYPE_ITEM_ACTION,
394         "cart-attach", uicart_show_dialog, NULL,
395         GDK_KEY_C, VICE_MOD_MASK },
396     { "Detach cartridge image(s)", UI_MENU_TYPE_ITEM_ACTION,
397         "cart-detach", (void *)uicart_detach, NULL,
398         0, 0 },
399     { "Cartridge freeze", UI_MENU_TYPE_ITEM_ACTION,
400         "cart-freeze", (void *)uicart_trigger_freeze, NULL,
401         GDK_KEY_Z, VICE_MOD_MASK },
402 
403     UI_MENU_SEPARATOR,
404 
405     /* monitor */
406     { "Activate monitor", UI_MENU_TYPE_ITEM_ACTION,
407         "monitor", ui_monitor_activate_callback, NULL,
408 #ifdef MACOSX_SUPPORT
409         /* use Command-Option-M on Mac */
410         GDK_KEY_M, VICE_MOD_MASK | GDK_MOD1_MASK
411 #else
412         GDK_KEY_H, VICE_MOD_MASK
413 #endif
414     },
415 
416     UI_MENU_SEPARATOR,
417 
418 #ifdef HAVE_NETWORK
419     { "Netplay ...", UI_MENU_TYPE_ITEM_ACTION,
420 #if 0
421         "netplay", ui_netplay_dialog_new, NULL,
422 #else
423         "netplay", ui_netplay_dialog, NULL,
424 #endif
425         0, 0 },
426 
427     UI_MENU_SEPARATOR,
428 #endif
429 
430     { "Reset", UI_MENU_TYPE_SUBMENU,
431         NULL, NULL, reset_submenu,
432         0, 0 },
433 
434     UI_MENU_SEPARATOR,
435 
436     { "Exit emulator", UI_MENU_TYPE_ITEM_ACTION,
437         "exit", ui_close_callback, NULL,
438         GDK_KEY_Q, VICE_MOD_MASK },
439 
440     UI_MENU_TERMINATOR
441 };
442 
443 
444 /** \brief  'Edit' menu
445  */
446 static ui_menu_item_t edit_menu[] = {
447     { "Copy", UI_MENU_TYPE_ITEM_ACTION,
448         "copy", (void *)ui_copy_callback, NULL,
449         GDK_KEY_Delete, VICE_MOD_MASK },
450     { "Paste", UI_MENU_TYPE_ITEM_ACTION,
451         "paste", (void *)ui_paste_callback, NULL,
452         GDK_KEY_Insert, VICE_MOD_MASK },
453 
454     UI_MENU_TERMINATOR
455 };
456 
457 
458 /** \brief  'Snapshot' menu
459  */
460 static ui_menu_item_t snapshot_menu[] = {
461     { "Load snapshot image ...", UI_MENU_TYPE_ITEM_ACTION,
462         "snapshot-load", uisnapshot_open_file, NULL,
463         GDK_KEY_L, VICE_MOD_MASK },
464     { "Save snapshot image ...", UI_MENU_TYPE_ITEM_ACTION,
465         "snapshot-save", uisnapshot_save_file, NULL,
466         GDK_KEY_S, VICE_MOD_MASK },
467 
468     UI_MENU_SEPARATOR,
469 
470     { "Quickload snapshot", UI_MENU_TYPE_ITEM_ACTION,
471         "snapshot-quickload", uisnapshot_quickload_snapshot, NULL,
472         GDK_KEY_F10, VICE_MOD_MASK },   /* Shortcut doesn't work in MATE, key
473                                          is mapped to Maximize Window. Using
474                                          the menu to active this item does
475                                          work though -- compyx */
476     { "Quicksave snapshot", UI_MENU_TYPE_ITEM_ACTION,
477         "snapshot-quicksave", uisnapshot_quicksave_snapshot, NULL,
478         GDK_KEY_F11, VICE_MOD_MASK },
479 
480     UI_MENU_SEPARATOR,
481 #if 0
482     { "Select history directory ...", UI_MENU_TYPE_ITEM_ACTION,
483         "history-select-dir", uisnapshot_history_select_dir, "0:3",
484         0, 0 },
485 #endif
486     { "Start recording events", UI_MENU_TYPE_ITEM_ACTION,
487         "history-record-start", uisnapshot_history_record_start, NULL,
488         0, 0 },
489     { "Stop recording events", UI_MENU_TYPE_ITEM_ACTION,
490         "history-record-stop", uisnapshot_history_record_stop, NULL,
491         0, 0 },
492     { "Start playing back events", UI_MENU_TYPE_ITEM_ACTION,
493         "history-playback-start", uisnapshot_history_playback_start, NULL,
494         0, 0 },
495     { "Stop playing back events", UI_MENU_TYPE_ITEM_ACTION,
496         "history-playback-stop", uisnapshot_history_playback_stop, NULL,
497         0, 0 },
498     { "Set recording milestone", UI_MENU_TYPE_ITEM_ACTION,
499         "history-milestone-set", uisnapshot_history_milestone_set, NULL,
500         GDK_KEY_E, VICE_MOD_MASK },
501     { "Return to milestone", UI_MENU_TYPE_ITEM_ACTION,
502         "history-milestone-reset", uisnapshot_history_milestone_reset, NULL,
503         GDK_KEY_U, VICE_MOD_MASK },
504 
505     UI_MENU_SEPARATOR,
506 #if 0
507     { "Recording start mode ...", UI_MENU_TYPE_ITEM_ACTION,
508         "history-recording-start-mode", ui_settings_dialog_create, "20,0",
509         0, 0 },
510 
511     UI_MENU_SEPARATOR,
512 #endif
513 
514     { "Save media file ...", UI_MENU_TYPE_ITEM_ACTION,
515         "media-save", uimedia_dialog_show, NULL,
516         GDK_KEY_R, VICE_MOD_MASK | GDK_SHIFT_MASK },
517 
518     { "Stop media recording", UI_MENU_TYPE_ITEM_ACTION,
519         "media-stop", (void *)uimedia_stop_recording, NULL,
520         GDK_KEY_S, VICE_MOD_MASK | GDK_SHIFT_MASK },
521 
522     UI_MENU_TERMINATOR
523 };
524 
525 
526 /** \brief  'Settings' menu - head section
527  */
528 static ui_menu_item_t settings_menu_head[] = {
529     { "Toggle fullscreen", UI_MENU_TYPE_ITEM_ACTION,
530         "fullscreen", ui_fullscreen_callback, NULL,
531         GDK_KEY_D, VICE_MOD_MASK },
532 #if 1
533     { "Show menu/status in fullscreen", UI_MENU_TYPE_ITEM_ACTION,
534         "fullscreen-widgets", ui_fullscreen_decorations_callback, NULL,
535         GDK_KEY_B, VICE_MOD_MASK },
536 #else
537     /* Mac menubar version */
538     { "Show statusbar in fullscreen", UI_MENU_TYPE_ITEM_ACTION,
539         "fullscreen-widgets", ui_fullscreen_decorations_callback, NULL,
540         GDK_KEY_B, VICE_MOD_MASK },
541 #endif
542 
543 #if 0
544     UI_MENU_SEPARATOR,
545     { "Toggle warp mode", UI_MENU_TYPE_ITEM_CHECK,
546         "warp", (void *)(ui_toggle_resource), (void *)"WarpMode",
547         GDK_KEY_W, VICE_MOD_MASK },
548     { "Pause emulation", UI_MENU_TYPE_ITEM_CHECK,
549         "pause", (void *)(ui_toggle_pause), NULL,
550         GDK_KEY_P, VICE_MOD_MASK },
551     { "Advance frame", UI_MENU_TYPE_ITEM_ACTION,
552         "frame-advance", (void *)(ui_advance_frame), NULL,
553         GDK_KEY_P, VICE_MOD_MASK | GDK_SHIFT_MASK },
554 #endif
555     UI_MENU_SEPARATOR,
556 
557     UI_MENU_TERMINATOR
558 };
559 
560 
561 /** \brief  'Settings' menu - joystick section pointer
562  *
563  * Set by ...
564  */
565 static ui_menu_item_t *settings_menu_joy_section = NULL;
566 
567 
568 /** \brief  'Settings' menu - all joystick items
569  *
570  * Only valid for x64/x64sc/xscpu64/x128/xplus4
571  */
572 static ui_menu_item_t settings_menu_all_joy[] = {
573 
574     { "Swap joysticks", UI_MENU_TYPE_ITEM_ACTION,
575         "joystick-swap", (void *)(ui_swap_joysticks_callback), NULL,
576         GDK_KEY_J, VICE_MOD_MASK },
577     { "Swap userport joysticks", UI_MENU_TYPE_ITEM_ACTION,
578         "userportjoy-swap", (void *)(ui_swap_userport_joysticks_callback), NULL,
579         GDK_KEY_U, VICE_MOD_MASK | GDK_SHIFT_MASK },
580     { "Allow keyset joystick", UI_MENU_TYPE_ITEM_CHECK,
581         "keyset", (void *)(ui_toggle_resource), (void *)"KeySetEnable",
582         GDK_KEY_J, VICE_MOD_MASK | GDK_SHIFT_MASK },
583     { "Enable mouse grab", UI_MENU_TYPE_ITEM_CHECK,
584         "mouse", (void *)(ui_toggle_resource), (void *)"Mouse",
585         GDK_KEY_M, VICE_MOD_MASK },
586 
587     UI_MENU_TERMINATOR
588 };
589 
590 /** \brief  'Settings' menu - control port joystick items
591  *
592  * Only valid for x64dtv/xcbm5x0
593  */
594 static ui_menu_item_t settings_menu_cbm5x0_joy[] = {
595 
596     { "Swap joysticks", UI_MENU_TYPE_ITEM_ACTION,
597         "joystick-swap", (void *)(ui_swap_joysticks_callback), NULL,
598         GDK_KEY_J, VICE_MOD_MASK },
599     { "Allow keyset joystick", UI_MENU_TYPE_ITEM_CHECK,
600         "keyset", (void *)(ui_toggle_resource), (void *)"KeySetEnable",
601         GDK_KEY_J, VICE_MOD_MASK | GDK_SHIFT_MASK },
602     { "Enable mouse grab", UI_MENU_TYPE_ITEM_CHECK,
603         "mouse", (void *)(ui_toggle_resource), (void *)"Mouse",
604         GDK_KEY_M, VICE_MOD_MASK },
605 
606     UI_MENU_TERMINATOR
607 };
608 
609 /** \brief  'Settings' menu - userport joystick items
610  *
611  * Only valid for xvic/xpet/xcbm2
612  */
613 static ui_menu_item_t settings_menu_userport_joy[] = {
614     { "Swap userport joysticks", UI_MENU_TYPE_ITEM_ACTION,
615         "userportjoy-swap", (void *)(ui_swap_userport_joysticks_callback), NULL,
616         GDK_KEY_U, VICE_MOD_MASK | GDK_SHIFT_MASK },
617     { "Allow keyset joystick", UI_MENU_TYPE_ITEM_CHECK,
618         "keyset", (void *)(ui_toggle_resource), (void *)"KeySetEnable",
619         GDK_KEY_J, VICE_MOD_MASK | GDK_SHIFT_MASK },
620     { "Enable mouse grab", UI_MENU_TYPE_ITEM_CHECK,
621         "mouse", (void *)(ui_toggle_resource), (void *)"Mouse",
622         GDK_KEY_M, VICE_MOD_MASK },
623 
624     UI_MENU_TERMINATOR
625 };
626 
627 /** \brief  'Settings' menu tail section
628  */
629 static ui_menu_item_t settings_menu_tail[] = {
630 
631     UI_MENU_SEPARATOR,
632 
633     /* the settings dialog */
634     { "Settings ...", UI_MENU_TYPE_ITEM_ACTION,
635         "settings", (void *)ui_settings_dialog_create, NULL,
636         GDK_KEY_O, VICE_MOD_MASK },
637     { "Load settings", UI_MENU_TYPE_ITEM_ACTION,
638         "settings-load", settings_load_callback, NULL,
639         0, 0 },
640     { "Load custom settings ...", UI_MENU_TYPE_ITEM_ACTION,
641         "settings-load-custom", settings_load_custom_callback, NULL,
642         0, 0 },
643     { "Save settings", UI_MENU_TYPE_ITEM_ACTION,
644         "settings-save", settings_save_callback, NULL,
645         0, 0 },
646     { "Save custom settings ...", UI_MENU_TYPE_ITEM_ACTION,
647         "settings-save-custom", settings_save_custom_callback, NULL,
648         0, 0 },
649     UI_MENU_TERMINATOR
650 };
651 
652 
653 #ifdef DEBUG
654 
655 /** \brief  'Debug' menu items for emu's except x64dtv
656  */
657 static ui_menu_item_t debug_menu[] = {
658     { "Trace mode ...", UI_MENU_TYPE_ITEM_ACTION,
659         "tracemode", uidebug_trace_mode_callback, NULL,
660         0, 0 },
661 
662     UI_MENU_SEPARATOR,
663 
664     { "Main CPU trace", UI_MENU_TYPE_ITEM_CHECK,
665         "trace-maincpu", (void *)(ui_toggle_resource), (void *)"MainCPU_TRACE",
666         0, 0 },
667 
668     UI_MENU_SEPARATOR,
669 
670     { "Drive #8 CPU trace", UI_MENU_TYPE_ITEM_CHECK,
671         "trace-drive8", (void *)(ui_toggle_resource), (void *)"Drive0CPU_TRACE",
672         0, 0 },
673     { "Drive #9 CPU trace", UI_MENU_TYPE_ITEM_CHECK,
674         "trace-drive9", (void *)(ui_toggle_resource), (void *)"Drive1CPU_TRACE",
675         0, 0 },
676     { "Drive #10 CPU trace", UI_MENU_TYPE_ITEM_CHECK,
677         "trace-drive10", (void *)(ui_toggle_resource), (void *)"Drive2CPU_TRACE",
678         0, 0 },
679     { "Drive #11 CPU trace", UI_MENU_TYPE_ITEM_CHECK,
680         "trace-drive11", (void *)(ui_toggle_resource), (void *)"Drive3CPU_TRACE",
681         0, 0 },
682 
683     UI_MENU_SEPARATOR,
684 
685     { "Autoplay playback frames ...", UI_MENU_TYPE_ITEM_ACTION,
686         "playframes", uidebug_playback_frames_callback, NULL,
687         0, 0 },
688     { "Save core dump", UI_MENU_TYPE_ITEM_CHECK,
689         "coredump", (void *)(ui_toggle_resource), (void *)"DoCoreDump",
690         0, 0 },
691 
692     UI_MENU_TERMINATOR
693 };
694 
695 
696 /** \brief  'Debug' menu items for x64dtv
697  */
698 static ui_menu_item_t debug_menu_c64dtv[] = {
699     { "Trace mode ...", UI_MENU_TYPE_ITEM_ACTION,
700         "tracemode", uidebug_trace_mode_callback, NULL,
701         0, 0 },
702 
703     UI_MENU_SEPARATOR,
704 
705     { "Main CPU trace", UI_MENU_TYPE_ITEM_CHECK,
706         "trace-maincpu", (void *)(ui_toggle_resource), (void *)"MainCPU_TRACE",
707         0, 0 },
708 
709     UI_MENU_SEPARATOR,
710 
711     { "Drive #8 CPU trace", UI_MENU_TYPE_ITEM_CHECK,
712         "trace-drive8", (void *)(ui_toggle_resource), (void *)"Drive0CPU_TRACE",
713         0, 0 },
714     { "Drive #9 CPU trace", UI_MENU_TYPE_ITEM_CHECK,
715         "trace-drive9", (void *)(ui_toggle_resource), (void *)"Drive1CPU_TRACE",
716         0, 0 },
717     { "Drive #10 CPU trace", UI_MENU_TYPE_ITEM_CHECK,
718         "trace-drive10", (void *)(ui_toggle_resource), (void *)"Drive2CPU_TRACE",
719         0, 0 },
720     { "Drive #11 CPU trace", UI_MENU_TYPE_ITEM_CHECK,
721         "trace-drive11", (void *)(ui_toggle_resource), (void *)"Drive3CPU_TRACE",
722         0, 0 },
723 
724     UI_MENU_SEPARATOR,
725 
726     { "Blitter log", UI_MENU_TYPE_ITEM_CHECK,
727       "blitter-log", (void *)ui_toggle_resource, (void *)"DtvBlitterLog",
728       0, 0 },
729     { "DMA log", UI_MENU_TYPE_ITEM_CHECK,
730       "dma-log", (void *)ui_toggle_resource, (void *)"DtvDMALog",
731       0, 0 },
732     { "Flash log", UI_MENU_TYPE_ITEM_CHECK,
733       "flash-log", (void *)ui_toggle_resource, (void*)"DtvFlashLog",
734       0, 0 },
735 
736     UI_MENU_SEPARATOR,
737 
738     { "Autoplay playback frames ...", UI_MENU_TYPE_ITEM_ACTION,
739         "playframes", uidebug_playback_frames_callback, NULL,
740         0, 0 },
741     { "Save core dump", UI_MENU_TYPE_ITEM_CHECK,
742         "coredump", (void *)(ui_toggle_resource), (void *)"DoCoreDump",
743         0, 0 },
744 
745     UI_MENU_TERMINATOR
746 };
747 
748 #endif
749 
750 
751 /** \brief  'Help' menu items
752  */
753 static ui_menu_item_t help_menu[] = {
754     { "Browse manual", UI_MENU_TYPE_ITEM_ACTION,
755         "manual", ui_open_manual_callback, NULL,
756         0, 0 },
757     { "Command line options ...", UI_MENU_TYPE_ITEM_ACTION,
758         "cmdline", uicmdline_dialog_show, NULL,
759         0, 0 },
760     { "Compile time features ...", UI_MENU_TYPE_ITEM_ACTION,
761         "features", uicompiletimefeatures_dialog_show, NULL,
762         0, 0 },
763     { "About VICE", UI_MENU_TYPE_ITEM_ACTION,
764         "about", ui_about_dialog_callback, NULL,
765         0, 0 },
766 
767     UI_MENU_TERMINATOR
768 };
769 
770 
771 /** \brief  Create the top menu bar with standard submenus
772  *
773  * \return  GtkMenuBar
774  */
ui_machine_menu_bar_create(void)775 GtkWidget *ui_machine_menu_bar_create(void)
776 {
777     GtkWidget *menu_bar;
778 
779     /* create the top menu bar */
780     menu_bar = gtk_menu_bar_new();
781 
782     /* create the top-level 'File' menu */
783     file_submenu = ui_menu_submenu_create(menu_bar, "File");
784 
785     /* create the top-level 'Edit' menu */
786     edit_submenu = ui_menu_submenu_create(menu_bar, "Edit");
787 
788     /* create the top-level 'Snapshot' menu */
789     snapshot_submenu = ui_menu_submenu_create(menu_bar, "Snapshot");
790 
791     /* create the top-level 'Settings' menu */
792     settings_submenu = ui_menu_submenu_create(menu_bar, "Settings");
793 
794 #ifdef DEBUG
795     /* create the top-level 'Debug' menu (when --enable-debug is used) */
796     debug_submenu = ui_menu_submenu_create(menu_bar, "Debug");
797 #endif
798 
799     /* create the top-level 'Help' menu */
800     help_submenu = ui_menu_submenu_create(menu_bar, "Help");
801 
802     /* determine which joystick swap menu items should be added */
803     switch (machine_class) {
804         case VICE_MACHINE_C64:      /* fall through */
805         case VICE_MACHINE_C64SC:    /* fall through */
806         case VICE_MACHINE_C128:     /* fall through */
807         case VICE_MACHINE_PLUS4:
808             /* add tape section */
809             file_menu_tape_section = file_menu_tape;
810             /* fall through */
811         case VICE_MACHINE_SCPU64:
812             /* add both swap-joy and swap-userport-joy */
813             settings_menu_joy_section = settings_menu_all_joy;
814             break;
815         case VICE_MACHINE_CBM5x0:
816             /* add tape section */
817             file_menu_tape_section = file_menu_tape;
818             /* fall through */
819         case VICE_MACHINE_C64DTV:
820             /* only add swap-joy */
821             settings_menu_joy_section = settings_menu_cbm5x0_joy;
822             break;
823         case VICE_MACHINE_PET:      /* fall through */
824         case VICE_MACHINE_VIC20:    /* fall through */
825         case VICE_MACHINE_CBM6x0:
826             /* add tape section */
827             file_menu_tape_section = file_menu_tape;
828             /* only add swap-userport-joy */
829             settings_menu_joy_section = settings_menu_userport_joy;
830             break;
831         case VICE_MACHINE_VSID:
832             archdep_vice_exit(1);
833             break;
834         default:
835             break;
836     }
837 
838     /* add items to the File menu */
839     ui_menu_add(file_submenu, file_menu_head);
840     if (file_menu_tape_section != NULL) {
841         ui_menu_add(file_submenu, file_menu_tape_section);
842     }
843     ui_menu_add(file_submenu, file_menu_tail);
844 
845     /* add items to the Edit menu */
846     ui_menu_add(edit_submenu, edit_menu);
847     /* add items to the Snapshot menu */
848     ui_menu_add(snapshot_submenu, snapshot_menu);
849 
850     /* add items to the Settings menu */
851     ui_menu_add(settings_submenu, settings_menu_head);
852     if (settings_menu_joy_section != NULL) {
853         ui_menu_add(settings_submenu, settings_menu_joy_section);
854     }
855     ui_menu_add(settings_submenu, settings_menu_tail);
856 
857 #ifdef DEBUG
858     /* add items to the Debug menu */
859     if (machine_class == VICE_MACHINE_C64DTV) {
860         ui_menu_add(debug_submenu, debug_menu_c64dtv);
861     } else {
862         ui_menu_add(debug_submenu, debug_menu);
863     }
864 #endif
865 
866     /* add items to the Help menu */
867     ui_menu_add(help_submenu, help_menu);
868 
869     main_menu_bar = menu_bar;    /* XXX: do I need g_object_ref()/g_object_unref()
870                                          for this */
871     return menu_bar;
872 }
873