Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for multiple monitors (issue 51) #98

Closed
croesch opened this issue Feb 8, 2014 · 6 comments
Closed

Add support for multiple monitors (issue 51) #98

croesch opened this issue Feb 8, 2014 · 6 comments

Comments

@croesch
Copy link
Collaborator

croesch commented Feb 8, 2014

Issue by Alex Ruiz from Mon, 2 Mar 2009 14:06:28 -0600
Originally opened as http://jira.codehaus.org/browse/FEST-24


E-mail form Epaga:

Unfortunately, on my dual monitor system with my main monitor on the right and the second monitor on the left, FEST seems to be trying to click at the wrong position when it tries to click on a component.

My code looks something like this:

fixture = WindowFinder.findDialog( JDialog.class ).withTimeout( 10000 ).using( RobotFixture.robotWithCurrentAwtHierarchy() );
fixture.textBox( "Dtf_PromptName" ).click().deleteText().enterText( "text" );

When it runs the click method, the cursor vibrates on the right screen, apparently looking for the text box, but the dialog is on the left side of the screen. Is there some way to avoid this problem? I've tried setting the location of the dialog to move to the right side, but then FEST just moves the cursor to the right as well.


Original report: Issue 51 (Google Code)


votes (original issue): 4
watches (original issue): 3

@croesch
Copy link
Collaborator Author

croesch commented Feb 8, 2014

Comment by plm31 from Wed, 2 Jun 2010 04:11:12 -0500


A possible fix to this is in the AWT class with code similar to (I needed to do this for multiple monitor setup);

  /**
   * Indicates whether the given point, relative to the given <code>JComponent</code>, is inside the screen boundaries.
   * @param c the given <code>JComponent</code>.
   * @param p the point to verify.
   * @return <code>true</code> if the point is inside the screen boundaries; <code>false</code> otherwise.
   * @since 1.2
   */
  public static boolean isPointInScreenBoundaries(JComponent c, Point p) {
    Point where = translate(c, p.x, p.y);
    return isPointInScreenBoundaries(where);
  }
  /**
   * Indicates whether the given point is inside the screen boundaries.
   * @param p the point to verify.
   * @return <code>true</code> if the point is inside the screen boundaries; <code>false</code> otherwise.
   * @since 1.2
   */
  public static boolean isPointInScreenBoundaries(Point p) {
    GraphicsDevice[] screens = GraphicsEnvironment.getLocalGraphicsEnvironment().getScreenDevices();
    if (screens.length == 1) {
      Rectangle screen = new Rectangle(Toolkit.getDefaultToolkit().getScreenSize());
      return screen.contains(p);
    } else {
      for (GraphicsDevice device : screens) {
        for (GraphicsConfiguration config : device.getConfigurations()) {
          if (config.getBounds().contains(p)) {
            return true;
          }
        }
      }
    }
    return false;
  }

I think that caching would be necessary as there appears to be an overhead with the above code, but screens tend not to change during the tests, or if they did it would be rather unusual.

@croesch
Copy link
Collaborator Author

croesch commented Feb 8, 2014

Comment by pavolmarko from Fri, 24 Sep 2010 10:47:07 -0500


Hello, I have used a similar solution to Peter Murray's, except for caching the results and using getDefaultConfiguration instead of enumerating over getConfigurations.

It seems that getConfigurations is really slow on Win32 and returns configurations with the same boundary rectangles (only the pixel format varies AFAIK).
getDefaultConfiguration returns in virtually no time and has no disadvantage on my setup.

Edit: Java Bug for getConfigurations: http://bugs.sun.com/bugdatabase/view_bug.do;jsessionid=425c52554972830be3116e029f2d?bug_id=6477756

@tagliola
Copy link

tagliola commented Jun 3, 2015

It also fails if the second monitor is layed out above the first monitor. I have a dual screen setup where the secondary screen is to the right in portrait, and it sticks out slightly above the primary monitor. The clicks are offset vertically at the distance the second monitor sticks out. If I align the tops of the two screens, it works.

@croesch
Copy link
Collaborator Author

croesch commented Jun 8, 2015

@tagliola okay, I cannot reproduce the behavior described here since for me mouse pointer wobbles in that scenario. The click never happens. The code above seems to have no affect.

Can you confirm that? How is the behavior you're experiencing?

@croesch
Copy link
Collaborator Author

croesch commented Jun 8, 2015

For me the problem begins while showing the dialog. We wait for it to be ready and showing. A dialog is ready when it is showing for 10 seconds or if a mouse event occurred.

The mouse event is the first thing that needs to be fixed. When my main monitor is on the right, the window appears on the right, while the mouse is on the other monitor. This prevents the initial mouse event marking the window as ready from occurring. And AssertJ Swing will then wait for ten seconds for the window being ready.

Afterwards the click seems to appear on the wrong monitor. For me it seems it's more to do than just adding the code above to AWT.

@croesch
Copy link
Collaborator Author

croesch commented Jun 8, 2015

Okay, I finally got the/one problem: The robot has a different coordinate system than Component#getLocation().

The problem occurs in:

org.assertj.swing.monitor.WindowStatus.mouseMove(Window, Point)
org.assertj.swing.monitor.WindowStatus.checkSafelyIfReady(Window)
org.assertj.swing.monitor.WindowStatus.checkIfReady(Window)
org.assertj.swing.monitor.WindowMonitor.isWindowReady(Window)
org.assertj.swing.core.BasicRobot.waitForWindow(Window)
org.assertj.swing.core.BasicRobot.showWindow(Window, Dimension, boolean)org.assertj.swing.core.BasicRobot.showWindow(Window)

This is just one example where the problem occurs.

In this method the point where to move the mouse is another than java.awt.Robot.mouseMove(int, int) needs to get. Why? Because in

org.assertj.swing.util.RobotFactory.newRobotInPrimaryScreen()
org.assertj.swing.monitor.WindowStatus.WindowStatus(Windows, RobotFactory)

a Robot with the coordinate system of the primary screen is created. This leads to problems if the primary screen is not the most left screen.

A simple solution for the problem I could reproduce with my window manager is to use the coordinate system of the most left screen instead of the coordinate system of the primary screen.

This will not fix your problem @tagliola but I'm not sure if I'll have the time to fix it by myself. I would be very pleased if you could have a look at the named methods and try to fix the code that mouse movements use. Opened #158 for that problem.

I think it won't be sufficient to use the coordinate system of a specific screen but to translate the coordinates for the robot each time the mouse is moved.

Also it might be necessary to add the code to AWT as mentioned above. If so, please let me know and I'll make the changes as requested! But for me the original problem here is fixed.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants