use std::sync::{Arc, Mutex};
use wayland_client::commons::Implementation;
use wayland_client::protocol::{wl_compositor, wl_output, wl_seat, wl_shm, wl_subcompositor,
wl_surface};
use wayland_client::Proxy;
use wayland_protocols::xdg_shell::client::xdg_toplevel::ResizeEdge;
pub use wayland_protocols::xdg_shell::client::xdg_toplevel::State;
use Shell;
mod basic_frame;
mod shell;
pub use self::basic_frame::BasicFrame;
#[derive(Clone, Debug)]
pub enum Event {
Configure {
new_size: Option<(u32, u32)>,
states: Vec<State>,
},
Close,
Refresh,
}
struct WindowInner<F> {
frame: Arc<Mutex<F>>,
shell_surface: Arc<Box<shell::ShellSurface>>,
user_impl: Box<Implementation<(), Event> + Send>,
min_size: Option<(u32, u32)>,
max_size: Option<(u32, u32)>,
current_size: (u32, u32),
old_size: Option<(u32, u32)>,
}
pub struct Window<F: Frame> {
frame: Arc<Mutex<F>>,
surface: Proxy<wl_surface::WlSurface>,
shell_surface: Arc<Box<shell::ShellSurface>>,
inner: Arc<Mutex<Option<WindowInner<F>>>>,
}
impl<F: Frame + 'static> Window<F> {
pub fn init<Impl>(
surface: Proxy<wl_surface::WlSurface>,
initial_dims: (u32, u32),
compositor: &Proxy<wl_compositor::WlCompositor>,
subcompositor: &Proxy<wl_subcompositor::WlSubcompositor>,
shm: &Proxy<wl_shm::WlShm>,
shell: &Shell,
implementation: Impl,
) -> Result<Window<F>, F::Error>
where
Impl: Implementation<(), Event> + Send,
{
let inner = Arc::new(Mutex::new(None::<WindowInner<F>>));
let frame_inner = inner.clone();
let shell_inner = inner.clone();
let mut frame = F::init(
&surface,
compositor,
subcompositor,
shm,
Box::new(move |req, serial| {
if let Some(ref mut inner) = *shell_inner.lock().unwrap() {
match req {
FrameRequest::Minimize => inner.shell_surface.set_minimized(),
FrameRequest::Maximize => inner.shell_surface.set_maximized(),
FrameRequest::UnMaximize => inner.shell_surface.unset_maximized(),
FrameRequest::Move(seat) => inner.shell_surface.move_(&seat, serial),
FrameRequest::Resize(seat, edges) => {
inner.shell_surface.resize(&seat, serial, edges)
}
FrameRequest::Close => inner.user_impl.receive(Event::Close, ()),
FrameRequest::Refresh => inner.user_impl.receive(Event::Refresh, ()),
}
}
}) as Box<_>,
)?;
frame.resize(initial_dims);
let frame = Arc::new(Mutex::new(frame));
let shell_surface = Arc::new(shell::create_shell_surface(
shell,
&surface,
move |evt, ()| {
if let Some(ref mut inner) = *frame_inner.lock().unwrap() {
if let Event::Configure {
states,
mut new_size,
} = evt
{
let mut frame = inner.frame.lock().unwrap();
new_size = new_size.map(|(w, h)| {
use std::cmp::{max, min};
let (mut w, mut h) = frame.subtract_borders(w as i32, h as i32);
if let Some((minw, minh)) = inner.min_size {
w = max(w, minw as i32);
h = max(h, minh as i32);
}
if let Some((maxw, maxh)) = inner.max_size {
w = min(w, maxw as i32);
h = min(h, maxh as i32);
}
(w as u32, h as u32)
});
let mut need_refresh = false;
need_refresh |= frame.set_maximized(states.contains(&State::Maximized));
if need_refresh {
if states.contains(&State::Maximized) {
inner.old_size = Some(inner.current_size);
} else {
if new_size.is_none() {
new_size = inner.old_size.take();
}
}
}
need_refresh |= frame.set_active(states.contains(&State::Activated));
if need_refresh {
inner.user_impl.receive(Event::Refresh, ());
}
inner
.user_impl
.receive(Event::Configure { states, new_size }, ());
} else {
inner.user_impl.receive(evt, ());
}
}
},
));
*(inner.lock().unwrap()) = Some(WindowInner {
frame: frame.clone(),
shell_surface: shell_surface.clone(),
user_impl: Box::new(implementation) as Box<_>,
min_size: None,
max_size: None,
current_size: initial_dims,
old_size: None,
});
Ok(Window {
frame,
shell_surface,
surface,
inner,
})
}
pub fn new_seat(&mut self, seat: &Proxy<wl_seat::WlSeat>) {
self.frame.lock().unwrap().new_seat(seat);
}
pub fn surface(&self) -> &Proxy<wl_surface::WlSurface> {
&self.surface
}
pub fn refresh(&mut self) {
self.frame.lock().unwrap().redraw();
}
pub fn set_title(&self, title: String) {
self.shell_surface.set_title(title);
}
pub fn set_app_id(&self, app_id: String) {
self.shell_surface.set_app_id(app_id);
}
pub fn set_decorate(&self, decorate: bool) {
self.frame.lock().unwrap().set_hidden(!decorate);
}
pub fn set_resizable(&self, resizable: bool) {
self.frame.lock().unwrap().set_resizable(resizable);
let mut inner = self.inner.lock().unwrap();
if let Some(ref mut inner) = *inner {
if resizable {
self.shell_surface.set_min_size(inner.min_size.map(u_to_i));
self.shell_surface.set_max_size(inner.max_size.map(u_to_i));
} else {
self.shell_surface
.set_min_size(Some(u_to_i(inner.current_size)));
self.shell_surface
.set_max_size(Some(u_to_i(inner.current_size)));
}
}
}
pub fn resize(&mut self, w: u32, h: u32) {
use std::cmp::max;
let w = max(w, 1);
let h = max(h, 1);
if let Some(ref mut inner) = *self.inner.lock().unwrap() {
inner.current_size = (w, h);
}
self.frame.lock().unwrap().resize((w, h));
}
pub fn set_maximized(&self) {
self.shell_surface.set_maximized();
}
pub fn unset_maximized(&self) {
self.shell_surface.unset_maximized();
}
pub fn set_minimized(&self) {
self.shell_surface.set_minimized();
}
pub fn set_fullscreen(&self, output: Option<&Proxy<wl_output::WlOutput>>) {
self.shell_surface.set_fullscreen(output);
}
pub fn unset_fullscreen(&self) {
self.shell_surface.unset_fullscreen();
}
pub fn set_min_size(&mut self, size: Option<(u32, u32)>) {
let min_size =
size.map(|(w, h)| self.frame.lock().unwrap().add_borders(w as i32, h as i32));
self.shell_surface.set_min_size(min_size);
if let Some(ref mut inner) = *(self.inner.lock().unwrap()) {
inner.min_size = min_size.map(|(w, h)| (w as u32, h as u32));
}
}
pub fn set_max_size(&mut self, size: Option<(u32, u32)>) {
let max_size =
size.map(|(w, h)| self.frame.lock().unwrap().add_borders(w as i32, h as i32));
self.shell_surface.set_max_size(max_size);
if let Some(ref mut inner) = *(self.inner.lock().unwrap()) {
inner.max_size = max_size.map(|(w, h)| (w as u32, h as u32));
}
}
}
impl<F: Frame> Drop for Window<F> {
fn drop(&mut self) {
self.inner.lock().unwrap().take();
}
}
pub enum FrameRequest {
Minimize,
Maximize,
UnMaximize,
Close,
Move(Proxy<wl_seat::WlSeat>),
Resize(Proxy<wl_seat::WlSeat>, ResizeEdge),
Refresh,
}
pub trait Frame: Sized + Send {
type Error;
fn init(
base_surface: &Proxy<wl_surface::WlSurface>,
compositor: &Proxy<wl_compositor::WlCompositor>,
subcompositor: &Proxy<wl_subcompositor::WlSubcompositor>,
shm: &Proxy<wl_shm::WlShm>,
implementation: Box<Implementation<u32, FrameRequest> + Send>,
) -> Result<Self, Self::Error>;
fn set_active(&mut self, active: bool) -> bool;
fn set_maximized(&mut self, maximized: bool) -> bool;
fn set_hidden(&mut self, hidden: bool);
fn set_resizable(&mut self, resizable: bool);
fn new_seat(&mut self, seat: &Proxy<wl_seat::WlSeat>);
fn resize(&mut self, newsize: (u32, u32));
fn redraw(&mut self);
fn subtract_borders(&self, width: i32, height: i32) -> (i32, i32);
fn add_borders(&self, width: i32, height: i32) -> (i32, i32);
}
fn u_to_i(v: (u32, u32)) -> (i32, i32) {
(v.0 as i32, v.1 as i32)
}