Safari 5.1 npapi issue - cocoa

Since several days I am trying to resolve the folowing issue, reading all I found around the web about npapi on mac.
The goal is to have a npapi plugin which works for safari and firefox(mac).
My software (that I can not rewrite specialy for this purpose hase about 45000 lines of C code) is based on a NSView attached to a NSDocument....
I have a webkit version based plugin that I must trash (thanks to Apple!) based to the same NSView.
I have a npapi version plugin which works fine on firefox. In this npapi plugin, I take the carbon window ref, I make a NSWindow based on that:
NSWindow *browserWindow = [[[NSWindow alloc] initWithWindowRef:wind]autorelease];
and I put my NSView on this window and that works.
Now the pb is that I can not do the same thing on safari.
Look at attached picture, the window is not in the safari's window!
I tryed several ways... it dose not work.
Can a cocoa's gourou says where I am making something wrong? or is this a known issue?
NPError NPP_SetWindow(NPP instance, NPWindow* window){
NP_CGContext *ctx = window->window;
void *wind = ctx->window;
...
in the NSView init function:
NSWindow *browserWindow = [[NSWindow alloc] initWithWindowRef:wind];
self = [super initWithFrame:frame];
if( self )
{
[browserWindow makeFirstResponder: self];
[self setNextResponder: nil];
[browserWindow setContentView:self];
[self webPlugInInitialize];// my own initializing
}
return self;

In Safari 5.1, the web rendering is not done by Safari itself, but on a different process to enhance security. Open up the Activity Monitor, and you see that background process called "Safari Web Process" or something like that.
So, you can't and shouldn't create NSWindow based on the Carbon window ref which can be obtained within NPAPI plugin.
Read Apple's own documentation on this point. You should request the core graphics drawing method, and then the WindowRef field of NP_CGContext should have a NSWindow*, not the Carbon window ref.

If it works on Firefox, that's totally shocking and completely unsupported. Does it work in Firefox 4 and later?
If you absolutely have to use an NSView, the only way that I know to do it in a plugin is to render the NSView into your CGContext. Keep in mind that in newer NPAPI browsers with the Cocoa event system you get the CGContextRef as part of the draw event; to request a draw event you can call NPN_InvalidateWindow.
FireBreath has a completely experimental and not-fully-functional example of rendering an NSView (ans specifically a WebView) into a CGContextRef that you could look at as an example.
Other than using a CGContextRef your only other choice is to use a CALayer; if you can find a way to make a NSWindow or NSView in that you could be okay, but I don't know if there is one. Someone suggested that setting the CALayer as the rendering layer for the NSView might work. Either way you'll most likely have to forward all the events since you are basically hosting the NSView in an offscreen view.
Make no mistake; there is no supported way to get an NSView in the browser. There never has been -- methods that people have used were unsupported and depended on browser-specific implementations of the API. When you use things like that, you can reliably expect them to eventually break, such as in this case. For more information on the drawing models, you could read Stuart Morgan's blog post on the subject, check out the FireBreath mac drawing model docs, or read the Cocoa event model spec.

Given that you start with "take the carbon window ref", your approach is doomed, because it is based on the Carbon event model (and not just that, but assumptions about its internal implementation details). Anyone running Firefox on a 64-bit system will have to manually restart Firefox in 32-bit mode for your hack to work, and even then it will only work until Firefox completely removes Carbon support (which is planned for the foreseeable future).
As the other answers said, where you are going wrong is that your whole approach is completely unsupported, and the fact that it ever worked at all as an NPAPI plugin was luck. You simply cannot use an NSView directly in an NPAPI plugin.

Related

NSWindowWillCloseNotification is received when exiting full screen

In my 3D application, I handle NSWindowWillCloseNotification to perform cleanup (stop display link, release resources, etc.). The app can run in two modes, OpenGL and Metal. There is a ViewBase class that implements common functionality and among other things handles the notification.
Everything works fine in OpenGL mode, however in Metal mode, the NSWindowWillCloseNotification is received when exiting fullscreen window causing the app to stop showing anything. The only meaningful difference between Metal and OpenGL is that Metal view uses backing layer, but I do not know why this may matter.
I am totally confused why this could be happening and would appreciate any help.
As it turned out, I was setting notification handler in awakeFromNib, where [self window] was nil. So notification handler was set of null window. I fixed the problem by referencing the main application window instead: auto* mainWindow = [[NSApplication sharedApplication] mainWindow];

Responsive Scrolling - setWantsLayer Webkit problems

My project is on base SDK 10.6 built in Xcode 3 - it’s important that it is a universal binary that also works with PPC.
In 10.9 my application has really jerky scrolling compared to Safari - if I add
[self setWantsLayer:YES]; the scrolling is super fast like Safari, great!
However I get visual glitches when scrolling, see screenshot of eBay where the legal image which was supposed to be fixed at the bottom of the page keeps repeating.
I know setWantsLayer isn’t supposed to be used with a webKit, but is there anyway to stop these visual glitches or is there another way to get the smooth scrolling without using setWantsLayer.
Above is an issue with eBay when scrolling and below is an issue with Twitter while scrolling, happens on various websites especially with fixed objects.
Issue with Twitter
Actually I originally thought the below solution was a solution without realising that I was back to the horrible jumpy scrolling. I leave it for reference.
I had the same problem you seems to have here.
I found that if I implemented the canDrawSubviewsIntoLayer in the subclass my glitches with the rendering were fixed.
so in the initWithCoder/initWithFrame method call:
[self setWantsLayer:YES];
then implement canDrawSubviewsIntoLayer
- (BOOL)canDrawSubviewsIntoLayer {
return YES;
}
You need to subclass the webView. I also found that works equally well if instead you subclass the NSView below and do the same in the NSView subclass but since I don't understand why that works my suggestion is to subclass the webView.
I hope it helps you and helps others.

Disable All Interaction with a Cocoa WebView

I'm having difficulty in using a WebView that is being used purely to display a preview of a website - and I want to ignore all/any interactions the user may try to make with it.
I've already tried Cocoa webView - Disable all interaction to no avail; you can still easily spam-click and it will recognise the presses. (at least there's no context menu)
This one seems overkill; Disable a WebKit WebView - there must be an easier way.
In iOS I know exactly how to solve this, but as a Cocoa newcomer I am stumped - does anyone have any suggestions or better ways to achieve this? Or dump a transparent NSView on top and gobble up interactions? (tried this as well by subclassing an NSView, also to no effect)
Whole project is in IB currently, if this makes any difference.
I think you want to implement a WebPolicy Delegate and have it deny navigation events.

How to render HTML from an NPAPI plugin in Safari

I've been writing a Mac NPAPI-based browser plugin to convert a file of custom mimetype (say, "application/x-foo") into an HTML representation, which can then be viewed directly in a browser. These files are usually directly served, so I'm more concerned about supporting full-page viewing, rather than embedded views via <object> tags.
On Firefox, this has been relatively simple: I make a call to NPN_NewStream with the text/html mimetype, write the converted HTML into the stream, and then clean it up with NPN_DestroySteam. The browser automatically handles the request for a new HTML stream and renders the given HTML into a tab or window. Pretty standard.
For Safari, though, NPN_NewStream does not appear to be implemented (and I did check the WebKit source code). Previously, I was able to use the WebKitPlugin API. With Safari 5.1, this API is gone.
I thought I would be able to create a WebView in a drawing event handler, like this:
NSRect rect = NSMakeRect(0, 0, obj->window.width, obj->window.height);
//...
WebView* webView = [[WebView alloc] initWithFrame:rect frameName:nil groupName:nil];
[[webView mainFrame] loadHTMLString:#"<html><head><title>This is a message from my plug-in!</title></head><body><p><strong>This is a message from my plug-in!</strong></p></body>/html>" baseURL:[NSURL URLWithString:#"http://example.com"]];
[webView drawRect:rect];
and see it in browser. But all that does is render a gray screen with no content, as if not drawn. If I replace the WebView with an NSTextView and set its string to the HTML, everything draws just fine, but of course the HTML is not rendered by an NSTextView.
My question boils down to: is there a good way to render some HTML into a Safari window from an NPAPI plugin? Or if that won't work, into a Google Chrome window? Or some other approach that lets me handle a custom MIME type and display some HTML representation of it?
Honestly, I'm surprised that your newstream approach works on Firefox; that's a new one I've never heard of. If you have to do the drawing yourself, you are limited to either using CoreGraphics with a CGContext or CoreAnimation with a CALayer. In other words, you don't get a NSView, so you can't directly render a WebView into it.
That said, you could put the webview in an offscreen context and render it to your CGContext, then proxy the events; this seems a little complicated for what you're trying to do, but I don't know of another way to do it.
There is an experimental library in FireBreath that does this; scroll wheel isn't implemented, but the other events work, including mouse drag and keyboard. There are still a few strange things with it when using form events, so whether or not this would work for you depends on what content you'll be displaying.
If you're interested in trying to use FireBreath for this you can drop into the FireBreath chat room during business hours (GMT-0600) and I'm usually around and can discuss it with out.

Mac OSX, Cocoa event model in NPAPI , NSView, and Out of process plugins

Well, currently chrome has out of process plugins. and firefox 4 will use same model.
That means plugin process is now seperated from browser process.
Plugin process might NOT have window at all.
My plugin is based on NSView.
Before cocoa event model, when I can access NSWindow in browser process, All I have to do is just add my_view as a subview of the contentView in the window.
[[the_window contentView] addSubview:my_view]
I do NOT need to process events myself. It worked itself.
But now, I convert NPCocoaEvents into NSEvents in event process code.
Do I have to change it myself?
Also some instance of NSEvents, I can not make them for example, wheel mouse events.
What should do I do?
Did I approach a wrong way?
Please enlighten me.
Do I have to change it myself?
If you plan to use the approach of forwarding NSEvents to your existing NSView then yes; there's no way to get access to the original NSEvents. They don't exist in the plugin process.
Another option would be to move away from trying to use native controls, and do your own drawing and event handling. This is the way most NPAPI plugins work.
A third possibility would be to open a separate window for your plugin content, and put your view in that window. This isn't technically supported by NPAPI, and it won't be perfect, but it might be a short-term way to get your plugin working while you explore long-term options.
Did I approach a wrong way?
Yes, what you were doing before was an unsupported hack, and not how NPAPI was intended to be used. Adding a view to a browser's window assumes things about the browser's view hierarchy that are implementation details, and subject to change at any time.
One option would be to use the FireBreath framework to create your plugin, as it already has a lot of the abstraction for negotiating the event and drawing models as well as an event abstraction. It's pretty straightforward to get up and going.

Resources