29package com.jogamp.opengl.test.junit.util;
31import jogamp.newt.awt.event.AWTNewtEventFactory;
33import java.lang.Thread.UncaughtExceptionHandler;
34import java.lang.reflect.InvocationTargetException;
35import java.util.concurrent.atomic.AtomicInteger;
36import java.awt.AWTException;
37import java.awt.EventQueue;
38import java.awt.MouseInfo;
42import com.jogamp.nativewindow.NativeWindow;
43import com.jogamp.nativewindow.NativeWindowFactory;
44import com.jogamp.opengl.GLAutoDrawable;
46import org.junit.Assert;
48import com.jogamp.common.ExceptionUtils;
49import com.jogamp.common.util.awt.AWTEDTExecutor;
53 static final boolean DEBUG =
false;
58 static class OurUncaughtExceptionHandler
implements UncaughtExceptionHandler {
60 public void uncaughtException(
final Thread t,
final Throwable e) {
61 System.err.println(
"*** AWTRobotUtil: UncaughtException (this Thread "+Thread.currentThread().getName()+
") : Thread <"+t.getName()+
">, "+e.getClass().getName()+
": "+e.getMessage());
67 Thread.setDefaultUncaughtExceptionHandler(
new OurUncaughtExceptionHandler() );
73 if( EventQueue.isDispatchThread() ) {
76 synchronized ( awtEDTAliveSync ) {
77 awtEDTAliveFlag =
false;
78 EventQueue.invokeLater(aliveRun);
79 for (
int wait=0; wait<
POLL_DIVIDER && !awtEDTAliveFlag; wait++) {
82 }
catch (
final InterruptedException e) {
86 return awtEDTAliveFlag;
89 private static Runnable aliveRun =
new Runnable() {
92 awtEDTAliveFlag =
true;
94 private static Object awtEDTAliveSync =
new Object();
95 private static volatile boolean awtEDTAliveFlag =
false;
100 throw new Error(
"AWT EDT not alive");
110 public static void clearAWTFocus(Robot robot)
throws InterruptedException, InvocationTargetException, AWTException {
113 robot.setAutoWaitForIdle(
true);
115 javax.swing.SwingUtilities.invokeAndWait(
new Runnable() {
118 System.err.println(
"******** clearAWTFocus.0");
119 java.awt.KeyboardFocusManager.getCurrentKeyboardFocusManager().clearGlobalFocusOwner();
122 System.err.println(
"******** clearAWTFocus.X");
127 throws InterruptedException, InvocationTargetException {
128 if(obj instanceof com.jogamp.newt.Window) {
129 return getCenterLocationNEWT((com.jogamp.newt.Window)obj, onTitleBarIfWindow);
131 return getCenterLocationAWT((java.awt.Component)obj, onTitleBarIfWindow);
133 throw new RuntimeException(
"Neither AWT nor NEWT: "+obj);
136 private static int[] getCenterLocationNEWT(
final com.jogamp.newt.Window win,
final boolean onTitleBarIfWindow)
137 throws InterruptedException, InvocationTargetException {
140 if( onTitleBarIfWindow ) {
144 p0.
translate(win.getWidth()/2, win.getHeight()/2);
146 return new int[] { p0.
getX(), p0.
getY() };
148 private static int[] getCenterLocationAWT(
final java.awt.Component comp,
final boolean onTitleBarIfWindow)
149 throws InterruptedException, InvocationTargetException {
151 final java.awt.Point p0 = comp.getLocationOnScreen();
152 final java.awt.Rectangle r0 = comp.getBounds();
153 if( onTitleBarIfWindow && comp instanceof java.awt.Window) {
154 final java.awt.Window window = (java.awt.Window) comp;
155 final java.awt.Insets insets = window.getInsets();
156 y0 = (int) ( p0.getY() + insets.top / 2.0 + .5 ) ;
158 y0 = (int) ( p0.getY() + r0.getHeight() / 2.0 + .5 ) ;
160 x0 = (int) ( p0.getX() + r0.getWidth() / 2.0 + .5 ) ;
161 return new int[] { x0, y0 };
166 throws InterruptedException, InvocationTargetException {
167 if(obj instanceof com.jogamp.newt.Window) {
168 return getClientLocationNEWT((com.jogamp.newt.Window)obj, x, y);
170 return getClientLocationAWT((java.awt.Component)obj, x, y);
172 throw new RuntimeException(
"Neither AWT nor NEWT: "+obj);
175 private static int[] getClientLocationNEWT(
final com.jogamp.newt.Window win,
final int x,
final int y)
176 throws InterruptedException, InvocationTargetException {
178 return new int[] { p0.
getX(), p0.
getY() };
180 private static int[] getClientLocationAWT(
final java.awt.Component comp,
final int x,
final int y)
181 throws InterruptedException, InvocationTargetException {
182 final java.awt.Point p0 = comp.getLocationOnScreen();
183 return new int[] { (int)p0.
getX(), (int)p0.getY() };
187 robot.mouseMove( x, y );
199 throws AWTException, InterruptedException, InvocationTargetException {
203 window.addWindowFocusListener(winFA);
207 robot.setAutoWaitForIdle(
true);
210 System.err.println(
"toFront: robot pos: "+p0[0]+
"/"+p0[1]);
215 final int _wait = wait;
216 javax.swing.SwingUtilities.invokeAndWait(
new Runnable() {
220 window.setVisible(
true);
223 window.requestFocus();
230 window.removeWindowFocusListener(winFA);
232 System.err.println(
"*** AWTRobotUtil.toFrontAndRequestFocus() UI failure");
233 System.err.println(
"*** window: "+window);
234 System.err.println(
"*** window.hasFocus(): "+window.hasFocus());
235 ExceptionUtils.dumpStack(System.err);
245 public static void centerMouse(Robot robot,
final Object obj,
final boolean onTitleBarIfWindow)
246 throws AWTException, InterruptedException, InvocationTargetException {
250 robot.setAutoWaitForIdle(
true);
254 System.err.println(
"centerMouse: robot pos: "+p0[0]+
"x"+p0[1]+
", onTitleBarIfWindow: "+onTitleBarIfWindow);
260 throws AWTException, InterruptedException, InvocationTargetException {
264 robot.setAutoWaitForIdle(
true);
271 private static int getAWTClickTimeout() {
274 (Integer) java.awt.Toolkit.getDefaultToolkit().getDesktopProperty(
"awt.multiClickInterval");
283 if(obj instanceof com.jogamp.newt.Window) {
284 final int newt_to = com.jogamp.newt.event.MouseEvent.getClickTimeout();
285 final int awt_to = getAWTClickTimeout();
286 return Math.max(awt_to, newt_to);
288 return getAWTClickTimeout();
290 throw new RuntimeException(
"Neither AWT nor NEWT: "+obj);
301 throws AWTException, InterruptedException, InvocationTargetException {
311 public static void requestFocus(
final Robot robot,
final Object obj,
final boolean onTitleBarIfWindow)
312 throws AWTException, InterruptedException, InvocationTargetException {
314 final int mouseButton = java.awt.event.InputEvent.BUTTON1_MASK;
318 robot.mousePress(mouseButton);
319 robot.mouseRelease(mouseButton);
322 System.err.println(
"requestFocus: click, d: "+d+
" ms");
324 if(obj instanceof com.jogamp.newt.Window) {
325 requestFocusNEWT((com.jogamp.newt.Window) obj, onTitleBarIfWindow);
327 requestFocusAWT((java.awt.Component) obj, onTitleBarIfWindow);
329 throw new RuntimeException(
"Neither AWT nor NEWT: "+obj);
333 private static void requestFocusNEWT(
final com.jogamp.newt.Window win,
final boolean onTitleBarIfWindow)
334 throws AWTException, InterruptedException, InvocationTargetException {
336 System.err.println(
"requestFocus: NEWT Component");
338 private static void requestFocusAWT(
final java.awt.Component comp,
final boolean onTitleBarIfWindow)
339 throws AWTException, InterruptedException, InvocationTargetException {
340 javax.swing.SwingUtilities.invokeAndWait(
new Runnable() {
344 System.err.println(
"requestFocus: AWT Component");
349 public static void requestFocus(
final Robot robot,
final Object obj,
final int x,
final int y)
350 throws AWTException, InterruptedException, InvocationTargetException {
353 final boolean idling = robot.isAutoWaitForIdle();
354 final int mouseButton = java.awt.event.InputEvent.BUTTON1_MASK;
355 robot.mouseMove( x, y );
359 try { Thread.sleep(50); }
catch (
final InterruptedException e) { }
361 robot.mousePress(mouseButton);
362 robot.mouseRelease(mouseButton);
369 if(obj instanceof com.jogamp.newt.Window) {
370 return ((com.jogamp.newt.Window) obj).hasFocus();
372 final java.awt.Component comp = (java.awt.Component) obj;
373 final java.awt.KeyboardFocusManager kfm = java.awt.KeyboardFocusManager.getCurrentKeyboardFocusManager();
374 return comp == kfm.getPermanentFocusOwner();
376 throw new RuntimeException(
"Neither AWT nor NEWT: "+obj);
385 public static boolean waitForFocus(
final java.awt.Component comp,
final Runnable waitAction)
throws InterruptedException {
387 final java.awt.KeyboardFocusManager kfm = java.awt.KeyboardFocusManager.getCurrentKeyboardFocusManager();
388 for (wait=0; wait<
POLL_DIVIDER && comp != kfm.getPermanentFocusOwner(); wait++) {
389 if(
null != waitAction ) {
414 throws AWTException, InterruptedException, InvocationTargetException {
426 throw new RuntimeException(
"Neither AWT nor NEWT: "+
waitForFocus);
430 System.err.print(
"*** AWTRobotUtil.assertRequestFocusAndWait() ");
431 if( (
null == gain || gain.focusGained() ) && (
null == lost || !lost.focusLost() ) ) {
433 System.err.println(
"minor UI failure");
436 System.err.println(
"major UI failure");
441 System.err.println(
"*** requestFocus.hasFocus() - AWT: "+((java.awt.Component)
requestFocus).hasFocus());
446 System.err.println(
"*** waitForFocus.hasFocus() - AWT: "+((java.awt.Component)
waitForFocus).hasFocus());
448 System.err.println(
"*** gain: "+gain);
449 System.err.println(
"*** lost: "+lost);
450 ExceptionUtils.dumpStack(System.err);
452 Assert.assertTrue(
"Did not gain focus",
hasFocus);
455 private static void awtRobotKeyPress(
final Robot robot,
final int keyCode,
final int msDelay) {
456 robot.keyPress(keyCode);
457 robot.delay(msDelay);
459 private static void awtRobotKeyRelease(
final Robot robot,
final int keyCode,
final int msDelay) {
460 robot.keyRelease(keyCode);
461 robot.delay(msDelay);
465 public static int keyType(
final int i,
final Robot robot,
final int keyCode,
466 final Object obj,
final KeyEventCountAdapter counter)
throws InterruptedException, AWTException, InvocationTargetException
470 final long t0 = System.currentTimeMillis();
471 final int c0 =
null!=counter ? counter.getCount() : 0;
476 if(DEBUG) { System.err.println(i+
":"+j+
" KC1.0: "+counter+
" - regain focus on thread "+Thread.currentThread().getName()); }
480 if(DEBUG) { System.err.println(i+
":"+j+
" KC1.1: "+counter+
" on thread "+Thread.currentThread().getName()); }
481 awtRobotKeyPress(robot, keyCode, 50);
482 if(DEBUG) { System.err.println(i+
":"+j+
" KC1.2: "+counter+
" on thread "+Thread.currentThread().getName()); }
483 awtRobotKeyRelease(robot, keyCode, 100);
485 if(DEBUG) { System.err.println(i+
":"+j+
" KC1.3: "+counter); }
486 tc = (
null!=counter ? counter.getCount() : 1 ) - c0;
487 for (
int wait=0; wait<POLL_DIVIDER && 1 > tc; wait++) {
488 if(DEBUG) { System.err.println(i+
":"+j+
" KC1.4."+wait+
": "+counter+
", sleep for "+
TIME_OUT+
"ms"); }
490 tc = counter.getCount() - c0;
492 if(DEBUG) { System.err.println(i+
":"+j+
" KC1.X: tc "+tc+
", "+counter+
" on thread "+Thread.currentThread().getName()); }
494 Assert.assertEquals(
"Key ("+i+
":"+j+
") not typed one time on thread "+Thread.currentThread().getName(), 1, tc);
495 return (
int) ( System.currentTimeMillis() - t0 ) ;
499 public static int keyPress(
final int i,
final Robot robot,
final boolean press,
final int keyCode,
final int msDelay) {
500 final long t0 = System.currentTimeMillis();
502 awtRobotKeyPress(robot, keyCode, msDelay);
504 awtRobotKeyRelease(robot, keyCode, msDelay);
507 return (
int) ( System.currentTimeMillis() - t0 ) ;
511 public static int newtKeyPress(
final int i,
final Robot robot,
final boolean press,
final short newtKeyCode,
final int msDelay) {
512 final int keyCode = AWTNewtEventFactory.newtKeyCode2AWTKeyCode(newtKeyCode);
513 final long t0 = System.currentTimeMillis();
515 awtRobotKeyPress(robot, keyCode, msDelay);
517 awtRobotKeyRelease(robot, keyCode, msDelay);
520 return (
int) ( System.currentTimeMillis() - t0 ) ;
529 public static void assertKeyType(Robot robot,
final int keyCode,
final int typeCount,
531 throws AWTException, InterruptedException, InvocationTargetException {
535 robot.setAutoWaitForIdle(
true);
540 Assert.assertEquals(
"Key already pressed",
false, counter.isPressed());
543 System.err.println(
"**************************************");
544 System.err.println(
"KC0: "+counter);
547 final int c0 = counter.getCount();
549 for(
int i=0; i<typeCount; i++) {
550 keyType(i, robot, keyCode, obj, counter);
553 if(DEBUG) { System.err.println(
"KC3.0: "+counter); }
554 Assert.assertEquals(
"Wrong key count", typeCount, counter.getCount()-c0);
563 public static void assertKeyPress(Robot robot,
final int keyCode,
final int typeCount,
565 throws AWTException, InterruptedException, InvocationTargetException {
569 robot.setAutoWaitForIdle(
true);
574 Assert.assertEquals(
"Key already pressed",
false, counter.isPressed());
577 System.err.println(
"**************************************");
578 System.err.println(
"KC0: "+counter);
581 final int c0 = counter.getCount();
583 for(
int i=0; i<typeCount; i++) {
584 keyType(i, robot, keyCode, obj, counter);
587 if(DEBUG) { System.err.println(
"KC3.0: "+counter); }
588 Assert.assertEquals(
"Wrong key count", typeCount, counter.getCount()-c0);
591 public static void mouseMove(
final Robot robot,
final Point destination,
final int iter,
final int delay) {
592 final Point origin = MouseInfo.getPointerInfo().getLocation();
593 for (
int i = 1; i <= iter; i++) {
594 final float alpha = i / (float) iter;
595 robot.mouseMove((
int) (origin.x * (1 - alpha) + destination.x * alpha),
596 (int) (origin.y * (1 - alpha) + destination.y * alpha));
600 public static void mouseClick(
final Robot robot,
final Point pos,
final int moveIter,
final int moveDelay,
final int actionDelay) {
601 robot.delay(actionDelay);
602 mouseMove(robot, pos, moveIter, moveDelay);
604 robot.delay(actionDelay);
605 robot.mousePress(java.awt.event.InputEvent.BUTTON1_MASK);
606 robot.mouseRelease(java.awt.event.InputEvent.BUTTON1_MASK);
607 robot.delay(actionDelay);
611 static int mouseClick(
final int i,
final Robot robot,
final int mouseButton,
612 final Object obj,
final InputEventCountAdapter counter)
throws InterruptedException, AWTException, InvocationTargetException
616 final long t0 = System.currentTimeMillis();
621 if(DEBUG) { System.err.println(i+
":"+j+
" MC1.0: "+counter+
" - regain focus"); }
624 final int c0 =
null != counter ? counter.getCount() : 0;
625 if(DEBUG) { System.err.println(i+
":"+j+
" MC1.1: "+counter); }
627 robot.mousePress(mouseButton);
628 robot.mouseRelease(mouseButton);
629 if(DEBUG) { System.err.println(i+
":"+j+
" MC1.2: "+counter); }
630 tc = (
null != counter ? counter.getCount() : 1 ) - c0;
631 for (
int wait=0; wait<POLL_DIVIDER && 1 > tc; wait++) {
633 tc = counter.getCount() - c0;
635 if(DEBUG) { System.err.println(i+
":"+j+
" MC1.X: tc "+tc+
", "+counter); }
637 Assert.assertEquals(
"Mouse ("+i+
":"+j+
") not clicked one time", 1, tc);
638 return (
int) ( System.currentTimeMillis() - t0 ) ;
647 public static void assertMouseClick(Robot robot,
final int mouseButton,
final int clickCount,
649 throws AWTException, InterruptedException, InvocationTargetException {
653 robot.setAutoWaitForIdle(
true);
660 Assert.assertEquals(
"Mouse already pressed",
false, counter.isPressed());
663 System.err.println(
"**************************************");
664 System.err.println(
"MC0: "+counter);
667 final int c0 = counter.getCount();
669 for(
int i=0; i<clickCount; i++) {
670 final int waited =
mouseClick(i, robot, mouseButton, obj, counter);
671 if(DEBUG) { System.err.println(i+
": MC2.X: "+counter+
", consumed: "+waited); }
672 robot.delay( clickTO + 1 );
675 if(DEBUG) { System.err.println(
"MC3.0: "+counter); }
676 Assert.assertEquals(
"Wrong mouse click count", clickCount, counter.getCount() - c0);
684 public static boolean waitForVisible(
final java.awt.Component comp,
final boolean visible,
final Runnable waitAction)
throws InterruptedException {
686 for (wait=0; wait<
POLL_DIVIDER && visible != comp.isShowing(); wait++) {
687 if(
null != waitAction ) {
703 public static boolean waitForRealized(
final java.awt.Component comp,
final boolean realized,
final Runnable waitAction)
throws InterruptedException {
704 long t0 = System.currentTimeMillis();
706 while( (t1-t0) <
TIME_OUT && realized != comp.isShowing() ) {
707 if(
null != waitAction ) {
712 t1 = System.currentTimeMillis();
717 t0 = System.currentTimeMillis();
719 if(
null != waitAction ) {
724 t1 = System.currentTimeMillis();
728 System.err.println(
"XXX: FORCE REPAINT PRE - glad: "+glad);
730 t0 = System.currentTimeMillis();
732 if(
null != waitAction ) {
737 t1 = System.currentTimeMillis();
739 System.err.println(
"XXX: FORCE REPAINT POST - glad: "+glad);
759 closingListener.reset();
760 final java.awt.Toolkit tk = java.awt.Toolkit.getDefaultToolkit();
761 final java.awt.EventQueue evtQ = tk.getSystemEventQueue();
762 AWTEDTExecutor.singleton.invoke(
true,
new Runnable() {
765 evtQ.postEvent(
new java.awt.event.WindowEvent(win, java.awt.event.WindowEvent.WINDOW_CLOSING));
771 final AWTWindowClosingAdapter acl =
new AWTWindowClosingAdapter();
772 AWTEDTExecutor.singleton.invoke(
true,
new Runnable() {
775 win.addWindowListener(acl);
779 static class AWTWindowClosingAdapter
780 extends java.awt.event.WindowAdapter implements
TestUtil.WindowClosingListener
782 AtomicInteger closing =
new AtomicInteger(0);
783 AtomicInteger closed =
new AtomicInteger(0);
786 public void reset() {
791 public int getWindowClosingCount() {
792 return closing.get();
795 public int getWindowClosedCount() {
799 public boolean isWindowClosing() {
800 return 0 < closing.get();
803 public boolean isWindowClosed() {
804 return 0 < closed.get();
807 public void windowClosing(
final java.awt.event.WindowEvent e) {
808 closing.incrementAndGet();
809 System.err.println(
"AWTWindowClosingAdapter.windowClosing: "+
this);
812 public void windowClosed(
final java.awt.event.WindowEvent e) {
813 closed.incrementAndGet();
814 System.err.println(
"AWTWindowClosingAdapter.windowClosed: "+
this);
817 public String toString() {
818 return "AWTWindowClosingAdapter[closing "+closing+
", closed "+closed+
"]";
Provides a pluggable mechanism for arbitrary window toolkits to adapt their components to the NativeW...
final Point translate(final Point pd)
Translate this instance's x- and y-components, i.e.
static void centerMouse(Robot robot, final Object obj, final boolean onTitleBarIfWindow)
centerMouse FIXME: AWTRobotUtil Cleanup: Use specific type for argument object
static void requestFocus(final Robot robot, final Object obj, final int x, final int y)
static final int ROBOT_DELAY
static int keyType(final int i, final Robot robot, final int keyCode, final Object obj, final KeyEventCountAdapter counter)
static void setMouseToClientLocation(Robot robot, final Object obj, final int x, final int y)
static boolean hasFocus(final Object obj)
static void assertKeyType(Robot robot, final int keyCode, final int typeCount, final Object obj, final KeyEventCountAdapter counter)
FIXME: AWTRobotUtil Cleanup: Use specific type for argument object.
static void awtRobotMouseMove(final Robot robot, final int x, final int y)
static boolean waitForFocus(final java.awt.Component comp, final Runnable waitAction)
static void validateAWTEDTIsAlive()
Throws Error if isAWTEDTAlive() returns false.
static int newtKeyPress(final int i, final Robot robot, final boolean press, final short newtKeyCode, final int msDelay)
No validation is performed .
static void assertMouseClick(Robot robot, final int mouseButton, final int clickCount, final Object obj, final InputEventCountAdapter counter)
FIXME: AWTRobotUtil Cleanup: Use specific type for argument object.
static void requestFocus(final Robot robot, final Object obj)
FIXME: AWTRobotUtil Cleanup: Use specific type for argument object.
static boolean toFrontAndRequestFocus(Robot robot, final java.awt.Window window)
toFront, call setVisible(true) and toFront(), after positioning the mouse in the middle of the window...
static int[] getCenterLocation(final Object obj, final boolean onTitleBarIfWindow)
static void mouseMove(final Robot robot, final Point destination, final int iter, final int delay)
static TestUtil.WindowClosingListener addClosingListener(final java.awt.Window win)
static int getClickTimeout(final Object obj)
static void clearAWTFocus(Robot robot)
static boolean isAWTEDTAlive()
Probes whether AWT's EDT is alive or not.
static boolean waitForRealized(final java.awt.Component comp, final boolean realized, final Runnable waitAction)
static boolean closeWindow(final java.awt.Window win, final boolean willClose, final TestUtil.WindowClosingListener closingListener, final Runnable waitAction)
Programmatically issue windowClosing on AWT or NEWT.
static void assertKeyPress(Robot robot, final int keyCode, final int typeCount, final Object obj, final KeyEventCountAdapter counter)
FIXME: AWTRobotUtil Cleanup: Use specific type for argument object.
static boolean waitForVisible(final java.awt.Component comp, final boolean visible, final Runnable waitAction)
static void mouseClick(final Robot robot, final Point pos, final int moveIter, final int moveDelay, final int actionDelay)
static boolean waitForFocus(final java.awt.Component comp, final FocusEventCountAdapter gain, final FocusEventCountAdapter lost, final Runnable waitAction)
static int keyPress(final int i, final Robot robot, final boolean press, final int keyCode, final int msDelay)
No validation is performed .
static int[] getClientLocation(final Object obj, final int x, final int y)
static Integer AWT_CLICK_TO
static void assertRequestFocusAndWait(final Robot robot, final Object requestFocus, final Object waitForFocus, final FocusEventCountAdapter gain, final FocusEventCountAdapter lost)
static void waitForIdle(final Robot robot)
Issuing validateAWTEDTIsAlive() before calling Robot#waitForIdle().
static void requestFocus(final Robot robot, final Object obj, final boolean onTitleBarIfWindow)
FIXME: AWTRobotUtil Cleanup: Use specific type for argument object.
static boolean waitForFocus(final Window win, final Runnable waitAction)
static final int RETRY_NUMBER
static final int TIME_SLICE
static final int POLL_DIVIDER
static boolean waitForFocus(final FocusEventCountAdapter gain, final FocusEventCountAdapter lost, final Runnable waitAction)
static boolean waitUntilClosed(final boolean willClose, final TestUtil.WindowClosingListener closingListener, final Runnable waitAction)
Wait until the window is closing within TIME_OUT.
static final int TIME_OUT
Extend the NativeSurface interface with windowing information such as window-handle,...
Immutable insets representing rectangular window decoration insets on all four edges in window units.
A higher-level abstraction than GLDrawable which supplies an event based mechanism (GLEventListener) ...
boolean isRealized()
Returns true if this drawable is realized, otherwise false.