Skip to content

Commit 2a10a42

Browse files
committed
feat: implement support for monitoring D-Bus signals
Implements support for using `dbus-monitor`, which allows direct monitoring of signals, which are send when the settings changes. This reduces the system load, as continuous polling is no longer required, as well as improving the responsiveness, as the theme is now updated immediately, instead of waiting for the next polling-cycle to complete. If `dbus-monitor` is not available, the polling method will be used as a fallback.
1 parent a517a62 commit 2a10a42

File tree

2 files changed

+42
-3
lines changed

2 files changed

+42
-3
lines changed

lua/auto-dark-mode/init.lua

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,8 @@ M.state = {
5454
system = nil,
5555
---@type table
5656
query_command = {},
57+
---@type string?
58+
monitor_command = nil,
5759
}
5860

5961
---@return nil
@@ -92,6 +94,10 @@ M.init = function()
9294
"string:org.freedesktop.appearance",
9395
"string:color-scheme",
9496
}
97+
98+
if vim.fn.executable("dbus-monitor") ~= 0 then
99+
M.state.monitor_command = "dbus-monitor --session type=signal,interface=org.freedesktop.portal.Settings,member=SettingChanged,path=/org/freedesktop/portal/desktop,arg0='org.freedesktop.appearance',arg1='color-scheme'"
100+
end
95101
elseif M.state.system == "Windows_NT" or M.state.system == "WSL" then
96102
local reg = "reg.exe"
97103

lua/auto-dark-mode/interval.lua

Lines changed: 36 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,9 +16,9 @@ local uv = vim.uv or vim.loop
1616
---@return Appearance?
1717
local function parse_query_response(stdout, stderr)
1818
if M.state.system == "Linux" then
19-
if stderr ~= "" then
20-
return nil;
21-
end
19+
if stderr ~= "" then
20+
return nil;
21+
end
2222

2323
-- https://github.com/flatpak/xdg-desktop-portal/blob/c0f0eb103effdcf3701a1bf53f12fe953fbf0b75/data/org.freedesktop.impl.portal.Settings.xml#L32-L46
2424
-- 0: no preference
@@ -67,6 +67,33 @@ local function sync_theme(appearance)
6767
end
6868
end
6969

70+
-- Uses a subprocess to monitor the system for the current dark mode setting.
71+
-- The callback is called with the plaintext stdout response of the query.
72+
---@param callback? fun(stdout: string, stderr: string): nil
73+
---@return nil
74+
M.monitor_dark_mode = function (callback)
75+
-- if no callback is provided, use a no-op
76+
callback = callback or function() end
77+
78+
vim.fn.jobstart(M.state.monitor_command,
79+
{
80+
on_stdout = function (_, data, _)
81+
data = table.concat(data, "")
82+
83+
if string.match(data, "uint32") then
84+
-- check if this was a signal update with a new value,
85+
-- as otherwise the fallback option will be incorrectly triggered
86+
callback(data, "")
87+
end
88+
end,
89+
on_stderr = function (_, data, _)
90+
data = table.concat(data, "")
91+
callback("", data)
92+
end
93+
}
94+
);
95+
end
96+
7097
-- Uses a subprocess to query the system for the current dark mode setting.
7198
-- The callback is called with the plaintext stdout response of the query.
7299
---@param callback? fun(stdout: string, stderr: string): nil
@@ -151,7 +178,13 @@ M.start = function(options, state)
151178
-- act as if the timer has finished once to instantly sync on startup
152179
timer_callback()
153180

181+
-- if the system supports monitoring, prefer that over polling updates
182+
if M.state.monitor_command then
183+
M.monitor_dark_mode(M.parse_callback)
184+
else
154185
M.start_timer()
186+
end
187+
155188
end
156189

157190
return M

0 commit comments

Comments
 (0)