mirror of
https://github.com/shadps4-emu/ext-SDL.git
synced 2025-02-25 13:10:30 +00:00
Handle all Android lifecycle events on the main thread
This restructuring also allows us to wait efficiently in SDL_WaitEvent() on Android
This commit is contained in:
parent
a7c0192017
commit
c601120883
@ -404,8 +404,10 @@ static jobject javaAssetManagerRef = 0;
|
||||
static SDL_AtomicInt bAllowRecreateActivity;
|
||||
|
||||
static SDL_Mutex *Android_ActivityMutex = NULL;
|
||||
SDL_Semaphore *Android_PauseSem = NULL;
|
||||
SDL_Semaphore *Android_ResumeSem = NULL;
|
||||
static SDL_Mutex *Android_LifecycleMutex = NULL;
|
||||
static SDL_Semaphore *Android_LifecycleEventSem = NULL;
|
||||
static SDL_AndroidLifecycleEvent Android_LifecycleEvents[SDL_NUM_ANDROID_LIFECYCLE_EVENTS];
|
||||
static int Android_NumLifecycleEvents;
|
||||
|
||||
/*******************************************************************************
|
||||
Functions called by JNI
|
||||
@ -614,14 +616,14 @@ JNIEXPORT void JNICALL SDL_JAVA_INTERFACE(nativeSetupJNI)(JNIEnv *env, jclass cl
|
||||
__android_log_print(ANDROID_LOG_ERROR, "SDL", "failed to create Android_ActivityMutex mutex");
|
||||
}
|
||||
|
||||
Android_PauseSem = SDL_CreateSemaphore(0);
|
||||
if (!Android_PauseSem) {
|
||||
__android_log_print(ANDROID_LOG_ERROR, "SDL", "failed to create Android_PauseSem semaphore");
|
||||
Android_LifecycleMutex = SDL_CreateMutex();
|
||||
if (!Android_LifecycleMutex) {
|
||||
__android_log_print(ANDROID_LOG_ERROR, "SDL", "failed to create Android_LifecycleMutex mutex");
|
||||
}
|
||||
|
||||
Android_ResumeSem = SDL_CreateSemaphore(0);
|
||||
if (!Android_ResumeSem) {
|
||||
__android_log_print(ANDROID_LOG_ERROR, "SDL", "failed to create Android_ResumeSem semaphore");
|
||||
Android_LifecycleEventSem = SDL_CreateSemaphore(0);
|
||||
if (!Android_LifecycleEventSem) {
|
||||
__android_log_print(ANDROID_LOG_ERROR, "SDL", "failed to create Android_LifecycleEventSem semaphore");
|
||||
}
|
||||
|
||||
mActivityClass = (jclass)((*env)->NewGlobalRef(env, cls));
|
||||
@ -895,18 +897,101 @@ JNIEXPORT int JNICALL SDL_JAVA_INTERFACE(nativeRunMain)(JNIEnv *env, jclass cls,
|
||||
return status;
|
||||
}
|
||||
|
||||
/* Drop file */
|
||||
JNIEXPORT void JNICALL SDL_JAVA_INTERFACE(onNativeDropFile)(
|
||||
JNIEnv *env, jclass jcls,
|
||||
jstring filename)
|
||||
static int FindLifecycleEvent(SDL_AndroidLifecycleEvent event)
|
||||
{
|
||||
const char *path = (*env)->GetStringUTFChars(env, filename, NULL);
|
||||
SDL_SendDropFile(NULL, NULL, path);
|
||||
(*env)->ReleaseStringUTFChars(env, filename, path);
|
||||
SDL_SendDropComplete(NULL);
|
||||
for (int index = 0; index < Android_NumLifecycleEvents; ++index) {
|
||||
if (Android_LifecycleEvents[index] == event) {
|
||||
return index;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
static void RemoveLifecycleEvent(int index)
|
||||
{
|
||||
if (index < Android_NumLifecycleEvents - 1) {
|
||||
SDL_memcpy(&Android_LifecycleEvents[index], &Android_LifecycleEvents[index+1], (Android_NumLifecycleEvents - index - 1) * sizeof(Android_LifecycleEvents[index]));
|
||||
}
|
||||
--Android_NumLifecycleEvents;
|
||||
}
|
||||
|
||||
void Android_SendLifecycleEvent(SDL_AndroidLifecycleEvent event)
|
||||
{
|
||||
SDL_LockMutex(Android_LifecycleMutex);
|
||||
{
|
||||
int index;
|
||||
SDL_bool add_event = SDL_TRUE;
|
||||
|
||||
switch (event) {
|
||||
case SDL_ANDROID_LIFECYCLE_WAKE:
|
||||
// We don't need more than one wake queued
|
||||
index = FindLifecycleEvent(SDL_ANDROID_LIFECYCLE_WAKE);
|
||||
if (index >= 0) {
|
||||
add_event = SDL_FALSE;
|
||||
}
|
||||
break;
|
||||
case SDL_ANDROID_LIFECYCLE_PAUSE:
|
||||
// If we have a resume queued, just stay in the paused state
|
||||
index = FindLifecycleEvent(SDL_ANDROID_LIFECYCLE_RESUME);
|
||||
if (index >= 0) {
|
||||
RemoveLifecycleEvent(index);
|
||||
add_event = SDL_FALSE;
|
||||
}
|
||||
break;
|
||||
case SDL_ANDROID_LIFECYCLE_RESUME:
|
||||
// If we have a pause queued, just stay in the resumed state
|
||||
index = FindLifecycleEvent(SDL_ANDROID_LIFECYCLE_PAUSE);
|
||||
if (index >= 0) {
|
||||
RemoveLifecycleEvent(index);
|
||||
add_event = SDL_FALSE;
|
||||
}
|
||||
break;
|
||||
case SDL_ANDROID_LIFECYCLE_LOWMEMORY:
|
||||
// We don't need more than one low memory event queued
|
||||
index = FindLifecycleEvent(SDL_ANDROID_LIFECYCLE_LOWMEMORY);
|
||||
if (index >= 0) {
|
||||
add_event = SDL_FALSE;
|
||||
}
|
||||
break;
|
||||
case SDL_ANDROID_LIFECYCLE_DESTROY:
|
||||
// Remove all other events, we're done!
|
||||
while (Android_NumLifecycleEvents > 0) {
|
||||
RemoveLifecycleEvent(0);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
SDL_assert(!"Sending unexpected lifecycle event");
|
||||
add_event = SDL_FALSE;
|
||||
break;
|
||||
}
|
||||
|
||||
if (add_event) {
|
||||
SDL_assert(Android_NumLifecycleEvents < SDL_arraysize(Android_LifecycleEvents));
|
||||
Android_LifecycleEvents[Android_NumLifecycleEvents++] = event;
|
||||
SDL_SignalSemaphore(Android_LifecycleEventSem);
|
||||
}
|
||||
}
|
||||
SDL_UnlockMutex(Android_LifecycleMutex);
|
||||
}
|
||||
|
||||
SDL_bool Android_WaitLifecycleEvent(SDL_AndroidLifecycleEvent *event, Sint64 timeoutNS)
|
||||
{
|
||||
SDL_bool got_event = SDL_FALSE;
|
||||
|
||||
while (!got_event && SDL_WaitSemaphoreTimeoutNS(Android_LifecycleEventSem, timeoutNS) == 0) {
|
||||
SDL_LockMutex(Android_LifecycleMutex);
|
||||
{
|
||||
if (Android_NumLifecycleEvents > 0) {
|
||||
*event = Android_LifecycleEvents[0];
|
||||
RemoveLifecycleEvent(0);
|
||||
got_event = SDL_TRUE;
|
||||
}
|
||||
}
|
||||
SDL_UnlockMutex(Android_LifecycleMutex);
|
||||
}
|
||||
return got_event;
|
||||
}
|
||||
|
||||
/* Lock / Unlock Mutex */
|
||||
void Android_LockActivityMutex(void)
|
||||
{
|
||||
SDL_LockMutex(Android_ActivityMutex);
|
||||
@ -917,24 +1002,15 @@ void Android_UnlockActivityMutex(void)
|
||||
SDL_UnlockMutex(Android_ActivityMutex);
|
||||
}
|
||||
|
||||
/* Lock the Mutex when the Activity is in its 'Running' state */
|
||||
void Android_LockActivityMutexOnceRunning(void)
|
||||
/* Drop file */
|
||||
JNIEXPORT void JNICALL SDL_JAVA_INTERFACE(onNativeDropFile)(
|
||||
JNIEnv *env, jclass jcls,
|
||||
jstring filename)
|
||||
{
|
||||
int pauseSignaled = 0;
|
||||
int resumeSignaled = 0;
|
||||
|
||||
retry:
|
||||
|
||||
SDL_LockMutex(Android_ActivityMutex);
|
||||
|
||||
pauseSignaled = SDL_GetSemaphoreValue(Android_PauseSem);
|
||||
resumeSignaled = SDL_GetSemaphoreValue(Android_ResumeSem);
|
||||
|
||||
if (pauseSignaled > resumeSignaled) {
|
||||
SDL_UnlockMutex(Android_ActivityMutex);
|
||||
SDL_Delay(50);
|
||||
goto retry;
|
||||
}
|
||||
const char *path = (*env)->GetStringUTFChars(env, filename, NULL);
|
||||
SDL_SendDropFile(NULL, NULL, path);
|
||||
(*env)->ReleaseStringUTFChars(env, filename, path);
|
||||
SDL_SendDropComplete(NULL);
|
||||
}
|
||||
|
||||
/* Set screen resolution */
|
||||
@ -1335,7 +1411,7 @@ JNIEXPORT void JNICALL SDL_JAVA_INTERFACE(onNativeClipboardChanged)(
|
||||
JNIEXPORT void JNICALL SDL_JAVA_INTERFACE(nativeLowMemory)(
|
||||
JNIEnv *env, jclass cls)
|
||||
{
|
||||
SDL_SendAppEvent(SDL_EVENT_LOW_MEMORY);
|
||||
Android_SendLifecycleEvent(SDL_ANDROID_LIFECYCLE_LOWMEMORY);
|
||||
}
|
||||
|
||||
/* Locale
|
||||
@ -1357,20 +1433,7 @@ JNIEXPORT void JNICALL SDL_JAVA_INTERFACE(onNativeDarkModeChanged)(
|
||||
JNIEXPORT void JNICALL SDL_JAVA_INTERFACE(nativeSendQuit)(
|
||||
JNIEnv *env, jclass cls)
|
||||
{
|
||||
/* Discard previous events. The user should have handled state storage
|
||||
* in SDL_EVENT_WILL_ENTER_BACKGROUND. After nativeSendQuit() is called, no
|
||||
* events other than SDL_EVENT_QUIT and SDL_EVENT_TERMINATING should fire */
|
||||
SDL_FlushEvents(SDL_EVENT_FIRST, SDL_EVENT_LAST);
|
||||
/* Inject a SDL_EVENT_QUIT event */
|
||||
SDL_SendQuit();
|
||||
SDL_SendAppEvent(SDL_EVENT_TERMINATING);
|
||||
/* Robustness: clear any pending Pause */
|
||||
while (SDL_TryWaitSemaphore(Android_PauseSem) == 0) {
|
||||
/* empty */
|
||||
}
|
||||
/* Resume the event loop so that the app can catch SDL_EVENT_QUIT which
|
||||
* should now be the top event in the event queue. */
|
||||
SDL_SignalSemaphore(Android_ResumeSem);
|
||||
Android_SendLifecycleEvent(SDL_ANDROID_LIFECYCLE_DESTROY);
|
||||
}
|
||||
|
||||
/* Activity ends */
|
||||
@ -1384,16 +1447,18 @@ JNIEXPORT void JNICALL SDL_JAVA_INTERFACE(nativeQuit)(
|
||||
Android_ActivityMutex = NULL;
|
||||
}
|
||||
|
||||
if (Android_PauseSem) {
|
||||
SDL_DestroySemaphore(Android_PauseSem);
|
||||
Android_PauseSem = NULL;
|
||||
if (Android_LifecycleMutex) {
|
||||
SDL_DestroyMutex(Android_LifecycleMutex);
|
||||
Android_LifecycleMutex = NULL;
|
||||
}
|
||||
|
||||
if (Android_ResumeSem) {
|
||||
SDL_DestroySemaphore(Android_ResumeSem);
|
||||
Android_ResumeSem = NULL;
|
||||
if (Android_LifecycleEventSem) {
|
||||
SDL_DestroySemaphore(Android_LifecycleEventSem);
|
||||
Android_LifecycleEventSem = NULL;
|
||||
}
|
||||
|
||||
Android_NumLifecycleEvents = 0;
|
||||
|
||||
Internal_Android_Destroy_AssetManager();
|
||||
|
||||
str = SDL_GetError();
|
||||
@ -1410,9 +1475,7 @@ JNIEXPORT void JNICALL SDL_JAVA_INTERFACE(nativePause)(
|
||||
{
|
||||
__android_log_print(ANDROID_LOG_VERBOSE, "SDL", "nativePause()");
|
||||
|
||||
/* Signal the pause semaphore so the event loop knows to pause and (optionally) block itself.
|
||||
* Sometimes 2 pauses can be queued (eg pause/resume/pause), so it's always increased. */
|
||||
SDL_SignalSemaphore(Android_PauseSem);
|
||||
Android_SendLifecycleEvent(SDL_ANDROID_LIFECYCLE_PAUSE);
|
||||
}
|
||||
|
||||
/* Resume */
|
||||
@ -1421,11 +1484,7 @@ JNIEXPORT void JNICALL SDL_JAVA_INTERFACE(nativeResume)(
|
||||
{
|
||||
__android_log_print(ANDROID_LOG_VERBOSE, "SDL", "nativeResume()");
|
||||
|
||||
/* Signal the resume semaphore so the event loop knows to resume and restore the GL Context
|
||||
* We can't restore the GL Context here because it needs to be done on the SDL main thread
|
||||
* and this function will be called from the Java thread instead.
|
||||
*/
|
||||
SDL_SignalSemaphore(Android_ResumeSem);
|
||||
Android_SendLifecycleEvent(SDL_ANDROID_LIFECYCLE_RESUME);
|
||||
}
|
||||
|
||||
JNIEXPORT void JNICALL SDL_JAVA_INTERFACE(nativeFocusChanged)(
|
||||
|
@ -20,6 +20,9 @@
|
||||
*/
|
||||
#include "SDL_internal.h"
|
||||
|
||||
#ifndef SDL_android_h
|
||||
#define SDL_android_h
|
||||
|
||||
/* Set up for C function definitions, even when using C++ */
|
||||
#ifdef __cplusplus
|
||||
/* *INDENT-OFF* */
|
||||
@ -35,6 +38,23 @@ extern "C" {
|
||||
// this appears to be broken right now (on Android, not SDL, I think...?).
|
||||
#define ALLOW_MULTIPLE_ANDROID_AUDIO_DEVICES 0
|
||||
|
||||
/* Life cycle */
|
||||
typedef enum
|
||||
{
|
||||
SDL_ANDROID_LIFECYCLE_WAKE,
|
||||
SDL_ANDROID_LIFECYCLE_PAUSE,
|
||||
SDL_ANDROID_LIFECYCLE_RESUME,
|
||||
SDL_ANDROID_LIFECYCLE_LOWMEMORY,
|
||||
SDL_ANDROID_LIFECYCLE_DESTROY,
|
||||
SDL_NUM_ANDROID_LIFECYCLE_EVENTS
|
||||
} SDL_AndroidLifecycleEvent;
|
||||
|
||||
void Android_SendLifecycleEvent(SDL_AndroidLifecycleEvent event);
|
||||
SDL_bool Android_WaitLifecycleEvent(SDL_AndroidLifecycleEvent *event, Sint64 timeoutNS);
|
||||
|
||||
void Android_LockActivityMutex(void);
|
||||
void Android_UnlockActivityMutex(void);
|
||||
|
||||
/* Interface from the SDL library into the Android Java activity */
|
||||
extern void Android_JNI_SetActivityTitle(const char *title);
|
||||
extern void Android_JNI_SetWindowStyle(SDL_bool fullscreen);
|
||||
@ -111,9 +131,6 @@ int Android_JNI_GetLocale(char *buf, size_t buflen);
|
||||
/* Generic messages */
|
||||
int Android_JNI_SendMessage(int command, int param);
|
||||
|
||||
/* Init */
|
||||
JNIEXPORT void JNICALL SDL_Android_Init(JNIEnv *mEnv, jclass cls);
|
||||
|
||||
/* MessageBox */
|
||||
int Android_JNI_ShowMessageBox(const SDL_MessageBoxData *messageboxdata, int *buttonID);
|
||||
|
||||
@ -139,22 +156,16 @@ SDL_bool SDL_IsAndroidTV(void);
|
||||
SDL_bool SDL_IsChromebook(void);
|
||||
SDL_bool SDL_IsDeXMode(void);
|
||||
|
||||
void Android_LockActivityMutex(void);
|
||||
void Android_UnlockActivityMutex(void);
|
||||
void Android_LockActivityMutexOnceRunning(void);
|
||||
|
||||
/* File Dialogs */
|
||||
SDL_bool Android_JNI_OpenFileDialog(SDL_DialogFileCallback callback, void* userdata,
|
||||
const SDL_DialogFileFilter *filters, int nfilters, SDL_bool forwrite,
|
||||
SDL_bool multiple);
|
||||
|
||||
/* Semaphores for event state processing */
|
||||
extern SDL_Semaphore *Android_PauseSem;
|
||||
extern SDL_Semaphore *Android_ResumeSem;
|
||||
|
||||
/* Ends C function definitions when using C++ */
|
||||
#ifdef __cplusplus
|
||||
/* *INDENT-OFF* */
|
||||
}
|
||||
/* *INDENT-ON* */
|
||||
#endif
|
||||
|
||||
#endif // SDL_android_h
|
||||
|
@ -34,7 +34,11 @@
|
||||
#include "../sensor/SDL_sensor_c.h"
|
||||
#endif
|
||||
#include "../video/SDL_sysvideo.h"
|
||||
|
||||
#ifdef SDL_PLATFORM_ANDROID
|
||||
#include "../core/android/SDL_android.h"
|
||||
#include "../video/android/SDL_androidevents.h"
|
||||
#endif
|
||||
|
||||
/* An arbitrary limit so we don't have unbounded growth */
|
||||
#define SDL_MAX_QUEUED_EVENTS 65535
|
||||
@ -1029,6 +1033,9 @@ static void SDL_CutEvent(SDL_EventEntry *entry)
|
||||
|
||||
static int SDL_SendWakeupEvent(void)
|
||||
{
|
||||
#ifdef SDL_PLATFORM_ANDROID
|
||||
Android_SendLifecycleEvent(SDL_ANDROID_LIFECYCLE_WAKE);
|
||||
#else
|
||||
SDL_VideoDevice *_this = SDL_GetVideoDevice();
|
||||
if (_this == NULL || !_this->SendWakeupEvent) {
|
||||
return 0;
|
||||
@ -1044,6 +1051,7 @@ static int SDL_SendWakeupEvent(void)
|
||||
}
|
||||
}
|
||||
SDL_UnlockMutex(_this->wakeup_lock);
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -1182,7 +1190,7 @@ static void SDL_PumpEventsInternal(SDL_bool push_sentinel)
|
||||
|
||||
#ifdef SDL_PLATFORM_ANDROID
|
||||
/* Android event processing is independent of the video subsystem */
|
||||
Android_PumpEvents();
|
||||
Android_PumpEvents(0);
|
||||
#else
|
||||
/* Get events from the video subsystem */
|
||||
SDL_VideoDevice *_this = SDL_GetVideoDevice();
|
||||
@ -1241,6 +1249,8 @@ SDL_bool SDL_PollEvent(SDL_Event *event)
|
||||
return SDL_WaitEventTimeoutNS(event, 0);
|
||||
}
|
||||
|
||||
#ifndef SDL_PLATFORM_ANDROID
|
||||
|
||||
static Sint64 SDL_events_get_polling_interval(void)
|
||||
{
|
||||
Sint64 poll_intervalNS = SDL_MAX_SINT64;
|
||||
@ -1347,6 +1357,8 @@ static SDL_Window *SDL_find_active_window(SDL_VideoDevice *_this)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#endif // !SDL_PLATFORM_ANDROID
|
||||
|
||||
SDL_bool SDL_WaitEvent(SDL_Event *event)
|
||||
{
|
||||
return SDL_WaitEventTimeoutNS(event, -1);
|
||||
@ -1366,8 +1378,6 @@ SDL_bool SDL_WaitEventTimeout(SDL_Event *event, Sint32 timeoutMS)
|
||||
|
||||
SDL_bool SDL_WaitEventTimeoutNS(SDL_Event *event, Sint64 timeoutNS)
|
||||
{
|
||||
SDL_VideoDevice *_this = SDL_GetVideoDevice();
|
||||
SDL_Window *wakeup_window;
|
||||
Uint64 start, expiration;
|
||||
SDL_bool include_sentinel = (timeoutNS == 0);
|
||||
int result;
|
||||
@ -1420,9 +1430,28 @@ SDL_bool SDL_WaitEventTimeoutNS(SDL_Event *event, Sint64 timeoutNS)
|
||||
/* We should have completely handled timeoutNS == 0 above */
|
||||
SDL_assert(timeoutNS != 0);
|
||||
|
||||
#ifdef SDL_PLATFORM_ANDROID
|
||||
for (;;) {
|
||||
if (SDL_PeepEvents(event, 1, SDL_GETEVENT, SDL_EVENT_FIRST, SDL_EVENT_LAST) > 0) {
|
||||
return SDL_TRUE;
|
||||
}
|
||||
|
||||
Uint64 delay = -1;
|
||||
if (timeoutNS > 0) {
|
||||
Uint64 now = SDL_GetTicksNS();
|
||||
if (now >= expiration) {
|
||||
/* Timeout expired and no events */
|
||||
return SDL_FALSE;
|
||||
}
|
||||
delay = (expiration - now);
|
||||
}
|
||||
Android_PumpEvents(delay);
|
||||
}
|
||||
#else
|
||||
SDL_VideoDevice *_this = SDL_GetVideoDevice();
|
||||
if (_this && _this->WaitEventTimeout && _this->SendWakeupEvent) {
|
||||
/* Look if a shown window is available to send the wakeup event. */
|
||||
wakeup_window = SDL_find_active_window(_this);
|
||||
SDL_Window *wakeup_window = SDL_find_active_window(_this);
|
||||
if (wakeup_window) {
|
||||
result = SDL_WaitEventTimeout_Device(_this, wakeup_window, event, start, timeoutNS);
|
||||
if (result > 0) {
|
||||
@ -1455,6 +1484,7 @@ SDL_bool SDL_WaitEventTimeoutNS(SDL_Event *event, Sint64 timeoutNS)
|
||||
}
|
||||
SDL_DelayNS(delay);
|
||||
}
|
||||
#endif // SDL_PLATFORM_ANDROID
|
||||
}
|
||||
|
||||
static SDL_bool SDL_CallEventWatchers(SDL_Event *event)
|
||||
|
@ -29,6 +29,7 @@
|
||||
|
||||
#ifdef SDL_PLATFORM_ANDROID
|
||||
#include "../core/android/SDL_android.h"
|
||||
#include "../video/android/SDL_androidevents.h"
|
||||
#endif
|
||||
|
||||
/* as a courtesy to iOS apps, we don't try to draw when in the background, as
|
||||
@ -960,17 +961,19 @@ SDL_Renderer *SDL_CreateRendererWithProperties(SDL_PropertiesID props)
|
||||
int i, attempted = 0;
|
||||
SDL_PropertiesID new_props;
|
||||
|
||||
#ifdef SDL_PLATFORM_ANDROID
|
||||
if (Android_WaitActiveAndLockActivity() < 0) {
|
||||
return NULL;
|
||||
}
|
||||
#endif
|
||||
|
||||
SDL_Renderer *renderer = (SDL_Renderer *)SDL_calloc(1, sizeof(*renderer));
|
||||
if (!renderer) {
|
||||
return NULL;
|
||||
goto error;
|
||||
}
|
||||
|
||||
SDL_SetObjectValid(renderer, SDL_OBJECT_TYPE_RENDERER, SDL_TRUE);
|
||||
|
||||
#ifdef SDL_PLATFORM_ANDROID
|
||||
Android_LockActivityMutexOnceRunning();
|
||||
#endif
|
||||
|
||||
if ((!window && !surface) || (window && surface)) {
|
||||
SDL_InvalidParamError("window");
|
||||
goto error;
|
||||
@ -1135,14 +1138,16 @@ SDL_Renderer *SDL_CreateRendererWithProperties(SDL_PropertiesID props)
|
||||
return renderer;
|
||||
|
||||
error:
|
||||
|
||||
SDL_SetObjectValid(renderer, SDL_OBJECT_TYPE_RENDERER, SDL_FALSE);
|
||||
|
||||
#ifdef SDL_PLATFORM_ANDROID
|
||||
Android_UnlockActivityMutex();
|
||||
#endif
|
||||
SDL_free(renderer->texture_formats);
|
||||
SDL_free(renderer);
|
||||
|
||||
if (renderer) {
|
||||
SDL_SetObjectValid(renderer, SDL_OBJECT_TYPE_RENDERER, SDL_FALSE);
|
||||
|
||||
SDL_free(renderer->texture_formats);
|
||||
SDL_free(renderer);
|
||||
}
|
||||
return NULL;
|
||||
|
||||
#else
|
||||
|
@ -82,91 +82,170 @@ static void android_egl_context_backup(SDL_Window *window)
|
||||
* Android_ResumeSem and Android_PauseSem are signaled from Java_org_libsdl_app_SDLActivity_nativePause and Java_org_libsdl_app_SDLActivity_nativeResume
|
||||
*/
|
||||
static SDL_bool Android_EventsInitialized;
|
||||
static SDL_bool Android_BlockOnPause = SDL_TRUE;
|
||||
static SDL_bool Android_Paused;
|
||||
static SDL_bool Android_PausedAudio;
|
||||
static Sint32 Android_PausedWaitTime = -1;
|
||||
static SDL_bool Android_Destroyed;
|
||||
|
||||
void Android_InitEvents(void)
|
||||
{
|
||||
if (!Android_EventsInitialized) {
|
||||
if (SDL_GetHintBoolean(SDL_HINT_ANDROID_BLOCK_ON_PAUSE, SDL_TRUE)) {
|
||||
Android_PausedWaitTime = -1;
|
||||
} else {
|
||||
Android_PausedWaitTime = 100;
|
||||
}
|
||||
Android_BlockOnPause = SDL_GetHintBoolean(SDL_HINT_ANDROID_BLOCK_ON_PAUSE, SDL_TRUE);
|
||||
Android_Paused = SDL_FALSE;
|
||||
Android_Destroyed = SDL_FALSE;
|
||||
Android_EventsInitialized = SDL_TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
void Android_PumpEvents(void)
|
||||
static void Android_OnPause(void)
|
||||
{
|
||||
SDL_OnApplicationWillEnterBackground();
|
||||
SDL_OnApplicationDidEnterBackground();
|
||||
|
||||
/* The semantics are that as soon as the enter background event
|
||||
* has been queued, the app will block. The application should
|
||||
* do any life cycle handling in an event filter while the event
|
||||
* was being queued.
|
||||
*/
|
||||
#ifdef SDL_VIDEO_OPENGL_EGL
|
||||
if (Android_Window && !Android_Window->external_graphics_context) {
|
||||
Android_LockActivityMutex();
|
||||
android_egl_context_backup(Android_Window);
|
||||
Android_UnlockActivityMutex();
|
||||
}
|
||||
#endif
|
||||
|
||||
if (Android_BlockOnPause) {
|
||||
/* We're blocking, also pause audio */
|
||||
ANDROIDAUDIO_PauseDevices();
|
||||
OPENSLES_PauseDevices();
|
||||
AAUDIO_PauseDevices();
|
||||
Android_PausedAudio = SDL_TRUE;
|
||||
}
|
||||
|
||||
Android_Paused = SDL_TRUE;
|
||||
}
|
||||
|
||||
static void Android_OnResume(void)
|
||||
{
|
||||
Android_Paused = SDL_FALSE;
|
||||
|
||||
SDL_OnApplicationWillEnterForeground();
|
||||
|
||||
if (Android_PausedAudio) {
|
||||
ANDROIDAUDIO_ResumeDevices();
|
||||
OPENSLES_ResumeDevices();
|
||||
AAUDIO_ResumeDevices();
|
||||
}
|
||||
|
||||
#ifdef SDL_VIDEO_OPENGL_EGL
|
||||
/* Restore the GL Context from here, as this operation is thread dependent */
|
||||
if (Android_Window && !Android_Window->external_graphics_context && !SDL_HasEvent(SDL_EVENT_QUIT)) {
|
||||
Android_LockActivityMutex();
|
||||
android_egl_context_restore(Android_Window);
|
||||
Android_UnlockActivityMutex();
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Make sure SW Keyboard is restored when an app becomes foreground */
|
||||
if (Android_Window) {
|
||||
Android_RestoreScreenKeyboardOnResume(SDL_GetVideoDevice(), Android_Window);
|
||||
}
|
||||
|
||||
SDL_OnApplicationDidEnterForeground();
|
||||
}
|
||||
|
||||
static void Android_OnLowMemory(void)
|
||||
{
|
||||
SDL_SendAppEvent(SDL_EVENT_LOW_MEMORY);
|
||||
}
|
||||
|
||||
static void Android_OnDestroy(void)
|
||||
{
|
||||
/* Discard previous events. The user should have handled state storage
|
||||
* in SDL_EVENT_WILL_ENTER_BACKGROUND. After nativeSendQuit() is called, no
|
||||
* events other than SDL_EVENT_QUIT and SDL_EVENT_TERMINATING should fire */
|
||||
SDL_FlushEvents(SDL_EVENT_FIRST, SDL_EVENT_LAST);
|
||||
SDL_SendQuit();
|
||||
SDL_SendAppEvent(SDL_EVENT_TERMINATING);
|
||||
|
||||
Android_Destroyed = SDL_TRUE;
|
||||
}
|
||||
|
||||
static void Android_HandleLifecycleEvent(SDL_AndroidLifecycleEvent event)
|
||||
{
|
||||
switch (event) {
|
||||
case SDL_ANDROID_LIFECYCLE_WAKE:
|
||||
// Nothing to do, just return
|
||||
break;
|
||||
case SDL_ANDROID_LIFECYCLE_PAUSE:
|
||||
Android_OnPause();
|
||||
break;
|
||||
case SDL_ANDROID_LIFECYCLE_RESUME:
|
||||
Android_OnResume();
|
||||
break;
|
||||
case SDL_ANDROID_LIFECYCLE_LOWMEMORY:
|
||||
Android_OnLowMemory();
|
||||
break;
|
||||
case SDL_ANDROID_LIFECYCLE_DESTROY:
|
||||
Android_OnDestroy();
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static Sint64 GetLifecycleEventTimeout(SDL_bool paused, Sint64 timeoutNS)
|
||||
{
|
||||
if (Android_Paused) {
|
||||
if (SDL_WaitSemaphoreTimeout(Android_ResumeSem, Android_PausedWaitTime) == 0) {
|
||||
|
||||
Android_Paused = SDL_FALSE;
|
||||
|
||||
/* Android_ResumeSem was signaled */
|
||||
SDL_OnApplicationWillEnterForeground();
|
||||
|
||||
if (Android_PausedAudio) {
|
||||
ANDROIDAUDIO_ResumeDevices();
|
||||
OPENSLES_ResumeDevices();
|
||||
AAUDIO_ResumeDevices();
|
||||
}
|
||||
|
||||
#ifdef SDL_VIDEO_OPENGL_EGL
|
||||
/* Restore the GL Context from here, as this operation is thread dependent */
|
||||
if (Android_Window && !Android_Window->external_graphics_context && !SDL_HasEvent(SDL_EVENT_QUIT)) {
|
||||
Android_LockActivityMutex();
|
||||
android_egl_context_restore(Android_Window);
|
||||
Android_UnlockActivityMutex();
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Make sure SW Keyboard is restored when an app becomes foreground */
|
||||
if (Android_Window) {
|
||||
Android_RestoreScreenKeyboardOnResume(SDL_GetVideoDevice(), Android_Window);
|
||||
}
|
||||
|
||||
SDL_OnApplicationDidEnterForeground();
|
||||
}
|
||||
} else {
|
||||
if (SDL_TryWaitSemaphore(Android_PauseSem) == 0) {
|
||||
|
||||
/* Android_PauseSem was signaled */
|
||||
SDL_OnApplicationWillEnterBackground();
|
||||
SDL_OnApplicationDidEnterBackground();
|
||||
|
||||
/* Make sure we handle potentially multiple pause/resume sequences */
|
||||
while (SDL_GetSemaphoreValue(Android_PauseSem) > 0) {
|
||||
SDL_WaitSemaphore(Android_ResumeSem);
|
||||
SDL_WaitSemaphore(Android_PauseSem);
|
||||
}
|
||||
|
||||
/* The semantics are that as soon as the enter background event
|
||||
* has been queued, the app will block. The application should
|
||||
* do any life cycle handling in an event filter while the event
|
||||
* was being queued.
|
||||
*/
|
||||
#ifdef SDL_VIDEO_OPENGL_EGL
|
||||
if (Android_Window && !Android_Window->external_graphics_context) {
|
||||
Android_LockActivityMutex();
|
||||
android_egl_context_backup(Android_Window);
|
||||
Android_UnlockActivityMutex();
|
||||
}
|
||||
#endif
|
||||
if (Android_PausedWaitTime < 0) {
|
||||
/* We're blocking, also pause audio */
|
||||
ANDROIDAUDIO_PauseDevices();
|
||||
OPENSLES_PauseDevices();
|
||||
AAUDIO_PauseDevices();
|
||||
Android_PausedAudio = SDL_TRUE;
|
||||
}
|
||||
|
||||
Android_Paused = SDL_TRUE;
|
||||
if (Android_BlockOnPause) {
|
||||
timeoutNS = -1;
|
||||
} else if (timeoutNS == 0) {
|
||||
timeoutNS = SDL_MS_TO_NS(100);
|
||||
}
|
||||
}
|
||||
return timeoutNS;
|
||||
}
|
||||
|
||||
void Android_PumpEvents(Sint64 timeoutNS)
|
||||
{
|
||||
SDL_AndroidLifecycleEvent event;
|
||||
SDL_bool paused = Android_Paused;
|
||||
|
||||
while (Android_WaitLifecycleEvent(&event, GetLifecycleEventTimeout(paused, timeoutNS))) {
|
||||
Android_HandleLifecycleEvent(event);
|
||||
|
||||
switch (event) {
|
||||
case SDL_ANDROID_LIFECYCLE_WAKE:
|
||||
// Finish handling events quickly if we're not paused
|
||||
timeoutNS = 0;
|
||||
break;
|
||||
case SDL_ANDROID_LIFECYCLE_PAUSE:
|
||||
// Finish handling events at the current timeout and return to process events one more time before blocking.
|
||||
break;
|
||||
case SDL_ANDROID_LIFECYCLE_RESUME:
|
||||
// Finish handling events at the resume state timeout
|
||||
paused = SDL_FALSE;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int Android_WaitActiveAndLockActivity(void)
|
||||
{
|
||||
while (Android_Paused && !Android_Destroyed) {
|
||||
Android_PumpEvents(-1);
|
||||
}
|
||||
|
||||
if (Android_Destroyed) {
|
||||
SDL_SetError("Android activity has been destroyed");
|
||||
return -1;
|
||||
}
|
||||
|
||||
Android_LockActivityMutex();
|
||||
return 0;
|
||||
}
|
||||
|
||||
void Android_QuitEvents(void)
|
||||
|
@ -20,8 +20,7 @@
|
||||
*/
|
||||
#include "SDL_internal.h"
|
||||
|
||||
#include "SDL_androidvideo.h"
|
||||
|
||||
extern void Android_InitEvents(void);
|
||||
extern void Android_PumpEvents(void);
|
||||
extern void Android_PumpEvents(Sint64 timeoutNS);
|
||||
extern int Android_WaitActiveAndLockActivity(void);
|
||||
extern void Android_QuitEvents(void);
|
||||
|
@ -28,6 +28,7 @@
|
||||
#include "SDL_androidwindow.h"
|
||||
|
||||
#include "SDL_androidvideo.h"
|
||||
#include "SDL_androidevents.h"
|
||||
#include "SDL_androidgl.h"
|
||||
#include "../../core/android/SDL_android.h"
|
||||
|
||||
@ -48,7 +49,9 @@ SDL_GLContext Android_GLES_CreateContext(SDL_VideoDevice *_this, SDL_Window *win
|
||||
{
|
||||
SDL_GLContext ret;
|
||||
|
||||
Android_LockActivityMutexOnceRunning();
|
||||
if (Android_WaitActiveAndLockActivity() < 0) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ret = SDL_EGL_CreateContext(_this, window->internal->egl_surface);
|
||||
|
||||
|
@ -29,6 +29,7 @@
|
||||
#include "../../core/android/SDL_android.h"
|
||||
|
||||
#include "SDL_androidvideo.h"
|
||||
#include "SDL_androidevents.h"
|
||||
#include "SDL_androidwindow.h"
|
||||
|
||||
|
||||
@ -40,7 +41,9 @@ int Android_CreateWindow(SDL_VideoDevice *_this, SDL_Window *window, SDL_Propert
|
||||
SDL_WindowData *data;
|
||||
int retval = 0;
|
||||
|
||||
Android_LockActivityMutexOnceRunning();
|
||||
if (Android_WaitActiveAndLockActivity() < 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (Android_Window) {
|
||||
retval = SDL_SetError("Android only supports one window");
|
||||
|
Loading…
x
Reference in New Issue
Block a user