From 2c81b3fbc7ae66431acac8e71479ce567498ccc6 Mon Sep 17 00:00:00 2001 From: GallowsDove <71831019+GallowsDove@users.noreply.github.com> Date: Fri, 27 Dec 2024 00:44:06 +0100 Subject: [PATCH] feat: Add support for on-demand window focus on wayland (#1215) * feat: Add support for on-demand window focus on wayland * fix: cargo fmt * Update CHANGELOG.md with OnDemand focusable * fix: add v0_6 feature to gtk-layer-shell in eww/cargo.toml --- CHANGELOG.md | 1 + crates/eww/Cargo.toml | 2 +- crates/eww/src/display_backend.rs | 12 ++++-- .../yuck/src/config/backend_window_options.rs | 42 +++++++++++++++---- docs/src/configuration.md | 12 +++--- examples/data-structures/eww.yuck | 2 +- 6 files changed, 52 insertions(+), 19 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3710363e4..7ee0298bf 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -18,6 +18,7 @@ All notable changes to eww will be listed here, starting at changes since versio - Fix wayland monitor names support (By: dragonnn) ### Features +- Add OnDemand support for focusable on wayland (By: GallowsDove) - Update rust toolchain to 1.81.0 (By: w-lfchen) - Add `:fill-svg` and `:preserve-aspect-ratio` properties to images (By: hypernova7, w-lfchen) - Add `:truncate` property to labels, disabled by default (except in cases where truncation would be enabled in version `0.5.0` and before) (By: Rayzeq). diff --git a/crates/eww/Cargo.toml b/crates/eww/Cargo.toml index d934c455a..cd6e2e631 100644 --- a/crates/eww/Cargo.toml +++ b/crates/eww/Cargo.toml @@ -20,7 +20,7 @@ eww_shared_util.workspace = true yuck.workspace = true notifier_host.workspace = true -gtk-layer-shell = { version = "0.8.1", optional = true } +gtk-layer-shell = { version = "0.8.1", optional = true, features=["v0_6"] } gdkx11 = { version = "0.18", optional = true } x11rb = { version = "0.13.1", features = ["randr"], optional = true } gdk-sys = "0.18.0" diff --git a/crates/eww/src/display_backend.rs b/crates/eww/src/display_backend.rs index fe80dcbb0..87ca8aa8f 100644 --- a/crates/eww/src/display_backend.rs +++ b/crates/eww/src/display_backend.rs @@ -28,14 +28,14 @@ impl DisplayBackend for NoBackend { #[cfg(feature = "wayland")] mod platform_wayland { + use super::DisplayBackend; use crate::{widgets::window::Window, window_initiator::WindowInitiator}; use gtk::gdk; use gtk::prelude::*; - use gtk_layer_shell::LayerShell; + use gtk_layer_shell::{KeyboardMode, LayerShell}; + use yuck::config::backend_window_options::WlWindowFocusable; use yuck::config::{window_definition::WindowStacking, window_geometry::AnchorAlignment}; - use super::DisplayBackend; - pub struct WaylandBackend; impl DisplayBackend for WaylandBackend { @@ -70,7 +70,11 @@ mod platform_wayland { } // Sets the keyboard interactivity - window.set_keyboard_interactivity(window_init.backend_options.wayland.focusable); + match window_init.backend_options.wayland.focusable { + WlWindowFocusable::None => window.set_keyboard_mode(KeyboardMode::None), + WlWindowFocusable::Exclusive => window.set_keyboard_mode(KeyboardMode::Exclusive), + WlWindowFocusable::OnDemand => window.set_keyboard_mode(KeyboardMode::OnDemand), + } if let Some(geometry) = window_init.geometry { // Positioning surface diff --git a/crates/yuck/src/config/backend_window_options.rs b/crates/yuck/src/config/backend_window_options.rs index 1314664ae..bb6f28c6a 100644 --- a/crates/yuck/src/config/backend_window_options.rs +++ b/crates/yuck/src/config/backend_window_options.rs @@ -7,6 +7,7 @@ use simplexpr::{ SimplExpr, }; +use super::{attributes::Attributes, window_definition::EnumParseError}; use crate::{ enum_parse, error::DiagResult, @@ -14,8 +15,7 @@ use crate::{ value::{coords, NumWithUnit}, }; use eww_shared_util::{Span, VarName}; - -use super::{attributes::Attributes, window_definition::EnumParseError}; +use simplexpr::dynval::ConversionError; use crate::error::{DiagError, DiagResultExt}; @@ -27,6 +27,8 @@ pub enum Error { CoordsError(#[from] coords::Error), #[error(transparent)] EvalError(#[from] EvalError), + #[error(transparent)] + ConversionError(#[from] ConversionError), } /// Backend-specific options of a window @@ -45,6 +47,7 @@ impl BackendWindowOptionsDef { pub fn from_attrs(attrs: &mut Attributes) -> DiagResult { let struts = attrs.ast_optional("reserve")?; let window_type = attrs.ast_optional("windowtype")?; + let focusable = attrs.ast_optional("focusable")?; let x11 = X11BackendWindowOptionsDef { sticky: attrs.ast_optional("sticky")?, struts, @@ -53,7 +56,7 @@ impl BackendWindowOptionsDef { }; let wayland = WlBackendWindowOptionsDef { exclusive: attrs.ast_optional("exclusive")?, - focusable: attrs.ast_optional("focusable")?, + focusable, namespace: attrs.ast_optional("namespace")?, }; @@ -109,7 +112,7 @@ impl X11BackendWindowOptionsDef { #[derive(Debug, Clone, PartialEq, Eq, serde::Serialize)] pub struct WlBackendWindowOptions { pub exclusive: bool, - pub focusable: bool, + pub focusable: WlWindowFocusable, pub namespace: Option, } @@ -122,10 +125,13 @@ pub struct WlBackendWindowOptionsDef { } impl WlBackendWindowOptionsDef { - fn eval(&self, local_variables: &HashMap) -> Result { + fn eval(&self, local_variables: &HashMap) -> Result { Ok(WlBackendWindowOptions { exclusive: eval_opt_expr_as_bool(&self.exclusive, false, local_variables)?, - focusable: eval_opt_expr_as_bool(&self.focusable, false, local_variables)?, + focusable: match &self.focusable { + Some(expr) => WlWindowFocusable::from_dynval(&expr.eval(local_variables)?)?, + None => WlWindowFocusable::default(), + }, namespace: match &self.namespace { Some(expr) => Some(expr.eval(local_variables)?.as_string()?), None => None, @@ -145,6 +151,28 @@ fn eval_opt_expr_as_bool( }) } +#[derive(Debug, Clone, PartialEq, Eq, smart_default::SmartDefault, serde::Serialize)] +pub enum WlWindowFocusable { + #[default] + None, + Exclusive, + OnDemand, +} +impl FromStr for WlWindowFocusable { + type Err = EnumParseError; + + fn from_str(s: &str) -> Result { + enum_parse! { "focusable", s, + "none" => Self::None, + "exclusive" => Self::Exclusive, + "ondemand" => Self::OnDemand, + // legacy support + "true" => Self::Exclusive, + "false" => Self::None, + } + } +} + /// Window type of an x11 window #[derive(Debug, Clone, PartialEq, Eq, smart_default::SmartDefault, serde::Serialize)] pub enum X11WindowType { @@ -182,7 +210,7 @@ pub enum Side { Bottom, } -impl std::str::FromStr for Side { +impl FromStr for Side { type Err = EnumParseError; fn from_str(s: &str) -> Result { diff --git a/docs/src/configuration.md b/docs/src/configuration.md index 78775e15a..0cc16dabd 100644 --- a/docs/src/configuration.md +++ b/docs/src/configuration.md @@ -86,12 +86,12 @@ Depending on if you are using X11 or Wayland, some additional properties exist: #### Wayland -| Property | Description | -| ----------: | ------------------------------------------------------------ | -| `stacking` | Where the window should appear in the stack. Possible values: `fg`, `bg`, `overlay`, `bottom`. | -| `exclusive` | Whether the compositor should reserve space for the window automatically. Either `true` or `false`. | -| `focusable` | Whether the window should be able to be focused. This is necessary for any widgets that use the keyboard to work. Either `true` or `false`. | -| `namespace` | Set the wayland layersurface namespace eww uses. Accepts a `string` value. | +| Property | Description | +| ----------: |------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| `stacking` | Where the window should appear in the stack. Possible values: `fg`, `bg`, `overlay`, `bottom`. | +| `exclusive` | Whether the compositor should reserve space for the window automatically. Either `true` or `false`. | +| `focusable` | Whether the window should be able to be focused. This is necessary for any widgets that use the keyboard to work. Possible values: `none`, `exclusive` and `ondemand`. | +| `namespace` | Set the wayland layersurface namespace eww uses. Accepts a `string` value. | diff --git a/examples/data-structures/eww.yuck b/examples/data-structures/eww.yuck index c7ad9746c..f1a3416f7 100644 --- a/examples/data-structures/eww.yuck +++ b/examples/data-structures/eww.yuck @@ -65,7 +65,7 @@ (defwindow data-structures :monitor 0 :exclusive false - :focusable false + :focusable none :geometry (geometry :anchor "center" )