Skip to content

Commit 2c56112

Browse files
committed
Text control should not redraw indefinitely
In some scenarios, `Text` control redraws on every event loop iteration. See eclipse-platform/eclipse.platform.ui#3920 This is a JUnit test reproducing the problem.
1 parent f03d65d commit 2c56112

1 file changed

Lines changed: 54 additions & 0 deletions

File tree

tests/org.eclipse.swt.tests/JUnit Tests/org/eclipse/swt/tests/junit/Test_org_eclipse_swt_widgets_Text.java

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,12 +13,14 @@
1313
*******************************************************************************/
1414
package org.eclipse.swt.tests.junit;
1515

16+
import static java.lang.System.currentTimeMillis;
1617
import static org.eclipse.swt.tests.junit.SwtTestUtil.JENKINS_DETECT_ENV_VAR;
1718
import static org.eclipse.swt.tests.junit.SwtTestUtil.JENKINS_DETECT_REGEX;
1819
import static org.junit.jupiter.api.Assertions.assertEquals;
1920
import static org.junit.jupiter.api.Assertions.assertFalse;
2021
import static org.junit.jupiter.api.Assertions.assertThrows;
2122
import static org.junit.jupiter.api.Assertions.assertTrue;
23+
import static org.junit.jupiter.api.Assertions.fail;
2224

2325
import org.eclipse.swt.SWT;
2426
import org.eclipse.swt.events.ModifyListener;
@@ -30,6 +32,7 @@
3032
import org.eclipse.swt.graphics.Font;
3133
import org.eclipse.swt.graphics.FontData;
3234
import org.eclipse.swt.graphics.Point;
35+
import org.eclipse.swt.layout.FillLayout;
3336
import org.eclipse.swt.widgets.Display;
3437
import org.eclipse.swt.widgets.Event;
3538
import org.eclipse.swt.widgets.Group;
@@ -1376,6 +1379,48 @@ public void test_showSelection() {
13761379
text.showSelection();
13771380
}
13781381

1382+
// Originally reported as https://github.com/eclipse-platform/eclipse.platform.ui/issues/3920
1383+
@Test
1384+
public void test_finiteRedraw() {
1385+
if ( text != null ) text.dispose();
1386+
// Style constants are causing
1387+
// org.eclipse.swt.widgets.Text.drawInteriorWithFrame_inView_searchfield(long, long, NSRect, long)
1388+
// to call
1389+
// org.eclipse.swt.internal.cocoa.NSControl.stringValue()
1390+
// which schedules redraw
1391+
text = new Text(shell, SWT.SEARCH | SWT.ICON_CANCEL);
1392+
// Background prevents early exit from drawInteriorWithFrame_inView_searchfield(long, long, NSRect, long)
1393+
text.setBackground(shell.getDisplay().getSystemColor(SWT.COLOR_RED));
1394+
setWidget(text);
1395+
shell.setLayout(new FillLayout());
1396+
text.requestLayout();
1397+
shell.open();
1398+
Display display = shell.getDisplay();
1399+
text.forceFocus();
1400+
waitUntilIdle();
1401+
long start = currentTimeMillis();
1402+
long stop = start + 1000;
1403+
int eventStreakCount = 0;
1404+
while (currentTimeMillis() < stop) {
1405+
// If redraws are constantly scheduled, readAndDispatch() rarely return false.
1406+
// Side effects - high CPU usage, asyncExec() stops working in modal contexts
1407+
if (display.readAndDispatch()) {
1408+
eventStreakCount++;
1409+
// Skip other events of the streak
1410+
// No need to count events individually, as many events immediately following each other are common and normal
1411+
// Currently, streaks are short, but we do no want any noise to cause test failures as UI evolves
1412+
waitUntilIdle();
1413+
} else {
1414+
Thread.yield();
1415+
}
1416+
}
1417+
String message = "Detected " + eventStreakCount + " UI event streaks per second. Expected rate: 5 event streaks per second or less.";
1418+
assertTrue(eventStreakCount < 50, message);
1419+
if (SwtTestUtil.verbose) {
1420+
System.out.println(message);
1421+
}
1422+
}
1423+
13791424
/* custom */
13801425
Text text;
13811426
String delimiterString;
@@ -1639,4 +1684,13 @@ private void pasteFromClipboard(Text text) throws InterruptedException {
16391684
SwtTestUtil.processEvents(1000, () -> !oldText.equals(text.getText()));
16401685
}
16411686

1687+
private void waitUntilIdle() {
1688+
long hangTimeout = currentTimeMillis() + 1000;
1689+
while (shell.getDisplay().readAndDispatch()) {
1690+
if (currentTimeMillis() > hangTimeout) {
1691+
fail("UI scheduler should settle");
1692+
}
1693+
}
1694+
}
1695+
16421696
}

0 commit comments

Comments
 (0)