From 23df9228a91b87df2493062d1f4d1e9b41c98733 Mon Sep 17 00:00:00 2001 From: galister <22305755+galister@users.noreply.github.com> Date: Sat, 20 Dec 2025 17:42:18 +0900 Subject: [PATCH] persist BackendAttrib across sessions --- wlx-common/src/config.rs | 21 ++------ wlx-common/src/overlays.rs | 36 ++++++++++++++ wlx-overlay-s/src/backend/mod.rs | 1 + wlx-overlay-s/src/backend/openvr/lines.rs | 4 +- wlx-overlay-s/src/config.rs | 8 ++- wlx-overlay-s/src/gui/panel/mod.rs | 4 +- wlx-overlay-s/src/overlays/edit/mod.rs | 9 ++-- wlx-overlay-s/src/overlays/edit/mouse.rs | 52 +++++++++----------- wlx-overlay-s/src/overlays/edit/stereo.rs | 10 ++-- wlx-overlay-s/src/overlays/keyboard/mod.rs | 6 +-- wlx-overlay-s/src/overlays/mirror.rs | 16 ++++-- wlx-overlay-s/src/overlays/screen/backend.rs | 35 ++++++++----- wlx-overlay-s/src/overlays/screen/capture.rs | 4 +- wlx-overlay-s/src/overlays/screen/pw.rs | 2 +- wlx-overlay-s/src/overlays/screen/wl.rs | 4 +- wlx-overlay-s/src/overlays/screen/x11.rs | 3 +- wlx-overlay-s/src/overlays/wayvr.rs | 5 +- wlx-overlay-s/src/windowing/backend.rs | 24 +-------- wlx-overlay-s/src/windowing/manager.rs | 28 ++++++++++- 19 files changed, 158 insertions(+), 114 deletions(-) diff --git a/wlx-common/src/config.rs b/wlx-common/src/config.rs index c3462b7..0845d5f 100644 --- a/wlx-common/src/config.rs +++ b/wlx-common/src/config.rs @@ -1,13 +1,12 @@ use std::{collections::HashMap, sync::Arc}; use chrono::Offset; -use glam::Affine3A; use idmap::IdMap; use serde::{Deserialize, Serialize}; use crate::{ astr_containers::{AStrMap, AStrSet}, - overlays::{ToastDisplayMethod, ToastTopic}, + overlays::{BackendAttribValue, ToastDisplayMethod, ToastTopic}, windowing::OverlayWindowState, }; @@ -92,11 +91,7 @@ const fn def_astrset_empty() -> AStrSet { AStrSet::new() } -const fn def_curve_values() -> AStrMap { - AStrMap::new() -} - -const fn def_transforms() -> AStrMap { +const fn def_attribs() -> AStrMap> { AStrMap::new() } @@ -134,6 +129,9 @@ pub struct GeneralConfig { pub color_faded: Option, pub default_keymap: Option, + #[serde(default = "def_attribs")] + pub attribs: AStrMap>, + #[serde(default = "def_click_freeze_time_ms")] pub click_freeze_time_ms: u32, @@ -194,15 +192,6 @@ pub struct GeneralConfig { #[serde(default = "def_astrset_empty")] pub custom_panels: AStrSet, - #[serde(default = "def_astrset_empty")] - pub show_screens: AStrSet, - - #[serde(default = "def_curve_values")] - pub curve_values: AStrMap, - - #[serde(default = "def_transforms")] - pub transform_values: AStrMap, - #[serde(default = "def_auto")] pub capture_method: Arc, diff --git a/wlx-common/src/overlays.rs b/wlx-common/src/overlays.rs index 3663ee4..150f16b 100644 --- a/wlx-common/src/overlays.rs +++ b/wlx-common/src/overlays.rs @@ -15,3 +15,39 @@ pub enum ToastDisplayMethod { Center, Watch, } + +#[derive(Clone, Copy)] +pub enum BackendAttrib { + Stereo, + MouseTransform, +} + +#[derive(Debug, Clone, Serialize, Deserialize)] +pub enum BackendAttribValue { + Stereo(StereoMode), + MouseTransform(MouseTransform), +} + +#[derive(Default, Debug, Clone, Copy, Serialize, Deserialize)] +pub enum StereoMode { + #[default] + None, + LeftRight, + RightLeft, + TopBottom, + BottomTop, +} + +#[derive(Default, Debug, Clone, Copy, Serialize, Deserialize)] +pub enum MouseTransform { + #[default] + Default, + Normal, + Rotated90, + Rotated180, + Rotated270, + Flipped, + Flipped90, + Flipped180, + Flipped270, +} diff --git a/wlx-overlay-s/src/backend/mod.rs b/wlx-overlay-s/src/backend/mod.rs index f3f1c52..39b7d55 100644 --- a/wlx-overlay-s/src/backend/mod.rs +++ b/wlx-overlay-s/src/backend/mod.rs @@ -15,6 +15,7 @@ pub mod task; use thiserror::Error; +#[derive(Clone, Copy)] pub enum XrBackend { OpenXR, OpenVR, diff --git a/wlx-overlay-s/src/backend/openvr/lines.rs b/wlx-overlay-s/src/backend/openvr/lines.rs index 100eb65..8545d9f 100644 --- a/wlx-overlay-s/src/backend/openvr/lines.rs +++ b/wlx-overlay-s/src/backend/openvr/lines.rs @@ -21,14 +21,14 @@ use vulkano::{ }, }; use wgui::gfx::WGfx; +use wlx_common::overlays::{BackendAttrib, BackendAttribValue}; use crate::backend::input::{HoverResult, PointerHit}; use crate::state::AppState; use crate::subsystem::hid::WheelDelta; use crate::windowing::Z_ORDER_LINES; use crate::windowing::backend::{ - BackendAttrib, BackendAttribValue, FrameMeta, OverlayBackend, OverlayEventData, - RenderResources, ShouldRender, + FrameMeta, OverlayBackend, OverlayEventData, RenderResources, ShouldRender, }; use crate::windowing::window::{OverlayWindowConfig, OverlayWindowData}; diff --git a/wlx-overlay-s/src/config.rs b/wlx-overlay-s/src/config.rs index 84a6507..62cbd6b 100644 --- a/wlx-overlay-s/src/config.rs +++ b/wlx-overlay-s/src/config.rs @@ -3,7 +3,11 @@ use config::{Config, File}; use log::error; use serde::{Deserialize, Serialize}; use std::path::PathBuf; -use wlx_common::config::{GeneralConfig, SerializedWindowSet, SerializedWindowStates}; +use wlx_common::{ + astr_containers::AStrMap, + config::{GeneralConfig, SerializedWindowSet, SerializedWindowStates}, + overlays::BackendAttribValue, +}; const FALLBACKS: [&str; 2] = [ include_str!("res/keyboard.yaml"), @@ -140,6 +144,7 @@ pub struct AutoState { pub sets: Vec, pub global_set: SerializedWindowStates, pub last_set: u32, + pub attribs: AStrMap>, } fn get_state_path() -> PathBuf { @@ -153,6 +158,7 @@ pub fn save_state(config: &GeneralConfig) -> anyhow::Result<()> { sets: config.sets.clone(), last_set: config.last_set, global_set: config.global_set.clone(), + attribs: config.attribs.clone(), }; let json = serde_json::to_string_pretty(&conf).unwrap(); // want panic diff --git a/wlx-overlay-s/src/gui/panel/mod.rs b/wlx-overlay-s/src/gui/panel/mod.rs index b461750..3cfb4c6 100644 --- a/wlx-overlay-s/src/gui/panel/mod.rs +++ b/wlx-overlay-s/src/gui/panel/mod.rs @@ -18,6 +18,7 @@ use wgui::{ renderer_vk::context::Context as WguiContext, widget::{EventResult, label::WidgetLabel}, }; +use wlx_common::overlays::{BackendAttrib, BackendAttribValue}; use wlx_common::timestep::Timestep; use crate::{ @@ -25,8 +26,7 @@ use crate::{ state::AppState, subsystem::hid::WheelDelta, windowing::backend::{ - BackendAttrib, BackendAttribValue, FrameMeta, OverlayBackend, OverlayEventData, - RenderResources, ShouldRender, ui_transform, + FrameMeta, OverlayBackend, OverlayEventData, RenderResources, ShouldRender, ui_transform, }, }; diff --git a/wlx-overlay-s/src/overlays/edit/mod.rs b/wlx-overlay-s/src/overlays/edit/mod.rs index 8fd0b07..7aadf95 100644 --- a/wlx-overlay-s/src/overlays/edit/mod.rs +++ b/wlx-overlay-s/src/overlays/edit/mod.rs @@ -14,7 +14,7 @@ use wgui::{ parser::Fetchable, widget::EventResult, }; -use wlx_capture::frame::Transform; +use wlx_common::overlays::{BackendAttrib, BackendAttribValue, MouseTransform, StereoMode}; use crate::{ attrib_value, @@ -35,10 +35,7 @@ use crate::{ subsystem::hid::WheelDelta, windowing::{ OverlayID, OverlaySelector, - backend::{ - BackendAttrib, BackendAttribValue, DummyBackend, OverlayBackend, OverlayEventData, - RenderResources, ShouldRender, StereoMode, - }, + backend::{DummyBackend, OverlayBackend, OverlayEventData, RenderResources, ShouldRender}, window::OverlayWindowConfig, }, }; @@ -69,7 +66,7 @@ struct EditModeState { lock: InteractLockHandler, pos: SpriteTabHandler, stereo: SpriteTabHandler, - mouse: SpriteTabHandler, + mouse: SpriteTabHandler, } type EditModeWrapPanel = GuiPanel; diff --git a/wlx-overlay-s/src/overlays/edit/mouse.rs b/wlx-overlay-s/src/overlays/edit/mouse.rs index 6c008c3..d4449a0 100644 --- a/wlx-overlay-s/src/overlays/edit/mouse.rs +++ b/wlx-overlay-s/src/overlays/edit/mouse.rs @@ -1,12 +1,8 @@ -use wlx_capture::frame::Transform; - -use crate::{ - overlays::edit::{ - EditModeWrapPanel, - sprite_tab::{SpriteTabHandler, SpriteTabKey}, - }, - windowing::backend::BackendAttribValue, +use crate::overlays::edit::{ + EditModeWrapPanel, + sprite_tab::{SpriteTabHandler, SpriteTabKey}, }; +use wlx_common::overlays::{BackendAttribValue, MouseTransform}; static MOUSE_NAMES: [&str; 9] = [ "default", @@ -22,7 +18,7 @@ static MOUSE_NAMES: [&str; 9] = [ pub fn new_mouse_tab_handler( panel: &mut EditModeWrapPanel, -) -> anyhow::Result> { +) -> anyhow::Result> { SpriteTabHandler::new( panel, "mouse", @@ -38,32 +34,32 @@ pub fn new_mouse_tab_handler( ) } -impl SpriteTabKey for Transform { +impl SpriteTabKey for MouseTransform { fn to_tab_key(&self) -> &'static str { match self { - Transform::Undefined => "default", - Transform::Normal => "normal", - Transform::Rotated90 => "rotate90", - Transform::Rotated180 => "rotate180", - Transform::Rotated270 => "rotate270", - Transform::Flipped => "flipped", - Transform::Flipped90 => "flip90", - Transform::Flipped180 => "flip180", - Transform::Flipped270 => "flip270", + MouseTransform::Default => "default", + MouseTransform::Normal => "normal", + MouseTransform::Rotated90 => "rotate90", + MouseTransform::Rotated180 => "rotate180", + MouseTransform::Rotated270 => "rotate270", + MouseTransform::Flipped => "flipped", + MouseTransform::Flipped90 => "flip90", + MouseTransform::Flipped180 => "flip180", + MouseTransform::Flipped270 => "flip270", } } fn from_tab_key(key: &str) -> Self { match key { - "default" => Transform::Undefined, - "normal" => Transform::Normal, - "rotate90" => Transform::Rotated90, - "rotate180" => Transform::Rotated180, - "rotate270" => Transform::Rotated270, - "flipped" => Transform::Flipped, - "flip90" => Transform::Flipped90, - "flip180" => Transform::Flipped180, - "flip270" => Transform::Flipped270, + "default" => MouseTransform::Default, + "normal" => MouseTransform::Normal, + "rotate90" => MouseTransform::Rotated90, + "rotate180" => MouseTransform::Rotated180, + "rotate270" => MouseTransform::Rotated270, + "flipped" => MouseTransform::Flipped, + "flip90" => MouseTransform::Flipped90, + "flip180" => MouseTransform::Flipped180, + "flip270" => MouseTransform::Flipped270, _ => { panic!("cannot translate to mouse transform: {key}") } diff --git a/wlx-overlay-s/src/overlays/edit/stereo.rs b/wlx-overlay-s/src/overlays/edit/stereo.rs index 658b115..ab4b76d 100644 --- a/wlx-overlay-s/src/overlays/edit/stereo.rs +++ b/wlx-overlay-s/src/overlays/edit/stereo.rs @@ -1,10 +1,8 @@ -use crate::{ - overlays::edit::{ - EditModeWrapPanel, - sprite_tab::{SpriteTabHandler, SpriteTabKey}, - }, - windowing::backend::{BackendAttribValue, StereoMode}, +use crate::overlays::edit::{ + EditModeWrapPanel, + sprite_tab::{SpriteTabHandler, SpriteTabKey}, }; +use wlx_common::overlays::{BackendAttribValue, StereoMode}; static STEREO_NAMES: [&str; 5] = ["none", "leftright", "rightleft", "topbottom", "bottomtop"]; diff --git a/wlx-overlay-s/src/overlays/keyboard/mod.rs b/wlx-overlay-s/src/overlays/keyboard/mod.rs index 9470e33..88b70bb 100644 --- a/wlx-overlay-s/src/overlays/keyboard/mod.rs +++ b/wlx-overlay-s/src/overlays/keyboard/mod.rs @@ -16,10 +16,7 @@ use crate::{ get_keymap_wl, get_keymap_x11, }, windowing::{ - backend::{ - BackendAttrib, BackendAttribValue, FrameMeta, OverlayBackend, OverlayEventData, - RenderResources, ShouldRender, - }, + backend::{FrameMeta, OverlayBackend, OverlayEventData, RenderResources, ShouldRender}, window::{OverlayCategory, OverlayWindowConfig}, }, }; @@ -31,6 +28,7 @@ use wgui::{ drawing, event::{InternalStateChangeEvent, MouseButton, MouseButtonIndex}, }; +use wlx_common::overlays::{BackendAttrib, BackendAttribValue}; use wlx_common::windowing::{OverlayWindowState, Positioning}; pub mod builder; diff --git a/wlx-overlay-s/src/overlays/mirror.rs b/wlx-overlay-s/src/overlays/mirror.rs index 5f4c59d..e54e601 100644 --- a/wlx-overlay-s/src/overlays/mirror.rs +++ b/wlx-overlay-s/src/overlays/mirror.rs @@ -9,7 +9,10 @@ use std::{ use futures::{Future, FutureExt}; use glam::{Affine2, Affine3A, Quat, Vec3, vec3}; use wlx_capture::pipewire::{PipewireCapture, PipewireSelectScreenResult, pipewire_select_screen}; -use wlx_common::windowing::OverlayWindowState; +use wlx_common::{ + overlays::{BackendAttrib, BackendAttribValue}, + windowing::OverlayWindowState, +}; use crate::{ backend::{ @@ -21,8 +24,8 @@ use crate::{ windowing::{ OverlaySelector, backend::{ - BackendAttrib, BackendAttribValue, FrameMeta, OverlayBackend, OverlayEventData, - RenderResources, ShouldRender, ui_transform, + FrameMeta, OverlayBackend, OverlayEventData, RenderResources, ShouldRender, + ui_transform, }, window::{OverlayCategory, OverlayWindowConfig}, }, @@ -76,8 +79,11 @@ impl OverlayBackend for MirrorBackend { let node_id = pw_result.streams.first().unwrap().node_id; // streams guaranteed to have at least one element log::info!("{}: PipeWire node selected: {}", self.name.clone(), node_id); let capture = PipewireCapture::new(self.name.clone(), node_id); - self.renderer = - Some(ScreenBackend::new_raw(self.name.clone(), Box::new(capture))); + self.renderer = Some(ScreenBackend::new_raw( + self.name.clone(), + app.xr_backend, + Box::new(capture), + )); app.tasks.enqueue(TaskType::Overlay(OverlayTask::Modify( OverlaySelector::Name(self.name.clone()), Box::new(|app, o| { diff --git a/wlx-overlay-s/src/overlays/screen/backend.rs b/wlx-overlay-s/src/overlays/screen/backend.rs index 170c1a2..6241b56 100644 --- a/wlx-overlay-s/src/overlays/screen/backend.rs +++ b/wlx-overlay-s/src/overlays/screen/backend.rs @@ -15,10 +15,10 @@ use crate::{ state::AppState, subsystem::hid::{MOUSE_LEFT, MOUSE_MIDDLE, MOUSE_RIGHT, WheelDelta}, windowing::backend::{ - BackendAttrib, BackendAttribValue, FrameMeta, OverlayBackend, OverlayEventData, - RenderResources, ShouldRender, StereoMode, ui_transform, + FrameMeta, OverlayBackend, OverlayEventData, RenderResources, ShouldRender, ui_transform, }, }; +use wlx_common::overlays::{BackendAttrib, BackendAttribValue, MouseTransform, StereoMode}; use super::capture::{ScreenPipeline, WlxCaptureIn, WlxCaptureOut, receive_callback}; @@ -50,12 +50,13 @@ pub struct ScreenBackend { pub(super) logical_pos: Vec2, pub(super) logical_size: Vec2, pub(super) mouse_transform_original: Transform, - mouse_transform_override: Transform, + mouse_transform_override: MouseTransform, } impl ScreenBackend { pub fn new_raw( name: Arc, + xr_backend: XrBackend, capture: Box>, ) -> Self { Self { @@ -66,11 +67,15 @@ impl ScreenBackend { meta: None, mouse_transform: Affine2::ZERO, interaction_transform: None, - stereo: None, + stereo: if matches!(xr_backend, XrBackend::OpenXR) { + Some(StereoMode::None) + } else { + None + }, logical_pos: Vec2::ZERO, logical_size: Vec2::ZERO, mouse_transform_original: Transform::Undefined, - mouse_transform_override: Transform::Undefined, + mouse_transform_override: MouseTransform::Default, } } @@ -125,12 +130,7 @@ impl ScreenBackend { } impl OverlayBackend for ScreenBackend { - fn init(&mut self, app: &mut AppState) -> anyhow::Result<()> { - self.stereo = if matches!(app.xr_backend, XrBackend::OpenXR) { - Some(StereoMode::None) - } else { - None - }; + fn init(&mut self, _app: &mut AppState) -> anyhow::Result<()> { Ok(()) } fn should_render(&mut self, app: &mut AppState) -> anyhow::Result { @@ -317,7 +317,18 @@ impl OverlayBackend for ScreenBackend { } BackendAttribValue::MouseTransform(new) => { self.mouse_transform_override = new; - self.apply_mouse_transform_with_override(new); + let frame_transform = match new { + MouseTransform::Default => Transform::Undefined, + MouseTransform::Normal => Transform::Normal, + MouseTransform::Rotated90 => Transform::Rotated90, + MouseTransform::Rotated180 => Transform::Rotated180, + MouseTransform::Rotated270 => Transform::Rotated270, + MouseTransform::Flipped => Transform::Flipped, + MouseTransform::Flipped90 => Transform::Flipped90, + MouseTransform::Flipped180 => Transform::Flipped180, + MouseTransform::Flipped270 => Transform::Flipped270, + }; + self.apply_mouse_transform_with_override(frame_transform); true } _ => false, diff --git a/wlx-overlay-s/src/overlays/screen/capture.rs b/wlx-overlay-s/src/overlays/screen/capture.rs index a5a7a27..baee1c3 100644 --- a/wlx-overlay-s/src/overlays/screen/capture.rs +++ b/wlx-overlay-s/src/overlays/screen/capture.rs @@ -20,7 +20,7 @@ use wlx_capture::{ WlxCapture, frame::{self as wlx_frame, DrmFormat, FrameFormat, MouseMeta, Transform, WlxFrame}, }; -use wlx_common::config::GeneralConfig; +use wlx_common::{config::GeneralConfig, overlays::StereoMode}; use crate::{ graphics::{ @@ -29,7 +29,7 @@ use crate::{ upload_quad_vertices, }, state::AppState, - windowing::backend::{FrameMeta, RenderResources, StereoMode}, + windowing::backend::{FrameMeta, RenderResources}, }; const CURSOR_SIZE: f32 = 16. / 1440.; diff --git a/wlx-overlay-s/src/overlays/screen/pw.rs b/wlx-overlay-s/src/overlays/screen/pw.rs index f071bce..112c946 100644 --- a/wlx-overlay-s/src/overlays/screen/pw.rs +++ b/wlx-overlay-s/src/overlays/screen/pw.rs @@ -49,7 +49,7 @@ impl ScreenBackend { PipewireCapture::new(name, node_id) ); Ok(( - Self::new_raw(output.name.clone(), capture), + Self::new_raw(output.name.clone(), app.xr_backend, capture), select_screen_result.restore_token, )) } diff --git a/wlx-overlay-s/src/overlays/screen/wl.rs b/wlx-overlay-s/src/overlays/screen/wl.rs index 771a103..fe77b97 100644 --- a/wlx-overlay-s/src/overlays/screen/wl.rs +++ b/wlx-overlay-s/src/overlays/screen/wl.rs @@ -27,7 +27,7 @@ impl ScreenBackend { app.gfx_extras.queue_capture, WlrDmabufCapture::new(client, output.id) ); - Some(Self::new_raw(output.name.clone(), capture)) + Some(Self::new_raw(output.name.clone(), app.xr_backend, capture)) } pub fn new_wlr_screencopy(output: &WlxOutput, app: &AppState) -> Option { @@ -36,7 +36,7 @@ impl ScreenBackend { app.gfx_extras.queue_capture, WlrScreencopyCapture::new(client, output.id) ); - Some(Self::new_raw(output.name.clone(), capture)) + Some(Self::new_raw(output.name.clone(), app.xr_backend, capture)) } } diff --git a/wlx-overlay-s/src/overlays/screen/x11.rs b/wlx-overlay-s/src/overlays/screen/x11.rs index c3f9ee8..3401610 100644 --- a/wlx-overlay-s/src/overlays/screen/x11.rs +++ b/wlx-overlay-s/src/overlays/screen/x11.rs @@ -27,7 +27,7 @@ impl ScreenBackend { app.gfx_extras.queue_capture, XshmCapture::new(screen.clone()) ); - Self::new_raw(screen.name.clone(), capture) + Self::new_raw(screen.name.clone(), app.xr_backend, capture) } } @@ -97,6 +97,7 @@ pub fn create_screens_x11pw(app: &mut AppState) -> anyhow::Result; 2]>, } @@ -109,18 +99,6 @@ macro_rules! attrib_value { }; } -#[derive(Clone, Copy)] -pub enum BackendAttrib { - Stereo, - MouseTransform, -} - -#[derive(Debug, Clone)] -pub enum BackendAttribValue { - Stereo(StereoMode), - MouseTransform(Transform), -} - pub struct OverlayMeta { pub id: OverlayID, pub name: Arc, diff --git a/wlx-overlay-s/src/windowing/manager.rs b/wlx-overlay-s/src/windowing/manager.rs index 59a7f24..57bbbdc 100644 --- a/wlx-overlay-s/src/windowing/manager.rs +++ b/wlx-overlay-s/src/windowing/manager.rs @@ -8,7 +8,7 @@ use slotmap::{HopSlotMap, Key, SecondaryMap}; use wlx_common::{ astr_containers::{AStrMap, AStrMapExt}, config::SerializedWindowSet, - overlays::ToastTopic, + overlays::{BackendAttrib, ToastTopic}, }; use crate::{ @@ -277,6 +277,8 @@ where } } +const SAVED_ATTRIBS: [BackendAttrib; 2] = [BackendAttrib::Stereo, BackendAttrib::MouseTransform]; + impl OverlayWindowManager { pub fn pop_dropped(&mut self) -> Option> { self.dropped_overlays.pop_front() @@ -334,6 +336,17 @@ impl OverlayWindowManager { .insert(o.config.name.clone(), state.clone()); } + // BackendAttrib + for o in self.overlays.values() { + app.session.config.attribs.arc_set( + o.config.name.clone(), + SAVED_ATTRIBS + .iter() + .filter_map(|a| o.config.backend.get_attrib(*a)) + .collect(), + ); + } + if restore_after { self.switch_to_set(app, Some(self.restore_set)); } @@ -389,6 +402,19 @@ impl OverlayWindowManager { } } + for (name, attribs) in &app.session.config.attribs.clone() { + let Some(oid) = self.lookup(&*name) else { + continue; + }; + let Some(o) = self.mut_by_id(oid) else { + continue; + }; + + for value in attribs { + o.config.backend.set_attrib(app, value.clone()); + } + } + self.restore_set = (app.session.config.last_set as usize).min(self.sets.len() - 1); }