Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
96 changes: 96 additions & 0 deletions mangowm-status/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
# Mangowm Status

Shows the current Mangowm tiling layout and keymode on your bar. Click to open a picker and switch layouts instantly.

![Thumbnail](thumbnail.webp)

## Plugin

| Field | Value |
| --- | --- |
| ID | `x0d7x/mangowm-status` |
| Entries | Bar widget: `status`; panel: `layout-picker` |

## Requirements

- Noctalia v5
- [`mmsg`](https://github.com/mangowm/mango) — Mangowm's IPC CLI tool (must be on `PATH`)

## Usage

### Bar widget

Add the **Mangowm Status** widget from the Add-widget picker in your bar settings, or configure it by hand with:

```toml
[widget.mangowm-status]
type = "x0d7x/mangowm-status:status"
```

The widget displays the current layout's icon and letter code. When the active keymode is not `default`, the keymode name is shown beside the layout code.

- **Left-click** the widget → opens the **Layout Picker** panel. Click any layout to switch immediately.
- **Horizontal scroll** over the widget → cycles through the core layouts (T → S → G → …).

### Layout picker panel

Open with:

```sh
noctalia msg panel-toggle x0d7x/mangowm-status:layout-picker
```

A scrollable list of all 14 supported layouts. The current layout is highlighted. Click any other layout to switch — the panel closes automatically.

## Settings

| Setting | Type | Default | Description |
| --- | --- | --- | --- |
| Hide on default | `bool` | `false` | Hide the widget when keymode is `default` |
| Show text | `bool` | `true` | Show the keymode name beside the layout glyph |
| Notify on change | `bool` | `true` | Show a notification when the keymode changes |

## IPC

Control the widget from the terminal:

```sh
# Refresh layout data
noctalia msg plugin x0d7x/mangowm-status:status focused refresh

# Get current status (logged as JSON)
noctalia msg plugin x0d7x/mangowm-status:status focused get-status

# Set layout by code (T, S, G, M, K, CT, RT, DW, F, VS, VT, VG, VK, VF)
noctalia msg plugin x0d7x/mangowm-status:status focused set-layout S
```

## Layout Codes

| Code | Layout | Icon |
|------|--------|------|
| T | Tile | columns |
| S | Scroller | menu |
| G | Grid | dashboard |
| M | Monocle | window |
| K | Deck | cards |
| CT | Center Tile | layout |
| RT | Right Tile | columns |
| DW | Dwindle | columns |
| F | Fair | layout |
| VS | Vertical Scroller | menu |
| VT | Vertical Tile | columns |
| VG | Vertical Grid | dashboard |
| VK | Vertical Deck | cards |
| VF | Vertical Fair | layout |

## Notes

- This plugin spawns `mmsg` subprocesses to query and change the compositor state. `mmsg` must be installed and on `PATH`.
- Layout changes use `mmsg dispatch setlayout,<name>`.
- The widget keeps two long-running `mmsg watch` streams (keymode + all-tags) for live updates, with a 1-second polling fallback.
- The panel entry fetches tag data on open and does not keep a persistent connection.

## License

MIT
135 changes: 135 additions & 0 deletions mangowm-status/panel.luau
Original file line number Diff line number Diff line change
@@ -0,0 +1,135 @@
--!nonstrict
-- Mangowm Status — Layout Picker Panel
-- Shows all available tiling layouts; click one to switch immediately.

-- Layout manifest: glyph + letter + name (same as widget.luau)
local layoutConfig = {
T = { glyph = "columns", letter = "T", name = "tile" },
S = { glyph = "menu", letter = "S", name = "scroller" },
G = { glyph = "dashboard", letter = "G", name = "grid" },
M = { glyph = "window", letter = "M", name = "monocle" },
K = { glyph = "cards", letter = "K", name = "deck" },
CT = { glyph = "layout", letter = "C", name = "center_tile" },
RT = { glyph = "columns", letter = "R", name = "right_tile" },
VS = { glyph = "menu", letter = "V", name = "vertical_scroller" },
VT = { glyph = "columns", letter = "V", name = "vertical_tile" },
VG = { glyph = "dashboard", letter = "G", name = "vertical_grid" },
VK = { glyph = "cards", letter = "K", name = "vertical_deck" },
DW = { glyph = "columns", letter = "D", name = "dwindle" },
F = { glyph = "layout", letter = "F", name = "fair" },
VF = { glyph = "layout", letter = "F", name = "vertical_fair" },
}

-- Layout codes in display order
local layoutOrder = { "T", "S", "G", "M", "K", "CT", "RT", "DW", "F", "VS", "VT", "VG", "VK", "VF" }

local currentLayoutCode = "T"
local switching = false

-- Helper to switch layout and close panel
local function setLayout(code)
if switching or code == currentLayoutCode then return end
switching = true

local cfg = layoutConfig[code]
local name = cfg and cfg.name or "tile"
noctalia.runAsync("mmsg dispatch setlayout," .. name, function(result)
switching = false
if result.exitCode == 0 then
currentLayoutCode = code
panel.close()
else
noctalia.notifyError("Mangowm Status", "Failed to set layout: " .. (result.stderr or "unknown error"))
doRender()
end
end)
end

-- Named global functions for each layout button (onClick doesn't pass arguments)
function onLayoutT() setLayout("T") end
function onLayoutS() setLayout("S") end
function onLayoutG() setLayout("G") end
function onLayoutM() setLayout("M") end
function onLayoutK() setLayout("K") end
function onLayoutCT() setLayout("CT") end
function onLayoutRT() setLayout("RT") end
function onLayoutDW() setLayout("DW") end
function onLayoutF() setLayout("F") end
function onLayoutVS() setLayout("VS") end
function onLayoutVT() setLayout("VT") end
function onLayoutVG() setLayout("VG") end
function onLayoutVK() setLayout("VK") end
function onLayoutVF() setLayout("VF") end

local function doRender()
-- Map layout code -> onClick handler name
local onClickHandler = {
T = "onLayoutT", S = "onLayoutS", G = "onLayoutG",
M = "onLayoutM", K = "onLayoutK", CT = "onLayoutCT",
RT = "onLayoutRT", DW = "onLayoutDW", F = "onLayoutF",
VS = "onLayoutVS", VT = "onLayoutVT", VG = "onLayoutVG",
VK = "onLayoutVK", VF = "onLayoutVF",
}

-- Current layout indicator (compact, shown at top)
local currentCfg = layoutConfig[currentLayoutCode] or layoutConfig["T"]
local currentBadge = ui.row({ gap = 6, align = "center", fill = "primary/0.12", radius = 6, paddingH = 10, paddingV = 5 }, {
ui.label({ text = "Now:", color = "on_surface_variant", fontSize = 11 }),
ui.glyph({ name = currentCfg.glyph, size = 12, color = "primary" }),
ui.label({ text = currentCfg.letter .. " — " .. currentCfg.name, color = "primary", fontWeight = "bold", fontSize = 11 }),
})

-- Build layout buttons
local buttons = {}
for _, code in ipairs(layoutOrder) do
local cfg = layoutConfig[code]
if cfg then
local isActive = code == currentLayoutCode
table.insert(buttons, ui.button({
key = "layout-" .. code,
glyph = cfg.glyph,
glyphSize = 14,
text = " " .. cfg.letter .. " — " .. cfg.name,
contentAlign = "start",
variant = isActive and "primary" or "ghost",
controlSize = "sm",
onClick = onClickHandler[code],
}))
end
end

panel.render(ui.column({ flexGrow = 1, gap = 2, padding = 8 }, {
currentBadge,
ui.separator({ thickness = 1, color = "outline/0.15", spacing = 3 }),
ui.scroll({ flexGrow = 1, gap = 2 }, buttons),
}))
end

-- Fetch current layout from mmsg, then render
local function refreshCurrentLayout()
noctalia.runAsync("mmsg get all-tags", function(result)
if result.exitCode == 0 and result.stdout then
local ok, data = pcall(noctalia.json.decode, result.stdout)
if ok and data and data.all_tags then
for _, monitorEntry in ipairs(data.all_tags) do
if type(monitorEntry) == "table" and monitorEntry.tags then
for _, tag in ipairs(monitorEntry.tags) do
if type(tag) == "table" and tag.is_active and tag.layout then
currentLayoutCode = tag.layout
doRender()
return
end
end
end
end
end
end
-- Render even if fetch failed (uses fallback currentLayoutCode)
doRender()
end)
end

function onOpen(_context)
-- Fetch current layout first, then render (avoids flash of wrong layout)
refreshCurrentLayout()
end
44 changes: 44 additions & 0 deletions mangowm-status/plugin.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
id = "x0d7x/mangowm-status"
name = "Mangowm Status"
version = "1.1.0"
plugin_api = 4
author = "x0d7x"
license = "MIT"
dependencies = ["mmsg"]
icon = "grid"
description = "Shows current tiling layout and keymode for Mangowm"
tags = ["bar", "mangowc"]

[[widget]]
id = "status"
entry = "widget.luau"

[[widget.setting]]
key = "hide_on_default"
type = "bool"
label_key = "settings.hide_on_default.label"
description_key = "settings.hide_on_default.description"
default = false

[[widget.setting]]
key = "show_text"
type = "bool"
label_key = "settings.show_text.label"
description_key = "settings.show_text.description"
default = true

[[widget.setting]]
key = "notify_change"
type = "bool"
label_key = "settings.notify_change.label"
description_key = "settings.notify_change.description"
default = true

# Layout picker panel — opens on click, shows all layouts to choose from
[[panel]]
id = "layout-picker"
entry = "panel.luau"
width = 280
height = 400
placement = "floating"
position = "auto"
Binary file added mangowm-status/thumbnail.webp
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
19 changes: 19 additions & 0 deletions mangowm-status/translations/en.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
{
"plugin": {
"description": "Shows current tiling layout and keymode for Mangowm"
},
"settings": {
"hide_on_default": {
"label": "Hide on default",
"description": "Hide the widget when keymode is default"
},
"show_text": {
"label": "Show text",
"description": "Show the keymode name beside the glyph"
},
"notify_change": {
"label": "Notify on change",
"description": "Show a notification when keymode changes"
}
}
}
Loading