psychon / x11rb

X11 bindings for the rust programming language, similar to xcb being the X11 C bindings
Apache License 2.0
359 stars 38 forks source link

Port dwm #182

Open psychon opened 4 years ago

psychon commented 4 years ago

Related to #93:

DWM might be a nice example since it is relatively small. To do: double check its license.

Amanita-muscaria commented 4 years ago

I actually stumbled across x11rb specifically because I was looking to port dwm to Rust. Let me know what, if anything, you've already got done and I'll see what I can do to help.

psychon commented 4 years ago

Creating this issue is all I did so far.

Usually, I have random ideas while showering and then I turn them into GitHub issues. So, feel free to work on this if you want. You can also ask questions and show incremental process.

I'd still have to double check the license, but I think something like examples/dwm.rs should be possible, if you want to work on that. Or just start in a separate project, because that might be easier.

Anyway, one idea of these "Port X" issues is that this might help in figuring out what good helper functions are that could be added to x11rb. So, if you come across anything like this, feel free to also open an issue for these helpers.

I'll assign this issue to you for now.

Nicholas-Baron commented 4 years ago

Small bit of backstory: I originally tried to use the x11 crate, which provide raw FFI (read as unsafe extern "C") bindings to X11. I started writing some wrappers and then realized that I would spend most of my time writing wrappers, and so I went looking for another crate.

I found this crate and it had a lot of wrappers already in place (no unsafe blocks in main). I started by copying the example window manager and then taking on dwm-like features.

The largest problem I have run into so far is how to get the keycode for a given keysym or X11 name. dwm does this with XKeysymToKeycode and uses the predefined keysym list in the C headers. I found a binding in this crate for getting a list of keycodes from the GetKeyboardMapping struct, but the X11 standard is unclear on how to convert from keysym to keycode manually (almost like the client should use the X11 functions for the task).

So the two part problem so far is

  1. How to get keysyms (C has a header full of them, where are the Rust consts)
  2. Converting from keysyms to keycodes (I cannot find how to call XKeysymToKeycode in this crate)
Nicholas-Baron commented 4 years ago

As a separate comment, here is a list of possible X11 identifiers (tend to start with 'X') found in dwm.c. It is probably not exhaustive and skips the X11 macros, but it is a starting place for porting dwm.

pickfire commented 4 years ago

From what I recall, xcb does not provide XKeysymToKeycode and you need to handle that manually, x11rb is similar to xcb if I am not mistaken rather than xlib. We manually search for the keycode from keysyms.

https://github.com/neXromancers/hacksaw/blob/867e95473c338861de048f3beb56f771997d3331/src/lib/mod.rs#L142-L158

Amanita-muscaria commented 4 years ago

I, uh, clearly forgot about this until just now. Feel free to unassign me or whatever. I don't know if I'll have the time. Sorry. :(

psychon commented 4 years ago

dwm does this with XKeysymToKeycode and uses the predefined keysym list in the C headers

The part of X11 where I suspect my biggest "knowledge holes": input handling, especially keyboard stuff. :-)

As a separate comment, here is a list of possible X11 identifiers (tend to start with 'X') found in dwm.c.

From a quick look:

Sorry. Input handling...

We manually search for the keycode from keysyms.

I feel like this is what Xlib does, too, but I am not actually sure.

Feel free to unassign me

Okay, done.

pickfire commented 4 years ago

I want to try this but I don't even know how to start since xcb is so different from xlib and x11rb is a bit different from xcb.

I am stuck in almost the first step.

void
checkotherwm(void)
{
        xerrorxlib = XSetErrorHandler(xerrorstart);
        /* this causes an error if some other window manager is running */
        XSelectInput(dpy, DefaultRootWindow(dpy), SubstructureRedirectMask);
        XSync(dpy, False);
        XSetErrorHandler(xerror);
        XSync(dpy, False);
}

Where could I get resources related to these? Like which version of the same thing in xcb should I use? Usually I when I checked there is not even an alternative.

psychon commented 4 years ago

@pickfire Xlib makes it a bit difficult to catch errors for requests without reply (as you see). With xcb / x11rb, this becomes easier. XSelectInput is actually a thin wrapper around XChangeWindowAttributes. In x11rb, change_window_attributes returns a VoidCookie and you can just call check() on it to check for errors.

An example can be found in the simple_window_manager example:

https://github.com/psychon/x11rb/blob/ee4086c3c93ee3116ffcc7f3bc12d02859592e59/examples/simple_window_manager.rs#L320-L324

pickfire commented 4 years ago

Ah, now I kinda get it after looking at https://github.com/psychon/x11rb/blob/ee4086c3c93ee3116ffcc7f3bc12d02859592e59/examples/simple_window_manager.rs#L320-L324, https://github.com/julian-goldsmith/dwm-xcb/blob/4515e6a70d49c506f6a6547bbcea951d7d40f807/dwm.c#L100 and https://github.com/i3/i3/blob/5bc5fc188b8825c1cc2b2a1afa2d1e9f7f4a33c9/src/main.c#L642.

@psychon Thanks for the quick reply, I just got frustrated at first by looking at how different xlib and xcb like how I did last time.

XSelectInput is actually a thin wrapper around XChangeWindowAttributes

But how do you know about that? I wonder if these kind of stuff are written in the thick manual.

psychon commented 4 years ago

But how do you know about that?

Well. I guess in my case the honest answer is "experience", but that does not help you, so....

Use the source, Luke. ;-)

https://gitlab.freedesktop.org/xorg/lib/libx11/-/blob/master/src/SelInput.c

This mentions ChangeWindowAttributes in four places and CWEventMask in one.

Xlib is from the time where it made sense to have each function in a separate C file (this allowed the linker to discard unused function when statically linking). Thus, the name XSelectInput is "kind of similar" to SelInput.c. Alternatively, one can also use the "Search or jump to..." at the top of the gitlab page to find the definition of the function.

pickfire commented 4 years ago

Okay, I got to port the the very first function I tried, maybe I should try out something like https://github.com/rust-dc/fish-manpage-completions/issues/2 to port all the functions to make it faster and then advertise it in this-week-in-rust.org, then later put it back here as an example.

pickfire commented 3 years ago

I did a very tiny part then I stopped, https://github.com/pickfire/dwm I would continue if I have time later. But it is part of hacktoberfest.

MarcusGrass commented 2 years ago

I wrote a WM with this goal in mind, it's not exactly like dwm but I used that codebase as an inspiration and it aims to be resource efficient. With x11rb (and the render feature) I was able to write it entirely in safe Rust, font-drawing and all.

Worth noting is that it's fairly difficult to make a clean 1to1, dwm uses libX11 and libXft, while x11rb maps xcb which has a few big differences in its APIs and different capabilities, for drawing text for example you'd need to find some other library that can draw fonts, or use xrender through xcb which is one part of what libXft does.