diff --git a/class/System.Windows/Mono/NativeMethods.cs b/class/System.Windows/Mono/NativeMethods.cs index b8b906a..e95fa66 100644 --- a/class/System.Windows/Mono/NativeMethods.cs +++ b/class/System.Windows/Mono/NativeMethods.cs @@ -65,7 +65,7 @@ namespace Mono { internal delegate void ApplyDefaultStyleCallback (IntPtr fwe_ptr, IntPtr type_info_ptr); internal delegate void ApplyStyleCallback (IntPtr fwe_ptr, IntPtr style_ptr); internal delegate void ConvertKeyframeValueCallback (Mono.Kind kind, IntPtr property, IntPtr original, out Value converted); - internal delegate IntPtr GetResourceCallback (string name, out int size); + internal delegate ManagedStreamCallbacks GetResourceCallback (string name); // Used in databinding to interact with managed objects internal delegate Value GetValueCallback (); diff --git a/class/System.Windows/System.Windows/Application.cs b/class/System.Windows/System.Windows/Application.cs index 5b0f6ab..124742e 100644 --- a/class/System.Windows/System.Windows/Application.cs +++ b/class/System.Windows/System.Windows/Application.cs @@ -387,34 +387,28 @@ namespace System.Windows { return null; } - internal static IntPtr get_resource_cb_safe (string name, out int size) + internal static ManagedStreamCallbacks get_resource_cb_safe (string name) { try { - return get_resource_cb (name, out size); + return get_resource_cb (name); } catch (Exception ex) { try { Console.WriteLine ("Moonlight: Unhandled exception in Application.get_resource_cb: {0}", ex); } catch { } } - size = 0; - return new IntPtr (); + return new ManagedStreamCallbacks (); } - - internal static IntPtr get_resource_cb (string name, out int size) + + internal static ManagedStreamCallbacks get_resource_cb (string name) { - size = 0; - try { - StreamResourceInfo info = GetResourceStream (new Uri (name, UriKind.Relative)); + StreamResourceInfo info = GetResourceStream (new Uri (name, UriKind.Relative)); - if (info == null) - return IntPtr.Zero; - - size = (int) info.Stream.Length; - return Helper.StreamToIntPtr (info.Stream); - } catch { - return IntPtr.Zero; + if (info == null) { + return new ManagedStreamCallbacks (); } + + return new StreamWrapper (info.Stream).GetCallbacks (); } internal static Assembly GetAssembly (string name) diff --git a/class/System.Windows/System.Windows/ChangeLog b/class/System.Windows/System.Windows/ChangeLog index 6b1b3d0..27aeded 100644 --- a/class/System.Windows/System.Windows/ChangeLog +++ b/class/System.Windows/System.Windows/ChangeLog @@ -1,3 +1,7 @@ +2009-07-14 Stephane Delcroix + + * Application.cs: GetResource returns a ManagedStreamCallbacks ptr + 2009-07-09 Rolf Bjarne Kvinge * Duration.cs: Subtract != Add. diff --git a/plugin/cbinding.h b/plugin/cbinding.h index 10e90a8..9dd5389 100644 --- a/plugin/cbinding.h +++ b/plugin/cbinding.h @@ -305,6 +305,7 @@ class Border; class BounceEase; class BrowserBridge; class Brush; +class Cancellable; class Canvas; class CircleEase; class Clock; @@ -755,7 +756,7 @@ struct XamlLoaderCallbacks; typedef void ( * ApplyDefaultStyleCallback ) ( FrameworkElement * fwe , ManagedTypeInfo * key ) ; typedef void ( * ApplyStyleCallback ) ( FrameworkElement * fwe , Style * style ) ; typedef void * ( * ConvertKeyframeValueCallback ) ( int kind , DependencyProperty * property , Value * original , Value * converted ) ; -typedef void * ( * GetResourceCallback ) ( const char * name , int * size ) ; +typedef ManagedStreamCallbacks ( * GetResourceCallback ) ( const char * name ) ; typedef void ( * TickCallHandler ) ( EventObject * object ) ; typedef void ( * EventHandler ) ( EventObject * sender , EventArgs * args , gpointer closure ) ; typedef void ( * ToggleNotifyHandler ) ( EventObject * sender , bool isLastRef ) ; diff --git a/src/ChangeLog b/src/ChangeLog index 0e1b397..74b02b0 100644 --- a/src/ChangeLog +++ b/src/ChangeLog @@ -1,3 +1,19 @@ +2009-07-14 Stephane Delcroix + + * bitmapimage.h|cpp: drop the downloader references, rely on + Application::GetResource () for getting from resource AND downloading. The + old downloader mechanism for v1 js callbacks. + +2009-07-14 Stephane Delcroix + + * application.h|cpp: Application.GetResource () now try to get the resource + from the managed callback, then fallback to downloading. + +2009-07-14 Stephane Delcroix + + * utils.h|cpp: Cancellable class, passed as method argument, allows + to abort an async action. + 2009-07-13 Jeffrey Stedfast * fonts.cpp (TextFont::Load): Don't g_strfreev() the families diff --git a/src/application.cpp b/src/application.cpp index 4636bd5..ec31a06 100644 --- a/src/application.cpp +++ b/src/application.cpp @@ -97,22 +97,152 @@ Application::ConvertKeyframeValue (Type::Kind kind, DependencyProperty *property } } -gpointer -Application::GetResource (const Uri *uri, int *size) +struct NotifyCtx { + gpointer user_data; + NotifyFunc notify_cb; +}; + +void downloader_abort (gpointer data); +void downloader_progress_changed (EventObject *sender, EventArgs *calldata, gpointer closure); +void downloader_complete (EventObject *sender, EventArgs *calldata, gpointer closure); +void downloader_failed (EventObject *sender, EventArgs *calldata, gpointer closure); + +void +Application::GetResource (const Uri *uri, NotifyFunc notify_cb, WriteFunc write_cb, DownloaderAccessPolicy policy, Cancellable *cancellable, gpointer user_data) { - if (get_resource_cb && uri) { + g_warning ("GetResource"); + if (!uri) { + g_warning ("Passing a null uri to Application::GetResource"); + return; + } + + if (get_resource_cb && uri && !uri->isAbsolute) { char *url = uri->ToString (); - gpointer ptr = get_resource_cb (url, size); + ManagedStreamCallbacks stream = get_resource_cb (url); g_free (url); - - return ptr; + if (stream.handle) { + g_warning ("wo oh oh, got a stream"); + if (notify_cb) { + notify_cb (NotifyStarted, NULL, user_data); + notify_cb (NotifySize, stream.Length (stream.handle), user_data); + } + + char buffer [1024]; + if (stream.CanSeek (stream.handle) && stream.Position (stream.handle) != 0) + stream.Seek (stream.handle, 0, 0); + + gint32 nread; + do { + nread = stream.Read (stream.handle, buffer, 0, 1024); + if (write_cb) + write_cb (buffer, 0, nread, user_data); + } while (nread); + + if (notify_cb) + notify_cb (NotifyCompleted, NULL, user_data); + + return; + } + } + + //no get_resource_cb or empty stream + Downloader *downloader; + Surface *surface = Deployment::GetCurrent ()->GetSurface (); + if (!(downloader = surface->CreateDownloader ())) + return; + + NotifyCtx *ctx = g_new (NotifyCtx, 1); + ctx->user_data = user_data; + ctx->notify_cb = notify_cb; + + if (notify_cb) { + downloader->AddHandler (Downloader::DownloadProgressChangedEvent, downloader_progress_changed, ctx); + downloader->AddHandler (Downloader::DownloadFailedEvent, downloader_failed, ctx); + downloader->AddHandler (Downloader::CompletedEvent, downloader_complete, ctx); } + + if (cancellable) { + cancellable->SetCancelFuncAndData (downloader_abort, downloader); + } + + if (downloader->Completed ()) { + if (notify_cb) + notify_cb (NotifyCompleted, NULL, user_data); + } else { + if (!downloader->Started ()) { + downloader->Open ("GET", (Uri*)uri, policy); + downloader->SetStreamFunctions (write_cb, NULL, user_data); + downloader->Send (); + } + } +} + +void +downloader_abort (gpointer data) +{ + Downloader *dl = (Downloader *) data; + dl->Abort (); +} + +void +downloader_progress_changed (EventObject *sender, EventArgs *calldata, gpointer closure) +{ + NotifyCtx *ctx = (NotifyCtx *) closure; + Downloader *dl = (Downloader *) sender; + ctx->notify_cb (NotifyProgressChanged, (gint64) (100 * dl->GetDownloadProgress ()), ctx->user_data); +} + +void +downloader_complete (EventObject *sender, EventArgs *calldata, gpointer closure) +{ + NotifyCtx *ctx = (NotifyCtx *) closure; + ctx->notify_cb (NotifyCompleted, NULL, ctx->user_data); + g_free (ctx); +} + +void +downloader_failed (EventObject *sender, EventArgs *calldata, gpointer closure) +{ + NotifyCtx *ctx = (NotifyCtx *) closure; + ctx->notify_cb (NotifyFailed, NULL, ctx->user_data); + g_free (ctx); +} + +//compatibility function, act like the old get_resource_cb +gpointer +Application::GetResourceAsBuffer (const Uri *uri, int *size) +{ + gpointer buffer = NULL; + + if (!uri) { + g_warning ("Passing a null uri to Application::GetResource"); + return NULL; + } + + if (get_resource_cb && uri && !uri->isAbsolute) { + char *url = uri->ToString (); + ManagedStreamCallbacks stream = get_resource_cb (url); + g_free (url); + + if (stream.handle) { + + *size = stream.Length (stream.handle); + if (!size) + return NULL; + + buffer = g_new (char, *size); + + if (stream.CanSeek (stream.handle) && stream.Position (stream.handle) != 0) + stream.Seek (stream.handle, 0, 0); - *size = 0; + stream.Read (stream.handle, buffer, 0, *size); + } + } - return NULL; + return buffer; } +//FIXME: nuke this! char * Application::GetResourceAsPath (const Uri *uri) { @@ -160,14 +290,11 @@ Application::GetResourceAsPath (const Uri *uri) g_free (dirname); // now we need to get the resource buffer and dump it to disk - url = uri->ToString (); - if (!(buf = get_resource_cb (url, &size))) { + if (!(buf = GetResourceAsBuffer (uri, &size))) { g_free (path); - g_free (url); return NULL; } - g_free (url); // create and save the buffer to disk if ((fd = open (path, O_WRONLY | O_CREAT | O_EXCL, 0600)) == -1) { diff --git a/src/application.h b/src/application.h index 1e3eb87..dc459a2 100644 --- a/src/application.h +++ b/src/application.h @@ -12,9 +12,11 @@ #include +#include "utils.h" #include "enums.h" #include "control.h" #include "dependencyobject.h" +#include "downloader.h" /* @CBindingRequisite */ typedef void (*ApplyDefaultStyleCallback)(FrameworkElement *fwe, ManagedTypeInfo *key); @@ -23,7 +25,11 @@ typedef void (*ApplyStyleCallback)(FrameworkElement *fwe, Style *style); /* @CBindingRequisite */ typedef void *(*ConvertKeyframeValueCallback)(int kind, DependencyProperty *property, Value *original, Value *converted); /* @CBindingRequisite */ -typedef void *(*GetResourceCallback)(const char *name, int *size); +typedef ManagedStreamCallbacks (*GetResourceCallback)(const char *name); + +enum NotifyType {NotifyStarted, NotifySize, NotifyProgressChanged, NotifyCompleted, NotifyFailed}; +typedef void (*NotifyFunc) (NotifyType type, gint64 args, gpointer user_data); +typedef void (*WriteFunc) (void* buf, gint32 offset, gint32 n, gpointer user_data); /* @ManagedDependencyProperties=Manual */ /* @Namespace=None */ @@ -43,7 +49,7 @@ public: void ConvertKeyframeValue (Type::Kind kind, DependencyProperty *property, Value *original, Value *converted); - gpointer GetResource (const Uri *uri, int *size); + void GetResource (const Uri *uri, NotifyFunc notify_cb, WriteFunc write_cb, DownloaderAccessPolicy policy, Cancellable *cancellable, gpointer user_data); char *GetResourceAsPath (const Uri *uri); /* @GenerateCBinding,GeneratePInvoke */ @@ -61,6 +67,7 @@ protected: virtual ~Application (); private: + gpointer GetResourceAsBuffer (const Uri *uri, int *size); ApplyDefaultStyleCallback apply_default_style_cb; ApplyStyleCallback apply_style_cb; ConvertKeyframeValueCallback convert_keyframe_callback; diff --git a/src/bitmapimage.cpp b/src/bitmapimage.cpp index 5734210..ce7f053 100644 --- a/src/bitmapimage.cpp +++ b/src/bitmapimage.cpp @@ -145,6 +145,7 @@ BitmapImage::BitmapImage () loader = NULL; error = NULL; part_name = NULL; + get_res_aborter = NULL; } BitmapImage::~BitmapImage () @@ -165,7 +166,10 @@ BitmapImage::Dispose () CleanupDownloader (); downloader->Abort (); } - + + if (get_res_aborter) + get_res_aborter->Cancel (); + BitmapSource::Dispose (); } @@ -176,36 +180,37 @@ BitmapImage::uri_source_changed_callback (EventObject *user_data) image->UriSourceChanged (); } +void resource_notify (NotifyType type, gint64 args, gpointer user_data); + void BitmapImage::UriSourceChanged () { Surface *surface = Deployment::GetCurrent ()->GetSurface (); Application *current = Application::GetCurrent (); Uri *uri = GetUriSource (); - Downloader *downloader; - - if (current && uri) { - int size = 0; - unsigned char *buffer = (unsigned char *) current->GetResource (uri, &size); - if (size > 0) { - PixbufWrite (buffer, 0, size); - PixmapComplete (); - - g_free (buffer); - return; - } - } if (surface == NULL) { SetBitmapData (NULL); return; } - if (!(downloader = surface->CreateDownloader ())) - return; + if (current && uri) { + get_res_aborter = new Cancellable (); + current->GetResource (uri, resource_notify, pixbuf_write, MediaPolicy, get_res_aborter, this); + } +} - SetDownloader (downloader, uri, NULL); - downloader->unref (); +void +resource_notify (NotifyType type, gint64 args, gpointer user_data) +{ + BitmapImage *media = (BitmapImage *) user_data; + + if (type == NotifyProgressChanged) + media->SetProgress ((double)(args)/100.0); + else if (type == NotifyFailed) + media->DownloaderFailed (); + else if (type == NotifyCompleted) + media->DownloaderComplete (); } @@ -222,6 +227,9 @@ BitmapImage::OnPropertyChanged (PropertyChangedEventArgs *args, MoonError *error downloader = NULL; } + if (get_res_aborter) + get_res_aborter->Cancel (); + if (Uri::IsNullOrEmpty (uri)) { SetBitmapData (NULL); } else { @@ -304,11 +312,12 @@ BitmapImage::DownloaderProgressChanged () void BitmapImage::DownloaderComplete () { - CleanupDownloader (); + if (downloader) + CleanupDownloader (); SetProgress (1.0); - if (loader == NULL) { + if (downloader && loader == NULL) { char *filename = downloader->GetDownloadedFilename (part_name); if (filename == NULL) { @@ -344,8 +353,10 @@ BitmapImage::DownloaderComplete () } } - downloader->unref (); - downloader = NULL; + if (downloader) { + downloader->unref (); + downloader = NULL; + } PixmapComplete (); @@ -405,10 +416,12 @@ failed: void BitmapImage::DownloaderFailed () { - CleanupDownloader (); + if (downloader) { + CleanupDownloader (); - downloader->unref (); - downloader = NULL; + downloader->unref (); + downloader = NULL; + } Emit (ImageFailedEvent, new ExceptionRoutedEventArgs ()); } diff --git a/src/bitmapimage.h b/src/bitmapimage.h index 75c1dad..a49632d 100644 --- a/src/bitmapimage.h +++ b/src/bitmapimage.h @@ -16,6 +16,7 @@ #include +#include "utils.h" #include "dependencyobject.h" #include "downloader.h" #include "bitmapsource.h" @@ -27,6 +28,7 @@ class BitmapImage : public BitmapSource { GdkPixbufLoader *loader; GError *error; char *part_name; + Cancellable *get_res_aborter; protected: virtual ~BitmapImage (); diff --git a/src/cbinding.h b/src/cbinding.h index ab5fb69..e68876a 100644 --- a/src/cbinding.h +++ b/src/cbinding.h @@ -305,6 +305,7 @@ class Border; class BounceEase; class BrowserBridge; class Brush; +class Cancellable; class Canvas; class CircleEase; class Clock; @@ -755,7 +756,7 @@ struct XamlLoaderCallbacks; typedef void ( * ApplyDefaultStyleCallback ) ( FrameworkElement * fwe , ManagedTypeInfo * key ) ; typedef void ( * ApplyStyleCallback ) ( FrameworkElement * fwe , Style * style ) ; typedef void * ( * ConvertKeyframeValueCallback ) ( int kind , DependencyProperty * property , Value * original , Value * converted ) ; -typedef void * ( * GetResourceCallback ) ( const char * name , int * size ) ; +typedef ManagedStreamCallbacks ( * GetResourceCallback ) ( const char * name ) ; typedef void ( * TickCallHandler ) ( EventObject * object ) ; typedef void ( * EventHandler ) ( EventObject * sender , EventArgs * args , gpointer closure ) ; typedef void ( * ToggleNotifyHandler ) ( EventObject * sender , bool isLastRef ) ; diff --git a/src/utils.cpp b/src/utils.cpp index 9301671..87f20a9 100644 --- a/src/utils.cpp +++ b/src/utils.cpp @@ -962,4 +962,22 @@ char *parse_rfc_1945_token (char *input, char *c, char **end) return start; } +Cancellable::Cancellable () +{ + cancel_cb = NULL; + user_data = NULL; +} +void +Cancellable::Cancel () +{ + if (cancel_cb) + cancel_cb (user_data); +} + +void +Cancellable::SetCancelFuncAndData (CancelCallback cb, gpointer data) +{ + cancel_cb = cb; + user_data = data; +} diff --git a/src/utils.h b/src/utils.h index a08e099..6475e71 100644 --- a/src/utils.h +++ b/src/utils.h @@ -138,4 +138,17 @@ public: ssize_t Read (char *buf, size_t n); }; +typedef void (*CancelCallback) (gpointer user_data); + +class Cancellable { + private: + CancelCallback cancel_cb; + gpointer user_data; + public: + Cancellable (); + + void Cancel (); + void SetCancelFuncAndData (CancelCallback cb, gpointer user_data); +}; + #endif /* __UTILS_H__ */