1 /* LightweightDispatcher.java -- Dispatches mouse events to lightweights
2 Copyright (C) 2006 Free Software Foundation, Inc.
4 This file is part of GNU Classpath.
6 GNU Classpath is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2, or (at your option)
11 GNU Classpath is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with GNU Classpath; see the file COPYING. If not, write to the
18 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
21 Linking this library statically or dynamically with other modules is
22 making a combined work based on this library. Thus, the terms and
23 conditions of the GNU General Public License cover the whole
26 As a special exception, the copyright holders of this library give you
27 permission to link this library with independent modules to produce an
28 executable, regardless of the license terms of these independent
29 modules, and to copy and distribute the resulting executable under
30 terms of your choice, provided that you also meet, for each linked
31 independent module, the terms and conditions of the license of that
32 module. An independent module is a module which is not derived from
33 or based on this library. If you modify this library, you may extend
34 this exception to your version of the library, but you are not
35 obligated to do so. If you do not wish to do so, delete this
36 exception statement from your version. */
41 import gnu.java.awt.AWTUtilities;
43 import java.awt.event.MouseEvent;
44 import java.util.WeakHashMap;
47 * Redispatches mouse events to lightweight components. The native peers know
48 * nothing about the lightweight components and thus mouse events are always
49 * targetted at Windows or heavyweight components. This class listenes directly
50 * on the eventqueue and dispatches mouse events to lightweight components.
52 * @author Roman Kennke (kennke@aicas.com)
54 class LightweightDispatcher
58 * Maps thread groups to lightweight dispatcher instances. We need to
59 * have one instance per thread group so that 2 or more applets or otherwise
60 * separated applications (like in OSGI) do not interfer with each other.
62 private static WeakHashMap instances = new WeakHashMap();
65 * The component that is the start of a mouse dragging. All MOUSE_DRAGGED
66 * events that follow the initial press must have the source set to this,
67 * as well as the MOUSE_RELEASED event following the dragging.
69 private Component dragTarget;
72 * The last mouse event target. If the target changes, additional
73 * MOUSE_ENTERED and MOUSE_EXITED events must be dispatched.
75 private Component lastTarget;
78 * Returns an instance of LightweightDispatcher for the current thread's
81 * @return an instance of LightweightDispatcher for the current thread's
84 static LightweightDispatcher getInstance()
86 Thread t = Thread.currentThread();
87 ThreadGroup tg = t.getThreadGroup();
88 LightweightDispatcher instance = (LightweightDispatcher) instances.get(tg);
91 instance = new LightweightDispatcher();
92 instances.put(tg, instance);
98 * Creates a new LightweightDispatcher. This is private to prevent access
99 * from outside. Use {@link #getInstance()} instead.
101 private LightweightDispatcher()
103 // Nothing to do here.
107 * Receives notification if a mouse event passes along the eventqueue.
109 * @param event the event
111 public boolean dispatchEvent(AWTEvent event)
113 if (event instanceof MouseEvent && event.getSource() instanceof Window)
115 MouseEvent mouseEvent = (MouseEvent) event;
116 return handleMouseEvent(mouseEvent);
122 * Handles all mouse events that are targetted at toplevel containers
123 * (Window instances) and dispatches them to the correct lightweight child.
125 * @param ev the mouse event
126 * @return whether or not we found a lightweight that handled the event.
128 private boolean handleMouseEvent(MouseEvent ev)
130 Window window = (Window) ev.getSource();
131 Component target = window.findComponentAt(ev.getX(), ev.getY());
132 target = findTarget(target);
133 if (target == null || target.isLightweight())
135 // Dispatch additional MOUSE_EXITED and MOUSE_ENTERED if event target
136 // is different from the last event target.
137 if (target != lastTarget)
139 if (lastTarget != null)
141 Point p1 = AWTUtilities.convertPoint(window, ev.getX(),
142 ev.getY(), lastTarget);
143 MouseEvent mouseExited =
144 new MouseEvent(lastTarget, MouseEvent.MOUSE_EXITED,
145 ev.getWhen(), ev.getModifiers(), p1.x, p1.y,
146 ev.getClickCount(), ev.isPopupTrigger());
147 lastTarget.dispatchEvent(mouseExited);
151 Point p = AWTUtilities.convertPoint(window, ev.getX(), ev.getY(),
153 MouseEvent mouseEntered =
154 new MouseEvent(target, MouseEvent.MOUSE_ENTERED, ev.getWhen(),
155 ev.getModifiers(), p.x, p.y, ev.getClickCount(),
156 ev.isPopupTrigger());
157 target.dispatchEvent(mouseEntered);
163 case MouseEvent.MOUSE_PRESSED:
166 case MouseEvent.MOUSE_RELEASED:
167 if (dragTarget != null)
171 case MouseEvent.MOUSE_CLICKED:
172 // When we receive a MOUSE_CLICKED, we set the target to the
173 // previous target, which must have been a MOUSE_RELEASED event.
174 // This is necessary for the case when the MOUSE_RELEASED has
175 // caused the original target (like an internal component) go
179 case MouseEvent.MOUSE_DRAGGED:
183 // Do nothing in other cases.
191 Point targetCoordinates =
192 AWTUtilities.convertPoint(window, ev.getX(), ev.getY(), target);
193 int dx = targetCoordinates.x - ev.getX();
194 int dy = targetCoordinates.y - ev.getY();
195 ev.translatePoint(dx, dy);
196 ev.setSource(target);
197 target.dispatchEvent(ev);
198 // We reset the event, so that the normal event dispatching is not
199 // influenced by this modified event.
200 ev.setSource(window);
201 ev.translatePoint(-dx, -dy);
211 * Finds the actual target for a mouseevent, starting at <code>c</code>.
212 * This searches upwards the component hierarchy until it finds a component
213 * that has a mouselistener attached.
215 * @param c the component to start searching from
217 * @return the actual receiver of the mouse event
219 private Component findTarget(Component c)
221 Component target = c;
222 while (target != null && target.getMouseListeners().length == 0)
224 target = target.getParent();