IUP Next: New Modern Backends for the Cross-Platform Native GUI Library

This is a transcript of the talk originally presented at the Lua Workshop 2017. You are highly encouraged to watch the video as it contains videos and images omitted here.

IUP Next: New Modern Backends for the Cross-Platform Native GUI Library
Mac/Cocoa iOS/CocoaTouch Android Web/DOM
Eric Wing & Chris Matzenbach
Lua Workshop 2017

Hi my name is Eric Wing. I will be talking about the library, IUP or Yup today.

I learned last year at the Lua Workshop that it's pronounced Yup. Old habits die hard so sorry in advance for mispronouncing it.

Very quickly, I'll give you my background. 

I worked on a global satellite communication system called Globalstar. It involved launching satellites into space with rockets! It's not relevant for this talk, but everybody says it sounds cool.

I've done a lot of cross-platform development.

I started in Scientific Visualization.

It eventually led me to becoming a Mac OS 10 Cocoa expert to build deeply integrated native UI's with OpenGL visualization systems.I wrote the world's first full-featured bridge between the Lua language and Cocoa

I gave a talk on this last year at the 2016 LuaWorkshop.

I co-authored the book, Beginning iPhone Games Development, published by Apress.I worked on some commercial game engines.


I was the chief architect for the Corona SDK which allowed people to write native cross-platform games in Lua.


I later co-founded Lanica to build a game engine for Appcelerator, so people could write native cross-platform games in JavaScript, embedding JS like Lua. I also gave a talk on this last year at the 2016 Lua Workshop.


Since Android is so painful, I was forced to become an Android expert to help out.- I am currently working on a cross-platform SDK to make native app & game development simpler, called Blurrr SDK.


With that out of the way, let me quickly introduce IUP to everybody for those who are not familiar with it.


IUP is a library designed to help you build NATIVE user interfaces in a cross-platform way.

Picture of original IUP research paper.

It was developed at PUC-Rio, the same university as Lua. In fact, it started as a research project in the mid-90s, and you may recognize that one of the Lua authors is on this paper.


It is MIT licensed.


Look at the list of backends.

You'll notice that Mac OS 10 is missing from this list. I believe this is why Iup remained relatively obscure and unknown, even though it has been around so long. That is a hard platform to ignore when talking about using a cross-platform GUI library. So that's where this talk starts.


So let me tell you my personal story of what led me to IUP.


I have been creating a new SDK called Blurrr, originally designed to make cross-platform mobile-and-desktop native game development easier. My co-presenter Chris describes it as Create React App for native development.

BlurrrGenProj produces native projects like Visual Studio, Android Studio, Xcode, Makefiles, Qt Creator


The core set of libraries consists of many pure C libraries, for maximum portability and performance, but also to allow language bindings. So Blurrr officially supports writing in C, Lua, Javascript, and Swift.


I showed a couple of shots last year in my JavaScript talk.


But to make things really great, I realized I needed GUI tools.


For example, one feature of Blurrr is that it provides a centralized cross-platform build system built on CMake which allows you to simply list your project files in one text file, but you get out native IDE projects such as Xcode, Visual Studio, and Android Studio so you can use the native tooling for each platform and without needing to manually keep them all in sync.


<start video>

While I could reuse the same game technology to make some of them, like this particle designer, there are a lot of things that really should to be more native.


Since this feature launches other programs, it should be lightweight and not take much CPU or RAM. And it should not require a lot of screen real estate since the typical workflow will have multiple applications open at the same time, so a large OpenGL window encompassing all widgets isn't ideal.


Since I support developing on multiple platforms, I didn't want really to write different GUIs for each platform. I've been in cross-platform for a long time, so I've also used a lot of different toolkits. wxWidgets, Qt, Java, Tk, NodeWebKit, and so forth.


I dislike all of them. For time, I'm not going to go into details about all these, but this time around I decided to go with Qt Quick. While I've done some old Qt before, Qt Quick is a relatively new feature-slash-rewrite that the Qt community has been pushing developers to use, so I decided to finally give it a try.


In the end, I was very unhappy. I'm going to skip describing all the bugs and details. But I did get something that eventually worked. 


But as somebody who spends a lot of time on Mac, I hated the user-experience of my own program. My program is in the grand-scheme of things, very simple…not much more complicated than a hello world or calculator.

But why does my app eat up so much more RAM? Depending on platform and how you measure it, it can be like 4x.

RAM Usage Comparison (macOS 10.12)
IUP Version uses low memory. Apple Calculator uses a little more. Qt Version uses a lot.

Similar result on Linux.

RAM Usage Comparison (Ubuntu 12.04 LTS)
gcalctool uses the lowest amount of memory. IUP Version uses a little bit more. Qt Version uses a lot.


Why does my app take so long to launch?


Watch how many times the icon bounces in the Dock.

(Video shows about a 7 second launch time, plus a slight stall when pressing a button.)


Compare this with native.

(Video shows a sub-1-second launch time.)


And the GUI experience wasn't truly native. For those who don't know, Qt, isn't fully native. They reimplement their own widgets, but happen to have really good skin artwork. But Mac users like me quickly feel where everything is wrong because there is a lot of subtle behavior that Qt does not reproduce.

And I don't want to pick on Qt too much here because most of the other toolkits are far worse.


But…I had a working program. I was unhappy, but it was good enough.

Then, one day I needed to add Raspberry Pi support.

And at the time, Qt Quick on Pi could not support this due to the way it uses OpenGL for rendering its non-native widgets. And even if it could, the RAM is really tight on the Pi and I was already complaining it took too much RAM. Furthermore, the default windowing kit on Raspbian is GTK based, not Qt based, so that would make it even worse.


So Raspberry Pi was the straw that broke the camel's back for me.


But what was I going to do? I still didn't want to write different apps for each platform. 

But I really needed something truly native…it would not only solve my Raspberry Pi problem, but also the user experience problem that was causing me to hate using my own app.


Oh, yeah, there is IUP.

IUP is cross-platform and truly native.

The reason I skipped it is because it didn't have Mac support. 

But I'm an experienced Cocoa developer. I know how to fix this.

I started counting how much time I've wasted over the years trying to work around the lack of a good native cross-platform library. The world really needs this but nobody wants to build it because it is hard. But I have the skills to do this. It's time  to fix this.


So as I already gave it away in previous clips, I already rewrote my tool in IUP and started writing the Mac Cocoa backend.Because I really hammer the native UI thing, I need to demonstrate why native UI matters.

I already mentioned RAM and performance. But usability conventions are important to.


Each platform has their set of conventions and features that users come to expect. And if your app doesn't behave like every other app on the platform, people notice and become unhappy like me. If I wanted my Mac to behave like Linux or Windows, I wouldn't use a Mac, and vice-versa.


So let me quickly show you some interesting Mac features that non-native cross-platform GUI libraries frequently miss.

Cocoa Discontinuous Text Selection

All Cocoa TextViews have the ability to select discontinuous blocks of text, even vertically.

<start video>

First, I select all the vertical numbers and cut-and-paste them.

Then I select discontinuous words and cut-and-paste them.

This is a feature I use heavily on Mac for all Text Views so when apps screw this up, it irritates me to no end. Cmd-E will put the currently highlighted text into the Find buffer. Then Cmd-G will then find next occurrence of the word in the current focused view.


Mac Find Buffer: Cmd-E, Cmd-G

In this example, Native Cocoa is at the top, Java based Android Studio is on the bottom.

I want to find all occurrences of the word malloc in the file. 

<start video>

So I highlight the first malloc I see, and hit Cmd-E. I then hit Cmd-G multiple times until I wrap around the document.

But when I use the non-native app, Cmd-E does the completely wrong thing and pulls up a Recent Files dialog, and Cmd-G does absolutely nothing.


Services & Menu Built-ins: Capitalize

Macs have a ton of features packed into the menus. And Apple's built-in behaviors and UI guidelines result in apps sporting the same features in every app. They also have something called services which can talk to other apps.

Here, I want to capitalize my words. Notice the native-app on the left has a conventionally packed menu, while the app on the right is missing most things.

<start video>



Services & Menu Built-ins: Dictionary service

You can bring up a dictionary service for any native Cocoa text. Notice again how it fails to work on the right.


Because of some of my past work in audio, I have been contacted by people with impaired vision. I always feel a tremendous amount of guilt because the projects I worked on never spent resources on this. The video game industry is the absolute worst at being accessible.


But if I at least use native UI, those users have a fighting chance because the big platform vendors spend a lot of resources to make their platforms accessible and apply automatic behaviors to any apps that use their native widgets.


So here are two very simple examples.


There are built-in options for people with impaired vision which can change how widgets look.

In this screen, the native apps are at the Top-left and top-center. Qt is at the top-right. The Java based Android Studio is bottom-left. And the Electron based Slack is bottom-right.

<start video>

High Contrast off

Notice as I toggle the high-contrast option, the native rendering changes, but nothing happens with the non-natives.

High Contrast on


It is worth noting that on iOS when they moved to “flat design”, the buttons started looking like labels. If you turn on accessibility features, those buttons will actually be drawn differently so you can clearly see they are buttons.

Here, I want to use speech recognition for the text entry.

Native is on the left, qt is on the right.

<start video>

Microphone Speech-to-text




IUP researched how to solve the problem of creating *native* user interfaces in a cross-platform way. The problems are as follows:

How can you make a cross-platform interface when the native interfaces for every platform are so drastically different?

- Additionally, since every platform uses a different programming language for their native development, how do you deal with this in a flexible and cross-platform way.

- For example, Qt is implemented in C++ and expects you to subclass to override things. But remember, Qt isn't native. If a native widget is implemented in, C on GTK, Obj-C on Mac, Java on Android, and so forth, it is not possible to subclass a C++ class in any meaningful cross-platform way to alter the underlying widgets implemented in a different language.


IUP solves these problems in the following ways:


- IUP's core and public API are implemented in pure C, because C is the one language that every language can talk to

- Platform backends are implemented in each platform's native language using the native widget set

- IUP does not employ language subclassing since that can't be expected to work across all the platforms. 

- Instead IUP uses attributes to set propertiesThe advantages are

they can scale to cover entire native API features

It Does not require breaking/changing the API

Unsupported properties on platforms can simply ignore the feature request

And it Makes IUP simple to useIUP Also recognized that not everybody wants to write in C, so the API was designed with language bindings in mind.

- Since this is PUC-Rio, Lua bindings get first class support

To address the different sizing and layout problem, IUP invented a textual layout description format called LED.

It is optional. But it can be very convenient if you want to make slightly different layouts for different platforms while keeping your code unchanged.

IUP also has a live in-app runtime layout editor.

IupLayoutDialog: (Live) Run-time Layout Editor

The real app gui is on the left. 

<start video>

The layout editor is opened on the right.

Watch as I move some buttons around.

We won't be focusing on these in this talk, but just so you are aware, Iup has accessory libraries.

IupCD for Canvas Draw provides access to native 2D drawing APIs in a cross-platform way.

Then on top of IupCD, there are a bunch of other libraries that create custom, cross-platform non-native widgets, sort of like Qt.

Finally, let's talk about the Cocoa backend for IUP.


Just so everybody is on the same page,

Cocoa is the name of the framework you write native Mac applications in. 

It provides widgets like Text, Buttons, and Windows.

Objective-C is the native programming language you write Cocoa applications in. It is a 100% pure superset of C. Obj-C adds an object system and powerful runtime inspired by Smalltalk.


So the Cocoa backend for IUP is implemented in Obj-C.

For the most part, the Mac Cocoa implementation is pretty straight forward and matches well with Windows and GTK.


IupCocoa isn't finished yet. But sometimes, when I say that, people assume the worst and nothing is implemented. It is actually further along than most people think. I just started shipping my Mac IUP version of BlurrrGenProj. 

So here are some screenshots of things that have been implemented to various degrees.

Top left is Windows. Top right is GTK.

Bottom is Mac.

In this, we have a basic dialog, with labels and buttons.

Somebody specifically asked me if unicode and complex text layout worked, for example, does the word “Peace” in Arabic get displayed correctly and in the correct right-to-left order? The answer appears to be yes. 

Dialogs, Labels, & Buttons
IUP Native Widgets compared for Windows, GTK, Mac.
(Input) Text
IUP Native Widgets compared for Windows, GTK, Mac.
Progress Bar
IUP Native Widgets compared for Windows, GTK, Mac.
Tree
IUP Native Widgets compared for Windows, GTK, Mac.
Calendar
IUP Native Widgets compared for Windows, GTK, Mac.
File Dialogs
IUP Native Widgets compared for Windows, GTK, Mac.
Canvas
IUP Native Widgets compared for Windows, GTK, Mac.


Of course, not everything is rosy and perfect. I want to highlight two of the more interesting differences.

Currently in IUP, you are expected to have complete control over the event loop. There is a function called IupMainLoop() which basically is a while-loop that keeps pumping the event loop until the app quits.


On Mac, you really can't do this. Apple expects you to call a method which starts Apple's event loop and Apple wants complete control of the loop. Some game devs in the audience may know APIs to get around this, but there are a whole bunch of things in Apple's frameworks that assume the proper event loop and break when it is not used. So we can't do this.


We'll come back to this topic later because you'll see a similar event loop problem appear 3 more times in this talk.


Other desktop environments like Windows use per-window menus. But Mac doesn't have this. Instead there is a single global application menu.


After a lot of experimentation, I decided the best way to go was to ignore the per-dialog IupSetAttribute, and shanghai the the IupSetGlobal() API for this purpose.

Mac Application Menu


Unfortunately, this means the user needs to add a new case to opt-into the Mac application menu. But to help make things easier, I make IUP provide a default menu pre-populated with all the normal stuff.


The backend will automatically merge manually added menu items with ones that are in the default, which avoids duplicate entries and allows overriding default behaviors.

I should mention that Cocoa was originally invented in the mid-late 80's at NeXT, Steve Jobs company after Apple. A joint effort between NeXT and Sun Microsystems tried to push it as a cross-platform environment called OpenStep. That didn't get much traction, but there was another implementation called GNUStep which still survives today.


Somebody already forked my IUP Cocoa branch and modified it to work in GNUStep on Linux.

GNUStep demo


So that's IupCocoaBut it's 2017, not 2004. The world has shifted to mobile.

Mobile Revolution statistics (Gartner)


270 million PCs shipped in 2016 compared with

1.5 billion smartphones.


And PC sales are on the decline.

Google is switching to mobile-first indexing.

Google: Mobile-first indexing announcement

Mobile game revenues are now larger than PC and Consoles.

Mobile game revenue surpasses PC and consoles (Venture Beat)

So to really be useful in today's world, we also need to talk about Iup for mobile.


The good news is that IUP's thoughtful design seems flexible enough to handle mobile already.

For example, Attributes already avoided APIs from getting deeply entrenched with Desktop-only things.


So, yes, we can do this, but it just requires some careful thought how things should map and work on mobile.So let's go through one of these thought exercises.


What does Dialog mean for mobile?

<start video>

iOS UIWindow example

On mobile, we really don't have space for multiple windows.

On iOS, there is a class called UIWindow which shares similarities with the desktop window,

where it is a fullscreen window that serves as a view container for all the widgets on

screen.

A naive mapping would suggest we map this as the Dialog, but the problem is multiple

Dialogs.

UIWindow by itself isn't particularly useful without more complicated user interfaces to

manage multiple UIWindows.

Safari is an example of this.

You can see that Apple has designed a special custom user interface to let users select

between multiple windows.

But most apps don't do this because this is actually not the common case on mobile,

and this UI is kind of complicated.

<start video>

iOS UIViewController & Android Activity

The more common navigation element on mobile is not arbitrarily selecting between windows,

but drilling down and back through a stack of views.

We start on a first screen and select an option which pushes a new view.

We continue drilling down until we are done, and then pop our way back out from the stack.

This is true on both iOS and Android.

So my proposal for Dialog (at least as the common default), is map to this kind of navigation

structure.

On iOS, we use UINavigationController and Android we use Activity.

Every time we create and show a new dialog, it pushes into the navigation stack.

Since we are leveraging native OS widgets and paradigms for this, users are presented

the common UI they used to and know they can navigate back.

On iOS, NavigationController gives you the back button on the Navbar.

On Android, users know to use the Back button.So let's implement it and put everything together to see how a singular IUP program can be made to work naturally for all platforms. 


This is a simple IUP program written in Swift.

Demo IUP program to create a dialog & button (recursive). Written in Swift using bindings to IUP.

You don't need to understand this code, but this program creates a Dialog containing a Button. When you press the button, it creates a new Dialog with a button, and so forth.


So here is the program running on Ubuntu Linux.

vlcsnap-2017-12-10-01h39m09s698



Since I mentioned Raspberry Pi earlier, here is the same program on a Raspberry Pi.

vlcsnap-2017-12-10-01h39m27s539

Windows

Windows Dialog & Button demo

Now we are on Mac.

Mac Dialog & Button demo

Now let's do iOS.

iOS Dialog & Button demo

We are mapping Dialog to use UINavigationController and UIViewControllers under the hood.


And finally, Android.

Android Dialog & Button demo

Here we map Dialog to Activity, which is a little like iOS View Controller.


So implementing IUP for iOS is pretty straight-forward, aside from all the thought exercises.



I do want to mention that the event loop design problem is on iOS too. Apple wants full control of the event loop.

So let's talk about Android.


For developers that haven't done any Android development, there are a lot of assumptions, myths, and misconceptions about what you can do and how things work. So I'm going to dispel them right now.


All Android apps must be written using the Android SDK which is in Java.

You cannot escape this.

Android's GUI APIs are completely in Java.

Android originally was Java only, but had to cave to game developers and they provided

the Android NDK which allows for C and C++ development.Unfortunately, The Android NDK is awful.


Legendary game developer, John Carmack of Doom and Quake fame, called it “half baked” and says it “really does suck”

The Android NDK "Really Does Suck" - John Carmack


People like to remind me that Carmack has rarely complained about developer environments, even ones that were notoriously famous for being hard, such as the Sega Saturn. So this is damning. But this quote went viral because every NDK developer knows this pain.


The NDK is a second class citizen on Android with poor integration.


The Android NDK provides very few APIs.

And they have no APIs for native GUI.


So to get native GUI from C, we must use Java JNI to cross back and forth between Java and

C.



I have given multiple talks bashing the NDK. For more details, check out my JavaScript talk from last year. Also check out my Swift on Android talk from earlier this year at the try! Swift conference in Tokyo.


I'm not going to repeat those, because I have other Android problems I need to bash in the context of Iup.

Another horrible thing about Android development is its use of “God” objects. In Android, a large number APIs require a Context parameter. 


And of course, Android couldn't be bothered to give you a standard API to get a Context. This one choice has made it a nightmare for authoring libraries, especially for pre-existing cross-platform libraries which never needed a platform God object to be explicitly supplied with most API calls.Imagine all the pre-existing libraries that call fopen(). You must change every instance of this to call an Android replacement. Okay, fine, function rename wrappers are easy, but

now you must somehow also acquire a Context instance and pass it as an additional parameter. But there is no standard way to get a Context.



Of course, the reality is that nobody is going to do this and everybody tries to find an awful workaround for it.



The most common source of a Context is an Activity class.


A common mistake cross-platform libraries make trying to support Android is to hold a reference to a particular Activity.  But because Activities are intended to come and go at will, it is incorrect to hold a reference to one and keep it rooted past its expected closing.So there is another object called the Application, which fortunately does last the life of the entire application. But as before, there is no standard API to get the Application Context. The typical pattern is to create your own subclass of Application, force it to be the Application class, and implement your own getter so you have a way to retrieve it throughout your own application. 


So this is what I've employed for IUP. 


On Android, Android controls the event loop, period.

You must NEVER block the event loop.

You cannot manually pump the event loop.


Also note, there is no “int main” because we are in Java, not C.


A big, but common mistake is to workaround the event loop design by putting the NDK in a background thread.


It's a mistake because Android GUI APIs must be called on the main UI thread.



I've been through this with multiple companies across different products, and compared notes with other experienced Android developers, and this always ends in tears when you extend beyond your original base case.


Google made it worse because they have an example called NativeActivity which does this. It has steered so many people in the wrong direction, it is a disgrace.


I don't have time to go into detail the problems this causes, but at a high level:


You now end up locking everything for safety which ultimately kills performance.

You can no longer just directly call a system API because you must redirect everything to happen on the correct thread.

Users now must understand the threading models of their app, the framework, and the OS…implementation has leaked into everything

And time and time again, I've seen race condition bugs happen during application life-cycle events like background, resume, and quit which is hard enough to get right even single threaded.



So IupAndroid is unapologically designed to be on the main UI Thread.


But there is one more major platform to talk about, the web browser.

For the past few years, web developers have been trying to make native apps.


And unfortunately, they are bringing their bloat and bad ideas about the DOM into our native environments.


So this is my revenge.

Turnabout is fair play.

Let's build a web backend for IUP so we native developers can go in the other direction and build web apps with all our bloat and bad ideas. Ha!



But, while I know JavaScript in non-web contexts, I actually don't know much about the DOM and web browser.


Fortunately, I got really lucky and found Chris Matzenbach who is an expert on these matters.

He's been doing the heavy lifting for this backend, so I turn the talk over to him.

IupEmscripten (Chris Matzenbach)

Ever since the early 2000s, we've had a battle in the industry between writing native programs or writing applications for the web. Everyone has their preferences, and it's clear this battle won't be won any time soon. Thus, why not hedge our bets? Why don't we treat the webbrowser like any other platform? This is the core idea of IupEmscripten. Let's take our native programs and deploy them to the webbrowser, as if it were any other platform.

One of the problems up to this point has been Javascript; it's the only language you can use to write applications for the browser. Native developers don't use Javascript for many reasons, and thus a re-write has always been required. But now, thanks to the Emscripten compiler, we can change that. This new tool allows us to bring additional languages to the webbrowser, thus breaking down the division between native and web applications. A few years ago, some very smart programmers created a C-to-JavaScript compiler called Emscripten. Around the time of its release, the folks at Unreal decided to see how far they could push this new tool - the result, as you can see on the screen, is the unreal engine, running at an acceptable frame-rate, inside a web browser. 

Unreal in the web browser via Emscripten


What does this mean? We can take an entire game, written in C/C++, and actually get it to run in the browser.

While they did compile all their code into JavaScript, they rendered it all 

inside of a canvas, allowing them to draw all their widgets and components. However, that violates one of the core tenants of the Iup Library - which is, of course, native widgets. We want to bring that idea to the browser - thus we present the first cross-platform library using the browser's own native widgets. 

So normally with emscripten you give it your C code and it compiles in Javascript - you have a file ready to run in the browser (it also has planned WebAssembly support). But, for our case, this isn't quite good enough. In order for us to render native widgets, we need to be able to call into Javascript to access the DOM APIs. Emscripten didn't necessarily intend for this to be the case - they didn't expect us to be modifying the Javascript side. However, they do provide us with the ability to write external Javascript functions, which can then be called from our C code. Thanks to these external function calls, we can now implement the native Javascript DOM backend. 


This is what really sets us apart. There are other cross-platform libraries that compile to the web - Qt is one example. However, just like the Unreal team, they draw their own widgets, losing the native experience. For a truly native backend, we have to call into Javascript. Of course, the end result is a lot of jumping back and forth between C and JavaScript. Constantly jumping around may not sound pleasant, but Eric swears this is still better than Android! 


Emscripten example: Calling JavaScript from C

Now, onto the widget creation itself. The user defines the widget they want to create, which we have access to on the C side. The question is, how to we get that over to Javascript to render it using the DOM? Emscripten does not allow us to pass objects across the C/Javascript language bridge. We don't get a stack API like in Lua. However, we can pass integers across. Our solution then is to utilize a global ID map that maps integers to objects, thus serving as a proxy. 


So, how does this work? A call is made into JavaScript, which creates the object as a HTML node, assigns any necessary properties, and then generates a unique ID. This ID is stored in a global container object along with a reference to the object. The ID is then returned back to the C side, which stores it in the widget's data properties. The widget itself isn't passed back and forth, but rather each side references the same ID along with their own interpretation of what the particular widget is. This 1-for-1 integer ID map allows us to easily access objects on either side, creating a surprising bit of simplicity in a world of constant language-shifting. 


(Order from left to right: Chrome, Firefox, Safari)

Label, Input Text, & Button
IUP Native Widgets compared for Chrome, Firefox, Safari
Dialog, Label, & Button
IUP Native Widgets compared for Chrome, Firefox, Safari
Dropdown List
IUP Native Widgets compared for Chrome, Firefox, Safari
IupNext.105


(Order from left-to-right: Chrome, Firefox, Opera)

Apple Safari does not support this widget. Opera is pictured instead.

Editbox+Dropdown List
IUP Native Widgets compared for Chrome, Firefox, Safari








 

 

Because Emscripten follows a C/C++ paradigm, it assumes we are man- aging memory manually - there is no garbage collector on the C side. As it follows normal C rules, we use Iup to manage the memory for us. Iup provides Map and UnMap functions to handle the creation and destruction of widgets; however, the objects we create on the Javascript side will be garbage collected. How do we prevent that from happening? The answer is…the global ID map! Besides solving the problems of object access across the bridge, it also solves our memory management problems. Because an object exists in the ID map, it prevents it from being garbage collected Javascript. Otherwise, the object would no longer exists after our remote function was finished and returned to C. Likewise, by calling into Javascript during Iup's UnMap function, we remove the object from the ID map, ensuring it is garbage collected, and both sides always stay in sync. 


As Eric mentioned earlier, by its design Iup wants to control the Event Loop. We cannot let that happen. We need to let the web browser and JavaScript control this, since all the interaction is taking place within the DOM. We have no other option. The native experience Iup promises can be brought to the web. While this more than likely wasn't even a thought during the library's creation, modern tools have made this possible. With the addition of a web backend, your apps become more portable than ever. Forget worrying about operating systems, version differences - if your user's device can run a web browser, it can run your application. You no longer have to make the choice between building a native or web app - you get both! This returns developer focus to what's important - actually creating your application, and not worrying about system requirements limiting your user base. 

So finally, let's bring all the implementations together.

A few changes will be needed.

The rules are:

Legacy code must continue to work as before.


But we are allowed to add and change things as long as we don't break existing stuff.

Existing platforms must also be updated to work with the new changes.So we mentioned the Event Loop 4 times.


This is the old way you start an Iup application. IupMainLoop() is a blocking function that can be imagined as an infinite while-loop that manually pumps the platform's native event-loop until the application is finished.

IUP Init code (legacy)

That design won't work anymore.


So the key idea is instead of forcing the new platforms to behave like the old, we can make the old behave like the new, and make everything cross-platform again.

So the old way is on the left, and the new way is on the right.

IupNext.114

First, notice, we add 2 callback functions. The ENTRY_POINT callback is required and that function is now our designated starting point for where the user adds their code. The new int main() should be used as you see here and not changed.

Iup Init code (Old vs. New)
Callbacks for IupEntryPoint & IupExitPoint are introduced.

The second callback is now the designated callback for when the program is quitting.


User code gets moved into the IupEntryPoint() function.

Iup Init code (Old vs. New)
IupClose() gets moved into IupExitPoint(). User code gets moved into IupEntryPoint().

And IupClose() gets moved into the Exit Callback.

So now we'll step through the code on each platform to see why this works.


On Cocoa platforms, IupMainLoop starts the native event loop.

Iup Init on Cocoa/CocoaTouch


Behind the scenes, we also make sure to call IupEntryPoint() which is now the place where Iup user code starts.

Also, note, depending on various factors, IupMainLoop() may never return. For example, on iOS, apps don't ever really quit. They stay active until the process just gets killed.


On Android, there is no int main(), since everything starts in Java.

Iup Init on Android

Also remember, we must never block the event loop on Android since we do not control it.

So internally, we make our Android startup routine in Java call IupEntryPoint directly. If for some reason, you need to change the startup function, you can override the default in the AndroidManifest.xml, which is an XML file that contains configuration information that every Android app has.



With Emscripten, we don't have control over the event loop and we must never block the event loop.

Iup Init on Emscripten

So IupMainLoop() must return immediately and cannot block. In our IupMainLoop() implementation, we call the IupEntryPoint() callback to run the user's code. That runs and returns immediately, and the code flow continues. 


This means int main() runs all the way through to completion and ends. There is a special compile flag for Emscripten that allows the app to stay alive and continue running even though int main() has returned.

Notice, this is also why we remove IupClose() from being called right after IupMainLoop(), otherwise we would shutdown Iup pre-maturely.


So I've updated Iup's existing platforms to work with the new design.

Iup Init updated for existing platforms

When the IupSetFunction with ENTRY_POINT is called, we now know we want the new behavior. Legacy programs won't have this, so we can maintain backwards compatibility.


In IupMainLoop, we call IupEntryPoint to get things started. Then we run our infinite while-loop to pump the event loop. At this point, things are pretty much as before.

When the application quits, we end the infinite-while-loop and call the Exit Callback which will call IupClose().

IupMainLoop returns and main finishes. So now, our code is cross-platform again.

Iup Init is cross-platform again


All 4 of our new platforms must operate on the main thread.

Apple is unapologetic about it and embraces it.

Android we already talked about.

And the web doesn't allow threads.


Iup doesn't say anything about threads. But we require it now only be on the main thread.So we're at the finale.

Let's bring everything together.

For native development, the big question I am asked is how far can I take it. Usually developers have code that is mostly cross-platform, but then needs to reach beyond and do very native and platform specific things.


This usually breaks down into two sub-questions. Can I use custom or platform specific code in my IUP app?


So things like the accelerometer, gps, or random custom libraries. The answer is YES!





And here's a silly example, finally with Lua.

Last year I showed a LuaCocoa demo of a Swedish Chef translator app that uses LPeg.

Example: IupBork
A (Muppet) Swedish Chef translator implemented using Lua+LPeg

So let's raise the bar this year. 

I've ported it to IUP to use across all our platforms.

It is one common GUI in IUP, but each platform has a completely different way to access a native speech synthesizer.

Windows

IupBork: Windows

Linux

IupBork: Linux

Mac

IupBork: Mac

iOS

IupBork: iOS

Android

IupBork: Android

And yes, even the web browser.

IupBork: Emscripten

This one is really crazy.

We start with all our C code, including IUP, the Lua VM, and LPeg, and compile it to JavaScript using Emscripten.

We load all that JavaScript in a web browser.

We run a Lua script inside that JS-compiled LuaVm which is inside the JS web browser VM.

And we poke holes out of our C code to call directly into the Web APIs in JavaScript for Speech and GUI.


The second question is, Can I integrate my own custom or native views with IUP.

These may be things like Map views, video players, PDFs, or Augmented Reality views.

The answer is also yes! That's how we wrote IUP in the first place.

As an example of this, we will demonstrate a web widget. Every platform has a different native control to render web content. We'll write the interface so it can work with an IUP program. The web widget is also a convenient widget of last resort since web widgets have so much functionality baked into them now.

IupWeb: Windows
IupWeb: Linux
IupWeb: Mac
IupWeb: iOS
IupWeb: Android
IupWeb: Emscripten

What would you use this for?

Embed YouTube videos into your app

Show PDF if you don't have a native PDF viewer

MapViews in platforms that don't have native versions

Example: cable company that already created a web app showing channels and schedule.  They commissioned a separate native app, but instead of re-implementing what they had on the website, used a web view to show the schedule and channel listing within their native appThis is a screenshot of Linux.  Unlike say Electron, we don't need to embed a whole Chrome instance. This is already provided by the OS.

This entire app is under 1MB of native binaries.

Small binary size
On Ubuntu
libiup.so: 769.6kb
libiupweb.so: 20.4kb
main executable: 13.9kb


All the source repositories can be found on Github.


Repos:

https://github.com/ewmailing/IupCocoa

https://github.com/ewmailing/IupCocoaTouch

https://github.com/ewmailing/IupAndroid

https://github.com/ewmailing/IupEmscripten

Contains templates & examples seen today (e.g IupBork, IupWeb)

https://blurrrsdk.com


Links:

Repos:
https://github.com/ewmailing/IupCocoa

https://github.com/ewmailing/IupCocoaTouch

https://github.com/ewmailing/IupAndroid

https://github.com/ewmailing/IupEmscripten



Contains templates & examples seen today (e.g IupBork, IupWeb)

https://blurrrsdk.com


For those who just want to try it out and don't want to fuss around with getting it built, just in time for this workshop, Blurrr SDK now ships a sneak-preview of IUP. Assuming you have your platform's compilers installed, it's just download and go. No installers to mess up your system. It is completely self-contained. No fuss. IUP with C, Lua, and Swift is available. Please try it out. It has a free, unlimited trial.


So now I beg for your help. This project has gone on much longer than I expected. I would like to see it finished and remain open source, but I need help.


Ways you can help.

Purchase Blurrr SDK.

Also, I added a Donation link on the Blurrr SDK page. If you are interested in Patreon or GoFundMe, please let me know.

Maybe corporate sponsorships?

If you have an Iup project that you would like ported to these new platforms, or need help with a Iup project, maybe we can work out a consulting arrangement.

And of course, volunteers are welcome.

Also, we applied to Google Summer of Code this year with the Iup project lead Antonio Scuri, but our application was declined because there were too many applicants. If you have an organization that we can work under, maybe LuaLab, we may be able to recruit mentors again for next year.


And finally, please help spread the word about IUP Next with friends and on social media.



Finally, if you'll indulge me for a few moments.

Last year, in my LuaCocoa talk, I mentioned the annual GIST Walk for a Cure. GIST is a lesser known cancer, which took my mother. It happens that this year's walk is this Sunday in San Jose, which is 40 miles south of here. If you are in the area or would like to make a donation, we'd appreciate your support.

GIST Walk for a Cure
www.gistwalksanjose.org



Finally, last year, I mentioned my friend, and former co-founder, Carlos Icaza passed away. The Lua community knew him as the co-founder of the Corona SDK. Also, many people may have used products he helped create, such as Adobe Illustrator and Macromedia Flash.

RIP Carlos M. Icaza
Adobe, Macromedia, Corona SDK, Platino, @codinginswift


I was working on a little tribute in his memory, but I had not finished in time for last year's workshop. But I've since finished it and would like to share it. 


In some sense, this is a bucket list of things we wanted to achieve together, but time ran out. For example, he was an expert at splines. We wanted to do a spline project together, but it could never get a high enough priority.


<Go to “Dance of the Fairies” for video tribute>

Demo tribute: Dance of the Fairies


Thank you

© PlayControl Software
Mac OS X, iOS, and logos are trademars of Apple Inc.
Windows, Visual Studio, and logos are trademars of Microsoft Corportation.
Android and Android Studio, are trademars of Google Inc.
Steam and the Steam logo are trademarks and/or registered trademarks of Valve Corporation in the U.S. and/or other countries.
Other company and product names mentioned herein are trademarks of their respective companies and constitutes neither an endorsement nor recommendation. 
Privavy Policy