[Mac]extension弹出窗口的实现

记录为了怕自己以后忘记了。

最近在chromium解了几个extension的bug,顺便把这块整理一下.


1. UI方面,弹出的是一个 NSWindow,   对应的代码是 NSExtensionPopupController : BaseBubbleController

     scoped_ptr<extension::ExtensionViewHost> host_;

    NSExtensionPopupController的作用是: 

              1) 控制NSWindow的显示以及关闭,即一个正常Bubble应该有的动作。例如 当你点击popup窗口外的地方,会关闭(这部分功能是继承与 BaseBubbleController的)

              2) 在合适的时候,把 extension的内容放到合适的位置显示.


 一般显示的时候,是直接调用静态函数的 

+ (ExtensionPopupController*)showURL:(GURL)url
                           inBrowser:(Browser*)browser
                          anchoredAt:(NSPoint)anchoredAt
                       arrowLocation:(info_bubble::BubbleArrowLocation)
                                         arrowLocation
                             devMode:(BOOL)devMode {


  extensions::ExtensionViewHost* host =               //根据url 和 browser 来创建一个 ExtensionViewHost
      extensions::ExtensionViewHostFactory::CreatePopupHost(url, browser);
  DCHECK(host);
  if (!host)
    return nil;

  ...
  [gPopup close]; // 关闭之前的popup,默认是只显示一个extension的popup

  ...

  gPopup = [[ExtensionPopupController alloc]            // 创建新的popup的controller
      initWithHost:host
      parentWindow:browser->window()->GetNativeWindow()
        anchoredAt:anchoredAt
     arrowLocation:arrowLocation
           devMode:devMode];
  return gPopup;
}


那么当ExtensionPopupController创建的时候,他已经拥有了他需要的 ExtensionViewHost. 以及BaseBubbleController一些需要的参数,例如箭头位置.

现在又2个问题:

     1)  ExtensionViewHost 是什么,作用是什么?

         C++代码层的view,是真正要在Popup中显示内容的view

     2)ExtensionPopupController 那么具体他干了什么呢?

           ExtensionPopupController 有2个成员变量,一个是 extension::ExtensionViewHost host_,另外一个是 NSView* extensionView_.

           看下他初始化

  

- (id)initWithHost:(extensions::ExtensionViewHost*)host
      parentWindow:(NSWindow*)parentWindow
        anchoredAt:(NSPoint)anchoredAt
     arrowLocation:(info_bubble::BubbleArrowLocation)arrowLocation
           devMode:(BOOL)devMode {
  base::scoped_nsobject<InfoBubbleWindow> window([[InfoBubbleWindow alloc]
      initWithContentRect:ui::kWindowSizeDeterminedLater
                styleMask:NSBorderlessWindowMask
                  backing:NSBackingStoreBuffered
                    defer:YES]);     // 创建一个 InfoBubbleWindow,最终是作为BaseBubble的window
  if (!window.get())
    return nil;

  anchoredAt = [parentWindow convertBaseToScreen:anchoredAt];
  if ((self = [super initWithWindow:window   // 看上面的注释
                       parentWindow:parentWindow
                         anchoredAt:anchoredAt])) {
    host_.reset(host);
    beingInspected_ = devMode;
    ignoreWindowDidResignKey_ = NO;

    InfoBubbleView* view = self.bubble;   // 获取自己的显示内容的view,其实就是NSWindow的 contentView
    [view setArrowLocation:arrowLocation];

    extensionView_ = host->view()->native_view();   // 这里,把c++的view 与cocoa的算是联系上了,看下面也有介绍
    container_.reset(new ExtensionPopupContainer(self));
    host->view()->set_container(container_.get());  // 把 view 设置了 container

    NSNotificationCenter* center = [NSNotificationCenter defaultCenter];
    [center addObserver:self
               selector:@selector(extensionViewFrameChanged)
                   name:NSViewFrameDidChangeNotification
                 object:extensionView_];

    [view addSubview:extensionView_];  // 把 extensionView 加入到这个window的 contentView里

    notificationBridge_.reset(new DevtoolsNotificationBridge(self));
    registrar_.reset(new content::NotificationRegistrar);
    if (beingInspected_) {
      // Listen for the extension to finish loading so the dev tools can be
      // opened.
      registrar_->Add(notificationBridge_.get(),
                      chrome::NOTIFICATION_EXTENSION_HOST_DID_STOP_LOADING,
                      content::Source<BrowserContext>(host->browser_context()));
    }
  }
  return self;
}

看完初始化,估计会oc的人明白差不多了,大体就是说,

c++有view的,他是显示内容的提供者,就是 ExtensionViewHost, 要显示在mac上,他打开一个 NSWindow,然后把 ExtensionViewHost里的真正的view设置为NSWindow的contentView的一个子View,然后就可以画出了,同时用户如果操作或者别的 影响了这个window,比如frame变化,或者widow关闭了,这里会有相应的处理,返回通知host_以让c++侧代码得以反应.


2. 其实这里重点想说下 ExtensionHostView 以及如何去建立 renderer process 去运行extension的.

   在上面showURL已经看到

    extensions::ExtensionViewHostFactory::CreatePopupHost(url, browser);

   返回的是  ExtensionViewHostMac.

   ExtensionViewHostMac : public ExtensionViewHost

   ExtensionViewHostMac 几乎啥都没做吧

   

  // ExtensionViewHost 是在browser ui线程里来backing一个view用的,例如,可以是popup,infobar, dialog

   ExtensionViewHost: public ExtensionHost, 

                                 public web_modal::WebContentsModalDialogManagerDelegate,

                                 public web_modal::WebContentsModalDialogHost

  重要成员变量:

  scoped_ptr<PlatformExtensionView> view_;  // 这里是 ExtensionViewMac , typdef的,上面代码里 extensionView_ = host->view()->native_view().

                                                                   // ExtensionViewMac 其实是一个桥梁,是mac 和 c++代码的桥梁



  如何建立起rederer process,需要看 ExtensionHost


ExtensionHost::ExtensionHost(const Extension* extension,
                             SiteInstance* site_instance,
                             const GURL& url,
                             ViewType host_type)
    : delegate_(ExtensionsBrowserClient::Get()->CreateExtensionHostDelegate()),
      extension_(extension),
      extension_id_(extension->id()),
      browser_context_(site_instance->GetBrowserContext()),
      render_view_host_(NULL),
      did_stop_loading_(false),
      document_element_available_(false),
      initial_url_(url),
      extension_function_dispatcher_(browser_context_, this),
      extension_host_type_(host_type) {
  // Not used for panels, see PanelHost.
  DCHECK(host_type == VIEW_TYPE_EXTENSION_BACKGROUND_PAGE ||
         host_type == VIEW_TYPE_EXTENSION_DIALOG ||
         host_type == VIEW_TYPE_EXTENSION_INFOBAR ||
         host_type == VIEW_TYPE_EXTENSION_POPUP);
  host_contents_.reset(WebContents::Create(              // 又见到熟悉的 WebContents::Create
      WebContents::CreateParams(browser_context_, site_instance))),
  content::WebContentsObserver::Observe(host_contents_.get());
  host_contents_->SetDelegate(this);
  SetViewType(host_contents_.get(), host_type);

  render_view_host_ = host_contents_->GetRenderViewHost();

  // Listen for when an extension is unloaded from the same profile, as it may
  // be the same extension that this points to.
  registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_UNLOADED_DEPRECATED,
                 content::Source<BrowserContext>(browser_context_));

  // Set up web contents observers and pref observers.
  delegate_->OnExtensionHostCreated(host_contents());
}

我觉的,当我们看到 WebContents::Create的时候就已经明白了(不明白同学得自己去看了,那是一大块内容,一时半会将不明白).





-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值