1/* 2 * Licensed to the Apache Software Foundation (ASF) under one or more 3 * contributor license agreements. See the NOTICE file distributed with 4 * this work for additional information regarding copyright ownership. 5 * The ASF licenses this file to You under the Apache License, Version 2.0 6 * (the "License"); you may not use this file except in compliance with 7 * the License. You may obtain a copy of the License at 8 * 9 * http://www.apache.org/licenses/LICENSE-2.0 10 * 11 * Unless required by applicable law or agreed to in writing, software 12 * distributed under the License is distributed on an "AS IS" BASIS, 13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 * See the License for the specific language governing permissions and 15 * limitations under the License. 16 */ 17/** 18 * @author Dmitry A. Durnev, Michael Danilov, Pavel Dolgov 19 * @version $Revision$ 20 */ 21package java.awt; 22 23import java.awt.event.MouseEvent; 24import java.awt.event.MouseListener; 25import java.awt.event.MouseMotionListener; 26import java.awt.event.MouseWheelEvent; 27import java.awt.event.MouseWheelListener; 28import java.awt.Dispatcher.MouseGrabManager; 29import java.util.EventListener; 30 31import org.apache.harmony.awt.wtk.NativeEvent; 32import org.apache.harmony.awt.wtk.NativeWindow; 33 34 35class MouseDispatcher { 36 37 // Fields for synthetic mouse click events generation 38 private static final int clickDelta = 5; 39 private final long[] lastPressTime = new long[] {0l, 0l, 0l}; 40 private final Point[] lastPressPos = new Point[] {null, null, null}; 41 private final boolean[] buttonPressed = new boolean[] {false, false, false}; 42 private final int[] clickCount = new int[] {0, 0, 0}; 43 44 // Fields for mouse entered/exited support 45 private Component lastUnderPointer = null; 46 private final Point lastScreenPos = new Point(-1, -1); 47 48 // Fields for redundant mouse moved/dragged filtering 49 private Component lastUnderMotion = null; 50 private Point lastLocalPos = new Point(-1, -1); 51 52 private final MouseGrabManager mouseGrabManager; 53 private final Toolkit toolkit; 54 55 static Point convertPoint(Component src, int x, int y, Component dest) { 56 Point srcPoint = getAbsLocation(src); 57 Point destPoint = getAbsLocation(dest); 58 59 return new Point(x + (srcPoint.x - destPoint.x), 60 y + (srcPoint.y - destPoint.y)); 61 } 62 63 static Point convertPoint(Component src, Point p, Component dst) { 64 return convertPoint(src, p.x, p.y, dst); 65 } 66 67 private static Point getAbsLocation(Component comp) { 68 Point location = new Point(0, 0); 69// BEGIN android-changed: AWT components not supported 70// for (Component parent = comp; parent != null; parent = parent.parent) { 71// Point parentPos = (parent instanceof EmbeddedWindow ? 72// parent.getNativeWindow().getScreenPos() : 73// parent.getLocation()); 74// 75// location.translate(parentPos.x, parentPos.y); 76// 77// if (parent instanceof Window) { 78// break; 79// } 80// } 81// END android-changed 82 83 return location; 84 } 85 86 MouseDispatcher(MouseGrabManager mouseGrabManager, 87 Toolkit toolkit) { 88 this.mouseGrabManager = mouseGrabManager; 89 this.toolkit = toolkit; 90 } 91 92 Point getPointerPos() { 93 return lastScreenPos; 94 } 95 96 boolean dispatch(Component src, NativeEvent event) { 97 int id = event.getEventId(); 98 99 lastScreenPos.setLocation(event.getScreenPos()); 100 checkMouseEnterExit(event.getInputModifiers(), event.getTime()); 101 102 if (id == MouseEvent.MOUSE_WHEEL) { 103// BEGIN android-changed: AWT components not supported 104// dispatchWheelEvent(src, event); 105// END android-changed 106 } else if ((id != MouseEvent.MOUSE_ENTERED) && 107 (id != MouseEvent.MOUSE_EXITED)) { 108 PointerInfo info = new PointerInfo(src, event.getLocalPos()); 109 110 mouseGrabManager.preprocessEvent(event); 111 findEventSource(info); 112 if ((id == MouseEvent.MOUSE_PRESSED) || 113 (id == MouseEvent.MOUSE_RELEASED)) { 114 115 dispatchButtonEvent(info, event); 116 } else if ((id == MouseEvent.MOUSE_MOVED) || 117 (id == MouseEvent.MOUSE_DRAGGED)) { 118 119 dispatchMotionEvent(info, event); 120 } 121 } 122 123 return false; 124 } 125 126 private void checkMouseEnterExit(int modifiers, long when) { 127// BEGIN android-changed: AWT components not supported 128// PointerInfo info = findComponentUnderPointer(); 129// Component curUnderPointer = 130// propagateEvent(info, AWTEvent.MOUSE_EVENT_MASK, 131// MouseListener.class, false).src; 132// 133// if (curUnderPointer != lastUnderPointer) { 134// Point pos = info.position; 135// if ((lastUnderPointer != null) && 136// lastUnderPointer.isMouseExitedExpected()) { 137// 138// Point exitPos = convertPoint(null, lastScreenPos.x, 139// lastScreenPos.y, lastUnderPointer); 140// 141// postMouseEnterExit(MouseEvent.MOUSE_EXITED, modifiers, when, 142// exitPos.x, exitPos.y, lastUnderPointer); 143// } 144// setCursor(curUnderPointer); 145// if (curUnderPointer != null) { 146// postMouseEnterExit(MouseEvent.MOUSE_ENTERED, modifiers, when, 147// pos.x, pos.y, curUnderPointer); 148// } 149// lastUnderPointer = curUnderPointer; 150// } 151// END android-changed 152 } 153 154 private void setCursor(Component comp) { 155 if (comp == null) { 156 return; 157 } 158 Component grabOwner = mouseGrabManager.getSyntheticGrabOwner(); 159 Component cursorComp = ((grabOwner != null) && 160 grabOwner.isShowing() ? grabOwner : comp); 161 cursorComp.setCursor(); 162 } 163 164 private void postMouseEnterExit(int id, int mod, long when, 165 int x, int y, Component comp) { 166 if (comp.isIndirectlyEnabled()) { 167 toolkit.getSystemEventQueueImpl().postEvent( 168 new MouseEvent(comp, id, when, mod, x, y, 0, false)); 169 comp.setMouseExitedExpected(id == MouseEvent.MOUSE_ENTERED); 170 } else { 171 comp.setMouseExitedExpected(false); 172 } 173 } 174 175 // BEGIN android-changed: AWT components not supported 176// private PointerInfo findComponentUnderPointer() { 177// NativeWindow nativeWindow = toolkit.getWindowFactory(). 178// getWindowFromPoint(lastScreenPos); 179// 180// if (nativeWindow != null) { 181// Component comp = toolkit.getComponentById(nativeWindow.getId()); 182// 183// if (comp != null) { 184// Window window = comp.getWindowAncestor(); 185// Point pointerPos = convertPoint(null, lastScreenPos.x, 186// lastScreenPos.y, window); 187// 188// if (window.getClient().contains(pointerPos)) { 189// PointerInfo info = new PointerInfo(window, pointerPos); 190// 191// fall2Child(info); 192// 193// return info; 194// } 195// } 196// } 197// 198// return new PointerInfo(null, null); 199// } 200// END android-changed 201 202 private void findEventSource(PointerInfo info) { 203 Component grabOwner = mouseGrabManager.getSyntheticGrabOwner(); 204 205 if (grabOwner != null && grabOwner.isShowing()) { 206 info.position = convertPoint(info.src, info.position, grabOwner); 207 info.src = grabOwner; 208 } else { 209 //???AWT: rise2TopLevel(info); 210 //???AWT: fall2Child(info); 211 } 212 } 213 214 // BEGIN android-changed: AWT components not supported 215// private void rise2TopLevel(PointerInfo info) { 216// while (!(info.src instanceof Window)) { 217// info.position.translate(info.src.x, info.src.y); 218// info.src = info.src.parent; 219// } 220// } 221// 222// private void fall2Child(PointerInfo info) { 223// Insets insets = info.src.getInsets(); 224// 225// final Point pos = info.position; 226// final int x = pos.x; 227// final int y = pos.y; 228// if ((x >= insets.left) && (y >= insets.top) && 229// (x < (info.src.w - insets.right)) && 230// (y < (info.src.h - insets.bottom))) 231// { 232// Component[] children = ((Container) info.src).getComponents(); 233// 234// for (Component child : children) { 235// if (child.isShowing()) { 236// if (child.contains(x - child.getX(), 237// y - child.getY())) 238// { 239// info.src = child; 240// pos.translate(-child.x, -child.y); 241// 242// if (child instanceof Container) { 243// fall2Child(info); 244// } 245// 246// return; 247// } 248// } 249// } 250// } 251// } 252// END android-changed 253 254 private void dispatchButtonEvent(PointerInfo info, NativeEvent event) { 255 int button = event.getMouseButton(); 256 long time = event.getTime(); 257 int id = event.getEventId(); 258 int index = button - 1; 259 boolean clickRequired = false; 260 261 propagateEvent(info, AWTEvent.MOUSE_EVENT_MASK, 262 MouseListener.class, false); 263 if (id == MouseEvent.MOUSE_PRESSED) { 264 int clickInterval = toolkit.dispatcher.clickInterval; 265 mouseGrabManager.onMousePressed(info.src); 266 buttonPressed[index] = true; 267 clickCount[index] = (!deltaExceeded(index, info) && 268 ((time - lastPressTime[index]) <= clickInterval)) ? 269 clickCount[index] + 1 : 1; 270 lastPressTime[index] = time; 271 lastPressPos[index] = info.position; 272 } else { 273 mouseGrabManager.onMouseReleased(info.src); 274 // set cursor back on synthetic mouse grab end: 275// BEGIN android-changed: AWT components not supported 276// setCursor(findComponentUnderPointer().src); 277// END android-changed 278 if (buttonPressed[index]) { 279 buttonPressed[index] = false; 280 clickRequired = !deltaExceeded(index, info); 281 } else { 282 clickCount[index] = 0; 283 } 284 } 285 if (info.src.isIndirectlyEnabled()) { 286 final Point pos = info.position; 287 final int mod = event.getInputModifiers(); 288 toolkit.getSystemEventQueueImpl().postEvent( 289 new MouseEvent(info.src, id, time, mod, pos.x, 290 pos.y, clickCount[index], 291 event.getTrigger(), button)); 292 if (clickRequired) { 293 toolkit.getSystemEventQueueImpl().postEvent( 294 new MouseEvent(info.src, 295 MouseEvent.MOUSE_CLICKED, 296 time, mod, pos.x, pos.y, 297 clickCount[index], false, 298 button)); 299 } 300 } 301 } 302 303 private boolean deltaExceeded(int index, PointerInfo info) { 304 final Point lastPos = lastPressPos[index]; 305 if (lastPos == null) { 306 return true; 307 } 308 return ((Math.abs(lastPos.x - info.position.x) > clickDelta) || 309 (Math.abs(lastPos.y - info.position.y) > clickDelta)); 310 } 311 312 private void dispatchMotionEvent(PointerInfo info, NativeEvent event) { 313 propagateEvent(info, AWTEvent.MOUSE_MOTION_EVENT_MASK, 314 MouseMotionListener.class, false); 315 final Point pos = info.position; 316 if ((lastUnderMotion != info.src) || 317 !lastLocalPos.equals(pos)) { 318 319 lastUnderMotion = info.src; 320 lastLocalPos = pos; 321 322 if (info.src.isIndirectlyEnabled()) { 323 toolkit.getSystemEventQueueImpl().postEvent( 324 new MouseEvent(info.src, event.getEventId(), 325 event.getTime(), 326 event.getInputModifiers(), 327 pos.x, pos.y, 0, false)); 328 } 329 } 330 } 331 332 MouseWheelEvent createWheelEvent(Component src, NativeEvent event, 333 Point where) { 334 335 Integer scrollAmountProperty = 336 (Integer)toolkit.getDesktopProperty("awt.wheelScrollingSize"); //$NON-NLS-1$ 337 int amount = 1; 338 int type = MouseWheelEvent.WHEEL_UNIT_SCROLL; 339 340 if (scrollAmountProperty != null) { 341 amount = scrollAmountProperty.intValue(); 342 if (amount == -1) { 343 type = MouseWheelEvent.WHEEL_BLOCK_SCROLL; 344 amount = 1; 345 } 346 } 347 return new MouseWheelEvent(src, event.getEventId(), 348 event.getTime(), event.getInputModifiers(), 349 where.x, where.y, 0, false, type, amount, 350 event.getWheelRotation()); 351 } 352 353// BEGIN android-changed: AWT components not supported 354// private void dispatchWheelEvent(Component src, NativeEvent event) { 355// PointerInfo info = findComponentUnderPointer(); 356// 357// if (info.src == null) { 358// info.src = src; 359// info.position = event.getLocalPos(); 360// } 361// 362// propagateEvent(info, AWTEvent.MOUSE_WHEEL_EVENT_MASK, 363// MouseWheelListener.class, true); 364// if ((info.src != null) && info.src.isIndirectlyEnabled()) { 365// toolkit.getSystemEventQueueImpl().postEvent( 366// createWheelEvent(info.src, event, info.position)); 367// } 368// } 369// END android-changed 370 371 private PointerInfo propagateEvent(PointerInfo info, long mask, 372 Class<? extends EventListener> type, boolean pierceHW) { 373 Component src = info.src; 374 while ((src != null) && 375 (src.isLightweight() || pierceHW) && 376 !(src.isMouseEventEnabled(mask) || 377 (src.getListeners(type).length > 0))) { 378 379 info.position.translate(src.x, src.y); 380// BEGIN android-changed: AWT components not supported 381// src = src.parent; 382// END android-changed 383 info.src = src; 384 } 385 386 return info; 387 } 388 389// BEGIN android-changed: AWT components not supported 390// Window findWindowAt(Point p) { 391// NativeWindow nativeWindow = 392// toolkit.getWindowFactory().getWindowFromPoint(p); 393// 394// Window window = null; 395// if (nativeWindow != null) { 396// Component comp = toolkit.getComponentById(nativeWindow.getId()); 397// 398// if (comp != null) { 399// window = comp.getWindowAncestor(); 400// } 401// } 402// return window; 403// } 404// END android-changed 405 406 private class PointerInfo { 407 408 Component src; 409 Point position; 410 411 PointerInfo(Component src, Point position) { 412 this.src = src; 413 this.position = position; 414 } 415 416 } 417 418} 419