int main(int argc, char *argv[]) { std::string config_path, cmdln_font; bool launch_game = false; process_args( argc, argv, config_path, cmdln_font ); // // Run the front-end // std::cout << "Starting " << FE_NAME << " " << FE_VERSION << " (" << get_OS_string() << ")" << std::endl; FeSettings feSettings( config_path, cmdln_font ); feSettings.load(); if ( feSettings.get_info_bool( FeSettings::AutoLaunchLastGame ) ) { feSettings.select_last_launch(); launch_game=true; } std::string defaultFontFile; if ( feSettings.get_font_file( defaultFontFile ) == false ) { std::cerr << "Error, could not find default font." << std::endl; return 1; } FeFontContainer defaultFont; defaultFont.set_font( defaultFontFile ); // // Set up music/sound playing objects // #ifndef NO_MOVIE sf::AudioDevice audio_device; #endif FeSoundSystem soundsys( &feSettings ); soundsys.update_volumes(); soundsys.play_ambient(); FeWindow window( feSettings ); window.initial_create(); FeVM feVM( feSettings, defaultFont, window, soundsys.get_ambient_sound() ); FeOverlay feOverlay( window, feSettings, feVM ); feVM.set_overlay( &feOverlay ); bool exit_selected=false; if ( feSettings.get_language().empty() ) { // If our language isn't set at this point, we want to prompt the user for the language // they wish to use // // TODO: FIXME: languages_dialog segfaults unless there is a layout loaded first feVM.load_layout( true ); if ( feOverlay.languages_dialog() < 0 ) exit_selected = true; } soundsys.sound_event( FeInputMap::EventStartup ); bool redraw=true; int guard_joyid=-1, guard_axis=-1; // variables used to track movement when a key is held down FeInputMap::Command move_state( FeInputMap::LAST_COMMAND ); sf::Clock move_timer; sf::Event move_event; int move_last_triggered( 0 ); // go straight into config mode if there are no lists configured for // display // bool config_mode = ( feSettings.displays_count() < 1 ); if ( !config_mode ) { // start the intro now if ( !feVM.load_intro() ) feVM.load_layout( true ); } while (window.isOpen() && (!exit_selected)) { if ( config_mode ) { // // Enter config mode // int old_mode = feSettings.get_window_mode(); if ( feOverlay.config_dialog() ) { // Settings changed, reload // if ( feSettings.get_font_file( defaultFontFile ) ) defaultFont.set_font( defaultFontFile ); feSettings.set_display( feSettings.get_current_display_index() ); feVM.load_layout(); soundsys.stop(); soundsys.update_volumes(); soundsys.play_ambient(); // Recreate window if the window mode changed if ( feSettings.get_window_mode() != old_mode ) { window.on_exit(); window.initial_create(); } } feVM.reset_screen_saver(); config_mode=false; redraw=true; } else if ( launch_game ) { if ( feSettings.get_rom_info( 0, 0, FeRomInfo::Emulator ).compare( "@" ) == 0 ) { // If the rom_info's emulator is set to "@" then this is a shortcut to another // display, so instead of running a game we switch to the display specified in the // rom_info's Romname field // std::string name = feSettings.get_rom_info( 0, 0, FeRomInfo::Romname ); int index = feSettings.get_display_index_from_name( name ); // if index not found or if we are already in the specified display, then // jump to the altromname display instead // if (( index < 0 ) || ( index == feSettings.get_current_display_index() )) { name = feSettings.get_rom_info( 0, 0, FeRomInfo::AltRomname ); if ( !name.empty() ) index = feSettings.get_display_index_from_name( name ); } if ( index < 0 ) { std::cerr << "Error resolving shortcut, Display `" << name << "' not found."; } else { if ( feSettings.set_display( index ) ) feVM.load_layout(); else feVM.update_to_new_list( 0, true ); } } else { soundsys.stop(); feVM.pre_run(); // window.run() returns true if our window has been closed while the other program was running if ( !window.run() ) exit_selected = true; feVM.post_run(); soundsys.sound_event( FeInputMap::EventGameReturn ); soundsys.play_ambient(); } launch_game=false; redraw=true; } FeInputMap::Command c; sf::Event ev; while ( feVM.poll_command( c, ev ) ) { // // Special case handling based on event type // switch ( ev.type ) { case sf::Event::Closed: exit_selected = true; break; case sf::Event::MouseMoved: if ( feSettings.test_mouse_reset( ev.mouseMove.x, ev.mouseMove.y )) { // We reset the mouse if we are capturing it and it has moved // outside of its bounding box // sf::Vector2u s = window.getSize(); sf::Mouse::setPosition( sf::Vector2i( s.x / 2, s.y / 2 ), window ); } break; case sf::Event::KeyPressed: case sf::Event::MouseButtonPressed: case sf::Event::JoystickButtonPressed: // // We always want to reset the screen saver on these events, // even if they aren't mapped otherwise (mapped events cause // a reset too) // if (( c == FeInputMap::LAST_COMMAND ) && ( feVM.reset_screen_saver() )) redraw = true; break; case sf::Event::GainedFocus: case sf::Event::Resized: redraw = true; break; case sf::Event::JoystickMoved: if ( c == FeInputMap::LAST_COMMAND ) { if (( (int)ev.joystickMove.joystickId == guard_joyid ) && ( ev.joystickMove.axis == guard_axis )) { // Reset the joystick guard because the axis we are guarding has moved // below the joystick threshold guard_joyid = -1; guard_axis = -1; } } else { // Only allow one mapped "Joystick Moved" input through at a time // if ( guard_joyid != -1 ) continue; guard_joyid = ev.joystickMove.joystickId; guard_axis = ev.joystickMove.axis; } break; case sf::Event::Count: default: break; } if (( c == FeInputMap::LAST_COMMAND ) || ( move_state != FeInputMap::LAST_COMMAND )) continue; move_state=FeInputMap::LAST_COMMAND; if (( c == FeInputMap::Down ) || ( c == FeInputMap::Up ) || ( c == FeInputMap::PageDown ) || ( c == FeInputMap::PageUp ) || ( c == FeInputMap::NextLetter ) || ( c == FeInputMap::PrevLetter ) || ( c == FeInputMap::NextFavourite ) || ( c == FeInputMap::PrevFavourite )) { // setup variables to test for when the navigation keys are held down move_state = c; move_timer.restart(); move_event = ev; } // // Special case: handle the reload signal now // if ( c == FeInputMap::Reload ) { feVM.load_layout(); continue; } // // Give the script the option to handle the command. // if ( feVM.script_handle_event( c, redraw ) ) continue; // // Check if we need to get out of intro mode // if ( feSettings.get_present_state() == FeSettings::Intro_Showing ) { feVM.load_layout( true ); redraw=true; continue; } // // Default command handling // soundsys.sound_event( c ); if ( feVM.handle_event( c ) ) redraw = true; else { // handle the things that fePresent doesn't do switch ( c ) { case FeInputMap::ExitMenu: { int retval = feOverlay.confirm_dialog( "Exit Attract-Mode?" ); // // retval is 0 if the user confirmed exit. // it is <0 if we are being forced to close // if ( retval < 1 ) { exit_selected = true; if ( retval == 0 ) feSettings.exit_command(); } else redraw=true; } break; case FeInputMap::ExitNoMenu: exit_selected = true; break; case FeInputMap::ReplayLastGame: if ( feSettings.select_last_launch() ) feVM.load_layout(); else feVM.update_to_new_list(); launch_game=true; redraw=true; break; case FeInputMap::Select: launch_game=true; break; case FeInputMap::ToggleMute: feSettings.set_mute( !feSettings.get_mute() ); soundsys.update_volumes(); feVM.toggle_mute(); break; case FeInputMap::ScreenShot: { std::string filename; get_available_filename( feSettings.get_config_dir(), "screen", ".png", filename ); sf::Image sshot_img = window.capture(); sshot_img.saveToFile( filename ); } break; case FeInputMap::Configure: config_mode = true; break; case FeInputMap::DisplaysMenu: { std::vector<std::string> names_list; feSettings.get_display_names( names_list ); std::string title; feSettings.get_resource( "Lists", title ); int exit_opt=-999; if ( feSettings.get_info_bool( FeSettings::DisplaysMenuExit ) ) { // // Add an exit option at the end of the lists menu // std::string exit_str; feSettings.get_resource( "Exit Attract-Mode", exit_str ); names_list.push_back( exit_str ); exit_opt = names_list.size() - 1; } int display_index = feOverlay.common_list_dialog( title, names_list, feSettings.get_current_display_index(), -1 ); if ( display_index == exit_opt ) { exit_selected = true; feSettings.exit_command(); } else if ( display_index >= 0 ) { if ( feSettings.set_display( display_index ) ) feVM.load_layout(); else feVM.update_to_new_list( 0, true ); } redraw=true; } break; case FeInputMap::FiltersMenu: { std::vector<std::string> names_list; feSettings.get_current_display_filter_names( names_list ); std::string title; feSettings.get_resource( "Filters", title ); int filter_index = feOverlay.common_list_dialog( title, names_list, feSettings.get_current_filter_index(), -1 ); if ( filter_index >= 0 ) { feSettings.set_current_selection( filter_index, -1 ); feVM.update_to_new_list(); } redraw=true; } break; case FeInputMap::ToggleFavourite: { bool new_state = !feSettings.get_current_fav(); if ( feSettings.get_info_bool( FeSettings::ConfirmFavourites ) ) { std::string msg = ( new_state ) ? "Add '$1' to Favourites?" : "Remove '$1' from Favourites?"; // returns 0 if user confirmed toggle if ( feOverlay.confirm_dialog( msg, feSettings.get_rom_info( 0, 0, FeRomInfo::Title ) ) == 0 ) { if ( feSettings.set_current_fav( new_state ) ) feVM.update_to_new_list(); // our current display might have changed, so update } } else { if ( feSettings.set_current_fav( new_state ) ) feVM.update_to_new_list(); // our current display might have changed, so update } redraw = true; } break; case FeInputMap::ToggleTags: if ( feOverlay.tags_dialog() < 0 ) exit_selected = true; redraw = true; break; default: break; } } } // // Determine if we have to do anything because a key is being held down // if ( move_state != FeInputMap::LAST_COMMAND ) { bool cont=false; switch ( move_event.type ) { case sf::Event::KeyPressed: if ( sf::Keyboard::isKeyPressed( move_event.key.code ) ) cont=true; break; case sf::Event::MouseButtonPressed: if ( sf::Mouse::isButtonPressed( move_event.mouseButton.button ) ) cont=true; break; case sf::Event::JoystickButtonPressed: if ( sf::Joystick::isButtonPressed( move_event.joystickButton.joystickId, move_event.joystickButton.button ) ) cont=true; break; case sf::Event::JoystickMoved: { sf::Joystick::update(); float pos = sf::Joystick::getAxisPosition( move_event.joystickMove.joystickId, move_event.joystickMove.axis ); if ( abs( pos ) > feSettings.get_joy_thresh() ) cont=true; } break; default: break; } if ( cont ) { const int TRIG_CHANGE_MS = 400; int t = move_timer.getElapsedTime().asMilliseconds(); if (( t > TRIG_CHANGE_MS ) && ( t - move_last_triggered > feSettings.selection_speed() )) { move_last_triggered = t; int step = 1; if ( feSettings.get_info_bool( FeSettings::AccelerateSelection ) ) { // As the button is held down, the advancement accelerates int shift = ( t / TRIG_CHANGE_MS ) - 3; if ( shift < 0 ) shift = 0; else if ( shift > 7 ) // don't go above a maximum advance of 2^7 (128) shift = 7; step = 1 << ( shift ); } switch ( move_state ) { case FeInputMap::Up: step = -step; break; case FeInputMap::Down: break; // do nothing case FeInputMap::PageUp: step *= -feVM.get_page_size(); break; case FeInputMap::PageDown: step *= feVM.get_page_size(); break; case FeInputMap::PrevFavourite: { int temp = feSettings.get_prev_fav_offset(); step = ( temp < 0 ) ? temp : 0; } break; case FeInputMap::NextFavourite: { int temp = feSettings.get_next_fav_offset(); step = ( temp > 0 ) ? temp : 0; } break; case FeInputMap::PrevLetter: { int temp = feSettings.get_next_letter_offset( -1 ); step = ( temp < 0 ) ? temp : 0; } break; case FeInputMap::NextLetter: { int temp = feSettings.get_next_letter_offset( 1 ); step = ( temp > 0 ) ? temp : 0; } break; default: break; } // // Limit the size of our step so that there is no wrapping around at the end of the list // int curr_sel = feSettings.get_rom_index( feSettings.get_current_filter_index(), 0 ); if ( ( curr_sel + step ) < 0 ) step = -curr_sel; else { int list_size = feSettings.get_filter_size( feSettings.get_current_filter_index() ); if ( ( curr_sel + step ) >= list_size ) step = list_size - curr_sel - 1; } if (( step != 0 ) && ( feVM.script_handle_event( move_state, redraw ) == false )) { feVM.change_selection( step, false ); redraw=true; } } } else { move_state = FeInputMap::LAST_COMMAND; move_last_triggered = 0; feVM.on_end_navigation(); redraw=true; } } if ( feVM.on_tick() ) redraw=true; if ( feVM.video_tick() ) redraw=true; if ( feVM.saver_activation_check() ) soundsys.sound_event( FeInputMap::ScreenSaver ); if ( redraw ) { // begin drawing window.clear(); window.draw( feVM ); window.display(); redraw=false; } else sf::sleep( sf::milliseconds( 30 ) ); soundsys.tick(); } window.on_exit(); feVM.on_stop_frontend(); if ( window.isOpen() ) window.close(); FeRomListSorter::clear_title_rex(); soundsys.stop(); feSettings.save_state(); return 0; }
static as_bool download_complete (ASDownload *dl) { char *prefixed_name; AS_DBG_1 ("Completed download \"%s\"", dl->filename); /* close fd */ if (dl->fp) { fclose (dl->fp); dl->fp = NULL; } /* rename complete file to not include the prefix. */ prefixed_name = as_get_filename (dl->path); if (strncmp (prefixed_name, AS_DOWNLOAD_INCOMPLETE_PREFIX, strlen (AS_DOWNLOAD_INCOMPLETE_PREFIX)) == 0) { char *completed_path, *uniq_path, *dir; /* construct path without ___ARESTRA___ prefix */ dir = gift_strndup (dl->path, prefixed_name - dl->path); completed_path = stringf_dup ("%s%s", dir ? dir : "", prefixed_name + strlen (AS_DOWNLOAD_INCOMPLETE_PREFIX)); free (dir); if ((uniq_path = get_available_filename (completed_path))) { if (rename (dl->path, uniq_path) >= 0) { AS_DBG_2 ("Moved complete file \"%s\" to \"%s\"", dl->path, uniq_path); /* update download filename */ free (dl->path); dl->path = uniq_path; dl->filename = as_get_filename (dl->path); } else { AS_ERR_2 ("Renaming file from \"%s\" to \"%s\" failed.", dl->path, uniq_path); free (uniq_path); } } else { AS_ERR_1 ("No unique name found for \"%s\"", dl->path); } } else { AS_WARN_1 ("Complete file \"%s\" has no prefix. No renaming performed.", dl->path); } /* raise callback */ if (!download_set_state (dl, DOWNLOAD_COMPLETE, TRUE)) return FALSE; return TRUE; }
bool FeSettings::build_romlist( const std::vector< FeImportTask > &task_list, const std::string &output_name, FeFilter &filter, bool full ) { FeRomInfoListType total_romlist; std::string best_name, list_name, path; for ( std::vector<FeImportTask>::const_iterator itr=task_list.begin(); itr < task_list.end(); ++itr ) { if ( (*itr).task_type == FeImportTask::BuildRomlist ) { // Build romlist task std::cout << "*** Generating Collection/Rom List" << std::endl; FeEmulatorInfo *emu = m_rl.get_emulator( (*itr).emulator_name ); if ( emu == NULL ) { std::cout << "Error: Invalid -build-rom-list target: " << (*itr).emulator_name << std::endl; } else { FeRomInfoListType romlist; best_name = emu->get_info( FeEmulatorInfo::Name ); FeImporterContext ctx( *emu, romlist ); build_basic_romlist( ctx ); apply_xml_import( ctx ); apply_import_extras( ctx ); apply_emulator_name( best_name, romlist ); total_romlist.splice( total_romlist.end(), romlist ); } } else if ( (*itr).task_type == FeImportTask::ImportRomlist ) { // import romlist from file task std::cout << "*** Importing Collection/Rom List" << std::endl; FeRomInfoListType romlist; std::string emu_name; if ( (*itr).emulator_name.empty() ) { // deduce the emulator name from the filename provided size_t my_start = (*itr).file_name.find_last_of( "\\/" ); if ( my_start == std::string::npos ) // if there is no / we start at the beginning my_start = 0; else my_start += 1; size_t my_end = (*itr).file_name.find_last_of( "." ); if ( my_end != std::string::npos ) emu_name = (*itr).file_name.substr( my_start, my_end - my_start ); } else emu_name = (*itr).emulator_name; best_name = emu_name; if ( tail_compare( (*itr).file_name, ".txt" ) ) { // Attract-Mode format list // FeRomList temp_list( m_config_path ); temp_list.load_from_file( (*itr).file_name, ";" ); FeRomInfoListType &entries = temp_list.get_list(); for ( FeRomInfoListType::iterator itr = entries.begin(); itr != entries.end(); ++itr ) romlist.push_back( *itr ); } else if ( tail_compare( (*itr).file_name, ".lst" ) ) { // Mamewah/Wahcade! format list // import_mamewah( (*itr).file_name, emu_name, romlist ); } else if ( tail_compare( (*itr).file_name, ".xml" ) ) { // HyperSpin format list // FeHyperSpinXMLParser my_parser( romlist ); if ( my_parser.parse( (*itr).file_name ) ) apply_emulator_name( emu_name, romlist ); } else { std::cerr << "Error: Unsupported --import-rom-list file: " << (*itr).file_name << std::endl; } std::cout << "[Import " << (*itr).file_name << "] - Imported " << romlist.size() << " entries." << std::endl; FeEmulatorInfo *emu = m_rl.get_emulator( emu_name ); if ( emu == NULL ) { std::cout << "Warning: The emulator specified with --import-rom-list was not found: " << emu_name << std::endl; } else { FeImporterContext ctx( *emu, romlist ); apply_import_extras( ctx ); } total_romlist.splice( total_romlist.end(), romlist ); } else // scrape artwork { FeEmulatorInfo *emu = m_rl.get_emulator( (*itr).emulator_name ); if ( emu == NULL ) return false; std::cout << "*** Scraping artwork for: " << (*itr).emulator_name << std::endl; FeRomInfoListType romlist; std::string fn = get_config_dir() + FE_ROMLIST_SUBDIR + (*itr).emulator_name + FE_ROMLIST_FILE_EXTENSION; FeImporterContext ctx( *emu, romlist ); if ( file_exists( fn ) ) { FeRomList loader( get_config_dir() ); loader.load_from_file( fn, ";" ); ctx.romlist.swap( loader.get_list() ); } else { build_basic_romlist( ctx ); apply_xml_import( ctx ); } ctx.scrape_art = true; confirm_directory( get_config_dir(), FE_SCRAPER_SUBDIR ); // do the mamedb scraper first (which only does anything for mame) followed // by the more general thegamesdb scraper. mamedb_scraper( ctx ); thegamesdb_scraper( ctx ); std::cout << "*** Scraping done." << std::endl; } } // return now if all we did was scrape artwork if ( total_romlist.empty() ) return true; total_romlist.sort( FeRomListSorter() ); // strip duplicate entries std::cout << " - Removing any duplicate entries..." << std::endl; total_romlist.unique(); // Apply the specified filter if ( filter.get_rule_count() > 0 ) { std::cout << " - Applying filter..." << std::endl; filter.init(); FeRomInfoListType::iterator last_it=total_romlist.begin(); for ( FeRomInfoListType::iterator it=total_romlist.begin(); it!=total_romlist.end(); ) { if ( filter.apply_filter( *it ) ) { if ( last_it != it ) it = total_romlist.erase( last_it, it ); else ++it; last_it = it; } else ++it; } if ( last_it != total_romlist.end() ) total_romlist.erase( last_it, total_romlist.end() ); } if ( task_list.size() > 1 ) best_name = "multi"; path = get_config_dir(); confirm_directory( path, FE_ROMLIST_SUBDIR ); path += FE_ROMLIST_SUBDIR; // if we weren't given a specific output name, then we come up with a name // that doesn't exist already // if ( output_name.empty() ) get_available_filename( path, best_name, FE_ROMLIST_FILE_EXTENSION, list_name ); else list_name = path + output_name + FE_ROMLIST_FILE_EXTENSION; write_romlist( list_name, total_romlist ); return true; }
/* Start download using hash, filesize and save name. */ as_bool as_download_start (ASDownload *dl, ASHash *hash, size_t filesize, const char *save_path) { ASDownChunk *chunk; char *incomplete, *dir; if (dl->state != DOWNLOAD_NEW) { assert (dl->state == DOWNLOAD_NEW); return FALSE; } if (!hash || !save_path || filesize == 0) { assert (hash); assert (save_path); assert (filesize > 0); return FALSE; } /* create incomplete file path */ dir = gift_strndup (save_path, as_get_filename (save_path) - save_path); incomplete = stringf_dup ("%s%s%s", dir ? dir : "", AS_DOWNLOAD_INCOMPLETE_PREFIX, as_get_filename (save_path)); free (dir); /* find a name which is not used already */ if (!(dl->path = get_available_filename (incomplete))) { AS_ERR_1 ("Couldn't find available file name for download \"%s\"", dl->path); free (incomplete); return FALSE; } free (incomplete); /* set filename after __ARESTRA__prefix */ dl->filename = as_get_filename (dl->path); if (strncmp (dl->filename, AS_DOWNLOAD_INCOMPLETE_PREFIX, strlen (AS_DOWNLOAD_INCOMPLETE_PREFIX)) == 0) dl->filename += strlen (AS_DOWNLOAD_INCOMPLETE_PREFIX); /* open file */ if (!(dl->fp = fopen (dl->path, "w+b"))) { AS_ERR_1 ("Unable to open download file \"%s\" for writing", dl->path); free (dl->path); dl->path = NULL; dl->filename = NULL; return FALSE; } /* create one initial chunk for entire file */ dl->size = filesize; if (!(chunk = as_downchunk_create (0, dl->size))) { AS_ERR_1 ("Couldn't create initial chunk (0,%u)", dl->size); free (dl->path); dl->path = NULL; dl->filename = NULL; dl->size = 0; return FALSE; } dl->chunks = list_prepend (dl->chunks, chunk); /* copy hash */ dl->hash = as_hash_copy (hash); /* raise callback */ if (!download_set_state (dl, DOWNLOAD_ACTIVE, TRUE)) return FALSE; /* Immediately save state data so we have something to recover from. */ if (!as_downstate_save (dl)) { AS_ERR_1 ("Failed to write state data for \"%s\". Pausing.", dl->filename); as_download_pause (dl); /* return TRUE because the download setup has succeeded */ return TRUE; } /* start things off if we are still in active state */ if (dl->state == DOWNLOAD_ACTIVE) download_maintain (dl); return TRUE; }