From 2e845063632cfef755317976dbd0d3e86319d974 Mon Sep 17 00:00:00 2001 From: Richard Cornwell Date: Thu, 3 Dec 2020 19:48:12 -0500 Subject: [PATCH] SCP: Updated to current. --- scp.c | 72 ++--- sim_ether.c | 4 +- sim_video.c | 809 ++++++++++++++++++++++++++++++++++------------------ sim_video.h | 19 +- 4 files changed, 590 insertions(+), 314 deletions(-) diff --git a/scp.c b/scp.c index caedbe9..e3fb9a8 100644 --- a/scp.c +++ b/scp.c @@ -520,6 +520,7 @@ typedef enum { SW_NUMBER /* Numeric Value */ } SWITCH_PARSE; SWITCH_PARSE get_switches (const char *cptr, int32 *sw_val, int32 *sw_number); +void put_rval_pcchk (REG *rptr, uint32 idx, t_value val, t_bool pc_chk); void put_rval (REG *rptr, uint32 idx, t_value val); void fprint_help (FILE *st); void fprint_stopped (FILE *st, t_stat r); @@ -1567,9 +1568,7 @@ static const char simh_help2[] = "+sh{ow} ethernet show ethernet devices\n" "+sh{ow} serial show serial devices\n" "+sh{ow} multiplexer {dev} show open multiplexer device info\n" -#if defined(USE_SIM_VIDEO) "+sh{ow} video show video capabilities\n" -#endif "+sh{ow} clocks show calibrated timer information\n" "+sh{ow} throttle show throttle info\n" "+sh{ow} on show on condition actions\n" @@ -2416,7 +2415,7 @@ static const char simh_help2[] = /***************** 80 character line width template *************************/ #define HLP_SCREENSHOT "*Commands Screenshot_Video_Window" "2Screenshot Video Window\n" - " Simulators with Video devices display the simulated video in a window\n" + " Simulators with Video devices display the simulated video in a window(s)\n" " on the local system. The contents of that display can be saved in a\n" " file with the SCREENSHOT command:\n\n" "++SCREENSHOT screenshotfile\n\n" @@ -2472,7 +2471,7 @@ static const char simh_help2[] = #define HLP_CURL "*Commands File_Tools Curl_Tool" "3Curl Tool\n" " curl is a utility to transfer a URL\n\n" - " The quick and dirty help for the TAR command can be viewed with:\n\n" + " The quick and dirty help for the CURL command can be viewed with:\n\n" "++sim> curl --help\n\n" #define HLP_DISKINFO "*Commands DISKINFO" "2Disk Container Information\n" @@ -2546,9 +2545,7 @@ static CTAB cmd_table[] = { { "SLEEP", &sleep_cmd, 0, HLP_SLEEP, NULL, NULL }, { "!", &spawn_cmd, 0, HLP_SPAWN, NULL, NULL }, { "HELP", &help_cmd, 0, HLP_HELP, NULL, NULL }, -#if defined(USE_SIM_VIDEO) { "SCREENSHOT", &screenshot_cmd,0, HLP_SCREENSHOT, NULL, NULL }, -#endif { "TAR", &tar_cmd, 0, HLP_TAR, NULL, NULL }, { "CURL", &curl_cmd, 0, HLP_CURL, NULL, NULL }, { "RUNLIMIT", &runlimit_cmd, 1, HLP_RUNLIMIT, NULL, NULL }, @@ -2640,9 +2637,7 @@ static SHTAB show_glob_tab[] = { { "SERIAL", &sim_show_serial, 0, HLP_SHOW_SERIAL }, { "MULTIPLEXER", &tmxr_show_open_devices, 0, HLP_SHOW_MULTIPLEXER }, { "MUX", &tmxr_show_open_devices, 0, HLP_SHOW_MULTIPLEXER }, -#if defined(USE_SIM_VIDEO) { "VIDEO", &vid_show, 0, HLP_SHOW_VIDEO }, -#endif { "CLOCKS", &sim_show_timers, 0, HLP_SHOW_CLOCKS }, { "SEND", &sim_show_send, 0, HLP_SHOW_SEND }, { "EXPECT", &sim_show_expect, 0, HLP_SHOW_EXPECT }, @@ -2803,15 +2798,15 @@ if ((stat = sim_ttinit ()) != SCPE_OK) { sim_error_text (stat)); if (sim_ttisatty()) read_line_p ("Hit Return to exit: ", cbuf, sizeof (cbuf) - 1, stdin); - free (targv); - return EXIT_FAILURE; + sim_exit_status = EXIT_FAILURE; + goto cleanup_and_exit; } if ((sim_eval = (t_value *) calloc (sim_emax, sizeof (t_value))) == NULL) { fprintf (stderr, "Unable to allocate examine buffer\n"); if (sim_ttisatty()) read_line_p ("Hit Return to exit: ", cbuf, sizeof (cbuf) - 1, stdin); - free (targv); - return EXIT_FAILURE; + sim_exit_status = EXIT_FAILURE; + goto cleanup_and_exit; }; if (sim_dflt_dev == NULL) /* if no default */ sim_dflt_dev = sim_devices[0]; @@ -2820,8 +2815,8 @@ if ((stat = reset_all_p (0)) != SCPE_OK) { sim_failed_reset_dptr->name, sim_error_text (stat)); if (sim_ttisatty()) read_line_p ("Hit Return to exit: ", cbuf, sizeof (cbuf) - 1, stdin); - free (targv); - return EXIT_FAILURE; + sim_exit_status = EXIT_FAILURE; + goto cleanup_and_exit; } if (register_check) { /* This test is explicitly run after the above reset_all_p() so that any devices @@ -2831,13 +2826,13 @@ if (register_check) { sim_printf ("Simulator device register sanity check error\n"); if (sim_ttisatty()) read_line_p ("Hit Return to exit: ", cbuf, sizeof (cbuf) - 1, stdin); - free (targv); - return EXIT_FAILURE; + sim_exit_status = EXIT_FAILURE; + goto cleanup_and_exit; } sim_printf ("*** Good Registers in %s simulator.\n", sim_name); if (argc < 2) { /* No remaining command arguments? */ - free (targv); - return EXIT_SUCCESS; /* then we're done */ + sim_exit_status = EXIT_SUCCESS; /* then we're done */ + goto cleanup_and_exit; } } if ((stat = sim_brk_init ()) != SCPE_OK) { @@ -2845,8 +2840,8 @@ if ((stat = sim_brk_init ()) != SCPE_OK) { sim_error_text (stat)); if (sim_ttisatty()) read_line_p ("Hit Return to exit: ", cbuf, sizeof (cbuf) - 1, stdin); - free (targv); - return EXIT_FAILURE; + sim_exit_status = EXIT_FAILURE; + goto cleanup_and_exit; } /* always check for register definition problems */ sim_sanity_check_register_declarations (); @@ -2907,11 +2902,13 @@ if (SCPE_BARE_STATUS(stat) == SCPE_OPENERR) /* didn't exist/can't op if (SCPE_BARE_STATUS(stat) != SCPE_EXIT) process_stdin_commands (SCPE_BARE_STATUS(stat), argv, FALSE); +cleanup_and_exit: + detach_all (0, TRUE); /* close files */ sim_set_deboff (0, NULL); /* close debug */ sim_set_logoff (0, NULL); /* close log */ sim_set_notelnet (0, NULL); /* close Telnet */ -vid_close (); /* close video */ +vid_close_all (); /* close video */ sim_ttclose (); /* close console */ AIO_CLEANUP; /* Asynch I/O */ sim_cleanup_sock (); /* cleanup sockets */ @@ -3706,12 +3703,7 @@ t_stat screenshot_cmd (int32 flag, CONST char *cptr) { if ((cptr == NULL) || (strlen (cptr) == 0)) return sim_messagef (SCPE_ARG, "Missing screen shot filename\n"); -#if defined (USE_SIM_VIDEO) return vid_screenshot (cptr); -#else -sim_printf ("No video device\n"); -return SCPE_UNK|SCPE_NOMESSAGE; -#endif } /* Echo command */ @@ -8600,7 +8592,7 @@ CONST char *tptr; uint32 i, j; int32 sim_next = 0; int32 unitno; -t_value pcv, orig_pcv; +t_value new_pcv, orig_pcv; t_stat r; DEVICE *dptr; UNIT *uptr; @@ -8613,22 +8605,25 @@ if (sim_runlimit_enabled && /* If the run limit has GET_SWITCHES (cptr); /* get switches */ sim_step = 0; if ((flag == RU_RUN) || (flag == RU_GO)) { /* run or go */ - orig_pcv = get_rval (sim_PC, 0); /* get current PC value */ + t_bool new_pc = FALSE; + + new_pcv = orig_pcv = get_rval (sim_PC, 0); /* get current PC value */ if (*cptr != 0) { /* argument? */ cptr = get_glyph (cptr, gbuf, 0); /* get next glyph */ if (MATCH_CMD (gbuf, "UNTIL") != 0) { if (sim_vm_parse_addr) /* address parser? */ - pcv = sim_vm_parse_addr (sim_dflt_dev, gbuf, &tptr); - else pcv = strtotv (gbuf, &tptr, sim_PC->radix);/* parse PC */ + new_pcv = sim_vm_parse_addr (sim_dflt_dev, gbuf, &tptr); + else + new_pcv = strtotv (gbuf, &tptr, sim_PC->radix);/* parse PC */ if ((tptr == gbuf) || (*tptr != 0) || /* error? */ - (pcv > width_mask[sim_PC->width])) + (new_pcv > width_mask[sim_PC->width])) return SCPE_ARG; - put_rval (sim_PC, 0, pcv); /* Save in PC */ + new_pc = TRUE; } } if ((flag == RU_RUN) && /* run? */ ((r = sim_run_boot_prep (flag)) != SCPE_OK)) { /* reset sim */ - put_rval (sim_PC, 0, orig_pcv); /* restore original PC */ + put_rval_pcchk (sim_PC, 0, orig_pcv, FALSE); /* restore original PC */ return r; } if ((*cptr) || (MATCH_CMD (gbuf, "UNTIL") == 0)) { /* should be end */ @@ -8658,6 +8653,7 @@ if ((flag == RU_RUN) || (flag == RU_GO)) { /* run or go */ } sim_switches = saved_switches; } + put_rval_pcchk (sim_PC, 0, new_pcv, new_pc); /* Save in PC */ } else if ((flag == RU_STEP) || @@ -9414,7 +9410,7 @@ return SCPE_OK; none */ -void put_rval (REG *rptr, uint32 idx, t_value val) +void put_rval_pcchk (REG *rptr, uint32 idx, t_value val, t_bool pc_chk) { size_t sz; t_value mask; @@ -9425,7 +9421,7 @@ uint32 *ptr; (sz)((*(((sz *) rp->loc) + id) & \ ~((m) << (rp)->offset)) | ((v) << (rp)->offset)) -if (rptr == sim_PC) +if (pc_chk && (rptr == sim_PC)) sim_brk_npc (0); sz = SZ_R (rptr); mask = width_mask[rptr->width]; @@ -9479,6 +9475,12 @@ else PUT_RVAL (uint32, rptr, idx, val, mask); #endif } +void put_rval (REG *rptr, uint32 idx, t_value val) +{ +put_rval_pcchk (rptr, idx, val, TRUE); +} + + /* Examine address routine Inputs: (sim_eval is an implicit argument) diff --git a/sim_ether.c b/sim_ether.c index f9c7868..7848876 100644 --- a/sim_ether.c +++ b/sim_ether.c @@ -751,12 +751,12 @@ void eth_zero(ETH_DEV* dev) dev->reflections = -1; /* not established yet */ } -static char* (*p_pcap_lib_version) (void); - static ETH_DEV **eth_open_devices = NULL; static int eth_open_device_count = 0; #if defined (USE_NETWORK) || defined (USE_SHARED) +static char* (*p_pcap_lib_version) (void); + static void _eth_add_to_open_list (ETH_DEV* dev) { eth_open_devices = (ETH_DEV**)realloc(eth_open_devices, (eth_open_device_count+1)*sizeof(*eth_open_devices)); diff --git a/sim_video.c b/sim_video.c index 796f4f4..d750048 100644 --- a/sim_video.c +++ b/sim_video.c @@ -30,7 +30,7 @@ #include "sim_video.h" #include "scp.h" -t_bool vid_active = FALSE; +int vid_active = 0; int32 vid_cursor_x; int32 vid_cursor_y; t_bool vid_mouse_b1 = FALSE; @@ -40,7 +40,6 @@ static VID_QUIT_CALLBACK vid_quit_callback = NULL; static VID_GAMEPAD_CALLBACK motion_callback[10]; static VID_GAMEPAD_CALLBACK button_callback[10]; static int vid_gamepad_inited = 0; -static int vid_gamepad_ok = 0; /* Or else just joysticks. */ t_stat vid_register_quit_callback (VID_QUIT_CALLBACK callback) { @@ -88,12 +87,14 @@ t_stat vid_show (FILE* st, DEVICE *dptr, UNIT* uptr, int32 val, CONST char* des return vid_show_video (st, uptr, val, desc); } +#if defined(USE_SIM_VIDEO) && defined(HAVE_LIBSDL) + static const char *vid_dname (DEVICE *dev) { return dev ? sim_dname(dev) : "Video Device"; } -#if defined(USE_SIM_VIDEO) && defined(HAVE_LIBSDL) +static int vid_gamepad_ok = 0; /* Or else just joysticks. */ char vid_release_key[64] = "Ctrl-Right-Shift"; @@ -341,34 +342,61 @@ typedef struct { } MOUSE_EVENT_QUEUE; int vid_thread (void* arg); -int vid_video_events (void); +int vid_video_events (VID_DISPLAY *vptr); void vid_show_video_event (void); void vid_screenshot_event (void); void vid_beep_event (void); +static void vid_beep_setup (int duration_ms, int tone_frequency); +static void vid_beep_cleanup (void); +static void vid_controllers_setup (DEVICE *dptr); +static void vid_controllers_cleanup (void); +struct VID_DISPLAY { +t_bool vid_active_window; t_bool vid_mouse_captured; int32 vid_flags; /* Open Flags */ int32 vid_width; int32 vid_height; t_bool vid_ready; char vid_title[128]; -static void vid_beep_setup (int duration_ms, int tone_frequency); -static void vid_beep_cleanup (void); -static void vid_controllers_setup (void); -static void vid_controllers_cleanup (void); -t_bool vid_key_state[SDL_NUM_SCANCODES]; SDL_Texture *vid_texture; /* video buffer in GPU */ SDL_Renderer *vid_renderer; SDL_Window *vid_window; /* window handle */ SDL_PixelFormat *vid_format; uint32 vid_windowID; +SDL_mutex *vid_draw_mutex; /* window update mutex */ +SDL_Cursor *vid_cursor; /* current cursor */ +t_bool vid_cursor_visible; /* cursor visibility state */ +DEVICE *vid_dev; +t_bool vid_key_state[SDL_NUM_SCANCODES]; +VID_DISPLAY *next; +}; + SDL_Thread *vid_thread_handle = NULL; /* event thread handle */ -SDL_mutex *vid_draw_mutex = NULL; /* window update mutex */ -SDL_Cursor *vid_cursor = NULL; /* current cursor */ -t_bool vid_cursor_visible = FALSE; /* cursor visibility state */ + +static VID_DISPLAY vid_first; + KEY_EVENT_QUEUE vid_key_events; /* keyboard events */ MOUSE_EVENT_QUEUE vid_mouse_events; /* mouse events */ -DEVICE *vid_dev; + +static VID_DISPLAY *vid_window_from_id (Uint32 windowID) +{ +static Uint32 lastID = 0xffffffff; +static VID_DISPLAY *last_display = NULL; +VID_DISPLAY *vptr; + +if (windowID == lastID) + return last_display; + +for (vptr = &vid_first; vptr != NULL; vptr = vptr->next) { + if (windowID == vptr->vid_windowID) { + lastID = windowID; + return last_display = vptr; + } + } + +return NULL; +} #if defined (SDL_MAIN_AVAILABLE) #if defined (main) @@ -427,7 +455,7 @@ while (1) { if (event.user.code == EVENT_EXIT) break; if (event.user.code == EVENT_OPEN) - vid_video_events (); + vid_video_events ((VID_DISPLAY *)event.user.data1); else { if (event.user.code == EVENT_SHOW) vid_show_video_event (); @@ -456,39 +484,50 @@ SDL_Quit (); return status; } -static t_stat vid_create_window () +static t_stat vid_create_window (VID_DISPLAY *vptr) { int wait_count = 0; SDL_Event user_event; -vid_ready = FALSE; +vptr->vid_ready = FALSE; user_event.type = SDL_USEREVENT; user_event.user.code = EVENT_OPEN; -user_event.user.data1 = NULL; +user_event.user.data1 = vptr; user_event.user.data2 = NULL; SDL_PushEvent (&user_event); -while ((!vid_ready) && (++wait_count < 20)) +while ((!vptr->vid_ready) && (++wait_count < 20)) sim_os_ms_sleep (100); -if (!vid_ready) { +if (!vptr->vid_ready) { vid_close (); return SCPE_OPENERR; } return SCPE_OK; } #else -static int vid_create_window () +static int vid_create_window (VID_DISPLAY *vptr) { int wait_count = 0; -vid_thread_handle = SDL_CreateThread (vid_thread, "vid-thread", NULL); +if (vid_thread_handle == NULL) + vid_thread_handle = SDL_CreateThread (vid_thread, "vid-thread", vptr); +else { + SDL_Event user_event; + vptr->vid_ready = FALSE; + user_event.type = SDL_USEREVENT; + user_event.user.code = EVENT_OPEN; + user_event.user.data1 = vptr; + user_event.user.data2 = NULL; + SDL_PushEvent (&user_event); + } + if (vid_thread_handle == NULL) { vid_close (); return SCPE_OPENERR; } -while ((!vid_ready) && (++wait_count < 20)) +while ((!vptr->vid_ready) && (++wait_count < 20)) sim_os_ms_sleep (100); -if (!vid_ready) { +if (!vptr->vid_ready) { vid_close (); return SCPE_OPENERR; } @@ -496,7 +535,7 @@ return SCPE_OK; } #endif -static void vid_controllers_setup (void) +static void vid_controllers_setup (DEVICE *dev) { SDL_Joystick *y; SDL_version ver; @@ -521,7 +560,7 @@ if (SDL_JoystickEventState (SDL_ENABLE) < 0) { SDL_QuitSubSystem(SDL_INIT_GAMECONTROLLER); else SDL_QuitSubSystem(SDL_INIT_JOYSTICK); - sim_printf ("%s: vid_controllers_setup(): SDL_JoystickEventState error: %s\n", vid_dname(vid_dev), SDL_GetError()); + sim_printf ("%s: vid_controllers_setup(): SDL_JoystickEventState error: %s\n", vid_dname(dev), SDL_GetError()); return; } @@ -530,7 +569,7 @@ if (vid_gamepad_ok && SDL_GameControllerEventState (SDL_ENABLE) < 0) { SDL_QuitSubSystem(SDL_INIT_GAMECONTROLLER); else SDL_QuitSubSystem(SDL_INIT_JOYSTICK); - sim_printf ("%s: vid_controllers_setup(): SDL_GameControllerEventState error: %s\n", vid_dname(vid_dev), SDL_GetError()); + sim_printf ("%s: vid_controllers_setup(): SDL_GameControllerEventState error: %s\n", vid_dname(dev), SDL_GetError()); return; } @@ -540,16 +579,16 @@ for (i = 0; i < n; i++) { if (vid_gamepad_ok && SDL_IsGameController (i)) { SDL_GameController *x = SDL_GameControllerOpen (i); if (x != NULL) { - sim_debug (SIM_VID_DBG_VIDEO, vid_dev, + sim_debug (SIM_VID_DBG_VIDEO, dev, "Game controller: %s\n", SDL_GameControllerNameForIndex(i)); } } else { y = SDL_JoystickOpen (i); if (y != NULL) { - sim_debug (SIM_VID_DBG_VIDEO, vid_dev, + sim_debug (SIM_VID_DBG_VIDEO, dev, "Joystick: %s\n", SDL_JoystickNameForIndex(i)); - sim_debug (SIM_VID_DBG_VIDEO, vid_dev, + sim_debug (SIM_VID_DBG_VIDEO, dev, "Number of axes: %d, buttons: %d\n", SDL_JoystickNumAxes(y), SDL_JoystickNumButtons(y)); @@ -570,23 +609,22 @@ if (0 == (--vid_gamepad_inited)) { } } -t_stat vid_open (DEVICE *dptr, const char *title, uint32 width, uint32 height, int flags) +static t_stat vid_init_window (VID_DISPLAY *vptr, DEVICE *dptr, const char *title, uint32 width, uint32 height, int flags) { +t_stat stat; + +if ((strlen(sim_name) + 7 + (dptr ? strlen (dptr->name) : 0) + (title ? strlen (title) : 0)) < sizeof (vptr->vid_title)) + sprintf (vptr->vid_title, "%s%s%s%s%s", sim_name, dptr ? " - " : "", dptr ? dptr->name : "", title ? " - " : "", title ? title : ""); +else + sprintf (vptr->vid_title, "%s", sim_name); +vptr->vid_flags = flags; +vptr->vid_active_window = TRUE; +vptr->vid_width = width; +vptr->vid_height = height; +vptr->vid_mouse_captured = FALSE; +vptr->vid_cursor_visible = (vptr->vid_flags & SIM_VID_INPUTCAPTURED); + if (!vid_active) { - int wait_count = 0; - t_stat stat; - - if ((strlen(sim_name) + 7 + (dptr ? strlen (dptr->name) : 0) + (title ? strlen (title) : 0)) < sizeof (vid_title)) - sprintf (vid_title, "%s%s%s%s%s", sim_name, dptr ? " - " : "", dptr ? dptr->name : "", title ? " - " : "", title ? title : ""); - else - sprintf (vid_title, "%s", sim_name); - vid_flags = flags; - vid_active = TRUE; - vid_width = width; - vid_height = height; - vid_mouse_captured = FALSE; - vid_cursor_visible = (vid_flags & SIM_VID_INPUTCAPTURED); - vid_key_events.head = 0; vid_key_events.tail = 0; vid_key_events.count = 0; @@ -595,55 +633,96 @@ if (!vid_active) { vid_mouse_events.tail = 0; vid_mouse_events.count = 0; vid_mouse_events.sem = SDL_CreateSemaphore (1); +} - vid_dev = dptr; +vptr->vid_dev = dptr; - memset (motion_callback, 0, sizeof motion_callback); - memset (button_callback, 0, sizeof button_callback); +memset (motion_callback, 0, sizeof motion_callback); +memset (button_callback, 0, sizeof button_callback); - stat = vid_create_window (); - if (stat != SCPE_OK) - return stat; +stat = vid_create_window (vptr); +if (stat != SCPE_OK) + return stat; - sim_debug (SIM_VID_DBG_VIDEO|SIM_VID_DBG_KEY|SIM_VID_DBG_MOUSE, vid_dev, "vid_open() - Success\n"); +sim_debug (SIM_VID_DBG_VIDEO|SIM_VID_DBG_KEY|SIM_VID_DBG_MOUSE, vptr->vid_dev, "vid_open() - Success\n"); + +return SCPE_OK; +} + +t_stat vid_open_window (VID_DISPLAY **vptr, DEVICE *dptr, const char *title, uint32 width, uint32 height, int flags) +{ +t_stat r; +*vptr = (VID_DISPLAY *)malloc (sizeof (VID_DISPLAY)); +if (*vptr == NULL) + return SCPE_NXM; +(*vptr)->next = vid_first.next; +vid_first.next = *vptr; +r = vid_init_window (*vptr, dptr, title, width, height, flags); +if (r != SCPE_OK) { + vid_first.next = (*vptr)->next; + free (*vptr); + *vptr = NULL; + return r; + } +return SCPE_OK; +} + +t_stat vid_open (DEVICE *dptr, const char *title, uint32 width, uint32 height, int flags) +{ +if (!vid_first.vid_active_window) + return vid_init_window (&vid_first, dptr, title, width, height, flags); +return SCPE_OK; +} + +t_stat vid_close_window (VID_DISPLAY *vptr) +{ +SDL_Event user_event; +int status; + +if (vptr->vid_ready) { + sim_debug (SIM_VID_DBG_VIDEO|SIM_VID_DBG_KEY|SIM_VID_DBG_MOUSE, vptr->vid_dev, "vid_close()\n"); + user_event.type = SDL_USEREVENT; + user_event.user.windowID = vptr->vid_windowID; + user_event.user.code = EVENT_CLOSE; + user_event.user.data1 = NULL; + user_event.user.data2 = NULL; + + while (SDL_PushEvent (&user_event) < 0) + sim_os_ms_sleep (10); + vptr->vid_dev = NULL; + } +if (vid_thread_handle && vid_active <= 1) { + SDL_WaitThread (vid_thread_handle, &status); + vid_thread_handle = NULL; + } +while (vptr->vid_ready) + sim_os_ms_sleep (10); + +vptr->vid_active_window = FALSE; +if (!vid_active && vid_mouse_events.sem) { + SDL_DestroySemaphore(vid_mouse_events.sem); + vid_mouse_events.sem = NULL; + } +if (!vid_active && vid_key_events.sem) { + SDL_DestroySemaphore(vid_key_events.sem); + vid_key_events.sem = NULL; } return SCPE_OK; } t_stat vid_close (void) { -if (vid_active) { - SDL_Event user_event; - int status; +if (vid_first.vid_active_window) + return vid_close_window (&vid_first); +return SCPE_OK; +} - vid_active = FALSE; /* Signal rendering thread we'd like to exit */ - if (vid_ready) { - sim_debug (SIM_VID_DBG_VIDEO|SIM_VID_DBG_KEY|SIM_VID_DBG_MOUSE, vid_dev, "vid_close()\n"); - user_event.type = SDL_USEREVENT; - user_event.user.code = EVENT_CLOSE; - user_event.user.data1 = NULL; - user_event.user.data2 = NULL; - - while (SDL_PushEvent (&user_event) < 0) - sim_os_ms_sleep (10); - vid_dev = NULL; - } - if (vid_thread_handle) { - SDL_WaitThread (vid_thread_handle, &status); - vid_thread_handle = NULL; - } - while (vid_ready) - sim_os_ms_sleep (10); - - if (vid_mouse_events.sem) { - SDL_DestroySemaphore(vid_mouse_events.sem); - vid_mouse_events.sem = NULL; - } - if (vid_key_events.sem) { - SDL_DestroySemaphore(vid_key_events.sem); - vid_key_events.sem = NULL; - } - } +t_stat vid_close_all (void) +{ +VID_DISPLAY *vptr; +vid_close (); +for (vptr = vid_first.next; vptr != NULL; vptr = vptr->next) + vid_close_window (vptr); return SCPE_OK; } @@ -686,44 +765,49 @@ if (SDL_SemTryWait (vid_mouse_events.sem) == 0) { vid_mouse_events.head = 0; vid_mouse_events.count--; stat = SCPE_EOF; - sim_debug (SIM_VID_DBG_MOUSE, vid_dev, "vid_poll_mouse: ignoring bouncing events\n"); + sim_debug (SIM_VID_DBG_MOUSE, ev->dev, "vid_poll_mouse: ignoring bouncing events\n"); } } if (SDL_SemPost (vid_mouse_events.sem)) - sim_printf ("%s: vid_poll_mouse(): SDL_SemPost error: %s\n", vid_dname(vid_dev), SDL_GetError()); + sim_printf ("vid_poll_mouse(): SDL_SemPost error: %s\n", SDL_GetError()); } return stat; } +uint32 vid_map_rgb_window (VID_DISPLAY *vptr, uint8 r, uint8 g, uint8 b) +{ +return SDL_MapRGB (vptr->vid_format, r, g, b); +} + uint32 vid_map_rgb (uint8 r, uint8 g, uint8 b) { -return SDL_MapRGB (vid_format, r, g, b); +return vid_map_rgb_window (&vid_first, r, g, b); } static SDL_Rect *vid_dst_last; static uint32 *vid_data_last; -void vid_draw (int32 x, int32 y, int32 w, int32 h, uint32 *buf) +void vid_draw_window (VID_DISPLAY *vptr, int32 x, int32 y, int32 w, int32 h, uint32 *buf) { SDL_Event user_event; SDL_Rect *vid_dst; uint32 *vid_data; -sim_debug (SIM_VID_DBG_VIDEO, vid_dev, "vid_draw(%d, %d, %d, %d)\n", x, y, w, h); +sim_debug (SIM_VID_DBG_VIDEO, vptr->vid_dev, "vid_draw(%d, %d, %d, %d)\n", x, y, w, h); -SDL_LockMutex (vid_draw_mutex); /* Synchronize to check region dimensions */ +SDL_LockMutex (vptr->vid_draw_mutex); /* Synchronize to check region dimensions */ if (vid_dst_last && /* As yet unprocessed draw rectangle? */ (vid_dst_last->x == x) && (vid_dst_last->y == y) && /* AND identical position? */ (vid_dst_last->w == w) && (vid_dst_last->h == h)) { /* AND identical dimensions? */ memcpy (vid_data_last, buf, w*h*sizeof(*buf)); /* Replace region contents */ - SDL_UnlockMutex (vid_draw_mutex); /* Done */ + SDL_UnlockMutex (vptr->vid_draw_mutex); /* Done */ return; } -SDL_UnlockMutex (vid_draw_mutex); +SDL_UnlockMutex (vptr->vid_draw_mutex); vid_dst = (SDL_Rect *)malloc (sizeof(*vid_dst)); if (!vid_dst) { - sim_printf ("%s: vid_draw() memory allocation error\n", vid_dname(vid_dev)); + sim_printf ("%s: vid_draw() memory allocation error\n", vid_dname(vptr->vid_dev)); return; } vid_dst->x = x; @@ -732,71 +816,83 @@ vid_dst->w = w; vid_dst->h = h; vid_data = (uint32 *)malloc (w*h*sizeof(*buf)); if (!vid_data) { - sim_printf ("%s: vid_draw() memory allocation error\n", vid_dname(vid_dev)); + sim_printf ("%s: vid_draw() memory allocation error\n", vid_dname(vptr->vid_dev)); free (vid_dst); return; } memcpy (vid_data, buf, w*h*sizeof(*buf)); user_event.type = SDL_USEREVENT; +user_event.user.windowID = vptr->vid_windowID; user_event.user.code = EVENT_DRAW; user_event.user.data1 = (void *)vid_dst; user_event.user.data2 = (void *)vid_data; -SDL_LockMutex (vid_draw_mutex); /* protect vid_dst_last & vid_data_last */ +SDL_LockMutex (vptr->vid_draw_mutex); /* protect vid_dst_last & vid_data_last */ vid_dst_last = vid_dst; vid_data_last = vid_data; -SDL_UnlockMutex (vid_draw_mutex); /* done protection */ +SDL_UnlockMutex (vptr->vid_draw_mutex); /* done protection */ if (SDL_PushEvent (&user_event) < 0) { - sim_printf ("%s: vid_draw() SDL_PushEvent error: %s\n", vid_dname(vid_dev), SDL_GetError()); + sim_printf ("%s: vid_draw() SDL_PushEvent error: %s\n", vid_dname(vptr->vid_dev), SDL_GetError()); free (vid_dst); free (vid_data); } } -t_stat vid_set_cursor (t_bool visible, uint32 width, uint32 height, uint8 *data, uint8 *mask, uint32 hot_x, uint32 hot_y) +void vid_draw (int32 x, int32 y, int32 w, int32 h, uint32 *buf) +{ +vid_draw_window (&vid_first, x, y, w, h, buf); +} + +t_stat vid_set_cursor_window (VID_DISPLAY *vptr, t_bool visible, uint32 width, uint32 height, uint8 *data, uint8 *mask, uint32 hot_x, uint32 hot_y) { SDL_Cursor *cursor = SDL_CreateCursor (data, mask, width, height, hot_x, hot_y); SDL_Event user_event; -sim_debug (SIM_VID_DBG_CURSOR, vid_dev, "vid_set_cursor(%s, %d, %d) Setting New Cursor\n", visible ? "visible" : "invisible", width, height); +sim_debug (SIM_VID_DBG_CURSOR, vptr->vid_dev, "vid_set_cursor(%s, %d, %d) Setting New Cursor\n", visible ? "visible" : "invisible", width, height); if (sim_deb) { uint32 i, j; for (i=0; ivid_dev, "Cursor: "); for (j=0; j> 3; int bit = 7 - ((j + i*width) & 0x7); static char mode[] = "TWIB"; - sim_debug (SIM_VID_DBG_CURSOR, vid_dev, "%c", mode[(((data[byte]>>bit)&1)<<1)|(mask[byte]>>bit)&1]); + sim_debug (SIM_VID_DBG_CURSOR, vptr->vid_dev, "%c", mode[(((data[byte]>>bit)&1)<<1)|(mask[byte]>>bit)&1]); } - sim_debug (SIM_VID_DBG_CURSOR, vid_dev, "\n"); + sim_debug (SIM_VID_DBG_CURSOR, vptr->vid_dev, "\n"); } } user_event.type = SDL_USEREVENT; +user_event.user.windowID = vptr->vid_windowID; user_event.user.code = EVENT_CURSOR; user_event.user.data1 = cursor; user_event.user.data2 = (void *)((size_t)visible); if (SDL_PushEvent (&user_event) < 0) { - sim_printf ("%s: vid_set_cursor() SDL_PushEvent error: %s\n", vid_dname(vid_dev), SDL_GetError()); + sim_printf ("%s: vid_set_cursor() SDL_PushEvent error: %s\n", vid_dname(vptr->vid_dev), SDL_GetError()); SDL_FreeCursor (cursor); } return SCPE_OK; } -void vid_set_cursor_position (int32 x, int32 y) +t_stat vid_set_cursor (t_bool visible, uint32 width, uint32 height, uint8 *data, uint8 *mask, uint32 hot_x, uint32 hot_y) +{ +return vid_set_cursor_window (&vid_first, visible, width, height, data, mask, hot_x, hot_y); +} + +void vid_set_cursor_position_window (VID_DISPLAY *vptr, int32 x, int32 y) { int32 x_delta = vid_cursor_x - x; int32 y_delta = vid_cursor_y - y; -if (vid_flags & SIM_VID_INPUTCAPTURED) +if (vptr->vid_flags & SIM_VID_INPUTCAPTURED) return; if ((x_delta) || (y_delta)) { - sim_debug (SIM_VID_DBG_CURSOR, vid_dev, "vid_set_cursor_position(%d, %d) - Cursor position changed\n", x, y); + sim_debug (SIM_VID_DBG_CURSOR, vptr->vid_dev, "vid_set_cursor_position(%d, %d) - Cursor position changed\n", x, y); /* Any queued mouse motion events need to have their relative positions adjusted since they were queued based on different info. */ if (SDL_SemWait (vid_mouse_events.sem) == 0) { @@ -805,49 +901,61 @@ if ((x_delta) || (y_delta)) { for (i=0; ix_rel, ev->y_rel, ev->x_rel + x_delta, ev->y_rel + y_delta); + sim_debug (SIM_VID_DBG_CURSOR, vptr->vid_dev, "Pending Mouse Motion Event Adjusted from: (%d, %d) to (%d, %d)\n", ev->x_rel, ev->y_rel, ev->x_rel + x_delta, ev->y_rel + y_delta); ev->x_rel += x_delta; ev->y_rel += y_delta; } if (SDL_SemPost (vid_mouse_events.sem)) - sim_printf ("%s: vid_set_cursor_position(): SDL_SemPost error: %s\n", vid_dname(vid_dev), SDL_GetError()); + sim_printf ("%s: vid_set_cursor_position(): SDL_SemPost error: %s\n", vid_dname(vptr->vid_dev), SDL_GetError()); } else { - sim_printf ("%s: vid_set_cursor_position(): SDL_SemWait error: %s\n", vid_dname(vid_dev), SDL_GetError()); + sim_printf ("%s: vid_set_cursor_position(): SDL_SemWait error: %s\n", vid_dname(vptr->vid_dev), SDL_GetError()); } vid_cursor_x = x; vid_cursor_y = y; - if (vid_cursor_visible) { + if (vptr->vid_cursor_visible) { SDL_Event user_event; user_event.type = SDL_USEREVENT; + user_event.user.windowID = vptr->vid_windowID; user_event.user.code = EVENT_WARP; user_event.user.data1 = NULL; user_event.user.data2 = NULL; if (SDL_PushEvent (&user_event) < 0) - sim_printf ("%s: vid_set_cursor_position() SDL_PushEvent error: %s\n", vid_dname(vid_dev), SDL_GetError()); - sim_debug (SIM_VID_DBG_CURSOR, vid_dev, "vid_set_cursor_position() - Warp Queued\n"); + sim_printf ("%s: vid_set_cursor_position() SDL_PushEvent error: %s\n", vid_dname(vptr->vid_dev), SDL_GetError()); + sim_debug (SIM_VID_DBG_CURSOR, vptr->vid_dev, "vid_set_cursor_position() - Warp Queued\n"); } else { - sim_debug (SIM_VID_DBG_CURSOR, vid_dev, "vid_set_cursor_position() - Warp Skipped\n"); + sim_debug (SIM_VID_DBG_CURSOR, vptr->vid_dev, "vid_set_cursor_position() - Warp Skipped\n"); } } } -void vid_refresh (void) +void vid_set_cursor_position (int32 x, int32 y) +{ +vid_set_cursor_position_window (&vid_first, x, y); +} + +void vid_refresh_window (VID_DISPLAY *vptr) { SDL_Event user_event; -sim_debug (SIM_VID_DBG_VIDEO, vid_dev, "vid_refresh() - Queueing Refresh Event\n"); +sim_debug (SIM_VID_DBG_VIDEO, vptr->vid_dev, "vid_refresh() - Queueing Refresh Event\n"); user_event.type = SDL_USEREVENT; +user_event.user.windowID = vptr->vid_windowID; user_event.user.code = EVENT_REDRAW; user_event.user.data1 = NULL; user_event.user.data2 = NULL; if (SDL_PushEvent (&user_event) < 0) - sim_printf ("%s: vid_refresh() SDL_PushEvent error: %s\n", vid_dname(vid_dev), SDL_GetError()); + sim_printf ("%s: vid_refresh() SDL_PushEvent error: %s\n", vid_dname(vptr->vid_dev), SDL_GetError()); +} + +void vid_refresh (void) +{ +vid_refresh_window (&vid_first); } int vid_map_key (int key) @@ -1228,21 +1336,22 @@ void vid_controller_button (SDL_ControllerButtonEvent *event) void vid_key (SDL_KeyboardEvent *event) { SIM_KEY_EVENT ev; +VID_DISPLAY *vptr = vid_window_from_id (event->windowID); -if (vid_mouse_captured) { +if (vptr->vid_mouse_captured) { static const Uint8 *KeyStates = NULL; static int numkeys; if (!KeyStates) KeyStates = SDL_GetKeyboardState(&numkeys); - if ((vid_flags & SIM_VID_INPUTCAPTURED) && + if ((vptr->vid_flags & SIM_VID_INPUTCAPTURED) && (event->state == SDL_PRESSED) && KeyStates[SDL_SCANCODE_RSHIFT] && (KeyStates[SDL_SCANCODE_LCTRL] || KeyStates[SDL_SCANCODE_RCTRL])) { - sim_debug (SIM_VID_DBG_KEY, vid_dev, "vid_key() - Cursor Release\n"); + sim_debug (SIM_VID_DBG_KEY, vptr->vid_dev, "vid_key() - Cursor Release\n"); if (SDL_SetRelativeMouseMode(SDL_FALSE) < 0) /* release cursor, show cursor */ - sim_printf ("%s: vid_key(): SDL_SetRelativeMouseMode error: %s\n", vid_dname(vid_dev), SDL_GetError()); - vid_mouse_captured = FALSE; + sim_printf ("%s: vid_key(): SDL_SetRelativeMouseMode error: %s\n", vid_dname(vptr->vid_dev), SDL_GetError()); + vptr->vid_mouse_captured = FALSE; return; } } @@ -1251,17 +1360,19 @@ if (!sim_is_running) if (SDL_SemWait (vid_key_events.sem) == 0) { if (vid_key_events.count < MAX_EVENTS) { ev.key = vid_map_key (event->keysym.sym); - sim_debug (SIM_VID_DBG_KEY, vid_dev, "Keyboard Event: State: %s, Keysym(scancode,sym): (%d,%d) - %s\n", (event->state == SDL_PRESSED) ? "PRESSED" : "RELEASED", event->keysym.scancode, event->keysym.sym, vid_key_name(ev.key)); + ev.dev = vptr->vid_dev; + ev.vptr = vptr; + sim_debug (SIM_VID_DBG_KEY, vptr->vid_dev, "Keyboard Event: State: %s, Keysym(scancode,sym): (%d,%d) - %s\n", (event->state == SDL_PRESSED) ? "PRESSED" : "RELEASED", event->keysym.scancode, event->keysym.sym, vid_key_name(ev.key)); if (event->state == SDL_PRESSED) { - if (!vid_key_state[event->keysym.scancode]) {/* Key was not down before */ - vid_key_state[event->keysym.scancode] = TRUE; + if (!vptr->vid_key_state[event->keysym.scancode]) {/* Key was not down before */ + vptr->vid_key_state[event->keysym.scancode] = TRUE; ev.state = SIM_KEYPRESS_DOWN; } else ev.state = SIM_KEYPRESS_REPEAT; } else { - vid_key_state[event->keysym.scancode] = FALSE; + vptr->vid_key_state[event->keysym.scancode] = FALSE; ev.state = SIM_KEYPRESS_UP; } vid_key_events.events[vid_key_events.tail++] = ev; @@ -1270,10 +1381,10 @@ if (SDL_SemWait (vid_key_events.sem) == 0) { vid_key_events.tail = 0; } else { - sim_debug (SIM_VID_DBG_KEY, vid_dev, "Keyboard Event DISCARDED: State: %s, Keysym: Scancode: %d, Keysym: %d\n", (event->state == SDL_PRESSED) ? "PRESSED" : "RELEASED", event->keysym.scancode, event->keysym.sym); + sim_debug (SIM_VID_DBG_KEY, vptr->vid_dev, "Keyboard Event DISCARDED: State: %s, Keysym: Scancode: %d, Keysym: %d\n", (event->state == SDL_PRESSED) ? "PRESSED" : "RELEASED", event->keysym.scancode, event->keysym.sym); } if (SDL_SemPost (vid_key_events.sem)) - sim_printf ("%s: vid_key(): SDL_SemPost error: %s\n", vid_dname(vid_dev), SDL_GetError()); + sim_printf ("%s: vid_key(): SDL_SemPost error: %s\n", vid_dname(vptr->vid_dev), SDL_GetError()); } } @@ -1282,15 +1393,16 @@ void vid_mouse_move (SDL_MouseMotionEvent *event) SDL_Event dummy_event; SDL_MouseMotionEvent *dev = (SDL_MouseMotionEvent *)&dummy_event; SIM_MOUSE_EVENT ev; +VID_DISPLAY *vptr = vid_window_from_id (event->windowID); -if ((!vid_mouse_captured) && (vid_flags & SIM_VID_INPUTCAPTURED)) +if ((!vptr->vid_mouse_captured) && (vptr->vid_flags & SIM_VID_INPUTCAPTURED)) return; if (!sim_is_running) return; -if (!vid_cursor_visible) +if (!vptr->vid_cursor_visible) return; -sim_debug (SIM_VID_DBG_MOUSE, vid_dev, "Mouse Move Event: pos:(%d,%d) rel:(%d,%d) buttons:(%d,%d,%d)\n", +sim_debug (SIM_VID_DBG_MOUSE, vptr->vid_dev, "Mouse Move Event: pos:(%d,%d) rel:(%d,%d) buttons:(%d,%d,%d)\n", event->x, event->y, event->xrel, event->yrel, (event->state & SDL_BUTTON(SDL_BUTTON_LEFT)) ? 1 : 0, (event->state & SDL_BUTTON(SDL_BUTTON_MIDDLE)) ? 1 : 0, (event->state & SDL_BUTTON(SDL_BUTTON_RIGHT)) ? 1 : 0); while (SDL_PeepEvents (&dummy_event, 1, SDL_GETEVENT, SDL_MOUSEMOTION, SDL_MOUSEMOTION)) { /* Coalesce motion activity to avoid thrashing */ @@ -1299,22 +1411,23 @@ while (SDL_PeepEvents (&dummy_event, 1, SDL_GETEVENT, SDL_MOUSEMOTION, SDL_MOUSE event->x = dev->x; event->y = dev->y; event->state = dev->state; - sim_debug (SIM_VID_DBG_MOUSE, vid_dev, "Mouse Move Event: Additional Event Coalesced:pos:(%d,%d) rel:(%d,%d) buttons:(%d,%d,%d)\n", + sim_debug (SIM_VID_DBG_MOUSE, vptr->vid_dev, "Mouse Move Event: Additional Event Coalesced:pos:(%d,%d) rel:(%d,%d) buttons:(%d,%d,%d)\n", dev->x, dev->y, dev->xrel, dev->yrel, (dev->state & SDL_BUTTON(SDL_BUTTON_LEFT)) ? 1 : 0, (dev->state & SDL_BUTTON(SDL_BUTTON_MIDDLE)) ? 1 : 0, (dev->state & SDL_BUTTON(SDL_BUTTON_RIGHT)) ? 1 : 0); }; if (SDL_SemWait (vid_mouse_events.sem) == 0) { - if (!vid_mouse_captured) { + if (!vptr->vid_mouse_captured) { event->xrel = (event->x - vid_cursor_x); event->yrel = (event->y - vid_cursor_y); } vid_mouse_b1 = (event->state & SDL_BUTTON(SDL_BUTTON_LEFT)) ? TRUE : FALSE; vid_mouse_b2 = (event->state & SDL_BUTTON(SDL_BUTTON_MIDDLE)) ? TRUE : FALSE; vid_mouse_b3 = (event->state & SDL_BUTTON(SDL_BUTTON_RIGHT)) ? TRUE : FALSE; - sim_debug (SIM_VID_DBG_MOUSE, vid_dev, "Mouse Move Event: pos:(%d,%d) rel:(%d,%d) buttons:(%d,%d,%d) - Count: %d vid_cursor:(%d,%d)\n", + sim_debug (SIM_VID_DBG_MOUSE, vptr->vid_dev, "Mouse Move Event: pos:(%d,%d) rel:(%d,%d) buttons:(%d,%d,%d) - Count: %d vid_cursor:(%d,%d)\n", event->x, event->y, event->xrel, event->yrel, (event->state & SDL_BUTTON(SDL_BUTTON_LEFT)) ? 1 : 0, (event->state & SDL_BUTTON(SDL_BUTTON_MIDDLE)) ? 1 : 0, (event->state & SDL_BUTTON(SDL_BUTTON_RIGHT)) ? 1 : 0, vid_mouse_events.count, vid_cursor_x, vid_cursor_y); if (vid_mouse_events.count < MAX_EVENTS) { SIM_MOUSE_EVENT *tail = &vid_mouse_events.events[(vid_mouse_events.tail+MAX_EVENTS-1)%MAX_EVENTS]; + ev.dev = vptr->vid_dev; ev.x_rel = event->xrel; ev.y_rel = event->yrel; ev.b1_state = vid_mouse_b1; @@ -1330,7 +1443,7 @@ if (SDL_SemWait (vid_mouse_events.sem) == 0) { tail->y_rel += ev.y_rel; tail->x_pos = ev.x_pos; tail->y_pos = ev.y_pos; - sim_debug (SIM_VID_DBG_MOUSE, vid_dev, "Mouse Move Event: Coalesced into pending event: (%d,%d)\n", + sim_debug (SIM_VID_DBG_MOUSE, vptr->vid_dev, "Mouse Move Event: Coalesced into pending event: (%d,%d)\n", tail->x_rel, tail->y_rel); } else { /* Add a new event */ @@ -1341,10 +1454,10 @@ if (SDL_SemWait (vid_mouse_events.sem) == 0) { } } else { - sim_debug (SIM_VID_DBG_MOUSE, vid_dev, "Mouse Move Event Discarded: Count: %d\n", vid_mouse_events.count); + sim_debug (SIM_VID_DBG_MOUSE, vptr->vid_dev, "Mouse Move Event Discarded: Count: %d\n", vid_mouse_events.count); } if (SDL_SemPost (vid_mouse_events.sem)) - sim_printf ("%s: vid_mouse_move(): SDL_SemPost error: %s\n", vid_dname(vid_dev), SDL_GetError()); + sim_printf ("%s: vid_mouse_move(): SDL_SemPost error: %s\n", vid_dname(vptr->vid_dev), SDL_GetError()); } } @@ -1353,17 +1466,18 @@ void vid_mouse_button (SDL_MouseButtonEvent *event) SDL_Event dummy_event; SIM_MOUSE_EVENT ev; t_bool state; +VID_DISPLAY *vptr = vid_window_from_id (event->windowID); -if ((!vid_mouse_captured) && (vid_flags & SIM_VID_INPUTCAPTURED)) { +if ((!vptr->vid_mouse_captured) && (vptr->vid_flags & SIM_VID_INPUTCAPTURED)) { if ((event->state == SDL_PRESSED) && (event->button == SDL_BUTTON_LEFT)) { /* left click and cursor not captured? */ - sim_debug (SIM_VID_DBG_KEY, vid_dev, "vid_mouse_button() - Cursor Captured\n"); + sim_debug (SIM_VID_DBG_KEY, vptr->vid_dev, "vid_mouse_button() - Cursor Captured\n"); if (SDL_SetRelativeMouseMode (SDL_TRUE) < 0) /* lock cursor to window, hide cursor */ - sim_printf ("%s: vid_mouse_button(): SDL_SetRelativeMouseMode error: %s\n", vid_dname(vid_dev), SDL_GetError()); - SDL_WarpMouseInWindow (NULL, vid_width/2, vid_height/2);/* back to center */ + sim_printf ("%s: vid_mouse_button(): SDL_SetRelativeMouseMode error: %s\n", vid_dname(vptr->vid_dev), SDL_GetError()); + SDL_WarpMouseInWindow (NULL, vptr->vid_width/2, vptr->vid_height/2);/* back to center */ SDL_PumpEvents (); while (SDL_PeepEvents (&dummy_event, 1, SDL_GETEVENT, SDL_MOUSEMOTION, SDL_MOUSEMOTION)) {}; - vid_mouse_captured = TRUE; + vptr->vid_mouse_captured = TRUE; } return; } @@ -1382,8 +1496,9 @@ if (SDL_SemWait (vid_mouse_events.sem) == 0) { vid_mouse_b3 = state; break; } - sim_debug (SIM_VID_DBG_MOUSE, vid_dev, "Mouse Button Event: State: %d, Button: %d, (%d,%d)\n", event->state, event->button, event->x, event->y); + sim_debug (SIM_VID_DBG_MOUSE, vptr->vid_dev, "Mouse Button Event: State: %d, Button: %d, (%d,%d)\n", event->state, event->button, event->x, event->y); if (vid_mouse_events.count < MAX_EVENTS) { + ev.dev = vptr->vid_dev; ev.x_rel = 0; ev.y_rel = 0; ev.x_pos = event->x; @@ -1397,111 +1512,204 @@ if (SDL_SemWait (vid_mouse_events.sem) == 0) { vid_mouse_events.tail = 0; } else { - sim_debug (SIM_VID_DBG_MOUSE, vid_dev, "Mouse Button Event Discarded: Count: %d\n", vid_mouse_events.count); + sim_debug (SIM_VID_DBG_MOUSE, vptr->vid_dev, "Mouse Button Event Discarded: Count: %d\n", vid_mouse_events.count); } if (SDL_SemPost (vid_mouse_events.sem)) - sim_printf ("%s: Mouse Button Event: SDL_SemPost error: %s\n", vid_dname(vid_dev), SDL_GetError()); + sim_printf ("%s: Mouse Button Event: SDL_SemPost error: %s\n", vid_dname(vptr->vid_dev), SDL_GetError()); } } +t_bool vid_is_fullscreen_window (VID_DISPLAY *vptr) +{ +return SDL_GetWindowFlags (vptr->vid_window) & SDL_WINDOW_FULLSCREEN_DESKTOP; +} + t_bool vid_is_fullscreen (void) { - return SDL_GetWindowFlags (vid_window) & SDL_WINDOW_FULLSCREEN_DESKTOP; +return vid_is_fullscreen_window (&vid_first); +} + +t_stat vid_set_fullscreen_window (VID_DISPLAY *vptr, t_bool flag) +{ +if (flag) + SDL_SetWindowFullscreen (vptr->vid_window, SDL_WINDOW_FULLSCREEN_DESKTOP); +else + SDL_SetWindowFullscreen (vptr->vid_window, 0); +return SCPE_OK; } t_stat vid_set_fullscreen (t_bool flag) { -if (flag) - SDL_SetWindowFullscreen (vid_window, SDL_WINDOW_FULLSCREEN_DESKTOP); -else - SDL_SetWindowFullscreen (vid_window, 0); -return SCPE_OK; +return vid_set_fullscreen_window (&vid_first, flag); } -static void vid_stretch(SDL_Rect *r) +static void vid_stretch(VID_DISPLAY *vptr, SDL_Rect *r) { /* Return in r a rectangle with the same aspect ratio as the video buffer but scaled to fit precisely in the output window. Normally, the buffer and the window have the same sizes, but if the window is resized, or fullscreen is in effect, they are not. */ int w, h; -SDL_GetRendererOutputSize(vid_renderer, &w, &h); -if ((double)h / vid_height < (double)w / vid_width) { - r->w = vid_width * h / vid_height; +SDL_GetRendererOutputSize(vptr->vid_renderer, &w, &h); +if ((double)h / vptr->vid_height < (double)w / vptr->vid_width) { + r->w = vptr->vid_width * h / vptr->vid_height; r->h = h; r->x = (w - r->w) / 2; r->y = 0; } else { r->w = w; - r->h = vid_height * w / vid_width; + r->h = vptr->vid_height * w / vptr->vid_width; r->x = 0; r->y = (h - r->h) / 2; } } -void vid_update (void) +void vid_update (VID_DISPLAY *vptr) { SDL_Rect vid_dst; -vid_stretch(&vid_dst); -sim_debug (SIM_VID_DBG_VIDEO, vid_dev, "Video Update Event: \n"); +vid_stretch(vptr, &vid_dst); +sim_debug (SIM_VID_DBG_VIDEO, vptr->vid_dev, "Video Update Event: \n"); if (sim_deb) fflush (sim_deb); -if (SDL_RenderClear (vid_renderer)) - sim_printf ("%s: Video Update Event: SDL_RenderClear error: %s\n", vid_dname(vid_dev), SDL_GetError()); -if (SDL_RenderCopy (vid_renderer, vid_texture, NULL, &vid_dst)) - sim_printf ("%s: Video Update Event: SDL_RenderCopy error: %s\n", vid_dname(vid_dev), SDL_GetError()); -SDL_RenderPresent (vid_renderer); +if (SDL_RenderClear (vptr->vid_renderer)) + sim_printf ("%s: Video Update Event: SDL_RenderClear error: %s\n", vid_dname(vptr->vid_dev), SDL_GetError()); +if (SDL_RenderCopy (vptr->vid_renderer, vptr->vid_texture, NULL, &vid_dst)) + sim_printf ("%s: Video Update Event: SDL_RenderCopy error: %s\n", vid_dname(vptr->vid_dev), SDL_GetError()); +SDL_RenderPresent (vptr->vid_renderer); } -void vid_update_cursor (SDL_Cursor *cursor, t_bool visible) +void vid_update_cursor (VID_DISPLAY *vptr, SDL_Cursor *cursor, t_bool visible) { if (!cursor) return; -sim_debug (SIM_VID_DBG_VIDEO, vid_dev, "Cursor Update Event: Previously %s, Now %s, New Cursor object at: %p, Old Cursor object at: %p\n", - SDL_ShowCursor(-1) ? "visible" : "invisible", visible ? "visible" : "invisible", cursor, vid_cursor); +sim_debug (SIM_VID_DBG_VIDEO, vptr->vid_dev, "Cursor Update Event: Previously %s, Now %s, New Cursor object at: %p, Old Cursor object at: %p\n", + SDL_ShowCursor(-1) ? "visible" : "invisible", visible ? "visible" : "invisible", cursor, vptr->vid_cursor); SDL_SetCursor (cursor); -if ((vid_window == SDL_GetMouseFocus ()) && visible) +if ((vptr->vid_window == SDL_GetMouseFocus ()) && visible) SDL_WarpMouseInWindow (NULL, vid_cursor_x, vid_cursor_y);/* sync position */ -if ((vid_cursor != cursor) && (vid_cursor)) - SDL_FreeCursor (vid_cursor); -vid_cursor = cursor; +if ((vptr->vid_cursor != cursor) && (vptr->vid_cursor)) + SDL_FreeCursor (vptr->vid_cursor); +vptr->vid_cursor = cursor; SDL_ShowCursor (visible); -vid_cursor_visible = visible; +vptr->vid_cursor_visible = visible; } -void vid_warp_position (void) +void vid_warp_position (VID_DISPLAY *vptr) { -sim_debug (SIM_VID_DBG_VIDEO, vid_dev, "Mouse Warp Event: Warp to: (%d,%d)\n", vid_cursor_x, vid_cursor_y); +sim_debug (SIM_VID_DBG_VIDEO, vptr->vid_dev, "Mouse Warp Event: Warp to: (%d,%d)\n", vid_cursor_x, vid_cursor_y); SDL_PumpEvents (); SDL_WarpMouseInWindow (NULL, vid_cursor_x, vid_cursor_y); SDL_PumpEvents (); } -void vid_draw_region (SDL_UserEvent *event) +void vid_draw_region (VID_DISPLAY *vptr, SDL_UserEvent *event) { SDL_Rect *vid_dst = (SDL_Rect *)event->data1; uint32 *buf = (uint32 *)event->data2; -sim_debug (SIM_VID_DBG_VIDEO, vid_dev, "Draw Region Event: (%d,%d,%d,%d)\n", vid_dst->x, vid_dst->x, vid_dst->w, vid_dst->h); +sim_debug (SIM_VID_DBG_VIDEO, vptr->vid_dev, "Draw Region Event: (%d,%d,%d,%d)\n", vid_dst->x, vid_dst->x, vid_dst->w, vid_dst->h); -SDL_LockMutex (vid_draw_mutex); +SDL_LockMutex (vptr->vid_draw_mutex); if (vid_dst == vid_dst_last) { vid_dst_last = NULL; vid_data_last = NULL; } -SDL_UnlockMutex (vid_draw_mutex); +SDL_UnlockMutex (vptr->vid_draw_mutex); -if (SDL_UpdateTexture(vid_texture, vid_dst, buf, vid_dst->w*sizeof(*buf))) - sim_printf ("%s: vid_draw_region() - SDL_UpdateTexture error: %s\n", vid_dname(vid_dev), SDL_GetError()); +if (SDL_UpdateTexture(vptr->vid_texture, vid_dst, buf, vid_dst->w*sizeof(*buf))) + sim_printf ("%s: vid_draw_region() - SDL_UpdateTexture error: %s\n", vid_dname(vptr->vid_dev), SDL_GetError()); free (vid_dst); free (buf); event->data1 = NULL; } -int vid_video_events (void) +static int vid_new_window (VID_DISPLAY *vptr) +{ +SDL_CreateWindowAndRenderer (vptr->vid_width, vptr->vid_height, SDL_WINDOW_SHOWN, &vptr->vid_window, &vptr->vid_renderer); + +if ((vptr->vid_window == NULL) || (vptr->vid_renderer == NULL)) { + sim_printf ("%s: Error Creating Video Window: %s\n", vid_dname(vptr->vid_dev), SDL_GetError()); + SDL_Quit (); + return 0; + } + +vptr->vid_draw_mutex = SDL_CreateMutex(); + +if (vptr->vid_draw_mutex == NULL) { + fprintf (stderr, "%s: SDL_CreateMutex failed: %s\n", vid_dname(vptr->vid_dev), SDL_GetError ()); + SDL_Quit (); + return 0; + } + +SDL_SetRenderDrawColor (vptr->vid_renderer, 0, 0, 0, 255); +SDL_RenderClear (vptr->vid_renderer); +SDL_RenderPresent (vptr->vid_renderer); + +vptr->vid_texture = SDL_CreateTexture (vptr->vid_renderer, + SDL_PIXELFORMAT_ARGB8888, + SDL_TEXTUREACCESS_STREAMING, + vptr->vid_width, vptr->vid_height); +if (!vptr->vid_texture) { + sim_printf ("%s: Error configuring Video environment: %s\n", vid_dname(vptr->vid_dev), SDL_GetError()); + SDL_DestroyRenderer(vptr->vid_renderer); + vptr->vid_renderer = NULL; + SDL_DestroyWindow(vptr->vid_window); + vptr->vid_window = NULL; + SDL_Quit (); + return 0; + } + +vptr->vid_format = SDL_AllocFormat (SDL_PIXELFORMAT_ARGB8888); + +SDL_StopTextInput (); + +vptr->vid_windowID = SDL_GetWindowID (vptr->vid_window); + +if (vptr->vid_flags & SIM_VID_INPUTCAPTURED) { + char title[150]; + + memset (title, 0, sizeof(title)); + strlcpy (title, vptr->vid_title, sizeof(title)); + strlcat (title, " ReleaseKey=", sizeof(title)); + strlcat (title, vid_release_key, sizeof(title)); + SDL_SetWindowTitle (vptr->vid_window, title); + } +else + SDL_SetWindowTitle (vptr->vid_window, vptr->vid_title); + +memset (&vptr->vid_key_state, 0, sizeof(vptr->vid_key_state)); + +vid_active++; +return 1; +} + +static void vid_destroy (VID_DISPLAY *vptr) +{ +VID_DISPLAY *parent; +vptr->vid_ready = FALSE; +if (vptr->vid_cursor) { + SDL_FreeCursor (vptr->vid_cursor); + vptr->vid_cursor = NULL; + } +SDL_DestroyTexture(vptr->vid_texture); +vptr->vid_texture = NULL; +SDL_DestroyRenderer(vptr->vid_renderer); +vptr->vid_renderer = NULL; +SDL_DestroyWindow(vptr->vid_window); +vptr->vid_window = NULL; +SDL_DestroyMutex (vptr->vid_draw_mutex); +vptr->vid_draw_mutex = NULL; +for (parent = &vid_first; parent != NULL; parent = parent->next) { + if (parent->next == vptr) + parent->next = vptr->next; + } +vid_active--; +} + +int vid_video_events (VID_DISPLAY *vptr0) { SDL_Event event; static const char *eventtypes[SDL_LASTEVENT]; @@ -1624,74 +1832,24 @@ if (!initialized) { eventtypes[SDL_USEREVENT] = "USEREVENT"; } -sim_debug (SIM_VID_DBG_VIDEO|SIM_VID_DBG_KEY|SIM_VID_DBG_MOUSE, vid_dev, "vid_thread() - Starting\n"); +sim_debug (SIM_VID_DBG_VIDEO|SIM_VID_DBG_KEY|SIM_VID_DBG_MOUSE, vptr0->vid_dev, "vid_thread() - Starting\n"); sim_os_set_thread_priority (PRIORITY_ABOVE_NORMAL); -memset (&vid_key_state, 0, sizeof(vid_key_state)); - -SDL_CreateWindowAndRenderer (vid_width, vid_height, SDL_WINDOW_SHOWN, &vid_window, &vid_renderer); - -if ((vid_window == NULL) || (vid_renderer == NULL)) { - sim_printf ("%s: Error Creating Video Window: %s\n", vid_dname(vid_dev), SDL_GetError()); - SDL_Quit (); +if (!vid_new_window (vptr0)) { return 0; } -vid_draw_mutex = SDL_CreateMutex(); - -if (vid_draw_mutex == NULL) { - fprintf (stderr, "%s: SDL_CreateMutex failed: %s\n", vid_dname(vid_dev), SDL_GetError ()); - SDL_Quit (); - return 0; - } - -SDL_SetRenderDrawColor (vid_renderer, 0, 0, 0, 255); -SDL_RenderClear (vid_renderer); -SDL_RenderPresent (vid_renderer); - -vid_texture = SDL_CreateTexture (vid_renderer, - SDL_PIXELFORMAT_ARGB8888, - SDL_TEXTUREACCESS_STREAMING, - vid_width, vid_height); -if (!vid_texture) { - sim_printf ("%s: Error configuring Video environment: %s\n", vid_dname(vid_dev), SDL_GetError()); - SDL_DestroyRenderer(vid_renderer); - vid_renderer = NULL; - SDL_DestroyWindow(vid_window); - vid_window = NULL; - SDL_Quit (); - return 0; - } - -vid_format = SDL_AllocFormat (SDL_PIXELFORMAT_ARGB8888); - -SDL_StopTextInput (); - -vid_windowID = SDL_GetWindowID (vid_window); - -if (vid_flags & SIM_VID_INPUTCAPTURED) { - char title[150]; - - memset (title, 0, sizeof(title)); - strlcpy (title, vid_title, sizeof(title)); - strlcat (title, " ReleaseKey=", sizeof(title)); - strlcat (title, vid_release_key, sizeof(title)); - SDL_SetWindowTitle (vid_window, title); - } -else - SDL_SetWindowTitle (vid_window, vid_title); - vid_beep_setup (400, 660); -vid_controllers_setup (); +vid_controllers_setup (vptr0->vid_dev); -vid_ready = TRUE; - -sim_debug (SIM_VID_DBG_VIDEO|SIM_VID_DBG_KEY|SIM_VID_DBG_MOUSE|SIM_VID_DBG_CURSOR, vid_dev, "vid_thread() - Started\n"); +vptr0->vid_ready = TRUE; +sim_debug (SIM_VID_DBG_VIDEO|SIM_VID_DBG_KEY|SIM_VID_DBG_MOUSE|SIM_VID_DBG_CURSOR, vptr0->vid_dev, "vid_thread() - Started\n"); while (vid_active) { int status = SDL_WaitEvent (&event); if (status == 1) { + VID_DISPLAY *vptr; switch (event.type) { case SDL_KEYDOWN: @@ -1727,37 +1885,42 @@ while (vid_active) { break; case SDL_WINDOWEVENT: - if (event.window.windowID == vid_windowID) { - sim_debug (SIM_VID_DBG_VIDEO|SIM_VID_DBG_KEY|SIM_VID_DBG_MOUSE|SIM_VID_DBG_CURSOR, vid_dev, "vid_thread() - Window Event: %d - %s\n", event.window.event, windoweventtypes[event.window.event]); + vptr = vid_window_from_id (event.window.windowID); + if (vptr != NULL) { + sim_debug (SIM_VID_DBG_VIDEO|SIM_VID_DBG_KEY|SIM_VID_DBG_MOUSE|SIM_VID_DBG_CURSOR, vptr->vid_dev, "vid_thread() - Window Event: %d - %s\n", event.window.event, windoweventtypes[event.window.event]); switch (event.window.event) { case SDL_WINDOWEVENT_ENTER: - if (vid_flags & SIM_VID_INPUTCAPTURED) - SDL_WarpMouseInWindow (NULL, vid_width/2, vid_height/2); /* center position */ + if (vptr->vid_flags & SIM_VID_INPUTCAPTURED) + SDL_WarpMouseInWindow (NULL, vptr->vid_width/2, vptr->vid_height/2); /* center position */ break; case SDL_WINDOWEVENT_EXPOSED: - vid_update (); + vid_update (vptr); break; } } break; case SDL_USEREVENT: - /* There are 6 user events generated */ + /* There are 9 user events generated */ /* EVENT_REDRAW to update the display */ /* EVENT_DRAW to update a region in the display texture */ /* EVENT_SHOW to display the current SDL video capabilities */ /* EVENT_CURSOR to change the current cursor */ /* EVENT_WARP to warp the cursor position */ + /* EVENT_OPEN to open a new window */ /* EVENT_CLOSE to wake up this thread and let */ /* it notice vid_active has changed */ + /* EVENT_SCREENSHOT to take a screenshot */ + /* EVENT_BEEP to emit a beep sound */ while (vid_active && event.user.code) { + vptr = vid_window_from_id (event.user.windowID); if (event.user.code == EVENT_REDRAW) { - vid_update (); + vid_update (vptr); event.user.code = 0; /* Mark as done */ if (0) while (SDL_PeepEvents (&event, 1, SDL_GETEVENT, SDL_USEREVENT, SDL_USEREVENT)) { if (event.user.code == EVENT_REDRAW) { /* Only do a single video update between waiting for events */ - sim_debug (SIM_VID_DBG_VIDEO, vid_dev, "vid_thread() - Ignored extra REDRAW Event\n"); + sim_debug (SIM_VID_DBG_VIDEO, vptr->vid_dev, "vid_thread() - Ignored extra REDRAW Event\n"); event.user.code = 0; /* Mark as done */ continue; } @@ -1765,19 +1928,20 @@ if (0) while (SDL_PeepEvents (&event, 1, SDL_GETEVENT, SD } } if (event.user.code == EVENT_CURSOR) { - vid_update_cursor ((SDL_Cursor *)(event.user.data1), (t_bool)((size_t)event.user.data2)); + vid_update_cursor (vptr, (SDL_Cursor *)(event.user.data1), (t_bool)((size_t)event.user.data2)); event.user.data1 = NULL; event.user.code = 0; /* Mark as done */ } if (event.user.code == EVENT_WARP) { - vid_warp_position (); + vid_warp_position (vptr); event.user.code = 0; /* Mark as done */ } if (event.user.code == EVENT_CLOSE) { + vid_destroy (vptr); event.user.code = 0; /* Mark as done */ } if (event.user.code == EVENT_DRAW) { - vid_draw_region ((SDL_UserEvent*)&event); + vid_draw_region (vptr, (SDL_UserEvent*)&event); event.user.code = 0; /* Mark as done */ } if (event.user.code == EVENT_SHOW) { @@ -1792,48 +1956,42 @@ if (0) while (SDL_PeepEvents (&event, 1, SDL_GETEVENT, SD vid_beep_event (); event.user.code = 0; /* Mark as done */ } + if (event.user.code == EVENT_OPEN) { + VID_DISPLAY *vptr = (VID_DISPLAY *)event.user.data1; + vid_new_window (vptr); + vptr->vid_ready = TRUE; + event.user.code = 0; /* Mark as done */ + } if (event.user.code != 0) { sim_printf ("vid_thread(): Unexpected user event code: %d\n", event.user.code); } } break; case SDL_QUIT: - sim_debug (SIM_VID_DBG_VIDEO|SIM_VID_DBG_KEY|SIM_VID_DBG_MOUSE|SIM_VID_DBG_CURSOR, vid_dev, "vid_thread() - QUIT Event - %s\n", vid_quit_callback ? "Signaled" : "Ignored"); + sim_debug (SIM_VID_DBG_VIDEO|SIM_VID_DBG_KEY|SIM_VID_DBG_MOUSE|SIM_VID_DBG_CURSOR, vptr->vid_dev, "vid_thread() - QUIT Event - %s\n", vid_quit_callback ? "Signaled" : "Ignored"); if (vid_quit_callback) vid_quit_callback (); break; default: - sim_debug (SIM_VID_DBG_VIDEO|SIM_VID_DBG_KEY|SIM_VID_DBG_MOUSE|SIM_VID_DBG_CURSOR, vid_dev, "vid_thread() - Ignored Event: Type: %s(%d)\n", eventtypes[event.type], event.type); + sim_debug (SIM_VID_DBG_VIDEO|SIM_VID_DBG_KEY|SIM_VID_DBG_MOUSE|SIM_VID_DBG_CURSOR, vptr0->vid_dev, "vid_thread() - Ignored Event: Type: %s(%d)\n", eventtypes[event.type], event.type); break; } } else { if (status < 0) - sim_printf ("%s: vid_thread() - SDL_WaitEvent error: %s\n", vid_dname(vid_dev), SDL_GetError()); + sim_printf ("%s: vid_thread() - SDL_WaitEvent error: %s\n", vid_dname(vptr0->vid_dev), SDL_GetError()); } } -vid_ready = FALSE; -if (vid_cursor) { - SDL_FreeCursor (vid_cursor); - vid_cursor = NULL; - } -SDL_DestroyTexture(vid_texture); -vid_texture = NULL; -SDL_DestroyRenderer(vid_renderer); -vid_renderer = NULL; -SDL_DestroyWindow(vid_window); -vid_window = NULL; -SDL_DestroyMutex (vid_draw_mutex); -vid_draw_mutex = NULL; vid_controllers_cleanup (); vid_beep_cleanup (); -sim_debug (SIM_VID_DBG_VIDEO|SIM_VID_DBG_KEY|SIM_VID_DBG_MOUSE|SIM_VID_DBG_CURSOR, vid_dev, "vid_thread() - Exiting\n"); +sim_debug (SIM_VID_DBG_VIDEO|SIM_VID_DBG_KEY|SIM_VID_DBG_MOUSE|SIM_VID_DBG_CURSOR, vptr0->vid_dev, "vid_thread() - Exiting\n"); return 0; } int vid_thread (void *arg) { +VID_DISPLAY *vptr = (VID_DISPLAY *)arg; int stat; SDL_SetHint (SDL_HINT_RENDER_DRIVER, "software"); @@ -1844,7 +2002,7 @@ if (stat) { sim_printf ("SDL Video subsystem can't initialize\n"); return 0; } -vid_video_events (); +vid_video_events (vptr); SDL_Quit (); return 0; } @@ -1900,14 +2058,20 @@ return SCPE_NOFNC; t_stat vid_show_release_key (FILE* st, UNIT* uptr, int32 val, CONST void* desc) { -if (vid_flags & SIM_VID_INPUTCAPTURED) - fprintf (st, "ReleaseKey=%s", vid_release_key); +VID_DISPLAY *vptr; +for (vptr = &vid_first; vptr != NULL; vptr = vptr->next) { + if (vptr->vid_flags & SIM_VID_INPUTCAPTURED) { + fprintf (st, "ReleaseKey=%s", vid_release_key); + return SCPE_OK; + } + } return SCPE_OK; } static t_stat _vid_show_video (FILE* st, UNIT* uptr, int32 val, CONST void* desc) { int i; +VID_DISPLAY *vptr; fprintf (st, "Video support using SDL: %s\n", vid_version()); #if defined (SDL_MAIN_AVAILABLE) @@ -1922,9 +2086,13 @@ if (!vid_active) { #endif } else { - fprintf (st, " Currently Active Video Window: (%d by %d pixels)\n", vid_width, vid_height); - fprintf (st, " "); - vid_show_release_key (st, uptr, val, desc); + for (vptr = &vid_first; vptr != NULL; vptr = vptr->next) { + if (!vptr->vid_active_window) + continue; + fprintf (st, " Currently Active Video Window: (%d by %d pixels)\n", vptr->vid_width, vptr->vid_height); + fprintf (st, " "); + vid_show_release_key (st, uptr, val, desc); + } fprintf (st, "\n"); fprintf (st, " SDL Video Driver: %s\n", SDL_GetCurrentVideoDriver()); } @@ -2016,7 +2184,12 @@ for (i = 0; i < SDL_GetNumRenderDrivers(); ++i) { if (vid_active) { SDL_RendererInfo info; - SDL_GetRendererInfo (vid_renderer, &info); + for (vptr = &vid_first; vptr != NULL; vptr = vptr->next) { + if (vptr->vid_active_window) { + SDL_GetRendererInfo (vptr->vid_renderer, &info); + break; + } + } fprintf (st, " Currently Active Renderer: %s\n", info.name); } if (1) { @@ -2161,7 +2334,7 @@ while (_show_stat == -1) return _show_stat; } -static t_stat _vid_screenshot (const char *filename) +static t_stat _vid_screenshot (VID_DISPLAY *vptr, const char *filename) { int stat; char *fullname = NULL; @@ -2174,9 +2347,9 @@ fullname = (char *)malloc (strlen(filename) + 5); if (!fullname) return SCPE_MEM; if (1) { - SDL_Surface *sshot = sim_end ? SDL_CreateRGBSurface(0, vid_width, vid_height, 32, 0x00ff0000, 0x0000ff00, 0x000000ff, 0xff000000) : - SDL_CreateRGBSurface(0, vid_width, vid_height, 32, 0x0000ff00, 0x000ff000, 0xff000000, 0x000000ff) ; - SDL_RenderReadPixels(vid_renderer, NULL, SDL_PIXELFORMAT_ARGB8888, sshot->pixels, sshot->pitch); + SDL_Surface *sshot = sim_end ? SDL_CreateRGBSurface(0, vptr->vid_width, vptr->vid_height, 32, 0x00ff0000, 0x0000ff00, 0x000000ff, 0xff000000) : + SDL_CreateRGBSurface(0, vptr->vid_width, vptr->vid_height, 32, 0x0000ff00, 0x000ff000, 0xff000000, 0x000000ff) ; + SDL_RenderReadPixels(vptr->vid_renderer, NULL, SDL_PIXELFORMAT_ARGB8888, sshot->pixels, sshot->pitch); #if defined(HAVE_LIBPNG) if (!match_ext (filename, "bmp")) { sprintf (fullname, "%s%s", filename, match_ext (filename, "png") ? "" : ".png"); @@ -2210,7 +2383,33 @@ static const char *_screenshot_filename; void vid_screenshot_event (void) { -_screenshot_stat = _vid_screenshot (_screenshot_filename); +VID_DISPLAY *vptr; +int i = 0, n; +char *name = (char *)malloc (strlen (_screenshot_filename) + 5); +char *extension = strrchr ((char *)_screenshot_filename, '.'); +if (name == NULL) { + _screenshot_stat = SCPE_NXM; + return; + } +if (extension) + n = extension - _screenshot_filename; +else { + n = strlen (_screenshot_filename); + extension = (char *)""; + } +strncpy (name, _screenshot_filename, n); +for (vptr = &vid_first; vptr != NULL; vptr = vptr->next) { + if (vid_active > 1) + sprintf (name + n, "%d%s", i++, extension); + else + sprintf (name + n, "%s", extension); + _screenshot_stat = _vid_screenshot (vptr, name); + if (_screenshot_stat != SCPE_OK) { + free (name); + return; + } + } +free (name); } t_stat vid_screenshot (const char *filename) @@ -2247,7 +2446,6 @@ static int vid_beep_samples; static void vid_audio_callback(void *ctx, Uint8 *stream, int length) { -int16 *data = (int16 *)stream; int i, sum, remnant = ((vid_beep_samples - vid_beep_offset) * sizeof (*vid_beep_data)); if (length > remnant) { @@ -2332,6 +2530,11 @@ t_stat vid_close (void) return SCPE_OK; } +t_stat vid_close_all (void) +{ +return SCPE_OK; +} + t_stat vid_poll_kb (SIM_KEY_EVENT *ev) { return SCPE_EOF; @@ -2390,7 +2593,7 @@ return SCPE_OK; t_stat vid_show_video (FILE* st, UNIT* uptr, int32 val, CONST void* desc) { -fprintf (st, "video support unavailable"); +fprintf (st, "video support unavailable\n"); return SCPE_OK; } @@ -2411,4 +2614,58 @@ t_stat vid_set_fullscreen (t_bool flag) sim_printf ("video support unavailable\n"); return SCPE_OK; } + +t_stat vid_open_window (VID_DISPLAY **vptr, DEVICE *dptr, const char *title, uint32 width, uint32 height, int flags) +{ +*vptr = NULL; +return SCPE_NOFNC; +} + +t_stat vid_close_window (VID_DISPLAY *vptr) +{ +return SCPE_OK; +} + +uint32 vid_map_rgb_window (VID_DISPLAY *vptr, uint8 r, uint8 g, uint8 b) +{ +return 0; +} + +void vid_draw_window (VID_DISPLAY *vptr, int32 x, int32 y, int32 w, int32 h, uint32 *buf) +{ +return; +} + +void vid_refresh_window (VID_DISPLAY *vptr) +{ +return; +} + +t_stat vid_set_cursor_window (VID_DISPLAY *vptr, t_bool visible, uint32 width, uint32 height, uint8 *data, uint8 *mask, uint32 hot_x, uint32 hot_y) +{ +return SCPE_NOFNC; +} + +t_bool vid_is_fullscreen_window (VID_DISPLAY *vptr) +{ +sim_printf ("video support unavailable\n"); +return FALSE; +} + +t_stat vid_set_fullscreen_window (VID_DISPLAY *vptr, t_bool flag) +{ +sim_printf ("video support unavailable\n"); +return SCPE_OK; +} + +void vid_set_cursor_position_window (VID_DISPLAY *vptr, int32 x, int32 y) +{ +return; +} + +const char *vid_key_name (int32 key) +{ +return ""; +} + #endif /* defined(USE_SIM_VIDEO) */ diff --git a/sim_video.h b/sim_video.h index 1e232ee..6e9ebea 100644 --- a/sim_video.h +++ b/sim_video.h @@ -157,6 +157,8 @@ extern "C" { #define SIM_KEY_UNKNOWN 200 +typedef struct VID_DISPLAY VID_DISPLAY; + struct mouse_event { int32 x_rel; /* X axis relative motion */ int32 y_rel; /* Y axis relative motion */ @@ -165,11 +167,15 @@ struct mouse_event { t_bool b1_state; /* state of button 1 */ t_bool b2_state; /* state of button 2 */ t_bool b3_state; /* state of button 3 */ + DEVICE *dev; /* which device */ + VID_DISPLAY *vptr; /* which display */ }; struct key_event { uint32 key; /* key sym */ uint32 state; /* key state change */ + DEVICE *dev; /* which device */ + VID_DISPLAY *vptr; /* which display */ }; typedef struct mouse_event SIM_MOUSE_EVENT; @@ -201,9 +207,20 @@ t_stat vid_screenshot (const char *filename); t_bool vid_is_fullscreen (void); t_stat vid_set_fullscreen (t_bool flag); -extern t_bool vid_active; +extern int vid_active; void vid_set_cursor_position (int32 x, int32 y); /* cursor position (set by calling code) */ +t_stat vid_open_window (VID_DISPLAY **vptr, DEVICE *dptr, const char *title, uint32 width, uint32 height, int flags); +t_stat vid_close_window (VID_DISPLAY *vptr); +t_stat vid_close_all (void); +uint32 vid_map_rgb_window (VID_DISPLAY *vptr, uint8 r, uint8 g, uint8 b); +void vid_draw_window (VID_DISPLAY *vptr, int32 x, int32 y, int32 w, int32 h, uint32 *buf); +void vid_refresh_window (VID_DISPLAY *vptr); +t_stat vid_set_cursor_window (VID_DISPLAY *vptr, t_bool visible, uint32 width, uint32 height, uint8 *data, uint8 *mask, uint32 hot_x, uint32 hot_y); +t_bool vid_is_fullscreen_window (VID_DISPLAY *vptr); +t_stat vid_set_fullscreen_window (VID_DISPLAY *vptr, t_bool flag); +void vid_set_cursor_position_window (VID_DISPLAY *vptr, int32 x, int32 y); /* cursor position (set by calling code) */ + /* A device simulator can optionally set the vid_display_kb_event_process * routine pointer to the address of a routine. * Simulator code which uses the display library which processes window