Jogamp
Bug 741 HiDPI: Add ScalableSurface interface to get/set pixelScale w/ full OSX impl.
[jogl.git] / src / newt / classes / jogamp / newt / driver / awt / WindowDriver.java
1 /*
2  * Copyright (c) 2008 Sun Microsystems, Inc. All Rights Reserved.
3  * Copyright (c) 2010 JogAmp Community. All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions are
7  * met:
8  *
9  * - Redistribution of source code must retain the above copyright
10  *   notice, this list of conditions and the following disclaimer.
11  *
12  * - Redistribution in binary form must reproduce the above copyright
13  *   notice, this list of conditions and the following disclaimer in the
14  *   documentation and/or other materials provided with the distribution.
15  *
16  * Neither the name of Sun Microsystems, Inc. or the names of
17  * contributors may be used to endorse or promote products derived from
18  * this software without specific prior written permission.
19  *
20  * This software is provided "AS IS," without a warranty of any kind. ALL
21  * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES,
22  * INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A
23  * PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN
24  * MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL NOT BE LIABLE FOR
25  * ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR
26  * DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL SUN OR
27  * ITS LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, OR FOR
28  * DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE
29  * DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY,
30  * ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, EVEN IF
31  * SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
32  *
33  */
34
35 package jogamp.newt.driver.awt;
36
37 import java.awt.BorderLayout;
38 import java.awt.Container;
39 import java.awt.Dimension;
40 import java.awt.Frame;
41 import java.awt.Insets;
42
43 import javax.media.nativewindow.NativeSurface;
44 import javax.media.nativewindow.NativeWindow;
45 import javax.media.nativewindow.NativeWindowException;
46 import javax.media.nativewindow.util.Point;
47
48 import jogamp.nativewindow.awt.AWTMisc;
49 import jogamp.newt.WindowImpl;
50
51 import com.jogamp.common.os.Platform;
52 import com.jogamp.nativewindow.awt.AWTGraphicsConfiguration;
53 import com.jogamp.nativewindow.awt.AWTGraphicsDevice;
54 import com.jogamp.nativewindow.awt.AWTGraphicsScreen;
55 import com.jogamp.newt.event.WindowEvent;
56 import com.jogamp.newt.event.WindowUpdateEvent;
57 import com.jogamp.newt.event.awt.AWTKeyAdapter;
58 import com.jogamp.newt.event.awt.AWTMouseAdapter;
59 import com.jogamp.newt.event.awt.AWTWindowAdapter;
60
61 /** An implementation of the Newt Window class built using the
62     AWT. This is provided for convenience of porting to platforms
63     supporting Java SE. */
64
65 public class WindowDriver extends WindowImpl {
66
67     public WindowDriver() {
68         this(null);
69     }
70
71     public static Class<?>[] getCustomConstructorArgumentTypes() {
72         return new Class<?>[] { Container.class } ;
73     }
74
75     public WindowDriver(Container container) {
76         super();
77         this.awtContainer = container;
78         if(container instanceof Frame) {
79             awtFrame = (Frame) container;
80         }
81     }
82
83     private boolean owningFrame;
84     private Container awtContainer = null;
85     /** same instance as container, just for impl. convenience */
86     private Frame awtFrame = null;
87     private AWTCanvas awtCanvas;
88
89     @Override
90     protected void requestFocusImpl(boolean reparented) {
91         awtContainer.requestFocus();
92     }
93
94     @Override
95     protected void setTitleImpl(final String title) {
96         if (awtFrame != null) {
97             awtFrame.setTitle(title);
98         }
99     }
100
101     private final AWTCanvas.UpstreamScalable upstreamScalable = new AWTCanvas.UpstreamScalable() {
102         @Override
103         public int[] getReqPixelScale() {
104             return WindowDriver.this.reqPixelScale;
105         }
106
107         @Override
108         public void setHasPixelScale(final int[] pixelScale) {
109             System.arraycopy(pixelScale, 0, WindowDriver.this.hasPixelScale, 0, 2);
110         }
111     };
112
113     @Override
114     protected void createNativeImpl() {
115         if(0!=getParentWindowHandle()) {
116             throw new RuntimeException("Window parenting not supported in AWT, use AWTWindow(Frame) cstr for wrapping instead");
117         }
118
119         if(null==awtContainer) {
120             awtFrame = new Frame();
121             awtContainer = awtFrame;
122             owningFrame=true;
123         } else {
124             owningFrame=false;
125             defineSize(awtContainer.getWidth(), awtContainer.getHeight());
126             definePosition(awtContainer.getX(), awtContainer.getY());
127         }
128         if(null!=awtFrame) {
129             awtFrame.setTitle(getTitle());
130         }
131         awtContainer.setLayout(new BorderLayout());
132
133         if( null == awtCanvas ) {
134             awtCanvas = new AWTCanvas(capsRequested, WindowDriver.this.capabilitiesChooser, upstreamScalable);
135
136             // canvas.addComponentListener(listener);
137             awtContainer.add(awtCanvas, BorderLayout.CENTER);
138
139             // via EDT ..
140             new AWTMouseAdapter(this).addTo(awtCanvas); // fwd all AWT Mouse events to here
141             new AWTKeyAdapter(this).addTo(awtCanvas); // fwd all AWT Key events to here
142
143             // direct w/o EDT
144             new AWTWindowAdapter(new LocalWindowListener(), this).addTo(awtCanvas); // fwd all AWT Window events to here
145         }
146
147         reconfigureWindowImpl(getX(), getY(), getWidth(), getHeight(), getReconfigureFlags(FLAG_CHANGE_VISIBILITY | FLAG_CHANGE_DECORATION, true));
148         // throws exception if failed ..
149
150         final NativeWindow nw = awtCanvas.getNativeWindow();
151         if( null != nw ) {
152             setGraphicsConfiguration( awtCanvas.getAWTGraphicsConfiguration() );
153             setWindowHandle( nw.getWindowHandle() );
154         }
155     }
156
157     @Override
158     protected void closeNativeImpl() {
159         setWindowHandle(0);
160         if(null!=awtContainer) {
161             awtContainer.setVisible(false);
162             awtContainer.remove(awtCanvas);
163             awtContainer.setEnabled(false);
164             awtCanvas.setEnabled(false);
165         }
166         if(owningFrame && null!=awtFrame) {
167             awtFrame.dispose();
168             owningFrame=false;
169         }
170         awtCanvas = null;
171         awtFrame = null;
172         awtContainer = null;
173     }
174
175     @Override
176     public boolean hasDeviceChanged() {
177         boolean res = awtCanvas.hasDeviceChanged();
178         if(res) {
179             final AWTGraphicsConfiguration cfg = awtCanvas.getAWTGraphicsConfiguration();
180             if (null == cfg) {
181                 throw new NativeWindowException("Error Device change null GraphicsConfiguration: "+this);
182             }
183             setGraphicsConfiguration(cfg);
184
185             // propagate new info ..
186             ((ScreenDriver)getScreen()).setAWTGraphicsScreen((AWTGraphicsScreen)cfg.getScreen());
187             ((DisplayDriver)getScreen().getDisplay()).setAWTGraphicsDevice((AWTGraphicsDevice)cfg.getScreen().getDevice());
188
189             ((ScreenDriver)getScreen()).updateVirtualScreenOriginAndSize();
190         }
191         return res;
192     }
193
194     @Override
195     protected void updateInsetsImpl(javax.media.nativewindow.util.Insets insets) {
196         final Insets contInsets = awtContainer.getInsets();
197         insets.set(contInsets.left, contInsets.right, contInsets.top, contInsets.bottom);
198     }
199
200     private void setCanvasSizeImpl(int width, int height) {
201         final Dimension szClient = new Dimension(width, height);
202         final java.awt.Window awtWindow = AWTMisc.getWindow(awtCanvas);
203         final Container c= null != awtWindow ? awtWindow : awtContainer;
204         awtCanvas.setMinimumSize(szClient);
205         awtCanvas.setPreferredSize(szClient);
206         if(DEBUG_IMPLEMENTATION) {
207             final Insets insets = c.getInsets();
208             final Dimension szContainer = new Dimension(width + insets.left + insets.right,
209                                                         height + insets.top + insets.bottom);
210             System.err.println(getThreadName()+": AWTWindow setCanvasSize: szClient "+szClient+", szCont "+szContainer+", insets "+insets);
211         }
212         awtCanvas.setSize(szClient);
213         awtCanvas.invalidate();
214         if(null != awtWindow) {
215             awtWindow.pack();
216         } else {
217             awtContainer.validate();
218         }
219     }
220     private void setFrameSizeImpl(int width, int height) {
221         final Insets insets = awtContainer.getInsets();
222         final Dimension szContainer = new Dimension(width + insets.left + insets.right,
223                                                     height + insets.top + insets.bottom);
224         if(DEBUG_IMPLEMENTATION) {
225             final Dimension szClient = new Dimension(width, height);
226             System.err.println(getThreadName()+": AWTWindow setFrameSize: szClient "+szClient+", szCont "+szContainer+", insets "+insets);
227         }
228         awtContainer.setSize(szContainer);
229         awtCanvas.invalidate();
230         awtContainer.validate();
231     }
232
233     @Override
234     protected boolean reconfigureWindowImpl(int x, int y, int width, int height, int flags) {
235         if(DEBUG_IMPLEMENTATION) {
236             System.err.println("AWTWindow reconfig: "+x+"/"+y+" "+width+"x"+height+", "+
237                                getReconfigureFlagsAsString(null, flags));
238         }
239         if(0 != ( FLAG_CHANGE_DECORATION & flags) && null!=awtFrame) {
240             if(!awtContainer.isDisplayable()) {
241                 awtFrame.setUndecorated(isUndecorated());
242             } else {
243                 if(DEBUG_IMPLEMENTATION) {
244                     System.err.println(getThreadName()+": AWTWindow can't undecorate already created frame");
245                 }
246             }
247         }
248
249         if( 0 != ( FLAG_CHANGE_VISIBILITY & flags) ) {
250             if( 0 != ( FLAG_IS_VISIBLE & flags) ) {
251                 setCanvasSizeImpl(width, height);
252                 awtContainer.setVisible( true );
253             } else {
254                 awtContainer.setVisible( false );
255             }
256         } else if( awtCanvas.getWidth() != width || awtCanvas.getHeight() != height ) {
257             if( Platform.OSType.MACOS == Platform.getOSType() && awtCanvas.isOffscreenLayerSurfaceEnabled() ) {
258                 setFrameSizeImpl(width, height);
259             } else {
260                 setCanvasSizeImpl(width, height);
261             }
262         }
263         defineSize(width, height); // we are on AWT-EDT .. change values immediately
264
265         if( awtContainer.getX() != x || awtContainer.getY() != y ) {
266             awtContainer.setLocation(x, y);
267         }
268
269         if( 0 != ( FLAG_CHANGE_VISIBILITY & flags) ) {
270             if( 0 != ( FLAG_IS_VISIBLE & flags ) ) {
271                 if( !hasDeviceChanged() ) {
272                     // oops ??
273                     final AWTGraphicsConfiguration cfg = awtCanvas.getAWTGraphicsConfiguration();
274                     if(null == cfg) {
275                         throw new NativeWindowException("Error: !hasDeviceChanged && null == GraphicsConfiguration: "+this);
276                     }
277                     setGraphicsConfiguration(cfg);
278                 }
279             }
280             visibleChanged(false, 0 != ( FLAG_IS_VISIBLE & flags));
281         }
282
283         return true;
284     }
285
286     @Override
287     protected Point getLocationOnScreenImpl(int x, int y) {
288         java.awt.Point ap = awtCanvas.getLocationOnScreen();
289         ap.translate(x, y);
290         return new Point((int)(ap.getX()+0.5),(int)(ap.getY()+0.5));
291     }
292
293     @Override
294     public NativeSurface getWrappedSurface() {
295         return ( null != awtCanvas ) ? awtCanvas.getNativeWindow() : null;
296     }
297
298     class LocalWindowListener implements com.jogamp.newt.event.WindowListener {
299         @Override
300         public void windowMoved(com.jogamp.newt.event.WindowEvent e) {
301             if(null!=awtContainer) {
302                 WindowDriver.this.positionChanged(false, awtContainer.getX(), awtContainer.getY());
303             }
304         }
305         @Override
306         public void windowResized(com.jogamp.newt.event.WindowEvent e) {
307             if(null!=awtCanvas) {
308                 if(DEBUG_IMPLEMENTATION) {
309                     System.err.println("Window Resized: "+awtCanvas);
310                 }
311                 WindowDriver.this.sizeChanged(false, awtCanvas.getWidth(), awtCanvas.getHeight(), true);
312                 WindowDriver.this.windowRepaint(false, 0, 0, getSurfaceWidth(), getSurfaceHeight());
313             }
314         }
315         @Override
316         public void windowDestroyNotify(WindowEvent e) {
317             WindowDriver.this.windowDestroyNotify(false);
318         }
319         @Override
320         public void windowDestroyed(WindowEvent e) {
321             // Not fwd by AWTWindowAdapter, synthesized by NEWT
322         }
323         @Override
324         public void windowGainedFocus(WindowEvent e) {
325             WindowDriver.this.focusChanged(false, true);
326         }
327         @Override
328         public void windowLostFocus(WindowEvent e) {
329             WindowDriver.this.focusChanged(false, false);
330         }
331         @Override
332         public void windowRepaint(WindowUpdateEvent e) {
333             if(null!=awtCanvas) {
334                 if(DEBUG_IMPLEMENTATION) {
335                     System.err.println("Window Repaint: "+awtCanvas);
336                 }
337                 WindowDriver.this.windowRepaint(false, 0, 0, getSurfaceWidth(), getSurfaceHeight());
338             }
339         }
340     }
341 }
http://JogAmp.org git info: FAQ, tutorial and man pages.