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
This commit is contained in:
GallowsDove 2024-12-27 00:44:06 +01:00 committed by GitHub
parent 95124ad274
commit 2c81b3fbc7
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
6 changed files with 52 additions and 19 deletions

View file

@ -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).

View file

@ -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"

View file

@ -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

View file

@ -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<Self> {
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<String>,
}
@ -122,10 +125,13 @@ pub struct WlBackendWindowOptionsDef {
}
impl WlBackendWindowOptionsDef {
fn eval(&self, local_variables: &HashMap<VarName, DynVal>) -> Result<WlBackendWindowOptions, EvalError> {
fn eval(&self, local_variables: &HashMap<VarName, DynVal>) -> Result<WlBackendWindowOptions, Error> {
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<Self, Self::Err> {
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<Side, Self::Err> {

View file

@ -87,10 +87,10 @@ 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`. |
| `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. |

View file

@ -65,7 +65,7 @@
(defwindow data-structures
:monitor 0
:exclusive false
:focusable false
:focusable none
:geometry (geometry
:anchor "center"
)