As I said earlier, the way IUP does its startup sequence and main loop
is incompatible with Android and iOS, and potentially other backends
like Emscripten/asm.js/WebAssembly. So I have developed a new
alternative sequence that I believe will work with all platforms.

Android Background:
The reason IUP’s current system doesn’t work on Android is two-fold.
1) All Android applications start in Java, and Android/Java completely
control the event loop. It is not possible to access it or control it.
2) Android is event driven. Everything starts from a callback in Java.
There is no C main function. We use callbacks to cross into C via JNI
so we can run normal IUP user code. But because this is an event
callback, the function must return. Calling IupMainLoop() is expected
to not return which thus would block the event loop.

iOS Background:
iOS almost works, but not quite, so in the end, it is ultimately the
same problem as Android. In iOS, to start the main event loop, we need
to call UIApplicationMain(). I made this the implementation for
IupMainLoop(), and this seems to fit. But the problem is that IUP APIs
are expected to work before you call IupMainLoop(). If
UIApplicationMain hasn’t been started yet, there are a bunch of
implementation details in CocoaTouch I depend on to make the
implementation work that have not created/initialized yet. These are
things like the application delegate, and even the autorelease pool.
So basically, UIApplicationMain is expected to be the first thing run
in an iOS app. But once you run it, it doesn’t return and it takes
control of the event loop. So now our problem looks the same as
Android.

Mac background:
Mac’s startup sequence is a little different than iOS’s, so I was
actually able to make Mac conform to the legacy startup sequence.
However, Mac really wants to behave more like iOS/Android and what I
did to implement this is not typical.


Proposal:
We introduce a new callback function, e.g. void IupEntryPoint(void)
which gets invoked after the application gets started. This is where
the user’s code officially begins.


So for a typical cross-platform project, I expect something like:


void IupEntryPoint(void);
void IupExitCallback(void);

// Remember that main is never run on Android.
// This main function should be a template/copy-and-paste for all IUP projects.
// Don't put any user code here. All user code should start in IupEntryPoint.
// The main you see here is only to get the platform to eventually
invoke IupEntryPoint() on platforms that need it.
int main(int argc, char* argv[])
{
        IupOpen(0, NULL);
        IupSetFunction("ENTRY_POINT", (Icallback)IupEntryPoint);
        // User can no longer assume that IupMainLoop blocks, and may return
immediately.
        // You should probably not put code after this call.
        // On the pre-existing platforms, IupMainLoop will be
implemented to lead to IupEntryPoint being invoked.
        IupMainLoop();
        return 0;
}

// This is where user code should start
void IupEntryPoint()
{
        // TODO: Proposed exit callback so the user can call IupClose()
        IupSetFunction("EXIT_CB", (Icallback)IupExitCallback);

        Ihandle* button = IupButton("Iup Button", "");
        IupSetCallback(button, "ACTION", (Icallback)OnButtonCallback);
        Ihandle* dialog = IupDialog(button);
        IupShow(dialog);
}

// TODO: Proposed exit callback which the user should setup in the
IupEntryPoint() callback.
void IupExitCallback()
{
        IupClose();
}

So here are the major points:

- Unchanged legacy code will continue to work as before (Windows, GTK,
Motif).IupEntryPoint() will not exist nor IupSetFunction is never
called for it, so it will never get invoked. IupMainLoop() will still
behave exactly as before on those existing implementations. So nobody
is forced to migrate until ready.

- New code should adopt this new design. That way it will work on both
the existing platforms (Windows, GTK, Motif), but also work on the new
platforms (iOS, Android, Mac).

        - On Android, the main() function never gets run. But all the other
platforms will run it. The callback entry point is where all platforms
will start running the same code.

        - On Android, because main() is never run, there is no opportunity to
call IupSetFunction() beforehand, IupEntryPoint() is a hardcoded
fallback/default. Because of this, documentation/conventions should
strongly encourage one standard function name, e.g. IupEntryPoint.
However, I made it possible to specify a different function name in
the AndroidManifest.xml.


        - Unix dlsym allows us to search for a symbol globally instead of a
specific library. This allows me to hard code a fallback and
explicitly look for a function called IupEntryPoint if the user did
not call IupSetFunction("ENTRY_POINT", (Icallback)IupEntryPoint)
without causing linking headaches. Windows is a harder to support
this, though it looks like it can be done:
https://john.nachtimwald.com/2012/07/15/calling-functions-in-exe-from-plugins-in-windows/
But it looks clumsy enough that we probably shouldn’t for Windows. So
always having IupSetFunction("ENTRY_POINT", (Icallback)IupEntryPoint);
as above solves this problem.


- On Android, nothing must block the event loop, so IupMainLoop() must
return immediately if called. The contract for IupMainLoop needs to be
relaxed the reflect this. If users need to distinguish, we could
introduce a new return value that expresses it immediately returned.

- Because IupMainLoop() may immediately return, shutdown code like
IupClose() should no longer immediately follow IupMainLoop().


- We should have an exit/shutdown callback that can be defined too so
users have a place to call IupClose() and any special quit cleanup
they may need to do. However, everybody also needs to keep in mind
that Android and iOS apps don’t typically quit. Instead, they suspend
and resume. (And they may be silently killed and never give a quit
event.) So we will also need to introduce new callbacks for suspend
and resume and developers need to start thinking about what is actual
shutdown code vs. what is suspend code (e.g. save to disk).

        - Thus, we should probably introduce suspend/background and resume
callbacks too. On legacy desktop implementations, they will never be
needed/used so backwards compatibility will just work. (Modern Mac and
WinRT seem to have introduced features that might be able to leverage
these events.)




I have implemented this prototype for Android, iOS, and Mac.

https://github.com/ewmailing/IupAndroid
https://github.com/ewmailing/IupCocoaTouch
https://github.com/ewmailing/IupCocoa

I’m reasonably convinced this can be made to work for all the existing
platforms.

Thanks,
Eric

P.S. I'm completely open to changing the names of the functions and attributes.

------------------------------------------------------------------------------
Check out the vibrant tech community on one of the world's most 
engaging tech sites, SlashDot.org! http://sdm.link/slashdot
_______________________________________________
Iup-users mailing list
Iup-users@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/iup-users

Reply via email to