Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion AffinityHook/AffinityHook.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
<PropertyGroup>
<Product>AffinityHook</Product>
<Description>Launch wrapper to hook Affinity and inject AffinityBootstrap</Description>
<Version>0.2.0</Version>
<Version>0.3.0</Version>
<Company>Noah Curoe &amp; AffinityHook Contributors</Company>
<!-- Disable git hash in Release builds -->
<IncludeSourceRevisionInInformationalVersion Condition="'$(Configuration)' == 'Release'">false</IncludeSourceRevisionInInformationalVersion>
Expand Down
2 changes: 1 addition & 1 deletion AffinityPluginLoader/AffinityPluginLoader.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
<PropertyGroup>
<Product>Affinity Plugin Loader</Product>
<Description>Plugin loader for 'Affinity by Canva'.</Description>
<Version>0.2.0</Version>
<Version>0.3.0</Version>
<Company>Noah Curoe &amp; APL Contributors</Company>
<!-- Disable git hash in Release builds -->
<IncludeSourceRevisionInInformationalVersion Condition="'$(Configuration)' == 'Release'">false</IncludeSourceRevisionInInformationalVersion>
Expand Down
2 changes: 1 addition & 1 deletion AffinityPluginLoader/Core/AplSettings.cs
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ public static PluginSettingsDefinition CreateDefinition()
.AddSection("Logging")
.AddBool(FileLogging, "Enable logging to file",
defaultValue: false,
description: "Write APL and plugin log output to plugins/logs/apl.latest.log.")
description: "Write APL and plugin log output to apl/logs/apl.latest.log.")
.AddEnum(LogLevel, "Log level",
new List<EnumOption>
{
Expand Down
75 changes: 74 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,78 @@ As such it's recommended you update your existing shortcuts or create new shortc

## Developing Plugins

A better guide will be written up soon. For now you should reference the source code of WineFix for how to get the basic plugin structure going and how you can patch code using IL transpilation. Also take a look the source code of Affinity Plugin Loader for an example of how to inject custom UI and XAML.
Plugins extend `AffinityPlugin` and override stage methods to hook into Affinity's loading pipeline. APL calls your plugin at each stage as Affinity starts up:

| Stage | Method | What's available |
|---|---|---|
| 0 – Load | `OnLoad` | Plugin discovered, settings initialized. No Affinity types yet. |
| 1 – Patch | `OnPatch` | Serif assemblies loaded. Apply Harmony patches here. |
| 2 – ServicesReady | `OnServicesReady` | Affinity's DI container and services initialized. |
| 3 – Ready | `OnReady` | Full runtime including native engine, tools, effects. |
| 4 – UiReady | `OnUiReady` | Main window loaded. Full UI tree available. |
| 5 – StartupComplete | `OnStartupComplete` | Splash hidden, app idle. Safe to show dialogs. |

Each stage method receives an `IPluginContext` with:
- `Harmony` — shared Harmony instance for patching
- `Settings` — your plugin's settings store (if you defined settings)
- `Patch(description, action)` — apply a patch with automatic deferral if dependencies aren't loaded yet
- `Log` / `LogWarning` / `LogError` — logging helpers

### Settings API

Override `DefineSettings()` to declare configuration options. APL auto-generates a preferences page in Affinity's preferences dialog using native Affinity controls.

```csharp
public override PluginSettingsDefinition DefineSettings()
{
return new PluginSettingsDefinition("myplugin")
.AddSection("General")
.AddBool("my_toggle", "Enable feature", defaultValue: true,
description: "Description shown below the toggle.")
.AddEnum("my_choice", "Pick one", new List<EnumOption>
{
new EnumOption("a", "Option A"),
new EnumOption("b", "Option B"),
})
.AddSlider("my_slider", "Amount", 0, 100, defaultValue: 50);
}
```

Supported setting types: `Bool`, `String`, `Enum`, `Slider`, `DropdownSlider`. Layout elements like `AddSection`, `AddInlineText`, `AddInlineMutedText`, and `AddInlineXaml` are also available. Settings descriptions support basic markdown formatting.

Settings are persisted as TOML in the `apl/config/` directory and can be overridden via environment variables (`APL__PLUGINID__KEY`).

### Minimal Plugin Example

```csharp
using HarmonyLib;
using AffinityPluginLoader;
using AffinityPluginLoader.Settings;

public class MyPlugin : AffinityPlugin
{
public override PluginSettingsDefinition DefineSettings()
{
return new PluginSettingsDefinition("myplugin")
.AddBool("enabled", "Enable patch", defaultValue: true);
}

public override void OnPatch(Harmony harmony, IPluginContext context)
{
if (context.Settings.GetEffectiveValue<bool>("enabled"))
{
context.Patch("My patch", h =>
{
// Use reflection to find target types, then apply Harmony patches
});
}
}
}
```

See [WineFix/](WineFix/) for a full working example with multiple patches, settings, and deferred patching.

### Building

Build scripts are provided for Windows and Linux.

Expand All @@ -42,6 +113,8 @@ Build scripts are provided for Windows and Linux.
>
> APL fully supports building on Linux via mingw-w64 and the dotnet SDK, you'll just need to grab a Windows SDK header and library from Wine.

Use `./deploy.sh` to build and deploy directly to your Affinity install directory for testing.


## Licensing

Expand Down
21 changes: 18 additions & 3 deletions WineFix/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,13 +13,28 @@ As of now WineFix fixes the following bugs:

- Fixed: Preferences fail to save on application exit
- Fixed: Vector path preview lines are drawn incorrectly and don't match the underlying stroke path
- Fixed: Color picker zoom preview displays a black image on Wayland (auto-detected; configurable)
- Fixed: Intermittent startup crash caused by parallel font enumeration (force-disabled by default)

> [!WARNING]
> WineFix currently patches out the Canva sign-in dialog prompt when launching Affinity. This is temporary and the sign-in dialog prompt will be restored as soon as we have a known consistent way to fix the sign-in browser redirect and Affinity protocol handler.

More fixes are planned. We are currently researching potential solutions for the following bugs:
## Configuration

WineFix settings are configurable from Affinity's preferences dialog (under the WineFix tab) or via environment variables.

| Setting | Default | Description |
|---|---|---|
| Color picker magnifier fix | Auto | Wayland zoom preview fix. Auto enables only on Wayland/XWayland. |
| Color picker sampling mode | Native | Native uses Affinity's color space; Exact picks the literal pixel color (sRGB). |
| Force synchronous font enumeration | Enabled | Disables parallel font loading to reduce startup crashes. May increase startup time. |

Environment variable overrides use the format `APL__WINEFIX__KEY` (e.g. `APL__WINEFIX__COLOR_PICKER_MAGNIFIER_FIX=disabled`).

## Known Open Bugs

We are currently researching potential solutions for the following bugs:

- Color picker doesn't display zoom image on Wayland
- Accepting crash reporting causes permanent crash until prefs are cleared
- Embedded SVG document editor causes crash after being open for some amount of time

Expand All @@ -33,7 +48,7 @@ WineFix is licensed under the terms of the GPLv2 except for the exclusion and ex

### License Exclusion

WineFix includes source code from the Wine project for d2d1.dll under `/WineFix/lib/d2d1`. In accordance with the original project, the code in this directory are instead licensed under the LGPLv2.1. A copy of this license can be found at `/WineFix/lib/d2d1/LICENSE`. Changes have been applied to the d2d1 source code to implement a recursive cubic bezier subdivision algorithm to correct cubic bezier rendering in Affinity, and to allow building d2d1.dll standalone from the full Wine source code repository.
WineFix includes source code from the Wine project for d2d1.dll under `WineFix/lib/d2d1`. In accordance with the original project, the code in this directory is instead licensed under the LGPLv2.1. A copy of this license can be found at `WineFix/lib/d2d1/LICENSE`. Changes have been applied to the d2d1 source code to implement a recursive cubic bezier subdivision algorithm to correct cubic bezier rendering in Affinity, and to allow building d2d1.dll standalone from the full Wine source code repository.

### License Exemption

Expand Down
2 changes: 1 addition & 1 deletion WineFix/WineFix.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
<PropertyGroup>
<Product>WineFix</Product>
<Description>Plugin to fix Wine compatibility issues in Affinity applications</Description>
<Version>0.2.0</Version>
<Version>0.3.0</Version>
<Company>Noah Curoe &amp; WineFix Contributors</Company>
<!-- Disable git hash in Release builds -->
<IncludeSourceRevisionInInformationalVersion Condition="'$(Configuration)' == 'Release'">false</IncludeSourceRevisionInInformationalVersion>
Expand Down
Loading