[f-spot: 12/40] Correctly Close and Dispose loaders and stream
- From: Stephane Delcroix <sdelcroix src gnome org>
- To: svn-commits-list gnome org
- Subject: [f-spot: 12/40] Correctly Close and Dispose loaders and stream
- Date: Wed, 24 Jun 2009 09:48:42 +0000 (UTC)
commit d7ed9a96d4eea82a9f6836bea83d07675d569c69
Author: Stephane Delcroix <stephane delcroix org>
Date: Sun Jun 21 13:50:58 2009 +0200
Correctly Close and Dispose loaders and stream
* ImageLoader.cs: Drop all the old code from AsyncPixbufLoader, override Dispose() so we know when it's disposed, Close the loader on Dispose ().
* PhotoImageView.cs: keep a ref to the current loader, move all the loading stuffs together in a #region, don't process the delegates if they're coming from an event from a previous loader.
src/ImageLoader.cs | 457 +++++--------------------------------------------
src/PhotoImageView.cs | 55 ++++--
2 files changed, 77 insertions(+), 435 deletions(-)
---
diff --git a/src/ImageLoader.cs b/src/ImageLoader.cs
index 92cd72f..81caf82 100644
--- a/src/ImageLoader.cs
+++ b/src/ImageLoader.cs
@@ -1,11 +1,12 @@
//
// Fspot.ImageLoader.cs
//
+// Copyright (c) 2009 Novell, Inc.
+//
// Author(s)
-// Larry Ewing <lewing novell com>
// Stephane Delcroix <sdelcroix novell com>
//
-// This is free softwae. See COPYING fro details
+// This is free software. See COPYING for details
//
using Gtk;
@@ -52,6 +53,9 @@ namespace FSpot {
public void Load (Uri uri)
{
+ if (is_disposed)
+ return;
+
using (ImageFile image_file = ImageFile.Create (uri)) {
image_stream = image_file.PixbufStream ();
pixbuf_orientation = image_file.Orientation;
@@ -78,11 +82,28 @@ namespace FSpot {
public PixbufOrientation PixbufOrientation {
get { return pixbuf_orientation; }
}
+
+ bool is_disposed = false;
+ public override void Dispose ()
+ {
+ is_disposed = true;
+ image_stream.Close ();
+ try {
+ Close ();
+ } catch (GLib.GException) {
+ //it's normal to get an exception here if we're closing in the early loading stages, and it's safe to ignore
+ // that exception as we don't want the loading to finish but want to cancel it.
+ }
+ base.Dispose ();
+ }
#endregion
#region event handlers
protected override void OnAreaPrepared ()
{
+ if (is_disposed)
+ return;
+
base.OnAreaPrepared ();
prepared = true;
EventHandler<AreaPreparedEventArgs> eh = AreaPrepared;
@@ -92,6 +113,9 @@ namespace FSpot {
protected override void OnAreaUpdated (int x, int y, int width, int height)
{
+ if (is_disposed)
+ return;
+
base.OnAreaUpdated (x, y, width, height);
EventHandler<AreaUpdatedEventArgs> eh = AreaUpdated;
if (eh != null)
@@ -100,6 +124,9 @@ namespace FSpot {
protected virtual void OnCompleted ()
{
+ if (is_disposed)
+ return;
+
loading = false;
EventHandler eh = Completed;
if (eh != null)
@@ -110,12 +137,15 @@ namespace FSpot {
#region private stuffs
System.IO.Stream image_stream;
- const int count = 1 << 16;
+ const int count = 1 << 16; //64k
byte [] buffer = new byte [count];
void HandleReadDone (IAsyncResult ar)
{
+ if (is_disposed)
+ return;
+
int byte_read = image_stream.EndRead (ar);
if (byte_read == 0) {
image_stream.Close ();
@@ -124,421 +154,14 @@ namespace FSpot {
}
Gtk.Application.Invoke (this, null, delegate (object sender, EventArgs e) {
- if (Write (buffer, (ulong)byte_read)) {
- image_stream.BeginRead (buffer, 0, count, HandleReadDone, null);
- } else
- OnWriteError ();
+ try {
+ if (!is_disposed && Write (buffer, (ulong)byte_read))
+ image_stream.BeginRead (buffer, 0, count, HandleReadDone, null);
+ } catch (System.ObjectDisposedException od) {
+ } catch (GLib.GException ge) {
+ }
});
}
-
- void OnWriteError ()
- {
- Console.WriteLine ("error while feeding the pixbufloader!");
- }
#endregion
-//
-// StreamWrapper stream;
-// Gdk.PixbufLoader loader;
-// Uri uri;
-// bool area_prepared = false;
-// bool done_reading = false;
-// Gdk.Pixbuf pixbuf;
-// Gdk.Pixbuf thumb;
-// PixbufOrientation orientation;
-//
-// private Gdk.AreaUpdatedHandler au;
-// private System.EventHandler ap;
-// private System.EventHandler ev;
-//
-// byte [] buffer = new byte [1 << 16];
-//
-// public event EventHandler<AreaUpdatedEventArgs> AreaUpdated;
-// public event EventHandler<AreaPreparedEventArgs> AreaPrepared;
-// public event System.EventHandler Done;
-//
-// // If the photo we just loaded has an out of date
-// // thumbnail save a new one
-// bool validate_thumbnail = true;
-//
-// // Limit pass control back to the main loop after
-// // chunk_timeout miliseconds.
-// int chunk_timeout = 75;
-//
-// Delay delay;
-// IAsyncResult result;
-//
-// Gdk.Rectangle damage;
-//
-// public AsyncPixbufLoader ()
-// {
-// delay = new Delay (0, new GLib.IdleHandler (AsyncRead));
-// ap = new System.EventHandler (HandleAreaPrepared);
-// au = new Gdk.AreaUpdatedHandler (HandleAreaUpdated);
-// ev = new System.EventHandler (HandleClosed);
-// }
-//
-// public bool Loading
-// {
-// get { return ! done_reading; }
-// }
-//
-// public bool Prepared
-// {
-// get { return area_prepared; }
-// }
-//
-// public Gdk.Pixbuf Pixbuf {
-// get { return pixbuf; }
-// }
-//
-// public Gdk.PixbufLoader Loader {
-// get { return loader; }
-// }
-//
-// private void FileLoad (ImageFile img)
-// {
-// pixbuf = img.Load ();
-// done_reading = true;
-// if (Done != null)
-// Done (this, System.EventArgs.Empty);
-// }
-//
-// public void Load (Uri uri)
-// {
-// this.uri = uri;
-//
-// delay.Stop ();
-//
-// if (!done_reading)
-// Close ();
-//
-// done_reading = false;
-// area_prepared = false;
-// damage = Gdk.Rectangle.Zero;
-//
-// using (ImageFile img = ImageFile.Create (uri)) {
-// orientation = Accelerometer.GetViewOrientation (img.Orientation);
-//
-// try {
-// PixbufOrientation thumb_orientation = Accelerometer.GetViewOrientation (PixbufOrientation.TopLeft);
-// thumb = ThumbnailFactory.LoadThumbnail (uri);
-// thumb = PixbufUtils.TransformOrientation (thumb, thumb_orientation);
-//
-// if (FSpot.ColorManagement.IsEnabled && !thumb.HasAlpha) {
-// if (img.GetProfile () == null)
-// FSpot.ColorManagement.PhotoImageView.Transform = FSpot.ColorManagement.StandardTransform ();
-// else
-// FSpot.ColorManagement.PhotoImageView.Transform = FSpot.ColorManagement.CreateTransform (thumb, img.GetProfile ());
-// }
-// else
-// FSpot.ColorManagement.PhotoImageView.Transform = null;
-// } catch (System.Exception e) {
-// if (!(e is GLib.GException))
-// Log.DebugException (e);
-// }
-//
-// System.IO.Stream nstream = img.PixbufStream ();
-// if (nstream == null) {
-// FileLoad (img);
-// return;
-// } else
-// stream = new StreamWrapper (nstream);
-//
-// loader = new Gdk.PixbufLoader ();
-// loader.AreaPrepared += ap;
-// loader.AreaUpdated += au;
-// loader.Closed += ev;
-//
-// if (AreaPrepared != null && thumb != null) {
-// pixbuf = thumb;
-// AreaPrepared (this, new AreaPreparedEventArgs (true));
-// }
-//
-// ThumbnailGenerator.Default.PushBlock ();
-// //AsyncIORead (null);
-// if (nstream is IOChannel) {
-// ((IOChannel)nstream).DataReady += IOChannelRead;
-// } else
-// delay.Start ();
-// }
-//
-// }
-//
-// private void LoadToAreaPrepared ()
-// {
-// while (!area_prepared && delay.IsPending)
-// Application.RunIteration ();
-// }
-//
-// public void LoadToDone ()
-// {
-// while (!done_reading && delay.IsPending)
-// Application.RunIteration ();
-// }
-//
-// private void Close () {
-// ThumbnailGenerator.Default.PopBlock ();
-//
-// try {
-// result = null;
-//
-// delay.Stop ();
-// if (loader != null) {
-// loader.AreaPrepared -= ap;
-// loader.AreaUpdated -= au;
-// // this can throw exceptions
-// loader.Close ();
-// }
-// } catch (System.Exception) {
-// //System.Console.WriteLine (e.ToString ());
-// if (pixbuf != null)
-// pixbuf.Dispose ();
-//
-// pixbuf = null;
-// } finally {
-// if (loader != null) {
-// loader.Closed -= ev;
-// loader.Dispose ();
-// }
-//
-// loader = null;
-//
-// if (stream != null)
-// stream.Close ();
-//
-// stream = null;
-// }
-// }
-//
-// private void UpdateListeners ()
-// {
-// Gdk.Rectangle area = damage;
-//
-// if (pixbuf != null && loader.Pixbuf != null && loader.Pixbuf != pixbuf && damage != Gdk.Rectangle.Zero)
-// area = PixbufUtils.TransformAndCopy (loader.Pixbuf, pixbuf, orientation, damage);
-//
-// if (area.Width != 0 && area.Height != 0 && AreaUpdated != null)
-// AreaUpdated (this, new AreaUpdatedEventArgs (area));
-//
-// //System.Console.WriteLine ("orig {0} tform {1}", damage.ToString (), area.ToString ());
-// damage = Gdk.Rectangle.Zero;
-// }
-//
-// private class StreamWrapper {
-// private delegate int ReadDelegate (byte [] buffer, int offset, int count);
-// System.IO.Stream stream;
-//
-// public System.IO.Stream Stream {
-// get { return stream; }
-// }
-//
-// public StreamWrapper (System.IO.Stream stream)
-// {
-// this.stream = stream;
-// }
-//
-// public int Read (byte[] buffer, int offset, int count)
-// {
-// return stream.Read (buffer, offset, count);
-// }
-//
-// public IAsyncResult BeginRead (byte [] buffer, int offset, int count, AsyncCallback cb, object state)
-// {
-// ReadDelegate del = new ReadDelegate (Read);
-// return del.BeginInvoke (buffer, offset, count, cb, state);
-// }
-//
-// public int EndRead (IAsyncResult result)
-// {
-// AsyncResult art = result as AsyncResult;
-// ReadDelegate del = art.AsyncDelegate as ReadDelegate;
-// int i = del.EndInvoke (result);
-// return i;
-// }
-//
-// public void Close ()
-// {
-// stream.Close ();
-// }
-// }
-//
-// private void IOChannelRead (object sender, DataReadEventArgs args)
-// {
-// //Console.WriteLine ("IO read {0}", args.Condition);
-//
-// if ( (System.IO.Stream)sender == stream.Stream)
-// args.Continue = AsyncRead ();
-// else {
-// args.Continue = false;
-// stream.Close ();
-// }
-//
-// return;
-// }
-//
-// private bool AsyncIORead ()
-// {
-// try {
-// if (result == null) {
-// //System.Console.WriteLine ("start read");
-// result = stream.BeginRead (buffer, 0, buffer.Length, AsyncIOEnd, stream);
-// } else {
-// //Console.WriteLine ("not done");
-// UpdateListeners ();
-// }
-// } catch (System.Exception e) {
-// System.Console.WriteLine ("In read got {0}", e);
-// }
-//
-// if (done_reading)
-// delay.Stop ();
-//
-// return ! done_reading;
-// }
-//
-// private void AsyncIOEnd (IAsyncResult iar)
-// {
-// //System.Console.WriteLine ("ioended");
-// if (stream == (StreamWrapper)iar.AsyncState)
-// Gtk.Application.Invoke (ReadDone);
-// }
-//
-// public void ReadDone (object sender, System.EventArgs args)
-// {
-// if (result == null)
-// return;
-//
-// int len = 0;
-// try {
-// len = stream.EndRead (result);
-// //System.Console.WriteLine ("read {0} bytes", len);
-// loader.Write (buffer, (ulong)len);
-// } catch (System.ObjectDisposedException od) {
-// System.Console.WriteLine ("error in endread {0}", od);
-// //delay.Start ();
-// len = -1;
-// } catch (GLib.GException e) {
-// System.Console.WriteLine (e.ToString ());
-// pixbuf = null;
-// len = -1;
-// }
-// result = null;
-//
-// if (len <= 0) {
-// if (loader.Pixbuf == null) {
-// if (pixbuf != null)
-// pixbuf.Dispose ();
-//
-// pixbuf = null;
-// }
-//
-// UpdateListeners ();
-// done_reading = true;
-// Close ();
-// return;
-// }
-// }
-//
-// private bool AsyncRead ()
-// {
-//#if false
-// return AsyncIORead ();
-//#else
-// return NormalRead ();
-//#endif
-// }
-//
-// private bool NormalRead ()
-// {
-// System.DateTime start_time = System.DateTime.Now;
-// System.TimeSpan span = start_time - start_time;
-//
-// do {
-// span = System.DateTime.Now - start_time;
-//
-// int len;
-// try {
-// len = stream.Read (buffer, 0, buffer.Length);
-// loader.Write (buffer, (ulong)len);
-// } catch (Exception) {
-// len = -1;
-// }
-//
-// if (len <= 0) {
-// if (loader.Pixbuf == null) {
-// if (pixbuf != null)
-// pixbuf.Dispose ();
-//
-// pixbuf = null;
-// }
-//
-// UpdateListeners ();
-// done_reading = true;
-// Close ();
-// return false;
-// }
-// } while (!done_reading && span.TotalMilliseconds <= chunk_timeout);
-//
-// UpdateListeners ();
-// return true;
-// }
-//
-// private void HandleAreaPrepared (object sender, System.EventArgs args)
-// {
-// pixbuf = PixbufUtils.TransformOrientation (loader.Pixbuf, orientation, false);
-//
-// if (thumb != null && pixbuf != null)
-// thumb.Composite (pixbuf, 0, 0,
-// pixbuf.Width, pixbuf.Height,
-// 0.0, 0.0,
-// pixbuf.Width/(double)thumb.Width, pixbuf.Height/(double)thumb.Height,
-// Gdk.InterpType.Bilinear, 0xff);
-//
-// if (thumb != null)
-// if (!ThumbnailFactory.ThumbnailIsValid (thumb, uri))
-// FSpot.ThumbnailGenerator.Default.Request (uri, 0, 256, 256);
-//
-// area_prepared = true;
-// if (AreaUpdated != null)
-// AreaPrepared (this, new AreaPreparedEventArgs (false));
-//
-// if (thumb != null)
-// thumb.Dispose ();
-// thumb = null;
-// }
-//
-// private void HandleAreaUpdated (object sender, Gdk.AreaUpdatedArgs args)
-// {
-// Gdk.Rectangle area = new Gdk.Rectangle (args.X, args.Y, args.Width, args.Height);
-//
-// if (damage.Width == 0 || damage.Height == 0)
-// damage = area;
-// else
-// damage = area.Union (damage);
-// }
-//
-// private void HandleClosed (object sender, System.EventArgs args)
-// {
-// // FIXME This should probably queue the
-// // thumbnail regeneration to a worker thread
-// if (validate_thumbnail && done_reading && pixbuf != null) {
-// PhotoLoader.ValidateThumbnail (uri, pixbuf);
-// }
-//
-// if (Done != null)
-// Done (this, System.EventArgs.Empty);
-//
-// ThumbnailGenerator.Default.PopBlock ();
-// }
-//
-// public void Dispose ()
-// {
-// Close ();
-//
-// if (pixbuf != null)
-// pixbuf.Dispose ();
-// }
}
-}
-
-
+}
diff --git a/src/PhotoImageView.cs b/src/PhotoImageView.cs
index 989e109..697790a 100644
--- a/src/PhotoImageView.cs
+++ b/src/PhotoImageView.cs
@@ -115,20 +115,27 @@ namespace FSpot.Widgets {
Glx.Destroy ();
}
- // Display.
- private void HandlePixbufAreaUpdated (object sender, AreaUpdatedEventArgs args)
- {
- if (!ShowProgress)
- return;
+#region loader
+ ImageLoader loader;
- Gdk.Rectangle area = this.ImageCoordsToWindow (args.Area);
- this.QueueDrawArea (area.X, area.Y, area.Width, area.Height);
+ void Load (Uri uri)
+ {
+ if (loader != null)
+ loader.Dispose ();
+
+ loader = new ImageLoader ();
+ loader.AreaPrepared += HandlePixbufPrepared;
+ loader.AreaUpdated += HandlePixbufAreaUpdated;
+ loader.Completed += HandleDone;
+ loader.Load (uri);
}
-
- private void HandlePixbufPrepared (object sender, AreaPreparedEventArgs args)
+ void HandlePixbufPrepared (object sender, AreaPreparedEventArgs args)
{
ImageLoader loader = sender as ImageLoader;
+ if (loader != this.loader)
+ return;
+
if (!ShowProgress)
return;
@@ -141,9 +148,24 @@ namespace FSpot.Widgets {
this.ZoomFit (args.ReducedResolution);
}
- private void HandleDone (object sender, System.EventArgs args)
+ void HandlePixbufAreaUpdated (object sender, AreaUpdatedEventArgs args)
+ {
+ if (loader != this.loader)
+ return;
+
+ if (!ShowProgress)
+ return;
+
+ Gdk.Rectangle area = this.ImageCoordsToWindow (args.Area);
+ this.QueueDrawArea (area.X, area.Y, area.Width, area.Height);
+ }
+
+ void HandleDone (object sender, System.EventArgs args)
{
ImageLoader loader = sender as ImageLoader;
+ if (loader != this.loader)
+ return;
+
// FIXME the error hander here needs to provide proper information and we should
// pass the state and the write exception in the args
Gdk.Pixbuf prev = this.Pixbuf;
@@ -189,11 +211,10 @@ namespace FSpot.Widgets {
if (prev != this.Pixbuf && prev != null)
prev.Dispose ();
}
+#endregion
private bool ShowProgress {
- get {
- return !(load_async != ProgressType.Full || !progressive_display);
- }
+ get { return !(load_async != ProgressType.Full || !progressive_display); }
}
// Zoom scaled between 0.0 and 1.0
@@ -253,11 +274,7 @@ namespace FSpot.Widgets {
try {
if (Item.IsValid) {
System.Uri uri = Item.Current.DefaultVersionUri;
- ImageLoader loader = new ImageLoader ();
- loader.AreaPrepared += HandlePixbufPrepared;
- loader.AreaUpdated += HandlePixbufAreaUpdated;
- loader.Completed += HandleDone;
- loader.Load (uri);
+ Load (uri);
} else
LoadErrorImage (null);
@@ -395,6 +412,8 @@ namespace FSpot.Widgets {
//loader.AreaUpdated -= HandlePixbufAreaUpdated;
//loader.AreaPrepared -= HandlePixbufPrepared;
//loader.Dispose ();
+ if (loader != null)
+ loader.Dispose ();
}
}
}
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]