Bug 117095  -  [flex-hierarchy] resuming one thread does not select next suspended thread
diff --git a/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/viewers/AsynchronousTreeViewer.java b/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/viewers/AsynchronousTreeViewer.java
index 77f6f37..90ec23e 100644
--- a/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/viewers/AsynchronousTreeViewer.java
+++ b/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/viewers/AsynchronousTreeViewer.java
@@ -936,6 +936,16 @@
 		}
 	}	
 
+	synchronized void remove(final Widget widget) {
+		preservingSelection(new Runnable() {
+			public void run() {
+				Object element = widget.getData(); 
+				unmap(element, widget);
+				widget.dispose();		
+			}
+		});
+	}
+	
 	void setLabels(Widget widget, String[] text, ImageDescriptor[] image) {
 		if (widget instanceof TreeItem) {
 			TreeItem item = (TreeItem) widget;
diff --git a/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/viewers/RemoveRequestMonitor.java b/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/viewers/RemoveRequestMonitor.java
index 989b618..33b0049 100644
--- a/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/viewers/RemoveRequestMonitor.java
+++ b/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/viewers/RemoveRequestMonitor.java
@@ -33,10 +33,7 @@
 	 * @see org.eclipse.debug.internal.ui.viewers.AsynchronousRequestMonitor#performUpdate()
 	 */
 	protected void performUpdate() {
-		Widget widget = getWidget();
-		Object element = widget.getData(); 
-		getViewer().unmap(element, widget);
-		widget.dispose();
+		((AsynchronousTreeViewer)getViewer()).remove(getWidget());
 	}
 
 }
diff --git a/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/viewers/update/DefaultSelectionPolicy.java b/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/viewers/update/DefaultSelectionPolicy.java
index 68db304..516e298 100644
--- a/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/viewers/update/DefaultSelectionPolicy.java
+++ b/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/viewers/update/DefaultSelectionPolicy.java
@@ -83,7 +83,7 @@
 		if (existing instanceof IStackFrame && candidate instanceof IStackFrame) {
 			IStackFrame curr = (IStackFrame) existing;
 			IStackFrame next = (IStackFrame) candidate;
-			return curr.getThread().equals(next.getThread());
+			return curr.getThread().equals(next.getThread()) || !isSticky(existing);
 		}
 		return !isSticky(existing);
 	}
diff --git a/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/viewers/update/ThreadEventHandler.java b/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/viewers/update/ThreadEventHandler.java
index e6e4405..ef54077 100644
--- a/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/viewers/update/ThreadEventHandler.java
+++ b/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/viewers/update/ThreadEventHandler.java
@@ -11,7 +11,9 @@
 package org.eclipse.debug.internal.ui.viewers.update;
 
 import java.util.HashMap;
+import java.util.LinkedHashSet;
 import java.util.Map;
+import java.util.Set;
 
 import org.eclipse.debug.core.DebugEvent;
 import org.eclipse.debug.core.DebugException;
@@ -27,6 +29,13 @@
  */
 public class ThreadEventHandler extends DebugEventHandler {
 	
+	/**
+	 * Queue of suspended threads to choose from when needing
+	 * to select a thread when another is resumed. Threads
+	 * are added in the order they suspend.
+	 */
+	private Set fThreadQueue = new LinkedHashSet();
+	
 	/** 
 	 * Map of previous TOS per thread
 	 */
@@ -44,6 +53,9 @@
 		synchronized (fLastTopFrame) {
 			fLastTopFrame.clear();
 		}
+		synchronized (fThreadQueue) {
+			fThreadQueue.clear();
+		}
 		super.dispose();
 	}
 
@@ -59,6 +71,7 @@
 			} catch (DebugException e) {
 			}
         } else {
+        	queueSuspendedThread(event);
         	fireDeltaUpdatingTopFrame(thread, IModelDelta.NOCHANGE);
         }
 	}
@@ -74,7 +87,12 @@
 	}
 
 	protected void handleResume(DebugEvent event) {
-		fireDeltaAndClearTopFrame((IThread) event.getSource(), IModelDelta.CHANGED | IModelDelta.STATE | IModelDelta.CONTENT);
+		IThread thread = removeSuspendedThread(event);
+		fireDeltaAndClearTopFrame(thread, IModelDelta.CHANGED | IModelDelta.STATE | IModelDelta.CONTENT);
+		thread = getNextSuspendedThread();
+		if (thread != null) {
+			fireDeltaUpdatingTopFrame(thread, IModelDelta.NOCHANGE);
+		}
 	}
 
 	protected void handleCreate(DebugEvent event) {
@@ -90,11 +108,13 @@
 	}
 
 	protected void handleLateSuspend(DebugEvent suspend, DebugEvent resume) {
-		fireDeltaUpdatingTopFrame((IThread) suspend.getSource(), IModelDelta.CHANGED | IModelDelta.CONTENT | IModelDelta.EXPAND);
+		IThread thread = queueSuspendedThread(suspend);
+		fireDeltaUpdatingTopFrame(thread, IModelDelta.CHANGED | IModelDelta.CONTENT | IModelDelta.EXPAND);
 	}
 
 	protected void handleSuspendTimeout(DebugEvent event) {
-		fireDeltaAndClearTopFrame((IThread) event.getSource(), IModelDelta.CHANGED | IModelDelta.CONTENT);
+		IThread thread = removeSuspendedThread(event);
+		fireDeltaAndClearTopFrame(thread, IModelDelta.CHANGED | IModelDelta.CONTENT);
 	}
 	
 	private IModelDeltaNode buildBaseDelta(ModelDelta delta, IThread thread) {
@@ -143,5 +163,30 @@
 	protected boolean handlesEvent(DebugEvent event) {
 		return event.getSource() instanceof IThread;
 	}
+	
+	protected IThread queueSuspendedThread(DebugEvent event) {
+		IThread thread = (IThread) event.getSource();
+		synchronized (fThreadQueue) {
+			fThreadQueue.add(thread);
+		}
+		return thread;
+	}
+	
+	protected IThread removeSuspendedThread(DebugEvent event) {
+		IThread thread = (IThread)event.getSource();
+		synchronized (fThreadQueue) {
+			fThreadQueue.remove(thread);
+		}
+		return thread;
+	}
+	
+	protected IThread getNextSuspendedThread() {
+		synchronized (fThreadQueue) {
+			if (!fThreadQueue.isEmpty()) {
+				return (IThread) fThreadQueue.iterator().next();
+			}
+		}
+		return null;
+	}
 
 }