[Comment removed by author]
At my last company I was in charge of Mac porting of all our Windows applications. We had a cross platform library that was meant to make the process instant, ie. a continuous integration server could take a Windows only application and create Mac, Linux, Android and iOS versions 20 minutes later. In reality about 30% of the applications were created before this system and no one had any reason to not use Win32 so those were a pain to port. The rest were created since this system came into place and should have just required hitting compile. Of course a lot of raw Win32 code was still used anyway, either because the Windows programmer didn’t know how to replace it, was under pressure to get a product out, or just didn’t care about the porting teams. At least half my job was just rewriting Win32 code that should have been written in a cross platform matter from the start, such a waste of time.
Then there was the problem of abstracting generic concepts.
Toolbars: small, big, configurable, not configurable, drag and drop, drop down items in the toolbar etc.
Menus: per document, per window, or per application? checkboxes, radio buttons, wacky fonts, etc.
Keyboard shortcuts, is control the same as command? Can we use something + x/c/v for copy paste on all platforms, should alt + f4 quit the application? Shift tab to cycle document windows? Crtl + f/g for finding or F3? Are there reserved shortcuts we shouldn’t allow the user to override (there are wildly different ones on each platform).
All sorts of special widgets, buttons with drop downs, search bars, toggles, weird things in listviews, drag and drop behaviour etc.
That’s just desktop platforms, it gets weirder on iOS and android.
We tried to wrap all these things so you could just have a “toolbar”, “ menu”, and a variety of widgets and the platform would work out what to do, but as soon as you go past the basic common functionality you get a leaky abstraction.
After 10 years of porting in this manner I (and most of my ex-colleagues) are of the opinion that you can create the business logic in a cross platform way, but the GUI should always be written specifically for the platform. You can even do tricky stuff like write the core in C/C++ and then use the NDK to call into it from your Java Android code, Objective C and obviously Windows/Mac/Linux have no issues calling it either. If you want to avoid using Win32 directly on Windows, you can even create a Windows specific library that your applications use, but never try and port this to other platforms.
Your recommendation is exactly how we built software for all 3 desktop platforms at VMware and it worked pretty well.
This option is always rejected out of hand, but I think we should at least ask what percentage of our program relates to drawing things in windows? Like it seems if, theoretically, you wouldn’t object to writing 3000 lines of cross platform GUI code, you shouldn’t object to writing 3x 1000 lines of GUI code.
At the last place I worked we had a file mac/windows.cpp in our cross platform library, it alone was something like 3-6000 lines. It was on Mac and was the base class for about 10 other window classes and all those windows classes and probably 20 more “widget” existed on Windows, Linux, Android and iOS too. There was other functionality in the library too such as networking, filesystem, audio, video, graphics, telephony, a lot of the code in the other areas was more cross platform, but there must have been millions of lines of code in total.
That’s a bit larger than the programs I was considering. Hopefully you had more than a few 1000 lines of application code to go with your million line portability layer. :)
Or did I read that wrong. You had a million line application with 6000 lines of portability per platform? That sounds pretty reasonable to me given the scale of the application.
Each application was an additional 4,000-20,000 lines perhaps, depending on the application. Each application also picked and chose each file it wanted to use from the library so most of the applications only pulled in say 1/3 of the total library. A few of the applications definitely pulled in close to 100% of the code for the platform they were being built on.
Well, then there is a question that when I write a program in Lazarus (on Linux), I don’t expect to have to test the GUI code separately on Windows.
1×3000 lines are probably easier to keep agreeing to each other than 3×1000, and cross-platform approach promises to reduce the amount of time you need to spend fixing things outside the preferred platform.
“when I write a program in Lazarus (on Linux), I don’t expect to have to test the GUI code separately on Windows.”
I think that is just the nature of the beast. Even if you took the best, most cross platform, hit compile and it just works framework, I think you would still need at least minor testing. If you look at either Java Swing (or whatever the kids use these days), QT or HTML5, they are meant to be quite consistent, but as we know there can be some quite large differences between each implementation.
Some testing is needed, but in most cases it is either obviously broken in all the places using some feature, or working correctly — so some testing is of course required, and it is useful to open every screen, but silently getting slightly out of sync is way less likely when writing cross-platform code than in the case of 3 independent GUIs.
I like this option actually because it kinda forces you to push back on GUI dependent parts thrown into your code further and further.
Especially if you already plan to tailor your application to each platform’s norms!
I ran into the same problem when I was writing the launcher/updater for my game.
All the normal GUI toolkits are just appalling, hundreds of thousands of lines of code to put pixels on the screen is nuts.
I ended up going with IMGUI because:
There’s always the “separate the logic of your app into a service that communicates with a GUI via named pipes” or something. Makes instrumenting tests, exporting your code as a service, and privilege separation easier, but obviously makes other things harder.
That approach still needs a cross platform GUI to write the thing your code communicates with.
I meant write three platform-specific UIs, plus because of the abstraction maybe a CLI interface and web interface too. :)
I think the core of the complaint is that there’s nothing worthwhile that allows you to avoid doing it three times.
The higan multi-system emulator¹ comes with a cross-platform UI library named “hiro” that wraps GTK+2, Qt, Win32 and Cocoa, so you get native controls and text-rendering (not just look-alikes) on every platform. higan’s total executable size (on Linux) is 6MB; hiro.o is only 1.6MB.
The downsides are that it doesn’t support every type of widget (only ones that are available on every platform), and it uses deep C++ wizardry to provide a safe, ergonomic API, so good luck using it from any other language, or even older C++ compilers. Also, there’s not really any documentation or API stability guarantees.
Apart from that, though, it seems vastly better than any of the competition listed in the linked article.
¹: higan and its author were recently in the news about a lost shipment of PAL SNES games, and a few years ago he wrote a well-regarded Ars Technica article about emulation.
The author says “Qt is not the answer to everything,” but I’d really like to see him delve into why.
Depending on the exact requirements, you could spin up a lightweight embedded web server, and open the system default web browser navigated to the embedded web server.