/** * menu_shader_manager_apply_changes: * * Apply shader state changes. **/ void menu_shader_manager_apply_changes(void) { #ifdef HAVE_SHADER_MANAGER unsigned shader_type; struct video_shader *shader = NULL; menu_driver_ctl(RARCH_MENU_CTL_SHADER_GET, &shader); if (!shader) return; shader_type = menu_shader_manager_get_type(shader); if (shader->passes && shader_type != RARCH_SHADER_NONE) { menu_shader_manager_save_preset(NULL, true); return; } /* Fall-back */ #if defined(HAVE_CG) || defined(HAVE_HLSL) || defined(HAVE_GLSL) shader_type = video_shader_parse_type("", DEFAULT_SHADER_TYPE); #endif if (shader_type == RARCH_SHADER_NONE) { #if defined(HAVE_GLSL) shader_type = RARCH_SHADER_GLSL; #elif defined(HAVE_CG) || defined(HAVE_HLSL) shader_type = RARCH_SHADER_CG; #endif } menu_shader_manager_set_preset(NULL, shader_type, NULL); #endif }
/** * main_exit: * * Cleanly exit RetroArch. * * Also saves configuration files to disk, * and (optionally) autosave state. **/ void main_exit(void *args) { settings_t *settings = config_get_ptr(); global_t *global = global_get_ptr(); event_command(EVENT_CMD_MENU_SAVE_CURRENT_CONFIG); if (global->inited.main) { #ifdef HAVE_MENU /* Do not want menu context to live any more. */ menu_driver_ctl(RARCH_MENU_CTL_UNSET_OWN_DRIVER, NULL); #endif rarch_main_deinit(); } event_command(EVENT_CMD_PERFCNT_REPORT_FRONTEND_LOG); #if defined(HAVE_LOGGER) && !defined(ANDROID) logger_shutdown(); #endif frontend_driver_deinit(args); frontend_driver_exitspawn(settings->libretro, sizeof(settings->libretro)); rarch_ctl(RARCH_CTL_DESTROY, NULL); ui_companion_driver_deinit(); frontend_driver_shutdown(false); driver_ctl(RARCH_DRIVER_CTL_DEINIT, NULL); ui_companion_driver_free(); frontend_driver_free(); }
/** * Before a refresh, we could have deleted a * file on disk, causing selection_ptr to * suddendly be out of range. * * Ensure it doesn't overflow. **/ static bool menu_entries_refresh(void *data) { size_t list_size; file_list_t *list = (file_list_t*)data; size_t selection = menu_navigation_get_selection(); menu_entries_build_scroll_indices(list); list_size = menu_entries_get_size(); if ((selection >= list_size) && list_size) { size_t idx = list_size - 1; menu_navigation_set_selection(idx); menu_driver_navigation_set(true); } else if (!list_size) { bool pending_push = true; menu_driver_ctl(MENU_NAVIGATION_CTL_CLEAR, &pending_push); } return true; }
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; }
static int menu_input_pointer_post_iterate( menu_file_list_cbs_t *cbs, menu_entry_t *entry, unsigned action) { static bool pointer_oldpressed[2]; static bool pointer_oldback = false; static int16_t start_x = 0; static int16_t start_y = 0; static int16_t pointer_old_x = 0; static int16_t pointer_old_y = 0; int ret = 0; bool check_overlay = false; menu_input_t *menu_input = menu_input_get_ptr(); settings_t *settings = config_get_ptr(); if (!menu_input || !settings) return -1; check_overlay = !settings->menu.pointer.enable; #ifdef HAVE_OVERLAY if (!check_overlay) check_overlay = (settings->input.overlay_enable && input_overlay_is_alive(NULL)); #endif if (check_overlay) return 0; if (menu_input->pointer.pressed[0]) { gfx_ctx_metrics_t metrics; float dpi; static float accel0 = 0.0f; static float accel1 = 0.0f; int16_t pointer_x = menu_input_pointer_state(MENU_POINTER_X_AXIS); int16_t pointer_y = menu_input_pointer_state(MENU_POINTER_Y_AXIS); metrics.type = DISPLAY_METRIC_DPI; metrics.value = &dpi; video_context_driver_get_metrics(&metrics); if (!pointer_oldpressed[0]) { menu_input->pointer.accel = 0; accel0 = 0; accel1 = 0; start_x = pointer_x; start_y = pointer_y; pointer_old_x = pointer_x; pointer_old_y = pointer_y; pointer_oldpressed[0] = true; } else if (abs(pointer_x - start_x) > (dpi / 10) || abs(pointer_y - start_y) > (dpi / 10)) { float s, delta_time; menu_input_ctl(MENU_INPUT_CTL_SET_POINTER_DRAGGED, NULL); menu_input->pointer.dx = pointer_x - pointer_old_x; menu_input->pointer.dy = pointer_y - pointer_old_y; pointer_old_x = pointer_x; pointer_old_y = pointer_y; menu_animation_ctl(MENU_ANIMATION_CTL_DELTA_TIME, &delta_time); s = (menu_input->pointer.dy * 550000000.0 ) / ( dpi * delta_time ); menu_input->pointer.accel = (accel0 + accel1 + s) / 3; accel0 = accel1; accel1 = menu_input->pointer.accel; } } else { if (pointer_oldpressed[0]) { if (!menu_input_ctl(MENU_INPUT_CTL_IS_POINTER_DRAGGED, NULL)) { menu_ctx_pointer_t point; point.x = start_x; point.y = start_y; point.ptr = menu_input->pointer.ptr; point.cbs = cbs; point.entry = entry; point.action = action; menu_driver_ctl(RARCH_MENU_CTL_POINTER_TAP, &point); ret = point.retcode; } pointer_oldpressed[0] = false; start_x = 0; start_y = 0; pointer_old_x = 0; pointer_old_y = 0; menu_input->pointer.dx = 0; menu_input->pointer.dy = 0; menu_input_ctl(MENU_INPUT_CTL_UNSET_POINTER_DRAGGED, NULL); } } if (menu_input->pointer.back) { if (!pointer_oldback) { size_t selection; pointer_oldback = true; menu_navigation_ctl(MENU_NAVIGATION_CTL_GET_SELECTION, &selection); menu_entry_action(entry, selection, MENU_ACTION_CANCEL); } } pointer_oldback = menu_input->pointer.back; return ret; }
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; }
/** * 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; static retro_input_t last_input = {0}; 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; 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].state) { cmd.state[0].state = 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].state, 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].state = cmd.state[0].state & ~cmd.state[1].state; /* 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)) { int ret = runloop_iterate_menu((enum menu_action) menu_input_frame_retropad(cmd.state[0], cmd.state[2]), sleep_ms); if (ret == -1) goto end; return ret; } #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; }
/** * menu_content_load_from_playlist: * @playlist : Playlist handle. * @idx : Index in playlist. * * Initializes core and loads content based on playlist entry. **/ static bool menu_content_load_from_playlist(void *data) { unsigned idx; const char *core_path = NULL; const char *path = NULL; menu_content_ctx_playlist_info_t *info = (menu_content_ctx_playlist_info_t *)data; content_playlist_t *playlist = NULL; if (!info) return false; playlist = (content_playlist_t*)info->data; idx = info->idx; if (!playlist) return false; content_playlist_get_index(playlist, idx, &path, NULL, &core_path, NULL, NULL, NULL); if (path && !string_is_empty(path)) { unsigned i; RFILE *fp = NULL; char *path_check = NULL; char *path_tolower = strdup(path); for (i = 0; i < strlen(path_tolower); ++i) path_tolower[i] = tolower(path_tolower[i]); if (strstr(path_tolower, ".zip")) strstr(path_tolower, ".zip")[4] = '\0'; else if (strstr(path_tolower, ".7z")) strstr(path_tolower, ".7z")[3] = '\0'; path_check = (char *) calloc(strlen(path_tolower) + 1, sizeof(char)); strncpy(path_check, path, strlen(path_tolower)); free(path_tolower); fp = retro_fopen(path_check, RFILE_MODE_READ, -1); free(path_check); if (!fp) goto error; retro_fclose(fp); } runloop_ctl(RUNLOOP_CTL_SET_LIBRETRO_PATH, (void*)core_path); if (path) menu_driver_ctl(RARCH_MENU_CTL_UNSET_LOAD_NO_CONTENT, NULL); else menu_driver_ctl(RARCH_MENU_CTL_SET_LOAD_NO_CONTENT, NULL); if (!event_cmd_ctl(EVENT_CMD_EXEC, (void*)path)) return false; event_cmd_ctl(EVENT_CMD_LOAD_CORE, NULL); return true; error: runloop_msg_queue_push("File could not be loaded.\n", 1, 100, true); return false; }
bool menu_driver_ctl(enum rarch_menu_ctl_state state, void *data) { static struct retro_system_info menu_driver_system; static bool menu_driver_pending_quick_menu = false; static bool menu_driver_pending_action = false; static bool menu_driver_prevent_populate = false; static bool menu_driver_load_no_content = false; static bool menu_driver_alive = false; static bool menu_driver_data_own = false; static bool menu_driver_pending_quit = false; static bool menu_driver_pending_shutdown = false; static playlist_t *menu_driver_playlist = NULL; static struct video_shader *menu_driver_shader = NULL; static menu_handle_t *menu_driver_data = NULL; static const menu_ctx_driver_t *menu_driver_ctx = NULL; static void *menu_userdata = NULL; settings_t *settings = config_get_ptr(); switch (state) { case RARCH_MENU_CTL_IS_PENDING_ACTION: if (!menu_driver_pending_action) return false; menu_driver_ctl(RARCH_MENU_CTL_UNSET_PENDING_ACTION, NULL); break; case RARCH_MENU_CTL_SET_PENDING_ACTION: menu_driver_pending_action = true; break; case RARCH_MENU_CTL_UNSET_PENDING_ACTION: menu_driver_pending_action = false; break; case RARCH_MENU_CTL_DRIVER_DATA_GET: { menu_handle_t **driver_data = (menu_handle_t**)data; if (!driver_data) return false; *driver_data = menu_driver_data; } break; case RARCH_MENU_CTL_IS_PENDING_QUICK_MENU: return menu_driver_pending_quick_menu; case RARCH_MENU_CTL_SET_PENDING_QUICK_MENU: menu_driver_pending_quick_menu = true; break; case RARCH_MENU_CTL_UNSET_PENDING_QUICK_MENU: menu_driver_pending_quick_menu = false; break; case RARCH_MENU_CTL_IS_PENDING_QUIT: return menu_driver_pending_quit; case RARCH_MENU_CTL_SET_PENDING_QUIT: menu_driver_pending_quit = true; break; case RARCH_MENU_CTL_UNSET_PENDING_QUIT: menu_driver_pending_quit = false; break; case RARCH_MENU_CTL_IS_PENDING_SHUTDOWN: return menu_driver_pending_shutdown; case RARCH_MENU_CTL_SET_PENDING_SHUTDOWN: menu_driver_pending_shutdown = true; break; case RARCH_MENU_CTL_UNSET_PENDING_SHUTDOWN: menu_driver_pending_shutdown = false; break; case RARCH_MENU_CTL_DESTROY: menu_driver_pending_quick_menu = false; menu_driver_pending_action = false; menu_driver_pending_quit = false; menu_driver_pending_shutdown = false; menu_driver_prevent_populate = false; menu_driver_load_no_content = false; menu_driver_alive = false; menu_driver_data_own = false; menu_driver_ctx = NULL; menu_userdata = NULL; break; case RARCH_MENU_CTL_PLAYLIST_FREE: if (menu_driver_playlist) playlist_free(menu_driver_playlist); menu_driver_playlist = NULL; break; case RARCH_MENU_CTL_FIND_DRIVER: { int i; driver_ctx_info_t drv; settings_t *settings = config_get_ptr(); drv.label = "menu_driver"; drv.s = settings->menu.driver; driver_ctl(RARCH_DRIVER_CTL_FIND_INDEX, &drv); i = drv.len; if (i >= 0) menu_driver_ctx = (const menu_ctx_driver_t*) menu_driver_find_handle(i); else { unsigned d; RARCH_WARN("Couldn't find any menu driver named \"%s\"\n", settings->menu.driver); RARCH_LOG_OUTPUT("Available menu drivers are:\n"); for (d = 0; menu_driver_find_handle(d); d++) RARCH_LOG_OUTPUT("\t%s\n", menu_driver_find_ident(d)); RARCH_WARN("Going to default to first menu driver...\n"); menu_driver_ctx = (const menu_ctx_driver_t*) menu_driver_find_handle(0); if (!menu_driver_ctx) { retroarch_fail(1, "find_menu_driver()"); return false; } } } break; case RARCH_MENU_CTL_PLAYLIST_INIT: { const char *path = (const char*)data; if (string_is_empty(path)) return false; menu_driver_playlist = playlist_init(path, COLLECTION_SIZE); } break; case RARCH_MENU_CTL_PLAYLIST_GET: { playlist_t **playlist = (playlist_t**)data; if (!playlist) return false; *playlist = menu_driver_playlist; } break; case RARCH_MENU_CTL_SYSTEM_INFO_GET: { struct retro_system_info **system = (struct retro_system_info**)data; if (!system) return false; *system = &menu_driver_system; } break; case RARCH_MENU_CTL_SYSTEM_INFO_DEINIT: libretro_free_system_info(&menu_driver_system); memset(&menu_driver_system, 0, sizeof(struct retro_system_info)); break; case RARCH_MENU_CTL_RENDER_MESSAGEBOX: if (menu_driver_ctx->render_messagebox) menu_driver_ctx->render_messagebox(menu_userdata, menu_driver_data->menu_state.msg); break; case RARCH_MENU_CTL_BLIT_RENDER: if (menu_driver_ctx->render) menu_driver_ctx->render(menu_userdata); break; case RARCH_MENU_CTL_RENDER: if (!menu_driver_data) return false; if (BIT64_GET(menu_driver_data->state, MENU_STATE_RENDER_FRAMEBUFFER) != BIT64_GET(menu_driver_data->state, MENU_STATE_RENDER_MESSAGEBOX)) BIT64_SET(menu_driver_data->state, MENU_STATE_RENDER_FRAMEBUFFER); if (BIT64_GET(menu_driver_data->state, MENU_STATE_RENDER_FRAMEBUFFER)) menu_display_set_framebuffer_dirty_flag(); if (BIT64_GET(menu_driver_data->state, MENU_STATE_RENDER_MESSAGEBOX) && !string_is_empty(menu_driver_data->menu_state.msg)) { menu_driver_ctl(RARCH_MENU_CTL_RENDER_MESSAGEBOX, NULL); if (ui_companion_is_on_foreground()) { const ui_companion_driver_t *ui = ui_companion_get_ptr(); if (ui->render_messagebox) ui->render_messagebox(menu_driver_data->menu_state.msg); } } if (BIT64_GET(menu_driver_data->state, MENU_STATE_BLIT)) { menu_animation_ctl(MENU_ANIMATION_CTL_UPDATE_TIME, NULL); menu_driver_ctl(RARCH_MENU_CTL_BLIT_RENDER, NULL); } if (menu_driver_ctl(RARCH_MENU_CTL_IS_ALIVE, NULL) && !runloop_ctl(RUNLOOP_CTL_IS_IDLE, NULL)) menu_display_libretro(); menu_driver_ctl(RARCH_MENU_CTL_SET_TEXTURE, NULL); menu_driver_data->state = 0; break; case RARCH_MENU_CTL_SHADER_DEINIT: #ifdef HAVE_SHADER_MANAGER if (menu_driver_shader) free(menu_driver_shader); menu_driver_shader = NULL; #endif break; case RARCH_MENU_CTL_SHADER_INIT: #ifdef HAVE_SHADER_MANAGER menu_driver_shader = (struct video_shader*) calloc(1, sizeof(struct video_shader)); if (!menu_driver_shader) return false; #endif break; case RARCH_MENU_CTL_SHADER_GET: { struct video_shader **shader = (struct video_shader**)data; if (!shader) return false; *shader = menu_driver_shader; } break; case RARCH_MENU_CTL_FRAME: if (!menu_driver_alive) return false; if (menu_driver_ctx->frame) menu_driver_ctx->frame(menu_userdata); break; case RARCH_MENU_CTL_SET_PREVENT_POPULATE: menu_driver_prevent_populate = true; break; case RARCH_MENU_CTL_UNSET_PREVENT_POPULATE: menu_driver_prevent_populate = false; break; case RARCH_MENU_CTL_IS_PREVENT_POPULATE: return menu_driver_prevent_populate; case RARCH_MENU_CTL_SET_TOGGLE: menu_driver_toggle(true); break; case RARCH_MENU_CTL_UNSET_TOGGLE: menu_driver_toggle(false); break; case RARCH_MENU_CTL_SET_ALIVE: menu_driver_alive = true; break; case RARCH_MENU_CTL_UNSET_ALIVE: menu_driver_alive = false; break; case RARCH_MENU_CTL_IS_ALIVE: return menu_driver_alive; case RARCH_MENU_CTL_SET_OWN_DRIVER: menu_driver_data_own = true; break; case RARCH_MENU_CTL_UNSET_OWN_DRIVER: if (!content_is_inited()) return false; menu_driver_data_own = false; break; case RARCH_MENU_CTL_SET_TEXTURE: if (menu_driver_ctx->set_texture) menu_driver_ctx->set_texture(); break; case RARCH_MENU_CTL_IS_SET_TEXTURE: if (!menu_driver_ctx) return false; return menu_driver_ctx->set_texture; case RARCH_MENU_CTL_OWNS_DRIVER: return menu_driver_data_own; case RARCH_MENU_CTL_DEINIT: menu_driver_ctl(RARCH_MENU_CTL_CONTEXT_DESTROY, NULL); if (menu_driver_ctl(RARCH_MENU_CTL_OWNS_DRIVER, NULL)) return true; if (menu_driver_data) { menu_driver_ctl(RARCH_MENU_CTL_PLAYLIST_FREE, NULL); menu_shader_free(menu_driver_data); menu_input_ctl(MENU_INPUT_CTL_DEINIT, NULL); menu_navigation_ctl(MENU_NAVIGATION_CTL_DEINIT, NULL); if (menu_driver_ctx && menu_driver_ctx->free) menu_driver_ctx->free(menu_userdata); if (menu_userdata) free(menu_userdata); menu_userdata = NULL; menu_driver_ctl(RARCH_MENU_CTL_SYSTEM_INFO_DEINIT, NULL); menu_display_deinit(); menu_entries_ctl(MENU_ENTRIES_CTL_DEINIT, NULL); command_event(CMD_EVENT_HISTORY_DEINIT, NULL); core_info_deinit_list(); core_info_free_current_core(); free(menu_driver_data); } menu_driver_data = NULL; break; case RARCH_MENU_CTL_INIT: if (menu_driver_data) return true; menu_driver_data = (menu_handle_t*) menu_driver_ctx->init(&menu_userdata); if (!menu_driver_data || !menu_init(menu_driver_data)) { retroarch_fail(1, "init_menu()"); return false; } strlcpy(settings->menu.driver, menu_driver_ctx->ident, sizeof(settings->menu.driver)); if (menu_driver_ctx->lists_init) { if (!menu_driver_ctx->lists_init(menu_driver_data)) { retroarch_fail(1, "init_menu()"); return false; } } break; case RARCH_MENU_CTL_LOAD_NO_CONTENT_GET: { bool **ptr = (bool**)data; if (!ptr) return false; *ptr = (bool*)&menu_driver_load_no_content; } break; case RARCH_MENU_CTL_HAS_LOAD_NO_CONTENT: return menu_driver_load_no_content; case RARCH_MENU_CTL_SET_LOAD_NO_CONTENT: menu_driver_load_no_content = true; break; case RARCH_MENU_CTL_UNSET_LOAD_NO_CONTENT: menu_driver_load_no_content = false; break; case RARCH_MENU_CTL_NAVIGATION_INCREMENT: if (menu_driver_ctx->navigation_increment) menu_driver_ctx->navigation_increment(menu_userdata); break; case RARCH_MENU_CTL_NAVIGATION_DECREMENT: if (menu_driver_ctx->navigation_decrement) menu_driver_ctx->navigation_decrement(menu_userdata); break; case RARCH_MENU_CTL_NAVIGATION_SET: { bool *scroll = (bool*)data; if (!scroll) return false; if (menu_driver_ctx->navigation_set) menu_driver_ctx->navigation_set(menu_userdata, *scroll); } break; case RARCH_MENU_CTL_NAVIGATION_SET_LAST: if (menu_driver_ctx->navigation_set_last) menu_driver_ctx->navigation_set_last(menu_userdata); break; case RARCH_MENU_CTL_NAVIGATION_ASCEND_ALPHABET: { size_t *ptr_out = (size_t*)data; if (!ptr_out) return false; if (menu_driver_ctx->navigation_ascend_alphabet) menu_driver_ctx->navigation_ascend_alphabet( menu_userdata, ptr_out); } case RARCH_MENU_CTL_NAVIGATION_DESCEND_ALPHABET: { size_t *ptr_out = (size_t*)data; if (!ptr_out) return false; if (menu_driver_ctx->navigation_descend_alphabet) menu_driver_ctx->navigation_descend_alphabet( menu_userdata, ptr_out); } break; case RARCH_MENU_CTL_NAVIGATION_CLEAR: { bool *pending_push = (bool*)data; if (!pending_push) return false; if (menu_driver_ctx->navigation_clear) menu_driver_ctx->navigation_clear( menu_userdata, pending_push); } break; case RARCH_MENU_CTL_POPULATE_ENTRIES: { menu_displaylist_info_t *info = (menu_displaylist_info_t*)data; if (!info) return false; if (menu_driver_ctx->populate_entries) menu_driver_ctx->populate_entries( menu_userdata, info->path, info->label, info->type); } break; case RARCH_MENU_CTL_LIST_GET_ENTRY: { menu_ctx_list_t *list = (menu_ctx_list_t*)data; if (!menu_driver_ctx || !menu_driver_ctx->list_get_entry) { list->entry = NULL; return false; } list->entry = menu_driver_ctx->list_get_entry(menu_userdata, list->type, list->idx); } break; case RARCH_MENU_CTL_LIST_GET_SIZE: { menu_ctx_list_t *list = (menu_ctx_list_t*)data; if (!menu_driver_ctx || !menu_driver_ctx->list_get_size) { list->size = 0; return false; } list->size = menu_driver_ctx->list_get_size(menu_userdata, list->type); } break; case RARCH_MENU_CTL_LIST_GET_SELECTION: { menu_ctx_list_t *list = (menu_ctx_list_t*)data; if (!menu_driver_ctx || !menu_driver_ctx->list_get_selection) { list->selection = 0; return false; } list->selection = menu_driver_ctx->list_get_selection(menu_userdata); } break; case RARCH_MENU_CTL_LIST_FREE: { menu_ctx_list_t *list = (menu_ctx_list_t*)data; if (menu_driver_ctx) { if (menu_driver_ctx->list_free) menu_driver_ctx->list_free(list->list, list->idx, list->list_size); } if (list->list) { file_list_free_userdata (list->list, list->idx); file_list_free_actiondata(list->list, list->idx); } } break; case RARCH_MENU_CTL_LIST_PUSH: { menu_ctx_displaylist_t *disp_list = (menu_ctx_displaylist_t*)data; if (menu_driver_ctx->list_push) if (menu_driver_ctx->list_push(menu_driver_data, menu_userdata, disp_list->info, disp_list->type) == 0) return true; } return false; case RARCH_MENU_CTL_LIST_CLEAR: { file_list_t *list = (file_list_t*)data; if (!list) return false; if (menu_driver_ctx->list_clear) menu_driver_ctx->list_clear(list); } break; case RARCH_MENU_CTL_TOGGLE: { bool *latch = (bool*)data; if (!latch) return false; if (menu_driver_ctx && menu_driver_ctx->toggle) menu_driver_ctx->toggle(menu_userdata, *latch); } break; case RARCH_MENU_CTL_REFRESH: { #if 0 bool refresh = false; menu_entries_ctl(MENU_ENTRIES_CTL_LIST_DEINIT, NULL); menu_entries_ctl(MENU_ENTRIES_CTL_SETTINGS_DEINIT, NULL); menu_entries_ctl(MENU_ENTRIES_CTL_INIT, NULL); menu_entries_ctl(MENU_ENTRIES_CTL_SET_REFRESH, &refresh); #endif } break; case RARCH_MENU_CTL_CONTEXT_RESET: if (!menu_driver_ctx || !menu_driver_ctx->context_reset) return false; menu_driver_ctx->context_reset(menu_userdata); break; case RARCH_MENU_CTL_CONTEXT_DESTROY: if (!menu_driver_ctx || !menu_driver_ctx->context_destroy) return false; menu_driver_ctx->context_destroy(menu_userdata); break; case RARCH_MENU_CTL_SHADER_MANAGER_INIT: menu_shader_manager_init(menu_driver_data); break; case RARCH_MENU_CTL_LIST_SET_SELECTION: { file_list_t *list = (file_list_t*)data; if (!list) return false; if (!menu_driver_ctx || !menu_driver_ctx->list_set_selection) return false; menu_driver_ctx->list_set_selection(menu_userdata, list); } break; case RARCH_MENU_CTL_LIST_CACHE: { menu_ctx_list_t *list = (menu_ctx_list_t*)data; if (!list || !menu_driver_ctx || !menu_driver_ctx->list_cache) return false; menu_driver_ctx->list_cache(menu_userdata, list->type, list->action); } break; case RARCH_MENU_CTL_LIST_INSERT: { menu_ctx_list_t *list = (menu_ctx_list_t*)data; if (!list || !menu_driver_ctx || !menu_driver_ctx->list_insert) return false; menu_driver_ctx->list_insert(menu_userdata, list->list, list->path, list->label, list->idx); } break; case RARCH_MENU_CTL_LOAD_IMAGE: { menu_ctx_load_image_t *load_image_info = (menu_ctx_load_image_t*)data; if (!menu_driver_ctx || !menu_driver_ctx->load_image) return false; return menu_driver_ctx->load_image(menu_userdata, load_image_info->data, load_image_info->type); } case RARCH_MENU_CTL_ITERATE: { bool retcode = false; menu_ctx_iterate_t *iterate = (menu_ctx_iterate_t*)data; if (menu_driver_ctl(RARCH_MENU_CTL_IS_PENDING_QUICK_MENU, NULL)) { menu_driver_ctl(RARCH_MENU_CTL_UNSET_PENDING_QUICK_MENU, NULL); menu_entries_flush_stack(NULL, MENU_SETTINGS); menu_display_set_msg_force(true); generic_action_ok_displaylist_push("", "", 0, 0, 0, ACTION_OK_DL_CONTENT_SETTINGS); if (menu_driver_ctl(RARCH_MENU_CTL_IS_PENDING_QUIT, NULL)) { menu_driver_ctl(RARCH_MENU_CTL_UNSET_PENDING_QUIT, NULL); return false; } return true; } if (menu_driver_ctl(RARCH_MENU_CTL_IS_PENDING_QUIT, NULL)) { menu_driver_ctl(RARCH_MENU_CTL_UNSET_PENDING_QUIT, NULL); return false; } if (menu_driver_ctl(RARCH_MENU_CTL_IS_PENDING_SHUTDOWN, NULL)) { menu_driver_ctl(RARCH_MENU_CTL_UNSET_PENDING_SHUTDOWN, NULL); if (!command_event(CMD_EVENT_QUIT, NULL)) return false; return true; } if (!menu_driver_ctx || !menu_driver_ctx->iterate) return false; if (menu_driver_ctl(RARCH_MENU_CTL_IS_PENDING_ACTION, &retcode)) { iterate->action = pending_iter.action; pending_iter.action = MENU_ACTION_NOOP; } if (menu_driver_ctx->iterate(menu_driver_data, menu_userdata, iterate->action) == -1) return false; } break; case RARCH_MENU_CTL_ENVIRONMENT: { menu_ctx_environment_t *menu_environ = (menu_ctx_environment_t*)data; if (menu_driver_ctx->environ_cb) { if (menu_driver_ctx->environ_cb(menu_environ->type, menu_environ->data, menu_userdata) == 0) return true; } } return false; case RARCH_MENU_CTL_POINTER_TAP: { menu_ctx_pointer_t *point = (menu_ctx_pointer_t*)data; if (!menu_driver_ctx || !menu_driver_ctx->pointer_tap) { point->retcode = 0; return false; } point->retcode = menu_driver_ctx->pointer_tap(menu_userdata, point->x, point->y, point->ptr, point->cbs, point->entry, point->action); } break; case RARCH_MENU_CTL_BIND_INIT: { menu_ctx_bind_t *bind = (menu_ctx_bind_t*)data; if (!menu_driver_ctx || !menu_driver_ctx->bind_init) { bind->retcode = 0; return false; } bind->retcode = menu_driver_ctx->bind_init( bind->cbs, bind->path, bind->label, bind->type, bind->idx, bind->elem0, bind->elem1, bind->label_hash, bind->menu_label_hash); } break; case RARCH_MENU_CTL_UPDATE_THUMBNAIL_PATH: { size_t selection; if (!menu_navigation_ctl(MENU_NAVIGATION_CTL_GET_SELECTION, &selection)) return false; if (!menu_driver_ctx || !menu_driver_ctx->update_thumbnail_path) return false; menu_driver_ctx->update_thumbnail_path(menu_userdata, selection); } break; case RARCH_MENU_CTL_UPDATE_THUMBNAIL_IMAGE: { if (!menu_driver_ctx || !menu_driver_ctx->update_thumbnail_image) return false; menu_driver_ctx->update_thumbnail_image(menu_userdata); } break; default: case RARCH_MENU_CTL_NONE: break; } return true; }
/* This sets up all the callback functions for a menu entry. * * OK : When we press the 'OK' button on an entry. * Cancel : When we press the 'Cancel' button on an entry. * Scan : When we press the 'Scan' button on an entry. * Start : When we press the 'Start' button on an entry. * Select : When we press the 'Select' button on an entry. * Info : When we press the 'Info' button on an entry. * Content Switch : ??? (TODO/FIXME - Kivutar should document this) * Up : when we press 'Up' on the D-pad while this entry is selected. * Down : when we press 'Down' on the D-pad while this entry is selected. * Left : when we press 'Left' on the D-pad while this entry is selected. * Right : when we press 'Right' on the D-pad while this entry is selected. * Deferred push : When pressing an entry results in spawning a new list, it waits until the next * frame to push this onto the stack. This function callback will then be invoked. * Refresh : What happens when the screen has to be refreshed. Does an entry have internal state * that needs to be rebuild? * Get value: Each entry has associated 'text', which we call the value. This function callback * lets us render that text. * Get title: Each entry can have a custom 'title'. * Label: Each entry has a label name. This function callback lets us render that label text. * Sublabel: each entry has a sublabel, which consists of one or more lines of additional information. * This function callback lets us render that text. */ void menu_cbs_init(void *data, menu_file_list_cbs_t *cbs, const char *path, const char *label, unsigned type, size_t idx) { menu_ctx_bind_t bind_info; const char *repr_label = NULL; const char *menu_label = NULL; uint32_t label_hash = 0; uint32_t menu_label_hash = 0; enum msg_hash_enums enum_idx = MSG_UNKNOWN; file_list_t *list = (file_list_t*)data; if (!list) return; menu_entries_get_last_stack(NULL, &menu_label, NULL, &enum_idx, NULL); if (!label || !menu_label) return; label_hash = msg_hash_calculate(label); menu_label_hash = msg_hash_calculate(menu_label); #ifdef DEBUG_LOG RARCH_LOG("\n"); #endif repr_label = (!string_is_empty(label)) ? label : path; #ifdef DEBUG_LOG if (cbs && cbs->enum_idx != MSG_UNKNOWN) RARCH_LOG("\t\t\tenum_idx %d [%s]\n", cbs->enum_idx, msg_hash_to_str(cbs->enum_idx)); #endif /* It will try to find a corresponding callback function inside * menu_cbs_ok.c, then map this callback to the entry. */ menu_cbs_init_bind_ok(cbs, path, label, type, idx, label_hash, menu_label_hash); menu_cbs_init_log(repr_label, "OK", cbs->action_ok_ident); /* It will try to find a corresponding callback function inside * menu_cbs_cancel.c, then map this callback to the entry. */ menu_cbs_init_bind_cancel(cbs, path, label, type, idx); menu_cbs_init_log(repr_label, "CANCEL", cbs->action_cancel_ident); /* It will try to find a corresponding callback function inside * menu_cbs_scan.c, then map this callback to the entry. */ menu_cbs_init_bind_scan(cbs, path, label, type, idx); menu_cbs_init_log(repr_label, "SCAN", cbs->action_scan_ident); /* It will try to find a corresponding callback function inside * menu_cbs_start.c, then map this callback to the entry. */ menu_cbs_init_bind_start(cbs, path, label, type, idx); menu_cbs_init_log(repr_label, "START", cbs->action_start_ident); /* It will try to find a corresponding callback function inside * menu_cbs_select.c, then map this callback to the entry. */ menu_cbs_init_bind_select(cbs, path, label, type, idx); menu_cbs_init_log(repr_label, "SELECT", cbs->action_select_ident); /* It will try to find a corresponding callback function inside * menu_cbs_info.c, then map this callback to the entry. */ menu_cbs_init_bind_info(cbs, path, label, type, idx); menu_cbs_init_log(repr_label, "INFO", cbs->action_info_ident); /* It will try to find a corresponding callback function inside * menu_cbs_bind_content_list_switch.c, then map this callback to the entry. */ menu_cbs_init_bind_content_list_switch(cbs, path, label, type, idx); menu_cbs_init_log(repr_label, "CONTENT SWITCH", cbs->action_content_list_switch_ident); /* It will try to find a corresponding callback function inside * menu_cbs_up.c, then map this callback to the entry. */ menu_cbs_init_bind_up(cbs, path, label, type, idx); menu_cbs_init_log(repr_label, "UP", cbs->action_up_ident); /* It will try to find a corresponding callback function inside * menu_cbs_down.c, then map this callback to the entry. */ menu_cbs_init_bind_down(cbs, path, label, type, idx); menu_cbs_init_log(repr_label, "DOWN", cbs->action_down_ident); /* It will try to find a corresponding callback function inside * menu_cbs_left.c, then map this callback to the entry. */ menu_cbs_init_bind_left(cbs, path, label, type, idx, menu_label, label_hash); menu_cbs_init_log(repr_label, "LEFT", cbs->action_left_ident); /* It will try to find a corresponding callback function inside * menu_cbs_right.c, then map this callback to the entry. */ menu_cbs_init_bind_right(cbs, path, label, type, idx, menu_label, label_hash); menu_cbs_init_log(repr_label, "RIGHT", cbs->action_right_ident); /* It will try to find a corresponding callback function inside * menu_cbs_deferred_push.c, then map this callback to the entry. */ menu_cbs_init_bind_deferred_push(cbs, path, label, type, idx, label_hash); menu_cbs_init_log(repr_label, "DEFERRED PUSH", cbs->action_deferred_push_ident); /* It will try to find a corresponding callback function inside * menu_cbs_refresh.c, then map this callback to the entry. */ menu_cbs_init_bind_refresh(cbs, path, label, type, idx); menu_cbs_init_log(repr_label, "REFRESH", cbs->action_refresh_ident); /* It will try to find a corresponding callback function inside * menu_cbs_get_string_representation.c, then map this callback to the entry. */ menu_cbs_init_bind_get_string_representation(cbs, path, label, type, idx); menu_cbs_init_log(repr_label, "GET VALUE", cbs->action_get_value_ident); /* It will try to find a corresponding callback function inside * menu_cbs_title.c, then map this callback to the entry. */ menu_cbs_init_bind_title(cbs, path, label, type, idx, label_hash); menu_cbs_init_log(repr_label, "GET TITLE", cbs->action_get_title_ident); /* It will try to find a corresponding callback function inside * menu_cbs_label.c, then map this callback to the entry. */ menu_cbs_init_bind_label(cbs, path, label, type, idx); menu_cbs_init_log(repr_label, "LABEL", cbs->action_label_ident); /* It will try to find a corresponding callback function inside * menu_cbs_sublabel.c, then map this callback to the entry. */ menu_cbs_init_bind_sublabel(cbs, path, label, type, idx); menu_cbs_init_log(repr_label, "SUBLABEL", cbs->action_sublabel_ident); bind_info.cbs = cbs; bind_info.path = path; bind_info.label = label; bind_info.type = type; bind_info.idx = idx; bind_info.label_hash = label_hash; menu_driver_ctl(RARCH_MENU_CTL_BIND_INIT, &bind_info); }
/** * menu_shader_manager_save_preset: * @basename : basename of preset * @apply : immediately set preset after saving * * Save a shader preset to disk. **/ bool menu_shader_manager_save_preset( const char *basename, bool apply, bool fullpath) { #ifdef HAVE_SHADER_MANAGER char buffer[PATH_MAX_LENGTH]; char config_directory[PATH_MAX_LENGTH]; char preset_path[PATH_MAX_LENGTH]; unsigned d, type = RARCH_SHADER_NONE; const char *dirs[3] = {0}; config_file_t *conf = NULL; bool ret = false; struct video_shader *shader = NULL; settings_t *settings = config_get_ptr(); menu_handle_t *menu = NULL; buffer[0] = config_directory[0] = '\0'; preset_path[0] = '\0'; if (!menu_driver_ctl(RARCH_MENU_CTL_DRIVER_DATA_GET, &menu)) { RARCH_ERR("Cannot save shader preset.\n"); return false; } menu_driver_ctl(RARCH_MENU_CTL_SHADER_GET, &shader); if (!shader) return false; type = menu_shader_manager_get_type(shader); if (type == RARCH_SHADER_NONE) return false; *config_directory = '\0'; if (basename) { strlcpy(buffer, basename, sizeof(buffer)); /* Append extension automatically as appropriate. */ if ( !strstr(basename, file_path_str(FILE_PATH_CGP_EXTENSION)) && !strstr(basename, file_path_str(FILE_PATH_GLSLP_EXTENSION)) && !strstr(basename, file_path_str(FILE_PATH_SLANGP_EXTENSION))) { switch (type) { case RARCH_SHADER_GLSL: strlcat(buffer, file_path_str(FILE_PATH_GLSLP_EXTENSION), sizeof(buffer)); break; case RARCH_SHADER_SLANG: strlcat(buffer, file_path_str(FILE_PATH_SLANGP_EXTENSION), sizeof(buffer)); break; case RARCH_SHADER_CG: strlcat(buffer, file_path_str(FILE_PATH_CGP_EXTENSION), sizeof(buffer)); break; } } } else { const char *conf_path = NULL; switch (type) { case RARCH_SHADER_GLSL: conf_path = default_glslp; break; case RARCH_SHADER_SLANG: conf_path = default_slangp; break; default: case RARCH_SHADER_CG: conf_path = default_cgp; break; } if (!string_is_empty(conf_path)) strlcpy(buffer, conf_path, sizeof(buffer)); } if (!path_is_empty(RARCH_PATH_CONFIG)) fill_pathname_basedir( config_directory, path_get(RARCH_PATH_CONFIG), sizeof(config_directory)); if (!fullpath) { dirs[0] = settings->directory.video_shader; dirs[1] = settings->directory.menu_config; dirs[2] = config_directory; } if (!(conf = (config_file_t*)config_file_new(NULL))) return false; video_shader_write_conf_cgp(conf, shader); if (!fullpath) { for (d = 0; d < ARRAY_SIZE(dirs); d++) { if (!*dirs[d]) continue; fill_pathname_join(preset_path, dirs[d], buffer, sizeof(preset_path)); if (config_file_write(conf, preset_path)) { RARCH_LOG("Saved shader preset to %s.\n", preset_path); if (apply) menu_shader_manager_set_preset(NULL, type, preset_path); ret = true; break; } else RARCH_LOG("Failed writing shader preset to %s.\n", preset_path); } } else { if (!string_is_empty(basename)) strlcpy(preset_path, buffer, sizeof(preset_path)); if (config_file_write(conf, preset_path)) { RARCH_LOG("Saved shader preset to %s.\n", preset_path); if (apply) menu_shader_manager_set_preset(NULL, type, preset_path); ret = true; } else RARCH_LOG("Failed writing shader preset to %s.\n", preset_path); } config_file_free(conf); if (ret) return true; RARCH_ERR("Failed to save shader preset. Make sure config directory" " and/or shader dir are writable.\n"); #endif return false; }
bool driver_ctl(enum driver_ctl_state state, void *data) { switch (state) { case RARCH_DRIVER_CTL_DEINIT: video_driver_destroy(); audio_driver_destroy(); input_driver_destroy(); #ifdef HAVE_MENU menu_driver_destroy(); #endif location_driver_ctl(RARCH_LOCATION_CTL_DESTROY, NULL); camera_driver_ctl(RARCH_CAMERA_CTL_DESTROY, NULL); wifi_driver_ctl(RARCH_WIFI_CTL_DESTROY, NULL); core_uninit_libretro_callbacks(); break; case RARCH_DRIVER_CTL_INIT_PRE: audio_driver_find_driver(); video_driver_find_driver(); input_driver_find_driver(); camera_driver_ctl(RARCH_CAMERA_CTL_FIND_DRIVER, NULL); wifi_driver_ctl(RARCH_WIFI_CTL_FIND_DRIVER, NULL); find_location_driver(); #ifdef HAVE_MENU menu_driver_ctl(RARCH_MENU_CTL_FIND_DRIVER, NULL); #endif break; case RARCH_DRIVER_CTL_SET_REFRESH_RATE: { float *hz = (float*)data; video_monitor_set_refresh_rate(*hz); audio_driver_monitor_set_rate(); driver_adjust_system_rates(); } break; case RARCH_DRIVER_CTL_UPDATE_SYSTEM_AV_INFO: { const struct retro_system_av_info **info = (const struct retro_system_av_info**)data; if (info) return driver_update_system_av_info(*info); } return false; case RARCH_DRIVER_CTL_FIND_FIRST: { driver_ctx_info_t *drv = (driver_ctx_info_t*)data; if (!drv) return false; return driver_find_first(drv->label, drv->s, drv->len); } case RARCH_DRIVER_CTL_FIND_LAST: { driver_ctx_info_t *drv = (driver_ctx_info_t*)data; if (!drv) return false; return driver_find_last(drv->label, drv->s, drv->len); } case RARCH_DRIVER_CTL_FIND_PREV: { driver_ctx_info_t *drv = (driver_ctx_info_t*)data; if (!drv) return false; return driver_find_prev(drv->label, drv->s, drv->len); } case RARCH_DRIVER_CTL_FIND_NEXT: { driver_ctx_info_t *drv = (driver_ctx_info_t*)data; if (!drv) return false; return driver_find_next(drv->label, drv->s, drv->len); } case RARCH_DRIVER_CTL_FIND_INDEX: { driver_ctx_info_t *drv = (driver_ctx_info_t*)data; if (!drv) return false; drv->len = driver_find_index(drv->label, drv->s); } break; case RARCH_DRIVER_CTL_NONE: default: break; } 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(); }
static void rmenu_render(void) { bool msg_force; uint64_t *frame_count; size_t begin, end, i, j, selection; struct font_params font_parms; char title[256] = {0}; char title_buf[256] = {0}; char title_msg[64] = {0}; menu_handle_t *menu = menu_driver_get_ptr(); size_t entries_end = menu_entries_get_end(); video_driver_ctl(RARCH_DISPLAY_CTL_GET_FRAME_COUNT, &frame_count); if (!menu_navigation_ctl(MENU_NAVIGATION_CTL_GET_SELECTION, &selection)) return; if (!menu) return; if (!render_normal) { render_normal = true; return; } menu_display_ctl(MENU_DISPLAY_CTL_MSG_FORCE, &msg_force); if (menu_entries_needs_refresh() && menu_driver_ctl(RARCH_MENU_CTL_IS_ALIVE, NULL) && !msg_force) return; menu_display_ctl(MENU_DISPLAY_CTL_UNSET_FRAMEBUFFER_DIRTY_FLAG, NULL); menu_animation_ctl(MENU_ANIMATION_CTL_CLEAR_ACTIVE, NULL); begin = (selection >= (ENTRIES_HEIGHT / 2)) ? (selection - (ENTRIES_HEIGHT / 2)) : 0; end = ((selection + ENTRIES_HEIGHT) <= entries_end) ? selection + ENTRIES_HEIGHT : entries_end; if (entries_end <= ENTRIES_HEIGHT) begin = 0; if (end - begin > ENTRIES_HEIGHT) end = begin + ENTRIES_HEIGHT; menu_entries_get_title(title, sizeof(title)); menu_animation_ticker_str(title_buf, RMENU_TERM_WIDTH, *frame_count / 15, title, true); font_parms.x = POSITION_EDGE_MIN + POSITION_OFFSET; font_parms.y = POSITION_EDGE_MIN + POSITION_RENDER_OFFSET - (POSITION_OFFSET*2); font_parms.scale = FONT_SIZE_NORMAL; font_parms.color = WHITE; font_parms.drop_mod = 0.0f; font_parms.drop_x = 0.0f; font_parms.drop_y = 0.0f; video_driver_set_osd_msg(title_buf, &font_parms, NULL); font_parms.x = POSITION_EDGE_MIN + POSITION_OFFSET; font_parms.y = POSITION_EDGE_MAX - (POSITION_OFFSET*2); font_parms.scale = FONT_SIZE_NORMAL; font_parms.color = WHITE; menu_entries_get_core_title(title_msg, sizeof(title_msg)); video_driver_set_osd_msg(title_msg, &font_parms, NULL); j = 0; for (i = begin; i < end; i++, j++) { char entry_path[PATH_MAX_LENGTH] = {0}; char entry_value[PATH_MAX_LENGTH] = {0}; char message[PATH_MAX_LENGTH] = {0}; char entry_title_buf[PATH_MAX_LENGTH] = {0}; char type_str_buf[PATH_MAX_LENGTH] = {0}; unsigned entry_spacing = menu_entry_get_spacing(i); bool entry_selected = menu_entry_is_currently_selected(i); menu_entry_get_value(i, entry_value, sizeof(entry_value)); menu_entry_get_path(i, entry_path, sizeof(entry_path)); menu_animation_ticker_str(entry_title_buf, RMENU_TERM_WIDTH - (entry_spacing + 1 + 2), *frame_count / 15, entry_path, entry_selected); menu_animation_ticker_str(type_str_buf, entry_spacing, *frame_count / 15, entry_value, entry_selected); snprintf(message, sizeof(message), "%c %s", entry_selected ? '>' : ' ', entry_title_buf); font_parms.x = POSITION_EDGE_MIN + POSITION_OFFSET; font_parms.y = POSITION_EDGE_MIN + POSITION_RENDER_OFFSET + (POSITION_OFFSET * j); font_parms.scale = FONT_SIZE_NORMAL; font_parms.color = WHITE; video_driver_set_osd_msg(message, &font_parms, NULL); font_parms.x = POSITION_EDGE_CENTER + POSITION_OFFSET; video_driver_set_osd_msg(type_str_buf, &font_parms, NULL); } }
void menu_shader_free(menu_handle_t *menu) { menu_driver_ctl(RARCH_MENU_CTL_SHADER_DEINIT, NULL); }
/** * task_load_content: * * Loads content into currently selected core. * Will also optionally push the content entry to the history playlist. * * Returns: true (1) if successful, otherwise false (0). **/ static bool task_load_content(content_ctx_info_t *content_info, content_information_ctx_t *content_ctx, bool launched_from_menu, enum content_mode_load mode, char **error_string) { char name[255]; char msg[255]; name[0] = msg[0] = '\0'; if (!content_load(content_info)) goto error; /* Push entry to top of history playlist */ if (_content_is_inited || content_does_not_need_content()) { char tmp[PATH_MAX_LENGTH]; struct retro_system_info *info = NULL; rarch_system_info_t *sys_info = NULL; tmp[0] = '\0'; runloop_ctl(RUNLOOP_CTL_SYSTEM_INFO_GET, &sys_info); if (sys_info) info = &sys_info->info; #ifdef HAVE_MENU if (launched_from_menu) menu_driver_ctl(RARCH_MENU_CTL_SYSTEM_INFO_GET, &info); #endif strlcpy(tmp, path_get(RARCH_PATH_CONTENT), sizeof(tmp)); if (!launched_from_menu) { /* Path can be relative here. * Ensure we're pushing absolute path. */ if (!string_is_empty(tmp)) path_resolve_realpath(tmp, sizeof(tmp)); } if (info && !string_is_empty(tmp)) { const char *core_path = NULL; const char *core_name = NULL; playlist_t *playlist_tmp = g_defaults.content_history; switch (path_is_media_type(tmp)) { case RARCH_CONTENT_MOVIE: #ifdef HAVE_FFMPEG playlist_tmp = g_defaults.video_history; core_name = "movieplayer"; core_path = "builtin"; #endif break; case RARCH_CONTENT_MUSIC: #ifdef HAVE_FFMPEG playlist_tmp = g_defaults.music_history; core_name = "musicplayer"; core_path = "builtin"; #endif break; case RARCH_CONTENT_IMAGE: #ifdef HAVE_IMAGEVIEWER playlist_tmp = g_defaults.image_history; core_name = "imageviewer"; core_path = "builtin"; #endif break; default: core_path = path_get(RARCH_PATH_CORE); core_name = info->library_name; break; } if (mode == CONTENT_MODE_LOAD_FROM_CLI) { settings_t *settings = config_get_ptr(); content_ctx->history_list_enable = settings->history_list_enable; } if ( content_ctx->history_list_enable && playlist_tmp && playlist_push( playlist_tmp, tmp, NULL, core_path, core_name, NULL, NULL) ) playlist_write_file(playlist_tmp); } } return true; error: if (launched_from_menu) { if (!path_is_empty(RARCH_PATH_CONTENT) && !string_is_empty(name)) { snprintf(msg, sizeof(msg), "%s %s.\n", msg_hash_to_str(MSG_FAILED_TO_LOAD), name); if (error_string) free(error_string); *error_string = strdup(msg); } } return false; }
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 }
/** * menu_shader_manager_init: * * Initializes shader manager. **/ void menu_shader_manager_init(void) { #ifdef HAVE_SHADER_MANAGER struct video_shader *shader = NULL; config_file_t *conf = NULL; settings_t *settings = config_get_ptr(); const char *config_path = path_get(RARCH_PATH_CONFIG); menu_driver_ctl(RARCH_MENU_CTL_SHADER_GET, &shader); /* In a multi-config setting, we can't have * conflicts on menu.cgp/menu.glslp. */ if (config_path) { fill_pathname_base_ext(default_glslp, config_path, file_path_str(FILE_PATH_GLSLP_EXTENSION), sizeof(default_glslp)); fill_pathname_base_ext(default_cgp, config_path, file_path_str(FILE_PATH_CGP_EXTENSION), sizeof(default_cgp)); fill_pathname_base_ext(default_slangp, config_path, file_path_str(FILE_PATH_SLANGP_EXTENSION), sizeof(default_slangp)); } else { strlcpy(default_glslp, "menu.glslp", sizeof(default_glslp)); strlcpy(default_cgp, "menu.cgp", sizeof(default_cgp)); strlcpy(default_slangp, "menu.slangp", sizeof(default_slangp)); } switch (msg_hash_to_file_type(msg_hash_calculate( path_get_extension(settings->path.shader)))) { case FILE_TYPE_SHADER_PRESET_GLSLP: case FILE_TYPE_SHADER_PRESET_CGP: case FILE_TYPE_SHADER_PRESET_SLANGP: conf = config_file_new(settings->path.shader); if (conf) { if (video_shader_read_conf_cgp(conf, shader)) { video_shader_resolve_relative(shader, settings->path.shader); video_shader_resolve_parameters(conf, shader); } config_file_free(conf); } break; case FILE_TYPE_SHADER_GLSL: case FILE_TYPE_SHADER_CG: case FILE_TYPE_SHADER_SLANG: strlcpy(shader->pass[0].source.path, settings->path.shader, sizeof(shader->pass[0].source.path)); shader->passes = 1; break; default: { char preset_path[PATH_MAX_LENGTH]; const char *shader_dir = *settings->directory.video_shader ? settings->directory.video_shader : settings->directory.system; preset_path[0] = '\0'; fill_pathname_join(preset_path, shader_dir, "menu.glslp", sizeof(preset_path)); conf = config_file_new(preset_path); if (!conf) { fill_pathname_join(preset_path, shader_dir, "menu.cgp", sizeof(preset_path)); conf = config_file_new(preset_path); } if (!conf) { fill_pathname_join(preset_path, shader_dir, "menu.slangp", sizeof(preset_path)); conf = config_file_new(preset_path); } if (conf) { if (video_shader_read_conf_cgp(conf, shader)) { video_shader_resolve_relative(shader, preset_path); video_shader_resolve_parameters(conf, shader); } config_file_free(conf); } } break; } #endif }
static int general_push(menu_displaylist_info_t *info, unsigned id, enum menu_displaylist_ctl_state state) { struct retro_system_info *system_menu = NULL; settings_t *settings = config_get_ptr(); rarch_system_info_t *system = NULL; core_info_list_t *list = NULL; menu_handle_t *menu = NULL; if (!menu_driver_ctl(RARCH_MENU_CTL_DRIVER_DATA_GET, &menu)) return menu_cbs_exit(); core_info_ctl(CORE_INFO_CTL_LIST_GET, &list); menu_driver_ctl(RARCH_MENU_CTL_SYSTEM_INFO_GET, &system_menu); runloop_ctl(RUNLOOP_CTL_SYSTEM_INFO_GET, &system); switch (id) { case PUSH_DEFAULT: case PUSH_DETECT_CORE_LIST: break; default: fill_pathname_join(info->path, menu->scratch2_buf, menu->scratch_buf, sizeof(info->path)); fill_pathname_join(info->label, menu->scratch2_buf, menu->scratch_buf, sizeof(info->label)); break; } info->type_default = MENU_FILE_PLAIN; switch (id) { case PUSH_ARCHIVE_OPEN_DETECT_CORE: case PUSH_ARCHIVE_OPEN: case PUSH_DEFAULT: info->setting = menu_setting_find(info->label); break; default: break; } switch (id) { case PUSH_ARCHIVE_OPEN_DETECT_CORE: if (!string_is_empty(list->all_ext)) strlcpy(info->exts, list->all_ext, sizeof(info->exts)); else if (system_menu->valid_extensions) { if (*system_menu->valid_extensions) strlcpy(info->exts, system_menu->valid_extensions, sizeof(info->exts)); } else strlcpy(info->exts, system->valid_extensions, sizeof(info->exts)); break; case PUSH_ARCHIVE_OPEN: if (system_menu->valid_extensions) { if (*system_menu->valid_extensions) strlcpy(info->exts, system_menu->valid_extensions, sizeof(info->exts)); } else strlcpy(info->exts, system->valid_extensions, sizeof(info->exts)); break; case PUSH_DEFAULT: if (menu_setting_get_browser_selection_type(info->setting) == ST_DIR) { } else if (system_menu->valid_extensions) { if (*system_menu->valid_extensions) strlcpy(info->exts, system_menu->valid_extensions, sizeof(info->exts)); } else strlcpy(info->exts, system->valid_extensions, sizeof(info->exts)); break; case PUSH_DETECT_CORE_LIST: if (!string_is_empty(list->all_ext)) strlcpy(info->exts, list->all_ext, sizeof(info->exts)); break; } (void)settings; if (settings->multimedia.builtin_mediaplayer_enable || settings->multimedia.builtin_imageviewer_enable) { struct retro_system_info sysinfo = {0}; (void)sysinfo; #ifdef HAVE_FFMPEG if (settings->multimedia.builtin_mediaplayer_enable) { libretro_ffmpeg_retro_get_system_info(&sysinfo); strlcat(info->exts, "|", sizeof(info->exts)); strlcat(info->exts, sysinfo.valid_extensions, sizeof(info->exts)); } #endif #ifdef HAVE_IMAGEVIEWER if (settings->multimedia.builtin_imageviewer_enable) { libretro_imageviewer_retro_get_system_info(&sysinfo); strlcat(info->exts, "|", sizeof(info->exts)); strlcat(info->exts, sysinfo.valid_extensions, sizeof(info->exts)); } #endif } return deferred_push_dlist(info, state); }
/* * This function gets called in order to process all input events * for the current frame. * * Sends input code to menu for one frame. * * It uses as input the local variables' input' and 'trigger_input'. * * Mouse and touch input events get processed inside this function. * * NOTE: 'input' and 'trigger_input' is sourced from the keyboard and/or * the gamepad. It does not contain input state derived from the mouse * and/or touch - this gets dealt with separately within this function. * * TODO/FIXME - maybe needs to be overhauled so we can send multiple * events per frame if we want to, and we shouldn't send the * entire button state either but do a separate event per button * state. */ unsigned menu_event(input_bits_t *p_input, input_bits_t *p_trigger_input) { /* Used for key repeat */ static float delay_timer = 0.0f; static float delay_count = 0.0f; static unsigned ok_old = 0; 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(); bool swap_ok_cancel_btns = settings->bools.input_menu_swap_ok_cancel_buttons; bool input_swap_override = input_autoconfigure_get_swap_override(); unsigned menu_ok_btn = (!input_swap_override && swap_ok_cancel_btns) ? RETRO_DEVICE_ID_JOYPAD_B : RETRO_DEVICE_ID_JOYPAD_A; unsigned menu_cancel_btn = (!input_swap_override && swap_ok_cancel_btns) ? RETRO_DEVICE_ID_JOYPAD_A : RETRO_DEVICE_ID_JOYPAD_B; unsigned ok_current = BIT256_GET_PTR(p_input, menu_ok_btn ); unsigned ok_trigger = ok_current & ~ok_old; ok_old = ok_current; if (bits_any_set(p_input->data, ARRAY_SIZE(p_input->data))) { if (!first_held) { /* don't run anything first frame, only capture held inputs * for old_input_state. */ first_held = true; delay_timer = initial_held ? 200 : 100; delay_count = 0; } if (delay_count >= delay_timer) { uint32_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; p_trigger_input->data[0] |= p_input->data[0] & input_repeat; menu_driver_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_driver_ctl(MENU_NAVIGATION_CTL_SET_SCROLL_ACCEL, &new_scroll_accel); delay_count += menu_animation_get_delta_time(); if (menu_input_dialog_get_display_kb()) { menu_event_osk_iterate(); if (BIT256_GET_PTR(p_trigger_input, RETRO_DEVICE_ID_JOYPAD_DOWN)) { if (menu_event_get_osk_ptr() < 33) menu_event_set_osk_ptr(menu_event_get_osk_ptr() + OSK_CHARS_PER_LINE); } if (BIT256_GET_PTR(p_trigger_input, RETRO_DEVICE_ID_JOYPAD_UP)) { if (menu_event_get_osk_ptr() >= OSK_CHARS_PER_LINE) menu_event_set_osk_ptr(menu_event_get_osk_ptr() - OSK_CHARS_PER_LINE); } if (BIT256_GET_PTR(p_trigger_input, RETRO_DEVICE_ID_JOYPAD_RIGHT)) { if (menu_event_get_osk_ptr() < 43) menu_event_set_osk_ptr(menu_event_get_osk_ptr() + 1); } if (BIT256_GET_PTR(p_trigger_input, RETRO_DEVICE_ID_JOYPAD_LEFT)) { if (menu_event_get_osk_ptr() >= 1) menu_event_set_osk_ptr(menu_event_get_osk_ptr() - 1); } if (BIT256_GET_PTR(p_trigger_input, RETRO_DEVICE_ID_JOYPAD_L)) { if (menu_event_get_osk_idx() > OSK_TYPE_UNKNOWN + 1) menu_event_set_osk_idx((enum osk_type)( menu_event_get_osk_idx() - 1)); else menu_event_set_osk_idx((enum osk_type)(OSK_TYPE_LAST - 1)); } if (BIT256_GET_PTR(p_trigger_input, RETRO_DEVICE_ID_JOYPAD_R)) { if (menu_event_get_osk_idx() < OSK_TYPE_LAST - 1) menu_event_set_osk_idx((enum osk_type)( menu_event_get_osk_idx() + 1)); else menu_event_set_osk_idx((enum osk_type)(OSK_TYPE_UNKNOWN + 1)); } if (BIT256_GET_PTR(p_trigger_input, menu_ok_btn)) { if (menu_event_get_osk_ptr() >= 0) menu_event_osk_append(menu_event_get_osk_ptr()); } if (BIT256_GET_PTR(p_trigger_input, menu_cancel_btn)) input_keyboard_event(true, '\x7f', '\x7f', 0, RETRO_DEVICE_KEYBOARD); /* send return key to close keyboard input window */ if (BIT256_GET_PTR(p_trigger_input, RETRO_DEVICE_ID_JOYPAD_START)) input_keyboard_event(true, '\n', '\n', 0, RETRO_DEVICE_KEYBOARD); BIT256_CLEAR_ALL_PTR(p_trigger_input); } else { if (BIT256_GET_PTR(p_trigger_input, RETRO_DEVICE_ID_JOYPAD_UP)) ret = MENU_ACTION_UP; else if (BIT256_GET_PTR(p_trigger_input, RETRO_DEVICE_ID_JOYPAD_DOWN)) ret = MENU_ACTION_DOWN; else if (BIT256_GET_PTR(p_trigger_input, RETRO_DEVICE_ID_JOYPAD_LEFT)) ret = MENU_ACTION_LEFT; else if (BIT256_GET_PTR(p_trigger_input, RETRO_DEVICE_ID_JOYPAD_RIGHT)) ret = MENU_ACTION_RIGHT; else if (BIT256_GET_PTR(p_trigger_input, RETRO_DEVICE_ID_JOYPAD_L)) ret = MENU_ACTION_SCROLL_UP; else if (BIT256_GET_PTR(p_trigger_input, RETRO_DEVICE_ID_JOYPAD_R)) ret = MENU_ACTION_SCROLL_DOWN; else if (ok_trigger) ret = MENU_ACTION_OK; else if (BIT256_GET_PTR(p_trigger_input, menu_cancel_btn)) ret = MENU_ACTION_CANCEL; else if (BIT256_GET_PTR(p_trigger_input, RETRO_DEVICE_ID_JOYPAD_X)) ret = MENU_ACTION_SEARCH; else if (BIT256_GET_PTR(p_trigger_input, RETRO_DEVICE_ID_JOYPAD_Y)) ret = MENU_ACTION_SCAN; else if (BIT256_GET_PTR(p_trigger_input, RETRO_DEVICE_ID_JOYPAD_START)) ret = MENU_ACTION_START; else if (BIT256_GET_PTR(p_trigger_input, RETRO_DEVICE_ID_JOYPAD_SELECT)) ret = MENU_ACTION_INFO; else if (BIT256_GET_PTR(p_trigger_input, RARCH_MENU_TOGGLE)) ret = MENU_ACTION_TOGGLE; } if (menu_event_kb_is_set(RETROK_F11)) { command_event(CMD_EVENT_GRAB_MOUSE_TOGGLE, NULL); menu_event_kb_set_internal(RETROK_F11, 0); } mouse_enabled = settings->bools.menu_mouse_enable; #ifdef HAVE_OVERLAY if (!mouse_enabled) mouse_enabled = !(settings->bools.input_overlay_enable && input_overlay_is_alive(overlay_ptr)); #endif menu_input = &menu_input_state; if (!mouse_enabled) menu_input->mouse.ptr = 0; if (settings->bools.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; }
static int menu_input_mouse_frame( menu_file_list_cbs_t *cbs, menu_entry_t *entry, unsigned action) { bool mouse_activity = false; bool no_mouse_activity = false; uint64_t mouse_state = MENU_MOUSE_ACTION_NONE; int ret = 0; settings_t *settings = config_get_ptr(); menu_input_t *menu_input = &menu_input_state; bool mouse_enable = settings->bools.menu_mouse_enable; if (mouse_enable) ret = menu_input_mouse_post_iterate(&mouse_state, cbs, action, &mouse_activity); if ((settings->bools.menu_pointer_enable || mouse_enable)) { menu_ctx_pointer_t point; point.x = menu_input_mouse_state(MENU_MOUSE_X_AXIS); point.y = menu_input_mouse_state(MENU_MOUSE_Y_AXIS); point.ptr = 0; point.cbs = NULL; point.entry = NULL; point.action = 0; point.retcode = 0; if (menu_input_dialog_get_display_kb()) menu_driver_ctl(RARCH_MENU_CTL_OSK_PTR_AT_POS, &point); if (rarch_timer_is_running(&mouse_activity_timer)) rarch_timer_tick(&mouse_activity_timer); if (mouse_old_x != point.x || mouse_old_y != point.y) { if (!rarch_timer_is_running(&mouse_activity_timer)) mouse_activity = true; menu_event_set_osk_ptr(point.retcode); } else { if (rarch_timer_has_expired(&mouse_activity_timer)) no_mouse_activity = true; } mouse_old_x = point.x; mouse_old_y = point.y; } if (BIT64_GET(mouse_state, MENU_MOUSE_ACTION_BUTTON_L)) { menu_ctx_pointer_t point; point.x = menu_input_mouse_state(MENU_MOUSE_X_AXIS); point.y = menu_input_mouse_state(MENU_MOUSE_Y_AXIS); point.ptr = menu_input->mouse.ptr; point.cbs = cbs; point.entry = entry; point.action = action; if (menu_input_dialog_get_display_kb()) { menu_driver_ctl(RARCH_MENU_CTL_OSK_PTR_AT_POS, &point); if (point.retcode > -1) { menu_event_set_osk_ptr(point.retcode); menu_event_osk_append(point.retcode); } } else { menu_driver_ctl(RARCH_MENU_CTL_POINTER_UP, &point); menu_driver_ctl(RARCH_MENU_CTL_POINTER_TAP, &point); ret = point.retcode; } } if (BIT64_GET(mouse_state, MENU_MOUSE_ACTION_BUTTON_R)) { size_t selection = menu_navigation_get_selection(); menu_entry_action(entry, (unsigned)selection, MENU_ACTION_CANCEL); } if (BIT64_GET(mouse_state, MENU_MOUSE_ACTION_WHEEL_DOWN)) { unsigned increment_by = 1; menu_driver_ctl(MENU_NAVIGATION_CTL_INCREMENT, &increment_by); } if (BIT64_GET(mouse_state, MENU_MOUSE_ACTION_WHEEL_UP)) { unsigned decrement_by = 1; menu_driver_ctl(MENU_NAVIGATION_CTL_DECREMENT, &decrement_by); } if (BIT64_GET(mouse_state, MENU_MOUSE_ACTION_HORIZ_WHEEL_UP)) { /* stub */ } if (BIT64_GET(mouse_state, MENU_MOUSE_ACTION_HORIZ_WHEEL_DOWN)) { /* stub */ } if (mouse_activity) { menu_ctx_environment_t menu_environ; rarch_timer_begin(&mouse_activity_timer, 4); menu_environ.type = MENU_ENVIRON_ENABLE_MOUSE_CURSOR; menu_environ.data = NULL; menu_driver_ctl(RARCH_MENU_CTL_ENVIRONMENT, &menu_environ); } if (no_mouse_activity) { menu_ctx_environment_t menu_environ; rarch_timer_end(&mouse_activity_timer); menu_environ.type = MENU_ENVIRON_DISABLE_MOUSE_CURSOR; menu_environ.data = NULL; menu_driver_ctl(RARCH_MENU_CTL_ENVIRONMENT, &menu_environ); } return ret; }
static int menu_input_pointer_post_iterate( menu_file_list_cbs_t *cbs, menu_entry_t *entry, unsigned action) { static bool pointer_oldpressed[2]; static bool pointer_oldback = false; static int16_t start_x = 0; static int16_t start_y = 0; static int16_t pointer_old_x = 0; static int16_t pointer_old_y = 0; int ret = 0; menu_input_t *menu_input = &menu_input_state; settings_t *settings = config_get_ptr(); if (!menu_input || !settings) return -1; #ifdef HAVE_OVERLAY /* If we have overlays enabled, overlay controls take * precedence and we don't want regular menu * pointer controls to be handled */ if (( settings->bools.input_overlay_enable && input_overlay_is_alive(overlay_ptr))) return 0; #endif if (menu_input->pointer.pressed[0]) { gfx_ctx_metrics_t metrics; float dpi; static float accel0 = 0.0f; static float accel1 = 0.0f; int16_t pointer_x = menu_input_pointer_state(MENU_POINTER_X_AXIS); int16_t pointer_y = menu_input_pointer_state(MENU_POINTER_Y_AXIS); metrics.type = DISPLAY_METRIC_DPI; metrics.value = &dpi; menu_input->pointer.counter++; if (menu_input->pointer.counter == 1 && !menu_input_ctl(MENU_INPUT_CTL_IS_POINTER_DRAGGED, NULL)) { menu_ctx_pointer_t point; point.x = pointer_x; point.y = pointer_y; point.ptr = menu_input->pointer.ptr; point.cbs = cbs; point.entry = entry; point.action = action; menu_driver_ctl(RARCH_MENU_CTL_POINTER_DOWN, &point); } if (!pointer_oldpressed[0]) { menu_input->pointer.accel = 0; accel0 = 0; accel1 = 0; start_x = pointer_x; start_y = pointer_y; pointer_old_x = pointer_x; pointer_old_y = pointer_y; pointer_oldpressed[0] = true; } else if (video_context_driver_get_metrics(&metrics)) { if (abs(pointer_x - start_x) > (dpi / 10) || abs(pointer_y - start_y) > (dpi / 10)) { float s; menu_input_ctl(MENU_INPUT_CTL_SET_POINTER_DRAGGED, NULL); menu_input->pointer.dx = pointer_x - pointer_old_x; menu_input->pointer.dy = pointer_y - pointer_old_y; pointer_old_x = pointer_x; pointer_old_y = pointer_y; s = menu_input->pointer.dy; menu_input->pointer.accel = (accel0 + accel1 + s) / 3; accel0 = accel1; accel1 = menu_input->pointer.accel; } } } else { if (pointer_oldpressed[0]) { if (!menu_input_ctl(MENU_INPUT_CTL_IS_POINTER_DRAGGED, NULL)) { menu_ctx_pointer_t point; point.x = start_x; point.y = start_y; point.ptr = menu_input->pointer.ptr; point.cbs = cbs; point.entry = entry; point.action = action; if (menu_input_dialog_get_display_kb()) { menu_driver_ctl(RARCH_MENU_CTL_OSK_PTR_AT_POS, &point); if (point.retcode > -1) { menu_event_set_osk_ptr(point.retcode); menu_event_osk_append(point.retcode); } } else { if (menu_input->pointer.counter > 32) { size_t selection = menu_navigation_get_selection(); if (cbs && cbs->action_start) return menu_entry_action(entry, (unsigned)selection, MENU_ACTION_START); } else { menu_driver_ctl(RARCH_MENU_CTL_POINTER_UP, &point); menu_driver_ctl(RARCH_MENU_CTL_POINTER_TAP, &point); ret = point.retcode; } } } pointer_oldpressed[0] = false; start_x = 0; start_y = 0; pointer_old_x = 0; pointer_old_y = 0; menu_input->pointer.dx = 0; menu_input->pointer.dy = 0; menu_input->pointer.counter = 0; menu_input_ctl(MENU_INPUT_CTL_UNSET_POINTER_DRAGGED, NULL); } } if (menu_input->pointer.back) { if (!pointer_oldback) { pointer_oldback = true; menu_entry_action(entry, (unsigned)menu_navigation_get_selection(), MENU_ACTION_CANCEL); } } pointer_oldback = menu_input->pointer.back; return ret; }
bool menu_input_ctl(enum menu_input_ctl_state state, void *data) { static char menu_input_keyboard_label_setting[256]; static const char **menu_input_keyboard_buffer; static const char *menu_input_keyboard_label = NULL; static bool pointer_dragging = false; menu_input_t *menu_input = menu_input_get_ptr(); if (!menu_input) return false; switch (state) { case MENU_INPUT_CTL_BIND_SET_MIN_MAX: { menu_input_ctx_bind_limits_t *lim = (menu_input_ctx_bind_limits_t*)data; if (!lim || !menu_input) return false; menu_input->binds.begin = lim->min; menu_input->binds.last = lim->max; } break; case MENU_INPUT_CTL_CHECK_INSIDE_HITBOX: { menu_input_ctx_hitbox_t *hitbox = (menu_input_ctx_hitbox_t*)data; int16_t mouse_x = menu_input_mouse_state(MENU_MOUSE_X_AXIS); int16_t mouse_y = menu_input_mouse_state(MENU_MOUSE_Y_AXIS); bool inside_hitbox = (mouse_x >= hitbox->x1) && (mouse_x <= hitbox->x2) && (mouse_y >= hitbox->y1) && (mouse_y <= hitbox->y2) ; if (!inside_hitbox) return false; } break; case MENU_INPUT_CTL_DEINIT: memset(menu_input, 0, sizeof(menu_input_t)); pointer_dragging = false; break; case MENU_INPUT_CTL_SEARCH_START: { menu_handle_t *menu = NULL; if (!menu_driver_ctl( RARCH_MENU_CTL_DRIVER_DATA_GET, &menu)) return false; menu_input->keyboard.display = true; menu_input_keyboard_label = menu_hash_to_str(MENU_VALUE_SEARCH); menu_input_keyboard_buffer = input_keyboard_start_line(menu, menu_input_search_cb); } break; case MENU_INPUT_CTL_MOUSE_PTR: { unsigned *ptr = (unsigned*)data; menu_input->mouse.ptr = *ptr; } break; case MENU_INPUT_CTL_POINTER_PTR: { unsigned *ptr = (unsigned*)data; menu_input->pointer.ptr = *ptr; } break; case MENU_INPUT_CTL_POINTER_ACCEL_READ: { float *ptr = (float*)data; *ptr = menu_input->pointer.accel; } break; case MENU_INPUT_CTL_POINTER_ACCEL_WRITE: { float *ptr = (float*)data; menu_input->pointer.accel = *ptr; } break; case MENU_INPUT_CTL_IS_POINTER_DRAGGED: return pointer_dragging; case MENU_INPUT_CTL_SET_POINTER_DRAGGED: pointer_dragging = true; break; case MENU_INPUT_CTL_UNSET_POINTER_DRAGGED: pointer_dragging = false; break; case MENU_INPUT_CTL_KEYBOARD_DISPLAY: { bool *ptr = (bool*)data; *ptr = menu_input->keyboard.display; } break; case MENU_INPUT_CTL_SET_KEYBOARD_DISPLAY: { bool *ptr = (bool*)data; menu_input->keyboard.display = *ptr; } break; case MENU_INPUT_CTL_KEYBOARD_BUFF_PTR: { const char **ptr = (const char**)data; *ptr = *menu_input_keyboard_buffer; } break; case MENU_INPUT_CTL_KEYBOARD_LABEL: { const char **ptr = (const char**)data; *ptr = menu_input_keyboard_label; } break; case MENU_INPUT_CTL_SET_KEYBOARD_LABEL: { char **ptr = (char**)data; menu_input_keyboard_label = *ptr; } break; case MENU_INPUT_CTL_UNSET_KEYBOARD_LABEL: menu_input_keyboard_label = NULL; break; case MENU_INPUT_CTL_KEYBOARD_LABEL_SETTING: { const char **ptr = (const char**)data; *ptr = menu_input_keyboard_label_setting; } break; case MENU_INPUT_CTL_SET_KEYBOARD_LABEL_SETTING: { char **ptr = (char**)data; strlcpy(menu_input_keyboard_label_setting, *ptr, sizeof(menu_input_keyboard_label_setting)); } break; case MENU_INPUT_CTL_UNSET_KEYBOARD_LABEL_SETTING: menu_input_keyboard_label_setting[0] = '\0'; break; case MENU_INPUT_CTL_BIND_NONE: case MENU_INPUT_CTL_BIND_SINGLE: case MENU_INPUT_CTL_BIND_ALL: return menu_input_key_bind_set_mode(state, data); case MENU_INPUT_CTL_BIND_ITERATE: { menu_input_ctx_bind_t *bind = (menu_input_ctx_bind_t*)data; if (!bind) return false; return menu_input_key_bind_iterate(bind->s, bind->len); } case MENU_INPUT_CTL_START_LINE: { bool keyboard_display = true; menu_handle_t *menu = NULL; menu_input_ctx_line_t *line = (menu_input_ctx_line_t*)data; if (!menu_input || !line) return false; if (!menu_driver_ctl(RARCH_MENU_CTL_DRIVER_DATA_GET, &menu)) return false; menu_input_ctl(MENU_INPUT_CTL_SET_KEYBOARD_DISPLAY, &keyboard_display); menu_input_ctl(MENU_INPUT_CTL_SET_KEYBOARD_LABEL, &line->label); menu_input_ctl(MENU_INPUT_CTL_SET_KEYBOARD_LABEL_SETTING, &line->label_setting); menu_input->keyboard.type = line->type; menu_input->keyboard.idx = line->idx; menu_input_keyboard_buffer = input_keyboard_start_line(menu, line->cb); } break; default: case MENU_INPUT_CTL_NONE: break; } return true; }
/** * menu_shader_manager_save_preset: * @basename : basename of preset * @apply : immediately set preset after saving * * Save a shader preset to disk. **/ void menu_shader_manager_save_preset( const char *basename, bool apply) { #ifdef HAVE_SHADER_MANAGER char buffer[PATH_MAX_LENGTH]; char config_directory[PATH_MAX_LENGTH]; char preset_path[PATH_MAX_LENGTH]; unsigned d, type = RARCH_SHADER_NONE; const char *dirs[3] = {0}; config_file_t *conf = NULL; bool ret = false; struct video_shader *shader = NULL; global_t *global = global_get_ptr(); settings_t *settings = config_get_ptr(); menu_handle_t *menu = NULL; if (!menu_driver_ctl(RARCH_MENU_CTL_DRIVER_DATA_GET, &menu)) { RARCH_ERR("Cannot save shader preset, menu handle" " is not initialized.\n"); return; } menu_driver_ctl(RARCH_MENU_CTL_SHADER_GET, &shader); if (!shader) return; type = menu_shader_manager_get_type(shader); if (type == RARCH_SHADER_NONE) return; *config_directory = '\0'; if (basename) { strlcpy(buffer, basename, sizeof(buffer)); /* Append extension automatically as appropriate. */ if ( !strstr(basename, ".cgp") && !strstr(basename, ".glslp") && !strstr(basename, ".slangp")) { switch (type) { case RARCH_SHADER_GLSL: strlcat(buffer, ".glslp", sizeof(buffer)); break; case RARCH_SHADER_SLANG: strlcat(buffer, ".slangp", sizeof(buffer)); break; case RARCH_SHADER_CG: strlcat(buffer, ".cgp", sizeof(buffer)); break; } } } else { const char *conf_path = NULL; switch (type) { case RARCH_SHADER_GLSL: conf_path = menu->default_glslp; break; case RARCH_SHADER_SLANG: conf_path = menu->default_slangp; break; default: case RARCH_SHADER_CG: conf_path = menu->default_cgp; break; } strlcpy(buffer, conf_path, sizeof(buffer)); } if (*global->path.config) fill_pathname_basedir( config_directory, global->path.config, sizeof(config_directory)); dirs[0] = settings->directory.video_shader; dirs[1] = settings->directory.menu_config; dirs[2] = config_directory; if (!(conf = (config_file_t*)config_file_new(NULL))) return; video_shader_write_conf_cgp(conf, shader); for (d = 0; d < ARRAY_SIZE(dirs); d++) { if (!*dirs[d]) continue; fill_pathname_join(preset_path, dirs[d], buffer, sizeof(preset_path)); if (config_file_write(conf, preset_path)) { RARCH_LOG("Saved shader preset to %s.\n", preset_path); if (apply) menu_shader_manager_set_preset(NULL, type, preset_path); ret = true; break; } else RARCH_LOG("Failed writing shader preset to %s.\n", preset_path); } config_file_free(conf); if (!ret) RARCH_ERR("Failed to save shader preset. Make sure config directory" " and/or shader dir are writable.\n"); #endif }
/** * 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; }
/** * menu_shader_manager_init: * * Initializes shader manager. **/ void menu_shader_manager_init(menu_handle_t *menu) { #ifdef HAVE_SHADER_MANAGER uint32_t ext_hash; const char *ext = NULL; struct video_shader *shader = NULL; config_file_t *conf = NULL; const char *config_path = NULL; settings_t *settings = config_get_ptr(); global_t *global = global_get_ptr(); if (!menu) return; menu_driver_ctl(RARCH_MENU_CTL_SHADER_GET, &shader); if (*global->path.core_specific_config && settings->core_specific_config) config_path = global->path.core_specific_config; else if (*global->path.config) config_path = global->path.config; /* In a multi-config setting, we can't have * conflicts on menu.cgp/menu.glslp. */ if (config_path) { fill_pathname_base(menu->default_glslp, config_path, sizeof(menu->default_glslp)); path_remove_extension(menu->default_glslp); strlcat(menu->default_glslp, ".glslp", sizeof(menu->default_glslp)); fill_pathname_base(menu->default_cgp, config_path, sizeof(menu->default_cgp)); path_remove_extension(menu->default_cgp); strlcat(menu->default_cgp, ".cgp", sizeof(menu->default_cgp)); fill_pathname_base(menu->default_slangp, config_path, sizeof(menu->default_slangp)); path_remove_extension(menu->default_slangp); strlcat(menu->default_slangp, ".slangp", sizeof(menu->default_slangp)); } else { strlcpy(menu->default_glslp, "menu.glslp", sizeof(menu->default_glslp)); strlcpy(menu->default_cgp, "menu.cgp", sizeof(menu->default_cgp)); strlcpy(menu->default_slangp, "menu.slangp", sizeof(menu->default_slangp)); } ext = path_get_extension(settings->path.shader); ext_hash = menu_hash_calculate(ext); switch (ext_hash) { case MENU_VALUE_GLSLP: case MENU_VALUE_CGP: case MENU_VALUE_SLANGP: conf = config_file_new(settings->path.shader); if (conf) { if (video_shader_read_conf_cgp(conf, shader)) { video_shader_resolve_relative(shader, settings->path.shader); video_shader_resolve_parameters(conf, shader); } config_file_free(conf); } break; case MENU_VALUE_GLSL: case MENU_VALUE_CG: case MENU_VALUE_SLANG: strlcpy(shader->pass[0].source.path, settings->path.shader, sizeof(shader->pass[0].source.path)); shader->passes = 1; break; default: { char preset_path[PATH_MAX_LENGTH]; const char *shader_dir = *settings->directory.video_shader ? settings->directory.video_shader : settings->directory.system; fill_pathname_join(preset_path, shader_dir, "menu.glslp", sizeof(preset_path)); conf = config_file_new(preset_path); if (!conf) { fill_pathname_join(preset_path, shader_dir, "menu.cgp", sizeof(preset_path)); conf = config_file_new(preset_path); } if (!conf) { fill_pathname_join(preset_path, shader_dir, "menu.slangp", sizeof(preset_path)); conf = config_file_new(preset_path); } if (conf) { if (video_shader_read_conf_cgp(conf, shader)) { video_shader_resolve_relative(shader, preset_path); video_shader_resolve_parameters(conf, shader); } config_file_free(conf); } } break; } #endif }
static int action_right_mainmenu(unsigned type, const char *label, bool wraparound) { menu_ctx_list_t list_info; size_t selection = 0; menu_file_list_cbs_t *cbs = NULL; unsigned push_list = 0; file_list_t *selection_buf = menu_entries_get_selection_buf_ptr(0); file_list_t *menu_stack = menu_entries_get_menu_stack_ptr(0); settings_t *settings = config_get_ptr(); unsigned action = MENU_ACTION_RIGHT; menu_driver_ctl(RARCH_MENU_CTL_LIST_GET_SELECTION, &list_info); list_info.type = MENU_LIST_PLAIN; menu_driver_ctl(RARCH_MENU_CTL_LIST_GET_SIZE, &list_info); if (list_info.size == 1) { menu_ctx_list_t list_horiz_info; menu_ctx_list_t list_tabs_info; list_horiz_info.type = MENU_LIST_HORIZONTAL; list_tabs_info.type = MENU_LIST_TABS; menu_driver_ctl(RARCH_MENU_CTL_LIST_GET_SIZE, &list_horiz_info); menu_driver_ctl(RARCH_MENU_CTL_LIST_GET_SIZE, &list_tabs_info); menu_navigation_ctl(MENU_NAVIGATION_CTL_SET_SELECTION, &selection); if ((list_info.selection != (list_horiz_info.size + list_tabs_info.size)) || settings->menu.navigation.wraparound.enable) push_list = 1; } else push_list = 2; menu_navigation_ctl(MENU_NAVIGATION_CTL_GET_SELECTION, &selection); cbs = menu_entries_get_actiondata_at_offset(selection_buf, selection); switch (push_list) { case 1: { menu_ctx_list_t list_info; list_info.type = MENU_LIST_HORIZONTAL; list_info.action = action; menu_driver_ctl(RARCH_MENU_CTL_LIST_CACHE, &list_info); if (cbs && cbs->action_content_list_switch) return cbs->action_content_list_switch(selection_buf, menu_stack, "", "", 0); } break; case 2: action_right_scroll(0, "", false); break; case 0: default: break; } return 0; }
bool menu_navigation_ctl(enum menu_navigation_ctl_state state, void *data) { /* Quick jumping indices with L/R. * Rebuilt when parsing directory. */ static struct scroll_indices { size_t list[2 * (26 + 2) + 1]; unsigned size; } scroll_index; static unsigned scroll_acceleration = 0; static size_t selection_ptr = 0; switch (state) { case MENU_NAVIGATION_CTL_DEINIT: scroll_acceleration = 0; selection_ptr = 0; memset(&scroll_index, 0, sizeof(struct scroll_indices)); break; case MENU_NAVIGATION_CTL_CLEAR: { size_t idx = 0; bool scroll = true; menu_navigation_ctl(MENU_NAVIGATION_CTL_SET_SELECTION, &idx); menu_navigation_ctl(MENU_NAVIGATION_CTL_SET, &scroll); menu_driver_ctl(RARCH_MENU_CTL_NAVIGATION_CLEAR, data); } break; case MENU_NAVIGATION_CTL_INCREMENT: { settings_t *settings = config_get_ptr(); unsigned *scroll_speed = (unsigned*)data; size_t menu_list_size = menu_entries_get_size(); if (!scroll_speed) return false; if (selection_ptr >= menu_list_size - 1 && !settings->menu.navigation.wraparound.enable) return false; if ((selection_ptr + (*scroll_speed)) < menu_list_size) { size_t idx = selection_ptr + (*scroll_speed); bool scroll = true; menu_navigation_ctl(MENU_NAVIGATION_CTL_SET_SELECTION, &idx); menu_navigation_ctl(MENU_NAVIGATION_CTL_SET, &scroll); menu_navigation_ctl(MENU_NAVIGATION_CTL_INCREMENT, NULL); } else { if (settings->menu.navigation.wraparound.enable) { bool pending_push = false; menu_navigation_ctl(MENU_NAVIGATION_CTL_CLEAR, &pending_push); } else { if (menu_list_size > 0) { menu_navigation_ctl(MENU_NAVIGATION_CTL_SET_LAST, NULL); menu_navigation_ctl(MENU_NAVIGATION_CTL_INCREMENT, NULL); } } } menu_driver_ctl(RARCH_MENU_CTL_NAVIGATION_INCREMENT, NULL); } break; case MENU_NAVIGATION_CTL_DECREMENT: { size_t idx = 0; bool scroll = true; settings_t *settings = config_get_ptr(); unsigned *scroll_speed = (unsigned*)data; size_t menu_list_size = menu_entries_get_size(); if (!scroll_speed) return false; if (selection_ptr == 0 && !settings->menu.navigation.wraparound.enable) return false; if (selection_ptr >= *scroll_speed) idx = selection_ptr - *scroll_speed; else { idx = menu_list_size - 1; if (!settings->menu.navigation.wraparound.enable) idx = 0; } menu_navigation_ctl(MENU_NAVIGATION_CTL_SET_SELECTION, &idx); menu_navigation_ctl(MENU_NAVIGATION_CTL_SET, &scroll); menu_navigation_ctl(MENU_NAVIGATION_CTL_DECREMENT, NULL); menu_driver_ctl(RARCH_MENU_CTL_NAVIGATION_DECREMENT, NULL); } break; case MENU_NAVIGATION_CTL_SET: menu_driver_ctl(RARCH_MENU_CTL_NAVIGATION_SET, data); break; case MENU_NAVIGATION_CTL_SET_LAST: { size_t menu_list_size = menu_entries_get_size(); size_t new_selection = menu_list_size - 1; menu_navigation_ctl( MENU_NAVIGATION_CTL_SET_SELECTION, &new_selection); menu_driver_ctl(RARCH_MENU_CTL_NAVIGATION_SET_LAST, NULL); } break; case MENU_NAVIGATION_CTL_ASCEND_ALPHABET: { size_t i = 0, ptr; size_t *ptr_out = (size_t*)&selection_ptr; size_t menu_list_size = menu_entries_get_size(); if (!scroll_index.size || !ptr_out) return false; ptr = *ptr_out; if (ptr == scroll_index.list[scroll_index.size - 1]) { *ptr_out = menu_list_size - 1; menu_driver_ctl(RARCH_MENU_CTL_NAVIGATION_ASCEND_ALPHABET, ptr_out); return true; } while (i < scroll_index.size - 1 && scroll_index.list[i + 1] <= ptr) i++; *ptr_out = scroll_index.list[i + 1]; if (*ptr_out >= menu_list_size) *ptr_out = menu_list_size - 1; menu_driver_ctl(RARCH_MENU_CTL_NAVIGATION_ASCEND_ALPHABET, ptr_out); } break; case MENU_NAVIGATION_CTL_DESCEND_ALPHABET: { size_t i = 0, ptr; size_t *ptr_out = (size_t*)&selection_ptr; if (!scroll_index.size || !ptr_out) return false; ptr = *ptr_out; if (ptr == 0) return false; i = scroll_index.size - 1; while (i && scroll_index.list[i - 1] >= ptr) i--; *ptr_out = scroll_index.list[i - 1]; menu_driver_ctl( RARCH_MENU_CTL_NAVIGATION_DESCEND_ALPHABET, ptr_out); } break; case MENU_NAVIGATION_CTL_GET_SELECTION: { size_t *sel = (size_t*)data; if (!sel) return false; *sel = selection_ptr; } break; case MENU_NAVIGATION_CTL_SET_SELECTION: { size_t *sel = (size_t*)data; if (!sel) return false; selection_ptr = *sel; } break; case MENU_NAVIGATION_CTL_CLEAR_SCROLL_INDICES: scroll_index.size = 0; break; case MENU_NAVIGATION_CTL_ADD_SCROLL_INDEX: { size_t *sel = (size_t*)data; if (!sel) return false; scroll_index.list[scroll_index.size++] = *sel; } break; case MENU_NAVIGATION_CTL_GET_SCROLL_ACCEL: { size_t *sel = (size_t*)data; if (!sel) return false; *sel = scroll_acceleration; } break; case MENU_NAVIGATION_CTL_SET_SCROLL_ACCEL: { size_t *sel = (size_t*)data; if (!sel) return false; scroll_acceleration = *sel; } break; default: case MENU_NAVIGATION_CTL_NONE: break; } return true; }
void cb_net_generic(void *task_data, void *user_data, const char *err) { #ifdef HAVE_NETWORKING bool refresh = false; http_transfer_data_t *data = (http_transfer_data_t*)task_data; file_transfer_t *state = (file_transfer_t*)user_data; menu_handle_t *menu = NULL; if (!menu_driver_ctl(RARCH_MENU_CTL_DRIVER_DATA_GET, &menu)) goto finish; if (menu->core_buf) free(menu->core_buf); menu->core_buf = NULL; menu->core_len = 0; if (!data || err) goto finish; menu->core_buf = (char*)malloc((data->len+1) * sizeof(char)); if (!menu->core_buf) goto finish; if (!string_is_empty(data->data)) memcpy(menu->core_buf, data->data, data->len * sizeof(char)); menu->core_buf[data->len] = '\0'; menu->core_len = data->len; finish: refresh = true; menu_entries_ctl(MENU_ENTRIES_CTL_UNSET_REFRESH, &refresh); if (data) { if (data->data) free(data->data); free(data); } if (!err && !strstr(state->path, file_path_str(FILE_PATH_INDEX_DIRS_URL))) { char *parent_dir = (char*)malloc(PATH_MAX_LENGTH * sizeof(char)); file_transfer_t *transf = NULL; parent_dir[0] = '\0'; fill_pathname_parent_dir(parent_dir, state->path, PATH_MAX_LENGTH * sizeof(char)); strlcat(parent_dir, file_path_str(FILE_PATH_INDEX_DIRS_URL), PATH_MAX_LENGTH * sizeof(char)); transf = (file_transfer_t*)malloc(sizeof(*transf)); transf->enum_idx = MSG_UNKNOWN; strlcpy(transf->path, parent_dir, sizeof(transf->path)); task_push_http_transfer(parent_dir, true, "index_dirs", cb_net_generic_subdir, transf); free(parent_dir); } if (state) free(state); #endif }
/** * 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; retro_time_t current, target, to_sleep_ms; static uint64_t last_input = 0; enum runloop_state runloop_status = RUNLOOP_STATE_NONE; static retro_time_t frame_limit_minimum_time = 0.0; static retro_time_t frame_limit_last_time = 0.0; settings_t *settings = config_get_ptr(); uint64_t current_input = menu_driver_ctl(RARCH_MENU_CTL_IS_ALIVE, NULL) ? input_menu_keys_pressed() : input_keys_pressed(); uint64_t old_input = last_input; last_input = current_input; if (runloop_frame_time_last_enable) { runloop_frame_time_last = 0; runloop_frame_time_last_enable = false; } if (runloop_set_frame_limit) { 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_set_frame_limit = false; } 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_paused || 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_slowmotion) delta /= settings->slowmotion_ratio; runloop_frame_time_last = current; if (is_locked_fps) runloop_frame_time_last = 0; runloop_frame_time.callback(delta); } runloop_status = runloop_check_state(settings, current_input, old_input, sleep_ms); switch (runloop_status) { case RUNLOOP_STATE_QUIT: frame_limit_last_time = 0.0; command_event(CMD_EVENT_QUIT, NULL); return -1; case RUNLOOP_STATE_SLEEP: case RUNLOOP_STATE_END: case RUNLOOP_STATE_MENU_ITERATE: core_poll(); #ifdef HAVE_NETWORKING /* FIXME: This is an ugly way to tell Netplay this... */ netplay_driver_ctl(RARCH_NETPLAY_CTL_PAUSE, NULL); #endif if (runloop_status == RUNLOOP_STATE_SLEEP) *sleep_ms = 10; if (runloop_status == RUNLOOP_STATE_END) goto end; if (runloop_status == RUNLOOP_STATE_MENU_ITERATE) return 0; return 1; case RUNLOOP_STATE_ITERATE: case RUNLOOP_STATE_NONE: default: break; } autosave_lock(); 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); autosave_unlock(); if (!settings->fastforward_ratio) return 0; end: 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; }