1 /*
   2  * Copyright (c) 2003, 2011, 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 
  26 package sun.awt.X11;
  27 
  28 import java.awt.*;
  29 import java.awt.peer.ComponentPeer;
  30 import java.awt.peer.LightweightPeer;
  31 import java.lang.ref.WeakReference;
  32 import java.lang.reflect.Field;
  33 import java.lang.reflect.Method;
  34 import sun.awt.AWTAccessor;
  35 
  36 import sun.awt.GlobalCursorManager;
  37 import sun.awt.SunToolkit;
  38 
  39 public final class XGlobalCursorManager extends GlobalCursorManager {
  40 
  41     private static Field  field_pData;
  42     private static Field  field_type;
  43     private static Class  cursorClass;
  44     private static Method method_setPData;
  45     static {
  46         cursorClass = java.awt.Cursor.class;
  47         field_pData = SunToolkit.getField(cursorClass, "pData");
  48         field_type  = SunToolkit.getField(cursorClass, "type");
  49         method_setPData = SunToolkit.getMethod(cursorClass, "setPData", new Class[] {long.class});
  50         if (field_pData == null || field_type == null || method_setPData == null) {
  51             System.out.println("Unable to initialize XGlobalCursorManager: ");
  52             Thread.dumpStack();
  53 
  54         }
  55     }
  56 
  57 
  58     // cached nativeContainer
  59     private WeakReference<Component> nativeContainer;
  60 
  61 
  62     /**
  63      * The XGlobalCursorManager is a singleton.
  64      */
  65     private static XGlobalCursorManager manager;
  66 
  67 
  68     static GlobalCursorManager getCursorManager() {
  69         if (manager == null) {
  70             manager = new XGlobalCursorManager();
  71         }
  72         return manager;
  73     }
  74 
  75     /**
  76      * Should be called in response to a native mouse enter or native mouse
  77      * button released message. Should not be called during a mouse drag.
  78      */
  79     static void nativeUpdateCursor(Component heavy) {
  80         XGlobalCursorManager.getCursorManager().updateCursorLater(heavy);
  81     }
  82 
  83 
  84     protected void setCursor(Component comp, Cursor cursor, boolean useCache) {
  85         if (comp == null) {
  86             return;
  87         }
  88 
  89         Cursor cur = useCache ? cursor : getCapableCursor(comp);
  90 
  91         Component nc = null;
  92         if (useCache) {
  93             synchronized (this) {
  94                 nc = nativeContainer.get();
  95             }
  96         } else {
  97            nc = SunToolkit.getHeavyweightComponent(comp);
  98         }
  99 
 100         if (nc != null) {
 101             ComponentPeer nc_peer = AWTAccessor.getComponentAccessor().getPeer(nc);
 102             if (nc_peer instanceof XComponentPeer) {
 103                 synchronized (this) {
 104                     nativeContainer = new WeakReference<Component>(nc);
 105                 }
 106 
 107                 //6431076. A subcomponents (a XTextArea in particular)
 108                 //may want to override the cursor over some of their parts.
 109                 ((XComponentPeer)nc_peer).pSetCursor(cur, false);
 110                 // in case of grab we do for Swing we need to update keep cursor updated
 111                 // (we don't need this in case of AWT menus).  Window Manager consider
 112                 // the grabber as a current window and use its cursor.  So we need to
 113                 // change cursor on the grabber too.
 114                 updateGrabbedCursor(cur);
 115             }
 116         }
 117     }
 118 
 119     /**
 120      * Updates cursor on the grabber if it is window peer (i.e. current grab is for
 121      * Swing, not for AWT.
 122      */
 123     private static void updateGrabbedCursor(Cursor cur) {
 124         XBaseWindow target = XAwtState.getGrabWindow();
 125         if (target instanceof XWindowPeer) {
 126             XWindowPeer grabber = (XWindowPeer) target;
 127             grabber.pSetCursor(cur);
 128         }
 129     }
 130 
 131     protected void updateCursorOutOfJava() {
 132         // in case we have grabbed input for Swing we need to reset cursor
 133         // when mouse pointer is out of any java toplevel.
 134         // let's use default cursor for this.
 135         updateGrabbedCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
 136     }
 137 
 138     protected void getCursorPos(Point p) {
 139 
 140         if (!((XToolkit)Toolkit.getDefaultToolkit()).getLastCursorPos(p)) {
 141             XToolkit.awtLock();
 142             try {
 143                 long display = XToolkit.getDisplay();
 144                 long root_window = XlibWrapper.RootWindow(display,
 145                                                           XlibWrapper.DefaultScreen(display));
 146 
 147                 XlibWrapper.XQueryPointer(display, root_window,
 148                                           XlibWrapper.larg1,
 149                                           XlibWrapper.larg2,
 150                                           XlibWrapper.larg3,
 151                                           XlibWrapper.larg4,
 152                                           XlibWrapper.larg5,
 153                                           XlibWrapper.larg6,
 154                                           XlibWrapper.larg7);
 155 
 156                 p.x = (int) XlibWrapper.unsafe.getInt(XlibWrapper.larg3);
 157                 p.y = (int) XlibWrapper.unsafe.getInt(XlibWrapper.larg4);
 158             } finally {
 159                 XToolkit.awtUnlock();
 160             }
 161         }
 162     }
 163     protected  Component findHeavyweightUnderCursor() {
 164         return XAwtState.getComponentMouseEntered();
 165     }
 166 
 167     /*
 168      * two native methods to call corresponding methods in Container and
 169      * Component
 170      */
 171     protected  Component findComponentAt(Container con, int x, int y) {
 172         return con.findComponentAt(x,y);
 173     }
 174 
 175     protected  Point getLocationOnScreen(Component c) {
 176         return c.getLocationOnScreen();
 177     }
 178 
 179     protected Component findHeavyweightUnderCursor(boolean useCache) {
 180         return findHeavyweightUnderCursor();
 181     }
 182 
 183     private Cursor getCapableCursor(Component comp) {
 184         AWTAccessor.ComponentAccessor compAccessor = AWTAccessor.getComponentAccessor();
 185 
 186         Component c = comp;
 187         while ((c != null) && !(c instanceof Window)
 188                && compAccessor.isEnabled(c)
 189                && compAccessor.isVisible(c)
 190                && compAccessor.isDisplayable(c))
 191         {
 192             c = compAccessor.getParent(c);
 193         }
 194         if (c instanceof Window) {
 195             return (compAccessor.isEnabled(c)
 196                     && compAccessor.isVisible(c)
 197                     && compAccessor.isDisplayable(c)
 198                     && compAccessor.isEnabled(comp))
 199                    ?
 200                     compAccessor.getCursor(comp)
 201                    :
 202                     Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR);
 203         } else if (c == null) {
 204             return null;
 205         }
 206         return getCapableCursor(compAccessor.getParent(c));
 207     }
 208 
 209     /* This methods needs to be called from within XToolkit.awtLock / XToolkit.awtUnlock section. */
 210 
 211     static long getCursor(Cursor c) {
 212 
 213         long pData = 0;
 214         int type = 0;
 215         try {
 216             pData = field_pData.getLong(c);
 217             type = field_type.getInt(c);
 218         }
 219         catch (Exception e)
 220         {
 221             e.printStackTrace();
 222         }
 223 
 224         if (pData != 0) return pData;
 225 
 226         int cursorType = 0;
 227         switch (type) {
 228           case Cursor.DEFAULT_CURSOR:
 229               cursorType = XCursorFontConstants.XC_left_ptr;
 230               break;
 231           case Cursor.CROSSHAIR_CURSOR:
 232               cursorType = XCursorFontConstants.XC_crosshair;
 233               break;
 234           case Cursor.TEXT_CURSOR:
 235               cursorType = XCursorFontConstants.XC_xterm;
 236               break;
 237           case Cursor.WAIT_CURSOR:
 238               cursorType = XCursorFontConstants.XC_watch;
 239               break;
 240           case Cursor.SW_RESIZE_CURSOR:
 241               cursorType = XCursorFontConstants.XC_bottom_left_corner;
 242               break;
 243           case Cursor.NW_RESIZE_CURSOR:
 244               cursorType = XCursorFontConstants.XC_top_left_corner;
 245               break;
 246           case Cursor.SE_RESIZE_CURSOR:
 247               cursorType = XCursorFontConstants.XC_bottom_right_corner;
 248               break;
 249           case Cursor.NE_RESIZE_CURSOR:
 250               cursorType = XCursorFontConstants.XC_top_right_corner;
 251               break;
 252           case Cursor.S_RESIZE_CURSOR:
 253               cursorType = XCursorFontConstants.XC_bottom_side;
 254               break;
 255           case Cursor.N_RESIZE_CURSOR:
 256               cursorType = XCursorFontConstants.XC_top_side;
 257               break;
 258           case Cursor.W_RESIZE_CURSOR:
 259               cursorType = XCursorFontConstants.XC_left_side;
 260               break;
 261           case Cursor.E_RESIZE_CURSOR:
 262               cursorType = XCursorFontConstants.XC_right_side;
 263               break;
 264           case Cursor.HAND_CURSOR:
 265               cursorType = XCursorFontConstants.XC_hand2;
 266               break;
 267           case Cursor.MOVE_CURSOR:
 268               cursorType = XCursorFontConstants.XC_fleur;
 269               break;
 270         }
 271 
 272         XToolkit.awtLock();
 273         try {
 274             pData =(long) XlibWrapper.XCreateFontCursor(XToolkit.getDisplay(), cursorType);
 275         }
 276         finally {
 277             XToolkit.awtUnlock();
 278         }
 279 
 280         setPData(c,pData);
 281         return pData;
 282     }
 283 
 284 
 285     static void setPData(Cursor c, long pData) {
 286         try {
 287             method_setPData.invoke(c, pData);
 288         }
 289         catch (Exception e)
 290         {
 291             e.printStackTrace();
 292         }
 293 
 294     }
 295 }