Haskell wlroots bindings

Just to give a more general update on Tiny-wlhs.

I did some very basic analysis using cloc to count lines of code. In TinyWl.c there are around 800 lines of actual code, of these around 300 lines are function calls (or verbs ) and 500 lines are concerned with data structures and memory( or nouns).

So I think only the 300 lines of functions will be converted to Haskell and the remaining 500 left in C. Fortunately the conversation isnt too complex its follows the pattern of what has already been done.

My assumption is the C functions will provide everything needed to interact with the structs in the code and the act of converting the C functions into Haskell will expose everything we need via Haskell interface. Assuming we had all 300 lines converted to Haskell and all the getters and setters they need ser up, then in theory someone could come along and build a compositor using only the Haskell functions and types.

The reality likely is a lot complex and more will probably be needed but its not clear what this will be until we get to that point and try to build a compositor with what we have.

1 Like

Appreciate this! Iā€™ll add to what Shane said with suggesting https://wayland-book.com/ for reference material on Wayland itself. Section 1.1 is a really good primer, in particular, but the rest can be treated as reference.

2 Likes

Iā€™m toying around with adding keybindings from the Haskell side on my ā€œhs-keybindsā€ branch, and Iā€™m running into an issue. It seems that any call to handleKeybinding function results in a crash.

I get the sense that debugging this is going to be an ordeal, to say the least. Before I go through with that, though, Iā€™d like to consider alternatives to what Iā€™m doing; as far as I know, exporting Haskell functions to C comes with some overhead, and it definitely complicates things. Fortunately, the export would go away once more code is translated, but Iā€™m just trying to go step-by-step for now.

Anyways, maybe someone else could take a look and let me know if they have any suggestions?

There is a small amount of overhead on the first call to a foreign export function within a given thread, but the result is cached unless you explicitly discard the cache so subsequent calls are fast (see 6.17. Foreign function interface (FFI) ā€” Glasgow Haskell Compiler 9.10.1 User's Guide). If this makes things easier for you, Iā€™d say go for it.

1 Like

Thanks! I clicked on your link, and I see now that I canā€™t just declare the extern myself and link against the library.

I think @bradrn mentioned that we was willing to hand over the repo to somebody. My injury is manageable now and Iā€™d like to contribute again.

I think weā€™d need to decide some things, like checking in the XML files for the protocol that we need to use to generate C headers to link with to build wlroots. I still have this outstanding PR (outstanding as in not handled), and I might have a little bit more work on top of it on my fork.

And I didnā€™t notice that we had a PR, we should get that merged too.

Wayland adoption seems to be picking up, which is exciting. (I still need to get rid of this Nvidia card and switch to AMD)

1 Like

I had a brief look at the code but nothing jumped out at me. For debugging I use gdb on the binary created by cabal. However I can attest debugging is not pleasant.

Its interesting you choose to work on the keybindings this is something I have been thinking about.

Originally I created the repo to test wlroots bindings then this morphed into simply taking the current running C from a tinywl shared library and controlling it with Haskell.

So currently we have the following


main :: IO ()
main = do
    -- Initialize logging
    wlr_log_init WLR_DEBUG nullFunPtr

    -- Add a test log message
    wlr_log WLR_INFO "Initializing TinyWL with wlhs bindings"
    

    args <- getArgs
    server <- FFI.c_server_create
    wlr_log WLR_DEBUG "Server created"

    initSuccess <- FFI.c_server_init server
    if initSuccess
        then do
            wlr_log WLR_INFO "Server initialized successfully"
            wlDisplay <- Server.getWlDisplay server
            renderer <- Server.getRenderer server
            _ <- Compositor.initialize_compositor wlDisplay 5 renderer
            socket <- FFI.c_server_start server
            if socket /= nullPtr
                then do
                    socketStr <- peekCString socket
                    setEnv "WAYLAND_DISPLAY" socketStr
                    wlr_log WLR_INFO $ "WAYLAND_DISPLAY set to " ++ socketStr
                    case args of
                        ("-s":cmd:_) -> do
                            withCString cmd FFI.c_server_set_startup_command
                            wlr_log WLR_DEBUG $ "Startup command set: " ++ cmd
                        _ -> return ()
                    putStrLn $ "Running Wayland compositor on WAYLAND_DISPLAY=" ++ socketStr
                    FFI.c_server_run server
                else wlr_log WLR_ERROR "Failed to start server"
        else wlr_log WLR_ERROR "Failed to initialize server"
    FFI.c_server_destroy server
    wlr_log WLR_INFO "Server destroyed, shutting down"

I tried breaking down things like server_init, but that felt like a dead end. Manually sequencing C calls from Haskell isnā€™t very useful. Creating tons of getters/setters for C structs and then calling wlroots functions via FFI is a lot of work for not much gain.

So, what should tiny-wlhs be? The C shared library approach simplifies some things (Wayland scanner, memory management), but it limits how ā€œHaskell-yā€ the compositor can be, especially if weā€™re aiming for something like Waymonad. Itā€™s a C compositor at its core, with a Haskell control layer. That has limitations. The Haskell/C interface and debugging are also major pain points.

The alternative it to create a compositor from scratch Haskell. This to me at least is just not viable atm. It needs wlroots bindings and perhaps a bigger roadblock it needs a Haskell version of the wayland scanner. So a Haskell xml scanner to be run on each build with the latest wayland protocols, converting the protocol which is very C focused into Haskell.

So with all that in mind I think tiny-wlhs can be three things.

First, a way to test any wlroots bindings or xml scanners if created. This can help provide some peace of mind and checks for anyone working on these, and I would be more than happy to do the integrations to test anything, it might also provide a target to work towards.

Second, an educational tool. If you look back over this long thread you will see a lot of confusion about the wayland protocol and how to actually use it. This repo can provide a basic working example that can be played around with to become more familiar with the concepts. Besides that it will offer anyone who works on it directly a lot of insight of what is required from a bindings library, and about the limitations and possibilities of a c based compositor and what a Haskell implementation might look like.

And Thirdly, while support for a wayland implementation of xmonad is being worked on it can serve as a stand-in for anyone who wants to mess around with compositors in Haskell.

To the final point about getting some minimal app people can control and configure in Haskell I think the following features(for lack of a better term) are needed in a basic implementation and should be fully controllable in idiomatic Haskell.

1. Core Functionality & Lifecycle:

  • Start/Stop Server: Essential for basic control.

  • Server Configuration: Logging levels are important for debugging.

2. Output Management:

  • List Outputs: Useful for information and debugging.

  • Basic Output Configuration: Setting resolution is important for usability, but advanced multi-monitor setups can be deferred.

3. Window Management:

  • Window Placement (Tiled): Focus on basic tiling layouts (e.g., tall, wide).

  • Window Resizing/Moving (Basic): Within the constraints of the tiling layout.

  • Window Focus: Essential for interacting with windows.

  • Window Closing: A fundamental window management operation.

  • Fullscreen: A common use case.

4. Input Handling:

  • Keyboard Bindings: Crucial for controlling the compositor. Focus on keybindings for window management actions.

  • Mouse Bindings: Basic mouse clicks for window focus and interaction.

5. Application Launching & Management:

  • Application Spawning: Allowing users to launch applications is important for daily use. Defer startup applications for now.

6. Compositor Features :

  • Basic Decorations: Simple borders and titles are helpful for distinguishing windows. Advanced customization can come later.

7. Inter-Client Communication (Deferred):

  • Wayland Protocols (Advanced): This is not a priority for the initial experimental phase. Clipboard management, drag-and-drop, and other advanced protocol interactions can be explored later.

So if we think about these features instead of comprehensive bindings its actually easier to just go feature by feature and leave as much of the complexity in the C side as possible (as this is already written, or can be borrowed from projects like sway) and only pulling into a Haskell interface what we actually need for what ever feature we are trying to support.

But I would like to get peoples thoughts, its unfortunately not going to address the need for bindings or a xml scanner but I think having something configurable and controllable in Haskell should provide dividends by simply providing a way to play around with a compositor in Haskell.

So with all that being said, this will likely be my last update post on this thread, tiny-wlhs has changed its scope so is no longer relevant in this thread unless directly talking about testing any wlroots bindings. Ill likely post updates on tiny-wlhs in its own thread.

2 Likes

Tiny-wlhs will be useful too I think but most people in this thread concurred that a very basic binding from Haskell to wlroots that tried to create 0 abstractions would be best starting point. Because it then could become a component of other projects more easily than it could be if wlhs tried to also provide a nicer interface than calling C functions.

For example, as far as I can tell in the Haskell world there are two major ways to architecture applications, one is building your own monad onion (which has performance implications apparently) and two is using ReaderT over IO. Iā€™m trying the latter for a web application that I am building and I like it.

The point is that compositor authors are likely to have opinions about how the compositor state should be managed, and we imagined that wlroots would be as ā€˜dumbā€™ as possible so that it could be used by any kind of project.

I think youā€™re idea about making something that actually works & runs by itself is wonderful, Iā€™m just explaining the thought process behind WLHS.

1 Like

I probably should have posted an update. Donā€™t even bother right now; itā€™s not even linking. I forgot that the make clean part of the nix shell hook wasnā€™t working and didnā€™t realize that my changes werenā€™t being reflected every time I restarted the shell :man_facepalming:.

Anyways, Iā€™ve since figured out a lot more and hope to finish up what I was doing and post about it in the next few days.

2 Likes

Yup, Iā€™m fully on board with this. If I can daily-drive it, then Iā€™ll be much happier working on it, and Iā€™m sure this goes for most people.

I think ā€œlimitationsā€ is a good way to put it. I found this idea rather unsavory, at first, but the ā€œworse is betterā€ approach may just be necessary.

I no longer agree. This idea sounded good to me on paper, but I think that Shaneā€™s effort on tiny-wlhs made me confront reality. As he said:

Wlroots is a great library, but at the end of the day itā€™s a C library designed for C programs. Iā€™m not sure what a good C library designed for Haskell programs looks like, but I think that we can build on the steps that Shane outlined in order to figure that out.

2 Likes

Iā€™ve got something basic working, but it took me a while to figure out how to get everything to link properly. Iā€™m not familiar with any of the intricacies of cabal, so I ended up modifying the Makefile. Even then, Iā€™ve got little idea of what GHC is doing behind the scenes, so some of what I had to do to get this working is still spooky to me. I did spend a fair bit of time trying to get this working with cabal, but Iā€™ve given up at this point; help would be appreciated.

As an aside, this is pretty clearly off-topic at this point. @l-Shane-l, I could start a new thread next time, if you donā€™t mind. If youā€™d rather write the OP, would you mind starting it soon?

1 Like

I created a thread here Tiny-wlhs, a hybrid haskell and C Wayland compositor

We probably should set up a discord or IRC or something, somewhere to ask questions and help each other.

2 Likes

@bradrn Hey Brad. Do you think I could become the maintainer of wlhs? I want to continue writing the bindings as we were, and Iā€™m not opposed to just using the already-existing wayland scanner, even if it means checking in XML files and having an extra build step.

What do you need me to do?

We have two outstanding PRs, and it says " Only those with write access to this repository can merge pull requests."

I know my PR wasnā€™t merged because the project was likely to go in another direction, but if Iā€™ve continued adding things in on my fork here and there.

I wasnā€™t sure if I should take up the WLHS repo, or if I should hard fork it and continue working.

Iā€™d need write access at least.

Iā€™ve thought about this once or twice but Iā€™m not sure. What does everyone else think?

(Iā€™d be happy to give you write access, but if other people want a fork that might be easier.)

Iā€™m not sure what the point of a fork would be unless you plan on updating your version of the repo separately. I think that itā€™s fine to just give write access.

I logged in to just cheer this effort on. Iā€™m currently stuck using gnome because x11 wonā€™t start and I already miss XMonad so much. I want it to have a bright future, and I have to admit that wayland is a little bit smoother in certain aspects, it doesnā€™t have any tearing issues for example. Thank you so much to everyone that is putting in effort to making xmonad work on wayland. I canā€™t wait for this to be work, Iā€™ve been periodically checking in to see if there is progress Iā€™m happy I found this thread. Please continue to work hard!

4 Likes

I should say that on this thread but Iā€™ve ditch a few weeks ago my 10years old XMonad config for gnome PaperWM - GNOME Shell Extensions it is pretty good. It is not quite a tiling WM but solves lots of the same problem in an interesting way (basically by sticking all window next to each other).
Iā€™m sure this model could be added to XMonad as a new layout.

@l-Shane-l Are there any library functions from WLRoots that youā€™d like to have done sooner? Iā€™m just looking at Sway code and then picking wlroots modules that look important and implementing those.

I canā€™t find a definitive ā€œthis is the public APIā€ of wlroots, but I think I should focus on the include/wlr/types/* directory.

2 Likes