2009-08-26 Chris Toshok <toshok@ximian.com>
[moon.git] / plugin / plugin.cpp
blob414c1a5003e631500fe6f0a229e3cf619c275ac6
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
2 /*
3 * moon-plugin.cpp: MoonLight browser plugin.
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 <fcntl.h>
18 #include <stdlib.h>
19 #include <dlfcn.h>
21 #include "plugin.h"
22 #include "plugin-spinner.h"
23 #include "plugin-class.h"
24 #include "plugin-debug.h"
25 #include "browser-bridge.h"
26 #include "downloader.h"
27 #include "pipeline-ui.h"
28 #include "plugin-downloader.h"
29 #include "npstream-request.h"
30 #include "xap.h"
31 #include "windowless.h"
32 #include "window-gtk.h"
33 #include "unzip.h"
34 #include "deployment.h"
35 #include "uri.h"
36 #include "timemanager.h"
38 #define Visual _XxVisual
39 #define Region _XxRegion
40 #include "gdk/gdkx.h"
41 #undef Visual
42 #undef Region
44 #ifdef DEBUG
45 #define d(x) x
46 #else
47 #define d(x)
48 #endif
50 #define w(x) x
51 // Debug NPStreams
52 #define nps(x)//x
54 extern guint32 moonlight_flags;
56 /* gleaned from svn log of the moon module, as well as olive/class/{agclr,agmono,System.Silverlight} */
57 static const char *moonlight_authors[] = {
58 "Aaron Bockover <abockover@novell.com>",
59 "Alan McGovern <amcgovern@novell.com>",
60 "Alp Toker <alp@nuanti.com>",
61 "Andreia Gaita <avidigal@novell.com>",
62 "Andrew Jorgensen <ajorgensen@novell.com>",
63 "Argiris Kirtzidis <akyrtzi@gmail.com>",
64 "Atsushi Enomoto <atsushi@ximian.com>",
65 "Chris Toshok <toshok@ximian.com>",
66 "Dick Porter <dick@ximian.com>",
67 "Everaldo Canuto <ecanuto@novell.com>",
68 "Fernando Herrera <fherrera@novell.com>",
69 "Geoff Norton <gnorton@novell.com>",
70 "Jackson Harper <jackson@ximian.com>",
71 "Jb Evain <jbevain@novell.com>",
72 "Jeffrey Stedfast <fejj@novell.com>",
73 "Larry Ewing <lewing@novell.com>",
74 "Manuel Ceron <ceronman@unicauca.edu.co>",
75 "Marek Habersack <mhabersack@novell.com>",
76 "Michael Dominic K. <mdk@mdk.am>",
77 "Michael Hutchinson <mhutchinson@novell.com>",
78 "Miguel de Icaza <miguel@novell.com>",
79 "Paolo Molaro <lupus@ximian.com>",
80 "Raja R Harinath <harinath@hurrynot.org>",
81 "Rodrigo Kumpera <rkumpera@novell.com>",
82 "Rolf Bjarne Kvinge <RKvinge@novell.com>",
83 "Rusty Howell <rhowell@novell.com>",
84 "Sebastien Pouliot <sebastien@ximian.com>",
85 "Stephane Delcroix <sdelcroix@novell.com>",
86 "Zoltan Varga <vargaz@gmail.com>",
87 NULL
90 void
91 plugin_menu_about (PluginInstance *plugin)
93 GtkAboutDialog *about = GTK_ABOUT_DIALOG (gtk_about_dialog_new ());
95 gtk_about_dialog_set_name (about, PLUGIN_OURNAME);
96 gtk_about_dialog_set_version (about, VERSION);
98 gtk_about_dialog_set_copyright (about, "Copyright 2007-2009 Novell, Inc. (http://www.novell.com/)");
99 #if FINAL_RELEASE
100 gtk_about_dialog_set_website (about, "http://moonlight-project.com/");
101 #else
102 gtk_about_dialog_set_website (about, "http://moonlight-project.com/Beta");
103 #endif
105 gtk_about_dialog_set_website_label (about, "Project Website");
107 gtk_about_dialog_set_authors (about, moonlight_authors);
109 /* Newer gtk+ versions require this for the close button to work */
110 g_signal_connect_swapped (about,
111 "response",
112 G_CALLBACK (gtk_widget_destroy),
113 about);
115 gtk_dialog_run (GTK_DIALOG (about));
118 void
119 plugin_media_pack (PluginInstance *plugin)
121 CodecDownloader::ShowUI (plugin->GetSurface ());
124 void
125 plugin_properties (PluginInstance *plugin)
127 plugin->Properties ();
130 void
131 plugin_show_menu (PluginInstance *plugin)
133 GtkWidget *menu;
134 GtkWidget *menu_item;
135 char *name;
137 menu = gtk_menu_new();
139 name = g_strdup_printf ("%s %s", PLUGIN_OURNAME, VERSION);
140 menu_item = gtk_menu_item_new_with_label (name);
141 g_free (name);
143 gtk_menu_shell_append (GTK_MENU_SHELL (menu), menu_item);
144 g_signal_connect_swapped (G_OBJECT(menu_item), "activate", G_CALLBACK (plugin_menu_about), plugin);
146 menu_item = gtk_menu_item_new_with_label ("Properties");
147 gtk_menu_shell_append (GTK_MENU_SHELL (menu), menu_item);
148 g_signal_connect_swapped (G_OBJECT(menu_item), "activate", G_CALLBACK (plugin_properties), plugin);
150 if (!Media::IsMSCodecsInstalled ()) {
151 menu_item = gtk_menu_item_new_with_label ("Install Microsoft Media Pack");
152 gtk_menu_shell_append (GTK_MENU_SHELL (menu), menu_item);
153 g_signal_connect_swapped (G_OBJECT(menu_item), "activate", G_CALLBACK (plugin_media_pack), plugin);
156 #ifdef DEBUG
157 menu_item = gtk_menu_item_new_with_label ("Show XAML Hierarchy");
158 gtk_menu_shell_append (GTK_MENU_SHELL (menu), menu_item);
159 g_signal_connect_swapped (G_OBJECT(menu_item), "activate", G_CALLBACK (plugin_debug), plugin);
161 menu_item = gtk_menu_item_new_with_label ("Sources");
162 gtk_menu_shell_append (GTK_MENU_SHELL (menu), menu_item);
163 g_signal_connect_swapped (G_OBJECT(menu_item), "activate", G_CALLBACK (plugin_sources), plugin);
164 #endif
166 gtk_widget_show_all (menu);
167 gtk_menu_popup (GTK_MENU (menu), NULL, NULL, NULL, NULL, 0, gtk_get_current_event_time());
170 gboolean
171 PluginInstance::plugin_button_press_callback (GtkWidget *widget, GdkEventButton *event, gpointer user_data)
173 PluginInstance *plugin = (PluginInstance *) user_data;
175 if (event->button == 3) {
176 plugin_show_menu (plugin);
177 return TRUE;
180 return FALSE;
183 char *
184 NPN_strdup (const char *tocopy)
186 int len = strlen(tocopy);
187 char *ptr = (char *)NPN_MemAlloc (len+1);
188 if (ptr != NULL) {
189 strcpy (ptr, tocopy);
190 // WebKit should calloc so we dont have to do this
191 ptr[len] = 0;
194 return ptr;
197 /*** PluginInstance:: *********************************************************/
199 GSList *plugin_instances = NULL;
201 static void
202 table_add (GtkWidget *table, const char *txt, int col, int row)
204 GtkWidget *l = gtk_label_new (txt);
206 gtk_misc_set_alignment (GTK_MISC (l), 0.0, 0.5);
207 gtk_table_attach (GTK_TABLE(table), l, col, col+1, row, row+1, (GtkAttachOptions) (GTK_FILL), (GtkAttachOptions) 0, 4, 0);
210 static GtkWidget *
211 title (const char *txt)
213 char *fmt = g_strdup_printf ("<b>%s</b>", txt);
214 GtkWidget *label = gtk_label_new (NULL);
216 gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
217 gtk_label_set_markup (GTK_LABEL (label), fmt);
218 g_free (fmt);
220 return label;
223 static void
224 expose_regions (GtkToggleButton *checkbox, gpointer user_data)
226 if (gtk_toggle_button_get_active (checkbox))
227 moonlight_flags |= RUNTIME_INIT_SHOW_EXPOSE;
228 else
229 moonlight_flags &= ~RUNTIME_INIT_SHOW_EXPOSE;
232 static void
233 clipping_regions (GtkToggleButton *checkbox, gpointer user_data)
235 if (gtk_toggle_button_get_active (checkbox))
236 moonlight_flags |= RUNTIME_INIT_SHOW_CLIPPING;
237 else
238 moonlight_flags &= ~RUNTIME_INIT_SHOW_CLIPPING;
241 static void
242 bounding_boxes (GtkToggleButton *checkbox, gpointer user_data)
244 if (gtk_toggle_button_get_active (checkbox))
245 moonlight_flags |= RUNTIME_INIT_SHOW_BOUNDING_BOXES;
246 else
247 moonlight_flags &= ~RUNTIME_INIT_SHOW_BOUNDING_BOXES;
250 static void
251 textboxes (GtkToggleButton *checkbox, gpointer user_data)
253 if (gtk_toggle_button_get_active (checkbox))
254 moonlight_flags |= RUNTIME_INIT_SHOW_TEXTBOXES;
255 else
256 moonlight_flags &= ~RUNTIME_INIT_SHOW_TEXTBOXES;
259 static void
260 show_fps (GtkToggleButton *checkbox, gpointer user_data)
262 if (gtk_toggle_button_get_active (checkbox))
263 moonlight_flags |= RUNTIME_INIT_SHOW_FPS;
264 else
265 moonlight_flags &= ~RUNTIME_INIT_SHOW_FPS;
268 void
269 PluginInstance::properties_dialog_response (GtkWidget *dialog, int response, PluginInstance *plugin)
271 plugin->properties_fps_label = NULL;
272 plugin->properties_cache_label = NULL;
273 gtk_widget_destroy (dialog);
276 void
277 PluginInstance::Properties ()
279 GtkWidget *dialog, *table, *checkbox;
280 char buffer[40];
281 GtkBox *vbox;
282 int row = 0;
284 dialog = gtk_dialog_new_with_buttons ("Object Properties", NULL, (GtkDialogFlags)
285 GTK_DIALOG_NO_SEPARATOR,
286 GTK_STOCK_CLOSE, GTK_RESPONSE_NONE, NULL);
287 gtk_container_set_border_width (GTK_CONTAINER (dialog), 8);
289 vbox = GTK_BOX (GTK_DIALOG (dialog)->vbox);
291 // Silverlight Application properties
292 gtk_box_pack_start (vbox, title ("Properties"), FALSE, FALSE, 0);
293 gtk_box_pack_start (vbox, gtk_hseparator_new (), FALSE, FALSE, 8);
295 table = gtk_table_new (11, 2, FALSE);
296 gtk_box_pack_start (vbox, table, TRUE, TRUE, 0);
298 table_add (table, "Source:", 0, row++);
299 table_add (table, "Width:", 0, row++);
300 table_add (table, "Height:", 0, row++);
301 table_add (table, "Background:", 0, row++);
302 table_add (table, "Kind:", 0, row++);
303 table_add (table, "Windowless:", 0, row++);
304 table_add (table, "MaxFrameRate:", 0, row++);
305 table_add (table, "Codecs:", 0, row++);
307 row = 0;
308 table_add (table, source, 1, row++);
309 snprintf (buffer, sizeof (buffer), "%dpx", GetActualWidth ());
310 table_add (table, buffer, 1, row++);
311 snprintf (buffer, sizeof (buffer), "%dpx", GetActualHeight ());
312 table_add (table, buffer, 1, row++);
313 table_add (table, background, 1, row++);
314 table_add (table, xaml_loader == NULL ? "(Unknown)" : (xaml_loader->IsManaged () ? "1.1 (XAML + Managed Code)" : "1.0 (Pure XAML)"), 1, row++);
315 table_add (table, windowless ? "yes" : "no", 1, row++);
316 snprintf (buffer, sizeof (buffer), "%i", maxFrameRate);
317 table_add (table, buffer, 1, row++);
318 #if INCLUDE_FFMPEG
319 table_add (table, Media::IsMSCodecsInstalled () ? "ms-codecs" : "ffmpeg", 1, row++);
320 #else
321 table_add (table, Media::IsMSCodecsInstalled () ? "ms-codecs" : "none", 1, row++);
322 #endif
324 row++;
325 properties_fps_label = gtk_label_new ("");
326 gtk_misc_set_alignment (GTK_MISC (properties_fps_label), 0.0, 0.5);
327 gtk_table_attach (GTK_TABLE(table), properties_fps_label, 0, 2, row, row+1, (GtkAttachOptions) (GTK_FILL), (GtkAttachOptions) 0, 4, 0);
329 row++;
330 properties_cache_label = gtk_label_new ("");
331 gtk_misc_set_alignment (GTK_MISC (properties_cache_label), 0.0, 0.5);
332 gtk_table_attach (GTK_TABLE(table), properties_cache_label, 0, 2, row, row+1, (GtkAttachOptions) (GTK_FILL), (GtkAttachOptions) 0, 4, 0);
334 // Runtime debug options
335 gtk_box_pack_start (vbox, title ("Runtime Debug Options"), FALSE, FALSE, 0);
336 gtk_box_pack_start (vbox, gtk_hseparator_new (), FALSE, FALSE, 8);
338 checkbox = gtk_check_button_new_with_label ("Show exposed regions");
339 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (checkbox), moonlight_flags & RUNTIME_INIT_SHOW_EXPOSE);
340 g_signal_connect (checkbox, "toggled", G_CALLBACK (expose_regions), NULL);
341 gtk_box_pack_start (vbox, checkbox, FALSE, FALSE, 0);
343 checkbox = gtk_check_button_new_with_label ("Show clipping regions");
344 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (checkbox), moonlight_flags & RUNTIME_INIT_SHOW_CLIPPING);
345 g_signal_connect (checkbox, "toggled", G_CALLBACK (clipping_regions), NULL);
346 gtk_box_pack_start (vbox, checkbox, FALSE, FALSE, 0);
348 checkbox = gtk_check_button_new_with_label ("Show bounding boxes");
349 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (checkbox), moonlight_flags & RUNTIME_INIT_SHOW_BOUNDING_BOXES);
350 g_signal_connect (checkbox, "toggled", G_CALLBACK (bounding_boxes), NULL);
351 gtk_box_pack_start (vbox, checkbox, FALSE, FALSE, 0);
353 checkbox = gtk_check_button_new_with_label ("Show text boxes");
354 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (checkbox), moonlight_flags & RUNTIME_INIT_SHOW_TEXTBOXES);
355 g_signal_connect (checkbox, "toggled", G_CALLBACK (textboxes), NULL);
356 gtk_box_pack_start (vbox, checkbox, FALSE, FALSE, 0);
358 checkbox = gtk_check_button_new_with_label ("Show Frames Per Second");
359 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (checkbox), moonlight_flags & RUNTIME_INIT_SHOW_FPS);
360 g_signal_connect (checkbox, "toggled", G_CALLBACK (show_fps), NULL);
361 gtk_box_pack_start (vbox, checkbox, FALSE, FALSE, 0);
363 g_signal_connect (dialog, "response", G_CALLBACK (properties_dialog_response), this);
364 gtk_widget_show_all (dialog);
367 PluginInstance::PluginInstance (NPMIMEType pluginType, NPP instance, guint16 mode)
369 this->instance = instance;
370 this->mode = mode;
371 window = NULL;
373 properties_fps_label = NULL;
374 properties_cache_label = NULL;
376 rootobject = NULL;
378 container = NULL;
379 surface = NULL;
380 moon_window = NULL;
382 // Property fields
383 source_location = NULL;
384 source_location_original = NULL;
385 initParams = NULL;
386 source = NULL;
387 source_original = NULL;
388 source_idle = 0;
389 onLoad = NULL;
390 onError = NULL;
391 onResize = NULL;
392 onSourceDownloadProgressChanged = NULL;
393 onSourceDownloadComplete = NULL;
394 splashscreensource = NULL;
395 background = NULL;
396 id = NULL;
398 windowless = false;
399 cross_domain_app = false; // false, since embedded xaml (in html) won't load anything (to change this value)
400 default_enable_html_access = true; // should we use the default value (wrt the HTML script supplied value)
401 enable_html_access = true; // an empty plugin must return TRUE before loading anything else (e.g. scripting)
402 allow_html_popup_window = false;
403 xembed_supported = FALSE;
404 loading_splash = false;
405 is_splash = false;
407 bridge = NULL;
409 // MSDN says the default is 24: http://msdn2.microsoft.com/en-us/library/bb979688.aspx
410 // blog says the default is 60: http://blogs.msdn.com/seema/archive/2007/10/07/perf-debugging-tips-enableredrawregions-a-performance-bug-in-videobrush.aspx
411 // testing seems to confirm that the default is 60.
412 maxFrameRate = 60;
413 enable_framerate_counter = false;
415 vm_missing_file = NULL;
416 xaml_loader = NULL;
417 #if PLUGIN_SL_2_0
418 system_windows_assembly = NULL;
420 moon_load_xaml =
421 moon_initialize_deployment_xap =
422 moon_initialize_deployment_xaml =
423 moon_destroy_application = NULL;
425 #endif
426 timers = NULL;
428 wrapped_objects = g_hash_table_new (g_direct_hash, g_direct_equal);
430 cleanup_pointers = NULL;
432 plugin_instances = g_slist_append (plugin_instances, instance);
434 /* back pointer to us */
435 instance->pdata = this;
437 #if DEBUG
438 moon_sources = NULL;
439 #endif
442 PluginInstance::~PluginInstance ()
444 // Kill timers
445 GSList *p;
447 Deployment::SetCurrent (deployment);
449 for (p = timers; p != NULL; p = p->next){
450 guint32 source_id = GPOINTER_TO_INT (p->data);
452 g_source_remove (source_id);
454 g_slist_free (p);
456 g_hash_table_destroy (wrapped_objects);
458 // Remove us from the list.
459 plugin_instances = g_slist_remove (plugin_instances, instance);
461 for (GSList *l = cleanup_pointers; l; l = l->next) {
462 gpointer* p = (gpointer*)l->data;
463 *p = NULL;
465 g_slist_free (cleanup_pointers);
467 if (rootobject)
468 NPN_ReleaseObject ((NPObject*)rootobject);
470 g_free (background);
471 g_free (id);
472 g_free (initParams);
473 delete xaml_loader;
475 #if PLUGIN_SL_2_0
476 // Destroy the XAP application
477 DestroyApplication ();
478 #endif
480 g_free (source);
481 g_free (source_original);
482 g_free (source_location);
483 g_free (source_location_original);
485 if (source_idle)
486 g_source_remove (source_idle);
489 // The code below was an attempt at fixing this, but we are still getting spurious errors
490 // we might have another source of problems
492 //fprintf (stderr, "Destroying the surface: %p, plugin: %p\n", surface, this);
493 if (surface != NULL) {
494 //gdk_error_trap_push ();
495 surface->Zombify();
496 surface->Dispose ();
497 surface->unref_delayed();
498 //gdk_display_sync (display);
499 //gdk_error_trap_pop ();
502 if (bridge)
503 delete bridge;
504 bridge = NULL;
506 deployment->Dispose ();
507 deployment->unref_delayed();
508 #if DEBUG
509 delete moon_sources;
510 #endif
513 #if DEBUG
514 void
515 PluginInstance::AddSource (const char *uri, const char *filename)
517 moon_source *src = new moon_source ();
518 src->uri = g_strdup (uri);
519 src->filename = g_strdup (filename);
520 if (moon_sources == NULL)
521 moon_sources = new List ();
522 moon_sources->Append (src);
525 List*
526 PluginInstance::GetSources ()
528 return moon_sources;
530 #endif
533 static bool
534 same_site_of_origin (const char *url1, const char *url2)
536 bool result = false;
537 Uri *uri1;
539 if (url1 == NULL || url2 == NULL)
540 return false;
542 uri1 = new Uri ();
543 if (uri1->Parse (url1)) {
544 Uri *uri2 = new Uri ();
546 if (uri2->Parse (url2)) {
547 // if only one of the two URI is absolute then the second one is relative to the first,
548 // which makes it part of the same site of origin
549 if ((uri1->isAbsolute && !uri2->isAbsolute) || (!uri1->isAbsolute && uri2->isAbsolute))
550 result = true;
551 else
552 result = Uri::SameSiteOfOrigin (uri1, uri2);
554 delete uri2;
556 delete uri1;
557 return result;
560 static bool
561 parse_bool_arg (const char *arg)
563 bool b;
564 return xaml_bool_from_str (arg, &b) && b;
567 void
568 PluginInstance::Initialize (int argc, char* const argn[], char* const argv[])
570 for (int i = 0; i < argc; i++) {
571 if (argn[i] == NULL) {
572 //g_warning ("PluginInstance::Initialize, arg %d == NULL", i);
573 continue;
575 else if (!g_ascii_strcasecmp (argn[i], "initParams")) {
576 initParams = g_strdup (argv[i]);
578 else if (!g_ascii_strcasecmp (argn[i], "onLoad")) {
579 onLoad = argv[i];
581 else if (!g_ascii_strcasecmp (argn[i], "onError")) {
582 onError = argv[i];
584 else if (!g_ascii_strcasecmp (argn[i], "onResize")) {
585 onResize = argv[i];
587 else if (!g_ascii_strcasecmp (argn[i], "src") || !g_ascii_strcasecmp (argn[i], "source")) {
588 /* There is a new design pattern that creates a silverlight object with data="data:application/x-silverlight,"
589 * firefox is passing this to us as the src element. We need to ensure we dont set source to this value
590 * as this design pattern sets a xap up after the fact, but checks to ensure Source hasn't been set yet.
592 * eg: http://theamazingalbumcoveratlas.org/
594 * TODO: Find a site that has data:application/x-silverlight,SOMEDATA and figure out what we do with it
596 if (g_ascii_strncasecmp (argv[i], "data:application/x-silverlight", 30) != 0 && argv[i][strlen(argv[i])-1] != ',') {
597 source = g_strdup (argv[i]);
598 // we must be able to retrieve the original source, e.g. after a redirect
599 source_original = g_strdup (source);
602 else if (!g_ascii_strcasecmp (argn[i], "background")) {
603 background = g_strdup (argv[i]);
605 else if (!g_ascii_strcasecmp (argn [i], "windowless")) {
606 windowless = parse_bool_arg (argv [i]);
608 else if (!g_ascii_strcasecmp (argn [i], "maxFramerate")) {
609 maxFrameRate = atoi (argv [i]);
611 else if (!g_ascii_strcasecmp (argn [i], "id")) {
612 id = g_strdup (argv [i]);
614 else if (!g_ascii_strcasecmp (argn [i], "enablehtmlaccess")) {
615 default_enable_html_access = false; // we're using the application value, not the default one
616 enable_html_access = parse_bool_arg (argv [i]);
618 else if (!g_ascii_strcasecmp (argn [i], "allowhtmlpopupwindow")) {
619 allow_html_popup_window = parse_bool_arg (argv [i]);
621 else if (!g_ascii_strcasecmp (argn [i], "splashscreensource")) {
622 splashscreensource = g_strdup (argv [i]);
624 else if (!g_ascii_strcasecmp (argn [i], "onSourceDownloadProgressChanged")) {
625 onSourceDownloadProgressChanged = g_strdup (argv [i]);
627 else if (!g_ascii_strcasecmp (argn [i], "onSourceDownloadComplete")) {
628 onSourceDownloadComplete = g_strdup (argv [i]);
630 else {
631 //fprintf (stderr, "unhandled attribute %s='%s' in PluginInstance::Initialize\n", argn[i], argv[i]);
635 // like 'source' the original location can also be required later (for cross-domain checks after redirections)
636 source_location_original = GetPageLocation ();
638 guint32 supportsWindowless = FALSE; // NPBool + padding
640 int plugin_major, plugin_minor;
641 int netscape_major, netscape_minor;
642 bool try_opera_quirks = FALSE;
644 /* Find the version numbers. */
645 NPN_Version(&plugin_major, &plugin_minor,
646 &netscape_major, &netscape_minor);
648 //d(printf ("Plugin NPAPI version = %d.%d\n", plugin_major, netscape_minor));
649 //d(printf ("Browser NPAPI version = %d.%d\n", netscape_major, netscape_minor));
651 NPError error;
652 error = NPN_GetValue (instance, NPNVSupportsXEmbedBool, &xembed_supported);
653 if (error || !xembed_supported) {
654 // This should be an error but we'll use it to detect
655 // that we are running in opera
656 //return NPERR_INCOMPATIBLE_VERSION_ERROR;
657 if (!windowless)
658 d(printf ("*** XEmbed not supported\n"));
660 try_opera_quirks = true;
663 error = NPN_GetValue (instance, NPNVSupportsWindowless, &supportsWindowless);
664 supportsWindowless = (error == NPERR_NO_ERROR) && supportsWindowless;
666 #ifdef DEBUG
667 if ((moonlight_flags & RUNTIME_INIT_ALLOW_WINDOWLESS) == 0) {
668 printf ("plugin wants to be windowless, but we're not going to let it\n");
669 windowless = false;
671 #endif
672 if (windowless) {
673 if (supportsWindowless) {
674 NPN_SetValue (instance, NPPVpluginWindowBool, (void *) FALSE);
675 NPN_SetValue (instance, NPPVpluginTransparentBool, (void *) TRUE);
676 d(printf ("windowless mode\n"));
677 } else {
678 d(printf ("browser doesn't support windowless mode.\n"));
679 windowless = false;
683 // grovel around in the useragent and try to figure out which
684 // browser bridge we should use.
685 const char *useragent = NPN_UserAgent (instance);
687 if (strstr (useragent, "Opera")) {
688 // opera based
689 TryLoadBridge ("opera");
691 else if (strstr (useragent, "AppleWebKit")) {
692 // webkit based
693 TryLoadBridge ("webkit");
695 else if (strstr (useragent, "Gecko")) {
696 // gecko based, let's look for 'rv:1.8' vs 'rv:1.9'
697 if (strstr (useragent, "rv:1.8")) {
698 TryLoadBridge ("ff2");
700 else if (strstr (useragent, "rv:1.9")) {
701 TryLoadBridge ("ff3");
705 // XXX Opera currently claims to be mozilla when we query it
706 if (!bridge && try_opera_quirks)
707 TryLoadBridge ("opera");
709 if (!bridge) {
710 g_warning ("probing for browser type failed, user agent = `%s'",
711 useragent);
714 if (!CreatePluginDeployment ()) {
715 g_warning ("Couldn't initialize Mono or create the plugin Deployment");
719 typedef BrowserBridge* (*create_bridge_func)();
721 const char*
722 get_plugin_dir (void)
724 static char *plugin_dir = NULL;
726 if (!plugin_dir) {
727 Dl_info dlinfo;
728 if (dladdr((void *) &plugin_show_menu, &dlinfo) == 0) {
729 fprintf (stderr, "Unable to find the location of libmoonplugin.so: %s\n", dlerror ());
730 return NULL;
732 plugin_dir = g_path_get_dirname (dlinfo.dli_fname);
734 return plugin_dir;
737 void
738 PluginInstance::TryLoadBridge (const char *prefix)
740 char *bridge_name = g_strdup_printf ("libmoonplugin-%sbridge.so", prefix);
741 char *bridge_path;
743 bridge_path = g_build_filename (get_plugin_dir (), bridge_name, NULL);
745 void* bridge_handle = dlopen (bridge_path, RTLD_LAZY);
747 g_free (bridge_name);
748 g_free (bridge_path);
750 if (bridge_handle == NULL) {
751 g_warning ("failed to load browser bridge: %s", dlerror());
752 return;
755 create_bridge_func bridge_ctor = (create_bridge_func)dlsym (bridge_handle, "CreateBrowserBridge");
756 if (bridge_ctor == NULL) {
757 g_warning ("failed to locate CreateBrowserBridge symbol: %s", dlerror());
758 return;
761 bridge = bridge_ctor ();
764 void
765 PluginInstance::Finalize ()
769 NPError
770 PluginInstance::GetValue (NPPVariable variable, void *result)
772 NPError err = NPERR_NO_ERROR;
774 switch (variable) {
775 case NPPVpluginNeedsXEmbed:
776 *((NPBool *)result) = !windowless;
777 break;
778 case NPPVpluginScriptableNPObject:
779 *((NPObject**) result) = GetRootObject ();
780 break;
781 default:
782 err = NPERR_INVALID_PARAM;
783 break;
786 return err;
789 NPError
790 PluginInstance::SetValue (NPNVariable variable, void *value)
792 return NPERR_NO_ERROR;
795 NPError
796 PluginInstance::SetWindow (NPWindow *window)
798 Deployment::SetCurrent (deployment);
800 if (moon_window) {
801 // XXX opera Window lifetime hack needs this
802 this->window = window;
804 if (!surface)
805 return NPERR_GENERIC_ERROR;
807 moon_window->Resize (window->width, window->height);
808 return NPERR_NO_ERROR;
811 this->window = window;
812 CreateWindow ();
814 return NPERR_NO_ERROR;
817 NPObject*
818 PluginInstance::GetHost()
820 NPObject *object = NULL;
821 if (NPERR_NO_ERROR != NPN_GetValue(instance, NPNVPluginElementNPObject, &object)) {
822 d(printf ("Failed to get plugin host object\n"));
824 return object;
827 void
828 PluginInstance::ReportFPS (Surface *surface, int nframes, float nsecs, void *user_data)
830 PluginInstance *plugin = (PluginInstance *) user_data;
831 char *msg;
833 msg = g_strdup_printf ("Rendered %d frames in %.3fs = %.3f FPS",
834 nframes, nsecs, nframes / nsecs);
836 NPN_Status (plugin->instance, msg);
838 if (plugin->properties_fps_label)
839 gtk_label_set_text (GTK_LABEL (plugin->properties_fps_label), msg);
841 g_free (msg);
844 void
845 PluginInstance::ReportCache (Surface *surface, long bytes, void *user_data)
847 PluginInstance *plugin = (PluginInstance *) user_data;
848 char *msg;
850 if (bytes < 1048576)
851 msg = g_strdup_printf ("Cache size is ~%d KB", (int) (bytes / 1024));
852 else
853 msg = g_strdup_printf ("Cache size is ~%.2f MB", bytes / 1048576.0);
855 NPN_Status (plugin->instance, msg);
857 if (plugin->properties_cache_label)
858 gtk_label_set_text (GTK_LABEL (plugin->properties_cache_label), msg);
860 g_free (msg);
863 static void
864 register_event (NPP instance, const char *event_name, char *script_name, NPObject *npobj)
866 if (!script_name)
867 return;
869 char *retval = NPN_strdup (script_name);
870 NPVariant npvalue;
872 STRINGZ_TO_NPVARIANT (retval, npvalue);
873 NPIdentifier identifier = NPN_GetStringIdentifier (event_name);
874 NPN_SetProperty (instance, npobj, identifier, &npvalue);
875 NPN_MemFree (retval);
878 bool
879 PluginInstance::IsLoaded ()
881 if (!GetSurface () || is_splash)
882 return false;
884 return GetSurface()->IsLoaded();
887 void
888 PluginInstance::CreateWindow ()
890 if (windowless) {
891 moon_window = new MoonWindowless (window->width, window->height, this);
892 moon_window->SetTransparent (true);
894 else {
895 moon_window = new MoonWindowGtk (false, window->width, window->height);
898 surface = new Surface (moon_window);
899 deployment->SetSurface (surface);
901 MoonlightScriptControlObject *root = GetRootObject ();
902 register_event (instance, "onSourceDownloadProgressChanged", onSourceDownloadProgressChanged, root);
903 register_event (instance, "onSourceDownloadComplete", onSourceDownloadComplete, root);
904 register_event (instance, "onError", onError, root);
905 // register_event (instance, "onResize", onResize, rootx->content);
907 // NOTE: last testing showed this call causes opera to reenter but moving it is trouble and
908 // the bug is on opera's side.
909 SetPageURL ();
910 LoadSplash ();
912 surface->SetFPSReportFunc (ReportFPS, this);
913 surface->SetCacheReportFunc (ReportCache, this);
914 surface->SetDownloaderContext (this);
916 surface->GetTimeManager()->SetMaximumRefreshRate (maxFrameRate);
918 if (background) {
919 Color *c = color_from_str (background);
921 if (c == NULL) {
922 d(printf ("error setting background color\n"));
923 c = new Color (0x00FFFFFF);
926 surface->SetBackgroundColor (c);
927 delete c;
930 if (!windowless) {
931 // GtkPlug container and surface inside
932 container = gtk_plug_new ((GdkNativeWindow) window->window);
934 // Connect signals to container
935 GTK_WIDGET_SET_FLAGS (GTK_WIDGET (container), GTK_CAN_FOCUS);
937 gtk_widget_add_events (container,
938 GDK_BUTTON_PRESS_MASK |
939 GDK_BUTTON_RELEASE_MASK |
940 GDK_KEY_PRESS_MASK |
941 GDK_KEY_RELEASE_MASK |
942 GDK_POINTER_MOTION_MASK |
943 GDK_SCROLL_MASK |
944 GDK_EXPOSURE_MASK |
945 GDK_VISIBILITY_NOTIFY_MASK |
946 GDK_ENTER_NOTIFY_MASK |
947 GDK_LEAVE_NOTIFY_MASK |
948 GDK_FOCUS_CHANGE_MASK
951 g_signal_connect (G_OBJECT(container), "button-press-event", G_CALLBACK (PluginInstance::plugin_button_press_callback), this);
953 gtk_container_add (GTK_CONTAINER (container), ((MoonWindowGtk*)moon_window)->GetWidget());
954 //display = gdk_drawable_get_display (surface->GetWidget()->window);
955 gtk_widget_show_all (container);
959 void
960 PluginInstance::UpdateSource ()
962 if (source_idle) {
963 g_source_remove (source_idle);
964 source_idle = 0;
967 if (surface != NULL)
968 surface->DetachDownloaders ();
970 if (!source || strlen (source) == 0)
971 return;
973 char *pos = strchr (source, '#');
974 if (pos) {
975 // FIXME: this will crash if this object has been deleted by the time IdleUpdateSourceByReference is called.
976 source_idle = g_idle_add (IdleUpdateSourceByReference, this);
977 SetPageURL ();
978 } else {
979 StreamNotify *notify = new StreamNotify (StreamNotify::SOURCE, source);
981 // FIXME: check for errors
982 NPN_GetURLNotify (instance, source, NULL, notify);
986 gboolean
987 PluginInstance::IdleUpdateSourceByReference (gpointer data)
989 PluginInstance *instance = (PluginInstance*)data;
990 char *pos = NULL;
992 instance->source_idle = 0;
994 if (instance->source)
995 pos = strchr (instance->source, '#');
997 if (pos && strlen (pos+1) > 0)
998 instance->UpdateSourceByReference (pos+1);
1000 instance->GetSurface ()->EmitSourceDownloadProgressChanged (new DownloadProgressEventArgs (1.0));
1001 instance->GetSurface ()->EmitSourceDownloadComplete ();
1002 return FALSE;
1005 void
1006 PluginInstance::UpdateSourceByReference (const char *value)
1008 // basically do the equivalent of document.getElementById('@value').textContent
1009 // all using NPAPI.
1011 NPVariant _document;
1012 NPVariant _element;
1013 NPVariant _elementName;
1014 NPVariant _textContent;
1016 Deployment::SetCurrent (deployment);
1018 NPIdentifier id_ownerDocument = NPN_GetStringIdentifier ("ownerDocument");
1019 NPIdentifier id_getElementById = NPN_GetStringIdentifier ("getElementById");
1020 NPIdentifier id_textContent = NPN_GetStringIdentifier ("textContent");
1022 NPObject *host = GetHost();
1023 if (!host) {
1024 // printf ("no host\n");
1025 return;
1028 // get host.ownerDocument
1029 bool nperr;
1030 if (!(nperr = NPN_GetProperty (instance, host, id_ownerDocument, &_document))
1031 || !NPVARIANT_IS_OBJECT (_document)) {
1032 // printf ("no document (type == %d, nperr = %d)\n", _document.type, nperr);
1033 return;
1036 // _element = document.getElementById ('@value')
1037 string_to_npvariant (value, &_elementName);
1038 if (!(nperr = NPN_Invoke (instance, NPVARIANT_TO_OBJECT (_document), id_getElementById,
1039 &_elementName, 1, &_element))
1040 || !NPVARIANT_IS_OBJECT (_element)) {
1041 // printf ("no valid element named #%s (type = %d, nperr = %d)\n", value, _element.type, nperr);
1042 NPN_ReleaseVariantValue (&_document);
1045 // _textContent = _element.textContent
1046 if (!(nperr = NPN_GetProperty (instance, NPVARIANT_TO_OBJECT (_element), id_textContent, &_textContent))
1047 || !NPVARIANT_IS_STRING (_textContent)) {
1048 // printf ("no text content for element named #%s (type = %d, nperr = %d)\n", value, _textContent.type, nperr);
1049 NPN_ReleaseVariantValue (&_document);
1050 NPN_ReleaseVariantValue (&_element);
1051 return;
1054 char *xaml = g_strndup ((char *) NPVARIANT_TO_STRING (_textContent).utf8characters, NPVARIANT_TO_STRING (_textContent).utf8length);
1056 // printf ("yay, xaml = %s\n", xaml);
1058 if (xaml_loader)
1059 delete xaml_loader;
1061 xaml_loader = PluginXamlLoader::FromStr (NULL/*FIXME*/, xaml, this, surface);
1062 LoadXAML ();
1064 g_free (xaml);
1066 NPN_ReleaseVariantValue (&_document);
1067 NPN_ReleaseVariantValue (&_element);
1068 NPN_ReleaseVariantValue (&_textContent);
1072 Downloader *
1073 PluginInstance::CreateDownloader (PluginInstance *instance)
1075 if (instance) {
1076 return instance->surface->CreateDownloader ();
1077 } else {
1078 printf ("PluginInstance::CreateDownloader (%p): Unable to create contextual downloader.\n", instance);
1079 return new Downloader ();
1083 void
1084 PluginInstance::SetInitParams (const char *value)
1086 g_free (initParams);
1087 initParams = g_strdup (value);
1090 char*
1091 PluginInstance::GetPageLocation ()
1093 char *location = NULL;
1094 NPIdentifier str_location = NPN_GetStringIdentifier ("location");
1095 NPIdentifier str_href = NPN_GetStringIdentifier ("href");
1096 NPVariant location_property;
1097 NPVariant location_object;
1098 NPObject *window;
1100 if (NPERR_NO_ERROR == NPN_GetValue (instance, NPNVWindowNPObject, &window)) {
1101 // Get the location property from the window object (which is another object).
1102 if (NPN_GetProperty (instance, window, str_location, &location_property)) {
1103 // Get the location property from the location object.
1104 if (NPN_GetProperty (instance, location_property.value.objectValue, str_href, &location_object )) {
1105 location = g_strndup (NPVARIANT_TO_STRING (location_object).utf8characters, NPVARIANT_TO_STRING (location_object).utf8length);
1106 NPN_ReleaseVariantValue (&location_object);
1108 NPN_ReleaseVariantValue (&location_property);
1111 NPN_ReleaseObject (window);
1112 return location;
1115 void
1116 PluginInstance::SetPageURL ()
1118 if (source_location != NULL)
1119 return;
1121 char* location = GetPageLocation ();
1122 if (location && surface) {
1123 this->source_location = location;
1124 surface->SetSourceLocation (this->source_location);
1129 NPError
1130 PluginInstance::NewStream (NPMIMEType type, NPStream *stream, NPBool seekable, guint16 *stype)
1132 nps (printf ("PluginInstance::NewStream (%p, %p, %i, %p)\n", type, stream, seekable, stype));
1134 if (IS_NOTIFY_SPLASHSOURCE (stream->notifyData)) {
1135 SetPageURL ();
1137 *stype = NP_ASFILEONLY;
1138 return NPERR_NO_ERROR;
1140 if (IS_NOTIFY_SOURCE (stream->notifyData)) {
1141 // See http://developer.mozilla.org/En/Getting_the_page_URL_in_NPAPI_plugin
1143 // but don't call GetProperty inside SetWindow because it breaks opera by
1144 // causing it to reenter
1146 // this->source_location = g_strdup (stream->url);
1147 SetPageURL ();
1149 *stype = NP_ASFILE;
1150 return NPERR_NO_ERROR;
1153 if (IS_NOTIFY_DOWNLOADER (stream->notifyData)) {
1154 StreamNotify *notify = (StreamNotify *) stream->notifyData;
1155 Downloader *dl = (Downloader *) notify->pdata;
1156 // check if (a) it's a redirection and (b) if it is allowed for the current downloader policy
1157 if (!dl->CheckRedirectionPolicy (stream->url))
1158 return NPERR_INVALID_URL;
1160 npstream_request_set_stream_data (dl, instance, stream);
1161 *stype = NP_ASFILE;
1162 return NPERR_NO_ERROR;
1165 if (IS_NOTIFY_REQUEST (stream->notifyData)) {
1166 *stype = NP_ASFILEONLY;
1167 return NPERR_NO_ERROR;
1170 *stype = NP_NORMAL;
1172 return NPERR_NO_ERROR;
1175 NPError
1176 PluginInstance::DestroyStream (NPStream *stream, NPError reason)
1178 nps (printf ("PluginInstance::DestroyStream (%p, %i)\n", stream, reason));
1180 PluginDownloader *pd = (PluginDownloader*) stream->pdata;
1181 if (pd != NULL) {
1182 NPStreamRequest *req = (NPStreamRequest *) pd->getRequest ();
1183 if (req != NULL)
1184 req->StreamDestroyed ();
1187 return NPERR_NO_ERROR;
1191 // Tries to load the XAML file, the parsing might fail because a
1192 // required dependency is not available, so we need to queue the
1193 // request to fetch the data.
1195 void
1196 PluginInstance::LoadXAML ()
1198 int error = 0;
1200 if (!InitializePluginAppDomain ()) {
1201 g_warning ("Couldn't initialize the plugin AppDomain");
1202 return;
1206 // Only try to load if there's no missing files.
1208 Surface *our_surface = surface;
1209 AddCleanupPointer (&our_surface);
1211 ManagedInitializeDeployment (NULL);
1212 xaml_loader->LoadVM ();
1214 MoonlightScriptControlObject *root = GetRootObject ();
1215 if (!loading_splash) {
1216 register_event (instance, "onLoad", onLoad, root);
1217 //register_event (instance, "onError", onError, root);
1218 register_event (instance, "onResize", onResize, root->content);
1219 is_splash = false;
1220 loading_splash = false;
1221 } else {
1222 register_event (instance, "onLoad", (char*)"", root);
1223 //register_event (instance, "onError", "", root);
1224 register_event (instance, "onResize", (char*)"", root->content);
1225 is_splash = true;
1226 loading_splash = false;
1229 const char *missing = xaml_loader->TryLoad (&error);
1231 if (!our_surface)
1232 return;
1234 RemoveCleanupPointer (&our_surface);
1236 if (vm_missing_file == NULL)
1237 vm_missing_file = g_strdup (missing);
1239 if (vm_missing_file != NULL) {
1240 StreamNotify *notify = new StreamNotify (StreamNotify::REQUEST, vm_missing_file);
1242 // FIXME: check for errors
1243 NPN_GetURLNotify (instance, vm_missing_file, NULL, notify);
1244 return;
1248 #if PLUGIN_SL_2_0
1250 // Loads a XAP file
1252 void
1253 PluginInstance::LoadXAP (const char *url, const char *fname)
1255 if (!InitializePluginAppDomain ()) {
1256 g_warning ("Couldn't initialize the plugin AppDomain");
1257 return;
1260 g_free (source_location);
1262 source_location = g_strdup (url);
1264 MoonlightScriptControlObject *root = GetRootObject ();
1266 register_event (instance, "onLoad", onLoad, root);
1267 //register_event (instance, "onError", onError, root);
1268 register_event (instance, "onResize", onResize, root->content);
1269 loading_splash = false;
1270 is_splash = false;
1272 Deployment::GetCurrent ()->Reinitialize ();
1273 GetDeployment()->SetXapLocation (url);
1274 ManagedInitializeDeployment (fname);
1277 void
1278 PluginInstance::DestroyApplication ()
1280 ManagedDestroyApplication ();
1282 #endif
1285 * Prepares a string to be passed to Javascript, escapes the " and '
1286 * characters and maps the newline to \n sequence and cr to \r sequence
1288 static char*
1289 string_to_js (char *s)
1291 char *res;
1292 GString *result;
1294 if (strchr (s, '\'') == NULL && strchr (s, '\n') == NULL)
1295 return g_strdup (s);
1297 result = g_string_new ("");
1299 for (char *p = s; *p != 0; *p++){
1300 if (*p == '"' || *p == '\''){
1301 g_string_append_c (result, '\\');
1302 g_string_append_c (result, *p);
1303 } else if (*p == '\n'){
1304 g_string_append_c (result, '\\');
1305 g_string_append_c (result, 'n');
1306 } else if (*p == '\r'){
1307 g_string_append_c (result, '\\');
1308 g_string_append_c (result, 'r');
1309 } else
1310 g_string_append_c (result, *p);
1313 res = result->str;
1314 g_string_free (result, FALSE);
1316 return res;
1319 void
1320 PluginInstance::ReportException (char *msg, char *details, char **stack_trace, int num_frames)
1322 NPObject *object;
1323 NPVariant result;
1324 char *script, *row_js, *msg_escaped, *details_escaped;
1325 char **stack_trace_escaped;
1326 NPString str;
1327 int i;
1328 bool res;
1330 // Get a reference to our element
1331 object = GetHost();
1332 if (!object)
1333 return;
1335 // FIXME:
1336 // - make sure the variables do not become global
1338 // Remove ' from embedded strings
1339 msg_escaped = string_to_js (msg);
1340 details_escaped = string_to_js (details);
1341 stack_trace_escaped = g_new0 (char*, num_frames);
1342 for (i = 0; i < num_frames; ++i)
1343 stack_trace_escaped [i] = string_to_js (stack_trace [i]);
1345 // JS code to create our elements
1346 row_js = g_strdup (" ");
1347 for (i = 0; i < num_frames; ++i) {
1348 char *s;
1350 s = g_strdup_printf ("%s%s%s", row_js, (i == 0) ? "" : "\\n ", stack_trace_escaped [i]);
1351 g_free (row_js);
1352 row_js = s;
1355 script = g_strdup_printf ("text1 = document.createTextNode ('%s'); text2 = document.createTextNode ('Exception Details: '); text3 = document.createTextNode ('%s'); text4 = document.createTextNode ('Stack Trace:'); parent = this.parentNode; a = document.createElement ('div'); a.appendChild (document.createElement ('hr')); msg = document.createElement ('font'); a.appendChild (msg); h2 = document.createElement ('h2'); i = document.createElement ('i'); b = document.createElement ('b'); msg.appendChild (h2); msg.appendChild (b); msg.appendChild (text3); msg.appendChild (document.createElement ('br')); msg.appendChild (document.createElement ('br')); b2 = document.createElement ('b'); b2.appendChild (text4); msg.appendChild (b2); b.appendChild (text2); h2.appendChild (i); i.appendChild (text1); msg.appendChild (document.createElement ('br')); msg.appendChild (document.createElement ('br')); a.appendChild (document.createElement ('hr')); table = document.createElement ('table'); msg.appendChild (table); table.width = '100%%'; table.bgColor = '#ffffcc'; tbody = document.createElement ('tbody'); table.appendChild (tbody); tr = document.createElement ('tr'); tbody.appendChild (tr); td = document.createElement ('td'); tr.appendChild (td); pre = document.createElement ('pre'); td.appendChild (pre); text = document.createTextNode ('%s'); pre.appendChild (text); previous = parent.firstChild; if (parent.firstChild.tagName == 'DIV') parent.removeChild (parent.firstChild); parent.insertBefore (a, this)", msg_escaped, details_escaped, row_js);
1357 g_free (msg_escaped);
1358 g_free (details_escaped);
1359 for (i = 0; i < num_frames; ++i)
1360 g_free (stack_trace_escaped [i]);
1361 g_free (stack_trace_escaped);
1362 g_free (row_js);
1364 str.utf8characters = script;
1365 str.utf8length = strlen (script);
1367 res = NPN_Evaluate (instance, object, &str, &result);
1368 if (res)
1369 NPN_ReleaseVariantValue (&result);
1370 NPN_ReleaseObject (object);
1371 g_free (script);
1374 void *
1375 PluginInstance::Evaluate (const char *code)
1377 NPObject *object = GetHost ();
1378 NPString string;
1379 NPVariant npresult;
1381 if (object == NULL)
1382 return NULL;
1385 string.utf8characters = code;
1386 string.utf8length = strlen (code);
1388 bool ret = NPN_Evaluate (instance, object, &string, &npresult);
1390 Value *res = NULL;
1391 bool keep_ref = false;
1392 if (ret) {
1393 if (!NPVARIANT_IS_VOID (npresult) && !NPVARIANT_IS_NULL (npresult)) {
1394 variant_to_value (&npresult, &res);
1395 if (npresult.type == NPVariantType_Object)
1396 keep_ref = true;
1400 if (!keep_ref)
1401 NPN_ReleaseVariantValue (&npresult);
1403 return (void*)res;
1406 void
1407 PluginInstance::CrossDomainApplicationCheck (const char *source)
1409 char* page_url = GetPageLocation ();
1410 // note: source might not be an absolute URL at this stage - but that only indicates that it's relative to the page url
1411 cross_domain_app = !same_site_of_origin (page_url, source);
1412 if (!cross_domain_app) {
1413 // we need also to consider a web page having cross-domain XAP that redirects to a XAP on the SOO
1414 // this will still be considered a cross-domain
1415 cross_domain_app = !same_site_of_origin (page_url, source_original);
1417 g_free (page_url);
1419 // if the application did not specify 'enablehtmlaccess' then we use its default value
1420 // which is TRUE for same-site applications and FALSE for cross-domain applications
1421 if (default_enable_html_access)
1422 enable_html_access = !cross_domain_app;
1425 static bool
1426 is_xap (const char *fname)
1428 // Check for the ZIP magic header
1430 int fd;
1431 int nread;
1432 char buf[4];
1434 if ((fd = open (fname, O_RDONLY)) == -1)
1435 return false;
1437 nread = read (fd, buf, 4);
1438 if (nread != 4) {
1439 close (fd);
1440 return false;
1443 if (buf [0] != 0x50 || buf [1] != 0x4B || buf [2] != 0x03 || buf [3] != 0x04) {
1444 close (fd);
1445 return false;
1448 close (fd);
1449 return true;
1452 void
1453 PluginInstance::StreamAsFile (NPStream *stream, const char *fname)
1455 nps (printf ("PluginInstance::StreamAsFile (%p, %s)\n", stream, fname));
1457 Deployment::SetCurrent (deployment);
1458 #if DEBUG
1459 AddSource (stream->url, fname);
1460 #endif
1461 if (IS_NOTIFY_SPLASHSOURCE (stream->notifyData)) {
1462 xaml_loader = PluginXamlLoader::FromFilename (stream->url, fname, this, surface);
1463 loading_splash = true;
1464 LoadXAML ();
1465 FlushSplash ();
1467 if (IS_NOTIFY_SOURCE (stream->notifyData)) {
1468 bool splash = (xaml_loader != NULL);
1469 delete xaml_loader;
1470 xaml_loader = NULL;
1472 CrossDomainApplicationCheck (stream->url);
1474 Uri *uri = new Uri ();
1477 if (uri->Parse (stream->url, false) && is_xap (fname)) {
1478 LoadXAP (stream->url, fname);
1479 } else {
1480 xaml_loader = PluginXamlLoader::FromFilename (stream->url, fname, this, surface);
1481 LoadXAML ();
1484 GetSurface ()->EmitSourceDownloadProgressChanged (new DownloadProgressEventArgs (1.0));
1485 GetSurface ()->EmitSourceDownloadComplete ();
1487 delete uri;
1488 } else if (IS_NOTIFY_DOWNLOADER (stream->notifyData)){
1489 Downloader *dl = (Downloader *) ((StreamNotify *)stream->notifyData)->pdata;
1491 dl->SetFilename (fname);
1492 } else if (IS_NOTIFY_REQUEST (stream->notifyData)) {
1495 /// Commented out for now, I don't think we should need this code at all anymore since we never request assemblies
1496 /// to be downloaded anymore.
1498 bool reload = true;
1500 if (!vm_missing_file)
1501 reload = false;
1503 if (reload && xaml_loader->GetMapping (vm_missing_file) != NULL)
1504 reload = false;
1506 if (reload && xaml_loader->GetMapping (stream->url) != NULL)
1507 reload = false;
1509 if (vm_missing_file)
1510 xaml_loader->RemoveMissing (vm_missing_file);
1512 char *missing = vm_missing_file;
1513 vm_missing_file = NULL;
1515 if (reload) {
1516 // There may be more missing files.
1517 vm_missing_file = g_strdup (xaml_loader->GetMissing ());
1519 xaml_loader->InsertMapping (missing, fname);
1520 xaml_loader->InsertMapping (stream->url, fname);
1522 // retry to load
1523 LoadXAML ();
1526 g_free (missing);
1531 gint32
1532 PluginInstance::WriteReady (NPStream *stream)
1534 nps (printf ("PluginInstance::WriteReady (%p)\n", stream));
1536 Deployment::SetCurrent (deployment);
1538 StreamNotify *notify = STREAM_NOTIFY (stream->notifyData);
1540 if (notify && notify->pdata) {
1541 if (IS_NOTIFY_DOWNLOADER (notify)) {
1542 Downloader *dl = (Downloader *) notify->pdata;
1544 dl->NotifySize (stream->end);
1546 return MAX_STREAM_SIZE;
1548 if (IS_NOTIFY_SOURCE (notify)) {
1549 source_size = stream->end;
1551 return MAX_STREAM_SIZE;
1555 NPN_DestroyStream (instance, stream, NPRES_DONE);
1557 return -1;
1560 gint32
1561 PluginInstance::Write (NPStream *stream, gint32 offset, gint32 len, void *buffer)
1563 nps (printf ("PluginInstance::Write (%p, %i, %i, %p)\n", stream, offset, len, buffer));
1565 Deployment::SetCurrent (deployment);
1567 StreamNotify *notify = STREAM_NOTIFY (stream->notifyData);
1569 if (notify && notify->pdata) {
1570 if (IS_NOTIFY_DOWNLOADER (notify)) {
1571 Downloader *dl = (Downloader *) notify->pdata;
1573 dl->Write (buffer, offset, len);
1575 if (IS_NOTIFY_SOURCE (notify)) {
1576 if (source_size > 0) {
1577 float progress = (offset+len)/(float)source_size;
1578 if (GetSurface ()->GetToplevel () != NULL) {
1579 GetSurface ()->EmitSourceDownloadProgressChanged (new DownloadProgressEventArgs (progress));
1585 return len;
1588 class PluginClosure : public EventObject {
1589 public:
1590 PluginClosure (PluginInstance *plugin)
1591 : plugin (plugin)
1595 virtual ~PluginClosure ()
1599 PluginInstance *plugin;
1602 void
1603 PluginInstance::network_error_tickcall (EventObject *data)
1605 PluginClosure *closure = (PluginClosure*)data;
1606 Surface *s = closure->plugin->GetSurface();
1608 s->EmitError (new ErrorEventArgs (RuntimeError, 2104, "Failed to download silverlight application."));
1611 void
1612 PluginInstance::splashscreen_error_tickcall (EventObject *data)
1614 PluginClosure *closure = (PluginClosure*)data;
1615 Surface *s = closure->plugin->GetSurface();
1617 s->EmitError (new ErrorEventArgs (RuntimeError, 2108, "Failed to download the splash screen"));
1618 closure->plugin->is_splash = false;
1620 // we need this check beccause the plugin might have been
1621 // dtor'ed (and the surface zombified) in the amove EmitError.
1622 if (!s->IsZombie())
1623 closure->plugin->UpdateSource ();
1625 closure->unref();
1628 void
1629 PluginInstance::UrlNotify (const char *url, NPReason reason, void *notifyData)
1631 nps (printf ("PluginInstance::UrlNotify (%s, %i, %p)\n", url, reason, notifyData));
1633 StreamNotify *notify = STREAM_NOTIFY (notifyData);
1635 Deployment::SetCurrent (deployment);
1637 if (reason == NPRES_DONE) {
1638 d(printf ("URL %s downloaded successfully.\n", url));
1639 } else {
1640 d(printf ("Download of URL %s failed: %i (%s)\n", url, reason,
1641 reason == NPRES_USER_BREAK ? "user break" :
1642 (reason == NPRES_NETWORK_ERR ? "network error" : "other error")));
1643 if (IS_NOTIFY_SOURCE (notify))
1644 GetSurface()->GetTimeManager()->AddTickCall (network_error_tickcall,
1645 new PluginClosure (this));
1648 if (notify && notify->pdata && IS_NOTIFY_DOWNLOADER (notify)) {
1649 Downloader *dl = (Downloader *) notify->pdata;
1651 if (reason != NPRES_DONE) {
1653 switch (reason) {
1654 case NPRES_USER_BREAK:
1655 dl->NotifyFailed ("user break");
1656 break;
1657 case NPRES_NETWORK_ERR:
1658 dl->NotifyFailed ("network error");
1659 break;
1660 default:
1661 dl->NotifyFailed ("unknown error");
1662 break;
1664 } else {
1665 dl->NotifyFinished (url);
1669 if (notify && notify->pdata && IS_NOTIFY_SPLASHSOURCE (notify)) {
1670 if (reason == NPRES_NETWORK_ERR)
1671 GetSurface()->GetTimeManager()->AddTickCall (splashscreen_error_tickcall,
1672 new PluginClosure (this));
1673 else
1674 UpdateSource ();
1677 if (notify)
1678 delete notify;
1681 void
1682 PluginInstance::LoadSplash ()
1684 if (splashscreensource != NULL) {
1685 char *pos = strchr (splashscreensource, '#');
1686 if (pos) {
1687 splashscreensource = pos+1;
1688 loading_splash = true;
1689 UpdateSourceByReference (splashscreensource);
1690 FlushSplash ();
1691 UpdateSource ();
1692 } else {
1693 StreamNotify *notify = new StreamNotify (StreamNotify::SPLASHSOURCE, splashscreensource);
1695 // FIXME: check for errors
1696 NPN_GetURLNotify (instance, splashscreensource, NULL, notify);
1698 } else {
1699 xaml_loader = PluginXamlLoader::FromStr (NULL, PLUGIN_SPINNER, this, surface);
1700 loading_splash = true;
1701 LoadXAML ();
1702 FlushSplash ();
1703 UpdateSource ();
1707 void
1708 PluginInstance::FlushSplash ()
1710 // FIXME we may want to flush all events here but since this is written to the
1711 // tests I'm not sure.
1713 UIElement *toplevel = GetSurface ()->GetToplevel ();
1714 if (toplevel != NULL) {
1715 List *list = toplevel->WalkTreeForLoaded (NULL);
1716 toplevel->EmitSubtreeLoad (list);
1717 delete list;
1719 loading_splash = false;
1722 void
1723 PluginInstance::Print (NPPrint *platformPrint)
1725 // nothing to do.
1728 int16_t
1729 PluginInstance::EventHandle (void *event)
1731 if (!surface) {
1732 g_warning ("EventHandle called before SetWindow, discarding event.");
1733 return 0;
1736 if (!windowless) {
1737 g_warning ("EventHandle called for windowed plugin, discarding event.");
1738 return 0;
1742 return ((MoonWindowless*)moon_window)->HandleEvent ((XEvent*)event);
1745 void
1746 PluginInstance::AddWrappedObject (EventObject *obj, NPObject *wrapper)
1748 g_hash_table_insert (wrapped_objects, obj, wrapper);
1751 void
1752 PluginInstance::RemoveWrappedObject (EventObject *obj)
1754 g_hash_table_remove (wrapped_objects, obj);
1757 NPObject*
1758 PluginInstance::LookupWrappedObject (EventObject *obj)
1760 return (NPObject*)g_hash_table_lookup (wrapped_objects, obj);
1763 void
1764 PluginInstance::AddCleanupPointer (gpointer p)
1766 cleanup_pointers = g_slist_prepend (cleanup_pointers, p);
1769 void
1770 PluginInstance::RemoveCleanupPointer (gpointer p)
1772 cleanup_pointers = g_slist_remove (cleanup_pointers, p);
1775 /*** Getters and Setters ******************************************************/
1777 void
1778 PluginInstance::SetSource (const char *value)
1780 if (source) {
1781 g_free (source);
1782 source = NULL;
1785 source = g_strdup (value);
1786 // we may not have an original set at this point (e.g. when source is set via scripting)
1787 if (!source_original)
1788 source_original = g_strdup (value);
1790 UpdateSource ();
1793 char *
1794 PluginInstance::GetBackground ()
1796 return background;
1799 bool
1800 PluginInstance::SetBackground (const char *value)
1802 g_free (background);
1803 background = g_strdup (value);
1805 if (surface) {
1806 Color *c = color_from_str (background);
1808 if (c == NULL)
1809 return false;
1811 surface->SetBackgroundColor (c);
1812 delete c;
1815 return true;
1818 bool
1819 PluginInstance::GetEnableFramerateCounter ()
1821 return enable_framerate_counter;
1824 void
1825 PluginInstance::SetEnableFramerateCounter (bool value)
1827 enable_framerate_counter = value;
1830 bool
1831 PluginInstance::GetEnableRedrawRegions ()
1833 return moonlight_flags & RUNTIME_INIT_SHOW_EXPOSE;
1836 void
1837 PluginInstance::SetEnableRedrawRegions (bool value)
1839 if (value)
1840 moonlight_flags |= RUNTIME_INIT_SHOW_EXPOSE;
1841 else
1842 moonlight_flags &= ~RUNTIME_INIT_SHOW_EXPOSE;
1845 bool
1846 PluginInstance::GetEnableHtmlAccess ()
1848 return enable_html_access;
1851 bool
1852 PluginInstance::GetAllowHtmlPopupWindow ()
1854 return allow_html_popup_window;
1857 bool
1858 PluginInstance::GetWindowless ()
1860 return windowless;
1864 PluginInstance::GetMaxFrameRate ()
1866 return maxFrameRate;
1869 Deployment*
1870 PluginInstance::GetDeployment ()
1872 return deployment;
1875 void
1876 PluginInstance::SetMaxFrameRate (int value)
1878 maxFrameRate = value;
1880 surface->GetTimeManager()->SetMaximumRefreshRate (MAX (value, 64));
1883 gint32
1884 PluginInstance::GetActualHeight ()
1886 return surface ? surface->GetWindow()->GetHeight() : 0;
1889 gint32
1890 PluginInstance::GetActualWidth ()
1892 return surface ? surface->GetWindow()->GetWidth() : 0;
1895 MoonlightScriptControlObject *
1896 PluginInstance::GetRootObject ()
1898 if (rootobject == NULL)
1899 rootobject = NPN_CreateObject (instance, MoonlightScriptControlClass);
1901 NPN_RetainObject (rootobject);
1902 return (MoonlightScriptControlObject*)rootobject;
1906 PluginInstance::GetInstance ()
1908 return instance;
1911 NPWindow*
1912 PluginInstance::GetWindow ()
1914 return window;
1917 // [Obselete (this is obsolete in SL b2.)]
1918 guint32
1919 PluginInstance::TimeoutAdd (gint32 interval, GSourceFunc callback, gpointer data)
1921 guint32 id;
1923 #if GLIB_CHECK_VERSION(2,14,0)
1924 if (glib_check_version (2,14,0) && interval > 1000 && ((interval % 1000) == 0))
1925 id = g_timeout_add_seconds (interval / 1000, callback, data);
1926 else
1927 #endif
1928 id = g_timeout_add (interval, callback, data);
1930 timers = g_slist_append (timers, GINT_TO_POINTER ((int)id));
1932 return id;
1935 // [Obselete (this is obsolete in SL b2.)]
1936 void
1937 PluginInstance::TimeoutStop (guint32 source_id)
1939 g_source_remove (source_id);
1940 timers = g_slist_remove (timers, GINT_TO_POINTER (source_id));
1943 char*
1944 plugin_instance_get_id (PluginInstance *instance)
1946 return instance->GetId ();
1949 void
1950 plugin_instance_get_browser_runtime_settings (bool *debug, bool *html_access,
1951 bool *httpnet_access, bool *script_access)
1953 *debug = *html_access = *httpnet_access = *script_access = false;
1957 XamlLoader
1960 bool
1961 PluginXamlLoader::LoadVM ()
1963 #if PLUGIN_SL_2_0
1964 return InitializeLoader ();
1965 #endif
1966 return false;
1969 bool
1970 PluginXamlLoader::InitializeLoader ()
1972 if (initialized)
1973 return true;
1975 #if PLUGIN_SL_2_0
1976 if (managed_loader)
1977 return true;
1979 if (GetFilename ()) {
1980 managed_loader = plugin->ManagedCreateXamlLoaderForFile (this, GetResourceBase(), GetFilename ());
1981 } else if (GetString ()) {
1982 managed_loader = plugin->ManagedCreateXamlLoaderForString (this, GetResourceBase(), GetString ());
1983 } else {
1984 return false;
1987 initialized = managed_loader != NULL;
1988 #else
1989 initialized = true;
1990 #endif
1991 return initialized;
1995 // On error it sets the @error ref to 1
1996 // Returns the filename that we are missing
1998 const char *
1999 PluginXamlLoader::TryLoad (int *error)
2001 DependencyObject *element;
2002 Type::Kind element_type;
2004 *error = 0;
2006 //d(printf ("PluginXamlLoader::TryLoad, filename: %s, str: %s\n", GetFilename (), GetString ()));
2008 GetSurface ()->Attach (NULL);
2010 if (GetFilename ()) {
2011 element = CreateDependencyObjectFromFile (GetFilename (), true, &element_type);
2012 } else if (GetString ()) {
2013 element = CreateDependencyObjectFromString (GetString (), true, &element_type);
2014 } else {
2015 *error = 1;
2016 return NULL;
2019 if (!element) {
2020 if (error_args && error_args->error_code != -1) {
2021 d(printf ("PluginXamlLoader::TryLoad: Could not load xaml %s: %s (error: %s attr=%s)\n",
2022 GetFilename () ? "file" : "string", GetFilename () ? GetFilename () : GetString (),
2023 error_args->xml_element, error_args->xml_attribute));
2024 error_args->ref ();
2025 GetSurface ()->EmitError (error_args);
2026 return NULL;
2027 } else {
2029 d(printf ("PluginXamlLoader::TryLoad: Could not load xaml %s: %s (missing_assembly: %s)\n",
2030 GetFilename () ? "file" : "string", GetFilename () ? GetFilename () : GetString (),
2031 GetMissing ()));
2033 xaml_is_managed = true;
2034 return GetMissing ();
2036 return NULL;
2040 Type *t = Type::Find(element_type);
2041 if (!t) {
2042 d(printf ("PluginXamlLoader::TryLoad: Return value does not subclass Canvas, it is an unregistered type\n"));
2043 element->unref ();
2044 GetSurface ()->EmitError (new ErrorEventArgs (RuntimeError, 2101, "Failed to initialize the application's root visual"));
2045 return NULL;
2048 if (!t->IsSubclassOf(Type::PANEL)) {
2049 d(printf ("PluginXamlLoader::TryLoad: Return value does not subclass of Panel, it is a %s\n",
2050 element->GetTypeName ()));
2051 element->unref ();
2052 GetSurface ()->EmitError (new ErrorEventArgs (RuntimeError, 2101, "Failed to initialize the application's root visual"));
2053 return NULL;
2056 //d(printf ("PluginXamlLoader::TryLoad () succeeded.\n"));
2058 GetSurface ()->Attach ((Panel*) element);
2060 // xaml_create_from_* passed us a ref which we don't need to
2061 // keep.
2062 element->unref ();
2064 return NULL;
2067 bool
2068 PluginXamlLoader::SetProperty (void *parser, Value *top_level, const char *xmlns, Value* target, void* target_data, Value *target_parent, const char *prop_xmlns, const char *name, Value* value, void* value_data)
2070 if (XamlLoader::SetProperty (parser, top_level, xmlns, target, target_data, target_parent, prop_xmlns, name, value, value_data))
2071 return true;
2073 if (value->GetKind () != Type::STRING)
2074 return false;
2076 if (!xaml_is_valid_event_name (target->GetKind(), name, false))
2077 return false;
2079 const char* function_name = value->AsString ();
2081 if (!strncmp (function_name, "javascript:", strlen ("javascript:")))
2082 return false;
2084 event_object_add_xaml_listener ((EventObject *) target->AsDependencyObject (), plugin, name, function_name);
2086 return true;
2089 PluginXamlLoader::PluginXamlLoader (const char *resourceBase, const char *filename, const char *str, PluginInstance *plugin, Surface *surface, bool import_default_xmlns)
2090 : XamlLoader (resourceBase, filename, str, surface)
2092 this->plugin = plugin;
2093 xaml_is_managed = false;
2094 initialized = false;
2095 error_args = NULL;
2097 SetImportDefaultXmlns (import_default_xmlns);
2099 #if PLUGIN_SL_2_0
2100 xap = NULL;
2102 managed_loader = NULL;
2103 #endif
2106 PluginXamlLoader::~PluginXamlLoader ()
2108 #if PLUGIN_SL_2_0
2109 if (xap)
2110 delete xap;
2112 if (managed_loader)
2113 plugin->ManagedLoaderDestroy (managed_loader);
2114 #endif
2117 PluginXamlLoader *
2118 plugin_xaml_loader_from_str (const char *resourceBase, const char *str, PluginInstance *plugin, Surface *surface)
2120 return PluginXamlLoader::FromStr (resourceBase, str, plugin, surface);
2124 // Our Mono embedding bits are here. By storing the mono_domain in
2125 // the PluginInstance instead of in a global variable, we don't need
2126 // the code in moonlight.cs for managing app domains.
2127 #if PLUGIN_SL_2_0
2128 MonoMethod *
2129 PluginInstance::MonoGetMethodFromName (MonoClass *klass, const char *name, int narg)
2131 MonoMethod *method;
2132 method = mono_class_get_method_from_name (klass, name, narg);
2134 if (!method)
2135 printf ("Warning could not find method %s\n", name);
2137 return method;
2140 MonoProperty *
2141 PluginInstance::MonoGetPropertyFromName (MonoClass *klass, const char *name)
2143 MonoProperty *property;
2144 property = mono_class_get_property_from_name (klass, name);
2146 if (!property)
2147 printf ("Warning could not find property %s\n", name);
2149 return property;
2152 bool PluginInstance::mono_is_loaded = false;
2154 bool
2155 PluginInstance::MonoIsLoaded ()
2157 return mono_is_loaded;
2160 extern "C" {
2161 extern gboolean mono_jit_set_trace_options (const char *options);
2164 bool
2165 PluginInstance::DeploymentInit ()
2167 return mono_is_loaded = true; // We load mono in runtime_init.
2171 bool
2172 PluginInstance::CreatePluginDeployment ()
2174 deployment = new Deployment ();
2175 Deployment::SetCurrent (deployment);
2177 return true;
2180 bool
2181 PluginInstance::InitializePluginAppDomain ()
2183 bool result = false;
2185 system_windows_assembly = mono_assembly_load_with_partial_name ("System.Windows, Version=2.0.5.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e", NULL);
2187 if (system_windows_assembly) {
2188 MonoImage *image;
2189 MonoClass *app_launcher;
2191 result = true;
2193 image = mono_assembly_get_image (system_windows_assembly);
2195 d (printf ("Assembly: %s\n", mono_image_get_filename (image)));
2197 app_launcher = mono_class_from_name (image, "Mono", "ApplicationLauncher");
2198 if (!app_launcher) {
2199 g_warning ("could not find ApplicationLauncher type");
2200 return false;
2203 moon_exception = mono_class_from_name (image, "Mono", "MoonException");
2204 if (!moon_exception) {
2205 g_warning ("could not find MoonException type");
2206 return false;
2209 moon_load_xaml = MonoGetMethodFromName (app_launcher, "CreateXamlLoader", -1);
2210 moon_initialize_deployment_xap = MonoGetMethodFromName (app_launcher, "InitializeDeployment", 2);
2211 moon_initialize_deployment_xaml = MonoGetMethodFromName (app_launcher, "InitializeDeployment", 0);
2212 moon_destroy_application = MonoGetMethodFromName (app_launcher, "DestroyApplication", -1);
2214 if (moon_load_xaml == NULL || moon_initialize_deployment_xap == NULL || moon_initialize_deployment_xaml == NULL || moon_destroy_application == NULL) {
2215 g_warning ("lookup for ApplicationLauncher methods failed");
2216 result = false;
2219 moon_exception_message = MonoGetPropertyFromName (mono_get_exception_class(), "Message");
2220 moon_exception_error_code = MonoGetPropertyFromName (moon_exception, "ErrorCode");
2222 if (moon_exception_message == NULL || moon_exception_error_code == NULL) {
2223 g_warning ("lookup for MoonException properties failed");
2224 result = false;
2226 } else {
2227 printf ("Plugin AppDomain Creation: could not find System.Windows.dll.\n");
2230 printf ("Plugin AppDomain Creation: %s\n", result ? "OK" : "Failed");
2232 return result;
2235 ErrorEventArgs *
2236 PluginInstance::ManagedExceptionToErrorEventArgs (MonoObject *exc)
2238 int errorCode = -1;
2239 char* message = NULL;
2241 if (mono_object_isinst (exc, mono_get_exception_class())) {
2242 MonoObject *ret = mono_property_get_value (moon_exception_message, exc, NULL, NULL);
2244 message = mono_string_to_utf8 ((MonoString*)ret);
2246 if (mono_object_isinst (exc, moon_exception)) {
2247 MonoObject *ret = mono_property_get_value (moon_exception_error_code, exc, NULL, NULL);
2249 errorCode = *(int*) mono_object_unbox (ret);
2252 return new ErrorEventArgs (RuntimeError, errorCode, message);
2255 gpointer
2256 PluginInstance::ManagedCreateXamlLoader (XamlLoader* native_loader, const char *resourceBase, const char *file, const char *str)
2258 MonoObject *loader;
2259 MonoObject *exc = NULL;
2260 if (moon_load_xaml == NULL)
2261 return NULL;
2263 PluginInstance *this_obj = this;
2264 void *params [6];
2266 Deployment::SetCurrent (deployment);
2268 params [0] = &native_loader;
2269 params [1] = &this_obj;
2270 params [2] = &surface;
2271 params [3] = resourceBase ? mono_string_new (mono_domain_get (), resourceBase) : NULL;
2272 params [4] = file ? mono_string_new (mono_domain_get (), file) : NULL;
2273 params [5] = str ? mono_string_new (mono_domain_get (), str) : NULL;
2274 loader = mono_runtime_invoke (moon_load_xaml, NULL, params, &exc);
2276 if (exc) {
2277 deployment->GetSurface()->EmitError (ManagedExceptionToErrorEventArgs (exc));
2278 return NULL;
2281 return GUINT_TO_POINTER (mono_gchandle_new (loader, false));
2284 gpointer
2285 PluginInstance::ManagedCreateXamlLoaderForFile (XamlLoader *native_loader, const char *resourceBase, const char *file)
2287 return ManagedCreateXamlLoader (native_loader, resourceBase, file, NULL);
2290 gpointer
2291 PluginInstance::ManagedCreateXamlLoaderForString (XamlLoader* native_loader, const char *resourceBase, const char *str)
2293 return ManagedCreateXamlLoader (native_loader, resourceBase, NULL, str);
2296 void
2297 PluginInstance::ManagedLoaderDestroy (gpointer loader_object)
2299 guint32 loader = GPOINTER_TO_UINT (loader_object);
2300 if (loader)
2301 mono_gchandle_free (loader);
2304 bool
2305 PluginInstance::ManagedInitializeDeployment (const char *file)
2307 if (moon_initialize_deployment_xap == NULL && moon_initialize_deployment_xaml)
2308 return NULL;
2310 PluginInstance *this_obj = this;
2311 void *params [2];
2312 MonoObject *ret;
2313 MonoObject *exc = NULL;
2315 Deployment::SetCurrent (deployment);
2317 params [0] = &this_obj;
2318 if (file != NULL) {
2319 params [1] = mono_string_new (mono_domain_get (), file);
2320 ret = mono_runtime_invoke (moon_initialize_deployment_xap, NULL, params, &exc);
2321 } else {
2322 ret = mono_runtime_invoke (moon_initialize_deployment_xaml, NULL, params, &exc);
2325 if (exc) {
2326 deployment->GetSurface()->EmitError (ManagedExceptionToErrorEventArgs (exc));
2327 return false;
2330 return (bool) (*(MonoBoolean *) mono_object_unbox(ret));
2333 void
2334 PluginInstance::ManagedDestroyApplication ()
2336 if (moon_destroy_application == NULL)
2337 return;
2339 PluginInstance *this_obj = this;
2340 MonoObject *exc = NULL;
2341 void *params [1];
2342 params [0] = &this_obj;
2344 Deployment::SetCurrent (deployment);
2346 mono_runtime_invoke (moon_destroy_application, NULL, params, &exc);
2348 if (exc)
2349 deployment->GetSurface()->EmitError (ManagedExceptionToErrorEventArgs (exc));
2352 #endif