1 /* 2 * Copyright (c) 1997, 2009, 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; 27 28 import java.awt.AWTException; 29 import java.awt.BufferCapabilities; 30 import java.awt.BufferCapabilities.FlipContents; 31 import java.awt.Component; 32 import java.awt.Toolkit; 33 import java.awt.GraphicsConfiguration; 34 import java.awt.GraphicsDevice; 35 import java.awt.Image; 36 import java.awt.ImageCapabilities; 37 import java.awt.Transparency; 38 import java.awt.image.BufferedImage; 39 import java.awt.image.ColorModel; 40 import java.awt.image.DirectColorModel; 41 import java.awt.image.VolatileImage; 42 import java.awt.image.WritableRaster; 43 import java.awt.geom.AffineTransform; 44 import java.awt.Rectangle; 45 import sun.java2d.Disposer; 46 import sun.java2d.DisposerRecord; 47 import sun.java2d.SurfaceData; 48 import sun.java2d.loops.RenderLoops; 49 import sun.java2d.loops.SurfaceType; 50 import sun.java2d.loops.CompositeType; 51 import sun.java2d.x11.X11SurfaceData; 52 import sun.awt.image.OffScreenImage; 53 import sun.awt.image.SunVolatileImage; 54 import sun.awt.image.SurfaceManager; 55 import sun.awt.X11ComponentPeer; 56 57 /** 58 * This is an implementation of a GraphicsConfiguration object for a 59 * single X11 visual. 60 * 61 * @see GraphicsEnvironment 62 * @see GraphicsDevice 63 */ 64 public class X11GraphicsConfig extends GraphicsConfiguration 65 implements SurfaceManager.ProxiedGraphicsConfig 66 { 67 protected X11GraphicsDevice screen; 68 protected int visual; 69 int depth; 70 int colormap; 71 ColorModel colorModel; 72 long aData; 73 boolean doubleBuffer; 74 private Object disposerReferent = new Object(); 75 private BufferCapabilities bufferCaps; 76 private static ImageCapabilities imageCaps = 77 new ImageCapabilities(X11SurfaceData.isAccelerationEnabled()); 78 79 // will be set on native level from init() 80 protected int bitsPerPixel; 81 82 protected SurfaceType surfaceType; 83 84 public RenderLoops solidloops; 85 86 public static X11GraphicsConfig getConfig(X11GraphicsDevice device, 87 int visualnum, int depth, 88 int colormap, 89 boolean doubleBuffer) 90 { 91 return new X11GraphicsConfig(device, visualnum, depth, colormap, doubleBuffer); 92 } 93 94 /* 95 * Note this method is currently here for backward compatability 96 * as this was the method used in jdk 1.2 beta4 to create the 97 * X11GraphicsConfig objects. Java3D code had called this method 98 * explicitly so without this, if a user tries to use JDK1.2 fcs 99 * with Java3D beta1, a NoSuchMethod execption is thrown and 100 * the program exits. REMOVE this method after Java3D fcs is 101 * released! 102 */ 103 public static X11GraphicsConfig getConfig(X11GraphicsDevice device, 104 int visualnum, int depth, 105 int colormap, int type) 106 { 107 return new X11GraphicsConfig(device, visualnum, depth, colormap, false); 108 } 109 110 private native int getNumColors(); 111 private native void init(int visualNum, int screen); 112 private native ColorModel makeColorModel(); 113 114 protected X11GraphicsConfig(X11GraphicsDevice device, 115 int visualnum, int depth, 116 int colormap, boolean doubleBuffer) 117 { 118 this.screen = device; 119 this.visual = visualnum; 120 this.doubleBuffer = doubleBuffer; 121 this.depth = depth; 122 this.colormap = colormap; 123 init (visualnum, screen.getScreen()); 124 125 // add a record to the Disposer so that we destroy the native 126 // AwtGraphicsConfigData when this object goes away (i.e. after a 127 // display change event) 128 long x11CfgData = getAData(); 129 Disposer.addRecord(disposerReferent, 130 new X11GCDisposerRecord(x11CfgData)); 131 } 132 133 /** 134 * Return the graphics device associated with this configuration. 135 */ 136 public GraphicsDevice getDevice() { 137 return screen; 138 } 139 140 /** 141 * Returns the visual id associated with this configuration. 142 */ 143 public int getVisual () { 144 return visual; 145 } 146 147 148 /** 149 * Returns the depth associated with this configuration. 150 */ 151 public int getDepth () { 152 return depth; 153 } 154 155 /** 156 * Returns the colormap associated with this configuration. 157 */ 158 public int getColormap () { 159 return colormap; 160 } 161 162 /** 163 * Returns a number of bits allocated per pixel 164 * (might be different from depth) 165 */ 166 public int getBitsPerPixel() { 167 return bitsPerPixel; 168 } 169 170 public synchronized SurfaceType getSurfaceType() { 171 if (surfaceType != null) { 172 return surfaceType; 173 } 174 175 surfaceType = X11SurfaceData.getSurfaceType(this, Transparency.OPAQUE); 176 return surfaceType; 177 } 178 179 public Object getProxyKey() { 180 return screen.getProxyKeyFor(getSurfaceType()); 181 } 182 183 /** 184 * Return the RenderLoops this type of destination uses for 185 * solid fills and strokes. 186 */ 187 public synchronized RenderLoops getSolidLoops(SurfaceType stype) { 188 if (solidloops == null) { 189 solidloops = SurfaceData.makeRenderLoops(SurfaceType.OpaqueColor, 190 CompositeType.SrcNoEa, 191 stype); 192 } 193 return solidloops; 194 } 195 196 public BufferedImage createCompatibleImage(int width, int height) { 197 ColorModel model = getColorModel(); 198 WritableRaster raster = 199 model.createCompatibleWritableRaster(width, height); 200 return new BufferedImage(model, raster, 201 model.isAlphaPremultiplied(), null); 202 } 203 204 /** 205 * Returns the color model associated with this configuration. 206 */ 207 public synchronized ColorModel getColorModel() { 208 if (colorModel == null) { 209 // Force SystemColors to be resolved before we create the CM 210 java.awt.SystemColor.window.getRGB(); 211 // This method, makeColorModel(), can return null if the 212 // toolkit is not initialized yet. 213 // The toolkit will then call back to this routine after it 214 // is initialized and makeColorModel() should return a non-null 215 // colorModel. 216 colorModel = makeColorModel(); 217 if (colorModel == null) 218 colorModel = Toolkit.getDefaultToolkit ().getColorModel (); 219 } 220 221 return colorModel; 222 } 223 224 /** 225 * Returns the color model associated with this configuration that 226 * supports the specified transparency. 227 */ 228 public ColorModel getColorModel(int transparency) { 229 switch (transparency) { 230 case Transparency.OPAQUE: 231 return getColorModel(); 232 case Transparency.BITMASK: 233 return new DirectColorModel(25, 0xff0000, 0xff00, 0xff, 0x1000000); 234 case Transparency.TRANSLUCENT: 235 return ColorModel.getRGBdefault(); 236 default: 237 return null; 238 } 239 } 240 241 /** 242 * Returns the default Transform for this configuration. This 243 * Transform is typically the Identity transform for most normal 244 * screens. Device coordinates for screen and printer devices will 245 * have the origin in the upper left-hand corner of the target region of 246 * the device, with X coordinates 247 * increasing to the right and Y coordinates increasing downwards. 248 * For image buffers, this Transform will be the Identity transform. 249 */ 250 public AffineTransform getDefaultTransform() { 251 return new AffineTransform(); 252 } 253 254 /** 255 * 256 * Returns a Transform that can be composed with the default Transform 257 * of a Graphics2D so that 72 units in user space will equal 1 inch 258 * in device space. 259 * Given a Graphics2D, g, one can reset the transformation to create 260 * such a mapping by using the following pseudocode: 261 * <pre> 262 * GraphicsConfiguration gc = g.getGraphicsConfiguration(); 263 * 264 * g.setTransform(gc.getDefaultTransform()); 265 * g.transform(gc.getNormalizingTransform()); 266 * </pre> 267 * Note that sometimes this Transform will be identity (e.g. for 268 * printers or metafile output) and that this Transform is only 269 * as accurate as the information supplied by the underlying system. 270 * For image buffers, this Transform will be the Identity transform, 271 * since there is no valid distance measurement. 272 */ 273 public AffineTransform getNormalizingTransform() { 274 double xscale = getXResolution(screen.getScreen()) / 72.0; 275 double yscale = getYResolution(screen.getScreen()) / 72.0; 276 return new AffineTransform(xscale, 0.0, 0.0, yscale, 0.0, 0.0); 277 } 278 279 private native double getXResolution(int screen); 280 private native double getYResolution(int screen); 281 282 public long getAData() { 283 return aData; 284 } 285 286 public String toString() { 287 return ("X11GraphicsConfig[dev="+screen+ 288 ",vis=0x"+Integer.toHexString(visual)+ 289 "]"); 290 } 291 292 /* 293 * Initialize JNI field and method IDs for fields that may be 294 * accessed from C. 295 */ 296 private static native void initIDs(); 297 298 static { 299 initIDs (); 300 } 301 302 public Rectangle getBounds() { 303 return pGetBounds(screen.getScreen()); 304 } 305 306 public native Rectangle pGetBounds(int screenNum); 307 308 private static class XDBECapabilities extends BufferCapabilities { 309 public XDBECapabilities() { 310 super(imageCaps, imageCaps, FlipContents.UNDEFINED); 311 } 312 } 313 314 public BufferCapabilities getBufferCapabilities() { 315 if (bufferCaps == null) { 316 if (doubleBuffer) { 317 bufferCaps = new XDBECapabilities(); 318 } else { 319 bufferCaps = super.getBufferCapabilities(); 320 } 321 } 322 return bufferCaps; 323 } 324 325 public ImageCapabilities getImageCapabilities() { 326 return imageCaps; 327 } 328 329 public boolean isDoubleBuffered() { 330 return doubleBuffer; 331 } 332 333 private static native void dispose(long x11ConfigData); 334 335 private static class X11GCDisposerRecord implements DisposerRecord { 336 private long x11ConfigData; 337 public X11GCDisposerRecord(long x11CfgData) { 338 this.x11ConfigData = x11CfgData; 339 } 340 public synchronized void dispose() { 341 if (x11ConfigData != 0L) { 342 X11GraphicsConfig.dispose(x11ConfigData); 343 x11ConfigData = 0L; 344 } 345 } 346 } 347 348 /** 349 * The following methods are invoked from {M,X}Toolkit.java and 350 * X11ComponentPeer.java rather than having the X11-dependent 351 * implementations hardcoded in those classes. This way the appropriate 352 * actions are taken based on the peer's GraphicsConfig, whether it is 353 * an X11GraphicsConfig or a GLXGraphicsConfig. 354 */ 355 356 /** 357 * Creates a new SurfaceData that will be associated with the given 358 * X11ComponentPeer. 359 */ 360 public SurfaceData createSurfaceData(X11ComponentPeer peer) { 361 return X11SurfaceData.createData(peer); 362 } 363 364 /** 365 * Creates a new hidden-acceleration image of the given width and height 366 * that is associated with the target Component. 367 */ 368 public Image createAcceleratedImage(Component target, 369 int width, int height) 370 { 371 // As of 1.7 we no longer create pmoffscreens here... 372 ColorModel model = getColorModel(Transparency.OPAQUE); 373 WritableRaster wr = 374 model.createCompatibleWritableRaster(width, height); 375 return new OffScreenImage(target, model, wr, 376 model.isAlphaPremultiplied()); 377 } 378 379 /** 380 * The following methods correspond to the multibuffering methods in 381 * X11ComponentPeer.java... 382 */ 383 384 private native long createBackBuffer(long window, int swapAction); 385 private native void swapBuffers(long window, int swapAction); 386 387 /** 388 * Attempts to create an XDBE-based backbuffer for the given peer. If 389 * the requested configuration is not natively supported, an AWTException 390 * is thrown. Otherwise, if the backbuffer creation is successful, a 391 * handle to the native backbuffer is returned. 392 */ 393 public long createBackBuffer(X11ComponentPeer peer, 394 int numBuffers, BufferCapabilities caps) 395 throws AWTException 396 { 397 if (!X11GraphicsDevice.isDBESupported()) { 398 throw new AWTException("Page flipping is not supported"); 399 } 400 if (numBuffers > 2) { 401 throw new AWTException( 402 "Only double or single buffering is supported"); 403 } 404 BufferCapabilities configCaps = getBufferCapabilities(); 405 if (!configCaps.isPageFlipping()) { 406 throw new AWTException("Page flipping is not supported"); 407 } 408 409 long window = peer.getContentWindow(); 410 int swapAction = getSwapAction(caps.getFlipContents()); 411 412 return createBackBuffer(window, swapAction); 413 } 414 415 /** 416 * Destroys the backbuffer object represented by the given handle value. 417 */ 418 public native void destroyBackBuffer(long backBuffer); 419 420 /** 421 * Creates a VolatileImage that essentially wraps the target Component's 422 * backbuffer, using the provided backbuffer handle. 423 */ 424 public VolatileImage createBackBufferImage(Component target, 425 long backBuffer) 426 { 427 // it is possible for the component to have size 0x0, adjust it to 428 // be at least 1x1 to avoid IAE 429 int w = Math.max(1, target.getWidth()); 430 int h = Math.max(1, target.getHeight()); 431 return new SunVolatileImage(target, 432 w, h, 433 Long.valueOf(backBuffer)); 434 } 435 436 /** 437 * Performs the native XDBE flip operation for the given target Component. 438 */ 439 public void flip(X11ComponentPeer peer, 440 Component target, VolatileImage xBackBuffer, 441 int x1, int y1, int x2, int y2, 442 BufferCapabilities.FlipContents flipAction) 443 { 444 long window = peer.getContentWindow(); 445 int swapAction = getSwapAction(flipAction); 446 swapBuffers(window, swapAction); 447 } 448 449 /** 450 * Maps the given FlipContents constant to the associated XDBE swap 451 * action constant. 452 */ 453 private static int getSwapAction( 454 BufferCapabilities.FlipContents flipAction) { 455 if (flipAction == BufferCapabilities.FlipContents.BACKGROUND) { 456 return 0x01; 457 } else if (flipAction == BufferCapabilities.FlipContents.PRIOR) { 458 return 0x02; 459 } else if (flipAction == BufferCapabilities.FlipContents.COPIED) { 460 return 0x03; 461 } else { 462 return 0x00; // UNDEFINED 463 } 464 } 465 466 /* 467 @Override 468 */ 469 public boolean isTranslucencyCapable() { 470 return isTranslucencyCapable(getAData()); 471 } 472 473 private native boolean isTranslucencyCapable(long x11ConfigData); 474 }