diff --git a/CHANGELOG.md b/CHANGELOG.md index 92a77b4c3..de4dfa659 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -22,7 +22,8 @@ Many bugs have been fixed, and numerous features that were only partially implem * Added support for Windows, macOS, FreeBSD, NetBSD and OpenBSD * New default theme rbsimple-DE bundled with the software (this theme is largely based on recalbox-multi by the Recalbox community) * Added extensive es_systems.cfg templates for Unix, macOS and Windows that are automatically installed on first application startup -* Full navigation sound support, configurable per theme with a fallback to the built-in sounds if there is no theme support +* Added full navigation sound support, configurable per theme with a fallback to the built-in sounds if there is no theme support +* Added multi-monitor support by giving the option to define on which display to run ES-DE * Improved input device configuration and default keyboard mappings are now applied if the keyboard has not been configured by the user * Reorganization and general overhaul of the menu system, hopefully making it more intuitive to navigate and easier to understand the menu entries * New game media file logic using a media directory with files matching the ROM names instead of explicitly pointing to the media files from the gamelist.xml files diff --git a/INSTALL.md b/INSTALL.md index 78e16fd9c..80c69ad12 100644 --- a/INSTALL.md +++ b/INSTALL.md @@ -1098,16 +1098,17 @@ Here is such an example: You normally don't need to modify this file manually as it's created by the built-in input configuration step. This procedure is detailed in the [User guide](USERGUIDE.md#input-device-configuration). -If your controller and keyboard stop working, you can delete the `~/.emulationstation/es_input.cfg` file to make the input configuration screen re-appear on the next startup, or you can start ES-DE with the `--force-input-config` command line argument. +If your controller and keyboard stop working, you can delete the `~/.emulationstation/es_input.cfg` file to make the input configuration screen re-appear on the next startup, or you can start ES-DE with the `--force-input-config` command line option. -## Command line arguments +## Command line options You can use **--help** or **-h** to view the list of command line options, as shown here. ### Unix ``` +--display [index] Display/monitor to use (1, 2, 3 or 4) --resolution [width] [height] Application resolution --windowed Windowed mode, should be combined with --resolution --fullscreen-normal Normal fullscreen mode @@ -1133,6 +1134,7 @@ You can use **--help** or **-h** to view the list of command line options, as sh ### macOS and Windows ``` +--display [index] Display/monitor to use (1, 2, 3 or 4) --resolution [width] [height] Application resolution --vsync [1/on or 0/off] Turn VSync on or off (default is on) --max-vram [size] Max VRAM to use (in mebibytes) before swapping diff --git a/USERGUIDE.md b/USERGUIDE.md index 16dcd3b00..3f0223c8a 100644 --- a/USERGUIDE.md +++ b/USERGUIDE.md @@ -948,6 +948,10 @@ These are mostly technical settings. The amount of video RAM to use for the application. Defaults to 256 MiB which seems to work fine most of the time. The allowed range is 80 to 1024 MiB. If you try to set it lower or higher than this by passing such values as command line parameters or edit the es_settings.cfg file manually, ES-DE will log a warning and automatically adjust the value within the allowable range. +**Display/monitor (requires restart)** + +This option sets the display to use for ES-DE for multi-monitor setups. The possible values are the monitor index numbers 1, 2, 3 or 4. If a value is set here for a display that does not actually exist, then ES-DE will set it to 1 upon startup. Index 1 is the primary display of the computer. It's also possible to override the setting by passing the --display command line argument. Doing so will also overwrite the display setting in es_settings.cfg. Be aware that the Display/monitor option only changes the display used by ES-DE; the emulators need to be configured separately (which can easily be done globally if using RetroArch). + **Fullscreen mode (requires restart)** _(Unix only)_ This gives you a choice between _Normal_ and _Borderless_ modes. With the borderless being more seamless as the ES-DE window will always stay on top of other windows so the taskbar will not be visible when launching and returning from games. It will however break the alt-tab application switching of your window manager. For normal fullscreen mode, if a lower resolution than the screen resolution has been set via the --resolution command line argument, ES-DE will render in full screen at the lower resolution. If a higher resolution than the screen resolution has been set, ES-DE will run in a window. For the borderless mode, any changes to the resolution will make ES-DE run in a window. diff --git a/es-app/assets/emulationstation.6.gz b/es-app/assets/emulationstation.6.gz index 0f2248345..0d476c36b 100644 Binary files a/es-app/assets/emulationstation.6.gz and b/es-app/assets/emulationstation.6.gz differ diff --git a/es-app/src/guis/GuiMenu.cpp b/es-app/src/guis/GuiMenu.cpp index 82b04aae0..cbce9d10f 100644 --- a/es-app/src/guis/GuiMenu.cpp +++ b/es-app/src/guis/GuiMenu.cpp @@ -662,6 +662,27 @@ void GuiMenu::openOtherSettings() } }); + // Display/monitor. + auto display_index = std::make_shared> + (mWindow, getHelpStyle(), "DISPLAY/MONITOR", false); + std::vector displayIndex; + displayIndex.push_back("1"); + displayIndex.push_back("2"); + displayIndex.push_back("3"); + displayIndex.push_back("4"); + for (auto it = displayIndex.cbegin(); it != displayIndex.cend(); it++) + display_index->add(*it, *it, + Settings::getInstance()->getInt("DisplayIndex") == atoi((*it).c_str())); + s->addWithLabel("DISPLAY/MONITOR (REQUIRES RESTART)", display_index); + s->addSaveFunc([display_index, s] { + if (atoi(display_index->getSelected().c_str()) != + Settings::getInstance()->getInt("DisplayIndex")) { + Settings::getInstance()->setInt("DisplayIndex", + atoi(display_index->getSelected().c_str())); + s->setNeedsSaving(); + } + }); + #if defined(__unix__) // Fullscreen mode. auto fullscreen_mode = std::make_shared> diff --git a/es-app/src/main.cpp b/es-app/src/main.cpp index 99c7e1918..42fb0bcab 100644 --- a/es-app/src/main.cpp +++ b/es-app/src/main.cpp @@ -165,7 +165,17 @@ bool parseArgs(int argc, char* argv[]) i++; // Skip the argument value. continue; } - if (strcmp(argv[i], "--resolution") == 0) { + if (strcmp(argv[i], "--display") == 0) { + if (i >= argc - 1 || atoi(argv[i + 1]) < 1 || atoi(argv[i + 1]) > 4) { + std::cerr << "Error: Invalid display index supplied.\n"; + return false; + } + int DisplayIndex = atoi(argv[i + 1]); + i++; + Settings::getInstance()->setInt("DisplayIndex", DisplayIndex); + Settings::getInstance()->saveFile(); + } + else if (strcmp(argv[i], "--resolution") == 0) { if (i >= argc - 2) { std::cerr << "Error: Invalid resolution values supplied.\n"; return false; @@ -280,6 +290,7 @@ bool parseArgs(int argc, char* argv[]) "Usage: emulationstation [options]\n" "EmulationStation Desktop Edition, Emulator Front-end\n\n" "Options:\n" +" --display [index] Display/monitor to use (1, 2, 3 or 4)\n" " --resolution [width] [height] Application resolution\n" #if defined(__unix__) " --windowed Windowed mode, should be combined with --resolution\n" diff --git a/es-core/src/Settings.cpp b/es-core/src/Settings.cpp index dc0dd8803..2932aca3f 100644 --- a/es-core/src/Settings.cpp +++ b/es-core/src/Settings.cpp @@ -191,6 +191,7 @@ void Settings::setDefaults() #else mIntMap["MaxVRAM"] = { 256, 256 }; #endif + mIntMap["DisplayIndex"] = { 1, 1 }; #if defined (__unix__) mStringMap["FullscreenMode"] = { "normal", "normal" }; #endif diff --git a/es-core/src/renderers/Renderer.cpp b/es-core/src/renderers/Renderer.cpp index b5baf8f9f..45af73e9a 100644 --- a/es-core/src/renderers/Renderer.cpp +++ b/es-core/src/renderers/Renderer.cpp @@ -87,16 +87,24 @@ namespace Renderer initialCursorState = (SDL_ShowCursor(0) != 0); - int displayIndex = 0; - int availableDisplays = SDL_GetNumVideoDisplays(); - - if (displayIndex > availableDisplays - 1) { - LOG(LogWarning) << "Requested display index " << std::to_string(displayIndex + 1) << - " does not exist, changing to index 1"; + int displayIndex = Settings::getInstance()->getInt("DisplayIndex"); + // Check that an invalid value has not been manually entered in the es_settings.cfg file. + if (displayIndex != 1 && displayIndex != 2 && displayIndex != 3 && displayIndex != 4) { + Settings::getInstance()->setInt("DisplayIndex", 1); displayIndex = 0; } else { - LOG(LogInfo) << "Using display index: " << std::to_string(displayIndex + 1); + displayIndex--; + } + + int availableDisplays = SDL_GetNumVideoDisplays(); + if (displayIndex > availableDisplays - 1) { + LOG(LogWarning) << "Requested display " << std::to_string(displayIndex + 1) << + " does not exist, changing to display 1"; + displayIndex = 0; + } + else { + LOG(LogInfo) << "Using display: " << std::to_string(displayIndex + 1); } SDL_DisplayMode displayMode; @@ -154,8 +162,8 @@ namespace Renderer // For Windows, always set the mode to windowed, as full screen mode seems to // behave quite erratic. There may be a proper fix for this, but for now windowed // mode seems to behave well and it's almost completely seamless, especially with - // a hidden taskbar. As well, setting SDL_WINDOW_BORDERLESS introduces issues as - // well so unfortunately this needs to be avoided. + // a hidden taskbar. As well, setting SDL_WINDOW_BORDERLESS introduces issues too + // so unfortunately this needs to be avoided. windowFlags = getWindowFlags(); #elif defined(__APPLE__) // This seems to be the only full window mode that somehow works on macOS as a real