1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
3 * moon-plugin.cpp: MoonLight browser plugin.
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.
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"
31 #include "windowless.h"
32 #include "window-gtk.h"
34 #include "deployment.h"
36 #include "timemanager.h"
38 #define Visual _XxVisual
39 #define Region _XxRegion
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>",
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/)");
100 gtk_about_dialog_set_website (about
, "http://moonlight-project.com/");
102 gtk_about_dialog_set_website (about
, "http://moonlight-project.com/Beta");
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
,
112 G_CALLBACK (gtk_widget_destroy
),
115 gtk_dialog_run (GTK_DIALOG (about
));
119 plugin_media_pack (PluginInstance
*plugin
)
121 CodecDownloader::ShowUI (plugin
->GetSurface ());
125 plugin_properties (PluginInstance
*plugin
)
127 plugin
->Properties ();
131 plugin_show_menu (PluginInstance
*plugin
)
134 GtkWidget
*menu_item
;
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
);
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
);
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
);
166 gtk_widget_show_all (menu
);
167 gtk_menu_popup (GTK_MENU (menu
), NULL
, NULL
, NULL
, NULL
, 0, gtk_get_current_event_time());
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
);
184 NPN_strdup (const char *tocopy
)
186 int len
= strlen(tocopy
);
187 char *ptr
= (char *)NPN_MemAlloc (len
+1);
189 strcpy (ptr
, tocopy
);
190 // WebKit should calloc so we dont have to do this
197 /*** PluginInstance:: *********************************************************/
199 GSList
*plugin_instances
= NULL
;
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);
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
);
224 expose_regions (GtkToggleButton
*checkbox
, gpointer user_data
)
226 if (gtk_toggle_button_get_active (checkbox
))
227 moonlight_flags
|= RUNTIME_INIT_SHOW_EXPOSE
;
229 moonlight_flags
&= ~RUNTIME_INIT_SHOW_EXPOSE
;
233 clipping_regions (GtkToggleButton
*checkbox
, gpointer user_data
)
235 if (gtk_toggle_button_get_active (checkbox
))
236 moonlight_flags
|= RUNTIME_INIT_SHOW_CLIPPING
;
238 moonlight_flags
&= ~RUNTIME_INIT_SHOW_CLIPPING
;
242 bounding_boxes (GtkToggleButton
*checkbox
, gpointer user_data
)
244 if (gtk_toggle_button_get_active (checkbox
))
245 moonlight_flags
|= RUNTIME_INIT_SHOW_BOUNDING_BOXES
;
247 moonlight_flags
&= ~RUNTIME_INIT_SHOW_BOUNDING_BOXES
;
251 textboxes (GtkToggleButton
*checkbox
, gpointer user_data
)
253 if (gtk_toggle_button_get_active (checkbox
))
254 moonlight_flags
|= RUNTIME_INIT_SHOW_TEXTBOXES
;
256 moonlight_flags
&= ~RUNTIME_INIT_SHOW_TEXTBOXES
;
260 show_fps (GtkToggleButton
*checkbox
, gpointer user_data
)
262 if (gtk_toggle_button_get_active (checkbox
))
263 moonlight_flags
|= RUNTIME_INIT_SHOW_FPS
;
265 moonlight_flags
&= ~RUNTIME_INIT_SHOW_FPS
;
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
);
277 PluginInstance::Properties ()
279 GtkWidget
*dialog
, *table
, *checkbox
;
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
++);
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
++);
320 table_add (table
, "(Unknown)", 1, row
++);
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
++);
329 table_add (table
, Media::IsMSCodecsInstalled () ? "ms-codecs" : "ffmpeg", 1, row
++);
331 table_add (table
, Media::IsMSCodecsInstalled () ? "ms-codecs" : "none", 1, 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);
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
;
383 properties_fps_label
= NULL
;
384 properties_cache_label
= NULL
;
393 source_location
= NULL
;
394 source_location_original
= NULL
;
397 source_original
= NULL
;
402 onSourceDownloadProgressChanged
= NULL
;
403 onSourceDownloadComplete
= NULL
;
404 splashscreensource
= NULL
;
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;
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.
425 enable_framerate_counter
= false;
427 vm_missing_file
= NULL
;
430 system_windows_assembly
= NULL
;
433 moon_initialize_deployment_xap
=
434 moon_initialize_deployment_xaml
=
435 moon_destroy_application
= 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;
454 PluginInstance::~PluginInstance ()
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
);
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
;
477 g_slist_free (cleanup_pointers
);
480 NPN_ReleaseObject ((NPObject
*)rootobject
);
484 g_free (onSourceDownloadProgressChanged
);
485 g_free (onSourceDownloadComplete
);
486 g_free (splashscreensource
);
490 g_free (vm_missing_file
);
494 // Destroy the XAP application
495 DestroyApplication ();
499 g_free (source_original
);
500 g_free (source_location
);
501 g_free (source_location_original
);
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 ();
515 surface
->unref_delayed();
516 //gdk_display_sync (display);
517 //gdk_error_trap_pop ();
524 deployment
->Dispose ();
525 deployment
->unref_delayed();
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
);
544 PluginInstance::GetSources ()
552 same_site_of_origin (const char *url1
, const char *url2
)
557 if (url1
== NULL
|| url2
== NULL
)
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
))
570 result
= Uri::SameSiteOfOrigin (uri1
, uri2
);
579 parse_bool_arg (const char *arg
)
582 return xaml_bool_from_str (arg
, &b
) && b
;
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);
593 else if (!g_ascii_strcasecmp (argn
[i
], "initParams")) {
594 initParams
= g_strdup (argv
[i
]);
596 else if (!g_ascii_strcasecmp (argn
[i
], "onLoad")) {
599 else if (!g_ascii_strcasecmp (argn
[i
], "onError")) {
602 else if (!g_ascii_strcasecmp (argn
[i
], "onResize")) {
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
]);
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));
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;
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
;
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");
697 if (supportsWindowless
) {
698 NPN_SetValue (instance
, NPPVpluginWindowBool
, (void *) FALSE
);
699 NPN_SetValue (instance
, NPPVpluginTransparentBool
, (void *) TRUE
);
700 d(printf ("windowless mode\n"));
702 d(printf ("browser doesn't support windowless mode.\n"));
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")) {
713 TryLoadBridge ("opera");
715 else if (strstr (useragent
, "AppleWebKit")) {
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");
734 g_warning ("probing for browser type failed, user agent = `%s'",
738 if (!CreatePluginDeployment ()) {
739 g_warning ("Couldn't initialize Mono or create the plugin Deployment");
743 typedef BrowserBridge
* (*create_bridge_func
)();
746 get_plugin_dir (void)
748 static char *plugin_dir
= NULL
;
752 if (dladdr((void *) &plugin_show_menu
, &dlinfo
) == 0) {
753 fprintf (stderr
, "Unable to find the location of libmoonplugin.so: %s\n", dlerror ());
756 plugin_dir
= g_path_get_dirname (dlinfo
.dli_fname
);
762 PluginInstance::TryLoadBridge (const char *prefix
)
764 char *bridge_name
= g_strdup_printf ("libmoonplugin-%sbridge.so", prefix
);
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());
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());
785 bridge
= bridge_ctor ();
789 PluginInstance::Finalize ()
794 PluginInstance::GetValue (NPPVariable variable
, void *result
)
796 NPError err
= NPERR_NO_ERROR
;
799 case NPPVpluginNeedsXEmbed
:
800 *((NPBool
*)result
) = !windowless
;
802 case NPPVpluginScriptableNPObject
:
803 *((NPObject
**) result
) = GetRootObject ();
806 err
= NPERR_INVALID_PARAM
;
814 PluginInstance::SetValue (NPNVariable variable
, void *value
)
816 return NPERR_NO_ERROR
;
820 PluginInstance::SetWindow (NPWindow
*window
)
822 Deployment::SetCurrent (deployment
);
825 // XXX opera Window lifetime hack needs this
826 this->window
= window
;
829 return NPERR_GENERIC_ERROR
;
831 moon_window
->Resize (window
->width
, window
->height
);
832 return NPERR_NO_ERROR
;
835 this->window
= window
;
838 return NPERR_NO_ERROR
;
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"));
852 PluginInstance::ReportFPS (Surface
*surface
, int nframes
, float nsecs
, void *user_data
)
854 PluginInstance
*plugin
= (PluginInstance
*) user_data
;
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
);
869 PluginInstance::ReportCache (Surface
*surface
, long bytes
, void *user_data
)
871 PluginInstance
*plugin
= (PluginInstance
*) user_data
;
875 msg
= g_strdup_printf ("Cache size is ~%d KB", (int) (bytes
/ 1024));
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
);
888 register_event (NPP instance
, const char *event_name
, char *script_name
, NPObject
*npobj
)
893 char *retval
= NPN_strdup (script_name
);
896 STRINGZ_TO_NPVARIANT (retval
, npvalue
);
897 NPIdentifier identifier
= NPN_GetStringIdentifier (event_name
);
898 NPN_SetProperty (instance
, npobj
, identifier
, &npvalue
);
899 NPN_MemFree (retval
);
903 PluginInstance::IsLoaded ()
905 if (!GetSurface () || is_splash
)
908 return GetSurface()->IsLoaded();
912 PluginInstance::CreateWindow ()
915 moon_window
= new MoonWindowless (window
->width
, window
->height
, this);
916 moon_window
->SetTransparent (true);
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.
936 surface
->SetFPSReportFunc (ReportFPS
, this);
937 surface
->SetCacheReportFunc (ReportCache
, this);
938 surface
->SetDownloaderContext (this);
940 surface
->GetTimeManager()->SetMaximumRefreshRate (maxFrameRate
);
943 Color
*c
= color_from_str (background
);
946 d(printf ("error setting background color\n"));
947 c
= new Color (0x00FFFFFF);
950 surface
->SetBackgroundColor (c
);
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
|
965 GDK_KEY_RELEASE_MASK
|
966 GDK_POINTER_MOTION_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
);
984 PluginInstance::UpdateSource ()
987 g_source_remove (source_idle
);
992 surface
->DetachDownloaders ();
994 if (!source
|| strlen (source
) == 0)
997 char *pos
= strchr (source
, '#');
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);
1003 StreamNotify
*notify
= new StreamNotify (StreamNotify::SOURCE
, source
);
1005 // FIXME: check for errors
1006 NPN_GetURLNotify (instance
, source
, NULL
, notify
);
1011 PluginInstance::IdleUpdateSourceByReference (gpointer data
)
1013 PluginInstance
*instance
= (PluginInstance
*)data
;
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 ();
1030 PluginInstance::UpdateSourceByReference (const char *value
)
1032 // basically do the equivalent of document.getElementById('@value').textContent
1035 NPVariant _document
;
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();
1048 // printf ("no host\n");
1052 // get host.ownerDocument
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);
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
);
1078 char *xaml
= g_strndup ((char *) NPVARIANT_TO_STRING (_textContent
).utf8characters
, NPVARIANT_TO_STRING (_textContent
).utf8length
);
1080 // printf ("yay, xaml = %s\n", xaml);
1085 xaml_loader
= PluginXamlLoader::FromStr (NULL
/*FIXME*/, xaml
, this, surface
);
1090 NPN_ReleaseVariantValue (&_document
);
1091 NPN_ReleaseVariantValue (&_element
);
1092 NPN_ReleaseVariantValue (&_textContent
);
1097 PluginInstance::CreateDownloader (PluginInstance
*instance
)
1100 return instance
->surface
->CreateDownloader ();
1102 printf ("PluginInstance::CreateDownloader (%p): Unable to create contextual downloader.\n", instance
);
1103 return new Downloader ();
1108 PluginInstance::SetInitParams (const char *value
)
1110 g_free (initParams
);
1111 initParams
= g_strdup (value
);
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
;
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
);
1140 PluginInstance::SetPageURL ()
1142 if (source_location
!= NULL
)
1145 char* location
= GetPageLocation ();
1146 if (location
&& surface
) {
1147 this->source_location
= location
;
1148 surface
->SetSourceLocation (this->source_location
);
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
)) {
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);
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
);
1188 return NPERR_NO_ERROR
;
1191 if (IS_NOTIFY_REQUEST (stream
->notifyData
)) {
1192 *stype
= NP_ASFILEONLY
;
1193 return NPERR_NO_ERROR
;
1198 return NPERR_NO_ERROR
;
1202 PluginInstance::DestroyStream (NPStream
*stream
, NPError reason
)
1204 nps (printf ("PluginInstance::DestroyStream (%p, %i)\n", stream
, reason
));
1206 PluginDownloader
*pd
= (PluginDownloader
*) stream
->pdata
;
1208 NPStreamRequest
*req
= (NPStreamRequest
*) pd
->getRequest ();
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.
1222 PluginInstance::LoadXAML ()
1226 if (!InitializePluginAppDomain ()) {
1227 g_warning ("Couldn't initialize the plugin AppDomain");
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
);
1246 loading_splash
= false;
1248 register_event (instance
, "onLoad", (char*)"", root
);
1249 //register_event (instance, "onError", "", root);
1250 register_event (instance
, "onResize", (char*)"", root
->content
);
1252 loading_splash
= false;
1255 const char *missing
= xaml_loader
->TryLoad (&error
);
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
);
1279 PluginInstance::LoadXAP (const char *url
, const char *fname
)
1281 if (!InitializePluginAppDomain ()) {
1282 g_warning ("Couldn't initialize the plugin AppDomain");
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;
1298 Deployment::GetCurrent ()->Reinitialize ();
1299 GetDeployment()->SetXapLocation (url
);
1300 ManagedInitializeDeployment (fname
);
1304 PluginInstance::DestroyApplication ()
1306 ManagedDestroyApplication ();
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
1315 string_to_js (char *s
)
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');
1336 g_string_append_c (result
, *p
);
1340 g_string_free (result
, FALSE
);
1346 PluginInstance::ReportException (char *msg
, char *details
, char **stack_trace
, int num_frames
)
1350 char *script
, *row_js
, *msg_escaped
, *details_escaped
;
1351 char **stack_trace_escaped
;
1356 // Get a reference to our element
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
) {
1376 s
= g_strdup_printf ("%s%s%s", row_js
, (i
== 0) ? "" : "\\n ", stack_trace_escaped
[i
]);
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
);
1390 str
.utf8characters
= script
;
1391 str
.utf8length
= strlen (script
);
1393 res
= NPN_Evaluate (instance
, object
, &str
, &result
);
1395 NPN_ReleaseVariantValue (&result
);
1396 NPN_ReleaseObject (object
);
1401 PluginInstance::Evaluate (const char *code
)
1403 NPObject
*object
= GetHost ();
1411 string
.utf8characters
= code
;
1412 string
.utf8length
= strlen (code
);
1414 bool ret
= NPN_Evaluate (instance
, object
, &string
, &npresult
);
1417 bool keep_ref
= false;
1419 if (!NPVARIANT_IS_VOID (npresult
) && !NPVARIANT_IS_NULL (npresult
)) {
1420 variant_to_value (&npresult
, &res
);
1421 if (npresult
.type
== NPVariantType_Object
)
1427 NPN_ReleaseVariantValue (&npresult
);
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
);
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
;
1452 is_xap (const char *fname
)
1454 // Check for the ZIP magic header
1460 if ((fd
= open (fname
, O_RDONLY
)) == -1)
1463 nread
= read (fd
, buf
, 4);
1469 if (buf
[0] != 0x50 || buf
[1] != 0x4B || buf
[2] != 0x03 || buf
[3] != 0x04) {
1479 PluginInstance::StreamAsFile (NPStream
*stream
, const char *fname
)
1481 nps (printf ("PluginInstance::StreamAsFile (%p, %s)\n", stream
, fname
));
1483 Deployment::SetCurrent (deployment
);
1485 AddSource (stream
->url
, fname
);
1487 if (IS_NOTIFY_SPLASHSOURCE (stream
->notifyData
)) {
1488 xaml_loader
= PluginXamlLoader::FromFilename (stream
->url
, fname
, this, surface
);
1489 loading_splash
= true;
1493 if (IS_NOTIFY_SOURCE (stream
->notifyData
)) {
1497 CrossDomainApplicationCheck (stream
->url
);
1499 Uri
*uri
= new Uri ();
1502 if (uri
->Parse (stream
->url
, false) && is_xap (fname
)) {
1503 LoadXAP (stream
->url
, fname
);
1505 xaml_loader
= PluginXamlLoader::FromFilename (stream
->url
, fname
, this, surface
);
1509 GetSurface ()->EmitSourceDownloadProgressChanged (new DownloadProgressEventArgs (1.0));
1510 GetSurface ()->EmitSourceDownloadComplete ();
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.
1525 if (!vm_missing_file)
1528 if (reload && xaml_loader->GetMapping (vm_missing_file) != NULL)
1531 if (reload && xaml_loader->GetMapping (stream->url) != NULL)
1534 if (vm_missing_file)
1535 xaml_loader->RemoveMissing (vm_missing_file);
1537 char *missing = vm_missing_file;
1538 vm_missing_file = NULL;
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);
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
);
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
));
1613 class PluginClosure
: public EventObject
{
1615 PluginClosure (PluginInstance
*plugin
)
1620 virtual ~PluginClosure ()
1624 PluginInstance
*plugin
;
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.")));
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.
1650 closure
->plugin
->UpdateSource ();
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
));
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
) {
1681 case NPRES_USER_BREAK
:
1682 dl
->NotifyFailed ("user break");
1684 case NPRES_NETWORK_ERR
:
1685 dl
->NotifyFailed ("network error");
1688 dl
->NotifyFailed ("unknown error");
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));
1709 PluginInstance::LoadSplash ()
1711 if (splashscreensource
!= NULL
) {
1712 char *pos
= strchr (splashscreensource
, '#');
1714 char *original
= splashscreensource
;
1715 splashscreensource
= g_strdup (pos
+ 1);
1717 loading_splash
= true;
1718 UpdateSourceByReference (splashscreensource
);
1722 StreamNotify
*notify
= new StreamNotify (StreamNotify::SPLASHSOURCE
, splashscreensource
);
1724 // FIXME: check for errors
1725 NPN_GetURLNotify (instance
, splashscreensource
, NULL
, notify
);
1728 xaml_loader
= PluginXamlLoader::FromStr (NULL
, PLUGIN_SPINNER
, this, surface
);
1729 loading_splash
= true;
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
);
1748 loading_splash
= false;
1752 PluginInstance::Print (NPPrint
*platformPrint
)
1758 PluginInstance::EventHandle (void *event
)
1761 g_warning ("EventHandle called before SetWindow, discarding event.");
1766 g_warning ("EventHandle called for windowed plugin, discarding event.");
1771 return ((MoonWindowless
*)moon_window
)->HandleEvent ((XEvent
*)event
);
1775 PluginInstance::AddWrappedObject (EventObject
*obj
, NPObject
*wrapper
)
1777 g_hash_table_insert (wrapped_objects
, obj
, wrapper
);
1781 PluginInstance::RemoveWrappedObject (EventObject
*obj
)
1783 g_hash_table_remove (wrapped_objects
, obj
);
1787 PluginInstance::LookupWrappedObject (EventObject
*obj
)
1789 return (NPObject
*)g_hash_table_lookup (wrapped_objects
, obj
);
1793 PluginInstance::AddCleanupPointer (gpointer p
)
1795 cleanup_pointers
= g_slist_prepend (cleanup_pointers
, p
);
1799 PluginInstance::RemoveCleanupPointer (gpointer p
)
1801 cleanup_pointers
= g_slist_remove (cleanup_pointers
, p
);
1804 /*** Getters and Setters ******************************************************/
1807 PluginInstance::SetSource (const char *value
)
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
);
1823 PluginInstance::GetBackground ()
1829 PluginInstance::SetBackground (const char *value
)
1831 g_free (background
);
1832 background
= g_strdup (value
);
1835 Color
*c
= color_from_str (background
);
1840 surface
->SetBackgroundColor (c
);
1848 PluginInstance::GetEnableFramerateCounter ()
1850 return enable_framerate_counter
;
1854 PluginInstance::SetEnableFramerateCounter (bool value
)
1856 enable_framerate_counter
= value
;
1860 PluginInstance::GetEnableRedrawRegions ()
1862 return moonlight_flags
& RUNTIME_INIT_SHOW_EXPOSE
;
1866 PluginInstance::SetEnableRedrawRegions (bool value
)
1869 moonlight_flags
|= RUNTIME_INIT_SHOW_EXPOSE
;
1871 moonlight_flags
&= ~RUNTIME_INIT_SHOW_EXPOSE
;
1875 PluginInstance::GetEnableHtmlAccess ()
1877 return enable_html_access
;
1881 PluginInstance::GetAllowHtmlPopupWindow ()
1883 return allow_html_popup_window
;
1887 PluginInstance::GetWindowless ()
1893 PluginInstance::GetMaxFrameRate ()
1895 return maxFrameRate
;
1899 PluginInstance::GetDeployment ()
1905 PluginInstance::SetMaxFrameRate (int value
)
1907 maxFrameRate
= value
;
1909 surface
->GetTimeManager()->SetMaximumRefreshRate (MAX (value
, 64));
1913 PluginInstance::GetActualHeight ()
1915 return surface
&& surface
->GetWindow () ? surface
->GetWindow()->GetHeight() : 0;
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 ()
1941 PluginInstance::GetWindow ()
1946 // [Obselete (this is obsolete in SL b2.)]
1948 PluginInstance::TimeoutAdd (gint32 interval
, GSourceFunc callback
, gpointer data
)
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
);
1957 id
= g_timeout_add (interval
, callback
, data
);
1959 timers
= g_slist_append (timers
, GINT_TO_POINTER ((int)id
));
1964 // [Obselete (this is obsolete in SL b2.)]
1966 PluginInstance::TimeoutStop (guint32 source_id
)
1968 g_source_remove (source_id
);
1969 timers
= g_slist_remove (timers
, GINT_TO_POINTER (source_id
));
1973 plugin_instance_get_id (PluginInstance
*instance
)
1975 return instance
->GetId ();
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;
1990 PluginXamlLoader::LoadVM ()
1993 return InitializeLoader ();
1999 PluginXamlLoader::InitializeLoader ()
2008 if (GetFilename ()) {
2009 managed_loader
= plugin
->ManagedCreateXamlLoaderForFile (this, GetResourceBase(), GetFilename ());
2010 } else if (GetString ()) {
2011 managed_loader
= plugin
->ManagedCreateXamlLoaderForString (this, GetResourceBase(), GetString ());
2016 initialized
= managed_loader
!= NULL
;
2024 // On error it sets the @error ref to 1
2025 // Returns the filename that we are missing
2028 PluginXamlLoader::TryLoad (int *error
)
2030 DependencyObject
*element
;
2031 Type::Kind element_type
;
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
);
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
));
2054 GetSurface ()->EmitError (error_args
);
2058 d(printf ("PluginXamlLoader::TryLoad: Could not load xaml %s: %s (missing_assembly: %s)\n",
2059 GetFilename () ? "file" : "string", GetFilename () ? GetFilename () : GetString (),
2062 xaml_is_managed = true;
2063 return GetMissing ();
2069 Type
*t
= Type::Find(element_type
);
2071 d(printf ("PluginXamlLoader::TryLoad: Return value does not subclass Canvas, it is an unregistered type\n"));
2073 GetSurface ()->EmitError (new ErrorEventArgs (RuntimeError
,
2074 MoonError (MoonError::EXCEPTION
, 2101, "Failed to initialize the application's root visual")));
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 ()));
2082 GetSurface ()->EmitError (new ErrorEventArgs (RuntimeError
,
2083 MoonError (MoonError::EXCEPTION
, 2101, "Failed to initialize the application's root visual")));
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
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
))
2104 if (value
->GetKind () != Type::STRING
)
2107 if (!xaml_is_valid_event_name (target
->GetKind(), name
, false))
2110 const char* function_name
= value
->AsString ();
2112 if (!strncmp (function_name
, "javascript:", strlen ("javascript:")))
2115 event_object_add_xaml_listener ((EventObject
*) target
->AsDependencyObject (), plugin
, name
, function_name
);
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;
2131 managed_loader
= NULL
;
2135 PluginXamlLoader::~PluginXamlLoader ()
2142 plugin
->ManagedLoaderDestroy (managed_loader
);
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.
2158 PluginInstance::MonoGetMethodFromName (MonoClass
*klass
, const char *name
, int narg
)
2161 method
= mono_class_get_method_from_name (klass
, name
, narg
);
2164 printf ("Warning could not find method %s\n", name
);
2170 PluginInstance::MonoGetPropertyFromName (MonoClass
*klass
, const char *name
)
2172 MonoProperty
*property
;
2173 property
= mono_class_get_property_from_name (klass
, name
);
2176 printf ("Warning could not find property %s\n", name
);
2181 bool PluginInstance::mono_is_loaded
= false;
2184 PluginInstance::MonoIsLoaded ()
2186 return mono_is_loaded
;
2190 extern gboolean
mono_jit_set_trace_options (const char *options
);
2194 PluginInstance::DeploymentInit ()
2196 return mono_is_loaded
= true; // We load mono in runtime_init.
2201 PluginInstance::CreatePluginDeployment ()
2203 deployment
= new Deployment ();
2204 Deployment::SetCurrent (deployment
);
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
) {
2218 MonoClass
*app_launcher
;
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");
2232 moon_exception
= mono_class_from_name (image
, "Mono", "MoonException");
2233 if (!moon_exception
) {
2234 g_warning ("could not find MoonException type");
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");
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");
2256 printf ("Plugin AppDomain Creation: could not find System.Windows.dll.\n");
2259 printf ("Plugin AppDomain Creation: %s\n", result
? "OK" : "Failed");
2265 PluginInstance::ManagedExceptionToErrorEventArgs (MonoObject
*exc
)
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
));
2287 PluginInstance::ManagedCreateXamlLoader (XamlLoader
* native_loader
, const char *resourceBase
, const char *file
, const char *str
)
2290 MonoObject
*exc
= NULL
;
2291 if (moon_load_xaml
== NULL
)
2294 PluginInstance
*this_obj
= this;
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
);
2308 deployment
->GetSurface()->EmitError (ManagedExceptionToErrorEventArgs (exc
));
2312 return GUINT_TO_POINTER (mono_gchandle_new (loader
, false));
2316 PluginInstance::ManagedCreateXamlLoaderForFile (XamlLoader
*native_loader
, const char *resourceBase
, const char *file
)
2318 return ManagedCreateXamlLoader (native_loader
, resourceBase
, file
, NULL
);
2322 PluginInstance::ManagedCreateXamlLoaderForString (XamlLoader
* native_loader
, const char *resourceBase
, const char *str
)
2324 return ManagedCreateXamlLoader (native_loader
, resourceBase
, NULL
, str
);
2328 PluginInstance::ManagedLoaderDestroy (gpointer loader_object
)
2330 guint32 loader
= GPOINTER_TO_UINT (loader_object
);
2332 mono_gchandle_free (loader
);
2336 PluginInstance::ManagedInitializeDeployment (const char *file
)
2338 if (moon_initialize_deployment_xap
== NULL
&& moon_initialize_deployment_xaml
)
2341 PluginInstance
*this_obj
= this;
2344 MonoObject
*exc
= NULL
;
2346 Deployment::SetCurrent (deployment
);
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
);
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
);
2361 deployment
->GetSurface()->EmitError (ManagedExceptionToErrorEventArgs (exc
));
2365 return (bool) (*(MonoBoolean
*) mono_object_unbox(ret
));
2369 PluginInstance::ManagedDestroyApplication ()
2371 if (moon_destroy_application
== NULL
)
2374 PluginInstance
*this_obj
= this;
2375 MonoObject
*exc
= NULL
;
2377 params
[0] = &this_obj
;
2379 Deployment::SetCurrent (deployment
);
2381 mono_runtime_invoke (moon_destroy_application
, NULL
, params
, &exc
);
2384 deployment
->GetSurface()->EmitError (ManagedExceptionToErrorEventArgs (exc
));