2009-09-12 Chris Toshok <toshok@ximian.com>
[moon.git] / src / application.cpp
blob175aff286e02ea1c513bd52f08ff3a894e259af5
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
2 /*
3 * application.cpp:
5 * Contact:
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.
14 #include <config.h>
16 #include <glib.h>
17 #include <glib/gstdio.h>
19 #include <sys/types.h>
20 #include <sys/stat.h>
21 #include <unistd.h>
22 #include <fcntl.h>
23 #include <errno.h>
25 #include "application.h"
26 #include "runtime.h"
27 #include "deployment.h"
28 #include "utils.h"
29 #include "uri.h"
32 Application::Application ()
34 SetObjectType (Type::APPLICATION);
36 resource_root = NULL;
38 apply_default_style_cb = NULL;
39 get_default_template_root_cb = NULL;
40 apply_style_cb = NULL;
41 convert_keyframe_callback = NULL;
42 get_resource_cb = NULL;
45 Application::~Application ()
47 if (resource_root) {
48 RemoveDir (resource_root);
49 g_free (resource_root);
53 Application*
54 Application::GetCurrent ()
56 return Deployment::GetCurrent()->GetCurrentApplication();
59 void
60 Application::SetCurrent (Application *application)
62 Deployment::GetCurrent()->SetCurrentApplication (application);
65 void
66 Application::RegisterCallbacks (ApplyDefaultStyleCallback apply_default_style_cb,
67 ApplyStyleCallback apply_style_cb,
68 GetResourceCallback get_resource_cb,
69 ConvertKeyframeValueCallback convert_keyframe_callback,
70 GetDefaultTemplateRootCallback get_default_template_root_cb)
72 this->apply_default_style_cb = apply_default_style_cb;
73 this->get_default_template_root_cb = get_default_template_root_cb;
74 this->apply_style_cb = apply_style_cb;
75 this->convert_keyframe_callback = convert_keyframe_callback;
76 this->get_resource_cb = get_resource_cb;
79 void
80 Application::ApplyDefaultStyle (FrameworkElement *fwe, ManagedTypeInfo *key)
82 if (apply_default_style_cb)
83 apply_default_style_cb (fwe, key);
86 UIElement *
87 Application::GetDefaultTemplateRoot (ContentControl *ctrl)
89 if (get_default_template_root_cb)
90 return get_default_template_root_cb (ctrl);
91 return NULL;
94 void
95 Application::ApplyStyle (FrameworkElement *fwe, Style *style)
97 if (apply_style_cb)
98 apply_style_cb (fwe, style);
101 void
102 Application::ConvertKeyframeValue (Type::Kind kind, DependencyProperty *property, Value *original, Value *converted)
104 if (convert_keyframe_callback) {
105 convert_keyframe_callback (kind, property, original, converted);
106 } else {
107 converted = new Value (*original);
111 struct NotifyCtx {
112 gpointer user_data;
113 NotifyFunc notify_cb;
114 WriteFunc write_cb;
117 static void downloader_abort (gpointer data, void *ctx);
118 static void downloader_progress_changed (EventObject *sender, EventArgs *calldata, gpointer closure);
119 static void downloader_complete (EventObject *sender, EventArgs *calldata, gpointer closure);
120 static void downloader_failed (EventObject *sender, EventArgs *calldata, gpointer closure);
121 static void downloader_write (void *data, gint32 offset, gint32 n, void *closure);
122 static void downloader_notify_size (gint64 size, gpointer closure);
124 void
125 Application::GetResource (const char *resourceBase, const Uri *uri,
126 NotifyFunc notify_cb, WriteFunc write_cb,
127 DownloaderAccessPolicy policy,
128 Cancellable *cancellable, gpointer user_data)
130 if (!uri) {
131 g_warning ("Passing a null uri to Application::GetResource");
132 return;
135 if (get_resource_cb && uri && !uri->isAbsolute) {
136 char *url = uri->ToString ();
137 ManagedStreamCallbacks stream = get_resource_cb (resourceBase, url);
138 g_free (url);
140 if (stream.handle) {
141 if (notify_cb) {
142 notify_cb (NotifyStarted, NULL, user_data);
143 notify_cb (NotifySize, stream.Length (stream.handle), user_data);
146 if (write_cb) {
147 char buf[4096];
148 int offset = 0;
149 int nread;
151 if (stream.CanSeek (stream.handle))
152 stream.Seek (stream.handle, 0, 0);
154 do {
155 if ((nread = stream.Read (stream.handle, buf, 0, sizeof (buf))) <= 0)
156 break;
158 write_cb (buf, offset, nread, user_data);
159 offset += nread;
160 } while (true);
163 if (notify_cb)
164 notify_cb (NotifyCompleted, NULL, user_data);
166 stream.Close (stream.handle);
168 return;
172 //no get_resource_cb or empty stream
173 Downloader *downloader;
174 Surface *surface = Deployment::GetCurrent ()->GetSurface ();
175 if (!(downloader = surface->CreateDownloader ()))
176 return;
178 NotifyCtx *ctx = g_new (NotifyCtx, 1);
179 ctx->user_data = user_data;
180 ctx->notify_cb = notify_cb;
181 ctx->write_cb = write_cb;
183 if (notify_cb) {
184 downloader->AddHandler (Downloader::DownloadProgressChangedEvent, downloader_progress_changed, ctx);
185 downloader->AddHandler (Downloader::DownloadFailedEvent, downloader_failed, ctx);
186 downloader->AddHandler (Downloader::CompletedEvent, downloader_complete, ctx);
189 if (cancellable) {
190 cancellable->SetCancelFuncAndData (downloader_abort, downloader, ctx);
193 if (downloader->Completed ()) {
194 if (notify_cb)
195 notify_cb (NotifyCompleted, NULL, user_data);
196 } else {
197 if (!downloader->Started ()) {
198 downloader->Open ("GET", (Uri*)uri, policy);
199 downloader->SetStreamFunctions (downloader_write, downloader_notify_size, ctx);
200 downloader->Send ();
205 static void
206 downloader_notify_size (gint64 size, gpointer closure)
208 NotifyCtx *ctx = (NotifyCtx *) closure;
209 ctx->notify_cb (NotifySize, size, ctx->user_data);
212 static void
213 downloader_write (void *data, gint32 offset, gint32 n, void *closure)
215 NotifyCtx *ctx = (NotifyCtx *) closure;
216 ctx->write_cb (data, offset, n, ctx->user_data);
219 static void
220 downloader_abort (gpointer data, void *ctx)
222 Downloader *dl = (Downloader *) data;
223 NotifyCtx *nc = (NotifyCtx *)ctx;
224 dl->RemoveHandler (Downloader::DownloadProgressChangedEvent, downloader_progress_changed, nc);
225 dl->RemoveHandler (Downloader::DownloadFailedEvent, downloader_failed, nc);
226 dl->RemoveHandler (Downloader::CompletedEvent, downloader_complete, nc);
227 dl->Abort ();
230 static void
231 downloader_progress_changed (EventObject *sender, EventArgs *calldata, gpointer closure)
233 NotifyCtx *ctx = (NotifyCtx *) closure;
234 Downloader *dl = (Downloader *) sender;
235 ctx->notify_cb (NotifyProgressChanged, (gint64) (100 * dl->GetDownloadProgress ()), ctx->user_data);
238 static void
239 downloader_complete (EventObject *sender, EventArgs *calldata, gpointer closure)
241 NotifyCtx *ctx = (NotifyCtx *) closure;
242 ctx->notify_cb (NotifyCompleted, NULL, ctx->user_data);
243 g_free (ctx);
244 ((Downloader *) sender)->unref_delayed ();
247 static void
248 downloader_failed (EventObject *sender, EventArgs *calldata, gpointer closure)
250 NotifyCtx *ctx = (NotifyCtx *) closure;
251 ctx->notify_cb (NotifyFailed, NULL, ctx->user_data);
252 g_free (ctx);
253 ((Downloader *) sender)->unref_delayed ();
256 //FIXME: nuke this!
257 char *
258 Application::GetResourceAsPath (const char *resourceBase, const Uri *uri)
260 char *dirname, *path, *filename, *url;
261 ManagedStreamCallbacks stream;
262 unzFile zipfile;
263 struct stat st;
264 char buf[4096];
265 int nread;
266 int fd;
268 if (!get_resource_cb || !uri || uri->isAbsolute)
269 return NULL;
271 if (!resource_root) {
272 // create a root temp directory for our resource files
273 if (!(resource_root = CreateTempDir ("moonlight-app")))
274 return NULL;
277 // construct the path name for this resource
278 filename = uri->ToString ();
279 CanonicalizeFilename (filename, -1, true);
280 if (uri->GetQuery () != NULL) {
281 char *sc = strchr (filename, ';');
282 if (sc)
283 *sc = '/';
286 path = g_build_filename (resource_root, filename, NULL);
287 g_free (filename);
289 if (stat (path, &st) != -1) {
290 // path exists, we're done
291 return path;
294 // create the directory for our resource (keeping the relative path intact)
295 dirname = g_path_get_dirname (path);
296 if (g_mkdir_with_parents (dirname, 0700) == -1 && errno != EEXIST) {
297 g_free (dirname);
298 g_free (path);
299 return NULL;
302 g_free (dirname);
304 url = uri->ToString ();
305 stream = get_resource_cb (resourceBase, url);
306 g_free (url);
308 if (!stream.handle) {
309 g_free (path);
310 return NULL;
313 // reset the stream to 0
314 if (stream.CanSeek (stream.handle))
315 stream.Seek (stream.handle, 0, SEEK_SET);
317 // create and save the buffer to disk
318 if ((fd = open (path, O_WRONLY | O_CREAT | O_EXCL, 0600)) == -1) {
319 stream.Close (stream.handle);
320 g_free (path);
321 return NULL;
324 // write the stream to disk
325 do {
326 if ((nread = stream.Read (stream.handle, buf, 0, sizeof (buf))) <= 0)
327 break;
329 if (write_all (fd, buf, (size_t) nread) == -1) {
330 stream.Close (stream.handle);
331 g_unlink (path);
332 g_free (path);
333 close (fd);
335 return NULL;
337 } while (true);
339 stream.Close (stream.handle);
340 close (fd);
342 // check to see if the resource is zipped
343 if (!(zipfile = unzOpen (path))) {
344 // nope, not zipped...
345 return path;
348 // create a directory to contain our unzipped content
349 dirname = g_strdup_printf ("%s.XXXXXX", path);
350 if (!MakeTempDir (dirname)) {
351 unzClose (zipfile);
352 g_free (dirname);
353 g_unlink (path);
354 g_free (path);
355 return NULL;
358 // unzip the contents
359 if (!ExtractAll (zipfile, dirname, true)) {
360 RemoveDir (dirname);
361 unzClose (zipfile);
362 g_free (dirname);
363 g_unlink (path);
364 g_free (path);
365 return NULL;
368 unzClose (zipfile);
369 g_unlink (path);
371 if (rename (dirname, path) == -1) {
372 RemoveDir (dirname);
373 g_free (dirname);
374 g_free (path);
375 return NULL;
378 g_free (dirname);
380 return path;