diff --git a/HellionChat/Configuration.cs b/HellionChat/Configuration.cs index 5ae47b6..b5cc5bb 100755 --- a/HellionChat/Configuration.cs +++ b/HellionChat/Configuration.cs @@ -482,6 +482,16 @@ public class Tab // session. NonSerialized because the temp tab itself is session-only. [NonSerialized] public bool IsGreeted; + // v1.4.2 — TabTintCache uses separate validation keys per cache so a + // TellTarget change picked up by GetTint can't strand GetIcon (or vice + // versa) with a stale entry that looks fresh on the shared key. + [NonSerialized] internal string? _cachedTintTellName; + [NonSerialized] internal uint _cachedTintTellWorld; + [NonSerialized] internal uint _cachedTellTint; + [NonSerialized] internal string? _cachedIconTellName; + [NonSerialized] internal uint _cachedIconTellWorld; + [NonSerialized] internal string? _cachedTellIcon; + public bool Matches(Message message) { if (!message.Matches(SelectedChannels, ExtraChatAll, ExtraChatChannels)) diff --git a/HellionChat/Ui/ChatLogWindow.cs b/HellionChat/Ui/ChatLogWindow.cs index 53bfc56..14cdfcb 100644 --- a/HellionChat/Ui/ChatLogWindow.cs +++ b/HellionChat/Ui/ChatLogWindow.cs @@ -1571,7 +1571,7 @@ public sealed class ChatLogWindow : Window { // v1.2.0 — Hash-Color-Tint differenziert parallele Auto-Tell-Tabs // visuell ohne dass User pro Tab manuell ein Custom-Icon setzen muss. - iconColor = AutoTellTabTint.For(tab.TellTarget.Name, tab.TellTarget.World); + iconColor = TabTintCache.GetTint(tab); } else { diff --git a/HellionChat/Ui/TabIconMapping.cs b/HellionChat/Ui/TabIconMapping.cs index c185231..ed61db7 100644 --- a/HellionChat/Ui/TabIconMapping.cs +++ b/HellionChat/Ui/TabIconMapping.cs @@ -61,7 +61,7 @@ internal static class TabIconMapping string? autoTellGlyph = null; if (tab.IsTempTab && tab.TellTarget != null && tab.TellTarget.IsSet()) { - autoTellGlyph = AutoTellTabTint.IconFor(tab.TellTarget.Name, tab.TellTarget.World); + autoTellGlyph = TabTintCache.GetIcon(tab); } var glyph = TabIconGlyphResolver.ResolveGlyphName(tab, autoTellGlyph); diff --git a/HellionChat/Ui/TabTintCache.cs b/HellionChat/Ui/TabTintCache.cs new file mode 100644 index 0000000..85f2cbb --- /dev/null +++ b/HellionChat/Ui/TabTintCache.cs @@ -0,0 +1,36 @@ +namespace HellionChat.Ui; + +// Per-Tab cache wrapper around the pure AutoTellTabTint hash helpers. +// Each cache (tint, icon) carries its own name+world validation key so +// neither read path mutates the other's state — refilling one never +// invalidates the other. No string allocation in the steady-state lookup. +internal static class TabTintCache +{ + public static uint GetTint(Tab tab) + { + var name = tab.TellTarget.Name; + var world = tab.TellTarget.World; + if (tab._cachedTintTellName != name || tab._cachedTintTellWorld != world) + { + tab._cachedTintTellName = name; + tab._cachedTintTellWorld = world; + tab._cachedTellTint = AutoTellTabTint.For(name, world); + } + return tab._cachedTellTint; + } + + public static string GetIcon(Tab tab) + { + var name = tab.TellTarget.Name; + var world = tab.TellTarget.World; + if (tab._cachedTellIcon is null + || tab._cachedIconTellName != name + || tab._cachedIconTellWorld != world) + { + tab._cachedIconTellName = name; + tab._cachedIconTellWorld = world; + tab._cachedTellIcon = AutoTellTabTint.IconFor(name, world); + } + return tab._cachedTellIcon; + } +}