diff options
author | Guilhem Lavaux <guilhem@kaffe.org> | 2006-07-09 16:59:05 +0000 |
---|---|---|
committer | Guilhem Lavaux <guilhem@kaffe.org> | 2006-07-09 16:59:05 +0000 |
commit | 8f2887fc8c74aae0d541cbd59ea36c37d420267d (patch) | |
tree | adfecf70948384fcc6aa9cae41103dc4551d1b53 /gnu/java/awt/peer | |
parent | 4714fb23de2d811f49438611ac0d13ccd302e1ea (diff) | |
download | classpath-8f2887fc8c74aae0d541cbd59ea36c37d420267d.tar.gz |
2006-07-09 Guilhem Lavaux <guilhem@kaffe.org>
* Merged HEAD as of 2006-06-09 0:00.
Diffstat (limited to 'gnu/java/awt/peer')
39 files changed, 6967 insertions, 1369 deletions
diff --git a/gnu/java/awt/peer/ClasspathTextLayoutPeer.java b/gnu/java/awt/peer/ClasspathTextLayoutPeer.java deleted file mode 100644 index 70df2ef74..000000000 --- a/gnu/java/awt/peer/ClasspathTextLayoutPeer.java +++ /dev/null @@ -1,104 +0,0 @@ -/* ClasspathTextLayoutPeer.java - Copyright (C) 2003 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; - -import java.awt.Graphics2D; -import java.awt.Shape; -import java.awt.font.TextHitInfo; -import java.awt.font.TextLayout; -import java.awt.geom.AffineTransform; -import java.awt.geom.Rectangle2D; - -/** - * @author Graydon Hoare - */ - -public interface ClasspathTextLayoutPeer -{ - TextHitInfo getStrongCaret (TextHitInfo hit1, - TextHitInfo hit2); - - void draw (Graphics2D g2, float x, float y); - - byte getBaseline (); - - boolean isLeftToRight (); - boolean isVertical (); - - float getAdvance (); - float getAscent (); - float getDescent (); - float getLeading (); - - int getCharacterCount (); - byte getCharacterLevel (int index); - - float[] getBaselineOffsets (); - Shape getBlackBoxBounds (int firstEndpoint, int secondEndpoint); - Rectangle2D getBounds (); - - float[] getCaretInfo (TextHitInfo hit, Rectangle2D bounds); - Shape getCaretShape (TextHitInfo hit, Rectangle2D bounds); - Shape[] getCaretShapes (int offset, Rectangle2D bounds, - TextLayout.CaretPolicy policy); - - Shape getLogicalHighlightShape (int firstEndpoint, int secondEndpoint, - Rectangle2D bounds); - int[] getLogicalRangesForVisualSelection (TextHitInfo firstEndpoint, - TextHitInfo secondEndpoint); - - TextHitInfo getNextLeftHit (int offset, TextLayout.CaretPolicy policy); - TextHitInfo getNextRightHit (int offset, TextLayout.CaretPolicy policy); - TextHitInfo hitTestChar (float x, float y, Rectangle2D bounds); - TextHitInfo getVisualOtherHit (TextHitInfo hit); - - float getVisibleAdvance (); - Shape getOutline (AffineTransform tx); - Shape getVisualHighlightShape (TextHitInfo firstEndpoint, - TextHitInfo secondEndpoint, - Rectangle2D bounds); - - TextLayout getJustifiedLayout (float justificationWidth); - void handleJustify (float justificationWidth); - - Object clone (); - int hashCode (); - boolean equals (ClasspathTextLayoutPeer tl); - String toString (); -} diff --git a/gnu/java/awt/peer/gtk/CairoGraphics2D.java b/gnu/java/awt/peer/gtk/CairoGraphics2D.java index dfebd995b..61871ccbc 100644 --- a/gnu/java/awt/peer/gtk/CairoGraphics2D.java +++ b/gnu/java/awt/peer/gtk/CairoGraphics2D.java @@ -38,14 +38,13 @@ exception statement from your version. */ package gnu.java.awt.peer.gtk; -import gnu.classpath.Configuration; import gnu.java.awt.ClasspathToolkit; import java.awt.AlphaComposite; +import java.awt.AWTPermission; import java.awt.BasicStroke; import java.awt.Color; import java.awt.Composite; -import java.awt.Dimension; import java.awt.Font; import java.awt.FontMetrics; import java.awt.GradientPaint; @@ -63,9 +62,10 @@ import java.awt.TexturePaint; import java.awt.Toolkit; import java.awt.font.FontRenderContext; import java.awt.font.GlyphVector; +import java.awt.font.TextLayout; import java.awt.geom.AffineTransform; import java.awt.geom.Arc2D; -import java.awt.geom.Line2D; +import java.awt.geom.Area; import java.awt.geom.GeneralPath; import java.awt.geom.NoninvertibleTransformException; import java.awt.geom.PathIterator; @@ -76,12 +76,11 @@ import java.awt.image.AffineTransformOp; import java.awt.image.BufferedImage; import java.awt.image.BufferedImageOp; import java.awt.image.ColorModel; -import java.awt.image.CropImageFilter; import java.awt.image.DataBuffer; import java.awt.image.DataBufferInt; import java.awt.image.DirectColorModel; -import java.awt.image.FilteredImageSource; import java.awt.image.ImageObserver; +import java.awt.image.ImageProducer; import java.awt.image.ImagingOpException; import java.awt.image.MultiPixelPackedSampleModel; import java.awt.image.Raster; @@ -93,7 +92,6 @@ import java.awt.image.renderable.RenderableImage; import java.text.AttributedCharacterIterator; import java.util.HashMap; import java.util.Map; -import java.util.Stack; /** * This is an abstract implementation of Graphics2D on Cairo. @@ -240,13 +238,10 @@ public abstract class CairoGraphics2D extends Graphics2D bg = new Color(g.bg.getRGB()); } - if (g.clip == null) - clip = null; - else - clip = new Rectangle(g.getClipBounds()); + clip = g.getClip(); if (g.transform == null) - transform = new AffineTransform(); + transform = null; else transform = new AffineTransform(g.transform); @@ -256,7 +251,8 @@ public abstract class CairoGraphics2D extends Graphics2D setBackground(bg); setPaint(paint); setStroke(stroke); - setTransform(transform); + setTransformImpl(transform); + setClip(clip); } /** @@ -274,8 +270,8 @@ public abstract class CairoGraphics2D extends Graphics2D * they have additional native structures. */ public void dispose() - { - disposeNative(); + { + disposeNative(nativePointer); nativePointer = 0; } @@ -303,7 +299,7 @@ public abstract class CairoGraphics2D extends Graphics2D /** * Dispose of allocate native resouces. */ - public native void disposeNative(); + public native void disposeNative(long pointer); /** * Draw pixels as an RGBA int matrix @@ -311,119 +307,165 @@ public abstract class CairoGraphics2D extends Graphics2D * @param stride - stride of the array width * @param i2u - affine transform array */ - private native void drawPixels(int[] pixels, int w, int h, int stride, - double[] i2u); + private native void drawPixels(long pointer, int[] pixels, int w, int h, + int stride, double[] i2u, double alpha); - private native void setGradient(double x1, double y1, double x2, double y2, + private native void setGradient(long pointer, double x1, double y1, + double x2, double y2, int r1, int g1, int b1, int a1, int r2, int g2, int b2, int a2, boolean cyclic); - private native void setTexturePixels(int[] pixels, int w, int h, int stride); + private native void setTexturePixels(long pointer, int[] pixels, int w, + int h, int stride); /** * Set the current transform matrix */ - private native void cairoSetMatrix(double[] m); + private native void cairoSetMatrix(long pointer, double[] m); /** * Set the compositing operator */ - private native void cairoSetOperator(int cairoOperator); + private native void cairoSetOperator(long pointer, int cairoOperator); /** * Sets the current color in RGBA as a 0.0-1.0 double */ - private native void cairoSetRGBAColor(double red, double green, + private native void cairoSetRGBAColor(long pointer, double red, double green, double blue, double alpha); /** * Sets the current winding rule in Cairo */ - private native void cairoSetFillRule(int cairoFillRule); + private native void cairoSetFillRule(long pointer, int cairoFillRule); /** * Set the line style, cap, join and miter limit. * Cap and join parameters are in the BasicStroke enumerations. */ - private native void cairoSetLine(double width, int cap, int join, double miterLimit); + private native void cairoSetLine(long pointer, double width, int cap, + int join, double miterLimit); /** * Set the dash style */ - private native void cairoSetDash(double[] dashes, int ndash, double offset); + private native void cairoSetDash(long pointer, double[] dashes, int ndash, + double offset); /* * Draws a Glyph Vector */ - native void cairoDrawGlyphVector(GdkFontPeer font, + native void cairoDrawGlyphVector(long pointer, GdkFontPeer font, float x, float y, int n, int[] codes, float[] positions); - private native void cairoRelCurveTo(double dx1, double dy1, double dx2, - double dy2, double dx3, double dy3); + private native void cairoRelCurveTo(long pointer, double dx1, double dy1, + double dx2, double dy2, double dx3, + double dy3); /** * Appends a rectangle to the current path */ - private native void cairoRectangle(double x, double y, double width, - double height); + private native void cairoRectangle(long pointer, double x, double y, + double width, double height); /** * New current path */ - private native void cairoNewPath(); + private native void cairoNewPath(long pointer); /** * Close current path */ - private native void cairoClosePath(); + private native void cairoClosePath(long pointer); /** moveTo */ - private native void cairoMoveTo(double x, double y); + private native void cairoMoveTo(long pointer, double x, double y); /** relative moveTo */ - private native void cairoRelMoveTo(double dx, double dy); + private native void cairoRelMoveTo(long pointer, double dx, double dy); /** lineTo */ - private native void cairoLineTo(double x, double y); + private native void cairoLineTo(long pointer, double x, double y); /** relative lineTo */ - private native void cairoRelLineTo(double dx, double dy); + private native void cairoRelLineTo(long pointer, double dx, double dy); /** Cubic curve-to */ - private native void cairoCurveTo(double x1, double y1, double x2, double y2, + private native void cairoCurveTo(long pointer, double x1, double y1, + double x2, double y2, double x3, double y3); /** * Stroke current path */ - private native void cairoStroke(); + private native void cairoStroke(long pointer); /** * Fill current path */ - private native void cairoFill(); + private native void cairoFill(long pointer, double alpha); /** * Clip current path */ - private native void cairoClip(); + private native void cairoClip(long pointer); /** * Save clip */ - private native void cairoPreserveClip(); + private native void cairoPreserveClip(long pointer); /** * Save clip */ - private native void cairoResetClip(); + private native void cairoResetClip(long pointer); /** * Set interpolation types */ - private native void cairoSurfaceSetFilter(int filter); + private native void cairoSurfaceSetFilter(long pointer, int filter); + + /** + * Draws a line from (x1,y1) to (x2,y2). + * + * @param pointer the native pointer + * + * @param x1 the x coordinate of the starting point + * @param y1 the y coordinate of the starting point + * @param x2 the x coordinate of the end point + * @param y2 the y coordinate of the end point + */ + private native void cairoDrawLine(long pointer, double x1, double y1, + double x2, double y2); + + /** + * Draws a rectangle at starting point (x,y) and with the specified width + * and height. + * + * @param pointer the native pointer + * @param x the x coordinate of the upper left corner + * @param y the y coordinate of the upper left corner + * @param w the width of the rectangle + * @param h the height of the rectangle + */ + private native void cairoDrawRect(long pointer, double x, double y, double w, + double h); + + /** + * Fills a rectangle at starting point (x,y) and with the specified width + * and height. + * + * @param pointer the native pointer + * @param x the x coordinate of the upper left corner + * @param y the y coordinate of the upper left corner + * @param w the width of the rectangle + * @param h the height of the rectangle + */ + private native void cairoFillRect(long pointer, double x, double y, double w, + double h); + ///////////////////////// TRANSFORMS /////////////////////////////////// /** @@ -431,43 +473,60 @@ public abstract class CairoGraphics2D extends Graphics2D */ public void setTransform(AffineTransform tx) { + // Transform clip into target space using the old transform. + updateClip(transform); + + // Update the native transform. + setTransformImpl(tx); + + // Transform the clip back into user space using the inverse new transform. + try + { + updateClip(transform.createInverse()); + } + catch (NoninvertibleTransformException ex) + { + // TODO: How can we deal properly with this? + ex.printStackTrace(); + } + + if (clip != null) + setClip(clip); + } + + private void setTransformImpl(AffineTransform tx) + { transform = tx; if (transform != null) { - double[] m = new double[6]; - transform.getMatrix(m); - cairoSetMatrix(m); + double[] m = new double[6]; + transform.getMatrix(m); + cairoSetMatrix(nativePointer, m); } } - + public void transform(AffineTransform tx) { if (transform == null) transform = new AffineTransform(tx); else transform.concatenate(tx); - setTransform(transform); + if (clip != null) { - // FIXME: this should actuall try to transform the shape - // rather than degrade to bounds. - Rectangle2D r = clip.getBounds2D(); - double[] coords = new double[] - { - r.getX(), r.getY(), r.getX() + r.getWidth(), - r.getY() + r.getHeight() - }; - try - { - tx.createInverse().transform(coords, 0, coords, 0, 2); - r.setRect(coords[0], coords[1], coords[2] - coords[0], - coords[3] - coords[1]); - clip = r; - } - catch (java.awt.geom.NoninvertibleTransformException e) - { - } + try + { + AffineTransform clipTransform = tx.createInverse(); + updateClip(clipTransform); + } + catch (NoninvertibleTransformException ex) + { + // TODO: How can we deal properly with this? + ex.printStackTrace(); + } } + + setTransformImpl(transform); } public void rotate(double theta) @@ -500,18 +559,21 @@ public abstract class CairoGraphics2D extends Graphics2D { // FIXME: this should actuall try to transform the shape // rather than degrade to bounds. - Rectangle2D r; - if (clip instanceof Rectangle2D) - r = (Rectangle2D) clip; + { + Rectangle2D r = (Rectangle2D) clip; + r.setRect(r.getX() - tx, r.getY() - ty, r.getWidth(), + r.getHeight()); + } else - r = clip.getBounds2D(); - - r.setRect(r.getX() - tx, r.getY() - ty, r.getWidth(), r.getHeight()); - clip = r; + { + AffineTransform clipTransform = + AffineTransform.getTranslateInstance(-tx, -ty); + updateClip(clipTransform); + } } - setTransform(transform); + setTransformImpl(transform); } public void translate(int x, int y) @@ -528,10 +590,50 @@ public abstract class CairoGraphics2D extends Graphics2D public void clip(Shape s) { - if( s == null ) - setClip( originalClip ); + // Do not touch clip when s == null. + if (s == null) + { + // The spec says this should clear the clip. The reference + // implementation throws a NullPointerException instead. I think, + // in this case we should conform to the specs, as it shouldn't + // affect compatibility. + setClip(null); + return; + } - setClip(s); + // If the current clip is still null, initialize it. + if (clip == null) + { + clip = getRealBounds(); + } + + // This is so common, let's optimize this. + if (clip instanceof Rectangle2D && s instanceof Rectangle2D) + { + Rectangle2D clipRect = (Rectangle2D) clip; + Rectangle2D r = (Rectangle2D) s; + Rectangle2D.intersect(clipRect, r, clipRect); + setClip(clipRect); + } + else + { + Area current; + if (clip instanceof Area) + current = (Area) clip; + else + current = new Area(clip); + + Area intersect; + if (s instanceof Area) + intersect = (Area) s; + else + intersect = new Area(s); + + current.intersect(intersect); + clip = current; + // Call setClip so that the native side gets notified. + setClip(clip); + } } public Paint getPaint() @@ -570,7 +672,7 @@ public abstract class CairoGraphics2D extends Graphics2D AffineTransformOp op = new AffineTransformOp(at, getRenderingHints()); BufferedImage texture = op.filter(img, null); int[] pixels = texture.getRGB(0, 0, width, height, null, 0, width); - setTexturePixels(pixels, width, height, width); + setTexturePixels(nativePointer, pixels, width, height, width); } else if (paint instanceof GradientPaint) { @@ -579,9 +681,10 @@ public abstract class CairoGraphics2D extends Graphics2D Point2D p2 = gp.getPoint2(); Color c1 = gp.getColor1(); Color c2 = gp.getColor2(); - setGradient(p1.getX(), p1.getY(), p2.getX(), p2.getY(), c1.getRed(), - c1.getGreen(), c1.getBlue(), c1.getAlpha(), c2.getRed(), - c2.getGreen(), c2.getBlue(), c2.getAlpha(), gp.isCyclic()); + setGradient(nativePointer, p1.getX(), p1.getY(), p2.getX(), p2.getY(), + c1.getRed(), c1.getGreen(), c1.getBlue(), c1.getAlpha(), + c2.getRed(), c2.getGreen(), c2.getBlue(), c2.getAlpha(), + gp.isCyclic()); } else throw new java.lang.UnsupportedOperationException(); @@ -598,7 +701,7 @@ public abstract class CairoGraphics2D extends Graphics2D if (stroke instanceof BasicStroke) { BasicStroke bs = (BasicStroke) stroke; - cairoSetLine(bs.getLineWidth(), bs.getEndCap(), + cairoSetLine(nativePointer, bs.getLineWidth(), bs.getEndCap(), bs.getLineJoin(), bs.getMiterLimit()); float[] dashes = bs.getDashArray(); @@ -607,11 +710,11 @@ public abstract class CairoGraphics2D extends Graphics2D double[] double_dashes = new double[dashes.length]; for (int i = 0; i < dashes.length; i++) double_dashes[i] = dashes[i]; - cairoSetDash(double_dashes, double_dashes.length, + cairoSetDash(nativePointer, double_dashes, double_dashes.length, (double) bs.getDashPhase()); } else - cairoSetDash(new double[0], 0, 0.0); + cairoSetDash(nativePointer, new double[0], 0, 0.0); } } @@ -642,8 +745,9 @@ public abstract class CairoGraphics2D extends Graphics2D { if (fg == null) fg = Color.BLACK; - cairoSetRGBAColor(fg.getRed() / 255.0, fg.getGreen() / 255.0, - fg.getBlue() / 255.0, fg.getAlpha() / 255.0); + cairoSetRGBAColor(nativePointer, fg.getRed() / 255.0, + fg.getGreen() / 255.0,fg.getBlue() / 255.0, + fg.getAlpha() / 255.0); } public Color getColor() @@ -653,15 +757,30 @@ public abstract class CairoGraphics2D extends Graphics2D public void clipRect(int x, int y, int width, int height) { - clip(new Rectangle(x, y, width, height)); + if (clip == null) + setClip(new Rectangle(x, y, width, height)); + else if (clip instanceof Rectangle) + { + computeIntersection(x, y, width, height, (Rectangle) clip); + setClip(clip); + } + else + clip(new Rectangle(x, y, width, height)); } public Shape getClip() { if (clip == null) return null; - else + else if (clip instanceof Rectangle2D) return clip.getBounds2D(); //getClipInDevSpace(); + else + { + GeneralPath p = new GeneralPath(); + PathIterator pi = clip.getPathIterator(null); + p.append(pi, false); + return p; + } } public Rectangle getClipBounds() @@ -701,7 +820,7 @@ public abstract class CairoGraphics2D extends Graphics2D } public void setClip(Shape s) - { + { // The first time the clip is set, save it as the original clip // to reset to on s == null. We can rely on this being non-null // because the constructor in subclasses is expected to set the @@ -712,23 +831,23 @@ public abstract class CairoGraphics2D extends Graphics2D firstClip = false; } - if (s == null) - clip = originalClip; - else - clip = s; - - cairoResetClip(); + clip = s; + cairoResetClip(nativePointer); - cairoNewPath(); - if (clip instanceof Rectangle2D) + if (clip != null) { - Rectangle2D r = (Rectangle2D) clip; - cairoRectangle(r.getX(), r.getY(), r.getWidth(), r.getHeight()); + cairoNewPath(nativePointer); + if (clip instanceof Rectangle2D) + { + Rectangle2D r = (Rectangle2D) clip; + cairoRectangle(nativePointer, r.getX(), r.getY(), r.getWidth(), + r.getHeight()); + } + else + walkPath(clip.getPathIterator(null), false); + + cairoClip(nativePointer); } - else - walkPath(clip.getPathIterator(null), false); - - cairoClip(); } public void setBackground(Color c) @@ -764,13 +883,16 @@ public abstract class CairoGraphics2D extends Graphics2D if (comp instanceof AlphaComposite) { AlphaComposite a = (AlphaComposite) comp; - cairoSetOperator(a.getRule()); - Color c = getColor(); - setColor(new Color(c.getRed(), c.getGreen(), c.getBlue(), - (int) (a.getAlpha() * ((float) c.getAlpha())))); + cairoSetOperator(nativePointer, a.getRule()); } else { + // FIXME: this check is only required "if this Graphics2D + // context is drawing to a Component on the display screen". + SecurityManager sm = System.getSecurityManager(); + if (sm != null) + sm.checkPermission(new AWTPermission("readDisplayPixels")); + // FIXME: implement general Composite support throw new java.lang.UnsupportedOperationException(); } @@ -780,38 +902,54 @@ public abstract class CairoGraphics2D extends Graphics2D public void draw(Shape s) { - if (stroke != null && ! (stroke instanceof BasicStroke)) + if ((stroke != null && ! (stroke instanceof BasicStroke)) + || (comp instanceof AlphaComposite + && ((AlphaComposite) comp).getAlpha() != 1.0)) { + // FIXME: This is a hack to work around BasicStrokes's current + // limitations wrt cubic curves. + // See CubicSegment.getDisplacedSegments(). + if (stroke instanceof BasicStroke) + { + PathIterator flatten = s.getPathIterator(null, 1.0); + GeneralPath p = new GeneralPath(); + p.append(flatten, false); + s = p; + } fill(stroke.createStrokedShape(s)); return; } - cairoNewPath(); + cairoNewPath(nativePointer); if (s instanceof Rectangle2D) { Rectangle2D r = (Rectangle2D) s; - cairoRectangle(shifted(r.getX(), shiftDrawCalls), + cairoRectangle(nativePointer, shifted(r.getX(), shiftDrawCalls), shifted(r.getY(), shiftDrawCalls), r.getWidth(), r.getHeight()); } else walkPath(s.getPathIterator(null), shiftDrawCalls); - cairoStroke(); + cairoStroke(nativePointer); } public void fill(Shape s) { - cairoNewPath(); + cairoNewPath(nativePointer); if (s instanceof Rectangle2D) { Rectangle2D r = (Rectangle2D) s; - cairoRectangle(r.getX(), r.getY(), r.getWidth(), r.getHeight()); + cairoRectangle(nativePointer, r.getX(), r.getY(), r.getWidth(), + r.getHeight()); } else walkPath(s.getPathIterator(null), false); - cairoFill(); + double alpha = 1.0; + if (comp instanceof AlphaComposite) + alpha = ((AlphaComposite) comp).getAlpha(); + cairoFill(nativePointer, alpha); } /** @@ -823,8 +961,8 @@ public abstract class CairoGraphics2D extends Graphics2D public void clearRect(int x, int y, int width, int height) { if (bg != null) - cairoSetRGBAColor(bg.getRed() / 255.0, bg.getGreen() / 255.0, - bg.getBlue() / 255.0, 1.0); + cairoSetRGBAColor(nativePointer, bg.getRed() / 255.0, + bg.getGreen() / 255.0, bg.getBlue() / 255.0, 1.0); fillRect(x, y, width, height); updateColor(); } @@ -847,12 +985,15 @@ public abstract class CairoGraphics2D extends Graphics2D public void drawLine(int x1, int y1, int x2, int y2) { - draw(new Line2D.Double(x1, y1, x2, y2)); + cairoDrawLine(nativePointer, shifted(x1, shiftDrawCalls), + shifted(y1, shiftDrawCalls), shifted(x2, shiftDrawCalls), + shifted(y2, shiftDrawCalls)); } public void drawRect(int x, int y, int width, int height) { - draw(new Rectangle(x, y, width, height)); + cairoDrawRect(nativePointer, shifted(x, shiftDrawCalls), + shifted(y, shiftDrawCalls), width, height); } public void fillArc(int x, int y, int width, int height, int startAngle, @@ -865,7 +1006,7 @@ public abstract class CairoGraphics2D extends Graphics2D public void fillRect(int x, int y, int width, int height) { - fill(new Rectangle(x, y, width, height)); + cairoFillRect(nativePointer, x, y, width, height); } public void fillPolygon(int[] xPoints, int[] yPoints, int nPoints) @@ -972,19 +1113,19 @@ public abstract class CairoGraphics2D extends Graphics2D || hintKey.equals(RenderingHints.KEY_ALPHA_INTERPOLATION)) { if (hintValue.equals(RenderingHints.VALUE_INTERPOLATION_NEAREST_NEIGHBOR)) - cairoSurfaceSetFilter(0); + cairoSurfaceSetFilter(nativePointer, 0); else if (hintValue.equals(RenderingHints.VALUE_INTERPOLATION_BILINEAR)) - cairoSurfaceSetFilter(1); + cairoSurfaceSetFilter(nativePointer, 1); else if (hintValue.equals(RenderingHints.VALUE_ALPHA_INTERPOLATION_SPEED)) - cairoSurfaceSetFilter(2); + cairoSurfaceSetFilter(nativePointer, 2); else if (hintValue.equals(RenderingHints.VALUE_ALPHA_INTERPOLATION_QUALITY)) - cairoSurfaceSetFilter(3); + cairoSurfaceSetFilter(nativePointer, 3); else if (hintValue.equals(RenderingHints.VALUE_ALPHA_INTERPOLATION_DEFAULT)) - cairoSurfaceSetFilter(4); + cairoSurfaceSetFilter(nativePointer, 4); } shiftDrawCalls = hints.containsValue(RenderingHints.VALUE_STROKE_NORMALIZE) @@ -1004,22 +1145,22 @@ public abstract class CairoGraphics2D extends Graphics2D if (hints.containsKey(RenderingHints.KEY_INTERPOLATION)) { if (hints.containsValue(RenderingHints.VALUE_INTERPOLATION_NEAREST_NEIGHBOR)) - cairoSurfaceSetFilter(0); + cairoSurfaceSetFilter(nativePointer, 0); else if (hints.containsValue(RenderingHints.VALUE_INTERPOLATION_BILINEAR)) - cairoSurfaceSetFilter(1); + cairoSurfaceSetFilter(nativePointer, 1); } if (hints.containsKey(RenderingHints.KEY_ALPHA_INTERPOLATION)) { if (hints.containsValue(RenderingHints.VALUE_ALPHA_INTERPOLATION_SPEED)) - cairoSurfaceSetFilter(2); + cairoSurfaceSetFilter(nativePointer, 2); else if (hints.containsValue(RenderingHints.VALUE_ALPHA_INTERPOLATION_QUALITY)) - cairoSurfaceSetFilter(3); + cairoSurfaceSetFilter(nativePointer, 3); else if (hints.containsValue(RenderingHints.VALUE_ALPHA_INTERPOLATION_DEFAULT)) - cairoSurfaceSetFilter(4); + cairoSurfaceSetFilter(nativePointer, 4); } shiftDrawCalls = hints.containsValue(RenderingHints.VALUE_STROKE_NORMALIZE) @@ -1051,7 +1192,7 @@ public abstract class CairoGraphics2D extends Graphics2D // other way around. Therefore to get the "user -> pixel" transform // that cairo wants from "image -> user" transform that we currently // have, we will need to invert the transformation matrix. - AffineTransform invertedXform = new AffineTransform(); + AffineTransform invertedXform; try { @@ -1063,11 +1204,18 @@ public abstract class CairoGraphics2D extends Graphics2D + xform.toString()); } - // Unrecognized image - convert to a BufferedImage and come back. + // Unrecognized image - convert to a BufferedImage + // Note - this can get us in trouble when the gdk lock is re-acquired. + // for example by VolatileImage. See ComponentGraphics for how we work + // around this. + if( !(img instanceof BufferedImage) ) - return this.drawImage(Toolkit.getDefaultToolkit(). - createImage(img.getSource()), - xform, bgcolor, obs); + { + ImageProducer source = img.getSource(); + if (source == null) + return false; + img = Toolkit.getDefaultToolkit().createImage(source); + } BufferedImage b = (BufferedImage) img; DataBuffer db; @@ -1077,6 +1225,7 @@ public abstract class CairoGraphics2D extends Graphics2D // If this BufferedImage has a BufferedImageGraphics object, // use the cached CairoSurface that BIG is drawing onto + if( BufferedImageGraphics.bufferedImages.get( b ) != null ) db = (DataBuffer)BufferedImageGraphics.bufferedImages.get( b ); else @@ -1084,9 +1233,14 @@ public abstract class CairoGraphics2D extends Graphics2D invertedXform.getMatrix(i2u); + double alpha = 1.0; + if (comp instanceof AlphaComposite) + alpha = ((AlphaComposite) comp).getAlpha(); + if(db instanceof CairoSurface) { - ((CairoSurface)db).drawSurface(this, i2u); + ((CairoSurface)db).drawSurface(nativePointer, i2u, alpha); + updateColor(); return true; } @@ -1103,26 +1257,9 @@ public abstract class CairoGraphics2D extends Graphics2D setPaint( oldPaint ); } - int[] pixels; - - // Shortcut for easy color models. - if( b.getColorModel().equals(rgb32) ) - { - pixels = ((DataBufferInt)db).getData(); - for(int i = 0; i < pixels.length; i++) - pixels[i] |= 0xFF000000; - } - else if( b.getColorModel().equals(argb32) ) - { - pixels = ((DataBufferInt)db).getData(); - } - else - { - pixels = b.getRGB(0, 0, width, height, - null, 0, width); - } + int[] pixels = b.getRGB(0, 0, width, height, null, 0, width); - drawPixels(pixels, width, height, width, i2u); + drawPixels(nativePointer, pixels, width, height, width, i2u, alpha); // Cairo seems to lose the current color which must be restored. updateColor(); @@ -1214,7 +1351,7 @@ public abstract class CairoGraphics2D extends Graphics2D else { cy = dy2; ch = dy1 - dy2; } - setClip( cx, cy, cw, ch ); + clipRect( cx, cy, cw, ch ); AffineTransform tx = new AffineTransform(); tx.translate( dx1 - sx1*scaleX, dy1 - sy1*scaleY ); @@ -1238,8 +1375,8 @@ public abstract class CairoGraphics2D extends Graphics2D { if (str == null || str.length() == 0) return; - - drawGlyphVector(getFont().createGlyphVector(null, str), x, y); + (new TextLayout( str, getFont(), getFontRenderContext() )). + draw(this, x, y); } public void drawString(String str, int x, int y) @@ -1254,12 +1391,29 @@ public abstract class CairoGraphics2D extends Graphics2D public void drawGlyphVector(GlyphVector gv, float x, float y) { - int n = gv.getNumGlyphs (); - int[] codes = gv.getGlyphCodes (0, n, null); - float[] positions = gv.getGlyphPositions (0, n, null); - - setFont (gv.getFont ()); - cairoDrawGlyphVector( (GdkFontPeer)getFont().getPeer(), x, y, n, codes, positions); + double alpha = 1.0; + + if( gv.getNumGlyphs() <= 0 ) + return; + + if (comp instanceof AlphaComposite) + alpha = ((AlphaComposite) comp).getAlpha(); + if (gv instanceof FreetypeGlyphVector && alpha == 1.0) + { + int n = gv.getNumGlyphs (); + int[] codes = gv.getGlyphCodes (0, n, null); + float[] positions = gv.getGlyphPositions (0, n, null); + + setFont (gv.getFont ()); + cairoDrawGlyphVector(nativePointer, (GdkFontPeer)getFont().getPeer(), + x, y, n, codes, positions); + } + else + { + translate(x, y); + fill(gv.getOutline()); + translate(-x, -y); + } } public void drawString(AttributedCharacterIterator ci, float x, float y) @@ -1412,7 +1566,11 @@ public abstract class CairoGraphics2D extends Graphics2D for (int i = 0; i < pixels.length; i++) pixels[i] |= 0xFF000000; - drawPixels(pixels, r.getWidth(), r.getHeight(), r.getWidth(), i2u); + double alpha = 1.0; + if (comp instanceof AlphaComposite) + alpha = ((AlphaComposite) comp).getAlpha(); + drawPixels(nativePointer, pixels, r.getWidth(), r.getHeight(), + r.getWidth(), i2u, alpha); // Cairo seems to lose the current color which must be restored. updateColor(); @@ -1440,7 +1598,7 @@ public abstract class CairoGraphics2D extends Graphics2D double y = 0; double[] coords = new double[6]; - cairoSetFillRule(p.getWindingRule()); + cairoSetFillRule(nativePointer, p.getWindingRule()); for (; ! p.isDone(); p.next()) { int seg = p.currentSegment(coords); @@ -1449,12 +1607,12 @@ public abstract class CairoGraphics2D extends Graphics2D case PathIterator.SEG_MOVETO: x = shifted(coords[0], doShift); y = shifted(coords[1], doShift); - cairoMoveTo(x, y); + cairoMoveTo(nativePointer, x, y); break; case PathIterator.SEG_LINETO: x = shifted(coords[0], doShift); y = shifted(coords[1], doShift); - cairoLineTo(x, y); + cairoLineTo(nativePointer, x, y); break; case PathIterator.SEG_QUADTO: // splitting a quadratic bezier into a cubic: @@ -1467,18 +1625,18 @@ public abstract class CairoGraphics2D extends Graphics2D x = shifted(coords[2], doShift); y = shifted(coords[3], doShift); - cairoCurveTo(x1, y1, x2, y2, x, y); + cairoCurveTo(nativePointer, x1, y1, x2, y2, x, y); break; case PathIterator.SEG_CUBICTO: x = shifted(coords[4], doShift); y = shifted(coords[5], doShift); - cairoCurveTo(shifted(coords[0], doShift), + cairoCurveTo(nativePointer, shifted(coords[0], doShift), shifted(coords[1], doShift), shifted(coords[2], doShift), shifted(coords[3], doShift), x, y); break; case PathIterator.SEG_CLOSE: - cairoClosePath(); + cairoClosePath(nativePointer); break; } } @@ -1550,4 +1708,47 @@ public abstract class CairoGraphics2D extends Graphics2D return db.getData(); } + + /** + * Helper method to transform the clip. This is called by the various + * transformation-manipulation methods to update the clip (which is in + * userspace) accordingly. + * + * The transform usually is the inverse transform that was applied to the + * graphics object. + * + * @param t the transform to apply to the clip + */ + private void updateClip(AffineTransform t) + { + if (clip == null) + return; + + if (! (clip instanceof GeneralPath)) + clip = new GeneralPath(clip); + + GeneralPath p = (GeneralPath) clip; + p.transform(t); + } + + private static Rectangle computeIntersection(int x, int y, int w, int h, + Rectangle rect) + { + int x2 = (int) rect.x; + int y2 = (int) rect.y; + int w2 = (int) rect.width; + int h2 = (int) rect.height; + + int dx = (x > x2) ? x : x2; + int dy = (y > y2) ? y : y2; + int dw = (x + w < x2 + w2) ? (x + w - dx) : (x2 + w2 - dx); + int dh = (y + h < y2 + h2) ? (y + h - dy) : (y2 + h2 - dy); + + if (dw >= 0 && dh >= 0) + rect.setBounds(dx, dy, dw, dh); + else + rect.setBounds(0, 0, 0, 0); + + return rect; + } } diff --git a/gnu/java/awt/peer/gtk/CairoSurface.java b/gnu/java/awt/peer/gtk/CairoSurface.java index c3b07d874..b4d08c6ad 100644 --- a/gnu/java/awt/peer/gtk/CairoSurface.java +++ b/gnu/java/awt/peer/gtk/CairoSurface.java @@ -52,6 +52,7 @@ import java.awt.image.ColorModel; import java.awt.image.DirectColorModel; import java.io.File; import java.io.IOException; +import java.nio.ByteOrder; import java.util.Hashtable; import java.util.Vector; import java.io.ByteArrayOutputStream; @@ -88,49 +89,65 @@ public class CairoSurface extends DataBuffer /** * Allocates and clears the buffer and creates the cairo surface. * @param width, height - the image size - * @param stride - the buffer row stride. + * @param stride - the buffer row stride. (in ints) */ private native void create(int width, int height, int stride); /** * Destroys the cairo surface and frees the buffer. */ - private native void destroy(); + private native void destroy(long surfacePointer, long bufferPointer); /** * Gets buffer elements */ - private native int nativeGetElem(int i); + private native int nativeGetElem(long bufferPointer, int i); /** * Sets buffer elements. */ - private native void nativeSetElem(int i, int val); + private native void nativeSetElem(long bufferPointer, int i, int val); /** * Draws this image to a given CairoGraphics context, * with an affine transform given by i2u. */ - public native void drawSurface(CairoGraphics2D context, double[] i2u); + public native void nativeDrawSurface(long surfacePointer, long contextPointer, + double[] i2u, double alpha); + + public void drawSurface(long contextPointer, double[] i2u, double alpha) + { + nativeDrawSurface(surfacePointer, contextPointer, i2u, alpha); + } /** * getPixels -return the pixels as a java array. */ - native int[] getPixels(int size); + native int[] nativeGetPixels(long bufferPointer, int size); + + public int[] getPixels(int size) + { + return nativeGetPixels(bufferPointer, size); + } /** * getPixels -return the pixels as a java array. */ - native void setPixels(int[] pixels); + native void nativeSetPixels(long bufferPointer, int[] pixels); - native long getFlippedBuffer(int size); + public void setPixels(int[] pixels) + { + nativeSetPixels(bufferPointer, pixels); + } + + native long getFlippedBuffer(long bufferPointer, int size); /** * Create a cairo_surface_t with specified width and height. * The format will be ARGB32 with premultiplied alpha and native bit * and word ordering. */ - CairoSurface(int width, int height) + public CairoSurface(int width, int height) { super(DataBuffer.TYPE_INT, width * height); @@ -140,7 +157,7 @@ public class CairoSurface extends DataBuffer this.width = width; this.height = height; - create(width, height, width * 4); + create(width, height, width); if(surfacePointer == 0 || bufferPointer == 0) throw new Error("Could not allocate bitmap."); @@ -160,29 +177,52 @@ public class CairoSurface extends DataBuffer width = image.width; height = image.height; - create(width, height, width * 4); - + create(width, height, width); + if(surfacePointer == 0 || bufferPointer == 0) throw new Error("Could not allocate bitmap."); - + // Copy the pixel data from the GtkImage. int[] data = image.getPixels(); // Swap ordering from GdkPixbuf to Cairo for(int i = 0; i < data.length; i++ ) { - int alpha = (data[i] & 0xFF000000) >> 24; - if( alpha == 0 ) // I do not know why we need this, but it works. - data[i] = 0; + if (ByteOrder.nativeOrder() == ByteOrder.BIG_ENDIAN) + { + // On a big endian system we get a RRGGBBAA data array. + int alpha = (data[i] & 0xFF); + if( alpha == 0 ) // I do not know why we need this, but it works. + data[i] = 0; + else + { + int r = (((data[i] & 0xFF000000) >> 24)); + int g = (((data[i] & 0x00FF0000) >> 16)); + int b = (((data[i] & 0x0000FF00) >> 8)); + // Cairo needs a ARGB32 native array. + data[i] = (( alpha << 24 ) & 0xFF000000) + | (( r << 16 ) & 0x00FF0000) + | (( g << 8 ) & 0x0000FF00) + | ( b & 0x000000FF); + } + } else { - int r = (((data[i] & 0x00FF0000) >> 16) ); - int g = (((data[i] & 0x0000FF00) >> 8) ); - int b = ((data[i] & 0x000000FF) ); - data[i] = (( alpha << 24 ) & 0xFF000000) - | (( b << 16 ) & 0x00FF0000) - | (( g << 8 ) & 0x0000FF00) - | ( r & 0x000000FF); + // On a little endian system we get a AABBGGRR data array. + int alpha = (data[i] & 0xFF000000) >> 24; + if( alpha == 0 ) // I do not know why we need this, but it works. + data[i] = 0; + else + { + int b = (((data[i] & 0x00FF0000) >> 16)); + int g = (((data[i] & 0x0000FF00) >> 8)); + int r = ((data[i] & 0x000000FF)); + // Cairo needs a ARGB32 native array. + data[i] = (( alpha << 24 ) & 0xFF000000) + | (( r << 16 ) & 0x00FF0000) + | (( g << 8 ) & 0x0000FF00) + | ( b & 0x000000FF); + } } } @@ -195,7 +235,15 @@ public class CairoSurface extends DataBuffer public void dispose() { if(surfacePointer != 0) - destroy(); + destroy(surfacePointer, bufferPointer); + } + + /** + * Call dispose() to clean up any native resources allocated. + */ + protected void finalize() + { + dispose(); } /** @@ -203,7 +251,8 @@ public class CairoSurface extends DataBuffer */ public GtkImage getGtkImage() { - return new GtkImage( width, height, getFlippedBuffer( width * height )); + return new GtkImage( width, height, + getFlippedBuffer(bufferPointer, width * height )); } /** @@ -243,7 +292,7 @@ public class CairoSurface extends DataBuffer { if(bank != 0 || i < 0 || i >= width*height) throw new IndexOutOfBoundsException(i+" size: "+width*height); - return nativeGetElem(i); + return nativeGetElem(bufferPointer, i); } /** @@ -253,7 +302,7 @@ public class CairoSurface extends DataBuffer { if(bank != 0 || i < 0 || i >= width*height) throw new IndexOutOfBoundsException(i+" size: "+width*height); - nativeSetElem(i, val); + nativeSetElem(bufferPointer, i, val); } /** @@ -269,12 +318,22 @@ public class CairoSurface extends DataBuffer * Creates a cairo_t drawing context, returns the pointer as a long. * Used by CairoSurfaceGraphics. */ - native long newCairoContext(); + native long nativeNewCairoContext(long surfacePointer); + + public long newCairoContext() + { + return nativeNewCairoContext(surfacePointer); + } /** * Copy an area of the surface. Expects parameters must be within bounds. * Count on a segfault otherwise. */ - native void copyAreaNative(int x, int y, int width, int height, - int dx, int dy, int stride); + native void copyAreaNative2(long bufferPointer, int x, int y, int width, + int height, int dx, int dy, int stride); + public void copyAreaNative(int x, int y, int width, + int height, int dx, int dy, int stride) + { + copyAreaNative2(bufferPointer, x, y, width, height, dx, dy, stride); + } } diff --git a/gnu/java/awt/peer/gtk/CairoSurfaceGraphics.java b/gnu/java/awt/peer/gtk/CairoSurfaceGraphics.java index 38c549d1d..91f0b4981 100644 --- a/gnu/java/awt/peer/gtk/CairoSurfaceGraphics.java +++ b/gnu/java/awt/peer/gtk/CairoSurfaceGraphics.java @@ -40,6 +40,7 @@ package gnu.java.awt.peer.gtk; import java.awt.Graphics; import java.awt.Color; +import java.awt.GraphicsEnvironment; import java.awt.Image; import java.awt.Point; import java.awt.Graphics2D; @@ -63,7 +64,6 @@ public class CairoSurfaceGraphics extends CairoGraphics2D this.surface = surface; cairo_t = surface.newCairoContext(); setup( cairo_t ); - setClip(0, 0, surface.width, surface.height); } /** @@ -75,7 +75,6 @@ public class CairoSurfaceGraphics extends CairoGraphics2D surface = copyFrom.surface; cairo_t = surface.newCairoContext(); copy( copyFrom, cairo_t ); - setClip(0, 0, surface.width, surface.height); } public Graphics create() @@ -85,7 +84,7 @@ public class CairoSurfaceGraphics extends CairoGraphics2D public GraphicsConfiguration getDeviceConfiguration() { - throw new UnsupportedOperationException(); + return GraphicsEnvironment.getLocalGraphicsEnvironment().getDefaultScreenDevice().getDefaultConfiguration(); } protected Rectangle2D getRealBounds() diff --git a/gnu/java/awt/peer/gtk/ComponentGraphics.java b/gnu/java/awt/peer/gtk/ComponentGraphics.java index 5f17d7bef..cb8350265 100644 --- a/gnu/java/awt/peer/gtk/ComponentGraphics.java +++ b/gnu/java/awt/peer/gtk/ComponentGraphics.java @@ -39,20 +39,19 @@ exception statement from your version. */ package gnu.java.awt.peer.gtk; import java.awt.Color; -import java.awt.Font; 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.font.FontRenderContext; +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.ImagingOpException; +import java.awt.image.ImageProducer; import java.awt.image.RenderedImage; /** @@ -64,8 +63,41 @@ import java.awt.image.RenderedImage; public class ComponentGraphics extends CairoGraphics2D { private GtkComponentPeer component; - private long cairo_t; + 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; @@ -94,6 +126,26 @@ public class ComponentGraphics extends CairoGraphics2D 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(); @@ -113,8 +165,9 @@ public class ComponentGraphics extends CairoGraphics2D int width, int height, int dx, int dy); private native void drawVolatile(GtkComponentPeer component, - Image vimg, int x, int y, - int width, int height); + long vimg, int x, int y, + int width, int height, int cx, int cy, + int cw, int ch); /** * Returns a Graphics2D object for a component, either an instance of this @@ -155,65 +208,198 @@ public class ComponentGraphics extends CairoGraphics2D */ public void draw(Shape s) { - start_gdk_drawing(); - super.draw(s); - end_gdk_drawing(); + lock(); + try + { + super.draw(s); + } + finally + { + unlock(); + } } public void fill(Shape s) { - start_gdk_drawing(); - super.fill(s); - end_gdk_drawing(); + lock(); + try + { + super.fill(s); + } + finally + { + unlock(); + } } public void drawRenderedImage(RenderedImage image, AffineTransform xform) { - start_gdk_drawing(); - super.drawRenderedImage(image, xform); - end_gdk_drawing(); + lock(); + try + { + super.drawRenderedImage(image, xform); + } + finally + { + unlock(); + } } protected boolean drawImage(Image img, AffineTransform xform, Color bgcolor, ImageObserver obs) { - start_gdk_drawing(); - boolean rv = super.drawImage(img, xform, bgcolor, obs); - end_gdk_drawing(); + boolean rv; + lock(); + try + { + rv = super.drawImage(img, xform, bgcolor, obs); + } + finally + { + unlock(); + } return rv; } public void drawGlyphVector(GlyphVector gv, float x, float y) { - start_gdk_drawing(); - super.drawGlyphVector(gv, x, y); - end_gdk_drawing(); + lock(); + try + { + super.drawGlyphVector(gv, x, y); + } + finally + { + unlock(); + } } public boolean drawImage(Image img, int x, int y, ImageObserver observer) { - if( img instanceof GtkVolatileImage ) + // 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)img).validate( null ); - drawVolatile( component, img, x, y-20 , - ((GtkVolatileImage)img).width, - ((GtkVolatileImage)img).height ); - return true; - } - return super.drawImage( img, x, y, observer ); + 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( img instanceof GtkVolatileImage ) + // 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 { - ((GtkVolatileImage)img).validate( null ); - drawVolatile( component, img, x, y-20, - width, height ); - return true; - } - return super.drawImage( img, x, y, width, height, observer ); + unlock(); + } } } diff --git a/gnu/java/awt/peer/gtk/FreetypeGlyphVector.java b/gnu/java/awt/peer/gtk/FreetypeGlyphVector.java new file mode 100644 index 000000000..2c9d91793 --- /dev/null +++ b/gnu/java/awt/peer/gtk/FreetypeGlyphVector.java @@ -0,0 +1,504 @@ +/* FreetypeGlyphVector.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.Font; +import java.awt.Shape; +import java.awt.geom.AffineTransform; +import java.awt.geom.Point2D; +import java.awt.geom.Rectangle2D; +import java.awt.geom.GeneralPath; +import java.awt.font.GlyphJustificationInfo; +import java.awt.font.GlyphMetrics; +import java.awt.font.GlyphVector; +import java.awt.font.FontRenderContext; + +public class FreetypeGlyphVector extends GlyphVector +{ + /** + * The associated font and its peer. + */ + private Font font; + private GdkFontPeer peer; // ATTN: Accessed from native code. + + private Rectangle2D logicalBounds; + + private float[] glyphPositions; + /** + * The string represented by this GlyphVector. + */ + private String s; + + /** + * The font render context + */ + private FontRenderContext frc; + + /** + * The total # of glyphs. + */ + private int nGlyphs; + + /** + * The glyph codes + */ + private int[] glyphCodes; + + /** + * Glyph transforms. (de facto only the translation is used) + */ + private AffineTransform[] glyphTransforms; + + private GlyphMetrics[] metricsCache; + + /** + * Create a glyphvector from a given (Freetype) font and a String. + */ + public FreetypeGlyphVector(Font f, String s, FontRenderContext frc) + { + this(f, s, frc, Font.LAYOUT_LEFT_TO_RIGHT); + } + + /** + * Create a glyphvector from a given (Freetype) font and a String. + */ + public FreetypeGlyphVector(Font f, String s, FontRenderContext frc, + int flags) + { + this.s = s; + this.font = f; + this.frc = frc; + if( !(font.getPeer() instanceof GdkFontPeer ) ) + throw new IllegalArgumentException("Not a valid font."); + peer = (GdkFontPeer)font.getPeer(); + + getGlyphs(); + if( flags == Font.LAYOUT_RIGHT_TO_LEFT ) + { + // reverse the glyph ordering. + int[] temp = new int[ nGlyphs ]; + for(int i = 0; i < nGlyphs; i++) + temp[ i ] = glyphCodes[ nGlyphs - i - 1]; + glyphCodes = temp; + } + performDefaultLayout(); + } + + /** + * Create a glyphvector from a given set of glyph codes. + */ + public FreetypeGlyphVector(Font f, int[] codes, FontRenderContext frc) + { + this.font = f; + this.frc = frc; + if( !(font.getPeer() instanceof GdkFontPeer ) ) + throw new IllegalArgumentException("Not a valid font."); + peer = (GdkFontPeer)font.getPeer(); + + glyphCodes = new int[ codes.length ]; + System.arraycopy(codes, 0, glyphCodes, 0, codes.length); + nGlyphs = glyphCodes.length; + performDefaultLayout(); + } + + /** + * Cloning constructor + */ + private FreetypeGlyphVector( FreetypeGlyphVector gv ) + { + font = gv.font; + peer = gv.peer; + frc = gv.frc; + s = gv.s; + nGlyphs = gv.nGlyphs; + logicalBounds = gv.logicalBounds.getBounds2D(); + + if( gv.metricsCache != null ) + { + metricsCache = new GlyphMetrics[ nGlyphs ]; + System.arraycopy(gv.metricsCache, 0, metricsCache, 0, nGlyphs); + } + + glyphCodes = new int[ nGlyphs ]; + glyphPositions = new float[ nGlyphs ]; + glyphTransforms = new AffineTransform[ nGlyphs ]; + for(int i = 0; i < nGlyphs; i++ ) + { + glyphTransforms[ i ] = new AffineTransform( gv.glyphTransforms[ i ] ); + glyphCodes[i] = gv.glyphCodes[ i ]; + glyphPositions[i] = gv.glyphPositions[ i ]; + } + } + + /** + * Create the array of glyph codes. + */ + private void getGlyphs() + { + nGlyphs = s.codePointCount( 0, s.length() ); + glyphCodes = new int[ nGlyphs ]; + int[] codePoints = new int[ nGlyphs ]; + int stringIndex = 0; + + for(int i = 0; i < nGlyphs; i++) + { + codePoints[i] = s.codePointAt( stringIndex ); + // UTF32 surrogate handling + if( codePoints[i] != (int)s.charAt( stringIndex ) ) + stringIndex ++; + stringIndex ++; + } + + glyphCodes = getGlyphs( codePoints ); + } + + /** + * Returns the glyph code within the font for a given character + */ + public native int[] getGlyphs(int[] codepoints); + + /** + * Returns the kerning of a glyph pair + */ + private native Point2D getKerning(int leftGlyph, int rightGlyph); + + private native double[] getMetricsNative( int glyphCode ); + + private native GeneralPath getGlyphOutlineNative(int glyphIndex); + + + public Object clone() + { + return new FreetypeGlyphVector( this ); + } + + /** + * Duh, compares two instances. + */ + public boolean equals(GlyphVector gv) + { + if( ! (gv instanceof FreetypeGlyphVector) ) + return false; + + return (((FreetypeGlyphVector)gv).font.equals(font) && + ((FreetypeGlyphVector)gv).frc.equals(frc) + && ((FreetypeGlyphVector)gv).s.equals(s)); + } + + /** + * Returns the associated Font + */ + public Font getFont() + { + return font; + } + + /** + * Returns the associated FontRenderContext + */ + public FontRenderContext getFontRenderContext() + { + return frc; + } + + /** + * Layout the glyphs. + */ + public void performDefaultLayout() + { + logicalBounds = null; // invalidate caches. + glyphPositions = null; + + glyphTransforms = new AffineTransform[ nGlyphs ]; + double x = 0; + + for(int i = 0; i < nGlyphs; i++) + { + GlyphMetrics gm = getGlyphMetrics( i ); + glyphTransforms[ i ] = AffineTransform.getTranslateInstance(x, 0); + x += gm.getAdvanceX(); + if( i > 0 ) + { + Point2D p = getKerning( glyphCodes[ i - 1 ], glyphCodes[ i ] ); + x += p.getX(); + } + } + } + + /** + * Returns the code of the glyph at glyphIndex; + */ + public int getGlyphCode(int glyphIndex) + { + return glyphCodes[ glyphIndex ]; + } + + /** + * Returns multiple glyphcodes. + */ + public int[] getGlyphCodes(int beginGlyphIndex, int numEntries, + int[] codeReturn) + { + int[] rval; + + if( codeReturn == null ) + rval = new int[ numEntries ]; + else + rval = codeReturn; + + System.arraycopy(glyphCodes, beginGlyphIndex, rval, 0, numEntries); + + return rval; + } + + /** + * FIXME: Implement me. + */ + public Shape getGlyphLogicalBounds(int glyphIndex) + { + GlyphMetrics gm = getGlyphMetrics( glyphIndex ); + if( gm == null ) + return null; + Rectangle2D r = gm.getBounds2D(); + Point2D p = getGlyphPosition( glyphIndex ); + return new Rectangle2D.Double( p.getX() + r.getX() - gm.getLSB(), + p.getY() + r.getY(), + gm.getAdvanceX(), + r.getHeight() ); + } + + /* + * FIXME: Not all glyph types are supported. + * (The JDK doesn't really seem to do so either) + */ + public void setupGlyphMetrics() + { + metricsCache = new GlyphMetrics[ nGlyphs ]; + + for(int i = 0; i < nGlyphs; i++) + { + GlyphMetrics gm = (GlyphMetrics) + peer.getGlyphMetrics( glyphCodes[ i ] ); + if( gm == null ) + { + double[] val = getMetricsNative( glyphCodes[ i ] ); + if( val == null ) + gm = null; + else + { + gm = new GlyphMetrics( true, + (float)val[1], + (float)val[2], + new Rectangle2D.Double + ( val[3], val[4], + val[5], val[6] ), + GlyphMetrics.STANDARD ); + peer.putGlyphMetrics( glyphCodes[ i ], gm ); + } + } + metricsCache[ i ] = gm; + } + } + + /** + * Returns the metrics of a single glyph. + */ + public GlyphMetrics getGlyphMetrics(int glyphIndex) + { + if( metricsCache == null ) + setupGlyphMetrics(); + + return metricsCache[ glyphIndex ]; + } + + /** + * Returns the outline of a single glyph. + */ + public Shape getGlyphOutline(int glyphIndex) + { + GeneralPath gp = getGlyphOutlineNative( glyphCodes[ glyphIndex ] ); + gp.transform( glyphTransforms[ glyphIndex ] ); + return gp; + } + + /** + * Returns the position of a single glyph. + */ + public Point2D getGlyphPosition(int glyphIndex) + { + return glyphTransforms[ glyphIndex ].transform( new Point2D.Double(0, 0), + null ); + } + + /** + * Returns the positions of multiple glyphs. + */ + public float[] getGlyphPositions(int beginGlyphIndex, int numEntries, + float[] positionReturn) + { + if( glyphPositions != null ) + return glyphPositions; + + float[] rval; + + if( positionReturn == null ) + rval = new float[2 * numEntries]; + else + rval = positionReturn; + + for( int i = beginGlyphIndex; i < numEntries; i++ ) + { + Point2D p = getGlyphPosition( i ); + rval[i * 2] = (float)p.getX(); + rval[i * 2 + 1] = (float)p.getY(); + } + + glyphPositions = rval; + return rval; + } + + /** + * Returns the transform of a glyph. + */ + public AffineTransform getGlyphTransform(int glyphIndex) + { + return new AffineTransform( glyphTransforms[ glyphIndex ] ); + } + + /** + * Returns the visual bounds of a glyph + * May be off by a pixel or two due to hinting/rasterization. + */ + public Shape getGlyphVisualBounds(int glyphIndex) + { + return getGlyphOutline( glyphIndex ).getBounds2D(); + } + + /** + * Return the logical bounds of the whole thing. + */ + public Rectangle2D getLogicalBounds() + { + if( nGlyphs == 0 ) + return new Rectangle2D.Double(0, 0, 0, 0); + if( logicalBounds != null ) + return logicalBounds; + + Rectangle2D rect = (Rectangle2D)getGlyphLogicalBounds( 0 ); + for( int i = 1; i < nGlyphs; i++ ) + { + Rectangle2D r2 = (Rectangle2D)getGlyphLogicalBounds( i ); + rect = rect.createUnion( r2 ); + } + + logicalBounds = rect; + return rect; + } + + /** + * Returns the number of glyphs. + */ + public int getNumGlyphs() + { + return glyphCodes.length; + } + + /** + * Returns the outline of the entire GlyphVector. + */ + public Shape getOutline() + { + GeneralPath path = new GeneralPath(); + for( int i = 0; i < getNumGlyphs(); i++ ) + path.append( getGlyphOutline( i ), false ); + return path; + } + + /** + * TODO: + * FreeType does not currently have an API for the JSTF table. We should + * probably get the table ourselves from FT and pass it to some parser + * which the native font peers will need. + */ + public GlyphJustificationInfo getGlyphJustificationInfo(int glyphIndex) + { + return null; + } + + /** + * Returns the outline of the entire vector, drawn at (x,y). + */ + public Shape getOutline(float x, float y) + { + AffineTransform tx = AffineTransform.getTranslateInstance( x, y ); + GeneralPath gp = (GeneralPath)getOutline(); + gp.transform( tx ); + return gp; + } + + /** + * Returns the visual bounds of the entire GlyphVector. + * May be off by a pixel or two due to hinting/rasterization. + */ + public Rectangle2D getVisualBounds() + { + return getOutline().getBounds2D(); + } + + /** + * Sets the position of a glyph. + */ + public void setGlyphPosition(int glyphIndex, Point2D newPos) + { + // FIXME: Scaling, etc.? + glyphTransforms[ glyphIndex ].setToTranslation( newPos.getX(), + newPos.getY() ); + logicalBounds = null; + glyphPositions = null; + } + + /** + * Sets the transform of a single glyph. + */ + public void setGlyphTransform(int glyphIndex, AffineTransform newTX) + { + glyphTransforms[ glyphIndex ].setTransform( newTX ); + logicalBounds = null; + glyphPositions = null; + } +} diff --git a/gnu/java/awt/peer/gtk/GdkFontPeer.java b/gnu/java/awt/peer/gtk/GdkFontPeer.java index 4781cb067..f5ed8a710 100644 --- a/gnu/java/awt/peer/gtk/GdkFontPeer.java +++ b/gnu/java/awt/peer/gtk/GdkFontPeer.java @@ -47,20 +47,28 @@ import java.awt.FontMetrics; import java.awt.Toolkit; import java.awt.font.FontRenderContext; import java.awt.font.GlyphVector; +import java.awt.font.GlyphMetrics; import java.awt.font.LineMetrics; import java.awt.geom.Rectangle2D; +import java.awt.geom.Point2D; import java.text.CharacterIterator; import java.text.StringCharacterIterator; import java.util.Locale; import java.util.Map; import java.util.ResourceBundle; import java.nio.ByteBuffer; +import java.util.HashMap; public class GdkFontPeer extends ClasspathFontPeer { static native void initStaticState(); private final int native_state = GtkGenericPeer.getUniqueInteger (); private static ResourceBundle bundle; + + /** + * Cache GlyphMetrics objects. + */ + private HashMap metricsCache; static { @@ -143,6 +151,7 @@ public class GdkFontPeer extends ClasspathFontPeer super(name, style, size); initState (); setFont (this.familyName, this.style, (int)this.size); + metricsCache = new HashMap(); } public GdkFontPeer (String name, Map attributes) @@ -150,6 +159,7 @@ public class GdkFontPeer extends ClasspathFontPeer super(name, attributes); initState (); setFont (this.familyName, this.style, (int)this.size); + metricsCache = new HashMap(); } /** @@ -234,39 +244,41 @@ public class GdkFontPeer extends ClasspathFontPeer return -1; } - private native GdkGlyphVector getGlyphVector(String txt, - Font f, - FontRenderContext ctx); - public GlyphVector createGlyphVector (Font font, FontRenderContext ctx, CharacterIterator i) { - return getGlyphVector(buildString (i), font, ctx); + return new FreetypeGlyphVector(font, buildString (i), ctx); } public GlyphVector createGlyphVector (Font font, FontRenderContext ctx, int[] glyphCodes) { - return null; - // return new GdkGlyphVector (font, this, ctx, glyphCodes); + return new FreetypeGlyphVector(font, glyphCodes, ctx); } public byte getBaselineFor (Font font, char c) { - throw new UnsupportedOperationException (); + // FIXME: Actually check. + return Font.ROMAN_BASELINE; } - protected class GdkFontLineMetrics extends LineMetrics + private static class GdkFontLineMetrics extends LineMetrics { - FontMetrics fm; - int nchars; + private FontMetrics fm; + private int nchars; + private float strikethroughOffset, strikethroughThickness, + underlineOffset, underlineThickness; - public GdkFontLineMetrics (FontMetrics m, int n) + public GdkFontLineMetrics (GdkFontPeer fp, FontMetrics m, int n) { fm = m; nchars = n; + strikethroughOffset = 0f; + underlineOffset = 0f; + strikethroughThickness = ((float)fp.getSize(null)) / 12f; + underlineThickness = strikethroughThickness; } public float getAscent() @@ -275,7 +287,8 @@ public class GdkFontPeer extends ClasspathFontPeer } public int getBaselineIndex() - { + { + // FIXME return Font.ROMAN_BASELINE; } @@ -306,7 +319,7 @@ public class GdkFontPeer extends ClasspathFontPeer public LineMetrics getLineMetrics (Font font, CharacterIterator ci, int begin, int limit, FontRenderContext rc) { - return new GdkFontLineMetrics (getFontMetrics (font), limit - begin); + return new GdkFontLineMetrics (this, getFontMetrics (font), limit - begin); } public Rectangle2D getMaxCharBounds (Font font, FontRenderContext rc) @@ -338,7 +351,9 @@ public class GdkFontPeer extends ClasspathFontPeer public Rectangle2D getStringBounds (Font font, CharacterIterator ci, int begin, int limit, FontRenderContext frc) { - GdkGlyphVector gv = getGlyphVector(buildString (ci, begin, limit), font, frc); + GlyphVector gv = new FreetypeGlyphVector( font, + buildString(ci, begin, limit), + frc); return gv.getVisualBounds(); } @@ -351,20 +366,15 @@ public class GdkFontPeer extends ClasspathFontPeer char[] chars, int start, int limit, int flags) { - int nchars = (limit - start) + 1; - char[] nc = new char[nchars]; - - for (int i = 0; i < nchars; ++i) - nc[i] = chars[start + i]; - - return createGlyphVector (font, frc, - new StringCharacterIterator (new String (nc))); + return new FreetypeGlyphVector( font, new String( chars, start, + limit - start), + frc, flags); } public LineMetrics getLineMetrics (Font font, String str, FontRenderContext frc) { - return new GdkFontLineMetrics (getFontMetrics (font), str.length ()); + return new GdkFontLineMetrics (this, getFontMetrics (font), str.length ()); } public FontMetrics getFontMetrics (Font font) @@ -374,4 +384,20 @@ public class GdkFontPeer extends ClasspathFontPeer return Toolkit.getDefaultToolkit().getFontMetrics (font); } + /** + * Returns a cached GlyphMetrics object for a given glyphcode, + * or null if it doesn't exist in the cache. + */ + GlyphMetrics getGlyphMetrics( int glyphCode ) + { + return (GlyphMetrics)metricsCache.get( new Integer( glyphCode ) ); + } + + /** + * Put a GlyphMetrics object in the cache. + */ + void putGlyphMetrics( int glyphCode, Object metrics ) + { + metricsCache.put( new Integer( glyphCode ), metrics ); + } } diff --git a/gnu/java/awt/peer/gtk/GdkGlyphVector.java b/gnu/java/awt/peer/gtk/GdkGlyphVector.java deleted file mode 100644 index f0ddea43a..000000000 --- a/gnu/java/awt/peer/gtk/GdkGlyphVector.java +++ /dev/null @@ -1,359 +0,0 @@ -/* GdkGlyphVector.java -- Glyph vector object - Copyright (C) 2003, 2004, 2005 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.Font; -import java.awt.Rectangle; -import java.awt.Shape; -import java.awt.font.FontRenderContext; -import java.awt.font.GlyphJustificationInfo; -import java.awt.font.GlyphMetrics; -import java.awt.font.GlyphVector; -import java.awt.geom.AffineTransform; -import java.awt.geom.Point2D; -import java.awt.geom.Rectangle2D; - -public class GdkGlyphVector extends GlyphVector -{ - - /* We use a simple representation for glyph vectors here. Glyph i - * consumes 8 doubles: - * - * logical x: extents[ 10*i ] - * logical y: extents[ 10*i + 1 ] - * logical width: extents[ 10*i + 2 ] - * logical height: extents[ 10*i + 3 ] - * - * visual x: extents[ 10*i + 4 ] - * visual y: extents[ 10*i + 5 ] - * visual width: extents[ 10*i + 6 ] - * visual height: extents[ 10*i + 7 ] - * - * origin pos x: extents[ 10*i + 8 ] - * origin pos y: extents[ 10*i + 9 ] - * - * as well as one int, code[i], representing the glyph code in the font. - */ - - double [] extents; - int [] codes; - - Font font; - FontRenderContext fontRenderContext; - - Rectangle2D allLogical; - Rectangle2D allVisual; - - public GdkGlyphVector(double[] extents, int[] codes, Font font, FontRenderContext frc) - { - this.extents = extents; - this.codes = codes; - this.font = font; - this.fontRenderContext = frc; - - allLogical = new Rectangle2D.Double(); - allVisual = new Rectangle2D.Double(); - - for (int i = 0; i < codes.length; ++i) - { - allLogical.add (new Rectangle2D.Double(extents[10*i ] + extents[10*i + 8], - extents[10*i + 1] + extents[10*i + 9], - extents[10*i + 2], - extents[10*i + 3])); - - allVisual.add (new Rectangle2D.Double(extents[10*i + 4] + extents[10*i + 8], - extents[10*i + 5] + extents[10*i + 9], - extents[10*i + 6], - extents[10*i + 7])); - } - } - - /* - geometric notes: - - the FRC contains a mapping from points -> pixels. - - typographics points are typically 1/72 of an inch. - - pixel displays are often around 72 dpi. - - so the FRC can get away with using an identity transform on a screen, - often. behavior is documented by sun to fall back to an identity - transform if the internal transformation is null. - - coordinates coming up from pango are expressed as floats -- in device - space, so basically pixels-with-fractional-bits -- derived from their - storage format in pango (1024ths of pixels). - - it is not clear from the javadocs whether the results of methods like - getGlyphPositions ought to return coordinates in device space, or - "point" space, or what. for now I'm returning them in device space. - - */ - - public double[] getExtents() - { - return extents; - } - - public int[] getCodes() - { - return codes; - } - - public Font getFont () - { - return font; - } - - public FontRenderContext getFontRenderContext () - { - return fontRenderContext; - } - - public int getGlyphCharIndex (int glyphIndex) - { - // FIXME: currently pango does not provide glyph-by-glyph - // reverse mapping information, so we assume a broken 1:1 - // glyph model here. This is plainly wrong. - return glyphIndex; - } - - public int[] getGlyphCharIndices (int beginGlyphIndex, - int numEntries, - int[] codeReturn) - { - int ix[] = codeReturn; - if (ix == null) - ix = new int[numEntries]; - - for (int i = 0; i < numEntries; i++) - ix[i] = getGlyphCharIndex (beginGlyphIndex + i); - return ix; - } - - public int getGlyphCode (int glyphIndex) - { - return codes[glyphIndex]; - } - - public int[] getGlyphCodes (int beginGlyphIndex, int numEntries, - int[] codeReturn) - { - if (codeReturn == null) - codeReturn = new int[numEntries]; - - System.arraycopy(codes, beginGlyphIndex, codeReturn, 0, numEntries); - return codeReturn; - } - - public Shape getGlyphLogicalBounds (int i) - { - return new Rectangle2D.Double (extents[8*i], extents[8*i + 1], - extents[8*i + 2], extents[8*i + 3]); - } - - public GlyphMetrics getGlyphMetrics (int i) - { - // FIXME: pango does not yield vertical layout information at the - // moment. - - boolean is_horizontal = true; - double advanceX = extents[8*i + 2]; // "logical width" == advanceX - double advanceY = 0; - - return new GlyphMetrics (is_horizontal, - (float) advanceX, (float) advanceY, - (Rectangle2D) getGlyphVisualBounds(i), - GlyphMetrics.STANDARD); - } - - public Shape getGlyphOutline (int glyphIndex) - { - throw new UnsupportedOperationException (); - } - - public Shape getGlyphOutline (int glyphIndex, float x, float y) - { - throw new UnsupportedOperationException (); - } - - public Rectangle getGlyphPixelBounds (int i, - FontRenderContext renderFRC, - float x, float y) - { - return new Rectangle((int) x, (int) y, - (int) extents[8*i + 6], (int) extents[8*i + 7]); - } - - public Point2D getGlyphPosition (int i) - { - return new Point2D.Double (extents[10*i + 8], - extents[10*i + 9]); - } - - public float[] getGlyphPositions (int beginGlyphIndex, - int numEntries, - float[] positionReturn) - { - float fx[] = positionReturn; - if (fx == null) - fx = new float[numEntries * 2]; - - for (int i = 0; i < numEntries; ++i) - { - fx[2*i ] = (float) extents[10*i + 8]; - fx[2*i + 1] = (float) extents[10*i + 9]; - } - return fx; - } - - public AffineTransform getGlyphTransform (int glyphIndex) - { - // Glyphs don't have independent transforms in these simple glyph - // vectors; docs specify null is an ok return here. - return null; - } - - public Shape getGlyphVisualBounds (int i) - { - return new Rectangle2D.Double(extents[8*i + 4], extents[8*i + 5], - extents[8*i + 6], extents[8*i + 7]); - } - - public int getLayoutFlags () - { - return 0; - } - - public Rectangle2D getLogicalBounds () - { - return allLogical; - } - - public int getNumGlyphs () - { - return codes.length; - } - - public Shape getOutline () - { - throw new UnsupportedOperationException (); - } - - public Rectangle getPixelBounds (FontRenderContext renderFRC, - float x, float y) - { - return new Rectangle((int)x, - (int)y, - (int) allVisual.getWidth(), - (int) allVisual.getHeight()); - } - - public Rectangle2D getVisualBounds () - { - return allVisual; - } - - public void performDefaultLayout () - { - } - - public void setGlyphPosition (int i, Point2D newPos) - { - extents[8*i ] = newPos.getX(); - extents[8*i + 1] = newPos.getY(); - - extents[8*i + 4] = newPos.getX(); - extents[8*i + 5] = newPos.getY(); - } - - public void setGlyphTransform (int glyphIndex, - AffineTransform newTX) - { - // not yet.. maybe not ever? - throw new UnsupportedOperationException (); - } - - public boolean equals(GlyphVector gv) - { - if (gv == null) - return false; - - if (! (gv instanceof GdkGlyphVector)) - return false; - - GdkGlyphVector ggv = (GdkGlyphVector) gv; - - if ((ggv.codes.length != this.codes.length) - || (ggv.extents.length != this.extents.length)) - return false; - - if ((ggv.font == null && this.font != null) - || (ggv.font != null && this.font == null) - || (!ggv.font.equals(this.font))) - return false; - - if ((ggv.fontRenderContext == null && this.fontRenderContext != null) - || (ggv.fontRenderContext != null && this.fontRenderContext == null) - || (!ggv.fontRenderContext.equals(this.fontRenderContext))) - return false; - - for (int i = 0; i < ggv.codes.length; ++i) - if (ggv.codes[i] != this.codes[i]) - return false; - - for (int i = 0; i < ggv.extents.length; ++i) - if (ggv.extents[i] != this.extents[i]) - return false; - - return true; - } - - public GlyphJustificationInfo getGlyphJustificationInfo(int idx) - { - throw new UnsupportedOperationException (); - } - - public Shape getOutline(float x, float y) - { - throw new UnsupportedOperationException (); - } - -} diff --git a/gnu/java/awt/peer/gtk/GdkGraphicsConfiguration.java b/gnu/java/awt/peer/gtk/GdkGraphicsConfiguration.java index 6cf7310a5..147f8f3e6 100644 --- a/gnu/java/awt/peer/gtk/GdkGraphicsConfiguration.java +++ b/gnu/java/awt/peer/gtk/GdkGraphicsConfiguration.java @@ -1,5 +1,5 @@ /* GdkGraphicsConfiguration.java -- describes characteristics of graphics - Copyright (C) 2000, 2001, 2002, 2003, 2004 Free Software Foundation + Copyright (C) 2000, 2001, 2002, 2003, 2004, 2006 Free Software Foundation This file is part of GNU Classpath. @@ -42,26 +42,33 @@ import java.awt.GraphicsConfiguration; import java.awt.GraphicsDevice; import java.awt.ImageCapabilities; import java.awt.Rectangle; -import java.awt.Toolkit; +import java.awt.Transparency; import java.awt.geom.AffineTransform; import java.awt.image.BufferedImage; import java.awt.image.ColorModel; +import java.awt.image.DirectColorModel; import java.awt.image.VolatileImage; public class GdkGraphicsConfiguration extends GraphicsConfiguration { GdkScreenGraphicsDevice gdkScreenGraphicsDevice; - ColorModel cm; - Rectangle bounds; + + ColorModel opaqueColorModel; + ColorModel bitmaskColorModel; + + ColorModel translucentColorModel; + public GdkGraphicsConfiguration(GdkScreenGraphicsDevice dev) { - this.gdkScreenGraphicsDevice = dev; - cm = new BufferedImage(1, 1, BufferedImage.TYPE_INT_ARGB).getColorModel(); - bounds = ((GtkToolkit) Toolkit.getDefaultToolkit()).getBounds(); + gdkScreenGraphicsDevice = dev; + + opaqueColorModel = new DirectColorModel(32, 0xFF0000, 0xFF00, 0xFF, 0); + bitmaskColorModel = new DirectColorModel(32, 0xFF0000, 0xFF00, 0xFF, 0x1000000); + translucentColorModel = new DirectColorModel(32, 0xFF0000, 0xFF00, 0xFF, 0xFF000000); } public GraphicsDevice getDevice() @@ -94,12 +101,21 @@ public class GdkGraphicsConfiguration public ColorModel getColorModel() { - return cm; + return opaqueColorModel; } public ColorModel getColorModel(int transparency) { - return getColorModel(); + switch (transparency) + { + case Transparency.OPAQUE: + return opaqueColorModel; + case Transparency.BITMASK: + return bitmaskColorModel; + default: + case Transparency.TRANSLUCENT: + return translucentColorModel; + } } public AffineTransform getDefaultTransform() @@ -116,7 +132,7 @@ public class GdkGraphicsConfiguration public Rectangle getBounds() { - return bounds; + return gdkScreenGraphicsDevice.getBounds(); } public BufferCapabilities getBufferCapabilities() @@ -133,8 +149,8 @@ public class GdkGraphicsConfiguration public VolatileImage createCompatibleVolatileImage(int width, int height, int transparency) { - // FIXME: implement - return null; + // FIXME: support the transparency argument + return new GtkVolatileImage(width, height); } } diff --git a/gnu/java/awt/peer/gtk/GdkGraphicsEnvironment.java b/gnu/java/awt/peer/gtk/GdkGraphicsEnvironment.java index b2615a912..035819d1c 100644 --- a/gnu/java/awt/peer/gtk/GdkGraphicsEnvironment.java +++ b/gnu/java/awt/peer/gtk/GdkGraphicsEnvironment.java @@ -1,5 +1,5 @@ /* GdkGraphicsEnvironment.java -- information about the graphics environment - Copyright (C) 2004, 2005 Free Software Foundation, Inc. + Copyright (C) 2004, 2005, 2006 Free Software Foundation, Inc. This file is part of GNU Classpath. @@ -43,30 +43,63 @@ import java.awt.Graphics2D; import java.awt.GraphicsDevice; import java.awt.GraphicsEnvironment; import java.awt.HeadlessException; -import java.awt.Toolkit; import java.awt.image.BufferedImage; import java.awt.image.DataBuffer; import java.util.Locale; public class GdkGraphicsEnvironment extends GraphicsEnvironment { + private final int native_state = GtkGenericPeer.getUniqueInteger (); + + private GdkScreenGraphicsDevice defaultDevice; + + private GdkScreenGraphicsDevice[] devices; + + static + { + System.loadLibrary("gtkpeer"); + + initStaticState (); + } + + static native void initStaticState(); + public GdkGraphicsEnvironment () { + nativeInitState(); } + + native void nativeInitState(); public GraphicsDevice[] getScreenDevices () { - // FIXME: Support multiple screens, since GDK can. - return new GraphicsDevice[] { new GdkScreenGraphicsDevice (this) }; + if (devices == null) + { + devices = nativeGetScreenDevices(); + } + + return (GraphicsDevice[]) devices.clone(); } + + private native GdkScreenGraphicsDevice[] nativeGetScreenDevices(); public GraphicsDevice getDefaultScreenDevice () { if (GraphicsEnvironment.isHeadless ()) throw new HeadlessException (); - - return new GdkScreenGraphicsDevice (this); + + synchronized (GdkGraphicsEnvironment.class) + { + if (defaultDevice == null) + { + defaultDevice = nativeGetDefaultScreenDevice(); + } + } + + return defaultDevice; } + + private native GdkScreenGraphicsDevice nativeGetDefaultScreenDevice(); public Graphics2D createGraphics (BufferedImage image) { @@ -89,10 +122,10 @@ public class GdkGraphicsEnvironment extends GraphicsEnvironment { String[] family_names; int array_size; - + array_size = nativeGetNumFontFamilies(); family_names = new String[array_size]; - + nativeGetFontFamilies(family_names); return family_names; } @@ -101,4 +134,5 @@ public class GdkGraphicsEnvironment extends GraphicsEnvironment { throw new java.lang.UnsupportedOperationException (); } + } diff --git a/gnu/java/awt/peer/gtk/GdkPixbufDecoder.java b/gnu/java/awt/peer/gtk/GdkPixbufDecoder.java index 4e6181f0e..cd047f267 100644 --- a/gnu/java/awt/peer/gtk/GdkPixbufDecoder.java +++ b/gnu/java/awt/peer/gtk/GdkPixbufDecoder.java @@ -103,8 +103,15 @@ public class GdkPixbufDecoder extends gnu.java.awt.image.ImageDecoder native void pumpBytes (byte[] bytes, int len) throws IOException; native void pumpDone () throws IOException; native void finish (boolean needsClose); - static native void streamImage(int[] bytes, String format, int width, int height, boolean hasAlpha, DataOutput sink); - + + /** + * Converts given image to bytes. + * Will call the GdkPixbufWriter for each chunk. + */ + static native void streamImage(int[] bytes, String format, + int width, int height, + boolean hasAlpha, GdkPixbufWriter writer); + // gdk-pixbuf provids data in RGBA format static final ColorModel cm = new DirectColorModel (32, 0xff000000, 0x00ff0000, @@ -461,7 +468,7 @@ public class GdkPixbufDecoder extends gnu.java.awt.image.ImageDecoder } private static class GdkPixbufWriter - extends ImageWriter + extends ImageWriter implements Runnable { String ext; public GdkPixbufWriter(GdkPixbufWriterSpi ownerSpi, Object ext) @@ -519,14 +526,106 @@ public class GdkPixbufDecoder extends gnu.java.awt.image.ImageDecoder model = img.getColorModel(); } + Thread workerThread = new Thread(this, "GdkPixbufWriter"); + workerThread.start(); processImageStarted(1); synchronized(pixbufLock) { streamImage(pixels, this.ext, width, height, model.hasAlpha(), - (DataOutput) this.getOutput()); + this); } + synchronized(data) + { + data.add(DATADONE); + data.notifyAll(); + } + + while (workerThread.isAlive()) + { + try + { + workerThread.join(); + } + catch (InterruptedException ioe) + { + // Ignored. + } + } + + if (exception != null) + throw exception; + processImageComplete(); } + + /** + * Object marking end of data from native streamImage code. + */ + private static final Object DATADONE = new Object(); + + /** + * Holds the data gotten from the native streamImage code. + * A worker thread will pull data out. + * Needs to be synchronized for access. + * The special object DATADONE is added when all data has been delivered. + */ + private ArrayList data = new ArrayList(); + + /** + * Holds any IOException thrown by the run method that needs + * to be rethrown by the write method. + */ + private IOException exception; + + /** Callback for streamImage native code. **/ + private void write(byte[] bs) + { + synchronized(data) + { + data.add(bs); + data.notifyAll(); + } + } + + public void run() + { + boolean done = false; + while (!done) + { + synchronized(data) + { + while (data.isEmpty()) + { + try + { + data.wait(); + } + catch (InterruptedException ie) + { + /* ignore */ + } + } + + Object o = data.remove(0); + if (o == DATADONE) + done = true; + else + { + DataOutput out = (DataOutput) getOutput(); + try + { + out.write((byte[]) o); + } + catch (IOException ioe) + { + // We are only interested in the first exception. + if (exception == null) + exception = ioe; + } + } + } + } + } } private static class GdkPixbufReader diff --git a/gnu/java/awt/peer/gtk/GdkScreenGraphicsDevice.java b/gnu/java/awt/peer/gtk/GdkScreenGraphicsDevice.java index b5d1237a4..62116a322 100644 --- a/gnu/java/awt/peer/gtk/GdkScreenGraphicsDevice.java +++ b/gnu/java/awt/peer/gtk/GdkScreenGraphicsDevice.java @@ -1,5 +1,5 @@ /* GdkScreenGraphicsDevice.java -- information about a screen device - Copyright (C) 2004, 2005 Free Software Foundation, Inc. + Copyright (C) 2004, 2005, 2006 Free Software Foundation, Inc. This file is part of GNU Classpath. @@ -38,44 +38,110 @@ exception statement from your version. */ package gnu.java.awt.peer.gtk; -import java.awt.Dimension; import java.awt.DisplayMode; +import java.awt.Frame; import java.awt.GraphicsConfiguration; import java.awt.GraphicsDevice; -import java.awt.Toolkit; +import java.awt.Rectangle; +import java.awt.Window; +import java.util.ArrayList; -public class GdkScreenGraphicsDevice extends GraphicsDevice +class GdkScreenGraphicsDevice extends GraphicsDevice { + private final int native_state = GtkGenericPeer.getUniqueInteger (); + + private Window fullscreenWindow; + + private boolean oldWindowDecorationState; + + private Rectangle oldWindowBounds; + + private Rectangle bounds; + + private GdkGraphicsConfiguration[] configurations; + + /** The <code>GdkGraphicsEnvironment</code> instance that created this + * <code>GdkScreenGraphicsDevice</code>. This is only needed for native + * methods which need to access the 'native_state' field storing a pointer + * to a GdkDisplay object. + */ GdkGraphicsEnvironment env; + + /** An identifier that is created by Gdk + */ + String idString; + + /** The display modes supported by this <code>GdkScreenGraphicsDevice</code>. + * If the array is <code>null</code> <code>nativeGetDisplayModes</code> has + * to be called. + */ + X11DisplayMode[] displayModes; - public GdkScreenGraphicsDevice (GdkGraphicsEnvironment e) - { - super (); + /** The non-changeable display mode of this <code>GdkScreenGraphicsDevice + * </code>. This field gets initialized by the {@link #init()} method. If it + * is still <code>null</code> afterwards, the XRandR extension is available + * and display mode changes are possible. If it is non-null XRandR is not + * available, no display mode changes are possible and no other native + * method must be called. + */ + DisplayMode fixedDisplayMode; + + static + { + System.loadLibrary("gtkpeer"); + + initStaticState (); + } + + static native void initStaticState(); + + GdkScreenGraphicsDevice (GdkGraphicsEnvironment e) + { + super(); env = e; + + configurations = new GdkGraphicsConfiguration[1]; + configurations[0] = new GdkGraphicsConfiguration(this); } + /** This method is called from the native side immediately after + * the constructor is run. + */ + void init() + { + fixedDisplayMode = nativeGetFixedDisplayMode(env); + } + + /** Depending on the availability of the XRandR extension the method returns + * the screens' non-changeable display mode or null, meaning that XRandR can + * handle display mode changes. + */ + native DisplayMode nativeGetFixedDisplayMode(GdkGraphicsEnvironment env); + public int getType () { + // Gdk manages only raster screens. return GraphicsDevice.TYPE_RASTER_SCREEN; } public String getIDstring () { - // FIXME: query X for this string - return "default GDK device ID string"; + if (idString == null) + idString = nativeGetIDString(); + + return idString; } + + private native String nativeGetIDString(); public GraphicsConfiguration[] getConfigurations () { - // FIXME: query X for the list of possible configurations - return new GraphicsConfiguration [] { new GdkGraphicsConfiguration(this) }; + return (GraphicsConfiguration[]) configurations.clone(); } - + public GraphicsConfiguration getDefaultConfiguration () { - - // FIXME: query X for default configuration - return new GdkGraphicsConfiguration(this); + return configurations[0]; } @@ -89,23 +155,193 @@ public class GdkScreenGraphicsDevice extends GraphicsDevice */ public DisplayMode getDisplayMode() { - // determine display mode - Dimension dim = Toolkit.getDefaultToolkit().getScreenSize(); - DisplayMode mode = new DisplayMode(dim.width, dim.height, 0, - DisplayMode.REFRESH_RATE_UNKNOWN); - return mode; + if (fixedDisplayMode != null) + return fixedDisplayMode; + + synchronized (this) + { + if (displayModes == null) + displayModes = nativeGetDisplayModes(env); + } + + int index = nativeGetDisplayModeIndex(env); + int rate = nativeGetDisplayModeRate(env); + + return new DisplayMode(displayModes[index].width, + displayModes[index].height, + DisplayMode.BIT_DEPTH_MULTI, + rate); + } + + native int nativeGetDisplayModeIndex(GdkGraphicsEnvironment env); + + native int nativeGetDisplayModeRate(GdkGraphicsEnvironment env); + + public DisplayMode[] getDisplayModes() + { + if (fixedDisplayMode != null) + return new DisplayMode[] { fixedDisplayMode }; + + synchronized (this) + { + if (displayModes == null) + displayModes = nativeGetDisplayModes(env); + } + + ArrayList list = new ArrayList(); + for(int i=0;i<displayModes.length;i++) + for(int j=0;j<displayModes[i].rates.length;j++) + list.add(new DisplayMode(displayModes[i].width, + displayModes[i].height, + DisplayMode.BIT_DEPTH_MULTI, + displayModes[i].rates[j])); + + return (DisplayMode[]) list.toArray(new DisplayMode[list.size()]); } + + native X11DisplayMode[] nativeGetDisplayModes(GdkGraphicsEnvironment env); /** - * This device does not yet support fullscreen exclusive mode, so this - * returns <code>false</code>. + * Real fullscreen exclusive mode is not supported. * * @return <code>false</code> * @since 1.4 */ public boolean isFullScreenSupported() { - return false; + return true; + } + + public boolean isDisplayChangeSupported() + { + return fixedDisplayMode == null; + } + + public void setDisplayMode(DisplayMode dm) + { + if (fixedDisplayMode != null) + throw new UnsupportedOperationException("Cannnot change display mode."); + + if (dm == null) + throw new IllegalArgumentException("DisplayMode must not be null."); + + synchronized (this) + { + if (displayModes == null) + displayModes = nativeGetDisplayModes(env); + } + + for (int i=0; i<displayModes.length; i++) + if (displayModes[i].width == dm.getWidth() + && displayModes[i].height == dm.getHeight()) + { + synchronized (this) + { + nativeSetDisplayMode(env, + i, + (short) dm.getRefreshRate()); + + bounds = null; + } + + return; + } + + throw new IllegalArgumentException("Mode not supported by this device."); + } + + native void nativeSetDisplayMode(GdkGraphicsEnvironment env, + int index, short rate); + + /** A class that simply encapsulates the X11 display mode data. + */ + static class X11DisplayMode + { + short[] rates; + int width; + int height; + + X11DisplayMode(int width, int height, short[] rates) + { + this.width = width; + this.height = height; + this.rates = rates; + } + + } + + public void setFullScreenWindow(Window w) + { + // Bring old fullscreen window back into its original state. + if (fullscreenWindow != null && w != fullscreenWindow) + { + if (fullscreenWindow instanceof Frame) + { + // Decoration state can only be switched when the peer is + // non-existent. That means we have to dispose the + // Frame. + Frame f = (Frame) fullscreenWindow; + if (oldWindowDecorationState != f.isUndecorated()) + { + f.dispose(); + f.setUndecorated(oldWindowDecorationState); + } + } + + fullscreenWindow.setBounds(oldWindowBounds); + + if (!fullscreenWindow.isVisible()) + fullscreenWindow.setVisible(true); + } + + // If applicable remove decoration, then maximize the window and + // bring it to the foreground. + if (w != null) + { + if (w instanceof Frame) + { + Frame f = (Frame) w; + oldWindowDecorationState = f.isUndecorated(); + if (!oldWindowDecorationState) + { + f.dispose(); + f.setUndecorated(true); + } + } + + oldWindowBounds = w.getBounds(); + + DisplayMode dm = getDisplayMode(); + + w.setBounds(0, 0, dm.getWidth(), dm.getHeight()); + + if (!w.isVisible()) + w.setVisible(true); + + w.requestFocus(); + w.toFront(); + + } + + fullscreenWindow = w; + } + + public Window getFullScreenWindow() + { + return fullscreenWindow; + } + + Rectangle getBounds() + { + synchronized(this) + { + if (bounds == null) + bounds = nativeGetBounds(); + } + + return bounds; } + + native Rectangle nativeGetBounds(); } diff --git a/gnu/java/awt/peer/gtk/GdkTextLayout.java b/gnu/java/awt/peer/gtk/GdkTextLayout.java deleted file mode 100644 index d6b3de8c0..000000000 --- a/gnu/java/awt/peer/gtk/GdkTextLayout.java +++ /dev/null @@ -1,393 +0,0 @@ -/* GdkTextLayout.java - Copyright (C) 2003, 2005 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 gnu.classpath.Configuration; -import gnu.java.awt.peer.ClasspathTextLayoutPeer; - -import java.awt.Font; -import java.awt.Graphics2D; -import java.awt.Shape; -import java.awt.font.FontRenderContext; -import java.awt.font.GlyphMetrics; -import java.awt.font.GlyphVector; -import java.awt.font.TextAttribute; -import java.awt.font.TextHitInfo; -import java.awt.font.TextLayout; -import java.awt.geom.AffineTransform; -import java.awt.geom.GeneralPath; -import java.awt.geom.Rectangle2D; -import java.text.AttributedCharacterIterator; -import java.text.AttributedString; -import java.text.CharacterIterator; - -/** - * This is an implementation of the text layout peer interface which - * delegates all the hard work to pango. - * - * @author Graydon Hoare - */ - -public class GdkTextLayout - implements ClasspathTextLayoutPeer -{ - // native side, plumbing, etc. - static - { - System.loadLibrary("gtkpeer"); - - initStaticState (); - } - private native void setText(String str); - private native void setFont(GdkFontPeer font); - private native void getExtents(double[] inkExtents, - double[] logExtents); - private native void indexToPos(int idx, double[] pos); - - private native void initState (); - - private native void dispose (); - - private native void cairoDrawGdkTextLayout(CairoGraphics2D g, float x, float y); - - static native void initStaticState(); - - private final int native_state = GtkGenericPeer.getUniqueInteger (); - - protected void finalize () - { - dispose (); - } - - // we hold on to these to make sure we can render when presented - // with non-GdkGraphics2D paint targets - private AttributedString attributedString; - private FontRenderContext fontRenderContext; - - public GdkTextLayout(AttributedString str, FontRenderContext frc) - { - initState(); - attributedString = str; - fontRenderContext = frc; - AttributedCharacterIterator aci = str.getIterator(); - char[] chars = new char[aci.getEndIndex() - aci.getBeginIndex()]; - for(int i = aci.getBeginIndex(); i < aci.getEndIndex(); i++) - chars[i] = aci.setIndex(i); - setText(new String(chars)); - - Object fnt = aci.getAttribute(TextAttribute.FONT); - if (fnt != null && fnt instanceof Font) - setFont( (GdkFontPeer) ((Font)fnt).getPeer() ); - } - - protected class CharacterIteratorProxy - implements CharacterIterator - { - public CharacterIterator target; - public int begin; - public int limit; - public int index; - - public CharacterIteratorProxy (CharacterIterator ci) - { - target = ci; - } - - public int getBeginIndex () - { - return begin; - } - - public int getEndIndex () - { - return limit; - } - - public int getIndex () - { - return index; - } - - public char setIndex (int idx) - throws IllegalArgumentException - { - if (idx < begin || idx >= limit) - throw new IllegalArgumentException (); - char ch = target.setIndex (idx); - index = idx; - return ch; - } - - public char first () - { - int save = target.getIndex (); - char ch = target.setIndex (begin); - target.setIndex (save); - return ch; - } - - public char last () - { - if (begin == limit) - return this.first (); - - int save = target.getIndex (); - char ch = target.setIndex (limit - 1); - target.setIndex (save); - return ch; - } - - public char current () - { - return target.current(); - } - - public char next () - { - if (index >= limit - 1) - return CharacterIterator.DONE; - else - { - index++; - return target.next(); - } - } - - public char previous () - { - if (index <= begin) - return CharacterIterator.DONE; - else - { - index--; - return target.previous (); - } - } - - public Object clone () - { - CharacterIteratorProxy cip = new CharacterIteratorProxy (this.target); - cip.begin = this.begin; - cip.limit = this.limit; - cip.index = this.index; - return cip; - } - - } - - - // public side - - public void draw (Graphics2D g2, float x, float y) - { - cairoDrawGdkTextLayout((CairoGraphics2D)g2, x, y); - } - - public TextHitInfo getStrongCaret (TextHitInfo hit1, - TextHitInfo hit2) - { - throw new Error("not implemented"); - } - - public byte getBaseline () - { - throw new Error("not implemented"); - } - - public boolean isLeftToRight () - { - throw new Error("not implemented"); - } - - public boolean isVertical () - { - throw new Error("not implemented"); - } - - public float getAdvance () - { - throw new Error("not implemented"); - } - - public float getAscent () - { - throw new Error("not implemented"); - } - - public float getDescent () - { - throw new Error("not implemented"); - } - - public float getLeading () - { - throw new Error("not implemented"); - } - - public int getCharacterCount () - { - throw new Error("not implemented"); - } - - public byte getCharacterLevel (int index) - { - throw new Error("not implemented"); - } - - public float[] getBaselineOffsets () - { - throw new Error("not implemented"); - } - - public Shape getBlackBoxBounds (int firstEndpoint, int secondEndpoint) - { - throw new Error("not implemented"); - } - - public Rectangle2D getBounds () - { - double[] inkExtents = new double[4]; - double[] logExtents = new double[4]; - getExtents(inkExtents, logExtents); - return new Rectangle2D.Double(logExtents[0], logExtents[1], - logExtents[2], logExtents[3]); - } - - public float[] getCaretInfo (TextHitInfo hit, Rectangle2D bounds) - { - throw new Error("not implemented"); - } - - public Shape getCaretShape (TextHitInfo hit, Rectangle2D bounds) - { - throw new Error("not implemented"); - } - - public Shape[] getCaretShapes (int offset, Rectangle2D bounds, - TextLayout.CaretPolicy policy) - { - throw new Error("not implemented"); - } - - public Shape getLogicalHighlightShape (int firstEndpoint, int secondEndpoint, - Rectangle2D bounds) - { - AffineTransform at = new AffineTransform(); - GeneralPath gp = new GeneralPath(); - double [] rect = new double[4]; - Rectangle2D tmp = new Rectangle2D.Double(); - for (int i = firstEndpoint; i <= secondEndpoint; ++i) - { - indexToPos(i, rect); - tmp.setRect(rect[0], rect[1], rect[2], rect[3]); - Rectangle2D.intersect(tmp, bounds, tmp); - gp.append(tmp.getPathIterator(at), false); - } - return gp; - } - - public int[] getLogicalRangesForVisualSelection (TextHitInfo firstEndpoint, - TextHitInfo secondEndpoint) - { - throw new Error("not implemented"); - } - - public TextHitInfo getNextLeftHit (int offset, TextLayout.CaretPolicy policy) - { - throw new Error("not implemented"); - } - public TextHitInfo getNextRightHit (int offset, TextLayout.CaretPolicy policy) - { - throw new Error("not implemented"); - } - public TextHitInfo hitTestChar (float x, float y, Rectangle2D bounds) - { - throw new Error("not implemented"); - } - public TextHitInfo getVisualOtherHit (TextHitInfo hit) - { - throw new Error("not implemented"); - } - - public float getVisibleAdvance () - { - throw new Error("not implemented"); - } - - public native Shape getOutline (AffineTransform tx); - - public Shape getVisualHighlightShape (TextHitInfo firstEndpoint, - TextHitInfo secondEndpoint, - Rectangle2D bounds) - { - throw new Error("not implemented"); - } - - - public TextLayout getJustifiedLayout (float justificationWidth) - { - throw new Error("not implemented"); - } - - public void handleJustify (float justificationWidth) - { - throw new Error("not implemented"); - } - - public Object clone () - { - throw new Error("not implemented"); - } - - public int hashCode () - { - throw new Error("not implemented"); - } - - public boolean equals (ClasspathTextLayoutPeer tl) - { - throw new Error("not implemented"); - } - - public String toString () - { - throw new Error("not implemented"); - } - -} diff --git a/gnu/java/awt/peer/gtk/GtkCheckboxPeer.java b/gnu/java/awt/peer/gtk/GtkCheckboxPeer.java index 094aa3c03..1c5400c27 100644 --- a/gnu/java/awt/peer/gtk/GtkCheckboxPeer.java +++ b/gnu/java/awt/peer/gtk/GtkCheckboxPeer.java @@ -40,20 +40,32 @@ package gnu.java.awt.peer.gtk; import java.awt.Checkbox; import java.awt.CheckboxGroup; -import java.awt.peer.CheckboxPeer; - import java.awt.event.ItemEvent; +import java.awt.peer.CheckboxPeer; +import java.util.WeakHashMap; +/** + * This class wraps either a GtkCheckButton or a GtkOptionButton + * depending on if this peer's owner belongs to a CheckboxGroup. + */ public class GtkCheckboxPeer extends GtkComponentPeer implements CheckboxPeer { - // Group from last time it was set. - public GtkCheckboxGroupPeer old_group; + // The CheckboxGroup to which this GtkCheckboxPeer's owner belongs. + public CheckboxGroup current_group; // The current state of the GTK checkbox. - private boolean currentState; + private boolean currentState; + + // A map from CheckboxGroup to GSList* GTK option group pointer. + private static WeakHashMap groupMap = new WeakHashMap(); + + public native void createCheckButton (); + public native void createRadioButton (long groupPointer); - public native void create (GtkCheckboxGroupPeer group); - public native void nativeSetCheckboxGroup (GtkCheckboxGroupPeer group); + public native void addToGroup (long groupPointer); + public native void removeFromGroup (); + public native void switchToGroup (long groupPointer); + public native void connectSignals (); /** @@ -68,17 +80,47 @@ public class GtkCheckboxPeer extends GtkComponentPeer super (c); } - // FIXME: we must be able to switch between a checkbutton and a - // radiobutton dynamically. public void create () { Checkbox checkbox = (Checkbox) awtComponent; - CheckboxGroup g = checkbox.getCheckboxGroup (); - old_group = GtkCheckboxGroupPeer.getCheckboxGroupPeer (g); - create (old_group); + current_group = checkbox.getCheckboxGroup (); + if (current_group == null) + { + // Initially we're not part of a group so we're backed by a + // GtkCheckButton. + createCheckButton(); + } + else + { + // Initially we're part of a group. + + // See if this group is already stored in our map. + Long groupPointer = null; + synchronized (groupMap) + { + groupPointer = (Long) groupMap.get(current_group); + } + + if (groupPointer == null) + { + // We don't know about this group. Create a new native + // group pointer for this group and store it in our map. + createRadioButton(0); + } + else + { + // We already know about this group. Pass the + // corresponding native group pointer value to the native + // create method. + createRadioButton(groupPointer.longValue()); + } + } currentState = checkbox.getState(); gtkToggleButtonSetActive(currentState); - gtkButtonSetLabel (checkbox.getLabel ()); + + String label = checkbox.getLabel(); + if (label != null) + gtkButtonSetLabel(label); } /** @@ -87,7 +129,7 @@ public class GtkCheckboxPeer extends GtkComponentPeer * event since events should only be posted for user initiated * clicks on the GtkCheckButton. */ - synchronized public void setState (boolean state) + public synchronized void setState (boolean state) { if (currentState != state) { @@ -103,21 +145,87 @@ public class GtkCheckboxPeer extends GtkComponentPeer public void setCheckboxGroup (CheckboxGroup group) { - GtkCheckboxGroupPeer gp - = GtkCheckboxGroupPeer.getCheckboxGroupPeer (group); - if (gp != old_group) + if (current_group == null && group != null) { - if (old_group != null) - old_group.remove (this); - nativeSetCheckboxGroup (gp); - old_group = gp; + // This peer's owner is currently not in a group, and now + // we're adding it to a group. This means that the backing + // GtkWidget will change from a GtkCheckButton to a + // GtkRadioButton. + + current_group = group; + + // See if the new group is already stored in our map. + Long groupPointer = null; + synchronized (groupMap) + { + groupPointer = (Long) groupMap.get(current_group); + } + + if (groupPointer == null) + { + // We don't know about this group. Create a new native + // group pointer for this group and store it in our map. + addToGroup(0); + } + else + { + // We already know about this group. Pass the + // corresponding native group pointer value to the native + // create method. + addToGroup(groupPointer.longValue()); + } + } + else if (current_group != null && group == null) + { + // This peer's owner is currently in a group, and now we're + // removing it from a group. This means that the backing + // GtkWidget will change from a GtkRadioButton to a + // GtkCheckButton. + removeFromGroup(); + current_group = null; + } + else if (current_group == null && group == null) + { + // This peer's owner is currently not in a group, and we're + // not adding it to a group, so simply return. + return; + } + else if (current_group != group) + { + // This peer's owner is currently in a group, and now we're + // putting it in another group. This means that we must + // remove the backing GtkRadioButton from one group and add it + // to the other group. + + current_group = group; + + // See if the new group is already stored in our map. + Long groupPointer = null; + synchronized (groupMap) + { + groupPointer = (Long) groupMap.get(current_group); + } + + if (groupPointer == null) + { + // We don't know about this group. Create a new native + // group pointer for this group and store it in our map. + switchToGroup(0); + } + else + { + // We already know about this group. Pass the + // corresponding native group pointer value to the native + // create method. + switchToGroup(groupPointer.longValue()); + } } } // Override the superclass postItemEvent so that the peer doesn't // need information that we have. // called back by native side: item_toggled_cb - synchronized public void postItemEvent(Object item, boolean state) + public synchronized void postItemEvent(Object item, boolean state) { // Only fire event is state actually changed. if (currentState != state) @@ -127,13 +235,17 @@ public class GtkCheckboxPeer extends GtkComponentPeer state ? ItemEvent.SELECTED : ItemEvent.DESELECTED); } } + + public void addToGroupMap(long groupPointer) + { + synchronized (groupMap) + { + groupMap.put(current_group, new Long (groupPointer)); + } + } public void dispose () { - // Notify the group so that the native state can be cleaned up - // appropriately. - if (old_group != null) - old_group.remove (this); super.dispose (); } } diff --git a/gnu/java/awt/peer/gtk/GtkComponentPeer.java b/gnu/java/awt/peer/gtk/GtkComponentPeer.java index 625855f01..dcbac1259 100644 --- a/gnu/java/awt/peer/gtk/GtkComponentPeer.java +++ b/gnu/java/awt/peer/gtk/GtkComponentPeer.java @@ -52,6 +52,8 @@ import java.awt.Font; import java.awt.FontMetrics; import java.awt.Graphics; import java.awt.GraphicsConfiguration; +import java.awt.GraphicsDevice; +import java.awt.GraphicsEnvironment; import java.awt.Image; import java.awt.Insets; import java.awt.ItemSelectable; @@ -647,8 +649,10 @@ public class GtkComponentPeer extends GtkGenericPeer public GraphicsConfiguration getGraphicsConfiguration () { - // FIXME: just a stub for now. - return null; + // FIXME: The component might be showing on a non-default screen. + GraphicsEnvironment env = GraphicsEnvironment.getLocalGraphicsEnvironment(); + GraphicsDevice dev = env.getDefaultScreenDevice(); + return dev.getDefaultConfiguration(); } public void setEventMask (long mask) diff --git a/gnu/java/awt/peer/gtk/GtkLabelPeer.java b/gnu/java/awt/peer/gtk/GtkLabelPeer.java index bbf4230b3..02db90d72 100644 --- a/gnu/java/awt/peer/gtk/GtkLabelPeer.java +++ b/gnu/java/awt/peer/gtk/GtkLabelPeer.java @@ -56,7 +56,7 @@ public class GtkLabelPeer extends GtkComponentPeer native void nativeSetAlignment (float alignment); - public native void setText(String text); + public native void setNativeText(String text); native void setNativeBounds (int x, int y, int width, int height); // Because this is a composite widget, we need to retrieve the @@ -69,6 +69,12 @@ public class GtkLabelPeer extends GtkComponentPeer create (label.getText (), getGtkAlignment (label.getAlignment ())); } + public void setText(String text) + { + if (text != null) + setNativeText(text); + } + public GtkLabelPeer (Label l) { super (l); diff --git a/gnu/java/awt/peer/gtk/GtkToolkit.java b/gnu/java/awt/peer/gtk/GtkToolkit.java index 163fc52f7..fdd7e09cb 100644 --- a/gnu/java/awt/peer/gtk/GtkToolkit.java +++ b/gnu/java/awt/peer/gtk/GtkToolkit.java @@ -39,32 +39,82 @@ exception statement from your version. */ package gnu.java.awt.peer.gtk; -import gnu.classpath.Configuration; import gnu.java.awt.EmbeddedWindow; +import gnu.java.awt.dnd.GtkMouseDragGestureRecognizer; +import gnu.java.awt.dnd.peer.gtk.GtkDragSourceContextPeer; import gnu.java.awt.peer.ClasspathFontPeer; -import gnu.java.awt.peer.ClasspathTextLayoutPeer; import gnu.java.awt.peer.EmbeddedWindowPeer; -import java.awt.*; +import java.awt.AWTException; +import java.awt.Button; +import java.awt.Canvas; +import java.awt.Checkbox; +import java.awt.CheckboxMenuItem; +import java.awt.Choice; +import java.awt.Component; +import java.awt.Cursor; +import java.awt.Dialog; +import java.awt.Dimension; +import java.awt.EventQueue; +import java.awt.FileDialog; +import java.awt.Font; +import java.awt.FontMetrics; +import java.awt.Frame; +import java.awt.GraphicsDevice; +import java.awt.GraphicsEnvironment; +import java.awt.Image; +import java.awt.Label; +import java.awt.List; +import java.awt.Menu; +import java.awt.MenuBar; +import java.awt.MenuItem; +import java.awt.Panel; +import java.awt.Point; +import java.awt.PopupMenu; +import java.awt.PrintJob; +import java.awt.Rectangle; +import java.awt.ScrollPane; +import java.awt.Scrollbar; +import java.awt.TextArea; +import java.awt.TextField; +import java.awt.Window; import java.awt.datatransfer.Clipboard; import java.awt.dnd.DragGestureEvent; +import java.awt.dnd.DragGestureListener; +import java.awt.dnd.DragGestureRecognizer; +import java.awt.dnd.DragSource; import java.awt.dnd.peer.DragSourceContextPeer; -import java.awt.font.FontRenderContext; import java.awt.im.InputMethodHighlight; -import java.awt.image.BufferedImage; import java.awt.image.ColorModel; import java.awt.image.DirectColorModel; -import java.awt.image.ImageConsumer; import java.awt.image.ImageObserver; import java.awt.image.ImageProducer; -import java.awt.peer.*; +import java.awt.peer.ButtonPeer; +import java.awt.peer.CanvasPeer; +import java.awt.peer.CheckboxMenuItemPeer; +import java.awt.peer.CheckboxPeer; +import java.awt.peer.ChoicePeer; +import java.awt.peer.DialogPeer; +import java.awt.peer.FileDialogPeer; +import java.awt.peer.FontPeer; +import java.awt.peer.FramePeer; +import java.awt.peer.LabelPeer; +import java.awt.peer.ListPeer; +import java.awt.peer.MenuBarPeer; +import java.awt.peer.MenuItemPeer; +import java.awt.peer.MenuPeer; +import java.awt.peer.PanelPeer; +import java.awt.peer.PopupMenuPeer; +import java.awt.peer.RobotPeer; +import java.awt.peer.ScrollPanePeer; +import java.awt.peer.ScrollbarPeer; +import java.awt.peer.TextAreaPeer; +import java.awt.peer.TextFieldPeer; +import java.awt.peer.WindowPeer; import java.io.InputStream; import java.net.URL; -import java.text.AttributedString; import java.util.HashMap; -import java.util.HashSet; import java.util.Hashtable; -import java.util.Iterator; import java.util.LinkedHashMap; import java.util.Map; import java.util.Properties; @@ -310,6 +360,11 @@ public class GtkToolkit extends gnu.java.awt.ClasspathToolkit public PrintJob getPrintJob (Frame frame, String jobtitle, Properties props) { + SecurityManager sm; + sm = System.getSecurityManager(); + if (sm != null) + sm.checkPrintJobAccess(); + return null; } @@ -528,12 +583,6 @@ public class GtkToolkit extends gnu.java.awt.ClasspathToolkit } } - public ClasspathTextLayoutPeer getClasspathTextLayoutPeer (AttributedString str, - FontRenderContext frc) - { - return new GdkTextLayout(str, frc); - } - protected EventQueue getSystemEventQueueImpl() { synchronized (GtkToolkit.class) @@ -555,7 +604,18 @@ public class GtkToolkit extends gnu.java.awt.ClasspathToolkit public DragSourceContextPeer createDragSourceContextPeer(DragGestureEvent e) { - throw new Error("not implemented"); + return new GtkDragSourceContextPeer(e); + } + + public DragGestureRecognizer createDragGestureRecognizer(Class recognizer, + DragSource ds, + Component comp, + int actions, + DragGestureListener l) + { + if (recognizer.getName().equals("java.awt.dnd.MouseDragGestureRecognizer")) + return new GtkMouseDragGestureRecognizer(ds, comp, actions, l); + return null; } public Map mapInputMethodHighlight(InputMethodHighlight highlight) diff --git a/gnu/java/awt/peer/gtk/GtkVolatileImage.java b/gnu/java/awt/peer/gtk/GtkVolatileImage.java index cebb715ab..44e7b027b 100644 --- a/gnu/java/awt/peer/gtk/GtkVolatileImage.java +++ b/gnu/java/awt/peer/gtk/GtkVolatileImage.java @@ -50,25 +50,36 @@ public class GtkVolatileImage extends VolatileImage int width, height; private ImageCapabilities caps; + final GtkComponentPeer component; + /** * Don't touch, accessed from native code. */ - private long nativePointer; + long nativePointer; - /** - * Offscreen image we draw to. - */ - CairoSurface offScreen; + native long init(GtkComponentPeer component, int width, int height); - private boolean needsUpdate = false; + native void destroy(long pointer); - native long init(GtkComponentPeer component, int width, int height); + native int[] nativeGetPixels(long pointer); + public int[] getPixels() + { + return nativeGetPixels(nativePointer); + } - native void destroy(); + native void nativeCopyArea(long pointer, int x, int y, int w, int h, int dx, + int dy ); + public void copyArea(int x, int y, int w, int h, int dx, int dy) + { + nativeCopyArea(nativePointer, x, y, w, h, dx, dy); + } - native int[] getPixels(); - - native void update(GtkImage image); + native void nativeDrawVolatile(long pointer, long srcPtr, int x, int y, + int w, int h ); + public void drawVolatile(long srcPtr, int x, int y, int w, int h ) + { + nativeDrawVolatile(nativePointer, srcPtr, x, y, w, h); + } public GtkVolatileImage(GtkComponentPeer component, int width, int height, ImageCapabilities caps) @@ -76,8 +87,8 @@ public class GtkVolatileImage extends VolatileImage this.width = width; this.height = height; this.caps = caps; + this.component = component; nativePointer = init( component, width, height ); - offScreen = new CairoSurface( width, height ); } public GtkVolatileImage(int width, int height, ImageCapabilities caps) @@ -97,12 +108,7 @@ public class GtkVolatileImage extends VolatileImage public void dispose() { - destroy(); - } - - void invalidate() - { - needsUpdate = true; + destroy(nativePointer); } public BufferedImage getSnapshot() @@ -119,24 +125,17 @@ public class GtkVolatileImage extends VolatileImage public Graphics2D createGraphics() { - invalidate(); - return offScreen.getGraphics(); + return new VolatileImageGraphics( this ); } public int validate(GraphicsConfiguration gc) { - if( needsUpdate ) - { - update( offScreen.getGtkImage() ); - needsUpdate = false; - return VolatileImage.IMAGE_RESTORED; - } return VolatileImage.IMAGE_OK; } public boolean contentsLost() { - return needsUpdate; + return false; } public ImageCapabilities getCapabilities() diff --git a/gnu/java/awt/peer/gtk/VolatileImageGraphics.java b/gnu/java/awt/peer/gtk/VolatileImageGraphics.java index 81de3d705..de67b316e 100644 --- a/gnu/java/awt/peer/gtk/VolatileImageGraphics.java +++ b/gnu/java/awt/peer/gtk/VolatileImageGraphics.java @@ -58,72 +58,68 @@ import java.awt.image.RenderedImage; import java.awt.image.ImageObserver; import java.util.WeakHashMap; -public class VolatileImageGraphics extends CairoSurfaceGraphics +public class VolatileImageGraphics extends ComponentGraphics { private GtkVolatileImage owner; - public VolatileImageGraphics(GtkVolatileImage owner) + public VolatileImageGraphics(GtkVolatileImage img) { - super( owner.offScreen ); - this.owner = owner; - } - - VolatileImageGraphics(VolatileImageGraphics copyFrom) - { - super( copyFrom.owner.offScreen ); - owner = copyFrom.owner; + this.owner = img; + cairo_t = initFromVolatile( owner.nativePointer, img.width, img.height ); + setup( cairo_t ); } - /** - * Abstract methods. - */ - public Graphics create() + private VolatileImageGraphics(VolatileImageGraphics copy) { - return new VolatileImageGraphics( this ); + this.owner = copy.owner; + cairo_t = initFromVolatile(owner.nativePointer, owner.width, owner.height); + copy( copy, cairo_t ); } - + public void copyAreaImpl(int x, int y, int width, int height, int dx, int dy) { - surface.copyAreaNative(x, y, width, height, dx, dy, surface.width); - owner.invalidate(); + owner.copyArea(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) + public GraphicsConfiguration getDeviceConfiguration() { - super.draw(s); - Rectangle r = s.getBounds(); - owner.invalidate(); + return owner.component.getGraphicsConfiguration(); } - public void fill(Shape s) + public Graphics create() { - super.fill(s); - Rectangle r = s.getBounds(); - owner.invalidate(); + return new VolatileImageGraphics( this ); } - public void drawRenderedImage(RenderedImage image, AffineTransform xform) + + public boolean drawImage(Image img, int x, int y, ImageObserver observer) { - super.drawRenderedImage(image, xform); - owner.invalidate(); + if( img instanceof GtkVolatileImage ) + { + owner.drawVolatile( ((GtkVolatileImage)img).nativePointer, + x, y, + ((GtkVolatileImage)img).width, + ((GtkVolatileImage)img).height ); + return true; + } + return super.drawImage( img, x, y, observer ); } - - protected boolean drawImage(Image img, AffineTransform xform, - Color bgcolor, ImageObserver obs) + + public boolean drawImage(Image img, int x, int y, int width, int height, + ImageObserver observer) { - boolean rv = super.drawImage(img, xform, bgcolor, obs); - owner.invalidate(); - return rv; + if( img instanceof GtkVolatileImage ) + { + owner.drawVolatile( ((GtkVolatileImage)img).nativePointer, + x, y, width, height ); + return true; + } + return super.drawImage( img, x, y, width, height, observer ); } - public void drawGlyphVector(GlyphVector gv, float x, float y) + protected Rectangle2D getRealBounds() { - super.drawGlyphVector(gv, x, y); - owner.invalidate(); + return new Rectangle2D.Double(0, 0, owner.width, owner.height); } } diff --git a/gnu/java/awt/peer/qt/QtGraphics.java b/gnu/java/awt/peer/qt/QtGraphics.java index f9b4f2672..7b828f7e9 100644 --- a/gnu/java/awt/peer/qt/QtGraphics.java +++ b/gnu/java/awt/peer/qt/QtGraphics.java @@ -38,6 +38,7 @@ exception statement from your version. */ package gnu.java.awt.peer.qt; import java.awt.AlphaComposite; +import java.awt.AWTPermission; import java.awt.BasicStroke; import java.awt.Color; import java.awt.Composite; @@ -605,8 +606,16 @@ public abstract class QtGraphics extends Graphics2D composite = comp; } else - throw new UnsupportedOperationException("We don't support custom"+ - " composites yet."); + { + // FIXME: this check is only required "if this Graphics2D + // context is drawing to a Component on the display screen". + SecurityManager sm = System.getSecurityManager(); + if (sm != null) + sm.checkPermission(new AWTPermission("readDisplayPixels")); + + throw new UnsupportedOperationException("We don't support custom"+ + " composites yet."); + } } public Composite getComposite() diff --git a/gnu/java/awt/peer/qt/QtToolkit.java b/gnu/java/awt/peer/qt/QtToolkit.java index 591b52803..a8bfb1b51 100644 --- a/gnu/java/awt/peer/qt/QtToolkit.java +++ b/gnu/java/awt/peer/qt/QtToolkit.java @@ -41,7 +41,6 @@ import gnu.classpath.Configuration; import gnu.java.awt.EmbeddedWindow; import gnu.java.awt.peer.ClasspathFontPeer; import gnu.java.awt.peer.EmbeddedWindowPeer; -import gnu.java.awt.peer.ClasspathTextLayoutPeer; import java.awt.AWTEvent; import java.awt.AWTException; import java.awt.Button; @@ -136,8 +135,7 @@ public class QtToolkit extends ClasspathToolkit { eventQueue = new EventQueue(); repaintThread = new QtRepaintThread(); - if (Configuration.INIT_LOAD_LIBRARY) - System.loadLibrary("qtpeer"); + System.loadLibrary("qtpeer"); String theme = null; try @@ -403,6 +401,11 @@ public class QtToolkit extends ClasspathToolkit String jobtitle, Properties props) { + SecurityManager sm; + sm = System.getSecurityManager(); + if (sm != null) + sm.checkPrintJobAccess(); + throw new RuntimeException("Not implemented"); } @@ -446,12 +449,6 @@ public class QtToolkit extends ClasspathToolkit return new QtFontPeer (name, attrs); } - public ClasspathTextLayoutPeer getClasspathTextLayoutPeer(AttributedString str, - FontRenderContext frc) - { - return null; - } - // FIXME public Font createFont(int format, InputStream stream) { diff --git a/gnu/java/awt/peer/swing/SwingComponentPeer.java b/gnu/java/awt/peer/swing/SwingComponentPeer.java index f60c8e96c..96ccc00b8 100644 --- a/gnu/java/awt/peer/swing/SwingComponentPeer.java +++ b/gnu/java/awt/peer/swing/SwingComponentPeer.java @@ -48,8 +48,6 @@ import java.awt.Font; import java.awt.FontMetrics; import java.awt.Graphics; import java.awt.GraphicsConfiguration; -import java.awt.GraphicsDevice; -import java.awt.GraphicsEnvironment; import java.awt.Image; import java.awt.Point; import java.awt.Rectangle; @@ -101,8 +99,8 @@ public class SwingComponentPeer /** * Creates a SwingComponentPeer instance. Subclasses are expected to call * this constructor and thereafter call - * {@link #init(Component, SwingComponent)} in order to setup the AWT and - * Swing components properly. + * {@link #init(Component,SwingComponent)} + * in order to setup the AWT and Swing components properly. */ protected SwingComponentPeer() { @@ -167,12 +165,9 @@ public class SwingComponentPeer */ public Image createImage(int width, int height) { - GraphicsEnvironment graphicsEnv = - GraphicsEnvironment.getLocalGraphicsEnvironment(); - GraphicsDevice dev = graphicsEnv.getDefaultScreenDevice(); - GraphicsConfiguration conf = dev.getDefaultConfiguration(); - Image image = conf.createCompatibleImage(width, height); - return image; + Component parent = awtComponent.getParent(); + ComponentPeer parentPeer = parent.getPeer(); + return parentPeer.createImage(width, height); } /** @@ -336,21 +331,24 @@ public class SwingComponentPeer { case PaintEvent.UPDATE: case PaintEvent.PAINT: - Graphics g = getGraphics(); - Rectangle clip = ((PaintEvent)e).getUpdateRect(); - g.clipRect(clip.x, clip.y, clip.width, clip.height); - //if (this instanceof LightweightPeer) - // { + // This only will work when the component is showing. + if (awtComponent.isShowing()) + { + Graphics g = getGraphics(); + Rectangle clip = ((PaintEvent)e).getUpdateRect(); + g.clipRect(clip.x, clip.y, clip.width, clip.height); + //if (this instanceof LightweightPeer) + // { if (e.getID() == PaintEvent.UPDATE) awtComponent.update(g); else awtComponent.paint(g); - // } - // We paint the 'heavyweights' at last, so that they appear on top of - // everything else. - peerPaint(g); - - g.dispose(); + // } + // We paint the 'heavyweights' at last, so that they appear on top of + // everything else. + peerPaint(g); + g.dispose(); + } break; case MouseEvent.MOUSE_PRESSED: case MouseEvent.MOUSE_RELEASED: @@ -384,6 +382,11 @@ public class SwingComponentPeer { if (swingComponent != null) swingComponent.getJComponent().setVisible(false); + + Component parent = awtComponent.getParent(); + if (parent != null) + parent.repaint(awtComponent.getX(), awtComponent.getY(), + awtComponent.getWidth(), awtComponent.getHeight()); } /** @@ -470,17 +473,15 @@ public class SwingComponentPeer public boolean prepareImage(Image img, int width, int height, ImageObserver ob) { Component parent = awtComponent.getParent(); - boolean res; if(parent != null) - { - ComponentPeer parentPeer = parent.getPeer(); - res = parentPeer.prepareImage(img, width, height, ob); - } + { + ComponentPeer parentPeer = parent.getPeer(); + return parentPeer.prepareImage(img, width, height, ob); + } else - { - res = Toolkit.getDefaultToolkit().prepareImage(img, width, height, ob); - } - return res; + { + return Toolkit.getDefaultToolkit().prepareImage(img, width, height, ob); + } } public void print(Graphics graphics) @@ -662,8 +663,10 @@ public class SwingComponentPeer */ public void setVisible(boolean visible) { - if (swingComponent != null) - swingComponent.getJComponent().setVisible(visible); + if (visible) + show(); + else + hide(); } /** @@ -782,8 +785,13 @@ public class SwingComponentPeer public VolatileImage createVolatileImage(int width, int height) { Component parent = awtComponent.getParent(); - ComponentPeer parentPeer = parent.getPeer(); - return parentPeer.createVolatileImage(width, height); + VolatileImage im = null; + if (parent != null) + { + ComponentPeer parentPeer = parent.getPeer(); + im = parentPeer.createVolatileImage(width, height); + } + return im; } /** diff --git a/gnu/java/awt/peer/x/GLGraphics.java b/gnu/java/awt/peer/x/GLGraphics.java new file mode 100644 index 000000000..c80c85c28 --- /dev/null +++ b/gnu/java/awt/peer/x/GLGraphics.java @@ -0,0 +1,123 @@ +/* GLGraphics.java -- Graphics2D impl on top of GLX + 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.x; + +import java.awt.Color; +import java.awt.GraphicsConfiguration; +import java.awt.image.ColorModel; + +import gnu.java.awt.java2d.AbstractGraphics2D; +import gnu.x11.extension.glx.GL; + +/** + * An implementation of Graphics2D on top of the GLX extension of X. + * + * @author Roman Kennke (kennke@aicas.com) + */ +public class GLGraphics extends AbstractGraphics2D +{ + + /** + * The rendering context. + */ + private GL gl; + + /** + * Creates a new GLGraphics that paints on the specified GL context. + * + * @param g the GL context to paint to + */ + GLGraphics(GL g) + { + gl = g; + } + + public void setBackground(Color b) + { + super.setBackground(b); + gl.clear_color(b.getRed() / 255.F, b.getGreen() / 255.F, + b.getBlue() / 255.F, b.getAlpha() / 255.F); + } + + public void clearRect(int x, int y, int w, int h) + { + // TODO: Maybe use fillRect(). + gl.clear(GL.COLOR_BUFFER_BIT); + } + + public void drawLine(int x1, int y1, int x2, int y2) + { + gl.begin(GL.LINES); + gl.vertex2i(x1, y1); + gl.vertex2i(x2, y2); + gl.end(); + // TODO: Maybe do: + // gl.flush(); + } + + public void drawRect(int x, int y, int w, int h) + { + gl.polygon_mode(GL.FRONT_AND_BACK, GL.LINE); + gl.begin(GL.POLYGON); + gl.recti(x, y, x + w, y + h); + gl.end(); + // TODO: Maybe do: + // gl.flush(); + } + + public void fillRect(int x, int y, int w, int h) + { + gl.polygon_mode(GL.FRONT_AND_BACK, GL.FILL); + gl.recti(x, y, x + w, y + h); + // TODO: Maybe do: + // gl.flush(); + } + + protected ColorModel getColorModel() + { + // FIXME: Implement this. + throw new UnsupportedOperationException("Not yet implemented"); + } + + public GraphicsConfiguration getDeviceConfiguration() + { + // FIXME: Implement this. + throw new UnsupportedOperationException("Not yet implemented"); + } + +} diff --git a/gnu/java/awt/peer/x/ImageConverter.java b/gnu/java/awt/peer/x/ImageConverter.java new file mode 100644 index 000000000..6d32448ee --- /dev/null +++ b/gnu/java/awt/peer/x/ImageConverter.java @@ -0,0 +1,113 @@ +/* ImageConverter.java -- Convert arbitrary Image impl to XImage + 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.x; + +import java.awt.Color; +import java.awt.Graphics; +import java.awt.image.ColorModel; +import java.awt.image.ImageConsumer; +import java.util.Hashtable; + +/** + * Convert a non-XImage to an XImage. + * + * @author Roman Kennke (kennke@aicas.com) + */ +public class ImageConverter implements ImageConsumer +{ + + private XImage image; + private Graphics imageGraphics; + + public void setDimensions(int width, int height) + { + image = new XImage(width, height); + } + + public void setProperties(Hashtable props) + { + // Ignore for now. + } + + public void setColorModel(ColorModel model) + { + // Ignore for now. + } + + public void setHints(int flags) + { + // Ignore for now. + } + + public void setPixels(int x, int y, int w, int h, ColorModel model, + byte[] pixels, int offset, int scansize) + { + // FIXME: Implement this. + throw new UnsupportedOperationException("Not yet implemented"); + } + + public void setPixels(int x, int y, int w, int h, ColorModel model, + int[] pixels, int offset, int scansize) + { + System.err.println("transferType: " + model.getTransferType()); + System.err.println("colorModel: " + model); + if (imageGraphics == null) + imageGraphics = image.getGraphics(); + int xend = x + w; + int yend = y + h; + for (int yy = y; yy < yend; yy++) + { + for (int xx = x; xx < xend; xx++) + { + int pixel = pixels[yy * scansize + xx + offset]; + imageGraphics.setColor(new Color(model.getRGB(pixel))); + imageGraphics.fillRect(xx, yy, 1, 1); + } + } + } + + public void imageComplete(int status) + { + // Nothing to do here. + } + + XImage getXImage() + { + return image; + } +} diff --git a/gnu/java/awt/peer/x/KeyboardMapping.java b/gnu/java/awt/peer/x/KeyboardMapping.java new file mode 100644 index 000000000..8e0a31f5d --- /dev/null +++ b/gnu/java/awt/peer/x/KeyboardMapping.java @@ -0,0 +1,415 @@ +/* KeyboardMapping.java -- Maps X keysyms to Java keyCode and keyChar + 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.x; + +import gnu.x11.Input; +import gnu.x11.keysym.Latin1; +import gnu.x11.keysym.Misc; + +import java.awt.event.KeyEvent; + +/** + * Defines the keyboard mapping from X keysyms to Java + * keycodes and keychars. + * + * @author Roman Kennke (kennke@aicas.com) + */ +final class KeyboardMapping +{ + + /** + * Maps X keycodes to AWT keycodes. + * + * @param xInput the X input event + * @param xKeyCode the X keycode to map + * @param xMods the X modifiers + * + * @return the AWT keycode and keychar + */ + static int mapToKeyCode(gnu.x11.Input xInput, int xKeyCode, int xMods) + { + int mapped = KeyEvent.VK_UNDEFINED; + int keysym = xInput.keycode_to_keysym(xKeyCode, xMods, true); + + // Special keys. + if (keysym >= 255 << 8) + { + // FIXME: Add missing mappings. + switch (keysym) + { + case Misc.BACKSPACE: + mapped = KeyEvent.VK_BACK_SPACE; + break; + case Misc.TAB: + mapped = KeyEvent.VK_TAB; + break; + case Misc.CLEAR: + mapped = KeyEvent.VK_CLEAR; + break; + case Misc.RETURN: + mapped = KeyEvent.VK_ENTER; + break; + case Misc.PAUSE: + mapped = KeyEvent.VK_PAUSE; + break; + case Misc.SCROLL_LOCK: + mapped = KeyEvent.VK_SCROLL_LOCK; + break; + case Misc.ESCAPE: + mapped = KeyEvent.VK_ESCAPE; + break; + case Misc.HOME: + mapped = KeyEvent.VK_HOME; + break; + case Misc.LEFT: + mapped = KeyEvent.VK_LEFT; + break; + case Misc.UP: + mapped = KeyEvent.VK_UP; + break; + case Misc.RIGHT: + mapped = KeyEvent.VK_RIGHT; + break; + case Misc.DOWN: + mapped = KeyEvent.VK_DOWN; + break; + case Misc.PAGE_UP: + mapped = KeyEvent.VK_PAGE_UP; + break; + case Misc.PAGE_DOWN: + mapped = KeyEvent.VK_PAGE_DOWN; + break; + case Misc.END: + mapped = KeyEvent.VK_END; + break; + case Misc.BEGIN: + mapped = KeyEvent.VK_BEGIN; + break; + case Misc.INSERT: + mapped = KeyEvent.VK_INSERT; + break; + case Misc.UNDO: + mapped = KeyEvent.VK_UNDO; + break; + case Misc.FIND: + mapped = KeyEvent.VK_FIND; + break; + case Misc.CANCEL: + mapped = KeyEvent.VK_CANCEL; + break; + case Misc.HELP: + mapped = KeyEvent.VK_HELP; + break; + case Misc.MODE_SWITCH: + mapped = KeyEvent.VK_MODECHANGE; + break; + case Misc.NUM_LOCK: + mapped = KeyEvent.VK_NUM_LOCK; + break; + case Misc.KP_LEFT: + mapped = KeyEvent.VK_KP_LEFT; + break; + case Misc.KP_UP: + mapped = KeyEvent.VK_KP_UP; + break; + case Misc.KP_RIGHT: + mapped = KeyEvent.VK_KP_RIGHT; + break; + case Misc.KP_DOWN: + mapped = KeyEvent.VK_KP_DOWN; + break; + case Misc.F1: + mapped = KeyEvent.VK_F1; + break; + case Misc.F2: + mapped = KeyEvent.VK_F2; + break; + case Misc.F3: + mapped = KeyEvent.VK_F3; + break; + case Misc.F4: + mapped = KeyEvent.VK_F4; + break; + case Misc.F5: + mapped = KeyEvent.VK_F5; + break; + case Misc.F6: + mapped = KeyEvent.VK_F6; + break; + case Misc.F7: + mapped = KeyEvent.VK_F7; + break; + case Misc.F8: + mapped = KeyEvent.VK_F8; + break; + case Misc.F9: + mapped = KeyEvent.VK_F9; + break; + case Misc.F10: + mapped = KeyEvent.VK_F10; + break; + case Misc.F11: + mapped = KeyEvent.VK_F11; + break; + case Misc.F12: + mapped = KeyEvent.VK_F12; + break; + case Misc.F13: + mapped = KeyEvent.VK_F13; + break; + case Misc.F14: + mapped = KeyEvent.VK_F14; + break; + case Misc.F15: + mapped = KeyEvent.VK_F15; + break; + case Misc.F16: + mapped = KeyEvent.VK_F16; + break; + case Misc.F17: + mapped = KeyEvent.VK_F17; + break; + case Misc.F18: + mapped = KeyEvent.VK_F18; + break; + case Misc.F19: + mapped = KeyEvent.VK_F19; + break; + case Misc.F20: + mapped = KeyEvent.VK_F20; + break; + case Misc.F21: + mapped = KeyEvent.VK_F21; + break; + case Misc.F22: + mapped = KeyEvent.VK_F22; + break; + case Misc.F23: + mapped = KeyEvent.VK_F23; + break; + case Misc.F24: + mapped = KeyEvent.VK_F24; + break; + case Misc.SHIFT_L: + case Misc.SHIFT_R: + mapped = KeyEvent.VK_SHIFT; + break; + case Misc.CONTROL_L: + case Misc.CONTROL_R: + mapped = KeyEvent.VK_CONTROL; + break; + case Misc.CAPS_LOCK: + case Misc.SHIFT_LOCK: + mapped = KeyEvent.VK_CAPS_LOCK; + break; + case Misc.META_L: + case Misc.META_R: + mapped = KeyEvent.VK_META; + break; + case Misc.ALT_L: + case Misc.ALT_R: + mapped = KeyEvent.VK_ALT; + break; + case Misc.DELETE: + mapped = KeyEvent.VK_DELETE; + break; + default: + mapped = KeyEvent.VK_UNDEFINED; + } + } + // Map Latin1 characters. + else if (keysym < 256) + { + // TODO: Add missing mappings, if any. + // Lowercase characters are mapped to + // their corresponding upper case pendants. + if (keysym >= Latin1.A_SMALL && keysym <= Latin1.Z_SMALL) + mapped = keysym - 0x20; + // Uppercase characters are mapped 1:1. + else if (keysym >= Latin1.A && keysym <= Latin1.Z) + mapped = keysym; + // Digits are mapped 1:1. + else if (keysym >= Latin1.NUM_0 && keysym <= Latin1.NUM_9) + mapped = keysym; + else + { + switch (keysym) + { + case Latin1.SPACE: + mapped = KeyEvent.VK_SPACE; + break; + case Latin1.EXCLAM: + mapped = KeyEvent.VK_EXCLAMATION_MARK; + break; + case Latin1.QUOTE_DBL: + mapped = KeyEvent.VK_QUOTEDBL; + break; + case Latin1.NUMBER_SIGN: + mapped = KeyEvent.VK_NUMBER_SIGN; + break; + case Latin1.DOLLAR: + mapped = KeyEvent.VK_DOLLAR; + break; + case Latin1.AMPERSAND: + mapped = KeyEvent.VK_AMPERSAND; + break; + case Latin1.APOSTROPHE: + mapped = KeyEvent.VK_QUOTE; + break; + case Latin1.PAREN_LEFT: + mapped = KeyEvent.VK_LEFT_PARENTHESIS; + break; + case Latin1.PAREN_RIGHT: + mapped = KeyEvent.VK_RIGHT_PARENTHESIS; + break; + case Latin1.ASTERISK: + mapped = KeyEvent.VK_ASTERISK; + break; + case Latin1.PLUS: + mapped = KeyEvent.VK_PLUS; + break; + case Latin1.COMMA: + mapped = KeyEvent.VK_COMMA; + break; + case Latin1.MINUS: + mapped = KeyEvent.VK_MINUS; + break; + case Latin1.PERIOD: + mapped = KeyEvent.VK_PERIOD; + break; + case Latin1.SLASH: + mapped = KeyEvent.VK_SLASH; + break; + case Latin1.COLON: + mapped = KeyEvent.VK_COLON; + break; + case Latin1.SEMICOLON: + mapped = KeyEvent.VK_SEMICOLON; + break; + case Latin1.LESS: + mapped = KeyEvent.VK_LESS; + break; + case Latin1.EQUAL: + mapped = KeyEvent.VK_EQUALS; + break; + case Latin1.GREATER: + mapped = KeyEvent.VK_GREATER; + break; + case Latin1.AT: + mapped = KeyEvent.VK_AT; + break; + case Latin1.BRACKET_LEFT: + mapped = KeyEvent.VK_OPEN_BRACKET; + break; + case Latin1.BACKSLASH: + mapped = KeyEvent.VK_BACK_SLASH; + break; + case Latin1.BRACKET_RIGHT: + mapped = KeyEvent.VK_CLOSE_BRACKET; + break; + case Latin1.ASCII_CIRCUM: + mapped = KeyEvent.VK_CIRCUMFLEX; + break; + case Latin1.UNDERSCORE: + mapped = KeyEvent.VK_UNDERSCORE; + break; + case Latin1.GRAVE: + mapped = KeyEvent.VK_DEAD_GRAVE; + break; + case Latin1.BRACE_LEFT: + mapped = KeyEvent.VK_BRACELEFT; + break; + case Latin1.BRACE_RIGHT: + mapped = KeyEvent.VK_BRACERIGHT; + break; + case Latin1.ASCII_TILDE: + mapped = KeyEvent.VK_DEAD_TILDE; + break; + case Latin1.EXCLAM_DOWN: + mapped = KeyEvent.VK_INVERTED_EXCLAMATION_MARK; + break; + default: + mapped = KeyEvent.VK_UNDEFINED; + } + } + } + return mapped; + } + + /** + * Maps X keycodes+modifiers to Java keychars. + * + * @param xInput The X Input to use for mapping + * @param xKeyCode the X keycode + * @param xMods the X key modifiers + * + * @return the Java keychar + */ + static char mapToKeyChar(gnu.x11.Input xInput, int xKeyCode, int xMods) + { + char mapped = KeyEvent.CHAR_UNDEFINED; + char keysym = (char) xInput.keycode_to_keysym(xKeyCode, xMods, false); + // FIXME: Map other encodings properly. + if (keysym < 256) // Latin1. + { + mapped = keysym; + } + return mapped; + } + + /** + * Maps X modifier masks to AWT modifier masks. + * + * @param xMods the X modifiers + * + * @return the AWT modifiers + */ + static int mapModifiers(int xMods) + { + int mods = 0; + + if ((xMods & Input.SHIFT_MASK) != 0) + mods |= KeyEvent.SHIFT_MASK | KeyEvent.SHIFT_DOWN_MASK; + if ((xMods & Input.ALT_MASK) != 0) + mods |= KeyEvent.ALT_MASK | KeyEvent.ALT_DOWN_MASK; + if ((xMods & Input.CONTROL_MASK) != 0) + mods |= KeyEvent.CTRL_MASK | KeyEvent.CTRL_DOWN_MASK; + + return mods; + } +} diff --git a/gnu/java/awt/peer/x/XEventPump.java b/gnu/java/awt/peer/x/XEventPump.java new file mode 100644 index 000000000..bd1ef08ce --- /dev/null +++ b/gnu/java/awt/peer/x/XEventPump.java @@ -0,0 +1,287 @@ +/* XEventPump.java -- Pumps events from X to AWT + 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.x; + +import java.awt.Graphics; +import java.awt.Rectangle; +import java.awt.Toolkit; +import java.awt.Window; +import java.awt.event.ComponentEvent; +import java.awt.event.KeyEvent; +import java.awt.event.MouseEvent; +import java.awt.event.PaintEvent; +import java.util.HashMap; + +import gnu.x11.Display; +import gnu.x11.event.ButtonPress; +import gnu.x11.event.ButtonRelease; +import gnu.x11.event.ConfigureNotify; +import gnu.x11.event.Event; +import gnu.x11.event.Expose; +import gnu.x11.event.Input; +import gnu.x11.event.KeyPress; +import gnu.x11.event.KeyRelease; +import gnu.x11.event.MotionNotify; + +/** + * Fetches events from X, translates them to AWT events and pumps them up + * into the AWT event queue. + * + * @author Roman Kennke (kennke@aicas.com) + */ +public class XEventPump + implements Runnable +{ + + /** + * The X Display from which we fetch and pump up events. + */ + private Display display; + + /** + * Maps X Windows to AWT Windows to be able to correctly determine the + * event targets. + */ + private HashMap windows; + + /** + * Indicates if we are currently inside a drag operation. This is + * set to the button ID when a button is pressed and to -1 (indicating + * that no drag is active) when the mouse is released. + */ + private int drag; + + /** + * Creates a new XEventPump for the specified X Display. + * + * @param d the X Display + */ + XEventPump(Display d) + { + display = d; + windows = new HashMap(); + drag = -1; + Thread t = new Thread(this); + t.start(); + } + + /** + * The main event pump loop. This basically fetches events from the + * X Display and pumps them into the system event queue. + */ + public void run() + { + while (display.connected) + { + try + { + Event xEvent = display.next_event(); + handleEvent(xEvent); + } + catch (ThreadDeath death) + { + // If someone wants to kill us, let them. + return; + } + catch (Throwable x) + { + System.err.println("Exception during event dispatch:"); + x.printStackTrace(System.err); + } + } + } + + /** + * Adds an X Window to AWT Window mapping. This is required so that the + * event pump can correctly determine the event targets. + * + * @param xWindow the X Window + * @param awtWindow the AWT Window + */ + void registerWindow(gnu.x11.Window xWindow, Window awtWindow) + { + if (XToolkit.DEBUG) + System.err.println("registering window id: " + xWindow.id); + windows.put(new Integer(xWindow.id), awtWindow); + } + + void unregisterWindow(gnu.x11.Window xWindow) + { + windows.remove(new Integer(xWindow.id)); + } + + private void handleEvent(Event xEvent) + { + Integer key = new Integer(xEvent.window_id());; + Window awtWindow = (Window) windows.get(key); + + if (XToolkit.DEBUG) + System.err.println("fetched event: " + xEvent); + switch (xEvent.code()) + { + case ButtonPress.CODE: + ButtonPress bp = (ButtonPress) xEvent; + // Create and post the mouse event. + int button = bp.detail(); + drag = button; + MouseEvent mp = new MouseEvent(awtWindow, MouseEvent.MOUSE_PRESSED, + System.currentTimeMillis(), 0, + bp.event_x(), bp.event_y(), + 1, false, button); + Toolkit.getDefaultToolkit().getSystemEventQueue().postEvent(mp); + break; + case ButtonRelease.CODE: + ButtonRelease br = (ButtonRelease) xEvent; + drag = -1; + MouseEvent mr = new MouseEvent(awtWindow, MouseEvent.MOUSE_RELEASED, + System.currentTimeMillis(), 0, + br.event_x(), br.event_y(), + 1, false, br.detail()); + Toolkit.getDefaultToolkit().getSystemEventQueue().postEvent(mr); + break; + case MotionNotify.CODE: + MotionNotify mn = (MotionNotify) xEvent; + MouseEvent mm; + if (drag == -1) + { + mm = new MouseEvent(awtWindow, MouseEvent.MOUSE_MOVED, + System.currentTimeMillis(), 0, + mn.event_x(), mn.event_y(), + 1, false); + } + else + { + mm = new MouseEvent(awtWindow, MouseEvent.MOUSE_DRAGGED, + System.currentTimeMillis(), 0, + mn.event_x(), mn.event_y(), + 1, false); + } + Toolkit.getDefaultToolkit().getSystemEventQueue().postEvent(mm); + break; + case ConfigureNotify.CODE: + ConfigureNotify c = (ConfigureNotify) xEvent; + if (XToolkit.DEBUG) + System.err.println("resize request for window id: " + key); + + // Detect and report size changes. + if (c.width() != awtWindow.getWidth() + || c.height() != awtWindow.getHeight()) + { + if (XToolkit.DEBUG) + System.err.println("Setting size on AWT window: " + c.width() + + ", " + c.height() + ", " + awtWindow.getWidth() + + ", " + awtWindow.getHeight()); + ((XFramePeer) awtWindow.getPeer()).callback = true; + awtWindow.setSize(c.width(), c.height()); + ((XFramePeer) awtWindow.getPeer()).callback = false; + } + break; + case Expose.CODE: + Expose exp = (Expose) xEvent; + if (XToolkit.DEBUG) + System.err.println("expose request for window id: " + key); + Rectangle r = new Rectangle(exp.x(), exp.y(), exp.width(), + exp.height()); + //System.err.println("expose paint: " + r); + // We need to clear the background of the exposed rectangle. + Graphics g = awtWindow.getGraphics(); + g.clearRect(r.x, r.y, r.width, r.height); + g.dispose(); + PaintEvent pev = new PaintEvent(awtWindow, PaintEvent.PAINT, r); + Toolkit.getDefaultToolkit().getSystemEventQueue().postEvent(pev); + break; + case KeyPress.CODE: + case KeyRelease.CODE: + handleKeyEvent(xEvent, awtWindow); + break; + default: + if (XToolkit.DEBUG) + System.err.println("Unhandled X event: " + xEvent); + } + } + + /** + * Handles key events from X. + * + * @param xEvent the X event + * @param awtWindow the AWT window to which the event gets posted + */ + private void handleKeyEvent(Event xEvent, Window awtWindow) + { + Input keyEvent = (Input) xEvent; + int xKeyCode = keyEvent.detail(); + int xMods = keyEvent.state(); + int keyCode = KeyboardMapping.mapToKeyCode(xEvent.display.input, xKeyCode, + xMods); + char keyChar = KeyboardMapping.mapToKeyChar(xEvent.display.input, xKeyCode, + xMods); + if (XToolkit.DEBUG) + System.err.println("XEventPump.handleKeyEvent: " + xKeyCode + ", " + + xMods + ": " + ((int) keyChar) + ", " + keyCode); + int awtMods = KeyboardMapping.mapModifiers(xMods); + long when = System.currentTimeMillis(); + KeyEvent ke; + if (keyEvent.code() == KeyPress.CODE) + { + ke = new KeyEvent(awtWindow, KeyEvent.KEY_PRESSED, when, + awtMods, keyCode, + KeyEvent.CHAR_UNDEFINED); + Toolkit.getDefaultToolkit().getSystemEventQueue().postEvent(ke); + if (keyChar != KeyEvent.CHAR_UNDEFINED) + { + ke = new KeyEvent(awtWindow, KeyEvent.KEY_TYPED, when, + awtMods, KeyEvent.VK_UNDEFINED, + keyChar); + Toolkit.getDefaultToolkit().getSystemEventQueue().postEvent(ke); + } + + } + else + { + ke = new KeyEvent(awtWindow, KeyEvent.KEY_RELEASED, when, + awtMods, keyCode, + KeyEvent.CHAR_UNDEFINED); + Toolkit.getDefaultToolkit().getSystemEventQueue().postEvent(ke); + } + + } + + +} + diff --git a/gnu/java/awt/peer/x/XFontPeer.java b/gnu/java/awt/peer/x/XFontPeer.java new file mode 100644 index 000000000..8a499db1a --- /dev/null +++ b/gnu/java/awt/peer/x/XFontPeer.java @@ -0,0 +1,740 @@ +/* XFontPeer.java -- The font peer for X + 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.x; + +import java.awt.AWTError; +import java.awt.Font; +import java.awt.FontMetrics; +import java.awt.GraphicsDevice; +import java.awt.GraphicsEnvironment; +import java.awt.font.FontRenderContext; +import java.awt.font.GlyphVector; +import java.awt.font.LineMetrics; +import java.awt.font.TextAttribute; +import java.awt.geom.Rectangle2D; +import java.io.IOException; +import java.io.InputStream; +import java.text.CharacterIterator; +import java.util.HashMap; +import java.util.Iterator; +import java.util.Locale; +import java.util.Map; +import java.util.Properties; + +import gnu.java.awt.peer.ClasspathFontPeer; +import gnu.x11.Display; +import gnu.x11.Fontable; + +/** + * The bridge from AWT to X fonts. + * + * @author Roman Kennke (kennke@aicas.com) + */ +public class XFontPeer + extends ClasspathFontPeer +{ + + /** + * The font mapping as specified in the file fonts.properties. + */ + private static Properties fontProperties; + static + { + fontProperties = new Properties(); + InputStream in = XFontPeer.class.getResourceAsStream("fonts.properties"); + try + { + fontProperties.load(in); + } + catch (IOException e) + { + e.printStackTrace(); + } + } + + /** + * The FontMetrics implementation for XFontPeer. + */ + private class XFontMetrics + extends FontMetrics + { + /** + * The ascent of the font. + */ + int ascent; + + /** + * The descent of the font. + */ + int descent; + + /** + * The maximum of the character advances. + */ + private int maxAdvance; + + /** + * The internal leading. + */ + int leading; + + /** + * Cached string metrics. This caches string metrics locally so that the + * server doesn't have to be asked each time. + */ + private HashMap metricsCache; + + /** + * The widths of the characters indexed by the characters themselves. + */ + private int[] charWidths; + + /** + * Creates a new XFontMetrics for the specified font. + * + * @param font the font + */ + protected XFontMetrics(Font font) + { + super(font); + metricsCache = new HashMap(); + Fontable.FontReply info = getXFont().info(); + ascent = info.font_ascent(); + descent = info.font_descent(); + maxAdvance = info.max_bounds().character_width(); + leading = 0; // TODO: Not provided by X. Possible not needed. + + if (info.min_byte1() == 0 && info.max_byte1() == 0) + readCharWidthsLinear(info); + else + readCharWidthsNonLinear(info); + } + + /** + * Reads the character widths when specified in a linear fashion. That is + * when the min-byte1 and max-byte2 fields are both zero in the X protocol. + * + * @param info the font info reply + */ + private void readCharWidthsLinear(Fontable.FontReply info) + { + int startIndex = info.min_char_or_byte2(); + int endIndex = info.max_char_or_byte2(); + charWidths = new int[endIndex + 1]; + // All the characters before startIndex are zero width. + for (int i = 0; i < startIndex; i++) + { + charWidths[i] = 0; + } + // All the other character info is fetched from the font info. + int index = startIndex; + Iterator charInfos = info.char_infos().iterator(); + while (charInfos.hasNext()) + { + Fontable.FontReply.CharInfo charInfo = + (Fontable.FontReply.CharInfo) charInfos.next(); + charWidths[index] = charInfo.character_width(); + index++; + } + } + + private void readCharWidthsNonLinear(Fontable.FontReply info) + { + // TODO: Implement. + throw new UnsupportedOperationException("Not yet implemented"); + } + + /** + * Returns the ascent of the font. + * + * @return the ascent of the font + */ + public int getAscent() + { + return ascent; + } + + /** + * Returns the descent of the font. + * + * @return the descent of the font + */ + public int getDescent() + { + return descent; + } + + /** + * Returns the overall height of the font. This is the distance from + * baseline to baseline (usually ascent + descent + leading). + * + * @return the overall height of the font + */ + public int getHeight() + { + return ascent + descent; + } + + /** + * Returns the leading of the font. + * + * @return the leading of the font + */ + public int getLeading() + { + return leading; + } + + /** + * Returns the maximum advance for this font. + * + * @return the maximum advance for this font + */ + public int getMaxAdvance() + { + return maxAdvance; + } + + /** + * Determines the width of the specified character <code>c</code>. + * + * @param c the character + * + * @return the width of the character + */ + public int charWidth(char c) + { + int width; + if (c > charWidths.length) + width = charWidths['?']; + else + width = charWidths[c]; + return width; + } + + /** + * Determines the overall width of the specified string. + * + * @param c the char buffer holding the string + * @param offset the starting offset of the string in the buffer + * @param length the number of characters in the string buffer + * + * @return the overall width of the specified string + */ + public int charsWidth(char[] c, int offset, int length) + { + int width = 0; + if (c.length > 0 && length > 0) + { + String s = new String(c, offset, length); + width = stringWidth(s); + } + return width; + } + + /** + * Determines the overall width of the specified string. + * + * @param s the string + * + * @return the overall width of the specified string + */ + public int stringWidth(String s) + { + int width = 0; + if (s.length() > 0) + { + if (metricsCache.containsKey(s)) + { + width = ((Integer) metricsCache.get(s)).intValue(); + } + else + { + Fontable.TextExtentReply extents = getXFont().text_extent(s); + /* + System.err.println("string: '" + s + "' : "); + System.err.println("ascent: " + extents.getAscent()); + System.err.println("descent: " + extents.getDescent()); + System.err.println("overall ascent: " + extents.getOverallAscent()); + System.err.println("overall descent: " + extents.getOverallDescent()); + System.err.println("overall width: " + extents.getOverallWidth()); + System.err.println("overall left: " + extents.getOverallLeft()); + System.err.println("overall right: " + extents.getOverallRight()); + */ + width = extents.overall_width(); // + extents.overall_left(); + //System.err.println("String: " + s + ", width: " + width); + metricsCache.put(s, new Integer(width)); + } + } + //System.err.print("stringWidth: '" + s + "': "); + //System.err.println(width); + return width; + } + } + + /** + * The LineMetrics implementation for the XFontPeer. + */ + private class XLineMetrics + extends LineMetrics + { + + /** + * Returns the ascent of the font. + * + * @return the ascent of the font + */ + public float getAscent() + { + return fontMetrics.ascent; + } + + public int getBaselineIndex() + { + // FIXME: Implement this. + throw new UnsupportedOperationException(); + } + + public float[] getBaselineOffsets() + { + // FIXME: Implement this. + throw new UnsupportedOperationException(); + } + + /** + * Returns the descent of the font. + * + * @return the descent of the font + */ + public float getDescent() + { + return fontMetrics.descent; + } + + /** + * Returns the overall height of the font. This is the distance from + * baseline to baseline (usually ascent + descent + leading). + * + * @return the overall height of the font + */ + public float getHeight() + { + return fontMetrics.ascent + fontMetrics.descent; + } + + /** + * Returns the leading of the font. + * + * @return the leading of the font + */ + public float getLeading() + { + return fontMetrics.leading; + } + + public int getNumChars() + { + // FIXME: Implement this. + throw new UnsupportedOperationException(); + } + + public float getStrikethroughOffset() + { + return 0.F; // TODO: Provided by X?? + } + + public float getStrikethroughThickness() + { + return 1.F; // TODO: Provided by X?? + } + + public float getUnderlineOffset() + { + return 0.F; // TODO: Provided by X?? + } + + public float getUnderlineThickness() + { + return 1.F; // TODO: Provided by X?? + } + + } + + /** + * The X font. + */ + private gnu.x11.Font xfont; + + private String name; + + private int style; + + private int size; + + /** + * The font metrics for this font. + */ + XFontMetrics fontMetrics; + + /** + * Creates a new XFontPeer for the specified font name, style and size. + * + * @param name the font name + * @param style the font style (bold / italic / normal) + * @param size the size of the font + */ + public XFontPeer(String name, int style, int size) + { + super(name, style, size); + this.name = name; + this.style = style; + this.size = size; + } + + /** + * Creates a new XFontPeer for the specified font name and style + * attributes. + * + * @param name the font name + * @param atts the font attributes + */ + public XFontPeer(String name, Map atts) + { + super(name, atts); + String family = name; + if (family == null || family.equals("")) + family = (String) atts.get(TextAttribute.FAMILY); + if (family == null) + family = "SansSerif"; + + int size = 12; + Float sizeFl = (Float) atts.get(TextAttribute.SIZE); + if (sizeFl != null) + size = sizeFl.intValue(); + + int style = 0; + // Detect italic attribute. + Float posture = (Float) atts.get(TextAttribute.POSTURE); + if (posture != null && !posture.equals(TextAttribute.POSTURE_REGULAR)) + style |= Font.ITALIC; + + // Detect bold attribute. + Float weight = (Float) atts.get(TextAttribute.WEIGHT); + if (weight != null && weight.compareTo(TextAttribute.WEIGHT_REGULAR) > 0) + style |= Font.BOLD; + + this.name = name; + this.style = style; + this.size = size; + } + + /** + * Initializes the font peer with the specified attributes. This method is + * called from both constructors. + * + * @param name the font name + * @param style the font style + * @param size the font size + */ + private void init(String name, int style, int size) + { + GraphicsEnvironment env = GraphicsEnvironment.getLocalGraphicsEnvironment(); + GraphicsDevice dev = env.getDefaultScreenDevice(); + if (dev instanceof XGraphicsDevice) + { + Display display = ((XGraphicsDevice) dev).getDisplay(); + String fontDescr = encodeFont(name, style, size); + if (XToolkit.DEBUG) + System.err.println("XLFD font description: " + fontDescr); + xfont = new gnu.x11.Font(display, fontDescr); + } + else + { + throw new AWTError("Local GraphicsEnvironment is not XWindowGraphicsEnvironment"); + } + } + + public boolean canDisplay(Font font, char c) + { + // TODO: Implement this. + throw new UnsupportedOperationException("Not yet implemented."); + } + + public int canDisplayUpTo(Font font, CharacterIterator i, int start, int limit) + { + // TODO: Implement this. + throw new UnsupportedOperationException("Not yet implemented."); + } + + public String getSubFamilyName(Font font, Locale locale) + { + // TODO: Implement this. + throw new UnsupportedOperationException("Not yet implemented."); + } + + public String getPostScriptName(Font font) + { + // TODO: Implement this. + throw new UnsupportedOperationException("Not yet implemented."); + } + + public int getNumGlyphs(Font font) + { + // TODO: Implement this. + throw new UnsupportedOperationException("Not yet implemented."); + } + + public int getMissingGlyphCode(Font font) + { + // TODO: Implement this. + throw new UnsupportedOperationException("Not yet implemented."); + } + + public byte getBaselineFor(Font font, char c) + { + // TODO: Implement this. + throw new UnsupportedOperationException("Not yet implemented."); + } + + public String getGlyphName(Font font, int glyphIndex) + { + // TODO: Implement this. + throw new UnsupportedOperationException("Not yet implemented."); + } + + public GlyphVector createGlyphVector(Font font, FontRenderContext frc, + CharacterIterator ci) + { + // TODO: Implement this. + throw new UnsupportedOperationException("Not yet implemented."); + } + + public GlyphVector createGlyphVector(Font font, FontRenderContext ctx, + int[] glyphCodes) + { + // TODO: Implement this. + throw new UnsupportedOperationException("Not yet implemented."); + } + + public GlyphVector layoutGlyphVector(Font font, FontRenderContext frc, + char[] chars, int start, int limit, + int flags) + { + // TODO: Implement this. + throw new UnsupportedOperationException("Not yet implemented."); + } + + /** + * Returns the font metrics for the specified font. + * + * @param font the font for which to fetch the font metrics + * + * @return the font metrics for the specified font + */ + public FontMetrics getFontMetrics(Font font) + { + if (font.getPeer() != this) + throw new AWTError("The specified font has a different peer than this"); + + if (fontMetrics == null) + fontMetrics = new XFontMetrics(font); + return fontMetrics; + } + + /** + * Frees the font in the X server. + */ + protected void finalize() + { + if (xfont != null) + xfont.close(); + } + + public boolean hasUniformLineMetrics(Font font) + { + // TODO: Implement this. + throw new UnsupportedOperationException("Not yet implemented."); + } + + /** + * Returns the line metrics for this font and the specified string and + * font render context. + */ + public LineMetrics getLineMetrics(Font font, CharacterIterator ci, int begin, + int limit, FontRenderContext rc) + { + return new XLineMetrics(); + } + + public Rectangle2D getMaxCharBounds(Font font, FontRenderContext rc) + { + // TODO: Implement this. + throw new UnsupportedOperationException("Not yet implemented."); + } + + public Rectangle2D getStringBounds(Font font, CharacterIterator ci, + int begin, int limit, FontRenderContext frc) + { + // TODO: Implement this. + throw new UnsupportedOperationException("Not yet implemented."); + } + + /** + * Encodes a font name + style + size specification into a X logical font + * description (XLFD) as described here: + * + * http://www.meretrx.com/e93/docs/xlfd.html + * + * This is implemented to look up the font description in the + * fonts.properties of this package. + * + * @param name the font name + * @param atts the text attributes + * + * @return the encoded font description + */ + static String encodeFont(String name, Map atts) + { + String family = name; + if (family == null || family.equals("")) + family = (String) atts.get(TextAttribute.FAMILY); + if (family == null) + family = "SansSerif"; + + int size = 12; + Float sizeFl = (Float) atts.get(TextAttribute.SIZE); + if (sizeFl != null) + size = sizeFl.intValue(); + + int style = 0; + // Detect italic attribute. + Float posture = (Float) atts.get(TextAttribute.POSTURE); + if (posture != null && !posture.equals(TextAttribute.POSTURE_REGULAR)) + style |= Font.ITALIC; + + // Detect bold attribute. + Float weight = (Float) atts.get(TextAttribute.WEIGHT); + if (weight != null && weight.compareTo(TextAttribute.WEIGHT_REGULAR) > 0) + style |= Font.BOLD; + + return encodeFont(name, style, size); + } + + /** + * Encodes a font name + style + size specification into a X logical font + * description (XLFD) as described here: + * + * http://www.meretrx.com/e93/docs/xlfd.html + * + * This is implemented to look up the font description in the + * fonts.properties of this package. + * + * @param name the font name + * @param style the font style + * @param size the font size + * + * @return the encoded font description + */ + static String encodeFont(String name, int style, int size) + { + StringBuilder key = new StringBuilder(); + key.append(validName(name)); + key.append('.'); + switch (style) + { + case Font.BOLD: + key.append("bold"); + break; + case Font.ITALIC: + key.append("italic"); + break; + case (Font.BOLD | Font.ITALIC): + key.append("bolditalic"); + break; + case Font.PLAIN: + default: + key.append("plain"); + + } + + String protoType = fontProperties.getProperty(key.toString()); + return protoType.replaceFirst("%d", String.valueOf(size)); + } + + /** + * Checks the specified font name for a valid font name. If the font name + * is not known, then this returns 'sansserif' as fallback. + * + * @param name the font name to check + * + * @return a valid font name + */ + static String validName(String name) + { + String retVal; + if (name.equalsIgnoreCase("sansserif") + || name.equalsIgnoreCase("serif") + || name.equalsIgnoreCase("monospaced") + || name.equalsIgnoreCase("dialog") + || name.equalsIgnoreCase("dialoginput")) + { + retVal = name.toLowerCase(); + } + else + { + retVal = "sansserif"; + } + return retVal; + } + + /** + * Returns the X Font reference. This lazily loads the font when first + * requested. + * + * @return the X Font reference + */ + gnu.x11.Font getXFont() + { + if (xfont == null) + { + init(name, style, size); + } + return xfont; + } +} diff --git a/gnu/java/awt/peer/x/XFontPeer2.java b/gnu/java/awt/peer/x/XFontPeer2.java new file mode 100644 index 000000000..25371de1a --- /dev/null +++ b/gnu/java/awt/peer/x/XFontPeer2.java @@ -0,0 +1,335 @@ +/* XFontPeer2.java -- A Java based TTF font peer for X + 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.x; + +import java.awt.Font; +import java.awt.FontMetrics; +import java.awt.font.FontRenderContext; +import java.awt.font.GlyphVector; +import java.awt.font.LineMetrics; +import java.awt.geom.AffineTransform; +import java.awt.geom.Point2D; +import java.awt.geom.Rectangle2D; +import java.io.File; +import java.io.FileInputStream; +import java.nio.ByteBuffer; +import java.nio.channels.FileChannel; +import java.text.CharacterIterator; +import java.text.StringCharacterIterator; +import java.util.Locale; +import java.util.Map; + +import gnu.java.awt.font.FontDelegate; +import gnu.java.awt.font.FontFactory; +import gnu.java.awt.peer.ClasspathFontPeer; + +public class XFontPeer2 + extends ClasspathFontPeer +{ + + private class XLineMetrics + extends LineMetrics + { + + private Font font; +// private CharacterIterator characterIterator; +// private int begin; +// private int limit; + private FontRenderContext fontRenderContext; + XLineMetrics(Font f, CharacterIterator ci, int b, int l, + FontRenderContext rc) + { + font = f; +// characterIterator = ci; +// begin = b; +// limit = l; + fontRenderContext = rc; + } + + public float getAscent() + { + return fontDelegate.getAscent(font.getSize(), fontRenderContext.getTransform(), + fontRenderContext.isAntiAliased(), + fontRenderContext.usesFractionalMetrics(), true); + } + + public int getBaselineIndex() + { + // FIXME: Implement this. + throw new UnsupportedOperationException("Not yet implemented"); + } + + public float[] getBaselineOffsets() + { + // FIXME: Implement this. + throw new UnsupportedOperationException("Not yet implemented"); + } + + public float getDescent() + { + return (int) fontDelegate.getDescent(font.getSize(), + new AffineTransform(), false, false, + false); + } + + public float getHeight() + { + // FIXME: Implement this. + throw new UnsupportedOperationException("Not yet implemented"); + } + + public float getLeading() + { + // FIXME: Implement this. + throw new UnsupportedOperationException("Not yet implemented"); + } + + public int getNumChars() + { + // FIXME: Implement this. + throw new UnsupportedOperationException("Not yet implemented"); + } + + public float getStrikethroughOffset() + { + return 0.F; + } + + public float getStrikethroughThickness() + { + return 0.F; + } + + public float getUnderlineOffset() + { + return 0.F; + } + + public float getUnderlineThickness() + { + return 0.F; + } + + } + + private class XFontMetrics + extends FontMetrics + { + XFontMetrics(Font f) + { + super(f); + } + + public int getAscent() + { + return (int) fontDelegate.getAscent(getFont().getSize(), + new AffineTransform(), false, false, + false); + } + + public int getDescent() + { + return (int) fontDelegate.getDescent(getFont().getSize(), + new AffineTransform(), false, false, + false); + } + + public int getHeight() + { + GlyphVector gv = fontDelegate.createGlyphVector(getFont(), + new FontRenderContext(new AffineTransform(), false, false), + new StringCharacterIterator("m")); + Rectangle2D b = gv.getVisualBounds(); + return (int) b.getHeight(); + } + + public int charWidth(char c) + { + Point2D advance = new Point2D.Double(); + fontDelegate.getAdvance(c, getFont().getSize(), new AffineTransform(), + false, false, true, advance); + return (int) advance.getX(); + } + + public int charsWidth(char[] chars, int offs, int len) + { + return stringWidth(new String(chars, offs, len)); + } + + public int stringWidth(String s) + { + GlyphVector gv = fontDelegate.createGlyphVector(getFont(), + new FontRenderContext(new AffineTransform(), false, false), + new StringCharacterIterator(s)); + Rectangle2D b = gv.getVisualBounds(); + return (int) b.getWidth(); + } + } + + private FontDelegate fontDelegate; + + XFontPeer2(String name, int style, int size) + { + super(name, style, size); + try + { + File fontfile = new File("/usr/share/fonts/truetype/ttf-bitstream-vera/Vera.ttf"); + FileInputStream in = new FileInputStream(fontfile); + FileChannel ch = in.getChannel(); + ByteBuffer buffer = ch.map(FileChannel.MapMode.READ_ONLY, 0, + fontfile.length()); + fontDelegate = FontFactory.createFonts(buffer)[0]; + } + catch (Exception ex) + { + ex.printStackTrace(); + } + } + + XFontPeer2(String name, Map atts) + { + super(name, atts); + try + { + File fontfile = new File("/usr/share/fonts/truetype/freefont/FreeSans.ttf"); + FileInputStream in = new FileInputStream(fontfile); + FileChannel ch = in.getChannel(); + ByteBuffer buffer = ch.map(FileChannel.MapMode.READ_ONLY, 0, + fontfile.length()); + fontDelegate = FontFactory.createFonts(buffer)[0]; + } + catch (Exception ex) + { + ex.printStackTrace(); + } + } + + public boolean canDisplay(Font font, char c) + { + // FIXME: Implement this. + throw new UnsupportedOperationException("Not yet implemented"); + } + + public int canDisplayUpTo(Font font, CharacterIterator i, int start, int limit) + { + // FIXME: Implement this. + throw new UnsupportedOperationException("Not yet implemented"); + } + + public String getSubFamilyName(Font font, Locale locale) + { + // FIXME: Implement this. + throw new UnsupportedOperationException("Not yet implemented"); + } + + public String getPostScriptName(Font font) + { + // FIXME: Implement this. + throw new UnsupportedOperationException("Not yet implemented"); + } + + public int getNumGlyphs(Font font) + { + // FIXME: Implement this. + throw new UnsupportedOperationException("Not yet implemented"); + } + + public int getMissingGlyphCode(Font font) + { + // FIXME: Implement this. + throw new UnsupportedOperationException("Not yet implemented"); + } + + public byte getBaselineFor(Font font, char c) + { + // FIXME: Implement this. + throw new UnsupportedOperationException("Not yet implemented"); + } + + public String getGlyphName(Font font, int glyphIndex) + { + // FIXME: Implement this. + throw new UnsupportedOperationException("Not yet implemented"); + } + + public GlyphVector createGlyphVector(Font font, FontRenderContext frc, CharacterIterator ci) + { + return fontDelegate.createGlyphVector(font, frc, ci); + } + + public GlyphVector createGlyphVector(Font font, FontRenderContext ctx, int[] glyphCodes) + { + // FIXME: Implement this. + throw new UnsupportedOperationException("Not yet implemented"); + } + + public GlyphVector layoutGlyphVector(Font font, FontRenderContext frc, char[] chars, int start, int limit, int flags) + { + StringCharacterIterator i = new StringCharacterIterator(new String(chars), start, limit, 0); + return fontDelegate.createGlyphVector(font, frc, i); + } + + public FontMetrics getFontMetrics(Font font) + { + return new XFontMetrics(font); + } + + public boolean hasUniformLineMetrics(Font font) + { + // FIXME: Implement this. + throw new UnsupportedOperationException("Not yet implemented"); + } + + public LineMetrics getLineMetrics(Font font, CharacterIterator ci, int begin, int limit, FontRenderContext rc) + { + return new XLineMetrics(font, ci, begin, limit, rc); + } + + public Rectangle2D getMaxCharBounds(Font font, FontRenderContext rc) + { + // FIXME: Implement this. + throw new UnsupportedOperationException("Not yet implemented"); + } + + public Rectangle2D getStringBounds(Font font, CharacterIterator ci, int begin, int limit, FontRenderContext frc) + { + // FIXME: Implement this. + throw new UnsupportedOperationException("Not yet implemented"); + } + +} diff --git a/gnu/java/awt/peer/x/XFramePeer.java b/gnu/java/awt/peer/x/XFramePeer.java new file mode 100644 index 000000000..1d34b1a81 --- /dev/null +++ b/gnu/java/awt/peer/x/XFramePeer.java @@ -0,0 +1,321 @@ +/* XFramePeer.java -- The X FramePeer implementation + 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.x; + +import java.awt.Component; +import java.awt.EventQueue; +import java.awt.Font; +import java.awt.FontMetrics; +import java.awt.Frame; +import java.awt.Graphics; +import java.awt.Image; +import java.awt.Insets; +import java.awt.Point; +import java.awt.Rectangle; +import java.awt.event.PaintEvent; +import java.awt.event.WindowEvent; + +import gnu.java.awt.peer.swing.SwingFramePeer; +import gnu.x11.Window; +import gnu.x11.event.Event; + +public class XFramePeer + extends SwingFramePeer +{ + + private static int standardSelect = Event.BUTTON_PRESS_MASK + | Event.BUTTON_RELEASE_MASK + | Event.POINTER_MOTION_MASK + //| Event.RESIZE_REDIRECT_MASK + | Event.EXPOSURE_MASK + //| Event.PROPERTY_CHANGE_MASK + | Event.STRUCTURE_NOTIFY_MASK + | Event.KEY_PRESS_MASK + | Event.KEY_RELEASE_MASK + ; + + /** + * The X window. + */ + private Window xwindow; + + /** + * Indicates if we are in callback mode, that is when a property (like size) + * is changed in reponse to a request from the X server and doesn't need + * to be propagated back to the X server. + */ + boolean callback = false; + + public XFramePeer(Frame frame) + { + super(frame); + XGraphicsDevice dev = XToolkit.getDefaultDevice(); + + // TODO: Maybe initialize lazily in show(). + int x = Math.max(frame.getX(), 0); + int y = Math.max(frame.getY(), 0); + int w = Math.max(frame.getWidth(), 1); + int h = Math.max(frame.getHeight(), 1); + xwindow = new Window(dev.getDisplay().default_root, x, y, w, h); + xwindow.create(); + xwindow.select_input(standardSelect); + dev.getEventPump().registerWindow(xwindow, frame); + } + + public void setIconImage(Image image) + { + // TODO: Implement this. + throw new UnsupportedOperationException("Not yet implemented."); + } + + public void setResizable(boolean resizable) + { + // TODO: Implement this. + throw new UnsupportedOperationException("Not yet implemented."); + } + + public void setTitle(String title) + { + // TODO: Implement this. + throw new UnsupportedOperationException("Not yet implemented."); + } + + public int getState() + { + // TODO: Implement this. + throw new UnsupportedOperationException("Not yet implemented."); + } + + public void setState(int state) + { + // FIXME: Implement this. + throw new UnsupportedOperationException("Not yet implemented."); + } + + public void setMaximizedBounds(Rectangle r) + { + // FIXME: Implement this. + throw new UnsupportedOperationException("Not yet implemented."); + } + + public void setBoundsPrivate(int x, int y, int width, int height) + { + // FIXME: Implement this. + throw new UnsupportedOperationException("Not yet implemented."); + } + + public void toBack() + { + // FIXME: Implement this. + throw new UnsupportedOperationException("Not yet implemented."); + } + + public void toFront() + { + // FIXME: Implement this. + throw new UnsupportedOperationException("Not yet implemented."); + } + + public void updateAlwaysOnTop() + { + // FIXME: Implement this. + throw new UnsupportedOperationException("Not yet implemented."); + } + + public boolean requestWindowFocus() + { + // FIXME: Implement this. + throw new UnsupportedOperationException("Not yet implemented."); + } + + public Point getLocationOnScreen() + { + return new Point(xwindow.x, xwindow.y); + } + + /** + * Returns a XGraphics suitable for drawing on this frame. + * + * @return a XGraphics suitable for drawing on this frame + */ + public Graphics getGraphics() + { + return new XGraphics(xwindow); + } + + public Image createImage(int w, int h) + { + return new XImage(w, h); + } + + /** + * Sets the visibility state of the component. This is called by + * {@link Component#setVisible(boolean)}. + * + * This is implemented to call setVisible() on the Swing component. + * + * @param visible <code>true</code> to make the component visible, + * <code>false</code> to make it invisible + */ + public void setVisible(boolean visible) + { + if (visible) + show(); + else + hide(); + } + + /** + * Makes the component visible. This is called by {@link Component#show()}. + * + * This is implemented to call setVisible(true) on the Swing component. + */ + public void show() + { +// // Prevent ResizeRedirect events. +// //xwindow.select_input(noResizeRedirectSelect); +// Window.Attributes atts = new Window.Attributes(); +// atts.set_override_redirect(true); +// xwindow.change_attributes(atts); + + // Prevent ResizeRedirect events. + //xwindow.select_input(Event.NO_EVENT_MASK); + //xwindow.select_input(noResizeRedirectSelect); + + xwindow.map(); + EventQueue eq = XToolkit.getDefaultToolkit().getSystemEventQueue(); + java.awt.Window w = (java.awt.Window) super.awtComponent; + eq.postEvent(new WindowEvent(w, WindowEvent.WINDOW_OPENED)); + eq.postEvent(new PaintEvent(w, PaintEvent.PAINT, + new Rectangle(0, 0, w.getWidth(), + w.getHeight()))); + +// // Reset input selection. +// atts.set_override_redirect(false); +// xwindow.change_attributes(atts); + } + + /** + * Makes the component invisible. This is called from + * {@link Component#hide()}. + * + * This is implemented to call setVisible(false) on the Swing component. + */ + public void hide() + { + xwindow.unmap(); + } + + /** + * Notifies the peer that the bounds of this component have changed. This + * is called by {@link Component#reshape(int, int, int, int)}. + * + * This is implemented to call setBounds() on the Swing component. + * + * @param x the X coordinate of the upper left corner of the component + * @param y the Y coordinate of the upper left corner of the component + * @param width the width of the component + * @param height the height of the component + */ + public void reshape(int x, int y, int width, int height) + { +// if (callback) +// return; + + // Prevent ResizeRedirect events. +// //xwindow.select_input(noResizeRedirectSelect); +// Window.Attributes atts = new Window.Attributes(); +// atts.set_override_redirect(true); +// xwindow.change_attributes(atts); + + // Need to substract insets because AWT size is including insets, + // and X size is excuding insets. + Insets i = insets(); + xwindow.move_resize(x - i.left, y - i.right, width - i.left - i.right, + height - i.top - i.bottom); + + // Reset input selection. +// atts = new Window.Attributes(); +// atts.set_override_redirect(false); +// xwindow.change_attributes(atts); + } + + public Insets insets() + { + Insets i = new Insets(0, 0, 0, 0); +// Window.GeometryReply g = xwindow.geometry(); +// int b = g.border_width(); +// Insets i = new Insets(b, b, b, b); +// Window.WMSizeHints wmSize = xwindow.wm_normal_hints(); +// if (wmSize != null) +// { +// i.left = wmSize.x() - g.x(); +// i.right = wmSize.width() - g.width() - i.left ; +// i.top = wmSize.y() - g.y(); +// i.bottom = wmSize.height() - g.height() - i.top; +// } +// System.err.println("insets: " + i); + return i; + } + + /** + * Returns the font metrics for the specified font. + * + * @return the font metrics for the specified font + */ + public FontMetrics getFontMetrics(Font font) + { + XFontPeer fontPeer = (XFontPeer) font.getPeer(); + return fontPeer.getFontMetrics(font); + } + + /** + * Unregisters the window in the event pump when it is closed. + */ + protected void finalize() + { + XGraphicsDevice dev = XToolkit.getDefaultDevice(); + dev.getEventPump().unregisterWindow(xwindow); + } + + public Rectangle getBounds() + { + return new Rectangle(xwindow.x, xwindow.y, xwindow.width, xwindow.height); + } +} diff --git a/gnu/java/awt/peer/x/XGraphics.java b/gnu/java/awt/peer/x/XGraphics.java new file mode 100644 index 000000000..81168797c --- /dev/null +++ b/gnu/java/awt/peer/x/XGraphics.java @@ -0,0 +1,855 @@ +/* XGraphics.java -- The Graphics implementation for X + 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.x; + +import gnu.x11.Drawable; +import gnu.x11.GC; +import gnu.x11.Pixmap; +import gnu.x11.Point; + +import java.awt.AWTError; +import java.awt.Color; +import java.awt.Composite; +import java.awt.Font; +import java.awt.FontMetrics; +import java.awt.Graphics; +import java.awt.Graphics2D; +import java.awt.GraphicsConfiguration; +import java.awt.Image; +import java.awt.Paint; +import java.awt.Rectangle; +import java.awt.RenderingHints; +import java.awt.Shape; +import java.awt.Stroke; +import java.awt.RenderingHints.Key; +import java.awt.font.FontRenderContext; +import java.awt.font.GlyphVector; +import java.awt.geom.AffineTransform; +import java.awt.image.BufferedImage; +import java.awt.image.BufferedImageOp; +import java.awt.image.ImageObserver; +import java.awt.image.ImageProducer; +import java.awt.image.RenderedImage; +import java.awt.image.renderable.RenderableImage; +import java.text.AttributedCharacterIterator; +import java.util.Map; + +public class XGraphics + extends Graphics2D + implements Cloneable +{ + + /** + * The X Drawable to draw on. + */ + private Drawable xdrawable; + + /** + * The X graphics context (GC). + */ + private GC xgc; + + /** + * The current translation. + */ + private int translateX; + private int translateY; + + /** + * The current clip. Possibly null. + */ + private Rectangle clip; + + /** + * The current font, possibly null. + */ + private Font font; + + /** + * The current foreground color, possibly null. + */ + private Color foreground; + + /** + * Indicates if this object has been disposed. + */ + private boolean disposed = false; + + /** + * Creates a new XGraphics on the specified X Drawable. + * + * @param d the X Drawable for which we create the Graphics + */ + XGraphics(Drawable d) + { + xdrawable = d; + xgc = new GC(d); + translateX = 0; + translateY = 0; + clip = new Rectangle(0, 0, d.width, d.height); + } + + /** + * Creates an exact copy of this graphics context. + * + * @return an exact copy of this graphics context + */ + public Graphics create() + { + XGraphics copy = (XGraphics) clone(); + return copy; + } + + /** + * Translates the origin by (x, y). + */ + public void translate(int x, int y) + { + translateX += x; + translateY += y; + if (clip != null) + { + clip.x -= x; + clip.y -= y; + setClip(clip); + } + } + + /** + * Returns the current foreground color, possibly <code>null</code>. + * + * @return the current foreground color, possibly <code>null</code> + */ + public Color getColor() + { + return foreground; + } + + /** + * Sets the current foreground color. A <code>null</code> value doesn't + * change the current setting. + * + * @param c the foreground color to set + */ + public void setColor(Color c) + { + if (c != null) + { + xgc.set_foreground(c.getRGB()); + foreground = c; + } + } + + public void setPaintMode() + { + // FIXME: Implement this. + throw new UnsupportedOperationException("Not yet implemented"); + } + + public void setXORMode(Color color) + { + // FIXME: Implement this. + throw new UnsupportedOperationException("Not yet implemented"); + } + + /** + * Returns the current font, possibly <code>null</code>. + * + * @return the current font, possibly <code>null</code> + */ + public Font getFont() + { + return font; + } + + /** + * Sets the font on the graphics context. A <code>null</code> value doesn't + * change the current setting. + * + * @param f the font to set + */ + public void setFont(Font f) + { + if (f != null) + { + XFontPeer xFontPeer = (XFontPeer) f.getPeer(); + xgc.set_font(xFontPeer.getXFont()); + font = f; + } + } + + /** + * Returns the font metrics for the specified font. + * + * @param font the font for which we want the font metrics + * + * @return the font metrics for the specified font + */ + public FontMetrics getFontMetrics(Font font) + { + if (font == null) + { + if (this.font == null) + setFont(new Font("Dialog", Font.PLAIN, 12)); + font = this.font; + } + XFontPeer xFontPeer = (XFontPeer) font.getPeer(); + return xFontPeer.getFontMetrics(font); + } + + /** + * Returns the bounds of the current clip. + * + * @return the bounds of the current clip + */ + public Rectangle getClipBounds() + { + return clip != null ? clip.getBounds() : null; + } + + /** + * Clips the current clip with the specified clip. + */ + public void clipRect(int x, int y, int width, int height) + { + if (clip == null) + { + clip = new Rectangle(x, y, width, height); + } + else + { + computeIntersection(x, y, width, height, clip); + } + // Update the X clip setting. + setClip(clip.x, clip.y, clip.width, clip.height); + } + + /** + * Returns <code>true</code> when the specified rectangle intersects with + * the current clip, <code>false</code> otherwise. This is overridden to + * avoid unnecessary creation of Rectangles via getBounds(). + * + * @param x the x coordinate of the rectangle + * @param y the y coordinate of the rectangle + * @param w the width of the rectangle + * @param h the height of the rectangle + * + * @return <code>true</code> when the specified rectangle intersects with + * the current clip, <code>false</code> otherwise + */ + public boolean hitClip(int x, int y, int w, int h) + { + boolean hit; + if (clip == null) + { + hit = true; + } + else + { + hit = clip.intersects(x, y, w, h); + } + //System.err.println("hitClip: " + hit); + return hit; + } + + public void setClip(int x, int y, int width, int height) + { + if (clip != null) + clip.setBounds(x, y, width, height); + else + clip = new Rectangle(x, y, width, height); + + gnu.x11.Rectangle[] clipRects = new gnu.x11.Rectangle[] { + new gnu.x11.Rectangle(x, y, width, height) }; + xgc.set_clip_rectangles(translateX, translateY, clipRects, GC.UN_SORTED); + } + + public Shape getClip() + { + // Return a copy here, so nobody can trash our clip. + return clip == null ? null : clip.getBounds(); + } + + /** + * Sets the current clip. + * + * @param clip the clip to set + */ + public void setClip(Shape clip) + { + if (clip != null) + { + Rectangle b; + if (clip instanceof Rectangle) + { + b = (Rectangle) clip; + } + else + { + b = clip.getBounds(); + } + setClip(b.x, b.y, b.width, b.height); + } + else + { + setClip(0, 0, xdrawable.width, xdrawable.height); + } + } + + public void copyArea(int x, int y, int width, int height, int dx, int dy) + { + // FIXME: Implement this. + throw new UnsupportedOperationException("Not yet implemented"); + } + + /** + * Draws a line from point (x1, y1) to point (x2, y2). + */ + public void drawLine(int x1, int y1, int x2, int y2) + { + //System.err.println("drawLine: " + (x1 + translateX) + ", " + ( y1 + translateY) + ", " + (x2 + translateX) + ", " + (y2 + translateY) + " on: " + xdrawable); + xdrawable.line(xgc, x1 + translateX, y1 + translateY, + x2 + translateX, y2 + translateY); + } + + /** + * Fills the specified rectangle. + */ + public void fillRect(int x, int y, int width, int height) + { + xdrawable.rectangle(xgc, x + translateX, y + translateY, + width, height, true); + } + + public void clearRect(int x, int y, int width, int height) + { + xgc.set_foreground(Color.WHITE.getRGB()); + xdrawable.rectangle(xgc, x, y, width, height, true); + if (foreground != null) + xgc.set_foreground(foreground.getRGB()); + } + + public void drawRoundRect(int x, int y, int width, int height, int arcWidth, + int arcHeight) + { + // Draw 4 lines. + int arcRadiusX = arcWidth / 2; + int arcRadiusY = arcHeight / 2; + drawLine(x + arcRadiusX, y, x + width - arcRadiusX, y); + drawLine(x, y + arcRadiusY, x, y + height - arcRadiusY); + drawLine(x + arcRadiusX, y + height, x + width - arcRadiusX, y + height); + drawLine(x + width, y + arcRadiusY, x + width, y + height - arcRadiusY); + + // Draw the 4 arcs at the corners. + // Upper left. + drawArc(x, y, arcWidth, arcHeight, 90, 90); + // Lower left. + drawArc(x, y + height - arcHeight, arcWidth, arcHeight, 180, 90); + // Upper right. + drawArc(x + width - arcWidth, y, arcWidth, arcHeight, 0, 90); + // Lower right. + drawArc(x + width - arcWidth, y + height - arcHeight, arcWidth, arcHeight, + 270, 90); + } + + public void fillRoundRect(int x, int y, int width, int height, int arcWidth, + int arcHeight) + { + // Fill the 3 rectangles that make up the inner area. + int arcRadiusX = arcWidth / 2; + int arcRadiusY = arcHeight / 2; + // Left. + fillRect(x, y + arcRadiusY, arcRadiusX, height - arcHeight); + // Middle. + fillRect(x + arcRadiusX, y, width - arcWidth, height); + // Right. + fillRect(x + width - arcRadiusX, y + arcRadiusY, arcRadiusX, + height - arcHeight); + + // Fill the 4 arcs in the corners. + // Upper left. + fillArc(x, y, arcWidth, arcHeight, 90, 90); + // Lower left. + fillArc(x, y + height - arcHeight, arcWidth, arcHeight, 180, 90); + // Upper right. + fillArc(x + width - arcWidth, y, arcWidth, arcHeight, 0, 90); + // Lower right. + fillArc(x + width - arcWidth, y + height - arcHeight, arcWidth, arcHeight, + 270, 90); + } + + public void drawOval(int x, int y, int width, int height) + { + xdrawable.arc(xgc, x, y, width, height, 0, 360 * 64, false); + } + + public void fillOval(int x, int y, int width, int height) + { + xdrawable.arc(xgc, x, y, width, height, 0, 360 * 64, true); + } + + public void drawArc(int x, int y, int width, int height, int arcStart, + int arcAngle) + { + xdrawable.arc(xgc, x, y, width, height, arcStart * 64, arcAngle * 64, false); + } + + public void fillArc(int x, int y, int width, int height, int arcStart, + int arcAngle) + { + xdrawable.arc(xgc, x, y, width, height, arcStart * 64, arcAngle * 64, true); + } + + public void drawPolyline(int[] xPoints, int[] yPoints, int npoints) + { + int numPoints = Math.min(xPoints.length, yPoints.length); + Point[] points = new Point[numPoints]; + // FIXME: Improve Escher API to accept arrays to avoid creation + // of many Point objects. + for (int i = 0; i < numPoints; i++) + points[i] = new Point(xPoints[i], yPoints[i]); + xdrawable.poly_line(xgc, points, Drawable.ORIGIN); + } + + public void drawPolygon(int[] xPoints, int[] yPoints, int npoints) + { + int numPoints = Math.min(xPoints.length, yPoints.length); + Point[] points = new Point[numPoints]; + // FIXME: Improve Escher API to accept arrays to avoid creation + // of many Point objects. + for (int i = 0; i < numPoints; i++) + points[i] = new Point(xPoints[i], yPoints[i]); + xdrawable.poly_line(xgc, points, Drawable.ORIGIN); + } + + public void fillPolygon(int[] xPoints, int[] yPoints, int npoints) + { + int numPoints = Math.min(xPoints.length, yPoints.length); + Point[] points = new Point[numPoints]; + // FIXME: Improve Escher API to accept arrays to avoid creation + // of many Point objects. + for (int i = 0; i < numPoints; i++) + points[i] = new Point(xPoints[i], yPoints[i]); + xdrawable.fill_poly(xgc, points, Drawable.COMPLEX, Drawable.ORIGIN); + } + + /** + * Draws the specified string at (x, y). + */ + public void drawString(String string, int x, int y) + { + if (disposed) + throw new AWTError("XGraphics already disposed"); + + xdrawable.text(xgc, x + translateX, y + translateY, string); + } + + public void drawString(AttributedCharacterIterator ci, int x, int y) + { + // FIXME: Implement this. + throw new UnsupportedOperationException("Not yet implemented"); + } + + /** + * Draws the specified image on the drawable at position (x,y). + */ + public boolean drawImage(Image image, int x, int y, ImageObserver observer) + { + if (image instanceof XImage) + { + XImage xim = (XImage) image; + Pixmap pm = xim.pixmap; + xdrawable.copy_area(pm, xgc, 0, 0, pm.width, pm.height, + x + translateX, y + translateY); + } +// else if (image instanceof BufferedImage) +// { +// BufferedImage bufferedImage = (BufferedImage) image; +// Raster raster = bufferedImage.getData(); +// int w = bufferedImage.getWidth(); +// int h = bufferedImage.getHeight(); +// // Push data to X server. +// ZPixmap zPixmap = new ZPixmap(xdrawable.display, w, h, +// xdrawable.display.default_pixmap_format); +// System.err.println("data buffer length: " + zPixmap.data.length); +// int[] pixel = new int[4]; +// for (int tx = 0; tx < w; tx++) +// { +// for (int ty = 0; ty < h; ty++) +// { +// pixel = raster.getPixel(tx, ty, pixel); +//// System.err.print("r: " + pixel[0]); +//// System.err.print(", g: " + pixel[1]); +//// System.err.println(", b: " + pixel[2]); +// zPixmap.set_red(tx, ty, pixel[0]); +// zPixmap.set_green(tx, ty, pixel[1]); +// zPixmap.set_blue(tx, ty, pixel[2]); +// } +// } +// xdrawable.put_image(xgc, zPixmap, x, y); +// } + else + { + // Pre-render the image into an XImage. + ImageProducer source = image.getSource(); + ImageConverter conv = new ImageConverter(); + source.startProduction(conv); + XImage xim = conv.getXImage(); + Pixmap pm = xim.pixmap; + xdrawable.copy_area(pm, xgc, 0, 0, pm.width, pm.height, + x + translateX, y + translateY); + } + return true; + } + + public boolean drawImage(Image image, int x, int y, int width, int height, + ImageObserver observer) + { + // FIXME: Implement this. + throw new UnsupportedOperationException("Not yet implemented"); + } + + public boolean drawImage(Image image, int x, int y, Color bgcolor, + ImageObserver observer) + { + // FIXME: Implement this. + throw new UnsupportedOperationException("Not yet implemented"); + } + + public boolean drawImage(Image image, int x, int y, int width, int height, + Color bgcolor, ImageObserver observer) + { + // FIXME: Implement this. + throw new UnsupportedOperationException("Not yet implemented"); + } + + public boolean drawImage(Image image, int dx1, int dy1, int dx2, int dy2, + int sx1, int sy1, int sx2, int sy2, + ImageObserver observer) + { + // FIXME: Implement this. + throw new UnsupportedOperationException("Not yet implemented"); + } + + public boolean drawImage(Image image, int dx1, int dy1, int dx2, int dy2, + int sx1, int sy1, int sx2, int sy2, Color bgcolor, + ImageObserver observer) + { + // FIXME: Implement this. + throw new UnsupportedOperationException("Not yet implemented"); + } + + /** + * Frees any resources associated with this object. + */ + public void dispose() + { + xdrawable.display.flush(); + if (! disposed) + { + xgc.free(); + disposed = true; + } + } + + // Additional Graphics2D methods. + + public void draw(Shape shape) + { + // FIXME: Implement this. + throw new UnsupportedOperationException("Not yet implemented"); + } + + public boolean drawImage(Image image, AffineTransform xform, ImageObserver obs) + { + // FIXME: Implement this. + throw new UnsupportedOperationException("Not yet implemented"); + } + + public void drawImage(BufferedImage image, BufferedImageOp op, int x, int y) + { + // FIXME: Implement this. + throw new UnsupportedOperationException("Not yet implemented"); + } + + public void drawRenderedImage(RenderedImage image, AffineTransform xform) + { + // FIXME: Implement this. + throw new UnsupportedOperationException("Not yet implemented"); + } + + public void drawRenderableImage(RenderableImage image, AffineTransform xform) + { + // FIXME: Implement this. + throw new UnsupportedOperationException("Not yet implemented"); + } + + public void drawString(String text, float x, float y) + { + // FIXME: Implement this. + throw new UnsupportedOperationException("Not yet implemented"); + } + + public void drawString(AttributedCharacterIterator iterator, float x, float y) + { + // FIXME: Implement this. + throw new UnsupportedOperationException("Not yet implemented"); + } + + public void fill(Shape shape) + { + // FIXME: Implement this. + throw new UnsupportedOperationException("Not yet implemented"); + } + + public boolean hit(Rectangle rect, Shape text, boolean onStroke) + { + // FIXME: Implement this. + throw new UnsupportedOperationException("Not yet implemented"); + } + + public GraphicsConfiguration getDeviceConfiguration() + { + // FIXME: Implement this. + throw new UnsupportedOperationException("Not yet implemented"); + } + + public void setComposite(Composite comp) + { + // FIXME: Implement this. + throw new UnsupportedOperationException("Not yet implemented"); + } + + public void setPaint(Paint paint) + { + // FIXME: Implement this. + throw new UnsupportedOperationException("Not yet implemented"); + } + + public void setStroke(Stroke stroke) + { + // FIXME: Implement this. + throw new UnsupportedOperationException("Not yet implemented"); + } + + public void setRenderingHint(Key hintKey, Object hintValue) + { + // FIXME: Implement this. + throw new UnsupportedOperationException("Not yet implemented"); + } + + public Object getRenderingHint(Key hintKey) + { + // FIXME: Implement this. + throw new UnsupportedOperationException("Not yet implemented"); + } + + public void setRenderingHints(Map hints) + { + // FIXME: Implement this. + throw new UnsupportedOperationException("Not yet implemented"); + } + + public void addRenderingHints(Map hints) + { + // FIXME: Implement this. + throw new UnsupportedOperationException("Not yet implemented"); + } + + public RenderingHints getRenderingHints() + { + // FIXME: Implement this. + throw new UnsupportedOperationException("Not yet implemented"); + } + + public void translate(double tx, double ty) + { + // FIXME: Implement this. + throw new UnsupportedOperationException("Not yet implemented"); + } + + public void rotate(double theta) + { + // FIXME: Implement this. + throw new UnsupportedOperationException("Not yet implemented"); + } + + public void rotate(double theta, double x, double y) + { + // FIXME: Implement this. + throw new UnsupportedOperationException("Not yet implemented"); + } + + public void scale(double scaleX, double scaleY) + { + // FIXME: Implement this. + throw new UnsupportedOperationException("Not yet implemented"); + } + + public void shear(double shearX, double shearY) + { + // FIXME: Implement this. + throw new UnsupportedOperationException("Not yet implemented"); + } + + public void transform(AffineTransform Tx) + { + // FIXME: Implement this. + throw new UnsupportedOperationException("Not yet implemented"); + } + + public void setTransform(AffineTransform Tx) + { + // FIXME: Implement this. + throw new UnsupportedOperationException("Not yet implemented"); + } + + public AffineTransform getTransform() + { + // FIXME: Implement this. + throw new UnsupportedOperationException("Not yet implemented"); + } + + public Paint getPaint() + { + // FIXME: Implement this. + throw new UnsupportedOperationException("Not yet implemented"); + } + + public Composite getComposite() + { + // FIXME: Implement this. + throw new UnsupportedOperationException("Not yet implemented"); + } + + public void setBackground(Color color) + { + // FIXME: Implement this. + throw new UnsupportedOperationException("Not yet implemented"); + } + + public Color getBackground() + { + // FIXME: Implement this. + throw new UnsupportedOperationException("Not yet implemented"); + } + + public Stroke getStroke() + { + // FIXME: Implement this. + throw new UnsupportedOperationException("Not yet implemented"); + } + + public void clip(Shape s) + { + // FIXME: Implement this. + throw new UnsupportedOperationException("Not yet implemented"); + } + + public FontRenderContext getFontRenderContext() + { + // FIXME: Implement this. + throw new UnsupportedOperationException("Not yet implemented"); + } + + public void drawGlyphVector(GlyphVector g, float x, float y) + { + // FIXME: Implement this. + throw new UnsupportedOperationException("Not yet implemented"); + } + + + // Additional helper methods. + + /** + * Creates and returns an exact copy of this XGraphics. + */ + protected Object clone() + { + try + { + XGraphics copy = (XGraphics) super.clone(); + copy.xgc = xgc.copy(); + + // Save the original clip. + if (clip != null) + copy.clip = new Rectangle(clip); + return copy; + } + catch (CloneNotSupportedException ex) + { + AWTError err = new AWTError("Error while cloning XGraphics"); + err.initCause(ex); + throw err; + } + } + + /** + * Computes the intersection between two rectangles and stores the result + * int the second rectangle. + * + * This method has been copied from {@link javax.swing.SwingUtilities}. + * + * @param x the x coordinate of the rectangle #1 + * @param y the y coordinate of the rectangle #1 + * @param w the width of the rectangle #1 + * @param h the height of the rectangle #1 + * @param rect the rectangle #2 and output rectangle + */ + private static void computeIntersection(int x, int y, int w, int h, + Rectangle rect) + { + int x2 = (int) rect.x; + int y2 = (int) rect.y; + int w2 = (int) rect.width; + int h2 = (int) rect.height; + + int dx = (x > x2) ? x : x2; + int dy = (y > y2) ? y : y2; + int dw = (x + w < x2 + w2) ? (x + w - dx) : (x2 + w2 - dx); + int dh = (y + h < y2 + h2) ? (y + h - dy) : (y2 + h2 - dy); + + if (dw >= 0 && dh >= 0) + rect.setBounds(dx, dy, dw, dh); + else + rect.setBounds(0, 0, 0, 0); + } + + +} diff --git a/gnu/java/awt/peer/x/XGraphics2D.java b/gnu/java/awt/peer/x/XGraphics2D.java new file mode 100644 index 000000000..5dc79ff5c --- /dev/null +++ b/gnu/java/awt/peer/x/XGraphics2D.java @@ -0,0 +1,295 @@ +/* XGraphics2D.java -- A Java based Graphics2D impl for X + 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.x; + +import java.awt.Graphics; +import java.awt.GraphicsConfiguration; +import java.awt.Rectangle; +import java.awt.Shape; +import java.awt.Toolkit; +import java.awt.geom.AffineTransform; +import java.awt.image.ColorModel; +import java.awt.image.Raster; + +import gnu.java.awt.java2d.AbstractGraphics2D; +import gnu.x11.Drawable; +import gnu.x11.GC; +import gnu.x11.image.ZPixmap; + +public class XGraphics2D + extends AbstractGraphics2D +{ + + /** + * The X Drawable to draw on. + */ + private Drawable xdrawable; + + /** + * The X graphics context (GC). + */ + private GC xgc; + + /** + * Indicates if this graphics has already been disposed. + */ + private boolean disposed; + + XGraphics2D(Drawable d) + { + super(); + xdrawable = d; + xgc = new GC(d); + init(); + disposed = false; + //setClip(new Rectangle(0, 0, xdrawable.width, xdrawable.height)); + } + + /** + * Draws a pixel in the target coordinate space using the specified color. + * + * @param x the x coordinate + * @param y the y coordinate + */ + protected void rawSetPixel(int x, int y) + { + xdrawable.point(xgc, x, y); + } + +// protected void rawFillPolygon(double[] xpoints, double[] ypoints, int npoints) +// { +// Point[] points = new Point[npoints]; +// for (int n = 0; n < npoints; n++) +// { +// points[n] = new Point((int) xpoints[n], (int) ypoints[n]); +// } +// xdrawable.fill_poly(xgc, points, Drawable.COMPLEX, Drawable.ORIGIN); +// xdrawable.display.flush(); +// } + + protected void rawDrawLine(int x0, int y0, int x1, int y1) + { + xdrawable.line(xgc, x0, y0, x1, y1); + } + + protected void rawFillRect(int x, int y, int w, int h) + { + xdrawable.rectangle(xgc, x, y, w, h, true); + } + + protected void rawSetForeground(java.awt.Color c) + { + if (c != null) + xgc.set_foreground(c.getRGB()); + } + + protected void rawSetForeground(int r, int g, int b) + { + xgc.set_foreground( r << 16 | g << 8 | b ); + } + + /** + * Returns the color model of this Graphics object. + * + * @return the color model of this Graphics object + */ + protected ColorModel getColorModel() + { + return Toolkit.getDefaultToolkit().getColorModel(); + } + + /** + * Returns the color model of the target device. + * + * @return the color model of the target device + */ + protected ColorModel getDestinationColorModel() + { + return Toolkit.getDefaultToolkit().getColorModel(); + } + + /** + * Returns the bounds of the target. + * + * @return the bounds of the target + */ + protected Rectangle getDeviceBounds() + { + return new Rectangle(0, 0, xdrawable.width, xdrawable.height); + } + + public GraphicsConfiguration getDeviceConfiguration() + { + // FIXME: Implement this. + throw new UnsupportedOperationException("Not yet implemented"); + } + + public void dispose() + { + if (!disposed) + { + xgc.free(); + xdrawable.display.flush(); + disposed = true; + } + } + + public Graphics create() + { + // super.create() returns a copy created by clone(), so it should + // be a XGraphics2D. + XGraphics2D copy = (XGraphics2D) super.create(); + copy.xgc = xgc.copy(); + return copy; + } + +// /** +// * Draws the specified image on the drawable at position (x,y). +// */ +// +// public boolean drawImage(Image image, int x, int y, ImageObserver observer) +// { +// AffineTransform transform = getTransform(); +// int translateX = (int) transform.getTranslateX(); +// int translateY = (int) transform.getTranslateY(); +// if (image instanceof XImage) +// { +// XImage xim = (XImage) image; +// Pixmap pm = xim.pixmap; +// xdrawable.copy_area(pm, xgc, 0, 0, pm.width, pm.height, +// x + translateX, y + translateY); +// } +// else if (image instanceof BufferedImage) +// { +// BufferedImage bufferedImage = (BufferedImage) image; +// Raster raster = bufferedImage.getData(); +// int w = bufferedImage.getWidth(); +// int h = bufferedImage.getHeight(); +// // Push data to X server. +// ZPixmap zPixmap = new ZPixmap(xdrawable.display, w, h, +// xdrawable.display.default_pixmap_format); +// System.err.println("data buffer length: " + zPixmap.data.length); +// int[] pixel = new int[4]; +// for (int tx = 0; tx < w; tx++) +// { +// for (int ty = 0; ty < h; ty++) +// { +// pixel = raster.getPixel(tx, ty, pixel); +//// System.err.print("r: " + pixel[0]); +//// System.err.print(", g: " + pixel[1]); +//// System.err.println(", b: " + pixel[2]); +// zPixmap.set_red(tx, ty, pixel[0]); +// zPixmap.set_green(tx, ty, pixel[1]); +// zPixmap.set_blue(tx, ty, pixel[2]); +// } +// } +// xdrawable.put_image(xgc, zPixmap, x, y); +// } +// else +// { +// throw new UnsupportedOperationException("Not yet implemented."); +// } +// return true; +// } +// + public void setClip(Shape c) + { + super.setClip(c); + if (c instanceof Rectangle) + { + Rectangle r = (Rectangle) c; + AffineTransform t = getTransform(); + int translateX = (int) t.getTranslateX(); + //System.err.println("translateX: " + translateX); + int translateY = (int) t.getTranslateY(); + //System.err.println("translateY: " + translateY); + //System.err.println("clip: " + c); + gnu.x11.Rectangle clip = new gnu.x11.Rectangle(r.x, r.y, r.width, + r.height); + xgc.set_clip_rectangles(translateX, translateY, + new gnu.x11.Rectangle[]{clip}, GC.UN_SORTED); + } + } + + /** + * Notifies the backend that the raster has changed in the specified + * rectangular area. The raster that is provided in this method is always + * the same as the one returned in {@link #getDestinationRaster}. + * Backends that reflect changes to this raster directly don't need to do + * anything here. + * + * @param raster the updated raster, identical to the raster returned + * by {@link #getDestinationRaster()} + * @param x the upper left corner of the updated region, X coordinate + * @param y the upper lef corner of the updated region, Y coordinate + * @param w the width of the updated region + * @param h the height of the updated region + */ + protected void updateRaster(Raster raster, int x, int y, int w, int h) + { + if (w > 0 && h > 0) + { + ZPixmap zPixmap = new ZPixmap(xdrawable.display, w, h, + xdrawable.display.default_pixmap_format); + int[] pixel = null; + int x1 = x + w; + int y1 = y + h; + for (int tx = x; tx < x1; tx++) + { + for (int ty = y; ty < y1; ty++) + { + pixel = raster.getPixel(tx, ty, pixel); + //System.err.println("tx: " + tx + ", ty: " + ty + ", pixel: " + pixel[0] + ", " + pixel[1] + ", " + pixel[2]); +// System.err.print("r: " + pixel[0]); +// System.err.print(", g: " + pixel[1]); +// System.err.println(", b: " + pixel[2]); + zPixmap.set_red(tx - x, ty - y, pixel[0]); + zPixmap.set_green(tx - x, ty - y, pixel[1]); + zPixmap.set_blue(tx - x, ty - y, pixel[2]); + } + } + xdrawable.put_image(xgc, zPixmap, x, y); + } + } + + + protected void init() + { + super.init(); + } +} diff --git a/gnu/java/awt/peer/x/XGraphicsConfiguration.java b/gnu/java/awt/peer/x/XGraphicsConfiguration.java new file mode 100644 index 000000000..d6e66cbd2 --- /dev/null +++ b/gnu/java/awt/peer/x/XGraphicsConfiguration.java @@ -0,0 +1,118 @@ +/* XGraphicsConfiguration.java -- GraphicsConfiguration for X + 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.x; + +import java.awt.GraphicsConfiguration; +import java.awt.GraphicsDevice; +import java.awt.Rectangle; +import java.awt.geom.AffineTransform; +import java.awt.image.BufferedImage; +import java.awt.image.ColorModel; +import java.awt.image.VolatileImage; + +public class XGraphicsConfiguration + extends GraphicsConfiguration +{ + + XGraphicsDevice device; + + XGraphicsConfiguration(XGraphicsDevice dev) + { + device = dev; + } + + public GraphicsDevice getDevice() + { + return device; + } + + public BufferedImage createCompatibleImage(int w, int h) + { + return new BufferedImage(w, h, BufferedImage.TYPE_INT_RGB); + } + + public VolatileImage createCompatibleVolatileImage(int w, int h) + { + // TODO: Implement this. + throw new UnsupportedOperationException("Not yet implemented."); + } + + public VolatileImage createCompatibleVolatileImage(int width, int height, + int transparency) + { + // TODO: Implement this. + throw new UnsupportedOperationException("Not yet implemented."); + } + + public BufferedImage createCompatibleImage(int w, int h, int transparency) + { + // TODO: Implement this. + throw new UnsupportedOperationException("Not yet implemented."); + } + + public ColorModel getColorModel() + { + // TODO: Implement this. + throw new UnsupportedOperationException("Not yet implemented."); + } + + public ColorModel getColorModel(int transparency) + { + // TODO: Implement this. + throw new UnsupportedOperationException("Not yet implemented."); + } + + public AffineTransform getDefaultTransform() + { + // TODO: Implement this. + throw new UnsupportedOperationException("Not yet implemented."); + } + + public AffineTransform getNormalizingTransform() + { + // TODO: Implement this. + throw new UnsupportedOperationException("Not yet implemented."); + } + + public Rectangle getBounds() + { + // TODO: Implement this. + throw new UnsupportedOperationException("Not yet implemented."); + } + +} diff --git a/gnu/java/awt/peer/x/XGraphicsDevice.java b/gnu/java/awt/peer/x/XGraphicsDevice.java new file mode 100644 index 000000000..6a020ec4e --- /dev/null +++ b/gnu/java/awt/peer/x/XGraphicsDevice.java @@ -0,0 +1,166 @@ +/* XGraphicsDevice.java -- GraphicsDevice for X + 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.x; + +import gnu.classpath.SystemProperties; +import gnu.java.net.local.LocalSocket; +import gnu.java.net.local.LocalSocketAddress; +import gnu.x11.Connection; +import gnu.x11.Display; + +import java.awt.AWTError; +import java.awt.GraphicsConfiguration; +import java.awt.GraphicsDevice; +import java.net.SocketException; + +/** + * This class represents an X Display. The actual connection is established + * lazily when it is first needed. + * + * @author Roman Kennke (kennke@aicas.com) + */ +public class XGraphicsDevice + extends GraphicsDevice +{ + + private XGraphicsConfiguration defaultConfiguration; + + /** + * The X display associated with the XGraphicsDevice. This is established + * when {@link #getDisplay} is first called. + */ + private Display display; + + /** + * The display name from which the display will be initialized. + */ + private Display.Name displayName; + + /** + * The event pump for this X Display. + */ + private XEventPump eventPump; + + /** + * Creates a new XGraphicsDevice. + */ + XGraphicsDevice(Display.Name dn) + { + displayName = dn; + } + + public int getType() + { + return TYPE_RASTER_SCREEN; + } + + public String getIDstring() + { + // TODO: Implement this. + throw new UnsupportedOperationException("Not yet implemented."); + } + + public GraphicsConfiguration[] getConfigurations() + { + // TODO: Implement this. + throw new UnsupportedOperationException("Not yet implemented."); + } + + public GraphicsConfiguration getDefaultConfiguration() + { + if (defaultConfiguration == null) + defaultConfiguration = new XGraphicsConfiguration(this); + return defaultConfiguration; + } + + /** + * Returns the X Display associated with this XGraphicsDevice. + * This establishes the connection to the X server on the first invocation. + * + * @return the X Display associated with this XGraphicsDevice + */ + Display getDisplay() + { + if (display == null) + { + if (displayName.hostname.equals("")) + displayName.hostname = "localhost"; + if (XToolkit.DEBUG) + System.err.println("connecting to : " + displayName); + // Try to connect via unix domain sockets when host == localhost. + if ((displayName.hostname.equals("localhost") + || displayName.hostname.equals("")) + && SystemProperties.getProperty("gnu.xawt.no_local_sockets") == null) + { + // TODO: Is this 100% ok? + String sockPath = "/tmp/.X11-unix/X" + displayName.display_no; + LocalSocketAddress addr = new LocalSocketAddress(sockPath); + try + { + if (XToolkit.DEBUG) + System.err.println("connecting to local socket: " + + sockPath); + LocalSocket socket = new LocalSocket(addr); + display = new Display(socket, "localhost", + displayName.display_no, + displayName.screen_no); + display.connection.send_mode = Connection.ASYNCHRONOUS; + if (XToolkit.DEBUG) + System.err.println("connected to local socket"); + } + catch (SocketException ex) + { + AWTError err = new AWTError("could not connect to X server"); + err.initCause(ex); + throw err; + } + } + else + { + display = new Display(displayName); + } + eventPump = new XEventPump(display); + } + return display; + } + + XEventPump getEventPump() + { + return eventPump; + } +} diff --git a/gnu/java/awt/peer/x/XGraphicsEnvironment.java b/gnu/java/awt/peer/x/XGraphicsEnvironment.java new file mode 100644 index 000000000..707b44c38 --- /dev/null +++ b/gnu/java/awt/peer/x/XGraphicsEnvironment.java @@ -0,0 +1,202 @@ +/* XGraphicsEnvironment.java -- Represents the X environment + 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.x; + +import gnu.java.awt.java2d.RasterGraphics; +import gnu.x11.Display; + +import java.awt.Font; +import java.awt.Graphics2D; +import java.awt.GraphicsDevice; +import java.awt.GraphicsEnvironment; +import java.awt.image.BufferedImage; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.util.ArrayList; +import java.util.Locale; +import java.util.Properties; + +/** + * Represents the X environment for AWT. + * + * @author Roman Kennke (kennke@aicas.com) + */ +public class XGraphicsEnvironment + extends GraphicsEnvironment +{ + + /** + * The default graphics device. This is normally the local main X + * Display, but can be configured to be any X connection. + */ + private XGraphicsDevice defaultDevice; + + /** + * All configured devices. + */ + private XGraphicsDevice[] devices; + + /** + * Creates a new XGraphicsEnvironment. This loads the configuration if + * there is one present and initializes the XGraphicsDevices in the + * environment. If there is no configuration, then there is one + * default device initialized with the local main X device. + */ + XGraphicsEnvironment() + { + // Initiliaze the devices. + Properties props = new Properties(); + File config = new File(System.getProperty("user.home"), + ".xawt.properties"); + + try + { + FileInputStream configIn = new FileInputStream(config); + props.load(configIn); + int dev = 1; + ArrayList deviceList = new ArrayList(); + while (true) + { + String propName = "display." + dev; + String propValue = props.getProperty(propName); + if (propValue != null) + { + Display.Name displayName = new Display.Name(propValue); + XGraphicsDevice device = new XGraphicsDevice(displayName); + if (dev == 1) + defaultDevice = device; + deviceList.add(device); + dev++; + } + else + { + if (dev == 1) + { + defaultDevice = initDefaultDevice(); + deviceList.add(defaultDevice); + } + break; + } + } + devices = (XGraphicsDevice[]) deviceList.toArray + (new XGraphicsDevice[deviceList.size()]); + } + catch (FileNotFoundException ex) + { + defaultDevice = initDefaultDevice(); + devices = new XGraphicsDevice[]{ defaultDevice }; + } + catch (IOException ex) + { + defaultDevice = initDefaultDevice(); + devices = new XGraphicsDevice[]{ defaultDevice }; + } + + } + + /** + * Helper method that initializes the default device in the case when there + * is no configuration for the default. + */ + private XGraphicsDevice initDefaultDevice() + { + String display = System.getenv("DISPLAY"); + if (display == null) + display = ":0.0"; + Display.Name displayName = new Display.Name(display); + return new XGraphicsDevice(displayName); + } + + /** + * Returns all configured screen devices. + * + * @return all configured screen devices + */ + public GraphicsDevice[] getScreenDevices() + { + // We return a copy so that nobody can fiddle with our devices. + XGraphicsDevice[] copy = new XGraphicsDevice[devices.length]; + System.arraycopy(devices, 0, copy, 0, devices.length); + return copy; + } + + /** + * Returns the default screen device. + * + * @return the default screen device + */ + public GraphicsDevice getDefaultScreenDevice() + { + return defaultDevice; + } + + /** + * Returns a Graphics instance suitable for drawing on top of the + * BufferedImage. + * + * @param image the buffered image to create a graphics for + * + * @return a Graphics2D instance for drawing on the BufferedImage + */ + public Graphics2D createGraphics(BufferedImage image) + { + return new RasterGraphics(image.getRaster(), image.getColorModel()); + } + + public Font[] getAllFonts() + { + // TODO: Implement this. + throw new UnsupportedOperationException("Not yet implemented."); + } + + public String[] getAvailableFontFamilyNames() + { + // TODO: Implement this. + throw new UnsupportedOperationException("Not yet implemented."); + } + + public String[] getAvailableFontFamilyNames(Locale l) + { + // TODO: Implement this. + throw new UnsupportedOperationException("Not yet implemented."); + } + +} diff --git a/gnu/java/awt/peer/x/XImage.java b/gnu/java/awt/peer/x/XImage.java new file mode 100644 index 000000000..28bc6b90a --- /dev/null +++ b/gnu/java/awt/peer/x/XImage.java @@ -0,0 +1,107 @@ +/* XImage.java -- Image impl for X Pixmaps + 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.x; + +import gnu.x11.Pixmap; + +import java.awt.Graphics; +import java.awt.GraphicsEnvironment; +import java.awt.Image; +import java.awt.Toolkit; +import java.awt.image.ImageObserver; +import java.awt.image.ImageProducer; + +public class XImage + extends Image +{ + + Pixmap pixmap; + + XImage(int w, int h) + { + XToolkit tk = (XToolkit) Toolkit.getDefaultToolkit(); + GraphicsEnvironment env = tk.getLocalGraphicsEnvironment(); + XGraphicsDevice dev = (XGraphicsDevice) env.getDefaultScreenDevice(); + pixmap = new Pixmap(dev.getDisplay(), w, h); + } + + public int getWidth(ImageObserver observer) + { + return pixmap.width; + } + + public int getHeight(ImageObserver observer) + { + return pixmap.height; + } + + public ImageProducer getSource() + { + // TODO: Implement this. + throw new UnsupportedOperationException("Not yet implemented."); + } + + /** + * Creates an XGraphics for drawing on this XImage. + * + * @return an XGraphics for drawing on this XImage + */ + public Graphics getGraphics() + { + XGraphics g = new XGraphics(pixmap); + return g; + } + + public Object getProperty(String name, ImageObserver observer) + { + // TODO: Implement this. + throw new UnsupportedOperationException("Not yet implemented."); + } + + public void flush() + { + // TODO: Implement this. + throw new UnsupportedOperationException("Not yet implemented."); + } + + protected void finalize() + { + pixmap.free(); + } +} diff --git a/gnu/java/awt/peer/gtk/GtkCheckboxGroupPeer.java b/gnu/java/awt/peer/x/XLightweightPeer.java index 46b0733d3..2613d84d8 100644 --- a/gnu/java/awt/peer/gtk/GtkCheckboxGroupPeer.java +++ b/gnu/java/awt/peer/x/XLightweightPeer.java @@ -1,5 +1,5 @@ -/* GtkCheckboxGroupPeer.java - Wrap a CheckboxGroup - Copyright (C) 2002 Free Software Foundation, Inc. +/* XLightweightPeer.java -- A lightweight peer for X + Copyright (C) 2006 Free Software Foundation, Inc. This file is part of GNU Classpath. @@ -36,51 +36,21 @@ 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; +package gnu.java.awt.peer.x; -import java.awt.CheckboxGroup; -import java.util.WeakHashMap; +import java.awt.Component; +import java.awt.peer.LightweightPeer; -// Note that there is no peer interface for a CheckboxGroup. We -// introduce our own in order to make it easier to keep a piece of -// native state for each one. -public class GtkCheckboxGroupPeer extends GtkGenericPeer -{ - // This maps from a CheckboxGroup to the native peer. - private static WeakHashMap map = new WeakHashMap (); +import gnu.java.awt.peer.swing.SwingContainerPeer; - // Find the native peer corresponding to a CheckboxGroup. - public static synchronized GtkCheckboxGroupPeer - getCheckboxGroupPeer (CheckboxGroup group) - { - if (group == null) - return null; - GtkCheckboxGroupPeer nat = (GtkCheckboxGroupPeer) map.get (group); - if (nat == null) - { - nat = new GtkCheckboxGroupPeer (); - map.put (group, nat); - } - return nat; - } - - private GtkCheckboxGroupPeer () - { - // We don't need any special state here. Note that we can't store - // a reference to the java-side CheckboxGroup. That would mean - // they could never be collected. - super (null); - } - - // Dispose of our native resources. - public native void dispose (); - - // Remove a given checkbox from this group. - public native void remove (GtkCheckboxPeer box); +public class XLightweightPeer + extends SwingContainerPeer + implements LightweightPeer +{ - // When collected, clean up the native state. - protected void finalize () + XLightweightPeer(Component c) { - dispose (); + super(c); + init(c, null); } } diff --git a/gnu/java/awt/peer/x/XToolkit.java b/gnu/java/awt/peer/x/XToolkit.java new file mode 100644 index 000000000..05e8a5963 --- /dev/null +++ b/gnu/java/awt/peer/x/XToolkit.java @@ -0,0 +1,575 @@ +/* XToolkit.java -- The central AWT Toolkit for the X peers + 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.x; + +import java.awt.AWTException; +import java.awt.Button; +import java.awt.Canvas; +import java.awt.Checkbox; +import java.awt.CheckboxMenuItem; +import java.awt.Choice; +import java.awt.Component; +import java.awt.Dialog; +import java.awt.Dimension; +import java.awt.EventQueue; +import java.awt.FileDialog; +import java.awt.Font; +import java.awt.FontMetrics; +import java.awt.Frame; +import java.awt.GraphicsDevice; +import java.awt.GraphicsEnvironment; +import java.awt.Image; +import java.awt.Label; +import java.awt.List; +import java.awt.Menu; +import java.awt.MenuBar; +import java.awt.MenuItem; +import java.awt.Panel; +import java.awt.PopupMenu; +import java.awt.PrintJob; +import java.awt.ScrollPane; +import java.awt.Scrollbar; +import java.awt.TextArea; +import java.awt.TextField; +import java.awt.Window; +import java.awt.datatransfer.Clipboard; +import java.awt.dnd.DragGestureEvent; +import java.awt.dnd.peer.DragSourceContextPeer; +import java.awt.font.FontRenderContext; +import java.awt.im.InputMethodHighlight; +import java.awt.image.BufferedImage; +import java.awt.image.ColorModel; +import java.awt.image.DirectColorModel; +import java.awt.image.ImageObserver; +import java.awt.image.ImageProducer; +import java.awt.peer.ButtonPeer; +import java.awt.peer.CanvasPeer; +import java.awt.peer.CheckboxMenuItemPeer; +import java.awt.peer.CheckboxPeer; +import java.awt.peer.ChoicePeer; +import java.awt.peer.DialogPeer; +import java.awt.peer.FileDialogPeer; +import java.awt.peer.FontPeer; +import java.awt.peer.FramePeer; +import java.awt.peer.LabelPeer; +import java.awt.peer.LightweightPeer; +import java.awt.peer.ListPeer; +import java.awt.peer.MenuBarPeer; +import java.awt.peer.MenuItemPeer; +import java.awt.peer.MenuPeer; +import java.awt.peer.PanelPeer; +import java.awt.peer.PopupMenuPeer; +import java.awt.peer.RobotPeer; +import java.awt.peer.ScrollPanePeer; +import java.awt.peer.ScrollbarPeer; +import java.awt.peer.TextAreaPeer; +import java.awt.peer.TextFieldPeer; +import java.awt.peer.WindowPeer; +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.net.MalformedURLException; +import java.net.URL; +import java.text.AttributedString; +import java.util.HashMap; +import java.util.Map; +import java.util.Properties; +import java.util.WeakHashMap; + +import javax.imageio.ImageIO; + +import gnu.java.awt.ClasspathToolkit; +import gnu.java.awt.EmbeddedWindow; +import gnu.java.awt.peer.ClasspathFontPeer; +import gnu.java.awt.peer.EmbeddedWindowPeer; +import gnu.java.awt.peer.swing.SwingCanvasPeer; +import gnu.java.awt.peer.swing.SwingLabelPeer; +import gnu.java.awt.peer.swing.SwingPanelPeer; + +public class XToolkit + extends ClasspathToolkit +{ + + /** + * Set to true to enable debug output. + */ + static boolean DEBUG = false; + + private XGraphicsEnvironment env; + + /** + * The system event queue. + */ + private EventQueue eventQueue; + + /** + * The default color model of this toolkit. + */ + private ColorModel colorModel; + + /** + * Maps image URLs to Image instances. + */ + private HashMap imageCache = new HashMap(); + + /** + * The cached fonts. + */ + private WeakHashMap fontCache = new WeakHashMap(); + + public XToolkit() + { + System.setProperty("gnu.javax.swing.noGraphics2D", "true"); + } + + public GraphicsEnvironment getLocalGraphicsEnvironment() + { + if (env == null) + env = new XGraphicsEnvironment(); + return env; + } + + /** + * Returns the font peer for a font with the specified name and attributes. + * + * @param name the font name + * @param attrs the font attributes + * + * @return the font peer for a font with the specified name and attributes + */ + public ClasspathFontPeer getClasspathFontPeer(String name, Map attrs) + { + String canonical = XFontPeer.encodeFont(name, attrs); + XFontPeer font; + if (!fontCache.containsKey(canonical)) + { + font = new XFontPeer(name, attrs); + fontCache.put(canonical, font); + } + else + { + font = (XFontPeer) fontCache.get(canonical); + } + return font; + } + + public Font createFont(int format, InputStream stream) + { + return null; + } + + public RobotPeer createRobot(GraphicsDevice screen) throws AWTException + { + // TODO: Implement this. + throw new UnsupportedOperationException("Not yet implemented."); + } + + public EmbeddedWindowPeer createEmbeddedWindow(EmbeddedWindow w) + { + // TODO: Implement this. + throw new UnsupportedOperationException("Not yet implemented."); + } + + protected ButtonPeer createButton(Button target) + { + // TODO: Implement this. + throw new UnsupportedOperationException("Not yet implemented."); + } + + protected TextFieldPeer createTextField(TextField target) + { + // TODO: Implement this. + throw new UnsupportedOperationException("Not yet implemented."); + } + + protected LabelPeer createLabel(Label target) + { + return new SwingLabelPeer(target); + } + + protected ListPeer createList(List target) + { + // TODO: Implement this. + throw new UnsupportedOperationException("Not yet implemented."); + } + + protected CheckboxPeer createCheckbox(Checkbox target) + { + // TODO: Implement this. + throw new UnsupportedOperationException("Not yet implemented."); + } + + protected ScrollbarPeer createScrollbar(Scrollbar target) + { + // TODO: Implement this. + throw new UnsupportedOperationException("Not yet implemented."); + } + + protected ScrollPanePeer createScrollPane(ScrollPane target) + { + // TODO: Implement this. + throw new UnsupportedOperationException("Not yet implemented."); + } + + protected TextAreaPeer createTextArea(TextArea target) + { + // TODO: Implement this. + throw new UnsupportedOperationException("Not yet implemented."); + } + + protected ChoicePeer createChoice(Choice target) + { + // TODO: Implement this. + throw new UnsupportedOperationException("Not yet implemented."); + } + + protected FramePeer createFrame(Frame target) + { + XFramePeer frame = new XFramePeer(target); + return frame; + } + + protected CanvasPeer createCanvas(Canvas target) + { + return new SwingCanvasPeer(target); + } + + protected PanelPeer createPanel(Panel target) + { + return new SwingPanelPeer(target); + } + + protected WindowPeer createWindow(Window target) + { + return new XWindowPeer(target); + } + + protected DialogPeer createDialog(Dialog target) + { + // TODO: Implement this. + throw new UnsupportedOperationException("Not yet implemented."); + } + + protected MenuBarPeer createMenuBar(MenuBar target) + { + // TODO: Implement this. + throw new UnsupportedOperationException("Not yet implemented."); + } + + protected MenuPeer createMenu(Menu target) + { + // TODO: Implement this. + throw new UnsupportedOperationException("Not yet implemented."); + } + + protected PopupMenuPeer createPopupMenu(PopupMenu target) + { + // TODO: Implement this. + throw new UnsupportedOperationException("Not yet implemented."); + } + + protected MenuItemPeer createMenuItem(MenuItem target) + { + // TODO: Implement this. + throw new UnsupportedOperationException("Not yet implemented."); + } + + protected FileDialogPeer createFileDialog(FileDialog target) + { + // TODO: Implement this. + throw new UnsupportedOperationException("Not yet implemented."); + } + + protected CheckboxMenuItemPeer createCheckboxMenuItem(CheckboxMenuItem target) + { + // TODO: Implement this. + throw new UnsupportedOperationException("Not yet implemented."); + } + + protected FontPeer getFontPeer(String name, int style) + { + // TODO: Implement this. + throw new UnsupportedOperationException("Not yet implemented."); + } + + public Dimension getScreenSize() + { + // FIXME: This is only a hack to get some apps working. + return new Dimension(1024, 768); + } + + public int getScreenResolution() + { + // TODO: Implement this. + throw new UnsupportedOperationException("Not yet implemented."); + } + + /** + * Returns the color model used by this toolkit. + * + * @return the color model used by this toolkit + */ + public ColorModel getColorModel() + { + // TODO: I assume 24 bit depth here, we can do this better. + if (colorModel == null) + colorModel = new DirectColorModel(24, 0xFF0000, 0xFF00, 0xFF); + return colorModel; + } + + public String[] getFontList() + { + // TODO: Implement this. + throw new UnsupportedOperationException("Not yet implemented."); + } + + public FontMetrics getFontMetrics(Font name) + { + XFontPeer peer = (XFontPeer) name.getPeer(); + return peer.getFontMetrics(name); + } + + public void sync() + { + // TODO: Implement this. + throw new UnsupportedOperationException("Not yet implemented."); + } + + /** + * Returns an image that has its pixel data loaded from a file with the + * specified name. If that file doesn't exist, an empty or error image + * is returned instead. + * + * @param name the filename of the file that contains the pixel data + * + * @return the image + */ + public Image getImage(String name) + { + Image image; + try + { + File file = new File(name); + image = getImage(file.toURL()); + } + catch (MalformedURLException ex) + { + // TODO: Replace by a more meaningful error image instead. + image = null; + } + return image; + } + + /** + * Returns an image that has its pixel data loaded from the specified URL. + * If the image cannot be loaded for some reason, an empty or error image + * is returned instead. + * + * @param url the URL to the image data + * + * @return the image + */ + public Image getImage(URL url) + { + Image image; + if (imageCache.containsKey(url)) + { + image = (Image) imageCache.get(url); + } + else + { + image = createImage(url); + imageCache.put(url, image); + } + return image; + } + + /** + * Returns an image that has its pixel data loaded from a file with the + * specified name. If that file doesn't exist, an empty or error image + * is returned instead. + * + * @param filename the filename of the file that contains the pixel data + * + * @return the image + */ + public Image createImage(String filename) + { + Image im; + try + { + File file = new File(filename); + URL url = file.toURL(); + im = createImage(url); + } + catch (MalformedURLException ex) + { + im = createErrorImage(); + } + return im; + } + + /** + * Returns an image that has its pixel data loaded from the specified URL. + * If the image cannot be loaded for some reason, an empty or error image + * is returned instead. + * + * @param url the URL to the image data + * + * @return the image + */ + public Image createImage(URL url) + { + Image image; + try + { + BufferedImage buffered = ImageIO.read(url); + if (buffered != null) + { + ImageConverter conv = new ImageConverter(); + ImageProducer source = buffered.getSource(); + source.startProduction(conv); + return conv.getXImage(); + } + else return createErrorImage(); + + } + catch (IOException ex) + { + image = createErrorImage(); + } + return image; + } + + /** + * Creates an image that is returned when calls to createImage() yields an + * error. + * + * @return an image that is returned when calls to createImage() yields an + * error + */ + private Image createErrorImage() + { + // TODO: Create better error image. + return new XImage(1, 1); + } + + public boolean prepareImage(Image image, int width, int height, ImageObserver observer) + { + // Images are loaded synchronously, so we don't bother and return true. + return true; + } + + public int checkImage(Image image, int width, int height, ImageObserver observer) + { + // TODO: Implement this. + throw new UnsupportedOperationException("Not yet implemented."); + } + + public Image createImage(ImageProducer producer) + { + // TODO: Implement this. + throw new UnsupportedOperationException("Not yet implemented."); + } + + public Image createImage(byte[] data, int offset, int len) + { + // TODO: Implement this. + throw new UnsupportedOperationException("Not yet implemented."); + } + + public PrintJob getPrintJob(Frame frame, String title, Properties props) + { + // TODO: Implement this. + throw new UnsupportedOperationException("Not yet implemented."); + } + + public void beep() + { + // TODO: Implement this. + throw new UnsupportedOperationException("Not yet implemented."); + } + + public Clipboard getSystemClipboard() + { + // TODO: Implement this. + throw new UnsupportedOperationException("Not yet implemented."); + } + + /** + * Returns the eventqueue used by the XLib peers. + * + * @return the eventqueue used by the XLib peers + */ + protected EventQueue getSystemEventQueueImpl() + { + if (eventQueue == null) + eventQueue = new EventQueue(); + return eventQueue; + } + + public DragSourceContextPeer createDragSourceContextPeer(DragGestureEvent e) + { + // TODO: Implement this. + throw new UnsupportedOperationException("Not yet implemented."); + } + + public Map mapInputMethodHighlight(InputMethodHighlight highlight) + { + // TODO: Implement this. + throw new UnsupportedOperationException("Not yet implemented."); + } + + /** + * Helper method to quickly fetch the default device (X Display). + * + * @return the default XGraphicsDevice + */ + static XGraphicsDevice getDefaultDevice() + { + XGraphicsEnvironment env = (XGraphicsEnvironment) + XGraphicsEnvironment.getLocalGraphicsEnvironment(); + return (XGraphicsDevice) env.getDefaultScreenDevice(); + } + + protected LightweightPeer createComponent(Component c) + { + return new XLightweightPeer(c); + } +} diff --git a/gnu/java/awt/peer/x/XWindowPeer.java b/gnu/java/awt/peer/x/XWindowPeer.java new file mode 100644 index 000000000..f4815ce7f --- /dev/null +++ b/gnu/java/awt/peer/x/XWindowPeer.java @@ -0,0 +1,256 @@ +/* XWindowPeer.java -- Window peer for X + 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.x; + +import java.awt.Component; +import java.awt.EventQueue; +import java.awt.Font; +import java.awt.FontMetrics; +import java.awt.Graphics; +import java.awt.Image; +import java.awt.Insets; +import java.awt.Point; +import java.awt.Rectangle; +import java.awt.event.PaintEvent; +import java.awt.event.WindowEvent; + +import gnu.x11.Window; +import gnu.x11.event.Event; + +import gnu.java.awt.peer.swing.SwingWindowPeer; + +public class XWindowPeer + extends SwingWindowPeer +{ + + private static int standardSelect = Event.BUTTON_PRESS_MASK + | Event.BUTTON_RELEASE_MASK + | Event.POINTER_MOTION_MASK + //| Event.RESIZE_REDIRECT_MASK + | Event.EXPOSURE_MASK + //| Event.PROPERTY_CHANGE_MASK + | Event.STRUCTURE_NOTIFY_MASK + | Event.KEY_PRESS_MASK + | Event.KEY_RELEASE_MASK + ; + + /** + * Indicates if we are in callback mode, that is when a property (like size) + * is changed in reponse to a request from the X server and doesn't need + * to be propagated back to the X server. + */ + boolean callback = false; + + /** + * The X window. + */ + private Window xwindow; + + XWindowPeer(java.awt.Window window) + { + super(window); + System.err.println("new XWindowPeer"); + XGraphicsDevice dev = XToolkit.getDefaultDevice(); + + // TODO: Maybe initialize lazily in show(). + // FIXME: Howto generate a Window without decorations? + int x = Math.max(window.getX(), 0); + int y = Math.max(window.getY(), 0); + int w = Math.max(window.getWidth(), 1); + int h = Math.max(window.getHeight(), 1); + xwindow = new Window(dev.getDisplay().default_root, x, y, w, h); + xwindow.create(); + xwindow.select_input(standardSelect); + dev.getEventPump().registerWindow(xwindow, window); + } + + public void toBack() + { + // TODO Auto-generated method stub + + } + + public void toFront() + { + // TODO Auto-generated method stub + + } + + public void updateAlwaysOnTop() + { + // TODO Auto-generated method stub + + } + + public boolean requestWindowFocus() + { + // TODO Auto-generated method stub + return false; + } + + public Point getLocationOnScreen() + { + return new Point(xwindow.x, xwindow.y); + } + + /** + * Returns a XGraphics suitable for drawing on this frame. + * + * @return a XGraphics suitable for drawing on this frame + */ + public Graphics getGraphics() + { + return new XGraphics(xwindow); + } + + public Image createImage(int w, int h) + { + return new XImage(w, h); + } + + /** + * Makes the component visible. This is called by {@link Component#show()}. + * + * This is implemented to call setVisible(true) on the Swing component. + */ + public void show() + { +// // Prevent ResizeRedirect events. +// //xwindow.select_input(noResizeRedirectSelect); +// Window.Attributes atts = new Window.Attributes(); +// atts.set_override_redirect(true); +// xwindow.change_attributes(atts); + + // Prevent ResizeRedirect events. + //xwindow.select_input(Event.NO_EVENT_MASK); + //xwindow.select_input(noResizeRedirectSelect); + + xwindow.map(); + EventQueue eq = XToolkit.getDefaultToolkit().getSystemEventQueue(); + java.awt.Window w = (java.awt.Window) super.awtComponent; + eq.postEvent(new WindowEvent(w, WindowEvent.WINDOW_OPENED)); + eq.postEvent(new PaintEvent(w, PaintEvent.PAINT, + new Rectangle(0, 0, w.getWidth(), + w.getHeight()))); + +// // Reset input selection. +// atts.set_override_redirect(false); +// xwindow.change_attributes(atts); + } + + /** + * Makes the component invisible. This is called from + * {@link Component#hide()}. + * + * This is implemented to call setVisible(false) on the Swing component. + */ + public void hide() + { + xwindow.unmap(); + } + + /** + * Notifies the peer that the bounds of this component have changed. This + * is called by {@link Component#reshape(int, int, int, int)}. + * + * This is implemented to call setBounds() on the Swing component. + * + * @param x the X coordinate of the upper left corner of the component + * @param y the Y coordinate of the upper left corner of the component + * @param width the width of the component + * @param height the height of the component + */ + public void reshape(int x, int y, int width, int height) + { + // Prevent ResizeRedirect events. +// //xwindow.select_input(noResizeRedirectSelect); +// Window.Attributes atts = new Window.Attributes(); +// atts.set_override_redirect(true); +// xwindow.change_attributes(atts); + + // Need to substract insets because AWT size is including insets, + // and X size is excuding insets. + Insets i = insets(); + xwindow.move_resize(x - i.left, y - i.right, width - i.left - i.right, + height - i.top - i.bottom); + + // Reset input selection. +// atts = new Window.Attributes(); +// atts.set_override_redirect(false); +// xwindow.change_attributes(atts); + } + + public Insets insets() + { + Insets i = new Insets(0, 0, 0, 0); +// Window.GeometryReply g = xwindow.geometry(); +// int b = g.border_width(); +// Insets i = new Insets(b, b, b, b); +// Window.WMSizeHints wmSize = xwindow.wm_normal_hints(); +// if (wmSize != null) +// { +// i.left = wmSize.x() - g.x(); +// i.right = wmSize.width() - g.width() - i.left ; +// i.top = wmSize.y() - g.y(); +// i.bottom = wmSize.height() - g.height() - i.top; +// } +// System.err.println("insets: " + i); + return i; + } + + /** + * Returns the font metrics for the specified font. + * + * @return the font metrics for the specified font + */ + public FontMetrics getFontMetrics(Font font) + { + XFontPeer fontPeer = (XFontPeer) font.getPeer(); + return fontPeer.getFontMetrics(font); + } + + /** + * Unregisters the window in the event pump when it is closed. + */ + protected void finalize() + { + XGraphicsDevice dev = XToolkit.getDefaultDevice(); + dev.getEventPump().unregisterWindow(xwindow); + } +} diff --git a/gnu/java/awt/peer/x/fonts.properties b/gnu/java/awt/peer/x/fonts.properties new file mode 100644 index 000000000..2c8755ceb --- /dev/null +++ b/gnu/java/awt/peer/x/fonts.properties @@ -0,0 +1,25 @@ + +serif.plain=-adobe-times-medium-r-normal--%d-*-*-*-p-*-iso8859-1 +serif.bold=-adobe-times-bold-r-normal--%d-*-*-*-p-*-iso8859-1 +serif.italic=-adobe-times-medium-o-normal--%d-*-*-*-p-*-iso8859-1 +serif.bolditalic=-adobe-times-bold-o-normal--%d-*-*-*-p-*-iso8859-1 + +sansserif.plain=-adobe-helvetica-medium-r-normal--%d-*-*-*-p-*-iso8859-1 +sansserif.bold=-adobe-helvetica-bold-r-normal--%d-*-*-*-p-*-iso8859-1 +sansserif.italic=-adobe-helvetica-medium-o-normal--%d-*-*-*-p-*-iso8859-1 +sansserif.bolditalic=-adobe-helvetica-bold-o-normal--%d-*-*-*-p-*-iso8859-1 + +monospaced.plain=-adobe-courier-medium-r-normal--%d-*-*-*-p-*-iso8859-1 +monospaced.bold=-adobe-courier-bold-r-normal--%d-*-*-*-p-*-iso8859-1 +monospaced.italic=-adobe-courier-medium-o-normal--%d-*-*-*-p-*-iso8859-1 +monospaced.bolditalic=-adobe-courier-bold-o-normal--%d-*-*-*-p-*-iso8859-1 + +dialog.plain=-adobe-helvetica-medium-r-normal--%d-*-*-*-p-*-iso8859-1 +dialog.bold=-adobe-helvetica-bold-r-normal--%d-*-*-*-p-*-iso8859-1 +dialog.italic=-adobe-helvetica-medium-o-normal--%d-*-*-*-p-*-iso8859-1 +dialog.bolditalic=-adobe-helvetica-bold-o-normal--%d-*-*-*-p-*-iso8859-1 + +dialoginput.plain=-adobe-helvetica-medium-r-normal--%d-*-*-*-p-*-iso8859-1 +dialoginput.bold=-adobe-helvetica-bold-r-normal--%d-*-*-*-p-*-iso8859-1 +dialoginput.italic=-adobe-helvetica-medium-o-normal--%d-*-*-*-p-*-iso8859-1 +dialoginput.bolditalic=-adobe-helvetica-bold-o-normal--%d-*-*-*-p-*-iso8859-1 |