private void generateMouseEnterExitEventsForComponents(
      long when,
      int button,
      int x,
      int y,
      int screenX,
      int screenY,
      int modifiers,
      int clickCount,
      boolean popupTrigger,
      final LWComponentPeer<?, ?> targetPeer) {

    if (!isMouseOver || targetPeer == lastMouseEventPeer) {
      return;
    }

    // Generate Mouse Exit for components
    if (lastMouseEventPeer != null && lastMouseEventPeer.isEnabled()) {
      Point oldp = lastMouseEventPeer.windowToLocal(x, y, this);
      Component target = lastMouseEventPeer.getTarget();
      postMouseExitedEvent(
          target, when, modifiers, oldp, screenX, screenY, clickCount, popupTrigger, button);
    }
    lastCommonMouseEventPeer = targetPeer;
    lastMouseEventPeer = targetPeer;

    // Generate Mouse Enter for components
    if (targetPeer != null && targetPeer.isEnabled()) {
      Point newp = targetPeer.windowToLocal(x, y, this);
      Component target = targetPeer.getTarget();
      postMouseEnteredEvent(
          target, when, modifiers, newp, screenX, screenY, clickCount, popupTrigger, button);
    }
  }
  @Override
  public void notifyMouseWheelEvent(
      long when,
      int x,
      int y,
      int modifiers,
      int scrollType,
      int scrollAmount,
      int wheelRotation,
      double preciseWheelRotation,
      byte[] bdata) {
    // TODO: could we just use the last mouse event target here?
    Rectangle r = getBounds();
    // findPeerAt() expects parent coordinates
    final LWComponentPeer<?, ?> targetPeer = findPeerAt(r.x + x, r.y + y);
    if (targetPeer == null || !targetPeer.isEnabled()) {
      return;
    }

    Point lp = targetPeer.windowToLocal(x, y, this);
    // TODO: fill "bdata" member of AWTEvent
    // TODO: screenX/screenY
    postEvent(
        new MouseWheelEvent(
            targetPeer.getTarget(),
            MouseEvent.MOUSE_WHEEL,
            when,
            modifiers,
            lp.x,
            lp.y,
            0,
            0, /* screenX, Y */
            0 /* clickCount */,
            false /* popupTrigger */,
            scrollType,
            scrollAmount,
            wheelRotation,
            preciseWheelRotation));
  }
 public static LWWindowPeer getWindowUnderCursor() {
   return lastCommonMouseEventPeer != null ? lastCommonMouseEventPeer.getWindowPeerOrSelf() : null;
 }
  /*
   * Called by the delegate to dispatch the event to Java. Event
   * coordinates are relative to non-client window are, i.e. the top-left
   * point of the client area is (insets.top, insets.left).
   */
  @Override
  public void notifyMouseEvent(
      PlatformWindow eventPlatformWindow,
      int id,
      long when,
      int button,
      int x,
      int y,
      int screenX,
      int screenY,
      int modifiers,
      int clickCount,
      boolean popupTrigger,
      byte[] bdata) {
    // TODO: fill "bdata" member of AWTEvent
    Rectangle r = getBounds();
    // findPeerAt() expects parent coordinates
    LWComponentPeer<?, ?> targetPeer = findPeerAt(r.x + x, r.y + y);

    if (id == MouseEvent.MOUSE_EXITED) {
      isMouseOver = false;
      if (lastMouseEventPeer != null) {
        if (lastMouseEventPeer.isEnabled()) {
          Point lp = lastMouseEventPeer.windowToLocal(x, y, this);
          Component target = lastMouseEventPeer.getTarget();
          postMouseExitedEvent(
              target, when, modifiers, lp, screenX, screenY, clickCount, popupTrigger, button);
        }

        // Sometimes we may get MOUSE_EXITED after lastCommonMouseEventPeer is switched
        // to a peer from another window. So we must first check if this peer is
        // the same as lastWindowPeer
        if (lastCommonMouseEventPeer != null
            && lastCommonMouseEventPeer.getWindowPeerOrSelf() == this) {
          lastCommonMouseEventPeer = null;
        }
        lastMouseEventPeer = null;
      }
    } else if (id == MouseEvent.MOUSE_ENTERED) {
      isMouseOver = true;
      if (targetPeer != null) {
        if (targetPeer.isEnabled()) {
          Point lp = targetPeer.windowToLocal(x, y, this);
          Component target = targetPeer.getTarget();
          postMouseEnteredEvent(
              target, when, modifiers, lp, screenX, screenY, clickCount, popupTrigger, button);
        }
        lastCommonMouseEventPeer = targetPeer;
        lastMouseEventPeer = targetPeer;
      }
    } else {

      LWWindowPeer topmostWindowPeer =
          eventPlatformWindow != null ? eventPlatformWindow.getPeer() : null;

      // topmostWindowPeer == null condition is added for the backward
      // compatibility with applets. It can be removed when the
      // getTopmostPlatformWindowUnderMouse() method will be properly
      // implemented in CPlatformEmbeddedFrame class
      if (topmostWindowPeer == this || topmostWindowPeer == null) {
        generateMouseEnterExitEventsForComponents(
            when, button, x, y, screenX, screenY, modifiers, clickCount, popupTrigger, targetPeer);
      } else {
        LWComponentPeer<?, ?> topmostTargetPeer = topmostWindowPeer.findPeerAt(r.x + x, r.y + y);
        topmostWindowPeer.generateMouseEnterExitEventsForComponents(
            when,
            button,
            x,
            y,
            screenX,
            screenY,
            modifiers,
            clickCount,
            popupTrigger,
            topmostTargetPeer);
      }

      // TODO: fill "bdata" member of AWTEvent

      int eventButtonMask = (button > 0) ? MouseEvent.getMaskForButton(button) : 0;
      int otherButtonsPressed = modifiers & ~eventButtonMask;

      // For pressed/dragged/released events OS X treats other
      // mouse buttons as if they were BUTTON2, so we do the same
      int targetIdx = (button > 3) ? MouseEvent.BUTTON2 - 1 : button - 1;

      // MOUSE_ENTERED/EXITED are generated for the components strictly under
      // mouse even when dragging. That's why we first update lastMouseEventPeer
      // based on initial targetPeer value and only then recalculate targetPeer
      // for MOUSE_DRAGGED/RELEASED events
      if (id == MouseEvent.MOUSE_PRESSED) {

        // Ungrab only if this window is not an owned window of the grabbing one.
        if (!isGrabbing() && grabbingWindow != null && !grabbingWindow.isOneOfOwnersOf(this)) {
          grabbingWindow.ungrab();
        }
        if (otherButtonsPressed == 0) {
          mouseClickButtons = eventButtonMask;
        } else {
          mouseClickButtons |= eventButtonMask;
        }

        // The window should be focused on mouse click. If it gets activated by the native platform,
        // this request will be no op. It will take effect when:
        // 1. A simple not focused window is clicked.
        // 2. An active but not focused owner frame/dialog is clicked.
        // The mouse event then will trigger a focus request "in window" to the component, so the
        // window
        // should gain focus before.
        requestWindowFocus(CausedFocusEvent.Cause.MOUSE_EVENT);

        mouseDownTarget[targetIdx] = targetPeer;
      } else if (id == MouseEvent.MOUSE_DRAGGED) {
        // Cocoa dragged event has the information about which mouse
        // button is being dragged. Use it to determine the peer that
        // should receive the dragged event.
        targetPeer = mouseDownTarget[targetIdx];
        mouseClickButtons &= ~modifiers;
      } else if (id == MouseEvent.MOUSE_RELEASED) {
        // TODO: currently, mouse released event goes to the same component
        // that received corresponding mouse pressed event. For most cases,
        // it's OK, however, we need to make sure that our behavior is consistent
        // with 1.6 for cases where component in question have been
        // hidden/removed in between of mouse pressed/released events.
        targetPeer = mouseDownTarget[targetIdx];

        if ((modifiers & eventButtonMask) == 0) {
          mouseDownTarget[targetIdx] = null;
        }

        // mouseClickButtons is updated below, after MOUSE_CLICK is sent
      }

      if (targetPeer == null) {
        // TODO This can happen if this window is invisible. this is correct behavior in this case?
        targetPeer = this;
      }

      Point lp = targetPeer.windowToLocal(x, y, this);
      if (targetPeer.isEnabled()) {
        MouseEvent event =
            new MouseEvent(
                targetPeer.getTarget(),
                id,
                when,
                modifiers,
                lp.x,
                lp.y,
                screenX,
                screenY,
                clickCount,
                popupTrigger,
                button);
        postEvent(event);
      }

      if (id == MouseEvent.MOUSE_RELEASED) {
        if ((mouseClickButtons & eventButtonMask) != 0 && targetPeer.isEnabled()) {
          postEvent(
              new MouseEvent(
                  targetPeer.getTarget(),
                  MouseEvent.MOUSE_CLICKED,
                  when,
                  modifiers,
                  lp.x,
                  lp.y,
                  screenX,
                  screenY,
                  clickCount,
                  popupTrigger,
                  button));
        }
        mouseClickButtons &= ~eventButtonMask;
      }
    }
    notifyUpdateCursor();
  }
  /*
   * Called by the delegate to dispatch the event to Java. Event
   * coordinates are relative to non-client window are, i.e. the top-left
   * point of the client area is (insets.top, insets.left).
   */
  @Override
  public void notifyMouseEvent(
      int id,
      long when,
      int button,
      int x,
      int y,
      int screenX,
      int screenY,
      int modifiers,
      int clickCount,
      boolean popupTrigger,
      byte[] bdata) {
    // TODO: fill "bdata" member of AWTEvent
    Rectangle r = getBounds();
    // findPeerAt() expects parent coordinates
    LWComponentPeer targetPeer = findPeerAt(r.x + x, r.y + y);
    LWWindowPeer lastWindowPeer =
        (lastMouseEventPeer != null) ? lastMouseEventPeer.getWindowPeerOrSelf() : null;
    LWWindowPeer curWindowPeer = (targetPeer != null) ? targetPeer.getWindowPeerOrSelf() : null;

    if (id == MouseEvent.MOUSE_EXITED) {
      // Sometimes we may get MOUSE_EXITED after lastMouseEventPeer is switched
      // to a peer from another window. So we must first check if this peer is
      // the same as lastWindowPeer
      if (lastWindowPeer == this) {
        if (isEnabled()) {
          Point lp = lastMouseEventPeer.windowToLocal(x, y, lastWindowPeer);
          Component target = lastMouseEventPeer.getTarget();
          postMouseEnteredExitedEvent(
              target,
              MouseEvent.MOUSE_EXITED,
              when,
              modifiers,
              lp,
              screenX,
              screenY,
              clickCount,
              popupTrigger,
              button);
        }
        lastMouseEventPeer = null;
      }
    } else {
      if (targetPeer != lastMouseEventPeer) {
        // lastMouseEventPeer may be null if mouse was out of Java windows
        if (lastMouseEventPeer != null && lastMouseEventPeer.isEnabled()) {
          // Sometimes, MOUSE_EXITED is not sent by delegate (or is sent a bit
          // later), in which case lastWindowPeer is another window
          if (lastWindowPeer != this) {
            Point oldp = lastMouseEventPeer.windowToLocal(x, y, lastWindowPeer);
            // Additionally translate from this to lastWindowPeer coordinates
            Rectangle lr = lastWindowPeer.getBounds();
            oldp.x += r.x - lr.x;
            oldp.y += r.y - lr.y;
            Component target = lastMouseEventPeer.getTarget();
            postMouseEnteredExitedEvent(
                target,
                MouseEvent.MOUSE_EXITED,
                when,
                modifiers,
                oldp,
                screenX,
                screenY,
                clickCount,
                popupTrigger,
                button);
          } else {
            Point oldp = lastMouseEventPeer.windowToLocal(x, y, this);
            Component target = lastMouseEventPeer.getTarget();
            postMouseEnteredExitedEvent(
                target,
                MouseEvent.MOUSE_EXITED,
                when,
                modifiers,
                oldp,
                screenX,
                screenY,
                clickCount,
                popupTrigger,
                button);
          }
        }
        lastMouseEventPeer = targetPeer;
        if (targetPeer != null && targetPeer.isEnabled() && id != MouseEvent.MOUSE_ENTERED) {
          Point newp = targetPeer.windowToLocal(x, y, curWindowPeer);
          Component target = targetPeer.getTarget();
          postMouseEnteredExitedEvent(
              target,
              MouseEvent.MOUSE_ENTERED,
              when,
              modifiers,
              newp,
              screenX,
              screenY,
              clickCount,
              popupTrigger,
              button);
        }
      }
      // TODO: fill "bdata" member of AWTEvent

      int eventButtonMask = (button > 0) ? MouseEvent.getMaskForButton(button) : 0;
      int otherButtonsPressed = modifiers & ~eventButtonMask;

      // For pressed/dragged/released events OS X treats other
      // mouse buttons as if they were BUTTON2, so we do the same
      int targetIdx = (button > 3) ? MouseEvent.BUTTON2 - 1 : button - 1;

      // MOUSE_ENTERED/EXITED are generated for the components strictly under
      // mouse even when dragging. That's why we first update lastMouseEventPeer
      // based on initial targetPeer value and only then recalculate targetPeer
      // for MOUSE_DRAGGED/RELEASED events
      if (id == MouseEvent.MOUSE_PRESSED) {

        // Ungrab only if this window is not an owned window of the grabbing one.
        if (!isGrabbing()
            && grabbingWindow != null
            && grabbingWindow != getOwnerFrameDialog(this)) {
          grabbingWindow.ungrab();
        }
        if (otherButtonsPressed == 0) {
          mouseClickButtons = eventButtonMask;
        } else {
          mouseClickButtons |= eventButtonMask;
        }

        mouseDownTarget[targetIdx] = targetPeer;
      } else if (id == MouseEvent.MOUSE_DRAGGED) {
        // Cocoa dragged event has the information about which mouse
        // button is being dragged. Use it to determine the peer that
        // should receive the dragged event.
        targetPeer = mouseDownTarget[targetIdx];
        mouseClickButtons &= ~modifiers;
      } else if (id == MouseEvent.MOUSE_RELEASED) {
        // TODO: currently, mouse released event goes to the same component
        // that received corresponding mouse pressed event. For most cases,
        // it's OK, however, we need to make sure that our behavior is consistent
        // with 1.6 for cases where component in question have been
        // hidden/removed in between of mouse pressed/released events.
        targetPeer = mouseDownTarget[targetIdx];

        if ((modifiers & eventButtonMask) == 0) {
          mouseDownTarget[targetIdx] = null;
        }

        // mouseClickButtons is updated below, after MOUSE_CLICK is sent
      }

      // check if we receive mouseEvent from outside the window's bounds
      // it can be either mouseDragged or mouseReleased
      if (curWindowPeer == null) {
        // TODO This can happen if this window is invisible. this is correct behavior in this case?
        curWindowPeer = this;
      }
      if (targetPeer == null) {
        // TODO This can happen if this window is invisible. this is correct behavior in this case?
        targetPeer = this;
      }

      Point lp = targetPeer.windowToLocal(x, y, curWindowPeer);
      if (targetPeer.isEnabled()) {
        if (id == MouseEvent.MOUSE_ENTERED || id == MouseEvent.MOUSE_EXITED) {
          postMouseEnteredExitedEvent(
              targetPeer.getTarget(),
              id,
              when,
              modifiers,
              lp,
              screenX,
              screenY,
              clickCount,
              popupTrigger,
              button);

        } else {
          MouseEvent event =
              new MouseEvent(
                  targetPeer.getTarget(),
                  id,
                  when,
                  modifiers,
                  lp.x,
                  lp.y,
                  screenX,
                  screenY,
                  clickCount,
                  popupTrigger,
                  button);
          postEvent(event);
        }
      }

      if (id == MouseEvent.MOUSE_RELEASED) {
        if ((mouseClickButtons & eventButtonMask) != 0 && targetPeer.isEnabled()) {
          postEvent(
              new MouseEvent(
                  targetPeer.getTarget(),
                  MouseEvent.MOUSE_CLICKED,
                  when,
                  modifiers,
                  lp.x,
                  lp.y,
                  screenX,
                  screenY,
                  clickCount,
                  popupTrigger,
                  button));
        }
        mouseClickButtons &= ~eventButtonMask;
      }
    }
    notifyUpdateCursor();
  }