Skip to content
This repository has been archived by the owner on Feb 11, 2021. It is now read-only.

Commit

Permalink
Browse files Browse the repository at this point in the history
Added mobile application events, with implementations for iOS and And…
…roid
  • Loading branch information
slouken committed May 18, 2013
1 parent 06944f7 commit d8d8542
Show file tree
Hide file tree
Showing 9 changed files with 182 additions and 44 deletions.
63 changes: 63 additions & 0 deletions README.iOS
Expand Up @@ -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
==============================================================================
Expand Down
16 changes: 12 additions & 4 deletions android-project/src/org/libsdl/app/SDLActivity.java
Expand Up @@ -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() {
Expand Down Expand Up @@ -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();
Expand Down Expand Up @@ -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) {
Expand Down
36 changes: 35 additions & 1 deletion include/SDL_events.h
Expand Up @@ -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 */
Expand Down Expand Up @@ -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()
*/
Expand Down Expand Up @@ -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.*)
Expand Down
20 changes: 19 additions & 1 deletion src/core/android/SDL_android.cpp
Expand Up @@ -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
Expand All @@ -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
Expand Down Expand Up @@ -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;

Expand Down
22 changes: 18 additions & 4 deletions src/events/SDL_events.c
Expand Up @@ -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 */
Expand All @@ -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);
Expand Down Expand Up @@ -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;
}
Expand Down Expand Up @@ -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)
{
Expand Down
1 change: 1 addition & 0 deletions src/events/SDL_events_c.h
Expand Up @@ -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);
Expand Down
10 changes: 1 addition & 9 deletions src/events/SDL_quit.c
Expand Up @@ -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: */
52 changes: 29 additions & 23 deletions src/video/uikit/SDL_uikitappdelegate.m
Expand Up @@ -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);
}
}
}

Expand Down
6 changes: 4 additions & 2 deletions src/video/uikit/SDL_uikitopengles.m
Expand Up @@ -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)
Expand Down

0 comments on commit d8d8542

Please sign in to comment.