OpenCores
URL https://opencores.org/ocsvn/openrisc/openrisc/trunk

Subversion Repositories openrisc

[/] [openrisc/] [trunk/] [gnu-dev/] [or1k-gcc/] [libjava/] [classpath/] [java/] [awt/] [LightweightDispatcher.java] - Blame information for rev 771

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 771 jeremybenn
/* LightweightDispatcher.java -- Dispatches mouse events to lightweights
2
   Copyright (C) 2006 Free Software Foundation, Inc.
3
 
4
This file is part of GNU Classpath.
5
 
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)
9
any later version.
10
 
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.
15
 
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
19
02110-1301 USA.
20
 
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
24
combination.
25
 
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. */
37
 
38
 
39
package java.awt;
40
 
41
import java.awt.event.InputEvent;
42
import java.awt.event.MouseEvent;
43
import java.awt.event.MouseWheelEvent;
44
import java.awt.peer.LightweightPeer;
45
import java.util.WeakHashMap;
46
 
47
/**
48
 * Redispatches mouse events to lightweight components. The native peers know
49
 * nothing about the lightweight components and thus mouse events are always
50
 * targetted at Windows or heavyweight components. This class listenes directly
51
 * on the eventqueue and dispatches mouse events to lightweight components.
52
 *
53
 * @author Roman Kennke (kennke@aicas.com)
54
 */
55
final class LightweightDispatcher
56
{
57
 
58
  /**
59
   * Maps thread groups to lightweight dispatcher instances. We need to
60
   * have one instance per thread group so that 2 or more applets or otherwise
61
   * separated applications (like in OSGI) do not interfer with each other.
62
   */
63
  private static WeakHashMap instances = new WeakHashMap();
64
 
65
  /**
66
   * The last mouse event target. If the target changes, additional
67
   * MOUSE_ENTERED and MOUSE_EXITED events must be dispatched.
68
   */
69
  private Component lastTarget;
70
 
71
  /**
72
   * The current mouseEventTarget.
73
   */
74
  private Component mouseEventTarget;
75
 
76
  /**
77
   * Returns an instance of LightweightDispatcher for the current thread's
78
   * thread group.
79
   *
80
   * @return an instance of LightweightDispatcher for the current thread's
81
   *         thread group
82
   */
83
  static LightweightDispatcher getInstance()
84
  {
85
    Thread t = Thread.currentThread();
86
    ThreadGroup tg = t.getThreadGroup();
87
    LightweightDispatcher instance = (LightweightDispatcher) instances.get(tg);
88
    if (instance == null)
89
      {
90
        instance = new LightweightDispatcher();
91
        instances.put(tg, instance);
92
      }
93
    return instance;
94
  }
95
 
96
  /**
97
   * Creates a new LightweightDispatcher. This is private to prevent access
98
   * from outside. Use {@link #getInstance()} instead.
99
   */
100
  private LightweightDispatcher()
101
  {
102
    // Nothing to do here.
103
  }
104
 
105
  /**
106
   * Receives notification if a mouse event passes along the eventqueue.
107
   *
108
   * @param event the event
109
   */
110
  public boolean dispatchEvent(final AWTEvent event)
111
  {
112
    if (event instanceof MouseEvent)
113
      {
114
        MouseEvent mouseEvent = (MouseEvent) event;
115
        return handleMouseEvent(mouseEvent);
116
      }
117
    return false;
118
  }
119
 
120
  /**
121
   * Handles all mouse events that are targetted at toplevel containers
122
   * (Window instances) and dispatches them to the correct lightweight child.
123
   *
124
   * @param ev the mouse event
125
   * @return whether or not we found a lightweight that handled the event.
126
   */
127
  private boolean handleMouseEvent(final MouseEvent ev)
128
  {
129
    Container container = (Container) ev.getSource();
130
    Component target = findTarget(container, ev.getX(), ev.getY());
131
    trackEnterExit(target, ev);
132
    int id = ev.getID();
133
 
134
    // Dont update the mouseEventTarget when dragging. Also, MOUSE_CLICKED
135
    // must be dispatched to the original target of MOUSE_PRESSED, so don't
136
    // update in this case either.
137
    if (! isDragging(ev) && id != MouseEvent.MOUSE_CLICKED)
138
      mouseEventTarget = (target != container) ? target : null;
139
 
140
    if (mouseEventTarget != null)
141
      {
142
        switch (id)
143
          {
144
          case MouseEvent.MOUSE_ENTERED:
145
          case MouseEvent.MOUSE_EXITED:
146
            // This is already handled in trackEnterExit().
147
            break;
148
          case MouseEvent.MOUSE_PRESSED:
149
          case MouseEvent.MOUSE_RELEASED:
150
          case MouseEvent.MOUSE_MOVED:
151
            redispatch(ev, mouseEventTarget, id);
152
            break;
153
          case MouseEvent.MOUSE_CLICKED:
154
            // MOUSE_CLICKED must be dispatched to the original target of
155
            // MOUSE_PRESSED.
156
            if (target == mouseEventTarget)
157
              redispatch(ev, mouseEventTarget, id);
158
            break;
159
          case MouseEvent.MOUSE_DRAGGED:
160
            if (isDragging(ev))
161
              redispatch(ev, mouseEventTarget, id);
162
            break;
163
          case MouseEvent.MOUSE_WHEEL:
164
            redispatch(ev, mouseEventTarget, id);
165
          }
166
        ev.consume();
167
      }
168
 
169
    return ev.isConsumed();
170
  }
171
 
172
  /**
173
   * Finds the actual target for a mouseevent, starting at <code>c</code>.
174
   * This searches through the children of the container and finds the first
175
   * one which is showing, at the location from the mouse event and has
176
   * a MouseListener or MouseMotionListener attached. If no such child component
177
   * is found, null is returned.
178
   *
179
   * @param c the container to search through
180
   * @param loc the mouse event point
181
   *
182
   * @return the actual receiver of the mouse event, or null, if no such
183
   *         component has been found
184
   */
185
  private Component findTarget(final Container c, final int x, final int y)
186
  {
187
    Component target = null;
188
 
189
    // First we check the children of the container.
190
 
191
    // Note: It is important that we use the package private Container
192
    // fields ncomponents and component here. There are applications
193
    // that override getComponentCount()
194
    // and getComponent() to hide internal components, which makes
195
    // the LightweightDispatcher not work correctly in these cases.
196
    // As a positive sideeffect this is slightly more efficient.
197
    int nChildren = c.ncomponents;
198
    for (int i = 0; i < nChildren && target == null; i++)
199
      {
200
        Component child = c.component[i];
201
        int childX = x - child.x;
202
        int childY = y - child.y;
203
        if (child != null && child.visible
204
            && child.peer instanceof LightweightPeer
205
            && child.contains(childX, childY))
206
          {
207
            // Check if there's a deeper possible target.
208
            if (child instanceof Container)
209
              {
210
                Component deeper = findTarget((Container) child,
211
                                              childX, childY);
212
                if (deeper != null)
213
                  target = deeper;
214
              }
215
            // Check if the child itself is interested in mouse events.
216
            else if (isMouseListening(child))
217
              target = child;
218
          }
219
      }
220
 
221
    // Check the container itself, if we didn't find a target yet.
222
    if (target == null  && c.contains(x, y) && isMouseListening(c))
223
      target = c;
224
 
225
    return target;
226
  }
227
 
228
  /**
229
   * Checks if the specified component would be interested in a mouse event.
230
   *
231
   * @param c the component to check
232
   *
233
   * @return <code>true</code> if the component has mouse listeners installed,
234
   *         <code>false</code> otherwise
235
   */
236
  private boolean isMouseListening(final Component c)
237
  {
238
    // Note: It is important to NOT check if the component is listening
239
    // for a specific event (for instance, mouse motion events). The event
240
    // gets dispatched to the component if the component is listening
241
    // for ANY mouse event, even when the component is not listening for the
242
    // specific type of event. There are applications that depend on this
243
    // (sadly).
244
    return c.mouseListener != null
245
           || c.mouseMotionListener != null
246
           || c.mouseWheelListener != null
247
           || (c.eventMask & AWTEvent.MOUSE_EVENT_MASK) != 0
248
           || (c.eventMask & AWTEvent.MOUSE_MOTION_EVENT_MASK) != 0
249
           || (c.eventMask & AWTEvent.MOUSE_WHEEL_EVENT_MASK) != 0;
250
  }
251
 
252
  /**
253
   * Tracks MOUSE_ENTERED and MOUSE_EXIT as well as MOUSE_MOVED and
254
   * MOUSE_DRAGGED and creates synthetic MOUSE_ENTERED and MOUSE_EXITED for
255
   * lightweight component.s
256
   *
257
   * @param target the current mouse event target
258
   * @param ev the mouse event
259
   */
260
  private void trackEnterExit(final Component target, final MouseEvent ev)
261
  {
262
    int id = ev.getID();
263
    if (target != lastTarget)
264
      {
265
        if (lastTarget != null)
266
          redispatch(ev, lastTarget, MouseEvent.MOUSE_EXITED);
267
        if (id == MouseEvent.MOUSE_EXITED)
268
          ev.consume();
269
        if (target != null)
270
          redispatch(ev, target, MouseEvent.MOUSE_ENTERED);
271
        if (id == MouseEvent.MOUSE_ENTERED)
272
          ev.consume();
273
        lastTarget = target;
274
      }
275
 
276
  }
277
 
278
  /**
279
   * Redispatches the specified mouse event to the specified target with the
280
   * specified id.
281
   *
282
   * @param ev the mouse event
283
   * @param target the new target
284
   * @param id the new id
285
   */
286
  private void redispatch(MouseEvent ev, Component target, int id)
287
  {
288
    Component source = ev.getComponent();
289
    assert target != null;
290
    if (target.isShowing())
291
      {
292
        // Translate coordinates.
293
        int x = ev.getX();
294
        int y = ev.getY();
295
        for (Component c = target; c != null && c != source; c = c.getParent())
296
          {
297
            x -= c.x;
298
            y -= c.y;
299
          }
300
 
301
        // Retarget event.
302
        MouseEvent retargeted;
303
        if (id == MouseEvent.MOUSE_WHEEL)
304
          {
305
            MouseWheelEvent mwe = (MouseWheelEvent) ev;
306
            retargeted = new MouseWheelEvent(target, id, ev.getWhen(),
307
                                             ev.getModifiers()
308
                                             | ev.getModifiersEx(), x, y,
309
                                             ev.getClickCount(),
310
                                             ev.isPopupTrigger(),
311
                                             mwe.getScrollType(),
312
                                             mwe.getScrollAmount(),
313
                                             mwe.getWheelRotation());
314
          }
315
        else
316
          {
317
            retargeted = new MouseEvent(target, id, ev.getWhen(),
318
                                       ev.getModifiers() | ev.getModifiersEx(),
319
                                       x, y, ev.getClickCount(),
320
                                       ev.isPopupTrigger(), ev.getButton());
321
          }
322
 
323
        if (target == source)
324
          ((Container) target).dispatchNoLightweight(retargeted);
325
        else
326
          target.dispatchEvent(retargeted);
327
      }
328
  }
329
 
330
  /**
331
   * Determines if we are in the middle of a drag operation, that is, if
332
   * any of the buttons is held down.
333
   *
334
   * @param ev the mouse event to check
335
   *
336
   * @return <code>true</code> if we are in the middle of a drag operation,
337
   *         <code>false</code> otherwise
338
   */
339
  private boolean isDragging(MouseEvent ev)
340
  {
341
    int mods = ev.getModifiersEx();
342
    int id = ev.getID();
343
    if (id == MouseEvent.MOUSE_PRESSED || id == MouseEvent.MOUSE_RELEASED)
344
      {
345
        switch (ev.getButton())
346
          {
347
            case MouseEvent.BUTTON1:
348
              mods ^= InputEvent.BUTTON1_DOWN_MASK;
349
              break;
350
            case MouseEvent.BUTTON2:
351
              mods ^= InputEvent.BUTTON2_DOWN_MASK;
352
              break;
353
            case MouseEvent.BUTTON3:
354
              mods ^= InputEvent.BUTTON3_DOWN_MASK;
355
              break;
356
          }
357
      }
358
    return (mods & (InputEvent.BUTTON1_DOWN_MASK
359
                    | InputEvent.BUTTON2_DOWN_MASK
360
                    | InputEvent.BUTTON3_DOWN_MASK)) != 0;
361
  }
362
}

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.