status bar
git clone https://git.lucas.co/cce-status-interface.git
feat(menu): window-mode dropdown in the window module's menu
The mode readout in the window module's right-click menu becomes a
dropdown when the mode is user-settable (Floating/Tiled/Fullscreen): the
row opens a submenu page listing the three modes, the current one marked
[x] and disabled, and picking another runs ccectl set-mode <mode> on the
focused window (status segments never take seat focus, so the target is
the real window). Internal roles and the no-focus readout stay inert.
Needs cce-fx with the set-mode IPC command (cce-compositor@71fdd88).
Co-Authored-By: Claude Fable 5 <[email protected]>
src/main.rs | 63 +++++++++++++++++++++++++++++++++++++++++++++++++++++--------
1 file changed, 55 insertions(+), 8 deletions(-)
diff --git a/src/main.rs b/src/main.rs
index ab3bd3b..c5f81f5 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -2122,17 +2122,64 @@ impl cce_ui::engine::Application for StatusApp {
});
}
// The window module's strip shows only the title; the
- // focused window's mode lives here in its menu.
+ // focused window's mode lives here in its menu — as a
+ // dropdown when the mode is one a user may set, opening
+ // a submenu page whose rows run `ccectl set-mode <mode>`
+ // on the focused window (status segments never take seat
+ // focus, so "focused" is still the real window).
+ let mut extra_pages: Vec<MenuPage> = Vec::new();
if mb.name == "window" && !self.layout.is_empty() {
- rows.insert(0, MenuRow {
- label: self.layout.clone(),
- enabled: true,
- separator: false,
- action: MenuRowAction::Inert,
- });
+ const MODES: [&str; 3] = ["Floating", "Tiled", "Fullscreen"];
+ if MODES.contains(&self.layout.as_str()) {
+ // Page 0 is the root built below; the mode page is
+ // the only extra, so it is always page 1.
+ rows.insert(0, MenuRow {
+ label: format!("{} >", self.layout),
+ enabled: true,
+ separator: false,
+ action: MenuRowAction::Submenu(1),
+ });
+ let mut mode_rows = vec![MenuRow {
+ label: "< Back".to_string(),
+ enabled: true,
+ separator: false,
+ action: MenuRowAction::Back(0),
+ }];
+ for mode in MODES {
+ let current = mode == self.layout;
+ mode_rows.push(MenuRow {
+ label: format!(
+ "{} {}",
+ if current { "[x]" } else { "[ ]" },
+ mode
+ ),
+ // The current mode is a marker, not a
+ // target — disabled rows never match a
+ // click.
+ enabled: !current,
+ separator: false,
+ action: MenuRowAction::Ccectl(vec![
+ "set-mode".to_string(),
+ mode.to_lowercase(),
+ ]),
+ });
+ }
+ extra_pages.push(MenuPage { title: "Mode".to_string(), rows: mode_rows });
+ } else {
+ // Internal roles (Popup/Overlay/Status/Utility)
+ // and the no-focus "---" stay a plain readout.
+ rows.insert(0, MenuRow {
+ label: self.layout.clone(),
+ enabled: true,
+ separator: false,
+ action: MenuRowAction::Inert,
+ });
+ }
}
+ let mut pages = vec![MenuPage { title: mb.name.clone(), rows }];
+ pages.extend(extra_pages);
self.context_menu = Some(ModuleContextMenu {
- pages: vec![MenuPage { title: mb.name.clone(), rows }],
+ pages,
page: 0,
tray_target: None,
min_w: 190.0,