1/*
2 * Copyright (c) 1996, 2013, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation.  Oracle designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Oracle in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
25
26package java.awt.event;
27
28import java.awt.Component;
29import java.awt.GraphicsEnvironment;
30import java.awt.Point;
31import java.awt.Toolkit;
32import java.io.IOException;
33import java.io.ObjectInputStream;
34import java.awt.IllegalComponentStateException;
35import java.awt.MouseInfo;
36import sun.awt.SunToolkit;
37
38/**
39 * An event which indicates that a mouse action occurred in a component.
40 * A mouse action is considered to occur in a particular component if and only
41 * if the mouse cursor is over the unobscured part of the component's bounds
42 * when the action happens.
43 * For lightweight components, such as Swing's components, mouse events
44 * are only dispatched to the component if the mouse event type has been
45 * enabled on the component. A mouse event type is enabled by adding the
46 * appropriate mouse-based {@code EventListener} to the component
47 * ({@link MouseListener} or {@link MouseMotionListener}), or by invoking
48 * {@link Component#enableEvents(long)} with the appropriate mask parameter
49 * ({@code AWTEvent.MOUSE_EVENT_MASK} or {@code AWTEvent.MOUSE_MOTION_EVENT_MASK}).
50 * If the mouse event type has not been enabled on the component, the
51 * corresponding mouse events are dispatched to the first ancestor that
52 * has enabled the mouse event type.
53 *<p>
54 * For example, if a {@code MouseListener} has been added to a component, or
55 * {@code enableEvents(AWTEvent.MOUSE_EVENT_MASK)} has been invoked, then all
56 * the events defined by {@code MouseListener} are dispatched to the component.
57 * On the other hand, if a {@code MouseMotionListener} has not been added and
58 * {@code enableEvents} has not been invoked with
59 * {@code AWTEvent.MOUSE_MOTION_EVENT_MASK}, then mouse motion events are not
60 * dispatched to the component. Instead the mouse motion events are
61 * dispatched to the first ancestors that has enabled mouse motion
62 * events.
63 * <P>
64 * This low-level event is generated by a component object for:
65 * <ul>
66 * <li>Mouse Events
67 *     <ul>
68 *     <li>a mouse button is pressed
69 *     <li>a mouse button is released
70 *     <li>a mouse button is clicked (pressed and released)
71 *     <li>the mouse cursor enters the unobscured part of component's geometry
72 *     <li>the mouse cursor exits the unobscured part of component's geometry
73 *     </ul>
74 * <li> Mouse Motion Events
75 *     <ul>
76 *     <li>the mouse is moved
77 *     <li>the mouse is dragged
78 *     </ul>
79 * </ul>
80 * <P>
81 * A {@code MouseEvent} object is passed to every
82 * {@code MouseListener}
83 * or {@code MouseAdapter} object which is registered to receive
84 * the "interesting" mouse events using the component's
85 * {@code addMouseListener} method.
86 * ({@code MouseAdapter} objects implement the
87 * {@code MouseListener} interface.) Each such listener object
88 * gets a {@code MouseEvent} containing the mouse event.
89 * <P>
90 * A {@code MouseEvent} object is also passed to every
91 * {@code MouseMotionListener} or
92 * {@code MouseMotionAdapter} object which is registered to receive
93 * mouse motion events using the component's
94 * {@code addMouseMotionListener}
95 * method. ({@code MouseMotionAdapter} objects implement the
96 * {@code MouseMotionListener} interface.) Each such listener object
97 * gets a {@code MouseEvent} containing the mouse motion event.
98 * <P>
99 * When a mouse button is clicked, events are generated and sent to the
100 * registered {@code MouseListener}s.
101 * The state of modal keys can be retrieved using {@link InputEvent#getModifiers}
102 * and {@link InputEvent#getModifiersEx}.
103 * The button mask returned by {@link InputEvent#getModifiers} reflects
104 * only the button that changed state, not the current state of all buttons.
105 * (Note: Due to overlap in the values of ALT_MASK/BUTTON2_MASK and
106 * META_MASK/BUTTON3_MASK, this is not always true for mouse events involving
107 * modifier keys).
108 * To get the state of all buttons and modifier keys, use
109 * {@link InputEvent#getModifiersEx}.
110 * The button which has changed state is returned by {@link MouseEvent#getButton}
111 * <P>
112 * For example, if the first mouse button is pressed, events are sent in the
113 * following order:
114 * <pre><b>
115 *    id              modifiers    button</b>{@code
116 *    MOUSE_PRESSED:  BUTTON1_MASK BUTTON1
117 *    MOUSE_RELEASED: BUTTON1_MASK BUTTON1
118 *    MOUSE_CLICKED:  BUTTON1_MASK BUTTON1
119 * }</pre>
120 * When multiple mouse buttons are pressed, each press, release, and click
121 * results in a separate event.
122 * <P>
123 * For example, if the user presses <b>button 1</b> followed by
124 * <b>button 2</b>, and then releases them in the same order,
125 * the following sequence of events is generated:
126 * <pre><b>
127 *    id              modifiers    button</b>{@code
128 *    MOUSE_PRESSED:  BUTTON1_MASK BUTTON1
129 *    MOUSE_PRESSED:  BUTTON2_MASK BUTTON2
130 *    MOUSE_RELEASED: BUTTON1_MASK BUTTON1
131 *    MOUSE_CLICKED:  BUTTON1_MASK BUTTON1
132 *    MOUSE_RELEASED: BUTTON2_MASK BUTTON2
133 *    MOUSE_CLICKED:  BUTTON2_MASK BUTTON2
134 * }</pre>
135 * If <b>button 2</b> is released first, the
136 * {@code MOUSE_RELEASED}/{@code MOUSE_CLICKED} pair
137 * for {@code BUTTON2_MASK} arrives first,
138 * followed by the pair for {@code BUTTON1_MASK}.
139 * <p>
140 * Some extra mouse buttons are added to extend the standard set of buttons
141 * represented by the following constants:{@code BUTTON1}, {@code BUTTON2}, and {@code BUTTON3}.
142 * Extra buttons have no assigned {@code BUTTONx}
143 * constants as well as their button masks have no assigned {@code BUTTONx_DOWN_MASK}
144 * constants. Nevertheless, ordinal numbers starting from 4 may be
145 * used as button numbers (button ids). Values obtained by the
146 * {@link InputEvent#getMaskForButton(int) getMaskForButton(button)} method may be used
147 * as button masks.
148 * <p>
149 * {@code MOUSE_DRAGGED} events are delivered to the {@code Component}
150 * in which the mouse button was pressed until the mouse button is released
151 * (regardless of whether the mouse position is within the bounds of the
152 * {@code Component}).  Due to platform-dependent Drag&amp;Drop implementations,
153 * {@code MOUSE_DRAGGED} events may not be delivered during a native
154 * Drag&amp;Drop operation.
155 *
156 * In a multi-screen environment mouse drag events are delivered to the
157 * {@code Component} even if the mouse position is outside the bounds of the
158 * {@code GraphicsConfiguration} associated with that
159 * {@code Component}. However, the reported position for mouse drag events
160 * in this case may differ from the actual mouse position:
161 * <ul>
162 * <li>In a multi-screen environment without a virtual device:
163 * <br>
164 * The reported coordinates for mouse drag events are clipped to fit within the
165 * bounds of the {@code GraphicsConfiguration} associated with
166 * the {@code Component}.
167 * <li>In a multi-screen environment with a virtual device:
168 * <br>
169 * The reported coordinates for mouse drag events are clipped to fit within the
170 * bounds of the virtual device associated with the {@code Component}.
171 * </ul>
172 * <p>
173 * An unspecified behavior will be caused if the {@code id} parameter
174 * of any particular {@code MouseEvent} instance is not
175 * in the range from {@code MOUSE_FIRST} to {@code MOUSE_LAST}-1
176 * ({@code MOUSE_WHEEL} is not acceptable).
177 *
178 * @author Carl Quinn
179 *
180 * @see MouseAdapter
181 * @see MouseListener
182 * @see MouseMotionAdapter
183 * @see MouseMotionListener
184 * @see MouseWheelListener
185 * @see <a href="http://docs.oracle.com/javase/tutorial/uiswing/events/mouselistener.html">Tutorial: Writing a Mouse Listener</a>
186 * @see <a href="http://docs.oracle.com/javase/tutorial/uiswing/events/mousemotionlistener.html">Tutorial: Writing a Mouse Motion Listener</a>
187 *
188 * @since 1.1
189 */
190public class MouseEvent extends InputEvent {
191
192    /**
193     * The first number in the range of ids used for mouse events.
194     */
195    public static final int MOUSE_FIRST         = 500;
196
197    /**
198     * The last number in the range of ids used for mouse events.
199     */
200    public static final int MOUSE_LAST          = 507;
201
202    /**
203     * The "mouse clicked" event. This {@code MouseEvent}
204     * occurs when a mouse button is pressed and released.
205     */
206    public static final int MOUSE_CLICKED = MOUSE_FIRST;
207
208    /**
209     * The "mouse pressed" event. This {@code MouseEvent}
210     * occurs when a mouse button is pushed down.
211     */
212    public static final int MOUSE_PRESSED = 1 + MOUSE_FIRST; //Event.MOUSE_DOWN
213
214    /**
215     * The "mouse released" event. This {@code MouseEvent}
216     * occurs when a mouse button is let up.
217     */
218    public static final int MOUSE_RELEASED = 2 + MOUSE_FIRST; //Event.MOUSE_UP
219
220    /**
221     * The "mouse moved" event. This {@code MouseEvent}
222     * occurs when the mouse position changes.
223     */
224    public static final int MOUSE_MOVED = 3 + MOUSE_FIRST; //Event.MOUSE_MOVE
225
226    /**
227     * The "mouse entered" event. This {@code MouseEvent}
228     * occurs when the mouse cursor enters the unobscured part of component's
229     * geometry.
230     */
231    public static final int MOUSE_ENTERED = 4 + MOUSE_FIRST; //Event.MOUSE_ENTER
232
233    /**
234     * The "mouse exited" event. This {@code MouseEvent}
235     * occurs when the mouse cursor exits the unobscured part of component's
236     * geometry.
237     */
238    public static final int MOUSE_EXITED = 5 + MOUSE_FIRST; //Event.MOUSE_EXIT
239
240    /**
241     * The "mouse dragged" event. This {@code MouseEvent}
242     * occurs when the mouse position changes while a mouse button is pressed.
243     */
244    public static final int MOUSE_DRAGGED = 6 + MOUSE_FIRST; //Event.MOUSE_DRAG
245
246    /**
247     * The "mouse wheel" event.  This is the only {@code MouseWheelEvent}.
248     * It occurs when a mouse equipped with a wheel has its wheel rotated.
249     * @since 1.4
250     */
251    public static final int MOUSE_WHEEL = 7 + MOUSE_FIRST;
252
253    /**
254     * Indicates no mouse buttons; used by {@link #getButton}.
255     * @since 1.4
256     */
257    public static final int NOBUTTON = 0;
258
259    /**
260     * Indicates mouse button #1; used by {@link #getButton}.
261     * @since 1.4
262     */
263    public static final int BUTTON1 = 1;
264
265    /**
266     * Indicates mouse button #2; used by {@link #getButton}.
267     * @since 1.4
268     */
269    public static final int BUTTON2 = 2;
270
271    /**
272     * Indicates mouse button #3; used by {@link #getButton}.
273     * @since 1.4
274     */
275    public static final int BUTTON3 = 3;
276
277    /**
278     * The mouse event's x coordinate.
279     * The x value is relative to the component that fired the event.
280     *
281     * @serial
282     * @see #getX()
283     */
284    int x;
285
286    /**
287     * The mouse event's y coordinate.
288     * The y value is relative to the component that fired the event.
289     *
290     * @serial
291     * @see #getY()
292     */
293    int y;
294
295    /**
296     * The mouse event's x absolute coordinate.
297     * In a virtual device multi-screen environment in which the
298     * desktop area could span multiple physical screen devices,
299     * this coordinate is relative to the virtual coordinate system.
300     * Otherwise, this coordinate is relative to the coordinate system
301     * associated with the Component's GraphicsConfiguration.
302     *
303     * @serial
304   */
305    private int xAbs;
306
307    /**
308     * The mouse event's y absolute coordinate.
309     * In a virtual device multi-screen environment in which the
310     * desktop area could span multiple physical screen devices,
311     * this coordinate is relative to the virtual coordinate system.
312     * Otherwise, this coordinate is relative to the coordinate system
313     * associated with the Component's GraphicsConfiguration.
314     *
315     * @serial
316     */
317    private int yAbs;
318
319    /**
320     * Indicates the number of quick consecutive clicks of
321     * a mouse button.
322     * clickCount will be valid for only three mouse events :<BR>
323     * {@code MOUSE_CLICKED},
324     * {@code MOUSE_PRESSED} and
325     * {@code MOUSE_RELEASED}.
326     * For the above, the {@code clickCount} will be at least 1.
327     * For all other events the count will be 0.
328     *
329     * @serial
330     * @see #getClickCount()
331     */
332    int clickCount;
333
334    /**
335     * Indicates which, if any, of the mouse buttons has changed state.
336     *
337     * The valid values are ranged from 0 to the value returned by the
338     * {@link java.awt.MouseInfo#getNumberOfButtons() MouseInfo.getNumberOfButtons()} method.
339     * This range already includes constants {@code NOBUTTON}, {@code BUTTON1},
340     * {@code BUTTON2}, and {@code BUTTON3}
341     * if these buttons are present. So it is allowed to use these constants too.
342     * For example, for a mouse with two buttons this field may contain the following values:
343     * <ul>
344     * <li> 0 ({@code NOBUTTON})
345     * <li> 1 ({@code BUTTON1})
346     * <li> 2 ({@code BUTTON2})
347     * </ul>
348     * If a mouse has 5 buttons, this field may contain the following values:
349     * <ul>
350     * <li> 0 ({@code NOBUTTON})
351     * <li> 1 ({@code BUTTON1})
352     * <li> 2 ({@code BUTTON2})
353     * <li> 3 ({@code BUTTON3})
354     * <li> 4
355     * <li> 5
356     * </ul>
357     * If support for extended mouse buttons is {@link Toolkit#areExtraMouseButtonsEnabled()} disabled by Java
358     * then the field may not contain the value larger than {@code BUTTON3}.
359     * @serial
360     * @see #getButton()
361     * @see java.awt.Toolkit#areExtraMouseButtonsEnabled()
362     */
363    int button;
364
365    /**
366     * A property used to indicate whether a Popup Menu
367     * should appear  with a certain gestures.
368     * If {@code popupTrigger} = {@code false},
369     * no popup menu should appear.  If it is {@code true}
370     * then a popup menu should appear.
371     *
372     * @serial
373     * @see java.awt.PopupMenu
374     * @see #isPopupTrigger()
375     */
376    boolean popupTrigger = false;
377
378    /*
379     * JDK 1.1 serialVersionUID
380     */
381    private static final long serialVersionUID = -991214153494842848L;
382
383    /**
384     * A number of buttons available on the mouse at the {@code Toolkit} machinery startup.
385     */
386    private static int cachedNumberOfButtons;
387
388    static {
389        /* ensure that the necessary native libraries are loaded */
390        NativeLibLoader.loadLibraries();
391        if (!GraphicsEnvironment.isHeadless()) {
392            initIDs();
393        }
394        final Toolkit tk = Toolkit.getDefaultToolkit();
395        if (tk instanceof SunToolkit) {
396            cachedNumberOfButtons = ((SunToolkit)tk).getNumberOfButtons();
397        } else {
398            //It's expected that some toolkits (Headless,
399            //whatever besides SunToolkit) could also operate.
400            cachedNumberOfButtons = 3;
401        }
402    }
403
404    /**
405     * Initialize JNI field and method IDs for fields that may be
406     *  accessed from C.
407     */
408    private static native void initIDs();
409
410    /**
411     * Returns the absolute x, y position of the event.
412     * In a virtual device multi-screen environment in which the
413     * desktop area could span multiple physical screen devices,
414     * these coordinates are relative to the virtual coordinate system.
415     * Otherwise, these coordinates are relative to the coordinate system
416     * associated with the Component's GraphicsConfiguration.
417     *
418     * @return a {@code Point} object containing the absolute  x
419     *  and y coordinates.
420     *
421     * @see java.awt.GraphicsConfiguration
422     * @since 1.6
423     */
424    public Point getLocationOnScreen(){
425      return new Point(xAbs, yAbs);
426    }
427
428    /**
429     * Returns the absolute horizontal x position of the event.
430     * In a virtual device multi-screen environment in which the
431     * desktop area could span multiple physical screen devices,
432     * this coordinate is relative to the virtual coordinate system.
433     * Otherwise, this coordinate is relative to the coordinate system
434     * associated with the Component's GraphicsConfiguration.
435     *
436     * @return x  an integer indicating absolute horizontal position.
437     *
438     * @see java.awt.GraphicsConfiguration
439     * @since 1.6
440     */
441    public int getXOnScreen() {
442        return xAbs;
443    }
444
445    /**
446     * Returns the absolute vertical y position of the event.
447     * In a virtual device multi-screen environment in which the
448     * desktop area could span multiple physical screen devices,
449     * this coordinate is relative to the virtual coordinate system.
450     * Otherwise, this coordinate is relative to the coordinate system
451     * associated with the Component's GraphicsConfiguration.
452     *
453     * @return y  an integer indicating absolute vertical position.
454     *
455     * @see java.awt.GraphicsConfiguration
456     * @since 1.6
457     */
458    public int getYOnScreen() {
459        return yAbs;
460    }
461
462    /**
463     * Constructs a {@code MouseEvent} object with the
464     * specified source component,
465     * type, time, modifiers, coordinates, click count, popupTrigger flag,
466     * and button number.
467     * <p>
468     * Creating an invalid event (such
469     * as by using more than one of the old _MASKs, or modifier/button
470     * values which don't match) results in unspecified behavior.
471     * An invocation of the form
472     * {@code MouseEvent(source, id, when, modifiers, x, y, clickCount, popupTrigger, button)}
473     * behaves in exactly the same way as the invocation
474     * {@link #MouseEvent(Component, int, long, int, int, int,
475     * int, int, int, boolean, int) MouseEvent(source, id, when, modifiers,
476     * x, y, xAbs, yAbs, clickCount, popupTrigger, button)}
477     * where xAbs and yAbs defines as source's location on screen plus
478     * relative coordinates x and y.
479     * xAbs and yAbs are set to zero if the source is not showing.
480     * This method throws an
481     * {@code IllegalArgumentException} if {@code source}
482     * is {@code null}.
483     *
484     * @param source       The {@code Component} that originated the event
485     * @param id              An integer indicating the type of event.
486     *                     For information on allowable values, see
487     *                     the class description for {@link MouseEvent}
488     * @param when         A long integer that gives the time the event occurred.
489     *                     Passing negative or zero value
490     *                     is not recommended
491     * @param modifiers    a modifier mask describing the modifier keys and mouse
492     *                     buttons (for example, shift, ctrl, alt, and meta) that
493     *                     are down during the event.
494     *                     Only extended modifiers are allowed to be used as a
495     *                     value for this parameter (see the {@link InputEvent#getModifiersEx}
496     *                     class for the description of extended modifiers).
497     *                     Passing negative parameter
498     *                     is not recommended.
499     *                     Zero value means that no modifiers were passed
500     * @param x            The horizontal x coordinate for the mouse location.
501     *                       It is allowed to pass negative values
502     * @param y            The vertical y coordinate for the mouse location.
503     *                       It is allowed to pass negative values
504     * @param clickCount   The number of mouse clicks associated with event.
505     *                       Passing negative value
506     *                       is not recommended
507     * @param popupTrigger A boolean that equals {@code true} if this event
508     *                     is a trigger for a popup menu
509     * @param button       An integer that indicates, which of the mouse buttons has
510     *                     changed its state.
511     * The following rules are applied to this parameter:
512     * <ul>
513     * <li>If support for the extended mouse buttons is
514     * {@link Toolkit#areExtraMouseButtonsEnabled() disabled} by Java
515     * then it is allowed to create {@code MouseEvent} objects only with the standard buttons:
516     * {@code NOBUTTON}, {@code BUTTON1}, {@code BUTTON2}, and
517     * {@code BUTTON3}.
518     * <li> If support for the extended mouse buttons is
519     * {@link Toolkit#areExtraMouseButtonsEnabled() enabled} by Java
520     * then it is allowed to create {@code MouseEvent} objects with
521     * the standard buttons.
522     * In case the support for extended mouse buttons is
523     * {@link Toolkit#areExtraMouseButtonsEnabled() enabled} by Java, then
524     * in addition to the standard buttons, {@code MouseEvent} objects can be created
525     * using buttons from the range starting from 4 to
526     * {@link java.awt.MouseInfo#getNumberOfButtons() MouseInfo.getNumberOfButtons()}
527     * if the mouse has more than three buttons.
528     * </ul>
529     * @throws IllegalArgumentException if {@code button} is less than zero
530     * @throws IllegalArgumentException if {@code source} is null
531     * @throws IllegalArgumentException if {@code button} is greater than BUTTON3
532     *                                  and the support for extended mouse buttons is
533     *                                  {@link Toolkit#areExtraMouseButtonsEnabled() disabled} by Java
534     * @throws IllegalArgumentException if {@code button} is greater than the
535     *                                  {@link java.awt.MouseInfo#getNumberOfButtons() current number of buttons}
536     *                                  and the support for extended mouse buttons is
537     *                                  {@link Toolkit#areExtraMouseButtonsEnabled() enabled}
538     *                                  by Java
539     * @throws IllegalArgumentException if an invalid {@code button}
540     *            value is passed in
541     * @throws IllegalArgumentException if {@code source} is null
542     * @see #getSource()
543     * @see #getID()
544     * @see #getWhen()
545     * @see #getModifiers()
546     * @see #getX()
547     * @see #getY()
548     * @see #getClickCount()
549     * @see #isPopupTrigger()
550     * @see #getButton()
551     * @since 1.4
552     */
553    public MouseEvent(Component source, int id, long when, int modifiers,
554                      int x, int y, int clickCount, boolean popupTrigger,
555                      int button)
556    {
557        this(source, id, when, modifiers, x, y, 0, 0, clickCount, popupTrigger, button);
558        Point eventLocationOnScreen = new Point(0, 0);
559        try {
560          eventLocationOnScreen = source.getLocationOnScreen();
561          this.xAbs = eventLocationOnScreen.x + x;
562          this.yAbs = eventLocationOnScreen.y + y;
563        } catch (IllegalComponentStateException e){
564          this.xAbs = 0;
565          this.yAbs = 0;
566        }
567    }
568
569    /**
570     * Constructs a {@code MouseEvent} object with the
571     * specified source component,
572     * type, modifiers, coordinates, click count, and popupTrigger flag.
573     * An invocation of the form
574     * {@code MouseEvent(source, id, when, modifiers, x, y, clickCount, popupTrigger)}
575     * behaves in exactly the same way as the invocation
576     * {@link #MouseEvent(Component, int, long, int, int, int,
577     * int, int, int, boolean, int) MouseEvent(source, id, when, modifiers,
578     * x, y, xAbs, yAbs, clickCount, popupTrigger, MouseEvent.NOBUTTON)}
579     * where xAbs and yAbs defines as source's location on screen plus
580     * relative coordinates x and y.
581     * xAbs and yAbs are set to zero if the source is not showing.
582     * This method throws an {@code IllegalArgumentException}
583     * if {@code source} is {@code null}.
584     *
585     * @param source       The {@code Component} that originated the event
586     * @param id              An integer indicating the type of event.
587     *                     For information on allowable values, see
588     *                     the class description for {@link MouseEvent}
589     * @param when         A long integer that gives the time the event occurred.
590     *                     Passing negative or zero value
591     *                     is not recommended
592     * @param modifiers    a modifier mask describing the modifier keys and mouse
593     *                     buttons (for example, shift, ctrl, alt, and meta) that
594     *                     are down during the event.
595     *                     Only extended modifiers are allowed to be used as a
596     *                     value for this parameter (see the {@link InputEvent#getModifiersEx}
597     *                     class for the description of extended modifiers).
598     *                     Passing negative parameter
599     *                     is not recommended.
600     *                     Zero value means that no modifiers were passed
601     * @param x            The horizontal x coordinate for the mouse location.
602     *                       It is allowed to pass negative values
603     * @param y            The vertical y coordinate for the mouse location.
604     *                       It is allowed to pass negative values
605     * @param clickCount   The number of mouse clicks associated with event.
606     *                       Passing negative value
607     *                       is not recommended
608     * @param popupTrigger A boolean that equals {@code true} if this event
609     *                     is a trigger for a popup menu
610     * @throws IllegalArgumentException if {@code source} is null
611     * @see #getSource()
612     * @see #getID()
613     * @see #getWhen()
614     * @see #getModifiers()
615     * @see #getX()
616     * @see #getY()
617     * @see #getClickCount()
618     * @see #isPopupTrigger()
619     */
620     public MouseEvent(Component source, int id, long when, int modifiers,
621                      int x, int y, int clickCount, boolean popupTrigger) {
622        this(source, id, when, modifiers, x, y, clickCount, popupTrigger, NOBUTTON);
623     }
624
625
626    /* if the button is an extra button and it is released or clicked then in Xsystem its state
627       is not modified. Exclude this button number from ExtModifiers mask.*/
628    private transient boolean shouldExcludeButtonFromExtModifiers = false;
629
630    /**
631     * {@inheritDoc}
632     */
633    public int getModifiersEx() {
634        int tmpModifiers = modifiers;
635        if (shouldExcludeButtonFromExtModifiers) {
636            tmpModifiers &= ~(InputEvent.getMaskForButton(getButton()));
637        }
638        return tmpModifiers & ~JDK_1_3_MODIFIERS;
639    }
640
641    /**
642     * Constructs a {@code MouseEvent} object with the
643     * specified source component,
644     * type, time, modifiers, coordinates, absolute coordinates, click count, popupTrigger flag,
645     * and button number.
646     * <p>
647     * Creating an invalid event (such
648     * as by using more than one of the old _MASKs, or modifier/button
649     * values which don't match) results in unspecified behavior.
650     * Even if inconsistent values for relative and absolute coordinates are
651     * passed to the constructor, the mouse event instance is still
652     * created and no exception is thrown.
653     * This method throws an
654     * {@code IllegalArgumentException} if {@code source}
655     * is {@code null}.
656     *
657     * @param source       The {@code Component} that originated the event
658     * @param id              An integer indicating the type of event.
659     *                     For information on allowable values, see
660     *                     the class description for {@link MouseEvent}
661     * @param when         A long integer that gives the time the event occurred.
662     *                     Passing negative or zero value
663     *                     is not recommended
664     * @param modifiers    a modifier mask describing the modifier keys and mouse
665     *                     buttons (for example, shift, ctrl, alt, and meta) that
666     *                     are down during the event.
667     *                     Only extended modifiers are allowed to be used as a
668     *                     value for this parameter (see the {@link InputEvent#getModifiersEx}
669     *                     class for the description of extended modifiers).
670     *                     Passing negative parameter
671     *                     is not recommended.
672     *                     Zero value means that no modifiers were passed
673     * @param x            The horizontal x coordinate for the mouse location.
674     *                       It is allowed to pass negative values
675     * @param y            The vertical y coordinate for the mouse location.
676     *                       It is allowed to pass negative values
677     * @param xAbs           The absolute horizontal x coordinate for the mouse location
678     *                       It is allowed to pass negative values
679     * @param yAbs           The absolute vertical y coordinate for the mouse location
680     *                       It is allowed to pass negative values
681     * @param clickCount   The number of mouse clicks associated with event.
682     *                       Passing negative value
683     *                       is not recommended
684     * @param popupTrigger A boolean that equals {@code true} if this event
685     *                     is a trigger for a popup menu
686     * @param button       An integer that indicates, which of the mouse buttons has
687     *                     changed its state.
688     * The following rules are applied to this parameter:
689     * <ul>
690     * <li>If support for the extended mouse buttons is
691     * {@link Toolkit#areExtraMouseButtonsEnabled() disabled} by Java
692     * then it is allowed to create {@code MouseEvent} objects only with the standard buttons:
693     * {@code NOBUTTON}, {@code BUTTON1}, {@code BUTTON2}, and
694     * {@code BUTTON3}.
695     * <li> If support for the extended mouse buttons is
696     * {@link Toolkit#areExtraMouseButtonsEnabled() enabled} by Java
697     * then it is allowed to create {@code MouseEvent} objects with
698     * the standard buttons.
699     * In case the support for extended mouse buttons is
700     * {@link Toolkit#areExtraMouseButtonsEnabled() enabled} by Java, then
701     * in addition to the standard buttons, {@code MouseEvent} objects can be created
702     * using buttons from the range starting from 4 to
703     * {@link java.awt.MouseInfo#getNumberOfButtons() MouseInfo.getNumberOfButtons()}
704     * if the mouse has more than three buttons.
705     * </ul>
706     * @throws IllegalArgumentException if {@code button} is less than zero
707     * @throws IllegalArgumentException if {@code source} is null
708     * @throws IllegalArgumentException if {@code button} is greater than BUTTON3
709     *                                  and the support for extended mouse buttons is
710     *                                  {@link Toolkit#areExtraMouseButtonsEnabled() disabled} by Java
711     * @throws IllegalArgumentException if {@code button} is greater than the
712     *                                  {@link java.awt.MouseInfo#getNumberOfButtons()
713     *                                  current number of buttons} and the support
714     *                                  for extended mouse buttons is {@link Toolkit#areExtraMouseButtonsEnabled() enabled}
715     *                                  by Java
716     * @throws IllegalArgumentException if an invalid {@code button}
717     *            value is passed in
718     * @throws IllegalArgumentException if {@code source} is null
719     * @see #getSource()
720     * @see #getID()
721     * @see #getWhen()
722     * @see #getModifiers()
723     * @see #getX()
724     * @see #getY()
725     * @see #getXOnScreen()
726     * @see #getYOnScreen()
727     * @see #getClickCount()
728     * @see #isPopupTrigger()
729     * @see #getButton()
730     * @see #button
731     * @see Toolkit#areExtraMouseButtonsEnabled()
732     * @see java.awt.MouseInfo#getNumberOfButtons()
733     * @see InputEvent#getMaskForButton(int)
734     * @since 1.6
735     */
736    @SuppressWarnings("deprecation")
737    public MouseEvent(Component source, int id, long when, int modifiers,
738                      int x, int y, int xAbs, int yAbs,
739                      int clickCount, boolean popupTrigger, int button)
740    {
741        super(source, id, when, modifiers);
742        this.x = x;
743        this.y = y;
744        this.xAbs = xAbs;
745        this.yAbs = yAbs;
746        this.clickCount = clickCount;
747        this.popupTrigger = popupTrigger;
748        if (button < NOBUTTON){
749            throw new IllegalArgumentException("Invalid button value :" + button);
750        }
751        if (button > BUTTON3) {
752            if (!Toolkit.getDefaultToolkit().areExtraMouseButtonsEnabled()){
753                throw new IllegalArgumentException("Extra mouse events are disabled " + button);
754            } else {
755                if (button > cachedNumberOfButtons) {
756                    throw new IllegalArgumentException("Nonexistent button " + button);
757                }
758            }
759            // XToolkit: extra buttons are not reporting about their state correctly.
760            // Being pressed they report the state=0 both on the press and on the release.
761            // For 1-3 buttons the state value equals zero on press and non-zero on release.
762            // Other modifiers like Shift, ALT etc seem report well with extra buttons.
763            // The problem reveals as follows: one button is pressed and then another button is pressed and released.
764            // So, the getModifiersEx() would not be zero due to a first button and we will skip this modifier.
765            // This may have to be moved into the peer code instead if possible.
766
767            if (getModifiersEx() != 0) { //There is at least one more button in a pressed state.
768                if (id == MouseEvent.MOUSE_RELEASED || id == MouseEvent.MOUSE_CLICKED){
769                    shouldExcludeButtonFromExtModifiers = true;
770                }
771            }
772        }
773
774        this.button = button;
775
776        if ((getModifiers() != 0) && (getModifiersEx() == 0)) {
777            setNewModifiers();
778        } else if ((getModifiers() == 0) &&
779                   (getModifiersEx() != 0 || button != NOBUTTON) &&
780                   (button <= BUTTON3))
781        {
782            setOldModifiers();
783        }
784    }
785
786    /**
787     * Returns the horizontal x position of the event relative to the
788     * source component.
789     *
790     * @return x  an integer indicating horizontal position relative to
791     *            the component
792     */
793    public int getX() {
794        return x;
795    }
796
797    /**
798     * Returns the vertical y position of the event relative to the
799     * source component.
800     *
801     * @return y  an integer indicating vertical position relative to
802     *            the component
803     */
804    public int getY() {
805        return y;
806    }
807
808    /**
809     * Returns the x,y position of the event relative to the source component.
810     *
811     * @return a {@code Point} object containing the x and y coordinates
812     *         relative to the source component
813     *
814     */
815    public Point getPoint() {
816        int x;
817        int y;
818        synchronized (this) {
819            x = this.x;
820            y = this.y;
821        }
822        return new Point(x, y);
823    }
824
825    /**
826     * Translates the event's coordinates to a new position
827     * by adding specified {@code x} (horizontal) and {@code y}
828     * (vertical) offsets.
829     *
830     * @param x the horizontal x value to add to the current x
831     *          coordinate position
832     * @param y the vertical y value to add to the current y
833                coordinate position
834     */
835    public synchronized void translatePoint(int x, int y) {
836        this.x += x;
837        this.y += y;
838    }
839
840    /**
841     * Returns the number of mouse clicks associated with this event.
842     *
843     * @return integer value for the number of clicks
844     */
845    public int getClickCount() {
846        return clickCount;
847    }
848
849    /**
850     * Returns which, if any, of the mouse buttons has changed state.
851     * The returned value is ranged
852     * from 0 to the {@link java.awt.MouseInfo#getNumberOfButtons() MouseInfo.getNumberOfButtons()}
853     * value.
854     * The returned value includes at least the following constants:
855     * <ul>
856     * <li> {@code NOBUTTON}
857     * <li> {@code BUTTON1}
858     * <li> {@code BUTTON2}
859     * <li> {@code BUTTON3}
860     * </ul>
861     * It is allowed to use those constants to compare with the returned button number in the application.
862     * For example,
863     * <pre>
864     * if (anEvent.getButton() == MouseEvent.BUTTON1) {
865     * </pre>
866     * In particular, for a mouse with one, two, or three buttons this method may return the following values:
867     * <ul>
868     * <li> 0 ({@code NOBUTTON})
869     * <li> 1 ({@code BUTTON1})
870     * <li> 2 ({@code BUTTON2})
871     * <li> 3 ({@code BUTTON3})
872     * </ul>
873     * Button numbers greater than {@code BUTTON3} have no constant identifier.
874     * So if a mouse with five buttons is
875     * installed, this method may return the following values:
876     * <ul>
877     * <li> 0 ({@code NOBUTTON})
878     * <li> 1 ({@code BUTTON1})
879     * <li> 2 ({@code BUTTON2})
880     * <li> 3 ({@code BUTTON3})
881     * <li> 4
882     * <li> 5
883     * </ul>
884     * <p>
885     * Note: If support for extended mouse buttons is {@link Toolkit#areExtraMouseButtonsEnabled() disabled} by Java
886     * then the AWT event subsystem does not produce mouse events for the extended mouse
887     * buttons. So it is not expected that this method returns anything except {@code NOBUTTON}, {@code BUTTON1},
888     * {@code BUTTON2}, {@code BUTTON3}.
889     *
890     * @return one of the values from 0 to {@link java.awt.MouseInfo#getNumberOfButtons() MouseInfo.getNumberOfButtons()}
891     *         if support for the extended mouse buttons is {@link Toolkit#areExtraMouseButtonsEnabled() enabled} by Java.
892     *         That range includes {@code NOBUTTON}, {@code BUTTON1}, {@code BUTTON2}, {@code BUTTON3};
893     *         <br>
894     *         {@code NOBUTTON}, {@code BUTTON1}, {@code BUTTON2} or {@code BUTTON3}
895     *         if support for the extended mouse buttons is {@link Toolkit#areExtraMouseButtonsEnabled() disabled} by Java
896     * @since 1.4
897     * @see Toolkit#areExtraMouseButtonsEnabled()
898     * @see java.awt.MouseInfo#getNumberOfButtons()
899     * @see #MouseEvent(Component, int, long, int, int, int, int, int, int, boolean, int)
900     * @see InputEvent#getMaskForButton(int)
901     */
902    public int getButton() {
903        return button;
904    }
905
906    /**
907     * Returns whether or not this mouse event is the popup menu
908     * trigger event for the platform.
909     * <p><b>Note</b>: Popup menus are triggered differently
910     * on different systems. Therefore, {@code isPopupTrigger}
911     * should be checked in both {@code mousePressed}
912     * and {@code mouseReleased}
913     * for proper cross-platform functionality.
914     *
915     * @return boolean, true if this event is the popup menu trigger
916     *         for this platform
917     */
918    public boolean isPopupTrigger() {
919        return popupTrigger;
920    }
921
922    /**
923     * Returns a {@code String} instance describing the modifier keys and
924     * mouse buttons that were down during the event, such as "Shift",
925     * or "Ctrl+Shift". These strings can be localized by changing
926     * the {@code awt.properties} file.
927     * <p>
928     * Note that the {@code InputEvent.ALT_MASK} and
929     * {@code InputEvent.BUTTON2_MASK} have equal values,
930     * so the "Alt" string is returned for both modifiers.  Likewise,
931     * the {@code InputEvent.META_MASK} and
932     * {@code InputEvent.BUTTON3_MASK} have equal values,
933     * so the "Meta" string is returned for both modifiers.
934     * <p>
935     * Note that passing negative parameter is incorrect,
936     * and will cause the returning an unspecified string.
937     * Zero parameter means that no modifiers were passed and will
938     * cause the returning an empty string.
939     *
940     * @param modifiers A modifier mask describing the modifier keys and
941     *                  mouse buttons that were down during the event
942     * @return string   string text description of the combination of modifier
943     *                  keys and mouse buttons that were down during the event
944     * @see InputEvent#getModifiersExText(int)
945     * @since 1.4
946     */
947    @SuppressWarnings("deprecation")
948    public static String getMouseModifiersText(int modifiers) {
949        StringBuilder buf = new StringBuilder();
950        if ((modifiers & InputEvent.ALT_MASK) != 0) {
951            buf.append(Toolkit.getProperty("AWT.alt", "Alt"));
952            buf.append("+");
953        }
954        if ((modifiers & InputEvent.META_MASK) != 0) {
955            buf.append(Toolkit.getProperty("AWT.meta", "Meta"));
956            buf.append("+");
957        }
958        if ((modifiers & InputEvent.CTRL_MASK) != 0) {
959            buf.append(Toolkit.getProperty("AWT.control", "Ctrl"));
960            buf.append("+");
961        }
962        if ((modifiers & InputEvent.SHIFT_MASK) != 0) {
963            buf.append(Toolkit.getProperty("AWT.shift", "Shift"));
964            buf.append("+");
965        }
966        if ((modifiers & InputEvent.ALT_GRAPH_MASK) != 0) {
967            buf.append(Toolkit.getProperty("AWT.altGraph", "Alt Graph"));
968            buf.append("+");
969        }
970        if ((modifiers & InputEvent.BUTTON1_MASK) != 0) {
971            buf.append(Toolkit.getProperty("AWT.button1", "Button1"));
972            buf.append("+");
973        }
974        if ((modifiers & InputEvent.BUTTON2_MASK) != 0) {
975            buf.append(Toolkit.getProperty("AWT.button2", "Button2"));
976            buf.append("+");
977        }
978        if ((modifiers & InputEvent.BUTTON3_MASK) != 0) {
979            buf.append(Toolkit.getProperty("AWT.button3", "Button3"));
980            buf.append("+");
981        }
982
983        int mask;
984
985        // TODO: add a toolkit field that holds a number of button on the mouse.
986        // As the method getMouseModifiersText() is static and obtain
987        // an integer as a parameter then we may not restrict this with the number
988        // of buttons installed on the mouse.
989        // It's a temporary solution. We need to somehow hold the number of buttons somewhere else.
990        for (int i = 1; i <= cachedNumberOfButtons; i++){
991            mask = InputEvent.getMaskForButton(i);
992            if ((modifiers & mask) != 0 &&
993                buf.indexOf(Toolkit.getProperty("AWT.button"+i, "Button"+i)) == -1) //1,2,3 buttons may already be there; so don't duplicate it.
994            {
995                buf.append(Toolkit.getProperty("AWT.button"+i, "Button"+i));
996                buf.append("+");
997            }
998        }
999
1000        if (buf.length() > 0) {
1001            buf.setLength(buf.length()-1); // remove trailing '+'
1002        }
1003        return buf.toString();
1004    }
1005
1006    /**
1007     * Returns a parameter string identifying this event.
1008     * This method is useful for event-logging and for debugging.
1009     *
1010     * @return a string identifying the event and its attributes
1011     */
1012    @SuppressWarnings("deprecation")
1013    public String paramString() {
1014        StringBuilder str = new StringBuilder(80);
1015
1016        switch(id) {
1017          case MOUSE_PRESSED:
1018              str.append("MOUSE_PRESSED");
1019              break;
1020          case MOUSE_RELEASED:
1021              str.append("MOUSE_RELEASED");
1022              break;
1023          case MOUSE_CLICKED:
1024              str.append("MOUSE_CLICKED");
1025              break;
1026          case MOUSE_ENTERED:
1027              str.append("MOUSE_ENTERED");
1028              break;
1029          case MOUSE_EXITED:
1030              str.append("MOUSE_EXITED");
1031              break;
1032          case MOUSE_MOVED:
1033              str.append("MOUSE_MOVED");
1034              break;
1035          case MOUSE_DRAGGED:
1036              str.append("MOUSE_DRAGGED");
1037              break;
1038          case MOUSE_WHEEL:
1039              str.append("MOUSE_WHEEL");
1040              break;
1041           default:
1042              str.append("unknown type");
1043        }
1044
1045        // (x,y) coordinates
1046        str.append(",(").append(x).append(",").append(y).append(")");
1047        str.append(",absolute(").append(xAbs).append(",").append(yAbs).append(")");
1048
1049        if (id != MOUSE_DRAGGED && id != MOUSE_MOVED){
1050            str.append(",button=").append(getButton());
1051        }
1052
1053        if (getModifiers() != 0) {
1054            str.append(",modifiers=").append(getMouseModifiersText(modifiers));
1055        }
1056
1057        if (getModifiersEx() != 0) {
1058            //Using plain "modifiers" here does show an excluded extended buttons in the string event representation.
1059            //getModifiersEx() solves the problem.
1060            str.append(",extModifiers=").append(getModifiersExText(getModifiersEx()));
1061        }
1062
1063        str.append(",clickCount=").append(clickCount);
1064
1065        return str.toString();
1066    }
1067
1068    /**
1069     * Sets new modifiers by the old ones.
1070     * Also sets button.
1071     */
1072    @SuppressWarnings("deprecation")
1073    private void setNewModifiers() {
1074        if ((modifiers & BUTTON1_MASK) != 0) {
1075            modifiers |= BUTTON1_DOWN_MASK;
1076        }
1077        if ((modifiers & BUTTON2_MASK) != 0) {
1078            modifiers |= BUTTON2_DOWN_MASK;
1079        }
1080        if ((modifiers & BUTTON3_MASK) != 0) {
1081            modifiers |= BUTTON3_DOWN_MASK;
1082        }
1083        if (id == MOUSE_PRESSED
1084            || id == MOUSE_RELEASED
1085            || id == MOUSE_CLICKED)
1086        {
1087            if ((modifiers & BUTTON1_MASK) != 0) {
1088                button = BUTTON1;
1089                modifiers &= ~BUTTON2_MASK & ~BUTTON3_MASK;
1090                if (id != MOUSE_PRESSED) {
1091                    modifiers &= ~BUTTON1_DOWN_MASK;
1092                }
1093            } else if ((modifiers & BUTTON2_MASK) != 0) {
1094                button = BUTTON2;
1095                modifiers &= ~BUTTON1_MASK & ~BUTTON3_MASK;
1096                if (id != MOUSE_PRESSED) {
1097                    modifiers &= ~BUTTON2_DOWN_MASK;
1098                }
1099            } else if ((modifiers & BUTTON3_MASK) != 0) {
1100                button = BUTTON3;
1101                modifiers &= ~BUTTON1_MASK & ~BUTTON2_MASK;
1102                if (id != MOUSE_PRESSED) {
1103                    modifiers &= ~BUTTON3_DOWN_MASK;
1104                }
1105            }
1106        }
1107        if ((modifiers & InputEvent.ALT_MASK) != 0) {
1108            modifiers |= InputEvent.ALT_DOWN_MASK;
1109        }
1110        if ((modifiers & InputEvent.META_MASK) != 0) {
1111            modifiers |= InputEvent.META_DOWN_MASK;
1112        }
1113        if ((modifiers & InputEvent.SHIFT_MASK) != 0) {
1114            modifiers |= InputEvent.SHIFT_DOWN_MASK;
1115        }
1116        if ((modifiers & InputEvent.CTRL_MASK) != 0) {
1117            modifiers |= InputEvent.CTRL_DOWN_MASK;
1118        }
1119        if ((modifiers & InputEvent.ALT_GRAPH_MASK) != 0) {
1120            modifiers |= InputEvent.ALT_GRAPH_DOWN_MASK;
1121        }
1122    }
1123
1124    /**
1125     * Sets old modifiers by the new ones.
1126     */
1127    @SuppressWarnings("deprecation")
1128    private void setOldModifiers() {
1129        if (id == MOUSE_PRESSED
1130            || id == MOUSE_RELEASED
1131            || id == MOUSE_CLICKED)
1132        {
1133            switch(button) {
1134            case BUTTON1:
1135                modifiers |= BUTTON1_MASK;
1136                break;
1137            case BUTTON2:
1138                modifiers |= BUTTON2_MASK;
1139                break;
1140            case BUTTON3:
1141                modifiers |= BUTTON3_MASK;
1142                break;
1143            }
1144        } else {
1145            if ((modifiers & BUTTON1_DOWN_MASK) != 0) {
1146                modifiers |= BUTTON1_MASK;
1147            }
1148            if ((modifiers & BUTTON2_DOWN_MASK) != 0) {
1149                modifiers |= BUTTON2_MASK;
1150            }
1151            if ((modifiers & BUTTON3_DOWN_MASK) != 0) {
1152                modifiers |= BUTTON3_MASK;
1153            }
1154        }
1155        if ((modifiers & ALT_DOWN_MASK) != 0) {
1156            modifiers |= ALT_MASK;
1157        }
1158        if ((modifiers & META_DOWN_MASK) != 0) {
1159            modifiers |= META_MASK;
1160        }
1161        if ((modifiers & SHIFT_DOWN_MASK) != 0) {
1162            modifiers |= SHIFT_MASK;
1163        }
1164        if ((modifiers & CTRL_DOWN_MASK) != 0) {
1165            modifiers |= CTRL_MASK;
1166        }
1167        if ((modifiers & ALT_GRAPH_DOWN_MASK) != 0) {
1168            modifiers |= ALT_GRAPH_MASK;
1169        }
1170    }
1171
1172    /**
1173     * Sets new modifiers by the old ones.
1174     * @serial
1175     */
1176    @SuppressWarnings("deprecation")
1177    private void readObject(ObjectInputStream s)
1178      throws IOException, ClassNotFoundException {
1179        s.defaultReadObject();
1180        if (getModifiers() != 0 && getModifiersEx() == 0) {
1181            setNewModifiers();
1182        }
1183    }
1184}
1185