Added mobile application events, with implementations for iOS and Android
authorSam Lantinga <slouken@libsdl.org>
Sat, 18 May 2013 12:48:50 -0700
changeset 719011612d544fcd
parent 7189 414be1d64060
child 7191 75360622e65f
Added mobile application events, with implementations for iOS and Android
README.iOS
android-project/src/org/libsdl/app/SDLActivity.java
include/SDL_events.h
src/core/android/SDL_android.cpp
src/events/SDL_events.c
src/events/SDL_events_c.h
src/events/SDL_quit.c
src/video/uikit/SDL_uikitappdelegate.m
src/video/uikit/SDL_uikitopengles.m
     1.1 --- a/README.iOS	Sat May 18 09:35:09 2013 -0700
     1.2 +++ b/README.iOS	Sat May 18 12:48:50 2013 -0700
     1.3 @@ -55,6 +55,69 @@
     1.4  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.
     1.5  
     1.6  ==============================================================================
     1.7 +Notes -- Application events
     1.8 +==============================================================================
     1.9 +
    1.10 +On iOS the application goes through a fixed life cycle and you will get
    1.11 +notifications of state changes via application events. When these events
    1.12 +are delivered you must handle them in an event callback because the OS may
    1.13 +not give you any processing time after the events are delivered.
    1.14 +
    1.15 +e.g.
    1.16 +
    1.17 +int HandleAppEvents(void *userdata, SDL_Event *event)
    1.18 +{
    1.19 +    switch (event->type)
    1.20 +    {
    1.21 +    case SDL_APP_TERMINATING:
    1.22 +        /* Terminate the app.
    1.23 +           Shut everything down before returning from this function.
    1.24 +        */
    1.25 +        return 0;
    1.26 +    case SDL_APP_LOWMEMORY:
    1.27 +        /* You will get this when your app is paused and iOS wants more memory.
    1.28 +           Release as much memory as possible.
    1.29 +        */
    1.30 +        return 0;
    1.31 +    case SDL_APP_WILLENTERBACKGROUND:
    1.32 +        /* Prepare your app to go into the background.  Stop loops, etc.
    1.33 +           This gets called when the user hits the home button, or gets a call.
    1.34 +        */
    1.35 +        return 0;
    1.36 +    case SDL_APP_DIDENTERBACKGROUND:
    1.37 +        /* This will get called if the user accepted whatever sent your app to the background.
    1.38 +           If the user got a phone call and canceled it, you'll instead get an SDL_APP_DIDENTERFOREGROUND event and restart your loops.
    1.39 +           When you get this, you have 5 seconds to save all your state or the app will be terminated.
    1.40 +           Your app is NOT active at this point.
    1.41 +        */
    1.42 +        return 0;
    1.43 +    case SDL_APP_WILLENTERFOREGROUND:
    1.44 +        /* This call happens when your app is coming back to the foreground.
    1.45 +           Restore all your state here.
    1.46 +        */
    1.47 +        return 0;
    1.48 +    case SDL_APP_DIDENTERFOREGROUND:
    1.49 +        /* Restart your loops here.
    1.50 +           Your app is interactive and getting CPU again.
    1.51 +        */
    1.52 +        return 0;
    1.53 +    default:
    1.54 +        /* No special processing, add it to the event queue */
    1.55 +        return 1;
    1.56 +    }
    1.57 +}
    1.58 +
    1.59 +int main(int argc, char *argv[])
    1.60 +{
    1.61 +    SDL_SetEventFilter(HandleAppEvents, NULL);
    1.62 +
    1.63 +    ... run your main loop
    1.64 +
    1.65 +    return 0;
    1.66 +}
    1.67 +
    1.68 +    
    1.69 +==============================================================================
    1.70  Notes -- Accelerometer as Joystick
    1.71  ==============================================================================
    1.72  
     2.1 --- a/android-project/src/org/libsdl/app/SDLActivity.java	Sat May 18 09:35:09 2013 -0700
     2.2 +++ b/android-project/src/org/libsdl/app/SDLActivity.java	Sat May 18 12:48:50 2013 -0700
     2.3 @@ -78,17 +78,26 @@
     2.4      }
     2.5  
     2.6      // Events
     2.7 -    /*protected void onPause() {
     2.8 +    @Override
     2.9 +    protected void onPause() {
    2.10          Log.v("SDL", "onPause()");
    2.11          super.onPause();
    2.12          // Don't call SDLActivity.nativePause(); here, it will be called by SDLSurface::surfaceDestroyed
    2.13      }
    2.14  
    2.15 +    @Override
    2.16      protected void onResume() {
    2.17          Log.v("SDL", "onResume()");
    2.18          super.onResume();
    2.19          // Don't call SDLActivity.nativeResume(); here, it will be called via SDLSurface::surfaceChanged->SDLActivity::startApp
    2.20 -    }*/
    2.21 +    }
    2.22 +
    2.23 +    @Override
    2.24 +    public void onLowMemory() {
    2.25 +        Log.v("SDL", "onLowMemory()");
    2.26 +        super.onLowMemory();
    2.27 +        SDLActivity.nativeLowMemory();
    2.28 +    }
    2.29  
    2.30      @Override
    2.31      protected void onDestroy() {
    2.32 @@ -180,6 +189,7 @@
    2.33  
    2.34      // C functions we call
    2.35      public static native void nativeInit();
    2.36 +    public static native void nativeLowMemory();
    2.37      public static native void nativeQuit();
    2.38      public static native void nativePause();
    2.39      public static native void nativeResume();
    2.40 @@ -600,8 +610,6 @@
    2.41      public void onDraw(Canvas canvas) {}
    2.42  
    2.43  
    2.44 -
    2.45 -
    2.46      // Key events
    2.47      @Override
    2.48      public boolean onKey(View  v, int keyCode, KeyEvent event) {
     3.1 --- a/include/SDL_events.h	Sat May 18 09:35:09 2013 -0700
     3.2 +++ b/include/SDL_events.h	Sat May 18 12:48:50 2013 -0700
     3.3 @@ -61,6 +61,32 @@
     3.4      /* Application events */
     3.5      SDL_QUIT           = 0x100, /**< User-requested quit */
     3.6  
     3.7 +    /* These application events have special meaning on iOS, see README.iOS for details */
     3.8 +	SDL_APP_TERMINATING,        /**< The application is being terminated by the OS
     3.9 +                                     Called on iOS in applicationWillTerminate()
    3.10 +                                     Called on Android in onDestroy()
    3.11 +                                */
    3.12 +	SDL_APP_LOWMEMORY,          /**< The application is low on memory, free memory if possible.
    3.13 +                                     Called on iOS in applicationDidReceiveMemoryWarning()
    3.14 +                                     Called on Android in onLowMemory()
    3.15 +                                */
    3.16 +	SDL_APP_WILLENTERBACKGROUND, /**< The application is about to enter the background
    3.17 +                                     Called on iOS in applicationWillResignActive()
    3.18 +                                     Called on Android in onPause()
    3.19 +                                */
    3.20 +	SDL_APP_DIDENTERBACKGROUND, /**< The application did enter the background and may not get CPU for some time
    3.21 +                                     Called on iOS in applicationDidEnterBackground()
    3.22 +                                     Called on Android in onPause()
    3.23 +                                */
    3.24 +	SDL_APP_WILLENTERFOREGROUND, /**< The application is about to enter the foreground
    3.25 +                                     Called on iOS in applicationWillEnterForeground()
    3.26 +                                     Called on Android in onResume()
    3.27 +                                */
    3.28 +	SDL_APP_DIDENTERFOREGROUND, /**< The application is now interactive
    3.29 +                                     Called on iOS in applicationDidBecomeActive()
    3.30 +                                     Called on Android in onResume()
    3.31 +                                */
    3.32 +
    3.33      /* Window events */
    3.34      SDL_WINDOWEVENT    = 0x200, /**< Window state change */
    3.35      SDL_SYSWMEVENT,             /**< System specific event */
    3.36 @@ -109,7 +135,7 @@
    3.37  
    3.38      /* Drag and drop events */
    3.39      SDL_DROPFILE        = 0x1000, /**< The system requests a file open */
    3.40 -
    3.41 +	
    3.42      /** Events ::SDL_USEREVENT through ::SDL_LASTEVENT are for your use,
    3.43       *  and should be allocated with SDL_RegisterEvents()
    3.44       */
    3.45 @@ -427,6 +453,14 @@
    3.46      Uint32 timestamp;
    3.47  } SDL_QuitEvent;
    3.48  
    3.49 +/**
    3.50 + *  \brief OS Specific event
    3.51 + */
    3.52 +typedef struct SDL_OSEvent
    3.53 +{
    3.54 +    Uint32 type;        /**< ::SDL_QUIT */
    3.55 +    Uint32 timestamp;
    3.56 +} SDL_OSEvent;
    3.57  
    3.58  /**
    3.59   *  \brief A user-defined event type (event.user.*)
     4.1 --- a/src/core/android/SDL_android.cpp	Sat May 18 09:35:09 2013 -0700
     4.2 +++ b/src/core/android/SDL_android.cpp	Sat May 18 12:48:50 2013 -0700
     4.3 @@ -181,12 +181,20 @@
     4.4      bHasNewData = true;
     4.5  }
     4.6  
     4.7 +// Low memory
     4.8 +extern "C" void Java_org_libsdl_app_SDLActivity_nativeLowMemory(
     4.9 +                                    JNIEnv* env, jclass cls)
    4.10 +{    
    4.11 +    SDL_SendAppEvent(SDL_APP_LOWMEMORY);
    4.12 +}
    4.13 +
    4.14  // Quit
    4.15  extern "C" void Java_org_libsdl_app_SDLActivity_nativeQuit(
    4.16                                      JNIEnv* env, jclass cls)
    4.17  {    
    4.18      // Inject a SDL_QUIT event
    4.19      SDL_SendQuit();
    4.20 +    SDL_SendAppEvent(SDL_APP_TERMINATING);
    4.21  }
    4.22  
    4.23  // Pause
    4.24 @@ -199,12 +207,20 @@
    4.25          SDL_SendWindowEvent(Android_Window, SDL_WINDOWEVENT_FOCUS_LOST, 0, 0);
    4.26          SDL_SendWindowEvent(Android_Window, SDL_WINDOWEVENT_MINIMIZED, 0, 0);
    4.27      }
    4.28 +
    4.29 +    __android_log_print(ANDROID_LOG_VERBOSE, "SDL", "nativePause()");
    4.30 +    SDL_SendAppEvent(SDL_APP_WILLENTERBACKGROUND);
    4.31 +    SDL_SendAppEvent(SDL_APP_DIDENTERBACKGROUND);
    4.32  }
    4.33  
    4.34  // Resume
    4.35  extern "C" void Java_org_libsdl_app_SDLActivity_nativeResume(
    4.36                                      JNIEnv* env, jclass cls)
    4.37  {
    4.38 +    __android_log_print(ANDROID_LOG_VERBOSE, "SDL", "nativeResume()");
    4.39 +    SDL_SendAppEvent(SDL_APP_WILLENTERFOREGROUND);
    4.40 +    SDL_SendAppEvent(SDL_APP_DIDENTERFOREGROUND);
    4.41 +
    4.42      if (Android_Window) {
    4.43          /* Signal the resume semaphore so the event loop knows to resume and restore the GL Context
    4.44           * We can't restore the GL Context here because it needs to be done on the SDL main thread
    4.45 @@ -616,7 +632,9 @@
    4.46  
    4.47      if (false) {
    4.48  fallback:
    4.49 -        __android_log_print(ANDROID_LOG_DEBUG, "SDL", "Falling back to legacy InputStream method for opening file");
    4.50 +        // Disabled log message because of spam on the Nexus 7
    4.51 +        //__android_log_print(ANDROID_LOG_DEBUG, "SDL", "Falling back to legacy InputStream method for opening file");
    4.52 +
    4.53          /* Try the old method using InputStream */
    4.54          ctx->hidden.androidio.assetFileDescriptorRef = NULL;
    4.55  
     5.1 --- a/src/events/SDL_events.c	Sat May 18 09:35:09 2013 -0700
     5.2 +++ b/src/events/SDL_events.c	Sat May 18 12:48:50 2013 -0700
     5.3 @@ -111,6 +111,7 @@
     5.4          SDL_event_watchers = tmp->next;
     5.5          SDL_free(tmp);
     5.6      }
     5.7 +    SDL_EventOK = NULL;
     5.8  }
     5.9  
    5.10  /* This function (and associated calls) may be called more than once */
    5.11 @@ -133,8 +134,7 @@
    5.12      }
    5.13  #endif /* !SDL_THREADS_DISABLED */
    5.14  
    5.15 -    /* No filter to start with, process most event types */
    5.16 -    SDL_EventOK = NULL;
    5.17 +    /* Process most event types */
    5.18      SDL_EventState(SDL_TEXTINPUT, SDL_DISABLE);
    5.19      SDL_EventState(SDL_TEXTEDITING, SDL_DISABLE);
    5.20      SDL_EventState(SDL_SYSWMEVENT, SDL_DISABLE);
    5.21 @@ -365,7 +365,9 @@
    5.22  SDL_PushEvent(SDL_Event * event)
    5.23  {
    5.24      SDL_EventWatcher *curr;
    5.25 +
    5.26      event->common.timestamp = SDL_GetTicks();
    5.27 +
    5.28      if (SDL_EventOK && !SDL_EventOK(SDL_EventOKParam, event)) {
    5.29          return 0;
    5.30      }
    5.31 @@ -516,8 +518,20 @@
    5.32      return event_base;
    5.33  }
    5.34  
    5.35 -/* This is a generic event handler.
    5.36 - */
    5.37 +int
    5.38 +SDL_SendAppEvent(SDL_EventType eventType)
    5.39 +{
    5.40 +    int posted;
    5.41 +
    5.42 +    posted = 0;
    5.43 +    if (SDL_GetEventState(eventType) == SDL_ENABLE) {
    5.44 +        SDL_Event event;
    5.45 +        event.type = eventType;
    5.46 +        posted = (SDL_PushEvent(&event) > 0);
    5.47 +    }
    5.48 +    return (posted);
    5.49 +}
    5.50 +
    5.51  int
    5.52  SDL_SendSysWMEvent(SDL_SysWMmsg * message)
    5.53  {
     6.1 --- a/src/events/SDL_events_c.h	Sat May 18 09:35:09 2013 -0700
     6.2 +++ b/src/events/SDL_events_c.h	Sat May 18 12:48:50 2013 -0700
     6.3 @@ -36,6 +36,7 @@
     6.4  extern void SDL_StopEventLoop(void);
     6.5  extern void SDL_QuitInterrupt(void);
     6.6  
     6.7 +extern int SDL_SendAppEvent(SDL_EventType eventType);
     6.8  extern int SDL_SendSysWMEvent(SDL_SysWMmsg * message);
     6.9  
    6.10  extern int SDL_QuitInit(void);
     7.1 --- a/src/events/SDL_quit.c	Sat May 18 09:35:09 2013 -0700
     7.2 +++ b/src/events/SDL_quit.c	Sat May 18 12:48:50 2013 -0700
     7.3 @@ -114,15 +114,7 @@
     7.4  int
     7.5  SDL_SendQuit(void)
     7.6  {
     7.7 -    int posted;
     7.8 -
     7.9 -    posted = 0;
    7.10 -    if (SDL_GetEventState(SDL_QUIT) == SDL_ENABLE) {
    7.11 -        SDL_Event event;
    7.12 -        event.type = SDL_QUIT;
    7.13 -        posted = (SDL_PushEvent(&event) > 0);
    7.14 -    }
    7.15 -    return (posted);
    7.16 +    return SDL_SendAppEvent(SDL_QUIT);
    7.17  }
    7.18  
    7.19  /* vi: set ts=4 sw=4 expandtab: */
     8.1 --- a/src/video/uikit/SDL_uikitappdelegate.m	Sat May 18 09:35:09 2013 -0700
     8.2 +++ b/src/video/uikit/SDL_uikitappdelegate.m	Sat May 18 12:48:50 2013 -0700
     8.3 @@ -228,42 +228,48 @@
     8.4  
     8.5  - (void)applicationWillTerminate:(UIApplication *)application
     8.6  {
     8.7 -    SDL_SendQuit();
     8.8 -     /* hack to prevent automatic termination.  See SDL_uikitevents.m for details */
     8.9 -    longjmp(*(jump_env()), 1);
    8.10 +    SDL_SendAppEvent(SDL_APP_TERMINATING);
    8.11 +}
    8.12 +
    8.13 +- (void)applicationDidReceiveMemoryWarning:(UIApplication *)application
    8.14 +{
    8.15 +    SDL_SendAppEvent(SDL_APP_LOWMEMORY);
    8.16  }
    8.17  
    8.18  - (void) applicationWillResignActive:(UIApplication*)application
    8.19  {
    8.20 -    //NSLog(@"%@", NSStringFromSelector(_cmd));
    8.21 +    SDL_VideoDevice *_this = SDL_GetVideoDevice();
    8.22 +    if (_this) {
    8.23 +        SDL_Window *window;
    8.24 +        for (window = _this->windows; window != nil; window = window->next) {
    8.25 +            SDL_SendWindowEvent(window, SDL_WINDOWEVENT_FOCUS_LOST, 0, 0);
    8.26 +            SDL_SendWindowEvent(window, SDL_WINDOWEVENT_MINIMIZED, 0, 0);
    8.27 +        }
    8.28 +    }
    8.29 +    SDL_SendAppEvent(SDL_APP_WILLENTERBACKGROUND);
    8.30 +}
    8.31  
    8.32 -    // Send every window on every screen a MINIMIZED event.
    8.33 -    SDL_VideoDevice *_this = SDL_GetVideoDevice();
    8.34 -    if (!_this) {
    8.35 -        return;
    8.36 -    }
    8.37 +- (void) applicationDidEnterBackground:(UIApplication*)application
    8.38 +{
    8.39 +    SDL_SendAppEvent(SDL_APP_DIDENTERBACKGROUND);
    8.40 +}
    8.41  
    8.42 -    SDL_Window *window;
    8.43 -    for (window = _this->windows; window != nil; window = window->next) {
    8.44 -        SDL_SendWindowEvent(window, SDL_WINDOWEVENT_FOCUS_LOST, 0, 0);
    8.45 -        SDL_SendWindowEvent(window, SDL_WINDOWEVENT_MINIMIZED, 0, 0);
    8.46 -    }
    8.47 +- (void) applicationWillEnterForeground:(UIApplication*)application
    8.48 +{
    8.49 +    SDL_SendAppEvent(SDL_APP_WILLENTERFOREGROUND);
    8.50  }
    8.51  
    8.52  - (void) applicationDidBecomeActive:(UIApplication*)application
    8.53  {
    8.54 -    //NSLog(@"%@", NSStringFromSelector(_cmd));
    8.55 +    SDL_SendAppEvent(SDL_APP_DIDENTERFOREGROUND);
    8.56  
    8.57 -    // Send every window on every screen a RESTORED event.
    8.58      SDL_VideoDevice *_this = SDL_GetVideoDevice();
    8.59 -    if (!_this) {
    8.60 -        return;
    8.61 -    }
    8.62 -
    8.63 -    SDL_Window *window;
    8.64 -    for (window = _this->windows; window != nil; window = window->next) {
    8.65 -        SDL_SendWindowEvent(window, SDL_WINDOWEVENT_FOCUS_GAINED, 0, 0);
    8.66 -        SDL_SendWindowEvent(window, SDL_WINDOWEVENT_RESTORED, 0, 0);
    8.67 +    if (_this) {
    8.68 +        SDL_Window *window;
    8.69 +        for (window = _this->windows; window != nil; window = window->next) {
    8.70 +            SDL_SendWindowEvent(window, SDL_WINDOWEVENT_FOCUS_GAINED, 0, 0);
    8.71 +            SDL_SendWindowEvent(window, SDL_WINDOWEVENT_RESTORED, 0, 0);
    8.72 +        }
    8.73      }
    8.74  }
    8.75  
     9.1 --- a/src/video/uikit/SDL_uikitopengles.m	Sat May 18 09:35:09 2013 -0700
     9.2 +++ b/src/video/uikit/SDL_uikitopengles.m	Sat May 18 12:48:50 2013 -0700
     9.3 @@ -91,8 +91,10 @@
     9.4      }
     9.5      [data->view swapBuffers];
     9.6  
     9.7 -    /* we need to let the event cycle run, or the OS won't update the OpenGL view! */
     9.8 -    SDL_PumpEvents();
     9.9 +    /* You need to pump events in order for the OS to make changes visible.
    9.10 +       We don't pump events here because we don't want iOS application events
    9.11 +       (low memory, terminate, etc.) to happen inside low level rendering.
    9.12 +     */
    9.13  }
    9.14  
    9.15  SDL_GLContext UIKit_GL_CreateContext(_THIS, SDL_Window * window)