Start on wlr-layer-shell

This commit is contained in:
Ottatop 2023-08-04 18:48:10 -05:00 committed by Ottatop
parent a552c3abda
commit a053c55f82
6 changed files with 222 additions and 127 deletions

View file

@ -1,6 +1,22 @@
// SPDX-License-Identifier: GPL-3.0-or-later // SPDX-License-Identifier: GPL-3.0-or-later
use smithay::{output::Output, reexports::wayland_server::protocol::wl_surface::WlSurface}; use std::time::Duration;
use smithay::{
backend::renderer::element::{
default_primary_scanout_output_compare, utils::select_dmabuf_feedback, RenderElementStates,
},
desktop::{
layer_map_for_output,
utils::{surface_primary_scanout_output, update_surface_primary_scanout_output},
Space,
},
output::Output,
reexports::wayland_server::protocol::wl_surface::WlSurface,
wayland::fractional_scale::with_fractional_scale,
};
use crate::{state::SurfaceDmabufFeedback, window::WindowElement};
pub mod udev; pub mod udev;
pub mod winit; pub mod winit;
@ -13,3 +29,84 @@ pub trait Backend: 'static {
// INFO: only for udev in anvil, maybe shouldn't be a trait fn? // INFO: only for udev in anvil, maybe shouldn't be a trait fn?
fn early_import(&mut self, surface: &WlSurface); fn early_import(&mut self, surface: &WlSurface);
} }
pub fn post_repaint(
output: &Output,
render_element_states: &RenderElementStates,
space: &Space<WindowElement>,
dmabuf_feedback: Option<SurfaceDmabufFeedback<'_>>,
time: Duration,
) {
let throttle = Some(Duration::from_secs(1));
space.elements().for_each(|window| {
window.with_surfaces(|surface, states_inner| {
let primary_scanout_output = update_surface_primary_scanout_output(
surface,
output,
states_inner,
render_element_states,
default_primary_scanout_output_compare,
);
if let Some(output) = primary_scanout_output {
with_fractional_scale(states_inner, |fraction_scale| {
fraction_scale.set_preferred_scale(output.current_scale().fractional_scale());
});
}
});
if space.outputs_for_element(window).contains(output) {
window.send_frame(output, time, throttle, surface_primary_scanout_output);
if let Some(dmabuf_feedback) = dmabuf_feedback {
window.send_dmabuf_feedback(
output,
surface_primary_scanout_output,
|surface, _| {
select_dmabuf_feedback(
surface,
render_element_states,
dmabuf_feedback.render_feedback,
dmabuf_feedback.scanout_feedback,
)
},
);
}
}
});
let map = layer_map_for_output(output);
for layer_surface in map.layers() {
layer_surface.with_surfaces(|surface, states| {
let primary_scanout_output = update_surface_primary_scanout_output(
surface,
output,
states,
render_element_states,
default_primary_scanout_output_compare,
);
if let Some(output) = primary_scanout_output {
with_fractional_scale(states, |fraction_scale| {
fraction_scale.set_preferred_scale(output.current_scale().fractional_scale());
});
}
});
layer_surface.send_frame(output, time, throttle, surface_primary_scanout_output);
if let Some(dmabuf_feedback) = dmabuf_feedback {
layer_surface.send_dmabuf_feedback(
output,
surface_primary_scanout_output,
|surface, _| {
select_dmabuf_feedback(
surface,
render_element_states,
dmabuf_feedback.render_feedback,
dmabuf_feedback.scanout_feedback,
)
},
);
}
}
}

View file

@ -32,8 +32,7 @@ use smithay::{
renderer::{ renderer::{
damage::{self, OutputDamageTracker}, damage::{self, OutputDamageTracker},
element::{ element::{
self, texture::TextureBuffer, utils::select_dmabuf_feedback, AsRenderElements, texture::TextureBuffer, AsRenderElements, RenderElement, RenderElementStates,
RenderElement, RenderElementStates,
}, },
gles::{GlesRenderer, GlesTexture}, gles::{GlesRenderer, GlesTexture},
multigpu::{gbm::GbmGlesBackend, GpuManager, MultiRenderer, MultiTexture}, multigpu::{gbm::GbmGlesBackend, GpuManager, MultiRenderer, MultiTexture},
@ -52,10 +51,7 @@ use smithay::{
delegate_dmabuf, delegate_dmabuf,
desktop::{ desktop::{
space::{self, SurfaceTree}, space::{self, SurfaceTree},
utils::{ utils::{send_frames_surface_tree, OutputPresentationFeedback},
self, send_frames_surface_tree, surface_primary_scanout_output,
OutputPresentationFeedback,
},
Space, Space,
}, },
input::pointer::{CursorImageAttributes, CursorImageStatus}, input::pointer::{CursorImageAttributes, CursorImageStatus},
@ -91,7 +87,6 @@ use smithay::{
DmabufFeedback, DmabufFeedbackBuilder, DmabufGlobal, DmabufHandler, DmabufState, DmabufFeedback, DmabufFeedbackBuilder, DmabufGlobal, DmabufHandler, DmabufState,
ImportError, ImportError,
}, },
fractional_scale,
input_method::{InputMethodHandle, InputMethodSeat}, input_method::{InputMethodHandle, InputMethodSeat},
}, },
}; };
@ -1588,8 +1583,6 @@ fn render_surface<'a>(
// post_repaint // post_repaint
{ {
let throttle = Some(Duration::from_secs(1));
let time = clock.now(); let time = clock.now();
// We need to send frames to the cursor surface so that xwayland windows will properly // We need to send frames to the cursor surface so that xwayland windows will properly
@ -1598,56 +1591,19 @@ fn render_surface<'a>(
send_frames_surface_tree(surf, output, time, Some(Duration::ZERO), |_, _| None); send_frames_surface_tree(surf, output, time, Some(Duration::ZERO), |_, _| None);
} }
space.elements().for_each(|window| { super::post_repaint(
window.with_surfaces(|surface, states_inner| { output,
let primary_scanout_output = utils::update_surface_primary_scanout_output( &res.states,
surface, space,
output, surface
states_inner, .dmabuf_feedback
&res.states, .as_ref()
element::default_primary_scanout_output_compare, .map(|feedback| SurfaceDmabufFeedback {
); render_feedback: &feedback.render_feedback,
scanout_feedback: &feedback.scanout_feedback,
if let Some(output) = primary_scanout_output { }),
fractional_scale::with_fractional_scale(states_inner, |fraction_scale| { time.into(),
fraction_scale )
.set_preferred_scale(output.current_scale().fractional_scale());
});
}
});
if space.outputs_for_element(window).contains(output) {
window.send_frame(
output,
time,
throttle,
utils::surface_primary_scanout_output,
);
if let Some(dmabuf_feedback) =
surface
.dmabuf_feedback
.as_ref()
.map(|feedback| SurfaceDmabufFeedback {
render_feedback: &feedback.render_feedback,
scanout_feedback: &feedback.scanout_feedback,
})
{
window.send_dmabuf_feedback(
output,
surface_primary_scanout_output,
|surface, _| {
select_dmabuf_feedback(
surface,
&res.states,
dmabuf_feedback.render_feedback,
dmabuf_feedback.scanout_feedback,
)
},
);
}
}
});
} }
if res.rendered { if res.rendered {

View file

@ -8,23 +8,14 @@ use smithay::{
egl::EGLDevice, egl::EGLDevice,
renderer::{ renderer::{
damage::{self, OutputDamageTracker}, damage::{self, OutputDamageTracker},
element::{ element::{surface::WaylandSurfaceRenderElement, AsRenderElements},
default_primary_scanout_output_compare, surface::WaylandSurfaceRenderElement,
AsRenderElements,
},
gles::{GlesRenderer, GlesTexture}, gles::{GlesRenderer, GlesTexture},
ImportDma, ImportEgl, ImportMemWl, ImportDma, ImportEgl, ImportMemWl,
}, },
winit::{WinitError, WinitEvent, WinitGraphicsBackend}, winit::{WinitError, WinitEvent, WinitGraphicsBackend},
}, },
delegate_dmabuf, delegate_dmabuf,
desktop::{ desktop::{space, utils::send_frames_surface_tree},
space,
utils::{
send_frames_surface_tree, surface_primary_scanout_output,
update_surface_primary_scanout_output,
},
},
input::pointer::{CursorImageAttributes, CursorImageStatus}, input::pointer::{CursorImageAttributes, CursorImageStatus},
output::{Output, Subpixel}, output::{Output, Subpixel},
reexports::{ reexports::{
@ -42,7 +33,6 @@ use smithay::{
DmabufFeedback, DmabufFeedbackBuilder, DmabufGlobal, DmabufHandler, DmabufState, DmabufFeedback, DmabufFeedbackBuilder, DmabufGlobal, DmabufHandler, DmabufState,
ImportError, ImportError,
}, },
fractional_scale::with_fractional_scale,
}, },
}; };
@ -357,11 +347,9 @@ pub fn run_winit() -> Result<(), Box<dyn Error>> {
.window() .window()
.set_cursor_visible(cursor_visible); .set_cursor_visible(cursor_visible);
let throttle = Some(Duration::from_secs(1));
// let throttle = Some(Duration::ZERO);
let time = state.clock.now(); let time = state.clock.now();
// Send frames to the cursor surface so it updates in xwayland
if let CursorImageStatus::Surface(surf) = &state.cursor_status { if let CursorImageStatus::Surface(surf) = &state.cursor_status {
if let Some(op) = state.focus_state.focused_output.as_ref() { if let Some(op) = state.focus_state.focused_output.as_ref() {
send_frames_surface_tree( send_frames_surface_tree(
@ -374,35 +362,13 @@ pub fn run_winit() -> Result<(), Box<dyn Error>> {
} }
} }
state.space.elements().for_each(|window| { super::post_repaint(
window.with_surfaces(|surface, states_inner| { &output,
let primary_scanout_output = update_surface_primary_scanout_output( &render_output_result.states,
surface, &state.space,
&output, None,
states_inner, time.into(),
&render_output_result.states, );
default_primary_scanout_output_compare,
);
if let Some(output) = primary_scanout_output {
with_fractional_scale(states_inner, |fraction_scale| {
fraction_scale.set_preferred_scale(
output.current_scale().fractional_scale(),
);
});
}
});
if state.space.outputs_for_element(window).contains(&output) {
window.send_frame(
&output,
time,
throttle,
surface_primary_scanout_output,
);
// TODO: dmabuf_feedback
}
});
if has_rendered { if has_rendered {
let mut output_presentation_feedback = take_presentation_feedback( let mut output_presentation_feedback = take_presentation_feedback(
@ -432,11 +398,11 @@ pub fn run_winit() -> Result<(), Box<dyn Error>> {
.flush_clients() .flush_clients()
.expect("failed to flush client buffers"); .expect("failed to flush client buffers");
TimeoutAction::ToDuration(Duration::from_millis(6)) TimeoutAction::ToDuration(Duration::from_millis(1))
})?; })?;
event_loop.run( event_loop.run(
Some(Duration::from_millis(6)), Some(Duration::from_millis(1)),
&mut CalloopData { display, state }, &mut CalloopData { display, state },
|_data| { |_data| {
// println!("{}", _data.state.space.elements().count()); // println!("{}", _data.state.space.elements().count());

View file

@ -1,7 +1,7 @@
// SPDX-License-Identifier: GPL-3.0-or-later // SPDX-License-Identifier: GPL-3.0-or-later
use smithay::{ use smithay::{
desktop::PopupKind, desktop::{LayerSurface, PopupKind},
input::{ input::{
keyboard::KeyboardTarget, keyboard::KeyboardTarget,
pointer::{MotionEvent, PointerTarget}, pointer::{MotionEvent, PointerTarget},
@ -49,7 +49,7 @@ impl FocusState {
pub enum FocusTarget { pub enum FocusTarget {
Window(WindowElement), Window(WindowElement),
Popup(PopupKind), Popup(PopupKind),
// TODO: LayerSurface LayerSurface(LayerSurface),
} }
impl IsAlive for FocusTarget { impl IsAlive for FocusTarget {
@ -57,6 +57,7 @@ impl IsAlive for FocusTarget {
match self { match self {
FocusTarget::Window(window) => window.alive(), FocusTarget::Window(window) => window.alive(),
FocusTarget::Popup(popup) => popup.alive(), FocusTarget::Popup(popup) => popup.alive(),
FocusTarget::LayerSurface(surf) => surf.alive(),
} }
} }
} }
@ -77,6 +78,7 @@ impl<B: Backend> PointerTarget<State<B>> for FocusTarget {
FocusTarget::Popup(popup) => { FocusTarget::Popup(popup) => {
PointerTarget::enter(popup.wl_surface(), seat, data, event); PointerTarget::enter(popup.wl_surface(), seat, data, event);
} }
FocusTarget::LayerSurface(surf) => PointerTarget::enter(surf, seat, data, event),
} }
} }
@ -86,6 +88,7 @@ impl<B: Backend> PointerTarget<State<B>> for FocusTarget {
FocusTarget::Popup(popup) => { FocusTarget::Popup(popup) => {
PointerTarget::motion(popup.wl_surface(), seat, data, event); PointerTarget::motion(popup.wl_surface(), seat, data, event);
} }
FocusTarget::LayerSurface(surf) => PointerTarget::motion(surf, seat, data, event),
} }
} }
@ -102,6 +105,9 @@ impl<B: Backend> PointerTarget<State<B>> for FocusTarget {
FocusTarget::Popup(popup) => { FocusTarget::Popup(popup) => {
PointerTarget::relative_motion(popup.wl_surface(), seat, data, event); PointerTarget::relative_motion(popup.wl_surface(), seat, data, event);
} }
FocusTarget::LayerSurface(surf) => {
PointerTarget::relative_motion(surf, seat, data, event);
}
} }
} }
@ -116,6 +122,7 @@ impl<B: Backend> PointerTarget<State<B>> for FocusTarget {
FocusTarget::Popup(popup) => { FocusTarget::Popup(popup) => {
PointerTarget::button(popup.wl_surface(), seat, data, event); PointerTarget::button(popup.wl_surface(), seat, data, event);
} }
FocusTarget::LayerSurface(surf) => PointerTarget::button(surf, seat, data, event),
} }
} }
@ -128,6 +135,7 @@ impl<B: Backend> PointerTarget<State<B>> for FocusTarget {
match self { match self {
FocusTarget::Window(window) => PointerTarget::axis(window, seat, data, frame), FocusTarget::Window(window) => PointerTarget::axis(window, seat, data, frame),
FocusTarget::Popup(popup) => PointerTarget::axis(popup.wl_surface(), seat, data, frame), FocusTarget::Popup(popup) => PointerTarget::axis(popup.wl_surface(), seat, data, frame),
FocusTarget::LayerSurface(surf) => PointerTarget::axis(surf, seat, data, frame),
} }
} }
@ -144,6 +152,7 @@ impl<B: Backend> PointerTarget<State<B>> for FocusTarget {
FocusTarget::Popup(popup) => { FocusTarget::Popup(popup) => {
PointerTarget::leave(popup.wl_surface(), seat, data, serial, time); PointerTarget::leave(popup.wl_surface(), seat, data, serial, time);
} }
FocusTarget::LayerSurface(surf) => PointerTarget::leave(surf, seat, data, serial, time),
} }
} }
} }
@ -161,6 +170,9 @@ impl<B: Backend> KeyboardTarget<State<B>> for FocusTarget {
FocusTarget::Popup(popup) => { FocusTarget::Popup(popup) => {
KeyboardTarget::enter(popup.wl_surface(), seat, data, keys, serial); KeyboardTarget::enter(popup.wl_surface(), seat, data, keys, serial);
} }
FocusTarget::LayerSurface(surf) => {
KeyboardTarget::enter(surf, seat, data, keys, serial);
}
} }
} }
@ -170,6 +182,7 @@ impl<B: Backend> KeyboardTarget<State<B>> for FocusTarget {
FocusTarget::Popup(popup) => { FocusTarget::Popup(popup) => {
KeyboardTarget::leave(popup.wl_surface(), seat, data, serial); KeyboardTarget::leave(popup.wl_surface(), seat, data, serial);
} }
FocusTarget::LayerSurface(surf) => KeyboardTarget::leave(surf, seat, data, serial),
} }
} }
@ -189,6 +202,9 @@ impl<B: Backend> KeyboardTarget<State<B>> for FocusTarget {
FocusTarget::Popup(popup) => { FocusTarget::Popup(popup) => {
KeyboardTarget::key(popup.wl_surface(), seat, data, key, state, serial, time); KeyboardTarget::key(popup.wl_surface(), seat, data, key, state, serial, time);
} }
FocusTarget::LayerSurface(surf) => {
KeyboardTarget::key(surf, seat, data, key, state, serial, time);
}
} }
} }
@ -206,6 +222,9 @@ impl<B: Backend> KeyboardTarget<State<B>> for FocusTarget {
FocusTarget::Popup(popup) => { FocusTarget::Popup(popup) => {
KeyboardTarget::modifiers(popup.wl_surface(), seat, data, modifiers, serial); KeyboardTarget::modifiers(popup.wl_surface(), seat, data, modifiers, serial);
} }
FocusTarget::LayerSurface(surf) => {
KeyboardTarget::modifiers(surf, seat, data, modifiers, serial);
}
} }
} }
} }
@ -215,6 +234,7 @@ impl WaylandFocus for FocusTarget {
match self { match self {
FocusTarget::Window(window) => window.wl_surface(), FocusTarget::Window(window) => window.wl_surface(),
FocusTarget::Popup(popup) => Some(popup.wl_surface().clone()), FocusTarget::Popup(popup) => Some(popup.wl_surface().clone()),
FocusTarget::LayerSurface(surf) => Some(surf.wl_surface().clone()),
} }
} }
@ -226,6 +246,7 @@ impl WaylandFocus for FocusTarget {
FocusTarget::Window(WindowElement::Wayland(window)) => window.same_client_as(object_id), FocusTarget::Window(WindowElement::Wayland(window)) => window.same_client_as(object_id),
FocusTarget::Window(WindowElement::X11(surface)) => surface.same_client_as(object_id), FocusTarget::Window(WindowElement::X11(surface)) => surface.same_client_as(object_id),
FocusTarget::Popup(popup) => popup.wl_surface().id().same_client_as(object_id), FocusTarget::Popup(popup) => popup.wl_surface().id().same_client_as(object_id),
FocusTarget::LayerSurface(surf) => surf.wl_surface().id().same_client_as(object_id),
} }
} }
} }
@ -241,3 +262,9 @@ impl From<PopupKind> for FocusTarget {
FocusTarget::Popup(value) FocusTarget::Popup(value)
} }
} }
impl From<LayerSurface> for FocusTarget {
fn from(value: LayerSurface) -> Self {
FocusTarget::LayerSurface(value)
}
}

View file

@ -6,24 +6,25 @@ use std::time::Duration;
use smithay::{ use smithay::{
backend::renderer::utils, backend::renderer::utils,
delegate_compositor, delegate_data_device, delegate_fractional_scale, delegate_output, delegate_compositor, delegate_data_device, delegate_fractional_scale, delegate_layer_shell,
delegate_presentation, delegate_primary_selection, delegate_relative_pointer, delegate_seat, delegate_output, delegate_presentation, delegate_primary_selection, delegate_relative_pointer,
delegate_shm, delegate_viewporter, delegate_xdg_shell, delegate_seat, delegate_shm, delegate_viewporter, delegate_xdg_shell,
desktop::{ desktop::{
find_popup_root_surface, utils::surface_primary_scanout_output, PopupKeyboardGrab, self, find_popup_root_surface, layer_map_for_output, utils::surface_primary_scanout_output,
PopupKind, PopupPointerGrab, PopupUngrabStrategy, Window, PopupKeyboardGrab, PopupKind, PopupPointerGrab, PopupUngrabStrategy, Window,
}, },
input::{ input::{
pointer::{CursorImageStatus, Focus}, pointer::{CursorImageStatus, Focus},
Seat, SeatHandler, SeatState, Seat, SeatHandler, SeatState,
}, },
output::Output,
reexports::{ reexports::{
calloop::Interest, calloop::Interest,
wayland_protocols::xdg::shell::server::xdg_toplevel::{self, ResizeEdge}, wayland_protocols::xdg::shell::server::xdg_toplevel::{self, ResizeEdge},
wayland_server::{ wayland_server::{
protocol::{ protocol::{
wl_buffer::WlBuffer, wl_data_source::WlDataSource, wl_seat::WlSeat, wl_buffer::WlBuffer, wl_data_source::WlDataSource, wl_output::WlOutput,
wl_surface::WlSurface, wl_seat::WlSeat, wl_surface::WlSurface,
}, },
Client, Resource, Client, Resource,
}, },
@ -45,9 +46,12 @@ use smithay::{
self, set_primary_focus, PrimarySelectionHandler, PrimarySelectionState, self, set_primary_focus, PrimarySelectionHandler, PrimarySelectionState,
}, },
seat::WaylandFocus, seat::WaylandFocus,
shell::xdg::{ shell::{
Configure, PopupSurface, PositionerState, ToplevelSurface, XdgPopupSurfaceData, wlr_layer::{self, Layer, WlrLayerShellHandler, WlrLayerShellState},
XdgShellHandler, XdgShellState, XdgToplevelSurfaceData, xdg::{
Configure, PopupSurface, PositionerState, ToplevelSurface, XdgPopupSurfaceData,
XdgShellHandler, XdgShellState, XdgToplevelSurfaceData,
},
}, },
shm::{ShmHandler, ShmState}, shm::{ShmHandler, ShmState},
}, },
@ -640,18 +644,16 @@ impl<B: Backend> FractionalScaleHandler for State<B> {
compositor::with_states(&surface, |states| { compositor::with_states(&surface, |states| {
let primary_scanout_output = let primary_scanout_output =
smithay::desktop::utils::surface_primary_scanout_output(&surface, states) desktop::utils::surface_primary_scanout_output(&surface, states)
.or_else(|| { .or_else(|| {
if root != surface { if root != surface {
compositor::with_states(&root, |states| { compositor::with_states(&root, |states| {
smithay::desktop::utils::surface_primary_scanout_output( desktop::utils::surface_primary_scanout_output(&root, states)
&root, states, .or_else(|| {
) self.window_for_surface(&root).and_then(|window| {
.or_else(|| { self.space.outputs_for_element(&window).first().cloned()
self.window_for_surface(&root).and_then(|window| { })
self.space.outputs_for_element(&window).first().cloned()
}) })
})
}) })
} else { } else {
self.window_for_surface(&root).and_then(|window| { self.window_for_surface(&root).and_then(|window| {
@ -674,3 +676,45 @@ delegate_fractional_scale!(@<B: Backend> State<B>);
delegate_relative_pointer!(@<B: Backend> State<B>); delegate_relative_pointer!(@<B: Backend> State<B>);
delegate_presentation!(@<B: Backend> State<B>); delegate_presentation!(@<B: Backend> State<B>);
impl<B: Backend> WlrLayerShellHandler for State<B> {
fn shell_state(&mut self) -> &mut WlrLayerShellState {
&mut self.layer_shell_state
}
fn new_layer_surface(
&mut self,
surface: wlr_layer::LayerSurface,
output: Option<WlOutput>,
_layer: Layer,
namespace: String,
) {
let output = output
.as_ref()
.and_then(Output::from_resource)
.or_else(|| self.space.outputs().next().cloned());
let Some(output) = output else {
tracing::error!("New layer surface, but there was no output to map it on");
return;
};
let mut map = layer_map_for_output(&output);
map.map_layer(&desktop::LayerSurface::new(surface, namespace))
.expect("failed to map layer surface");
}
fn layer_destroyed(&mut self, surface: wlr_layer::LayerSurface) {
if let Some((mut map, layer)) = self.space.outputs().find_map(|o| {
let map = layer_map_for_output(o);
let layer = map
.layers()
.find(|&layer| layer.layer_surface() == &surface)
.cloned();
layer.map(|layer| (map, layer))
}) {
map.unmap_layer(&layer);
}
}
}
delegate_layer_shell!(@<B: Backend> State<B>);

View file

@ -58,7 +58,10 @@ use smithay::{
fractional_scale::FractionalScaleManagerState, fractional_scale::FractionalScaleManagerState,
output::OutputManagerState, output::OutputManagerState,
primary_selection::PrimarySelectionState, primary_selection::PrimarySelectionState,
shell::xdg::{XdgShellState, XdgToplevelSurfaceData}, shell::{
wlr_layer::WlrLayerShellState,
xdg::{XdgShellState, XdgToplevelSurfaceData},
},
shm::ShmState, shm::ShmState,
socket::ListeningSocketSource, socket::ListeningSocketSource,
viewporter::ViewporterState, viewporter::ViewporterState,
@ -92,6 +95,7 @@ pub struct State<B: Backend> {
pub viewporter_state: ViewporterState, pub viewporter_state: ViewporterState,
pub fractional_scale_manager_state: FractionalScaleManagerState, pub fractional_scale_manager_state: FractionalScaleManagerState,
pub primary_selection_state: PrimarySelectionState, pub primary_selection_state: PrimarySelectionState,
pub layer_shell_state: WlrLayerShellState,
pub input_state: InputState, pub input_state: InputState,
pub api_state: ApiState, pub api_state: ApiState,
@ -960,6 +964,7 @@ impl<B: Backend> State<B> {
&display_handle, &display_handle,
), ),
primary_selection_state: PrimarySelectionState::new::<Self>(&display_handle), primary_selection_state: PrimarySelectionState::new::<Self>(&display_handle),
layer_shell_state: WlrLayerShellState::new::<Self>(&display_handle),
input_state: InputState::new(), input_state: InputState::new(),
api_state: ApiState::new(), api_state: ApiState::new(),