feat(autotell): wire temp-tab pop-outs to the channel-popout pool
This commit is contained in:
@@ -218,7 +218,7 @@ internal sealed class AutoTellTabsService : IDisposable
|
||||
return null;
|
||||
}
|
||||
|
||||
private static Tab? FindTempTab(string name, uint world)
|
||||
internal static Tab? FindTempTab(string name, uint world)
|
||||
{
|
||||
var byTarget = Plugin.Config.Tabs.FirstOrDefault(t =>
|
||||
t.IsTempTab
|
||||
@@ -256,21 +256,20 @@ internal sealed class AutoTellTabsService : IDisposable
|
||||
return;
|
||||
}
|
||||
|
||||
// Pop-out-window cleanup is offline while the channel-popout pool
|
||||
// is rebuilt — Tab.PopOut still flips on/off, the visible window
|
||||
// disappears once the new pool comes online.
|
||||
|
||||
var dropped = victim.Tab;
|
||||
Plugin.Config.Tabs.RemoveAt(victim.Index);
|
||||
|
||||
// Re-anchor the UI selection if it pointed at the dropped tab. This runs on
|
||||
// the PendingMessage worker thread and the repair mutates the re-seeded
|
||||
// tab's channel via OnTabActivated, so marshal it onto the framework thread
|
||||
// to serialize with Draw (reference_dalamud_framework_thread) — otherwise a
|
||||
// half-applied strip could race the input bar's send-routing read.
|
||||
// Re-anchor the UI selection if it pointed at the dropped tab, and close any
|
||||
// pop-out window the dropped tab owned. Both run on the PendingMessage worker
|
||||
// thread and touch window state the Draw path reads (OnTabActivated re-seed +
|
||||
// the pool's Unbind), so marshal onto the framework thread to serialize with
|
||||
// Draw (reference_dalamud_framework_thread). TryClose is idempotent: a tab that
|
||||
// was never popped is a silent no-op.
|
||||
Plugin.Framework.RunOnFrameworkThread(() =>
|
||||
_plugin.MainWindow?.ResetActiveTabIfRemoved(dropped)
|
||||
);
|
||||
{
|
||||
_plugin.ChannelPopoutPool.TryClose(dropped.Identifier);
|
||||
_plugin.MainWindow?.ResetActiveTabIfRemoved(dropped);
|
||||
});
|
||||
}
|
||||
|
||||
private void SpawnTempTab((string Name, uint World) partner, Message currentMessage)
|
||||
@@ -282,13 +281,28 @@ internal sealed class AutoTellTabsService : IDisposable
|
||||
|
||||
tab.AddMessage(currentMessage, unread: true);
|
||||
|
||||
// Open as pop-out if configured (set before Tabs.Add for next render-tick)
|
||||
// Open as pop-out if configured (flag set before Tabs.Add for the next render-tick).
|
||||
if (Plugin.Config.AutoTellTabsOpenAsPopout)
|
||||
{
|
||||
tab.PopOut = true;
|
||||
}
|
||||
|
||||
Plugin.Config.Tabs.Add(tab);
|
||||
|
||||
// Actually open the pop-out window for the flagged tab — without this the
|
||||
// flag was dead (a PopOut tab with no window). SpawnTempTab runs on the
|
||||
// PendingMessage worker thread under _tempTabsLock; TryOpen does
|
||||
// OnTabActivated + Bind (window state Draw reads), so marshal onto the
|
||||
// framework thread. If the pool is full, drop the flag so it never claims a
|
||||
// window it didn't get (flag/window parity).
|
||||
if (tab.PopOut)
|
||||
{
|
||||
Plugin.Framework.RunOnFrameworkThread(() =>
|
||||
{
|
||||
if (!_plugin.ChannelPopoutPool.TryOpen(tab))
|
||||
tab.PopOut = false;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
private static Tab BuildTempTab(string playerName, uint worldRowId)
|
||||
@@ -427,8 +441,12 @@ internal sealed class AutoTellTabsService : IDisposable
|
||||
.Config.Tabs.Where(t => TabLifecycleHelpers.IsInUnpinnedPool(t) && t.PopOut)
|
||||
.Select(t => t.Identifier)
|
||||
.ToList();
|
||||
// Pop-out-window cleanup is offline; see Disconnect path above.
|
||||
_ = poppedTempTabIds;
|
||||
|
||||
// Close each popped temp tab's window before the tabs leave the list.
|
||||
// Logout is a framework-thread event (serialized with Draw), so no
|
||||
// marshalling is needed here, unlike the worker-thread eviction path.
|
||||
foreach (var id in poppedTempTabIds)
|
||||
_plugin.ChannelPopoutPool.TryClose(id);
|
||||
|
||||
Plugin.Config.Tabs.RemoveAll(TabLifecycleHelpers.IsInUnpinnedPool);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user