419 lines
15 KiB
Java
419 lines
15 KiB
Java
/*
|
|
* 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;
|
|
}
|
|
|
|
}
|
|
|
|
}
|