(Android) Added experimental support for running in multi-window mode

This commit is contained in:
Leon Styhre 2024-11-18 22:57:39 +01:00
parent 697c3fb74f
commit b26da9d80d
10 changed files with 177 additions and 8 deletions

View file

@ -596,6 +596,13 @@ bool SystemData::loadConfig()
sStartupExitSignal = true;
return true;
}
#if defined(__ANDROID__)
if (event.type == SDL_WINDOWEVENT &&
event.window.event == SDL_WINDOWEVENT_SIZE_CHANGED) {
ViewController::getInstance()->setWindowSizeChanged(
static_cast<int>(event.window.data1), static_cast<int>(event.window.data2));
}
#endif
};
std::string name;

View file

@ -503,6 +503,15 @@ void applicationLoop()
if (SDL_PollEvent(&event)) {
do {
#if defined(__ANDROID__)
if (event.type == SDL_WINDOWEVENT &&
event.window.event == SDL_WINDOWEVENT_SIZE_CHANGED) {
// This covers switching to/from multi-window mode. Note that the reload
// mechanism is rather ungraceful as it just forcekills any open windows, which
// is problematic if the scraper or theme downloader is running for instance.
ViewController::getInstance()->setWindowSizeChanged(
static_cast<int>(event.window.data1), static_cast<int>(event.window.data2));
ViewController::getInstance()->checkWindowSizeChanged();
}
// Prevent that button presses get registered immediately when entering the
// foreground (which most commonly mean we're returning from a game).
// Also perform some other tasks on resume such as resetting timers.
@ -1101,7 +1110,16 @@ int main(int argc, char* argv[])
if (Settings::getInstance()->getBool("SplashScreen"))
window->renderSplashScreen(Window::SplashScreenState::SCANNING, 0.0f);
#if defined(__ANDROID__)
while (SDL_PollEvent(&event)) {
if (event.type == SDL_WINDOWEVENT && event.window.event == SDL_WINDOWEVENT_SIZE_CHANGED) {
ViewController::getInstance()->setWindowSizeChanged(
static_cast<int>(event.window.data1), static_cast<int>(event.window.data2));
}
};
#else
while (SDL_PollEvent(&event)) {};
#endif
#if defined(_WIN64)
// Hide taskbar if the setting for this is enabled.
@ -1249,6 +1267,11 @@ int main(int argc, char* argv[])
// Main application loop.
#if defined(__ANDROID__)
// If the window size changed during startup then we need to resize and reload.
ViewController::getInstance()->checkWindowSizeChanged();
#endif
if (!SystemData::sStartupExitSignal) {
#if defined(__EMSCRIPTEN__)
emscripten_set_main_loop(&applicationLoop, 0, 1);

View file

@ -13,6 +13,7 @@
#include "views/ViewController.h"
#include "ApplicationUpdater.h"
#include "AudioManager.h"
#include "CollectionSystemsManager.h"
#include "FileFilterIndex.h"
#include "InputManager.h"
@ -35,6 +36,10 @@
#include "views/GamelistView.h"
#include "views/SystemView.h"
#if defined(__ANDROID__)
#include "utils/PlatformUtilAndroid.h"
#endif
ViewController::ViewController() noexcept
: mRenderer {Renderer::getInstance()}
, mNoGamesMessageBox {nullptr}
@ -49,6 +54,8 @@ ViewController::ViewController() noexcept
, mFadeOpacity {0}
, mCancelledTransition {false}
, mNextSystem {false}
, mWindowChangedWidth {0}
, mWindowChangedHeight {0}
{
mState.viewing = ViewMode::NOTHING;
mState.previouslyViewed = ViewMode::NOTHING;
@ -1373,6 +1380,13 @@ void ViewController::preload()
SystemData::sStartupExitSignal = true;
return;
}
#if defined(__ANDROID__)
if (event.type == SDL_WINDOWEVENT &&
event.window.event == SDL_WINDOWEVENT_SIZE_CHANGED) {
setWindowSizeChanged(static_cast<int>(event.window.data1),
static_cast<int>(event.window.data2));
}
#endif
};
const std::string entryType {(*it)->isCustomCollection() ? "custom collection" : "system"};
@ -1551,6 +1565,71 @@ void ViewController::reloadAll()
updateHelpPrompts();
}
void ViewController::setWindowSizeChanged(const int width, const int height)
{
#if defined(__ANDROID__)
const std::pair<int, int> windowSize {Utils::Platform::Android::getWindowSize()};
if (windowSize.first == static_cast<int>(mRenderer->getScreenWidth()) &&
windowSize.second == static_cast<int>(mRenderer->getScreenHeight())) {
mWindowChangedWidth = 0;
mWindowChangedHeight = 0;
}
else {
mWindowChangedWidth = windowSize.first;
mWindowChangedHeight = windowSize.second;
}
#endif
}
void ViewController::checkWindowSizeChanged()
{
if (mWindowChangedWidth == 0 || mWindowChangedHeight == 0)
return;
LOG(LogInfo) << "Window size has changed from " << mRenderer->getScreenWidth() << "x"
<< mRenderer->getScreenHeight() << " to " << mWindowChangedWidth << "x"
<< mWindowChangedHeight << ", reloading...";
mWindowChangedWidth = 0;
mWindowChangedHeight = 0;
mWindow->stopInfoPopup();
if (mState.viewing != ViewController::ViewMode::NOTHING) {
mWindow->stopScreensaver();
mWindow->stopMediaViewer();
mWindow->stopPDFViewer();
}
// This is done quite ungracefully, essentially forcekilling all open windows.
while (mWindow->getGuiStackSize() > 1)
mWindow->removeGui(mWindow->peekGui());
AudioManager::getInstance().deinit();
mWindow->deinit();
SDL_Delay(20);
AudioManager::getInstance().init();
mWindow->init(true);
mWindow->setLaunchedGame(false);
mWindow->invalidateCachedBackground();
mWindow->renderSplashScreen(Window::SplashScreenState::RELOADING, 0.0f);
if (mState.viewing != ViewController::ViewMode::NOTHING) {
reloadAll();
goToStart(false);
resetCamera();
}
else {
noGamesDialog();
}
#if defined(__ANDROID__)
InputOverlay::getInstance().init();
#endif
}
void ViewController::rescanROMDirectory()
{
mWindow->setBlockInput(true);

View file

@ -56,6 +56,10 @@ public:
// Reload everything with a theme, used when the "Theme" setting changes.
void reloadAll();
// On window size changes we need to deinit/init the application, reload the systems etc.
void setWindowSizeChanged(const int width, const int height);
void checkWindowSizeChanged();
// Rescan the ROM directory for any changes to games and systems.
void rescanROMDirectory();
@ -199,6 +203,8 @@ private:
float mFadeOpacity;
bool mCancelledTransition; // Needed only for the Fade transition style.
bool mNextSystem;
int mWindowChangedWidth;
int mWindowChangedHeight;
};
#endif // ES_APP_VIEWS_VIEW_CONTROLLER_H

View file

@ -107,7 +107,7 @@ GuiComponent* Window::peekGui()
return mGuiStack.back();
}
bool Window::init()
bool Window::init(bool resized)
{
if (!mRenderer->init()) {
LOG(LogError) << "Renderer failed to initialize.";
@ -133,6 +133,9 @@ bool Window::init()
mDefaultFonts.push_back(Font::get(FONT_SIZE_LARGE_FIXED));
}
if (resized)
Font::updateFontSizes();
if (mRenderer->getIsVerticalOrientation())
mSplash->setResize(mRenderer->getScreenWidth() * 0.8f, 0.0f);
else

View file

@ -93,7 +93,7 @@ public:
int getGuiStackSize() { return static_cast<int>(mGuiStack.size()); }
bool isBackgroundDimmed();
bool init();
bool init(bool resized = false);
void deinit();
void input(InputConfig* config, Input input);

View file

@ -15,6 +15,10 @@
#include "renderers/ShaderOpenGL.h"
#include "resources/ResourceManager.h"
#if defined(__ANDROID__)
#include "utils/PlatformUtilAndroid.h"
#endif
#if defined(_WIN64)
#include <windows.h>
#endif
@ -101,12 +105,26 @@ bool Renderer::createWindow()
displayMode.h = displayBounds.h;
#endif
#if defined(__ANDROID__)
const std::pair<int, int> windowSize {Utils::Platform::Android::getWindowSize()};
if (windowSize.first != 0 && windowSize.second != 0) {
sScreenWidth = windowSize.first;
sScreenHeight = windowSize.second;
}
else {
sScreenWidth = displayMode.w;
sScreenHeight = displayMode.h;
}
#else
sScreenWidth = Settings::getInstance()->getInt("ScreenWidth") ?
Settings::getInstance()->getInt("ScreenWidth") :
displayMode.w;
sScreenHeight = Settings::getInstance()->getInt("ScreenHeight") ?
Settings::getInstance()->getInt("ScreenHeight") :
displayMode.h;
#endif
mScreenOffsetX = glm::clamp((Settings::getInstance()->getInt("ScreenOffsetX") ?
Settings::getInstance()->getInt("ScreenOffsetX") :
0),
@ -228,6 +246,8 @@ bool Renderer::createWindow()
return false;
}
mDisplayIndex = displayIndex;
#if defined(__APPLE__)
// The code below is required as the high DPI scaling on macOS is very bizarre and is
// measured in "points" rather than pixels (even though the naming convention sure looks

View file

@ -183,6 +183,7 @@ public:
const glm::mat4& getProjectionMatrix() { return mProjectionMatrix; }
const glm::mat4& getProjectionMatrixNormal() { return mProjectionMatrixNormal; }
SDL_Window* getSDLWindow() { return mSDLWindow; }
const int getDisplayIndex() { return mDisplayIndex; }
const int getScreenRotation() { return mScreenRotation; }
static const bool getIsVerticalOrientation() { return sIsVerticalOrientation; }
static const float getScreenWidth() { return static_cast<float>(sScreenWidth); }
@ -249,6 +250,7 @@ private:
static inline int sScreenWidth {0};
static inline int sScreenHeight {0};
int mDisplayIndex {0};
int mScreenRotation {0};
bool mInitialCursorState {true};
static inline bool sIsVerticalOrientation {false};

View file

@ -118,6 +118,16 @@ std::shared_ptr<Font> Font::get(float size, const std::string& path)
return font;
}
void Font::updateFontSizes()
{
getMiniFont(true);
getSmallFont(true);
getMediumFont(true);
getMediumFixedFont(true);
getLargeFont(true);
getLargeFixedFont(true);
}
glm::vec2 Font::sizeText(std::string text, float lineSpacing)
{
if (text == "")

View file

@ -37,46 +37,65 @@ class Font : public IReloadable
public:
virtual ~Font();
static std::shared_ptr<Font> get(float size, const std::string& path = getDefaultPath());
static float getMiniFont()
static float getMiniFont(bool forceUpdate = false)
{
static float sMiniFont {0.030f *
std::min(Renderer::getScreenHeight(), Renderer::getScreenWidth())};
if (forceUpdate)
sMiniFont = 0.030f * std::min(Renderer::getScreenHeight(), Renderer::getScreenWidth());
return sMiniFont;
}
static float getSmallFont()
static float getSmallFont(bool forceUpdate = false)
{
static float sSmallFont {0.035f *
std::min(Renderer::getScreenHeight(), Renderer::getScreenWidth())};
if (forceUpdate)
sSmallFont = 0.035f * std::min(Renderer::getScreenHeight(), Renderer::getScreenWidth());
return sSmallFont;
}
static float getMediumFont()
static float getMediumFont(bool forceUpdate = false)
{
static float sMediumFont {
(Renderer::getIsVerticalOrientation() ? 0.040f : 0.045f) *
std::min(Renderer::getScreenHeight(), Renderer::getScreenWidth())};
if (forceUpdate)
sMediumFont = (Renderer::getIsVerticalOrientation() ? 0.040f : 0.045f) *
std::min(Renderer::getScreenHeight(), Renderer::getScreenWidth());
return sMediumFont;
}
static float getMediumFixedFont()
static float getMediumFixedFont(bool forceUpdate = false)
{
// Fixed size regardless of screen orientation.
static float sMediumFixedFont {
0.045f * std::min(Renderer::getScreenHeight(), Renderer::getScreenWidth())};
if (forceUpdate)
sMediumFixedFont =
0.045f * std::min(Renderer::getScreenHeight(), Renderer::getScreenWidth());
return sMediumFixedFont;
}
static float getLargeFont()
static float getLargeFont(bool forceUpdate = false)
{
static float sLargeFont {(Renderer::getIsVerticalOrientation() ? 0.080f : 0.085f) *
std::min(Renderer::getScreenHeight(), Renderer::getScreenWidth())};
if (forceUpdate)
sLargeFont = (Renderer::getIsVerticalOrientation() ? 0.080f : 0.085f) *
std::min(Renderer::getScreenHeight(), Renderer::getScreenWidth());
return sLargeFont;
}
static float getLargeFixedFont()
static float getLargeFixedFont(bool forceUpdate = false)
{
// Fixed size regardless of screen orientation.
static float sLargeFixedFont {
0.085f * std::min(Renderer::getScreenHeight(), Renderer::getScreenWidth())};
if (forceUpdate)
sLargeFixedFont =
0.085f * std::min(Renderer::getScreenHeight(), Renderer::getScreenWidth());
return sLargeFixedFont;
}
// Needed for when the application window has been resized.
static void updateFontSizes();
// Returns the size of shaped text without applying any wrapping or abbreviations.
glm::vec2 sizeText(std::string text, float lineSpacing = 1.5f);