git.lucas.co / cce-system-interface
system settings
git clone https://git.lucas.co/cce-system-interface.git

commit3bf4ce621b4db1fc9218db0429676b17f1055362
parent754958a962
authorLucas Galante <[email protected]>
date2026-06-26 09:58
Optimize scrolling performance on Interface page by caching layout status asynchronously

 src/main.rs            |  8 ++++++++
 src/pages/interface.rs | 56 +++++++++++++++++++++++++++++---------------------
 src/watchers.rs        | 28 +++++++++++++++++++++++++
 3 files changed, 69 insertions(+), 23 deletions(-)

diff --git a/src/main.rs b/src/main.rs
index 92559ef..1459322 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -183,6 +183,7 @@ struct SystemInterface {
     rx_services: std::sync::mpsc::Receiver<Vec<pages::processes::ServiceInfo>>,
     rx_interface: std::sync::mpsc::Receiver<pages::interface::InterfaceState>,
     rx_accounts: std::sync::mpsc::Receiver<Vec<pages::accounts::AccountInfo>>,
+    rx_layout_status: std::sync::mpsc::Receiver<pages::interface::LayoutStatusInfo>,
     tx_backup: std::sync::mpsc::Sender<pages::storage::StorageMessage>,
     rx_backup: std::sync::mpsc::Receiver<pages::storage::StorageMessage>,
     rx_packages: std::sync::mpsc::Receiver<pages::packages::PackagesState>,
@@ -285,6 +286,7 @@ impl cce_ui::engine::Application for SystemInterface {
             rx_services: watchers.rx_services,
             rx_interface: watchers.rx_interface,
             rx_accounts: watchers.rx_accounts,
+            rx_layout_status: watchers.rx_layout_status,
             tx_backup,
             rx_backup,
             rx_packages: watchers.rx_packages,
@@ -725,6 +727,12 @@ fn collect_popover_rects(w: &dyn cce_ui::widget::Element, popovers: &mut Vec<(f3
                 self.needs_rebuild = true;
             }
         }
+        while let Ok(s) = self.rx_layout_status.try_recv() {
+            interface::update(&mut self.app.interface, pages::interface::InterfaceMessage::LayoutStatusRefreshed(s));
+            if self.app.current_page == Page::Interface {
+                self.needs_rebuild = true;
+            }
+        }
         while let Ok(s) = self.rx_accounts.try_recv() {
             accounts::update(&mut self.app.accounts, accounts::AccountsMessage::Refreshed(s));
             if self.app.current_page == Page::Accounts {
diff --git a/src/pages/interface.rs b/src/pages/interface.rs
index df3d3ac..0fdcac1 100644
--- a/src/pages/interface.rs
+++ b/src/pages/interface.rs
@@ -384,6 +384,7 @@ pub struct InterfaceState {
     pub graph_gap_width: u16,
     pub graph_gap_width_spinbox: Spinbox,
     pub custom_multicontrol: MultiControl,
+    pub layout_status: Option<LayoutStatusInfo>,
 }
 
 impl Default for InterfaceState {
@@ -570,6 +571,7 @@ impl Default for InterfaceState {
             status_module_spacing: 8,
             status_module_spacing_spinbox: Spinbox::new(8, 0, 100, 1).with_label("Spacing").with_unit("px").with_config(CONFIG_PATH, "status_module_spacing"),
             custom_multicontrol: MultiControl::new("custom_parameters".to_string()).with_label("custom_parameters"),
+            layout_status: None,
         }
     }
 }
@@ -675,6 +677,7 @@ pub enum InterfaceMessage {
     PickLayerColor,
     Refreshed(InterfaceState),
     TypefaceRefreshed(InterfaceState),
+    LayoutStatusRefreshed(LayoutStatusInfo),
     SetSans(String),
     SetSerif(String),
     SetMono(String),
@@ -977,6 +980,7 @@ pub fn read_interface_config() -> InterfaceState {
         backplate_corner_radius,
         backplate_corner_radius_spinbox: Spinbox::new(backplate_corner_radius as i32, 0, 100, 1).with_label("Corner Radius").with_unit("px").with_config(CONFIG_PATH, "backplate_corner_radius"),
         custom_multicontrol: MultiControl::new("custom_parameters".to_string()).with_label("custom_parameters"),
+        layout_status: None,
     }
 }
 
@@ -1200,29 +1204,30 @@ fn apply_edge_gap(val: u16) {
     send_ipc_command(&format!("layout gap_bottom {}", val));
 }
 
-#[derive(Debug, Clone)]
+#[derive(Debug, Clone, Default)]
 #[allow(dead_code)]
-struct PreviewWindow {
-    app_id: String,
-    title: String,
-    x: f32,
-    y: f32,
-    w: f32,
-    h: f32,
-    tags: u32,
-    _minimized: bool,
-    has_parent: bool,
-    layout_mode: String,
-}
-
+pub struct PreviewWindow {
+    pub app_id: String,
+    pub title: String,
+    pub x: f32,
+    pub y: f32,
+    pub w: f32,
+    pub h: f32,
+    pub tags: u32,
+    pub _minimized: bool,
+    pub has_parent: bool,
+    pub layout_mode: String,
+}
+
+#[derive(Debug, Clone, Default)]
 #[allow(dead_code)]
-struct LayoutStatusInfo {
-    active_tags: u32,
-    focused_tags: u32,
-    _num_tags: u32,
-    windows: Vec<PreviewWindow>,
-    focused_title: String,
-    focused_layout_mode: String,
+pub struct LayoutStatusInfo {
+    pub active_tags: u32,
+    pub focused_tags: u32,
+    pub _num_tags: u32,
+    pub windows: Vec<PreviewWindow>,
+    pub focused_title: String,
+    pub focused_layout_mode: String,
 }
 
 fn get_closest_tag(x: f64, y: f64) -> i32 {
@@ -1241,7 +1246,7 @@ fn get_closest_tag(x: f64, y: f64) -> i32 {
     best_tag
 }
 
-fn read_current_layout_status() -> LayoutStatusInfo {
+pub fn read_current_layout_status() -> LayoutStatusInfo {
     let mut active_tags = 1;
     let mut focused_tags = 1;
     let mut _num_tags = 4;
@@ -3109,7 +3114,7 @@ pub fn view(state: &mut InterfaceState, cx: f32, cy: f32, cw: f32, ch: f32, sec_
         sec.add_section("Current Layout", false, |sec_cl| {
             sec_cl.spacing(8.0);
             
-            let info = read_current_layout_status();
+            let info = state.layout_status.as_ref().cloned().unwrap_or_default();
             
             let card_w = (sec_w - 24.0) / 2.0;
             let card_h = 135.0;
@@ -3626,6 +3631,7 @@ pub fn update(state: &mut InterfaceState, msg: InterfaceMessage) {
         }
         InterfaceMessage::PickLowColor | InterfaceMessage::PickHighColor | InterfaceMessage::PickDisabledColor | InterfaceMessage::PickVisualGuides | InterfaceMessage::PickSliderTrackColor | InterfaceMessage::PickPageLowColor | InterfaceMessage::PickColorBordersColor | InterfaceMessage::PickNormalColor | InterfaceMessage::PickPaginatorSidebarColor | InterfaceMessage::PickPrimaryHighlightColor | InterfaceMessage::PickMenubarTabLabelColor | InterfaceMessage::PickToggleEnabledColor | InterfaceMessage::PickToggleDisabledColor | InterfaceMessage::PickScrollingListBgColor | InterfaceMessage::PickScrollingListEntryBgColor | InterfaceMessage::PickScrollingListEntryHighlightColor | InterfaceMessage::PickBreadcrumbBgColor | InterfaceMessage::PickPopoverBgColor | InterfaceMessage::PickNotificationBgColor | InterfaceMessage::PickWindowColor | InterfaceMessage::PickPageColor | InterfaceMessage::PickLayerColor => {}
         InterfaceMessage::Refreshed(new) => {
+            let layout_status = state.layout_status.clone();
             let was_bp_hovered = state.button_padding_spinbox.hovered();
             let was_bss_hovered = state.button_strip_spacing_spinbox.hovered();
             let was_sp_hovered = state.section_padding_spinbox.hovered();
@@ -3691,6 +3697,7 @@ pub fn update(state: &mut InterfaceState, msg: InterfaceMessage) {
             let terminal_size_box = state.terminal_size_box.clone();
 
             *state = new;
+            state.layout_status = layout_status;
 
             state.button_padding_spinbox.set_hovered(was_bp_hovered);
             state.button_strip_spacing_spinbox.set_hovered(was_bss_hovered);
@@ -3799,6 +3806,9 @@ pub fn update(state: &mut InterfaceState, msg: InterfaceMessage) {
             state.fuzzel_size_box = new.fuzzel_size_box;
             state.terminal_size_box = new.terminal_size_box;
         }
+        InterfaceMessage::LayoutStatusRefreshed(s) => {
+            state.layout_status = Some(s);
+        }
         InterfaceMessage::SetSans(sans) => {
             state.sans_serif = sans.clone();
             state.sans_box.text = sans;
diff --git a/src/watchers.rs b/src/watchers.rs
index 8a97368..036e39f 100644
--- a/src/watchers.rs
+++ b/src/watchers.rs
@@ -21,6 +21,7 @@ pub struct Watchers {
     pub rx_interface: Receiver<interface::InterfaceState>,
     pub rx_accounts: Receiver<Vec<accounts::AccountInfo>>,
     pub rx_packages: Receiver<packages::PackagesState>,
+    pub rx_layout_status: Receiver<interface::LayoutStatusInfo>,
 }
 
 fn spawn_bg_active<T, F>(
@@ -215,6 +216,32 @@ pub fn spawn_all(
         rx
     };
 
+    let rx_layout_status = {
+        let (tx, rx) = channel::<interface::LayoutStatusInfo>();
+        let current_page_shared = current_page_shared.clone();
+        tokio::spawn(async move {
+            let mut last_fetch: Option<std::time::Instant> = None;
+            loop {
+                let current_page = current_page_shared.load(Ordering::SeqCst);
+                if current_page == 4 { // Interface is index 4
+                    let should_fetch = match last_fetch {
+                        None => true,
+                        Some(t) => t.elapsed() >= std::time::Duration::from_millis(250),
+                    };
+                    if should_fetch {
+                        let val = tokio::task::spawn_blocking(|| interface::read_current_layout_status()).await;
+                        if let Ok(val) = val {
+                            if tx.send(val).is_err() { break; }
+                        }
+                        last_fetch = Some(std::time::Instant::now());
+                    }
+                }
+                tokio::time::sleep(std::time::Duration::from_millis(50)).await;
+            }
+        });
+        rx
+    };
+
     let (tx_backup, rx_backup) = channel();
     let rx_packages = spawn_bg_active(current_page_shared.clone(), 5, 30, || packages::fetch_packages_state());
     let (tx_update, rx_update) = channel();
@@ -237,6 +264,7 @@ pub fn spawn_all(
             rx_interface,
             rx_accounts,
             rx_packages,
+            rx_layout_status,
         },
         tx_backup,
         rx_backup,