| /* ComponentGraphics.java -- |
| Copyright (C) 2006 Free Software Foundation, Inc. |
| |
| This file is part of GNU Classpath. |
| |
| GNU Classpath is free software; you can redistribute it and/or modify |
| it under the terms of the GNU General Public License as published by |
| the Free Software Foundation; either version 2, or (at your option) |
| any later version. |
| |
| GNU Classpath is distributed in the hope that it will be useful, but |
| WITHOUT ANY WARRANTY; without even the implied warranty of |
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| General Public License for more details. |
| |
| You should have received a copy of the GNU General Public License |
| along with GNU Classpath; see the file COPYING. If not, write to the |
| Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA |
| 02110-1301 USA. |
| |
| Linking this library statically or dynamically with other modules is |
| making a combined work based on this library. Thus, the terms and |
| conditions of the GNU General Public License cover the whole |
| combination. |
| |
| As a special exception, the copyright holders of this library give you |
| permission to link this library with independent modules to produce an |
| executable, regardless of the license terms of these independent |
| modules, and to copy and distribute the resulting executable under |
| terms of your choice, provided that you also meet, for each linked |
| independent module, the terms and conditions of the license of that |
| module. An independent module is a module which is not derived from |
| or based on this library. If you modify this library, you may extend |
| this exception to your version of the library, but you are not |
| obligated to do so. If you do not wish to do so, delete this |
| exception statement from your version. */ |
| |
| |
| package gnu.java.awt.peer.gtk; |
| |
| import java.awt.Color; |
| import java.awt.Graphics; |
| import java.awt.Graphics2D; |
| import java.awt.GraphicsConfiguration; |
| import java.awt.Image; |
| import java.awt.Rectangle; |
| import java.awt.Shape; |
| import java.awt.Toolkit; |
| import java.awt.font.GlyphVector; |
| import java.awt.geom.AffineTransform; |
| import java.awt.geom.Rectangle2D; |
| import java.awt.image.BufferedImage; |
| import java.awt.image.ImageObserver; |
| import java.awt.image.ImageProducer; |
| import java.awt.image.RenderedImage; |
| import gnu.classpath.Pointer; |
| |
| /** |
| * ComponentGraphics - context for drawing directly to a component, |
| * as this is an X drawable, it requires that we use GTK locks. |
| * |
| * This context draws directly to the drawable and requires xrender. |
| */ |
| public class ComponentGraphics extends CairoGraphics2D |
| { |
| private static final boolean hasXRenderExtension = hasXRender(); |
| |
| private GtkComponentPeer component; |
| protected long cairo_t; |
| |
| private static ThreadLocal hasLock = new ThreadLocal(); |
| private static Integer ONE = Integer.valueOf(1); |
| |
| private void lock() |
| { |
| Integer i = (Integer) hasLock.get(); |
| if (i == null) |
| { |
| start_gdk_drawing(); |
| hasLock.set(ONE); |
| } |
| else |
| hasLock.set(Integer.valueOf(i.intValue() + 1)); |
| } |
| |
| private void unlock() |
| { |
| Integer i = (Integer) hasLock.get(); |
| if (i == null) |
| throw new IllegalStateException(); |
| if (i == ONE) |
| { |
| hasLock.set(null); |
| end_gdk_drawing(); |
| } |
| else |
| hasLock.set(Integer.valueOf(i.intValue() - 1)); |
| } |
| |
| ComponentGraphics() |
| { |
| } |
| |
| private ComponentGraphics(GtkComponentPeer component) |
| { |
| this.component = component; |
| cairo_t = initState(component); |
| setup( cairo_t ); |
| Rectangle bounds = component.awtComponent.getBounds(); |
| setClip( new Rectangle( 0, 0, bounds.width, bounds.height) ); |
| setBackground(component.awtComponent.getBackground()); |
| setColor(component.awtComponent.getForeground()); |
| } |
| |
| private ComponentGraphics(ComponentGraphics cg) |
| { |
| component = cg.component; |
| cairo_t = initState(component); |
| copy( cg, cairo_t ); |
| Rectangle bounds = component.awtComponent.getBounds(); |
| setClip( new Rectangle( 0, 0, bounds.width, bounds.height) ); |
| setBackground(component.awtComponent.getBackground()); |
| setColor(component.awtComponent.getForeground()); |
| } |
| |
| /** |
| * Creates a cairo_t for the component surface and return it. |
| */ |
| private native long initState(GtkComponentPeer component); |
| |
| /** |
| * Destroys the component surface and calls dispose on the cairo |
| * graphics2d to destroy any super class resources. |
| */ |
| public void dispose() |
| { |
| super.dispose(); |
| disposeSurface(nativePointer); |
| } |
| |
| /** |
| * Destroys the component surface. |
| */ |
| private native void disposeSurface(long nativePointer); |
| |
| /** |
| * Creates a cairo_t for a volatile image |
| */ |
| protected native long initFromVolatile( long pixmapPtr, int width, int height); |
| |
| /** |
| * Grab lock |
| */ |
| private native void start_gdk_drawing(); |
| |
| /** |
| * Release lock |
| */ |
| private native void end_gdk_drawing(); |
| |
| /** |
| * Query if the system has the XRender extension. |
| */ |
| public static native boolean hasXRender(); |
| |
| /** |
| * This is a utility method (used by GtkComponentPeer) for grabbing the |
| * image of a component. |
| */ |
| private static native Pointer nativeGrab(GtkComponentPeer component); |
| |
| private native void copyAreaNative(GtkComponentPeer component, int x, int y, |
| int width, int height, int dx, int dy); |
| |
| private native void drawVolatile(GtkComponentPeer component, |
| long vimg, int x, int y, |
| int width, int height, int cx, int cy, |
| int cw, int ch); |
| |
| /** |
| * Not really related (moveme?). Utility method used by GtkComponent. |
| */ |
| public static GtkImage grab( GtkComponentPeer component ) |
| { |
| return new GtkImage( nativeGrab( component ) ); |
| } |
| |
| /** |
| * Returns a Graphics2D object for a component, either an instance of this |
| * class (if xrender is supported), or a context which copies. |
| */ |
| public static Graphics2D getComponentGraphics(GtkComponentPeer component) |
| { |
| if( hasXRenderExtension ) |
| return new ComponentGraphics(component); |
| |
| Rectangle r = component.awtComponent.getBounds(); |
| return new ComponentGraphicsCopy(r.width, r.height, component); |
| } |
| |
| public GraphicsConfiguration getDeviceConfiguration() |
| { |
| return component.getGraphicsConfiguration(); |
| } |
| |
| public Graphics create() |
| { |
| return new ComponentGraphics(this); |
| } |
| |
| protected Rectangle2D getRealBounds() |
| { |
| return component.awtComponent.getBounds(); |
| } |
| |
| public void copyAreaImpl(int x, int y, int width, int height, int dx, int dy) |
| { |
| copyAreaNative(component, x, y, width, height, dx, dy); |
| } |
| |
| /** |
| * Overloaded methods that do actual drawing need to enter the gdk threads |
| * and also do certain things before and after. |
| */ |
| public void draw(Shape s) |
| { |
| lock(); |
| try |
| { |
| super.draw(s); |
| } |
| finally |
| { |
| unlock(); |
| } |
| } |
| |
| public void fill(Shape s) |
| { |
| lock(); |
| try |
| { |
| super.fill(s); |
| } |
| finally |
| { |
| unlock(); |
| } |
| } |
| |
| public void drawRenderedImage(RenderedImage image, AffineTransform xform) |
| { |
| lock(); |
| try |
| { |
| super.drawRenderedImage(image, xform); |
| } |
| finally |
| { |
| unlock(); |
| } |
| } |
| |
| protected boolean drawImage(Image img, AffineTransform xform, |
| Color bgcolor, ImageObserver obs) |
| { |
| boolean rv; |
| lock(); |
| try |
| { |
| rv = super.drawImage(img, xform, bgcolor, obs); |
| } |
| finally |
| { |
| unlock(); |
| } |
| return rv; |
| } |
| |
| public void drawGlyphVector(GlyphVector gv, float x, float y) |
| { |
| lock(); |
| try |
| { |
| super.drawGlyphVector(gv, x, y); |
| } |
| finally |
| { |
| unlock(); |
| } |
| } |
| |
| public boolean drawImage(Image img, int x, int y, ImageObserver observer) |
| { |
| // If it is a GtkVolatileImage with an "easy" transform then |
| // draw directly. Always pass a BufferedImage to super to avoid |
| // deadlock (see Note in CairoGraphics.drawImage()). |
| if (img instanceof GtkVolatileImage) |
| { |
| GtkVolatileImage vimg = (GtkVolatileImage) img; |
| int type = transform.getType(); |
| if ((type == AffineTransform.TYPE_IDENTITY |
| || type == AffineTransform.TYPE_TRANSLATION) |
| && (clip == null || clip instanceof Rectangle2D)) |
| { |
| Rectangle2D r = (Rectangle2D) clip; |
| if (r == null) |
| r = getRealBounds(); |
| x += transform.getTranslateX(); |
| y += transform.getTranslateY(); |
| drawVolatile(component, vimg.nativePointer, |
| x, y, vimg.width, vimg.height, |
| (int) (r.getX() + transform.getTranslateX()), |
| (int) (r.getY() + transform.getTranslateY()), |
| (int) r.getWidth(), |
| (int) r.getHeight()); |
| return true; |
| } |
| else |
| return super.drawImage(vimg.getSnapshot(), x, y, observer); |
| } |
| |
| BufferedImage bimg; |
| if (img instanceof BufferedImage) |
| bimg = (BufferedImage) img; |
| else |
| { |
| ImageProducer source = img.getSource(); |
| if (source == null) |
| return false; |
| bimg = (BufferedImage) Toolkit.getDefaultToolkit().createImage(source); |
| } |
| return super.drawImage(bimg, x, y, observer); |
| } |
| |
| public boolean drawImage(Image img, int x, int y, int width, int height, |
| ImageObserver observer) |
| { |
| // If it is a GtkVolatileImage with an "easy" transform then |
| // draw directly. Always pass a BufferedImage to super to avoid |
| // deadlock (see Note in CairoGraphics.drawImage()). |
| if (img instanceof GtkVolatileImage |
| && (clip == null || clip instanceof Rectangle2D)) |
| { |
| GtkVolatileImage vimg = (GtkVolatileImage) img; |
| int type = transform.getType(); |
| if ((type == AffineTransform.TYPE_IDENTITY |
| || type == AffineTransform.TYPE_TRANSLATION) |
| && (clip == null || clip instanceof Rectangle2D)) |
| { |
| Rectangle2D r = (Rectangle2D) clip; |
| if (r == null) |
| r = getRealBounds(); |
| x += transform.getTranslateX(); |
| y += transform.getTranslateY(); |
| drawVolatile(component, vimg.nativePointer, |
| x, y, width, height, |
| (int) (r.getX() + transform.getTranslateX()), |
| (int) (r.getY() + transform.getTranslateY()), |
| (int) r.getWidth(), |
| (int) r.getHeight()); |
| return true; |
| } |
| else |
| return super.drawImage(vimg.getSnapshot(), x, y, |
| width, height, observer); |
| } |
| |
| BufferedImage bimg; |
| if (img instanceof BufferedImage) |
| bimg = (BufferedImage) img; |
| else |
| { |
| ImageProducer source = img.getSource(); |
| if (source == null) |
| return false; |
| bimg = (BufferedImage) Toolkit.getDefaultToolkit().createImage(source); |
| } |
| return super.drawImage(bimg, x, y, width, height, observer); |
| } |
| |
| public void drawLine(int x1, int y1, int x2, int y2) |
| { |
| lock(); |
| try |
| { |
| super.drawLine(x1, y1, x2, y2); |
| } |
| finally |
| { |
| unlock(); |
| } |
| } |
| |
| public void drawRect(int x, int y, int width, int height) |
| { |
| lock(); |
| try |
| { |
| super.drawRect(x, y, width, height); |
| } |
| finally |
| { |
| unlock(); |
| } |
| } |
| |
| public void fillRect(int x, int y, int width, int height) |
| { |
| lock(); |
| try |
| { |
| super.fillRect(x, y, width, height); |
| } |
| finally |
| { |
| unlock(); |
| } |
| } |
| |
| public void setClip(Shape s) |
| { |
| lock(); |
| try |
| { |
| super.setClip(s); |
| } |
| finally |
| { |
| unlock(); |
| } |
| } |
| |
| } |
| |