refactor: move devtools from brightray to atom (#15234)

This commit is contained in:
Milan Burda 2018-10-19 15:50:30 +02:00 committed by Alexey Kuzmin
parent 122017e6fa
commit 6f3c46cc7e
58 changed files with 315 additions and 400 deletions

View file

@ -82,7 +82,7 @@ class BrowserWindow : public TopLevelWindow,
private:
#if defined(OS_MACOSX)
void OverrideNSWindowContentView(brightray::InspectableWebContents* iwc);
void OverrideNSWindowContentView(InspectableWebContents* iwc);
#endif
// Helpers.

View file

@ -8,9 +8,9 @@
#include "atom/browser/native_browser_view.h"
#include "atom/browser/native_window_mac.h"
#include "atom/browser/ui/inspectable_web_contents_view.h"
#include "atom/common/draggable_region.h"
#include "base/mac/scoped_nsobject.h"
#include "brightray/browser/inspectable_web_contents_view.h"
@interface NSView (WebContentsView)
- (void)setMouseDownCanMoveWindow:(BOOL)can_move;
@ -55,8 +55,7 @@ std::vector<gfx::Rect> CalculateNonDraggableRegions(
} // namespace
void BrowserWindow::OverrideNSWindowContentView(
brightray::InspectableWebContents* iwc) {
void BrowserWindow::OverrideNSWindowContentView(InspectableWebContents* iwc) {
// Make NativeWindow use a NSView as content view.
static_cast<NativeWindowMac*>(window())->OverrideNSWindowContentView();
// Add webview to contentView.

View file

@ -22,6 +22,8 @@
#include "atom/browser/native_window.h"
#include "atom/browser/net/atom_network_delegate.h"
#include "atom/browser/ui/drag_util.h"
#include "atom/browser/ui/inspectable_web_contents.h"
#include "atom/browser/ui/inspectable_web_contents_view.h"
#include "atom/browser/web_contents_permission_helper.h"
#include "atom/browser/web_contents_preferences.h"
#include "atom/browser/web_contents_zoom_controller.h"
@ -48,8 +50,6 @@
#include "base/threading/thread_restrictions.h"
#include "base/threading/thread_task_runner_handle.h"
#include "base/values.h"
#include "brightray/browser/inspectable_web_contents.h"
#include "brightray/browser/inspectable_web_contents_view.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/ssl/security_state_tab_helper.h"
#include "content/browser/frame_host/frame_tree_node.h"

View file

@ -29,10 +29,6 @@ namespace blink {
struct WebDeviceEmulationParams;
}
namespace brightray {
class InspectableWebContents;
}
namespace mate {
class Arguments;
class Dictionary;
@ -46,6 +42,7 @@ namespace atom {
class AtomBrowserContext;
class AtomJavaScriptDialogManager;
class InspectableWebContents;
class WebContentsZoomController;
class WebViewGuestDelegate;
class FrameSubscriber;
@ -419,10 +416,10 @@ class WebContents : public mate::TrackableObject<WebContents>,
content::WebContentsObserver::MediaStoppedReason reason) override;
void DidChangeThemeColor(SkColor theme_color) override;
// brightray::InspectableWebContentsDelegate:
// InspectableWebContentsDelegate:
void DevToolsReloadPage() override;
// brightray::InspectableWebContentsViewDelegate:
// InspectableWebContentsViewDelegate:
void DevToolsFocused() override;
void DevToolsOpened() override;
void DevToolsClosed() override;

View file

@ -5,8 +5,8 @@
#include "atom/browser/api/atom_api_web_contents_view.h"
#include "atom/browser/api/atom_api_web_contents.h"
#include "atom/browser/ui/inspectable_web_contents_view.h"
#include "atom/common/api/constructor.h"
#include "brightray/browser/inspectable_web_contents_view.h"
#include "content/public/browser/web_contents_user_data.h"
#include "native_mate/dictionary.h"
@ -43,7 +43,7 @@ namespace api {
WebContentsView::WebContentsView(v8::Isolate* isolate,
mate::Handle<WebContents> web_contents,
brightray::InspectableWebContents* iwc)
InspectableWebContents* iwc)
#if defined(OS_MACOSX)
: View(new DelayedNativeViewHost(iwc->GetView()->GetNativeView())),
#else

View file

@ -9,12 +9,10 @@
#include "content/public/browser/web_contents_observer.h"
#include "native_mate/handle.h"
namespace brightray {
class InspectableWebContents;
}
namespace atom {
class InspectableWebContents;
namespace api {
class WebContents;
@ -30,7 +28,7 @@ class WebContentsView : public View, public content::WebContentsObserver {
protected:
WebContentsView(v8::Isolate* isolate,
mate::Handle<WebContents> web_contents,
brightray::InspectableWebContents* iwc);
InspectableWebContents* iwc);
~WebContentsView() override;
// content::WebContentsObserver:

View file

@ -26,6 +26,7 @@
#include "atom/browser/notifications/notification_presenter.h"
#include "atom/browser/notifications/platform_notification_service.h"
#include "atom/browser/session_preferences.h"
#include "atom/browser/ui/devtools_manager_delegate.h"
#include "atom/browser/web_contents_permission_helper.h"
#include "atom/browser/web_contents_preferences.h"
#include "atom/browser/window_list.h"
@ -494,6 +495,11 @@ void AtomBrowserClient::GetAdditionalAllowedSchemesForFileSystem(
additional_schemes->push_back(content::kChromeDevToolsScheme);
}
void AtomBrowserClient::GetAdditionalWebUISchemes(
std::vector<std::string>* additional_schemes) {
additional_schemes->push_back(content::kChromeDevToolsScheme);
}
void AtomBrowserClient::SiteInstanceDeleting(
content::SiteInstance* site_instance) {
// We are storing weak_ptr, is it fundamental to maintain the map up-to-date
@ -677,6 +683,11 @@ AtomBrowserClient::CreateThrottlesForNavigation(
return throttles;
}
content::DevToolsManagerDelegate*
AtomBrowserClient::GetDevToolsManagerDelegate() {
return new DevToolsManagerDelegate;
}
NotificationPresenter* AtomBrowserClient::GetNotificationPresenter() {
if (!notification_presenter_) {
notification_presenter_.reset(NotificationPresenter::Create());

View file

@ -111,7 +111,9 @@ class AtomBrowserClient : public brightray::BrowserClient,
bool opener_suppressed,
bool* no_javascript_access) override;
void GetAdditionalAllowedSchemesForFileSystem(
std::vector<std::string>* schemes) override;
std::vector<std::string>* additional_schemes) override;
void GetAdditionalWebUISchemes(
std::vector<std::string>* additional_schemes) override;
void SiteInstanceDeleting(content::SiteInstance* site_instance) override;
std::unique_ptr<net::ClientCertStore> CreateClientCertStore(
content::ResourceContext* resource_context) override;
@ -125,6 +127,7 @@ class AtomBrowserClient : public brightray::BrowserClient,
std::unique_ptr<base::Value> GetServiceManifestOverlay(
base::StringPiece name) override;
net::NetLog* GetNetLog() override;
content::DevToolsManagerDelegate* GetDevToolsManagerDelegate() override;
content::PlatformNotificationService* GetPlatformNotificationService()
override;

View file

@ -15,6 +15,7 @@
#include "atom/browser/net/resolve_proxy_helper.h"
#include "atom/browser/pref_store_delegate.h"
#include "atom/browser/special_storage_policy.h"
#include "atom/browser/ui/inspectable_web_contents_impl.h"
#include "atom/browser/web_view_manager.h"
#include "atom/common/atom_version.h"
#include "atom/common/chrome_version.h"
@ -27,7 +28,6 @@
#include "base/threading/sequenced_task_runner_handle.h"
#include "base/threading/thread_restrictions.h"
#include "brightray/browser/brightray_paths.h"
#include "brightray/browser/inspectable_web_contents_impl.h"
#include "brightray/browser/zoom_level_delegate.h"
#include "brightray/common/application_info.h"
#include "chrome/common/chrome_paths.h"
@ -152,7 +152,7 @@ void AtomBrowserContext::InitPrefs() {
registry->RegisterFilePathPref(prefs::kDownloadDefaultDirectory,
download_dir);
registry->RegisterDictionaryPref(prefs::kDevToolsFileSystemPaths);
brightray::InspectableWebContentsImpl::RegisterPrefs(registry.get());
InspectableWebContentsImpl::RegisterPrefs(registry.get());
brightray::MediaDeviceIDSalt::RegisterPrefs(registry.get());
brightray::ZoomLevelDelegate::RegisterPrefs(registry.get());
PrefProxyConfigTrackerImpl::RegisterPrefs(registry.get());

View file

@ -10,10 +10,12 @@
#include "atom/browser/api/trackable_object.h"
#include "atom/browser/atom_browser_client.h"
#include "atom/browser/atom_browser_context.h"
#include "atom/browser/atom_web_ui_controller_factory.h"
#include "atom/browser/browser.h"
#include "atom/browser/io_thread.h"
#include "atom/browser/javascript_environment.h"
#include "atom/browser/node_debugger.h"
#include "atom/browser/ui/devtools_manager_delegate.h"
#include "atom/common/api/atom_bindings.h"
#include "atom/common/asar/asar_util.h"
#include "atom/common/node_bindings.h"
@ -25,6 +27,8 @@
#include "components/net_log/chrome_net_log.h"
#include "components/net_log/net_export_file_writer.h"
#include "content/public/browser/child_process_security_policy.h"
#include "content/public/browser/web_ui_controller_factory.h"
#include "content/public/common/content_switches.h"
#include "content/public/common/result_codes.h"
#include "content/public/common/service_manager_connection.h"
#include "electron/buildflags/buildflags.h"
@ -39,14 +43,10 @@
#include "ui/events/devices/x11/touch_factory_x11.h"
#endif
#if BUILDFLAG(ENABLE_PDF_VIEWER)
#include "atom/browser/atom_web_ui_controller_factory.h"
#endif // BUILDFLAG(ENABLE_PDF_VIEWER)
#if defined(OS_MACOSX)
#include "atom/browser/ui/cocoa/views_delegate_mac.h"
#else
#include "brightray/browser/views/views_delegate.h"
#include "atom/browser/ui/views/atom_views_delegate.h"
#endif
// Must be included after all other headers.
@ -212,7 +212,7 @@ void AtomBrowserMainParts::ToolkitInitialized() {
#if defined(OS_MACOSX)
views_delegate_.reset(new ViewsDelegateMac);
#else
views_delegate_.reset(new brightray::ViewsDelegate);
views_delegate_.reset(new ViewsDelegate);
#endif
}
@ -231,12 +231,13 @@ void AtomBrowserMainParts::PreMainMessageLoopRun() {
base::Bind(&v8::Isolate::LowMemoryNotification,
base::Unretained(js_env_->isolate())));
#if BUILDFLAG(ENABLE_PDF_VIEWER)
content::WebUIControllerFactory::RegisterFactory(
AtomWebUIControllerFactory::GetInstance());
#endif // BUILDFLAG(ENABLE_PDF_VIEWER)
brightray::BrowserMainParts::PreMainMessageLoopRun();
// --remote-debugging-port
auto* command_line = base::CommandLine::ForCurrentProcess();
if (command_line->HasSwitch(switches::kRemoteDebuggingPort))
DevToolsManagerDelegate::StartHttpHandler();
#if defined(USE_X11)
libgtkui::GtkInitFromCommandLine(*base::CommandLine::ForCurrentProcess());

View file

@ -19,12 +19,6 @@
class BrowserProcess;
class IconManager;
#if defined(TOOLKIT_VIEWS)
namespace brightray {
class ViewsDelegate;
}
#endif
namespace net_log {
class ChromeNetLog;
}
@ -40,6 +34,10 @@ class NodeDebugger;
class NodeEnvironment;
class BridgeTaskRunner;
#if defined(TOOLKIT_VIEWS)
class ViewsDelegate;
#endif
#if defined(OS_MACOSX)
class ViewsDelegateMac;
#endif
@ -103,7 +101,7 @@ class AtomBrowserMainParts : public brightray::BrowserMainParts {
#if defined(OS_MACOSX)
std::unique_ptr<ViewsDelegateMac> views_delegate_;
#else
std::unique_ptr<brightray::ViewsDelegate> views_delegate_;
std::unique_ptr<ViewsDelegate> views_delegate_;
#endif
// A fake BrowserProcess object that used to feed the source code from chrome.

View file

@ -13,12 +13,20 @@
#include "atom/common/atom_constants.h"
#include "base/strings/string_split.h"
#include "base/strings/string_util.h"
#include "content/public/browser/web_contents.h"
#include "net/base/escape.h"
#endif // BUILDFLAG(ENABLE_PDF_VIEWER)
#include "atom/browser/ui/devtools_ui.h"
#include "content/public/browser/web_contents.h"
namespace atom {
namespace {
const char kChromeUIDevToolsBundledHost[] = "devtools";
} // namespace
// static
AtomWebUIControllerFactory* AtomWebUIControllerFactory::GetInstance() {
return base::Singleton<AtomWebUIControllerFactory>::get();
@ -36,6 +44,9 @@ content::WebUI::TypeID AtomWebUIControllerFactory::GetWebUIType(
return const_cast<AtomWebUIControllerFactory*>(this);
}
#endif // BUILDFLAG(ENABLE_PDF_VIEWER)
if (url.host() == kChromeUIDevToolsBundledHost) {
return const_cast<AtomWebUIControllerFactory*>(this);
}
return content::WebUI::kNoWebUI;
}
@ -78,6 +89,10 @@ AtomWebUIControllerFactory::CreateWebUIControllerForURL(content::WebUI* web_ui,
return new PdfViewerUI(browser_context, web_ui, src);
}
#endif // BUILDFLAG(ENABLE_PDF_VIEWER)
if (url.host() == kChromeUIDevToolsBundledHost) {
auto* browser_context = web_ui->GetWebContents()->GetBrowserContext();
return std::make_unique<DevToolsUI>(browser_context, web_ui);
}
return std::unique_ptr<content::WebUIController>();
}

View file

@ -188,7 +188,7 @@ void CommonWebContentsDelegate::InitWithWebContents(
!web_preferences || web_preferences->IsEnabled(options::kOffscreen);
// Create InspectableWebContents.
web_contents_.reset(brightray::InspectableWebContents::Create(
web_contents_.reset(InspectableWebContents::Create(
web_contents, browser_context->prefs(), is_guest));
web_contents_->SetDelegate(this);
}
@ -229,11 +229,12 @@ void CommonWebContentsDelegate::ResetManagedWebContents(bool async) {
// is required to get the right quit closure for the main message loop.
base::ThreadTaskRunnerHandle::Get()->PostNonNestableTask(
FROM_HERE,
base::BindOnce([](scoped_refptr<AtomBrowserContext> browser_context,
std::unique_ptr<brightray::InspectableWebContents>
web_contents) { web_contents.reset(); },
base::RetainedRef(browser_context_),
std::move(web_contents_)));
base::BindOnce(
[](scoped_refptr<AtomBrowserContext> browser_context,
std::unique_ptr<InspectableWebContents> web_contents) {
web_contents.reset();
},
base::RetainedRef(browser_context_), std::move(web_contents_)));
} else {
web_contents_.reset();
}

View file

@ -10,10 +10,10 @@
#include <string>
#include <vector>
#include "atom/browser/ui/inspectable_web_contents_delegate.h"
#include "atom/browser/ui/inspectable_web_contents_impl.h"
#include "atom/browser/ui/inspectable_web_contents_view_delegate.h"
#include "base/memory/weak_ptr.h"
#include "brightray/browser/inspectable_web_contents_delegate.h"
#include "brightray/browser/inspectable_web_contents_impl.h"
#include "brightray/browser/inspectable_web_contents_view_delegate.h"
#include "chrome/browser/devtools/devtools_file_system_indexer.h"
#include "content/public/browser/web_contents_delegate.h"
#include "electron/buildflags/buildflags.h"
@ -36,10 +36,9 @@ class WebDialogHelper;
class OffScreenRenderWidgetHostView;
#endif
class CommonWebContentsDelegate
: public content::WebContentsDelegate,
public brightray::InspectableWebContentsDelegate,
public brightray::InspectableWebContentsViewDelegate {
class CommonWebContentsDelegate : public content::WebContentsDelegate,
public InspectableWebContentsDelegate,
public InspectableWebContentsViewDelegate {
public:
CommonWebContentsDelegate();
~CommonWebContentsDelegate() override;
@ -61,7 +60,7 @@ class CommonWebContentsDelegate
// Returns the WebContents of devtools.
content::WebContents* GetDevToolsWebContents() const;
brightray::InspectableWebContents* managed_web_contents() const {
InspectableWebContents* managed_web_contents() const {
return web_contents_.get();
}
@ -115,7 +114,7 @@ class CommonWebContentsDelegate
void HideAutofillPopup();
#endif
// brightray::InspectableWebContentsDelegate:
// InspectableWebContentsDelegate:
void DevToolsSaveToFile(const std::string& url,
const std::string& content,
bool save_as) override;
@ -134,7 +133,7 @@ class CommonWebContentsDelegate
const std::string& file_system_path,
const std::string& query) override;
// brightray::InspectableWebContentsViewDelegate:
// InspectableWebContentsViewDelegate:
#if defined(TOOLKIT_VIEWS) && !defined(OS_MACOSX)
gfx::ImageSkia GetDevToolsWindowIcon() override;
#endif
@ -189,7 +188,7 @@ class CommonWebContentsDelegate
// Notice that web_contents_ must be placed after dialog_manager_, so we can
// make sure web_contents_ is destroyed before dialog_manager_, otherwise a
// crash would happen.
std::unique_ptr<brightray::InspectableWebContents> web_contents_;
std::unique_ptr<InspectableWebContents> web_contents_;
// Maps url to file path, used by the file requests sent from devtools.
typedef std::map<std::string, base::FilePath> PathsMap;

View file

@ -6,8 +6,8 @@
#import <Cocoa/Cocoa.h>
#include "atom/browser/ui/cocoa/event_dispatching_window.h"
#include "atom/browser/web_contents_preferences.h"
#include "brightray/browser/mac/event_dispatching_window.h"
#include "content/public/browser/native_web_keyboard_event.h"
#include "ui/events/keycodes/keyboard_codes.h"

View file

@ -7,18 +7,17 @@
#include "atom/browser/native_browser_view.h"
#include "atom/browser/api/atom_api_web_contents.h"
#include "brightray/browser/inspectable_web_contents.h"
#include "atom/browser/ui/inspectable_web_contents.h"
namespace atom {
NativeBrowserView::NativeBrowserView(
brightray::InspectableWebContents* inspectable_web_contents)
InspectableWebContents* inspectable_web_contents)
: inspectable_web_contents_(inspectable_web_contents) {}
NativeBrowserView::~NativeBrowserView() {}
brightray::InspectableWebContentsView*
NativeBrowserView::GetInspectableWebContentsView() {
InspectableWebContentsView* NativeBrowserView::GetInspectableWebContentsView() {
return inspectable_web_contents_->GetView();
}

View file

@ -12,11 +12,6 @@
#include "content/public/browser/web_contents.h"
#include "third_party/skia/include/core/SkColor.h"
namespace brightray {
class InspectableWebContents;
class InspectableWebContentsView;
} // namespace brightray
namespace gfx {
class Rect;
}
@ -28,18 +23,21 @@ enum AutoResizeFlags {
kAutoResizeHeight = 0x2,
};
class InspectableWebContents;
class InspectableWebContentsView;
class NativeBrowserView {
public:
virtual ~NativeBrowserView();
static NativeBrowserView* Create(
brightray::InspectableWebContents* inspectable_web_contents);
InspectableWebContents* inspectable_web_contents);
brightray::InspectableWebContents* GetInspectableWebContents() {
InspectableWebContents* GetInspectableWebContents() {
return inspectable_web_contents_;
}
brightray::InspectableWebContentsView* GetInspectableWebContentsView();
InspectableWebContentsView* GetInspectableWebContentsView();
content::WebContents* GetWebContents();
virtual void SetAutoResizeFlags(uint8_t flags) = 0;
@ -51,10 +49,9 @@ class NativeBrowserView {
const std::vector<gfx::Rect>& system_drag_exclude_areas) {}
protected:
explicit NativeBrowserView(
brightray::InspectableWebContents* inspectable_web_contents);
explicit NativeBrowserView(InspectableWebContents* inspectable_web_contents);
brightray::InspectableWebContents* inspectable_web_contents_;
InspectableWebContents* inspectable_web_contents_;
private:
DISALLOW_COPY_AND_ASSIGN(NativeBrowserView);

View file

@ -17,7 +17,7 @@ namespace atom {
class NativeBrowserViewMac : public NativeBrowserView {
public:
explicit NativeBrowserViewMac(
brightray::InspectableWebContents* inspectable_web_contents);
InspectableWebContents* inspectable_web_contents);
~NativeBrowserViewMac() override;
void SetAutoResizeFlags(uint8_t flags) override;

View file

@ -4,8 +4,8 @@
#include "atom/browser/native_browser_view_mac.h"
#include "brightray/browser/inspectable_web_contents.h"
#include "brightray/browser/inspectable_web_contents_view.h"
#include "atom/browser/ui/inspectable_web_contents.h"
#include "atom/browser/ui/inspectable_web_contents_view.h"
#include "skia/ext/skia_utils_mac.h"
#include "ui/gfx/geometry/rect.h"
@ -158,7 +158,7 @@ const NSAutoresizingMaskOptions kDefaultAutoResizingMask =
namespace atom {
NativeBrowserViewMac::NativeBrowserViewMac(
brightray::InspectableWebContents* inspectable_web_contents)
InspectableWebContents* inspectable_web_contents)
: NativeBrowserView(inspectable_web_contents) {
auto* view = GetInspectableWebContentsView()->GetNativeView();
view.autoresizingMask = kDefaultAutoResizingMask;
@ -233,7 +233,7 @@ void NativeBrowserViewMac::UpdateDraggableRegions(
// static
NativeBrowserView* NativeBrowserView::Create(
brightray::InspectableWebContents* inspectable_web_contents) {
InspectableWebContents* inspectable_web_contents) {
return new NativeBrowserViewMac(inspectable_web_contents);
}

View file

@ -4,7 +4,7 @@
#include "atom/browser/native_browser_view_views.h"
#include "brightray/browser/inspectable_web_contents_view.h"
#include "atom/browser/ui/inspectable_web_contents_view.h"
#include "ui/gfx/geometry/rect.h"
#include "ui/views/background.h"
#include "ui/views/view.h"
@ -12,7 +12,7 @@
namespace atom {
NativeBrowserViewViews::NativeBrowserViewViews(
brightray::InspectableWebContents* inspectable_web_contents)
InspectableWebContents* inspectable_web_contents)
: NativeBrowserView(inspectable_web_contents) {}
NativeBrowserViewViews::~NativeBrowserViewViews() {}
@ -33,7 +33,7 @@ void NativeBrowserViewViews::SetBackgroundColor(SkColor color) {
// static
NativeBrowserView* NativeBrowserView::Create(
brightray::InspectableWebContents* inspectable_web_contents) {
InspectableWebContents* inspectable_web_contents) {
return new NativeBrowserViewViews(inspectable_web_contents);
}

View file

@ -12,7 +12,7 @@ namespace atom {
class NativeBrowserViewViews : public NativeBrowserView {
public:
explicit NativeBrowserViewViews(
brightray::InspectableWebContents* inspectable_web_contents);
InspectableWebContents* inspectable_web_contents);
~NativeBrowserViewViews() override;
uint8_t GetAutoResizeFlags() { return auto_resize_flags_; }

View file

@ -16,13 +16,13 @@
#include "atom/browser/ui/cocoa/atom_preview_item.h"
#include "atom/browser/ui/cocoa/atom_touch_bar.h"
#include "atom/browser/ui/cocoa/root_view_mac.h"
#include "atom/browser/ui/inspectable_web_contents.h"
#include "atom/browser/ui/inspectable_web_contents_view.h"
#include "atom/browser/window_list.h"
#include "atom/common/options_switches.h"
#include "base/mac/mac_util.h"
#include "base/mac/scoped_cftyperef.h"
#include "base/strings/sys_string_conversions.h"
#include "brightray/browser/inspectable_web_contents.h"
#include "brightray/browser/inspectable_web_contents_view.h"
#include "content/public/browser/browser_accessibility_state.h"
#include "native_mate/dictionary.h"
#include "skia/ext/skia_utils_mac.h"

View file

@ -15,6 +15,8 @@
#include "atom/browser/api/atom_api_web_contents.h"
#include "atom/browser/native_browser_view_views.h"
#include "atom/browser/ui/inspectable_web_contents.h"
#include "atom/browser/ui/inspectable_web_contents_view.h"
#include "atom/browser/ui/views/root_view.h"
#include "atom/browser/web_contents_preferences.h"
#include "atom/browser/web_view_manager.h"
@ -23,8 +25,6 @@
#include "atom/common/native_mate_converters/image_converter.h"
#include "atom/common/options_switches.h"
#include "base/strings/utf_string_conversions.h"
#include "brightray/browser/inspectable_web_contents.h"
#include "brightray/browser/inspectable_web_contents_view.h"
#include "content/public/browser/browser_thread.h"
#include "native_mate/dictionary.h"
#include "ui/aura/window_tree_host.h"

View file

@ -0,0 +1,47 @@
// 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.
#ifndef ATOM_BROWSER_UI_COCOA_BRY_INSPECTABLE_WEB_CONTENTS_VIEW_H_
#define ATOM_BROWSER_UI_COCOA_BRY_INSPECTABLE_WEB_CONTENTS_VIEW_H_
#import <AppKit/AppKit.h>
#include "base/mac/scoped_nsobject.h"
#include "chrome/browser/devtools/devtools_contents_resizing_strategy.h"
#include "ui/base/cocoa/base_view.h"
namespace atom {
class InspectableWebContentsViewMac;
}
using atom::InspectableWebContentsViewMac;
@interface AtomInspectableWebContentsView : BaseView <NSWindowDelegate> {
@private
atom::InspectableWebContentsViewMac* inspectableWebContentsView_;
base::scoped_nsobject<NSView> fake_view_;
base::scoped_nsobject<NSWindow> devtools_window_;
BOOL devtools_visible_;
BOOL devtools_docked_;
BOOL devtools_is_first_responder_;
DevToolsContentsResizingStrategy strategy_;
}
- (instancetype)initWithInspectableWebContentsViewMac:
(InspectableWebContentsViewMac*)view;
- (void)removeObservers;
- (void)notifyDevToolsFocused;
- (void)setDevToolsVisible:(BOOL)visible;
- (BOOL)isDevToolsVisible;
- (BOOL)isDevToolsFocused;
- (void)setIsDocked:(BOOL)docked;
- (void)setContentsResizingStrategy:
(const DevToolsContentsResizingStrategy&)strategy;
- (void)setTitle:(NSString*)title;
@end
#endif // ATOM_BROWSER_UI_COCOA_BRY_INSPECTABLE_WEB_CONTENTS_VIEW_H_

View file

@ -0,0 +1,273 @@
// 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 "atom/browser/ui/cocoa/atom_inspectable_web_contents_view.h"
#include "atom/browser/ui/cocoa/event_dispatching_window.h"
#include "atom/browser/ui/inspectable_web_contents_impl.h"
#include "atom/browser/ui/inspectable_web_contents_view_delegate.h"
#include "atom/browser/ui/inspectable_web_contents_view_mac.h"
#include "content/public/browser/render_widget_host_view.h"
#include "ui/gfx/mac/scoped_cocoa_disable_screen_updates.h"
@implementation AtomInspectableWebContentsView
- (instancetype)initWithInspectableWebContentsViewMac:
(InspectableWebContentsViewMac*)view {
self = [super init];
if (!self)
return nil;
inspectableWebContentsView_ = view;
devtools_visible_ = NO;
devtools_docked_ = NO;
devtools_is_first_responder_ = NO;
[[NSNotificationCenter defaultCenter]
addObserver:self
selector:@selector(viewDidBecomeFirstResponder:)
name:kViewDidBecomeFirstResponder
object:nil];
[[NSNotificationCenter defaultCenter]
addObserver:self
selector:@selector(parentWindowBecameMain:)
name:NSWindowDidBecomeMainNotification
object:nil];
if (inspectableWebContentsView_->inspectable_web_contents()->IsGuest()) {
fake_view_.reset([[NSView alloc] init]);
[fake_view_ setAutoresizingMask:NSViewWidthSizable | NSViewHeightSizable];
[self addSubview:fake_view_];
} else {
auto* contents = inspectableWebContentsView_->inspectable_web_contents()
->GetWebContents();
auto contentsView = contents->GetNativeView();
[contentsView setAutoresizingMask:NSViewWidthSizable | NSViewHeightSizable];
[self addSubview:contentsView];
}
// See https://code.google.com/p/chromium/issues/detail?id=348490.
[self setWantsLayer:YES];
return self;
}
- (void)removeObservers {
[[NSNotificationCenter defaultCenter] removeObserver:self];
}
- (void)resizeSubviewsWithOldSize:(NSSize)oldBoundsSize {
[self adjustSubviews];
}
- (IBAction)showDevTools:(id)sender {
inspectableWebContentsView_->inspectable_web_contents()->ShowDevTools();
}
- (void)notifyDevToolsFocused {
if (inspectableWebContentsView_->GetDelegate())
inspectableWebContentsView_->GetDelegate()->DevToolsFocused();
}
- (void)setDevToolsVisible:(BOOL)visible {
if (visible == devtools_visible_)
return;
auto* inspectable_web_contents =
inspectableWebContentsView_->inspectable_web_contents();
auto* webContents = inspectable_web_contents->GetWebContents();
auto* devToolsWebContents =
inspectable_web_contents->GetDevToolsWebContents();
auto devToolsView = devToolsWebContents->GetNativeView();
if (visible && devtools_docked_) {
webContents->SetAllowOtherViews(true);
devToolsWebContents->SetAllowOtherViews(true);
} else if (!inspectable_web_contents->IsGuest()) {
webContents->SetAllowOtherViews(false);
}
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];
}
} else {
if (visible) {
[devtools_window_ makeKeyAndOrderFront:nil];
} else {
[devtools_window_ setDelegate:nil];
[devtools_window_ close];
devtools_window_.reset();
}
}
}
- (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 {
// Revert to no-devtools state.
[self setDevToolsVisible:NO];
// Switch to new state.
devtools_docked_ = docked;
if (!docked) {
auto* inspectable_web_contents =
inspectableWebContentsView_->inspectable_web_contents();
auto* devToolsWebContents =
inspectable_web_contents->GetDevToolsWebContents();
auto devToolsView = devToolsWebContents->GetNativeView();
auto styleMask = NSWindowStyleMaskTitled | NSWindowStyleMaskClosable |
NSMiniaturizableWindowMask | NSWindowStyleMaskResizable |
NSTexturedBackgroundWindowMask |
NSWindowStyleMaskUnifiedTitleAndToolbar;
devtools_window_.reset([[EventDispatchingWindow alloc]
initWithContentRect:NSMakeRect(0, 0, 800, 600)
styleMask:styleMask
backing:NSBackingStoreBuffered
defer:YES]);
[devtools_window_ setDelegate:self];
[devtools_window_ setFrameAutosaveName:@"brightray.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];
}
[self setDevToolsVisible:YES];
}
- (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]];
}
- (void)setTitle:(NSString*)title {
[devtools_window_ setTitle:title];
}
- (void)viewDidBecomeFirstResponder:(NSNotification*)notification {
auto* inspectable_web_contents =
inspectableWebContentsView_->inspectable_web_contents();
if (!inspectable_web_contents || inspectable_web_contents->IsGuest())
return;
auto* webContents = inspectable_web_contents->GetWebContents();
auto webContentsView = webContents->GetNativeView();
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();
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];
}
#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

View file

@ -5,7 +5,7 @@
#ifndef ATOM_BROWSER_UI_COCOA_ATOM_NS_WINDOW_H_
#define ATOM_BROWSER_UI_COCOA_ATOM_NS_WINDOW_H_
#include "brightray/browser/mac/event_dispatching_window.h"
#include "atom/browser/ui/cocoa/event_dispatching_window.h"
#include "ui/views/cocoa/native_widget_mac_nswindow.h"
#include "ui/views/widget/native_widget_mac.h"

View file

@ -0,0 +1,19 @@
// Copyright (c) 2016 GitHub, Inc.
// Use of this source code is governed by the MIT license that can be
// found in the LICENSE file.
#ifndef ATOM_BROWSER_UI_COCOA_EVENT_DISPATCHING_WINDOW_H_
#define ATOM_BROWSER_UI_COCOA_EVENT_DISPATCHING_WINDOW_H_
#import "ui/base/cocoa/underlay_opengl_hosting_window.h"
@interface EventDispatchingWindow : UnderlayOpenGLHostingWindow {
@private
BOOL redispatchingEvent_;
}
- (void)redispatchKeyEvent:(NSEvent*)event;
@end
#endif // ATOM_BROWSER_UI_COCOA_EVENT_DISPATCHING_WINDOW_H_

View file

@ -0,0 +1,34 @@
// Copyright (c) 2016 GitHub, Inc.
// Use of this source code is governed by the MIT license that can be
// found in the LICENSE file.
#include "atom/browser/ui/cocoa/event_dispatching_window.h"
@implementation EventDispatchingWindow
- (void)sendEvent:(NSEvent*)event {
if (!redispatchingEvent_)
[super sendEvent:event];
}
- (BOOL)performKeyEquivalent:(NSEvent*)event {
if (redispatchingEvent_)
return NO;
else
return [super performKeyEquivalent:event];
}
- (void)redispatchKeyEvent:(NSEvent*)event {
NSEventType eventType = [event type];
if (eventType != NSKeyDown && eventType != NSKeyUp &&
eventType != NSFlagsChanged) {
return;
}
// Redispatch the event.
redispatchingEvent_ = YES;
[NSApp sendEvent:event];
redispatchingEvent_ = NO;
}
@end

View file

@ -0,0 +1,119 @@
// 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 "atom/browser/ui/devtools_manager_delegate.h"
#include <memory>
#include <vector>
#include "base/bind.h"
#include "base/command_line.h"
#include "base/files/file_path.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/stringprintf.h"
#include "base/strings/utf_string_conversions.h"
#include "brightray/common/content_client.h"
#include "content/public/browser/devtools_agent_host.h"
#include "content/public/browser/devtools_frontend_host.h"
#include "content/public/browser/devtools_socket_factory.h"
#include "content/public/browser/favicon_status.h"
#include "content/public/browser/navigation_entry.h"
#include "content/public/common/content_switches.h"
#include "content/public/common/url_constants.h"
#include "content/public/common/user_agent.h"
#include "content/shell/grit/shell_resources.h"
#include "net/base/net_errors.h"
#include "net/socket/stream_socket.h"
#include "net/socket/tcp_server_socket.h"
#include "ui/base/resource/resource_bundle.h"
namespace atom {
namespace {
class TCPServerSocketFactory : public content::DevToolsSocketFactory {
public:
TCPServerSocketFactory(const std::string& address, int port)
: address_(address), port_(port) {}
private:
// content::ServerSocketFactory.
std::unique_ptr<net::ServerSocket> CreateForHttpServer() override {
std::unique_ptr<net::ServerSocket> socket(
new net::TCPServerSocket(nullptr, net::NetLogSource()));
if (socket->ListenWithAddressAndPort(address_, port_, 10) != net::OK)
return std::unique_ptr<net::ServerSocket>();
return socket;
}
std::unique_ptr<net::ServerSocket> CreateForTethering(
std::string* name) override {
return std::unique_ptr<net::ServerSocket>();
}
std::string address_;
uint16_t port_;
DISALLOW_COPY_AND_ASSIGN(TCPServerSocketFactory);
};
std::unique_ptr<content::DevToolsSocketFactory> CreateSocketFactory() {
auto& command_line = *base::CommandLine::ForCurrentProcess();
// See if the user specified a port on the command line (useful for
// automation). If not, use an ephemeral port by specifying 0.
int port = 0;
if (command_line.HasSwitch(switches::kRemoteDebuggingPort)) {
int temp_port;
std::string port_str =
command_line.GetSwitchValueASCII(switches::kRemoteDebuggingPort);
if (base::StringToInt(port_str, &temp_port) && temp_port > 0 &&
temp_port < 65535) {
port = temp_port;
} else {
DLOG(WARNING) << "Invalid http debugger port number " << temp_port;
}
}
return std::unique_ptr<content::DevToolsSocketFactory>(
new TCPServerSocketFactory("127.0.0.1", port));
}
} // namespace
// DevToolsManagerDelegate ---------------------------------------------------
// static
void DevToolsManagerDelegate::StartHttpHandler() {
content::DevToolsAgentHost::StartRemoteDebuggingServer(
CreateSocketFactory(), base::FilePath(), base::FilePath());
}
DevToolsManagerDelegate::DevToolsManagerDelegate() {}
DevToolsManagerDelegate::~DevToolsManagerDelegate() {}
void DevToolsManagerDelegate::Inspect(content::DevToolsAgentHost* agent_host) {}
bool DevToolsManagerDelegate::HandleCommand(
content::DevToolsAgentHost* agent_host,
content::DevToolsAgentHostClient* client,
base::DictionaryValue* command) {
return false;
}
scoped_refptr<content::DevToolsAgentHost>
DevToolsManagerDelegate::CreateNewTarget(const GURL& url) {
return nullptr;
}
std::string DevToolsManagerDelegate::GetDiscoveryPageHTML() {
return ui::ResourceBundle::GetSharedInstance()
.GetRawDataResource(IDR_CONTENT_SHELL_DEVTOOLS_DISCOVERY_PAGE)
.as_string();
}
bool DevToolsManagerDelegate::HasBundledFrontendResources() {
return true;
}
} // namespace atom

View file

@ -0,0 +1,39 @@
// 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.
#ifndef ATOM_BROWSER_UI_DEVTOOLS_MANAGER_DELEGATE_H_
#define ATOM_BROWSER_UI_DEVTOOLS_MANAGER_DELEGATE_H_
#include <string>
#include "base/compiler_specific.h"
#include "base/macros.h"
#include "content/public/browser/devtools_manager_delegate.h"
namespace atom {
class DevToolsManagerDelegate : public content::DevToolsManagerDelegate {
public:
static void StartHttpHandler();
DevToolsManagerDelegate();
~DevToolsManagerDelegate() override;
// DevToolsManagerDelegate implementation.
void Inspect(content::DevToolsAgentHost* agent_host) override;
bool HandleCommand(content::DevToolsAgentHost* agent_host,
content::DevToolsAgentHostClient* client,
base::DictionaryValue* command) override;
scoped_refptr<content::DevToolsAgentHost> CreateNewTarget(
const GURL& url) override;
std::string GetDiscoveryPageHTML() override;
bool HasBundledFrontendResources() override;
private:
DISALLOW_COPY_AND_ASSIGN(DevToolsManagerDelegate);
};
} // namespace atom
#endif // ATOM_BROWSER_UI_DEVTOOLS_MANAGER_DELEGATE_H_

View file

@ -0,0 +1,120 @@
// Copyright (c) 2012 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 "atom/browser/ui/devtools_ui.h"
#include <string>
#include "base/memory/ref_counted_memory.h"
#include "base/strings/string_util.h"
#include "base/strings/stringprintf.h"
#include "content/public/browser/devtools_frontend_host.h"
#include "content/public/browser/url_data_source.h"
#include "content/public/browser/web_contents.h"
#include "content/public/browser/web_ui.h"
namespace atom {
namespace {
const char kChromeUIDevToolsHost[] = "devtools";
const char kChromeUIDevToolsBundledPath[] = "bundled";
std::string PathWithoutParams(const std::string& path) {
return GURL(std::string("chrome-devtools://devtools/") + path)
.path()
.substr(1);
}
std::string GetMimeTypeForPath(const std::string& path) {
std::string filename = PathWithoutParams(path);
if (base::EndsWith(filename, ".html", base::CompareCase::INSENSITIVE_ASCII)) {
return "text/html";
} else if (base::EndsWith(filename, ".css",
base::CompareCase::INSENSITIVE_ASCII)) {
return "text/css";
} else if (base::EndsWith(filename, ".js",
base::CompareCase::INSENSITIVE_ASCII)) {
return "application/javascript";
} else if (base::EndsWith(filename, ".png",
base::CompareCase::INSENSITIVE_ASCII)) {
return "image/png";
} else if (base::EndsWith(filename, ".gif",
base::CompareCase::INSENSITIVE_ASCII)) {
return "image/gif";
} else if (base::EndsWith(filename, ".svg",
base::CompareCase::INSENSITIVE_ASCII)) {
return "image/svg+xml";
} else if (base::EndsWith(filename, ".manifest",
base::CompareCase::INSENSITIVE_ASCII)) {
return "text/cache-manifest";
}
return "text/html";
}
class BundledDataSource : public content::URLDataSource {
public:
BundledDataSource() {}
// content::URLDataSource implementation.
std::string GetSource() const override { return kChromeUIDevToolsHost; }
void StartDataRequest(
const std::string& path,
const content::ResourceRequestInfo::WebContentsGetter& wc_getter,
const GotDataCallback& callback) override {
// Serve request from local bundle.
std::string bundled_path_prefix(kChromeUIDevToolsBundledPath);
bundled_path_prefix += "/";
if (base::StartsWith(path, bundled_path_prefix,
base::CompareCase::INSENSITIVE_ASCII)) {
StartBundledDataRequest(path.substr(bundled_path_prefix.length()),
callback);
return;
}
// We do not handle remote and custom requests.
callback.Run(nullptr);
}
std::string GetMimeType(const std::string& path) const override {
return GetMimeTypeForPath(path);
}
bool ShouldAddContentSecurityPolicy() const override { return false; }
bool ShouldDenyXFrameOptions() const override { return false; }
bool ShouldServeMimeTypeAsContentTypeHeader() const override { return true; }
void StartBundledDataRequest(const std::string& path,
const GotDataCallback& callback) {
std::string filename = PathWithoutParams(path);
base::StringPiece resource =
content::DevToolsFrontendHost::GetFrontendResource(filename);
DLOG_IF(WARNING, resource.empty())
<< "Unable to find dev tool resource: " << filename
<< ". If you compiled with debug_devtools=1, try running with "
"--debug-devtools.";
scoped_refptr<base::RefCountedStaticMemory> bytes(
new base::RefCountedStaticMemory(resource.data(), resource.length()));
callback.Run(bytes.get());
}
private:
~BundledDataSource() override {}
DISALLOW_COPY_AND_ASSIGN(BundledDataSource);
};
} // namespace
DevToolsUI::DevToolsUI(content::BrowserContext* browser_context,
content::WebUI* web_ui)
: WebUIController(web_ui) {
web_ui->SetBindings(0);
content::URLDataSource::Add(browser_context, new BundledDataSource());
}
} // namespace atom

View file

@ -0,0 +1,27 @@
// Copyright (c) 2011 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.
#ifndef ATOM_BROWSER_UI_DEVTOOLS_UI_H_
#define ATOM_BROWSER_UI_DEVTOOLS_UI_H_
#include "base/compiler_specific.h"
#include "content/public/browser/browser_context.h"
#include "content/public/browser/web_ui_controller.h"
namespace atom {
class BrowserContext;
class DevToolsUI : public content::WebUIController {
public:
explicit DevToolsUI(content::BrowserContext* browser_context,
content::WebUI* web_ui);
private:
DISALLOW_COPY_AND_ASSIGN(DevToolsUI);
};
} // namespace atom
#endif // ATOM_BROWSER_UI_DEVTOOLS_UI_H_

View file

@ -0,0 +1,19 @@
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Copyright (c) 2013 Adam Roben <adam@roben.org>. 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 "atom/browser/ui/inspectable_web_contents.h"
#include "atom/browser/ui/inspectable_web_contents_impl.h"
namespace atom {
InspectableWebContents* InspectableWebContents::Create(
content::WebContents* web_contents,
PrefService* pref_service,
bool is_guest) {
return new InspectableWebContentsImpl(web_contents, pref_service, is_guest);
}
} // namespace atom

View file

@ -0,0 +1,64 @@
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Copyright (c) 2013 Adam Roben <adam@roben.org>. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE-CHROMIUM file.
#ifndef ATOM_BROWSER_UI_INSPECTABLE_WEB_CONTENTS_H_
#define ATOM_BROWSER_UI_INSPECTABLE_WEB_CONTENTS_H_
#include <string>
#include "content/public/browser/web_contents.h"
namespace base {
class Value;
}
namespace content {
class DevToolsAgentHost;
}
class PrefService;
namespace atom {
class InspectableWebContentsDelegate;
class InspectableWebContentsView;
class InspectableWebContents {
public:
// The returned InspectableWebContents takes ownership of the passed-in
// WebContents.
static InspectableWebContents* Create(content::WebContents* web_contents,
PrefService* pref_service,
bool is_guest);
virtual ~InspectableWebContents() {}
virtual InspectableWebContentsView* GetView() const = 0;
virtual content::WebContents* GetWebContents() const = 0;
virtual content::WebContents* GetDevToolsWebContents() const = 0;
// The delegate manages its own life.
virtual void SetDelegate(InspectableWebContentsDelegate* delegate) = 0;
virtual InspectableWebContentsDelegate* GetDelegate() const = 0;
virtual bool IsGuest() const = 0;
virtual void ReleaseWebContents() = 0;
virtual void SetDevToolsWebContents(content::WebContents* devtools) = 0;
virtual void SetDockState(const std::string& state) = 0;
virtual void ShowDevTools() = 0;
virtual void CloseDevTools() = 0;
virtual bool IsDevToolsViewShowing() = 0;
virtual void AttachTo(scoped_refptr<content::DevToolsAgentHost>) = 0;
virtual void Detach() = 0;
virtual void CallClientFunction(const std::string& function_name,
const base::Value* arg1 = nullptr,
const base::Value* arg2 = nullptr,
const base::Value* arg3 = nullptr) = 0;
virtual void InspectElement(int x, int y) = 0;
};
} // namespace atom
#endif // ATOM_BROWSER_UI_INSPECTABLE_WEB_CONTENTS_H_

View file

@ -0,0 +1,42 @@
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Copyright (c) 2013 Adam Roben <adam@roben.org>. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE-CHROMIUM file.
#ifndef ATOM_BROWSER_UI_INSPECTABLE_WEB_CONTENTS_DELEGATE_H_
#define ATOM_BROWSER_UI_INSPECTABLE_WEB_CONTENTS_DELEGATE_H_
#include <string>
#include "base/files/file_path.h"
namespace atom {
class InspectableWebContentsDelegate {
public:
virtual ~InspectableWebContentsDelegate() {}
// Requested by WebContents of devtools.
virtual void DevToolsReloadPage() {}
virtual void DevToolsSaveToFile(const std::string& url,
const std::string& content,
bool save_as) {}
virtual void DevToolsAppendToFile(const std::string& url,
const std::string& content) {}
virtual void DevToolsRequestFileSystems() {}
virtual void DevToolsAddFileSystem(const std::string& type,
const base::FilePath& file_system_path) {}
virtual void DevToolsRemoveFileSystem(
const base::FilePath& file_system_path) {}
virtual void DevToolsIndexPath(int request_id,
const std::string& file_system_path,
const std::string& excluded_folders) {}
virtual void DevToolsStopIndexing(int request_id) {}
virtual void DevToolsSearchInPath(int request_id,
const std::string& file_system_path,
const std::string& query) {}
};
} // namespace atom
#endif // ATOM_BROWSER_UI_INSPECTABLE_WEB_CONTENTS_DELEGATE_H_

View file

@ -0,0 +1,897 @@
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Copyright (c) 2013 Adam Roben <adam@roben.org>. 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 <memory>
#include <utility>
#include "atom/browser/ui/inspectable_web_contents_impl.h"
#include "atom/browser/ui/inspectable_web_contents_delegate.h"
#include "atom/browser/ui/inspectable_web_contents_view.h"
#include "atom/browser/ui/inspectable_web_contents_view_delegate.h"
#include "atom/common/platform_util.h"
#include "base/guid.h"
#include "base/json/json_reader.h"
#include "base/json/json_writer.h"
#include "base/metrics/histogram.h"
#include "base/strings/pattern.h"
#include "base/strings/string_util.h"
#include "base/strings/stringprintf.h"
#include "base/strings/utf_string_conversions.h"
#include "base/values.h"
#include "components/prefs/pref_registry_simple.h"
#include "components/prefs/pref_service.h"
#include "components/prefs/scoped_user_pref_update.h"
#include "content/public/browser/browser_context.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/browser/host_zoom_map.h"
#include "content/public/browser/navigation_handle.h"
#include "content/public/browser/render_frame_host.h"
#include "content/public/browser/render_view_host.h"
#include "content/public/browser/storage_partition.h"
#include "content/public/common/user_agent.h"
#include "ipc/ipc_channel.h"
#include "net/base/io_buffer.h"
#include "net/http/http_response_headers.h"
#include "net/url_request/url_fetcher.h"
#include "net/url_request/url_fetcher_response_writer.h"
#include "ui/display/display.h"
#include "ui/display/screen.h"
namespace atom {
namespace {
const double kPresetZoomFactors[] = {0.25, 0.333, 0.5, 0.666, 0.75, 0.9,
1.0, 1.1, 1.25, 1.5, 1.75, 2.0,
2.5, 3.0, 4.0, 5.0};
const char kChromeUIDevToolsURL[] =
"chrome-devtools://devtools/bundled/devtools_app.html?"
"remoteBase=%s&"
"can_dock=%s&"
"toolbarColor=rgba(223,223,223,1)&"
"textColor=rgba(0,0,0,1)&"
"experiments=true";
const char kChromeUIDevToolsRemoteFrontendBase[] =
"https://chrome-devtools-frontend.appspot.com/";
const char kChromeUIDevToolsRemoteFrontendPath[] = "serve_file";
const char kDevToolsBoundsPref[] = "brightray.devtools.bounds";
const char kDevToolsZoomPref[] = "brightray.devtools.zoom";
const char kDevToolsPreferences[] = "brightray.devtools.preferences";
const char kFrontendHostId[] = "id";
const char kFrontendHostMethod[] = "method";
const char kFrontendHostParams[] = "params";
const char kTitleFormat[] = "Developer Tools - %s";
const size_t kMaxMessageChunkSize = IPC::Channel::kMaximumMessageSize / 4;
void RectToDictionary(const gfx::Rect& bounds, base::DictionaryValue* dict) {
dict->SetInteger("x", bounds.x());
dict->SetInteger("y", bounds.y());
dict->SetInteger("width", bounds.width());
dict->SetInteger("height", bounds.height());
}
void DictionaryToRect(const base::DictionaryValue& dict, gfx::Rect* bounds) {
int x = 0, y = 0, width = 800, height = 600;
dict.GetInteger("x", &x);
dict.GetInteger("y", &y);
dict.GetInteger("width", &width);
dict.GetInteger("height", &height);
*bounds = gfx::Rect(x, y, width, height);
}
bool IsPointInRect(const gfx::Point& point, const gfx::Rect& rect) {
return point.x() > rect.x() && point.x() < (rect.width() + rect.x()) &&
point.y() > rect.y() && point.y() < (rect.height() + rect.y());
}
bool IsPointInScreen(const gfx::Point& point) {
for (const auto& display : display::Screen::GetScreen()->GetAllDisplays()) {
if (IsPointInRect(point, display.bounds()))
return true;
}
return false;
}
void SetZoomLevelForWebContents(content::WebContents* web_contents,
double level) {
content::HostZoomMap::SetZoomLevel(web_contents, level);
}
double GetNextZoomLevel(double level, bool out) {
double factor = content::ZoomLevelToZoomFactor(level);
size_t size = arraysize(kPresetZoomFactors);
for (size_t i = 0; i < size; ++i) {
if (!content::ZoomValuesEqual(kPresetZoomFactors[i], factor))
continue;
if (out && i > 0)
return content::ZoomFactorToZoomLevel(kPresetZoomFactors[i - 1]);
if (!out && i != size - 1)
return content::ZoomFactorToZoomLevel(kPresetZoomFactors[i + 1]);
}
return level;
}
GURL GetRemoteBaseURL() {
return GURL(base::StringPrintf("%s%s/%s/",
kChromeUIDevToolsRemoteFrontendBase,
kChromeUIDevToolsRemoteFrontendPath,
content::GetWebKitRevision().c_str()));
}
GURL GetDevToolsURL(bool can_dock) {
auto url_string = base::StringPrintf(kChromeUIDevToolsURL,
GetRemoteBaseURL().spec().c_str(),
can_dock ? "true" : "");
return GURL(url_string);
}
// ResponseWriter -------------------------------------------------------------
class ResponseWriter : public net::URLFetcherResponseWriter {
public:
ResponseWriter(base::WeakPtr<InspectableWebContentsImpl> bindings,
int stream_id);
~ResponseWriter() override;
// URLFetcherResponseWriter overrides:
int Initialize(const net::CompletionCallback& callback) override;
int Write(net::IOBuffer* buffer,
int num_bytes,
const net::CompletionCallback& callback) override;
int Finish(int net_error, const net::CompletionCallback& callback) override;
private:
base::WeakPtr<InspectableWebContentsImpl> bindings_;
int stream_id_;
DISALLOW_COPY_AND_ASSIGN(ResponseWriter);
};
ResponseWriter::ResponseWriter(
base::WeakPtr<InspectableWebContentsImpl> bindings,
int stream_id)
: bindings_(bindings), stream_id_(stream_id) {}
ResponseWriter::~ResponseWriter() {}
int ResponseWriter::Initialize(const net::CompletionCallback& callback) {
return net::OK;
}
int ResponseWriter::Write(net::IOBuffer* buffer,
int num_bytes,
const net::CompletionCallback& callback) {
std::string chunk = std::string(buffer->data(), num_bytes);
if (!base::IsStringUTF8(chunk))
return num_bytes;
base::Value* id = new base::Value(stream_id_);
base::Value* chunk_value = new base::Value(chunk);
content::BrowserThread::PostTask(
content::BrowserThread::UI, FROM_HERE,
base::BindOnce(&InspectableWebContentsImpl::CallClientFunction, bindings_,
"DevToolsAPI.streamWrite", base::Owned(id),
base::Owned(chunk_value), nullptr));
return num_bytes;
}
int ResponseWriter::Finish(int net_error,
const net::CompletionCallback& callback) {
return net::OK;
}
} // namespace
// Implemented separately on each platform.
InspectableWebContentsView* CreateInspectableContentsView(
InspectableWebContentsImpl* inspectable_web_contents_impl);
void InspectableWebContentsImpl::RegisterPrefs(PrefRegistrySimple* registry) {
std::unique_ptr<base::DictionaryValue> bounds_dict(new base::DictionaryValue);
RectToDictionary(gfx::Rect(0, 0, 800, 600), bounds_dict.get());
registry->RegisterDictionaryPref(kDevToolsBoundsPref, std::move(bounds_dict));
registry->RegisterDoublePref(kDevToolsZoomPref, 0.);
registry->RegisterDictionaryPref(kDevToolsPreferences);
}
InspectableWebContentsImpl::InspectableWebContentsImpl(
content::WebContents* web_contents,
PrefService* pref_service,
bool is_guest)
: frontend_loaded_(false),
can_dock_(true),
delegate_(nullptr),
pref_service_(pref_service),
web_contents_(web_contents),
is_guest_(is_guest),
view_(CreateInspectableContentsView(this)),
weak_factory_(this) {
auto* bounds_dict = pref_service_->GetDictionary(kDevToolsBoundsPref);
if (bounds_dict) {
DictionaryToRect(*bounds_dict, &devtools_bounds_);
// Sometimes the devtools window is out of screen or has too small size.
if (devtools_bounds_.height() < 100 || devtools_bounds_.width() < 100) {
devtools_bounds_.set_height(600);
devtools_bounds_.set_width(800);
}
if (!IsPointInScreen(devtools_bounds_.origin())) {
gfx::Rect display;
if (!is_guest && web_contents->GetNativeView()) {
display = display::Screen::GetScreen()
->GetDisplayNearestView(web_contents->GetNativeView())
.bounds();
} else {
display = display::Screen::GetScreen()->GetPrimaryDisplay().bounds();
}
devtools_bounds_.set_x(display.x() +
(display.width() - devtools_bounds_.width()) / 2);
devtools_bounds_.set_y(
display.y() + (display.height() - devtools_bounds_.height()) / 2);
}
}
}
InspectableWebContentsImpl::~InspectableWebContentsImpl() {
// Unsubscribe from devtools and Clean up resources.
if (GetDevToolsWebContents()) {
if (managed_devtools_web_contents_)
managed_devtools_web_contents_->SetDelegate(nullptr);
// Calling this also unsubscribes the observer, so WebContentsDestroyed
// won't be called again.
WebContentsDestroyed();
}
// Let destructor destroy managed_devtools_web_contents_.
}
InspectableWebContentsView* InspectableWebContentsImpl::GetView() const {
return view_.get();
}
content::WebContents* InspectableWebContentsImpl::GetWebContents() const {
return web_contents_.get();
}
content::WebContents* InspectableWebContentsImpl::GetDevToolsWebContents()
const {
if (external_devtools_web_contents_)
return external_devtools_web_contents_;
else
return managed_devtools_web_contents_.get();
}
void InspectableWebContentsImpl::InspectElement(int x, int y) {
if (agent_host_)
agent_host_->InspectElement(web_contents_->GetMainFrame(), x, y);
}
void InspectableWebContentsImpl::SetDelegate(
InspectableWebContentsDelegate* delegate) {
delegate_ = delegate;
}
InspectableWebContentsDelegate* InspectableWebContentsImpl::GetDelegate()
const {
return delegate_;
}
bool InspectableWebContentsImpl::IsGuest() const {
return is_guest_;
}
void InspectableWebContentsImpl::ReleaseWebContents() {
web_contents_.release();
}
void InspectableWebContentsImpl::SetDockState(const std::string& state) {
if (state == "detach") {
can_dock_ = false;
} else {
can_dock_ = true;
dock_state_ = state;
}
}
void InspectableWebContentsImpl::SetDevToolsWebContents(
content::WebContents* devtools) {
if (!managed_devtools_web_contents_)
external_devtools_web_contents_ = devtools;
}
void InspectableWebContentsImpl::ShowDevTools() {
if (embedder_message_dispatcher_) {
if (managed_devtools_web_contents_)
view_->ShowDevTools();
return;
}
// Show devtools only after it has done loading, this is to make sure the
// SetIsDocked is called *BEFORE* ShowDevTools.
embedder_message_dispatcher_.reset(
DevToolsEmbedderMessageDispatcher::CreateForDevToolsFrontend(this));
if (!external_devtools_web_contents_) { // no external devtools
managed_devtools_web_contents_ = content::WebContents::Create(
content::WebContents::CreateParams(web_contents_->GetBrowserContext()));
managed_devtools_web_contents_->SetDelegate(this);
}
Observe(GetDevToolsWebContents());
AttachTo(content::DevToolsAgentHost::GetOrCreateFor(web_contents_.get()));
GetDevToolsWebContents()->GetController().LoadURL(
GetDevToolsURL(can_dock_), content::Referrer(),
ui::PAGE_TRANSITION_AUTO_TOPLEVEL, std::string());
}
void InspectableWebContentsImpl::CloseDevTools() {
if (GetDevToolsWebContents()) {
frontend_loaded_ = false;
if (managed_devtools_web_contents_) {
view_->CloseDevTools();
managed_devtools_web_contents_.reset();
}
embedder_message_dispatcher_.reset();
if (!IsGuest())
web_contents_->Focus();
}
}
bool InspectableWebContentsImpl::IsDevToolsViewShowing() {
return managed_devtools_web_contents_ && view_->IsDevToolsViewShowing();
}
void InspectableWebContentsImpl::AttachTo(
scoped_refptr<content::DevToolsAgentHost> host) {
Detach();
agent_host_ = std::move(host);
// We could use ForceAttachClient here if problem arises with
// devtools multiple session support.
agent_host_->AttachClient(this);
}
void InspectableWebContentsImpl::Detach() {
if (agent_host_)
agent_host_->DetachClient(this);
agent_host_ = nullptr;
}
void InspectableWebContentsImpl::Reattach(const DispatchCallback& callback) {
if (agent_host_) {
agent_host_->DetachClient(this);
agent_host_->AttachClient(this);
}
callback.Run(nullptr);
}
void InspectableWebContentsImpl::CallClientFunction(
const std::string& function_name,
const base::Value* arg1,
const base::Value* arg2,
const base::Value* arg3) {
if (!GetDevToolsWebContents())
return;
std::string javascript = function_name + "(";
if (arg1) {
std::string json;
base::JSONWriter::Write(*arg1, &json);
javascript.append(json);
if (arg2) {
base::JSONWriter::Write(*arg2, &json);
javascript.append(", ").append(json);
if (arg3) {
base::JSONWriter::Write(*arg3, &json);
javascript.append(", ").append(json);
}
}
}
javascript.append(");");
GetDevToolsWebContents()->GetMainFrame()->ExecuteJavaScript(
base::UTF8ToUTF16(javascript));
}
gfx::Rect InspectableWebContentsImpl::GetDevToolsBounds() const {
return devtools_bounds_;
}
void InspectableWebContentsImpl::SaveDevToolsBounds(const gfx::Rect& bounds) {
base::DictionaryValue bounds_dict;
RectToDictionary(bounds, &bounds_dict);
pref_service_->Set(kDevToolsBoundsPref, bounds_dict);
devtools_bounds_ = bounds;
}
double InspectableWebContentsImpl::GetDevToolsZoomLevel() const {
return pref_service_->GetDouble(kDevToolsZoomPref);
}
void InspectableWebContentsImpl::UpdateDevToolsZoomLevel(double level) {
pref_service_->SetDouble(kDevToolsZoomPref, level);
}
void InspectableWebContentsImpl::ActivateWindow() {
// Set the zoom level.
SetZoomLevelForWebContents(GetDevToolsWebContents(), GetDevToolsZoomLevel());
}
void InspectableWebContentsImpl::CloseWindow() {
GetDevToolsWebContents()->DispatchBeforeUnload();
}
void InspectableWebContentsImpl::LoadCompleted() {
frontend_loaded_ = true;
if (managed_devtools_web_contents_)
view_->ShowDevTools();
// If the devtools can dock, "SetIsDocked" will be called by devtools itself.
if (!can_dock_) {
SetIsDocked(DispatchCallback(), false);
} else {
if (dock_state_.empty()) {
const base::DictionaryValue* prefs =
pref_service_->GetDictionary(kDevToolsPreferences);
std::string current_dock_state;
prefs->GetString("currentDockState", &current_dock_state);
base::RemoveChars(current_dock_state, "\"", &dock_state_);
}
base::string16 javascript = base::UTF8ToUTF16(
"Components.dockController.setDockSide(\"" + dock_state_ + "\");");
GetDevToolsWebContents()->GetMainFrame()->ExecuteJavaScript(javascript);
}
if (view_->GetDelegate())
view_->GetDelegate()->DevToolsOpened();
}
void InspectableWebContentsImpl::SetInspectedPageBounds(const gfx::Rect& rect) {
DevToolsContentsResizingStrategy strategy(rect);
if (contents_resizing_strategy_.Equals(strategy))
return;
contents_resizing_strategy_.CopyFrom(strategy);
if (managed_devtools_web_contents_)
view_->SetContentsResizingStrategy(contents_resizing_strategy_);
}
void InspectableWebContentsImpl::InspectElementCompleted() {}
void InspectableWebContentsImpl::InspectedURLChanged(const std::string& url) {
if (managed_devtools_web_contents_)
view_->SetTitle(
base::UTF8ToUTF16(base::StringPrintf(kTitleFormat, url.c_str())));
}
void InspectableWebContentsImpl::LoadNetworkResource(
const DispatchCallback& callback,
const std::string& url,
const std::string& headers,
int stream_id) {
GURL gurl(url);
if (!gurl.is_valid()) {
base::DictionaryValue response;
response.SetInteger("statusCode", 404);
callback.Run(&response);
return;
}
auto* browser_context = GetDevToolsWebContents()->GetBrowserContext();
net::URLFetcher* fetcher =
(net::URLFetcher::Create(gurl, net::URLFetcher::GET, this)).release();
pending_requests_[fetcher] = callback;
fetcher->SetRequestContext(
content::BrowserContext::GetDefaultStoragePartition(browser_context)
->GetURLRequestContext());
fetcher->SetExtraRequestHeaders(headers);
fetcher->SaveResponseWithWriter(
std::unique_ptr<net::URLFetcherResponseWriter>(
new ResponseWriter(weak_factory_.GetWeakPtr(), stream_id)));
fetcher->Start();
}
void InspectableWebContentsImpl::SetIsDocked(const DispatchCallback& callback,
bool docked) {
if (managed_devtools_web_contents_)
view_->SetIsDocked(docked);
if (!callback.is_null())
callback.Run(nullptr);
}
void InspectableWebContentsImpl::OpenInNewTab(const std::string& url) {}
void InspectableWebContentsImpl::ShowItemInFolder(
const std::string& file_system_path) {
if (file_system_path.empty())
return;
base::FilePath path = base::FilePath::FromUTF8Unsafe(file_system_path);
platform_util::ShowItemInFolder(path);
}
void InspectableWebContentsImpl::SaveToFile(const std::string& url,
const std::string& content,
bool save_as) {
if (delegate_)
delegate_->DevToolsSaveToFile(url, content, save_as);
}
void InspectableWebContentsImpl::AppendToFile(const std::string& url,
const std::string& content) {
if (delegate_)
delegate_->DevToolsAppendToFile(url, content);
}
void InspectableWebContentsImpl::RequestFileSystems() {
if (delegate_)
delegate_->DevToolsRequestFileSystems();
}
void InspectableWebContentsImpl::AddFileSystem(const std::string& type) {
if (delegate_)
delegate_->DevToolsAddFileSystem(type, base::FilePath());
}
void InspectableWebContentsImpl::RemoveFileSystem(
const std::string& file_system_path) {
if (delegate_)
delegate_->DevToolsRemoveFileSystem(
base::FilePath::FromUTF8Unsafe(file_system_path));
}
void InspectableWebContentsImpl::UpgradeDraggedFileSystemPermissions(
const std::string& file_system_url) {}
void InspectableWebContentsImpl::IndexPath(
int request_id,
const std::string& file_system_path,
const std::string& excluded_folders) {
if (delegate_)
delegate_->DevToolsIndexPath(request_id, file_system_path,
excluded_folders);
}
void InspectableWebContentsImpl::StopIndexing(int request_id) {
if (delegate_)
delegate_->DevToolsStopIndexing(request_id);
}
void InspectableWebContentsImpl::SearchInPath(
int request_id,
const std::string& file_system_path,
const std::string& query) {
if (delegate_)
delegate_->DevToolsSearchInPath(request_id, file_system_path, query);
}
void InspectableWebContentsImpl::SetWhitelistedShortcuts(
const std::string& message) {}
void InspectableWebContentsImpl::SetEyeDropperActive(bool active) {}
void InspectableWebContentsImpl::ShowCertificateViewer(
const std::string& cert_chain) {}
void InspectableWebContentsImpl::ZoomIn() {
double new_level = GetNextZoomLevel(GetDevToolsZoomLevel(), false);
SetZoomLevelForWebContents(GetDevToolsWebContents(), new_level);
UpdateDevToolsZoomLevel(new_level);
}
void InspectableWebContentsImpl::ZoomOut() {
double new_level = GetNextZoomLevel(GetDevToolsZoomLevel(), true);
SetZoomLevelForWebContents(GetDevToolsWebContents(), new_level);
UpdateDevToolsZoomLevel(new_level);
}
void InspectableWebContentsImpl::ResetZoom() {
SetZoomLevelForWebContents(GetDevToolsWebContents(), 0.);
UpdateDevToolsZoomLevel(0.);
}
void InspectableWebContentsImpl::SetDevicesDiscoveryConfig(
bool discover_usb_devices,
bool port_forwarding_enabled,
const std::string& port_forwarding_config,
bool network_discovery_enabled,
const std::string& network_discovery_config) {}
void InspectableWebContentsImpl::SetDevicesUpdatesEnabled(bool enabled) {}
void InspectableWebContentsImpl::PerformActionOnRemotePage(
const std::string& page_id,
const std::string& action) {}
void InspectableWebContentsImpl::OpenRemotePage(const std::string& browser_id,
const std::string& url) {}
void InspectableWebContentsImpl::OpenNodeFrontend() {}
void InspectableWebContentsImpl::DispatchProtocolMessageFromDevToolsFrontend(
const std::string& message) {
// If the devtools wants to reload the page, hijack the message and handle it
// to the delegate.
if (base::MatchPattern(message,
"{\"id\":*,"
"\"method\":\"Page.reload\","
"\"params\":*}")) {
if (delegate_)
delegate_->DevToolsReloadPage();
return;
}
if (agent_host_)
agent_host_->DispatchProtocolMessage(this, message);
}
void InspectableWebContentsImpl::SendJsonRequest(
const DispatchCallback& callback,
const std::string& browser_id,
const std::string& url) {
callback.Run(nullptr);
}
void InspectableWebContentsImpl::GetPreferences(
const DispatchCallback& callback) {
const base::DictionaryValue* prefs =
pref_service_->GetDictionary(kDevToolsPreferences);
callback.Run(prefs);
}
void InspectableWebContentsImpl::SetPreference(const std::string& name,
const std::string& value) {
DictionaryPrefUpdate update(pref_service_, kDevToolsPreferences);
update.Get()->SetKey(name, base::Value(value));
}
void InspectableWebContentsImpl::RemovePreference(const std::string& name) {
DictionaryPrefUpdate update(pref_service_, kDevToolsPreferences);
update.Get()->RemoveWithoutPathExpansion(name, nullptr);
}
void InspectableWebContentsImpl::ClearPreferences() {
DictionaryPrefUpdate update(pref_service_, kDevToolsPreferences);
update.Get()->Clear();
}
void InspectableWebContentsImpl::ConnectionReady() {}
void InspectableWebContentsImpl::RegisterExtensionsAPI(
const std::string& origin,
const std::string& script) {
extensions_api_[origin + "/"] = script;
}
void InspectableWebContentsImpl::HandleMessageFromDevToolsFrontend(
const std::string& message) {
// TODO(alexeykuzmin): Should we expect it to exist?
if (!embedder_message_dispatcher_) {
return;
}
std::string method;
base::ListValue empty_params;
base::ListValue* params = &empty_params;
base::DictionaryValue* dict = nullptr;
std::unique_ptr<base::Value> parsed_message(base::JSONReader::Read(message));
if (!parsed_message || !parsed_message->GetAsDictionary(&dict) ||
!dict->GetString(kFrontendHostMethod, &method) ||
(dict->HasKey(kFrontendHostParams) &&
!dict->GetList(kFrontendHostParams, &params))) {
LOG(ERROR) << "Invalid message was sent to embedder: " << message;
return;
}
int id = 0;
dict->GetInteger(kFrontendHostId, &id);
embedder_message_dispatcher_->Dispatch(
base::Bind(&InspectableWebContentsImpl::SendMessageAck,
weak_factory_.GetWeakPtr(), id),
method, params);
}
void InspectableWebContentsImpl::DispatchProtocolMessage(
content::DevToolsAgentHost* agent_host,
const std::string& message) {
if (!frontend_loaded_)
return;
if (message.length() < kMaxMessageChunkSize) {
base::string16 javascript =
base::UTF8ToUTF16("DevToolsAPI.dispatchMessage(" + message + ");");
GetDevToolsWebContents()->GetMainFrame()->ExecuteJavaScript(javascript);
return;
}
base::Value total_size(static_cast<int>(message.length()));
for (size_t pos = 0; pos < message.length(); pos += kMaxMessageChunkSize) {
base::Value message_value(message.substr(pos, kMaxMessageChunkSize));
CallClientFunction("DevToolsAPI.dispatchMessageChunk", &message_value,
pos ? nullptr : &total_size, nullptr);
}
}
void InspectableWebContentsImpl::AgentHostClosed(
content::DevToolsAgentHost* agent_host) {}
void InspectableWebContentsImpl::RenderFrameHostChanged(
content::RenderFrameHost* old_host,
content::RenderFrameHost* new_host) {
if (new_host->GetParent())
return;
frontend_host_.reset(content::DevToolsFrontendHost::Create(
new_host,
base::Bind(&InspectableWebContentsImpl::HandleMessageFromDevToolsFrontend,
weak_factory_.GetWeakPtr())));
}
void InspectableWebContentsImpl::WebContentsDestroyed() {
frontend_loaded_ = false;
external_devtools_web_contents_ = nullptr;
Observe(nullptr);
Detach();
embedder_message_dispatcher_.reset();
for (const auto& pair : pending_requests_)
delete pair.first;
if (view_ && view_->GetDelegate())
view_->GetDelegate()->DevToolsClosed();
}
bool InspectableWebContentsImpl::DidAddMessageToConsole(
content::WebContents* source,
int32_t level,
const base::string16& message,
int32_t line_no,
const base::string16& source_id) {
logging::LogMessage("CONSOLE", line_no, level).stream()
<< "\"" << message << "\", source: " << source_id << " (" << line_no
<< ")";
return true;
}
bool InspectableWebContentsImpl::ShouldCreateWebContents(
content::WebContents* web_contents,
content::RenderFrameHost* opener,
content::SiteInstance* source_site_instance,
int32_t route_id,
int32_t main_frame_route_id,
int32_t main_frame_widget_route_id,
content::mojom::WindowContainerType window_container_type,
const GURL& opener_url,
const std::string& frame_name,
const GURL& target_url,
const std::string& partition_id,
content::SessionStorageNamespace* session_storage_namespace) {
return false;
}
void InspectableWebContentsImpl::HandleKeyboardEvent(
content::WebContents* source,
const content::NativeWebKeyboardEvent& event) {
auto* delegate = web_contents_->GetDelegate();
if (delegate)
delegate->HandleKeyboardEvent(source, event);
}
void InspectableWebContentsImpl::CloseContents(content::WebContents* source) {
// This is where the devtools closes itself (by clicking the x button).
CloseDevTools();
}
content::ColorChooser* InspectableWebContentsImpl::OpenColorChooser(
content::WebContents* source,
SkColor color,
const std::vector<blink::mojom::ColorSuggestionPtr>& suggestions) {
auto* delegate = web_contents_->GetDelegate();
if (delegate)
return delegate->OpenColorChooser(source, color, suggestions);
return nullptr;
}
void InspectableWebContentsImpl::RunFileChooser(
content::RenderFrameHost* render_frame_host,
const content::FileChooserParams& params) {
auto* delegate = web_contents_->GetDelegate();
if (delegate)
delegate->RunFileChooser(render_frame_host, params);
}
void InspectableWebContentsImpl::EnumerateDirectory(
content::WebContents* source,
int request_id,
const base::FilePath& path) {
auto* delegate = web_contents_->GetDelegate();
if (delegate)
delegate->EnumerateDirectory(source, request_id, path);
}
void InspectableWebContentsImpl::OnWebContentsFocused(
content::RenderWidgetHost* render_widget_host) {
#if defined(TOOLKIT_VIEWS)
if (view_->GetDelegate())
view_->GetDelegate()->DevToolsFocused();
#endif
}
void InspectableWebContentsImpl::ReadyToCommitNavigation(
content::NavigationHandle* navigation_handle) {
if (navigation_handle->IsInMainFrame()) {
if (navigation_handle->GetRenderFrameHost() ==
GetDevToolsWebContents()->GetMainFrame() &&
frontend_host_) {
return;
}
frontend_host_.reset(content::DevToolsFrontendHost::Create(
web_contents()->GetMainFrame(),
base::Bind(
&InspectableWebContentsImpl::HandleMessageFromDevToolsFrontend,
base::Unretained(this))));
return;
}
}
void InspectableWebContentsImpl::DidFinishNavigation(
content::NavigationHandle* navigation_handle) {
if (navigation_handle->IsInMainFrame() ||
!navigation_handle->GetURL().SchemeIs("chrome-extension") ||
!navigation_handle->HasCommitted())
return;
content::RenderFrameHost* frame = navigation_handle->GetRenderFrameHost();
auto origin = navigation_handle->GetURL().GetOrigin().spec();
auto it = extensions_api_.find(origin);
if (it == extensions_api_.end())
return;
// Injected Script from devtools frontend doesn't expose chrome,
// most likely bug in chromium.
base::ReplaceFirstSubstringAfterOffset(&it->second, 0, "var chrome",
"var chrome = window.chrome ");
auto script = base::StringPrintf("%s(\"%s\")", it->second.c_str(),
base::GenerateGUID().c_str());
// Invoking content::DevToolsFrontendHost::SetupExtensionsAPI(frame, script);
// should be enough, but it seems to be a noop currently.
frame->ExecuteJavaScriptForTests(base::UTF8ToUTF16(script));
}
void InspectableWebContentsImpl::OnURLFetchComplete(
const net::URLFetcher* source) {
DCHECK(source);
auto it = pending_requests_.find(source);
DCHECK(it != pending_requests_.end());
base::DictionaryValue response;
net::HttpResponseHeaders* rh = source->GetResponseHeaders();
response.SetInteger("statusCode", rh ? rh->response_code() : 200);
{
auto headers = std::make_unique<base::DictionaryValue>();
size_t iterator = 0;
std::string name;
std::string value;
while (rh && rh->EnumerateHeaderLines(&iterator, &name, &value))
headers->SetString(name, value);
response.Set("headers", std::move(headers));
}
it->second.Run(&response);
pending_requests_.erase(it);
delete source;
}
void InspectableWebContentsImpl::SendMessageAck(int request_id,
const base::Value* arg) {
base::Value id_value(request_id);
CallClientFunction("DevToolsAPI.embedderMessageAck", &id_value, arg, nullptr);
}
} // namespace atom

View file

@ -0,0 +1,242 @@
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Copyright (c) 2013 Adam Roben <adam@roben.org>. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE-CHROMIUM file.
#ifndef ATOM_BROWSER_UI_INSPECTABLE_WEB_CONTENTS_IMPL_H_
#define ATOM_BROWSER_UI_INSPECTABLE_WEB_CONTENTS_IMPL_H_
#include <map>
#include <memory>
#include <string>
#include <vector>
#include "atom/browser/ui/inspectable_web_contents.h"
#include "base/memory/weak_ptr.h"
#include "chrome/browser/devtools/devtools_contents_resizing_strategy.h"
#include "chrome/browser/devtools/devtools_embedder_message_dispatcher.h"
#include "content/public/browser/devtools_agent_host.h"
#include "content/public/browser/devtools_frontend_host.h"
#include "content/public/browser/web_contents_delegate.h"
#include "content/public/browser/web_contents_observer.h"
#include "net/url_request/url_fetcher_delegate.h"
#include "ui/gfx/geometry/rect.h"
class PrefService;
class PrefRegistrySimple;
namespace atom {
class InspectableWebContentsDelegate;
class InspectableWebContentsView;
class InspectableWebContentsImpl
: public InspectableWebContents,
public content::DevToolsAgentHostClient,
public content::WebContentsObserver,
public content::WebContentsDelegate,
public DevToolsEmbedderMessageDispatcher::Delegate,
public net::URLFetcherDelegate {
public:
static void RegisterPrefs(PrefRegistrySimple* pref_registry);
InspectableWebContentsImpl(content::WebContents* web_contents,
PrefService* pref_service,
bool is_guest);
~InspectableWebContentsImpl() override;
InspectableWebContentsView* GetView() const override;
content::WebContents* GetWebContents() const override;
content::WebContents* GetDevToolsWebContents() const override;
void SetDelegate(InspectableWebContentsDelegate* delegate) override;
InspectableWebContentsDelegate* GetDelegate() const override;
bool IsGuest() const override;
void ReleaseWebContents() override;
void SetDevToolsWebContents(content::WebContents* devtools) override;
void SetDockState(const std::string& state) override;
void ShowDevTools() override;
void CloseDevTools() override;
bool IsDevToolsViewShowing() override;
void AttachTo(scoped_refptr<content::DevToolsAgentHost>) override;
void Detach() override;
void CallClientFunction(const std::string& function_name,
const base::Value* arg1,
const base::Value* arg2,
const base::Value* arg3) override;
void InspectElement(int x, int y) override;
// Return the last position and size of devtools window.
gfx::Rect GetDevToolsBounds() const;
void SaveDevToolsBounds(const gfx::Rect& bounds);
// Return the last set zoom level of devtools window.
double GetDevToolsZoomLevel() const;
void UpdateDevToolsZoomLevel(double level);
private:
// DevToolsEmbedderMessageDispacher::Delegate
void ActivateWindow() override;
void CloseWindow() override;
void LoadCompleted() override;
void SetInspectedPageBounds(const gfx::Rect& rect) override;
void InspectElementCompleted() override;
void InspectedURLChanged(const std::string& url) override;
void LoadNetworkResource(const DispatchCallback& callback,
const std::string& url,
const std::string& headers,
int stream_id) override;
void SetIsDocked(const DispatchCallback& callback, bool is_docked) override;
void OpenInNewTab(const std::string& url) override;
void ShowItemInFolder(const std::string& file_system_path) override;
void SaveToFile(const std::string& url,
const std::string& content,
bool save_as) override;
void AppendToFile(const std::string& url,
const std::string& content) override;
void RequestFileSystems() override;
void AddFileSystem(const std::string& type) override;
void RemoveFileSystem(const std::string& file_system_path) override;
void UpgradeDraggedFileSystemPermissions(
const std::string& file_system_url) override;
void IndexPath(int index_request_id,
const std::string& file_system_path,
const std::string& excluded_folders) override;
void StopIndexing(int index_request_id) override;
void SearchInPath(int search_request_id,
const std::string& file_system_path,
const std::string& query) override;
void SetWhitelistedShortcuts(const std::string& message) override;
void SetEyeDropperActive(bool active) override;
void ShowCertificateViewer(const std::string& cert_chain) override;
void ZoomIn() override;
void ZoomOut() override;
void ResetZoom() override;
void SetDevicesDiscoveryConfig(
bool discover_usb_devices,
bool port_forwarding_enabled,
const std::string& port_forwarding_config,
bool network_discovery_enabled,
const std::string& network_discovery_config) override;
void SetDevicesUpdatesEnabled(bool enabled) override;
void PerformActionOnRemotePage(const std::string& page_id,
const std::string& action) override;
void OpenRemotePage(const std::string& browser_id,
const std::string& url) override;
void OpenNodeFrontend() override;
void DispatchProtocolMessageFromDevToolsFrontend(
const std::string& message) override;
void SendJsonRequest(const DispatchCallback& callback,
const std::string& browser_id,
const std::string& url) override;
void GetPreferences(const DispatchCallback& callback) override;
void SetPreference(const std::string& name,
const std::string& value) override;
void RemovePreference(const std::string& name) override;
void ClearPreferences() override;
void ConnectionReady() override;
void RegisterExtensionsAPI(const std::string& origin,
const std::string& script) override;
void Reattach(const DispatchCallback& callback) override;
void RecordEnumeratedHistogram(const std::string& name,
int sample,
int boundary_value) override {}
void ReadyForTest() override {}
void SetOpenNewWindowForPopups(bool value) override {}
// content::DevToolsFrontendHostDelegate:
void HandleMessageFromDevToolsFrontend(const std::string& message);
// content::DevToolsAgentHostClient:
void DispatchProtocolMessage(content::DevToolsAgentHost* agent_host,
const std::string& message) override;
void AgentHostClosed(content::DevToolsAgentHost* agent_host) override;
// content::WebContentsObserver:
void RenderFrameHostChanged(content::RenderFrameHost* old_host,
content::RenderFrameHost* new_host) override;
void WebContentsDestroyed() override;
void OnWebContentsFocused(
content::RenderWidgetHost* render_widget_host) override;
void ReadyToCommitNavigation(
content::NavigationHandle* navigation_handle) override;
void DidFinishNavigation(
content::NavigationHandle* navigation_handle) override;
// content::WebContentsDelegate:
bool DidAddMessageToConsole(content::WebContents* source,
int32_t level,
const base::string16& message,
int32_t line_no,
const base::string16& source_id) override;
bool ShouldCreateWebContents(
content::WebContents* web_contents,
content::RenderFrameHost* opener,
content::SiteInstance* source_site_instance,
int32_t route_id,
int32_t main_frame_route_id,
int32_t main_frame_widget_route_id,
content::mojom::WindowContainerType window_container_type,
const GURL& opener_url,
const std::string& frame_name,
const GURL& target_url,
const std::string& partition_id,
content::SessionStorageNamespace* session_storage_namespace) override;
void HandleKeyboardEvent(content::WebContents*,
const content::NativeWebKeyboardEvent&) override;
void CloseContents(content::WebContents* source) override;
content::ColorChooser* OpenColorChooser(
content::WebContents* source,
SkColor color,
const std::vector<blink::mojom::ColorSuggestionPtr>& suggestions)
override;
void RunFileChooser(content::RenderFrameHost* render_frame_host,
const content::FileChooserParams& params) override;
void EnumerateDirectory(content::WebContents* source,
int request_id,
const base::FilePath& path) override;
// net::URLFetcherDelegate:
void OnURLFetchComplete(const net::URLFetcher* source) override;
void SendMessageAck(int request_id, const base::Value* arg1);
bool frontend_loaded_;
scoped_refptr<content::DevToolsAgentHost> agent_host_;
std::unique_ptr<content::DevToolsFrontendHost> frontend_host_;
std::unique_ptr<DevToolsEmbedderMessageDispatcher>
embedder_message_dispatcher_;
DevToolsContentsResizingStrategy contents_resizing_strategy_;
gfx::Rect devtools_bounds_;
bool can_dock_;
std::string dock_state_;
using PendingRequestsMap = std::map<const net::URLFetcher*, DispatchCallback>;
PendingRequestsMap pending_requests_;
InspectableWebContentsDelegate* delegate_; // weak references.
PrefService* pref_service_; // weak reference.
std::unique_ptr<content::WebContents> web_contents_;
// The default devtools created by this class when we don't have an external
// one assigned by SetDevToolsWebContents.
std::unique_ptr<content::WebContents> managed_devtools_web_contents_;
// The external devtools assigned by SetDevToolsWebContents.
content::WebContents* external_devtools_web_contents_ = nullptr;
bool is_guest_;
std::unique_ptr<InspectableWebContentsView> view_;
using ExtensionsAPIs = std::map<std::string, std::string>;
ExtensionsAPIs extensions_api_;
base::WeakPtrFactory<InspectableWebContentsImpl> weak_factory_;
DISALLOW_COPY_AND_ASSIGN(InspectableWebContentsImpl);
};
} // namespace atom
#endif // ATOM_BROWSER_UI_INSPECTABLE_WEB_CONTENTS_IMPL_H_

View file

@ -0,0 +1,62 @@
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Copyright (c) 2013 Adam Roben <adam@roben.org>. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE-CHROMIUM file.
#ifndef ATOM_BROWSER_UI_INSPECTABLE_WEB_CONTENTS_VIEW_H_
#define ATOM_BROWSER_UI_INSPECTABLE_WEB_CONTENTS_VIEW_H_
#include "base/strings/string16.h"
#include "ui/gfx/native_widget_types.h"
class DevToolsContentsResizingStrategy;
#if defined(TOOLKIT_VIEWS)
namespace views {
class View;
}
#endif
namespace atom {
class InspectableWebContentsViewDelegate;
class InspectableWebContentsView {
public:
InspectableWebContentsView() : delegate_(nullptr) {}
virtual ~InspectableWebContentsView() {}
// The delegate manages its own life.
void SetDelegate(InspectableWebContentsViewDelegate* delegate) {
delegate_ = delegate;
}
InspectableWebContentsViewDelegate* GetDelegate() const { return delegate_; }
#if defined(TOOLKIT_VIEWS) && !defined(OS_MACOSX)
// Returns the container control, which has devtools view attached.
virtual views::View* GetView() = 0;
// Returns the web view control, which can be used by the
// GetInitiallyFocusedView() to set initial focus to web view.
virtual views::View* GetWebView() = 0;
#else
virtual gfx::NativeView GetNativeView() const = 0;
#endif
virtual void ShowDevTools() = 0;
// Hide the DevTools view.
virtual void CloseDevTools() = 0;
virtual bool IsDevToolsViewShowing() = 0;
virtual bool IsDevToolsViewFocused() = 0;
virtual void SetIsDocked(bool docked) = 0;
virtual void SetContentsResizingStrategy(
const DevToolsContentsResizingStrategy& strategy) = 0;
virtual void SetTitle(const base::string16& title) = 0;
private:
InspectableWebContentsViewDelegate* delegate_; // weak references.
};
} // namespace atom
#endif // ATOM_BROWSER_UI_INSPECTABLE_WEB_CONTENTS_VIEW_H_

View file

@ -0,0 +1,14 @@
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Copyright (c) 2013 Adam Roben <adam@roben.org>. 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 "atom/browser/ui/inspectable_web_contents_view_delegate.h"
namespace atom {
gfx::ImageSkia InspectableWebContentsViewDelegate::GetDevToolsWindowIcon() {
return gfx::ImageSkia();
}
} // namespace atom

View file

@ -0,0 +1,35 @@
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Copyright (c) 2013 Adam Roben <adam@roben.org>. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE-CHROMIUM file.
#ifndef ATOM_BROWSER_UI_INSPECTABLE_WEB_CONTENTS_VIEW_DELEGATE_H_
#define ATOM_BROWSER_UI_INSPECTABLE_WEB_CONTENTS_VIEW_DELEGATE_H_
#include <string>
#include "ui/gfx/image/image_skia.h"
namespace atom {
class InspectableWebContentsViewDelegate {
public:
virtual ~InspectableWebContentsViewDelegate() {}
virtual void DevToolsFocused() {}
virtual void DevToolsOpened() {}
virtual void DevToolsClosed() {}
// Returns the icon of devtools window.
virtual gfx::ImageSkia GetDevToolsWindowIcon();
#if defined(USE_X11)
// Called when creating devtools window.
virtual void GetDevToolsWindowWMClass(std::string* name,
std::string* class_name) {}
#endif
};
} // namespace atom
#endif // ATOM_BROWSER_UI_INSPECTABLE_WEB_CONTENTS_VIEW_DELEGATE_H_

View file

@ -0,0 +1,50 @@
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Copyright (c) 2013 Adam Roben <adam@roben.org>. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE-CHROMIUM file.
#ifndef ATOM_BROWSER_UI_INSPECTABLE_WEB_CONTENTS_VIEW_MAC_H_
#define ATOM_BROWSER_UI_INSPECTABLE_WEB_CONTENTS_VIEW_MAC_H_
#include "atom/browser/ui/inspectable_web_contents_view.h"
#include "base/mac/scoped_nsobject.h"
@class AtomInspectableWebContentsView;
namespace atom {
class InspectableWebContentsImpl;
class InspectableWebContentsViewMac : public InspectableWebContentsView {
public:
explicit InspectableWebContentsViewMac(
InspectableWebContentsImpl* inspectable_web_contents_impl);
~InspectableWebContentsViewMac() override;
gfx::NativeView GetNativeView() const override;
void ShowDevTools() override;
void CloseDevTools() override;
bool IsDevToolsViewShowing() override;
bool IsDevToolsViewFocused() override;
void SetIsDocked(bool docked) override;
void SetContentsResizingStrategy(
const DevToolsContentsResizingStrategy& strategy) override;
void SetTitle(const base::string16& title) override;
InspectableWebContentsImpl* inspectable_web_contents() {
return inspectable_web_contents_;
}
private:
// Owns us.
InspectableWebContentsImpl* inspectable_web_contents_;
base::scoped_nsobject<AtomInspectableWebContentsView> view_;
DISALLOW_COPY_AND_ASSIGN(InspectableWebContentsViewMac);
};
} // namespace atom
#endif // ATOM_BROWSER_UI_INSPECTABLE_WEB_CONTENTS_VIEW_MAC_H_

View file

@ -0,0 +1,66 @@
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Copyright (c) 2013 Adam Roben <adam@roben.org>. 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 "atom/browser/ui/inspectable_web_contents_view_mac.h"
#import <AppKit/AppKit.h>
#import "atom/browser/ui/cocoa/atom_inspectable_web_contents_view.h"
#include "atom/browser/ui/inspectable_web_contents.h"
#include "atom/browser/ui/inspectable_web_contents_view_delegate.h"
#include "base/strings/sys_string_conversions.h"
namespace atom {
InspectableWebContentsView* CreateInspectableContentsView(
InspectableWebContentsImpl* inspectable_web_contents) {
return new InspectableWebContentsViewMac(inspectable_web_contents);
}
InspectableWebContentsViewMac::InspectableWebContentsViewMac(
InspectableWebContentsImpl* inspectable_web_contents)
: inspectable_web_contents_(inspectable_web_contents),
view_([[AtomInspectableWebContentsView alloc]
initWithInspectableWebContentsViewMac:this]) {}
InspectableWebContentsViewMac::~InspectableWebContentsViewMac() {
[view_ removeObservers];
CloseDevTools();
}
gfx::NativeView InspectableWebContentsViewMac::GetNativeView() const {
return view_.get();
}
void InspectableWebContentsViewMac::ShowDevTools() {
[view_ setDevToolsVisible:YES];
}
void InspectableWebContentsViewMac::CloseDevTools() {
[view_ setDevToolsVisible:NO];
}
bool InspectableWebContentsViewMac::IsDevToolsViewShowing() {
return [view_ isDevToolsVisible];
}
bool InspectableWebContentsViewMac::IsDevToolsViewFocused() {
return [view_ isDevToolsFocused];
}
void InspectableWebContentsViewMac::SetIsDocked(bool docked) {
[view_ setIsDocked:docked];
}
void InspectableWebContentsViewMac::SetContentsResizingStrategy(
const DevToolsContentsResizingStrategy& strategy) {
[view_ setContentsResizingStrategy:strategy];
}
void InspectableWebContentsViewMac::SetTitle(const base::string16& title) {
[view_ setTitle:base::SysUTF16ToNSString(title)];
}
} // namespace atom

View file

@ -0,0 +1,118 @@
// 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 "atom/browser/ui/views/atom_views_delegate.h"
#include <memory>
#include "ui/views/widget/desktop_aura/desktop_native_widget_aura.h"
#include "ui/views/widget/native_widget_aura.h"
#if defined(OS_LINUX)
#include "base/environment.h"
#include "base/nix/xdg_util.h"
#include "ui/views/linux_ui/linux_ui.h"
#endif
namespace {
#if defined(OS_LINUX)
bool IsDesktopEnvironmentUnity() {
std::unique_ptr<base::Environment> env(base::Environment::Create());
base::nix::DesktopEnvironment desktop_env =
base::nix::GetDesktopEnvironment(env.get());
return desktop_env == base::nix::DESKTOP_ENVIRONMENT_UNITY;
}
#endif
} // namespace
namespace atom {
ViewsDelegate::ViewsDelegate() {}
ViewsDelegate::~ViewsDelegate() {}
void ViewsDelegate::SaveWindowPlacement(const views::Widget* window,
const std::string& window_name,
const gfx::Rect& bounds,
ui::WindowShowState show_state) {}
bool ViewsDelegate::GetSavedWindowPlacement(
const views::Widget* widget,
const std::string& window_name,
gfx::Rect* bounds,
ui::WindowShowState* show_state) const {
return false;
}
void ViewsDelegate::NotifyAccessibilityEvent(views::View* view,
ax::mojom::Event event_type) {}
void ViewsDelegate::NotifyMenuItemFocused(const base::string16& menu_name,
const base::string16& menu_item_name,
int item_index,
int item_count,
bool has_submenu) {}
#if defined(OS_WIN)
HICON ViewsDelegate::GetDefaultWindowIcon() const {
// Use current exe's icon as default window icon.
return LoadIcon(GetModuleHandle(NULL),
MAKEINTRESOURCE(1 /* IDR_MAINFRAME */));
}
HICON ViewsDelegate::GetSmallWindowIcon() const {
return GetDefaultWindowIcon();
}
bool ViewsDelegate::IsWindowInMetro(gfx::NativeWindow window) const {
return false;
}
#elif defined(OS_LINUX) && !defined(OS_CHROMEOS)
gfx::ImageSkia* ViewsDelegate::GetDefaultWindowIcon() const {
return NULL;
}
#endif
views::NonClientFrameView* ViewsDelegate::CreateDefaultNonClientFrameView(
views::Widget* widget) {
return NULL;
}
void ViewsDelegate::AddRef() {}
void ViewsDelegate::ReleaseRef() {}
void ViewsDelegate::OnBeforeWidgetInit(
views::Widget::InitParams* params,
views::internal::NativeWidgetDelegate* delegate) {
// If we already have a native_widget, we don't have to try to come
// up with one.
if (params->native_widget)
return;
if (params->parent && params->type != views::Widget::InitParams::TYPE_MENU &&
params->type != views::Widget::InitParams::TYPE_TOOLTIP) {
params->native_widget = new views::NativeWidgetAura(delegate);
} else {
params->native_widget = new views::DesktopNativeWidgetAura(delegate);
}
}
bool ViewsDelegate::WindowManagerProvidesTitleBar(bool maximized) {
#if defined(OS_LINUX)
// On Ubuntu Unity, the system always provides a title bar for maximized
// windows.
if (!maximized)
return false;
static bool is_desktop_environment_unity = IsDesktopEnvironmentUnity();
return is_desktop_environment_unity;
#else
return false;
#endif
}
} // namespace atom

View file

@ -0,0 +1,60 @@
// 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.
#ifndef ATOM_BROWSER_UI_VIEWS_ATOM_VIEWS_DELEGATE_H_
#define ATOM_BROWSER_UI_VIEWS_ATOM_VIEWS_DELEGATE_H_
#include <string>
#include "base/compiler_specific.h"
#include "ui/views/views_delegate.h"
namespace atom {
class ViewsDelegate : public views::ViewsDelegate {
public:
ViewsDelegate();
~ViewsDelegate() override;
protected:
// views::ViewsDelegate:
void SaveWindowPlacement(const views::Widget* window,
const std::string& window_name,
const gfx::Rect& bounds,
ui::WindowShowState show_state) override;
bool GetSavedWindowPlacement(const views::Widget* widget,
const std::string& window_name,
gfx::Rect* bounds,
ui::WindowShowState* show_state) const override;
void NotifyAccessibilityEvent(views::View* view,
ax::mojom::Event event_type) override;
void NotifyMenuItemFocused(const base::string16& menu_name,
const base::string16& menu_item_name,
int item_index,
int item_count,
bool has_submenu) override;
#if defined(OS_WIN)
HICON GetDefaultWindowIcon() const override;
HICON GetSmallWindowIcon() const override;
bool IsWindowInMetro(gfx::NativeWindow window) const override;
#elif defined(OS_LINUX) && !defined(OS_CHROMEOS)
gfx::ImageSkia* GetDefaultWindowIcon() const override;
#endif
views::NonClientFrameView* CreateDefaultNonClientFrameView(
views::Widget* widget) override;
void AddRef() override;
void ReleaseRef() override;
void OnBeforeWidgetInit(
views::Widget::InitParams* params,
views::internal::NativeWidgetDelegate* delegate) override;
bool WindowManagerProvidesTitleBar(bool maximized) override;
private:
DISALLOW_COPY_AND_ASSIGN(ViewsDelegate);
};
} // namespace atom
#endif // ATOM_BROWSER_UI_VIEWS_ATOM_VIEWS_DELEGATE_H_

View file

@ -0,0 +1,231 @@
// 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 "atom/browser/ui/views/inspectable_web_contents_view_views.h"
#include "atom/browser/ui/inspectable_web_contents_delegate.h"
#include "atom/browser/ui/inspectable_web_contents_impl.h"
#include "atom/browser/ui/inspectable_web_contents_view_delegate.h"
#include "base/strings/utf_string_conversions.h"
#include "ui/views/controls/label.h"
#include "ui/views/controls/webview/webview.h"
#include "ui/views/widget/widget.h"
#include "ui/views/widget/widget_delegate.h"
#include "ui/views/window/client_view.h"
namespace atom {
namespace {
class DevToolsWindowDelegate : public views::ClientView,
public views::WidgetDelegate {
public:
DevToolsWindowDelegate(InspectableWebContentsViewViews* shell,
views::View* view,
views::Widget* widget)
: views::ClientView(widget, view),
shell_(shell),
view_(view),
widget_(widget) {
// A WidgetDelegate should be deleted on DeleteDelegate.
set_owned_by_client();
if (shell->GetDelegate())
icon_ = shell->GetDelegate()->GetDevToolsWindowIcon();
}
~DevToolsWindowDelegate() override {}
// views::WidgetDelegate:
void DeleteDelegate() override { delete this; }
views::View* GetInitiallyFocusedView() override { return view_; }
bool CanResize() const override { return true; }
bool CanMaximize() const override { return true; }
bool CanMinimize() const override { return true; }
base::string16 GetWindowTitle() const override { return shell_->GetTitle(); }
gfx::ImageSkia GetWindowAppIcon() override { return GetWindowIcon(); }
gfx::ImageSkia GetWindowIcon() override { return icon_; }
views::Widget* GetWidget() override { return widget_; }
const views::Widget* GetWidget() const override { return widget_; }
views::View* GetContentsView() override { return view_; }
views::ClientView* CreateClientView(views::Widget* widget) override {
return this;
}
// views::ClientView:
bool CanClose() override {
shell_->inspectable_web_contents()->CloseDevTools();
return false;
}
private:
InspectableWebContentsViewViews* shell_;
views::View* view_;
views::Widget* widget_;
gfx::ImageSkia icon_;
DISALLOW_COPY_AND_ASSIGN(DevToolsWindowDelegate);
};
} // namespace
InspectableWebContentsView* CreateInspectableContentsView(
InspectableWebContentsImpl* inspectable_web_contents) {
return new InspectableWebContentsViewViews(inspectable_web_contents);
}
InspectableWebContentsViewViews::InspectableWebContentsViewViews(
InspectableWebContentsImpl* inspectable_web_contents)
: inspectable_web_contents_(inspectable_web_contents),
devtools_window_web_view_(nullptr),
contents_web_view_(nullptr),
devtools_web_view_(new views::WebView(nullptr)),
devtools_visible_(false),
devtools_window_delegate_(nullptr),
title_(base::ASCIIToUTF16("Developer Tools")) {
set_owned_by_client();
if (!inspectable_web_contents_->IsGuest() &&
inspectable_web_contents_->GetWebContents()->GetNativeView()) {
views::WebView* contents_web_view = new views::WebView(nullptr);
contents_web_view->SetWebContents(
inspectable_web_contents_->GetWebContents());
contents_web_view_ = contents_web_view;
} else {
contents_web_view_ =
new views::Label(base::ASCIIToUTF16("No content under offscreen mode"));
}
devtools_web_view_->SetVisible(false);
AddChildView(devtools_web_view_);
AddChildView(contents_web_view_);
}
InspectableWebContentsViewViews::~InspectableWebContentsViewViews() {
if (devtools_window_)
inspectable_web_contents()->SaveDevToolsBounds(
devtools_window_->GetWindowBoundsInScreen());
}
views::View* InspectableWebContentsViewViews::GetView() {
return this;
}
views::View* InspectableWebContentsViewViews::GetWebView() {
return contents_web_view_;
}
void InspectableWebContentsViewViews::ShowDevTools() {
if (devtools_visible_)
return;
devtools_visible_ = true;
if (devtools_window_) {
devtools_window_web_view_->SetWebContents(
inspectable_web_contents_->GetDevToolsWebContents());
devtools_window_->SetBounds(
inspectable_web_contents()->GetDevToolsBounds());
devtools_window_->Show();
} else {
devtools_web_view_->SetVisible(true);
devtools_web_view_->SetWebContents(
inspectable_web_contents_->GetDevToolsWebContents());
devtools_web_view_->RequestFocus();
Layout();
}
}
void InspectableWebContentsViewViews::CloseDevTools() {
if (!devtools_visible_)
return;
devtools_visible_ = false;
if (devtools_window_) {
inspectable_web_contents()->SaveDevToolsBounds(
devtools_window_->GetWindowBoundsInScreen());
devtools_window_.reset();
devtools_window_web_view_ = nullptr;
devtools_window_delegate_ = nullptr;
} else {
devtools_web_view_->SetVisible(false);
devtools_web_view_->SetWebContents(NULL);
Layout();
}
}
bool InspectableWebContentsViewViews::IsDevToolsViewShowing() {
return devtools_visible_;
}
bool InspectableWebContentsViewViews::IsDevToolsViewFocused() {
if (devtools_window_web_view_)
return devtools_window_web_view_->HasFocus();
else if (devtools_web_view_)
return devtools_web_view_->HasFocus();
else
return false;
}
void InspectableWebContentsViewViews::SetIsDocked(bool docked) {
CloseDevTools();
if (!docked) {
devtools_window_.reset(new views::Widget);
devtools_window_web_view_ = new views::WebView(NULL);
devtools_window_delegate_ = new DevToolsWindowDelegate(
this, devtools_window_web_view_, devtools_window_.get());
views::Widget::InitParams params;
params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
params.delegate = devtools_window_delegate_;
params.bounds = inspectable_web_contents()->GetDevToolsBounds();
#if defined(USE_X11)
params.wm_role_name = "devtools";
if (GetDelegate())
GetDelegate()->GetDevToolsWindowWMClass(&params.wm_class_name,
&params.wm_class_class);
#endif
devtools_window_->Init(params);
devtools_window_->UpdateWindowIcon();
}
ShowDevTools();
}
void InspectableWebContentsViewViews::SetContentsResizingStrategy(
const DevToolsContentsResizingStrategy& strategy) {
strategy_.CopyFrom(strategy);
Layout();
}
void InspectableWebContentsViewViews::SetTitle(const base::string16& title) {
if (devtools_window_) {
title_ = title;
devtools_window_->UpdateWindowTitle();
}
}
void InspectableWebContentsViewViews::Layout() {
if (!devtools_web_view_->visible()) {
contents_web_view_->SetBoundsRect(GetContentsBounds());
return;
}
gfx::Size container_size(width(), height());
gfx::Rect new_devtools_bounds;
gfx::Rect new_contents_bounds;
ApplyDevToolsContentsResizingStrategy(
strategy_, container_size, &new_devtools_bounds, &new_contents_bounds);
// DevTools cares about the specific position, so we have to compensate RTL
// layout here.
new_devtools_bounds.set_x(GetMirroredXForRect(new_devtools_bounds));
new_contents_bounds.set_x(GetMirroredXForRect(new_contents_bounds));
devtools_web_view_->SetBoundsRect(new_devtools_bounds);
contents_web_view_->SetBoundsRect(new_contents_bounds);
}
} // namespace atom

View file

@ -0,0 +1,72 @@
// 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.
#ifndef ATOM_BROWSER_UI_VIEWS_INSPECTABLE_WEB_CONTENTS_VIEW_VIEWS_H_
#define ATOM_BROWSER_UI_VIEWS_INSPECTABLE_WEB_CONTENTS_VIEW_VIEWS_H_
#include <memory>
#include "atom/browser/ui/inspectable_web_contents_view.h"
#include "base/compiler_specific.h"
#include "chrome/browser/devtools/devtools_contents_resizing_strategy.h"
#include "ui/views/view.h"
namespace views {
class WebView;
class Widget;
class WidgetDelegate;
} // namespace views
namespace atom {
class InspectableWebContentsImpl;
class InspectableWebContentsViewViews : public InspectableWebContentsView,
public views::View {
public:
explicit InspectableWebContentsViewViews(
InspectableWebContentsImpl* inspectable_web_contents_impl);
~InspectableWebContentsViewViews() override;
// InspectableWebContentsView:
views::View* GetView() override;
views::View* GetWebView() override;
void ShowDevTools() override;
void CloseDevTools() override;
bool IsDevToolsViewShowing() override;
bool IsDevToolsViewFocused() override;
void SetIsDocked(bool docked) override;
void SetContentsResizingStrategy(
const DevToolsContentsResizingStrategy& strategy) override;
void SetTitle(const base::string16& title) override;
InspectableWebContentsImpl* inspectable_web_contents() {
return inspectable_web_contents_;
}
const base::string16& GetTitle() const { return title_; }
private:
// views::View:
void Layout() override;
// Owns us.
InspectableWebContentsImpl* inspectable_web_contents_;
std::unique_ptr<views::Widget> devtools_window_;
views::WebView* devtools_window_web_view_;
views::View* contents_web_view_;
views::WebView* devtools_web_view_;
DevToolsContentsResizingStrategy strategy_;
bool devtools_visible_;
views::WidgetDelegate* devtools_window_delegate_;
base::string16 title_;
DISALLOW_COPY_AND_ASSIGN(InspectableWebContentsViewViews);
};
} // namespace atom
#endif // ATOM_BROWSER_UI_VIEWS_INSPECTABLE_WEB_CONTENTS_VIEW_VIEWS_H_