2009-10-05 Chris Toshok <toshok@ximian.com>
[moon.git] / plugin / plugin.cpp
blobd811e27b6521f9776f90431079c34e7511030ee3
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, "RuntimeVersion:", 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 if (!xaml_loader || xaml_loader->IsManaged ()) {
315 Deployment *deployment = GetDeployment ();
317 if (deployment && deployment->GetRuntimeVersion ()) {
318 table_add (table, deployment->GetRuntimeVersion (), 1, row++);
319 } else {
320 table_add (table, "(Unknown)", 1, row++);
322 } else {
323 table_add (table, "1.0 (Pure XAML)", 1, row++);
325 table_add (table, windowless ? "yes" : "no", 1, row++);
326 snprintf (buffer, sizeof (buffer), "%i", maxFrameRate);
327 table_add (table, buffer, 1, row++);
328 #if INCLUDE_FFMPEG
329 table_add (table, Media::IsMSCodecsInstalled () ? "ms-codecs" : "ffmpeg", 1, row++);
330 #else
331 table_add (table, Media::IsMSCodecsInstalled () ? "ms-codecs" : "none", 1, row++);
332 #endif
334 row++;
335 properties_fps_label = gtk_label_new ("");
336 gtk_misc_set_alignment (GTK_MISC (properties_fps_label), 0.0, 0.5);
337 gtk_table_attach (GTK_TABLE(table), properties_fps_label, 0, 2, row, row+1, (GtkAttachOptions) (GTK_FILL), (GtkAttachOptions) 0, 4, 0);
339 row++;
340 properties_cache_label = gtk_label_new ("");
341 gtk_misc_set_alignment (GTK_MISC (properties_cache_label), 0.0, 0.5);
342 gtk_table_attach (GTK_TABLE(table), properties_cache_label, 0, 2, row, row+1, (GtkAttachOptions) (GTK_FILL), (GtkAttachOptions) 0, 4, 0);
344 // Runtime debug options
345 gtk_box_pack_start (vbox, title ("Runtime Debug Options"), FALSE, FALSE, 0);
346 gtk_box_pack_start (vbox, gtk_hseparator_new (), FALSE, FALSE, 8);
348 checkbox = gtk_check_button_new_with_label ("Show exposed regions");
349 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (checkbox), moonlight_flags & RUNTIME_INIT_SHOW_EXPOSE);
350 g_signal_connect (checkbox, "toggled", G_CALLBACK (expose_regions), NULL);
351 gtk_box_pack_start (vbox, checkbox, FALSE, FALSE, 0);
353 checkbox = gtk_check_button_new_with_label ("Show clipping regions");
354 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (checkbox), moonlight_flags & RUNTIME_INIT_SHOW_CLIPPING);
355 g_signal_connect (checkbox, "toggled", G_CALLBACK (clipping_regions), NULL);
356 gtk_box_pack_start (vbox, checkbox, FALSE, FALSE, 0);
358 checkbox = gtk_check_button_new_with_label ("Show bounding boxes");
359 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (checkbox), moonlight_flags & RUNTIME_INIT_SHOW_BOUNDING_BOXES);
360 g_signal_connect (checkbox, "toggled", G_CALLBACK (bounding_boxes), NULL);
361 gtk_box_pack_start (vbox, checkbox, FALSE, FALSE, 0);
363 checkbox = gtk_check_button_new_with_label ("Show text boxes");
364 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (checkbox), moonlight_flags & RUNTIME_INIT_SHOW_TEXTBOXES);
365 g_signal_connect (checkbox, "toggled", G_CALLBACK (textboxes), NULL);
366 gtk_box_pack_start (vbox, checkbox, FALSE, FALSE, 0);
368 checkbox = gtk_check_button_new_with_label ("Show Frames Per Second");
369 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (checkbox), moonlight_flags & RUNTIME_INIT_SHOW_FPS);
370 g_signal_connect (checkbox, "toggled", G_CALLBACK (show_fps), NULL);
371 gtk_box_pack_start (vbox, checkbox, FALSE, FALSE, 0);
373 g_signal_connect (dialog, "response", G_CALLBACK (properties_dialog_response), this);
374 gtk_widget_show_all (dialog);
377 PluginInstance::PluginInstance (NPMIMEType pluginType, NPP instance, guint16 mode)
379 this->instance = instance;
380 this->mode = mode;
381 window = NULL;
383 properties_fps_label = NULL;
384 properties_cache_label = NULL;
386 rootobject = NULL;
388 container = NULL;
389 surface = NULL;
390 moon_window = NULL;
392 // Property fields
393 source_location = NULL;
394 source_location_original = NULL;
395 initParams = NULL;
396 source = NULL;
397 source_original = NULL;
398 source_idle = 0;
399 onLoad = NULL;
400 onError = NULL;
401 onResize = NULL;
402 onSourceDownloadProgressChanged = NULL;
403 onSourceDownloadComplete = NULL;
404 splashscreensource = NULL;
405 background = NULL;
406 id = NULL;
407 culture = NULL;
408 uiCulture = NULL;
410 windowless = false;
411 cross_domain_app = false; // false, since embedded xaml (in html) won't load anything (to change this value)
412 default_enable_html_access = true; // should we use the default value (wrt the HTML script supplied value)
413 enable_html_access = true; // an empty plugin must return TRUE before loading anything else (e.g. scripting)
414 allow_html_popup_window = false;
415 xembed_supported = FALSE;
416 loading_splash = false;
417 is_splash = false;
419 bridge = NULL;
421 // MSDN says the default is 24: http://msdn2.microsoft.com/en-us/library/bb979688.aspx
422 // 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
423 // testing seems to confirm that the default is 60.
424 maxFrameRate = 60;
425 enable_framerate_counter = false;
427 vm_missing_file = NULL;
428 xaml_loader = NULL;
429 #if PLUGIN_SL_2_0
430 system_windows_assembly = NULL;
432 moon_load_xaml =
433 moon_initialize_deployment_xap =
434 moon_initialize_deployment_xaml =
435 moon_destroy_application = NULL;
437 #endif
438 timers = NULL;
440 wrapped_objects = g_hash_table_new (g_direct_hash, g_direct_equal);
442 cleanup_pointers = NULL;
444 plugin_instances = g_slist_append (plugin_instances, instance);
446 /* back pointer to us */
447 instance->pdata = this;
449 #if DEBUG
450 moon_sources = NULL;
451 #endif
454 PluginInstance::~PluginInstance ()
456 // Kill timers
457 GSList *p;
459 Deployment::SetCurrent (deployment);
461 for (p = timers; p != NULL; p = p->next){
462 guint32 source_id = GPOINTER_TO_INT (p->data);
464 g_source_remove (source_id);
466 g_slist_free (p);
468 g_hash_table_destroy (wrapped_objects);
470 // Remove us from the list.
471 plugin_instances = g_slist_remove (plugin_instances, instance);
473 for (GSList *l = cleanup_pointers; l; l = l->next) {
474 gpointer* p = (gpointer*)l->data;
475 *p = NULL;
477 g_slist_free (cleanup_pointers);
479 if (rootobject)
480 NPN_ReleaseObject ((NPObject*)rootobject);
482 g_free (background);
483 g_free (id);
484 g_free (onSourceDownloadProgressChanged);
485 g_free (onSourceDownloadComplete);
486 g_free (splashscreensource);
487 g_free (culture);
488 g_free (uiCulture);
489 g_free (initParams);
490 g_free (vm_missing_file);
491 delete xaml_loader;
493 #if PLUGIN_SL_2_0
494 // Destroy the XAP application
495 DestroyApplication ();
496 #endif
498 g_free (source);
499 g_free (source_original);
500 g_free (source_location);
501 g_free (source_location_original);
503 if (source_idle)
504 g_source_remove (source_idle);
507 // The code below was an attempt at fixing this, but we are still getting spurious errors
508 // we might have another source of problems
510 //fprintf (stderr, "Destroying the surface: %p, plugin: %p\n", surface, this);
511 if (surface != NULL) {
512 //gdk_error_trap_push ();
513 surface->Zombify();
514 surface->Dispose ();
515 surface->unref_delayed();
516 //gdk_display_sync (display);
517 //gdk_error_trap_pop ();
520 if (bridge)
521 delete bridge;
522 bridge = NULL;
524 deployment->Dispose ();
525 deployment->unref_delayed();
526 #if DEBUG
527 delete moon_sources;
528 #endif
531 #if DEBUG
532 void
533 PluginInstance::AddSource (const char *uri, const char *filename)
535 moon_source *src = new moon_source ();
536 src->uri = g_strdup (uri);
537 src->filename = g_strdup (filename);
538 if (moon_sources == NULL)
539 moon_sources = new List ();
540 moon_sources->Append (src);
543 List*
544 PluginInstance::GetSources ()
546 return moon_sources;
548 #endif
551 static bool
552 same_site_of_origin (const char *url1, const char *url2)
554 bool result = false;
555 Uri *uri1;
557 if (url1 == NULL || url2 == NULL)
558 return false;
560 uri1 = new Uri ();
561 if (uri1->Parse (url1)) {
562 Uri *uri2 = new Uri ();
564 if (uri2->Parse (url2)) {
565 // if only one of the two URI is absolute then the second one is relative to the first,
566 // which makes it part of the same site of origin
567 if ((uri1->isAbsolute && !uri2->isAbsolute) || (!uri1->isAbsolute && uri2->isAbsolute))
568 result = true;
569 else
570 result = Uri::SameSiteOfOrigin (uri1, uri2);
572 delete uri2;
574 delete uri1;
575 return result;
578 static bool
579 parse_bool_arg (const char *arg)
581 bool b;
582 return xaml_bool_from_str (arg, &b) && b;
585 void
586 PluginInstance::Initialize (int argc, char* const argn[], char* const argv[])
588 for (int i = 0; i < argc; i++) {
589 if (argn[i] == NULL) {
590 //g_warning ("PluginInstance::Initialize, arg %d == NULL", i);
591 continue;
593 else if (!g_ascii_strcasecmp (argn[i], "initParams")) {
594 initParams = g_strdup (argv[i]);
596 else if (!g_ascii_strcasecmp (argn[i], "onLoad")) {
597 onLoad = argv[i];
599 else if (!g_ascii_strcasecmp (argn[i], "onError")) {
600 onError = argv[i];
602 else if (!g_ascii_strcasecmp (argn[i], "onResize")) {
603 onResize = argv[i];
605 else if (!g_ascii_strcasecmp (argn[i], "src") || !g_ascii_strcasecmp (argn[i], "source")) {
606 /* There is a new design pattern that creates a silverlight object with data="data:application/x-silverlight,"
607 * firefox is passing this to us as the src element. We need to ensure we dont set source to this value
608 * as this design pattern sets a xap up after the fact, but checks to ensure Source hasn't been set yet.
610 * eg: http://theamazingalbumcoveratlas.org/
612 * TODO: Find a site that has data:application/x-silverlight,SOMEDATA and figure out what we do with it
614 if (g_ascii_strncasecmp (argv[i], "data:application/x-silverlight", 30) != 0 && argv[i][strlen(argv[i])-1] != ',') {
615 source = g_strdup (argv[i]);
616 // we must be able to retrieve the original source, e.g. after a redirect
617 source_original = g_strdup (source);
620 else if (!g_ascii_strcasecmp (argn[i], "background")) {
621 background = g_strdup (argv[i]);
623 else if (!g_ascii_strcasecmp (argn [i], "windowless")) {
624 windowless = parse_bool_arg (argv [i]);
626 else if (!g_ascii_strcasecmp (argn [i], "maxFramerate")) {
627 maxFrameRate = atoi (argv [i]);
629 else if (!g_ascii_strcasecmp (argn [i], "id")) {
630 id = g_strdup (argv [i]);
632 else if (!g_ascii_strcasecmp (argn [i], "enablehtmlaccess")) {
633 default_enable_html_access = false; // we're using the application value, not the default one
634 enable_html_access = parse_bool_arg (argv [i]);
636 else if (!g_ascii_strcasecmp (argn [i], "allowhtmlpopupwindow")) {
637 allow_html_popup_window = parse_bool_arg (argv [i]);
639 else if (!g_ascii_strcasecmp (argn [i], "splashscreensource")) {
640 splashscreensource = g_strdup (argv [i]);
642 else if (!g_ascii_strcasecmp (argn [i], "onSourceDownloadProgressChanged")) {
643 onSourceDownloadProgressChanged = g_strdup (argv [i]);
645 else if (!g_ascii_strcasecmp (argn [i], "onSourceDownloadComplete")) {
646 onSourceDownloadComplete = g_strdup (argv [i]);
648 else if (!g_ascii_strcasecmp (argn [i], "culture")) {
649 culture = g_strdup (argv[i]);
651 else if (!g_ascii_strcasecmp (argn [i], "uiCulture")) {
652 uiCulture = g_strdup (argv[i]);
654 else {
655 //fprintf (stderr, "unhandled attribute %s='%s' in PluginInstance::Initialize\n", argn[i], argv[i]);
659 // like 'source' the original location can also be required later (for cross-domain checks after redirections)
660 source_location_original = GetPageLocation ();
662 guint32 supportsWindowless = FALSE; // NPBool + padding
664 int plugin_major, plugin_minor;
665 int netscape_major, netscape_minor;
666 bool try_opera_quirks = FALSE;
668 /* Find the version numbers. */
669 NPN_Version(&plugin_major, &plugin_minor,
670 &netscape_major, &netscape_minor);
672 //d(printf ("Plugin NPAPI version = %d.%d\n", plugin_major, netscape_minor));
673 //d(printf ("Browser NPAPI version = %d.%d\n", netscape_major, netscape_minor));
675 NPError error;
676 error = NPN_GetValue (instance, NPNVSupportsXEmbedBool, &xembed_supported);
677 if (error || !xembed_supported) {
678 // This should be an error but we'll use it to detect
679 // that we are running in opera
680 //return NPERR_INCOMPATIBLE_VERSION_ERROR;
681 if (!windowless)
682 d(printf ("*** XEmbed not supported\n"));
684 try_opera_quirks = true;
687 error = NPN_GetValue (instance, NPNVSupportsWindowless, &supportsWindowless);
688 supportsWindowless = (error == NPERR_NO_ERROR) && supportsWindowless;
690 #ifdef DEBUG
691 if ((moonlight_flags & RUNTIME_INIT_ALLOW_WINDOWLESS) == 0) {
692 printf ("plugin wants to be windowless, but we're not going to let it\n");
693 windowless = false;
695 #endif
696 if (windowless) {
697 if (supportsWindowless) {
698 NPN_SetValue (instance, NPPVpluginWindowBool, (void *) FALSE);
699 NPN_SetValue (instance, NPPVpluginTransparentBool, (void *) TRUE);
700 d(printf ("windowless mode\n"));
701 } else {
702 d(printf ("browser doesn't support windowless mode.\n"));
703 windowless = false;
707 // grovel around in the useragent and try to figure out which
708 // browser bridge we should use.
709 const char *useragent = NPN_UserAgent (instance);
711 if (strstr (useragent, "Opera")) {
712 // opera based
713 TryLoadBridge ("opera");
715 else if (strstr (useragent, "AppleWebKit")) {
716 // webkit based
717 TryLoadBridge ("webkit");
719 else if (strstr (useragent, "Gecko")) {
720 // gecko based, let's look for 'rv:1.8' vs 'rv:1.9'
721 if (strstr (useragent, "rv:1.8")) {
722 TryLoadBridge ("ff2");
724 else if (strstr (useragent, "rv:1.9")) {
725 TryLoadBridge ("ff3");
729 // XXX Opera currently claims to be mozilla when we query it
730 if (!bridge && try_opera_quirks)
731 TryLoadBridge ("opera");
733 if (!bridge) {
734 g_warning ("probing for browser type failed, user agent = `%s'",
735 useragent);
738 if (!CreatePluginDeployment ()) {
739 g_warning ("Couldn't initialize Mono or create the plugin Deployment");
743 typedef BrowserBridge* (*create_bridge_func)();
745 const char*
746 get_plugin_dir (void)
748 static char *plugin_dir = NULL;
750 if (!plugin_dir) {
751 Dl_info dlinfo;
752 if (dladdr((void *) &plugin_show_menu, &dlinfo) == 0) {
753 fprintf (stderr, "Unable to find the location of libmoonplugin.so: %s\n", dlerror ());
754 return NULL;
756 plugin_dir = g_path_get_dirname (dlinfo.dli_fname);
758 return plugin_dir;
761 void
762 PluginInstance::TryLoadBridge (const char *prefix)
764 char *bridge_name = g_strdup_printf ("libmoonplugin-%sbridge.so", prefix);
765 char *bridge_path;
767 bridge_path = g_build_filename (get_plugin_dir (), bridge_name, NULL);
769 void* bridge_handle = dlopen (bridge_path, RTLD_LAZY);
771 g_free (bridge_name);
772 g_free (bridge_path);
774 if (bridge_handle == NULL) {
775 g_warning ("failed to load browser bridge: %s", dlerror());
776 return;
779 create_bridge_func bridge_ctor = (create_bridge_func)dlsym (bridge_handle, "CreateBrowserBridge");
780 if (bridge_ctor == NULL) {
781 g_warning ("failed to locate CreateBrowserBridge symbol: %s", dlerror());
782 return;
785 bridge = bridge_ctor ();
788 void
789 PluginInstance::Finalize ()
793 NPError
794 PluginInstance::GetValue (NPPVariable variable, void *result)
796 NPError err = NPERR_NO_ERROR;
798 switch (variable) {
799 case NPPVpluginNeedsXEmbed:
800 *((NPBool *)result) = !windowless;
801 break;
802 case NPPVpluginScriptableNPObject:
803 *((NPObject**) result) = GetRootObject ();
804 break;
805 default:
806 err = NPERR_INVALID_PARAM;
807 break;
810 return err;
813 NPError
814 PluginInstance::SetValue (NPNVariable variable, void *value)
816 return NPERR_NO_ERROR;
819 NPError
820 PluginInstance::SetWindow (NPWindow *window)
822 Deployment::SetCurrent (deployment);
824 if (moon_window) {
825 // XXX opera Window lifetime hack needs this
826 this->window = window;
828 if (!surface)
829 return NPERR_GENERIC_ERROR;
831 moon_window->Resize (window->width, window->height);
832 return NPERR_NO_ERROR;
835 this->window = window;
836 CreateWindow ();
838 return NPERR_NO_ERROR;
841 NPObject*
842 PluginInstance::GetHost()
844 NPObject *object = NULL;
845 if (NPERR_NO_ERROR != NPN_GetValue(instance, NPNVPluginElementNPObject, &object)) {
846 d(printf ("Failed to get plugin host object\n"));
848 return object;
851 void
852 PluginInstance::ReportFPS (Surface *surface, int nframes, float nsecs, void *user_data)
854 PluginInstance *plugin = (PluginInstance *) user_data;
855 char *msg;
857 msg = g_strdup_printf ("Rendered %d frames in %.3fs = %.3f FPS",
858 nframes, nsecs, nframes / nsecs);
860 NPN_Status (plugin->instance, msg);
862 if (plugin->properties_fps_label)
863 gtk_label_set_text (GTK_LABEL (plugin->properties_fps_label), msg);
865 g_free (msg);
868 void
869 PluginInstance::ReportCache (Surface *surface, long bytes, void *user_data)
871 PluginInstance *plugin = (PluginInstance *) user_data;
872 char *msg;
874 if (bytes < 1048576)
875 msg = g_strdup_printf ("Cache size is ~%d KB", (int) (bytes / 1024));
876 else
877 msg = g_strdup_printf ("Cache size is ~%.2f MB", bytes / 1048576.0);
879 NPN_Status (plugin->instance, msg);
881 if (plugin->properties_cache_label)
882 gtk_label_set_text (GTK_LABEL (plugin->properties_cache_label), msg);
884 g_free (msg);
887 static void
888 register_event (NPP instance, const char *event_name, char *script_name, NPObject *npobj)
890 if (!script_name)
891 return;
893 char *retval = NPN_strdup (script_name);
894 NPVariant npvalue;
896 STRINGZ_TO_NPVARIANT (retval, npvalue);
897 NPIdentifier identifier = NPN_GetStringIdentifier (event_name);
898 NPN_SetProperty (instance, npobj, identifier, &npvalue);
899 NPN_MemFree (retval);
902 bool
903 PluginInstance::IsLoaded ()
905 if (!GetSurface () || is_splash)
906 return false;
908 return GetSurface()->IsLoaded();
911 void
912 PluginInstance::CreateWindow ()
914 if (windowless) {
915 moon_window = new MoonWindowless (window->width, window->height, this);
916 moon_window->SetTransparent (true);
918 else {
919 moon_window = new MoonWindowGtk (false, window->width, window->height);
922 surface = new Surface (moon_window);
923 deployment->SetSurface (surface);
925 MoonlightScriptControlObject *root = GetRootObject ();
926 register_event (instance, "onSourceDownloadProgressChanged", onSourceDownloadProgressChanged, root);
927 register_event (instance, "onSourceDownloadComplete", onSourceDownloadComplete, root);
928 register_event (instance, "onError", onError, root);
929 // register_event (instance, "onResize", onResize, rootx->content);
931 // NOTE: last testing showed this call causes opera to reenter but moving it is trouble and
932 // the bug is on opera's side.
933 SetPageURL ();
934 LoadSplash ();
936 surface->SetFPSReportFunc (ReportFPS, this);
937 surface->SetCacheReportFunc (ReportCache, this);
938 surface->SetDownloaderContext (this);
940 surface->GetTimeManager()->SetMaximumRefreshRate (maxFrameRate);
942 if (background) {
943 Color *c = color_from_str (background);
945 if (c == NULL) {
946 d(printf ("error setting background color\n"));
947 c = new Color (0x00FFFFFF);
950 surface->SetBackgroundColor (c);
951 delete c;
954 if (!windowless) {
955 // GtkPlug container and surface inside
956 container = gtk_plug_new ((GdkNativeWindow) window->window);
958 // Connect signals to container
959 GTK_WIDGET_SET_FLAGS (GTK_WIDGET (container), GTK_CAN_FOCUS);
961 gtk_widget_add_events (container,
962 GDK_BUTTON_PRESS_MASK |
963 GDK_BUTTON_RELEASE_MASK |
964 GDK_KEY_PRESS_MASK |
965 GDK_KEY_RELEASE_MASK |
966 GDK_POINTER_MOTION_MASK |
967 GDK_SCROLL_MASK |
968 GDK_EXPOSURE_MASK |
969 GDK_VISIBILITY_NOTIFY_MASK |
970 GDK_ENTER_NOTIFY_MASK |
971 GDK_LEAVE_NOTIFY_MASK |
972 GDK_FOCUS_CHANGE_MASK
975 g_signal_connect (G_OBJECT(container), "button-press-event", G_CALLBACK (PluginInstance::plugin_button_press_callback), this);
977 gtk_container_add (GTK_CONTAINER (container), ((MoonWindowGtk*)moon_window)->GetWidget());
978 //display = gdk_drawable_get_display (surface->GetWidget()->window);
979 gtk_widget_show_all (container);
983 void
984 PluginInstance::UpdateSource ()
986 if (source_idle) {
987 g_source_remove (source_idle);
988 source_idle = 0;
991 if (surface != NULL)
992 surface->DetachDownloaders ();
994 if (!source || strlen (source) == 0)
995 return;
997 char *pos = strchr (source, '#');
998 if (pos) {
999 // FIXME: this will crash if this object has been deleted by the time IdleUpdateSourceByReference is called.
1000 source_idle = g_idle_add (IdleUpdateSourceByReference, this);
1001 SetPageURL ();
1002 } else {
1003 StreamNotify *notify = new StreamNotify (StreamNotify::SOURCE, source);
1005 // FIXME: check for errors
1006 NPN_GetURLNotify (instance, source, NULL, notify);
1010 gboolean
1011 PluginInstance::IdleUpdateSourceByReference (gpointer data)
1013 PluginInstance *instance = (PluginInstance*)data;
1014 char *pos = NULL;
1016 instance->source_idle = 0;
1018 if (instance->source)
1019 pos = strchr (instance->source, '#');
1021 if (pos && strlen (pos+1) > 0)
1022 instance->UpdateSourceByReference (pos+1);
1024 instance->GetSurface ()->EmitSourceDownloadProgressChanged (new DownloadProgressEventArgs (1.0));
1025 instance->GetSurface ()->EmitSourceDownloadComplete ();
1026 return FALSE;
1029 void
1030 PluginInstance::UpdateSourceByReference (const char *value)
1032 // basically do the equivalent of document.getElementById('@value').textContent
1033 // all using NPAPI.
1035 NPVariant _document;
1036 NPVariant _element;
1037 NPVariant _elementName;
1038 NPVariant _textContent;
1040 Deployment::SetCurrent (deployment);
1042 NPIdentifier id_ownerDocument = NPN_GetStringIdentifier ("ownerDocument");
1043 NPIdentifier id_getElementById = NPN_GetStringIdentifier ("getElementById");
1044 NPIdentifier id_textContent = NPN_GetStringIdentifier ("textContent");
1046 NPObject *host = GetHost();
1047 if (!host) {
1048 // printf ("no host\n");
1049 return;
1052 // get host.ownerDocument
1053 bool nperr;
1054 if (!(nperr = NPN_GetProperty (instance, host, id_ownerDocument, &_document))
1055 || !NPVARIANT_IS_OBJECT (_document)) {
1056 // printf ("no document (type == %d, nperr = %d)\n", _document.type, nperr);
1057 return;
1060 // _element = document.getElementById ('@value')
1061 string_to_npvariant (value, &_elementName);
1062 if (!(nperr = NPN_Invoke (instance, NPVARIANT_TO_OBJECT (_document), id_getElementById,
1063 &_elementName, 1, &_element))
1064 || !NPVARIANT_IS_OBJECT (_element)) {
1065 // printf ("no valid element named #%s (type = %d, nperr = %d)\n", value, _element.type, nperr);
1066 NPN_ReleaseVariantValue (&_document);
1069 // _textContent = _element.textContent
1070 if (!(nperr = NPN_GetProperty (instance, NPVARIANT_TO_OBJECT (_element), id_textContent, &_textContent))
1071 || !NPVARIANT_IS_STRING (_textContent)) {
1072 // printf ("no text content for element named #%s (type = %d, nperr = %d)\n", value, _textContent.type, nperr);
1073 NPN_ReleaseVariantValue (&_document);
1074 NPN_ReleaseVariantValue (&_element);
1075 return;
1078 char *xaml = g_strndup ((char *) NPVARIANT_TO_STRING (_textContent).utf8characters, NPVARIANT_TO_STRING (_textContent).utf8length);
1080 // printf ("yay, xaml = %s\n", xaml);
1082 if (xaml_loader)
1083 delete xaml_loader;
1085 xaml_loader = PluginXamlLoader::FromStr (NULL/*FIXME*/, xaml, this, surface);
1086 LoadXAML ();
1088 g_free (xaml);
1090 NPN_ReleaseVariantValue (&_document);
1091 NPN_ReleaseVariantValue (&_element);
1092 NPN_ReleaseVariantValue (&_textContent);
1096 Downloader *
1097 PluginInstance::CreateDownloader (PluginInstance *instance)
1099 if (instance) {
1100 return instance->surface->CreateDownloader ();
1101 } else {
1102 printf ("PluginInstance::CreateDownloader (%p): Unable to create contextual downloader.\n", instance);
1103 return new Downloader ();
1107 void
1108 PluginInstance::SetInitParams (const char *value)
1110 g_free (initParams);
1111 initParams = g_strdup (value);
1114 char*
1115 PluginInstance::GetPageLocation ()
1117 char *location = NULL;
1118 NPIdentifier str_location = NPN_GetStringIdentifier ("location");
1119 NPIdentifier str_href = NPN_GetStringIdentifier ("href");
1120 NPVariant location_property;
1121 NPVariant location_object;
1122 NPObject *window;
1124 if (NPERR_NO_ERROR == NPN_GetValue (instance, NPNVWindowNPObject, &window)) {
1125 // Get the location property from the window object (which is another object).
1126 if (NPN_GetProperty (instance, window, str_location, &location_property)) {
1127 // Get the location property from the location object.
1128 if (NPN_GetProperty (instance, location_property.value.objectValue, str_href, &location_object )) {
1129 location = g_strndup (NPVARIANT_TO_STRING (location_object).utf8characters, NPVARIANT_TO_STRING (location_object).utf8length);
1130 NPN_ReleaseVariantValue (&location_object);
1132 NPN_ReleaseVariantValue (&location_property);
1135 NPN_ReleaseObject (window);
1136 return location;
1139 void
1140 PluginInstance::SetPageURL ()
1142 if (source_location != NULL)
1143 return;
1145 char* location = GetPageLocation ();
1146 if (location && surface) {
1147 this->source_location = location;
1148 surface->SetSourceLocation (this->source_location);
1153 NPError
1154 PluginInstance::NewStream (NPMIMEType type, NPStream *stream, NPBool seekable, guint16 *stype)
1156 Deployment::SetCurrent (deployment);
1158 nps (printf ("PluginInstance::NewStream (%p, %p, %i, %p)\n", type, stream, seekable, stype));
1160 if (IS_NOTIFY_SPLASHSOURCE (stream->notifyData)) {
1161 SetPageURL ();
1163 *stype = NP_ASFILEONLY;
1164 return NPERR_NO_ERROR;
1166 if (IS_NOTIFY_SOURCE (stream->notifyData)) {
1167 // See http://developer.mozilla.org/En/Getting_the_page_URL_in_NPAPI_plugin
1169 // but don't call GetProperty inside SetWindow because it breaks opera by
1170 // causing it to reenter
1172 // this->source_location = g_strdup (stream->url);
1173 SetPageURL ();
1175 *stype = NP_ASFILE;
1176 return NPERR_NO_ERROR;
1179 if (IS_NOTIFY_DOWNLOADER (stream->notifyData)) {
1180 StreamNotify *notify = (StreamNotify *) stream->notifyData;
1181 Downloader *dl = (Downloader *) notify->pdata;
1182 // check if (a) it's a redirection and (b) if it is allowed for the current downloader policy
1183 if (!dl->CheckRedirectionPolicy (stream->url))
1184 return NPERR_INVALID_URL;
1186 npstream_request_set_stream_data (dl, instance, stream);
1187 *stype = NP_ASFILE;
1188 return NPERR_NO_ERROR;
1191 if (IS_NOTIFY_REQUEST (stream->notifyData)) {
1192 *stype = NP_ASFILEONLY;
1193 return NPERR_NO_ERROR;
1196 *stype = NP_NORMAL;
1198 return NPERR_NO_ERROR;
1201 NPError
1202 PluginInstance::DestroyStream (NPStream *stream, NPError reason)
1204 nps (printf ("PluginInstance::DestroyStream (%p, %i)\n", stream, reason));
1206 PluginDownloader *pd = (PluginDownloader*) stream->pdata;
1207 if (pd != NULL) {
1208 NPStreamRequest *req = (NPStreamRequest *) pd->getRequest ();
1209 if (req != NULL)
1210 req->StreamDestroyed ();
1213 return NPERR_NO_ERROR;
1217 // Tries to load the XAML file, the parsing might fail because a
1218 // required dependency is not available, so we need to queue the
1219 // request to fetch the data.
1221 void
1222 PluginInstance::LoadXAML ()
1224 int error = 0;
1226 if (!InitializePluginAppDomain ()) {
1227 g_warning ("Couldn't initialize the plugin AppDomain");
1228 return;
1232 // Only try to load if there's no missing files.
1234 Surface *our_surface = surface;
1235 AddCleanupPointer (&our_surface);
1237 ManagedInitializeDeployment (NULL);
1238 xaml_loader->LoadVM ();
1240 MoonlightScriptControlObject *root = GetRootObject ();
1241 if (!loading_splash) {
1242 register_event (instance, "onLoad", onLoad, root);
1243 //register_event (instance, "onError", onError, root);
1244 register_event (instance, "onResize", onResize, root->content);
1245 is_splash = false;
1246 loading_splash = false;
1247 } else {
1248 register_event (instance, "onLoad", (char*)"", root);
1249 //register_event (instance, "onError", "", root);
1250 register_event (instance, "onResize", (char*)"", root->content);
1251 is_splash = true;
1252 loading_splash = false;
1255 const char *missing = xaml_loader->TryLoad (&error);
1257 if (!our_surface)
1258 return;
1260 RemoveCleanupPointer (&our_surface);
1262 if (vm_missing_file == NULL)
1263 vm_missing_file = g_strdup (missing);
1265 if (vm_missing_file != NULL) {
1266 StreamNotify *notify = new StreamNotify (StreamNotify::REQUEST, vm_missing_file);
1268 // FIXME: check for errors
1269 NPN_GetURLNotify (instance, vm_missing_file, NULL, notify);
1270 return;
1274 #if PLUGIN_SL_2_0
1276 // Loads a XAP file
1278 void
1279 PluginInstance::LoadXAP (const char *url, const char *fname)
1281 if (!InitializePluginAppDomain ()) {
1282 g_warning ("Couldn't initialize the plugin AppDomain");
1283 return;
1286 g_free (source_location);
1288 source_location = g_strdup (url);
1290 MoonlightScriptControlObject *root = GetRootObject ();
1292 register_event (instance, "onLoad", onLoad, root);
1293 //register_event (instance, "onError", onError, root);
1294 register_event (instance, "onResize", onResize, root->content);
1295 loading_splash = false;
1296 is_splash = false;
1298 Deployment::GetCurrent ()->Reinitialize ();
1299 GetDeployment()->SetXapLocation (url);
1300 ManagedInitializeDeployment (fname);
1303 void
1304 PluginInstance::DestroyApplication ()
1306 ManagedDestroyApplication ();
1308 #endif
1311 * Prepares a string to be passed to Javascript, escapes the " and '
1312 * characters and maps the newline to \n sequence and cr to \r sequence
1314 static char*
1315 string_to_js (char *s)
1317 char *res;
1318 GString *result;
1320 if (strchr (s, '\'') == NULL && strchr (s, '\n') == NULL)
1321 return g_strdup (s);
1323 result = g_string_new ("");
1325 for (char *p = s; *p != 0; *p++){
1326 if (*p == '"' || *p == '\''){
1327 g_string_append_c (result, '\\');
1328 g_string_append_c (result, *p);
1329 } else if (*p == '\n'){
1330 g_string_append_c (result, '\\');
1331 g_string_append_c (result, 'n');
1332 } else if (*p == '\r'){
1333 g_string_append_c (result, '\\');
1334 g_string_append_c (result, 'r');
1335 } else
1336 g_string_append_c (result, *p);
1339 res = result->str;
1340 g_string_free (result, FALSE);
1342 return res;
1345 void
1346 PluginInstance::ReportException (char *msg, char *details, char **stack_trace, int num_frames)
1348 NPObject *object;
1349 NPVariant result;
1350 char *script, *row_js, *msg_escaped, *details_escaped;
1351 char **stack_trace_escaped;
1352 NPString str;
1353 int i;
1354 bool res;
1356 // Get a reference to our element
1357 object = GetHost();
1358 if (!object)
1359 return;
1361 // FIXME:
1362 // - make sure the variables do not become global
1364 // Remove ' from embedded strings
1365 msg_escaped = string_to_js (msg);
1366 details_escaped = string_to_js (details);
1367 stack_trace_escaped = g_new0 (char*, num_frames);
1368 for (i = 0; i < num_frames; ++i)
1369 stack_trace_escaped [i] = string_to_js (stack_trace [i]);
1371 // JS code to create our elements
1372 row_js = g_strdup (" ");
1373 for (i = 0; i < num_frames; ++i) {
1374 char *s;
1376 s = g_strdup_printf ("%s%s%s", row_js, (i == 0) ? "" : "\\n ", stack_trace_escaped [i]);
1377 g_free (row_js);
1378 row_js = s;
1381 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);
1383 g_free (msg_escaped);
1384 g_free (details_escaped);
1385 for (i = 0; i < num_frames; ++i)
1386 g_free (stack_trace_escaped [i]);
1387 g_free (stack_trace_escaped);
1388 g_free (row_js);
1390 str.utf8characters = script;
1391 str.utf8length = strlen (script);
1393 res = NPN_Evaluate (instance, object, &str, &result);
1394 if (res)
1395 NPN_ReleaseVariantValue (&result);
1396 NPN_ReleaseObject (object);
1397 g_free (script);
1400 void *
1401 PluginInstance::Evaluate (const char *code)
1403 NPObject *object = GetHost ();
1404 NPString string;
1405 NPVariant npresult;
1407 if (object == NULL)
1408 return NULL;
1411 string.utf8characters = code;
1412 string.utf8length = strlen (code);
1414 bool ret = NPN_Evaluate (instance, object, &string, &npresult);
1416 Value *res = NULL;
1417 bool keep_ref = false;
1418 if (ret) {
1419 if (!NPVARIANT_IS_VOID (npresult) && !NPVARIANT_IS_NULL (npresult)) {
1420 variant_to_value (&npresult, &res);
1421 if (npresult.type == NPVariantType_Object)
1422 keep_ref = true;
1426 if (!keep_ref)
1427 NPN_ReleaseVariantValue (&npresult);
1429 return (void*)res;
1432 void
1433 PluginInstance::CrossDomainApplicationCheck (const char *source)
1435 char* page_url = GetPageLocation ();
1436 // note: source might not be an absolute URL at this stage - but that only indicates that it's relative to the page url
1437 cross_domain_app = !same_site_of_origin (page_url, source);
1438 if (!cross_domain_app) {
1439 // we need also to consider a web page having cross-domain XAP that redirects to a XAP on the SOO
1440 // this will still be considered a cross-domain
1441 cross_domain_app = !same_site_of_origin (page_url, source_original);
1443 g_free (page_url);
1445 // if the application did not specify 'enablehtmlaccess' then we use its default value
1446 // which is TRUE for same-site applications and FALSE for cross-domain applications
1447 if (default_enable_html_access)
1448 enable_html_access = !cross_domain_app;
1451 static bool
1452 is_xap (const char *fname)
1454 // Check for the ZIP magic header
1456 int fd;
1457 int nread;
1458 char buf[4];
1460 if ((fd = open (fname, O_RDONLY)) == -1)
1461 return false;
1463 nread = read (fd, buf, 4);
1464 if (nread != 4) {
1465 close (fd);
1466 return false;
1469 if (buf [0] != 0x50 || buf [1] != 0x4B || buf [2] != 0x03 || buf [3] != 0x04) {
1470 close (fd);
1471 return false;
1474 close (fd);
1475 return true;
1478 void
1479 PluginInstance::StreamAsFile (NPStream *stream, const char *fname)
1481 nps (printf ("PluginInstance::StreamAsFile (%p, %s)\n", stream, fname));
1483 Deployment::SetCurrent (deployment);
1484 #if DEBUG
1485 AddSource (stream->url, fname);
1486 #endif
1487 if (IS_NOTIFY_SPLASHSOURCE (stream->notifyData)) {
1488 xaml_loader = PluginXamlLoader::FromFilename (stream->url, fname, this, surface);
1489 loading_splash = true;
1490 LoadXAML ();
1491 FlushSplash ();
1493 if (IS_NOTIFY_SOURCE (stream->notifyData)) {
1494 delete xaml_loader;
1495 xaml_loader = NULL;
1497 CrossDomainApplicationCheck (stream->url);
1499 Uri *uri = new Uri ();
1502 if (uri->Parse (stream->url, false) && is_xap (fname)) {
1503 LoadXAP (stream->url, fname);
1504 } else {
1505 xaml_loader = PluginXamlLoader::FromFilename (stream->url, fname, this, surface);
1506 LoadXAML ();
1509 GetSurface ()->EmitSourceDownloadProgressChanged (new DownloadProgressEventArgs (1.0));
1510 GetSurface ()->EmitSourceDownloadComplete ();
1512 delete uri;
1513 } else if (IS_NOTIFY_DOWNLOADER (stream->notifyData)){
1514 Downloader *dl = (Downloader *) ((StreamNotify *)stream->notifyData)->pdata;
1516 dl->SetFilename (fname);
1517 } else if (IS_NOTIFY_REQUEST (stream->notifyData)) {
1520 /// Commented out for now, I don't think we should need this code at all anymore since we never request assemblies
1521 /// to be downloaded anymore.
1523 bool reload = true;
1525 if (!vm_missing_file)
1526 reload = false;
1528 if (reload && xaml_loader->GetMapping (vm_missing_file) != NULL)
1529 reload = false;
1531 if (reload && xaml_loader->GetMapping (stream->url) != NULL)
1532 reload = false;
1534 if (vm_missing_file)
1535 xaml_loader->RemoveMissing (vm_missing_file);
1537 char *missing = vm_missing_file;
1538 vm_missing_file = NULL;
1540 if (reload) {
1541 // There may be more missing files.
1542 vm_missing_file = g_strdup (xaml_loader->GetMissing ());
1544 xaml_loader->InsertMapping (missing, fname);
1545 xaml_loader->InsertMapping (stream->url, fname);
1547 // retry to load
1548 LoadXAML ();
1551 g_free (missing);
1556 gint32
1557 PluginInstance::WriteReady (NPStream *stream)
1559 nps (printf ("PluginInstance::WriteReady (%p)\n", stream));
1561 Deployment::SetCurrent (deployment);
1563 StreamNotify *notify = STREAM_NOTIFY (stream->notifyData);
1565 if (notify && notify->pdata) {
1566 if (IS_NOTIFY_DOWNLOADER (notify)) {
1567 Downloader *dl = (Downloader *) notify->pdata;
1569 dl->NotifySize (stream->end);
1571 return MAX_STREAM_SIZE;
1573 if (IS_NOTIFY_SOURCE (notify)) {
1574 source_size = stream->end;
1576 return MAX_STREAM_SIZE;
1580 NPN_DestroyStream (instance, stream, NPRES_DONE);
1582 return -1;
1585 gint32
1586 PluginInstance::Write (NPStream *stream, gint32 offset, gint32 len, void *buffer)
1588 nps (printf ("PluginInstance::Write (%p, %i, %i, %p)\n", stream, offset, len, buffer));
1590 Deployment::SetCurrent (deployment);
1592 StreamNotify *notify = STREAM_NOTIFY (stream->notifyData);
1594 if (notify && notify->pdata) {
1595 if (IS_NOTIFY_DOWNLOADER (notify)) {
1596 Downloader *dl = (Downloader *) notify->pdata;
1598 dl->Write (buffer, offset, len);
1600 if (IS_NOTIFY_SOURCE (notify)) {
1601 if (source_size > 0) {
1602 float progress = (offset+len)/(float)source_size;
1603 if (GetSurface ()->GetToplevel () != NULL) {
1604 GetSurface ()->EmitSourceDownloadProgressChanged (new DownloadProgressEventArgs (progress));
1610 return len;
1613 class PluginClosure : public EventObject {
1614 public:
1615 PluginClosure (PluginInstance *plugin)
1616 : plugin (plugin)
1620 virtual ~PluginClosure ()
1624 PluginInstance *plugin;
1627 void
1628 PluginInstance::network_error_tickcall (EventObject *data)
1630 PluginClosure *closure = (PluginClosure*)data;
1631 Surface *s = closure->plugin->GetSurface();
1633 s->EmitError (new ErrorEventArgs (RuntimeError,
1634 MoonError (MoonError::EXCEPTION, 2104, "Failed to download silverlight application.")));
1637 void
1638 PluginInstance::splashscreen_error_tickcall (EventObject *data)
1640 PluginClosure *closure = (PluginClosure*)data;
1641 Surface *s = closure->plugin->GetSurface();
1643 s->EmitError (new ErrorEventArgs (RuntimeError,
1644 MoonError (MoonError::EXCEPTION, 2108, "Failed to download the splash screen")));
1645 closure->plugin->is_splash = false;
1647 // we need this check beccause the plugin might have been
1648 // dtor'ed (and the surface zombified) in the amove EmitError.
1649 if (!s->IsZombie())
1650 closure->plugin->UpdateSource ();
1652 closure->unref();
1655 void
1656 PluginInstance::UrlNotify (const char *url, NPReason reason, void *notifyData)
1658 nps (printf ("PluginInstance::UrlNotify (%s, %i, %p)\n", url, reason, notifyData));
1660 StreamNotify *notify = STREAM_NOTIFY (notifyData);
1662 Deployment::SetCurrent (deployment);
1664 if (reason == NPRES_DONE) {
1665 d(printf ("URL %s downloaded successfully.\n", url));
1666 } else {
1667 d(printf ("Download of URL %s failed: %i (%s)\n", url, reason,
1668 reason == NPRES_USER_BREAK ? "user break" :
1669 (reason == NPRES_NETWORK_ERR ? "network error" : "other error")));
1670 if (IS_NOTIFY_SOURCE (notify))
1671 GetSurface()->GetTimeManager()->AddTickCall (network_error_tickcall,
1672 new PluginClosure (this));
1675 if (notify && notify->pdata && IS_NOTIFY_DOWNLOADER (notify)) {
1676 Downloader *dl = (Downloader *) notify->pdata;
1678 if (reason != NPRES_DONE) {
1680 switch (reason) {
1681 case NPRES_USER_BREAK:
1682 dl->NotifyFailed ("user break");
1683 break;
1684 case NPRES_NETWORK_ERR:
1685 dl->NotifyFailed ("network error");
1686 break;
1687 default:
1688 dl->NotifyFailed ("unknown error");
1689 break;
1691 } else {
1692 dl->NotifyFinished (url);
1696 if (notify && notify->pdata && IS_NOTIFY_SPLASHSOURCE (notify)) {
1697 if (reason == NPRES_NETWORK_ERR)
1698 GetSurface()->GetTimeManager()->AddTickCall (splashscreen_error_tickcall,
1699 new PluginClosure (this));
1700 else
1701 UpdateSource ();
1704 if (notify)
1705 delete notify;
1708 void
1709 PluginInstance::LoadSplash ()
1711 if (splashscreensource != NULL) {
1712 char *pos = strchr (splashscreensource, '#');
1713 if (pos) {
1714 char *original = splashscreensource;
1715 splashscreensource = g_strdup (pos + 1);
1716 g_free (original);
1717 loading_splash = true;
1718 UpdateSourceByReference (splashscreensource);
1719 FlushSplash ();
1720 UpdateSource ();
1721 } else {
1722 StreamNotify *notify = new StreamNotify (StreamNotify::SPLASHSOURCE, splashscreensource);
1724 // FIXME: check for errors
1725 NPN_GetURLNotify (instance, splashscreensource, NULL, notify);
1727 } else {
1728 xaml_loader = PluginXamlLoader::FromStr (NULL, PLUGIN_SPINNER, this, surface);
1729 loading_splash = true;
1730 LoadXAML ();
1731 FlushSplash ();
1732 UpdateSource ();
1736 void
1737 PluginInstance::FlushSplash ()
1739 // FIXME we may want to flush all events here but since this is written to the
1740 // tests I'm not sure.
1742 UIElement *toplevel = GetSurface ()->GetToplevel ();
1743 if (toplevel != NULL) {
1744 List *list = toplevel->WalkTreeForLoaded (NULL);
1745 toplevel->EmitSubtreeLoad (list);
1746 delete list;
1748 loading_splash = false;
1751 void
1752 PluginInstance::Print (NPPrint *platformPrint)
1754 // nothing to do.
1757 int16_t
1758 PluginInstance::EventHandle (void *event)
1760 if (!surface) {
1761 g_warning ("EventHandle called before SetWindow, discarding event.");
1762 return 0;
1765 if (!windowless) {
1766 g_warning ("EventHandle called for windowed plugin, discarding event.");
1767 return 0;
1771 return ((MoonWindowless*)moon_window)->HandleEvent ((XEvent*)event);
1774 void
1775 PluginInstance::AddWrappedObject (EventObject *obj, NPObject *wrapper)
1777 g_hash_table_insert (wrapped_objects, obj, wrapper);
1780 void
1781 PluginInstance::RemoveWrappedObject (EventObject *obj)
1783 g_hash_table_remove (wrapped_objects, obj);
1786 NPObject*
1787 PluginInstance::LookupWrappedObject (EventObject *obj)
1789 return (NPObject*)g_hash_table_lookup (wrapped_objects, obj);
1792 void
1793 PluginInstance::AddCleanupPointer (gpointer p)
1795 cleanup_pointers = g_slist_prepend (cleanup_pointers, p);
1798 void
1799 PluginInstance::RemoveCleanupPointer (gpointer p)
1801 cleanup_pointers = g_slist_remove (cleanup_pointers, p);
1804 /*** Getters and Setters ******************************************************/
1806 void
1807 PluginInstance::SetSource (const char *value)
1809 if (source) {
1810 g_free (source);
1811 source = NULL;
1814 source = g_strdup (value);
1815 // we may not have an original set at this point (e.g. when source is set via scripting)
1816 if (!source_original)
1817 source_original = g_strdup (value);
1819 UpdateSource ();
1822 char *
1823 PluginInstance::GetBackground ()
1825 return background;
1828 bool
1829 PluginInstance::SetBackground (const char *value)
1831 g_free (background);
1832 background = g_strdup (value);
1834 if (surface) {
1835 Color *c = color_from_str (background);
1837 if (c == NULL)
1838 return false;
1840 surface->SetBackgroundColor (c);
1841 delete c;
1844 return true;
1847 bool
1848 PluginInstance::GetEnableFramerateCounter ()
1850 return enable_framerate_counter;
1853 void
1854 PluginInstance::SetEnableFramerateCounter (bool value)
1856 enable_framerate_counter = value;
1859 bool
1860 PluginInstance::GetEnableRedrawRegions ()
1862 return moonlight_flags & RUNTIME_INIT_SHOW_EXPOSE;
1865 void
1866 PluginInstance::SetEnableRedrawRegions (bool value)
1868 if (value)
1869 moonlight_flags |= RUNTIME_INIT_SHOW_EXPOSE;
1870 else
1871 moonlight_flags &= ~RUNTIME_INIT_SHOW_EXPOSE;
1874 bool
1875 PluginInstance::GetEnableHtmlAccess ()
1877 return enable_html_access;
1880 bool
1881 PluginInstance::GetAllowHtmlPopupWindow ()
1883 return allow_html_popup_window;
1886 bool
1887 PluginInstance::GetWindowless ()
1889 return windowless;
1893 PluginInstance::GetMaxFrameRate ()
1895 return maxFrameRate;
1898 Deployment*
1899 PluginInstance::GetDeployment ()
1901 return deployment;
1904 void
1905 PluginInstance::SetMaxFrameRate (int value)
1907 maxFrameRate = value;
1909 surface->GetTimeManager()->SetMaximumRefreshRate (MAX (value, 64));
1912 gint32
1913 PluginInstance::GetActualHeight ()
1915 return surface && surface->GetWindow () ? surface->GetWindow()->GetHeight() : 0;
1918 gint32
1919 PluginInstance::GetActualWidth ()
1921 return surface && surface->GetWindow () ? surface->GetWindow()->GetWidth() : 0;
1924 MoonlightScriptControlObject *
1925 PluginInstance::GetRootObject ()
1927 if (rootobject == NULL)
1928 rootobject = NPN_CreateObject (instance, MoonlightScriptControlClass);
1930 NPN_RetainObject (rootobject);
1931 return (MoonlightScriptControlObject*)rootobject;
1935 PluginInstance::GetInstance ()
1937 return instance;
1940 NPWindow*
1941 PluginInstance::GetWindow ()
1943 return window;
1946 // [Obselete (this is obsolete in SL b2.)]
1947 guint32
1948 PluginInstance::TimeoutAdd (gint32 interval, GSourceFunc callback, gpointer data)
1950 guint32 id;
1952 #if GLIB_CHECK_VERSION(2,14,0)
1953 if (glib_check_version (2,14,0) && interval > 1000 && ((interval % 1000) == 0))
1954 id = g_timeout_add_seconds (interval / 1000, callback, data);
1955 else
1956 #endif
1957 id = g_timeout_add (interval, callback, data);
1959 timers = g_slist_append (timers, GINT_TO_POINTER ((int)id));
1961 return id;
1964 // [Obselete (this is obsolete in SL b2.)]
1965 void
1966 PluginInstance::TimeoutStop (guint32 source_id)
1968 g_source_remove (source_id);
1969 timers = g_slist_remove (timers, GINT_TO_POINTER (source_id));
1972 char*
1973 plugin_instance_get_id (PluginInstance *instance)
1975 return instance->GetId ();
1978 void
1979 plugin_instance_get_browser_runtime_settings (bool *debug, bool *html_access,
1980 bool *httpnet_access, bool *script_access)
1982 *debug = *html_access = *httpnet_access = *script_access = false;
1986 XamlLoader
1989 bool
1990 PluginXamlLoader::LoadVM ()
1992 #if PLUGIN_SL_2_0
1993 return InitializeLoader ();
1994 #endif
1995 return false;
1998 bool
1999 PluginXamlLoader::InitializeLoader ()
2001 if (initialized)
2002 return true;
2004 #if PLUGIN_SL_2_0
2005 if (managed_loader)
2006 return true;
2008 if (GetFilename ()) {
2009 managed_loader = plugin->ManagedCreateXamlLoaderForFile (this, GetResourceBase(), GetFilename ());
2010 } else if (GetString ()) {
2011 managed_loader = plugin->ManagedCreateXamlLoaderForString (this, GetResourceBase(), GetString ());
2012 } else {
2013 return false;
2016 initialized = managed_loader != NULL;
2017 #else
2018 initialized = true;
2019 #endif
2020 return initialized;
2024 // On error it sets the @error ref to 1
2025 // Returns the filename that we are missing
2027 const char *
2028 PluginXamlLoader::TryLoad (int *error)
2030 DependencyObject *element;
2031 Type::Kind element_type;
2033 *error = 0;
2035 //d(printf ("PluginXamlLoader::TryLoad, filename: %s, str: %s\n", GetFilename (), GetString ()));
2037 GetSurface ()->Attach (NULL);
2039 if (GetFilename ()) {
2040 element = CreateDependencyObjectFromFile (GetFilename (), true, &element_type);
2041 } else if (GetString ()) {
2042 element = CreateDependencyObjectFromString (GetString (), true, &element_type);
2043 } else {
2044 *error = 1;
2045 return NULL;
2048 if (!element) {
2049 if (error_args && error_args->GetErrorCode() != -1) {
2050 d(printf ("PluginXamlLoader::TryLoad: Could not load xaml %s: %s (error: %s attr=%s)\n",
2051 GetFilename () ? "file" : "string", GetFilename () ? GetFilename () : GetString (),
2052 error_args->xml_element, error_args->xml_attribute));
2053 error_args->ref ();
2054 GetSurface ()->EmitError (error_args);
2055 return NULL;
2056 } else {
2058 d(printf ("PluginXamlLoader::TryLoad: Could not load xaml %s: %s (missing_assembly: %s)\n",
2059 GetFilename () ? "file" : "string", GetFilename () ? GetFilename () : GetString (),
2060 GetMissing ()));
2062 xaml_is_managed = true;
2063 return GetMissing ();
2065 return NULL;
2069 Type *t = Type::Find(element_type);
2070 if (!t) {
2071 d(printf ("PluginXamlLoader::TryLoad: Return value does not subclass Canvas, it is an unregistered type\n"));
2072 element->unref ();
2073 GetSurface ()->EmitError (new ErrorEventArgs (RuntimeError,
2074 MoonError (MoonError::EXCEPTION, 2101, "Failed to initialize the application's root visual")));
2075 return NULL;
2078 if (!t->IsSubclassOf(Type::PANEL)) {
2079 d(printf ("PluginXamlLoader::TryLoad: Return value does not subclass of Panel, it is a %s\n",
2080 element->GetTypeName ()));
2081 element->unref ();
2082 GetSurface ()->EmitError (new ErrorEventArgs (RuntimeError,
2083 MoonError (MoonError::EXCEPTION, 2101, "Failed to initialize the application's root visual")));
2084 return NULL;
2087 //d(printf ("PluginXamlLoader::TryLoad () succeeded.\n"));
2089 GetSurface ()->Attach ((Panel*) element);
2091 // xaml_create_from_* passed us a ref which we don't need to
2092 // keep.
2093 element->unref ();
2095 return NULL;
2098 bool
2099 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, int flags)
2101 if (XamlLoader::SetProperty (parser, top_level, xmlns, target, target_data, target_parent, prop_xmlns, name, value, value_data))
2102 return true;
2104 if (value->GetKind () != Type::STRING)
2105 return false;
2107 if (!xaml_is_valid_event_name (target->GetKind(), name, false))
2108 return false;
2110 const char* function_name = value->AsString ();
2112 if (!strncmp (function_name, "javascript:", strlen ("javascript:")))
2113 return false;
2115 event_object_add_xaml_listener ((EventObject *) target->AsDependencyObject (), plugin, name, function_name);
2117 return true;
2120 PluginXamlLoader::PluginXamlLoader (const char *resourceBase, const char *filename, const char *str, PluginInstance *plugin, Surface *surface)
2121 : XamlLoader (resourceBase, filename, str, surface)
2123 this->plugin = plugin;
2124 xaml_is_managed = false;
2125 initialized = false;
2126 error_args = NULL;
2128 #if PLUGIN_SL_2_0
2129 xap = NULL;
2131 managed_loader = NULL;
2132 #endif
2135 PluginXamlLoader::~PluginXamlLoader ()
2137 #if PLUGIN_SL_2_0
2138 if (xap)
2139 delete xap;
2141 if (managed_loader)
2142 plugin->ManagedLoaderDestroy (managed_loader);
2143 #endif
2146 PluginXamlLoader *
2147 plugin_xaml_loader_from_str (const char *resourceBase, const char *str, PluginInstance *plugin, Surface *surface)
2149 return PluginXamlLoader::FromStr (resourceBase, str, plugin, surface);
2153 // Our Mono embedding bits are here. By storing the mono_domain in
2154 // the PluginInstance instead of in a global variable, we don't need
2155 // the code in moonlight.cs for managing app domains.
2156 #if PLUGIN_SL_2_0
2157 MonoMethod *
2158 PluginInstance::MonoGetMethodFromName (MonoClass *klass, const char *name, int narg)
2160 MonoMethod *method;
2161 method = mono_class_get_method_from_name (klass, name, narg);
2163 if (!method)
2164 printf ("Warning could not find method %s\n", name);
2166 return method;
2169 MonoProperty *
2170 PluginInstance::MonoGetPropertyFromName (MonoClass *klass, const char *name)
2172 MonoProperty *property;
2173 property = mono_class_get_property_from_name (klass, name);
2175 if (!property)
2176 printf ("Warning could not find property %s\n", name);
2178 return property;
2181 bool PluginInstance::mono_is_loaded = false;
2183 bool
2184 PluginInstance::MonoIsLoaded ()
2186 return mono_is_loaded;
2189 extern "C" {
2190 extern gboolean mono_jit_set_trace_options (const char *options);
2193 bool
2194 PluginInstance::DeploymentInit ()
2196 return mono_is_loaded = true; // We load mono in runtime_init.
2200 bool
2201 PluginInstance::CreatePluginDeployment ()
2203 deployment = new Deployment ();
2204 Deployment::SetCurrent (deployment);
2206 return true;
2209 bool
2210 PluginInstance::InitializePluginAppDomain ()
2212 bool result = false;
2214 system_windows_assembly = mono_assembly_load_with_partial_name ("System.Windows, Version=2.0.5.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e", NULL);
2216 if (system_windows_assembly) {
2217 MonoImage *image;
2218 MonoClass *app_launcher;
2220 result = true;
2222 image = mono_assembly_get_image (system_windows_assembly);
2224 d (printf ("Assembly: %s\n", mono_image_get_filename (image)));
2226 app_launcher = mono_class_from_name (image, "Mono", "ApplicationLauncher");
2227 if (!app_launcher) {
2228 g_warning ("could not find ApplicationLauncher type");
2229 return false;
2232 moon_exception = mono_class_from_name (image, "Mono", "MoonException");
2233 if (!moon_exception) {
2234 g_warning ("could not find MoonException type");
2235 return false;
2238 moon_load_xaml = MonoGetMethodFromName (app_launcher, "CreateXamlLoader", -1);
2239 moon_initialize_deployment_xap = MonoGetMethodFromName (app_launcher, "InitializeDeployment", 4);
2240 moon_initialize_deployment_xaml = MonoGetMethodFromName (app_launcher, "InitializeDeployment", 2);
2241 moon_destroy_application = MonoGetMethodFromName (app_launcher, "DestroyApplication", -1);
2243 if (moon_load_xaml == NULL || moon_initialize_deployment_xap == NULL || moon_initialize_deployment_xaml == NULL || moon_destroy_application == NULL) {
2244 g_warning ("lookup for ApplicationLauncher methods failed");
2245 result = false;
2248 moon_exception_message = MonoGetPropertyFromName (mono_get_exception_class(), "Message");
2249 moon_exception_error_code = MonoGetPropertyFromName (moon_exception, "ErrorCode");
2251 if (moon_exception_message == NULL || moon_exception_error_code == NULL) {
2252 g_warning ("lookup for MoonException properties failed");
2253 result = false;
2255 } else {
2256 printf ("Plugin AppDomain Creation: could not find System.Windows.dll.\n");
2259 printf ("Plugin AppDomain Creation: %s\n", result ? "OK" : "Failed");
2261 return result;
2264 ErrorEventArgs *
2265 PluginInstance::ManagedExceptionToErrorEventArgs (MonoObject *exc)
2267 int errorCode = -1;
2268 char* message = NULL;
2270 if (mono_object_isinst (exc, mono_get_exception_class())) {
2271 MonoObject *ret = mono_property_get_value (moon_exception_message, exc, NULL, NULL);
2273 message = mono_string_to_utf8 ((MonoString*)ret);
2275 if (mono_object_isinst (exc, moon_exception)) {
2276 MonoObject *ret = mono_property_get_value (moon_exception_error_code, exc, NULL, NULL);
2278 errorCode = *(int*) mono_object_unbox (ret);
2281 // FIXME: we need to figure out what type of exception it is
2282 // and map it to the right MoonError::ExceptionType enum
2283 return new ErrorEventArgs (RuntimeError, MoonError (MoonError::EXCEPTION, errorCode, message));
2286 gpointer
2287 PluginInstance::ManagedCreateXamlLoader (XamlLoader* native_loader, const char *resourceBase, const char *file, const char *str)
2289 MonoObject *loader;
2290 MonoObject *exc = NULL;
2291 if (moon_load_xaml == NULL)
2292 return NULL;
2294 PluginInstance *this_obj = this;
2295 void *params [6];
2297 Deployment::SetCurrent (deployment);
2299 params [0] = &native_loader;
2300 params [1] = &this_obj;
2301 params [2] = &surface;
2302 params [3] = resourceBase ? mono_string_new (mono_domain_get (), resourceBase) : NULL;
2303 params [4] = file ? mono_string_new (mono_domain_get (), file) : NULL;
2304 params [5] = str ? mono_string_new (mono_domain_get (), str) : NULL;
2305 loader = mono_runtime_invoke (moon_load_xaml, NULL, params, &exc);
2307 if (exc) {
2308 deployment->GetSurface()->EmitError (ManagedExceptionToErrorEventArgs (exc));
2309 return NULL;
2312 return GUINT_TO_POINTER (mono_gchandle_new (loader, false));
2315 gpointer
2316 PluginInstance::ManagedCreateXamlLoaderForFile (XamlLoader *native_loader, const char *resourceBase, const char *file)
2318 return ManagedCreateXamlLoader (native_loader, resourceBase, file, NULL);
2321 gpointer
2322 PluginInstance::ManagedCreateXamlLoaderForString (XamlLoader* native_loader, const char *resourceBase, const char *str)
2324 return ManagedCreateXamlLoader (native_loader, resourceBase, NULL, str);
2327 void
2328 PluginInstance::ManagedLoaderDestroy (gpointer loader_object)
2330 guint32 loader = GPOINTER_TO_UINT (loader_object);
2331 if (loader)
2332 mono_gchandle_free (loader);
2335 bool
2336 PluginInstance::ManagedInitializeDeployment (const char *file)
2338 if (moon_initialize_deployment_xap == NULL && moon_initialize_deployment_xaml)
2339 return NULL;
2341 PluginInstance *this_obj = this;
2342 void *params [4];
2343 MonoObject *ret;
2344 MonoObject *exc = NULL;
2346 Deployment::SetCurrent (deployment);
2348 if (file != NULL) {
2349 params [0] = &this_obj;
2350 params [1] = mono_string_new (mono_domain_get (), file);
2351 params [2] = culture ? mono_string_new (mono_domain_get (), culture) : NULL;
2352 params [3] = uiCulture ? mono_string_new (mono_domain_get (), uiCulture) : NULL;
2353 ret = mono_runtime_invoke (moon_initialize_deployment_xap, NULL, params, &exc);
2354 } else {
2355 params [0] = culture ? mono_string_new (mono_domain_get (), culture) : NULL;
2356 params [1] = uiCulture ? mono_string_new (mono_domain_get (), uiCulture) : NULL;
2357 ret = mono_runtime_invoke (moon_initialize_deployment_xaml, NULL, params, &exc);
2360 if (exc) {
2361 deployment->GetSurface()->EmitError (ManagedExceptionToErrorEventArgs (exc));
2362 return false;
2365 return (bool) (*(MonoBoolean *) mono_object_unbox(ret));
2368 void
2369 PluginInstance::ManagedDestroyApplication ()
2371 if (moon_destroy_application == NULL)
2372 return;
2374 PluginInstance *this_obj = this;
2375 MonoObject *exc = NULL;
2376 void *params [1];
2377 params [0] = &this_obj;
2379 Deployment::SetCurrent (deployment);
2381 mono_runtime_invoke (moon_destroy_application, NULL, params, &exc);
2383 if (exc)
2384 deployment->GetSurface()->EmitError (ManagedExceptionToErrorEventArgs (exc));
2387 #endif