Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions src/backend/wayland/backend/state_init/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,7 @@ pub(super) fn init_state(backend: &WaylandBackend, setup: WaylandSetup) -> Resul
frozen_enabled: frozen_supported,
preferred_output_identity: output_prefs.preferred_output_identity,
xdg_fullscreen: output_prefs.xdg_fullscreen,
main_surface_uses_overlay_layer: output_prefs.main_surface_uses_overlay_layer,
pending_freeze_on_start: freeze_on_start,
screencopy_manager: setup.screencopy_manager,
#[cfg(tablet)]
Expand Down
63 changes: 63 additions & 0 deletions src/backend/wayland/backend/state_init/output.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ use crate::config::Config;
pub(super) struct OutputPreferences {
pub(super) preferred_output_identity: Option<String>,
pub(super) xdg_fullscreen: bool,
pub(super) main_surface_uses_overlay_layer: bool,
}

pub(super) fn resolve(config: &Config) -> OutputPreferences {
Expand All @@ -24,6 +25,8 @@ pub(super) fn resolve(config: &Config) -> OutputPreferences {
.map(|v| v == "1" || v.eq_ignore_ascii_case("true"))
.unwrap_or(config.ui.xdg_fullscreen);
let desktop_env = env::var("XDG_CURRENT_DESKTOP").unwrap_or_default();
let session_env = env::var("XDG_SESSION_DESKTOP").unwrap_or_default();
let desktop_session = env::var("DESKTOP_SESSION").unwrap_or_default();
let force_fullscreen = env::var("WAYSCRIBER_XDG_FULLSCREEN_FORCE")
.map(|v| v == "1" || v.eq_ignore_ascii_case("true"))
.unwrap_or(false);
Expand All @@ -33,9 +36,69 @@ pub(super) fn resolve(config: &Config) -> OutputPreferences {
);
xdg_fullscreen = false;
}
let main_surface_uses_overlay_layer =
main_surface_uses_overlay_layer_with_env(&desktop_env, &session_env, &desktop_session);
if main_surface_uses_overlay_layer {
info!(
"Niri detected; mapping the main overlay surface in the overlay layer so fullscreen windows cannot cover Wayscriber"
);
}

OutputPreferences {
preferred_output_identity,
xdg_fullscreen,
main_surface_uses_overlay_layer,
}
}

fn main_surface_uses_overlay_layer_with_env(
desktop_env: &str,
session_env: &str,
desktop_session: &str,
) -> bool {
desktop_matches(desktop_env, "niri")
|| desktop_matches(session_env, "niri")
|| desktop_matches(desktop_session, "niri")
}

fn desktop_matches(value: &str, target: &str) -> bool {
value
.split(':')
.map(str::trim)
.any(|entry| entry.eq_ignore_ascii_case(target))
}

#[cfg(test)]
mod tests {
use super::main_surface_uses_overlay_layer_with_env;

#[test]
fn main_surface_uses_overlay_layer_for_niri_desktop() {
assert!(main_surface_uses_overlay_layer_with_env("niri", "", ""));
assert!(main_surface_uses_overlay_layer_with_env(
"Hyprland:Niri",
"",
""
));
}

#[test]
fn main_surface_uses_overlay_layer_for_niri_session() {
assert!(main_surface_uses_overlay_layer_with_env("", "NIRI", ""));
}

#[test]
fn main_surface_uses_overlay_layer_for_niri_desktop_session() {
assert!(main_surface_uses_overlay_layer_with_env("", "", "niri"));
}

#[test]
fn main_surface_stays_on_top_layer_for_other_desktops() {
assert!(!main_surface_uses_overlay_layer_with_env(
"Hyprland", "", ""
));
assert!(!main_surface_uses_overlay_layer_with_env(
"KDE", "plasma", ""
));
}
}
9 changes: 4 additions & 5 deletions src/backend/wayland/backend/surface.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,7 @@
use anyhow::Result;
use log::info;
use smithay_client_toolkit::shell::{
WaylandSurface,
wlr_layer::{Anchor, Layer},
xdg::window::WindowDecorations,
WaylandSurface, wlr_layer::Anchor, xdg::window::WindowDecorations,
};

use crate::app_id::runtime_app_id;
Expand All @@ -17,11 +15,12 @@ pub(super) fn create_overlay_surface(
// Create surface using layer-shell when available, otherwise fall back to xdg-shell
let wl_surface = state.compositor_state.create_surface(qh);
if let Some(layer_shell) = state.layer_shell.as_ref() {
info!("Creating layer shell surface");
let layer = state.main_surface_layer();
info!("Creating layer shell surface in {:?} layer", layer);
let layer_surface = layer_shell.create_layer_surface(
qh,
wl_surface,
Layer::Top,
layer,
Some("wayscriber"),
None, // Default output
);
Expand Down
1 change: 1 addition & 0 deletions src/backend/wayland/state.rs
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,7 @@ pub(in crate::backend::wayland) struct WaylandStateInit {
pub frozen_enabled: bool,
pub preferred_output_identity: Option<String>,
pub xdg_fullscreen: bool,
pub main_surface_uses_overlay_layer: bool,
pub pending_freeze_on_start: bool,
pub screencopy_manager: Option<ScreencopyManager>,
#[cfg(tablet)]
Expand Down
10 changes: 10 additions & 0 deletions src/backend/wayland/state/core/accessors.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
use smithay_client_toolkit::shell::wlr_layer::Layer;

use super::super::*;
use std::time::{Duration, Instant};

Expand Down Expand Up @@ -176,6 +178,14 @@ impl WaylandState {
self.data.xdg_fullscreen
}

pub(in crate::backend::wayland) fn main_surface_layer(&self) -> Layer {
if self.data.main_surface_uses_overlay_layer {
Layer::Overlay
} else {
Layer::Top
}
}

pub(in crate::backend::wayland) fn xdg_focus_loss_exits_overlay(&self) -> bool {
matches!(
self.config.ui.xdg_focus_loss_behavior,
Expand Down
10 changes: 9 additions & 1 deletion src/backend/wayland/state/core/init.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ impl WaylandState {
frozen_enabled,
preferred_output_identity,
xdg_fullscreen,
main_surface_uses_overlay_layer,
pending_freeze_on_start,
screencopy_manager,
#[cfg(tablet)]
Expand Down Expand Up @@ -53,13 +54,20 @@ impl WaylandState {
data.startup_activation_token = startup_activation_token;
data.preferred_output_identity = preferred_output_identity;
data.xdg_fullscreen = xdg_fullscreen;
data.main_surface_uses_overlay_layer = main_surface_uses_overlay_layer;
let force_inline_toolbars = force_inline_toolbars_requested(&config);
data.inline_toolbars = layer_shell.is_none() || force_inline_toolbars;
data.inline_toolbars =
layer_shell.is_none() || force_inline_toolbars || main_surface_uses_overlay_layer;
if force_inline_toolbars {
info!(
"Forcing inline toolbars (config/ui.toolbar.force_inline or WAYSCRIBER_FORCE_INLINE_TOOLBARS)"
);
}
if main_surface_uses_overlay_layer {
info!(
"Using inline toolbars because the main overlay surface runs above fullscreen windows"
);
}
data.toolbar_top_offset = config.ui.toolbar.top_offset;
data.toolbar_top_offset_y = config.ui.toolbar.top_offset_y;
data.toolbar_side_offset = config.ui.toolbar.side_offset;
Expand Down
8 changes: 3 additions & 5 deletions src/backend/wayland/state/core/output.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,5 @@
use log::{info, warn};
use smithay_client_toolkit::shell::{
WaylandSurface,
wlr_layer::{Anchor, Layer},
};
use smithay_client_toolkit::shell::{WaylandSurface, wlr_layer::Anchor};
use std::time::Instant;

use super::super::*;
Expand Down Expand Up @@ -285,10 +282,11 @@ impl WaylandState {

let wl_surface = self.compositor_state.create_surface(qh);
wl_surface.set_buffer_scale(self.surface.scale().max(1));
let layer = self.main_surface_layer();
let layer_surface = layer_shell.create_layer_surface(
qh,
wl_surface,
Layer::Top,
layer,
Some("wayscriber"),
Some(output),
);
Expand Down
2 changes: 2 additions & 0 deletions src/backend/wayland/state/data.rs
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,7 @@ pub struct StateData {
pub(super) has_seen_surface_enter: bool,
pub(super) preferred_output_identity: Option<String>,
pub(super) xdg_fullscreen: bool,
pub(super) main_surface_uses_overlay_layer: bool,
pub(super) overlay_suppression: OverlaySuppression,
/// True when surface is configured and has keyboard focus; keys are blocked until ready.
pub(super) overlay_ready: bool,
Expand Down Expand Up @@ -139,6 +140,7 @@ impl StateData {
has_seen_surface_enter: false,
preferred_output_identity: None,
xdg_fullscreen: false,
main_surface_uses_overlay_layer: false,
overlay_suppression: OverlaySuppression::None,
overlay_ready: false,
suppress_next_release: false,
Expand Down
3 changes: 2 additions & 1 deletion src/backend/wayland/state/toolbar/visibility/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,9 @@ mod sync;
fn desired_keyboard_interactivity_for(
layer_shell_available: bool,
toolbar_visible: bool,
inline_toolbars_active: bool,
) -> KeyboardInteractivity {
if layer_shell_available && toolbar_visible {
if layer_shell_available && toolbar_visible && !inline_toolbars_active {
KeyboardInteractivity::OnDemand
} else {
KeyboardInteractivity::Exclusive
Expand Down
6 changes: 5 additions & 1 deletion src/backend/wayland/state/toolbar/visibility/sync.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,11 @@ impl WaylandState {
if self.overlay_suppressed() {
return KeyboardInteractivity::None;
}
desired_keyboard_interactivity_for(self.layer_shell.is_some(), self.toolbar.is_visible())
desired_keyboard_interactivity_for(
self.layer_shell.is_some(),
self.toolbar.is_visible(),
self.inline_toolbars_active(),
)
}

fn log_toolbar_layer_shell_missing_once(&mut self) {
Expand Down
12 changes: 8 additions & 4 deletions src/backend/wayland/state/toolbar/visibility/tests.rs
Original file line number Diff line number Diff line change
@@ -1,17 +1,21 @@
use super::*;

#[test]
fn desired_keyboard_interactivity_requires_layer_shell_and_visibility() {
fn desired_keyboard_interactivity_requires_layer_shell_and_layer_toolbars() {
assert_eq!(
desired_keyboard_interactivity_for(true, true),
desired_keyboard_interactivity_for(true, true, false),
KeyboardInteractivity::OnDemand
);
assert_eq!(
desired_keyboard_interactivity_for(true, false),
desired_keyboard_interactivity_for(true, false, false),
KeyboardInteractivity::Exclusive
);
assert_eq!(
desired_keyboard_interactivity_for(false, true),
desired_keyboard_interactivity_for(false, true, false),
KeyboardInteractivity::Exclusive
);
assert_eq!(
desired_keyboard_interactivity_for(true, true, true),
KeyboardInteractivity::Exclusive
);
}
10 changes: 9 additions & 1 deletion src/session/snapshot/apply.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,15 @@ pub fn apply_snapshot(input: &mut InputState, snapshot: SessionSnapshot, options
}
}

input.switch_board_force(&snapshot.active_board_id);
if input.boards.has_board(&snapshot.active_board_id) {
input.switch_board_force(&snapshot.active_board_id);
} else {
log::warn!(
"Session active board '{}' missing after restore; keeping current board '{}'",
snapshot.active_board_id,
input.board_id()
);
}

if options.restore_tool_state {
if let Some(tool_state) = snapshot.tool_state {
Expand Down
Loading
Loading