This fixes some remaining locking issue in AsyncImage. There was still a
small chance of tripping into NPEs here. This also fixes the
checkImage() issue which showed up in Mauve.
2006-12-06 Roman Kennke <[EMAIL PROTECTED]>
* gnu/java/awt/peer/gtk/AsyncImage.java
(Loader.run): Synchronize on the AsyncImage to avoid threading
issues.
(addObservers): Check for obs==null outside and synchronize on
this inside to avoid locking issues.
(checkImage): New helper method.
(notifyObservers): Check that the correct lock is held and
remove actual locking.
* gnu/java/awt/peer/gtk/GtkToolkit.java
(checkImage): Added special handling for AsyncImages.
/Roman
Index: gnu/java/awt/peer/gtk/AsyncImage.java
===================================================================
RCS file: /cvsroot/classpath/classpath/gnu/java/awt/peer/gtk/AsyncImage.java,v
retrieving revision 1.4
diff -u -1 -5 -r1.4 AsyncImage.java
--- gnu/java/awt/peer/gtk/AsyncImage.java 6 Dec 2006 21:53:23 -0000 1.4
+++ gnu/java/awt/peer/gtk/AsyncImage.java 6 Dec 2006 22:19:47 -0000
@@ -114,33 +114,36 @@
}
public void run()
{
Image image;
try
{
GtkImage gtkImage = new GtkImage(url);
image = CairoSurface.getBufferedImage(gtkImage);
}
catch (IllegalArgumentException iae)
{
image = null;
}
realImage = GtkToolkit.imageOrError(image);
- notifyObservers(ImageObserver.ALLBITS | ImageObserver.HEIGHT
- | ImageObserver.WIDTH | ImageObserver.PROPERTIES);
- observers = null; // Not needed anymore.
+ synchronized (AsyncImage.this)
+ {
+ notifyObservers(ImageObserver.ALLBITS | ImageObserver.HEIGHT
+ | ImageObserver.WIDTH | ImageObserver.PROPERTIES);
+ observers = null; // Not needed anymore.
+ }
}
}
/**
* The real image. This is null as long as the image is not complete.
*/
Image realImage;
/**
* The image observers.
*
* This is package private to avoid accessor methods.
*/
HashSet observers;
@@ -200,71 +203,81 @@
return source;
}
public int getWidth(ImageObserver observer)
{
addObserver(observer);
int width = 0;
Image r = realImage;
if (r != null)
width = r.getWidth(observer);
return width;
}
void addObserver(ImageObserver obs)
{
- // This field gets null when image loading is complete and we don't
- // need to store any more observers.
- HashSet observs = observers;
- if (observs != null)
+ if (obs != null)
{
- if (obs != null)
+ synchronized (this)
{
- synchronized (observs)
+ // This field gets null when image loading is complete and we don't
+ // need to store any more observers.
+ HashSet observs = observers;
+ if (observs != null)
{
observs.add(obs);
}
+ else
+ {
+ // When the image is complete, notify the observer. Dunno if
+ // that's really needed, but to be sure.
+ obs.imageUpdate(this, ImageObserver.WIDTH
+ | ImageObserver.HEIGHT
+ |ImageObserver.ALLBITS
+ | ImageObserver.PROPERTIES, 0, 0,
+ realImage.getWidth(null),
+ realImage.getHeight(null));
+ }
}
}
- else if (obs != null)
- {
- // When the image is complete, notify the observer. Dunno if that's
- // really needed, but to be sure.
- obs.imageUpdate(this, ImageObserver.WIDTH | ImageObserver.HEIGHT
- |ImageObserver.ALLBITS | ImageObserver.PROPERTIES,
- 0, 0, realImage.getWidth(null),
- realImage.getHeight(null));
- }
}
static Image realImage(Image img, ImageObserver obs)
{
if (img instanceof AsyncImage)
{
((AsyncImage) img).addObserver(obs);
Image r = ((AsyncImage) img).realImage;
if (r != null)
img = r;
}
return img;
}
void notifyObservers(int status)
{
+ assert Thread.holdsLock(this);
// This field gets null when image loading is complete.
HashSet observs = observers;
if (observs != null)
{
- synchronized (observs)
+ Image r = realImage;
+ Iterator i = observs.iterator();
+ while (i.hasNext())
{
- Image r = realImage;
- Iterator i = observs.iterator();
- while (i.hasNext())
- {
- ImageObserver obs = (ImageObserver) i.next();
- obs.imageUpdate(this, status, 0, 0, r.getWidth(null),
- r.getHeight(null));
- }
+ ImageObserver obs = (ImageObserver) i.next();
+ obs.imageUpdate(this, status, 0, 0, r.getWidth(null),
+ r.getHeight(null));
}
}
}
+
+ int checkImage(ImageObserver obs)
+ {
+ addObserver(obs);
+ int flags = 0;
+ if (realImage != null)
+ flags = ImageObserver.ALLBITS | ImageObserver.WIDTH
+ | ImageObserver.HEIGHT | ImageObserver.PROPERTIES;
+ return flags;
+ }
}
Index: gnu/java/awt/peer/gtk/GtkToolkit.java
===================================================================
RCS file: /cvsroot/classpath/classpath/gnu/java/awt/peer/gtk/GtkToolkit.java,v
retrieving revision 1.97
diff -u -1 -5 -r1.97 GtkToolkit.java
--- gnu/java/awt/peer/gtk/GtkToolkit.java 5 Dec 2006 11:11:16 -0000 1.97
+++ gnu/java/awt/peer/gtk/GtkToolkit.java 6 Dec 2006 22:19:47 -0000
@@ -164,30 +164,33 @@
public native void beep();
private native void getScreenSizeDimensions(int[] xy);
public int checkImage (Image image, int width, int height,
ImageObserver observer)
{
int status = ImageObserver.ALLBITS
| ImageObserver.WIDTH
| ImageObserver.HEIGHT;
if (image instanceof GtkImage)
return ((GtkImage) image).checkImage (observer);
+ if (image instanceof AsyncImage)
+ return ((AsyncImage) image).checkImage(observer);
+
if (observer != null)
observer.imageUpdate (image, status,
-1, -1,
image.getWidth (observer),
image.getHeight (observer));
return status;
}
/**
* Helper to return either a Image -- the argument -- or a
* GtkImage with the errorLoading flag set if the argument is null.
*/
static Image imageOrError(Image b)
{