use crate::context::DrawContext; use crate::controller::Controller; use crate::font::FontCache; use crate::scene::*; use crate::wayland::*; use crate::*; use smithay_client_toolkit::reexports::calloop::{EventLoop, LoopHandle, RegistrationToken}; use smithay_client_toolkit::seat::keyboard::ModifiersState; use smithay_client_toolkit::shm::AutoMemPool; use smithay_client_toolkit::WaylandSource; use std::cell::RefCell; use std::ops::{Deref, DerefMut}; use std::rc::Rc; use smithay_client_toolkit::reexports::client::{ global_filter, protocol::wl_buffer::WlBuffer, protocol::wl_callback, protocol::wl_compositor::WlCompositor, protocol::wl_output::{self, WlOutput}, protocol::wl_pointer::{self, WlPointer}, protocol::wl_region::WlRegion, protocol::wl_seat::{self, Capability, WlSeat}, protocol::wl_shm::WlShm, protocol::wl_surface::WlSurface, Attached, Display, GlobalError, GlobalManager, Interface, Main, Proxy, }; use smithay_client_toolkit::reexports::protocols::wlr::unstable::layer_shell::v1::client::{ zwlr_layer_shell_v1::ZwlrLayerShellV1, zwlr_layer_surface_v1, zwlr_layer_surface_v1::ZwlrLayerSurfaceV1, }; pub struct Application where C: Controller + Clone + 'static, { display: Display, globals: Rc>, global_manager: GlobalManager, pub inner: Vec>, token: RegistrationToken, } struct Context { pending_cb: bool, time: Option, render_node: Option, font_cache: FontCache, } pub struct CoreApplication where C: Controller + Clone, { pub controller: C, ctx: Context, globals: Rc>, mempool: AutoMemPool, widget: Box>, surface: Option, } pub struct InnerApplication where C: Controller + Clone, { core: CoreApplication, cb: Box, Event)>, } impl Surface { fn new( surface: Main, shell: Shell, region: Main, previous: Option, ) -> Self { Surface { alive: true, surface, shell, region, previous: if let Some(surface) = previous { Some(Box::new(surface)) } else { None }, buffer: None, } } fn commit(&mut self) { self.surface.commit(); std::mem::drop(&mut self.previous); self.previous = None; } fn destroy(&mut self) { self.alive = false; self.surface.destroy(); self.region.destroy(); self.shell.destroy(); if let Some(buffer) = self.buffer.as_ref() { buffer.destroy(); } self.buffer = None; } fn destroy_previous(&mut self) { if let Some(surface) = self.previous.as_mut() { surface.destroy(); } self.previous = None; } fn set_size(&self, width: u32, height: u32) { self.shell.set_size(width, height); } fn damage(&self, report: &[Region]) { self.surface.attach(self.buffer.as_ref(), 0, 0); for d in report { self.surface .damage(d.x as i32, d.y as i32, d.width as i32, d.height as i32); } } fn attach_buffer(&mut self, buffer: WlBuffer) { self.buffer = Some(buffer); } } impl Globals { fn new() -> Self { Self { outputs: Vec::new(), seats: Vec::new(), shm: None, compositor: None, shell: None, } } pub fn create_shell_surface_from( &self, geometry: &dyn Widget, config: ShellConfig, previous: Option, ) -> Option where M: 'static, C: Controller + Clone + 'static, { if self.compositor.is_some() { match config { ShellConfig::LayerShell(config) => { if let Some(layer_shell) = self.shell.as_ref() { let region = self.compositor.as_ref().unwrap().create_region(); let wl_surface = self.compositor.as_ref().unwrap().create_surface(); let layer_surface = layer_shell.get_layer_surface( &wl_surface, config.output.as_ref(), config.layer, config.namespace.clone(), ); if let Some(anchor) = &config.anchor { layer_surface.set_anchor(*anchor); } wl_surface.quick_assign(|_, _, _| {}); layer_surface.set_exclusive_zone(config.exclusive); layer_surface.set_keyboard_interactivity(config.interactivity); layer_surface.set_size(geometry.width() as u32, geometry.height() as u32); layer_surface.set_margin( config.margin[0], config.margin[1], config.margin[2], config.margin[3], ); wl_surface.commit(); assign_surface::(&layer_surface); return Some(Surface::new( wl_surface, Shell::LayerShell { surface: layer_surface, config, }, region, previous, )); } } } } None } pub fn create_mempool(&self) -> AutoMemPool { let attached = Attached::from(self.shm.clone().unwrap()); AutoMemPool::new(attached).unwrap() } pub fn get_outputs(&self) -> Vec { self.outputs.clone() } pub fn get_seats(&self) -> &[Seat] { &self.seats } } impl Output { fn new(output: Main) -> Self { Output { width: 0, height: 0, scale: 1, name: String::new(), output, } } } impl Application where M: 'static, C: Controller + Clone + 'static, { pub fn new(pointer: bool) -> (Self, EventLoop<'static, Self>) { let display = Display::connect_to_env().unwrap(); let event_queue = display.create_event_queue(); let attached_display = (*display).clone().attach(event_queue.token()); let display_handle = display.clone(); let globals = Globals::new(); let global_manager = GlobalManager::new_with_cb( &attached_display, global_filter!( [ ZwlrLayerShellV1, 1, |layer_shell: Main, mut application: DispatchData| { if let Some(application) = application.get::>() { if let Ok(mut globals) = application.globals.try_borrow_mut() { globals.shell = Some(layer_shell); } } } ], [ WlShm, 1, |shm: Main, mut application: DispatchData| { shm.quick_assign(|_, _, _| {}); if let Some(application) = application.get::>() { if let Ok(mut globals) = application.globals.try_borrow_mut() { globals.shm = Some(shm); } } } ], [ WlCompositor, 4, |compositor: Main, mut application: DispatchData| { if let Some(application) = application.get::>() { if let Ok(mut globals) = application.globals.try_borrow_mut() { globals.compositor = Some(compositor); } } } ], [WlSeat, 7, move |seat: Main, _: DispatchData| { seat.quick_assign(move |wl_seat, event, mut application| match event { wl_seat::Event::Capabilities { capabilities } => { if let Some(application) = application.get::>() { if pointer && capabilities & Capability::Pointer == Capability::Pointer { let pointer = wl_seat.get_pointer(); assign_pointer::(&pointer); } if let Ok(mut globals) = application.globals.try_borrow_mut() { let mut found = None; for seat in &mut globals.seats { if wl_seat.eq(&seat.seat) { found = Some(()); seat.capabilities = capabilities; } } if found.is_none() { globals.seats.push(Seat { capabilities, seat: wl_seat, }); } } } } _ => {} }); }], [ WlOutput, 3, |output: Main, _application: DispatchData| { output.quick_assign(move |wl_output, event, mut application| match event { wl_output::Event::Geometry { x: _, y: _, physical_width: _, physical_height: _, subpixel: _, make, model: _, transform: _, } => { if let Some(application) = application.get::>() { if let Ok(mut globals) = application.globals.try_borrow_mut() { let mut found = None; for output in &mut globals.outputs { if wl_output.eq(&output.output) { found = Some(()); output.name = make.clone(); } } if found.is_none() { let mut output = Output::new(wl_output); output.name = make; globals.outputs.push(output); } } } } wl_output::Event::Mode { flags: _, width, height, refresh: _, } => { if let Some(application) = application.get::>() { if let Ok(mut globals) = application.globals.try_borrow_mut() { let mut found = None; for output in &mut globals.outputs { if wl_output.eq(&output.output) { found = Some(()); output.width = width; output.height = height; } } if found.is_none() { let mut output = Output::new(wl_output); output.width = width; output.height = height; globals.outputs.push(output); } } } } wl_output::Event::Scale { factor } => { if let Some(application) = application.get::>() { if let Ok(mut globals) = application.globals.try_borrow_mut() { let mut found = None; for output in &mut globals.outputs { if wl_output.eq(&output.output) { found = Some(()); output.scale = factor; } } if found.is_none() { let mut output = Output::new(wl_output); output.scale = factor; globals.outputs.push(output); } } } } wl_output::Event::Done => {} _ => {} }); } ] ), ); let event_loop = EventLoop::try_new().expect("Failed to initialize the event loop!"); let token = WaylandSource::new(event_queue) .quick_insert(event_loop.handle()) .unwrap(); let (mut application, mut event_loop) = ( Application { display, globals: Rc::new(RefCell::new(globals)), global_manager, inner: Vec::new(), token, }, event_loop, ); for _ in 0..2 { display_handle.flush().unwrap(); event_loop.dispatch(None, &mut application).unwrap(); } (application, event_loop) } fn get_index(&self, surface: &WlSurface) -> usize { for i in 0..self.inner.len() { if self.inner[i].eq(surface) { return i; } } 0 } fn get_application(&mut self, surface: &WlSurface) -> Option<&mut InnerApplication> { for inner in &mut self.inner { if inner.eq(surface) { return Some(inner); } } None } pub fn get_global(&self) -> Result, GlobalError> where I: Interface + AsRef> + From>, { self.global_manager.instantiate_range::(0, 1 << 8) } pub fn create_empty_inner_application( &mut self, controller: C, widget: impl Widget + 'static, handle: LoopHandle<'_, Data>, cb: impl FnMut(&mut CoreApplication, Event) + 'static, ) { let inner_application = InnerApplication::empty(controller, widget, self.globals.clone(), cb); self.inner.push(inner_application); handle.update(&self.token).unwrap(); } pub fn create_inner_application_from( &mut self, controller: C, config: ShellConfig, widget: impl Widget + 'static, handle: LoopHandle<'_, Data>, cb: impl FnMut(&mut CoreApplication, Event) + 'static, ) { let inner_application = InnerApplication::new(controller, widget, config, self.globals.clone(), cb); self.inner.push(inner_application); handle.update(&self.token).unwrap(); } pub fn create_inner_application( &mut self, controller: C, widget: impl Widget + 'static, handle: LoopHandle<'_, Data>, cb: impl FnMut(&mut CoreApplication, Event) + 'static, ) { let inner_application = InnerApplication::normal(controller, widget, self.globals.clone(), cb); self.inner.push(inner_application); handle.update(&self.token).unwrap(); } pub fn run(mut self, event_loop: &mut EventLoop<'static, Self>) { loop { self.display.flush().unwrap(); event_loop.dispatch(None, &mut self).unwrap(); } } } impl Deref for InnerApplication where C: Controller + Clone + 'static, { type Target = CoreApplication; fn deref(&self) -> &Self::Target { &self.core } } impl DerefMut for InnerApplication where C: Controller + Clone + 'static, { fn deref_mut(&mut self) -> &mut Self::Target { &mut self.core } } impl CoreApplication where M: 'static, C: Controller + Clone + 'static, { pub fn poll(&mut self, ev: Event) -> C { let mut ctl = self.controller.clone(); let mut sync_ctx = SyncContext::new(&mut ctl, &mut self.ctx.font_cache); self.widget.sync(&mut sync_ctx, ev); ctl } pub fn sync(&mut self, ev: Event) -> bool { let mut sync_ctx = SyncContext::new(&mut self.controller, &mut self.ctx.font_cache); let mut damage = self.widget.sync(&mut sync_ctx, ev); while let Ok(msg) = sync_ctx.sync() { damage = damage.max(self.widget.sync(&mut sync_ctx, Event::Message(&msg))); } if damage == Damage::Frame { if self.ctx.time.is_none() { self.ctx.time = Some(0); } } damage.is_some() && !self.ctx.pending_cb } pub fn destroy(&mut self) { if let Some(surface) = self.surface.as_mut() { surface.destroy(); } } pub fn get_layer_surface(&self) -> ZwlrLayerSurfaceV1 { match &self.surface.as_ref().unwrap().shell { Shell::LayerShell { config: _, surface } => surface.detach(), } } pub fn is_hidden(&self) -> bool { if let Some(surface) = self.surface.as_ref() { return !surface.alive; } else { true } } pub fn replace_surface(&mut self) { if let Some(surface) = self.surface.as_mut() { surface.destroy(); surface.alive = true; match &surface.shell { Shell::LayerShell { config, surface: _ } => { self.surface = self.globals.borrow().create_shell_surface_from::( self.widget.deref(), ShellConfig::LayerShell(config.clone()), Some(surface.clone()), ); } } } else { self.surface = self.globals.borrow().create_shell_surface_from::( self.widget.deref(), ShellConfig::LayerShell(LayerShellConfig::default()), None, ); } } pub fn replace_surface_by(&mut self, config: ShellConfig) { if let Some(surface) = self.surface.as_mut() { surface.destroy(); surface.alive = true; self.surface = self.globals.borrow().create_shell_surface_from::( self.widget.deref(), config, Some(surface.clone()), ); } else { self.surface = self.globals.borrow().create_shell_surface_from::( self.widget.deref(), config, None, ); } } } impl Geometry for InnerApplication where C: Controller + Clone + 'static, { fn width(&self) -> f32 { self.widget.width() } fn height(&self) -> f32 { self.widget.height() } fn set_size(&mut self, width: f32, height: f32) -> Result<(), (f32, f32)> { if let Some(surface) = self.surface.as_ref() { surface.set_size(width as u32, height as u32); surface.surface.commit(); } Ok(()) } } impl InnerApplication where M: 'static, C: Controller + Clone + 'static, { pub fn empty( controller: C, widget: impl Widget + 'static, globals: Rc>, cb: impl FnMut(&mut CoreApplication, Event) + 'static, ) -> Self { let mempool = globals.borrow().create_mempool(); let mut default = InnerApplication { core: CoreApplication { controller, ctx: Context { pending_cb: false, time: None, font_cache: FontCache::new(), render_node: None, }, surface: None, widget: Box::new(widget), mempool, globals, }, cb: Box::new(cb), }; default.sync(Event::Prepare); default } pub fn normal( controller: C, widget: impl Widget + 'static, globals: Rc>, cb: impl FnMut(&mut CoreApplication, Event) + 'static, ) -> Self { let mempool = globals.borrow().create_mempool(); let mut default = InnerApplication { core: CoreApplication { controller, ctx: Context { pending_cb: false, time: None, font_cache: FontCache::new(), render_node: None, }, surface: None, widget: Box::new(widget), mempool, globals, }, cb: Box::new(cb), }; default.sync(Event::Prepare); default.replace_surface(); default } pub fn new( controller: C, widget: impl Widget + 'static, config: ShellConfig, globals: Rc>, cb: impl FnMut(&mut CoreApplication, Event) + 'static, ) -> Self { let mempool = globals.borrow().create_mempool(); let mut new = InnerApplication { core: CoreApplication { controller, ctx: Context { pending_cb: false, time: None, font_cache: FontCache::new(), render_node: None, }, surface: None, widget: Box::new(widget), mempool, globals, }, cb: Box::new(cb), }; new.sync(Event::Prepare); new.replace_surface_by(config); new } fn eq(&self, wl_surface: &WlSurface) -> bool { if let Some(surface) = &self.surface { return surface.surface.detach().eq(wl_surface); } false } pub fn roundtrip(&mut self, ev: Event) -> Result { let width = self.width(); let height = self.height(); // Sending the event to the widget tree if self.sync(ev) || ev.is_frame() { // Calling the applicationĀ“s closure (self.cb)(&mut self.core, ev); if !self.is_hidden() { let current_width = self.width(); let current_height = self.height(); // Resizing the surface in case the widget changed size if ev.is_frame() { self.ctx.render_node = None; } else if width != current_width || height != current_height { let _ = self.set_size(current_width, current_height); return Err(()); } // Creating the render node let render_node = self.core.widget.create_node(0., 0.); self.ctx.pending_cb = true; return Ok(render_node); } } else { // Calling the applicationĀ“s closure (self.cb)(&mut self.core, ev); } Err(()) } fn render(&mut self, time: u32, recent_node: RenderNode) { let width = recent_node.width(); let height = recent_node.height(); if Some(time).ne(&self.core.ctx.time) || time == 0 { if let Ok((buffer, wl_buffer)) = Buffer::new(&mut self.core.mempool, width as i32, height as i32) { let mut v = Vec::new(); let mut ctx = DrawContext::new(buffer.backend, &mut self.core.ctx.font_cache, &mut v); if let Some(render_node) = self.core.ctx.render_node.as_mut() { if let Err(region) = render_node.draw_merge( recent_node, &mut ctx, &Instruction::empty(0., 0., width, height), None, ) { ctx.damage_region(&Background::Transparent, region, false); } } else { ctx.damage_region( &Background::Transparent, Region::new(0., 0., width, height), false, ); recent_node.render(&mut ctx, None); self.core.ctx.render_node = Some(recent_node); } self.core.ctx.pending_cb = false; if let Some(surface) = self.core.surface.as_mut() { surface.attach_buffer(wl_buffer); surface.damage(&v); surface.commit(); if let Some(_) = self.core.ctx.time { self.core.ctx.time = Some(time); frame_callback::(time, surface.surface.clone()); } } } } } pub fn callback(&mut self, ev: Event) { if self.ctx.time.is_none() || ev.is_cb() { if let Ok(render_node) = self.roundtrip(ev) { if let Some(surface) = self.surface.as_ref() { draw_callback::(&surface.surface, render_node); } } } else { let width = self.width(); let height = self.height(); self.sync(ev); let current_width = self.width(); let current_height = self.height(); // Resizing the surface in case the widget changed size if width != current_width || height != current_height { let _ = self.set_size(current_width, current_height); } } } } fn frame_callback(time: u32, surface: Main) where M: 'static, C: Controller + Clone + 'static, { let h = surface.detach(); surface .frame() .quick_assign(move |_, event, mut application| match event { wl_callback::Event::Done { callback_data } => { let timeout = (callback_data - time).min(50); if let Some(application) = application.get::>() { if let Some(inner_application) = application.get_application(&h) { inner_application.ctx.time = None; inner_application.callback(Event::Callback(timeout)); } } } _ => {} }); surface.commit(); } fn draw_callback(surface: &Main, mut recent_node: RenderNode) where M: 'static, C: Controller + Clone + 'static, { let h = surface.detach(); surface .frame() .quick_assign(move |_, event, mut application| match event { wl_callback::Event::Done { callback_data } => { if let Some(application) = application.get::>() { let inner_application = application.get_application(&h).unwrap(); inner_application.render(callback_data, std::mem::take(&mut recent_node)); } } _ => {} }); surface.commit(); } impl From for Modifiers { fn from(modifer_state: ModifiersState) -> Modifiers { Modifiers { ctrl: modifer_state.ctrl, alt: modifer_state.alt, shift: modifer_state.shift, caps_lock: modifer_state.caps_lock, logo: modifer_state.logo, num_lock: modifer_state.num_lock, } } } fn assign_pointer(pointer: &Main) where M: 'static, C: Controller + Clone + 'static, { let mut index = 0; let mut input = Pointer::Enter; let (mut x, mut y) = (0., 0.); pointer.quick_assign(move |_, event, mut inner| match event { wl_pointer::Event::Leave { serial: _, surface } => { input = Pointer::Leave; if let Some(application) = inner.get::>() { if let Some(inner_application) = application.get_application(&surface) { inner_application.callback(Event::Pointer(x as f32, y as f32, input)); } } } wl_pointer::Event::Button { serial: _, time, button, state, } => { input = Pointer::MouseClick { time, button: MouseButton::new(button), pressed: state == wl_pointer::ButtonState::Pressed, }; } wl_pointer::Event::Frame => { if let Some(application) = inner.get::>() { let inner_application = application.inner.get_mut(index).unwrap(); inner_application.callback(Event::Pointer(x as f32, y as f32, input)); } } wl_pointer::Event::Axis { time: _, axis, value, } => { input = Pointer::Scroll { orientation: match axis { wl_pointer::Axis::VerticalScroll => Orientation::Vertical, wl_pointer::Axis::HorizontalScroll => Orientation::Horizontal, _ => Orientation::Vertical, }, value: value as f32, } } wl_pointer::Event::Enter { serial: _, surface, surface_x, surface_y, } => { if let Some(application) = inner.get::>() { x = surface_x; y = surface_y; index = application.get_index(&surface); } } wl_pointer::Event::Motion { time: _, surface_x, surface_y, } => { x = surface_x; y = surface_y; input = Pointer::Hover; } _ => {} }); } fn assign_surface(shell: &Main) where M: 'static, C: Controller + Clone + 'static, { shell.quick_assign(move |shell, event, mut inner| match event { zwlr_layer_surface_v1::Event::Configure { serial, width, height, } => { shell.ack_configure(serial); println!("\nCONFIGURE - {} : {} X {}\n", serial, width, height); if let Some(application) = inner.get::>() { for inner_application in &mut application.inner { if let Some(app_surface) = inner_application.surface.as_mut() { match &app_surface.shell { Shell::LayerShell { config: _, surface } => { if shell.eq(surface) { app_surface.destroy_previous(); let _ = inner_application .widget .set_size(width as f32, height as f32); if inner_application.ctx.pending_cb { if let Ok(render_node) = inner_application.roundtrip(Event::Frame) { draw_callback::( &inner_application .surface .as_ref() .unwrap() .surface, render_node, ); } } else { if let Ok(render_node) = inner_application.roundtrip(Event::Frame) { inner_application.render(0, render_node); } } } } } } } } } _ => unreachable!(), }); }