changeset 1224:cfe73335a065

6799099: All automatic regression tests that create Robot fail on X11 Reviewed-by: art, ant
author dav
date Fri, 22 May 2009 16:09:45 +0400
parents 97ece6b3d84f
children 52493efeb137
files make/sun/xawt/mapfile-vers src/share/classes/java/awt/Robot.java src/share/classes/java/awt/event/InputEvent.java src/share/classes/java/awt/event/MouseEvent.java src/share/classes/java/awt/peer/RobotPeer.java src/share/classes/sun/awt/SunToolkit.java src/solaris/classes/sun/awt/X11/XBaseWindow.java src/solaris/classes/sun/awt/X11/XDragSourceContextPeer.java src/solaris/classes/sun/awt/X11/XRobotPeer.java src/solaris/classes/sun/awt/X11/XToolkit.java src/solaris/classes/sun/awt/X11/XWindow.java src/solaris/classes/sun/awt/X11/XWindowPeer.java src/solaris/classes/sun/awt/motif/MToolkit.java src/solaris/native/sun/awt/awt_MToolkit.c src/solaris/native/sun/awt/awt_Robot.c src/solaris/native/sun/xawt/XToolkit.c src/windows/classes/sun/awt/windows/WRobotPeer.java src/windows/classes/sun/awt/windows/WToolkit.java src/windows/native/sun/windows/awt_Robot.cpp src/windows/native/sun/windows/awt_Toolkit.cpp
diffstat 20 files changed, 218 insertions(+), 129 deletions(-) [+]
line wrap: on
line diff
--- a/make/sun/xawt/mapfile-vers	Thu May 21 15:04:23 2009 +0400
+++ b/make/sun/xawt/mapfile-vers	Fri May 22 16:09:45 2009 +0400
@@ -155,7 +155,7 @@
         Java_sun_awt_X11_XRobotPeer_mouseReleaseImpl;
         Java_sun_awt_X11_XRobotPeer_mouseWheelImpl;
         Java_sun_awt_X11_XRobotPeer_setup;
-        Java_sun_awt_X11_XRobotPeer_getNumberOfButtonsImpl;
+        Java_sun_awt_X11_XToolkit_getNumberOfButtonsImpl;
         Java_java_awt_Component_initIDs;
         Java_java_awt_Container_initIDs;
         Java_java_awt_Button_initIDs;
--- a/src/share/classes/java/awt/Robot.java	Thu May 21 15:04:23 2009 +0400
+++ b/src/share/classes/java/awt/Robot.java	Fri May 22 16:09:45 2009 +0400
@@ -96,9 +96,13 @@
         init(GraphicsEnvironment.getLocalGraphicsEnvironment()
             .getDefaultScreenDevice());
         int tmpMask = 0;
+
         if (Toolkit.getDefaultToolkit().areExtraMouseButtonsEnabled()){
-            for (int i = 0; i < peer.getNumberOfButtons(); i++){
-                tmpMask |= InputEvent.getMaskForButton(i+1);
+            if (Toolkit.getDefaultToolkit() instanceof SunToolkit) {
+                final int buttonsNumber = ((SunToolkit)(Toolkit.getDefaultToolkit())).getNumberOfButtons();
+                for (int i = 0; i < buttonsNumber; i++){
+                    tmpMask |= InputEvent.getMaskForButton(i+1);
+                }
             }
         }
         tmpMask |= InputEvent.BUTTON1_MASK|
--- a/src/share/classes/java/awt/event/InputEvent.java	Thu May 21 15:04:23 2009 +0400
+++ b/src/share/classes/java/awt/event/InputEvent.java	Fri May 22 16:09:45 2009 +0400
@@ -157,6 +157,8 @@
     /**
      * An array of extended modifiers for additional buttons.
      * @see getButtonDownMasks
+     * There are twenty buttons fit into 4byte space.
+     * one more bit is reserved for FIRST_HIGH_BIT.
      * @since 7.0
      */
     private static final int [] BUTTON_DOWN_MASK = new int [] { BUTTON1_DOWN_MASK,
@@ -169,7 +171,16 @@
                                                                1<<18,
                                                                1<<19,
                                                                1<<20,
-                                                               1<<21 };
+                                                               1<<21,
+                                                               1<<22,
+                                                               1<<23,
+                                                               1<<24,
+                                                               1<<25,
+                                                               1<<26,
+                                                               1<<27,
+                                                               1<<28,
+                                                               1<<29,
+                                                               1<<30};
 
     /**
      * A method to access an array of extended modifiers for additional buttons.
@@ -240,7 +251,7 @@
     // in fact, it is undesirable to add modifier bits
     // to the same field as this may break applications
     // see bug# 5066958
-    static final int FIRST_HIGH_BIT = 1 << 22;
+    static final int FIRST_HIGH_BIT = 1 << 31;
 
     static final int JDK_1_3_MODIFIERS = SHIFT_DOWN_MASK - 1;
     static final int HIGH_MODIFIERS = ~( FIRST_HIGH_BIT - 1 );
--- a/src/share/classes/java/awt/event/MouseEvent.java	Thu May 21 15:04:23 2009 +0400
+++ b/src/share/classes/java/awt/event/MouseEvent.java	Fri May 22 16:09:45 2009 +0400
@@ -33,6 +33,7 @@
 import java.io.ObjectInputStream;
 import java.awt.IllegalComponentStateException;
 import java.awt.MouseInfo;
+import sun.awt.SunToolkit;
 
 /**
  * An event which indicates that a mouse action occurred in a component.
@@ -379,12 +380,25 @@
      */
     private static final long serialVersionUID = -991214153494842848L;
 
+    /**
+     * A number of buttons available on the mouse at the {@code Toolkit} machinery startup.
+     */
+    private static int cachedNumberOfButtons;
+
     static {
         /* ensure that the necessary native libraries are loaded */
         NativeLibLoader.loadLibraries();
         if (!GraphicsEnvironment.isHeadless()) {
             initIDs();
         }
+        final Toolkit tk = Toolkit.getDefaultToolkit();
+        if (tk instanceof SunToolkit) {
+            cachedNumberOfButtons = ((SunToolkit)tk).getNumberOfButtons();
+        } else {
+            //It's expected that some toolkits (Headless,
+            //whatever besides SunToolkit) could also operate.
+            cachedNumberOfButtons = 3;
+        }
     }
 
     /**
@@ -412,15 +426,6 @@
     }
 
     /**
-     * A number of buttons available on the mouse at the {@code Toolkit} machinery startup.
-     */
-    private static int cachedNumberOfButtons;
-
-    static {
-        cachedNumberOfButtons = MouseInfo.getNumberOfButtons();
-    }
-
-    /**
      * Returns the absolute horizontal x position of the event.
      * In a virtual device multi-screen environment in which the
      * desktop area could span multiple physical screen devices,
@@ -735,7 +740,6 @@
         if (button < NOBUTTON){
             throw new IllegalArgumentException("Invalid button value :" + button);
         }
-        //TODO: initialize MouseInfo.cachedNumber on toolkit creation.
         if (button > BUTTON3) {
             if (!Toolkit.getDefaultToolkit().areExtraMouseButtonsEnabled()){
                 throw new IllegalArgumentException("Extra mouse events are disabled " + button);
--- a/src/share/classes/java/awt/peer/RobotPeer.java	Thu May 21 15:04:23 2009 +0400
+++ b/src/share/classes/java/awt/peer/RobotPeer.java	Fri May 22 16:09:45 2009 +0400
@@ -121,11 +121,4 @@
      * Disposes the robot peer when it is not needed anymore.
      */
     void dispose();
-
-    /**
-     * Returns the number of buttons that the robot simulates.
-     *
-     * @return the number of buttons that the robot simulates
-     */
-    int getNumberOfButtons();
 }
--- a/src/share/classes/sun/awt/SunToolkit.java	Thu May 21 15:04:23 2009 +0400
+++ b/src/share/classes/sun/awt/SunToolkit.java	Fri May 22 16:09:45 2009 +0400
@@ -89,6 +89,25 @@
      */
     private static final String POST_EVENT_QUEUE_KEY = "PostEventQueue";
 
+    /**
+     * Number of buttons.
+     * By default it's taken from the system. If system value does not
+     * fit into int type range, use our own MAX_BUTTONS_SUPPORT value.
+     */
+    protected static int numberOfButtons = 0;
+
+
+    /* XFree standard mention 24 buttons as maximum:
+     * http://www.xfree86.org/current/mouse.4.html
+     * We workaround systems supporting more than 24 buttons.
+     * Otherwise, we have to use long type values as masks
+     * which leads to API change.
+     * InputEvent.BUTTON_DOWN_MASK may contain only 21 masks due to
+     * the 4-bytes limit for the int type. (CR 6799099)
+     * One more bit is reserved for FIRST_HIGH_BIT.
+     */
+    public final static int MAX_BUTTONS_SUPPORTED = 20;
+
     public SunToolkit() {
         /* If awt.threadgroup is set to class name the instance of
          * this class is created (should be subclass of ThreadGroup)
@@ -2079,6 +2098,12 @@
         return false;
     }
 
+    /**
+     * Descendants of the SunToolkit should override and put their own logic here.
+     */
+    public int getNumberOfButtons(){
+        return 3;
+    }
 } // class SunToolkit
 
 
--- a/src/solaris/classes/sun/awt/X11/XBaseWindow.java	Thu May 21 15:04:23 2009 +0400
+++ b/src/solaris/classes/sun/awt/X11/XBaseWindow.java	Fri May 22 16:09:45 2009 +0400
@@ -989,8 +989,17 @@
      */
     public void handleButtonPressRelease(XEvent xev) {
         XButtonEvent xbe = xev.get_xbutton();
+        /*
+         * Ignore the buttons above 20 due to the bit limit for
+         * InputEvent.BUTTON_DOWN_MASK.
+         * One more bit is reserved for FIRST_HIGH_BIT.
+         */
+        if (xbe.get_button() > SunToolkit.MAX_BUTTONS_SUPPORTED) {
+            return;
+        }
         int buttonState = 0;
-        for (int i = 0; i<XToolkit.getNumMouseButtons(); i++){
+        final int buttonsNumber = ((SunToolkit)(Toolkit.getDefaultToolkit())).getNumberOfButtons();
+        for (int i = 0; i<buttonsNumber; i++){
             // A bug in WM implementation: extra buttons doesn't have state!=0 as they should on Release message.
             if ((i != 4) && (i != 5)){
                 buttonState |= (xbe.get_state() & XConstants.buttonsMask[i]);
@@ -1026,7 +1035,9 @@
      * Checks ButtonRelease released all Mouse buttons
      */
     static boolean isFullRelease(int buttonState, int button) {
-        if (button < 0 || button > XToolkit.getNumMouseButtons()) {
+        final int buttonsNumber = ((SunToolkit)(Toolkit.getDefaultToolkit())).getNumberOfButtons();
+
+        if (button < 0 || button > buttonsNumber) {
             return buttonState == 0;
         } else {
             return buttonState == XConstants.buttonsMask[button - 1];
--- a/src/solaris/classes/sun/awt/X11/XDragSourceContextPeer.java	Thu May 21 15:04:23 2009 +0400
+++ b/src/solaris/classes/sun/awt/X11/XDragSourceContextPeer.java	Fri May 22 16:09:45 2009 +0400
@@ -42,6 +42,7 @@
 
 import sun.awt.dnd.SunDragSourceContextPeer;
 import sun.awt.dnd.SunDropTargetContextPeer;
+import sun.awt.SunToolkit;
 
 /**
  * The XDragSourceContextPeer class is the class responsible for handling
@@ -666,6 +667,15 @@
         case XConstants.ButtonRelease: {
             XButtonEvent xbutton = ev.get_xbutton();
             /*
+             * Ignore the buttons above 20 due to the bit limit for
+             * InputEvent.BUTTON_DOWN_MASK.
+             * One more bit is reserved for FIRST_HIGH_BIT.
+             */
+            if (xbutton.get_button() > SunToolkit.MAX_BUTTONS_SUPPORTED) {
+                return true;
+            }
+
+            /*
              * On some X servers it could happen that ButtonRelease coordinates
              * differ from the latest MotionNotify coordinates, so we need to
              * process it as a mouse motion.
--- a/src/solaris/classes/sun/awt/X11/XRobotPeer.java	Thu May 21 15:04:23 2009 +0400
+++ b/src/solaris/classes/sun/awt/X11/XRobotPeer.java	Fri May 22 16:09:45 2009 +0400
@@ -81,16 +81,11 @@
         return pixelArray;
     }
 
-    public int getNumberOfButtons(){
-        return getNumberOfButtonsImpl();
-    }
-
     private static native synchronized void setup();
 
     private static native synchronized void mouseMoveImpl(X11GraphicsConfig xgc, int x, int y);
     private static native synchronized void mousePressImpl(int buttons);
     private static native synchronized void mouseReleaseImpl(int buttons);
-    private static native synchronized int getNumberOfButtonsImpl();
     private static native synchronized void mouseWheelImpl(int wheelAmt);
 
     private static native synchronized void keyPressImpl(int keycode);
--- a/src/solaris/classes/sun/awt/X11/XToolkit.java	Thu May 21 15:04:23 2009 +0400
+++ b/src/solaris/classes/sun/awt/X11/XToolkit.java	Fri May 22 16:09:45 2009 +0400
@@ -85,21 +85,6 @@
     private static boolean areExtraMouseButtonsEnabled = true;
 
     /**
-     * Number of buttons.
-     * By default it's taken from the system. If system value does not
-     * fit into int type range, use our own MAX_BUTTONS_SUPPORT value.
-     */
-    private static int numberOfButtons = 0;
-
-    /* XFree standard mention 24 buttons as maximum:
-     * http://www.xfree86.org/current/mouse.4.html
-     * We workaround systems supporting more than 24 buttons.
-     * Otherwise, we have to use long type values as masks
-     * which leads to API change.
-     */
-    private static int MAX_BUTTONS_SUPPORT = 24;
-
-    /**
      * True when the x settings have been loaded.
      */
     private boolean loadedXSettings;
@@ -1458,19 +1443,26 @@
             desktopProperties.put("awt.multiClickInterval",
                                   Integer.valueOf(getMultiClickTime()));
             desktopProperties.put("awt.mouse.numButtons",
-                                  Integer.valueOf(getNumMouseButtons()));
+                                  Integer.valueOf(getNumberOfButtons()));
         }
     }
 
-    public static int getNumMouseButtons() {
+    /**
+     * This method runs through the XPointer and XExtendedPointer array.
+     * XExtendedPointer has priority because on some systems XPointer
+     * (which is assigned to the virtual pointer) reports the maximum
+     * capabilities of the mouse pointer (i.e. 32 physical buttons).
+     */
+    private native synchronized int getNumberOfButtonsImpl();
+
+    @Override
+    public int getNumberOfButtons(){
         awtLock();
         try {
             if (numberOfButtons == 0) {
-                numberOfButtons = Math.min(
-                    XlibWrapper.XGetPointerMapping(XToolkit.getDisplay(), 0, 0),
-                    MAX_BUTTONS_SUPPORT);
+                numberOfButtons = getNumberOfButtonsImpl();
             }
-            return numberOfButtons;
+            return (numberOfButtons > MAX_BUTTONS_SUPPORTED)? MAX_BUTTONS_SUPPORTED : numberOfButtons;
         } finally {
             awtUnlock();
         }
--- a/src/solaris/classes/sun/awt/X11/XWindow.java	Thu May 21 15:04:23 2009 +0400
+++ b/src/solaris/classes/sun/awt/X11/XWindow.java	Fri May 22 16:09:45 2009 +0400
@@ -677,6 +677,14 @@
         int button=0;
         boolean wheel_mouse = false;
         int lbutton = xbe.get_button();
+        /*
+         * Ignore the buttons above 20 due to the bit limit for
+         * InputEvent.BUTTON_DOWN_MASK.
+         * One more bit is reserved for FIRST_HIGH_BIT.
+         */
+        if (lbutton > SunToolkit.MAX_BUTTONS_SUPPORTED) {
+            return;
+        }
         int type = xev.get_type();
         when = xbe.get_time();
         long jWhen = XToolkit.nowMillisUTC_offset(when);
@@ -795,8 +803,9 @@
         //this doesn't work for extra buttons because Xsystem is sending state==0 for every extra button event.
         // we can't correct it in MouseEvent class as we done it with modifiers, because exact type (DRAG|MOVE)
         // should be passed from XWindow.
-        //TODO: eliminate it with some other value obtained w/o AWTLock.
-        for (int i = 0; i < XToolkit.getNumMouseButtons(); i++){
+        final int buttonsNumber = ((SunToolkit)(Toolkit.getDefaultToolkit())).getNumberOfButtons();
+
+        for (int i = 0; i < buttonsNumber; i++){
             // TODO : here is the bug in WM: extra buttons doesn't have state!=0 as they should.
             if ((i != 4) && (i != 5)) {
                 mouseKeyState = mouseKeyState | (xme.get_state() & XConstants.buttonsMask[i]);
--- a/src/solaris/classes/sun/awt/X11/XWindowPeer.java	Thu May 21 15:04:23 2009 +0400
+++ b/src/solaris/classes/sun/awt/X11/XWindowPeer.java	Fri May 22 16:09:45 2009 +0400
@@ -1894,7 +1894,9 @@
         }
         if (isGrabbed()) {
             boolean dragging = false;
-            for (int i = 0; i<XToolkit.getNumMouseButtons(); i++){
+            final int buttonsNumber = ((SunToolkit)(Toolkit.getDefaultToolkit())).getNumberOfButtons();
+
+            for (int i = 0; i < buttonsNumber; i++){
                 // here is the bug in WM: extra buttons doesn't have state!=0 as they should.
                 if ((i != 4) && (i != 5)){
                     dragging = dragging || ((xme.get_state() & XConstants.buttonsMask[i]) != 0);
@@ -1940,6 +1942,15 @@
 
     public void handleButtonPressRelease(XEvent xev) {
         XButtonEvent xbe = xev.get_xbutton();
+
+        /*
+         * Ignore the buttons above 20 due to the bit limit for
+         * InputEvent.BUTTON_DOWN_MASK.
+         * One more bit is reserved for FIRST_HIGH_BIT.
+         */
+        if (xbe.get_button() > SunToolkit.MAX_BUTTONS_SUPPORTED) {
+            return;
+        }
         if (grabLog.isLoggable(Level.FINE)) {
             grabLog.log(Level.FINE, "{0}, when grabbed {1}, contains {2} ({3}, {4}, {5}x{6})",
                         new Object[] {xbe, isGrabbed(), containsGlobal(xbe.get_x_root(), xbe.get_y_root()), getAbsoluteX(), getAbsoluteY(), getWidth(), getHeight()});
--- a/src/solaris/classes/sun/awt/motif/MToolkit.java	Thu May 21 15:04:23 2009 +0400
+++ b/src/solaris/classes/sun/awt/motif/MToolkit.java	Fri May 22 16:09:45 2009 +0400
@@ -1,5 +1,5 @@
 /*
- * Copyright 1995-2007 Sun Microsystems, Inc.  All Rights Reserved.
+ * Copyright 1995-2009 Sun Microsystems, Inc.  All Rights Reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -624,7 +624,6 @@
     }
 
     private native int getMulticlickTime();
-    private native int getNumMouseButtons();
 
     protected void initializeDesktopProperties() {
         desktopProperties.put("DnD.Autoscroll.initialDelay",     Integer.valueOf(50));
@@ -643,7 +642,7 @@
             desktopProperties.put("awt.multiClickInterval",
                                   Integer.valueOf(getMulticlickTime()));
             desktopProperties.put("awt.mouse.numButtons",
-                                  Integer.valueOf(getNumMouseButtons()));
+                                  Integer.valueOf(getNumberOfButtons()));
         }
     }
 
--- a/src/solaris/native/sun/awt/awt_MToolkit.c	Thu May 21 15:04:23 2009 +0400
+++ b/src/solaris/native/sun/awt/awt_MToolkit.c	Fri May 22 16:09:45 2009 +0400
@@ -3168,21 +3168,6 @@
 
 /*
  * Class:     sun_awt_motif_MToolkit
- * Method:    getNumMouseButtons
- * Signature: ()I
- */
-JNIEXPORT jint JNICALL Java_sun_awt_motif_MToolkit_getNumMouseButtons
-  (JNIEnv *env, jobject this)
-{
-    jint res = 0;
-    AWT_LOCK();
-    res = XGetPointerMapping(awt_display, NULL, 0);
-    AWT_UNLOCK();
-    return res;
-}
-
-/*
- * Class:     sun_awt_motif_MToolkit
  * Method:    loadXSettings
  * Signature: ()V
  */
--- a/src/solaris/native/sun/awt/awt_Robot.c	Thu May 21 15:04:23 2009 +0400
+++ b/src/solaris/native/sun/awt/awt_Robot.c	Fri May 22 16:09:45 2009 +0400
@@ -51,9 +51,8 @@
 
 extern struct X11GraphicsConfigIDs x11GraphicsConfigIDs;
 
-// 2 would be more correct, however that's how Robot originally worked
-// and tests start to fail if this value is changed
-static int32_t num_buttons = 3;
+extern int32_t getNumButtons();
+
 static jint * masks;
 
 static int32_t isXTestAvailable() {
@@ -90,46 +89,6 @@
     return isXTestAvailable;
 }
 
-static void getNumButtons() {
-    int32_t major_opcode, first_event, first_error;
-    int32_t xinputAvailable;
-    int32_t numDevices, devIdx, clsIdx;
-    XDeviceInfo* devices;
-    XDeviceInfo* aDevice;
-    XButtonInfo* bInfo;
-
-    /* 4700242:
-     * If XTest is asked to press a non-existant mouse button
-     * (i.e. press Button3 on a system configured with a 2-button mouse),
-     * then a crash may happen.  To avoid this, we use the XInput
-     * extension to query for the number of buttons on the XPointer, and check
-     * before calling XTestFakeButtonEvent().
-     */
-    xinputAvailable = XQueryExtension(awt_display, INAME, &major_opcode, &first_event, &first_error);
-    DTRACE_PRINTLN3("RobotPeer: XQueryExtension(XINPUT) returns major_opcode = %d, first_event = %d, first_error = %d",
-                    major_opcode, first_event, first_error);
-    if (xinputAvailable) {
-        devices = XListInputDevices(awt_display, &numDevices);
-        for (devIdx = 0; devIdx < numDevices; devIdx++) {
-            aDevice = &(devices[devIdx]);
-            if (aDevice->use == IsXPointer) {
-                for (clsIdx = 0; clsIdx < aDevice->num_classes; clsIdx++) {
-                    if (aDevice->inputclassinfo[clsIdx].class == ButtonClass) {
-                        bInfo = (XButtonInfo*)(&(aDevice->inputclassinfo[clsIdx]));
-                        num_buttons = bInfo->num_buttons;
-                        DTRACE_PRINTLN1("RobotPeer: XPointer has %d buttons", num_buttons);
-                        break;
-                    }
-                }
-                break;
-            }
-        }
-        XFreeDeviceList(devices);
-    }
-    else {
-        DTRACE_PRINTLN1("RobotPeer: XINPUT extension is unavailable, assuming %d mouse buttons", num_buttons);
-    }
-}
 
 static XImage *getWindowImage(Display * display, Window window,
                               int32_t x, int32_t y,
@@ -241,17 +200,10 @@
         return;
     }
 
-    getNumButtons();
     finally:
     AWT_UNLOCK();
 }
 
-JNIEXPORT jint JNICALL
-Java_sun_awt_X11_XRobotPeer_getNumberOfButtonsImpl(JNIEnv *env,
-                                                   jclass cls) {
-    // At the moment this routine being called we already should have an initialized num_buttons variable.
-    return num_buttons;
-}
 
 JNIEXPORT void JNICALL
 Java_sun_awt_X11_XRobotPeer_getRGBPixelsImpl( JNIEnv *env,
@@ -386,6 +338,8 @@
 {
     AWT_LOCK();
 
+    int32_t num_buttons = getNumButtons(); //from XToolkit.c
+
     DTRACE_PRINTLN1("RobotPeer: mouseAction(%i)", buttonMask);
     DTRACE_PRINTLN1("RobotPeer: mouseAction, press = %d", isMousePress);
 
--- a/src/solaris/native/sun/xawt/XToolkit.c	Thu May 21 15:04:23 2009 +0400
+++ b/src/solaris/native/sun/xawt/XToolkit.c	Fri May 22 16:09:45 2009 +0400
@@ -45,10 +45,14 @@
 #include "sun_awt_X11_XToolkit.h"
 #include "java_awt_SystemColor.h"
 #include "java_awt_TrayIcon.h"
+#include <X11/extensions/XTest.h>
 
 uint32_t awt_NumLockMask = 0;
 Boolean  awt_ModLockIsShiftLock = False;
 
+static int32_t num_buttons = 0;
+int32_t getNumButtons();
+
 extern JavaVM *jvm;
 
 // Tracing level
@@ -908,3 +912,78 @@
         AWT_UNLOCK();
     }
 }
+
+
+/*
+ * Class:     sun_awt_X11_XToolkit
+ * Method:    getNumberOfButtonsImpl
+ * Signature: ()I
+ */
+JNIEXPORT jint JNICALL Java_sun_awt_X11_XToolkit_getNumberOfButtonsImpl
+(JNIEnv * env, jobject cls){
+    if (num_buttons == 0) {
+        num_buttons = getNumButtons();
+    }
+    return num_buttons;
+}
+
+int32_t getNumButtons() {
+    int32_t major_opcode, first_event, first_error;
+    int32_t xinputAvailable;
+    int32_t numDevices, devIdx, clsIdx;
+    XDeviceInfo* devices;
+    XDeviceInfo* aDevice;
+    XButtonInfo* bInfo;
+    int32_t local_num_buttons = 0;
+
+    /* 4700242:
+     * If XTest is asked to press a non-existant mouse button
+     * (i.e. press Button3 on a system configured with a 2-button mouse),
+     * then a crash may happen.  To avoid this, we use the XInput
+     * extension to query for the number of buttons on the XPointer, and check
+     * before calling XTestFakeButtonEvent().
+     */
+    xinputAvailable = XQueryExtension(awt_display, INAME, &major_opcode, &first_event, &first_error);
+    DTRACE_PRINTLN3("RobotPeer: XQueryExtension(XINPUT) returns major_opcode = %d, first_event = %d, first_error = %d",
+                    major_opcode, first_event, first_error);
+    if (xinputAvailable) {
+        devices = XListInputDevices(awt_display, &numDevices);
+        for (devIdx = 0; devIdx < numDevices; devIdx++) {
+            aDevice = &(devices[devIdx]);
+            if (aDevice->use == IsXExtensionPointer) {
+                for (clsIdx = 0; clsIdx < aDevice->num_classes; clsIdx++) {
+                    if (aDevice->inputclassinfo[clsIdx].class == ButtonClass) {
+                        bInfo = (XButtonInfo*)(&(aDevice->inputclassinfo[clsIdx]));
+                        local_num_buttons = bInfo->num_buttons;
+                        DTRACE_PRINTLN1("RobotPeer: XPointer has %d buttons", num_buttons);
+                        break;
+                    }
+                }
+                break;
+            }
+            if (local_num_buttons <= 0 ) {
+                if (aDevice->use == IsXPointer) {
+                    for (clsIdx = 0; clsIdx < aDevice->num_classes; clsIdx++) {
+                        if (aDevice->inputclassinfo[clsIdx].class == ButtonClass) {
+                            bInfo = (XButtonInfo*)(&(aDevice->inputclassinfo[clsIdx]));
+                            local_num_buttons = bInfo->num_buttons;
+                            DTRACE_PRINTLN1("RobotPeer: XPointer has %d buttons", num_buttons);
+                            break;
+                        }
+                    }
+                    break;
+                }
+            }
+        }
+
+        XFreeDeviceList(devices);
+    }
+    else {
+        DTRACE_PRINTLN1("RobotPeer: XINPUT extension is unavailable, assuming %d mouse buttons", num_buttons);
+    }
+    if (local_num_buttons == 0 ) {
+        local_num_buttons = 3;
+    }
+
+    return local_num_buttons;
+}
--- a/src/windows/classes/sun/awt/windows/WRobotPeer.java	Thu May 21 15:04:23 2009 +0400
+++ b/src/windows/classes/sun/awt/windows/WRobotPeer.java	Fri May 22 16:09:45 2009 +0400
@@ -60,8 +60,6 @@
     }
     public native int getRGBPixelImpl(int x, int y);
 
-    public native int getNumberOfButtons();
-
     public int [] getRGBPixels(Rectangle bounds) {
         int pixelArray[] = new int[bounds.width*bounds.height];
         getRGBPixels(bounds.x, bounds.y, bounds.width, bounds.height, pixelArray);
--- a/src/windows/classes/sun/awt/windows/WToolkit.java	Thu May 21 15:04:23 2009 +0400
+++ b/src/windows/classes/sun/awt/windows/WToolkit.java	Fri May 22 16:09:45 2009 +0400
@@ -982,6 +982,16 @@
         return areExtraMouseButtonsEnabled;
     }
 
+    private native synchronized int getNumberOfButtonsImpl();
+
+    @Override
+    public int getNumberOfButtons(){
+        if (numberOfButtons == 0) {
+            numberOfButtons = getNumberOfButtonsImpl();
+        }
+        return (numberOfButtons > MAX_BUTTONS_SUPPORTED)? MAX_BUTTONS_SUPPORTED : numberOfButtons;
+    }
+
     @Override
     public boolean isWindowOpacitySupported() {
         // supported in Win2K and later
--- a/src/windows/native/sun/windows/awt_Robot.cpp	Thu May 21 15:04:23 2009 +0400
+++ b/src/windows/native/sun/windows/awt_Robot.cpp	Fri May 22 16:09:45 2009 +0400
@@ -437,9 +437,3 @@
 
     CATCH_BAD_ALLOC;
 }
-
-JNIEXPORT jint JNICALL Java_sun_awt_windows_WRobotPeer_getNumberOfButtons(
-  JNIEnv *, jobject self)
-{
-    return GetSystemMetrics(SM_CMOUSEBUTTONS);
-}
--- a/src/windows/native/sun/windows/awt_Toolkit.cpp	Thu May 21 15:04:23 2009 +0400
+++ b/src/windows/native/sun/windows/awt_Toolkit.cpp	Fri May 22 16:09:45 2009 +0400
@@ -2259,3 +2259,8 @@
 void AwtToolkit::setExtraMouseButtonsEnabled(BOOL enable) {
     m_areExtraMouseButtonsEnabled = enable;
 }
+
+JNIEXPORT jint JNICALL Java_sun_awt_windows_WToolkit_getNumberOfButtonsImpl
+(JNIEnv *, jobject self) {
+    return GetSystemMetrics(SM_CMOUSEBUTTONS);
+}