Event Callback/iOS Patch

I implemented this, again, in the hopes of moving things forward.

http://www.klinksoftware.com/download/SDL_iOS_event_patch.diff

This patch is relatively simple but does a couple things:

[1] It allows you to gather all events as callbacks:

typedef int (SDLCALL * SDL_EventCallback) (SDL_Event *event, void *userdata);
extern DECLSPEC void SDLCALL SDL_SetEventCallback(SDL_EventCallback callback, void *userdata);

This is automatic. ALL events can now be treated as callbacks instead of polled.

[2] It allows you to get any events as callbacks and let others fall back to the event stack

Return 0 from your callback to let events fall to the stack, return 1 to say “I handled them” and they go no further than your code

[3] Added new event type + events for specific OS events

SDL_OSEvent is the struct

the types are:

SDL_IOS_WILLTERMINATE
SDL_IOS_DIDRECEIVEMEMORYWARNING
SDL_IOS_WILLRESIGNACTIVE
SDL_IOS_DIDBECOMEACTIVE
SDL_IOS_DIDENTERBACKGROUND
SDL_IOS_WILLENTERFOREGROUND

[4] I have not removed any long jump or watch code, this is something people will have to talk about, but it should be unnecessary now

==== EXAMPLE ====

SDL_SetEventCallback(ios_event_callback,0);

int ios_event_callback(SDL_Event *event,void *userdata)
{
switch (event->type) {
case SDL_IOS_WILLTERMINATE:
SDL_iOSEvent_WillTerminate();
return(1);

	case SDL_IOS_DIDRECEIVEMEMORYWARNING:
		SDL_iOSEvent_DidReceiveMemoryWarning();
		return(1);
		
	case SDL_IOS_WILLRESIGNACTIVE:
		SDL_iOSEvent_WillResignActive();
		return(1);
		
	case SDL_IOS_DIDBECOMEACTIVE:
		SDL_iOSEvent_DidBecomeActive();
		return(1);
		
	case SDL_IOS_DIDENTERBACKGROUND:
		SDL_iOSEvent_DidEnterBackground();
		return(1);
		
	case SDL_IOS_WILLENTERFOREGROUND:
		SDL_iOSEvent_WillEnterForeground();
		return(1);
		
}

return(0);		// all other events stay on stack

}

====== THE PATCH ======

diff -r 6bb657898f55 include/SDL_events.h
— a/include/SDL_events.h Tue Feb 28 21:58:36 2012 -0500
+++ b/include/SDL_events.h Mon Apr 02 18:45:40 2012 -0400
@@ -108,6 +108,14 @@

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

  • SDL_IOS_WILLTERMINATE = 0x1100,

  • SDL_IOS_DIDRECEIVEMEMORYWARNING,

  • SDL_IOS_WILLRESIGNACTIVE,

  • SDL_IOS_DIDBECOMEACTIVE,

  • SDL_IOS_DIDENTERBACKGROUND,

  • SDL_IOS_WILLENTERFOREGROUND,

    /** Events ::SDL_USEREVENT through ::SDL_LASTEVENT are for your use,

    • and should be allocated with SDL_RegisterEvents()
      @@ -382,6 +390,14 @@
      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.*)
    @@ -438,6 +454,7 @@
    SDL_MultiGestureEvent mgesture; /< Multi Finger Gesture data */
    SDL_DollarGestureEvent dgesture; /
    < Multi Finger Gesture data */
    SDL_DropEvent drop; /**< Drag and drop event data */
  • SDL_OSEvent os;
    } SDL_Event;

@@ -535,6 +552,9 @@
*/
extern DECLSPEC int SDLCALL SDL_PushEvent(SDL_Event * event);

+typedef int (SDLCALL * SDL_EventCallback) (SDL_Event *event, void *userdata);
+extern DECLSPEC void SDLCALL SDL_SetEventCallback(SDL_EventCallback callback, void *userdata);
+
typedef int (SDLCALL * SDL_EventFilter) (void *userdata, SDL_Event * event);

/**
diff -r 6bb657898f55 src/events/SDL_events.c
— a/src/events/SDL_events.c Tue Feb 28 21:58:36 2012 -0500
+++ b/src/events/SDL_events.c Mon Apr 02 18:45:40 2012 -0400
@@ -37,6 +37,13 @@
SDL_EventFilter SDL_EventOK = NULL;
void *SDL_EventOKParam;

+typedef struct SDL_EventCallback_Data {

  • SDL_EventCallback callback;
  • void *userdata;
    +} SDL_EventCallback_Block;

+static SDL_EventCallback_Block SDL_EventCallback_Data={NULL,0};
+
typedef struct SDL_EventWatcher {
SDL_EventFilter callback;
void *userdata;
@@ -357,26 +364,44 @@
int
SDL_PushEvent(SDL_Event * event)
{

  • int skip_add;
    SDL_EventWatcher *curr;
    event->window.timestamp = SDL_GetTicks();
    if (SDL_EventOK && !SDL_EventOK(SDL_EventOKParam, event)) {
    return 0;
    }
  • for (curr = SDL_event_watchers; curr; curr = curr->next) {
  •    curr->callback(curr->userdata, event);
    
  • }
  •   // after filtering, before watches
    
  • if (SDL_PeepEvents(event, 1, SDL_ADDEVENT, 0, 0) <= 0) {
  •    return -1;
    
  • }
  • skip_add=0;

  • if (SDL_EventCallback_Data.callback!=NULL) {

  •   skip_add=SDL_EventCallback_Data.callback(event,SDL_EventCallback_Data.userdata);
    
  • }

  • if (skip_add==0) {

  •   for (curr = SDL_event_watchers; curr; curr = curr->next) {
    
  •   	curr->callback(curr->userdata, event);
    
  •   }
    
  •   if (SDL_PeepEvents(event, 1, SDL_ADDEVENT, 0, 0) <= 0) {
    
  •   	return -1;
    
  •   }
    
  • }

  • SDL_GestureProcessEvent(event);

    return 1;
    }

+void SDL_SetEventCallback(SDL_EventCallback callback,void *userdata)
+{

  • SDL_EventCallback_Data.callback=callback;
  • SDL_EventCallback_Data.userdata=userdata;
    +}

void
SDL_SetEventFilter(SDL_EventFilter filter, void *userdata)
{
diff -r 6bb657898f55 src/video/uikit/SDL_uikitappdelegate.m
— a/src/video/uikit/SDL_uikitappdelegate.m Tue Feb 28 21:58:36 2012 -0500
+++ b/src/video/uikit/SDL_uikitappdelegate.m Mon Apr 02 18:45:40 2012 -0400
@@ -123,16 +123,27 @@

  • (void)applicationWillTerminate:(UIApplication *)application
    {
  • SDL_SendQuit();
  • /* hack to prevent automatic termination.  See SDL_uikitevents.m for details */
    
  • longjmp(*(jump_env()), 1);
  • SDL_Event event;
  • event.type = SDL_IOS_WILLTERMINATE;
  • SDL_PushEvent(&event);
    +}

± (void)applicationDidReceiveMemoryWarning:(UIApplication *)application
+{

  • SDL_Event event;
  • event.type = SDL_IOS_DIDRECEIVEMEMORYWARNING;
  • SDL_PushEvent(&event);
    }
  • (void) applicationWillResignActive:(UIApplication*)application
    {
  • //NSLog(@"%@", NSStringFromSelector(_cmd));
  • SDL_Event event;
  • event.type = SDL_IOS_WILLRESIGNACTIVE;
  • SDL_PushEvent(&event);
  • // Send every window on every screen a MINIMIZED event.
    SDL_VideoDevice *_this = SDL_GetVideoDevice();
    if (!_this) {
    return;
    @@ -143,13 +154,16 @@
    SDL_SendWindowEvent(window, SDL_WINDOWEVENT_FOCUS_LOST, 0, 0);
    SDL_SendWindowEvent(window, SDL_WINDOWEVENT_MINIMIZED, 0, 0);
    }

}

  • (void) applicationDidBecomeActive:(UIApplication*)application
    {
  • //NSLog(@"%@", NSStringFromSelector(_cmd));
  • // Send every window on every screen a RESTORED event.
  • SDL_Event event;
  • event.type = SDL_IOS_DIDBECOMEACTIVE;
  • SDL_PushEvent(&event);
  • SDL_VideoDevice *_this = SDL_GetVideoDevice();
    if (!_this) {
    return;
    @@ -162,6 +176,25 @@
    }
    }

± (void) applicationDidEnterBackground:(UIApplication*)application
+{

  • SDL_Event event;
  • event.type = SDL_IOS_DIDENTERBACKGROUND;
  • SDL_PushEvent(&event);
    +}

± (void) applicationWillEnterForeground:(UIApplication*)application
+{

  • SDL_Event event;
  • event.type = SDL_IOS_WILLENTERFOREGROUND;
  • SDL_PushEvent(&event);
    +}

@end

#endif /* SDL_VIDEO_DRIVER_UIKIT */
diff -r 6bb657898f55 src/video/uikit/SDL_uikitopengles.m
— a/src/video/uikit/SDL_uikitopengles.m Tue Feb 28 21:58:36 2012 -0500
+++ b/src/video/uikit/SDL_uikitopengles.m Mon Apr 02 18:45:40 2012 -0400
@@ -95,7 +95,7 @@
[data->uiwindow makeKeyAndVisible];

 /* we need to let the event cycle run, or the OS won't update the OpenGL view! */
  • SDL_PumpEvents();
  • // SDL_PumpEvents();

}

[>] Brian

Anybody have any comments? Sam, Ryan, does this look like something that could get into the trunk? This topic suddenly went very silent. My apologies for being a bug about this, I just thought I’d push for some progress. I know everybody is super busy which is why I did it myself.

[>] Brian

Is there any functional difference between your event callback
and SDL_SetEventFilter()?

It seems like those events are not necessarily iOS specific.On Wed, Apr 4, 2012 at 11:48 PM, Brian Barnes wrote:

Anybody have any comments? Sam, Ryan, does this look like something that
could get into the trunk? This topic suddenly went very silent. My
apologies for being a bug about this, I just thought I’d push for some
progress. I know everybody is super busy which is why I did it myself.

[>] Brian


SDL mailing list
SDL at lists.libsdl.org
http://lists.libsdl.org/listinfo.cgi/sdl-libsdl.org

I asked this before but it seems the mailing list simply swallowed my mail, so I’ll try it through the forum:

Isn’t this also relevant for Android? You seem to be talking of iOS purely, but isn’t Android pretty similar in this regard? If it isn’t then sorry for interrupting :slight_smile: I just thought I’d drop a note that Android should also be handled if it suffers from the same problems.

Regards,
Jonas Thiem------------------------
-Jonas Thiem
My Blog: http://gamedev-couch.blogspot.com/

Sam wrote:

Is there any functional difference between your event callback
and SDL_SetEventFilter()?

It seems like those events are not necessarily iOS specific.

Anybody have any comments? Sam, Ryan, does this look like something that
could get into the trunk? This topic suddenly went very silent. My
apologies for being a bug about this, I just thought I’d push for some
progress. I know everybody is super busy which is why I did it myself.

It works slightly differently, but it’s functionally the same. You’d have to go through a lot of email on this list to see how we arrived at this location. We’ve gone over this a lot :slight_smile:

  1. These events ARE specific to iOS (for instance, there are multiple events where specific things have to happen in each on whenever your application is sent to the background.) A single wrapped “minimize” event on a queue will not work. Your app will crash or behave strangely and worse yet be hard to track why (as you might get lucky and have it work sometimes.)

  2. There’s the problem of iOS removing time from your code, so the events have to happen in callbacks, period. Also, some events can come in when your code is paused (low memory) that you have to respond to or your application will be killed.

  3. The added events are:

SDL_IOS_WILLTERMINATE // iOS is telling you that it’s about to send you a kill
SDL_IOS_DIDRECEIVEMEMORYWARNING // release as much memory as possible or get killed
SDL_IOS_WILLRESIGNACTIVE // stop things
SDL_IOS_DIDBECOMEACTIVE // start things
SDL_IOS_DIDENTERBACKGROUND // save things – this is timed, complete in 5 seconds or get killed
SDL_IOS_WILLENTERFOREGROUND // load things

Notice there are multiple stages for both entering and exiting the background.

The bottom line is, on iOS, you HAVE TO HANDLE THESE EVENTS IN CALLBACKS. These events CURRENTLY do not EXIST in the trunk. How they get in there, I don’t care, I just want to see them in, therefore the patch. The have to be callbacks and they have to be these specific events.

  1. This patch changes the buffer swap for iOS – there’s a pump event calls which will make these events impossible to deal with because of unpredictability

  2. Nobody likes the wacky quit event long jump stuff in the iOS specific code (for various reasons, again, it was a long discussion). This patch doesn’t actually remove that, but they won’t get hit when this patch is in, and your application will behave to spec.

  3. THEN, the conversation jumped to “in the future we’ll need SDL to respond to all events by callback” solution, which expanded this patch to it’s current size. It was an actual “Here’s the SDL for a complete callback system”. I have no problem leveraging EventFilter, but this was just an attempt to make it more specific about what this was.

Regardless, the problem that needs to be solved is iOS callback events. Sam, if you want to discuss this off list, I can go through all the other stuff we talked about instead of re-hashing it here, again, for the 10th time :slight_smile:

[>] Brian> On Wed, Apr 4, 2012 at 11:48 PM, Brian Barnes <@Brian_Barnes> wrote:

MrJones wrote:

I asked this before but it seems the mailing list simply swallowed my mail, so I’ll try it through the forum:

Isn’t this also relevant for Android? You seem to be talking of iOS purely, but isn’t Android pretty similar in this regard? If it isn’t then sorry for interrupting :slight_smile: I just thought I’d drop a note that Android should also be handled if it suffers from the same problems.

Nobody has gotten any kind of iOS patch in at all, but I assume there will have to be similar stuff for Android, and I assume it’ll be specific to Android from what I’ve seen. Regardless, this is just a solution to add some extra events and expose a callback mechanism, so I don’t see this being any big jump for Android, but somebody will experience will have to talk about it.

The fact is, with these modern phone and tablet system, realtime callbacks that have to be responded to in time will be the norm for certain events.

[>] Brian

Hi Brian,

Your patch has one general issue - it is specific to just one platform and
cant be used as a general callback mechanism for system events on
other mobile platforms.
Some time ago I posted a patch I did earlier, which implements more
generic approach and contains both iOS and Android support (with win 8
metro support coming soon).
Moreover, it can be easily adapted to various existing platforms, as it
maps most platform specific events to their generic SDL equivalents. I
researched five platforms (iOS, Android, Win8 Metro, Blackberry Playbook,
Bada) and have their mappings to SDL events.
The patch can be found there:
http://union.org.pl/download/sdl/

regards,
PiotrOn Wed, 4 Apr 2012, Brian Barnes wrote:

Anybody have any comments? Sam, Ryan, does this look like something that could get into the trunk? This topic suddenly went very silent. My apologies for being a bug about this, I just thought I’d push for some progress. I know everybody is super busy which is why I did it myself.

[>] Brian


SDL mailing list
SDL at lists.libsdl.org
http://lists.libsdl.org/listinfo.cgi/sdl-libsdl.org

Hi Jonas,
If you want to test something similar for Android, check the patch
located here: http://union.org.pl/download/sdl/
It contains also Android implementation for event callbacks. Let me know
if it worked for you :slight_smile:

regards,
PiotrOn Sun, 8 Apr 2012, MrJones wrote:

I asked this before but it seems the mailing list simply swallowed my mail, so I’ll try it through the forum:

Isn’t this also relevant for Android? You seem to be talking of iOS purely, but isn’t Android pretty similar in this regard? If it isn’t then sorry for interrupting :slight_smile: I just thought I’d drop a note that Android should also be handled if it suffers from the same problems.

Regards,
Jonas Thiem


-Jonas Thiem
My Blog: http://gamedev-couch.blogspot.com/

Piotr wrote:

Hi Brian,

Your patch has one general issue - it is specific to just one platform and
cant be used as a general callback mechanism for system events on
other mobile platforms.

It can. You just need to add them. All this patch does is this:

  1. It adds a backwards compatible way to have all events delivered by
    callback
  2. It adds the iOS specific callbacks to events

All you need to do is apply the patch, add the android specific events
to the OS event structure (just like all other events) and you’re good
to go.

The one thing this has is it preserves how SDL does events right now
(through the event structures and polling mechanism) but fixes the
normal problems on iOS and doesn’t add a new mechanism that tied apart
from the event system.

If you ended up doing that and then re-sending the patch back, we might
be getting somewhere :slight_smile: I can send your further instructions if you
want, we might be able to get something into trunk if we all work together!

[>] Brian