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

commit346766f6fc9f84f11bdffc70fd7b7cad38711cbc
parentd67aa1f0dd
authorLucas Galante <[email protected]>
date2026-06-19 16:08
Move Window Manager page into Windows section in Interface page, remove Layout page

 src/app.rs             |   4 -
 src/main.rs            | 801 +++++++++++++++++++++++--------------------
 src/pages/interface.rs | 896 +++++++++++++++++++++++++++++++++++++++++++++++-
 src/pages/layout.rs    | 910 -------------------------------------------------
 src/pages/mod.rs       |   6 +-
 5 files changed, 1326 insertions(+), 1291 deletions(-)

diff --git a/src/app.rs b/src/app.rs
index 3203e93..0478dd9 100644
--- a/src/app.rs
+++ b/src/app.rs
@@ -3,7 +3,6 @@ use cce_ui::layout::RenderTarget;
 use crate::pages::audio;
 use crate::pages::display;
 use crate::pages::input;
-use crate::pages::layout;
 use crate::pages::network;
 use crate::pages::hardware;
 use crate::pages::system_info;
@@ -19,7 +18,6 @@ pub struct AppState {
     pub audio: audio::AudioState,
     pub display: display::DisplayState,
     pub network: network::NetworkState,
-    pub layout: layout::LayoutState,
     pub input: input::InputState,
     pub hardware: hardware::HardwareState,
     pub system_info: system_info::SystemState,
@@ -37,7 +35,6 @@ impl Default for AppState {
             audio: audio::AudioState::default(),
             display: display::DisplayState::default(),
             network: network::NetworkState::default(),
-            layout: layout::LayoutState::default(),
             input: input::InputState::default(),
             hardware: hardware::HardwareState::default(),
             system_info: system_info::SystemState::default(),
@@ -56,7 +53,6 @@ pub enum AppAction {
     Audio(audio::AudioMessage),
     Display(display::DisplayMessage),
     Radios(network::NetworkMessage),
-    Layout(layout::LayoutMessage),
     Input(input::InputMessage),
     Hardware(hardware::HardwareMessage),
     SystemInfo(system_info::SystemMessage),
diff --git a/src/main.rs b/src/main.rs
index 744a6a1..7b797c6 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -132,7 +132,7 @@ struct SystemInterface {
     rx_audio: std::sync::mpsc::Receiver<pages::audio::AudioState>,
     rx_display: std::sync::mpsc::Receiver<pages::display::DisplayState>,
     rx_network: std::sync::mpsc::Receiver<pages::network::NetworkState>,
-    rx_layout: std::sync::mpsc::Receiver<pages::layout::LayoutState>,
+    rx_layout: std::sync::mpsc::Receiver<pages::interface::WindowsState>,
     rx_wm_events: std::sync::mpsc::Receiver<()>,
     rx_input: std::sync::mpsc::Receiver<pages::input::InputState>,
     rx_fingers: std::sync::mpsc::Receiver<Vec<Finger>>,
@@ -180,7 +180,6 @@ impl cce_ui::engine::Application for SystemInterface {
     fn new(_qh: &wayland_client::QueueHandle<cce_ui::engine::EngineState<Self>>, sender: calloop::channel::Sender<Self::Message>) -> Self {
         cce_ui::scale::set_scale_factor(1.0);
         let app = AppState {
-            layout: pages::layout::read_layout_config(),
             input: pages::input::read_input_config(),
             interface: pages::interface::read_interface_config(),
             ..Default::default()
@@ -226,19 +225,19 @@ impl cce_ui::engine::Application for SystemInterface {
         let rx_display = spawn_bg_active(current_page_shared.clone(), 2, 10, || pages::display::fetch_display_state());
         let rx_network = spawn_bg_active(current_page_shared.clone(), 7, 5, || pages::network::fetch_network_state());
         let rx_layout = {
-            let (tx, rx) = std::sync::mpsc::channel::<pages::layout::LayoutState>();
+            let (tx, rx) = std::sync::mpsc::channel::<pages::interface::WindowsState>();
             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(std::sync::atomic::Ordering::SeqCst);
-                    if current_page == 11 { // Layout is index 11
+                    if current_page == 5 { // Interface is index 5
                         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(|| pages::layout::read_layout_config()).await;
+                            let val = tokio::task::spawn_blocking(|| pages::interface::read_windows_config()).await;
                             if let Ok(val) = val {
                                 if tx.send(val).is_err() { break; }
                             }
@@ -267,7 +266,7 @@ impl cce_ui::engine::Application for SystemInterface {
 
                 loop {
                     let current_page = current_page_shared.load(std::sync::atomic::Ordering::SeqCst);
-                    if current_page == 11 { // Layout is index 11
+                    if current_page == 5 { // Interface is index 5
                         let mut changed = false;
                         for p in &[&windows_path, &tags_path, &title_path] {
                             if let Some(mtime) = check_mtime(p) {
@@ -682,16 +681,16 @@ fn collect_popover_rects(w: &dyn cce_ui::widget::Element, popovers: &mut Vec<(f3
 
         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);
 
-        for sb in &mut self.app.layout.spinboxes {
+        for sb in &mut self.app.interface.windows.spinboxes {
             sb.clear_children(&mut self.ui_context);
             sb.set_parent(None, &mut self.ui_context);
         }
-        self.app.layout.cascade_offset_spinbox.clear_children(&mut self.ui_context); self.app.layout.cascade_offset_spinbox.set_parent(None, &mut self.ui_context);
-        self.app.layout.edge_gap_spinbox.clear_children(&mut self.ui_context); self.app.layout.edge_gap_spinbox.set_parent(None, &mut self.ui_context);
-        self.app.layout.top_gap_spinbox.clear_children(&mut self.ui_context); self.app.layout.top_gap_spinbox.set_parent(None, &mut self.ui_context);
-        self.app.layout.grid_gap_spinbox.clear_children(&mut self.ui_context); self.app.layout.grid_gap_spinbox.set_parent(None, &mut self.ui_context);
-        self.app.layout.transition_duration_spinbox.clear_children(&mut self.ui_context); self.app.layout.transition_duration_spinbox.set_parent(None, &mut self.ui_context);
-        self.app.layout.status_height_spinbox.clear_children(&mut self.ui_context); self.app.layout.status_height_spinbox.set_parent(None, &mut self.ui_context);
+        self.app.interface.windows.cascade_offset_spinbox.clear_children(&mut self.ui_context); self.app.interface.windows.cascade_offset_spinbox.set_parent(None, &mut self.ui_context);
+        self.app.interface.windows.edge_gap_spinbox.clear_children(&mut self.ui_context); self.app.interface.windows.edge_gap_spinbox.set_parent(None, &mut self.ui_context);
+        self.app.interface.windows.top_gap_spinbox.clear_children(&mut self.ui_context); self.app.interface.windows.top_gap_spinbox.set_parent(None, &mut self.ui_context);
+        self.app.interface.windows.grid_gap_spinbox.clear_children(&mut self.ui_context); self.app.interface.windows.grid_gap_spinbox.set_parent(None, &mut self.ui_context);
+        self.app.interface.windows.transition_duration_spinbox.clear_children(&mut self.ui_context); self.app.interface.windows.transition_duration_spinbox.set_parent(None, &mut self.ui_context);
+        self.app.interface.windows.status_height_spinbox.clear_children(&mut self.ui_context); self.app.interface.windows.status_height_spinbox.set_parent(None, &mut self.ui_context);
 
         for cs in &mut self.app.interface.color_selectors {
             cs.clear_children(&mut self.ui_context);
@@ -862,20 +861,20 @@ fn collect_popover_rects(w: &dyn cce_ui::widget::Element, popovers: &mut Vec<(f3
         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);
 
-        for menu in &mut self.app.layout.tag_layout_menus {
+        for menu in &mut self.app.interface.windows.tag_layout_menus {
             menu.clear_children(&mut self.ui_context);
             menu.set_parent(None, &mut self.ui_context);
         }
-        self.app.layout.side_panel_behavior_menu.clear_children(&mut self.ui_context);
-        self.app.layout.side_panel_behavior_menu.set_parent(None, &mut self.ui_context);
-        self.app.layout.side_panel_position_menu.clear_children(&mut self.ui_context);
-        self.app.layout.side_panel_position_menu.set_parent(None, &mut self.ui_context);
-        self.app.layout.side_panel_width_spinbox.clear_children(&mut self.ui_context);
-        self.app.layout.side_panel_width_spinbox.set_parent(None, &mut self.ui_context);
-        self.app.layout.side_panel_border_gap_spinbox.clear_children(&mut self.ui_context);
-        self.app.layout.side_panel_border_gap_spinbox.set_parent(None, &mut self.ui_context);
-        self.app.layout.side_panel_border_opacity_spinbox.clear_children(&mut self.ui_context);
-        self.app.layout.side_panel_border_opacity_spinbox.set_parent(None, &mut self.ui_context);
+        self.app.interface.windows.side_panel_behavior_menu.clear_children(&mut self.ui_context);
+        self.app.interface.windows.side_panel_behavior_menu.set_parent(None, &mut self.ui_context);
+        self.app.interface.windows.side_panel_position_menu.clear_children(&mut self.ui_context);
+        self.app.interface.windows.side_panel_position_menu.set_parent(None, &mut self.ui_context);
+        self.app.interface.windows.side_panel_width_spinbox.clear_children(&mut self.ui_context);
+        self.app.interface.windows.side_panel_width_spinbox.set_parent(None, &mut self.ui_context);
+        self.app.interface.windows.side_panel_border_gap_spinbox.clear_children(&mut self.ui_context);
+        self.app.interface.windows.side_panel_border_gap_spinbox.set_parent(None, &mut self.ui_context);
+        self.app.interface.windows.side_panel_border_opacity_spinbox.clear_children(&mut self.ui_context);
+        self.app.interface.windows.side_panel_border_opacity_spinbox.set_parent(None, &mut self.ui_context);
 
         use cce_ui::widget::focus::link_parent_child;
         match self.app.current_page {
@@ -927,47 +926,10 @@ fn collect_popover_rects(w: &dyn cce_ui::widget::Element, popovers: &mut Vec<(f3
                 }
                 link_parent_child(&mut self.page_sec_containers[0], &mut self.app.network.wifi_list_box.scroll_box, &mut self.ui_context);
             }
-            Page::Layout => {
-                self.page_sec_containers.resize_with(7, cce_ui::widget::Container::new);
-                
-                for i in 0..7 {
-                    link_parent_child(page_root, &mut self.page_sec_containers[i], &mut self.ui_context);
-                }
-                
-                // Fullscreen (Section 0)
-                link_parent_child(&mut self.page_sec_containers[0], &mut self.app.layout.spinboxes[0], &mut self.ui_context);
-                
-                // Cascade (Section 1)
-                link_parent_child(&mut self.page_sec_containers[1], &mut self.app.layout.spinboxes[1], &mut self.ui_context);
-                link_parent_child(&mut self.page_sec_containers[1], &mut self.app.layout.cascade_offset_spinbox, &mut self.ui_context);
-                link_parent_child(&mut self.page_sec_containers[1], &mut self.app.layout.edge_gap_spinbox, &mut self.ui_context);
-                link_parent_child(&mut self.page_sec_containers[1], &mut self.app.layout.top_gap_spinbox, &mut self.ui_context);
-                
-                // Grid (Section 2)
-                link_parent_child(&mut self.page_sec_containers[2], &mut self.app.layout.grid_gap_spinbox, &mut self.ui_context);
-                
-                // Floating (Section 3)
-                link_parent_child(&mut self.page_sec_containers[3], &mut self.app.layout.spinboxes[3], &mut self.ui_context);
-                
-                // Movement (Section 4)
-                link_parent_child(&mut self.page_sec_containers[4], &mut self.app.layout.transition_duration_spinbox, &mut self.ui_context);
-                
-                // Default Layouts (Section 5)
-                for menu in &mut self.app.layout.tag_layout_menus {
-                    link_parent_child(&mut self.page_sec_containers[5], menu, &mut self.ui_context);
-                }
-
-                // Side Panel (Section 6)
-                link_parent_child(&mut self.page_sec_containers[6], &mut self.app.layout.side_panel_behavior_menu, &mut self.ui_context);
-                link_parent_child(&mut self.page_sec_containers[6], &mut self.app.layout.side_panel_position_menu, &mut self.ui_context);
-                link_parent_child(&mut self.page_sec_containers[6], &mut self.app.layout.side_panel_width_spinbox, &mut self.ui_context);
-                link_parent_child(&mut self.page_sec_containers[6], &mut self.app.layout.side_panel_border_gap_spinbox, &mut self.ui_context);
-                link_parent_child(&mut self.page_sec_containers[6], &mut self.app.layout.side_panel_border_opacity_spinbox, &mut self.ui_context);
-            }
             Page::Interface => {
-                self.page_sec_containers.resize_with(9, cce_ui::widget::Container::new);
+                self.page_sec_containers.resize_with(10, cce_ui::widget::Container::new);
                 
-                for i in 0..9 {
+                for i in 0..10 {
                     link_parent_child(page_root, &mut self.page_sec_containers[i], &mut self.ui_context);
                 }
                 
@@ -1099,6 +1061,41 @@ fn collect_popover_rects(w: &dyn cce_ui::widget::Element, popovers: &mut Vec<(f3
                 link_parent_child(&mut self.page_sec_containers[8], &mut self.app.interface.graph_cell_opacity_spinbox, &mut self.ui_context);
                 link_parent_child(&mut self.page_sec_containers[8], &mut self.app.interface.graph_gap_opacity_spinbox, &mut self.ui_context);
                 link_parent_child(&mut self.page_sec_containers[8], &mut self.app.interface.graph_gap_width_spinbox, &mut self.ui_context);
+
+                // Section 9: Windows (parent of Fullscreen, Cascade, Grid, Floating, Movement, Default Layouts, Side Panel, Effects)
+                // Fullscreen
+                link_parent_child(&mut self.page_sec_containers[9], &mut self.app.interface.windows.spinboxes[0], &mut self.ui_context);
+                
+                // Cascade
+                link_parent_child(&mut self.page_sec_containers[9], &mut self.app.interface.windows.spinboxes[1], &mut self.ui_context);
+                link_parent_child(&mut self.page_sec_containers[9], &mut self.app.interface.windows.cascade_offset_spinbox, &mut self.ui_context);
+                link_parent_child(&mut self.page_sec_containers[9], &mut self.app.interface.windows.edge_gap_spinbox, &mut self.ui_context);
+                link_parent_child(&mut self.page_sec_containers[9], &mut self.app.interface.windows.top_gap_spinbox, &mut self.ui_context);
+                
+                // Grid
+                link_parent_child(&mut self.page_sec_containers[9], &mut self.app.interface.windows.grid_gap_spinbox, &mut self.ui_context);
+                
+                // Floating
+                link_parent_child(&mut self.page_sec_containers[9], &mut self.app.interface.windows.spinboxes[3], &mut self.ui_context);
+                
+                // Movement
+                link_parent_child(&mut self.page_sec_containers[9], &mut self.app.interface.windows.transition_duration_spinbox, &mut self.ui_context);
+                
+                // Default Layouts
+                for menu in &mut self.app.interface.windows.tag_layout_menus {
+                    link_parent_child(&mut self.page_sec_containers[9], menu, &mut self.ui_context);
+                }
+
+                // Side Panel
+                link_parent_child(&mut self.page_sec_containers[9], &mut self.app.interface.windows.side_panel_behavior_menu, &mut self.ui_context);
+                link_parent_child(&mut self.page_sec_containers[9], &mut self.app.interface.windows.side_panel_position_menu, &mut self.ui_context);
+                link_parent_child(&mut self.page_sec_containers[9], &mut self.app.interface.windows.side_panel_width_spinbox, &mut self.ui_context);
+                link_parent_child(&mut self.page_sec_containers[9], &mut self.app.interface.windows.side_panel_border_gap_spinbox, &mut self.ui_context);
+                link_parent_child(&mut self.page_sec_containers[9], &mut self.app.interface.windows.side_panel_border_opacity_spinbox, &mut self.ui_context);
+
+                // Effects
+                link_parent_child(&mut self.page_sec_containers[9], &mut self.app.interface.windows.transparency_toggle, &mut self.ui_context);
+                link_parent_child(&mut self.page_sec_containers[9], &mut self.app.interface.windows.blur_toggle, &mut self.ui_context);
             }
 
 
@@ -1479,7 +1476,6 @@ fn collect_popover_rects(w: &dyn cce_ui::widget::Element, popovers: &mut Vec<(f3
             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::Layout => layout::view(&mut self.app.layout, cx, cy, cw, ch, &sec_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::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),
@@ -1604,13 +1600,13 @@ fn collect_popover_rects(w: &dyn cce_ui::widget::Element, popovers: &mut Vec<(f3
             }
         }
         while let Ok(s) = self.rx_layout.try_recv() {
-            layout::update(&mut self.app.layout, layout::LayoutMessage::Refreshed(s));
-            if self.app.current_page == Page::Layout {
+            interface::update_windows(&mut self.app.interface.windows, interface::WindowsMessage::Refreshed(s));
+            if self.app.current_page == Page::Interface {
                 self.needs_rebuild = true;
             }
         }
         while let Ok(_) = self.rx_wm_events.try_recv() {
-            if self.app.current_page == Page::Layout {
+            if self.app.current_page == Page::Interface {
                 self.needs_rebuild = true;
             }
         }
@@ -1714,7 +1710,6 @@ fn collect_popover_rects(w: &dyn cce_ui::widget::Element, popovers: &mut Vec<(f3
             AppAction::Audio(m) => audio::update(&mut self.app.audio, m.clone()),
             AppAction::Display(m) => display::update(&mut self.app.display, m.clone()),
             AppAction::Radios(m) => network::update(&mut self.app.network, m.clone()),
-            AppAction::Layout(m) => layout::update(&mut self.app.layout, 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()),
@@ -1845,57 +1840,7 @@ fn collect_popover_rects(w: &dyn cce_ui::widget::Element, popovers: &mut Vec<(f3
                 changed = true;
             }
         }
-        if self.app.current_page == Page::Layout {
-            for sb in &mut self.app.layout.spinboxes {
-                if sb.cursor_moved(lx, ly, &mut self.ui_context) {
-                    changed = true;
-                }
-            }
-            if self.app.layout.cascade_offset_spinbox.cursor_moved(lx, ly, &mut self.ui_context) {
-                changed = true;
-            }
-            if self.app.layout.edge_gap_spinbox.cursor_moved(lx, ly, &mut self.ui_context) {
-                changed = true;
-            }
-            if self.app.layout.top_gap_spinbox.cursor_moved(lx, ly, &mut self.ui_context) {
-                changed = true;
-            }
-            if self.app.layout.grid_gap_spinbox.cursor_moved(lx, ly, &mut self.ui_context) {
-                changed = true;
-            }
-            if self.app.layout.transition_duration_spinbox.cursor_moved(lx, ly, &mut self.ui_context) {
-                changed = true;
-            }
-            if self.app.layout.status_height_spinbox.cursor_moved(lx, ly, &mut self.ui_context) {
-                changed = true;
-            }
-            for menu in &mut self.app.layout.tag_layout_menus {
-                if menu.cursor_moved(lx, ly, &mut self.ui_context) {
-                    changed = true;
-                }
-            }
-            if self.app.layout.side_panel_behavior_menu.cursor_moved(lx, ly, &mut self.ui_context) {
-                changed = true;
-            }
-            if self.app.layout.side_panel_position_menu.cursor_moved(lx, ly, &mut self.ui_context) {
-                changed = true;
-            }
-            if self.app.layout.side_panel_width_spinbox.cursor_moved(lx, ly, &mut self.ui_context) {
-                changed = true;
-            }
-            if self.app.layout.side_panel_border_gap_spinbox.cursor_moved(lx, ly, &mut self.ui_context) {
-                changed = true;
-            }
-            if self.app.layout.side_panel_border_opacity_spinbox.cursor_moved(lx, ly, &mut self.ui_context) {
-                changed = true;
-            }
-            if self.app.layout.transparency_toggle.cursor_moved(lx, ly, &mut self.ui_context) {
-                changed = true;
-            }
-            if self.app.layout.blur_toggle.cursor_moved(lx, ly, &mut self.ui_context) {
-                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) {
@@ -2087,6 +2032,55 @@ fn collect_popover_rects(w: &dyn cce_ui::widget::Element, popovers: &mut Vec<(f3
             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) {
@@ -2492,27 +2486,7 @@ fn collect_popover_rects(w: &dyn cce_ui::widget::Element, popovers: &mut Vec<(f3
                         if accs.smtp_box.hit_test(lx, ly, &self.ui_context) { clicked_any_focusable = true; }
                     }
                 }
-                Page::Layout => {
-                    for sb in &mut self.app.layout.spinboxes {
-                        if sb.hit_test(lx, ly, &self.ui_context) { clicked_any_focusable = true; }
-                    }
-                    if self.app.layout.cascade_offset_spinbox.hit_test(lx, ly, &self.ui_context) { clicked_any_focusable = true; }
-                    if self.app.layout.edge_gap_spinbox.hit_test(lx, ly, &self.ui_context) { clicked_any_focusable = true; }
-                    if self.app.layout.top_gap_spinbox.hit_test(lx, ly, &self.ui_context) { clicked_any_focusable = true; }
-                    if self.app.layout.grid_gap_spinbox.hit_test(lx, ly, &self.ui_context) { clicked_any_focusable = true; }
-                    if self.app.layout.transition_duration_spinbox.hit_test(lx, ly, &self.ui_context) { clicked_any_focusable = true; }
-                    if self.app.layout.status_height_spinbox.hit_test(lx, ly, &self.ui_context) { clicked_any_focusable = true; }
-                    for menu in &mut self.app.layout.tag_layout_menus {
-                        if menu.hit_test(lx, ly, &self.ui_context) { clicked_any_focusable = true; }
-                    }
-                    if self.app.layout.side_panel_behavior_menu.hit_test(lx, ly, &self.ui_context) { clicked_any_focusable = true; }
-                    if self.app.layout.side_panel_position_menu.hit_test(lx, ly, &self.ui_context) { clicked_any_focusable = true; }
-                    if self.app.layout.side_panel_width_spinbox.hit_test(lx, ly, &self.ui_context) { clicked_any_focusable = true; }
-                    if self.app.layout.side_panel_border_gap_spinbox.hit_test(lx, ly, &self.ui_context) { clicked_any_focusable = true; }
-                    if self.app.layout.side_panel_border_opacity_spinbox.hit_test(lx, ly, &self.ui_context) { clicked_any_focusable = true; }
-                    if self.app.layout.transparency_toggle.hit_test(lx, ly, &self.ui_context) { clicked_any_focusable = true; }
-                    if self.app.layout.blur_toggle.hit_test(lx, ly, &self.ui_context) { clicked_any_focusable = true; }
-                }
+
                 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 {
@@ -2577,6 +2551,25 @@ fn collect_popover_rects(w: &dyn cce_ui::widget::Element, popovers: &mut Vec<(f3
                     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; }
+                    }
+                    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; }
@@ -2657,127 +2650,169 @@ fn collect_popover_rects(w: &dyn cce_ui::widget::Element, popovers: &mut Vec<(f3
             }
         }
 
-        if state == cce_ui::widget::ElementState::Pressed && self.app.current_page == Page::Layout {
-            for (i, sb) in self.app.layout.spinboxes.iter_mut().enumerate() {
+        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::Layout(
-                        pages::layout::LayoutMessage::SetWidth(
-                            pages::layout::WidthParam::ALL[i],
-                            sb.value as u16,
+                    actions.push(AppAction::Interface(
+                        pages::interface::InterfaceMessage::Windows(
+                            pages::interface::WindowsMessage::SetWidth(
+                                pages::interface::WidthParam::ALL[i],
+                                sb.value as u16,
+                            )
                         )
                     ));
                 }
             }
-            let sb = &mut self.app.layout.cascade_offset_spinbox;
+            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::Layout(
-                    pages::layout::LayoutMessage::SetCascadeOffset(sb.value as u16)
+                actions.push(AppAction::Interface(
+                    pages::interface::InterfaceMessage::Windows(
+                        pages::interface::WindowsMessage::SetCascadeOffset(sb.value as u16)
+                    )
                 ));
             }
-            let sb = &mut self.app.layout.edge_gap_spinbox;
+            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::Layout(
-                    pages::layout::LayoutMessage::SetEdgeGap(sb.value as u16)
+                actions.push(AppAction::Interface(
+                    pages::interface::InterfaceMessage::Windows(
+                        pages::interface::WindowsMessage::SetEdgeGap(sb.value as u16)
+                    )
                 ));
             }
-            let sb = &mut self.app.layout.top_gap_spinbox;
+            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::Layout(
-                    pages::layout::LayoutMessage::SetTopGap(sb.value as u16)
+                actions.push(AppAction::Interface(
+                    pages::interface::InterfaceMessage::Windows(
+                        pages::interface::WindowsMessage::SetTopGap(sb.value as u16)
+                    )
                 ));
             }
-            let sb = &mut self.app.layout.grid_gap_spinbox;
+            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::Layout(
-                    pages::layout::LayoutMessage::SetGridGap(sb.value as u16)
+                actions.push(AppAction::Interface(
+                    pages::interface::InterfaceMessage::Windows(
+                        pages::interface::WindowsMessage::SetGridGap(sb.value as u16)
+                    )
                 ));
             }
-            let sb = &mut self.app.layout.transition_duration_spinbox;
+            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::Layout(
-                    pages::layout::LayoutMessage::SetTransitionDuration(sb.value as u16)
+                actions.push(AppAction::Interface(
+                    pages::interface::InterfaceMessage::Windows(
+                        pages::interface::WindowsMessage::SetTransitionDuration(sb.value as u16)
+                    )
                 ));
             }
-            let sb = &mut self.app.layout.status_height_spinbox;
+            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::Layout(
-                    pages::layout::LayoutMessage::SetStatusHeight(sb.value as u16)
+                actions.push(AppAction::Interface(
+                    pages::interface::InterfaceMessage::Windows(
+                        pages::interface::WindowsMessage::SetStatusHeight(sb.value as u16)
+                    )
                 ));
             }
         }
-        if self.app.current_page == Page::Layout {
-            for (idx, menu) in self.app.layout.tag_layout_menus.iter_mut().enumerate() {
+        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::Layout(pages::layout::LayoutMessage::SetTagLayout(idx + 1, menu.selected)));
+                    actions.push(AppAction::Interface(
+                        pages::interface::InterfaceMessage::Windows(
+                            pages::interface::WindowsMessage::SetTagLayout(idx + 1, menu.selected)
+                        )
+                    ));
                 }
             }
-            let menu = &mut self.app.layout.side_panel_behavior_menu;
+            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::Layout(pages::layout::LayoutMessage::SetSidePanelBehavior(menu.selected)));
+                actions.push(AppAction::Interface(
+                    pages::interface::InterfaceMessage::Windows(
+                        pages::interface::WindowsMessage::SetSidePanelBehavior(menu.selected)
+                    )
+                ));
             }
-            let menu = &mut self.app.layout.side_panel_position_menu;
+            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::Layout(pages::layout::LayoutMessage::SetSidePanelPosition(menu.selected)));
+                actions.push(AppAction::Interface(
+                    pages::interface::InterfaceMessage::Windows(
+                        pages::interface::WindowsMessage::SetSidePanelPosition(menu.selected)
+                    )
+                ));
             }
-            let sb = &mut self.app.layout.side_panel_width_spinbox;
+            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::Layout(
-                    pages::layout::LayoutMessage::SetSidePanelWidth(sb.value as u16)
+                actions.push(AppAction::Interface(
+                    pages::interface::InterfaceMessage::Windows(
+                        pages::interface::WindowsMessage::SetSidePanelWidth(sb.value as u16)
+                    )
                 ));
             }
-            let sb = &mut self.app.layout.side_panel_border_gap_spinbox;
+            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::Layout(
-                    pages::layout::LayoutMessage::SetSidePanelBorderGap(sb.value as u16)
+                actions.push(AppAction::Interface(
+                    pages::interface::InterfaceMessage::Windows(
+                        pages::interface::WindowsMessage::SetSidePanelBorderGap(sb.value as u16)
+                    )
                 ));
             }
-            let sb = &mut self.app.layout.side_panel_border_opacity_spinbox;
+            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::Layout(
-                    pages::layout::LayoutMessage::SetSidePanelBorderOpacity(sb.value as u16)
+                actions.push(AppAction::Interface(
+                    pages::interface::InterfaceMessage::Windows(
+                        pages::interface::WindowsMessage::SetSidePanelBorderOpacity(sb.value as u16)
+                    )
                 ));
             }
-            let toggle = &mut self.app.layout.transparency_toggle;
+            let toggle = &mut tf.transparency_toggle;
             toggle.mouse_input(button, state, lx, ly, &mut self.ui_context);
             if toggle.take_click() {
-                actions.push(AppAction::Layout(pages::layout::LayoutMessage::ToggleTransparency));
+                actions.push(AppAction::Interface(
+                    pages::interface::InterfaceMessage::Windows(
+                        pages::interface::WindowsMessage::ToggleTransparency
+                    )
+                ));
             }
-            let toggle2 = &mut self.app.layout.blur_toggle;
+            let toggle2 = &mut tf.blur_toggle;
             toggle2.mouse_input(button, state, lx, ly, &mut self.ui_context);
             if toggle2.take_click() {
-                actions.push(AppAction::Layout(pages::layout::LayoutMessage::ToggleBlur));
+                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 {
@@ -3752,51 +3787,6 @@ fn collect_popover_rects(w: &dyn cce_ui::widget::Element, popovers: &mut Vec<(f3
 
     fn propagate_widget_changes(&mut self, actions: &mut Vec<AppAction>) {
         match self.app.current_page {
-            Page::Layout => {
-                for (i, sb) in self.app.layout.spinboxes.iter_mut().enumerate() {
-                    if sb.take_change() {
-                        actions.push(AppAction::Layout(pages::layout::LayoutMessage::SetWidth(pages::layout::WidthParam::ALL[i], sb.value as u16)));
-                    }
-                }
-                if self.app.layout.cascade_offset_spinbox.take_change() {
-                    actions.push(AppAction::Layout(pages::layout::LayoutMessage::SetCascadeOffset(self.app.layout.cascade_offset_spinbox.value as u16)));
-                }
-                if self.app.layout.edge_gap_spinbox.take_change() {
-                    actions.push(AppAction::Layout(pages::layout::LayoutMessage::SetEdgeGap(self.app.layout.edge_gap_spinbox.value as u16)));
-                }
-                if self.app.layout.top_gap_spinbox.take_change() {
-                    actions.push(AppAction::Layout(pages::layout::LayoutMessage::SetTopGap(self.app.layout.top_gap_spinbox.value as u16)));
-                }
-                if self.app.layout.grid_gap_spinbox.take_change() {
-                    actions.push(AppAction::Layout(pages::layout::LayoutMessage::SetGridGap(self.app.layout.grid_gap_spinbox.value as u16)));
-                }
-                if self.app.layout.transition_duration_spinbox.take_change() {
-                    actions.push(AppAction::Layout(pages::layout::LayoutMessage::SetTransitionDuration(self.app.layout.transition_duration_spinbox.value as u16)));
-                }
-                if self.app.layout.status_height_spinbox.take_change() {
-                    actions.push(AppAction::Layout(pages::layout::LayoutMessage::SetStatusHeight(self.app.layout.status_height_spinbox.value as u16)));
-                }
-                for (idx, menu) in self.app.layout.tag_layout_menus.iter_mut().enumerate() {
-                    if menu.take_change() {
-                        actions.push(AppAction::Layout(pages::layout::LayoutMessage::SetTagLayout(idx + 1, menu.selected)));
-                    }
-                }
-                if self.app.layout.side_panel_behavior_menu.take_change() {
-                    actions.push(AppAction::Layout(pages::layout::LayoutMessage::SetSidePanelBehavior(self.app.layout.side_panel_behavior_menu.selected)));
-                }
-                if self.app.layout.side_panel_position_menu.take_change() {
-                    actions.push(AppAction::Layout(pages::layout::LayoutMessage::SetSidePanelPosition(self.app.layout.side_panel_position_menu.selected)));
-                }
-                if self.app.layout.side_panel_width_spinbox.take_change() {
-                    actions.push(AppAction::Layout(pages::layout::LayoutMessage::SetSidePanelWidth(self.app.layout.side_panel_width_spinbox.value as u16)));
-                }
-                if self.app.layout.side_panel_border_gap_spinbox.take_change() {
-                    actions.push(AppAction::Layout(pages::layout::LayoutMessage::SetSidePanelBorderGap(self.app.layout.side_panel_border_gap_spinbox.value as u16)));
-                }
-                if self.app.layout.side_panel_border_opacity_spinbox.take_change() {
-                    actions.push(AppAction::Layout(pages::layout::LayoutMessage::SetSidePanelBorderOpacity(self.app.layout.side_panel_border_opacity_spinbox.value as u16)));
-                }
-            }
             Page::Interface => {
                 for (i, cp) in self.app.interface.color_selectors.iter_mut().enumerate() {
                     if cp.take_change() {
@@ -3990,6 +3980,51 @@ fn collect_popover_rects(w: &dyn cce_ui::widget::Element, popovers: &mut Vec<(f3
                 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() {
@@ -4446,145 +4481,6 @@ fn collect_popover_rects(w: &dyn cce_ui::widget::Element, popovers: &mut Vec<(f3
             }
         }
 
-        if self.app.current_page == Page::Layout {
-            let mut changed = false;
-            let mut actions = Vec::new();
-            for (i, sb) in self.app.layout.spinboxes.iter_mut().enumerate() {
-                let old = sb.value;
-                if sb.keyboard_input(event, &mut self.ui_context) {
-                    if sb.value != old {
-                        actions.push(AppAction::Layout(
-                            pages::layout::LayoutMessage::SetWidth(
-                                pages::layout::WidthParam::ALL[i],
-                                sb.value as u16,
-                            )
-                        ));
-                    }
-                    changed = true;
-                }
-            }
-            let sb = &mut self.app.layout.cascade_offset_spinbox;
-            let old = sb.value;
-            if sb.keyboard_input(event, &mut self.ui_context) {
-                if sb.value != old {
-                    actions.push(AppAction::Layout(
-                        pages::layout::LayoutMessage::SetCascadeOffset(sb.value as u16)
-                    ));
-                }
-                changed = true;
-            }
-            let sb = &mut self.app.layout.edge_gap_spinbox;
-            let old = sb.value;
-            if sb.keyboard_input(event, &mut self.ui_context) {
-                if sb.value != old {
-                    actions.push(AppAction::Layout(
-                        pages::layout::LayoutMessage::SetEdgeGap(sb.value as u16)
-                    ));
-                }
-                changed = true;
-            }
-            let sb = &mut self.app.layout.top_gap_spinbox;
-            let old = sb.value;
-            if sb.keyboard_input(event, &mut self.ui_context) {
-                if sb.value != old {
-                    actions.push(AppAction::Layout(
-                        pages::layout::LayoutMessage::SetTopGap(sb.value as u16)
-                    ));
-                }
-                changed = true;
-            }
-            let sb = &mut self.app.layout.grid_gap_spinbox;
-            let old = sb.value;
-            if sb.keyboard_input(event, &mut self.ui_context) {
-                if sb.value != old {
-                    actions.push(AppAction::Layout(
-                        pages::layout::LayoutMessage::SetGridGap(sb.value as u16)
-                    ));
-                }
-                changed = true;
-            }
-            let sb = &mut self.app.layout.transition_duration_spinbox;
-            let old = sb.value;
-            if sb.keyboard_input(event, &mut self.ui_context) {
-                if sb.value != old {
-                    actions.push(AppAction::Layout(
-                        pages::layout::LayoutMessage::SetTransitionDuration(sb.value as u16)
-                    ));
-                }
-                changed = true;
-            }
-            let sb = &mut self.app.layout.status_height_spinbox;
-            let old = sb.value;
-            if sb.keyboard_input(event, &mut self.ui_context) {
-                if sb.value != old {
-                    actions.push(AppAction::Layout(
-                        pages::layout::LayoutMessage::SetStatusHeight(sb.value as u16)
-                    ));
-                }
-                changed = true;
-            }
-            let (menu_changed, old_selected, new_selected) = {
-                let menu = &mut self.app.layout.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::Layout(pages::layout::LayoutMessage::SetSidePanelBehavior(new_selected)));
-                }
-                changed = true;
-            }
-            let (menu_changed, old_selected, new_selected) = {
-                let menu = &mut self.app.layout.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::Layout(pages::layout::LayoutMessage::SetSidePanelPosition(new_selected)));
-                }
-                changed = true;
-            }
-            let sb = &mut self.app.layout.side_panel_width_spinbox;
-            let old = sb.value;
-            if sb.keyboard_input(event, &mut self.ui_context) {
-                if sb.value != old {
-                    actions.push(AppAction::Layout(
-                        pages::layout::LayoutMessage::SetSidePanelWidth(sb.value as u16)
-                    ));
-                }
-                changed = true;
-            }
-            let sb = &mut self.app.layout.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::Layout(
-                        pages::layout::LayoutMessage::SetSidePanelBorderGap(sb.value as u16)
-                    ));
-                }
-                changed = true;
-            }
-            let sb = &mut self.app.layout.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::Layout(
-                        pages::layout::LayoutMessage::SetSidePanelBorderOpacity(sb.value as u16)
-                    ));
-                }
-                changed = true;
-            }
-            for a in &actions {
-                self.handle_action(a);
-            }
-            if changed {
-                self.needs_rebuild = true;
-                return true;
-            }
-        }
         if self.app.current_page == Page::Interface {
             let mc = &mut self.app.interface.custom_multicontrol;
             if mc.keyboard_input(event, &mut self.ui_context) {
@@ -5087,6 +4983,175 @@ fn collect_popover_rects(w: &dyn cce_ui::widget::Element, popovers: &mut Vec<(f3
                 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;
+                    }
+                }
+                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;
+                }
+                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;
+                }
+                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;
+                }
+                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;
+                }
+                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;
+                }
+                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;
+                }
+                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;
+                }
+                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;
+                }
+                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;
+                }
+                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;
+                }
+                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;
+                }
+            }
+            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;
diff --git a/src/pages/interface.rs b/src/pages/interface.rs
index 60c0f5a..51409df 100644
--- a/src/pages/interface.rs
+++ b/src/pages/interface.rs
@@ -1,9 +1,10 @@
 use std::fs;
 use std::io::Write;
 use crate::app::PageContent;
-use cce_ui::layout::{PageLayoutBuilder, LayoutStrategy};
+use cce_ui::layout::{render_widget, PageLayoutBuilder, LayoutStrategy};
 use cce_ui::widget::{
-    ColorSelector, Spinbox, Element, Dropdown, TextBox, FontSelector, Toggle, MultiControl
+    ColorSelector, Spinbox, Element, Dropdown, TextBox, FontSelector, Toggle, MultiControl,
+    LayoutPreview, PreviewLayoutMode
 };
 
 const CONFIG_PATH: &str = "/home/lsgalante/.config/cce/config.json";
@@ -16,8 +17,154 @@ fn get_socket_path() -> String {
     }
 }
 
+#[derive(Debug, Clone, Copy, PartialEq, Eq)]
+pub enum WidthParam {
+    Fullscreen, Cascade, Grid, Floating,
+}
+
+impl WidthParam {
+    pub const ALL: [WidthParam; 4] = [
+        WidthParam::Fullscreen, WidthParam::Cascade, WidthParam::Grid,
+        WidthParam::Floating,
+    ];
+    pub fn key(self) -> &'static str {
+        match self {
+            WidthParam::Fullscreen => "fullscreen_border_width",
+            WidthParam::Cascade => "cascade_border_width",
+            WidthParam::Grid => "grid_border_width",
+            WidthParam::Floating => "floating_border_width",
+        }
+    }
+    pub fn label(self) -> &'static str {
+        match self {
+            WidthParam::Fullscreen => "Fullscreen",
+            WidthParam::Cascade => "Cascade",
+            WidthParam::Grid => "Grid",
+            WidthParam::Floating => "Floating",
+        }
+    }
+}
+
+fn make_spinboxes(fs: u16, ca: u16, g: u16, fl: u16) -> Vec<Spinbox> {
+    vec![
+        Spinbox::new(fs as i32, 0, 100, 1),
+        Spinbox::new(ca as i32, 0, 100, 1),
+        Spinbox::new(g as i32, 0, 100, 1),
+        Spinbox::new(fl as i32, 0, 100, 1),
+    ]
+}
+
+#[derive(Debug, Clone)]
+pub struct WindowsState {
+    pub fullscreen_border_width: u16,
+    pub cascade_border_width: u16,
+    pub grid_border_width: u16,
+    pub floating_border_width: u16,
+    pub cascade_offset: u16,
+    pub edge_gap: u16,
+    pub top_gap: u16,
+    pub grid_gap: u16,
+    pub status_height: u16,
+    pub transition_duration: u16,
+    pub spinboxes: Vec<Spinbox>,
+    pub cascade_offset_spinbox: Spinbox,
+    pub edge_gap_spinbox: Spinbox,
+    pub top_gap_spinbox: Spinbox,
+    pub grid_gap_spinbox: Spinbox,
+    pub status_height_spinbox: Spinbox,
+    pub transition_duration_spinbox: Spinbox,
+    pub tag_layout_menus: Vec<Dropdown>,
+    pub side_panel_behavior_menu: Dropdown,
+    pub side_panel_position_menu: Dropdown,
+    pub side_panel_width: u16,
+    pub side_panel_width_spinbox: Spinbox,
+    pub side_panel_border_gap: u16,
+    pub side_panel_border_gap_spinbox: Spinbox,
+    pub side_panel_border_opacity: u16,
+    pub side_panel_border_opacity_spinbox: Spinbox,
+    pub transparency_enabled: bool,
+    pub transparency_toggle: Toggle,
+    pub blur_enabled: bool,
+    pub blur_toggle: Toggle,
+}
+
+impl Default for WindowsState {
+    fn default() -> Self {
+        Self {
+            fullscreen_border_width: 0,
+            cascade_border_width: 6,
+            grid_border_width: 6,
+            floating_border_width: 6,
+            cascade_offset: 20,
+            edge_gap: 48,
+            top_gap: 48,
+            grid_gap: 6,
+            status_height: 24,
+            transition_duration: 300,
+            spinboxes: make_spinboxes(0, 6, 6, 6),
+            cascade_offset_spinbox: Spinbox::new(20, 0, 200, 1),
+            edge_gap_spinbox: Spinbox::new(48, 0, 200, 1),
+            top_gap_spinbox: Spinbox::new(48, 0, 200, 1),
+            grid_gap_spinbox: Spinbox::new(6, 0, 200, 1),
+            status_height_spinbox: Spinbox::new(24, 0, 100, 1),
+            transition_duration_spinbox: Spinbox::new(300, 0, 2000, 50),
+            tag_layout_menus: (1..=4).map(|i| {
+                Dropdown::new(
+                    vec![
+                        "Cascade".to_string(),
+                        "Grid".to_string(),
+                        "Fullscreen".to_string(),
+                        "Floating".to_string(),
+                        "Popup".to_string(),
+                    ],
+                    0
+                ).with_label(&format!("Tag {}", i))
+            }).collect(),
+            side_panel_behavior_menu: Dropdown::new(
+                vec!["Above".to_string(), "Inline".to_string()],
+                1,
+            ).with_label("Behavior"),
+            side_panel_position_menu: Dropdown::new(
+                vec!["Left".to_string(), "Right".to_string()],
+                0,
+            ).with_label("Position"),
+            side_panel_width: 360,
+            side_panel_width_spinbox: Spinbox::new(360, 0, 2000, 10),
+            side_panel_border_gap: 0,
+            side_panel_border_gap_spinbox: Spinbox::new(0, 0, 500, 1),
+            side_panel_border_opacity: 100,
+            side_panel_border_opacity_spinbox: Spinbox::new(100, 0, 100, 5),
+            transparency_enabled: true,
+            transparency_toggle: Toggle::new().with_label("Transparency"),
+            blur_enabled: true,
+            blur_toggle: Toggle::new().with_label("Blur"),
+        }
+    }
+}
+
+#[derive(Debug, Clone)]
+pub enum WindowsMessage {
+    SetWidth(WidthParam, u16),
+    SetCascadeOffset(u16),
+    SetEdgeGap(u16),
+    SetTopGap(u16),
+    SetGridGap(u16),
+    SetTransitionDuration(u16),
+    SetStatusHeight(u16),
+    SetTagLayout(usize, usize),
+    SetSidePanelBehavior(usize),
+    SetSidePanelPosition(usize),
+    SetSidePanelWidth(u16),
+    SetSidePanelBorderGap(u16),
+    SetSidePanelBorderOpacity(u16),
+    ToggleTransparency,
+    ToggleBlur,
+    Refreshed(WindowsState),
+}
+
 #[derive(Debug, Clone)]
 pub struct InterfaceState {
+    pub windows: WindowsState,
     pub low_color: [u8; 3],
     pub high_color: [u8; 3],
     pub disabled_color: [u8; 3],
@@ -168,6 +315,7 @@ pub struct InterfaceState {
 impl Default for InterfaceState {
     fn default() -> Self {
         Self {
+            windows: WindowsState::default(),
             low_color: [0x0a, 0x1a, 0x0e],
             high_color: [0x3e, 0x3e, 0x3e],
             disabled_color: [0x55, 0x55, 0x55],
@@ -342,6 +490,7 @@ impl Default for InterfaceState {
 
 #[derive(Debug, Clone)]
 pub enum InterfaceMessage {
+    Windows(WindowsMessage),
     SetLowColor([u8; 3]),
     SetHighColor([u8; 3]),
     SetDisabledColor([u8; 3]),
@@ -555,6 +704,7 @@ pub fn read_interface_config() -> InterfaceState {
     let window_corner_radius = parse_surfaces_u16(&content, "window_corner_radius", 12);
     
     InterfaceState {
+        windows: read_windows_config(),
         low_color: bg,
         high_color: border,
         disabled_color: disabled,
@@ -726,6 +876,339 @@ pub fn read_interface_config() -> InterfaceState {
     }
 }
 
+pub fn read_windows_config() -> WindowsState {
+    let content = fs::read_to_string(CONFIG_PATH).unwrap_or_default();
+    let fs = parse_u16_from(&content, "fullscreen_border_width", 0);
+    let ca = parse_u16_from(&content, "cascade_border_width", 6);
+    let g = parse_u16_from(&content, "grid_border_width", 6);
+    let fl = parse_u16_from(&content, "floating_border_width", 6);
+    let co = parse_u16_from(&content, "cascade_offset", 20);
+    let gl = parse_u16_from(&content, "gap_left", 48);
+    let gt = parse_u16_from(&content, "gap_top", 48);
+    let gg = parse_u16_from(&content, "grid_gap", 6);
+    let sh = parse_u16_from(&content, "bar_height", 24);
+    let td = parse_u16_from(&content, "transition_duration", 300);
+
+    let tag_modes = parse_tag_layouts_from_config(&content);
+    let dropdown_options = vec![
+        "Cascade".to_string(),
+        "Grid".to_string(),
+        "Fullscreen".to_string(),
+        "Floating".to_string(),
+        "Popup".to_string(),
+    ];
+    let tag_layout_menus = (1..=4).map(|i| {
+        let mode_str = &tag_modes[i - 1];
+        let idx = dropdown_options.iter().position(|opt| opt.to_lowercase() == mode_str.to_lowercase()).unwrap_or(0);
+        Dropdown::new(dropdown_options.clone(), idx).with_label(&format!("Tag {}", i))
+    }).collect();
+
+    let side_panel_behavior = parse_string_from(&content, "side_panel_behavior", "inline");
+    let side_panel_behavior_idx = if side_panel_behavior == "above" { 0 } else { 1 };
+    let side_panel_behavior_menu = Dropdown::new(
+        vec!["Above".to_string(), "Inline".to_string()],
+        side_panel_behavior_idx,
+    ).with_label("Behavior");
+
+    let side_panel_position = parse_string_from(&content, "side_panel_position", "left");
+    let side_panel_position_idx = if side_panel_position == "right" { 1 } else { 0 };
+    let side_panel_position_menu = Dropdown::new(
+        vec!["Left".to_string(), "Right".to_string()],
+        side_panel_position_idx,
+    ).with_label("Position");
+
+    let spw = parse_u16_from(&content, "side_panel_width", 360);
+    let spbg = parse_u16_from(&content, "side_panel_border_gap", 0);
+    let spbo = parse_u16_from(&content, "side_panel_border_opacity", 100);
+
+    let transparency_opacity = parse_transparency_opacity(&content);
+    let transparency_enabled = transparency_opacity < 1.0;
+
+    let window_blur = parse_bool_from(&content, "window_blur", false);
+    let border_blur = parse_bool_from(&content, "border_blur", false);
+    let blur_enabled = window_blur || border_blur;
+
+    WindowsState {
+        fullscreen_border_width: fs,
+        cascade_border_width: ca,
+        grid_border_width: g,
+        floating_border_width: fl,
+        cascade_offset: co,
+        edge_gap: gl,
+        top_gap: gt,
+        grid_gap: gg,
+        status_height: sh,
+        transition_duration: td,
+        spinboxes: make_spinboxes(fs, ca, g, fl),
+        cascade_offset_spinbox: Spinbox::new(co as i32, 0, 200, 1),
+        edge_gap_spinbox: Spinbox::new(gl as i32, 0, 200, 1),
+        top_gap_spinbox: Spinbox::new(gt as i32, 0, 200, 1),
+        grid_gap_spinbox: Spinbox::new(gg as i32, 0, 200, 1),
+        status_height_spinbox: Spinbox::new(sh as i32, 0, 100, 1),
+        transition_duration_spinbox: Spinbox::new(td as i32, 0, 2000, 50),
+        tag_layout_menus,
+        side_panel_behavior_menu,
+        side_panel_position_menu,
+        side_panel_width: spw,
+        side_panel_width_spinbox: Spinbox::new(spw as i32, 0, 2000, 10),
+        side_panel_border_gap: spbg,
+        side_panel_border_gap_spinbox: Spinbox::new(spbg as i32, 0, 500, 1),
+        side_panel_border_opacity: spbo,
+        side_panel_border_opacity_spinbox: Spinbox::new(spbo as i32, 0, 100, 5),
+        transparency_enabled,
+        transparency_toggle: Toggle::new().with_label("Transparency"),
+        blur_enabled,
+        blur_toggle: Toggle::new().with_label("Blur"),
+    }
+}
+
+fn parse_tag_layouts_from_config(content: &str) -> Vec<String> {
+    let val = parse_json(content);
+    let mut modes = vec!["cascade".to_string(); 4];
+    if let Some(arr) = val.get("tag_layout").and_then(|t| t.as_array()) {
+        for item in arr {
+            if let (Some(tag), Some(mode)) = (
+                item.get("tag").and_then(|t| t.as_u64()),
+                item.get("mode").and_then(|m| m.as_str())
+            ) {
+                if tag >= 1 && tag <= 4 {
+                    modes[tag as usize - 1] = mode.to_string();
+                }
+            }
+        }
+    }
+    modes
+}
+
+fn write_tag_layout(tag_num: usize, mode_str: &str) -> bool {
+    let content = fs::read_to_string(CONFIG_PATH).unwrap_or_default();
+    let mut val = parse_json(&content);
+    
+    let mut found = false;
+    if let Some(arr) = val.get_mut("tag_layout").and_then(|t| t.as_array_mut()) {
+        for item in arr.iter_mut() {
+            if item.get("tag").and_then(|t| t.as_u64()) == Some(tag_num as u64) {
+                if let Some(obj) = item.as_object_mut() {
+                    obj.insert("mode".to_string(), serde_json::json!(mode_str.to_lowercase()));
+                    found = true;
+                    break;
+                }
+            }
+        }
+        if !found {
+            arr.push(serde_json::json!({
+                "tag": tag_num,
+                "mode": mode_str.to_lowercase()
+            }));
+        }
+    } else {
+        let arr = vec![serde_json::json!({
+            "tag": tag_num,
+            "mode": mode_str.to_lowercase()
+        })];
+        if let Some(obj) = val.as_object_mut() {
+            obj.insert("tag_layout".to_string(), serde_json::Value::Array(arr));
+        }
+    }
+    
+    if let Ok(updated_str) = serde_json::to_string_pretty(&val) {
+        return fs::write(CONFIG_PATH, updated_str).is_ok();
+    }
+    false
+}
+
+fn apply_all_widths(s: &WindowsState) {
+    let w = |k: &str, v: u16| { write_config_value(k, &v.to_string()); send_ipc_command(&format!("layout {} {}", k, v)); };
+    w("fullscreen_border_width", s.fullscreen_border_width);
+    w("cascade_border_width", s.cascade_border_width);
+    w("grid_border_width", s.grid_border_width);
+    w("floating_border_width", s.floating_border_width);
+    w("cascade_offset", s.cascade_offset);
+    w("gap_left", s.edge_gap);
+    w("gap_right", s.edge_gap);
+    w("gap_bottom", s.edge_gap);
+    w("gap_top", s.top_gap);
+    w("transition_duration", s.transition_duration);
+}
+
+fn apply_single_layout_param(key: &str, val: u16) {
+    write_config_value(key, &val.to_string());
+    send_ipc_command(&format!("layout {} {}", key, val));
+}
+
+fn apply_edge_gap(val: u16) {
+    let val_str = val.to_string();
+    write_config_value("gap_left", &val_str);
+    write_config_value("gap_right", &val_str);
+    write_config_value("gap_bottom", &val_str);
+    send_ipc_command(&format!("layout gap_left {}", val));
+    send_ipc_command(&format!("layout gap_right {}", val));
+    send_ipc_command(&format!("layout gap_bottom {}", val));
+}
+
+#[derive(Debug, Clone)]
+#[allow(dead_code)]
+struct PreviewWindow {
+    app_id: String,
+    title: String,
+    x: f32,
+    y: f32,
+    w: f32,
+    h: f32,
+    tags: u32,
+    _minimized: bool,
+    has_parent: bool,
+    layout_mode: String,
+}
+
+#[allow(dead_code)]
+struct LayoutStatusInfo {
+    active_tags: u32,
+    focused_tags: u32,
+    _num_tags: u32,
+    windows: Vec<PreviewWindow>,
+    focused_title: String,
+    focused_layout_mode: String,
+}
+
+fn read_current_layout_status() -> LayoutStatusInfo {
+    let mut active_tags = 1;
+    let mut focused_tags = 1;
+    let mut _num_tags = 4;
+
+    let display = std::env::var("WAYLAND_DISPLAY").unwrap_or_else(|_| "wayland-0".to_string());
+    
+    let tags_path = format!("/tmp/cce-tags-{}", display);
+    let tags_fallback = "/tmp/cce-tags".to_string();
+    let tags_content = fs::read_to_string(&tags_path)
+        .or_else(|_| fs::read_to_string(&tags_fallback))
+        .unwrap_or_default();
+
+    if let Some(line) = tags_content.lines().next() {
+        let parts: Vec<&str> = line.split_whitespace().collect();
+        if parts.len() >= 3 {
+            active_tags = parts[0].parse().unwrap_or(1);
+            focused_tags = parts[1].parse().unwrap_or(1);
+            _num_tags = parts[2].parse().unwrap_or(4);
+        }
+    }
+
+    let title_path = format!("/tmp/cce-title-{}", display);
+    let title_fallback = "/tmp/cce-title".to_string();
+    let focused_title = fs::read_to_string(&title_path)
+        .or_else(|_| fs::read_to_string(&title_fallback))
+        .unwrap_or_default()
+        .trim()
+        .to_string();
+
+    let layout_path = format!("/tmp/cce-layout-{}", display);
+    let layout_fallback = "/tmp/cce-layout".to_string();
+    let focused_layout_mode = fs::read_to_string(&layout_path)
+        .or_else(|_| fs::read_to_string(&layout_fallback))
+        .unwrap_or_else(|_| "Cascade".to_string())
+        .trim()
+        .to_string();
+
+    let windows_path = format!("/tmp/cce-windows-{}", display);
+    let windows_fallback = "/tmp/cce-windows".to_string();
+    let windows_content = fs::read_to_string(&windows_path)
+        .or_else(|_| fs::read_to_string(&windows_fallback))
+        .unwrap_or_default();
+
+    let mut windows = Vec::new();
+    for line in windows_content.lines() {
+        if !line.starts_with("window ") { continue; }
+        
+        let mut app_id = String::new();
+        let mut title = String::new();
+        let mut x = 0.0;
+        let mut y = 0.0;
+        let mut w = 0.0;
+        let mut h = 0.0;
+        let mut tags = 0;
+        let mut minimized = false;
+        let mut has_parent = false;
+        let mut layout_mode = "Cascade".to_string();
+        
+        let parts = line.strip_prefix("window ").unwrap_or(line);
+        
+        let get_val = |p: &str, k: &str| -> Option<String> {
+            if let Some(idx) = p.find(k) {
+                let start = idx + k.len();
+                let mut end = p.len();
+                let next_keys = [
+                    " app_id=", " title=", " mode=", " decoration=", " presentation=",
+                    " tags=", " x=", " y=", " w=", " h=", " has_parent=", " minimized="
+                ];
+                for nk in next_keys {
+                    if nk != k {
+                        if let Some(nidx) = p[start..].find(nk) {
+                            end = end.min(start + nidx);
+                        }
+                    }
+                }
+                Some(p[start..end].trim().to_string())
+            } else {
+                None
+            }
+        };
+
+        if let Some(val) = get_val(parts, "app_id=") { app_id = val; }
+        if let Some(val) = get_val(parts, "title=") { title = val; }
+        if let Some(val) = get_val(parts, "x=") { x = val.parse().unwrap_or(0.0); }
+        if let Some(val) = get_val(parts, "y=") { y = val.parse().unwrap_or(0.0); }
+        if let Some(val) = get_val(parts, "w=") { w = val.parse().unwrap_or(0.0); }
+        if let Some(val) = get_val(parts, "h=") { h = val.parse().unwrap_or(0.0); }
+        if let Some(val) = get_val(parts, "tags=") { tags = val.parse().unwrap_or(0); }
+        if let Some(val) = get_val(parts, "minimized=") { minimized = val == "true"; }
+        if let Some(val) = get_val(parts, "has_parent=") { has_parent = val == "true"; }
+        if let Some(val) = get_val(parts, "mode=") { layout_mode = val; }
+
+        windows.push(PreviewWindow {
+            app_id,
+            title,
+            x,
+            y,
+            w,
+            h,
+            tags,
+            _minimized: minimized,
+            has_parent,
+            layout_mode,
+        });
+    }
+
+    LayoutStatusInfo {
+        active_tags,
+        focused_tags,
+        _num_tags,
+        windows,
+        focused_title,
+        focused_layout_mode,
+    }
+}
+
+fn set_width(state: &mut WindowsState, param: WidthParam, val: u16) {
+    let val = val.min(100);
+    match param {
+        WidthParam::Fullscreen => state.fullscreen_border_width = val,
+        WidthParam::Cascade => state.cascade_border_width = val,
+        WidthParam::Grid => state.grid_border_width = val,
+        WidthParam::Floating => state.floating_border_width = val,
+    }
+    state.spinboxes[param_idx(param)].value = val as i32;
+    apply_all_widths(state);
+}
+
+fn param_idx(p: WidthParam) -> usize {
+    match p {
+        WidthParam::Fullscreen => 0,
+        WidthParam::Cascade => 1,
+        WidthParam::Grid => 2,
+        WidthParam::Floating => 3,
+    }
+}
+
 fn parse_json(content: &str) -> serde_json::Value {
     serde_json::from_str(content).unwrap_or_default()
 }
@@ -1922,7 +2405,7 @@ pub async fn fetch_typeface_state() -> InterfaceState {
 pub fn view(state: &mut InterfaceState, 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 = 260.0f32;
-    let mut builder = PageLayoutBuilder::new(layout, cx, cy, cw, ch, sec_w).with_section_count(9);
+    let mut builder = PageLayoutBuilder::new(layout, cx, cy, cw, ch, sec_w).with_section_count(10);
 
 
     // 1. Custom Parameters Section
@@ -2399,8 +2882,143 @@ pub fn view(state: &mut InterfaceState, cx: f32, cy: f32, cw: f32, ch: f32, sec_
         sec.spacing(12.0);
     });
 
-    final_pc
+    // 10. Windows Section
+    builder.add_section(&mut final_pc, "Windows", sec_focused.get(9).copied().unwrap_or(false), |sec| {
+        sec.spacing(8.0);
+        
+        // 1. Current Layout Preview
+        sec.add_section("Current Layout", false, |sec_cl| {
+            sec_cl.spacing(8.0);
+            
+            let info = read_current_layout_status();
+            
+            let card_w = (sec_w - 24.0) / 2.0;
+            let card_h = 135.0;
+            let rx = sec_cl.left;
+            
+            for tag_idx in 0..4 {
+                let col = tag_idx % 2;
+                let row = tag_idx / 2;
+                let tx = rx + 8.0 + col as f32 * (card_w + 8.0);
+                let ty = sec_cl.ay() + row as f32 * (card_h + 8.0);
+                
+                let is_active = (info.active_tags & (1 << tag_idx)) != 0;
+                let layout_idx = state.windows.tag_layout_menus.get(tag_idx).map(|m| m.selected).unwrap_or(0);
+                let mode = match layout_idx {
+                    1 => PreviewLayoutMode::Cascade,
+                    2 => PreviewLayoutMode::Stack,
+                    3 => PreviewLayoutMode::Grid,
+                    4 => PreviewLayoutMode::LeftTiled,
+                    5 => PreviewLayoutMode::RightTiled,
+                    6 => PreviewLayoutMode::Equal,
+                    7 => PreviewLayoutMode::Spiral,
+                    8 => PreviewLayoutMode::Floating,
+                    _ => PreviewLayoutMode::Fullscreen,
+                };
+
+                let mut preview = LayoutPreview::new(mode)
+                    .with_active(is_active)
+                    .with_label(&format!("TAG {}", tag_idx + 1));
+                render_widget(sec_cl.pc, &mut preview, tx, ty, card_w, card_h, ctx);
+            }
+            
+            sec_cl.content_y += 2.0 * (card_h + 8.0) + 4.0;
+        });
+
+        // 2. Fullscreen Section
+        sec.add_section("Fullscreen", false, |subsec| {
+            subsec.spacing(8.0);
+            state.windows.spinboxes[0].set_label("Border Width");
+            subsec.widget_full(&mut state.windows.spinboxes[0], 44.0, ctx);
+            subsec.spacing(8.0);
+        });
+
+        // 3. Cascade Section
+        sec.add_section("Cascade", false, |subsec| {
+            subsec.spacing(8.0);
+            state.windows.spinboxes[1].set_label("Border Width");
+            subsec.widget_full(&mut state.windows.spinboxes[1], 44.0, ctx);
+            subsec.spacing(8.0);
+            state.windows.cascade_offset_spinbox.set_label("Offset");
+            subsec.widget_full(&mut state.windows.cascade_offset_spinbox, 44.0, ctx);
+            subsec.spacing(8.0);
+            state.windows.edge_gap_spinbox.set_label("Edge Gap");
+            subsec.widget_full(&mut state.windows.edge_gap_spinbox, 44.0, ctx);
+            subsec.spacing(8.0);
+            state.windows.top_gap_spinbox.set_label("Top Gap");
+            subsec.widget_full(&mut state.windows.top_gap_spinbox, 44.0, ctx);
+            subsec.spacing(8.0);
+        });
+
+        // 4. Grid Section
+        sec.add_section("Grid", false, |subsec| {
+            subsec.spacing(8.0);
+            state.windows.spinboxes[2].set_label("Border Width");
+            subsec.widget_full(&mut state.windows.spinboxes[2], 44.0, ctx);
+            subsec.spacing(8.0);
+            state.windows.grid_gap_spinbox.set_label("Gap");
+            subsec.widget_full(&mut state.windows.grid_gap_spinbox, 44.0, ctx);
+            subsec.spacing(8.0);
+        });
+
+        // 5. Floating Section
+        sec.add_section("Floating", false, |subsec| {
+            subsec.spacing(8.0);
+            state.windows.spinboxes[3].set_label("Border Width");
+            subsec.widget_full(&mut state.windows.spinboxes[3], 44.0, ctx);
+            subsec.spacing(8.0);
+        });
+
+        // 6. Movement Section
+        sec.add_section("Movement", false, |subsec| {
+            subsec.spacing(8.0);
+            state.windows.transition_duration_spinbox.set_label("Duration (ms)");
+            subsec.widget_full(&mut state.windows.transition_duration_spinbox, 44.0, ctx);
+            subsec.spacing(8.0);
+        });
+
+        // 7. Default Layouts Section
+        sec.add_section("Default Layouts", false, |subsec| {
+            subsec.spacing(8.0);
+            for i in 0..4 {
+                subsec.widget_full(&mut state.windows.tag_layout_menus[i], 44.0, ctx);
+                subsec.spacing(8.0);
+            }
+        });
+
+        // 8. Side Panel Section
+        sec.add_section("Side Panel", false, |subsec| {
+            subsec.spacing(8.0);
+            subsec.widget_full(&mut state.windows.side_panel_behavior_menu, 44.0, ctx);
+            subsec.spacing(8.0);
+            subsec.widget_full(&mut state.windows.side_panel_position_menu, 44.0, ctx);
+            subsec.spacing(8.0);
+            state.windows.side_panel_width_spinbox.set_label("Default Width");
+            subsec.widget_full(&mut state.windows.side_panel_width_spinbox, 44.0, ctx);
+            subsec.spacing(8.0);
+            state.windows.side_panel_border_gap_spinbox.set_label("Border Gap");
+            subsec.widget_full(&mut state.windows.side_panel_border_gap_spinbox, 44.0, ctx);
+            subsec.spacing(8.0);
+            state.windows.side_panel_border_opacity_spinbox.set_label("Border Opacity");
+            subsec.widget_full(&mut state.windows.side_panel_border_opacity_spinbox, 44.0, ctx);
+            subsec.spacing(8.0);
+        });
 
+        // 9. Effects Section
+        sec.add_section("Effects", false, |subsec| {
+            subsec.spacing(8.0);
+            state.windows.transparency_toggle.set_toggled(state.windows.transparency_enabled);
+            subsec.widget_full(&mut state.windows.transparency_toggle, cce_ui::layout::toggle_height(), ctx);
+            subsec.spacing(8.0);
+            state.windows.blur_toggle.set_toggled(state.windows.blur_enabled);
+            subsec.widget_full(&mut state.windows.blur_toggle, cce_ui::layout::toggle_height(), ctx);
+            subsec.spacing(8.0);
+        });
+
+        sec.spacing(8.0);
+    });
+
+    final_pc
 }
 
 
@@ -3177,6 +3795,154 @@ pub fn update(state: &mut InterfaceState, msg: InterfaceMessage) {
             state.terminal_size_box.value = val;
             write_terminal_size(val as u16);
         }
+        InterfaceMessage::Windows(sub_msg) => {
+            update_windows(&mut state.windows, sub_msg);
+        }
+    }
+}
+
+pub fn update_windows(state: &mut WindowsState, msg: WindowsMessage) {
+    match msg {
+        WindowsMessage::SetWidth(p, v) => set_width(state, p, v),
+        WindowsMessage::SetCascadeOffset(v) => {
+            let val = v.min(200);
+            state.cascade_offset = val;
+            state.cascade_offset_spinbox.value = val as i32;
+            apply_single_layout_param("cascade_offset", val);
+        }
+        WindowsMessage::SetEdgeGap(v) => {
+            let val = v.min(200);
+            state.edge_gap = val;
+            state.edge_gap_spinbox.value = val as i32;
+            apply_edge_gap(val);
+        }
+        WindowsMessage::SetTopGap(v) => {
+            let val = v.min(200);
+            state.top_gap = val;
+            state.top_gap_spinbox.value = val as i32;
+            apply_single_layout_param("gap_top", val);
+        }
+        WindowsMessage::SetGridGap(v) => {
+            let val = v.min(200);
+            state.grid_gap = val;
+            state.grid_gap_spinbox.value = val as i32;
+            apply_single_layout_param("grid_gap", val);
+        }
+        WindowsMessage::SetTransitionDuration(v) => {
+            let val = v.min(2000);
+            state.transition_duration = val;
+            state.transition_duration_spinbox.value = val as i32;
+            apply_single_layout_param("transition_duration", val);
+        }
+        WindowsMessage::SetStatusHeight(v) => {
+            let val = v.min(100);
+            state.status_height = val;
+            state.status_height_spinbox.value = val as i32;
+            apply_single_layout_param("bar_height", val);
+        }
+        WindowsMessage::SetTagLayout(tag, idx) => {
+            if tag >= 1 && tag <= 4 && idx < 5 {
+                state.tag_layout_menus[tag - 1].selected = idx;
+                let modes = vec!["cascade", "grid", "fullscreen", "floating", "popup"];
+                let mode_str = modes[idx];
+                write_tag_layout(tag, mode_str);
+                send_ipc_command(&format!("tag-layout {} {}", tag, mode_str));
+            }
+        }
+        WindowsMessage::SetSidePanelBehavior(idx) => {
+            if idx < 2 {
+                state.side_panel_behavior_menu.selected = idx;
+                let val = if idx == 0 { "above" } else { "inline" };
+                write_config_value("side_panel_behavior", &format!("\"{}\"", val));
+                send_ipc_command(&format!("layout side_panel_behavior {}", val));
+            }
+        }
+        WindowsMessage::SetSidePanelPosition(idx) => {
+            if idx < 2 {
+                state.side_panel_position_menu.selected = idx;
+                let val = if idx == 1 { "right" } else { "left" };
+                write_config_value("side_panel_position", &format!("\"{}\"", val));
+                send_ipc_command(&format!("layout side_panel_position {}", val));
+            }
+        }
+        WindowsMessage::SetSidePanelWidth(v) => {
+            let val = v.min(2000);
+            state.side_panel_width = val;
+            state.side_panel_width_spinbox.value = val as i32;
+            write_config_value("side_panel_width", &val.to_string());
+            send_ipc_command(&format!("layout side_panel_width {}", val));
+        }
+        WindowsMessage::SetSidePanelBorderGap(v) => {
+            let val = v.min(500);
+            state.side_panel_border_gap = val;
+            state.side_panel_border_gap_spinbox.value = val as i32;
+            write_config_value("side_panel_border_gap", &val.to_string());
+            send_ipc_command(&format!("layout side_panel_border_gap {}", val));
+        }
+        WindowsMessage::SetSidePanelBorderOpacity(v) => {
+            let val = v.min(100);
+            state.side_panel_border_opacity = val;
+            state.side_panel_border_opacity_spinbox.value = val as i32;
+            write_config_value("side_panel_border_opacity", &val.to_string());
+            send_ipc_command(&format!("layout side_panel_border_opacity {}", val));
+        }
+        WindowsMessage::ToggleTransparency => {
+            state.transparency_enabled = !state.transparency_enabled;
+            if state.transparency_enabled {
+                write_transparency_config_value("opacity", "0.85");
+            } else {
+                write_transparency_config_value("opacity", "1.00");
+            }
+            send_ipc_command("reload");
+            status_interface_reload();
+        }
+        WindowsMessage::ToggleBlur => {
+            state.blur_enabled = !state.blur_enabled;
+            let val = state.blur_enabled.to_string();
+            write_config_value("window_blur", &val);
+            write_config_value("border_blur", &val);
+            send_ipc_command("reload");
+        }
+        WindowsMessage::Refreshed(new) => {
+            // Restore hover states
+            let transparency_hover = state.transparency_toggle.hovered();
+            let blur_hover = state.blur_toggle.hovered();
+            let tag_layout_menus_hover: Vec<bool> = state.tag_layout_menus.iter().map(|m| m.hovered()).collect();
+            let side_panel_behavior_hover = state.side_panel_behavior_menu.hovered();
+            let side_panel_position_hover = state.side_panel_position_menu.hovered();
+            let spinboxes_hover: Vec<bool> = state.spinboxes.iter().map(|sb| sb.hovered()).collect();
+            let cascade_offset_hover = state.cascade_offset_spinbox.hovered();
+            let edge_gap_hover = state.edge_gap_spinbox.hovered();
+            let top_gap_hover = state.top_gap_spinbox.hovered();
+            let grid_gap_hover = state.grid_gap_spinbox.hovered();
+            let status_height_hover = state.status_height_spinbox.hovered();
+            let transition_duration_hover = state.transition_duration_spinbox.hovered();
+            let side_panel_width_hover = state.side_panel_width_spinbox.hovered();
+            let side_panel_border_gap_hover = state.side_panel_border_gap_spinbox.hovered();
+            let side_panel_border_opacity_hover = state.side_panel_border_opacity_spinbox.hovered();
+
+            *state = new;
+
+            state.transparency_toggle.set_hovered(transparency_hover);
+            state.blur_toggle.set_hovered(blur_hover);
+            for (menu, hover) in state.tag_layout_menus.iter_mut().zip(tag_layout_menus_hover) {
+                menu.set_hovered(hover);
+            }
+            state.side_panel_behavior_menu.set_hovered(side_panel_behavior_hover);
+            state.side_panel_position_menu.set_hovered(side_panel_position_hover);
+            for (sb, hover) in state.spinboxes.iter_mut().zip(spinboxes_hover) {
+                sb.set_hovered(hover);
+            }
+            state.cascade_offset_spinbox.set_hovered(cascade_offset_hover);
+            state.edge_gap_spinbox.set_hovered(edge_gap_hover);
+            state.top_gap_spinbox.set_hovered(top_gap_hover);
+            state.grid_gap_spinbox.set_hovered(grid_gap_hover);
+            state.status_height_spinbox.set_hovered(status_height_hover);
+            state.transition_duration_spinbox.set_hovered(transition_duration_hover);
+            state.side_panel_width_spinbox.set_hovered(side_panel_width_hover);
+            state.side_panel_border_gap_spinbox.set_hovered(side_panel_border_gap_hover);
+            state.side_panel_border_opacity_spinbox.set_hovered(side_panel_border_opacity_hover);
+        }
     }
 }
 
@@ -4557,6 +5323,128 @@ mod tests {
 
         let _ = fs::remove_file(path_str);
     }
+
+    #[test]
+    fn test_parse_tag_layouts_empty() {
+        let content = "";
+        let modes = parse_tag_layouts_from_config(content);
+        assert_eq!(modes, vec!["cascade", "cascade", "cascade", "cascade"]);
+    }
+
+    #[test]
+    fn test_parse_side_panel_width_default() {
+        let content = "";
+        let width = parse_u16_from(content, "side_panel_width", 360);
+        assert_eq!(width, 360);
+    }
+
+    #[test]
+    fn test_parse_side_panel_width_explicit() {
+        let content = "{\"layout\": {\"side_panel_width\": 450}}";
+        let width = parse_u16_from(content, "side_panel_width", 360);
+        assert_eq!(width, 450);
+    }
+
+    #[test]
+    fn test_parse_side_panel_border_opacity_default() {
+        let content = "";
+        let opacity = parse_u16_from(content, "side_panel_border_opacity", 100);
+        assert_eq!(opacity, 100);
+    }
+
+    #[test]
+    fn test_parse_side_panel_border_opacity_explicit() {
+        let content = "{\"layout\": {\"side_panel_border_opacity\": 75}}";
+        let opacity = parse_u16_from(content, "side_panel_border_opacity", 100);
+        assert_eq!(opacity, 75);
+    }
+
+    #[test]
+    fn test_parse_tag_layouts_single() {
+        let content = r#"{
+            "layout": {"gap": 10},
+            "tag_layout": [
+                {"tag": 2, "mode": "grid"}
+            ]
+        }"#;
+        let modes = parse_tag_layouts_from_config(content);
+        assert_eq!(modes, vec!["cascade", "grid", "cascade", "cascade"]);
+    }
+
+    #[test]
+    fn test_parse_tag_layouts_multiple() {
+        let content = r#"{
+            "tag_layout": [
+                {"tag": 1, "mode": "fullscreen"},
+                {"tag": 4, "mode": "floating"}
+            ]
+        }"#;
+        let modes = parse_tag_layouts_from_config(content);
+        assert_eq!(modes, vec!["fullscreen", "cascade", "cascade", "floating"]);
+    }
+
+    #[test]
+    fn test_parse_tag_layouts_out_of_bounds() {
+        let content = r#"{
+            "tag_layout": [
+                {"tag": 5, "mode": "grid"},
+                {"tag": 0, "mode": "popup"}
+            ]
+        }"#;
+        let modes = parse_tag_layouts_from_config(content);
+        assert_eq!(modes, vec!["cascade", "cascade", "cascade", "cascade"]);
+    }
+
+    #[test]
+    fn test_view_layout_grid() {
+        let mut state = InterfaceState::default();
+        let mut layout = cce_ui::layout::ColumnLayout::new(20.0);
+        let pc = view(&mut state, 10.0, 20.0, 800.0, 600.0, &[false, false, false, false, false, false, false, false, false, false], &mut layout, &mut cce_ui::context::UiContext::new());
+        assert!(!pc.rects.is_empty() || !pc.texts.is_empty());
+    }
+
+    #[test]
+    fn test_spinbox_right_click() {
+        use cce_ui::widget::Element;
+        let mut state = InterfaceState::default();
+        let mut ctx = cce_ui::context::UiContext::new();
+        let sb = &mut state.windows.spinboxes[0];
+        sb.set_rect(0.0, 0.0, 100.0, 44.0);
+        let res = sb.mouse_input(
+            cce_ui::widget::MouseButton::Right,
+            cce_ui::widget::ElementState::Pressed,
+            50.0,
+            20.0,
+            &mut ctx,
+        );
+        assert!(res);
+    }
+
+    #[test]
+    #[allow(unused_assignments)]
+    fn test_spinbox_right_click_crash() {
+        use cce_ui::widget::Element;
+        let mut state = InterfaceState::default();
+        let mut ctx = cce_ui::context::UiContext::new();
+        let sb = &mut state.windows.spinboxes[0];
+        sb.set_rect(0.0, 0.0, 100.0, 44.0);
+        let res = sb.mouse_input(
+            cce_ui::widget::MouseButton::Right,
+            cce_ui::widget::ElementState::Pressed,
+            50.0,
+            20.0,
+            &mut ctx,
+        );
+        assert!(res);
+        assert!(cce_ui::widget::context_menu::is_visible());
+
+        // Now replace the state simulating config reload/refresh
+        let new_state = InterfaceState::default();
+        state = new_state;
+
+        // Assert that the context menu is hidden (cleared)
+        assert!(!cce_ui::widget::context_menu::is_visible());
+    }
 }
 
 
diff --git a/src/pages/layout.rs b/src/pages/layout.rs
deleted file mode 100644
index 1e25e76..0000000
--- a/src/pages/layout.rs
+++ /dev/null
@@ -1,910 +0,0 @@
-use std::fs;
-use std::io::Write;
-
-use crate::app::PageContent;
-use cce_ui::layout::{render_widget, PageLayoutBuilder, LayoutStrategy};
-use cce_ui::widget::{Spinbox, Dropdown, LayoutPreview, PreviewLayoutMode, Toggle, Element};
-use crate::pages::interface::{parse_bool_from, parse_transparency_opacity, write_transparency_config_value, status_interface_reload};
-
-
-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(),
-    }
-}
-
-#[derive(Debug, Clone, Copy, PartialEq, Eq)]
-pub enum WidthParam {
-    Fullscreen, Cascade, Grid, Floating,
-}
-
-impl WidthParam {
-    pub const ALL: [WidthParam; 4] = [
-        WidthParam::Fullscreen, WidthParam::Cascade, WidthParam::Grid,
-        WidthParam::Floating,
-    ];
-    pub fn key(self) -> &'static str {
-        match self {
-            WidthParam::Fullscreen => "fullscreen_border_width",
-            WidthParam::Cascade => "cascade_border_width",
-            WidthParam::Grid => "grid_border_width",
-            WidthParam::Floating => "floating_border_width",
-        }
-    }
-    pub fn label(self) -> &'static str {
-        match self {
-            WidthParam::Fullscreen => "Fullscreen",
-            WidthParam::Cascade => "Cascade",
-            WidthParam::Grid => "Grid",
-            WidthParam::Floating => "Floating",
-        }
-    }
-}
-
-fn make_spinboxes(fs: u16, ca: u16, g: u16, fl: u16) -> Vec<Spinbox> {
-    vec![
-        Spinbox::new(fs as i32, 0, 100, 1),
-        Spinbox::new(ca as i32, 0, 100, 1),
-        Spinbox::new(g as i32, 0, 100, 1),
-        Spinbox::new(fl as i32, 0, 100, 1),
-    ]
-}
-
-#[derive(Debug, Clone)]
-pub struct LayoutState {
-    pub fullscreen_border_width: u16,
-    pub cascade_border_width: u16,
-    pub grid_border_width: u16,
-    pub floating_border_width: u16,
-    pub cascade_offset: u16,
-    pub edge_gap: u16,
-    pub top_gap: u16,
-    pub grid_gap: u16,
-    pub status_height: u16,
-    pub transition_duration: u16,
-    pub spinboxes: Vec<Spinbox>,
-    pub cascade_offset_spinbox: Spinbox,
-    pub edge_gap_spinbox: Spinbox,
-    pub top_gap_spinbox: Spinbox,
-    pub grid_gap_spinbox: Spinbox,
-    pub status_height_spinbox: Spinbox,
-    pub transition_duration_spinbox: Spinbox,
-    pub tag_layout_menus: Vec<Dropdown>,
-    pub side_panel_behavior_menu: Dropdown,
-    pub side_panel_position_menu: Dropdown,
-    pub side_panel_width: u16,
-    pub side_panel_width_spinbox: Spinbox,
-    pub side_panel_border_gap: u16,
-    pub side_panel_border_gap_spinbox: Spinbox,
-    pub side_panel_border_opacity: u16,
-    pub side_panel_border_opacity_spinbox: Spinbox,
-    pub transparency_enabled: bool,
-    pub transparency_toggle: Toggle,
-    pub blur_enabled: bool,
-    pub blur_toggle: Toggle,
-}
-
-impl Default for LayoutState {
-    fn default() -> Self {
-        Self {
-            fullscreen_border_width: 0,
-            cascade_border_width: 6,
-            grid_border_width: 6,
-            floating_border_width: 6,
-            cascade_offset: 20,
-            edge_gap: 48,
-            top_gap: 48,
-            grid_gap: 6,
-            status_height: 24,
-            transition_duration: 300,
-            spinboxes: make_spinboxes(0, 6, 6, 6),
-            cascade_offset_spinbox: Spinbox::new(20, 0, 200, 1),
-            edge_gap_spinbox: Spinbox::new(48, 0, 200, 1),
-            top_gap_spinbox: Spinbox::new(48, 0, 200, 1),
-            grid_gap_spinbox: Spinbox::new(6, 0, 200, 1),
-            status_height_spinbox: Spinbox::new(24, 0, 100, 1),
-            transition_duration_spinbox: Spinbox::new(300, 0, 2000, 50),
-            tag_layout_menus: (1..=4).map(|i| {
-                Dropdown::new(
-                    vec![
-                        "Cascade".to_string(),
-                        "Grid".to_string(),
-                        "Fullscreen".to_string(),
-                        "Floating".to_string(),
-                        "Popup".to_string(),
-                    ],
-                    0
-                ).with_label(&format!("Tag {}", i))
-            }).collect(),
-            side_panel_behavior_menu: Dropdown::new(
-                vec!["Above".to_string(), "Inline".to_string()],
-                1,
-            ).with_label("Behavior"),
-            side_panel_position_menu: Dropdown::new(
-                vec!["Left".to_string(), "Right".to_string()],
-                0,
-            ).with_label("Position"),
-            side_panel_width: 360,
-            side_panel_width_spinbox: Spinbox::new(360, 0, 2000, 10),
-            side_panel_border_gap: 0,
-            side_panel_border_gap_spinbox: Spinbox::new(0, 0, 500, 1),
-            side_panel_border_opacity: 100,
-            side_panel_border_opacity_spinbox: Spinbox::new(100, 0, 100, 5),
-            transparency_enabled: true,
-            transparency_toggle: Toggle::new().with_label("Transparency"),
-            blur_enabled: true,
-            blur_toggle: Toggle::new().with_label("Blur"),
-        }
-    }
-}
-
-#[derive(Debug, Clone)]
-pub enum LayoutMessage {
-    SetWidth(WidthParam, u16),
-    SetCascadeOffset(u16),
-    SetEdgeGap(u16),
-    SetTopGap(u16),
-    SetGridGap(u16),
-    SetTransitionDuration(u16),
-    SetStatusHeight(u16),
-    SetTagLayout(usize, usize),
-    SetSidePanelBehavior(usize),
-    SetSidePanelPosition(usize),
-    SetSidePanelWidth(u16),
-    SetSidePanelBorderGap(u16),
-    SetSidePanelBorderOpacity(u16),
-    ToggleTransparency,
-    ToggleBlur,
-    Refreshed(LayoutState),
-}
-
-pub fn read_layout_config() -> LayoutState {
-    let content = fs::read_to_string(CONFIG_PATH).unwrap_or_default();
-    let fs = parse_u16_from(&content, "fullscreen_border_width", 0);
-    let ca = parse_u16_from(&content, "cascade_border_width", 6);
-    let g = parse_u16_from(&content, "grid_border_width", 6);
-    let fl = parse_u16_from(&content, "floating_border_width", 6);
-    let co = parse_u16_from(&content, "cascade_offset", 20);
-    let gl = parse_u16_from(&content, "gap_left", 48);
-    let gt = parse_u16_from(&content, "gap_top", 48);
-    let gg = parse_u16_from(&content, "grid_gap", 6);
-    let sh = parse_u16_from(&content, "bar_height", 24);
-    let td = parse_u16_from(&content, "transition_duration", 300);
-
-    let tag_modes = parse_tag_layouts_from_config(&content);
-    let dropdown_options = vec![
-        "Cascade".to_string(),
-        "Grid".to_string(),
-        "Fullscreen".to_string(),
-        "Floating".to_string(),
-        "Popup".to_string(),
-    ];
-    let tag_layout_menus = (1..=4).map(|i| {
-        let mode_str = &tag_modes[i - 1];
-        let idx = dropdown_options.iter().position(|opt| opt.to_lowercase() == mode_str.to_lowercase()).unwrap_or(0);
-        Dropdown::new(dropdown_options.clone(), idx).with_label(&format!("Tag {}", i))
-    }).collect();
-
-    let side_panel_behavior = parse_string_from(&content, "side_panel_behavior", "inline");
-    let side_panel_behavior_idx = if side_panel_behavior == "above" { 0 } else { 1 };
-    let side_panel_behavior_menu = Dropdown::new(
-        vec!["Above".to_string(), "Inline".to_string()],
-        side_panel_behavior_idx,
-    ).with_label("Behavior");
-
-    let side_panel_position = parse_string_from(&content, "side_panel_position", "left");
-    let side_panel_position_idx = if side_panel_position == "right" { 1 } else { 0 };
-    let side_panel_position_menu = Dropdown::new(
-        vec!["Left".to_string(), "Right".to_string()],
-        side_panel_position_idx,
-    ).with_label("Position");
-
-    let spw = parse_u16_from(&content, "side_panel_width", 360);
-    let spbg = parse_u16_from(&content, "side_panel_border_gap", 0);
-    let spbo = parse_u16_from(&content, "side_panel_border_opacity", 100);
-
-    let transparency_opacity = parse_transparency_opacity(&content);
-    let transparency_enabled = transparency_opacity < 1.0;
-
-    let window_blur = parse_bool_from(&content, "window_blur", false);
-    let border_blur = parse_bool_from(&content, "border_blur", false);
-    let blur_enabled = window_blur || border_blur;
-
-    LayoutState {
-        fullscreen_border_width: fs,
-        cascade_border_width: ca,
-        grid_border_width: g,
-        floating_border_width: fl,
-        cascade_offset: co,
-        edge_gap: gl,
-        top_gap: gt,
-        grid_gap: gg,
-        status_height: sh,
-        transition_duration: td,
-        spinboxes: make_spinboxes(fs, ca, g, fl),
-        cascade_offset_spinbox: Spinbox::new(co as i32, 0, 200, 1),
-        edge_gap_spinbox: Spinbox::new(gl as i32, 0, 200, 1),
-        top_gap_spinbox: Spinbox::new(gt as i32, 0, 200, 1),
-        grid_gap_spinbox: Spinbox::new(gg as i32, 0, 200, 1),
-        status_height_spinbox: Spinbox::new(sh as i32, 0, 100, 1),
-        transition_duration_spinbox: Spinbox::new(td as i32, 0, 2000, 50),
-        tag_layout_menus,
-        side_panel_behavior_menu,
-        side_panel_position_menu,
-        side_panel_width: spw,
-        side_panel_width_spinbox: Spinbox::new(spw as i32, 0, 2000, 10),
-        side_panel_border_gap: spbg,
-        side_panel_border_gap_spinbox: Spinbox::new(spbg as i32, 0, 500, 1),
-        side_panel_border_opacity: spbo,
-        side_panel_border_opacity_spinbox: Spinbox::new(spbo as i32, 0, 100, 5),
-        transparency_enabled,
-        transparency_toggle: Toggle::new().with_label("Transparency"),
-        blur_enabled,
-        blur_toggle: Toggle::new().with_label("Blur"),
-    }
-}
-
-fn parse_json(content: &str) -> serde_json::Value {
-    serde_json::from_str(content).unwrap_or_default()
-}
-
-fn json_find_key<'a>(val: &'a serde_json::Value, key: &str) -> Option<&'a serde_json::Value> {
-    if let Some(obj) = val.as_object() {
-        for (_, sec_val) in obj.iter() {
-            if let Some(sec_obj) = sec_val.as_object() {
-                if let Some(v) = sec_obj.get(key) {
-                    return Some(v);
-                }
-            }
-        }
-    }
-    None
-}
-
-fn parse_tag_layouts_from_config(content: &str) -> Vec<String> {
-    let val = parse_json(content);
-    let mut modes = vec!["cascade".to_string(); 4];
-    if let Some(arr) = val.get("tag_layout").and_then(|t| t.as_array()) {
-        for item in arr {
-            if let (Some(tag), Some(mode)) = (
-                item.get("tag").and_then(|t| t.as_u64()),
-                item.get("mode").and_then(|m| m.as_str())
-            ) {
-                if tag >= 1 && tag <= 4 {
-                    modes[tag as usize - 1] = mode.to_string();
-                }
-            }
-        }
-    }
-    modes
-}
-
-fn write_tag_layout(tag_num: usize, mode_str: &str) -> bool {
-    let content = fs::read_to_string(CONFIG_PATH).unwrap_or_default();
-    let mut val = parse_json(&content);
-    
-    let mut found = false;
-    if let Some(arr) = val.get_mut("tag_layout").and_then(|t| t.as_array_mut()) {
-        for item in arr.iter_mut() {
-            if item.get("tag").and_then(|t| t.as_u64()) == Some(tag_num as u64) {
-                if let Some(obj) = item.as_object_mut() {
-                    obj.insert("mode".to_string(), serde_json::json!(mode_str.to_lowercase()));
-                    found = true;
-                    break;
-                }
-            }
-        }
-        if !found {
-            arr.push(serde_json::json!({
-                "tag": tag_num,
-                "mode": mode_str.to_lowercase()
-            }));
-        }
-    } else {
-        let arr = vec![serde_json::json!({
-            "tag": tag_num,
-            "mode": mode_str.to_lowercase()
-        })];
-        if let Some(obj) = val.as_object_mut() {
-            obj.insert("tag_layout".to_string(), serde_json::Value::Array(arr));
-        }
-    }
-    
-    if let Ok(updated_str) = serde_json::to_string_pretty(&val) {
-        return fs::write(CONFIG_PATH, updated_str).is_ok();
-    }
-    false
-}
-
-fn parse_u16_from(content: &str, key: &str, default: u16) -> u16 {
-    let val = parse_json(content);
-    json_find_key(&val, key).and_then(|v| v.as_u64()).map(|n| n as u16).unwrap_or(default)
-}
-
-fn parse_string_from(content: &str, key: &str, default: &str) -> String {
-    let val = parse_json(content);
-    json_find_key(&val, key).and_then(|v| v.as_str()).map(|s| s.to_string()).unwrap_or_else(|| default.to_string())
-}
-
-fn write_config_value(key: &str, value: &str) -> bool {
-    super::interface::write_config_value_path(CONFIG_PATH, key, value)
-}
-
-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 apply_all_widths(s: &LayoutState) {
-    let w = |k: &str, v: u16| { write_config_value(k, &v.to_string()); send_ipc_command(&format!("layout {} {}", k, v)); };
-    w("fullscreen_border_width", s.fullscreen_border_width);
-    w("cascade_border_width", s.cascade_border_width);
-    w("grid_border_width", s.grid_border_width);
-    w("floating_border_width", s.floating_border_width);
-    w("cascade_offset", s.cascade_offset);
-    w("gap_left", s.edge_gap);
-    w("gap_right", s.edge_gap);
-    w("gap_bottom", s.edge_gap);
-    w("gap_top", s.top_gap);
-    w("transition_duration", s.transition_duration);
-}
-
-fn apply_single_layout_param(key: &str, val: u16) {
-    write_config_value(key, &val.to_string());
-    send_ipc_command(&format!("layout {} {}", key, val));
-}
-
-fn apply_edge_gap(val: u16) {
-    let val_str = val.to_string();
-    write_config_value("gap_left", &val_str);
-    write_config_value("gap_right", &val_str);
-    write_config_value("gap_bottom", &val_str);
-    send_ipc_command(&format!("layout gap_left {}", val));
-    send_ipc_command(&format!("layout gap_right {}", val));
-    send_ipc_command(&format!("layout gap_bottom {}", val));
-}
-
-#[derive(Debug, Clone)]
-#[allow(dead_code)]
-struct PreviewWindow {
-    app_id: String,
-    title: String,
-    x: f32,
-    y: f32,
-    w: f32,
-    h: f32,
-    tags: u32,
-    _minimized: bool,
-    has_parent: bool,
-    layout_mode: String,
-}
-
-#[allow(dead_code)]
-struct LayoutStatusInfo {
-    active_tags: u32,
-    focused_tags: u32,
-    _num_tags: u32,
-    windows: Vec<PreviewWindow>,
-    focused_title: String,
-    focused_layout_mode: String,
-}
-
-fn read_current_layout_status() -> LayoutStatusInfo {
-    let mut active_tags = 1;
-    let mut focused_tags = 1;
-    let mut _num_tags = 4;
-
-    let display = std::env::var("WAYLAND_DISPLAY").unwrap_or_else(|_| "wayland-0".to_string());
-    
-    let tags_path = format!("/tmp/cce-tags-{}", display);
-    let tags_fallback = "/tmp/cce-tags".to_string();
-    let tags_content = fs::read_to_string(&tags_path)
-        .or_else(|_| fs::read_to_string(&tags_fallback))
-        .unwrap_or_default();
-
-    if let Some(line) = tags_content.lines().next() {
-        let parts: Vec<&str> = line.split_whitespace().collect();
-        if parts.len() >= 3 {
-            active_tags = parts[0].parse().unwrap_or(1);
-            focused_tags = parts[1].parse().unwrap_or(1);
-            _num_tags = parts[2].parse().unwrap_or(4);
-        }
-    }
-
-    let title_path = format!("/tmp/cce-title-{}", display);
-    let title_fallback = "/tmp/cce-title".to_string();
-    let focused_title = fs::read_to_string(&title_path)
-        .or_else(|_| fs::read_to_string(&title_fallback))
-        .unwrap_or_default()
-        .trim()
-        .to_string();
-
-    let layout_path = format!("/tmp/cce-layout-{}", display);
-    let layout_fallback = "/tmp/cce-layout".to_string();
-    let focused_layout_mode = fs::read_to_string(&layout_path)
-        .or_else(|_| fs::read_to_string(&layout_fallback))
-        .unwrap_or_else(|_| "Cascade".to_string())
-        .trim()
-        .to_string();
-
-    let windows_path = format!("/tmp/cce-windows-{}", display);
-    let windows_fallback = "/tmp/cce-windows".to_string();
-    let windows_content = fs::read_to_string(&windows_path)
-        .or_else(|_| fs::read_to_string(&windows_fallback))
-        .unwrap_or_default();
-
-    let mut windows = Vec::new();
-    for line in windows_content.lines() {
-        if !line.starts_with("window ") { continue; }
-        
-        let mut app_id = String::new();
-        let mut title = String::new();
-        let mut x = 0.0;
-        let mut y = 0.0;
-        let mut w = 0.0;
-        let mut h = 0.0;
-        let mut tags = 0;
-        let mut minimized = false;
-        let mut has_parent = false;
-        let mut layout_mode = "Cascade".to_string();
-        
-        let parts = line.strip_prefix("window ").unwrap_or(line);
-        
-        let get_val = |p: &str, k: &str| -> Option<String> {
-            if let Some(idx) = p.find(k) {
-                let start = idx + k.len();
-                let mut end = p.len();
-                let next_keys = [
-                    " app_id=", " title=", " mode=", " decoration=", " presentation=",
-                    " tags=", " x=", " y=", " w=", " h=", " has_parent=", " minimized="
-                ];
-                for nk in next_keys {
-                    if nk != k {
-                        if let Some(nidx) = p[start..].find(nk) {
-                            end = end.min(start + nidx);
-                        }
-                    }
-                }
-                Some(p[start..end].trim().to_string())
-            } else {
-                None
-            }
-        };
-
-        if let Some(val) = get_val(parts, "app_id=") { app_id = val; }
-        if let Some(val) = get_val(parts, "title=") { title = val; }
-        if let Some(val) = get_val(parts, "x=") { x = val.parse().unwrap_or(0.0); }
-        if let Some(val) = get_val(parts, "y=") { y = val.parse().unwrap_or(0.0); }
-        if let Some(val) = get_val(parts, "w=") { w = val.parse().unwrap_or(0.0); }
-        if let Some(val) = get_val(parts, "h=") { h = val.parse().unwrap_or(0.0); }
-        if let Some(val) = get_val(parts, "tags=") { tags = val.parse().unwrap_or(0); }
-        if let Some(val) = get_val(parts, "minimized=") { minimized = val == "true"; }
-        if let Some(val) = get_val(parts, "has_parent=") { has_parent = val == "true"; }
-        if let Some(val) = get_val(parts, "mode=") { layout_mode = val; }
-
-        windows.push(PreviewWindow {
-            app_id,
-            title,
-            x,
-            y,
-            w,
-            h,
-            tags,
-            _minimized: minimized,
-            has_parent,
-            layout_mode,
-        });
-    }
-
-    LayoutStatusInfo {
-        active_tags,
-        focused_tags,
-        _num_tags,
-        windows,
-        focused_title,
-        focused_layout_mode,
-    }
-}
-
-pub fn view(state: &mut LayoutState, 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 = 320.0f32;
-    let mut builder = PageLayoutBuilder::new(layout, cx, cy, cw, ch, sec_w).with_section_count(9);
-
-    // Current Layout Section (Read-only visual preview)
-    builder.add_section(&mut final_pc, "Current Layout", false, |sec_cl| {
-        sec_cl.spacing(8.0);
-        
-        let info = read_current_layout_status();
-        
-        let card_w = (sec_w - 24.0) / 2.0;
-        let card_h = 135.0;
-        let rx = sec_cl.left;
-        
-        for tag_idx in 0..4 {
-            let col = tag_idx % 2;
-            let row = tag_idx / 2;
-            let tx = rx + 8.0 + col as f32 * (card_w + 8.0);
-            let ty = sec_cl.ay() + row as f32 * (card_h + 8.0);
-            
-            let is_active = (info.active_tags & (1 << tag_idx)) != 0;
-            let layout_idx = state.tag_layout_menus.get(tag_idx).map(|m| m.selected).unwrap_or(0);
-            let mode = match layout_idx {
-                1 => PreviewLayoutMode::Cascade,
-                2 => PreviewLayoutMode::Stack,
-                3 => PreviewLayoutMode::Grid,
-                4 => PreviewLayoutMode::LeftTiled,
-                5 => PreviewLayoutMode::RightTiled,
-                6 => PreviewLayoutMode::Equal,
-                7 => PreviewLayoutMode::Spiral,
-                8 => PreviewLayoutMode::Floating,
-                _ => PreviewLayoutMode::Fullscreen,
-            };
-
-            let mut preview = LayoutPreview::new(mode)
-                .with_active(is_active)
-                .with_label(&format!("TAG {}", tag_idx + 1));
-            render_widget(sec_cl.pc, &mut preview, tx, ty, card_w, card_h, ctx);
-        }
-        
-        sec_cl.content_y += 2.0 * (card_h + 8.0) + 4.0;
-    });
-
-    // 1. Fullscreen Section
-    builder.add_section(&mut final_pc, "Fullscreen", sec_focused.get(0).copied().unwrap_or(false), |sec_fs| {
-        sec_fs.spacing(8.0);
-        state.spinboxes[0].set_label("Border Width");
-        sec_fs.widget_full(&mut state.spinboxes[0], 44.0, ctx);
-        sec_fs.spacing(8.0);
-    });
-
-    // 2. Cascade Section
-    builder.add_section(&mut final_pc, "Cascade", sec_focused.get(1).copied().unwrap_or(false), |sec_cascade| {
-        sec_cascade.spacing(8.0);
-        state.spinboxes[1].set_label("Border Width");
-        sec_cascade.widget_full(&mut state.spinboxes[1], 44.0, ctx);
-        sec_cascade.spacing(8.0);
-        state.cascade_offset_spinbox.set_label("Offset");
-        sec_cascade.widget_full(&mut state.cascade_offset_spinbox, 44.0, ctx);
-        sec_cascade.spacing(8.0);
-        state.edge_gap_spinbox.set_label("Edge Gap");
-        sec_cascade.widget_full(&mut state.edge_gap_spinbox, 44.0, ctx);
-        sec_cascade.spacing(8.0);
-        state.top_gap_spinbox.set_label("Top Gap");
-        sec_cascade.widget_full(&mut state.top_gap_spinbox, 44.0, ctx);
-        sec_cascade.spacing(8.0);
-    });
-
-    // 3. Grid Section
-    builder.add_section(&mut final_pc, "Grid", sec_focused.get(2).copied().unwrap_or(false), |sec_grid| {
-        sec_grid.spacing(8.0);
-        state.spinboxes[2].set_label("Border Width");
-        sec_grid.widget_full(&mut state.spinboxes[2], 44.0, ctx);
-        sec_grid.spacing(8.0);
-        state.grid_gap_spinbox.set_label("Gap");
-        sec_grid.widget_full(&mut state.grid_gap_spinbox, 44.0, ctx);
-        sec_grid.spacing(8.0);
-    });
-
-    // 4. Floating Section
-    builder.add_section(&mut final_pc, "Floating", sec_focused.get(3).copied().unwrap_or(false), |sec_float| {
-        sec_float.spacing(8.0);
-        state.spinboxes[3].set_label("Border Width");
-        sec_float.widget_full(&mut state.spinboxes[3], 44.0, ctx);
-        sec_float.spacing(8.0);
-    });
-
-    // 5. Movement Section
-    builder.add_section(&mut final_pc, "Movement", sec_focused.get(4).copied().unwrap_or(false), |movement_sec| {
-        movement_sec.spacing(8.0);
-        state.transition_duration_spinbox.set_label("Duration (ms)");
-        movement_sec.widget_full(&mut state.transition_duration_spinbox, 44.0, ctx);
-        movement_sec.spacing(8.0);
-    });
-
-    // 6. Default Layouts Section
-    builder.add_section(&mut final_pc, "Default Layouts", true, |default_layouts_sec| {
-        default_layouts_sec.spacing(8.0);
-        for i in 0..4 {
-            default_layouts_sec.widget_full(&mut state.tag_layout_menus[i], 44.0, ctx);
-            default_layouts_sec.spacing(8.0);
-        }
-    });
-
-    // 7. Side Panel Section
-    builder.add_section(&mut final_pc, "Side Panel", true, |side_panel_sec| {
-        side_panel_sec.spacing(8.0);
-        side_panel_sec.widget_full(&mut state.side_panel_behavior_menu, 44.0, ctx);
-        side_panel_sec.spacing(8.0);
-        side_panel_sec.widget_full(&mut state.side_panel_position_menu, 44.0, ctx);
-        side_panel_sec.spacing(8.0);
-        state.side_panel_width_spinbox.set_label("Default Width");
-        side_panel_sec.widget_full(&mut state.side_panel_width_spinbox, 44.0, ctx);
-        side_panel_sec.spacing(8.0);
-        state.side_panel_border_gap_spinbox.set_label("Border Gap");
-        side_panel_sec.widget_full(&mut state.side_panel_border_gap_spinbox, 44.0, ctx);
-        side_panel_sec.spacing(8.0);
-        state.side_panel_border_opacity_spinbox.set_label("Border Opacity");
-        side_panel_sec.widget_full(&mut state.side_panel_border_opacity_spinbox, 44.0, ctx);
-        side_panel_sec.spacing(8.0);
-    });
-
-    // 8. Effects Section
-    builder.add_section(&mut final_pc, "Effects", true, |effects_sec| {
-        effects_sec.spacing(8.0);
-        state.transparency_toggle.set_toggled(state.transparency_enabled);
-        effects_sec.widget_full(&mut state.transparency_toggle, cce_ui::layout::toggle_height(), ctx);
-        effects_sec.spacing(8.0);
-        state.blur_toggle.set_toggled(state.blur_enabled);
-        effects_sec.widget_full(&mut state.blur_toggle, cce_ui::layout::toggle_height(), ctx);
-        effects_sec.spacing(8.0);
-    });
-
-
-    final_pc
-}
-
-fn set_width(state: &mut LayoutState, param: WidthParam, val: u16) {
-    let val = val.min(100);
-    match param {
-        WidthParam::Fullscreen => state.fullscreen_border_width = val,
-        WidthParam::Cascade => state.cascade_border_width = val,
-        WidthParam::Grid => state.grid_border_width = val,
-        WidthParam::Floating => state.floating_border_width = val,
-    }
-    state.spinboxes[param_idx(param)].value = val as i32;
-    apply_all_widths(state);
-}
-
-fn param_idx(p: WidthParam) -> usize {
-    match p {
-        WidthParam::Fullscreen => 0,
-        WidthParam::Cascade => 1,
-        WidthParam::Grid => 2,
-        WidthParam::Floating => 3,
-    }
-}
-
-pub fn update(state: &mut LayoutState, msg: LayoutMessage) {
-    match msg {
-        LayoutMessage::SetWidth(p, v) => set_width(state, p, v),
-        LayoutMessage::SetCascadeOffset(v) => {
-            let val = v.min(200);
-            state.cascade_offset = val;
-            state.cascade_offset_spinbox.value = val as i32;
-            apply_single_layout_param("cascade_offset", val);
-        }
-        LayoutMessage::SetEdgeGap(v) => {
-            let val = v.min(200);
-            state.edge_gap = val;
-            state.edge_gap_spinbox.value = val as i32;
-            apply_edge_gap(val);
-        }
-        LayoutMessage::SetTopGap(v) => {
-            let val = v.min(200);
-            state.top_gap = val;
-            state.top_gap_spinbox.value = val as i32;
-            apply_single_layout_param("gap_top", val);
-        }
-        LayoutMessage::SetGridGap(v) => {
-            let val = v.min(200);
-            state.grid_gap = val;
-            state.grid_gap_spinbox.value = val as i32;
-            apply_single_layout_param("grid_gap", val);
-        }
-        LayoutMessage::SetTransitionDuration(v) => {
-            let val = v.min(2000);
-            state.transition_duration = val;
-            state.transition_duration_spinbox.value = val as i32;
-            apply_single_layout_param("transition_duration", val);
-        }
-        LayoutMessage::SetStatusHeight(v) => {
-            let val = v.min(100);
-            state.status_height = val;
-            state.status_height_spinbox.value = val as i32;
-            apply_single_layout_param("bar_height", val);
-        }
-        LayoutMessage::SetTagLayout(tag, idx) => {
-            if tag >= 1 && tag <= 4 && idx < 5 {
-                state.tag_layout_menus[tag - 1].selected = idx;
-                let modes = vec!["cascade", "grid", "fullscreen", "floating", "popup"];
-                let mode_str = modes[idx];
-                write_tag_layout(tag, mode_str);
-                send_ipc_command(&format!("tag-layout {} {}", tag, mode_str));
-            }
-        }
-        LayoutMessage::SetSidePanelBehavior(idx) => {
-            if idx < 2 {
-                state.side_panel_behavior_menu.selected = idx;
-                let val = if idx == 0 { "above" } else { "inline" };
-                write_config_value("side_panel_behavior", &format!("\"{}\"", val));
-                send_ipc_command(&format!("layout side_panel_behavior {}", val));
-            }
-        }
-        LayoutMessage::SetSidePanelPosition(idx) => {
-            if idx < 2 {
-                state.side_panel_position_menu.selected = idx;
-                let val = if idx == 1 { "right" } else { "left" };
-                write_config_value("side_panel_position", &format!("\"{}\"", val));
-                send_ipc_command(&format!("layout side_panel_position {}", val));
-            }
-        }
-        LayoutMessage::SetSidePanelWidth(v) => {
-            let val = v.min(2000);
-            state.side_panel_width = val;
-            state.side_panel_width_spinbox.value = val as i32;
-            write_config_value("side_panel_width", &val.to_string());
-            send_ipc_command(&format!("layout side_panel_width {}", val));
-        }
-        LayoutMessage::SetSidePanelBorderGap(v) => {
-            let val = v.min(500);
-            state.side_panel_border_gap = val;
-            state.side_panel_border_gap_spinbox.value = val as i32;
-            write_config_value("side_panel_border_gap", &val.to_string());
-            send_ipc_command(&format!("layout side_panel_border_gap {}", val));
-        }
-        LayoutMessage::SetSidePanelBorderOpacity(v) => {
-            let val = v.min(100);
-            state.side_panel_border_opacity = val;
-            state.side_panel_border_opacity_spinbox.value = val as i32;
-            write_config_value("side_panel_border_opacity", &val.to_string());
-            send_ipc_command(&format!("layout side_panel_border_opacity {}", val));
-        }
-        LayoutMessage::ToggleTransparency => {
-            state.transparency_enabled = !state.transparency_enabled;
-            if state.transparency_enabled {
-                write_transparency_config_value("opacity", "0.85");
-            } else {
-                write_transparency_config_value("opacity", "1.00");
-            }
-            send_ipc_command("reload");
-            status_interface_reload();
-        }
-        LayoutMessage::ToggleBlur => {
-            state.blur_enabled = !state.blur_enabled;
-            let val = state.blur_enabled.to_string();
-            write_config_value("window_blur", &val);
-            write_config_value("border_blur", &val);
-            send_ipc_command("reload");
-        }
-        LayoutMessage::Refreshed(new) => {
-            let transparency_hover = state.transparency_toggle.hovered();
-            let blur_hover = state.blur_toggle.hovered();
-            *state = new;
-            state.transparency_toggle.set_hovered(transparency_hover);
-            state.blur_toggle.set_hovered(blur_hover);
-        }
-    }
-}
-
-#[cfg(test)]
-mod tests {
-    use super::*;
-
-    #[test]
-    fn test_parse_tag_layouts_empty() {
-        let content = "";
-        let modes = parse_tag_layouts_from_config(content);
-        assert_eq!(modes, vec!["cascade", "cascade", "cascade", "cascade"]);
-    }
-
-    #[test]
-    fn test_parse_side_panel_width_default() {
-        let content = "";
-        let width = parse_u16_from(content, "side_panel_width", 360);
-        assert_eq!(width, 360);
-    }
-
-    #[test]
-    fn test_parse_side_panel_width_explicit() {
-        let content = "{\"layout\": {\"side_panel_width\": 450}}";
-        let width = parse_u16_from(content, "side_panel_width", 360);
-        assert_eq!(width, 450);
-    }
-
-    #[test]
-    fn test_parse_side_panel_border_opacity_default() {
-        let content = "";
-        let opacity = parse_u16_from(content, "side_panel_border_opacity", 100);
-        assert_eq!(opacity, 100);
-    }
-
-    #[test]
-    fn test_parse_side_panel_border_opacity_explicit() {
-        let content = "{\"layout\": {\"side_panel_border_opacity\": 75}}";
-        let opacity = parse_u16_from(content, "side_panel_border_opacity", 100);
-        assert_eq!(opacity, 75);
-    }
-
-    #[test]
-    fn test_parse_tag_layouts_single() {
-        let content = r#"{
-            "layout": {"gap": 10},
-            "tag_layout": [
-                {"tag": 2, "mode": "grid"}
-            ]
-        }"#;
-        let modes = parse_tag_layouts_from_config(content);
-        assert_eq!(modes, vec!["cascade", "grid", "cascade", "cascade"]);
-    }
-
-    #[test]
-    fn test_parse_tag_layouts_multiple() {
-        let content = r#"{
-            "tag_layout": [
-                {"tag": 1, "mode": "fullscreen"},
-                {"tag": 4, "mode": "floating"}
-            ]
-        }"#;
-        let modes = parse_tag_layouts_from_config(content);
-        assert_eq!(modes, vec!["fullscreen", "cascade", "cascade", "floating"]);
-    }
-
-    #[test]
-    fn test_parse_tag_layouts_out_of_bounds() {
-        let content = r#"{
-            "tag_layout": [
-                {"tag": 5, "mode": "grid"},
-                {"tag": 0, "mode": "popup"}
-            ]
-        }"#;
-        let modes = parse_tag_layouts_from_config(content);
-        assert_eq!(modes, vec!["cascade", "cascade", "cascade", "cascade"]);
-    }
-
-    #[test]
-    fn test_view_layout_grid() {
-        let mut state = LayoutState::default();
-        let mut layout = cce_ui::layout::ColumnLayout::new(20.0);
-        let pc = view(&mut state, 10.0, 20.0, 800.0, 600.0, &[false, false, false, false], &mut layout, &mut cce_ui::context::UiContext::new());
-        assert!(!pc.rects.is_empty() || !pc.texts.is_empty());
-    }
-
-    #[test]
-    fn test_spinbox_right_click() {
-        use cce_ui::widget::Element;
-        let mut state = LayoutState::default();
-        let mut ctx = cce_ui::context::UiContext::new();
-        let sb = &mut state.spinboxes[0];
-        sb.set_rect(0.0, 0.0, 100.0, 44.0);
-        let res = sb.mouse_input(
-            cce_ui::widget::MouseButton::Right,
-            cce_ui::widget::ElementState::Pressed,
-            50.0,
-            20.0,
-            &mut ctx,
-        );
-        assert!(res);
-    }
-
-    #[test]
-    #[allow(unused_assignments)]
-    fn test_spinbox_right_click_crash() {
-        use cce_ui::widget::Element;
-        let mut state = LayoutState::default();
-        let mut ctx = cce_ui::context::UiContext::new();
-        let sb = &mut state.spinboxes[0];
-        sb.set_rect(0.0, 0.0, 100.0, 44.0);
-        let res = sb.mouse_input(
-            cce_ui::widget::MouseButton::Right,
-            cce_ui::widget::ElementState::Pressed,
-            50.0,
-            20.0,
-            &mut ctx,
-        );
-        assert!(res);
-        assert!(cce_ui::widget::context_menu::is_visible());
-
-        // Now replace the state simulating config reload/refresh
-        let new_state = LayoutState::default();
-        state = new_state;
-
-        // Assert that the context menu is hidden (cleared)
-        assert!(!cce_ui::widget::context_menu::is_visible());
-    }
-}
-
diff --git a/src/pages/mod.rs b/src/pages/mod.rs
index d96c261..ffecbab 100644
--- a/src/pages/mod.rs
+++ b/src/pages/mod.rs
@@ -1,7 +1,6 @@
 pub mod audio;
 pub mod network;
 pub mod display;
-pub mod layout;
 pub mod storage;
 pub mod system_info;
 pub mod keybindings;
@@ -20,7 +19,6 @@ pub enum Page {
     Services,
     Storage,
     Display,
-    Layout,
     System,
     Hardware,
     Input,
@@ -29,7 +27,7 @@ pub enum Page {
 }
 
 impl Page {
-    pub const ALL: [Page; 12] = [
+    pub const ALL: [Page; 11] = [
         Page::Accounts,
         Page::Audio,
         Page::Display,
@@ -41,7 +39,6 @@ impl Page {
         Page::Services,
         Page::Storage,
         Page::System,
-        Page::Layout,
     ];
 
     pub fn label(self) -> &'static str {
@@ -52,7 +49,6 @@ impl Page {
             Page::Services => "Services",
             Page::Storage => "Storage",
             Page::Display => "Display",
-            Page::Layout => "Window Manager",
             Page::System => "System",
             Page::Hardware => "Hardware",
             Page::Input => "Input",