diff --git a/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/widgets/Link.java b/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/widgets/Link.java
index 48d78d9b565..0e20b8175d3 100644
--- a/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/widgets/Link.java
+++ b/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/widgets/Link.java
@@ -627,6 +627,17 @@ LRESULT WM_CHAR (long wParam, long lParam) {
return result;
}
+@Override
+LRESULT WM_ERASEBKGND (long wParam, long lParam) {
+ LRESULT result = super.WM_ERASEBKGND (wParam, lParam);
+ if (result != null) return result;
+ /*
+ * Feature in Windows. The SysLink control flashes when resized.
+ * The fix is to prevent the background from being erased.
+ */
+ return LRESULT.ONE;
+}
+
@Override
LRESULT WM_GETDLGCODE (long wParam, long lParam) {
long code = callWindowProc (handle, OS.WM_GETDLGCODE, wParam, lParam);
diff --git a/tests/org.eclipse.swt.tests.win32/JUnit Tests/org/eclipse/swt/tests/win32/widgets/Test_org_eclipse_swt_widgets_Link.java b/tests/org.eclipse.swt.tests.win32/JUnit Tests/org/eclipse/swt/tests/win32/widgets/Test_org_eclipse_swt_widgets_Link.java
new file mode 100644
index 00000000000..3a29416f46b
--- /dev/null
+++ b/tests/org.eclipse.swt.tests.win32/JUnit Tests/org/eclipse/swt/tests/win32/widgets/Test_org_eclipse_swt_widgets_Link.java
@@ -0,0 +1,128 @@
+package org.eclipse.swt.tests.win32.widgets;
+
+import static org.junit.jupiter.api.Assertions.*;
+
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.graphics.Point;
+import org.eclipse.swt.graphics.Rectangle;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.swt.widgets.Link;
+import org.eclipse.swt.widgets.Shell;
+import org.junit.jupiter.api.Test;
+
+public class Test_org_eclipse_swt_widgets_Link {
+
+ @Test
+ public void test_LinkRendersCorrectlyAfterResize() {
+ Display display = new Display();
+ try {
+ Shell shell = new Shell(display);
+ shell.setSize(400, 300);
+ Link link = new Link(shell, SWT.NONE);
+ link.setText("Visit Eclipse website");
+ link.setBounds(10, 10, 200, 50);
+
+ shell.open();
+
+ // Force initial paint
+ while (display.readAndDispatch()) {
+ // loop until no more events
+ }
+
+ // Resize multiple times rapidly (stress test for flicker)
+ for (int i = 0; i < 10; i++) {
+ link.setSize(200 + (i * 10), 50 + (i * 5));
+ while (display.readAndDispatch()) {
+ // loop until no more events
+ }
+ }
+
+ // Verify link is still functional and sized correctly
+ Point size = link.getSize();
+ assertTrue(size.x > 0 && size.y > 0, "Link should have valid size after resize");
+ assertEquals("Visit Eclipse website",
+ link.getText(), "Link text should be preserved after resize");
+
+ // Verify the link is still visible and has proper bounds
+ Rectangle bounds = link.getBounds();
+ assertTrue(bounds.width > 0 && bounds.height > 0,
+ "Link should have valid bounds after multiple resizes");
+
+ shell.close();
+ } finally {
+ display.dispose();
+ }
+ }
+
+ @Test
+ public void test_LinkBackgroundNotErasedDuringPaint() {
+ Display display = new Display();
+ try {
+ Shell shell = new Shell(display);
+ Link link = new Link(shell, SWT.NONE);
+ link.setText("Test link");
+
+ final int[] paintCount = {0};
+ final int[] eraseCount = {0};
+
+ // Monitor paint events
+ link.addListener(SWT.Paint, e -> paintCount[0]++);
+ link.addListener(SWT.EraseItem, e -> eraseCount[0]++);
+
+ shell.setSize(300, 200);
+ shell.open();
+
+ // Trigger redraws
+ for (int i = 0; i < 5; i++) {
+ link.redraw();
+ while (display.readAndDispatch()) {
+ // loop until no more events
+ }
+ }
+
+ // We should see paints, but minimal erase operations
+ assertTrue(paintCount[0] > 0, "Link should have been painted");
+ // Note: EraseItem may not fire for Link widget, this is platform-specific
+
+ shell.close();
+ } finally {
+ display.dispose();
+ }
+ }
+
+ @Test
+ public void test_LinkMaintainsContentDuringRapidResize() {
+ Display display = new Display();
+ try {
+ Shell shell = new Shell(display);
+ shell.setSize(400, 300);
+ Link link = new Link(shell, SWT.NONE);
+ String testText = "Click here or there";
+ link.setText(testText);
+ link.setBounds(10, 10, 300, 100);
+
+ shell.open();
+ while (display.readAndDispatch()) {
+ // loop until no more events
+ }
+
+ // Rapidly resize - this would cause flickering in the old implementation
+ for (int i = 0; i < 20; i++) {
+ int newWidth = 200 + (i % 2) * 100;
+ int newHeight = 50 + (i % 2) * 30;
+ link.setSize(newWidth, newHeight);
+
+ // Process events but don't wait for full redraw
+ display.readAndDispatch();
+
+ // Content should remain intact
+ assertEquals(testText, link.getText(),
+ "Link text should remain unchanged during resize iteration " + i);
+ }
+
+ shell.close();
+ } finally {
+ display.dispose();
+ }
+ }
+}
\ No newline at end of file
diff --git a/tests/org.eclipse.swt.tests/JUnit Tests/org/eclipse/swt/tests/junit/Test_org_eclipse_swt_widgets_Link.java b/tests/org.eclipse.swt.tests/JUnit Tests/org/eclipse/swt/tests/junit/Test_org_eclipse_swt_widgets_Link.java
index 0159400a080..2bb30e8a30e 100644
--- a/tests/org.eclipse.swt.tests/JUnit Tests/org/eclipse/swt/tests/junit/Test_org_eclipse_swt_widgets_Link.java
+++ b/tests/org.eclipse.swt.tests/JUnit Tests/org/eclipse/swt/tests/junit/Test_org_eclipse_swt_widgets_Link.java
@@ -24,6 +24,9 @@
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.events.SelectionListener;
import org.eclipse.swt.graphics.Color;
+import org.eclipse.swt.graphics.Point;
+import org.eclipse.swt.graphics.Rectangle;
+import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Event;
import org.eclipse.swt.widgets.Link;
import org.junit.jupiter.api.BeforeEach;
@@ -62,6 +65,7 @@ public void test_ConstructorLorg_eclipse_swt_widgets_CompositeI() {
fail("No exception thrown for parent == null");
}
catch (IllegalArgumentException e) {
+ // expected
}
}
@@ -82,6 +86,7 @@ public void widgetDefaultSelected(SelectionEvent e) {
link.addSelectionListener(null);
fail("No exception thrown for addSelectionListener with null argument");
} catch (IllegalArgumentException e) {
+ // expected
}
link.addSelectionListener(listener);
@@ -92,6 +97,7 @@ public void widgetDefaultSelected(SelectionEvent e) {
link.removeSelectionListener(null);
fail("No exception thrown for removeSelectionListener with null argument");
} catch (IllegalArgumentException e) {
+ // expected
}
listenerCalled = false;
link.removeSelectionListener(listener);
@@ -172,6 +178,7 @@ public void test_setTextLjava_lang_String() {
link.setText(null);
fail("No exception thrown for text == null");
} catch (IllegalArgumentException e) {
+ // expected
}
}
@@ -184,4 +191,90 @@ public void test_setLinkForegroundLorg_eclipse_swt_graphics_Color() {
link.setLinkForeground(null);
assertNotEquals(color, link.getForeground());
}
+
+
+@Test
+public void test_LinkRendersCorrectlyAfterResize() {
+ shell.setSize(400, 300);
+ link.setText("Visit Eclipse website");
+ link.setBounds(10, 10, 200, 50);
+
+ shell.open();
+
+ Display display = shell.getDisplay();
+ // Force initial paint
+ while (display.readAndDispatch()) {
+ // loop until no more events
+ }
+
+ // Resize multiple times rapidly (stress test for flicker)
+ for (int i = 0; i < 10; i++) {
+ link.setSize(200 + (i * 10), 50 + (i * 5));
+ while (display.readAndDispatch()) {
+ // loop until no more events
+ }
+ }
+
+ // Verify link is still functional and sized correctly
+ Point size = link.getSize();
+ assertTrue(size.x > 0 && size.y > 0, "Link should have valid size after resize");
+ assertEquals("Visit Eclipse website",
+ link.getText(), "Link text should be preserved after resize");
+
+ // Verify the link is still visible and has proper bounds
+ Rectangle bounds = link.getBounds();
+ assertTrue(bounds.width > 0 && bounds.height > 0,
+ "Link should have valid bounds after multiple resizes");
+}
+
+@Test
+public void test_LinkBackgroundNotErasedDuringPaint() {
+ link.setText("Test link");
+
+ shell.setSize(300, 200);
+ link.setVisible(true);
+ shell.open();
+
+ Display display = shell.getDisplay();
+ // Trigger redraws and ensure no crashes or obvious rendering failure
+ for (int i = 0; i < 10; i++) {
+ link.redraw();
+ link.update();
+ while (display.readAndDispatch()) {
+ // loop until no more events
+ }
+ }
+
+ // Verify the link is still valid and has correct text
+ assertFalse(link.isDisposed(), "Link should not be disposed after multiple redraws");
+ assertEquals("Test link", link.getText(), "Link text should be intact");
+}
+
+@Test
+public void test_LinkMaintainsContentDuringRapidResize() {
+ shell.setSize(400, 300);
+ String testText = "Click here or there";
+ link.setText(testText);
+ link.setBounds(10, 10, 300, 100);
+
+ shell.open();
+ Display display = shell.getDisplay();
+ while (display.readAndDispatch()) {
+ // loop until no more events
+ }
+
+ // Rapidly resize - this would cause flickering in the old implementation
+ for (int i = 0; i < 20; i++) {
+ int newWidth = 200 + (i % 2) * 100;
+ int newHeight = 50 + (i % 2) * 30;
+ link.setSize(newWidth, newHeight);
+
+ // Process events but don't wait for full redraw
+ display.readAndDispatch();
+
+ // Content should remain intact
+ assertEquals(testText, link.getText(),
+ "Link text should remain unchanged during resize iteration " + i);
+ }
+}
}