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 }