mirror of git://gcc.gnu.org/git/gcc.git
				
				
				
			
		
			
				
	
	
		
			229 lines
		
	
	
		
			7.9 KiB
		
	
	
	
		
			Java
		
	
	
	
			
		
		
	
	
			229 lines
		
	
	
		
			7.9 KiB
		
	
	
	
		
			Java
		
	
	
	
| /* LightweightDispatcher.java -- Dispatches mouse events to lightweights
 | |
|    Copyright (C) 2006 Free Software Foundation, Inc.
 | |
| 
 | |
| This file is part of GNU Classpath.
 | |
| 
 | |
| GNU Classpath is free software; you can redistribute it and/or modify
 | |
| it under the terms of the GNU General Public License as published by
 | |
| the Free Software Foundation; either version 2, or (at your option)
 | |
| any later version.
 | |
| 
 | |
| GNU Classpath is distributed in the hope that it will be useful, but
 | |
| WITHOUT ANY WARRANTY; without even the implied warranty of
 | |
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 | |
| General Public License for more details.
 | |
| 
 | |
| You should have received a copy of the GNU General Public License
 | |
| along with GNU Classpath; see the file COPYING.  If not, write to the
 | |
| Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
 | |
| 02110-1301 USA.
 | |
| 
 | |
| Linking this library statically or dynamically with other modules is
 | |
| making a combined work based on this library.  Thus, the terms and
 | |
| conditions of the GNU General Public License cover the whole
 | |
| combination.
 | |
| 
 | |
| As a special exception, the copyright holders of this library give you
 | |
| permission to link this library with independent modules to produce an
 | |
| executable, regardless of the license terms of these independent
 | |
| modules, and to copy and distribute the resulting executable under
 | |
| terms of your choice, provided that you also meet, for each linked
 | |
| independent module, the terms and conditions of the license of that
 | |
| module.  An independent module is a module which is not derived from
 | |
| or based on this library.  If you modify this library, you may extend
 | |
| this exception to your version of the library, but you are not
 | |
| obligated to do so.  If you do not wish to do so, delete this
 | |
| exception statement from your version. */
 | |
| 
 | |
| 
 | |
| package java.awt;
 | |
| 
 | |
| import gnu.java.awt.AWTUtilities;
 | |
| 
 | |
| import java.awt.event.MouseEvent;
 | |
| import java.util.WeakHashMap;
 | |
| 
 | |
| /**
 | |
|  * Redispatches mouse events to lightweight components. The native peers know
 | |
|  * nothing about the lightweight components and thus mouse events are always
 | |
|  * targetted at Windows or heavyweight components. This class listenes directly
 | |
|  * on the eventqueue and dispatches mouse events to lightweight components.
 | |
|  *
 | |
|  * @author Roman Kennke (kennke@aicas.com)
 | |
|  */
 | |
| class LightweightDispatcher
 | |
| {
 | |
| 
 | |
|   /**
 | |
|    * Maps thread groups to lightweight dispatcher instances. We need to
 | |
|    * have one instance per thread group so that 2 or more applets or otherwise
 | |
|    * separated applications (like in OSGI) do not interfer with each other.
 | |
|    */
 | |
|   private static WeakHashMap instances = new WeakHashMap();
 | |
| 
 | |
|   /**
 | |
|    * The component that is the start of a mouse dragging. All MOUSE_DRAGGED
 | |
|    * events that follow the initial press must have the source set to this,
 | |
|    * as well as the MOUSE_RELEASED event following the dragging.
 | |
|    */
 | |
|   private Component dragTarget;
 | |
| 
 | |
|   /**
 | |
|    * The last mouse event target. If the target changes, additional
 | |
|    * MOUSE_ENTERED and MOUSE_EXITED events must be dispatched.
 | |
|    */
 | |
|   private Component lastTarget;
 | |
| 
 | |
|   /**
 | |
|    * Returns an instance of LightweightDispatcher for the current thread's
 | |
|    * thread group.
 | |
|    *
 | |
|    * @return an instance of LightweightDispatcher for the current thread's
 | |
|    *         thread group
 | |
|    */
 | |
|   static LightweightDispatcher getInstance()
 | |
|   {
 | |
|     Thread t = Thread.currentThread();
 | |
|     ThreadGroup tg = t.getThreadGroup();
 | |
|     LightweightDispatcher instance = (LightweightDispatcher) instances.get(tg);
 | |
|     if (instance == null)
 | |
|       {
 | |
|         instance = new LightweightDispatcher();
 | |
|         instances.put(tg, instance);
 | |
|       }
 | |
|     return instance;
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * Creates a new LightweightDispatcher. This is private to prevent access
 | |
|    * from outside. Use {@link #getInstance()} instead.
 | |
|    */
 | |
|   private LightweightDispatcher()
 | |
|   {
 | |
|     // Nothing to do here.
 | |
|   }
 | |
|   
 | |
|   /**
 | |
|    * Receives notification if a mouse event passes along the eventqueue.
 | |
|    *
 | |
|    * @param event the event
 | |
|    */
 | |
|   public boolean dispatchEvent(AWTEvent event)
 | |
|   {
 | |
|     if (event instanceof MouseEvent && event.getSource() instanceof Window)
 | |
|       {
 | |
|         MouseEvent mouseEvent = (MouseEvent) event;
 | |
|         return handleMouseEvent(mouseEvent);
 | |
|       }
 | |
|     return false;
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * Handles all mouse events that are targetted at toplevel containers
 | |
|    * (Window instances) and dispatches them to the correct lightweight child.
 | |
|    *
 | |
|    * @param ev the mouse event
 | |
|    * @return whether or not we found a lightweight that handled the event.
 | |
|    */
 | |
|   private boolean handleMouseEvent(MouseEvent ev)
 | |
|   {
 | |
|     Window window = (Window) ev.getSource();
 | |
|     Component target = window.findComponentAt(ev.getX(), ev.getY());
 | |
|     target = findTarget(target);
 | |
|     if (target == null || target.isLightweight())
 | |
|       {
 | |
|         // Dispatch additional MOUSE_EXITED and MOUSE_ENTERED if event target
 | |
|         // is different from the last event target.
 | |
|         if (target != lastTarget)
 | |
|           {
 | |
|             if (lastTarget != null)
 | |
|               {
 | |
|                 Point p1 = AWTUtilities.convertPoint(window, ev.getX(),
 | |
|                                                      ev.getY(), lastTarget);
 | |
|                 MouseEvent mouseExited =
 | |
|                   new MouseEvent(lastTarget, MouseEvent.MOUSE_EXITED,
 | |
|                                  ev.getWhen(), ev.getModifiers(), p1.x, p1.y,
 | |
|                                  ev.getClickCount(), ev.isPopupTrigger());
 | |
|                 lastTarget.dispatchEvent(mouseExited);
 | |
|               }
 | |
|             if (target != null)
 | |
|               {
 | |
|                 Point p = AWTUtilities.convertPoint(window, ev.getX(), ev.getY(),
 | |
|                                                     target);
 | |
|                 MouseEvent mouseEntered =
 | |
|                   new MouseEvent(target, MouseEvent.MOUSE_ENTERED, ev.getWhen(),
 | |
|                                  ev.getModifiers(), p.x, p.y, ev.getClickCount(),
 | |
|                                  ev.isPopupTrigger());
 | |
|                 target.dispatchEvent(mouseEntered);
 | |
|               }
 | |
|           }
 | |
|         
 | |
|         switch (ev.getID())
 | |
|         {
 | |
|           case MouseEvent.MOUSE_PRESSED:
 | |
|             dragTarget = target;
 | |
|             break;
 | |
|           case MouseEvent.MOUSE_RELEASED:
 | |
|             if (dragTarget != null)
 | |
|               target = dragTarget;
 | |
|             dragTarget = null;
 | |
|             break;
 | |
|           case MouseEvent.MOUSE_CLICKED:
 | |
|             // When we receive a MOUSE_CLICKED, we set the target to the
 | |
|             // previous target, which must have been a MOUSE_RELEASED event.
 | |
|             // This is necessary for the case when the MOUSE_RELEASED has
 | |
|             // caused the original target (like an internal component) go
 | |
|             // away.
 | |
|             target = lastTarget;
 | |
|             break;
 | |
|           case MouseEvent.MOUSE_DRAGGED:
 | |
|             target = dragTarget;
 | |
|             break;
 | |
|           default:
 | |
|             // Do nothing in other cases.
 | |
|             break;
 | |
|         }
 | |
| 
 | |
|         lastTarget = target;
 | |
| 
 | |
|         if (target != null)
 | |
|           {
 | |
|             Point targetCoordinates =
 | |
|               AWTUtilities.convertPoint(window, ev.getX(), ev.getY(), target);
 | |
|             int dx = targetCoordinates.x - ev.getX();
 | |
|             int dy = targetCoordinates.y - ev.getY();
 | |
|             ev.translatePoint(dx, dy);
 | |
|             ev.setSource(target);
 | |
|             target.dispatchEvent(ev);
 | |
|             // We reset the event, so that the normal event dispatching is not
 | |
|             // influenced by this modified event.
 | |
|             ev.setSource(window);
 | |
|             ev.translatePoint(-dx, -dy);
 | |
|           }
 | |
| 
 | |
| 	return true;
 | |
|       }
 | |
|     else
 | |
|       return false;
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * Finds the actual target for a mouseevent, starting at <code>c</code>.
 | |
|    * This searches upwards the component hierarchy until it finds a component
 | |
|    * that has a mouselistener attached.
 | |
|    *
 | |
|    * @param c the component to start searching from
 | |
|    *
 | |
|    * @return the actual receiver of the mouse event
 | |
|    */
 | |
|   private Component findTarget(Component c)
 | |
|   {
 | |
|     Component target = c;
 | |
|     while (target != null && target.getMouseListeners().length == 0)
 | |
|       {
 | |
|         target = target.getParent();
 | |
|       }
 | |
|     return target;
 | |
|   }
 | |
| }
 |