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