Compare commits

..

15 Commits

Author SHA1 Message Date
Ivan Molodetskikh 8ba57fcf25 Bump version to 25.05.1 2025-05-25 08:45:41 +03:00
Ivan Molodetskikh 126ca37d96 Rename Un/Set/ToggleUrgent to Un/Set/ToggleWindowUrgent
Overlooked this when reviewing. This change is not cfg-breaking (since you
can't bind these directly), but it does break calling these actions through
IPC. I don't imagine they are widely used though, and the original PR author
who also implemented urgency for bars said he didn't use these actions either.
2025-05-25 08:43:27 +03:00
Ivan Molodetskikh e6bd60fbb1 wiki: Remove note about numlock issue
It's been fixed.
2025-05-25 08:36:33 +03:00
Ivan Molodetskikh a605a3f016 Account for hidden pointer in move_cursor() 2025-05-23 23:08:51 +03:00
Ivan Molodetskikh ef44adea69 Set pointer contents straight to nothing when disabling pointer 2025-05-23 23:08:51 +03:00
Duncan Overbruck 7fdb918cd0 input: do not revert fully invisible cursor to hidden (#1650)
* input: do not force redraw to hide an already hidden cursor

* more

---------

Co-authored-by: Ivan Molodetskikh <yalterz@gmail.com>
2025-05-23 05:24:24 +00:00
Ivan Molodetskikh 8347cc20dc Update Smithay (pen tilt, num lock, keymap spam) 2025-05-22 18:05:17 +03:00
alex-huff 51a176ec4a layer-shell: only reset 'initial_configure_sent' for mapped surfaces 2025-05-22 08:02:56 -07:00
alex-huff d618daf6b9 layer-shell: don't dismiss popups because of unmapped layer surfaces
Fixes #1640
2025-05-22 07:55:29 -07:00
Ivan Molodetskikh 357f9157cc wiki/packaging: Mention RUN_SLOW_TESTS 2025-05-22 11:37:09 +03:00
Ivan Molodetskikh c4a759e620 wiki/packaging: Document limiting test threads 2025-05-22 11:35:12 +03:00
Ivan Molodetskikh f369a0f810 input: Add missing check for output under 2025-05-22 08:55:01 +03:00
Ivan Molodetskikh 71251a7003 input: Add missing redraws on urgency actions
The layout urgent colors update even without window rule changes.
2025-05-21 19:50:13 +03:00
alex-huff 2415346caa layer-shell: properly handle re-map
According to the zwlr_layer_surface_v1 documentation: Unmapping a
layer_surface means that the surface cannot be shown by the compositor
until it is explicitly mapped again. The layer_surface returns to the
state it had right after layer_shell.get_layer_surface. The client can
re-map the surface by performing a commit without any buffer attached,
waiting for a configure event and handling it as usual.

Before this commit, no configure event was sent when a client performed
a commit without any buffer attached.
2025-05-21 07:25:22 -07:00
Ivan Molodetskikh 3f2b7e63ba Improve comment in on-demand layer-shell keyboard alive check 2025-05-19 09:18:07 +03:00
13 changed files with 178 additions and 39 deletions
Generated
+72 -6
View File
@@ -385,6 +385,15 @@ version = "2.9.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1b8e56985ec62d17e9c1001dc89c88ecd7dc08e47eba5ec7c29c7b5eeecde967"
[[package]]
name = "block-buffer"
version = "0.10.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71"
dependencies = [
"generic-array",
]
[[package]]
name = "block2"
version = "0.5.1"
@@ -747,6 +756,15 @@ dependencies = [
"libc",
]
[[package]]
name = "cpufeatures"
version = "0.2.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "59ed5838eebb26a2bb2e58f6d5b5316989ae9d08bab10e0e6d103e656d1b0280"
dependencies = [
"libc",
]
[[package]]
name = "crc32fast"
version = "1.4.2"
@@ -781,6 +799,16 @@ version = "0.8.21"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28"
[[package]]
name = "crypto-common"
version = "0.1.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3"
dependencies = [
"generic-array",
"typenum",
]
[[package]]
name = "csscolorparser"
version = "0.7.0"
@@ -802,6 +830,16 @@ version = "0.1.13"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "56254986775e3233ffa9c4d7d3faaf6d36a2c09d30b20687e9f88bc8bafc16c8"
[[package]]
name = "digest"
version = "0.10.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292"
dependencies = [
"block-buffer",
"crypto-common",
]
[[package]]
name = "directories"
version = "6.0.0"
@@ -1256,6 +1294,16 @@ dependencies = [
"windows",
]
[[package]]
name = "generic-array"
version = "0.14.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a"
dependencies = [
"typenum",
"version_check",
]
[[package]]
name = "gethostname"
version = "0.4.3"
@@ -2210,7 +2258,7 @@ dependencies = [
[[package]]
name = "niri"
version = "25.5.0"
version = "25.5.1"
dependencies = [
"anyhow",
"approx 0.5.1",
@@ -2267,7 +2315,7 @@ dependencies = [
[[package]]
name = "niri-config"
version = "25.5.0"
version = "25.5.1"
dependencies = [
"bitflags 2.9.1",
"csscolorparser",
@@ -2284,7 +2332,7 @@ dependencies = [
[[package]]
name = "niri-ipc"
version = "25.5.0"
version = "25.5.1"
dependencies = [
"clap",
"schemars",
@@ -2294,7 +2342,7 @@ dependencies = [
[[package]]
name = "niri-visual-tests"
version = "25.5.0"
version = "25.5.1"
dependencies = [
"anyhow",
"gtk4",
@@ -3365,6 +3413,17 @@ dependencies = [
"serde",
]
[[package]]
name = "sha2"
version = "0.10.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a7507d819769d01a365ab707794a4084392c824f54a7a6a7862f8c3d0892b283"
dependencies = [
"cfg-if",
"cpufeatures",
"digest",
]
[[package]]
name = "sharded-slab"
version = "0.1.7"
@@ -3431,7 +3490,7 @@ checksum = "b7c388c1b5e93756d0c740965c41e8822f866621d41acbdf6336a6a168f8840c"
[[package]]
name = "smithay"
version = "0.6.0"
source = "git+https://github.com/Smithay/smithay.git#c1f13a6b9605c9f7009122a7b2b34f210255dac3"
source = "git+https://github.com/Smithay/smithay.git#ede27079f45eeb7c21796e22f3bc25b741b024ea"
dependencies = [
"aliasable",
"appendlist",
@@ -3458,6 +3517,7 @@ dependencies = [
"profiling",
"rand 0.9.1",
"rustix 0.38.44",
"sha2",
"smallvec",
"tempfile",
"thiserror 2.0.12",
@@ -3504,7 +3564,7 @@ dependencies = [
[[package]]
name = "smithay-drm-extras"
version = "0.1.0"
source = "git+https://github.com/Smithay/smithay.git#c1f13a6b9605c9f7009122a7b2b34f210255dac3"
source = "git+https://github.com/Smithay/smithay.git#ede27079f45eeb7c21796e22f3bc25b741b024ea"
dependencies = [
"drm",
"libdisplay-info",
@@ -3852,6 +3912,12 @@ dependencies = [
"windows-targets 0.52.6",
]
[[package]]
name = "typenum"
version = "1.18.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1dccffe3ce07af9386bfd29e80c0ab1a8205a2fc34e4bcd40364df902cfa8f3f"
[[package]]
name = "udev"
version = "0.9.3"
+3 -3
View File
@@ -6,7 +6,7 @@ members = [
]
[workspace.package]
version = "25.5.0"
version = "25.5.1"
description = "A scrollable-tiling Wayland compositor"
authors = ["Ivan Molodetskikh <yalterz@gmail.com>"]
license = "GPL-3.0-or-later"
@@ -71,8 +71,8 @@ keyframe = { version = "1.1.1", default-features = false }
libc = "0.2.172"
libdisplay-info = "0.2.2"
log = { version = "0.4.27", features = ["max_level_trace", "release_max_level_debug"] }
niri-config = { version = "25.5.0", path = "niri-config" }
niri-ipc = { version = "25.5.0", path = "niri-ipc", features = ["clap"] }
niri-config = { version = "25.5.1", path = "niri-config" }
niri-ipc = { version = "25.5.1", path = "niri-ipc", features = ["clap"] }
ordered-float = "5.0.0"
pango = { version = "0.20.10", features = ["v1_44"] }
pangocairo = "0.20.10"
+1 -1
View File
@@ -12,7 +12,7 @@ bitflags.workspace = true
csscolorparser = "0.7.0"
knuffel = "3.2.0"
miette = { version = "5.10.0", features = ["fancy-no-backtrace"] }
niri-ipc = { version = "25.5.0", path = "../niri-ipc" }
niri-ipc = { version = "25.5.1", path = "../niri-ipc" }
regex = "1.11.1"
smithay = { workspace = true, features = ["backend_libinput"] }
tracing.workspace = true
+6 -6
View File
@@ -1888,11 +1888,11 @@ pub enum Action {
OpenOverview,
CloseOverview,
#[knuffel(skip)]
ToggleUrgent(u64),
ToggleWindowUrgent(u64),
#[knuffel(skip)]
SetUrgent(u64),
SetWindowUrgent(u64),
#[knuffel(skip)]
UnsetUrgent(u64),
UnsetWindowUrgent(u64),
}
impl From<niri_ipc::Action> for Action {
@@ -2165,9 +2165,9 @@ impl From<niri_ipc::Action> for Action {
niri_ipc::Action::ToggleOverview {} => Self::ToggleOverview,
niri_ipc::Action::OpenOverview {} => Self::OpenOverview,
niri_ipc::Action::CloseOverview {} => Self::CloseOverview,
niri_ipc::Action::ToggleUrgent { id } => Self::ToggleUrgent(id),
niri_ipc::Action::SetUrgent { id } => Self::SetUrgent(id),
niri_ipc::Action::UnsetUrgent { id } => Self::UnsetUrgent(id),
niri_ipc::Action::ToggleWindowUrgent { id } => Self::ToggleWindowUrgent(id),
niri_ipc::Action::SetWindowUrgent { id } => Self::SetWindowUrgent(id),
niri_ipc::Action::UnsetWindowUrgent { id } => Self::UnsetWindowUrgent(id),
}
}
}
+1 -1
View File
@@ -12,5 +12,5 @@ Use an exact version requirement to avoid breaking changes:
```toml
[dependencies]
niri-ipc = "=25.5.0"
niri-ipc = "=25.5.1"
```
+4 -4
View File
@@ -41,7 +41,7 @@
//!
//! ```toml
//! [dependencies]
//! niri-ipc = "=25.5.0"
//! niri-ipc = "=25.5.1"
//! ```
//!
//! ## Features
@@ -823,19 +823,19 @@ pub enum Action {
/// Close the Overview.
CloseOverview {},
/// Toggle urgent status of a window.
ToggleUrgent {
ToggleWindowUrgent {
/// Id of the window to toggle urgent.
#[cfg_attr(feature = "clap", arg(long))]
id: u64,
},
/// Set urgent status of a window.
SetUrgent {
SetWindowUrgent {
/// Id of the window to set urgent.
#[cfg_attr(feature = "clap", arg(long))]
id: u64,
},
/// Unset urgent status of a window.
UnsetUrgent {
UnsetWindowUrgent {
/// Id of the window to unset urgent.
#[cfg_attr(feature = "clap", arg(long))]
id: u64,
+2 -2
View File
@@ -11,8 +11,8 @@ repository.workspace = true
adw = { version = "0.7.2", package = "libadwaita", features = ["v1_4"] }
anyhow.workspace = true
gtk = { version = "0.9.6", package = "gtk4", features = ["v4_12"] }
niri = { version = "25.5.0", path = ".." }
niri-config = { version = "25.5.0", path = "../niri-config" }
niri = { version = "25.5.1", path = ".." }
niri-config = { version = "25.5.1", path = "../niri-config" }
smithay.workspace = true
tracing.workspace = true
tracing-subscriber.workspace = true
+17 -1
View File
@@ -174,8 +174,24 @@ impl State {
self.niri.layer_shell_on_demand_focus = Some(layer.clone());
}
} else {
self.niri.mapped_layer_surfaces.remove(layer);
let was_mapped = self.niri.mapped_layer_surfaces.remove(layer).is_some();
self.niri.unmapped_layer_surfaces.insert(surface.clone());
// After layer surface unmaps it has to perform the initial commit-configure
// sequence again. This is a workaround until Smithay properly resets
// initial_configure_sent upon the surface unmapping itself as it does for
// toplevels.
if was_mapped {
with_states(surface, |states| {
let mut data = states
.data_map
.get::<LayerSurfaceData>()
.unwrap()
.lock()
.unwrap();
data.initial_configure_sent = false;
});
}
}
} else {
let scale = output.current_scale();
+6 -4
View File
@@ -334,9 +334,10 @@ impl XdgShellHandler for State {
// higher input priority.
if layers.layers_on(Layer::Overlay).any(|l| {
l.cached_state().keyboard_interactivity
(l.cached_state().keyboard_interactivity
== wlr_layer::KeyboardInteractivity::Exclusive
|| Some(l) == self.niri.layer_shell_on_demand_focus.as_ref()
|| Some(l) == self.niri.layer_shell_on_demand_focus.as_ref())
&& self.niri.mapped_layer_surfaces.contains_key(l)
}) {
trace!("ignoring toplevel popup grab because the overlay layer has focus");
let _ = PopupManager::dismiss_popup(&root, &popup);
@@ -346,9 +347,10 @@ impl XdgShellHandler for State {
let mon = self.niri.layout.monitor_for_output(output).unwrap();
if !mon.render_above_top_layer()
&& layers.layers_on(Layer::Top).any(|l| {
l.cached_state().keyboard_interactivity
(l.cached_state().keyboard_interactivity
== wlr_layer::KeyboardInteractivity::Exclusive
|| Some(l) == self.niri.layer_shell_on_demand_focus.as_ref()
|| Some(l) == self.niri.layer_shell_on_demand_focus.as_ref())
&& self.niri.mapped_layer_surfaces.contains_key(l)
})
{
trace!("ignoring toplevel popup grab because the top layer has focus");
+17 -4
View File
@@ -472,6 +472,12 @@ impl State {
}
fn hide_cursor_if_needed(&mut self) {
// If the pointer is already invisible, don't reset it back to Hidden causing one frame
// of hover.
if !self.niri.pointer_visibility.is_visible() {
return;
}
if !self.niri.config.borrow().cursor.hide_when_typing {
return;
}
@@ -1976,7 +1982,7 @@ impl State {
self.niri.queue_redraw_all();
}
}
Action::ToggleUrgent(id) => {
Action::ToggleWindowUrgent(id) => {
let window = self
.niri
.layout
@@ -1986,8 +1992,9 @@ impl State {
let urgent = window.is_urgent();
window.set_urgent(!urgent);
}
self.niri.queue_redraw_all();
}
Action::SetUrgent(id) => {
Action::SetWindowUrgent(id) => {
let window = self
.niri
.layout
@@ -1996,8 +2003,9 @@ impl State {
if let Some(window) = window {
window.set_urgent(true);
}
self.niri.queue_redraw_all();
}
Action::UnsetUrgent(id) => {
Action::UnsetWindowUrgent(id) => {
let window = self
.niri
.layout
@@ -2006,6 +2014,7 @@ impl State {
if let Some(window) = window {
window.set_urgent(false);
}
self.niri.queue_redraw_all();
}
}
}
@@ -3598,7 +3607,11 @@ impl State {
let mods = modifiers_from_state(mods);
let mod_down = mods.contains(mod_key.to_modifiers());
if self.niri.layout.is_overview_open() && !mod_down && under.layer.is_none() {
if self.niri.layout.is_overview_open()
&& !mod_down
&& under.layer.is_none()
&& under.output.is_some()
{
let (output, pos_within_output) = self.niri.output_under(pos).unwrap();
let output = output.clone();
+33 -5
View File
@@ -740,7 +740,21 @@ impl State {
}
pub fn move_cursor(&mut self, location: Point<f64, Logical>) {
let under = self.niri.contents_under(location);
let mut under = match self.niri.pointer_visibility {
PointerVisibility::Disabled => PointContents::default(),
_ => self.niri.contents_under(location),
};
// Disable the hidden pointer if the contents underneath have changed.
if !self.niri.pointer_visibility.is_visible() && self.niri.pointer_contents != under {
self.niri.pointer_visibility = PointerVisibility::Disabled;
// When setting PointerVisibility::Hidden together with pointer contents changing,
// we can change straight to nothing to avoid one frame of hover. Notably, this can
// be triggered through warp-mouse-to-focus combined with hide-when-typing.
under = PointContents::default();
}
self.niri.pointer_contents.clone_from(&under);
let pointer = &self.niri.seat.get_pointer().unwrap();
@@ -929,7 +943,7 @@ impl State {
let pointer = &self.niri.seat.get_pointer().unwrap();
let location = pointer.current_location();
let under = match self.niri.pointer_visibility {
let mut under = match self.niri.pointer_visibility {
PointerVisibility::Disabled => PointContents::default(),
_ => self.niri.contents_under(location),
};
@@ -943,6 +957,14 @@ impl State {
// Disable the hidden pointer if the contents underneath have changed.
if !self.niri.pointer_visibility.is_visible() {
self.niri.pointer_visibility = PointerVisibility::Disabled;
// When setting PointerVisibility::Hidden together with pointer contents changing,
// we can change straight to nothing to avoid one frame of hover. Notably, this can
// be triggered through warp-mouse-to-focus combined with hide-when-typing.
under = PointContents::default();
if self.niri.pointer_contents == under {
return false;
}
}
self.niri.pointer_contents.clone_from(&under);
@@ -996,12 +1018,13 @@ impl State {
&& surface.cached_state().keyboard_interactivity
== wlr_layer::KeyboardInteractivity::OnDemand;
// Check if it moved to the overview backdrop.
if let Some(mapped) = self.niri.mapped_layer_surfaces.get(surface) {
// Check if it moved to the overview backdrop.
if mapped.place_within_backdrop() {
good = false;
}
} else {
// The layer surface is alive but it got unmapped.
good = false;
}
@@ -5985,8 +6008,13 @@ impl Niri {
.event_loop
.insert_source(timer, move |_, _, state| {
state.niri.pointer_inactivity_timer = None;
state.niri.pointer_visibility = PointerVisibility::Hidden;
state.niri.queue_redraw_all();
// If the pointer is already invisible, don't reset it back to Hidden causing one
// frame of hover.
if state.niri.pointer_visibility.is_visible() {
state.niri.pointer_visibility = PointerVisibility::Hidden;
state.niri.queue_redraw_all();
}
TimeoutAction::Drop
})
-2
View File
@@ -175,8 +175,6 @@ Set the `numlock` flag to turn on Num Lock automatically at startup.
You might want to disable (comment out) `numlock` if you're using a laptop with a keyboard that overlays Num Lock keys on top of regular keys.
Note that there's a [known issue](https://github.com/YaLTeR/niri/issues/1501) with this setting: Num Lock only turns on after you press some modifier key (Super, Alt, etc.).
```kdl
input {
keyboard {
+16
View File
@@ -28,6 +28,22 @@ To do that, put files into the correct directories according to this table.
Doing this will make niri appear in GDM and other display managers.
### Running tests
A bulk of our tests spawn niri compositor instances and test Wayland clients.
This does not require a graphical session, however due to test parallelism, it can run into file descriptor limits on high core count systems.
If you run into this problem, you may need to limit not just the Rust test harness thread count, but also the Rayon thread count, since some niri tests use internal Rayon threading:
```
$ export RAYON_NUM_THREADS=2
...proceed to run cargo test, perhaps with --test-threads=2
```
Don't forget to exclude the development-only `niri-visual-tests` crate when running tests.
You may also want to set the `RUN_SLOW_TESTS=1` environment variable to run the slower tests.
### Version string
The niri version string includes its version and commit hash: