diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index 63abe526..e6ca28bc 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -1,10 +1,8 @@ -Replace this text with a description of your changes, and why these changes are important. Read and acknowledge the list below. PRs without a completed checkbox will be closed. +- [ ] I have disclosed use of any AI generated code in my commit messages. + - If you are using an LLM, and do not fully understand the changes it is making to the code base, do not create a PR. + - In our experience, AI generated code often results in overly complex code that lacks enough context for a proper fix or feature inclusion. This results in considerably longer code reviews. Due to this, AI authored or partially authored PRs may be closed without comment. +- [ ] I understand these changes in full and will be able to respond to review comments. +- [ ] My change is accurately described in the commit message. +- [ ] My contribution is tested and working as described. +- [ ] I have read the [Developer Certificate of Origin](https://developercertificate.org/) and certify my contribution under its conditions. ---- - -- I have not included any LLM (also known as AI) generated content in this PR, including code, comments, and descriptions. -- I understand these changes in full and will be able to respond to review comments. -- My change is accurately described in the commit message. -- My contribution is tested and working as described. -- I have read the [Developer Certificate of Origin](https://developercertificate.org/) and certify my contribution under its conditions. -- [ ] I have read and followed all of the above requirements. For more information, see our [contributor guide](https://github.com/pop-os/pop/blob/master/CONTRIBUTING.md). diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index e9277414..bc455356 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -13,12 +13,18 @@ jobs: - name: Checkout sources uses: actions/checkout@v6 - name: Rust toolchain - uses: actions-rust-lang/setup-rust-toolchain@v1 + uses: dtolnay/rust-toolchain@stable with: components: rustfmt - rustflags: "" + - name: Cargo cache + uses: actions/cache@v5 + with: + path: | + ~/.cargo/registry + ~/.cargo/git + key: ${{ runner.os }}-cargo-${{ hashFiles('**/Cargo.toml') }} - name: Format - run: cargo fmt --all -- --check + run: cargo +stable fmt --all -- --check clippy-check: runs-on: ubuntu-latest @@ -26,14 +32,20 @@ jobs: - name: Checkout sources uses: actions/checkout@v6 - name: Rust toolchain - uses: actions-rust-lang/setup-rust-toolchain@v1 + uses: dtolnay/rust-toolchain@stable with: components: clippy - rustflags: "" + - name: Cargo cache + uses: actions/cache@v5 + with: + path: | + ~/.cargo/registry + ~/.cargo/git + key: ${{ runner.os }}-cargo-${{ hashFiles('**/Cargo.toml') }} - name: System dependencies run: sudo apt-get update; sudo apt-get install libudev-dev libgbm-dev libxkbcommon-dev libegl1-mesa-dev libwayland-dev libinput-dev libdbus-1-dev libsystemd-dev libseat-dev libdisplay-info-dev - name: Clippy - run: cargo clippy --all-features -- -D warnings + run: cargo +stable clippy --all-features -- -D warnings check-features: runs-on: ubuntu-latest @@ -41,15 +53,20 @@ jobs: - name: Checkout sources uses: actions/checkout@v6 - name: Rust toolchain - uses: actions-rust-lang/setup-rust-toolchain@v1 + uses: dtolnay/rust-toolchain@stable + - name: Cargo cache + uses: actions/cache@v5 with: - rustflags: "" + path: | + ~/.cargo/registry + ~/.cargo/git + key: ${{ runner.os }}-cargo-${{ hashFiles('**/Cargo.toml') }} - name: System dependencies run: sudo apt-get update; sudo apt-get install libudev-dev libgbm-dev libxkbcommon-dev libegl1-mesa-dev libwayland-dev libinput-dev libdbus-1-dev libsystemd-dev libseat-dev libdisplay-info-dev - - run: cargo check --no-default-features - - run: cargo check --features debug - - run: cargo check --features profile-with-tracy - - run: cargo check --features profile-with-tracy-gpu + - run: cargo +stable check --no-default-features + - run: cargo +stable check --features debug + - run: cargo +stable check --features profile-with-tracy + - run: cargo +stable check --features profile-with-tracy-gpu test: runs-on: ubuntu-latest @@ -57,11 +74,21 @@ jobs: - name: Checkout sources uses: actions/checkout@v6 - name: Rust toolchain - uses: actions-rust-lang/setup-rust-toolchain@v1 + uses: dtolnay/rust-toolchain@stable + - name: Cargo cache + uses: actions/cache@v5 with: - rustflags: "" + path: | + ~/.cargo/registry + ~/.cargo/git + key: ${{ runner.os }}-cargo-${{ hashFiles('**/Cargo.toml') }} - name: System dependencies run: sudo apt-get update; sudo apt-get install libudev-dev libgbm-dev libxkbcommon-dev libegl1-mesa-dev libwayland-dev libinput-dev libdbus-1-dev libsystemd-dev libdisplay-info-dev libpixman-1-dev meson ninja-build + - name: Build cache + uses: actions/cache@v5 + with: + path: target + key: ${{ runner.os }}-build-${{ hashFiles('**/Cargo.toml') }} - name: Build and install Libseat run: | wget https://git.sr.ht/~kennylevinsen/seatd/archive/0.9.1.tar.gz -O libseat-source.tar.gz diff --git a/.github/workflows/require-checklist.yml b/.github/workflows/require-checklist.yml deleted file mode 100644 index fd4ca8c6..00000000 --- a/.github/workflows/require-checklist.yml +++ /dev/null @@ -1,14 +0,0 @@ -# From https://github.com/mheap/require-checklist-action, license MIT -name: Require Checklist - -on: - pull_request: - types: [opened, edited, synchronize] - -jobs: - job1: - runs-on: ubuntu-latest - steps: - - uses: mheap/require-checklist-action@v2 - with: - requireChecklist: true diff --git a/Cargo.lock b/Cargo.lock index 715836fc..a53353a7 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -21,7 +21,7 @@ checksum = "366ffbaa4442f4684d91e2cd7c5ea7c4ed8add41959a31447066e279e432b618" [[package]] name = "accesskit" version = "0.22.0" -source = "git+https://github.com/wash2/accesskit?rev=6c20249#6c20249d3b9fd45e7002efad9f6b6171a9257912" +source = "git+https://github.com/wash2/accesskit?tag=cosmic-0.14#f0599eed5f18111228266fe3f28991cc48b5964f" dependencies = [ "uuid", ] @@ -29,7 +29,7 @@ dependencies = [ [[package]] name = "accesskit_consumer" version = "0.32.0" -source = "git+https://github.com/wash2/accesskit?rev=6c20249#6c20249d3b9fd45e7002efad9f6b6171a9257912" +source = "git+https://github.com/wash2/accesskit?tag=cosmic-0.14#f0599eed5f18111228266fe3f28991cc48b5964f" dependencies = [ "accesskit", "hashbrown 0.16.1", @@ -38,7 +38,7 @@ dependencies = [ [[package]] name = "accesskit_macos" version = "0.23.0" -source = "git+https://github.com/wash2/accesskit?rev=6c20249#6c20249d3b9fd45e7002efad9f6b6171a9257912" +source = "git+https://github.com/wash2/accesskit?tag=cosmic-0.14#f0599eed5f18111228266fe3f28991cc48b5964f" dependencies = [ "accesskit", "accesskit_consumer", @@ -51,7 +51,7 @@ dependencies = [ [[package]] name = "accesskit_windows" version = "0.30.0" -source = "git+https://github.com/wash2/accesskit?rev=6c20249#6c20249d3b9fd45e7002efad9f6b6171a9257912" +source = "git+https://github.com/wash2/accesskit?tag=cosmic-0.14#f0599eed5f18111228266fe3f28991cc48b5964f" dependencies = [ "accesskit", "accesskit_consumer", @@ -64,7 +64,7 @@ dependencies = [ [[package]] name = "accesskit_winit" version = "0.30.0" -source = "git+https://github.com/wash2/accesskit?rev=6c20249#6c20249d3b9fd45e7002efad9f6b6171a9257912" +source = "git+https://github.com/wash2/accesskit?tag=cosmic-0.14#f0599eed5f18111228266fe3f28991cc48b5964f" dependencies = [ "accesskit", "accesskit_macos", @@ -1012,7 +1012,7 @@ dependencies = [ [[package]] name = "cosmic-randr-shell" -version = "1.10.0" +version = "1.3.0" dependencies = [ "kdl", "slotmap", @@ -1021,7 +1021,7 @@ dependencies = [ [[package]] name = "cosmic-settings-config" -version = "1.10.0" +version = "0.1.0" dependencies = [ "cosmic-config", "ron 0.11.0", @@ -1040,7 +1040,7 @@ dependencies = [ [[package]] name = "cosmic-settings-daemon-config" -version = "1.10.0" +version = "0.1.0" dependencies = [ "cosmic-config", "cosmic-theme", @@ -1564,7 +1564,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb" dependencies = [ "libc", - "windows-sys 0.52.0", + "windows-sys 0.61.2", ] [[package]] @@ -1963,8 +1963,8 @@ dependencies = [ "libc", "log", "rustversion", - "windows-link 0.1.3", - "windows-result 0.3.4", + "windows-link 0.2.1", + "windows-result 0.4.1", ] [[package]] @@ -2329,7 +2329,7 @@ dependencies = [ "js-sys", "log", "wasm-bindgen", - "windows-core 0.61.2", + "windows-core 0.62.2", ] [[package]] @@ -2833,7 +2833,7 @@ dependencies = [ "portable-atomic", "portable-atomic-util", "serde_core", - "windows-sys 0.52.0", + "windows-sys 0.61.2", ] [[package]] @@ -3072,7 +3072,6 @@ dependencies = [ "log", "palette", "phf 0.13.1", - "roxmltree 0.20.0", "rust-embed", "serde", "slotmap", @@ -3136,9 +3135,9 @@ checksum = "b6d2cec3eae94f9f509c767b45932f1ada8350c4bdb85af2fcab4a3c14807981" [[package]] name = "libredox" -version = "0.1.25" +version = "0.1.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "61ff90caf6077a803a240f62fdbe88645a890bbca49ef8174c3cb0404362171d" +checksum = "8d8f1ea3f21fd3405dcaf6c9b5c1630af9afc422d9073ea39c5f6d6c772e08ed" dependencies = [ "bitflags 2.13.2", "libc", @@ -4811,7 +4810,7 @@ dependencies = [ "errno", "libc", "linux-raw-sys 0.4.15", - "windows-sys 0.52.0", + "windows-sys 0.59.0", ] [[package]] @@ -4824,7 +4823,7 @@ dependencies = [ "errno", "libc", "linux-raw-sys 0.12.1", - "windows-sys 0.52.0", + "windows-sys 0.61.2", ] [[package]] @@ -5433,7 +5432,7 @@ dependencies = [ "getrandom 0.4.1", "once_cell", "rustix 1.1.4", - "windows-sys 0.52.0", + "windows-sys 0.61.2", ] [[package]] @@ -6547,7 +6546,7 @@ version = "0.1.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c2a7b1c03c876122aa43f3020e6c3c3ee5c05081c9a00739faf7503aeba10d22" dependencies = [ - "windows-sys 0.52.0", + "windows-sys 0.61.2", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index 49cfb455..11001e83 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -65,7 +65,7 @@ tracing = { version = "0.1.44", features = [ "max_level_debug", "release_max_level_info", ] } -tracing-journald = { version = "0.3.2", optional = true } +tracing-journald = "0.3.2" tracing-subscriber = { version = "0.3.22", features = [ "env-filter", "tracing-log", @@ -125,7 +125,7 @@ optional = true debug = ["egui", "egui_plot", "smithay-egui", "anyhow/backtrace"] default = ["systemd"] logind = ["logind-zbus"] -systemd = ["libsystemd", "logind", "tracing-journald"] +systemd = ["libsystemd", "logind"] profile-with-tracy = ["profiling/profile-with-tracy", "tracy-client/default"] profile-with-tracy-gpu = ["profile-with-tracy", "smithay/tracy_gpu_profiling"] diff --git a/Makefile b/Makefile new file mode 100644 index 00000000..16f59ee6 --- /dev/null +++ b/Makefile @@ -0,0 +1,67 @@ +export prefix ?= /usr +sysconfdir ?= /etc +bindir = $(prefix)/bin +libdir = $(prefix)/lib +sharedir = $(prefix)/share + +BINARY = cosmic-comp +CARGO_TARGET_DIR ?= target +TARGET = debug +DEBUG ?= 0 + +.PHONY = all clean install uninstall vendor + +ifeq ($(DEBUG),0) + TARGET = release + ARGS += --release +endif + +VENDOR ?= 0 +ifneq ($(VENDOR),0) + ARGS += --offline --locked +endif + +TARGET_BIN="$(DESTDIR)$(bindir)/$(BINARY)" + +KEYBINDINGS_CONF="$(DESTDIR)$(sharedir)/cosmic/com.system76.CosmicSettings.Shortcuts/v1/defaults" +TILING_EXCEPTIONS_CONF="$(DESTDIR)$(sharedir)/cosmic/com.system76.CosmicSettings.WindowRules/v1/tiling_exception_defaults" + +all: extract-vendor + cargo build $(ARGS) + +clean: + cargo clean + +distclean: + rm -rf .cargo vendor vendor.tar target + +vendor: + mkdir -p .cargo + cargo vendor | head -n -1 > .cargo/config + echo 'directory = "vendor"' >> .cargo/config + [ -n "$(SOURCE_GIT_HASH)" ] && printf '\n[env]\nGIT_HASH = "%s"\n' "$(SOURCE_GIT_HASH)" >> .cargo/config || true + tar pcf vendor.tar vendor + rm -rf vendor + +extract-vendor: +ifeq ($(VENDOR),1) + rm -rf vendor; tar pxf vendor.tar +endif + +install: + install -Dm0755 "$(CARGO_TARGET_DIR)/$(TARGET)/$(BINARY)" "$(TARGET_BIN)" + install -Dm0644 "data/keybindings.ron" "$(KEYBINDINGS_CONF)" + install -Dm0644 "data/tiling-exceptions.ron" "$(TILING_EXCEPTIONS_CONF)" + +install-bare-session: install + install -Dm0644 "data/cosmic.desktop" "$(DESTDIR)$(sharedir)/wayland-sessions/cosmic.desktop" + install -Dm0644 "data/cosmic-session.target" "$(DESTDIR)$(libdir)/systemd/user/cosmic-session.target" + install -Dm0644 "data/cosmic-session-pre.target" "$(DESTDIR)$(libdir)/systemd/user/cosmic-session-pre.target" + install -Dm0644 "data/cosmic-comp.service" "$(DESTDIR)$(libdir)/systemd/user/cosmic-comp.service" + install -Dm0755 "data/cosmic-service" "$(DESTDIR)/$(bindir)/cosmic-service" + +uninstall: + rm "$(TARGET_BIN)" "$(KEYBINDINGS_CONF)" + +uninstall-bare-session: + rm "$(DESTDIR)$(sharedir)/wayland-sessions/cosmic.desktop" diff --git a/README.md b/README.md deleted file mode 100644 index 0465d1a9..00000000 --- a/README.md +++ /dev/null @@ -1,31 +0,0 @@ -# cosmic-comp -Compositor for the COSMIC desktop environment - -## Development - -This project uses [just](https://github.com/casey/just) as a command runner. - -### Available Commands - -#### Building -- `just build-debug` - Compile with debug profile -- `just build-release` - Compile with release profile (default) -- `just build-vendored` - Compile release profile with vendored dependencies - - Requires vendoring first, which can be done with `just vendor` - -#### Code Quality -- `just check` - Run clippy linter with pedantic warnings - -#### Installation -- `just install` - Install binary and configuration files -- `just install-bare-session` - Install with bare session files (wayland session, systemd units) -- `just uninstall` - Remove installed files -- `just uninstall-bare-session` - Remove installed files including bare session files - -#### Cleanup -- `just clean` - Run `cargo clean` -- `just clean-dist` - Run `cargo clean` and remove vendored dependencies - -#### Vendoring -- `just vendor` - Vendor dependencies locally and create vendor.tar -- `just vendor-extract` - Extract vendored dependencies from vendor.tar diff --git a/cargo.just b/cargo.just deleted file mode 100644 index c05f7fff..00000000 --- a/cargo.just +++ /dev/null @@ -1,53 +0,0 @@ -cargo-target-dir := env('CARGO_TARGET_DIR', 'target') - -# Compile with debug profile -build-debug *args: - cargo build {{ args }} - -# Compile with release profile -build-release *args: (build-debug '--release' args) - -# Compile with a vendored tarball -build-vendored *args: vendor-extract (build-release '--frozen --offline' args) - -# Check for errors and linter warnings -check *args: - cargo clippy --all-features {{ args }} -- -W clippy::pedantic - -# Remove Cargo build artifacts -[no-cd] -clean: - cargo clean - -# Also remove .cargo and vendored dependencies -[no-cd] -clean-dist: clean - rm -rf .cargo vendor vendor.tar - -# Vendor Cargo dependencies locally -[no-cd] -vendor: - #!/usr/bin/env sh - mkdir -p .cargo - cargo vendor --sync Cargo.toml | head -n -1 > .cargo/config.toml - echo 'directory = "vendor"' >> .cargo/config.toml - echo >> .cargo/config.toml - echo '[env]' >> .cargo/config.toml - if [ -n "${SOURCE_DATE_EPOCH}" ] - then - source_date="$(date -d "@${SOURCE_DATE_EPOCH}" "+%Y-%m-%d")" - echo "VERGEN_GIT_COMMIT_DATE = \"${source_date}\"" >> .cargo/config.toml - fi - if [ -n "${SOURCE_GIT_HASH}" ] - then - echo "GIT_HASH = \"${SOURCE_GIT_HASH}\"" >> .cargo/config.toml - fi - tar pcf vendor.tar .cargo vendor - rm -rf .cargo vendor - -# Extracts vendored dependencies -[no-cd] -[private] -vendor-extract: - rm -rf vendor - tar pxf vendor.tar diff --git a/cosmic-comp-config/src/lib.rs b/cosmic-comp-config/src/lib.rs index 193fd0db..510927f9 100644 --- a/cosmic-comp-config/src/lib.rs +++ b/cosmic-comp-config/src/lib.rs @@ -3,7 +3,6 @@ use cosmic_config::{CosmicConfigEntry, cosmic_config_derive::CosmicConfigEntry}; use serde::{Deserialize, Serialize}; use std::collections::HashMap; -use std::time::Duration; use crate::input::TouchpadOverride; @@ -107,8 +106,8 @@ pub struct CosmicCompConfig { pub edge_snap_threshold: u32, pub accessibility_zoom: ZoomConfig, pub appearance_settings: AppearanceConfig, - /// When the cursor hides itself: idle, fullscreen idle, typing, touch - pub cursor_hide: CursorHideConfig, + /// Hide the cursor after this many seconds of pointer inactivity (None disables) + pub cursor_hide_timeout: Option, /// Briefly magnify the cursor when the pointer is shaken, to help locate it pub cursor_shake_to_find: bool, pub activation_policy: ActivationPolicy, @@ -149,7 +148,7 @@ impl Default for CosmicCompConfig { edge_snap_threshold: 0, accessibility_zoom: ZoomConfig::default(), appearance_settings: AppearanceConfig::default(), - cursor_hide: CursorHideConfig::default(), + cursor_hide_timeout: None, cursor_shake_to_find: true, activation_policy: ActivationPolicy::default(), decoration_preference: DecorationPreference::default(), @@ -199,81 +198,6 @@ fn default_repeat_delay() -> u32 { 600 } -/// What the cursor idle timer should do when it fires. -#[derive(Debug, Clone, Copy, PartialEq, Eq)] -pub enum HideDecision { - /// Nothing applies in this context; drop the timer until the next activity. - Drop, - /// Hide the cursor now. - Hide, - /// Not yet — re-arm for this long. - RearmAfter(Duration), -} - -/// When the cursor hides itself. Every trigger is revealed by pointer input, so -/// these differ only in what arms the hide and after how long. -// `default`: a trigger added later must not make every existing file fail to -// deserialize, which `get_entry` would swallow as "reset everyone to defaults". -#[derive(Debug, Clone, Copy, PartialEq, Eq, Deserialize, Serialize)] -#[serde(default)] -pub struct CursorHideConfig { - /// Seconds of pointer inactivity before hiding, anywhere. `None` disables. - pub idle_timeout: Option, - /// Seconds of pointer inactivity before hiding over a fullscreen window. - /// Shortens `idle_timeout` in fullscreen; it never lengthens it. - pub fullscreen_idle_timeout: Option, - /// Hide as soon as a key is pressed. - pub while_typing: bool, - /// Hide on touch input, until the pointer next moves. - pub after_touch: bool, -} - -impl CursorHideConfig { - /// The shortest timeout that applies right now, if any. - pub fn effective_timeout(&self, fullscreen: bool) -> Option { - let secs = if fullscreen { - match (self.idle_timeout, self.fullscreen_idle_timeout) { - (Some(a), Some(b)) => Some(a.min(b)), - (a, b) => a.or(b), - } - } else { - self.idle_timeout - }?; - Some(Duration::from_secs(secs as u64)) - } - - /// What to do when the idle timer fires after `elapsed` without pointer input. - pub fn resolve(&self, elapsed: Duration, fullscreen: bool) -> HideDecision { - match self.effective_timeout(fullscreen) { - None => HideDecision::Drop, - Some(timeout) if elapsed >= timeout => HideDecision::Hide, - Some(timeout) => HideDecision::RearmAfter(timeout - elapsed), - } - } - - /// How long to wait before the idle timer should next fire, given how long - /// it has been since the last pointer event. Pessimistic: fullscreen only - /// ever shortens a timeout, so arming as if fullscreen cannot fire too - /// late, and `resolve` corrects an early fire once the context is known. - pub fn arm_delay(&self, since_pointer_activity: Duration) -> Option { - Some( - self.effective_timeout(true)? - .saturating_sub(since_pointer_activity), - ) - } -} - -impl Default for CursorHideConfig { - fn default() -> Self { - CursorHideConfig { - idle_timeout: None, - fullscreen_idle_timeout: Some(3), - while_typing: false, - after_touch: true, - } - } -} - #[derive(Debug, Clone, Copy, PartialEq, Eq, Deserialize, Serialize)] pub struct ZoomConfig { pub start_on_login: bool, @@ -339,109 +263,3 @@ pub enum XwaylandDescaling { #[default] Fractional, } - -#[cfg(test)] -mod test { - use super::{CursorHideConfig, HideDecision}; - use std::time::Duration; - - const OFF: CursorHideConfig = CursorHideConfig { - idle_timeout: None, - fullscreen_idle_timeout: None, - while_typing: false, - after_touch: false, - }; - - fn secs(n: u64) -> Duration { - Duration::from_secs(n) - } - - #[test] - fn no_timeout_never_hides() { - assert_eq!(OFF.resolve(secs(600), false), HideDecision::Drop); - assert_eq!(OFF.resolve(secs(600), true), HideDecision::Drop); - } - - #[test] - fn global_timeout_applies_everywhere() { - let cfg = CursorHideConfig { - idle_timeout: Some(10), - ..OFF - }; - assert_eq!( - cfg.resolve(secs(4), false), - HideDecision::RearmAfter(secs(6)) - ); - assert_eq!(cfg.resolve(secs(10), false), HideDecision::Hide); - // A fullscreen window must not suppress an enabled global timeout. - assert_eq!(cfg.resolve(secs(10), true), HideDecision::Hide); - } - - #[test] - fn fullscreen_timeout_only_applies_in_fullscreen() { - let cfg = CursorHideConfig { - fullscreen_idle_timeout: Some(3), - ..OFF - }; - assert_eq!(cfg.resolve(secs(3), true), HideDecision::Hide); - assert_eq!(cfg.resolve(secs(600), false), HideDecision::Drop); - } - - #[test] - fn fullscreen_shortens_but_never_lengthens() { - let short_fs = CursorHideConfig { - idle_timeout: Some(10), - fullscreen_idle_timeout: Some(3), - ..OFF - }; - assert_eq!(short_fs.resolve(secs(3), true), HideDecision::Hide); - assert_eq!( - short_fs.resolve(secs(3), false), - HideDecision::RearmAfter(secs(7)) - ); - - let long_fs = CursorHideConfig { - idle_timeout: Some(3), - fullscreen_idle_timeout: Some(30), - ..OFF - }; - assert_eq!(long_fs.resolve(secs(3), true), HideDecision::Hide); - } - - #[test] - fn boundary_is_inclusive() { - let cfg = CursorHideConfig { - idle_timeout: Some(5), - ..OFF - }; - assert_eq!( - cfg.resolve(Duration::from_millis(4999), false), - HideDecision::RearmAfter(Duration::from_millis(1)) - ); - assert_eq!(cfg.resolve(secs(5), false), HideDecision::Hide); - assert_eq!(cfg.resolve(secs(6), false), HideDecision::Hide); - } - - #[test] - fn arm_delay_measures_from_the_last_pointer_event() { - let cfg = CursorHideConfig { - idle_timeout: Some(10), - ..OFF - }; - assert_eq!(cfg.arm_delay(Duration::ZERO), Some(secs(10))); - assert_eq!(cfg.arm_delay(secs(4)), Some(secs(6))); - // Exactly due, and past due: fire immediately rather than deferring. - assert_eq!(cfg.arm_delay(secs(10)), Some(Duration::ZERO)); - assert_eq!(cfg.arm_delay(secs(600)), Some(Duration::ZERO)); - - // Armed against the shortest timeout that any context could want. - let fs = CursorHideConfig { - idle_timeout: Some(10), - fullscreen_idle_timeout: Some(3), - ..OFF - }; - assert_eq!(fs.arm_delay(secs(1)), Some(secs(2))); - - assert_eq!(OFF.arm_delay(Duration::ZERO), None); - } -} diff --git a/debian/control b/debian/control index 18c26482..a3baf0eb 100644 --- a/debian/control +++ b/debian/control @@ -6,7 +6,6 @@ Build-Depends: cargo, cmake, debhelper-compat (=10), - just, libegl1-mesa-dev, libfontconfig-dev, libgbm-dev, diff --git a/debian/rules b/debian/rules index 8bd7c8d4..5a266947 100755 --- a/debian/rules +++ b/debian/rules @@ -1,6 +1,6 @@ #!/usr/bin/make -f -DESTDIR = debian/cosmic-comp +export sysconfdir = "/usr/share" export VENDOR ?= 1 CLEAN ?= 1 @@ -9,18 +9,12 @@ CLEAN ?= 1 override_dh_auto_clean: ifeq ($(CLEAN),1) - ischroot && just clean || just clean-dist + ischroot && make clean || make distclean endif ifeq ($(VENDOR),1) - ischroot || just vendor + ischroot || make vendor endif -override_dh_auto_build: - just build-vendored - -override_dh_auto_install: - just rootdir=$(DESTDIR) install - override_dh_installinit: dh_installinit -r diff --git a/justfile b/justfile deleted file mode 100644 index 05db4b52..00000000 --- a/justfile +++ /dev/null @@ -1,64 +0,0 @@ -name := 'cosmic-comp' - -rootdir := '' -prefix := '/usr' -sysconfdir := '/etc' - -base-dir := absolute_path(clean(rootdir / prefix)) -sysconfdir-dir := absolute_path(clean(rootdir / sysconfdir)) - -bin-dir := base-dir / 'bin' -lib-dir := base-dir / 'lib' -share-dir := base-dir / 'share' - -bin-src := cargo-target-dir / 'release' / name -bin-dst := bin-dir / name - -keybindings-src := 'data' / 'keybindings.ron' -keybindings-dst := share-dir / 'cosmic' / 'com.system76.CosmicSettings.Shortcuts' / 'v1' / 'defaults' - -tiling-exceptions-src := 'data' / 'tiling-exceptions.ron' -tiling-exceptions-dst := share-dir / 'cosmic' / 'com.system76.CosmicSettings.WindowRules' / 'v1' / 'tiling_exception_defaults' - -session-desktop-src := 'data' / 'cosmic.desktop' -session-desktop-dst := share-dir / 'wayland-sessions' / 'cosmic.desktop' - -systemd-session-target-src := 'data' / 'cosmic-session.target' -systemd-session-target-dst := lib-dir / 'systemd' / 'user' / 'cosmic-session.target' - -systemd-session-pre-target-src := 'data' / 'cosmic-session-pre.target' -systemd-session-pre-target-dst := lib-dir / 'systemd' / 'user' / 'cosmic-session-pre.target' - -systemd-comp-service-src := 'data' / 'cosmic-comp.service' -systemd-comp-service-dst := lib-dir / 'systemd' / 'user' / 'cosmic-comp.service' - -cosmic-service-src := 'data' / 'cosmic-service' -cosmic-service-dst := bin-dir / 'cosmic-service' - -import 'cargo.just' - -# Default recipe which runs `just build-release` -[private] -default: build-release - -# Installs files -install: - install -Dm0755 {{bin-src}} {{bin-dst}} - install -Dm0644 {{keybindings-src}} {{keybindings-dst}} - install -Dm0644 {{tiling-exceptions-src}} {{tiling-exceptions-dst}} - -# Installs files including bare session files -install-bare-session: install - install -Dm0644 {{session-desktop-src}} {{session-desktop-dst}} - install -Dm0644 {{systemd-session-target-src}} {{systemd-session-target-dst}} - install -Dm0644 {{systemd-session-pre-target-src}} {{systemd-session-pre-target-dst}} - install -Dm0644 {{systemd-comp-service-src}} {{systemd-comp-service-dst}} - install -Dm0755 {{cosmic-service-src}} {{cosmic-service-dst}} - -# Uninstalls installed files -uninstall: - rm {{bin-dst}} {{keybindings-dst}} {{tiling-exceptions-dst}} - -# Uninstalls installed files including bare session files -uninstall-bare-session: uninstall - rm {{session-desktop-dst}} {{systemd-session-target-dst}} {{systemd-session-pre-target-dst}} {{systemd-comp-service-dst}} {{cosmic-service-dst}} diff --git a/src/backend/kms/mod.rs b/src/backend/kms/mod.rs index 4dcffc75..36c6407c 100644 --- a/src/backend/kms/mod.rs +++ b/src/backend/kms/mod.rs @@ -615,13 +615,7 @@ impl State { .clone(); let mut feedback = - DmabufFeedbackBuilder::new(primary_node.dev_id(), primary_formats.clone()) - .add_preference_tranche( - primary_node.dev_id(), - TrancheFlags::Sampling, - primary_formats.iter().cloned(), - 3..=6, - ); + DmabufFeedbackBuilder::new(primary_node.dev_id(), primary_formats.clone()); for dev in kms .drm_devices .values() diff --git a/src/backend/render/cursor.rs b/src/backend/render/cursor.rs index 02da0685..8e14d1be 100644 --- a/src/backend/render/cursor.rs +++ b/src/backend/render/cursor.rs @@ -5,11 +5,9 @@ use crate::{ element::AsGlowRenderer, wayland::{SurfaceRenderElement, push_render_elements_from_surface_tree}, }, - shell::focus::target::KeyboardFocusTarget, utils::prelude::*, wayland::handlers::compositor::FRAME_TIME_FILTER, }; -use cosmic_comp_config::HideDecision; use keyframe::{ease, functions::EaseInOutCubic}; use resvg::{tiny_skia, usvg}; use serde::Deserialize; @@ -453,32 +451,6 @@ pub fn draw_dnd_icon( ); } -/// Why the cursor is currently hidden. Determines what brings it back. -#[derive(Debug, Clone, Copy, PartialEq, Eq)] -pub enum HideReason { - /// No pointer activity for the configured timeout. - Idle, - /// A key was pressed while `while_typing` is enabled. - Typing, - /// Touch input arrived while `after_touch` is enabled. - Touch, -} - -/// Whether a pointer event carries movement. A touch-hidden cursor comes back -/// only on real movement, so the distinction has to reach the call site. -#[derive(Debug, Clone, Copy, PartialEq, Eq)] -pub enum PointerEventKind { - Motion, - Other, -} - -impl HideReason { - /// Whether an event of this kind should reveal the cursor. - fn revealed_by(self, kind: PointerEventKind) -> bool { - matches!(kind, PointerEventKind::Motion) || !matches!(self, HideReason::Touch) - } -} - pub type CursorState = Mutex; pub struct CursorStateInner { current_cursor: Option, @@ -490,10 +462,9 @@ pub struct CursorStateInner { current_image: Option, image_cache: Vec, - hidden: Option, + hidden: bool, idle_timer: Option, last_armed: Option, - last_pointer_activity: Instant, // shake-to-find shake_path: VecDeque, @@ -723,8 +694,7 @@ impl Default for CursorStateInner { current_image: None, image_cache: Vec::new(), - hidden: None, - last_pointer_activity: Instant::now(), + hidden: false, idle_timer: None, last_armed: None, @@ -777,7 +747,7 @@ pub fn draw_cursor( let mut state_ref = seat_userdata.get::().unwrap().lock().unwrap(); let state = &mut *state_ref; - if state.hidden.is_some() { + if state.hidden { return; } @@ -867,175 +837,68 @@ pub fn draw_cursor( const ACTIVITY_THROTTLE: Duration = Duration::from_millis(100); -/// Reveal the cursor if this event should, and (re)arm the idle-hide timer. -/// Returns true if the cursor was previously hidden and is now visible. -pub fn notify_cursor_activity(state: &State, seat: &Seat, kind: PointerEventKind) -> bool { - let cursor_state = seat.user_data().get::().unwrap(); - - let revealed = { - let mut inner = cursor_state.lock().unwrap(); - inner.last_pointer_activity = Instant::now(); - match inner.hidden { - Some(reason) if reason.revealed_by(kind) => { - inner.hidden = None; - true - } - // Still hidden on purpose: leave the timer alone. - Some(_) => return false, - None => false, - } - }; - - refresh_idle_timer(state, seat); - revealed -} - -/// (Re)arm the idle-hide timer without counting as pointer activity. -/// -/// The deadline is measured from the last *pointer* event, not from now, so a -/// caller that does not stamp activity — a keystroke, a config reload — cannot -/// postpone the hide by re-arming. -/// -/// Armed with the shortest timeout any context could want: the input that arms -/// the timer is usually what goes on to make a window fullscreen, so the -/// context is not yet knowable here. `on_idle_timer` evaluates it on fire and -/// re-arms for the remainder if nothing applied yet. -pub fn refresh_idle_timer(state: &State, seat: &Seat) { - let config = state.common.config.cosmic_conf.cursor_hide; +/// Reveal the cursor and (re)arm the idle-hide timer; returns true if it was previously hidden +pub fn notify_cursor_activity(state: &State, seat: &Seat) -> bool { + let timeout = state.common.config.cosmic_conf.cursor_hide_timeout; let loop_handle = &state.common.event_loop_handle; let cursor_state = seat.user_data().get::().unwrap(); let now = Instant::now(); - let (old_token, since_activity) = { + let (was_hidden, old_token) = { let mut inner = cursor_state.lock().unwrap(); - if inner.hidden.is_some() { - return; - } - // Coalesce bursts from high-frequency pointers. - let throttled = inner.idle_timer.is_some() + let was_hidden = inner.hidden; + inner.hidden = false; + + let throttled = timeout.is_some() + && !was_hidden + && inner.idle_timer.is_some() && inner .last_armed .is_some_and(|t| now.duration_since(t) < ACTIVITY_THROTTLE); if throttled { - return; + return was_hidden; } - let since_activity = now.duration_since(inner.last_pointer_activity); + + let old_token = inner.idle_timer.take(); inner.last_armed = None; - (inner.idle_timer.take(), since_activity) + (was_hidden, old_token) }; if let Some(token) = old_token { loop_handle.remove(token); } - let Some(delay) = config.arm_delay(since_activity) else { - return; - }; - - let timer = Timer::from_duration(delay); - let timer_seat = seat.clone(); - match loop_handle.insert_source(timer, move |_, _, state| on_idle_timer(state, &timer_seat)) { - Ok(token) => { + if let Some(secs) = timeout { + let timer = Timer::from_duration(Duration::from_secs(secs as u64)); + let seat = seat.clone(); + if let Ok(token) = loop_handle.insert_source(timer, move |_, _, state| { + hide_cursor(state, &seat); + TimeoutAction::Drop + }) { let mut inner = cursor_state.lock().unwrap(); inner.idle_timer = Some(token); inner.last_armed = Some(now); } - // `idle_timer` stays `None`, so the next activity is unthrottled and retries. - Err(err) => warn!(?err, "Failed to arm the cursor idle-hide timer"), } + + was_hidden } -/// Whether the seat is focusing a fullscreen surface. A fullscreen window that -/// is not focused can be stacked behind others, so its presence on the output -/// says nothing about what the user is looking at. -fn fullscreen_focused(seat: &Seat) -> bool { - matches!( - seat.get_keyboard().and_then(|kbd| kbd.current_focus()), - Some(KeyboardFocusTarget::Fullscreen(_)) - ) -} - -fn on_idle_timer(state: &mut State, seat: &Seat) -> TimeoutAction { - let config = state.common.config.cosmic_conf.cursor_hide; - let fullscreen = fullscreen_focused(seat); - let cursor_state = seat.user_data().get::().unwrap(); - - let elapsed = { - let inner = cursor_state.lock().unwrap(); - Instant::now().duration_since(inner.last_pointer_activity) - }; - - match config.resolve(elapsed, fullscreen) { - HideDecision::Hide => { - hide_cursor(state, seat, HideReason::Idle); - TimeoutAction::Drop - } - HideDecision::Drop => { - let mut inner = cursor_state.lock().unwrap(); - inner.idle_timer = None; - inner.last_armed = None; - TimeoutAction::Drop - } - HideDecision::RearmAfter(delay) => { - cursor_state.lock().unwrap().last_armed = Some(Instant::now()); - TimeoutAction::ToDuration(delay) - } +fn hide_cursor(state: &mut State, seat: &Seat) { + if let Some(ptr) = seat.get_pointer() + && ptr.is_grabbed() + { + return; } -} - -/// Hide the cursor immediately, for a trigger that does not wait on the timer. -pub fn hide_cursor_now(state: &mut State, seat: &Seat, reason: HideReason) { - let loop_handle = state.common.event_loop_handle.clone(); - let token = { - let cursor_state = seat.user_data().get::().unwrap(); - let mut inner = cursor_state.lock().unwrap(); - inner.idle_timer.take() - }; - if let Some(token) = token { - loop_handle.remove(token); - } - hide_cursor(state, seat, reason); -} - -fn hide_cursor(state: &mut State, seat: &Seat, reason: HideReason) { - let grabbed = seat.get_pointer().is_some_and(|ptr| ptr.is_grabbed()); let cursor_state = seat.user_data().get::().unwrap(); { let mut inner = cursor_state.lock().unwrap(); - // Every caller has already disposed of the timer source, so clear the - // bookkeeping before the grab check rather than only on success. + inner.hidden = true; inner.idle_timer = None; inner.last_armed = None; - // The reason only ever tightens: `Touch` waits for real movement, so a - // later trigger must not relax it back to click-or-scroll. - if grabbed || inner.hidden == Some(reason) || inner.hidden == Some(HideReason::Touch) { - return; - } - inner.hidden = Some(reason); } let outputs: Vec<_> = state.common.shell.read().outputs().cloned().collect(); for output in outputs { state.backend.schedule_render(&output); } } - -#[cfg(test)] -mod test { - use super::{HideReason, PointerEventKind}; - - #[test] - fn touch_hidden_cursor_waits_for_movement() { - assert!(HideReason::Touch.revealed_by(PointerEventKind::Motion)); - assert!(!HideReason::Touch.revealed_by(PointerEventKind::Other)); - } - - #[test] - fn idle_and_typing_hidden_cursors_are_revealed_by_any_pointer_event() { - for reason in [HideReason::Idle, HideReason::Typing] { - assert!(reason.revealed_by(PointerEventKind::Motion)); - // A click or a scroll must rescue the cursor rather than forcing a - // blind click. - assert!(reason.revealed_by(PointerEventKind::Other)); - } - } -} diff --git a/src/config/mod.rs b/src/config/mod.rs index 9bdef7c1..4d2fad9b 100644 --- a/src/config/mod.rs +++ b/src/config/mod.rs @@ -10,7 +10,7 @@ use crate::{ }, }; use anyhow::Context; -use cosmic_config::{ConfigGet, ConfigSet, CosmicConfigEntry}; +use cosmic_config::{ConfigGet, CosmicConfigEntry}; use cosmic_settings_config::window_rules::ApplicationException; use cosmic_settings_config::{Shortcuts, shortcuts, window_rules}; use serde::{Deserialize, Serialize}; @@ -49,8 +49,8 @@ mod types; use cosmic::config::CosmicTk; pub use cosmic_comp_config::EdidProduct; use cosmic_comp_config::{ - ActivationPolicy, AppearanceConfig, CosmicCompConfig, CursorHideConfig, DecorationPreference, - KeyboardConfig, TileBehavior, XkbConfig, XwaylandDescaling, XwaylandEavesdropping, ZoomConfig, + ActivationPolicy, AppearanceConfig, CosmicCompConfig, DecorationPreference, KeyboardConfig, + TileBehavior, XkbConfig, XwaylandDescaling, XwaylandEavesdropping, ZoomConfig, input::{DeviceState as InputDeviceState, InputConfig, TouchpadOverride}, output::comp::{ OutputConfig, OutputInfo, OutputState, OutputsConfig, TransformDef, load_outputs, @@ -172,7 +172,7 @@ pub enum ColorFilter { } impl Config { - pub fn load(loop_handle: &LoopHandle<'_, State>, kiosk_mode: bool) -> Config { + pub fn load(loop_handle: &LoopHandle<'_, State>) -> Config { let config = cosmic_config::Config::new("com.system76.CosmicComp", 1).unwrap(); let source = cosmic_config::calloop::ConfigWatchSource::new(&config).unwrap(); loop_handle @@ -182,7 +182,7 @@ impl Config { .expect("Failed to add cosmic-config to the event loop"); let xdg = xdg::BaseDirectories::new(); - let mut cosmic_comp_config = + let cosmic_comp_config = CosmicCompConfig::get_entry(&config).unwrap_or_else(|(errs, c)| { if cfg!(debug_assertions) { for err in errs { @@ -192,18 +192,6 @@ impl Config { c }); - // `cursor_hide_timeout` was replaced by the grouped `cursor_hide` key. - // Seed the new key once so configs hand-edited before the rename keep - // working; the old file is left in place so a downgrade still reads it. - if config.get::("cursor_hide").is_err() - && let Ok(legacy) = config.get::>("cursor_hide_timeout") - { - cosmic_comp_config.cursor_hide.idle_timeout = legacy; - if let Err(err) = config.set("cursor_hide", cosmic_comp_config.cursor_hide) { - warn!(?err, "Failed to migrate cursor_hide_timeout to cursor_hide"); - } - } - // Listen for updates to the toolkit config if let Ok(tk_config) = cosmic_config::Config::new("com.system76.CosmicTk", 1) { fn handle_new_toolkit_config(config: CosmicTk, state: &mut State) { @@ -260,48 +248,40 @@ impl Config { // Source key bindings from com.system76.CosmicSettings.Shortcuts let settings_context = shortcuts::context().expect("Failed to load shortcuts config"); - let mut system_actions = Default::default(); - let mut shortcuts = Default::default(); - // Kiosk mode disables shortcuts - if !kiosk_mode { - system_actions = shortcuts::system_actions(&settings_context); - shortcuts = shortcuts::shortcuts(&settings_context); + let system_actions = shortcuts::system_actions(&settings_context); + let shortcuts = shortcuts::shortcuts(&settings_context); - // Listen for updates to the keybindings config. - match cosmic_config::calloop::ConfigWatchSource::new(&settings_context) { - Ok(source) => { - if let Err(err) = - loop_handle.insert_source(source, |(config, keys), (), state| { - for key in keys { - match key.as_str() { - // Reload the keyboard shortcuts config. - "custom" | "defaults" => { - state.common.config.shortcuts = - shortcuts::shortcuts(&config); - } - - "system_actions" => { - state.common.config.system_actions = - shortcuts::system_actions(&config); - } - - _ => (), - } + // Listen for updates to the keybindings config. + match cosmic_config::calloop::ConfigWatchSource::new(&settings_context) { + Ok(source) => { + if let Err(err) = loop_handle.insert_source(source, |(config, keys), (), state| { + for key in keys { + match key.as_str() { + // Reload the keyboard shortcuts config. + "custom" | "defaults" => { + state.common.config.shortcuts = shortcuts::shortcuts(&config); } - }) - { - warn!( - ?err, - "Failed to watch com.system76.CosmicSettings.Shortcuts config" - ); + + "system_actions" => { + state.common.config.system_actions = + shortcuts::system_actions(&config); + } + + _ => (), + } } + }) { + warn!( + ?err, + "Failed to watch com.system76.CosmicSettings.Shortcuts config" + ); } - Err(err) => warn!( - ?err, - "failed to create config watch source for com.system76.CosmicSettings.Shortcuts" - ), - }; - } + } + Err(err) => warn!( + ?err, + "failed to create config watch source for com.system76.CosmicSettings.Shortcuts" + ), + }; let window_rules_context = window_rules::context().expect("Failed to load window rules config"); @@ -1003,21 +983,15 @@ fn config_changed(config: cosmic_config::Config, keys: Vec, state: &mut let new = get_config::(&config, "cursor_shake_to_find"); state.common.config.cosmic_conf.cursor_shake_to_find = new; } - "cursor_hide" => { - let new = get_config::(&config, "cursor_hide"); - if new != state.common.config.cosmic_conf.cursor_hide { - state.common.config.cosmic_conf.cursor_hide = new; - // Reveal on every change: a visible cursor is the safe state, - // and it avoids stranding a hidden cursor when the trigger - // that hid it is switched off. + "cursor_hide_timeout" => { + let new = get_config::>(&config, "cursor_hide_timeout"); + if new != state.common.config.cosmic_conf.cursor_hide_timeout { + state.common.config.cosmic_conf.cursor_hide_timeout = new; let seats: Vec<_> = state.common.shell.read().seats.iter().cloned().collect(); let mut needs_render = false; for seat in seats { - needs_render |= crate::backend::render::cursor::notify_cursor_activity( - state, - &seat, - crate::backend::render::cursor::PointerEventKind::Motion, - ); + needs_render |= + crate::backend::render::cursor::notify_cursor_activity(state, &seat); } if needs_render { let outputs: Vec<_> = diff --git a/src/input/mod.rs b/src/input/mod.rs index 6cac7cdf..45586b03 100644 --- a/src/input/mod.rs +++ b/src/input/mod.rs @@ -1,10 +1,7 @@ // SPDX-License-Identifier: GPL-3.0-only use crate::{ - backend::render::{ - ElementFilter, - cursor::{PointerEventKind, notify_cursor_activity}, - }, + backend::render::{ElementFilter, cursor::notify_cursor_activity}, config::{ Action, Config, PrivateAction, key_bindings::{ @@ -22,7 +19,7 @@ use crate::{ Stage, render_input_order, target::{KeyboardFocusTarget, PointerFocusTarget}, }, - grabs::{MenuGrab, MoveGrab, ReleaseMode, ResizeEdge, ResizeGrab}, + grabs::{ReleaseMode, ResizeEdge}, layout::{ floating::ResizeGrabMarker, tiling::{NodeDesc, SwapWindowGrab, TilingLayout}, @@ -52,7 +49,7 @@ use smithay::{ PointerAxisEvent, ProximityState, TabletToolButtonEvent, TabletToolEvent, TabletToolProximityEvent, TabletToolTipEvent, TabletToolTipState, TouchEvent, }, - desktop::{WindowSurfaceType, utils::under_from_surface_tree}, + desktop::{PopupKeyboardGrab, WindowSurfaceType, utils::under_from_surface_tree}, input::{ Seat, keyboard::KeyboardHandle, @@ -223,16 +220,7 @@ impl State { ) where ::Device: 'static, { - // An input device going away is not user activity, e.g. a wireless keyboard - // dropping its link when it sleeps, so it must not power displays back on. - // Device additions still wake: after a system resume the re-enumerated - // devices may be the only input seen, and the wake resets idle anyway. - if !matches!( - &event, - InputEvent::DeviceRemoved { .. } | InputEvent::Special(_) - ) { - crate::wayland::handlers::output_power::set_all_surfaces_dpms_on(self); - } + crate::wayland::handlers::output_power::set_all_surfaces_dpms_on(self); use smithay::backend::input::Event; match event { @@ -339,26 +327,6 @@ impl State { keyboard.modifier_state().num_lock; } } - - // A bare modifier press changes the modifier state; a real - // keystroke does not. Super+drag moves windows, so hiding on - // Super-down would take the cursor away exactly as the user - // reaches for it. Super+1 still counts as typing. - let bare_modifier = previous_modifiers != keyboard.modifier_state(); - if self.common.config.cosmic_conf.cursor_hide.while_typing - && state == KeyState::Pressed - && !bare_modifier - { - crate::backend::render::cursor::hide_cursor_now( - self, - &seat, - crate::backend::render::cursor::HideReason::Typing, - ); - } else { - // Still refresh: this is how entering fullscreen by - // keyboard arms the fullscreen timeout. - crate::backend::render::cursor::refresh_idle_timer(self, &seat); - } } } @@ -372,7 +340,7 @@ impl State { .cloned() { self.common.idle_notifier_state.notify_activity(&seat); - notify_cursor_activity(self, &seat, PointerEventKind::Motion); + notify_cursor_activity(self, &seat); let current_output = seat.active_output(); if self.common.config.cosmic_conf.cursor_shake_to_find @@ -746,7 +714,7 @@ impl State { .cloned(); if let Some(seat) = maybe_seat { self.common.idle_notifier_state.notify_activity(&seat); - notify_cursor_activity(self, &seat, PointerEventKind::Motion); + notify_cursor_activity(self, &seat); let (output, position) = if matches!(&backend_id, InputBackendId::Ei(_)) { // EI absolute coordinates are in the compositor's *global* // logical space: each advertised region carries its output's @@ -841,7 +809,7 @@ impl State { return; }; self.common.idle_notifier_state.notify_activity(&seat); - notify_cursor_activity(self, &seat, PointerEventKind::Other); + notify_cursor_activity(self, &seat); let current_focus = seat.get_keyboard().unwrap().current_focus(); let shortcuts_inhibited = current_focus.as_ref().is_some_and(|f| { @@ -1092,7 +1060,7 @@ impl State { .cloned(); if let Some(seat) = maybe_seat { self.common.idle_notifier_state.notify_activity(&seat); - notify_cursor_activity(self, &seat, PointerEventKind::Other); + notify_cursor_activity(self, &seat); if self.source_modifiers(&backend_id, &seat).logo && self @@ -1494,18 +1462,11 @@ impl State { }; let under = State::surface_under(position, &output, &shell) .map(|(target, pos)| (target, pos.as_logical())); - let focus_target = State::element_under(position, &output, &shell, &seat); std::mem::drop(shell); let serial = SERIAL_COUNTER.next_serial(); let touch = seat.get_touch().unwrap(); - // change the keyboard focus unless the touch is grabbed, like pointer buttons - if !touch.is_grabbed() - && let Some(target) = focus_target.as_ref() - { - Shell::set_focus(self, Some(target), &seat, Some(serial), false); - } touch.down( self, under, @@ -1516,14 +1477,6 @@ impl State { time: event.time(), }, ); - - if self.common.config.cosmic_conf.cursor_hide.after_touch { - crate::backend::render::cursor::hide_cursor_now( - self, - &seat, - crate::backend::render::cursor::HideReason::Touch, - ); - } } } InputEvent::TouchMotion { event, .. } => { @@ -1639,7 +1592,7 @@ impl State { .cloned() { self.common.idle_notifier_state.notify_activity(&seat); - notify_cursor_activity(self, &seat, PointerEventKind::Motion); + notify_cursor_activity(self, &seat); let Some(output) = mapped_output_for_device(&self.common.config, &shell, &event.device()) .cloned() @@ -1743,7 +1696,7 @@ impl State { .cloned() { self.common.idle_notifier_state.notify_activity(&seat); - notify_cursor_activity(self, &seat, PointerEventKind::Motion); + notify_cursor_activity(self, &seat); let Some(output) = mapped_output_for_device(&self.common.config, &shell, &event.device()) .cloned() @@ -1892,7 +1845,7 @@ impl State { .cloned(); if let Some(seat) = maybe_seat { self.common.idle_notifier_state.notify_activity(&seat); - notify_cursor_activity(self, &seat, PointerEventKind::Other); + notify_cursor_activity(self, &seat); let serial = SERIAL_COUNTER.next_serial(); let output = seat.active_output(); @@ -1945,7 +1898,7 @@ impl State { .cloned(); if let Some(seat) = maybe_seat { self.common.idle_notifier_state.notify_activity(&seat); - notify_cursor_activity(self, &seat, PointerEventKind::Other); + notify_cursor_activity(self, &seat); if let Some(tool) = seat.tablet_seat().get_tool(&event.tool()) { tool.button( self, @@ -2143,21 +2096,6 @@ impl State { 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) && !seat.get_keyboard().unwrap().is_grabbed() && !shortcuts_inhibited @@ -2353,15 +2291,17 @@ impl State { let keyboard = seat.get_keyboard().unwrap(); let pointer = seat.get_pointer().unwrap(); - // Escape only cancels grabs the compositor started for its own interactions - // For keyboard: SwapWindowGrab - // For pointer: MoveGrab, ResizeGrab, and MenuGrab - let keyboard_grabbed = - keyboard.with_grab(|_serial, grab| grab.is::()) == Some(true); - let pointer_grabbed = pointer.with_grab(|_serial, grab| { - grab.is::() || grab.is::() || grab.is::() + // We're only interested in filtering keyboard grabs if we initiated them. + // The easiest way to check that is to check the type of the grab. + let keyboard_grabbed = keyboard.with_grab(|_serial, grab| { + grab.is::() || grab.is::>() }) == Some(true); - let is_grabbed = keyboard_grabbed || pointer_grabbed; + // A virtual-keyboard key can arrive while the seat's pointer is grabbed by that + // 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(); //this should fall back to active output since there may not be a focused output diff --git a/src/lib.rs b/src/lib.rs index 98bfa2a3..aa31a464 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -289,7 +289,7 @@ Project home page: https://github.com/pop-os/cosmic-comp Options: -h, --help Show this message --no-xwayland Run without Xwayland - -V, --version Show the version of cosmic-comp"# + -v, --version Show the version of cosmic-comp"# ); } diff --git a/src/logger/mod.rs b/src/logger/mod.rs index 34baf42d..3e5347df 100644 --- a/src/logger/mod.rs +++ b/src/logger/mod.rs @@ -4,10 +4,7 @@ use std::str::FromStr; use anyhow::Result; -#[cfg(feature = "systemd")] -use tracing::warn; -use tracing::{debug, info}; -#[cfg(feature = "systemd")] +use tracing::{debug, info, warn}; use tracing_journald as journald; use tracing_subscriber::{EnvFilter, filter::Directive, fmt, prelude::*}; @@ -32,7 +29,6 @@ pub fn init_logger() -> Result<()> { let fmt_layer = fmt::layer().compact(); - #[cfg(feature = "systemd")] match journald::layer() { Ok(journald_layer) => tracing_subscriber::registry() .with(fmt_layer) @@ -47,11 +43,6 @@ pub fn init_logger() -> Result<()> { warn!(?err, "Failed to init journald logging."); } }; - #[cfg(not(feature = "systemd"))] - tracing_subscriber::registry() - .with(fmt_layer) - .with(filter) - .init(); log_panics::init(); info!("Version: {}", std::env!("CARGO_PKG_VERSION")); diff --git a/src/shell/element/mod.rs b/src/shell/element/mod.rs index c7e799be..d4743b7f 100644 --- a/src/shell/element/mod.rs +++ b/src/shell/element/mod.rs @@ -430,10 +430,6 @@ impl CosmicMapped { } } - pub fn is_sticky(&self) -> bool { - self.active_window().is_sticky() - } - pub fn pending_size(&self) -> Option> { match &self.element { CosmicMappedInternal::Stack(s) => s.pending_size(), diff --git a/src/shell/focus/mod.rs b/src/shell/focus/mod.rs index 8b2348eb..f631372e 100644 --- a/src/shell/focus/mod.rs +++ b/src/shell/focus/mod.rs @@ -2,18 +2,12 @@ use crate::{ shell::{CosmicSurface, MinimizedWindow, Shell, Trigger, element::CosmicMapped}, state::{Common, State}, utils::prelude::*, - wayland::{ - handlers::{xdg_shell::PopupGrabData, xwayland_keyboard_grab::XWaylandGrabSeatData}, - protocols::session_lock_layer::layer_show_on_lock, - }, + wayland::handlers::{xdg_shell::PopupGrabData, xwayland_keyboard_grab::XWaylandGrabSeatData}, }; use indexmap::IndexSet; use smithay::{ backend::input::InputTime, - desktop::{ - LayerSurface, PopupUngrabStrategy, WindowSurfaceType, find_popup_root_surface, - layer_map_for_output, - }, + desktop::{PopupUngrabStrategy, layer_map_for_output}, input::{Seat, pointer::MotionEvent}, output::Output, reexports::wayland_server::{Resource, protocol::wl_surface::WlSurface}, @@ -255,17 +249,8 @@ impl Shell { let workspace = if let Some(workspace) = workspace { self.workspaces.space_for_handle_mut(&workspace.0).unwrap() } else { - let output = match &target { - FocusTarget::Window(mapped) => self - .workspaces - .sets - .iter() - .find(|(_, set)| set.sticky_layer.mapped().any(|m| m == mapped)) - .map(|(output, _)| output.clone()), - FocusTarget::Fullscreen(_) => None, - }; - - self.active_space_mut(&output.unwrap_or_else(|| seat.active_output())) + //should this be the active output or the focused output? + self.active_space_mut(&seat.focused_or_active_output()) .unwrap() }; @@ -642,42 +627,19 @@ fn focus_target_is_valid( output: &Output, target: KeyboardFocusTarget, ) -> bool { - // If a session lock is active, only lock surfaces and lock layers can be focused + // If a session lock is active, only lock surfaces 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(_)); } // If an exclusive layer shell surface exists (on any output), only exclusive // 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) { - let is_exclusive_on_layer = |layer_surface: &LayerSurface| { + return if let KeyboardFocusTarget::LayerSurface(layer_surface) = target { let data = layer_surface.cached_state(); (data.keyboard_interactivity, data.layer) == (KeyboardInteractivity::Exclusive, layer) - }; - 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, + } else { + false }; } diff --git a/src/shell/focus/order.rs b/src/shell/focus/order.rs index 937fa311..fb904c01 100644 --- a/src/shell/focus/order.rs +++ b/src/shell/focus/order.rs @@ -22,7 +22,7 @@ use crate::{ prelude::OutputExt, quirks::{WORKSPACE_OVERVIEW_NAMESPACE, workspace_overview_is_open}, }, - wayland::protocols::{session_lock_layer::layer_show_on_lock, workspace::WorkspaceHandle}, + wayland::protocols::workspace::WorkspaceHandle, }; pub enum Stage<'a> { @@ -77,8 +77,6 @@ fn render_input_order_internal( element_filter: ElementFilter, mut callback: impl FnMut(Stage) -> ControlFlow, ()>, ) -> ControlFlow, ()> { - // NOTE: Keep in sync with other surface iteration functions - if shell .zoom_state .as_ref() @@ -89,92 +87,7 @@ fn render_input_order_internal( // Session Lock if let Some(session_lock) = &shell.session_lock { - 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(()); + return callback(Stage::SessionLock(session_lock.surfaces.get(output))); } // Overlay-level layer shell diff --git a/src/shell/grabs/menu/mod.rs b/src/shell/grabs/menu/mod.rs index 37755027..9ea37a31 100644 --- a/src/shell/grabs/menu/mod.rs +++ b/src/shell/grabs/menu/mod.rs @@ -579,12 +579,10 @@ impl PointerGrab for MenuGrab { PointerTarget::motion(&element.iced, &self.seat, state, &new_event); } } else { - // Keep the root menu hovered while a submenu is open - let keep_root = usize::from(elements.len() > 1); elements .iter_mut() .filter(|element| element.pointer_entered) - .skip(keep_root) + .skip(1) .for_each(|element| { PointerTarget::leave( &element.iced, @@ -1022,11 +1020,10 @@ impl TabletToolGrab for MenuGrab { ); self.last_tablet_idx = Some(i); } else { - let keep_root = usize::from(elements.len() > 1); elements .iter_mut() .filter(|element| element.tablet_entered.is_some()) - .skip(keep_root) + .skip(1) .for_each(|element| { TabletToolTarget::proximity_out( &element.iced, diff --git a/src/shell/layout/tiling/mod.rs b/src/shell/layout/tiling/mod.rs index 20e11b71..8706dc59 100644 --- a/src/shell/layout/tiling/mod.rs +++ b/src/shell/layout/tiling/mod.rs @@ -3271,34 +3271,12 @@ impl TilingLayout { } } - let (_, inner) = self.gaps(); let mut result = None; - let mut fork = None; let mut lookup = Some(root.clone()); while let Some(node) = lookup { let data = tree.get(&node).unwrap().data(); if data.geometry().contains(location) { result = Some(node.clone()); - if let Data::Group { - orientation, - sizes, - last_geometry, - .. - } = data - { - let (pos, mut split) = match orientation { - Orientation::Vertical => (location.x, last_geometry.loc.x), - Orientation::Horizontal => (location.y, last_geometry.loc.y), - }; - for (idx, size) in - sizes.iter().take(sizes.len().saturating_sub(1)).enumerate() - { - split += size; - if (pos - split).abs() <= inner / 2 { - fork = Some((node.clone(), idx)); - } - } - } } lookup = None; @@ -3345,16 +3323,25 @@ impl TilingLayout { ) }) } - Some((_, Data::Group { .. })) => { - let (id, idx) = fork?; - let Data::Group { + Some(( + id, + Data::Group { orientation, last_geometry, .. - } = tree.get(&id).unwrap().data().clone() - else { - unreachable!() - }; + }, + )) => { + let idx = tree + .children(&id) + .unwrap() + .position(|node| { + let data = node.data(); + match orientation { + Orientation::Vertical => location.x < data.geometry().loc.x, + Orientation::Horizontal => location.y < data.geometry().loc.y, + } + }) + .and_then(|x| x.checked_sub(1))?; Some(( ResizeForkTarget { node: id.clone(), diff --git a/src/shell/mod.rs b/src/shell/mod.rs index 10b40b59..47d78851 100644 --- a/src/shell/mod.rs +++ b/src/shell/mod.rs @@ -19,10 +19,7 @@ use crate::{ utils, wayland::{ handlers::data_device::{self, get_dnd_icon}, - protocols::{ - session_lock_layer::layer_show_on_lock, - workspace::{State as WState, WorkspaceCapabilities}, - }, + protocols::workspace::{State as WState, WorkspaceCapabilities}, }, }; use cosmic_comp_config::{ @@ -516,12 +513,6 @@ impl WorkspaceSet { } } - fn refresh_focus_stacks(&mut self) { - for workspace in &mut self.workspaces { - workspace.refresh_focus_stack(); - } - } - fn activate( &mut self, idx: usize, @@ -626,7 +617,6 @@ impl WorkspaceSet { self.workspaces[self.active].refresh(); } self.sticky_layer.refresh(); - self.refresh_focus_stacks(); } fn add_empty_workspace(&mut self, state: &mut WorkspaceUpdateGuard) { @@ -2056,27 +2046,12 @@ impl Shell { } 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((output, _)) = session_lock + return session_lock .surfaces .iter() .find(|(_, v)| v.wl_surface() == surface) - { - 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; - } - } - } + .map(|(k, _)| k); } self.outputs() diff --git a/src/shell/workspace.rs b/src/shell/workspace.rs index fd63dcb1..84a020ff 100644 --- a/src/shell/workspace.rs +++ b/src/shell/workspace.rs @@ -526,16 +526,10 @@ impl Workspace { .mapped() .chain(self.tiling_layer.mapped().map(|(w, _)| w)) .chain(move_mapped.iter()) - .chain( - self.minimized_windows - .iter() - .flat_map(MinimizedWindow::mapped), - ) }; stack.retain(|w| match w { FocusTarget::Fullscreen(s) => fullscreen_surfaces.contains(&s), - // Sticky windows live in the `WorkspaceSet` but are shown on whichever workspace is current - FocusTarget::Window(w) => w.is_sticky() || mapped().any(|m| w == m), + FocusTarget::Window(w) => mapped().any(|m| w == m), }); } } @@ -1773,17 +1767,13 @@ impl Workspace { self.floating_layer.render( renderer, - render_focus - .then(|| { - focused.as_ref().and_then(|target| { - if let FocusTarget::Window(mapped) = target { - Some(mapped) - } else { - None - } - }) - }) - .flatten(), + focused.as_ref().and_then(|target| { + if let FocusTarget::Window(mapped) = target { + Some(mapped) + } else { + None + } + }), resize_indicator.clone(), indicator_thickness, alpha, diff --git a/src/state.rs b/src/state.rs index 86f5e23e..28ed8fd4 100644 --- a/src/state.rs +++ b/src/state.rs @@ -23,7 +23,6 @@ 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}, @@ -321,7 +320,6 @@ pub struct Common { pub xwayland_state: Option, pub xwayland_shell_state: XWaylandShellState, pub pointer_focus_state: Option, - pub session_lock_layer_state: SessionLockLayerState, #[cfg(feature = "logind")] pub inhibit_lid_fd: Option, @@ -667,7 +665,7 @@ impl State { .unwrap(); let clock = Clock::new(); - let config = Config::load(&handle, kiosk_command.is_some()); + let config = Config::load(&handle); let compositor_state = CompositorState::new::(dh); let corner_radius_state = CornerRadiusState::new::(dh); let data_device_state = DataDeviceState::new::(dh); @@ -765,9 +763,6 @@ impl State { let dbus_state = DBusState::init(&handle); - let session_lock_layer_state = - SessionLockLayerState::new::(dh, client_not_sandboxed); - State { common: Common { config, @@ -835,7 +830,6 @@ impl State { pointer_focus_state: None, dbus_state, keyboard_layout_state, - session_lock_layer_state, #[cfg(feature = "logind")] inhibit_lid_fd: None, @@ -974,8 +968,6 @@ impl Common { output: &Output, render_element_states: &RenderElementStates, ) { - // NOTE: Keep in sync with surface iteration in `render_input_order_internal` - let shell = self.shell.read(); let processor = |namespace: Option| { move |surface: &WlSurface, states: &SurfaceData| { @@ -1082,8 +1074,6 @@ impl Common { render_element_states: &RenderElementStates, mut dmabuf_feedback: impl FnMut(DrmNode) -> Option, ) { - // NOTE: Keep in sync with surface iteration in `render_input_order_internal` - let shell = self.shell.read(); if let Some(session_lock) = shell.session_lock.as_ref() @@ -1297,8 +1287,6 @@ impl Common { #[profiling::function] pub fn send_frames(&self, output: &Output, sequence: Option) { - // NOTE: Keep in sync with surface iteration in `render_input_order_internal` - let time = self.clock.now(); let should_send = |surface: &WlSurface, states: &SurfaceData| { // Do the standard primary scanout output check. For pointer surfaces it deduplicates diff --git a/src/utils/iced/mod.rs b/src/utils/iced/mod.rs index 8baf87f9..4522644b 100644 --- a/src/utils/iced/mod.rs +++ b/src/utils/iced/mod.rs @@ -519,7 +519,6 @@ impl TabletToolTarget for Iced _tool_descriptor: &TabletToolDescriptor, ) { let mut internal = self.0.lock().unwrap(); - internal.cursor_pos = None; internal .state .queue_event(Event::Mouse(MouseEvent::CursorLeft)); @@ -729,7 +728,6 @@ impl PointerTarget for IcedEle _time: InputTime, ) { let mut internal = self.0.lock().unwrap(); - internal.cursor_pos = None; internal .state .queue_event(Event::Mouse(MouseEvent::CursorLeft)); diff --git a/src/wayland/handlers/image_copy_capture/mod.rs b/src/wayland/handlers/image_copy_capture/mod.rs index 57ef9500..85a01c9a 100644 --- a/src/wayland/handlers/image_copy_capture/mod.rs +++ b/src/wayland/handlers/image_copy_capture/mod.rs @@ -1,8 +1,6 @@ // SPDX-License-Identifier: GPL-3.0-only -use std::{borrow::Borrow, sync::Mutex}; - -use indexmap::IndexMap; +use std::{borrow::Borrow, collections::HashMap, sync::Mutex}; use smithay::{ backend::{ @@ -454,28 +452,23 @@ fn constraints_for_renderer( .ok() .and_then(|device| device.try_get_render_node().ok().flatten()) { - let mut formats = renderer - .egl_context() - .dmabuf_render_formats() - .iter() - .fold( - IndexMap::>::new(), - |mut map, format| { - map.entry(format.code).or_default().push(format.modifier); - map - }, - ) - .into_iter() - .collect::>(); - formats.sort_by_key(|(code, _)| !is_preferred_capture_format(*code)); - constraints.dma = Some(DmabufConstraints { node, formats }); + constraints.dma = Some(DmabufConstraints { + node, + formats: renderer + .egl_context() + .dmabuf_render_formats() + .iter() + .fold( + HashMap::>::new(), + |mut map, format| { + map.entry(format.code).or_default().push(format.modifier); + map + }, + ) + .into_iter() + .collect::>(), + }); } constraints } - -/// Formats most screencast consumers handle natively, offered first. WebRTC, for -/// example, swaps RGBA frames to BGRA on the CPU for every captured frame. -fn is_preferred_capture_format(code: Fourcc) -> bool { - matches!(code, Fourcc::Argb8888 | Fourcc::Xrgb8888) -} diff --git a/src/wayland/handlers/output_power.rs b/src/wayland/handlers/output_power.rs index 333aacc6..2675009a 100644 --- a/src/wayland/handlers/output_power.rs +++ b/src/wayland/handlers/output_power.rs @@ -21,11 +21,6 @@ pub fn set_all_surfaces_dpms_on(state: &mut State) { } if changed { - // Powering an output on because of input is activity. Without this the idle - // notifier stays idled, the idle daemon never sees `resumed`, and nothing - // powers the output off again until real input arrives. - let seat = state.common.shell.read().seats.last_active().clone(); - state.common.idle_notifier_state.notify_activity(&seat); OutputPowerState::refresh(state); } } diff --git a/src/wayland/handlers/xdg_activation.rs b/src/wayland/handlers/xdg_activation.rs index 38ba6219..ad8ce0d0 100644 --- a/src/wayland/handlers/xdg_activation.rs +++ b/src/wayland/handlers/xdg_activation.rs @@ -243,7 +243,7 @@ impl State { { for mapped in current_workspace .mapped() - .filter(|m| m.maximized_state.lock().unwrap().is_some() && *m != &element) + .filter(|m| m.maximized_state.lock().unwrap().is_some()) .cloned() .collect::>() .into_iter() diff --git a/src/wayland/protocols/mod.rs b/src/wayland/protocols/mod.rs index 48aa8337..c6c0234a 100644 --- a/src/wayland/protocols/mod.rs +++ b/src/wayland/protocols/mod.rs @@ -8,7 +8,6 @@ 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; diff --git a/src/wayland/protocols/session_lock_layer.rs b/src/wayland/protocols/session_lock_layer.rs deleted file mode 100644 index 85edda50..00000000 --- a/src/wayland/protocols/session_lock_layer.rs +++ /dev/null @@ -1,136 +0,0 @@ -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(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::( - 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 Fn(&'a Client) -> bool + Send + Sync>, -} - -impl GlobalDispatch2 - 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, - 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::() { - let mut state = states.cached_state.get::(); - state.current().show_on_lock - } else { - false - } - }) -} - -impl Dispatch2 - 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::(); - state.pending().show_on_lock = value; - }); - } - } -}