Add cosmic-session-lock-layer-v1 protocol
https://github.com/pop-os/cosmic-protocols/pull/88
This commit is contained in:
parent
f9e02f4321
commit
a7349b72e3
7 changed files with 339 additions and 85 deletions
|
|
@ -2,12 +2,15 @@ use crate::{
|
|||
shell::{CosmicSurface, MinimizedWindow, Shell, Trigger, element::CosmicMapped},
|
||||
state::{Common, State},
|
||||
utils::prelude::*,
|
||||
wayland::handlers::{xdg_shell::PopupGrabData, xwayland_keyboard_grab::XWaylandGrabSeatData},
|
||||
wayland::{
|
||||
handlers::{xdg_shell::PopupGrabData, xwayland_keyboard_grab::XWaylandGrabSeatData},
|
||||
protocols::session_lock_layer::layer_show_on_lock,
|
||||
},
|
||||
};
|
||||
use indexmap::IndexSet;
|
||||
use smithay::{
|
||||
backend::input::InputTime,
|
||||
desktop::{PopupUngrabStrategy, layer_map_for_output},
|
||||
desktop::{PopupUngrabStrategy, find_popup_root_surface, layer_map_for_output},
|
||||
input::{Seat, pointer::MotionEvent},
|
||||
output::Output,
|
||||
reexports::wayland_server::{Resource, protocol::wl_surface::WlSurface},
|
||||
|
|
@ -627,8 +630,15 @@ fn focus_target_is_valid(
|
|||
output: &Output,
|
||||
target: KeyboardFocusTarget,
|
||||
) -> bool {
|
||||
// If a session lock is active, only lock surfaces can be focused
|
||||
// If a session lock is active, only lock surfaces and lock layers can be focused
|
||||
if shell.session_lock.is_some() {
|
||||
if let KeyboardFocusTarget::LayerSurface(layer) = &target {
|
||||
return layer_show_on_lock(layer.wl_surface());
|
||||
} else if let KeyboardFocusTarget::Popup(popup) = &target
|
||||
&& let Ok(root) = find_popup_root_surface(popup)
|
||||
{
|
||||
return layer_show_on_lock(&root);
|
||||
}
|
||||
return matches!(target, KeyboardFocusTarget::LockSurface(_));
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -22,7 +22,7 @@ use crate::{
|
|||
prelude::OutputExt,
|
||||
quirks::{WORKSPACE_OVERVIEW_NAMESPACE, workspace_overview_is_open},
|
||||
},
|
||||
wayland::protocols::workspace::WorkspaceHandle,
|
||||
wayland::protocols::{session_lock_layer::layer_show_on_lock, workspace::WorkspaceHandle},
|
||||
};
|
||||
|
||||
pub enum Stage<'a> {
|
||||
|
|
@ -89,7 +89,92 @@ fn render_input_order_internal<R: 'static>(
|
|||
|
||||
// Session Lock
|
||||
if let Some(session_lock) = &shell.session_lock {
|
||||
return callback(Stage::SessionLock(session_lock.surfaces.get(output)));
|
||||
for (layer, popup, location) in layer_popups(output, Layer::Overlay, element_filter) {
|
||||
if !layer_show_on_lock(layer.wl_surface()) {
|
||||
continue;
|
||||
}
|
||||
callback(Stage::LayerPopup {
|
||||
layer,
|
||||
popup: &popup,
|
||||
location,
|
||||
workspace_idx: current.1,
|
||||
})?;
|
||||
}
|
||||
for (layer, location) in layer_surfaces(output, Layer::Overlay, element_filter) {
|
||||
if !layer_show_on_lock(layer.wl_surface()) {
|
||||
continue;
|
||||
}
|
||||
callback(Stage::LayerSurface {
|
||||
layer,
|
||||
location,
|
||||
workspace_idx: current.1,
|
||||
})?;
|
||||
}
|
||||
for (layer, popup, location) in layer_popups(output, Layer::Top, element_filter) {
|
||||
if !layer_show_on_lock(layer.wl_surface()) {
|
||||
continue;
|
||||
}
|
||||
callback(Stage::LayerPopup {
|
||||
layer,
|
||||
popup: &popup,
|
||||
location,
|
||||
workspace_idx: current.1,
|
||||
})?;
|
||||
}
|
||||
for (layer, location) in layer_surfaces(output, Layer::Top, element_filter) {
|
||||
if !layer_show_on_lock(layer.wl_surface()) {
|
||||
continue;
|
||||
}
|
||||
callback(Stage::LayerSurface {
|
||||
layer,
|
||||
location,
|
||||
workspace_idx: current.1,
|
||||
})?;
|
||||
}
|
||||
callback(Stage::SessionLock(session_lock.surfaces.get(output)))?;
|
||||
for (layer, popup, location) in layer_popups(output, Layer::Bottom, element_filter) {
|
||||
if !layer_show_on_lock(layer.wl_surface()) {
|
||||
continue;
|
||||
}
|
||||
callback(Stage::LayerPopup {
|
||||
layer,
|
||||
popup: &popup,
|
||||
location,
|
||||
workspace_idx: current.1,
|
||||
})?;
|
||||
}
|
||||
for (layer, popup, location) in layer_popups(output, Layer::Background, element_filter) {
|
||||
if !layer_show_on_lock(layer.wl_surface()) {
|
||||
continue;
|
||||
}
|
||||
callback(Stage::LayerPopup {
|
||||
layer,
|
||||
popup: &popup,
|
||||
location,
|
||||
workspace_idx: current.1,
|
||||
})?;
|
||||
}
|
||||
for (layer, location) in layer_surfaces(output, Layer::Bottom, element_filter) {
|
||||
if !layer_show_on_lock(layer.wl_surface()) {
|
||||
continue;
|
||||
}
|
||||
callback(Stage::LayerSurface {
|
||||
layer,
|
||||
location,
|
||||
workspace_idx: current.1,
|
||||
})?;
|
||||
}
|
||||
for (layer, location) in layer_surfaces(output, Layer::Background, element_filter) {
|
||||
if !layer_show_on_lock(layer.wl_surface()) {
|
||||
continue;
|
||||
}
|
||||
callback(Stage::LayerSurface {
|
||||
layer,
|
||||
location,
|
||||
workspace_idx: current.1,
|
||||
})?;
|
||||
}
|
||||
return ControlFlow::Continue(());
|
||||
}
|
||||
|
||||
// Overlay-level layer shell
|
||||
|
|
|
|||
|
|
@ -19,7 +19,10 @@ use crate::{
|
|||
utils,
|
||||
wayland::{
|
||||
handlers::data_device::{self, get_dnd_icon},
|
||||
protocols::workspace::{State as WState, WorkspaceCapabilities},
|
||||
protocols::{
|
||||
session_lock_layer::layer_show_on_lock,
|
||||
workspace::{State as WState, WorkspaceCapabilities},
|
||||
},
|
||||
},
|
||||
};
|
||||
use cosmic_comp_config::{
|
||||
|
|
@ -2049,11 +2052,24 @@ impl Shell {
|
|||
// NOTE: Keep in sync with surface iteration in `render_input_order_internal`
|
||||
|
||||
if let Some(session_lock) = &self.session_lock {
|
||||
return session_lock
|
||||
if let Some((output, _)) = session_lock
|
||||
.surfaces
|
||||
.iter()
|
||||
.find(|(_, v)| v.wl_surface() == surface)
|
||||
.map(|(k, _)| k);
|
||||
{
|
||||
return Some(output);
|
||||
}
|
||||
for o in self.outputs() {
|
||||
let map = layer_map_for_output(o);
|
||||
if let Some(layer_surface) = map.layer_for_surface(surface, WindowSurfaceType::ALL)
|
||||
{
|
||||
if layer_show_on_lock(layer_surface.wl_surface()) {
|
||||
return Some(o);
|
||||
} else {
|
||||
return None;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
self.outputs()
|
||||
|
|
|
|||
|
|
@ -23,6 +23,7 @@ use crate::{
|
|||
output_configuration::OutputConfigurationState,
|
||||
output_power::OutputPowerState,
|
||||
overlap_notify::OverlapNotifyState,
|
||||
session_lock_layer::SessionLockLayerState,
|
||||
toplevel_info::ToplevelInfoState,
|
||||
toplevel_management::{ManagementCapabilities, ToplevelManagementState},
|
||||
workspace::{WorkspaceState, WorkspaceUpdateGuard},
|
||||
|
|
@ -320,6 +321,7 @@ pub struct Common {
|
|||
pub xwayland_state: Option<XWaylandState>,
|
||||
pub xwayland_shell_state: XWaylandShellState,
|
||||
pub pointer_focus_state: Option<PointerFocusState>,
|
||||
pub session_lock_layer_state: SessionLockLayerState,
|
||||
|
||||
#[cfg(feature = "logind")]
|
||||
pub inhibit_lid_fd: Option<OwnedFd>,
|
||||
|
|
@ -763,6 +765,9 @@ impl State {
|
|||
|
||||
let dbus_state = DBusState::init(&handle);
|
||||
|
||||
let session_lock_layer_state =
|
||||
SessionLockLayerState::new::<State, _>(dh, client_not_sandboxed);
|
||||
|
||||
State {
|
||||
common: Common {
|
||||
config,
|
||||
|
|
@ -830,6 +835,7 @@ impl State {
|
|||
pointer_focus_state: None,
|
||||
dbus_state,
|
||||
keyboard_layout_state,
|
||||
session_lock_layer_state,
|
||||
|
||||
#[cfg(feature = "logind")]
|
||||
inhibit_lid_fd: None,
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@ pub mod keyboard_layout;
|
|||
pub mod output_configuration;
|
||||
pub mod output_power;
|
||||
pub mod overlap_notify;
|
||||
pub mod session_lock_layer;
|
||||
pub mod toplevel_info;
|
||||
pub mod toplevel_management;
|
||||
pub mod workspace;
|
||||
|
|
|
|||
136
src/wayland/protocols/session_lock_layer.rs
Normal file
136
src/wayland/protocols/session_lock_layer.rs
Normal file
|
|
@ -0,0 +1,136 @@
|
|||
use cosmic_protocols::session_lock_layer::v1::server::cosmic_session_lock_layer_manager_v1;
|
||||
use smithay::{
|
||||
reexports::wayland_server::{
|
||||
Client, DataInit, Dispatch, DisplayHandle, GlobalDispatch, New, backend::GlobalId,
|
||||
protocol::wl_surface,
|
||||
},
|
||||
wayland::{
|
||||
Dispatch2, GlobalDispatch2,
|
||||
compositor::{Cacheable, with_states},
|
||||
shell::wlr_layer::WlrLayerShellHandler,
|
||||
},
|
||||
};
|
||||
|
||||
struct SessionLockLayerData;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct SessionLockLayerState {
|
||||
global: GlobalId,
|
||||
}
|
||||
|
||||
impl SessionLockLayerState {
|
||||
pub fn new<D, F>(dh: &DisplayHandle, client_filter: F) -> Self
|
||||
where
|
||||
F: for<'a> Fn(&'a Client) -> bool + Clone + Send + Sync + 'static,
|
||||
D: GlobalDispatch<
|
||||
cosmic_session_lock_layer_manager_v1::CosmicSessionLockLayerManagerV1,
|
||||
SessionLockLayerGlobalData,
|
||||
> + 'static,
|
||||
{
|
||||
let global = dh
|
||||
.create_global::<D, cosmic_session_lock_layer_manager_v1::CosmicSessionLockLayerManagerV1, _>(
|
||||
1,
|
||||
SessionLockLayerGlobalData {
|
||||
filter: Box::new(client_filter.clone()),
|
||||
},
|
||||
);
|
||||
Self { global }
|
||||
}
|
||||
|
||||
pub fn global_id(&self) -> GlobalId {
|
||||
self.global.clone()
|
||||
}
|
||||
}
|
||||
|
||||
#[doc(hidden)]
|
||||
pub struct SessionLockLayerGlobalData {
|
||||
filter: Box<dyn for<'a> Fn(&'a Client) -> bool + Send + Sync>,
|
||||
}
|
||||
|
||||
impl<D> GlobalDispatch2<cosmic_session_lock_layer_manager_v1::CosmicSessionLockLayerManagerV1, D>
|
||||
for SessionLockLayerGlobalData
|
||||
where
|
||||
D: Dispatch<
|
||||
cosmic_session_lock_layer_manager_v1::CosmicSessionLockLayerManagerV1,
|
||||
SessionLockLayerData,
|
||||
>,
|
||||
{
|
||||
fn bind(
|
||||
&self,
|
||||
_state: &mut D,
|
||||
_handle: &DisplayHandle,
|
||||
_client: &Client,
|
||||
resource: New<cosmic_session_lock_layer_manager_v1::CosmicSessionLockLayerManagerV1>,
|
||||
data_init: &mut DataInit<'_, D>,
|
||||
) {
|
||||
data_init.init(resource, SessionLockLayerData);
|
||||
}
|
||||
|
||||
fn can_view(&self, client: &Client) -> bool {
|
||||
(self.filter)(client)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Default)]
|
||||
struct SessionLockLayerSurfaceData {
|
||||
show_on_lock: bool,
|
||||
}
|
||||
|
||||
impl Cacheable for SessionLockLayerSurfaceData {
|
||||
fn commit(&mut self, _dh: &DisplayHandle) -> Self {
|
||||
*self
|
||||
}
|
||||
|
||||
fn merge_into(self, into: &mut Self, _dh: &DisplayHandle) {
|
||||
*into = self;
|
||||
}
|
||||
}
|
||||
|
||||
pub fn layer_show_on_lock(wl_surface: &wl_surface::WlSurface) -> bool {
|
||||
with_states(wl_surface, |states| {
|
||||
if states.cached_state.has::<SessionLockLayerSurfaceData>() {
|
||||
let mut state = states.cached_state.get::<SessionLockLayerSurfaceData>();
|
||||
state.current().show_on_lock
|
||||
} else {
|
||||
false
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
impl<D> Dispatch2<cosmic_session_lock_layer_manager_v1::CosmicSessionLockLayerManagerV1, D>
|
||||
for SessionLockLayerData
|
||||
where
|
||||
D: WlrLayerShellHandler,
|
||||
{
|
||||
fn request(
|
||||
&self,
|
||||
state: &mut D,
|
||||
_: &Client,
|
||||
_: &cosmic_session_lock_layer_manager_v1::CosmicSessionLockLayerManagerV1,
|
||||
request: cosmic_session_lock_layer_manager_v1::Request,
|
||||
_: &DisplayHandle,
|
||||
_: &mut DataInit<'_, D>,
|
||||
) {
|
||||
let (layer, value) = match request {
|
||||
cosmic_session_lock_layer_manager_v1::Request::SetShowOnLock { layer } => (layer, true),
|
||||
cosmic_session_lock_layer_manager_v1::Request::UnsetShowOnLock { layer } => {
|
||||
(layer, false)
|
||||
}
|
||||
cosmic_session_lock_layer_manager_v1::Request::Destroy => {
|
||||
return;
|
||||
}
|
||||
_ => unreachable!(),
|
||||
};
|
||||
|
||||
if let Some(layer) = state
|
||||
.shell_state()
|
||||
.layer_surfaces()
|
||||
.find(|surface| surface.shell_surface() == &layer)
|
||||
{
|
||||
with_states(layer.wl_surface(), |states| {
|
||||
let mut state = states.cached_state.get::<SessionLockLayerSurfaceData>();
|
||||
state.pending().show_on_lock = value;
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue