QWidget在NPAPI插件开发中的使用

       使用NPAPI(Netscape PluginApplication Programming Interface,网景插件应用程序接口)开发safari插件并没有像使用Cocoa and WebKit那样方便快捷,只可惜后者由于安全性的问题,被苹果无情的抛弃了,无奈只能使用NPAPI。

       NPAPI是用于在浏览器中执行外部应用程序的通用接口,与微软的ActiveX是竞争技术。但是NPAPI是一款跨浏览器的接口,因此在市面上的使用要比ActiveX更为广泛,基本上所有主流的浏览器都支持该接口开发的插件,其中比较有代表性的插件是Adobe Flash Player、QuickTime、RealPlayer、Windows Media Player。在safari中使用该接口优点是将运行插件的进程和safari进程分隔开,保证了数据的安全性,缺点是不能使用cocoa的Interface Builder以及相应的控件来创建界面。

       说了这么多废话,只是为了说明为什么要用NPAPI来开发safari插件。现在说说Qt和使用NPAPI开发safari插件之间的千丝万缕。Qt中所有的控件和窗口都是基于QWidget衍生出来的,而cocoa下的视图和控件都会继承NSView这个类,所以第一步想到的是怎样才能把QWidget转换成NSView呢?查阅了大量的资料发现Qt不愧是跨平台第一解决方案,Qt API中竟然提供了现存的方法和例子:
       QMacNativeWidget*nativeWidget = new QMacNativeWidget();
       nativeWidget->move(0,0);
       QVBoxLayout*layout = new QVBoxLayout();
       QPushButton*pushButton = new QPushButton("An Embedded Qt Button!",nativeWidget);
       // Don't use thelayout rect calculated from QMacStyle.
       pushButton->setAttribute(Qt::WA_LayoutUsesWidgetRect);layout->addWidget(pushButton);
       nativeWidget->setLayout(layout);
      // Adjust Cocoalayouts
      NSView*nativeWidgetView = reinterpret_cast(nativeWidget->winId());
      [nativeWidgetView setAutoresizingMask:NSViewWidthSizable | NSViewHeightSizable];
      [nativeWidgetViewsetAutoresizesSubviews:YES];
      NSView*pushButtonView = reinterpret_cast(pushButton->winId());
      [pushButtonViewsetAutoresizingMask:NSViewWidthSizable];

      //show widget
      nativeWidget->show();
      pushButton->show();

         QWidget转成成NSView后,发现另外一个比较悲剧的事情就是,NPAPI中不支持NSView结构,但是支持层结构(CALayer),没有办法只能寻找NSView和CALayer之间的关系,查阅苹果API发现NSView中还真有一个方法将其转化为CALayer,通过下面的描述得知,要想把NSView的内容放到CALayer上面,首先的传入一个CALayer的指针,然后设置NSView使用Core Animation 作为一个后备存储。
        Alayer-hosting view is a view that contains a Core Animation layer that youintend to manipulate directly. You create a layer-hosting view by instantiatingan instance of a Core Animation layer class and setting that layer using theview’s setLayer: method. After doingso, you then invoke setWantsLayer:with a value of YES. When using a layer-hosting view you shouldnot rely on the view for drawing, nor should you add subviews to thelayer-hosting view。

       所以把QWidget转换成CALayer就得经过以下步骤:
       第一步:QWidget转换为NSview,参考上面的代码。
       第二步:创建一个NSView,把它作为layer-hosting view。
                 NSView  *hostView  = [[NSView alloc] initWithFrame:NSMakeRect(0,0, width, height)];
                 CALayer  *rootLayer = [CALayer layer];
                 [hostView  setLayer: rootLayer];
                 [hostView  setWantsLayer:YES];
      第三步:完成QWidget到CALayer的最终转换。
                [hostViewaddSubview: nativeWidgetView positioned:NSWindowAbove relativeTo:nil];

你可能感兴趣的:(QWidget在NPAPI插件开发中的使用)