summaryrefslogtreecommitdiff
path: root/gnu/java
diff options
context:
space:
mode:
Diffstat (limited to 'gnu/java')
-rw-r--r--gnu/java/awt/ComponentReshapeEvent.java85
-rw-r--r--gnu/java/awt/peer/NativeEventLoopRunningEvent.java58
-rw-r--r--gnu/java/awt/peer/gtk/BufferedImageGraphics.java246
-rw-r--r--gnu/java/awt/peer/gtk/CairoGraphics2D.java97
-rw-r--r--gnu/java/awt/peer/gtk/CairoSurface.java30
-rw-r--r--gnu/java/awt/peer/gtk/CairoSurfaceGraphics.java216
-rw-r--r--gnu/java/awt/peer/gtk/FreetypeGlyphVector.java20
-rw-r--r--gnu/java/awt/peer/gtk/GtkFramePeer.java22
-rw-r--r--gnu/java/awt/peer/gtk/GtkMainThread.java113
-rw-r--r--gnu/java/awt/peer/gtk/GtkToolkit.java8
-rw-r--r--gnu/java/awt/peer/gtk/GtkVolatileImage.java45
-rw-r--r--gnu/java/awt/peer/gtk/GtkWindowPeer.java69
-rw-r--r--gnu/java/awt/peer/gtk/VolatileImageGraphics.java13
-rw-r--r--gnu/java/lang/InstrumentationImpl.java4
-rw-r--r--gnu/java/net/PlainDatagramSocketImpl.java57
-rw-r--r--gnu/java/net/PlainSocketImpl.java55
-rw-r--r--gnu/java/nio/KqueueSelectorImpl.java27
17 files changed, 985 insertions, 180 deletions
diff --git a/gnu/java/awt/ComponentReshapeEvent.java b/gnu/java/awt/ComponentReshapeEvent.java
new file mode 100644
index 000000000..8f15c8519
--- /dev/null
+++ b/gnu/java/awt/ComponentReshapeEvent.java
@@ -0,0 +1,85 @@
+/* WindowResizeEvent.java -- Used to synchronize the AWT and peer sizes
+ 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;
+
+import java.awt.AWTEvent;
+import java.awt.Component;
+
+/**
+ * This is used to update the AWT's knowledge about a Window's size when
+ * the user changes the window bounds.
+ *
+ * This event is _not_ posted to the eventqueue, but rather dispatched directly
+ * via Window.dispatchEvent(). It is the cleanest way we could find to update
+ * the AWT's knowledge of the window size. Small testprograms showed the
+ * following:
+ * - Component.reshape() and its derivatives are _not_ called. This makes sense
+ * as it could end up in loops,because this calls back into the peers.
+ * - Intercepting event dispatching for any events in
+ * EventQueue.dispatchEvent() showed that the size is still updated. So it
+ * is not done via an event dispatched over the eventqueue.
+ *
+ * Possible other candidates for implementation would have been:
+ * - Call a (private) callback method in Window/Component from the native
+ * side.
+ * - Call a (private) callback method in Window/Component via reflection.
+ *
+ * Both is uglier than sending this event directly. Note however that this
+ * is impossible to test, as Component.dispatchEvent() is final and can't be
+ * intercepted from outside code. But this impossibility to test the issue from
+ * outside code also means that this shouldn't raise any compatibility issues.
+ */
+public class ComponentReshapeEvent
+ extends AWTEvent
+{
+
+ public int x;
+ public int y;
+ public int width;
+ public int height;
+
+ public ComponentReshapeEvent(Component c, int x, int y, int width, int height)
+ {
+ super(c, 1999);
+ this.x = x;
+ this.y = y;
+ this.width = width;
+ this.height = height;
+ }
+}
diff --git a/gnu/java/awt/peer/NativeEventLoopRunningEvent.java b/gnu/java/awt/peer/NativeEventLoopRunningEvent.java
new file mode 100644
index 000000000..962ecd990
--- /dev/null
+++ b/gnu/java/awt/peer/NativeEventLoopRunningEvent.java
@@ -0,0 +1,58 @@
+/* NativeEventLoopRunningEvent.java -- communicates to EventQueue the
+ state of the native event loop
+ 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;
+
+import java.awt.AWTEvent;
+
+public class NativeEventLoopRunningEvent
+ extends AWTEvent
+{
+ private boolean running;
+
+ public NativeEventLoopRunningEvent(Object source)
+ {
+ super(source, 2999);
+ running = ((Boolean) source).booleanValue();
+ }
+
+ public boolean isRunning()
+ {
+ return running;
+ }
+}
diff --git a/gnu/java/awt/peer/gtk/BufferedImageGraphics.java b/gnu/java/awt/peer/gtk/BufferedImageGraphics.java
index e188d3fd0..341fa2a4e 100644
--- a/gnu/java/awt/peer/gtk/BufferedImageGraphics.java
+++ b/gnu/java/awt/peer/gtk/BufferedImageGraphics.java
@@ -38,23 +38,27 @@ exception statement from your version. */
package gnu.java.awt.peer.gtk;
+import java.awt.AlphaComposite;
import java.awt.Color;
import java.awt.Graphics;
+import java.awt.Graphics2D;
import java.awt.GraphicsConfiguration;
import java.awt.Image;
import java.awt.Rectangle;
import java.awt.Shape;
+import java.awt.Toolkit;
import java.awt.font.GlyphVector;
import java.awt.geom.AffineTransform;
+import java.awt.geom.Point2D;
import java.awt.geom.Rectangle2D;
import java.awt.image.BufferedImage;
-import java.awt.image.Raster;
-import java.awt.image.DataBuffer;
-import java.awt.image.DataBufferInt;
import java.awt.image.ColorModel;
+import java.awt.image.DataBufferInt;
import java.awt.image.DirectColorModel;
-import java.awt.image.RenderedImage;
import java.awt.image.ImageObserver;
+import java.awt.image.ImageProducer;
+import java.awt.image.Raster;
+import java.awt.image.RenderedImage;
import java.util.WeakHashMap;
/**
@@ -68,7 +72,13 @@ public class BufferedImageGraphics extends CairoGraphics2D
/**
* the buffered Image.
*/
- private BufferedImage image;
+ private BufferedImage image, buffer;
+
+ /**
+ * Allows us to lock the image from updates (if we want to perform a few
+ * intermediary operations on the cairo surface, then update it all at once)
+ */
+ private boolean locked;
/**
* Image size.
@@ -93,7 +103,7 @@ public class BufferedImageGraphics extends CairoGraphics2D
/**
* Colormodels we recognize for fast copying.
*/
- static ColorModel rgb32 = new DirectColorModel(32, 0xFF0000, 0xFF00, 0xFF);
+ static ColorModel rgb32 = new DirectColorModel(24, 0xFF0000, 0xFF00, 0xFF);
static ColorModel argb32 = new DirectColorModel(32, 0xFF0000, 0xFF00, 0xFF,
0xFF000000);
private boolean hasFastCM;
@@ -105,6 +115,8 @@ public class BufferedImageGraphics extends CairoGraphics2D
this.image = bi;
imageWidth = bi.getWidth();
imageHeight = bi.getHeight();
+ locked = false;
+
if(bi.getColorModel().equals(rgb32))
{
hasFastCM = true;
@@ -113,7 +125,7 @@ public class BufferedImageGraphics extends CairoGraphics2D
else if(bi.getColorModel().equals(argb32))
{
hasFastCM = true;
- hasAlpha = false;
+ hasAlpha = true;
}
else
hasFastCM = false;
@@ -163,6 +175,7 @@ public class BufferedImageGraphics extends CairoGraphics2D
cairo_t = surface.newCairoContext();
imageWidth = copyFrom.imageWidth;
imageHeight = copyFrom.imageHeight;
+ locked = false;
copy( copyFrom, cairo_t );
setClip(0, 0, surface.width, surface.height);
}
@@ -172,6 +185,9 @@ public class BufferedImageGraphics extends CairoGraphics2D
*/
private void updateBufferedImage(int x, int y, int width, int height)
{
+ if (locked)
+ return;
+
int[] pixels = surface.getPixels(imageWidth * imageHeight);
if( x > imageWidth || y > imageHeight )
@@ -184,18 +200,18 @@ public class BufferedImageGraphics extends CairoGraphics2D
if( y + height > imageHeight )
height = imageHeight - y;
- boolean wasPremultiplied = image.isAlphaPremultiplied();
- image.coerceData(true);
-
- if( !hasFastCM )
+ // The setRGB method assumes (or should assume) that pixels are NOT
+ // alpha-premultiplied, but Cairo stores data with premultiplication
+ // (thus the pixels returned in getPixels are premultiplied).
+ // This is ignored for consistency, however, since in
+ // CairoGrahpics2D.drawImage we also use non-premultiplied data
+ if(!hasFastCM)
image.setRGB(x, y, width, height, pixels,
x + y * imageWidth, imageWidth);
else
System.arraycopy(pixels, y * imageWidth,
((DataBufferInt)image.getRaster().getDataBuffer()).
getData(), y * imageWidth, height * imageWidth);
-
- image.coerceData(wasPremultiplied);
}
/**
@@ -228,36 +244,214 @@ public class BufferedImageGraphics extends CairoGraphics2D
*/
public void draw(Shape s)
{
- super.draw(s);
- Rectangle r = s.getBounds();
- updateBufferedImage(r.x, r.y, r.width, r.height);
+ if (comp == null || comp instanceof AlphaComposite)
+ {
+ super.draw(s);
+ Rectangle r = s.getBounds();
+
+ if (shiftDrawCalls)
+ updateBufferedImage(r.x, r.y, r.width+1, r.height+1);
+ else
+ updateBufferedImage(r.x, r.y, r.width, r.height);
+ }
+ else
+ {
+ createBuffer();
+
+ Graphics2D g2d = (Graphics2D)buffer.getGraphics();
+ g2d.setStroke(this.getStroke());
+ g2d.setColor(this.getColor());
+ g2d.draw(s);
+
+ drawComposite(s.getBounds2D(), null);
+ }
}
public void fill(Shape s)
{
- super.fill(s);
- Rectangle r = s.getBounds();
- updateBufferedImage(r.x, r.y, r.width, r.height);
+ if (comp == null || comp instanceof AlphaComposite)
+ {
+ super.fill(s);
+ Rectangle r = s.getBounds();
+ updateBufferedImage(r.x, r.y, r.width, r.height);
+ }
+ else
+ {
+ createBuffer();
+
+ Graphics2D g2d = (Graphics2D)buffer.getGraphics();
+ g2d.setPaint(this.getPaint());
+ g2d.setColor(this.getColor());
+ g2d.fill(s);
+
+ drawComposite(s.getBounds2D(), null);
+ }
}
public void drawRenderedImage(RenderedImage image, AffineTransform xform)
{
- super.drawRenderedImage(image, xform);
- updateBufferedImage(0, 0, imageWidth, imageHeight);
+ if (comp == null || comp instanceof AlphaComposite)
+ {
+ super.drawRenderedImage(image, xform);
+ updateBufferedImage(0, 0, imageWidth, imageHeight);
+ }
+ else
+ {
+ createBuffer();
+
+ Graphics2D g2d = (Graphics2D)buffer.getGraphics();
+ g2d.setRenderingHints(this.getRenderingHints());
+ g2d.drawRenderedImage(image, xform);
+
+ drawComposite(buffer.getRaster().getBounds(), null);
+ }
+
}
protected boolean drawImage(Image img, AffineTransform xform,
Color bgcolor, ImageObserver obs)
{
- boolean rv = super.drawImage(img, xform, bgcolor, obs);
- updateBufferedImage(0, 0, imageWidth, imageHeight);
- return rv;
+ if (comp == null || comp instanceof AlphaComposite)
+ {
+ boolean rv = super.drawImage(img, xform, bgcolor, obs);
+ updateBufferedImage(0, 0, imageWidth, imageHeight);
+ return rv;
+ }
+ else
+ {
+ // Get buffered image of source
+ if( !(img instanceof BufferedImage) )
+ {
+ ImageProducer source = img.getSource();
+ if (source == null)
+ return false;
+ img = Toolkit.getDefaultToolkit().createImage(source);
+ }
+ BufferedImage bImg = (BufferedImage) img;
+
+ // Find translated bounds
+ Point2D origin = new Point2D.Double(bImg.getMinX(), bImg.getMinY());
+ Point2D pt = new Point2D.Double(bImg.getWidth() + bImg.getMinX(),
+ bImg.getHeight() + bImg.getMinY());
+ if (xform != null)
+ {
+ origin = xform.transform(origin, origin);
+ pt = xform.transform(pt, pt);
+ }
+
+ // Create buffer and draw image
+ createBuffer();
+
+ Graphics2D g2d = (Graphics2D)buffer.getGraphics();
+ g2d.setRenderingHints(this.getRenderingHints());
+ g2d.drawImage(img, xform, obs);
+
+ // Perform compositing
+ return drawComposite(new Rectangle2D.Double(origin.getX(),
+ origin.getY(),
+ pt.getX(), pt.getY()),
+ obs);
+ }
}
public void drawGlyphVector(GlyphVector gv, float x, float y)
{
- super.drawGlyphVector(gv, x, y);
- updateBufferedImage(0, 0, imageWidth, imageHeight);
+ if (comp == null || comp instanceof AlphaComposite)
+ {
+ super.drawGlyphVector(gv, x, y);
+ updateBufferedImage(0, 0, imageWidth, imageHeight);
+ }
+ else
+ {
+ createBuffer();
+
+ Graphics2D g2d = (Graphics2D)buffer.getGraphics();
+ g2d.setPaint(this.getPaint());
+ g2d.setStroke(this.getStroke());
+ g2d.drawGlyphVector(gv, x, y);
+
+ Rectangle2D bounds = gv.getLogicalBounds();
+ bounds = new Rectangle2D.Double(x + bounds.getX(), y + bounds.getY(),
+ bounds.getWidth(), bounds.getHeight());
+ drawComposite(bounds, null);
+ }
+ }
+
+ private boolean drawComposite(Rectangle2D bounds, ImageObserver observer)
+ {
+ // Clip source to visible areas that need updating
+ Rectangle2D clip = this.getClipBounds();
+ Rectangle2D.intersect(bounds, clip, bounds);
+ clip = new Rectangle(buffer.getMinX(), buffer.getMinY(),
+ buffer.getWidth(), buffer.getHeight());
+ Rectangle2D.intersect(bounds, clip, bounds);
+
+ BufferedImage buffer2 = buffer;
+ if (!bounds.equals(buffer2.getRaster().getBounds()))
+ buffer2 = buffer2.getSubimage((int)bounds.getX(), (int)bounds.getY(),
+ (int)bounds.getWidth(),
+ (int)bounds.getHeight());
+
+ // Get destination clip to bounds
+ double[] points = new double[] {bounds.getX(), bounds.getY(),
+ bounds.getMaxX(), bounds.getMaxY()};
+ transform.transform(points, 0, points, 0, 2);
+
+ Rectangle2D deviceBounds = new Rectangle2D.Double(points[0], points[1],
+ points[2] - points[0],
+ points[3] - points[1]);
+
+ Rectangle2D.intersect(deviceBounds, this.getClipInDevSpace(), deviceBounds);
+
+ BufferedImage current = image;
+ current = current.getSubimage((int)deviceBounds.getX(),
+ (int)deviceBounds.getY(),
+ (int)deviceBounds.getWidth(),
+ (int)deviceBounds.getHeight());
+
+ // Perform actual composite operation
+ compCtx.compose(buffer2.getRaster(), current.getRaster(),
+ current.getRaster());
+
+ // Prevent the clearRect in CairoGraphics2D.drawImage from clearing
+ // our composited image
+ locked = true;
+
+ // This MUST call directly into the "action" method in CairoGraphics2D,
+ // not one of the wrappers, to ensure that the composite isn't processed
+ // more than once!
+ boolean rv = super.drawImage(current,
+ AffineTransform.getTranslateInstance(bounds.getX(),
+ bounds.getY()),
+ new Color(0,0,0,0), null);
+ locked = false;
+ return rv;
+ }
+
+ private void createBuffer()
+ {
+ if (buffer == null)
+ {
+ buffer = new BufferedImage(image.getWidth(), image.getHeight(),
+ BufferedImage.TYPE_INT_ARGB);
+ }
+ else
+ {
+ Graphics2D g2d = ((Graphics2D)buffer.getGraphics());
+
+ g2d.setBackground(new Color(0,0,0,0));
+ g2d.clearRect(0, 0, buffer.getWidth(), buffer.getHeight());
+ }
+ }
+
+ protected ColorModel getNativeCM()
+ {
+ return image.getColorModel();
+ }
+
+ protected ColorModel getBufferCM()
+ {
+ return ColorModel.getRGBdefault();
}
}
diff --git a/gnu/java/awt/peer/gtk/CairoGraphics2D.java b/gnu/java/awt/peer/gtk/CairoGraphics2D.java
index fd69c9b48..4c60336a3 100644
--- a/gnu/java/awt/peer/gtk/CairoGraphics2D.java
+++ b/gnu/java/awt/peer/gtk/CairoGraphics2D.java
@@ -176,7 +176,7 @@ public abstract class CairoGraphics2D extends Graphics2D
* coords be shifted to land on 0.5-pixel boundaries, in order to land on
* "middle of pixel" coordinates and light up complete pixels.
*/
- private boolean shiftDrawCalls = false;
+ protected boolean shiftDrawCalls = false;
/**
* Keep track if the first clip to be set, which is restored on setClip(null);
@@ -220,7 +220,7 @@ public abstract class CairoGraphics2D extends Graphics2D
{
nativePointer = init(cairo_t_pointer);
setRenderingHints(new RenderingHints(getDefaultHints()));
- font = new Font("SansSerif", Font.PLAIN, 12);
+ setFont(new Font("SansSerif", Font.PLAIN, 12));
setColor(Color.black);
setBackground(Color.white);
setPaint(Color.black);
@@ -236,7 +236,6 @@ public abstract class CairoGraphics2D extends Graphics2D
nativePointer = init(cairo_t_pointer);
paint = g.paint;
stroke = g.stroke;
- comp = g.comp;
setRenderingHints(g.hints);
Color foreground;
@@ -263,8 +262,7 @@ public abstract class CairoGraphics2D extends Graphics2D
else
transform = new AffineTransform(g.transform);
- font = g.font;
-
+ setFont(g.font);
setColor(foreground);
setBackground(bg);
setPaint(paint);
@@ -386,6 +384,10 @@ public abstract class CairoGraphics2D extends Graphics2D
float x, float y, int n,
int[] codes, float[] positions);
+ /**
+ * Set the font in cairo.
+ */
+ private native void cairoSetFont(long pointer, GdkFontPeer font);
private native void cairoRelCurveTo(long pointer, double dx1, double dy1,
double dx2, double dy2, double dx3,
@@ -965,27 +967,30 @@ public abstract class CairoGraphics2D extends Graphics2D
compCtx.dispose();
compCtx = null;
- if (comp == null)
- comp = AlphaComposite.SrcOver;
-
if (comp instanceof AlphaComposite)
{
AlphaComposite a = (AlphaComposite) comp;
- cairoSetOperator(nativePointer, a.getRule());
+ 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();
- // this is in progress! yay!
- compCtx = comp.createContext(getNativeCM(), getNativeCM(), hints);
+ cairoSetOperator(nativePointer, AlphaComposite.SRC_OVER);
+
+ if (comp != null)
+ {
+ // 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();
+ // this is in progress! yay!
+ //compCtx = comp.createContext(getNativeCM(), getNativeCM(), hints);
+ compCtx = comp.createContext(getBufferCM(), getNativeCM(), hints);
+ }
}
}
@@ -1003,6 +1008,12 @@ public abstract class CairoGraphics2D extends Graphics2D
// for now, so that the build doesn't break.
return null;
}
+
+ // This may be overridden by some subclasses
+ protected ColorModel getBufferCM()
+ {
+ return getNativeCM();
+ }
///////////////////////// DRAWING PRIMITIVES ///////////////////////////////////
@@ -1017,13 +1028,13 @@ public abstract class CairoGraphics2D extends Graphics2D
return;
}
- createPath(s);
+ createPath(s, true);
cairoStroke(nativePointer);
}
public void fill(Shape s)
{
- createPath(s);
+ createPath(s, false);
double alpha = 1.0;
if (comp instanceof AlphaComposite)
@@ -1031,7 +1042,7 @@ public abstract class CairoGraphics2D extends Graphics2D
cairoFill(nativePointer, alpha);
}
- private void createPath(Shape s)
+ private void createPath(Shape s, boolean isDraw)
{
cairoNewPath(nativePointer);
@@ -1039,8 +1050,8 @@ public abstract class CairoGraphics2D extends Graphics2D
if (s instanceof Rectangle2D)
{
Rectangle2D r = (Rectangle2D) s;
- cairoRectangle(nativePointer, shifted(r.getX(), shiftDrawCalls),
- shifted(r.getY(), shiftDrawCalls), r.getWidth(),
+ cairoRectangle(nativePointer, shifted(r.getX(),shiftDrawCalls && isDraw),
+ shifted(r.getY(), shiftDrawCalls && isDraw), r.getWidth(),
r.getHeight());
}
@@ -1070,9 +1081,9 @@ public abstract class CairoGraphics2D extends Graphics2D
}
cairoArc(nativePointer,
- shifted(e.getCenterX() / xscale, shiftDrawCalls),
- shifted(e.getCenterY() / yscale, shiftDrawCalls), radius, 0,
- Math.PI * 2);
+ shifted(e.getCenterX() / xscale, shiftDrawCalls && isDraw),
+ shifted(e.getCenterY() / yscale, shiftDrawCalls && isDraw),
+ radius, 0, Math.PI * 2);
if (xscale != 1 || yscale != 1)
cairoRestore(nativePointer);
@@ -1081,7 +1092,7 @@ public abstract class CairoGraphics2D extends Graphics2D
// All other shapes are broken down and drawn in steps using the
// PathIterator
else
- walkPath(s.getPathIterator(null), shiftDrawCalls);
+ walkPath(s.getPathIterator(null), shiftDrawCalls && isDraw);
}
/**
@@ -1214,7 +1225,7 @@ public abstract class CairoGraphics2D extends Graphics2D
Rectangle2D r = getRealBounds();
- if( width < 0 || height < 0 )
+ if( width <= 0 || height <= 0 )
return;
// Return if outside the surface
if( x + dx > r.getWidth() || y + dy > r.getHeight() )
@@ -1358,9 +1369,6 @@ public abstract class CairoGraphics2D extends Graphics2D
int width = b.getWidth();
int height = b.getHeight();
- boolean wasPremultplied = b.isAlphaPremultiplied();
- b.coerceData(true);
-
// If this BufferedImage has a BufferedImageGraphics object,
// use the cached CairoSurface that BIG is drawing onto
@@ -1380,31 +1388,32 @@ public abstract class CairoGraphics2D extends Graphics2D
((CairoSurface)raster).drawSurface(nativePointer, i2u, alpha,
getInterpolation());
updateColor();
- b.coerceData(wasPremultplied);
return true;
}
if( bgcolor != null )
{
- // Fill a rectangle with the background color
- // to composite the image onto.
- Paint oldPaint = paint;
- AffineTransform oldTransform = transform;
- setPaint( bgcolor );
- setTransform( invertedXform );
- fillRect(0, 0, width, height);
- setTransform( oldTransform );
- setPaint( oldPaint );
+ Color oldColor = bg;
+ setBackground(bgcolor);
+
+ double[] origin = new double[] {0,0};
+ xform.transform(origin, 0, origin, 0, 1);
+ clearRect((int)origin[0], (int)origin[1], width, height);
+
+ setBackground(oldColor);
}
int[] pixels = b.getRGB(0, 0, width, height, null, 0, width);
+
+ // FIXME: The above method returns data in the standard ARGB colorspace,
+ // meaning data should NOT be alpha pre-multiplied; however Cairo expects
+ // data to be premultiplied.
drawPixels(nativePointer, pixels, width, height, width, i2u, alpha,
getInterpolation());
// Cairo seems to lose the current color which must be restored.
updateColor();
- b.coerceData(wasPremultplied);
return true;
}
@@ -1607,6 +1616,8 @@ public abstract class CairoGraphics2D extends Graphics2D
font =
((ClasspathToolkit)(Toolkit.getDefaultToolkit()))
.getFont(f.getName(), f.getAttributes());
+
+ cairoSetFont(nativePointer, (GdkFontPeer)getFont().getPeer());
}
public Font getFont()
diff --git a/gnu/java/awt/peer/gtk/CairoSurface.java b/gnu/java/awt/peer/gtk/CairoSurface.java
index 91b10369d..d3b3d4504 100644
--- a/gnu/java/awt/peer/gtk/CairoSurface.java
+++ b/gnu/java/awt/peer/gtk/CairoSurface.java
@@ -72,16 +72,22 @@ public class CairoSurface extends WritableRaster
*/
long bufferPointer;
- // nativeGetPixels will return [0]=red, [1]=green, [2]=blue, [3]=alpha
- static ColorModel nativeColorModel = new DirectColorModel(ColorSpace.getInstance(ColorSpace.CS_sRGB),
- 32,
- 0x000000FF,
+ // FIXME: use only the cairoCM_pre colormodel
+ // since that's what Cairo really uses (is there a way to do this cheaply?
+ // we use a non-multiplied model most of the time to avoid costly coercion
+ // operations...)
+ static ColorModel cairoColorModel = new DirectColorModel(32, 0x00FF0000,
+ 0x0000FF00,
+ 0x000000FF,
+ 0xFF000000);
+
+ static ColorModel cairoCM_pre = new DirectColorModel(ColorSpace.getInstance(ColorSpace.CS_sRGB),
+ 32, 0x00FF0000,
0x0000FF00,
- 0x00FF0000,
+ 0x000000FF,
0xFF000000,
true,
Buffers.smallestAppropriateTransferType(32));
-
/**
* Allocates and clears the buffer and creates the cairo surface.
* @param width, height - the image size
@@ -147,7 +153,7 @@ public class CairoSurface extends WritableRaster
*/
public CairoSurface(int width, int height)
{
- super(createNativeSampleModel(width, height),
+ super(createCairoSampleModel(width, height),
null, new Point(0, 0));
if(width <= 0 || height <= 0)
@@ -260,7 +266,9 @@ public class CairoSurface extends WritableRaster
*/
public static BufferedImage getBufferedImage(CairoSurface surface)
{
- return new BufferedImage(nativeColorModel, surface, true, new Hashtable());
+ return new BufferedImage(cairoColorModel, surface,
+ cairoColorModel.isAlphaPremultiplied(),
+ new Hashtable());
}
private class CairoDataBuffer extends DataBuffer
@@ -326,10 +334,10 @@ public class CairoSurface extends WritableRaster
/**
* Creates a SampleModel that matches Cairo's native format
*/
- protected static SampleModel createNativeSampleModel(int w, int h)
+ protected static SampleModel createCairoSampleModel(int w, int h)
{
return new SinglePixelPackedSampleModel(DataBuffer.TYPE_INT, w, h,
- new int[]{0x000000FF, 0x0000FF00,
- 0x00FF0000, 0xFF000000});
+ new int[]{0x00FF0000, 0x0000FF00,
+ 0x000000FF, 0xFF000000});
}
}
diff --git a/gnu/java/awt/peer/gtk/CairoSurfaceGraphics.java b/gnu/java/awt/peer/gtk/CairoSurfaceGraphics.java
index 7bd136c38..36743b9c2 100644
--- a/gnu/java/awt/peer/gtk/CairoSurfaceGraphics.java
+++ b/gnu/java/awt/peer/gtk/CairoSurfaceGraphics.java
@@ -38,10 +38,26 @@ exception statement from your version. */
package gnu.java.awt.peer.gtk;
+import java.awt.AlphaComposite;
+import java.awt.Color;
import java.awt.Graphics;
-import java.awt.GraphicsEnvironment;
+import java.awt.Graphics2D;
import java.awt.GraphicsConfiguration;
+import java.awt.GraphicsEnvironment;
+import java.awt.Image;
+import java.awt.Rectangle;
+import java.awt.Shape;
+import java.awt.Toolkit;
+import java.awt.font.GlyphVector;
+import java.awt.geom.AffineTransform;
+import java.awt.geom.Point2D;
import java.awt.geom.Rectangle2D;
+import java.awt.image.BufferedImage;
+import java.awt.image.ColorModel;
+import java.awt.image.ImageObserver;
+import java.awt.image.ImageProducer;
+import java.awt.image.RenderedImage;
+import java.util.Hashtable;
/**
* Implementation of Graphics2D on a Cairo surface.
@@ -49,6 +65,7 @@ import java.awt.geom.Rectangle2D;
public class CairoSurfaceGraphics extends CairoGraphics2D
{
protected CairoSurface surface;
+ private BufferedImage buffer;
private long cairo_t;
/**
@@ -59,6 +76,7 @@ public class CairoSurfaceGraphics extends CairoGraphics2D
this.surface = surface;
cairo_t = surface.newCairoContext();
setup( cairo_t );
+ setClip(0, 0, surface.width, surface.height);
}
/**
@@ -91,4 +109,200 @@ public class CairoSurfaceGraphics extends CairoGraphics2D
{
surface.copyAreaNative(x, y, width, height, dx, dy, surface.width);
}
+
+ /**
+ * Overloaded methods that do actual drawing need to account for custom
+ * composites
+ */
+ public void draw(Shape s)
+ {
+ if (comp == null || comp instanceof AlphaComposite)
+ super.draw(s);
+
+ else
+ {
+ createBuffer();
+
+ Graphics2D g2d = (Graphics2D)buffer.getGraphics();
+ g2d.setStroke(this.getStroke());
+ g2d.setColor(this.getColor());
+ g2d.draw(s);
+
+ drawComposite(s.getBounds2D(), null);
+ }
+ }
+
+ public void fill(Shape s)
+ {
+ if (comp == null || comp instanceof AlphaComposite)
+ super.fill(s);
+
+ else
+ {
+ createBuffer();
+
+ Graphics2D g2d = (Graphics2D)buffer.getGraphics();
+ g2d.setPaint(this.getPaint());
+ g2d.setColor(this.getColor());
+ g2d.fill(s);
+
+ drawComposite(s.getBounds2D(), null);
+ }
+ }
+
+ public void drawRenderedImage(RenderedImage image, AffineTransform xform)
+ {
+ if (comp == null || comp instanceof AlphaComposite)
+ super.drawRenderedImage(image, xform);
+
+ else
+ {
+ createBuffer();
+
+ Graphics2D g2d = (Graphics2D)buffer.getGraphics();
+ g2d.setRenderingHints(this.getRenderingHints());
+ g2d.drawRenderedImage(image, xform);
+
+ drawComposite(buffer.getRaster().getBounds(), null);
+ }
+
+ }
+
+ protected boolean drawImage(Image img, AffineTransform xform,
+ Color bgcolor, ImageObserver obs)
+ {
+ if (comp == null || comp instanceof AlphaComposite)
+ return super.drawImage(img, xform, bgcolor, obs);
+
+ else
+ {
+ // Get buffered image of source
+ if( !(img instanceof BufferedImage) )
+ {
+ ImageProducer source = img.getSource();
+ if (source == null)
+ return false;
+ img = Toolkit.getDefaultToolkit().createImage(source);
+ }
+ BufferedImage bImg = (BufferedImage) img;
+
+ // Find translated bounds
+ Point2D origin = new Point2D.Double(bImg.getMinX(), bImg.getMinY());
+ Point2D pt = new Point2D.Double(bImg.getWidth() + bImg.getMinX(),
+ bImg.getHeight() + bImg.getMinY());
+ if (xform != null)
+ {
+ origin = xform.transform(origin, origin);
+ pt = xform.transform(pt, pt);
+ }
+
+ // Create buffer and draw image
+ createBuffer();
+
+ Graphics2D g2d = (Graphics2D)buffer.getGraphics();
+ g2d.setRenderingHints(this.getRenderingHints());
+ g2d.drawImage(img, xform, obs);
+
+ // Perform compositing
+ return drawComposite(new Rectangle2D.Double(origin.getX(),
+ origin.getY(),
+ pt.getX(), pt.getY()),
+ obs);
+ }
+ }
+
+ public void drawGlyphVector(GlyphVector gv, float x, float y)
+ {
+ if (comp == null || comp instanceof AlphaComposite)
+ super.drawGlyphVector(gv, x, y);
+
+ else
+ {
+ createBuffer();
+
+ Graphics2D g2d = (Graphics2D)buffer.getGraphics();
+ g2d.setPaint(this.getPaint());
+ g2d.setStroke(this.getStroke());
+ g2d.drawGlyphVector(gv, x, y);
+
+ Rectangle2D bounds = gv.getLogicalBounds();
+ bounds = new Rectangle2D.Double(x + bounds.getX(), y + bounds.getY(),
+ bounds.getWidth(), bounds.getHeight());
+ drawComposite(bounds, null);
+ }
+ }
+
+ private boolean drawComposite(Rectangle2D bounds, ImageObserver observer)
+ {
+ // Clip source to visible areas that need updating
+ Rectangle2D clip = this.getClipBounds();
+ Rectangle2D.intersect(bounds, clip, bounds);
+ clip = new Rectangle(buffer.getMinX(), buffer.getMinY(),
+ buffer.getWidth(), buffer.getHeight());
+ Rectangle2D.intersect(bounds, clip, bounds);
+
+ BufferedImage buffer2 = buffer;
+ if (!bounds.equals(buffer2.getRaster().getBounds()))
+ buffer2 = buffer2.getSubimage((int)bounds.getX(), (int)bounds.getY(),
+ (int)bounds.getWidth(),
+ (int)bounds.getHeight());
+
+ // Get destination clip to bounds
+ double[] points = new double[] {bounds.getX(), bounds.getY(),
+ bounds.getMaxX(), bounds.getMaxY()};
+ transform.transform(points, 0, points, 0, 2);
+
+ Rectangle2D deviceBounds = new Rectangle2D.Double(points[0], points[1],
+ points[2] - points[0],
+ points[3] - points[1]);
+
+ Rectangle2D.intersect(deviceBounds, this.getClipInDevSpace(), deviceBounds);
+
+ BufferedImage current = CairoSurface.getBufferedImage(surface);
+ current = current.getSubimage((int)deviceBounds.getX(),
+ (int)deviceBounds.getY(),
+ (int)deviceBounds.getWidth(),
+ (int)deviceBounds.getHeight());
+
+ // Perform actual composite operation
+ compCtx.compose(buffer2.getRaster(), current.getRaster(),
+ buffer2.getRaster());
+
+ // This MUST call directly into the "action" method in CairoGraphics2D,
+ // not one of the wrappers, to ensure that the composite isn't processed
+ // more than once!
+ boolean rv = super.drawImage(buffer2,
+ AffineTransform.getTranslateInstance(bounds.getX(),
+ bounds.getY()),
+ new Color(0,0,0,0), null);
+ return rv;
+ }
+
+ private void createBuffer()
+ {
+ if (buffer == null)
+ {
+ buffer = new BufferedImage(getBufferCM(),
+ surface.createCompatibleWritableRaster(),
+ getBufferCM().isAlphaPremultiplied(),
+ new Hashtable());
+ }
+ else
+ {
+ Graphics2D g2d = ((Graphics2D)buffer.getGraphics());
+
+ g2d.setBackground(new Color(0,0,0,0));
+ g2d.clearRect(0, 0, buffer.getWidth(), buffer.getHeight());
+ }
+ }
+
+ protected ColorModel getNativeCM()
+ {
+ return CairoSurface.cairoCM_pre;
+ }
+
+ protected ColorModel getBufferCM()
+ {
+ return CairoSurface.cairoColorModel;
+ }
}
diff --git a/gnu/java/awt/peer/gtk/FreetypeGlyphVector.java b/gnu/java/awt/peer/gtk/FreetypeGlyphVector.java
index 44c1ad926..1449cdf61 100644
--- a/gnu/java/awt/peer/gtk/FreetypeGlyphVector.java
+++ b/gnu/java/awt/peer/gtk/FreetypeGlyphVector.java
@@ -424,10 +424,18 @@ public class FreetypeGlyphVector extends GlyphVector
return logicalBounds;
Rectangle2D rect = (Rectangle2D)getGlyphLogicalBounds( 0 );
+ AffineTransform tx = new AffineTransform();
for( int i = 1; i < nGlyphs; i++ )
{
- Rectangle2D r2 = (Rectangle2D)getGlyphLogicalBounds( i );
- rect = rect.createUnion( r2 );
+ Rectangle2D r2 = (Rectangle2D)getGlyphLogicalBounds( i );
+
+ // Translate to the glyph's position
+ tx.setToTranslation(glyphPositions[i*2], glyphPositions[i*2+1]);
+ Point2D pt = new Point2D.Double(r2.getMinX(), r2.getMinY());
+ tx.transform(pt, pt);
+ r2.setRect(pt.getX(), pt.getY(), r2.getWidth(), r2.getHeight());
+
+ rect = rect.createUnion( r2 );
}
logicalBounds = rect;
@@ -448,8 +456,14 @@ public class FreetypeGlyphVector extends GlyphVector
public Shape getOutline()
{
GeneralPath path = new GeneralPath();
+ AffineTransform tx = new AffineTransform();
for( int i = 0; i < getNumGlyphs(); i++ )
- path.append( getGlyphOutline( i ), false );
+ {
+ Shape outline = getGlyphOutline(i);
+ tx.setToTranslation(glyphPositions[i*2], glyphPositions[i*2 +1]);
+ outline = tx.createTransformedShape(outline);
+ path.append(outline, false);
+ }
return path;
}
diff --git a/gnu/java/awt/peer/gtk/GtkFramePeer.java b/gnu/java/awt/peer/gtk/GtkFramePeer.java
index bb6f8b3bb..d113e92f5 100644
--- a/gnu/java/awt/peer/gtk/GtkFramePeer.java
+++ b/gnu/java/awt/peer/gtk/GtkFramePeer.java
@@ -57,6 +57,11 @@ public class GtkFramePeer extends GtkWindowPeer
native void removeMenuBarPeer ();
native void gtkFixedSetVisible (boolean visible);
+ private native void maximize();
+ private native void unmaximize();
+ private native void iconify();
+ private native void deiconify();
+
int getMenuBarHeight ()
{
return menuBar == null ? 0 : getMenuBarHeight (menuBar);
@@ -199,12 +204,25 @@ public class GtkFramePeer extends GtkWindowPeer
public int getState ()
{
- return 0;
+ return windowState;
}
public void setState (int state)
{
-
+ switch (state)
+ {
+ case Frame.NORMAL:
+ if ((windowState & Frame.ICONIFIED) != 0)
+ deiconify();
+ if ((windowState & Frame.MAXIMIZED_BOTH) != 0)
+ unmaximize();
+ break;
+ case Frame.ICONIFIED:
+ iconify();
+ break;
+ case Frame.MAXIMIZED_BOTH:
+ maximize();
+ }
}
public void setMaximizedBounds (Rectangle r)
diff --git a/gnu/java/awt/peer/gtk/GtkMainThread.java b/gnu/java/awt/peer/gtk/GtkMainThread.java
index 19d3f1d0b..a4e280fe4 100644
--- a/gnu/java/awt/peer/gtk/GtkMainThread.java
+++ b/gnu/java/awt/peer/gtk/GtkMainThread.java
@@ -38,6 +38,44 @@ exception statement from your version. */
package gnu.java.awt.peer.gtk;
+import gnu.java.awt.peer.NativeEventLoopRunningEvent;
+
+import java.awt.AWTEvent;
+
+/**
+ * The Java thread representing the native GTK main loop, that is,
+ * GtkMainThread.mainThread, terminates when GtkToolkit.gtkMain()
+ * returns. That happens in response to the last window peer being
+ * disposed (see GtkWindowPeer.dispose).
+ *
+ * When GtkMainThread.destroyWindow is called for the last window, it
+ * in turn calls GtkMainThread.endMainThread, which calls gtk_quit.
+ * gtk_quit signals gtk_main to return, which causes GtkMainThread.run
+ * to return.
+ *
+ * There should only be one native GTK main loop running at any given
+ * time. In order to safely start and stop the GTK main loop, we use
+ * a running flag and corresponding runningLock. startMainThread will
+ * not return until the native GTK main loop has started, as confirmed
+ * by the native set_running_flag callback setting the running flag to
+ * true. Without this protection, gtk_quit could be called before the
+ * main loop has actually started, which causes GTK assertion
+ * failures. Likewise endMainThread will not return until the native
+ * GTK main loop has ended.
+ *
+ * post_running_flag_callback is called during gtk_main initialization
+ * and no window can be created before startMainThread returns. This
+ * ensures that calling post_running_flag_callback is the first action
+ * taken by the native GTK main loop.
+ *
+ * GtkMainThread.mainThread is started when the window count goes from
+ * zero to one.
+ *
+ * GtkMainThread keeps the AWT event queue informed of its status by
+ * posting NativeEventLoopRunningEvents. The AWT event queue uses
+ * this status to determine whether or not the AWT exit conditions
+ * have been met (see EventQueue.isShutdown).
+ */
public class GtkMainThread extends Thread
{
/** Count of the number of open windows */
@@ -46,6 +84,12 @@ public class GtkMainThread extends Thread
/** Lock for the above */
private static Object nWindowsLock = new Object();
+ /** Indicates whether or not the GTK main loop is running. */
+ private static boolean running = false;
+
+ /** Lock for the above. */
+ private static Object runningLock = new Object();
+
/** The main thread instance (singleton) */
public static GtkMainThread mainThread;
@@ -60,26 +104,75 @@ public class GtkMainThread extends Thread
GtkToolkit.gtkMain ();
}
+ private static void setRunning(boolean running)
+ {
+ synchronized (runningLock)
+ {
+ GtkMainThread.running = running;
+ runningLock.notifyAll();
+ }
+ }
+
private static void startMainThread()
{
- if( mainThread == null )
+ synchronized (runningLock)
{
- mainThread = new GtkMainThread();
- mainThread.start();
+ if (!running)
+ {
+ mainThread = new GtkMainThread();
+ mainThread.start();
+
+ while (!running)
+ {
+ try
+ {
+ runningLock.wait();
+ }
+ catch (InterruptedException e)
+ {
+ System.err.println ("GtkMainThread.startMainThread:"
+ + " interrupted while waiting "
+ + " for GTK main loop to start");
+ }
+ }
+ GtkGenericPeer.q()
+ .postEvent(new NativeEventLoopRunningEvent(new Boolean(true)));
+ }
}
}
private static void endMainThread()
{
- if( mainThread != null )
- GtkToolkit.gtkQuit();
+ synchronized (runningLock)
+ {
+ if (running)
+ {
+ GtkToolkit.gtkQuit();
+
+ while (running)
+ {
+ try
+ {
+ runningLock.wait();
+ }
+ catch (InterruptedException e)
+ {
+ System.err.println ("GtkMainThread.endMainThread:"
+ + " interrupted while waiting "
+ + " for GTK main loop to stop");
+ }
+ }
+ GtkGenericPeer.q()
+ .postEvent(new NativeEventLoopRunningEvent(new Boolean(false)));
+ }
+ }
}
public static void createWindow()
{
- synchronized( nWindowsLock )
+ synchronized (nWindowsLock)
{
- if( numberOfWindows == 0 )
+ if (numberOfWindows == 0)
startMainThread();
numberOfWindows++;
}
@@ -87,11 +180,11 @@ public class GtkMainThread extends Thread
public static void destroyWindow()
{
- synchronized( nWindowsLock )
+ synchronized (nWindowsLock)
{
numberOfWindows--;
- if( numberOfWindows == 0 )
+ if (numberOfWindows == 0)
endMainThread();
}
}
-} \ No newline at end of file
+}
diff --git a/gnu/java/awt/peer/gtk/GtkToolkit.java b/gnu/java/awt/peer/gtk/GtkToolkit.java
index 3f87ca6e6..d2721b43f 100644
--- a/gnu/java/awt/peer/gtk/GtkToolkit.java
+++ b/gnu/java/awt/peer/gtk/GtkToolkit.java
@@ -664,6 +664,14 @@ public class GtkToolkit extends gnu.java.awt.ClasspathToolkit
return new GtkMouseInfoPeer();
}
+ public boolean isFrameStateSupported(int state)
+ {
+ // GTK supports ICONFIED, NORMAL and MAXIMIZE_BOTH, but
+ // not (yet?) MAXIMIZE_VERT and MAXIMIZE_HORIZ.
+ return state == Frame.NORMAL || state == Frame.ICONIFIED
+ || state == Frame.MAXIMIZED_BOTH;
+ }
+
public native int getMouseNumberOfButtons();
} // class GtkToolkit
diff --git a/gnu/java/awt/peer/gtk/GtkVolatileImage.java b/gnu/java/awt/peer/gtk/GtkVolatileImage.java
index 44e7b027b..8660ced8e 100644
--- a/gnu/java/awt/peer/gtk/GtkVolatileImage.java
+++ b/gnu/java/awt/peer/gtk/GtkVolatileImage.java
@@ -37,13 +37,21 @@ exception statement from your version. */
package gnu.java.awt.peer.gtk;
-import java.awt.ImageCapabilities;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.GraphicsConfiguration;
+import java.awt.ImageCapabilities;
+import java.awt.Point;
import java.awt.image.BufferedImage;
+import java.awt.image.ColorModel;
+import java.awt.image.DataBuffer;
+import java.awt.image.DirectColorModel;
import java.awt.image.ImageObserver;
+import java.awt.image.Raster;
+import java.awt.image.SampleModel;
+import java.awt.image.SinglePixelPackedSampleModel;
import java.awt.image.VolatileImage;
+import java.awt.image.WritableRaster;
public class GtkVolatileImage extends VolatileImage
{
@@ -52,6 +60,12 @@ public class GtkVolatileImage extends VolatileImage
final GtkComponentPeer component;
+ static ColorModel gdkColorModel = new DirectColorModel(32,
+ 0x000000FF,
+ 0x0000FF00,
+ 0x00FF0000,
+ 0xFF000000);
+
/**
* Don't touch, accessed from native code.
*/
@@ -62,6 +76,17 @@ public class GtkVolatileImage extends VolatileImage
native void destroy(long pointer);
native int[] nativeGetPixels(long pointer);
+
+ /**
+ * Gets the pixels in the current image from GDK.
+ *
+ * Note that pixels are in 32-bit RGBA, non-premultiplied, which is different
+ * from Cairo's premultiplied ARGB, which is different from Java's standard
+ * non-premultiplied ARGB. Caution is advised when using this method, to
+ * ensure that the data format remains consistent with what you expect.
+ *
+ * @return the current pixels, as reported by GDK.
+ */
public int[] getPixels()
{
return nativeGetPixels(nativePointer);
@@ -113,9 +138,11 @@ public class GtkVolatileImage extends VolatileImage
public BufferedImage getSnapshot()
{
- CairoSurface cs = new CairoSurface( width, height );
- cs.setPixels( getPixels() );
- return CairoSurface.getBufferedImage( cs );
+ WritableRaster raster = Raster.createWritableRaster(createGdkSampleModel(width, height),
+ new Point(0, 0));
+ raster.setDataElements(0, 0, getPixels());
+ return new BufferedImage(gdkColorModel, raster,
+ gdkColorModel.isAlphaPremultiplied(), null);
}
public Graphics getGraphics()
@@ -167,4 +194,14 @@ public class GtkVolatileImage extends VolatileImage
{
return null;
}
+
+ /**
+ * Creates a SampleModel that matches GDK's native format
+ */
+ protected static SampleModel createGdkSampleModel(int w, int h)
+ {
+ return new SinglePixelPackedSampleModel(DataBuffer.TYPE_INT, w, h,
+ new int[]{0x000000FF, 0x0000FF00,
+ 0x00FF0000, 0xFF000000});
+ }
}
diff --git a/gnu/java/awt/peer/gtk/GtkWindowPeer.java b/gnu/java/awt/peer/gtk/GtkWindowPeer.java
index 1f340611e..1abc5ca84 100644
--- a/gnu/java/awt/peer/gtk/GtkWindowPeer.java
+++ b/gnu/java/awt/peer/gtk/GtkWindowPeer.java
@@ -38,6 +38,8 @@ exception statement from your version. */
package gnu.java.awt.peer.gtk;
+import gnu.java.awt.ComponentReshapeEvent;
+
import java.awt.Component;
import java.awt.Frame;
import java.awt.Graphics;
@@ -62,8 +64,7 @@ public class GtkWindowPeer extends GtkContainerPeer
protected static final int GDK_WINDOW_TYPE_HINT_DOCK = 6;
protected static final int GDK_WINDOW_TYPE_HINT_DESKTOP = 7;
- private boolean hasBeenShown = false;
- private int oldState = Frame.NORMAL;
+ protected int windowState = Frame.NORMAL;
// Cached awt window component location, width and height.
private int x, y, width, height;
@@ -224,9 +225,31 @@ public class GtkWindowPeer extends GtkContainerPeer
// only called from GTK thread
protected void postConfigureEvent (int x, int y, int width, int height)
{
+ int frame_x = x - insets.left;
+ int frame_y = y - insets.top;
int frame_width = width + insets.left + insets.right;
int frame_height = height + insets.top + insets.bottom;
+ // Update the component's knowledge about the size.
+ // Important: Please look at the big comment in ComponentReshapeEvent
+ // to learn why we did it this way. If you change this code, make
+ // sure that the peer->AWT bounds update still works.
+ // (for instance: http://gcc.gnu.org/bugzilla/show_bug.cgi?id=29448 )
+
+ // We do this befor we post the ComponentEvent, because (in Window)
+ // we invalidate() / revalidate() when a ComponentEvent is seen,
+ // and the AWT must already know about the new size then.
+ if (frame_x != this.x || frame_y != this.y || frame_width != this.width
+ || frame_height != this.height)
+ {
+ ComponentReshapeEvent ev = new ComponentReshapeEvent(awtComponent,
+ frame_x,
+ frame_y,
+ frame_width,
+ frame_height);
+ awtComponent.dispatchEvent(ev);
+ }
+
if (frame_width != getWidth()
|| frame_height != getHeight())
{
@@ -236,9 +259,6 @@ public class GtkWindowPeer extends GtkContainerPeer
ComponentEvent.COMPONENT_RESIZED));
}
- int frame_x = x - insets.left;
- int frame_y = y - insets.top;
-
if (frame_x != getX()
|| frame_y != getY())
{
@@ -247,6 +267,7 @@ public class GtkWindowPeer extends GtkContainerPeer
q().postEvent(new ComponentEvent(awtComponent,
ComponentEvent.COMPONENT_MOVED));
}
+
}
public void show ()
@@ -261,23 +282,26 @@ public class GtkWindowPeer extends GtkContainerPeer
void postWindowEvent (int id, Window opposite, int newState)
{
- if (id == WindowEvent.WINDOW_OPENED)
+ if (id == WindowEvent.WINDOW_STATE_CHANGED)
{
- // Post a WINDOW_OPENED event the first time this window is shown.
- if (!hasBeenShown)
+ if (windowState != newState)
{
+ // Post old styleWindowEvent with WINDOW_ICONIFIED or
+ // WINDOW_DEICONIFIED if appropriate.
+ if ((windowState & Frame.ICONIFIED) != 0
+ && (newState & Frame.ICONIFIED) == 0)
+ q().postEvent(new WindowEvent((Window) awtComponent,
+ WindowEvent.WINDOW_DEICONIFIED,
+ opposite, 0, 0));
+ else if ((windowState & Frame.ICONIFIED) == 0
+ && (newState & Frame.ICONIFIED) != 0)
+ q().postEvent(new WindowEvent((Window) awtComponent,
+ WindowEvent.WINDOW_ICONIFIED,
+ opposite, 0, 0));
+ // Post new-style WindowStateEvent.
q().postEvent (new WindowEvent ((Window) awtComponent, id,
- opposite));
- hasBeenShown = true;
- }
- }
- else if (id == WindowEvent.WINDOW_STATE_CHANGED)
- {
- if (oldState != newState)
- {
- q().postEvent (new WindowEvent ((Window) awtComponent, id, opposite,
- oldState, newState));
- oldState = newState;
+ opposite, windowState, newState));
+ windowState = newState;
}
}
else
@@ -356,13 +380,6 @@ public class GtkWindowPeer extends GtkContainerPeer
return g;
}
- protected void updateComponent (PaintEvent event)
- {
- // Do not clear anything before painting. Sun never calls
- // Window.update, only Window.paint.
- paintComponent(event);
- }
-
protected void postMouseEvent(int id, long when, int mods, int x, int y,
int clickCount, boolean popupTrigger)
{
diff --git a/gnu/java/awt/peer/gtk/VolatileImageGraphics.java b/gnu/java/awt/peer/gtk/VolatileImageGraphics.java
index 560d31750..3a9f9d693 100644
--- a/gnu/java/awt/peer/gtk/VolatileImageGraphics.java
+++ b/gnu/java/awt/peer/gtk/VolatileImageGraphics.java
@@ -282,12 +282,12 @@ public class VolatileImageGraphics extends ComponentGraphics
if (buffer == null)
{
WritableRaster rst;
- rst = Raster.createWritableRaster(CairoSurface.
- createNativeSampleModel(owner.width,
+ rst = Raster.createWritableRaster(GtkVolatileImage.createGdkSampleModel(owner.width,
owner.height),
new Point(0,0));
- buffer = new BufferedImage(CairoSurface.nativeColorModel, rst, true,
+ buffer = new BufferedImage(GtkVolatileImage.gdkColorModel, rst,
+ GtkVolatileImage.gdkColorModel.isAlphaPremultiplied(),
new Hashtable());
}
else
@@ -301,7 +301,12 @@ public class VolatileImageGraphics extends ComponentGraphics
protected ColorModel getNativeCM()
{
- return CairoSurface.nativeColorModel;
+ // We should really return GtkVolatileImage.gdkColorModel ,
+ // but CairoGraphics2D doesn't handle alpha premultiplication properly (see
+ // the fixme in drawImage) so we use the naive Cairo model instead to trick
+ // the compositing context.
+ // Because getNativeCM() == getBufferCM() for this peer, it doesn't break.
+ return CairoSurface.cairoCM_pre;
}
}
diff --git a/gnu/java/lang/InstrumentationImpl.java b/gnu/java/lang/InstrumentationImpl.java
index 3192683ef..2425b35c8 100644
--- a/gnu/java/lang/InstrumentationImpl.java
+++ b/gnu/java/lang/InstrumentationImpl.java
@@ -1,6 +1,6 @@
/* InstrumentationImpl.java -- GNU implementation of
java.lang.instrument.Instrumentation
- Copyright (C) 2005 Free Software Foundation, Inc.
+ Copyright (C) 2005, 2006 Free Software Foundation, Inc.
This file is part of GNU Classpath.
@@ -67,7 +67,7 @@ public final class InstrumentationImpl implements Instrumentation
new ArrayList<ClassFileTransformer>();
- private InstrumentationImpl()
+ InstrumentationImpl()
{
}
diff --git a/gnu/java/net/PlainDatagramSocketImpl.java b/gnu/java/net/PlainDatagramSocketImpl.java
index be2fc796b..a84525e18 100644
--- a/gnu/java/net/PlainDatagramSocketImpl.java
+++ b/gnu/java/net/PlainDatagramSocketImpl.java
@@ -1,5 +1,5 @@
/* PlainDatagramSocketImpl.java -- Default DatagramSocket implementation
- Copyright (C) 1998, 1999, 2001, 2003, 2004, 2005 Free Software Foundation, Inc.
+ Copyright (C) 1998, 1999, 2001, 2003, 2004, 2005, 2006 Free Software Foundation, Inc.
This file is part of GNU Classpath.
@@ -42,7 +42,6 @@ import gnu.java.nio.VMChannel;
import java.io.IOException;
import java.io.InterruptedIOException;
-import java.lang.reflect.Field;
import java.net.DatagramPacket;
import java.net.DatagramSocketImpl;
import java.net.InetAddress;
@@ -69,7 +68,6 @@ import java.nio.ByteBuffer;
*/
public final class PlainDatagramSocketImpl extends DatagramSocketImpl
{
-
private final VMChannel channel;
/**
@@ -171,7 +169,7 @@ public final class PlainDatagramSocketImpl extends DatagramSocketImpl
*/
protected void connect(InetAddress addr, int port) throws SocketException
{
- VMPlainDatagramSocketImpl.connect(this, addr, port);
+ channel.connect(new InetSocketAddress(addr, port), 0);
}
/**
@@ -203,7 +201,7 @@ public final class PlainDatagramSocketImpl extends DatagramSocketImpl
*/
protected synchronized void setTimeToLive(int ttl) throws IOException
{
- setOption(VMPlainDatagramSocketImpl.IP_TTL, new Integer(ttl));
+ impl.setTimeToLive(ttl);
}
/**
@@ -215,12 +213,7 @@ public final class PlainDatagramSocketImpl extends DatagramSocketImpl
*/
protected synchronized int getTimeToLive() throws IOException
{
- Object obj = getOption(VMPlainDatagramSocketImpl.IP_TTL);
-
- if (! (obj instanceof Integer))
- throw new IOException("Internal Error");
-
- return ((Integer) obj).intValue();
+ return impl.getTimeToLive();
}
protected int getLocalPort()
@@ -318,30 +311,53 @@ public final class PlainDatagramSocketImpl extends DatagramSocketImpl
/**
* Sets the value of an option on the socket
*
- * @param option_id The identifier of the option to set
- * @param val The value of the option to set
+ * @param optionId The identifier of the option to set
+ * @param value The value of the option to set
*
* @exception SocketException If an error occurs
*/
- public synchronized void setOption(int option_id, Object val)
+ public synchronized void setOption(int optionId, Object value)
throws SocketException
{
- impl.setOption(option_id, val);
+ switch (optionId)
+ {
+ case IP_MULTICAST_IF:
+ case IP_MULTICAST_IF2:
+ impl.setMulticastInterface(optionId, (InetAddress) value);
+ break;
+
+ case IP_MULTICAST_LOOP:
+ case SO_BROADCAST:
+ case SO_KEEPALIVE:
+ case SO_OOBINLINE:
+ case TCP_NODELAY:
+ case IP_TOS:
+ case SO_LINGER:
+ case SO_RCVBUF:
+ case SO_SNDBUF:
+ case SO_TIMEOUT:
+ case SO_REUSEADDR:
+ impl.setOption(optionId, value);
+ return;
+
+ default:
+ throw new SocketException("cannot set option " + optionId);
+ }
}
/**
* Retrieves the value of an option on the socket
*
- * @param option_id The identifier of the option to retrieve
+ * @param optionId The identifier of the option to retrieve
*
* @return The value of the option
*
* @exception SocketException If an error occurs
*/
- public synchronized Object getOption(int option_id)
+ public synchronized Object getOption(int optionId)
throws SocketException
{
- if (option_id == SO_BINDADDR)
+ if (optionId == SO_BINDADDR)
{
try
{
@@ -361,7 +377,10 @@ public final class PlainDatagramSocketImpl extends DatagramSocketImpl
throw se;
}
}
- return impl.getOption(option_id);
+ if (optionId == IP_MULTICAST_IF || optionId == IP_MULTICAST_IF2)
+ return impl.getMulticastInterface(optionId);
+
+ return impl.getOption(optionId);
}
/**
diff --git a/gnu/java/net/PlainSocketImpl.java b/gnu/java/net/PlainSocketImpl.java
index 750243d5d..64e498746 100644
--- a/gnu/java/net/PlainSocketImpl.java
+++ b/gnu/java/net/PlainSocketImpl.java
@@ -39,12 +39,9 @@ exception statement from your version. */
package gnu.java.net;
-import gnu.java.nio.SelectorProviderImpl;
import gnu.java.nio.SocketChannelImpl;
import gnu.java.nio.VMChannel;
-import gnu.java.security.action.GetSecurityPropertyAction;
-import java.io.EOFException;
import java.io.InputStream;
import java.io.IOException;
import java.io.InterruptedIOException;
@@ -56,7 +53,6 @@ import java.net.SocketException;
import java.net.SocketImpl;
import java.net.SocketTimeoutException;
import java.nio.ByteBuffer;
-import java.nio.channels.SocketChannel;
/**
* Written using on-line Java Platform 1.2 API Specification, as well
@@ -148,26 +144,21 @@ public class PlainSocketImpl extends SocketImpl
{
switch (optionId)
{
- case IP_MULTICAST_IF:
- case IP_MULTICAST_IF2:
- throw new UnsupportedOperationException("FIXME");
-
+ case SO_LINGER:
case IP_MULTICAST_LOOP:
case SO_BROADCAST:
case SO_KEEPALIVE:
case SO_OOBINLINE:
case TCP_NODELAY:
case IP_TOS:
- case SO_LINGER:
case SO_RCVBUF:
case SO_SNDBUF:
case SO_TIMEOUT:
case SO_REUSEADDR:
impl.setOption(optionId, value);
return;
-
- default:
- throw new SocketException("cannot set option " + optionId);
+ default:
+ throw new SocketException("Unrecognized TCP option: " + optionId);
}
}
@@ -197,10 +188,26 @@ public class PlainSocketImpl extends SocketImpl
throw se;
}
}
- if (optionId == IP_MULTICAST_IF || optionId == IP_MULTICAST_IF2)
- throw new UnsupportedOperationException ("can't get option " +
- optionId + " yet");
- return impl.getOption(optionId);
+
+ // This filters options which are invalid for TCP.
+ switch (optionId)
+ {
+ case SO_LINGER:
+ case IP_MULTICAST_LOOP:
+ case SO_BROADCAST:
+ case SO_KEEPALIVE:
+ case SO_OOBINLINE:
+ case TCP_NODELAY:
+ case IP_TOS:
+ case SO_RCVBUF:
+ case SO_SNDBUF:
+ case SO_TIMEOUT:
+ case SO_REUSEADDR:
+ return impl.getOption(optionId);
+ default:
+ throw new SocketException("Unrecognized TCP option: " + optionId);
+ }
+
}
public void shutdownInput() throws IOException
@@ -274,7 +281,10 @@ public class PlainSocketImpl extends SocketImpl
boolean connected = channel.connect(address, timeout);
if (!connected)
throw new SocketTimeoutException("connect timed out");
- InetSocketAddress addr = channel.getVMChannel().getPeerAddress();
+
+ // Using the given SocketAddress is important to preserve
+ // hostnames given by the caller.
+ InetSocketAddress addr = (InetSocketAddress) address;
this.address = addr.getAddress();
this.port = addr.getPort();
}
@@ -364,6 +374,9 @@ public class PlainSocketImpl extends SocketImpl
{
if (impl.getState().isValid())
impl.close();
+
+ address = null;
+ port = -1;
}
public void sendUrgentData(int data) throws IOException
@@ -417,11 +430,18 @@ public class PlainSocketImpl extends SocketImpl
{
if (channel == null)
return null;
+
try
{
InetSocketAddress remote = channel.getVMChannel().getPeerAddress();
if (remote == null)
return null;
+ // To mimic behavior of the RI the InetAddress instance which was
+ // used to establish the connection is returned instead of one that
+ // was created by the native layer (this preserves exact hostnames).
+ if (address != null)
+ return address;
+
return remote.getAddress();
}
catch (IOException ioe)
@@ -471,6 +491,7 @@ public class PlainSocketImpl extends SocketImpl
{
if (channel == null)
return -1;
+
try
{
InetSocketAddress remote = channel.getVMChannel().getPeerAddress();
diff --git a/gnu/java/nio/KqueueSelectorImpl.java b/gnu/java/nio/KqueueSelectorImpl.java
index eed86119c..34ca1dc59 100644
--- a/gnu/java/nio/KqueueSelectorImpl.java
+++ b/gnu/java/nio/KqueueSelectorImpl.java
@@ -63,7 +63,10 @@ import java.util.Set;
*/
public class KqueueSelectorImpl extends AbstractSelector
{
- private static final int sizeof_struct_kevent;
+ // Prepended underscore to field name to make it distinct
+ // from the method with the similar name.
+ private static final int _sizeof_struct_kevent;
+
private static final int MAX_DOUBLING_CAPACITY = 16384;
private static final int CAP_INCREMENT = 1024;
private static final int INITIAL_CAPACITY;
@@ -80,10 +83,10 @@ public class KqueueSelectorImpl extends AbstractSelector
}
if (kqueue_supported ())
- sizeof_struct_kevent = sizeof_struct_kevent();
+ _sizeof_struct_kevent = sizeof_struct_kevent();
else
- sizeof_struct_kevent = -1;
- INITIAL_CAPACITY = 16 * sizeof_struct_kevent;
+ _sizeof_struct_kevent = -1;
+ INITIAL_CAPACITY = 16 * _sizeof_struct_kevent;
}
/**
@@ -205,7 +208,7 @@ public class KqueueSelectorImpl extends AbstractSelector
key.interestOps = 0;
}
- int events_size = (2 * sizeof_struct_kevent) * keys.size();
+ int events_size = (2 * _sizeof_struct_kevent) * keys.size();
int num_events = 0;
for (Iterator it = keys.entrySet().iterator(); it.hasNext(); )
@@ -256,7 +259,7 @@ public class KqueueSelectorImpl extends AbstractSelector
if (blockedThread.isInterrupted())
timeout = 0;
n = kevent(kq, events, num_events,
- events.capacity() / sizeof_struct_kevent, timeout);
+ events.capacity() / _sizeof_struct_kevent, timeout);
}
finally
{
@@ -267,7 +270,7 @@ public class KqueueSelectorImpl extends AbstractSelector
}
//System.out.println("dump of keys selected:");
- //dump_selection_keys((ByteBuffer) events.duplicate().limit(n * sizeof_struct_kevent));
+ //dump_selection_keys((ByteBuffer) events.duplicate().limit(n * _sizeof_struct_kevent));
// Commit the operations we've just added in the call to kevent.
for (Iterator it = keys.values().iterator(); it.hasNext(); )
@@ -280,8 +283,8 @@ public class KqueueSelectorImpl extends AbstractSelector
int x = 0;
for (int i = 0; i < n; i++)
{
- events.position(x).limit(x + sizeof_struct_kevent);
- x += sizeof_struct_kevent;
+ events.position(x).limit(x + _sizeof_struct_kevent);
+ x += _sizeof_struct_kevent;
int y = fetch_key(events.slice());
KqueueSelectionKeyImpl key =
(KqueueSelectionKeyImpl) keys.get(new Integer(y));
@@ -370,7 +373,7 @@ public class KqueueSelectorImpl extends AbstractSelector
{
synchronized (keys)
{
- if (events.capacity() < (2 * sizeof_struct_kevent) * keys.size())
+ if (events.capacity() < (2 * _sizeof_struct_kevent) * keys.size())
{
int cap = events.capacity();
if (cap >= MAX_DOUBLING_CAPACITY)
@@ -380,7 +383,7 @@ public class KqueueSelectorImpl extends AbstractSelector
events = ByteBuffer.allocateDirect(cap);
}
- else if (events.capacity() > 4 * (sizeof_struct_kevent) * keys.size() + 1
+ else if (events.capacity() > 4 * (_sizeof_struct_kevent) * keys.size() + 1
&& events.capacity() > INITIAL_CAPACITY)
{
int cap = events.capacity();
@@ -437,7 +440,7 @@ public class KqueueSelectorImpl extends AbstractSelector
/**
* Return the size of a <code>struct kevent</code> on this system.
- *
+ *
* @return The size of <code>struct kevent</code>.
*/
private static native int sizeof_struct_kevent();