mirror of
https://github.com/electron/electron.git
synced 2026-02-19 03:14:51 -05:00
Compare commits
70 Commits
v3.1.0-bet
...
v3.1.4
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
08d8c16720 | ||
|
|
439e9d61d6 | ||
|
|
dd4b688b5f | ||
|
|
0082e8083c | ||
|
|
b398305cdd | ||
|
|
94a53cdb30 | ||
|
|
438a7d8e1e | ||
|
|
cdb7eed21d | ||
|
|
98d7b61a4a | ||
|
|
72ff292302 | ||
|
|
c0c179fad0 | ||
|
|
b450e51319 | ||
|
|
753683ad22 | ||
|
|
34a68725a0 | ||
|
|
8ab1309215 | ||
|
|
440a3fa6d8 | ||
|
|
3b61384c26 | ||
|
|
ce33169b71 | ||
|
|
6d5b225ac5 | ||
|
|
bb28fa8e8e | ||
|
|
42acbec1c8 | ||
|
|
3c97c90621 | ||
|
|
1e27157de2 | ||
|
|
95c73eebb2 | ||
|
|
03e051cfbb | ||
|
|
84f3470032 | ||
|
|
cbf5274a96 | ||
|
|
22a7f57293 | ||
|
|
9b6eab1b42 | ||
|
|
8733c2d6c6 | ||
|
|
8f629a2f31 | ||
|
|
ece0487228 | ||
|
|
edf2938ca5 | ||
|
|
79e55e5e85 | ||
|
|
27bfeb6148 | ||
|
|
55e9c211f8 | ||
|
|
8db09e26b1 | ||
|
|
17c00954bd | ||
|
|
034ea3cdfb | ||
|
|
4913fc81d1 | ||
|
|
846b43d7bd | ||
|
|
d644eb4164 | ||
|
|
dc4057bb48 | ||
|
|
c3867ba6d5 | ||
|
|
aa57be70a0 | ||
|
|
9d24d28816 | ||
|
|
75a21678d7 | ||
|
|
7f0056f683 | ||
|
|
02eeef4dc0 | ||
|
|
7d8c59deda | ||
|
|
1e9a75d9f2 | ||
|
|
e7688723f9 | ||
|
|
6fb569cc6c | ||
|
|
349f10d779 | ||
|
|
9f6bee704f | ||
|
|
e6668f60c8 | ||
|
|
409b58525a | ||
|
|
ea83871cf6 | ||
|
|
53ace2e099 | ||
|
|
38fc10f068 | ||
|
|
03b9f0db58 | ||
|
|
aea44b9227 | ||
|
|
eb9e468bcc | ||
|
|
936d088210 | ||
|
|
9490a9f9ba | ||
|
|
3c4cd3f662 | ||
|
|
15f8d15b1b | ||
|
|
9f472acf80 | ||
|
|
0043acf70a | ||
|
|
e25f8c1a08 |
2
DEPS
2
DEPS
@@ -2,7 +2,7 @@ vars = {
|
||||
'chromium_version':
|
||||
'63.0.3239.150',
|
||||
'libchromiumcontent_revision':
|
||||
'99d8f691c3d64704304020f68d46113a1993e281',
|
||||
'cd7a2326b0668f24b83d568eccab16ee9ba8dc9a',
|
||||
'node_version':
|
||||
'v9.7.0-33-g538a5023af',
|
||||
'native_mate_revision':
|
||||
|
||||
@@ -24,10 +24,14 @@
|
||||
#include "base/win/windows_version.h"
|
||||
#include "content/public/app/sandbox_helper_win.h"
|
||||
#include "sandbox/win/src/sandbox_types.h"
|
||||
#elif defined(OS_LINUX) // defined(OS_WIN)
|
||||
#elif defined(OS_LINUX) // defined(OS_WIN)
|
||||
#include <unistd.h>
|
||||
#include <cstdio>
|
||||
#include "atom/app/atom_main_delegate.h" // NOLINT
|
||||
#include "content/public/app/content_main.h"
|
||||
#else // defined(OS_LINUX)
|
||||
#include <unistd.h>
|
||||
#include <cstdio>
|
||||
#include "atom/app/atom_library_main.h"
|
||||
#endif // defined(OS_MACOSX)
|
||||
|
||||
@@ -55,6 +59,25 @@ bool IsEnvSet(const char* name) {
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(OS_POSIX)
|
||||
void FixStdioStreams() {
|
||||
// libuv may mark stdin/stdout/stderr as close-on-exec, which interferes
|
||||
// with chromium's subprocess spawning. As a workaround, we detect if these
|
||||
// streams are closed on startup, and reopen them as /dev/null if necessary.
|
||||
// Otherwise, an unrelated file descriptor will be assigned as stdout/stderr
|
||||
// which may cause various errors when attempting to write to them.
|
||||
//
|
||||
// For details see https://github.com/libuv/libuv/issues/2062
|
||||
struct stat st;
|
||||
if (fstat(STDIN_FILENO, &st) < 0 && errno == EBADF)
|
||||
freopen("/dev/null", "r", stdin);
|
||||
if (fstat(STDOUT_FILENO, &st) < 0 && errno == EBADF)
|
||||
freopen("/dev/null", "w", stdout);
|
||||
if (fstat(STDERR_FILENO, &st) < 0 && errno == EBADF)
|
||||
freopen("/dev/null", "w", stderr);
|
||||
}
|
||||
#endif
|
||||
|
||||
} // namespace
|
||||
|
||||
#if defined(OS_WIN)
|
||||
@@ -157,6 +180,8 @@ int APIENTRY wWinMain(HINSTANCE instance, HINSTANCE, wchar_t* cmd, int) {
|
||||
|
||||
int main(int argc, char* argv[]) {
|
||||
#ifdef ENABLE_RUN_AS_NODE
|
||||
FixStdioStreams();
|
||||
|
||||
if (IsEnvSet(kRunAsNode)) {
|
||||
base::i18n::InitializeICU();
|
||||
base::AtExitManager atexit_manager;
|
||||
@@ -176,6 +201,8 @@ int main(int argc, char* argv[]) {
|
||||
|
||||
int main(int argc, char* argv[]) {
|
||||
#ifdef ENABLE_RUN_AS_NODE
|
||||
FixStdioStreams();
|
||||
|
||||
if (IsEnvSet(kRunAsNode)) {
|
||||
return AtomInitializeICUandStartNode(argc, argv);
|
||||
}
|
||||
|
||||
@@ -183,7 +183,14 @@ bool BrowserWindow::OnMessageReceived(const IPC::Message& message,
|
||||
}
|
||||
|
||||
void BrowserWindow::OnCloseContents() {
|
||||
DCHECK(web_contents());
|
||||
// On some machines it may happen that the window gets destroyed for twice,
|
||||
// checking web_contents() can effectively guard against that.
|
||||
// https://github.com/electron/electron/issues/16202.
|
||||
//
|
||||
// TODO(zcbenz): We should find out the root cause and improve the closing
|
||||
// procedure of BrowserWindow.
|
||||
if (!web_contents())
|
||||
return;
|
||||
|
||||
// Close all child windows before closing current window.
|
||||
v8::Locker locker(isolate());
|
||||
|
||||
@@ -63,7 +63,12 @@ void BrowserWindow::OverrideNSWindowContentView(
|
||||
NSView* webView = iwc->GetView()->GetNativeView();
|
||||
NSView* contentView = [window()->GetNativeWindow() contentView];
|
||||
[webView setFrame:[contentView bounds]];
|
||||
[contentView addSubview:webView];
|
||||
|
||||
// ensure that buttons view is floated to top of view hierarchy
|
||||
NSArray* subviews = [contentView subviews];
|
||||
NSView* last = subviews.lastObject;
|
||||
[contentView addSubview:webView positioned:NSWindowBelow relativeTo:last];
|
||||
|
||||
[contentView viewDidMoveToWindow];
|
||||
}
|
||||
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
|
||||
#include "atom/common/native_mate_converters/callback.h"
|
||||
#include "atom/common/native_mate_converters/file_path_converter.h"
|
||||
#include "atom/common/native_mate_converters/value_converter.h"
|
||||
#include "base/bind.h"
|
||||
#include "base/files/file_util.h"
|
||||
#include "content/public/browser/tracing_controller.h"
|
||||
@@ -23,15 +24,27 @@ struct Converter<base::trace_event::TraceConfig> {
|
||||
static bool FromV8(v8::Isolate* isolate,
|
||||
v8::Local<v8::Value> val,
|
||||
base::trace_event::TraceConfig* out) {
|
||||
// (alexeykuzmin): A combination of "categoryFilter" and "traceOptions"
|
||||
// has to be checked first because none of the fields
|
||||
// in the `memory_dump_config` dict below are mandatory
|
||||
// and we cannot check the config format.
|
||||
Dictionary options;
|
||||
if (!ConvertFromV8(isolate, val, &options))
|
||||
return false;
|
||||
std::string category_filter, trace_options;
|
||||
if (!options.Get("categoryFilter", &category_filter) ||
|
||||
!options.Get("traceOptions", &trace_options))
|
||||
return false;
|
||||
*out = base::trace_event::TraceConfig(category_filter, trace_options);
|
||||
return true;
|
||||
if (ConvertFromV8(isolate, val, &options)) {
|
||||
std::string category_filter, trace_options;
|
||||
if (options.Get("categoryFilter", &category_filter) &&
|
||||
options.Get("traceOptions", &trace_options)) {
|
||||
*out = base::trace_event::TraceConfig(category_filter, trace_options);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
base::DictionaryValue memory_dump_config;
|
||||
if (ConvertFromV8(isolate, val, &memory_dump_config)) {
|
||||
*out = base::trace_event::TraceConfig(memory_dump_config);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -6,15 +6,45 @@
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "atom/browser/api/atom_api_system_preferences.h"
|
||||
#include "atom/common/native_mate_converters/accelerator_converter.h"
|
||||
#include "atom/common/native_mate_converters/callback.h"
|
||||
#include "base/stl_util.h"
|
||||
#include "base/strings/utf_string_conversions.h"
|
||||
#include "native_mate/dictionary.h"
|
||||
|
||||
#include "atom/common/node_includes.h"
|
||||
#include "atom/common/platform_util.h"
|
||||
|
||||
#if defined(OS_MACOSX)
|
||||
#include "base/mac/mac_util.h"
|
||||
#endif
|
||||
|
||||
using extensions::GlobalShortcutListener;
|
||||
|
||||
namespace {
|
||||
|
||||
#if defined(OS_MACOSX)
|
||||
bool RegisteringMediaKeyForUntrustedClient(const ui::Accelerator& accelerator) {
|
||||
if (platform_util::IsAtLeastOS10_14()) {
|
||||
constexpr ui::KeyboardCode mediaKeys[] = {
|
||||
ui::VKEY_MEDIA_PLAY_PAUSE, ui::VKEY_MEDIA_NEXT_TRACK,
|
||||
ui::VKEY_MEDIA_PREV_TRACK, ui::VKEY_MEDIA_STOP};
|
||||
|
||||
if (std::find(std::begin(mediaKeys), std::end(mediaKeys),
|
||||
accelerator.key_code()) != std::end(mediaKeys)) {
|
||||
bool trusted =
|
||||
atom::api::SystemPreferences::IsTrustedAccessibilityClient(false);
|
||||
if (!trusted)
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
|
||||
} // namespace
|
||||
|
||||
namespace atom {
|
||||
|
||||
namespace api {
|
||||
@@ -31,7 +61,7 @@ void GlobalShortcut::OnKeyPressed(const ui::Accelerator& accelerator) {
|
||||
if (accelerator_callback_map_.find(accelerator) ==
|
||||
accelerator_callback_map_.end()) {
|
||||
// This should never occur, because if it does, GlobalGlobalShortcutListener
|
||||
// notifes us with wrong accelerator.
|
||||
// notifies us with wrong accelerator.
|
||||
NOTREACHED();
|
||||
return;
|
||||
}
|
||||
@@ -40,6 +70,11 @@ void GlobalShortcut::OnKeyPressed(const ui::Accelerator& accelerator) {
|
||||
|
||||
bool GlobalShortcut::Register(const ui::Accelerator& accelerator,
|
||||
const base::Closure& callback) {
|
||||
#if defined(OS_MACOSX)
|
||||
if (RegisteringMediaKeyForUntrustedClient(accelerator))
|
||||
return false;
|
||||
#endif
|
||||
|
||||
if (!GlobalShortcutListener::GetInstance()->RegisterAccelerator(accelerator,
|
||||
this)) {
|
||||
return false;
|
||||
|
||||
@@ -41,6 +41,8 @@ void Menu::AfterInit(v8::Isolate* isolate) {
|
||||
delegate.Get("isCommandIdEnabled", &is_enabled_);
|
||||
delegate.Get("isCommandIdVisible", &is_visible_);
|
||||
delegate.Get("getAcceleratorForCommandId", &get_accelerator_);
|
||||
delegate.Get("shouldRegisterAcceleratorForCommandId",
|
||||
&should_register_accelerator_);
|
||||
delegate.Get("executeCommand", &execute_command_);
|
||||
delegate.Get("menuWillShow", &menu_will_show_);
|
||||
}
|
||||
@@ -74,6 +76,12 @@ bool Menu::GetAcceleratorForCommandIdWithParams(
|
||||
return mate::ConvertFromV8(isolate(), val, accelerator);
|
||||
}
|
||||
|
||||
bool Menu::ShouldRegisterAcceleratorForCommandId(int command_id) const {
|
||||
v8::Locker locker(isolate());
|
||||
v8::HandleScope handle_scope(isolate());
|
||||
return should_register_accelerator_.Run(GetWrapper(), command_id);
|
||||
}
|
||||
|
||||
void Menu::ExecuteCommand(int command_id, int flags) {
|
||||
v8::Locker locker(isolate());
|
||||
v8::HandleScope handle_scope(isolate());
|
||||
|
||||
@@ -51,6 +51,7 @@ class Menu : public mate::TrackableObject<Menu>,
|
||||
int command_id,
|
||||
bool use_default_accelerator,
|
||||
ui::Accelerator* accelerator) const override;
|
||||
bool ShouldRegisterAcceleratorForCommandId(int command_id) const override;
|
||||
void ExecuteCommand(int command_id, int event_flags) override;
|
||||
void MenuWillShow(ui::SimpleMenuModel* source) override;
|
||||
|
||||
@@ -101,6 +102,7 @@ class Menu : public mate::TrackableObject<Menu>,
|
||||
base::Callback<bool(v8::Local<v8::Value>, int)> is_visible_;
|
||||
base::Callback<v8::Local<v8::Value>(v8::Local<v8::Value>, int, bool)>
|
||||
get_accelerator_;
|
||||
base::Callback<bool(v8::Local<v8::Value>, int)> should_register_accelerator_;
|
||||
base::Callback<void(v8::Local<v8::Value>, v8::Local<v8::Value>, int)>
|
||||
execute_command_;
|
||||
base::Callback<void(v8::Local<v8::Value>)> menu_will_show_;
|
||||
|
||||
@@ -93,6 +93,8 @@ class SystemPreferences : public mate::EventEmitter<SystemPreferences>
|
||||
mate::Arguments* args);
|
||||
void RemoveUserDefault(const std::string& name);
|
||||
bool IsSwipeTrackingFromScrollEventsEnabled();
|
||||
|
||||
static bool IsTrustedAccessibilityClient(bool prompt);
|
||||
#endif
|
||||
bool IsDarkMode();
|
||||
bool IsInvertedColorScheme();
|
||||
|
||||
@@ -308,6 +308,12 @@ void SystemPreferences::SetUserDefault(const std::string& name,
|
||||
}
|
||||
}
|
||||
|
||||
// static
|
||||
bool SystemPreferences::IsTrustedAccessibilityClient(bool prompt) {
|
||||
NSDictionary* options = @{(id)kAXTrustedCheckOptionPrompt : @(prompt)};
|
||||
return AXIsProcessTrustedWithOptions((CFDictionaryRef)options);
|
||||
}
|
||||
|
||||
void SystemPreferences::RemoveUserDefault(const std::string& name) {
|
||||
NSUserDefaults* defaults = [NSUserDefaults standardUserDefaults];
|
||||
[defaults removeObjectForKey:base::SysUTF8ToNSString(name)];
|
||||
|
||||
@@ -667,8 +667,8 @@ v8::Local<v8::Value> TopLevelWindow::GetNativeWindowHandle() {
|
||||
// TODO(MarshallOfSound): Replace once
|
||||
// https://chromium-review.googlesource.com/c/chromium/src/+/1253094/ has
|
||||
// landed
|
||||
auto handle = window_->GetNativeWindowHandlePointer();
|
||||
return ToBuffer(isolate(), std::get<0>(handle), std::get<1>(handle));
|
||||
NativeWindowHandle handle = window_->GetNativeWindowHandle();
|
||||
return ToBuffer(isolate(), &handle, sizeof(handle));
|
||||
}
|
||||
|
||||
void TopLevelWindow::SetProgressBar(double progress, mate::Arguments* args) {
|
||||
|
||||
@@ -163,7 +163,7 @@ void CommonWebContentsDelegate::InitWithWebContents(
|
||||
// Determien whether the WebContents is offscreen.
|
||||
auto* web_preferences = WebContentsPreferences::From(web_contents);
|
||||
offscreen_ =
|
||||
!web_preferences || web_preferences->IsEnabled(options::kOffscreen);
|
||||
web_preferences && web_preferences->IsEnabled(options::kOffscreen);
|
||||
|
||||
// Create InspectableWebContents.
|
||||
web_contents_.reset(brightray::InspectableWebContents::Create(
|
||||
|
||||
@@ -45,6 +45,12 @@ class NativeBrowserView;
|
||||
|
||||
struct DraggableRegion;
|
||||
|
||||
#if defined(OS_MACOSX)
|
||||
typedef NSView* NativeWindowHandle;
|
||||
#else
|
||||
typedef gfx::AcceleratedWidget NativeWindowHandle;
|
||||
#endif
|
||||
|
||||
class NativeWindow : public base::SupportsUserData,
|
||||
public views::WidgetDelegate {
|
||||
public:
|
||||
@@ -151,7 +157,7 @@ class NativeWindow : public base::SupportsUserData,
|
||||
virtual gfx::NativeView GetNativeView() const = 0;
|
||||
virtual gfx::NativeWindow GetNativeWindow() const = 0;
|
||||
virtual gfx::AcceleratedWidget GetAcceleratedWidget() const = 0;
|
||||
virtual std::tuple<void*, int> GetNativeWindowHandlePointer() const = 0;
|
||||
virtual NativeWindowHandle GetNativeWindowHandle() const = 0;
|
||||
|
||||
// Taskbar/Dock APIs.
|
||||
enum ProgressState {
|
||||
|
||||
@@ -104,7 +104,7 @@ class NativeWindowMac : public NativeWindow {
|
||||
gfx::NativeView GetNativeView() const override;
|
||||
gfx::NativeWindow GetNativeWindow() const override;
|
||||
gfx::AcceleratedWidget GetAcceleratedWidget() const override;
|
||||
std::tuple<void*, int> GetNativeWindowHandlePointer() const override;
|
||||
NativeWindowHandle GetNativeWindowHandle() const override;
|
||||
void SetProgressBar(double progress, const ProgressState state) override;
|
||||
void SetOverlayIcon(const gfx::Image& overlay,
|
||||
const std::string& description) override;
|
||||
|
||||
@@ -74,9 +74,7 @@
|
||||
forStyleMask:NSTitledWindowMask];
|
||||
NSButton* miniaturize_button =
|
||||
[NSWindow standardWindowButton:NSWindowMiniaturizeButton
|
||||
forStyleMask:NSTitledWindowMask];
|
||||
NSButton* zoom_button = [NSWindow standardWindowButton:NSWindowZoomButton
|
||||
forStyleMask:NSTitledWindowMask];
|
||||
forStyleMask:NSWindowStyleMaskTitled];
|
||||
|
||||
CGFloat x = 0;
|
||||
const CGFloat space_between = 20;
|
||||
@@ -89,11 +87,7 @@
|
||||
x += space_between;
|
||||
[self addSubview:miniaturize_button];
|
||||
|
||||
[zoom_button setFrameOrigin:NSMakePoint(x, 0)];
|
||||
x += space_between;
|
||||
[self addSubview:zoom_button];
|
||||
|
||||
const auto last_button_frame = zoom_button.frame;
|
||||
const auto last_button_frame = miniaturize_button.frame;
|
||||
[self setFrameSize:NSMakeSize(last_button_frame.origin.x +
|
||||
last_button_frame.size.width,
|
||||
last_button_frame.size.height)];
|
||||
@@ -478,7 +472,8 @@ NativeWindowMac::NativeWindowMac(const mate::Dictionary& options,
|
||||
}
|
||||
|
||||
NativeWindowMac::~NativeWindowMac() {
|
||||
[NSEvent removeMonitor:wheel_event_monitor_];
|
||||
if (wheel_event_monitor_)
|
||||
[NSEvent removeMonitor:wheel_event_monitor_];
|
||||
}
|
||||
|
||||
void NativeWindowMac::SetContentView(views::View* view) {
|
||||
@@ -515,6 +510,13 @@ void NativeWindowMac::Close() {
|
||||
}
|
||||
|
||||
void NativeWindowMac::CloseImmediately() {
|
||||
// Remove event monitor before destroying window, otherwise the monitor may
|
||||
// call its callback after window has been destroyed.
|
||||
if (wheel_event_monitor_) {
|
||||
[NSEvent removeMonitor:wheel_event_monitor_];
|
||||
wheel_event_monitor_ = nil;
|
||||
}
|
||||
|
||||
// Retain the child window before closing it. If the last reference to the
|
||||
// NSWindow goes away inside -[NSWindow close], then bad stuff can happen.
|
||||
// See e.g. http://crbug.com/616701.
|
||||
@@ -1079,26 +1081,31 @@ gfx::AcceleratedWidget NativeWindowMac::GetAcceleratedWidget() const {
|
||||
return gfx::kNullAcceleratedWidget;
|
||||
}
|
||||
|
||||
std::tuple<void*, int> NativeWindowMac::GetNativeWindowHandlePointer() const {
|
||||
NSView* view = [window_ contentView];
|
||||
return std::make_tuple(static_cast<void*>(view), sizeof(view));
|
||||
NativeWindowHandle NativeWindowMac::GetNativeWindowHandle() const {
|
||||
return [window_ contentView];
|
||||
}
|
||||
|
||||
void NativeWindowMac::SetProgressBar(double progress,
|
||||
const NativeWindow::ProgressState state) {
|
||||
NSDockTile* dock_tile = [NSApp dockTile];
|
||||
|
||||
// Sometimes macOS would install a default contentView for dock, we must
|
||||
// verify whether NSProgressIndicator has been installed.
|
||||
bool first_time = !dock_tile.contentView ||
|
||||
[[dock_tile.contentView subviews] count] == 0 ||
|
||||
![[[dock_tile.contentView subviews] lastObject]
|
||||
isKindOfClass:[NSProgressIndicator class]];
|
||||
|
||||
// For the first time API invoked, we need to create a ContentView in
|
||||
// DockTile.
|
||||
if (dock_tile.contentView == nullptr) {
|
||||
NSImageView* image_view = [[NSImageView alloc] init];
|
||||
if (first_time) {
|
||||
NSImageView* image_view = [[[NSImageView alloc] init] autorelease];
|
||||
[image_view setImage:[NSApp applicationIconImage]];
|
||||
[dock_tile setContentView:image_view];
|
||||
}
|
||||
|
||||
if ([[dock_tile.contentView subviews] count] == 0) {
|
||||
NSProgressIndicator* progress_indicator = [[AtomProgressBar alloc]
|
||||
initWithFrame:NSMakeRect(0.0f, 0.0f, dock_tile.size.width, 15.0)];
|
||||
NSRect frame = NSMakeRect(0.0f, 0.0f, dock_tile.size.width, 15.0);
|
||||
NSProgressIndicator* progress_indicator =
|
||||
[[[AtomProgressBar alloc] initWithFrame:frame] autorelease];
|
||||
[progress_indicator setStyle:NSProgressIndicatorBarStyle];
|
||||
[progress_indicator setIndeterminate:NO];
|
||||
[progress_indicator setBezeled:YES];
|
||||
@@ -1109,7 +1116,7 @@ void NativeWindowMac::SetProgressBar(double progress,
|
||||
}
|
||||
|
||||
NSProgressIndicator* progress_indicator = static_cast<NSProgressIndicator*>(
|
||||
[[[dock_tile contentView] subviews] objectAtIndex:0]);
|
||||
[[[dock_tile contentView] subviews] lastObject]);
|
||||
if (progress < 0) {
|
||||
[progress_indicator setHidden:YES];
|
||||
} else if (progress > 1) {
|
||||
@@ -1361,6 +1368,8 @@ void NativeWindowMac::AddContentViewLayers() {
|
||||
if (title_bar_style_ == CUSTOM_BUTTONS_ON_HOVER) {
|
||||
buttons_view_.reset(
|
||||
[[CustomWindowButtonView alloc] initWithFrame:NSZeroRect]);
|
||||
// NSWindowStyleMaskFullSizeContentView does not work with zoom button
|
||||
SetFullScreenable(false);
|
||||
[[window_ contentView] addSubview:buttons_view_];
|
||||
} else {
|
||||
if (title_bar_style_ != NORMAL) {
|
||||
|
||||
@@ -1047,9 +1047,8 @@ gfx::AcceleratedWidget NativeWindowViews::GetAcceleratedWidget() const {
|
||||
return GetNativeWindow()->GetHost()->GetAcceleratedWidget();
|
||||
}
|
||||
|
||||
std::tuple<void*, int> NativeWindowViews::GetNativeWindowHandlePointer() const {
|
||||
gfx::AcceleratedWidget handle = GetAcceleratedWidget();
|
||||
return std::make_tuple(static_cast<void*>(&handle), sizeof(handle));
|
||||
NativeWindowHandle NativeWindowViews::GetNativeWindowHandle() const {
|
||||
return GetAcceleratedWidget();
|
||||
}
|
||||
|
||||
gfx::Rect NativeWindowViews::ContentBoundsToWindowBounds(
|
||||
|
||||
@@ -124,7 +124,7 @@ class NativeWindowViews : public NativeWindow,
|
||||
bool IsVisibleOnAllWorkspaces() override;
|
||||
|
||||
gfx::AcceleratedWidget GetAcceleratedWidget() const override;
|
||||
std::tuple<void*, int> GetNativeWindowHandlePointer() const override;
|
||||
NativeWindowHandle GetNativeWindowHandle() const override;
|
||||
|
||||
gfx::Rect ContentBoundsToWindowBounds(const gfx::Rect& bounds) const override;
|
||||
gfx::Rect WindowBoundsToContentBounds(const gfx::Rect& bounds) const override;
|
||||
|
||||
@@ -308,6 +308,7 @@ void URLRequestContextGetter::NotifyContextShuttingDown(
|
||||
|
||||
context_shutting_down_ = true;
|
||||
resource_context.reset();
|
||||
http_auth_preferences_.reset();
|
||||
net::URLRequestContextGetter::NotifyContextShuttingDown();
|
||||
}
|
||||
|
||||
@@ -341,22 +342,32 @@ net::URLRequestContext* URLRequestContextGetter::GetURLRequestContext() {
|
||||
host_resolver = std::move(remapped_resolver);
|
||||
}
|
||||
|
||||
net::HttpAuthPreferences auth_preferences;
|
||||
std::vector<std::string> supported_schemes = {
|
||||
net::kBasicAuthScheme, net::kDigestAuthScheme,
|
||||
net::kNegotiateAuthScheme, net::kNtlmAuthScheme};
|
||||
http_auth_preferences_ =
|
||||
std::make_unique<net::HttpAuthPreferences>(supported_schemes
|
||||
#if defined(OS_POSIX)
|
||||
,
|
||||
std::string()
|
||||
#endif
|
||||
); // NOLINT(whitespace/parens)
|
||||
|
||||
// --auth-server-whitelist
|
||||
if (command_line.HasSwitch(switches::kAuthServerWhitelist)) {
|
||||
auth_preferences.SetServerWhitelist(
|
||||
http_auth_preferences_->SetServerWhitelist(
|
||||
command_line.GetSwitchValueASCII(switches::kAuthServerWhitelist));
|
||||
}
|
||||
|
||||
// --auth-negotiate-delegate-whitelist
|
||||
if (command_line.HasSwitch(switches::kAuthNegotiateDelegateWhitelist)) {
|
||||
auth_preferences.SetDelegateWhitelist(command_line.GetSwitchValueASCII(
|
||||
switches::kAuthNegotiateDelegateWhitelist));
|
||||
http_auth_preferences_->SetDelegateWhitelist(
|
||||
command_line.GetSwitchValueASCII(
|
||||
switches::kAuthNegotiateDelegateWhitelist));
|
||||
}
|
||||
auto http_auth_handler_factory =
|
||||
net::HttpAuthHandlerRegistryFactory::CreateDefault(host_resolver.get());
|
||||
http_auth_handler_factory->SetHttpAuthPreferences(net::kNegotiateAuthScheme,
|
||||
&auth_preferences);
|
||||
net::HttpAuthHandlerRegistryFactory::Create(
|
||||
http_auth_preferences_.get(), host_resolver.get());
|
||||
builder->SetHttpAuthHandlerFactory(std::move(http_auth_handler_factory));
|
||||
builder->set_host_resolver(std::move(host_resolver));
|
||||
builder->set_ct_verifier(std::make_unique<net::MultiLogCTVerifier>());
|
||||
|
||||
@@ -24,8 +24,9 @@ class RequireCTDelegate;
|
||||
} // namespace brightray
|
||||
|
||||
namespace net {
|
||||
class HttpAuthPreferences;
|
||||
class NetLog;
|
||||
}
|
||||
} // namespace net
|
||||
|
||||
namespace atom {
|
||||
|
||||
@@ -100,6 +101,7 @@ class URLRequestContextGetter : public net::URLRequestContextGetter {
|
||||
|
||||
std::unique_ptr<brightray::RequireCTDelegate> ct_delegate_;
|
||||
std::unique_ptr<AtomURLRequestJobFactory> top_job_factory_;
|
||||
std::unique_ptr<net::HttpAuthPreferences> http_auth_preferences_;
|
||||
std::unique_ptr<network::mojom::NetworkContext> network_context_;
|
||||
|
||||
net::NetLog* net_log_;
|
||||
|
||||
@@ -17,9 +17,9 @@
|
||||
<key>CFBundleIconFile</key>
|
||||
<string>electron.icns</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>3.1.0</string>
|
||||
<string>3.1.4</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>3.1.0</string>
|
||||
<string>3.1.4</string>
|
||||
<key>LSApplicationCategoryType</key>
|
||||
<string>public.app-category.developer-tools</string>
|
||||
<key>LSMinimumSystemVersion</key>
|
||||
|
||||
@@ -56,8 +56,8 @@ END
|
||||
//
|
||||
|
||||
VS_VERSION_INFO VERSIONINFO
|
||||
FILEVERSION 3,1,0,1
|
||||
PRODUCTVERSION 3,1,0,1
|
||||
FILEVERSION 3,1,4,0
|
||||
PRODUCTVERSION 3,1,4,0
|
||||
FILEFLAGSMASK 0x3fL
|
||||
#ifdef _DEBUG
|
||||
FILEFLAGS 0x1L
|
||||
@@ -74,12 +74,12 @@ BEGIN
|
||||
BEGIN
|
||||
VALUE "CompanyName", "GitHub, Inc."
|
||||
VALUE "FileDescription", "Electron"
|
||||
VALUE "FileVersion", "3.1.0"
|
||||
VALUE "FileVersion", "3.1.4"
|
||||
VALUE "InternalName", "electron.exe"
|
||||
VALUE "LegalCopyright", "Copyright (C) 2015 GitHub, Inc. All rights reserved."
|
||||
VALUE "OriginalFilename", "electron.exe"
|
||||
VALUE "ProductName", "Electron"
|
||||
VALUE "ProductVersion", "3.1.0"
|
||||
VALUE "ProductVersion", "3.1.4"
|
||||
VALUE "SquirrelAwareVersion", "1"
|
||||
END
|
||||
END
|
||||
|
||||
@@ -78,9 +78,11 @@ void GenerateAcceleratorTable(AcceleratorTable* table,
|
||||
GenerateAcceleratorTable(table, submodel);
|
||||
} else {
|
||||
ui::Accelerator accelerator;
|
||||
if (model->GetAcceleratorAtWithParams(i, true, &accelerator)) {
|
||||
MenuItem item = {i, model};
|
||||
(*table)[accelerator] = item;
|
||||
if (model->ShouldRegisterAcceleratorAt(i)) {
|
||||
if (model->GetAcceleratorAtWithParams(i, true, &accelerator)) {
|
||||
MenuItem item = {i, model};
|
||||
(*table)[accelerator] = item;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -43,6 +43,14 @@ bool AtomMenuModel::GetAcceleratorAtWithParams(
|
||||
return false;
|
||||
}
|
||||
|
||||
bool AtomMenuModel::ShouldRegisterAcceleratorAt(int index) const {
|
||||
if (delegate_) {
|
||||
return delegate_->ShouldRegisterAcceleratorForCommandId(
|
||||
GetCommandIdAt(index));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void AtomMenuModel::MenuWillClose() {
|
||||
ui::SimpleMenuModel::MenuWillClose();
|
||||
for (Observer& observer : observers_) {
|
||||
|
||||
@@ -23,6 +23,9 @@ class AtomMenuModel : public ui::SimpleMenuModel {
|
||||
bool use_default_accelerator,
|
||||
ui::Accelerator* accelerator) const = 0;
|
||||
|
||||
virtual bool ShouldRegisterAcceleratorForCommandId(
|
||||
int command_id) const = 0;
|
||||
|
||||
private:
|
||||
// ui::SimpleMenuModel::Delegate:
|
||||
bool GetAcceleratorForCommandId(
|
||||
@@ -52,6 +55,7 @@ class AtomMenuModel : public ui::SimpleMenuModel {
|
||||
bool GetAcceleratorAtWithParams(int index,
|
||||
bool use_default_accelerator,
|
||||
ui::Accelerator* accelerator) const;
|
||||
bool ShouldRegisterAcceleratorAt(int index) const;
|
||||
|
||||
// ui::SimpleMenuModel:
|
||||
void MenuWillClose() override;
|
||||
|
||||
@@ -5,7 +5,6 @@
|
||||
#include "atom/browser/ui/views/menu_bar.h"
|
||||
|
||||
#include <memory>
|
||||
#include <string>
|
||||
|
||||
#include "atom/browser/ui/views/menu_delegate.h"
|
||||
#include "atom/browser/ui/views/submenu_button.h"
|
||||
@@ -129,13 +128,11 @@ void MenuBar::RefreshColorCache(const ui::NativeTheme* theme) {
|
||||
theme = ui::NativeTheme::GetInstanceForNativeUi();
|
||||
if (theme) {
|
||||
#if defined(USE_X11)
|
||||
const std::string menubar_selector = "GtkMenuBar#menubar";
|
||||
background_color_ = libgtkui::GetBgColor(menubar_selector);
|
||||
|
||||
enabled_color_ = theme->GetSystemColor(
|
||||
ui::NativeTheme::kColorId_EnabledMenuItemForegroundColor);
|
||||
disabled_color_ = theme->GetSystemColor(
|
||||
ui::NativeTheme::kColorId_DisabledMenuItemForegroundColor);
|
||||
background_color_ = libgtkui::GetBgColor("GtkMenuBar#menubar");
|
||||
enabled_color_ = libgtkui::GetFgColor(
|
||||
"GtkMenuBar#menubar GtkMenuItem#menuitem GtkLabel");
|
||||
disabled_color_ = libgtkui::GetFgColor(
|
||||
"GtkMenuBar#menubar GtkMenuItem#menuitem:disabled GtkLabel");
|
||||
#else
|
||||
background_color_ =
|
||||
theme->GetSystemColor(ui::NativeTheme::kColorId_MenuBackgroundColor);
|
||||
|
||||
@@ -7,8 +7,8 @@
|
||||
|
||||
#define ATOM_MAJOR_VERSION 3
|
||||
#define ATOM_MINOR_VERSION 1
|
||||
#define ATOM_PATCH_VERSION 0
|
||||
#define ATOM_PRE_RELEASE_VERSION -beta.1
|
||||
#define ATOM_PATCH_VERSION 4
|
||||
// #define ATOM_PRE_RELEASE_VERSION
|
||||
|
||||
#ifndef ATOM_STRINGIFY
|
||||
#define ATOM_STRINGIFY(n) ATOM_STRINGIFY_HELPER(n)
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
#include <windows.h>
|
||||
|
||||
#include "base/logging.h"
|
||||
#include "base/sys_info.h"
|
||||
|
||||
extern "C" {
|
||||
#include "vendor/node/deps/uv/src/win/internal.h"
|
||||
@@ -15,7 +16,20 @@ extern "C" {
|
||||
namespace atom {
|
||||
|
||||
NodeBindingsWin::NodeBindingsWin(BrowserEnvironment browser_env)
|
||||
: NodeBindings(browser_env) {}
|
||||
: NodeBindings(browser_env) {
|
||||
// on single-core the io comp port NumberOfConcurrentThreads needs to be 2
|
||||
// to avoid cpu pegging likely caused by a busy loop in PollEvents
|
||||
if (base::SysInfo::NumberOfProcessors() == 1) {
|
||||
// the expectation is the uv_loop_ has just been initialized
|
||||
// which makes iocp replacement safe
|
||||
CHECK_EQ(0u, uv_loop_->active_handles);
|
||||
CHECK_EQ(0u, uv_loop_->active_reqs.count);
|
||||
|
||||
if (uv_loop_->iocp && uv_loop_->iocp != INVALID_HANDLE_VALUE)
|
||||
CloseHandle(uv_loop_->iocp);
|
||||
uv_loop_->iocp = CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, 0, 2);
|
||||
}
|
||||
}
|
||||
|
||||
NodeBindingsWin::~NodeBindingsWin() {}
|
||||
|
||||
|
||||
@@ -60,6 +60,7 @@ void Beep();
|
||||
#if defined(OS_MACOSX)
|
||||
bool GetLoginItemEnabled();
|
||||
void SetLoginItemEnabled(bool enabled);
|
||||
bool IsAtLeastOS10_14();
|
||||
#endif
|
||||
|
||||
} // namespace platform_util
|
||||
|
||||
@@ -8,6 +8,8 @@
|
||||
#import <Cocoa/Cocoa.h>
|
||||
#import <ServiceManagement/ServiceManagement.h>
|
||||
|
||||
#include "atom/common/platform_util.h"
|
||||
|
||||
#include "base/callback.h"
|
||||
#include "base/files/file_path.h"
|
||||
#include "base/files/file_util.h"
|
||||
@@ -18,6 +20,7 @@
|
||||
#include "base/strings/stringprintf.h"
|
||||
#include "base/strings/sys_string_conversions.h"
|
||||
#include "net/base/mac/url_conversions.h"
|
||||
#include "third_party/WebKit/Source/platform/mac/VersionUtilMac.h"
|
||||
#include "url/gurl.h"
|
||||
|
||||
namespace {
|
||||
@@ -166,6 +169,10 @@ void OpenExternal(const GURL& url,
|
||||
});
|
||||
}
|
||||
|
||||
bool IsAtLeastOS10_14() {
|
||||
return blink::internal::MacOSXMinorVersion() >= 14;
|
||||
}
|
||||
|
||||
bool MoveItemToTrash(const base::FilePath& full_path) {
|
||||
NSString* path_string = base::SysUTF8ToNSString(full_path.value());
|
||||
BOOL status = [[NSFileManager defaultManager]
|
||||
|
||||
@@ -2,7 +2,10 @@
|
||||
// Use of this source code is governed by the MIT license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include "atom/renderer/api/atom_api_web_frame.h"
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#include "atom/common/api/api_messages.h"
|
||||
#include "atom/common/api/event_emitter_caller.h"
|
||||
@@ -109,15 +112,15 @@ class ScriptExecutionCallback : public blink::WebScriptExecutionCallback {
|
||||
DISALLOW_COPY_AND_ASSIGN(ScriptExecutionCallback);
|
||||
};
|
||||
|
||||
class FrameSpellChecker : public content::RenderFrameVisitor {
|
||||
class FrameSetSpellChecker : public content::RenderFrameVisitor {
|
||||
public:
|
||||
explicit FrameSpellChecker(SpellCheckClient* spell_check_client,
|
||||
content::RenderFrame* main_frame)
|
||||
: spell_check_client_(spell_check_client), main_frame_(main_frame) {}
|
||||
~FrameSpellChecker() override {
|
||||
spell_check_client_ = nullptr;
|
||||
main_frame_ = nullptr;
|
||||
FrameSetSpellChecker(SpellCheckClient* spell_check_client,
|
||||
content::RenderFrame* main_frame)
|
||||
: spell_check_client_(spell_check_client), main_frame_(main_frame) {
|
||||
content::RenderFrame::ForEach(this);
|
||||
main_frame->GetWebFrame()->SetSpellCheckPanelHostClient(spell_check_client);
|
||||
}
|
||||
|
||||
bool Visit(content::RenderFrame* render_frame) override {
|
||||
auto* view = render_frame->GetRenderView();
|
||||
if (view->GetMainRenderFrame() == main_frame_ ||
|
||||
@@ -130,71 +133,128 @@ class FrameSpellChecker : public content::RenderFrameVisitor {
|
||||
private:
|
||||
SpellCheckClient* spell_check_client_;
|
||||
content::RenderFrame* main_frame_;
|
||||
DISALLOW_COPY_AND_ASSIGN(FrameSpellChecker);
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(FrameSetSpellChecker);
|
||||
};
|
||||
|
||||
class SpellCheckerHolder : public content::RenderFrameObserver {
|
||||
public:
|
||||
// Find existing holder for the |render_frame|.
|
||||
static SpellCheckerHolder* FromRenderFrame(
|
||||
content::RenderFrame* render_frame) {
|
||||
for (auto* holder : instances_) {
|
||||
if (holder->render_frame() == render_frame)
|
||||
return holder;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
SpellCheckerHolder(content::RenderFrame* render_frame,
|
||||
std::unique_ptr<SpellCheckClient> spell_check_client)
|
||||
: content::RenderFrameObserver(render_frame),
|
||||
spell_check_client_(std::move(spell_check_client)) {
|
||||
DCHECK(!FromRenderFrame(render_frame));
|
||||
instances_.insert(this);
|
||||
}
|
||||
|
||||
~SpellCheckerHolder() final { instances_.erase(this); }
|
||||
|
||||
void UnsetAndDestroy() {
|
||||
FrameSetSpellChecker set_spell_checker(nullptr, render_frame());
|
||||
delete this;
|
||||
}
|
||||
|
||||
// RenderFrameObserver implementation.
|
||||
void OnDestruct() final {
|
||||
// Since we delete this in WillReleaseScriptContext, this method is unlikely
|
||||
// to be called, but override anyway since I'm not sure if there are some
|
||||
// corner cases.
|
||||
//
|
||||
// Note that while there are two "delete this", it is totally fine as the
|
||||
// observer unsubscribes automatically in destructor and the other one won't
|
||||
// be called.
|
||||
//
|
||||
// Also note that we should not call UnsetAndDestroy here, as the render
|
||||
// frame is going to be destroyed.
|
||||
delete this;
|
||||
}
|
||||
|
||||
void WillReleaseScriptContext(v8::Local<v8::Context> context,
|
||||
int world_id) final {
|
||||
// Unset spell checker when the script context is going to be released, as
|
||||
// the spell check implementation lives there.
|
||||
UnsetAndDestroy();
|
||||
}
|
||||
|
||||
private:
|
||||
static std::set<SpellCheckerHolder*> instances_;
|
||||
|
||||
std::unique_ptr<SpellCheckClient> spell_check_client_;
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
WebFrame::WebFrame(v8::Isolate* isolate)
|
||||
: web_frame_(blink::WebLocalFrame::FrameForCurrentContext()) {
|
||||
Init(isolate);
|
||||
// static
|
||||
std::set<SpellCheckerHolder*> SpellCheckerHolder::instances_;
|
||||
|
||||
void SetName(v8::Local<v8::Value> window, const std::string& name) {
|
||||
GetRenderFrame(window)->GetWebFrame()->SetName(
|
||||
blink::WebString::FromUTF8(name));
|
||||
}
|
||||
|
||||
WebFrame::WebFrame(v8::Isolate* isolate, blink::WebLocalFrame* blink_frame)
|
||||
: web_frame_(blink_frame) {
|
||||
Init(isolate);
|
||||
}
|
||||
|
||||
WebFrame::~WebFrame() {}
|
||||
|
||||
void WebFrame::SetName(const std::string& name) {
|
||||
web_frame_->SetName(blink::WebString::FromUTF8(name));
|
||||
}
|
||||
|
||||
double WebFrame::SetZoomLevel(double level) {
|
||||
double SetZoomLevel(v8::Local<v8::Value> window, double level) {
|
||||
double result = 0.0;
|
||||
content::RenderFrame* render_frame =
|
||||
content::RenderFrame::FromWebFrame(web_frame_);
|
||||
content::RenderFrame* render_frame = GetRenderFrame(window);
|
||||
render_frame->Send(new AtomFrameHostMsg_SetTemporaryZoomLevel(
|
||||
render_frame->GetRoutingID(), level, &result));
|
||||
return result;
|
||||
}
|
||||
|
||||
double WebFrame::GetZoomLevel() const {
|
||||
double GetZoomLevel(v8::Local<v8::Value> window) {
|
||||
double result = 0.0;
|
||||
content::RenderFrame* render_frame =
|
||||
content::RenderFrame::FromWebFrame(web_frame_);
|
||||
content::RenderFrame* render_frame = GetRenderFrame(window);
|
||||
render_frame->Send(
|
||||
new AtomFrameHostMsg_GetZoomLevel(render_frame->GetRoutingID(), &result));
|
||||
return result;
|
||||
}
|
||||
|
||||
double WebFrame::SetZoomFactor(double factor) {
|
||||
double SetZoomFactor(v8::Local<v8::Value> window, double factor) {
|
||||
return blink::WebView::ZoomLevelToZoomFactor(
|
||||
SetZoomLevel(blink::WebView::ZoomFactorToZoomLevel(factor)));
|
||||
SetZoomLevel(window, blink::WebView::ZoomFactorToZoomLevel(factor)));
|
||||
}
|
||||
|
||||
double WebFrame::GetZoomFactor() const {
|
||||
return blink::WebView::ZoomLevelToZoomFactor(GetZoomLevel());
|
||||
double GetZoomFactor(v8::Local<v8::Value> window) {
|
||||
return blink::WebView::ZoomLevelToZoomFactor(GetZoomLevel(window));
|
||||
}
|
||||
|
||||
void WebFrame::SetVisualZoomLevelLimits(double min_level, double max_level) {
|
||||
web_frame_->View()->SetDefaultPageScaleLimits(min_level, max_level);
|
||||
web_frame_->View()->SetIgnoreViewportTagScaleLimits(true);
|
||||
void SetVisualZoomLevelLimits(v8::Local<v8::Value> window,
|
||||
double min_level,
|
||||
double max_level) {
|
||||
blink::WebFrame* web_frame = GetRenderFrame(window)->GetWebFrame();
|
||||
web_frame->View()->SetDefaultPageScaleLimits(min_level, max_level);
|
||||
web_frame->View()->SetIgnoreViewportTagScaleLimits(true);
|
||||
}
|
||||
|
||||
void WebFrame::SetLayoutZoomLevelLimits(double min_level, double max_level) {
|
||||
web_frame_->View()->ZoomLimitsChanged(min_level, max_level);
|
||||
void SetLayoutZoomLevelLimits(v8::Local<v8::Value> window,
|
||||
double min_level,
|
||||
double max_level) {
|
||||
blink::WebFrame* web_frame = GetRenderFrame(window)->GetWebFrame();
|
||||
web_frame->View()->ZoomLimitsChanged(min_level, max_level);
|
||||
}
|
||||
|
||||
v8::Local<v8::Value> WebFrame::RegisterEmbedderCustomElement(
|
||||
v8::Local<v8::Value> RegisterEmbedderCustomElement(
|
||||
v8::Local<v8::Value> window,
|
||||
const base::string16& name,
|
||||
v8::Local<v8::Object> options) {
|
||||
return web_frame_->GetDocument().RegisterEmbedderCustomElement(
|
||||
blink::WebString::FromUTF16(name), options);
|
||||
return GetRenderFrame(window)
|
||||
->GetWebFrame()
|
||||
->GetDocument()
|
||||
.RegisterEmbedderCustomElement(blink::WebString::FromUTF16(name),
|
||||
options);
|
||||
}
|
||||
|
||||
int WebFrame::GetWebFrameId(v8::Local<v8::Value> content_window) {
|
||||
int GetWebFrameId(v8::Local<v8::Value> window,
|
||||
v8::Local<v8::Value> content_window) {
|
||||
// Get the WebLocalFrame before (possibly) executing any user-space JS while
|
||||
// getting the |params|. We track the status of the RenderFrame via an
|
||||
// observer in case it is deleted during user code execution.
|
||||
@@ -213,34 +273,42 @@ int WebFrame::GetWebFrameId(v8::Local<v8::Value> content_window) {
|
||||
return render_frame->GetRoutingID();
|
||||
}
|
||||
|
||||
void WebFrame::SetSpellCheckProvider(mate::Arguments* args,
|
||||
const std::string& language,
|
||||
bool auto_spell_correct_turned_on,
|
||||
v8::Local<v8::Object> provider) {
|
||||
void SetSpellCheckProvider(mate::Arguments* args,
|
||||
v8::Local<v8::Value> window,
|
||||
const std::string& language,
|
||||
bool auto_spell_correct_turned_on,
|
||||
v8::Local<v8::Object> provider) {
|
||||
if (!provider->Has(mate::StringToV8(args->isolate(), "spellCheck"))) {
|
||||
args->ThrowError("\"spellCheck\" has to be defined");
|
||||
return;
|
||||
}
|
||||
|
||||
auto client = std::make_unique<SpellCheckClient>(
|
||||
language, auto_spell_correct_turned_on, args->isolate(), provider);
|
||||
// Remove the old client.
|
||||
content::RenderFrame* render_frame = GetRenderFrame(window);
|
||||
auto* existing = SpellCheckerHolder::FromRenderFrame(render_frame);
|
||||
if (existing)
|
||||
existing->UnsetAndDestroy();
|
||||
|
||||
// Set spellchecker for all live frames in the same process or
|
||||
// in the sandbox mode for all live sub frames to this WebFrame.
|
||||
FrameSpellChecker spell_checker(
|
||||
client.get(), content::RenderFrame::FromWebFrame(web_frame_));
|
||||
content::RenderFrame::ForEach(&spell_checker);
|
||||
spell_check_client_.swap(client);
|
||||
web_frame_->SetSpellCheckPanelHostClient(spell_check_client_.get());
|
||||
auto spell_check_client = std::make_unique<SpellCheckClient>(
|
||||
language, auto_spell_correct_turned_on, args->isolate(), provider);
|
||||
FrameSetSpellChecker spell_checker(spell_check_client.get(), render_frame);
|
||||
|
||||
// Attach the spell checker to RenderFrame.
|
||||
new SpellCheckerHolder(render_frame, std::move(spell_check_client));
|
||||
}
|
||||
|
||||
void WebFrame::RegisterURLSchemeAsBypassingCSP(const std::string& scheme) {
|
||||
void RegisterURLSchemeAsBypassingCSP(v8::Local<v8::Value> window,
|
||||
const std::string& scheme) {
|
||||
// Register scheme to bypass pages's Content Security Policy.
|
||||
blink::SchemeRegistry::RegisterURLSchemeAsBypassingContentSecurityPolicy(
|
||||
WTF::String::FromUTF8(scheme.data(), scheme.length()));
|
||||
}
|
||||
|
||||
void WebFrame::RegisterURLSchemeAsPrivileged(const std::string& scheme,
|
||||
mate::Arguments* args) {
|
||||
void RegisterURLSchemeAsPrivileged(v8::Local<v8::Value> window,
|
||||
const std::string& scheme,
|
||||
mate::Arguments* args) {
|
||||
// TODO(deepak1556): blink::SchemeRegistry methods should be called
|
||||
// before any renderer threads are created. Fixing this would break
|
||||
// current api. Change it with 2.0.
|
||||
@@ -251,7 +319,7 @@ void WebFrame::RegisterURLSchemeAsPrivileged(const std::string& scheme,
|
||||
bool allowServiceWorkers = true;
|
||||
bool supportFetchAPI = true;
|
||||
bool corsEnabled = true;
|
||||
if (args->Length() == 2) {
|
||||
if (args->Length() == 3) {
|
||||
mate::Dictionary options;
|
||||
if (args->GetNext(&options)) {
|
||||
options.Get("secure", &secure);
|
||||
@@ -281,30 +349,42 @@ void WebFrame::RegisterURLSchemeAsPrivileged(const std::string& scheme,
|
||||
}
|
||||
}
|
||||
|
||||
void WebFrame::InsertText(const std::string& text) {
|
||||
web_frame_->FrameWidget()->GetActiveWebInputMethodController()->CommitText(
|
||||
blink::WebString::FromUTF8(text),
|
||||
blink::WebVector<blink::WebImeTextSpan>(), blink::WebRange(), 0);
|
||||
void InsertText(v8::Local<v8::Value> window, const std::string& text) {
|
||||
blink::WebFrame* web_frame = GetRenderFrame(window)->GetWebFrame();
|
||||
if (web_frame->IsWebLocalFrame()) {
|
||||
web_frame->ToWebLocalFrame()
|
||||
->FrameWidget()
|
||||
->GetActiveWebInputMethodController()
|
||||
->CommitText(blink::WebString::FromUTF8(text),
|
||||
blink::WebVector<blink::WebImeTextSpan>(),
|
||||
blink::WebRange(), 0);
|
||||
}
|
||||
}
|
||||
|
||||
void WebFrame::InsertCSS(const std::string& css) {
|
||||
web_frame_->GetDocument().InsertStyleSheet(blink::WebString::FromUTF8(css));
|
||||
void InsertCSS(v8::Local<v8::Value> window, const std::string& css) {
|
||||
blink::WebFrame* web_frame = GetRenderFrame(window)->GetWebFrame();
|
||||
if (web_frame->IsWebLocalFrame()) {
|
||||
web_frame->ToWebLocalFrame()->GetDocument().InsertStyleSheet(
|
||||
blink::WebString::FromUTF8(css));
|
||||
}
|
||||
}
|
||||
|
||||
void WebFrame::ExecuteJavaScript(const base::string16& code,
|
||||
mate::Arguments* args) {
|
||||
void ExecuteJavaScript(v8::Local<v8::Value> window,
|
||||
const base::string16& code,
|
||||
mate::Arguments* args) {
|
||||
bool has_user_gesture = false;
|
||||
args->GetNext(&has_user_gesture);
|
||||
ScriptExecutionCallback::CompletionCallback completion_callback;
|
||||
args->GetNext(&completion_callback);
|
||||
std::unique_ptr<blink::WebScriptExecutionCallback> callback(
|
||||
new ScriptExecutionCallback(completion_callback));
|
||||
web_frame_->RequestExecuteScriptAndReturnValue(
|
||||
GetRenderFrame(window)->GetWebFrame()->RequestExecuteScriptAndReturnValue(
|
||||
blink::WebScriptSource(blink::WebString::FromUTF16(code)),
|
||||
has_user_gesture, callback.release());
|
||||
}
|
||||
|
||||
void WebFrame::ExecuteJavaScriptInIsolatedWorld(
|
||||
void ExecuteJavaScriptInIsolatedWorld(
|
||||
v8::Local<v8::Value> window,
|
||||
int world_id,
|
||||
const std::vector<mate::Dictionary>& scripts,
|
||||
mate::Arguments* args) {
|
||||
@@ -339,186 +419,131 @@ void WebFrame::ExecuteJavaScriptInIsolatedWorld(
|
||||
std::unique_ptr<blink::WebScriptExecutionCallback> callback(
|
||||
new ScriptExecutionCallback(completion_callback));
|
||||
|
||||
web_frame_->RequestExecuteScriptInIsolatedWorld(
|
||||
GetRenderFrame(window)->GetWebFrame()->RequestExecuteScriptInIsolatedWorld(
|
||||
world_id, &sources.front(), sources.size(), has_user_gesture,
|
||||
scriptExecutionType, callback.release());
|
||||
}
|
||||
|
||||
void WebFrame::SetIsolatedWorldSecurityOrigin(int world_id,
|
||||
const std::string& origin_url) {
|
||||
web_frame_->SetIsolatedWorldSecurityOrigin(
|
||||
void SetIsolatedWorldSecurityOrigin(v8::Local<v8::Value> window,
|
||||
int world_id,
|
||||
const std::string& origin_url) {
|
||||
GetRenderFrame(window)->GetWebFrame()->SetIsolatedWorldSecurityOrigin(
|
||||
world_id, blink::WebSecurityOrigin::CreateFromString(
|
||||
blink::WebString::FromUTF8(origin_url)));
|
||||
}
|
||||
|
||||
void WebFrame::SetIsolatedWorldContentSecurityPolicy(
|
||||
int world_id,
|
||||
const std::string& security_policy) {
|
||||
web_frame_->SetIsolatedWorldContentSecurityPolicy(
|
||||
void SetIsolatedWorldContentSecurityPolicy(v8::Local<v8::Value> window,
|
||||
int world_id,
|
||||
const std::string& security_policy) {
|
||||
GetRenderFrame(window)->GetWebFrame()->SetIsolatedWorldContentSecurityPolicy(
|
||||
world_id, blink::WebString::FromUTF8(security_policy));
|
||||
}
|
||||
|
||||
void WebFrame::SetIsolatedWorldHumanReadableName(int world_id,
|
||||
const std::string& name) {
|
||||
web_frame_->SetIsolatedWorldHumanReadableName(
|
||||
void SetIsolatedWorldHumanReadableName(v8::Local<v8::Value> window,
|
||||
int world_id,
|
||||
const std::string& name) {
|
||||
GetRenderFrame(window)->GetWebFrame()->SetIsolatedWorldHumanReadableName(
|
||||
world_id, blink::WebString::FromUTF8(name));
|
||||
}
|
||||
|
||||
// static
|
||||
mate::Handle<WebFrame> WebFrame::Create(v8::Isolate* isolate) {
|
||||
return mate::CreateHandle(isolate, new WebFrame(isolate));
|
||||
}
|
||||
|
||||
blink::WebCache::ResourceTypeStats WebFrame::GetResourceUsage(
|
||||
v8::Isolate* isolate) {
|
||||
blink::WebCache::ResourceTypeStats GetResourceUsage(v8::Isolate* isolate) {
|
||||
blink::WebCache::ResourceTypeStats stats;
|
||||
blink::WebCache::GetResourceTypeStats(&stats);
|
||||
return stats;
|
||||
}
|
||||
|
||||
void WebFrame::ClearCache(v8::Isolate* isolate) {
|
||||
void ClearCache(v8::Isolate* isolate) {
|
||||
isolate->IdleNotificationDeadline(0.5);
|
||||
blink::WebCache::Clear();
|
||||
base::MemoryPressureListener::NotifyMemoryPressure(
|
||||
base::MemoryPressureListener::MEMORY_PRESSURE_LEVEL_CRITICAL);
|
||||
}
|
||||
|
||||
v8::Local<v8::Value> WebFrame::Opener() const {
|
||||
blink::WebFrame* frame = web_frame_->Opener();
|
||||
if (frame && frame->IsWebLocalFrame())
|
||||
return mate::CreateHandle(isolate(),
|
||||
new WebFrame(isolate(), frame->ToWebLocalFrame()))
|
||||
.ToV8();
|
||||
else
|
||||
return v8::Null(isolate());
|
||||
}
|
||||
|
||||
v8::Local<v8::Value> WebFrame::Parent() const {
|
||||
blink::WebFrame* frame = web_frame_->Parent();
|
||||
if (frame && frame->IsWebLocalFrame())
|
||||
return mate::CreateHandle(isolate(),
|
||||
new WebFrame(isolate(), frame->ToWebLocalFrame()))
|
||||
.ToV8();
|
||||
else
|
||||
return v8::Null(isolate());
|
||||
}
|
||||
|
||||
v8::Local<v8::Value> WebFrame::Top() const {
|
||||
blink::WebFrame* frame = web_frame_->Top();
|
||||
if (frame && frame->IsWebLocalFrame())
|
||||
return mate::CreateHandle(isolate(),
|
||||
new WebFrame(isolate(), frame->ToWebLocalFrame()))
|
||||
.ToV8();
|
||||
else
|
||||
return v8::Null(isolate());
|
||||
}
|
||||
|
||||
v8::Local<v8::Value> WebFrame::FirstChild() const {
|
||||
blink::WebFrame* frame = web_frame_->FirstChild();
|
||||
if (frame && frame->IsWebLocalFrame())
|
||||
return mate::CreateHandle(isolate(),
|
||||
new WebFrame(isolate(), frame->ToWebLocalFrame()))
|
||||
.ToV8();
|
||||
else
|
||||
return v8::Null(isolate());
|
||||
}
|
||||
|
||||
v8::Local<v8::Value> WebFrame::NextSibling() const {
|
||||
blink::WebFrame* frame = web_frame_->NextSibling();
|
||||
if (frame && frame->IsWebLocalFrame())
|
||||
return mate::CreateHandle(isolate(),
|
||||
new WebFrame(isolate(), frame->ToWebLocalFrame()))
|
||||
.ToV8();
|
||||
else
|
||||
return v8::Null(isolate());
|
||||
}
|
||||
|
||||
v8::Local<v8::Value> WebFrame::GetFrameForSelector(
|
||||
const std::string& selector) const {
|
||||
blink::WebElement element = web_frame_->GetDocument().QuerySelector(
|
||||
blink::WebString::FromUTF8(selector));
|
||||
blink::WebLocalFrame* element_frame =
|
||||
blink::WebLocalFrame::FromFrameOwnerElement(element);
|
||||
if (element_frame)
|
||||
return mate::CreateHandle(isolate(), new WebFrame(isolate(), element_frame))
|
||||
.ToV8();
|
||||
else
|
||||
return v8::Null(isolate());
|
||||
}
|
||||
|
||||
v8::Local<v8::Value> WebFrame::FindFrameByName(const std::string& name) const {
|
||||
blink::WebLocalFrame* local_frame =
|
||||
web_frame_->FindFrameByName(blink::WebString::FromUTF8(name))
|
||||
->ToWebLocalFrame();
|
||||
if (local_frame)
|
||||
return mate::CreateHandle(isolate(), new WebFrame(isolate(), local_frame))
|
||||
.ToV8();
|
||||
else
|
||||
return v8::Null(isolate());
|
||||
}
|
||||
|
||||
v8::Local<v8::Value> WebFrame::FindFrameByRoutingId(int routing_id) const {
|
||||
v8::Local<v8::Value> FindFrameByRoutingId(v8::Isolate* isolate,
|
||||
v8::Local<v8::Value> window,
|
||||
int routing_id) {
|
||||
content::RenderFrame* render_frame =
|
||||
content::RenderFrame::FromRoutingID(routing_id);
|
||||
blink::WebLocalFrame* local_frame = nullptr;
|
||||
if (render_frame)
|
||||
local_frame = render_frame->GetWebFrame();
|
||||
if (local_frame)
|
||||
return mate::CreateHandle(isolate(), new WebFrame(isolate(), local_frame))
|
||||
.ToV8();
|
||||
return render_frame->GetWebFrame()->MainWorldScriptContext()->Global();
|
||||
else
|
||||
return v8::Null(isolate());
|
||||
return v8::Null(isolate);
|
||||
}
|
||||
|
||||
v8::Local<v8::Value> WebFrame::RoutingId() const {
|
||||
int routing_id = content::RenderFrame::GetRoutingIdForWebFrame(web_frame_);
|
||||
return v8::Number::New(isolate(), routing_id);
|
||||
v8::Local<v8::Value> GetOpener(v8::Isolate* isolate,
|
||||
v8::Local<v8::Value> window) {
|
||||
blink::WebFrame* frame = GetRenderFrame(window)->GetWebFrame()->Opener();
|
||||
if (frame && frame->IsWebLocalFrame())
|
||||
return frame->ToWebLocalFrame()->MainWorldScriptContext()->Global();
|
||||
else
|
||||
return v8::Null(isolate);
|
||||
}
|
||||
|
||||
// static
|
||||
void WebFrame::BuildPrototype(v8::Isolate* isolate,
|
||||
v8::Local<v8::FunctionTemplate> prototype) {
|
||||
prototype->SetClassName(mate::StringToV8(isolate, "WebFrame"));
|
||||
mate::ObjectTemplateBuilder(isolate, prototype->PrototypeTemplate())
|
||||
.SetMethod("setName", &WebFrame::SetName)
|
||||
.SetMethod("setZoomLevel", &WebFrame::SetZoomLevel)
|
||||
.SetMethod("getZoomLevel", &WebFrame::GetZoomLevel)
|
||||
.SetMethod("setZoomFactor", &WebFrame::SetZoomFactor)
|
||||
.SetMethod("getZoomFactor", &WebFrame::GetZoomFactor)
|
||||
.SetMethod("setVisualZoomLevelLimits",
|
||||
&WebFrame::SetVisualZoomLevelLimits)
|
||||
.SetMethod("setLayoutZoomLevelLimits",
|
||||
&WebFrame::SetLayoutZoomLevelLimits)
|
||||
.SetMethod("registerEmbedderCustomElement",
|
||||
&WebFrame::RegisterEmbedderCustomElement)
|
||||
.SetMethod("getWebFrameId", &WebFrame::GetWebFrameId)
|
||||
.SetMethod("setSpellCheckProvider", &WebFrame::SetSpellCheckProvider)
|
||||
.SetMethod("registerURLSchemeAsBypassingCSP",
|
||||
&WebFrame::RegisterURLSchemeAsBypassingCSP)
|
||||
.SetMethod("registerURLSchemeAsPrivileged",
|
||||
&WebFrame::RegisterURLSchemeAsPrivileged)
|
||||
.SetMethod("insertText", &WebFrame::InsertText)
|
||||
.SetMethod("insertCSS", &WebFrame::InsertCSS)
|
||||
.SetMethod("executeJavaScript", &WebFrame::ExecuteJavaScript)
|
||||
.SetMethod("executeJavaScriptInIsolatedWorld",
|
||||
&WebFrame::ExecuteJavaScriptInIsolatedWorld)
|
||||
.SetMethod("setIsolatedWorldSecurityOrigin",
|
||||
&WebFrame::SetIsolatedWorldSecurityOrigin)
|
||||
.SetMethod("setIsolatedWorldContentSecurityPolicy",
|
||||
&WebFrame::SetIsolatedWorldContentSecurityPolicy)
|
||||
.SetMethod("setIsolatedWorldHumanReadableName",
|
||||
&WebFrame::SetIsolatedWorldHumanReadableName)
|
||||
.SetMethod("getResourceUsage", &WebFrame::GetResourceUsage)
|
||||
.SetMethod("clearCache", &WebFrame::ClearCache)
|
||||
.SetMethod("getFrameForSelector", &WebFrame::GetFrameForSelector)
|
||||
.SetMethod("findFrameByName", &WebFrame::FindFrameByName)
|
||||
.SetProperty("opener", &WebFrame::Opener)
|
||||
.SetProperty("parent", &WebFrame::Parent)
|
||||
.SetProperty("top", &WebFrame::Top)
|
||||
.SetProperty("firstChild", &WebFrame::FirstChild)
|
||||
.SetProperty("nextSibling", &WebFrame::NextSibling)
|
||||
.SetProperty("routingId", &WebFrame::RoutingId)
|
||||
.SetMethod("findFrameByRoutingId", &WebFrame::FindFrameByRoutingId);
|
||||
v8::Local<v8::Value> GetFrameParent(v8::Isolate* isolate,
|
||||
v8::Local<v8::Value> window) {
|
||||
blink::WebFrame* frame = GetRenderFrame(window)->GetWebFrame()->Parent();
|
||||
if (frame && frame->IsWebLocalFrame())
|
||||
return frame->ToWebLocalFrame()->MainWorldScriptContext()->Global();
|
||||
else
|
||||
return v8::Null(isolate);
|
||||
}
|
||||
|
||||
v8::Local<v8::Value> GetTop(v8::Isolate* isolate, v8::Local<v8::Value> window) {
|
||||
blink::WebFrame* frame = GetRenderFrame(window)->GetWebFrame()->Top();
|
||||
if (frame && frame->IsWebLocalFrame())
|
||||
return frame->ToWebLocalFrame()->MainWorldScriptContext()->Global();
|
||||
else
|
||||
return v8::Null(isolate);
|
||||
}
|
||||
|
||||
v8::Local<v8::Value> GetFirstChild(v8::Isolate* isolate,
|
||||
v8::Local<v8::Value> window) {
|
||||
blink::WebFrame* frame = GetRenderFrame(window)->GetWebFrame()->FirstChild();
|
||||
if (frame && frame->IsWebLocalFrame())
|
||||
return frame->ToWebLocalFrame()->MainWorldScriptContext()->Global();
|
||||
else
|
||||
return v8::Null(isolate);
|
||||
}
|
||||
|
||||
v8::Local<v8::Value> GetNextSibling(v8::Isolate* isolate,
|
||||
v8::Local<v8::Value> window) {
|
||||
blink::WebFrame* frame = GetRenderFrame(window)->GetWebFrame()->NextSibling();
|
||||
if (frame && frame->IsWebLocalFrame())
|
||||
return frame->ToWebLocalFrame()->MainWorldScriptContext()->Global();
|
||||
else
|
||||
return v8::Null(isolate);
|
||||
}
|
||||
|
||||
v8::Local<v8::Value> GetFrameForSelector(v8::Isolate* isolate,
|
||||
v8::Local<v8::Value> window,
|
||||
const std::string& selector) {
|
||||
blink::WebElement element =
|
||||
GetRenderFrame(window)->GetWebFrame()->GetDocument().QuerySelector(
|
||||
blink::WebString::FromUTF8(selector));
|
||||
if (element.IsNull()) // not found
|
||||
return v8::Null(isolate);
|
||||
|
||||
blink::WebFrame* frame = blink::WebFrame::FromFrameOwnerElement(element);
|
||||
if (frame && frame->IsWebLocalFrame())
|
||||
return frame->ToWebLocalFrame()->MainWorldScriptContext()->Global();
|
||||
else
|
||||
return v8::Null(isolate);
|
||||
}
|
||||
|
||||
v8::Local<v8::Value> FindFrameByName(v8::Isolate* isolate,
|
||||
v8::Local<v8::Value> window,
|
||||
const std::string& name) {
|
||||
blink::WebFrame* frame =
|
||||
GetRenderFrame(window)->GetWebFrame()->FindFrameByName(
|
||||
blink::WebString::FromUTF8(name));
|
||||
if (frame && frame->IsWebLocalFrame())
|
||||
return frame->ToWebLocalFrame()->MainWorldScriptContext()->Global();
|
||||
else
|
||||
return v8::Null(isolate);
|
||||
}
|
||||
|
||||
int GetRoutingId(v8::Local<v8::Value> window) {
|
||||
return GetRenderFrame(window)->GetRoutingID();
|
||||
}
|
||||
|
||||
} // namespace api
|
||||
@@ -527,16 +552,51 @@ void WebFrame::BuildPrototype(v8::Isolate* isolate,
|
||||
|
||||
namespace {
|
||||
|
||||
using atom::api::WebFrame;
|
||||
|
||||
void Initialize(v8::Local<v8::Object> exports,
|
||||
v8::Local<v8::Value> unused,
|
||||
v8::Local<v8::Context> context,
|
||||
void* priv) {
|
||||
using namespace atom::api; // NOLINT(build/namespaces)
|
||||
|
||||
v8::Isolate* isolate = context->GetIsolate();
|
||||
mate::Dictionary dict(isolate, exports);
|
||||
dict.Set("webFrame", WebFrame::Create(isolate));
|
||||
dict.Set("WebFrame", WebFrame::GetConstructor(isolate)->GetFunction());
|
||||
dict.SetMethod("setName", &SetName);
|
||||
dict.SetMethod("setZoomLevel", &SetZoomLevel);
|
||||
dict.SetMethod("getZoomLevel", &GetZoomLevel);
|
||||
dict.SetMethod("setZoomFactor", &SetZoomFactor);
|
||||
dict.SetMethod("getZoomFactor", &GetZoomFactor);
|
||||
dict.SetMethod("setVisualZoomLevelLimits", &SetVisualZoomLevelLimits);
|
||||
dict.SetMethod("setLayoutZoomLevelLimits", &SetLayoutZoomLevelLimits);
|
||||
dict.SetMethod("registerEmbedderCustomElement",
|
||||
&RegisterEmbedderCustomElement);
|
||||
dict.SetMethod("getWebFrameId", &GetWebFrameId);
|
||||
dict.SetMethod("setSpellCheckProvider", &SetSpellCheckProvider);
|
||||
dict.SetMethod("registerURLSchemeAsBypassingCSP",
|
||||
&RegisterURLSchemeAsBypassingCSP);
|
||||
dict.SetMethod("registerURLSchemeAsPrivileged",
|
||||
&RegisterURLSchemeAsPrivileged);
|
||||
dict.SetMethod("insertText", &InsertText);
|
||||
dict.SetMethod("insertCSS", &InsertCSS);
|
||||
dict.SetMethod("executeJavaScript", &ExecuteJavaScript);
|
||||
dict.SetMethod("executeJavaScriptInIsolatedWorld",
|
||||
&ExecuteJavaScriptInIsolatedWorld);
|
||||
dict.SetMethod("setIsolatedWorldSecurityOrigin",
|
||||
&SetIsolatedWorldSecurityOrigin);
|
||||
dict.SetMethod("setIsolatedWorldContentSecurityPolicy",
|
||||
&SetIsolatedWorldContentSecurityPolicy);
|
||||
dict.SetMethod("setIsolatedWorldHumanReadableName",
|
||||
&SetIsolatedWorldHumanReadableName);
|
||||
dict.SetMethod("getResourceUsage", &GetResourceUsage);
|
||||
dict.SetMethod("clearCache", &ClearCache);
|
||||
dict.SetMethod("_findFrameByRoutingId", &FindFrameByRoutingId);
|
||||
dict.SetMethod("_getFrameForSelector", &GetFrameForSelector);
|
||||
dict.SetMethod("_findFrameByName", &FindFrameByName);
|
||||
dict.SetMethod("_getOpener", &GetOpener);
|
||||
dict.SetMethod("_getParent", &GetFrameParent);
|
||||
dict.SetMethod("_getTop", &GetTop);
|
||||
dict.SetMethod("_getFirstChild", &GetFirstChild);
|
||||
dict.SetMethod("_getNextSibling", &GetNextSibling);
|
||||
dict.SetMethod("_getRoutingId", &GetRoutingId);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
@@ -1,113 +0,0 @@
|
||||
// Copyright (c) 2014 GitHub, Inc.
|
||||
// Use of this source code is governed by the MIT license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#ifndef ATOM_RENDERER_API_ATOM_API_WEB_FRAME_H_
|
||||
#define ATOM_RENDERER_API_ATOM_API_WEB_FRAME_H_
|
||||
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "native_mate/handle.h"
|
||||
#include "native_mate/wrappable.h"
|
||||
#include "third_party/WebKit/public/platform/WebCache.h"
|
||||
|
||||
namespace blink {
|
||||
class WebLocalFrame;
|
||||
}
|
||||
|
||||
namespace mate {
|
||||
class Dictionary;
|
||||
class Arguments;
|
||||
} // namespace mate
|
||||
|
||||
namespace atom {
|
||||
|
||||
namespace api {
|
||||
|
||||
class SpellCheckClient;
|
||||
|
||||
class WebFrame : public mate::Wrappable<WebFrame> {
|
||||
public:
|
||||
static mate::Handle<WebFrame> Create(v8::Isolate* isolate);
|
||||
|
||||
static void BuildPrototype(v8::Isolate* isolate,
|
||||
v8::Local<v8::FunctionTemplate> prototype);
|
||||
|
||||
private:
|
||||
explicit WebFrame(v8::Isolate* isolate);
|
||||
explicit WebFrame(v8::Isolate* isolate, blink::WebLocalFrame* blink_frame);
|
||||
~WebFrame() override;
|
||||
|
||||
void SetName(const std::string& name);
|
||||
|
||||
double SetZoomLevel(double level);
|
||||
double GetZoomLevel() const;
|
||||
double SetZoomFactor(double factor);
|
||||
double GetZoomFactor() const;
|
||||
|
||||
void SetVisualZoomLevelLimits(double min_level, double max_level);
|
||||
void SetLayoutZoomLevelLimits(double min_level, double max_level);
|
||||
|
||||
v8::Local<v8::Value> RegisterEmbedderCustomElement(
|
||||
const base::string16& name,
|
||||
v8::Local<v8::Object> options);
|
||||
int GetWebFrameId(v8::Local<v8::Value> content_window);
|
||||
|
||||
// Set the provider that will be used by SpellCheckClient for spell check.
|
||||
void SetSpellCheckProvider(mate::Arguments* args,
|
||||
const std::string& language,
|
||||
bool auto_spell_correct_turned_on,
|
||||
v8::Local<v8::Object> provider);
|
||||
|
||||
void RegisterURLSchemeAsBypassingCSP(const std::string& scheme);
|
||||
void RegisterURLSchemeAsPrivileged(const std::string& scheme,
|
||||
mate::Arguments* args);
|
||||
|
||||
// Editing.
|
||||
void InsertText(const std::string& text);
|
||||
void InsertCSS(const std::string& css);
|
||||
|
||||
// Executing scripts.
|
||||
void ExecuteJavaScript(const base::string16& code, mate::Arguments* args);
|
||||
void ExecuteJavaScriptInIsolatedWorld(
|
||||
int world_id,
|
||||
const std::vector<mate::Dictionary>& scripts,
|
||||
mate::Arguments* args);
|
||||
|
||||
// Isolated world related methods
|
||||
void SetIsolatedWorldSecurityOrigin(int world_id,
|
||||
const std::string& origin_url);
|
||||
void SetIsolatedWorldContentSecurityPolicy(
|
||||
int world_id,
|
||||
const std::string& security_policy);
|
||||
void SetIsolatedWorldHumanReadableName(int world_id, const std::string& name);
|
||||
|
||||
// Resource related methods
|
||||
blink::WebCache::ResourceTypeStats GetResourceUsage(v8::Isolate* isolate);
|
||||
void ClearCache(v8::Isolate* isolate);
|
||||
|
||||
// Frame navigation
|
||||
v8::Local<v8::Value> Opener() const;
|
||||
v8::Local<v8::Value> Parent() const;
|
||||
v8::Local<v8::Value> Top() const;
|
||||
v8::Local<v8::Value> FirstChild() const;
|
||||
v8::Local<v8::Value> NextSibling() const;
|
||||
v8::Local<v8::Value> GetFrameForSelector(const std::string& selector) const;
|
||||
v8::Local<v8::Value> FindFrameByName(const std::string& name) const;
|
||||
v8::Local<v8::Value> FindFrameByRoutingId(int routing_id) const;
|
||||
v8::Local<v8::Value> RoutingId() const;
|
||||
|
||||
std::unique_ptr<SpellCheckClient> spell_check_client_;
|
||||
|
||||
blink::WebLocalFrame* web_frame_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(WebFrame);
|
||||
};
|
||||
|
||||
} // namespace api
|
||||
|
||||
} // namespace atom
|
||||
|
||||
#endif // ATOM_RENDERER_API_ATOM_API_WEB_FRAME_H_
|
||||
@@ -222,11 +222,11 @@ It creates a new `BrowserWindow` with native properties as set by the `options`.
|
||||
the top left.
|
||||
* `hiddenInset` - Results in a hidden title bar with an alternative look
|
||||
where the traffic light buttons are slightly more inset from the window edge.
|
||||
* `customButtonsOnHover` Boolean (optional) - Draw custom close, minimize,
|
||||
and full screen buttons on macOS frameless windows. These buttons will not
|
||||
display unless hovered over in the top left of the window. These custom
|
||||
buttons prevent issues with mouse events that occur with the standard
|
||||
window toolbar buttons. **Note:** This option is currently experimental.
|
||||
* `customButtonsOnHover` Boolean (optional) - Draw custom close,
|
||||
and minimize buttons on macOS frameless windows. These buttons will not display
|
||||
unless hovered over in the top left of the window. These custom buttons prevent
|
||||
issues with mouse events that occur with the standard window toolbar buttons.
|
||||
**Note:** This option is currently experimental.
|
||||
* `fullscreenWindowTitle` Boolean (optional) - Shows the title in the
|
||||
title bar in full screen mode on macOS for all `titleBarStyle` options.
|
||||
Default is `false`.
|
||||
|
||||
@@ -51,9 +51,7 @@ Once all child processes have acknowledged the `getCategories` request the
|
||||
|
||||
### `contentTracing.startRecording(options, callback)`
|
||||
|
||||
* `options` Object
|
||||
* `categoryFilter` String
|
||||
* `traceOptions` String
|
||||
* `options` ([TraceCategoriesAndOptions](structures/trace-categories-and-options.md) | [TraceConfig](structures/trace-config.md))
|
||||
* `callback` Function
|
||||
|
||||
Start recording on all processes.
|
||||
@@ -62,35 +60,6 @@ Recording begins immediately locally and asynchronously on child processes
|
||||
as soon as they receive the EnableRecording request. The `callback` will be
|
||||
called once all child processes have acknowledged the `startRecording` request.
|
||||
|
||||
`categoryFilter` is a filter to control what category groups should be
|
||||
traced. A filter can have an optional `-` prefix to exclude category groups
|
||||
that contain a matching category. Having both included and excluded
|
||||
category patterns in the same list is not supported.
|
||||
|
||||
Examples:
|
||||
|
||||
* `test_MyTest*`,
|
||||
* `test_MyTest*,test_OtherStuff`,
|
||||
* `"-excluded_category1,-excluded_category2`
|
||||
|
||||
`traceOptions` controls what kind of tracing is enabled, it is a comma-delimited
|
||||
list. Possible options are:
|
||||
|
||||
* `record-until-full`
|
||||
* `record-continuously`
|
||||
* `trace-to-console`
|
||||
* `enable-sampling`
|
||||
* `enable-systrace`
|
||||
|
||||
The first 3 options are trace recording modes and hence mutually exclusive.
|
||||
If more than one trace recording modes appear in the `traceOptions` string,
|
||||
the last one takes precedence. If none of the trace recording modes are
|
||||
specified, recording mode is `record-until-full`.
|
||||
|
||||
The trace option will first be reset to the default option (`record_mode` set to
|
||||
`record-until-full`, `enable_sampling` and `enable_systrace` set to `false`)
|
||||
before options parsed from `traceOptions` are applied on it.
|
||||
|
||||
### `contentTracing.stopRecording(resultFilePath, callback)`
|
||||
|
||||
* `resultFilePath` String
|
||||
|
||||
@@ -50,10 +50,12 @@ win.show()
|
||||
|
||||
#### `customButtonsOnHover`
|
||||
|
||||
Uses custom drawn close, miniaturize, and fullscreen buttons that display
|
||||
when hovering in the top left of the window. These custom buttons prevent issues
|
||||
with mouse events that occur with the standard window toolbar buttons. This
|
||||
option is only applicable for frameless windows.
|
||||
Uses custom drawn close, and miniaturize buttons that display
|
||||
when hovering in the top left of the window. The fullscreen button
|
||||
is not available due to restrictions of frameless windows as they
|
||||
interface with Apple's MacOS window masks. These custom buttons prevent
|
||||
issues with mouse events that occur with the standard window toolbar buttons.
|
||||
This option is only applicable for frameless windows.
|
||||
|
||||
```javascript
|
||||
const {BrowserWindow} = require('electron')
|
||||
|
||||
@@ -54,6 +54,14 @@ When the accelerator is already taken by other applications, this call will
|
||||
silently fail. This behavior is intended by operating systems, since they don't
|
||||
want applications to fight for global shortcuts.
|
||||
|
||||
The following accelerators will not be registered successfully on macOS 10.14 Mojave unless
|
||||
the app has been authorized as a [trusted accessibility client](https://developer.apple.com/library/archive/documentation/Accessibility/Conceptual/AccessibilityMacOSX/OSXAXTestingApps.html):
|
||||
|
||||
* "Media Play/Pause"
|
||||
* "Media Next Track"
|
||||
* "Media Previous Track"
|
||||
* "Media Stop"
|
||||
|
||||
### `globalShortcut.isRegistered(accelerator)`
|
||||
|
||||
* `accelerator` [Accelerator](accelerator.md)
|
||||
|
||||
@@ -27,6 +27,8 @@ See [`Menu`](menu.md) for examples.
|
||||
* `visible` Boolean (optional) - If false, the menu item will be entirely hidden.
|
||||
* `checked` Boolean (optional) - Should only be specified for `checkbox` or `radio` type
|
||||
menu items.
|
||||
* `registerAccelerator` Boolean (optional) - If false, the accelerator won't be registered
|
||||
with the system, but it will still be displayed. Defaults to true.
|
||||
* `submenu` (MenuItemConstructorOptions[] | [Menu](menu.md)) (optional) - Should be specified for `submenu` type menu items. If
|
||||
`submenu` is specified, the `type: 'submenu'` can be omitted. If the value
|
||||
is not a [`Menu`](menu.md) then it will be automatically converted to one using
|
||||
|
||||
18
docs/api/structures/trace-categories-and-options.md
Normal file
18
docs/api/structures/trace-categories-and-options.md
Normal file
@@ -0,0 +1,18 @@
|
||||
# TraceCategoriesAndOptions Object
|
||||
|
||||
* `categoryFilter` String – is a filter to control what category groups
|
||||
should be traced. A filter can have an optional `-` prefix to exclude
|
||||
category groups that contain a matching category. Having both included
|
||||
and excluded category patterns in the same list is not supported. Examples:
|
||||
`test_MyTest*`, `test_MyTest*,test_OtherStuff`, `-excluded_category1,-excluded_category2`.
|
||||
* `traceOptions` String - Controls what kind of tracing is enabled,
|
||||
it is a comma-delimited sequence of the following strings:
|
||||
`record-until-full`, `record-continuously`, `trace-to-console`, `enable-sampling`, `enable-systrace`,
|
||||
e.g. `'record-until-full,enable-sampling'`.
|
||||
The first 3 options are trace recording modes and hence mutually exclusive.
|
||||
If more than one trace recording modes appear in the `traceOptions` string,
|
||||
the last one takes precedence. If none of the trace recording modes are
|
||||
specified, recording mode is `record-until-full`.
|
||||
The trace option will first be reset to the default option (`record_mode` set
|
||||
to `record-until-full`, `enable_sampling` and `enable_systrace`
|
||||
set to `false`) before options parsed from `traceOptions` are applied on it.
|
||||
9
docs/api/structures/trace-config.md
Normal file
9
docs/api/structures/trace-config.md
Normal file
@@ -0,0 +1,9 @@
|
||||
# TraceConfig Object
|
||||
|
||||
* `included_categories` String[] (optional)
|
||||
* `excluded_categories` String[] (optional)
|
||||
* `memory_dump_config` Object (optional)
|
||||
|
||||
See an example in the [Chromium docs][1].
|
||||
|
||||
[1]: https://chromium.googlesource.com/chromium/src/+/master/docs/memory-infra/memory_infra_startup_tracing.md#the-advanced-way
|
||||
@@ -72,25 +72,24 @@ The `callback` has to be called with an `response` object.
|
||||
* `urls` String[] - Array of URL patterns that will be used to filter out the
|
||||
requests that do not match the URL patterns.
|
||||
* `listener` Function
|
||||
* `details` Object
|
||||
* `id` Integer
|
||||
* `url` String
|
||||
* `method` String
|
||||
* `webContentsId` Integer (optional)
|
||||
* `resourceType` String
|
||||
* `timestamp` Double
|
||||
* `requestHeaders` Object
|
||||
* `callback` Function
|
||||
* `response` Object
|
||||
* `cancel` Boolean (optional)
|
||||
* `requestHeaders` Object (optional) - When provided, request will be made
|
||||
with these headers.
|
||||
|
||||
The `listener` will be called with `listener(details, callback)` before sending
|
||||
an HTTP request, once the request headers are available. This may occur after a
|
||||
TCP connection is made to the server, but before any http data is sent.
|
||||
|
||||
* `details` Object
|
||||
* `id` Integer
|
||||
* `url` String
|
||||
* `method` String
|
||||
* `webContentsId` Integer (optional)
|
||||
* `resourceType` String
|
||||
* `timestamp` Double
|
||||
* `requestHeaders` Object
|
||||
* `callback` Function
|
||||
* `response` Object
|
||||
* `cancel` Boolean (optional)
|
||||
* `requestHeaders` Object (optional) - When provided, request will be made
|
||||
with these headers.
|
||||
|
||||
The `callback` has to be called with an `response` object.
|
||||
|
||||
#### `webRequest.onSendHeaders([filter, ]listener)`
|
||||
@@ -118,29 +117,28 @@ response are visible by the time this listener is fired.
|
||||
* `urls` String[] - Array of URL patterns that will be used to filter out the
|
||||
requests that do not match the URL patterns.
|
||||
* `listener` Function
|
||||
* `details` Object
|
||||
* `id` Integer
|
||||
* `url` String
|
||||
* `method` String
|
||||
* `webContentsId` Integer (optional)
|
||||
* `resourceType` String
|
||||
* `timestamp` Double
|
||||
* `statusLine` String
|
||||
* `statusCode` Integer
|
||||
* `responseHeaders` Object
|
||||
* `callback` Function
|
||||
* `response` Object
|
||||
* `cancel` Boolean
|
||||
* `responseHeaders` Object (optional) - When provided, the server is assumed
|
||||
to have responded with these headers.
|
||||
* `statusLine` String (optional) - Should be provided when overriding
|
||||
`responseHeaders` to change header status otherwise original response
|
||||
header's status will be used.
|
||||
|
||||
The `listener` will be called with `listener(details, callback)` when HTTP
|
||||
response headers of a request have been received.
|
||||
|
||||
* `details` Object
|
||||
* `id` Integer
|
||||
* `url` String
|
||||
* `method` String
|
||||
* `webContentsId` Integer (optional)
|
||||
* `resourceType` String
|
||||
* `timestamp` Double
|
||||
* `statusLine` String
|
||||
* `statusCode` Integer
|
||||
* `responseHeaders` Object
|
||||
* `callback` Function
|
||||
* `response` Object
|
||||
* `cancel` Boolean
|
||||
* `responseHeaders` Object (optional) - When provided, the server is assumed
|
||||
to have responded with these headers.
|
||||
* `statusLine` String (optional) - Should be provided when overriding
|
||||
`responseHeaders` to change header status otherwise original response
|
||||
header's status will be used.
|
||||
|
||||
The `callback` has to be called with an `response` object.
|
||||
|
||||
#### `webRequest.onResponseStarted([filter, ]listener)`
|
||||
|
||||
@@ -36,26 +36,7 @@ the following Python modules:
|
||||
If you're developing Electron and don't plan to redistribute your
|
||||
custom Electron build, you may skip this section.
|
||||
|
||||
For certain features (e.g. pinch-zoom) to work properly, you must target the
|
||||
macOS 10.10 SDK.
|
||||
|
||||
Official Electron builds are built with [Xcode 8.2.1](http://adcdownload.apple.com/Developer_Tools/Xcode_8.2.1/Xcode_8.2.1.xip), which does not contain
|
||||
the 10.10 SDK by default. To obtain it, first download and mount the
|
||||
[Xcode 6.4](http://developer.apple.com/devcenter/download.action?path=/Developer_Tools/Xcode_6.4/Xcode_6.4.dmg)
|
||||
DMG.
|
||||
|
||||
Then, assuming that the Xcode 6.4 DMG has been mounted at `/Volumes/Xcode` and
|
||||
that your Xcode 8.2.1 install is at `/Applications/Xcode.app`, run:
|
||||
|
||||
```sh
|
||||
cp -r /Volumes/Xcode/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.10.sdk /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/
|
||||
```
|
||||
|
||||
You will also need to enable Xcode to build against the 10.10 SDK:
|
||||
|
||||
- Open `/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Info.plist`
|
||||
- Set the `MinimumSDKVersion` to `10.10`
|
||||
- Save the file
|
||||
Official Electron builds are built with [Xcode 8.3.3](http://adcdownload.apple.com/Developer_Tools/Xcode_8.3.3/Xcode_8.3.3.xip), and the MacOS 10.12 SDK. Building with a newer SDK works too, but the releases currently use the 10.12 SDK.
|
||||
|
||||
## Getting the Code
|
||||
|
||||
|
||||
@@ -23,9 +23,8 @@ While code and user experience across operating systems are similar, there
|
||||
are subtle differences.
|
||||
|
||||
## Windows
|
||||
|
||||
* On Windows 10, a shortcut to your app with an [Application User
|
||||
Model ID][app-user-model-id] must be installed to the Start Menu.
|
||||
Model ID][app-user-model-id] must be installed to the Start Menu. This can be overkill during development, so adding `node_modules\electron\dist\electron.exe` to your Start Menu also does the trick. Navigate to the file in Explorer, right-click and 'Pin to Start Menu'. You will then need to add the line `app.setAppUserModelId(process.execPath)` to your main process to see notifications.
|
||||
* On Windows 8.1 and Windows 8, a shortcut to your app with an [Application User
|
||||
Model ID][app-user-model-id] must be installed to the Start screen. Note,
|
||||
however, that it does not need to be pinned to the Start screen.
|
||||
@@ -97,4 +96,4 @@ GNOME, KDE.
|
||||
[notification-spec]: https://developer.gnome.org/notification-spec/
|
||||
[app-user-model-id]: https://msdn.microsoft.com/en-us/library/windows/desktop/dd378459(v=vs.85).aspx
|
||||
[set-app-user-model-id]: ../api/app.md#appsetappusermodelidid-windows
|
||||
[squirrel-events]: https://github.com/electron/windows-installer/blob/master/README.md#handling-squirrel-events
|
||||
[squirrel-events]: https://github.com/electron/windows-installer/blob/master/README.md#handling-squirrel-events
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
'product_name%': 'Electron',
|
||||
'company_name%': 'GitHub, Inc',
|
||||
'company_abbr%': 'github',
|
||||
'version%': '3.1.0-beta.1',
|
||||
'version%': '3.1.4',
|
||||
'js2c_input_dir': '<(SHARED_INTERMEDIATE_DIR)/js2c',
|
||||
},
|
||||
'includes': [
|
||||
|
||||
@@ -537,7 +537,6 @@
|
||||
'atom/renderer/api/atom_api_spell_check_client.cc',
|
||||
'atom/renderer/api/atom_api_spell_check_client.h',
|
||||
'atom/renderer/api/atom_api_web_frame.cc',
|
||||
'atom/renderer/api/atom_api_web_frame.h',
|
||||
'atom/renderer/atom_autofill_agent.cc',
|
||||
'atom/renderer/atom_autofill_agent.h',
|
||||
'atom/renderer/atom_render_frame_observer.cc',
|
||||
|
||||
@@ -1,9 +1,8 @@
|
||||
'use strict'
|
||||
|
||||
const electron = require('electron')
|
||||
const {ipcMain, WebContentsView, TopLevelWindow} = electron
|
||||
const {WebContentsView, TopLevelWindow} = electron
|
||||
const {BrowserWindow} = process.atomBinding('window')
|
||||
const v8Util = process.atomBinding('v8_util')
|
||||
|
||||
Object.setPrototypeOf(BrowserWindow.prototype, TopLevelWindow.prototype)
|
||||
|
||||
@@ -17,67 +16,6 @@ BrowserWindow.prototype._init = function () {
|
||||
// Create WebContentsView.
|
||||
this.setContentView(new WebContentsView(this.webContents))
|
||||
|
||||
// Make new windows requested by links behave like "window.open"
|
||||
this.webContents.on('-new-window', (event, url, frameName, disposition,
|
||||
additionalFeatures, postData,
|
||||
referrer) => {
|
||||
const options = {
|
||||
show: true,
|
||||
width: 800,
|
||||
height: 600
|
||||
}
|
||||
ipcMain.emit('ELECTRON_GUEST_WINDOW_MANAGER_INTERNAL_WINDOW_OPEN',
|
||||
event, url, referrer, frameName, disposition,
|
||||
options, additionalFeatures, postData)
|
||||
})
|
||||
|
||||
this.webContents.on('-web-contents-created', (event, webContents, url,
|
||||
frameName) => {
|
||||
v8Util.setHiddenValue(webContents, 'url-framename', {url, frameName})
|
||||
})
|
||||
|
||||
// Create a new browser window for the native implementation of
|
||||
// "window.open", used in sandbox and nativeWindowOpen mode
|
||||
this.webContents.on('-add-new-contents', (event, webContents, disposition,
|
||||
userGesture, left, top, width,
|
||||
height) => {
|
||||
let urlFrameName = v8Util.getHiddenValue(webContents, 'url-framename')
|
||||
if ((disposition !== 'foreground-tab' && disposition !== 'new-window' &&
|
||||
disposition !== 'background-tab') || !urlFrameName) {
|
||||
event.preventDefault()
|
||||
return
|
||||
}
|
||||
|
||||
if (webContents.getLastWebPreferences().nodeIntegration === true) {
|
||||
const message =
|
||||
'Enabling Node.js integration in child windows opened with the ' +
|
||||
'"nativeWindowOpen" option will cause memory leaks, please turn off ' +
|
||||
'the "nodeIntegration" option.\\n' +
|
||||
'See https://github.com/electron/electron/pull/15076 for more.'
|
||||
// console is only available after DOM is created.
|
||||
const printWarning = () => this.webContents.executeJavaScript(`console.warn('${message}')`)
|
||||
if (this.webContents.isDomReady()) {
|
||||
printWarning()
|
||||
} else {
|
||||
this.webContents.once('dom-ready', printWarning)
|
||||
}
|
||||
}
|
||||
|
||||
let {url, frameName} = urlFrameName
|
||||
v8Util.deleteHiddenValue(webContents, 'url-framename')
|
||||
const options = {
|
||||
show: true,
|
||||
x: left,
|
||||
y: top,
|
||||
width: width || 800,
|
||||
height: height || 600,
|
||||
webContents: webContents
|
||||
}
|
||||
const referrer = { url: '', policy: 'default' }
|
||||
ipcMain.emit('ELECTRON_GUEST_WINDOW_MANAGER_INTERNAL_WINDOW_OPEN',
|
||||
event, url, referrer, frameName, disposition, options)
|
||||
})
|
||||
|
||||
// window.resizeTo(...)
|
||||
// window.moveTo(...)
|
||||
this.webContents.on('move', (event, size) => {
|
||||
|
||||
@@ -14,12 +14,14 @@ const roles = {
|
||||
copy: {
|
||||
label: 'Copy',
|
||||
accelerator: 'CommandOrControl+C',
|
||||
webContentsMethod: 'copy'
|
||||
webContentsMethod: 'copy',
|
||||
registerAccelerator: false
|
||||
},
|
||||
cut: {
|
||||
label: 'Cut',
|
||||
accelerator: 'CommandOrControl+X',
|
||||
webContentsMethod: 'cut'
|
||||
webContentsMethod: 'cut',
|
||||
registerAccelerator: false
|
||||
},
|
||||
delete: {
|
||||
label: 'Delete',
|
||||
@@ -57,12 +59,14 @@ const roles = {
|
||||
paste: {
|
||||
label: 'Paste',
|
||||
accelerator: 'CommandOrControl+V',
|
||||
webContentsMethod: 'paste'
|
||||
webContentsMethod: 'paste',
|
||||
registerAccelerator: false
|
||||
},
|
||||
pasteandmatchstyle: {
|
||||
label: 'Paste and Match Style',
|
||||
accelerator: 'Shift+CommandOrControl+V',
|
||||
webContentsMethod: 'pasteAndMatchStyle'
|
||||
webContentsMethod: 'pasteAndMatchStyle',
|
||||
registerAccelerator: false
|
||||
},
|
||||
quit: {
|
||||
get label () {
|
||||
@@ -241,6 +245,11 @@ exports.getDefaultAccelerator = (role) => {
|
||||
if (roles.hasOwnProperty(role)) return roles[role].accelerator
|
||||
}
|
||||
|
||||
exports.shouldRegisterAccelerator = (role) => {
|
||||
const hasRoleRegister = roles.hasOwnProperty(role) && roles[role].registerAccelerator !== undefined
|
||||
return hasRoleRegister ? roles[role].registerAccelerator : true
|
||||
}
|
||||
|
||||
exports.getDefaultSubmenu = (role) => {
|
||||
if (!roles.hasOwnProperty(role)) return
|
||||
|
||||
|
||||
@@ -36,6 +36,7 @@ const MenuItem = function (options) {
|
||||
this.overrideProperty('enabled', true)
|
||||
this.overrideProperty('visible', true)
|
||||
this.overrideProperty('checked', false)
|
||||
this.overrideProperty('registerAccelerator', roles.shouldRegisterAccelerator(this.role))
|
||||
|
||||
if (!MenuItem.types.includes(this.type)) {
|
||||
throw new Error(`Unknown menu item type: ${this.type}`)
|
||||
|
||||
@@ -24,6 +24,7 @@ const delegate = {
|
||||
if (command.accelerator != null) return command.accelerator
|
||||
if (useDefaultAccelerator) return command.getDefaultRoleAccelerator()
|
||||
},
|
||||
shouldRegisterAcceleratorForCommandId: (menu, id) => menu.commandsMap[id] ? menu.commandsMap[id].registerAccelerator : undefined,
|
||||
executeCommand: (menu, event, id) => {
|
||||
const command = menu.commandsMap[id]
|
||||
if (!command) return
|
||||
|
||||
@@ -5,6 +5,7 @@ const electron = require('electron')
|
||||
const path = require('path')
|
||||
const url = require('url')
|
||||
const {app, ipcMain, session, NavigationController, deprecate} = electron
|
||||
const v8Util = process.atomBinding('v8_util')
|
||||
|
||||
// session is not used here, the purpose is to make sure session is initalized
|
||||
// before the webContents module.
|
||||
@@ -313,6 +314,79 @@ WebContents.prototype._init = function () {
|
||||
this.reload()
|
||||
})
|
||||
|
||||
// Handle window.open for BrowserWindow and BrowserView.
|
||||
if (['browserView', 'window'].includes(this.getType())) {
|
||||
// Make new windows requested by links behave like "window.open"
|
||||
this.on('-new-window', (event, url, frameName, disposition,
|
||||
additionalFeatures, postData,
|
||||
referrer) => {
|
||||
const options = {
|
||||
show: true,
|
||||
width: 800,
|
||||
height: 600
|
||||
}
|
||||
ipcMain.emit('ELECTRON_GUEST_WINDOW_MANAGER_INTERNAL_WINDOW_OPEN',
|
||||
event, url, referrer, frameName, disposition,
|
||||
options, additionalFeatures, postData)
|
||||
})
|
||||
|
||||
this.on('-web-contents-created', (event, webContents, url,
|
||||
frameName) => {
|
||||
v8Util.setHiddenValue(webContents, 'url-framename', {
|
||||
url,
|
||||
frameName
|
||||
})
|
||||
})
|
||||
|
||||
// Create a new browser window for the native implementation of
|
||||
// "window.open", used in sandbox and nativeWindowOpen mode
|
||||
this.on('-add-new-contents', (event, webContents, disposition,
|
||||
userGesture, left, top, width,
|
||||
height) => {
|
||||
let urlFrameName = v8Util.getHiddenValue(webContents, 'url-framename')
|
||||
if ((disposition !== 'foreground-tab' && disposition !== 'new-window' &&
|
||||
disposition !== 'background-tab') || !urlFrameName) {
|
||||
event.preventDefault()
|
||||
return
|
||||
}
|
||||
|
||||
if (webContents.getLastWebPreferences().nodeIntegration === true) {
|
||||
const message =
|
||||
'Enabling Node.js integration in child windows opened with the ' +
|
||||
'"nativeWindowOpen" option will cause memory leaks, please turn off ' +
|
||||
'the "nodeIntegration" option.\\n' +
|
||||
'See https://github.com/electron/electron/pull/15076 for more.'
|
||||
// console is only available after DOM is created.
|
||||
const printWarning = () => this.webContents.executeJavaScript(`console.warn('${message}')`)
|
||||
if (this.webContents.isDomReady()) {
|
||||
printWarning()
|
||||
} else {
|
||||
this.webContents.once('dom-ready', printWarning)
|
||||
}
|
||||
}
|
||||
|
||||
let {
|
||||
url,
|
||||
frameName
|
||||
} = urlFrameName
|
||||
v8Util.deleteHiddenValue(webContents, 'url-framename')
|
||||
const options = {
|
||||
show: true,
|
||||
x: left,
|
||||
y: top,
|
||||
width: width || 800,
|
||||
height: height || 600,
|
||||
webContents: webContents
|
||||
}
|
||||
const referrer = {
|
||||
url: '',
|
||||
policy: 'default'
|
||||
}
|
||||
ipcMain.emit('ELECTRON_GUEST_WINDOW_MANAGER_INTERNAL_WINDOW_OPEN',
|
||||
event, url, referrer, frameName, disposition, options)
|
||||
})
|
||||
}
|
||||
|
||||
app.emit('web-contents-created', {}, this)
|
||||
}
|
||||
|
||||
|
||||
@@ -424,7 +424,7 @@ app.once('ready', function () {
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
if (process.env.ELECTRON_ENABLE_LOGGING) {
|
||||
if (process.env.ELECTRON_ENABLE_LOGGING && error.code !== 'ENOENT') {
|
||||
console.error('Failed to load browser extensions from directory:', loadedDevToolsExtensionsPath)
|
||||
console.error(error)
|
||||
}
|
||||
|
||||
@@ -1,13 +1,67 @@
|
||||
'use strict'
|
||||
|
||||
const {EventEmitter} = require('events')
|
||||
const {webFrame, WebFrame} = process.atomBinding('web_frame')
|
||||
const { EventEmitter } = require('events')
|
||||
const binding = process.atomBinding('web_frame')
|
||||
|
||||
// WebFrame is an EventEmitter.
|
||||
Object.setPrototypeOf(WebFrame.prototype, EventEmitter.prototype)
|
||||
EventEmitter.call(webFrame)
|
||||
class WebFrame extends EventEmitter {
|
||||
constructor (context) {
|
||||
super()
|
||||
|
||||
// Lots of webview would subscribe to webFrame's events.
|
||||
webFrame.setMaxListeners(0)
|
||||
this.context = context
|
||||
// Lots of webview would subscribe to webFrame's events.
|
||||
this.setMaxListeners(0)
|
||||
}
|
||||
|
||||
module.exports = webFrame
|
||||
findFrameByRoutingId (...args) {
|
||||
return getWebFrame(binding._findFrameByRoutingId(this.context, ...args))
|
||||
}
|
||||
|
||||
getFrameForSelector (...args) {
|
||||
return getWebFrame(binding._getFrameForSelector(this.context, ...args))
|
||||
}
|
||||
|
||||
findFrameByName (...args) {
|
||||
return getWebFrame(binding._findFrameByName(this.context, ...args))
|
||||
}
|
||||
|
||||
get opener () {
|
||||
return getWebFrame(binding._getOpener(this.context))
|
||||
}
|
||||
|
||||
get parent () {
|
||||
return getWebFrame(binding._getParent(this.context))
|
||||
}
|
||||
|
||||
get top () {
|
||||
return getWebFrame(binding._getTop(this.context))
|
||||
}
|
||||
|
||||
get firstChild () {
|
||||
return getWebFrame(binding._getFirstChild(this.context))
|
||||
}
|
||||
|
||||
get nextSibling () {
|
||||
return getWebFrame(binding._getNextSibling(this.context))
|
||||
}
|
||||
|
||||
get routingId () {
|
||||
return binding._getRoutingId(this.context)
|
||||
}
|
||||
}
|
||||
|
||||
// Populate the methods.
|
||||
for (const name in binding) {
|
||||
if (!name.startsWith('_')) { // some methods are manully populated above
|
||||
WebFrame.prototype[name] = function (...args) {
|
||||
return binding[name](this.context, ...args)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Helper to return WebFrame or null depending on context.
|
||||
// TODO(zcbenz): Consider returning same WebFrame for the same context.
|
||||
function getWebFrame (context) {
|
||||
return context ? new WebFrame(context) : null
|
||||
}
|
||||
|
||||
module.exports = new WebFrame(window)
|
||||
|
||||
2
package-lock.json
generated
2
package-lock.json
generated
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "electron",
|
||||
"version": "3.1.0",
|
||||
"version": "3.1.3",
|
||||
"lockfileVersion": 1,
|
||||
"requires": true,
|
||||
"dependencies": {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "electron",
|
||||
"version": "3.1.0-beta.1",
|
||||
"version": "3.1.4",
|
||||
"repository": "https://github.com/electron/electron",
|
||||
"description": "Build cross platform desktop apps with JavaScript, HTML, and CSS",
|
||||
"devDependencies": {
|
||||
|
||||
@@ -149,7 +149,7 @@ async function createRelease (branchToTarget, isBeta) {
|
||||
console.log(`Checking for existing draft release.`)
|
||||
let releases = await github.repos.getReleases(githubOpts)
|
||||
.catch(err => {
|
||||
console.log('$fail} Could not get releases. Error was', err)
|
||||
console.log(`${fail} Could not get releases. Error was: `, err)
|
||||
})
|
||||
let drafts = releases.data.filter(release => release.draft &&
|
||||
release.tag_name === newVersion)
|
||||
@@ -180,13 +180,13 @@ async function createRelease (branchToTarget, isBeta) {
|
||||
}
|
||||
githubOpts.tag_name = newVersion
|
||||
githubOpts.target_commitish = newVersion.indexOf('nightly') !== -1 ? 'master' : branchToTarget
|
||||
console.log('creating release with github opts', githubOpts)
|
||||
await github.repos.createRelease(githubOpts)
|
||||
const release = await github.repos.createRelease(githubOpts)
|
||||
.catch(err => {
|
||||
console.log(`${fail} Error creating new release: `, err)
|
||||
process.exit(1)
|
||||
})
|
||||
console.log(`${pass} Draft release for ${newVersion} has been created.`)
|
||||
console.log(`Release has been created with id: ${release.data.id}.`)
|
||||
console.log(`${pass} Draft release for ${newVersion} successful.`)
|
||||
}
|
||||
|
||||
async function pushRelease (branch) {
|
||||
|
||||
@@ -2,8 +2,11 @@
|
||||
|
||||
if (!process.env.CI) require('dotenv-safe').load()
|
||||
require('colors')
|
||||
const pass = '\u2713'.green
|
||||
const fail = '\u2717'.red
|
||||
const args = require('minimist')(process.argv.slice(2), {
|
||||
string: ['tag']
|
||||
string: ['tag', 'releaseID'],
|
||||
default: { releaseID: '' }
|
||||
})
|
||||
const { execSync } = require('child_process')
|
||||
const { GitProcess } = require('dugite')
|
||||
@@ -11,8 +14,8 @@ const { GitProcess } = require('dugite')
|
||||
const GitHub = require('github')
|
||||
const path = require('path')
|
||||
|
||||
const github = new GitHub()
|
||||
const gitDir = path.resolve(__dirname, '..')
|
||||
const github = new GitHub()
|
||||
|
||||
github.authenticate({
|
||||
type: 'token',
|
||||
@@ -42,35 +45,37 @@ async function revertBumpCommit (tag) {
|
||||
await GitProcess.exec(['revert', commitToRevert], gitDir)
|
||||
const pushDetails = await GitProcess.exec(['push', 'origin', `HEAD:${branch}`, '--follow-tags'], gitDir)
|
||||
if (pushDetails.exitCode === 0) {
|
||||
console.log(`Successfully reverted release commit.`)
|
||||
console.log(`${pass} successfully reverted release commit.`)
|
||||
} else {
|
||||
const error = GitProcess.parseError(pushDetails.stderr)
|
||||
console.error(`Failed to push release commit: `, error)
|
||||
console.error(`${fail} could not push release commit: `, error)
|
||||
process.exit(1)
|
||||
}
|
||||
}
|
||||
|
||||
async function deleteDraft (tag, targetRepo) {
|
||||
async function deleteDraft (releaseId, targetRepo) {
|
||||
try {
|
||||
const result = await github.repos.getReleaseByTag({
|
||||
const result = await github.repos.getRelease({
|
||||
owner: 'electron',
|
||||
repo: targetRepo,
|
||||
tag
|
||||
id: parseInt(releaseId, 10)
|
||||
})
|
||||
if (!result.draft) {
|
||||
console.log(`Published releases cannot be deleted.`)
|
||||
process.exit(1)
|
||||
console.log(result)
|
||||
if (!result.data.draft) {
|
||||
console.log(`${fail} published releases cannot be deleted.`)
|
||||
return false
|
||||
} else {
|
||||
await github.repos.deleteRelease({
|
||||
owner: 'electron',
|
||||
repo: targetRepo,
|
||||
release_id: result.id
|
||||
release_id: result.data.id
|
||||
})
|
||||
}
|
||||
console.log(`Successfully deleted draft with tag ${tag} from ${targetRepo}`)
|
||||
console.log(`${pass} successfully deleted draft with id ${releaseId} from ${targetRepo}`)
|
||||
return true
|
||||
} catch (err) {
|
||||
console.error(`Couldn't delete draft with tag ${tag} from ${targetRepo}: `, err)
|
||||
process.exit(1)
|
||||
console.error(`${fail} couldn't delete draft with id ${releaseId} from ${targetRepo}: `, err)
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
@@ -79,30 +84,47 @@ async function deleteTag (tag, targetRepo) {
|
||||
await github.gitdata.deleteReference({
|
||||
owner: 'electron',
|
||||
repo: targetRepo,
|
||||
ref: tag
|
||||
ref: `tags/${tag}`
|
||||
})
|
||||
console.log(`Successfully deleted tag ${tag} from ${targetRepo}`)
|
||||
console.log(`${pass} successfully deleted tag ${tag} from ${targetRepo}`)
|
||||
} catch (err) {
|
||||
console.log(`Couldn't delete tag ${tag} from ${targetRepo}: `, err)
|
||||
process.exit(1)
|
||||
console.log(`${fail} couldn't delete tag ${tag} from ${targetRepo}: `, err)
|
||||
}
|
||||
}
|
||||
|
||||
async function cleanReleaseArtifacts () {
|
||||
const tag = args.tag
|
||||
const releaseId = args.releaseID.length > 0 ? args.releaseID : null
|
||||
const isNightly = args.tag.includes('nightly')
|
||||
|
||||
if (isNightly) {
|
||||
await deleteDraft(tag, 'nightlies')
|
||||
await deleteTag(tag, 'nightlies')
|
||||
// try to revert commit regardless of tag and draft deletion status
|
||||
await revertBumpCommit(args.tag)
|
||||
|
||||
if (releaseId) {
|
||||
if (isNightly) {
|
||||
const deletedNightlyDraft = await deleteDraft(releaseId, 'nightlies')
|
||||
|
||||
// don't delete tag unless draft deleted successfully
|
||||
if (deletedNightlyDraft) {
|
||||
await Promise.all([
|
||||
deleteTag(args.tag, 'electron'),
|
||||
deleteTag(args.tag, 'nightlies')
|
||||
])
|
||||
}
|
||||
} else {
|
||||
const deletedElectronDraft = await deleteDraft(releaseId, 'electron')
|
||||
// don't delete tag unless draft deleted successfully
|
||||
if (deletedElectronDraft) {
|
||||
await deleteTag(args.tag, 'electron')
|
||||
}
|
||||
}
|
||||
} else {
|
||||
await deleteDraft(tag, 'electron')
|
||||
await Promise.all([
|
||||
deleteTag(args.tag, 'electron'),
|
||||
deleteTag(args.tag, 'nightlies')
|
||||
])
|
||||
}
|
||||
|
||||
await deleteTag(tag, 'electron')
|
||||
await revertBumpCommit(tag)
|
||||
|
||||
console.log('Failed release artifact cleanup complete')
|
||||
console.log(`${pass} failed release artifact cleanup complete`)
|
||||
}
|
||||
|
||||
cleanReleaseArtifacts()
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
import json
|
||||
import os
|
||||
import sys
|
||||
import urllib2
|
||||
@@ -15,6 +16,13 @@ BASE_URL = 'https://electron-metadumper.herokuapp.com/?version='
|
||||
version = sys.argv[1]
|
||||
authToken = os.getenv('META_DUMPER_AUTH_HEADER')
|
||||
|
||||
def is_json(myjson):
|
||||
try:
|
||||
json.loads(myjson)
|
||||
except ValueError:
|
||||
return False
|
||||
return True
|
||||
|
||||
def get_content(retry_count = 5):
|
||||
try:
|
||||
request = urllib2.Request(
|
||||
@@ -22,9 +30,14 @@ def get_content(retry_count = 5):
|
||||
headers={"Authorization" : authToken}
|
||||
)
|
||||
|
||||
return urllib2.urlopen(
|
||||
proposed_content = urllib2.urlopen(
|
||||
request
|
||||
).read()
|
||||
|
||||
if is_json(proposed_content):
|
||||
return proposed_content
|
||||
print("bad attempt")
|
||||
raise Exception("Failed to fetch valid JSON from the metadumper service")
|
||||
except Exception as e:
|
||||
if retry_count == 0:
|
||||
raise e
|
||||
|
||||
@@ -34,6 +34,11 @@ def main():
|
||||
files = glob.glob(SYMBOLS_DIR + '/*.pdb/*/*.pdb')
|
||||
else:
|
||||
files = glob.glob(SYMBOLS_DIR + '/*/*/*.sym')
|
||||
|
||||
# The file upload needs to be atom-shell/symbols/:symbol_name/:hash/:symbol
|
||||
os.chdir(SYMBOLS_DIR)
|
||||
files = [os.path.relpath(f, os.getcwd()) for f in files]
|
||||
|
||||
# The symbol server needs lowercase paths, it will fail otherwise
|
||||
# So lowercase all the file paths here
|
||||
files = [f.lower() for f in files]
|
||||
|
||||
@@ -34,6 +34,8 @@ function uploadToGitHub () {
|
||||
console.log(`Error uploading ${fileName} to GitHub, will retry. Error was:`, err)
|
||||
retry++
|
||||
github.repos.getRelease(githubOpts).then(release => {
|
||||
console.log('Got list of assets for existing release:')
|
||||
console.log(JSON.stringify(release.data.assets, null, ' '))
|
||||
let existingAssets = release.data.assets.filter(asset => asset.name === fileName)
|
||||
if (existingAssets.length > 0) {
|
||||
console.log(`${fileName} already exists; will delete before retrying upload.`)
|
||||
@@ -41,10 +43,15 @@ function uploadToGitHub () {
|
||||
owner: 'electron',
|
||||
repo: targetRepo,
|
||||
id: existingAssets[0].id
|
||||
}).then(uploadToGitHub).catch(uploadToGitHub)
|
||||
}).catch((deleteErr) => {
|
||||
console.log(`Failed to delete existing asset ${fileName}. Error was:`, deleteErr)
|
||||
}).then(uploadToGitHub)
|
||||
} else {
|
||||
console.log(`Current asset ${fileName} not found in existing assets; retrying upload.`)
|
||||
uploadToGitHub()
|
||||
}
|
||||
}).catch((getReleaseErr) => {
|
||||
console.log(`Fatal: Unable to get current release assets via getRelease! Error was:`, getReleaseErr)
|
||||
})
|
||||
} else {
|
||||
console.log(`Error retrying uploading ${fileName} to GitHub:`, err)
|
||||
|
||||
2
spec/.hash
Normal file
2
spec/.hash
Normal file
@@ -0,0 +1,2 @@
|
||||
24d8222313d02ffe2a2181b9c82fbfa5ab8372aec6442839302622fbf45cbe47
|
||||
null
|
||||
@@ -432,7 +432,10 @@ describe('app module', () => {
|
||||
})
|
||||
})
|
||||
|
||||
describe('app.get/setLoginItemSettings API', () => {
|
||||
describe('app.get/setLoginItemSettings API', function () {
|
||||
// allow up to three retries to account for flaky mas results
|
||||
this.retries(3)
|
||||
|
||||
const updateExe = path.resolve(path.dirname(process.execPath), '..', 'Update.exe')
|
||||
const processStartArgs = [
|
||||
'--processStart', `"${path.basename(process.execPath)}"`,
|
||||
@@ -440,9 +443,7 @@ describe('app module', () => {
|
||||
]
|
||||
|
||||
before(function () {
|
||||
if (process.platform === 'linux') {
|
||||
this.skip()
|
||||
}
|
||||
if (process.platform === 'linux' || process.mas) this.skip()
|
||||
})
|
||||
|
||||
beforeEach(() => {
|
||||
@@ -513,11 +514,7 @@ describe('app module', () => {
|
||||
})
|
||||
|
||||
it('allows you to pass a custom executable and arguments', function () {
|
||||
if (process.platform !== 'win32') {
|
||||
// FIXME(alexeykuzmin): Skip the test.
|
||||
// this.skip()
|
||||
return
|
||||
}
|
||||
if (process.platform !== 'win32') this.skip()
|
||||
|
||||
app.setLoginItemSettings({openAtLogin: true, path: updateExe, args: processStartArgs})
|
||||
|
||||
|
||||
@@ -2790,6 +2790,19 @@ describe('BrowserWindow module', () => {
|
||||
})
|
||||
})
|
||||
|
||||
describe('window.getNativeWindowHandle()', () => {
|
||||
if (!nativeModulesEnabled) {
|
||||
this.skip()
|
||||
}
|
||||
|
||||
it('returns valid handle', () => {
|
||||
// The module's source code is hosted at
|
||||
// https://github.com/electron/node-is-valid-window
|
||||
const isValidWindow = remote.require('is-valid-window')
|
||||
assert.ok(isValidWindow(w.getNativeWindowHandle()))
|
||||
})
|
||||
})
|
||||
|
||||
describe('extensions and dev tools extensions', () => {
|
||||
let showPanelTimeoutId
|
||||
|
||||
|
||||
145
spec/api-content-tracing-spec.js
Normal file
145
spec/api-content-tracing-spec.js
Normal file
@@ -0,0 +1,145 @@
|
||||
const { remote } = require('electron')
|
||||
const chai = require('chai')
|
||||
const dirtyChai = require('dirty-chai')
|
||||
const fs = require('fs')
|
||||
const path = require('path')
|
||||
|
||||
const { expect } = chai
|
||||
const { app, contentTracing } = remote
|
||||
|
||||
chai.use(dirtyChai)
|
||||
|
||||
const timeout = async (milliseconds) => {
|
||||
return new Promise((resolve) => {
|
||||
setTimeout(resolve, milliseconds)
|
||||
})
|
||||
}
|
||||
|
||||
const getPathInATempFolder = (filename) => {
|
||||
return path.join(app.getPath('temp'), filename)
|
||||
}
|
||||
|
||||
describe('contentTracing', () => {
|
||||
beforeEach(function () {
|
||||
// FIXME: The tests are skipped on arm/arm64.
|
||||
if (process.platform === 'linux' &&
|
||||
['arm', 'arm64'].includes(process.arch)) {
|
||||
this.skip()
|
||||
}
|
||||
})
|
||||
|
||||
const startRecording = async (options) => {
|
||||
return new Promise((resolve) => {
|
||||
contentTracing.startRecording(options, () => {
|
||||
resolve()
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
const stopRecording = async (filePath) => {
|
||||
return new Promise((resolve) => {
|
||||
contentTracing.stopRecording(filePath, (resultFilePath) => {
|
||||
resolve(resultFilePath)
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
const record = async (options, outputFilePath, recordTimeInMilliseconds = 1e3) => {
|
||||
await app.whenReady()
|
||||
|
||||
await startRecording(options)
|
||||
await timeout(recordTimeInMilliseconds)
|
||||
const resultFilePath = await stopRecording(outputFilePath)
|
||||
|
||||
return resultFilePath
|
||||
}
|
||||
|
||||
const outputFilePath = getPathInATempFolder('trace.json')
|
||||
beforeEach(() => {
|
||||
if (fs.existsSync(outputFilePath)) {
|
||||
fs.unlinkSync(outputFilePath)
|
||||
}
|
||||
})
|
||||
|
||||
describe('startRecording', function () {
|
||||
this.timeout(5e3)
|
||||
|
||||
const getFileSizeInKiloBytes = (filePath) => {
|
||||
const stats = fs.statSync(filePath)
|
||||
const fileSizeInBytes = stats.size
|
||||
const fileSizeInKiloBytes = fileSizeInBytes / 1024
|
||||
return fileSizeInKiloBytes
|
||||
}
|
||||
|
||||
it('accepts an empty config', async () => {
|
||||
const config = {}
|
||||
await record(config, outputFilePath)
|
||||
|
||||
expect(fs.existsSync(outputFilePath)).to.be.true()
|
||||
|
||||
const fileSizeInKiloBytes = getFileSizeInKiloBytes(outputFilePath)
|
||||
expect(fileSizeInKiloBytes).to.be.above(0,
|
||||
`the trace output file is empty, check "${outputFilePath}"`)
|
||||
})
|
||||
|
||||
it('accepts a trace config', async () => {
|
||||
// (alexeykuzmin): All categories are excluded on purpose,
|
||||
// so only metadata gets into the output file.
|
||||
const config = {
|
||||
excluded_categories: ['*']
|
||||
}
|
||||
await record(config, outputFilePath)
|
||||
|
||||
expect(fs.existsSync(outputFilePath)).to.be.true()
|
||||
|
||||
// If the `excluded_categories` param above is not respected
|
||||
// the file size will be above 50KB.
|
||||
const fileSizeInKiloBytes = getFileSizeInKiloBytes(outputFilePath)
|
||||
const expectedMaximumFileSize = 10 // Depends on a platform.
|
||||
|
||||
expect(fileSizeInKiloBytes).to.be.above(0,
|
||||
`the trace output file is empty, check "${outputFilePath}"`)
|
||||
expect(fileSizeInKiloBytes).to.be.below(expectedMaximumFileSize,
|
||||
`the trace output file is suspiciously large (${fileSizeInKiloBytes}KB),
|
||||
check "${outputFilePath}"`)
|
||||
})
|
||||
|
||||
it('accepts "categoryFilter" and "traceOptions" as a config', async () => {
|
||||
// (alexeykuzmin): All categories are excluded on purpose,
|
||||
// so only metadata gets into the output file.
|
||||
const config = {
|
||||
categoryFilter: '__ThisIsANonexistentCategory__',
|
||||
traceOptions: ''
|
||||
}
|
||||
await record(config, outputFilePath)
|
||||
|
||||
expect(fs.existsSync(outputFilePath)).to.be.true()
|
||||
|
||||
// If the `categoryFilter` param above is not respected
|
||||
// the file size will be above 50KB.
|
||||
const fileSizeInKiloBytes = getFileSizeInKiloBytes(outputFilePath)
|
||||
const expectedMaximumFileSize = 10 // Depends on a platform.
|
||||
|
||||
expect(fileSizeInKiloBytes).to.be.above(0,
|
||||
`the trace output file is empty, check "${outputFilePath}"`)
|
||||
expect(fileSizeInKiloBytes).to.be.below(expectedMaximumFileSize,
|
||||
`the trace output file is suspiciously large (${fileSizeInKiloBytes}KB),
|
||||
check "${outputFilePath}"`)
|
||||
})
|
||||
})
|
||||
|
||||
describe('stopRecording', function () {
|
||||
this.timeout(5e3)
|
||||
|
||||
it('calls its callback with a result file path', async () => {
|
||||
const resultFilePath = await record(/* options */ {}, outputFilePath)
|
||||
expect(resultFilePath).to.be.a('string').and.be.equal(outputFilePath)
|
||||
})
|
||||
|
||||
// FIXME(alexeykuzmin): https://github.com/electron/electron/issues/16019
|
||||
xit('creates a temporary file when an empty string is passed', async function () {
|
||||
const resultFilePath = await record(/* options */ {}, /* outputFilePath */ '')
|
||||
expect(resultFilePath).to.be.a('string').that.is.not.empty()
|
||||
})
|
||||
})
|
||||
})
|
||||
@@ -158,4 +158,28 @@ describe('webFrame module', function () {
|
||||
const [, text] = await spellCheckerFeedback
|
||||
expect(text).to.equal(misspelledWord)
|
||||
})
|
||||
|
||||
it('top is self for top frame', () => {
|
||||
expect(webFrame.top.context).to.equal(webFrame.context)
|
||||
})
|
||||
|
||||
it('opener is null for top frame', () => {
|
||||
expect(webFrame.opener).to.be.null()
|
||||
})
|
||||
|
||||
it('firstChild is null for top frame', () => {
|
||||
expect(webFrame.firstChild).to.be.null()
|
||||
})
|
||||
|
||||
it('getFrameForSelector() does not crash when not found', () => {
|
||||
expect(webFrame.getFrameForSelector('unexist-selector')).to.be.null()
|
||||
})
|
||||
|
||||
it('findFrameByName() does not crash when not found', () => {
|
||||
expect(webFrame.findFrameByName('unexist-name')).to.be.null()
|
||||
})
|
||||
|
||||
it('findFrameByRoutingId() does not crash when not found', () => {
|
||||
expect(webFrame.findFrameByRoutingId(-1)).to.be.null()
|
||||
})
|
||||
})
|
||||
|
||||
626
spec/package-lock.json
generated
626
spec/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@@ -15,6 +15,7 @@
|
||||
"dbus-native": "^0.2.5",
|
||||
"dirty-chai": "^2.0.1",
|
||||
"graceful-fs": "^4.1.11",
|
||||
"is-valid-window": "^0.0.3",
|
||||
"mkdirp": "^0.5.1",
|
||||
"mocha": "^5.2.0",
|
||||
"mocha-junit-reporter": "^1.17.0",
|
||||
|
||||
2
vendor/libchromiumcontent
vendored
2
vendor/libchromiumcontent
vendored
Submodule vendor/libchromiumcontent updated: 99d8f691c3...cd7a2326b0
Reference in New Issue
Block a user