Backported fix for bug 312189: [quick assist] BadLocationException when applying proposal while preview is computed
diff --git a/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/text/correction/proposals/ChangeCorrectionProposal.java b/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/text/correction/proposals/ChangeCorrectionProposal.java
index da64adc..3c9a32f 100644
--- a/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/text/correction/proposals/ChangeCorrectionProposal.java
+++ b/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/text/correction/proposals/ChangeCorrectionProposal.java
@@ -17,6 +17,7 @@
 import org.eclipse.swt.graphics.Image;
 import org.eclipse.swt.graphics.Point;
 import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Display;
 
 import org.eclipse.core.runtime.CoreException;
 import org.eclipse.core.runtime.IProgressMonitor;
@@ -63,6 +64,8 @@
  */
 public class ChangeCorrectionProposal implements IJavaCompletionProposal, ICommandAccess, ICompletionProposalExtension5, ICompletionProposalExtension6 {
 
+	private static final NullChange COMPUTING_CHANGE= new NullChange("ChangeCorrectionProposal computing..."); //$NON-NLS-1$
+	
 	private Change fChange;
 	private String fName;
 	private int fRelevance;
@@ -301,9 +304,53 @@
 		if (Util.isGtk()) {
 			// workaround for https://bugs.eclipse.org/bugs/show_bug.cgi?id=293995 :
 			// [Widgets] Deadlock while UI thread displaying/computing a change proposal and non-UI thread creating image
-			if (fChange == null) {
-				fChange= createChange();
+			
+			// Solution is to create the change outside a 'synchronized' block.
+			// Synchronization is achieved by polling fChange, using "fChange == COMPUTING_CHANGE" as barrier.
+			// Timeout of 10s for safety reasons (should not be reached).
+			long end= System.currentTimeMillis() + 10000;
+			do {
+				boolean computing;
+				synchronized (this) {
+					computing= fChange == COMPUTING_CHANGE;
+				}
+				if (computing) {
+					try {
+						Display display= Display.getCurrent();
+						if (display != null) {
+							while (! display.isDisposed() && display.readAndDispatch()) {
+							}
+							display.sleep();
+						} else {
+							Thread.sleep(100);
+						}
+					} catch (InterruptedException e) {
+						//continue
+					}
+				} else {
+					synchronized (this) {
+						if (fChange == COMPUTING_CHANGE) {
+							continue;
+						} else if (fChange != null) {
+							return fChange;
+						} else {
+							fChange= COMPUTING_CHANGE;
+						}
+					}
+					Change change= createChange();
+					synchronized (this) {
+						fChange= change;
+					}
+					return change;
+				}
+			} while (System.currentTimeMillis() < end);
+			
+			synchronized (this) {
+				if (fChange == COMPUTING_CHANGE) {
+					return null; //failed
+				}
 			}
+			
 		} else {
 			synchronized (this) {
 				if (fChange == null) {