diff --git a/UI/GameSettingsScreen.cpp b/UI/GameSettingsScreen.cpp index 2747ed9f8245..05b3a4a43d62 100644 --- a/UI/GameSettingsScreen.cpp +++ b/UI/GameSettingsScreen.cpp @@ -1175,8 +1175,10 @@ UI::EventReturn GameSettingsScreen::OnSysInfo(UI::EventParams &e) { void DeveloperToolsScreen::CreateViews() { using namespace UI; - root_ = new ScrollView(ORIENT_VERTICAL); - root_->SetTag("DevToolsSettings"); + root_ = new LinearLayout(ORIENT_VERTICAL, new LayoutParams(FILL_PARENT, FILL_PARENT)); + ScrollView *settingsScroll = new ScrollView(ORIENT_VERTICAL, new LinearLayoutParams(1.0f)); + settingsScroll->SetTag("DevToolsSettings"); + root_->Add(settingsScroll); I18NCategory *di = GetI18NCategory("Dialog"); I18NCategory *dev = GetI18NCategory("Developer"); @@ -1184,7 +1186,9 @@ void DeveloperToolsScreen::CreateViews() { I18NCategory *a = GetI18NCategory("Audio"); I18NCategory *sy = GetI18NCategory("System"); - LinearLayout *list = root_->Add(new LinearLayout(ORIENT_VERTICAL, new LinearLayoutParams(1.0f))); + AddStandardBack(root_); + + LinearLayout *list = settingsScroll->Add(new LinearLayout(ORIENT_VERTICAL, new LinearLayoutParams(1.0f))); list->SetSpacing(0); list->Add(new ItemHeader(sy->T("General"))); @@ -1227,8 +1231,6 @@ void DeveloperToolsScreen::CreateViews() { #if !defined(MOBILE_DEVICE) list->Add(new Choice(dev->T("Create/Open textures.ini file for current game")))->OnClick.Handle(this, &DeveloperToolsScreen::OnOpenTexturesIniFile); #endif - list->Add(new ItemHeader("")); - list->Add(new Choice(di->T("Back")))->OnClick.Handle(this, &UIScreen::OnBack); } void DeveloperToolsScreen::onFinish(DialogResult result) { diff --git a/UI/RemoteISOScreen.cpp b/UI/RemoteISOScreen.cpp index 5d3346729c8e..690b06ad9bab 100644 --- a/UI/RemoteISOScreen.cpp +++ b/UI/RemoteISOScreen.cpp @@ -50,6 +50,7 @@ static std::mutex serverStatusLock; static std::condition_variable serverStatusCond; static bool scanCancelled = false; +static bool scanAborted = false; static void UpdateStatus(ServerStatus s) { std::lock_guard guard(serverStatusLock); @@ -69,7 +70,7 @@ static void RegisterServer(int port) { Buffer theVoid; if (http.Resolve(REPORT_HOSTNAME, REPORT_PORT)) { - if (http.Connect()) { + if (http.Connect(2, 20.0, &scanCancelled)) { char resource[1024] = {}; std::string ip = fd_util::GetLocalIP(http.sock()); snprintf(resource, sizeof(resource) - 1, "/match/update?local=%s&port=%d", ip.c_str(), port); @@ -190,22 +191,34 @@ static bool FindServer(std::string &resultHost, int &resultPort) { Buffer result; int code = 500; + auto TryServer = [&](const std::string &host, int port) { + // Don't wait as long for a connect - we need a good connection for smooth streaming anyway. + // This way if it's down, we'll find the right one faster. + if (http.Resolve(host.c_str(), port) && http.Connect(1, 10.0, &scanCancelled)) { + http.Disconnect(); + resultHost = host; + resultPort = port; + return true; + } + + return false; + }; + // Try last server first, if it is set - if (g_Config.iLastRemoteISOPort && g_Config.sLastRemoteISOServer != "" && http.Resolve(g_Config.sLastRemoteISOServer.c_str(), g_Config.iLastRemoteISOPort) && http.Connect()) { - http.Disconnect(); - resultHost = g_Config.sLastRemoteISOServer; - resultPort = g_Config.iLastRemoteISOPort; - return true; + if (g_Config.iLastRemoteISOPort && g_Config.sLastRemoteISOServer != "") { + if (TryServer(g_Config.sLastRemoteISOServer.c_str(), g_Config.iLastRemoteISOPort)) { + return true; + } } - //don't scan if in manual mode - if (g_Config.bRemoteISOManual) { + // Don't scan if in manual mode. + if (g_Config.bRemoteISOManual || scanCancelled) { return false; } // Start by requesting a list of recent local ips for this network. if (http.Resolve(REPORT_HOSTNAME, REPORT_PORT)) { - if (http.Connect()) { + if (http.Connect(2, 20.0, &scanCancelled)) { code = http.GET("/match/list", &result); http.Disconnect(); } @@ -230,7 +243,7 @@ static bool FindServer(std::string &resultHost, int &resultPort) { std::vector servers; const json_value *entry = entries->first_child; - while (entry) { + while (entry && !scanCancelled) { const char *host = entry->getString("ip", ""); int port = entry->getInt("p", 0); @@ -238,10 +251,7 @@ static bool FindServer(std::string &resultHost, int &resultPort) { snprintf(url, sizeof(url), "http://%s:%d", host, port); servers.push_back(url); - if (http.Resolve(host, port) && http.Connect()) { - http.Disconnect(); - resultHost = host; - resultPort = port; + if (TryServer(host, port)) { return true; } @@ -271,7 +281,7 @@ static bool LoadGameList(const std::string &host, int port, std::vectorT("Settings")); rightColumnItems->Add(settingsChoice)->OnClick.Handle(this, &RemoteISOScreen::HandleSettings); - rightColumnItems->Add(new Spacer(25.0)); - rightColumnItems->Add(new Choice(di->T("Back"), "", false, new AnchorLayoutParams(150, WRAP_CONTENT, 10, NONE, NONE, 10)))->OnClick.Handle(this, &UIScreen::OnBack); - - root_ = new LinearLayout(ORIENT_HORIZONTAL, new LinearLayoutParams(FILL_PARENT, FILL_PARENT, 1.0f)); - root_->Add(leftColumn); - root_->Add(rightColumn); + LinearLayout *beforeBack = new LinearLayout(ORIENT_HORIZONTAL, new AnchorLayoutParams(FILL_PARENT, FILL_PARENT)); + beforeBack->Add(leftColumn); + beforeBack->Add(rightColumn); + root_ = new AnchorLayout(new LayoutParams(FILL_PARENT, FILL_PARENT)); + root_->Add(beforeBack); + root_->Add(new Choice(di->T("Back"), "", false, new AnchorLayoutParams(150, WRAP_CONTENT, 10, NONE, NONE, 10)))->OnClick.Handle(this, &UIScreen::OnBack); leftColumn->Add(leftColumnItems); rightColumn->Add(rightColumnItems); @@ -441,6 +451,7 @@ UI::EventReturn RemoteISOScreen::HandleSettings(UI::EventParams &e) { RemoteISOConnectScreen::RemoteISOConnectScreen() : status_(ScanStatus::SCANNING), nextRetry_(0.0) { scanCancelled = false; + scanAborted = false; scanThread_ = new std::thread([](RemoteISOConnectScreen *thiz) { thiz->ExecuteScan(); @@ -455,6 +466,7 @@ RemoteISOConnectScreen::~RemoteISOConnectScreen() { sleep_ms(1); if (--maxWait < 0) { // If it does ever wake up, it may crash... but better than hanging? + scanAborted = true; break; } } @@ -473,8 +485,6 @@ void RemoteISOConnectScreen::CreateViews() { statusView_ = leftColumnItems->Add(new TextView(sy->T("RemoteISOScanning", "Scanning... click Share Games on your desktop"), new LinearLayoutParams(Margins(12, 5, 0, 5)))); - // TODO: Here would be a good place for manual entry. - rightColumnItems->SetSpacing(0.0f); rightColumnItems->Add(new Choice(sy->T("Cancel"), "", false, new AnchorLayoutParams(150, WRAP_CONTENT, 10, NONE, NONE, 10)))->OnClick.Handle(this, &UIScreen::OnBack); @@ -536,7 +546,7 @@ void RemoteISOConnectScreen::update() { void RemoteISOConnectScreen::ExecuteScan() { FindServer(host_, port_); - if (scanCancelled) { + if (scanAborted) { return; } @@ -551,7 +561,7 @@ ScanStatus RemoteISOConnectScreen::GetStatus() { void RemoteISOConnectScreen::ExecuteLoad() { bool result = LoadGameList(host_, port_, games_); - if (scanCancelled) { + if (scanAborted) { return; } @@ -639,13 +649,27 @@ void RemoteISOBrowseScreen::CreateViews() { upgradeBar_ = 0; } +RemoteISOSettingsScreen::RemoteISOSettingsScreen() { + serverRunning_ = RetrieveStatus() != ServerStatus::STOPPED;; +} + +void RemoteISOSettingsScreen::update() { + UIDialogScreenWithBackground::update(); + + bool nowRunning = RetrieveStatus() != ServerStatus::STOPPED; + if (serverRunning_ != nowRunning) { + RecreateViews(); + } + serverRunning_ = nowRunning; +} + void RemoteISOSettingsScreen::CreateViews() { I18NCategory *di = GetI18NCategory("Dialog"); I18NCategory *n = GetI18NCategory("Networking"); I18NCategory *ms = GetI18NCategory("MainSettings"); - ViewGroup *remoteisoSettingsScroll = new ScrollView(ORIENT_VERTICAL, new LinearLayoutParams(FILL_PARENT, FILL_PARENT)); - remoteisoSettingsScroll->SetTag("GameSettingsNetworking"); + ViewGroup *remoteisoSettingsScroll = new ScrollView(ORIENT_VERTICAL, new LayoutParams(FILL_PARENT, FILL_PARENT)); + remoteisoSettingsScroll->SetTag("RemoteISOSettings"); LinearLayout *remoteisoSettings = new LinearLayout(ORIENT_VERTICAL); remoteisoSettings->SetSpacing(0); remoteisoSettingsScroll->Add(remoteisoSettings); @@ -659,12 +683,15 @@ void RemoteISOSettingsScreen::CreateViews() { PopupTextInputChoice *remoteSubdir = remoteisoSettings->Add(new PopupTextInputChoice(&g_Config.sRemoteISOSubdir, n->T("Remote Subdirectory"), "", 255, screenManager())); remoteSubdir->SetEnabledPtr(&g_Config.bRemoteISOManual); remoteSubdir->OnChange.Handle(this, &RemoteISOSettingsScreen::OnChangeRemoteISOSubdir); - remoteisoSettings->Add(new PopupSliderChoice(&g_Config.iRemoteISOPort, 0, 65535, n->T("Local Server Port", "Local Server Port"), 100, screenManager())); + + PopupSliderChoice *portChoice = new PopupSliderChoice(&g_Config.iRemoteISOPort, 0, 65535, n->T("Local Server Port", "Local Server Port"), 100, screenManager()); + remoteisoSettings->Add(portChoice); + portChoice->SetDisabledPtr(&serverRunning_); remoteisoSettings->Add(new Spacer(25.0)); - remoteisoSettings->Add(new Choice(di->T("Back"), "", false, new AnchorLayoutParams(150, WRAP_CONTENT, 10, NONE, NONE, 10)))->OnClick.Handle(this, &UIScreen::OnBack); root_ = new AnchorLayout(new LayoutParams(FILL_PARENT, FILL_PARENT)); - root_->Add(remoteisoSettings); + root_->Add(remoteisoSettingsScroll); + AddStandardBack(root_); } UI::EventReturn RemoteISOSettingsScreen::OnChangeRemoteISOSubdir(UI::EventParams &e) { diff --git a/UI/RemoteISOScreen.h b/UI/RemoteISOScreen.h index 75b34ff968b4..85995e219466 100644 --- a/UI/RemoteISOScreen.h +++ b/UI/RemoteISOScreen.h @@ -85,12 +85,15 @@ class RemoteISOBrowseScreen : public MainScreen { std::vector games_; }; -class RemoteISOSettingsScreen : public UIScreenWithBackground { +class RemoteISOSettingsScreen : public UIDialogScreenWithBackground { public: + RemoteISOSettingsScreen(); protected: + void update() override; void CreateViews() override; UI::EventReturn OnChangeRemoteISOSubdir(UI::EventParams &e); + bool serverRunning_ = false; }; diff --git a/ext/native/net/http_client.cpp b/ext/native/net/http_client.cpp index a8836b257bca..becb4e4473a1 100644 --- a/ext/native/net/http_client.cpp +++ b/ext/native/net/http_client.cpp @@ -73,7 +73,7 @@ bool Connection::Resolve(const char *host, int port) { return true; } -bool Connection::Connect(int maxTries, double timeout) { +bool Connection::Connect(int maxTries, double timeout, bool *cancelConnect) { if (port_ <= 0) { ELOG("Bad port"); return false; @@ -106,10 +106,26 @@ bool Connection::Connect(int maxTries, double timeout) { } } - struct timeval tv; - tv.tv_sec = floor(timeout); - tv.tv_usec = (timeout - floor(timeout)) * 1000000.0; - if (select(maxfd, NULL, &fds, NULL, &tv) > 0) { + int selectResult = 0; + long timeoutHalfSeconds = floor(2 * timeout); + while (timeoutHalfSeconds >= 0 && selectResult == 0) { + struct timeval tv; + tv.tv_sec = 0; + if (timeoutHalfSeconds > 0) { + // Wait up to 0.5 seconds between cancel checks. + tv.tv_usec = 500000; + } else { + // Wait the remaining <= 0.5 seconds. Possibly 0, but that's okay. + tv.tv_usec = (timeout - floor(2 * timeout) / 2) * 1000000.0; + } + --timeoutHalfSeconds; + + selectResult = select(maxfd, nullptr, &fds, nullptr, &tv); + if (cancelConnect && *cancelConnect) { + break; + } + } + if (selectResult > 0) { // Something connected. Pick the first one that did (if multiple.) for (int sock : sockets) { if ((intptr_t)sock_ == -1 && FD_ISSET(sock, &fds)) { @@ -123,6 +139,11 @@ bool Connection::Connect(int maxTries, double timeout) { // Great, now we're good to go. return true; } + + if (cancelConnect && *cancelConnect) { + break; + } + sleep_ms(1); } diff --git a/ext/native/net/http_client.h b/ext/native/net/http_client.h index 1147540301d6..8cc910c4c2fd 100644 --- a/ext/native/net/http_client.h +++ b/ext/native/net/http_client.h @@ -29,7 +29,7 @@ class Connection { // Inits the sockaddr_in. bool Resolve(const char *host, int port); - bool Connect(int maxTries = 2, double timeout = 20.0f); + bool Connect(int maxTries = 2, double timeout = 20.0f, bool *cancelConnect = nullptr); void Disconnect(); // Only to be used for bring-up and debugging. @@ -167,4 +167,4 @@ class Downloader { std::vector> downloads_; }; -} // http \ No newline at end of file +} // http