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