Speedy Desktop Apps with GTK and Rust
nora.codes
nora.codes
At the end the result is good, but the code looks awful.
That being said it's been a while since I've used gtk-rs so it is entirely possible things have changed. I'd love to be corrected if that's the case :)
This is such a pain that even Gtk-rs samples have macros to work around cloning widget state into callbacks.
From my point of view language ergonomics still need to improve for Rust to actually be a candidate for GUI development, versus what the GC based languages (RC and tracing GC) offer out of the box with their UI kits.
Unless one envisions it just to take C++'s role of visualization layer and integration with graphics drivers.
Ownership defines who frees who. Parentage defines control nesting. References should to be handled via an indirection (e.g. names) and a protocol so that referees get notified when referents die. The indirection means that components get wired up in a late bound fashion; and the late binding means the gubbins for a protocol can be in place by then.
This stuff was figured out reasonably well with Delphi's VCL.
Even simple stuff like what Apple has demoed with SwiftUI designer can be a challenge, as you cannot just drag stuff around without changing the ownership semantics.
Naturally Swift has the advantage that Rc<RefCell<T>> is implicit, so it isn't as if the cost is magical gone.
However having to deal with it explicitly is a hard sell for anyone used to the comfort of GUI tooling.
So I imagine Rust is an easier sell for doing the low level stuff of a GUI engine, with what 90% of the devs using some managed language on top.
Basically what is happening to C++ on current desktop and mobile OSes, although for different reasons.
Or what is being done to Firefox actually.
Since then it got better libraries which reduce lots of the verbosity (e.g. gtk-rs), which is great. But the language itself probably won't change too much to better accommodate that use-case, since what things things painful here are the core features that prevent issues elsewhere.
I think we have to accept the fact that for different kinds of problems different programing languages are preferable instead of trying to find a single solution for all problems.
For UIs I think a naturally garbage-collected or refcounted language with reasonable support for dynamic dispatch is a lot easier to work with. In addition to that a restriction towards a single thread or even an inbuilt event loop can avoid bugs, improve interoperability between libraries, and reduce the amount of boilerplate and application-level design decisions even further.
If we take those properties we get the most common languages for GUI apps: Javascript/Dart which have single-threaded runtimes, and C#/Java/Kotlin/Swift as general-purpose languages which are more powerful but require an eventloop on application/library/framework level.
Those properties actually also expand to other very stateful and very concurrent applications. E.g. stateful network servers (something like Redis or a websocket server) have similar implementation challenges, and therefore are currently not very straightforward to write in Rust either (compared to e.g. in node.js).
This seems to work OK in SWT, so what's the problem in GTK/Rust? Are there some particular categories of objects that don't fit into that hierarchical model and need to be handled with a GC?
(Those objects would presumably be regular Java objects in an SWT app and handled by Java's GC.)
[1] https://www.eclipse.org/articles/swt-design-2/swt-design-2.h...
"Appendix: What the proposal won’t fix"
http://smallcultfollowing.com/babysteps/blog/2017/07/11/non-...
So one could say, it is a case of holding it wrong, and a Rust UI toolkit needs to be written from scratch. Which might be ok, but it does require some support for market adoption.
Having said this, Gtk-rs now has some help in the form of relm, exactly to overcome this issue.
I'm not really sure this can be reconciled with any arbitrary C library. One of the benefits I see from Rust is the ability to be unable to do unsafe things without explicitly stating you know what you're doing, thus preventing various classes of errors. But it feels like if the ownership model just doesn't fit with Rust's model that allows those guarantees to be made in the first place, it won't work. You can't write just anything in safe Rust without limiting the things you can do, but C libraries don't have such limits.
It might take creating new ways of representing GUI objects before the best model for that problem arises for Rust. I don't think libraries like GTK were designed with the lessons in safe memory management Rust learned from years after the fact in mind.
[0] http://way-cooler.org/blog/2019/04/29/rewriting-way-cooler-i...
It also might be that Rust is not the right language to write high level UI logic in at this time, and a GC'd language would be more appropriate. That's fine too. One of the strengths of Rust is its interoperability with other languages. C and C++ are certainly not the right languages to implement high level UI logic in, for example.
Let me be clear: Given the choice between Rust or C++ for writing Photoshop, I will pick Rust every time.
Apparently because that is the only way to sell MFC/ATL holdouts to WinUI, and allow WinUI to be called from classical Win32 without too much overhead, and also because .NET Native ideas will be migrated to .NET 5.
C++'s problem is that the path of righteousness is too narrow, but with heavy cultural idioms and norms, you can keep a lot of the people safely hemmed in, while retaining all the escape hatches.
Empirically, no, you cannot. Nobody has succeeded at writing memory-safe C++ at scale using normal software development practices.
After working with Vue/React, doing GUI apps "the old way" feels like writing quick-sort in assembly language.
You will notice that it is surprisingly simpler than React.
React got so popular because React implemented it very nicely in the web browsers, not because it brought new concepts.
When using C++, looks like you have to use things like QAbstractListModel https://qmlbook.github.io/ch16-qtcpp/qtcpp.html#a-simple-mod...
Even without C++, there are things like ListModel and ListElement https://qmlbook.github.io/ch07-modelview/modelview.html
This is a far cry from React where you just use language-native data structures directly (you only need to do mutations in specific ways).
As far as I can tell, you also can't just use native language constructs like functions/ifs/.map, etc. to compose the UI elements. Instead you have containers like Repeater.
It seems very different to me compared to React, like built around a significantly different philosophy.
Even defining what a "native" type is seems like it would be fraught. I guess the c++ way would be to accept begin and end iterators - but of what type?
When I imagine how a C++ implementation of something like React would look, my first thought is a bunch of functions which take whatever custom types they need (props), and return a tree of UI primitives (analogous to DOM element representations). Nothing that would require inspecting types.
Think about it. How do you iterate the tree? What even is a tree? The typical c++ answer depends on templates and iterators within the template. Which means they wildly change at compile time. It is clumsy for a shared library to deal with this, or, say, bind properties from an XML file or similar parsed at runtime.
Hence, it would make sense for a c++ solution to impose its own format or base class for trees or models. (Perhaps a template could help to wrap it.)
There may be some limitations and some things may need to be done differently because of C++, but from a brief look it should be basically possible. The UI library doesn't need to iterate through props, those can be a single opaque structure from its point of view.
I tried doing something similar in Kotlin a few years back and from what I remember there wasn't any reflection used for that part. https://github.com/peterholak/mogul
I'm also still not convinced that Kotlin/Native will catch on in any significant way, but we'll see.
WPF still has the same kind of approach and to be terribly honest, Silverlight, as hated as it was, did it before React.
It adds single 5mb DLL to the equation.
Yet it allows to build native applications where UI structure is defined by HTML, style by CSS and reactivity by script or by Rust (or by C++, Go, Python, etc.)
"Sciter makes GUI programming genuinely fun!" https://sciter.com/forums/topic/attach-detach-behavior/#post...
However it has one major issue : it's proprietary... And that's a no go for many project / companies.
I would not make my entire business depend on a blob which I have no control on it.
You can buy Sciter License.
This way you a) will solve the problem and b) will help further Sciter development.
Otherwise you don't really need Sciter sources.
You protect your business, That's your choice. But it will make me stay with Qt until better OSS alternative.
As of HTML: most of HTML5 constructs (I participated in HTML5 spec development at W3C as Invited Expert)
As of CSS: CSS2.1 in full. Some practically useful modules of CSS3 - transitions, transforms, etc.
I haven't added FlexBox as I think it is an architectural disaster - will not survive on the long run. Instead Sciter offers "flow and flex units" module: https://sciter.com/docs/flex-flow/flex-layout.htm that covers as FlexBox as Grid in unified manner. Yet check this: https://terrainformatica.com/w3/flex-layout/flex-vs-flexbox....
Yet, I've added quite a lot of HTML/CSS features that are the must for specifically desktop UI:
- <menu class=popup> and <popup> elements and their CSS support - windowed DOM elements that are rendered outside of main window canvas.
- <frame type=pager> - print preview and print feature.
- view.dialog("some.html"), view.window("some.html"), view.msgbox("some.html") - HTML defined windows and dialogs.
- <htmlarea> - native WYSIWYG HTML editing widget.
More on this: https://sciter.com/developers/for-web-programmers/
I only very rarely do CSS, but from a user perspective it's a huge improvement to what we had before.
Are you talking about implementation complexity?
2. FlexBox introduces 12 (sic!) new properties in already overcrowded CSS property map. But as demonstrated by Sciter that can be achieved by just one property `flow` and flex units.
3. Flexbox and Grid are conflicting in the sense that the flexibility (as a feature) is defined in two different ways: separate properties (FlexBox) and 'fr' units (Grid) - overall CSS architecture becomes a zoo. Yet CSS has that famous 'auto' value that in some cases is just 1fr ( 1* in Sciter terms).
4. FlexBox is applied through 'display' property that is conceptually wrong. 'display' specifies how the element itself is replaced among its siblings but flexbox is rather about layout of element's children. These two entities are orthogonal. Example:
display:list-item; or display:table-cell; cannot be flexboxes. Just because of architectural specification error but physically nothing prevents <td> to use flexbox layout for their children.
5. Flexbox arrived too late. We started talking about the feature 12 years ago on www-style WG at W3C. And all these years Sciter already used flexibility (the must for desktop UI).
More on this: https://terrainformatica.com/2018/12/11/10-years-of-flexboxi...
Don't get me wrong, it's _miles_ better for web layout than the old systems, but since Sciter seems to be focused on application-style layouts, it makes sense to prefer a layout system that can better represent common patterns in that domain.
Also, if you plan on go responsive, the required flex wrappers kind of hold you back when you need to reorient a bunch of your layout to fit a vertical screen (or horizontal, if you're doing mobile-first), while Grid's `grid-area` is beautifully flexible in that regard.
TL;DR: If you're gonna have to have Grid, then just having Grid is perfectly fine as it can do everything Flex can and more.
McAfee - not.
But these AV and security providers - yes:
- ESET (NOD32 Antivirus)
- AVAST Antivirus
- AVG Antivirus
- Bitdefender Antivirus
- Comodo Antivirus
- Dr.WEB Antivirus
- WEBROOT Security Antivirus
- 360 ( 360.cn ) Antivirus
- Secui antivirus
So Sciter's code works on any PC that has any of these installed.
[0]https://github.com/revery-ui/revery [1]https://github.com/cljfx/cljfx
https://github.com/fn-fx/fn-fx
Fn-fx is a more complex beast and no one seems to really know how it all works internally except the creator who isn't maintaining it.. so unfortunately it's in a semi unmaintained state. But the interface was a bit cleaner when I tried it
CSS had to get WPF grid design in order to not be a poor table sibling in what concerns layouts.
While WPF is backed by DirectX, CSS requires playing with Z order, so that some browsers might eventually put the rendering into the GPU, but one needs to take care because space is limited.
While I can render anything down to pixel level control, if I wish to do so, I am still waiting for Houdini and worlets to actually become available.
And the whole template language with events and theming for low level customisation of control behaviours? Nowhere to be seen.
CSS layout was indeed a struggle many years ago, but now with flexbox I never failed to put stuff exactly where I wanted, and I barely understand it. And the new shiny thing, CSS Grid, is supposedly even better at controlling layout.
With the same source code, my applications are natively compiled to:
Linux, Windows, MacOS, Android, iOS, QNX, Browser (WebAssembly / WebGL Streaming)
And you are free to theme it as you like, one example:
Any framework that comes with tooling support out of box is a plus for me.
Hence in what concerns Web, I care mostly about WebComponents, CMS middleware with page designers and SPA frameworks like Angular.
CRUD apps is a really big application space to cede, though, I totally think tooling is worth it.
- Write the WPF view code in any .NET language and expose the classes to COM as COM Callable Wrapper (https://docs.microsoft.com/en-us/dotnet/framework/interop/co...)
- Similar way, but using Windows HWND messages instead, https://docs.microsoft.com/en-us/dotnet/framework/wpf/advanc...
- Or if using Windows 10, given that UWP is COM vNext, and Microsoft is merging both worlds, use XAML Islands, https://docs.microsoft.com/en-us/windows/apps/desktop/modern...
I wrote my first GTK+ program in my high school years in 2014-2015, and I can't think of any native toolkit ever approached the ease of work of GTK.
Which other native UI toolkits do you have experience with to make that claim?
Here's very simple to implement change which saves dozens of MB of IO bandwidth every startup: https://github.com/Microsoft/vscode/issues/61343
"We will very likely not do this."
I remember someone telling me that it’s not as good a fit but I can’t remember why that is.
The QtSharp project used technology that couldn't really address the problem (MonoCppSharp).
QML.Net is different. It is purely a QML integration (no c++ wrapper), using a C interop.
There is extensive unit tests for QML.Net, including garbage collection tests.
I consider it segfault-proof.
It's currently used in production on embedded medical devices: https://medxchange.com/4klear-all-in-one-camera-recorder/
I strongly believe that Microsoft made a huge mistake not making .Net WPF and Silverlight cross platform and open source it. they would have made money by selling the Visual Studio IDE,
I run it on embedded Linux.
Travis and Appveyor cover tests for Linux/Mac/Windows.
They provide some tutorial links in the README.
The usual workaround is to wrap the C++ API into a C API.
It does: the "Itanium ABI" (initially for IA64, adopted for other architectures).
The minor complication you get is that the C/C++ ecosystem uses char, short, int, long, and long long to determine types, while most other languages use a more sensible i8, i16, i32, i64 system. This means you can't use the native type system of your target language as the base for mangling, since i32 and i64 do not map cleanly to int, long, and long long. (Doesn't help either that pre-stdint.h libraries for defining target-independent i64 types may have chosen a different value for i64 than stdint.h).
The real problem is that a lot of the functions you would wish to call don't actually exist in the binary library you're linking against. Inline methods are frequently excluded as linkable targets, and you often don't want to link to them anyways, because they're meant to be inlined (think something like std::vector<T>::operator[]). On top of that, templated things are rarely instantiated (and have code generated for them) until their point of use).
If you restrict the API to a subset of the language, you can make C++ ABI just fine. My favorite style is abstract interfaces.
For the GUI example, look at WinRT. It exposes very high-level functionality, expressed in C++ as IUnknown-derived interfaces. These interfaces can be consumed or implemented by any compilers, or even other languages.
Such APIs work well even for very performance-critical code like DirectX or Direct2D. But there's downside, such APIs is not the most idiomatic form of C++: no exceptions, no iterators or other template shenanigans, no RTTI, no standard collections not even strings. All that stuff needs to be replaced with some equivalents.
When I only have C++ clients, I don't usually inherit from IUnknown, instead making an abstract base class with virtual destructor, and using std::unique_ptr smart pointers instead of CComPTR.
Name mangling wasn’t originally standardized, so every compiler did it differently, and now it’s too late to standardize.
I wrote a .NET Core/QML interior layer.
No idea why anyone would want to do this, because it seems you’ll be hated by half the Linux users for using gtk, but seems cool for personal projects.
I did not see people asking for GTK apps to be ported to Qt (if it happens is much lower then the rewrite it in rust phenomenon) , there were a number of projects that switched from GTK2 to Qt instead of GTK3 because they re-evaluated the toolkits and decided Qt was better for those projects.
Actually this is a real benefit.
It means no one will show up and convince people on your project to waste time packaging your software for [pick a Linux Distribution].
Now instead of getting user reports from a hall of mirrors of various packages for various distros with various states of dependency disrepair, you've got one central source of truth.
Anyway if you don't have a Linux system and your program is open source then the useers should contribute packages. For closed source programs then you are fine with a cross distro method, like I seen small games made with Unity,Unreal,RenPy,RPG Maker that are also packagted for linux into a .zip archive and nobody complained and asked for special packages.
There are assholes Linux users out-there but is the same in all communities where you have entitled people that think their opinions are the truth.
Due to desktop Linux fragmentation you will never please everyone, but everyone will feel entitled that your care about their snowflake distribution.
It's kind of embarrassing (or a testament to hard of a problem that it is) the state we are in because of (IMO) Microsoft/Apple/Canonical.
If they had a really, really good GUI foundation, it'd be a quick job to do a minimal Slack or Things for macOS clone in C++/Rust.
Edit: Seems people get irritated about what the users want. But that's not really up to us to decide as coders...
WPF can also be styled extensively, at least in theory, but this is much harder to accomplish. MS has developed Blend to assist with this, but you still need a deep knowledge of the internal hierarchy if elements of a widget to get good results.
Given the choice I would prever native UI any day.
The smart phone design aesthetic has taken over and is now constantly being used in places where the whitespace is a waste and the giant buttons make things terrible. Canonical may have finally given up on "convergence" but few other companies have woken up.
No, both those examples are terrible. The 300 baud modem because of the low speed and the smart phone LTE connection because the round trip time is highly variable and TCP backoff applies a heavy penalty. Additionally, most smart phone internet connections don't have ports or even an ipv4 and are behind Carrier-NAT. Given that, I'd prefer the 300 baud modem.
> If they had a really, really good GUI foundation.
It is not true at all. They already have really nice GUI foundations. Brining the web tech to desktop apps gots so popular because the web is won so that devs are forced to make web apps, not because it is better than the "traditional" GUI development.
Do I want to code in 3 languages, let the app swallow copious amounts of RAM and break behaviours that users expect? NO. Will they do a hard pass on software if it's not pretty enough? YES.
If you want to chalk it up to not enough good themes in QT/JavaFX, that's fine two less languages and less packaging for them to worry about. But until those themes exist that makes the user turn its head...
But we need them because they're the only cross-platform and device-independent solution.
If you're going to allow a runtime as bloated and complicated as a web browser to count as "cross platform" then you'll have to admit that Java met those same criteria 2 decades ago.
Java doesn't even come pre-installed on a normal machine.
It's not about technical considerations, it's just that one cross-platform runtime has won.
Speed doesn't come into it that much. Current desktop systems are fast enough such that most GUI manipulation just isn't a speed bottleneck, except for things like realtime graphics or something.
Complex web UIs in general have perceivable latency and are perceivably sluggish for me. I noticed how bad the problem is when I noticed some latency in responding to mouse clicks in a React application I was developing. After unsuccessfully trying to bring it down, I compared it to a handful of other web apps I use routinely, and then a handful of native desktop apps. When I did that it became depressingly obvious how conditioned I am to the poor responsiveness of these UIs.
For the record, this is all on a 4-core i7 machine with an NVMe SSD and 16GB of RAM. It's fair to say that the average machine where these are used is far lower.
And obviously, most users don't seem to care that much. Otherwise you wouldn't have these web applications. Developers would spend the multiple amounts of work, gladly paid by their employers and investors and gladly reimbursed by the users through licensing fees, necessary to make hot-to-the touch user interfaces for everything we use computers nowadays.
Rust drives all of that down somewhat. Also webassembly will bring the ability to trust almost-native machine code.
Most of it is about trust, and you'll see certain web APIs built around asking for permission to access the camera, or image files or whatever.
Desktop apps often can't really trust each other. It's not a problem right now, but if you could XSS something into a game or social app which, with user-level permissions on your desktop could remote-control (for example click-simulating) your electron banking app, that would be really bad. Just a contrived example, but with great power comes great exploitability.
For the electron apps I use, they are generally available online as a website anyways, so I just use that, and get the whole common instance thing for free.
I think this isn’t really a problem of Electron, but more to Chromium. We bundle python inside the binary and it’s fine. I don’t think I’ll hate command line programs that embed nodejs inside the binary.
It’s the Chromium that’s problematic, and just by switching Chromium to the native WebView will make Electron apps much, much more lightweight.