We are currently migrating Bugzilla to GitHub issues.
Any changes made to the bug tracker now will be lost, so please do not post new bugs or make changes to them.
When we're done, all bug URLs will redirect to their equivalent location on the new bug tracker.

Bug 1505 - Required iOS Callbacks
Summary: Required iOS Callbacks
Status: RESOLVED FIXED
Alias: None
Product: SDL
Classification: Unclassified
Component: video (show other bugs)
Version: HG 2.0
Hardware: iPhone/iPod touch iOS (All)
: P2 critical
Assignee: Sam Lantinga
QA Contact: Sam Lantinga
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2012-05-25 11:06 UTC by Brian Barnes
Modified: 2013-05-18 15:50 UTC (History)
3 users (show)

See Also:


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Brian Barnes 2012-05-25 11:06:43 UTC
iOS requires that certain events are dealt with in callbacks.  Failure to do this will cause mysterious crashes and not follow the guidelines for proper app behavior.  Also, iOS removes time from your app so they must be handled in the callbacks.

These messages are:

willterminate
didreceivememorywarning
resignactive
becomeactive
enterbackground
enterforeground

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

This patch creates a new callback system.  Once registered, all events happen in a callback (and can be rerouted in the queue.)  This callback mechanism does the same as the filter mechanism, and could be combined.

This patch can also be used for Android with the proper messages added, and the basis for the game center patch.

Note this patch also removes a pump events from the screen flip, this causes these events to come at unexpected times (outside when you call pump.)
Comment 1 Gabriel Jacobo 2012-05-25 12:04:06 UTC
A few notes:

As Brian mentioned on the mailing list, his patch does not use the already existing event filter mechanism.

For alternatives to his solution, see here:
http://forums.libsdl.org/viewtopic.php?t=8133 (includes Game Center functionality as well)
http://forums.libsdl.org/viewtopic.php?t=7733


The original discussion:
http://forums.libsdl.org/viewtopic.php?t=8053


I think we need to do some consolidation of the alternatives, probably based on the solution given here: http://forums.libsdl.org/viewtopic.php?t=8133 which uses SetEventFilter as Sam suggested, though I'm confused by his complete disabling of the UIKit_PumpEvents function.
Comment 2 Brian Barnes 2012-05-25 12:24:53 UTC
(In reply to comment #1)

I'm not the biggest fan of http://forums.libsdl.org/viewtopic.php?t=8133 for a couple of reasons:

1. It makes the iOS and every other OS operate differently; it kinds of defeats the purpose of SDL to have one OS be push only and the others be polling.  As discussed earlier, going to all pushing is probably the best bet, especially if you can push back to the queue.

2. It still puts the entire background to foreground cycle in ONE pair of messages.  This is *bad*.  This will not work under certain circumstances and does NOT follow the guidelines.  There needs to be at least 4 separate messages, and this doesn't count memory low and will terminate.

3. I don't like the main function not being under my control.  This can be a performance bottleneck for games, and it's a pretty big difference in how SDL is integrated as is, right now (see #1.)

Mine should go through the filters -- this is easy enough to fix and I can update and put up a new diff later on.
Comment 3 Brian Barnes 2012-05-25 21:10:51 UTC
I've updated the patch:

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

It now removes the call back and instead uses SDL_SetEventFilter.  I retested this and it all works correctly.

[>] Brian
Comment 4 Sam Lantinga 2012-05-26 07:02:18 UTC
Thanks for the patch!

I have a few questions about this.
1. How is the application expected to handle these events?  Can we add documentation for these to README.iOS?
2. Why did you remove the call to SDL_PumpEvents()?
3. How does this affect (or not) GameCenter integration?

That last question is for my own personal use. :)
Comment 5 Brian Barnes 2012-05-26 09:03:13 UTC
Sam, this has actually brought up a place where I think the patch might have a problem.  I'm not sure what the solution is, we'll have to think about it.

> 1. How is the application expected to handle these events?  Can we add
>documentation for these to README.iOS?

Sure!

Per iOS docs (and this is what dim3 does):

SDL_IOS_WILLTERMINATE

Terminate the app.  Shut everything down before returning from this routine.  

** The problem is quitting SQL, this is something you don't do as you are in SDL.  I do make this call, and it seems to work, and it might be because the long jump still exist. **

SDL_IOS_DIDRECEIVEMEMORYWARNING

You will get this when you app is paused and iOS wants more memory.  Release as much memory as possible.

SDL_IOS_WILLRESIGNACTIVE

Prepare you app to go into the background.  Stop loops, etc.  This gets called first when the user hits the home button, or gets a call.

SDL_IOS_DIDENTERBACKGROUND

This will get called if the user accepted whatever send your app to the background.  If the user got a phone call and canceled it, you'll instead get a SDL_IOS_DIDBECOMEACTIVE and restart your loops.  When you get this, you have 5 seconds to save all your state.  You app is NOT active at this point.

SDL_IOS_WILLENTERFOREGROUND

This call happens when you app is coming back tot the foreground.  Restore all your state here.

SDL_IOS_DIDBECOMEACTIVE

Restart your loops here, your app is ready to start receiving time.

>2. Why did you remove the call to SDL_PumpEvents()?

It's a call to pump events which makes one of these events get back to your application.  Therefore, you need to have these events happen at predictable times (i.e., it's hard to shut down a loop when you could get called in any place in it.)  The solution is to make sure that you only get a callback when you expect it, i.e., YOU pump events.  This is something that will have to go into the docs.

The real reason you need to be able to expect this is some of these calls happen when you are no longer in control of your app (i.e., it has no time.)  So you can't let a loop run out, you need to have it frozen at that point.

>3. How does this affect (or not) GameCenter integration?

That's the big question, and I suspect it will still be broken.  If you look at the other patch, the big thing about it is it takes away control of the loop from the SDL application and hands it back to the OS.  I'm betting *this* is what makes game center work.  This is a bad solution for games that need to be in fine control of their timing, especially things like mine which are pretty complex 3D engines.

What *might* need to happen is a "game center" mode where you can call into SDL and it goes into it's own loop of this so you can run the game center dialogs, and returns when done.  Sadly, that will mean an iOS specific call.

[>] Brian
Comment 6 Gabriel Jacobo 2012-05-26 09:19:40 UTC
(In reply to comment #5)
> >2. Why did you remove the call to SDL_PumpEvents()?
> 
> It's a call to pump events which makes one of these events get back to your
> application.  Therefore, you need to have these events happen at predictable
> times (i.e., it's hard to shut down a loop when you could get called in any
> place in it.)  The solution is to make sure that you only get a callback when
> you expect it, i.e., YOU pump events.  This is something that will have to go
> into the docs.
> 
> The real reason you need to be able to expect this is some of these calls
> happen when you are no longer in control of your app (i.e., it has no time.) 
> So you can't let a loop run out, you need to have it frozen at that point.


It seems to me this should be an app specific solution...as the end user, you should be aware that when you call SDL_RenderPresent, that will eventually pump events, which implies potentially getting an iOS callback, and you should structure your loop around that (which basically is being aware of it and interrupting or restarting your loop after calling SDL_RenderPresent), or am I missing a different important factor?
Comment 7 Brian Barnes 2012-05-26 09:36:47 UTC
(In reply to comment #6)
> (In reply to comment #5)
> > >2. Why did you remove the call to SDL_PumpEvents()?
> > 
> > It's a call to pump events which makes one of these events get back to your
> > application.  Therefore, you need to have these events happen at predictable
> > times (i.e., it's hard to shut down a loop when you could get called in any
> > place in it.)  The solution is to make sure that you only get a callback when
> > you expect it, i.e., YOU pump events.  This is something that will have to go
> > into the docs.
> > 
> > The real reason you need to be able to expect this is some of these calls
> > happen when you are no longer in control of your app (i.e., it has no time.) 
> > So you can't let a loop run out, you need to have it frozen at that point.
> 
> 
> It seems to me this should be an app specific solution...as the end user, you
> should be aware that when you call SDL_RenderPresent, that will eventually pump
> events, which implies potentially getting an iOS callback, and you should
> structure your loop around that (which basically is being aware of it and
> interrupting or restarting your loop after calling SDL_RenderPresent), or am I
> missing a different important factor?

Sure, but it's errata.  It's easier to say "during a call to event code (specifically pump) is when you could get these callbacks" then a list of possible places.  The problem with this iOS stuff is getting these events means your code, after the event, will NO LONGER BE RUNNING.  When it comes back to the foreground, it'll start out right where it ended, and this can cause all sorts of havoc.  I'd rather have it up at the top of a loop (when you'll be pumping and running the math) then at the bottom, where you are in the middle of rendering stuff that might no longer exist by the time you return.

For instance, you should free as much memory as you can.  I save all my state and back out to the title page, which is as low memory as possible.  I'd have a hard time with that if it restarted right where it was rendering.

I also might not be necessary to call pump events there, I'd have to talk to the person that originally wrote the code.  I don't mind there being a flag.

[>] Brian
Comment 8 Brian Barnes 2012-05-26 09:39:56 UTC
(In reply to comment #6)
> (In reply to comment #5)
> > >2. Why did you remove the call to SDL_PumpEvents()?
> > 
> > It's a call to pump events which makes one of these events get back to your
> > application.  Therefore, you need to have these events happen at predictable
> > times (i.e., it's hard to shut down a loop when you could get called in any
> > place in it.)  The solution is to make sure that you only get a callback when
> > you expect it, i.e., YOU pump events.  This is something that will have to go
> > into the docs.
> > 
> > The real reason you need to be able to expect this is some of these calls
> > happen when you are no longer in control of your app (i.e., it has no time.) 
> > So you can't let a loop run out, you need to have it frozen at that point.
> 
> 
> It seems to me this should be an app specific solution...as the end user, you
> should be aware that when you call SDL_RenderPresent, that will eventually pump
> events, which implies potentially getting an iOS callback, and you should
> structure your loop around that (which basically is being aware of it and
> interrupting or restarting your loop after calling SDL_RenderPresent), or am I
> missing a different important factor?

One other quick note (sorry about all the email): The other solution that completely takes over the game loop?  This is why that one works the way it does, you are never going to be inside your game loop when the message comes.  For a solution where the app controls the loop, you need to be sure you'll know where the message will come in.
Comment 9 Sam Lantinga 2012-05-26 18:17:53 UTC
That makes sense
Comment 10 Vittorio Giovara 2012-07-15 00:48:50 UTC
Hi Brian, I apreciate you work on the SDL for iOS events.

I have just a few concerns on this, I hope to express them clearly so that you'll be able to address them.

- Are iOS-specific events a good thing? What about Android and future mobile ports? I fear that system-specific events become a documentation burden and it also fragments the operating system support. What I would long for is a "mobile" events system, where independently of the platform, the application code can react in the same way to the same events.
- I'm not sure the callback mechanism is actually required, why isn't it possible to reply in the event loop? After all, iOS events give you some time to respond and an "immediate" action at every system event is not really required.
- This is more a doubt, implementing a callback mechanis wouldn't break the SDL paradigm? As far as i know, there are no public callbacks besides SetEventFilter.

I hope we will be able to find a way to accomodate everyone proposal as each of them provided some very nice functionality.
Comment 11 Brian Barnes 2012-07-16 21:45:17 UTC
(In reply to comment #10)
> Hi Brian, I apreciate you work on the SDL for iOS events.
> 
> I have just a few concerns on this, I hope to express them clearly so that
> you'll be able to address them.
> 
> - Are iOS-specific events a good thing? What about Android and future mobile
> ports? I fear that system-specific events become a documentation burden and it
> also fragments the operating system support. What I would long for is a
> "mobile" events system, where independently of the platform, the application
> code can react in the same way to the same events.
> - I'm not sure the callback mechanism is actually required, why isn't it
> possible to reply in the event loop? After all, iOS events give you some time
> to respond and an "immediate" action at every system event is not really
> required.
> - This is more a doubt, implementing a callback mechanis wouldn't break the SDL
> paradigm? As far as i know, there are no public callbacks besides
> SetEventFilter.
> 
> I hope we will be able to find a way to accomodate everyone proposal as each of
> them provided some very nice functionality.

Vittorio,

We've gone over most of this on the list, but I'll try and hit a couple points.  There is another proposal out there that has events mapped to generic events, and we should use that setup.

The callback is definitely required.  Apple demands that you do the required tasks within the callback.  Once the callback exits, you can lose all time to your application, so a callback is the only way (and the documented way) to handle this.  Apple gives you time, but that's within the callback and that's the only guaranteed time you have.

Worse yet, since there's no processor time, you WILL NOT get the callback for memory low, which happens when you application is already frozen.  This will cause you application to be killed.

The latest implementation will just use SetEventFilter.  You setup the callback, and ignore everything that isn't a specific mobile event.  These events will go back on the stack to be picked up n the regular event mechanism.
Comment 12 Sam Lantinga 2013-05-18 15:50:29 UTC
Okay, I generalized the events for Android and checked them in:
http://hg.libsdl.org/SDL/rev/11612d544fcd

Please let me know if there are any issues!