From f29c3d04241b32791462c7027938abeb887f8140 Mon Sep 17 00:00:00 2001 From: Martin Fleck Date: Tue, 29 Oct 2024 11:16:20 +0000 Subject: [PATCH] Properly dispose tab/title-based resources on tab close (#14359) Fixes https://github.com/eclipse-theia/theia/issues/14203 --- .../src/main/browser/tabs/tabs-main.ts | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/packages/plugin-ext/src/main/browser/tabs/tabs-main.ts b/packages/plugin-ext/src/main/browser/tabs/tabs-main.ts index d78631ef74d0c..6d95564e771ee 100644 --- a/packages/plugin-ext/src/main/browser/tabs/tabs-main.ts +++ b/packages/plugin-ext/src/main/browser/tabs/tabs-main.ts @@ -43,6 +43,7 @@ export class TabsMainImpl implements TabsMain, Disposable { private applicationShell: ApplicationShell; private disposableTabBarListeners: DisposableCollection = new DisposableCollection(); + private disposableTitleListeners: Map = new Map(); private toDisposeOnDestroy: DisposableCollection = new DisposableCollection(); private groupIdCounter = 1; @@ -131,6 +132,7 @@ export class TabsMainImpl implements TabsMain, Disposable { } const newTabGroupModel = new Map, TabGroupDto>(); this.tabInfoLookup.clear(); + this.disposableTitleListeners.forEach(disposable => disposable.dispose()); this.disposableTabBarListeners.dispose(); this.applicationShell.mainAreaTabBars .forEach(tabBar => { @@ -185,12 +187,21 @@ export class TabsMainImpl implements TabsMain, Disposable { }; } + protected getTitleDisposables(title: Title): DisposableCollection { + let disposable = this.disposableTitleListeners.get(title.owner.id); + if (!disposable) { + disposable = new DisposableCollection(); + this.disposableTitleListeners.set(title.owner.id, disposable); + } + return disposable; + } + protected attachListenersToTabBar(tabBar: TabBar | undefined): void { if (!tabBar) { return; } tabBar.titles.forEach(title => { - this.connectToSignal(this.disposableTabBarListeners, title.changed, this.onTabTitleChanged); + this.connectToSignal(this.getTitleDisposables(title), title.changed, this.onTabTitleChanged); }); this.connectToSignal(this.disposableTabBarListeners, tabBar.tabMoved, this.onTabMoved); @@ -261,7 +272,7 @@ export class TabsMainImpl implements TabsMain, Disposable { // #region event listeners private onTabCreated(tabBar: TabBar, args: TabBar.ITabActivateRequestedArgs): void { const group = this.getOrRebuildModel(this.tabGroupModel, tabBar); - this.connectToSignal(this.disposableTabBarListeners, args.title.changed, this.onTabTitleChanged); + this.connectToSignal(this.getTitleDisposables(args.title), args.title.changed, this.onTabTitleChanged); const tabDto = this.createTabDto(args.title, group.groupId, true); this.tabInfoLookup.set(args.title, { group, tab: tabDto, tabIndex: args.index }); group.tabs.splice(args.index, 0, tabDto); @@ -306,6 +317,8 @@ export class TabsMainImpl implements TabsMain, Disposable { } private onTabClosed(tabInfo: TabInfo, title: Title): void { + this.disposableTitleListeners.get(title.owner.id)?.dispose(); + this.disposableTitleListeners.delete(title.owner.id); tabInfo.group.tabs.splice(tabInfo.tabIndex, 1); this.tabInfoLookup.delete(title); this.updateTabIndices(tabInfo, tabInfo.tabIndex); @@ -384,5 +397,7 @@ export class TabsMainImpl implements TabsMain, Disposable { dispose(): void { this.toDisposeOnDestroy.dispose(); this.disposableTabBarListeners.dispose(); + this.disposableTitleListeners.forEach(disposable => disposable.dispose()); + this.disposableTitleListeners.clear(); } }