1/**
2 * Copyright (c) 2006-2023 LOVE Development Team
3 *
4 * This software is provided 'as-is', without any express or implied
5 * warranty. In no event will the authors be held liable for any damages
6 * arising from the use of this software.
7 *
8 * Permission is granted to anyone to use this software for any purpose,
9 * including commercial applications, and to alter it and redistribute it
10 * freely, subject to the following restrictions:
11 *
12 * 1. The origin of this software must not be misrepresented; you must not
13 * claim that you wrote the original software. If you use this software
14 * in a product, an acknowledgment in the product documentation would be
15 * appreciated but is not required.
16 * 2. Altered source versions must be plainly marked as such, and must not be
17 * misrepresented as being the original software.
18 * 3. This notice may not be removed or altered from any source distribution.
19 **/
20
21// LOVE
22#include "common/config.h"
23#include "System.h"
24
25#if defined(LOVE_MACOSX)
26#include <CoreServices/CoreServices.h>
27#elif defined(LOVE_IOS)
28#include "common/ios.h"
29#elif defined(LOVE_LINUX) || defined(LOVE_ANDROID)
30#include <signal.h>
31#include <sys/wait.h>
32#include <errno.h>
33#elif defined(LOVE_WINDOWS)
34#include "common/utf8.h"
35#include <shlobj.h>
36#include <shellapi.h>
37#pragma comment(lib, "shell32.lib")
38#endif
39#if defined(LOVE_ANDROID)
40#include "common/android.h"
41#elif defined(LOVE_LINUX)
42
43#ifdef __has_include
44#if __has_include(<spawn.h>)
45#define LOVE_HAS_POSIX_SPAWN
46#endif
47#endif
48
49#ifdef LOVE_HAS_POSIX_SPAWN
50#include <spawn.h>
51#else
52#include <unistd.h>
53#endif
54#endif
55
56namespace love
57{
58namespace system
59{
60
61System::System()
62{
63}
64
65std::string System::getOS() const
66{
67#if defined(LOVE_MACOSX)
68 return "OS X";
69#elif defined(LOVE_IOS)
70 return "iOS";
71#elif defined(LOVE_WINDOWS_UWP)
72 return "UWP";
73#elif defined(LOVE_WINDOWS)
74 return "Windows";
75#elif defined(LOVE_ANDROID)
76 return "Android";
77#elif defined(LOVE_LINUX)
78 return "Linux";
79#else
80 return "Unknown";
81#endif
82}
83
84#ifdef LOVE_HAS_POSIX_SPAWN
85extern "C"
86{
87 extern char **environ; // The environment, always available
88}
89#endif
90
91bool System::openURL(const std::string &url) const
92{
93
94#if defined(LOVE_MACOSX)
95
96 bool success = false;
97 CFURLRef cfurl = CFURLCreateWithBytes(nullptr,
98 (const UInt8 *) url.c_str(),
99 url.length(),
100 kCFStringEncodingUTF8,
101 nullptr);
102
103 success = LSOpenCFURLRef(cfurl, nullptr) == noErr;
104 CFRelease(cfurl);
105 return success;
106
107#elif defined(LOVE_IOS)
108
109 return love::ios::openURL(url);
110
111#elif defined(LOVE_ANDROID)
112
113 return love::android::openURL(url);
114
115#elif defined(LOVE_LINUX)
116
117 pid_t pid;
118 const char *argv[] = {"xdg-open", url.c_str(), nullptr};
119
120#ifdef LOVE_HAS_POSIX_SPAWN
121 // Note: at the moment this process inherits our file descriptors.
122 // Note: the below const_cast is really ugly as well.
123 if (posix_spawnp(&pid, "xdg-open", nullptr, nullptr, const_cast<char **>(argv), environ) != 0)
124 return false;
125#else
126 pid = fork();
127 if (pid == 0)
128 {
129 execvp("xdg-open", const_cast<char **>(argv));
130 return false;
131 }
132#endif
133
134 // Check if xdg-open already completed (or failed.)
135 int status = 0;
136 if (waitpid(pid, &status, WNOHANG) > 0)
137 return (status == 0);
138 else
139 // We can't tell what actually happens without waiting for
140 // the process to finish, which could take forever (literally).
141 return true;
142
143#elif defined(LOVE_WINDOWS)
144
145 // Unicode-aware WinAPI functions don't accept UTF-8, so we need to convert.
146 std::wstring wurl = to_widestr(url);
147
148 HINSTANCE result = 0;
149
150#if defined(LOVE_WINDOWS_UWP)
151
152 Platform::String^ urlString = ref new Platform::String(wurl.c_str());
153 auto uwpUri = ref new Windows::Foundation::Uri(urlString);
154 Windows::System::Launcher::LaunchUriAsync(uwpUri);
155
156#else
157
158 result = ShellExecuteW(nullptr,
159 L"open",
160 wurl.c_str(),
161 nullptr,
162 nullptr,
163 SW_SHOW);
164
165#endif
166
167 return (ptrdiff_t) result > 32;
168
169#endif
170}
171
172void System::vibrate(double seconds) const
173{
174#ifdef LOVE_ANDROID
175 love::android::vibrate(seconds);
176#elif defined(LOVE_IOS)
177 love::ios::vibrate();
178#else
179 LOVE_UNUSED(seconds);
180#endif
181}
182
183bool System::hasBackgroundMusic() const
184{
185#if defined(LOVE_ANDROID)
186 return love::android::hasBackgroundMusic();
187#elif defined(LOVE_IOS)
188 return love::ios::hasBackgroundMusic();
189#else
190 return false;
191#endif
192}
193
194bool System::getConstant(const char *in, System::PowerState &out)
195{
196 return powerStates.find(in, out);
197}
198
199bool System::getConstant(System::PowerState in, const char *&out)
200{
201 return powerStates.find(in, out);
202}
203
204StringMap<System::PowerState, System::POWER_MAX_ENUM>::Entry System::powerEntries[] =
205{
206 {"unknown", System::POWER_UNKNOWN},
207 {"battery", System::POWER_BATTERY},
208 {"nobattery", System::POWER_NO_BATTERY},
209 {"charging", System::POWER_CHARGING},
210 {"charged", System::POWER_CHARGED},
211};
212
213StringMap<System::PowerState, System::POWER_MAX_ENUM> System::powerStates(System::powerEntries, sizeof(System::powerEntries));
214
215} // system
216} // love
217