--list-objects / --disable-object / --enable-object were recently added
(see ApplicationContext.cpp), and the we_manager Electron app now has a UI
for toggling layers and adjusting per-wallpaper volume live from a sidebar.
Because those settings are only read from argv at process startup
(ApplicationContext::loadSettingsFromArgv), the app currently applies any
change by killing the running process and spawning a brand new one with the
updated flags. That works, but it's the wrong tool for the job:
stopLwe() sends SIGTERM and
moves on without waiting for the old process to actually exit. If it's
still shutting down when the new one starts, both processes are briefly
alive at once (we saw DBus service org.linuxwallpaperengine.WaylandDetector
is already owned by another process in the logs from exactly this). The
app now guards against the worst symptom (a corrupted activeProcess
reference that made the new launch hang forever - see
we_manager/src/main/services/lwe.service.ts, the cleanup closure in
launchLweAsync), but the underlying process-overlap window is still
there and still wasteful.The hotswap mechanism (SIGUSR1 + control file) already exists for switching which background plays, without a process restart. This task is to extend it to carry more than just a path, so layers/volume/etc. can be updated the same lightweight way.
WallpaperApplication::checkHotswapRequest() in
src/WallpaperEngine/Application/WallpaperApplication.cpp (~line 506).$XDG_RUNTIME_DIR/lwe-control (or /tmp/lwe-control), triggered by
SIGUSR1 (m_hotswapRequested flag, set in WallpaperApplication::signal).loadBackground), re-runs
setupPropertiesForProject, and reconstructs a CWallpaper per screen via
CWallpaper::fromWallpaper(...).hotReloadLwe() in
we_manager/src/main/services/lwe.service.ts, which just writes the path
and sends the signal.Both target settings already re-evaluate fresh on every reload, they're just not reachable from the control-file path yet:
Layers: ApplicationContext::resolveObjectVisibility(id, name)
(ApplicationContext.cpp:261) reads straight from
settings.general.disabledObjects / enabledObjects, and is called during
object construction (CImage.cpp:865,929, CText.cpp:592,
CParticle.cpp:178, CScene.cpp:366) - which already runs again on every
hotswap reload. If the control-file handler updates those two vectors on
m_context.settings.general before calling loadBackground, visibility
should just work without touching the object-construction code at all.
Volume: GLPlayer::setVolume(double)
(VideoPlayback/MPV/GLPlayer.cpp:102) already does a live
mpv_set_property(..., "volume", ...) on the existing mpv handle - no
reload needed at all for video wallpapers, it just needs a path from the
control file to this call. Scene/particle audio (Render/Objects/CSound.h)
wasn't checked in detail; confirm whether it has an equivalent live setter
or needs the same "re-apply on reload" treatment as layers.
Replace the single-line control file with a small line-based or JSON format so it can carry multiple fields without breaking existing readers, e.g.:
path=/path/to/wallpaper
disable-object=13
disable-object=110
enable-object=7
volume=42
or a JSON object with the same fields. Either is fine; pick whichever is
less code given checkHotswapRequest is currently a simple
std::getline.
In checkHotswapRequest, before calling loadBackground:
m_context.settings.general.disabledObjects /
enabledObjects with the new lists.GLPlayer::setVolume directly (no reload needed - this can
probably be handled as its own signal path, separate from a full
background reload, since it doesn't need loadBackground at all).Path stays optional in the payload: a volume-only or layers-only update shouldn't require re-sending the current path and doing a full reload when nothing about the project changed. Worth splitting into two distinct requests internally: "reload background" (path/layers, since layers currently only take effect through object construction) vs. "live property push" (volume, and anything else with a direct setter).
src/main/services/lwe.service.ts: extend getControlFilePath/
hotReloadLwe to write the richer payload, and add a variant that doesn't
require isLweRunning() to be false (currently only used as a fallback
inside launchLweAsync).src/renderer/src/components/common/DetailSidebar.tsx: toggleObject and
commitVolume currently call lwe.stop() + wallpaper.apply() when
isActive is true - swap that for a new lighter IPC call (e.g.
lwe.hotswapSettings(...)) once the above exists, dropping the ~2-3s
relaunch wait and the "live" restart flash entirely.