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:
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:
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.