feat: valw backdrop
This commit is contained in:
1 parent
94cc30475f
commit
3f529f3a65
4 files changed
+326
-7
No files matched your search
+269
@@ -0,0 +1,269 @@
|
|||||||
|
//! `valw backdrop`: the paint shader, slow and calm, behind niri's
|
||||||
|
//! overview (niri's `place-within-backdrop` layer rule), coloured from each
|
||||||
|
//! output's wallpaper. It draws only when niri asks for frames, so it costs
|
||||||
|
//! nothing while the overview is closed.
|
||||||
|
|
||||||
|
use std::sync::mpsc;
|
||||||
|
use std::time::{Duration, Instant};
|
||||||
|
|
||||||
|
use anyhow::Result;
|
||||||
|
use smithay_client_toolkit::{
|
||||||
|
compositor::{FrameCallbackData, Region},
|
||||||
|
shell::{
|
||||||
|
WaylandSurface,
|
||||||
|
wlr_layer::{Anchor, KeyboardInteractivity, Layer, LayerSurface},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
use wayland_client::{
|
||||||
|
Connection, QueueHandle,
|
||||||
|
protocol::{wl_output::WlOutput, wl_surface::WlSurface},
|
||||||
|
};
|
||||||
|
use wayland_protocols::wp::viewporter::client::wp_viewport::WpViewport;
|
||||||
|
|
||||||
|
use crate::lock::Lock;
|
||||||
|
use crate::theme::Palette;
|
||||||
|
use crate::theme::gl::{Frame, Paint};
|
||||||
|
use crate::wayland::{State, Wayland};
|
||||||
|
|
||||||
|
pub const NAMESPACE: &str = "valw-backdrop";
|
||||||
|
const SPEED: f32 = 0.35;
|
||||||
|
/// A pause this long means the overview was closed: re-read the wallpaper.
|
||||||
|
const PAUSE: Duration = Duration::from_secs(2);
|
||||||
|
const EASE: Duration = Duration::from_secs(1);
|
||||||
|
|
||||||
|
/// Whether to re-read the wallpaper's colours before this frame.
|
||||||
|
pub fn should_refresh(last_frame: Option<Instant>, now: Instant) -> bool {
|
||||||
|
last_frame.is_none_or(|t| now.saturating_duration_since(t) > PAUSE)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// `from` easing into `to`, `since` after the change started.
|
||||||
|
pub fn ease(from: &Palette, to: &Palette, since: Duration) -> Palette {
|
||||||
|
from.lerp(to, since.as_secs_f32() / EASE.as_secs_f32())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The wallpaper's palette on `connector`, if Noctalia tells us one.
|
||||||
|
fn wallpaper_palette(connector: &str) -> Option<Palette> {
|
||||||
|
let path = crate::theme::wallpaper(connector)?;
|
||||||
|
let img = image::ImageReader::open(&path)
|
||||||
|
.ok()?
|
||||||
|
.with_guessed_format()
|
||||||
|
.ok()?
|
||||||
|
.decode()
|
||||||
|
.ok()?
|
||||||
|
.thumbnail(256, 256)
|
||||||
|
.to_rgba8();
|
||||||
|
Some(crate::theme::from_image(&img, false))
|
||||||
|
}
|
||||||
|
|
||||||
|
struct Surface {
|
||||||
|
// Dropped first: the EGL surface goes before the wl_surface under it.
|
||||||
|
paint: Option<Paint>,
|
||||||
|
layer: LayerSurface,
|
||||||
|
viewport: WpViewport,
|
||||||
|
output: WlOutput,
|
||||||
|
name: String,
|
||||||
|
scale: f64,
|
||||||
|
start: Instant,
|
||||||
|
last_frame: Option<Instant>,
|
||||||
|
from: Palette,
|
||||||
|
to: Palette,
|
||||||
|
changed: Instant,
|
||||||
|
/// A wallpaper palette being worked out on a thread.
|
||||||
|
incoming: Option<mpsc::Receiver<Option<Palette>>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Default)]
|
||||||
|
pub struct Backdrop {
|
||||||
|
surfaces: Vec<Surface>,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Runs until the compositor goes away. A second instance exits at once.
|
||||||
|
pub fn run() -> Result<()> {
|
||||||
|
let path = crate::lock::default_path().with_file_name("valw-backdrop.lock");
|
||||||
|
let Ok(_lock) = Lock::acquire(&path) else {
|
||||||
|
tracing::info!("another backdrop is running");
|
||||||
|
return Ok(());
|
||||||
|
};
|
||||||
|
let mut wl = Wayland::connect()?;
|
||||||
|
wl.state.backdrop = Some(Backdrop::default());
|
||||||
|
let qh = wl.queue.handle();
|
||||||
|
for output in wl.outputs() {
|
||||||
|
add(&mut wl.state, &qh, &output.wl);
|
||||||
|
}
|
||||||
|
wl.dispatch_blocking(|_| false)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Puts a backdrop surface on `output`.
|
||||||
|
pub fn add(state: &mut State, qh: &QueueHandle<State>, output: &WlOutput) {
|
||||||
|
let Some(info) = state.output_list().into_iter().find(|o| &o.wl == output) else {
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
let (Some(layer_shell), Some(viewporter)) = (&state.layer_shell, &state.viewporter) else {
|
||||||
|
tracing::warn!("no layer-shell or viewporter: no backdrop");
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
let surface = state.compositor.create_surface(qh);
|
||||||
|
let layer = layer_shell.create_layer_surface(
|
||||||
|
qh,
|
||||||
|
surface,
|
||||||
|
Layer::Background,
|
||||||
|
Some(NAMESPACE),
|
||||||
|
Some(output),
|
||||||
|
);
|
||||||
|
layer.set_anchor(Anchor::all());
|
||||||
|
layer.set_exclusive_zone(-1);
|
||||||
|
layer.set_keyboard_interactivity(KeyboardInteractivity::None);
|
||||||
|
// Clicks go to niri, not to the backdrop.
|
||||||
|
if let Ok(empty) = Region::new(&state.compositor) {
|
||||||
|
layer.wl_surface().set_input_region(Some(empty.wl_region()));
|
||||||
|
}
|
||||||
|
layer.commit();
|
||||||
|
let viewport = viewporter.get_viewport(layer.wl_surface(), qh, ());
|
||||||
|
let now = Instant::now();
|
||||||
|
tracing::info!("backdrop on {}", info.geom.name);
|
||||||
|
let palette = crate::theme::current();
|
||||||
|
if let Some(b) = &mut state.backdrop {
|
||||||
|
b.surfaces.push(Surface {
|
||||||
|
paint: None,
|
||||||
|
layer,
|
||||||
|
viewport,
|
||||||
|
output: output.clone(),
|
||||||
|
name: info.geom.name,
|
||||||
|
scale: info.scale,
|
||||||
|
start: now,
|
||||||
|
last_frame: None,
|
||||||
|
from: palette,
|
||||||
|
to: palette,
|
||||||
|
changed: now,
|
||||||
|
incoming: None,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Backdrop {
|
||||||
|
fn index(&self, surface: &WlSurface) -> Option<usize> {
|
||||||
|
self.surfaces
|
||||||
|
.iter()
|
||||||
|
.position(|s| s.layer.wl_surface() == surface)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn remove(&mut self, output: &WlOutput) {
|
||||||
|
self.surfaces.retain(|s| &s.output != output);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn closed(&mut self, layer: &LayerSurface) {
|
||||||
|
self.surfaces
|
||||||
|
.retain(|s| s.layer.wl_surface() != layer.wl_surface());
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn configure(
|
||||||
|
&mut self,
|
||||||
|
conn: &Connection,
|
||||||
|
layer: &LayerSurface,
|
||||||
|
(w, h): (u32, u32),
|
||||||
|
qh: &QueueHandle<State>,
|
||||||
|
) {
|
||||||
|
let Some(i) = self.index(layer.wl_surface()) else {
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
let s = &mut self.surfaces[i];
|
||||||
|
if w == 0 || h == 0 {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
let px = (
|
||||||
|
(w as f64 * s.scale).round() as u32,
|
||||||
|
(h as f64 * s.scale).round() as u32,
|
||||||
|
);
|
||||||
|
s.viewport.set_destination(w as i32, h as i32);
|
||||||
|
match &mut s.paint {
|
||||||
|
Some(paint) => paint.resize(px),
|
||||||
|
None => match Paint::new(conn, s.layer.wl_surface(), px) {
|
||||||
|
Ok(paint) => s.paint = Some(paint),
|
||||||
|
Err(e) => {
|
||||||
|
tracing::warn!("no backdrop on {}: {e:#}", s.name);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}
|
||||||
|
s.draw(qh);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn frame_done(&mut self, surface: &WlSurface, qh: &QueueHandle<State>) {
|
||||||
|
if let Some(i) = self.index(surface) {
|
||||||
|
self.surfaces[i].draw(qh);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Surface {
|
||||||
|
fn draw(&mut self, qh: &QueueHandle<State>) {
|
||||||
|
let now = Instant::now();
|
||||||
|
if should_refresh(self.last_frame, now) && self.incoming.is_none() {
|
||||||
|
let (tx, rx) = mpsc::channel();
|
||||||
|
let name = self.name.clone();
|
||||||
|
std::thread::spawn(move || {
|
||||||
|
let _ = tx.send(wallpaper_palette(&name));
|
||||||
|
});
|
||||||
|
self.incoming = Some(rx);
|
||||||
|
}
|
||||||
|
if let Some(rx) = &self.incoming
|
||||||
|
&& let Ok(result) = rx.try_recv()
|
||||||
|
{
|
||||||
|
match &result {
|
||||||
|
Some(p) => tracing::info!("backdrop on {}: wallpaper palette {p:?}", self.name),
|
||||||
|
None => tracing::info!("backdrop on {}: no wallpaper palette", self.name),
|
||||||
|
}
|
||||||
|
if let Some(palette) = result {
|
||||||
|
self.from = ease(&self.from, &self.to, now - self.changed);
|
||||||
|
self.to = palette;
|
||||||
|
self.changed = now;
|
||||||
|
}
|
||||||
|
self.incoming = None;
|
||||||
|
}
|
||||||
|
self.last_frame = Some(now);
|
||||||
|
let Some(paint) = &self.paint else {
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
let surface = self.layer.wl_surface();
|
||||||
|
surface.frame(qh, FrameCallbackData(surface.clone()));
|
||||||
|
let frame = Frame {
|
||||||
|
time: (now - self.start).as_secs_f32(),
|
||||||
|
motion: 0.0,
|
||||||
|
speed: SPEED,
|
||||||
|
scale: 1.0,
|
||||||
|
palette: ease(&self.from, &self.to, now - self.changed),
|
||||||
|
};
|
||||||
|
if let Err(e) = paint.draw(&frame) {
|
||||||
|
tracing::warn!("backdrop on {}: {e:#}", self.name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn refresh_after_a_pause() {
|
||||||
|
let now = Instant::now();
|
||||||
|
assert!(should_refresh(None, now), "first frame");
|
||||||
|
assert!(!should_refresh(Some(now - Duration::from_secs(1)), now));
|
||||||
|
assert!(should_refresh(Some(now - Duration::from_secs(3)), now));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn colours_ease_over_a_second() {
|
||||||
|
let from = Palette::DEFAULT;
|
||||||
|
let to = Palette {
|
||||||
|
base: [1.0; 3],
|
||||||
|
body: [1.0; 3],
|
||||||
|
highlight: [1.0; 3],
|
||||||
|
};
|
||||||
|
assert_eq!(ease(&from, &to, Duration::ZERO), from);
|
||||||
|
assert_eq!(
|
||||||
|
ease(&from, &to, Duration::from_millis(500)),
|
||||||
|
from.lerp(&to, 0.5)
|
||||||
|
);
|
||||||
|
assert_eq!(ease(&from, &to, Duration::from_secs(2)), to);
|
||||||
|
}
|
||||||
|
}
|
||||||
+5
-2
@@ -1,3 +1,4 @@
|
|||||||
|
mod backdrop;
|
||||||
mod capture;
|
mod capture;
|
||||||
mod config;
|
mod config;
|
||||||
mod detach;
|
mod detach;
|
||||||
@@ -18,8 +19,6 @@ mod selection;
|
|||||||
mod shadow;
|
mod shadow;
|
||||||
mod sound;
|
mod sound;
|
||||||
mod stack;
|
mod stack;
|
||||||
// Parts of the theme are used from Task 4 of the theme plan on; that task removes this.
|
|
||||||
#[allow(dead_code)]
|
|
||||||
mod theme;
|
mod theme;
|
||||||
mod thumbnail;
|
mod thumbnail;
|
||||||
mod toolbar;
|
mod toolbar;
|
||||||
@@ -82,6 +81,8 @@ enum Command {
|
|||||||
},
|
},
|
||||||
/// Pick a mode from a floating bar (Cmd+Shift+5).
|
/// Pick a mode from a floating bar (Cmd+Shift+5).
|
||||||
Toolbar,
|
Toolbar,
|
||||||
|
/// The paint shader behind niri's overview (keep it running; see the README).
|
||||||
|
Backdrop,
|
||||||
/// Report what the compositor and system support.
|
/// Report what the compositor and system support.
|
||||||
Doctor,
|
Doctor,
|
||||||
/// Internal: the process that shows preview thumbnails.
|
/// Internal: the process that shows preview thumbnails.
|
||||||
@@ -198,6 +199,7 @@ fn main() -> ExitCode {
|
|||||||
fn run(cli: Cli) -> Result<()> {
|
fn run(cli: Cli) -> Result<()> {
|
||||||
match cli.command {
|
match cli.command {
|
||||||
Command::Doctor => doctor::run(),
|
Command::Doctor => doctor::run(),
|
||||||
|
Command::Backdrop => backdrop::run(),
|
||||||
Command::PreviewHost => host::run(),
|
Command::PreviewHost => host::run(),
|
||||||
Command::Screen { all, common } => capture(Mode::Screen { all }, common),
|
Command::Screen { all, common } => capture(Mode::Screen { all }, common),
|
||||||
Command::Region { common } => capture(Mode::Region, common),
|
Command::Region { common } => capture(Mode::Region, common),
|
||||||
@@ -446,6 +448,7 @@ mod tests {
|
|||||||
assert!(!parses(&["edit"]));
|
assert!(!parses(&["edit"]));
|
||||||
assert!(parses(&["__clipboard"]));
|
assert!(parses(&["__clipboard"]));
|
||||||
assert!(parses(&["toolbar"]));
|
assert!(parses(&["toolbar"]));
|
||||||
|
assert!(parses(&["backdrop"]));
|
||||||
assert!(parses(&["__combo-demo"]));
|
assert!(parses(&["__combo-demo"]));
|
||||||
assert!(parses(&["__check-config", "c.toml"]));
|
assert!(parses(&["__check-config", "c.toml"]));
|
||||||
assert!(!parses(&["__check-config"]));
|
assert!(!parses(&["__check-config"]));
|
||||||
|
|||||||
+23
-2
@@ -48,6 +48,8 @@ struct Uniforms {
|
|||||||
pub struct Paint {
|
pub struct Paint {
|
||||||
gl: glow::Context,
|
gl: glow::Context,
|
||||||
u: Uniforms,
|
u: Uniforms,
|
||||||
|
// Read by set_overlay, which the picker (theme plan Task 6) starts using.
|
||||||
|
#[allow(dead_code)]
|
||||||
overlay: glow::Texture,
|
overlay: glow::Texture,
|
||||||
size: (u32, u32),
|
size: (u32, u32),
|
||||||
egl: Egl,
|
egl: Egl,
|
||||||
@@ -104,9 +106,22 @@ impl Paint {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Several renderers (one per output) share the EGL display: each makes
|
||||||
|
/// its own context current before touching GL.
|
||||||
|
fn current(&self) -> Result<()> {
|
||||||
|
self.egl
|
||||||
|
.make_current(
|
||||||
|
self.display,
|
||||||
|
Some(self.surface),
|
||||||
|
Some(self.surface),
|
||||||
|
Some(self.context),
|
||||||
|
)
|
||||||
|
.context("eglMakeCurrent failed")
|
||||||
|
}
|
||||||
|
|
||||||
/// The surface's buffer size changed.
|
/// The surface's buffer size changed.
|
||||||
pub fn resize(&mut self, size: (u32, u32)) {
|
pub fn resize(&mut self, size: (u32, u32)) {
|
||||||
if size != self.size {
|
if size != self.size && self.current().is_ok() {
|
||||||
self.window.resize(size.0 as i32, size.1 as i32, 0, 0);
|
self.window.resize(size.0 as i32, size.1 as i32, 0, 0);
|
||||||
unsafe { self.gl.viewport(0, 0, size.0 as i32, size.1 as i32) };
|
unsafe { self.gl.viewport(0, 0, size.0 as i32, size.1 as i32) };
|
||||||
self.size = size;
|
self.size = size;
|
||||||
@@ -115,7 +130,11 @@ impl Paint {
|
|||||||
|
|
||||||
/// Shows `pixmap` (premultiplied RGBA, the surface's size) over the
|
/// Shows `pixmap` (premultiplied RGBA, the surface's size) over the
|
||||||
/// paint, or nothing.
|
/// paint, or nothing.
|
||||||
|
#[allow(dead_code)] // the picker (theme plan Task 6) removes this
|
||||||
pub fn set_overlay(&mut self, pixmap: Option<&tiny_skia::Pixmap>) {
|
pub fn set_overlay(&mut self, pixmap: Option<&tiny_skia::Pixmap>) {
|
||||||
|
if self.current().is_err() {
|
||||||
|
return;
|
||||||
|
}
|
||||||
unsafe {
|
unsafe {
|
||||||
self.gl
|
self.gl
|
||||||
.uniform_1_i32(Some(&self.u.use_overlay), pixmap.is_some() as i32);
|
.uniform_1_i32(Some(&self.u.use_overlay), pixmap.is_some() as i32);
|
||||||
@@ -139,6 +158,7 @@ impl Paint {
|
|||||||
|
|
||||||
/// Draws `frame` and swaps (which commits the surface).
|
/// Draws `frame` and swaps (which commits the surface).
|
||||||
pub fn draw(&self, frame: &Frame) -> Result<()> {
|
pub fn draw(&self, frame: &Frame) -> Result<()> {
|
||||||
|
self.current()?;
|
||||||
let p = frame.palette;
|
let p = frame.palette;
|
||||||
unsafe {
|
unsafe {
|
||||||
let gl = &self.gl;
|
let gl = &self.gl;
|
||||||
@@ -168,7 +188,8 @@ impl Drop for Paint {
|
|||||||
let _ = self.egl.make_current(self.display, None, None, None);
|
let _ = self.egl.make_current(self.display, None, None, None);
|
||||||
let _ = self.egl.destroy_surface(self.display, self.surface);
|
let _ = self.egl.destroy_surface(self.display, self.surface);
|
||||||
let _ = self.egl.destroy_context(self.display, self.context);
|
let _ = self.egl.destroy_context(self.display, self.context);
|
||||||
let _ = self.egl.terminate(self.display);
|
// No eglTerminate: the display is shared by every renderer on this
|
||||||
|
// connection, and terminating it would break the others.
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+29
-3
@@ -36,6 +36,7 @@ use wayland_protocols::wp::viewporter::client::{
|
|||||||
};
|
};
|
||||||
use wayland_protocols_wlr::screencopy::v1::client::zwlr_screencopy_manager_v1::ZwlrScreencopyManagerV1;
|
use wayland_protocols_wlr::screencopy::v1::client::zwlr_screencopy_manager_v1::ZwlrScreencopyManagerV1;
|
||||||
|
|
||||||
|
use crate::backdrop::Backdrop;
|
||||||
use crate::capture::Pending;
|
use crate::capture::Pending;
|
||||||
use crate::dnd::Outcome;
|
use crate::dnd::Outcome;
|
||||||
use crate::error::HintExt;
|
use crate::error::HintExt;
|
||||||
@@ -87,6 +88,8 @@ pub struct State {
|
|||||||
/// The toolbar and its countdown, while they are open.
|
/// The toolbar and its countdown, while they are open.
|
||||||
pub toolbar: Option<Toolbar>,
|
pub toolbar: Option<Toolbar>,
|
||||||
pub pill: Option<Pill>,
|
pub pill: Option<Pill>,
|
||||||
|
/// `valw backdrop`'s surfaces.
|
||||||
|
pub backdrop: Option<Backdrop>,
|
||||||
/// The preview thumbnails, in the preview host process.
|
/// The preview thumbnails, in the preview host process.
|
||||||
pub preview: Option<Host>,
|
pub preview: Option<Host>,
|
||||||
}
|
}
|
||||||
@@ -121,6 +124,7 @@ impl Wayland {
|
|||||||
zoom: None,
|
zoom: None,
|
||||||
toolbar: None,
|
toolbar: None,
|
||||||
pill: None,
|
pill: None,
|
||||||
|
backdrop: None,
|
||||||
preview: None,
|
preview: None,
|
||||||
};
|
};
|
||||||
// Two round trips: one for wl_output, one for the xdg-output details.
|
// Two round trips: one for wl_output, one for the xdg-output details.
|
||||||
@@ -310,6 +314,9 @@ impl CompositorHandler for State {
|
|||||||
if let Some(zoom) = &mut self.zoom {
|
if let Some(zoom) = &mut self.zoom {
|
||||||
zoom.frame_done(surface, qh);
|
zoom.frame_done(surface, qh);
|
||||||
}
|
}
|
||||||
|
if let Some(backdrop) = &mut self.backdrop {
|
||||||
|
backdrop.frame_done(surface, qh);
|
||||||
|
}
|
||||||
if let Some(preview) = &mut self.preview {
|
if let Some(preview) = &mut self.preview {
|
||||||
preview.frame_done(surface, qh);
|
preview.frame_done(surface, qh);
|
||||||
}
|
}
|
||||||
@@ -339,11 +346,24 @@ impl OutputHandler for State {
|
|||||||
&mut self.outputs
|
&mut self.outputs
|
||||||
}
|
}
|
||||||
|
|
||||||
fn new_output(&mut self, _: &Connection, _: &QueueHandle<Self>, _: wl_output::WlOutput) {}
|
fn new_output(&mut self, _: &Connection, qh: &QueueHandle<Self>, output: wl_output::WlOutput) {
|
||||||
|
if self.backdrop.is_some() {
|
||||||
|
crate::backdrop::add(self, qh, &output);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn update_output(&mut self, _: &Connection, _: &QueueHandle<Self>, _: wl_output::WlOutput) {}
|
fn update_output(&mut self, _: &Connection, _: &QueueHandle<Self>, _: wl_output::WlOutput) {}
|
||||||
|
|
||||||
fn output_destroyed(&mut self, _: &Connection, _: &QueueHandle<Self>, _: wl_output::WlOutput) {}
|
fn output_destroyed(
|
||||||
|
&mut self,
|
||||||
|
_: &Connection,
|
||||||
|
_: &QueueHandle<Self>,
|
||||||
|
output: wl_output::WlOutput,
|
||||||
|
) {
|
||||||
|
if let Some(backdrop) = &mut self.backdrop {
|
||||||
|
backdrop.remove(&output);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl LayerShellHandler for State {
|
impl LayerShellHandler for State {
|
||||||
@@ -360,6 +380,9 @@ impl LayerShellHandler for State {
|
|||||||
if let Some(pill) = &mut self.pill {
|
if let Some(pill) = &mut self.pill {
|
||||||
pill.closed(layer);
|
pill.closed(layer);
|
||||||
}
|
}
|
||||||
|
if let Some(backdrop) = &mut self.backdrop {
|
||||||
|
backdrop.closed(layer);
|
||||||
|
}
|
||||||
if let Some(preview) = &mut self.preview {
|
if let Some(preview) = &mut self.preview {
|
||||||
preview.closed(layer);
|
preview.closed(layer);
|
||||||
}
|
}
|
||||||
@@ -367,7 +390,7 @@ impl LayerShellHandler for State {
|
|||||||
|
|
||||||
fn configure(
|
fn configure(
|
||||||
&mut self,
|
&mut self,
|
||||||
_: &Connection,
|
conn: &Connection,
|
||||||
qh: &QueueHandle<Self>,
|
qh: &QueueHandle<Self>,
|
||||||
layer: &LayerSurface,
|
layer: &LayerSurface,
|
||||||
configure: LayerSurfaceConfigure,
|
configure: LayerSurfaceConfigure,
|
||||||
@@ -385,6 +408,9 @@ impl LayerShellHandler for State {
|
|||||||
if let Some(pill) = &mut self.pill {
|
if let Some(pill) = &mut self.pill {
|
||||||
pill.configure(layer);
|
pill.configure(layer);
|
||||||
}
|
}
|
||||||
|
if let Some(backdrop) = &mut self.backdrop {
|
||||||
|
backdrop.configure(conn, layer, configure.new_size, qh);
|
||||||
|
}
|
||||||
if let Some(preview) = &mut self.preview {
|
if let Some(preview) = &mut self.preview {
|
||||||
preview.configure(layer, qh);
|
preview.configure(layer, qh);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in new issue
Block a user