/** * main_entry: * * Main function of RetroArch. * * If HAVE_MAIN is not defined, will contain main loop and will not * be exited from until we exit the program. Otherwise, will * just do initialization. * * Returns: varies per platform. **/ int rarch_main(int argc, char *argv[], void *data) { void *args = (void*)data; int ret = 0; settings_t *settings = NULL; rarch_ctl(RARCH_CTL_PREINIT, NULL); frontend_driver_init_first(args); rarch_ctl(RARCH_CTL_INIT, NULL); #ifdef HAVE_THREADS async_jobs = async_job_new(); #endif if (frontend_driver_is_inited()) { ret = main_load_content(argc, argv, args, frontend_driver_environment_get_ptr()); if (!ret) return ret; } event_command(EVENT_CMD_HISTORY_INIT); settings = config_get_ptr(); if (settings->history_list_enable) { char *fullpath = NULL; global_t *global = global_get_ptr(); rarch_system_info_t *system = NULL; runloop_ctl(RUNLOOP_CTL_SYSTEM_INFO_GET, &system); runloop_ctl(RUNLOOP_CTL_GET_CONTENT_PATH, &fullpath); if (global->inited.content || system->no_content) history_playlist_push( g_defaults.history, fullpath, settings->libretro, system ? &system->info : NULL); } ui_companion_driver_init_first(); #ifndef HAVE_MAIN do { unsigned sleep_ms = 0; ret = runloop_iterate(&sleep_ms); if (ret == 1 && sleep_ms > 0) retro_sleep(sleep_ms); runloop_ctl(RUNLOOP_CTL_DATA_ITERATE, NULL); }while(ret != -1); main_exit(args); #endif #ifdef HAVE_THREADS async_job_free(async_jobs); async_jobs = NULL; #endif return 0; }
static enum runloop_state runloop_check_state( settings_t *settings, uint64_t current_input, uint64_t old_input, unsigned *sleep_ms) { static bool old_focus = true; #ifdef HAVE_OVERLAY static char prev_overlay_restore = false; bool osk_enable = input_driver_is_onscreen_keyboard_enabled(); #endif #ifdef HAVE_NETWORKING bool tmp = false; #endif bool focused = true; uint64_t trigger_input = current_input & ~old_input; bool pause_pressed = runloop_cmd_triggered(trigger_input, RARCH_PAUSE_TOGGLE); if (input_driver_is_flushing_input()) { input_driver_unset_flushing_input(); if (current_input) { current_input = 0; /* If core was paused before entering menu, evoke * pause toggle to wake it up. */ if (runloop_paused) BIT64_SET(current_input, RARCH_PAUSE_TOGGLE); input_driver_set_flushing_input(); } } if (runloop_cmd_triggered(trigger_input, RARCH_OVERLAY_NEXT)) command_event(CMD_EVENT_OVERLAY_NEXT, NULL); if (runloop_cmd_triggered(trigger_input, RARCH_FULLSCREEN_TOGGLE_KEY)) { bool fullscreen_toggled = !runloop_paused; #ifdef HAVE_MENU fullscreen_toggled = fullscreen_toggled || menu_driver_ctl(RARCH_MENU_CTL_IS_ALIVE, NULL); #endif if (fullscreen_toggled) command_event(CMD_EVENT_FULLSCREEN_TOGGLE, NULL); } if (runloop_cmd_triggered(trigger_input, RARCH_GRAB_MOUSE_TOGGLE)) command_event(CMD_EVENT_GRAB_MOUSE_TOGGLE, NULL); #ifdef HAVE_OVERLAY if (osk_enable && !input_keyboard_ctl( RARCH_INPUT_KEYBOARD_CTL_IS_LINEFEED_ENABLED, NULL)) { input_driver_unset_onscreen_keyboard_enabled(); prev_overlay_restore = true; command_event(CMD_EVENT_OVERLAY_DEINIT, NULL); } else if (!osk_enable && input_keyboard_ctl( RARCH_INPUT_KEYBOARD_CTL_IS_LINEFEED_ENABLED, NULL)) { input_driver_set_onscreen_keyboard_enabled(); prev_overlay_restore = false; command_event(CMD_EVENT_OVERLAY_INIT, NULL); } else if (prev_overlay_restore) { if (!settings->input.overlay_hide_in_menu) command_event(CMD_EVENT_OVERLAY_INIT, NULL); prev_overlay_restore = false; } #endif if (runloop_iterate_time_to_exit( runloop_cmd_press(current_input, RARCH_QUIT_KEY)) != 1) return RUNLOOP_STATE_QUIT; #ifdef HAVE_MENU if (menu_driver_ctl(RARCH_MENU_CTL_IS_ALIVE, NULL)) { menu_ctx_iterate_t iter; bool skip = false; #ifdef HAVE_OVERLAY skip = osk_enable && input_keyboard_return_pressed(); #endif if (!skip) { enum menu_action action = (enum menu_action)menu_event(current_input, trigger_input); bool focused = settings->pause_nonactive ? video_driver_is_focused() : true; focused = focused && !ui_companion_is_on_foreground(); iter.action = action; if (!menu_driver_ctl(RARCH_MENU_CTL_ITERATE, &iter)) rarch_ctl(RARCH_CTL_MENU_RUNNING_FINISHED, NULL); if (focused || !runloop_idle) menu_driver_ctl(RARCH_MENU_CTL_RENDER, NULL); if (!focused) return RUNLOOP_STATE_SLEEP; if (action == MENU_ACTION_QUIT) return RUNLOOP_STATE_QUIT; } } #endif if (runloop_idle) return RUNLOOP_STATE_SLEEP; #ifdef HAVE_MENU if (menu_event_keyboard_is_set(RETROK_F1) == 1) { if (menu_driver_ctl(RARCH_MENU_CTL_IS_ALIVE, NULL)) { if (rarch_ctl(RARCH_CTL_IS_INITED, NULL) && !rarch_ctl(RARCH_CTL_IS_DUMMY_CORE, NULL)) { rarch_ctl(RARCH_CTL_MENU_RUNNING_FINISHED, NULL); menu_event_keyboard_set(false, RETROK_F1); } } } else if ((!menu_event_keyboard_is_set(RETROK_F1) && runloop_cmd_menu_press(current_input, old_input, trigger_input)) || rarch_ctl(RARCH_CTL_IS_DUMMY_CORE, NULL)) { if (menu_driver_ctl(RARCH_MENU_CTL_IS_ALIVE, NULL)) { if (rarch_ctl(RARCH_CTL_IS_INITED, NULL) && !rarch_ctl(RARCH_CTL_IS_DUMMY_CORE, NULL)) rarch_ctl(RARCH_CTL_MENU_RUNNING_FINISHED, NULL); } else { menu_display_toggle_set_reason(MENU_TOGGLE_REASON_USER); rarch_ctl(RARCH_CTL_MENU_RUNNING, NULL); } } else menu_event_keyboard_set(false, RETROK_F1); if (menu_driver_ctl(RARCH_MENU_CTL_IS_ALIVE, NULL)) { if (!settings->menu.throttle_framerate && !settings->fastforward_ratio) return RUNLOOP_STATE_MENU_ITERATE; return RUNLOOP_STATE_END; } #endif if (settings->pause_nonactive) focused = video_driver_is_focused(); if (runloop_cmd_triggered(trigger_input, RARCH_SCREENSHOT)) command_event(CMD_EVENT_TAKE_SCREENSHOT, NULL); if (runloop_cmd_triggered(trigger_input, RARCH_MUTE)) command_event(CMD_EVENT_AUDIO_MUTE_TOGGLE, NULL); if (runloop_cmd_triggered(trigger_input, RARCH_OSK)) { if (input_keyboard_ctl( RARCH_INPUT_KEYBOARD_CTL_IS_LINEFEED_ENABLED, NULL)) input_keyboard_ctl( RARCH_INPUT_KEYBOARD_CTL_UNSET_LINEFEED_ENABLED, NULL); else input_keyboard_ctl( RARCH_INPUT_KEYBOARD_CTL_SET_LINEFEED_ENABLED, NULL); } if (runloop_cmd_press(current_input, RARCH_VOLUME_UP)) command_event(CMD_EVENT_VOLUME_UP, NULL); else if (runloop_cmd_press(current_input, RARCH_VOLUME_DOWN)) command_event(CMD_EVENT_VOLUME_DOWN, NULL); #ifdef HAVE_NETWORKING tmp = runloop_cmd_triggered(trigger_input, RARCH_NETPLAY_FLIP); netplay_driver_ctl(RARCH_NETPLAY_CTL_FLIP_PLAYERS, &tmp); tmp = runloop_cmd_triggered(trigger_input, RARCH_FULLSCREEN_TOGGLE_KEY); netplay_driver_ctl(RARCH_NETPLAY_CTL_FULLSCREEN_TOGGLE, &tmp); #endif /* Check if libretro pause key was pressed. If so, pause or * unpause the libretro core. */ /* FRAMEADVANCE will set us into pause mode. */ pause_pressed |= !runloop_paused && runloop_cmd_triggered(trigger_input, RARCH_FRAMEADVANCE); if (focused && pause_pressed) command_event(CMD_EVENT_PAUSE_TOGGLE, NULL); else if (focused && !old_focus) command_event(CMD_EVENT_UNPAUSE, NULL); else if (!focused && old_focus) command_event(CMD_EVENT_PAUSE, NULL); old_focus = focused; if (!focused) return RUNLOOP_STATE_SLEEP; if (runloop_paused) { /* check pause state */ bool check_is_oneshot = runloop_cmd_triggered(trigger_input, RARCH_FRAMEADVANCE) || runloop_cmd_press(current_input, RARCH_REWIND); if (runloop_cmd_triggered(trigger_input, RARCH_FULLSCREEN_TOGGLE_KEY)) { command_event(CMD_EVENT_FULLSCREEN_TOGGLE, NULL); if (!runloop_ctl(RUNLOOP_CTL_IS_IDLE, NULL)) video_driver_cached_frame(); } if (!check_is_oneshot) return RUNLOOP_STATE_SLEEP; } /* To avoid continous switching if we hold the button down, we require * that the button must go from pressed to unpressed back to pressed * to be able to toggle between then. */ if (runloop_cmd_triggered(trigger_input, RARCH_FAST_FORWARD_KEY)) { if (input_driver_is_nonblock_state()) input_driver_unset_nonblock_state(); else input_driver_set_nonblock_state(); driver_ctl(RARCH_DRIVER_CTL_SET_NONBLOCK_STATE, NULL); } else if ((runloop_cmd_pressed(old_input, RARCH_FAST_FORWARD_HOLD_KEY) != runloop_cmd_press(current_input, RARCH_FAST_FORWARD_HOLD_KEY))) { if (runloop_cmd_press(current_input, RARCH_FAST_FORWARD_HOLD_KEY)) input_driver_set_nonblock_state(); else input_driver_unset_nonblock_state(); driver_ctl(RARCH_DRIVER_CTL_SET_NONBLOCK_STATE, NULL); } /* Checks if the state increase/decrease keys have been pressed * for this frame. */ if (runloop_cmd_triggered(trigger_input, RARCH_STATE_SLOT_PLUS)) { char msg[128]; msg[0] = '\0'; settings->state_slot++; snprintf(msg, sizeof(msg), "%s: %d", msg_hash_to_str(MSG_STATE_SLOT), settings->state_slot); runloop_msg_queue_push(msg, 2, 180, true); RARCH_LOG("%s\n", msg); } else if (runloop_cmd_triggered(trigger_input, RARCH_STATE_SLOT_MINUS)) { char msg[128]; msg[0] = '\0'; if (settings->state_slot > 0) settings->state_slot--; snprintf(msg, sizeof(msg), "%s: %d", msg_hash_to_str(MSG_STATE_SLOT), settings->state_slot); runloop_msg_queue_push(msg, 2, 180, true); RARCH_LOG("%s\n", msg); } if (runloop_cmd_triggered(trigger_input, RARCH_SAVE_STATE_KEY)) command_event(CMD_EVENT_SAVE_STATE, NULL); else if (runloop_cmd_triggered(trigger_input, RARCH_LOAD_STATE_KEY)) command_event(CMD_EVENT_LOAD_STATE, NULL); #ifdef HAVE_CHEEVOS if (!settings->cheevos.hardcore_mode_enable) #endif state_manager_check_rewind(runloop_cmd_press(current_input, RARCH_REWIND)); runloop_slowmotion = runloop_cmd_press(current_input, RARCH_SLOWMOTION); if (runloop_slowmotion) { /* Checks if slowmotion toggle/hold was being pressed and/or held. */ if (settings->video.black_frame_insertion) { if (!runloop_ctl(RUNLOOP_CTL_IS_IDLE, NULL)) video_driver_cached_frame(); } if (state_manager_frame_is_reversed()) runloop_msg_queue_push(msg_hash_to_str(MSG_SLOW_MOTION_REWIND), 2, 30, true); else runloop_msg_queue_push(msg_hash_to_str(MSG_SLOW_MOTION), 2, 30, true); } if (runloop_cmd_triggered(trigger_input, RARCH_MOVIE_RECORD_TOGGLE)) bsv_movie_check(); if (runloop_cmd_triggered(trigger_input, RARCH_SHADER_NEXT) || runloop_cmd_triggered(trigger_input, RARCH_SHADER_PREV)) dir_check_shader( runloop_cmd_triggered(trigger_input, RARCH_SHADER_NEXT), runloop_cmd_triggered(trigger_input, RARCH_SHADER_PREV)); if (runloop_cmd_triggered(trigger_input, RARCH_DISK_EJECT_TOGGLE)) command_event(CMD_EVENT_DISK_EJECT_TOGGLE, NULL); else if (runloop_cmd_triggered(trigger_input, RARCH_DISK_NEXT)) command_event(CMD_EVENT_DISK_NEXT, NULL); else if (runloop_cmd_triggered(trigger_input, RARCH_DISK_PREV)) command_event(CMD_EVENT_DISK_PREV, NULL); if (runloop_cmd_triggered(trigger_input, RARCH_RESET)) command_event(CMD_EVENT_RESET, NULL); cheat_manager_state_checks( runloop_cmd_triggered(trigger_input, RARCH_CHEAT_INDEX_PLUS), runloop_cmd_triggered(trigger_input, RARCH_CHEAT_INDEX_MINUS), runloop_cmd_triggered(trigger_input, RARCH_CHEAT_TOGGLE)); return RUNLOOP_STATE_ITERATE; }
/** * recording_init: * * Initializes recording. * * Returns: true (1) if successful, otherwise false (0). **/ bool recording_init(void) { char recording_file[PATH_MAX_LENGTH]; struct ffemu_params params = {0}; struct retro_system_av_info *av_info = video_viewport_get_system_av_info(); bool *recording_enabled = recording_is_enabled(); settings_t *settings = config_get_ptr(); global_t *global = global_get_ptr(); if (!*recording_enabled) return false; recording_file[0] = '\0'; if (rarch_ctl(RARCH_CTL_IS_DUMMY_CORE, NULL)) { RARCH_WARN("%s\n", msg_hash_to_str(MSG_USING_LIBRETRO_DUMMY_CORE_RECORDING_SKIPPED)); return false; } if (!settings->bools.video_gpu_record && video_driver_is_hw_context()) { RARCH_WARN("%s.\n", msg_hash_to_str(MSG_HW_RENDERED_MUST_USE_POSTSHADED_RECORDING)); return false; } RARCH_LOG("%s: FPS: %.4f, Sample rate: %.4f\n", msg_hash_to_str(MSG_CUSTOM_TIMING_GIVEN), (float)av_info->timing.fps, (float)av_info->timing.sample_rate); strlcpy(recording_file, global->record.path, sizeof(recording_file)); if (recording_use_output_dir) fill_pathname_join(recording_file, global->record.output_dir, global->record.path, sizeof(recording_file)); params.out_width = av_info->geometry.base_width; params.out_height = av_info->geometry.base_height; params.fb_width = av_info->geometry.max_width; params.fb_height = av_info->geometry.max_height; params.channels = 2; params.filename = recording_file; params.fps = av_info->timing.fps; params.samplerate = av_info->timing.sample_rate; params.pix_fmt = (video_driver_get_pixel_format() == RETRO_PIXEL_FORMAT_XRGB8888) ? FFEMU_PIX_ARGB8888 : FFEMU_PIX_RGB565; params.config = NULL; if (!string_is_empty(global->record.config)) params.config = global->record.config; if (video_driver_supports_recording()) { unsigned gpu_size; struct video_viewport vp; vp.x = 0; vp.y = 0; vp.width = 0; vp.height = 0; vp.full_width = 0; vp.full_height = 0; video_driver_get_viewport_info(&vp); if (!vp.width || !vp.height) { RARCH_ERR("Failed to get viewport information from video driver. " "Cannot start recording ...\n"); return false; } params.out_width = vp.width; params.out_height = vp.height; params.fb_width = next_pow2(vp.width); params.fb_height = next_pow2(vp.height); if (settings->bools.video_force_aspect && (video_driver_get_aspect_ratio() > 0.0f)) params.aspect_ratio = video_driver_get_aspect_ratio(); else params.aspect_ratio = (float)vp.width / vp.height; params.pix_fmt = FFEMU_PIX_BGR24; recording_gpu_width = vp.width; recording_gpu_height = vp.height; RARCH_LOG("%s %u x %u\n", msg_hash_to_str(MSG_DETECTED_VIEWPORT_OF), vp.width, vp.height); gpu_size = vp.width * vp.height * 3; if (!video_driver_gpu_record_init(gpu_size)) return false; } else { if (recording_width || recording_height) { params.out_width = recording_width; params.out_height = recording_height; } if (settings->bools.video_force_aspect && (video_driver_get_aspect_ratio() > 0.0f)) params.aspect_ratio = video_driver_get_aspect_ratio(); else params.aspect_ratio = (float)params.out_width / params.out_height; if (settings->bools.video_post_filter_record && video_driver_frame_filter_alive()) { unsigned max_width = 0; unsigned max_height = 0; params.pix_fmt = FFEMU_PIX_RGB565; if (video_driver_frame_filter_is_32bit()) params.pix_fmt = FFEMU_PIX_ARGB8888; rarch_softfilter_get_max_output_size( video_driver_frame_filter_get_ptr(), &max_width, &max_height); params.fb_width = next_pow2(max_width); params.fb_height = next_pow2(max_height); } } RARCH_LOG("%s %s @ %ux%u. (FB size: %ux%u pix_fmt: %u)\n", msg_hash_to_str(MSG_RECORDING_TO), global->record.path, params.out_width, params.out_height, params.fb_width, params.fb_height, (unsigned)params.pix_fmt); if (!record_driver_init_first(&recording_driver, &recording_data, ¶ms)) { RARCH_ERR("%s\n", msg_hash_to_str(MSG_FAILED_TO_START_RECORDING)); command_event(CMD_EVENT_GPU_RECORD_DEINIT, NULL); return false; } return true; }
bool runloop_ctl(enum runloop_ctl_state state, void *data) { switch (state) { case RUNLOOP_CTL_SYSTEM_INFO_INIT: core_get_system_info(&runloop_system.info); if (!runloop_system.info.library_name) runloop_system.info.library_name = msg_hash_to_str(MSG_UNKNOWN); if (!runloop_system.info.library_version) runloop_system.info.library_version = "v0"; video_driver_set_title_buf(); strlcpy(runloop_system.valid_extensions, runloop_system.info.valid_extensions ? runloop_system.info.valid_extensions : DEFAULT_EXT, sizeof(runloop_system.valid_extensions)); break; case RUNLOOP_CTL_GET_CORE_OPTION_SIZE: { unsigned *idx = (unsigned*)data; if (!idx) return false; *idx = core_option_manager_size(runloop_core_options); } break; case RUNLOOP_CTL_HAS_CORE_OPTIONS: return runloop_core_options; case RUNLOOP_CTL_CORE_OPTIONS_LIST_GET: { core_option_manager_t **coreopts = (core_option_manager_t**)data; if (!coreopts) return false; *coreopts = runloop_core_options; } break; case RUNLOOP_CTL_SYSTEM_INFO_GET: { rarch_system_info_t **system = (rarch_system_info_t**)data; if (!system) return false; *system = &runloop_system; } break; case RUNLOOP_CTL_SYSTEM_INFO_FREE: /* No longer valid. */ if (runloop_system.subsystem.data) free(runloop_system.subsystem.data); runloop_system.subsystem.data = NULL; runloop_system.subsystem.size = 0; if (runloop_system.ports.data) free(runloop_system.ports.data); runloop_system.ports.data = NULL; runloop_system.ports.size = 0; if (runloop_system.mmaps.descriptors) free((void *)runloop_system.mmaps.descriptors); runloop_system.mmaps.descriptors = NULL; runloop_system.mmaps.num_descriptors = 0; runloop_key_event = NULL; runloop_frontend_key_event = NULL; audio_driver_unset_callback(); memset(&runloop_system, 0, sizeof(rarch_system_info_t)); break; case RUNLOOP_CTL_SET_FRAME_TIME_LAST: runloop_frame_time_last_enable = true; break; case RUNLOOP_CTL_SET_OVERRIDES_ACTIVE: runloop_overrides_active = true; break; case RUNLOOP_CTL_UNSET_OVERRIDES_ACTIVE: runloop_overrides_active = false; break; case RUNLOOP_CTL_IS_OVERRIDES_ACTIVE: return runloop_overrides_active; case RUNLOOP_CTL_SET_GAME_OPTIONS_ACTIVE: runloop_game_options_active = true; break; case RUNLOOP_CTL_UNSET_GAME_OPTIONS_ACTIVE: runloop_game_options_active = false; break; case RUNLOOP_CTL_IS_GAME_OPTIONS_ACTIVE: return runloop_game_options_active; case RUNLOOP_CTL_SET_FRAME_LIMIT: runloop_set_frame_limit = true; break; case RUNLOOP_CTL_GET_PERFCNT: { bool **perfcnt = (bool**)data; if (!perfcnt) return false; *perfcnt = &runloop_perfcnt_enable; } break; case RUNLOOP_CTL_SET_PERFCNT_ENABLE: runloop_perfcnt_enable = true; break; case RUNLOOP_CTL_UNSET_PERFCNT_ENABLE: runloop_perfcnt_enable = false; break; case RUNLOOP_CTL_IS_PERFCNT_ENABLE: return runloop_perfcnt_enable; case RUNLOOP_CTL_SET_NONBLOCK_FORCED: runloop_force_nonblock = true; break; case RUNLOOP_CTL_UNSET_NONBLOCK_FORCED: runloop_force_nonblock = false; break; case RUNLOOP_CTL_IS_NONBLOCK_FORCED: return runloop_force_nonblock; case RUNLOOP_CTL_SET_FRAME_TIME: { const struct retro_frame_time_callback *info = (const struct retro_frame_time_callback*)data; #ifdef HAVE_NETWORKING /* retro_run() will be called in very strange and * mysterious ways, have to disable it. */ if (netplay_driver_ctl(RARCH_NETPLAY_CTL_IS_ENABLED, NULL)) return false; #endif runloop_frame_time = *info; } break; case RUNLOOP_CTL_GET_WINDOWED_SCALE: { unsigned **scale = (unsigned**)data; if (!scale) return false; *scale = (unsigned*)&runloop_pending_windowed_scale; } break; case RUNLOOP_CTL_SET_WINDOWED_SCALE: { unsigned *idx = (unsigned*)data; if (!idx) return false; runloop_pending_windowed_scale = *idx; } break; case RUNLOOP_CTL_SET_LIBRETRO_PATH: return path_set(RARCH_PATH_CORE, (const char*)data); case RUNLOOP_CTL_FRAME_TIME_FREE: memset(&runloop_frame_time, 0, sizeof(struct retro_frame_time_callback)); runloop_frame_time_last = 0; runloop_max_frames = 0; break; case RUNLOOP_CTL_STATE_FREE: runloop_perfcnt_enable = false; runloop_idle = false; runloop_paused = false; runloop_slowmotion = false; runloop_frame_time_last_enable = false; runloop_set_frame_limit = false; runloop_overrides_active = false; runloop_ctl(RUNLOOP_CTL_FRAME_TIME_FREE, NULL); break; case RUNLOOP_CTL_GLOBAL_FREE: { global_t *global = NULL; command_event(CMD_EVENT_TEMPORARY_CONTENT_DEINIT, NULL); path_deinit_subsystem(); command_event(CMD_EVENT_RECORD_DEINIT, NULL); command_event(CMD_EVENT_LOG_FILE_DEINIT, NULL); rarch_ctl(RARCH_CTL_UNSET_BLOCK_CONFIG_READ, NULL); rarch_ctl(RARCH_CTL_UNSET_SRAM_LOAD_DISABLED, NULL); rarch_ctl(RARCH_CTL_UNSET_SRAM_SAVE_DISABLED, NULL); rarch_ctl(RARCH_CTL_UNSET_SRAM_ENABLE, NULL); rarch_ctl(RARCH_CTL_UNSET_BPS_PREF, NULL); rarch_ctl(RARCH_CTL_UNSET_IPS_PREF, NULL); rarch_ctl(RARCH_CTL_UNSET_UPS_PREF, NULL); rarch_ctl(RARCH_CTL_UNSET_PATCH_BLOCKED, NULL); runloop_overrides_active = false; core_unset_input_descriptors(); global = global_get_ptr(); path_clear_all(); dir_clear_all(); memset(global, 0, sizeof(struct global)); retroarch_override_setting_free_state(); } break; case RUNLOOP_CTL_CLEAR_STATE: driver_ctl(RARCH_DRIVER_CTL_DEINIT, NULL); runloop_ctl(RUNLOOP_CTL_STATE_FREE, NULL); runloop_ctl(RUNLOOP_CTL_GLOBAL_FREE, NULL); break; case RUNLOOP_CTL_SET_MAX_FRAMES: { unsigned *ptr = (unsigned*)data; if (!ptr) return false; runloop_max_frames = *ptr; } break; case RUNLOOP_CTL_IS_IDLE: return runloop_idle; case RUNLOOP_CTL_SET_IDLE: { bool *ptr = (bool*)data; if (!ptr) return false; runloop_idle = *ptr; } break; case RUNLOOP_CTL_IS_SLOWMOTION: return runloop_slowmotion; case RUNLOOP_CTL_SET_SLOWMOTION: { bool *ptr = (bool*)data; if (!ptr) return false; runloop_slowmotion = *ptr; } break; case RUNLOOP_CTL_SET_PAUSED: { bool *ptr = (bool*)data; if (!ptr) return false; runloop_paused = *ptr; } break; case RUNLOOP_CTL_IS_PAUSED: return runloop_paused; case RUNLOOP_CTL_MSG_QUEUE_PULL: #ifdef HAVE_THREADS slock_lock(_runloop_msg_queue_lock); #endif { const char **ret = (const char**)data; if (!ret) { #ifdef HAVE_THREADS slock_unlock(_runloop_msg_queue_lock); #endif return false; } *ret = msg_queue_pull(runloop_msg_queue); } #ifdef HAVE_THREADS slock_unlock(_runloop_msg_queue_lock); #endif break; case RUNLOOP_CTL_MSG_QUEUE_DEINIT: if (!runloop_msg_queue) return true; #ifdef HAVE_THREADS slock_lock(_runloop_msg_queue_lock); #endif msg_queue_free(runloop_msg_queue); #ifdef HAVE_THREADS slock_unlock(_runloop_msg_queue_lock); #endif #ifdef HAVE_THREADS slock_free(_runloop_msg_queue_lock); _runloop_msg_queue_lock = NULL; #endif runloop_msg_queue = NULL; break; case RUNLOOP_CTL_MSG_QUEUE_INIT: runloop_ctl(RUNLOOP_CTL_MSG_QUEUE_DEINIT, NULL); runloop_msg_queue = msg_queue_new(8); retro_assert(runloop_msg_queue); #ifdef HAVE_THREADS _runloop_msg_queue_lock = slock_new(); retro_assert(_runloop_msg_queue_lock); #endif break; case RUNLOOP_CTL_TASK_INIT: { #ifdef HAVE_THREADS settings_t *settings = config_get_ptr(); bool threaded_enable = settings->threaded_data_runloop_enable; #else bool threaded_enable = false; #endif task_queue_ctl(TASK_QUEUE_CTL_DEINIT, NULL); task_queue_ctl(TASK_QUEUE_CTL_INIT, &threaded_enable); } break; case RUNLOOP_CTL_SET_CORE_SHUTDOWN: runloop_core_shutdown_initiated = true; break; case RUNLOOP_CTL_SET_SHUTDOWN: runloop_shutdown_initiated = true; break; case RUNLOOP_CTL_IS_SHUTDOWN: return runloop_shutdown_initiated; case RUNLOOP_CTL_SET_EXEC: runloop_exec = true; break; case RUNLOOP_CTL_DATA_DEINIT: task_queue_ctl(TASK_QUEUE_CTL_DEINIT, NULL); break; case RUNLOOP_CTL_IS_CORE_OPTION_UPDATED: if (!runloop_core_options) return false; return core_option_manager_updated(runloop_core_options); case RUNLOOP_CTL_CORE_OPTION_PREV: { unsigned *idx = (unsigned*)data; if (!idx) return false; core_option_manager_prev(runloop_core_options, *idx); if (ui_companion_is_on_foreground()) ui_companion_driver_notify_refresh(); } break; case RUNLOOP_CTL_CORE_OPTION_NEXT: { unsigned *idx = (unsigned*)data; if (!idx) return false; core_option_manager_next(runloop_core_options, *idx); if (ui_companion_is_on_foreground()) ui_companion_driver_notify_refresh(); } break; case RUNLOOP_CTL_CORE_OPTIONS_GET: { struct retro_variable *var = (struct retro_variable*)data; if (!runloop_core_options || !var) return false; RARCH_LOG("Environ GET_VARIABLE %s:\n", var->key); core_option_manager_get(runloop_core_options, var); RARCH_LOG("\t%s\n", var->value ? var->value : msg_hash_to_str(MENU_ENUM_LABEL_VALUE_NOT_AVAILABLE)); } break; case RUNLOOP_CTL_CORE_OPTIONS_INIT: { settings_t *settings = config_get_ptr(); char *game_options_path = NULL; bool ret = false; const struct retro_variable *vars = (const struct retro_variable*)data; if (settings && settings->game_specific_options) ret = rarch_game_specific_options(&game_options_path); if(ret) { runloop_ctl(RUNLOOP_CTL_SET_GAME_OPTIONS_ACTIVE, NULL); runloop_core_options = core_option_manager_new(game_options_path, vars); free(game_options_path); } else { char buf[PATH_MAX_LENGTH]; const char *options_path = NULL; buf[0] = '\0'; if (settings) options_path = settings->path.core_options; if (string_is_empty(options_path) && !path_is_empty(RARCH_PATH_CONFIG)) { fill_pathname_resolve_relative(buf, path_get(RARCH_PATH_CONFIG), file_path_str(FILE_PATH_CORE_OPTIONS_CONFIG), sizeof(buf)); options_path = buf; } runloop_ctl(RUNLOOP_CTL_UNSET_GAME_OPTIONS_ACTIVE, NULL); if (!string_is_empty(options_path)) runloop_core_options = core_option_manager_new(options_path, vars); } } break; case RUNLOOP_CTL_CORE_OPTIONS_FREE: if (runloop_core_options) core_option_manager_free(runloop_core_options); runloop_core_options = NULL; break; case RUNLOOP_CTL_CORE_OPTIONS_DEINIT: { if (!runloop_core_options) return false; /* check if game options file was just created and flush to that file instead */ if(!path_is_empty(RARCH_PATH_CORE_OPTIONS)) { core_option_manager_flush_game_specific(runloop_core_options, path_get(RARCH_PATH_CORE_OPTIONS)); path_clear(RARCH_PATH_CORE_OPTIONS); } else core_option_manager_flush(runloop_core_options); if (runloop_ctl(RUNLOOP_CTL_IS_GAME_OPTIONS_ACTIVE, NULL)) runloop_ctl(RUNLOOP_CTL_UNSET_GAME_OPTIONS_ACTIVE, NULL); runloop_ctl(RUNLOOP_CTL_CORE_OPTIONS_FREE, NULL); } break; case RUNLOOP_CTL_KEY_EVENT_GET: { retro_keyboard_event_t **key_event = (retro_keyboard_event_t**)data; if (!key_event) return false; *key_event = &runloop_key_event; } break; case RUNLOOP_CTL_FRONTEND_KEY_EVENT_GET: { retro_keyboard_event_t **key_event = (retro_keyboard_event_t**)data; if (!key_event) return false; *key_event = &runloop_frontend_key_event; } break; case RUNLOOP_CTL_HTTPSERVER_INIT: #if defined(HAVE_HTTPSERVER) && defined(HAVE_ZLIB) httpserver_init(8888); #endif break; case RUNLOOP_CTL_HTTPSERVER_DESTROY: #if defined(HAVE_HTTPSERVER) && defined(HAVE_ZLIB) httpserver_destroy(); #endif break; case RUNLOOP_CTL_NONE: default: break; } return true; }
/* Time to exit out of the main loop? * Reasons for exiting: * a) Shutdown environment callback was invoked. * b) Quit key was pressed. * c) Frame count exceeds or equals maximum amount of frames to run. * d) Video driver no longer alive. * e) End of BSV movie and BSV EOF exit is true. (TODO/FIXME - explain better) */ static INLINE int runloop_iterate_time_to_exit(bool quit_key_pressed) { settings_t *settings = config_get_ptr(); bool time_to_exit = runloop_shutdown_initiated; time_to_exit = time_to_exit || quit_key_pressed; time_to_exit = time_to_exit || !video_driver_is_alive(); time_to_exit = time_to_exit || bsv_movie_ctl(BSV_MOVIE_CTL_END_EOF, NULL); time_to_exit = time_to_exit || (runloop_max_frames && (*(video_driver_get_frame_count_ptr()) >= runloop_max_frames)); time_to_exit = time_to_exit || runloop_exec; if (!time_to_exit) return 1; #ifdef HAVE_MENU if (!runloop_is_quit_confirm()) { if (settings && settings->confirm_on_exit) { if (menu_dialog_is_active()) return 1; if (content_is_inited()) { if(menu_display_toggle_get_reason() != MENU_TOGGLE_REASON_USER) menu_display_toggle_set_reason(MENU_TOGGLE_REASON_MESSAGE); rarch_ctl(RARCH_CTL_MENU_RUNNING, NULL); } menu_dialog_show_message(MENU_DIALOG_QUIT_CONFIRM, MENU_ENUM_LABEL_CONFIRM_ON_EXIT); return 1; } } #endif if (runloop_exec) runloop_exec = false; if (runloop_core_shutdown_initiated && settings && settings->load_dummy_on_core_shutdown) { content_ctx_info_t content_info = {0}; if (!task_push_content_load_default( NULL, NULL, &content_info, CORE_TYPE_DUMMY, CONTENT_MODE_LOAD_NOTHING_WITH_DUMMY_CORE, NULL, NULL)) return -1; /* Loads dummy core instead of exiting RetroArch completely. * Aborts core shutdown if invoked. */ runloop_shutdown_initiated = false; runloop_core_shutdown_initiated = false; return 1; } /* Quits out of RetroArch main loop. */ return -1; }
unsigned menu_event(uint64_t input, uint64_t trigger_input) { menu_animation_ctx_delta_t delta; float delta_time; /* Used for key repeat */ static float delay_timer = 0.0f; static float delay_count = 0.0f; unsigned ret = MENU_ACTION_NOOP; static bool initial_held = true; static bool first_held = false; bool set_scroll = false; bool mouse_enabled = false; size_t new_scroll_accel = 0; menu_input_t *menu_input = NULL; settings_t *settings = config_get_ptr(); if (input) { if (!first_held) { /* don't run anything first frame, only capture held inputs * for old_input_state. */ first_held = true; delay_timer = initial_held ? 12 : 6; delay_count = 0; } if (delay_count >= delay_timer) { uint64_t input_repeat = 0; BIT32_SET(input_repeat, RETRO_DEVICE_ID_JOYPAD_UP); BIT32_SET(input_repeat, RETRO_DEVICE_ID_JOYPAD_DOWN); BIT32_SET(input_repeat, RETRO_DEVICE_ID_JOYPAD_LEFT); BIT32_SET(input_repeat, RETRO_DEVICE_ID_JOYPAD_RIGHT); BIT32_SET(input_repeat, RETRO_DEVICE_ID_JOYPAD_L); BIT32_SET(input_repeat, RETRO_DEVICE_ID_JOYPAD_R); set_scroll = true; first_held = false; trigger_input |= input & input_repeat; menu_navigation_ctl(MENU_NAVIGATION_CTL_GET_SCROLL_ACCEL, &new_scroll_accel); new_scroll_accel = MIN(new_scroll_accel + 1, 64); } initial_held = false; } else { set_scroll = true; first_held = false; initial_held = true; } if (set_scroll) menu_navigation_ctl(MENU_NAVIGATION_CTL_SET_SCROLL_ACCEL, &new_scroll_accel); menu_animation_ctl(MENU_ANIMATION_CTL_DELTA_TIME, &delta_time); delta.current = delta_time; if (menu_animation_ctl(MENU_ANIMATION_CTL_IDEAL_DELTA_TIME_GET, &delta)) delay_count += delta.ideal; if (menu_input_dialog_get_display_kb()) { if (kbd_upper) strlcpy(kbd_grid, "!@#$%^&*()QWERTYUIOPASDFGHJKL:ZXCVBNM <>?", sizeof(kbd_grid)); else strlcpy(kbd_grid, "1234567890qwertyuiopasdfghjkl:zxcvbnm ,./", sizeof(kbd_grid)); if (trigger_input & (UINT64_C(1) << RETRO_DEVICE_ID_JOYPAD_DOWN)) { if (kbd_index < 30) kbd_index = kbd_index + 10; } if (trigger_input & (UINT64_C(1) << RETRO_DEVICE_ID_JOYPAD_UP)) { if (kbd_index >= 10) kbd_index = kbd_index - 10; } if (trigger_input & (UINT64_C(1) << RETRO_DEVICE_ID_JOYPAD_RIGHT)) { if (kbd_index < 39) kbd_index = kbd_index + 1; } if (trigger_input & (UINT64_C(1) << RETRO_DEVICE_ID_JOYPAD_LEFT)) { if (kbd_index >= 1) kbd_index = kbd_index - 1; } if (trigger_input & (UINT64_C(1) << RETRO_DEVICE_ID_JOYPAD_Y)) { kbd_upper = ! kbd_upper; } if (trigger_input & (UINT64_C(1) << RETRO_DEVICE_ID_JOYPAD_A)) { input_keyboard_event(true, kbd_grid[kbd_index], kbd_grid[kbd_index], 0, RETRO_DEVICE_KEYBOARD); } if (trigger_input & (UINT64_C(1) << RETRO_DEVICE_ID_JOYPAD_B)) { input_keyboard_event(true, '\x7f', '\x7f', 0, RETRO_DEVICE_KEYBOARD); } /* send return key to close keyboard input window */ if (trigger_input & (UINT64_C(1) << RETRO_DEVICE_ID_JOYPAD_START)) input_keyboard_event(true, '\n', '\n', 0, RETRO_DEVICE_KEYBOARD); trigger_input = 0; } if (trigger_input & (UINT64_C(1) << RETRO_DEVICE_ID_JOYPAD_UP)) ret = MENU_ACTION_UP; else if (trigger_input & (UINT64_C(1) << RETRO_DEVICE_ID_JOYPAD_DOWN)) ret = MENU_ACTION_DOWN; else if (trigger_input & (UINT64_C(1) << RETRO_DEVICE_ID_JOYPAD_LEFT)) ret = MENU_ACTION_LEFT; else if (trigger_input & (UINT64_C(1) << RETRO_DEVICE_ID_JOYPAD_RIGHT)) ret = MENU_ACTION_RIGHT; else if (trigger_input & (UINT64_C(1) << settings->menu_scroll_up_btn)) ret = MENU_ACTION_SCROLL_UP; else if (trigger_input & (UINT64_C(1) << settings->menu_scroll_down_btn)) ret = MENU_ACTION_SCROLL_DOWN; else if (trigger_input & (UINT64_C(1) << settings->menu_cancel_btn)) ret = MENU_ACTION_CANCEL; else if (trigger_input & (UINT64_C(1) << settings->menu_ok_btn)) ret = MENU_ACTION_OK; else if (trigger_input & (UINT64_C(1) << settings->menu_search_btn)) ret = MENU_ACTION_SEARCH; else if (trigger_input & (UINT64_C(1) << RETRO_DEVICE_ID_JOYPAD_Y)) ret = MENU_ACTION_SCAN; else if (trigger_input & (UINT64_C(1) << settings->menu_default_btn)) ret = MENU_ACTION_START; else if (trigger_input & (UINT64_C(1) << settings->menu_info_btn)) ret = MENU_ACTION_INFO; else if (trigger_input & (UINT64_C(1) << RARCH_MENU_TOGGLE)) ret = MENU_ACTION_TOGGLE; if (menu_keyboard_key_state[RETROK_F11]) { command_event(CMD_EVENT_GRAB_MOUSE_TOGGLE, NULL); menu_keyboard_key_state[RETROK_F11] = false; } if (runloop_cmd_press(trigger_input, RARCH_QUIT_KEY)) { int should_we_quit = true; if (!runloop_is_quit_confirm()) { if (settings && settings->confirm_on_exit) { if (!menu_dialog_is_active() && content_is_inited()) { if(menu_display_toggle_get_reason() != MENU_TOGGLE_REASON_USER) menu_display_toggle_set_reason(MENU_TOGGLE_REASON_MESSAGE); rarch_ctl(RARCH_CTL_MENU_RUNNING, NULL); } menu_dialog_show_message(MENU_DIALOG_QUIT_CONFIRM, MENU_ENUM_LABEL_CONFIRM_ON_EXIT); should_we_quit = false; } if ((settings && !settings->confirm_on_exit) || should_we_quit) return MENU_ACTION_QUIT; } } mouse_enabled = settings->menu.mouse.enable; #ifdef HAVE_OVERLAY if (!mouse_enabled) mouse_enabled = !(settings->input.overlay_enable && input_overlay_is_alive(NULL)); #endif if (!(menu_input = menu_input_get_ptr())) return 0; if (!mouse_enabled) menu_input->mouse.ptr = 0; if (settings->menu.pointer.enable) menu_event_pointer(&ret); else { menu_input->pointer.x = 0; menu_input->pointer.y = 0; menu_input->pointer.dx = 0; menu_input->pointer.dy = 0; menu_input->pointer.accel = 0; menu_input->pointer.pressed[0] = false; menu_input->pointer.pressed[1] = false; menu_input->pointer.back = false; menu_input->pointer.ptr = 0; } return ret; }
bool rarch_task_push_content_load_default( const char *core_path, const char *fullpath, content_ctx_info_t *content_info, enum rarch_core_type type, enum content_mode_load mode, retro_task_callback_t cb, void *user_data) { settings_t *settings = config_get_ptr(); #ifdef HAVE_MENU switch (mode) { case CONTENT_MODE_LOAD_NOTHING_WITH_CURRENT_CORE_FROM_MENU: case CONTENT_MODE_LOAD_CONTENT_FROM_PLAYLIST_FROM_MENU: case CONTENT_MODE_LOAD_CONTENT_WITH_NEW_CORE_FROM_MENU: case CONTENT_MODE_LOAD_CONTENT_WITH_FFMPEG_CORE_FROM_MENU: case CONTENT_MODE_LOAD_CONTENT_WITH_CURRENT_CORE_FROM_MENU: case CONTENT_MODE_LOAD_CONTENT_WITH_IMAGEVIEWER_CORE_FROM_MENU: case CONTENT_MODE_LOAD_CONTENT_WITH_CURRENT_CORE_FROM_COMPANION_UI: case CONTENT_MODE_LOAD_NOTHING_WITH_DUMMY_CORE: if (content_info && !content_info->environ_get) content_info->environ_get = menu_content_environment_get; break; default: break; } #endif switch (mode) { case CONTENT_MODE_LOAD_NOTHING_WITH_DUMMY_CORE: runloop_ctl(RUNLOOP_CTL_STATE_FREE, NULL); #ifdef HAVE_MENU menu_driver_ctl(RARCH_MENU_CTL_UNSET_LOAD_NO_CONTENT, NULL); #endif runloop_ctl(RUNLOOP_CTL_DATA_DEINIT, NULL); runloop_ctl(RUNLOOP_CTL_TASK_INIT, NULL); runloop_ctl(RUNLOOP_CTL_CLEAR_CONTENT_PATH, NULL); if (!content_load_wrapper(content_info, false)) goto error; break; case CONTENT_MODE_LOAD_FROM_CLI: if (!content_load_wrapper(content_info, false)) goto error; break; case CONTENT_MODE_LOAD_NOTHING_WITH_CURRENT_CORE_FROM_MENU: runloop_ctl(RUNLOOP_CTL_CLEAR_CONTENT_PATH, NULL); #ifdef HAVE_MENU if (!content_load_wrapper(content_info, true)) goto error; #endif break; case CONTENT_MODE_LOAD_CONTENT_WITH_CURRENT_CORE_FROM_MENU: core_path = settings->path.libretro; runloop_ctl(RUNLOOP_CTL_SET_CONTENT_PATH, (void*)fullpath); runloop_ctl(RUNLOOP_CTL_SET_LIBRETRO_PATH, (void*)core_path); #ifdef HAVE_DYNAMIC command_event(CMD_EVENT_LOAD_CORE, NULL); #endif #ifdef HAVE_MENU if (!content_load_wrapper(content_info, true)) goto error; #endif break; case CONTENT_MODE_LOAD_CONTENT_WITH_CURRENT_CORE_FROM_COMPANION_UI: core_path = settings->path.libretro; runloop_ctl(RUNLOOP_CTL_SET_CONTENT_PATH, (void*)fullpath); runloop_ctl(RUNLOOP_CTL_SET_LIBRETRO_PATH, (void*)core_path); #ifdef HAVE_MENU if (!content_load_wrapper(content_info, true)) goto error; #endif break; case CONTENT_MODE_LOAD_CONTENT_WITH_FFMPEG_CORE_FROM_MENU: core_path = settings->path.libretro; /* TODO/FIXME */ runloop_ctl(RUNLOOP_CTL_SET_CONTENT_PATH, (void*)fullpath); runloop_ctl(RUNLOOP_CTL_SET_LIBRETRO_PATH, (void*)core_path); #ifdef HAVE_DYNAMIC command_event(CMD_EVENT_LOAD_CORE, NULL); #endif #ifdef HAVE_MENU if (!content_load_wrapper(content_info, true)) goto error; #endif break; case CONTENT_MODE_LOAD_CONTENT_WITH_IMAGEVIEWER_CORE_FROM_MENU: core_path = settings->path.libretro; /* TODO/FIXME */ runloop_ctl(RUNLOOP_CTL_SET_LIBRETRO_PATH, (void*)core_path); #ifdef HAVE_DYNAMIC command_event(CMD_EVENT_LOAD_CORE, NULL); #endif runloop_ctl(RUNLOOP_CTL_SET_CONTENT_PATH, (void*)fullpath); #ifdef HAVE_MENU if (!content_load_wrapper(content_info, true)) goto error; #endif break; case CONTENT_MODE_LOAD_CONTENT_WITH_NEW_CORE_FROM_MENU: runloop_ctl(RUNLOOP_CTL_SET_CONTENT_PATH, (void*)fullpath); runloop_ctl(RUNLOOP_CTL_SET_LIBRETRO_PATH, (void*)core_path); #ifdef HAVE_DYNAMIC command_event(CMD_EVENT_LOAD_CORE, NULL); #ifdef HAVE_MENU if (!content_load_wrapper(content_info, true)) goto error; #endif #else { char *fullpath = NULL; runloop_ctl(RUNLOOP_CTL_GET_CONTENT_PATH, &fullpath); command_event_cmd_exec((void*)fullpath); command_event(CMD_EVENT_QUIT, NULL); } #endif break; case CONTENT_MODE_LOAD_CONTENT_FROM_PLAYLIST_FROM_MENU: runloop_ctl(RUNLOOP_CTL_SET_LIBRETRO_PATH, (void*)core_path); #ifdef HAVE_MENU if (fullpath) menu_driver_ctl(RARCH_MENU_CTL_UNSET_LOAD_NO_CONTENT, NULL); else menu_driver_ctl(RARCH_MENU_CTL_SET_LOAD_NO_CONTENT, NULL); #endif if (!command_event_cmd_exec((void*)fullpath)) return false; command_event(CMD_EVENT_LOAD_CORE, NULL); break; case CONTENT_MODE_LOAD_NONE: break; } #ifdef HAVE_MENU if (type != CORE_TYPE_DUMMY && mode != CONTENT_MODE_LOAD_FROM_CLI) { menu_driver_ctl(RARCH_MENU_CTL_SET_PENDING_QUIT, NULL); menu_driver_ctl(RARCH_MENU_CTL_SET_PENDING_QUICK_MENU, NULL); } #endif return true; error: #ifdef HAVE_MENU switch (mode) { case CONTENT_MODE_LOAD_NOTHING_WITH_CURRENT_CORE_FROM_MENU: case CONTENT_MODE_LOAD_CONTENT_WITH_CURRENT_CORE_FROM_MENU: case CONTENT_MODE_LOAD_CONTENT_WITH_FFMPEG_CORE_FROM_MENU: case CONTENT_MODE_LOAD_CONTENT_WITH_IMAGEVIEWER_CORE_FROM_MENU: case CONTENT_MODE_LOAD_CONTENT_WITH_NEW_CORE_FROM_MENU: rarch_ctl(RARCH_CTL_MENU_RUNNING, NULL); break; default: break; } #endif return false; }
LRESULT win32_menu_loop(HWND owner, WPARAM wparam) { WPARAM mode = wparam & 0xffff; enum event_command cmd = CMD_EVENT_NONE; bool do_wm_close = false; settings_t *settings = config_get_ptr(); switch (mode) { case ID_M_LOAD_CORE: case ID_M_LOAD_CONTENT: { char win32_file[PATH_MAX_LENGTH] = {0}; wchar_t title_wide[PATH_MAX]; char title_cp[PATH_MAX]; const char *extensions = NULL; const char *title = NULL; const char *initial_dir = NULL; size_t converted = 0; switch (mode) { /* OPENFILENAME.lpstrFilter requires a null separated list of name/ext pairs terminated by a second null at the end. */ case ID_M_LOAD_CORE: extensions = "Libretro core (.dll)\0*.dll\0All Files\0*.*\0\0"; title = msg_hash_to_str(MENU_ENUM_LABEL_VALUE_CORE_LIST); initial_dir = settings->paths.directory_libretro; break; case ID_M_LOAD_CONTENT: extensions = "All Files (*.*)\0*.*\0\0"; title = msg_hash_to_str( MENU_ENUM_LABEL_VALUE_LOAD_CONTENT_LIST); initial_dir = settings->paths.directory_menu_content; break; } /* Convert UTF8 to UTF16, then back to the local code page. * This is needed for proper multi-byte string display until Unicode is fully supported. */ MultiByteToWideChar(CP_UTF8, 0, title, -1, title_wide, sizeof(title_wide) / sizeof(title_wide[0])); wcstombs(title_cp, title_wide, sizeof(title_cp) - 1); if (!win32_browser(owner, win32_file, sizeof(win32_file), extensions, title_cp, initial_dir)) break; switch (mode) { case ID_M_LOAD_CORE: rarch_ctl(RARCH_CTL_SET_LIBRETRO_PATH, win32_file); cmd = CMD_EVENT_LOAD_CORE; break; case ID_M_LOAD_CONTENT: { content_ctx_info_t content_info = {0}; path_set(RARCH_PATH_CONTENT, win32_file); do_wm_close = true; task_push_load_content_with_current_core_from_companion_ui( NULL, &content_info, CORE_TYPE_PLAIN, NULL, NULL); } break; } } break; case ID_M_RESET: cmd = CMD_EVENT_RESET; break; case ID_M_MUTE_TOGGLE: cmd = CMD_EVENT_AUDIO_MUTE_TOGGLE; break; case ID_M_MENU_TOGGLE: cmd = CMD_EVENT_MENU_TOGGLE; break; case ID_M_PAUSE_TOGGLE: cmd = CMD_EVENT_PAUSE_TOGGLE; break; case ID_M_LOAD_STATE: cmd = CMD_EVENT_LOAD_STATE; break; case ID_M_SAVE_STATE: cmd = CMD_EVENT_SAVE_STATE; break; case ID_M_DISK_CYCLE: cmd = CMD_EVENT_DISK_EJECT_TOGGLE; break; case ID_M_DISK_NEXT: cmd = CMD_EVENT_DISK_NEXT; break; case ID_M_DISK_PREV: cmd = CMD_EVENT_DISK_PREV; break; case ID_M_FULL_SCREEN: cmd = CMD_EVENT_FULLSCREEN_TOGGLE; break; #ifndef _XBOX case ID_M_SHADER_PARAMETERS: shader_dlg_show(owner); break; #endif case ID_M_MOUSE_GRAB: cmd = CMD_EVENT_GRAB_MOUSE_TOGGLE; break; case ID_M_TAKE_SCREENSHOT: cmd = CMD_EVENT_TAKE_SCREENSHOT; break; case ID_M_QUIT: do_wm_close = true; break; default: if (mode >= ID_M_WINDOW_SCALE_1X && mode <= ID_M_WINDOW_SCALE_10X) { unsigned idx = (mode - (ID_M_WINDOW_SCALE_1X-1)); rarch_ctl(RARCH_CTL_SET_WINDOWED_SCALE, &idx); cmd = CMD_EVENT_RESIZE_WINDOWED_SCALE; } else if (mode == ID_M_STATE_INDEX_AUTO) { signed idx = -1; configuration_set_int(settings, settings->ints.state_slot, idx); } else if (mode >= (ID_M_STATE_INDEX_AUTO+1) && mode <= (ID_M_STATE_INDEX_AUTO+10)) { signed idx = (mode - (ID_M_STATE_INDEX_AUTO+1)); configuration_set_int(settings, settings->ints.state_slot, idx); } break; } if (cmd != CMD_EVENT_NONE) command_event(cmd, NULL); if (do_wm_close) PostMessage(owner, WM_CLOSE, 0, 0); return 0L; }
/** * event_cmd_ctl: * @cmd : Event command index. * * Performs program event command with index @cmd. * * Returns: true (1) on success, otherwise false (0). **/ bool event_cmd_ctl(enum event_command cmd, void *data) { unsigned i = 0; bool boolean = false; settings_t *settings = config_get_ptr(); rarch_system_info_t *info = NULL; runloop_ctl(RUNLOOP_CTL_SYSTEM_INFO_GET, &info); (void)i; switch (cmd) { case EVENT_CMD_MENU_REFRESH: #ifdef HAVE_MENU menu_driver_ctl(RARCH_MENU_CTL_REFRESH, NULL); #endif break; case EVENT_CMD_SET_PER_GAME_RESOLUTION: #if defined(GEKKO) { unsigned width = 0, height = 0; event_cmd_ctl(EVENT_CMD_VIDEO_SET_ASPECT_RATIO, NULL); if (video_driver_get_video_output_size(&width, &height)) { char msg[128] = {0}; video_driver_set_video_mode(width, height, true); if (width == 0 || height == 0) strlcpy(msg, "Resolution: DEFAULT", sizeof(msg)); else snprintf(msg, sizeof(msg),"Resolution: %dx%d",width, height); runloop_msg_queue_push(msg, 1, 100, true); } } #endif break; case EVENT_CMD_LOAD_CONTENT_PERSIST: #ifdef HAVE_DYNAMIC event_cmd_ctl(EVENT_CMD_LOAD_CORE, NULL); #endif rarch_ctl(RARCH_CTL_LOAD_CONTENT, NULL); break; #ifdef HAVE_FFMPEG case EVENT_CMD_LOAD_CONTENT_FFMPEG: rarch_ctl(RARCH_CTL_LOAD_CONTENT_FFMPEG, NULL); break; #endif case EVENT_CMD_LOAD_CONTENT_IMAGEVIEWER: rarch_ctl(RARCH_CTL_LOAD_CONTENT_IMAGEVIEWER, NULL); break; case EVENT_CMD_LOAD_CONTENT: { #ifdef HAVE_DYNAMIC event_cmd_ctl(EVENT_CMD_LOAD_CONTENT_PERSIST, NULL); #else char *fullpath = NULL; runloop_ctl(RUNLOOP_CTL_GET_CONTENT_PATH, &fullpath); runloop_ctl(RUNLOOP_CTL_SET_LIBRETRO_PATH, settings->libretro); event_cmd_ctl(EVENT_CMD_EXEC, (void*)fullpath); event_cmd_ctl(EVENT_CMD_QUIT, NULL); #endif } break; case EVENT_CMD_LOAD_CORE_DEINIT: #ifdef HAVE_MENU menu_driver_ctl(RARCH_MENU_CTL_SYSTEM_INFO_DEINIT, NULL); #endif break; case EVENT_CMD_LOAD_CORE_PERSIST: event_cmd_ctl(EVENT_CMD_LOAD_CORE_DEINIT, NULL); { #ifdef HAVE_MENU bool *ptr = NULL; struct retro_system_info *system = NULL; menu_driver_ctl(RARCH_MENU_CTL_SYSTEM_INFO_GET, &system); if (menu_driver_ctl(RARCH_MENU_CTL_LOAD_NO_CONTENT_GET, &ptr)) { core_info_ctx_find_t info_find; #if defined(HAVE_DYNAMIC) if (!(*settings->libretro)) return false; libretro_get_system_info(settings->libretro, system, ptr); #endif info_find.path = settings->libretro; if (!core_info_ctl(CORE_INFO_CTL_LOAD, &info_find)) return false; } #endif } break; case EVENT_CMD_LOAD_CORE: event_cmd_ctl(EVENT_CMD_LOAD_CORE_PERSIST, NULL); #ifndef HAVE_DYNAMIC event_cmd_ctl(EVENT_CMD_QUIT, NULL); #endif break; case EVENT_CMD_LOAD_STATE: /* Immutable - disallow savestate load when * we absolutely cannot change game state. */ if (bsv_movie_ctl(BSV_MOVIE_CTL_IS_INITED, NULL)) return false; #ifdef HAVE_NETPLAY if (netplay_driver_ctl(RARCH_NETPLAY_CTL_IS_DATA_INITED, NULL)) return false; #endif #ifdef HAVE_CHEEVOS if (settings->cheevos.hardcore_mode_enable) return false; #endif event_main_state(cmd); break; case EVENT_CMD_RESIZE_WINDOWED_SCALE: { unsigned idx = 0; unsigned *window_scale = NULL; runloop_ctl(RUNLOOP_CTL_GET_WINDOWED_SCALE, &window_scale); if (*window_scale == 0) return false; settings->video.scale = *window_scale; if (!settings->video.fullscreen) event_cmd_ctl(EVENT_CMD_REINIT, NULL); runloop_ctl(RUNLOOP_CTL_SET_WINDOWED_SCALE, &idx); } break; case EVENT_CMD_MENU_TOGGLE: #ifdef HAVE_MENU if (menu_driver_ctl(RARCH_MENU_CTL_IS_ALIVE, NULL)) rarch_ctl(RARCH_CTL_MENU_RUNNING_FINISHED, NULL); else rarch_ctl(RARCH_CTL_MENU_RUNNING, NULL); #endif break; case EVENT_CMD_CONTROLLERS_INIT: event_init_controllers(); break; case EVENT_CMD_RESET: RARCH_LOG("%s.\n", msg_hash_to_str(MSG_RESET)); runloop_msg_queue_push(msg_hash_to_str(MSG_RESET), 1, 120, true); #ifdef HAVE_CHEEVOS cheevos_ctl(CHEEVOS_CTL_SET_CHEATS, NULL); #endif core_ctl(CORE_CTL_RETRO_RESET, NULL); break; case EVENT_CMD_SAVE_STATE: #ifdef HAVE_CHEEVOS if (settings->cheevos.hardcore_mode_enable) return false; #endif if (settings->savestate_auto_index) settings->state_slot++; event_main_state(cmd); break; case EVENT_CMD_SAVE_STATE_DECREMENT: /* Slot -1 is (auto) slot. */ if (settings->state_slot >= 0) settings->state_slot--; break; case EVENT_CMD_SAVE_STATE_INCREMENT: settings->state_slot++; break; case EVENT_CMD_TAKE_SCREENSHOT: if (!take_screenshot()) return false; break; case EVENT_CMD_UNLOAD_CORE: runloop_ctl(RUNLOOP_CTL_PREPARE_DUMMY, NULL); event_cmd_ctl(EVENT_CMD_LOAD_CORE_DEINIT, NULL); break; case EVENT_CMD_QUIT: rarch_ctl(RARCH_CTL_QUIT, NULL); break; case EVENT_CMD_CHEEVOS_HARDCORE_MODE_TOGGLE: #ifdef HAVE_CHEEVOS cheevos_ctl(CHEEVOS_CTL_TOGGLE_HARDCORE_MODE, NULL); #endif break; case EVENT_CMD_REINIT: { struct retro_hw_render_callback *hwr = NULL; video_driver_ctl(RARCH_DISPLAY_CTL_HW_CONTEXT_GET, &hwr); if (hwr->cache_context) video_driver_ctl( RARCH_DISPLAY_CTL_SET_VIDEO_CACHE_CONTEXT, NULL); else video_driver_ctl( RARCH_DISPLAY_CTL_UNSET_VIDEO_CACHE_CONTEXT, NULL); video_driver_ctl( RARCH_DISPLAY_CTL_UNSET_VIDEO_CACHE_CONTEXT_ACK, NULL); event_cmd_ctl(EVENT_CMD_RESET_CONTEXT, NULL); video_driver_ctl( RARCH_DISPLAY_CTL_UNSET_VIDEO_CACHE_CONTEXT, NULL); /* Poll input to avoid possibly stale data to corrupt things. */ input_driver_ctl(RARCH_INPUT_CTL_POLL, NULL); #ifdef HAVE_MENU menu_display_ctl( MENU_DISPLAY_CTL_SET_FRAMEBUFFER_DIRTY_FLAG, NULL); if (menu_driver_ctl(RARCH_MENU_CTL_IS_ALIVE, NULL)) event_cmd_ctl(EVENT_CMD_VIDEO_SET_BLOCKING_STATE, NULL); #endif } break; case EVENT_CMD_CHEATS_DEINIT: cheat_manager_state_free(); break; case EVENT_CMD_CHEATS_INIT: event_cmd_ctl(EVENT_CMD_CHEATS_DEINIT, NULL); event_init_cheats(); break; case EVENT_CMD_CHEATS_APPLY: cheat_manager_apply_cheats(); break; case EVENT_CMD_REWIND_DEINIT: #ifdef HAVE_NETPLAY if (netplay_driver_ctl(RARCH_NETPLAY_CTL_IS_DATA_INITED, NULL)) return false; #endif #ifdef HAVE_CHEEVOS if (settings->cheevos.hardcore_mode_enable) return false; #endif state_manager_event_deinit(); break; case EVENT_CMD_REWIND_INIT: #ifdef HAVE_CHEEVOS if (settings->cheevos.hardcore_mode_enable) return false; #endif #ifdef HAVE_NETPLAY if (!netplay_driver_ctl(RARCH_NETPLAY_CTL_IS_DATA_INITED, NULL)) #endif init_rewind(); break; case EVENT_CMD_REWIND_TOGGLE: if (settings->rewind_enable) event_cmd_ctl(EVENT_CMD_REWIND_INIT, NULL); else event_cmd_ctl(EVENT_CMD_REWIND_DEINIT, NULL); break; case EVENT_CMD_AUTOSAVE_DEINIT: #ifdef HAVE_THREADS autosave_event_deinit(); #endif break; case EVENT_CMD_AUTOSAVE_INIT: event_cmd_ctl(EVENT_CMD_AUTOSAVE_DEINIT, NULL); #ifdef HAVE_THREADS autosave_event_init(); #endif break; case EVENT_CMD_AUTOSAVE_STATE: event_save_auto_state(); break; case EVENT_CMD_AUDIO_STOP: if (!audio_driver_ctl(RARCH_AUDIO_CTL_ALIVE, NULL)) return false; if (!audio_driver_ctl(RARCH_AUDIO_CTL_STOP, NULL)) return false; break; case EVENT_CMD_AUDIO_START: if (audio_driver_ctl(RARCH_AUDIO_CTL_ALIVE, NULL)) return false; if (!settings->audio.mute_enable && !audio_driver_ctl(RARCH_AUDIO_CTL_START, NULL)) { RARCH_ERR("Failed to start audio driver. " "Will continue without audio.\n"); audio_driver_ctl(RARCH_AUDIO_CTL_UNSET_ACTIVE, NULL); } break; case EVENT_CMD_AUDIO_MUTE_TOGGLE: { const char *msg = !settings->audio.mute_enable ? msg_hash_to_str(MSG_AUDIO_MUTED): msg_hash_to_str(MSG_AUDIO_UNMUTED); if (!audio_driver_ctl(RARCH_AUDIO_CTL_MUTE_TOGGLE, NULL)) { RARCH_ERR("%s.\n", msg_hash_to_str(MSG_FAILED_TO_UNMUTE_AUDIO)); return false; } runloop_msg_queue_push(msg, 1, 180, true); RARCH_LOG("%s\n", msg); } break; case EVENT_CMD_OVERLAY_DEINIT: #ifdef HAVE_OVERLAY input_overlay_free(); #endif break; case EVENT_CMD_OVERLAY_INIT: event_cmd_ctl(EVENT_CMD_OVERLAY_DEINIT, NULL); #ifdef HAVE_OVERLAY input_overlay_init(); #endif break; case EVENT_CMD_OVERLAY_NEXT: #ifdef HAVE_OVERLAY input_overlay_next(settings->input.overlay_opacity); #endif break; case EVENT_CMD_DSP_FILTER_DEINIT: audio_driver_dsp_filter_free(); break; case EVENT_CMD_DSP_FILTER_INIT: event_cmd_ctl(EVENT_CMD_DSP_FILTER_DEINIT, NULL); if (!*settings->audio.dsp_plugin) break; audio_driver_dsp_filter_init(settings->audio.dsp_plugin); break; case EVENT_CMD_GPU_RECORD_DEINIT: video_driver_ctl(RARCH_DISPLAY_CTL_GPU_RECORD_DEINIT, NULL); break; case EVENT_CMD_RECORD_DEINIT: if (!recording_deinit()) return false; break; case EVENT_CMD_RECORD_INIT: event_cmd_ctl(EVENT_CMD_HISTORY_DEINIT, NULL); if (!recording_init()) return false; break; case EVENT_CMD_HISTORY_DEINIT: if (g_defaults.history) { content_playlist_write_file(g_defaults.history); content_playlist_free(g_defaults.history); } g_defaults.history = NULL; break; case EVENT_CMD_HISTORY_INIT: event_cmd_ctl(EVENT_CMD_HISTORY_DEINIT, NULL); if (!settings->history_list_enable) return false; RARCH_LOG("%s: [%s].\n", msg_hash_to_str(MSG_LOADING_HISTORY_FILE), settings->content_history_path); g_defaults.history = content_playlist_init( settings->content_history_path, settings->content_history_size); break; case EVENT_CMD_CORE_INFO_DEINIT: core_info_ctl(CORE_INFO_CTL_LIST_DEINIT, NULL); break; case EVENT_CMD_CORE_INFO_INIT: event_cmd_ctl(EVENT_CMD_CORE_INFO_DEINIT, NULL); if (*settings->libretro_directory) core_info_ctl(CORE_INFO_CTL_LIST_INIT, NULL); break; case EVENT_CMD_CORE_DEINIT: { struct retro_hw_render_callback *hwr = NULL; video_driver_ctl(RARCH_DISPLAY_CTL_HW_CONTEXT_GET, &hwr); event_deinit_core(true); if (hwr) memset(hwr, 0, sizeof(*hwr)); break; } case EVENT_CMD_CORE_INIT: if (!event_init_core(data)) return false; break; case EVENT_CMD_VIDEO_APPLY_STATE_CHANGES: video_driver_ctl(RARCH_DISPLAY_CTL_APPLY_STATE_CHANGES, NULL); break; case EVENT_CMD_VIDEO_SET_NONBLOCKING_STATE: boolean = true; /* fall-through */ case EVENT_CMD_VIDEO_SET_BLOCKING_STATE: video_driver_ctl(RARCH_DISPLAY_CTL_SET_NONBLOCK_STATE, &boolean); break; case EVENT_CMD_VIDEO_SET_ASPECT_RATIO: video_driver_ctl(RARCH_DISPLAY_CTL_SET_ASPECT_RATIO, NULL); break; case EVENT_CMD_AUDIO_SET_NONBLOCKING_STATE: boolean = true; /* fall-through */ case EVENT_CMD_AUDIO_SET_BLOCKING_STATE: audio_driver_set_nonblocking_state(boolean); break; case EVENT_CMD_OVERLAY_SET_SCALE_FACTOR: #ifdef HAVE_OVERLAY input_overlay_set_scale_factor(settings->input.overlay_scale); #endif break; case EVENT_CMD_OVERLAY_SET_ALPHA_MOD: #ifdef HAVE_OVERLAY input_overlay_set_alpha_mod(settings->input.overlay_opacity); #endif break; case EVENT_CMD_AUDIO_REINIT: { int flags = DRIVER_AUDIO; driver_ctl(RARCH_DRIVER_CTL_UNINIT, &flags); driver_ctl(RARCH_DRIVER_CTL_INIT, &flags); } break; case EVENT_CMD_RESET_CONTEXT: { /* RARCH_DRIVER_CTL_UNINIT clears the callback struct so we * need to make sure to keep a copy */ struct retro_hw_render_callback *hwr = NULL; struct retro_hw_render_callback hwr_copy; int flags = DRIVERS_CMD_ALL; video_driver_ctl(RARCH_DISPLAY_CTL_HW_CONTEXT_GET, &hwr); memcpy(&hwr_copy, hwr, sizeof(hwr_copy)); driver_ctl(RARCH_DRIVER_CTL_UNINIT, &flags); memcpy(hwr, &hwr_copy, sizeof(*hwr)); driver_ctl(RARCH_DRIVER_CTL_INIT, &flags); } break; case EVENT_CMD_QUIT_RETROARCH: rarch_ctl(RARCH_CTL_FORCE_QUIT, NULL); break; case EVENT_CMD_SHUTDOWN: #if defined(__linux__) && !defined(ANDROID) runloop_msg_queue_push("Shutting down...", 1, 180, true); rarch_ctl(RARCH_CTL_FORCE_QUIT, NULL); system("shutdown -P now"); #endif break; case EVENT_CMD_REBOOT: #if defined(__linux__) && !defined(ANDROID) runloop_msg_queue_push("Rebooting...", 1, 180, true); rarch_ctl(RARCH_CTL_FORCE_QUIT, NULL); system("shutdown -r now"); #endif break; case EVENT_CMD_RESUME: rarch_ctl(RARCH_CTL_MENU_RUNNING_FINISHED, NULL); if (ui_companion_is_on_foreground()) ui_companion_driver_toggle(); break; case EVENT_CMD_RESTART_RETROARCH: if (!frontend_driver_set_fork(FRONTEND_FORK_RESTART)) return false; break; case EVENT_CMD_MENU_SAVE_CURRENT_CONFIG: event_save_current_config(); break; case EVENT_CMD_MENU_SAVE_CONFIG: if (!event_save_core_config()) return false; break; case EVENT_CMD_SHADERS_APPLY_CHANGES: #ifdef HAVE_MENU menu_shader_manager_apply_changes(); #endif break; case EVENT_CMD_PAUSE_CHECKS: if (runloop_ctl(RUNLOOP_CTL_IS_PAUSED, NULL)) { RARCH_LOG("%s\n", msg_hash_to_str(MSG_PAUSED)); event_cmd_ctl(EVENT_CMD_AUDIO_STOP, NULL); if (settings->video.black_frame_insertion) video_driver_ctl(RARCH_DISPLAY_CTL_CACHED_FRAME_RENDER, NULL); } else { RARCH_LOG("%s\n", msg_hash_to_str(MSG_UNPAUSED)); event_cmd_ctl(EVENT_CMD_AUDIO_START, NULL); } break; case EVENT_CMD_PAUSE_TOGGLE: boolean = runloop_ctl(RUNLOOP_CTL_IS_PAUSED, NULL); boolean = !boolean; runloop_ctl(RUNLOOP_CTL_SET_PAUSED, &boolean); event_cmd_ctl(EVENT_CMD_PAUSE_CHECKS, NULL); break; case EVENT_CMD_UNPAUSE: boolean = false; runloop_ctl(RUNLOOP_CTL_SET_PAUSED, &boolean); event_cmd_ctl(EVENT_CMD_PAUSE_CHECKS, NULL); break; case EVENT_CMD_PAUSE: boolean = true; runloop_ctl(RUNLOOP_CTL_SET_PAUSED, &boolean); event_cmd_ctl(EVENT_CMD_PAUSE_CHECKS, NULL); break; case EVENT_CMD_MENU_PAUSE_LIBRETRO: #ifdef HAVE_MENU if (menu_driver_ctl(RARCH_MENU_CTL_IS_ALIVE, NULL)) { if (settings->menu.pause_libretro) event_cmd_ctl(EVENT_CMD_AUDIO_STOP, NULL); else event_cmd_ctl(EVENT_CMD_AUDIO_START, NULL); } else { if (settings->menu.pause_libretro) event_cmd_ctl(EVENT_CMD_AUDIO_START, NULL); } #endif break; case EVENT_CMD_SHADER_DIR_DEINIT: runloop_ctl(RUNLOOP_CTL_SHADER_DIR_DEINIT, NULL); break; case EVENT_CMD_SHADER_DIR_INIT: event_cmd_ctl(EVENT_CMD_SHADER_DIR_DEINIT, NULL); if (!runloop_ctl(RUNLOOP_CTL_SHADER_DIR_INIT, NULL)) return false; break; case EVENT_CMD_SAVEFILES: { global_t *global = global_get_ptr(); if (!global->savefiles || !global->sram.use) return false; for (i = 0; i < global->savefiles->size; i++) { ram_type_t ram; ram.type = global->savefiles->elems[i].attr.i; ram.path = global->savefiles->elems[i].data; RARCH_LOG("%s #%u %s \"%s\".\n", msg_hash_to_str(MSG_SAVING_RAM_TYPE), ram.type, msg_hash_to_str(MSG_TO), ram.path); content_ctl(CONTENT_CTL_SAVE_RAM_FILE, &ram); } } return true; case EVENT_CMD_SAVEFILES_DEINIT: { global_t *global = global_get_ptr(); if (!global) break; if (global->savefiles) string_list_free(global->savefiles); global->savefiles = NULL; } break; case EVENT_CMD_SAVEFILES_INIT: { global_t *global = global_get_ptr(); global->sram.use = global->sram.use && !global->sram.save_disable; #ifdef HAVE_NETPLAY global->sram.use = global->sram.use && (!netplay_driver_ctl(RARCH_NETPLAY_CTL_IS_DATA_INITED, NULL) || !global->netplay.is_client); #endif if (!global->sram.use) RARCH_LOG("%s\n", msg_hash_to_str(MSG_SRAM_WILL_NOT_BE_SAVED)); if (global->sram.use) event_cmd_ctl(EVENT_CMD_AUTOSAVE_INIT, NULL); } break; case EVENT_CMD_BSV_MOVIE_DEINIT: bsv_movie_ctl(BSV_MOVIE_CTL_DEINIT, NULL); break; case EVENT_CMD_BSV_MOVIE_INIT: event_cmd_ctl(EVENT_CMD_BSV_MOVIE_DEINIT, NULL); bsv_movie_ctl(BSV_MOVIE_CTL_INIT, NULL); break; case EVENT_CMD_NETPLAY_DEINIT: #ifdef HAVE_NETPLAY deinit_netplay(); #endif break; case EVENT_CMD_NETWORK_DEINIT: #ifdef HAVE_NETWORKING network_deinit(); #endif break; case EVENT_CMD_NETWORK_INIT: #ifdef HAVE_NETWORKING network_init(); #endif break; case EVENT_CMD_NETPLAY_INIT: event_cmd_ctl(EVENT_CMD_NETPLAY_DEINIT, NULL); #ifdef HAVE_NETPLAY if (!init_netplay()) return false; #endif break; case EVENT_CMD_NETPLAY_FLIP_PLAYERS: #ifdef HAVE_NETPLAY netplay_driver_ctl(RARCH_NETPLAY_CTL_FLIP_PLAYERS, NULL); #endif break; case EVENT_CMD_FULLSCREEN_TOGGLE: if (!video_driver_ctl(RARCH_DISPLAY_CTL_HAS_WINDOWED, NULL)) return false; /* If we go fullscreen we drop all drivers and * reinitialize to be safe. */ settings->video.fullscreen = !settings->video.fullscreen; event_cmd_ctl(EVENT_CMD_REINIT, NULL); break; case EVENT_CMD_COMMAND_DEINIT: input_driver_ctl(RARCH_INPUT_CTL_COMMAND_DEINIT, NULL); break; case EVENT_CMD_COMMAND_INIT: event_cmd_ctl(EVENT_CMD_COMMAND_DEINIT, NULL); input_driver_ctl(RARCH_INPUT_CTL_COMMAND_INIT, NULL); break; case EVENT_CMD_REMOTE_DEINIT: input_driver_ctl(RARCH_INPUT_CTL_REMOTE_DEINIT, NULL); break; case EVENT_CMD_REMOTE_INIT: event_cmd_ctl(EVENT_CMD_REMOTE_DEINIT, NULL); input_driver_ctl(RARCH_INPUT_CTL_REMOTE_INIT, NULL); break; case EVENT_CMD_TEMPORARY_CONTENT_DEINIT: content_ctl(CONTENT_CTL_DEINIT, NULL); break; case EVENT_CMD_SUBSYSTEM_FULLPATHS_DEINIT: { global_t *global = global_get_ptr(); if (!global) break; if (global->subsystem_fullpaths) string_list_free(global->subsystem_fullpaths); global->subsystem_fullpaths = NULL; } break; case EVENT_CMD_LOG_FILE_DEINIT: retro_main_log_file_deinit(); break; case EVENT_CMD_DISK_APPEND_IMAGE: { const char *path = (const char*)data; if (string_is_empty(path)) return false; return event_disk_control_append_image(path); } case EVENT_CMD_DISK_EJECT_TOGGLE: if (info && info->disk_control_cb.get_num_images) { const struct retro_disk_control_callback *control = (const struct retro_disk_control_callback*) &info->disk_control_cb; if (control) { bool new_state = !control->get_eject_state(); event_disk_control_set_eject(new_state, true); } } else runloop_msg_queue_push( msg_hash_to_str(MSG_CORE_DOES_NOT_SUPPORT_DISK_OPTIONS), 1, 120, true); break; case EVENT_CMD_DISK_NEXT: if (info && info->disk_control_cb.get_num_images) { const struct retro_disk_control_callback *control = (const struct retro_disk_control_callback*) &info->disk_control_cb; if (!control) return false; if (!control->get_eject_state()) return false; event_check_disk_next(control); } else runloop_msg_queue_push( msg_hash_to_str(MSG_CORE_DOES_NOT_SUPPORT_DISK_OPTIONS), 1, 120, true); break; case EVENT_CMD_DISK_PREV: if (info && info->disk_control_cb.get_num_images) { const struct retro_disk_control_callback *control = (const struct retro_disk_control_callback*) &info->disk_control_cb; if (!control) return false; if (!control->get_eject_state()) return false; event_check_disk_prev(control); } else runloop_msg_queue_push( msg_hash_to_str(MSG_CORE_DOES_NOT_SUPPORT_DISK_OPTIONS), 1, 120, true); break; case EVENT_CMD_RUMBLE_STOP: for (i = 0; i < MAX_USERS; i++) { input_driver_set_rumble_state(i, RETRO_RUMBLE_STRONG, 0); input_driver_set_rumble_state(i, RETRO_RUMBLE_WEAK, 0); } break; case EVENT_CMD_GRAB_MOUSE_TOGGLE: { bool ret = false; static bool grab_mouse_state = false; grab_mouse_state = !grab_mouse_state; if (grab_mouse_state) ret = input_driver_ctl(RARCH_INPUT_CTL_GRAB_MOUSE, NULL); else ret = input_driver_ctl(RARCH_INPUT_CTL_UNGRAB_MOUSE, NULL); if (!ret) return false; RARCH_LOG("%s: %s.\n", msg_hash_to_str(MSG_GRAB_MOUSE_STATE), grab_mouse_state ? "yes" : "no"); if (grab_mouse_state) video_driver_ctl(RARCH_DISPLAY_CTL_HIDE_MOUSE, NULL); else video_driver_ctl(RARCH_DISPLAY_CTL_SHOW_MOUSE, NULL); } break; case EVENT_CMD_PERFCNT_REPORT_FRONTEND_LOG: rarch_perf_log(); break; case EVENT_CMD_VOLUME_UP: event_set_volume(0.5f); break; case EVENT_CMD_VOLUME_DOWN: event_set_volume(-0.5f); break; case EVENT_CMD_SET_FRAME_LIMIT: runloop_ctl(RUNLOOP_CTL_SET_FRAME_LIMIT, NULL); break; case EVENT_CMD_EXEC: return event_cmd_exec(data); case EVENT_CMD_NONE: default: return false; } return true; }
bool runloop_ctl(enum runloop_ctl_state state, void *data) { static rarch_dir_list_t runloop_shader_dir; static char runloop_fullpath[PATH_MAX_LENGTH]; static rarch_system_info_t runloop_system; static unsigned runloop_pending_windowed_scale; static retro_keyboard_event_t runloop_key_event = NULL; static unsigned runloop_max_frames = false; static bool runloop_frame_time_last = false; static bool runloop_set_frame_limit = false; static bool runloop_paused = false; static bool runloop_idle = false; static bool runloop_exec = false; static bool runloop_slowmotion = false; static bool runloop_shutdown_initiated = false; static bool runloop_core_shutdown_initiated = false; static bool runloop_perfcnt_enable = false; static bool runloop_overrides_active = false; static bool runloop_game_options_active = false; #ifdef HAVE_THREADS static slock_t *runloop_msg_queue_lock = NULL; #endif static core_info_t *core_info_current = NULL; static core_info_list_t *core_info_curr_list = NULL; settings_t *settings = config_get_ptr(); switch (state) { case RUNLOOP_CTL_DATA_ITERATE: rarch_task_check(); return true; case RUNLOOP_CTL_SHADER_DIR_DEINIT: shader_dir_free(&runloop_shader_dir); return true; case RUNLOOP_CTL_SHADER_DIR_INIT: return shader_dir_init(&runloop_shader_dir); case RUNLOOP_CTL_SYSTEM_INFO_INIT: core.retro_get_system_info(&runloop_system.info); if (!runloop_system.info.library_name) runloop_system.info.library_name = msg_hash_to_str(MSG_UNKNOWN); if (!runloop_system.info.library_version) runloop_system.info.library_version = "v0"; #ifndef RARCH_CONSOLE strlcpy(runloop_system.title_buf, msg_hash_to_str(MSG_PROGRAM), sizeof(runloop_system.title_buf)); strlcat(runloop_system.title_buf, " : ", sizeof(runloop_system.title_buf)); #endif strlcat(runloop_system.title_buf, runloop_system.info.library_name, sizeof(runloop_system.title_buf)); strlcat(runloop_system.title_buf, " ", sizeof(runloop_system.title_buf)); strlcat(runloop_system.title_buf, runloop_system.info.library_version, sizeof(runloop_system.title_buf)); strlcpy(runloop_system.valid_extensions, runloop_system.info.valid_extensions ? runloop_system.info.valid_extensions : DEFAULT_EXT, sizeof(runloop_system.valid_extensions)); runloop_system.block_extract = runloop_system.info.block_extract; break; case RUNLOOP_CTL_GET_CORE_OPTION_SIZE: { unsigned *idx = (unsigned*)data; if (!idx) return false; *idx = core_option_size(runloop_system.core_options); } return true; case RUNLOOP_CTL_HAS_CORE_OPTIONS: return runloop_system.core_options; case RUNLOOP_CTL_CURRENT_CORE_LIST_FREE: if (core_info_curr_list) core_info_list_free(core_info_curr_list); core_info_curr_list = NULL; return true; case RUNLOOP_CTL_CURRENT_CORE_LIST_INIT: core_info_curr_list = core_info_list_new(); return true; case RUNLOOP_CTL_CURRENT_CORE_LIST_GET: { core_info_list_t **core = (core_info_list_t**)data; if (!core) return false; *core = core_info_curr_list; } return true; case RUNLOOP_CTL_CURRENT_CORE_FREE: if (core_info_current) free(core_info_current); core_info_current = NULL; return true; case RUNLOOP_CTL_CURRENT_CORE_INIT: core_info_current = (core_info_t*)calloc(1, sizeof(core_info_t)); if (!core_info_current) return false; return true; case RUNLOOP_CTL_CURRENT_CORE_GET: { core_info_t **core = (core_info_t**)data; if (!core) return false; *core = core_info_current; } return true; case RUNLOOP_CTL_SYSTEM_INFO_GET: { rarch_system_info_t **system = (rarch_system_info_t**)data; if (!system) return false; *system = &runloop_system; } return true; case RUNLOOP_CTL_SYSTEM_INFO_FREE: if (runloop_system.core_options) { core_option_flush(runloop_system.core_options); core_option_free(runloop_system.core_options); } runloop_system.core_options = NULL; /* No longer valid. */ if (runloop_system.special) free(runloop_system.special); runloop_system.special = NULL; if (runloop_system.ports) free(runloop_system.ports); runloop_system.ports = NULL; runloop_key_event = NULL; global_get_ptr()->frontend_key_event = NULL; audio_driver_unset_callback(); memset(&runloop_system, 0, sizeof(rarch_system_info_t)); break; case RUNLOOP_CTL_IS_FRAME_COUNT_END: { uint64_t *frame_count = NULL; video_driver_ctl(RARCH_DISPLAY_CTL_GET_FRAME_COUNT, &frame_count); return runloop_max_frames && (*frame_count >= runloop_max_frames); } case RUNLOOP_CTL_SET_FRAME_TIME_LAST: runloop_frame_time_last = true; break; case RUNLOOP_CTL_UNSET_FRAME_TIME_LAST: runloop_frame_time_last = false; break; case RUNLOOP_CTL_SET_OVERRIDES_ACTIVE: runloop_overrides_active = true; break; case RUNLOOP_CTL_UNSET_OVERRIDES_ACTIVE: runloop_overrides_active = false; break; case RUNLOOP_CTL_IS_OVERRIDES_ACTIVE: return runloop_overrides_active; case RUNLOOP_CTL_SET_GAME_OPTIONS_ACTIVE: runloop_game_options_active = true; break; case RUNLOOP_CTL_UNSET_GAME_OPTIONS_ACTIVE: runloop_game_options_active = false; break; case RUNLOOP_CTL_IS_GAME_OPTIONS_ACTIVE: return runloop_game_options_active; case RUNLOOP_CTL_IS_FRAME_TIME_LAST: return runloop_frame_time_last; case RUNLOOP_CTL_SET_FRAME_LIMIT: runloop_set_frame_limit = true; break; case RUNLOOP_CTL_UNSET_FRAME_LIMIT: runloop_set_frame_limit = false; break; case RUNLOOP_CTL_SHOULD_SET_FRAME_LIMIT: return runloop_set_frame_limit; case RUNLOOP_CTL_GET_PERFCNT: { bool **perfcnt = (bool**)data; if (!perfcnt) return false; *perfcnt = &runloop_perfcnt_enable; } return true; case RUNLOOP_CTL_SET_PERFCNT_ENABLE: runloop_perfcnt_enable = true; break; case RUNLOOP_CTL_UNSET_PERFCNT_ENABLE: runloop_perfcnt_enable = false; break; case RUNLOOP_CTL_IS_PERFCNT_ENABLE: return runloop_perfcnt_enable; case RUNLOOP_CTL_GET_WINDOWED_SCALE: { unsigned **scale = (unsigned**)data; if (!scale) return false; *scale = (unsigned*)&runloop_pending_windowed_scale; } break; case RUNLOOP_CTL_SET_WINDOWED_SCALE: { unsigned *idx = (unsigned*)data; if (!idx) return false; runloop_pending_windowed_scale = *idx; } break; case RUNLOOP_CTL_SET_LIBRETRO_PATH: { const char *fullpath = (const char*)data; if (!fullpath) return false; strlcpy(settings->libretro, fullpath, sizeof(settings->libretro)); } break; case RUNLOOP_CTL_CLEAR_CONTENT_PATH: *runloop_fullpath = '\0'; break; case RUNLOOP_CTL_GET_CONTENT_PATH: { char **fullpath = (char**)data; if (!fullpath) return false; *fullpath = (char*)runloop_fullpath; } break; case RUNLOOP_CTL_SET_CONTENT_PATH: { const char *fullpath = (const char*)data; if (!fullpath) return false; strlcpy(runloop_fullpath, fullpath, sizeof(runloop_fullpath)); } break; case RUNLOOP_CTL_CHECK_FOCUS: if (settings->pause_nonactive) return video_driver_ctl(RARCH_DISPLAY_CTL_IS_FOCUSED, NULL); return true; case RUNLOOP_CTL_CHECK_IDLE_STATE: { event_cmd_state_t *cmd = (event_cmd_state_t*)data; bool focused = runloop_ctl(RUNLOOP_CTL_CHECK_FOCUS, NULL); check_pause(settings, focused, runloop_cmd_triggered(cmd, RARCH_PAUSE_TOGGLE), runloop_cmd_triggered(cmd, RARCH_FRAMEADVANCE)); if (!runloop_ctl(RUNLOOP_CTL_CHECK_PAUSE_STATE, cmd) || !focused) return false; break; } case RUNLOOP_CTL_CHECK_STATE: { bool tmp = false; event_cmd_state_t *cmd = (event_cmd_state_t*)data; if (!cmd || runloop_idle) return false; if (runloop_cmd_triggered(cmd, RARCH_SCREENSHOT)) event_command(EVENT_CMD_TAKE_SCREENSHOT); if (runloop_cmd_triggered(cmd, RARCH_MUTE)) event_command(EVENT_CMD_AUDIO_MUTE_TOGGLE); if (runloop_cmd_triggered(cmd, RARCH_OSK)) { if (input_driver_ctl(RARCH_INPUT_CTL_IS_KEYBOARD_LINEFEED_ENABLED, NULL)) input_driver_ctl(RARCH_INPUT_CTL_UNSET_KEYBOARD_LINEFEED_ENABLED, NULL); else input_driver_ctl(RARCH_INPUT_CTL_SET_KEYBOARD_LINEFEED_ENABLED, NULL); } if (runloop_cmd_press(cmd, RARCH_VOLUME_UP)) event_command(EVENT_CMD_VOLUME_UP); else if (runloop_cmd_press(cmd, RARCH_VOLUME_DOWN)) event_command(EVENT_CMD_VOLUME_DOWN); #ifdef HAVE_NETPLAY tmp = runloop_cmd_triggered(cmd, RARCH_NETPLAY_FLIP); netplay_driver_ctl(RARCH_NETPLAY_CTL_FLIP_PLAYERS, &tmp); tmp = runloop_cmd_triggered(cmd, RARCH_FULLSCREEN_TOGGLE_KEY); netplay_driver_ctl(RARCH_NETPLAY_CTL_FULLSCREEN_TOGGLE, &tmp); #endif if (!runloop_ctl(RUNLOOP_CTL_CHECK_IDLE_STATE, data)) return false; check_fast_forward_button( runloop_cmd_triggered(cmd, RARCH_FAST_FORWARD_KEY), runloop_cmd_press (cmd, RARCH_FAST_FORWARD_HOLD_KEY), runloop_cmd_pressed (cmd, RARCH_FAST_FORWARD_HOLD_KEY)); check_stateslots(settings, runloop_cmd_triggered(cmd, RARCH_STATE_SLOT_PLUS), runloop_cmd_triggered(cmd, RARCH_STATE_SLOT_MINUS) ); if (runloop_cmd_triggered(cmd, RARCH_SAVE_STATE_KEY)) event_command(EVENT_CMD_SAVE_STATE); else if (runloop_cmd_triggered(cmd, RARCH_LOAD_STATE_KEY)) event_command(EVENT_CMD_LOAD_STATE); state_manager_check_rewind(runloop_cmd_press(cmd, RARCH_REWIND)); tmp = runloop_cmd_press(cmd, RARCH_SLOWMOTION); runloop_ctl(RUNLOOP_CTL_CHECK_SLOWMOTION, &tmp); if (runloop_cmd_triggered(cmd, RARCH_MOVIE_RECORD_TOGGLE)) runloop_ctl(RUNLOOP_CTL_CHECK_MOVIE, NULL); check_shader_dir(&runloop_shader_dir, runloop_cmd_triggered(cmd, RARCH_SHADER_NEXT), runloop_cmd_triggered(cmd, RARCH_SHADER_PREV)); if (runloop_cmd_triggered(cmd, RARCH_DISK_EJECT_TOGGLE)) event_command(EVENT_CMD_DISK_EJECT_TOGGLE); else if (runloop_cmd_triggered(cmd, RARCH_DISK_NEXT)) event_command(EVENT_CMD_DISK_NEXT); else if (runloop_cmd_triggered(cmd, RARCH_DISK_PREV)) event_command(EVENT_CMD_DISK_PREV); if (runloop_cmd_triggered(cmd, RARCH_RESET)) event_command(EVENT_CMD_RESET); cheat_manager_state_checks( runloop_cmd_triggered(cmd, RARCH_CHEAT_INDEX_PLUS), runloop_cmd_triggered(cmd, RARCH_CHEAT_INDEX_MINUS), runloop_cmd_triggered(cmd, RARCH_CHEAT_TOGGLE)); } break; case RUNLOOP_CTL_CHECK_PAUSE_STATE: { bool check_is_oneshot; event_cmd_state_t *cmd = (event_cmd_state_t*)data; if (!cmd) return false; check_is_oneshot = runloop_cmd_triggered(cmd, RARCH_FRAMEADVANCE) || runloop_cmd_press(cmd, RARCH_REWIND); if (!runloop_paused) return true; if (runloop_cmd_triggered(cmd, RARCH_FULLSCREEN_TOGGLE_KEY)) { event_command(EVENT_CMD_FULLSCREEN_TOGGLE); video_driver_ctl(RARCH_DISPLAY_CTL_CACHED_FRAME_RENDER, NULL); } if (!check_is_oneshot) return false; } break; case RUNLOOP_CTL_CHECK_SLOWMOTION: { bool *ptr = (bool*)data; if (!ptr) return false; runloop_slowmotion = *ptr; if (!runloop_slowmotion) return false; if (settings->video.black_frame_insertion) video_driver_ctl(RARCH_DISPLAY_CTL_CACHED_FRAME_RENDER, NULL); if (state_manager_frame_is_reversed()) runloop_msg_queue_push_new(MSG_SLOW_MOTION_REWIND, 0, 30, true); else runloop_msg_queue_push_new(MSG_SLOW_MOTION, 0, 30, true); } break; case RUNLOOP_CTL_CHECK_MOVIE: if (bsv_movie_ctl(BSV_MOVIE_CTL_PLAYBACK_ON, NULL)) return runloop_ctl(RUNLOOP_CTL_CHECK_MOVIE_PLAYBACK, NULL); if (!bsv_movie_ctl(BSV_MOVIE_CTL_IS_INITED, NULL)) return runloop_ctl(RUNLOOP_CTL_CHECK_MOVIE_INIT, NULL); return runloop_ctl(RUNLOOP_CTL_CHECK_MOVIE_RECORD, NULL); case RUNLOOP_CTL_CHECK_MOVIE_RECORD: if (!bsv_movie_ctl(BSV_MOVIE_CTL_IS_INITED, NULL)) return false; runloop_msg_queue_push_new( MSG_MOVIE_RECORD_STOPPED, 2, 180, true); RARCH_LOG("%s\n", msg_hash_to_str(MSG_MOVIE_RECORD_STOPPED)); event_command(EVENT_CMD_BSV_MOVIE_DEINIT); break; case RUNLOOP_CTL_CHECK_MOVIE_INIT: if (bsv_movie_ctl(BSV_MOVIE_CTL_IS_INITED, NULL)) return false; { char msg[128]; char path[PATH_MAX_LENGTH]; settings->rewind_granularity = 1; if (settings->state_slot > 0) snprintf(path, sizeof(path), "%s%d", bsv_movie_get_path(), settings->state_slot); else strlcpy(path, bsv_movie_get_path(), sizeof(path)); strlcat(path, ".bsv", sizeof(path)); snprintf(msg, sizeof(msg), "%s \"%s\".", msg_hash_to_str(MSG_STARTING_MOVIE_RECORD_TO), path); bsv_movie_init_handle(path, RARCH_MOVIE_RECORD); if (!bsv_movie_ctl(BSV_MOVIE_CTL_IS_INITED, NULL)) return false; else if (bsv_movie_ctl(BSV_MOVIE_CTL_IS_INITED, NULL)) { runloop_msg_queue_push(msg, 1, 180, true); RARCH_LOG("%s \"%s\".\n", msg_hash_to_str(MSG_STARTING_MOVIE_RECORD_TO), path); } else { runloop_msg_queue_push_new( MSG_FAILED_TO_START_MOVIE_RECORD, 1, 180, true); RARCH_ERR("%s\n", msg_hash_to_str(MSG_FAILED_TO_START_MOVIE_RECORD)); } } break; case RUNLOOP_CTL_CHECK_MOVIE_PLAYBACK: if (!bsv_movie_ctl(BSV_MOVIE_CTL_END, NULL)) return false; runloop_msg_queue_push_new( MSG_MOVIE_PLAYBACK_ENDED, 1, 180, false); RARCH_LOG("%s\n", msg_hash_to_str(MSG_MOVIE_PLAYBACK_ENDED)); event_command(EVENT_CMD_BSV_MOVIE_DEINIT); bsv_movie_ctl(BSV_MOVIE_CTL_UNSET_END, NULL); bsv_movie_ctl(BSV_MOVIE_CTL_UNSET_PLAYBACK, NULL); break; case RUNLOOP_CTL_STATE_FREE: runloop_perfcnt_enable = false; runloop_idle = false; runloop_paused = false; runloop_slowmotion = false; runloop_frame_time_last = false; runloop_set_frame_limit = false; runloop_overrides_active = false; runloop_max_frames = 0; break; case RUNLOOP_CTL_GLOBAL_FREE: { global_t *global; event_command(EVENT_CMD_TEMPORARY_CONTENT_DEINIT); event_command(EVENT_CMD_SUBSYSTEM_FULLPATHS_DEINIT); event_command(EVENT_CMD_RECORD_DEINIT); event_command(EVENT_CMD_LOG_FILE_DEINIT); rarch_ctl(RARCH_CTL_UNSET_BLOCK_CONFIG_READ, NULL); runloop_ctl(RUNLOOP_CTL_CLEAR_CONTENT_PATH, NULL); runloop_overrides_active = false; global = global_get_ptr(); memset(global, 0, sizeof(struct global)); } break; case RUNLOOP_CTL_CLEAR_STATE: driver_ctl(RARCH_DRIVER_CTL_DEINIT, NULL); runloop_ctl(RUNLOOP_CTL_STATE_FREE, NULL); runloop_ctl(RUNLOOP_CTL_GLOBAL_FREE, NULL); break; case RUNLOOP_CTL_SET_MAX_FRAMES: { unsigned *ptr = (unsigned*)data; if (!ptr) return false; runloop_max_frames = *ptr; } break; case RUNLOOP_CTL_IS_IDLE: return runloop_idle; case RUNLOOP_CTL_SET_IDLE: { bool *ptr = (bool*)data; if (!ptr) return false; runloop_idle = *ptr; } break; case RUNLOOP_CTL_IS_SLOWMOTION: { bool *ptr = (bool*)data; if (!ptr) return false; *ptr = runloop_slowmotion; } break; case RUNLOOP_CTL_SET_SLOWMOTION: { bool *ptr = (bool*)data; if (!ptr) return false; runloop_slowmotion = *ptr; } break; case RUNLOOP_CTL_SET_PAUSED: { bool *ptr = (bool*)data; if (!ptr) return false; runloop_paused = *ptr; } break; case RUNLOOP_CTL_IS_PAUSED: return runloop_paused; case RUNLOOP_CTL_MSG_QUEUE_FREE: #ifdef HAVE_THREADS slock_free(runloop_msg_queue_lock); runloop_msg_queue_lock = NULL; #endif break; case RUNLOOP_CTL_MSG_QUEUE_DEINIT: if (!g_msg_queue) return true; runloop_ctl(RUNLOOP_CTL_MSG_QUEUE_LOCK, NULL); msg_queue_free(g_msg_queue); runloop_ctl(RUNLOOP_CTL_MSG_QUEUE_UNLOCK, NULL); runloop_ctl(RUNLOOP_CTL_MSG_QUEUE_FREE, NULL); g_msg_queue = NULL; break; case RUNLOOP_CTL_MSG_QUEUE_INIT: runloop_ctl(RUNLOOP_CTL_MSG_QUEUE_DEINIT, NULL); g_msg_queue = msg_queue_new(8); retro_assert(g_msg_queue); #ifdef HAVE_THREADS runloop_msg_queue_lock = slock_new(); retro_assert(runloop_msg_queue_lock); #endif break; case RUNLOOP_CTL_MSG_QUEUE_LOCK: #ifdef HAVE_THREADS slock_lock(runloop_msg_queue_lock); #endif break; case RUNLOOP_CTL_MSG_QUEUE_UNLOCK: #ifdef HAVE_THREADS slock_unlock(runloop_msg_queue_lock); #endif break; case RUNLOOP_CTL_PREPARE_DUMMY: #ifdef HAVE_MENU menu_driver_ctl(RARCH_MENU_CTL_UNSET_LOAD_NO_CONTENT, NULL); #endif runloop_data_clear_state(); runloop_ctl(RUNLOOP_CTL_CLEAR_CONTENT_PATH, NULL); rarch_ctl(RARCH_CTL_LOAD_CONTENT, NULL); break; case RUNLOOP_CTL_SET_CORE_SHUTDOWN: runloop_core_shutdown_initiated = true; break; case RUNLOOP_CTL_UNSET_CORE_SHUTDOWN: runloop_core_shutdown_initiated = false; break; case RUNLOOP_CTL_IS_CORE_SHUTDOWN: return runloop_core_shutdown_initiated; case RUNLOOP_CTL_SET_SHUTDOWN: runloop_shutdown_initiated = true; break; case RUNLOOP_CTL_UNSET_SHUTDOWN: runloop_shutdown_initiated = false; break; case RUNLOOP_CTL_IS_SHUTDOWN: return runloop_shutdown_initiated; case RUNLOOP_CTL_SET_EXEC: runloop_exec = true; break; case RUNLOOP_CTL_UNSET_EXEC: runloop_exec = false; break; case RUNLOOP_CTL_IS_EXEC: return runloop_exec; case RUNLOOP_CTL_DATA_DEINIT: rarch_task_deinit(); break; case RUNLOOP_CTL_IS_CORE_OPTION_UPDATED: return runloop_system.core_options ? core_option_updated(runloop_system.core_options) : false; case RUNLOOP_CTL_CORE_OPTION_PREV: { unsigned *idx = (unsigned*)data; if (!idx) return false; core_option_prev(runloop_system.core_options, *idx); if (ui_companion_is_on_foreground()) ui_companion_driver_notify_refresh(); } return true; case RUNLOOP_CTL_CORE_OPTION_NEXT: { unsigned *idx = (unsigned*)data; if (!idx) return false; core_option_next(runloop_system.core_options, *idx); if (ui_companion_is_on_foreground()) ui_companion_driver_notify_refresh(); } return true; case RUNLOOP_CTL_CORE_OPTIONS_GET: { struct retro_variable *var = (struct retro_variable*)data; if (!runloop_system.core_options || !var) return false; RARCH_LOG("Environ GET_VARIABLE %s:\n", var->key); core_option_get(runloop_system.core_options, var); RARCH_LOG("\t%s\n", var->value ? var->value : "N/A"); } return true; case RUNLOOP_CTL_CORE_OPTIONS_INIT: { char *game_options_path = NULL; bool ret = false; const struct retro_variable *vars = (const struct retro_variable*)data; char buf[PATH_MAX_LENGTH] = {0}; global_t *global = global_get_ptr(); const char *options_path = settings->core_options_path; if (!*options_path && *global->path.config) { fill_pathname_resolve_relative(buf, global->path.config, "retroarch-core-options.cfg", sizeof(buf)); options_path = buf; } if (settings->game_specific_options) ret = rarch_game_specific_options(&game_options_path); if(ret) { runloop_ctl(RUNLOOP_CTL_SET_GAME_OPTIONS_ACTIVE, NULL); runloop_system.core_options = core_option_new(game_options_path, vars); free(game_options_path); } else { runloop_ctl(RUNLOOP_CTL_UNSET_GAME_OPTIONS_ACTIVE, NULL); runloop_system.core_options = core_option_new(options_path, vars); } } break; case RUNLOOP_CTL_CORE_OPTIONS_DEINIT: if (!runloop_system.core_options) return false; core_option_flush(runloop_system.core_options); core_option_free(runloop_system.core_options); runloop_system.core_options = NULL; return true; case RUNLOOP_CTL_KEY_EVENT_GET: { retro_keyboard_event_t **key_event = (retro_keyboard_event_t**)data; if (!key_event) return false; *key_event = &runloop_key_event; } break; case RUNLOOP_CTL_NONE: default: return false; } return true; }
static int httpserver_handle_basic_info(struct mg_connection* conn, void* cbdata) { static const char *libretro_btn_desc[] = { "B (bottom)", "Y (left)", "Select", "Start", "D-Pad Up", "D-Pad Down", "D-Pad Left", "D-Pad Right", "A (right)", "X (up)", "L", "R", "L2", "R2", "L3", "R3", }; unsigned p, q, r; retro_ctx_api_info_t api; retro_ctx_region_info_t region; retro_ctx_memory_info_t sram; retro_ctx_memory_info_t rtc; retro_ctx_memory_info_t sysram; retro_ctx_memory_info_t vram; char core_path[PATH_MAX_LENGTH] = {0}; const char* pixel_format = NULL; const struct retro_subsystem_info* subsys = NULL; const struct retro_subsystem_rom_info* rom = NULL; const struct retro_subsystem_memory_info* mem = NULL; const struct retro_controller_description* ctrl = NULL; const char* comma = NULL; const struct core_option* opts = NULL; const struct retro_system_av_info* av_info = NULL; const core_option_manager_t* core_opts = NULL; const struct mg_request_info * req = mg_get_request_info(conn); const settings_t * settings = config_get_ptr(); rarch_system_info_t *system = runloop_get_system_info(); if (string_is_empty(system->info.library_name)) return httpserver_error(conn, 500, "Core not initialized in %s", __FUNCTION__); if (!core_is_game_loaded()) return httpserver_error(conn, 500, "Game not loaded in %s", __FUNCTION__); json_string_encode(core_path, sizeof(core_path), config_get_active_core_path()); core_api_version(&api); core_get_region(®ion); switch (video_driver_get_pixel_format()) { case RETRO_PIXEL_FORMAT_0RGB1555: pixel_format = "RETRO_PIXEL_FORMAT_0RGB1555"; break; case RETRO_PIXEL_FORMAT_XRGB8888: pixel_format = "RETRO_PIXEL_FORMAT_XRGB8888"; break; case RETRO_PIXEL_FORMAT_RGB565: pixel_format = "RETRO_PIXEL_FORMAT_RGB565"; break; default: pixel_format = "?"; break; } sram.id = RETRO_MEMORY_SAVE_RAM; core_get_memory(&sram); rtc.id = RETRO_MEMORY_RTC; core_get_memory(&rtc); sysram.id = RETRO_MEMORY_SYSTEM_RAM; core_get_memory(&sysram); vram.id = RETRO_MEMORY_VIDEO_RAM; core_get_memory(&vram); mg_printf(conn, "HTTP/1.1 200 OK\r\nContent-Type: application/json\r\n\r\n" "{" "\"corePath\":\"%s\"," "\"apiVersion\":%u," "\"systemInfo\":" "{" "\"libraryName\":\"%s\"," "\"libraryVersion\":\"%s\"," "\"validExtensions\":\"%s\"," "\"needsFullpath\":%s," "\"blockExtract\":%s" "}," "\"region\":\"%s\"," "\"pixelFormat\":\"%s\"," "\"rotation\":%u," "\"performaceLevel\":%u," "\"supportsNoGame\":%s," #ifdef HAVE_CHEEVOS "\"frontendSupportsAchievements\":true," "\"coreSupportsAchievements\":%s," #else "\"frontendSupportsAchievements\":false," "\"coreSupportsAchievements\":null," #endif "\"saveRam\":{\"pointer\":\"%" PRIXPTR "\",\"size\":" STRING_REP_UINT64 "}," "\"rtcRam\":{\"pointer\":\"%" PRIXPTR "\",\"size\":" STRING_REP_UINT64 "}," "\"systemRam\":{\"pointer\":\"%" PRIXPTR "\",\"size\":" STRING_REP_UINT64 "}," "\"videoRam\":{\"pointer\":\"%" PRIXPTR "\",\"size\":" STRING_REP_UINT64 "},", core_path, api.version, system->info.library_name, system->info.library_version, system->info.valid_extensions, system->info.need_fullpath ? "true" : "false", system->info.block_extract ? "true" : "false", region.region ? "RETRO_REGION_PAL" : "RETRO_REGION_NTSC", pixel_format, system->rotation, system->performance_level, content_does_not_need_content() ? "true" : "false", #ifdef HAVE_CHEEVOS cheevos_get_support_cheevos() ? "true" : "false", #endif (uintptr_t)sram.data, sram.size, (uintptr_t)rtc.data, rtc.size, (uintptr_t)sysram.data, sysram.size, (uintptr_t)vram.data, vram.size ); mg_printf(conn, "\"subSystems\":["); subsys = system->subsystem.data; for (p = 0; p < system->subsystem.size; p++, subsys++) { mg_printf(conn, "%s{\"id\":%u,\"description\":\"%s\",\"identifier\":\"%s\",\"roms\":[", p == 0 ? "" : ",", subsys->id, subsys->desc, subsys->ident); rom = subsys->roms; for (q = 0; q < subsys->num_roms; q++, rom++) { mg_printf(conn, "%s{" "\"description\":\"%s\"," "\"extensions\":\"%s\"," "\"needsFullpath\":%s," "\"blockExtract\":%s," "\"required\":%s," "\"memory\":[", q == 0 ? "" : ",", rom->desc, rom->valid_extensions, rom->need_fullpath ? "true" : "false", rom->block_extract ? "true" : "false", rom->required ? "true" : "false" ); mem = rom->memory; comma = ""; for (r = 0; r < rom->num_memory; r++, mem++) { mg_printf(conn, "%s{\"extension\":\"%s\",\"type\":%u}", comma, mem->extension, mem->type); comma = ","; } mg_printf(conn, "]}"); } mg_printf(conn, "]}"); } av_info = video_viewport_get_system_av_info(); mg_printf(conn, "],\"avInfo\":{" "\"geometry\":{" "\"baseWidth\":%u," "\"baseHeight\":%u," "\"maxWidth\":%u," "\"maxHeight\":%u," "\"aspectRatio\":%f" "}," "\"timing\":{" "\"fps\":%f," "\"sampleRate\":%f" "}" "},", av_info->geometry.base_width, av_info->geometry.base_height, av_info->geometry.max_width, av_info->geometry.max_height, av_info->geometry.aspect_ratio, av_info->timing.fps, av_info->timing.sample_rate ); mg_printf(conn, "\"ports\":["); comma = ""; for (p = 0; p < system->ports.size; p++) { ctrl = system->ports.data[p].types; for (q = 0; q < system->ports.data[p].num_types; q++, ctrl++) { mg_printf(conn, "%s{\"id\":%u,\"description\":\"%s\"}", comma, ctrl->id, ctrl->desc); comma = ","; } } mg_printf(conn, "],\"inputDescriptors\":["); comma = ""; if (core_has_set_input_descriptor()) { for (p = 0; p < settings->input.max_users; p++) { for (q = 0; q < RARCH_FIRST_CUSTOM_BIND; q++) { const char* description = system->input_desc_btn[p][q]; if (description) { mg_printf(conn, "%s{\"player\":%u,\"button\":\"%s\",\"description\":\"%s\"}", comma, p + 1, libretro_btn_desc[q], description ); comma = ","; } } } } mg_printf(conn, "],\"coreOptions\":["); rarch_ctl(RARCH_CTL_CORE_OPTIONS_LIST_GET, (void*)&core_opts); opts = core_opts->opts; for (p = 0; p < core_opts->size; p++, opts++) { mg_printf(conn, "%s{\"key\":\"%s\",\"description\":\"%s\",\"values\":[", p == 0 ? "" : ",", opts->key, opts->desc); comma = ""; for (q = 0; q < opts->vals->size; q++) { mg_printf(conn, "%s\"%s\"", comma, opts->vals->elems[q].data); comma = ","; } mg_printf(conn, "]}"); } mg_printf(conn, "]}"); return 1; }
/** * runloop_iterate: * * Run Libretro core in RetroArch for one frame. * * Returns: 0 on success, 1 if we have to wait until button input in order * to wake up the loop, -1 if we forcibly quit out of the RetroArch iteration loop. **/ int runloop_iterate(unsigned *sleep_ms) { unsigned i; event_cmd_state_t cmd; event_cmd_state_t *cmd_ptr = &cmd; retro_time_t current, target, to_sleep_ms; static retro_usec_t frame_time_last = 0; static retro_time_t frame_limit_minimum_time = 0.0; static retro_time_t frame_limit_last_time = 0.0; static retro_input_t last_input = 0; settings_t *settings = config_get_ptr(); global_t *global = global_get_ptr(); rarch_system_info_t *system = NULL; cmd.state[1] = last_input; cmd.state[0] = input_keys_pressed(); last_input = cmd.state[0]; runloop_ctl(RUNLOOP_CTL_SYSTEM_INFO_GET, &system); if (runloop_ctl(RUNLOOP_CTL_IS_FRAME_TIME_LAST, NULL)) { frame_time_last = 0; runloop_ctl(RUNLOOP_CTL_UNSET_FRAME_TIME_LAST, NULL); } if (runloop_ctl(RUNLOOP_CTL_SHOULD_SET_FRAME_LIMIT, NULL)) { struct retro_system_av_info *av_info = video_viewport_get_system_av_info(); float fastforward_ratio = (settings->fastforward_ratio == 0.0f) ? 1.0f : settings->fastforward_ratio; frame_limit_last_time = retro_get_time_usec(); frame_limit_minimum_time = (retro_time_t)roundf(1000000.0f / (av_info->timing.fps * fastforward_ratio)); runloop_ctl(RUNLOOP_CTL_UNSET_FRAME_LIMIT, NULL); } if (input_driver_ctl(RARCH_INPUT_CTL_IS_FLUSHING_INPUT, NULL)) { input_driver_ctl(RARCH_INPUT_CTL_UNSET_FLUSHING_INPUT, NULL); if (cmd.state[0]) { cmd.state[0] = 0; /* If core was paused before entering menu, evoke * pause toggle to wake it up. */ if (runloop_ctl(RUNLOOP_CTL_IS_PAUSED, NULL)) BIT64_SET(cmd.state[0], RARCH_PAUSE_TOGGLE); input_driver_ctl(RARCH_INPUT_CTL_SET_FLUSHING_INPUT, NULL); } } if (system->frame_time.callback) { /* Updates frame timing if frame timing callback is in use by the core. * Limits frame time if fast forward ratio throttle is enabled. */ bool is_slowmotion; retro_time_t current = retro_get_time_usec(); retro_time_t delta = current - frame_time_last; bool is_locked_fps = (runloop_ctl(RUNLOOP_CTL_IS_PAUSED, NULL) || input_driver_ctl(RARCH_INPUT_CTL_IS_NONBLOCK_STATE, NULL)) | !!recording_driver_get_data_ptr(); runloop_ctl(RUNLOOP_CTL_IS_SLOWMOTION, &is_slowmotion); if (!frame_time_last || is_locked_fps) delta = system->frame_time.reference; if (!is_locked_fps && is_slowmotion) delta /= settings->slowmotion_ratio; frame_time_last = current; if (is_locked_fps) frame_time_last = 0; system->frame_time.callback(delta); } cmd.state[2] = cmd.state[0] & ~cmd.state[1]; /* trigger */ if (runloop_cmd_triggered(cmd_ptr, RARCH_OVERLAY_NEXT)) event_command(EVENT_CMD_OVERLAY_NEXT); if (runloop_cmd_triggered(cmd_ptr, RARCH_FULLSCREEN_TOGGLE_KEY)) { bool fullscreen_toggled = !runloop_ctl(RUNLOOP_CTL_IS_PAUSED, NULL); #ifdef HAVE_MENU fullscreen_toggled = fullscreen_toggled || menu_driver_ctl(RARCH_MENU_CTL_IS_ALIVE, NULL); #endif if (fullscreen_toggled) event_command(EVENT_CMD_FULLSCREEN_TOGGLE); } if (runloop_cmd_triggered(cmd_ptr, RARCH_GRAB_MOUSE_TOGGLE)) event_command(EVENT_CMD_GRAB_MOUSE_TOGGLE); #ifdef HAVE_MENU if (runloop_cmd_menu_press(cmd_ptr) || (global->inited.core.type == CORE_TYPE_DUMMY)) { if (menu_driver_ctl(RARCH_MENU_CTL_IS_ALIVE, NULL)) { if (global->inited.main && (global->inited.core.type != CORE_TYPE_DUMMY)) rarch_ctl(RARCH_CTL_MENU_RUNNING_FINISHED, NULL); } else rarch_ctl(RARCH_CTL_MENU_RUNNING, NULL); } #endif #ifdef HAVE_OVERLAY runloop_iterate_linefeed_overlay(settings); #endif if (runloop_iterate_time_to_exit(runloop_cmd_press(cmd_ptr, RARCH_QUIT_KEY)) != 1) { frame_limit_last_time = 0.0; return -1; } #ifdef HAVE_MENU if (menu_driver_ctl(RARCH_MENU_CTL_IS_ALIVE, NULL)) { bool focused = runloop_ctl(RUNLOOP_CTL_CHECK_FOCUS, NULL) && !ui_companion_is_on_foreground(); bool is_idle = runloop_ctl(RUNLOOP_CTL_IS_IDLE, NULL); if (menu_driver_iterate((enum menu_action)menu_input_frame_retropad(cmd.state[0], cmd.state[2])) == -1) rarch_ctl(RARCH_CTL_MENU_RUNNING_FINISHED, NULL); if (focused || !is_idle) menu_driver_ctl(RARCH_MENU_CTL_RENDER, NULL); if (!focused || is_idle) { *sleep_ms = 10; return 1; } goto end; } #endif if (!runloop_ctl(RUNLOOP_CTL_CHECK_STATE, &cmd)) { /* RetroArch has been paused. */ retro_ctx.poll_cb(); *sleep_ms = 10; return 1; } #if defined(HAVE_THREADS) lock_autosave(); #endif #ifdef HAVE_NETPLAY netplay_driver_ctl(RARCH_NETPLAY_CTL_PRE_FRAME, NULL); #endif if (bsv_movie_ctl(BSV_MOVIE_CTL_IS_INITED, NULL)) bsv_movie_ctl(BSV_MOVIE_CTL_SET_FRAME_START, NULL); if (system->camera_callback.caps) driver_camera_poll(); /* Update binds for analog dpad modes. */ for (i = 0; i < settings->input.max_users; i++) { if (!settings->input.analog_dpad_mode[i]) continue; input_push_analog_dpad(settings->input.binds[i], settings->input.analog_dpad_mode[i]); input_push_analog_dpad(settings->input.autoconf_binds[i], settings->input.analog_dpad_mode[i]); } if ((settings->video.frame_delay > 0) && !input_driver_ctl(RARCH_INPUT_CTL_IS_NONBLOCK_STATE, NULL)) retro_sleep(settings->video.frame_delay); /* Run libretro for one frame. */ core.retro_run(); #ifdef HAVE_CHEEVOS /* Test the achievements. */ cheevos_test(); #endif for (i = 0; i < settings->input.max_users; i++) { if (!settings->input.analog_dpad_mode[i]) continue; input_pop_analog_dpad(settings->input.binds[i]); input_pop_analog_dpad(settings->input.autoconf_binds[i]); } if (bsv_movie_ctl(BSV_MOVIE_CTL_IS_INITED, NULL)) bsv_movie_ctl(BSV_MOVIE_CTL_SET_FRAME_END, NULL); #ifdef HAVE_NETPLAY netplay_driver_ctl(RARCH_NETPLAY_CTL_POST_FRAME, NULL); #endif #if defined(HAVE_THREADS) unlock_autosave(); #endif #ifdef HAVE_MENU end: #endif if (!settings->fastforward_ratio) return 0; current = retro_get_time_usec(); target = frame_limit_last_time + frame_limit_minimum_time; to_sleep_ms = (target - current) / 1000; if (to_sleep_ms > 0) { *sleep_ms = (unsigned)to_sleep_ms; /* Combat jitter a bit. */ frame_limit_last_time += frame_limit_minimum_time; return 1; } frame_limit_last_time = retro_get_time_usec(); return 0; }
bool task_push_content_load_default( const char *core_path, const char *fullpath, content_ctx_info_t *content_info, enum rarch_core_type type, enum content_mode_load mode, retro_task_callback_t cb, void *user_data) { content_information_ctx_t content_ctx; bool loading_from_menu = false; char *error_string = NULL; settings_t *settings = config_get_ptr(); if (!content_info) return false; content_ctx.history_list_enable = false; content_ctx.directory_system = NULL; content_ctx.directory_cache = NULL; content_ctx.valid_extensions = NULL; content_ctx.block_extract = false; content_ctx.need_fullpath = false; content_ctx.set_supports_no_game_enable = false; content_ctx.subsystem.data = NULL; content_ctx.subsystem.size = 0; if (settings) { content_ctx.history_list_enable = settings->history_list_enable; if (!string_is_empty(settings->directory.system)) content_ctx.directory_system = strdup(settings->directory.system); } /* First we determine if we are loading from a menu */ switch (mode) { case CONTENT_MODE_LOAD_NOTHING_WITH_NEW_CORE_FROM_MENU: #if defined(HAVE_VIDEO_PROCESSOR) case CONTENT_MODE_LOAD_NOTHING_WITH_VIDEO_PROCESSOR_CORE_FROM_MENU: #endif #if defined(HAVE_NETWORKING) && defined(HAVE_NETWORKGAMEPAD) case CONTENT_MODE_LOAD_NOTHING_WITH_NET_RETROPAD_CORE_FROM_MENU: #endif case CONTENT_MODE_LOAD_NOTHING_WITH_CURRENT_CORE_FROM_MENU: case CONTENT_MODE_LOAD_CONTENT_WITH_CURRENT_CORE_FROM_MENU: case CONTENT_MODE_LOAD_CONTENT_WITH_CURRENT_CORE_FROM_COMPANION_UI: case CONTENT_MODE_LOAD_CONTENT_WITH_NEW_CORE_FROM_COMPANION_UI: #ifdef HAVE_DYNAMIC case CONTENT_MODE_LOAD_CONTENT_WITH_NEW_CORE_FROM_MENU: #endif case CONTENT_MODE_LOAD_CONTENT_WITH_FFMPEG_CORE_FROM_MENU: case CONTENT_MODE_LOAD_CONTENT_WITH_IMAGEVIEWER_CORE_FROM_MENU: loading_from_menu = true; break; default: break; } switch (mode) { case CONTENT_MODE_LOAD_NOTHING_WITH_CURRENT_CORE_FROM_MENU: case CONTENT_MODE_LOAD_NOTHING_WITH_VIDEO_PROCESSOR_CORE_FROM_MENU: case CONTENT_MODE_LOAD_NOTHING_WITH_NET_RETROPAD_CORE_FROM_MENU: case CONTENT_MODE_LOAD_CONTENT_FROM_PLAYLIST_FROM_MENU: case CONTENT_MODE_LOAD_CONTENT_WITH_NEW_CORE_FROM_MENU: case CONTENT_MODE_LOAD_CONTENT_WITH_FFMPEG_CORE_FROM_MENU: case CONTENT_MODE_LOAD_CONTENT_WITH_CURRENT_CORE_FROM_MENU: case CONTENT_MODE_LOAD_CONTENT_WITH_IMAGEVIEWER_CORE_FROM_MENU: case CONTENT_MODE_LOAD_CONTENT_WITH_CURRENT_CORE_FROM_COMPANION_UI: case CONTENT_MODE_LOAD_CONTENT_WITH_NEW_CORE_FROM_COMPANION_UI: case CONTENT_MODE_LOAD_NOTHING_WITH_DUMMY_CORE: #ifdef HAVE_MENU if (!content_info->environ_get) content_info->environ_get = menu_content_environment_get; #endif break; default: break; } /* Clear content path */ switch (mode) { case CONTENT_MODE_LOAD_NOTHING_WITH_DUMMY_CORE: case CONTENT_MODE_LOAD_NOTHING_WITH_CURRENT_CORE_FROM_MENU: case CONTENT_MODE_LOAD_NOTHING_WITH_VIDEO_PROCESSOR_CORE_FROM_MENU: case CONTENT_MODE_LOAD_NOTHING_WITH_NET_RETROPAD_CORE_FROM_MENU: path_clear(RARCH_PATH_CONTENT); break; default: break; } /* Set content path */ switch (mode) { case CONTENT_MODE_LOAD_CONTENT_WITH_CURRENT_CORE_FROM_MENU: case CONTENT_MODE_LOAD_CONTENT_WITH_CURRENT_CORE_FROM_COMPANION_UI: case CONTENT_MODE_LOAD_CONTENT_WITH_NEW_CORE_FROM_COMPANION_UI: case CONTENT_MODE_LOAD_CONTENT_WITH_FFMPEG_CORE_FROM_MENU: case CONTENT_MODE_LOAD_CONTENT_WITH_IMAGEVIEWER_CORE_FROM_MENU: case CONTENT_MODE_LOAD_CONTENT_WITH_NEW_CORE_FROM_MENU: path_set(RARCH_PATH_CONTENT, fullpath); break; default: break; } /* Set libretro core path */ switch (mode) { case CONTENT_MODE_LOAD_NOTHING_WITH_NEW_CORE_FROM_MENU: case CONTENT_MODE_LOAD_CONTENT_WITH_NEW_CORE_FROM_MENU: case CONTENT_MODE_LOAD_CONTENT_WITH_NEW_CORE_FROM_COMPANION_UI: case CONTENT_MODE_LOAD_CONTENT_FROM_PLAYLIST_FROM_MENU: runloop_ctl(RUNLOOP_CTL_SET_LIBRETRO_PATH, (void*)core_path); break; default: break; } /* Is content required by this core? */ switch (mode) { case CONTENT_MODE_LOAD_CONTENT_FROM_PLAYLIST_FROM_MENU: #ifdef HAVE_MENU if (fullpath) menu_driver_ctl(RARCH_MENU_CTL_UNSET_LOAD_NO_CONTENT, NULL); else menu_driver_ctl(RARCH_MENU_CTL_SET_LOAD_NO_CONTENT, NULL); #endif break; default: break; } /* On targets that have no dynamic core loading support, we'd * execute the new core from this point. If this returns false, * we assume we can dynamically load the core. */ switch (mode) { case CONTENT_MODE_LOAD_CONTENT_FROM_PLAYLIST_FROM_MENU: if (!command_event_cmd_exec(fullpath, &content_ctx, mode, error_string)) goto error; #ifndef HAVE_DYNAMIC runloop_ctl(RUNLOOP_CTL_SET_SHUTDOWN, NULL); #ifdef HAVE_MENU rarch_ctl(RARCH_CTL_MENU_RUNNING_FINISHED, NULL); #endif #endif break; default: break; } /* Load core */ switch (mode) { case CONTENT_MODE_LOAD_NOTHING_WITH_NEW_CORE_FROM_MENU: #ifdef HAVE_DYNAMIC case CONTENT_MODE_LOAD_CONTENT_WITH_NEW_CORE_FROM_MENU: case CONTENT_MODE_LOAD_CONTENT_WITH_NEW_CORE_FROM_COMPANION_UI: case CONTENT_MODE_LOAD_CONTENT_FROM_PLAYLIST_FROM_MENU: #endif command_event(CMD_EVENT_LOAD_CORE, NULL); break; default: break; } #ifndef HAVE_DYNAMIC /* Fork core? */ switch (mode) { case CONTENT_MODE_LOAD_NOTHING_WITH_NEW_CORE_FROM_MENU: if (!frontend_driver_set_fork(FRONTEND_FORK_CORE)) goto cleanup; break; default: break; } #endif /* Preliminary stuff that has to be done before we * load the actual content. Can differ per mode. */ switch (mode) { case CONTENT_MODE_LOAD_NOTHING_WITH_DUMMY_CORE: runloop_ctl(RUNLOOP_CTL_STATE_FREE, NULL); #ifdef HAVE_MENU menu_driver_ctl(RARCH_MENU_CTL_UNSET_LOAD_NO_CONTENT, NULL); #endif runloop_ctl(RUNLOOP_CTL_DATA_DEINIT, NULL); runloop_ctl(RUNLOOP_CTL_TASK_INIT, NULL); break; case CONTENT_MODE_LOAD_NOTHING_WITH_CURRENT_CORE_FROM_MENU: case CONTENT_MODE_LOAD_NOTHING_WITH_NEW_CORE_FROM_MENU: retroarch_set_current_core_type(type, true); break; case CONTENT_MODE_LOAD_NOTHING_WITH_NET_RETROPAD_CORE_FROM_MENU: #if defined(HAVE_NETWORKING) && defined(HAVE_NETWORKGAMEPAD) retroarch_set_current_core_type(CORE_TYPE_NETRETROPAD, true); break; #endif case CONTENT_MODE_LOAD_NOTHING_WITH_VIDEO_PROCESSOR_CORE_FROM_MENU: #ifdef HAVE_VIDEO_PROCESSOR retroarch_set_current_core_type(CORE_TYPE_VIDEO_PROCESSOR, true); break; #endif default: break; } /* Load content */ switch (mode) { case CONTENT_MODE_LOAD_NOTHING_WITH_DUMMY_CORE: if (!task_load_content(content_info, &content_ctx, loading_from_menu, mode, error_string)) goto error; break; case CONTENT_MODE_LOAD_FROM_CLI: #if defined(HAVE_NETWORKING) && defined(HAVE_NETWORKGAMEPAD) case CONTENT_MODE_LOAD_NOTHING_WITH_NET_RETROPAD_CORE_FROM_MENU: #endif #ifdef HAVE_VIDEO_PROCESSOR case CONTENT_MODE_LOAD_NOTHING_WITH_VIDEO_PROCESSOR_CORE_FROM_MENU: #endif case CONTENT_MODE_LOAD_NOTHING_WITH_CURRENT_CORE_FROM_MENU: case CONTENT_MODE_LOAD_CONTENT_WITH_CURRENT_CORE_FROM_MENU: case CONTENT_MODE_LOAD_CONTENT_WITH_CURRENT_CORE_FROM_COMPANION_UI: case CONTENT_MODE_LOAD_CONTENT_WITH_NEW_CORE_FROM_COMPANION_UI: #ifdef HAVE_DYNAMIC case CONTENT_MODE_LOAD_CONTENT_WITH_NEW_CORE_FROM_MENU: #endif case CONTENT_MODE_LOAD_CONTENT_WITH_FFMPEG_CORE_FROM_MENU: case CONTENT_MODE_LOAD_CONTENT_WITH_IMAGEVIEWER_CORE_FROM_MENU: task_push_content_update_firmware_status(&content_ctx); if(runloop_ctl(RUNLOOP_CTL_IS_MISSING_BIOS, NULL) && settings->check_firmware_before_loading) goto skip; if (!task_load_content(content_info, &content_ctx, loading_from_menu, mode, error_string)) goto error; break; #ifndef HAVE_DYNAMIC case CONTENT_MODE_LOAD_CONTENT_WITH_NEW_CORE_FROM_MENU: command_event_cmd_exec(path_get(RARCH_PATH_CONTENT), &content_ctx, mode, error_string); command_event(CMD_EVENT_QUIT, NULL); break; #endif case CONTENT_MODE_LOAD_NONE: default: break; } /* Push quick menu onto menu stack */ switch (mode) { case CONTENT_MODE_LOAD_CONTENT_FROM_PLAYLIST_FROM_MENU: case CONTENT_MODE_LOAD_NOTHING_WITH_NEW_CORE_FROM_MENU: break; default: #ifdef HAVE_MENU if (type != CORE_TYPE_DUMMY && mode != CONTENT_MODE_LOAD_FROM_CLI) menu_driver_ctl(RARCH_MENU_CTL_SET_PENDING_QUICK_MENU, NULL); #endif break; } if (content_ctx.directory_system) free(content_ctx.directory_system); return true; error: if (error_string) { runloop_msg_queue_push(error_string, 2, 90, true); free(error_string); } #ifdef HAVE_MENU switch (mode) { case CONTENT_MODE_LOAD_CONTENT_FROM_PLAYLIST_FROM_MENU: case CONTENT_MODE_LOAD_NOTHING_WITH_CURRENT_CORE_FROM_MENU: case CONTENT_MODE_LOAD_NOTHING_WITH_NET_RETROPAD_CORE_FROM_MENU: case CONTENT_MODE_LOAD_NOTHING_WITH_VIDEO_PROCESSOR_CORE_FROM_MENU: case CONTENT_MODE_LOAD_CONTENT_WITH_CURRENT_CORE_FROM_MENU: case CONTENT_MODE_LOAD_CONTENT_WITH_FFMPEG_CORE_FROM_MENU: case CONTENT_MODE_LOAD_CONTENT_WITH_IMAGEVIEWER_CORE_FROM_MENU: case CONTENT_MODE_LOAD_CONTENT_WITH_NEW_CORE_FROM_MENU: rarch_ctl(RARCH_CTL_MENU_RUNNING, NULL); break; default: break; } #endif if (content_ctx.directory_system) free(content_ctx.directory_system); return false; skip: runloop_msg_queue_push(msg_hash_to_str(MSG_FIRMWARE), 100, 500, true); RARCH_LOG("Load content blocked. Reason: %s\n", msg_hash_to_str(MSG_FIRMWARE)); return true; #ifndef HAVE_DYNAMIC cleanup: if (content_ctx.directory_system) free(content_ctx.directory_system); return false; #endif }
static void qnx_handle_navigator_event( qnx_input_t *qnx, bps_event_t *event) { navigator_window_state_t state; bps_event_t *event_pause = NULL; switch (bps_event_get_code(event)) { case NAVIGATOR_SYSKEY_PRESS: switch(navigator_event_get_syskey_key(event)) { case NAVIGATOR_SYSKEY_BACK: input_keyboard_event(true, RETROK_BACKSPACE, 0, 0, RETRO_DEVICE_KEYBOARD); input_keyboard_event(false, RETROK_BACKSPACE, 0, 0, RETRO_DEVICE_KEYBOARD); break; case NAVIGATOR_SYSKEY_SEND: case NAVIGATOR_SYSKEY_END: break; default: break; } break; case NAVIGATOR_SWIPE_DOWN: command_event(CMD_EVENT_MENU_TOGGLE, NULL); break; case NAVIGATOR_WINDOW_STATE: switch(navigator_event_get_window_state(event)) { case NAVIGATOR_WINDOW_THUMBNAIL: case NAVIGATOR_WINDOW_INVISIBLE: while(true) { unsigned event_code; /* Block until we get a resume or exit event. */ bps_get_event(&event_pause, -1); event_code = bps_event_get_code(event_pause); if(event_code == NAVIGATOR_WINDOW_STATE) { if(navigator_event_get_window_state(event_pause) == NAVIGATOR_WINDOW_FULLSCREEN) break; } else if(event_code == NAVIGATOR_EXIT) goto shutdown; } break; case NAVIGATOR_WINDOW_FULLSCREEN: break; } break; case NAVIGATOR_EXIT: goto shutdown; default: break; } return; togglemenu: command_event(CMD_EVENT_MENU_TOGGLE, NULL); return; shutdown: rarch_ctl(RARCH_CTL_SET_SHUTDOWN, NULL); return; }
/** * event_command: * @cmd : Event command index. * * Performs program event command with index @cmd. * * Returns: true (1) on success, otherwise false (0). **/ bool event_command(enum event_command cmd) { unsigned i = 0; bool boolean = false; driver_t *driver = driver_get_ptr(); global_t *global = global_get_ptr(); settings_t *settings = config_get_ptr(); rarch_system_info_t *system = rarch_system_info_get_ptr(); (void)i; switch (cmd) { case EVENT_CMD_LOAD_CONTENT_PERSIST: #ifdef HAVE_DYNAMIC event_command(EVENT_CMD_LOAD_CORE); #endif rarch_ctl(RARCH_ACTION_STATE_LOAD_CONTENT, NULL); break; #ifdef HAVE_FFMPEG case EVENT_CMD_LOAD_CONTENT_FFMPEG: rarch_ctl(RARCH_ACTION_STATE_LOAD_CONTENT_FFMPEG, NULL); break; #endif case EVENT_CMD_LOAD_CONTENT_IMAGEVIEWER: rarch_ctl(RARCH_ACTION_STATE_LOAD_CONTENT_IMAGEVIEWER, NULL); break; case EVENT_CMD_LOAD_CONTENT: #ifdef HAVE_DYNAMIC event_command(EVENT_CMD_LOAD_CONTENT_PERSIST); #else rarch_environment_cb(RETRO_ENVIRONMENT_SET_LIBRETRO_PATH, (void*)settings->libretro); rarch_environment_cb(RETRO_ENVIRONMENT_EXEC, (void*)global->path.fullpath); event_command(EVENT_CMD_QUIT); #endif break; case EVENT_CMD_LOAD_CORE_DEINIT: #ifdef HAVE_DYNAMIC libretro_free_system_info(&global->menu.info); #endif break; case EVENT_CMD_LOAD_CORE_PERSIST: event_command(EVENT_CMD_LOAD_CORE_DEINIT); { #ifdef HAVE_MENU menu_handle_t *menu = menu_driver_get_ptr(); if (menu) event_update_system_info(&global->menu.info, &menu->load_no_content); #endif } break; case EVENT_CMD_LOAD_CORE: event_command(EVENT_CMD_LOAD_CORE_PERSIST); #ifndef HAVE_DYNAMIC event_command(EVENT_CMD_QUIT); #endif break; case EVENT_CMD_LOAD_STATE: /* Immutable - disallow savestate load when * we absolutely cannot change game state. */ if (global->bsv.movie) return false; #ifdef HAVE_NETPLAY if (driver->netplay_data) return false; #endif event_main_state(cmd); break; case EVENT_CMD_RESIZE_WINDOWED_SCALE: if (global->pending.windowed_scale == 0) return false; settings->video.scale = global->pending.windowed_scale; if (!settings->video.fullscreen) event_command(EVENT_CMD_REINIT); global->pending.windowed_scale = 0; break; case EVENT_CMD_MENU_TOGGLE: #ifdef HAVE_MENU if (menu_driver_alive()) rarch_ctl(RARCH_ACTION_STATE_MENU_RUNNING_FINISHED, NULL); else rarch_ctl(RARCH_ACTION_STATE_MENU_RUNNING, NULL); #endif break; case EVENT_CMD_CONTROLLERS_INIT: event_init_controllers(); break; case EVENT_CMD_RESET: RARCH_LOG("%s.\n", msg_hash_to_str(MSG_RESET)); rarch_main_msg_queue_push_new(MSG_RESET, 1, 120, true); core.retro_reset(); /* bSNES since v073r01 resets controllers to JOYPAD * after a reset, so just enforce it here. */ event_command(EVENT_CMD_CONTROLLERS_INIT); break; case EVENT_CMD_SAVE_STATE: if (settings->savestate_auto_index) settings->state_slot++; event_main_state(cmd); break; case EVENT_CMD_SAVE_STATE_DECREMENT: /* Slot -1 is (auto) slot. */ if (settings->state_slot >= 0) settings->state_slot--; break; case EVENT_CMD_SAVE_STATE_INCREMENT: settings->state_slot++; break; case EVENT_CMD_TAKE_SCREENSHOT: if (!take_screenshot()) return false; break; case EVENT_CMD_PREPARE_DUMMY: { #ifdef HAVE_MENU menu_handle_t *menu = menu_driver_get_ptr(); if (menu) menu->load_no_content = false; #endif rarch_main_data_deinit(); *global->path.fullpath = '\0'; rarch_ctl(RARCH_ACTION_STATE_LOAD_CONTENT, NULL); } break; case EVENT_CMD_UNLOAD_CORE: event_command(EVENT_CMD_PREPARE_DUMMY); event_command(EVENT_CMD_LOAD_CORE_DEINIT); break; case EVENT_CMD_QUIT: rarch_ctl(RARCH_ACTION_STATE_QUIT, NULL); break; case EVENT_CMD_REINIT: { const struct retro_hw_render_callback *hw_render = (const struct retro_hw_render_callback*)video_driver_callback(); const input_driver_t *input = driver ? (const input_driver_t*)driver->input : NULL; driver->video_cache_context = hw_render->cache_context; driver->video_cache_context_ack = false; event_command(EVENT_CMD_RESET_CONTEXT); driver->video_cache_context = false; /* Poll input to avoid possibly stale data to corrupt things. */ input->poll(driver->input_data); #ifdef HAVE_MENU menu_display_ctl(MENU_DISPLAY_CTL_SET_FRAMEBUFFER_DIRTY_FLAG, NULL); if (menu_driver_alive()) event_command(EVENT_CMD_VIDEO_SET_BLOCKING_STATE); #endif } break; case EVENT_CMD_CHEATS_DEINIT: if (!global) break; if (global->cheat) cheat_manager_free(global->cheat); global->cheat = NULL; break; case EVENT_CMD_CHEATS_INIT: event_command(EVENT_CMD_CHEATS_DEINIT); event_init_cheats(); break; case EVENT_CMD_CHEATS_APPLY: if (!global->cheat) break; cheat_manager_apply_cheats(global->cheat); break; case EVENT_CMD_REMAPPING_DEINIT: break; case EVENT_CMD_REMAPPING_INIT: event_command(EVENT_CMD_REMAPPING_DEINIT); event_init_remapping(); break; case EVENT_CMD_REWIND_DEINIT: if (!global) break; #ifdef HAVE_NETPLAY if (driver->netplay_data) return false; #endif if (global->rewind.state) state_manager_free(global->rewind.state); global->rewind.state = NULL; break; case EVENT_CMD_REWIND_INIT: if (!driver->netplay_data) init_rewind(); break; case EVENT_CMD_REWIND_TOGGLE: if (settings->rewind_enable) event_command(EVENT_CMD_REWIND_INIT); else event_command(EVENT_CMD_REWIND_DEINIT); break; case EVENT_CMD_AUTOSAVE_DEINIT: #ifdef HAVE_THREADS event_deinit_autosave(); #endif break; case EVENT_CMD_AUTOSAVE_INIT: event_command(EVENT_CMD_AUTOSAVE_DEINIT); #ifdef HAVE_THREADS event_init_autosave(); #endif break; case EVENT_CMD_AUTOSAVE_STATE: event_save_auto_state(); break; case EVENT_CMD_AUDIO_STOP: if (!driver->audio_data) return false; if (!audio_driver_alive()) return false; if (!audio_driver_stop()) return false; break; case EVENT_CMD_AUDIO_START: if (!driver->audio_data || audio_driver_alive()) return false; if (!settings->audio.mute_enable && !audio_driver_start()) { RARCH_ERR("Failed to start audio driver. Will continue without audio.\n"); driver->audio_active = false; } break; case EVENT_CMD_AUDIO_MUTE_TOGGLE: { const char *msg = !settings->audio.mute_enable ? msg_hash_to_str(MSG_AUDIO_MUTED): msg_hash_to_str(MSG_AUDIO_UNMUTED); if (!audio_driver_mute_toggle()) { RARCH_ERR("%s.\n", msg_hash_to_str(MSG_FAILED_TO_UNMUTE_AUDIO)); return false; } rarch_main_msg_queue_push(msg, 1, 180, true); RARCH_LOG("%s\n", msg); } break; case EVENT_CMD_OVERLAY_DEINIT: #ifdef HAVE_OVERLAY input_overlay_free_ptr(); #endif break; case EVENT_CMD_OVERLAY_INIT: event_command(EVENT_CMD_OVERLAY_DEINIT); #ifdef HAVE_OVERLAY if (input_overlay_new_ptr() == -1) RARCH_ERR("%s.\n", msg_hash_to_str(MSG_FAILED_TO_LOAD_OVERLAY)); #endif break; case EVENT_CMD_OVERLAY_NEXT: #ifdef HAVE_OVERLAY input_overlay_next(settings->input.overlay_opacity); #endif break; case EVENT_CMD_DSP_FILTER_DEINIT: if (!global) break; audio_driver_dsp_filter_free(); break; case EVENT_CMD_DSP_FILTER_INIT: event_command(EVENT_CMD_DSP_FILTER_DEINIT); if (!*settings->audio.dsp_plugin) break; audio_driver_dsp_filter_init(settings->audio.dsp_plugin); break; case EVENT_CMD_GPU_RECORD_DEINIT: if (!global) break; if (global->record.gpu_buffer) free(global->record.gpu_buffer); global->record.gpu_buffer = NULL; break; case EVENT_CMD_RECORD_DEINIT: if (!recording_deinit()) return false; break; case EVENT_CMD_RECORD_INIT: event_command(EVENT_CMD_HISTORY_DEINIT); if (!recording_init()) return false; break; case EVENT_CMD_HISTORY_DEINIT: if (g_defaults.history) { content_playlist_write_file(g_defaults.history); content_playlist_free(g_defaults.history); } g_defaults.history = NULL; break; case EVENT_CMD_HISTORY_INIT: event_command(EVENT_CMD_HISTORY_DEINIT); if (!settings->history_list_enable) return false; RARCH_LOG("%s: [%s].\n", msg_hash_to_str(MSG_LOADING_HISTORY_FILE), settings->content_history_path); g_defaults.history = content_playlist_init( settings->content_history_path, settings->content_history_size); break; case EVENT_CMD_CORE_INFO_DEINIT: if (!global) break; if (global->core_info.list) core_info_list_free(global->core_info.list); global->core_info.list = NULL; break; case EVENT_CMD_DATA_RUNLOOP_FREE: rarch_main_data_free(); break; case EVENT_CMD_CORE_INFO_INIT: event_command(EVENT_CMD_CORE_INFO_DEINIT); if (*settings->libretro_directory) global->core_info.list = core_info_list_new(); break; case EVENT_CMD_CORE_DEINIT: { struct retro_hw_render_callback *cb = video_driver_callback(); event_deinit_core(true); if (cb) memset(cb, 0, sizeof(*cb)); break; } case EVENT_CMD_CORE_INIT: if (!event_init_core()) return false; break; case EVENT_CMD_VIDEO_APPLY_STATE_CHANGES: video_driver_apply_state_changes(); break; case EVENT_CMD_VIDEO_SET_NONBLOCKING_STATE: boolean = true; /* fall-through */ case EVENT_CMD_VIDEO_SET_BLOCKING_STATE: video_driver_set_nonblock_state(boolean); break; case EVENT_CMD_VIDEO_SET_ASPECT_RATIO: video_driver_set_aspect_ratio(settings->video.aspect_ratio_idx); break; case EVENT_CMD_AUDIO_SET_NONBLOCKING_STATE: boolean = true; /* fall-through */ case EVENT_CMD_AUDIO_SET_BLOCKING_STATE: audio_driver_set_nonblock_state(boolean); break; case EVENT_CMD_OVERLAY_SET_SCALE_FACTOR: #ifdef HAVE_OVERLAY input_overlay_set_scale_factor(settings->input.overlay_scale); #endif break; case EVENT_CMD_OVERLAY_SET_ALPHA_MOD: #ifdef HAVE_OVERLAY input_overlay_set_alpha_mod(settings->input.overlay_opacity); #endif break; case EVENT_CMD_DRIVERS_DEINIT: uninit_drivers(DRIVERS_CMD_ALL); break; case EVENT_CMD_DRIVERS_INIT: init_drivers(DRIVERS_CMD_ALL); break; case EVENT_CMD_AUDIO_REINIT: uninit_drivers(DRIVER_AUDIO); init_drivers(DRIVER_AUDIO); break; case EVENT_CMD_RESET_CONTEXT: event_command(EVENT_CMD_DRIVERS_DEINIT); event_command(EVENT_CMD_DRIVERS_INIT); break; case EVENT_CMD_QUIT_RETROARCH: rarch_ctl(RARCH_ACTION_STATE_FORCE_QUIT, NULL); break; case EVENT_CMD_RESUME: rarch_ctl(RARCH_ACTION_STATE_MENU_RUNNING_FINISHED, NULL); break; case EVENT_CMD_RESTART_RETROARCH: #if defined(GEKKO) && defined(HW_RVL) fill_pathname_join(global->path.fullpath, g_defaults.dir.core, SALAMANDER_FILE, sizeof(global->path.fullpath)); #endif if (driver->frontend_ctx && driver->frontend_ctx->set_fork) driver->frontend_ctx->set_fork(true, false); break; case EVENT_CMD_MENU_SAVE_CONFIG: if (!event_save_core_config()) return false; break; case EVENT_CMD_SHADERS_APPLY_CHANGES: #ifdef HAVE_MENU menu_shader_manager_apply_changes(); #endif break; case EVENT_CMD_PAUSE_CHECKS: rarch_main_ctl(RARCH_MAIN_CTL_IS_PAUSED, &boolean); if (boolean) { RARCH_LOG("%s\n", msg_hash_to_str(MSG_PAUSED)); event_command(EVENT_CMD_AUDIO_STOP); if (settings->video.black_frame_insertion) video_driver_cached_frame(); } else { RARCH_LOG("%s\n", msg_hash_to_str(MSG_UNPAUSED)); event_command(EVENT_CMD_AUDIO_START); } break; case EVENT_CMD_PAUSE_TOGGLE: rarch_main_ctl(RARCH_MAIN_CTL_IS_PAUSED, &boolean); boolean = !boolean; rarch_main_ctl(RARCH_MAIN_CTL_SET_PAUSED, &boolean); event_command(EVENT_CMD_PAUSE_CHECKS); break; case EVENT_CMD_UNPAUSE: boolean = false; rarch_main_ctl(RARCH_MAIN_CTL_SET_PAUSED, &boolean); event_command(EVENT_CMD_PAUSE_CHECKS); break; case EVENT_CMD_PAUSE: boolean = true; rarch_main_ctl(RARCH_MAIN_CTL_SET_PAUSED, &boolean); event_command(EVENT_CMD_PAUSE_CHECKS); break; case EVENT_CMD_MENU_PAUSE_LIBRETRO: #ifdef HAVE_MENU if (menu_driver_alive()) { if (settings->menu.pause_libretro) event_command(EVENT_CMD_AUDIO_STOP); else event_command(EVENT_CMD_AUDIO_START); } else { if (settings->menu.pause_libretro) event_command(EVENT_CMD_AUDIO_START); } #endif break; case EVENT_CMD_SHADER_DIR_DEINIT: if (!global) break; dir_list_free(global->shader_dir.list); global->shader_dir.list = NULL; global->shader_dir.ptr = 0; break; case EVENT_CMD_SHADER_DIR_INIT: event_command(EVENT_CMD_SHADER_DIR_DEINIT); if (!*settings->video.shader_dir) return false; global->shader_dir.list = dir_list_new_special(NULL, DIR_LIST_SHADERS); if (!global->shader_dir.list || global->shader_dir.list->size == 0) { event_command(EVENT_CMD_SHADER_DIR_DEINIT); return false; } global->shader_dir.ptr = 0; dir_list_sort(global->shader_dir.list, false); for (i = 0; i < global->shader_dir.list->size; i++) RARCH_LOG("%s \"%s\"\n", msg_hash_to_str(MSG_FOUND_SHADER), global->shader_dir.list->elems[i].data); break; case EVENT_CMD_SAVEFILES: event_save_files(); break; case EVENT_CMD_SAVEFILES_DEINIT: if (!global) break; if (global->savefiles) string_list_free(global->savefiles); global->savefiles = NULL; break; case EVENT_CMD_SAVEFILES_INIT: global->sram.use = global->sram.use && !global->sram.save_disable #ifdef HAVE_NETPLAY && (!driver->netplay_data || !global->netplay.is_client) #endif ; if (!global->sram.use) RARCH_LOG("%s\n", msg_hash_to_str(MSG_SRAM_WILL_NOT_BE_SAVED)); if (global->sram.use) event_command(EVENT_CMD_AUTOSAVE_INIT); break; case EVENT_CMD_MSG_QUEUE_DEINIT: rarch_main_msg_queue_free(); break; case EVENT_CMD_MSG_QUEUE_INIT: event_command(EVENT_CMD_MSG_QUEUE_DEINIT); rarch_main_msg_queue_init(); rarch_main_data_init_queues(); break; case EVENT_CMD_BSV_MOVIE_DEINIT: if (!global) break; if (global->bsv.movie) bsv_movie_free(global->bsv.movie); global->bsv.movie = NULL; break; case EVENT_CMD_BSV_MOVIE_INIT: event_command(EVENT_CMD_BSV_MOVIE_DEINIT); event_init_movie(); break; case EVENT_CMD_NETPLAY_DEINIT: #ifdef HAVE_NETPLAY deinit_netplay(); #endif break; case EVENT_CMD_NETWORK_DEINIT: #ifdef HAVE_NETWORKING network_deinit(); #endif break; case EVENT_CMD_NETWORK_INIT: #ifdef HAVE_NETWORKING network_init(); #endif break; case EVENT_CMD_NETPLAY_INIT: event_command(EVENT_CMD_NETPLAY_DEINIT); #ifdef HAVE_NETPLAY if (!init_netplay()) return false; #endif break; case EVENT_CMD_NETPLAY_FLIP_PLAYERS: #ifdef HAVE_NETPLAY { netplay_t *netplay = (netplay_t*)driver->netplay_data; if (!netplay) return false; netplay_flip_users(netplay); } #endif break; case EVENT_CMD_FULLSCREEN_TOGGLE: if (!video_driver_has_windowed()) return false; /* If we go fullscreen we drop all drivers and * reinitialize to be safe. */ settings->video.fullscreen = !settings->video.fullscreen; event_command(EVENT_CMD_REINIT); break; case EVENT_CMD_COMMAND_DEINIT: #ifdef HAVE_COMMAND if (driver->command) rarch_cmd_free(driver->command); driver->command = NULL; #endif break; case EVENT_CMD_COMMAND_INIT: event_command(EVENT_CMD_COMMAND_DEINIT); #ifdef HAVE_COMMAND event_init_command(); #endif break; case EVENT_CMD_TEMPORARY_CONTENT_DEINIT: if (!global) break; if (global->temporary_content) event_free_temporary_content(); global->temporary_content = NULL; break; case EVENT_CMD_SUBSYSTEM_FULLPATHS_DEINIT: if (!global) break; if (global->subsystem_fullpaths) string_list_free(global->subsystem_fullpaths); global->subsystem_fullpaths = NULL; break; case EVENT_CMD_LOG_FILE_DEINIT: if (!global) break; if (global->log_file && global->log_file != stderr) fclose(global->log_file); global->log_file = NULL; break; case EVENT_CMD_DISK_EJECT_TOGGLE: if (system && system->disk_control.get_num_images) { const struct retro_disk_control_callback *control = (const struct retro_disk_control_callback*) &system->disk_control; if (control) event_check_disk_eject(control); } else rarch_main_msg_queue_push_new( MSG_CORE_DOES_NOT_SUPPORT_DISK_OPTIONS, 1, 120, true); break; case EVENT_CMD_DISK_NEXT: if (system && system->disk_control.get_num_images) { const struct retro_disk_control_callback *control = (const struct retro_disk_control_callback*) &system->disk_control; if (!control) return false; if (!control->get_eject_state()) return false; event_check_disk_next(control); } else rarch_main_msg_queue_push_new( MSG_CORE_DOES_NOT_SUPPORT_DISK_OPTIONS, 1, 120, true); break; case EVENT_CMD_DISK_PREV: if (system && system->disk_control.get_num_images) { const struct retro_disk_control_callback *control = (const struct retro_disk_control_callback*) &system->disk_control; if (!control) return false; if (!control->get_eject_state()) return false; event_check_disk_prev(control); } else rarch_main_msg_queue_push_new( MSG_CORE_DOES_NOT_SUPPORT_DISK_OPTIONS, 1, 120, true); break; case EVENT_CMD_RUMBLE_STOP: for (i = 0; i < MAX_USERS; i++) { input_driver_set_rumble_state(i, RETRO_RUMBLE_STRONG, 0); input_driver_set_rumble_state(i, RETRO_RUMBLE_WEAK, 0); } break; case EVENT_CMD_GRAB_MOUSE_TOGGLE: { static bool grab_mouse_state = false; grab_mouse_state = !grab_mouse_state; if (!driver->input || !input_driver_grab_mouse(grab_mouse_state)) return false; RARCH_LOG("%s: %s.\n", msg_hash_to_str(MSG_GRAB_MOUSE_STATE), grab_mouse_state ? "yes" : "no"); video_driver_show_mouse(!grab_mouse_state); } break; case EVENT_CMD_PERFCNT_REPORT_FRONTEND_LOG: rarch_perf_log(); break; case EVENT_CMD_VOLUME_UP: event_set_volume(0.5f); break; case EVENT_CMD_VOLUME_DOWN: event_set_volume(-0.5f); break; case EVENT_CMD_SET_FRAME_LIMIT: rarch_main_ctl(RARCH_MAIN_CTL_SET_FRAME_LIMIT_LAST_TIME, NULL); break; case EVENT_CMD_NONE: default: return false; } return true; }
/** * rarch_main_init: * @argc : Count of (commandline) arguments. * @argv : (Commandline) arguments. * * Initializes the program. * * Returns: 0 on success, otherwise 1 if there was an error. **/ int rarch_main_init(int argc, char *argv[]) { int sjlj_ret; global_t *global = global_get_ptr(); init_state(); if ((sjlj_ret = setjmp(global->error_sjlj_context)) > 0) { RARCH_ERR("Fatal error received in: \"%s\"\n", global->error_string); return sjlj_ret; } global->inited.error = true; global->log_file = stderr; parse_input(argc, argv); if (global->verbosity) { char str[PATH_MAX_LENGTH] = {0}; RARCH_LOG_OUTPUT("=== Build ======================================="); rarch_info_get_capabilities(RARCH_CAPABILITIES_CPU, str, sizeof(str)); fprintf(stderr, "%s", str); fprintf(stderr, "Built: %s\n", __DATE__); RARCH_LOG_OUTPUT("Version: %s\n", PACKAGE_VERSION); #ifdef HAVE_GIT_VERSION RARCH_LOG_OUTPUT("Git: %s\n", rarch_git_version); #endif RARCH_LOG_OUTPUT("=================================================\n"); } rarch_ctl(RARCH_ACTION_STATE_VALIDATE_CPU_FEATURES, NULL); config_load(); { settings_t *settings = config_get_ptr(); if (settings && (settings->multimedia.builtin_mediaplayer_enable || settings->multimedia.builtin_imageviewer_enable)) { switch (rarch_path_is_media_type(global->path.fullpath)) { case RARCH_CONTENT_MOVIE: case RARCH_CONTENT_MUSIC: if (settings->multimedia.builtin_mediaplayer_enable) { #ifdef HAVE_FFMPEG global->has_set.libretro = false; global->inited.core.type = CORE_TYPE_FFMPEG; #endif } break; #ifdef HAVE_IMAGEVIEWER case RARCH_CONTENT_IMAGE: if (settings->multimedia.builtin_imageviewer_enable) { global->has_set.libretro = false; global->inited.core.type = CORE_TYPE_IMAGEVIEWER; } break; #endif default: break; } } } init_libretro_sym(global->inited.core.type); rarch_system_info_init(); init_drivers_pre(); if (!event_command(EVENT_CMD_CORE_INIT)) goto error; event_command(EVENT_CMD_DRIVERS_INIT); event_command(EVENT_CMD_COMMAND_INIT); event_command(EVENT_CMD_REWIND_INIT); event_command(EVENT_CMD_CONTROLLERS_INIT); event_command(EVENT_CMD_RECORD_INIT); event_command(EVENT_CMD_CHEATS_INIT); event_command(EVENT_CMD_REMAPPING_INIT); event_command(EVENT_CMD_SAVEFILES_INIT); #if defined(GEKKO) && defined(HW_RVL) { settings_t *settings = config_get_ptr(); if (settings) { event_command(EVENT_CMD_VIDEO_SET_ASPECT_RATIO); video_driver_set_aspect_ratio(settings->video.aspect_ratio_idx); } unsigned width = 0, height = 0; (void)width; (void)height; width = global->console.screen.resolutions.width; height = global->console.screen.resolutions.height; video_driver_set_video_mode(width, height, true); char msg[PATH_MAX_LENGTH] = {0}; snprintf(msg, sizeof(msg),"Resolution: %dx%d",width, height); rarch_main_msg_queue_push(msg, 1, 100, true); } #endif global->inited.error = false; global->inited.main = true; return 0; error: event_command(EVENT_CMD_CORE_DEINIT); global->inited.main = false; return 1; }
/** * rarch_environment_cb: * @cmd : Identifier of command. * @data : Pointer to data. * * Environment callback function implementation. * * Returns: true (1) if environment callback command could * be performed, otherwise false (0). **/ bool rarch_environment_cb(unsigned cmd, void *data) { unsigned p; settings_t *settings = config_get_ptr(); global_t *global = global_get_ptr(); rarch_system_info_t *system = NULL; runloop_ctl(RUNLOOP_CTL_SYSTEM_INFO_GET, &system); if (ignore_environment_cb) return false; switch (cmd) { case RETRO_ENVIRONMENT_GET_OVERSCAN: *(bool*)data = !settings->video.crop_overscan; RARCH_LOG("Environ GET_OVERSCAN: %u\n", (unsigned)!settings->video.crop_overscan); break; case RETRO_ENVIRONMENT_GET_CAN_DUPE: *(bool*)data = true; RARCH_LOG("Environ GET_CAN_DUPE: true\n"); break; case RETRO_ENVIRONMENT_GET_VARIABLE: if (!runloop_ctl(RUNLOOP_CTL_CORE_OPTIONS_GET, data)) { struct retro_variable *var = (struct retro_variable*)data; if (var) { RARCH_LOG("Environ GET_VARIABLE %s: not implemented.\n", var->key); var->value = NULL; } } break; case RETRO_ENVIRONMENT_GET_VARIABLE_UPDATE: *(bool*)data = runloop_ctl(RUNLOOP_CTL_IS_CORE_OPTION_UPDATED, NULL); break; case RETRO_ENVIRONMENT_SET_VARIABLES: RARCH_LOG("Environ SET_VARIABLES.\n"); runloop_ctl(RUNLOOP_CTL_CORE_OPTIONS_DEINIT, NULL); runloop_ctl(RUNLOOP_CTL_CORE_OPTIONS_INIT, data); break; case RETRO_ENVIRONMENT_SET_MESSAGE: { const struct retro_message *msg = (const struct retro_message*)data; RARCH_LOG("Environ SET_MESSAGE: %s\n", msg->msg); runloop_msg_queue_push(msg->msg, 1, msg->frames, true); break; } case RETRO_ENVIRONMENT_SET_ROTATION: { unsigned rotation = *(const unsigned*)data; RARCH_LOG("Environ SET_ROTATION: %u\n", rotation); if (!settings->video.allow_rotate) break; system->rotation = rotation; if (!video_driver_set_rotation(rotation)) return false; break; } case RETRO_ENVIRONMENT_SHUTDOWN: RARCH_LOG("Environ SHUTDOWN.\n"); runloop_ctl(RUNLOOP_CTL_SET_SHUTDOWN, NULL); runloop_ctl(RUNLOOP_CTL_SET_CORE_SHUTDOWN, NULL); break; case RETRO_ENVIRONMENT_SET_PERFORMANCE_LEVEL: system->performance_level = *(const unsigned*)data; RARCH_LOG("Environ PERFORMANCE_LEVEL: %u.\n", system->performance_level); break; case RETRO_ENVIRONMENT_GET_SYSTEM_DIRECTORY: if (string_is_empty(settings->system_directory)) { char *fullpath = NULL; runloop_ctl(RUNLOOP_CTL_GET_CONTENT_PATH, &fullpath); RARCH_WARN("SYSTEM DIR is empty, assume CONTENT DIR %s\n", fullpath); fill_pathname_basedir(global->dir.systemdir, fullpath, sizeof(global->dir.systemdir)); *(const char**)data = global->dir.systemdir; RARCH_LOG("Environ SYSTEM_DIRECTORY: \"%s\".\n", global->dir.systemdir); } else { *(const char**)data = settings->system_directory; RARCH_LOG("Environ SYSTEM_DIRECTORY: \"%s\".\n", settings->system_directory); } break; case RETRO_ENVIRONMENT_GET_SAVE_DIRECTORY: *(const char**)data = rarch_get_current_savefile_dir(); break; case RETRO_ENVIRONMENT_GET_USERNAME: *(const char**)data = *settings->username ? settings->username : NULL; RARCH_LOG("Environ GET_USERNAME: \"%s\".\n", settings->username); break; case RETRO_ENVIRONMENT_GET_LANGUAGE: *(unsigned *)data = settings->user_language; RARCH_LOG("Environ GET_LANGUAGE: \"%u\".\n", settings->user_language); break; case RETRO_ENVIRONMENT_SET_PIXEL_FORMAT: { enum retro_pixel_format pix_fmt = *(const enum retro_pixel_format*)data; switch (pix_fmt) { case RETRO_PIXEL_FORMAT_0RGB1555: RARCH_LOG("Environ SET_PIXEL_FORMAT: 0RGB1555.\n"); break; case RETRO_PIXEL_FORMAT_RGB565: RARCH_LOG("Environ SET_PIXEL_FORMAT: RGB565.\n"); break; case RETRO_PIXEL_FORMAT_XRGB8888: RARCH_LOG("Environ SET_PIXEL_FORMAT: XRGB8888.\n"); break; default: return false; } video_driver_set_pixel_format(pix_fmt); break; } case RETRO_ENVIRONMENT_SET_INPUT_DESCRIPTORS: { unsigned retro_id, retro_port; const struct retro_input_descriptor *desc = NULL; static const char *libretro_btn_desc[] = { "B (bottom)", "Y (left)", "Select", "Start", "D-Pad Up", "D-Pad Down", "D-Pad Left", "D-Pad Right", "A (right)", "X (up)", "L", "R", "L2", "R2", "L3", "R3", }; memset(system->input_desc_btn, 0, sizeof(system->input_desc_btn)); desc = (const struct retro_input_descriptor*)data; for (; desc->description; desc++) { retro_port = desc->port; retro_id = desc->id; if (desc->port >= MAX_USERS) continue; /* Ignore all others for now. */ if (desc->device != RETRO_DEVICE_JOYPAD && desc->device != RETRO_DEVICE_ANALOG) continue; if (desc->id >= RARCH_FIRST_CUSTOM_BIND) continue; if (desc->device == RETRO_DEVICE_ANALOG) { switch (retro_id) { case RETRO_DEVICE_ID_ANALOG_X: switch (desc->index) { case RETRO_DEVICE_INDEX_ANALOG_LEFT: system->input_desc_btn[retro_port][RARCH_ANALOG_LEFT_X_PLUS] = desc->description; system->input_desc_btn[retro_port][RARCH_ANALOG_LEFT_X_MINUS] = desc->description; break; case RETRO_DEVICE_INDEX_ANALOG_RIGHT: system->input_desc_btn[retro_port][RARCH_ANALOG_RIGHT_X_PLUS] = desc->description; system->input_desc_btn[retro_port][RARCH_ANALOG_RIGHT_X_MINUS] = desc->description; break; } break; case RETRO_DEVICE_ID_ANALOG_Y: switch (desc->index) { case RETRO_DEVICE_INDEX_ANALOG_LEFT: system->input_desc_btn[retro_port][RARCH_ANALOG_LEFT_Y_PLUS] = desc->description; system->input_desc_btn[retro_port][RARCH_ANALOG_LEFT_Y_MINUS] = desc->description; break; case RETRO_DEVICE_INDEX_ANALOG_RIGHT: system->input_desc_btn[retro_port][RARCH_ANALOG_RIGHT_Y_PLUS] = desc->description; system->input_desc_btn[retro_port][RARCH_ANALOG_RIGHT_Y_MINUS] = desc->description; break; } break; } } else system->input_desc_btn[retro_port][retro_id] = desc->description; } RARCH_LOG("Environ SET_INPUT_DESCRIPTORS:\n"); for (p = 0; p < settings->input.max_users; p++) { for (retro_id = 0; retro_id < RARCH_FIRST_CUSTOM_BIND; retro_id++) { const char *description = system->input_desc_btn[p][retro_id]; if (!description) continue; RARCH_LOG("\tRetroPad, User %u, Button \"%s\" => \"%s\"\n", p + 1, libretro_btn_desc[retro_id], description); } } global->has_set.input_descriptors = true; break; } case RETRO_ENVIRONMENT_SET_KEYBOARD_CALLBACK: { retro_keyboard_event_t *frontend_key_event = NULL; retro_keyboard_event_t *key_event = NULL; const struct retro_keyboard_callback *info = (const struct retro_keyboard_callback*)data; runloop_ctl(RUNLOOP_CTL_FRONTEND_KEY_EVENT_GET, &frontend_key_event); runloop_ctl(RUNLOOP_CTL_KEY_EVENT_GET, &key_event); RARCH_LOG("Environ SET_KEYBOARD_CALLBACK.\n"); if (key_event) *key_event = info->callback; if (frontend_key_event) *frontend_key_event = *key_event; break; } case RETRO_ENVIRONMENT_SET_DISK_CONTROL_INTERFACE: RARCH_LOG("Environ SET_DISK_CONTROL_INTERFACE.\n"); system->disk_control = *(const struct retro_disk_control_callback*)data; break; case RETRO_ENVIRONMENT_SET_HW_RENDER: case RETRO_ENVIRONMENT_SET_HW_RENDER | RETRO_ENVIRONMENT_EXPERIMENTAL: { struct retro_hw_render_callback *hw_render = video_driver_callback(); struct retro_hw_render_callback *cb = (struct retro_hw_render_callback*)data; RARCH_LOG("Environ SET_HW_RENDER.\n"); switch (cb->context_type) { case RETRO_HW_CONTEXT_NONE: RARCH_LOG("Requesting no HW context.\n"); break; #if defined(HAVE_OPENGLES2) case RETRO_HW_CONTEXT_OPENGLES2: #if defined(HAVE_OPENGLES3) case RETRO_HW_CONTEXT_OPENGLES3: #endif RARCH_LOG("Requesting OpenGLES%u context.\n", cb->context_type == RETRO_HW_CONTEXT_OPENGLES2 ? 2 : 3); break; #if defined(HAVE_OPENGLES3) case RETRO_HW_CONTEXT_OPENGLES_VERSION: RARCH_LOG("Requesting OpenGLES%u.%u context.\n", cb->version_major, cb->version_minor); break; #endif case RETRO_HW_CONTEXT_OPENGL: case RETRO_HW_CONTEXT_OPENGL_CORE: RARCH_ERR("Requesting OpenGL context, but RetroArch is compiled against OpenGLES2. Cannot use HW context.\n"); return false; #elif defined(HAVE_OPENGL) case RETRO_HW_CONTEXT_OPENGLES2: case RETRO_HW_CONTEXT_OPENGLES3: RARCH_ERR("Requesting OpenGLES%u context, but RetroArch is compiled against OpenGL. Cannot use HW context.\n", cb->context_type == RETRO_HW_CONTEXT_OPENGLES2 ? 2 : 3); return false; case RETRO_HW_CONTEXT_OPENGLES_VERSION: RARCH_ERR("Requesting OpenGLES%u.%u context, but RetroArch is compiled against OpenGL. Cannot use HW context.\n", cb->version_major, cb->version_minor); return false; case RETRO_HW_CONTEXT_OPENGL: RARCH_LOG("Requesting OpenGL context.\n"); break; case RETRO_HW_CONTEXT_OPENGL_CORE: RARCH_LOG("Requesting core OpenGL context (%u.%u).\n", cb->version_major, cb->version_minor); break; #endif default: RARCH_LOG("Requesting unknown context.\n"); return false; } cb->get_current_framebuffer = video_driver_get_current_framebuffer; cb->get_proc_address = video_driver_get_proc_address; if (cmd & RETRO_ENVIRONMENT_EXPERIMENTAL) /* Old ABI. Don't copy garbage. */ memcpy(hw_render, cb, offsetof(struct retro_hw_render_callback, stencil)); else memcpy(hw_render, cb, sizeof(*cb)); break; } case RETRO_ENVIRONMENT_SET_SUPPORT_NO_GAME: { bool state = *(const bool*)data; RARCH_LOG("Environ SET_SUPPORT_NO_GAME: %s.\n", state ? "yes" : "no"); system->no_content = state; break; } case RETRO_ENVIRONMENT_GET_LIBRETRO_PATH: { const char **path = (const char**)data; *path = NULL; #ifdef HAVE_DYNAMIC *path = settings->libretro; #endif break; } /* FIXME - PS3 audio driver needs to be fixed so that threaded * audio works correctly (audio is already on a thread for PS3 * audio driver so that's probably the problem) */ #if defined(HAVE_THREADS) && !defined(__CELLOS_LV2__) case RETRO_ENVIRONMENT_SET_AUDIO_CALLBACK: { const struct retro_audio_callback *info = (const struct retro_audio_callback*)data; RARCH_LOG("Environ SET_AUDIO_CALLBACK.\n"); if (recording_driver_get_data_ptr()) /* A/V sync is a must. */ return false; #ifdef HAVE_NETPLAY if (global->netplay.enable) return false; #endif audio_driver_set_callback(info); break; } #endif case RETRO_ENVIRONMENT_SET_FRAME_TIME_CALLBACK: { const struct retro_frame_time_callback *info = (const struct retro_frame_time_callback*)data; RARCH_LOG("Environ SET_FRAME_TIME_CALLBACK.\n"); #ifdef HAVE_NETPLAY /* retro_run() will be called in very strange and * mysterious ways, have to disable it. */ if (global->netplay.enable) return false; #endif system->frame_time = *info; break; } case RETRO_ENVIRONMENT_GET_RUMBLE_INTERFACE: { struct retro_rumble_interface *iface = (struct retro_rumble_interface*)data; RARCH_LOG("Environ GET_RUMBLE_INTERFACE.\n"); iface->set_rumble_state = input_driver_set_rumble_state; break; } case RETRO_ENVIRONMENT_GET_INPUT_DEVICE_CAPABILITIES: { uint64_t *mask = (uint64_t*)data; RARCH_LOG("Environ GET_INPUT_DEVICE_CAPABILITIES.\n"); if (input_driver_ctl(RARCH_INPUT_CTL_HAS_CAPABILITIES, NULL)) *mask = input_driver_get_capabilities(); else return false; break; } case RETRO_ENVIRONMENT_GET_SENSOR_INTERFACE: { struct retro_sensor_interface *iface = (struct retro_sensor_interface*)data; RARCH_LOG("Environ GET_SENSOR_INTERFACE.\n"); iface->set_sensor_state = input_sensor_set_state; iface->get_sensor_input = input_sensor_get_input; break; } case RETRO_ENVIRONMENT_GET_CAMERA_INTERFACE: { struct retro_camera_callback *cb = (struct retro_camera_callback*)data; RARCH_LOG("Environ GET_CAMERA_INTERFACE.\n"); cb->start = driver_camera_start; cb->stop = driver_camera_stop; system->camera_callback = *cb; if (cb->caps != 0) camera_driver_ctl(RARCH_CAMERA_CTL_SET_ACTIVE, NULL); else camera_driver_ctl(RARCH_CAMERA_CTL_UNSET_ACTIVE, NULL); break; } case RETRO_ENVIRONMENT_GET_LOCATION_INTERFACE: { struct retro_location_callback *cb = (struct retro_location_callback*)data; RARCH_LOG("Environ GET_LOCATION_INTERFACE.\n"); cb->start = driver_location_start; cb->stop = driver_location_stop; cb->get_position = driver_location_get_position; cb->set_interval = driver_location_set_interval; system->location_callback = *cb; location_driver_ctl(RARCH_LOCATION_CTL_UNSET_ACTIVE, NULL); break; } case RETRO_ENVIRONMENT_GET_LOG_INTERFACE: { struct retro_log_callback *cb = (struct retro_log_callback*)data; RARCH_LOG("Environ GET_LOG_INTERFACE.\n"); cb->log = rarch_log_libretro; break; } case RETRO_ENVIRONMENT_GET_PERF_INTERFACE: { struct retro_perf_callback *cb = (struct retro_perf_callback*)data; RARCH_LOG("Environ GET_PERF_INTERFACE.\n"); cb->get_time_usec = retro_get_time_usec; cb->get_cpu_features = retro_get_cpu_features; cb->get_perf_counter = retro_get_perf_counter; cb->perf_register = retro_perf_register; /* libretro specific path. */ cb->perf_start = retro_perf_start; cb->perf_stop = retro_perf_stop; cb->perf_log = retro_perf_log; /* libretro specific path. */ break; } case RETRO_ENVIRONMENT_GET_CORE_ASSETS_DIRECTORY: { const char **dir = (const char**)data; *dir = *settings->core_assets_directory ? settings->core_assets_directory : NULL; RARCH_LOG("Environ CORE_ASSETS_DIRECTORY: \"%s\".\n", settings->core_assets_directory); break; } case RETRO_ENVIRONMENT_SET_SYSTEM_AV_INFO: { RARCH_LOG("Environ SET_SYSTEM_AV_INFO.\n"); return driver_ctl(RARCH_DRIVER_CTL_UPDATE_SYSTEM_AV_INFO, (void**)&data); } case RETRO_ENVIRONMENT_SET_SUBSYSTEM_INFO: { unsigned i, j; const struct retro_subsystem_info *info = (const struct retro_subsystem_info*)data; RARCH_LOG("Environ SET_SUBSYSTEM_INFO.\n"); for (i = 0; info[i].ident; i++) { RARCH_LOG("Special game type: %s\n", info[i].desc); RARCH_LOG(" Ident: %s\n", info[i].ident); RARCH_LOG(" ID: %u\n", info[i].id); RARCH_LOG(" Content:\n"); for (j = 0; j < info[i].num_roms; j++) { RARCH_LOG(" %s (%s)\n", info[i].roms[j].desc, info[i].roms[j].required ? "required" : "optional"); } } free(system->special); system->special = (struct retro_subsystem_info*) calloc(i, sizeof(*system->special)); if (!system->special) return false; memcpy(system->special, info, i * sizeof(*system->special)); system->num_special = i; break; } case RETRO_ENVIRONMENT_SET_CONTROLLER_INFO: { unsigned i, j; const struct retro_controller_info *info = (const struct retro_controller_info*)data; RARCH_LOG("Environ SET_CONTROLLER_INFO.\n"); for (i = 0; info[i].types; i++) { RARCH_LOG("Controller port: %u\n", i + 1); for (j = 0; j < info[i].num_types; j++) RARCH_LOG(" %s (ID: %u)\n", info[i].types[j].desc, info[i].types[j].id); } free(system->ports); system->ports = (struct retro_controller_info*) calloc(i, sizeof(*system->ports)); if (!system->ports) return false; memcpy(system->ports, info, i * sizeof(*system->ports)); system->num_ports = i; break; } case RETRO_ENVIRONMENT_SET_GEOMETRY: { struct retro_system_av_info *av_info = video_viewport_get_system_av_info(); const struct retro_game_geometry *in_geom = (const struct retro_game_geometry*)data; struct retro_game_geometry *geom = av_info ? (struct retro_game_geometry*)&av_info->geometry : NULL; if (!geom) return false; RARCH_LOG("Environ SET_GEOMETRY.\n"); /* Can potentially be called every frame, * don't do anything unless required. */ if (geom->base_width != in_geom->base_width || geom->base_height != in_geom->base_height || geom->aspect_ratio != in_geom->aspect_ratio) { geom->base_width = in_geom->base_width; geom->base_height = in_geom->base_height; geom->aspect_ratio = in_geom->aspect_ratio; RARCH_LOG("SET_GEOMETRY: %ux%u, aspect: %.3f.\n", geom->base_width, geom->base_height, geom->aspect_ratio); /* Forces recomputation of aspect ratios if * using core-dependent aspect ratios. */ event_cmd_ctl(EVENT_CMD_VIDEO_SET_ASPECT_RATIO, NULL); /* TODO: Figure out what to do, if anything, with recording. */ } break; } case RETRO_ENVIRONMENT_GET_CURRENT_SOFTWARE_FRAMEBUFFER: return video_driver_get_current_software_framebuffer((struct retro_framebuffer*)data); /* Private extensions for internal use, not part of libretro API. */ case RETRO_ENVIRONMENT_EXEC: { RARCH_LOG("Environ (Private) EXEC.\n"); char *fullpath = NULL; runloop_ctl(RUNLOOP_CTL_GET_CONTENT_PATH, &fullpath); if (fullpath != data) { runloop_ctl(RUNLOOP_CTL_CLEAR_CONTENT_PATH, NULL); if (data) runloop_ctl(RUNLOOP_CTL_SET_CONTENT_PATH, data); } #if defined(RARCH_CONSOLE) frontend_driver_set_fork(true, true, false); #elif defined(HAVE_DYNAMIC) rarch_ctl(RARCH_CTL_LOAD_CONTENT, NULL); #endif } break; default: RARCH_LOG("Environ UNSUPPORTED (#%u).\n", cmd); return false; } return true; }
bool rarch_ctl(enum rarch_ctl_state state, void *data) { driver_t *driver = driver_get_ptr(); global_t *global = global_get_ptr(); settings_t *settings = config_get_ptr(); rarch_system_info_t *system = rarch_system_info_get_ptr(); switch(state) { case RARCH_ACTION_STATE_REPLACE_CONFIG: { char *path = (char*)data; if (!path) return false; /* If config file to be replaced is the same as the * current config file, exit. */ if (!strcmp(path, global->path.config)) return false; if (settings->config_save_on_exit && *global->path.config) config_save_file(global->path.config); strlcpy(global->path.config, path, sizeof(global->path.config)); global->block_config_read = false; *settings->libretro = '\0'; /* Load core in new config. */ } event_command(EVENT_CMD_PREPARE_DUMMY); return true; case RARCH_ACTION_STATE_MENU_RUNNING: #ifdef HAVE_MENU menu_driver_toggle(true); #endif #ifdef HAVE_OVERLAY if (settings->input.overlay_hide_in_menu) event_command(EVENT_CMD_OVERLAY_DEINIT); #endif break; case RARCH_ACTION_STATE_LOAD_CONTENT: #ifdef HAVE_MENU /* If content loading fails, we go back to menu. */ if (!menu_load_content(CORE_TYPE_PLAIN)) rarch_ctl(RARCH_ACTION_STATE_MENU_RUNNING, NULL); #endif if (driver->frontend_ctx && driver->frontend_ctx->content_loaded) driver->frontend_ctx->content_loaded(); break; #ifdef HAVE_FFMPEG case RARCH_ACTION_STATE_LOAD_CONTENT_FFMPEG: #ifdef HAVE_MENU /* If content loading fails, we go back to menu. */ if (!menu_load_content(CORE_TYPE_FFMPEG)) rarch_ctl(RARCH_ACTION_STATE_MENU_RUNNING, NULL); #endif if (driver->frontend_ctx && driver->frontend_ctx->content_loaded) driver->frontend_ctx->content_loaded(); break; #endif case RARCH_ACTION_STATE_LOAD_CONTENT_IMAGEVIEWER: #ifdef HAVE_MENU /* If content loading fails, we go back to menu. */ if (!menu_load_content(CORE_TYPE_IMAGEVIEWER)) rarch_ctl(RARCH_ACTION_STATE_MENU_RUNNING, NULL); #endif if (driver->frontend_ctx && driver->frontend_ctx->content_loaded) driver->frontend_ctx->content_loaded(); break; case RARCH_ACTION_STATE_MENU_RUNNING_FINISHED: #ifdef HAVE_MENU menu_driver_toggle(false); #endif video_driver_set_texture_enable(false, false); #ifdef HAVE_OVERLAY if (settings && settings->input.overlay_hide_in_menu) event_command(EVENT_CMD_OVERLAY_INIT); #endif break; case RARCH_ACTION_STATE_QUIT: if (global) system->shutdown = true; rarch_ctl(RARCH_ACTION_STATE_MENU_RUNNING_FINISHED, NULL); break; case RARCH_ACTION_STATE_FORCE_QUIT: rarch_ctl(RARCH_ACTION_STATE_QUIT, NULL); break; case RARCH_ACTION_STATE_VALIDATE_CPU_FEATURES: { uint64_t cpu = retro_get_cpu_features(); (void)cpu; #ifdef __SSE__ if (!(cpu & RETRO_SIMD_SSE)) FAIL_CPU("SSE"); #endif #ifdef __SSE2__ if (!(cpu & RETRO_SIMD_SSE2)) FAIL_CPU("SSE2"); #endif #ifdef __AVX__ if (!(cpu & RETRO_SIMD_AVX)) FAIL_CPU("AVX"); #endif } break; case RARCH_ACTION_STATE_VERIFY_API_VERSION: RARCH_LOG("Version of libretro API: %u\n", core.retro_api_version()); RARCH_LOG("Compiled against API: %u\n", RETRO_API_VERSION); if (core.retro_api_version() != RETRO_API_VERSION) RARCH_WARN("%s\n", msg_hash_to_str(MSG_LIBRETRO_ABI_BREAK)); break; case RARCH_ACTION_STATE_FILL_PATHNAMES: rarch_init_savefile_paths(); strlcpy(global->bsv.movie_path, global->name.savefile, sizeof(global->bsv.movie_path)); if (!*global->name.base) return false; if (!*global->name.ups) fill_pathname_noext(global->name.ups, global->name.base, ".ups", sizeof(global->name.ups)); if (!*global->name.bps) fill_pathname_noext(global->name.bps, global->name.base, ".bps", sizeof(global->name.bps)); if (!*global->name.ips) fill_pathname_noext(global->name.ips, global->name.base, ".ips", sizeof(global->name.ips)); break; case RARCH_ACTION_STATE_NONE: default: return false; } return true; }
/** * drivers_init: * @flags : Bitmask of drivers to initialize. * * Initializes drivers. * @flags determines which drivers get initialized. **/ void drivers_init(int flags) { bool video_is_threaded = false; if (flags & DRIVER_VIDEO_MASK) video_driver_unset_own_driver(); if (flags & DRIVER_AUDIO_MASK) audio_driver_unset_own_driver(); if (flags & DRIVER_INPUT_MASK) input_driver_unset_own_driver(); if (flags & DRIVER_CAMERA_MASK) camera_driver_ctl(RARCH_CAMERA_CTL_UNSET_OWN_DRIVER, NULL); if (flags & DRIVER_LOCATION_MASK) location_driver_ctl(RARCH_LOCATION_CTL_UNSET_OWN_DRIVER, NULL); if (flags & DRIVER_WIFI_MASK) wifi_driver_ctl(RARCH_WIFI_CTL_UNSET_OWN_DRIVER, NULL); #ifdef HAVE_MENU /* By default, we want the menu to persist through driver reinits. */ menu_driver_ctl(RARCH_MENU_CTL_SET_OWN_DRIVER, NULL); #endif if (flags & (DRIVER_VIDEO_MASK | DRIVER_AUDIO_MASK)) driver_adjust_system_rates(); if (flags & DRIVER_VIDEO_MASK) { struct retro_hw_render_callback *hwr = video_driver_get_hw_context(); video_driver_monitor_reset(); video_driver_init(&video_is_threaded); if (!video_driver_is_video_cache_context_ack() && hwr->context_reset) hwr->context_reset(); video_driver_unset_video_cache_context_ack(); rarch_ctl(RARCH_CTL_SET_FRAME_TIME_LAST, NULL); } if (flags & DRIVER_AUDIO_MASK) { audio_driver_init(); audio_driver_new_devices_list(); } /* Only initialize camera driver if we're ever going to use it. */ if ((flags & DRIVER_CAMERA_MASK) && camera_driver_ctl(RARCH_CAMERA_CTL_IS_ACTIVE, NULL)) camera_driver_ctl(RARCH_CAMERA_CTL_INIT, NULL); /* Only initialize location driver if we're ever going to use it. */ if ((flags & DRIVER_LOCATION_MASK) && location_driver_ctl(RARCH_LOCATION_CTL_IS_ACTIVE, NULL)) init_location(); core_info_init_current_core(); #ifdef HAVE_MENU if (flags & DRIVER_VIDEO_MASK) { if (flags & DRIVER_MENU_MASK) menu_driver_init(video_is_threaded); } #endif if (flags & (DRIVER_VIDEO_MASK | DRIVER_AUDIO_MASK)) { /* Keep non-throttled state as good as possible. */ if (input_driver_is_nonblock_state()) driver_set_nonblock_state(); } if (flags & DRIVER_LED_MASK) { led_driver_init(); } if (flags & DRIVER_MIDI_MASK) midi_driver_init(); }
/** * runloop_iterate: * * Run Libretro core in RetroArch for one frame. * * Returns: 0 on success, 1 if we have to wait until * button input in order to wake up the loop, * -1 if we forcibly quit out of the RetroArch iteration loop. **/ int runloop_iterate(unsigned *sleep_ms) { unsigned i; event_cmd_state_t cmd; retro_time_t current, target, to_sleep_ms; event_cmd_state_t *cmd_ptr = &cmd; static retro_time_t frame_limit_minimum_time = 0.0; static retro_time_t frame_limit_last_time = 0.0; static retro_input_t last_input = 0; settings_t *settings = config_get_ptr(); cmd.state[1] = last_input; cmd.state[0] = input_keys_pressed(); last_input = cmd.state[0]; runloop_ctl(RUNLOOP_CTL_UNSET_FRAME_TIME_LAST, NULL); if (runloop_ctl(RUNLOOP_CTL_SHOULD_SET_FRAME_LIMIT, NULL)) { struct retro_system_av_info *av_info = video_viewport_get_system_av_info(); float fastforward_ratio = (settings->fastforward_ratio == 0.0f) ? 1.0f : settings->fastforward_ratio; frame_limit_last_time = cpu_features_get_time_usec(); frame_limit_minimum_time = (retro_time_t)roundf(1000000.0f / (av_info->timing.fps * fastforward_ratio)); runloop_ctl(RUNLOOP_CTL_UNSET_FRAME_LIMIT, NULL); } if (input_driver_is_flushing_input()) { input_driver_unset_flushing_input(); if (cmd.state[0]) { cmd.state[0] = 0; /* If core was paused before entering menu, evoke * pause toggle to wake it up. */ if (runloop_ctl(RUNLOOP_CTL_IS_PAUSED, NULL)) BIT64_SET(cmd.state[0], RARCH_PAUSE_TOGGLE); input_driver_set_flushing_input(); } } if (runloop_frame_time.callback) { /* Updates frame timing if frame timing callback is in use by the core. * Limits frame time if fast forward ratio throttle is enabled. */ retro_time_t current = cpu_features_get_time_usec(); retro_time_t delta = current - runloop_frame_time_last; bool is_locked_fps = (runloop_ctl(RUNLOOP_CTL_IS_PAUSED, NULL) || input_driver_is_nonblock_state()) | !!recording_driver_get_data_ptr(); if (!runloop_frame_time_last || is_locked_fps) delta = runloop_frame_time.reference; if (!is_locked_fps && runloop_ctl(RUNLOOP_CTL_IS_SLOWMOTION, NULL)) delta /= settings->slowmotion_ratio; runloop_frame_time_last = current; if (is_locked_fps) runloop_frame_time_last = 0; runloop_frame_time.callback(delta); } cmd.state[2] = cmd.state[0] & ~cmd.state[1]; /* trigger */ if (runloop_cmd_triggered(cmd_ptr, RARCH_OVERLAY_NEXT)) command_event(CMD_EVENT_OVERLAY_NEXT, NULL); if (runloop_cmd_triggered(cmd_ptr, RARCH_FULLSCREEN_TOGGLE_KEY)) { bool fullscreen_toggled = !runloop_ctl(RUNLOOP_CTL_IS_PAUSED, NULL); #ifdef HAVE_MENU fullscreen_toggled = fullscreen_toggled || menu_driver_ctl(RARCH_MENU_CTL_IS_ALIVE, NULL); #endif if (fullscreen_toggled) command_event(CMD_EVENT_FULLSCREEN_TOGGLE, NULL); } if (runloop_cmd_triggered(cmd_ptr, RARCH_GRAB_MOUSE_TOGGLE)) command_event(CMD_EVENT_GRAB_MOUSE_TOGGLE, NULL); #ifdef HAVE_MENU if (runloop_cmd_menu_press(cmd_ptr) || rarch_ctl(RARCH_CTL_IS_DUMMY_CORE, NULL)) { if (menu_driver_ctl(RARCH_MENU_CTL_IS_ALIVE, NULL)) { if (rarch_ctl(RARCH_CTL_IS_INITED, NULL) && !rarch_ctl(RARCH_CTL_IS_DUMMY_CORE, NULL)) rarch_ctl(RARCH_CTL_MENU_RUNNING_FINISHED, NULL); } else rarch_ctl(RARCH_CTL_MENU_RUNNING, NULL); } #endif #ifdef HAVE_OVERLAY runloop_iterate_linefeed_overlay(settings); #endif if (runloop_iterate_time_to_exit( runloop_cmd_press(cmd_ptr, RARCH_QUIT_KEY)) != 1) { frame_limit_last_time = 0.0; return -1; } #ifdef HAVE_MENU if (menu_driver_ctl(RARCH_MENU_CTL_IS_ALIVE, NULL)) { menu_ctx_iterate_t iter; bool focused = runloop_is_focused() && !ui_companion_is_on_foreground(); bool is_idle = runloop_ctl(RUNLOOP_CTL_IS_IDLE, NULL); enum menu_action action = (enum menu_action) menu_input_frame_retropad(cmd.state[0], cmd.state[2]); iter.action = action; if (!menu_driver_ctl(RARCH_MENU_CTL_ITERATE, &iter)) rarch_ctl(RARCH_CTL_MENU_RUNNING_FINISHED, NULL); if (focused || !is_idle) menu_driver_ctl(RARCH_MENU_CTL_RENDER, NULL); if (!focused || is_idle) { *sleep_ms = 10; return 1; } if (!settings->menu.throttle_framerate) { if (!settings->fastforward_ratio) return 0; } goto end; } #endif if (!runloop_check_state(&cmd, &runloop_shader_dir)) { /* RetroArch has been paused. */ core_poll(); *sleep_ms = 10; return 1; } #if defined(HAVE_THREADS) autosave_lock(); #endif #ifdef HAVE_NETPLAY netplay_driver_ctl(RARCH_NETPLAY_CTL_PRE_FRAME, NULL); #endif if (bsv_movie_ctl(BSV_MOVIE_CTL_IS_INITED, NULL)) bsv_movie_ctl(BSV_MOVIE_CTL_SET_FRAME_START, NULL); camera_driver_ctl(RARCH_CAMERA_CTL_POLL, NULL); /* Update binds for analog dpad modes. */ for (i = 0; i < settings->input.max_users; i++) { if (!settings->input.analog_dpad_mode[i]) continue; input_push_analog_dpad(settings->input.binds[i], settings->input.analog_dpad_mode[i]); input_push_analog_dpad(settings->input.autoconf_binds[i], settings->input.analog_dpad_mode[i]); } if ((settings->video.frame_delay > 0) && !input_driver_is_nonblock_state()) retro_sleep(settings->video.frame_delay); core_run(); #ifdef HAVE_CHEEVOS cheevos_test(); #endif for (i = 0; i < settings->input.max_users; i++) { if (!settings->input.analog_dpad_mode[i]) continue; input_pop_analog_dpad(settings->input.binds[i]); input_pop_analog_dpad(settings->input.autoconf_binds[i]); } if (bsv_movie_ctl(BSV_MOVIE_CTL_IS_INITED, NULL)) bsv_movie_ctl(BSV_MOVIE_CTL_SET_FRAME_END, NULL); #ifdef HAVE_NETPLAY netplay_driver_ctl(RARCH_NETPLAY_CTL_POST_FRAME, NULL); #endif #if defined(HAVE_THREADS) autosave_unlock(); #endif if (!settings->fastforward_ratio) return 0; #ifdef HAVE_MENU end: #endif current = cpu_features_get_time_usec(); target = frame_limit_last_time + frame_limit_minimum_time; to_sleep_ms = (target - current) / 1000; if (to_sleep_ms > 0) { *sleep_ms = (unsigned)to_sleep_ms; /* Combat jitter a bit. */ frame_limit_last_time += frame_limit_minimum_time; return 1; } frame_limit_last_time = cpu_features_get_time_usec(); return 0; }