4444import org .eclipse .swt .widgets .Composite ;
4545import org .eclipse .swt .widgets .Control ;
4646import org .eclipse .swt .widgets .Display ;
47+ import org .eclipse .swt .widgets .Event ;
4748import org .eclipse .swt .widgets .Group ;
4849import org .eclipse .swt .widgets .Item ;
4950import org .eclipse .swt .widgets .Label ;
@@ -222,18 +223,32 @@ public static void context(Object widget, Object... args) {
222223
223224 Throwable thrown = null ;
224225 SWTBotMenu currMenu = null ;
226+ boolean firstAttempt = true ;
225227 while (System .nanoTime () < expireTimeInNanos && currMenu == null ) {
226228
227229 AbstractSWTBot <?> obj = null ;
228230 if (widget instanceof TreeItem ) {
229-
230231 obj = new SWTBotTreeItem ((TreeItem ) widget );
231232 } else if (widget instanceof TableItem ) {
232233 obj = new SWTBotTableItem ((TableItem ) widget );
233234 } else {
234235 throw new RuntimeException ("Unable to identify context object type: " + widget .getClass ().getName ());
235236 }
236237
238+ if (!firstAttempt ) {
239+ // On retry: dismiss any stale context menu that may still be open, then
240+ // re-select/focus the widget so Eclipse can repopulate dynamic contributions
241+ // (e.g. "Run As" / "Debug As") before we open the menu again.
242+ dismissOpenContextMenu ();
243+ if (widget instanceof TreeItem ) {
244+ SWTBotTreeItem ti = (SWTBotTreeItem ) obj ;
245+ ti .select ();
246+ ti .setFocus ();
247+ }
248+ pause (2000 );
249+ }
250+ firstAttempt = false ;
251+
237252 try {
238253 for (int x = 0 ; x < args .length ; x ++) {
239254 if (x == 0 ) {
@@ -252,8 +267,7 @@ public static void context(Object widget, Object... args) {
252267 } catch (Throwable t ) {
253268 thrown = t ;
254269 currMenu = null ;
255- System .out .println ("waiting for context menu." );
256- pause (2000 );
270+ System .out .println ("waiting for context menu: " + t .getMessage ());
257271 }
258272 } // end-while
259273
@@ -266,6 +280,36 @@ public static void context(Object widget, Object... args) {
266280 }
267281 }
268282
283+ /**
284+ * Dismisses any currently open context menu by sending an Escape key on the
285+ * active display.
286+ */
287+ private static void dismissOpenContextMenu () {
288+ try {
289+ Display .getDefault ().syncExec (new Runnable () {
290+ @ Override
291+ public void run () {
292+ // Post an Escape key event to close any open popup/context menu.
293+ Event escDown = new Event ();
294+ escDown .type = SWT .KeyDown ;
295+ escDown .keyCode = SWT .ESC ;
296+ Display .getDefault ().post (escDown );
297+
298+ Event escUp = new Event ();
299+ escUp .type = SWT .KeyUp ;
300+ escUp .keyCode = SWT .ESC ;
301+ Display .getDefault ().post (escUp );
302+ }
303+ });
304+ // Give the UI thread time to process the Escape and close the menu.
305+ pause (300 );
306+ } catch (Throwable t ) {
307+ // Non-fatal: if we cannot dismiss the menu, the next contextMenu() call
308+ // will still attempt to open a fresh one.
309+ System .out .println ("Could not dismiss open context menu: " + t .getMessage ());
310+ }
311+ }
312+
269313 public static Object get (Object w ) {
270314 return get (w , Option .getGlobalOptions ());
271315
0 commit comments