| /* |
| * Licensed to the Apache Software Foundation (ASF) under one or more |
| * contributor license agreements. See the NOTICE file distributed with |
| * this work for additional information regarding copyright ownership. |
| * The ASF licenses this file to You under the Apache License, Version 2.0 |
| * (the "License"); you may not use this file except in compliance with |
| * the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| /** |
| * @author Dmitry A. Durnev, Michael Danilov, Pavel Dolgov |
| * @version $Revision$ |
| */ |
| package java.awt; |
| |
| import java.awt.event.MouseEvent; |
| import java.awt.event.MouseListener; |
| import java.awt.event.MouseMotionListener; |
| import java.awt.event.MouseWheelEvent; |
| import java.awt.event.MouseWheelListener; |
| import java.awt.Dispatcher.MouseGrabManager; |
| import java.util.EventListener; |
| |
| import org.apache.harmony.awt.wtk.NativeEvent; |
| import org.apache.harmony.awt.wtk.NativeWindow; |
| |
| |
| class MouseDispatcher { |
| |
| // Fields for synthetic mouse click events generation |
| private static final int clickDelta = 5; |
| private final long[] lastPressTime = new long[] {0l, 0l, 0l}; |
| private final Point[] lastPressPos = new Point[] {null, null, null}; |
| private final boolean[] buttonPressed = new boolean[] {false, false, false}; |
| private final int[] clickCount = new int[] {0, 0, 0}; |
| |
| // Fields for mouse entered/exited support |
| private Component lastUnderPointer = null; |
| private final Point lastScreenPos = new Point(-1, -1); |
| |
| // Fields for redundant mouse moved/dragged filtering |
| private Component lastUnderMotion = null; |
| private Point lastLocalPos = new Point(-1, -1); |
| |
| private final MouseGrabManager mouseGrabManager; |
| private final Toolkit toolkit; |
| |
| static Point convertPoint(Component src, int x, int y, Component dest) { |
| Point srcPoint = getAbsLocation(src); |
| Point destPoint = getAbsLocation(dest); |
| |
| return new Point(x + (srcPoint.x - destPoint.x), |
| y + (srcPoint.y - destPoint.y)); |
| } |
| |
| static Point convertPoint(Component src, Point p, Component dst) { |
| return convertPoint(src, p.x, p.y, dst); |
| } |
| |
| private static Point getAbsLocation(Component comp) { |
| Point location = new Point(0, 0); |
| // BEGIN android-changed: AWT components not supported |
| // for (Component parent = comp; parent != null; parent = parent.parent) { |
| // Point parentPos = (parent instanceof EmbeddedWindow ? |
| // parent.getNativeWindow().getScreenPos() : |
| // parent.getLocation()); |
| // |
| // location.translate(parentPos.x, parentPos.y); |
| // |
| // if (parent instanceof Window) { |
| // break; |
| // } |
| // } |
| // END android-changed |
| |
| return location; |
| } |
| |
| MouseDispatcher(MouseGrabManager mouseGrabManager, |
| Toolkit toolkit) { |
| this.mouseGrabManager = mouseGrabManager; |
| this.toolkit = toolkit; |
| } |
| |
| Point getPointerPos() { |
| return lastScreenPos; |
| } |
| |
| boolean dispatch(Component src, NativeEvent event) { |
| int id = event.getEventId(); |
| |
| lastScreenPos.setLocation(event.getScreenPos()); |
| checkMouseEnterExit(event.getInputModifiers(), event.getTime()); |
| |
| if (id == MouseEvent.MOUSE_WHEEL) { |
| // BEGIN android-changed: AWT components not supported |
| // dispatchWheelEvent(src, event); |
| // END android-changed |
| } else if ((id != MouseEvent.MOUSE_ENTERED) && |
| (id != MouseEvent.MOUSE_EXITED)) { |
| PointerInfo info = new PointerInfo(src, event.getLocalPos()); |
| |
| mouseGrabManager.preprocessEvent(event); |
| findEventSource(info); |
| if ((id == MouseEvent.MOUSE_PRESSED) || |
| (id == MouseEvent.MOUSE_RELEASED)) { |
| |
| dispatchButtonEvent(info, event); |
| } else if ((id == MouseEvent.MOUSE_MOVED) || |
| (id == MouseEvent.MOUSE_DRAGGED)) { |
| |
| dispatchMotionEvent(info, event); |
| } |
| } |
| |
| return false; |
| } |
| |
| private void checkMouseEnterExit(int modifiers, long when) { |
| // BEGIN android-changed: AWT components not supported |
| // PointerInfo info = findComponentUnderPointer(); |
| // Component curUnderPointer = |
| // propagateEvent(info, AWTEvent.MOUSE_EVENT_MASK, |
| // MouseListener.class, false).src; |
| // |
| // if (curUnderPointer != lastUnderPointer) { |
| // Point pos = info.position; |
| // if ((lastUnderPointer != null) && |
| // lastUnderPointer.isMouseExitedExpected()) { |
| // |
| // Point exitPos = convertPoint(null, lastScreenPos.x, |
| // lastScreenPos.y, lastUnderPointer); |
| // |
| // postMouseEnterExit(MouseEvent.MOUSE_EXITED, modifiers, when, |
| // exitPos.x, exitPos.y, lastUnderPointer); |
| // } |
| // setCursor(curUnderPointer); |
| // if (curUnderPointer != null) { |
| // postMouseEnterExit(MouseEvent.MOUSE_ENTERED, modifiers, when, |
| // pos.x, pos.y, curUnderPointer); |
| // } |
| // lastUnderPointer = curUnderPointer; |
| // } |
| // END android-changed |
| } |
| |
| private void setCursor(Component comp) { |
| if (comp == null) { |
| return; |
| } |
| Component grabOwner = mouseGrabManager.getSyntheticGrabOwner(); |
| Component cursorComp = ((grabOwner != null) && |
| grabOwner.isShowing() ? grabOwner : comp); |
| cursorComp.setCursor(); |
| } |
| |
| private void postMouseEnterExit(int id, int mod, long when, |
| int x, int y, Component comp) { |
| if (comp.isIndirectlyEnabled()) { |
| toolkit.getSystemEventQueueImpl().postEvent( |
| new MouseEvent(comp, id, when, mod, x, y, 0, false)); |
| comp.setMouseExitedExpected(id == MouseEvent.MOUSE_ENTERED); |
| } else { |
| comp.setMouseExitedExpected(false); |
| } |
| } |
| |
| // BEGIN android-changed: AWT components not supported |
| // private PointerInfo findComponentUnderPointer() { |
| // NativeWindow nativeWindow = toolkit.getWindowFactory(). |
| // getWindowFromPoint(lastScreenPos); |
| // |
| // if (nativeWindow != null) { |
| // Component comp = toolkit.getComponentById(nativeWindow.getId()); |
| // |
| // if (comp != null) { |
| // Window window = comp.getWindowAncestor(); |
| // Point pointerPos = convertPoint(null, lastScreenPos.x, |
| // lastScreenPos.y, window); |
| // |
| // if (window.getClient().contains(pointerPos)) { |
| // PointerInfo info = new PointerInfo(window, pointerPos); |
| // |
| // fall2Child(info); |
| // |
| // return info; |
| // } |
| // } |
| // } |
| // |
| // return new PointerInfo(null, null); |
| // } |
| // END android-changed |
| |
| private void findEventSource(PointerInfo info) { |
| Component grabOwner = mouseGrabManager.getSyntheticGrabOwner(); |
| |
| if (grabOwner != null && grabOwner.isShowing()) { |
| info.position = convertPoint(info.src, info.position, grabOwner); |
| info.src = grabOwner; |
| } else { |
| //???AWT: rise2TopLevel(info); |
| //???AWT: fall2Child(info); |
| } |
| } |
| |
| // BEGIN android-changed: AWT components not supported |
| // private void rise2TopLevel(PointerInfo info) { |
| // while (!(info.src instanceof Window)) { |
| // info.position.translate(info.src.x, info.src.y); |
| // info.src = info.src.parent; |
| // } |
| // } |
| // |
| // private void fall2Child(PointerInfo info) { |
| // Insets insets = info.src.getInsets(); |
| // |
| // final Point pos = info.position; |
| // final int x = pos.x; |
| // final int y = pos.y; |
| // if ((x >= insets.left) && (y >= insets.top) && |
| // (x < (info.src.w - insets.right)) && |
| // (y < (info.src.h - insets.bottom))) |
| // { |
| // Component[] children = ((Container) info.src).getComponents(); |
| // |
| // for (Component child : children) { |
| // if (child.isShowing()) { |
| // if (child.contains(x - child.getX(), |
| // y - child.getY())) |
| // { |
| // info.src = child; |
| // pos.translate(-child.x, -child.y); |
| // |
| // if (child instanceof Container) { |
| // fall2Child(info); |
| // } |
| // |
| // return; |
| // } |
| // } |
| // } |
| // } |
| // } |
| // END android-changed |
| |
| private void dispatchButtonEvent(PointerInfo info, NativeEvent event) { |
| int button = event.getMouseButton(); |
| long time = event.getTime(); |
| int id = event.getEventId(); |
| int index = button - 1; |
| boolean clickRequired = false; |
| |
| propagateEvent(info, AWTEvent.MOUSE_EVENT_MASK, |
| MouseListener.class, false); |
| if (id == MouseEvent.MOUSE_PRESSED) { |
| int clickInterval = toolkit.dispatcher.clickInterval; |
| mouseGrabManager.onMousePressed(info.src); |
| buttonPressed[index] = true; |
| clickCount[index] = (!deltaExceeded(index, info) && |
| ((time - lastPressTime[index]) <= clickInterval)) ? |
| clickCount[index] + 1 : 1; |
| lastPressTime[index] = time; |
| lastPressPos[index] = info.position; |
| } else { |
| mouseGrabManager.onMouseReleased(info.src); |
| // set cursor back on synthetic mouse grab end: |
| // BEGIN android-changed: AWT components not supported |
| // setCursor(findComponentUnderPointer().src); |
| // END android-changed |
| if (buttonPressed[index]) { |
| buttonPressed[index] = false; |
| clickRequired = !deltaExceeded(index, info); |
| } else { |
| clickCount[index] = 0; |
| } |
| } |
| if (info.src.isIndirectlyEnabled()) { |
| final Point pos = info.position; |
| final int mod = event.getInputModifiers(); |
| toolkit.getSystemEventQueueImpl().postEvent( |
| new MouseEvent(info.src, id, time, mod, pos.x, |
| pos.y, clickCount[index], |
| event.getTrigger(), button)); |
| if (clickRequired) { |
| toolkit.getSystemEventQueueImpl().postEvent( |
| new MouseEvent(info.src, |
| MouseEvent.MOUSE_CLICKED, |
| time, mod, pos.x, pos.y, |
| clickCount[index], false, |
| button)); |
| } |
| } |
| } |
| |
| private boolean deltaExceeded(int index, PointerInfo info) { |
| final Point lastPos = lastPressPos[index]; |
| if (lastPos == null) { |
| return true; |
| } |
| return ((Math.abs(lastPos.x - info.position.x) > clickDelta) || |
| (Math.abs(lastPos.y - info.position.y) > clickDelta)); |
| } |
| |
| private void dispatchMotionEvent(PointerInfo info, NativeEvent event) { |
| propagateEvent(info, AWTEvent.MOUSE_MOTION_EVENT_MASK, |
| MouseMotionListener.class, false); |
| final Point pos = info.position; |
| if ((lastUnderMotion != info.src) || |
| !lastLocalPos.equals(pos)) { |
| |
| lastUnderMotion = info.src; |
| lastLocalPos = pos; |
| |
| if (info.src.isIndirectlyEnabled()) { |
| toolkit.getSystemEventQueueImpl().postEvent( |
| new MouseEvent(info.src, event.getEventId(), |
| event.getTime(), |
| event.getInputModifiers(), |
| pos.x, pos.y, 0, false)); |
| } |
| } |
| } |
| |
| MouseWheelEvent createWheelEvent(Component src, NativeEvent event, |
| Point where) { |
| |
| Integer scrollAmountProperty = |
| (Integer)toolkit.getDesktopProperty("awt.wheelScrollingSize"); //$NON-NLS-1$ |
| int amount = 1; |
| int type = MouseWheelEvent.WHEEL_UNIT_SCROLL; |
| |
| if (scrollAmountProperty != null) { |
| amount = scrollAmountProperty.intValue(); |
| if (amount == -1) { |
| type = MouseWheelEvent.WHEEL_BLOCK_SCROLL; |
| amount = 1; |
| } |
| } |
| return new MouseWheelEvent(src, event.getEventId(), |
| event.getTime(), event.getInputModifiers(), |
| where.x, where.y, 0, false, type, amount, |
| event.getWheelRotation()); |
| } |
| |
| // BEGIN android-changed: AWT components not supported |
| // private void dispatchWheelEvent(Component src, NativeEvent event) { |
| // PointerInfo info = findComponentUnderPointer(); |
| // |
| // if (info.src == null) { |
| // info.src = src; |
| // info.position = event.getLocalPos(); |
| // } |
| // |
| // propagateEvent(info, AWTEvent.MOUSE_WHEEL_EVENT_MASK, |
| // MouseWheelListener.class, true); |
| // if ((info.src != null) && info.src.isIndirectlyEnabled()) { |
| // toolkit.getSystemEventQueueImpl().postEvent( |
| // createWheelEvent(info.src, event, info.position)); |
| // } |
| // } |
| // END android-changed |
| |
| private PointerInfo propagateEvent(PointerInfo info, long mask, |
| Class<? extends EventListener> type, boolean pierceHW) { |
| Component src = info.src; |
| while ((src != null) && |
| (src.isLightweight() || pierceHW) && |
| !(src.isMouseEventEnabled(mask) || |
| (src.getListeners(type).length > 0))) { |
| |
| info.position.translate(src.x, src.y); |
| // BEGIN android-changed: AWT components not supported |
| // src = src.parent; |
| // END android-changed |
| info.src = src; |
| } |
| |
| return info; |
| } |
| |
| // BEGIN android-changed: AWT components not supported |
| // Window findWindowAt(Point p) { |
| // NativeWindow nativeWindow = |
| // toolkit.getWindowFactory().getWindowFromPoint(p); |
| // |
| // Window window = null; |
| // if (nativeWindow != null) { |
| // Component comp = toolkit.getComponentById(nativeWindow.getId()); |
| // |
| // if (comp != null) { |
| // window = comp.getWindowAncestor(); |
| // } |
| // } |
| // return window; |
| // } |
| // END android-changed |
| |
| private class PointerInfo { |
| |
| Component src; |
| Point position; |
| |
| PointerInfo(Component src, Point position) { |
| this.src = src; |
| this.position = position; |
| } |
| |
| } |
| |
| } |