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

commit993c6c2fae7f019e7a4445e0f3fb4a4a7cdc7608
parent72b4c6ea11
authorLucas Galante <[email protected]>
date2026-06-21 21:52
Merge Services page into Processes page, implement automated event propagation, and scrolling list clipping

 src/app.rs             |  102 +-
 src/input_handler.rs   | 3662 +++++-------------------------------------------
 src/main.rs            |   39 +-
 src/pages/hardware.rs  |  637 ---------
 src/pages/interface.rs |   54 +
 src/pages/mod.rs       |   14 +-
 src/pages/network.rs   |    4 +-
 src/pages/packages.rs  |    6 +-
 src/pages/processes.rs | 1524 ++++++++++++++++++++
 src/pages/services.rs  |  894 ------------
 src/renderer.rs        |   78 +-
 src/watchers.rs        |   44 +-
 12 files changed, 2129 insertions(+), 4929 deletions(-)

diff --git a/src/app.rs b/src/app.rs
index 0478dd9..d0eb14e 100644
--- a/src/app.rs
+++ b/src/app.rs
@@ -4,10 +4,9 @@ use crate::pages::audio;
 use crate::pages::display;
 use crate::pages::input;
 use crate::pages::network;
-use crate::pages::hardware;
+use crate::pages::processes;
 use crate::pages::system_info;
 use crate::pages::storage;
-use crate::pages::services;
 use crate::pages::interface;
 use crate::pages::accounts;
 use crate::pages::packages;
@@ -19,10 +18,9 @@ pub struct AppState {
     pub display: display::DisplayState,
     pub network: network::NetworkState,
     pub input: input::InputState,
-    pub hardware: hardware::HardwareState,
+    pub processes: processes::ProcessesState,
     pub system_info: system_info::SystemState,
     pub storage: storage::StorageState,
-    pub services: services::ServicesState,
     pub interface: interface::InterfaceState,
     pub accounts: accounts::AccountsState,
     pub packages: packages::PackagesState,
@@ -36,10 +34,9 @@ impl Default for AppState {
             display: display::DisplayState::default(),
             network: network::NetworkState::default(),
             input: input::InputState::default(),
-            hardware: hardware::HardwareState::default(),
+            processes: processes::ProcessesState::default(),
             system_info: system_info::SystemState::default(),
             storage: storage::StorageState::default(),
-            services: services::ServicesState::default(),
             interface: interface::InterfaceState::default(),
             accounts: accounts::AccountsState::default_mock(),
             packages: packages::PackagesState::default(),
@@ -54,10 +51,9 @@ pub enum AppAction {
     Display(display::DisplayMessage),
     Radios(network::NetworkMessage),
     Input(input::InputMessage),
-    Hardware(hardware::HardwareMessage),
+    Processes(processes::ProcessesMessage),
     SystemInfo(system_info::SystemMessage),
     Storage(storage::StorageMessage),
-    Services(services::ServicesMessage),
     Interface(interface::InterfaceMessage),
     Accounts(accounts::AccountsMessage),
     Packages(packages::PackagesMessage),
@@ -69,23 +65,64 @@ pub struct PageContent {
     pub rects: Vec<([f32; 4], f32, f32, f32, f32, f32, (bool, bool, bool, bool))>,
     pub texts: Vec<(String, f32, f32, f32, [f32; 4], Option<String>, Option<[f32; 4]>)>,
     pub buttons: Vec<(cce_ui::widget::Button, AppAction)>,
+    pub clip_stack: Vec<[f32; 4]>,
 }
 
 impl PageContent {
     pub fn new() -> Self {
-        Self { rects: Vec::new(), texts: Vec::new(), buttons: Vec::new() }
+        Self { rects: Vec::new(), texts: Vec::new(), buttons: Vec::new(), clip_stack: Vec::new() }
+    }
+
+    fn get_clipped_rect(&self, x: f32, y: f32, w: f32, h: f32) -> Option<(f32, f32, f32, f32)> {
+        if let Some(&clip) = self.clip_stack.last() {
+            let cx = clip[0];
+            let cy = clip[1];
+            let cw = clip[2];
+            let ch = clip[3];
+            let rx1 = x.max(cx);
+            let ry1 = y.max(cy);
+            let rx2 = (x + w).min(cx + cw);
+            let ry2 = (y + h).min(cy + ch);
+            if rx1 < rx2 && ry1 < ry2 {
+                Some((rx1, ry1, rx2 - rx1, ry2 - ry1))
+            } else {
+                None
+            }
+        } else {
+            Some((x, y, w, h))
+        }
+    }
+
+    fn get_clipped_bounds(&self, bounds: Option<[f32; 4]>) -> Option<[f32; 4]> {
+        if let Some(&clip) = self.clip_stack.last() {
+            if let Some(b) = bounds {
+                let rx1 = b[0].max(clip[0]);
+                let ry1 = b[1].max(clip[1]);
+                let rx2 = b[2].min(clip[0] + clip[2]);
+                let ry2 = b[3].min(clip[1] + clip[3]);
+                Some([rx1, ry1, rx2.max(rx1), ry2.max(ry1)])
+            } else {
+                Some([clip[0], clip[1], clip[0] + clip[2], clip[1] + clip[3]])
+            }
+        } else {
+            bounds
+        }
     }
 
     pub fn rect(&mut self, color: [f32; 4], x: f32, y: f32, w: f32, h: f32) {
-        self.rects.push((color, x, y, w, h, 0.0, (true, true, true, true)));
+        if let Some((cx, cy, cw, ch)) = self.get_clipped_rect(x, y, w, h) {
+            self.rects.push((color, cx, cy, cw, ch, 0.0, (true, true, true, true)));
+        }
     }
 
     pub fn text(&mut self, content: &str, x: f32, y: f32, size: f32, color: [f32; 4]) {
-        self.texts.push((content.to_string(), size, x, y, color, None, None));
+        let cb = self.get_clipped_bounds(None);
+        self.texts.push((content.to_string(), size, x, y, color, None, cb));
     }
 
     pub fn text_with_font(&mut self, content: &str, x: f32, y: f32, size: f32, color: [f32; 4], font: &str) {
-        self.texts.push((content.to_string(), size, x, y, color, Some(font.to_string()), None));
+        let cb = self.get_clipped_bounds(None);
+        self.texts.push((content.to_string(), size, x, y, color, Some(font.to_string()), cb));
     }
 
     pub fn button(&mut self, label: &str, x: f32, y: f32, w: f32, h: f32,
@@ -114,31 +151,58 @@ impl PageContent {
 
 impl RenderTarget for PageContent {
     fn rect(&mut self, color: [f32; 4], x: f32, y: f32, w: f32, h: f32) {
-        self.rects.push((color, x, y, w, h, 0.0, (true, true, true, true)));
+        if let Some((cx, cy, cw, ch)) = self.get_clipped_rect(x, y, w, h) {
+            self.rects.push((color, cx, cy, cw, ch, 0.0, (true, true, true, true)));
+        }
     }
 
     fn rect_with_radius(&mut self, color: [f32; 4], x: f32, y: f32, w: f32, h: f32, radius: f32) {
-        self.rects.push((color, x, y, w, h, radius, (true, true, true, true)));
+        if let Some((cx, cy, cw, ch)) = self.get_clipped_rect(x, y, w, h) {
+            self.rects.push((color, cx, cy, cw, ch, radius, (true, true, true, true)));
+        }
     }
 
     fn rect_with_radius_corners(&mut self, color: [f32; 4], x: f32, y: f32, w: f32, h: f32, radius: f32, corners: (bool, bool, bool, bool)) {
-        self.rects.push((color, x, y, w, h, radius, corners));
+        if let Some((cx, cy, cw, ch)) = self.get_clipped_rect(x, y, w, h) {
+            self.rects.push((color, cx, cy, cw, ch, radius, corners));
+        }
     }
 
     fn text(&mut self, content: &str, x: f32, y: f32, size: f32, color: [f32; 4]) {
-        self.texts.push((content.to_string(), size, x, y, color, None, None));
+        let cb = self.get_clipped_bounds(None);
+        self.texts.push((content.to_string(), size, x, y, color, None, cb));
     }
 
     fn text_with_font(&mut self, content: &str, x: f32, y: f32, size: f32, color: [f32; 4], font: &str) {
-        self.texts.push((content.to_string(), size, x, y, color, Some(font.to_string()), None));
+        let cb = self.get_clipped_bounds(None);
+        self.texts.push((content.to_string(), size, x, y, color, Some(font.to_string()), cb));
     }
 
     fn text_with_bounds(&mut self, content: &str, x: f32, y: f32, size: f32, color: [f32; 4], bounds: Option<[f32; 4]>) {
-        self.texts.push((content.to_string(), size, x, y, color, None, bounds));
+        let cb = self.get_clipped_bounds(bounds);
+        self.texts.push((content.to_string(), size, x, y, color, None, cb));
     }
 
     fn text_with_font_and_bounds(&mut self, content: &str, x: f32, y: f32, size: f32, color: [f32; 4], font: &str, bounds: Option<[f32; 4]>) {
-        self.texts.push((content.to_string(), size, x, y, color, Some(font.to_string()), bounds));
+        let cb = self.get_clipped_bounds(bounds);
+        self.texts.push((content.to_string(), size, x, y, color, Some(font.to_string()), cb));
+    }
+
+    fn push_clip_rect(&mut self, x: f32, y: f32, w: f32, h: f32) {
+        let clip = if let Some(&parent_clip) = self.clip_stack.last() {
+            let cx = x.max(parent_clip[0]);
+            let cy = y.max(parent_clip[1]);
+            let cw = (x + w).min(parent_clip[0] + parent_clip[2]) - cx;
+            let ch = (y + h).min(parent_clip[1] + parent_clip[3]) - cy;
+            [cx, cy, cw.max(0.0), ch.max(0.0)]
+        } else {
+            [x, y, w, h]
+        };
+        self.clip_stack.push(clip);
+    }
+
+    fn pop_clip_rect(&mut self) {
+        self.clip_stack.pop();
     }
 }
 
diff --git a/src/input_handler.rs b/src/input_handler.rs
index cfe29a5..a038d4a 100644
--- a/src/input_handler.rs
+++ b/src/input_handler.rs
@@ -30,300 +30,12 @@ impl SystemInterface {
         if self.switcher.cursor_moved(lx_no_scroll, ly_no_scroll, &mut self.ui_context) {
             changed = true;
         }
-        for w in &mut self.widgets {
-            let was = w.hovering;
-            w.hovering = self.cursor_x >= w.x && self.cursor_x <= w.x + w.w
-                && self.cursor_y >= w.y && self.cursor_y <= w.y + w.h;
-            if w.hovering != was {
-                w.color = if w.hovering { w.hover_color } else { w.color };
-                changed = true;
-            }
-        }
-
-        if self.app.current_page == Page::Interface {
-            for cp in &mut self.app.interface.color_selectors {
-                if cp.cursor_moved(lx, ly, &mut self.ui_context) {
-                    changed = true;
-                }
-            }
-            if self.app.interface.menubar_opacity_spinbox.cursor_moved(lx, ly, &mut self.ui_context) {
-                changed = true;
-            }
-            if self.app.interface.button_padding_spinbox.cursor_moved(lx, ly, &mut self.ui_context) {
-                changed = true;
-            }
-            if self.app.interface.section_padding_spinbox.cursor_moved(lx, ly, &mut self.ui_context) {
-                changed = true;
-            }
-            if self.app.interface.label_alignment_menu.cursor_moved(lx, ly, &mut self.ui_context) {
-                changed = true;
-            }
-            if self.app.interface.label_offset_spinbox.cursor_moved(lx, ly, &mut self.ui_context) {
-                changed = true;
-            }
-            if self.app.interface.label_margin_spinbox.cursor_moved(lx, ly, &mut self.ui_context) {
-                changed = true;
-            }
-            if self.app.interface.plate_padding_spinbox.cursor_moved(lx, ly, &mut self.ui_context) {
-                changed = true;
-            }
-            if self.app.interface.graph_show_grid_toggle.cursor_moved(lx, ly, &mut self.ui_context) {
-                changed = true;
-            }
-            if self.app.interface.graph_snap_enabled_toggle.cursor_moved(lx, ly, &mut self.ui_context) {
-                changed = true;
-            }
-            if self.app.interface.graph_uniform_background_toggle.cursor_moved(lx, ly, &mut self.ui_context) {
-                changed = true;
-            }
-            if self.app.interface.graph_cell_opacity_spinbox.cursor_moved(lx, ly, &mut self.ui_context) {
-                changed = true;
-            }
-            if self.app.interface.graph_gap_opacity_spinbox.cursor_moved(lx, ly, &mut self.ui_context) {
-                changed = true;
-            }
-            if self.app.interface.graph_gap_width_spinbox.cursor_moved(lx, ly, &mut self.ui_context) {
-                changed = true;
-            }
-            if self.app.interface.page_margin_spinbox.cursor_moved(lx, ly, &mut self.ui_context) {
-                changed = true;
-            }
-            if self.app.interface.grid_min_col_width_spinbox.cursor_moved(lx, ly, &mut self.ui_context) {
-                changed = true;
-            }
-            if self.app.interface.spinbox_height_spinbox.cursor_moved(lx, ly, &mut self.ui_context) {
-                changed = true;
-            }
-            if self.app.interface.spinbox_corner_radius_spinbox.cursor_moved(lx, ly, &mut self.ui_context) {
-                changed = true;
-            }
-            if self.app.interface.toggle_height_spinbox.cursor_moved(lx, ly, &mut self.ui_context) {
-                changed = true;
-            }
-            if self.app.interface.toggle_corner_radius_spinbox.cursor_moved(lx, ly, &mut self.ui_context) {
-                changed = true;
-            }
-            if self.app.interface.plate_opacity_spinbox.cursor_moved(lx, ly, &mut self.ui_context) {
-                changed = true;
-            }
-            if self.app.interface.plate_corner_radius_spinbox.cursor_moved(lx, ly, &mut self.ui_context) {
-                changed = true;
-            }
-            if self.app.interface.page_opacity_spinbox.cursor_moved(lx, ly, &mut self.ui_context) {
-                changed = true;
-            }
-            if self.app.interface.layer_opacity_spinbox.cursor_moved(lx, ly, &mut self.ui_context) {
-                changed = true;
-            }
-
 
-            if self.app.interface.color_selector_height_spinbox.cursor_moved(lx, ly, &mut self.ui_context) {
-                changed = true;
-            }
-            if self.app.interface.color_selector_corner_radius_spinbox.cursor_moved(lx, ly, &mut self.ui_context) {
-                changed = true;
-            }
-            if self.app.interface.color_selector_preview_corner_radius_spinbox.cursor_moved(lx, ly, &mut self.ui_context) {
-                changed = true;
-            }
-            if self.app.interface.color_selector_preview_margin_spinbox.cursor_moved(lx, ly, &mut self.ui_context) {
-                changed = true;
-            }
-            if self.app.interface.color_selector_font_selector.cursor_moved(lx, ly, &mut self.ui_context) {
-                changed = true;
-            }
-            if self.app.interface.menubar_font_selector.cursor_moved(lx, ly, &mut self.ui_context) {
-                changed = true;
-            }
-            if self.app.interface.breadcrumb_font_selector.cursor_moved(lx, ly, &mut self.ui_context) {
-                changed = true;
-            }
-            if self.app.interface.section_label_font_selector.cursor_moved(lx, ly, &mut self.ui_context) {
-                changed = true;
-            }
-            if self.app.interface.nested_section_label_font_selector.cursor_moved(lx, ly, &mut self.ui_context) {
-                changed = true;
-            }
-            if self.app.interface.textbox_height_spinbox.cursor_moved(lx, ly, &mut self.ui_context) {
-                changed = true;
-            }
-            if self.app.interface.textbox_corner_radius_spinbox.cursor_moved(lx, ly, &mut self.ui_context) {
-                changed = true;
-            }
-            if self.app.interface.slider_height_spinbox.cursor_moved(lx, ly, &mut self.ui_context) {
-                changed = true;
-            }
-            if self.app.interface.font_selector_height_spinbox.cursor_moved(lx, ly, &mut self.ui_context) {
-                changed = true;
-            }
-            if self.app.interface.font_selector_corner_radius_spinbox.cursor_moved(lx, ly, &mut self.ui_context) {
-                changed = true;
-            }
-            if self.app.interface.dropdown_height_spinbox.cursor_moved(lx, ly, &mut self.ui_context) {
-                changed = true;
-            }
-            if self.app.interface.dropdown_corner_radius_spinbox.cursor_moved(lx, ly, &mut self.ui_context) {
-                changed = true;
-            }
-            if self.app.interface.button_corner_radius_spinbox.cursor_moved(lx, ly, &mut self.ui_context) {
-                changed = true;
-            }
-            if self.app.interface.notification_opacity_spinbox.cursor_moved(lx, ly, &mut self.ui_context) {
-                changed = true;
-            }
-            if self.app.interface.window_opacity_spinbox.cursor_moved(lx, ly, &mut self.ui_context) {
-                changed = true;
-            }
-            if self.app.interface.window_corner_radius_spinbox.cursor_moved(lx, ly, &mut self.ui_context) {
-                changed = true;
-            }
-            if self.app.interface.sans_box.cursor_moved(lx, ly, &mut self.ui_context) {
-                changed = true;
-            }
-            if self.app.interface.serif_box.cursor_moved(lx, ly, &mut self.ui_context) {
-                changed = true;
-            }
-            if self.app.interface.mono_box.cursor_moved(lx, ly, &mut self.ui_context) {
-                changed = true;
-            }
-            if self.app.interface.borders_menu.cursor_moved(lx, ly, &mut self.ui_context) {
-                changed = true;
-            }
-            if self.app.interface.borders_box.cursor_moved(lx, ly, &mut self.ui_context) {
-                changed = true;
-            }
-            if self.app.interface.status_menu.cursor_moved(lx, ly, &mut self.ui_context) {
-                changed = true;
-            }
-            if self.app.interface.status_box.cursor_moved(lx, ly, &mut self.ui_context) {
-                changed = true;
-            }
-            if self.app.interface.fuzzel_menu.cursor_moved(lx, ly, &mut self.ui_context) {
-                changed = true;
-            }
-            if self.app.interface.fuzzel_box.cursor_moved(lx, ly, &mut self.ui_context) {
-                changed = true;
-            }
-            if self.app.interface.terminal_menu.cursor_moved(lx, ly, &mut self.ui_context) {
-                changed = true;
-            }
-            if self.app.interface.terminal_box.cursor_moved(lx, ly, &mut self.ui_context) {
-                changed = true;
-            }
-            if self.app.interface.borders_size_box.cursor_moved(lx, ly, &mut self.ui_context) {
-                changed = true;
-            }
-            if self.app.interface.status_size_box.cursor_moved(lx, ly, &mut self.ui_context) {
-                changed = true;
-            }
-            if self.app.interface.fuzzel_size_box.cursor_moved(lx, ly, &mut self.ui_context) {
-                changed = true;
-            }
-            if self.app.interface.terminal_size_box.cursor_moved(lx, ly, &mut self.ui_context) {
-                changed = true;
-            }
-            if self.app.interface.custom_multicontrol.cursor_moved(lx, ly, &mut self.ui_context) {
-                changed = true;
-            }
-            for sb in &mut self.app.interface.windows.spinboxes {
-                if sb.cursor_moved(lx, ly, &mut self.ui_context) {
-                    changed = true;
-                }
-            }
-            if self.app.interface.windows.cascade_offset_spinbox.cursor_moved(lx, ly, &mut self.ui_context) {
-                changed = true;
-            }
-            if self.app.interface.windows.edge_gap_spinbox.cursor_moved(lx, ly, &mut self.ui_context) {
-                changed = true;
-            }
-            if self.app.interface.windows.top_gap_spinbox.cursor_moved(lx, ly, &mut self.ui_context) {
-                changed = true;
-            }
-            if self.app.interface.windows.grid_gap_spinbox.cursor_moved(lx, ly, &mut self.ui_context) {
-                changed = true;
-            }
-            if self.app.interface.windows.transition_duration_spinbox.cursor_moved(lx, ly, &mut self.ui_context) {
-                changed = true;
-            }
-            if self.app.interface.windows.status_height_spinbox.cursor_moved(lx, ly, &mut self.ui_context) {
-                changed = true;
-            }
-            for menu in &mut self.app.interface.windows.tag_layout_menus {
-                if menu.cursor_moved(lx, ly, &mut self.ui_context) {
-                    changed = true;
-                }
-            }
-            if self.app.interface.windows.side_panel_behavior_menu.cursor_moved(lx, ly, &mut self.ui_context) {
-                changed = true;
-            }
-            if self.app.interface.windows.side_panel_position_menu.cursor_moved(lx, ly, &mut self.ui_context) {
-                changed = true;
-            }
-            if self.app.interface.windows.side_panel_width_spinbox.cursor_moved(lx, ly, &mut self.ui_context) {
-                changed = true;
-            }
-            if self.app.interface.windows.side_panel_border_gap_spinbox.cursor_moved(lx, ly, &mut self.ui_context) {
-                changed = true;
-            }
-            if self.app.interface.windows.side_panel_border_opacity_spinbox.cursor_moved(lx, ly, &mut self.ui_context) {
-                changed = true;
-            }
-            if self.app.interface.windows.transparency_toggle.cursor_moved(lx, ly, &mut self.ui_context) {
-                changed = true;
-            }
-            if self.app.interface.windows.blur_toggle.cursor_moved(lx, ly, &mut self.ui_context) {
-                changed = true;
-            }
-        }
-        if self.app.current_page == Page::Input {
-            if self.app.input.rate_spinbox.cursor_moved(lx, ly, &mut self.ui_context) {
-                changed = true;
-            }
-            if self.app.input.delay_spinbox.cursor_moved(lx, ly, &mut self.ui_context) {
-                changed = true;
-            }
-            if self.app.input.tap_toggle.cursor_moved(lx, ly, &mut self.ui_context) {
-                changed = true;
-            }
-            if self.app.input.scroll_toggle.cursor_moved(lx, ly, &mut self.ui_context) {
-                changed = true;
-            }
-            if self.app.input.scroll_friction_spinbox.cursor_moved(lx, ly, &mut self.ui_context) {
-                changed = true;
-            }
-            if self.app.input.pointer_toggle.cursor_moved(lx, ly, &mut self.ui_context) {
-                changed = true;
-            }
-            if self.app.input.pointer_friction_spinbox.cursor_moved(lx, ly, &mut self.ui_context) {
-                changed = true;
-            }
-            if self.app.input.trackpad_toggle.cursor_moved(lx, ly, &mut self.ui_context) {
-                changed = true;
-            }
-            if self.app.input.trackpad_friction_spinbox.cursor_moved(lx, ly, &mut self.ui_context) {
-                changed = true;
-            }
-            if self.app.input.dwtp_toggle.cursor_moved(lx, ly, &mut self.ui_context) {
-                changed = true;
-            }
-            if self.app.input.trackpoint_accel_speed_spinbox.cursor_moved(lx, ly, &mut self.ui_context) {
-                changed = true;
-            }
-            if self.app.input.trackpoint_accel_profile_menu.cursor_moved(lx, ly, &mut self.ui_context) {
-                changed = true;
-            }
-            if self.app.input.zoom_in_box.cursor_moved(lx, ly, &mut self.ui_context) {
-                changed = true;
-            }
-            if self.app.input.zoom_out_box.cursor_moved(lx, ly, &mut self.ui_context) {
-                changed = true;
-            }
-            if self.app.input.keybinds_control.cursor_moved(lx, ly, &mut self.ui_context) {
-                changed = true;
-            }
-        }
+        // Drag updates are high-priority overrides
+        let mut drag_handled = false;
         if self.app.current_page == Page::Audio {
             if let Some(idx) = self.audio_sink_dragging {
+                drag_handled = true;
                 if idx < self.app.audio.sink_sliders.len() {
                     if self.app.audio.sink_sliders[idx].drag_update(lx, ly) {
                         changed = true;
@@ -338,6 +50,7 @@ impl SystemInterface {
                     }
                 }
             } else if let Some(idx) = self.audio_source_dragging {
+                drag_handled = true;
                 if idx < self.app.audio.source_sliders.len() {
                     if self.app.audio.source_sliders[idx].drag_update(lx, ly) {
                         changed = true;
@@ -351,31 +64,11 @@ impl SystemInterface {
                         }
                     }
                 }
-            } else {
-                for sb in &mut self.app.audio.sink_spinboxes {
-                    if sb.cursor_moved(lx, ly, &mut self.ui_context) {
-                        changed = true;
-                    }
-                }
-                for sb in &mut self.app.audio.source_spinboxes {
-                    if sb.cursor_moved(lx, ly, &mut self.ui_context) {
-                        changed = true;
-                    }
-                }
-                for slider in &mut self.app.audio.sink_sliders {
-                    if slider.cursor_moved(lx, ly, &mut self.ui_context) {
-                        changed = true;
-                    }
-                }
-                for slider in &mut self.app.audio.source_sliders {
-                    if slider.cursor_moved(lx, ly, &mut self.ui_context) {
-                        changed = true;
-                    }
-                }
             }
         }
         if self.app.current_page == Page::Display {
             if self.display_brightness_dragging {
+                drag_handled = true;
                 if self.app.display.brightness_slider.drag_update(lx, ly) {
                     changed = true;
                     let val = self.app.display.brightness_slider.value();
@@ -383,172 +76,21 @@ impl SystemInterface {
                     self.app.display.brightness_spinbox.value = pct as i32;
                     self.handle_action(&AppAction::Display(pages::display::DisplayMessage::BrightnessSet(pct)));
                 }
-            } else {
-                if self.app.display.brightness_slider.cursor_moved(lx, ly, &mut self.ui_context) {
-                    changed = true;
-                }
-                if self.app.display.brightness_spinbox.cursor_moved(lx, ly, &mut self.ui_context) {
-                    changed = true;
-                }
-            }
-            if self.app.display.night_light_label.cursor_moved(lx, ly, &mut self.ui_context) {
-                changed = true;
-            }
-            for out in &mut self.app.display.outputs {
-                if out.name_label.cursor_moved(lx, ly, &mut self.ui_context) {
-                    changed = true;
-                }
-                if out.resolution_label.cursor_moved(lx, ly, &mut self.ui_context) {
-                    changed = true;
-                }
-                if let Some(ref mut scale_lbl) = out.scale_label {
-                    if scale_lbl.cursor_moved(lx, ly, &mut self.ui_context) {
-                        changed = true;
-                    }
-                }
-            }
-            if self.app.display.screensaver_enable_toggle.cursor_moved(lx, ly, &mut self.ui_context) {
-                changed = true;
-            }
-            if self.app.display.screensaver_lock_screen_toggle.cursor_moved(lx, ly, &mut self.ui_context) {
-                changed = true;
-            }
-            if self.app.display.screensaver_timeout_spinbox.cursor_moved(lx, ly, &mut self.ui_context) {
-                changed = true;
-            }
-            if self.app.display.screensaver_style_menu.cursor_moved(lx, ly, &mut self.ui_context) {
-                changed = true;
             }
         }
 
-        if self.app.current_page == Page::Hardware {
-            if self.app.hardware.cpu_label.cursor_moved(lx, ly, &mut self.ui_context) {
-                changed = true;
-            }
-            if self.app.hardware.cpu_usage_label.cursor_moved(lx, ly, &mut self.ui_context) {
-                changed = true;
-            }
-            if self.app.hardware.cpu_temp_label.cursor_moved(lx, ly, &mut self.ui_context) {
-                changed = true;
-            }
-            for gpu_lbl in &mut self.app.hardware.gpu_labels {
-                if gpu_lbl.cursor_moved(lx, ly, &mut self.ui_context) {
+        if !drag_handled {
+            let event = cce_ui::widget::Event::PointerMove { x: lx, y: ly };
+            if let Some(root) = self.get_page_root_widget() {
+                if self.ui_context.propagate_event(&event, root) {
                     changed = true;
                 }
             }
-            if self.app.hardware.cpu_list_box.cursor_moved(lx, ly, &mut self.ui_context) {
-                changed = true;
-            }
-            if self.app.hardware.cpu_gov_menu.cursor_moved(lx, ly, &mut self.ui_context) {
-                changed = true;
-            }
-            if self.app.hardware.gpu_gov_menu.cursor_moved(lx, ly, &mut self.ui_context) {
-                changed = true;
-            }
-        }
-
-        if self.app.current_page == Page::Packages {
-            let pkgs = &mut self.app.packages;
-            if pkgs.search_box.cursor_moved(lx, ly, &mut self.ui_context) {
-                changed = true;
-            }
-            match pkgs.active_tab {
-                pages::packages::PackageTab::Installed => {
-                    if pkgs.installed_list_box.cursor_moved(lx, ly, &mut self.ui_context) {
-                        changed = true;
-                    }
-                    let query = if pkgs.search_box.editing {
-                        pkgs.search_box.edit_buffer.to_lowercase()
-                    } else {
-                        pkgs.search_box.text.to_lowercase()
-                    };
-                    let matching = pkgs.installed.iter()
-                        .filter(|p| p.name.to_lowercase().contains(&query) || p.version.to_lowercase().contains(&query))
-                        .count();
-                    for i in 0..matching.min(pkgs.installed_items.len()) {
-                        if pkgs.installed_items[i].cursor_moved(lx, ly, &mut self.ui_context) {
-                            changed = true;
-                        }
-                    }
-                }
-                pages::packages::PackageTab::Updates => {
-                    if pkgs.updates_list_box.cursor_moved(lx, ly, &mut self.ui_context) {
-                        changed = true;
-                    }
-                    let query = if pkgs.search_box.editing {
-                        pkgs.search_box.edit_buffer.to_lowercase()
-                    } else {
-                        pkgs.search_box.text.to_lowercase()
-                    };
-                    let matching = pkgs.updates.iter()
-                        .filter(|p| p.name.to_lowercase().contains(&query))
-                        .count();
-                    for i in 0..matching.min(pkgs.updates_items.len()) {
-                        if pkgs.updates_items[i].cursor_moved(lx, ly, &mut self.ui_context) {
-                            changed = true;
-                        }
-                    }
-                }
-            }
         }
 
-
-
-        if self.app.current_page == Page::Services {
-            if self.app.services.search_box.cursor_moved(lx, ly, &mut self.ui_context) {
-                changed = true;
-            }
-            if self.app.services.list_box.cursor_moved(lx, ly, &mut self.ui_context) {
-                changed = true;
-            }
-            let query = if self.app.services.search_box.editing {
-                self.app.services.search_box.edit_buffer.to_lowercase()
-            } else {
-                self.app.services.search_box.text.to_lowercase()
-            };
-            let matching_count = self.app.services.services.iter()
-                .filter(|s| s.is_system == (self.app.services.active_tab == pages::services::ServiceTab::System))
-                .filter(|s| s.name.to_lowercase().contains(&query) || s.description.to_lowercase().contains(&query))
-                .count();
-            for i in 0..matching_count.min(self.app.services.service_items.len()) {
-                if self.app.services.service_items[i].cursor_moved(lx, ly, &mut self.ui_context) {
-                    changed = true;
-                }
-            }
-            if self.app.services.notifications_enable_toggle.cursor_moved(lx, ly, &mut self.ui_context) {
-                changed = true;
-            }
-            if self.app.services.notifications_bell_toggle.cursor_moved(lx, ly, &mut self.ui_context) {
-                changed = true;
-            }
-            if self.app.services.notifications_duration_spinbox.cursor_moved(lx, ly, &mut self.ui_context) {
-                changed = true;
-            }
-            if self.app.services.status_label.cursor_moved(lx, ly, &mut self.ui_context) {
-                changed = true;
-            }
-            if self.app.services.status_separators_toggle.cursor_moved(lx, ly, &mut self.ui_context) {
-                changed = true;
-            }
-            if self.app.services.status_underline_toggle.cursor_moved(lx, ly, &mut self.ui_context) {
-                changed = true;
-            }
-            if self.app.services.status_padding_spinbox.cursor_moved(lx, ly, &mut self.ui_context) {
-                changed = true;
-            }
-        }
-        if self.app.current_page == Page::Accounts {
-            if self.app.accounts.editing_oauth_creds {
-                if self.app.accounts.oauth_client_id_box.cursor_moved(lx, ly, &mut self.ui_context) { changed = true; }
-                if self.app.accounts.oauth_client_secret_box.cursor_moved(lx, ly, &mut self.ui_context) { changed = true; }
-            } else if self.app.accounts.adding_new {
-                if self.app.accounts.email_box.cursor_moved(lx, ly, &mut self.ui_context) { changed = true; }
-                if self.app.accounts.password_box.cursor_moved(lx, ly, &mut self.ui_context) { changed = true; }
-                if self.app.accounts.imap_box.cursor_moved(lx, ly, &mut self.ui_context) { changed = true; }
-                if self.app.accounts.smtp_box.cursor_moved(lx, ly, &mut self.ui_context) { changed = true; }
-            }
+        if changed {
+            self.needs_rebuild = true;
         }
-        if changed { self.needs_rebuild = true; }
         changed
     }
 
@@ -621,6 +163,7 @@ impl SystemInterface {
         }
 
         if button != cce_ui::widget::MouseButton::Left && button != cce_ui::widget::MouseButton::Right { return false; }
+        let mut actions = Vec::new();
         if button == cce_ui::widget::MouseButton::Left && state == cce_ui::widget::ElementState::Released {
             if self.app.current_page == Page::Audio {
                 let mut ended = false;
@@ -649,2769 +192,364 @@ impl SystemInterface {
                     self.needs_rebuild = true;
                 }
             }
-
-            let (px, py) = (self.cursor_x, self.cursor_y);
-            for (btn, action) in &self.page_buttons.clone() {
-                let base = btn.base().unwrap();
-                if px >= base.x && px <= base.x + base.w && py >= base.y && py <= base.y + base.h {
-                    self.handle_action(action);
-                    self.needs_rebuild = true;
-                    return true;
-                }
-            }
         }
+
         let lx = self.cursor_x / s;
         let ly = self.cursor_y / s + self.scroll_y;
-        let mut actions = Vec::new();
-
-        if state == cce_ui::widget::ElementState::Pressed {
-            let mut clicked_any_focusable = false;
-            match self.app.current_page {
-                Page::Accounts => {
-                    let accs = &mut self.app.accounts;
-                    if accs.editing_oauth_creds {
-                        if accs.oauth_client_id_box.hit_test(lx, ly, &self.ui_context) { clicked_any_focusable = true; }
-                        if accs.oauth_client_secret_box.hit_test(lx, ly, &self.ui_context) { clicked_any_focusable = true; }
-                    } else if accs.adding_new {
-                        if accs.email_box.hit_test(lx, ly, &self.ui_context) { clicked_any_focusable = true; }
-                        if accs.password_box.hit_test(lx, ly, &self.ui_context) { clicked_any_focusable = true; }
-                        if accs.imap_box.hit_test(lx, ly, &self.ui_context) { clicked_any_focusable = true; }
-                        if accs.smtp_box.hit_test(lx, ly, &self.ui_context) { clicked_any_focusable = true; }
-                    }
-                }
+        let event = cce_ui::widget::Event::MouseButton { button, state, x: lx, y: ly };
+        if let Some(root) = self.get_page_root_widget() {
+            self.ui_context.propagate_event(&event, root);
+        }
 
-                Page::Interface => {
-                    if self.app.interface.custom_multicontrol.hit_test(lx, ly, &self.ui_context) { clicked_any_focusable = true; }
-                    for cp in &mut self.app.interface.color_selectors {
-                        if cp.hit_test(lx, ly, &self.ui_context) { clicked_any_focusable = true; }
-                    }
-                    if self.app.interface.menubar_opacity_spinbox.hit_test(lx, ly, &self.ui_context) { clicked_any_focusable = true; }
-                    if self.app.interface.button_padding_spinbox.hit_test(lx, ly, &self.ui_context) { clicked_any_focusable = true; }
-                    if self.app.interface.section_padding_spinbox.hit_test(lx, ly, &self.ui_context) { clicked_any_focusable = true; }
-                    if self.app.interface.label_alignment_menu.hit_test(lx, ly, &self.ui_context) { clicked_any_focusable = true; }
-                    if self.app.interface.label_offset_spinbox.hit_test(lx, ly, &self.ui_context) { clicked_any_focusable = true; }
-                    if self.app.interface.label_margin_spinbox.hit_test(lx, ly, &self.ui_context) { clicked_any_focusable = true; }
-                    if self.app.interface.plate_padding_spinbox.hit_test(lx, ly, &self.ui_context) { clicked_any_focusable = true; }
-                    if self.app.interface.graph_show_grid_toggle.hit_test(lx, ly, &self.ui_context) { clicked_any_focusable = true; }
-                    if self.app.interface.graph_snap_enabled_toggle.hit_test(lx, ly, &self.ui_context) { clicked_any_focusable = true; }
-                    if self.app.interface.graph_uniform_background_toggle.hit_test(lx, ly, &self.ui_context) { clicked_any_focusable = true; }
-                    if self.app.interface.graph_cell_opacity_spinbox.hit_test(lx, ly, &self.ui_context) { clicked_any_focusable = true; }
-                    if self.app.interface.graph_gap_opacity_spinbox.hit_test(lx, ly, &self.ui_context) { clicked_any_focusable = true; }
-                    if self.app.interface.graph_gap_width_spinbox.hit_test(lx, ly, &self.ui_context) { clicked_any_focusable = true; }
-                    if self.app.interface.page_margin_spinbox.hit_test(lx, ly, &self.ui_context) { clicked_any_focusable = true; }
-                    if self.app.interface.grid_min_col_width_spinbox.hit_test(lx, ly, &self.ui_context) { clicked_any_focusable = true; }
-                    if self.app.interface.spinbox_height_spinbox.hit_test(lx, ly, &self.ui_context) { clicked_any_focusable = true; }
-                    if self.app.interface.spinbox_corner_radius_spinbox.hit_test(lx, ly, &self.ui_context) { clicked_any_focusable = true; }
-                    if self.app.interface.toggle_height_spinbox.hit_test(lx, ly, &self.ui_context) { clicked_any_focusable = true; }
-                    if self.app.interface.toggle_corner_radius_spinbox.hit_test(lx, ly, &self.ui_context) { clicked_any_focusable = true; }
-                    if self.app.interface.plate_opacity_spinbox.hit_test(lx, ly, &self.ui_context) { clicked_any_focusable = true; }
-                    if self.app.interface.plate_corner_radius_spinbox.hit_test(lx, ly, &self.ui_context) { clicked_any_focusable = true; }
-                    if self.app.interface.page_opacity_spinbox.hit_test(lx, ly, &self.ui_context) { clicked_any_focusable = true; }
-                    if self.app.interface.layer_opacity_spinbox.hit_test(lx, ly, &self.ui_context) { clicked_any_focusable = true; }
+        self.propagate_widget_changes(&mut actions);
 
+        for a in &actions {
+            self.handle_action(a);
+        }
+        if !actions.is_empty() {
+            self.needs_rebuild = true;
+            return true;
+        }
+        self.needs_rebuild = true;
+        true
+    }
 
-                    if self.app.interface.color_selector_height_spinbox.hit_test(lx, ly, &self.ui_context) { clicked_any_focusable = true; }
-                    if self.app.interface.color_selector_corner_radius_spinbox.hit_test(lx, ly, &self.ui_context) { clicked_any_focusable = true; }
-                    if self.app.interface.color_selector_preview_corner_radius_spinbox.hit_test(lx, ly, &self.ui_context) { clicked_any_focusable = true; }
-                    if self.app.interface.color_selector_preview_margin_spinbox.hit_test(lx, ly, &self.ui_context) { clicked_any_focusable = true; }
-                    if self.app.interface.color_selector_font_selector.hit_test(lx, ly, &self.ui_context) { clicked_any_focusable = true; }
-                    if self.app.interface.menubar_font_selector.hit_test(lx, ly, &self.ui_context) { clicked_any_focusable = true; }
-                    if self.app.interface.breadcrumb_font_selector.hit_test(lx, ly, &self.ui_context) { clicked_any_focusable = true; }
-                    if self.app.interface.section_label_font_selector.hit_test(lx, ly, &self.ui_context) { clicked_any_focusable = true; }
-                    if self.app.interface.nested_section_label_font_selector.hit_test(lx, ly, &self.ui_context) { clicked_any_focusable = true; }
-                    if self.app.interface.textbox_height_spinbox.hit_test(lx, ly, &self.ui_context) { clicked_any_focusable = true; }
-                    if self.app.interface.textbox_corner_radius_spinbox.hit_test(lx, ly, &self.ui_context) { clicked_any_focusable = true; }
-                    if self.app.interface.slider_height_spinbox.hit_test(lx, ly, &self.ui_context) { clicked_any_focusable = true; }
-                    if self.app.interface.font_selector_height_spinbox.hit_test(lx, ly, &self.ui_context) { clicked_any_focusable = true; }
-                    if self.app.interface.font_selector_corner_radius_spinbox.hit_test(lx, ly, &self.ui_context) { clicked_any_focusable = true; }
-                    if self.app.interface.dropdown_height_spinbox.hit_test(lx, ly, &self.ui_context) { clicked_any_focusable = true; }
-                    if self.app.interface.dropdown_corner_radius_spinbox.hit_test(lx, ly, &self.ui_context) { clicked_any_focusable = true; }
-                    if self.app.interface.button_corner_radius_spinbox.hit_test(lx, ly, &self.ui_context) { clicked_any_focusable = true; }
-                    if self.app.interface.notification_opacity_spinbox.hit_test(lx, ly, &self.ui_context) { clicked_any_focusable = true; }
-                    if self.app.interface.window_opacity_spinbox.hit_test(lx, ly, &self.ui_context) { clicked_any_focusable = true; }
-                    if self.app.interface.window_corner_radius_spinbox.hit_test(lx, ly, &self.ui_context) { clicked_any_focusable = true; }
-                    let tf = &mut self.app.interface;
-                    if tf.sans_box.hit_test(lx, ly, &self.ui_context) { clicked_any_focusable = true; }
-                    if tf.serif_box.hit_test(lx, ly, &self.ui_context) { clicked_any_focusable = true; }
-                    if tf.mono_box.hit_test(lx, ly, &self.ui_context) { clicked_any_focusable = true; }
-                    if tf.borders_menu.hit_test(lx, ly, &self.ui_context) { clicked_any_focusable = true; }
-                    if tf.borders_box.hit_test(lx, ly, &self.ui_context) { clicked_any_focusable = true; }
-                    if tf.status_menu.hit_test(lx, ly, &self.ui_context) { clicked_any_focusable = true; }
-                    if tf.status_box.hit_test(lx, ly, &self.ui_context) { clicked_any_focusable = true; }
-                    if tf.fuzzel_menu.hit_test(lx, ly, &self.ui_context) { clicked_any_focusable = true; }
-                    if tf.fuzzel_box.hit_test(lx, ly, &self.ui_context) { clicked_any_focusable = true; }
-                    if tf.terminal_menu.hit_test(lx, ly, &self.ui_context) { clicked_any_focusable = true; }
-                    if tf.terminal_box.hit_test(lx, ly, &self.ui_context) { clicked_any_focusable = true; }
-                    for sb in &mut tf.windows.spinboxes {
-                        if sb.hit_test(lx, ly, &self.ui_context) { clicked_any_focusable = true; }
-                    }
-                    if tf.windows.cascade_offset_spinbox.hit_test(lx, ly, &self.ui_context) { clicked_any_focusable = true; }
-                    if tf.windows.edge_gap_spinbox.hit_test(lx, ly, &self.ui_context) { clicked_any_focusable = true; }
-                    if tf.windows.top_gap_spinbox.hit_test(lx, ly, &self.ui_context) { clicked_any_focusable = true; }
-                    if tf.windows.grid_gap_spinbox.hit_test(lx, ly, &self.ui_context) { clicked_any_focusable = true; }
-                    if tf.windows.transition_duration_spinbox.hit_test(lx, ly, &self.ui_context) { clicked_any_focusable = true; }
-                    if tf.windows.status_height_spinbox.hit_test(lx, ly, &self.ui_context) { clicked_any_focusable = true; }
-                    for menu in &mut tf.windows.tag_layout_menus {
-                        if menu.hit_test(lx, ly, &self.ui_context) { clicked_any_focusable = true; }
+    pub(crate) fn propagate_widget_changes(&mut self, actions: &mut Vec<AppAction>) {
+        match self.app.current_page {
+            Page::Interface => {
+                for (i, cp) in self.app.interface.color_selectors.iter_mut().enumerate() {
+                    if cp.take_change() {
+                        actions.push(AppAction::Interface(match i {
+                            0 => pages::interface::InterfaceMessage::SetPageLowColor(cp.color),
+                            1 => pages::interface::InterfaceMessage::SetHighColor(cp.color),
+                            2 => pages::interface::InterfaceMessage::SetVisualGuidesColor(cp.color),
+                            3 => pages::interface::InterfaceMessage::SetDisabledColor(cp.color),
+                            4 => pages::interface::InterfaceMessage::SetSeparatorColor(cp.color),
+                            5 => pages::interface::InterfaceMessage::SetSliderTrackColor(cp.color),
+                            6 => pages::interface::InterfaceMessage::SetColorBordersColor(cp.color),
+                            7 => pages::interface::InterfaceMessage::SetDesktopBackground(cp.color),
+                            8 => pages::interface::InterfaceMessage::SetNormalColor(cp.color),
+                            9 => pages::interface::InterfaceMessage::SetPaginatorSidebarColor(cp.color),
+                            10 => pages::interface::InterfaceMessage::SetPrimaryHighlightColor(cp.color),
+                            11 => pages::interface::InterfaceMessage::SetMenubarTabLabelColor(cp.color),
+                            12 => pages::interface::InterfaceMessage::SetToggleEnabledColor(cp.color),
+                            13 => pages::interface::InterfaceMessage::SetToggleDisabledColor(cp.color),
+                            14 => pages::interface::InterfaceMessage::SetScrollingListBgColor(cp.color),
+                            15 => pages::interface::InterfaceMessage::SetBreadcrumbBgColor(cp.color),
+                            16 => pages::interface::InterfaceMessage::SetPopoverBgColor(cp.color),
+                            17 => pages::interface::InterfaceMessage::SetNotificationBgColor(cp.color),
+                            18 => pages::interface::InterfaceMessage::SetWindowColor(cp.color),
+                            19 => pages::interface::InterfaceMessage::SetPageColor(cp.color),
+                            20 => pages::interface::InterfaceMessage::SetLayerColor(cp.color),
+                            21 => pages::interface::InterfaceMessage::SetScrollingListEntryBgColor([cp.color[0], cp.color[1], cp.color[2], cp.alpha]),
+                            22 => pages::interface::InterfaceMessage::SetScrollingListEntryHighlightColor([cp.color[0], cp.color[1], cp.color[2], cp.alpha]),
+                            _ => pages::interface::InterfaceMessage::SetDesktopBackground(cp.color),
+                        }));
                     }
-                    if tf.windows.side_panel_behavior_menu.hit_test(lx, ly, &self.ui_context) { clicked_any_focusable = true; }
-                    if tf.windows.side_panel_position_menu.hit_test(lx, ly, &self.ui_context) { clicked_any_focusable = true; }
-                    if tf.windows.side_panel_width_spinbox.hit_test(lx, ly, &self.ui_context) { clicked_any_focusable = true; }
-                    if tf.windows.side_panel_border_gap_spinbox.hit_test(lx, ly, &self.ui_context) { clicked_any_focusable = true; }
-                    if tf.windows.side_panel_border_opacity_spinbox.hit_test(lx, ly, &self.ui_context) { clicked_any_focusable = true; }
-                    if tf.windows.transparency_toggle.hit_test(lx, ly, &self.ui_context) { clicked_any_focusable = true; }
-                    if tf.windows.blur_toggle.hit_test(lx, ly, &self.ui_context) { clicked_any_focusable = true; }
-                }
-                Page::Input => {
-                    if self.app.input.rate_spinbox.hit_test(lx, ly, &self.ui_context) { clicked_any_focusable = true; }
-                    if self.app.input.delay_spinbox.hit_test(lx, ly, &self.ui_context) { clicked_any_focusable = true; }
-                    if self.app.input.scroll_friction_spinbox.hit_test(lx, ly, &self.ui_context) { clicked_any_focusable = true; }
-                    if self.app.input.pointer_friction_spinbox.hit_test(lx, ly, &self.ui_context) { clicked_any_focusable = true; }
-                    if self.app.input.trackpad_friction_spinbox.hit_test(lx, ly, &self.ui_context) { clicked_any_focusable = true; }
-                    if self.app.input.trackpoint_accel_speed_spinbox.hit_test(lx, ly, &self.ui_context) { clicked_any_focusable = true; }
-                    if self.app.input.trackpoint_accel_profile_menu.hit_test(lx, ly, &self.ui_context) { clicked_any_focusable = true; }
-                    if self.app.input.zoom_in_box.hit_test(lx, ly, &self.ui_context) { clicked_any_focusable = true; }
-                    if self.app.input.zoom_out_box.hit_test(lx, ly, &self.ui_context) { clicked_any_focusable = true; }
-                    if self.app.input.keybinds_control.hit_test(lx, ly, &self.ui_context) { clicked_any_focusable = true; }
                 }
-
-                Page::Audio => {
-                    for sb in &mut self.app.audio.sink_spinboxes {
-                        if sb.hit_test(lx, ly, &self.ui_context) { clicked_any_focusable = true; }
-                    }
-                    for sb in &mut self.app.audio.source_spinboxes {
-                        if sb.hit_test(lx, ly, &self.ui_context) { clicked_any_focusable = true; }
-                    }
-                    for slider in &mut self.app.audio.sink_sliders {
-                        if slider.hit_test(lx, ly, &self.ui_context) { clicked_any_focusable = true; }
-                    }
-                    for slider in &mut self.app.audio.source_sliders {
-                        if slider.hit_test(lx, ly, &self.ui_context) { clicked_any_focusable = true; }
-                    }
+                if self.app.interface.notification_opacity_spinbox.take_change() {
+                    actions.push(AppAction::Interface(pages::interface::InterfaceMessage::SetNotificationOpacity(self.app.interface.notification_opacity_spinbox.value as f32 / 100.0)));
                 }
-                Page::Display => {
-                    if self.app.display.brightness_slider.hit_test(lx, ly, &self.ui_context) { clicked_any_focusable = true; }
-                    if self.app.display.brightness_spinbox.hit_test(lx, ly, &self.ui_context) { clicked_any_focusable = true; }
-                    if self.app.display.night_light_label.hit_test(lx, ly, &self.ui_context) { clicked_any_focusable = true; }
-                    for out in &mut self.app.display.outputs {
-                        if out.name_label.hit_test(lx, ly, &self.ui_context) { clicked_any_focusable = true; }
-                        if out.resolution_label.hit_test(lx, ly, &self.ui_context) { clicked_any_focusable = true; }
-                        if let Some(ref mut scale_lbl) = out.scale_label {
-                            if scale_lbl.hit_test(lx, ly, &self.ui_context) { clicked_any_focusable = true; }
-                        }
-                    }
-                    if self.app.display.screensaver_timeout_spinbox.hit_test(lx, ly, &self.ui_context) { clicked_any_focusable = true; }
-                    if self.app.display.screensaver_style_menu.hit_test(lx, ly, &self.ui_context) { clicked_any_focusable = true; }
-                }
-                Page::Services => {
-                    let srv = &mut self.app.services;
-                    if srv.search_box.hit_test(lx, ly, &self.ui_context) { clicked_any_focusable = true; }
-                    if srv.list_box.hit_test(lx, ly, &self.ui_context) { clicked_any_focusable = true; }
-                    if srv.notifications_duration_spinbox.hit_test(lx, ly, &self.ui_context) { clicked_any_focusable = true; }
-                    if srv.status_label.hit_test(lx, ly, &self.ui_context) { clicked_any_focusable = true; }
-                    if srv.status_padding_spinbox.hit_test(lx, ly, &self.ui_context) { clicked_any_focusable = true; }
-                }
-                Page::Packages => {
-                    let pkgs = &mut self.app.packages;
-                    if pkgs.search_box.hit_test(lx, ly, &self.ui_context) { clicked_any_focusable = true; }
-                    match pkgs.active_tab {
-                        pages::packages::PackageTab::Installed => {
-                            if pkgs.installed_list_box.hit_test(lx, ly, &self.ui_context) { clicked_any_focusable = true; }
-                        }
-                        pages::packages::PackageTab::Updates => {
-                            if pkgs.updates_list_box.hit_test(lx, ly, &self.ui_context) { clicked_any_focusable = true; }
-                        }
-                    }
+                if self.app.interface.menubar_opacity_spinbox.take_change() {
+                    actions.push(AppAction::Interface(pages::interface::InterfaceMessage::SetMenubarOpacity(self.app.interface.menubar_opacity_spinbox.value as f32 / 100.0)));
                 }
-                Page::Hardware => {
-                    let hw = &mut self.app.hardware;
-                    if hw.cpu_list_box.hit_test(lx, ly, &self.ui_context) { clicked_any_focusable = true; }
-                    if hw.cpu_gov_menu.hit_test(lx, ly, &self.ui_context) { clicked_any_focusable = true; }
-                    if hw.gpu_gov_menu.hit_test(lx, ly, &self.ui_context) { clicked_any_focusable = true; }
+
+                if self.app.interface.button_padding_spinbox.take_change() {
+                    actions.push(AppAction::Interface(pages::interface::InterfaceMessage::SetButtonPadding(self.app.interface.button_padding_spinbox.value as u16)));
                 }
-                Page::Radios => {
-                    let net = &mut self.app.network;
-                    if net.wifi_list_box.hit_test(lx, ly, &self.ui_context) { clicked_any_focusable = true; }
+                if self.app.interface.section_padding_spinbox.take_change() {
+                    actions.push(AppAction::Interface(pages::interface::InterfaceMessage::SetSectionPadding(self.app.interface.section_padding_spinbox.value as u16)));
                 }
-                _ => {}
-            }
-
-            if !clicked_any_focusable {
-                cce_ui::widget::focus::clear_focus();
-            }
-        }
-
-        if state == cce_ui::widget::ElementState::Pressed && self.app.current_page == Page::Interface {
-            let tf = &mut self.app.interface.windows;
-            for (i, sb) in tf.spinboxes.iter_mut().enumerate() {
-                if !sb.hit_test(lx, ly, &self.ui_context) { sb.unfocus(); }
-                let old = sb.value;
-                if sb.mouse_input(button, state, lx, ly, &mut self.ui_context) && sb.value != old {
-                    actions.push(AppAction::Interface(
-                        pages::interface::InterfaceMessage::Windows(
-                            pages::interface::WindowsMessage::SetWidth(
-                                pages::interface::WidthParam::ALL[i],
-                                sb.value as u16,
-                            )
-                        )
-                    ));
+                if self.app.interface.label_alignment_menu.take_change() {
+                    actions.push(AppAction::Interface(pages::interface::InterfaceMessage::SetNestedSectionLabelAlignment(self.app.interface.label_alignment_menu.selected)));
                 }
-            }
-            let sb = &mut tf.cascade_offset_spinbox;
-            if !sb.hit_test(lx, ly, &self.ui_context) { sb.unfocus(); }
-            let old = sb.value;
-            if sb.mouse_input(button, state, lx, ly, &mut self.ui_context) && sb.value != old {
-                actions.push(AppAction::Interface(
-                    pages::interface::InterfaceMessage::Windows(
-                        pages::interface::WindowsMessage::SetCascadeOffset(sb.value as u16)
-                    )
-                ));
-            }
-            let sb = &mut tf.edge_gap_spinbox;
-            if !sb.hit_test(lx, ly, &self.ui_context) { sb.unfocus(); }
-            let old = sb.value;
-            if sb.mouse_input(button, state, lx, ly, &mut self.ui_context) && sb.value != old {
-                actions.push(AppAction::Interface(
-                    pages::interface::InterfaceMessage::Windows(
-                        pages::interface::WindowsMessage::SetEdgeGap(sb.value as u16)
-                    )
-                ));
-            }
-            let sb = &mut tf.top_gap_spinbox;
-            if !sb.hit_test(lx, ly, &self.ui_context) { sb.unfocus(); }
-            let old = sb.value;
-            if sb.mouse_input(button, state, lx, ly, &mut self.ui_context) && sb.value != old {
-                actions.push(AppAction::Interface(
-                    pages::interface::InterfaceMessage::Windows(
-                        pages::interface::WindowsMessage::SetTopGap(sb.value as u16)
-                    )
-                ));
-            }
-            let sb = &mut tf.grid_gap_spinbox;
-            if !sb.hit_test(lx, ly, &self.ui_context) { sb.unfocus(); }
-            let old = sb.value;
-            if sb.mouse_input(button, state, lx, ly, &mut self.ui_context) && sb.value != old {
-                actions.push(AppAction::Interface(
-                    pages::interface::InterfaceMessage::Windows(
-                        pages::interface::WindowsMessage::SetGridGap(sb.value as u16)
-                    )
-                ));
-            }
-            let sb = &mut tf.transition_duration_spinbox;
-            if !sb.hit_test(lx, ly, &self.ui_context) { sb.unfocus(); }
-            let old = sb.value;
-            if sb.mouse_input(button, state, lx, ly, &mut self.ui_context) && sb.value != old {
-                actions.push(AppAction::Interface(
-                    pages::interface::InterfaceMessage::Windows(
-                        pages::interface::WindowsMessage::SetTransitionDuration(sb.value as u16)
-                    )
-                ));
-            }
-            let sb = &mut tf.status_height_spinbox;
-            if !sb.hit_test(lx, ly, &self.ui_context) { sb.unfocus(); }
-            let old = sb.value;
-            if sb.mouse_input(button, state, lx, ly, &mut self.ui_context) && sb.value != old {
-                actions.push(AppAction::Interface(
-                    pages::interface::InterfaceMessage::Windows(
-                        pages::interface::WindowsMessage::SetStatusHeight(sb.value as u16)
-                    )
-                ));
-            }
-        }
-        if self.app.current_page == Page::Interface {
-            let tf = &mut self.app.interface.windows;
-            for (idx, menu) in tf.tag_layout_menus.iter_mut().enumerate() {
-                if state == cce_ui::widget::ElementState::Pressed && !menu.hit_test(lx, ly, &self.ui_context) { menu.unfocus(); }
-                if menu.mouse_input(button, state, lx, ly, &mut self.ui_context) {
-                    self.needs_rebuild = true;
-                }
-                if state == cce_ui::widget::ElementState::Pressed && menu.take_change() {
-                    actions.push(AppAction::Interface(
-                        pages::interface::InterfaceMessage::Windows(
-                            pages::interface::WindowsMessage::SetTagLayout(idx + 1, menu.selected)
-                        )
-                    ));
-                }
-            }
-            let menu = &mut tf.side_panel_behavior_menu;
-            if state == cce_ui::widget::ElementState::Pressed && !menu.hit_test(lx, ly, &self.ui_context) { menu.unfocus(); }
-            if menu.mouse_input(button, state, lx, ly, &mut self.ui_context) {
-                self.needs_rebuild = true;
-            }
-            if state == cce_ui::widget::ElementState::Pressed && menu.take_change() {
-                actions.push(AppAction::Interface(
-                    pages::interface::InterfaceMessage::Windows(
-                        pages::interface::WindowsMessage::SetSidePanelBehavior(menu.selected)
-                    )
-                ));
-            }
-            let menu = &mut tf.side_panel_position_menu;
-            if state == cce_ui::widget::ElementState::Pressed && !menu.hit_test(lx, ly, &self.ui_context) { menu.unfocus(); }
-            if menu.mouse_input(button, state, lx, ly, &mut self.ui_context) {
-                self.needs_rebuild = true;
-            }
-            if state == cce_ui::widget::ElementState::Pressed && menu.take_change() {
-                actions.push(AppAction::Interface(
-                    pages::interface::InterfaceMessage::Windows(
-                        pages::interface::WindowsMessage::SetSidePanelPosition(menu.selected)
-                    )
-                ));
-            }
-            let sb = &mut tf.side_panel_width_spinbox;
-            if !sb.hit_test(lx, ly, &self.ui_context) { sb.unfocus(); }
-            let old = sb.value;
-            if sb.mouse_input(button, state, lx, ly, &mut self.ui_context) && sb.value != old {
-                actions.push(AppAction::Interface(
-                    pages::interface::InterfaceMessage::Windows(
-                        pages::interface::WindowsMessage::SetSidePanelWidth(sb.value as u16)
-                    )
-                ));
-            }
-            let sb = &mut tf.side_panel_border_gap_spinbox;
-            if !sb.hit_test(lx, ly, &self.ui_context) { sb.unfocus(); }
-            let old = sb.value;
-            if sb.mouse_input(button, state, lx, ly, &mut self.ui_context) && sb.value != old {
-                actions.push(AppAction::Interface(
-                    pages::interface::InterfaceMessage::Windows(
-                        pages::interface::WindowsMessage::SetSidePanelBorderGap(sb.value as u16)
-                    )
-                ));
-            }
-            let sb = &mut tf.side_panel_border_opacity_spinbox;
-            if !sb.hit_test(lx, ly, &self.ui_context) { sb.unfocus(); }
-            let old = sb.value;
-            if sb.mouse_input(button, state, lx, ly, &mut self.ui_context) && sb.value != old {
-                actions.push(AppAction::Interface(
-                    pages::interface::InterfaceMessage::Windows(
-                        pages::interface::WindowsMessage::SetSidePanelBorderOpacity(sb.value as u16)
-                    )
-                ));
-            }
-            let toggle = &mut tf.transparency_toggle;
-            toggle.mouse_input(button, state, lx, ly, &mut self.ui_context);
-            if toggle.take_click() {
-                actions.push(AppAction::Interface(
-                    pages::interface::InterfaceMessage::Windows(
-                        pages::interface::WindowsMessage::ToggleTransparency
-                    )
-                ));
-            }
-            let toggle2 = &mut tf.blur_toggle;
-            toggle2.mouse_input(button, state, lx, ly, &mut self.ui_context);
-            if toggle2.take_click() {
-                actions.push(AppAction::Interface(
-                    pages::interface::InterfaceMessage::Windows(
-                        pages::interface::WindowsMessage::ToggleBlur
-                    )
-                ));
-            }
-        }
-        if state == cce_ui::widget::ElementState::Pressed && self.app.current_page == Page::Interface {
-            for (i, cp) in self.app.interface.color_selectors.iter_mut().enumerate() {
-                let old = cp.color;
-                let old_alpha = cp.alpha;
-                if !cp.hit_test(lx, ly, &self.ui_context) { cp.unfocus(); }
-                cp.mouse_input(button, state, lx, ly, &mut self.ui_context);
-                if cp.take_click() {
-                    actions.push(AppAction::Interface(match i {
-                        0 => pages::interface::InterfaceMessage::PickPageLowColor,
-                        1 => pages::interface::InterfaceMessage::PickHighColor,
-                        2 => pages::interface::InterfaceMessage::PickVisualGuides,
-                        3 => pages::interface::InterfaceMessage::PickDisabledColor,
-                        4 => pages::interface::InterfaceMessage::PickSeparatorColor,
-                        5 => pages::interface::InterfaceMessage::PickSliderTrackColor,
-                        6 => pages::interface::InterfaceMessage::PickColorBordersColor,
-                        7 => pages::interface::InterfaceMessage::PickLowColor,
-                        8 => pages::interface::InterfaceMessage::PickNormalColor,
-                        9 => pages::interface::InterfaceMessage::PickPaginatorSidebarColor,
-                        10 => pages::interface::InterfaceMessage::PickPrimaryHighlightColor,
-                        11 => pages::interface::InterfaceMessage::PickMenubarTabLabelColor,
-                        12 => pages::interface::InterfaceMessage::PickToggleEnabledColor,
-                        13 => pages::interface::InterfaceMessage::PickToggleDisabledColor,
-                        14 => pages::interface::InterfaceMessage::PickScrollingListBgColor,
-                        15 => pages::interface::InterfaceMessage::PickBreadcrumbBgColor,
-                        16 => pages::interface::InterfaceMessage::PickPopoverBgColor,
-                        17 => pages::interface::InterfaceMessage::PickNotificationBgColor,
-                        18 => pages::interface::InterfaceMessage::PickWindowColor,
-                        19 => pages::interface::InterfaceMessage::PickPageColor,
-                        20 => pages::interface::InterfaceMessage::PickLayerColor,
-                        21 => pages::interface::InterfaceMessage::PickScrollingListEntryBgColor,
-                        22 => pages::interface::InterfaceMessage::PickScrollingListEntryHighlightColor,
-                        _ => pages::interface::InterfaceMessage::PickLowColor,
-                    }));
-                }
-                if cp.color != old || cp.alpha != old_alpha {
-                    actions.push(AppAction::Interface(match i {
-                        0 => pages::interface::InterfaceMessage::SetPageLowColor(cp.color),
-                        1 => pages::interface::InterfaceMessage::SetHighColor(cp.color),
-                        2 => pages::interface::InterfaceMessage::SetVisualGuidesColor(cp.color),
-                        3 => pages::interface::InterfaceMessage::SetDisabledColor(cp.color),
-                        4 => pages::interface::InterfaceMessage::SetSeparatorColor(cp.color),
-                        5 => pages::interface::InterfaceMessage::SetSliderTrackColor(cp.color),
-                        6 => pages::interface::InterfaceMessage::SetColorBordersColor(cp.color),
-                        7 => pages::interface::InterfaceMessage::SetDesktopBackground(cp.color),
-                        8 => pages::interface::InterfaceMessage::SetNormalColor(cp.color),
-                        9 => pages::interface::InterfaceMessage::SetPaginatorSidebarColor(cp.color),
-                        10 => pages::interface::InterfaceMessage::SetPrimaryHighlightColor(cp.color),
-                        11 => pages::interface::InterfaceMessage::SetMenubarTabLabelColor(cp.color),
-                        12 => pages::interface::InterfaceMessage::SetToggleEnabledColor(cp.color),
-                        13 => pages::interface::InterfaceMessage::SetToggleDisabledColor(cp.color),
-                        14 => pages::interface::InterfaceMessage::SetScrollingListBgColor(cp.color),
-                        15 => pages::interface::InterfaceMessage::SetBreadcrumbBgColor(cp.color),
-                        16 => pages::interface::InterfaceMessage::SetPopoverBgColor(cp.color),
-                        17 => pages::interface::InterfaceMessage::SetNotificationBgColor(cp.color),
-                        18 => pages::interface::InterfaceMessage::SetWindowColor(cp.color),
-                        19 => pages::interface::InterfaceMessage::SetPageColor(cp.color),
-                        20 => pages::interface::InterfaceMessage::SetLayerColor(cp.color),
-                        21 => pages::interface::InterfaceMessage::SetScrollingListEntryBgColor([cp.color[0], cp.color[1], cp.color[2], cp.alpha]),
-                        22 => pages::interface::InterfaceMessage::SetScrollingListEntryHighlightColor([cp.color[0], cp.color[1], cp.color[2], cp.alpha]),
-                        _ => pages::interface::InterfaceMessage::SetDesktopBackground(cp.color),
-                    }));
-                }
-            }
-            let sb = &mut self.app.interface.menubar_opacity_spinbox;
-            if !sb.hit_test(lx, ly, &self.ui_context) { sb.unfocus(); }
-            let old = sb.value;
-            if sb.mouse_input(button, state, lx, ly, &mut self.ui_context) && sb.value != old {
-                actions.push(AppAction::Interface(pages::interface::InterfaceMessage::SetMenubarOpacity(sb.value as f32 / 100.0)));
-            }
-            let sb = &mut self.app.interface.notification_opacity_spinbox;
-            if !sb.hit_test(lx, ly, &self.ui_context) { sb.unfocus(); }
-            let old = sb.value;
-            if sb.mouse_input(button, state, lx, ly, &mut self.ui_context) && sb.value != old {
-                actions.push(AppAction::Interface(pages::interface::InterfaceMessage::SetNotificationOpacity(sb.value as f32 / 100.0)));
-            }
-            let sb = &mut self.app.interface.window_opacity_spinbox;
-            if !sb.hit_test(lx, ly, &self.ui_context) { sb.unfocus(); }
-            let old = sb.value;
-            if sb.mouse_input(button, state, lx, ly, &mut self.ui_context) && sb.value != old {
-                actions.push(AppAction::Interface(pages::interface::InterfaceMessage::SetWindowOpacity(sb.value as f32 / 100.0)));
-            }
-            let sb = &mut self.app.interface.window_corner_radius_spinbox;
-            if !sb.hit_test(lx, ly, &self.ui_context) { sb.unfocus(); }
-            let old = sb.value;
-            if sb.mouse_input(button, state, lx, ly, &mut self.ui_context) && sb.value != old {
-                actions.push(AppAction::Interface(pages::interface::InterfaceMessage::SetWindowCornerRadius(sb.value as u16)));
-            }
-
-            let sb = &mut self.app.interface.button_padding_spinbox;
-            if !sb.hit_test(lx, ly, &self.ui_context) { sb.unfocus(); }
-            let old = sb.value;
-            if sb.mouse_input(button, state, lx, ly, &mut self.ui_context) && sb.value != old {
-                actions.push(AppAction::Interface(pages::interface::InterfaceMessage::SetButtonPadding(sb.value as u16)));
-            }
-            let sb = &mut self.app.interface.section_padding_spinbox;
-            if !sb.hit_test(lx, ly, &self.ui_context) { sb.unfocus(); }
-            let old = sb.value;
-            if sb.mouse_input(button, state, lx, ly, &mut self.ui_context) && sb.value != old {
-                actions.push(AppAction::Interface(pages::interface::InterfaceMessage::SetSectionPadding(sb.value as u16)));
-            }
-            let menu = &mut self.app.interface.label_alignment_menu;
-            if state == cce_ui::widget::ElementState::Pressed && !menu.hit_test(lx, ly, &self.ui_context) { menu.unfocus(); }
-            if menu.mouse_input(button, state, lx, ly, &mut self.ui_context) {
-                self.needs_rebuild = true;
-            }
-            if state == cce_ui::widget::ElementState::Pressed && menu.take_change() {
-                actions.push(AppAction::Interface(pages::interface::InterfaceMessage::SetNestedSectionLabelAlignment(menu.selected)));
-            }
-            let sb = &mut self.app.interface.label_offset_spinbox;
-            if !sb.hit_test(lx, ly, &self.ui_context) { sb.unfocus(); }
-            let old = sb.value;
-            if sb.mouse_input(button, state, lx, ly, &mut self.ui_context) && sb.value != old {
-                actions.push(AppAction::Interface(pages::interface::InterfaceMessage::SetNestedSectionLabelOffset(sb.value as i16)));
-            }
-            let sb = &mut self.app.interface.label_margin_spinbox;
-            if !sb.hit_test(lx, ly, &self.ui_context) { sb.unfocus(); }
-            let old = sb.value;
-            if sb.mouse_input(button, state, lx, ly, &mut self.ui_context) && sb.value != old {
-                actions.push(AppAction::Interface(pages::interface::InterfaceMessage::SetLabelMargin(sb.value as u16)));
-            }
-            let sb = &mut self.app.interface.plate_padding_spinbox;
-            if !sb.hit_test(lx, ly, &self.ui_context) { sb.unfocus(); }
-            let old = sb.value;
-            if sb.mouse_input(button, state, lx, ly, &mut self.ui_context) && sb.value != old {
-                actions.push(AppAction::Interface(pages::interface::InterfaceMessage::SetPlatePadding(sb.value as u16)));
-            }
-            let toggle = &mut self.app.interface.graph_show_grid_toggle;
-            toggle.mouse_input(button, state, lx, ly, &mut self.ui_context);
-            if toggle.take_click() {
-                actions.push(AppAction::Interface(pages::interface::InterfaceMessage::SetGraphShowGrid(toggle.toggled())));
-            }
-            let toggle = &mut self.app.interface.graph_snap_enabled_toggle;
-            toggle.mouse_input(button, state, lx, ly, &mut self.ui_context);
-            if toggle.take_click() {
-                actions.push(AppAction::Interface(pages::interface::InterfaceMessage::SetGraphSnapEnabled(toggle.toggled())));
-            }
-            let toggle = &mut self.app.interface.graph_uniform_background_toggle;
-            toggle.mouse_input(button, state, lx, ly, &mut self.ui_context);
-            if toggle.take_click() {
-                actions.push(AppAction::Interface(pages::interface::InterfaceMessage::SetGraphUniformBackground(toggle.toggled())));
-            }
-            let sb = &mut self.app.interface.graph_gap_width_spinbox;
-            if !sb.hit_test(lx, ly, &self.ui_context) { sb.unfocus(); }
-            let old = sb.value;
-            if sb.mouse_input(button, state, lx, ly, &mut self.ui_context) && sb.value != old {
-                actions.push(AppAction::Interface(pages::interface::InterfaceMessage::SetGraphGapWidth(sb.value as u16)));
-            }
-            let sb = &mut self.app.interface.graph_cell_opacity_spinbox;
-            if !sb.hit_test(lx, ly, &self.ui_context) { sb.unfocus(); }
-            let old = sb.value;
-            if sb.mouse_input(button, state, lx, ly, &mut self.ui_context) && sb.value != old {
-                actions.push(AppAction::Interface(pages::interface::InterfaceMessage::SetGraphCellOpacity(sb.value as f32 / 100.0)));
-            }
-            let sb = &mut self.app.interface.graph_gap_opacity_spinbox;
-            if !sb.hit_test(lx, ly, &self.ui_context) { sb.unfocus(); }
-            let old = sb.value;
-            if sb.mouse_input(button, state, lx, ly, &mut self.ui_context) && sb.value != old {
-                actions.push(AppAction::Interface(pages::interface::InterfaceMessage::SetGraphGapOpacity(sb.value as f32 / 100.0)));
-            }
-            let sb = &mut self.app.interface.page_margin_spinbox;
-            if !sb.hit_test(lx, ly, &self.ui_context) { sb.unfocus(); }
-            let old = sb.value;
-            if sb.mouse_input(button, state, lx, ly, &mut self.ui_context) && sb.value != old {
-                actions.push(AppAction::Interface(pages::interface::InterfaceMessage::SetPageMargin(sb.value as u16)));
-            }
-            let sb = &mut self.app.interface.grid_min_col_width_spinbox;
-            if !sb.hit_test(lx, ly, &self.ui_context) { sb.unfocus(); }
-            let old = sb.value;
-            if sb.mouse_input(button, state, lx, ly, &mut self.ui_context) && sb.value != old {
-                actions.push(AppAction::Interface(pages::interface::InterfaceMessage::SetGridMinColWidth(sb.value as u16)));
-            }
-            let sb = &mut self.app.interface.spinbox_height_spinbox;
-            if !sb.hit_test(lx, ly, &self.ui_context) { sb.unfocus(); }
-            let old = sb.value;
-            if sb.mouse_input(button, state, lx, ly, &mut self.ui_context) && sb.value != old {
-                actions.push(AppAction::Interface(pages::interface::InterfaceMessage::SetSpinboxHeight(sb.value as u16)));
-            }
-            let sb = &mut self.app.interface.spinbox_corner_radius_spinbox;
-            if !sb.hit_test(lx, ly, &self.ui_context) { sb.unfocus(); }
-            let old = sb.value;
-            if sb.mouse_input(button, state, lx, ly, &mut self.ui_context) && sb.value != old {
-                actions.push(AppAction::Interface(pages::interface::InterfaceMessage::SetSpinboxCornerRadius(sb.value as u16)));
-            }
-            let sb = &mut self.app.interface.toggle_height_spinbox;
-            if !sb.hit_test(lx, ly, &self.ui_context) { sb.unfocus(); }
-            let old = sb.value;
-            if sb.mouse_input(button, state, lx, ly, &mut self.ui_context) && sb.value != old {
-                actions.push(AppAction::Interface(pages::interface::InterfaceMessage::SetToggleHeight(sb.value as u16)));
-            }
-            let sb = &mut self.app.interface.toggle_corner_radius_spinbox;
-            if !sb.hit_test(lx, ly, &self.ui_context) { sb.unfocus(); }
-            let old = sb.value;
-            if sb.mouse_input(button, state, lx, ly, &mut self.ui_context) && sb.value != old {
-                actions.push(AppAction::Interface(pages::interface::InterfaceMessage::SetToggleCornerRadius(sb.value as u16)));
-            }
-            let sb = &mut self.app.interface.plate_opacity_spinbox;
-            if !sb.hit_test(lx, ly, &self.ui_context) { sb.unfocus(); }
-            let old = sb.value;
-            if sb.mouse_input(button, state, lx, ly, &mut self.ui_context) && sb.value != old {
-                actions.push(AppAction::Interface(pages::interface::InterfaceMessage::SetPlateOpacity(sb.value as f32 / 100.0)));
-            }
-            let sb = &mut self.app.interface.plate_corner_radius_spinbox;
-            if !sb.hit_test(lx, ly, &self.ui_context) { sb.unfocus(); }
-            let old = sb.value;
-            if sb.mouse_input(button, state, lx, ly, &mut self.ui_context) && sb.value != old {
-                actions.push(AppAction::Interface(pages::interface::InterfaceMessage::SetPlateCornerRadius(sb.value as u16)));
-            }
-            let sb = &mut self.app.interface.page_opacity_spinbox;
-            if !sb.hit_test(lx, ly, &self.ui_context) { sb.unfocus(); }
-            let old = sb.value;
-            if sb.mouse_input(button, state, lx, ly, &mut self.ui_context) && sb.value != old {
-                actions.push(AppAction::Interface(pages::interface::InterfaceMessage::SetPageOpacity(sb.value as f32 / 100.0)));
-            }
-            let sb = &mut self.app.interface.layer_opacity_spinbox;
-            if !sb.hit_test(lx, ly, &self.ui_context) { sb.unfocus(); }
-            let old = sb.value;
-            if sb.mouse_input(button, state, lx, ly, &mut self.ui_context) && sb.value != old {
-                actions.push(AppAction::Interface(pages::interface::InterfaceMessage::SetLayerOpacity(sb.value as f32 / 100.0)));
-            }
-
-
-            let sb = &mut self.app.interface.color_selector_height_spinbox;
-            if !sb.hit_test(lx, ly, &self.ui_context) { sb.unfocus(); }
-            let old = sb.value;
-            if sb.mouse_input(button, state, lx, ly, &mut self.ui_context) && sb.value != old {
-                actions.push(AppAction::Interface(pages::interface::InterfaceMessage::SetColorSelectorHeight(sb.value as u16)));
-            }
-            let sb = &mut self.app.interface.color_selector_corner_radius_spinbox;
-            if !sb.hit_test(lx, ly, &self.ui_context) { sb.unfocus(); }
-            let old = sb.value;
-            if sb.mouse_input(button, state, lx, ly, &mut self.ui_context) && sb.value != old {
-                actions.push(AppAction::Interface(pages::interface::InterfaceMessage::SetColorSelectorCornerRadius(sb.value as u16)));
-            }
-            let sb = &mut self.app.interface.color_selector_preview_corner_radius_spinbox;
-            if !sb.hit_test(lx, ly, &self.ui_context) { sb.unfocus(); }
-            let old = sb.value;
-            if sb.mouse_input(button, state, lx, ly, &mut self.ui_context) && sb.value != old {
-                actions.push(AppAction::Interface(pages::interface::InterfaceMessage::SetColorSelectorPreviewCornerRadius(sb.value as u16)));
-            }
-            let sb = &mut self.app.interface.color_selector_preview_margin_spinbox;
-            if !sb.hit_test(lx, ly, &self.ui_context) { sb.unfocus(); }
-            let old = sb.value;
-            if sb.mouse_input(button, state, lx, ly, &mut self.ui_context) && sb.value != old {
-                actions.push(AppAction::Interface(pages::interface::InterfaceMessage::SetColorSelectorPreviewMargin(sb.value as u16)));
-            }
-            let sb = &mut self.app.interface.textbox_height_spinbox;
-            if !sb.hit_test(lx, ly, &self.ui_context) { sb.unfocus(); }
-            let old = sb.value;
-            if sb.mouse_input(button, state, lx, ly, &mut self.ui_context) && sb.value != old {
-                actions.push(AppAction::Interface(pages::interface::InterfaceMessage::SetTextboxHeight(sb.value as u16)));
-            }
-            let sb = &mut self.app.interface.textbox_corner_radius_spinbox;
-            if !sb.hit_test(lx, ly, &self.ui_context) { sb.unfocus(); }
-            let old = sb.value;
-            if sb.mouse_input(button, state, lx, ly, &mut self.ui_context) && sb.value != old {
-                actions.push(AppAction::Interface(pages::interface::InterfaceMessage::SetTextboxCornerRadius(sb.value as u16)));
-            }
-            let sb = &mut self.app.interface.slider_height_spinbox;
-            if !sb.hit_test(lx, ly, &self.ui_context) { sb.unfocus(); }
-            let old = sb.value;
-            if sb.mouse_input(button, state, lx, ly, &mut self.ui_context) && sb.value != old {
-                actions.push(AppAction::Interface(pages::interface::InterfaceMessage::SetSliderHeight(sb.value as u16)));
-            }
-            let sb = &mut self.app.interface.font_selector_height_spinbox;
-            if !sb.hit_test(lx, ly, &self.ui_context) { sb.unfocus(); }
-            let old = sb.value;
-            if sb.mouse_input(button, state, lx, ly, &mut self.ui_context) && sb.value != old {
-                actions.push(AppAction::Interface(pages::interface::InterfaceMessage::SetFontSelectorHeight(sb.value as u16)));
-            }
-            let sb = &mut self.app.interface.font_selector_corner_radius_spinbox;
-            if !sb.hit_test(lx, ly, &self.ui_context) { sb.unfocus(); }
-            let old = sb.value;
-            if sb.mouse_input(button, state, lx, ly, &mut self.ui_context) && sb.value != old {
-                actions.push(AppAction::Interface(pages::interface::InterfaceMessage::SetFontSelectorCornerRadius(sb.value as u16)));
-            }
-            let sb = &mut self.app.interface.dropdown_height_spinbox;
-            if !sb.hit_test(lx, ly, &self.ui_context) { sb.unfocus(); }
-            let old = sb.value;
-            if sb.mouse_input(button, state, lx, ly, &mut self.ui_context) && sb.value != old {
-                actions.push(AppAction::Interface(pages::interface::InterfaceMessage::SetDropdownHeight(sb.value as u16)));
-            }
-            let sb = &mut self.app.interface.dropdown_corner_radius_spinbox;
-            if !sb.hit_test(lx, ly, &self.ui_context) { sb.unfocus(); }
-            let old = sb.value;
-            if sb.mouse_input(button, state, lx, ly, &mut self.ui_context) && sb.value != old {
-                actions.push(AppAction::Interface(pages::interface::InterfaceMessage::SetDropdownCornerRadius(sb.value as u16)));
-            }
-            let sb = &mut self.app.interface.button_corner_radius_spinbox;
-            if !sb.hit_test(lx, ly, &self.ui_context) { sb.unfocus(); }
-            let old = sb.value;
-            if sb.mouse_input(button, state, lx, ly, &mut self.ui_context) && sb.value != old {
-                actions.push(AppAction::Interface(pages::interface::InterfaceMessage::SetButtonCornerRadius(sb.value as u16)));
-            }
-        }
-
-        if self.app.current_page == Page::Interface {
-            let mc = &mut self.app.interface.custom_multicontrol;
-            if state == cce_ui::widget::ElementState::Pressed && !mc.hit_test(lx, ly, &self.ui_context) {
-                mc.unfocus();
-            }
-            if mc.mouse_input(button, state, lx, ly, &mut self.ui_context) {
-                self.needs_rebuild = true;
-            }
-        }
-        if state == cce_ui::widget::ElementState::Pressed && self.app.current_page == Page::Input {
-            let sb = &mut self.app.input.rate_spinbox;
-            if !sb.hit_test(lx, ly, &self.ui_context) { sb.unfocus(); }
-            let old = sb.value;
-            if sb.mouse_input(button, state, lx, ly, &mut self.ui_context) && sb.value != old {
-                actions.push(AppAction::Input(pages::input::InputMessage::ApplyRepeat));
-            }
-            let sb = &mut self.app.input.delay_spinbox;
-            if !sb.hit_test(lx, ly, &self.ui_context) { sb.unfocus(); }
-            let old = sb.value;
-            if sb.mouse_input(button, state, lx, ly, &mut self.ui_context) && sb.value != old {
-                actions.push(AppAction::Input(pages::input::InputMessage::ApplyRepeat));
-            }
-            let sb = &mut self.app.input.scroll_friction_spinbox;
-            if !sb.hit_test(lx, ly, &self.ui_context) { sb.unfocus(); }
-            let old = sb.value;
-            if sb.mouse_input(button, state, lx, ly, &mut self.ui_context) && sb.value != old {
-                actions.push(AppAction::Input(pages::input::InputMessage::ApplyScrollFriction));
-            }
-            let sb = &mut self.app.input.scroll_speed_spinbox;
-            if !sb.hit_test(lx, ly, &self.ui_context) { sb.unfocus(); }
-            let old = sb.value;
-            if sb.mouse_input(button, state, lx, ly, &mut self.ui_context) && sb.value != old {
-                actions.push(AppAction::Input(pages::input::InputMessage::ApplyScrollSpeed));
-            }
-            let sb = &mut self.app.input.pointer_friction_spinbox;
-            if !sb.hit_test(lx, ly, &self.ui_context) { sb.unfocus(); }
-            let old = sb.value;
-            if sb.mouse_input(button, state, lx, ly, &mut self.ui_context) && sb.value != old {
-                actions.push(AppAction::Input(pages::input::InputMessage::ApplyPointerFriction));
-            }
-            let sb = &mut self.app.input.trackpad_friction_spinbox;
-            if !sb.hit_test(lx, ly, &self.ui_context) { sb.unfocus(); }
-            let old = sb.value;
-            if sb.mouse_input(button, state, lx, ly, &mut self.ui_context) && sb.value != old {
-                actions.push(AppAction::Input(pages::input::InputMessage::ApplyTrackpadFriction));
-            }
-            let sb = &mut self.app.input.trackpoint_accel_speed_spinbox;
-            if !sb.hit_test(lx, ly, &self.ui_context) { sb.unfocus(); }
-            let old = sb.value;
-            if sb.mouse_input(button, state, lx, ly, &mut self.ui_context) && sb.value != old {
-                actions.push(AppAction::Input(pages::input::InputMessage::ApplyTrackpointAccelSpeed));
-            }
-            let sb = &mut self.app.input.cursor_size_spinbox;
-            if !sb.hit_test(lx, ly, &self.ui_context) { sb.unfocus(); }
-            let old = sb.value;
-            if sb.mouse_input(button, state, lx, ly, &mut self.ui_context) && sb.value != old {
-                actions.push(AppAction::Input(pages::input::InputMessage::ApplyCursorSize));
-            }
-            let kc = &mut self.app.input.keybinds_control;
-            if state == cce_ui::widget::ElementState::Pressed && !kc.hit_test(lx, ly, &self.ui_context) {
-                kc.unfocus();
-            }
-        }
-        if state == cce_ui::widget::ElementState::Pressed && self.app.current_page == Page::Services {
-            let sb = &mut self.app.services.notifications_duration_spinbox;
-            if !sb.hit_test(lx, ly, &self.ui_context) { sb.unfocus(); }
-            let old = sb.value;
-            if sb.mouse_input(button, state, lx, ly, &mut self.ui_context) && sb.value != old {
-                actions.push(AppAction::Services(pages::services::ServicesMessage::SetNotificationsDuration(sb.value)));
-            }
-            let sb2 = &mut self.app.services.status_padding_spinbox;
-            if !sb2.hit_test(lx, ly, &self.ui_context) { sb2.unfocus(); }
-            let old2 = sb2.value;
-            if sb2.mouse_input(button, state, lx, ly, &mut self.ui_context) && sb2.value != old2 {
-                actions.push(AppAction::Services(pages::services::ServicesMessage::StatusSetPadding(sb2.value as u16)));
-            }
-        }
-        if self.app.current_page == Page::Input {
-            let toggle = &mut self.app.input.tap_toggle;
-            toggle.mouse_input(button, state, lx, ly, &mut self.ui_context);
-            if toggle.take_click() {
-                actions.push(AppAction::Input(pages::input::InputMessage::ToggleTapToClick));
-            }
-            let toggle = &mut self.app.input.scroll_toggle;
-            toggle.mouse_input(button, state, lx, ly, &mut self.ui_context);
-            if toggle.take_click() {
-                actions.push(AppAction::Input(pages::input::InputMessage::ToggleInertialScroll));
-            }
-            let toggle = &mut self.app.input.natural_toggle;
-            toggle.mouse_input(button, state, lx, ly, &mut self.ui_context);
-            if toggle.take_click() {
-                actions.push(AppAction::Input(pages::input::InputMessage::ToggleNaturalScroll));
-            }
-            let toggle = &mut self.app.input.pointer_toggle;
-            toggle.mouse_input(button, state, lx, ly, &mut self.ui_context);
-            if toggle.take_click() {
-                actions.push(AppAction::Input(pages::input::InputMessage::ToggleInertialPointer));
-            }
-            let toggle = &mut self.app.input.trackpad_toggle;
-            toggle.mouse_input(button, state, lx, ly, &mut self.ui_context);
-            if toggle.take_click() {
-                actions.push(AppAction::Input(pages::input::InputMessage::ToggleInertialTrackpad));
-            }
-            let toggle = &mut self.app.input.dwtp_toggle;
-            toggle.mouse_input(button, state, lx, ly, &mut self.ui_context);
-            if toggle.take_click() {
-                actions.push(AppAction::Input(pages::input::InputMessage::ToggleDwtp));
-            }
-            let menu = &mut self.app.input.trackpoint_accel_profile_menu;
-            if state == cce_ui::widget::ElementState::Pressed && !menu.hit_test(lx, ly, &self.ui_context) { menu.unfocus(); }
-            if menu.mouse_input(button, state, lx, ly, &mut self.ui_context) {
-                self.needs_rebuild = true;
-            }
-            if state == cce_ui::widget::ElementState::Pressed && menu.take_change() {
-                actions.push(AppAction::Input(pages::input::InputMessage::ApplyTrackpointAccelProfile(menu.selected)));
-            }
-            let menu = &mut self.app.input.cursor_theme_menu;
-            if state == cce_ui::widget::ElementState::Pressed && !menu.hit_test(lx, ly, &self.ui_context) { menu.unfocus(); }
-            if menu.mouse_input(button, state, lx, ly, &mut self.ui_context) {
-                self.needs_rebuild = true;
-            }
-            if state == cce_ui::widget::ElementState::Pressed && menu.take_change() {
-                actions.push(AppAction::Input(pages::input::InputMessage::ApplyCursorTheme(menu.selected)));
-            }
-
-            let tb = &mut self.app.input.zoom_in_box;
-            if state == cce_ui::widget::ElementState::Pressed && !tb.hit_test(lx, ly, &self.ui_context) { tb.unfocus(); }
-            if tb.mouse_input(button, state, lx, ly, &mut self.ui_context) {
-                self.needs_rebuild = true;
-            }
-            if state == cce_ui::widget::ElementState::Pressed && tb.take_change() {
-                actions.push(AppAction::Input(pages::input::InputMessage::ApplyZoomIn));
-            }
-
-            let tb = &mut self.app.input.zoom_out_box;
-            if state == cce_ui::widget::ElementState::Pressed && !tb.hit_test(lx, ly, &self.ui_context) { tb.unfocus(); }
-            if tb.mouse_input(button, state, lx, ly, &mut self.ui_context) {
-                self.needs_rebuild = true;
-            }
-            if state == cce_ui::widget::ElementState::Pressed && tb.take_change() {
-                actions.push(AppAction::Input(pages::input::InputMessage::ApplyZoomOut));
-            }
-            let kc = &mut self.app.input.keybinds_control;
-            if kc.mouse_input(button, state, lx, ly, &mut self.ui_context) {
-                self.needs_rebuild = true;
-            }
-            if kc.take_change() {
-                actions.push(AppAction::Input(pages::input::InputMessage::ReloadKeybinds));
-                self.needs_rebuild = true;
-            }
-        }
-        if self.app.current_page == Page::Services {
-            let toggle = &mut self.app.services.notifications_enable_toggle;
-            toggle.mouse_input(button, state, lx, ly, &mut self.ui_context);
-            if toggle.take_click() {
-                actions.push(AppAction::Services(pages::services::ServicesMessage::ToggleNotificationsEnable));
-            }
-            let toggle = &mut self.app.services.notifications_bell_toggle;
-            toggle.mouse_input(button, state, lx, ly, &mut self.ui_context);
-            if toggle.take_click() {
-                actions.push(AppAction::Services(pages::services::ServicesMessage::ToggleNotificationsBell));
-            }
-            if state == cce_ui::widget::ElementState::Pressed {
-                let lbl1 = &mut self.app.services.status_label;
-                if !lbl1.hit_test(lx, ly, &self.ui_context) { lbl1.unfocus(); }
-                lbl1.mouse_input(button, state, lx, ly, &mut self.ui_context);
-            }
-            let toggle = &mut self.app.services.status_separators_toggle;
-            toggle.mouse_input(button, state, lx, ly, &mut self.ui_context);
-            if toggle.take_click() {
-                actions.push(AppAction::Services(pages::services::ServicesMessage::StatusToggleSeparators));
-            }
-            let toggle2 = &mut self.app.services.status_underline_toggle;
-            toggle2.mouse_input(button, state, lx, ly, &mut self.ui_context);
-            if toggle2.take_click() {
-                actions.push(AppAction::Services(pages::services::ServicesMessage::StatusToggleUnderline));
-            }
-        }
-        if self.app.current_page == Page::Display {
-            let toggle = &mut self.app.display.screensaver_enable_toggle;
-            toggle.mouse_input(button, state, lx, ly, &mut self.ui_context);
-            if toggle.take_click() {
-                actions.push(AppAction::Display(pages::display::DisplayMessage::ToggleScreensaverEnable));
-            }
-
-            let toggle = &mut self.app.display.screensaver_lock_screen_toggle;
-            toggle.mouse_input(button, state, lx, ly, &mut self.ui_context);
-            if toggle.take_click() {
-                actions.push(AppAction::Display(pages::display::DisplayMessage::ToggleScreensaverLockScreen));
-            }
-
-            let menu = &mut self.app.display.screensaver_style_menu;
-            if state == cce_ui::widget::ElementState::Pressed && !menu.hit_test(lx, ly, &self.ui_context) { menu.unfocus(); }
-            if menu.mouse_input(button, state, lx, ly, &mut self.ui_context) {
-                self.needs_rebuild = true;
-            }
-            if state == cce_ui::widget::ElementState::Pressed && menu.take_change() {
-                actions.push(AppAction::Display(pages::display::DisplayMessage::SetScreensaverStyle(menu.selected)));
-            }
-        }
-        if self.app.current_page == Page::Hardware {
-            let menu = &mut self.app.hardware.cpu_gov_menu;
-            if state == cce_ui::widget::ElementState::Pressed && !menu.hit_test(lx, ly, &self.ui_context) { menu.unfocus(); }
-            if menu.mouse_input(button, state, lx, ly, &mut self.ui_context) {
-                self.needs_rebuild = true;
-            }
-            if state == cce_ui::widget::ElementState::Pressed && menu.take_change() {
-                if menu.selected == 0 {
-                    actions.push(AppAction::Hardware(pages::hardware::HardwareMessage::SetCpuPerformance));
-                } else {
-                    actions.push(AppAction::Hardware(pages::hardware::HardwareMessage::SetCpuPowersave));
-                }
-            }
-
-            let menu = &mut self.app.hardware.gpu_gov_menu;
-            if state == cce_ui::widget::ElementState::Pressed && !menu.hit_test(lx, ly, &self.ui_context) { menu.unfocus(); }
-            if menu.mouse_input(button, state, lx, ly, &mut self.ui_context) {
-                self.needs_rebuild = true;
-            }
-            if state == cce_ui::widget::ElementState::Pressed && menu.take_change() {
-                if menu.selected == 0 {
-                    actions.push(AppAction::Hardware(pages::hardware::HardwareMessage::SetGpuDefault));
-                } else {
-                    actions.push(AppAction::Hardware(pages::hardware::HardwareMessage::SetGpuPowersave));
-                }
-            }
-        }
-
-        if state == cce_ui::widget::ElementState::Pressed && self.app.current_page == Page::Audio {
-            if button == cce_ui::widget::MouseButton::Left {
-                for (i, slider) in self.app.audio.sink_sliders.iter_mut().enumerate() {
-                    if slider.hit_test(lx, ly, &self.ui_context) {
-                        slider.drag_begin(lx, ly);
-                        self.audio_sink_dragging = Some(i);
-                        self.needs_rebuild = true;
-                    }
-                }
-                for (i, slider) in self.app.audio.source_sliders.iter_mut().enumerate() {
-                    if slider.hit_test(lx, ly, &self.ui_context) {
-                        slider.drag_begin(lx, ly);
-                        self.audio_source_dragging = Some(i);
-                        self.needs_rebuild = true;
-                    }
-                }
-            }
-            for (i, sb) in self.app.audio.sink_spinboxes.iter_mut().enumerate() {
-                if !sb.hit_test(lx, ly, &self.ui_context) { sb.unfocus(); }
-                let old = sb.value;
-                if sb.mouse_input(button, state, lx, ly, &mut self.ui_context) && sb.value != old {
-                    let id = self.app.audio.sinks[i].id;
-                    actions.push(AppAction::Audio(pages::audio::AudioMessage::SinkVolume(id, sb.value as f32 / 100.0)));
-                }
-            }
-            for (i, sb) in self.app.audio.source_spinboxes.iter_mut().enumerate() {
-                if !sb.hit_test(lx, ly, &self.ui_context) { sb.unfocus(); }
-                let old = sb.value;
-                if sb.mouse_input(button, state, lx, ly, &mut self.ui_context) && sb.value != old {
-                    let id = self.app.audio.sources[i].id;
-                    actions.push(AppAction::Audio(pages::audio::AudioMessage::SourceVolume(id, sb.value as f32 / 100.0)));
-                }
-            }
-        }
-        if state == cce_ui::widget::ElementState::Pressed && self.app.current_page == Page::Display {
-            if button == cce_ui::widget::MouseButton::Left {
-                let slider = &mut self.app.display.brightness_slider;
-                if slider.hit_test(lx, ly, &self.ui_context) {
-                    slider.drag_begin(lx, ly);
-                    self.display_brightness_dragging = true;
-                    self.needs_rebuild = true;
-                }
-            }
-            let sb = &mut self.app.display.brightness_spinbox;
-            if !sb.hit_test(lx, ly, &self.ui_context) { sb.unfocus(); }
-            let old = sb.value;
-            if sb.mouse_input(button, state, lx, ly, &mut self.ui_context) && sb.value != old {
-                actions.push(AppAction::Display(pages::display::DisplayMessage::BrightnessSet(sb.value as u32)));
-            }
-            let lbl = &mut self.app.display.night_light_label;
-            if !lbl.hit_test(lx, ly, &self.ui_context) { lbl.unfocus(); }
-            lbl.mouse_input(button, state, lx, ly, &mut self.ui_context);
-
-            for out in &mut self.app.display.outputs {
-                let lbl = &mut out.name_label;
-                if !lbl.hit_test(lx, ly, &self.ui_context) { lbl.unfocus(); }
-                lbl.mouse_input(button, state, lx, ly, &mut self.ui_context);
-
-                let lbl2 = &mut out.resolution_label;
-                if !lbl2.hit_test(lx, ly, &self.ui_context) { lbl2.unfocus(); }
-                lbl2.mouse_input(button, state, lx, ly, &mut self.ui_context);
-
-                if let Some(ref mut scale_lbl) = out.scale_label {
-                    if !scale_lbl.hit_test(lx, ly, &self.ui_context) { scale_lbl.unfocus(); }
-                    scale_lbl.mouse_input(button, state, lx, ly, &mut self.ui_context);
-                }
-            }
-
-            let sb = &mut self.app.display.screensaver_timeout_spinbox;
-            if !sb.hit_test(lx, ly, &self.ui_context) { sb.unfocus(); }
-            let old = sb.value;
-            if sb.mouse_input(button, state, lx, ly, &mut self.ui_context) && sb.value != old {
-                actions.push(AppAction::Display(pages::display::DisplayMessage::SetScreensaverTimeout(sb.value)));
-            }
-        }
-
-        if self.app.current_page == Page::Accounts {
-            if self.app.accounts.editing_oauth_creds {
-                let tb = &mut self.app.accounts.oauth_client_id_box;
-                if state == cce_ui::widget::ElementState::Pressed && !tb.hit_test(lx, ly, &self.ui_context) { tb.unfocus(); }
-                if tb.mouse_input(button, state, lx, ly, &mut self.ui_context) {
-                    self.needs_rebuild = true;
-                }
-
-                let tb = &mut self.app.accounts.oauth_client_secret_box;
-                if state == cce_ui::widget::ElementState::Pressed && !tb.hit_test(lx, ly, &self.ui_context) { tb.unfocus(); }
-                if tb.mouse_input(button, state, lx, ly, &mut self.ui_context) {
-                    self.needs_rebuild = true;
-                }
-            } else if self.app.accounts.adding_new {
-                let tb = &mut self.app.accounts.email_box;
-                if state == cce_ui::widget::ElementState::Pressed && !tb.hit_test(lx, ly, &self.ui_context) { tb.unfocus(); }
-                if tb.mouse_input(button, state, lx, ly, &mut self.ui_context) {
-                    self.needs_rebuild = true;
-                }
-                if state == cce_ui::widget::ElementState::Pressed && tb.take_change() {
-                    let email_val = tb.text.trim().to_lowercase();
-                    if email_val.ends_with("@gmail.com") {
-                        self.app.accounts.imap_box.text = "imap.gmail.com:993".to_string();
-                        self.app.accounts.imap_box.edit_buffer = "imap.gmail.com:993".to_string();
-                        self.app.accounts.smtp_box.text = "smtp.gmail.com:465".to_string();
-                        self.app.accounts.smtp_box.edit_buffer = "smtp.gmail.com:465".to_string();
-                    } else if email_val.ends_with("@icloud.com") {
-                        self.app.accounts.imap_box.text = "imap.mail.me.com:993".to_string();
-                        self.app.accounts.imap_box.edit_buffer = "imap.mail.me.com:993".to_string();
-                        self.app.accounts.smtp_box.text = "smtp.mail.me.com:587".to_string();
-                        self.app.accounts.smtp_box.edit_buffer = "smtp.mail.me.com:587".to_string();
-                    } else if email_val.ends_with("@outlook.com") || email_val.ends_with("@hotmail.com") {
-                        self.app.accounts.imap_box.text = "outlook.office365.com:993".to_string();
-                        self.app.accounts.imap_box.edit_buffer = "outlook.office365.com:993".to_string();
-                        self.app.accounts.smtp_box.text = "smtp.office365.com:587".to_string();
-                        self.app.accounts.smtp_box.edit_buffer = "smtp.office365.com:587".to_string();
-                    }
-                }
-
-                let tb = &mut self.app.accounts.password_box;
-                if state == cce_ui::widget::ElementState::Pressed && !tb.hit_test(lx, ly, &self.ui_context) { tb.unfocus(); }
-                if tb.mouse_input(button, state, lx, ly, &mut self.ui_context) {
-                    self.needs_rebuild = true;
-                }
-
-                let tb = &mut self.app.accounts.imap_box;
-                if state == cce_ui::widget::ElementState::Pressed && !tb.hit_test(lx, ly, &self.ui_context) { tb.unfocus(); }
-                if tb.mouse_input(button, state, lx, ly, &mut self.ui_context) {
-                    self.needs_rebuild = true;
-                }
-
-                let tb = &mut self.app.accounts.smtp_box;
-                if state == cce_ui::widget::ElementState::Pressed && !tb.hit_test(lx, ly, &self.ui_context) { tb.unfocus(); }
-                if tb.mouse_input(button, state, lx, ly, &mut self.ui_context) {
-                    self.needs_rebuild = true;
-                }
-            }
-        }
-        if self.app.current_page == Page::Interface {
-            let tb = &mut self.app.interface.sans_box;
-            if state == cce_ui::widget::ElementState::Pressed && !tb.hit_test(lx, ly, &self.ui_context) { tb.unfocus(); }
-            if tb.mouse_input(button, state, lx, ly, &mut self.ui_context) {
-                self.needs_rebuild = true;
-            }
-            if state == cce_ui::widget::ElementState::Pressed && tb.take_change() {
-                actions.push(AppAction::Interface(pages::interface::InterfaceMessage::SetSans(tb.text.clone())));
-            }
-
-            let tb = &mut self.app.interface.serif_box;
-            if state == cce_ui::widget::ElementState::Pressed && !tb.hit_test(lx, ly, &self.ui_context) { tb.unfocus(); }
-            if tb.mouse_input(button, state, lx, ly, &mut self.ui_context) {
-                self.needs_rebuild = true;
-            }
-            if state == cce_ui::widget::ElementState::Pressed && tb.take_change() {
-                actions.push(AppAction::Interface(pages::interface::InterfaceMessage::SetSerif(tb.text.clone())));
-            }
-
-            let tb = &mut self.app.interface.mono_box;
-            if state == cce_ui::widget::ElementState::Pressed && !tb.hit_test(lx, ly, &self.ui_context) { tb.unfocus(); }
-            if tb.mouse_input(button, state, lx, ly, &mut self.ui_context) {
-                self.needs_rebuild = true;
-            }
-            if state == cce_ui::widget::ElementState::Pressed && tb.take_change() {
-                actions.push(AppAction::Interface(pages::interface::InterfaceMessage::SetMono(tb.text.clone())));
-            }
-
-            let menu = &mut self.app.interface.borders_menu;
-            if state == cce_ui::widget::ElementState::Pressed && !menu.hit_test(lx, ly, &self.ui_context) { menu.unfocus(); }
-            if menu.mouse_input(button, state, lx, ly, &mut self.ui_context) {
-                self.needs_rebuild = true;
-            }
-            if state == cce_ui::widget::ElementState::Pressed && menu.take_change() {
-                actions.push(AppAction::Interface(pages::interface::InterfaceMessage::SetBordersMenu(menu.selected)));
-            }
-
-            let tb = &mut self.app.interface.borders_box;
-            if state == cce_ui::widget::ElementState::Pressed && !tb.hit_test(lx, ly, &self.ui_context) { tb.unfocus(); }
-            if tb.mouse_input(button, state, lx, ly, &mut self.ui_context) {
-                self.needs_rebuild = true;
-            }
-            if state == cce_ui::widget::ElementState::Pressed && tb.take_change() {
-                actions.push(AppAction::Interface(pages::interface::InterfaceMessage::SetBorders(tb.text.clone())));
-            }
-
-            let menu = &mut self.app.interface.status_menu;
-            if state == cce_ui::widget::ElementState::Pressed && !menu.hit_test(lx, ly, &self.ui_context) { menu.unfocus(); }
-            if menu.mouse_input(button, state, lx, ly, &mut self.ui_context) {
-                self.needs_rebuild = true;
-            }
-            if state == cce_ui::widget::ElementState::Pressed && menu.take_change() {
-                actions.push(AppAction::Interface(pages::interface::InterfaceMessage::SetStatusMenu(menu.selected)));
-            }
-
-            let tb = &mut self.app.interface.status_box;
-            if state == cce_ui::widget::ElementState::Pressed && !tb.hit_test(lx, ly, &self.ui_context) { tb.unfocus(); }
-            if tb.mouse_input(button, state, lx, ly, &mut self.ui_context) {
-                self.needs_rebuild = true;
-            }
-            if state == cce_ui::widget::ElementState::Pressed && tb.take_change() {
-                actions.push(AppAction::Interface(pages::interface::InterfaceMessage::SetStatus(tb.text.clone())));
-            }
-
-            let menu = &mut self.app.interface.fuzzel_menu;
-            if state == cce_ui::widget::ElementState::Pressed && !menu.hit_test(lx, ly, &self.ui_context) { menu.unfocus(); }
-            if menu.mouse_input(button, state, lx, ly, &mut self.ui_context) {
-                self.needs_rebuild = true;
-            }
-            if state == cce_ui::widget::ElementState::Pressed && menu.take_change() {
-                actions.push(AppAction::Interface(pages::interface::InterfaceMessage::SetFuzzelMenu(menu.selected)));
-            }
-
-            let tb = &mut self.app.interface.fuzzel_box;
-            if state == cce_ui::widget::ElementState::Pressed && !tb.hit_test(lx, ly, &self.ui_context) { tb.unfocus(); }
-            if tb.mouse_input(button, state, lx, ly, &mut self.ui_context) {
-                self.needs_rebuild = true;
-            }
-            if state == cce_ui::widget::ElementState::Pressed && tb.take_change() {
-                actions.push(AppAction::Interface(pages::interface::InterfaceMessage::SetFuzzel(tb.text.clone())));
-            }
-
-            let menu = &mut self.app.interface.terminal_menu;
-            if state == cce_ui::widget::ElementState::Pressed && !menu.hit_test(lx, ly, &self.ui_context) { menu.unfocus(); }
-            if menu.mouse_input(button, state, lx, ly, &mut self.ui_context) {
-                self.needs_rebuild = true;
-            }
-            if state == cce_ui::widget::ElementState::Pressed && menu.take_change() {
-                actions.push(AppAction::Interface(pages::interface::InterfaceMessage::SetTerminalMenu(menu.selected)));
-            }
-
-            let tb = &mut self.app.interface.terminal_box;
-            if state == cce_ui::widget::ElementState::Pressed && !tb.hit_test(lx, ly, &self.ui_context) { tb.unfocus(); }
-            if tb.mouse_input(button, state, lx, ly, &mut self.ui_context) {
-                self.needs_rebuild = true;
-            }
-            if state == cce_ui::widget::ElementState::Pressed && tb.take_change() {
-                actions.push(AppAction::Interface(pages::interface::InterfaceMessage::SetTerminal(tb.text.clone())));
-            }
-
-
-
-
-
-            let fs = &mut self.app.interface.color_selector_font_selector;
-            if state == cce_ui::widget::ElementState::Pressed && !fs.hit_test(lx, ly, &self.ui_context) { fs.unfocus(); }
-            if fs.mouse_input(button, state, lx, ly, &mut self.ui_context) {
-                self.needs_rebuild = true;
-            }
-            if fs.take_change() {
-                actions.push(AppAction::Interface(pages::interface::InterfaceMessage::SetColorSelectorFont(fs.font_family.clone())));
-            }
-
-            let fs = &mut self.app.interface.menubar_font_selector;
-            if state == cce_ui::widget::ElementState::Pressed && !fs.hit_test(lx, ly, &self.ui_context) { fs.unfocus(); }
-            if fs.mouse_input(button, state, lx, ly, &mut self.ui_context) {
-                self.needs_rebuild = true;
-            }
-            if fs.take_change() {
-                actions.push(AppAction::Interface(pages::interface::InterfaceMessage::SetMenubarFont(fs.font_family.clone())));
-            }
-
-            let fs = &mut self.app.interface.breadcrumb_font_selector;
-            if state == cce_ui::widget::ElementState::Pressed && !fs.hit_test(lx, ly, &self.ui_context) { fs.unfocus(); }
-            if fs.mouse_input(button, state, lx, ly, &mut self.ui_context) {
-                self.needs_rebuild = true;
-            }
-            if fs.take_change() {
-                actions.push(AppAction::Interface(pages::interface::InterfaceMessage::SetBreadcrumbFont(fs.font_family.clone())));
-            }
-
-            let fs = &mut self.app.interface.section_label_font_selector;
-            if state == cce_ui::widget::ElementState::Pressed && !fs.hit_test(lx, ly, &self.ui_context) { fs.unfocus(); }
-            if fs.mouse_input(button, state, lx, ly, &mut self.ui_context) {
-                self.needs_rebuild = true;
-            }
-            if fs.take_change() {
-                actions.push(AppAction::Interface(pages::interface::InterfaceMessage::SetSectionLabelFont(fs.font_family.clone())));
-            }
-
-            let fs = &mut self.app.interface.nested_section_label_font_selector;
-            if state == cce_ui::widget::ElementState::Pressed && !fs.hit_test(lx, ly, &self.ui_context) { fs.unfocus(); }
-            if fs.mouse_input(button, state, lx, ly, &mut self.ui_context) {
-                self.needs_rebuild = true;
-            }
-            if fs.take_change() {
-                actions.push(AppAction::Interface(pages::interface::InterfaceMessage::SetNestedSectionLabelFont(fs.font_family.clone())));
-            }
-
-            let sb = &mut self.app.interface.borders_size_box;
-            if state == cce_ui::widget::ElementState::Pressed && !sb.hit_test(lx, ly, &self.ui_context) { sb.unfocus(); }
-            let old_val = sb.value;
-            if sb.mouse_input(button, state, lx, ly, &mut self.ui_context) {
-                self.needs_rebuild = true;
-            }
-            if sb.value != old_val {
-                actions.push(AppAction::Interface(pages::interface::InterfaceMessage::SetBordersSize(sb.value)));
-            }
-
-            let sb = &mut self.app.interface.status_size_box;
-            if state == cce_ui::widget::ElementState::Pressed && !sb.hit_test(lx, ly, &self.ui_context) { sb.unfocus(); }
-            let old_val = sb.value;
-            if sb.mouse_input(button, state, lx, ly, &mut self.ui_context) {
-                self.needs_rebuild = true;
-            }
-            if sb.value != old_val {
-                actions.push(AppAction::Interface(pages::interface::InterfaceMessage::SetStatusSize(sb.value)));
-            }
-
-            let sb = &mut self.app.interface.fuzzel_size_box;
-            if state == cce_ui::widget::ElementState::Pressed && !sb.hit_test(lx, ly, &self.ui_context) { sb.unfocus(); }
-            let old_val = sb.value;
-            if sb.mouse_input(button, state, lx, ly, &mut self.ui_context) {
-                self.needs_rebuild = true;
-            }
-            if sb.value != old_val {
-                actions.push(AppAction::Interface(pages::interface::InterfaceMessage::SetFuzzelSize(sb.value)));
-            }
-
-            let sb = &mut self.app.interface.terminal_size_box;
-            if state == cce_ui::widget::ElementState::Pressed && !sb.hit_test(lx, ly, &self.ui_context) { sb.unfocus(); }
-            let old_val = sb.value;
-            if sb.mouse_input(button, state, lx, ly, &mut self.ui_context) {
-                self.needs_rebuild = true;
-            }
-            if sb.value != old_val {
-                actions.push(AppAction::Interface(pages::interface::InterfaceMessage::SetTerminalSize(sb.value)));
-            }
-
-
-
-
-        }
-        if self.app.current_page == Page::Services {
-            let tb = &mut self.app.services.search_box;
-            if state == cce_ui::widget::ElementState::Pressed && !tb.hit_test(lx, ly, &self.ui_context) { tb.unfocus(); }
-            if tb.mouse_input(button, state, lx, ly, &mut self.ui_context) {
-                self.needs_rebuild = true;
-            }
-            let srv = &mut self.app.services;
-            if srv.list_box.mouse_input(button, state, lx, ly, &mut self.ui_context) {
-                self.needs_rebuild = true;
-            }
-            let query = if srv.search_box.editing {
-                srv.search_box.edit_buffer.to_lowercase()
-            } else {
-                srv.search_box.text.to_lowercase()
-            };
-            let matching_count = srv.services.iter()
-                .filter(|s| s.is_system == (srv.active_tab == pages::services::ServiceTab::System))
-                .filter(|s| s.name.to_lowercase().contains(&query) || s.description.to_lowercase().contains(&query))
-                .count();
-            for i in 0..matching_count.min(srv.service_items.len()) {
-                if srv.service_items[i].mouse_input(button, state, lx, ly, &mut self.ui_context) {
-                    self.needs_rebuild = true;
-                }
-            }
-        }
-        if self.app.current_page == Page::Packages {
-            let pkgs = &mut self.app.packages;
-            let tb = &mut pkgs.search_box;
-            if state == cce_ui::widget::ElementState::Pressed && !tb.hit_test(lx, ly, &self.ui_context) {
-                tb.unfocus();
-            }
-            if tb.mouse_input(button, state, lx, ly, &mut self.ui_context) {
-                self.needs_rebuild = true;
-            }
-            match pkgs.active_tab {
-                pages::packages::PackageTab::Installed => {
-                    if pkgs.installed_list_box.mouse_input(button, state, lx, ly, &mut self.ui_context) {
-                        self.needs_rebuild = true;
-                    }
-                    let query = if pkgs.search_box.editing {
-                        pkgs.search_box.edit_buffer.to_lowercase()
-                    } else {
-                        pkgs.search_box.text.to_lowercase()
-                    };
-                    let filtered: Vec<&pages::packages::PackageInfo> = pkgs.installed.iter()
-                        .filter(|p| p.name.to_lowercase().contains(&query) || p.version.to_lowercase().contains(&query))
-                        .collect();
-                    let matching = filtered.len();
-                    for i in 0..matching.min(pkgs.installed_items.len()) {
-                        if pkgs.installed_items[i].mouse_input(button, state, lx, ly, &mut self.ui_context) {
-                            self.needs_rebuild = true;
-                        }
-                        if pkgs.installed_items[i].take_click() {
-                            let pkg_name = filtered[i].name.clone();
-                            actions.push(AppAction::Packages(pages::packages::PackagesMessage::SelectPackage(Some(pkg_name))));
-                        }
-                    }
-                }
-                pages::packages::PackageTab::Updates => {
-                    if pkgs.updates_list_box.mouse_input(button, state, lx, ly, &mut self.ui_context) {
-                        self.needs_rebuild = true;
-                    }
-                    let query = if pkgs.search_box.editing {
-                        pkgs.search_box.edit_buffer.to_lowercase()
-                    } else {
-                        pkgs.search_box.text.to_lowercase()
-                    };
-                    let filtered: Vec<&pages::packages::UpdateInfo> = pkgs.updates.iter()
-                        .filter(|p| p.name.to_lowercase().contains(&query))
-                        .collect();
-                    let matching = filtered.len();
-                    for i in 0..matching.min(pkgs.updates_items.len()) {
-                        if pkgs.updates_items[i].mouse_input(button, state, lx, ly, &mut self.ui_context) {
-                            self.needs_rebuild = true;
-                        }
-                        if pkgs.updates_items[i].take_click() {
-                            let pkg_name = filtered[i].name.clone();
-                            actions.push(AppAction::Packages(pages::packages::PackagesMessage::SelectPackage(Some(pkg_name))));
-                        }
-                    }
-                }
-            }
-        }
-        if state == cce_ui::widget::ElementState::Pressed && self.app.current_page == Page::Hardware {
-            let hw = &mut self.app.hardware;
-            if hw.cpu_list_box.mouse_input(button, state, lx, ly, &mut self.ui_context) {
-                self.needs_rebuild = true;
-            }
-        }
-        if state == cce_ui::widget::ElementState::Pressed && self.app.current_page == Page::Radios {
-            let net = &mut self.app.network;
-            if net.wifi_list_box.mouse_input(button, state, lx, ly, &mut self.ui_context) {
-                self.needs_rebuild = true;
-            }
-            net.wifi_toggle.mouse_input(button, state, lx, ly, &mut self.ui_context);
-            if net.wifi_toggle.take_click() {
-                actions.push(AppAction::Radios(pages::network::NetworkMessage::ToggleWifi));
-            }
-            net.bt_toggle.mouse_input(button, state, lx, ly, &mut self.ui_context);
-            if net.bt_toggle.take_click() {
-                actions.push(AppAction::Radios(pages::network::NetworkMessage::ToggleBluetooth));
-            }
-        }
-        for a in &actions {
-            self.handle_action(a);
-        }
-        if !actions.is_empty() {
-            self.needs_rebuild = true;
-            return true;
-        }
-        self.needs_rebuild = true;
-        true
-    }
-
-    pub(crate) fn propagate_widget_changes(&mut self, actions: &mut Vec<AppAction>) {
-        match self.app.current_page {
-            Page::Interface => {
-                for (i, cp) in self.app.interface.color_selectors.iter_mut().enumerate() {
-                    if cp.take_change() {
-                        actions.push(AppAction::Interface(match i {
-                            0 => pages::interface::InterfaceMessage::SetPageLowColor(cp.color),
-                            1 => pages::interface::InterfaceMessage::SetHighColor(cp.color),
-                            2 => pages::interface::InterfaceMessage::SetVisualGuidesColor(cp.color),
-                            3 => pages::interface::InterfaceMessage::SetDisabledColor(cp.color),
-                            4 => pages::interface::InterfaceMessage::SetSeparatorColor(cp.color),
-                            5 => pages::interface::InterfaceMessage::SetSliderTrackColor(cp.color),
-                            6 => pages::interface::InterfaceMessage::SetColorBordersColor(cp.color),
-                            7 => pages::interface::InterfaceMessage::SetDesktopBackground(cp.color),
-                            8 => pages::interface::InterfaceMessage::SetNormalColor(cp.color),
-                            9 => pages::interface::InterfaceMessage::SetPaginatorSidebarColor(cp.color),
-                            10 => pages::interface::InterfaceMessage::SetPrimaryHighlightColor(cp.color),
-                            11 => pages::interface::InterfaceMessage::SetMenubarTabLabelColor(cp.color),
-                            12 => pages::interface::InterfaceMessage::SetToggleEnabledColor(cp.color),
-                            13 => pages::interface::InterfaceMessage::SetToggleDisabledColor(cp.color),
-                            14 => pages::interface::InterfaceMessage::SetScrollingListBgColor(cp.color),
-                            15 => pages::interface::InterfaceMessage::SetBreadcrumbBgColor(cp.color),
-                            16 => pages::interface::InterfaceMessage::SetPopoverBgColor(cp.color),
-                            17 => pages::interface::InterfaceMessage::SetNotificationBgColor(cp.color),
-                            18 => pages::interface::InterfaceMessage::SetWindowColor(cp.color),
-                            19 => pages::interface::InterfaceMessage::SetPageColor(cp.color),
-                            20 => pages::interface::InterfaceMessage::SetLayerColor(cp.color),
-                            21 => pages::interface::InterfaceMessage::SetScrollingListEntryBgColor([cp.color[0], cp.color[1], cp.color[2], cp.alpha]),
-                            22 => pages::interface::InterfaceMessage::SetScrollingListEntryHighlightColor([cp.color[0], cp.color[1], cp.color[2], cp.alpha]),
-                            _ => pages::interface::InterfaceMessage::SetDesktopBackground(cp.color),
-                        }));
-                    }
-                }
-                if self.app.interface.notification_opacity_spinbox.take_change() {
-                    actions.push(AppAction::Interface(pages::interface::InterfaceMessage::SetNotificationOpacity(self.app.interface.notification_opacity_spinbox.value as f32 / 100.0)));
-                }
-                if self.app.interface.menubar_opacity_spinbox.take_change() {
-                    actions.push(AppAction::Interface(pages::interface::InterfaceMessage::SetMenubarOpacity(self.app.interface.menubar_opacity_spinbox.value as f32 / 100.0)));
-                }
-
-                if self.app.interface.button_padding_spinbox.take_change() {
-                    actions.push(AppAction::Interface(pages::interface::InterfaceMessage::SetButtonPadding(self.app.interface.button_padding_spinbox.value as u16)));
-                }
-                if self.app.interface.section_padding_spinbox.take_change() {
-                    actions.push(AppAction::Interface(pages::interface::InterfaceMessage::SetSectionPadding(self.app.interface.section_padding_spinbox.value as u16)));
-                }
-                if self.app.interface.label_alignment_menu.take_change() {
-                    actions.push(AppAction::Interface(pages::interface::InterfaceMessage::SetNestedSectionLabelAlignment(self.app.interface.label_alignment_menu.selected)));
-                }
-                if self.app.interface.label_offset_spinbox.take_change() {
-                    actions.push(AppAction::Interface(pages::interface::InterfaceMessage::SetNestedSectionLabelOffset(self.app.interface.label_offset_spinbox.value as i16)));
-                }
-                if self.app.interface.label_margin_spinbox.take_change() {
-                    actions.push(AppAction::Interface(pages::interface::InterfaceMessage::SetLabelMargin(self.app.interface.label_margin_spinbox.value as u16)));
-                }
-                if self.app.interface.plate_padding_spinbox.take_change() {
-                    actions.push(AppAction::Interface(pages::interface::InterfaceMessage::SetPlatePadding(self.app.interface.plate_padding_spinbox.value as u16)));
-                }
-                if self.app.interface.graph_show_grid_toggle.take_change() {
-                    actions.push(AppAction::Interface(pages::interface::InterfaceMessage::SetGraphShowGrid(self.app.interface.graph_show_grid_toggle.toggled())));
-                }
-                if self.app.interface.graph_snap_enabled_toggle.take_change() {
-                    actions.push(AppAction::Interface(pages::interface::InterfaceMessage::SetGraphSnapEnabled(self.app.interface.graph_snap_enabled_toggle.toggled())));
-                }
-                if self.app.interface.graph_uniform_background_toggle.take_change() {
-                    actions.push(AppAction::Interface(pages::interface::InterfaceMessage::SetGraphUniformBackground(self.app.interface.graph_uniform_background_toggle.toggled())));
-                }
-                if self.app.interface.graph_cell_opacity_spinbox.take_change() {
-                    actions.push(AppAction::Interface(pages::interface::InterfaceMessage::SetGraphCellOpacity(self.app.interface.graph_cell_opacity_spinbox.value as f32 / 100.0)));
-                }
-                if self.app.interface.graph_gap_opacity_spinbox.take_change() {
-                    actions.push(AppAction::Interface(pages::interface::InterfaceMessage::SetGraphGapOpacity(self.app.interface.graph_gap_opacity_spinbox.value as f32 / 100.0)));
-                }
-                if self.app.interface.page_margin_spinbox.take_change() {
-                    actions.push(AppAction::Interface(pages::interface::InterfaceMessage::SetPageMargin(self.app.interface.page_margin_spinbox.value as u16)));
-                }
-                if self.app.interface.grid_min_col_width_spinbox.take_change() {
-                    actions.push(AppAction::Interface(pages::interface::InterfaceMessage::SetGridMinColWidth(self.app.interface.grid_min_col_width_spinbox.value as u16)));
-                }
-                if self.app.interface.spinbox_height_spinbox.take_change() {
-                    actions.push(AppAction::Interface(pages::interface::InterfaceMessage::SetSpinboxHeight(self.app.interface.spinbox_height_spinbox.value as u16)));
-                }
-                if self.app.interface.spinbox_corner_radius_spinbox.take_change() {
-                    actions.push(AppAction::Interface(pages::interface::InterfaceMessage::SetSpinboxCornerRadius(self.app.interface.spinbox_corner_radius_spinbox.value as u16)));
-                }
-                if self.app.interface.toggle_height_spinbox.take_change() {
-                    actions.push(AppAction::Interface(pages::interface::InterfaceMessage::SetToggleHeight(self.app.interface.toggle_height_spinbox.value as u16)));
-                }
-                if self.app.interface.toggle_corner_radius_spinbox.take_change() {
-                    actions.push(AppAction::Interface(pages::interface::InterfaceMessage::SetToggleCornerRadius(self.app.interface.toggle_corner_radius_spinbox.value as u16)));
-                }
-                if self.app.interface.plate_opacity_spinbox.take_change() {
-                    actions.push(AppAction::Interface(pages::interface::InterfaceMessage::SetPlateOpacity(self.app.interface.plate_opacity_spinbox.value as f32 / 100.0)));
-                }
-                if self.app.interface.plate_corner_radius_spinbox.take_change() {
-                    actions.push(AppAction::Interface(pages::interface::InterfaceMessage::SetPlateCornerRadius(self.app.interface.plate_corner_radius_spinbox.value as u16)));
-                }
-                if self.app.interface.page_opacity_spinbox.take_change() {
-                    actions.push(AppAction::Interface(pages::interface::InterfaceMessage::SetPageOpacity(self.app.interface.page_opacity_spinbox.value as f32 / 100.0)));
-                }
-                if self.app.interface.layer_opacity_spinbox.take_change() {
-                    actions.push(AppAction::Interface(pages::interface::InterfaceMessage::SetLayerOpacity(self.app.interface.layer_opacity_spinbox.value as f32 / 100.0)));
-                }
-
-
-                if self.app.interface.color_selector_height_spinbox.take_change() {
-                    actions.push(AppAction::Interface(pages::interface::InterfaceMessage::SetColorSelectorHeight(self.app.interface.color_selector_height_spinbox.value as u16)));
-                }
-                if self.app.interface.color_selector_corner_radius_spinbox.take_change() {
-                    actions.push(AppAction::Interface(pages::interface::InterfaceMessage::SetColorSelectorCornerRadius(self.app.interface.color_selector_corner_radius_spinbox.value as u16)));
-                }
-                if self.app.interface.color_selector_preview_corner_radius_spinbox.take_change() {
-                    actions.push(AppAction::Interface(pages::interface::InterfaceMessage::SetColorSelectorPreviewCornerRadius(self.app.interface.color_selector_preview_corner_radius_spinbox.value as u16)));
-                }
-                if self.app.interface.color_selector_preview_margin_spinbox.take_change() {
-                    actions.push(AppAction::Interface(pages::interface::InterfaceMessage::SetColorSelectorPreviewMargin(self.app.interface.color_selector_preview_margin_spinbox.value as u16)));
-                }
-                if self.app.interface.textbox_height_spinbox.take_change() {
-                    actions.push(AppAction::Interface(pages::interface::InterfaceMessage::SetTextboxHeight(self.app.interface.textbox_height_spinbox.value as u16)));
-                }
-                if self.app.interface.textbox_corner_radius_spinbox.take_change() {
-                    actions.push(AppAction::Interface(pages::interface::InterfaceMessage::SetTextboxCornerRadius(self.app.interface.textbox_corner_radius_spinbox.value as u16)));
-                }
-                if self.app.interface.slider_height_spinbox.take_change() {
-                    actions.push(AppAction::Interface(pages::interface::InterfaceMessage::SetSliderHeight(self.app.interface.slider_height_spinbox.value as u16)));
-                }
-                if self.app.interface.font_selector_height_spinbox.take_change() {
-                    actions.push(AppAction::Interface(pages::interface::InterfaceMessage::SetFontSelectorHeight(self.app.interface.font_selector_height_spinbox.value as u16)));
-                }
-                if self.app.interface.font_selector_corner_radius_spinbox.take_change() {
-                    actions.push(AppAction::Interface(pages::interface::InterfaceMessage::SetFontSelectorCornerRadius(self.app.interface.font_selector_corner_radius_spinbox.value as u16)));
-                }
-                if self.app.interface.dropdown_height_spinbox.take_change() {
-                    actions.push(AppAction::Interface(pages::interface::InterfaceMessage::SetDropdownHeight(self.app.interface.dropdown_height_spinbox.value as u16)));
-                }
-                if self.app.interface.dropdown_corner_radius_spinbox.take_change() {
-                    actions.push(AppAction::Interface(pages::interface::InterfaceMessage::SetDropdownCornerRadius(self.app.interface.dropdown_corner_radius_spinbox.value as u16)));
-                }
-                if self.app.interface.button_corner_radius_spinbox.take_change() {
-                    actions.push(AppAction::Interface(pages::interface::InterfaceMessage::SetButtonCornerRadius(self.app.interface.button_corner_radius_spinbox.value as u16)));
-                }
-                if self.app.interface.sans_box.take_change() {
-                    actions.push(AppAction::Interface(pages::interface::InterfaceMessage::SetSans(self.app.interface.sans_box.text.clone())));
-                }
-                if self.app.interface.serif_box.take_change() {
-                    actions.push(AppAction::Interface(pages::interface::InterfaceMessage::SetSerif(self.app.interface.serif_box.text.clone())));
-                }
-                if self.app.interface.mono_box.take_change() {
-                    actions.push(AppAction::Interface(pages::interface::InterfaceMessage::SetMono(self.app.interface.mono_box.text.clone())));
-                }
-                if self.app.interface.borders_menu.take_change() {
-                    actions.push(AppAction::Interface(pages::interface::InterfaceMessage::SetBordersMenu(self.app.interface.borders_menu.selected)));
-                }
-                if self.app.interface.borders_box.take_change() {
-                    actions.push(AppAction::Interface(pages::interface::InterfaceMessage::SetBorders(self.app.interface.borders_box.text.clone())));
-                }
-                if self.app.interface.status_menu.take_change() {
-                    actions.push(AppAction::Interface(pages::interface::InterfaceMessage::SetStatusMenu(self.app.interface.status_menu.selected)));
-                }
-                if self.app.interface.status_box.take_change() {
-                    actions.push(AppAction::Interface(pages::interface::InterfaceMessage::SetStatus(self.app.interface.status_box.text.clone())));
-                }
-                if self.app.interface.fuzzel_menu.take_change() {
-                    actions.push(AppAction::Interface(pages::interface::InterfaceMessage::SetFuzzelMenu(self.app.interface.fuzzel_menu.selected)));
-                }
-                if self.app.interface.fuzzel_box.take_change() {
-                    actions.push(AppAction::Interface(pages::interface::InterfaceMessage::SetFuzzel(self.app.interface.fuzzel_box.text.clone())));
-                }
-                if self.app.interface.terminal_menu.take_change() {
-                    actions.push(AppAction::Interface(pages::interface::InterfaceMessage::SetTerminalMenu(self.app.interface.terminal_menu.selected)));
-                }
-                if self.app.interface.terminal_box.take_change() {
-                    actions.push(AppAction::Interface(pages::interface::InterfaceMessage::SetTerminal(self.app.interface.terminal_box.text.clone())));
-                }
-                if self.app.interface.color_selector_font_selector.take_change() {
-                    actions.push(AppAction::Interface(pages::interface::InterfaceMessage::SetColorSelectorFont(self.app.interface.color_selector_font_selector.font_family.clone())));
-                }
-                if self.app.interface.menubar_font_selector.take_change() {
-                    actions.push(AppAction::Interface(pages::interface::InterfaceMessage::SetMenubarFont(self.app.interface.menubar_font_selector.font_family.clone())));
-                }
-                if self.app.interface.section_label_font_selector.take_change() {
-                    actions.push(AppAction::Interface(pages::interface::InterfaceMessage::SetSectionLabelFont(self.app.interface.section_label_font_selector.font_family.clone())));
-                }
-                if self.app.interface.nested_section_label_font_selector.take_change() {
-                    actions.push(AppAction::Interface(pages::interface::InterfaceMessage::SetNestedSectionLabelFont(self.app.interface.nested_section_label_font_selector.font_family.clone())));
-                }
-                if self.app.interface.borders_size_box.take_change() {
-                    actions.push(AppAction::Interface(pages::interface::InterfaceMessage::SetBordersSize(self.app.interface.borders_size_box.value)));
-                }
-                if self.app.interface.status_size_box.take_change() {
-                    actions.push(AppAction::Interface(pages::interface::InterfaceMessage::SetStatusSize(self.app.interface.status_size_box.value)));
-                }
-
-                let tf = &mut self.app.interface.windows;
-                for (i, sb) in tf.spinboxes.iter_mut().enumerate() {
-                    if sb.take_change() {
-                        actions.push(AppAction::Interface(pages::interface::InterfaceMessage::Windows(pages::interface::WindowsMessage::SetWidth(pages::interface::WidthParam::ALL[i], sb.value as u16))));
-                    }
-                }
-                if tf.cascade_offset_spinbox.take_change() {
-                    actions.push(AppAction::Interface(pages::interface::InterfaceMessage::Windows(pages::interface::WindowsMessage::SetCascadeOffset(tf.cascade_offset_spinbox.value as u16))));
-                }
-                if tf.edge_gap_spinbox.take_change() {
-                    actions.push(AppAction::Interface(pages::interface::InterfaceMessage::Windows(pages::interface::WindowsMessage::SetEdgeGap(tf.edge_gap_spinbox.value as u16))));
-                }
-                if tf.top_gap_spinbox.take_change() {
-                    actions.push(AppAction::Interface(pages::interface::InterfaceMessage::Windows(pages::interface::WindowsMessage::SetTopGap(tf.top_gap_spinbox.value as u16))));
-                }
-                if tf.grid_gap_spinbox.take_change() {
-                    actions.push(AppAction::Interface(pages::interface::InterfaceMessage::Windows(pages::interface::WindowsMessage::SetGridGap(tf.grid_gap_spinbox.value as u16))));
-                }
-                if tf.transition_duration_spinbox.take_change() {
-                    actions.push(AppAction::Interface(pages::interface::InterfaceMessage::Windows(pages::interface::WindowsMessage::SetTransitionDuration(tf.transition_duration_spinbox.value as u16))));
-                }
-                if tf.status_height_spinbox.take_change() {
-                    actions.push(AppAction::Interface(pages::interface::InterfaceMessage::Windows(pages::interface::WindowsMessage::SetStatusHeight(tf.status_height_spinbox.value as u16))));
-                }
-                for (idx, menu) in tf.tag_layout_menus.iter_mut().enumerate() {
-                    if menu.take_change() {
-                        actions.push(AppAction::Interface(pages::interface::InterfaceMessage::Windows(pages::interface::WindowsMessage::SetTagLayout(idx + 1, menu.selected))));
-                    }
-                }
-                if tf.side_panel_behavior_menu.take_change() {
-                    actions.push(AppAction::Interface(pages::interface::InterfaceMessage::Windows(pages::interface::WindowsMessage::SetSidePanelBehavior(tf.side_panel_behavior_menu.selected))));
-                }
-                if tf.side_panel_position_menu.take_change() {
-                    actions.push(AppAction::Interface(pages::interface::InterfaceMessage::Windows(pages::interface::WindowsMessage::SetSidePanelPosition(tf.side_panel_position_menu.selected))));
-                }
-                if tf.side_panel_width_spinbox.take_change() {
-                    actions.push(AppAction::Interface(pages::interface::InterfaceMessage::Windows(pages::interface::WindowsMessage::SetSidePanelWidth(tf.side_panel_width_spinbox.value as u16))));
-                }
-                if tf.side_panel_border_gap_spinbox.take_change() {
-                    actions.push(AppAction::Interface(pages::interface::InterfaceMessage::Windows(pages::interface::WindowsMessage::SetSidePanelBorderGap(tf.side_panel_border_gap_spinbox.value as u16))));
-                }
-                if tf.side_panel_border_opacity_spinbox.take_change() {
-                    actions.push(AppAction::Interface(pages::interface::InterfaceMessage::Windows(pages::interface::WindowsMessage::SetSidePanelBorderOpacity(tf.side_panel_border_opacity_spinbox.value as u16))));
-                }
-            }
-            Page::Input => {
-                if self.app.input.rate_spinbox.take_change() {
-                    actions.push(AppAction::Input(pages::input::InputMessage::ApplyRepeat));
-                }
-                if self.app.input.delay_spinbox.take_change() {
-                    actions.push(AppAction::Input(pages::input::InputMessage::ApplyRepeat));
-                }
-                if self.app.input.scroll_friction_spinbox.take_change() {
-                    actions.push(AppAction::Input(pages::input::InputMessage::ApplyScrollFriction));
-                }
-                if self.app.input.scroll_speed_spinbox.take_change() {
-                    actions.push(AppAction::Input(pages::input::InputMessage::ApplyScrollSpeed));
-                }
-                if self.app.input.pointer_friction_spinbox.take_change() {
-                    actions.push(AppAction::Input(pages::input::InputMessage::ApplyPointerFriction));
-                }
-                if self.app.input.trackpad_friction_spinbox.take_change() {
-                    actions.push(AppAction::Input(pages::input::InputMessage::ApplyTrackpadFriction));
-                }
-                if self.app.input.trackpoint_accel_speed_spinbox.take_change() {
-                    actions.push(AppAction::Input(pages::input::InputMessage::ApplyTrackpointAccelSpeed));
-                }
-                if self.app.input.cursor_size_spinbox.take_change() {
-                    actions.push(AppAction::Input(pages::input::InputMessage::ApplyCursorSize));
-                }
-                if self.app.input.tap_toggle.take_change() {
-                    actions.push(AppAction::Input(pages::input::InputMessage::ToggleTapToClick));
-                }
-                if self.app.input.scroll_toggle.take_change() {
-                    actions.push(AppAction::Input(pages::input::InputMessage::ToggleInertialScroll));
-                }
-                if self.app.input.natural_toggle.take_change() {
-                    actions.push(AppAction::Input(pages::input::InputMessage::ToggleNaturalScroll));
-                }
-                if self.app.input.pointer_toggle.take_change() {
-                    actions.push(AppAction::Input(pages::input::InputMessage::ToggleInertialPointer));
-                }
-                if self.app.input.trackpad_toggle.take_change() {
-                    actions.push(AppAction::Input(pages::input::InputMessage::ToggleInertialTrackpad));
-                }
-                if self.app.input.dwtp_toggle.take_change() {
-                    actions.push(AppAction::Input(pages::input::InputMessage::ToggleDwtp));
-                }
-                if self.app.input.trackpoint_accel_profile_menu.take_change() {
-                    actions.push(AppAction::Input(pages::input::InputMessage::ApplyTrackpointAccelProfile(self.app.input.trackpoint_accel_profile_menu.selected)));
-                }
-                if self.app.input.cursor_theme_menu.take_change() {
-                    actions.push(AppAction::Input(pages::input::InputMessage::ApplyCursorTheme(self.app.input.cursor_theme_menu.selected)));
-                }
-                if self.app.input.zoom_in_box.take_change() {
-                    actions.push(AppAction::Input(pages::input::InputMessage::ApplyZoomIn));
-                }
-                if self.app.input.zoom_out_box.take_change() {
-                    actions.push(AppAction::Input(pages::input::InputMessage::ApplyZoomOut));
-                }
-                if self.app.input.keybinds_control.take_change() {
-                    actions.push(AppAction::Input(pages::input::InputMessage::ReloadKeybinds));
-                }
-            }
-            Page::Services => {
-                if self.app.services.notifications_duration_spinbox.take_change() {
-                    actions.push(AppAction::Services(pages::services::ServicesMessage::SetNotificationsDuration(self.app.services.notifications_duration_spinbox.value)));
-                }
-                if self.app.services.status_padding_spinbox.take_change() {
-                    actions.push(AppAction::Services(pages::services::ServicesMessage::StatusSetPadding(self.app.services.status_padding_spinbox.value as u16)));
-                }
-                if self.app.services.notifications_enable_toggle.take_change() {
-                    actions.push(AppAction::Services(pages::services::ServicesMessage::ToggleNotificationsEnable));
-                }
-                if self.app.services.notifications_bell_toggle.take_change() {
-                    actions.push(AppAction::Services(pages::services::ServicesMessage::ToggleNotificationsBell));
-                }
-                if self.app.services.status_separators_toggle.take_change() {
-                    actions.push(AppAction::Services(pages::services::ServicesMessage::StatusToggleSeparators));
-                }
-                if self.app.services.status_underline_toggle.take_change() {
-                    actions.push(AppAction::Services(pages::services::ServicesMessage::StatusToggleUnderline));
-                }
-            }
-            Page::Display => {
-                if self.app.display.screensaver_enable_toggle.take_change() {
-                    actions.push(AppAction::Display(pages::display::DisplayMessage::ToggleScreensaverEnable));
-                }
-                if self.app.display.screensaver_lock_screen_toggle.take_change() {
-                    actions.push(AppAction::Display(pages::display::DisplayMessage::ToggleScreensaverLockScreen));
-                }
-                if self.app.display.screensaver_style_menu.take_change() {
-                    actions.push(AppAction::Display(pages::display::DisplayMessage::SetScreensaverStyle(self.app.display.screensaver_style_menu.selected)));
-                }
-                if self.app.display.brightness_spinbox.take_change() {
-                    actions.push(AppAction::Display(pages::display::DisplayMessage::BrightnessSet(self.app.display.brightness_spinbox.value as u32)));
-                }
-                if self.app.display.brightness_slider.take_change() {
-                    actions.push(AppAction::Display(pages::display::DisplayMessage::BrightnessSet((self.app.display.brightness_slider.value() * 100.0).round() as u32)));
-                }
-                if self.app.display.screensaver_timeout_spinbox.take_change() {
-                    actions.push(AppAction::Display(pages::display::DisplayMessage::SetScreensaverTimeout(self.app.display.screensaver_timeout_spinbox.value)));
-                }
-            }
-            Page::Hardware => {
-                if self.app.hardware.cpu_gov_menu.take_change() {
-                    if self.app.hardware.cpu_gov_menu.selected == 0 {
-                        actions.push(AppAction::Hardware(pages::hardware::HardwareMessage::SetCpuPerformance));
-                    } else {
-                        actions.push(AppAction::Hardware(pages::hardware::HardwareMessage::SetCpuPowersave));
-                    }
-                }
-                if self.app.hardware.gpu_gov_menu.take_change() {
-                    if self.app.hardware.gpu_gov_menu.selected == 0 {
-                        actions.push(AppAction::Hardware(pages::hardware::HardwareMessage::SetGpuDefault));
-                    } else {
-                        actions.push(AppAction::Hardware(pages::hardware::HardwareMessage::SetGpuPowersave));
-                    }
-                }
-            }
-            Page::Accounts => {
-                if self.app.accounts.adding_new && self.app.accounts.email_box.take_change() {
-                    let email_val = self.app.accounts.email_box.text.trim().to_lowercase();
-                    if email_val.ends_with("@gmail.com") {
-                        self.app.accounts.imap_box.text = "imap.gmail.com:993".to_string();
-                        self.app.accounts.imap_box.edit_buffer = "imap.gmail.com:993".to_string();
-                        self.app.accounts.smtp_box.text = "smtp.gmail.com:465".to_string();
-                        self.app.accounts.smtp_box.edit_buffer = "smtp.gmail.com:465".to_string();
-                    } else if email_val.ends_with("@icloud.com") {
-                        self.app.accounts.imap_box.text = "imap.mail.me.com:993".to_string();
-                        self.app.accounts.imap_box.edit_buffer = "imap.mail.me.com:993".to_string();
-                        self.app.accounts.smtp_box.text = "smtp.mail.me.com:587".to_string();
-                        self.app.accounts.smtp_box.edit_buffer = "smtp.mail.me.com:587".to_string();
-                    } else if email_val.ends_with("@outlook.com") || email_val.ends_with("@hotmail.com") {
-                        self.app.accounts.imap_box.text = "outlook.office365.com:993".to_string();
-                        self.app.accounts.imap_box.edit_buffer = "outlook.office365.com:993".to_string();
-                        self.app.accounts.smtp_box.text = "smtp.office365.com:587".to_string();
-                        self.app.accounts.smtp_box.edit_buffer = "smtp.office365.com:587".to_string();
-                    }
-                }
-            }
-            Page::Audio => {
-                for (i, sb) in self.app.audio.sink_spinboxes.iter_mut().enumerate() {
-                    if sb.take_change() {
-                        let id = self.app.audio.sinks[i].id;
-                        actions.push(AppAction::Audio(pages::audio::AudioMessage::SinkVolume(id, sb.value as f32 / 100.0)));
-                    }
-                }
-                for (i, sb) in self.app.audio.source_spinboxes.iter_mut().enumerate() {
-                    if sb.take_change() {
-                        let id = self.app.audio.sources[i].id;
-                        actions.push(AppAction::Audio(pages::audio::AudioMessage::SourceVolume(id, sb.value as f32 / 100.0)));
-                    }
+                if self.app.interface.label_offset_spinbox.take_change() {
+                    actions.push(AppAction::Interface(pages::interface::InterfaceMessage::SetNestedSectionLabelOffset(self.app.interface.label_offset_spinbox.value as i16)));
                 }
-                for (i, slider) in self.app.audio.sink_sliders.iter_mut().enumerate() {
-                    if slider.take_change() {
-                        let id = self.app.audio.sinks[i].id;
-                        actions.push(AppAction::Audio(pages::audio::AudioMessage::SinkVolume(id, slider.value() as f32 / 100.0)));
-                    }
+                if self.app.interface.label_margin_spinbox.take_change() {
+                    actions.push(AppAction::Interface(pages::interface::InterfaceMessage::SetLabelMargin(self.app.interface.label_margin_spinbox.value as u16)));
                 }
-                for (i, slider) in self.app.audio.source_sliders.iter_mut().enumerate() {
-                    if slider.take_change() {
-                        let id = self.app.audio.sources[i].id;
-                        actions.push(AppAction::Audio(pages::audio::AudioMessage::SourceVolume(id, slider.value() as f32 / 100.0)));
-                    }
+                if self.app.interface.plate_padding_spinbox.take_change() {
+                    actions.push(AppAction::Interface(pages::interface::InterfaceMessage::SetPlatePadding(self.app.interface.plate_padding_spinbox.value as u16)));
                 }
-            }
-            Page::Radios => {
-                let net = &mut self.app.network;
-                if net.wifi_toggle.take_change() {
-                    actions.push(AppAction::Radios(pages::network::NetworkMessage::ToggleWifi));
+                if self.app.interface.graph_show_grid_toggle.take_change() {
+                    actions.push(AppAction::Interface(pages::interface::InterfaceMessage::SetGraphShowGrid(self.app.interface.graph_show_grid_toggle.toggled())));
                 }
-                if net.bt_toggle.take_change() {
-                    actions.push(AppAction::Radios(pages::network::NetworkMessage::ToggleBluetooth));
+                if self.app.interface.graph_snap_enabled_toggle.take_change() {
+                    actions.push(AppAction::Interface(pages::interface::InterfaceMessage::SetGraphSnapEnabled(self.app.interface.graph_snap_enabled_toggle.toggled())));
                 }
-            }
-            _ => {}
-        }
-    }
-
-    pub(crate) fn handle_mouse_wheel_internal(&mut self, delta: &cce_ui::widget::MouseScrollDelta, px: f32, py: f32) -> bool {
-        if let Ok(mut file) = std::fs::OpenOptions::new().create(true).append(true).open("/tmp/cce-scroll-debug.log") {
-            use std::io::Write;
-            let _ = writeln!(file, "handle_mouse_wheel_internal: px={}, py={}, delta={:?}, sidebar_w={}", px, py, delta, self.sidebar_width);
-        }
-        let s = 1.0f32;
-        if px >= self.sidebar_width * s {
-            let lx = px / s;
-            let ly = py / s + self.scroll_y;
-            
-            if self.app.current_page == Page::Input {
-                let input = &self.app.input;
-                if input.is_over_trackpad(lx, ly, &self.ui_context) {
-                    return true;
+                if self.app.interface.graph_uniform_background_toggle.take_change() {
+                    actions.push(AppAction::Interface(pages::interface::InterfaceMessage::SetGraphUniformBackground(self.app.interface.graph_uniform_background_toggle.toggled())));
                 }
-            }
-            if self.app.current_page == Page::Audio {
-                let mut actions = Vec::new();
-                for (i, sb) in self.app.audio.sink_spinboxes.iter_mut().enumerate() {
-                    let old = sb.value;
-                    if sb.mouse_wheel(delta, lx, ly, &mut self.ui_context) {
-                        if sb.value != old {
-                            let id = self.app.audio.sinks[i].id;
-                            actions.push(AppAction::Audio(pages::audio::AudioMessage::SinkVolume(id, sb.value as f32 / 100.0)));
-                        }
-                    }
+                if self.app.interface.graph_cell_opacity_spinbox.take_change() {
+                    actions.push(AppAction::Interface(pages::interface::InterfaceMessage::SetGraphCellOpacity(self.app.interface.graph_cell_opacity_spinbox.value as f32 / 100.0)));
                 }
-                for (i, sb) in self.app.audio.source_spinboxes.iter_mut().enumerate() {
-                    let old = sb.value;
-                    if sb.mouse_wheel(delta, lx, ly, &mut self.ui_context) {
-                        if sb.value != old {
-                            let id = self.app.audio.sources[i].id;
-                            actions.push(AppAction::Audio(pages::audio::AudioMessage::SourceVolume(id, sb.value as f32 / 100.0)));
-                        }
-                    }
+                if self.app.interface.graph_gap_opacity_spinbox.take_change() {
+                    actions.push(AppAction::Interface(pages::interface::InterfaceMessage::SetGraphGapOpacity(self.app.interface.graph_gap_opacity_spinbox.value as f32 / 100.0)));
                 }
-                for (i, slider) in self.app.audio.sink_sliders.iter_mut().enumerate() {
-                    let old = slider.value();
-                    if slider.mouse_wheel(delta, lx, ly, &mut self.ui_context) {
-                        let new_val = slider.value();
-                        if new_val != old {
-                            let id = self.app.audio.sinks[i].id;
-                            if i < self.app.audio.sink_spinboxes.len() {
-                                self.app.audio.sink_spinboxes[i].value = (new_val * 100.0).round() as i32;
-                            }
-                            actions.push(AppAction::Audio(pages::audio::AudioMessage::SinkVolume(id, new_val)));
-                        }
-                    }
+                if self.app.interface.page_margin_spinbox.take_change() {
+                    actions.push(AppAction::Interface(pages::interface::InterfaceMessage::SetPageMargin(self.app.interface.page_margin_spinbox.value as u16)));
                 }
-                for (i, slider) in self.app.audio.source_sliders.iter_mut().enumerate() {
-                    let old = slider.value();
-                    if slider.mouse_wheel(delta, lx, ly, &mut self.ui_context) {
-                        let new_val = slider.value();
-                        if new_val != old {
-                            let id = self.app.audio.sources[i].id;
-                            if i < self.app.audio.source_spinboxes.len() {
-                                self.app.audio.source_spinboxes[i].value = (new_val * 100.0).round() as i32;
-                            }
-                            actions.push(AppAction::Audio(pages::audio::AudioMessage::SourceVolume(id, new_val)));
-                        }
-                    }
+                if self.app.interface.grid_min_col_width_spinbox.take_change() {
+                    actions.push(AppAction::Interface(pages::interface::InterfaceMessage::SetGridMinColWidth(self.app.interface.grid_min_col_width_spinbox.value as u16)));
                 }
-                for a in &actions {
-                    self.handle_action(a);
+                if self.app.interface.spinbox_height_spinbox.take_change() {
+                    actions.push(AppAction::Interface(pages::interface::InterfaceMessage::SetSpinboxHeight(self.app.interface.spinbox_height_spinbox.value as u16)));
                 }
-                if !actions.is_empty() {
-                    self.needs_rebuild = true;
-                    return true;
+                if self.app.interface.spinbox_corner_radius_spinbox.take_change() {
+                    actions.push(AppAction::Interface(pages::interface::InterfaceMessage::SetSpinboxCornerRadius(self.app.interface.spinbox_corner_radius_spinbox.value as u16)));
                 }
-            }
-            
-            if self.app.current_page == Page::Display {
-                let mut actions = Vec::new();
-                let slider = &mut self.app.display.brightness_slider;
-                let old_val = slider.value();
-                if slider.mouse_wheel(delta, lx, ly, &mut self.ui_context) {
-                    let new_val = slider.value();
-                    if new_val != old_val {
-                        let pct = (new_val * 100.0).round() as u32;
-                        self.app.display.brightness_spinbox.value = pct as i32;
-                        actions.push(AppAction::Display(pages::display::DisplayMessage::BrightnessSet(pct)));
-                    }
+                if self.app.interface.toggle_height_spinbox.take_change() {
+                    actions.push(AppAction::Interface(pages::interface::InterfaceMessage::SetToggleHeight(self.app.interface.toggle_height_spinbox.value as u16)));
                 }
-                let sb = &mut self.app.display.brightness_spinbox;
-                let old = sb.value;
-                if sb.mouse_wheel(delta, lx, ly, &mut self.ui_context) {
-                    if sb.value != old {
-                        actions.push(AppAction::Display(pages::display::DisplayMessage::BrightnessSet(sb.value as u32)));
-                    }
+                if self.app.interface.toggle_corner_radius_spinbox.take_change() {
+                    actions.push(AppAction::Interface(pages::interface::InterfaceMessage::SetToggleCornerRadius(self.app.interface.toggle_corner_radius_spinbox.value as u16)));
                 }
-                let sb2 = &mut self.app.display.screensaver_timeout_spinbox;
-                let old2 = sb2.value;
-                if sb2.mouse_wheel(delta, lx, ly, &mut self.ui_context) {
-                    if sb2.value != old2 {
-                        actions.push(AppAction::Display(pages::display::DisplayMessage::SetScreensaverTimeout(sb2.value)));
-                    }
+                if self.app.interface.plate_opacity_spinbox.take_change() {
+                    actions.push(AppAction::Interface(pages::interface::InterfaceMessage::SetPlateOpacity(self.app.interface.plate_opacity_spinbox.value as f32 / 100.0)));
                 }
-                for a in &actions {
-                    self.handle_action(a);
+                if self.app.interface.plate_corner_radius_spinbox.take_change() {
+                    actions.push(AppAction::Interface(pages::interface::InterfaceMessage::SetPlateCornerRadius(self.app.interface.plate_corner_radius_spinbox.value as u16)));
                 }
-                if !actions.is_empty() {
-                    self.needs_rebuild = true;
-                    return true;
+                if self.app.interface.page_opacity_spinbox.take_change() {
+                    actions.push(AppAction::Interface(pages::interface::InterfaceMessage::SetPageOpacity(self.app.interface.page_opacity_spinbox.value as f32 / 100.0)));
+                }
+                if self.app.interface.layer_opacity_spinbox.take_change() {
+                    actions.push(AppAction::Interface(pages::interface::InterfaceMessage::SetLayerOpacity(self.app.interface.layer_opacity_spinbox.value as f32 / 100.0)));
                 }
-            }
 
 
-            if self.app.current_page == Page::Interface {
-                let mut actions = Vec::new();
-                let sb = &mut self.app.interface.graph_cell_opacity_spinbox;
-                let old = sb.value;
-                if sb.mouse_wheel(delta, lx, ly, &mut self.ui_context) {
-                    if sb.value != old {
-                        actions.push(AppAction::Interface(pages::interface::InterfaceMessage::SetGraphCellOpacity(sb.value as f32 / 100.0)));
-                    }
-                }
-                let sb2 = &mut self.app.interface.graph_gap_opacity_spinbox;
-                let old2 = sb2.value;
-                if sb2.mouse_wheel(delta, lx, ly, &mut self.ui_context) {
-                    if sb2.value != old2 {
-                        actions.push(AppAction::Interface(pages::interface::InterfaceMessage::SetGraphGapOpacity(sb2.value as f32 / 100.0)));
-                    }
-                }
-                let sb3 = &mut self.app.interface.window_opacity_spinbox;
-                let old3 = sb3.value;
-                if sb3.mouse_wheel(delta, lx, ly, &mut self.ui_context) {
-                    if sb3.value != old3 {
-                        actions.push(AppAction::Interface(pages::interface::InterfaceMessage::SetWindowOpacity(sb3.value as f32 / 100.0)));
-                    }
-                }
-                let sb4 = &mut self.app.interface.window_corner_radius_spinbox;
-                let old4 = sb4.value;
-                if sb4.mouse_wheel(delta, lx, ly, &mut self.ui_context) {
-                    if sb4.value != old4 {
-                        actions.push(AppAction::Interface(pages::interface::InterfaceMessage::SetWindowCornerRadius(sb4.value as u16)));
-                    }
-                }
-                let sb5 = &mut self.app.interface.plate_opacity_spinbox;
-                let old5 = sb5.value;
-                if sb5.mouse_wheel(delta, lx, ly, &mut self.ui_context) {
-                    if sb5.value != old5 {
-                        actions.push(AppAction::Interface(pages::interface::InterfaceMessage::SetPlateOpacity(sb5.value as f32 / 100.0)));
-                    }
-                }
-                let sb6 = &mut self.app.interface.plate_corner_radius_spinbox;
-                let old6 = sb6.value;
-                if sb6.mouse_wheel(delta, lx, ly, &mut self.ui_context) {
-                    if sb6.value != old6 {
-                        actions.push(AppAction::Interface(pages::interface::InterfaceMessage::SetPlateCornerRadius(sb6.value as u16)));
-                    }
-                }
-                let sb7 = &mut self.app.interface.page_opacity_spinbox;
-                let old7 = sb7.value;
-                if sb7.mouse_wheel(delta, lx, ly, &mut self.ui_context) {
-                    if sb7.value != old7 {
-                        actions.push(AppAction::Interface(pages::interface::InterfaceMessage::SetPageOpacity(sb7.value as f32 / 100.0)));
-                    }
-                }
-                let sb8 = &mut self.app.interface.layer_opacity_spinbox;
-                let old8 = sb8.value;
-                if sb8.mouse_wheel(delta, lx, ly, &mut self.ui_context) {
-                    if sb8.value != old8 {
-                        actions.push(AppAction::Interface(pages::interface::InterfaceMessage::SetLayerOpacity(sb8.value as f32 / 100.0)));
-                    }
-                }
-                for a in &actions {
-                    self.handle_action(a);
+                if self.app.interface.color_selector_height_spinbox.take_change() {
+                    actions.push(AppAction::Interface(pages::interface::InterfaceMessage::SetColorSelectorHeight(self.app.interface.color_selector_height_spinbox.value as u16)));
                 }
-                if !actions.is_empty() {
-                    self.needs_rebuild = true;
-                    return true;
+                if self.app.interface.color_selector_corner_radius_spinbox.take_change() {
+                    actions.push(AppAction::Interface(pages::interface::InterfaceMessage::SetColorSelectorCornerRadius(self.app.interface.color_selector_corner_radius_spinbox.value as u16)));
                 }
-            }
-
-            if self.app.current_page == Page::Services {
-                let srv = &mut self.app.services;
-                if srv.list_box.mouse_wheel(delta, lx, ly, &mut self.ui_context) {
-                    self.needs_rebuild = true;
-                    return true;
+                if self.app.interface.color_selector_preview_corner_radius_spinbox.take_change() {
+                    actions.push(AppAction::Interface(pages::interface::InterfaceMessage::SetColorSelectorPreviewCornerRadius(self.app.interface.color_selector_preview_corner_radius_spinbox.value as u16)));
                 }
-            }
-            if self.app.current_page == Page::Packages {
-                let pkgs = &mut self.app.packages;
-                match pkgs.active_tab {
-                    pages::packages::PackageTab::Installed => {
-                        if pkgs.installed_list_box.mouse_wheel(delta, lx, ly, &mut self.ui_context) {
-                            self.needs_rebuild = true;
-                            return true;
-                        }
-                    }
-                    pages::packages::PackageTab::Updates => {
-                        if pkgs.updates_list_box.mouse_wheel(delta, lx, ly, &mut self.ui_context) {
-                            self.needs_rebuild = true;
-                            return true;
-                        }
-                    }
+                if self.app.interface.color_selector_preview_margin_spinbox.take_change() {
+                    actions.push(AppAction::Interface(pages::interface::InterfaceMessage::SetColorSelectorPreviewMargin(self.app.interface.color_selector_preview_margin_spinbox.value as u16)));
                 }
-            }
-            if self.app.current_page == Page::Hardware {
-                let hw = &mut self.app.hardware;
-                if hw.cpu_list_box.mouse_wheel(delta, lx, ly, &mut self.ui_context) {
-                    self.needs_rebuild = true;
-                    return true;
+                if self.app.interface.textbox_height_spinbox.take_change() {
+                    actions.push(AppAction::Interface(pages::interface::InterfaceMessage::SetTextboxHeight(self.app.interface.textbox_height_spinbox.value as u16)));
                 }
-            }
-            if self.app.current_page == Page::Radios {
-                let net = &mut self.app.network;
-                if net.wifi_list_box.mouse_wheel(delta, lx, ly, &mut self.ui_context) {
-                    self.needs_rebuild = true;
-                    return true;
+                if self.app.interface.textbox_corner_radius_spinbox.take_change() {
+                    actions.push(AppAction::Interface(pages::interface::InterfaceMessage::SetTextboxCornerRadius(self.app.interface.textbox_corner_radius_spinbox.value as u16)));
                 }
-            }
-
-            let scroll_speed = 24.0;
-            let dy = match delta {
-                cce_ui::widget::MouseScrollDelta::LineDelta(_, y) => -y * scroll_speed,
-                cce_ui::widget::MouseScrollDelta::PixelDelta(pos) => -pos.y as f32,
-            };
-            let old_scroll = self.scroll_y;
-            self.scroll_y = (self.scroll_y + dy).max(0.0).min(self.max_scroll_y);
-            if (self.scroll_y - old_scroll).abs() > 0.01 {
-                self.needs_rebuild = true;
-                return true;
-            }
-        } else {
-            let lx = px / s;
-            let ly = py / s;
-            if self.menubar.mouse_wheel(delta, lx, ly, &mut self.ui_context) {
-                self.needs_rebuild = true;
-                return true;
-            }
-        }
-        false
-    }
-
-    pub(crate) fn get_page_root_widget(&mut self) -> Option<*mut (dyn cce_ui::widget::Element + 'static)> {
-        let page_idx = Page::ALL.iter().position(|&p| p == self.app.current_page).unwrap_or(0);
-        let ptr = &mut self.plates[page_idx] as &mut dyn cce_ui::widget::Element as *mut dyn cce_ui::widget::Element;
-        let static_ptr = unsafe {
-            std::mem::transmute::<*mut dyn cce_ui::widget::Element, *mut (dyn cce_ui::widget::Element + 'static)>(ptr)
-        };
-        Some(static_ptr)
-    }
-
-    pub(crate) fn handle_key_input_internal(&mut self, event: &cce_ui::widget::KeyEvent) -> bool {
-        if cce_ui::widget::context_menu::is_visible() {
-            if event.state == cce_ui::widget::ElementState::Pressed
-                && event.logical_key == cce_ui::widget::Key::Named(cce_ui::widget::NamedKey::Escape)
-            {
-                cce_ui::widget::context_menu::hide();
-                self.needs_rebuild = true;
-                return true;
-            }
-        }
-
-        if event.state == cce_ui::widget::ElementState::Pressed && !event.repeat {
-            let is_nav_key = match (&event.logical_key, event.ctrl) {
-                (cce_ui::widget::Key::Character(c), true) if c == "j" || c == "J" || c == "k" || c == "K" || c == "u" || c == "U" || c == "i" || c == "I" => true,
-                _ => false,
-            };
-            if is_nav_key {
-                if cce_ui::widget::focus::has_focus() {
-                    if cce_ui::widget::focus::navigate_focus(&event.logical_key, event.ctrl) {
-                        self.needs_rebuild = true;
-                        return true;
-                    }
-                } else {
-                    if let Some(root_ptr) = self.get_page_root_widget() {
-                        unsafe {
-                            let root_ref = &mut *root_ptr;
-                            cce_ui::widget::focus::set_focused(root_ref);
-                            root_ref.focus();
-                            self.needs_rebuild = true;
-                            return true;
-                        }
-                    }
+                if self.app.interface.slider_height_spinbox.take_change() {
+                    actions.push(AppAction::Interface(pages::interface::InterfaceMessage::SetSliderHeight(self.app.interface.slider_height_spinbox.value as u16)));
                 }
-            }
-        }
-
-        if self.app.current_page == Page::Interface {
-            let mc = &mut self.app.interface.custom_multicontrol;
-            if mc.keyboard_input(event, &mut self.ui_context) {
-                self.needs_rebuild = true;
-                return true;
-            }
-            let mut changed = false;
-            let mut actions = Vec::new();
-            for (i, cp) in self.app.interface.color_selectors.iter_mut().enumerate() {
-                let old = cp.color;
-                let old_alpha = cp.alpha;
-                if cp.keyboard_input(event, &mut self.ui_context) {
-                    if cp.color != old || cp.alpha != old_alpha {
-                        actions.push(AppAction::Interface(match i {
-                            0 => pages::interface::InterfaceMessage::SetPageLowColor(cp.color),
-                            1 => pages::interface::InterfaceMessage::SetHighColor(cp.color),
-                            2 => pages::interface::InterfaceMessage::SetVisualGuidesColor(cp.color),
-                            3 => pages::interface::InterfaceMessage::SetDisabledColor(cp.color),
-                            4 => pages::interface::InterfaceMessage::SetSeparatorColor(cp.color),
-                            5 => pages::interface::InterfaceMessage::SetSliderTrackColor(cp.color),
-                            6 => pages::interface::InterfaceMessage::SetColorBordersColor(cp.color),
-                            7 => pages::interface::InterfaceMessage::SetDesktopBackground(cp.color),
-                            8 => pages::interface::InterfaceMessage::SetNormalColor(cp.color),
-                            9 => pages::interface::InterfaceMessage::SetPaginatorSidebarColor(cp.color),
-                            10 => pages::interface::InterfaceMessage::SetPrimaryHighlightColor(cp.color),
-                            11 => pages::interface::InterfaceMessage::SetMenubarTabLabelColor(cp.color),
-                            12 => pages::interface::InterfaceMessage::SetToggleEnabledColor(cp.color),
-                            13 => pages::interface::InterfaceMessage::SetToggleDisabledColor(cp.color),
-                            14 => pages::interface::InterfaceMessage::SetScrollingListBgColor(cp.color),
-                            15 => pages::interface::InterfaceMessage::SetBreadcrumbBgColor(cp.color),
-                            16 => pages::interface::InterfaceMessage::SetPopoverBgColor(cp.color),
-                            17 => pages::interface::InterfaceMessage::SetNotificationBgColor(cp.color),
-                            18 => pages::interface::InterfaceMessage::SetWindowColor(cp.color),
-                            19 => pages::interface::InterfaceMessage::SetPageColor(cp.color),
-                            20 => pages::interface::InterfaceMessage::SetLayerColor(cp.color),
-                            21 => pages::interface::InterfaceMessage::SetScrollingListEntryBgColor([cp.color[0], cp.color[1], cp.color[2], cp.alpha]),
-                            22 => pages::interface::InterfaceMessage::SetScrollingListEntryHighlightColor([cp.color[0], cp.color[1], cp.color[2], cp.alpha]),
-                            _ => pages::interface::InterfaceMessage::SetDesktopBackground(cp.color),
-                        }));
-                    }
-                    changed = true;
+                if self.app.interface.font_selector_height_spinbox.take_change() {
+                    actions.push(AppAction::Interface(pages::interface::InterfaceMessage::SetFontSelectorHeight(self.app.interface.font_selector_height_spinbox.value as u16)));
                 }
-            }
-            for a in &actions {
-                self.handle_action(a);
-            }
-            if changed {
-                self.needs_rebuild = true;
-                return true;
-            }
-            let sb = &mut self.app.interface.notification_opacity_spinbox;
-            let old = sb.value;
-            if sb.keyboard_input(event, &mut self.ui_context) {
-                let new_val = sb.value;
-                if new_val != old {
-                    self.handle_action(&AppAction::Interface(pages::interface::InterfaceMessage::SetNotificationOpacity(new_val as f32 / 100.0)));
+                if self.app.interface.font_selector_corner_radius_spinbox.take_change() {
+                    actions.push(AppAction::Interface(pages::interface::InterfaceMessage::SetFontSelectorCornerRadius(self.app.interface.font_selector_corner_radius_spinbox.value as u16)));
                 }
-                self.needs_rebuild = true;
-                return true;
-            }
-            let sb = &mut self.app.interface.window_opacity_spinbox;
-            let old = sb.value;
-            if sb.keyboard_input(event, &mut self.ui_context) {
-                let new_val = sb.value;
-                if new_val != old {
-                    self.handle_action(&AppAction::Interface(pages::interface::InterfaceMessage::SetWindowOpacity(new_val as f32 / 100.0)));
+                if self.app.interface.dropdown_height_spinbox.take_change() {
+                    actions.push(AppAction::Interface(pages::interface::InterfaceMessage::SetDropdownHeight(self.app.interface.dropdown_height_spinbox.value as u16)));
                 }
-                self.needs_rebuild = true;
-                return true;
-            }
-            let sb = &mut self.app.interface.window_corner_radius_spinbox;
-            let old = sb.value;
-            if sb.keyboard_input(event, &mut self.ui_context) {
-                let new_val = sb.value;
-                if new_val != old {
-                    self.handle_action(&AppAction::Interface(pages::interface::InterfaceMessage::SetWindowCornerRadius(new_val as u16)));
+                if self.app.interface.dropdown_corner_radius_spinbox.take_change() {
+                    actions.push(AppAction::Interface(pages::interface::InterfaceMessage::SetDropdownCornerRadius(self.app.interface.dropdown_corner_radius_spinbox.value as u16)));
                 }
-                self.needs_rebuild = true;
-                return true;
-            }
-            let sb = &mut self.app.interface.menubar_opacity_spinbox;
-            let old = sb.value;
-            if sb.keyboard_input(event, &mut self.ui_context) {
-                let new_val = sb.value;
-                if new_val != old {
-                    self.handle_action(&AppAction::Interface(pages::interface::InterfaceMessage::SetMenubarOpacity(new_val as f32 / 100.0)));
+                if self.app.interface.button_corner_radius_spinbox.take_change() {
+                    actions.push(AppAction::Interface(pages::interface::InterfaceMessage::SetButtonCornerRadius(self.app.interface.button_corner_radius_spinbox.value as u16)));
                 }
-                self.needs_rebuild = true;
-                return true;
-            }
-            let sb = &mut self.app.interface.graph_gap_width_spinbox;
-            let old = sb.value;
-            if sb.keyboard_input(event, &mut self.ui_context) {
-                let new_val = sb.value;
-                if new_val != old {
-                    self.handle_action(&AppAction::Interface(pages::interface::InterfaceMessage::SetGraphGapWidth(new_val as u16)));
+                if self.app.interface.sans_box.take_change() {
+                    actions.push(AppAction::Interface(pages::interface::InterfaceMessage::SetSans(self.app.interface.sans_box.text.clone())));
                 }
-                self.needs_rebuild = true;
-                return true;
-            }
-
-            let sb = &mut self.app.interface.button_padding_spinbox;
-            let old = sb.value;
-            if sb.keyboard_input(event, &mut self.ui_context) {
-                let new_val = sb.value;
-                if new_val != old {
-                    self.handle_action(&AppAction::Interface(pages::interface::InterfaceMessage::SetButtonPadding(new_val as u16)));
+                if self.app.interface.serif_box.take_change() {
+                    actions.push(AppAction::Interface(pages::interface::InterfaceMessage::SetSerif(self.app.interface.serif_box.text.clone())));
                 }
-                self.needs_rebuild = true;
-                return true;
-            }
-            let sb = &mut self.app.interface.section_padding_spinbox;
-            let old = sb.value;
-            if sb.keyboard_input(event, &mut self.ui_context) {
-                let new_val = sb.value;
-                if new_val != old {
-                    self.handle_action(&AppAction::Interface(pages::interface::InterfaceMessage::SetSectionPadding(new_val as u16)));
+                if self.app.interface.mono_box.take_change() {
+                    actions.push(AppAction::Interface(pages::interface::InterfaceMessage::SetMono(self.app.interface.mono_box.text.clone())));
                 }
-                self.needs_rebuild = true;
-                return true;
-            }
-            let (menu_changed, old_selected, new_selected) = {
-                let menu = &mut self.app.interface.label_alignment_menu;
-                let old = menu.selected;
-                let changed = menu.keyboard_input(event, &mut self.ui_context);
-                (changed, old, menu.selected)
-            };
-            if menu_changed {
-                if new_selected != old_selected {
-                    self.handle_action(&AppAction::Interface(pages::interface::InterfaceMessage::SetNestedSectionLabelAlignment(new_selected)));
+                if self.app.interface.borders_menu.take_change() {
+                    actions.push(AppAction::Interface(pages::interface::InterfaceMessage::SetBordersMenu(self.app.interface.borders_menu.selected)));
                 }
-                self.needs_rebuild = true;
-                return true;
-            }
-            let sb = &mut self.app.interface.label_offset_spinbox;
-            let old = sb.value;
-            if sb.keyboard_input(event, &mut self.ui_context) {
-                let new_val = sb.value;
-                if new_val != old {
-                    self.handle_action(&AppAction::Interface(pages::interface::InterfaceMessage::SetNestedSectionLabelOffset(new_val as i16)));
+                if self.app.interface.borders_box.take_change() {
+                    actions.push(AppAction::Interface(pages::interface::InterfaceMessage::SetBorders(self.app.interface.borders_box.text.clone())));
                 }
-                self.needs_rebuild = true;
-                return true;
-            }
-            let sb = &mut self.app.interface.label_margin_spinbox;
-            let old = sb.value;
-            if sb.keyboard_input(event, &mut self.ui_context) {
-                let new_val = sb.value;
-                if new_val != old {
-                    self.handle_action(&AppAction::Interface(pages::interface::InterfaceMessage::SetLabelMargin(new_val as u16)));
+                if self.app.interface.status_menu.take_change() {
+                    actions.push(AppAction::Interface(pages::interface::InterfaceMessage::SetStatusMenu(self.app.interface.status_menu.selected)));
                 }
-                self.needs_rebuild = true;
-                return true;
-            }
-            let sb = &mut self.app.interface.plate_padding_spinbox;
-            let old = sb.value;
-            if sb.keyboard_input(event, &mut self.ui_context) {
-                let new_val = sb.value;
-                if new_val != old {
-                    self.handle_action(&AppAction::Interface(pages::interface::InterfaceMessage::SetPlatePadding(new_val as u16)));
+                if self.app.interface.status_box.take_change() {
+                    actions.push(AppAction::Interface(pages::interface::InterfaceMessage::SetStatus(self.app.interface.status_box.text.clone())));
                 }
-                self.needs_rebuild = true;
-                return true;
-            }
-            let sb = &mut self.app.interface.page_margin_spinbox;
-            let old = sb.value;
-            if sb.keyboard_input(event, &mut self.ui_context) {
-                let new_val = sb.value;
-                if new_val != old {
-                    self.handle_action(&AppAction::Interface(pages::interface::InterfaceMessage::SetPageMargin(new_val as u16)));
+                if self.app.interface.fuzzel_menu.take_change() {
+                    actions.push(AppAction::Interface(pages::interface::InterfaceMessage::SetFuzzelMenu(self.app.interface.fuzzel_menu.selected)));
                 }
-                self.needs_rebuild = true;
-                return true;
-            }
-            let sb = &mut self.app.interface.grid_min_col_width_spinbox;
-            let old = sb.value;
-            if sb.keyboard_input(event, &mut self.ui_context) {
-                let new_val = sb.value;
-                if new_val != old {
-                    self.handle_action(&AppAction::Interface(pages::interface::InterfaceMessage::SetGridMinColWidth(new_val as u16)));
+                if self.app.interface.fuzzel_box.take_change() {
+                    actions.push(AppAction::Interface(pages::interface::InterfaceMessage::SetFuzzel(self.app.interface.fuzzel_box.text.clone())));
                 }
-                self.needs_rebuild = true;
-                return true;
-            }
-            let sb = &mut self.app.interface.spinbox_height_spinbox;
-            let old = sb.value;
-            if sb.keyboard_input(event, &mut self.ui_context) {
-                let new_val = sb.value;
-                if new_val != old {
-                    self.handle_action(&AppAction::Interface(pages::interface::InterfaceMessage::SetSpinboxHeight(new_val as u16)));
+                if self.app.interface.terminal_menu.take_change() {
+                    actions.push(AppAction::Interface(pages::interface::InterfaceMessage::SetTerminalMenu(self.app.interface.terminal_menu.selected)));
                 }
-                self.needs_rebuild = true;
-                return true;
-            }
-            let sb = &mut self.app.interface.spinbox_corner_radius_spinbox;
-            let old = sb.value;
-            if sb.keyboard_input(event, &mut self.ui_context) {
-                let new_val = sb.value;
-                if new_val != old {
-                    self.handle_action(&AppAction::Interface(pages::interface::InterfaceMessage::SetSpinboxCornerRadius(new_val as u16)));
+                if self.app.interface.terminal_box.take_change() {
+                    actions.push(AppAction::Interface(pages::interface::InterfaceMessage::SetTerminal(self.app.interface.terminal_box.text.clone())));
                 }
-                self.needs_rebuild = true;
-                return true;
-            }
-            let sb = &mut self.app.interface.toggle_height_spinbox;
-            let old = sb.value;
-            if sb.keyboard_input(event, &mut self.ui_context) {
-                let new_val = sb.value;
-                if new_val != old {
-                    self.handle_action(&AppAction::Interface(pages::interface::InterfaceMessage::SetToggleHeight(new_val as u16)));
+                if self.app.interface.color_selector_font_selector.take_change() {
+                    actions.push(AppAction::Interface(pages::interface::InterfaceMessage::SetColorSelectorFont(self.app.interface.color_selector_font_selector.font_family.clone())));
                 }
-                self.needs_rebuild = true;
-                return true;
-            }
-            let sb = &mut self.app.interface.toggle_corner_radius_spinbox;
-            let old = sb.value;
-            if sb.keyboard_input(event, &mut self.ui_context) {
-                let new_val = sb.value;
-                if new_val != old {
-                    self.handle_action(&AppAction::Interface(pages::interface::InterfaceMessage::SetToggleCornerRadius(new_val as u16)));
+                if self.app.interface.menubar_font_selector.take_change() {
+                    actions.push(AppAction::Interface(pages::interface::InterfaceMessage::SetMenubarFont(self.app.interface.menubar_font_selector.font_family.clone())));
                 }
-                self.needs_rebuild = true;
-                return true;
-            }
-            let sb = &mut self.app.interface.plate_opacity_spinbox;
-            let old = sb.value;
-            if sb.keyboard_input(event, &mut self.ui_context) {
-                let new_val = sb.value;
-                if new_val != old {
-                    self.handle_action(&AppAction::Interface(pages::interface::InterfaceMessage::SetPlateOpacity(new_val as f32 / 100.0)));
+                if self.app.interface.section_label_font_selector.take_change() {
+                    actions.push(AppAction::Interface(pages::interface::InterfaceMessage::SetSectionLabelFont(self.app.interface.section_label_font_selector.font_family.clone())));
                 }
-                self.needs_rebuild = true;
-                return true;
-            }
-            let sb = &mut self.app.interface.plate_corner_radius_spinbox;
-            let old = sb.value;
-            if sb.keyboard_input(event, &mut self.ui_context) {
-                let new_val = sb.value;
-                if new_val != old {
-                    self.handle_action(&AppAction::Interface(pages::interface::InterfaceMessage::SetPlateCornerRadius(new_val as u16)));
+                if self.app.interface.nested_section_label_font_selector.take_change() {
+                    actions.push(AppAction::Interface(pages::interface::InterfaceMessage::SetNestedSectionLabelFont(self.app.interface.nested_section_label_font_selector.font_family.clone())));
                 }
-                self.needs_rebuild = true;
-                return true;
-            }
-            let sb = &mut self.app.interface.page_opacity_spinbox;
-            let old = sb.value;
-            if sb.keyboard_input(event, &mut self.ui_context) {
-                let new_val = sb.value;
-                if new_val != old {
-                    self.handle_action(&AppAction::Interface(pages::interface::InterfaceMessage::SetPageOpacity(new_val as f32 / 100.0)));
+                if self.app.interface.borders_size_box.take_change() {
+                    actions.push(AppAction::Interface(pages::interface::InterfaceMessage::SetBordersSize(self.app.interface.borders_size_box.value)));
                 }
-                self.needs_rebuild = true;
-                return true;
-            }
-            let sb = &mut self.app.interface.layer_opacity_spinbox;
-            let old = sb.value;
-            if sb.keyboard_input(event, &mut self.ui_context) {
-                let new_val = sb.value;
-                if new_val != old {
-                    self.handle_action(&AppAction::Interface(pages::interface::InterfaceMessage::SetLayerOpacity(new_val as f32 / 100.0)));
+                if self.app.interface.status_size_box.take_change() {
+                    actions.push(AppAction::Interface(pages::interface::InterfaceMessage::SetStatusSize(self.app.interface.status_size_box.value)));
                 }
-                self.needs_rebuild = true;
-                return true;
-            }
 
-
-            let sb = &mut self.app.interface.color_selector_height_spinbox;
-            let old = sb.value;
-            if sb.keyboard_input(event, &mut self.ui_context) {
-                let new_val = sb.value;
-                if new_val != old {
-                    self.handle_action(&AppAction::Interface(pages::interface::InterfaceMessage::SetColorSelectorHeight(new_val as u16)));
+                let tf = &mut self.app.interface.windows;
+                for (i, sb) in tf.spinboxes.iter_mut().enumerate() {
+                    if sb.take_change() {
+                        actions.push(AppAction::Interface(pages::interface::InterfaceMessage::Windows(pages::interface::WindowsMessage::SetWidth(pages::interface::WidthParam::ALL[i], sb.value as u16))));
+                    }
                 }
-                self.needs_rebuild = true;
-                return true;
-            }
-            let sb = &mut self.app.interface.color_selector_corner_radius_spinbox;
-            let old = sb.value;
-            if sb.keyboard_input(event, &mut self.ui_context) {
-                let new_val = sb.value;
-                if new_val != old {
-                    self.handle_action(&AppAction::Interface(pages::interface::InterfaceMessage::SetColorSelectorCornerRadius(new_val as u16)));
+                if tf.cascade_offset_spinbox.take_change() {
+                    actions.push(AppAction::Interface(pages::interface::InterfaceMessage::Windows(pages::interface::WindowsMessage::SetCascadeOffset(tf.cascade_offset_spinbox.value as u16))));
                 }
-                self.needs_rebuild = true;
-                return true;
-            }
-            let sb = &mut self.app.interface.color_selector_preview_corner_radius_spinbox;
-            let old = sb.value;
-            if sb.keyboard_input(event, &mut self.ui_context) {
-                let new_val = sb.value;
-                if new_val != old {
-                    self.handle_action(&AppAction::Interface(pages::interface::InterfaceMessage::SetColorSelectorPreviewCornerRadius(new_val as u16)));
+                if tf.edge_gap_spinbox.take_change() {
+                    actions.push(AppAction::Interface(pages::interface::InterfaceMessage::Windows(pages::interface::WindowsMessage::SetEdgeGap(tf.edge_gap_spinbox.value as u16))));
                 }
-                self.needs_rebuild = true;
-                return true;
-            }
-            let sb = &mut self.app.interface.color_selector_preview_margin_spinbox;
-            let old = sb.value;
-            if sb.keyboard_input(event, &mut self.ui_context) {
-                let new_val = sb.value;
-                if new_val != old {
-                    self.handle_action(&AppAction::Interface(pages::interface::InterfaceMessage::SetColorSelectorPreviewMargin(new_val as u16)));
+                if tf.top_gap_spinbox.take_change() {
+                    actions.push(AppAction::Interface(pages::interface::InterfaceMessage::Windows(pages::interface::WindowsMessage::SetTopGap(tf.top_gap_spinbox.value as u16))));
                 }
-                self.needs_rebuild = true;
-                return true;
-            }
-            let sb = &mut self.app.interface.textbox_height_spinbox;
-            let old = sb.value;
-            if sb.keyboard_input(event, &mut self.ui_context) {
-                let new_val = sb.value;
-                if new_val != old {
-                    self.handle_action(&AppAction::Interface(pages::interface::InterfaceMessage::SetTextboxHeight(new_val as u16)));
+                if tf.grid_gap_spinbox.take_change() {
+                    actions.push(AppAction::Interface(pages::interface::InterfaceMessage::Windows(pages::interface::WindowsMessage::SetGridGap(tf.grid_gap_spinbox.value as u16))));
                 }
-                self.needs_rebuild = true;
-                return true;
-            }
-            let sb = &mut self.app.interface.textbox_corner_radius_spinbox;
-            let old = sb.value;
-            if sb.keyboard_input(event, &mut self.ui_context) {
-                let new_val = sb.value;
-                if new_val != old {
-                    self.handle_action(&AppAction::Interface(pages::interface::InterfaceMessage::SetTextboxCornerRadius(new_val as u16)));
+                if tf.transition_duration_spinbox.take_change() {
+                    actions.push(AppAction::Interface(pages::interface::InterfaceMessage::Windows(pages::interface::WindowsMessage::SetTransitionDuration(tf.transition_duration_spinbox.value as u16))));
                 }
-                self.needs_rebuild = true;
-                return true;
-            }
-            let sb = &mut self.app.interface.slider_height_spinbox;
-            let old = sb.value;
-            if sb.keyboard_input(event, &mut self.ui_context) {
-                let new_val = sb.value;
-                if new_val != old {
-                    self.handle_action(&AppAction::Interface(pages::interface::InterfaceMessage::SetSliderHeight(new_val as u16)));
+                if tf.status_height_spinbox.take_change() {
+                    actions.push(AppAction::Interface(pages::interface::InterfaceMessage::Windows(pages::interface::WindowsMessage::SetStatusHeight(tf.status_height_spinbox.value as u16))));
                 }
-                self.needs_rebuild = true;
-                return true;
-            }
-            let sb = &mut self.app.interface.font_selector_height_spinbox;
-            let old = sb.value;
-            if sb.keyboard_input(event, &mut self.ui_context) {
-                let new_val = sb.value;
-                if new_val != old {
-                    self.handle_action(&AppAction::Interface(pages::interface::InterfaceMessage::SetFontSelectorHeight(new_val as u16)));
+                for (idx, menu) in tf.tag_layout_menus.iter_mut().enumerate() {
+                    if menu.take_change() {
+                        actions.push(AppAction::Interface(pages::interface::InterfaceMessage::Windows(pages::interface::WindowsMessage::SetTagLayout(idx + 1, menu.selected))));
+                    }
                 }
-                self.needs_rebuild = true;
-                return true;
-            }
-            let sb = &mut self.app.interface.font_selector_corner_radius_spinbox;
-            let old = sb.value;
-            if sb.keyboard_input(event, &mut self.ui_context) {
-                let new_val = sb.value;
-                if new_val != old {
-                    self.handle_action(&AppAction::Interface(pages::interface::InterfaceMessage::SetFontSelectorCornerRadius(new_val as u16)));
+                if tf.side_panel_behavior_menu.take_change() {
+                    actions.push(AppAction::Interface(pages::interface::InterfaceMessage::Windows(pages::interface::WindowsMessage::SetSidePanelBehavior(tf.side_panel_behavior_menu.selected))));
                 }
-                self.needs_rebuild = true;
-                return true;
-            }
-            let sb = &mut self.app.interface.dropdown_height_spinbox;
-            let old = sb.value;
-            if sb.keyboard_input(event, &mut self.ui_context) {
-                let new_val = sb.value;
-                if new_val != old {
-                    self.handle_action(&AppAction::Interface(pages::interface::InterfaceMessage::SetDropdownHeight(new_val as u16)));
+                if tf.side_panel_position_menu.take_change() {
+                    actions.push(AppAction::Interface(pages::interface::InterfaceMessage::Windows(pages::interface::WindowsMessage::SetSidePanelPosition(tf.side_panel_position_menu.selected))));
                 }
-                self.needs_rebuild = true;
-                return true;
-            }
-            let sb = &mut self.app.interface.dropdown_corner_radius_spinbox;
-            let old = sb.value;
-            if sb.keyboard_input(event, &mut self.ui_context) {
-                let new_val = sb.value;
-                if new_val != old {
-                    self.handle_action(&AppAction::Interface(pages::interface::InterfaceMessage::SetDropdownCornerRadius(new_val as u16)));
+                if tf.side_panel_width_spinbox.take_change() {
+                    actions.push(AppAction::Interface(pages::interface::InterfaceMessage::Windows(pages::interface::WindowsMessage::SetSidePanelWidth(tf.side_panel_width_spinbox.value as u16))));
                 }
-                self.needs_rebuild = true;
-                return true;
-            }
-            let sb = &mut self.app.interface.button_corner_radius_spinbox;
-            let old = sb.value;
-            if sb.keyboard_input(event, &mut self.ui_context) {
-                let new_val = sb.value;
-                if new_val != old {
-                    self.handle_action(&AppAction::Interface(pages::interface::InterfaceMessage::SetButtonCornerRadius(new_val as u16)));
+                if tf.side_panel_border_gap_spinbox.take_change() {
+                    actions.push(AppAction::Interface(pages::interface::InterfaceMessage::Windows(pages::interface::WindowsMessage::SetSidePanelBorderGap(tf.side_panel_border_gap_spinbox.value as u16))));
                 }
-                self.needs_rebuild = true;
-                return true;
-            }
-
-
-
-            let mut actions = Vec::new();
-            let mut consumed = false;
-            
-            let tf = &mut self.app.interface;
-            let tb = &mut tf.sans_box;
-            if tb.keyboard_input(event, &mut self.ui_context) {
-                if tb.take_change() {
-                    actions.push(AppAction::Interface(pages::interface::InterfaceMessage::SetSans(tb.text.clone())));
+                if tf.side_panel_border_opacity_spinbox.take_change() {
+                    actions.push(AppAction::Interface(pages::interface::InterfaceMessage::Windows(pages::interface::WindowsMessage::SetSidePanelBorderOpacity(tf.side_panel_border_opacity_spinbox.value as u16))));
                 }
-                consumed = true;
             }
-
-            let tb = &mut self.app.interface.serif_box;
-            if tb.keyboard_input(event, &mut self.ui_context) {
-                if tb.take_change() {
-                    actions.push(AppAction::Interface(pages::interface::InterfaceMessage::SetSerif(tb.text.clone())));
+            Page::Input => {
+                if self.app.input.rate_spinbox.take_change() {
+                    actions.push(AppAction::Input(pages::input::InputMessage::ApplyRepeat));
                 }
-                consumed = true;
-            }
-
-            let tb = &mut self.app.interface.mono_box;
-            if tb.keyboard_input(event, &mut self.ui_context) {
-                if tb.take_change() {
-                    actions.push(AppAction::Interface(pages::interface::InterfaceMessage::SetMono(tb.text.clone())));
+                if self.app.input.delay_spinbox.take_change() {
+                    actions.push(AppAction::Input(pages::input::InputMessage::ApplyRepeat));
                 }
-                consumed = true;
-            }
-
-            let tb = &mut self.app.interface.borders_box;
-            if tb.keyboard_input(event, &mut self.ui_context) {
-                if tb.take_change() {
-                    actions.push(AppAction::Interface(pages::interface::InterfaceMessage::SetBorders(tb.text.clone())));
+                if self.app.input.scroll_friction_spinbox.take_change() {
+                    actions.push(AppAction::Input(pages::input::InputMessage::ApplyScrollFriction));
                 }
-                consumed = true;
-            }
-
-            let tb = &mut self.app.interface.status_box;
-            if tb.keyboard_input(event, &mut self.ui_context) {
-                if tb.take_change() {
-                    actions.push(AppAction::Interface(pages::interface::InterfaceMessage::SetStatus(tb.text.clone())));
+                if self.app.input.scroll_speed_spinbox.take_change() {
+                    actions.push(AppAction::Input(pages::input::InputMessage::ApplyScrollSpeed));
                 }
-                consumed = true;
-            }
-
-            let tb = &mut self.app.interface.fuzzel_box;
-            if tb.keyboard_input(event, &mut self.ui_context) {
-                if tb.take_change() {
-                    actions.push(AppAction::Interface(pages::interface::InterfaceMessage::SetFuzzel(tb.text.clone())));
+                if self.app.input.pointer_friction_spinbox.take_change() {
+                    actions.push(AppAction::Input(pages::input::InputMessage::ApplyPointerFriction));
                 }
-                consumed = true;
-            }
-
-            let tb = &mut self.app.interface.terminal_box;
-            if tb.keyboard_input(event, &mut self.ui_context) {
-                if tb.take_change() {
-                    actions.push(AppAction::Interface(pages::interface::InterfaceMessage::SetTerminal(tb.text.clone())));
+                if self.app.input.trackpad_friction_spinbox.take_change() {
+                    actions.push(AppAction::Input(pages::input::InputMessage::ApplyTrackpadFriction));
                 }
-                consumed = true;
-            }
-
-
-
-
-
-            let sb = &mut self.app.interface.borders_size_box;
-            if sb.keyboard_input(event, &mut self.ui_context) {
-                actions.push(AppAction::Interface(pages::interface::InterfaceMessage::SetBordersSize(sb.value)));
-                consumed = true;
-            }
-
-            let sb = &mut self.app.interface.status_size_box;
-            if sb.keyboard_input(event, &mut self.ui_context) {
-                actions.push(AppAction::Interface(pages::interface::InterfaceMessage::SetStatusSize(sb.value)));
-                consumed = true;
-            }
-
-            let sb = &mut self.app.interface.fuzzel_size_box;
-            if sb.keyboard_input(event, &mut self.ui_context) {
-                actions.push(AppAction::Interface(pages::interface::InterfaceMessage::SetFuzzelSize(sb.value)));
-                consumed = true;
-            }
-
-            let sb = &mut self.app.interface.terminal_size_box;
-            if sb.keyboard_input(event, &mut self.ui_context) {
-                actions.push(AppAction::Interface(pages::interface::InterfaceMessage::SetTerminalSize(sb.value)));
-                consumed = true;
-            }
-
-
-            
-            for a in &actions {
-                self.handle_action(a);
-            }
-            if consumed {
-                self.needs_rebuild = true;
-                return true;
-            }
-
-            let mut changed = false;
-            let mut actions = Vec::new();
-            {
-                let tf = &mut self.app.interface.windows;
-                for (i, sb) in tf.spinboxes.iter_mut().enumerate() {
-                    let old = sb.value;
-                    if sb.keyboard_input(event, &mut self.ui_context) {
-                        if sb.value != old {
-                            actions.push(AppAction::Interface(
-                                pages::interface::InterfaceMessage::Windows(
-                                    pages::interface::WindowsMessage::SetWidth(
-                                        pages::interface::WidthParam::ALL[i],
-                                        sb.value as u16,
-                                    )
-                                )
-                            ));
-                        }
-                        changed = true;
-                    }
+                if self.app.input.trackpoint_accel_speed_spinbox.take_change() {
+                    actions.push(AppAction::Input(pages::input::InputMessage::ApplyTrackpointAccelSpeed));
+                }
+                if self.app.input.cursor_size_spinbox.take_change() {
+                    actions.push(AppAction::Input(pages::input::InputMessage::ApplyCursorSize));
+                }
+                if self.app.input.tap_toggle.take_change() {
+                    actions.push(AppAction::Input(pages::input::InputMessage::ToggleTapToClick));
+                }
+                if self.app.input.scroll_toggle.take_change() {
+                    actions.push(AppAction::Input(pages::input::InputMessage::ToggleInertialScroll));
+                }
+                if self.app.input.natural_toggle.take_change() {
+                    actions.push(AppAction::Input(pages::input::InputMessage::ToggleNaturalScroll));
+                }
+                if self.app.input.pointer_toggle.take_change() {
+                    actions.push(AppAction::Input(pages::input::InputMessage::ToggleInertialPointer));
                 }
-                let sb = &mut tf.cascade_offset_spinbox;
-                let old = sb.value;
-                if sb.keyboard_input(event, &mut self.ui_context) {
-                    if sb.value != old {
-                        actions.push(AppAction::Interface(
-                            pages::interface::InterfaceMessage::Windows(
-                                pages::interface::WindowsMessage::SetCascadeOffset(sb.value as u16)
-                            )
-                        ));
-                    }
-                    changed = true;
+                if self.app.input.trackpad_toggle.take_change() {
+                    actions.push(AppAction::Input(pages::input::InputMessage::ToggleInertialTrackpad));
                 }
-                let sb = &mut tf.edge_gap_spinbox;
-                let old = sb.value;
-                if sb.keyboard_input(event, &mut self.ui_context) {
-                    if sb.value != old {
-                        actions.push(AppAction::Interface(
-                            pages::interface::InterfaceMessage::Windows(
-                                pages::interface::WindowsMessage::SetEdgeGap(sb.value as u16)
-                            )
-                        ));
-                    }
-                    changed = true;
+                if self.app.input.dwtp_toggle.take_change() {
+                    actions.push(AppAction::Input(pages::input::InputMessage::ToggleDwtp));
                 }
-                let sb = &mut tf.top_gap_spinbox;
-                let old = sb.value;
-                if sb.keyboard_input(event, &mut self.ui_context) {
-                    if sb.value != old {
-                        actions.push(AppAction::Interface(
-                            pages::interface::InterfaceMessage::Windows(
-                                pages::interface::WindowsMessage::SetTopGap(sb.value as u16)
-                            )
-                        ));
-                    }
-                    changed = true;
+                if self.app.input.trackpoint_accel_profile_menu.take_change() {
+                    actions.push(AppAction::Input(pages::input::InputMessage::ApplyTrackpointAccelProfile(self.app.input.trackpoint_accel_profile_menu.selected)));
                 }
-                let sb = &mut tf.grid_gap_spinbox;
-                let old = sb.value;
-                if sb.keyboard_input(event, &mut self.ui_context) {
-                    if sb.value != old {
-                        actions.push(AppAction::Interface(
-                            pages::interface::InterfaceMessage::Windows(
-                                pages::interface::WindowsMessage::SetGridGap(sb.value as u16)
-                            )
-                        ));
-                    }
-                    changed = true;
+                if self.app.input.cursor_theme_menu.take_change() {
+                    actions.push(AppAction::Input(pages::input::InputMessage::ApplyCursorTheme(self.app.input.cursor_theme_menu.selected)));
                 }
-                let sb = &mut tf.transition_duration_spinbox;
-                let old = sb.value;
-                if sb.keyboard_input(event, &mut self.ui_context) {
-                    if sb.value != old {
-                        actions.push(AppAction::Interface(
-                            pages::interface::InterfaceMessage::Windows(
-                                pages::interface::WindowsMessage::SetTransitionDuration(sb.value as u16)
-                            )
-                        ));
-                    }
-                    changed = true;
+                if self.app.input.zoom_in_box.take_change() {
+                    actions.push(AppAction::Input(pages::input::InputMessage::ApplyZoomIn));
                 }
-                let sb = &mut tf.status_height_spinbox;
-                let old = sb.value;
-                if sb.keyboard_input(event, &mut self.ui_context) {
-                    if sb.value != old {
-                        actions.push(AppAction::Interface(
-                            pages::interface::InterfaceMessage::Windows(
-                                pages::interface::WindowsMessage::SetStatusHeight(sb.value as u16)
-                            )
-                        ));
-                    }
-                    changed = true;
+                if self.app.input.zoom_out_box.take_change() {
+                    actions.push(AppAction::Input(pages::input::InputMessage::ApplyZoomOut));
                 }
-                let (menu_changed, old_selected, new_selected) = {
-                    let menu = &mut tf.side_panel_behavior_menu;
-                    let old = menu.selected;
-                    let changed = menu.keyboard_input(event, &mut self.ui_context);
-                    (changed, old, menu.selected)
-                };
-                if menu_changed {
-                    if new_selected != old_selected {
-                        actions.push(AppAction::Interface(
-                            pages::interface::InterfaceMessage::Windows(
-                                pages::interface::WindowsMessage::SetSidePanelBehavior(new_selected)
-                            )
-                        ));
-                    }
-                    changed = true;
+                if self.app.input.keybinds_control.take_change() {
+                    actions.push(AppAction::Input(pages::input::InputMessage::ReloadKeybinds));
                 }
-                let (menu_changed, old_selected, new_selected) = {
-                    let menu = &mut tf.side_panel_position_menu;
-                    let old = menu.selected;
-                    let changed = menu.keyboard_input(event, &mut self.ui_context);
-                    (changed, old, menu.selected)
-                };
-                if menu_changed {
-                    if new_selected != old_selected {
-                        actions.push(AppAction::Interface(
-                            pages::interface::InterfaceMessage::Windows(
-                                pages::interface::WindowsMessage::SetSidePanelPosition(new_selected)
-                            )
-                        ));
-                    }
-                    changed = true;
+            }
+            Page::Display => {
+                if self.app.display.screensaver_enable_toggle.take_change() {
+                    actions.push(AppAction::Display(pages::display::DisplayMessage::ToggleScreensaverEnable));
                 }
-                let sb = &mut tf.side_panel_width_spinbox;
-                let old = sb.value;
-                if sb.keyboard_input(event, &mut self.ui_context) {
-                    if sb.value != old {
-                        actions.push(AppAction::Interface(
-                            pages::interface::InterfaceMessage::Windows(
-                                pages::interface::WindowsMessage::SetSidePanelWidth(sb.value as u16)
-                            )
-                        ));
-                    }
-                    changed = true;
+                if self.app.display.screensaver_lock_screen_toggle.take_change() {
+                    actions.push(AppAction::Display(pages::display::DisplayMessage::ToggleScreensaverLockScreen));
                 }
-                let sb = &mut tf.side_panel_border_gap_spinbox;
-                let old = sb.value;
-                if sb.keyboard_input(event, &mut self.ui_context) {
-                    if sb.value != old {
-                        actions.push(AppAction::Interface(
-                            pages::interface::InterfaceMessage::Windows(
-                                pages::interface::WindowsMessage::SetSidePanelBorderGap(sb.value as u16)
-                            )
-                        ));
-                    }
-                    changed = true;
+                if self.app.display.screensaver_style_menu.take_change() {
+                    actions.push(AppAction::Display(pages::display::DisplayMessage::SetScreensaverStyle(self.app.display.screensaver_style_menu.selected)));
                 }
-                let sb = &mut tf.side_panel_border_opacity_spinbox;
-                let old = sb.value;
-                if sb.keyboard_input(event, &mut self.ui_context) {
-                    if sb.value != old {
-                        actions.push(AppAction::Interface(
-                            pages::interface::InterfaceMessage::Windows(
-                                pages::interface::WindowsMessage::SetSidePanelBorderOpacity(sb.value as u16)
-                            )
-                        ));
-                    }
-                    changed = true;
+                if self.app.display.brightness_spinbox.take_change() {
+                    actions.push(AppAction::Display(pages::display::DisplayMessage::BrightnessSet(self.app.display.brightness_spinbox.value as u32)));
                 }
-            }
-            for a in &actions {
-                self.handle_action(a);
-            }
-            if changed {
-                self.needs_rebuild = true;
-                return true;
-            }
-        }
-        if self.app.current_page == Page::Services {
-            let sb = &mut self.app.services.notifications_duration_spinbox;
-            let old = sb.value;
-            if sb.keyboard_input(event, &mut self.ui_context) {
-                let new_val = sb.value;
-                if new_val != old {
-                    self.handle_action(&AppAction::Services(pages::services::ServicesMessage::SetNotificationsDuration(new_val)));
+                if self.app.display.brightness_slider.take_change() {
+                    actions.push(AppAction::Display(pages::display::DisplayMessage::BrightnessSet((self.app.display.brightness_slider.value() * 100.0).round() as u32)));
                 }
-                self.needs_rebuild = true;
-                return true;
-            }
-            let sb = &mut self.app.services.status_padding_spinbox;
-            let old = sb.value;
-            if sb.keyboard_input(event, &mut self.ui_context) {
-                let new_val = sb.value;
-                if new_val != old {
-                    self.handle_action(&AppAction::Services(pages::services::ServicesMessage::StatusSetPadding(new_val as u16)));
+                if self.app.display.screensaver_timeout_spinbox.take_change() {
+                    actions.push(AppAction::Display(pages::display::DisplayMessage::SetScreensaverTimeout(self.app.display.screensaver_timeout_spinbox.value)));
                 }
-                self.needs_rebuild = true;
-                return true;
-            }
-        }
-        if self.app.current_page == Page::Input {
-            if self.app.input.rate_spinbox.keyboard_input(event, &mut self.ui_context) {
-                self.handle_action(&AppAction::Input(pages::input::InputMessage::ApplyRepeat));
-                self.needs_rebuild = true;
-                return true;
-            }
-            if self.app.input.delay_spinbox.keyboard_input(event, &mut self.ui_context) {
-                self.handle_action(&AppAction::Input(pages::input::InputMessage::ApplyRepeat));
-                self.needs_rebuild = true;
-                return true;
-            }
-            if self.app.input.scroll_friction_spinbox.keyboard_input(event, &mut self.ui_context) {
-                self.handle_action(&AppAction::Input(pages::input::InputMessage::ApplyScrollFriction));
-                self.needs_rebuild = true;
-                return true;
-            }
-            if self.app.input.scroll_speed_spinbox.keyboard_input(event, &mut self.ui_context) {
-                self.handle_action(&AppAction::Input(pages::input::InputMessage::ApplyScrollSpeed));
-                self.needs_rebuild = true;
-                return true;
-            }
-            if self.app.input.pointer_friction_spinbox.keyboard_input(event, &mut self.ui_context) {
-                self.handle_action(&AppAction::Input(pages::input::InputMessage::ApplyPointerFriction));
-                self.needs_rebuild = true;
-                return true;
-            }
-            if self.app.input.trackpad_friction_spinbox.keyboard_input(event, &mut self.ui_context) {
-                self.handle_action(&AppAction::Input(pages::input::InputMessage::ApplyTrackpadFriction));
-                self.needs_rebuild = true;
-                return true;
-            }
-            if self.app.input.trackpoint_accel_speed_spinbox.keyboard_input(event, &mut self.ui_context) {
-                self.handle_action(&AppAction::Input(pages::input::InputMessage::ApplyTrackpointAccelSpeed));
-                self.needs_rebuild = true;
-                return true;
-            }
-            if self.app.input.cursor_size_spinbox.keyboard_input(event, &mut self.ui_context) {
-                self.handle_action(&AppAction::Input(pages::input::InputMessage::ApplyCursorSize));
-                self.needs_rebuild = true;
-                return true;
-            }
-            if self.app.input.zoom_in_box.keyboard_input(event, &mut self.ui_context) {
-                self.handle_action(&AppAction::Input(pages::input::InputMessage::ApplyZoomIn));
-                self.needs_rebuild = true;
-                return true;
-            }
-            if self.app.input.zoom_out_box.keyboard_input(event, &mut self.ui_context) {
-                self.handle_action(&AppAction::Input(pages::input::InputMessage::ApplyZoomOut));
-                self.needs_rebuild = true;
-                return true;
             }
-            if self.app.input.keybinds_control.keyboard_input(event, &mut self.ui_context) {
-                if self.app.input.keybinds_control.take_change() {
-                    self.handle_action(&AppAction::Input(pages::input::InputMessage::ReloadKeybinds));
+            Page::Processes => {
+                if self.app.processes.cpu_gov_menu.take_change() {
+                    if self.app.processes.cpu_gov_menu.selected == 0 {
+                        actions.push(AppAction::Processes(pages::processes::ProcessesMessage::SetCpuPerformance));
+                    } else {
+                        actions.push(AppAction::Processes(pages::processes::ProcessesMessage::SetCpuPowersave));
+                    }
+                }
+                if self.app.processes.gpu_gov_menu.take_change() {
+                    if self.app.processes.gpu_gov_menu.selected == 0 {
+                        actions.push(AppAction::Processes(pages::processes::ProcessesMessage::SetGpuDefault));
+                    } else {
+                        actions.push(AppAction::Processes(pages::processes::ProcessesMessage::SetGpuPowersave));
+                    }
                 }
-                self.needs_rebuild = true;
-                return true;
             }
-        }
-        if self.app.current_page == Page::Accounts {
-            let mut consumed = false;
-            if self.app.accounts.editing_oauth_creds {
-                let tb = &mut self.app.accounts.oauth_client_id_box;
-                if tb.keyboard_input(event, &mut self.ui_context) { consumed = true; }
-                let tb = &mut self.app.accounts.oauth_client_secret_box;
-                if tb.keyboard_input(event, &mut self.ui_context) { consumed = true; }
-            } else if self.app.accounts.adding_new {
-                let tb = &mut self.app.accounts.email_box;
-                if tb.keyboard_input(event, &mut self.ui_context) {
-                    consumed = true;
-                    let email_val = tb.edit_buffer.trim().to_lowercase();
+            Page::Accounts => {
+                if self.app.accounts.adding_new && self.app.accounts.email_box.take_change() {
+                    let email_val = self.app.accounts.email_box.text.trim().to_lowercase();
                     if email_val.ends_with("@gmail.com") {
                         self.app.accounts.imap_box.text = "imap.gmail.com:993".to_string();
                         self.app.accounts.imap_box.edit_buffer = "imap.gmail.com:993".to_string();
@@ -3429,65 +567,73 @@ impl SystemInterface {
                         self.app.accounts.smtp_box.edit_buffer = "smtp.office365.com:587".to_string();
                     }
                 }
-                let tb = &mut self.app.accounts.password_box;
-                if tb.keyboard_input(event, &mut self.ui_context) { consumed = true; }
-                let tb = &mut self.app.accounts.imap_box;
-                if tb.keyboard_input(event, &mut self.ui_context) { consumed = true; }
-                let tb = &mut self.app.accounts.smtp_box;
-                if tb.keyboard_input(event, &mut self.ui_context) { consumed = true; }
-            }
-            
-            if consumed {
-                self.needs_rebuild = true;
-                return true;
             }
-        }
-        if self.app.current_page == Page::Audio {
-            let mut actions = Vec::new();
-            for (i, sb) in self.app.audio.sink_spinboxes.iter_mut().enumerate() {
-                let old = sb.value;
-                if sb.keyboard_input(event, &mut self.ui_context) {
-                    if sb.value != old {
+            Page::Audio => {
+                for (i, sb) in self.app.audio.sink_spinboxes.iter_mut().enumerate() {
+                    if sb.take_change() {
                         let id = self.app.audio.sinks[i].id;
                         actions.push(AppAction::Audio(pages::audio::AudioMessage::SinkVolume(id, sb.value as f32 / 100.0)));
                     }
                 }
-            }
-            for (i, sb) in self.app.audio.source_spinboxes.iter_mut().enumerate() {
-                let old = sb.value;
-                if sb.keyboard_input(event, &mut self.ui_context) {
-                    if sb.value != old {
+                for (i, sb) in self.app.audio.source_spinboxes.iter_mut().enumerate() {
+                    if sb.take_change() {
                         let id = self.app.audio.sources[i].id;
                         actions.push(AppAction::Audio(pages::audio::AudioMessage::SourceVolume(id, sb.value as f32 / 100.0)));
                     }
                 }
-            }
-            for (i, slider) in self.app.audio.sink_sliders.iter_mut().enumerate() {
-                let old = slider.value();
-                if slider.keyboard_input(event, &mut self.ui_context) {
-                    let new_val = slider.value();
-                    if new_val != old {
+                for (i, slider) in self.app.audio.sink_sliders.iter_mut().enumerate() {
+                    if slider.take_change() {
                         let id = self.app.audio.sinks[i].id;
-                        if i < self.app.audio.sink_spinboxes.len() {
-                            self.app.audio.sink_spinboxes[i].value = (new_val * 100.0).round() as i32;
-                        }
-                        actions.push(AppAction::Audio(pages::audio::AudioMessage::SinkVolume(id, new_val)));
+                        actions.push(AppAction::Audio(pages::audio::AudioMessage::SinkVolume(id, slider.value() as f32 / 100.0)));
                     }
                 }
-            }
-            for (i, slider) in self.app.audio.source_sliders.iter_mut().enumerate() {
-                let old = slider.value();
-                if slider.keyboard_input(event, &mut self.ui_context) {
-                    let new_val = slider.value();
-                    if new_val != old {
+                for (i, slider) in self.app.audio.source_sliders.iter_mut().enumerate() {
+                    if slider.take_change() {
                         let id = self.app.audio.sources[i].id;
-                        if i < self.app.audio.source_spinboxes.len() {
-                            self.app.audio.source_spinboxes[i].value = (new_val * 100.0).round() as i32;
-                        }
-                        actions.push(AppAction::Audio(pages::audio::AudioMessage::SourceVolume(id, new_val)));
+                        actions.push(AppAction::Audio(pages::audio::AudioMessage::SourceVolume(id, slider.value() as f32 / 100.0)));
                     }
                 }
             }
+            Page::Radios => {
+                let net = &mut self.app.network;
+                if net.wifi_toggle.take_change() {
+                    actions.push(AppAction::Radios(pages::network::NetworkMessage::ToggleWifi));
+                }
+                if net.bt_toggle.take_change() {
+                    actions.push(AppAction::Radios(pages::network::NetworkMessage::ToggleBluetooth));
+                }
+            }
+            _ => {}
+        }
+    }
+
+    pub(crate) fn handle_mouse_wheel_internal(&mut self, delta: &cce_ui::widget::MouseScrollDelta, px: f32, py: f32) -> bool {
+        if let Ok(mut file) = std::fs::OpenOptions::new().create(true).append(true).open("/tmp/cce-scroll-debug.log") {
+            use std::io::Write;
+            let _ = writeln!(file, "handle_mouse_wheel_internal: px={}, py={}, delta={:?}, sidebar_w={}", px, py, delta, self.sidebar_width);
+        }
+        let s = 1.0f32;
+        if px >= self.sidebar_width * s {
+            let lx = px / s;
+            let ly = py / s + self.scroll_y;
+            
+            if self.app.current_page == Page::Input {
+                let input = &self.app.input;
+                if input.is_over_trackpad(lx, ly, &self.ui_context) {
+                    return true;
+                }
+            }
+
+            let event = cce_ui::widget::Event::MouseWheel { delta: delta.clone(), x: lx, y: ly };
+            let mut handled = false;
+            if let Some(root) = self.get_page_root_widget() {
+                if self.ui_context.propagate_event(&event, root) {
+                    handled = true;
+                }
+            }
+
+            let mut actions = Vec::new();
+            self.propagate_widget_changes(&mut actions);
             for a in &actions {
                 self.handle_action(a);
             }
@@ -3495,142 +641,92 @@ impl SystemInterface {
                 self.needs_rebuild = true;
                 return true;
             }
-        }
-        if self.app.current_page == Page::Display {
-            let slider = &mut self.app.display.brightness_slider;
-            let old_slider = slider.value();
-            if slider.keyboard_input(event, &mut self.ui_context) {
-                let new_slider = slider.value();
-                if new_slider != old_slider {
-                    let pct = (new_slider * 100.0).round() as u32;
-                    self.app.display.brightness_spinbox.value = pct as i32;
-                    self.handle_action(&AppAction::Display(pages::display::DisplayMessage::BrightnessSet(pct)));
-                }
-                self.needs_rebuild = true;
-                return true;
-            }
-            let sb = &mut self.app.display.brightness_spinbox;
-            let old = sb.value;
-            if sb.keyboard_input(event, &mut self.ui_context) {
-                let new_val = sb.value;
-                if new_val != old {
-                    self.handle_action(&AppAction::Display(pages::display::DisplayMessage::BrightnessSet(new_val as u32)));
-                }
+            if handled {
                 self.needs_rebuild = true;
                 return true;
             }
-            let sb = &mut self.app.display.screensaver_timeout_spinbox;
-            let old = sb.value;
-            if sb.keyboard_input(event, &mut self.ui_context) {
-                let new_val = sb.value;
-                if new_val != old {
-                    self.handle_action(&AppAction::Display(pages::display::DisplayMessage::SetScreensaverTimeout(new_val)));
-                }
+
+            let scroll_speed = 24.0;
+            let dy = match delta {
+                cce_ui::widget::MouseScrollDelta::LineDelta(_, y) => -y * scroll_speed,
+                cce_ui::widget::MouseScrollDelta::PixelDelta(pos) => -pos.y as f32,
+            };
+            let old_scroll = self.scroll_y;
+            self.scroll_y = (self.scroll_y + dy).max(0.0).min(self.max_scroll_y);
+            if (self.scroll_y - old_scroll).abs() > 0.01 {
                 self.needs_rebuild = true;
                 return true;
             }
-            let (menu_changed, old_selected, new_selected) = {
-                let menu = &mut self.app.display.screensaver_style_menu;
-                let old = menu.selected;
-                let changed = menu.keyboard_input(event, &mut self.ui_context);
-                (changed, old, menu.selected)
-            };
-            if menu_changed {
-                if new_selected != old_selected {
-                    self.handle_action(&AppAction::Display(pages::display::DisplayMessage::SetScreensaverStyle(new_selected)));
-                }
+        } else {
+            let lx = px / s;
+            let ly = py / s;
+            if self.menubar.mouse_wheel(delta, lx, ly, &mut self.ui_context) {
                 self.needs_rebuild = true;
                 return true;
             }
         }
+        false
+    }
 
+    pub(crate) fn get_page_root_widget(&mut self) -> Option<*mut (dyn cce_ui::widget::Element + 'static)> {
+        let page_idx = Page::ALL.iter().position(|&p| p == self.app.current_page).unwrap_or(0);
+        let ptr = &mut self.plates[page_idx] as &mut dyn cce_ui::widget::Element as *mut dyn cce_ui::widget::Element;
+        let static_ptr = unsafe {
+            std::mem::transmute::<*mut dyn cce_ui::widget::Element, *mut (dyn cce_ui::widget::Element + 'static)>(ptr)
+        };
+        Some(static_ptr)
+    }
 
-        if self.app.current_page == Page::Services {
-            let srv = &mut self.app.services;
-            if srv.list_box.keyboard_input(event, &mut self.ui_context) {
-                self.needs_rebuild = true;
-                return true;
-            }
-            let tb = &mut srv.search_box;
-            if tb.keyboard_input(event, &mut self.ui_context) {
-                tb.take_change();
+    pub(crate) fn handle_key_input_internal(&mut self, event: &cce_ui::widget::KeyEvent) -> bool {
+        if cce_ui::widget::context_menu::is_visible() {
+            if event.state == cce_ui::widget::ElementState::Pressed
+                && event.logical_key == cce_ui::widget::Key::Named(cce_ui::widget::NamedKey::Escape)
+            {
+                cce_ui::widget::context_menu::hide();
                 self.needs_rebuild = true;
                 return true;
             }
         }
-        if self.app.current_page == Page::Packages {
-            let pkgs = &mut self.app.packages;
-            match pkgs.active_tab {
-                pages::packages::PackageTab::Installed => {
-                    if pkgs.installed_list_box.keyboard_input(event, &mut self.ui_context) {
+
+        if event.state == cce_ui::widget::ElementState::Pressed && !event.repeat {
+            let is_nav_key = match (&event.logical_key, event.ctrl) {
+                (cce_ui::widget::Key::Character(c), true) if c == "j" || c == "J" || c == "k" || c == "K" || c == "u" || c == "U" || c == "i" || c == "I" => true,
+                _ => false,
+            };
+            if is_nav_key {
+                if cce_ui::widget::focus::has_focus() {
+                    if cce_ui::widget::focus::navigate_focus(&event.logical_key, event.ctrl) {
                         self.needs_rebuild = true;
                         return true;
                     }
-                }
-                pages::packages::PackageTab::Updates => {
-                    if pkgs.updates_list_box.keyboard_input(event, &mut self.ui_context) {
-                        self.needs_rebuild = true;
-                        return true;
+                } else {
+                    if let Some(root_ptr) = self.get_page_root_widget() {
+                        unsafe {
+                            let root_ref = &mut *root_ptr;
+                            cce_ui::widget::focus::set_focused(root_ref);
+                            root_ref.focus();
+                            self.needs_rebuild = true;
+                            return true;
+                        }
                     }
                 }
             }
-            let tb = &mut pkgs.search_box;
-            if tb.keyboard_input(event, &mut self.ui_context) {
-                tb.take_change();
-                self.needs_rebuild = true;
-                return true;
-            }
         }
-        if self.app.current_page == Page::Hardware {
-            let hw = &mut self.app.hardware;
-            if hw.cpu_list_box.keyboard_input(event, &mut self.ui_context) {
-                self.needs_rebuild = true;
-                return true;
-            }
-            let (cpu_changed, old_cpu, new_cpu) = {
-                let menu = &mut hw.cpu_gov_menu;
-                let old = menu.selected;
-                let changed = menu.keyboard_input(event, &mut self.ui_context);
-                (changed, old, menu.selected)
-            };
-            if cpu_changed {
-                if new_cpu != old_cpu {
-                    if new_cpu == 0 {
-                        self.handle_action(&AppAction::Hardware(pages::hardware::HardwareMessage::SetCpuPerformance));
-                    } else {
-                        self.handle_action(&AppAction::Hardware(pages::hardware::HardwareMessage::SetCpuPowersave));
-                    }
-                }
-                self.needs_rebuild = true;
-                return true;
-            }
-            let (gpu_changed, old_gpu, new_gpu) = {
-                let menu = &mut hw.gpu_gov_menu;
-                let old = menu.selected;
-                let changed = menu.keyboard_input(event, &mut self.ui_context);
-                (changed, old, menu.selected)
-            };
-            if gpu_changed {
-                if new_gpu != old_gpu {
-                    if new_gpu == 0 {
-                        self.handle_action(&AppAction::Hardware(pages::hardware::HardwareMessage::SetGpuDefault));
-                    } else {
-                        self.handle_action(&AppAction::Hardware(pages::hardware::HardwareMessage::SetGpuPowersave));
-                    }
+
+        let event_wrapper = cce_ui::widget::Event::KeyInput(event.clone());
+        if let Some(root) = self.get_page_root_widget() {
+            if self.ui_context.propagate_event(&event_wrapper, root) {
+                let mut actions = Vec::new();
+                self.propagate_widget_changes(&mut actions);
+                for a in actions {
+                    self.handle_action(&a);
                 }
                 self.needs_rebuild = true;
                 return true;
             }
         }
-        if self.app.current_page == Page::Radios {
-            let net = &mut self.app.network;
-            if net.wifi_list_box.keyboard_input(event, &mut self.ui_context) {
-                self.needs_rebuild = true;
-                return true;
-            }
-        }
+
         false
     }
-
 }
 
diff --git a/src/main.rs b/src/main.rs
index 2aca62c..f3b9e2d 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -138,13 +138,13 @@ struct SystemInterface {
     rx_wm_events: std::sync::mpsc::Receiver<()>,
     rx_input: std::sync::mpsc::Receiver<pages::input::InputState>,
     rx_fingers: std::sync::mpsc::Receiver<Vec<Finger>>,
-    rx_hardware: std::sync::mpsc::Receiver<pages::hardware::HardwareState>,
+    rx_processes: std::sync::mpsc::Receiver<pages::processes::ProcessesState>,
     rx_system: std::sync::mpsc::Receiver<pages::system_info::SystemState>,
-    rx_status: std::sync::mpsc::Receiver<pages::services::StatusData>,
+    rx_status: std::sync::mpsc::Receiver<pages::processes::StatusData>,
     rx_storage: std::sync::mpsc::Receiver<pages::storage::StorageState>,
-    rx_notifications: std::sync::mpsc::Receiver<pages::services::NotificationsConfig>,
+    rx_notifications: std::sync::mpsc::Receiver<pages::processes::NotificationsConfig>,
     rx_typeface: std::sync::mpsc::Receiver<pages::interface::InterfaceState>,
-    rx_services: std::sync::mpsc::Receiver<Vec<pages::services::ServiceInfo>>,
+    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>>,
     tx_backup: std::sync::mpsc::Sender<pages::storage::StorageMessage>,
@@ -237,7 +237,7 @@ impl cce_ui::engine::Application for SystemInterface {
             rx_wm_events: watchers.rx_wm_events,
             rx_input: watchers.rx_input,
             rx_fingers: watchers.rx_fingers,
-            rx_hardware: watchers.rx_hardware,
+            rx_processes: watchers.rx_processes,
             rx_system: watchers.rx_system,
             rx_status: watchers.rx_status,
             rx_storage: watchers.rx_storage,
@@ -320,14 +320,15 @@ impl cce_ui::engine::Application for SystemInterface {
             *needs_rebuild = true;
             self.needs_rebuild = true;
         }
-        if self.needs_rebuild {
+        if self.needs_rebuild || self.ui_context.is_dirty() {
             *needs_rebuild = true;
+            self.needs_rebuild = true;
         }
     }
 
     fn view(&mut self, _quads: &mut Vec<(f32, f32, f32, f32, [f32; 4])>, size: cce_ui::engine::LogicalSize, scale: f64) {
         let (width, height) = (size.width, size.height);
-        if self.needs_rebuild || self.width != width as u32 || self.height != height as u32 || self.scale_factor != scale {
+        if self.needs_rebuild || self.ui_context.is_dirty() || self.width != width as u32 || self.height != height as u32 || self.scale_factor != scale {
             self.width = width as u32;
             self.height = height as u32;
             self.scale_factor = scale;
@@ -338,7 +339,7 @@ impl cce_ui::engine::Application for SystemInterface {
 
     fn view_rounded_quads(&mut self, quads: &mut Vec<(f32, f32, f32, f32, f32, [f32; 4], (bool, bool, bool, bool))>, size: cce_ui::engine::LogicalSize, scale: f64) {
         let (width, height) = (size.width, size.height);
-        if self.needs_rebuild || self.width != width as u32 || self.height != height as u32 || self.scale_factor != scale {
+        if self.needs_rebuild || self.ui_context.is_dirty() || self.width != width as u32 || self.height != height as u32 || self.scale_factor != scale {
             self.width = width as u32;
             self.height = height as u32;
             self.scale_factor = scale;
@@ -611,15 +612,15 @@ fn collect_popover_rects(w: &dyn cce_ui::widget::Element, popovers: &mut Vec<(f3
                 self.needs_rebuild = true;
             }
         }
-        while let Ok(s) = self.rx_hardware.try_recv() {
-            hardware::update(&mut self.app.hardware, hardware::HardwareMessage::Refreshed(s));
-            if self.app.current_page == Page::Hardware {
+        while let Ok(s) = self.rx_processes.try_recv() {
+            processes::update(&mut self.app.processes, processes::ProcessesMessage::Refreshed(s));
+            if self.app.current_page == Page::Processes {
                 self.needs_rebuild = true;
             }
         }
         while let Ok(s) = self.rx_status.try_recv() {
-            services::update(&mut self.app.services, services::ServicesMessage::StatusRefreshed(s));
-            if self.app.current_page == Page::Services {
+            processes::update(&mut self.app.processes, processes::ProcessesMessage::StatusRefreshed(s));
+            if self.app.current_page == Page::Processes {
                 self.needs_rebuild = true;
             }
         }
@@ -630,8 +631,8 @@ fn collect_popover_rects(w: &dyn cce_ui::widget::Element, popovers: &mut Vec<(f3
             }
         }
         while let Ok(s) = self.rx_notifications.try_recv() {
-            services::update(&mut self.app.services, services::ServicesMessage::NotificationsRefreshed(s));
-            if self.app.current_page == Page::Services {
+            processes::update(&mut self.app.processes, processes::ProcessesMessage::NotificationsRefreshed(s));
+            if self.app.current_page == Page::Processes {
                 self.needs_rebuild = true;
             }
         }
@@ -645,8 +646,8 @@ fn collect_popover_rects(w: &dyn cce_ui::widget::Element, popovers: &mut Vec<(f3
             }
         }
         while let Ok(s) = self.rx_services.try_recv() {
-            pages::services::update(&mut self.app.services, pages::services::ServicesMessage::Refreshed(s));
-            if self.app.current_page == Page::Services {
+            processes::update(&mut self.app.processes, processes::ProcessesMessage::ServicesRefreshed(s));
+            if self.app.current_page == Page::Processes {
                 self.needs_rebuild = true;
             }
         }
@@ -691,7 +692,7 @@ fn collect_popover_rects(w: &dyn cce_ui::widget::Element, popovers: &mut Vec<(f3
             AppAction::Radios(m) => network::update(&mut self.app.network, m.clone()),
             AppAction::Input(m) => input::update(&mut self.app.input, m.clone()),
             AppAction::SystemInfo(m) => system_info::update(&mut self.app.system_info, m.clone()),
-            AppAction::Hardware(m) => hardware::update(&mut self.app.hardware, m.clone()),
+            AppAction::Processes(m) => processes::update(&mut self.app.processes, m.clone()),
             AppAction::Storage(m) => match m {
                 pages::storage::StorageMessage::StartBackup => {
                     pages::storage::update(&mut self.app.storage, pages::storage::StorageMessage::StartBackup);
@@ -704,7 +705,7 @@ fn collect_popover_rects(w: &dyn cce_ui::widget::Element, popovers: &mut Vec<(f3
                 _ => pages::storage::update(&mut self.app.storage, m.clone()),
             },
 
-            AppAction::Services(m) => services::update(&mut self.app.services, m.clone()),
+
             AppAction::Interface(m) => {
                 interface::update(&mut self.app.interface, m.clone());
                 self.sans_serif_family = self.app.interface.sans_serif.clone();
diff --git a/src/pages/hardware.rs b/src/pages/hardware.rs
deleted file mode 100644
index 1413639..0000000
--- a/src/pages/hardware.rs
+++ /dev/null
@@ -1,637 +0,0 @@
-use crate::app::{AppAction, PageContent};
-use cce_ui::layout::{render_widget, PageLayoutBuilder, LayoutStrategy};
-use cce_ui::widget::{Label, ScrollingList, Dropdown, InfoBox};
-
-#[derive(Debug, Clone, Default)]
-pub struct BatteryInfo {
-    pub percentage: f32,
-    pub state: String,
-    pub energy: f64,
-    pub energy_full: f64,
-    pub energy_rate: f64,
-    pub time_to_empty: i64,
-    pub time_to_full: i64,
-    pub vendor: String,
-    pub model: String,
-}
-
-#[derive(Debug, Clone)]
-pub struct HardwareState {
-    pub cpu_model: String,
-    pub cpu_usage: f32,
-    pub cpu_cores: u32,
-    pub gpus: Vec<String>,
-    pub loaded: bool,
-    pub cpu_label: Label,
-    pub cpu_usage_label: Label,
-    pub cpu_temp_label: Label,
-    pub gpu_labels: Vec<Label>,
-    pub processes: Vec<(String, String, String)>, // (pid, cpu, comm)
-    pub cpu_list_box: ScrollingList,
-
-    // Power-related fields
-    pub battery: BatteryInfo,
-    pub on_ac: bool,
-    pub cpu_powersave: bool,
-    pub gpu_powersave: bool,
-    pub cpu_gov_menu: Dropdown,
-    pub gpu_gov_menu: Dropdown,
-}
-
-impl Default for HardwareState {
-    fn default() -> Self {
-        Self {
-            cpu_model: String::new(),
-            cpu_usage: 0.0,
-            cpu_cores: 0,
-            gpus: Vec::new(),
-            loaded: false,
-            cpu_label: Label::new("CPU Info"),
-            cpu_usage_label: Label::new("CPU Usage"),
-            cpu_temp_label: Label::new("CPU Temp"),
-            gpu_labels: Vec::new(),
-            processes: Vec::new(),
-            cpu_list_box: ScrollingList::new(24.0, 2.0),
-
-            battery: BatteryInfo::default(),
-            on_ac: true,
-            cpu_powersave: false,
-            gpu_powersave: false,
-            cpu_gov_menu: Dropdown::new(
-                vec!["Performance".to_string(), "Powersave".to_string()],
-                0,
-            ).with_label("CPU Governor"),
-            gpu_gov_menu: Dropdown::new(
-                vec!["Default (80W)".to_string(), "Eco Cap (5W)".to_string()],
-                0,
-            ).with_label("GPU Power Limit"),
-        }
-    }
-}
-
-#[derive(Debug, Clone)]
-pub enum HardwareMessage {
-    Refreshed(HardwareState),
-    SetCpuPerformance,
-    SetCpuPowersave,
-    SetGpuDefault,
-    SetGpuPowersave,
-    None,
-}
-
-// ── zbus proxies ────────────────────────────────────────────────────
-
-#[zbus::proxy(
-    interface = "org.freedesktop.UPower.Device",
-    default_service = "org.freedesktop.UPower",
-    default_path = "/org/freedesktop/UPower/devices/battery_BAT0"
-)]
-trait UpowerBattery {
-    #[zbus(property)]
-    fn percentage(&self) -> zbus::Result<f64>;
-    #[zbus(property)]
-    fn state(&self) -> zbus::Result<u32>;
-    #[zbus(property)]
-    fn energy(&self) -> zbus::Result<f64>;
-    #[zbus(property)]
-    fn energy_full(&self) -> zbus::Result<f64>;
-    #[zbus(property)]
-    fn energy_rate(&self) -> zbus::Result<f64>;
-    #[zbus(property)]
-    fn time_to_empty(&self) -> zbus::Result<i64>;
-    #[zbus(property)]
-    fn time_to_full(&self) -> zbus::Result<i64>;
-    #[zbus(property)]
-    fn vendor(&self) -> zbus::Result<String>;
-    #[zbus(property)]
-    fn model(&self) -> zbus::Result<String>;
-}
-
-#[zbus::proxy(
-    interface = "org.freedesktop.UPower",
-    default_service = "org.freedesktop.UPower",
-    default_path = "/org/freedesktop/UPower"
-)]
-trait UpowerDaemon {
-    #[zbus(property, name = "OnBattery")]
-    fn on_battery(&self) -> zbus::Result<bool>;
-}
-
-// ── Helpers ─────────────────────────────────────────────────────────
-
-fn format_duration(secs: i64) -> String {
-    let h = secs / 3600;
-    let m = (secs % 3600) / 60;
-    if h > 0 { format!("{}h {}m", h, m) } else { format!("{}m", m) }
-}
-
-fn spawn_cpu_power(powersave: bool) {
-    let script = if powersave { "cpu-powersave-on" } else { "cpu-powersave-off" };
-    let _ = tokio::process::Command::new("pkexec")
-        .arg(format!("/home/lsgalante/.local/share/cce-system-interface/helpers/{}", script))
-        .spawn();
-}
-
-fn spawn_gpu_power(powersave: bool) {
-    let script = if powersave { "gpu-powersave-on" } else { "gpu-powersave-off" };
-    let _ = tokio::process::Command::new("pkexec")
-        .arg(format!("/home/lsgalante/.local/share/cce-system-interface/helpers/{}", script))
-        .spawn();
-}
-
-fn current_cpu_governor() -> String {
-    std::fs::read_to_string("/sys/devices/system/cpu/cpu0/cpufreq/scaling_governor")
-        .unwrap_or_default().trim().to_string()
-}
-
-async fn current_gpu_power_cap() -> bool {
-    tokio::process::Command::new("nvidia-smi")
-        .args(["--query-gpu=power.limit", "--format=csv,noheader,nounits"])
-        .output().await.ok()
-        .and_then(|o| String::from_utf8_lossy(&o.stdout).trim().parse::<f32>().ok())
-        .map(|w| w <= 10.0).unwrap_or(false)
-}
-
-async fn fetch_upower() -> (BatteryInfo, bool) {
-    let conn = match zbus::Connection::system().await {
-        Ok(c) => c,
-        Err(_) => return (BatteryInfo::default(), true),
-    };
-
-    let battery = match UpowerBatteryProxy::new(&conn).await {
-        Ok(proxy) => BatteryInfo {
-            percentage: proxy.percentage().await.unwrap_or(0.0) as f32,
-            state: {
-                let s = proxy.state().await.unwrap_or(0);
-                match s { 1 => "charging", 2 => "discharging", 4 => "fully-charged", _ => "unknown" }.into()
-            },
-            energy: proxy.energy().await.unwrap_or(0.0),
-            energy_full: proxy.energy_full().await.unwrap_or(0.0),
-            energy_rate: proxy.energy_rate().await.unwrap_or(0.0),
-            time_to_empty: proxy.time_to_empty().await.unwrap_or(0),
-            time_to_full: proxy.time_to_full().await.unwrap_or(0),
-            vendor: proxy.vendor().await.unwrap_or_default(),
-            model: proxy.model().await.unwrap_or_default(),
-        },
-        Err(_) => BatteryInfo::default(),
-    };
-
-    let on_ac = match UpowerDaemonProxy::new(&conn).await {
-        Ok(proxy) => !proxy.on_battery().await.unwrap_or(false),
-        Err(_) => true,
-    };
-
-    (battery, on_ac)
-}
-
-fn read_cpu_temp() -> Option<f32> {
-    if let Ok(entries) = std::fs::read_dir("/sys/class/hwmon") {
-        for entry in entries.filter_map(|e| e.ok()) {
-            let path = entry.path();
-            if let Ok(name) = std::fs::read_to_string(path.join("name")) {
-                let name = name.trim();
-                if name == "thinkpad" {
-                    if let Ok(val) = std::fs::read_to_string(path.join("temp1_input")) {
-                        if let Ok(temp_milli) = val.trim().parse::<f32>() {
-                            return Some(temp_milli / 1000.0);
-                        }
-                    }
-                } else if name == "coretemp" {
-                    if let Ok(val) = std::fs::read_to_string(path.join("temp1_input")) {
-                        if let Ok(temp_milli) = val.trim().parse::<f32>() {
-                            return Some(temp_milli / 1000.0);
-                        }
-                    }
-                }
-            }
-        }
-    }
-    None
-}
-
-fn read_thinkpad_gpu_temp() -> Option<f32> {
-    if let Ok(entries) = std::fs::read_dir("/sys/class/hwmon") {
-        for entry in entries.filter_map(|e| e.ok()) {
-            let path = entry.path();
-            if let Ok(name) = std::fs::read_to_string(path.join("name")) {
-                if name.trim() == "thinkpad" {
-                    for i in 1..=8 {
-                        let label_path = path.join(format!("temp{}_label", i));
-                        if let Ok(lbl) = std::fs::read_to_string(&label_path) {
-                            if lbl.trim() == "GPU" {
-                                if let Ok(val) = std::fs::read_to_string(path.join(format!("temp{}_input", i))) {
-                                    if let Ok(temp_milli) = val.trim().parse::<f32>() {
-                                        return Some(temp_milli / 1000.0);
-                                    }
-                                }
-                            }
-                        }
-                    }
-                }
-            }
-        }
-    }
-    None
-}
-
-async fn read_nvidia_gpu_temp() -> Option<f32> {
-    let out = tokio::process::Command::new("nvidia-smi")
-        .args(["--query-gpu=temperature.gpu", "--format=csv,noheader,nounits"])
-        .output().await.ok()?;
-    let val_str = String::from_utf8_lossy(&out.stdout);
-    val_str.trim().parse::<f32>().ok()
-}
-
-pub async fn fetch_hardware_state() -> HardwareState {
-    static CPU_INFO: std::sync::OnceLock<(String, u32)> = std::sync::OnceLock::new();
-    let (cpu_model, cpu_cores) = CPU_INFO.get_or_init(|| {
-        let output = std::process::Command::new("lscpu")
-            .output().ok()
-            .map(|o| String::from_utf8_lossy(&o.stdout).to_string())
-            .unwrap_or_default();
-        let model = output.lines()
-            .find(|l| l.contains("Model name"))
-            .and_then(|l| l.split(':').nth(1))
-            .map(|s| s.trim().to_string())
-            .unwrap_or_default();
-        let cores = output.lines()
-            .find(|l| l.contains("CPU(s)"))
-            .and_then(|l| {
-                let rest = l.split(':').nth(1).unwrap_or("").trim();
-                rest.split_whitespace().next().and_then(|n| n.parse::<u32>().ok())
-            })
-            .unwrap_or(0);
-        (model, cores)
-    }).clone();
-
-    let cpu_usage = {
-        let read_stat = || -> Option<(u64, u64)> {
-            let stat = std::fs::read_to_string("/proc/stat").ok()?;
-            let first = stat.lines().next()?;
-            let vals: Vec<u64> = first.split_whitespace().skip(1).filter_map(|v| v.parse().ok()).collect();
-            if vals.len() < 3 { return None; }
-            let total: u64 = vals.iter().sum();
-            let idle = vals.get(3).copied().unwrap_or(0);
-            Some((idle, total))
-        };
-        let (idle1, total1) = read_stat().unwrap_or((0, 1));
-        tokio::time::sleep(std::time::Duration::from_millis(100)).await;
-        let (idle2, total2) = read_stat().unwrap_or((0, 1));
-        let d_idle = idle2.saturating_sub(idle1);
-        let d_total = total2.saturating_sub(total1);
-        if d_total > 0 {
-            (1.0 - d_idle as f64 / d_total as f64) * 100.0
-        } else { 0.0 }
-    } as f32;
-
-    static GPUS_INFO: std::sync::OnceLock<Vec<String>> = std::sync::OnceLock::new();
-    let gpus = GPUS_INFO.get_or_init(|| {
-        let mut list = Vec::new();
-        if let Some(o) = std::process::Command::new("lspci").output().ok() {
-            for line in String::from_utf8_lossy(&o.stdout).lines() {
-                if line.contains("VGA") || line.contains("3D") {
-                    if let Some(name) = line.split(':').nth(2) {
-                        let trimmed = name.trim().to_string();
-                        if !trimmed.is_empty() {
-                            list.push(trimmed);
-                        }
-                    }
-                }
-            }
-        }
-        list
-    }).clone();
-
-    let processes = {
-        let mut list = Vec::new();
-        if let Some(o) = tokio::process::Command::new("ps")
-            .args(["-eo", "pid,%cpu,comm", "--sort=-%cpu"])
-            .output().await.ok()
-        {
-            let text = String::from_utf8_lossy(&o.stdout);
-            for line in text.lines().skip(1) {
-                let parts: Vec<&str> = line.split_whitespace().collect();
-                if parts.len() >= 3 {
-                    let pid = parts[0].to_string();
-                    let cpu = parts[1].to_string();
-                    let comm = parts[2..].join(" ");
-                    list.push((pid, cpu, comm));
-                }
-            }
-        }
-        list
-    };
-
-    let cpu_temp = read_cpu_temp();
-    let tp_gpu_temp = read_thinkpad_gpu_temp();
-    let nv_gpu_temp = read_nvidia_gpu_temp().await;
-
-    let cpu_label_text = format!("CPU  {}  ({} cores)", cpu_model, cpu_cores);
-    let cpu_usage_text = format!("Usage  {:.0}%", cpu_usage);
-    let cpu_temp_text = cpu_temp.map(|t| format!("Temp  {:.0}°C", t)).unwrap_or_else(|| "Temp  N/A".to_string());
-
-    let gpu_labels = gpus.iter().map(|gpu_name| {
-        let temp = if gpu_name.to_lowercase().contains("nvidia") {
-            nv_gpu_temp.or(tp_gpu_temp)
-        } else {
-            tp_gpu_temp
-        };
-        let temp_str = temp.map(|t| format!("  —  {:.0}°C", t)).unwrap_or_default();
-        let text = format!("GPU  {}{}", gpu_name, temp_str);
-        Label::new(&text).with_font_size(12.0).with_color([212, 212, 212])
-    }).collect();
-
-    let (battery, on_ac) = fetch_upower().await;
-    let cpu_powersave = current_cpu_governor() == "powersave";
-    let gpu_powersave = current_gpu_power_cap().await;
-
-    HardwareState {
-        cpu_model,
-        cpu_usage,
-        cpu_cores,
-        gpus,
-        loaded: true,
-        cpu_label: Label::new(&cpu_label_text).with_font_size(12.0).with_color([212, 212, 212]),
-        cpu_usage_label: Label::new(&cpu_usage_text).with_font_size(12.0).with_color([212, 212, 212]),
-        cpu_temp_label: Label::new(&cpu_temp_text).with_font_size(12.0).with_color([212, 212, 212]),
-        gpu_labels,
-        processes,
-        cpu_list_box: ScrollingList::new(24.0, 2.0),
-        battery,
-        on_ac,
-        cpu_powersave,
-        gpu_powersave,
-        cpu_gov_menu: Dropdown::new(
-            vec!["Performance".to_string(), "Powersave".to_string()],
-            if cpu_powersave { 1 } else { 0 },
-        ).with_label("CPU Governor"),
-        gpu_gov_menu: Dropdown::new(
-            vec!["Default (80W)".to_string(), "Eco Cap (5W)".to_string()],
-            if gpu_powersave { 1 } else { 0 },
-        ).with_label("GPU Power Limit"),
-    }
-}
-
-const TEXT_FG: [f32; 4] = [0.83, 0.83, 0.83, 1.0];
-const TEXT_DIM: [f32; 4] = [0.53, 0.53, 0.60, 1.0];
-const ACCENT: [f32; 4] = [0.36, 0.56, 0.38, 1.0];
-const RED: [f32; 4] = [1.0, 0.33, 0.33, 1.0];
-const ORANGE: [f32; 4] = [1.0, 0.73, 0.20, 1.0];
-
-pub fn view(state: &mut HardwareState, cx: f32, cy: f32, cw: f32, ch: f32, root_focused: bool, layout: &mut dyn LayoutStrategy, ctx: &mut cce_ui::context::UiContext) -> PageContent {
-    let mut final_pc = PageContent::new();
-    let sec_w = 320.0f32;
-    let mut builder = PageLayoutBuilder::new(layout, cx, cy, cw, ch, sec_w).with_section_count(5);
-
-    // ── CPU Section ──
-    builder.add_section(&mut final_pc, "CPU", root_focused, |sec| {
-        let rx = sec.left;
-        if !state.loaded {
-            sec.text("Loading CPU model and utilization...", 12.0, 0.0, 12.0, TEXT_FG);
-            sec.spacing(10.0);
-        } else {
-            // CPU Info Label
-            sec.widget(&mut state.cpu_label, 12.0, sec.cw - 24.0, 26.0, ctx);
-            sec.spacing(12.0);
-
-            // CPU Usage Label
-            sec.widget(&mut state.cpu_usage_label, 12.0, sec.cw - 24.0, 26.0, ctx);
-            sec.spacing(12.0);
-
-            // CPU Temp Label
-            sec.widget(&mut state.cpu_temp_label, 12.0, sec.cw - 24.0, 26.0, ctx);
-            sec.spacing(12.0);
-
-            // Scrolling box configuration for process list
-            let list_box_x = rx + 12.0;
-            let list_box_y = sec.ay();
-            let list_box_w = sec.cw - 24.0;
-            let list_box_h = 220.0;
-            
-            // Render the standardized ScrollBox widget
-            render_widget(sec.pc, &mut state.cpu_list_box, list_box_x, list_box_y, list_box_w, list_box_h, ctx);
-
-            // Header for process list columns (drawn static on top of the ScrollBox background)
-            let header_h = 22.0;
-            sec.pc.rect([0.12, 0.12, 0.16, 0.5], list_box_x + 1.0, list_box_y + 1.0, list_box_w - 2.0, header_h);
-            sec.pc.rect([0.18, 0.18, 0.24, 1.0], list_box_x + 1.0, list_box_y + header_h, list_box_w - 2.0, 1.0); // Divider
-            
-            sec.pc.text("PID", list_box_x + 12.0, list_box_y + 5.0, 11.0, [0.53, 0.53, 0.60, 1.0]);
-            sec.pc.text("COMMAND", list_box_x + 80.0, list_box_y + 5.0, 11.0, [0.53, 0.53, 0.60, 1.0]);
-            sec.pc.text("CPU %", list_box_x + list_box_w - 60.0, list_box_y + 5.0, 11.0, [0.53, 0.53, 0.60, 1.0]);
-
-            let row_h = 24.0;
-            // Update ScrollingList bounds for the scrollable viewport (which starts below the header)
-            state.cpu_list_box.update_bounds(state.processes.len(), list_box_y + header_h, list_box_h - header_h - 6.0);
-
-            // Visible process rows rendering (virtualized/clipped)
-            for (idx, (pid, cpu, comm)) in state.processes.iter().enumerate() {
-                if let Some(draw_y) = state.cpu_list_box.get_item_draw_y(idx, 4.0) {
-                    // Standard row action button (transparent background, highlights on hover)
-                    sec.pc.button(
-                        "",
-                        list_box_x + 2.0,
-                        draw_y,
-                        list_box_w - 16.0,
-                        row_h,
-                        [0.0, 0.0, 0.0, 0.0],
-                        [1.0, 1.0, 1.0, 0.06],
-                        [0.0, 0.0, 0.0, 0.0],
-                        AppAction::Hardware(HardwareMessage::None),
-                    );
-                    
-                    sec.pc.text(pid, list_box_x + 12.0, draw_y + 6.0, 12.0, [0.80, 0.80, 0.85, 1.0]);
-                    sec.pc.text(comm, list_box_x + 80.0, draw_y + 6.0, 12.0, [0.80, 0.80, 0.85, 1.0]);
-                    sec.pc.text(&format!("{}%", cpu), list_box_x + list_box_w - 60.0, draw_y + 6.0, 12.0, [0.56, 0.83, 0.56, 1.0]);
-                }
-            }
-            
-            if state.processes.is_empty() {
-                sec.pc.text("No active processes", list_box_x + 12.0, list_box_y + header_h + 16.0, 12.0, TEXT_DIM);
-            }
-
-            sec.content_y += list_box_h;
-        }
-    });
-
-    // ── GPU Section ──
-    builder.add_section(&mut final_pc, "GPU", false, |sec_gpu| {
-        if !state.loaded {
-            sec_gpu.text("Loading GPU models...", 12.0, 0.0, 12.0, TEXT_FG);
-            sec_gpu.spacing(10.0);
-        } else {
-            for (i, gpu_lbl) in state.gpu_labels.iter_mut().enumerate() {
-                if i > 0 { sec_gpu.spacing(12.0); }
-                sec_gpu.widget(gpu_lbl, 12.0, sec_gpu.cw - 24.0, 26.0, ctx);
-            }
-        }
-    });
-
-    // ── Battery Section ──
-    builder.add_section(&mut final_pc, "Battery", false, |sec_bat| {
-        if !state.loaded {
-            sec_bat.text("Loading battery status...", 12.0, 0.0, 12.0, TEXT_DIM);
-            sec_bat.spacing(18.0);
-        } else {
-            let bat = &state.battery;
-            let bat_icon = match bat.state.as_str() {
-                "charging" => "+",
-                "fully-charged" => "=",
-                _ => "",
-            };
-
-            let pct_color = if bat.percentage < 20.0 { RED }
-                else if bat.percentage < 50.0 { ORANGE }
-                else { ACCENT };
-
-            let pct_str = format!("{} {:.0}%", bat_icon, bat.percentage);
-            sec_bat.text(&pct_str, 12.0, 0.0, 24.0, pct_color);
-            sec_bat.spacing(30.0);
-
-            let state_str = format!("{}  •  {:.1}W  •  {:.1}/{:.1} Wh",
-                bat.state, bat.energy_rate, bat.energy, bat.energy_full);
-            sec_bat.text(&state_str, 12.0, 0.0, 12.0, TEXT_DIM);
-            sec_bat.spacing(18.0);
-
-            let time_str = if bat.time_to_empty > 0 {
-                format!("Time remaining: {}", format_duration(bat.time_to_empty))
-            } else if bat.time_to_full > 0 {
-                format!("Time to full: {}", format_duration(bat.time_to_full))
-            } else { String::new() };
-            if !time_str.is_empty() {
-                sec_bat.text(&time_str, 12.0, 0.0, 12.0, TEXT_DIM);
-                sec_bat.spacing(18.0);
-            }
-
-            let detail_str = format!("{}  {}", bat.vendor, bat.model);
-            sec_bat.text(&detail_str, 12.0, 0.0, 11.0, TEXT_DIM);
-            sec_bat.spacing(20.0);
-
-            let ac_str = if state.on_ac { "On AC Power" } else { "On Battery" };
-            sec_bat.text(ac_str, 12.0, 0.0, 14.0, TEXT_FG);
-            sec_bat.spacing(20.0);
-        }
-    });
-
-    // ── CPU Governor section ──
-    builder.add_section(&mut final_pc, "CPU Governor", false, |sec_gov| {
-        let rx = sec_gov.left;
-        if !state.loaded {
-            sec_gov.text("Loading CPU governor...", 12.0, 0.0, 12.0, TEXT_DIM);
-            sec_gov.spacing(18.0);
-        } else {
-            sec_gov.widget(&mut state.cpu_gov_menu, 12.0, sec_gov.cw - 24.0, 26.0, ctx);
-            sec_gov.spacing(12.0);
-
-            let (info_title, info_lines) = if state.cpu_powersave {
-                (
-                    "CPU Governor: Powersave",
-                    vec![
-                        "• Active: powersave".to_string(),
-                        "• Governor set to powersave — lower power, slower burst".to_string(),
-                    ],
-                )
-            } else {
-                (
-                    "CPU Governor: Performance",
-                    vec![
-                        "• Active: performance".to_string(),
-                        "• Governor set to performance".to_string(),
-                    ],
-                )
-            };
-
-            let mut info_box = InfoBox::new(info_title, info_lines);
-            let info_h = 80.0;
-            let info_y = sec_gov.ay();
-            render_widget(sec_gov.pc, &mut info_box, rx + 12.0, info_y, sec_gov.cw - 24.0, info_h, ctx);
-            sec_gov.spacing(info_h + 12.0);
-        }
-    });
-
-    // ── GPU Power section ──
-    builder.add_section(&mut final_pc, "GPU Power", false, |sec_gpow| {
-        let rx = sec_gpow.left;
-        if !state.loaded {
-            sec_gpow.text("Loading GPU power status...", 12.0, 0.0, 12.0, TEXT_DIM);
-            sec_gpow.spacing(18.0);
-        } else {
-            sec_gpow.widget(&mut state.gpu_gov_menu, 12.0, sec_gpow.cw - 24.0, 26.0, ctx);
-            sec_gpow.spacing(12.0);
-
-            let (info_title, info_lines) = if state.gpu_powersave {
-                (
-                    "GPU Power Limit: Eco Cap",
-                    vec![
-                        "• Mode: 5W Cap".to_string(),
-                        "• NVIDIA power limit capped at 5W — minimal draw".to_string(),
-                    ],
-                )
-            } else {
-                (
-                    "GPU Power Limit: Default",
-                    vec![
-                        "• Mode: 80W Default".to_string(),
-                        "• NVIDIA running at default power limit".to_string(),
-                    ],
-                )
-            };
-
-            let mut info_box = InfoBox::new(info_title, info_lines);
-            let info_h = 80.0;
-            let info_y = sec_gpow.ay();
-            render_widget(sec_gpow.pc, &mut info_box, rx + 12.0, info_y, sec_gpow.cw - 24.0, info_h, ctx);
-            sec_gpow.spacing(info_h + 12.0);
-        }
-    });
-
-    final_pc
-}
-
-pub fn update(state: &mut HardwareState, msg: HardwareMessage) {
-    match msg {
-        HardwareMessage::Refreshed(new) => {
-            state.loaded = new.loaded;
-            state.cpu_model = new.cpu_model;
-            state.cpu_usage = new.cpu_usage;
-            state.cpu_cores = new.cpu_cores;
-            state.gpus = new.gpus;
-            state.cpu_label = new.cpu_label;
-            state.cpu_usage_label = new.cpu_usage_label;
-            state.cpu_temp_label = new.cpu_temp_label;
-            state.gpu_labels = new.gpu_labels;
-            state.processes = new.processes;
-            let old_scroll = state.cpu_list_box.scroll_y();
-            state.cpu_list_box = new.cpu_list_box;
-            state.cpu_list_box.set_scroll_y(old_scroll);
-
-            state.battery = new.battery;
-            state.on_ac = new.on_ac;
-            state.cpu_powersave = new.cpu_powersave;
-            state.gpu_powersave = new.gpu_powersave;
-            state.cpu_gov_menu.selected = new.cpu_gov_menu.selected;
-            state.gpu_gov_menu.selected = new.gpu_gov_menu.selected;
-        }
-        HardwareMessage::SetCpuPerformance => {
-            state.cpu_powersave = false;
-            state.cpu_gov_menu.selected = 0;
-            spawn_cpu_power(false);
-        }
-        HardwareMessage::SetCpuPowersave => {
-            state.cpu_powersave = true;
-            state.cpu_gov_menu.selected = 1;
-            spawn_cpu_power(true);
-        }
-        HardwareMessage::SetGpuDefault => {
-            state.gpu_powersave = false;
-            state.gpu_gov_menu.selected = 0;
-            spawn_gpu_power(false);
-        }
-        HardwareMessage::SetGpuPowersave => {
-            state.gpu_powersave = true;
-            state.gpu_gov_menu.selected = 1;
-            spawn_gpu_power(true);
-        }
-        HardwareMessage::None => {}
-    }
-}
diff --git a/src/pages/interface.rs b/src/pages/interface.rs
index c41e2f4..08f2be7 100644
--- a/src/pages/interface.rs
+++ b/src/pages/interface.rs
@@ -199,6 +199,8 @@ pub struct InterfaceState {
     pub paginator_tab_padding_y: u16,
     pub button_padding: u16,
     pub button_padding_spinbox: Spinbox,
+    pub button_strip_spacing: u16,
+    pub button_strip_spacing_spinbox: Spinbox,
     pub section_padding: u16,
     pub section_padding_spinbox: Spinbox,
     pub plate_padding: u16,
@@ -361,6 +363,8 @@ impl Default for InterfaceState {
             paginator_tab_padding_y: 14,
             button_padding: 14,
             button_padding_spinbox: Spinbox::new(14, 0, 100, 1).with_label("Button Padding").with_unit("px"),
+            button_strip_spacing: 8,
+            button_strip_spacing_spinbox: Spinbox::new(8, 0, 100, 1).with_label("Spacing").with_unit("px"),
             section_padding: 8,
             section_padding_spinbox: Spinbox::new(8, 0, 100, 1).with_label("Padding").with_unit("px"),
             plate_padding: 20,
@@ -512,6 +516,7 @@ pub enum InterfaceMessage {
     SetWindowOpacity(f32),
     SetWindowCornerRadius(u16),
     SetButtonPadding(u16),
+    SetButtonStripSpacing(u16),
     SetSectionPadding(u16),
     SetPlatePadding(u16),
     SetPlateOpacity(f32),
@@ -645,6 +650,7 @@ pub fn read_interface_config() -> InterfaceState {
     let paginator_tab_padding_x = parse_u16_from(&content, "paginator_tab_padding_x", 10);
     let paginator_tab_padding_y = parse_u16_from(&content, "paginator_tab_padding_y", 14);
     let button_padding = parse_u16_from(&content, "button_padding", paginator_tab_padding_y);
+    let button_strip_spacing = parse_u16_from(&content, "button_strip_spacing", 8);
     let section_padding = parse_u16_from(&content, "section_padding", 8);
     let plate_padding = parse_u16_from(&content, "plate_padding", 20);
     let plate_opacity = parse_f32_from(&content, "plate_opacity", 1.0);
@@ -745,6 +751,8 @@ pub fn read_interface_config() -> InterfaceState {
         paginator_tab_padding_y,
         button_padding,
         button_padding_spinbox: Spinbox::new(button_padding as i32, 0, 100, 1).with_label("Button Padding").with_unit("px"),
+        button_strip_spacing,
+        button_strip_spacing_spinbox: Spinbox::new(button_strip_spacing as i32, 0, 100, 1).with_label("Spacing").with_unit("px"),
         section_padding,
         section_padding_spinbox: Spinbox::new(section_padding as i32, 0, 100, 1).with_label("Padding").with_unit("px"),
         plate_padding,
@@ -1396,6 +1404,13 @@ pub fn propagate_links(state: &mut InterfaceState, key: &str, val_str: &str) {
                     apply_button_padding(val);
                 }
             }
+            "button_strip_spacing" => {
+                if let Ok(val) = val_str.parse::<u16>() {
+                    state.button_strip_spacing = val;
+                    state.button_strip_spacing_spinbox.value = val as i32;
+                    apply_button_strip_spacing(val);
+                }
+            }
             "section_padding" => {
                 if let Ok(val) = val_str.parse::<u16>() {
                     state.section_padding = val;
@@ -1847,6 +1862,12 @@ fn apply_button_padding(padding: u16) {
     cce_ui::layout::set_button_padding(padding as f32);
 }
 
+fn apply_button_strip_spacing(spacing: u16) {
+    write_config_value("button_strip_spacing", &spacing.to_string());
+    send_ipc_command(&format!("layout button_strip_spacing {}", spacing));
+    cce_ui::layout::set_button_strip_spacing(spacing as f32);
+}
+
 fn apply_plate_padding(padding: u16) {
     write_config_value("plate_padding", &padding.to_string());
     cce_ui::layout::set_plate_padding(padding as f32);
@@ -2607,6 +2628,9 @@ pub fn view(state: &mut InterfaceState, cx: f32, cy: f32, cw: f32, ch: f32, sec_
             state.button_padding_spinbox.value = state.button_padding as i32;
             subsec.widget_full(&mut state.button_padding_spinbox, 44.0, ctx);
             subsec.spacing(8.0);
+            state.button_strip_spacing_spinbox.value = state.button_strip_spacing as i32;
+            subsec.widget_full(&mut state.button_strip_spacing_spinbox, 44.0, ctx);
+            subsec.spacing(8.0);
         });
         sec.spacing(12.0);
 
@@ -3140,6 +3164,11 @@ pub fn update(state: &mut InterfaceState, msg: InterfaceMessage) {
             apply_button_padding(padding);
             propagate_links(state, "button_padding", &padding.to_string());
         }
+        InterfaceMessage::SetButtonStripSpacing(spacing) => {
+            state.button_strip_spacing = spacing;
+            apply_button_strip_spacing(spacing);
+            propagate_links(state, "button_strip_spacing", &spacing.to_string());
+        }
         InterfaceMessage::SetSectionPadding(padding) => {
             state.section_padding = padding;
             apply_section_padding(padding);
@@ -3371,6 +3400,7 @@ pub fn update(state: &mut InterfaceState, msg: InterfaceMessage) {
         InterfaceMessage::PickLowColor | InterfaceMessage::PickHighColor | InterfaceMessage::PickDisabledColor | InterfaceMessage::PickSeparatorColor | 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 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();
             let was_pp_hovered = state.plate_padding_spinbox.hovered();
             let was_pl_op_hovered = state.plate_opacity_spinbox.hovered();
@@ -3435,6 +3465,7 @@ pub fn update(state: &mut InterfaceState, msg: InterfaceMessage) {
             *state = new;
 
             state.button_padding_spinbox.set_hovered(was_bp_hovered);
+            state.button_strip_spacing_spinbox.set_hovered(was_bss_hovered);
             state.section_padding_spinbox.set_hovered(was_sp_hovered);
             state.plate_padding_spinbox.set_hovered(was_pp_hovered);
             state.plate_opacity_spinbox.set_hovered(was_pl_op_hovered);
@@ -4804,6 +4835,29 @@ mod tests {
         let _ = fs::remove_file(path_str);
     }
 
+    #[test]
+    fn test_read_write_button_strip_spacing() {
+        let dir = std::env::temp_dir();
+        let path = dir.join("test_button_strip_spacing_config.toml");
+        let path_str = path.to_str().unwrap();
+ 
+        let initial_content = "{\"layout\": {\"gap\": 18, \"border_color\": \"#374673\"}}";
+        fs::write(path_str, initial_content).unwrap();
+ 
+        let content = fs::read_to_string(path_str).unwrap();
+        let val = parse_u16_from(&content, "button_strip_spacing", 8);
+        assert_eq!(val, 8);
+ 
+        assert!(write_config_value_path(path_str, "button_strip_spacing", "12"));
+        let updated = fs::read_to_string(path_str).unwrap();
+        assert!(updated.contains("\"button_strip_spacing\": 12"));
+ 
+        let val2 = parse_u16_from(&updated, "button_strip_spacing", 8);
+        assert_eq!(val2, 12);
+ 
+        let _ = fs::remove_file(path_str);
+    }
+
     #[test]
     fn test_read_write_slider_height() {
         let dir = std::env::temp_dir();
diff --git a/src/pages/mod.rs b/src/pages/mod.rs
index ffecbab..c0ae57b 100644
--- a/src/pages/mod.rs
+++ b/src/pages/mod.rs
@@ -5,8 +5,7 @@ pub mod storage;
 pub mod system_info;
 pub mod keybindings;
 pub mod input;
-pub mod hardware;
-pub mod services;
+pub mod processes;
 pub mod interface;
 pub mod accounts;
 pub mod packages;
@@ -16,27 +15,25 @@ pub enum Page {
     Accounts,
     Audio,
     Radios,
-    Services,
     Storage,
     Display,
     System,
-    Hardware,
+    Processes,
     Input,
     Interface,
     Packages,
 }
 
 impl Page {
-    pub const ALL: [Page; 11] = [
+    pub const ALL: [Page; 10] = [
         Page::Accounts,
         Page::Audio,
         Page::Display,
-        Page::Hardware,
         Page::Input,
         Page::Interface,
         Page::Packages,
+        Page::Processes,
         Page::Radios,
-        Page::Services,
         Page::Storage,
         Page::System,
     ];
@@ -46,11 +43,10 @@ impl Page {
             Page::Accounts => "Accounts",
             Page::Audio => "Audio",
             Page::Radios => "Radios",
-            Page::Services => "Services",
             Page::Storage => "Storage",
             Page::Display => "Display",
             Page::System => "System",
-            Page::Hardware => "Hardware",
+            Page::Processes => "Processes",
             Page::Input => "Input",
             Page::Interface => "Interface",
             Page::Packages => "Packages",
diff --git a/src/pages/network.rs b/src/pages/network.rs
index 060c519..e4ac8d0 100644
--- a/src/pages/network.rs
+++ b/src/pages/network.rs
@@ -1,5 +1,5 @@
 use crate::app::{AppAction, PageContent, SectionContextExt};
-use cce_ui::layout::{render_widget, PageLayoutBuilder, LayoutStrategy};
+use cce_ui::layout::{render_widget, PageLayoutBuilder, LayoutStrategy, RenderTarget};
 use cce_ui::widget::{ScrollingList, Toggle, Element};
 
 #[derive(Debug, Clone)]
@@ -345,6 +345,7 @@ pub fn view(state: &mut NetworkState, cx: f32, cy: f32, cw: f32, ch: f32, root_f
                 let btn_w = list_box_w - 2.0 * margin;
                 let max_chars = ((btn_w / 6.5) as usize).saturating_sub(10).max(5);
 
+                sec.pc.push_clip_rect(list_box_x, list_box_y, list_box_w, list_box_h);
                 for (idx, net) in state.available.iter().enumerate() {
                     if let Some(draw_y) = state.wifi_list_box.get_item_draw_y(idx, 4.0) {
                         let prefix = if net.in_use { ">" } else { " " };
@@ -361,6 +362,7 @@ pub fn view(state: &mut NetworkState, cx: f32, cy: f32, cw: f32, ch: f32, root_f
                             AppAction::Radios(NetworkMessage::ConnectWifi(net.ssid.clone())));
                     }
                 }
+                sec.pc.pop_clip_rect();
                 sec.content_y += list_box_h + row_gap;
             }
         }
diff --git a/src/pages/packages.rs b/src/pages/packages.rs
index e6437ad..9971f77 100644
--- a/src/pages/packages.rs
+++ b/src/pages/packages.rs
@@ -1,5 +1,5 @@
 use crate::app::{AppAction, PageContent, SectionContextExt};
-use cce_ui::layout::{render_widget, PageLayoutBuilder, LayoutStrategy, SectionContext};
+use cce_ui::layout::{render_widget, PageLayoutBuilder, LayoutStrategy, SectionContext, RenderTarget};
 use cce_ui::widget::{Element, ScrollingList, TextBox, InteractiveListItem};
 
 #[derive(Debug, Clone)]
@@ -415,6 +415,7 @@ pub fn view(
                         }
                     }
 
+                    sec.pc.push_clip_rect(list_box_x, list_box_y, list_box_w, list_box_h);
                     for (idx, pkg) in filtered.iter().enumerate() {
                         if let Some(draw_y) = state.installed_list_box.get_item_draw_y(idx, 4.0) {
                             let item = &mut state.installed_items[idx];
@@ -424,6 +425,7 @@ pub fn view(
                             render_widget(sec.pc, item, list_box_x + 24.0, draw_y, list_box_w - 44.0, item_h, ctx);
                         }
                     }
+                    sec.pc.pop_clip_rect();
 
                     if filtered.is_empty() {
                         sec.pc.text("No packages match the query", list_box_x + 16.0, list_box_y + 16.0, 12.0, TEXT_DIM);
@@ -446,6 +448,7 @@ pub fn view(
                         }
                     }
 
+                    sec.pc.push_clip_rect(list_box_x, list_box_y, list_box_w, list_box_h);
                     for (idx, pkg) in filtered.iter().enumerate() {
                         if let Some(draw_y) = state.updates_list_box.get_item_draw_y(idx, 4.0) {
                             let item = &mut state.updates_items[idx];
@@ -455,6 +458,7 @@ pub fn view(
                             render_widget(sec.pc, item, list_box_x + 24.0, draw_y, list_box_w - 44.0, item_h, ctx);
                         }
                     }
+                    sec.pc.pop_clip_rect();
 
                     if filtered.is_empty() {
                         sec.pc.text("No updates match the query", list_box_x + 16.0, list_box_y + 16.0, 12.0, TEXT_DIM);
diff --git a/src/pages/processes.rs b/src/pages/processes.rs
new file mode 100644
index 0000000..16d94c9
--- /dev/null
+++ b/src/pages/processes.rs
@@ -0,0 +1,1524 @@
+use crate::app::{AppAction, PageContent, SectionContextExt};
+use cce_ui::layout::{render_widget, PageLayoutBuilder, LayoutStrategy, RenderTarget};
+use cce_ui::widget::{Label, ScrollingList, Dropdown, InfoBox, TextBox, StatusDot, DotStatus, InteractiveListItem, Toggle, Spinbox, Element};
+use crate::pages::interface::parse_u16_from;
+use std::io::Write;
+use std::fs;
+
+#[derive(Debug, Clone, Default)]
+pub struct BatteryInfo {
+    pub percentage: f32,
+    pub state: String,
+    pub energy: f64,
+    pub energy_full: f64,
+    pub energy_rate: f64,
+    pub time_to_empty: i64,
+    pub time_to_full: i64,
+    pub vendor: String,
+    pub model: String,
+}
+
+#[derive(Debug, Clone)]
+pub struct NotificationsConfig {
+    pub enable: bool,
+    pub bell: bool,
+    pub duration: i32,
+}
+
+#[derive(Debug, Clone)]
+pub struct StatusData {
+    pub font_size: u16,
+    pub padding: u16,
+    pub separators: bool,
+    pub underline: bool,
+    pub running: bool,
+}
+
+#[derive(Debug, Clone)]
+pub struct ServiceInfo {
+    pub name: String,
+    pub description: String,
+    pub active_state: String,
+    pub sub_state: String,
+    pub is_system: bool,
+}
+
+#[derive(Debug, Clone, Copy, PartialEq, Eq)]
+pub enum ServiceTab {
+    System,
+    User,
+}
+
+impl Default for ServiceTab {
+    fn default() -> Self {
+        ServiceTab::System
+    }
+}
+
+#[derive(Debug, Clone)]
+pub struct ProcessesState {
+    pub cpu_model: String,
+    pub cpu_usage: f32,
+    pub cpu_cores: u32,
+    pub gpus: Vec<String>,
+    pub loaded: bool,
+    pub cpu_label: Label,
+    pub cpu_usage_label: Label,
+    pub cpu_temp_label: Label,
+    pub gpu_labels: Vec<Label>,
+    pub processes: Vec<(String, String, String)>, // (pid, cpu, comm)
+    pub cpu_list_box: ScrollingList,
+
+    // Power-related fields
+    pub battery: BatteryInfo,
+    pub on_ac: bool,
+    pub cpu_powersave: bool,
+    pub gpu_powersave: bool,
+    pub cpu_gov_menu: Dropdown,
+    pub gpu_gov_menu: Dropdown,
+
+    // Services-related fields
+    pub services_loaded: bool,
+    pub services: Vec<ServiceInfo>,
+    pub services_active_tab: ServiceTab,
+    pub services_search_box: TextBox,
+    pub services_list_box: ScrollingList,
+    pub service_items: Vec<InteractiveListItem>,
+    pub notifications_loaded: bool,
+    pub notifications_enable: bool,
+    pub notifications_enable_toggle: Toggle,
+    pub notifications_bell: bool,
+    pub notifications_bell_toggle: Toggle,
+    pub notifications_duration: i32,
+    pub notifications_duration_spinbox: Spinbox,
+
+    // Status Interface fields
+    pub status_loaded: bool,
+    pub status_font_size: u16,
+    pub status_padding: u16,
+    pub status_separators: bool,
+    pub status_underline: bool,
+    pub status_running: bool,
+    pub status_label: Label,
+    pub status_separators_toggle: Toggle,
+    pub status_underline_toggle: Toggle,
+    pub status_padding_spinbox: Spinbox,
+}
+
+impl Default for ProcessesState {
+    fn default() -> Self {
+        Self {
+            cpu_model: String::new(),
+            cpu_usage: 0.0,
+            cpu_cores: 0,
+            gpus: Vec::new(),
+            loaded: false,
+            cpu_label: Label::new("CPU Info"),
+            cpu_usage_label: Label::new("CPU Usage"),
+            cpu_temp_label: Label::new("CPU Temp"),
+            gpu_labels: Vec::new(),
+            processes: Vec::new(),
+            cpu_list_box: ScrollingList::new(24.0, 2.0),
+
+            battery: BatteryInfo::default(),
+            on_ac: true,
+            cpu_powersave: false,
+            gpu_powersave: false,
+            cpu_gov_menu: Dropdown::new(
+                vec!["Performance".to_string(), "Powersave".to_string()],
+                0,
+            ).with_label("CPU Governor"),
+            gpu_gov_menu: Dropdown::new(
+                vec!["Default (80W)".to_string(), "Eco Cap (5W)".to_string()],
+                0,
+            ).with_label("GPU Power Limit"),
+
+            services_loaded: false,
+            services: Vec::new(),
+            services_active_tab: ServiceTab::System,
+            services_search_box: TextBox::new(String::new()).with_label("Filter Services"),
+            services_list_box: ScrollingList::new(36.0, 6.0),
+            service_items: Vec::new(),
+            notifications_loaded: false,
+            notifications_enable: true,
+            notifications_enable_toggle: Toggle::new().with_label("Enable Notifications"),
+            notifications_bell: false,
+            notifications_bell_toggle: Toggle::new().with_label("Play Bell Sound"),
+            notifications_duration: 5,
+            notifications_duration_spinbox: Spinbox::new(5, 1, 60, 1)
+                .with_label("Notification Duration")
+                .with_unit("s"),
+
+            status_loaded: false,
+            status_font_size: 11,
+            status_padding: 8,
+            status_separators: true,
+            status_underline: true,
+            status_running: false,
+            status_label: Label::new("Status Interface: Stopped").with_font_size(14.0).with_color([170, 51, 51]),
+            status_separators_toggle: Toggle::new().with_label("Show Separators"),
+            status_underline_toggle: Toggle::new().with_label("Show Underline"),
+            status_padding_spinbox: Spinbox::new(8, 0, 32, 1).with_label("Side Padding").with_unit("px"),
+        }
+    }
+}
+
+#[derive(Debug, Clone)]
+pub enum ProcessesMessage {
+    Refreshed(ProcessesState),
+    SetCpuPerformance,
+    SetCpuPowersave,
+    SetGpuDefault,
+    SetGpuPowersave,
+    None,
+
+    // Services-related variants
+    ServicesRefreshed(Vec<ServiceInfo>),
+    ServicesSetTab(ServiceTab),
+    ServicesStart(String, bool),
+    ServicesStop(String, bool),
+    ServicesRestart(String, bool),
+    ToggleNotificationsEnable,
+    ToggleNotificationsBell,
+    SetNotificationsDuration(i32),
+    SendTestNotification,
+    NotificationsRefreshed(NotificationsConfig),
+
+    // Status Interface variants
+    StatusRefreshed(StatusData),
+    StatusToggleSeparators,
+    StatusToggleUnderline,
+    StatusReload,
+    StatusSetPadding(u16),
+}
+
+// ── zbus proxies ────────────────────────────────────────────────────
+
+#[zbus::proxy(
+    interface = "org.freedesktop.UPower.Device",
+    default_service = "org.freedesktop.UPower",
+    default_path = "/org/freedesktop/UPower/devices/battery_BAT0"
+)]
+trait UpowerBattery {
+    #[zbus(property)]
+    fn percentage(&self) -> zbus::Result<f64>;
+    #[zbus(property)]
+    fn state(&self) -> zbus::Result<u32>;
+    #[zbus(property)]
+    fn energy(&self) -> zbus::Result<f64>;
+    #[zbus(property)]
+    fn energy_full(&self) -> zbus::Result<f64>;
+    #[zbus(property)]
+    fn energy_rate(&self) -> zbus::Result<f64>;
+    #[zbus(property)]
+    fn time_to_empty(&self) -> zbus::Result<i64>;
+    #[zbus(property)]
+    fn time_to_full(&self) -> zbus::Result<i64>;
+    #[zbus(property)]
+    fn vendor(&self) -> zbus::Result<String>;
+    #[zbus(property)]
+    fn model(&self) -> zbus::Result<String>;
+}
+
+#[zbus::proxy(
+    interface = "org.freedesktop.UPower",
+    default_service = "org.freedesktop.UPower",
+    default_path = "/org/freedesktop/UPower"
+)]
+trait UpowerDaemon {
+    #[zbus(property, name = "OnBattery")]
+    fn on_battery(&self) -> zbus::Result<bool>;
+}
+
+// ── Helpers ─────────────────────────────────────────────────────────
+
+fn format_duration(secs: i64) -> String {
+    let h = secs / 3600;
+    let m = (secs % 3600) / 60;
+    if h > 0 { format!("{}h {}m", h, m) } else { format!("{}m", m) }
+}
+
+fn spawn_cpu_power(powersave: bool) {
+    let script = if powersave { "cpu-powersave-on" } else { "cpu-powersave-off" };
+    let _ = tokio::process::Command::new("pkexec")
+        .arg(format!("/home/lsgalante/.local/share/cce-system-interface/helpers/{}", script))
+        .spawn();
+}
+
+fn spawn_gpu_power(powersave: bool) {
+    let script = if powersave { "gpu-powersave-on" } else { "gpu-powersave-off" };
+    let _ = tokio::process::Command::new("pkexec")
+        .arg(format!("/home/lsgalante/.local/share/cce-system-interface/helpers/{}", script))
+        .spawn();
+}
+
+fn current_cpu_governor() -> String {
+    std::fs::read_to_string("/sys/devices/system/cpu/cpu0/cpufreq/scaling_governor")
+        .unwrap_or_default().trim().to_string()
+}
+
+async fn current_gpu_power_cap() -> bool {
+    tokio::process::Command::new("nvidia-smi")
+        .args(["--query-gpu=power.limit", "--format=csv,noheader,nounits"])
+        .output().await.ok()
+        .and_then(|o| String::from_utf8_lossy(&o.stdout).trim().parse::<f32>().ok())
+        .map(|w| w <= 10.0).unwrap_or(false)
+}
+
+async fn fetch_upower() -> (BatteryInfo, bool) {
+    let conn = match zbus::Connection::system().await {
+        Ok(c) => c,
+        Err(_) => return (BatteryInfo::default(), true),
+    };
+
+    let battery = match UpowerBatteryProxy::new(&conn).await {
+        Ok(proxy) => BatteryInfo {
+            percentage: proxy.percentage().await.unwrap_or(0.0) as f32,
+            state: {
+                let s = proxy.state().await.unwrap_or(0);
+                match s { 1 => "charging", 2 => "discharging", 4 => "fully-charged", _ => "unknown" }.into()
+            },
+            energy: proxy.energy().await.unwrap_or(0.0),
+            energy_full: proxy.energy_full().await.unwrap_or(0.0),
+            energy_rate: proxy.energy_rate().await.unwrap_or(0.0),
+            time_to_empty: proxy.time_to_empty().await.unwrap_or(0),
+            time_to_full: proxy.time_to_full().await.unwrap_or(0),
+            vendor: proxy.vendor().await.unwrap_or_default(),
+            model: proxy.model().await.unwrap_or_default(),
+        },
+        Err(_) => BatteryInfo::default(),
+    };
+
+    let on_ac = match UpowerDaemonProxy::new(&conn).await {
+        Ok(proxy) => !proxy.on_battery().await.unwrap_or(false),
+        Err(_) => true,
+    };
+
+    (battery, on_ac)
+}
+
+fn read_cpu_temp() -> Option<f32> {
+    if let Ok(entries) = std::fs::read_dir("/sys/class/hwmon") {
+        for entry in entries.filter_map(|e| e.ok()) {
+            let path = entry.path();
+            if let Ok(name) = std::fs::read_to_string(path.join("name")) {
+                let name = name.trim();
+                if name == "thinkpad" {
+                    if let Ok(val) = std::fs::read_to_string(path.join("temp1_input")) {
+                        if let Ok(temp_milli) = val.trim().parse::<f32>() {
+                            return Some(temp_milli / 1000.0);
+                        }
+                    }
+                } else if name == "coretemp" {
+                    if let Ok(val) = std::fs::read_to_string(path.join("temp1_input")) {
+                        if let Ok(temp_milli) = val.trim().parse::<f32>() {
+                            return Some(temp_milli / 1000.0);
+                        }
+                    }
+                }
+            }
+        }
+    }
+    None
+}
+
+fn read_thinkpad_gpu_temp() -> Option<f32> {
+    if let Ok(entries) = std::fs::read_dir("/sys/class/hwmon") {
+        for entry in entries.filter_map(|e| e.ok()) {
+            let path = entry.path();
+            if let Ok(name) = std::fs::read_to_string(path.join("name")) {
+                if name.trim() == "thinkpad" {
+                    for i in 1..=8 {
+                        let label_path = path.join(format!("temp{}_label", i));
+                        if let Ok(lbl) = std::fs::read_to_string(&label_path) {
+                            if lbl.trim() == "GPU" {
+                                if let Ok(val) = std::fs::read_to_string(path.join(format!("temp{}_input", i))) {
+                                    if let Ok(temp_milli) = val.trim().parse::<f32>() {
+                                        return Some(temp_milli / 1000.0);
+                                    }
+                                }
+                            }
+                        }
+                    }
+                }
+            }
+        }
+    }
+    None
+}
+
+async fn read_nvidia_gpu_temp() -> Option<f32> {
+    let out = tokio::process::Command::new("nvidia-smi")
+        .args(["--query-gpu=temperature.gpu", "--format=csv,noheader,nounits"])
+        .output().await.ok()?;
+    let val_str = String::from_utf8_lossy(&out.stdout);
+    val_str.trim().parse::<f32>().ok()
+}
+
+pub async fn fetch_processes_state() -> ProcessesState {
+    static CPU_INFO: std::sync::OnceLock<(String, u32)> = std::sync::OnceLock::new();
+    let (cpu_model, cpu_cores) = CPU_INFO.get_or_init(|| {
+        let output = std::process::Command::new("lscpu")
+            .output().ok()
+            .map(|o| String::from_utf8_lossy(&o.stdout).to_string())
+            .unwrap_or_default();
+        let model = output.lines()
+            .find(|l| l.contains("Model name"))
+            .and_then(|l| l.split(':').nth(1))
+            .map(|s| s.trim().to_string())
+            .unwrap_or_default();
+        let cores = output.lines()
+            .find(|l| l.contains("CPU(s)"))
+            .and_then(|l| {
+                let rest = l.split(':').nth(1).unwrap_or("").trim();
+                rest.split_whitespace().next().and_then(|n| n.parse::<u32>().ok())
+            })
+            .unwrap_or(0);
+        (model, cores)
+    }).clone();
+
+    let cpu_usage = {
+        let read_stat = || -> Option<(u64, u64)> {
+            let stat = std::fs::read_to_string("/proc/stat").ok()?;
+            let first = stat.lines().next()?;
+            let vals: Vec<u64> = first.split_whitespace().skip(1).filter_map(|v| v.parse().ok()).collect();
+            if vals.len() < 3 { return None; }
+            let total: u64 = vals.iter().sum();
+            let idle = vals.get(3).copied().unwrap_or(0);
+            Some((idle, total))
+        };
+        let (idle1, total1) = read_stat().unwrap_or((0, 1));
+        tokio::time::sleep(std::time::Duration::from_millis(100)).await;
+        let (idle2, total2) = read_stat().unwrap_or((0, 1));
+        let d_idle = idle2.saturating_sub(idle1);
+        let d_total = total2.saturating_sub(total1);
+        if d_total > 0 {
+            (1.0 - d_idle as f64 / d_total as f64) * 100.0
+        } else { 0.0 }
+    } as f32;
+
+    static GPUS_INFO: std::sync::OnceLock<Vec<String>> = std::sync::OnceLock::new();
+    let gpus = GPUS_INFO.get_or_init(|| {
+        let mut list = Vec::new();
+        if let Some(o) = std::process::Command::new("lspci").output().ok() {
+            for line in String::from_utf8_lossy(&o.stdout).lines() {
+                if line.contains("VGA") || line.contains("3D") {
+                    if let Some(name) = line.split(':').nth(2) {
+                        let trimmed = name.trim().to_string();
+                        if !trimmed.is_empty() {
+                            list.push(trimmed);
+                        }
+                    }
+                }
+            }
+        }
+        list
+    }).clone();
+
+    let processes = {
+        let mut list = Vec::new();
+        if let Some(o) = tokio::process::Command::new("ps")
+            .args(["-eo", "pid,%cpu,comm", "--sort=-%cpu"])
+            .output().await.ok()
+        {
+            let text = String::from_utf8_lossy(&o.stdout);
+            for line in text.lines().skip(1) {
+                let parts: Vec<&str> = line.split_whitespace().collect();
+                if parts.len() >= 3 {
+                    let pid = parts[0].to_string();
+                    let cpu = parts[1].to_string();
+                    let comm = parts[2..].join(" ");
+                    list.push((pid, cpu, comm));
+                }
+            }
+        }
+        list
+    };
+
+    let cpu_temp = read_cpu_temp();
+    let tp_gpu_temp = read_thinkpad_gpu_temp();
+    let nv_gpu_temp = read_nvidia_gpu_temp().await;
+
+    let cpu_label_text = format!("CPU  {}  ({} cores)", cpu_model, cpu_cores);
+    let cpu_usage_text = format!("Usage  {:.0}%", cpu_usage);
+    let cpu_temp_text = cpu_temp.map(|t| format!("Temp  {:.0}°C", t)).unwrap_or_else(|| "Temp  N/A".to_string());
+
+    let gpu_labels = gpus.iter().map(|gpu_name| {
+        let temp = if gpu_name.to_lowercase().contains("nvidia") {
+            nv_gpu_temp.or(tp_gpu_temp)
+        } else {
+            tp_gpu_temp
+        };
+        let temp_str = temp.map(|t| format!("  —  {:.0}°C", t)).unwrap_or_default();
+        let text = format!("GPU  {}{}", gpu_name, temp_str);
+        Label::new(&text).with_font_size(12.0).with_color([212, 212, 212])
+    }).collect();
+
+    let (battery, on_ac) = fetch_upower().await;
+    let cpu_powersave = current_cpu_governor() == "powersave";
+    let gpu_powersave = current_gpu_power_cap().await;
+
+    ProcessesState {
+        cpu_model,
+        cpu_usage,
+        cpu_cores,
+        gpus,
+        loaded: true,
+        cpu_label: Label::new(&cpu_label_text).with_font_size(12.0).with_color([212, 212, 212]),
+        cpu_usage_label: Label::new(&cpu_usage_text).with_font_size(12.0).with_color([212, 212, 212]),
+        cpu_temp_label: Label::new(&cpu_temp_text).with_font_size(12.0).with_color([212, 212, 212]),
+        gpu_labels,
+        processes,
+        cpu_list_box: ScrollingList::new(24.0, 2.0),
+        battery,
+        on_ac,
+        cpu_powersave,
+        gpu_powersave,
+        cpu_gov_menu: Dropdown::new(
+            vec!["Performance".to_string(), "Powersave".to_string()],
+            if cpu_powersave { 1 } else { 0 },
+        ).with_label("CPU Governor"),
+        gpu_gov_menu: Dropdown::new(
+            vec!["Default (80W)".to_string(), "Eco Cap (5W)".to_string()],
+            if gpu_powersave { 1 } else { 0 },
+        ).with_label("GPU Power Limit"),
+
+        services_loaded: false,
+        services: Vec::new(),
+        services_active_tab: ServiceTab::System,
+        services_search_box: TextBox::new(String::new()).with_label("Filter Services"),
+        services_list_box: ScrollingList::new(36.0, 6.0),
+        service_items: Vec::new(),
+        notifications_loaded: false,
+        notifications_enable: true,
+        notifications_enable_toggle: Toggle::new().with_label("Enable Notifications"),
+        notifications_bell: false,
+        notifications_bell_toggle: Toggle::new().with_label("Play Bell Sound"),
+        notifications_duration: 5,
+        notifications_duration_spinbox: Spinbox::new(5, 1, 60, 1)
+            .with_label("Notification Duration")
+            .with_unit("s"),
+
+        status_loaded: false,
+        status_font_size: 11,
+        status_padding: 8,
+        status_separators: true,
+        status_underline: true,
+        status_running: false,
+        status_label: Label::new("Status Interface: Stopped").with_font_size(14.0).with_color([170, 51, 51]),
+        status_separators_toggle: Toggle::new().with_label("Show Separators"),
+        status_underline_toggle: Toggle::new().with_label("Show Underline"),
+        status_padding_spinbox: Spinbox::new(8, 0, 32, 1).with_label("Side Padding").with_unit("px"),
+    }
+}
+
+const TEXT_FG: [f32; 4] = [0.83, 0.83, 0.83, 1.0];
+const TEXT_DIM: [f32; 4] = [0.53, 0.53, 0.60, 1.0];
+const ACCENT: [f32; 4] = [0.36, 0.56, 0.38, 1.0];
+const RED: [f32; 4] = [1.0, 0.33, 0.33, 1.0];
+const ORANGE: [f32; 4] = [1.0, 0.73, 0.20, 1.0];
+
+pub fn view(state: &mut ProcessesState, cx: f32, cy: f32, cw: f32, ch: f32, root_focused: bool, sec_focused: &[bool], layout: &mut dyn LayoutStrategy, ctx: &mut cce_ui::context::UiContext) -> PageContent {
+    let mut final_pc = PageContent::new();
+    let sec_w = 320.0f32;
+    let mut builder = PageLayoutBuilder::new(layout, cx, cy, cw, ch, sec_w).with_section_count(8);
+
+    // ── CPU Section ──
+    builder.add_section(&mut final_pc, "CPU", root_focused, |sec| {
+        let rx = sec.left;
+        if !state.loaded {
+            sec.text("Loading CPU model and utilization...", 12.0, 0.0, 12.0, TEXT_FG);
+            sec.spacing(10.0);
+        } else {
+            // CPU Info Label
+            sec.widget(&mut state.cpu_label, 12.0, sec.cw - 24.0, 26.0, ctx);
+            sec.spacing(12.0);
+
+            // CPU Usage Label
+            sec.widget(&mut state.cpu_usage_label, 12.0, sec.cw - 24.0, 26.0, ctx);
+            sec.spacing(12.0);
+
+            // CPU Temp Label
+            sec.widget(&mut state.cpu_temp_label, 12.0, sec.cw - 24.0, 26.0, ctx);
+            sec.spacing(12.0);
+
+            // Scrolling box configuration for process list
+            let list_box_x = rx + 12.0;
+            let list_box_y = sec.ay();
+            let list_box_w = sec.cw - 24.0;
+            let list_box_h = 220.0;
+            
+            // Render the standardized ScrollBox widget
+            render_widget(sec.pc, &mut state.cpu_list_box, list_box_x, list_box_y, list_box_w, list_box_h, ctx);
+
+            // Header for process list columns (drawn static on top of the ScrollBox background)
+            let header_h = 22.0;
+            sec.pc.rect([0.12, 0.12, 0.16, 0.5], list_box_x + 1.0, list_box_y + 1.0, list_box_w - 2.0, header_h);
+            sec.pc.rect([0.18, 0.18, 0.24, 1.0], list_box_x + 1.0, list_box_y + header_h, list_box_w - 2.0, 1.0); // Divider
+            
+            sec.pc.text("PID", list_box_x + 12.0, list_box_y + 5.0, 11.0, [0.53, 0.53, 0.60, 1.0]);
+            sec.pc.text("COMMAND", list_box_x + 80.0, list_box_y + 5.0, 11.0, [0.53, 0.53, 0.60, 1.0]);
+            sec.pc.text("CPU %", list_box_x + list_box_w - 60.0, list_box_y + 5.0, 11.0, [0.53, 0.53, 0.60, 1.0]);
+
+            let row_h = 24.0;
+            // Update ScrollingList bounds for the scrollable viewport (which starts below the header)
+            state.cpu_list_box.update_bounds(state.processes.len(), list_box_y + header_h, list_box_h - header_h - 6.0);
+
+            // Visible process rows rendering (virtualized/clipped)
+            sec.pc.push_clip_rect(list_box_x, list_box_y + header_h, list_box_w, list_box_h - header_h);
+            for (idx, (pid, cpu, comm)) in state.processes.iter().enumerate() {
+                if let Some(draw_y) = state.cpu_list_box.get_item_draw_y(idx, 4.0) {
+                    // Standard row action button (transparent background, highlights on hover)
+                    sec.pc.button(
+                        "",
+                        list_box_x + 2.0,
+                        draw_y,
+                        list_box_w - 16.0,
+                        row_h,
+                        [0.0, 0.0, 0.0, 0.0],
+                        [1.0, 1.0, 1.0, 0.06],
+                        [0.0, 0.0, 0.0, 0.0],
+                        AppAction::Processes(ProcessesMessage::None),
+                    );
+                    
+                    sec.pc.text(pid, list_box_x + 12.0, draw_y + 6.0, 12.0, [0.80, 0.80, 0.85, 1.0]);
+                    sec.pc.text(comm, list_box_x + 80.0, draw_y + 6.0, 12.0, [0.80, 0.80, 0.85, 1.0]);
+                    sec.pc.text(&format!("{}%", cpu), list_box_x + list_box_w - 60.0, draw_y + 6.0, 12.0, [0.56, 0.83, 0.56, 1.0]);
+                }
+            }
+            sec.pc.pop_clip_rect();
+            
+            if state.processes.is_empty() {
+                sec.pc.text("No active processes", list_box_x + 12.0, list_box_y + header_h + 16.0, 12.0, TEXT_DIM);
+            }
+
+            sec.content_y += list_box_h;
+        }
+    });
+
+    // ── GPU Section ──
+    builder.add_section(&mut final_pc, "GPU", false, |sec_gpu| {
+        if !state.loaded {
+            sec_gpu.text("Loading GPU models...", 12.0, 0.0, 12.0, TEXT_FG);
+            sec_gpu.spacing(10.0);
+        } else {
+            for (i, gpu_lbl) in state.gpu_labels.iter_mut().enumerate() {
+                if i > 0 { sec_gpu.spacing(12.0); }
+                sec_gpu.widget(gpu_lbl, 12.0, sec_gpu.cw - 24.0, 26.0, ctx);
+            }
+        }
+    });
+
+    // ── Battery Section ──
+    builder.add_section(&mut final_pc, "Battery", false, |sec_bat| {
+        if !state.loaded {
+            sec_bat.text("Loading battery status...", 12.0, 0.0, 12.0, TEXT_DIM);
+            sec_bat.spacing(18.0);
+        } else {
+            let bat = &state.battery;
+            let bat_icon = match bat.state.as_str() {
+                "charging" => "+",
+                "fully-charged" => "=",
+                _ => "",
+            };
+
+            let pct_color = if bat.percentage < 20.0 { RED }
+                else if bat.percentage < 50.0 { ORANGE }
+                else { ACCENT };
+
+            let pct_str = format!("{} {:.0}%", bat_icon, bat.percentage);
+            sec_bat.text(&pct_str, 12.0, 0.0, 24.0, pct_color);
+            sec_bat.spacing(30.0);
+
+            let state_str = format!("{}  •  {:.1}W  •  {:.1}/{:.1} Wh",
+                bat.state, bat.energy_rate, bat.energy, bat.energy_full);
+            sec_bat.text(&state_str, 12.0, 0.0, 12.0, TEXT_DIM);
+            sec_bat.spacing(18.0);
+
+            let time_str = if bat.time_to_empty > 0 {
+                format!("Time remaining: {}", format_duration(bat.time_to_empty))
+            } else if bat.time_to_full > 0 {
+                format!("Time to full: {}", format_duration(bat.time_to_full))
+            } else { String::new() };
+            if !time_str.is_empty() {
+                sec_bat.text(&time_str, 12.0, 0.0, 12.0, TEXT_DIM);
+                sec_bat.spacing(18.0);
+            }
+
+            let detail_str = format!("{}  {}", bat.vendor, bat.model);
+            sec_bat.text(&detail_str, 12.0, 0.0, 11.0, TEXT_DIM);
+            sec_bat.spacing(20.0);
+
+            let ac_str = if state.on_ac { "On AC Power" } else { "On Battery" };
+            sec_bat.text(ac_str, 12.0, 0.0, 14.0, TEXT_FG);
+            sec_bat.spacing(20.0);
+        }
+    });
+
+    // ── CPU Governor section ──
+    builder.add_section(&mut final_pc, "CPU Governor", false, |sec_gov| {
+        let rx = sec_gov.left;
+        if !state.loaded {
+            sec_gov.text("Loading CPU governor...", 12.0, 0.0, 12.0, TEXT_DIM);
+            sec_gov.spacing(18.0);
+        } else {
+            sec_gov.widget(&mut state.cpu_gov_menu, 12.0, sec_gov.cw - 24.0, 26.0, ctx);
+            sec_gov.spacing(12.0);
+
+            let (info_title, info_lines) = if state.cpu_powersave {
+                (
+                    "CPU Governor: Powersave",
+                    vec![
+                        "• Active: powersave".to_string(),
+                        "• Governor set to powersave — lower power, slower burst".to_string(),
+                    ],
+                )
+            } else {
+                (
+                    "CPU Governor: Performance",
+                    vec![
+                        "• Active: performance".to_string(),
+                        "• Governor set to performance".to_string(),
+                    ],
+                )
+            };
+
+            let mut info_box = InfoBox::new(info_title, info_lines);
+            let info_h = 80.0;
+            let info_y = sec_gov.ay();
+            render_widget(sec_gov.pc, &mut info_box, rx + 12.0, info_y, sec_gov.cw - 24.0, info_h, ctx);
+            sec_gov.spacing(info_h + 12.0);
+        }
+    });
+
+    // ── GPU Power section ──
+    builder.add_section(&mut final_pc, "GPU Power", false, |sec_gpow| {
+        let rx = sec_gpow.left;
+        if !state.loaded {
+            sec_gpow.text("Loading GPU power status...", 12.0, 0.0, 12.0, TEXT_DIM);
+            sec_gpow.spacing(18.0);
+        } else {
+            sec_gpow.widget(&mut state.gpu_gov_menu, 12.0, sec_gpow.cw - 24.0, 26.0, ctx);
+            sec_gpow.spacing(12.0);
+
+            let (info_title, info_lines) = if state.gpu_powersave {
+                (
+                    "GPU Power Limit: Eco Cap",
+                    vec![
+                        "• Mode: 5W Cap".to_string(),
+                        "• NVIDIA power limit capped at 5W — minimal draw".to_string(),
+                    ],
+                )
+            } else {
+                (
+                    "GPU Power Limit: Default",
+                    vec![
+                        "• Mode: 80W Default".to_string(),
+                        "• NVIDIA running at default power limit".to_string(),
+                    ],
+                )
+            };
+
+            let mut info_box = InfoBox::new(info_title, info_lines);
+            let info_h = 80.0;
+            let info_y = sec_gpow.ay();
+            render_widget(sec_gpow.pc, &mut info_box, rx + 12.0, info_y, sec_gpow.cw - 24.0, info_h, ctx);
+            sec_gpow.spacing(info_h + 12.0);
+        }
+    });
+
+    // ── Services Section ──
+    builder.add_section_spanned(&mut final_pc, "Services", 2, sec_focused.get(5).copied().unwrap_or(false), |sec| {
+        let sec_w = sec.cw;
+        if !state.services_loaded {
+            sec.text("Loading systemd services...", 12.0, 0.0, 12.0, TEXT_DIM);
+            sec.spacing(18.0);
+        } else {
+            // Tab header buttons: System Services, User Services
+            let tab_w = (sec_w - 24.0 - 8.0) / 2.0;
+            let tab_h = 28.0;
+            let tab_y = sec.ay();
+            let active_bg = [0.20, 0.40, 0.65, 0.4];
+            let inactive_bg = [0.10, 0.10, 0.16, 0.3];
+            let hover_bg = [0.20, 0.20, 0.25, 0.15];
+
+            let label1 = if tab_w < 110.0 { "System" } else { "System Services" };
+            let label2 = if tab_w < 110.0 { "User" } else { "User Services" };
+
+            let tab_x1 = sec.left + 12.0;
+            let tab_x2 = sec.left + 12.0 + tab_w + 8.0;
+
+            sec.pc.button(
+                label1,
+                tab_x1,
+                tab_y,
+                tab_w,
+                tab_h,
+                if state.services_active_tab == ServiceTab::System { active_bg } else { inactive_bg },
+                hover_bg,
+                [0.90, 0.90, 0.95, 1.0],
+                crate::app::AppAction::Processes(ProcessesMessage::ServicesSetTab(ServiceTab::System)),
+            );
+
+            sec.pc.button(
+                label2,
+                tab_x2,
+                tab_y,
+                tab_w,
+                tab_h,
+                if state.services_active_tab == ServiceTab::User { active_bg } else { inactive_bg },
+                hover_bg,
+                [0.90, 0.90, 0.95, 1.0],
+                crate::app::AppAction::Processes(ProcessesMessage::ServicesSetTab(ServiceTab::User)),
+            );
+            sec.content_y += tab_h + 12.0;
+
+            // Search textbox
+            let search_y = sec.ay();
+            let search_w = sec_w - 24.0;
+            let search_h = 46.0;
+            
+            state.services_search_box.set_row_rect(sec.left + 12.0, search_w);
+            cce_ui::layout::render_widget(
+                sec.pc,
+                &mut state.services_search_box,
+                sec.left + 12.0,
+                search_y,
+                search_w,
+                search_h,
+                ctx,
+            );
+            sec.content_y += search_h + 16.0;
+
+            // Scroll box list
+            let list_box_x = sec.left + 12.0;
+            let list_box_y = sec.ay();
+            let list_box_w = sec_w - 24.0;
+            let list_box_h = 360.0;
+            
+            cce_ui::layout::render_widget(sec.pc, &mut state.services_list_box, list_box_x, list_box_y, list_box_w, list_box_h, ctx);
+
+            // Filter services
+            let query = if state.services_search_box.editing {
+                state.services_search_box.edit_buffer.to_lowercase()
+            } else {
+                state.services_search_box.text.to_lowercase()
+            };
+            let filtered_services: Vec<&ServiceInfo> = state.services.iter()
+                .filter(|s| s.is_system == (state.services_active_tab == ServiceTab::System))
+                .filter(|s| s.name.to_lowercase().contains(&query) || s.description.to_lowercase().contains(&query))
+                .collect();
+
+            // Update ScrollingList bounds
+            state.services_list_box.update_bounds(filtered_services.len(), list_box_y, list_box_h);
+
+            let item_h = state.services_list_box.item_height;
+
+            if state.service_items.len() != filtered_services.len() {
+                state.service_items.clear();
+                for _ in 0..filtered_services.len() {
+                    state.service_items.push(InteractiveListItem::new(""));
+                }
+            }
+
+            sec.pc.push_clip_rect(list_box_x, list_box_y, list_box_w, list_box_h);
+            for (idx, service) in filtered_services.iter().enumerate() {
+                if let Some(draw_y) = state.services_list_box.get_item_draw_y(idx, 4.0) {
+                    let is_active = service.active_state == "active" || service.sub_state == "running";
+
+                    // Control buttons: Start, Stop, Restart on the right
+                    let is_small = sec_w < 350.0;
+                    let btn_w = if is_small { 24.0 } else { 46.0 };
+                    let r_btn_w = if is_small { 24.0 } else { 54.0 };
+                    let btn_gap = if is_small { 4.0 } else { 6.0 };
+                    let right_edge = list_box_x + list_box_w - 24.0 - 8.0;
+
+                    let restart_x = right_edge - r_btn_w;
+                    let stop_x = restart_x - btn_gap - btn_w;
+                    let start_x = stop_x - btn_gap - btn_w;
+
+                    let btn_y = draw_y + (item_h - 22.0) / 2.0;
+                    let btn_h = 22.0;
+
+                    // Service Description (Truncate dynamically based on remaining space before Start button)
+                    let text_max_w = (start_x - 8.0) - (list_box_x + 32.0);
+                    let max_chars = ((text_max_w / 6.0) as usize).max(10);
+                    let desc = if service.description.is_empty() { "No description" } else { &service.description };
+                    let desc_truncated = if desc.len() > max_chars {
+                        format!("{}...", &desc[..max_chars.saturating_sub(3)])
+                    } else {
+                        desc.to_string()
+                    };
+
+                    // Render InteractiveListItem background and text labels
+                    let item_btn = &mut state.service_items[idx];
+                    item_btn.title = service.name.clone();
+                    item_btn.subtitle = Some(desc_truncated);
+                    cce_ui::layout::render_widget(sec.pc, item_btn, list_box_x + 24.0, draw_y, list_box_w - 44.0, item_h, ctx);
+
+                    // Render StatusDot
+                    let status_dot_state = if service.active_state == "failed" {
+                        DotStatus::Error
+                    } else if is_active {
+                        DotStatus::Active
+                    } else {
+                        DotStatus::Inactive
+                    };
+                    let mut dot = StatusDot::new(status_dot_state);
+                    cce_ui::layout::render_widget(sec.pc, &mut dot, list_box_x + 10.0, draw_y + (item_h - 10.0) / 2.0, 10.0, 10.0, ctx);
+
+                    let active_txt = [0.90, 0.90, 0.95, 1.0];
+                    let disabled_txt = [0.40, 0.40, 0.45, 1.0];
+
+                    let start_lbl = if is_small { "▶" } else { "Start" };
+                    let stop_lbl = if is_small { "■" } else { "Stop" };
+                    let restart_lbl = if is_small { "⟳" } else { "Restart" };
+
+                    // Start button
+                    sec.pc.button(
+                        start_lbl,
+                        start_x,
+                        btn_y,
+                        btn_w,
+                        btn_h,
+                        if !is_active { [0.16, 0.35, 0.18, 0.4] } else { [0.12, 0.12, 0.16, 0.1] },
+                        [0.22, 0.45, 0.25, 0.6],
+                        if !is_active { active_txt } else { disabled_txt },
+                        crate::app::AppAction::Processes(ProcessesMessage::ServicesStart(service.name.clone(), service.is_system)),
+                    );
+
+                    // Stop button
+                    sec.pc.button(
+                        stop_lbl,
+                        stop_x,
+                        btn_y,
+                        btn_w,
+                        btn_h,
+                        if is_active { [0.55, 0.16, 0.16, 0.3] } else { [0.12, 0.12, 0.16, 0.1] },
+                        [0.70, 0.22, 0.22, 0.5],
+                        if is_active { active_txt } else { disabled_txt },
+                        crate::app::AppAction::Processes(ProcessesMessage::ServicesStop(service.name.clone(), service.is_system)),
+                    );
+
+                    // Restart button
+                    sec.pc.button(
+                        restart_lbl,
+                        restart_x,
+                        btn_y,
+                        r_btn_w,
+                        btn_h,
+                        [0.15, 0.28, 0.45, 0.3],
+                        [0.20, 0.38, 0.58, 0.5],
+                        active_txt,
+                        crate::app::AppAction::Processes(ProcessesMessage::ServicesRestart(service.name.clone(), service.is_system)),
+                    );
+                }
+            }
+            sec.pc.pop_clip_rect();
+
+            if filtered_services.is_empty() {
+                sec.pc.text("No services match the query", list_box_x + 16.0, list_box_y + 16.0, 12.0, TEXT_DIM);
+            }
+
+            sec.content_y += list_box_h;
+        }
+    });
+
+    // ── System Notifications ──
+    builder.add_section(&mut final_pc, "System Notifications", sec_focused.get(6).copied().unwrap_or(false), |sec2| {
+        let sec_w = sec2.cw;
+        state.notifications_enable_toggle.set_toggled(state.notifications_enable);
+        sec2.widget_full(&mut state.notifications_enable_toggle, cce_ui::layout::toggle_height(), ctx);
+        sec2.spacing(8.0);
+
+        state.notifications_bell_toggle.set_toggled(state.notifications_bell);
+        sec2.widget_full(&mut state.notifications_bell_toggle, cce_ui::layout::toggle_height(), ctx);
+        sec2.spacing(16.0);
+
+        state.notifications_duration_spinbox.value = state.notifications_duration;
+        state.notifications_duration_spinbox.set_label("Notification Duration");
+        sec2.widget(&mut state.notifications_duration_spinbox, 14.0, sec_w - 28.0, 44.0, ctx);
+        sec2.spacing(16.0);
+
+        let btn_h = 32.0;
+        let btn_y = sec2.ay();
+        let white_color = [1.0, 1.0, 1.0, 1.0];
+        let btn_bg = [0.20, 0.40, 0.65, 1.0];
+        let btn_hover = [0.28, 0.50, 0.78, 1.0];
+        
+        let cols = sec2.row_layout(1, 0.0);
+        if let Some(&(x, w)) = cols.first() {
+            sec2.button(
+                "Send Test Notification",
+                x,
+                btn_y,
+                w,
+                btn_h,
+                btn_bg,
+                btn_hover,
+                white_color,
+                AppAction::Processes(ProcessesMessage::SendTestNotification),
+            );
+        }
+        sec2.spacing(12.0);
+    });
+
+    // ── Status Interface ──
+    builder.add_section(&mut final_pc, "Status Interface", sec_focused.get(7).copied().unwrap_or(false), |sec3| {
+        let sec_w = sec3.cw;
+        if !state.status_loaded {
+            sec3.text("Loading Status Interface status...", 12.0, 0.0, 12.0, TEXT_DIM);
+            sec3.spacing(18.0);
+        } else {
+            // Status
+            let status_text = if state.status_running { "Status Interface: Running" } else { "Status Interface: Stopped" };
+            let status_color = if state.status_running { [92, 143, 97] } else { [170, 51, 51] };
+            state.status_label.set_text(status_text);
+            state.status_label.set_color(status_color);
+            sec3.widget(&mut state.status_label, 12.0, sec_w - 24.0, 20.0, ctx);
+            sec3.spacing(12.0);
+
+            sec3.spacing(4.0);
+
+            // Separators toggle
+            state.status_separators_toggle.set_toggled(state.status_separators);
+            sec3.widget_full(&mut state.status_separators_toggle, cce_ui::layout::toggle_height(), ctx);
+            sec3.spacing(16.0);
+
+            // Underline toggle
+            state.status_underline_toggle.set_toggled(state.status_underline);
+            sec3.widget_full(&mut state.status_underline_toggle, cce_ui::layout::toggle_height(), ctx);
+            sec3.spacing(16.0);
+
+            // Padding spinbox
+            state.status_padding_spinbox.value = state.status_padding as i32;
+            sec3.widget(&mut state.status_padding_spinbox, 12.0, sec_w - 24.0, 44.0, ctx);
+            sec3.spacing(16.0);
+
+            // Reload button
+            let yt_reload = sec3.ay();
+            let btn_w = sec_w - 24.0;
+            let button_x = sec3.left + 12.0;
+            sec3.button(
+                "Reload Status Interface",
+                button_x,
+                yt_reload,
+                btn_w,
+                32.0,
+                [0.13, 0.18, 0.14, 1.0],
+                [0.25, 0.30, 0.26, 1.0],
+                [1.0, 1.0, 1.0, 1.0],
+                AppAction::Processes(ProcessesMessage::StatusReload),
+            );
+            sec3.spacing(12.0);
+        }
+    });
+
+    final_pc
+}
+
+pub fn update(state: &mut ProcessesState, msg: ProcessesMessage) {
+    match msg {
+        ProcessesMessage::Refreshed(new) => {
+            state.loaded = new.loaded;
+            state.cpu_model = new.cpu_model;
+            state.cpu_usage = new.cpu_usage;
+            state.cpu_cores = new.cpu_cores;
+            state.gpus = new.gpus;
+            state.cpu_label = new.cpu_label;
+            state.cpu_usage_label = new.cpu_usage_label;
+            state.cpu_temp_label = new.cpu_temp_label;
+            state.gpu_labels = new.gpu_labels;
+            state.processes = new.processes;
+            let old_scroll = state.cpu_list_box.scroll_y();
+            state.cpu_list_box = new.cpu_list_box;
+            state.cpu_list_box.set_scroll_y(old_scroll);
+
+            state.battery = new.battery;
+            state.on_ac = new.on_ac;
+            state.cpu_powersave = new.cpu_powersave;
+            state.gpu_powersave = new.gpu_powersave;
+            state.cpu_gov_menu.selected = new.cpu_gov_menu.selected;
+            state.gpu_gov_menu.selected = new.gpu_gov_menu.selected;
+        }
+        ProcessesMessage::SetCpuPerformance => {
+            state.cpu_powersave = false;
+            state.cpu_gov_menu.selected = 0;
+            spawn_cpu_power(false);
+        }
+        ProcessesMessage::SetCpuPowersave => {
+            state.cpu_powersave = true;
+            state.cpu_gov_menu.selected = 1;
+            spawn_cpu_power(true);
+        }
+        ProcessesMessage::SetGpuDefault => {
+            state.gpu_powersave = false;
+            state.gpu_gov_menu.selected = 0;
+            spawn_gpu_power(false);
+        }
+        ProcessesMessage::SetGpuPowersave => {
+            state.gpu_powersave = true;
+            state.gpu_gov_menu.selected = 1;
+            spawn_gpu_power(true);
+        }
+        ProcessesMessage::ServicesRefreshed(new_services) => {
+            state.services_loaded = true;
+            state.services = new_services;
+            state.service_items.clear();
+        }
+        ProcessesMessage::ServicesSetTab(tab) => {
+            state.services_active_tab = tab;
+            state.services_list_box.set_scroll_y(0.0);
+            state.service_items.clear();
+        }
+        ProcessesMessage::ServicesStart(name, is_system) => {
+            if let Some(srv) = state.services.iter_mut().find(|s| s.name == name && s.is_system == is_system) {
+                srv.active_state = "activating".to_string();
+                srv.sub_state = "starting".to_string();
+            }
+            service_action(&name, "start", is_system);
+        }
+        ProcessesMessage::ServicesStop(name, is_system) => {
+            if let Some(srv) = state.services.iter_mut().find(|s| s.name == name && s.is_system == is_system) {
+                srv.active_state = "deactivating".to_string();
+                srv.sub_state = "stopping".to_string();
+            }
+            service_action(&name, "stop", is_system);
+        }
+        ProcessesMessage::ServicesRestart(name, is_system) => {
+            if let Some(srv) = state.services.iter_mut().find(|s| s.name == name && s.is_system == is_system) {
+                srv.active_state = "activating".to_string();
+                srv.sub_state = "restarting".to_string();
+            }
+            service_action(&name, "restart", is_system);
+        }
+        ProcessesMessage::ToggleNotificationsEnable => {
+            state.notifications_enable = !state.notifications_enable;
+            write_enable_notifications(state.notifications_enable);
+        }
+        ProcessesMessage::ToggleNotificationsBell => {
+            state.notifications_bell = !state.notifications_bell;
+            write_config_value("bell", &state.notifications_bell.to_string());
+        }
+        ProcessesMessage::SetNotificationsDuration(d) => {
+            state.notifications_duration = d;
+            write_config_value("duration", &state.notifications_duration.to_string());
+        }
+        ProcessesMessage::SendTestNotification => {
+            tokio::spawn(async move {
+                if let Ok(connection) = zbus::Connection::session().await {
+                    let _ = connection.call_method(
+                        Some("org.freedesktop.Notifications"),
+                        "/org/freedesktop/Notifications",
+                        Some("org.freedesktop.Notifications"),
+                        "Notify",
+                        &(
+                            "cce-client",
+                            0u32,
+                            "",
+                            "System notifications are working correctly!",
+                            "",
+                            Vec::<&str>::new(),
+                            std::collections::HashMap::<&str, zbus::zvariant::Value>::new(),
+                            -1i32,
+                        )
+                    ).await;
+                }
+            });
+        }
+        ProcessesMessage::NotificationsRefreshed(new) => {
+            state.notifications_loaded = true;
+            state.notifications_enable = new.enable;
+            state.notifications_bell = new.bell;
+            state.notifications_duration = new.duration;
+        }
+        ProcessesMessage::StatusRefreshed(new) => {
+            let was_status_hovered = state.status_label.hovered();
+            let was_separators_hovered = state.status_separators_toggle.hovered();
+            let was_underline_hovered = state.status_underline_toggle.hovered();
+
+            state.status_loaded = true;
+            state.status_font_size = new.font_size;
+            state.status_padding = new.padding;
+            state.status_separators = new.separators;
+            state.status_underline = new.underline;
+            state.status_running = new.running;
+
+            state.status_label.set_hovered(was_status_hovered);
+            state.status_separators_toggle.set_hovered(was_separators_hovered);
+            state.status_underline_toggle.set_hovered(was_underline_hovered);
+        }
+        ProcessesMessage::StatusToggleSeparators => {
+            state.status_separators = !state.status_separators;
+            write_status_separators(state.status_separators);
+            status_interface_reload();
+        }
+        ProcessesMessage::StatusToggleUnderline => {
+            state.status_underline = !state.status_underline;
+            write_status_underline(state.status_underline);
+            status_interface_reload();
+        }
+        ProcessesMessage::StatusSetPadding(val) => {
+            state.status_padding = val;
+            write_status_padding(val);
+            status_interface_reload();
+        }
+        ProcessesMessage::StatusReload => {
+            status_interface_reload();
+        }
+        ProcessesMessage::None => {}
+    }
+}
+
+// ── Background Fetching ──
+
+pub async fn fetch_services() -> Vec<ServiceInfo> {
+    let mut services = Vec::new();
+
+    // 1. Fetch system-level services
+    if let Ok(output) = tokio::process::Command::new("systemctl")
+        .args(["list-units", "--type=service", "--all", "--no-legend"])
+        .output()
+        .await
+    {
+        let stdout = String::from_utf8_lossy(&output.stdout);
+        for line in stdout.lines() {
+            if let Some(info) = parse_service_line(line, true) {
+                services.push(info);
+            }
+        }
+    }
+
+    // 2. Fetch user-level services
+    if let Ok(output) = tokio::process::Command::new("systemctl")
+        .args(["--user", "list-units", "--type=service", "--all", "--no-legend"])
+        .output()
+        .await
+    {
+        let stdout = String::from_utf8_lossy(&output.stdout);
+        for line in stdout.lines() {
+            if let Some(info) = parse_service_line(line, false) {
+                services.push(info);
+            }
+        }
+    }
+
+    // Sort alphabetically by name
+    services.sort_by(|a, b| a.name.to_lowercase().cmp(&b.name.to_lowercase()));
+    services
+}
+
+fn parse_service_line(line: &str, is_system: bool) -> Option<ServiceInfo> {
+    let cleaned = line.trim_start_matches('●').trim();
+    if cleaned.is_empty() {
+        return None;
+    }
+    let parts: Vec<&str> = cleaned.split_whitespace().collect();
+    if parts.len() >= 4 && parts[0].ends_with(".service") {
+        let name = parts[0].to_string();
+        let _load = parts[1];
+        let active_state = parts[2].to_string();
+        let sub_state = parts[3].to_string();
+        let description = parts[4..].join(" ");
+        Some(ServiceInfo {
+            name,
+            description,
+            active_state,
+            sub_state,
+            is_system,
+        })
+    } else {
+        None
+    }
+}
+
+fn service_action(name: &str, action: &str, is_system: bool) {
+    if is_system {
+        // System service needs root privilege, spawn via pkexec
+        let _ = tokio::process::Command::new("pkexec")
+            .args(["systemctl", action, name])
+            .spawn();
+    } else {
+        let _ = tokio::process::Command::new("systemctl")
+            .args(["--user", action, name])
+            .spawn();
+    }
+}
+
+// ── Notifications Configuration Reader & Writer ──
+
+const CONFIG_PATH: &str = "/home/lsgalante/.config/cce/config.json";
+
+fn get_socket_path() -> String {
+    match std::env::var("WAYLAND_DISPLAY") {
+        Ok(display) => format!("/tmp/cce-{}.sock", display),
+        Err(_) => "/tmp/cce.sock".to_string(),
+    }
+}
+
+pub fn read_notifications_config() -> NotificationsConfig {
+    let content = fs::read_to_string(CONFIG_PATH).unwrap_or_default();
+    let enable = parse_notifications_enable(&content);
+    let bell = parse_notifications_bell(&content);
+    let duration = parse_notifications_duration(&content);
+    NotificationsConfig {
+        enable,
+        bell,
+        duration,
+    }
+}
+
+fn parse_json(content: &str) -> serde_json::Value {
+    serde_json::from_str(content).unwrap_or_default()
+}
+
+fn parse_notifications_enable(content: &str) -> bool {
+    let val = parse_json(content);
+    val["notifications"]["enable"].as_bool().unwrap_or(true)
+}
+
+fn parse_notifications_bell(content: &str) -> bool {
+    let val = parse_json(content);
+    val["notifications"]["bell"].as_bool().unwrap_or(false)
+}
+
+fn parse_notifications_duration(content: &str) -> i32 {
+    let val = parse_json(content);
+    val["notifications"]["duration"].as_i64().map(|v| v as i32).unwrap_or(5)
+}
+
+fn send_ipc_command(cmd: &str) {
+    if let Ok(mut stream) = std::os::unix::net::UnixStream::connect(get_socket_path()) {
+        let _ = stream.write_all(format!("{}\n", cmd).as_bytes());
+    }
+}
+
+fn write_config_value(key: &str, value: &str) {
+    let content = fs::read_to_string(CONFIG_PATH).unwrap_or_default();
+    let mut val = parse_json(&content);
+    let j_val = if let Ok(b) = value.parse::<bool>() {
+        serde_json::json!(b)
+    } else if let Ok(n) = value.parse::<i64>() {
+        serde_json::json!(n)
+    } else if let Ok(f) = value.parse::<f64>() {
+        serde_json::json!(f)
+    } else {
+        serde_json::json!(value)
+    };
+    if let Some(notifications) = val.get_mut("notifications").and_then(|n| n.as_object_mut()) {
+        notifications.insert(key.to_string(), j_val);
+    } else {
+        let mut map = serde_json::Map::new();
+        map.insert(key.to_string(), j_val);
+        if let Some(obj) = val.as_object_mut() {
+            obj.insert("notifications".to_string(), serde_json::Value::Object(map));
+        }
+    }
+    if let Ok(updated_str) = serde_json::to_string_pretty(&val) {
+        let _ = fs::write(CONFIG_PATH, updated_str);
+    }
+}
+
+fn write_enable_notifications(enabled: bool) {
+    write_config_value("enable", &enabled.to_string());
+    send_ipc_command("reload");
+}
+
+
+thread_local! {
+    static TEST_CONFIG_PATH: std::cell::RefCell<Option<String>> = std::cell::RefCell::new(None);
+}
+
+fn get_config_path() -> String {
+    #[cfg(test)]
+    {
+        TEST_CONFIG_PATH.with(|p| {
+            if let Some(path) = p.borrow().as_ref() {
+                return path.clone();
+            }
+            "/home/lsgalante/.config/cce/config.json".to_string()
+        })
+    }
+    #[cfg(not(test))]
+    {
+        "/home/lsgalante/.config/cce/config.json".to_string()
+    }
+}
+
+fn write_status_value(key: &str, value: &str) {
+    crate::pages::interface::write_config_value_path(&get_config_path(), key, value);
+}
+
+fn read_status_font_size() -> Option<u16> {
+    let content = std::fs::read_to_string(&get_config_path()).ok()?;
+    Some(parse_u16_from(&content, "status_font_size", 11))
+}
+
+
+fn read_status_padding() -> Option<u16> {
+    let content = std::fs::read_to_string(&get_config_path()).ok()?;
+    Some(parse_u16_from(&content, "status_padding", 8))
+}
+
+fn write_status_padding(padding: u16) {
+    write_status_value("status_padding", &padding.to_string());
+}
+
+fn read_status_separators() -> Option<bool> {
+    let content = std::fs::read_to_string(&get_config_path()).ok()?;
+    Some(crate::pages::interface::parse_bool_from(&content, "status_separators", true))
+}
+
+fn write_status_separators(val: bool) {
+    write_status_value("status_separators", &val.to_string());
+}
+
+fn read_status_underline() -> Option<bool> {
+    let content = std::fs::read_to_string(&get_config_path()).ok()?;
+    Some(crate::pages::interface::parse_bool_from(&content, "status_underline", true))
+}
+
+fn write_status_underline(val: bool) {
+    write_status_value("status_underline", &val.to_string());
+}
+
+fn status_interface_reload() {
+    let _ = std::process::Command::new("pkill")
+        .args(["-f", "cce-status-interface"])
+        .status();
+    std::thread::sleep(std::time::Duration::from_millis(150));
+    send_ipc_command("spawn cce-status-interface");
+}
+
+pub async fn fetch_status_state() -> StatusData {
+    let running = tokio::process::Command::new("pgrep")
+        .args(["-f", "cce-status-interface"]).output().await.ok()
+        .map(|o| !o.stdout.is_empty())
+        .unwrap_or(false);
+
+    let font_size = read_status_font_size().unwrap_or(11);
+    let padding = read_status_padding().unwrap_or(8);
+    let separators = read_status_separators().unwrap_or(true);
+    let underline = read_status_underline().unwrap_or(true);
+
+    StatusData {
+        font_size,
+        padding,
+        separators,
+        underline,
+        running,
+    }
+}
+
+#[cfg(test)]
+mod tests {
+    use super::*;
+
+    #[test]
+    fn test_view_layout_grid() {
+        let mut state = ProcessesState::default();
+        let mut layout = cce_ui::layout::ColumnLayout::new(20.0);
+        let sec_focused = vec![false, false, false, false, false, false, false, false];
+        let mut ctx = cce_ui::context::UiContext::new();
+        let pc = view(&mut state, 10.0, 20.0, 800.0, 600.0, false, &sec_focused, &mut layout, &mut ctx);
+        assert!(!pc.rects.is_empty() || !pc.texts.is_empty());
+    }
+
+    #[test]
+    fn test_parse_notifications_enable_default() {
+        assert!(parse_notifications_enable(""));
+        assert!(parse_notifications_enable("[layout]\ngap = 18\n"));
+    }
+
+    #[test]
+    fn test_parse_notifications_enable_explicit() {
+        let content = "{\"notifications\": {\"enable\": false}}";
+        assert!(!parse_notifications_enable(content));
+
+        let content = "{\"notifications\": {\"enable\": true}}";
+        assert!(parse_notifications_enable(content));
+    }
+
+    #[test]
+    fn test_parse_notifications_enable_other_sections() {
+        let content = r#"{
+            "layout": {"enable": false},
+            "notifications": {"enable": true},
+            "input": {"enable": false}
+        }"#;
+        assert!(parse_notifications_enable(content));
+
+        let content = r#"{
+            "layout": {"enable": true},
+            "notifications": {"enable": false},
+            "input": {"enable": true}
+        }"#;
+        assert!(!parse_notifications_enable(content));
+    }
+
+    #[test]
+    fn test_parse_notifications_duration_default() {
+        assert_eq!(parse_notifications_duration(""), 5);
+        assert_eq!(parse_notifications_duration("{\"notifications\": {}}"), 5);
+    }
+
+    #[test]
+    fn test_parse_notifications_duration_explicit() {
+        let content = "{\"notifications\": {\"duration\": 10}}";
+        assert_eq!(parse_notifications_duration(content), 10);
+    }
+
+    #[test]
+    fn test_read_write_separators() {
+        let dir = std::env::temp_dir();
+        let path = dir.join("test_status_separators.json");
+        let path_str = path.to_str().unwrap().to_string();
+
+        let _ = fs::write(&path_str, "{\"layout\": {\"status_separators\": true, \"status_padding\": 8}}");
+        TEST_CONFIG_PATH.with(|p| *p.borrow_mut() = Some(path_str));
+
+        let original = read_status_separators().unwrap_or(true);
+        write_status_separators(!original);
+        assert_eq!(read_status_separators(), Some(!original));
+        write_status_separators(original);
+        assert_eq!(read_status_separators(), Some(original));
+
+        let _ = fs::remove_file(path);
+    }
+
+    #[test]
+    fn test_read_write_padding() {
+        let dir = std::env::temp_dir();
+        let path = dir.join("test_status_padding.json");
+        let path_str = path.to_str().unwrap().to_string();
+
+        let _ = fs::write(&path_str, "{\"layout\": {\"status_separators\": true, \"status_padding\": 8}}");
+        TEST_CONFIG_PATH.with(|p| *p.borrow_mut() = Some(path_str));
+
+        let original = read_status_padding().unwrap_or(8);
+        write_status_padding(12);
+        assert_eq!(read_status_padding(), Some(12));
+        write_status_padding(original);
+        assert_eq!(read_status_padding(), Some(original));
+
+        let _ = fs::remove_file(path);
+    }
+
+    #[test]
+    fn test_read_write_underline() {
+        let dir = std::env::temp_dir();
+        let path = dir.join("test_status_underline.json");
+        let path_str = path.to_str().unwrap().to_string();
+
+        let _ = fs::write(&path_str, "{\"layout\": {\"status_underline\": true, \"status_padding\": 8}}");
+        TEST_CONFIG_PATH.with(|p| *p.borrow_mut() = Some(path_str));
+
+        let original = read_status_underline().unwrap_or(true);
+        write_status_underline(!original);
+        assert_eq!(read_status_underline(), Some(!original));
+        write_status_underline(original);
+        assert_eq!(read_status_underline(), Some(original));
+
+        let _ = fs::remove_file(path);
+    }
+}
diff --git a/src/pages/services.rs b/src/pages/services.rs
deleted file mode 100644
index 32d1679..0000000
--- a/src/pages/services.rs
+++ /dev/null
@@ -1,894 +0,0 @@
-use std::fs;
-use std::io::Write;
-use crate::app::{AppAction, PageContent, SectionContextExt};
-use cce_ui::layout::{PageLayoutBuilder, LayoutStrategy};
-use cce_ui::widget::{Element, ScrollingList, TextBox, StatusDot, DotStatus, InteractiveListItem, Toggle, Spinbox, Label};
-use crate::pages::interface::parse_u16_from;
-
-// ── Notifications Data and Settings Configuration ──
-
-#[derive(Debug, Clone)]
-pub struct NotificationsConfig {
-    pub enable: bool,
-    pub bell: bool,
-    pub duration: i32,
-}
-
-// ── Status Interface Data ──
-
-#[derive(Debug, Clone)]
-pub struct StatusData {
-    pub font_size: u16,
-    pub padding: u16,
-    pub separators: bool,
-    pub underline: bool,
-    pub running: bool,
-}
-
-// ── Service Types and Page State ──
-
-#[derive(Debug, Clone)]
-pub struct ServiceInfo {
-    pub name: String,
-    pub description: String,
-    pub active_state: String,
-    pub sub_state: String,
-    pub is_system: bool,
-}
-
-#[derive(Debug, Clone, Copy, PartialEq, Eq)]
-pub enum ServiceTab {
-    System,
-    User,
-}
-
-impl Default for ServiceTab {
-    fn default() -> Self {
-        ServiceTab::System
-    }
-}
-
-#[derive(Debug, Clone)]
-pub struct ServicesState {
-    pub loaded: bool,
-    pub services: Vec<ServiceInfo>,
-    pub active_tab: ServiceTab,
-    pub search_box: TextBox,
-    pub list_box: ScrollingList,
-    pub service_items: Vec<InteractiveListItem>,
-    pub notifications_loaded: bool,
-    pub notifications_enable: bool,
-    pub notifications_enable_toggle: Toggle,
-    pub notifications_bell: bool,
-    pub notifications_bell_toggle: Toggle,
-    pub notifications_duration: i32,
-    pub notifications_duration_spinbox: Spinbox,
-
-    // Status Interface fields
-    pub status_loaded: bool,
-    pub status_font_size: u16,
-    pub status_padding: u16,
-    pub status_separators: bool,
-    pub status_underline: bool,
-    pub status_running: bool,
-    pub status_label: Label,
-    pub status_separators_toggle: Toggle,
-    pub status_underline_toggle: Toggle,
-    pub status_padding_spinbox: Spinbox,
-}
-
-impl Default for ServicesState {
-    fn default() -> Self {
-        Self {
-            loaded: false,
-            services: Vec::new(),
-            active_tab: ServiceTab::System,
-            search_box: TextBox::new(String::new()).with_label("Filter Services"),
-            list_box: ScrollingList::new(36.0, 6.0),
-            service_items: Vec::new(),
-            notifications_loaded: false,
-            notifications_enable: true,
-            notifications_enable_toggle: Toggle::new().with_label("Enable Notifications"),
-            notifications_bell: false,
-            notifications_bell_toggle: Toggle::new().with_label("Play Bell Sound"),
-            notifications_duration: 5,
-            notifications_duration_spinbox: Spinbox::new(5, 1, 60, 1)
-                .with_label("Notification Duration")
-                .with_unit("s"),
-
-            // Status Interface default initialization
-            status_loaded: false,
-            status_font_size: 11,
-            status_padding: 8,
-            status_separators: true,
-            status_underline: true,
-            status_running: false,
-            status_label: Label::new("Status Interface: Stopped").with_font_size(14.0).with_color([170, 51, 51]),
-            status_separators_toggle: Toggle::new().with_label("Show Separators"),
-            status_underline_toggle: Toggle::new().with_label("Show Underline"),
-            status_padding_spinbox: Spinbox::new(8, 0, 32, 1).with_label("Side Padding").with_unit("px"),
-        }
-    }
-}
-
-#[derive(Debug, Clone)]
-pub enum ServicesMessage {
-    Refreshed(Vec<ServiceInfo>),
-    SetTab(ServiceTab),
-    Start(String, bool),
-    Stop(String, bool),
-    Restart(String, bool),
-    ToggleNotificationsEnable,
-    ToggleNotificationsBell,
-    SetNotificationsDuration(i32),
-    SendTestNotification,
-    NotificationsRefreshed(NotificationsConfig),
-
-    // Status Interface variants
-    StatusRefreshed(StatusData),
-    StatusToggleSeparators,
-    StatusToggleUnderline,
-    StatusReload,
-    StatusSetPadding(u16),
-}
-
-// ── Background Fetching ──
-
-pub async fn fetch_services() -> Vec<ServiceInfo> {
-    let mut services = Vec::new();
-
-    // 1. Fetch system-level services
-    if let Ok(output) = tokio::process::Command::new("systemctl")
-        .args(["list-units", "--type=service", "--all", "--no-legend"])
-        .output()
-        .await
-    {
-        let stdout = String::from_utf8_lossy(&output.stdout);
-        for line in stdout.lines() {
-            if let Some(info) = parse_service_line(line, true) {
-                services.push(info);
-            }
-        }
-    }
-
-    // 2. Fetch user-level services
-    if let Ok(output) = tokio::process::Command::new("systemctl")
-        .args(["--user", "list-units", "--type=service", "--all", "--no-legend"])
-        .output()
-        .await
-    {
-        let stdout = String::from_utf8_lossy(&output.stdout);
-        for line in stdout.lines() {
-            if let Some(info) = parse_service_line(line, false) {
-                services.push(info);
-            }
-        }
-    }
-
-    // Sort alphabetically by name
-    services.sort_by(|a, b| a.name.to_lowercase().cmp(&b.name.to_lowercase()));
-    services
-}
-
-fn parse_service_line(line: &str, is_system: bool) -> Option<ServiceInfo> {
-    let cleaned = line.trim_start_matches('●').trim();
-    if cleaned.is_empty() {
-        return None;
-    }
-    let parts: Vec<&str> = cleaned.split_whitespace().collect();
-    if parts.len() >= 4 && parts[0].ends_with(".service") {
-        let name = parts[0].to_string();
-        let _load = parts[1];
-        let active_state = parts[2].to_string();
-        let sub_state = parts[3].to_string();
-        let description = parts[4..].join(" ");
-        Some(ServiceInfo {
-            name,
-            description,
-            active_state,
-            sub_state,
-            is_system,
-        })
-    } else {
-        None
-    }
-}
-
-fn service_action(name: &str, action: &str, is_system: bool) {
-    if is_system {
-        // System service needs root privilege, spawn via pkexec
-        let _ = tokio::process::Command::new("pkexec")
-            .args(["systemctl", action, name])
-            .spawn();
-    } else {
-        // User service does not need root
-        let _ = tokio::process::Command::new("systemctl")
-            .args(["--user", action, name])
-            .spawn();
-    }
-}
-
-// ── View & Update ──
-
-const TEXT_DIM: [f32; 4] = [0.53, 0.53, 0.60, 1.0];
-
-pub fn view(state: &mut ServicesState, cx: f32, cy: f32, cw: f32, ch: f32, sec_focused: &[bool], layout: &mut dyn LayoutStrategy, ctx: &mut cce_ui::context::UiContext) -> PageContent {
-    let mut final_pc = PageContent::new();
-    let sec_w = 360.0f32;
-    let mut builder = PageLayoutBuilder::new(layout, cx, cy, cw, ch, sec_w).with_section_count(3);
-
-    builder.add_section_spanned(&mut final_pc, "Services", 2, sec_focused.first().copied().unwrap_or(false), |sec| {
-        let sec_w = sec.cw;
-        if !state.loaded {
-            sec.text("Loading systemd services...", 12.0, 0.0, 12.0, TEXT_DIM);
-            sec.spacing(18.0);
-        } else {
-            // Tab header buttons: System Services, User Services
-            let tab_w = (sec_w - 24.0 - 8.0) / 2.0;
-            let tab_h = 28.0;
-            let tab_y = sec.ay();
-            let active_bg = [0.20, 0.40, 0.65, 0.4];
-            let inactive_bg = [0.10, 0.10, 0.16, 0.3];
-            let hover_bg = [0.20, 0.20, 0.25, 0.15];
-
-            let label1 = if tab_w < 110.0 { "System" } else { "System Services" };
-            let label2 = if tab_w < 110.0 { "User" } else { "User Services" };
-
-            let tab_x1 = sec.left + 12.0;
-            let tab_x2 = sec.left + 12.0 + tab_w + 8.0;
-
-            sec.pc.button(
-                label1,
-                tab_x1,
-                tab_y,
-                tab_w,
-                tab_h,
-                if state.active_tab == ServiceTab::System { active_bg } else { inactive_bg },
-                hover_bg,
-                [0.90, 0.90, 0.95, 1.0],
-                crate::app::AppAction::Services(ServicesMessage::SetTab(ServiceTab::System)),
-            );
-
-            sec.pc.button(
-                label2,
-                tab_x2,
-                tab_y,
-                tab_w,
-                tab_h,
-                if state.active_tab == ServiceTab::User { active_bg } else { inactive_bg },
-                hover_bg,
-                [0.90, 0.90, 0.95, 1.0],
-                crate::app::AppAction::Services(ServicesMessage::SetTab(ServiceTab::User)),
-            );
-            sec.content_y += tab_h + 12.0;
-
-            // Search textbox
-            let search_y = sec.ay();
-            let search_w = sec_w - 24.0;
-            let search_h = 46.0;
-            
-            state.search_box.set_row_rect(sec.left + 12.0, search_w);
-            cce_ui::layout::render_widget(
-                sec.pc,
-                &mut state.search_box,
-                sec.left + 12.0,
-                search_y,
-                search_w,
-                search_h,
-                ctx,
-            );
-            sec.content_y += search_h + 16.0;
-
-            // Scroll box list
-            let list_box_x = sec.left + 12.0;
-            let list_box_y = sec.ay();
-            let list_box_w = sec_w - 24.0;
-            let list_box_h = 360.0;
-            
-            cce_ui::layout::render_widget(sec.pc, &mut state.list_box, list_box_x, list_box_y, list_box_w, list_box_h, ctx);
-
-            // Filter services
-            let query = if state.search_box.editing {
-                state.search_box.edit_buffer.to_lowercase()
-            } else {
-                state.search_box.text.to_lowercase()
-            };
-            let filtered_services: Vec<&ServiceInfo> = state.services.iter()
-                .filter(|s| s.is_system == (state.active_tab == ServiceTab::System))
-                .filter(|s| s.name.to_lowercase().contains(&query) || s.description.to_lowercase().contains(&query))
-                .collect();
-
-            // Update ScrollingList bounds
-            state.list_box.update_bounds(filtered_services.len(), list_box_y, list_box_h);
-
-            let item_h = state.list_box.item_height;
-
-            if state.service_items.len() != filtered_services.len() {
-                state.service_items.clear();
-                for _ in 0..filtered_services.len() {
-                    state.service_items.push(InteractiveListItem::new(""));
-                }
-            }
-
-            for (idx, service) in filtered_services.iter().enumerate() {
-                if let Some(draw_y) = state.list_box.get_item_draw_y(idx, 4.0) {
-                    let is_active = service.active_state == "active" || service.sub_state == "running";
-
-                    // Control buttons: Start, Stop, Restart on the right
-                    let is_small = sec_w < 350.0;
-                    let btn_w = if is_small { 24.0 } else { 46.0 };
-                    let r_btn_w = if is_small { 24.0 } else { 54.0 };
-                    let btn_gap = if is_small { 4.0 } else { 6.0 };
-                    let right_edge = list_box_x + list_box_w - 24.0 - 8.0;
-
-                    let restart_x = right_edge - r_btn_w;
-                    let stop_x = restart_x - btn_gap - btn_w;
-                    let start_x = stop_x - btn_gap - btn_w;
-
-                    let btn_y = draw_y + (item_h - 22.0) / 2.0;
-                    let btn_h = 22.0;
-
-                    // Service Description (Truncate dynamically based on remaining space before Start button)
-                    let text_max_w = (start_x - 8.0) - (list_box_x + 32.0);
-                    let max_chars = ((text_max_w / 6.0) as usize).max(10);
-                    let desc = if service.description.is_empty() { "No description" } else { &service.description };
-                    let desc_truncated = if desc.len() > max_chars {
-                        format!("{}...", &desc[..max_chars.saturating_sub(3)])
-                    } else {
-                        desc.to_string()
-                    };
-
-                    // Render InteractiveListItem background and text labels
-                    let item_btn = &mut state.service_items[idx];
-                    item_btn.title = service.name.clone();
-                    item_btn.subtitle = Some(desc_truncated);
-                    cce_ui::layout::render_widget(sec.pc, item_btn, list_box_x + 24.0, draw_y, list_box_w - 44.0, item_h, ctx);
-
-                    // Render StatusDot
-                    let status_dot_state = if service.active_state == "failed" {
-                        DotStatus::Error
-                    } else if is_active {
-                        DotStatus::Active
-                    } else {
-                        DotStatus::Inactive
-                    };
-                    let mut dot = StatusDot::new(status_dot_state);
-                    cce_ui::layout::render_widget(sec.pc, &mut dot, list_box_x + 10.0, draw_y + (item_h - 10.0) / 2.0, 10.0, 10.0, ctx);
-
-                    let active_txt = [0.90, 0.90, 0.95, 1.0];
-                    let disabled_txt = [0.40, 0.40, 0.45, 1.0];
-
-                    let start_lbl = if is_small { "▶" } else { "Start" };
-                    let stop_lbl = if is_small { "■" } else { "Stop" };
-                    let restart_lbl = if is_small { "⟳" } else { "Restart" };
-
-                    // Start button
-                    sec.pc.button(
-                        start_lbl,
-                        start_x,
-                        btn_y,
-                        btn_w,
-                        btn_h,
-                        if !is_active { [0.16, 0.35, 0.18, 0.4] } else { [0.12, 0.12, 0.16, 0.1] },
-                        [0.22, 0.45, 0.25, 0.6],
-                        if !is_active { active_txt } else { disabled_txt },
-                        crate::app::AppAction::Services(ServicesMessage::Start(service.name.clone(), service.is_system)),
-                    );
-
-                    // Stop button
-                    sec.pc.button(
-                        stop_lbl,
-                        stop_x,
-                        btn_y,
-                        btn_w,
-                        btn_h,
-                        if is_active { [0.55, 0.16, 0.16, 0.3] } else { [0.12, 0.12, 0.16, 0.1] },
-                        [0.70, 0.22, 0.22, 0.5],
-                        if is_active { active_txt } else { disabled_txt },
-                        crate::app::AppAction::Services(ServicesMessage::Stop(service.name.clone(), service.is_system)),
-                    );
-
-                    // Restart button
-                    sec.pc.button(
-                        restart_lbl,
-                        restart_x,
-                        btn_y,
-                        r_btn_w,
-                        btn_h,
-                        [0.15, 0.28, 0.45, 0.3],
-                        [0.20, 0.38, 0.58, 0.5],
-                        active_txt,
-                        crate::app::AppAction::Services(ServicesMessage::Restart(service.name.clone(), service.is_system)),
-                    );
-                }
-            }
-
-            if filtered_services.is_empty() {
-                sec.pc.text("No services match the query", list_box_x + 16.0, list_box_y + 16.0, 12.0, TEXT_DIM);
-            }
-
-            sec.content_y += list_box_h;
-        }
-    });
-
-    // ── System Notifications ──
-    builder.add_section(&mut final_pc, "System Notifications", sec_focused.get(1).copied().unwrap_or(false), |sec2| {
-        let sec_w = sec2.cw;
-        state.notifications_enable_toggle.set_toggled(state.notifications_enable);
-        sec2.widget_full(&mut state.notifications_enable_toggle, cce_ui::layout::toggle_height(), ctx);
-        sec2.spacing(8.0);
-
-        state.notifications_bell_toggle.set_toggled(state.notifications_bell);
-        sec2.widget_full(&mut state.notifications_bell_toggle, cce_ui::layout::toggle_height(), ctx);
-        sec2.spacing(16.0);
-
-        state.notifications_duration_spinbox.value = state.notifications_duration;
-        state.notifications_duration_spinbox.set_label("Notification Duration");
-        sec2.widget(&mut state.notifications_duration_spinbox, 14.0, sec_w - 28.0, 44.0, ctx);
-        sec2.spacing(16.0);
-
-        let btn_h = 32.0;
-        let btn_y = sec2.ay();
-        let white_color = [1.0, 1.0, 1.0, 1.0];
-        let btn_bg = [0.20, 0.40, 0.65, 1.0];
-        let btn_hover = [0.28, 0.50, 0.78, 1.0];
-        
-        let cols = sec2.row_layout(1, 0.0);
-        if let Some(&(x, w)) = cols.first() {
-            sec2.button(
-                "Send Test Notification",
-                x,
-                btn_y,
-                w,
-                btn_h,
-                btn_bg,
-                btn_hover,
-                white_color,
-                AppAction::Services(ServicesMessage::SendTestNotification),
-            );
-        }
-        sec2.spacing(12.0);
-    });
-
-    // ── Status Interface ──
-    builder.add_section(&mut final_pc, "Status Interface", sec_focused.get(2).copied().unwrap_or(false), |sec3| {
-        let sec_w = sec3.cw;
-        if !state.status_loaded {
-            sec3.text("Loading Status Interface status...", 12.0, 0.0, 12.0, TEXT_DIM);
-            sec3.spacing(18.0);
-        } else {
-            // Status
-            let status_text = if state.status_running { "Status Interface: Running" } else { "Status Interface: Stopped" };
-            let status_color = if state.status_running { [92, 143, 97] } else { [170, 51, 51] };
-            state.status_label.set_text(status_text);
-            state.status_label.set_color(status_color);
-            sec3.widget(&mut state.status_label, 12.0, sec_w - 24.0, 20.0, ctx);
-            sec3.spacing(12.0);
-
-            sec3.spacing(4.0);
-
-            // Separators toggle
-            state.status_separators_toggle.set_toggled(state.status_separators);
-            sec3.widget_full(&mut state.status_separators_toggle, cce_ui::layout::toggle_height(), ctx);
-            sec3.spacing(16.0);
-
-            // Underline toggle
-            state.status_underline_toggle.set_toggled(state.status_underline);
-            sec3.widget_full(&mut state.status_underline_toggle, cce_ui::layout::toggle_height(), ctx);
-            sec3.spacing(16.0);
-
-            // Padding spinbox
-            state.status_padding_spinbox.value = state.status_padding as i32;
-            sec3.widget(&mut state.status_padding_spinbox, 12.0, sec_w - 24.0, 44.0, ctx);
-            sec3.spacing(16.0);
-
-            // Reload button
-            let yt_reload = sec3.ay();
-            let btn_w = sec_w - 24.0;
-            let button_x = sec3.left + 12.0;
-            sec3.button(
-                "Reload Status Interface",
-                button_x,
-                yt_reload,
-                btn_w,
-                32.0,
-                [0.13, 0.18, 0.14, 1.0],
-                [0.25, 0.30, 0.26, 1.0],
-                [1.0, 1.0, 1.0, 1.0],
-                AppAction::Services(ServicesMessage::StatusReload),
-            );
-            sec3.spacing(12.0);
-        }
-    });
-
-    final_pc
-}
-
-pub fn update(state: &mut ServicesState, msg: ServicesMessage) {
-    match msg {
-        ServicesMessage::Refreshed(new_services) => {
-            state.loaded = true;
-            state.services = new_services;
-            state.service_items.clear();
-        }
-        ServicesMessage::SetTab(tab) => {
-            state.active_tab = tab;
-            state.list_box.set_scroll_y(0.0);
-            state.service_items.clear();
-        }
-        ServicesMessage::Start(name, is_system) => {
-            if let Some(srv) = state.services.iter_mut().find(|s| s.name == name && s.is_system == is_system) {
-                srv.active_state = "activating".to_string();
-                srv.sub_state = "starting".to_string();
-            }
-            service_action(&name, "start", is_system);
-        }
-        ServicesMessage::Stop(name, is_system) => {
-            if let Some(srv) = state.services.iter_mut().find(|s| s.name == name && s.is_system == is_system) {
-                srv.active_state = "deactivating".to_string();
-                srv.sub_state = "stopping".to_string();
-            }
-            service_action(&name, "stop", is_system);
-        }
-        ServicesMessage::Restart(name, is_system) => {
-            if let Some(srv) = state.services.iter_mut().find(|s| s.name == name && s.is_system == is_system) {
-                srv.active_state = "activating".to_string();
-                srv.sub_state = "restarting".to_string();
-            }
-            service_action(&name, "restart", is_system);
-        }
-        ServicesMessage::ToggleNotificationsEnable => {
-            state.notifications_enable = !state.notifications_enable;
-            write_enable_notifications(state.notifications_enable);
-        }
-        ServicesMessage::ToggleNotificationsBell => {
-            state.notifications_bell = !state.notifications_bell;
-            write_config_value("bell", &state.notifications_bell.to_string());
-        }
-        ServicesMessage::SetNotificationsDuration(d) => {
-            state.notifications_duration = d;
-            write_config_value("duration", &state.notifications_duration.to_string());
-        }
-        ServicesMessage::SendTestNotification => {
-            tokio::spawn(async move {
-                if let Ok(connection) = zbus::Connection::session().await {
-                    let _ = connection.call_method(
-                        Some("org.freedesktop.Notifications"),
-                        "/org/freedesktop/Notifications",
-                        Some("org.freedesktop.Notifications"),
-                        "Notify",
-                        &(
-                            "cce-client",
-                            0u32,
-                            "",
-                            "System notifications are working correctly!",
-                            "",
-                            Vec::<&str>::new(),
-                            std::collections::HashMap::<&str, zbus::zvariant::Value>::new(),
-                            -1i32,
-                        )
-                    ).await;
-                }
-            });
-        }
-        ServicesMessage::NotificationsRefreshed(new) => {
-            state.notifications_loaded = true;
-            state.notifications_enable = new.enable;
-            state.notifications_bell = new.bell;
-            state.notifications_duration = new.duration;
-        }
-        ServicesMessage::StatusRefreshed(new) => {
-            let was_status_hovered = state.status_label.hovered();
-            let was_separators_hovered = state.status_separators_toggle.hovered();
-            let was_underline_hovered = state.status_underline_toggle.hovered();
-
-            state.status_loaded = true;
-            state.status_font_size = new.font_size;
-            state.status_padding = new.padding;
-            state.status_separators = new.separators;
-            state.status_underline = new.underline;
-            state.status_running = new.running;
-
-            state.status_label.set_hovered(was_status_hovered);
-            state.status_separators_toggle.set_hovered(was_separators_hovered);
-            state.status_underline_toggle.set_hovered(was_underline_hovered);
-        }
-
-        ServicesMessage::StatusToggleSeparators => {
-            state.status_separators = !state.status_separators;
-            write_status_separators(state.status_separators);
-            status_interface_reload();
-        }
-        ServicesMessage::StatusToggleUnderline => {
-            state.status_underline = !state.status_underline;
-            write_status_underline(state.status_underline);
-            status_interface_reload();
-        }
-        ServicesMessage::StatusSetPadding(val) => {
-            state.status_padding = val;
-            write_status_padding(val);
-            status_interface_reload();
-        }
-        ServicesMessage::StatusReload => {
-            status_interface_reload();
-        }
-    }
-}
-
-// ── Notifications Configuration Reader & Writer ──
-
-const CONFIG_PATH: &str = "/home/lsgalante/.config/cce/config.json";
-
-fn get_socket_path() -> String {
-    match std::env::var("WAYLAND_DISPLAY") {
-        Ok(display) => format!("/tmp/cce-{}.sock", display),
-        Err(_) => "/tmp/cce.sock".to_string(),
-    }
-}
-
-pub fn read_notifications_config() -> NotificationsConfig {
-    let content = fs::read_to_string(CONFIG_PATH).unwrap_or_default();
-    let enable = parse_notifications_enable(&content);
-    let bell = parse_notifications_bell(&content);
-    let duration = parse_notifications_duration(&content);
-    NotificationsConfig {
-        enable,
-        bell,
-        duration,
-    }
-}
-
-fn parse_json(content: &str) -> serde_json::Value {
-    serde_json::from_str(content).unwrap_or_default()
-}
-
-fn parse_notifications_enable(content: &str) -> bool {
-    let val = parse_json(content);
-    val["notifications"]["enable"].as_bool().unwrap_or(true)
-}
-
-fn parse_notifications_bell(content: &str) -> bool {
-    let val = parse_json(content);
-    val["notifications"]["bell"].as_bool().unwrap_or(false)
-}
-
-fn parse_notifications_duration(content: &str) -> i32 {
-    let val = parse_json(content);
-    val["notifications"]["duration"].as_i64().map(|v| v as i32).unwrap_or(5)
-}
-
-fn send_ipc_command(cmd: &str) {
-    if let Ok(mut stream) = std::os::unix::net::UnixStream::connect(get_socket_path()) {
-        let _ = stream.write_all(format!("{}\n", cmd).as_bytes());
-    }
-}
-
-fn write_config_value(key: &str, value: &str) {
-    let content = fs::read_to_string(CONFIG_PATH).unwrap_or_default();
-    let mut val = parse_json(&content);
-    let j_val = if let Ok(b) = value.parse::<bool>() {
-        serde_json::json!(b)
-    } else if let Ok(n) = value.parse::<i64>() {
-        serde_json::json!(n)
-    } else if let Ok(f) = value.parse::<f64>() {
-        serde_json::json!(f)
-    } else {
-        serde_json::json!(value)
-    };
-    if let Some(notifications) = val.get_mut("notifications").and_then(|n| n.as_object_mut()) {
-        notifications.insert(key.to_string(), j_val);
-    } else {
-        let mut map = serde_json::Map::new();
-        map.insert(key.to_string(), j_val);
-        if let Some(obj) = val.as_object_mut() {
-            obj.insert("notifications".to_string(), serde_json::Value::Object(map));
-        }
-    }
-    if let Ok(updated_str) = serde_json::to_string_pretty(&val) {
-        let _ = fs::write(CONFIG_PATH, updated_str);
-    }
-}
-
-fn write_enable_notifications(enabled: bool) {
-    write_config_value("enable", &enabled.to_string());
-    send_ipc_command("reload");
-}
-
-
-thread_local! {
-    static TEST_CONFIG_PATH: std::cell::RefCell<Option<String>> = std::cell::RefCell::new(None);
-}
-
-fn get_config_path() -> String {
-    #[cfg(test)]
-    {
-        TEST_CONFIG_PATH.with(|p| {
-            if let Some(path) = p.borrow().as_ref() {
-                return path.clone();
-            }
-            "/home/lsgalante/.config/cce/config.json".to_string()
-        })
-    }
-    #[cfg(not(test))]
-    {
-        "/home/lsgalante/.config/cce/config.json".to_string()
-    }
-}
-
-fn write_status_value(key: &str, value: &str) {
-    crate::pages::interface::write_config_value_path(&get_config_path(), key, value);
-}
-
-fn read_status_font_size() -> Option<u16> {
-    let content = std::fs::read_to_string(&get_config_path()).ok()?;
-    Some(parse_u16_from(&content, "status_font_size", 11))
-}
-
-
-fn read_status_padding() -> Option<u16> {
-    let content = std::fs::read_to_string(&get_config_path()).ok()?;
-    Some(parse_u16_from(&content, "status_padding", 8))
-}
-
-fn write_status_padding(padding: u16) {
-    write_status_value("status_padding", &padding.to_string());
-}
-
-fn read_status_separators() -> Option<bool> {
-    let content = std::fs::read_to_string(&get_config_path()).ok()?;
-    Some(crate::pages::interface::parse_bool_from(&content, "status_separators", true))
-}
-
-fn write_status_separators(val: bool) {
-    write_status_value("status_separators", &val.to_string());
-}
-
-fn read_status_underline() -> Option<bool> {
-    let content = std::fs::read_to_string(&get_config_path()).ok()?;
-    Some(crate::pages::interface::parse_bool_from(&content, "status_underline", true))
-}
-
-fn write_status_underline(val: bool) {
-    write_status_value("status_underline", &val.to_string());
-}
-
-fn status_interface_reload() {
-    let _ = std::process::Command::new("pkill")
-        .args(["-f", "cce-status-interface"])
-        .status();
-    std::thread::sleep(std::time::Duration::from_millis(150));
-    send_ipc_command("spawn cce-status-interface");
-}
-
-pub async fn fetch_status_state() -> StatusData {
-    let running = tokio::process::Command::new("pgrep")
-        .args(["-f", "cce-status-interface"]).output().await.ok()
-        .map(|o| !o.stdout.is_empty())
-        .unwrap_or(false);
-
-    let font_size = read_status_font_size().unwrap_or(11);
-    let padding = read_status_padding().unwrap_or(8);
-    let separators = read_status_separators().unwrap_or(true);
-    let underline = read_status_underline().unwrap_or(true);
-
-    StatusData {
-        font_size,
-        padding,
-        separators,
-        underline,
-        running,
-    }
-}
-
-#[cfg(test)]
-mod tests {
-    use super::*;
-
-    #[test]
-    fn test_view_layout_grid() {
-        let mut state = ServicesState::default();
-        let mut layout = cce_ui::layout::ColumnLayout::new(20.0);
-        let sec_focused = vec![false, false];
-        let mut ctx = cce_ui::context::UiContext::new();
-        let pc = view(&mut state, 10.0, 20.0, 800.0, 600.0, &sec_focused, &mut layout, &mut ctx);
-        assert!(!pc.rects.is_empty() || !pc.texts.is_empty());
-    }
-
-    #[test]
-    fn test_parse_notifications_enable_default() {
-        assert!(parse_notifications_enable(""));
-        assert!(parse_notifications_enable("[layout]\ngap = 18\n"));
-    }
-
-    #[test]
-    fn test_parse_notifications_enable_explicit() {
-        let content = "{\"notifications\": {\"enable\": false}}";
-        assert!(!parse_notifications_enable(content));
-
-        let content = "{\"notifications\": {\"enable\": true}}";
-        assert!(parse_notifications_enable(content));
-    }
-
-    #[test]
-    fn test_parse_notifications_enable_other_sections() {
-        let content = r#"{
-            "layout": {"enable": false},
-            "notifications": {"enable": true},
-            "input": {"enable": false}
-        }"#;
-        assert!(parse_notifications_enable(content));
-
-        let content = r#"{
-            "layout": {"enable": true},
-            "notifications": {"enable": false},
-            "input": {"enable": true}
-        }"#;
-        assert!(!parse_notifications_enable(content));
-    }
-
-    #[test]
-    fn test_parse_notifications_duration_default() {
-        assert_eq!(parse_notifications_duration(""), 5);
-        assert_eq!(parse_notifications_duration("{\"notifications\": {}}"), 5);
-    }
-
-    #[test]
-    fn test_parse_notifications_duration_explicit() {
-        let content = "{\"notifications\": {\"duration\": 10}}";
-        assert_eq!(parse_notifications_duration(content), 10);
-    }
-
-    #[test]
-    fn test_read_write_separators() {
-        let dir = std::env::temp_dir();
-        let path = dir.join("test_status_separators.json");
-        let path_str = path.to_str().unwrap().to_string();
-
-        let _ = fs::write(&path_str, "{\"layout\": {\"status_separators\": true, \"status_padding\": 8}}");
-        TEST_CONFIG_PATH.with(|p| *p.borrow_mut() = Some(path_str));
-
-        let original = read_status_separators().unwrap_or(true);
-        write_status_separators(!original);
-        assert_eq!(read_status_separators(), Some(!original));
-        write_status_separators(original);
-        assert_eq!(read_status_separators(), Some(original));
-
-        let _ = fs::remove_file(path);
-    }
-
-    #[test]
-    fn test_read_write_padding() {
-        let dir = std::env::temp_dir();
-        let path = dir.join("test_status_padding.json");
-        let path_str = path.to_str().unwrap().to_string();
-
-        let _ = fs::write(&path_str, "{\"layout\": {\"status_separators\": true, \"status_padding\": 8}}");
-        TEST_CONFIG_PATH.with(|p| *p.borrow_mut() = Some(path_str));
-
-        let original = read_status_padding().unwrap_or(8);
-        write_status_padding(12);
-        assert_eq!(read_status_padding(), Some(12));
-        write_status_padding(original);
-        assert_eq!(read_status_padding(), Some(original));
-
-        let _ = fs::remove_file(path);
-    }
-
-    #[test]
-    fn test_read_write_underline() {
-        let dir = std::env::temp_dir();
-        let path = dir.join("test_status_underline.json");
-        let path_str = path.to_str().unwrap().to_string();
-
-        let _ = fs::write(&path_str, "{\"layout\": {\"status_underline\": true, \"status_padding\": 8}}");
-        TEST_CONFIG_PATH.with(|p| *p.borrow_mut() = Some(path_str));
-
-        let original = read_status_underline().unwrap_or(true);
-        write_status_underline(!original);
-        assert_eq!(read_status_underline(), Some(!original));
-        write_status_underline(original);
-        assert_eq!(read_status_underline(), Some(original));
-
-        let _ = fs::remove_file(path);
-    }
-}
diff --git a/src/renderer.rs b/src/renderer.rs
index 4aa6aaf..61a87b1 100644
--- a/src/renderer.rs
+++ b/src/renderer.rs
@@ -21,7 +21,7 @@ impl SystemInterface {
         self.page_sec_containers.clear();
 
         // Clear all widgets' hierarchy links
-        self.app.services.search_box.clear_children(&mut self.ui_context); self.app.services.search_box.set_parent(None, &mut self.ui_context);
+        self.app.processes.services_search_box.clear_children(&mut self.ui_context); self.app.processes.services_search_box.set_parent(None, &mut self.ui_context);
         self.app.packages.search_box.clear_children(&mut self.ui_context); self.app.packages.search_box.set_parent(None, &mut self.ui_context);
         self.app.packages.installed_list_box.scroll_box.clear_children(&mut self.ui_context); self.app.packages.installed_list_box.scroll_box.set_parent(None, &mut self.ui_context);
         self.app.packages.updates_list_box.scroll_box.clear_children(&mut self.ui_context); self.app.packages.updates_list_box.scroll_box.set_parent(None, &mut self.ui_context);
@@ -32,9 +32,8 @@ impl SystemInterface {
         self.app.accounts.oauth_client_id_box.clear_children(&mut self.ui_context); self.app.accounts.oauth_client_id_box.set_parent(None, &mut self.ui_context);
         self.app.accounts.oauth_client_secret_box.clear_children(&mut self.ui_context); self.app.accounts.oauth_client_secret_box.set_parent(None, &mut self.ui_context);
 
-        self.app.services.list_box.scroll_box.clear_children(&mut self.ui_context); self.app.services.list_box.scroll_box.set_parent(None, &mut self.ui_context);
-
-        self.app.hardware.cpu_list_box.scroll_box.clear_children(&mut self.ui_context); self.app.hardware.cpu_list_box.scroll_box.set_parent(None, &mut self.ui_context);
+        self.app.processes.services_list_box.scroll_box.clear_children(&mut self.ui_context); self.app.processes.services_list_box.scroll_box.set_parent(None, &mut self.ui_context);
+        self.app.processes.cpu_list_box.scroll_box.clear_children(&mut self.ui_context); self.app.processes.cpu_list_box.scroll_box.set_parent(None, &mut self.ui_context);
 
         self.app.network.wifi_list_box.scroll_box.clear_children(&mut self.ui_context); self.app.network.wifi_list_box.scroll_box.set_parent(None, &mut self.ui_context);
 
@@ -156,9 +155,9 @@ impl SystemInterface {
         self.app.interface.terminal_menu.clear_children(&mut self.ui_context); self.app.interface.terminal_menu.set_parent(None, &mut self.ui_context);
         self.app.interface.terminal_box.clear_children(&mut self.ui_context); self.app.interface.terminal_box.set_parent(None, &mut self.ui_context);
 
-        self.app.services.notifications_enable_toggle.clear_children(&mut self.ui_context); self.app.services.notifications_enable_toggle.set_parent(None, &mut self.ui_context);
-        self.app.services.notifications_bell_toggle.clear_children(&mut self.ui_context); self.app.services.notifications_bell_toggle.set_parent(None, &mut self.ui_context);
-        self.app.services.notifications_duration_spinbox.clear_children(&mut self.ui_context); self.app.services.notifications_duration_spinbox.set_parent(None, &mut self.ui_context);
+        self.app.processes.notifications_enable_toggle.clear_children(&mut self.ui_context); self.app.processes.notifications_enable_toggle.set_parent(None, &mut self.ui_context);
+        self.app.processes.notifications_bell_toggle.clear_children(&mut self.ui_context); self.app.processes.notifications_bell_toggle.set_parent(None, &mut self.ui_context);
+        self.app.processes.notifications_duration_spinbox.clear_children(&mut self.ui_context); self.app.processes.notifications_duration_spinbox.set_parent(None, &mut self.ui_context);
 
         self.app.input.rate_spinbox.clear_children(&mut self.ui_context); self.app.input.rate_spinbox.set_parent(None, &mut self.ui_context);
         self.app.input.delay_spinbox.clear_children(&mut self.ui_context); self.app.input.delay_spinbox.set_parent(None, &mut self.ui_context);
@@ -210,9 +209,9 @@ impl SystemInterface {
                 scale_lbl.clear_children(&mut self.ui_context); scale_lbl.set_parent(None, &mut self.ui_context);
             }
         }
-        self.app.services.status_separators_toggle.clear_children(&mut self.ui_context); self.app.services.status_separators_toggle.set_parent(None, &mut self.ui_context);
-        self.app.services.status_underline_toggle.clear_children(&mut self.ui_context); self.app.services.status_underline_toggle.set_parent(None, &mut self.ui_context);
-        self.app.services.status_padding_spinbox.clear_children(&mut self.ui_context); self.app.services.status_padding_spinbox.set_parent(None, &mut self.ui_context);
+        self.app.processes.status_separators_toggle.clear_children(&mut self.ui_context); self.app.processes.status_separators_toggle.set_parent(None, &mut self.ui_context);
+        self.app.processes.status_underline_toggle.clear_children(&mut self.ui_context); self.app.processes.status_underline_toggle.set_parent(None, &mut self.ui_context);
+        self.app.processes.status_padding_spinbox.clear_children(&mut self.ui_context); self.app.processes.status_padding_spinbox.set_parent(None, &mut self.ui_context);
 
         for menu in &mut self.app.interface.windows.tag_layout_menus {
             menu.clear_children(&mut self.ui_context);
@@ -247,30 +246,22 @@ impl SystemInterface {
                 }
             }
 
-            Page::Services => {
-                self.page_sec_containers.resize_with(3, cce_ui::widget::Container::new);
-                for i in 0..3 {
-                    link_parent_child(page_root, &mut self.page_sec_containers[i], &mut self.ui_context);
-                }
-                link_parent_child(&mut self.page_sec_containers[0], &mut self.app.services.search_box, &mut self.ui_context);
-                link_parent_child(&mut self.page_sec_containers[0], &mut self.app.services.list_box.scroll_box, &mut self.ui_context);
-
-                link_parent_child(&mut self.page_sec_containers[1], &mut self.app.services.notifications_enable_toggle, &mut self.ui_context);
-                link_parent_child(&mut self.page_sec_containers[1], &mut self.app.services.notifications_bell_toggle, &mut self.ui_context);
-                link_parent_child(&mut self.page_sec_containers[1], &mut self.app.services.notifications_duration_spinbox, &mut self.ui_context);
-
-                link_parent_child(&mut self.page_sec_containers[2], &mut self.app.services.status_separators_toggle, &mut self.ui_context);
-                link_parent_child(&mut self.page_sec_containers[2], &mut self.app.services.status_underline_toggle, &mut self.ui_context);
-                link_parent_child(&mut self.page_sec_containers[2], &mut self.app.services.status_padding_spinbox, &mut self.ui_context);
-            }
-            Page::Hardware => {
-                self.page_sec_containers.resize_with(5, cce_ui::widget::Container::new);
-                for i in 0..5 {
+            Page::Processes => {
+                self.page_sec_containers.resize_with(8, cce_ui::widget::Container::new);
+                for i in 0..8 {
                     link_parent_child(page_root, &mut self.page_sec_containers[i], &mut self.ui_context);
                 }
-                link_parent_child(&mut self.page_sec_containers[0], &mut self.app.hardware.cpu_list_box.scroll_box, &mut self.ui_context);
-                link_parent_child(&mut self.page_sec_containers[3], &mut self.app.hardware.cpu_gov_menu, &mut self.ui_context);
-                link_parent_child(&mut self.page_sec_containers[4], &mut self.app.hardware.gpu_gov_menu, &mut self.ui_context);
+                link_parent_child(&mut self.page_sec_containers[0], &mut self.app.processes.cpu_list_box.scroll_box, &mut self.ui_context);
+                link_parent_child(&mut self.page_sec_containers[3], &mut self.app.processes.cpu_gov_menu, &mut self.ui_context);
+                link_parent_child(&mut self.page_sec_containers[4], &mut self.app.processes.gpu_gov_menu, &mut self.ui_context);
+                link_parent_child(&mut self.page_sec_containers[5], &mut self.app.processes.services_search_box, &mut self.ui_context);
+                link_parent_child(&mut self.page_sec_containers[5], &mut self.app.processes.services_list_box.scroll_box, &mut self.ui_context);
+                link_parent_child(&mut self.page_sec_containers[6], &mut self.app.processes.notifications_enable_toggle, &mut self.ui_context);
+                link_parent_child(&mut self.page_sec_containers[6], &mut self.app.processes.notifications_bell_toggle, &mut self.ui_context);
+                link_parent_child(&mut self.page_sec_containers[6], &mut self.app.processes.notifications_duration_spinbox, &mut self.ui_context);
+                link_parent_child(&mut self.page_sec_containers[7], &mut self.app.processes.status_separators_toggle, &mut self.ui_context);
+                link_parent_child(&mut self.page_sec_containers[7], &mut self.app.processes.status_underline_toggle, &mut self.ui_context);
+                link_parent_child(&mut self.page_sec_containers[7], &mut self.app.processes.status_padding_spinbox, &mut self.ui_context);
             }
             Page::Radios => {
                 self.page_sec_containers.resize_with(2, cce_ui::widget::Container::new);
@@ -705,18 +696,17 @@ impl SystemInterface {
 
             // Auto-detect if inside a ScrollBox to apply left alignment by default
             if !left_align && base.w >= 60.0 {
-                if self.app.current_page == Page::Hardware {
-                    let sb = &self.app.hardware.cpu_list_box;
-                    let (sb_x, sb_y, sb_w, sb_h) = sb.rect();
-                    if base.x >= sb_x - 1.0 && base.x + base.w <= sb_x + sb_w + 1.0
-                       && base.y >= sb_y - 1.0 && base.y + base.h <= sb_y + sb_h + 1.0 {
+                if self.app.current_page == Page::Processes {
+                    let sb1 = &self.app.processes.cpu_list_box;
+                    let (sb1_x, sb1_y, sb1_w, sb1_h) = sb1.rect();
+                    if base.x >= sb1_x - 1.0 && base.x + base.w <= sb1_x + sb1_w + 1.0
+                       && base.y >= sb1_y - 1.0 && base.y + base.h <= sb1_y + sb1_h + 1.0 {
                         left_align = true;
                     }
-                } else if self.app.current_page == Page::Services {
-                    let sb = &self.app.services.list_box;
-                    let (sb_x, sb_y, sb_w, sb_h) = sb.rect();
-                    if base.x >= sb_x - 1.0 && base.x + base.w <= sb_x + sb_w + 1.0
-                       && base.y >= sb_y - 1.0 && base.y + base.h <= sb_y + sb_h + 1.0 {
+                    let sb2 = &self.app.processes.services_list_box;
+                    let (sb2_x, sb2_y, sb2_w, sb2_h) = sb2.rect();
+                    if base.x >= sb2_x - 1.0 && base.x + base.w <= sb2_x + sb2_w + 1.0
+                       && base.y >= sb2_y - 1.0 && base.y + base.h <= sb2_y + sb2_h + 1.0 {
                         left_align = true;
                     }
                 }
@@ -808,6 +798,7 @@ impl SystemInterface {
         self.text_items = text_items;
         self.page_buttons = page_buttons;
         self.needs_rebuild = false;
+        self.ui_context.clear_dirty();
     }
 
     pub(crate) fn render_page_content(&mut self, cx: f32, cy: f32, cw: f32, ch: f32) -> PageContent {
@@ -829,11 +820,10 @@ impl SystemInterface {
             Page::Audio => audio::view(&mut self.app.audio, cx, cy, cw, ch, &sec_focused, &mut layout, &mut self.ui_context),
             Page::Display => display::view(&mut self.app.display, cx, cy, cw, ch, &mut layout, &mut self.ui_context),
             Page::Radios => network::view(&mut self.app.network, cx, cy, cw, ch, root_focused, &mut layout, &mut self.ui_context),
-            Page::Hardware => hardware::view(&mut self.app.hardware, cx, cy, cw, ch, root_focused, &mut layout, &mut self.ui_context),
+            Page::Processes => processes::view(&mut self.app.processes, cx, cy, cw, ch, root_focused, &sec_focused, &mut layout, &mut self.ui_context),
             Page::Input => input::view(&mut self.app.input, cx, cy, cw, ch, &sec_focused, &mut layout, &mut self.ui_context),
             Page::System => system_info::view(&self.app.system_info, cx, cy, cw, ch, &mut layout, &mut self.ui_context),
             Page::Storage => storage::view(&self.app.storage, cx, cy, cw, ch, &mut layout, &mut self.ui_context),
-            Page::Services => services::view(&mut self.app.services, cx, cy, cw, ch, &sec_focused, &mut layout, &mut self.ui_context),
             Page::Interface => interface::view(&mut self.app.interface, cx, cy, cw, ch, &sec_focused, &mut layout, &mut self.ui_context),
             Page::Packages => packages::view(&mut self.app.packages, cx, cy, cw, ch, &sec_focused, &mut layout, &mut self.ui_context),
         }
diff --git a/src/watchers.rs b/src/watchers.rs
index f4a5067..f038872 100644
--- a/src/watchers.rs
+++ b/src/watchers.rs
@@ -1,7 +1,7 @@
 use std::sync::Arc;
 use std::sync::atomic::{AtomicU8, Ordering};
 use std::sync::mpsc::{channel, Receiver, Sender};
-use crate::pages::{audio, display, network, interface, input, hardware, system_info, services, storage, packages, accounts};
+use crate::pages::{audio, display, network, interface, input, processes, system_info, storage, packages, accounts};
 use cce_ui::widget::Finger;
 
 pub struct Watchers {
@@ -12,13 +12,13 @@ pub struct Watchers {
     pub rx_wm_events: Receiver<()>,
     pub rx_input: Receiver<input::InputState>,
     pub rx_fingers: Receiver<Vec<Finger>>,
-    pub rx_hardware: Receiver<hardware::HardwareState>,
+    pub rx_processes: Receiver<processes::ProcessesState>,
     pub rx_system: Receiver<system_info::SystemState>,
-    pub rx_status: Receiver<services::StatusData>,
+    pub rx_status: Receiver<processes::StatusData>,
     pub rx_storage: Receiver<storage::StorageState>,
-    pub rx_notifications: Receiver<services::NotificationsConfig>,
+    pub rx_notifications: Receiver<processes::NotificationsConfig>,
     pub rx_typeface: Receiver<interface::InterfaceState>,
-    pub rx_services: Receiver<Vec<services::ServiceInfo>>,
+    pub rx_services: Receiver<Vec<processes::ServiceInfo>>,
     pub rx_interface: Receiver<interface::InterfaceState>,
     pub rx_accounts: Receiver<Vec<accounts::AccountInfo>>,
     pub rx_packages: Receiver<packages::PackagesState>,
@@ -76,7 +76,7 @@ pub fn spawn_all(
             let mut last_fetch: Option<std::time::Instant> = None;
             loop {
                 let current_page = current_page_shared.load(Ordering::SeqCst);
-                if current_page == 5 { // Interface is index 5
+                if current_page == 4 { // Interface is index 4
                     let should_fetch = match last_fetch {
                         None => true,
                         Some(t) => t.elapsed() >= std::time::Duration::from_secs(30),
@@ -112,7 +112,7 @@ pub fn spawn_all(
 
             loop {
                 let current_page = current_page_shared.load(Ordering::SeqCst);
-                if current_page == 5 { // Interface is index 5
+                if current_page == 4 { // Interface is index 4
                     let mut changed = false;
                     for p in &[&windows_path, &tags_path, &title_path] {
                         if let Some(mtime) = check_mtime(p) {
@@ -139,7 +139,7 @@ pub fn spawn_all(
             let mut last_fetch: Option<std::time::Instant> = None;
             loop {
                 let current_page = current_page_shared.load(Ordering::SeqCst);
-                if current_page == 4 { // Input is index 4
+                if current_page == 3 { // Input is index 3
                     let should_fetch = match last_fetch {
                         None => true,
                         Some(t) => t.elapsed() >= std::time::Duration::from_secs(30),
@@ -168,13 +168,13 @@ pub fn spawn_all(
             };
             loop {
                 let current_page = current_page_shared.load(Ordering::SeqCst);
-                if current_page == 4 { // Input is index 4
+                if current_page == 3 { // Input is index 3
                     if let Ok(stream) = tokio::net::UnixStream::connect(&socket_path).await {
                         use tokio::io::AsyncBufReadExt;
                         let reader = tokio::io::BufReader::new(stream);
                         let mut lines = reader.lines();
                         while let Ok(Some(line)) = lines.next_line().await {
-                            if current_page_shared.load(Ordering::SeqCst) != 4 {
+                            if current_page_shared.load(Ordering::SeqCst) != 3 {
                                 break;
                             }
                             if let Ok(fingers) = serde_json::from_str::<Vec<Finger>>(&line) {
@@ -191,25 +191,25 @@ pub fn spawn_all(
         rx
     };
 
-    let rx_system = spawn_bg_active(current_page_shared.clone(), 10, 5, || system_info::fetch_system_state());
-    let rx_hardware = spawn_bg_active(current_page_shared.clone(), 3, 3, || hardware::fetch_hardware_state());
-    let rx_status = spawn_bg_active(current_page_shared.clone(), 8, 10, || services::fetch_status_state());
-    let rx_storage = spawn_bg_active(current_page_shared.clone(), 9, 10, || storage::fetch_storage_state());
+    let rx_system = spawn_bg_active(current_page_shared.clone(), 9, 5, || system_info::fetch_system_state());
+    let rx_processes = spawn_bg_active(current_page_shared.clone(), 6, 3, || processes::fetch_processes_state());
+    let rx_status = spawn_bg_active(current_page_shared.clone(), 6, 10, || processes::fetch_status_state());
+    let rx_storage = spawn_bg_active(current_page_shared.clone(), 8, 10, || storage::fetch_storage_state());
 
     let rx_notifications = {
-        let (tx, rx) = channel::<services::NotificationsConfig>();
+        let (tx, rx) = channel::<processes::NotificationsConfig>();
         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 == 8 { // Services is index 8
+                if current_page == 6 { // Processes is index 6
                     let should_fetch = match last_fetch {
                         None => true,
                         Some(t) => t.elapsed() >= std::time::Duration::from_secs(30),
                     };
                     if should_fetch {
-                        let val = tokio::task::spawn_blocking(|| services::read_notifications_config()).await;
+                        let val = tokio::task::spawn_blocking(|| processes::read_notifications_config()).await;
                         if let Ok(val) = val {
                             if tx.send(val).is_err() { break; }
                         }
@@ -222,8 +222,8 @@ pub fn spawn_all(
         rx
     };
 
-    let rx_typeface = spawn_bg_active(current_page_shared.clone(), 5, 30, || interface::fetch_typeface_state());
-    let rx_services = spawn_bg_active(current_page_shared.clone(), 8, 3, || services::fetch_services());
+    let rx_typeface = spawn_bg_active(current_page_shared.clone(), 4, 30, || interface::fetch_typeface_state());
+    let rx_services = spawn_bg_active(current_page_shared.clone(), 6, 3, || processes::fetch_services());
     let rx_accounts = spawn_bg_active(current_page_shared.clone(), 0, 3, || accounts::fetch_accounts());
 
     let rx_interface = {
@@ -233,7 +233,7 @@ pub fn spawn_all(
             let mut last_fetch: Option<std::time::Instant> = None;
             loop {
                 let current_page = current_page_shared.load(Ordering::SeqCst);
-                if current_page == 5 { // Interface is index 5
+                if current_page == 4 { // Interface is index 4
                     let should_fetch = match last_fetch {
                         None => true,
                         Some(t) => t.elapsed() >= std::time::Duration::from_secs(30),
@@ -253,7 +253,7 @@ pub fn spawn_all(
     };
 
     let (tx_backup, rx_backup) = channel();
-    let rx_packages = spawn_bg_active(current_page_shared.clone(), 6, 30, || packages::fetch_packages_state());
+    let rx_packages = spawn_bg_active(current_page_shared.clone(), 5, 30, || packages::fetch_packages_state());
     let (tx_update, rx_update) = channel();
 
     (
@@ -265,7 +265,7 @@ pub fn spawn_all(
             rx_wm_events,
             rx_input,
             rx_fingers,
-            rx_hardware,
+            rx_processes,
             rx_system,
             rx_status,
             rx_storage,