use std::io;
use std::sync::{Arc, Mutex};
use wayland_client::commons::Implementation;
use wayland_client::protocol::{wl_compositor, wl_data_device_manager, wl_output, wl_registry,
wl_shell, wl_shm, wl_subcompositor};
use wayland_client::{EventQueue, GlobalEvent, GlobalManager, NewProxy, Proxy};
use wayland_protocols::unstable::xdg_shell::v6::client::zxdg_shell_v6;
use wayland_protocols::xdg_shell::client::xdg_wm_base;
use wayland_client::protocol::wl_registry::RequestsTrait;
pub enum Shell {
Xdg(Proxy<xdg_wm_base::XdgWmBase>),
Zxdg(Proxy<zxdg_shell_v6::ZxdgShellV6>),
Wl(Proxy<wl_shell::WlShell>),
}
impl Shell {
pub fn needs_configure(&self) -> bool {
match *self {
Shell::Xdg(_) => true,
Shell::Zxdg(_) => true,
Shell::Wl(_) => false,
}
}
}
pub struct Environment {
pub manager: GlobalManager,
pub compositor: Proxy<wl_compositor::WlCompositor>,
pub subcompositor: Proxy<wl_subcompositor::WlSubcompositor>,
pub shell: Shell,
pub shm: Proxy<wl_shm::WlShm>,
pub data_device_manager: Proxy<wl_data_device_manager::WlDataDeviceManager>,
pub outputs: ::output::OutputMgr,
shm_formats: Arc<Mutex<Vec<wl_shm::Format>>>,
}
impl Environment {
pub fn from_registry(
registry: NewProxy<wl_registry::WlRegistry>,
evq: &mut EventQueue,
) -> io::Result<Environment> {
Environment::from_registry_with_cb(registry, evq, |_, _| {})
}
pub fn from_registry_with_cb<Impl>(
registry: NewProxy<wl_registry::WlRegistry>,
evq: &mut EventQueue,
mut cb: Impl,
) -> io::Result<Environment>
where
Impl: Implementation<Proxy<wl_registry::WlRegistry>, GlobalEvent> + Send + 'static,
{
let outputs = ::output::OutputMgr::new();
let outputs2 = outputs.clone();
let manager = GlobalManager::new_with_cb(registry, move |event, registry: Proxy<_>| {
match event {
GlobalEvent::New {
id,
ref interface,
version,
} => match &interface[..] {
"wl_output" => outputs2.new_output(
id,
registry.bind::<wl_output::WlOutput>(version, id).unwrap(),
),
_ => (),
},
GlobalEvent::Removed { id, ref interface } => match &interface[..] {
"wl_output" => outputs2.output_removed(id),
_ => (),
},
}
cb.receive(event, registry);
});
evq.sync_roundtrip()?;
evq.sync_roundtrip()?;
let compositor = manager
.instantiate_auto::<wl_compositor::WlCompositor>()
.expect("Server didn't advertize `wl_compositor`?!")
.implement(|e, _| match e {});
let subcompositor = manager
.instantiate_auto::<wl_subcompositor::WlSubcompositor>()
.expect("Server didn't advertize `wl_subcompositor`?!")
.implement(|e, _| match e {});
let shm_formats = Arc::new(Mutex::new(Vec::new()));
let shm_formats2 = shm_formats.clone();
let shm = manager
.instantiate_auto::<wl_shm::WlShm>()
.expect("Server didn't advertize `wl_shm`?!")
.implement(move |wl_shm::Event::Format { format }, _| {
shm_formats2.lock().unwrap().push(format);
});
let data_device_manager = manager
.instantiate_auto::<wl_data_device_manager::WlDataDeviceManager>()
.expect("Server didn't advertize `wl_data_device_manager`?!")
.implement(|e, _| match e {});
let shell = if let Ok(wm_base) = manager.instantiate_auto::<xdg_wm_base::XdgWmBase>() {
Shell::Xdg(
wm_base.implement(|xdg_wm_base::Event::Ping { serial }, proxy: Proxy<_>| {
use self::xdg_wm_base::RequestsTrait;
proxy.pong(serial)
}),
)
} else if let Ok(xdg_shell) = manager.instantiate_auto::<zxdg_shell_v6::ZxdgShellV6>() {
Shell::Zxdg(xdg_shell.implement(
|zxdg_shell_v6::Event::Ping { serial }, proxy: Proxy<_>| {
use self::zxdg_shell_v6::RequestsTrait;
proxy.pong(serial)
},
))
} else if let Ok(shell) = manager.instantiate_auto::<wl_shell::WlShell>() {
Shell::Wl(shell.implement(|e, _| match e {}))
} else {
panic!("Server didn't advertize neither `xdg_wm_base` nor `wl_shell`?!");
};
evq.sync_roundtrip()?;
Ok(Environment {
manager,
compositor,
subcompositor,
shell,
shm,
shm_formats,
data_device_manager,
outputs,
})
}
pub fn shm_formats(&self) -> Vec<wl_shm::Format> {
self.shm_formats.lock().unwrap().clone()
}
}