How to get surface / window x and y coordinates?

edited April 2017 in How To...

I have been banging my head against this for hours now.

I would like to know how to get the x and y coordinates of the Java GLWindow relative to my screen.

When I call frame.getLocation(), I receive (0,23) which I believe is the render frame inside of the GLWindow.

However, I would like to know how to get the x,y coordinates of that window!

Any advice?

Answers

  • I think the robot library has methods for this.

  • Depends on which version of Processing you are using.

  • Answer ✓

    This works in Processing 3

    // Either JAVA2D (default), P2D or P3D
    final String renderer = P2D; 
    
    void setup() {
      size(300, 300, renderer);
      PVector loc = getWindowLocation(renderer); // Make sure this matches value in size()
      println(loc);
    }
    
    PVector getWindowLocation(String renderer) {
      PVector l = new PVector();
      if (renderer == P2D || renderer == P3D) {
        com.jogamp.nativewindow.util.Point p = new com.jogamp.nativewindow.util.Point();
        ((com.jogamp.newt.opengl.GLWindow)surface.getNative()).getLocationOnScreen(p);
        l.x = p.getX();
        l.y = p.getY();
      } else if (renderer == JAVA2D) {
        java.awt.Frame f =  (java.awt.Frame) ((processing.awt.PSurfaceAWT.SmoothCanvas) surface.getNative()).getFrame();
        l.x = f.getX();
        l.y = f.getY();
      }
      return l;
    }
    
  • edited July 2016

    if (renderer == P2D || renderer == P3D)

    Finally some1 join in my club of daring Java skills. I also love to check constant String objects w/ == operator instead of that boring equals() method. \m/

    And why not | instead of ||. That'd be perfect: if (renderer == P2D | renderer == P3D) :P

  • I don't use

    if (renderer == P2D | renderer == P3D)

    because the second condition is always evaluated even if the first condition is true.

    In this conditional it doesn't make any sense to use the bitwise-or (|) because if renderer == P2D is true then renderer == P3D must be false so why evaluate it.

    I have the same aversion to using & rather than && in conditional statements.

  • edited July 2016

    @Quark: perfect answer. Thank you.

    For those interested. The reason I needed to implement this was because our application was frequently crashing when we used CMD+q or hit the 'x' button at the top left. We realized it it was because sometimes we would leave the frame with our cursor, but in the process hover over a button. The frameRate was not fast enough to track the mouse position between between when it left the button and exited the Frame. This would result in the sketch getting hung up when trying to close.

    Here's the full fix:

    boolean mouseInFrame = false;
    boolean windowOriginSet = false;
    int appletOriginX = 0;
    int appletOriginY = 0;
    PVector loc;
    
    void draw() {
      //other code ... 
      mouseOutOfBounds(); //put this at end of draw loop ... check each loop
    }
    
    void mouseOutOfBounds() {
      if (windowOriginSet && mouseInFrame) {
        if (MouseInfo.getPointerInfo().getLocation().x <= appletOriginX || 
          MouseInfo.getPointerInfo().getLocation().x >= appletOriginX+width ||
          MouseInfo.getPointerInfo().getLocation().y <= appletOriginY ||
          MouseInfo.getPointerInfo().getLocation().y >= appletOriginY+height) {
          mouseX = 0;
          mouseY = 0;
          println("Mouse out of bounds!");
          mouseInFrame = false;
        }
      } else {
        if (mouseX > 0 && mouseX < width && mouseY > 0 && mouseY < height) {
          loc = getWindowLocation(P2D);
          appletOriginX = (int)loc.x;
          appletOriginY = (int)loc.y;
          windowOriginSet = true;
          mouseInFrame = true;
          println("WINDOW ORIGIN SET!");
        }
      }
    }
    
    PVector getWindowLocation(String renderer) {
      PVector l = new PVector();
      if (renderer == P2D || renderer == P3D) {
        com.jogamp.nativewindow.util.Point p = new com.jogamp.nativewindow.util.Point();
        ((com.jogamp.newt.opengl.GLWindow)surface.getNative()).getLocationOnScreen(p);
        l.x = p.getX();
        l.y = p.getY();
      } else if (renderer == JAVA2D) {
        java.awt.Frame f =  (java.awt.Frame) ((processing.awt.PSurfaceAWT.SmoothCanvas) surface.getNative()).getFrame();
        l.x = f.getX();
        l.y = f.getY();
      }
      return l;
    }
    

    Cheers

  • edited July 2016

    because the second condition is always evaluated even if the first condition is true.

    Of course, that's why it's called eager eval, while the other is lazy eval + short-circuit.
    However, given the evaluation of renderer == P2D | renderer == P3D is so fast, by the time the short-circuit is set up prior to the lazy eval version, the former had already finished! $-)

  • The || uses short-circuit evaluation. The terms eager and lazy evaluation are used in a different context.

    by the time the short-circuit is set up prior to the lazy eval, the former had already finished!

    Since the short-circuit is setup by the compiler and not at runtime then this statement is incorrect.

    I have changed the method to simplify the byte code

    void getWindowLocation(String renderer) {
      PVector l = new PVector();
      if (renderer == P2D || renderer == P3D) {
        l.x = 1;
      }
    }
    

    Here is the byte code for using the ||

    // Using conditional or ||
      getWindowLocation(String) : void
       L0
        LINENUMBER 143 L0
        NEW PVector
        DUP
        INVOKESPECIAL PVector.<init> () : void
        ASTORE 2
       L1
        LINENUMBER 144 L1
        ALOAD 1: renderer
        LDC "processing.opengl.PGraphics2D"
        IF_ACMPEQ L2
        ALOAD 1: renderer
        LDC "processing.opengl.PGraphics3D"
        IF_ACMPNE L3
       L2
        LINENUMBER 145 L2
       FRAME APPEND [PVector]
        ALOAD 2: l
        FCONST_1
        PUTFIELD PVector.x : float
       L3
        LINENUMBER 147 L3
       FRAME SAME
        RETURN
       L4
        LOCALVARIABLE this Cannon L0 L4 0
        LOCALVARIABLE renderer String L0 L4 1
        LOCALVARIABLE l PVector L1 L4 2
        MAXSTACK = 2
        MAXLOCALS = 3
    

    Line 13 is the short circuit

    Here is the byte code for |

    // Using bitwise or |
      getWindowLocation(String) : void
       L0
        LINENUMBER 143 L0
        NEW PVector
        DUP
        INVOKESPECIAL PVector.<init> () : void
        ASTORE 2
       L1
        LINENUMBER 144 L1
        ALOAD 1: renderer
        LDC "processing.opengl.PGraphics2D"
        IF_ACMPNE L2
        ICONST_1
        GOTO L3
       L2
       FRAME APPEND [PVector]
        ICONST_0
       L3
       FRAME SAME1 int
        ALOAD 1: renderer
        LDC "processing.opengl.PGraphics3D"
        IF_ACMPNE L4
        ICONST_1
        GOTO L5
       L4
       FRAME SAME1 int
        ICONST_0
       L5
       FRAME FULL [Cannon String PVector] [int int]
        IOR
        IFEQ L6
       L7
        LINENUMBER 145 L7
        ALOAD 2: l
        FCONST_1
        PUTFIELD PVector.x : float
       L6
        LINENUMBER 147 L6
       FRAME SAME
        RETURN
       L8
        LOCALVARIABLE this Cannon L0 L8 0
        LOCALVARIABLE renderer String L0 L8 1
        LOCALVARIABLE l PVector L1 L8 2
        MAXSTACK = 3
        MAXLOCALS = 3
    

    Since the dawn of Java programmers have used the condition and/or operators in conditional statements. The only reason for using the bitwise is to force the evaluation of both conditions - a very rare need.

  • Dunno much bytecode specifics, so it's hard for me to judge which 1 is actually faster.
    However, The eager eval w/o short-circuit relies on GOTO, which is the fastest memory address jumper available in machine code AFAIK. :ar!

  • edited July 2016

    The only time | will be quicker than || is if the second has to be evaluated e.g.

    (a == 1 | b == 6) will ONLY be faster than (a == 1 || b == 6) if the first condition is false i.e. when a != 1

  • Wow! Y'all are really nerding out now :P

  • edited July 2016

    Anyways, I've come up w/ a more complete solution which includes FX2D renderer as well.
    Lotsa pain to dig in given inner class ResizableCanvas from processing.javafx.PSurfaceFX isn't public.
    And to make things worse, package javafx wasn't importable in Processing either! @-)
    So I had to go full reflection all the way down until reaching methods getX() & getY() for FX2D: #:-S

    /**
     * GetWindowLocation (v2.1)
     * by  Quark (2016-Jul-28)
     * mod GoToLoop
     *
     * forum.Processing.org/two/discussion/17675/
     * how-to-get-surface-window-x-and-y-coordinates#Item_12
     */
    
    // Either JAVA2D (default), FX2D, P2D or P3D:
    static final String RENDERER = FX2D;
    final int[] xy = new int[2];
    
    void setup() {
      size(300, 200, RENDERER);
      noLoop();
    }
    
    void draw() {
      background((color) random(#000000));
      getWindowLocation(this, xy);
      print(xy[0] + "," + xy[1], TAB);
    }
    
    void mousePressed() {
      redraw = true;
    }
    
    static final int[] getWindowLocation(final PApplet pa, int... xy) {
      if (xy == null || xy.length < 2)  xy = new int[2];
    
      final Object surf = pa.getSurface().getNative();
      final PGraphics canvas = pa.getGraphics();
    
      if (canvas.isGL()) {
        xy[0] = ((com.jogamp.nativewindow.NativeWindow) surf).getX();
        xy[1] = ((com.jogamp.nativewindow.NativeWindow) surf).getY();
      } else if (canvas instanceof processing.awt.PGraphicsJava2D) {
        final java.awt.Component f =
          ((processing.awt.PSurfaceAWT.SmoothCanvas) surf).getFrame();
    
        xy[0] = f.getX();
        xy[1] = f.getY();
      } else try {
        final java.lang.reflect.Method getStage =
          surf.getClass().getDeclaredMethod("getStage");
    
        getStage.setAccessible(true);
    
        final Object stage = getStage.invoke(surf);
        final Class<?> st = stage.getClass();
    
        final java.lang.reflect.Method getX = st.getMethod("getX");
        final java.lang.reflect.Method getY = st.getMethod("getY");
    
        xy[0] = ((Number) getX.invoke(stage)).intValue();
        xy[1] = ((Number) getY.invoke(stage)).intValue();
      }
      catch (final ReflectiveOperationException e) {
        System.err.println(e);
      }
    
      return xy;
    }
    
  • edited July 2016

    The only time | will be quicker than || is if the second has to be evaluated e.g.

    That depends whether IF_ACMPEQ L2 short-circuit is fast enough to beat down the GOTOs. :P
    Evaluating something as simple as renderer == P3D is instantaneous after all. >-)

  • There are no GOTOs here and nothing is instantaneous and the statements I made in my last post are correct.

    In this particular case the speed difference will be measured in nanoseconds so it's not important, what is important is promoting good programming practice especially in a forum like this where many of the programmers are inexperienced.

    Using the conditional operators && and || In conditional statements is good practice that has been accepted for decades. As I said, there will be some very, very rare occasions when it is important for both expressions to be evaluated in which case the bitwise operators should be used.

    If being nerdy means pointing out good practice then I happy to be nerdy :)

  • There are no GOTOs here and nothing is instantaneous

    #15 GOTO L3
    #25 GOTO L5
    
  • Yeah sorry about that, I missed those GOTOs :\"> but it doesn't affect the conclusions I reached in my last 2 posts.

Sign In or Register to comment.