Why does XCreateIC in XLib return null over FFI but not in C?

I'm currently working on a PR to minifb to fix this issue, and my research says that I need to use the function Xutf8LookupString to properly read key press events as characters. This requires that an XIC instance is created, but I'm having a problem with creating that instance. I found an example C program (and I compiled and tested it and it works fine) that does everything that is needed to get these key presses correctly, but when I try to do the exact same thing in Rust, XCreateIC returns a null pointer.

The relevant C code looks like this:

    setlocale(LC_ALL, "");

    Display* dpy = XOpenDisplay(NULL);

    Window win = XCreateSimpleWindow(dpy, DefaultRootWindow(dpy), 0, 0, 100, 100, 0, 0, 0);
    XMapRaised(dpy, win);
    XSync(dpy, False);

    // X input method setup, only strictly necessary for intl key text

    // loads the XMODIFIERS environment variable to see what IME to use

    XIM xim = XOpenIM(dpy, 0, 0, 0);
        // fallback to internal input method
        xim = XOpenIM(dpy, 0, 0, 0);

    // X input context, you can have multiple for text boxes etc, but having a
    // single one is the easiest.

    XIC xic = XCreateIC(xim,
                        XNInputStyle,   XIMPreeditNothing | XIMStatusNothing,
                        XNClientWindow, win,
                        XNFocusWindow,  win,

and the equivalent Rust code looks like this (some setup is removed since minifb has much more initialization code than that example):

            let handle = (d.lib.XCreateWindow)(
                x as i32,
                y as i32,
                width as u32,
                height as u32,
                0, /* border_width */
                xlib::InputOutput as u32, /* class */
                xlib::CWColormap | xlib::CWBackingStore | xlib::CWBackPixel | xlib::CWBorderPixel,
                &mut attributes,

            let empty_string = CString::new("").unwrap();

            let xim = (d.lib.XOpenIM)(d.display, 0 as XrmDatabase, 0 as *mut c_char, 0 as *mut c_char);
            if(xim as usize) == 0{
                panic!("Failed to setup X IM via XOpenIM.");

            let xn_input_style = CString::new(XNInputStyle).unwrap();
            let xn_client_window = CString::new(XNClientWindow).unwrap();
            let xic = (d.lib.XCreateIC)(xim, xn_input_style.as_ptr(), XIMPreeditNothing | XIMStatusNothing, xn_client_window.as_ptr(), handle as c_ulong, XNFocusWindow.as_ptr(), handle as c_ulong, std::ptr::null_mut::<c_void>());
            if (xic as usize) == 0{
               panic!("Failed to setup X IC via XCreateIC."); //panics here

In this code, the panic at the end always runs (I'll do proper error handling once I have it working). Yet, as far as I can tell, I am doing this call in the exact same way as in the C program so I don't understand why it is doing this. Furthermore, this being a C library there's no panic error message or error return type that I can inspect. I tried to add an error callback to Xlib via


but this error handler is not being called. Additionally, I can't step into the library usefully because it's all disassembly.

How can I debug this?

You seem to have forgotten to wrap XNFocusWindow in a CString. You could try to use CStr::as_ptr(&thing) rather than the method shorthand to avoid this kind of typos :slightly_smiling_face:

If that's not the cause of the problem, then I suggest you share a repo or something so that we can see the rest of the pipeline: I am mainly curious of the generated Rust "headers" for that FFI lib


Nice catch, it worked. Thank you!

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.