I Hate Programming Wayland Applications
55 points by gioele
55 points by gioele
Don't get me wrong: I'm not expecting that e.g. DPI aware mult-monitor applications using several input devices, mixed refreshrates and hot-plugging of devices "just works"
In my opinion this is exactly what you should expect. What’s the point of an abstraction if it cannot handle complex cases like that?
I agree. I wonder if the design of these abstractions works well for creating the Wayland backends for Qt and GTK or SDL (since GUI toolkits and libraries like SDL need to handle those complex cases), at the expense of making simple applications harder to write without a toolkit.
I share the author's frustration.
It seems like Wayland was never designed to build a desktop experience but as the most modular composition system and then the desktop part was added as an afterthought and on a ad-hoc basis. Thus you end-up with all this idiosyncrasy. I can think of at least three ways to handle scaling and you'll probably need to implement them all as a fallback. Let's not even get started on fact that different compositors implement a different set of protocols and they sometimes behave differently. At this point, I'm not even sure there's a good way to fix this mess.
To be fair, if you write your application on top of a toolkit (e.g. GTK, Qt) or a library (e.g. SDL, winit), it hides all of that. The downside is that then you're then reliant on them to support all the Wayland features you need.
It indeed wasnt. Wayland started as thing for car dashboards. weston and xdg-shell was more of a demo. Gnome did all desktop stuff on top of DBUS. Desktop was always a afterthought.
I share the author's frustration, because I've been at this exact place.
I have this tiny C/X11 program, xvisualbell, that simply blinks your screen (all displays) to get your attention. Notice how the whole program fits on a single page, or under 50 lines of code including blanks and comments.
I attempted to port this to libwayland twice (using hello-wayland as a starting point, and - embarrassingly - even an LLM). Not only did I not get it to work, the code to draw a simple window easily blows up to 300-400 lines (while missing any of the xvisbell "features").
Since it doesn't hurt to ask: If someone could port this thing for me, I'd love to pay you 100€, or a charity of your choice double that.
I was just wanting something like this a few months ago. You inspired me to throw Claude and the problem and we got something that seems to work fine. I am no C programmer, but I checked it for all the footguns I know and linted it. YMMV though, don't blame me if your monitors catch on fire or something :).
It really proves the article true though, even the simplest implementation is way way way more complicated. Not to mention all the generation stuff that would have taken me forever to figure out myself.
the one I used that got me somewhere is : https://gaultier.github.io/blog/wayland_from_scratch.html#
it basically just draws text in a way that does not depend on any toolkit: https://github.com/ossia/score/blob/master/src/linuxcheck/wayland.cpp (to warn users of missing dependencies that their toolkits may have before my app runs). Almost 800 lines (although not all are necessary for this use case).
X11 version: https://github.com/ossia/score/blob/master/src/linuxcheck/x11.cpp
For this you'd be looking at using the wlr-layer-shell protocol to have a surface ovelayed over the whole screen. That's if you're using a wlroot compositor or KWin (KDE). Mutter (GNOME) doesn't support it so you'd have to go for an extension (I've never tried though).
For examples you can base this on, the simplest project I can think of would be slurp. You can also look at a project of mine that also makes use of it, wl-kbptr, but it's more complex — though most of the Wayland stuff you'd need are in the main file. I'd also advise you to look at the Wayland Book which explains the different concepts.
So, the author uses a super-high-level, super-primitive SDL1-esque immediate mode drawing library under X11, and then complains that he cannot replicate the simplicity when using the lowest-level API possible under Wayland (roughly equivalent to raw xcb)?
Color me unimpressed.
It makes sense though in comparison of novelty and modern requirements; one could compare raw X11 and Raylib and the latter is obviously much more easy to use, but that's why the article states that X11 is 40 years old at this point and it was created for completely different desktop requirements.
So it actually makes sense to compare modern framework for displaying graphics on your screen (raylib) and modern approach to display graphics on your screen (Wayland). You cannot write off the sheer unneeded complexity of Wayland just because "it is old" or anything, it doesn't have excuses. It is just made badly.
Entertaining and depressing in equal measure
The internal programming model is not a big problem as long as it has no issues preventing better higher level primitives. Lots of people complain about Vulkan in a similar fashion: "so much work to do things that were simpler in OpenGL".
The thing is - you typically don't need to use lowest layer available. If it's possible to build nice higher level libraries, use these and be happy. Just like we all don't need to write machine code by hand.
Lots of tech is best when it has inconvenient but precise and efficient lowest layer plumbing and then many choices of higher level layers with good UX.
The thing is, using higher level abstractions has a cost.
I've made some software which uses OpenGL. I won't pretend OpenGL is a great API, but it's fairly simple to work with, and historically, it has given me access to all features of all graphics hardware; and if some driver or hardware has some quirks, it's easyish to work around those quirks because it's all my code.
I could never do the same with Vulkan. So, I'd have to pick a higher level abstraction. Tell me: which higher level abstraction over Vulkan should I use, which provides access to all available features including vendor-specific extensions, and gives me enough freedom to work around hardware/driver quirks without patching the abstraction layer? I'm not sure such a thing exists. The closest thing is probably the Rust WebGPU stuff but that's a gigantic abstraction layer (just cargo add wgpu adds 124 dependencies!) which hides all the details from you (it necessarily has to, since it supports Vulkan, Metal, DX12 and OpenGL back-ends). And it's naturally Rust-only, so it's not very applicable when I'm writing C++.
Oftentimes higher level abstractions don't have a cost, e.g. because compiler can compile them out. Or the cost is negligible.
https://www.youtube.com/watch?v=7bSzp-QildA is a good explanation why Vulcan is a more powerful and clean API.
The biggest problem with non-OpenGL is the fragmentation, as all platforms (kind of) could support OpenGL back in a day, but now there's: still Vulcan, OpenGL, Metal, webGL, DX. And most people want to write code once and run everywhere, so you need not just a wrapper, but an abstraction layer over all of the backends. So no wonder wgpu brings in bunch of dependencies. Also - counting dependencies is a bad way to judge how "heavy" an abstraction is. Most of these dependencies will not be compiled and/or executed. The actual runtime overhead might be near-zero.
Anyway in principle it is possible to write a simple wrapper that simplify the API. E.g. https://github.com/charles-lunarg/vk-bootstrap . But I have never used it - I'm not even C++ dev (for a long while).
Oftentimes higher level abstractions don't have a cost, e.g. because compiler can compile them out. Or the cost is negligible.
That's why wgpu adds several seconds of compilation time to your project. Arguably a worse outcome than slightly slower runtime performance.
This is your regularly scheduled reminder: one thing being bad doesn't imply something else is good.
It's entirely possible that both Wayland and X11 are awful.
This seems like a failure of the type system or binding structure. Why are all these illegal states representable?