1/*
2 * Copyright (c) 2011, 2016, 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.lwawt.macosx;
27
28import java.awt.*;
29import java.awt.geom.Rectangle2D;
30import java.util.concurrent.atomic.AtomicBoolean;
31import java.util.concurrent.atomic.AtomicInteger;
32import java.util.concurrent.atomic.AtomicReference;
33
34import sun.awt.CGraphicsConfig;
35import sun.awt.CGraphicsEnvironment;
36import sun.lwawt.LWWindowPeer;
37
38import sun.java2d.SurfaceData;
39import sun.java2d.opengl.CGLLayer;
40import sun.java2d.opengl.CGLSurfaceData;
41
42public class CPlatformView extends CFRetainedResource {
43    private native long nativeCreateView(int x, int y, int width, int height, long windowLayerPtr);
44    private static native void nativeSetAutoResizable(long awtView, boolean toResize);
45    private static native int nativeGetNSViewDisplayID(long awtView);
46    private static native Rectangle2D nativeGetLocationOnScreen(long awtView);
47    private static native boolean nativeIsViewUnderMouse(long ptr);
48
49    private LWWindowPeer peer;
50    private SurfaceData surfaceData;
51    private CGLLayer windowLayer;
52    private CPlatformResponder responder;
53
54    public CPlatformView() {
55        super(0, true);
56    }
57
58    public void initialize(LWWindowPeer peer, CPlatformResponder responder) {
59        initializeBase(peer, responder);
60
61        if (!LWCToolkit.getSunAwtDisableCALayers()) {
62            this.windowLayer = createCGLayer();
63        }
64        setPtr(nativeCreateView(0, 0, 0, 0, getWindowLayerPtr()));
65    }
66
67    public CGLLayer createCGLayer() {
68        return new CGLLayer(peer);
69    }
70
71    protected void initializeBase(LWWindowPeer peer, CPlatformResponder responder) {
72        this.peer = peer;
73        this.responder = responder;
74    }
75
76    public long getAWTView() {
77        return ptr;
78    }
79
80    public boolean isOpaque() {
81        return !peer.isTranslucent();
82    }
83
84    /*
85     * All coordinates passed to the method should be based on the origin being in the bottom-left corner (standard
86     * Cocoa coordinates).
87     */
88    public void setBounds(int x, int y, int width, int height) {
89        execute(ptr->CWrapper.NSView.setFrame(ptr, x, y, width, height));
90    }
91
92    // REMIND: CGLSurfaceData expects top-level's size
93    public Rectangle getBounds() {
94        return peer.getBounds();
95    }
96
97    public Object getDestination() {
98        return peer;
99    }
100
101    public void setToolTip(String msg) {
102        execute(ptr -> CWrapper.NSView.setToolTip(ptr, msg));
103    }
104
105    // ----------------------------------------------------------------------
106    // PAINTING METHODS
107    // ----------------------------------------------------------------------
108    public SurfaceData replaceSurfaceData() {
109        if (!LWCToolkit.getSunAwtDisableCALayers()) {
110            surfaceData = windowLayer.replaceSurfaceData();
111        } else {
112            if (surfaceData == null) {
113                CGraphicsConfig graphicsConfig = (CGraphicsConfig)getGraphicsConfiguration();
114                surfaceData = graphicsConfig.createSurfaceData(this);
115            } else {
116                validateSurface();
117            }
118        }
119        return surfaceData;
120    }
121
122    private void validateSurface() {
123        if (surfaceData != null) {
124            ((CGLSurfaceData)surfaceData).validate();
125        }
126    }
127
128    public GraphicsConfiguration getGraphicsConfiguration() {
129        return peer.getGraphicsConfiguration();
130    }
131
132    public SurfaceData getSurfaceData() {
133        return surfaceData;
134    }
135
136    @Override
137    public void dispose() {
138        if (!LWCToolkit.getSunAwtDisableCALayers()) {
139            windowLayer.dispose();
140        }
141        super.dispose();
142    }
143
144    public long getWindowLayerPtr() {
145        if (!LWCToolkit.getSunAwtDisableCALayers()) {
146            return windowLayer.getPointer();
147        } else {
148            return 0;
149        }
150    }
151
152    public void setAutoResizable(boolean toResize) {
153        execute(ptr -> nativeSetAutoResizable(ptr, toResize));
154    }
155
156    public boolean isUnderMouse() {
157        AtomicBoolean ref = new AtomicBoolean();
158        execute(ptr -> {
159            ref.set(nativeIsViewUnderMouse(ptr));
160        });
161        return ref.get();
162    }
163
164    public GraphicsDevice getGraphicsDevice() {
165        GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment();
166        CGraphicsEnvironment cge = (CGraphicsEnvironment)ge;
167        AtomicInteger ref = new AtomicInteger();
168        execute(ptr -> {
169            ref.set(nativeGetNSViewDisplayID(ptr));
170        });
171        GraphicsDevice gd = cge.getScreenDevice(ref.get());
172        if (gd == null) {
173            // this could possibly happen during device removal
174            // use the default screen device in this case
175            gd = ge.getDefaultScreenDevice();
176        }
177        return gd;
178    }
179
180    public Point getLocationOnScreen() {
181        AtomicReference<Rectangle> ref = new AtomicReference<>();
182        execute(ptr -> {
183            ref.set(nativeGetLocationOnScreen(ptr).getBounds());
184        });
185        Rectangle r = ref.get();
186        if (r != null) {
187            return new Point(r.x, r.y);
188        }
189        return new Point(0, 0);
190    }
191
192    // ----------------------------------------------------------------------
193    // NATIVE CALLBACKS
194    // ----------------------------------------------------------------------
195
196    /*
197     * The callback is called only in the embedded case when the view is
198     * automatically resized by the superview.
199     * In normal mode this method is never called.
200     */
201    private void deliverResize(int x, int y, int w, int h) {
202        peer.notifyReshape(x, y, w, h);
203    }
204
205
206    private void deliverMouseEvent(final NSEvent event) {
207        int x = event.getX();
208        int y = getBounds().height - event.getY();
209        int absX = event.getAbsX();
210        int absY = event.getAbsY();
211
212        if (event.getType() == CocoaConstants.NSScrollWheel) {
213            responder.handleScrollEvent(x, y, absX, absY, event.getModifierFlags(),
214                                        event.getScrollDeltaX(), event.getScrollDeltaY(),
215                                        event.getScrollPhase());
216        } else {
217            responder.handleMouseEvent(event.getType(), event.getModifierFlags(), event.getButtonNumber(),
218                                       event.getClickCount(), x, y,
219                                       absX, absY);
220        }
221    }
222
223    private void deliverKeyEvent(NSEvent event) {
224        responder.handleKeyEvent(event.getType(), event.getModifierFlags(), event.getCharacters(),
225                                 event.getCharactersIgnoringModifiers(), event.getKeyCode(), true, false);
226    }
227
228    /**
229     * Called by the native delegate in layer backed view mode or in the simple
230     * NSView mode. See NSView.drawRect().
231     */
232    private void deliverWindowDidExposeEvent() {
233        peer.notifyExpose(peer.getSize());
234    }
235}
236