merge: epoch-1.9.0 d'upstream
# Conflicts: # Cargo.lock
This commit is contained in:
commit
51c6cfedf6
11 changed files with 560 additions and 1056 deletions
1198
Cargo.lock
generated
1198
Cargo.lock
generated
File diff suppressed because it is too large
Load diff
|
|
@ -172,7 +172,7 @@ pub enum ColorFilter {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Config {
|
impl Config {
|
||||||
pub fn load(loop_handle: &LoopHandle<'_, State>) -> Config {
|
pub fn load(loop_handle: &LoopHandle<'_, State>, kiosk_mode: bool) -> Config {
|
||||||
let config = cosmic_config::Config::new("com.system76.CosmicComp", 1).unwrap();
|
let config = cosmic_config::Config::new("com.system76.CosmicComp", 1).unwrap();
|
||||||
let source = cosmic_config::calloop::ConfigWatchSource::new(&config).unwrap();
|
let source = cosmic_config::calloop::ConfigWatchSource::new(&config).unwrap();
|
||||||
loop_handle
|
loop_handle
|
||||||
|
|
@ -248,18 +248,24 @@ impl Config {
|
||||||
|
|
||||||
// Source key bindings from com.system76.CosmicSettings.Shortcuts
|
// Source key bindings from com.system76.CosmicSettings.Shortcuts
|
||||||
let settings_context = shortcuts::context().expect("Failed to load shortcuts config");
|
let settings_context = shortcuts::context().expect("Failed to load shortcuts config");
|
||||||
let system_actions = shortcuts::system_actions(&settings_context);
|
let mut system_actions = Default::default();
|
||||||
let shortcuts = shortcuts::shortcuts(&settings_context);
|
let mut shortcuts = Default::default();
|
||||||
|
// Kiosk mode disables shortcuts
|
||||||
|
if !kiosk_mode {
|
||||||
|
system_actions = shortcuts::system_actions(&settings_context);
|
||||||
|
shortcuts = shortcuts::shortcuts(&settings_context);
|
||||||
|
|
||||||
// Listen for updates to the keybindings config.
|
// Listen for updates to the keybindings config.
|
||||||
match cosmic_config::calloop::ConfigWatchSource::new(&settings_context) {
|
match cosmic_config::calloop::ConfigWatchSource::new(&settings_context) {
|
||||||
Ok(source) => {
|
Ok(source) => {
|
||||||
if let Err(err) = loop_handle.insert_source(source, |(config, keys), (), state| {
|
if let Err(err) =
|
||||||
|
loop_handle.insert_source(source, |(config, keys), (), state| {
|
||||||
for key in keys {
|
for key in keys {
|
||||||
match key.as_str() {
|
match key.as_str() {
|
||||||
// Reload the keyboard shortcuts config.
|
// Reload the keyboard shortcuts config.
|
||||||
"custom" | "defaults" => {
|
"custom" | "defaults" => {
|
||||||
state.common.config.shortcuts = shortcuts::shortcuts(&config);
|
state.common.config.shortcuts =
|
||||||
|
shortcuts::shortcuts(&config);
|
||||||
}
|
}
|
||||||
|
|
||||||
"system_actions" => {
|
"system_actions" => {
|
||||||
|
|
@ -270,7 +276,8 @@ impl Config {
|
||||||
_ => (),
|
_ => (),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}) {
|
})
|
||||||
|
{
|
||||||
warn!(
|
warn!(
|
||||||
?err,
|
?err,
|
||||||
"Failed to watch com.system76.CosmicSettings.Shortcuts config"
|
"Failed to watch com.system76.CosmicSettings.Shortcuts config"
|
||||||
|
|
@ -282,6 +289,7 @@ impl Config {
|
||||||
"failed to create config watch source for com.system76.CosmicSettings.Shortcuts"
|
"failed to create config watch source for com.system76.CosmicSettings.Shortcuts"
|
||||||
),
|
),
|
||||||
};
|
};
|
||||||
|
}
|
||||||
|
|
||||||
let window_rules_context =
|
let window_rules_context =
|
||||||
window_rules::context().expect("Failed to load window rules config");
|
window_rules::context().expect("Failed to load window rules config");
|
||||||
|
|
|
||||||
|
|
@ -19,7 +19,7 @@ use crate::{
|
||||||
Stage, render_input_order,
|
Stage, render_input_order,
|
||||||
target::{KeyboardFocusTarget, PointerFocusTarget},
|
target::{KeyboardFocusTarget, PointerFocusTarget},
|
||||||
},
|
},
|
||||||
grabs::{ReleaseMode, ResizeEdge},
|
grabs::{MenuGrab, MoveGrab, ReleaseMode, ResizeEdge, ResizeGrab},
|
||||||
layout::{
|
layout::{
|
||||||
floating::ResizeGrabMarker,
|
floating::ResizeGrabMarker,
|
||||||
tiling::{NodeDesc, SwapWindowGrab, TilingLayout},
|
tiling::{NodeDesc, SwapWindowGrab, TilingLayout},
|
||||||
|
|
@ -49,7 +49,7 @@ use smithay::{
|
||||||
PointerAxisEvent, ProximityState, TabletToolButtonEvent, TabletToolEvent,
|
PointerAxisEvent, ProximityState, TabletToolButtonEvent, TabletToolEvent,
|
||||||
TabletToolProximityEvent, TabletToolTipEvent, TabletToolTipState, TouchEvent,
|
TabletToolProximityEvent, TabletToolTipEvent, TabletToolTipState, TouchEvent,
|
||||||
},
|
},
|
||||||
desktop::{PopupKeyboardGrab, WindowSurfaceType, utils::under_from_surface_tree},
|
desktop::{WindowSurfaceType, utils::under_from_surface_tree},
|
||||||
input::{
|
input::{
|
||||||
Seat,
|
Seat,
|
||||||
keyboard::KeyboardHandle,
|
keyboard::KeyboardHandle,
|
||||||
|
|
@ -2096,6 +2096,21 @@ impl State {
|
||||||
backend_id, seat, modifiers, handle, serial, keycode, key_state, time,
|
backend_id, seat, modifiers, handle, serial, keycode, key_state, time,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// A modifier-only binding fires on the modifier's release, but its press was already
|
||||||
|
// forwarded. Forward the release too.
|
||||||
|
if key_state == KeyState::Released
|
||||||
|
&& matches!(&result, FilterResult::Intercept(Some((_, binding))) if binding.key.is_none())
|
||||||
|
{
|
||||||
|
seat.get_keyboard().unwrap().input_forward(
|
||||||
|
self,
|
||||||
|
keycode,
|
||||||
|
key_state,
|
||||||
|
serial,
|
||||||
|
time,
|
||||||
|
previous_modifiers != *modifiers,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
if (matches!(result, FilterResult::Forward)
|
if (matches!(result, FilterResult::Forward)
|
||||||
&& !seat.get_keyboard().unwrap().is_grabbed()
|
&& !seat.get_keyboard().unwrap().is_grabbed()
|
||||||
&& !shortcuts_inhibited
|
&& !shortcuts_inhibited
|
||||||
|
|
@ -2291,17 +2306,15 @@ impl State {
|
||||||
|
|
||||||
let keyboard = seat.get_keyboard().unwrap();
|
let keyboard = seat.get_keyboard().unwrap();
|
||||||
let pointer = seat.get_pointer().unwrap();
|
let pointer = seat.get_pointer().unwrap();
|
||||||
// We're only interested in filtering keyboard grabs if we initiated them.
|
// Escape only cancels grabs the compositor started for its own interactions
|
||||||
// The easiest way to check that is to check the type of the grab.
|
// For keyboard: SwapWindowGrab
|
||||||
let keyboard_grabbed = keyboard.with_grab(|_serial, grab| {
|
// For pointer: MoveGrab, ResizeGrab, and MenuGrab
|
||||||
grab.is::<SwapWindowGrab>() || grab.is::<PopupKeyboardGrab<State>>()
|
let keyboard_grabbed =
|
||||||
|
keyboard.with_grab(|_serial, grab| grab.is::<SwapWindowGrab>()) == Some(true);
|
||||||
|
let pointer_grabbed = pointer.with_grab(|_serial, grab| {
|
||||||
|
grab.is::<MoveGrab>() || grab.is::<ResizeGrab>() || grab.is::<MenuGrab>()
|
||||||
}) == Some(true);
|
}) == Some(true);
|
||||||
// A virtual-keyboard key can arrive while the seat's pointer is grabbed by that
|
let is_grabbed = keyboard_grabbed || pointer_grabbed;
|
||||||
// same on-screen keyboard's own button press (the implicit grab from clicking an OSK
|
|
||||||
// key). That pointer grab must not capture the injected key, otherwise e.g.
|
|
||||||
// pressing esc on a virtual keyboard gets swallowed here
|
|
||||||
let from_vk = matches!(backend_id, InputBackendId::VirtualKeyboard);
|
|
||||||
let is_grabbed = keyboard_grabbed || (pointer.is_grabbed() && !from_vk);
|
|
||||||
|
|
||||||
let current_focus = keyboard.current_focus();
|
let current_focus = keyboard.current_focus();
|
||||||
//this should fall back to active output since there may not be a focused output
|
//this should fall back to active output since there may not be a focused output
|
||||||
|
|
|
||||||
|
|
@ -289,7 +289,7 @@ Project home page: https://github.com/pop-os/cosmic-comp
|
||||||
Options:
|
Options:
|
||||||
-h, --help Show this message
|
-h, --help Show this message
|
||||||
--no-xwayland Run without Xwayland
|
--no-xwayland Run without Xwayland
|
||||||
-v, --version Show the version of cosmic-comp"#
|
-V, --version Show the version of cosmic-comp"#
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -2,12 +2,18 @@ use crate::{
|
||||||
shell::{CosmicSurface, MinimizedWindow, Shell, Trigger, element::CosmicMapped},
|
shell::{CosmicSurface, MinimizedWindow, Shell, Trigger, element::CosmicMapped},
|
||||||
state::{Common, State},
|
state::{Common, State},
|
||||||
utils::prelude::*,
|
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 indexmap::IndexSet;
|
||||||
use smithay::{
|
use smithay::{
|
||||||
backend::input::InputTime,
|
backend::input::InputTime,
|
||||||
desktop::{PopupUngrabStrategy, layer_map_for_output},
|
desktop::{
|
||||||
|
LayerSurface, PopupUngrabStrategy, WindowSurfaceType, find_popup_root_surface,
|
||||||
|
layer_map_for_output,
|
||||||
|
},
|
||||||
input::{Seat, pointer::MotionEvent},
|
input::{Seat, pointer::MotionEvent},
|
||||||
output::Output,
|
output::Output,
|
||||||
reexports::wayland_server::{Resource, protocol::wl_surface::WlSurface},
|
reexports::wayland_server::{Resource, protocol::wl_surface::WlSurface},
|
||||||
|
|
@ -627,19 +633,42 @@ fn focus_target_is_valid(
|
||||||
output: &Output,
|
output: &Output,
|
||||||
target: KeyboardFocusTarget,
|
target: KeyboardFocusTarget,
|
||||||
) -> bool {
|
) -> 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 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(_));
|
return matches!(target, KeyboardFocusTarget::LockSurface(_));
|
||||||
}
|
}
|
||||||
|
|
||||||
// If an exclusive layer shell surface exists (on any output), only exclusive
|
// If an exclusive layer shell surface exists (on any output), only exclusive
|
||||||
// shell surfaces can have focus, on the highest layer with exclusive surfaces.
|
// shell surfaces can have focus, on the highest layer with exclusive surfaces.
|
||||||
|
// Popups are judged by their root surface, so an exclusive surface can
|
||||||
|
// still open grabbing popups (menus, dropdowns, context menus).
|
||||||
if let Some(layer) = exclusive_layer_surface_layer(shell) {
|
if let Some(layer) = exclusive_layer_surface_layer(shell) {
|
||||||
return if let KeyboardFocusTarget::LayerSurface(layer_surface) = target {
|
let is_exclusive_on_layer = |layer_surface: &LayerSurface| {
|
||||||
let data = layer_surface.cached_state();
|
let data = layer_surface.cached_state();
|
||||||
(data.keyboard_interactivity, data.layer) == (KeyboardInteractivity::Exclusive, layer)
|
(data.keyboard_interactivity, data.layer) == (KeyboardInteractivity::Exclusive, layer)
|
||||||
} else {
|
};
|
||||||
false
|
return match target {
|
||||||
|
KeyboardFocusTarget::LayerSurface(layer_surface) => {
|
||||||
|
is_exclusive_on_layer(&layer_surface)
|
||||||
|
}
|
||||||
|
KeyboardFocusTarget::Popup(popup) => find_popup_root_surface(&popup)
|
||||||
|
.ok()
|
||||||
|
.and_then(|root| {
|
||||||
|
shell.outputs().find_map(|o| {
|
||||||
|
layer_map_for_output(o)
|
||||||
|
.layer_for_surface(&root, WindowSurfaceType::ALL)
|
||||||
|
.map(&is_exclusive_on_layer)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
.unwrap_or(false),
|
||||||
|
_ => false,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -22,7 +22,7 @@ use crate::{
|
||||||
prelude::OutputExt,
|
prelude::OutputExt,
|
||||||
quirks::{WORKSPACE_OVERVIEW_NAMESPACE, workspace_overview_is_open},
|
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> {
|
pub enum Stage<'a> {
|
||||||
|
|
@ -77,6 +77,8 @@ fn render_input_order_internal<R: 'static>(
|
||||||
element_filter: ElementFilter,
|
element_filter: ElementFilter,
|
||||||
mut callback: impl FnMut(Stage) -> ControlFlow<Result<R, OutputNoMode>, ()>,
|
mut callback: impl FnMut(Stage) -> ControlFlow<Result<R, OutputNoMode>, ()>,
|
||||||
) -> ControlFlow<Result<R, OutputNoMode>, ()> {
|
) -> ControlFlow<Result<R, OutputNoMode>, ()> {
|
||||||
|
// NOTE: Keep in sync with other surface iteration functions
|
||||||
|
|
||||||
if shell
|
if shell
|
||||||
.zoom_state
|
.zoom_state
|
||||||
.as_ref()
|
.as_ref()
|
||||||
|
|
@ -87,7 +89,92 @@ fn render_input_order_internal<R: 'static>(
|
||||||
|
|
||||||
// Session Lock
|
// Session Lock
|
||||||
if let Some(session_lock) = &shell.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
|
// Overlay-level layer shell
|
||||||
|
|
|
||||||
|
|
@ -19,7 +19,10 @@ use crate::{
|
||||||
utils,
|
utils,
|
||||||
wayland::{
|
wayland::{
|
||||||
handlers::data_device::{self, get_dnd_icon},
|
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::{
|
use cosmic_comp_config::{
|
||||||
|
|
@ -2046,12 +2049,27 @@ impl Shell {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn visible_output_for_surface(&self, surface: &WlSurface) -> Option<&Output> {
|
pub fn visible_output_for_surface(&self, surface: &WlSurface) -> Option<&Output> {
|
||||||
|
// NOTE: Keep in sync with surface iteration in `render_input_order_internal`
|
||||||
|
|
||||||
if let Some(session_lock) = &self.session_lock {
|
if let Some(session_lock) = &self.session_lock {
|
||||||
return session_lock
|
if let Some((output, _)) = session_lock
|
||||||
.surfaces
|
.surfaces
|
||||||
.iter()
|
.iter()
|
||||||
.find(|(_, v)| v.wl_surface() == surface)
|
.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()
|
self.outputs()
|
||||||
|
|
|
||||||
14
src/state.rs
14
src/state.rs
|
|
@ -23,6 +23,7 @@ use crate::{
|
||||||
output_configuration::OutputConfigurationState,
|
output_configuration::OutputConfigurationState,
|
||||||
output_power::OutputPowerState,
|
output_power::OutputPowerState,
|
||||||
overlap_notify::OverlapNotifyState,
|
overlap_notify::OverlapNotifyState,
|
||||||
|
session_lock_layer::SessionLockLayerState,
|
||||||
toplevel_info::ToplevelInfoState,
|
toplevel_info::ToplevelInfoState,
|
||||||
toplevel_management::{ManagementCapabilities, ToplevelManagementState},
|
toplevel_management::{ManagementCapabilities, ToplevelManagementState},
|
||||||
workspace::{WorkspaceState, WorkspaceUpdateGuard},
|
workspace::{WorkspaceState, WorkspaceUpdateGuard},
|
||||||
|
|
@ -320,6 +321,7 @@ pub struct Common {
|
||||||
pub xwayland_state: Option<XWaylandState>,
|
pub xwayland_state: Option<XWaylandState>,
|
||||||
pub xwayland_shell_state: XWaylandShellState,
|
pub xwayland_shell_state: XWaylandShellState,
|
||||||
pub pointer_focus_state: Option<PointerFocusState>,
|
pub pointer_focus_state: Option<PointerFocusState>,
|
||||||
|
pub session_lock_layer_state: SessionLockLayerState,
|
||||||
|
|
||||||
#[cfg(feature = "logind")]
|
#[cfg(feature = "logind")]
|
||||||
pub inhibit_lid_fd: Option<OwnedFd>,
|
pub inhibit_lid_fd: Option<OwnedFd>,
|
||||||
|
|
@ -665,7 +667,7 @@ impl State {
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
let clock = Clock::new();
|
let clock = Clock::new();
|
||||||
let config = Config::load(&handle);
|
let config = Config::load(&handle, kiosk_command.is_some());
|
||||||
let compositor_state = CompositorState::new::<Self>(dh);
|
let compositor_state = CompositorState::new::<Self>(dh);
|
||||||
let corner_radius_state = CornerRadiusState::new::<Self>(dh);
|
let corner_radius_state = CornerRadiusState::new::<Self>(dh);
|
||||||
let data_device_state = DataDeviceState::new::<Self>(dh);
|
let data_device_state = DataDeviceState::new::<Self>(dh);
|
||||||
|
|
@ -763,6 +765,9 @@ impl State {
|
||||||
|
|
||||||
let dbus_state = DBusState::init(&handle);
|
let dbus_state = DBusState::init(&handle);
|
||||||
|
|
||||||
|
let session_lock_layer_state =
|
||||||
|
SessionLockLayerState::new::<State, _>(dh, client_not_sandboxed);
|
||||||
|
|
||||||
State {
|
State {
|
||||||
common: Common {
|
common: Common {
|
||||||
config,
|
config,
|
||||||
|
|
@ -830,6 +835,7 @@ impl State {
|
||||||
pointer_focus_state: None,
|
pointer_focus_state: None,
|
||||||
dbus_state,
|
dbus_state,
|
||||||
keyboard_layout_state,
|
keyboard_layout_state,
|
||||||
|
session_lock_layer_state,
|
||||||
|
|
||||||
#[cfg(feature = "logind")]
|
#[cfg(feature = "logind")]
|
||||||
inhibit_lid_fd: None,
|
inhibit_lid_fd: None,
|
||||||
|
|
@ -968,6 +974,8 @@ impl Common {
|
||||||
output: &Output,
|
output: &Output,
|
||||||
render_element_states: &RenderElementStates,
|
render_element_states: &RenderElementStates,
|
||||||
) {
|
) {
|
||||||
|
// NOTE: Keep in sync with surface iteration in `render_input_order_internal`
|
||||||
|
|
||||||
let shell = self.shell.read();
|
let shell = self.shell.read();
|
||||||
let processor = |namespace: Option<usize>| {
|
let processor = |namespace: Option<usize>| {
|
||||||
move |surface: &WlSurface, states: &SurfaceData| {
|
move |surface: &WlSurface, states: &SurfaceData| {
|
||||||
|
|
@ -1074,6 +1082,8 @@ impl Common {
|
||||||
render_element_states: &RenderElementStates,
|
render_element_states: &RenderElementStates,
|
||||||
mut dmabuf_feedback: impl FnMut(DrmNode) -> Option<SurfaceDmabufFeedback>,
|
mut dmabuf_feedback: impl FnMut(DrmNode) -> Option<SurfaceDmabufFeedback>,
|
||||||
) {
|
) {
|
||||||
|
// NOTE: Keep in sync with surface iteration in `render_input_order_internal`
|
||||||
|
|
||||||
let shell = self.shell.read();
|
let shell = self.shell.read();
|
||||||
|
|
||||||
if let Some(session_lock) = shell.session_lock.as_ref()
|
if let Some(session_lock) = shell.session_lock.as_ref()
|
||||||
|
|
@ -1287,6 +1297,8 @@ impl Common {
|
||||||
|
|
||||||
#[profiling::function]
|
#[profiling::function]
|
||||||
pub fn send_frames(&self, output: &Output, sequence: Option<usize>) {
|
pub fn send_frames(&self, output: &Output, sequence: Option<usize>) {
|
||||||
|
// NOTE: Keep in sync with surface iteration in `render_input_order_internal`
|
||||||
|
|
||||||
let time = self.clock.now();
|
let time = self.clock.now();
|
||||||
let should_send = |surface: &WlSurface, states: &SurfaceData| {
|
let should_send = |surface: &WlSurface, states: &SurfaceData| {
|
||||||
// Do the standard primary scanout output check. For pointer surfaces it deduplicates
|
// Do the standard primary scanout output check. For pointer surfaces it deduplicates
|
||||||
|
|
|
||||||
|
|
@ -243,7 +243,7 @@ impl State {
|
||||||
{
|
{
|
||||||
for mapped in current_workspace
|
for mapped in current_workspace
|
||||||
.mapped()
|
.mapped()
|
||||||
.filter(|m| m.maximized_state.lock().unwrap().is_some())
|
.filter(|m| m.maximized_state.lock().unwrap().is_some() && *m != &element)
|
||||||
.cloned()
|
.cloned()
|
||||||
.collect::<Vec<_>>()
|
.collect::<Vec<_>>()
|
||||||
.into_iter()
|
.into_iter()
|
||||||
|
|
|
||||||
|
|
@ -8,6 +8,7 @@ pub mod keyboard_layout;
|
||||||
pub mod output_configuration;
|
pub mod output_configuration;
|
||||||
pub mod output_power;
|
pub mod output_power;
|
||||||
pub mod overlap_notify;
|
pub mod overlap_notify;
|
||||||
|
pub mod session_lock_layer;
|
||||||
pub mod toplevel_info;
|
pub mod toplevel_info;
|
||||||
pub mod toplevel_management;
|
pub mod toplevel_management;
|
||||||
pub mod workspace;
|
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