diff options
Diffstat (limited to 'libjava/classpath/gnu/java/awt/peer')
25 files changed, 996 insertions, 236 deletions
diff --git a/libjava/classpath/gnu/java/awt/peer/GLightweightPeer.java b/libjava/classpath/gnu/java/awt/peer/GLightweightPeer.java index 3bcaebcea62..5252e80f1e0 100644 --- a/libjava/classpath/gnu/java/awt/peer/GLightweightPeer.java +++ b/libjava/classpath/gnu/java/awt/peer/GLightweightPeer.java @@ -52,6 +52,7 @@ import java.awt.GraphicsConfiguration; import java.awt.Image; import java.awt.Insets; import java.awt.Point; +import java.awt.Rectangle; import java.awt.Toolkit; import java.awt.event.PaintEvent; import java.awt.image.ColorModel; @@ -295,4 +296,44 @@ public class GLightweightPeer public void flip(BufferCapabilities.FlipContents contents) { } public void destroyBuffers() { } + + public boolean isRestackSupported() + { + return false; + } + + public void cancelPendingPaint(int x, int y, int width, int height) + { + + } + + public void restack() + { + + } + + public Rectangle getBounds() + { + return null; + } + + public void reparent(ContainerPeer parent) + { + + } + + public void setBounds(int x, int y, int z, int width, int height) + { + + } + + public boolean isReparentSupported() + { + return false; + } + + public void layout() + { + + } } diff --git a/libjava/classpath/gnu/java/awt/peer/gtk/GdkGraphics.java b/libjava/classpath/gnu/java/awt/peer/gtk/GdkGraphics.java index a125be7b95e..160602b03bf 100644 --- a/libjava/classpath/gnu/java/awt/peer/gtk/GdkGraphics.java +++ b/libjava/classpath/gnu/java/awt/peer/gtk/GdkGraphics.java @@ -38,6 +38,8 @@ exception statement from your version. */ package gnu.java.awt.peer.gtk; +import gnu.classpath.Configuration; + import java.awt.Color; import java.awt.Dimension; import java.awt.Font; @@ -52,7 +54,17 @@ import java.text.AttributedCharacterIterator; public class GdkGraphics extends Graphics { - private final int native_state = GtkGenericPeer.getUniqueInteger(); + static + { + if (Configuration.INIT_LOAD_LIBRARY) + { + System.loadLibrary("gtkpeer"); + } + initStaticState (); + } + + static native void initStaticState(); + private final int native_state = GtkGenericPeer.getUniqueInteger (); Color color, xorColor; GtkComponentPeer component; @@ -66,6 +78,7 @@ public class GdkGraphics extends Graphics static final int GDK_COPY = 0, GDK_XOR = 2; native void initState (GtkComponentPeer component); + native void initStateUnlocked (GtkComponentPeer component); native void initState (int width, int height); native void initFromImage (GtkImage image); native void copyState (GdkGraphics g); @@ -119,6 +132,15 @@ public class GdkGraphics extends Graphics clip = new Rectangle (0, 0, d.width, d.height); } + // called back by native side: realize_cb + void initComponentGraphicsUnlocked () + { + initStateUnlocked (component); + color = component.awtComponent.getForeground (); + Dimension d = component.awtComponent.getSize (); + clip = new Rectangle (0, 0, d.width, d.height); + } + native void connectSignals (GtkComponentPeer component); public native void clearRect(int x, int y, int width, int height); @@ -327,7 +349,13 @@ public class GdkGraphics extends Graphics public void setClip (Shape clip) { - if (clip != null) + if (clip == null) + { + // Reset clipping. + Dimension d = component.awtComponent.getSize(); + setClip(new Rectangle (0, 0, d.width, d.height)); + } + else setClip(clip.getBounds()); } diff --git a/libjava/classpath/gnu/java/awt/peer/gtk/GdkGraphics2D.java b/libjava/classpath/gnu/java/awt/peer/gtk/GdkGraphics2D.java index b8203179d29..6d9aabf77d5 100644 --- a/libjava/classpath/gnu/java/awt/peer/gtk/GdkGraphics2D.java +++ b/libjava/classpath/gnu/java/awt/peer/gtk/GdkGraphics2D.java @@ -45,6 +45,7 @@ import java.awt.AlphaComposite; 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; @@ -106,8 +107,7 @@ public class GdkGraphics2D extends Graphics2D if (Configuration.INIT_LOAD_LIBRARY) System.loadLibrary("gtkpeer"); - if (GtkToolkit.useGraphics2D()) - initStaticState(); + initStaticState(); } static native void initStaticState(); @@ -132,12 +132,14 @@ public class GdkGraphics2D extends Graphics2D Composite comp; private Stack stateStack; + private native void initStateUnlocked(GtkComponentPeer component); private native void initState(GtkComponentPeer component); private native void initState(int width, int height); private native void initState(int[] pixes, int width, int height); private native void copyState(GdkGraphics2D g); public native void dispose(); private native void cairoSurfaceSetFilter(int filter); + private native void cairoSurfaceSetFilterUnlocked(int filter); native void connectSignals(GtkComponentPeer component); public void finalize() @@ -236,6 +238,21 @@ public class GdkGraphics2D extends Graphics2D stateStack = new Stack(); } + void initComponentGraphics2DUnlocked() + { + initStateUnlocked(component); + + setColorUnlocked(component.awtComponent.getForeground()); + setBackgroundUnlocked(component.awtComponent.getBackground()); + setPaintUnlocked(getColorUnlocked()); + setTransformUnlocked(new AffineTransform()); + setStrokeUnlocked(new BasicStroke()); + setRenderingHintsUnlocked(getDefaultHints()); + setFontUnlocked(new Font("SansSerif", Font.PLAIN, 12)); + + stateStack = new Stack(); + } + GdkGraphics2D(BufferedImage bimage) { this.bimage = bimage; @@ -280,25 +297,37 @@ public class GdkGraphics2D extends Graphics2D // drawing utility methods private native void drawPixels(int[] pixels, int w, int h, int stride, double[] i2u); + private native void setTexturePixelsUnlocked(int[] pixels, int w, int h, int stride); private native void setTexturePixels(int[] pixels, int w, int h, int stride); private native void setGradient(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 setGradientUnlocked(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); // simple passthroughs to cairo private native void cairoSave(); private native void cairoRestore(); private native void cairoSetMatrix(double[] m); + private native void cairoSetMatrixUnlocked(double[] m); private native void cairoSetOperator(int cairoOperator); private native void cairoSetRGBAColor(double red, double green, double blue, double alpha); + private native void cairoSetRGBAColorUnlocked(double red, double green, + double blue, double alpha); private native void cairoSetFillRule(int cairoFillRule); private native void cairoSetLineWidth(double width); + private native void cairoSetLineWidthUnlocked(double width); private native void cairoSetLineCap(int cairoLineCap); + private native void cairoSetLineCapUnlocked(int cairoLineCap); private native void cairoSetLineJoin(int cairoLineJoin); + private native void cairoSetLineJoinUnlocked(int cairoLineJoin); private native void cairoSetDash(double[] dashes, int ndash, double offset); + private native void cairoSetDashUnlocked(double[] dashes, int ndash, double offset); private native void cairoSetMiterLimit(double limit); + private native void cairoSetMiterLimitUnlocked(double limit); private native void cairoNewPath(); private native void cairoMoveTo(double x, double y); private native void cairoLineTo(double x, double y); @@ -689,6 +718,49 @@ public class GdkGraphics2D extends Graphics2D throw new java.lang.UnsupportedOperationException(); } + public void setPaintUnlocked(Paint p) + { + if (paint == null) + return; + + paint = p; + if (paint instanceof Color) + { + setColorUnlocked((Color) paint); + } + else if (paint instanceof TexturePaint) + { + TexturePaint tp = (TexturePaint) paint; + BufferedImage img = tp.getImage(); + + // map the image to the anchor rectangle + int width = (int) tp.getAnchorRect().getWidth(); + int height = (int) tp.getAnchorRect().getHeight(); + + double scaleX = width / (double) img.getWidth(); + double scaleY = width / (double) img.getHeight(); + + AffineTransform at = new AffineTransform(scaleX, 0, 0, scaleY, 0, 0); + AffineTransformOp op = new AffineTransformOp(at, getRenderingHints()); + BufferedImage texture = op.filter(img, null); + int[] pixels = texture.getRGB(0, 0, width, height, null, 0, width); + setTexturePixelsUnlocked(pixels, width, height, width); + } + else if (paint instanceof GradientPaint) + { + GradientPaint gp = (GradientPaint) paint; + Point2D p1 = gp.getPoint1(); + Point2D p2 = gp.getPoint2(); + Color c1 = gp.getColor1(); + Color c2 = gp.getColor2(); + setGradientUnlocked(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(); + } + public void setTransform(AffineTransform tx) { transform = tx; @@ -700,6 +772,17 @@ public class GdkGraphics2D extends Graphics2D } } + public void setTransformUnlocked(AffineTransform tx) + { + transform = tx; + if (transform != null) + { + double[] m = new double[6]; + transform.getMatrix(m); + cairoSetMatrixUnlocked(m); + } + } + public void transform(AffineTransform tx) { if (transform == null) @@ -784,6 +867,32 @@ public class GdkGraphics2D extends Graphics2D cairoSetDash(double_dashes, double_dashes.length, (double) bs.getDashPhase()); } + else + cairoSetDash(new double[0], 0, 0.0); + } + } + + public void setStrokeUnlocked(Stroke st) + { + stroke = st; + if (stroke instanceof BasicStroke) + { + BasicStroke bs = (BasicStroke) stroke; + cairoSetLineCapUnlocked(bs.getEndCap()); + cairoSetLineWidthUnlocked(bs.getLineWidth()); + cairoSetLineJoinUnlocked(bs.getLineJoin()); + cairoSetMiterLimitUnlocked(bs.getMiterLimit()); + float[] dashes = bs.getDashArray(); + if (dashes != null) + { + double[] double_dashes = new double[dashes.length]; + for (int i = 0; i < dashes.length; i++) + double_dashes[i] = dashes[i]; + cairoSetDashUnlocked(double_dashes, double_dashes.length, + (double) bs.getDashPhase()); + } + else + cairoSetDashUnlocked(new double[0], 0, 0.0); } } @@ -812,11 +921,27 @@ public class GdkGraphics2D extends Graphics2D fg.getBlue() / 255.0, fg.getAlpha() / 255.0); } + public void setColorUnlocked(Color c) + { + if (c == null) + c = Color.BLACK; + + fg = c; + paint = c; + cairoSetRGBAColorUnlocked(fg.getRed() / 255.0, fg.getGreen() / 255.0, + fg.getBlue() / 255.0, fg.getAlpha() / 255.0); + } + public Color getColor() { return fg; } + public Color getColorUnlocked() + { + return getColor(); + } + public void clipRect(int x, int y, int width, int height) { clip(new Rectangle(x, y, width, height)); @@ -864,7 +989,13 @@ public class GdkGraphics2D extends Graphics2D public void setClip(Shape s) { clip = s; - if (s != null) + if (clip == null) + { + // Reset clipping. + Dimension d = component.awtComponent.getSize(); + setClip(0, 0, d.width, d.height); + } + else { cairoNewPath(); if (s instanceof Rectangle2D) @@ -929,6 +1060,11 @@ public class GdkGraphics2D extends Graphics2D bg = c; } + public void setBackgroundUnlocked(Color c) + { + setBackground(c); + } + public Color getBackground() { return bg; @@ -1180,6 +1316,36 @@ public class GdkGraphics2D extends Graphics2D || hints.containsValue(RenderingHints.VALUE_STROKE_DEFAULT); } + public void setRenderingHintsUnlocked(Map hints) + { + this.hints = new RenderingHints(getDefaultHints()); + this.hints.add(new RenderingHints(hints)); + + if (hints.containsKey(RenderingHints.KEY_INTERPOLATION)) + { + if (hints.containsValue(RenderingHints.VALUE_INTERPOLATION_NEAREST_NEIGHBOR)) + cairoSurfaceSetFilterUnlocked(0); + + else if (hints.containsValue(RenderingHints.VALUE_INTERPOLATION_BILINEAR)) + cairoSurfaceSetFilterUnlocked(1); + } + + if (hints.containsKey(RenderingHints.KEY_ALPHA_INTERPOLATION)) + { + if (hints.containsValue(RenderingHints.VALUE_ALPHA_INTERPOLATION_SPEED)) + cairoSurfaceSetFilterUnlocked(2); + + else if (hints.containsValue(RenderingHints.VALUE_ALPHA_INTERPOLATION_QUALITY)) + cairoSurfaceSetFilterUnlocked(3); + + else if (hints.containsValue(RenderingHints.VALUE_ALPHA_INTERPOLATION_DEFAULT)) + cairoSurfaceSetFilterUnlocked(4); + } + + shiftDrawCalls = hints.containsValue(RenderingHints.VALUE_STROKE_NORMALIZE) + || hints.containsValue(RenderingHints.VALUE_STROKE_DEFAULT); + } + public void addRenderingHints(Map hints) { this.hints.add(new RenderingHints(hints)); @@ -1344,6 +1510,9 @@ public class GdkGraphics2D extends Graphics2D public void drawString(String str, float x, float y) { + if (str == null || str.length() == 0) + return; + drawGlyphVector(getFont().createGlyphVector(null, str), x, y); updateBufferedImage (); } @@ -1443,6 +1612,11 @@ public class GdkGraphics2D extends Graphics2D .getFont(f.getName(), f.getAttributes()); } + public void setFontUnlocked(Font f) + { + setFont (f); + } + public String toString() { return (getClass().getName() diff --git a/libjava/classpath/gnu/java/awt/peer/gtk/GdkGraphicsConfiguration.java b/libjava/classpath/gnu/java/awt/peer/gtk/GdkGraphicsConfiguration.java index bfad87acac0..6cf7310a550 100644 --- a/libjava/classpath/gnu/java/awt/peer/gtk/GdkGraphicsConfiguration.java +++ b/libjava/classpath/gnu/java/awt/peer/gtk/GdkGraphicsConfiguration.java @@ -42,6 +42,7 @@ import java.awt.GraphicsConfiguration; import java.awt.GraphicsDevice; import java.awt.ImageCapabilities; import java.awt.Rectangle; +import java.awt.Toolkit; import java.awt.geom.AffineTransform; @@ -56,16 +57,11 @@ public class GdkGraphicsConfiguration ColorModel cm; Rectangle bounds; - public GtkToolkit getToolkit() - { - return gdkScreenGraphicsDevice.getToolkit(); - } - public GdkGraphicsConfiguration(GdkScreenGraphicsDevice dev) { this.gdkScreenGraphicsDevice = dev; cm = new BufferedImage(1, 1, BufferedImage.TYPE_INT_ARGB).getColorModel(); - bounds = getToolkit().getBounds(); + bounds = ((GtkToolkit) Toolkit.getDefaultToolkit()).getBounds(); } public GraphicsDevice getDevice() @@ -135,4 +131,10 @@ public class GdkGraphicsConfiguration return new ImageCapabilities(false); } + public VolatileImage createCompatibleVolatileImage(int width, int height, int transparency) + { + // FIXME: implement + return null; + } + } diff --git a/libjava/classpath/gnu/java/awt/peer/gtk/GdkGraphicsEnvironment.java b/libjava/classpath/gnu/java/awt/peer/gtk/GdkGraphicsEnvironment.java index 4f9d1c27af6..4b0b5d30893 100644 --- a/libjava/classpath/gnu/java/awt/peer/gtk/GdkGraphicsEnvironment.java +++ b/libjava/classpath/gnu/java/awt/peer/gtk/GdkGraphicsEnvironment.java @@ -43,22 +43,14 @@ 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.util.Locale; public class GdkGraphicsEnvironment extends GraphicsEnvironment { - GtkToolkit gtkToolkit; - - public GtkToolkit getToolkit() - { - return gtkToolkit; - } - - public GdkGraphicsEnvironment (GtkToolkit tk) + public GdkGraphicsEnvironment () { - super(); - gtkToolkit = tk; } public GraphicsDevice[] getScreenDevices () diff --git a/libjava/classpath/gnu/java/awt/peer/gtk/GdkPixbufDecoder.java b/libjava/classpath/gnu/java/awt/peer/gtk/GdkPixbufDecoder.java index 57d5a36da3a..85cb1e47a9e 100644 --- a/libjava/classpath/gnu/java/awt/peer/gtk/GdkPixbufDecoder.java +++ b/libjava/classpath/gnu/java/awt/peer/gtk/GdkPixbufDecoder.java @@ -122,7 +122,7 @@ public class GdkPixbufDecoder extends gnu.java.awt.image.ImageDecoder super (imagedata, imageoffset, imagelength); } - // called back by native side + // called back by native side: area_prepared_cb void areaPrepared (int width, int height) { @@ -138,7 +138,7 @@ public class GdkPixbufDecoder extends gnu.java.awt.image.ImageDecoder } } - // called back by native side + // called back by native side: area_updated_cb void areaUpdated (int x, int y, int width, int height, int pixels[], int scansize) { @@ -306,7 +306,7 @@ public class GdkPixbufDecoder extends gnu.java.awt.image.ImageDecoder static String findFormatName(Object ext, boolean needWritable) { if (ext == null) - throw new IllegalArgumentException("extension is null"); + return null; if (!(ext instanceof String)) throw new IllegalArgumentException("extension is not a string"); diff --git a/libjava/classpath/gnu/java/awt/peer/gtk/GdkScreenGraphicsDevice.java b/libjava/classpath/gnu/java/awt/peer/gtk/GdkScreenGraphicsDevice.java index 2bf9d23db94..b5d1237a45d 100644 --- a/libjava/classpath/gnu/java/awt/peer/gtk/GdkScreenGraphicsDevice.java +++ b/libjava/classpath/gnu/java/awt/peer/gtk/GdkScreenGraphicsDevice.java @@ -42,16 +42,12 @@ import java.awt.Dimension; import java.awt.DisplayMode; import java.awt.GraphicsConfiguration; import java.awt.GraphicsDevice; +import java.awt.Toolkit; public class GdkScreenGraphicsDevice extends GraphicsDevice { GdkGraphicsEnvironment env; - public GtkToolkit getToolkit() - { - return env.getToolkit(); - } - public GdkScreenGraphicsDevice (GdkGraphicsEnvironment e) { super (); @@ -94,7 +90,7 @@ public class GdkScreenGraphicsDevice extends GraphicsDevice public DisplayMode getDisplayMode() { // determine display mode - Dimension dim = getToolkit().getScreenSize(); + Dimension dim = Toolkit.getDefaultToolkit().getScreenSize(); DisplayMode mode = new DisplayMode(dim.width, dim.height, 0, DisplayMode.REFRESH_RATE_UNKNOWN); return mode; diff --git a/libjava/classpath/gnu/java/awt/peer/gtk/GtkButtonPeer.java b/libjava/classpath/gnu/java/awt/peer/gtk/GtkButtonPeer.java index ab5df9f463f..054ead6d601 100644 --- a/libjava/classpath/gnu/java/awt/peer/gtk/GtkButtonPeer.java +++ b/libjava/classpath/gnu/java/awt/peer/gtk/GtkButtonPeer.java @@ -42,10 +42,14 @@ import java.awt.AWTEvent; import java.awt.Button; import java.awt.Component; import java.awt.Point; +import java.awt.event.ActionEvent; import java.awt.event.KeyEvent; import java.awt.event.MouseEvent; import java.awt.peer.ButtonPeer; +// A composite widget. GtkButtons have transparent backgrounds. An +// AWT Button is opaque. To compensate, a GtkButtonPeer is a +// GtkButton packed in a GtkEventBox. public class GtkButtonPeer extends GtkComponentPeer implements ButtonPeer { @@ -61,6 +65,11 @@ public class GtkButtonPeer extends GtkComponentPeer native void gtkWidgetRequestFocus (); native void setNativeBounds (int x, int y, int width, int height); + // Because this is a composite widget, we need to retrieve the + // GtkButton's preferred dimensions, not the enclosing + // GtkEventBox's. + native void gtkWidgetGetPreferredDimensions (int[] dim); + public GtkButtonPeer (Button b) { super (b); @@ -76,32 +85,11 @@ public class GtkButtonPeer extends GtkComponentPeer gtkSetLabel(label); } - public void handleEvent (AWTEvent e) + void postActionEvent (int mods) { - if (e.getID () == MouseEvent.MOUSE_RELEASED && isEnabled ()) - { - MouseEvent me = (MouseEvent) e; - Point p = me.getPoint(); - p.translate(((Component) me.getSource()).getX(), - ((Component) me.getSource()).getY()); - if (!me.isConsumed () - && (me.getModifiersEx () & MouseEvent.BUTTON1_DOWN_MASK) != 0 - && awtComponent.getBounds().contains(p)) - postActionEvent (((Button) awtComponent).getActionCommand (), - me.getModifiersEx ()); - } - - if (e.getID () == KeyEvent.KEY_PRESSED) - { - KeyEvent ke = (KeyEvent) e; - if (!ke.isConsumed () && ke.getKeyCode () == KeyEvent.VK_SPACE) - { - postActionEvent (((Button) awtComponent).getActionCommand (), - ke.getModifiersEx ()); - gtkActivate (); - } - } - - super.handleEvent (e); + q().postEvent (new ActionEvent (awtWidget, + ActionEvent.ACTION_PERFORMED, + ((Button) awtComponent).getActionCommand (), + mods)); } } diff --git a/libjava/classpath/gnu/java/awt/peer/gtk/GtkCheckboxPeer.java b/libjava/classpath/gnu/java/awt/peer/gtk/GtkCheckboxPeer.java index 851757245aa..3e05cf8ab07 100644 --- a/libjava/classpath/gnu/java/awt/peer/gtk/GtkCheckboxPeer.java +++ b/libjava/classpath/gnu/java/awt/peer/gtk/GtkCheckboxPeer.java @@ -49,6 +49,7 @@ public class GtkCheckboxPeer extends GtkComponentPeer public GtkCheckboxGroupPeer old_group; // The current state of the GTK checkbox. private boolean currentState; + private boolean changing = false; public native void create (GtkCheckboxGroupPeer group); public native void nativeSetCheckboxGroup (GtkCheckboxGroupPeer group); @@ -76,6 +77,15 @@ public class GtkCheckboxPeer extends GtkComponentPeer public void setState (boolean state) { + // prevent item_toggled_cb -> postItemEvent -> + // awtComponent.setState -> this.setState -> + // gtkToggleButtonSetActive self-deadlock on the GDK lock. + if (changing && Thread.currentThread() == GtkToolkit.mainThread) + { + changing = false; + return; + } + if (currentState != state) gtkToggleButtonSetActive (state); } @@ -100,6 +110,7 @@ public class GtkCheckboxPeer extends GtkComponentPeer // Override the superclass postItemEvent so that the peer doesn't // need information that we have. + // called back by native side: item_toggled_cb public void postItemEvent (Object item, int stateChange) { Checkbox currentCheckBox = ((Checkbox)awtComponent); @@ -113,6 +124,7 @@ public class GtkCheckboxPeer extends GtkComponentPeer { super.postItemEvent (awtComponent, stateChange); currentState = !currentCheckBox.getState(); + changing = true; currentCheckBox.setState(currentState); } } diff --git a/libjava/classpath/gnu/java/awt/peer/gtk/GtkChoicePeer.java b/libjava/classpath/gnu/java/awt/peer/gtk/GtkChoicePeer.java index 5028ea779c7..c140744397a 100644 --- a/libjava/classpath/gnu/java/awt/peer/gtk/GtkChoicePeer.java +++ b/libjava/classpath/gnu/java/awt/peer/gtk/GtkChoicePeer.java @@ -74,8 +74,17 @@ public class GtkChoicePeer extends GtkComponentPeer native void connectSignals (); - public native void select (int position); - + native void selectNative (int position); + native void selectNativeUnlocked (int position); + + public void select (int position) + { + if (Thread.currentThread() == GtkToolkit.mainThread) + selectNativeUnlocked (position); + else + selectNative (position); + } + public void add (String item, int index) { int before = nativeGetSelected(); diff --git a/libjava/classpath/gnu/java/awt/peer/gtk/GtkClipboard.java b/libjava/classpath/gnu/java/awt/peer/gtk/GtkClipboard.java index c719cddb575..a502e1fd6ef 100644 --- a/libjava/classpath/gnu/java/awt/peer/gtk/GtkClipboard.java +++ b/libjava/classpath/gnu/java/awt/peer/gtk/GtkClipboard.java @@ -38,133 +38,357 @@ exception statement from your version. */ package gnu.java.awt.peer.gtk; -import java.awt.datatransfer.Clipboard; -import java.awt.datatransfer.ClipboardOwner; -import java.awt.datatransfer.DataFlavor; -import java.awt.datatransfer.StringSelection; -import java.awt.datatransfer.Transferable; -import java.io.IOException; -import java.io.InputStream; -import java.io.InputStreamReader; +import java.awt.Image; +import java.awt.datatransfer.*; + +import java.io.*; + +import java.util.List; +import java.util.Iterator; public class GtkClipboard extends Clipboard { - /* the number of milliseconds that we'll wait around for the - owner of the GDK_SELECTION_PRIMARY selection to convert - the requested data */ - static final int SELECTION_RECEIVED_TIMEOUT = 5000; - /* We currently only support transferring of text between applications */ - static String selection; - static Object selectionLock = new Object (); + // Given to the native side so it can signal special targets that + // can be converted to one of the special predefined DataFlavors. + static final String stringMimeType; + static final String imageMimeType; + static final String filesMimeType; + + // Indicates whether the results of the clipboard selection can be + // cached by GtkSelection. True if + // gdk_display_supports_selection_notification. + static final boolean canCache; + + static + { + stringMimeType = DataFlavor.stringFlavor.getMimeType(); + imageMimeType = DataFlavor.imageFlavor.getMimeType(); + filesMimeType = DataFlavor.javaFileListFlavor.getMimeType(); + + canCache = initNativeState(stringMimeType, imageMimeType, filesMimeType); + } - static boolean hasSelection = false; + /** + * The one and only gtk+ clipboard instance. + */ + private static GtkClipboard instance = new GtkClipboard(); - protected GtkClipboard() + /** + * Creates the clipboard and sets the initial contents to the + * current gtk+ selection. + */ + private GtkClipboard() { super("System Clipboard"); - initNativeState(); + setContents(new GtkSelection(), null); + } + + /** + * Returns the one and only GtkClipboard instance. + */ + + static GtkClipboard getInstance() + { + return instance; } - public Transferable getContents(Object requestor) + /** + * Sets the GtkSelection facade as new contents of the clipboard. + * Called from gtk+ when another application grabs the clipboard and + * we loose ownership. + */ + private static void setSystemContents() { - synchronized (this) + GtkClipboardNotifier.announce(); + } + + /** + * Sets the new contents and advertises the available flavors to the + * gtk+ clipboard. + */ + public synchronized void setContents(Transferable contents, + ClipboardOwner owner) + { + super.setContents(contents, owner); + + if (contents == null) { - if (hasSelection) - return contents; + advertiseContent(null, false, false, false); + return; } - /* Java doesn't own the selection, so we need to ask X11 */ - // XXX: Does this hold with Swing too ? - synchronized (selectionLock) + // We don't need to do anything for a GtkSelection facade. + if (contents instanceof GtkSelection) + return; + + boolean text = false; + boolean images = false; + boolean files = false; + + if (contents instanceof StringSelection + || contents.isDataFlavorSupported(DataFlavor.stringFlavor) + || contents.isDataFlavorSupported(DataFlavor.plainTextFlavor) + || contents.isDataFlavorSupported(DataFlavor + .getTextPlainUnicodeFlavor())) + text = true; + + DataFlavor[] flavors = contents.getTransferDataFlavors(); + String[] mimeTargets = new String[flavors.length]; + for (int i = 0; i < flavors.length; i++) { - requestStringConversion(); - - try - { - selectionLock.wait(SELECTION_RECEIVED_TIMEOUT); - } - catch (InterruptedException e) + DataFlavor flavor = flavors[i]; + String mimeType = flavor.getMimeType(); + mimeTargets[i] = mimeType; + + if (! text) + if ("text".equals(flavor.getPrimaryType()) + || flavor.isRepresentationClassReader()) + text = true; + + // XXX - We only support automatic image conversion for + // GtkImages at the moment. So explicitly check that we have + // one. + if (! images && flavors[i].equals(DataFlavor.imageFlavor)) { - return null; + try + { + Object o = contents.getTransferData(DataFlavor.imageFlavor); + if (o instanceof GtkImage) + images = true; + } + catch (UnsupportedFlavorException ufe) + { + } + catch (IOException ioe) + { + } + catch (ClassCastException cce) + { + } } - - return selection == null ? null : new StringSelection(selection); + + if (flavors[i].equals(DataFlavor.javaFileListFlavor)) + files = true; } + + advertiseContent(mimeTargets, text, images, files); } - void stringSelectionReceived(String newSelection) + /** + * Advertises new contents to the gtk+ clipboard given a string + * array of (mime-type) targets. When the boolean flags text, images + * and/or files are set then gtk+ is asked to also advertise the + * availability of any text, image or uri/file content types it + * supports. If targets is null (and all flags false) then the + * selection has explicitly been erased. + */ + private native void advertiseContent(String[] targets, + boolean text, + boolean images, + boolean files); + + /** + * Called by the gtk+ clipboard when an application has requested + * text. Return a string representing the current clipboard + * contents or null when no text can be provided. + */ + private String provideText() { - synchronized (selectionLock) + Transferable contents = this.contents; + if (contents == null || contents instanceof GtkSelection) + return null; + + // Handle StringSelection special since that is just pure text. + if (contents instanceof StringSelection) { - selection = newSelection; - selectionLock.notify(); + try + { + return (String) contents.getTransferData(DataFlavor.stringFlavor); + } + catch (UnsupportedFlavorException ufe) + { + } + catch (IOException ioe) + { + } + catch (ClassCastException cce) + { + } } - } - - /* convert Java clipboard data into a String suitable for sending - to another application */ - synchronized String stringSelectionHandler() throws IOException - { - String selection = null; + // Try to get a plain text reader for the current contents and + // turn the result into a string. try { - if (contents.isDataFlavorSupported(DataFlavor.stringFlavor)) - selection = (String)contents.getTransferData(DataFlavor.stringFlavor); - else if (contents.isDataFlavorSupported(DataFlavor.plainTextFlavor)) + DataFlavor plainText = DataFlavor.getTextPlainUnicodeFlavor(); + Reader r = plainText.getReaderForText(contents); + if (r != null) { - StringBuffer sbuf = new StringBuffer(); - InputStreamReader reader; - char readBuf[] = new char[512]; - int numChars; - - reader = new InputStreamReader - ((InputStream) - contents.getTransferData(DataFlavor.plainTextFlavor), "UNICODE"); - - while (true) + StringBuffer sb = new StringBuffer(); + char[] cs = new char[1024]; + int l = r.read(cs); + while (l != -1) { - numChars = reader.read(readBuf); - if (numChars == -1) - break; - sbuf.append(readBuf, 0, numChars); + sb.append(cs, 0, l); + l = r.read(cs); } - - selection = new String(sbuf); + return sb.toString(); } } - catch (Exception e) + catch (IllegalArgumentException iae) + { + } + catch (UnsupportedEncodingException iee) { } - - return selection; + catch (UnsupportedFlavorException ufe) + { + } + catch (IOException ioe) + { + } + + return null; } - public synchronized void setContents(Transferable contents, - ClipboardOwner owner) + /** + * Called by the gtk+ clipboard when an application has requested an + * image. Returns a GtkImage representing the current clipboard + * contents or null when no image can be provided. + */ + private GtkImage provideImage() + { + Transferable contents = this.contents; + if (contents == null || contents instanceof GtkSelection) + return null; + + try + { + return (GtkImage) contents.getTransferData(DataFlavor.imageFlavor); + } + catch (UnsupportedFlavorException ufe) + { + } + catch (IOException ioe) + { + } + catch (ClassCastException cce) + { + } + + return null; + } + + /** + * Called by the gtk+ clipboard when an application has requested a + * uri-list. Return a string array containing the URIs representing + * the current clipboard contents or null when no URIs can be + * provided. + */ + private String[] provideURIs() { - selectionGet(); + Transferable contents = this.contents; + if (contents == null || contents instanceof GtkSelection) + return null; - this.contents = contents; - this.owner = owner; + try + { + List list = (List) contents.getTransferData + (DataFlavor.javaFileListFlavor); + String[] uris = new String[list.size()]; + int u = 0; + Iterator it = list.iterator(); + while (it.hasNext()) + uris[u++] = ((File) it.next()).toURI().toString(); + return uris; + } + catch (UnsupportedFlavorException ufe) + { + } + catch (IOException ioe) + { + } + catch (ClassCastException cce) + { + } - hasSelection = true; + return null; } - synchronized void selectionClear() + /** + * Called by gtk+ clipboard when an application requests the given + * target mime-type. Returns a byte array containing the requested + * data, or null when the contents cannot be provided in the + * requested target mime-type. Only called after any explicit text, + * image or file/uri requests have been handled earlier and failed. + */ + private byte[] provideContent(String target) { - hasSelection = false; + // Sanity check. The callback could be triggered just after we + // changed the clipboard. + Transferable contents = this.contents; + if (contents == null || contents instanceof GtkSelection) + return null; + + // XXX - We are being called from a gtk+ callback. Which means we + // should return as soon as possible and not call arbitrary code + // that could deadlock or go bonkers. But we don't really know + // what DataTransfer contents object we are dealing with. Same for + // the other provideXXX() methods. + try + { + DataFlavor flavor = new DataFlavor(target); + Object o = contents.getTransferData(flavor); + + if (o instanceof byte[]) + return (byte[]) o; + + if (o instanceof InputStream) + { + InputStream is = (InputStream) o; + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + byte[] bs = new byte[1024]; + int l = is.read(bs); + while (l != -1) + { + baos.write(bs, 0, l); + l = is.read(bs); + } + return baos.toByteArray(); + } - if (owner != null) + if (o instanceof Serializable) + { + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + ObjectOutputStream oos = new ObjectOutputStream(baos); + oos.writeObject(o); + oos.close(); + return baos.toByteArray(); + } + } + catch (ClassNotFoundException cnfe) + { + } + catch (UnsupportedFlavorException ufe) { - owner.lostOwnership(this, contents); - owner = null; - contents = null; } + catch (IOException ioe) + { + } + catch (ClassCastException cce) + { + } + + return null; } - native void initNativeState(); - static native void requestStringConversion(); - static native void selectionGet(); + /** + * Initializes the gtk+ clipboard and caches any native side + * structures needed. Returns whether or not the contents of the + * Clipboard can be cached (gdk_display_supports_selection_notification). + */ + private static native boolean initNativeState(String stringTarget, + String imageTarget, + String filesTarget); } diff --git a/libjava/classpath/gnu/java/awt/peer/gtk/GtkComponentPeer.java b/libjava/classpath/gnu/java/awt/peer/gtk/GtkComponentPeer.java index 1578a9cfc3c..60e8371277f 100644 --- a/libjava/classpath/gnu/java/awt/peer/gtk/GtkComponentPeer.java +++ b/libjava/classpath/gnu/java/awt/peer/gtk/GtkComponentPeer.java @@ -70,6 +70,9 @@ import java.awt.image.ImageObserver; import java.awt.image.ImageProducer; import java.awt.image.VolatileImage; import java.awt.peer.ComponentPeer; +import java.awt.peer.ContainerPeer; +import java.util.Timer; +import java.util.TimerTask; public class GtkComponentPeer extends GtkGenericPeer implements ComponentPeer @@ -83,6 +86,8 @@ public class GtkComponentPeer extends GtkGenericPeer boolean isInRepaint; + static final Timer repaintTimer = new Timer (true); + /* this isEnabled differs from Component.isEnabled, in that it knows if a parent is disabled. In that case Component.isEnabled may return true, but our isEnabled will always return false */ @@ -95,6 +100,7 @@ public class GtkComponentPeer extends GtkGenericPeer native void gtkWidgetGetPreferredDimensions (int[] dim); native void gtkWidgetGetLocationOnScreen (int[] point); native void gtkWidgetSetCursor (int type); + native void gtkWidgetSetCursorUnlocked (int type); native void gtkWidgetSetBackground (int red, int green, int blue); native void gtkWidgetSetForeground (int red, int green, int blue); native void gtkWidgetSetSensitive (boolean sensitive); @@ -372,8 +378,26 @@ public class GtkComponentPeer extends GtkGenericPeer if (x == 0 && y == 0 && width == 0 && height == 0) return; - q().postEvent (new PaintEvent (awtComponent, PaintEvent.UPDATE, - new Rectangle (x, y, width, height))); + repaintTimer.schedule(new RepaintTimerTask(x, y, width, height), tm); + } + + private class RepaintTimerTask extends TimerTask + { + private int x, y, width, height; + + RepaintTimerTask(int x, int y, int width, int height) + { + this.x = x; + this.y = y; + this.width = width; + this.height = height; + } + + public void run() + { + q().postEvent (new PaintEvent (awtComponent, PaintEvent.UPDATE, + new Rectangle (x, y, width, height))); + } } public void requestFocus () @@ -396,7 +420,11 @@ public class GtkComponentPeer extends GtkGenericPeer public void setBounds (int x, int y, int width, int height) { + int new_x = x; + int new_y = y; + Component parent = awtComponent.getParent (); + Component next_parent; // Heavyweight components that are children of one or more // lightweight containers have to be handled specially. Because @@ -414,30 +442,44 @@ public class GtkComponentPeer extends GtkGenericPeer { lightweightChild = true; + next_parent = parent.getParent (); + i = ((Container) parent).getInsets (); - x += parent.getX () + i.left; - y += parent.getY () + i.top; + if (next_parent instanceof Window) + { + new_x += i.left; + new_y += i.top; + } + else + { + new_x += parent.getX () + i.left; + new_y += parent.getY () + i.top; + } - parent = parent.getParent (); + parent = next_parent; } // We only need to convert from Java to GTK coordinates if we're // placing a heavyweight component in a Window. if (parent instanceof Window && !lightweightChild) { - Insets insets = ((Window) parent).getInsets (); GtkWindowPeer peer = (GtkWindowPeer) parent.getPeer (); + // important: we want the window peer's insets here, not the + // window's, since user sub-classes of Window can override + // getInset and we only want to correct for the frame borders, + // not for any user-defined inset values + Insets insets = peer.getInsets (); + int menuBarHeight = 0; if (peer instanceof GtkFramePeer) menuBarHeight = ((GtkFramePeer) peer).getMenuBarHeight (); - // Convert from Java coordinates to GTK coordinates. - setNativeBounds (x - insets.left, y - insets.top + menuBarHeight, - width, height); + new_x = x - insets.left; + new_y = y - insets.top + menuBarHeight; } - else - setNativeBounds (x, y, width, height); + + setNativeBounds (new_x, new_y, width, height); } void setCursor () @@ -447,7 +489,10 @@ public class GtkComponentPeer extends GtkGenericPeer public void setCursor (Cursor cursor) { - gtkWidgetSetCursor (cursor.getType ()); + if (Thread.currentThread() == GtkToolkit.mainThread) + gtkWidgetSetCursorUnlocked (cursor.getType ()); + else + gtkWidgetSetCursor (cursor.getType ()); } public void setEnabled (boolean b) @@ -480,16 +525,26 @@ public class GtkComponentPeer extends GtkGenericPeer return new Color (rgb[0], rgb[1], rgb[2]); } + public native void setVisibleNative (boolean b); + public native void setVisibleNativeUnlocked (boolean b); + public void setVisible (boolean b) { - if (b) - show (); + if (Thread.currentThread() == GtkToolkit.mainThread) + setVisibleNativeUnlocked (b); else - hide (); + setVisibleNative (b); + } + + public void hide () + { + setVisible (false); } - public native void hide (); - public native void show (); + public void show () + { + setVisible (true); + } protected void postMouseEvent(int id, long when, int mods, int x, int y, int clickCount, boolean popupTrigger) @@ -586,7 +641,8 @@ public class GtkComponentPeer extends GtkGenericPeer public void updateCursorImmediately () { - + if (awtComponent.getCursor() != null) + setCursor(awtComponent.getCursor()); } public boolean handlesWheelScrolling () @@ -648,4 +704,36 @@ public class GtkComponentPeer extends GtkGenericPeer { backBuffer.flush(); } + + public String toString () + { + return "peer of " + awtComponent.toString(); + } + public Rectangle getBounds() + { + // FIXME: implement + return null; + } + public void reparent(ContainerPeer parent) + { + // FIXME: implement + + } + public void setBounds(int x, int y, int width, int height, int z) + { + // FIXME: implement + setBounds (x, y, width, height); + + } + public boolean isReparentSupported() + { + // FIXME: implement + + return false; + } + public void layout() + { + // FIXME: implement + + } } diff --git a/libjava/classpath/gnu/java/awt/peer/gtk/GtkContainerPeer.java b/libjava/classpath/gnu/java/awt/peer/gtk/GtkContainerPeer.java index c2865f70f61..b035a9814c7 100644 --- a/libjava/classpath/gnu/java/awt/peer/gtk/GtkContainerPeer.java +++ b/libjava/classpath/gnu/java/awt/peer/gtk/GtkContainerPeer.java @@ -52,7 +52,6 @@ public class GtkContainerPeer extends GtkComponentPeer implements ContainerPeer { Container c; - boolean isValidating; public GtkContainerPeer(Container c) { @@ -62,7 +61,6 @@ public class GtkContainerPeer extends GtkComponentPeer public void beginValidate () { - isValidating = true; } public void endValidate () @@ -90,8 +88,6 @@ public class GtkContainerPeer extends GtkComponentPeer if (!(awtComponent instanceof Window)) setParentAndBounds (); } - - isValidating = false; } public Insets getInsets() @@ -153,4 +149,21 @@ public class GtkContainerPeer extends GtkComponentPeer comp.getPeer().setBackground(c); } } + + public boolean isRestackSupported() + { + // FIXME: implement + return false; + } + + public void cancelPendingPaint(int x, int y, int width, int height) + { + // FIXME: implement + } + + public void restack() + { + //FIXME: implement + + } } diff --git a/libjava/classpath/gnu/java/awt/peer/gtk/GtkFileDialogPeer.java b/libjava/classpath/gnu/java/awt/peer/gtk/GtkFileDialogPeer.java index bd1f0775a92..333407b247f 100644 --- a/libjava/classpath/gnu/java/awt/peer/gtk/GtkFileDialogPeer.java +++ b/libjava/classpath/gnu/java/awt/peer/gtk/GtkFileDialogPeer.java @@ -42,6 +42,7 @@ import java.awt.Dialog; import java.awt.FileDialog; import java.awt.Graphics; import java.awt.Window; +import java.awt.event.ComponentEvent; import java.awt.peer.FileDialogPeer; import java.io.File; import java.io.FilenameFilter; @@ -54,7 +55,7 @@ public class GtkFileDialogPeer extends GtkDialogPeer implements FileDialogPeer private String currentDirectory = null; private FilenameFilter filter; - native void create (GtkContainerPeer parent); + native void create (GtkContainerPeer parent, int mode); native void connectSignals (); native void nativeSetFile (String file); public native String nativeGetDirectory(); @@ -63,7 +64,8 @@ public class GtkFileDialogPeer extends GtkDialogPeer implements FileDialogPeer public void create() { - create((GtkContainerPeer) awtComponent.getParent().getPeer()); + create((GtkContainerPeer) awtComponent.getParent().getPeer(), + ((FileDialog) awtComponent).getMode()); FileDialog fd = (FileDialog) awtComponent; @@ -87,10 +89,10 @@ public class GtkFileDialogPeer extends GtkDialogPeer implements FileDialogPeer { int[] dims = new int[2]; gtkWidgetGetPreferredDimensions (dims); - ((GtkFileDialogPeer) this).setBoundsCallback ((Window) awtComponent, - awtComponent.getX (), - awtComponent.getY (), - dims[0], dims[1]); + + if (dims[0] != awtComponent.getWidth() + || dims[1] != awtComponent.getHeight()) + awtComponent.setSize(dims[0], dims[1]); } super.setComponentBounds (); } @@ -155,6 +157,7 @@ public class GtkFileDialogPeer extends GtkDialogPeer implements FileDialogPeer GtkFileFilterInfo object and send it to this method, which will in turn call the filter's accept() method and give back the return value. */ + // called back by native side: filename_filter_cb boolean filenameFilterCallback (String fullname) { String filename = fullname.substring(fullname.lastIndexOf(FS) + 1); String dirname = fullname.substring(0, fullname.lastIndexOf(FS)); @@ -167,20 +170,25 @@ public class GtkFileDialogPeer extends GtkDialogPeer implements FileDialogPeer // GtkFileDialog will repaint by itself return null; } - + + // called back by native side: handle_response_cb + // only called from the GTK thread void gtkHideFileDialog () { + // hide calls back the peer's setVisible method, so locking is a + // problem. ((Dialog) awtComponent).hide(); } + // called back by native side: handle_response_cb void gtkDisposeFileDialog () { ((Dialog) awtComponent).dispose(); } - /* Callback to set the file and directory values when the user is finished - * with the dialog. - */ + // Callback to set the file and directory values when the user is finished + // with the dialog. + // called back by native side: handle_response_cb void gtkSetFilename (String fileName) { FileDialog fd = (FileDialog) awtWidget; diff --git a/libjava/classpath/gnu/java/awt/peer/gtk/GtkFramePeer.java b/libjava/classpath/gnu/java/awt/peer/gtk/GtkFramePeer.java index b242d66adcb..6eb90ffa0bd 100644 --- a/libjava/classpath/gnu/java/awt/peer/gtk/GtkFramePeer.java +++ b/libjava/classpath/gnu/java/awt/peer/gtk/GtkFramePeer.java @@ -44,6 +44,7 @@ import java.awt.Image; import java.awt.MenuBar; import java.awt.Rectangle; import java.awt.Window; +import java.awt.event.ComponentEvent; import java.awt.event.PaintEvent; import java.awt.image.ColorModel; import java.awt.peer.FramePeer; @@ -55,6 +56,7 @@ public class GtkFramePeer extends GtkWindowPeer private int menuBarHeight; private MenuBarPeer menuBar; native int getMenuBarHeight (MenuBarPeer bar); + native void setMenuBarWidthUnlocked (MenuBarPeer bar, int width); native void setMenuBarWidth (MenuBarPeer bar, int width); native void setMenuBarPeer (MenuBarPeer bar); native void removeMenuBarPeer (); @@ -117,6 +119,17 @@ public class GtkFramePeer extends GtkWindowPeer public void setBounds (int x, int y, int width, int height) { + // prevent window_configure_cb -> awtComponent.setSize -> + // peer.setBounds -> nativeSetBounds self-deadlock on GDK lock. + if (Thread.currentThread() == GtkToolkit.mainThread) + { + int menuBarWidth = width - insets.left - insets.right; + if (menuBar != null && menuBarWidth > 0) + setMenuBarWidthUnlocked (menuBar, menuBarWidth); + + return; + } + int menuBarWidth = width - insets.left - insets.right; if (menuBar != null && menuBarWidth > 0) setMenuBarWidth (menuBar, menuBarWidth); @@ -192,31 +205,25 @@ public class GtkFramePeer extends GtkWindowPeer protected void postConfigureEvent (int x, int y, int width, int height) { - int frame_x = x - insets.left; - // Since insets.top includes the MenuBar height, we need to add back - // the MenuBar height to the frame's y position. - // If no MenuBar exists in this frame, the MenuBar height will be 0. - int frame_y = y - insets.top + menuBarHeight; int frame_width = width + insets.left + insets.right; - // Ditto as above. Since insets.top already includes the MenuBar's height, - // we need to subtract the MenuBar's height from the top inset. + // Since insets.top already includes the MenuBar's height, we need + // to subtract the MenuBar's height from the top inset. int frame_height = height + insets.top + insets.bottom - menuBarHeight; - if (frame_x != awtComponent.getX() - || frame_y != awtComponent.getY() - || frame_width != awtComponent.getWidth() + + if (frame_width != awtComponent.getWidth() || frame_height != awtComponent.getHeight()) - { - if (frame_width != awtComponent.getWidth() && menuBar != null - && width > 0) - setMenuBarWidth (menuBar, width); + awtComponent.setSize(frame_width, frame_height); - setBoundsCallback ((Window) awtComponent, - frame_x, - frame_y, - frame_width, - frame_height); + int frame_x = x - insets.left; + // Likewise, since insets.top includes the MenuBar height, we need + // to add back the MenuBar height to the frame's y position. If + // no MenuBar exists in this frame, the MenuBar height will be 0. + int frame_y = y - insets.top + menuBarHeight; - awtComponent.validate(); + if (frame_x != awtComponent.getX() + || frame_y != awtComponent.getY()) + { + // awtComponent.setLocation(frame_x, frame_y); } } @@ -251,6 +258,21 @@ public class GtkFramePeer extends GtkWindowPeer { } + public void setBoundsPrivate(int x, int y, int width, int height) + { + // TODO Auto-generated method stub + + } + public void updateAlwaysOnTop() + { + // TODO Auto-generated method stub + + } + public boolean requestWindowFocus() + { + // TODO Auto-generated method stub + return false; + } } diff --git a/libjava/classpath/gnu/java/awt/peer/gtk/GtkImage.java b/libjava/classpath/gnu/java/awt/peer/gtk/GtkImage.java index abb4137f4ae..82a346304ea 100644 --- a/libjava/classpath/gnu/java/awt/peer/gtk/GtkImage.java +++ b/libjava/classpath/gnu/java/awt/peer/gtk/GtkImage.java @@ -51,7 +51,10 @@ import java.io.File; import java.io.IOException; import java.util.Hashtable; import java.util.Vector; -import gnu.classpath.RawData; +import java.io.ByteArrayOutputStream; +import java.io.BufferedInputStream; +import java.net.URL; +import gnu.classpath.Pointer; /** * GtkImage - wraps a GdkPixbuf or GdkPixmap. @@ -87,7 +90,7 @@ public class GtkImage extends Image /** * Pointer to the GdkPixbuf */ - RawData pixmap; + Pointer pixmap; /** * Observer queue. @@ -129,11 +132,16 @@ public class GtkImage extends Image private native void setPixels(int[] pixels); /** - * Loads an image using gdk-pixbuf. + * Loads an image using gdk-pixbuf from a file. */ private native boolean loadPixbuf(String name); /** + * Loads an image using gdk-pixbuf from data. + */ + private native boolean loadImageFromData(byte[] data); + + /** * Allocates a Gtk Pixbuf or pixmap */ private native void createPixmap(); @@ -187,6 +195,21 @@ public class GtkImage extends Image } /** + * Constructs a blank GtkImage. This is called when + * GtkToolkit.createImage (String) is called with an empty string + * argument (""). A blank image is loaded immediately upon + * construction and has width -1 and height -1. + */ + public GtkImage () + { + isLoaded = true; + observers = null; + offScreen = false; + props = new Hashtable(); + errorLoading = false; + } + + /** * Constructs a GtkImage by loading a given file. * * @throws IllegalArgumentException if the image could not be loaded. @@ -211,6 +234,58 @@ public class GtkImage extends Image } /** + * Constructs a GtkImage from a byte array of an image file. + * + * @throws IllegalArgumentException if the image could not be + * loaded. + */ + public GtkImage (byte[] data) + { + if (loadImageFromData (data) != true) + throw new IllegalArgumentException ("Couldn't load image."); + + isLoaded = true; + observers = null; + offScreen = false; + props = new Hashtable(); + errorLoading = false; + } + + /** + * Constructs a GtkImage from a URL. May result in an error image. + */ + public GtkImage (URL url) + { + isLoaded = false; + observers = new Vector(); + errorLoading = false; + if( url == null) + return; + ByteArrayOutputStream baos = new ByteArrayOutputStream (5000); + try + { + BufferedInputStream bis = new BufferedInputStream (url.openStream()); + + byte[] buf = new byte[5000]; + int n = 0; + + while ((n = bis.read(buf)) != -1) + baos.write(buf, 0, n); + bis.close(); + } + catch(IOException e) + { + throw new IllegalArgumentException ("Couldn't load image."); + } + if (loadImageFromData (baos.toByteArray()) != true) + throw new IllegalArgumentException ("Couldn't load image."); + + isLoaded = true; + observers = null; + props = new Hashtable(); + } + + /** * Constructs an empty GtkImage. */ public GtkImage (int width, int height) @@ -241,6 +316,25 @@ public class GtkImage extends Image } /** + * Package private constructor to create a GtkImage from a given + * PixBuf pointer. + */ + GtkImage (Pointer pixbuf) + { + pixmap = pixbuf; + createFromPixbuf(); + isLoaded = true; + observers = null; + offScreen = false; + props = new Hashtable(); + } + + /** + * Native helper function for constructor that takes a pixbuf Pointer. + */ + private native void createFromPixbuf(); + + /** * Callback from the image consumer. */ public void setImage(int width, int height, diff --git a/libjava/classpath/gnu/java/awt/peer/gtk/GtkImageConsumer.java b/libjava/classpath/gnu/java/awt/peer/gtk/GtkImageConsumer.java index 564cc8d668c..299f01dcaa6 100644 --- a/libjava/classpath/gnu/java/awt/peer/gtk/GtkImageConsumer.java +++ b/libjava/classpath/gnu/java/awt/peer/gtk/GtkImageConsumer.java @@ -45,6 +45,7 @@ import java.awt.image.DirectColorModel; import java.awt.image.ImageConsumer; import java.awt.image.ImageObserver; import java.awt.image.ImageProducer; +import java.awt.image.MemoryImageSource; import java.util.Hashtable; import java.util.Vector; @@ -70,7 +71,10 @@ public class GtkImageConsumer implements ImageConsumer public synchronized void imageComplete (int status) { - source.removeConsumer(this); + // we need to reuse the pixel cache for memory image sources since + // a memory image's backing array can be updated "live". + if (!(source instanceof MemoryImageSource)) + source.removeConsumer(this); target.setImage(width, height, pixelCache, properties); } diff --git a/libjava/classpath/gnu/java/awt/peer/gtk/GtkLabelPeer.java b/libjava/classpath/gnu/java/awt/peer/gtk/GtkLabelPeer.java index fdd5fd15f63..3d099e9ca00 100644 --- a/libjava/classpath/gnu/java/awt/peer/gtk/GtkLabelPeer.java +++ b/libjava/classpath/gnu/java/awt/peer/gtk/GtkLabelPeer.java @@ -41,6 +41,9 @@ package gnu.java.awt.peer.gtk; import java.awt.Label; import java.awt.peer.LabelPeer; +// A composite widget. GtkLabels have transparent backgrounds. An +// AWT Label is opaque. To compensate, a GtkLabelPeer is a GtkLabel +// packed in a GtkEventBox. public class GtkLabelPeer extends GtkComponentPeer implements LabelPeer { @@ -51,6 +54,10 @@ public class GtkLabelPeer extends GtkComponentPeer public native void setText(String text); native void setNativeBounds (int x, int y, int width, int height); + // Because this is a composite widget, we need to retrieve the + // GtkLabel's preferred dimensions, not the enclosing GtkEventBox's. + native void gtkWidgetGetPreferredDimensions (int[] dim); + void create () { Label label = (Label) awtComponent; diff --git a/libjava/classpath/gnu/java/awt/peer/gtk/GtkMenuBarPeer.java b/libjava/classpath/gnu/java/awt/peer/gtk/GtkMenuBarPeer.java index 79eeaf9ba6a..a1a1cbd6d7c 100644 --- a/libjava/classpath/gnu/java/awt/peer/gtk/GtkMenuBarPeer.java +++ b/libjava/classpath/gnu/java/awt/peer/gtk/GtkMenuBarPeer.java @@ -77,4 +77,9 @@ public class GtkMenuBarPeer extends GtkMenuComponentPeer } public native void delMenu(int index); + + public void addMenu (Menu m) + { + // FIXME: implement + } } diff --git a/libjava/classpath/gnu/java/awt/peer/gtk/GtkMenuComponentPeer.java b/libjava/classpath/gnu/java/awt/peer/gtk/GtkMenuComponentPeer.java index 8d9d1ca04a0..4c6335933a8 100644 --- a/libjava/classpath/gnu/java/awt/peer/gtk/GtkMenuComponentPeer.java +++ b/libjava/classpath/gnu/java/awt/peer/gtk/GtkMenuComponentPeer.java @@ -38,6 +38,7 @@ exception statement from your version. */ package gnu.java.awt.peer.gtk; +import java.awt.Font; import java.awt.peer.MenuComponentPeer; public class GtkMenuComponentPeer extends GtkGenericPeer @@ -60,4 +61,9 @@ public class GtkMenuComponentPeer extends GtkGenericPeer } public native void dispose(); + + public void setFont(Font font) + { + // FIXME: implement + } } diff --git a/libjava/classpath/gnu/java/awt/peer/gtk/GtkMenuPeer.java b/libjava/classpath/gnu/java/awt/peer/gtk/GtkMenuPeer.java index 80332dd6a72..fabcf1f090b 100644 --- a/libjava/classpath/gnu/java/awt/peer/gtk/GtkMenuPeer.java +++ b/libjava/classpath/gnu/java/awt/peer/gtk/GtkMenuPeer.java @@ -100,4 +100,9 @@ public class GtkMenuPeer extends GtkMenuItemPeer } public native void delItem(int index); + + public void addSeparator() + { + // FIXME: implement + } } diff --git a/libjava/classpath/gnu/java/awt/peer/gtk/GtkTextAreaPeer.java b/libjava/classpath/gnu/java/awt/peer/gtk/GtkTextAreaPeer.java index a842b8318a2..e6896c9136c 100644 --- a/libjava/classpath/gnu/java/awt/peer/gtk/GtkTextAreaPeer.java +++ b/libjava/classpath/gnu/java/awt/peer/gtk/GtkTextAreaPeer.java @@ -43,6 +43,7 @@ import java.awt.Font; import java.awt.FontMetrics; import java.awt.Rectangle; import java.awt.TextArea; +import java.awt.im.InputMethodRequests; import java.awt.peer.TextAreaPeer; import java.awt.peer.TextComponentPeer; @@ -209,4 +210,10 @@ public class GtkTextAreaPeer extends GtkComponentPeer { insert (str, pos); } + + public InputMethodRequests getInputMethodRequests() + { + // FIXME: implement + return null; + } } diff --git a/libjava/classpath/gnu/java/awt/peer/gtk/GtkTextFieldPeer.java b/libjava/classpath/gnu/java/awt/peer/gtk/GtkTextFieldPeer.java index 73a976bba6d..4afdae82e5e 100644 --- a/libjava/classpath/gnu/java/awt/peer/gtk/GtkTextFieldPeer.java +++ b/libjava/classpath/gnu/java/awt/peer/gtk/GtkTextFieldPeer.java @@ -45,6 +45,7 @@ import java.awt.FontMetrics; import java.awt.Rectangle; import java.awt.TextField; import java.awt.event.KeyEvent; +import java.awt.im.InputMethodRequests; import java.awt.peer.TextFieldPeer; import java.awt.peer.TextComponentPeer; @@ -193,4 +194,9 @@ public class GtkTextFieldPeer extends GtkComponentPeer super.handleEvent (e); } + public InputMethodRequests getInputMethodRequests() + { + // FIXME: implement + return null; + } } diff --git a/libjava/classpath/gnu/java/awt/peer/gtk/GtkToolkit.java b/libjava/classpath/gnu/java/awt/peer/gtk/GtkToolkit.java index 69901102faf..0889d85f4bc 100644 --- a/libjava/classpath/gnu/java/awt/peer/gtk/GtkToolkit.java +++ b/libjava/classpath/gnu/java/awt/peer/gtk/GtkToolkit.java @@ -88,9 +88,9 @@ public class GtkToolkit extends gnu.java.awt.ClasspathToolkit { Hashtable containers = new Hashtable(); static EventQueue q; - static Clipboard systemClipboard; static boolean useGraphics2dSet; static boolean useGraphics2d; + static Thread mainThread; public static boolean useGraphics2D() { @@ -121,11 +121,19 @@ public class GtkToolkit extends gnu.java.awt.ClasspathToolkit portableNativeSync = 0; // false gtkInit(portableNativeSync); + + mainThread = new Thread ("GTK main thread") + { + public void run () + { + gtkMain (); + } + }; + mainThread.start (); } public GtkToolkit () { - systemClipboard = new GtkClipboard (); } public native void beep(); @@ -244,6 +252,9 @@ public class GtkToolkit extends gnu.java.awt.ClasspathToolkit public Image createImage (String filename) { + if (filename.length() == 0) + return new GtkImage (); + if (useGraphics2D()) return bufferedImageOrError(GdkPixbufDecoder.createBufferedImage (filename)); else @@ -255,11 +266,7 @@ public class GtkToolkit extends gnu.java.awt.ClasspathToolkit if (useGraphics2D()) return bufferedImageOrError(GdkPixbufDecoder.createBufferedImage (url)); else - { - GdkPixbufDecoder d = new GdkPixbufDecoder (url); - GtkImage image = new GtkImage (d); - return image; - } + return new GtkImage (url); } public Image createImage (ImageProducer producer) @@ -279,11 +286,9 @@ public class GtkToolkit extends gnu.java.awt.ClasspathToolkit imagelength)); else { - GdkPixbufDecoder d = new GdkPixbufDecoder (imagedata, - imageoffset, - imagelength); - GtkImage image = new GtkImage (d); - return image; + byte[] datacopy = new byte[imagelength]; + System.arraycopy (imagedata, imageoffset, datacopy, 0, imagelength); + return new GtkImage (datacopy); } } @@ -395,7 +400,11 @@ public class GtkToolkit extends gnu.java.awt.ClasspathToolkit public Clipboard getSystemClipboard() { - return systemClipboard; + SecurityManager secman = System.getSecurityManager(); + if (secman != null) + secman.checkSystemClipboardAccess(); + + return GtkClipboard.getInstance(); } /** @@ -628,7 +637,7 @@ public class GtkToolkit extends gnu.java.awt.ClasspathToolkit public GraphicsEnvironment getLocalGraphicsEnvironment() { - return new GdkGraphicsEnvironment(this); + return new GdkGraphicsEnvironment(); } public Font createFont(int format, InputStream stream) @@ -646,8 +655,5 @@ public class GtkToolkit extends gnu.java.awt.ClasspathToolkit GdkPixbufDecoder.registerSpis(reg); } - public native boolean nativeQueueEmpty(); - public native void wakeNativeQueue(); - public native void iterateNativeQueue(EventQueue locked, boolean block); - + public static native void gtkMain(); } // class GtkToolkit diff --git a/libjava/classpath/gnu/java/awt/peer/gtk/GtkWindowPeer.java b/libjava/classpath/gnu/java/awt/peer/gtk/GtkWindowPeer.java index 71e05a87dad..c84d51037e3 100644 --- a/libjava/classpath/gnu/java/awt/peer/gtk/GtkWindowPeer.java +++ b/libjava/classpath/gnu/java/awt/peer/gtk/GtkWindowPeer.java @@ -41,6 +41,7 @@ package gnu.java.awt.peer.gtk; import java.awt.Component; import java.awt.Frame; import java.awt.Window; +import java.awt.event.ComponentEvent; import java.awt.event.WindowEvent; import java.awt.peer.WindowPeer; @@ -104,6 +105,9 @@ public class GtkWindowPeer extends GtkContainerPeer { } + public native void setVisibleNative (boolean b); + public native void setVisibleNativeUnlocked (boolean b); + native void connectSignals (); public GtkWindowPeer (Window window) @@ -115,14 +119,27 @@ public class GtkWindowPeer extends GtkContainerPeer public native void toFront(); native void nativeSetBounds (int x, int y, int width, int height); + native void nativeSetBoundsUnlocked (int x, int y, int width, int height); public void setBounds (int x, int y, int width, int height) { + // prevent window_configure_cb -> awtComponent.setSize -> + // peer.setBounds -> nativeSetBounds self-deadlock on GDK lock. + if (Thread.currentThread() == GtkToolkit.mainThread) + return; + nativeSetBounds (x, y, width - insets.left - insets.right, height - insets.top - insets.bottom); } + public void setBoundsUnlocked (int x, int y, int width, int height) + { + nativeSetBoundsUnlocked (x, y, + width - insets.left - insets.right, + height - insets.top - insets.bottom); + } + public void setTitle (String title) { gtkWindowSetTitle (title); @@ -140,10 +157,6 @@ public class GtkWindowPeer extends GtkContainerPeer gtkWindowSetResizable (resizable); } - native void setBoundsCallback (Window window, - int x, int y, - int width, int height); - protected void postInsetsChangedEvent (int top, int left, int bottom, int right) { @@ -153,36 +166,36 @@ public class GtkWindowPeer extends GtkContainerPeer insets.right = right; } + // called back by native side: window_configure_cb + // 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; - if (frame_x != awtComponent.getX() - || frame_y != awtComponent.getY() - || frame_width != awtComponent.getWidth() + if (frame_width != awtComponent.getWidth() || frame_height != awtComponent.getHeight()) - { - setBoundsCallback ((Window) awtComponent, - frame_x, frame_y, frame_width, frame_height); + awtComponent.setSize(frame_width, frame_height); - awtComponent.validate(); + int frame_x = x - insets.left; + int frame_y = y - insets.top; + + if (frame_x != awtComponent.getX() + || frame_y != awtComponent.getY()) + { + // awtComponent.setLocation(frame_x, frame_y); } } - native void nativeSetVisible (boolean b); - public void setVisible (boolean b) + public void show () { // Prevent the window manager from automatically placing this // window when it is shown. - if (b) - setBounds (awtComponent.getX(), - awtComponent.getY(), - awtComponent.getWidth(), - awtComponent.getHeight()); - nativeSetVisible (b); + setBounds (awtComponent.getX(), + awtComponent.getY(), + awtComponent.getWidth(), + awtComponent.getHeight()); + setVisible (true); } void postWindowEvent (int id, Window opposite, int newState) @@ -209,4 +222,14 @@ public class GtkWindowPeer extends GtkContainerPeer else q().postEvent (new WindowEvent ((Window) awtComponent, id, opposite)); } + public void updateAlwaysOnTop() + { + // TODO Auto-generated method stub + + } + public boolean requestWindowFocus() + { + // TODO Auto-generated method stub + return false; + } } |