001: /*
002: * Licensed to the Apache Software Foundation (ASF) under one or more
003: * contributor license agreements. See the NOTICE file distributed with
004: * this work for additional information regarding copyright ownership.
005: * The ASF licenses this file to You under the Apache License, Version 2.0
006: * (the "License"); you may not use this file except in compliance with
007: * the License. You may obtain a copy of the License at
008: *
009: * http://www.apache.org/licenses/LICENSE-2.0
010: *
011: * Unless required by applicable law or agreed to in writing, software
012: * distributed under the License is distributed on an "AS IS" BASIS,
013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014: * See the License for the specific language governing permissions and
015: * limitations under the License.
016: */
017: /**
018: * @author Dmitry A. Durnev, Michael Danilov, Pavel Dolgov
019: * @version $Revision$
020: */package java.awt;
021:
022: import java.awt.event.MouseEvent;
023: import java.awt.event.MouseListener;
024: import java.awt.event.MouseMotionListener;
025: import java.awt.event.MouseWheelEvent;
026: import java.awt.event.MouseWheelListener;
027: import java.awt.Dispatcher.MouseGrabManager;
028: import java.util.EventListener;
029:
030: import org.apache.harmony.awt.wtk.NativeEvent;
031: import org.apache.harmony.awt.wtk.NativeWindow;
032:
033: class MouseDispatcher {
034:
035: // Fields for synthetic mouse click events generation
036: private static final int clickDelta = 5;
037: private final long[] lastPressTime = new long[] { 0l, 0l, 0l };
038: private final Point[] lastPressPos = new Point[] { null, null, null };
039: private final boolean[] buttonPressed = new boolean[] { false,
040: false, false };
041: private final int[] clickCount = new int[] { 0, 0, 0 };
042:
043: // Fields for mouse entered/exited support
044: private Component lastUnderPointer = null;
045: private final Point lastScreenPos = new Point(-1, -1);
046:
047: // Fields for redundant mouse moved/dragged filtering
048: private Component lastUnderMotion = null;
049: private Point lastLocalPos = new Point(-1, -1);
050:
051: private final MouseGrabManager mouseGrabManager;
052: private final Toolkit toolkit;
053:
054: static Point convertPoint(Component src, int x, int y,
055: Component dest) {
056: Point srcPoint = getAbsLocation(src);
057: Point destPoint = getAbsLocation(dest);
058:
059: return new Point(x + (srcPoint.x - destPoint.x), y
060: + (srcPoint.y - destPoint.y));
061: }
062:
063: static Point convertPoint(Component src, Point p, Component dst) {
064: return convertPoint(src, p.x, p.y, dst);
065: }
066:
067: private static Point getAbsLocation(Component comp) {
068: Point location = new Point(0, 0);
069:
070: for (Component parent = comp; parent != null; parent = parent.parent) {
071: Point parentPos = (parent instanceof EmbeddedWindow ? parent
072: .getNativeWindow().getScreenPos()
073: : parent.getLocation());
074:
075: location.translate(parentPos.x, parentPos.y);
076:
077: if (parent instanceof Window) {
078: break;
079: }
080: }
081:
082: return location;
083: }
084:
085: MouseDispatcher(MouseGrabManager mouseGrabManager, Toolkit toolkit) {
086: this .mouseGrabManager = mouseGrabManager;
087: this .toolkit = toolkit;
088: }
089:
090: Point getPointerPos() {
091: return lastScreenPos;
092: }
093:
094: boolean dispatch(Component src, NativeEvent event) {
095: int id = event.getEventId();
096:
097: lastScreenPos.setLocation(event.getScreenPos());
098: checkMouseEnterExit(event.getInputModifiers(), event.getTime());
099:
100: if (id == MouseEvent.MOUSE_WHEEL) {
101: dispatchWheelEvent(src, event);
102: } else if ((id != MouseEvent.MOUSE_ENTERED)
103: && (id != MouseEvent.MOUSE_EXITED)) {
104: PointerInfo info = new PointerInfo(src, event.getLocalPos());
105:
106: mouseGrabManager.preprocessEvent(event);
107: findEventSource(info);
108: if ((id == MouseEvent.MOUSE_PRESSED)
109: || (id == MouseEvent.MOUSE_RELEASED)) {
110:
111: dispatchButtonEvent(info, event);
112: } else if ((id == MouseEvent.MOUSE_MOVED)
113: || (id == MouseEvent.MOUSE_DRAGGED)) {
114:
115: dispatchMotionEvent(info, event);
116: }
117: }
118:
119: return false;
120: }
121:
122: private void checkMouseEnterExit(int modifiers, long when) {
123: PointerInfo info = findComponentUnderPointer();
124: Component curUnderPointer = propagateEvent(info,
125: AWTEvent.MOUSE_EVENT_MASK, MouseListener.class, false).src;
126:
127: if (curUnderPointer != lastUnderPointer) {
128: Point pos = info.position;
129: if ((lastUnderPointer != null)
130: && lastUnderPointer.isMouseExitedExpected()) {
131:
132: Point exitPos = convertPoint(null, lastScreenPos.x,
133: lastScreenPos.y, lastUnderPointer);
134:
135: postMouseEnterExit(MouseEvent.MOUSE_EXITED, modifiers,
136: when, exitPos.x, exitPos.y, lastUnderPointer);
137: }
138: setCursor(curUnderPointer);
139: if (curUnderPointer != null) {
140: postMouseEnterExit(MouseEvent.MOUSE_ENTERED, modifiers,
141: when, pos.x, pos.y, curUnderPointer);
142: }
143: lastUnderPointer = curUnderPointer;
144: }
145: }
146:
147: private void setCursor(Component comp) {
148: if (comp == null) {
149: return;
150: }
151: Component grabOwner = mouseGrabManager.getSyntheticGrabOwner();
152: Component cursorComp = ((grabOwner != null)
153: && grabOwner.isShowing() ? grabOwner : comp);
154: cursorComp.setCursor();
155: }
156:
157: private void postMouseEnterExit(int id, int mod, long when, int x,
158: int y, Component comp) {
159: if (comp.isIndirectlyEnabled()) {
160: toolkit.getSystemEventQueueImpl()
161: .postEvent(
162: new MouseEvent(comp, id, when, mod, x, y,
163: 0, false));
164: comp.setMouseExitedExpected(id == MouseEvent.MOUSE_ENTERED);
165: } else {
166: comp.setMouseExitedExpected(false);
167: }
168: }
169:
170: private PointerInfo findComponentUnderPointer() {
171: NativeWindow nativeWindow = toolkit.getWindowFactory()
172: .getWindowFromPoint(lastScreenPos);
173:
174: if (nativeWindow != null) {
175: Component comp = toolkit.getComponentById(nativeWindow
176: .getId());
177:
178: if (comp != null) {
179: Window window = comp.getWindowAncestor();
180: Point pointerPos = convertPoint(null, lastScreenPos.x,
181: lastScreenPos.y, window);
182:
183: if (window.getClient().contains(pointerPos)) {
184: PointerInfo info = new PointerInfo(window,
185: pointerPos);
186:
187: fall2Child(info);
188:
189: return info;
190: }
191: }
192: }
193:
194: return new PointerInfo(null, null);
195: }
196:
197: private void findEventSource(PointerInfo info) {
198: Component grabOwner = mouseGrabManager.getSyntheticGrabOwner();
199:
200: if (grabOwner != null && grabOwner.isShowing()) {
201: info.position = convertPoint(info.src, info.position,
202: grabOwner);
203: info.src = grabOwner;
204: } else {
205: rise2TopLevel(info);
206: fall2Child(info);
207: }
208: }
209:
210: private void rise2TopLevel(PointerInfo info) {
211: while (!(info.src instanceof Window)) {
212: info.position.translate(info.src.x, info.src.y);
213: info.src = info.src.parent;
214: }
215: }
216:
217: private void fall2Child(PointerInfo info) {
218: final Point pos = info.position;
219: final int x = pos.x;
220: final int y = pos.y;
221:
222: for (Component child : ((Container) info.src).getComponents()) {
223: if (child.isShowing()) {
224: if (child.contains(x - child.x, y - child.y)) {
225: info.src = child;
226: pos.translate(-child.x, -child.y);
227:
228: if (child instanceof Container) {
229: fall2Child(info);
230: }
231:
232: return;
233: }
234: }
235: }
236: }
237:
238: private void dispatchButtonEvent(PointerInfo info, NativeEvent event) {
239: int button = event.getMouseButton();
240: long time = event.getTime();
241: int id = event.getEventId();
242: int index = button - 1;
243: boolean clickRequired = false;
244:
245: propagateEvent(info, AWTEvent.MOUSE_EVENT_MASK,
246: MouseListener.class, false);
247: if (id == MouseEvent.MOUSE_PRESSED) {
248: int clickInterval = toolkit.dispatcher.clickInterval;
249: mouseGrabManager.onMousePressed(info.src);
250: buttonPressed[index] = true;
251: clickCount[index] = (!deltaExceeded(index, info) && ((time - lastPressTime[index]) <= clickInterval)) ? clickCount[index] + 1
252: : 1;
253: lastPressTime[index] = time;
254: lastPressPos[index] = info.position;
255: } else {
256: mouseGrabManager.onMouseReleased(info.src);
257: // set cursor back on synthetic mouse grab end:
258: setCursor(findComponentUnderPointer().src);
259: if (buttonPressed[index]) {
260: buttonPressed[index] = false;
261: clickRequired = !deltaExceeded(index, info);
262: } else {
263: clickCount[index] = 0;
264: }
265: }
266: if (info.src.isIndirectlyEnabled()) {
267: final Point pos = info.position;
268: final int mod = event.getInputModifiers();
269: toolkit.getSystemEventQueueImpl().postEvent(
270: new MouseEvent(info.src, id, time, mod, pos.x,
271: pos.y, clickCount[index], event
272: .getTrigger(), button));
273: if (clickRequired) {
274: toolkit.getSystemEventQueueImpl().postEvent(
275: new MouseEvent(info.src,
276: MouseEvent.MOUSE_CLICKED, time, mod,
277: pos.x, pos.y, clickCount[index], false,
278: button));
279: }
280: }
281: }
282:
283: private boolean deltaExceeded(int index, PointerInfo info) {
284: final Point lastPos = lastPressPos[index];
285: if (lastPos == null) {
286: return true;
287: }
288: return ((Math.abs(lastPos.x - info.position.x) > clickDelta) || (Math
289: .abs(lastPos.y - info.position.y) > clickDelta));
290: }
291:
292: private void dispatchMotionEvent(PointerInfo info, NativeEvent event) {
293: propagateEvent(info, AWTEvent.MOUSE_MOTION_EVENT_MASK,
294: MouseMotionListener.class, false);
295: final Point pos = info.position;
296: if ((lastUnderMotion != info.src) || !lastLocalPos.equals(pos)) {
297:
298: lastUnderMotion = info.src;
299: lastLocalPos = pos;
300:
301: if (info.src.isIndirectlyEnabled()) {
302: toolkit.getSystemEventQueueImpl().postEvent(
303: new MouseEvent(info.src, event.getEventId(),
304: event.getTime(), event
305: .getInputModifiers(), pos.x,
306: pos.y, 0, false));
307: }
308: }
309: }
310:
311: MouseWheelEvent createWheelEvent(Component src, NativeEvent event,
312: Point where) {
313:
314: Integer scrollAmountProperty = (Integer) toolkit
315: .getDesktopProperty("awt.wheelScrollingSize"); //$NON-NLS-1$
316: int amount = 1;
317: int type = MouseWheelEvent.WHEEL_UNIT_SCROLL;
318:
319: if (scrollAmountProperty != null) {
320: amount = scrollAmountProperty.intValue();
321: if (amount == -1) {
322: type = MouseWheelEvent.WHEEL_BLOCK_SCROLL;
323: amount = 1;
324: }
325: }
326: return new MouseWheelEvent(src, event.getEventId(), event
327: .getTime(), event.getInputModifiers(), where.x,
328: where.y, 0, false, type, amount, event
329: .getWheelRotation());
330: }
331:
332: private void dispatchWheelEvent(Component src, NativeEvent event) {
333: PointerInfo info = findComponentUnderPointer();
334:
335: if (info.src == null) {
336: info.src = src;
337: info.position = event.getLocalPos();
338: }
339:
340: propagateEvent(info, AWTEvent.MOUSE_WHEEL_EVENT_MASK,
341: MouseWheelListener.class, true);
342: if ((info.src != null) && info.src.isIndirectlyEnabled()) {
343: toolkit.getSystemEventQueueImpl().postEvent(
344: createWheelEvent(info.src, event, info.position));
345: }
346: }
347:
348: private PointerInfo propagateEvent(PointerInfo info, long mask,
349: Class<? extends EventListener> type, boolean pierceHW) {
350: Component src = info.src;
351: while ((src != null)
352: && (src.isLightweight() || pierceHW)
353: && !(src.isMouseEventEnabled(mask) || (src
354: .getListeners(type).length > 0))) {
355:
356: info.position.translate(src.x, src.y);
357: src = src.parent;
358: info.src = src;
359: }
360:
361: return info;
362: }
363:
364: Window findWindowAt(Point p) {
365: NativeWindow nativeWindow = toolkit.getWindowFactory()
366: .getWindowFromPoint(p);
367:
368: Window window = null;
369: if (nativeWindow != null) {
370: Component comp = toolkit.getComponentById(nativeWindow
371: .getId());
372:
373: if (comp != null) {
374: window = comp.getWindowAncestor();
375: }
376: }
377: return window;
378: }
379:
380: private class PointerInfo {
381:
382: Component src;
383: Point position;
384:
385: PointerInfo(Component src, Point position) {
386: this.src = src;
387: this.position = position;
388: }
389:
390: }
391:
392: }
|