123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340 |
- // Copyright (c) 2014 The Chromium Authors. All rights reserved.
- // Use of this source code is governed by a BSD-style license that can be
- // found in the LICENSE-CHROMIUM file.
- #include "shell/browser/ui/cocoa/electron_inspectable_web_contents_view.h"
- #include "content/public/browser/render_widget_host_view.h"
- #include "shell/browser/api/electron_api_web_contents.h"
- #include "shell/browser/ui/cocoa/event_dispatching_window.h"
- #include "shell/browser/ui/inspectable_web_contents.h"
- #include "shell/browser/ui/inspectable_web_contents_view_delegate.h"
- #include "shell/browser/ui/inspectable_web_contents_view_mac.h"
- #include "ui/base/cocoa/base_view.h"
- #include "ui/gfx/mac/scoped_cocoa_disable_screen_updates.h"
- #if !defined(__has_feature) || !__has_feature(objc_arc)
- #error "This file requires ARC support."
- #endif
- @implementation ElectronInspectableWebContentsView
- - (instancetype)initWithInspectableWebContentsViewMac:
- (InspectableWebContentsViewMac*)view {
- self = [super init];
- if (!self)
- return nil;
- inspectableWebContentsView_ = view;
- devtools_visible_ = NO;
- devtools_docked_ = NO;
- devtools_is_first_responder_ = NO;
- attached_to_window_ = NO;
- if (inspectableWebContentsView_->inspectable_web_contents()->IsGuest()) {
- fake_view_ = [[NSView alloc] init];
- [fake_view_ setAutoresizingMask:NSViewWidthSizable | NSViewHeightSizable];
- [self addSubview:fake_view_];
- } else {
- auto* contents = inspectableWebContentsView_->inspectable_web_contents()
- ->GetWebContents();
- auto* contentsView = contents->GetNativeView().GetNativeNSView();
- [contentsView setAutoresizingMask:NSViewWidthSizable | NSViewHeightSizable];
- [self addSubview:contentsView];
- }
- // See https://code.google.com/p/chromium/issues/detail?id=348490.
- [self setWantsLayer:YES];
- return self;
- }
- - (void)dealloc {
- [[NSNotificationCenter defaultCenter] removeObserver:self];
- }
- - (void)resizeSubviewsWithOldSize:(NSSize)oldBoundsSize {
- [self adjustSubviews];
- }
- - (void)viewDidMoveToWindow {
- if (attached_to_window_ && !self.window) {
- attached_to_window_ = NO;
- [[NSNotificationCenter defaultCenter] removeObserver:self];
- } else if (!attached_to_window_ && self.window) {
- attached_to_window_ = YES;
- [[NSNotificationCenter defaultCenter]
- addObserver:self
- selector:@selector(viewDidBecomeFirstResponder:)
- name:kViewDidBecomeFirstResponder
- object:nil];
- [[NSNotificationCenter defaultCenter]
- addObserver:self
- selector:@selector(parentWindowBecameMain:)
- name:NSWindowDidBecomeMainNotification
- object:nil];
- }
- }
- - (IBAction)showDevTools:(id)sender {
- inspectableWebContentsView_->inspectable_web_contents()->ShowDevTools(true);
- }
- - (void)notifyDevToolsFocused {
- if (inspectableWebContentsView_->GetDelegate())
- inspectableWebContentsView_->GetDelegate()->DevToolsFocused();
- }
- - (void)notifyDevToolsResized {
- // When devtools is opened, resizing devtools would not trigger
- // UpdateDraggableRegions for WebContents, so we have to notify the window
- // to do an update of draggable regions.
- if (inspectableWebContentsView_->GetDelegate())
- inspectableWebContentsView_->GetDelegate()->DevToolsResized();
- }
- - (void)setDevToolsVisible:(BOOL)visible activate:(BOOL)activate {
- if (visible == devtools_visible_)
- return;
- auto* inspectable_web_contents =
- inspectableWebContentsView_->inspectable_web_contents();
- auto* devToolsWebContents =
- inspectable_web_contents->GetDevToolsWebContents();
- auto* devToolsView = devToolsWebContents->GetNativeView().GetNativeNSView();
- devtools_visible_ = visible;
- if (devtools_docked_) {
- if (visible) {
- // Place the devToolsView under contentsView, notice that we didn't set
- // sizes for them until the setContentsResizingStrategy message.
- [self addSubview:devToolsView positioned:NSWindowBelow relativeTo:nil];
- [self adjustSubviews];
- // Focus on web view.
- devToolsWebContents->RestoreFocus();
- } else {
- gfx::ScopedCocoaDisableScreenUpdates disabler;
- [devToolsView removeFromSuperview];
- [self adjustSubviews];
- [self notifyDevToolsResized];
- }
- } else {
- if (visible) {
- if (activate) {
- [devtools_window_ makeKeyAndOrderFront:nil];
- } else {
- [devtools_window_ orderBack:nil];
- }
- } else {
- [devtools_window_ setDelegate:nil];
- [devtools_window_ close];
- devtools_window_ = nil;
- }
- }
- }
- - (BOOL)isDevToolsVisible {
- return devtools_visible_;
- }
- - (BOOL)isDevToolsFocused {
- if (devtools_docked_) {
- return [[self window] isKeyWindow] && devtools_is_first_responder_;
- } else {
- return [devtools_window_ isKeyWindow];
- }
- }
- - (void)setIsDocked:(BOOL)docked activate:(BOOL)activate {
- // Revert to no-devtools state.
- [self setDevToolsVisible:NO activate:NO];
- // Switch to new state.
- devtools_docked_ = docked;
- auto* inspectable_web_contents =
- inspectableWebContentsView_->inspectable_web_contents();
- auto* devToolsWebContents =
- inspectable_web_contents->GetDevToolsWebContents();
- auto devToolsView = devToolsWebContents->GetNativeView().GetNativeNSView();
- if (!docked) {
- auto styleMask = NSWindowStyleMaskTitled | NSWindowStyleMaskClosable |
- NSWindowStyleMaskMiniaturizable |
- NSWindowStyleMaskResizable |
- NSWindowStyleMaskTexturedBackground |
- NSWindowStyleMaskUnifiedTitleAndToolbar;
- devtools_window_ = [[EventDispatchingWindow alloc]
- initWithContentRect:NSMakeRect(0, 0, 800, 600)
- styleMask:styleMask
- backing:NSBackingStoreBuffered
- defer:YES];
- [devtools_window_ setDelegate:self];
- [devtools_window_ setFrameAutosaveName:@"electron.devtools"];
- [devtools_window_ setTitle:@"Developer Tools"];
- [devtools_window_ setReleasedWhenClosed:NO];
- [devtools_window_ setAutorecalculatesContentBorderThickness:NO
- forEdge:NSMaxYEdge];
- [devtools_window_ setContentBorderThickness:24 forEdge:NSMaxYEdge];
- NSView* contentView = [devtools_window_ contentView];
- devToolsView.frame = contentView.bounds;
- devToolsView.autoresizingMask = NSViewWidthSizable | NSViewHeightSizable;
- [contentView addSubview:devToolsView];
- [devToolsView setMouseDownCanMoveWindow:NO];
- } else {
- [devToolsView setMouseDownCanMoveWindow:YES];
- }
- [self setDevToolsVisible:YES activate:activate];
- }
- - (void)setContentsResizingStrategy:
- (const DevToolsContentsResizingStrategy&)strategy {
- strategy_.CopyFrom(strategy);
- [self adjustSubviews];
- }
- - (void)adjustSubviews {
- if (![[self subviews] count])
- return;
- if (![self isDevToolsVisible] || devtools_window_) {
- DCHECK_EQ(1u, [[self subviews] count]);
- NSView* contents = [[self subviews] objectAtIndex:0];
- [contents setFrame:[self bounds]];
- return;
- }
- NSView* devToolsView = [[self subviews] objectAtIndex:0];
- NSView* contentsView = [[self subviews] objectAtIndex:1];
- DCHECK_EQ(2u, [[self subviews] count]);
- gfx::Rect new_devtools_bounds;
- gfx::Rect new_contents_bounds;
- ApplyDevToolsContentsResizingStrategy(
- strategy_, gfx::Size(NSSizeToCGSize([self bounds].size)),
- &new_devtools_bounds, &new_contents_bounds);
- [devToolsView setFrame:[self flipRectToNSRect:new_devtools_bounds]];
- [contentsView setFrame:[self flipRectToNSRect:new_contents_bounds]];
- // Move mask to the devtools area to exclude it from dragging.
- NSRect cf = contentsView.frame;
- NSRect sb = [self bounds];
- NSRect devtools_frame;
- if (cf.size.height < sb.size.height) { // bottom docked
- devtools_frame.origin.x = 0;
- devtools_frame.origin.y = 0;
- devtools_frame.size.width = sb.size.width;
- devtools_frame.size.height = sb.size.height - cf.size.height;
- } else { // left or right docked
- if (cf.origin.x > 0) // left docked
- devtools_frame.origin.x = 0;
- else // right docked.
- devtools_frame.origin.x = cf.size.width;
- devtools_frame.origin.y = 0;
- devtools_frame.size.width = sb.size.width - cf.size.width;
- devtools_frame.size.height = sb.size.height;
- }
- [self notifyDevToolsResized];
- }
- - (void)setTitle:(NSString*)title {
- [devtools_window_ setTitle:title];
- }
- - (void)viewDidBecomeFirstResponder:(NSNotification*)notification {
- auto* inspectable_web_contents =
- inspectableWebContentsView_->inspectable_web_contents();
- DCHECK(inspectable_web_contents);
- auto* webContents = inspectable_web_contents->GetWebContents();
- if (!webContents)
- return;
- auto* webContentsView = webContents->GetNativeView().GetNativeNSView();
- NSView* view = [notification object];
- if ([[webContentsView subviews] containsObject:view]) {
- devtools_is_first_responder_ = NO;
- return;
- }
- auto* devToolsWebContents =
- inspectable_web_contents->GetDevToolsWebContents();
- if (!devToolsWebContents)
- return;
- auto devToolsView = devToolsWebContents->GetNativeView().GetNativeNSView();
- if ([[devToolsView subviews] containsObject:view]) {
- devtools_is_first_responder_ = YES;
- [self notifyDevToolsFocused];
- }
- }
- - (void)parentWindowBecameMain:(NSNotification*)notification {
- NSWindow* parentWindow = [notification object];
- if ([self window] == parentWindow && devtools_docked_ &&
- devtools_is_first_responder_)
- [self notifyDevToolsFocused];
- }
- - (void)redispatchContextMenuEvent:(base::apple::OwnedNSEvent)event {
- DCHECK(event.Get().type == NSEventTypeRightMouseDown ||
- (event.Get().type == NSEventTypeLeftMouseDown &&
- (event.Get().modifierFlags & NSEventModifierFlagControl)));
- content::WebContents* contents =
- inspectableWebContentsView_->inspectable_web_contents()->GetWebContents();
- electron::api::WebContents* api_contents =
- electron::api::WebContents::From(contents);
- if (api_contents) {
- // Temporarily pretend that the WebContents is fully non-draggable while we
- // re-send the mouse event. This allows the re-dispatched event to "land"
- // on the WebContents, instead of "falling through" back to the window.
- auto* rwhv = contents->GetRenderWidgetHostView();
- if (rwhv) {
- api_contents->SetForceNonDraggable(true);
- BaseView* contentsView =
- (BaseView*)rwhv->GetNativeView().GetNativeNSView();
- [contentsView mouseEvent:event.Get()];
- api_contents->SetForceNonDraggable(false);
- }
- }
- }
- #pragma mark - NSWindowDelegate
- - (void)windowWillClose:(NSNotification*)notification {
- inspectableWebContentsView_->inspectable_web_contents()->CloseDevTools();
- }
- - (void)windowDidBecomeMain:(NSNotification*)notification {
- content::WebContents* web_contents =
- inspectableWebContentsView_->inspectable_web_contents()
- ->GetDevToolsWebContents();
- if (!web_contents)
- return;
- web_contents->RestoreFocus();
- content::RenderWidgetHostView* rwhv = web_contents->GetRenderWidgetHostView();
- if (rwhv)
- rwhv->SetActive(true);
- [self notifyDevToolsFocused];
- }
- - (void)windowDidResignMain:(NSNotification*)notification {
- content::WebContents* web_contents =
- inspectableWebContentsView_->inspectable_web_contents()
- ->GetDevToolsWebContents();
- if (!web_contents)
- return;
- web_contents->StoreFocus();
- content::RenderWidgetHostView* rwhv = web_contents->GetRenderWidgetHostView();
- if (rwhv)
- rwhv->SetActive(false);
- }
- @end
|