summaryrefslogtreecommitdiff
path: root/contrib/SDL-3.2.8/src/video/android/SDL_androidevents.c
diff options
context:
space:
mode:
author3gg <3gg@shellblade.net>2025-12-27 12:03:39 -0800
committer3gg <3gg@shellblade.net>2025-12-27 12:03:39 -0800
commit5a079a2d114f96d4847d1ee305d5b7c16eeec50e (patch)
tree8926ab44f168acf787d8e19608857b3af0f82758 /contrib/SDL-3.2.8/src/video/android/SDL_androidevents.c
Initial commit
Diffstat (limited to 'contrib/SDL-3.2.8/src/video/android/SDL_androidevents.c')
-rw-r--r--contrib/SDL-3.2.8/src/video/android/SDL_androidevents.c269
1 files changed, 269 insertions, 0 deletions
diff --git a/contrib/SDL-3.2.8/src/video/android/SDL_androidevents.c b/contrib/SDL-3.2.8/src/video/android/SDL_androidevents.c
new file mode 100644
index 0000000..e32d272
--- /dev/null
+++ b/contrib/SDL-3.2.8/src/video/android/SDL_androidevents.c
@@ -0,0 +1,269 @@
1/*
2 Simple DirectMedia Layer
3 Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
4
5 This software is provided 'as-is', without any express or implied
6 warranty. In no event will the authors be held liable for any damages
7 arising from the use of this software.
8
9 Permission is granted to anyone to use this software for any purpose,
10 including commercial applications, and to alter it and redistribute it
11 freely, subject to the following restrictions:
12
13 1. The origin of this software must not be misrepresented; you must not
14 claim that you wrote the original software. If you use this software
15 in a product, an acknowledgment in the product documentation would be
16 appreciated but is not required.
17 2. Altered source versions must be plainly marked as such, and must not be
18 misrepresented as being the original software.
19 3. This notice may not be removed or altered from any source distribution.
20*/
21#include "SDL_internal.h"
22
23#ifdef SDL_VIDEO_DRIVER_ANDROID
24
25#include "SDL_androidevents.h"
26#include "SDL_androidkeyboard.h"
27#include "SDL_androidwindow.h"
28#include "../SDL_sysvideo.h"
29#include "../../events/SDL_events_c.h"
30
31#include "../../audio/aaudio/SDL_aaudio.h"
32#include "../../audio/openslES/SDL_openslES.h"
33
34
35#ifdef SDL_VIDEO_OPENGL_EGL
36static void android_egl_context_restore(SDL_Window *window)
37{
38 if (window) {
39 SDL_WindowData *data = window->internal;
40 SDL_GL_MakeCurrent(window, NULL);
41 if (!SDL_GL_MakeCurrent(window, (SDL_GLContext)data->egl_context)) {
42 // The context is no longer valid, create a new one
43 data->egl_context = (EGLContext)SDL_GL_CreateContext(window);
44 SDL_GL_MakeCurrent(window, (SDL_GLContext)data->egl_context);
45 SDL_Event event;
46 SDL_zero(event);
47 event.type = SDL_EVENT_RENDER_DEVICE_RESET;
48 event.render.windowID = SDL_GetWindowID(window);
49 SDL_PushEvent(&event);
50 }
51 data->backup_done = false;
52
53 if (data->has_swap_interval) {
54 SDL_GL_SetSwapInterval(data->swap_interval);
55 }
56
57 }
58}
59
60static void android_egl_context_backup(SDL_Window *window)
61{
62 if (window) {
63 int interval = 0;
64 // Keep a copy of the EGL Context so we can try to restore it when we resume
65 SDL_WindowData *data = window->internal;
66 data->egl_context = SDL_GL_GetCurrentContext();
67
68 // Save/Restore the swap interval / vsync
69 if (SDL_GL_GetSwapInterval(&interval)) {
70 data->has_swap_interval = 1;
71 data->swap_interval = interval;
72 }
73
74 // We need to do this so the EGLSurface can be freed
75 SDL_GL_MakeCurrent(window, NULL);
76 data->backup_done = true;
77 }
78}
79#endif
80
81/*
82 * Android_ResumeSem and Android_PauseSem are signaled from Java_org_libsdl_app_SDLActivity_nativePause and Java_org_libsdl_app_SDLActivity_nativeResume
83 */
84static bool Android_EventsInitialized;
85static bool Android_BlockOnPause = true;
86static bool Android_Paused;
87static bool Android_PausedAudio;
88static bool Android_Destroyed;
89
90void Android_InitEvents(void)
91{
92 if (!Android_EventsInitialized) {
93 Android_BlockOnPause = SDL_GetHintBoolean(SDL_HINT_ANDROID_BLOCK_ON_PAUSE, true);
94 Android_Paused = false;
95 Android_Destroyed = false;
96 Android_EventsInitialized = true;
97 }
98}
99
100static void Android_PauseAudio(void)
101{
102 OPENSLES_PauseDevices();
103 AAUDIO_PauseDevices();
104 Android_PausedAudio = true;
105}
106
107static void Android_ResumeAudio(void)
108{
109 if (Android_PausedAudio) {
110 OPENSLES_ResumeDevices();
111 AAUDIO_ResumeDevices();
112 Android_PausedAudio = false;
113 }
114}
115
116static void Android_OnPause(void)
117{
118 SDL_OnApplicationWillEnterBackground();
119 SDL_OnApplicationDidEnterBackground();
120
121 /* The semantics are that as soon as the enter background event
122 * has been queued, the app will block. The application should
123 * do any life cycle handling in an event filter while the event
124 * was being queued.
125 */
126#ifdef SDL_VIDEO_OPENGL_EGL
127 if (Android_Window && !Android_Window->external_graphics_context) {
128 Android_LockActivityMutex();
129 android_egl_context_backup(Android_Window);
130 Android_UnlockActivityMutex();
131 }
132#endif
133
134 if (Android_BlockOnPause) {
135 // We're blocking, also pause audio
136 Android_PauseAudio();
137 }
138
139 Android_Paused = true;
140}
141
142static void Android_OnResume(void)
143{
144 Android_Paused = false;
145
146 SDL_OnApplicationWillEnterForeground();
147
148 Android_ResumeAudio();
149
150#ifdef SDL_VIDEO_OPENGL_EGL
151 // Restore the GL Context from here, as this operation is thread dependent
152 if (Android_Window && !Android_Window->external_graphics_context && !SDL_HasEvent(SDL_EVENT_QUIT)) {
153 Android_LockActivityMutex();
154 android_egl_context_restore(Android_Window);
155 Android_UnlockActivityMutex();
156 }
157#endif
158
159 // Make sure SW Keyboard is restored when an app becomes foreground
160 if (Android_Window) {
161 Android_RestoreScreenKeyboardOnResume(SDL_GetVideoDevice(), Android_Window);
162 }
163
164 SDL_OnApplicationDidEnterForeground();
165}
166
167static void Android_OnLowMemory(void)
168{
169 SDL_SendAppEvent(SDL_EVENT_LOW_MEMORY);
170}
171
172static void Android_OnDestroy(void)
173{
174 // Make sure we unblock any audio processing before we quit
175 Android_ResumeAudio();
176
177 /* Discard previous events. The user should have handled state storage
178 * in SDL_EVENT_WILL_ENTER_BACKGROUND. After nativeSendQuit() is called, no
179 * events other than SDL_EVENT_QUIT and SDL_EVENT_TERMINATING should fire */
180 SDL_FlushEvents(SDL_EVENT_FIRST, SDL_EVENT_LAST);
181 SDL_SendQuit();
182 SDL_SendAppEvent(SDL_EVENT_TERMINATING);
183
184 Android_Destroyed = true;
185}
186
187static void Android_HandleLifecycleEvent(SDL_AndroidLifecycleEvent event)
188{
189 switch (event) {
190 case SDL_ANDROID_LIFECYCLE_WAKE:
191 // Nothing to do, just return
192 break;
193 case SDL_ANDROID_LIFECYCLE_PAUSE:
194 Android_OnPause();
195 break;
196 case SDL_ANDROID_LIFECYCLE_RESUME:
197 Android_OnResume();
198 break;
199 case SDL_ANDROID_LIFECYCLE_LOWMEMORY:
200 Android_OnLowMemory();
201 break;
202 case SDL_ANDROID_LIFECYCLE_DESTROY:
203 Android_OnDestroy();
204 break;
205 default:
206 break;
207 }
208}
209
210static Sint64 GetLifecycleEventTimeout(bool paused, Sint64 timeoutNS)
211{
212 if (Android_Paused) {
213 if (Android_BlockOnPause) {
214 timeoutNS = -1;
215 } else if (timeoutNS == 0) {
216 timeoutNS = SDL_MS_TO_NS(100);
217 }
218 }
219 return timeoutNS;
220}
221
222void Android_PumpEvents(Sint64 timeoutNS)
223{
224 SDL_AndroidLifecycleEvent event;
225 bool paused = Android_Paused;
226
227 while (!Android_Destroyed &&
228 Android_WaitLifecycleEvent(&event, GetLifecycleEventTimeout(paused, timeoutNS))) {
229 Android_HandleLifecycleEvent(event);
230
231 switch (event) {
232 case SDL_ANDROID_LIFECYCLE_WAKE:
233 // Finish handling events quickly if we're not paused
234 timeoutNS = 0;
235 break;
236 case SDL_ANDROID_LIFECYCLE_PAUSE:
237 // Finish handling events at the current timeout and return to process events one more time before blocking.
238 break;
239 case SDL_ANDROID_LIFECYCLE_RESUME:
240 // Finish handling events at the resume state timeout
241 paused = false;
242 break;
243 default:
244 break;
245 }
246 }
247}
248
249bool Android_WaitActiveAndLockActivity(void)
250{
251 while (Android_Paused && !Android_Destroyed) {
252 Android_PumpEvents(-1);
253 }
254
255 if (Android_Destroyed) {
256 SDL_SetError("Android activity has been destroyed");
257 return false;
258 }
259
260 Android_LockActivityMutex();
261 return true;
262}
263
264void Android_QuitEvents(void)
265{
266 Android_EventsInitialized = false;
267}
268
269#endif // SDL_VIDEO_DRIVER_ANDROID