iOS System Callback

I am in general agreement that there should be a real callback for
this. As you said, there has been a movement to event driven systems
for awhile now. As issues like battery life become more important to
end users, I believe the pressure for event systems will continue to
increase.

As for your patch, I’m thinking we might be able to improve upon this
so it is more optional, more extensible, and less platform specific. I
think we should introduce a new/general SDL function that lets you set
a function pointer to handle callback events. (This is akin to
SDL_mixer’s callback system.) On platforms that support callbacks, if
the function pointer is set, it will invoke the user’s function,
otherwise it is a no-op.

(All typed in mail, so code is unverified.)

void SDL_SetEventCallback( void
(sdl_event_callback_function)(SDL_Event event, void* userdata),
void* userdata);

I haven’t looked at the old iOS/SDL patch for handling events, but I
assume there is already special information packed into SDL_event so
you could get this through PollEvent. So I propose to reuse those
SDL_events for the callback. The callback will pass through an
SDL_event so you can identify which specific event is happening (e.g.
background, resume, low memory). I hope we might be able to also pass
any special OS specific data in this structure just in case, otherwise
we might want an additional void* parameter for this. The userdata
parameter is for users to pass through any special information they
need to get back from the callback so they don’t need global
variables. (This is a pet-peev of mine about SDL_mixer’s callbacks.)

void MyEventCallbackHandler(SDL_Event* event, void* userdata)
{
// Look at the SDL_Event to figure out what kind of event this is and handle it
if(MyIsSuspendEvent(event))
{
// Do what I need to do to save my info and prepare for suspend
}
else if(MyIsResumeEvent(event))
{

}
else if(MyIsLowMemoryEvent(event))
{
}

}

int main(int argc, char* argv[])
{
SDL_Init(SDL_INIT_VIDEO);
// ? yada yada yada

SDL_SetEventCallback(MyEventCallbackHandler, NULL);

return 0;

}

Then for example, in the iOS implementation of SDL:

  • (void)applicationWillTerminate:(UIApplication *)application
    {
    // Note: SDL will need some global/static variable to save the
    function pointer that user registered and another for the user data.
    // This will be in the SDL core and not the platform specific implementation.
    if(NULL != s_userSDLEventCallbackPtr)
    {
    // We need to create the SDL_event with the proper stuff to passthrough.
    // Can we do this on the stack, or do we need to do this on the heap?
    // If on the heap, we need to free the memory after the callback
    SDL_Event event;
    // Fill the event for this event type (terminate)
    // ?

     // Invoke the callback
     s_userSDLEventCallbackPtr(&event, s_userSDLEventCallbackUserData);
    
     // free the event if it was done on the heap
    

    }
    }

The nice thing about this is that it can be useful on more platforms
(e.g. Android, Mac, etc.) while at the same time allows users to
opt-into it instead of throwing a compile error. (I will argue that
though handling these is a good idea, not everybody actually needs to
handle it directly at this level so forcing it may not be correct.)

Thinking way, way ahead into the future, one possibility is that this
could be used to optionally use SDL as an event driven system instead
of the current polling architecture. So for example in Cocoa, we start
adding the callback check to all the event handlers such as mouse,
keyboard, touch, etc. and invoke the callback if defined and not be
restricted to just ‘special’ system events like iOS style
backgrounding. We might need one more API function to let users
specify which mode they want to run SDL in for these.

-EricOn 3/31/12, Brian Barnes wrote:

I created a patch.

http://www.klinksoftware.com/download/iOSCallback.zip

This contains 3 files. The patch itself, and the two changed .m files if
anybody wants to just apply it that way (both in video/uikit). This was
done off the trunk from about a day ago (I doubt these files have changed.)

This ASSUMES you are compiling a static library, which right now is your
only option, and it requires that these functions exist. The functions are:

void SDL_iOSEvent_WillTerminate(void);
void SDL_iOSEvent_DidReceiveMemoryWarning(void);
void SDL_iOSEvent_WillResignActive(void);
void SDL_iOSEvent_DidBecomeActive(void);
void SDL_iOSEvent_DidEnterBackground(void);
void SDL_iOSEvent_WillEnterForeground(void);

Currently, I get a crash every 3rd or so time. I will be tracking this;
it’s obviously some threaded or race condition, and I have some ideals. For
now, I’m assuming it’s my code.

I left in there the call that adds a minimize/maximize event onto the event
stack. I ignore these on iOS, so somebody else will have to fight over
include/not-include. :slight_smile:

NOTE: I REMOVED a pump events from swap buffer. ANY pump events outside of
event polling code is going to be asking for trouble. So using this
REQUIRES that you pump events yourself (or poll events, whatever.) This is
something you should probably be doing anyway. There could be more, and it
could be the source of my crash, but I won’t know until I can investigate
further.

The patch itself (don’t use this, use the one in the zip):

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 Sat Mar 31 12:54:02 2012 -0400
@@ -36,6 +36,15 @@
#undef main
#endif

+// these events must be defined in the client code
+// this assumes a static library
+extern void SDL_iOSEvent_WillTerminate(void);
+extern void SDL_iOSEvent_DidReceiveMemoryWarning(void);
+extern void SDL_iOSEvent_WillResignActive(void);
+extern void SDL_iOSEvent_DidBecomeActive(void);
+extern void SDL_iOSEvent_DidEnterBackground(void);
+extern void SDL_iOSEvent_WillEnterForeground(void);
+
extern int SDL_main(int argc, char *argv[]);
static int forward_argc;
static char **forward_argv;
@@ -123,16 +132,16 @@

  • (void)applicationWillTerminate:(UIApplication *)application
    {
  • SDL_SendQuit();
  • /* hack to prevent automatic termination.  See SDL_uikitevents.m for
    

details */

  • longjmp(*(jump_env()), 1);
  • SDL_iOSEvent_WillTerminate();
    +}

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

  • SDL_iOSEvent_DidReceiveMemoryWarning();
    }
  • (void) applicationWillResignActive:(UIApplication*)application
    {
  • //NSLog(@"%@", NSStringFromSelector(_cmd));
  • // Send every window on every screen a MINIMIZED event.
    SDL_VideoDevice *_this = SDL_GetVideoDevice();
    if (!_this) {
    return;
    @@ -143,13 +152,14 @@
    SDL_SendWindowEvent(window, SDL_WINDOWEVENT_FOCUS_LOST, 0, 0);
    SDL_SendWindowEvent(window, SDL_WINDOWEVENT_MINIMIZED, 0, 0);
    }
  • SDL_iOSEvent_WillResignActive();
    }
  • (void) applicationDidBecomeActive:(UIApplication*)application
    {
  • //NSLog(@"%@", NSStringFromSelector(_cmd));
  • // Send every window on every screen a RESTORED event.
  • SDL_iOSEvent_DidBecomeActive();
  • SDL_VideoDevice *_this = SDL_GetVideoDevice();
    if (!_this) {
    return;
    @@ -162,6 +172,16 @@
    }
    }

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

  • SDL_iOSEvent_DidEnterBackground();
    +}

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

  • SDL_iOSEvent_WillEnterForeground();
    +}

@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 Sat Mar 31 12:54:02 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


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


Beginning iPhone Games Development
http://playcontrol.net/iphonegamebook/

Eric wrote:

void SDL_SetEventCallback( void (sdl_event_callback_function)(SDL_Event event, void* userdata), void* userdata);

This would be a THIRD option (sigh!) It’s a bit larger of a change and has the habit of possibly being a bit stranger on some systems, but it’s as valuable as the others. The biggest problem with this is it’s a very large change to fix what is a very specific problem.

Eventually, somebody far up the chain who wields great masses of power will make a final decision :slight_smile:

I do think there is value to a stack/polling system, especially for games. There are numerous times you just can’t respond to events and you’ll end up stacking them up, anyway. The twist is these events have to happen in the callbacks, so now it’s catch-22.

[>] Brian

Eric wrote:

void SDL_SetEventCallback( void (sdl_event_callback_function)(SDL_Event
event, void* userdata), void* userdata);

This would be a THIRD option (sigh!) It’s a bit larger of a change and has
the habit of possibly being a bit stranger on some systems, but it’s as
valuable as the others. The biggest problem with this is it’s a very large
change to fix what is a very specific problem.

I don’t think this proposal to address your original problem is much
larger than the patch you proposed. Most of the code needed was in the
previous message. The missing details are packing the specific
SDL_events (which I assume already exist in the longjmp
implementations so they just need to be moved) and where to store the
global variables for the new API function.

This change will not affect any current behavior and users or
platforms that do not implement this will be none the wiser as this
will just be a no-op as before.

Eventually, somebody far up the chain who wields great masses of power will
make a final decision :slight_smile:

Definitely not me, but maybe my opinion has a little weight.

I do think there is value to a stack/polling system, especially for games.
There are numerous times you just can’t respond to events and you’ll end up
stacking them up, anyway. The twist is these events have to happen in the
callbacks, so now it’s catch-22.

[>] Brian

As I said, this is ‘way, way in the future’ and something that may be
opted into. What I’m proposing now solves your current problem in a
more general way, while also laying possible ground work for future
work on a general (but optional) event driven system.

The solution for today that I’m proposing should be fairly constrained.

-EricOn 3/31/12, Brian Barnes wrote:

Beginning iPhone Games Development
http://playcontrol.net/iphonegamebook/

Hi Eric,
I already did an implementation of generic callback mechanism very similar
to what you described. The initial version with usage instruction was
posted here:
http://forums.libsdl.org/viewtopic.php?t=7733&sid=21dffacbd29855581fe66d8a1126a1df
and the latest version with Android support here:
http://forums.libsdl.org/viewtopic.php?t=8021&sid=1fc02d7d3399878c1a2f11c0a2d94895
I’ll try to put it as a file somewhere tomorrow, because it looks like
spaces got messed a bit.

regards,
PiotrOn Sat, 31 Mar 2012, Eric Wing wrote:

On 3/31/12, Brian Barnes wrote:

I created a patch.

http://www.klinksoftware.com/download/iOSCallback.zip

This contains 3 files. The patch itself, and the two changed .m files if
anybody wants to just apply it that way (both in video/uikit). This was
done off the trunk from about a day ago (I doubt these files have changed.)

This ASSUMES you are compiling a static library, which right now is your
only option, and it requires that these functions exist. The functions are:

void SDL_iOSEvent_WillTerminate(void);
void SDL_iOSEvent_DidReceiveMemoryWarning(void);
void SDL_iOSEvent_WillResignActive(void);
void SDL_iOSEvent_DidBecomeActive(void);
void SDL_iOSEvent_DidEnterBackground(void);
void SDL_iOSEvent_WillEnterForeground(void);

Currently, I get a crash every 3rd or so time. I will be tracking this;
it’s obviously some threaded or race condition, and I have some ideals. For
now, I’m assuming it’s my code.

I left in there the call that adds a minimize/maximize event onto the event
stack. I ignore these on iOS, so somebody else will have to fight over
include/not-include. :slight_smile:

NOTE: I REMOVED a pump events from swap buffer. ANY pump events outside of
event polling code is going to be asking for trouble. So using this
REQUIRES that you pump events yourself (or poll events, whatever.) This is
something you should probably be doing anyway. There could be more, and it
could be the source of my crash, but I won’t know until I can investigate
further.

I am in general agreement that there should be a real callback for
this. As you said, there has been a movement to event driven systems
for awhile now. As issues like battery life become more important to
end users, I believe the pressure for event systems will continue to
increase.

As for your patch, I’m thinking we might be able to improve upon this
so it is more optional, more extensible, and less platform specific. I
think we should introduce a new/general SDL function that lets you set
a function pointer to handle callback events. (This is akin to
SDL_mixer’s callback system.) On platforms that support callbacks, if
the function pointer is set, it will invoke the user’s function,
otherwise it is a no-op.

(All typed in mail, so code is unverified.)

void SDL_SetEventCallback( void
(sdl_event_callback_function)(SDL_Event event, void* userdata),
void* userdata);

I haven’t looked at the old iOS/SDL patch for handling events, but I
assume there is already special information packed into SDL_event so
you could get this through PollEvent. So I propose to reuse those
SDL_events for the callback. The callback will pass through an
SDL_event so you can identify which specific event is happening (e.g.
background, resume, low memory). I hope we might be able to also pass
any special OS specific data in this structure just in case, otherwise
we might want an additional void* parameter for this. The userdata
parameter is for users to pass through any special information they
need to get back from the callback so they don’t need global
variables. (This is a pet-peev of mine about SDL_mixer’s callbacks.)

void MyEventCallbackHandler(SDL_Event* event, void* userdata)
{
// Look at the SDL_Event to figure out what kind of event this is and handle it
if(MyIsSuspendEvent(event))
{
// Do what I need to do to save my info and prepare for suspend
}
else if(MyIsResumeEvent(event))
{

}
else if(MyIsLowMemoryEvent(event))
{
}
}

int main(int argc, char* argv[])
{
SDL_Init(SDL_INIT_VIDEO);
// ? yada yada yada

SDL_SetEventCallback(MyEventCallbackHandler, NULL);

return 0;
}

Then for example, in the iOS implementation of SDL:

  • (void)applicationWillTerminate:(UIApplication *)application
    {
    // Note: SDL will need some global/static variable to save the
    function pointer that user registered and another for the user data.
    // This will be in the SDL core and not the platform specific implementation.
    if(NULL != s_userSDLEventCallbackPtr)
    {
    // We need to create the SDL_event with the proper stuff to passthrough.
    // Can we do this on the stack, or do we need to do this on the heap?
    // If on the heap, we need to free the memory after the callback
    SDL_Event event;
    // Fill the event for this event type (terminate)
    // ?

    // Invoke the callback
    s_userSDLEventCallbackPtr(&event, s_userSDLEventCallbackUserData);

    // free the event if it was done on the heap
    }
    }

The nice thing about this is that it can be useful on more platforms
(e.g. Android, Mac, etc.) while at the same time allows users to
opt-into it instead of throwing a compile error. (I will argue that
though handling these is a good idea, not everybody actually needs to
handle it directly at this level so forcing it may not be correct.)

Thinking way, way ahead into the future, one possibility is that this
could be used to optionally use SDL as an event driven system instead
of the current polling architecture. So for example in Cocoa, we start
adding the callback check to all the event handlers such as mouse,
keyboard, touch, etc. and invoke the callback if defined and not be
restricted to just ‘special’ system events like iOS style
backgrounding. We might need one more API function to let users
specify which mode they want to run SDL in for these.

-Eric

Beginning iPhone Games Development
http://playcontrol.net/iphonegamebook/


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

Oh cool Piotr!

I skimmed it over (though I am not good at reading diffs) and I think
we’re very much on agreement. Several very quick feedback items:

  1. Add a userdata callback parameter. (I have very strong opinions on this :))
  2. I think we are all in agreement that the longjmp stuff needs to go away
  3. I am a little concerned about the order of when the callback should
    be invoked. For example, in: - (void)
    applicationDidBecomeActive:(UIApplication*)application,

I think you invoke the callback first, and then do the video/window
reactivation stuff. I can’t give you a concrete example, but I have a
nagging feeling the order should be reversed. The risk is that some
SDL subsystem is suspended and in the callback, the user tries to make
API calls that affect or depend on the suspended subsystem not
actually being suspended. Here is an attempt at an example.

OS Suspend event comes in
Pass user a callback.
User pauses the audio in their game (remembers the seek position).
We return from callback and suspend SDL (including audio)

OS Resume event comes in.
We resume SDL subsystems (including audio)
Pass the user a callback.
User unpauses their audio (reseeks to position if necessary)

If we do this in the wrong order, for example in OS Resume, we do the
callback first and then resume SDL, the user might be calling audio
APIs that are no-ops or cause crashes since the underlying audio
subsystem isn’t fully active.

-EricOn 3/31/12, sdl at union.pl wrote:

Hi Eric,
I already did an implementation of generic callback mechanism very similar
to what you described. The initial version with usage instruction was
posted here:
http://forums.libsdl.org/viewtopic.php?t=7733&sid=21dffacbd29855581fe66d8a1126a1df
and the latest version with Android support here:
http://forums.libsdl.org/viewtopic.php?t=8021&sid=1fc02d7d3399878c1a2f11c0a2d94895
I’ll try to put it as a file somewhere tomorrow, because it looks like
spaces got messed a bit.

regards,
Piotr


Beginning iPhone Games Development
http://playcontrol.net/iphonegamebook/

Eric wrote:

I don’t think this proposal to address your original problem is much
larger than the patch you proposed. Most of the code needed was in the
previous message. The missing details are packing the specific
SDL_events (which I assume already exist in the longjmp
implementations so they just need to be moved) and where to store the
global variables for the new API function.

They don’t. You might need to check back on the longer, early thread about this. There are basically 6 messages, and 2 were exposed as minimize/maximum events, but that won’t work for a variety of reasons already discussed at length.

As I said before, I’m not married to any solution, and this one is also fine, and there’s nothing to stop us from adding the new events, but one important note: Some will be SPECIFIC to iOS. iOS has a lot of messages dealing with sending applications to the back and forward that have to be dealt with at the correct place, so we will be filling up the regular event system with very iOS specific events (and in the future, Android specific ones, etc.)

I just want to see something getting done ASAP :slight_smile:

While you solution is good, I do see it as a lot more work; the reason being is that if you only implement the 6 messages needed here, then it’s easier, but then it’s also a confusing API because it won’t function as a replacement for ALL the events when the API is named that way and targetted that way.

The other thing – and this is the one that could be a very big deal – is turning this on can be a either/or thing. If I start receiving events by callbacks, it would interfere how I receive them by polling, which would kind of force it to be either/or. If I just handle the iOS specific calls by callback, then I can leave my polling code in. Going to this means I need to begin to receive all events through this mechanism, and that would mean MASSIVE changes in a lot of code.

(That is if I am getting your proposal right.)

[>] Brian

Piotr wrote:

Hi Eric,
I already did an implementation of generic callback mechanism very similar
to what you described. The initial version with usage instruction was
posted here:
http://forums.libsdl.org/viewtopic.php?t=7733&sid=21dffacbd29855581fe66d8a1126a1df
and the latest version with Android support here:
http://forums.libsdl.org/viewtopic.php?t=8021&sid=1fc02d7d3399878c1a2f11c0a2d94895
I’ll try to put it as a file somewhere tomorrow, because it looks like
spaces got messed a bit.

regards,
Piotr

Oh cool Piotr!

Piotr’s version is where we started all this. My version was actually from another guy’s request, which I just implemented so others could play with it. Again, I have no horse in this race, anything that fits the requirements for a callback is fine with me, I’m just pushing and pushing to have something happen, so I’ll implement any idea if it pushes it forward.

If I had to pick, I’d probably go with Piotr’s solution as it’s more open-ended.

NOTE: Eric, this solution is not the same solution you proposed (unless I am completely mis-reading it.) Piotr’s solution is SPECIFICALLY for callback-required OS events, NOT for generic OS events. It can be tailored that way, but I think this is really where you might be getting confused. If you only implement it for OS stuff, then later implement it for everything else, it WILL break almost everybody’s code.

There are 3 solutions, right now:

  1. Was it Forest Hale? I think solution, the one I implemented, the required callbacks
  2. Piotr’s register callback by constant
  3. Eric’s move all events to callbacks

I’d pick 2. I know others picked 1. Not the biggest fan of 3.

Pros: Forces users to fill in required functions, easy to implement
Cons: Not open ended, very specific

Pros: Open ended, more cross platform
Cons: Allows programs the ability to ignore these message (they could stub in 1, above)

Pros: More forward thinking about events all together
Cons: Will take a lot more to implement and can’t really be done is steps

DISCUSS! :slight_smile:

[>] Brian

You are mis-reading it. Piotr’s solution is what I’m getting at. This
solves your problem in a way that is still compatible and reusable for
other platforms that have the same problem without being a pain for
people on iOS that don’t want to use it.

What I am also saying for the third time, that ‘very very far into the
future’, this could be extended (with a lot of work) to make SDL
optionally event-driven. When I say, very far, I’m likely talking
years from now. But by planting a compatible seed now, minimize future
breakage if/when that time comes.

-EricOn 4/1/12, Brian Barnes wrote:

Piotr wrote:

Hi Eric,
I already did an implementation of generic callback mechanism very
similar
to what you described. The initial version with usage instruction was
posted here:
http://forums.libsdl.org/viewtopic.php?t=7733&sid=21dffacbd29855581fe66d8a1126a1df
and the latest version with Android support here:
http://forums.libsdl.org/viewtopic.php?t=8021&sid=1fc02d7d3399878c1a2f11c0a2d94895
I’ll try to put it as a file somewhere tomorrow, because it looks like
spaces got messed a bit.

regards,
Piotr

Oh cool Piotr!

Piotr’s version is where we started all this. My version was actually from
another guy’s request, which I just implemented so others could play with
it. Again, I have no horse in this race, anything that fits the
requirements for a callback is fine with me, I’m just pushing and pushing to
have something happen, so I’ll implement any idea if it pushes it forward.

If I had to pick, I’d probably go with Piotr’s solution as it’s more
open-ended.

NOTE: Eric, this solution is not the same solution you proposed (unless I
am completely mis-reading it.) Piotr’s solution is SPECIFICALLY for
callback-required OS events, NOT for generic OS events. It can be tailored
that way, but I think this is really where you might be getting confused.
If you only implement it for OS stuff, then later implement it for
everything else, it WILL break almost everybody’s code.


Beginning iPhone Games Development
http://playcontrol.net/iphonegamebook/

Eric wrote:

What I am also saying for the third time, that ‘very very far into the
future’, this could be extended (with a lot of work) to make SDL
optionally event-driven. When I say, very far, I’m likely talking
years from now. But by planting a compatible seed now, minimize future
breakage if/when that time comes.

I understand, and I’m telling you for the third time that’ll break SDL on iOS if you ever make that change, when you do it in the future. :slight_smile: You can’t have a half-n-half solution between polling and callbacks unless that half-n-half is well defined, as it would be at this point. I don’t care how far in the future it is, it’s an important consideration.

Regardless, if you vote for Piotr’s solution as is, I’m on board. The future stuff we will leave to the future.

Also, this WILL not work unless you remove any unknown event pumps. The one I removed in my patch should continue on to this patch (in SDL_uikitopengles.m). If you do not remove this, you will get all sorts of crashes as these callbacks can come at inopportune times.

[>] Brian

I’m aware that this won’t be an easy change. That’s why I reiterate
that is a far in the future thing. As you said, the event pump stuff
will have to be disabled if running in a full event driven mode. This
suggests there will need to be another API mechanism to allow users to
select which mode they want to run in. By default, the mode would
retain current SDL behavior to preserve compatibility. To pull this
off will require non-trivial effort which I am well-aware of. But this
new API is not incompatible with this idea and in fact facilitates it.
And the nasty stuff is mostly behind the scenes implementation details
that don’t affect the public API (sans the mode toggling API).

But I do believe this needs to happen for SDL to remain
useful/relevant in the future. There are already places in Cocoa that
make assumptions about Apple driving the main event-loop, not the
other way around. There was a post recently about a user not being
able to use Game Center successfully with SDL (all the buttons
remained unresponsive when activated). While I don’t know for sure,
this sounds very much like typical run-loop ownership problem that
comes up every now and again in general Cocoa. Even though you didn’t
hit this specific one, these are real problems and very related to the
heart of the immediate problem you are trying to solve.

-EricOn 4/1/12, Brian Barnes wrote:

Eric wrote:

What I am also saying for the third time, that ‘very very far into the
future’, this could be extended (with a lot of work) to make SDL
optionally event-driven. When I say, very far, I’m likely talking
years from now. But by planting a compatible seed now, minimize future
breakage if/when that time comes.

I understand, and I’m telling you for the third time that’ll break SDL on
iOS if you ever make that change, when you do it in the future. :slight_smile: You
can’t have a half-n-half solution between polling and callbacks unless that
half-n-half is well defined, as it would be at this point. I don’t care how
far in the future it is, it’s an important consideration.

Regardless, if you vote for Piotr’s solution as is, I’m on board. The
future stuff we will leave to the future.

Also, this WILL not work unless you remove any unknown event pumps. The one
I removed in my patch should continue on to this patch (in
SDL_uikitopengles.m). If you do not remove this, you will get all sorts of
crashes as these callbacks can come at inopportune times.


Beginning iPhone Games Development
http://playcontrol.net/iphonegamebook/

Message-ID:
Content-Type: text/plain; charset=us-ascii

Eric wrote:

As I said before, I’m not married to any solution, and this one is also
fine, and there’s nothing to stop us from adding the new events, but one
important note: Some will be SPECIFIC to iOS. iOS has a lot of messages
dealing with sending applications to the back and forward that have to be
dealt with at the correct place, so we will be filling up the regular event
system with very iOS specific events (and in the future, Android specific
ones, etc.)

I just want to see something getting done ASAP :slight_smile:

While you solution is good, I do see it as a lot more work; the reason being
is that if you only implement the 6 messages needed here, then it’s easier,
but then it’s also a confusing API because it won’t function as a
replacement for ALL the events when the API is named that way and targetted
that way.

The other thing – and this is the one that could be a very big deal – is
turning this on can be a either/or thing. If I start receiving events by
callbacks, it would interfere how I receive them by polling, which would
kind of force it to be either/or. If I just handle the iOS specific calls
by callback, then I can leave my polling code in. Going to this means I
need to begin to receive all events through this mechanism, and that would
mean MASSIVE changes in a lot of code.

(That is if I am getting your proposal right.)

[>] Brian

Good points. I suggest a slight modification:

enum SDL_callbackstage
{
SDL_initialcallback,

SDL_queuecallback,

SDL_finishcallback

};
void SDL_SetEventCallback( int (sdl_event_callback_function)(
SDL_Event
event, void* userdata, SDL_callbackstage stage ), void*
userdata );

The basic concept is based on Aspect-oriented programming. With
Aspect-orientation, you basically replace calls to specific functions
with a set of 3 functions: one that happens before the call; one that
happens after the call; and one in between that decides whether the
original function is called at all, gets to modify the arguments
before they get passed to the original function, and gets to modify
the return before it gets returned to the original caller.

I propose that the final implementation be based on that, with the
’aspect’ specifically applying to the places in the library where OS
events are placed onto the SDL event queue (so that this doesn’t
affect user events).

SDL_callbackstage is used to signal which position the callback was
called from: SDL_initialcallback and SDL_finishcallback are both
self-explanatory, they happen at the beginning and end of set of
callback invocations, and their return value is ignored.
SDL_queuecallback is used to control whether the event is added to the
event queue (-1 for default (presumably “yes”, but see the final
paragraph of this post), 0 for no, 1 for yes).

The behavior would be something like this:

OS event comes in
Pass user initial callback
Pass user queue callback & react to return value
Suspend/resume SDL (*)
Pass user final callback

*The exact order of the queue call & SDL being suspended/resumed
should be event-dependent.

I think that the basic outline above is correct. A callback to control
whether SDL gets suspended/resumed might be useful on some platforms,
but I doubt it. Conveniently, this variant of the patch wouldn’t be
too different than the current one, it just involves a switch
statement (for the queue), two more callback invocations, an enum, and
an extra argument. Applying this to events in general might involve
more effort (I haven’t checked), but that’s effort that a callback
system would require anyways.

Note: I haven’t received the digest for the following post yet.

From Brian Barnes ggadwa at charter.net
At Sun Apr 1 12:20:14 PDT 2012

NOTE: Eric, this solution is not the same solution you proposed
(unless I am completely mis-reading it.) Piotr’s solution is SPECIFICALLY
for callback-required OS events, NOT for generic OS events. It can be
tailored that way, but I think this is really where you might be getting
confused. If you only implement it for OS stuff, then later implement
it for everything else, it WILL break almost everybody’s code.

Fortunately, my proposed variant doesn’t have this problem. No mode
switching, no magically knowing which generic events are hooked by
callback & which aren’t, just a simple add-in system where the
callback can effectively say “pretend I don’t exist”. It provides an
implementation route for Eric’s future-proofing, without requiring
SDL’s maintainers to keep track of when a particular event was moved
to the callback system.

In all cases of my proposed variant, returning -1 if the callback
doesn’t recognize either the SDL_callbackstage value or the event type
is correct, because it basically means “do the default”. Thus, if the
callback either doesn’t know about or care about some particular
SDL_callbackstage or event (or combination of the two) then it simply
does nothing other than return -1, and (one way or another) SDL will
do the default action.> Date: Sun, 1 Apr 2012 00:42:20 -0400

From: Brian Barnes
To: sdl at lists.libsdl.org
Subject: [SDL] iOS System Callback
Subject: [SDL] iOS System Callback

We are confronted with a fundamental choice of approach:

  1. SDL_main - app provides its own run loop in the single SDL_main function. (existing behavior)

  2. event-driven - app provides only event handlers, must stuff its own event queue with timer events to continue animation, etc. (more compatible)

Some platforms are perfectly happy with SDL_main (Windows, X11), some are designed explicitly around event-driven (Mac OSX, iOS, Android, Google NaCl, etc).

It is easy for SDL to emulate event-driven on SDL_main platforms so I will rate that option as “no harm”, however the current approach of implementing SDL_main on the event-driven platforms is an
ongoing maintenance mess.

So I propose that we should allow apps to be written for either model, with a big disclaimer about “Using SDL_main() on OSX, iOS and Android is not recommended and may be buggy”.

We could do this by providing two versions of the SDLmain code module to use in your app, one sets up the event-driven model (not linking to SDL_main in the app but rather to a set of event handler
functions) where as the other provides the existing functionality of simply invoking SDL_main in the app.

This is all somewhat tangential to the problem of SDL_iOSEvent_ callbacks which are system events of a much more significant nature than how we handle the event loop, but it is an important discussion
to have at this point.

I should note that if we support the option of event-driven apps, then SDL could additionally support web browser plugin APIs (Netscape Plugin API, Google NativeClient/Pepper Plugin API, Microsoft
ActiveX controls), which I think a lot of people would be interested in.–
LordHavoc
Author of DarkPlaces Quake1 engine - http://icculus.org/twilight/darkplaces
Co-designer of Nexuiz - http://alientrap.org/nexuiz
"War does not prove who is right, it proves who is left." - Unknown
"Any sufficiently advanced technology is indistinguishable from a rigged demo." - James Klass
"A game is a series of interesting choices." - Sid Meier

Jared wrote:

Fortunately, my proposed variant doesn’t have this problem. No mode
switching, no magically knowing which generic events are hooked by
callback & which aren’t, just a simple add-in system where the
callback can effectively say “pretend I don’t exist”. It provides an
implementation route for Eric’s future-proofing, without requiring
SDL’s maintainers to keep track of when a particular event was moved
to the callback system.

In all cases of my proposed variant, returning -1 if the callback
doesn’t recognize either the SDL_callbackstage value or the event type
is correct, because it basically means “do the default”. Thus, if the
callback either doesn’t know about or care about some particular
SDL_callbackstage or event (or combination of the two) then it simply
does nothing other than return -1, and (one way or another) SDL will
do the default action.

That’s a good idea but it can add a lot of overhead, especially in the problem were trying to solve which is time critical (the OS will actually attempt to halt you if you take to long to do what you are doing.)

Would a simpler solution be use Eric’s version, add a boolean return, if you return TRUE, you’ve handled the event, if you return FALSE, drop the event on the queue to later be picked up by an event poll? That solves the problem in the same way without a lot of overhead, and future proofs an iOS code (just return TRUE for all the iOS events, but FALSE for everything else.)

This is basically the same solution you’ve proposed, but without the various before/after stages. I’m not sure this would ever be useful, but I like the direction. Regardless, this would solve (so far) all the major problems.

[>] Brian

2012/4/1 Forest Hale :

We are confronted with a fundamental choice of approach:

  1. SDL_main - app provides its own run loop in the single SDL_main function. (existing behavior)

  2. event-driven - app provides only event handlers, must stuff its own event queue with timer events to continue animation, etc. (more compatible)

So I propose that we should allow apps to be written for either model, with a big disclaimer about “Using SDL_main() on OSX, iOS and Android is not recommended and may be buggy”.

LordHavoc
Author of DarkPlaces Quake1 engine - http://icculus.org/twilight/darkplaces
Co-designer of Nexuiz - http://alientrap.org/nexuiz
"War does not prove who is right, it proves who is left." - Unknown
"Any sufficiently advanced technology is indistinguishable from a rigged demo." - James Klass
"A game is a series of interesting choices." - Sid Meier

That was in my initial suggestion to solve the issue treated in this
thread, to think this as a general event driven vs polling issue, but
I dropped the argument later on in the discussion as I think I was
misunderstood and I was confusing the particular problem the thread
was trying to address. But yes, I think this is the general/broad
strategy that needs to be implemented in a, should I say, “middle
term” ? The more people interested in this, the more short term it can
become.–
Gabriel.

Jared wrote:

You forgot one bit: suspending/resuming SDL. I’m not all that
convinced that all of the invocations are needed either, but I do
think that at least 2 are needed: one before suspend/resume, another
after. The reason why is that if you’re suspending or resuming SDL,
then you likely want to do the same for some other libraries that
you’re running as well. If all of them support this sort of interface
then you just need to locate the callback in the right place for each
event, but that isn’t likely to happen. Thus, you need a 'hook point’
for both libraries that need to be suspended before/resumed after SDL,
and for libraries that need the opposite.

Going back to the original problem, iOS actually handles all these
events separately; i.e., there’s a before/after event (roughly) and
before/after event (again, roughly) for going in and out of suspending.

And each has very specific tasks you are supposed to handle.

Are you saying you want to wrap these into one event, with a before and
after? Or each one has a before and after?

For something that’s so OS specific, I think anything except exporting
the exact events will cause trouble. There really isn’t any docs on the
SDL side about what to do, but tons of docs on the iOS side telling you
what to do for each event.

If it’s a before/after for each one, I don’t really see the need.

I’ve done a bit of perusing of the code, and I could actually add a
event callback system pretty easily (I think), with a boolean return to
handle “put back in the polling stack” kind of thing that would actually
work (again, I think, without doing it.) Anybody care to try it out if
I push out a patch? It’d basically be Eric’s bit with a slight change,
plus the addition of some specific iOS events.

[>] Brian

Good points. I suggest a slight modification:

enum SDL_callbackstage
{
? ? ? ?SDL_initialcallback,

? ? ? ?SDL_queuecallback,

? ? ? ?SDL_finishcallback
};
void SDL_SetEventCallback( int (sdl_event_callback_function)(
SDL_Event
event, void* userdata, SDL_callbackstage stage ), void*
userdata );

The basic concept is based on Aspect-oriented programming. With
Aspect-orientation, you basically replace calls to specific functions
with a set of 3 functions: one that happens before the call; one that
happens after the call; and one in between that decides whether the
original function is called at all, gets to modify the arguments
before they get passed to the original function, and gets to modify
the return before it gets returned to the original caller.

Sorry for bashing, but this looks to me as an over engineered
solution, there’s been simpler (though perhaps less flexible)
solutions mentioned.–
Gabriel.

Here’s a proposal. NOTE: There IS already a system in place for this,
“event watches”. It doesn’t seem complete yet as there’s some comments
here and there. Is this a SDL2 thing? Should it be one or the other?
Both would serve the exact same purpose.

Anyway, quick code, haven’t attempted to compile as I just typed it out
for this message. This is step one, to add a overall event callback
mechanism. Step 2 is to create and expose the new iOS callback event types.===========================================================================

Add to SDL_events.h

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

===Add to SDL_events.c

===to top:

static struct
{
SDL_EventCallback callback;
void *userdata;
} SDL_EventCallback_Data;

===in SDL_StartEventLoop(void) add:

SDL_EventCallback_Data.callback=NULL;
SDL_EventCallback_Data.userdata=0;

===anywhere add:

void SDL_SetEventCallback(SDL_EventCallback callback,void *userdata)
{
SDL_EventCallback_Data.callback=callback;
SDL_EventCallback_Data.userdata=userdata;
}

===in SDL_PushEvent(SDL_Event * event) make:

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;
 }

// after filtering, before watches

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;

}

======================================

[>] Brian

Message-ID: <4F79AEE7.2060105 at charter.net>
Content-Type: text/plain; charset=“ISO-8859-1”; format=flowed

Jared wrote:

You forgot one bit: suspending/resuming SDL. I’m not all that
convinced that all of the invocations are needed either, but I do
think that at least 2 are needed: one before suspend/resume, another
after. The reason why is that if you’re suspending or resuming SDL,
then you likely want to do the same for some other libraries that
you’re running as well. If all of them support this sort of interface
then you just need to locate the callback in the right place for each
event, but that isn’t likely to happen. Thus, you need a 'hook point’
for both libraries that need to be suspended before/resumed after SDL,
and for libraries that need the opposite.

Going back to the original problem, iOS actually handles all these
events separately; i.e., there’s a before/after event (roughly) and
before/after event (again, roughly) for going in and out of suspending.

And each has very specific tasks you are supposed to handle.

Are you saying you want to wrap these into one event, with a before and
after? Or each one has a before and after?

I was saying, each one with a before/after. However, if it isn’t
needed, then there isn’t any reason to use two (besides which, the
possibility of more callback points being added at later dates/for
other platforms is part of why I worded things the way I did).

For something that’s so OS specific, I think anything except exporting
the exact events will cause trouble. There really isn’t any docs on the
SDL side about what to do, but tons of docs on the iOS side telling you
what to do for each event.

If it’s a before/after for each one, I don’t really see the need.

The basic assumption that I’m making is two-fold:

  1. There is a specific event where you suspend everything, and another
    where you resume;
  2. The SDL function that calls your callback suspends the SDL library itself.

With those two assumptions, if you have a mix of things that need to
be suspended before SDL, and others that need to be suspended after,
then you need two callback invocations in the relevant SDL function.

However, I’m not an iOS developer, so maybe this isn’t a real problem.

I’ve done a bit of perusing of the code, and I could actually add a
event callback system pretty easily (I think), with a boolean return to
handle “put back in the polling stack” kind of thing that would actually
work (again, I think, without doing it.)

Ease of implementation was one of the reasons I made that specific
suggestion :slight_smile: .> Date: Mon, 2 Apr 2012 09:51:35 -0400

From: Brian Barnes
To: sdl at lists.libsdl.org
Subject: [SDL] iOS System Callback