mirror of
https://github.com/pinnacle-comp/pinnacle.git
synced 2025-02-11 08:48:22 +01:00
Implement session lock
This commit is contained in:
parent
42f3e65255
commit
d708fccf58
11 changed files with 335 additions and 50 deletions
|
@ -33,7 +33,7 @@ use smithay::{
|
||||||
use tracing::error;
|
use tracing::error;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
state::{Pinnacle, State, SurfaceDmabufFeedback},
|
state::{Pinnacle, State, SurfaceDmabufFeedback, WithState},
|
||||||
window::WindowElement,
|
window::WindowElement,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -248,6 +248,16 @@ pub fn post_repaint(
|
||||||
if let CursorImageStatus::Surface(surf) = cursor_status {
|
if let CursorImageStatus::Surface(surf) = cursor_status {
|
||||||
send_frames_surface_tree(surf, output, time, Some(Duration::ZERO), |_, _| None);
|
send_frames_surface_tree(surf, output, time, Some(Duration::ZERO), |_, _| None);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if let Some(lock_surface) = output.with_state(|state| state.lock_surface.clone()) {
|
||||||
|
send_frames_surface_tree(
|
||||||
|
lock_surface.wl_surface(),
|
||||||
|
output,
|
||||||
|
time,
|
||||||
|
Some(Duration::ZERO),
|
||||||
|
|_, _| None,
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl DmabufHandler for State {
|
impl DmabufHandler for State {
|
||||||
|
|
|
@ -32,7 +32,10 @@ use smithay::{
|
||||||
renderer::{
|
renderer::{
|
||||||
self, damage,
|
self, damage,
|
||||||
element::{
|
element::{
|
||||||
self, surface::WaylandSurfaceRenderElement, texture::TextureBuffer, Element,
|
self,
|
||||||
|
surface::{render_elements_from_surface_tree, WaylandSurfaceRenderElement},
|
||||||
|
texture::TextureBuffer,
|
||||||
|
Element,
|
||||||
},
|
},
|
||||||
gles::{GlesRenderbuffer, GlesRenderer},
|
gles::{GlesRenderbuffer, GlesRenderer},
|
||||||
multigpu::{gbm::GbmGlesBackend, GpuManager, MultiRenderer, MultiTexture},
|
multigpu::{gbm::GbmGlesBackend, GpuManager, MultiRenderer, MultiTexture},
|
||||||
|
@ -88,7 +91,7 @@ use tracing::{debug, error, info, trace, warn};
|
||||||
use crate::{
|
use crate::{
|
||||||
backend::Backend,
|
backend::Backend,
|
||||||
config::ConnectorSavedState,
|
config::ConnectorSavedState,
|
||||||
output::OutputName,
|
output::{BlankingState, OutputName},
|
||||||
render::{
|
render::{
|
||||||
pointer::PointerElement, pointer_render_elements, take_presentation_feedback,
|
pointer::PointerElement, pointer_render_elements, take_presentation_feedback,
|
||||||
OutputRenderElement,
|
OutputRenderElement,
|
||||||
|
@ -1312,6 +1315,13 @@ impl Udev {
|
||||||
flags,
|
flags,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
output.with_state_mut(|state| {
|
||||||
|
if let BlankingState::Blanking = state.blanking_state {
|
||||||
|
debug!("Output {} blanked", output.name());
|
||||||
|
state.blanking_state = BlankingState::Blanked;
|
||||||
|
}
|
||||||
|
})
|
||||||
}
|
}
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
warn!("Error during rendering: {:?}", err);
|
warn!("Error during rendering: {:?}", err);
|
||||||
|
@ -1399,8 +1409,6 @@ impl Udev {
|
||||||
texture
|
texture
|
||||||
});
|
});
|
||||||
|
|
||||||
let windows = pinnacle.space.elements().cloned().collect::<Vec<_>>();
|
|
||||||
|
|
||||||
let pointer_location = pinnacle
|
let pointer_location = pinnacle
|
||||||
.seat
|
.seat
|
||||||
.get_pointer()
|
.get_pointer()
|
||||||
|
@ -1434,10 +1442,14 @@ impl Udev {
|
||||||
|
|
||||||
let mut output_render_elements = Vec::new();
|
let mut output_render_elements = Vec::new();
|
||||||
|
|
||||||
|
let should_blank = pinnacle.lock_state.is_locking()
|
||||||
|
|| (pinnacle.lock_state.is_locked()
|
||||||
|
&& output.with_state(|state| state.lock_surface.is_none()));
|
||||||
|
|
||||||
// If there isn't a pending screencopy that doesn't want to overlay the cursor,
|
// If there isn't a pending screencopy that doesn't want to overlay the cursor,
|
||||||
// render it.
|
// render it.
|
||||||
match pending_screencopy_with_cursor {
|
match pending_screencopy_with_cursor {
|
||||||
Some(include_cursor) => {
|
Some(include_cursor) if !should_blank => {
|
||||||
if include_cursor {
|
if include_cursor {
|
||||||
// HACK: Doing `RenderFrameResult::blit_frame_result` with something on the
|
// HACK: Doing `RenderFrameResult::blit_frame_result` with something on the
|
||||||
// | cursor plane causes the cursor to overwrite the pixels underneath it,
|
// | cursor plane causes the cursor to overwrite the pixels underneath it,
|
||||||
|
@ -1461,7 +1473,7 @@ impl Udev {
|
||||||
output_render_elements.extend(pointer_render_elements);
|
output_render_elements.extend(pointer_render_elements);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
None => {
|
_ => {
|
||||||
let pointer_render_elements = pointer_render_elements(
|
let pointer_render_elements = pointer_render_elements(
|
||||||
output,
|
output,
|
||||||
&mut renderer,
|
&mut renderer,
|
||||||
|
@ -1475,12 +1487,35 @@ impl Udev {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if should_blank {
|
||||||
|
// Don't push any render elements and we get a blank frame
|
||||||
|
output.with_state_mut(|state| {
|
||||||
|
if let BlankingState::NotBlanked = state.blanking_state {
|
||||||
|
debug!("Blanking output {} for session lock", output.name());
|
||||||
|
state.blanking_state = BlankingState::Blanking;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} else if let Some(lock_surface) = output.with_state(|state| state.lock_surface.clone()) {
|
||||||
|
let elems = render_elements_from_surface_tree(
|
||||||
|
&mut renderer,
|
||||||
|
lock_surface.wl_surface(),
|
||||||
|
(0, 0),
|
||||||
|
output.current_scale().fractional_scale(),
|
||||||
|
1.0,
|
||||||
|
element::Kind::Unspecified,
|
||||||
|
);
|
||||||
|
|
||||||
|
output_render_elements.extend(elems);
|
||||||
|
} else {
|
||||||
|
let windows = pinnacle.space.elements().cloned().collect::<Vec<_>>();
|
||||||
|
|
||||||
output_render_elements.extend(crate::render::output_render_elements(
|
output_render_elements.extend(crate::render::output_render_elements(
|
||||||
output,
|
output,
|
||||||
&mut renderer,
|
&mut renderer,
|
||||||
&pinnacle.space,
|
&pinnacle.space,
|
||||||
&windows,
|
&windows,
|
||||||
));
|
));
|
||||||
|
}
|
||||||
|
|
||||||
let result = (|| -> Result<bool, SwapBuffersError> {
|
let result = (|| -> Result<bool, SwapBuffersError> {
|
||||||
let render_frame_result = render_frame(
|
let render_frame_result = render_frame(
|
||||||
|
@ -1496,6 +1531,7 @@ impl Udev {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if pinnacle.lock_state.is_unlocked() {
|
||||||
handle_pending_screencopy(
|
handle_pending_screencopy(
|
||||||
&mut renderer,
|
&mut renderer,
|
||||||
output,
|
output,
|
||||||
|
@ -1503,6 +1539,7 @@ impl Udev {
|
||||||
&render_frame_result,
|
&render_frame_result,
|
||||||
&pinnacle.loop_handle,
|
&pinnacle.loop_handle,
|
||||||
);
|
);
|
||||||
|
}
|
||||||
|
|
||||||
super::post_repaint(
|
super::post_repaint(
|
||||||
output,
|
output,
|
||||||
|
|
|
@ -9,6 +9,7 @@ use smithay::{
|
||||||
renderer::{
|
renderer::{
|
||||||
self, buffer_type,
|
self, buffer_type,
|
||||||
damage::{self, OutputDamageTracker, RenderOutputResult},
|
damage::{self, OutputDamageTracker, RenderOutputResult},
|
||||||
|
element::{self, surface::render_elements_from_surface_tree},
|
||||||
gles::{GlesRenderbuffer, GlesRenderer, GlesTexture},
|
gles::{GlesRenderbuffer, GlesRenderer, GlesTexture},
|
||||||
Bind, Blit, BufferType, ExportMem, ImportDma, ImportEgl, ImportMemWl, Offscreen,
|
Bind, Blit, BufferType, ExportMem, ImportDma, ImportEgl, ImportMemWl, Offscreen,
|
||||||
TextureFilter,
|
TextureFilter,
|
||||||
|
@ -37,9 +38,10 @@ use smithay::{
|
||||||
utils::{IsAlive, Point, Rectangle, Transform},
|
utils::{IsAlive, Point, Rectangle, Transform},
|
||||||
wayland::dmabuf::{self, DmabufFeedback, DmabufFeedbackBuilder, DmabufGlobal, DmabufState},
|
wayland::dmabuf::{self, DmabufFeedback, DmabufFeedbackBuilder, DmabufGlobal, DmabufState},
|
||||||
};
|
};
|
||||||
use tracing::{error, trace, warn};
|
use tracing::{debug, error, trace, warn};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
|
output::BlankingState,
|
||||||
render::{pointer::PointerElement, pointer_render_elements, take_presentation_feedback},
|
render::{pointer::PointerElement, pointer_render_elements, take_presentation_feedback},
|
||||||
state::{Pinnacle, State, WithState},
|
state::{Pinnacle, State, WithState},
|
||||||
};
|
};
|
||||||
|
@ -266,19 +268,20 @@ impl State {
|
||||||
|
|
||||||
let mut output_render_elements = Vec::new();
|
let mut output_render_elements = Vec::new();
|
||||||
|
|
||||||
let pending_screencopy_without_cursor = output.with_state(|state| {
|
let should_blank = self.pinnacle.lock_state.is_locking()
|
||||||
state
|
|| (self.pinnacle.lock_state.is_locked()
|
||||||
|
&& output.with_state(|state| state.lock_surface.is_none()));
|
||||||
|
|
||||||
|
let should_draw_cursor = !should_blank
|
||||||
|
|| output.with_state(|state| {
|
||||||
|
// Don't draw cursor when screencopy without cursor is pending
|
||||||
|
!state
|
||||||
.screencopy
|
.screencopy
|
||||||
.as_ref()
|
.as_ref()
|
||||||
.is_some_and(|sc| !sc.overlay_cursor())
|
.is_some_and(|sc| !sc.overlay_cursor())
|
||||||
});
|
});
|
||||||
|
|
||||||
// If there isn't a pending screencopy that doesn't want to overlay the cursor,
|
if should_draw_cursor {
|
||||||
// render it.
|
|
||||||
//
|
|
||||||
// This will cause the cursor to disappear for a frame if there is one though,
|
|
||||||
// but it shouldn't meaningfully affect anything.
|
|
||||||
if !pending_screencopy_without_cursor {
|
|
||||||
let pointer_location = self
|
let pointer_location = self
|
||||||
.pinnacle
|
.pinnacle
|
||||||
.seat
|
.seat
|
||||||
|
@ -298,12 +301,33 @@ impl State {
|
||||||
output_render_elements.extend(pointer_render_elements);
|
output_render_elements.extend(pointer_render_elements);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if should_blank {
|
||||||
|
// Don't push any render elements and we get a blank frame
|
||||||
|
output.with_state_mut(|state| {
|
||||||
|
if let BlankingState::NotBlanked = state.blanking_state {
|
||||||
|
debug!("Blanking output {} for session lock", output.name());
|
||||||
|
state.blanking_state = BlankingState::Blanking;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} else if let Some(lock_surface) = output.with_state(|state| state.lock_surface.clone()) {
|
||||||
|
let elems = render_elements_from_surface_tree(
|
||||||
|
winit.backend.renderer(),
|
||||||
|
lock_surface.wl_surface(),
|
||||||
|
(0, 0),
|
||||||
|
output.current_scale().fractional_scale(),
|
||||||
|
1.0,
|
||||||
|
element::Kind::Unspecified,
|
||||||
|
);
|
||||||
|
|
||||||
|
output_render_elements.extend(elems);
|
||||||
|
} else {
|
||||||
output_render_elements.extend(crate::render::output_render_elements(
|
output_render_elements.extend(crate::render::output_render_elements(
|
||||||
output,
|
output,
|
||||||
winit.backend.renderer(),
|
winit.backend.renderer(),
|
||||||
&self.pinnacle.space,
|
&self.pinnacle.space,
|
||||||
&windows,
|
&windows,
|
||||||
));
|
));
|
||||||
|
}
|
||||||
|
|
||||||
let render_res = winit.backend.bind().and_then(|_| {
|
let render_res = winit.backend.bind().and_then(|_| {
|
||||||
let age = if *full_redraw > 0 {
|
let age = if *full_redraw > 0 {
|
||||||
|
@ -325,19 +349,32 @@ impl State {
|
||||||
|
|
||||||
match render_res {
|
match render_res {
|
||||||
Ok(render_output_result) => {
|
Ok(render_output_result) => {
|
||||||
|
if self.pinnacle.lock_state.is_unlocked() {
|
||||||
Winit::handle_pending_screencopy(
|
Winit::handle_pending_screencopy(
|
||||||
&mut winit.backend,
|
&mut winit.backend,
|
||||||
output,
|
output,
|
||||||
&render_output_result,
|
&render_output_result,
|
||||||
&self.pinnacle.loop_handle,
|
&self.pinnacle.loop_handle,
|
||||||
);
|
);
|
||||||
|
}
|
||||||
|
|
||||||
let has_rendered = render_output_result.damage.is_some();
|
let has_rendered = render_output_result.damage.is_some();
|
||||||
if let Some(damage) = render_output_result.damage {
|
if let Some(damage) = render_output_result.damage {
|
||||||
if let Err(err) = winit.backend.submit(Some(damage)) {
|
match winit.backend.submit(Some(damage)) {
|
||||||
|
Ok(()) => {
|
||||||
|
output.with_state_mut(|state| {
|
||||||
|
if matches!(state.blanking_state, BlankingState::Blanking) {
|
||||||
|
// TODO: this is probably wrong
|
||||||
|
debug!("Output {} blanked", output.name());
|
||||||
|
state.blanking_state = BlankingState::Blanked;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
Err(err) => {
|
||||||
error!("Failed to submit buffer: {}", err);
|
error!("Failed to submit buffer: {}", err);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
winit.backend.window().set_cursor_visible(cursor_visible);
|
winit.backend.window().set_cursor_visible(cursor_visible);
|
||||||
|
|
||||||
|
|
|
@ -7,7 +7,7 @@ use smithay::{
|
||||||
},
|
},
|
||||||
reexports::wayland_server::{protocol::wl_surface::WlSurface, Resource},
|
reexports::wayland_server::{protocol::wl_surface::WlSurface, Resource},
|
||||||
utils::{IsAlive, Serial},
|
utils::{IsAlive, Serial},
|
||||||
wayland::seat::WaylandFocus,
|
wayland::{seat::WaylandFocus, session_lock::LockSurface},
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::{state::State, window::WindowElement};
|
use crate::{state::State, window::WindowElement};
|
||||||
|
@ -18,6 +18,7 @@ pub enum KeyboardFocusTarget {
|
||||||
Window(WindowElement),
|
Window(WindowElement),
|
||||||
Popup(PopupKind),
|
Popup(PopupKind),
|
||||||
LayerSurface(LayerSurface),
|
LayerSurface(LayerSurface),
|
||||||
|
LockSurface(LockSurface),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl KeyboardTarget<State> for KeyboardFocusTarget {
|
impl KeyboardTarget<State> for KeyboardFocusTarget {
|
||||||
|
@ -38,6 +39,9 @@ impl KeyboardTarget<State> for KeyboardFocusTarget {
|
||||||
KeyboardFocusTarget::LayerSurface(surf) => {
|
KeyboardFocusTarget::LayerSurface(surf) => {
|
||||||
KeyboardTarget::enter(surf.wl_surface(), seat, data, keys, serial);
|
KeyboardTarget::enter(surf.wl_surface(), seat, data, keys, serial);
|
||||||
}
|
}
|
||||||
|
KeyboardFocusTarget::LockSurface(lock) => {
|
||||||
|
KeyboardTarget::enter(lock.wl_surface(), seat, data, keys, serial);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -52,6 +56,9 @@ impl KeyboardTarget<State> for KeyboardFocusTarget {
|
||||||
KeyboardFocusTarget::LayerSurface(surf) => {
|
KeyboardFocusTarget::LayerSurface(surf) => {
|
||||||
KeyboardTarget::leave(surf.wl_surface(), seat, data, serial)
|
KeyboardTarget::leave(surf.wl_surface(), seat, data, serial)
|
||||||
}
|
}
|
||||||
|
KeyboardFocusTarget::LockSurface(lock) => {
|
||||||
|
KeyboardTarget::leave(lock.wl_surface(), seat, data, serial);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -60,7 +67,7 @@ impl KeyboardTarget<State> for KeyboardFocusTarget {
|
||||||
seat: &Seat<State>,
|
seat: &Seat<State>,
|
||||||
data: &mut State,
|
data: &mut State,
|
||||||
key: KeysymHandle<'_>,
|
key: KeysymHandle<'_>,
|
||||||
state: smithay::backend::input::KeyState,
|
state: KeyState,
|
||||||
serial: Serial,
|
serial: Serial,
|
||||||
time: u32,
|
time: u32,
|
||||||
) {
|
) {
|
||||||
|
@ -74,6 +81,9 @@ impl KeyboardTarget<State> for KeyboardFocusTarget {
|
||||||
KeyboardFocusTarget::LayerSurface(surf) => {
|
KeyboardFocusTarget::LayerSurface(surf) => {
|
||||||
KeyboardTarget::key(surf.wl_surface(), seat, data, key, state, serial, time);
|
KeyboardTarget::key(surf.wl_surface(), seat, data, key, state, serial, time);
|
||||||
}
|
}
|
||||||
|
KeyboardFocusTarget::LockSurface(lock) => {
|
||||||
|
KeyboardTarget::key(lock.wl_surface(), seat, data, key, state, serial, time);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -81,7 +91,7 @@ impl KeyboardTarget<State> for KeyboardFocusTarget {
|
||||||
&self,
|
&self,
|
||||||
seat: &Seat<State>,
|
seat: &Seat<State>,
|
||||||
data: &mut State,
|
data: &mut State,
|
||||||
modifiers: smithay::input::keyboard::ModifiersState,
|
modifiers: ModifiersState,
|
||||||
serial: Serial,
|
serial: Serial,
|
||||||
) {
|
) {
|
||||||
match self {
|
match self {
|
||||||
|
@ -94,6 +104,9 @@ impl KeyboardTarget<State> for KeyboardFocusTarget {
|
||||||
KeyboardFocusTarget::LayerSurface(surf) => {
|
KeyboardFocusTarget::LayerSurface(surf) => {
|
||||||
KeyboardTarget::modifiers(surf.wl_surface(), seat, data, modifiers, serial);
|
KeyboardTarget::modifiers(surf.wl_surface(), seat, data, modifiers, serial);
|
||||||
}
|
}
|
||||||
|
KeyboardFocusTarget::LockSurface(lock) => {
|
||||||
|
KeyboardTarget::modifiers(lock.wl_surface(), seat, data, modifiers, serial);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -104,6 +117,7 @@ impl IsAlive for KeyboardFocusTarget {
|
||||||
KeyboardFocusTarget::Window(window) => window.alive(),
|
KeyboardFocusTarget::Window(window) => window.alive(),
|
||||||
KeyboardFocusTarget::Popup(popup) => popup.alive(),
|
KeyboardFocusTarget::Popup(popup) => popup.alive(),
|
||||||
KeyboardFocusTarget::LayerSurface(surf) => surf.alive(),
|
KeyboardFocusTarget::LayerSurface(surf) => surf.alive(),
|
||||||
|
KeyboardFocusTarget::LockSurface(lock) => lock.alive(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -114,6 +128,7 @@ impl WaylandFocus for KeyboardFocusTarget {
|
||||||
KeyboardFocusTarget::Window(window) => window.wl_surface(),
|
KeyboardFocusTarget::Window(window) => window.wl_surface(),
|
||||||
KeyboardFocusTarget::Popup(popup) => Some(popup.wl_surface().clone()),
|
KeyboardFocusTarget::Popup(popup) => Some(popup.wl_surface().clone()),
|
||||||
KeyboardFocusTarget::LayerSurface(surf) => Some(surf.wl_surface().clone()),
|
KeyboardFocusTarget::LayerSurface(surf) => Some(surf.wl_surface().clone()),
|
||||||
|
KeyboardFocusTarget::LockSurface(lock) => Some(lock.wl_surface().clone()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -127,6 +142,9 @@ impl WaylandFocus for KeyboardFocusTarget {
|
||||||
KeyboardFocusTarget::LayerSurface(surf) => {
|
KeyboardFocusTarget::LayerSurface(surf) => {
|
||||||
surf.wl_surface().id().same_client_as(object_id)
|
surf.wl_surface().id().same_client_as(object_id)
|
||||||
}
|
}
|
||||||
|
KeyboardFocusTarget::LockSurface(lock) => {
|
||||||
|
lock.wl_surface().id().same_client_as(object_id)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -414,6 +414,9 @@ impl From<KeyboardFocusTarget> for PointerFocusTarget {
|
||||||
KeyboardFocusTarget::LayerSurface(layer) => {
|
KeyboardFocusTarget::LayerSurface(layer) => {
|
||||||
PointerFocusTarget::WlSurface(layer.wl_surface().clone())
|
PointerFocusTarget::WlSurface(layer.wl_surface().clone())
|
||||||
}
|
}
|
||||||
|
KeyboardFocusTarget::LockSurface(lock) => {
|
||||||
|
PointerFocusTarget::WlSurface(lock.wl_surface().clone())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
|
pub mod session_lock;
|
||||||
mod xdg_shell;
|
mod xdg_shell;
|
||||||
mod xwayland;
|
mod xwayland;
|
||||||
|
|
||||||
|
@ -260,6 +261,21 @@ impl CompositorHandler for State {
|
||||||
.cloned()
|
.cloned()
|
||||||
{
|
{
|
||||||
vec![output] // surface is a layer surface
|
vec![output] // surface is a layer surface
|
||||||
|
} else if let Some(output) = self
|
||||||
|
.pinnacle
|
||||||
|
.space
|
||||||
|
.outputs()
|
||||||
|
.find(|op| {
|
||||||
|
op.with_state(|state| {
|
||||||
|
state
|
||||||
|
.lock_surface
|
||||||
|
.as_ref()
|
||||||
|
.is_some_and(|lock| lock.wl_surface() == surface)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
.cloned()
|
||||||
|
{
|
||||||
|
vec![output]
|
||||||
} else {
|
} else {
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
|
|
129
src/handlers/session_lock.rs
Normal file
129
src/handlers/session_lock.rs
Normal file
|
@ -0,0 +1,129 @@
|
||||||
|
use smithay::{
|
||||||
|
delegate_session_lock,
|
||||||
|
output::Output,
|
||||||
|
reexports::wayland_server::protocol::wl_output::WlOutput,
|
||||||
|
utils::SERIAL_COUNTER,
|
||||||
|
wayland::session_lock::{
|
||||||
|
LockSurface, SessionLockHandler, SessionLockManagerState, SessionLocker,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
use tracing::{debug, warn};
|
||||||
|
|
||||||
|
use crate::{
|
||||||
|
focus::keyboard::KeyboardFocusTarget,
|
||||||
|
output::BlankingState,
|
||||||
|
state::{State, WithState},
|
||||||
|
};
|
||||||
|
|
||||||
|
/// State of a session lock.
|
||||||
|
#[derive(Default, Debug)]
|
||||||
|
pub enum LockState {
|
||||||
|
/// There is no session lock.
|
||||||
|
#[default]
|
||||||
|
Unlocked,
|
||||||
|
/// A session lock request came in and we are in the process of blanking outputs.
|
||||||
|
Locking(SessionLocker),
|
||||||
|
/// The session is locked.
|
||||||
|
Locked,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl LockState {
|
||||||
|
/// Returns `true` if the lock state is [`Locking`].
|
||||||
|
///
|
||||||
|
/// [`Locking`]: LockState::Locking
|
||||||
|
#[must_use]
|
||||||
|
pub fn is_locking(&self) -> bool {
|
||||||
|
matches!(self, Self::Locking(..))
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns `true` if the lock state is [`Unlocked`].
|
||||||
|
///
|
||||||
|
/// [`Unlocked`]: LockState::Unlocked
|
||||||
|
#[must_use]
|
||||||
|
pub fn is_unlocked(&self) -> bool {
|
||||||
|
matches!(self, Self::Unlocked)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns `true` if the lock state is [`Locked`].
|
||||||
|
///
|
||||||
|
/// [`Locked`]: LockState::Locked
|
||||||
|
#[must_use]
|
||||||
|
pub fn is_locked(&self) -> bool {
|
||||||
|
matches!(self, Self::Locked)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl SessionLockHandler for State {
|
||||||
|
fn lock_state(&mut self) -> &mut SessionLockManagerState {
|
||||||
|
&mut self.pinnacle.session_lock_manager_state
|
||||||
|
}
|
||||||
|
|
||||||
|
fn lock(&mut self, confirmation: SessionLocker) {
|
||||||
|
debug!("Received session lock request");
|
||||||
|
self.pinnacle.lock_state = LockState::Locking(confirmation);
|
||||||
|
self.pinnacle.schedule(
|
||||||
|
|state| {
|
||||||
|
let all_outputs_blanked = state.pinnacle.space.outputs().all(|op| {
|
||||||
|
op.with_state(|st| matches!(st.blanking_state, BlankingState::Blanked))
|
||||||
|
});
|
||||||
|
!state.pinnacle.lock_state.is_locking() || all_outputs_blanked
|
||||||
|
},
|
||||||
|
|state| match std::mem::take(&mut state.pinnacle.lock_state) {
|
||||||
|
LockState::Unlocked => (),
|
||||||
|
LockState::Locking(locker) => {
|
||||||
|
debug!("Locking session");
|
||||||
|
locker.lock();
|
||||||
|
state.pinnacle.lock_state = LockState::Locked;
|
||||||
|
for output in state.pinnacle.space.outputs().cloned().collect::<Vec<_>>() {
|
||||||
|
state.schedule_render(&output);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
LockState::Locked => state.pinnacle.lock_state = LockState::Locked,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn unlock(&mut self) {
|
||||||
|
debug!("Session lock unlocked");
|
||||||
|
for output in self.pinnacle.space.outputs() {
|
||||||
|
output.with_state_mut(|state| {
|
||||||
|
state.lock_surface.take();
|
||||||
|
state.blanking_state = BlankingState::NotBlanked;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
self.pinnacle.lock_state = LockState::Unlocked;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn new_surface(&mut self, surface: LockSurface, output: WlOutput) {
|
||||||
|
let Some(output) = Output::from_resource(&output) else {
|
||||||
|
warn!(
|
||||||
|
"Session lock surface received but output doesn't exist for wl_output {output:?}"
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
|
||||||
|
debug!("Session lock surface received for output {}", output.name());
|
||||||
|
|
||||||
|
let Some(geo) = self.pinnacle.space.output_geometry(&output) else {
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
|
||||||
|
surface.with_pending_state(|state| {
|
||||||
|
state.size = Some((geo.size.w as u32, geo.size.h as u32).into())
|
||||||
|
});
|
||||||
|
surface.send_configure();
|
||||||
|
|
||||||
|
if let Some(keyboard) = self.pinnacle.seat.get_keyboard() {
|
||||||
|
keyboard.set_focus(
|
||||||
|
self,
|
||||||
|
Some(KeyboardFocusTarget::LockSurface(surface.clone())),
|
||||||
|
SERIAL_COUNTER.next_serial(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
output.with_state_mut(|state| state.lock_surface.replace(surface));
|
||||||
|
|
||||||
|
self.schedule_render(&output);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
delegate_session_lock!(State);
|
|
@ -185,6 +185,13 @@ impl Pinnacle {
|
||||||
.output_geometry(output)
|
.output_geometry(output)
|
||||||
.expect("called output_geometry on unmapped output");
|
.expect("called output_geometry on unmapped output");
|
||||||
|
|
||||||
|
if let Some(lock_surface) = output.with_state(|state| state.lock_surface.clone()) {
|
||||||
|
return Some((
|
||||||
|
PointerFocusTarget::WlSurface(lock_surface.wl_surface().clone()),
|
||||||
|
output_geo.loc,
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
let mut fullscreen_and_up_split_at = 0;
|
let mut fullscreen_and_up_split_at = 0;
|
||||||
|
|
||||||
for (i, win) in self
|
for (i, win) in self
|
||||||
|
|
|
@ -7,6 +7,7 @@ use smithay::{
|
||||||
desktop::layer_map_for_output,
|
desktop::layer_map_for_output,
|
||||||
output::{Mode, Output, Scale},
|
output::{Mode, Output, Scale},
|
||||||
utils::{Logical, Point, Transform},
|
utils::{Logical, Point, Transform},
|
||||||
|
wayland::session_lock::LockSurface,
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
|
@ -34,6 +35,18 @@ impl OutputName {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// State of an output's blanking status for session lock.
|
||||||
|
#[derive(Debug, Default, Copy, Clone)]
|
||||||
|
pub enum BlankingState {
|
||||||
|
/// The output is not blanked and is displaying normal content.
|
||||||
|
#[default]
|
||||||
|
NotBlanked,
|
||||||
|
/// A blank frame has been queued up.
|
||||||
|
Blanking,
|
||||||
|
/// A blank frame has been displayed.
|
||||||
|
Blanked,
|
||||||
|
}
|
||||||
|
|
||||||
/// The state of an output
|
/// The state of an output
|
||||||
#[derive(Default, Debug)]
|
#[derive(Default, Debug)]
|
||||||
pub struct OutputState {
|
pub struct OutputState {
|
||||||
|
@ -42,6 +55,8 @@ pub struct OutputState {
|
||||||
pub screencopy: Option<Screencopy>,
|
pub screencopy: Option<Screencopy>,
|
||||||
pub serial: Option<NonZeroU32>,
|
pub serial: Option<NonZeroU32>,
|
||||||
pub modes: Vec<Mode>,
|
pub modes: Vec<Mode>,
|
||||||
|
pub lock_surface: Option<LockSurface>,
|
||||||
|
pub blanking_state: BlankingState,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl WithState for Output {
|
impl WithState for Output {
|
||||||
|
|
|
@ -5,6 +5,7 @@ use std::{ops::Deref, sync::Mutex};
|
||||||
use smithay::{
|
use smithay::{
|
||||||
backend::renderer::{
|
backend::renderer::{
|
||||||
element::{
|
element::{
|
||||||
|
solid::SolidColorRenderElement,
|
||||||
surface::WaylandSurfaceRenderElement,
|
surface::WaylandSurfaceRenderElement,
|
||||||
utils::{CropRenderElement, RelocateRenderElement, RescaleRenderElement},
|
utils::{CropRenderElement, RelocateRenderElement, RescaleRenderElement},
|
||||||
AsRenderElements, RenderElementStates, Wrap,
|
AsRenderElements, RenderElementStates, Wrap,
|
||||||
|
@ -51,6 +52,7 @@ render_elements! {
|
||||||
Surface = WaylandSurfaceRenderElement<R>,
|
Surface = WaylandSurfaceRenderElement<R>,
|
||||||
Pointer = PointerRenderElement<R>,
|
Pointer = PointerRenderElement<R>,
|
||||||
Transform = TransformRenderElement<R, E>,
|
Transform = TransformRenderElement<R, E>,
|
||||||
|
Color = SolidColorRenderElement,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<R> AsRenderElements<R> for WindowElement
|
impl<R> AsRenderElements<R> for WindowElement
|
||||||
|
|
11
src/state.rs
11
src/state.rs
|
@ -7,6 +7,7 @@ use crate::{
|
||||||
config::Config,
|
config::Config,
|
||||||
focus::OutputFocusStack,
|
focus::OutputFocusStack,
|
||||||
grab::resize_grab::ResizeSurfaceState,
|
grab::resize_grab::ResizeSurfaceState,
|
||||||
|
handlers::session_lock::LockState,
|
||||||
layout::LayoutState,
|
layout::LayoutState,
|
||||||
protocol::{
|
protocol::{
|
||||||
foreign_toplevel::{self, ForeignToplevelManagerState},
|
foreign_toplevel::{self, ForeignToplevelManagerState},
|
||||||
|
@ -41,6 +42,7 @@ use smithay::{
|
||||||
data_device::DataDeviceState, primary_selection::PrimarySelectionState,
|
data_device::DataDeviceState, primary_selection::PrimarySelectionState,
|
||||||
wlr_data_control::DataControlState,
|
wlr_data_control::DataControlState,
|
||||||
},
|
},
|
||||||
|
session_lock::SessionLockManagerState,
|
||||||
shell::{wlr_layer::WlrLayerShellState, xdg::XdgShellState},
|
shell::{wlr_layer::WlrLayerShellState, xdg::XdgShellState},
|
||||||
shm::ShmState,
|
shm::ShmState,
|
||||||
socket::ListeningSocketSource,
|
socket::ListeningSocketSource,
|
||||||
|
@ -94,6 +96,9 @@ pub struct Pinnacle {
|
||||||
pub relative_pointer_manager_state: RelativePointerManagerState,
|
pub relative_pointer_manager_state: RelativePointerManagerState,
|
||||||
pub pointer_constraints_state: PointerConstraintsState,
|
pub pointer_constraints_state: PointerConstraintsState,
|
||||||
pub foreign_toplevel_manager_state: ForeignToplevelManagerState,
|
pub foreign_toplevel_manager_state: ForeignToplevelManagerState,
|
||||||
|
pub session_lock_manager_state: SessionLockManagerState,
|
||||||
|
|
||||||
|
pub lock_state: LockState,
|
||||||
|
|
||||||
/// The state of key and mousebinds along with libinput settings
|
/// The state of key and mousebinds along with libinput settings
|
||||||
pub input_state: InputState,
|
pub input_state: InputState,
|
||||||
|
@ -262,6 +267,12 @@ impl Pinnacle {
|
||||||
&display_handle,
|
&display_handle,
|
||||||
filter_restricted_client,
|
filter_restricted_client,
|
||||||
),
|
),
|
||||||
|
session_lock_manager_state: SessionLockManagerState::new::<State, _>(
|
||||||
|
&display_handle,
|
||||||
|
filter_restricted_client,
|
||||||
|
),
|
||||||
|
|
||||||
|
lock_state: LockState::default(),
|
||||||
|
|
||||||
input_state: InputState::new(),
|
input_state: InputState::new(),
|
||||||
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue