1/*
2 * Copyright (c) 2003, 2014, 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
26package sun.awt.X11;
27
28import java.awt.*;
29import java.awt.peer.ComponentPeer;
30import java.lang.ref.WeakReference;
31import sun.awt.AWTAccessor;
32
33import sun.awt.GlobalCursorManager;
34import sun.awt.SunToolkit;
35
36public 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 = XlibWrapper.unsafe.getInt(XlibWrapper.larg3);
137                p.y = 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     * native method to call corresponding methods in Component
149     */
150    protected  Point getLocationOnScreen(Component c) {
151        return c.getLocationOnScreen();
152    }
153
154    protected Component findHeavyweightUnderCursor(boolean useCache) {
155        return findHeavyweightUnderCursor();
156    }
157
158    private Cursor getCapableCursor(Component comp) {
159        AWTAccessor.ComponentAccessor compAccessor = AWTAccessor.getComponentAccessor();
160
161        Component c = comp;
162        while ((c != null) && !(c instanceof Window)
163               && compAccessor.isEnabled(c)
164               && compAccessor.isVisible(c)
165               && compAccessor.isDisplayable(c))
166        {
167            c = compAccessor.getParent(c);
168        }
169        if (c instanceof Window) {
170            return (compAccessor.isEnabled(c)
171                    && compAccessor.isVisible(c)
172                    && compAccessor.isDisplayable(c)
173                    && compAccessor.isEnabled(comp))
174                   ?
175                    compAccessor.getCursor(comp)
176                   :
177                    Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR);
178        } else if (c == null) {
179            return null;
180        }
181        return getCapableCursor(compAccessor.getParent(c));
182    }
183
184    /* This methods needs to be called from within XToolkit.awtLock / XToolkit.awtUnlock section. */
185
186    static long getCursor(Cursor c) {
187
188        long pData = 0;
189        int type = 0;
190        try {
191            pData = AWTAccessor.getCursorAccessor().getPData(c);
192            type = AWTAccessor.getCursorAccessor().getType(c);
193        }
194        catch (Exception e)
195        {
196            e.printStackTrace();
197        }
198
199        if (pData != 0) return pData;
200
201        int cursorType = 0;
202        switch (type) {
203          case Cursor.DEFAULT_CURSOR:
204              cursorType = XCursorFontConstants.XC_left_ptr;
205              break;
206          case Cursor.CROSSHAIR_CURSOR:
207              cursorType = XCursorFontConstants.XC_crosshair;
208              break;
209          case Cursor.TEXT_CURSOR:
210              cursorType = XCursorFontConstants.XC_xterm;
211              break;
212          case Cursor.WAIT_CURSOR:
213              cursorType = XCursorFontConstants.XC_watch;
214              break;
215          case Cursor.SW_RESIZE_CURSOR:
216              cursorType = XCursorFontConstants.XC_bottom_left_corner;
217              break;
218          case Cursor.NW_RESIZE_CURSOR:
219              cursorType = XCursorFontConstants.XC_top_left_corner;
220              break;
221          case Cursor.SE_RESIZE_CURSOR:
222              cursorType = XCursorFontConstants.XC_bottom_right_corner;
223              break;
224          case Cursor.NE_RESIZE_CURSOR:
225              cursorType = XCursorFontConstants.XC_top_right_corner;
226              break;
227          case Cursor.S_RESIZE_CURSOR:
228              cursorType = XCursorFontConstants.XC_bottom_side;
229              break;
230          case Cursor.N_RESIZE_CURSOR:
231              cursorType = XCursorFontConstants.XC_top_side;
232              break;
233          case Cursor.W_RESIZE_CURSOR:
234              cursorType = XCursorFontConstants.XC_left_side;
235              break;
236          case Cursor.E_RESIZE_CURSOR:
237              cursorType = XCursorFontConstants.XC_right_side;
238              break;
239          case Cursor.HAND_CURSOR:
240              cursorType = XCursorFontConstants.XC_hand2;
241              break;
242          case Cursor.MOVE_CURSOR:
243              cursorType = XCursorFontConstants.XC_fleur;
244              break;
245        }
246
247        XToolkit.awtLock();
248        try {
249            pData =(long) XlibWrapper.XCreateFontCursor(XToolkit.getDisplay(), cursorType);
250        }
251        finally {
252            XToolkit.awtUnlock();
253        }
254
255        setPData(c,pData);
256        return pData;
257    }
258
259
260    static void setPData(Cursor c, long pData) {
261        try {
262            AWTAccessor.getCursorAccessor().setPData(c, pData);
263        }
264        catch (Exception e)
265        {
266            e.printStackTrace();
267        }
268
269    }
270}
271