initial commit

This commit is contained in:
2026-11-04 14:29:22 -06:00
parent 73028cc5ba
commit 3f37abf34a
170 changed files with 22100 additions and 0 deletions
+119
View File
@@ -0,0 +1,119 @@
# Troubleshooting
## First stop: the log
Everything is in `%APPDATA%\LiveWall\logs\livewall-YYYYMMDD.log`. Plugin lines are prefixed with the
plugin id:
```
[com.example.clock] Clock plugin starting (plugin API 1.0, host 1.8.0)
[plugins] loaded com.example.clock v1.0.0 (sha256 3f8c…, verified)
```
Also useful:
* **Plugins ▸ Plugin log** — in-app summary: every plugin, its state, hash, permissions, overlays,
pages, commands, filters, renderers.
* **Advanced ▸ Diagnostics** — the same report inside the full diagnostics dump, plus the engine state.
* **Advanced ▸ Open log folder**.
## The plugin does not appear in the list
| Symptom | Cause | Fix |
|---|---|---|
| Folder listed but named after the folder | `plugin.json` missing or unparsable | Fix the JSON; the row says `Invalid manifest: …` |
| Nothing at all | Wrong folder | Must be `%APPDATA%\LiveWall\plugins\<something>\plugin.json`, not `plugins\plugin.json` |
| Nothing at all | Plugin system off | **Plugins ▸ Enable the plugin system** (warning required) |
| Appears, greyed state `Incompatible` | `apiVersion` major mismatch or `minHostVersion` too new | Update the plugin, or lower `minHostVersion` |
| Appears, `Rejected` | `checksum` in the manifest does not match the DLL | Rebuild, or clear `checksum` |
| Appears, `Failed` | Assembly/type problem, or `Initialize` threw | Read the state message; fix the type name or the exception |
| Appears, `NotApproved` | Loaded and ready, waiting for the user | Press **Enable** and accept the warning |
## `Enable` does nothing / warning reappears every time
* **"allow unverified plugins" is off** and the plugin is unverified → turn that option on (in the
*Plugin system* card) or use a build whose hash you approved before.
* The hash changes on every build (normal). Approving a build approves *that* binary; rebuild and you
are asked again. During development, leave **Allow unverified** on and keep an eye on the log rather
than re-approving each time.
* A **Forget trust** click clears the stored hash — that is what it does.
## "Could not load file or assembly … LiveWall.Sdk"
The plugin was built with an *incompatible* SDK, or it shipped its own `LiveWall.Sdk.dll`. Delete the
copy from the plugin folder and reference the SDK with `<Private>false</Private>`.
## "Cannot cast … to ILiveWallPlugin"
Same cause: a second copy of the contract assembly. The plugin's `ILiveWallPlugin` came from a
different assembly identity than the host's.
## Overlay does not show up
1. Is the plugin **Active** and does the log mention `overlay registered`?
2. Is the desktop icon window alive? LiveWall creates the overlay host window even with desktop icons
disabled, but a third-party shell replacement (StartAllBack, ExplorerPatcher) can break WorkerW —
press **Re-attach** on the Display tab.
3. Did you return a `FrameworkElement` with a size? A `StackPanel` with no children is invisible.
4. Is it *behind* the icons by design? The overlay sits above the wallpaper and below the icons; text
in the top-right corner is a safe place to test.
5. Did you call `OnVisibilityChanged` correctly? LiveWall calls it with `false` when overlays are
hidden (tray **Hide overlay**), so a timer you stopped there must be restarted on `true`.
## Clicks on my overlay do nothing
Expected. The overlay layer is `IsHitTestVisible = false`: clicks must reach the desktop icons. If you
need interaction, that is a *renderer* feature (renderers live in the wallpaper window and can be made
interactive with `InteractiveMode`), not an overlay feature.
## Settings page is blank
`CreateView` threw. The exception is shown in the page *and* logged. The usual culprit is referencing
`LiveWall.Themes` resources by key that does not exist — the safe keys are `BgWindow`, `BgCard`,
`BgField`, `BgHover`, `BorderBrushSoft`, `TextBrush`, `TextDim`, `AccentBrush`, `AccentSoft`,
`GreenBrush`, `DangerBrush`, and the styles `Card`, `Hint`, `SectionTitle`, `PageTitle`,
`AccentButton`, `GhostButton`, `TinyButton`, `Label`, `Mono`.
## Hotkey does nothing
* Another app (or LiveWall itself) already owns the combination — the log says so.
* Gesture syntax: modifiers first (`Ctrl+Alt+K`), one key. `Ctrl+Shift+3` is not valid, `Ctrl+Shift+D3`
is.
* The `Hotkeys` permission must be declared.
## Filter breaks wallpaper changes
Filters run **before** the engine applies a request, including requests from playlists and other
plugins. A filter that always returns a fixed request effectively pins the wallpaper (that is the point
of the sample's *Pin wallpaper* option). Exceptions inside `Apply` disable your filter for that pass
and are logged; they do not disable the plugin.
## Renderer never gets used
* `CanRender` must return `true` for the request the engine actually sees — after filters. Log what
you receive.
* Another plugin with a higher `Priority` claimed it first. Priorities are per plugin; the first `true`
wins.
* The `Renderer` permission must be declared, otherwise `AddRenderer` is refused.
* After a source change LiveWall calls `Create` once and `Load` per source. If `Load` throws, the
message appears in the status line and the plugin is not retried for that source.
## Unloading
LiveWall unloads a plugin when it is disabled, rescanned, or when the app exits. The collectible load
context only actually releases the assembly if nothing keeps a reference alive:
* unsubscribe every `IDisposable` you got from `Events.Subscribe` in `Shutdown`;
* stop and unhook `DispatcherTimer`s, `System.Timers.Timer`s, `FileSystemWatcher`s;
* do not keep static references **in the host's types** to your objects (a static in a host-owned class
is fine only if it lives in your assembly);
* do not leave `Task`s running: observe `context.ShutdownToken`.
If a plugin stays "loaded" after Disable, the log says `unload deferred` — restart LiveWall to finish
the job. This is a leak in the plugin, not in LiveWall.
## Reporting a bug
Include: LiveWall version, plugin id + version + hash (from the warning dialog or **Plugin log**), the
relevant log excerpt, and the exact steps. If the app crashed, the last lines of the log before the
crash are usually enough to identify the plugin.