Visible on all outputs

This commit is contained in:
Kenny Levinsen
2019-08-10 00:01:23 +02:00
parent e9decaa594
commit 2bb0a2f29f
+173 -55
View File
@@ -13,7 +13,7 @@ use chrono::Local;
use smithay_client_toolkit::keyboard::{keysyms, map_keyboard_auto, Event as KbEvent, KeyState}; use smithay_client_toolkit::keyboard::{keysyms, map_keyboard_auto, Event as KbEvent, KeyState};
use smithay_client_toolkit::utils::DoubleMemPool; use smithay_client_toolkit::utils::DoubleMemPool;
use wayland_client::protocol::{wl_compositor, wl_pointer, wl_shm, wl_surface}; use wayland_client::protocol::{wl_compositor, wl_pointer, wl_shm, wl_surface, wl_output};
use wayland_client::{Display, EventQueue, GlobalEvent, GlobalManager, NewProxy}; use wayland_client::{Display, EventQueue, GlobalEvent, GlobalManager, NewProxy};
use wayland_protocols::wlr::unstable::layer_shell::v1::client::{ use wayland_protocols::wlr::unstable::layer_shell::v1::client::{
zwlr_layer_shell_v1, zwlr_layer_surface_v1, zwlr_layer_shell_v1, zwlr_layer_surface_v1,
@@ -43,30 +43,151 @@ use crate::sound::PulseAudio;
enum Cmd { enum Cmd {
Exit, Exit,
Draw, Draw,
ForceDraw,
MouseInput { pos: (u32, u32), input: Input }, MouseInput { pos: (u32, u32), input: Input },
KeyboardInput { input: Input }, KeyboardInput { input: Input },
} }
struct AppInner {
compositor: Option<wl_compositor::WlCompositor>,
surfaces: Vec<wl_surface::WlSurface>,
shell_surfaces: Vec<zwlr_layer_surface_v1::ZwlrLayerSurfaceV1>,
configured_surfaces: Arc<Mutex<usize>>,
outputs: Vec<(u32, wl_output::WlOutput)>,
shell: Option<zwlr_layer_shell_v1::ZwlrLayerShellV1>,
dimensions: (u32, u32),
draw_tx: Sender<bool>,
}
impl AppInner {
fn new(tx: Sender<bool>) -> AppInner{
AppInner{
compositor: None,
surfaces: Vec::new(),
shell_surfaces: Vec::new(),
configured_surfaces: Arc::new(Mutex::new(0)),
outputs: Vec::new(),
shell: None,
dimensions: (0, 0),
draw_tx: tx,
}
}
fn outputs_changed(&mut self) {
let shell = match self.shell {
Some(ref shell) => shell.to_owned(),
None => return,
};
let compositor = match self.compositor {
Some(ref c) => c.to_owned(),
None => return,
};
for shell_surface in self.shell_surfaces.iter() {
shell_surface.destroy();
}
for surface in self.surfaces.iter() {
surface.destroy();
}
let mut surfaces = Vec::new();
let mut shell_surfaces = Vec::new();
self.configured_surfaces = Arc::new(Mutex::new(0));
for output in self.outputs.iter() {
let surface = compositor
.create_surface(NewProxy::implement_dummy)
.unwrap();
let configured = self.configured_surfaces.clone();
let tx = self.draw_tx.clone();
let shell_surface = shell
.get_layer_surface(
&surface,
Some(&output.1),
zwlr_layer_shell_v1::Layer::Overlay,
"".to_string(),
move |layer| {
layer.implement_closure(
move |evt, layer| match evt {
zwlr_layer_surface_v1::Event::Configure { serial, .. } => {
*(configured.lock().unwrap()) += 1;
layer.ack_configure(serial);
tx.send(false).unwrap();
}
_ => unreachable!(),
},
(),
)
},
)
.unwrap();
shell_surface.set_keyboard_interactivity(1);
shell_surface.set_size(self.dimensions.0, self.dimensions.1);
surface.commit();
shell_surfaces.push(shell_surface);
surfaces.push(surface);
}
self.surfaces = surfaces;
self.shell_surfaces = shell_surfaces;
self.draw_tx.send(false).unwrap();
}
fn add_output(&mut self, id: u32, output: wl_output::WlOutput) {
self.outputs.push((id, output));
self.outputs_changed();
}
fn remove_output(&mut self, id: u32) {
let old_output = self.outputs.iter().find(|(output_id, _)| *output_id == id);
if let Some(output) = old_output {
let new_outputs = self.outputs.iter().filter(|(output_id, _)| *output_id != id).map(|(x, y)| (x.clone(), y.clone())).collect();
if output.1.as_ref().version() >= 3 {
output.1.release()
}
self.outputs = new_outputs;
self.outputs_changed();
}
}
fn set_compositor(&mut self, compositor: Option<wl_compositor::WlCompositor>) {
self.compositor = compositor
}
fn set_shell(&mut self, shell: Option<zwlr_layer_shell_v1::ZwlrLayerShellV1>) {
self.shell = shell
}
fn set_dimensions(&mut self, dimensions: (u32, u32)) {
self.dimensions = dimensions
}
}
struct App { struct App {
pools: DoubleMemPool, pools: DoubleMemPool,
display: Display, display: Display,
event_queue: EventQueue, event_queue: EventQueue,
surface: wl_surface::WlSurface,
cmd_queue: Arc<Mutex<VecDeque<Cmd>>>, cmd_queue: Arc<Mutex<VecDeque<Cmd>>>,
dimensions: (u32, u32),
modules: Vec<Module>, modules: Vec<Module>,
inner: Arc<Mutex<AppInner>>,
} }
impl App { impl App {
fn redraw(&mut self, force: bool) -> Result<(), ::std::io::Error> { fn redraw(&mut self, force: bool) -> Result<(), ::std::io::Error> {
let inner = self.inner.lock().unwrap();
let time = Local::now(); let time = Local::now();
if inner.shell_surfaces.len() != *inner.configured_surfaces.lock().unwrap() {
// Not ready yet
return Ok(());
}
let pool = match self.pools.pool() { let pool = match self.pools.pool() {
Some(pool) => pool, Some(pool) => pool,
None => return Ok(()), None => return Ok(()),
}; };
let (buf_x, buf_y) = self.dimensions; let (buf_x, buf_y) = inner.dimensions;
let bg = Color::new(0.0, 0.0, 0.0, 0.9); let bg = Color::new(0.0, 0.0, 0.0, 0.9);
@@ -76,7 +197,7 @@ impl App {
.expect("Failed to resize the memory pool."); .expect("Failed to resize the memory pool.");
let mmap = pool.mmap(); let mmap = pool.mmap();
let mut buf = Buffer::new(mmap, self.dimensions); let mut buf = Buffer::new(mmap, inner.dimensions);
let mut damage = vec![]; let mut damage = vec![];
{ {
@@ -105,11 +226,13 @@ impl App {
4 * buf_x as i32, 4 * buf_x as i32,
wl_shm::Format::Argb8888, wl_shm::Format::Argb8888,
); );
self.surface.attach(Some(&new_buffer), 0, 0); for surface in inner.surfaces.iter() {
for d in damage { surface.attach(Some(&new_buffer), 0, 0);
self.surface.damage(d.0, d.1, d.2, d.3); for d in damage.iter() {
surface.damage(d.0, d.1, d.2, d.3);
}
surface.commit();
} }
self.surface.commit();
Ok(()) Ok(())
} }
@@ -126,14 +249,15 @@ impl App {
} }
fn wipe(&mut self) { fn wipe(&mut self) {
let inner = self.inner.lock().unwrap();
let pool = match self.pools.pool() { let pool = match self.pools.pool() {
Some(pool) => pool, Some(pool) => pool,
None => return, None => return,
}; };
pool.resize((4 * self.dimensions.0 * self.dimensions.1) as usize) pool.resize((4 * inner.dimensions.0 * inner.dimensions.1) as usize)
.expect("Failed to resize the memory pool."); .expect("Failed to resize the memory pool.");
let mmap = pool.mmap(); let mmap = pool.mmap();
let mut buf = Buffer::new(mmap, self.dimensions); let mut buf = Buffer::new(mmap, inner.dimensions);
let bg = Color::new(0.0, 0.0, 0.0, 0.9); let bg = Color::new(0.0, 0.0, 0.0, 0.9);
buf.memset(&bg); buf.memset(&bg);
} }
@@ -148,6 +272,8 @@ impl App {
} }
fn new(tx: Sender<bool>) -> App { fn new(tx: Sender<bool>) -> App {
let inner = Arc::new(Mutex::new(AppInner::new(tx.clone())));
// //
// Set up modules // Set up modules
// //
@@ -182,25 +308,36 @@ impl App {
let (display, mut event_queue) = Display::connect_to_env().unwrap(); let (display, mut event_queue) = Display::connect_to_env().unwrap();
let display_wrapper = display let display_wrapper = display
.as_ref() .as_ref()
.make_wrapper(&event_queue.get_token()) .make_wrapper(&event_queue.get_token())
.unwrap() .unwrap()
.into(); .into();
// //
// Set up global manager // Set up global manager
// //
let manager = GlobalManager::new_with_cb(&display_wrapper, move |event, _| match event { let inner_global = inner.clone();
let manager = GlobalManager::new_with_cb(&display_wrapper, move |event, registry| match event {
GlobalEvent::New { GlobalEvent::New {
id: _, id,
interface: _, ref interface,
version: _, version,
} => {} } => {
GlobalEvent::Removed { if let "wl_output" = &interface[..] {
id: _, let output = registry.bind(version, id, move |output| {
interface: _, output.implement_closure (move |_, _| {}, ())
} => {} }).unwrap();
inner_global.lock().unwrap().add_output(id, output);
}
}
GlobalEvent::Removed { id, ref interface } => {
if let "wl_output" = &interface[..] {
inner_global.lock().unwrap().remove_output(id);
}
}
}); });
// double sync to retrieve the global list // double sync to retrieve the global list
@@ -213,6 +350,8 @@ impl App {
.instantiate_range(1, 4, NewProxy::implement_dummy) .instantiate_range(1, 4, NewProxy::implement_dummy)
.expect("server didn't advertise `wl_compositor`"); .expect("server didn't advertise `wl_compositor`");
inner.lock().unwrap().set_compositor(Some(compositor));
// wl_shm // wl_shm
let shm_formats = Arc::new(Mutex::new(Vec::new())); let shm_formats = Arc::new(Mutex::new(Vec::new()));
let shm_formats2 = shm_formats.clone(); let shm_formats2 = shm_formats.clone();
@@ -267,7 +406,7 @@ impl App {
// //
// Prepare shell so that we can create our shell surface // Prepare shell so that we can create our shell surface
// //
let shell = if let Ok(layer) = manager.instantiate_exact( inner.lock().unwrap().set_shell(Some(if let Ok(layer) = manager.instantiate_exact(
1, 1,
|layer: NewProxy<zwlr_layer_shell_v1::ZwlrLayerShellV1>| { |layer: NewProxy<zwlr_layer_shell_v1::ZwlrLayerShellV1>| {
layer.implement_closure(|_, _| {}, ()) layer.implement_closure(|_, _| {}, ())
@@ -276,31 +415,7 @@ impl App {
layer layer
} else { } else {
panic!("server didn't advertise `zwlr_layer_shell_v1`"); panic!("server didn't advertise `zwlr_layer_shell_v1`");
}; }));
let surface = compositor
.create_surface(NewProxy::implement_dummy)
.unwrap();
let shell_surface = shell
.get_layer_surface(
&surface,
None,
zwlr_layer_shell_v1::Layer::Overlay,
"".to_string(),
move |layer| {
layer.implement_closure(
move |evt, layer| match evt {
zwlr_layer_surface_v1::Event::Configure { serial, .. } => {
layer.ack_configure(serial)
}
_ => unreachable!(),
},
(),
)
},
)
.unwrap();
// //
// Calculate window dimensions // Calculate window dimensions
@@ -314,11 +429,8 @@ impl App {
} }
// Add padding // Add padding
dimensions = (dimensions.0 + 40, dimensions.1 + 40); inner.lock().unwrap().set_dimensions((dimensions.0 + 40, dimensions.1 + 40));
inner.lock().unwrap().outputs_changed();
shell_surface.set_keyboard_interactivity(1);
shell_surface.set_size(dimensions.0, dimensions.1);
surface.commit();
event_queue.sync_roundtrip().unwrap(); event_queue.sync_roundtrip().unwrap();
// //
@@ -401,13 +513,12 @@ impl App {
display.flush().unwrap(); display.flush().unwrap();
App { App {
surface: surface,
display: display, display: display,
event_queue: event_queue, event_queue: event_queue,
cmd_queue: cmd_queue, cmd_queue: cmd_queue,
pools: pools, pools: pools,
dimensions: dimensions,
modules: modules, modules: modules,
inner: inner,
} }
} }
} }
@@ -421,8 +532,11 @@ fn main() {
let worker_queue = app.cmd_queue(); let worker_queue = app.cmd_queue();
std::thread::spawn(move || loop { std::thread::spawn(move || loop {
rx_draw.recv().unwrap(); if rx_draw.recv().unwrap() {
worker_queue.lock().unwrap().push_back(Cmd::Draw); worker_queue.lock().unwrap().push_back(Cmd::Draw);
} else {
worker_queue.lock().unwrap().push_back(Cmd::ForceDraw);
}
tx_pipe.write_all(&[0x1]).unwrap(); tx_pipe.write_all(&[0x1]).unwrap();
}); });
@@ -442,6 +556,10 @@ fn main() {
app.redraw(false).expect("Failed to draw"); app.redraw(false).expect("Failed to draw");
app.flush_display(); app.flush_display();
} }
Cmd::ForceDraw => {
app.redraw(true).expect("Failed to draw");
app.flush_display();
}
Cmd::MouseInput { pos, input } => { Cmd::MouseInput { pos, input } => {
if let Some(m) = app.get_module(pos) { if let Some(m) = app.get_module(pos) {
let bounds = m.get_bounds(); let bounds = m.get_bounds();