hyprland and dms configuration
This commit is contained in:
@@ -1,50 +1,267 @@
|
||||
-- Home Monitor Setup
|
||||
hl.monitor({
|
||||
output = "desc:GIGA-BYTE TECHNOLOGY CO. LTD. M34WQ 0x00000B52",
|
||||
mode = "3440x1440@60",
|
||||
position = "0x0",
|
||||
scale = "1"
|
||||
})
|
||||
-- Monitor configuration and automatic and manual switching--
|
||||
|
||||
hl.monitor({
|
||||
output = "desc:Dell Inc. DELL U2414H 292K475V26JL",
|
||||
mode = "1920x1080@60",
|
||||
position = "760x-1080",
|
||||
scale = "1"
|
||||
})
|
||||
------------------
|
||||
---- PROFILES ----
|
||||
------------------
|
||||
|
||||
hl.monitor({
|
||||
output = "desc:Dell Inc. DELL U2724D DL7R834",
|
||||
mode = "2560x1440@60",
|
||||
position = "3440x0",
|
||||
scale = "1"
|
||||
})
|
||||
-- Profiles:
|
||||
-- Key of the profile is the name of the profile
|
||||
-- Profiles are ordered by priority, higher number takes precedence over smaller number
|
||||
-- First (by priority) profile that matches will be applied, all others will be ignored
|
||||
--
|
||||
-- A profile matches the current setup if _ALL_ of its match criteria are fulfilled
|
||||
-- If there are no match criteria, it will match always
|
||||
local PROFILES = {
|
||||
-- The most basic fallback if nothing else ever works
|
||||
fallback = {
|
||||
priority = -999,
|
||||
matches = {},
|
||||
monitors = {
|
||||
{
|
||||
output = "",
|
||||
mode = "preferred",
|
||||
position = "auto",
|
||||
scale = 1,
|
||||
disabled = false,
|
||||
},
|
||||
},
|
||||
},
|
||||
laptop = {
|
||||
priority = 0,
|
||||
matches = {{ output = "eDP-1" }},
|
||||
monitors = {
|
||||
{
|
||||
output = "eDP-1",
|
||||
mode = "1920x1200@120",
|
||||
position = "0x0",
|
||||
scale = 1,
|
||||
disabled = false,
|
||||
},
|
||||
},
|
||||
},
|
||||
home_docked = {
|
||||
priority = 10,
|
||||
matches = {
|
||||
{ output = "desc:GIGA-BYTE TECHNOLOGY CO. LTD. M34WQ 0x00000B52" },
|
||||
{ output = "desc:Dell Inc. DELL U2414H 292K475V26JL" },
|
||||
{ output = "desc:Dell Inc. DELL U2724D DL7R834" },
|
||||
},
|
||||
monitors = {
|
||||
{
|
||||
output = "eDP-1",
|
||||
mode = "preferred",
|
||||
position = "0x0",
|
||||
scale = 1,
|
||||
disabled = true,
|
||||
},
|
||||
{
|
||||
output = "desc:GIGA-BYTE TECHNOLOGY CO. LTD. M34WQ 0x00000B52",
|
||||
mode = "3440x1440@60",
|
||||
position = "0x0",
|
||||
scale = 1,
|
||||
disabled = false,
|
||||
},
|
||||
{
|
||||
output = "desc:Dell Inc. DELL U2414H 292K475V26JL",
|
||||
mode = "1920x1080@60",
|
||||
position = "760x-1080",
|
||||
scale = 1,
|
||||
disabled = false,
|
||||
},
|
||||
{
|
||||
output = "desc:Dell Inc. DELL U2724D DL7R834",
|
||||
mode = "2560x1440@60",
|
||||
position = "3440x0",
|
||||
scale = 1,
|
||||
disabled = false,
|
||||
},
|
||||
},
|
||||
postprocess = function()
|
||||
debug_notify("now applying workspace rules")
|
||||
for i = 1,5 do
|
||||
hl.workspace_rule({ workspace = string.format("%d", i), monitor = "desc:GIGA-BYTE TECHNOLOGY CO. LTD. M34WQ 0x00000B52"})
|
||||
end
|
||||
hl.workspace_rule({ workspace = "1", default = true, persistent = true})
|
||||
for i = 6,9 do
|
||||
hl.workspace_rule({ workspace = string.format("%d", i), monitor = "desc:Dell Inc. DELL U2724D DL7R834"})
|
||||
end
|
||||
hl.workspace_rule({ workspace = "9", default = true, persistent = true})
|
||||
hl.workspace_rule({ workspace = "10", monitor = "desc:Dell Inc. DELL U2414H 292K475V26JL", default = true, persistent = true})
|
||||
|
||||
-- Integrated Laptop Monitor
|
||||
hl.monitor({
|
||||
output = "eDP-1",
|
||||
mode = "1920x1200@120",
|
||||
position = "auto",
|
||||
scale = "1"
|
||||
})
|
||||
hl.dispatch(hl.dsp.focus({workspace = 10}))
|
||||
hl.dispatch(hl.dsp.focus({workspace = 9}))
|
||||
hl.dispatch(hl.dsp.focus({workspace = 1}))
|
||||
end
|
||||
},
|
||||
}
|
||||
|
||||
-- Default for all other monitors
|
||||
hl.monitor({
|
||||
output = "",
|
||||
mode = "preferred",
|
||||
position = "auto",
|
||||
scale = "auto",
|
||||
})
|
||||
local function refresh_monitors()
|
||||
hl.exec_cmd("hyprctl monitors all -j | jq -r '.[] | [.name, .description] | @tsv' > /tmp/hypr_monitors.tsv")
|
||||
end
|
||||
local function get_monitors()
|
||||
-- FIXME: Use hl.get_monitors({all=true}) as soon as it is released
|
||||
local handle = io.open("/tmp/hypr_monitors.tsv", "r")
|
||||
if handle ~= nil then
|
||||
local out = handle:read("*a")
|
||||
handle:close()
|
||||
|
||||
-- In Clamshell Mode, deactivate the internal monitor
|
||||
hl.bind("switch:on:Lid Switch", function()
|
||||
local result = {}
|
||||
for line in out:gmatch("[^\n]+") do
|
||||
local name, desc = line:match("([^\t]+)\t(.+)")
|
||||
table.insert(result, { name = name, description = desc })
|
||||
end
|
||||
return result
|
||||
end
|
||||
return {}
|
||||
end
|
||||
|
||||
local function get_matching_profile()
|
||||
local monitors = get_monitors()
|
||||
local profiles = {} or {}
|
||||
|
||||
local monitor_debug = map(monitors, function(monitor)
|
||||
return monitor.name .. ": "..monitor.description
|
||||
end)
|
||||
debug_notify("Currently " .. #monitors .. " connected: " .. table.concat(monitor_debug, "; "))
|
||||
|
||||
for profile_name, profile in pairs(PROFILES) do
|
||||
profile.name = profile_name or "unknown"
|
||||
table.insert(profiles, profile)
|
||||
end
|
||||
table.sort(profiles, function(a, b) return (a.priority or 0) > (b.priority or 0) end)
|
||||
|
||||
for _, profile in ipairs(profiles) do
|
||||
local matches = profile.matches or {}
|
||||
local has_matched = {}
|
||||
for _, match in ipairs(matches) do
|
||||
if starts_with(match.output, "desc:") then
|
||||
table.insert(has_matched, any(monitors, function(m) return "desc:" .. m.description == match.output end))
|
||||
else
|
||||
table.insert(has_matched, any(monitors, function(m) return m.name == match.output end))
|
||||
end
|
||||
end
|
||||
|
||||
if #has_matched == 0 then
|
||||
debug_notify("Monitor profile " .. profile.name .. " is active because it does not require any matches (fallback)")
|
||||
return profile
|
||||
elseif all(has_matched, function(v) return v end) then
|
||||
return profile
|
||||
else
|
||||
local failed = map(has_matched, function(v, i)
|
||||
if not v then
|
||||
return matches[i].output
|
||||
else
|
||||
return ""
|
||||
end
|
||||
end)
|
||||
local failedmsg = table.concat(failed, " ")
|
||||
debug_notify("Monitor profile " .. profile.name .. " does not match, could not match " .. failedmsg)
|
||||
end
|
||||
end
|
||||
return nil
|
||||
end
|
||||
|
||||
local PROFILE_CHANGE_ONGOING = false
|
||||
local PROFILE_CHANGE_RESET_TIMER = nil
|
||||
local PROFILE_CHANGE_START_TIMER = nil
|
||||
local POSTPROCESS_TIMER = nil
|
||||
|
||||
local function apply_profile(profile)
|
||||
if PROFILE_CHANGE_ONGOING then
|
||||
debug_notify("Monitor profile change is inprogress (debounce)")
|
||||
return
|
||||
end
|
||||
|
||||
if profile == nil then
|
||||
debug_notify("No monitor profile available")
|
||||
return
|
||||
end
|
||||
|
||||
debug_notify("Applying monitor profile " .. profile.name)
|
||||
PROFILE_CHANGE_ONGOING = true
|
||||
|
||||
-- delay application of the profile for some time, as other monitor change events might still be arriving
|
||||
PROFILE_CHANGE_START_TIMER = hl.timer(function()
|
||||
|
||||
-- after we have started applying our profile, we will generate monitor change events that we do not
|
||||
-- want to process. Assume 5 seconds of non-interesting monitor events that we do not want to process
|
||||
-- afterwards, reset the PROFILE_CHANGE_ONGOING flag for the next time we actually want to change
|
||||
-- monitor profiles
|
||||
PROFILE_CHANGE_RESET_TIMER = hl.timer(function()
|
||||
PROFILE_CHANGE_ONGOING = false
|
||||
debug_notify("Monitor Profile Change Debounce Finished")
|
||||
PROFILE_CHANGE_RESET_TIMER = nil
|
||||
end, { timeout = 5000, type = "oneshot" })
|
||||
|
||||
local monitors = profile.monitors
|
||||
for _, monitor in ipairs(monitors) do
|
||||
hl.monitor(monitor)
|
||||
end
|
||||
|
||||
debug_notify("Monitor Profile " .. profile.name .. " successfully applied")
|
||||
|
||||
-- start any post processing
|
||||
if profile.postprocess ~= nil then
|
||||
POSTPROCESS_TIMER = hl.timer(function()
|
||||
if profile.postprocess ~= nil then
|
||||
profile.postprocess()
|
||||
end
|
||||
|
||||
PROFILE_CHANGE_START_TIMER = nil
|
||||
POSTPROCESS_TIMER = nil
|
||||
end, { timeout = 200, type = "oneshot" })
|
||||
else
|
||||
PROFILE_CHANGE_START_TIMER = nil
|
||||
end
|
||||
end, { timeout = 500, type = "oneshot" })
|
||||
end
|
||||
|
||||
local function apply_current_profile()
|
||||
apply_profile(get_matching_profile())
|
||||
end
|
||||
|
||||
local function force_refresh_profile()
|
||||
if PROFILE_CHANGE_RESET_TIMER ~= nil then PROFILE_CHANGE_RESET_TIMER:set_enabled(false) end
|
||||
if POSTPROCESS_TIMER ~= nil then POSTPROCESS_TIMER:set_enabled(false) end
|
||||
if PROFILE_CHANGE_START_TIMER ~= nil then PROFILE_CHANGE_START_TIMER:set_enabled(false) end
|
||||
|
||||
PROFILE_CHANGE_RESET_TIMER = nil
|
||||
POSTPROCESS_TIMER = nil
|
||||
PROFILE_CHANGE_START_TIMER = nil
|
||||
PROFILE_CHANGE_ONGOING = false
|
||||
|
||||
debug_notify("Force applying monitor profile")
|
||||
refresh_monitors()
|
||||
apply_current_profile()
|
||||
end
|
||||
|
||||
local function on_lid_close()
|
||||
debug_notify("Lid was closed")
|
||||
refresh_monitors()
|
||||
hl.monitor({ output = "eDP-1", disabled = true })
|
||||
end, { locked = true })
|
||||
|
||||
hl.bind("switch:off:Lid Switch", function()
|
||||
hl.monitor({ output = "eDP-1", disabled = false })
|
||||
end, { locked = true })
|
||||
end
|
||||
|
||||
local function on_lid_open()
|
||||
debug_notify("Lid was opened")
|
||||
refresh_monitors()
|
||||
apply_current_profile()
|
||||
end
|
||||
|
||||
local function on_monitor_added(_event)
|
||||
debug_notify("A monitor was added")
|
||||
refresh_monitors()
|
||||
apply_current_profile()
|
||||
end
|
||||
|
||||
local function on_monitor_removed(_event)
|
||||
debug_notify("A monitor was removed")
|
||||
refresh_monitors()
|
||||
apply_current_profile()
|
||||
end
|
||||
|
||||
hl.bind("switch:on:Lid Switch", on_lid_close, { locked = true })
|
||||
hl.bind("switch:off:Lid Switch", on_lid_open, { locked = true })
|
||||
hl.bind("SUPER + P", function() force_refresh_profile() end, { locked = true, description = "Force Refresh Monitor Profile" })
|
||||
hl.on("monitor.added", on_monitor_added)
|
||||
hl.on("monitor.removed", on_monitor_removed)
|
||||
hl.on("hyprland.start", function() refresh_monitors() end)
|
||||
|
||||
Reference in New Issue
Block a user