1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
6 * Moonlight List (moonlight-list@lists.ximian.com)
8 * Copyright 2007 Novell, Inc. (http://www.novell.com)
10 * See the LICENSE file included with the distribution for details.
16 #include <glib/gstdio.h>
20 #include "application.h"
22 #include "deployment.h"
27 Application::Application ()
29 SetObjectType (Type::APPLICATION
);
33 apply_default_style_cb
= NULL
;
34 apply_style_cb
= NULL
;
35 convert_keyframe_callback
= NULL
;
36 get_resource_cb
= NULL
;
39 Application::~Application ()
42 Deployment::GetCurrent()->UntrackPath (resource_root
);
43 RemoveDir (resource_root
);
44 g_free (resource_root
);
49 Application::GetCurrent ()
51 return Deployment::GetCurrent()->GetCurrentApplication();
55 Application::SetCurrent (Application
*application
)
57 Deployment::GetCurrent()->SetCurrentApplication (application
);
61 Application::RegisterCallbacks (ApplyDefaultStyleCallback apply_default_style_cb
,
62 ApplyStyleCallback apply_style_cb
,
63 GetResourceCallback get_resource_cb
,
64 ConvertKeyframeValueCallback convert_keyframe_callback
)
66 this->apply_default_style_cb
= apply_default_style_cb
;
67 this->apply_style_cb
= apply_style_cb
;
68 this->convert_keyframe_callback
= convert_keyframe_callback
;
69 this->get_resource_cb
= get_resource_cb
;
73 Application::ApplyDefaultStyle (FrameworkElement
*fwe
, ManagedTypeInfo
*key
)
75 if (apply_default_style_cb
)
76 apply_default_style_cb (fwe
, key
);
80 Application::ApplyStyle (FrameworkElement
*fwe
, Style
*style
)
83 apply_style_cb (fwe
, style
);
87 Application::ConvertKeyframeValue (Type::Kind kind
, DependencyProperty
*property
, Value
*original
, Value
*converted
)
89 if (convert_keyframe_callback
) {
90 convert_keyframe_callback (kind
, property
, original
, converted
);
92 converted
= new Value (*original
);
102 static void downloader_abort (gpointer data
, void *ctx
);
103 static void downloader_progress_changed (EventObject
*sender
, EventArgs
*calldata
, gpointer closure
);
104 static void downloader_complete (EventObject
*sender
, EventArgs
*calldata
, gpointer closure
);
105 static void downloader_failed (EventObject
*sender
, EventArgs
*calldata
, gpointer closure
);
106 static void downloader_write (void *data
, gint32 offset
, gint32 n
, void *closure
);
107 static void downloader_notify_size (gint64 size
, gpointer closure
);
110 Application::GetResource (const char *resourceBase
, const Uri
*uri
,
111 NotifyFunc notify_cb
, WriteFunc write_cb
,
112 DownloaderAccessPolicy policy
,
113 Cancellable
*cancellable
, gpointer user_data
)
116 g_warning ("Passing a null uri to Application::GetResource");
120 if (get_resource_cb
&& uri
&& !uri
->isAbsolute
) {
121 char *url
= uri
->ToString ();
122 ManagedStreamCallbacks stream
= get_resource_cb (resourceBase
, url
);
127 notify_cb (NotifyStarted
, NULL
, user_data
);
128 notify_cb (NotifySize
, stream
.Length (stream
.handle
), user_data
);
136 if (stream
.CanSeek (stream
.handle
))
137 stream
.Seek (stream
.handle
, 0, 0);
140 if ((nread
= stream
.Read (stream
.handle
, buf
, 0, sizeof (buf
))) <= 0)
143 write_cb (buf
, offset
, nread
, user_data
);
149 notify_cb (NotifyCompleted
, NULL
, user_data
);
151 stream
.Close (stream
.handle
);
158 // FIXME: drt 171 and 173 expect this to fail simply because the uri
159 // begins with a '/', but other drts (like 238) depend on this
160 // working. I give up.
161 if (!uri
->isAbsolute
&& uri
->path
&& uri
->path
[0] == '/')
165 //no get_resource_cb or empty stream
166 Downloader
*downloader
;
167 Surface
*surface
= Deployment::GetCurrent ()->GetSurface ();
168 if (!(downloader
= surface
->CreateDownloader ()))
171 NotifyCtx
*ctx
= g_new (NotifyCtx
, 1);
172 ctx
->user_data
= user_data
;
173 ctx
->notify_cb
= notify_cb
;
174 ctx
->write_cb
= write_cb
;
177 downloader
->AddHandler (Downloader::DownloadProgressChangedEvent
, downloader_progress_changed
, ctx
);
178 downloader
->AddHandler (Downloader::DownloadFailedEvent
, downloader_failed
, ctx
);
179 downloader
->AddHandler (Downloader::CompletedEvent
, downloader_complete
, ctx
);
183 cancellable
->SetCancelFuncAndData (downloader_abort
, downloader
, ctx
);
186 if (downloader
->Completed ()) {
188 notify_cb (NotifyCompleted
, NULL
, user_data
);
190 if (!downloader
->Started ()) {
191 downloader
->Open ("GET", (Uri
*)uri
, policy
);
192 downloader
->SetStreamFunctions (downloader_write
, downloader_notify_size
, ctx
);
201 downloader_notify_size (gint64 size
, gpointer closure
)
203 NotifyCtx
*ctx
= (NotifyCtx
*) closure
;
204 ctx
->notify_cb (NotifySize
, size
, ctx
->user_data
);
208 downloader_write (void *data
, gint32 offset
, gint32 n
, void *closure
)
210 NotifyCtx
*ctx
= (NotifyCtx
*) closure
;
211 ctx
->write_cb (data
, offset
, n
, ctx
->user_data
);
215 downloader_abort (gpointer data
, void *ctx
)
217 Downloader
*dl
= (Downloader
*) data
;
218 NotifyCtx
*nc
= (NotifyCtx
*)ctx
;
219 dl
->RemoveHandler (Downloader::DownloadProgressChangedEvent
, downloader_progress_changed
, nc
);
220 dl
->RemoveHandler (Downloader::DownloadFailedEvent
, downloader_failed
, nc
);
221 dl
->RemoveHandler (Downloader::CompletedEvent
, downloader_complete
, nc
);
226 downloader_progress_changed (EventObject
*sender
, EventArgs
*calldata
, gpointer closure
)
228 NotifyCtx
*ctx
= (NotifyCtx
*) closure
;
229 Downloader
*dl
= (Downloader
*) sender
;
230 ctx
->notify_cb (NotifyProgressChanged
, (gint64
) (100 * dl
->GetDownloadProgress ()), ctx
->user_data
);
234 downloader_complete (EventObject
*sender
, EventArgs
*calldata
, gpointer closure
)
236 NotifyCtx
*ctx
= (NotifyCtx
*) closure
;
237 ctx
->notify_cb (NotifyCompleted
, NULL
, ctx
->user_data
);
239 ((Downloader
*) sender
)->unref_delayed ();
243 downloader_failed (EventObject
*sender
, EventArgs
*calldata
, gpointer closure
)
245 NotifyCtx
*ctx
= (NotifyCtx
*) closure
;
246 ctx
->notify_cb (NotifyFailed
, NULL
, ctx
->user_data
);
248 ((Downloader
*) sender
)->unref_delayed ();
253 Application::GetResourceAsPath (const char *resourceBase
, const Uri
*uri
)
255 char *dirname
, *path
, *filename
, *url
;
256 ManagedStreamCallbacks stream
;
263 if (!get_resource_cb
|| !uri
|| uri
->isAbsolute
)
266 // construct the path name for this resource
267 filename
= uri
->ToString ();
268 CanonicalizeFilename (filename
, -1, CanonModeResource
);
269 if (uri
->GetQuery () != NULL
) {
270 char *sc
= strchr (filename
, ';');
275 path
= g_build_filename (GetResourceRoot(), filename
, NULL
);
278 if (g_stat (path
, &st
) != -1) {
279 // path exists, we're done
283 // create the directory for our resource (keeping the relative path intact)
284 dirname
= g_path_get_dirname (path
);
285 if (g_mkdir_with_parents (dirname
, 0700) == -1 && errno
!= EEXIST
) {
293 url
= uri
->ToString ();
294 stream
= get_resource_cb (resourceBase
, url
);
297 if (!stream
.handle
) {
302 // reset the stream to 0
303 if (stream
.CanSeek (stream
.handle
))
304 stream
.Seek (stream
.handle
, 0, SEEK_SET
);
306 // create and save the buffer to disk
307 if ((fd
= g_open (path
, O_WRONLY
| O_CREAT
| O_EXCL
, 0600)) == -1) {
308 stream
.Close (stream
.handle
);
313 // write the stream to disk
315 if ((nread
= stream
.Read (stream
.handle
, buf
, 0, sizeof (buf
))) <= 0)
318 if (write_all (fd
, buf
, (size_t) nread
) == -1) {
319 stream
.Close (stream
.handle
);
328 stream
.Close (stream
.handle
);
331 // check to see if the resource is zipped
332 if (!(zipfile
= unzOpen (path
))) {
333 // nope, not zipped...
337 // create a directory to contain our unzipped content
338 if (!(dirname
= CreateTempDir (path
))) {
346 // unzip the contents
347 if (!ExtractAll (zipfile
, dirname
, CanonModeResource
)) {
359 if (g_rename (dirname
, path
) == -1) {
372 Application::GetResourceRoot ()
374 if (!resource_root
) {
375 char *buf
= g_build_filename (g_get_tmp_dir (), "moonlight-app.XXXXXX", NULL
);
376 // create a root temp directory for all files
377 if (!(resource_root
= MakeTempDir (buf
)))
379 Deployment::GetCurrent()->TrackPath (resource_root
);
381 return resource_root
;