jdk/src/solaris/classes/sun/awt/X11/XGlobalCursorManager.java
author yan
Mon, 06 Oct 2008 16:45:00 +0400
changeset 1966 12a51fb0db0d
parent 439 3488710b02f8
child 4371 dc9dcb8b0ae7
permissions -rw-r--r--
5100701: Toolkit.getLockingKeyState() does not work on XToolkit, but works on Motif Summary: Does not work on Motif but works on XToolkit now; implemented using XQueryPointer. Reviewed-by: anthony

/*
 * Copyright 2003-2008 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
 * under the terms of the GNU General Public License version 2 only, as
 * published by the Free Software Foundation.  Sun designates this
 * particular file as subject to the "Classpath" exception as provided
 * by Sun in the LICENSE file that accompanied this code.
 *
 * This code is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 * version 2 for more details (a copy is included in the LICENSE file that
 * accompanied this code).
 *
 * You should have received a copy of the GNU General Public License version
 * 2 along with this work; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 *
 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
 * CA 95054 USA or visit www.sun.com if you need additional information or
 * have any questions.
 */

package sun.awt.X11;

import java.awt.*;
import java.awt.peer.ComponentPeer;
import java.awt.peer.LightweightPeer;
import java.lang.ref.WeakReference;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import sun.awt.ComponentAccessor;

import sun.awt.GlobalCursorManager;
import sun.awt.SunToolkit;

public final class XGlobalCursorManager extends GlobalCursorManager {

    private static Field  field_pData;
    private static Field  field_type;
    private static Class  cursorClass;
    private static Method method_setPData;
    static {
        cursorClass = java.awt.Cursor.class;
        field_pData = SunToolkit.getField(cursorClass, "pData");
        field_type  = SunToolkit.getField(cursorClass, "type");
        method_setPData = SunToolkit.getMethod(cursorClass, "setPData", new Class[] {long.class});
        if (field_pData == null || field_type == null || method_setPData == null) {
            System.out.println("Unable to initialize XGlobalCursorManager: ");
            Thread.dumpStack();

        }
    }


    // cached nativeContainer
    private WeakReference<Component> nativeContainer;


    /**
     * The XGlobalCursorManager is a singleton.
     */
    private static XGlobalCursorManager manager;


    static GlobalCursorManager getCursorManager() {
        if (manager == null) {
            manager = new XGlobalCursorManager();
        }
        return manager;
    }

    /**
     * Should be called in response to a native mouse enter or native mouse
     * button released message. Should not be called during a mouse drag.
     */
    static void nativeUpdateCursor(Component heavy) {
        XGlobalCursorManager.getCursorManager().updateCursorLater(heavy);
    }


    protected void setCursor(Component comp, Cursor cursor, boolean useCache) {
        if (comp == null) {
            return;
        }

        Cursor cur = useCache ? cursor : getCapableCursor(comp);

        Component nc = null;
        if (useCache) {
            synchronized (this) {
                nc = nativeContainer.get();
            }
        } else {
            nc = getNativeContainer(comp);
        }

        if (nc != null) {
            ComponentPeer nc_peer = ComponentAccessor.getPeer(nc);
            if (nc_peer instanceof XComponentPeer) {
                synchronized (this) {
                    nativeContainer = new WeakReference<Component>(nc);
                }

                ((XComponentPeer)nc_peer).pSetCursor(cur);
                // in case of grab we do for Swing we need to update keep cursor updated
                // (we don't need this in case of AWT menus).  Window Manager consider
                // the grabber as a current window and use its cursor.  So we need to
                // change cursor on the grabber too.
                updateGrabbedCursor(cur);
            }
        }
    }

    /**
     * Updates cursor on the grabber if it is window peer (i.e. current grab is for
     * Swing, not for AWT.
     */
    private static void updateGrabbedCursor(Cursor cur) {
        XBaseWindow target = XAwtState.getGrabWindow();
        if (target instanceof XWindowPeer) {
            XWindowPeer grabber = (XWindowPeer) target;
            grabber.pSetCursor(cur);
        }
    }

    protected void updateCursorOutOfJava() {
        // in case we have grabbed input for Swing we need to reset cursor
        // when mouse pointer is out of any java toplevel.
        // let's use default cursor for this.
        updateGrabbedCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
    }

    private Component getNativeContainer(Component comp) {
        while (comp != null && ComponentAccessor.getPeer(comp) instanceof LightweightPeer) {
            comp = ComponentAccessor.getParent_NoClientCode(comp);
        }
        return comp;
    }

    protected void getCursorPos(Point p) {

        if (!((XToolkit)Toolkit.getDefaultToolkit()).getLastCursorPos(p)) {
            XToolkit.awtLock();
            try {
                long display = XToolkit.getDisplay();
                long root_window = XlibWrapper.RootWindow(display,
                                                          XlibWrapper.DefaultScreen(display));

                XlibWrapper.XQueryPointer(display, root_window,
                                          XlibWrapper.larg1,
                                          XlibWrapper.larg2,
                                          XlibWrapper.larg3,
                                          XlibWrapper.larg4,
                                          XlibWrapper.larg5,
                                          XlibWrapper.larg6,
                                          XlibWrapper.larg7);

                p.x = (int) XlibWrapper.unsafe.getInt(XlibWrapper.larg3);
                p.y = (int) XlibWrapper.unsafe.getInt(XlibWrapper.larg4);
            } finally {
                XToolkit.awtUnlock();
            }
        }
    }
    protected  Component findHeavyweightUnderCursor() {
        return XAwtState.getComponentMouseEntered();
    }

    /*
     * two native methods to call corresponding methods in Container and
     * Component
     */
    protected  Component findComponentAt(Container con, int x, int y) {
        return con.findComponentAt(x,y);
    }

    protected  Point getLocationOnScreen(Component c) {
        return c.getLocationOnScreen();
    }

    protected Component findHeavyweightUnderCursor(boolean useCache) {
        return findHeavyweightUnderCursor();
    }

    private Cursor getCapableCursor(Component comp) {
        Component c = comp;
        while ((c != null) && !(c instanceof Window)
               && ComponentAccessor.isEnabledImpl(c)
               && ComponentAccessor.getVisible(c)
               && ComponentAccessor.getPeer(c) != null)
        {
            c = ComponentAccessor.getParent_NoClientCode(c);
        }
        if (c instanceof Window) {
            return (ComponentAccessor.isEnabledImpl(c)
                    && ComponentAccessor.getVisible(c)
                    && (ComponentAccessor.getPeer(c) != null)
                    && ComponentAccessor.isEnabledImpl(comp))
                   ?
                    ComponentAccessor.getCursor_NoClientCode(comp)
                   :
                    Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR);
        } else if (c == null) {
            return null;
        }
        return getCapableCursor(ComponentAccessor.getParent_NoClientCode(c));
    }

    /* This methods needs to be called from within XToolkit.awtLock / XToolkit.awtUnlock section. */

    static long getCursor(Cursor c) {

        long pData = 0;
        int type = 0;
        try {
            pData = field_pData.getLong(c);
            type = field_type.getInt(c);
        }
        catch (Exception e)
        {
            e.printStackTrace();
        }

        if (pData != 0) return pData;

        int cursorType = 0;
        switch (type) {
          case Cursor.DEFAULT_CURSOR:
              cursorType = XCursorFontConstants.XC_left_ptr;
              break;
          case Cursor.CROSSHAIR_CURSOR:
              cursorType = XCursorFontConstants.XC_crosshair;
              break;
          case Cursor.TEXT_CURSOR:
              cursorType = XCursorFontConstants.XC_xterm;
              break;
          case Cursor.WAIT_CURSOR:
              cursorType = XCursorFontConstants.XC_watch;
              break;
          case Cursor.SW_RESIZE_CURSOR:
              cursorType = XCursorFontConstants.XC_bottom_left_corner;
              break;
          case Cursor.NW_RESIZE_CURSOR:
              cursorType = XCursorFontConstants.XC_top_left_corner;
              break;
          case Cursor.SE_RESIZE_CURSOR:
              cursorType = XCursorFontConstants.XC_bottom_right_corner;
              break;
          case Cursor.NE_RESIZE_CURSOR:
              cursorType = XCursorFontConstants.XC_top_right_corner;
              break;
          case Cursor.S_RESIZE_CURSOR:
              cursorType = XCursorFontConstants.XC_bottom_side;
              break;
          case Cursor.N_RESIZE_CURSOR:
              cursorType = XCursorFontConstants.XC_top_side;
              break;
          case Cursor.W_RESIZE_CURSOR:
              cursorType = XCursorFontConstants.XC_left_side;
              break;
          case Cursor.E_RESIZE_CURSOR:
              cursorType = XCursorFontConstants.XC_right_side;
              break;
          case Cursor.HAND_CURSOR:
              cursorType = XCursorFontConstants.XC_hand2;
              break;
          case Cursor.MOVE_CURSOR:
              cursorType = XCursorFontConstants.XC_fleur;
              break;
        }

        XToolkit.awtLock();
        try {
            pData =(long) XlibWrapper.XCreateFontCursor(XToolkit.getDisplay(), cursorType);
        }
        finally {
            XToolkit.awtUnlock();
        }

        setPData(c,pData);
        return pData;
    }


    static void setPData(Cursor c, long pData) {
        try {
            method_setPData.invoke(c, pData);
        }
        catch (Exception e)
        {
            e.printStackTrace();
        }

    }
}