mirror of
https://github.com/YaLTeR/niri.git
synced 2024-10-26 11:48:09 +03:00
Add a config parse error notification
We can't rely on a notification daemon being available, especially during initial niri setup. So, render our own.
This commit is contained in:
parent
cc62a403c0
commit
fa9b3ed106
4
.github/workflows/ci.yml
vendored
4
.github/workflows/ci.yml
vendored
@ -35,7 +35,7 @@ jobs:
|
||||
sudo apt-get install -y software-properties-common
|
||||
sudo add-apt-repository -y ppa:pipewire-debian/pipewire-upstream
|
||||
sudo apt-get update -y
|
||||
sudo apt-get install -y libudev-dev libgbm-dev libxkbcommon-dev libegl1-mesa-dev libwayland-dev libinput-dev libdbus-1-dev libsystemd-dev libseat-dev libpipewire-0.3-dev
|
||||
sudo apt-get install -y libudev-dev libgbm-dev libxkbcommon-dev libegl1-mesa-dev libwayland-dev libinput-dev libdbus-1-dev libsystemd-dev libseat-dev libpipewire-0.3-dev libpango1.0-dev
|
||||
|
||||
- name: Install Rust
|
||||
run: |
|
||||
@ -78,7 +78,7 @@ jobs:
|
||||
sudo apt-get install -y software-properties-common
|
||||
sudo add-apt-repository -y ppa:pipewire-debian/pipewire-upstream
|
||||
sudo apt-get update -y
|
||||
sudo apt-get install -y libudev-dev libgbm-dev libxkbcommon-dev libegl1-mesa-dev libwayland-dev libinput-dev libdbus-1-dev libsystemd-dev libseat-dev libpipewire-0.3-dev
|
||||
sudo apt-get install -y libudev-dev libgbm-dev libxkbcommon-dev libegl1-mesa-dev libwayland-dev libinput-dev libdbus-1-dev libsystemd-dev libseat-dev libpipewire-0.3-dev libpango1.0-dev
|
||||
|
||||
- name: Install Rust
|
||||
run: |
|
||||
|
229
Cargo.lock
generated
229
Cargo.lock
generated
@ -468,6 +468,31 @@ version = "1.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a2bd12c1caf447e69cd4528f47f94d203fd2582878ecb9e9465484c4148a8223"
|
||||
|
||||
[[package]]
|
||||
name = "cairo-rs"
|
||||
version = "0.18.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8ca26ef0159422fb77631dc9d17b102f253b876fe1586b03b803e63a309b4ee2"
|
||||
dependencies = [
|
||||
"bitflags 2.4.1",
|
||||
"cairo-sys-rs",
|
||||
"glib",
|
||||
"libc",
|
||||
"once_cell",
|
||||
"thiserror",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cairo-sys-rs"
|
||||
version = "0.18.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "685c9fa8e590b8b3d678873528d83411db17242a73fccaed827770ea0fedda51"
|
||||
dependencies = [
|
||||
"glib-sys",
|
||||
"libc",
|
||||
"system-deps",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "calloop"
|
||||
version = "0.12.3"
|
||||
@ -1025,12 +1050,32 @@ dependencies = [
|
||||
"percent-encoding",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "futures-channel"
|
||||
version = "0.3.30"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "eac8f7d7865dcb88bd4373ab671c8cf4508703796caa2b1985a9ca867b3fcb78"
|
||||
dependencies = [
|
||||
"futures-core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "futures-core"
|
||||
version = "0.3.30"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dfc6580bb841c5a68e9ef15c77ccc837b40a7504914d52e47b8b0e9bbda25a1d"
|
||||
|
||||
[[package]]
|
||||
name = "futures-executor"
|
||||
version = "0.3.30"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a576fc72ae164fca6b9db127eaa9a9dda0d61316034f33a0a0d4eda41f02b01d"
|
||||
dependencies = [
|
||||
"futures-core",
|
||||
"futures-task",
|
||||
"futures-util",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "futures-io"
|
||||
version = "0.3.30"
|
||||
@ -1065,6 +1110,17 @@ dependencies = [
|
||||
"pin-project-lite",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "futures-macro"
|
||||
version = "0.3.30"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "87750cf4b7a4c0625b1529e4c543c2182106e4dedc60a2a6455e00d212c489ac"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.48",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "futures-sink"
|
||||
version = "0.3.30"
|
||||
@ -1085,6 +1141,7 @@ checksum = "3d6401deb83407ab3da39eba7e33987a73c3df0c82b4bb5813ee871c19c41d48"
|
||||
dependencies = [
|
||||
"futures-core",
|
||||
"futures-io",
|
||||
"futures-macro",
|
||||
"futures-sink",
|
||||
"futures-task",
|
||||
"memchr",
|
||||
@ -1161,6 +1218,38 @@ dependencies = [
|
||||
"wasi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "gio"
|
||||
version = "0.18.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d4fc8f532f87b79cbc51a79748f16a6828fb784be93145a322fa14d06d354c73"
|
||||
dependencies = [
|
||||
"futures-channel",
|
||||
"futures-core",
|
||||
"futures-io",
|
||||
"futures-util",
|
||||
"gio-sys",
|
||||
"glib",
|
||||
"libc",
|
||||
"once_cell",
|
||||
"pin-project-lite",
|
||||
"smallvec",
|
||||
"thiserror",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "gio-sys"
|
||||
version = "0.18.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "37566df850baf5e4cb0dfb78af2e4b9898d817ed9263d1090a2df958c64737d2"
|
||||
dependencies = [
|
||||
"glib-sys",
|
||||
"gobject-sys",
|
||||
"libc",
|
||||
"system-deps",
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "git-version"
|
||||
version = "0.3.9"
|
||||
@ -1192,12 +1281,70 @@ dependencies = [
|
||||
"xml-rs",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "glib"
|
||||
version = "0.18.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "233daaf6e83ae6a12a52055f568f9d7cf4671dabb78ff9560ab6da230ce00ee5"
|
||||
dependencies = [
|
||||
"bitflags 2.4.1",
|
||||
"futures-channel",
|
||||
"futures-core",
|
||||
"futures-executor",
|
||||
"futures-task",
|
||||
"futures-util",
|
||||
"gio-sys",
|
||||
"glib-macros",
|
||||
"glib-sys",
|
||||
"gobject-sys",
|
||||
"libc",
|
||||
"memchr",
|
||||
"once_cell",
|
||||
"smallvec",
|
||||
"thiserror",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "glib-macros"
|
||||
version = "0.18.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0bb0228f477c0900c880fd78c8759b95c7636dbd7842707f49e132378aa2acdc"
|
||||
dependencies = [
|
||||
"heck",
|
||||
"proc-macro-crate 2.0.1",
|
||||
"proc-macro-error",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.48",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "glib-sys"
|
||||
version = "0.18.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "063ce2eb6a8d0ea93d2bf8ba1957e78dbab6be1c2220dd3daca57d5a9d869898"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"system-deps",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "glob"
|
||||
version = "0.3.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b"
|
||||
|
||||
[[package]]
|
||||
name = "gobject-sys"
|
||||
version = "0.18.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0850127b514d1c4a4654ead6dedadb18198999985908e6ffe4436f53c785ce44"
|
||||
dependencies = [
|
||||
"glib-sys",
|
||||
"libc",
|
||||
"system-deps",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "hashbrown"
|
||||
version = "0.14.3"
|
||||
@ -1720,6 +1867,7 @@ dependencies = [
|
||||
"niri-config",
|
||||
"niri-ipc",
|
||||
"notify-rust",
|
||||
"pangocairo",
|
||||
"pipewire",
|
||||
"png",
|
||||
"portable-atomic",
|
||||
@ -1829,7 +1977,7 @@ version = "0.7.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "681030a937600a36906c185595136d26abfebb4aa9c65701cefcaf8578bb982b"
|
||||
dependencies = [
|
||||
"proc-macro-crate",
|
||||
"proc-macro-crate 2.0.1",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.48",
|
||||
@ -1923,6 +2071,57 @@ version = "0.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b15813163c1d831bf4a13c3610c05c0d03b39feb07f7e09fa234dac9b15aaf39"
|
||||
|
||||
[[package]]
|
||||
name = "pango"
|
||||
version = "0.18.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7ca27ec1eb0457ab26f3036ea52229edbdb74dee1edd29063f5b9b010e7ebee4"
|
||||
dependencies = [
|
||||
"gio",
|
||||
"glib",
|
||||
"libc",
|
||||
"once_cell",
|
||||
"pango-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pango-sys"
|
||||
version = "0.18.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "436737e391a843e5933d6d9aa102cb126d501e815b83601365a948a518555dc5"
|
||||
dependencies = [
|
||||
"glib-sys",
|
||||
"gobject-sys",
|
||||
"libc",
|
||||
"system-deps",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pangocairo"
|
||||
version = "0.18.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "57036589a9cfcacf83f9e606d15813fc6bf03f0e9e69aa2b5e3bb85af86b38a5"
|
||||
dependencies = [
|
||||
"cairo-rs",
|
||||
"glib",
|
||||
"libc",
|
||||
"pango",
|
||||
"pangocairo-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pangocairo-sys"
|
||||
version = "0.18.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fc3c8ff676a37e7a72ec1d5fc029f91c407278083d2752784ff9f5188c108833"
|
||||
dependencies = [
|
||||
"cairo-sys-rs",
|
||||
"glib-sys",
|
||||
"libc",
|
||||
"pango-sys",
|
||||
"system-deps",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "parking"
|
||||
version = "2.2.0"
|
||||
@ -2069,6 +2268,16 @@ dependencies = [
|
||||
"toml_edit 0.19.15",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro-crate"
|
||||
version = "2.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "97dc5fea232fc28d2f597b37c4876b348a40e33f3b02cc975c8d006d78d94b1a"
|
||||
dependencies = [
|
||||
"toml_datetime",
|
||||
"toml_edit 0.20.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro-error"
|
||||
version = "1.0.4"
|
||||
@ -2726,21 +2935,21 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20"
|
||||
|
||||
[[package]]
|
||||
name = "toml"
|
||||
version = "0.8.8"
|
||||
version = "0.8.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a1a195ec8c9da26928f773888e0742ca3ca1040c6cd859c919c9f59c1954ab35"
|
||||
checksum = "185d8ab0dfbb35cf1399a6344d8484209c088f75f8f68230da55d48d95d43e3d"
|
||||
dependencies = [
|
||||
"serde",
|
||||
"serde_spanned",
|
||||
"toml_datetime",
|
||||
"toml_edit 0.21.0",
|
||||
"toml_edit 0.20.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "toml_datetime"
|
||||
version = "0.6.5"
|
||||
version = "0.6.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3550f4e9685620ac18a50ed434eb3aec30db8ba93b0287467bca5826ea25baf1"
|
||||
checksum = "7cda73e2f1397b1262d6dfdcef8aafae14d1de7748d66822d3bfeeb6d03e5e4b"
|
||||
dependencies = [
|
||||
"serde",
|
||||
]
|
||||
@ -2758,9 +2967,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "toml_edit"
|
||||
version = "0.21.0"
|
||||
version = "0.20.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d34d383cd00a163b4a5b85053df514d45bc330f6de7737edfe0a93311d1eaa03"
|
||||
checksum = "396e4d48bbb2b7554c944bde63101b5ae446cff6ec4a24227428f15eb72ef338"
|
||||
dependencies = [
|
||||
"indexmap",
|
||||
"serde",
|
||||
@ -3675,7 +3884,7 @@ version = "3.14.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "41d1794a946878c0e807f55a397187c11fc7a038ba5d868e7db4f3bd7760bc9d"
|
||||
dependencies = [
|
||||
"proc-macro-crate",
|
||||
"proc-macro-crate 1.3.1",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"regex",
|
||||
@ -3734,7 +3943,7 @@ version = "3.15.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "934d7a7dfc310d6ee06c87ffe88ef4eca7d3e37bb251dece2ef93da8f17d8ecd"
|
||||
dependencies = [
|
||||
"proc-macro-crate",
|
||||
"proc-macro-crate 1.3.1",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 1.0.109",
|
||||
|
@ -52,6 +52,7 @@ logind-zbus = { version = "3.1.2", optional = true }
|
||||
niri-config = { version = "0.1.0-alpha.3", path = "niri-config" }
|
||||
niri-ipc = { version = "0.1.0-alpha.3", path = "niri-ipc" }
|
||||
notify-rust = { version = "4.10.0", optional = true }
|
||||
pangocairo = "0.18.0"
|
||||
pipewire = { version = "0.7.2", optional = true }
|
||||
png = "0.17.10"
|
||||
portable-atomic = { version = "1.6.0", default-features = false, features = ["float"] }
|
||||
|
@ -62,13 +62,13 @@ First, install the dependencies for your distribution.
|
||||
sudo apt-get install -y software-properties-common
|
||||
sudo add-apt-repository -y ppa:pipewire-debian/pipewire-upstream
|
||||
sudo apt-get update -y
|
||||
sudo apt-get install -y libudev-dev libgbm-dev libxkbcommon-dev libegl1-mesa-dev libwayland-dev libinput-dev libdbus-1-dev libsystemd-dev libseat-dev libpipewire-0.3-dev
|
||||
sudo apt-get install -y libudev-dev libgbm-dev libxkbcommon-dev libegl1-mesa-dev libwayland-dev libinput-dev libdbus-1-dev libsystemd-dev libseat-dev libpipewire-0.3-dev libpango1.0-dev
|
||||
```
|
||||
|
||||
- Fedora:
|
||||
|
||||
```sh
|
||||
sudo dnf install gcc libudev-devel libgbm-devel libxkbcommon-devel wayland-devel libinput-devel dbus-devel systemd-devel libseat-devel pipewire-devel clang
|
||||
sudo dnf install gcc libudev-devel libgbm-devel libxkbcommon-devel wayland-devel libinput-devel dbus-devel systemd-devel libseat-devel pipewire-devel pango-devel clang
|
||||
```
|
||||
|
||||
Next, build niri with `cargo build --release`.
|
||||
|
@ -67,6 +67,7 @@
|
||||
fontconfig
|
||||
stdenv.cc.cc.lib
|
||||
pipewire
|
||||
pango
|
||||
];
|
||||
|
||||
runtimeDependencies = with pkgs; [
|
||||
|
197
src/config_error_notification.rs
Normal file
197
src/config_error_notification.rs
Normal file
@ -0,0 +1,197 @@
|
||||
use std::cell::RefCell;
|
||||
use std::collections::HashMap;
|
||||
use std::time::Duration;
|
||||
|
||||
use pangocairo::cairo::{self, ImageSurface};
|
||||
use pangocairo::pango::FontDescription;
|
||||
use smithay::backend::renderer::element::memory::{
|
||||
MemoryRenderBuffer, MemoryRenderBufferRenderElement,
|
||||
};
|
||||
use smithay::backend::renderer::element::utils::{Relocate, RelocateRenderElement};
|
||||
use smithay::backend::renderer::element::{Element, Kind};
|
||||
use smithay::output::Output;
|
||||
use smithay::reexports::gbm::Format as Fourcc;
|
||||
use smithay::utils::Transform;
|
||||
|
||||
use crate::animation::Animation;
|
||||
use crate::render_helpers::NiriRenderer;
|
||||
|
||||
const TEXT: &str = "Failed to parse the config file. \
|
||||
Please run <span face='monospace' bgcolor='#000000'>niri validate</span> \
|
||||
to see the errors.";
|
||||
const PADDING: i32 = 8;
|
||||
const FONT: &str = "sans 14px";
|
||||
const BORDER: i32 = 4;
|
||||
|
||||
pub struct ConfigErrorNotification {
|
||||
state: State,
|
||||
buffers: RefCell<HashMap<i32, Option<MemoryRenderBuffer>>>,
|
||||
}
|
||||
|
||||
enum State {
|
||||
Hidden,
|
||||
Showing(Animation),
|
||||
Shown(Duration),
|
||||
Hiding(Animation),
|
||||
}
|
||||
|
||||
pub type ConfigErrorNotificationRenderElement<R> =
|
||||
RelocateRenderElement<MemoryRenderBufferRenderElement<R>>;
|
||||
|
||||
impl ConfigErrorNotification {
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
state: State::Hidden,
|
||||
buffers: RefCell::new(HashMap::new()),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn show(&mut self) {
|
||||
// Show from scratch even if already showing to bring attention.
|
||||
self.state = State::Showing(Animation::new(0., 1., Duration::from_millis(250)));
|
||||
}
|
||||
|
||||
pub fn hide(&mut self) {
|
||||
if matches!(self.state, State::Hidden) {
|
||||
return;
|
||||
}
|
||||
|
||||
self.state = State::Hiding(Animation::new(1., 0., Duration::from_millis(250)));
|
||||
}
|
||||
|
||||
pub fn advance_animations(&mut self, target_presentation_time: Duration) {
|
||||
match &mut self.state {
|
||||
State::Hidden => (),
|
||||
State::Showing(anim) => {
|
||||
anim.set_current_time(target_presentation_time);
|
||||
if anim.is_done() {
|
||||
self.state = State::Shown(target_presentation_time + Duration::from_secs(4));
|
||||
}
|
||||
}
|
||||
State::Shown(deadline) => {
|
||||
if target_presentation_time >= *deadline {
|
||||
self.hide();
|
||||
}
|
||||
}
|
||||
State::Hiding(anim) => {
|
||||
anim.set_current_time(target_presentation_time);
|
||||
if anim.is_done() {
|
||||
self.state = State::Hidden;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn are_animations_ongoing(&self) -> bool {
|
||||
!matches!(self.state, State::Hidden)
|
||||
}
|
||||
|
||||
pub fn render<R: NiriRenderer>(
|
||||
&self,
|
||||
renderer: &mut R,
|
||||
output: &Output,
|
||||
) -> Option<ConfigErrorNotificationRenderElement<R>> {
|
||||
if matches!(self.state, State::Hidden) {
|
||||
return None;
|
||||
}
|
||||
|
||||
let scale = output.current_scale().integer_scale();
|
||||
|
||||
let mut buffers = self.buffers.borrow_mut();
|
||||
let buffer = buffers
|
||||
.entry(scale)
|
||||
.or_insert_with_key(move |&scale| render(scale).ok());
|
||||
let buffer = buffer.as_ref()?;
|
||||
|
||||
let elem = MemoryRenderBufferRenderElement::from_buffer(
|
||||
renderer,
|
||||
(0., 0.),
|
||||
buffer,
|
||||
Some(0.9),
|
||||
None,
|
||||
None,
|
||||
Kind::Unspecified,
|
||||
)
|
||||
.ok()?;
|
||||
|
||||
let output_transform = output.current_transform();
|
||||
let output_mode = output.current_mode().unwrap();
|
||||
let output_size = output_transform.transform_size(output_mode.size);
|
||||
|
||||
let buffer_size = elem
|
||||
.geometry(output.current_scale().fractional_scale().into())
|
||||
.size;
|
||||
|
||||
let y_range = buffer_size.h + PADDING * 2 * scale;
|
||||
|
||||
let x = (output_size.w / 2 - buffer_size.w / 2).max(0);
|
||||
let y = match &self.state {
|
||||
State::Hidden => unreachable!(),
|
||||
State::Showing(anim) | State::Hiding(anim) => {
|
||||
(-buffer_size.h as f64 + anim.value() * y_range as f64).round() as i32
|
||||
}
|
||||
State::Shown(_) => PADDING * 2 * scale,
|
||||
};
|
||||
let elem = RelocateRenderElement::from_element(elem, (x, y), Relocate::Absolute);
|
||||
|
||||
Some(elem)
|
||||
}
|
||||
}
|
||||
|
||||
fn render(scale: i32) -> anyhow::Result<MemoryRenderBuffer> {
|
||||
let _span = tracy_client::span!("config_error_notification::render");
|
||||
|
||||
let padding = PADDING * scale;
|
||||
|
||||
let mut font = FontDescription::from_string(FONT);
|
||||
font.set_absolute_size((font.size() * scale).into());
|
||||
|
||||
let surface = ImageSurface::create(cairo::Format::ARgb32, 0, 0)?;
|
||||
let cr = cairo::Context::new(&surface)?;
|
||||
let layout = pangocairo::create_layout(&cr);
|
||||
layout.set_font_description(Some(&font));
|
||||
layout.set_markup(TEXT);
|
||||
|
||||
let (mut width, mut height) = layout.pixel_size();
|
||||
width += padding * 2;
|
||||
height += padding * 2;
|
||||
|
||||
// FIXME: fix bug in Smithay that rounds pixel sizes down to scale.
|
||||
width = (width + scale - 1) / scale * scale;
|
||||
height = (height + scale - 1) / scale * scale;
|
||||
|
||||
let surface = ImageSurface::create(cairo::Format::ARgb32, width, height)?;
|
||||
let cr = cairo::Context::new(&surface)?;
|
||||
cr.set_source_rgb(0.1, 0.1, 0.1);
|
||||
cr.paint()?;
|
||||
|
||||
cr.move_to(padding.into(), padding.into());
|
||||
let layout = pangocairo::create_layout(&cr);
|
||||
layout.set_font_description(Some(&font));
|
||||
layout.set_markup(TEXT);
|
||||
|
||||
cr.set_source_rgb(1., 1., 1.);
|
||||
pangocairo::show_layout(&cr, &layout);
|
||||
|
||||
cr.move_to(0., 0.);
|
||||
cr.line_to(width.into(), 0.);
|
||||
cr.line_to(width.into(), height.into());
|
||||
cr.line_to(0., height.into());
|
||||
cr.line_to(0., 0.);
|
||||
cr.set_source_rgb(1., 0.3, 0.3);
|
||||
cr.set_line_width((BORDER * scale).into());
|
||||
cr.stroke()?;
|
||||
drop(cr);
|
||||
|
||||
let data = surface.take_data().unwrap();
|
||||
let buffer = MemoryRenderBuffer::from_memory(
|
||||
&data,
|
||||
Fourcc::Argb8888,
|
||||
(width, height),
|
||||
scale,
|
||||
Transform::Normal,
|
||||
None,
|
||||
);
|
||||
|
||||
Ok(buffer)
|
||||
}
|
@ -3,6 +3,7 @@ extern crate tracing;
|
||||
|
||||
mod animation;
|
||||
mod backend;
|
||||
mod config_error_notification;
|
||||
mod cursor;
|
||||
#[cfg(feature = "dbus")]
|
||||
mod dbus;
|
||||
@ -157,12 +158,14 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||
// Load the config.
|
||||
let path = cli.config.or_else(default_config_path);
|
||||
|
||||
let mut config_errored = false;
|
||||
let mut config = path
|
||||
.as_deref()
|
||||
.and_then(|path| match Config::load(path) {
|
||||
Ok(config) => Some(config),
|
||||
Err(err) => {
|
||||
warn!("{err:?}");
|
||||
config_errored = true;
|
||||
None
|
||||
}
|
||||
})
|
||||
@ -239,6 +242,11 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||
spawn(elem.command);
|
||||
}
|
||||
|
||||
// Show the config error notification right away if needed.
|
||||
if config_errored {
|
||||
state.niri.config_error_notification.show();
|
||||
}
|
||||
|
||||
// Run the compositor.
|
||||
event_loop
|
||||
.run(None, &mut state, |state| state.refresh_and_flush_clients())
|
||||
|
40
src/niri.rs
40
src/niri.rs
@ -90,6 +90,9 @@ use smithay::wayland::virtual_keyboard::VirtualKeyboardManagerState;
|
||||
use crate::animation;
|
||||
use crate::backend::tty::{SurfaceDmabufFeedback, TtyFrame, TtyRenderer, TtyRendererError};
|
||||
use crate::backend::{Backend, RenderResult, Tty, Winit};
|
||||
use crate::config_error_notification::{
|
||||
ConfigErrorNotification, ConfigErrorNotificationRenderElement,
|
||||
};
|
||||
use crate::cursor::{CursorManager, CursorTextureCache, RenderCursor, XCursor};
|
||||
#[cfg(feature = "dbus")]
|
||||
use crate::dbus::gnome_shell_screenshot::{NiriToScreenshot, ScreenshotToNiri};
|
||||
@ -185,6 +188,7 @@ pub struct Niri {
|
||||
pub lock_state: LockState,
|
||||
|
||||
pub screenshot_ui: ScreenshotUi,
|
||||
pub config_error_notification: ConfigErrorNotification,
|
||||
|
||||
#[cfg(feature = "dbus")]
|
||||
pub dbus: Option<crate::dbus::DBusServers>,
|
||||
@ -540,10 +544,14 @@ impl State {
|
||||
Ok(config) => config,
|
||||
Err(err) => {
|
||||
warn!("{:?}", err.context("error loading config"));
|
||||
self.niri.config_error_notification.show();
|
||||
self.niri.queue_redraw_all();
|
||||
return;
|
||||
}
|
||||
};
|
||||
|
||||
self.niri.config_error_notification.hide();
|
||||
|
||||
self.niri.layout.update_config(&config);
|
||||
animation::ANIMATION_SLOWDOWN.store(config.debug.animation_slowdown, Ordering::Relaxed);
|
||||
|
||||
@ -850,6 +858,7 @@ impl Niri {
|
||||
});
|
||||
|
||||
let screenshot_ui = ScreenshotUi::new();
|
||||
let config_error_notification = ConfigErrorNotification::new();
|
||||
|
||||
let socket_source = ListeningSocketSource::new_auto().unwrap();
|
||||
let socket_name = socket_source.socket_name().to_os_string();
|
||||
@ -954,6 +963,7 @@ impl Niri {
|
||||
lock_state: LockState::Unlocked,
|
||||
|
||||
screenshot_ui,
|
||||
config_error_notification,
|
||||
|
||||
#[cfg(feature = "dbus")]
|
||||
dbus: None,
|
||||
@ -1788,6 +1798,11 @@ impl Niri {
|
||||
elements = self.pointer_element(renderer, output);
|
||||
}
|
||||
|
||||
// The config error notification too.
|
||||
if let Some(element) = self.config_error_notification.render(renderer, output) {
|
||||
elements.push(element.into());
|
||||
}
|
||||
|
||||
// If the session is locked, draw the lock surface.
|
||||
if self.is_locked() {
|
||||
let state = self.output_state.get(output).unwrap();
|
||||
@ -1915,6 +1930,11 @@ impl Niri {
|
||||
.unwrap()
|
||||
.are_animations_ongoing();
|
||||
|
||||
self.config_error_notification
|
||||
.advance_animations(target_presentation_time);
|
||||
state.unfinished_animations_remain |=
|
||||
self.config_error_notification.are_animations_ongoing();
|
||||
|
||||
// Also keep redrawing if the current cursor is animated.
|
||||
state.unfinished_animations_remain |= self
|
||||
.cursor_manager
|
||||
@ -2828,6 +2848,7 @@ pub enum OutputRenderElements<R: NiriRenderer> {
|
||||
NamedPointer(PrimaryGpuTextureRenderElement),
|
||||
SolidColor(SolidColorRenderElement),
|
||||
ScreenshotUi(ScreenshotUiRenderElement),
|
||||
ConfigErrorNotification(ConfigErrorNotificationRenderElement<R>),
|
||||
}
|
||||
|
||||
impl<R: NiriRenderer> Element for OutputRenderElements<R> {
|
||||
@ -2838,6 +2859,7 @@ impl<R: NiriRenderer> Element for OutputRenderElements<R> {
|
||||
Self::NamedPointer(elem) => elem.id(),
|
||||
Self::SolidColor(elem) => elem.id(),
|
||||
Self::ScreenshotUi(elem) => elem.id(),
|
||||
Self::ConfigErrorNotification(elem) => elem.id(),
|
||||
}
|
||||
}
|
||||
|
||||
@ -2848,6 +2870,7 @@ impl<R: NiriRenderer> Element for OutputRenderElements<R> {
|
||||
Self::NamedPointer(elem) => elem.current_commit(),
|
||||
Self::SolidColor(elem) => elem.current_commit(),
|
||||
Self::ScreenshotUi(elem) => elem.current_commit(),
|
||||
Self::ConfigErrorNotification(elem) => elem.current_commit(),
|
||||
}
|
||||
}
|
||||
|
||||
@ -2858,6 +2881,7 @@ impl<R: NiriRenderer> Element for OutputRenderElements<R> {
|
||||
Self::NamedPointer(elem) => elem.geometry(scale),
|
||||
Self::SolidColor(elem) => elem.geometry(scale),
|
||||
Self::ScreenshotUi(elem) => elem.geometry(scale),
|
||||
Self::ConfigErrorNotification(elem) => elem.geometry(scale),
|
||||
}
|
||||
}
|
||||
|
||||
@ -2868,6 +2892,7 @@ impl<R: NiriRenderer> Element for OutputRenderElements<R> {
|
||||
Self::NamedPointer(elem) => elem.transform(),
|
||||
Self::SolidColor(elem) => elem.transform(),
|
||||
Self::ScreenshotUi(elem) => elem.transform(),
|
||||
Self::ConfigErrorNotification(elem) => elem.transform(),
|
||||
}
|
||||
}
|
||||
|
||||
@ -2878,6 +2903,7 @@ impl<R: NiriRenderer> Element for OutputRenderElements<R> {
|
||||
Self::NamedPointer(elem) => elem.src(),
|
||||
Self::SolidColor(elem) => elem.src(),
|
||||
Self::ScreenshotUi(elem) => elem.src(),
|
||||
Self::ConfigErrorNotification(elem) => elem.src(),
|
||||
}
|
||||
}
|
||||
|
||||
@ -2892,6 +2918,7 @@ impl<R: NiriRenderer> Element for OutputRenderElements<R> {
|
||||
Self::NamedPointer(elem) => elem.damage_since(scale, commit),
|
||||
Self::SolidColor(elem) => elem.damage_since(scale, commit),
|
||||
Self::ScreenshotUi(elem) => elem.damage_since(scale, commit),
|
||||
Self::ConfigErrorNotification(elem) => elem.damage_since(scale, commit),
|
||||
}
|
||||
}
|
||||
|
||||
@ -2902,6 +2929,7 @@ impl<R: NiriRenderer> Element for OutputRenderElements<R> {
|
||||
Self::NamedPointer(elem) => elem.opaque_regions(scale),
|
||||
Self::SolidColor(elem) => elem.opaque_regions(scale),
|
||||
Self::ScreenshotUi(elem) => elem.opaque_regions(scale),
|
||||
Self::ConfigErrorNotification(elem) => elem.opaque_regions(scale),
|
||||
}
|
||||
}
|
||||
|
||||
@ -2912,6 +2940,7 @@ impl<R: NiriRenderer> Element for OutputRenderElements<R> {
|
||||
Self::NamedPointer(elem) => elem.alpha(),
|
||||
Self::SolidColor(elem) => elem.alpha(),
|
||||
Self::ScreenshotUi(elem) => elem.alpha(),
|
||||
Self::ConfigErrorNotification(elem) => elem.alpha(),
|
||||
}
|
||||
}
|
||||
|
||||
@ -2922,6 +2951,7 @@ impl<R: NiriRenderer> Element for OutputRenderElements<R> {
|
||||
Self::NamedPointer(elem) => elem.kind(),
|
||||
Self::SolidColor(elem) => elem.kind(),
|
||||
Self::ScreenshotUi(elem) => elem.kind(),
|
||||
Self::ConfigErrorNotification(elem) => elem.kind(),
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -2946,6 +2976,7 @@ impl RenderElement<GlesRenderer> for OutputRenderElements<GlesRenderer> {
|
||||
Self::ScreenshotUi(elem) => {
|
||||
RenderElement::<GlesRenderer>::draw(&elem, frame, src, dst, damage)
|
||||
}
|
||||
Self::ConfigErrorNotification(elem) => elem.draw(frame, src, dst, damage),
|
||||
}
|
||||
}
|
||||
|
||||
@ -2956,6 +2987,7 @@ impl RenderElement<GlesRenderer> for OutputRenderElements<GlesRenderer> {
|
||||
Self::NamedPointer(elem) => elem.underlying_storage(renderer),
|
||||
Self::SolidColor(elem) => elem.underlying_storage(renderer),
|
||||
Self::ScreenshotUi(elem) => elem.underlying_storage(renderer),
|
||||
Self::ConfigErrorNotification(elem) => elem.underlying_storage(renderer),
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -2982,6 +3014,7 @@ impl<'render, 'alloc> RenderElement<TtyRenderer<'render, 'alloc>>
|
||||
Self::ScreenshotUi(elem) => {
|
||||
RenderElement::<TtyRenderer<'render, 'alloc>>::draw(&elem, frame, src, dst, damage)
|
||||
}
|
||||
Self::ConfigErrorNotification(elem) => elem.draw(frame, src, dst, damage),
|
||||
}
|
||||
}
|
||||
|
||||
@ -2995,6 +3028,7 @@ impl<'render, 'alloc> RenderElement<TtyRenderer<'render, 'alloc>>
|
||||
Self::NamedPointer(elem) => elem.underlying_storage(renderer),
|
||||
Self::SolidColor(elem) => elem.underlying_storage(renderer),
|
||||
Self::ScreenshotUi(elem) => elem.underlying_storage(renderer),
|
||||
Self::ConfigErrorNotification(elem) => elem.underlying_storage(renderer),
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -3028,3 +3062,9 @@ impl<R: NiriRenderer> From<ScreenshotUiRenderElement> for OutputRenderElements<R
|
||||
Self::ScreenshotUi(x)
|
||||
}
|
||||
}
|
||||
|
||||
impl<R: NiriRenderer> From<ConfigErrorNotificationRenderElement<R>> for OutputRenderElements<R> {
|
||||
fn from(x: ConfigErrorNotificationRenderElement<R>) -> Self {
|
||||
Self::ConfigErrorNotification(x)
|
||||
}
|
||||
}
|
||||
|
@ -3,7 +3,9 @@ use smithay::backend::renderer::element::texture::TextureRenderElement;
|
||||
use smithay::backend::renderer::element::{Element, Id, Kind, RenderElement, UnderlyingStorage};
|
||||
use smithay::backend::renderer::gles::{GlesError, GlesFrame, GlesRenderer, GlesTexture};
|
||||
use smithay::backend::renderer::utils::CommitCounter;
|
||||
use smithay::backend::renderer::{Bind, ExportMem, ImportAll, Offscreen, Renderer, Texture};
|
||||
use smithay::backend::renderer::{
|
||||
Bind, ExportMem, ImportAll, ImportMem, Offscreen, Renderer, Texture,
|
||||
};
|
||||
use smithay::utils::{Buffer, Physical, Rectangle, Scale, Transform};
|
||||
|
||||
use crate::backend::tty::{TtyFrame, TtyRenderer, TtyRendererError};
|
||||
@ -11,6 +13,7 @@ use crate::backend::tty::{TtyFrame, TtyRenderer, TtyRendererError};
|
||||
/// Trait with our main renderer requirements to save on the typing.
|
||||
pub trait NiriRenderer:
|
||||
ImportAll
|
||||
+ ImportMem
|
||||
+ ExportMem
|
||||
+ Bind<Dmabuf>
|
||||
+ Offscreen<GlesTexture>
|
||||
@ -28,7 +31,7 @@ pub trait NiriRenderer:
|
||||
|
||||
impl<R> NiriRenderer for R
|
||||
where
|
||||
R: ImportAll + ExportMem + Bind<Dmabuf> + Offscreen<GlesTexture> + AsGlesRenderer,
|
||||
R: ImportAll + ImportMem + ExportMem + Bind<Dmabuf> + Offscreen<GlesTexture> + AsGlesRenderer,
|
||||
R::TextureId: Texture + Clone + 'static,
|
||||
R::Error: std::error::Error + Send + Sync + From<<GlesRenderer as Renderer>::Error> + 'static,
|
||||
{
|
||||
|
Loading…
Reference in New Issue
Block a user