mirror of
https://github.com/ddnet/ddnet.git
synced 2024-11-18 22:18:19 +00:00
Merge pull request #8562 from Robyt3/Client-Open-Link-SDL
Use `SDL_OpenURL` to open links and files on Android
This commit is contained in:
commit
398dc7ece9
|
@ -4175,6 +4175,7 @@ bool is_process_alive(PROCESS process)
|
|||
#endif
|
||||
}
|
||||
|
||||
#if !defined(CONF_PLATFORM_ANDROID)
|
||||
int open_link(const char *link)
|
||||
{
|
||||
#if defined(CONF_FAMILY_WINDOWS)
|
||||
|
@ -4236,6 +4237,7 @@ int open_file(const char *path)
|
|||
return open_link(buf);
|
||||
#endif
|
||||
}
|
||||
#endif // !defined(CONF_PLATFORM_ANDROID)
|
||||
|
||||
struct SECURE_RANDOM_DATA
|
||||
{
|
||||
|
|
|
@ -2583,6 +2583,7 @@ int kill_process(PROCESS process);
|
|||
*/
|
||||
bool is_process_alive(PROCESS process);
|
||||
|
||||
#if !defined(CONF_PLATFORM_ANDROID)
|
||||
/**
|
||||
* Opens a link in the browser.
|
||||
*
|
||||
|
@ -2598,11 +2599,11 @@ bool is_process_alive(PROCESS process);
|
|||
int open_link(const char *link);
|
||||
|
||||
/**
|
||||
* Opens a file or directory with default program.
|
||||
* Opens a file or directory with the default program.
|
||||
*
|
||||
* @ingroup Shell
|
||||
*
|
||||
* @param path The path to open.
|
||||
* @param path The file or folder to open with the default program.
|
||||
*
|
||||
* @return `1` on success, `0` on failure.
|
||||
*
|
||||
|
@ -2610,6 +2611,7 @@ int open_link(const char *link);
|
|||
* @remark This may not be called with untrusted input or it'll result in arbitrary code execution, especially on Windows.
|
||||
*/
|
||||
int open_file(const char *path);
|
||||
#endif // !defined(CONF_PLATFORM_ANDROID)
|
||||
|
||||
/**
|
||||
* @defgroup Secure-Random
|
||||
|
|
|
@ -289,6 +289,27 @@ public:
|
|||
virtual CChecksumData *ChecksumData() = 0;
|
||||
virtual int UdpConnectivity(int NetType) = 0;
|
||||
|
||||
/**
|
||||
* Opens a link in the browser.
|
||||
*
|
||||
* @param pLink The link to open in a browser.
|
||||
*
|
||||
* @return `true` on success, `false` on failure.
|
||||
*
|
||||
* @remark This may not be called with untrusted input or it'll result in arbitrary code execution, especially on Windows.
|
||||
*/
|
||||
virtual bool ViewLink(const char *pLink) = 0;
|
||||
/**
|
||||
* Opens a file or directory with the default program.
|
||||
*
|
||||
* @param pFilename The file or folder to open with the default program.
|
||||
*
|
||||
* @return `true` on success, `false` on failure.
|
||||
*
|
||||
* @remark This may not be called with untrusted input or it'll result in arbitrary code execution, especially on Windows.
|
||||
*/
|
||||
virtual bool ViewFile(const char *pFilename) = 0;
|
||||
|
||||
#if defined(CONF_FAMILY_WINDOWS)
|
||||
virtual void ShellRegister() = 0;
|
||||
virtual void ShellUnregister() = 0;
|
||||
|
|
|
@ -4781,6 +4781,51 @@ int CClient::UdpConnectivity(int NetType)
|
|||
return Connectivity;
|
||||
}
|
||||
|
||||
bool CClient::ViewLink(const char *pLink)
|
||||
{
|
||||
#if defined(CONF_PLATFORM_ANDROID)
|
||||
if(SDL_OpenURL(pLink) == 0)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
log_error("client", "Failed to open link '%s' (%s)", pLink, SDL_GetError());
|
||||
return false;
|
||||
#else
|
||||
if(open_link(pLink))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
log_error("client", "Failed to open link '%s'", pLink);
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
bool CClient::ViewFile(const char *pFilename)
|
||||
{
|
||||
#if defined(CONF_PLATFORM_MACOS)
|
||||
return ViewLink(pFilename);
|
||||
#else
|
||||
// Create a file link so the path can contain forward and
|
||||
// backward slashes. But the file link must be absolute.
|
||||
char aWorkingDir[IO_MAX_PATH_LENGTH];
|
||||
if(fs_is_relative_path(pFilename))
|
||||
{
|
||||
if(!fs_getcwd(aWorkingDir, sizeof(aWorkingDir)))
|
||||
{
|
||||
log_error("client", "Failed to open file '%s' (failed to get working directory)", pFilename);
|
||||
return false;
|
||||
}
|
||||
str_append(aWorkingDir, "/");
|
||||
}
|
||||
else
|
||||
aWorkingDir[0] = '\0';
|
||||
|
||||
char aFileLink[IO_MAX_PATH_LENGTH];
|
||||
str_format(aFileLink, sizeof(aFileLink), "file://%s%s", aWorkingDir, pFilename);
|
||||
return ViewLink(aFileLink);
|
||||
#endif
|
||||
}
|
||||
|
||||
#if defined(CONF_FAMILY_WINDOWS)
|
||||
void CClient::ShellRegister()
|
||||
{
|
||||
|
|
|
@ -503,6 +503,9 @@ public:
|
|||
CChecksumData *ChecksumData() override { return &m_Checksum.m_Data; }
|
||||
int UdpConnectivity(int NetType) override;
|
||||
|
||||
bool ViewLink(const char *pLink) override;
|
||||
bool ViewFile(const char *pFilename) override;
|
||||
|
||||
#if defined(CONF_FAMILY_WINDOWS)
|
||||
void ShellRegister() override;
|
||||
void ShellUnregister() override;
|
||||
|
|
|
@ -1625,10 +1625,7 @@ void CMenus::RenderPopupFullscreen(CUIRect Screen)
|
|||
static CButtonContainer s_ButtonOpenFolder;
|
||||
if(DoButton_Menu(&s_ButtonOpenFolder, Localize("Videos directory"), 0, &OpenFolder))
|
||||
{
|
||||
if(!open_file(aSaveFolder))
|
||||
{
|
||||
dbg_msg("menus", "couldn't open file '%s'", aSaveFolder);
|
||||
}
|
||||
Client()->ViewFile(aSaveFolder);
|
||||
}
|
||||
|
||||
static CButtonContainer s_ButtonOk;
|
||||
|
|
|
@ -1458,10 +1458,7 @@ void CMenus::RenderDemoBrowserButtons(CUIRect ButtonsView, bool WasListboxItemAc
|
|||
{
|
||||
char aBuf[IO_MAX_PATH_LENGTH];
|
||||
Storage()->GetCompletePath(m_DemolistSelectedIndex >= 0 ? m_vpFilteredDemos[m_DemolistSelectedIndex]->m_StorageType : IStorage::TYPE_SAVE, m_aCurrentDemoFolder[0] == '\0' ? "demos" : m_aCurrentDemoFolder, aBuf, sizeof(aBuf));
|
||||
if(!open_file(aBuf))
|
||||
{
|
||||
dbg_msg("menus", "couldn't open file '%s'", aBuf);
|
||||
}
|
||||
Client()->ViewFile(aBuf);
|
||||
}
|
||||
GameClient()->m_Tooltips.DoToolTip(&s_DemosDirectoryButton, &DemosDirectoryButton, Localize("Open the directory that contains the demo files"));
|
||||
}
|
||||
|
|
|
@ -1166,10 +1166,7 @@ void CMenus::RenderGhost(CUIRect MainView)
|
|||
char aBuf[IO_MAX_PATH_LENGTH];
|
||||
Storage()->GetCompletePath(IStorage::TYPE_SAVE, "ghosts", aBuf, sizeof(aBuf));
|
||||
Storage()->CreateFolder("ghosts", IStorage::TYPE_SAVE);
|
||||
if(!open_file(aBuf))
|
||||
{
|
||||
dbg_msg("menus", "couldn't open file '%s'", aBuf);
|
||||
}
|
||||
Client()->ViewFile(aBuf);
|
||||
}
|
||||
|
||||
Status.VSplitLeft(5.0f, &Button, &Status);
|
||||
|
|
|
@ -77,8 +77,8 @@ bool CMenusKeyBinder::OnInput(const IInput::CEvent &Event)
|
|||
void CMenus::RenderSettingsGeneral(CUIRect MainView)
|
||||
{
|
||||
char aBuf[128 + IO_MAX_PATH_LENGTH];
|
||||
CUIRect Label, Button, Left, Right, Game, Client;
|
||||
MainView.HSplitTop(150.0f, &Game, &Client);
|
||||
CUIRect Label, Button, Left, Right, Game, ClientSettings;
|
||||
MainView.HSplitTop(150.0f, &Game, &ClientSettings);
|
||||
|
||||
// game
|
||||
{
|
||||
|
@ -139,10 +139,10 @@ void CMenus::RenderSettingsGeneral(CUIRect MainView)
|
|||
// client
|
||||
{
|
||||
// headline
|
||||
Client.HSplitTop(30.0f, &Label, &Client);
|
||||
ClientSettings.HSplitTop(30.0f, &Label, &ClientSettings);
|
||||
Ui()->DoLabel(&Label, Localize("Client"), 20.0f, TEXTALIGN_ML);
|
||||
Client.HSplitTop(5.0f, nullptr, &Client);
|
||||
Client.VSplitMid(&Left, &Right, 20.0f);
|
||||
ClientSettings.HSplitTop(5.0f, nullptr, &ClientSettings);
|
||||
ClientSettings.VSplitMid(&Left, &Right, 20.0f);
|
||||
|
||||
// skip main menu
|
||||
Left.HSplitTop(20.0f, &Button, &Left);
|
||||
|
@ -165,10 +165,7 @@ void CMenus::RenderSettingsGeneral(CUIRect MainView)
|
|||
if(DoButton_Menu(&s_SettingsButtonId, Localize("Settings file"), 0, &SettingsButton))
|
||||
{
|
||||
Storage()->GetCompletePath(IStorage::TYPE_SAVE, CONFIG_FILE, aBuf, sizeof(aBuf));
|
||||
if(!open_file(aBuf))
|
||||
{
|
||||
dbg_msg("menus", "couldn't open file '%s'", aBuf);
|
||||
}
|
||||
Client()->ViewFile(aBuf);
|
||||
}
|
||||
GameClient()->m_Tooltips.DoToolTip(&s_SettingsButtonId, &SettingsButton, Localize("Open the settings file"));
|
||||
|
||||
|
@ -179,10 +176,7 @@ void CMenus::RenderSettingsGeneral(CUIRect MainView)
|
|||
if(DoButton_Menu(&s_ConfigButtonId, Localize("Config directory"), 0, &ConfigButton))
|
||||
{
|
||||
Storage()->GetCompletePath(IStorage::TYPE_SAVE, "", aBuf, sizeof(aBuf));
|
||||
if(!open_file(aBuf))
|
||||
{
|
||||
dbg_msg("menus", "couldn't open file '%s'", aBuf);
|
||||
}
|
||||
Client()->ViewFile(aBuf);
|
||||
}
|
||||
GameClient()->m_Tooltips.DoToolTip(&s_ConfigButtonId, &ConfigButton, Localize("Open the directory that contains the configuration and user files"));
|
||||
|
||||
|
@ -194,10 +188,7 @@ void CMenus::RenderSettingsGeneral(CUIRect MainView)
|
|||
{
|
||||
Storage()->GetCompletePath(IStorage::TYPE_SAVE, "themes", aBuf, sizeof(aBuf));
|
||||
Storage()->CreateFolder("themes", IStorage::TYPE_SAVE);
|
||||
if(!open_file(aBuf))
|
||||
{
|
||||
dbg_msg("menus", "couldn't open file '%s'", aBuf);
|
||||
}
|
||||
Client()->ViewFile(aBuf);
|
||||
}
|
||||
GameClient()->m_Tooltips.DoToolTip(&s_ThemesButtonId, &DirectoryButton, Localize("Open the directory to add custom themes"));
|
||||
|
||||
|
@ -938,11 +929,7 @@ void CMenus::RenderSettingsTee(CUIRect MainView)
|
|||
static CButtonContainer s_SkinDatabaseButton;
|
||||
if(DoButton_Menu(&s_SkinDatabaseButton, Localize("Skin Database"), 0, &DatabaseButton))
|
||||
{
|
||||
const char *pLink = "https://ddnet.org/skins/";
|
||||
if(!open_link(pLink))
|
||||
{
|
||||
dbg_msg("menus", "couldn't open link '%s'", pLink);
|
||||
}
|
||||
Client()->ViewLink("https://ddnet.org/skins/");
|
||||
}
|
||||
|
||||
static CButtonContainer s_DirectoryButton;
|
||||
|
@ -950,10 +937,7 @@ void CMenus::RenderSettingsTee(CUIRect MainView)
|
|||
{
|
||||
Storage()->GetCompletePath(IStorage::TYPE_SAVE, "skins", aBuf, sizeof(aBuf));
|
||||
Storage()->CreateFolder("skins", IStorage::TYPE_SAVE);
|
||||
if(!open_file(aBuf))
|
||||
{
|
||||
dbg_msg("menus", "couldn't open file '%s'", aBuf);
|
||||
}
|
||||
Client()->ViewFile(aBuf);
|
||||
}
|
||||
GameClient()->m_Tooltips.DoToolTip(&s_DirectoryButton, &DirectoryButton, Localize("Open the directory to add custom skins"));
|
||||
|
||||
|
|
|
@ -648,10 +648,7 @@ void CMenus::RenderSettingsCustom(CUIRect MainView)
|
|||
Storage()->GetCompletePath(IStorage::TYPE_SAVE, aBufFull, aBuf, sizeof(aBuf));
|
||||
Storage()->CreateFolder("assets", IStorage::TYPE_SAVE);
|
||||
Storage()->CreateFolder(aBufFull, IStorage::TYPE_SAVE);
|
||||
if(!open_file(aBuf))
|
||||
{
|
||||
dbg_msg("menus", "couldn't open file '%s'", aBuf);
|
||||
}
|
||||
Client()->ViewFile(aBuf);
|
||||
}
|
||||
GameClient()->m_Tooltips.DoToolTip(&s_AssetsDirId, &DirectoryButton, Localize("Open the directory to add custom assets"));
|
||||
|
||||
|
|
|
@ -43,11 +43,7 @@ void CMenus::RenderStartMenu(CUIRect MainView)
|
|||
static CButtonContainer s_DiscordButton;
|
||||
if(DoButton_Menu(&s_DiscordButton, Localize("Discord"), 0, &Button, 0, IGraphics::CORNER_ALL, 5.0f, 0.0f, ColorRGBA(0.0f, 0.0f, 0.0f, 0.25f)))
|
||||
{
|
||||
const char *pLink = Localize("https://ddnet.org/discord");
|
||||
if(!open_link(pLink))
|
||||
{
|
||||
dbg_msg("menus", "couldn't open link '%s'", pLink);
|
||||
}
|
||||
Client()->ViewLink(Localize("https://ddnet.org/discord"));
|
||||
}
|
||||
|
||||
ExtMenu.HSplitBottom(5.0f, &ExtMenu, 0); // little space
|
||||
|
@ -55,11 +51,7 @@ void CMenus::RenderStartMenu(CUIRect MainView)
|
|||
static CButtonContainer s_LearnButton;
|
||||
if(DoButton_Menu(&s_LearnButton, Localize("Learn"), 0, &Button, 0, IGraphics::CORNER_ALL, 5.0f, 0.0f, ColorRGBA(0.0f, 0.0f, 0.0f, 0.25f)))
|
||||
{
|
||||
const char *pLink = Localize("https://wiki.ddnet.org/");
|
||||
if(!open_link(pLink))
|
||||
{
|
||||
dbg_msg("menus", "couldn't open link '%s'", pLink);
|
||||
}
|
||||
Client()->ViewLink(Localize("https://wiki.ddnet.org/"));
|
||||
}
|
||||
|
||||
ExtMenu.HSplitBottom(5.0f, &ExtMenu, 0); // little space
|
||||
|
@ -96,11 +88,7 @@ void CMenus::RenderStartMenu(CUIRect MainView)
|
|||
static CButtonContainer s_WebsiteButton;
|
||||
if(DoButton_Menu(&s_WebsiteButton, Localize("Website"), 0, &Button, 0, IGraphics::CORNER_ALL, 5.0f, 0.0f, ColorRGBA(0.0f, 0.0f, 0.0f, 0.25f)))
|
||||
{
|
||||
const char *pLink = "https://ddnet.org/";
|
||||
if(!open_link(pLink))
|
||||
{
|
||||
dbg_msg("menus", "couldn't open link '%s'", pLink);
|
||||
}
|
||||
Client()->ViewLink("https://ddnet.org/");
|
||||
}
|
||||
|
||||
ExtMenu.HSplitBottom(5.0f, &ExtMenu, 0); // little space
|
||||
|
|
|
@ -5396,7 +5396,7 @@ void CEditor::RenderFileDialog()
|
|||
{
|
||||
char aOpenPath[IO_MAX_PATH_LENGTH];
|
||||
Storage()->GetCompletePath(m_FilesSelectedIndex >= 0 ? m_vpFilteredFileList[m_FilesSelectedIndex]->m_StorageType : IStorage::TYPE_SAVE, m_pFileDialogPath, aOpenPath, sizeof(aOpenPath));
|
||||
if(!open_file(aOpenPath))
|
||||
if(!Client()->ViewFile(aOpenPath))
|
||||
{
|
||||
ShowFileDialogError("Failed to open the directory '%s'.", aOpenPath);
|
||||
}
|
||||
|
@ -7712,7 +7712,7 @@ void CEditor::RenderMenubar(CUIRect MenuBar)
|
|||
if(DoButton_Editor(&s_HelpButton, "?", 0, &Help, 0, "[F1] Open the DDNet Wiki page for the Map Editor in a web browser") || (Input()->KeyPress(KEY_F1) && m_Dialog == DIALOG_NONE && CLineInput::GetActiveInput() == nullptr))
|
||||
{
|
||||
const char *pLink = Localize("https://wiki.ddnet.org/wiki/Mapping");
|
||||
if(!open_link(pLink))
|
||||
if(!Client()->ViewLink(pLink))
|
||||
{
|
||||
ShowFileDialogError("Failed to open the link '%s' in the default web browser.", pLink);
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue