Add iio-lock plugin for orientation locking (#13)
* Made a iio-hyprland plugin for noctalia kill iio-hyprland and restart it depending on the locked setting. The plugin has: -control center toggle -Bar wigdet for toggle of state --If rigth clicked this wigdet will open the panel -Panel for calling by msg --Panel also added possibally to specify lock direction -Bar wiget for open panel --Useful for touch - Tested with hyprland 0.55.4 and noctalia v5.0.0 - Should work with sway using iio-sway (not tested) * add en.json to translation unify settings keys for consistent naming update names add iio-service so tools work independently refactor code for readability and remove unused logic update readme add thumbnail * Updated plugin.toml names Reworked panel code * bump version * Make arrow buttons apply relative orientation instead of fixed original directions * fixed wrong labels * Delete iio_lock/iio_lock.luau * Delete iio_lock/iio_panel.luau * Delete iio_lock/shortcut.luau * make noctalia.getConfig the sole config accessor --------- Co-authored-by: Lemmy <studio@quadbyte.net>
This commit is contained in:
co-authored by
Lemmy
parent
2d637f9651
commit
ae06d34fcb
@@ -0,0 +1,16 @@
|
||||
iio-lock — Orientation Lock for 2‑in‑1 Devices
|
||||
|
||||
iio-lock is a small bar widget and panel plugin for Noctalia that provides manual control over screen orientation.
|
||||
It works by stopping and restarting the iio-hyprland service (or similar IIO rotation tools), preventing automatic rotation while the lock is active.
|
||||
|
||||
This is useful on 2‑in‑1 touch laptops, where automatic rotation may not always be desired — such as when using the device in tablet mode, drawing, or note‑taking.
|
||||
|
||||
Supported WM and Tools
|
||||
Hyprland / iio‑hyprland — Working and tested
|
||||
Sway / iio‑sway — Unverified (experimental)
|
||||
|
||||
External commands
|
||||
This plugin shells out to:
|
||||
-pgrep
|
||||
-pkill
|
||||
-iio-hyprland (or the user‑configured tool)
|
||||
@@ -0,0 +1,32 @@
|
||||
--!nonstrict
|
||||
|
||||
local locked = noctalia.state.get("iio-state")
|
||||
local glyph_unlocked = noctalia.getConfig("unlocked")
|
||||
local glyph_locked = noctalia.getConfig("locked")
|
||||
local locked_text = noctalia.tr("widget.locked")
|
||||
local unlocked_text = noctalia.tr("widget.unlocked")
|
||||
|
||||
local function render()
|
||||
shortcut.setLabel(if locked then locked_text else unlocked_text)
|
||||
if locked then
|
||||
shortcut.setIcon(glyph_locked)
|
||||
else
|
||||
shortcut.setIcon(glyph_unlocked)
|
||||
end
|
||||
shortcut.setActive(locked)
|
||||
end
|
||||
|
||||
noctalia.state.watch("iio-state", function (value)
|
||||
locked = value
|
||||
render()
|
||||
end)
|
||||
|
||||
function onClick()
|
||||
locked = not locked
|
||||
noctalia.state.set("iio-state", locked)
|
||||
render()
|
||||
end
|
||||
|
||||
|
||||
-- Initial state at load.
|
||||
render()
|
||||
@@ -0,0 +1,38 @@
|
||||
--!nonstrict
|
||||
-- Config
|
||||
local glyph_unlocked = noctalia.getConfig("unlocked")
|
||||
local glyph_locked = noctalia.getConfig("locked")
|
||||
|
||||
-- State
|
||||
local locked = false
|
||||
local glyph = glyph_unlocked
|
||||
|
||||
local function render()
|
||||
barWidget.setGlyph(glyph)
|
||||
end
|
||||
|
||||
local function apply_lock_state()
|
||||
if locked then
|
||||
glyph = glyph_locked
|
||||
else
|
||||
glyph = glyph_unlocked
|
||||
end
|
||||
end
|
||||
|
||||
function onClick()
|
||||
locked = not locked
|
||||
noctalia.state.set("iio-state",locked)
|
||||
render()
|
||||
end
|
||||
|
||||
noctalia.state.watch("iio-state", function (value)
|
||||
locked = value
|
||||
apply_lock_state()
|
||||
render()
|
||||
end)
|
||||
|
||||
function onRightClick()
|
||||
noctalia.togglePanel("nikolaj-zwergius/iio_lock:panel")
|
||||
end
|
||||
|
||||
render()
|
||||
@@ -0,0 +1,30 @@
|
||||
--!nonstrict
|
||||
local glyph_unlocked = noctalia.getConfig("unlocked")
|
||||
local glyph_locked = noctalia.getConfig("locked")
|
||||
|
||||
local locked = false
|
||||
local glyph = glyph_unlocked
|
||||
|
||||
local function render()
|
||||
barWidget.setGlyph(glyph)
|
||||
end
|
||||
|
||||
local function apply_lock_state()
|
||||
if locked then
|
||||
glyph = glyph_locked
|
||||
else
|
||||
glyph = glyph_unlocked
|
||||
end
|
||||
end
|
||||
|
||||
noctalia.state.watch("iio-state", function (value)
|
||||
locked = value
|
||||
apply_lock_state()
|
||||
render()
|
||||
end)
|
||||
|
||||
function onClick()
|
||||
noctalia.togglePanel("nikolaj-zwergius/iio_lock:panel")
|
||||
end
|
||||
|
||||
render()
|
||||
@@ -0,0 +1,39 @@
|
||||
--!nonstrict
|
||||
|
||||
local iio_tool = noctalia.getConfig("iio")
|
||||
local locked = false
|
||||
|
||||
-- Detect initial state by checking whether the IIO tool is running
|
||||
local function refresh_state()
|
||||
noctalia.runAsync("pgrep -fx "..iio_tool, function(result)
|
||||
local pid = noctalia.string.trim(result.stdout)
|
||||
if pid ~= "" then
|
||||
noctalia.state.set("iio-state",false)
|
||||
else
|
||||
noctalia.state.set("iio-state",true)
|
||||
end
|
||||
end)
|
||||
end
|
||||
|
||||
refresh_state()
|
||||
|
||||
local function kill_iio()
|
||||
noctalia.runAsync("pkill -x "..iio_tool)
|
||||
end
|
||||
|
||||
local function start_iio()
|
||||
noctalia.runAsync(iio_tool)
|
||||
end
|
||||
|
||||
local function apply_lock_state()
|
||||
if locked then
|
||||
kill_iio()
|
||||
else
|
||||
start_iio()
|
||||
end
|
||||
end
|
||||
|
||||
noctalia.state.watch("iio-state", function (value)
|
||||
locked = value
|
||||
apply_lock_state()
|
||||
end)
|
||||
@@ -0,0 +1,136 @@
|
||||
--!nonstrict
|
||||
|
||||
--config
|
||||
local used_vm = noctalia.getConfig("vm")
|
||||
local transform_order_string = noctalia.getConfig("transform-order")
|
||||
local transform_order = {}
|
||||
|
||||
|
||||
local function set_transform_order(order_string)
|
||||
local index = 0
|
||||
for i in string.gmatch(order_string, "%d+") do
|
||||
transform_order[index] = tonumber(i)
|
||||
index += 1
|
||||
end
|
||||
end
|
||||
|
||||
set_transform_order(transform_order_string)
|
||||
|
||||
--vm functions
|
||||
function hl(value,screen)
|
||||
screen = screen or "eDP-1"
|
||||
local cmd = string.format([[hyprctl eval 'hl.monitor({ output = "%s", transform = %d })']], screen, value)
|
||||
noctalia.runAsync(cmd)
|
||||
cmd = string.format([[hyprctl eval 'hl.config({input = {touchdevice = { transform = %d },tablet= { transform = %d }}})']],value,value)
|
||||
noctalia.runAsync(cmd)
|
||||
cmd = string.format([[hyprctl eval 'hl.workspace_rule({workspace = "m[%s]"})']],screen)
|
||||
noctalia.runAsync(cmd)
|
||||
end
|
||||
|
||||
function sw(value,screen)
|
||||
screen = screen or "eDP-1"
|
||||
local cmd = string.format("swaymsg \"output %s transform %d\"",screen,value)
|
||||
noctalia.runAsync(cmd)
|
||||
end
|
||||
|
||||
local wm = {
|
||||
hyprland = hl,
|
||||
sway = sw,
|
||||
}
|
||||
|
||||
|
||||
--render and layout
|
||||
local function section(title, control)
|
||||
return ui.column({ gap = 8 }, {
|
||||
ui.label({ text = title, fontWeight = "medium", color = "on_surface_variant" }),
|
||||
control,
|
||||
})
|
||||
end
|
||||
|
||||
local function render()
|
||||
panel.render(ui.column({ flexGrow = 1, gap = 12 }, {
|
||||
ui.row({ align = "center", justify = "space_between", gap = 12 }, {
|
||||
ui.label({ text = noctalia.tr("panel.title"), fontSize = 16, fontWeight = "bold", color = "on_surface", flexGrow = 1 }),
|
||||
ui.button({ glyph = "close", onClick = "onCloseClicked" }),
|
||||
}),
|
||||
|
||||
section("", ui.column({ gap = 12, align = "center" }, {
|
||||
ui.button({width = 60 , height=100, onClick = "onUp",glyph="arrow-big-up-filled",glyphSize=50}),
|
||||
section("", ui.row({ gap = 12, align = "center" }, {
|
||||
ui.button({width = 100 , height=60, onClick = "onLeft",glyph="arrow-big-left-filled",glyphSize=50}),
|
||||
ui.button({width = 100 , height=60, onClick = "onLock",glyph="lock",glyphSize=50}),
|
||||
ui.button({width = 100 , height=60, onClick = "onRight",glyph="arrow-big-right-filled",glyphSize=50})
|
||||
})),
|
||||
ui.button({width = 60 , height=100, onClick = "onDown",glyph="arrow-big-down-filled",glyphSize=50}),
|
||||
|
||||
})),
|
||||
|
||||
|
||||
}))
|
||||
end
|
||||
|
||||
--actions
|
||||
function onOpen(_context)
|
||||
render()
|
||||
end
|
||||
|
||||
function onLock()
|
||||
local locked = noctalia.state.get("iio-state")
|
||||
noctalia.state.set("iio-state",not locked)
|
||||
panel.close()
|
||||
end
|
||||
|
||||
|
||||
function onUp()
|
||||
wm[used_vm](transform_order[0])
|
||||
noctalia.state.set("iio-state",true)
|
||||
set_transform_order(table.concat({
|
||||
transform_order[0],
|
||||
transform_order[1],
|
||||
transform_order[2],
|
||||
transform_order[3],
|
||||
}, ","))
|
||||
panel.close()
|
||||
end
|
||||
function onLeft()
|
||||
wm[used_vm](transform_order[1])
|
||||
noctalia.state.set("iio-state",true)
|
||||
set_transform_order(table.concat({
|
||||
transform_order[1],
|
||||
transform_order[2],
|
||||
transform_order[3],
|
||||
transform_order[0],
|
||||
}, ","))
|
||||
panel.close()
|
||||
end
|
||||
function onDown()
|
||||
wm[used_vm](transform_order[2])
|
||||
noctalia.state.set("iio-state",true)
|
||||
set_transform_order(table.concat({
|
||||
transform_order[2],
|
||||
transform_order[3],
|
||||
transform_order[0],
|
||||
transform_order[1],
|
||||
}, ","))
|
||||
panel.close()
|
||||
end
|
||||
function onRight()
|
||||
wm[used_vm](transform_order[3])
|
||||
noctalia.state.set("iio-state",true)
|
||||
set_transform_order(table.concat({
|
||||
transform_order[3], --up
|
||||
transform_order[0], --left
|
||||
transform_order[1], --rig
|
||||
transform_order[2], --down
|
||||
}, ","))
|
||||
panel.close()
|
||||
end
|
||||
function onCloseClicked()
|
||||
panel.close()
|
||||
end
|
||||
|
||||
noctalia.state.watch("iio-state", function (value)
|
||||
if not value then
|
||||
set_transform_order(transform_order_string)
|
||||
end
|
||||
end)
|
||||
@@ -0,0 +1,95 @@
|
||||
id = "nikolaj-zwergius/iio_lock"
|
||||
name = "iio-lock"
|
||||
version = "1.0.0"
|
||||
min_noctalia = "5.0.0"
|
||||
author = "nikolaj-zwergius"
|
||||
license = "MIT"
|
||||
dependencies = ["pgrep","pkill","iio-hyprland","iio-sway","hyprctl","swaymsg"]
|
||||
tags = ["hyprland","sway","desktop","utility"]
|
||||
icon = "lock"
|
||||
description = "Orientation lock for 2‑in‑1 devices using iio-hyprland and similar."
|
||||
|
||||
|
||||
[[setting]]
|
||||
key = "iio"
|
||||
type = "select"
|
||||
label_key = "settings.iio.label"
|
||||
description_key = "settings.iio.description"
|
||||
default = "iio-hyprland"
|
||||
options = [
|
||||
{ value = "iio-hyprland", label_key = "settings.iio.options.hyprland" },
|
||||
{ value = "iio-sway", label_key = "settings.iio.options.sway" },
|
||||
]
|
||||
|
||||
[[setting]]
|
||||
key = "transform-order"
|
||||
type = "string"
|
||||
label_key = "settings.transform.label"
|
||||
description_key = "settings.transform.description"
|
||||
default = "0,1,2,3"
|
||||
|
||||
[[setting]]
|
||||
key = "vm"
|
||||
type = "select"
|
||||
label_key = "settings.wm.label"
|
||||
description_key = "settings.wm.description"
|
||||
default = "hyprland"
|
||||
options = [
|
||||
{ value = "hyprland", label_key = "settings.wm.options.hyprland" },
|
||||
{ value = "sway", label_key = "settings.wm.options.sway" },
|
||||
]
|
||||
|
||||
[[setting]]
|
||||
key = "locked"
|
||||
type = "glyph"
|
||||
label_key = "settings.glyph.locked.label"
|
||||
description_key = "settings.glyph.locked.description"
|
||||
default = "lock"
|
||||
|
||||
[[setting]]
|
||||
key = "unlocked"
|
||||
type = "glyph"
|
||||
label_key = "settings.glyph.unlocked.label"
|
||||
description_key = "settings.glyph.unlocked.description"
|
||||
default = "lock-open-2"
|
||||
|
||||
|
||||
[[service]]
|
||||
id = "iio-service"
|
||||
entry = "iio-service.luau"
|
||||
|
||||
[[widget]]
|
||||
id = "iio-lock"
|
||||
entry = "iio-lock.luau"
|
||||
|
||||
[[widget]]
|
||||
id = "lock-panel"
|
||||
entry = "iio-panel.luau"
|
||||
|
||||
[[widget.setting]]
|
||||
key = "unlocked"
|
||||
type = "glyph"
|
||||
label_key = "settings.glyph.unlocked.label"
|
||||
description_key = "settings.glyph.unlocked.description"
|
||||
default = "rotate-rectangle"
|
||||
|
||||
[[widget.setting]]
|
||||
key = "locked"
|
||||
type = "glyph"
|
||||
label_key = "settings.glyph.locked.label"
|
||||
description_key = "settings.glyph.locked.description"
|
||||
default = "rotate-rectangle"
|
||||
|
||||
|
||||
|
||||
[[shortcut]]
|
||||
id = "toggle"
|
||||
entry = "cc-toggle.luau"
|
||||
|
||||
[[panel]]
|
||||
id = "panel"
|
||||
entry = "panel.luau"
|
||||
width = 420
|
||||
height = 410
|
||||
placement = "floating"
|
||||
position = "center"
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 35 KiB |
@@ -0,0 +1,29 @@
|
||||
{
|
||||
"settings.iio.label": "IIO Tool",
|
||||
"settings.iio.description": "Executable used to control orientation",
|
||||
"settings.iio.options.sway":"iio-sway",
|
||||
"settings.iio.options.hyprland":"iio-hyprland",
|
||||
|
||||
"settings.transform.label": "Transform Order",
|
||||
"settings.transform.description":"Rotation values for Up, Left, Down, Right.",
|
||||
|
||||
"settings.wm.label": "Window Manager",
|
||||
"settings.wm.description": "Choose the window manager backend.",
|
||||
"settings.wm.options.sway":"Sway",
|
||||
"settings.wm.options.hyprland":"Hyprland",
|
||||
|
||||
|
||||
"settings.glyph.locked.label": "Locked Glyph",
|
||||
"settings.glyph.locked.description": "Icon displayed when the device is locked.",
|
||||
|
||||
"settings.glyph.unlocked.label": "Unlocked Glyph",
|
||||
"settings.glyph.unlocked.description": "Icon displayed when the device is unlocked.",
|
||||
|
||||
|
||||
"panel.title": "iio-lock",
|
||||
"panel.lock": "Toggle Lock",
|
||||
|
||||
"widget.locked": "Locked",
|
||||
"widget.unlocked": "Unlocked",
|
||||
"toggle.description": "Toggle orientation lock"
|
||||
}
|
||||
Reference in New Issue
Block a user