Path: blob/master/src/java.desktop/macosx/classes/com/apple/eawt/event/GestureHandler.java
41159 views
/*1* Copyright (c) 2011, 2013, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation. Oracle designates this7* particular file as subject to the "Classpath" exception as provided8* by Oracle in the LICENSE file that accompanied this code.9*10* This code is distributed in the hope that it will be useful, but WITHOUT11* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or12* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License13* version 2 for more details (a copy is included in the LICENSE file that14* accompanied this code).15*16* You should have received a copy of the GNU General Public License version17* 2 along with this work; if not, write to the Free Software Foundation,18* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.19*20* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA21* or visit www.oracle.com if you need additional information or have any22* questions.23*/2425package com.apple.eawt.event;2627import sun.awt.SunToolkit;2829import java.awt.*;30import java.util.*;31import java.util.List;3233import javax.swing.*;3435import java.lang.annotation.Native;3637final class GestureHandler {38private static final String CLIENT_PROPERTY = "com.apple.eawt.event.internalGestureHandler";3940// native constants for the supported types of high-level gestures41@Native static final int PHASE = 1;42@Native static final int ROTATE = 2;43@Native static final int MAGNIFY = 3;44@Native static final int SWIPE = 4;4546// installs a private instance of GestureHandler, if necessary47static void addGestureListenerTo(final JComponent component, final GestureListener listener) {48final Object value = component.getClientProperty(CLIENT_PROPERTY);49if (value instanceof GestureHandler) {50((GestureHandler)value).addListener(listener);51return;52}5354if (value != null) return; // some other garbage is in our client property5556final GestureHandler newHandler = new GestureHandler();57newHandler.addListener(listener);58component.putClientProperty(CLIENT_PROPERTY, newHandler);59}6061// asks the installed GestureHandler to remove it's listener (does not uninstall the GestureHandler)62static void removeGestureListenerFrom(final JComponent component, final GestureListener listener) {63final Object value = component.getClientProperty(CLIENT_PROPERTY);64if (!(value instanceof GestureHandler)) return;65((GestureHandler)value).removeListener(listener);66}676869// called from native - finds the deepest component with an installed GestureHandler,70// creates a single event, and dispatches it to a recursive notifier71static void handleGestureFromNative(final Window window, final int type, final double x, final double y, final double a, final double b) {72if (window == null) return; // should never happen...7374SunToolkit.executeOnEventHandlerThread(window, new Runnable() {75public void run() {76final Component component = SwingUtilities.getDeepestComponentAt(window, (int)x, (int)y);7778final PerComponentNotifier firstNotifier;79if (component instanceof RootPaneContainer) {80firstNotifier = getNextNotifierForComponent(((RootPaneContainer)component).getRootPane());81} else {82firstNotifier = getNextNotifierForComponent(component);83}84if (firstNotifier == null) return;8586switch (type) {87case PHASE:88firstNotifier.recursivelyHandlePhaseChange(a, new GesturePhaseEvent());89return;90case ROTATE:91firstNotifier.recursivelyHandleRotate(new RotationEvent(a));92return;93case MAGNIFY:94firstNotifier.recursivelyHandleMagnify(new MagnificationEvent(a));95return;96case SWIPE:97firstNotifier.recursivelyHandleSwipe(a, b, new SwipeEvent());98return;99}100}101});102}103104105final List<GesturePhaseListener> phasers = new LinkedList<GesturePhaseListener>();106final List<RotationListener> rotaters = new LinkedList<RotationListener>();107final List<MagnificationListener> magnifiers = new LinkedList<MagnificationListener>();108final List<SwipeListener> swipers = new LinkedList<SwipeListener>();109110GestureHandler() { }111112void addListener(final GestureListener listener) {113if (listener instanceof GesturePhaseListener) phasers.add((GesturePhaseListener)listener);114if (listener instanceof RotationListener) rotaters.add((RotationListener)listener);115if (listener instanceof MagnificationListener) magnifiers.add((MagnificationListener)listener);116if (listener instanceof SwipeListener) swipers.add((SwipeListener)listener);117}118119void removeListener(final GestureListener listener) {120phasers.remove(listener);121rotaters.remove(listener);122magnifiers.remove(listener);123swipers.remove(listener);124}125126// notifies all listeners in a particular component/handler pair127// and recursively notifies up the component hierarchy128static class PerComponentNotifier {129final Component component;130final GestureHandler handler;131132public PerComponentNotifier(final Component component, final GestureHandler handler) {133this.component = component;134this.handler = handler;135}136137void recursivelyHandlePhaseChange(final double phase, final GesturePhaseEvent e) {138for (final GesturePhaseListener listener : handler.phasers) {139if (phase < 0) {140listener.gestureBegan(e);141} else {142listener.gestureEnded(e);143}144if (e.isConsumed()) return;145}146147final PerComponentNotifier next = getNextNotifierForComponent(component.getParent());148if (next != null) next.recursivelyHandlePhaseChange(phase, e);149}150151void recursivelyHandleRotate(final RotationEvent e) {152for (final RotationListener listener : handler.rotaters) {153listener.rotate(e);154if (e.isConsumed()) return;155}156157final PerComponentNotifier next = getNextNotifierForComponent(component.getParent());158if (next != null) next.recursivelyHandleRotate(e);159}160161void recursivelyHandleMagnify(final MagnificationEvent e) {162for (final MagnificationListener listener : handler.magnifiers) {163listener.magnify(e);164if (e.isConsumed()) return;165}166167final PerComponentNotifier next = getNextNotifierForComponent(component.getParent());168if (next != null) next.recursivelyHandleMagnify(e);169}170171void recursivelyHandleSwipe(final double x, final double y, final SwipeEvent e) {172for (final SwipeListener listener : handler.swipers) {173if (x < 0) listener.swipedLeft(e);174if (x > 0) listener.swipedRight(e);175if (y < 0) listener.swipedDown(e);176if (y > 0) listener.swipedUp(e);177if (e.isConsumed()) return;178}179180final PerComponentNotifier next = getNextNotifierForComponent(component.getParent());181if (next != null) next.recursivelyHandleSwipe(x, y, e);182}183}184185// helper function to get a handler from a Component186static GestureHandler getHandlerForComponent(final Component c) {187if (!(c instanceof JComponent)) return null;188final Object value = ((JComponent)c).getClientProperty(CLIENT_PROPERTY);189if (!(value instanceof GestureHandler)) return null;190return (GestureHandler)value;191}192193// recursive helper to find the next component/handler pair194static PerComponentNotifier getNextNotifierForComponent(final Component c) {195if (c == null) return null;196197final GestureHandler handler = getHandlerForComponent(c);198if (handler != null) {199return new PerComponentNotifier(c, handler);200}201202return getNextNotifierForComponent(c.getParent());203}204}205206207