author | mchung |
Tue, 08 Dec 2009 09:02:09 -0800 | |
changeset 4374 | f672d9cf521e |
parent 3938 | ef327bd847c0 |
child 5506 | 202f599c92aa |
permissions | -rw-r--r-- |
2 | 1 |
/* |
2 |
* Copyright 2005-2007 Sun Microsystems, Inc. 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. Sun designates this |
|
8 |
* particular file as subject to the "Classpath" exception as provided |
|
9 |
* by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, |
|
22 |
* CA 95054 USA or visit www.sun.com if you need additional information or |
|
23 |
* have any questions. |
|
24 |
*/ |
|
25 |
package java.awt; |
|
26 |
||
27 |
import java.io.IOException; |
|
28 |
import java.awt.image.*; |
|
29 |
import java.net.URL; |
|
30 |
import java.net.URLConnection; |
|
31 |
import java.io.File; |
|
3938
ef327bd847c0
6879044: Eliminate the dependency on logging from the AWT/2D/Swing classes
mchung
parents:
2
diff
changeset
|
32 |
import sun.util.logging.PlatformLogger; |
2 | 33 |
import sun.awt.image.SunWritableRaster; |
34 |
||
35 |
/** |
|
36 |
* The splash screen can be created at application startup, before the |
|
37 |
* Java Virtual Machine (JVM) starts. The splash screen is displayed as an |
|
38 |
* undecorated window containing an image. You can use GIF, JPEG, and PNG files |
|
39 |
* for the image. Animation (for GIF) and transparency (for GIF, PNG) are |
|
40 |
* supported. The window is positioned at the center of the screen (the |
|
41 |
* position on multi-monitor systems is not specified - it is platform and |
|
42 |
* implementation dependent). |
|
43 |
* The window is closed automatically as soon as the first window is displayed by |
|
44 |
* Swing/AWT (may be also closed manually using the Java API, see below). |
|
45 |
* <P> |
|
46 |
* There are two ways to show the native splash screen: |
|
47 |
* <P> |
|
48 |
* <UL> |
|
49 |
* <LI>If your application is run from the command line or from a shortcut, |
|
50 |
* use the "-splash:" Java application launcher option to show a splash screen. |
|
51 |
* <BR> |
|
52 |
* For example: |
|
53 |
* <PRE> |
|
54 |
* java -splash:filename.gif Test |
|
55 |
* </PRE> |
|
56 |
* <LI>If your application is packaged in a jar file, you can use the |
|
57 |
* "SplashScreen-Image" option in a manifest file to show a splash screen. |
|
58 |
* Place the image in the jar archive and specify the path in the option. |
|
59 |
* The path should not have a leading slash. |
|
60 |
* <BR> |
|
61 |
* For example, in the <code>manifest.mf</code> file: |
|
62 |
* <PRE> |
|
63 |
* Manifest-Version: 1.0 |
|
64 |
* Main-Class: Test |
|
65 |
* SplashScreen-Image: filename.gif |
|
66 |
* </PRE> |
|
67 |
* The command line interface has higher precedence over the manifest |
|
68 |
* setting. |
|
69 |
* </UL> |
|
70 |
* <p> |
|
71 |
* The {@code SplashScreen} class provides the API for controlling the splash |
|
72 |
* screen. This class may be used to close the splash screen, change the splash |
|
73 |
* screen image, get the image position/size and paint in the splash screen. It |
|
74 |
* cannot be used to create the splash screen; you should use the command line or manifest |
|
75 |
* file option for that. |
|
76 |
* <p> |
|
77 |
* This class cannot be instantiated. Only a single instance of this class |
|
78 |
* can exist, and it may be obtained using the {@link #getSplashScreen()} |
|
79 |
* static method. In case the splash screen has not been created at |
|
80 |
* application startup via the command line or manifest file option, |
|
81 |
* the <code>getSplashScreen</code> method returns <code>null</code>. |
|
82 |
* |
|
83 |
* @author Oleg Semenov |
|
84 |
* @since 1.6 |
|
85 |
*/ |
|
86 |
public final class SplashScreen { |
|
87 |
||
88 |
SplashScreen(long ptr) { // non-public constructor |
|
89 |
splashPtr = ptr; |
|
90 |
} |
|
91 |
||
92 |
/** |
|
93 |
* Returns the {@code SplashScreen} object used for |
|
94 |
* Java startup splash screen control. |
|
95 |
* |
|
96 |
* @throws UnsupportedOperationException if the splash screen feature is not |
|
97 |
* supported by the current toolkit |
|
98 |
* @throws HeadlessException if {@code GraphicsEnvironment.isHeadless()} |
|
99 |
* returns true |
|
100 |
* @return the {@link SplashScreen} instance, or <code>null</code> if there is |
|
101 |
* none or it has already been closed |
|
102 |
*/ |
|
103 |
public static SplashScreen getSplashScreen() { |
|
104 |
synchronized (SplashScreen.class) { |
|
105 |
if (GraphicsEnvironment.isHeadless()) { |
|
106 |
throw new HeadlessException(); |
|
107 |
} |
|
108 |
// SplashScreen class is now a singleton |
|
109 |
if (!wasClosed && theInstance == null) { |
|
110 |
java.security.AccessController.doPrivileged( |
|
111 |
new sun.security.action.LoadLibraryAction("splashscreen")); |
|
112 |
long ptr = _getInstance(); |
|
113 |
if (ptr != 0 && _isVisible(ptr)) { |
|
114 |
theInstance = new SplashScreen(ptr); |
|
115 |
} |
|
116 |
} |
|
117 |
return theInstance; |
|
118 |
} |
|
119 |
} |
|
120 |
||
121 |
/** |
|
122 |
* Changes the splash screen image. The new image is loaded from the |
|
123 |
* specified URL; GIF, JPEG and PNG image formats are supported. |
|
124 |
* The method returns after the image has finished loading and the window |
|
125 |
* has been updated. |
|
126 |
* The splash screen window is resized according to the size of |
|
127 |
* the image and is centered on the screen. |
|
128 |
* |
|
129 |
* @param imageURL the non-<code>null</code> URL for the new |
|
130 |
* splash screen image |
|
131 |
* @throws NullPointerException if {@code imageURL} is <code>null</code> |
|
132 |
* @throws IOException if there was an error while loading the image |
|
133 |
* @throws IllegalStateException if the splash screen has already been |
|
134 |
* closed |
|
135 |
*/ |
|
136 |
public void setImageURL(URL imageURL) throws NullPointerException, IOException, IllegalStateException { |
|
137 |
checkVisible(); |
|
138 |
URLConnection connection = imageURL.openConnection(); |
|
139 |
connection.connect(); |
|
140 |
int length = connection.getContentLength(); |
|
141 |
java.io.InputStream stream = connection.getInputStream(); |
|
142 |
byte[] buf = new byte[length]; |
|
143 |
int off = 0; |
|
144 |
while(true) { |
|
145 |
// check for available data |
|
146 |
int available = stream.available(); |
|
147 |
if (available <= 0) { |
|
148 |
// no data available... well, let's try reading one byte |
|
149 |
// we'll see what happens then |
|
150 |
available = 1; |
|
151 |
} |
|
152 |
// check for enough room in buffer, realloc if needed |
|
153 |
// the buffer always grows in size 2x minimum |
|
154 |
if (off + available > length) { |
|
155 |
length = off*2; |
|
156 |
if (off + available > length) { |
|
157 |
length = available+off; |
|
158 |
} |
|
159 |
byte[] oldBuf = buf; |
|
160 |
buf = new byte[length]; |
|
161 |
System.arraycopy(oldBuf, 0, buf, 0, off); |
|
162 |
} |
|
163 |
// now read the data |
|
164 |
int result = stream.read(buf, off, available); |
|
165 |
if (result < 0) { |
|
166 |
break; |
|
167 |
} |
|
168 |
off += result; |
|
169 |
} |
|
170 |
synchronized(SplashScreen.class) { |
|
171 |
checkVisible(); |
|
172 |
if (!_setImageData(splashPtr, buf)) { |
|
173 |
throw new IOException("Bad image format or i/o error when loading image"); |
|
174 |
} |
|
175 |
this.imageURL = imageURL; |
|
176 |
} |
|
177 |
} |
|
178 |
||
179 |
private void checkVisible() { |
|
180 |
if (!isVisible()) { |
|
181 |
throw new IllegalStateException("no splash screen available"); |
|
182 |
} |
|
183 |
} |
|
184 |
/** |
|
185 |
* Returns the current splash screen image. |
|
186 |
* |
|
187 |
* @return URL for the current splash screen image file |
|
188 |
* @throws IllegalStateException if the splash screen has already been closed |
|
189 |
*/ |
|
190 |
public URL getImageURL() throws IllegalStateException { |
|
191 |
synchronized (SplashScreen.class) { |
|
192 |
checkVisible(); |
|
193 |
if (imageURL == null) { |
|
194 |
try { |
|
195 |
String fileName = _getImageFileName(splashPtr); |
|
196 |
String jarName = _getImageJarName(splashPtr); |
|
197 |
if (fileName != null) { |
|
198 |
if (jarName != null) { |
|
199 |
imageURL = new URL("jar:"+(new File(jarName).toURL().toString())+"!/"+fileName); |
|
200 |
} else { |
|
201 |
imageURL = new File(fileName).toURL(); |
|
202 |
} |
|
203 |
} |
|
204 |
} |
|
205 |
catch(java.net.MalformedURLException e) { |
|
3938
ef327bd847c0
6879044: Eliminate the dependency on logging from the AWT/2D/Swing classes
mchung
parents:
2
diff
changeset
|
206 |
if (log.isLoggable(PlatformLogger.FINE)) { |
ef327bd847c0
6879044: Eliminate the dependency on logging from the AWT/2D/Swing classes
mchung
parents:
2
diff
changeset
|
207 |
log.fine("MalformedURLException caught in the getImageURL() method", e); |
2 | 208 |
} |
209 |
} |
|
210 |
} |
|
211 |
return imageURL; |
|
212 |
} |
|
213 |
} |
|
214 |
||
215 |
/** |
|
216 |
* Returns the bounds of the splash screen window as a {@link Rectangle}. |
|
217 |
* This may be useful if, for example, you want to replace the splash |
|
218 |
* screen with your window at the same location. |
|
219 |
* <p> |
|
220 |
* You cannot control the size or position of the splash screen. |
|
221 |
* The splash screen size is adjusted automatically when the image changes. |
|
222 |
* |
|
223 |
* @return a {@code Rectangle} containing the splash screen bounds |
|
224 |
* @throws IllegalStateException if the splash screen has already been closed |
|
225 |
*/ |
|
226 |
public Rectangle getBounds() throws IllegalStateException { |
|
227 |
synchronized (SplashScreen.class) { |
|
228 |
checkVisible(); |
|
229 |
return _getBounds(splashPtr); |
|
230 |
} |
|
231 |
} |
|
232 |
||
233 |
/** |
|
234 |
* Returns the size of the splash screen window as a {@link Dimension}. |
|
235 |
* This may be useful if, for example, |
|
236 |
* you want to draw on the splash screen overlay surface. |
|
237 |
* <p> |
|
238 |
* You cannot control the size or position of the splash screen. |
|
239 |
* The splash screen size is adjusted automatically when the image changes. |
|
240 |
* |
|
241 |
* @return a {@link Dimension} object indicating the splash screen size |
|
242 |
* @throws IllegalStateException if the splash screen has already been closed |
|
243 |
*/ |
|
244 |
public Dimension getSize() throws IllegalStateException { |
|
245 |
return getBounds().getSize(); |
|
246 |
} |
|
247 |
||
248 |
/** |
|
249 |
* Creates a graphics context (as a {@link Graphics2D} object) for the splash |
|
250 |
* screen overlay image, which allows you to draw over the splash screen. |
|
251 |
* Note that you do not draw on the main image but on the image that is |
|
252 |
* displayed over the main image using alpha blending. Also note that drawing |
|
253 |
* on the overlay image does not necessarily update the contents of splash |
|
254 |
* screen window. You should call {@code update()} on the |
|
255 |
* <code>SplashScreen</code> when you want the splash screen to be |
|
256 |
* updated immediately. |
|
257 |
* |
|
258 |
* @return graphics context for the splash screen overlay surface |
|
259 |
* @throws IllegalStateException if the splash screen has already been closed |
|
260 |
*/ |
|
261 |
public Graphics2D createGraphics() throws IllegalStateException { |
|
262 |
synchronized (SplashScreen.class) { |
|
263 |
if (image==null) { |
|
264 |
Dimension dim = getSize(); |
|
265 |
image = new BufferedImage(dim.width, dim.height, BufferedImage.TYPE_INT_ARGB); |
|
266 |
} |
|
267 |
return image.createGraphics(); |
|
268 |
} |
|
269 |
} |
|
270 |
||
271 |
/** |
|
272 |
* Updates the splash window with current contents of the overlay image. |
|
273 |
* |
|
274 |
* @throws IllegalStateException if the overlay image does not exist; |
|
275 |
* for example, if {@code createGraphics} has never been called, |
|
276 |
* or if the splash screen has already been closed |
|
277 |
*/ |
|
278 |
public void update() throws IllegalStateException { |
|
279 |
BufferedImage image; |
|
280 |
synchronized (SplashScreen.class) { |
|
281 |
checkVisible(); |
|
282 |
image = this.image; |
|
283 |
} |
|
284 |
if (image == null) { |
|
285 |
throw new IllegalStateException("no overlay image available"); |
|
286 |
} |
|
287 |
DataBuffer buf = image.getRaster().getDataBuffer(); |
|
288 |
if (!(buf instanceof DataBufferInt)) { |
|
289 |
throw new AssertionError("Overlay image DataBuffer is of invalid type == "+buf.getClass().getName()); |
|
290 |
} |
|
291 |
int numBanks = buf.getNumBanks(); |
|
292 |
if (numBanks!=1) { |
|
293 |
throw new AssertionError("Invalid number of banks =="+numBanks+" in overlay image DataBuffer"); |
|
294 |
} |
|
295 |
if (!(image.getSampleModel() instanceof SinglePixelPackedSampleModel)) { |
|
296 |
throw new AssertionError("Overlay image has invalid sample model == "+image.getSampleModel().getClass().getName()); |
|
297 |
} |
|
298 |
SinglePixelPackedSampleModel sm = (SinglePixelPackedSampleModel)image.getSampleModel(); |
|
299 |
int scanlineStride = sm.getScanlineStride(); |
|
300 |
Rectangle rect = image.getRaster().getBounds(); |
|
301 |
// Note that we steal the data array here, but just for reading |
|
302 |
// so we do not need to mark the DataBuffer dirty... |
|
303 |
int[] data = SunWritableRaster.stealData((DataBufferInt)buf, 0); |
|
304 |
synchronized(SplashScreen.class) { |
|
305 |
checkVisible(); |
|
306 |
_update(splashPtr, data, rect.x, rect.y, rect.width, rect.height, scanlineStride); |
|
307 |
} |
|
308 |
} |
|
309 |
||
310 |
/** |
|
311 |
* Hides the splash screen, closes the window, and releases all associated |
|
312 |
* resources. |
|
313 |
* |
|
314 |
* @throws IllegalStateException if the splash screen has already been closed |
|
315 |
*/ |
|
316 |
public void close() throws IllegalStateException { |
|
317 |
synchronized (SplashScreen.class) { |
|
318 |
checkVisible(); |
|
319 |
_close(splashPtr); |
|
320 |
image = null; |
|
321 |
wasClosed = true; |
|
322 |
theInstance = null; |
|
323 |
} |
|
324 |
} |
|
325 |
||
326 |
||
327 |
/** |
|
328 |
* Determines whether the splash screen is visible. The splash screen may |
|
329 |
* be hidden using {@link #close()}, it is also hidden automatically when |
|
330 |
* the first AWT/Swing window is made visible. |
|
331 |
* |
|
332 |
* @return true if the splash screen is visible (has not been closed yet), |
|
333 |
* false otherwise |
|
334 |
*/ |
|
335 |
public boolean isVisible() { |
|
336 |
synchronized (SplashScreen.class) { |
|
337 |
return !wasClosed && _isVisible(splashPtr); |
|
338 |
} |
|
339 |
} |
|
340 |
||
341 |
private BufferedImage image; // overlay image |
|
342 |
||
343 |
private final long splashPtr; // pointer to native Splash structure |
|
344 |
private static boolean wasClosed = false; |
|
345 |
||
346 |
private URL imageURL; |
|
347 |
||
348 |
/** |
|
349 |
* The instance reference for the singleton. |
|
350 |
* (<code>null</code> if no instance exists yet.) |
|
351 |
* |
|
352 |
* @see #getSplashScreen |
|
353 |
* @see #close |
|
354 |
*/ |
|
355 |
private static SplashScreen theInstance = null; |
|
356 |
||
3938
ef327bd847c0
6879044: Eliminate the dependency on logging from the AWT/2D/Swing classes
mchung
parents:
2
diff
changeset
|
357 |
private static final PlatformLogger log = PlatformLogger.getLogger("java.awt.SplashScreen"); |
2 | 358 |
|
359 |
private native static void _update(long splashPtr, int[] data, int x, int y, int width, int height, int scanlineStride); |
|
360 |
private native static boolean _isVisible(long splashPtr); |
|
361 |
private native static Rectangle _getBounds(long splashPtr); |
|
362 |
private native static long _getInstance(); |
|
363 |
private native static void _close(long splashPtr); |
|
364 |
private native static String _getImageFileName(long splashPtr); |
|
365 |
private native static String _getImageJarName(long SplashPtr); |
|
366 |
private native static boolean _setImageData(long SplashPtr, byte[] data); |
|
367 |
||
368 |
}; |