Skip to content
This repository has been archived by the owner. It is now read-only.
Permalink
Browse files

Added mobile application events, with implementations for iOS and And…

…roid
  • Loading branch information
slouken committed May 18, 2013
1 parent 06944f7 commit d8d854298c1b9842a4a83ba3ddd11a3cf1a890ce
@@ -54,6 +54,69 @@ Here is a more manual method:
4. Remove the ApplicationDelegate.h and ApplicationDelegate.m files -- SDL for iPhone provides its own UIApplicationDelegate. Remove MainWindow.xib -- SDL for iPhone produces its user interface programmatically.
5. Delete the contents of main.m and program your app as a regular SDL program instead. You may replace main.m with your own main.c, but you must tell XCode not to use the project prefix file, as it includes Objective-C code.

==============================================================================
Notes -- Application events
==============================================================================

On iOS the application goes through a fixed life cycle and you will get
notifications of state changes via application events. When these events
are delivered you must handle them in an event callback because the OS may
not give you any processing time after the events are delivered.

e.g.

int HandleAppEvents(void *userdata, SDL_Event *event)
{
switch (event->type)
{
case SDL_APP_TERMINATING:
/* Terminate the app.
Shut everything down before returning from this function.
*/
return 0;
case SDL_APP_LOWMEMORY:
/* You will get this when your app is paused and iOS wants more memory.
Release as much memory as possible.
*/
return 0;
case SDL_APP_WILLENTERBACKGROUND:
/* Prepare your app to go into the background. Stop loops, etc.
This gets called when the user hits the home button, or gets a call.
*/
return 0;
case SDL_APP_DIDENTERBACKGROUND:
/* This will get called if the user accepted whatever sent your app to the background.
If the user got a phone call and canceled it, you'll instead get an SDL_APP_DIDENTERFOREGROUND event and restart your loops.
When you get this, you have 5 seconds to save all your state or the app will be terminated.
Your app is NOT active at this point.
*/
return 0;
case SDL_APP_WILLENTERFOREGROUND:
/* This call happens when your app is coming back to the foreground.
Restore all your state here.
*/
return 0;
case SDL_APP_DIDENTERFOREGROUND:
/* Restart your loops here.
Your app is interactive and getting CPU again.
*/
return 0;
default:
/* No special processing, add it to the event queue */
return 1;
}
}

int main(int argc, char *argv[])
{
SDL_SetEventFilter(HandleAppEvents, NULL);

... run your main loop

return 0;
}


==============================================================================
Notes -- Accelerometer as Joystick
==============================================================================
@@ -78,17 +78,26 @@ protected void onCreate(Bundle savedInstanceState) {
}

// Events
/*protected void onPause() {
@Override
protected void onPause() {
Log.v("SDL", "onPause()");
super.onPause();
// Don't call SDLActivity.nativePause(); here, it will be called by SDLSurface::surfaceDestroyed
}

@Override
protected void onResume() {
Log.v("SDL", "onResume()");
super.onResume();
// Don't call SDLActivity.nativeResume(); here, it will be called via SDLSurface::surfaceChanged->SDLActivity::startApp
}*/
}

@Override
public void onLowMemory() {
Log.v("SDL", "onLowMemory()");
super.onLowMemory();
SDLActivity.nativeLowMemory();
}

@Override
protected void onDestroy() {
@@ -180,6 +189,7 @@ boolean sendCommand(int command, Object data) {

// C functions we call
public static native void nativeInit();
public static native void nativeLowMemory();
public static native void nativeQuit();
public static native void nativePause();
public static native void nativeResume();
@@ -600,8 +610,6 @@ public void surfaceChanged(SurfaceHolder holder,
public void onDraw(Canvas canvas) {}




// Key events
@Override
public boolean onKey(View v, int keyCode, KeyEvent event) {
@@ -61,6 +61,32 @@ typedef enum
/* Application events */
SDL_QUIT = 0x100, /**< User-requested quit */

/* These application events have special meaning on iOS, see README.iOS for details */
SDL_APP_TERMINATING, /**< The application is being terminated by the OS
Called on iOS in applicationWillTerminate()
Called on Android in onDestroy()
*/
SDL_APP_LOWMEMORY, /**< The application is low on memory, free memory if possible.
Called on iOS in applicationDidReceiveMemoryWarning()
Called on Android in onLowMemory()
*/
SDL_APP_WILLENTERBACKGROUND, /**< The application is about to enter the background
Called on iOS in applicationWillResignActive()
Called on Android in onPause()
*/
SDL_APP_DIDENTERBACKGROUND, /**< The application did enter the background and may not get CPU for some time
Called on iOS in applicationDidEnterBackground()
Called on Android in onPause()
*/
SDL_APP_WILLENTERFOREGROUND, /**< The application is about to enter the foreground
Called on iOS in applicationWillEnterForeground()
Called on Android in onResume()
*/
SDL_APP_DIDENTERFOREGROUND, /**< The application is now interactive
Called on iOS in applicationDidBecomeActive()
Called on Android in onResume()
*/

/* Window events */
SDL_WINDOWEVENT = 0x200, /**< Window state change */
SDL_SYSWMEVENT, /**< System specific event */
@@ -109,7 +135,7 @@ typedef enum

/* Drag and drop events */
SDL_DROPFILE = 0x1000, /**< The system requests a file open */

/** Events ::SDL_USEREVENT through ::SDL_LASTEVENT are for your use,
* and should be allocated with SDL_RegisterEvents()
*/
@@ -427,6 +453,14 @@ typedef struct SDL_QuitEvent
Uint32 timestamp;
} SDL_QuitEvent;

/**
* \brief OS Specific event
*/
typedef struct SDL_OSEvent
{
Uint32 type; /**< ::SDL_QUIT */
Uint32 timestamp;
} SDL_OSEvent;

/**
* \brief A user-defined event type (event.user.*)
@@ -181,12 +181,20 @@ extern "C" void Java_org_libsdl_app_SDLActivity_onNativeAccel(
bHasNewData = true;
}

// Low memory
extern "C" void Java_org_libsdl_app_SDLActivity_nativeLowMemory(
JNIEnv* env, jclass cls)
{
SDL_SendAppEvent(SDL_APP_LOWMEMORY);
}

// Quit
extern "C" void Java_org_libsdl_app_SDLActivity_nativeQuit(
JNIEnv* env, jclass cls)
{
// Inject a SDL_QUIT event
SDL_SendQuit();
SDL_SendAppEvent(SDL_APP_TERMINATING);
}

// Pause
@@ -199,12 +207,20 @@ extern "C" void Java_org_libsdl_app_SDLActivity_nativePause(
SDL_SendWindowEvent(Android_Window, SDL_WINDOWEVENT_FOCUS_LOST, 0, 0);
SDL_SendWindowEvent(Android_Window, SDL_WINDOWEVENT_MINIMIZED, 0, 0);
}

__android_log_print(ANDROID_LOG_VERBOSE, "SDL", "nativePause()");
SDL_SendAppEvent(SDL_APP_WILLENTERBACKGROUND);
SDL_SendAppEvent(SDL_APP_DIDENTERBACKGROUND);
}

// Resume
extern "C" void Java_org_libsdl_app_SDLActivity_nativeResume(
JNIEnv* env, jclass cls)
{
__android_log_print(ANDROID_LOG_VERBOSE, "SDL", "nativeResume()");
SDL_SendAppEvent(SDL_APP_WILLENTERFOREGROUND);
SDL_SendAppEvent(SDL_APP_DIDENTERFOREGROUND);

if (Android_Window) {
/* 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
@@ -616,7 +632,9 @@ static int Android_JNI_FileOpen(SDL_RWops* ctx)

if (false) {
fallback:
__android_log_print(ANDROID_LOG_DEBUG, "SDL", "Falling back to legacy InputStream method for opening file");
// Disabled log message because of spam on the Nexus 7
//__android_log_print(ANDROID_LOG_DEBUG, "SDL", "Falling back to legacy InputStream method for opening file");

/* Try the old method using InputStream */
ctx->hidden.androidio.assetFileDescriptorRef = NULL;

@@ -111,6 +111,7 @@ SDL_StopEventLoop(void)
SDL_event_watchers = tmp->next;
SDL_free(tmp);
}
SDL_EventOK = NULL;
}

/* This function (and associated calls) may be called more than once */
@@ -133,8 +134,7 @@ SDL_StartEventLoop(void)
}
#endif /* !SDL_THREADS_DISABLED */

/* No filter to start with, process most event types */
SDL_EventOK = NULL;
/* Process most event types */
SDL_EventState(SDL_TEXTINPUT, SDL_DISABLE);
SDL_EventState(SDL_TEXTEDITING, SDL_DISABLE);
SDL_EventState(SDL_SYSWMEVENT, SDL_DISABLE);
@@ -365,7 +365,9 @@ int
SDL_PushEvent(SDL_Event * event)
{
SDL_EventWatcher *curr;

event->common.timestamp = SDL_GetTicks();

if (SDL_EventOK && !SDL_EventOK(SDL_EventOKParam, event)) {
return 0;
}
@@ -516,8 +518,20 @@ SDL_RegisterEvents(int numevents)
return event_base;
}

/* This is a generic event handler.
*/
int
SDL_SendAppEvent(SDL_EventType eventType)
{
int posted;

posted = 0;
if (SDL_GetEventState(eventType) == SDL_ENABLE) {
SDL_Event event;
event.type = eventType;
posted = (SDL_PushEvent(&event) > 0);
}
return (posted);
}

int
SDL_SendSysWMEvent(SDL_SysWMmsg * message)
{
@@ -36,6 +36,7 @@ extern int SDL_StartEventLoop(void);
extern void SDL_StopEventLoop(void);
extern void SDL_QuitInterrupt(void);

extern int SDL_SendAppEvent(SDL_EventType eventType);
extern int SDL_SendSysWMEvent(SDL_SysWMmsg * message);

extern int SDL_QuitInit(void);
@@ -114,15 +114,7 @@ SDL_QuitQuit(void)
int
SDL_SendQuit(void)
{
int posted;

posted = 0;
if (SDL_GetEventState(SDL_QUIT) == SDL_ENABLE) {
SDL_Event event;
event.type = SDL_QUIT;
posted = (SDL_PushEvent(&event) > 0);
}
return (posted);
return SDL_SendAppEvent(SDL_QUIT);
}

/* vi: set ts=4 sw=4 expandtab: */
@@ -228,42 +228,48 @@ - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(

- (void)applicationWillTerminate:(UIApplication *)application
{
SDL_SendQuit();
/* hack to prevent automatic termination. See SDL_uikitevents.m for details */
longjmp(*(jump_env()), 1);
SDL_SendAppEvent(SDL_APP_TERMINATING);
}

- (void) applicationWillResignActive:(UIApplication*)application
- (void)applicationDidReceiveMemoryWarning:(UIApplication *)application
{
//NSLog(@"%@", NSStringFromSelector(_cmd));
SDL_SendAppEvent(SDL_APP_LOWMEMORY);
}

// Send every window on every screen a MINIMIZED event.
- (void) applicationWillResignActive:(UIApplication*)application
{
SDL_VideoDevice *_this = SDL_GetVideoDevice();
if (!_this) {
return;
if (_this) {
SDL_Window *window;
for (window = _this->windows; window != nil; window = window->next) {
SDL_SendWindowEvent(window, SDL_WINDOWEVENT_FOCUS_LOST, 0, 0);
SDL_SendWindowEvent(window, SDL_WINDOWEVENT_MINIMIZED, 0, 0);
}
}
SDL_SendAppEvent(SDL_APP_WILLENTERBACKGROUND);
}

SDL_Window *window;
for (window = _this->windows; window != nil; window = window->next) {
SDL_SendWindowEvent(window, SDL_WINDOWEVENT_FOCUS_LOST, 0, 0);
SDL_SendWindowEvent(window, SDL_WINDOWEVENT_MINIMIZED, 0, 0);
}
- (void) applicationDidEnterBackground:(UIApplication*)application
{
SDL_SendAppEvent(SDL_APP_DIDENTERBACKGROUND);
}

- (void) applicationWillEnterForeground:(UIApplication*)application
{
SDL_SendAppEvent(SDL_APP_WILLENTERFOREGROUND);
}

- (void) applicationDidBecomeActive:(UIApplication*)application
{
//NSLog(@"%@", NSStringFromSelector(_cmd));
SDL_SendAppEvent(SDL_APP_DIDENTERFOREGROUND);

// Send every window on every screen a RESTORED event.
SDL_VideoDevice *_this = SDL_GetVideoDevice();
if (!_this) {
return;
}

SDL_Window *window;
for (window = _this->windows; window != nil; window = window->next) {
SDL_SendWindowEvent(window, SDL_WINDOWEVENT_FOCUS_GAINED, 0, 0);
SDL_SendWindowEvent(window, SDL_WINDOWEVENT_RESTORED, 0, 0);
if (_this) {
SDL_Window *window;
for (window = _this->windows; window != nil; window = window->next) {
SDL_SendWindowEvent(window, SDL_WINDOWEVENT_FOCUS_GAINED, 0, 0);
SDL_SendWindowEvent(window, SDL_WINDOWEVENT_RESTORED, 0, 0);
}
}
}

@@ -91,8 +91,10 @@ void UIKit_GL_SwapWindow(_THIS, SDL_Window * window)
}
[data->view swapBuffers];

/* we need to let the event cycle run, or the OS won't update the OpenGL view! */
SDL_PumpEvents();
/* You need to pump events in order for the OS to make changes visible.
We don't pump events here because we don't want iOS application events
(low memory, terminate, etc.) to happen inside low level rendering.
*/
}

SDL_GLContext UIKit_GL_CreateContext(_THIS, SDL_Window * window)

0 comments on commit d8d8542

Please sign in to comment.