mirror of
https://github.com/RetroGameSets/RGSX.git
synced 2026-03-20 00:36:06 +01:00
Compare commits
10 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
08f3e64d2a | ||
|
|
4968af2da9 | ||
|
|
920914b374 | ||
|
|
a326cb0b67 | ||
|
|
c9fdf93221 | ||
|
|
184a8c64fe | ||
|
|
9a2e4ce0db | ||
|
|
73eceeb777 | ||
|
|
2fcc4ca6df | ||
|
|
2ed889540b |
13
README.md
13
README.md
@@ -1,11 +1,11 @@
|
||||
# 🎮 Retro Game Sets Xtra (RGSX)
|
||||
|
||||
**[Discord Support](https://discord.gg/Vph9jwg3VV)** • **[Installation](#-installation)** • **[French Documentation](https://github.com/RetroGameSets/RGSX/blob/main/README_FR.md)**
|
||||
**[Discord Support](https://discord.gg/Vph9jwg3VV)** • **[Installation](#-installation)** • **[French Documentation](https://github.com/RetroGameSets/RGSX/blob/main/README_FR.md)** • **[Troubleshoot / Common Errors](https://github.com/RetroGameSets/RGSX#%EF%B8%8F-troubleshooting)** •
|
||||
|
||||
A free, user-friendly ROM downloader for Batocera, Knulli, and RetroBat with multi-source support.
|
||||
|
||||
<p align="center">
|
||||
<img width="69%" alt="platform menu" src="https://github.com/user-attachments/assets/4464b57b-06a8-45e9-a411-cc12b421545a" />
|
||||
<img width="69%" alt="main" src="https://github.com/user-attachments/assets/a98f1189-9a50-4cc3-b588-3f85245640d8" />
|
||||
<img width="30%" alt="controls help" src="https://github.com/user-attachments/assets/38cac7e6-14f2-4e83-91da-0679669822ee" />
|
||||
</p>
|
||||
<p align="center">
|
||||
@@ -201,11 +201,12 @@ RGSX includes a web interface that launched automatically when using RGSX for re
|
||||
|
||||
| Issue | Solution |
|
||||
|-------|----------|
|
||||
| Controls not working | Delete `/saves/ports/rgsx/controls.json` + restart |
|
||||
| Games not showing | Pause Menu > Games > Update Game Cache |
|
||||
| Download stuck | Check API keys in `/saves/ports/rgsx/` |
|
||||
| App crashes | Check `/roms/ports/RGSX/logs/RGSX.log` |
|
||||
| Controls not working | Delete `/saves/ports/rgsx/controls.json` + restart app, you can try delete /roms/ports/RGSX/assets/controls/xx.json too |
|
||||
| No games ? | Pause Menu > Games > Update Game Cache |
|
||||
| Missing systems on the list? | RGSX read es_systems.cfg to show only supported systems, if you want all systems : Pause Menu > Games > Show unsupported systems |
|
||||
| App crashes | Check `/roms/ports/RGSX/logs/RGSX.log` or `/roms/windows/logs/Retrobat_RGSX_log.txt` |
|
||||
| Layout change not applied | Restart RGSX after changing layout |
|
||||
| Downloading BIOS file is ok but you can't download any games? | Activate custom DNS on Pause Menu> Settings and reboot , server can be blocked by your ISP. check any threat/website protection on your router too, especially on ASUS one|
|
||||
|
||||
**Need help?** Share logs from `/roms/ports/RGSX/logs/` on [Discord](https://discord.gg/Vph9jwg3VV).
|
||||
|
||||
|
||||
@@ -1,5 +1,11 @@
|
||||
import os
|
||||
import platform
|
||||
import warnings
|
||||
|
||||
# Ignorer le warning de deprecation de pkg_resources dans pygame
|
||||
warnings.filterwarnings("ignore", category=UserWarning, module="pygame.pkgdata")
|
||||
warnings.filterwarnings("ignore", message="pkg_resources is deprecated")
|
||||
|
||||
# Ne pas forcer SDL_FBDEV ici; si déjà défini par l'environnement, on le garde
|
||||
try:
|
||||
if "SDL_FBDEV" in os.environ:
|
||||
@@ -170,7 +176,6 @@ config.init_footer_font()
|
||||
|
||||
# Mise à jour de la résolution dans config
|
||||
config.screen_width, config.screen_height = pygame.display.get_surface().get_size()
|
||||
logger.debug(f"Resolution d'ecran : {config.screen_width}x{config.screen_height}")
|
||||
print(f"Resolution ecran validee: {config.screen_width}x{config.screen_height}")
|
||||
|
||||
# Afficher un premier écran de chargement immédiatement pour éviter un écran noir
|
||||
@@ -270,7 +275,6 @@ logger.debug(f"Historique de téléchargement : {len(config.history)} entrées")
|
||||
|
||||
# Chargement des jeux téléchargés
|
||||
config.downloaded_games = load_downloaded_games()
|
||||
logger.debug(f"Jeux téléchargés : {sum(len(v) for v in config.downloaded_games.values())} jeux")
|
||||
|
||||
# Vérification et chargement de la configuration des contrôles (après mises à jour et détection manette)
|
||||
config.controls_config = load_controls_config()
|
||||
@@ -296,6 +300,9 @@ try:
|
||||
if config.controls_config:
|
||||
summary = {}
|
||||
for action, mapping in config.controls_config.items():
|
||||
# Vérifier que mapping est bien un dictionnaire
|
||||
if not isinstance(mapping, dict):
|
||||
continue
|
||||
mtype = mapping.get("type")
|
||||
val = None
|
||||
if mtype == "key":
|
||||
@@ -335,9 +342,6 @@ def start_web_server():
|
||||
global web_server_process
|
||||
try:
|
||||
web_server_script = os.path.join(config.APP_FOLDER, "rgsx_web.py")
|
||||
logger.info(f"Tentative de démarrage du serveur web...")
|
||||
logger.info(f"Script: {web_server_script}")
|
||||
logger.info(f"Fichier existe: {os.path.exists(web_server_script)}")
|
||||
|
||||
if not os.path.exists(web_server_script):
|
||||
logger.warning(f"Script serveur web introuvable: {web_server_script}")
|
||||
@@ -378,7 +382,6 @@ def start_web_server():
|
||||
|
||||
logger.info(f"✅ Serveur web démarré (PID: {web_server_process.pid})")
|
||||
logger.info(f"🌐 Serveur accessible sur http://localhost:5000")
|
||||
logger.info(f"📝 Logs de démarrage: {web_server_log}")
|
||||
|
||||
# Attendre un peu pour voir si le processus crash immédiatement
|
||||
import time
|
||||
@@ -441,7 +444,6 @@ async def main():
|
||||
# Démarrer le worker de la queue de téléchargement
|
||||
queue_worker_thread = threading.Thread(target=download_queue_worker, daemon=True)
|
||||
queue_worker_thread.start()
|
||||
logger.info("Worker de la queue de téléchargement démarré")
|
||||
|
||||
running = True
|
||||
loading_step = "none"
|
||||
@@ -1229,6 +1231,7 @@ async def main():
|
||||
config.loading_progress = 20.0
|
||||
config.needs_redraw = True
|
||||
logger.debug(f"Étape chargement : {loading_step}, progress={config.loading_progress}")
|
||||
continue # Passer immédiatement à check_ota
|
||||
else:
|
||||
config.menu_state = "error"
|
||||
config.error_message = _("error_no_internet")
|
||||
@@ -1258,6 +1261,7 @@ async def main():
|
||||
config.loading_progress = 50.0
|
||||
config.needs_redraw = True
|
||||
logger.debug(f"Étape chargement : {loading_step}, progress={config.loading_progress}")
|
||||
continue # Passer immédiatement à check_data
|
||||
elif loading_step == "check_data":
|
||||
is_data_empty = not os.path.exists(config.GAMES_FOLDER) or not any(os.scandir(config.GAMES_FOLDER))
|
||||
if is_data_empty:
|
||||
@@ -1265,6 +1269,7 @@ async def main():
|
||||
config.loading_progress = 30.0
|
||||
config.needs_redraw = True
|
||||
logger.debug("Dossier Data vide, début du téléchargement du ZIP")
|
||||
sources_zip_url = None # Initialiser pour éviter les erreurs
|
||||
try:
|
||||
zip_path = os.path.join(config.SAVE_FOLDER, "data_download.zip")
|
||||
headers = {'User-Agent': 'Mozilla/5.0'}
|
||||
@@ -1370,7 +1375,9 @@ async def main():
|
||||
config.loading_progress = 80.0
|
||||
config.needs_redraw = True
|
||||
logger.debug(f"Dossier Data non vide, passage à {loading_step}")
|
||||
continue # Passer immédiatement à load_sources
|
||||
elif loading_step == "load_sources":
|
||||
logger.debug(f"Étape chargement : {loading_step}, progress={config.loading_progress}")
|
||||
sources = load_sources()
|
||||
config.menu_state = "platform"
|
||||
config.loading_progress = 100.0
|
||||
|
||||
@@ -13,7 +13,7 @@ except Exception:
|
||||
pygame = None # type: ignore
|
||||
|
||||
# Version actuelle de l'application
|
||||
app_version = "2.3.3.3"
|
||||
app_version = "2.4.0.2"
|
||||
|
||||
|
||||
def get_application_root():
|
||||
|
||||
@@ -1658,12 +1658,14 @@ def handle_controls(event, sources, joystick, screen):
|
||||
config.needs_redraw = True
|
||||
logger.debug(f"Start: retour à {config.menu_state} depuis pause_menu")
|
||||
elif is_input_matched(event, "up"):
|
||||
config.selected_option = max(0, config.selected_option - 1)
|
||||
# Menu racine hiérarchique: nombre dynamique (langue + catégories)
|
||||
total = getattr(config, 'pause_menu_total_options', 7)
|
||||
config.selected_option = (config.selected_option - 1) % total
|
||||
config.needs_redraw = True
|
||||
elif is_input_matched(event, "down"):
|
||||
# Menu racine hiérarchique: nombre dynamique (langue + catégories)
|
||||
total = getattr(config, 'pause_menu_total_options', 7)
|
||||
config.selected_option = min(total - 1, config.selected_option + 1)
|
||||
config.selected_option = (config.selected_option + 1) % total
|
||||
config.needs_redraw = True
|
||||
elif is_input_matched(event, "confirm"):
|
||||
if config.selected_option == 0: # Games submenu
|
||||
@@ -1753,7 +1755,8 @@ def handle_controls(event, sources, joystick, screen):
|
||||
# Sous-menu Display
|
||||
elif config.menu_state == "pause_display_menu":
|
||||
sel = getattr(config, 'pause_display_selection', 0)
|
||||
total = 6 # layout, font size, footer font size, font family, allow unknown extensions, back
|
||||
# layout, font size, footer font size, font family, monitor, light, allow unknown extensions, back (8)
|
||||
total = 8
|
||||
if is_input_matched(event, "up"):
|
||||
config.pause_display_selection = (sel - 1) % total
|
||||
config.needs_redraw = True
|
||||
@@ -1848,8 +1851,37 @@ def handle_controls(event, sources, joystick, screen):
|
||||
config.needs_redraw = True
|
||||
except Exception as e:
|
||||
logger.error(f"Erreur changement font family: {e}")
|
||||
# 4 allow unknown extensions
|
||||
elif sel == 4 and (is_input_matched(event, "left") or is_input_matched(event, "right") or is_input_matched(event, "confirm")):
|
||||
# 4 monitor selection
|
||||
elif sel == 4 and (is_input_matched(event, "left") or is_input_matched(event, "right")):
|
||||
try:
|
||||
from rgsx_settings import get_display_monitor, set_display_monitor, get_available_monitors
|
||||
monitors = get_available_monitors()
|
||||
num_monitors = len(monitors)
|
||||
if num_monitors > 1:
|
||||
current = get_display_monitor()
|
||||
new_monitor = (current - 1) % num_monitors if is_input_matched(event, "left") else (current + 1) % num_monitors
|
||||
set_display_monitor(new_monitor)
|
||||
config.popup_message = _("display_monitor_restart_required") if _ else "Restart required to apply monitor change"
|
||||
config.popup_timer = 3000
|
||||
else:
|
||||
config.popup_message = _("display_monitor_single_only") if _ else "Only one monitor detected"
|
||||
config.popup_timer = 2000
|
||||
config.needs_redraw = True
|
||||
except Exception as e:
|
||||
logger.error(f"Erreur changement moniteur: {e}")
|
||||
# 5 light mode toggle
|
||||
elif sel == 5 and (is_input_matched(event, "left") or is_input_matched(event, "right") or is_input_matched(event, "confirm")):
|
||||
try:
|
||||
from rgsx_settings import get_light_mode, set_light_mode
|
||||
current = get_light_mode()
|
||||
new_val = set_light_mode(not current)
|
||||
config.popup_message = _("display_light_mode_enabled") if new_val else _("display_light_mode_disabled")
|
||||
config.popup_timer = 2000
|
||||
config.needs_redraw = True
|
||||
except Exception as e:
|
||||
logger.error(f"Erreur toggle light mode: {e}")
|
||||
# 6 allow unknown extensions
|
||||
elif sel == 6 and (is_input_matched(event, "left") or is_input_matched(event, "right") or is_input_matched(event, "confirm")):
|
||||
try:
|
||||
current = get_allow_unknown_extensions()
|
||||
new_val = set_allow_unknown_extensions(not current)
|
||||
@@ -1858,8 +1890,8 @@ def handle_controls(event, sources, joystick, screen):
|
||||
config.needs_redraw = True
|
||||
except Exception as e:
|
||||
logger.error(f"Erreur toggle allow_unknown_extensions: {e}")
|
||||
# 5 back
|
||||
elif sel == 5 and is_input_matched(event, "confirm"):
|
||||
# 7 back
|
||||
elif sel == 7 and is_input_matched(event, "confirm"):
|
||||
config.menu_state = "pause_menu"
|
||||
config.last_state_change_time = pygame.time.get_ticks()
|
||||
config.needs_redraw = True
|
||||
@@ -2051,14 +2083,15 @@ def handle_controls(event, sources, joystick, screen):
|
||||
config.needs_redraw = True
|
||||
logger.debug("Retour au menu pause depuis controls_help")
|
||||
|
||||
# Menu Affichage (layout, police, unsupported)
|
||||
# Menu Affichage (layout, police, moniteur, mode écran, unsupported, extensions, filtres)
|
||||
elif config.menu_state == "display_menu":
|
||||
sel = getattr(config, 'display_menu_selection', 0)
|
||||
num_options = 7 # Layout, Font, Monitor, Mode, Unsupported, Extensions, Filters
|
||||
if is_input_matched(event, "up"):
|
||||
config.display_menu_selection = (sel - 1) % 5
|
||||
config.display_menu_selection = (sel - 1) % num_options
|
||||
config.needs_redraw = True
|
||||
elif is_input_matched(event, "down"):
|
||||
config.display_menu_selection = (sel + 1) % 5
|
||||
config.display_menu_selection = (sel + 1) % num_options
|
||||
config.needs_redraw = True
|
||||
elif is_input_matched(event, "left") or is_input_matched(event, "right") or is_input_matched(event, "confirm"):
|
||||
# 0: layout change
|
||||
@@ -2104,8 +2137,40 @@ def handle_controls(event, sources, joystick, screen):
|
||||
except Exception as e:
|
||||
logger.error(f"Erreur init polices: {e}")
|
||||
config.needs_redraw = True
|
||||
# 2: toggle unsupported
|
||||
elif sel == 2 and (is_input_matched(event, "left") or is_input_matched(event, "right") or is_input_matched(event, "confirm")):
|
||||
# 2: monitor selection (new)
|
||||
elif sel == 2 and (is_input_matched(event, "left") or is_input_matched(event, "right")):
|
||||
try:
|
||||
from rgsx_settings import get_display_monitor, set_display_monitor, get_available_monitors
|
||||
monitors = get_available_monitors()
|
||||
num_monitors = len(monitors)
|
||||
if num_monitors > 1:
|
||||
current = get_display_monitor()
|
||||
new_monitor = (current - 1) % num_monitors if is_input_matched(event, "left") else (current + 1) % num_monitors
|
||||
set_display_monitor(new_monitor)
|
||||
config.needs_redraw = True
|
||||
# Informer l'utilisateur qu'un redémarrage est nécessaire
|
||||
config.popup_message = _("display_monitor_restart_required")
|
||||
config.popup_timer = 3000
|
||||
else:
|
||||
config.popup_message = _("display_monitor_single_only")
|
||||
config.popup_timer = 2000
|
||||
config.needs_redraw = True
|
||||
except Exception as e:
|
||||
logger.error(f"Erreur changement moniteur: {e}")
|
||||
# 3: fullscreen/windowed toggle (new)
|
||||
elif sel == 3 and (is_input_matched(event, "left") or is_input_matched(event, "right") or is_input_matched(event, "confirm")):
|
||||
try:
|
||||
from rgsx_settings import get_display_fullscreen, set_display_fullscreen
|
||||
current = get_display_fullscreen()
|
||||
new_val = set_display_fullscreen(not current)
|
||||
config.needs_redraw = True
|
||||
# Informer l'utilisateur qu'un redémarrage est nécessaire
|
||||
config.popup_message = _("display_mode_restart_required")
|
||||
config.popup_timer = 3000
|
||||
except Exception as e:
|
||||
logger.error(f"Erreur toggle fullscreen: {e}")
|
||||
# 4: toggle unsupported (was 2)
|
||||
elif sel == 4 and (is_input_matched(event, "left") or is_input_matched(event, "right") or is_input_matched(event, "confirm")):
|
||||
try:
|
||||
current = get_show_unsupported_platforms()
|
||||
new_val = set_show_unsupported_platforms(not current)
|
||||
@@ -2115,8 +2180,8 @@ def handle_controls(event, sources, joystick, screen):
|
||||
config.needs_redraw = True
|
||||
except Exception as e:
|
||||
logger.error(f"Erreur toggle unsupported: {e}")
|
||||
# 3: toggle allow unknown extensions
|
||||
elif sel == 3 and (is_input_matched(event, "left") or is_input_matched(event, "right") or is_input_matched(event, "confirm")):
|
||||
# 5: toggle allow unknown extensions (was 3)
|
||||
elif sel == 5 and (is_input_matched(event, "left") or is_input_matched(event, "right") or is_input_matched(event, "confirm")):
|
||||
try:
|
||||
current = get_allow_unknown_extensions()
|
||||
new_val = set_allow_unknown_extensions(not current)
|
||||
@@ -2125,8 +2190,8 @@ def handle_controls(event, sources, joystick, screen):
|
||||
config.needs_redraw = True
|
||||
except Exception as e:
|
||||
logger.error(f"Erreur toggle allow_unknown_extensions: {e}")
|
||||
# 4: open filter platforms menu
|
||||
elif sel == 4 and (is_input_matched(event, "confirm") or is_input_matched(event, "right")):
|
||||
# 6: open filter platforms menu (was 4)
|
||||
elif sel == 6 and (is_input_matched(event, "confirm") or is_input_matched(event, "right")):
|
||||
# Remember return target so the filter menu can go back to display
|
||||
config.filter_return_to = "display_menu"
|
||||
config.menu_state = "filter_platforms"
|
||||
|
||||
@@ -3,12 +3,21 @@
|
||||
import pygame # type: ignore
|
||||
import os
|
||||
import io
|
||||
import platform
|
||||
import random
|
||||
import config
|
||||
from utils import truncate_text_middle, wrap_text, load_system_image, truncate_text_end
|
||||
from utils import (truncate_text_middle, wrap_text, load_system_image, truncate_text_end,
|
||||
check_web_service_status, check_custom_dns_status, load_api_keys,
|
||||
_get_dest_folder_name, find_file_with_or_without_extension)
|
||||
import logging
|
||||
import math
|
||||
from history import load_history, is_game_downloaded
|
||||
from language import _, get_size_units, get_speed_unit
|
||||
from language import _, get_size_units, get_speed_unit, get_available_languages, get_language_name
|
||||
from rgsx_settings import (load_rgsx_settings, get_light_mode, get_show_unsupported_platforms,
|
||||
get_allow_unknown_extensions, get_display_monitor, get_display_fullscreen,
|
||||
get_available_monitors, get_font_family, get_sources_mode,
|
||||
get_hide_premium_systems, get_symlink_option)
|
||||
from game_filters import GameFilters
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
@@ -225,26 +234,113 @@ THEME_COLORS = {
|
||||
|
||||
# Général, résolution, overlay
|
||||
def init_display():
|
||||
"""Initialise l'écran et les ressources globales."""
|
||||
"""Initialise l'écran et les ressources globales.
|
||||
Supporte la sélection de moniteur en plein écran.
|
||||
Compatible Windows et Linux (Batocera).
|
||||
"""
|
||||
global OVERLAY
|
||||
logger.debug("Initialisation de l'écran")
|
||||
display_info = pygame.display.Info()
|
||||
screen_width = display_info.current_w
|
||||
screen_height = display_info.current_h
|
||||
screen = pygame.display.set_mode((screen_width, screen_height))
|
||||
|
||||
|
||||
# Charger les paramètres d'affichage
|
||||
settings = load_rgsx_settings()
|
||||
logger.debug(f"Settings chargés: display={settings.get('display', {})}")
|
||||
target_monitor = settings.get("display", {}).get("monitor", 0)
|
||||
|
||||
|
||||
# Vérifier les variables d'environnement (priorité sur les settings)
|
||||
env_display = os.environ.get("RGSX_DISPLAY")
|
||||
if env_display is not None:
|
||||
try:
|
||||
target_monitor = int(env_display)
|
||||
logger.debug(f"Override par RGSX_DISPLAY: monitor={target_monitor}")
|
||||
except ValueError:
|
||||
pass
|
||||
|
||||
|
||||
# Configurer SDL pour utiliser le bon moniteur
|
||||
# Cette variable d'environnement doit être définie AVANT la création de la fenêtre
|
||||
os.environ["SDL_VIDEO_FULLSCREEN_HEAD"] = str(target_monitor)
|
||||
|
||||
# Obtenir les informations d'affichage
|
||||
num_displays = 1
|
||||
try:
|
||||
num_displays = pygame.display.get_num_displays()
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
# S'assurer que le moniteur cible existe
|
||||
if target_monitor >= num_displays:
|
||||
logger.warning(f"Monitor {target_monitor} not available, using monitor 0")
|
||||
target_monitor = 0
|
||||
|
||||
# Obtenir la résolution du moniteur cible
|
||||
try:
|
||||
if hasattr(pygame.display, 'get_desktop_sizes') and num_displays > 1:
|
||||
desktop_sizes = pygame.display.get_desktop_sizes()
|
||||
if target_monitor < len(desktop_sizes):
|
||||
screen_width, screen_height = desktop_sizes[target_monitor]
|
||||
else:
|
||||
display_info = pygame.display.Info()
|
||||
screen_width = display_info.current_w
|
||||
screen_height = display_info.current_h
|
||||
else:
|
||||
display_info = pygame.display.Info()
|
||||
screen_width = display_info.current_w
|
||||
screen_height = display_info.current_h
|
||||
except Exception as e:
|
||||
logger.error(f"Error getting display info: {e}")
|
||||
display_info = pygame.display.Info()
|
||||
screen_width = display_info.current_w
|
||||
screen_height = display_info.current_h
|
||||
|
||||
# Créer la fenêtre en plein écran
|
||||
flags = pygame.FULLSCREEN
|
||||
# Sur Linux/Batocera, utiliser SCALED pour respecter la résolution forcée d'EmulationStation
|
||||
if platform.system() == "Linux":
|
||||
flags |= pygame.SCALED
|
||||
# Sur certains systèmes Windows, NOFRAME aide pour le multi-écran
|
||||
elif platform.system() == "Windows":
|
||||
flags |= pygame.NOFRAME
|
||||
|
||||
try:
|
||||
screen = pygame.display.set_mode((screen_width, screen_height), flags, display=target_monitor)
|
||||
except TypeError:
|
||||
# Anciennes versions de pygame ne supportent pas le paramètre display=
|
||||
screen = pygame.display.set_mode((screen_width, screen_height), flags)
|
||||
except Exception as e:
|
||||
logger.error(f"Error creating display on monitor {target_monitor}: {e}")
|
||||
screen = pygame.display.set_mode((screen_width, screen_height), flags)
|
||||
|
||||
config.screen_width = screen_width
|
||||
config.screen_height = screen_height
|
||||
config.current_monitor = target_monitor
|
||||
|
||||
# Initialisation de OVERLAY avec effet glassmorphism
|
||||
OVERLAY = pygame.Surface((screen_width, screen_height), pygame.SRCALPHA)
|
||||
OVERLAY.fill((5, 10, 20, 160)) # Bleu très foncé semi-transparent pour effet verre
|
||||
logger.debug(f"Écran initialisé avec résolution : {screen_width}x{screen_height}")
|
||||
logger.debug(f"Écran initialisé: {screen_width}x{screen_height} sur moniteur {target_monitor}")
|
||||
return screen
|
||||
|
||||
# Fond d'écran dégradé
|
||||
def draw_gradient(screen, top_color, bottom_color):
|
||||
"""Dessine un fond dégradé vertical avec des couleurs vibrantes et texture de grain."""
|
||||
def draw_gradient(screen, top_color, bottom_color, light_mode=None):
|
||||
"""Dessine un fond dégradé vertical avec des couleurs vibrantes et texture de grain.
|
||||
En mode light, utilise une couleur unie pour de meilleures performances."""
|
||||
if light_mode is None:
|
||||
light_mode = get_light_mode()
|
||||
|
||||
height = screen.get_height()
|
||||
width = screen.get_width()
|
||||
|
||||
if light_mode:
|
||||
# Mode light: couleur unie (moyenne des deux couleurs)
|
||||
avg_color = (
|
||||
(top_color[0] + bottom_color[0]) // 2,
|
||||
(top_color[1] + bottom_color[1]) // 2,
|
||||
(top_color[2] + bottom_color[2]) // 2
|
||||
)
|
||||
screen.fill(avg_color)
|
||||
return
|
||||
|
||||
top_color = pygame.Color(*top_color)
|
||||
bottom_color = pygame.Color(*bottom_color)
|
||||
|
||||
@@ -256,7 +352,6 @@ def draw_gradient(screen, top_color, bottom_color):
|
||||
|
||||
# Ajouter une texture de grain subtile pour plus de profondeur
|
||||
grain_surface = pygame.Surface((width, height), pygame.SRCALPHA)
|
||||
import random
|
||||
random.seed(42) # Seed fixe pour cohérence
|
||||
for _ in range(width * height // 200): # Réduire la densité pour performance
|
||||
x = random.randint(0, width - 1)
|
||||
@@ -266,15 +361,23 @@ def draw_gradient(screen, top_color, bottom_color):
|
||||
screen.blit(grain_surface, (0, 0))
|
||||
|
||||
|
||||
def draw_shadow(surface, rect, offset=6, alpha=120):
|
||||
"""Dessine une ombre portée pour un rectangle."""
|
||||
def draw_shadow(surface, rect, offset=6, alpha=120, light_mode=None):
|
||||
"""Dessine une ombre portée pour un rectangle. Désactivé en mode light."""
|
||||
if light_mode is None:
|
||||
light_mode = get_light_mode()
|
||||
if light_mode:
|
||||
return None # Pas d'ombre en mode light
|
||||
shadow = pygame.Surface((rect.width + offset, rect.height + offset), pygame.SRCALPHA)
|
||||
pygame.draw.rect(shadow, (0, 0, 0, alpha), (0, 0, rect.width + offset, rect.height + offset), border_radius=15)
|
||||
return shadow
|
||||
|
||||
|
||||
def draw_glow_effect(screen, rect, color, intensity=80, size=10):
|
||||
"""Dessine un effet de glow autour d'un rectangle."""
|
||||
def draw_glow_effect(screen, rect, color, intensity=80, size=10, light_mode=None):
|
||||
"""Dessine un effet de glow autour d'un rectangle. Désactivé en mode light."""
|
||||
if light_mode is None:
|
||||
light_mode = get_light_mode()
|
||||
if light_mode:
|
||||
return # Pas de glow en mode light
|
||||
glow = pygame.Surface((rect.width + size * 2, rect.height + size * 2), pygame.SRCALPHA)
|
||||
for i in range(size):
|
||||
alpha = int(intensity * (1 - i / size))
|
||||
@@ -284,55 +387,67 @@ def draw_glow_effect(screen, rect, color, intensity=80, size=10):
|
||||
screen.blit(glow, (rect.x - size, rect.y - size))
|
||||
|
||||
# Nouvelle fonction pour dessiner un bouton stylisé
|
||||
def draw_stylized_button(screen, text, x, y, width, height, selected=False):
|
||||
"""Dessine un bouton moderne avec effet de survol, ombre et bordure arrondie."""
|
||||
# Ombre portée subtile
|
||||
shadow_surf = pygame.Surface((width + 6, height + 6), pygame.SRCALPHA)
|
||||
pygame.draw.rect(shadow_surf, THEME_COLORS["shadow"], (3, 3, width, height), border_radius=12)
|
||||
screen.blit(shadow_surf, (x - 3, y - 3))
|
||||
def draw_stylized_button(screen, text, x, y, width, height, selected=False, light_mode=None):
|
||||
"""Dessine un bouton moderne avec effet de survol, ombre et bordure arrondie.
|
||||
En mode light, utilise un style simplifié pour de meilleures performances."""
|
||||
if light_mode is None:
|
||||
light_mode = get_light_mode()
|
||||
|
||||
button_color = THEME_COLORS["button_hover"] if selected else THEME_COLORS["button_idle"]
|
||||
|
||||
button_surface = pygame.Surface((width, height), pygame.SRCALPHA)
|
||||
|
||||
# Fond avec dégradé subtil pour bouton sélectionné
|
||||
if selected:
|
||||
# Créer le dégradé
|
||||
for i in range(height):
|
||||
ratio = i / height
|
||||
brightness = 1 + 0.2 * ratio
|
||||
r = min(255, int(button_color[0] * brightness))
|
||||
g = min(255, int(button_color[1] * brightness))
|
||||
b = min(255, int(button_color[2] * brightness))
|
||||
alpha = button_color[3] if len(button_color) > 3 else 255
|
||||
rect = pygame.Rect(0, i, width, 1)
|
||||
pygame.draw.rect(button_surface, (r, g, b, alpha), rect)
|
||||
|
||||
# Appliquer les coins arrondis avec un masque
|
||||
mask_surface = pygame.Surface((width, height), pygame.SRCALPHA)
|
||||
pygame.draw.rect(mask_surface, (255, 255, 255, 255), (0, 0, width, height), border_radius=12)
|
||||
button_surface.blit(mask_surface, (0, 0), special_flags=pygame.BLEND_RGBA_MIN)
|
||||
if light_mode:
|
||||
# Mode light: bouton simple sans effets
|
||||
pygame.draw.rect(screen, button_color[:3], (x, y, width, height), border_radius=8)
|
||||
if selected:
|
||||
# Bordure simple pour indiquer la sélection
|
||||
pygame.draw.rect(screen, THEME_COLORS["neon"], (x, y, width, height), width=2, border_radius=8)
|
||||
else:
|
||||
pygame.draw.rect(button_surface, button_color, (0, 0, width, height), border_radius=12)
|
||||
|
||||
# Reflet en haut
|
||||
highlight = pygame.Surface((width - 4, height // 3), pygame.SRCALPHA)
|
||||
highlight.fill(THEME_COLORS["highlight"])
|
||||
button_surface.blit(highlight, (2, 2))
|
||||
|
||||
# Bordure
|
||||
pygame.draw.rect(button_surface, THEME_COLORS["border"], (0, 0, width, height), 2, border_radius=12)
|
||||
|
||||
if selected:
|
||||
# Effet glow doux pour sélection
|
||||
glow_surface = pygame.Surface((width + 16, height + 16), pygame.SRCALPHA)
|
||||
for i in range(6):
|
||||
alpha = int(40 * (1 - i / 6))
|
||||
pygame.draw.rect(glow_surface, (*THEME_COLORS["glow"][:3], alpha),
|
||||
(i, i, width + 16 - i*2, height + 16 - i*2), border_radius=15)
|
||||
screen.blit(glow_surface, (x - 8, y - 8))
|
||||
|
||||
screen.blit(button_surface, (x, y))
|
||||
# Mode normal avec tous les effets
|
||||
# Ombre portée subtile
|
||||
shadow_surf = pygame.Surface((width + 6, height + 6), pygame.SRCALPHA)
|
||||
pygame.draw.rect(shadow_surf, THEME_COLORS["shadow"], (3, 3, width, height), border_radius=12)
|
||||
screen.blit(shadow_surf, (x - 3, y - 3))
|
||||
|
||||
button_surface = pygame.Surface((width, height), pygame.SRCALPHA)
|
||||
|
||||
# Fond avec dégradé subtil pour bouton sélectionné
|
||||
if selected:
|
||||
# Créer le dégradé
|
||||
for i in range(height):
|
||||
ratio = i / height
|
||||
brightness = 1 + 0.2 * ratio
|
||||
r = min(255, int(button_color[0] * brightness))
|
||||
g = min(255, int(button_color[1] * brightness))
|
||||
b = min(255, int(button_color[2] * brightness))
|
||||
alpha = button_color[3] if len(button_color) > 3 else 255
|
||||
rect = pygame.Rect(0, i, width, 1)
|
||||
pygame.draw.rect(button_surface, (r, g, b, alpha), rect)
|
||||
|
||||
# Appliquer les coins arrondis avec un masque
|
||||
mask_surface = pygame.Surface((width, height), pygame.SRCALPHA)
|
||||
pygame.draw.rect(mask_surface, (255, 255, 255, 255), (0, 0, width, height), border_radius=12)
|
||||
button_surface.blit(mask_surface, (0, 0), special_flags=pygame.BLEND_RGBA_MIN)
|
||||
else:
|
||||
pygame.draw.rect(button_surface, button_color, (0, 0, width, height), border_radius=12)
|
||||
|
||||
# Reflet en haut
|
||||
highlight = pygame.Surface((width - 4, height // 3), pygame.SRCALPHA)
|
||||
highlight.fill(THEME_COLORS["highlight"])
|
||||
button_surface.blit(highlight, (2, 2))
|
||||
|
||||
# Bordure
|
||||
pygame.draw.rect(button_surface, THEME_COLORS["border"], (0, 0, width, height), 2, border_radius=12)
|
||||
|
||||
if selected:
|
||||
# Effet glow doux pour sélection
|
||||
glow_surface = pygame.Surface((width + 16, height + 16), pygame.SRCALPHA)
|
||||
for i in range(6):
|
||||
alpha = int(40 * (1 - i / 6))
|
||||
pygame.draw.rect(glow_surface, (*THEME_COLORS["glow"][:3], alpha),
|
||||
(i, i, width + 16 - i*2, height + 16 - i*2), border_radius=15)
|
||||
screen.blit(glow_surface, (x - 8, y - 8))
|
||||
|
||||
screen.blit(button_surface, (x, y))
|
||||
|
||||
# Vérifier si le texte dépasse la largeur disponible
|
||||
text_surface = config.font.render(text, True, THEME_COLORS["text"])
|
||||
@@ -1721,49 +1836,46 @@ def draw_extension_warning(screen):
|
||||
def draw_controls(screen, menu_state, current_music_name=None, music_popup_start_time=0):
|
||||
"""Affiche les contrôles contextuels en bas de l'écran selon le menu_state."""
|
||||
|
||||
# Import local de la fonction de traduction pour éviter les conflits de scope
|
||||
from language import _ as i18n
|
||||
|
||||
# Mapping des contrôles par menu_state
|
||||
controls_map = {
|
||||
"platform": [
|
||||
("history", i18n("controls_action_history")),
|
||||
("confirm", i18n("controls_confirm_select")),
|
||||
("start", i18n("controls_action_start")),
|
||||
("history", _("controls_action_history")),
|
||||
("confirm", _("controls_confirm_select")),
|
||||
("start", _("controls_action_start")),
|
||||
],
|
||||
"game": [
|
||||
("confirm", i18n("controls_confirm_select")),
|
||||
("clear_history", i18n("controls_action_queue")),
|
||||
(("page_up", "page_down"), i18n("controls_pages")),
|
||||
("filter", i18n("controls_filter_search")),
|
||||
("history", i18n("controls_action_history")),
|
||||
("confirm", _("controls_confirm_select")),
|
||||
("clear_history", _("controls_action_queue")),
|
||||
(("page_up", "page_down"), _("controls_pages")),
|
||||
("filter", _("controls_filter_search")),
|
||||
("history", _("controls_action_history")),
|
||||
],
|
||||
"history": [
|
||||
("confirm", i18n("history_game_options_title")),
|
||||
("clear_history", i18n("controls_action_clear_history")),
|
||||
("history", i18n("controls_action_close_history")),
|
||||
("cancel", i18n("controls_cancel_back")),
|
||||
("confirm", _("history_game_options_title")),
|
||||
("clear_history", _("controls_action_clear_history")),
|
||||
("history", _("controls_action_close_history")),
|
||||
("cancel", _("controls_cancel_back")),
|
||||
],
|
||||
"scraper": [
|
||||
("confirm", i18n("controls_confirm_select")),
|
||||
("cancel", i18n("controls_cancel_back")),
|
||||
("confirm", _("controls_confirm_select")),
|
||||
("cancel", _("controls_cancel_back")),
|
||||
],
|
||||
"error": [
|
||||
("confirm", i18n("controls_confirm_select")),
|
||||
("confirm", _("controls_confirm_select")),
|
||||
],
|
||||
"confirm_exit": [
|
||||
("confirm", i18n("controls_confirm_select")),
|
||||
("cancel", i18n("controls_cancel_back")),
|
||||
("confirm", _("controls_confirm_select")),
|
||||
("cancel", _("controls_cancel_back")),
|
||||
],
|
||||
"extension_warning": [
|
||||
("confirm", i18n("controls_confirm_select")),
|
||||
("confirm", _("controls_confirm_select")),
|
||||
],
|
||||
}
|
||||
|
||||
# Récupérer les contrôles pour ce menu, sinon affichage par défaut
|
||||
controls_list = controls_map.get(menu_state, [
|
||||
("confirm", i18n("controls_confirm_select")),
|
||||
("cancel", i18n("controls_cancel_back")),
|
||||
("confirm", _("controls_confirm_select")),
|
||||
("cancel", _("controls_cancel_back")),
|
||||
])
|
||||
|
||||
# Construire les lignes avec icônes
|
||||
@@ -1777,7 +1889,7 @@ def draw_controls(screen, menu_state, current_music_name=None, music_popup_start
|
||||
# Si aucun joystick, afficher la touche entre crochets
|
||||
if not getattr(config, 'joystick', True):
|
||||
start_button = f"[{start_button}]"
|
||||
start_text = i18n("controls_action_start")
|
||||
start_text = _("controls_action_start")
|
||||
control_parts.append(f"RGSX v{config.app_version} - {start_button} : {start_text}")
|
||||
|
||||
# Afficher le nom du joystick s'il est détecté
|
||||
@@ -1785,7 +1897,7 @@ def draw_controls(screen, menu_state, current_music_name=None, music_popup_start
|
||||
device_name = getattr(config, 'controller_device_name', '') or ''
|
||||
if device_name:
|
||||
try:
|
||||
joy_label = i18n("footer_joystick")
|
||||
joy_label = _("footer_joystick")
|
||||
except Exception:
|
||||
joy_label = "Joystick: {0}"
|
||||
if isinstance(joy_label, str) and "{0}" in joy_label:
|
||||
@@ -1840,7 +1952,7 @@ def draw_controls(screen, menu_state, current_music_name=None, music_popup_start
|
||||
combined_surf = pygame.Surface((max_width, 50), pygame.SRCALPHA)
|
||||
x_pos = 10
|
||||
for action_tuple in all_controls:
|
||||
_, actions, label = action_tuple
|
||||
ignored, actions, label = action_tuple
|
||||
try:
|
||||
surf = _render_icons_line(actions, label, max_width - x_pos - 10, config.tiny_font, THEME_COLORS["text"], icon_size=scaled_icon_size, icon_gap=scaled_icon_gap, icon_text_gap=scaled_icon_text_gap)
|
||||
if x_pos + surf.get_width() > max_width - 10:
|
||||
@@ -1855,7 +1967,7 @@ def draw_controls(screen, menu_state, current_music_name=None, music_popup_start
|
||||
final_surf.blit(combined_surf, (0, 0), (0, 0, x_pos - 10, 50))
|
||||
icon_surfs.append(final_surf)
|
||||
elif line_data[0] == "icons" and len(line_data) == 3:
|
||||
_, actions, label = line_data
|
||||
ignored, actions, label = line_data
|
||||
try:
|
||||
surf = _render_icons_line(actions, label, max_width, config.tiny_font, THEME_COLORS["text"], icon_size=scaled_icon_size, icon_gap=scaled_icon_gap, icon_text_gap=scaled_icon_text_gap)
|
||||
icon_surfs.append(surf)
|
||||
@@ -1893,7 +2005,6 @@ def draw_language_menu(screen):
|
||||
- Bloc (titre + liste de langues) centré verticalement.
|
||||
- Gestion d'overflow: réduit légèrement la hauteur/espacement si nécessaire.
|
||||
"""
|
||||
from language import get_available_languages, get_language_name
|
||||
|
||||
screen.blit(OVERLAY, (0, 0))
|
||||
|
||||
@@ -2033,15 +2144,30 @@ def draw_menu_instruction(screen, instruction_text, last_button_bottom=None):
|
||||
logger.error(f"Erreur draw_menu_instruction: {e}")
|
||||
|
||||
def draw_display_menu(screen):
|
||||
"""Affiche le sous-menu Affichage (layout, taille de police, systèmes non supportés)."""
|
||||
"""Affiche le sous-menu Affichage (layout, taille de police, systèmes non supportés, moniteur)."""
|
||||
screen.blit(OVERLAY, (0, 0))
|
||||
|
||||
# États actuels
|
||||
layout_str = f"{getattr(config, 'GRID_COLS', 3)}x{getattr(config, 'GRID_ROWS', 4)}"
|
||||
font_scale = config.accessibility_settings.get("font_scale", 1.0)
|
||||
from rgsx_settings import get_show_unsupported_platforms, get_allow_unknown_extensions
|
||||
show_unsupported = get_show_unsupported_platforms()
|
||||
allow_unknown = get_allow_unknown_extensions()
|
||||
|
||||
# Monitor info
|
||||
current_monitor = get_display_monitor()
|
||||
is_fullscreen = get_display_fullscreen()
|
||||
monitors = get_available_monitors()
|
||||
num_monitors = len(monitors)
|
||||
|
||||
# Construire le label du moniteur
|
||||
if num_monitors > 1:
|
||||
monitor_info = monitors[current_monitor] if current_monitor < num_monitors else monitors[0]
|
||||
monitor_label = f"{_('display_monitor')}: {monitor_info['name']} ({monitor_info['resolution']})"
|
||||
else:
|
||||
monitor_label = f"{_('display_monitor')}: {_('display_monitor_single')}"
|
||||
|
||||
# Label mode écran
|
||||
fullscreen_label = f"{_('display_mode')}: {_('display_fullscreen') if is_fullscreen else _('display_windowed')}"
|
||||
|
||||
# Compter les systèmes non supportés actuellement masqués
|
||||
unsupported_list = getattr(config, "unsupported_platforms", []) or []
|
||||
@@ -2054,11 +2180,13 @@ def draw_display_menu(screen):
|
||||
else:
|
||||
unsupported_label = _("menu_show_unsupported_all_displayed")
|
||||
|
||||
# Libellés
|
||||
# Libellés - ajout des options moniteur et mode écran
|
||||
options = [
|
||||
f"{_('display_layout')}: {layout_str}",
|
||||
_("accessibility_font_size").format(f"{font_scale:.1f}"),
|
||||
unsupported_label,
|
||||
monitor_label,
|
||||
fullscreen_label,
|
||||
unsupported_label,
|
||||
_("menu_allow_unknown_ext_on") if allow_unknown else _("menu_allow_unknown_ext_off"),
|
||||
_("menu_filter_platforms"),
|
||||
]
|
||||
@@ -2277,10 +2405,6 @@ def draw_pause_controls_menu(screen, selected_index):
|
||||
draw_menu_instruction(screen, text, last_button_bottom)
|
||||
|
||||
def draw_pause_display_menu(screen, selected_index):
|
||||
from rgsx_settings import (
|
||||
get_allow_unknown_extensions,
|
||||
get_font_family
|
||||
)
|
||||
# Layout label
|
||||
layouts = [(3,3),(3,4),(4,3),(4,4)]
|
||||
try:
|
||||
@@ -2309,6 +2433,17 @@ def draw_pause_display_menu(screen, selected_index):
|
||||
fam_label = family_map.get(current_family, current_family)
|
||||
font_family_txt = f"{_('submenu_display_font_family') if _ else 'Font'}: < {fam_label} >"
|
||||
|
||||
# Monitor selection
|
||||
current_monitor = get_display_monitor()
|
||||
monitors = get_available_monitors()
|
||||
num_monitors = len(monitors)
|
||||
if num_monitors > 1:
|
||||
monitor_info = monitors[current_monitor] if current_monitor < num_monitors else monitors[0]
|
||||
monitor_value = f"{monitor_info['name']} ({monitor_info['resolution']})"
|
||||
else:
|
||||
monitor_value = _('display_monitor_single') if _ else "Single monitor"
|
||||
monitor_txt = f"{_('display_monitor') if _ else 'Monitor'}: < {monitor_value} >"
|
||||
|
||||
# Allow unknown extensions
|
||||
allow_unknown = get_allow_unknown_extensions()
|
||||
status_unknown = _('status_on') if allow_unknown else _('status_off')
|
||||
@@ -2317,17 +2452,28 @@ def draw_pause_display_menu(screen, selected_index):
|
||||
raw_unknown_label = raw_unknown_label.split('{status}')[0].rstrip(' :')
|
||||
unknown_txt = f"{raw_unknown_label}: < {status_unknown} >"
|
||||
|
||||
# Light mode (performance)
|
||||
light_mode = get_light_mode()
|
||||
light_status = _('status_on') if light_mode else _('status_off')
|
||||
light_txt = f"{_('display_light_mode') if _ else 'Light mode'}: < {light_status} >"
|
||||
|
||||
back_txt = _("menu_back") if _ else "Back"
|
||||
options = [layout_txt, font_txt, footer_font_txt, font_family_txt, unknown_txt, back_txt]
|
||||
_draw_submenu_generic(screen, _("menu_display"), options, selected_index)
|
||||
|
||||
# Build options list - same for all platforms
|
||||
# layout, font, footer, family, monitor, light, unknown, back (8)
|
||||
options = [layout_txt, font_txt, footer_font_txt, font_family_txt, monitor_txt, light_txt, unknown_txt, back_txt]
|
||||
instruction_keys = [
|
||||
"instruction_display_layout",
|
||||
"instruction_display_font_size",
|
||||
"instruction_display_footer_font_size",
|
||||
"instruction_display_font_family",
|
||||
"instruction_display_monitor",
|
||||
"instruction_display_light_mode",
|
||||
"instruction_display_unknown_ext",
|
||||
"instruction_generic_back",
|
||||
]
|
||||
|
||||
_draw_submenu_generic(screen, _("menu_display"), options, selected_index)
|
||||
key = instruction_keys[selected_index] if 0 <= selected_index < len(instruction_keys) else None
|
||||
if key:
|
||||
button_height = int(config.screen_height * 0.045)
|
||||
@@ -2342,7 +2488,6 @@ def draw_pause_display_menu(screen, selected_index):
|
||||
draw_menu_instruction(screen, _(key), last_button_bottom)
|
||||
|
||||
def draw_pause_games_menu(screen, selected_index):
|
||||
from rgsx_settings import get_sources_mode, get_show_unsupported_platforms, get_hide_premium_systems
|
||||
mode = get_sources_mode()
|
||||
source_label = _("games_source_rgsx") if mode == "rgsx" else _("games_source_custom")
|
||||
source_txt = f"{_('menu_games_source_prefix')}: < {source_label} >"
|
||||
@@ -2415,8 +2560,6 @@ def draw_pause_games_menu(screen, selected_index):
|
||||
draw_menu_instruction(screen, text, last_button_bottom)
|
||||
|
||||
def draw_pause_settings_menu(screen, selected_index):
|
||||
from rgsx_settings import get_symlink_option
|
||||
from utils import check_web_service_status, check_custom_dns_status
|
||||
# Music
|
||||
if config.music_enabled:
|
||||
music_name = config.current_music_name or ""
|
||||
@@ -2486,7 +2629,6 @@ def draw_pause_settings_menu(screen, selected_index):
|
||||
|
||||
def draw_pause_api_keys_status(screen):
|
||||
screen.blit(OVERLAY, (0,0))
|
||||
from utils import load_api_keys
|
||||
keys = load_api_keys()
|
||||
title = _("api_keys_status_title") if _ else "API Keys Status"
|
||||
# Préparer données avec masquage partiel des clés (afficher 4 premiers et 2 derniers caractères si longueur > 10)
|
||||
@@ -2590,7 +2732,6 @@ def draw_pause_api_keys_status(screen):
|
||||
|
||||
def draw_filter_platforms_menu(screen):
|
||||
"""Affiche le menu de filtrage des plateformes (afficher/masquer)."""
|
||||
from rgsx_settings import load_rgsx_settings
|
||||
screen.blit(OVERLAY, (0, 0))
|
||||
settings = load_rgsx_settings()
|
||||
hidden = set(settings.get("hidden_platforms", [])) if isinstance(settings, dict) else set()
|
||||
@@ -3135,8 +3276,6 @@ def show_toast(message, duration=2000):
|
||||
config.toast_start_time = pygame.time.get_ticks()
|
||||
def draw_history_game_options(screen):
|
||||
"""Affiche le menu d'options pour un jeu de l'historique."""
|
||||
import os
|
||||
from utils import _get_dest_folder_name, find_file_with_or_without_extension
|
||||
|
||||
screen.blit(OVERLAY, (0, 0))
|
||||
|
||||
@@ -3243,8 +3382,6 @@ def draw_history_game_options(screen):
|
||||
|
||||
def draw_history_show_folder(screen):
|
||||
"""Affiche le chemin complet du fichier téléchargé."""
|
||||
import os
|
||||
from utils import _get_dest_folder_name
|
||||
|
||||
screen.blit(OVERLAY, (0, 0))
|
||||
|
||||
@@ -3789,7 +3926,6 @@ def draw_filter_menu_choice(screen):
|
||||
|
||||
def draw_filter_advanced(screen):
|
||||
"""Affiche l'écran de filtrage avancé"""
|
||||
from game_filters import GameFilters
|
||||
|
||||
screen.blit(OVERLAY, (0, 0))
|
||||
|
||||
@@ -4069,7 +4205,6 @@ def draw_filter_advanced(screen):
|
||||
|
||||
def draw_filter_priority_config(screen):
|
||||
"""Affiche l'écran de configuration de la priorité des régions pour One ROM per game"""
|
||||
from game_filters import GameFilters
|
||||
|
||||
screen.blit(OVERLAY, (0, 0))
|
||||
|
||||
@@ -4087,7 +4222,6 @@ def draw_filter_priority_config(screen):
|
||||
|
||||
# Initialiser le filtre si nécessaire
|
||||
if not hasattr(config, 'game_filter_obj'):
|
||||
from game_filters import GameFilters
|
||||
from rgsx_settings import load_game_filters
|
||||
config.game_filter_obj = GameFilters()
|
||||
filter_dict = load_game_filters()
|
||||
|
||||
@@ -65,6 +65,17 @@
|
||||
"menu_accessibility": "Barrierefreiheit",
|
||||
"menu_display": "Anzeige",
|
||||
"display_layout": "Anzeigelayout",
|
||||
"display_monitor": "Monitor",
|
||||
"display_monitor_single": "Einzelner Monitor",
|
||||
"display_monitor_single_only": "Nur ein Monitor erkannt",
|
||||
"display_monitor_restart_required": "Neustart erforderlich um Monitor zu ändern",
|
||||
"display_mode": "Anzeigemodus",
|
||||
"display_fullscreen": "Vollbild",
|
||||
"display_windowed": "Fenster",
|
||||
"display_mode_restart_required": "Neustart erforderlich für Modusänderung",
|
||||
"display_light_mode": "Performance-Modus",
|
||||
"display_light_mode_enabled": "Performance-Modus aktiviert - Effekte deaktiviert",
|
||||
"display_light_mode_disabled": "Performance-Modus deaktiviert - Effekte aktiviert",
|
||||
"menu_redownload_cache": "Spieleliste aktualisieren",
|
||||
"menu_music_enabled": "Musik aktiviert: {0}",
|
||||
"menu_music_disabled": "Musik deaktiviert",
|
||||
@@ -196,6 +207,9 @@
|
||||
"instruction_display_font_size": "Schriftgröße für bessere Lesbarkeit anpassen",
|
||||
"instruction_display_footer_font_size": "Fußzeilen-Textgröße anpassen (Version & Steuerelemente)",
|
||||
"instruction_display_font_family": "Zwischen verfügbaren Schriftarten wechseln",
|
||||
"instruction_display_monitor": "Monitor für RGSX-Anzeige auswählen",
|
||||
"instruction_display_mode": "Zwischen Vollbild und Fenstermodus wechseln",
|
||||
"instruction_display_light_mode": "Performance-Modus für bessere FPS aktivieren",
|
||||
"instruction_display_show_unsupported": "Nicht in es_systems.cfg definierte Systeme anzeigen/ausblenden",
|
||||
"instruction_display_unknown_ext": "Warnung für in es_systems.cfg fehlende Dateiendungen an-/abschalten",
|
||||
"instruction_display_hide_premium": "Systeme ausblenden, die Premiumzugang erfordern über API: {providers}",
|
||||
|
||||
@@ -65,6 +65,17 @@
|
||||
"menu_accessibility": "Accessibility",
|
||||
"menu_display": "Display",
|
||||
"display_layout": "Display layout",
|
||||
"display_monitor": "Monitor",
|
||||
"display_monitor_single": "Single monitor",
|
||||
"display_monitor_single_only": "Only one monitor detected",
|
||||
"display_monitor_restart_required": "Restart required to apply monitor change",
|
||||
"display_mode": "Screen mode",
|
||||
"display_fullscreen": "Fullscreen",
|
||||
"display_windowed": "Windowed",
|
||||
"display_mode_restart_required": "Restart required to apply screen mode",
|
||||
"display_light_mode": "Performance mode",
|
||||
"display_light_mode_enabled": "Performance mode enabled - effects disabled",
|
||||
"display_light_mode_disabled": "Performance mode disabled - effects enabled",
|
||||
"menu_redownload_cache": "Update games list",
|
||||
"menu_music_enabled": "Music enabled: {0}",
|
||||
"menu_music_disabled": "Music disabled",
|
||||
@@ -198,6 +209,9 @@
|
||||
"instruction_display_font_size": "Adjust text scale for readability",
|
||||
"instruction_display_footer_font_size": "Adjust footer text scale (version & controls display)",
|
||||
"instruction_display_font_family": "Switch between available font families",
|
||||
"instruction_display_monitor": "Select which monitor to display RGSX on",
|
||||
"instruction_display_mode": "Toggle between fullscreen and windowed mode",
|
||||
"instruction_display_light_mode": "Enable performance mode for better FPS on low-end devices",
|
||||
"instruction_display_show_unsupported": "Show/hide systems not defined in es_systems.cfg",
|
||||
"instruction_display_unknown_ext": "Enable/disable warning for file extensions absent from es_systems.cfg",
|
||||
"instruction_display_hide_premium": "Hide systems requiring premium access via API: {providers}",
|
||||
|
||||
@@ -65,6 +65,17 @@
|
||||
"menu_accessibility": "Accesibilidad",
|
||||
"menu_display": "Pantalla",
|
||||
"display_layout": "Distribución",
|
||||
"display_monitor": "Monitor",
|
||||
"display_monitor_single": "Monitor único",
|
||||
"display_monitor_single_only": "Solo un monitor detectado",
|
||||
"display_monitor_restart_required": "Reinicio necesario para cambiar de monitor",
|
||||
"display_mode": "Modo de pantalla",
|
||||
"display_fullscreen": "Pantalla completa",
|
||||
"display_windowed": "Ventana",
|
||||
"display_mode_restart_required": "Reinicio necesario para cambiar el modo",
|
||||
"display_light_mode": "Modo rendimiento",
|
||||
"display_light_mode_enabled": "Modo rendimiento activado - efectos desactivados",
|
||||
"display_light_mode_disabled": "Modo rendimiento desactivado - efectos activados",
|
||||
"menu_redownload_cache": "Actualizar lista de juegos",
|
||||
"menu_music_enabled": "Música activada: {0}",
|
||||
"menu_music_disabled": "Música desactivada",
|
||||
@@ -198,6 +209,9 @@
|
||||
"instruction_display_font_size": "Ajustar tamaño del texto para mejor legibilidad",
|
||||
"instruction_display_footer_font_size": "Ajustar el tamaño del texto del pie de página (versión y controles)",
|
||||
"instruction_display_font_family": "Cambiar entre familias de fuentes disponibles",
|
||||
"instruction_display_monitor": "Seleccionar monitor para mostrar RGSX",
|
||||
"instruction_display_mode": "Alternar entre pantalla completa y ventana",
|
||||
"instruction_display_light_mode": "Activar modo rendimiento para mejores FPS",
|
||||
"instruction_display_show_unsupported": "Mostrar/ocultar sistemas no definidos en es_systems.cfg",
|
||||
"instruction_display_unknown_ext": "Activar/desactivar aviso para extensiones no presentes en es_systems.cfg",
|
||||
"instruction_display_hide_premium": "Ocultar sistemas que requieren acceso premium vía API: {providers}",
|
||||
|
||||
@@ -65,6 +65,17 @@
|
||||
"menu_accessibility": "Accessibilité",
|
||||
"menu_display": "Affichage",
|
||||
"display_layout": "Disposition",
|
||||
"display_monitor": "Écran",
|
||||
"display_monitor_single": "Écran unique",
|
||||
"display_monitor_single_only": "Un seul écran détecté",
|
||||
"display_monitor_restart_required": "Redémarrage requis pour changer d'écran",
|
||||
"display_mode": "Mode d'affichage",
|
||||
"display_fullscreen": "Plein écran",
|
||||
"display_windowed": "Fenêtré",
|
||||
"display_mode_restart_required": "Redémarrage requis pour changer le mode",
|
||||
"display_light_mode": "Mode performance",
|
||||
"display_light_mode_enabled": "Mode performance activé - effets désactivés",
|
||||
"display_light_mode_disabled": "Mode performance désactivé - effets activés",
|
||||
"menu_redownload_cache": "Mettre à jour la liste des jeux",
|
||||
"menu_support": "Support",
|
||||
"menu_quit": "Quitter",
|
||||
@@ -198,6 +209,9 @@
|
||||
"instruction_display_font_size": "Ajuster la taille du texte pour la lisibilité",
|
||||
"instruction_display_footer_font_size": "Ajuster la taille du texte du pied de page (version et contrôles)",
|
||||
"instruction_display_font_family": "Basculer entre les polices disponibles",
|
||||
"instruction_display_monitor": "Sélectionner l'écran pour afficher RGSX",
|
||||
"instruction_display_mode": "Basculer entre plein écran et fenêtré",
|
||||
"instruction_display_light_mode": "Activer le mode performance pour de meilleurs FPS",
|
||||
"instruction_display_show_unsupported": "Afficher/masquer systèmes absents de es_systems.cfg",
|
||||
"instruction_display_unknown_ext": "Avertir ou non pour extensions absentes de es_systems.cfg",
|
||||
"instruction_display_hide_premium": "Masquer les systèmes nécessitant un accès premium via API: {providers}",
|
||||
@@ -250,6 +264,8 @@
|
||||
"history_option_extract_archive": "Extraire l'archive",
|
||||
"history_option_open_file": "Ouvrir le fichier",
|
||||
"history_option_scraper": "Récupérer métadonnées",
|
||||
"history_option_remove_from_queue": "Retirer de la file d'attente",
|
||||
"history_option_cancel_download": "Annuler le téléchargement",
|
||||
"history_option_delete_game": "Supprimer le jeu",
|
||||
"history_option_error_info": "Détails de l'erreur",
|
||||
"history_option_retry": "Retenter le téléchargement",
|
||||
|
||||
@@ -65,7 +65,16 @@
|
||||
"menu_accessibility": "Accessibilità",
|
||||
"menu_display": "Schermo",
|
||||
"display_layout": "Layout schermo",
|
||||
"menu_redownload_cache": "Aggiorna elenco giochi",
|
||||
"display_monitor": "Monitor",
|
||||
"display_monitor_single": "Monitor singolo",
|
||||
"display_monitor_single_only": "Rilevato un solo monitor",
|
||||
"display_monitor_restart_required": "Riavvio necessario per cambiare monitor",
|
||||
"display_mode": "Modalità schermo",
|
||||
"display_fullscreen": "Schermo intero",
|
||||
"display_windowed": "Finestra",
|
||||
"display_mode_restart_required": "Riavvio necessario per cambiare modalità", "display_light_mode": "Modalità performance",
|
||||
"display_light_mode_enabled": "Modalità performance attivata - effetti disattivati",
|
||||
"display_light_mode_disabled": "Modalità performance disattivata - effetti attivati", "menu_redownload_cache": "Aggiorna elenco giochi",
|
||||
"menu_music_enabled": "Musica attivata: {0}",
|
||||
"menu_music_disabled": "Musica disattivata",
|
||||
"menu_restart": "Riavvia RGSX",
|
||||
@@ -195,6 +204,9 @@
|
||||
"instruction_display_font_size": "Regolare dimensione testo per leggibilità",
|
||||
"instruction_display_footer_font_size": "Regola dimensione testo piè di pagina (versione e controlli)",
|
||||
"instruction_display_font_family": "Cambiare famiglia di font disponibile",
|
||||
"instruction_display_monitor": "Selezionare monitor per visualizzare RGSX",
|
||||
"instruction_display_mode": "Alternare tra schermo intero e finestra",
|
||||
"instruction_display_light_mode": "Attivare modalità performance per FPS migliori",
|
||||
"instruction_display_show_unsupported": "Mostrare/nascondere sistemi non definiti in es_systems.cfg",
|
||||
"instruction_display_unknown_ext": "Attivare/disattivare avviso per estensioni assenti in es_systems.cfg",
|
||||
"instruction_display_hide_premium": "Nascondere sistemi che richiedono accesso premium via API: {providers}",
|
||||
@@ -247,6 +259,8 @@
|
||||
"history_option_extract_archive": "Estrai archivio",
|
||||
"history_option_open_file": "Apri file",
|
||||
"history_option_scraper": "Scraper metadati",
|
||||
"history_option_remove_from_queue": "Rimuovi dalla coda",
|
||||
"history_option_cancel_download": "Annulla download",
|
||||
"history_option_delete_game": "Elimina gioco",
|
||||
"history_option_error_info": "Dettagli errore",
|
||||
"history_option_retry": "Riprova download",
|
||||
|
||||
@@ -65,6 +65,17 @@
|
||||
"menu_accessibility": "Acessibilidade",
|
||||
"menu_display": "Exibição",
|
||||
"display_layout": "Layout de exibição",
|
||||
"display_monitor": "Monitor",
|
||||
"display_monitor_single": "Monitor único",
|
||||
"display_monitor_single_only": "Apenas um monitor detectado",
|
||||
"display_monitor_restart_required": "Reinício necessário para mudar de monitor",
|
||||
"display_mode": "Modo de tela",
|
||||
"display_fullscreen": "Tela cheia",
|
||||
"display_windowed": "Janela",
|
||||
"display_mode_restart_required": "Reinício necessário para mudar o modo",
|
||||
"display_light_mode": "Modo performance",
|
||||
"display_light_mode_enabled": "Modo performance ativado - efeitos desativados",
|
||||
"display_light_mode_disabled": "Modo performance desativado - efeitos ativados",
|
||||
"menu_redownload_cache": "Atualizar lista de jogos",
|
||||
"menu_music_enabled": "Música ativada: {0}",
|
||||
"menu_music_disabled": "Música desativada",
|
||||
@@ -197,6 +208,9 @@
|
||||
"instruction_display_font_size": "Ajustar tamanho do texto para legibilidade",
|
||||
"instruction_display_footer_font_size": "Ajustar tamanho do texto do rodapé (versão e controles)",
|
||||
"instruction_display_font_family": "Alternar entre famílias de fontes disponíveis",
|
||||
"instruction_display_monitor": "Selecionar monitor para exibir RGSX",
|
||||
"instruction_display_mode": "Alternar entre tela cheia e janela",
|
||||
"instruction_display_light_mode": "Ativar modo performance para melhor FPS",
|
||||
"instruction_display_show_unsupported": "Mostrar/ocultar sistemas não definidos em es_systems.cfg",
|
||||
"instruction_display_unknown_ext": "Ativar/desativar aviso para extensões ausentes em es_systems.cfg",
|
||||
"instruction_display_hide_premium": "Ocultar sistemas que exigem acesso premium via API: {providers}",
|
||||
|
||||
@@ -404,7 +404,6 @@ def test_internet():
|
||||
]
|
||||
|
||||
for test_url in test_urls:
|
||||
logger.debug(f"Test connexion HTTP vers {test_url}")
|
||||
try:
|
||||
response = requests.get(test_url, timeout=5, allow_redirects=True)
|
||||
if response.status_code == 200:
|
||||
|
||||
@@ -49,6 +49,8 @@ def load_rgsx_settings():
|
||||
"""Charge tous les paramètres depuis rgsx_settings.json."""
|
||||
from config import RGSX_SETTINGS_PATH
|
||||
|
||||
#logger.debug(f"Chargement des settings depuis: {RGSX_SETTINGS_PATH}")
|
||||
|
||||
default_settings = {
|
||||
"language": "en",
|
||||
"music_enabled": True,
|
||||
@@ -58,7 +60,10 @@ def load_rgsx_settings():
|
||||
},
|
||||
"display": {
|
||||
"grid": "3x4",
|
||||
"font_family": "pixel"
|
||||
"font_family": "pixel",
|
||||
"monitor": 0,
|
||||
"fullscreen": True,
|
||||
"light_mode": False
|
||||
},
|
||||
"symlink": {
|
||||
"enabled": False,
|
||||
@@ -78,13 +83,17 @@ def load_rgsx_settings():
|
||||
if os.path.exists(RGSX_SETTINGS_PATH):
|
||||
with open(RGSX_SETTINGS_PATH, 'r', encoding='utf-8') as f:
|
||||
settings = json.load(f)
|
||||
#logger.debug(f"Settings JSON chargé: display={settings.get('display', {})}")
|
||||
# Fusionner avec les valeurs par défaut pour assurer la compatibilité
|
||||
for key, value in default_settings.items():
|
||||
if key not in settings:
|
||||
settings[key] = value
|
||||
return settings
|
||||
else:
|
||||
logger.warning(f"Fichier settings non trouvé: {RGSX_SETTINGS_PATH}")
|
||||
except Exception as e:
|
||||
print(f"Erreur lors du chargement de rgsx_settings.json: {str(e)}")
|
||||
logger.error(f"Erreur chargement settings: {e}")
|
||||
|
||||
return default_settings
|
||||
|
||||
@@ -307,6 +316,92 @@ def set_display_grid(cols: int, rows: int):
|
||||
save_rgsx_settings(settings)
|
||||
return cols, rows
|
||||
|
||||
# ----------------------- Monitor/Display settings ----------------------- #
|
||||
|
||||
def get_display_monitor(settings=None):
|
||||
"""Retourne l'index du moniteur configuré (par défaut 0 = principal)."""
|
||||
if settings is None:
|
||||
settings = load_rgsx_settings()
|
||||
return settings.get("display", {}).get("monitor", 0)
|
||||
|
||||
def set_display_monitor(monitor_index: int):
|
||||
"""Définit et sauvegarde l'index du moniteur à utiliser."""
|
||||
settings = load_rgsx_settings()
|
||||
disp = settings.setdefault("display", {})
|
||||
disp["monitor"] = max(0, int(monitor_index))
|
||||
save_rgsx_settings(settings)
|
||||
return disp["monitor"]
|
||||
|
||||
def get_display_fullscreen(settings=None):
|
||||
"""Retourne True si le mode plein écran est activé."""
|
||||
if settings is None:
|
||||
settings = load_rgsx_settings()
|
||||
return settings.get("display", {}).get("fullscreen", True)
|
||||
|
||||
def set_display_fullscreen(fullscreen: bool):
|
||||
"""Définit et sauvegarde le mode plein écran."""
|
||||
settings = load_rgsx_settings()
|
||||
disp = settings.setdefault("display", {})
|
||||
disp["fullscreen"] = bool(fullscreen)
|
||||
save_rgsx_settings(settings)
|
||||
return disp["fullscreen"]
|
||||
|
||||
def get_light_mode(settings=None):
|
||||
"""Retourne True si le mode léger (performance) est activé."""
|
||||
if settings is None:
|
||||
settings = load_rgsx_settings()
|
||||
return settings.get("display", {}).get("light_mode", False)
|
||||
|
||||
def set_light_mode(enabled: bool):
|
||||
"""Définit et sauvegarde le mode léger (performance)."""
|
||||
settings = load_rgsx_settings()
|
||||
disp = settings.setdefault("display", {})
|
||||
disp["light_mode"] = bool(enabled)
|
||||
save_rgsx_settings(settings)
|
||||
return disp["light_mode"]
|
||||
|
||||
def get_available_monitors():
|
||||
"""Retourne la liste des moniteurs disponibles avec leurs informations.
|
||||
Compatible Windows, Linux (Batocera), et autres plateformes.
|
||||
Retourne une liste de dicts: [{"index": 0, "name": "Monitor 1", "resolution": "1920x1080"}, ...]
|
||||
"""
|
||||
monitors = []
|
||||
try:
|
||||
import pygame
|
||||
if not pygame.display.get_init():
|
||||
pygame.display.init()
|
||||
|
||||
num_displays = pygame.display.get_num_displays()
|
||||
for i in range(num_displays):
|
||||
try:
|
||||
# Essayer d'obtenir le mode desktop pour ce display
|
||||
mode = pygame.display.get_desktop_sizes()[i] if hasattr(pygame.display, 'get_desktop_sizes') else None
|
||||
if mode:
|
||||
width, height = mode
|
||||
else:
|
||||
# Fallback: utiliser la résolution actuelle si disponible
|
||||
info = pygame.display.Info()
|
||||
width, height = info.current_w, info.current_h
|
||||
|
||||
monitors.append({
|
||||
"index": i,
|
||||
"name": f"Monitor {i + 1}",
|
||||
"resolution": f"{width}x{height}"
|
||||
})
|
||||
except Exception as e:
|
||||
# Si on ne peut pas obtenir les infos, ajouter quand même le moniteur
|
||||
monitors.append({
|
||||
"index": i,
|
||||
"name": f"Monitor {i + 1}",
|
||||
"resolution": "Unknown"
|
||||
})
|
||||
except Exception as e:
|
||||
logger.error(f"Error getting monitors: {e}")
|
||||
# Fallback: au moins un moniteur
|
||||
monitors = [{"index": 0, "name": "Monitor 1 (Default)", "resolution": "Auto"}]
|
||||
|
||||
return monitors if monitors else [{"index": 0, "name": "Monitor 1 (Default)", "resolution": "Auto"}]
|
||||
|
||||
def get_font_family(settings=None):
|
||||
if settings is None:
|
||||
settings = load_rgsx_settings()
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
{
|
||||
"version": "2.3.3.3"
|
||||
"version": "2.4.0.2"
|
||||
}
|
||||
@@ -1,149 +1,385 @@
|
||||
@echo off
|
||||
setlocal EnableDelayedExpansion
|
||||
|
||||
:: Fichier de log
|
||||
if not exist "%CD%\logs" MD "%CD%\logs"
|
||||
set "LOG_FILE=%CD%\logs\Retrobat_RGSX_log.txt"
|
||||
:: Fichier de log (chemin absolu pour fiabilité)
|
||||
:: Détecter la racine (ROOT_DIR) d'abord pour construire un chemin stable
|
||||
set CURRENT_DIR=%CD%
|
||||
pushd "%CURRENT_DIR%\..\.."
|
||||
set "ROOT_DIR=%CD%"
|
||||
popd
|
||||
if not exist "%ROOT_DIR%\roms\windows\logs" MD "%ROOT_DIR%\roms\windows\logs"
|
||||
set "LOG_FILE=%ROOT_DIR%\roms\windows\logs\Retrobat_RGSX_log.txt"
|
||||
:: =============================================================================
|
||||
:: RGSX Retrobat Launcher v1.3
|
||||
:: =============================================================================
|
||||
:: Usage: "RGSX Retrobat.bat" [options]
|
||||
:: --display=N Launch on display N (0=primary, 1=secondary, etc.)
|
||||
:: --windowed Launch in windowed mode instead of fullscreen
|
||||
:: --help Show this help
|
||||
:: =============================================================================
|
||||
|
||||
:: Ajouter un horodatage au début du log
|
||||
echo [%DATE% %TIME%] Script start >> "%LOG_FILE%"
|
||||
:: Configuration des couleurs (codes ANSI)
|
||||
for /F "tokens=1,2 delims=#" %%a in ('"prompt #$H#$E# & echo on & for %%b in (1) do rem"') do (
|
||||
set "ESC=%%b"
|
||||
)
|
||||
|
||||
:: Afficher un message de démarrage
|
||||
:: Couleurs
|
||||
set "GREEN=[92m"
|
||||
set "YELLOW=[93m"
|
||||
set "RED=[91m"
|
||||
set "CYAN=[96m"
|
||||
set "RESET=[0m"
|
||||
set "BOLD=[1m"
|
||||
|
||||
:: =============================================================================
|
||||
:: Traitement des arguments
|
||||
:: =============================================================================
|
||||
set "DISPLAY_NUM="
|
||||
set "WINDOWED_MODE="
|
||||
set "CONFIG_FILE="
|
||||
|
||||
:parse_args
|
||||
if "%~1"=="" goto :args_done
|
||||
if /i "%~1"=="--help" goto :show_help
|
||||
if /i "%~1"=="-h" goto :show_help
|
||||
if /i "%~1"=="--windowed" (
|
||||
set "WINDOWED_MODE=1"
|
||||
shift
|
||||
goto :parse_args
|
||||
)
|
||||
:: Check for --display=N format
|
||||
echo %~1 | findstr /r "^--display=" >nul
|
||||
if !ERRORLEVEL! EQU 0 (
|
||||
for /f "tokens=2 delims==" %%a in ("%~1") do set "DISPLAY_NUM=%%a"
|
||||
shift
|
||||
goto :parse_args
|
||||
)
|
||||
shift
|
||||
goto :parse_args
|
||||
|
||||
:show_help
|
||||
echo.
|
||||
echo %ESC%%CYAN%RGSX Retrobat Launcher - Help%ESC%%RESET%
|
||||
echo.
|
||||
echo Usage: "RGSX Retrobat.bat" [options]
|
||||
echo.
|
||||
echo Options:
|
||||
echo --display=N Launch on display N (0=primary, 1=secondary, etc.)
|
||||
echo --windowed Launch in windowed mode instead of fullscreen
|
||||
echo --help, -h Show this help
|
||||
echo.
|
||||
echo Examples:
|
||||
echo "RGSX Retrobat.bat" Launch on primary display
|
||||
echo "RGSX Retrobat.bat" --display=1 Launch on secondary display (TV)
|
||||
echo "RGSX Retrobat.bat" --windowed Launch in windowed mode
|
||||
echo.
|
||||
echo You can also create shortcuts with different display settings.
|
||||
echo.
|
||||
pause
|
||||
exit /b 0
|
||||
|
||||
:args_done
|
||||
|
||||
:: URL de telechargement Python
|
||||
set "PYTHON_ZIP_URL=https://github.com/RetroGameSets/RGSX/raw/main/windows/python.zip"
|
||||
|
||||
:: Obtenir le chemin du script de maniere fiable
|
||||
set "SCRIPT_DIR=%~dp0"
|
||||
set "SCRIPT_DIR=%SCRIPT_DIR:~0,-1%"
|
||||
|
||||
:: Detecter le repertoire racine
|
||||
for %%I in ("%SCRIPT_DIR%\..\.." ) do set "ROOT_DIR=%%~fI"
|
||||
|
||||
:: Configuration des logs
|
||||
set "LOG_DIR=%ROOT_DIR%\roms\windows\logs"
|
||||
if not exist "%LOG_DIR%" mkdir "%LOG_DIR%"
|
||||
set "LOG_FILE=%LOG_DIR%\Retrobat_RGSX_log.txt"
|
||||
set "LOG_BACKUP=%LOG_DIR%\Retrobat_RGSX_log.old.txt"
|
||||
|
||||
:: Rotation des logs avec backup
|
||||
if exist "%LOG_FILE%" (
|
||||
for %%A in ("%LOG_FILE%") do (
|
||||
if %%~zA GTR 100000 (
|
||||
if exist "%LOG_BACKUP%" del /q "%LOG_BACKUP%"
|
||||
move /y "%LOG_FILE%" "%LOG_BACKUP%" >nul 2>&1
|
||||
echo [%DATE% %TIME%] Log rotated - previous log saved as .old.txt > "%LOG_FILE%"
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
:: =============================================================================
|
||||
:: Ecran d'accueil
|
||||
:: =============================================================================
|
||||
cls
|
||||
echo Running __main__.py for RetroBat...
|
||||
echo [%DATE% %TIME%] Running __main__.py for RetroBat >> "%LOG_FILE%"
|
||||
echo.
|
||||
echo %ESC%%CYAN% ____ ____ ______ __ %ESC%%RESET%
|
||||
echo %ESC%%CYAN% ^| _ \ / ___^/ ___\ \/ / %ESC%%RESET%
|
||||
echo %ESC%%CYAN% ^| ^|_) ^| ^| _\___ \\ / %ESC%%RESET%
|
||||
echo %ESC%%CYAN% ^| _ ^<^| ^|_^| ^|___) / \ %ESC%%RESET%
|
||||
echo %ESC%%CYAN% ^|_^| \_\\____^|____/_/\_\ %ESC%%RESET%
|
||||
echo.
|
||||
echo %ESC%%BOLD% RetroBat Launcher v1.3%ESC%%RESET%
|
||||
echo --------------------------------
|
||||
if "!DISPLAY_NUM!" NEQ "0" (
|
||||
echo %ESC%%CYAN%Display: !DISPLAY_NUM!%ESC%%RESET%
|
||||
)
|
||||
if "!WINDOWED_MODE!"=="1" (
|
||||
echo %ESC%%CYAN%Mode: Windowed%ESC%%RESET%
|
||||
)
|
||||
echo.
|
||||
|
||||
:: Définir les chemins relatifs et les convertir en absolus
|
||||
set CURRENT_DIR=%CD%
|
||||
set PYTHON_EXE=python.exe
|
||||
:: Debut du log
|
||||
echo [%DATE% %TIME%] ========================================== >> "%LOG_FILE%"
|
||||
echo [%DATE% %TIME%] RGSX Launcher v1.3 started >> "%LOG_FILE%"
|
||||
echo [%DATE% %TIME%] Display: !DISPLAY_NUM!, Windowed: !WINDOWED_MODE! >> "%LOG_FILE%"
|
||||
echo [%DATE% %TIME%] ========================================== >> "%LOG_FILE%"
|
||||
|
||||
:: Détecter le répertoire racine en remontant de deux niveaux depuis le script
|
||||
pushd "%CURRENT_DIR%\..\.."
|
||||
set "ROOT_DIR=%CD%"
|
||||
popd
|
||||
|
||||
:: Définir le chemin du script principal selon les spécifications
|
||||
:: Configuration des chemins
|
||||
set "PYTHON_DIR=%ROOT_DIR%\system\tools\Python"
|
||||
set "PYTHON_EXE=%PYTHON_DIR%\python.exe"
|
||||
set "MAIN_SCRIPT=%ROOT_DIR%\roms\ports\RGSX\__main__.py"
|
||||
set "ZIP_FILE=%ROOT_DIR%\roms\windows\python.zip"
|
||||
|
||||
:: Definir le chemin du script de mise à jour de la gamelist Windows
|
||||
set "UPDATE_GAMELIST_SCRIPT=%ROOT_DIR%\roms\ports\RGSX\update_gamelist_windows.py"
|
||||
:: Exporter RGSX_ROOT pour le script Python
|
||||
set "RGSX_ROOT=%ROOT_DIR%"
|
||||
|
||||
:: Convertir les chemins relatifs en absolus avec pushd/popd
|
||||
pushd "%ROOT_DIR%\system\tools\Python"
|
||||
set "PYTHON_EXE_FULL=%ROOT_DIR%\system\tools\Python\!PYTHON_EXE!"
|
||||
set "PYTHONW_EXE_FULL=%ROOT_DIR%\system\tools\Python\pythonw.exe"
|
||||
popd
|
||||
:: Logger les chemins
|
||||
echo [%DATE% %TIME%] System info: >> "%LOG_FILE%"
|
||||
echo [%DATE% %TIME%] ROOT_DIR: %ROOT_DIR% >> "%LOG_FILE%"
|
||||
echo [%DATE% %TIME%] PYTHON_EXE: %PYTHON_EXE% >> "%LOG_FILE%"
|
||||
echo [%DATE% %TIME%] MAIN_SCRIPT: %MAIN_SCRIPT% >> "%LOG_FILE%"
|
||||
echo [%DATE% %TIME%] RGSX_ROOT: %RGSX_ROOT% >> "%LOG_FILE%"
|
||||
|
||||
:: Afficher et logger les variables
|
||||
:: =============================================================================
|
||||
:: Verification Python
|
||||
:: =============================================================================
|
||||
echo %ESC%%YELLOW%[1/3]%ESC%%RESET% Checking Python environment...
|
||||
echo [%DATE% %TIME%] Step 1/3: Checking Python >> "%LOG_FILE%"
|
||||
|
||||
echo ROOT_DIR : %ROOT_DIR% >> "%LOG_FILE%"
|
||||
echo CURRENT_DIR : !CURRENT_DIR! >> "%LOG_FILE%"
|
||||
echo ROOT_DIR : !ROOT_DIR! >> "%LOG_FILE%"
|
||||
echo PYTHON_EXE_FULL : !PYTHON_EXE_FULL! >> "%LOG_FILE%"
|
||||
echo MAIN_SCRIPT : !MAIN_SCRIPT! >> "%LOG_FILE%"
|
||||
echo UPDATE_GAMELIST_SCRIPT : !UPDATE_GAMELIST_SCRIPT! >> "%LOG_FILE%"
|
||||
|
||||
:: Vérifier si l'exécutable Python existe
|
||||
echo Checking python.exe...
|
||||
echo [%DATE% %TIME%] Checking python.exe at !PYTHON_EXE_FULL! >> "%LOG_FILE%"
|
||||
if not exist "!PYTHON_EXE_FULL!" (
|
||||
echo python.exe not found in system/tools. Preparing to extract..
|
||||
echo [%DATE% %TIME%] python.exe not found in system/tools. Preparing to extract.. >> "%LOG_FILE%"
|
||||
if not exist "%PYTHON_EXE%" (
|
||||
echo %ESC%%YELLOW%^> Python not found, installing...%ESC%%RESET%
|
||||
echo [%DATE% %TIME%] Python not found, starting installation >> "%LOG_FILE%"
|
||||
|
||||
:: Créer le dossier Python s'il n'existe pas
|
||||
set "TOOLS_FOLDER_FULL=!ROOT_DIR!\system\tools"
|
||||
|
||||
if not exist "!TOOLS_FOLDER_FULL!\Python" (
|
||||
echo Creating folder !TOOLS_FOLDER_FULL!\Python...
|
||||
echo [%DATE% %TIME%] Creating folder !TOOLS_FOLDER_FULL!\Python... >> "%LOG_FILE%"
|
||||
mkdir "!TOOLS_FOLDER_FULL!\Python"
|
||||
:: Creer le dossier Python
|
||||
if not exist "%PYTHON_DIR%" (
|
||||
mkdir "%PYTHON_DIR%" 2>nul
|
||||
echo [%DATE% %TIME%] Created folder: %PYTHON_DIR% >> "%LOG_FILE%"
|
||||
)
|
||||
|
||||
set "ZIP_FILE=%ROOT_DIR%\roms\windows\python.zip"
|
||||
echo Extracting ZIP_FILE : !ZIP_FILE! in /system/tools/Python
|
||||
echo [%DATE% %TIME%] ZIP_FILE : !ZIP_FILE! >> "%LOG_FILE%"
|
||||
|
||||
if exist "!ZIP_FILE!" (
|
||||
echo [%DATE% %TIME%] Extracting python.zip to !TOOLS_FOLDER_FULL!... >> "%LOG_FILE%"
|
||||
tar -xf "!ZIP_FILE!" -C "!TOOLS_FOLDER_FULL!\Python" --strip-components=0
|
||||
echo Extraction finished.
|
||||
echo [%DATE% %TIME%] Extraction finished. >> "%LOG_FILE%"
|
||||
del /s /q "!ZIP_FILE!"
|
||||
echo python.zip file deleted.
|
||||
echo [%DATE% %TIME%] python.zip file deleted. >> "%LOG_FILE%"
|
||||
) else (
|
||||
echo Error: Error python.zip not found please download it from github and put in /roms/windows folder.
|
||||
echo [%DATE% %TIME%] Error: Error python.zip not found please download it from github and put in /roms/windows folder >> "%LOG_FILE%"
|
||||
:: Verifier si le ZIP existe, sinon le telecharger
|
||||
if not exist "%ZIP_FILE%" (
|
||||
echo %ESC%%YELLOW%^> python.zip not found, downloading from GitHub...%ESC%%RESET%
|
||||
echo [%DATE% %TIME%] python.zip not found, attempting download >> "%LOG_FILE%"
|
||||
echo [%DATE% %TIME%] Download URL: %PYTHON_ZIP_URL% >> "%LOG_FILE%"
|
||||
|
||||
:: Verifier si curl est disponible
|
||||
where curl.exe >nul 2>&1
|
||||
if !ERRORLEVEL! EQU 0 (
|
||||
echo %ESC%%CYAN%^> Using curl to download...%ESC%%RESET%
|
||||
echo [%DATE% %TIME%] Using curl.exe for download >> "%LOG_FILE%"
|
||||
curl.exe -L -# -o "%ZIP_FILE%" "%PYTHON_ZIP_URL%"
|
||||
set DOWNLOAD_RESULT=!ERRORLEVEL!
|
||||
) else (
|
||||
:: Fallback sur PowerShell
|
||||
echo %ESC%%CYAN%^> Using PowerShell to download...%ESC%%RESET%
|
||||
echo [%DATE% %TIME%] curl not found, using PowerShell >> "%LOG_FILE%"
|
||||
powershell -NoProfile -ExecutionPolicy Bypass -Command "[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12; $ProgressPreference = 'SilentlyContinue'; Invoke-WebRequest -Uri '%PYTHON_ZIP_URL%' -OutFile '%ZIP_FILE%'"
|
||||
set DOWNLOAD_RESULT=!ERRORLEVEL!
|
||||
)
|
||||
|
||||
:: Verifier le resultat du telechargement
|
||||
if !DOWNLOAD_RESULT! NEQ 0 (
|
||||
echo.
|
||||
echo %ESC%%RED% ERROR: Download failed!%ESC%%RESET%
|
||||
echo.
|
||||
echo Please download python.zip manually from:
|
||||
echo %ESC%%CYAN%%PYTHON_ZIP_URL%%ESC%%RESET%
|
||||
echo.
|
||||
echo And place it in:
|
||||
echo %ESC%%CYAN%%ROOT_DIR%\roms\windows\%ESC%%RESET%
|
||||
echo.
|
||||
echo [%DATE% %TIME%] ERROR: Download failed with code !DOWNLOAD_RESULT! >> "%LOG_FILE%"
|
||||
goto :error
|
||||
)
|
||||
|
||||
:: Verifier que le fichier a bien ete telecharge et n'est pas vide
|
||||
if not exist "%ZIP_FILE%" (
|
||||
echo.
|
||||
echo %ESC%%RED% ERROR: Download failed - file not created!%ESC%%RESET%
|
||||
echo [%DATE% %TIME%] ERROR: ZIP file not created after download >> "%LOG_FILE%"
|
||||
goto :error
|
||||
)
|
||||
|
||||
:: Verifier la taille du fichier (doit etre > 1MB pour etre valide)
|
||||
for %%A in ("%ZIP_FILE%") do set ZIP_SIZE=%%~zA
|
||||
if !ZIP_SIZE! LSS 1000000 (
|
||||
echo.
|
||||
echo %ESC%%RED% ERROR: Downloaded file appears invalid ^(too small^)!%ESC%%RESET%
|
||||
echo [%DATE% %TIME%] ERROR: Downloaded file too small: !ZIP_SIZE! bytes >> "%LOG_FILE%"
|
||||
del /q "%ZIP_FILE%" 2>nul
|
||||
goto :error
|
||||
)
|
||||
|
||||
echo %ESC%%GREEN%^> Download complete ^(!ZIP_SIZE! bytes^)%ESC%%RESET%
|
||||
echo [%DATE% %TIME%] Download successful: !ZIP_SIZE! bytes >> "%LOG_FILE%"
|
||||
)
|
||||
|
||||
:: Verifier que tar existe (Windows 10 1803+)
|
||||
where tar >nul 2>&1
|
||||
if !ERRORLEVEL! NEQ 0 (
|
||||
echo.
|
||||
echo %ESC%%RED% ERROR: tar command not available!%ESC%%RESET%
|
||||
echo.
|
||||
echo Please update Windows 10 or extract manually to:
|
||||
echo %ESC%%CYAN%%PYTHON_DIR%%ESC%%RESET%
|
||||
echo.
|
||||
echo [%DATE% %TIME%] ERROR: tar command not found >> "%LOG_FILE%"
|
||||
goto :error
|
||||
)
|
||||
|
||||
:: Vérifier à nouveau si python.exe existe après extraction
|
||||
if not exist "!PYTHON_EXE_FULL!" (
|
||||
echo Error: python.exe not found after extraction at !PYTHON_EXE_FULL!.
|
||||
echo [%DATE% %TIME%] Error: python.exe not found after extraction at !PYTHON_EXE_FULL! >> "%LOG_FILE%"
|
||||
:: Extraction avec progression simulee
|
||||
echo %ESC%%YELLOW%^> Extracting Python...%ESC%%RESET%
|
||||
echo [%DATE% %TIME%] Extracting python.zip >> "%LOG_FILE%"
|
||||
|
||||
<nul set /p "= ["
|
||||
tar -xf "%ZIP_FILE%" -C "%PYTHON_DIR%" --strip-components=0
|
||||
set TAR_RESULT=!ERRORLEVEL!
|
||||
echo %ESC%%GREEN%##########%ESC%%RESET%] Done
|
||||
|
||||
if !TAR_RESULT! NEQ 0 (
|
||||
echo.
|
||||
echo %ESC%%RED% ERROR: Extraction failed!%ESC%%RESET%
|
||||
echo [%DATE% %TIME%] ERROR: tar extraction failed with code !TAR_RESULT! >> "%LOG_FILE%"
|
||||
goto :error
|
||||
)
|
||||
|
||||
echo [%DATE% %TIME%] Extraction completed >> "%LOG_FILE%"
|
||||
|
||||
:: Supprimer ZIP
|
||||
del /q "%ZIP_FILE%" 2>nul
|
||||
echo %ESC%%GREEN%^> python.zip cleaned up%ESC%%RESET%
|
||||
echo [%DATE% %TIME%] python.zip deleted >> "%LOG_FILE%"
|
||||
|
||||
:: Verifier installation
|
||||
if not exist "%PYTHON_EXE%" (
|
||||
echo.
|
||||
echo %ESC%%RED% ERROR: Python not found after extraction!%ESC%%RESET%
|
||||
echo [%DATE% %TIME%] ERROR: python.exe not found after extraction >> "%LOG_FILE%"
|
||||
goto :error
|
||||
)
|
||||
)
|
||||
echo python.exe found.
|
||||
echo [%DATE% %TIME%] python.exe found. >> "%LOG_FILE%"
|
||||
|
||||
:: Vérifier si le script Python existe
|
||||
echo Checking __main__.py...
|
||||
echo [%DATE% %TIME%] Checking __main__.py at !MAIN_SCRIPT! >> "%LOG_FILE%"
|
||||
if not exist "!MAIN_SCRIPT!" (
|
||||
echo Error: __main__.py not found at !MAIN_SCRIPT!.
|
||||
echo [%DATE% %TIME%] Error: __main__.py not found at !MAIN_SCRIPT! >> "%LOG_FILE%"
|
||||
:: Afficher et logger la version Python
|
||||
for /f "tokens=*" %%v in ('"%PYTHON_EXE%" --version 2^>^&1') do set "PYTHON_VERSION=%%v"
|
||||
echo %ESC%%GREEN%^> %PYTHON_VERSION% found%ESC%%RESET%
|
||||
echo [%DATE% %TIME%] %PYTHON_VERSION% detected >> "%LOG_FILE%"
|
||||
|
||||
:: =============================================================================
|
||||
:: Verification script principal
|
||||
:: =============================================================================
|
||||
echo %ESC%%YELLOW%[2/3]%ESC%%RESET% Checking RGSX application...
|
||||
echo [%DATE% %TIME%] Step 2/3: Checking RGSX files >> "%LOG_FILE%"
|
||||
|
||||
if not exist "%MAIN_SCRIPT%" (
|
||||
echo.
|
||||
echo %ESC%%RED% ERROR: __main__.py not found!%ESC%%RESET%
|
||||
echo.
|
||||
echo Expected location:
|
||||
echo %ESC%%CYAN%%MAIN_SCRIPT%%ESC%%RESET%
|
||||
echo.
|
||||
echo [%DATE% %TIME%] ERROR: __main__.py not found at %MAIN_SCRIPT% >> "%LOG_FILE%"
|
||||
goto :error
|
||||
)
|
||||
echo __main__.py found.
|
||||
echo [%DATE% %TIME%] __main__.py found. >> "%LOG_FILE%"
|
||||
|
||||
:: L'étape de mise à jour de la gamelist est désormais appelée depuis __main__.py
|
||||
echo [%DATE% %TIME%] Skipping external gamelist update (handled in app). >> "%LOG_FILE%"
|
||||
echo %ESC%%GREEN%^> RGSX files OK%ESC%%RESET%
|
||||
echo [%DATE% %TIME%] RGSX files verified >> "%LOG_FILE%"
|
||||
|
||||
echo Launching __main__.py (attached)...
|
||||
echo [%DATE% %TIME%] Preparing to launch main. >> "%LOG_FILE%"
|
||||
:: =============================================================================
|
||||
:: Lancement
|
||||
:: =============================================================================
|
||||
echo %ESC%%YELLOW%[3/3]%ESC%%RESET% Launching RGSX...
|
||||
echo [%DATE% %TIME%] Step 3/3: Launching application >> "%LOG_FILE%"
|
||||
|
||||
:: Assurer le bon dossier de travail pour l'application
|
||||
:: Changer le repertoire de travail
|
||||
cd /d "%ROOT_DIR%\roms\ports\RGSX"
|
||||
echo [%DATE% %TIME%] Working directory: %CD% >> "%LOG_FILE%"
|
||||
|
||||
:: Forcer les drivers SDL côté Windows et réduire le bruit console
|
||||
:: Configuration SDL/Pygame
|
||||
set PYGAME_HIDE_SUPPORT_PROMPT=1
|
||||
set SDL_VIDEODRIVER=windows
|
||||
set SDL_AUDIODRIVER=directsound
|
||||
echo [%DATE% %TIME%] CWD before launch: %CD% >> "%LOG_FILE%"
|
||||
set PYTHONWARNINGS=ignore::UserWarning:pygame.pkgdata
|
||||
|
||||
:: Lancer l'application dans la même console et attendre sa fin
|
||||
:: Forcer python.exe pour capturer la sortie
|
||||
set "PY_MAIN_EXE=!PYTHON_EXE_FULL!"
|
||||
echo [%DATE% %TIME%] Using interpreter: !PY_MAIN_EXE! >> "%LOG_FILE%"
|
||||
echo [%DATE% %TIME%] Launching "!MAIN_SCRIPT!" now... >> "%LOG_FILE%"
|
||||
"!PY_MAIN_EXE!" "!MAIN_SCRIPT!" >> "%LOG_FILE%" 2>&1
|
||||
set EXITCODE=!ERRORLEVEL!
|
||||
echo [%DATE% %TIME%] __main__.py exit code: !EXITCODE! >> "%LOG_FILE%"
|
||||
if "!EXITCODE!"=="0" (
|
||||
echo Execution finished successfully.
|
||||
echo [%DATE% %TIME%] Execution of __main__.py finished successfully. >> "%LOG_FILE%"
|
||||
:: =============================================================================
|
||||
:: Configuration multi-ecran
|
||||
:: =============================================================================
|
||||
:: SDL_VIDEO_FULLSCREEN_HEAD: Selectionne l'ecran pour le mode plein ecran
|
||||
:: 0 = ecran principal, 1 = ecran secondaire, etc.
|
||||
:: Ces variables ne sont definies que si --display=N ou --windowed est passe
|
||||
:: Sinon, le script Python utilisera les parametres de rgsx_settings.json
|
||||
|
||||
echo [%DATE% %TIME%] Display configuration: >> "%LOG_FILE%"
|
||||
if defined DISPLAY_NUM (
|
||||
set SDL_VIDEO_FULLSCREEN_HEAD=!DISPLAY_NUM!
|
||||
set RGSX_DISPLAY=!DISPLAY_NUM!
|
||||
echo [%DATE% %TIME%] SDL_VIDEO_FULLSCREEN_HEAD=!DISPLAY_NUM! ^(from --display arg^) >> "%LOG_FILE%"
|
||||
echo [%DATE% %TIME%] RGSX_DISPLAY=!DISPLAY_NUM! ^(from --display arg^) >> "%LOG_FILE%"
|
||||
) else (
|
||||
echo Error: Failed to execute __main__.py (code !EXITCODE!).
|
||||
echo [%DATE% %TIME%] Error: Failed to execute __main__.py with error code !EXITCODE!. >> "%LOG_FILE%"
|
||||
echo [%DATE% %TIME%] Display: using rgsx_settings.json config >> "%LOG_FILE%"
|
||||
)
|
||||
if defined WINDOWED_MODE (
|
||||
set RGSX_WINDOWED=!WINDOWED_MODE!
|
||||
echo [%DATE% %TIME%] RGSX_WINDOWED=!WINDOWED_MODE! ^(from --windowed arg^) >> "%LOG_FILE%"
|
||||
) else (
|
||||
echo [%DATE% %TIME%] Windowed: using rgsx_settings.json config >> "%LOG_FILE%"
|
||||
)
|
||||
|
||||
:: Log environnement
|
||||
echo [%DATE% %TIME%] Environment variables set: >> "%LOG_FILE%"
|
||||
echo [%DATE% %TIME%] RGSX_ROOT=%RGSX_ROOT% >> "%LOG_FILE%"
|
||||
echo [%DATE% %TIME%] SDL_VIDEODRIVER=%SDL_VIDEODRIVER% >> "%LOG_FILE%"
|
||||
echo [%DATE% %TIME%] SDL_AUDIODRIVER=%SDL_AUDIODRIVER% >> "%LOG_FILE%"
|
||||
|
||||
echo.
|
||||
if defined DISPLAY_NUM (
|
||||
echo %ESC%%CYAN%Launching on display !DISPLAY_NUM!...%ESC%%RESET%
|
||||
)
|
||||
if defined WINDOWED_MODE (
|
||||
echo %ESC%%CYAN%Windowed mode enabled%ESC%%RESET%
|
||||
)
|
||||
echo %ESC%%CYAN%Starting RGSX application...%ESC%%RESET%
|
||||
echo %ESC%%BOLD%Press Ctrl+C to force quit if needed%ESC%%RESET%
|
||||
echo.
|
||||
echo [%DATE% %TIME%] Executing: "%PYTHON_EXE%" "%MAIN_SCRIPT%" >> "%LOG_FILE%"
|
||||
echo [%DATE% %TIME%] --- Application output start --- >> "%LOG_FILE%"
|
||||
|
||||
"%PYTHON_EXE%" "%MAIN_SCRIPT%" >> "%LOG_FILE%" 2>&1
|
||||
set EXITCODE=!ERRORLEVEL!
|
||||
|
||||
echo [%DATE% %TIME%] --- Application output end --- >> "%LOG_FILE%"
|
||||
echo [%DATE% %TIME%] Exit code: !EXITCODE! >> "%LOG_FILE%"
|
||||
|
||||
if "!EXITCODE!"=="0" (
|
||||
echo.
|
||||
echo %ESC%%GREEN%RGSX closed successfully.%ESC%%RESET%
|
||||
echo.
|
||||
echo [%DATE% %TIME%] Application closed successfully >> "%LOG_FILE%"
|
||||
) else (
|
||||
echo.
|
||||
echo %ESC%%RED%RGSX exited with error code !EXITCODE!%ESC%%RESET%
|
||||
echo.
|
||||
echo [%DATE% %TIME%] ERROR: Application exited with code !EXITCODE! >> "%LOG_FILE%"
|
||||
goto :error
|
||||
)
|
||||
|
||||
:end
|
||||
echo Task completed.
|
||||
echo [%DATE% %TIME%] Task completed successfully. >> "%LOG_FILE%"
|
||||
echo [%DATE% %TIME%] ========================================== >> "%LOG_FILE%"
|
||||
echo [%DATE% %TIME%] Session ended normally >> "%LOG_FILE%"
|
||||
echo [%DATE% %TIME%] ========================================== >> "%LOG_FILE%"
|
||||
timeout /t 2 >nul
|
||||
exit /b 0
|
||||
|
||||
:error
|
||||
echo An error occurred.
|
||||
echo [%DATE% %TIME%] An error occurred. >> "%LOG_FILE%"
|
||||
echo.
|
||||
echo %ESC%%RED%An error occurred. Check the log file:%ESC%%RESET%
|
||||
echo %ESC%%CYAN%%LOG_FILE%%ESC%%RESET%
|
||||
echo.
|
||||
echo [%DATE% %TIME%] ========================================== >> "%LOG_FILE%"
|
||||
echo [%DATE% %TIME%] Session ended with errors >> "%LOG_FILE%"
|
||||
echo [%DATE% %TIME%] ========================================== >> "%LOG_FILE%"
|
||||
echo.
|
||||
echo Press any key to close...
|
||||
pause >nul
|
||||
exit /b 1
|
||||
Reference in New Issue
Block a user