Haskell wlroots bindings

I’ve kind of stalled out here because I injured my arm somehow and I was having pains when typing. I’m healing slowly, but I haven’t contributed to WLHS in a while because the little free time I can spend on personal projects is being spent on learning about web development in Haskell (my day job is a Frontend developer “React andy”).

I’m still excited about a Wayland Window Manager written in Haskell so I’d like to continue to contribute but like I mentioned in my previous post the project kind of stalled out.

Oh, I’m really sorry to hear this! Hope you get better soon.

For my part, I’ve also pretty much stalled out on this project. I haven’t gotten as much time to work on it as I would have liked, and it’s difficult to work on because I know very little about writing C bindings and almost nothing about Wayland. If this is to be successful, I think this project should be led by someone with experience in at least one of those areas.

It’s C++ and appears to use C++ features pretty heavily, which would make bindings difficult; it would be necessary to wrap its APIs in C bindings first, as it’s effectively impossible to bind C++ directly and even if we could, working directly with C++ objects from Haskell would be difficult at best.

Someone just pointed out GitHub - michaelforney/velox: velox window manager, now I’m wondering if that would make a better starting point.

I don’t see why that would be any better as a starting point?

Actually I should have linked to https://github.com/michaelforney/swc, the compositor bindings. They stand some chance of being easier to work with than wlroots, although apparently some things would need to be added to them (wlr-layer-shell was mentioned).

1 Like

My wrist is getting better and I hope to get back in the saddle soon. With some direction I could start working on something, or I might keep working on wlhs for learning.

1 Like

Great to hear @anarchymatt! Hope you feel better soon.

(If you want me to give you push access to the existing wlhs repo, I’m happy to do so.)

Thank you! I’ll think about it. For now I’m just going to play around and push to my fork.

I kinda want to see how close we were to getting TinyWL running.

Something that was bothering me before I had to take my break (I was having finger and hand pains just from doing my day job, after a lot of stretching and being careful about my typing posture I’ve been slowly getting better), was a sense of a lack of direction.

The vague goal was to make bindings to Wlroots so that we could unblock the genius madlads behind XMonad (awesome!) from porting it to Wayland.

Some of the problems that we faced were:

  1. We didn’t (and still don’t) understand just how much of the wlroots API surface area we need to cover. If we are meant to cover all of it, that’s a big ask. We had 3 people when it started, and it went down to 2 and then to 1.
  2. I’m not a C expert (A have a 4 year CS degree where our primary language taught in school was C and C++, which helps) so I don’t understand the ‘safe’ way to bind to some of these structs. Particularly, structs that have a ‘union’ in them. I just couldn’t seem to think of a way to get the type represented in Haskell land, besides maybe making a different data type per entry in the C union.
  3. We never decided what t do about using a template language to make writing the FFI code easier. Dylan and Brad had discussed using Ninja (I think that was the name of it, a Python templating library), but it was decided that “all Haskell” was the way to go, so they (I think it was Brad) wrote us some Template Haskell that gave us templating capabilities that made writing out the structs and pattern synonyms a bit easier. If Brad and Dylan are out of the project, then I’m not sure what I should do. I could keep the templating language and use it (it does help), or I could just run it and then commit the output as a Haskell source file.
  4. I’m a web dev. I want to learn Haskell and backend web development, so what little “free time” I’ve had (my wrist) I spent on learning Web Dev in Haskell because it’s the most relevant to me. I’m still open to contributing to a Haskell Wayland project, but I can’t give up all of my personal project hours to it.
  5. In general we did not have an FFI expert. I was the least experienced I think (I was reading about the FFI in Real Word Haskell, which I was told is dated), and we had some good input from Burning Witness (helpful but also advanced, at least for me), but we didn’t have anybody that could help us out if we didn’t know how to write bindings to some of the weirder header files that the wlroots project has.

I’m not trying to throw stones or make excuses, I’m just recounting the procession of events as I saw it from my perspective, to try and open a dialogue about continuing the project.

<3

3 Likes

I would guess that besides myself there are a lot of people here with experience in C. From reading through the thread and other posts on waymonad it seems the core roadblock is the bindings?

This is something I’ve been thinking about a lot recently, but I guess for me at least I’m not sure what the requirements or desired outcome is. Do you just want to get the bindings working in any relatively type safe way? Or are you trying to get them to work in a memory performant and totally type safe but also elegant and idiomatic Haskell way.

With the FFI in my experience you can use as little or as much as you like, I mean you could just use them as dumb IO. With C in Haskell you can do all kinds of things with pointers and direct memory management, but this might lead to a world of pain if not handled correctly. I guess with Haskell great pains have been made to abstract away memory management.

Thats not to say it can’t be done well and indeed it might be a profitable thing to do, I think there are some really interesting ideas that could be adopted from C++ or Rust to act as an intermediate abstraction to go from C to Haskell.

But I guess with this it all depends on the project requirements, I can make some assumptions that we would want performant and safe bindings, but it would be helpful to have an explicit explanation of the requirements.

I think what would really help is if you could provide a hard example perhaps a struct with a union, perhaps with the current approach, the limitation and what you would like. I’d be really happy to take on some work, I also have other commitments, but I would be particularly keen to work on some tooling for problems like this because it would feed back into my other projects and goals

I wouldn’t say I’m ‘out of the project’, exactly. If we get someone who knows more about FFI and/or Wayland, I’m happy to continue working on it. But I don’t think I can lead the project as I was attempting to do: it’s a lot of work, in an unfamiliar area, and I just don’t have enough time to do that.

This was discussed earlier. As I recall, we were trying to make the simplest, rawest wrappers as possible. A more idiomatic API could then be built on top of that, but we never even got close to thinking seriously about that.

Being that I have a fair amount of free time (early retirement due to disability) and I now have a personal interest in XMonad on Wayland (my “new”-a-year-ago laptop is QHD, which X11 handles terribly — and I’m all too aware of why even if someone wanted to, they’ll never be able to fix it without ditching the whole X architecture and starting over), I may be able to contribute to this. What I can bring to the table is two of the things you specifically mentioned: C experience, and C<->Haskell FFI.

(BTW, while RWH is dated, the only significant change to the FFI is CApiFFI — which actually brings the FFI back to what RWH describes. ghc’s switch to generating asm directly instead of mutant C to be fed through the Evil Mangler™ broke ccall FFI significantly because calls are made directly from asm, so entry points that are cpp macros, calls to varargs functions, and the like don’t work any more unless you use CApiFFI.)

4 Likes

Oh, unfortunately the thing I don’t have is any real knowledge of Wayland. X11 I know quite well, though.

Not sure that’s the core roadblock, so much as a really big yak that needs to be shaved before we can do anything else: the Wayland architecture is rooted around a compositor with plugins for window management and such, so we must provide one from somewhere. wlroots is to date the best starting point we’ve found.

(The decision to plug the window manager directly into the compositor is largely a security consideration: if the core window system (X11) / compositor (Wayland) provides sufficient APIs for an external window manager like X11 does, those APIs are also trivially available to potential attackers to watch activity and to some extent even inject events, send_event notwithstanding.)

1 Like

I should probably apologize for not reading the thread and links in depth before posting earlier. Although, from reading through the messages, it’s clear I’m not the first person to do this :grinning_face_with_smiling_eyes:

I have read through it all in depth now and did some more research on top of it. I think it would be valuable to summarize the key points as I see them here. Also, it’s good to acknowledge how complicated all this is - there are a lot of moving parts, so I may get some of this wrong.

So first, I think it’s worth saying Wayland is a protocol and not a full implementation. The protocol defined here: protocol/wayland.xml · main · wayland / wayland · GitLab was brought up in the PR. This XML, along with the Wayland protocol extensions, will get you some of the way. The wayland-scanner works on the client and server protocols to create C header files. So you have the wayland protocol and then libwayland is the library that helps implement the Wayland protocol. It doesn’t act as a server itself; it provides the tools to build a Wayland client or a Wayland compositor (server).

Wlroots is a compositor library, so a library for creating compositors. In the project description, it says it’s the “60k lines you were going to write anyway.” So, there are obviously other libraries built on the Wayland protocol, and from the chat history, it seems people periodically hop in to recommend using one of these instead, and this generates a lot of confusion. I think sticking with wlroots makes the most sense for now.

Beyond that, wlroots lists several binding libraries, and for Haskell, it has hsroots, which looks to be abandoned. It is really interesting to compare hsroots with wlr; you can really see the advantage of the templating done in wlr.

So, with wayland xmls and the relevant Wayland extension XMLs, you can use wayland-scanner to generate C header files. We should probably do this in haskell, but it will likely only provide a subset of the bindings we need; we will still need to hand-roll the rest.

Also, within wlroots, there are more XMLs for wlroots-specific bindings. Again, we can use these to generate more bindings, but also, again, it will only be a subset of what we need.

So, it seems the original goal of the project was to get a subset of the bindings working to get tinywl working:

I think this is still a really good idea, and from the progress report, it looks like you were really close. All that was left was:

  1. wlr_subcompositor
  2. wlr_scene
  3. wlr_xdg_shell
  4. wlr_cursor
  5. wlr_xcursor_manager

From reading through the PR, it seems life got in the way for some, and then there was confusion about why the other libraries are using XML and how far this XML would take you if parsed.

I think, considering all the work done and the nice templating set up, it’s worth it to continue and just get tinywl working. From what bindings are needed tinywl will give us a lot in functionality and then we can use this as a core to iterate forward one feature at a time.

Ideally if there is an expert present they can do the XML parsing? , If not I can take it on and see how far I get. I would probably use xml-conduit and Template Haskell. The XML looks pretty straightforward; I don’t think anything like Alex/Happy is needed, but I’m open to suggestions. This might give use a nice win and boost.

So anyway I hope this helps

2 Likes

That’s a decent summary.

I do have XML experience, but not specifically in the area of generating bindings from an XML protocol description (and the last time I touched it was sometime in the early 1990s, and I used SAX for the heavy lifting because that was pretty much the only free tool available at the time). Still, I might be able to help somewhat there.

I did a bit more work on this, I compiled and ran both wlr and the PR mentioned about for wlr_scene. I ran into no issues so I’m assuming the PR is held up because of disagreements on implementation path.

In my last post I thought it might be good to try to get a XML parser running but thinking about it a little deeper I don’t think that is necessary.

The protocol XML’s are used by wlroots so I don’t think there is a need to create bindings for them (at least right now). It makes more sense to use wayland-scanner to create the required headers and then just continue creating bindings for the remaining headers.

wlr_subcompositor
wlr_scene
wlr_xdg_shell
wlr_cursor
wlr_xcursor_manager

These all begin with wlr so wlroots headers, I think they link against wayland protocol headers generated by the wayland-scanner.

The idea from wlroots was simple, it was better to generate the headers from the protocol each time its run to ensure compatibility. So, I think there is no way around adding this wayland-scanner step into wlr, unless we do it once and include the generated files.

What I’m really curious about is if we get the remaining five done what issues will we run into getting tinywl running? What I mean by this is when I built and ran the code for wlr and the latest PR I didnt see any errors or issues, im curious about how this is being tested? Or is that something that will need to be done when we have enough for tinywl.

What I was thinking is I might take this weekend and setup tinywl in C just to make sure I understand it right. I was also thinking I could start with this C implementation and start moving components one by one into haskell, this ideally would give a simple way to test the bindings.

4 Likes

I agree. I have some free time and want to help. I’ll look at what tinywl uses and start making bindings for those.

I actually started a haskell implementation this weekend of tinywl, you can find my approach here

Any help is greatly appreciated.

So what I have created is a Tinywl shared library that the Haskell project is linking against. The idea is to have it working and move, bit by bit the calls on this shared library to wlhs bindings or local haskell implementations.

Going forward my plan (which I outlined in the README and TODO) is to refactor the c_main to first be a series of C functions and to call these exposed c functions from Haskell so we can replace c_main totally with Haskell.

The intention is to get to a point in which we can focus on refactoring single sections of the code in an iterative fashion and have the peace of mind of testing tinywl as we go.

Its actually pretty easy to get started, just:

  1. git clone https://github.com/l-Shane-l/tiny-wlhs.git && cd tiny-wlhs

  2. nix-shell

  3. cabal run

You should then see a window open, I ran this on my xmonad setup, there was some confusion with hotkeys but it worked fine. Alt mouse left will move the window and alt mouse right will resize it.

I will add in what I did to the change log, but I anyone want to help or has any feedback on the approach please get in touch.

It probably makes sense to setup somewhere for anyone working on the wlroots bindings instead of posting updates on this forum.