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.
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.
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)?
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.
No, it doesn't, and I'm afraid you have missed the point. It makes no sense to compare programming models on two different extremes of the abstraction scale, and make conclusions about the complexity based on that comparison.
One is an ultra-high-level library for immediate mode rendering (which is a model that makes every possible tradeoff towards interface simplicity and optimizes for a very narrow set of applications, such as videogames and other programs that need to continuously render changing frames on a window-as-canvas), and the other is an extremely low-level event-driven protocol for window management, designed to be useful in the widest possible variety of scenarios. It makes no sense to compare the two.
[...] sheer unneeded complexity of Wayland [...] It is just made badly
I'm very sorry, but none of this was demonstrated.
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.
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).
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.
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++.
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).
Strong disagree. Apps are used orders of magnitude more than they are compiled, runtime performance should always be the priority if you care about your users
That doesn't mean I should make my own life miserable by having to wait several seconds between iterations. I'm pretty sure that will lead to me building a worse, less performant product overall.
indeed, and in my case I am considering "just writing something myself" - this solution will also be awful, but it is a road I am willing to explore. Can "just" replace Qt's mechanism from eglfs-kms to only create the dmabuf (and not do the modeset), then pass the descriptor for this buf to my yet-to-be-made compositor which will render this in a texture. Only difficulty I see (famous last words) is handling geometry/window resizes, and the fact that only Qt programs will work with this system, but that is fine.
Should we classify Wayland as an example of the second-system effect in a different form?
The creators actually threw away a lot of the idea from X as not being in scope, made something simple, but largely inadequate. Hence the slow adoption. Then in having to add extensions to the protocol, got the second-system effect in variant form?
Possibly Wayland should have been the 'throw one away' instance, and the learning from it used to produce a v2 with the missing pieces, rather than chuck everything in the extensions?
mrexodia | a day ago
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?
snazz | a day ago
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.
moverest | a day ago
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.
Cloudef | 22 hours ago
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.
bsandro | 7 hours ago
Are there any sources for that claim? I'm quite curious but wasn't able to find anything meaningful.
intelfx | 19 hours ago
So, the author uses a super-high-level, super-primitive
SDL1-esqueimmediate 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.
bsandro | 13 hours ago
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.
intelfx | 10 hours ago
No, it doesn't, and I'm afraid you have missed the point. It makes no sense to compare programming models on two different extremes of the abstraction scale, and make conclusions about the complexity based on that comparison.
One is an ultra-high-level library for immediate mode rendering (which is a model that makes every possible tradeoff towards interface simplicity and optimizes for a very narrow set of applications, such as videogames and other programs that need to continuously render changing frames on a window-as-canvas), and the other is an extremely low-level event-driven protocol for window management, designed to be useful in the widest possible variety of scenarios. It makes no sense to compare the two.
I'm very sorry, but none of this was demonstrated.
bsandro | 7 hours ago
Okay, touche.
gir | 23 hours ago
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
libwaylandtwice (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.
giodamelio | 22 hours ago
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.
https://github.com/giodamelio/wvisbell
gir | 3 hours ago
wow - thank you! i have just two½ requests:
then, please get in touch to claim your reward. my email is in the last sentence on https://gir.st, or a PM here is fine too.
jcelerier | 21 hours ago
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
moverest | 23 hours ago
For this you'd be looking at using the
wlr-layer-shellprotocol 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.dpc_pw | 21 hours ago
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.
mort | 19 hours ago
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 wgpuadds 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++.dpc_pw | 14 hours ago
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).
riki | 12 hours ago
That's why wgpu adds several seconds of compilation time to your project. Arguably a worse outcome than slightly slower runtime performance.
jcelerier | 8 hours ago
Strong disagree. Apps are used orders of magnitude more than they are compiled, runtime performance should always be the priority if you care about your users
riki | 7 hours ago
That doesn't mean I should make my own life miserable by having to wait several seconds between iterations. I'm pretty sure that will lead to me building a worse, less performant product overall.
dpc_pw | 4 hours ago
As I said, lots of the extra compilation is due to multiple backends.
mort | 11 hours ago
I wasn't talking about a runtime performance cost. I was talking about the things I laid out.
Of course it's possible in principle.
jmtd | a day ago
Entertaining and depressing in equal measure
orib | 14 hours ago
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.
dsc | 11 hours ago
indeed, and in my case I am considering "just writing something myself" - this solution will also be awful, but it is a road I am willing to explore. Can "just" replace Qt's mechanism from eglfs-kms to only create the dmabuf (and not do the modeset), then pass the descriptor for this buf to my yet-to-be-made compositor which will render this in a texture. Only difficulty I see (famous last words) is handling geometry/window resizes, and the fact that only Qt programs will work with this system, but that is fine.
zie | 3 hours ago
You might take a look at Arcan desktop. Here is an article about the low level API's available: https://arcan-fe.com/2019/03/03/writing-a-low-level-arcan-client/
At the very worst, it might give you ideas for your own!
dsc | 3 hours ago
cool, it's why I wrote the comment - for other people to either say I'm silly or perhaps get linked to some nice blogposts like these, thanks!
landon | 12 hours ago
This seems like a failure of the type system or binding structure. Why are all these illegal states representable?
dfawcus | 7 hours ago
Should we classify Wayland as an example of the second-system effect in a different form?
The creators actually threw away a lot of the idea from X as not being in scope, made something simple, but largely inadequate. Hence the slow adoption. Then in having to add extensions to the protocol, got the second-system effect in variant form?
Possibly Wayland should have been the 'throw one away' instance, and the learning from it used to produce a v2 with the missing pieces, rather than chuck everything in the extensions?