From 1d34399daf488bfe92ceadd0cf1366dac97bea6f Mon Sep 17 00:00:00 2001 From: fedejeanne <2205684+fedejeanne@users.noreply.github.com> Date: Sun, 15 Mar 2026 20:58:31 +0100 Subject: [PATCH 1/2] Fix shared-area views leaking across perspectives --- .../addons/dndaddon/StackDropAgent.java | 46 ++++++++++++++++++ .../internal/workbench/ModelServiceImpl.java | 6 +++ .../eclipse/ui/internal/WorkbenchPage.java | 48 +++++++++++++++++++ 3 files changed, 100 insertions(+) diff --git a/bundles/org.eclipse.e4.ui.workbench.addons.swt/src/org/eclipse/e4/ui/workbench/addons/dndaddon/StackDropAgent.java b/bundles/org.eclipse.e4.ui.workbench.addons.swt/src/org/eclipse/e4/ui/workbench/addons/dndaddon/StackDropAgent.java index f519151bbbd1..0e8fdaa484d2 100644 --- a/bundles/org.eclipse.e4.ui.workbench.addons.swt/src/org/eclipse/e4/ui/workbench/addons/dndaddon/StackDropAgent.java +++ b/bundles/org.eclipse.e4.ui.workbench.addons.swt/src/org/eclipse/e4/ui/workbench/addons/dndaddon/StackDropAgent.java @@ -21,7 +21,9 @@ import java.util.stream.Stream; import org.eclipse.e4.ui.internal.workbench.swt.AbstractPartRenderer; import org.eclipse.e4.ui.model.application.ui.MUIElement; +import org.eclipse.e4.ui.model.application.ui.advanced.MPerspective; import org.eclipse.e4.ui.model.application.ui.advanced.MPlaceholder; +import org.eclipse.e4.ui.model.application.ui.basic.MPart; import org.eclipse.e4.ui.model.application.ui.basic.MPartStack; import org.eclipse.e4.ui.model.application.ui.basic.MStackElement; import org.eclipse.e4.ui.model.application.ui.basic.MWindow; @@ -38,6 +40,9 @@ * This agent manage drag and drop when dragging a Tab in Eclipse Part Stacks. */ public class StackDropAgent extends DropAgent { + private static final String PERSPECTIVE_SCOPED_OWNER_ID = + "org.eclipse.ui.workbench.viewInSharedAreaOwnerPerspectiveId"; //$NON-NLS-1$ + private Rectangle tabArea; private MPartStack dropStack; private CTabFolder dropCTF; @@ -242,6 +247,7 @@ private void dock(MUIElement dragElement, int dropIndex) { List vItems = getVisibleItems(dropCTF); boolean hiddenTabs = (vItems.size() < dropCTF.getChildren().length); + List movedElements = new ArrayList<>(); // Adjust the index if necessary List dropChildren = dropStack.getChildren(); @@ -343,6 +349,7 @@ private void dock(MUIElement dragElement, int dropIndex) { } else { dropChildren.add((MStackElement) dragElement); } + movedElements.add((MStackElement) dragElement); // Bug 410164: remove placeholder element with same id from the drop stack to // avoid duplicated elements in same stack @@ -374,6 +381,7 @@ private void dock(MUIElement dragElement, int dropIndex) { } else { dropChildren.add(kid); } + movedElements.add(kid); } // Finally, move over the selected element @@ -384,10 +392,48 @@ private void dock(MUIElement dragElement, int dropIndex) { } else { dropChildren.add(curSel); } + movedElements.add(curSel); // (Re)active the element being dropped dropStack.setSelectedElement(curSel); } + + updatePerspectiveScopeForMovedViews(movedElements); + } + + private void updatePerspectiveScopeForMovedViews(List movedElements) { + EModelService modelService = dndManager.getModelService(); + boolean droppedInSharedArea = modelService.getElementLocation(dropStack) == EModelService.IN_SHARED_AREA; + String activePerspectiveId = null; + if (droppedInSharedArea) { + MWindow window = modelService.getTopLevelWindowFor(dropStack); + if (window != null) { + MPerspective activePerspective = modelService.getActivePerspective(window); + if (activePerspective != null) { + activePerspectiveId = activePerspective.getElementId(); + } + } + } + + for (MStackElement movedElement : movedElements) { + MUIElement trackedElement = movedElement; + if (movedElement instanceof MPlaceholder placeholder && placeholder.getRef() instanceof MPart part) { + if (part.getTags().contains("Editor")) { //$NON-NLS-1$ + continue; + } + trackedElement = placeholder; + } else if (movedElement instanceof MPart part) { + if (part.getTags().contains("Editor")) { //$NON-NLS-1$ + continue; + } + } + + if (droppedInSharedArea && activePerspectiveId != null) { + trackedElement.getPersistedState().put(PERSPECTIVE_SCOPED_OWNER_ID, activePerspectiveId); + } else { + trackedElement.getPersistedState().remove(PERSPECTIVE_SCOPED_OWNER_ID); + } + } } private void showFrame(MUIElement dragElement) { diff --git a/bundles/org.eclipse.e4.ui.workbench/src/org/eclipse/e4/ui/internal/workbench/ModelServiceImpl.java b/bundles/org.eclipse.e4.ui.workbench/src/org/eclipse/e4/ui/internal/workbench/ModelServiceImpl.java index 5fb2f8e00171..a53fd071b14b 100644 --- a/bundles/org.eclipse.e4.ui.workbench/src/org/eclipse/e4/ui/internal/workbench/ModelServiceImpl.java +++ b/bundles/org.eclipse.e4.ui.workbench/src/org/eclipse/e4/ui/internal/workbench/ModelServiceImpl.java @@ -88,6 +88,8 @@ public class ModelServiceImpl implements EModelService { static String HOSTED_ELEMENT = "HostedElement"; //$NON-NLS-1$ + private static final String PERSPECTIVE_SCOPED_OWNER_ID = + "org.eclipse.ui.workbench.viewInSharedAreaOwnerPerspectiveId"; //$NON-NLS-1$ private final IEclipseContext appContext; @@ -917,6 +919,10 @@ private void resetPerspectiveModel(MPerspective persp, MWindow window, // Strip out the placeholders in visible stacks List phList = findElements(area, null, MPlaceholder.class, null); for (MPlaceholder ph : phList) { + String ownerPerspectiveId = ph.getPersistedState().get(PERSPECTIVE_SCOPED_OWNER_ID); + if (ownerPerspectiveId != null && !ownerPerspectiveId.equals(persp.getElementId())) { + continue; + } ps.hidePart((MPart) ph.getRef()); ph.getParent().getChildren().remove(ph); } diff --git a/bundles/org.eclipse.ui.workbench/eclipseui/org/eclipse/ui/internal/WorkbenchPage.java b/bundles/org.eclipse.ui.workbench/eclipseui/org/eclipse/ui/internal/WorkbenchPage.java index 1a86593f6184..fa296e821921 100644 --- a/bundles/org.eclipse.ui.workbench/eclipseui/org/eclipse/ui/internal/WorkbenchPage.java +++ b/bundles/org.eclipse.ui.workbench/eclipseui/org/eclipse/ui/internal/WorkbenchPage.java @@ -199,6 +199,8 @@ public class WorkbenchPage implements IWorkbenchPage { private static final String ATT_AGGREGATE_WORKING_SET_ID = "aggregateWorkingSetId"; //$NON-NLS-1$ + private static final String PERSPECTIVE_SCOPED_OWNER_ID = + "org.eclipse.ui.workbench.viewInSharedAreaOwnerPerspectiveId"; //$NON-NLS-1$ private static final int WINDOW_SCOPE = EModelService.OUTSIDE_PERSPECTIVE | EModelService.IN_ANY_PERSPECTIVE | EModelService.IN_SHARED_AREA; @@ -2920,6 +2922,7 @@ private List getPartStacks(MPerspective perspective) { MPerspective oldPersp = (MPerspective) event.getProperty(UIEvents.EventTags.OLD_VALUE); MPerspective newPersp = (MPerspective) event.getProperty(UIEvents.EventTags.NEW_VALUE); // updatePerspectiveActionSets(oldPersp, newPersp); + updatePerspectiveScopedSharedViews(newPersp); // ((CoolBarToTrimManager) // legacyWindow.getCoolBarManager2()).updateAll(true); @@ -2980,6 +2983,51 @@ private List getPartStacks(MPerspective perspective) { legacyWindow.updateActionSets(); }; + private void updatePerspectiveScopedSharedViews(MPerspective activePerspective) { + String activePerspectiveId = activePerspective == null ? null : activePerspective.getElementId(); + + List sharedPlaceholders = modelService.findElements(window, null, MPlaceholder.class, null, + EModelService.OUTSIDE_PERSPECTIVE | EModelService.IN_SHARED_AREA); + for (MPlaceholder placeholder : sharedPlaceholders) { + String ownerPerspectiveId = placeholder.getPersistedState().get(PERSPECTIVE_SCOPED_OWNER_ID); + if (ownerPerspectiveId == null) { + continue; + } + boolean shouldRender = ownerPerspectiveId.equals(activePerspectiveId); + placeholder.setToBeRendered(shouldRender); + updateContainerVisibility(placeholder.getParent()); + } + + List sharedParts = modelService.findElements(window, null, MPart.class, null, + EModelService.OUTSIDE_PERSPECTIVE | EModelService.IN_SHARED_AREA); + for (MPart part : sharedParts) { + if (part.getCurSharedRef() != null) { + continue; + } + String ownerPerspectiveId = part.getPersistedState().get(PERSPECTIVE_SCOPED_OWNER_ID); + if (ownerPerspectiveId == null) { + continue; + } + boolean shouldRender = ownerPerspectiveId.equals(activePerspectiveId); + part.setToBeRendered(shouldRender); + updateContainerVisibility(part.getParent()); + } + } + + private void updateContainerVisibility(MElementContainer parent) { + if (parent == null) { + return; + } + for (Object child : parent.getChildren()) { + if (child instanceof MUIElement element && element.isVisible() && element.isToBeRendered()) { + parent.setToBeRendered(true); + return; + } + } + parent.setToBeRendered(false); + updateContainerVisibility(parent.getParent()); + } + /** * See IWorkbenchPage. */ From 44ec6d7640ac76f419c076f8caaa987f7b62b838 Mon Sep 17 00:00:00 2001 From: Eclipse Platform Bot Date: Sun, 15 Mar 2026 20:13:49 +0000 Subject: [PATCH 2/2] Version bump(s) for 4.40 stream --- .../org.eclipse.e4.ui.workbench.addons.swt/META-INF/MANIFEST.MF | 2 +- bundles/org.eclipse.e4.ui.workbench/META-INF/MANIFEST.MF | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/bundles/org.eclipse.e4.ui.workbench.addons.swt/META-INF/MANIFEST.MF b/bundles/org.eclipse.e4.ui.workbench.addons.swt/META-INF/MANIFEST.MF index b671e2de079a..b01ce425043e 100644 --- a/bundles/org.eclipse.e4.ui.workbench.addons.swt/META-INF/MANIFEST.MF +++ b/bundles/org.eclipse.e4.ui.workbench.addons.swt/META-INF/MANIFEST.MF @@ -1,7 +1,7 @@ Manifest-Version: 1.0 Bundle-ManifestVersion: 2 Bundle-SymbolicName: org.eclipse.e4.ui.workbench.addons.swt;singleton:=true -Bundle-Version: 1.6.0.qualifier +Bundle-Version: 1.6.100.qualifier Bundle-Name: %pluginName Bundle-Vendor: %providerName Bundle-Localization: plugin diff --git a/bundles/org.eclipse.e4.ui.workbench/META-INF/MANIFEST.MF b/bundles/org.eclipse.e4.ui.workbench/META-INF/MANIFEST.MF index 844d05c5e486..e2fe621770f0 100644 --- a/bundles/org.eclipse.e4.ui.workbench/META-INF/MANIFEST.MF +++ b/bundles/org.eclipse.e4.ui.workbench/META-INF/MANIFEST.MF @@ -1,7 +1,7 @@ Manifest-Version: 1.0 Bundle-ManifestVersion: 2 Bundle-SymbolicName: org.eclipse.e4.ui.workbench;singleton:=true -Bundle-Version: 1.18.200.qualifier +Bundle-Version: 1.18.300.qualifier Bundle-Name: %pluginName Bundle-Vendor: %providerName Bundle-Localization: plugin