Open psychon opened 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.
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.
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
const
s)XKeysymToKeycode
in this crate)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.
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.
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. :(
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:
XK
seems keyboard related. However, this does not seem too bad.
From keysymdef.h
, the "normal keys" seem to just provide the ASCII definition:
#define XK_q 0x0071 /* U+0071 LATIN SMALL LETTER Q */
XKeysymToKeycode
already does and the code seems not too easy to follow. There is a "no XKB" implementation in src/KeyBind.c
and a second implementation in src/xkb/XKBBind.c
.XkbGetMap
. This uses XkbKeyNumSyms
and XkbKeySym
which are both not part of Xlib...KeyCodetoKeySym(dpy, i, j) == input
and then return i
. KeyCodetoKeySym
then again does some complicated stuff that I do not really understand.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.
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.
@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:
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.
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.
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.
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.
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.
Related to #93:
DWM might be a nice example since it is relatively small. To do: double check its license.