Smithay/wayland-rs

WlRegistry.bind always outputs WlRegistry

laycookie opened this issue ยท 5 comments

Hello, I'm new to wayland so apologies if I had miss understood something. I had attempted to use this library to bind and interact with wayland globals, but the docs dont really explain how to do that. I have managed to find only one example of binding to a global in wayland_cliend::globals but the issue is that when I copy and paste the code it trows an error at me that it is expecting wl_compositor mean while the return type is wl_register.
I have wrote this little snippet of code to try to bind to all of the globals but the issue precists where now when I print the global my console reports it as being WlRegister.

use wayland_client::protocol::wl_registry::{self};
use wayland_client::{Connection, Dispatch, QueueHandle};

struct AppState;

impl Dispatch<wl_registry::WlRegistry, ()> for AppState {
    fn event(
        _state: &mut Self,
        registry: &wl_registry::WlRegistry,
        event: wl_registry::Event,
        _: &(),
        _: &Connection,
        qh: &QueueHandle<AppState>,
    ) {
        // When receiving events from the wl_registry, we are only interested in the
        // `global` event, which signals a new available global.
        // When receiving this event, we just print its characteristics in this example.
        if let wl_registry::Event::Global {
            name,
            interface,
            version,
        } = event
        {
            let g = registry.bind(name, version, qh, ());
            println!("{:#?}", g);

            println!("[{}] {} (v{})", name, interface, version);
        }
    }
}

pub fn get_screecopy() {
    let conn = Connection::connect_to_env().unwrap();
    let display = conn.display();
    let mut event_queue = conn.new_event_queue();
    let qh: QueueHandle<AppState> = event_queue.handle();

    display.get_registry(&qh, ());

    event_queue.roundtrip(&mut AppState).unwrap();
}

The registry.bind() method is a generic method, you need to specify the type of the object you expect it to create. See for example:

if let wl_registry::Event::Global { name, interface, .. } = event {
match &interface[..] {
"wl_compositor" => {
let compositor =
registry.bind::<wl_compositor::WlCompositor, _, _>(name, 1, qh, ());

@elinorbgr Thank you! Didn't notice there was an example folder in a repo. I had also figured out why I was receiving an error when copying the code from the wayland_cliend::globals. Apparently if you don't implement a dispatch and just copy past the code from example you receive this error.

error[E0308]: mismatched types
  --> src/wayland/get_screencopy.rs:55:30
   |
55 |     let comp: WlCompositor = globals.bind(&qh, 1..=4, ()).unwrap();
   |               ------------   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `WlCompositor`, found `WlRegistry`
   |               |
   |               expected due to this

I think it isn't hard to see where I got confused in here. Is it by any chance possible to change this line to something like?

    let comp = globals.bind::<WlCompositor, _, _>(&qh, 1..=4, ());

Which would instead give this much nicer error.

error[E0277]: the trait bound `wayland::get_screencopy::Delegate: wayland_client::Dispatch<wayland_client::protocol::wl_compositor::WlCompositor, _>` is not satisfied
   --> src/wayland/get_screencopy.rs:56:45
    |
56  |     let comp = globals.bind::<WlCompositor, _, _>(&qh, 1..=4, ());
    |                        ----                 ^ the trait `wayland_client::Dispatch<wayland_client::protocol::wl_compositor::WlCompositor, _>` is not implemented for `wayland::get_screencopy::Delegate`
    |                        |
    |                        required by a bound introduced by this call
    |

Or possibly instead just add delegate_noop!(Delegate: ignore WlCompositor); in the example to get rid of this error entirely.

I have also found docs to be a little confusing on the part were you want to bind to wl_outputs when using globals.bind. The reason why you dont want to bind WlOutputs is obvious however the way to bind them isn't.

https://smithay.github.io/wayland-rs/src/wayland_client/globals.rs.html#123-126
States that you should bind to WlOutput using "Dispatch implementation for WlRegistry of your State" however when implementing, no WlOutputs events are passed which would make sense as I assume they are in the GlobalList. but then do I still run global.bind to bind to WlOutput initially, and then just listen to the changes in the Dispatch impl? I'm slightly confused because the docs arent phrased in the way which would incentive's you to do that.

Is it by any chance possible to change this line to something like?

yes sure, the example can be updated to be made for explicit, that'd be a good thing I agree.

but then do I still run global.bind to bind to WlOutput initially, and then just listen to the changes in the Dispatch impl?

Doing that will not work if there are more than one output. Instead, you should use the .contents() method of the global list and filter it to find all outputs and manually bind them using the registry.

Note however if you are making a client app that you can use SCTK to handle a lot of the plumbing work for you, in case you didn't know about it.

@elinorbgr Thank you, I did see the following crate but I dont need most of the functionality from there, so using it will mostly just result in unnecessary abstraction and increase in bundle size of my application so I have decided that it was not worth it.

Doing that will not work if there are more than one output. Instead, you should use the .contents() method of the global list and filter it to find all outputs and manually bind them using the registry.
Understood, this is my current implementation glad to hear that it should work fine. However Im still not entirly sure if the GlobalList will update when a display is going to get unplugged or plugged?

Also can I open a pull request with the edit to the docs. relating the handling of displays trough the Dispatch and the edit of an let comp: WlCompositor = globals.bind(&qh, 1..=4, ()).unwrap(); example? I just haven't found any contribution guidelines so Im not sure if I can contribute or if all the pull requests are handled by a certain group of people.

Also can I open a pull request with the edit to the docs.

Sure, please go ahead ๐Ÿ‘

However Im still not entirly sure if the GlobalList will update when a display is going to get unplugged or plugged?

It will, but the most robust way to process these events after the initial startup of your app is to monitor them if your Dispatch<WlRegistry, ..> implementation.