Compare commits

..

25 Commits

Author SHA1 Message Date
Electron Bot
939be5eb8a Bump v12.0.0-nightly.20201021 2020-10-21 07:31:34 -07:00
Cheng Zhao
a631a8a8b0 docs: put required field frontmost in the dialog options (#26059) 2020-10-21 20:07:44 +09:00
Antonio
5c6fa7e420 docs: revised the online-offline event detection feature page (#26017)
* docs: revised the online-offline event detection feature page

* docs: fixed text and grammar mentions
2020-10-21 15:46:56 +09:00
Milan Burda
df1432a315 feat: add net.online / net.isOnline() (#21004) 2020-10-20 19:55:06 -07:00
Milan Burda
1ef803d2ea chore: make RenderProcessHostPrivilege enum class (#26050) 2020-10-20 19:47:04 -05:00
Julie Koubová
56d1fafe66 build: Wrap bundles using webpack (#25557) 2020-10-20 12:10:15 -07:00
David Sanders
f7945ade07 build: mtime cache for patches to speed up build (#25881) 2020-10-20 11:49:57 -07:00
Valentin Hăloiu
c4525b4ea6 fix: add Wayland support (#26022) 2020-10-20 11:24:52 -07:00
Electron Bot
d38c47e748 Bump v12.0.0-nightly.20201020 2020-10-20 07:33:02 -07:00
Antonio
aebb56cb33 docs: revised Notifications feature page (#25901)
* docs: revised Notifications feature page

* docs: fixed mentions and updated content according to style guide in the notifications feature page

* docs: fixed lint errors in the notifications feature page

* docs: slightly improved consistency of steps in the notifications feature page

* docs: fixed mentions in the notifications feature page
2020-10-20 11:24:27 +09:00
David Sanders
e6f570d191 docs: improve relative link linting and fix broken (#26020) 2020-10-20 10:46:27 +09:00
David Sanders
042ebdd5b0 build: lint patches for trailing whitespace (#26007) 2020-10-20 10:40:58 +09:00
Cheng Zhao
6b6ffbdd10 feat: add support for share menu on macOS (#25629) 2020-10-19 18:33:06 -07:00
Antonio
89c04b3c6c docs: revised the macos dock menu feature page (#25985)
* docs: revised the macos dock menu feature page

* docs: added a cross-link to api, fixed mentions in the macos feature page
2020-10-20 10:32:40 +09:00
Charles Kerr
ae5de3d9c5 perf: remove GC timer that fired once per minute. (#25958) 2020-10-20 10:31:02 +09:00
Antonio
12e3c85081 docs: revised the recent documents feature page (#25941)
* docs: revised the recent documents feature page

* docs: fixed lint errors in the recent documents feature page

* docs: slightly improved consistency of steps in the recent documents feature page
2020-10-20 10:26:24 +09:00
John Kleinschmidt
4ce7ca6cfb test: disable flaky arm tests (#26046)
* tests: disable flaking test on all arm platforms

* tests: disable flaky did-change-theme-color tests on WOA
2020-10-19 20:11:30 -04:00
Shelley Vohr
c6a6f53c8d fix: crash when printing (#25989) 2020-10-19 14:31:25 -07:00
The Gem Dev
3219812c02 docs: update native file drag and drop (#26044)
fixed a typo.
2020-10-19 14:18:43 -07:00
Electron Bot
e895353f7a chore: bump node to v14.14.0 (master) (#25994)
* chore: bump node in DEPS to v14.14.0

* Remove upstreamed certs patch

https://github.com/nodejs/node/pull/35546

* Remove V8 Isolate callbacks patch

https://github.com/nodejs/node/pull/35512

* Update patch indices

* Update Node.js filenames

Co-authored-by: Shelley Vohr <shelley.vohr@gmail.com>
2020-10-19 13:28:28 -07:00
Shelley Vohr
88508d5166 fix: support new PDF viewer update (#26010) 2020-10-19 13:07:02 -07:00
David Sanders
64504536fa build: fix invocation of cpplint on Windows (#26011) 2020-10-19 12:08:13 -07:00
Charles Kerr
16caa54248 chore: tweak branch detection in release notes. (#25973) 2020-10-19 11:36:37 -07:00
Michaela Laurencin
11ce55628e fix: correct null pointer checks in autoresizing browser views (#25951)
* Correction null pointer checks

* fix: correct null pointer checks in autoresizing browser views

Co-authored-by: mlaurencin <mlaurencin@microsoft.com>
2020-10-19 09:26:38 -07:00
John Kleinschmidt
87d3f3584c fix: segfault in SerialChooserController (#25969)
* fix: segfault in SerialChooserController

* Remove temporary testing
2020-10-19 10:51:25 -04:00
97 changed files with 1382 additions and 3037 deletions

5
.gitignore vendored
View File

@@ -65,4 +65,7 @@ ts-gen
# Used to accelerate CI builds
.depshash
.depshash-target
.depshash-target
# Used to accelerate builds after sync
patches/mtime-cache.json

34
DEPS
View File

@@ -16,7 +16,7 @@ vars = {
'chromium_version':
'9269f9eb1d98d29564c2b2ab97f30c6e148c4e11',
'node_version':
'v14.13.1',
'v14.14.0',
'nan_version':
'2c4ee8a32a299eada3cd6e468bbd0a473bfea96d',
'squirrel.mac_version':
@@ -38,6 +38,9 @@ vars = {
# To be able to build clean Chromium from sources.
'apply_patches': True,
# To use an mtime cache for patched files to speed up builds.
'use_mtime_cache': True,
# To allow in-house builds to checkout those manually.
'checkout_chromium': True,
'checkout_node': True,
@@ -112,6 +115,23 @@ deps = {
}
}
pre_deps_hooks = [
{
'name': 'generate_mtime_cache',
'condition': '(checkout_chromium and apply_patches and use_mtime_cache) and process_deps',
'pattern': 'src/electron',
'action': [
'python3',
'src/electron/script/patches-mtime-cache.py',
'generate',
'--cache-file',
'src/electron/patches/mtime-cache.json',
'--patches-config',
'src/electron/patches/config.json',
],
},
]
hooks = [
{
'name': 'patch_chromium',
@@ -123,6 +143,18 @@ hooks = [
'src/electron/patches/config.json',
],
},
{
'name': 'apply_mtime_cache',
'condition': '(checkout_chromium and apply_patches and use_mtime_cache) and process_deps',
'pattern': 'src/electron',
'action': [
'python3',
'src/electron/script/patches-mtime-cache.py',
'apply',
'--cache-file',
'src/electron/patches/mtime-cache.json',
],
},
{
'name': 'electron_external_binaries',
'pattern': 'src/electron/script/update-external-binaries.py',

View File

@@ -1 +1 @@
12.0.0-nightly.20201019
12.0.0-nightly.20201021

View File

@@ -1,2 +0,0 @@
process.env.PRINT_WEBPACK_GRAPH = true;
require('./run-compiler');

View File

@@ -1,45 +0,0 @@
const fs = require('fs');
const path = require('path');
const webpack = require('webpack');
const configPath = process.argv[2];
const outPath = path.resolve(process.argv[3]);
const config = require(configPath);
config.output = {
path: path.dirname(outPath),
filename: path.basename(outPath)
};
const { wrapInitWithProfilingTimeout, wrapInitWithTryCatch, ...webpackConfig } = config;
webpack(webpackConfig, (err, stats) => {
if (err) {
console.error(err);
process.exit(1);
} else if (stats.hasErrors()) {
console.error(stats.toString('normal'));
process.exit(1);
} else {
let contents = fs.readFileSync(outPath, 'utf8');
if (wrapInitWithTryCatch) {
contents = `try {
${contents}
} catch (err) {
console.error('Electron ${webpackConfig.output.filename} script failed to run');
console.error(err);
}`;
}
if (wrapInitWithProfilingTimeout) {
contents = `function ___electron_webpack_init__() {
${contents}
};
if ((globalThis.process || binding.process).argv.includes("--profile-electron-init")) {
setTimeout(___electron_webpack_init__, 0);
} else {
___electron_webpack_init__();
}`;
}
fs.writeFileSync(outPath, contents);
process.exit(0);
}
});

View File

@@ -2,16 +2,12 @@ const fs = require('fs');
const path = require('path');
const webpack = require('webpack');
const TerserPlugin = require('terser-webpack-plugin');
const WrapperPlugin = require('wrapper-webpack-plugin');
const electronRoot = path.resolve(__dirname, '../..');
const onlyPrintingGraph = !!process.env.PRINT_WEBPACK_GRAPH;
class AccessDependenciesPlugin {
apply (compiler) {
// Only hook into webpack when we are printing the dependency graph
if (!onlyPrintingGraph) return;
compiler.hooks.compilation.tap('AccessDependenciesPlugin', compilation => {
compilation.hooks.finishModules.tap('AccessDependenciesPlugin', modules => {
const filePaths = modules.map(m => m.resource).filter(p => p).map(p => path.relative(electronRoot, p));
@@ -21,49 +17,6 @@ class AccessDependenciesPlugin {
}
}
const defines = {
BUILDFLAG: onlyPrintingGraph ? '(a => a)' : ''
};
const buildFlagsPrefix = '--buildflags=';
const buildFlagArg = process.argv.find(arg => arg.startsWith(buildFlagsPrefix));
if (buildFlagArg) {
const buildFlagPath = buildFlagArg.substr(buildFlagsPrefix.length);
const flagFile = fs.readFileSync(buildFlagPath, 'utf8');
for (const line of flagFile.split(/(\r\n|\r|\n)/g)) {
const flagMatch = line.match(/#define BUILDFLAG_INTERNAL_(.+?)\(\) \(([01])\)/);
if (flagMatch) {
const [, flagName, flagValue] = flagMatch;
defines[flagName] = JSON.stringify(Boolean(parseInt(flagValue, 10)));
}
}
}
const ignoredModules = [];
if (defines.ENABLE_DESKTOP_CAPTURER === 'false') {
ignoredModules.push(
'@electron/internal/browser/desktop-capturer',
'@electron/internal/browser/api/desktop-capturer',
'@electron/internal/renderer/api/desktop-capturer'
);
}
if (defines.ENABLE_REMOTE_MODULE === 'false') {
ignoredModules.push(
'@electron/internal/browser/remote/server',
'@electron/internal/renderer/api/remote'
);
}
if (defines.ENABLE_VIEWS_API === 'false') {
ignoredModules.push(
'@electron/internal/browser/api/views/image-view.js'
);
}
module.exports = ({
alwaysHasNode,
loadElectronFromAlternateTarget,
@@ -79,76 +32,148 @@ module.exports = ({
const electronAPIFile = path.resolve(electronRoot, 'lib', loadElectronFromAlternateTarget || target, 'api', 'exports', 'electron.ts');
return ({
mode: 'development',
devtool: false,
entry,
target: alwaysHasNode ? 'node' : 'web',
output: {
filename: `${target}.bundle.js`
},
wrapInitWithProfilingTimeout,
wrapInitWithTryCatch,
resolve: {
alias: {
'@electron/internal': path.resolve(electronRoot, 'lib'),
electron$: electronAPIFile,
'electron/main$': electronAPIFile,
'electron/renderer$': electronAPIFile,
'electron/common$': electronAPIFile,
// Force timers to resolve to our dependency that doesn't use window.postMessage
timers: path.resolve(electronRoot, 'node_modules', 'timers-browserify', 'main.js')
},
extensions: ['.ts', '.js']
},
module: {
rules: [{
test: (moduleName) => !onlyPrintingGraph && ignoredModules.includes(moduleName),
loader: 'null-loader'
}, {
test: /\.ts$/,
loader: 'ts-loader',
options: {
configFile: path.resolve(electronRoot, 'tsconfig.electron.json'),
transpileOnly: onlyPrintingGraph,
ignoreDiagnostics: [
// File '{0}' is not under 'rootDir' '{1}'.
6059
]
return (env = {}, argv = {}) => {
const onlyPrintingGraph = !!env.PRINT_WEBPACK_GRAPH;
const outputFilename = argv['output-filename'] || `${target}.bundle.js`;
const defines = {
BUILDFLAG: onlyPrintingGraph ? '(a => a)' : ''
};
if (env.buildflags) {
const flagFile = fs.readFileSync(env.buildflags, 'utf8');
for (const line of flagFile.split(/(\r\n|\r|\n)/g)) {
const flagMatch = line.match(/#define BUILDFLAG_INTERNAL_(.+?)\(\) \(([01])\)/);
if (flagMatch) {
const [, flagName, flagValue] = flagMatch;
defines[flagName] = JSON.stringify(Boolean(parseInt(flagValue, 10)));
}
}]
},
node: {
__dirname: false,
__filename: false,
// We provide our own "timers" import above, any usage of setImmediate inside
// one of our renderer bundles should import it from the 'timers' package
setImmediate: false
},
optimization: {
minimize: true,
minimizer: [
new TerserPlugin({
terserOptions: {
keep_classnames: true,
keep_fnames: true
}
})
]
},
plugins: [
new AccessDependenciesPlugin(),
...(targetDeletesNodeGlobals ? [
new webpack.ProvidePlugin({
process: ['@electron/internal/common/webpack-provider', 'process'],
global: ['@electron/internal/common/webpack-provider', '_global'],
Buffer: ['@electron/internal/common/webpack-provider', 'Buffer']
})
] : []),
new webpack.ProvidePlugin({
Promise: ['@electron/internal/common/webpack-globals-provider', 'Promise']
}),
new webpack.DefinePlugin(defines)
]
});
}
}
const ignoredModules = [];
if (defines.ENABLE_DESKTOP_CAPTURER === 'false') {
ignoredModules.push(
'@electron/internal/browser/desktop-capturer',
'@electron/internal/browser/api/desktop-capturer',
'@electron/internal/renderer/api/desktop-capturer'
);
}
if (defines.ENABLE_REMOTE_MODULE === 'false') {
ignoredModules.push(
'@electron/internal/browser/remote/server',
'@electron/internal/renderer/api/remote'
);
}
if (defines.ENABLE_VIEWS_API === 'false') {
ignoredModules.push(
'@electron/internal/browser/api/views/image-view.js'
);
}
const plugins = [];
if (onlyPrintingGraph) {
plugins.push(new AccessDependenciesPlugin());
}
if (targetDeletesNodeGlobals) {
plugins.push(new webpack.ProvidePlugin({
process: ['@electron/internal/common/webpack-provider', 'process'],
global: ['@electron/internal/common/webpack-provider', '_global'],
Buffer: ['@electron/internal/common/webpack-provider', 'Buffer']
}));
}
plugins.push(new webpack.ProvidePlugin({
Promise: ['@electron/internal/common/webpack-globals-provider', 'Promise']
}));
plugins.push(new webpack.DefinePlugin(defines));
if (wrapInitWithProfilingTimeout) {
plugins.push(new WrapperPlugin({
header: 'function ___electron_webpack_init__() {',
footer: `
};
if ((globalThis.process || binding.process).argv.includes("--profile-electron-init")) {
setTimeout(___electron_webpack_init__, 0);
} else {
___electron_webpack_init__();
}`
}));
}
if (wrapInitWithTryCatch) {
plugins.push(new WrapperPlugin({
header: 'try {',
footer: `
} catch (err) {
console.error('Electron ${outputFilename} script failed to run');
console.error(err);
}`
}));
}
return {
mode: 'development',
devtool: false,
entry,
target: alwaysHasNode ? 'node' : 'web',
output: {
filename: outputFilename
},
resolve: {
alias: {
'@electron/internal': path.resolve(electronRoot, 'lib'),
electron$: electronAPIFile,
'electron/main$': electronAPIFile,
'electron/renderer$': electronAPIFile,
'electron/common$': electronAPIFile,
// Force timers to resolve to our dependency that doesn't use window.postMessage
timers: path.resolve(electronRoot, 'node_modules', 'timers-browserify', 'main.js')
},
extensions: ['.ts', '.js']
},
module: {
rules: [{
test: (moduleName) => !onlyPrintingGraph && ignoredModules.includes(moduleName),
loader: 'null-loader'
}, {
test: /\.ts$/,
loader: 'ts-loader',
options: {
configFile: path.resolve(electronRoot, 'tsconfig.electron.json'),
transpileOnly: onlyPrintingGraph,
ignoreDiagnostics: [
// File '{0}' is not under 'rootDir' '{1}'.
6059
]
}
}]
},
node: {
__dirname: false,
__filename: false,
// We provide our own "timers" import above, any usage of setImmediate inside
// one of our renderer bundles should import it from the 'timers' package
setImmediate: false
},
optimization: {
minimize: true,
minimizer: [
new TerserPlugin({
terserOptions: {
keep_classnames: true,
keep_fnames: true
}
})
]
},
plugins
};
};
};

View File

@@ -16,7 +16,6 @@ template("webpack_build") {
inputs = [
invoker.config_file,
"//electron/build/webpack/webpack.config.base.js",
"//electron/build/webpack/run-compiler.js",
"//electron/tsconfig.json",
"//electron/yarn.lock",
"//electron/typings/internal-ambient.d.ts",
@@ -24,9 +23,12 @@ template("webpack_build") {
] + invoker.inputs
args = [
"--config",
rebase_path(invoker.config_file),
rebase_path(invoker.out_file),
"--buildflags=" + rebase_path("$target_gen_dir/buildflags/buildflags.h"),
"--output-filename=" + get_path_info(invoker.out_file, "file"),
"--output-path=" + rebase_path(get_path_info(invoker.out_file, "dir")),
"--env.buildflags=" +
rebase_path("$target_gen_dir/buildflags/buildflags.h"),
]
deps += [ "buildflags" ]

View File

@@ -93,9 +93,18 @@ static_library("chrome") {
if (is_linux) {
sources += [ "//chrome/browser/icon_loader_auralinux.cc" ]
if (use_x11) {
sources += [
"//chrome/browser/extensions/global_shortcut_listener_x11.cc",
"//chrome/browser/extensions/global_shortcut_listener_x11.h",
]
} else if (use_ozone) {
sources += [
"//chrome/browser/extensions/global_shortcut_listener_ozone.cc",
"//chrome/browser/extensions/global_shortcut_listener_ozone.h",
]
}
sources += [
"//chrome/browser/extensions/global_shortcut_listener_x11.cc",
"//chrome/browser/extensions/global_shortcut_listener_x11.h",
"//chrome/browser/ui/views/status_icons/concat_menu_model.cc",
"//chrome/browser/ui/views/status_icons/concat_menu_model.h",
"//chrome/browser/ui/views/status_icons/status_icon_linux_dbus.cc",

View File

@@ -232,7 +232,7 @@ Specify ways of the inspector web socket url exposure.
By default inspector websocket url is available in stderr and under /json/list endpoint on http://host:port/json/list.
[app]: app.md
[append-switch]: app.md#appcommandlineappendswitchswitch-value
[append-switch]: command-line.md#commandlineappendswitchswitch-value
[ready]: app.md#event-ready
[play-silent-audio]: https://github.com/atom/atom/pull/9485/files
[debugging-main-process]: ../tutorial/debugging-main-process.md

View File

@@ -95,7 +95,7 @@ Returns `Promise<DesktopCapturerSource[]>` - Resolves with an array of [`Desktop
which can detected by [`systemPreferences.getMediaAccessStatus`].
[`navigator.mediaDevices.getUserMedia`]: https://developer.mozilla.org/en/docs/Web/API/MediaDevices/getUserMedia
[`systemPreferences.getMediaAccessStatus`]: system-preferences.md#systempreferencesgetmediaaccessstatusmediatype-macos
[`systemPreferences.getMediaAccessStatus`]: system-preferences.md#systempreferencesgetmediaaccessstatusmediatype-windows-macos
## Caveats

View File

@@ -221,6 +221,7 @@ expanding and collapsing the dialog.
* `browserWindow` [BrowserWindow](browser-window.md) (optional)
* `options` Object
* `message` String - Content of the message box.
* `type` String (optional) - Can be `"none"`, `"info"`, `"error"`, `"question"` or
`"warning"`. On Windows, `"question"` displays the same icon as `"info"`, unless
you set an icon using the `"icon"` option. On macOS, both `"warning"` and
@@ -230,7 +231,6 @@ expanding and collapsing the dialog.
* `defaultId` Integer (optional) - Index of the button in the buttons array which will
be selected by default when the message box opens.
* `title` String (optional) - Title of the message box, some platforms will not show it.
* `message` String - Content of the message box.
* `detail` String (optional) - Extra information of the message.
* `checkboxLabel` String (optional) - If provided, the message box will
include a checkbox with the given label.
@@ -267,6 +267,7 @@ If `browserWindow` is not shown dialog will not be attached to it. In such case
* `browserWindow` [BrowserWindow](browser-window.md) (optional)
* `options` Object
* `message` String - Content of the message box.
* `type` String (optional) - Can be `"none"`, `"info"`, `"error"`, `"question"` or
`"warning"`. On Windows, `"question"` displays the same icon as `"info"`, unless
you set an icon using the `"icon"` option. On macOS, both `"warning"` and
@@ -276,7 +277,6 @@ If `browserWindow` is not shown dialog will not be attached to it. In such case
* `defaultId` Integer (optional) - Index of the button in the buttons array which will
be selected by default when the message box opens.
* `title` String (optional) - Title of the message box, some platforms will not show it.
* `message` String - Content of the message box.
* `detail` String (optional) - Extra information of the message.
* `checkboxLabel` String (optional) - If provided, the message box will
include a checkbox with the given label.

View File

@@ -14,7 +14,7 @@ See [`Menu`](menu.md) for examples.
* `menuItem` MenuItem
* `browserWindow` [BrowserWindow](browser-window.md) | undefined - This will not be defined if no window is open.
* `event` [KeyboardEvent](structures/keyboard-event.md)
* `role` String (optional) - Can be `undo`, `redo`, `cut`, `copy`, `paste`, `pasteAndMatchStyle`, `delete`, `selectAll`, `reload`, `forceReload`, `toggleDevTools`, `resetZoom`, `zoomIn`, `zoomOut`, `togglefullscreen`, `window`, `minimize`, `close`, `help`, `about`, `services`, `hide`, `hideOthers`, `unhide`, `quit`, `startSpeaking`, `stopSpeaking`, `zoom`, `front`, `appMenu`, `fileMenu`, `editMenu`, `viewMenu`, `recentDocuments`, `toggleTabBar`, `selectNextTab`, `selectPreviousTab`, `mergeAllWindows`, `clearRecentDocuments`, `moveTabToNewWindow` or `windowMenu` - Define the action of the menu item, when specified the
* `role` String (optional) - Can be `undo`, `redo`, `cut`, `copy`, `paste`, `pasteAndMatchStyle`, `delete`, `selectAll`, `reload`, `forceReload`, `toggleDevTools`, `resetZoom`, `zoomIn`, `zoomOut`, `togglefullscreen`, `window`, `minimize`, `close`, `help`, `about`, `services`, `hide`, `hideOthers`, `unhide`, `quit`, `startSpeaking`, `stopSpeaking`, `zoom`, `front`, `appMenu`, `fileMenu`, `editMenu`, `viewMenu`, `shareMenu`, `recentDocuments`, `toggleTabBar`, `selectNextTab`, `selectPreviousTab`, `mergeAllWindows`, `clearRecentDocuments`, `moveTabToNewWindow` or `windowMenu` - Define the action of the menu item, when specified the
`click` property will be ignored. See [roles](#roles).
* `type` String (optional) - Can be `normal`, `separator`, `submenu`, `checkbox` or
`radio`.
@@ -31,6 +31,7 @@ See [`Menu`](menu.md) for examples.
menu items.
* `registerAccelerator` Boolean (optional) _Linux_ _Windows_ - If false, the accelerator won't be registered
with the system, but it will still be displayed. Defaults to true.
* `sharingItem` SharingItem (optional) _macOS_ - The item to share when the `role` is `shareMenu`.
* `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
@@ -112,6 +113,7 @@ The following additional roles are available on _macOS_:
* `services` - The submenu is a ["Services"](https://developer.apple.com/documentation/appkit/nsapplication/1428608-servicesmenu?language=objc) menu. This is only intended for use in the Application Menu and is *not* the same as the "Services" submenu used in context menus in macOS apps, which is not implemented in Electron.
* `recentDocuments` - The submenu is an "Open Recent" menu.
* `clearRecentDocuments` - Map to the `clearRecentDocuments` action.
* `shareMenu` - The submenu is [share menu][ShareMenu]. The `sharingItem` property must also be set to indicate the item to share.
When specifying a `role` on macOS, `label` and `accelerator` are the only
options that will affect the menu item. All other options will be ignored.
@@ -200,6 +202,12 @@ system or just displayed.
This property can be dynamically changed.
#### `menuItem.sharingItem` _macOS_
A `SharingItem` indicating the item to share when the `role` is `shareMenu`.
This property can be dynamically changed.
#### `menuItem.commandId`
A `Number` indicating an item's sequential unique id.
@@ -207,3 +215,5 @@ A `Number` indicating an item's sequential unique id.
#### `menuItem.menu`
A `Menu` that the item is a part of.
[ShareMenu]: https://developer.apple.com/design/human-interface-guidelines/macos/extensions/share-extensions/

View File

@@ -8,7 +8,7 @@ The `net` module is a client-side API for issuing HTTP(S) requests. It is
similar to the [HTTP](https://nodejs.org/api/http.html) and
[HTTPS](https://nodejs.org/api/https.html) modules of Node.js but uses
Chromium's native networking library instead of the Node.js implementation,
offering better support for web proxies.
offering better support for web proxies. It also supports checking network status.
The following is a non-exhaustive list of why you may consider using the `net`
module instead of the native Node.js modules:
@@ -62,3 +62,25 @@ Creates a [`ClientRequest`](./client-request.md) instance using the provided
`options` which are directly forwarded to the `ClientRequest` constructor.
The `net.request` method would be used to issue both secure and insecure HTTP
requests according to the specified protocol scheme in the `options` object.
### `net.isOnline()`
Returns `Boolean` - Whether there is currently internet connection.
A return value of `false` is a pretty strong indicator that the user
won't be able to connect to remote sites. However, a return value of
`true` is inconclusive; even if some link is up, it is uncertain
whether a particular connection attempt to a particular remote site
will be successful.
## Properties
### `net.online` _Readonly_
A `Boolean` property. Whether there is currently internet connection.
A return value of `false` is a pretty strong indicator that the user
won't be able to connect to remote sites. However, a return value of
`true` is inconclusive; even if some link is up, it is uncertain
whether a particular connection attempt to a particular remote site
will be successful.

45
docs/api/share-menu.md Normal file
View File

@@ -0,0 +1,45 @@
## Class: ShareMenu
> Create share menu on macOS.
Process: [Main](../glossary.md#main-process)
The `ShareMenu` class creates [Share Menu][share-menu] on macOS, which can be
used to share information from the current context to apps, social media
accounts, and other services.
For including the share menu as a submenu of other menus, please use the
`shareMenu` role of [`MenuItem`](menu-item.md).
### `new ShareMenu(sharingItem)`
* `sharingItem` SharingItem - The item to share.
Creates a new share menu.
### Instance Methods
The `shareMenu` object has the following instance methods:
#### `shareMenu.popup([options])`
* `options` PopupOptions (optional)
* `browserWindow` [BrowserWindow](browser-window.md) (optional) - Default is the focused window.
* `x` Number (optional) - Default is the current mouse cursor position.
Must be declared if `y` is declared.
* `y` Number (optional) - Default is the current mouse cursor position.
Must be declared if `x` is declared.
* `positioningItem` Number (optional) _macOS_ - The index of the menu item to
be positioned under the mouse cursor at the specified coordinates. Default
is -1.
* `callback` Function (optional) - Called when menu is closed.
Pops up this menu as a context menu in the [`BrowserWindow`](browser-window.md).
#### `shareMenu.closePopup([browserWindow])`
* `browserWindow` [BrowserWindow](browser-window.md) (optional) - Default is the focused window.
Closes the context menu in the `browserWindow`.
[share-menu]: https://developer.apple.com/design/human-interface-guidelines/macos/extensions/share-extensions/

View File

@@ -4,4 +4,4 @@
* `senderId` Integer - The `webContents.id` that sent the message, you can call `event.sender.sendTo(event.senderId, ...)` to reply to the message, see [ipcRenderer.sendTo][ipc-renderer-sendto] for more information. This only applies to messages sent from a different renderer. Messages sent directly from the main process set `event.senderId` to `0`.
* `ports` MessagePort[] - A list of MessagePorts that were transferred with this message
[ipc-renderer-sendto]: #ipcrenderersendtowindowid-channel--arg1-arg2-
[ipc-renderer-sendto]: ../ipc-renderer.md#ipcrenderersendtowebcontentsid-channel-args

View File

@@ -0,0 +1,5 @@
# SharingItem Object
* `texts` String[] (optional) - An array of text to share.
* `filePaths` String[] (optional) - An array of files to share.
* `urls` String[] (optional) - An array of URLs to share.

Binary file not shown.

After

Width:  |  Height:  |  Size: 100 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 21 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 44 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 46 KiB

View File

@@ -1,10 +1,11 @@
# macOS Dock
## Overview
Electron has APIs to configure the app's icon in the macOS Dock. A macOS-only
API exists to create a custom dock menu, but
Electron also uses the app's dock icon to implement cross-platform features
like [recent documents][recent-documents] and
[application progress][progress-bar].
API exists to create a custom dock menu, but Electron also uses the app dock
icon as the entry point for cross-platform features like
[recent documents][recent-documents] and [application progress][progress-bar].
The custom dock is commonly used to add shortcuts to tasks the user wouldn't
want to open the whole app window for.
@@ -13,8 +14,15 @@ __Dock menu of Terminal.app:__
![Dock Menu][dock-menu-image]
To set your custom dock menu, you can use the `app.dock.setMenu` API, which is
only available on macOS:
To set your custom dock menu, you need to use the
[`app.dock.setMenu`](../api/dock.md#docksetmenumenu-macos) API,
which is only available on macOS.
## Example
Starting with a working application from the
[Quick Start Guide](quick-start.md), update the `main.js` file with the
following lines:
```javascript
const { app, Menu } = require('electron')
@@ -33,9 +41,16 @@ const dockMenu = Menu.buildFromTemplate([
{ label: 'New Command...' }
])
app.dock.setMenu(dockMenu)
app.whenReady().then(() => {
app.dock.setMenu(dockMenu)
})
```
After launching the Electron application, right click the application icon.
You should see the custom menu you just defined:
![macOS dock menu](../images/macos-dock-menu.png)
[dock-menu-image]: https://cloud.githubusercontent.com/assets/639601/5069962/6032658a-6e9c-11e4-9953-aa84006bdfff.png
[recent-documents]: ./recent-documents.md
[progress-bar]: ./progress-bar.md

View File

@@ -51,7 +51,7 @@ ipcMain.on('ondragstart', (event, filePath) => {
})
```
After launching the Electron application, try to dragging and dropping
After launching the Electron application, try dragging and dropping
the item from the BroswerWindow onto your desktop. In this guide,
the item is a Markdown file located in the root of the project:

View File

@@ -1,17 +1,36 @@
# Notifications (Windows, Linux, macOS)
All three operating systems provide means for applications to send notifications
to the user. Electron conveniently allows developers to send notifications with
the [HTML5 Notification API](https://notifications.spec.whatwg.org/), using
the currently running operating system's native notification APIs to display it.
## Overview
**Note:** Since this is an HTML5 API it is only available in the renderer process. If
you want to show Notifications in the main process please check out the
All three operating systems provide means for applications to send
notifications to the user. The technique of showing notifications is different
for the Main and Renderer processes.
For the Renderer process, Electron conveniently allows developers to send
notifications with the [HTML5 Notification API](https://notifications.spec.whatwg.org/),
using the currently running operating system's native notification APIs
to display it.
To show notifications in the Main process, you need to use the
[Notification](../api/notification.md) module.
```javascript
## Example
### Show notifications in the Renderer process
Assuming you have a working Electron application from the
[Quick Start Guide](quick-start.md), add the following line to the
`index.html` file before the closing `</body>` tag:
```html
<script src="renderer.js"></script>
```
and add the `renderer.js` file:
```js
const myNotification = new Notification('Title', {
body: 'Lorem Ipsum Dolor Sit Amet'
body: 'Notification from the Renderer process'
})
myNotification.onclick = () => {
@@ -19,12 +38,52 @@ myNotification.onclick = () => {
}
```
After launching the Electron application, you should see the notification:
![Notification in the Renderer process](../images/notification-renderer.png)
If you open the Console and then click the notification, you will see the
message that was generated after triggering the `onclick` event:
![Onclick message for the notification](../images/message-notification-renderer.png)
### Show notifications in the Main process
Starting with a working application from the
[Quick Start Guide](quick-start.md), update the `main.js` file with the following lines:
```js
const { Notification } = require('electron')
function showNotification () {
const notification = {
title: 'Basic Notification',
body: 'Notification from the Main process'
}
new Notification(notification).show()
}
app.whenReady().then(createWindow).then(showNotification)
```
After launching the Electron application, you should see the notification:
![Notification in the Main process](../images/notification-main.png)
## Additional information
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. 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.
### 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. 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.
@@ -44,7 +103,7 @@ to 200 characters. That said, that limitation has been removed in Windows 10, wi
the Windows team asking developers to be reasonable. Attempting to send gigantic
amounts of text to the API (thousands of characters) might result in instability.
### Advanced Notifications
#### Advanced Notifications
Later versions of Windows allow for advanced notifications, with custom templates,
images, and other flexible elements. To send those notifications (from either the
@@ -53,40 +112,47 @@ main process or the renderer process), use the userland module
which uses native Node addons to send `ToastNotification` and `TileNotification` objects.
While notifications including buttons work with `electron-windows-notifications`,
handling replies requires the use of [`electron-windows-interactive-notifications`](https://github.com/felixrieseberg/electron-windows-interactive-notifications), which
helps with registering the required COM components and calling your Electron app with
the entered user data.
handling replies requires the use of
[`electron-windows-interactive-notifications`](https://github.com/felixrieseberg/electron-windows-interactive-notifications),
which helps with registering the required COM components and calling your
Electron app with the entered user data.
### Quiet Hours / Presentation Mode
#### Quiet Hours / Presentation Mode
To detect whether or not you're allowed to send a notification, use the userland module
[electron-notification-state](https://github.com/felixrieseberg/electron-notification-state).
To detect whether or not you're allowed to send a notification, use the
userland module [electron-notification-state](https://github.com/felixrieseberg/electron-notification-state).
This allows you to determine ahead of time whether or not Windows will silently throw
the notification away.
This allows you to determine ahead of time whether or not Windows will
silently throw the notification away.
## macOS
### macOS
Notifications are straight-forward on macOS, but you should be aware of
[Apple's Human Interface guidelines regarding notifications](https://developer.apple.com/macos/human-interface-guidelines/system-capabilities/notifications/).
[Apple's Human Interface guidelines regarding notifications][apple-notification-guidelines].
Note that notifications are limited to 256 bytes in size and will be truncated
if you exceed that limit.
### Advanced Notifications
[apple-notification-guidelines]: https://developer.apple.com/macos/human-interface-guidelines/system-capabilities/notifications/
#### Advanced Notifications
Later versions of macOS allow for notifications with an input field, allowing the user
to quickly reply to a notification. In order to send notifications with an input field,
use the userland module [node-mac-notifier](https://github.com/CharlieHess/node-mac-notifier).
use the userland module [node-mac-notifier][node-mac-notifier].
### Do not disturb / Session State
[node-mac-notifier]: https://github.com/CharlieHess/node-mac-notifier
#### Do not disturb / Session State
To detect whether or not you're allowed to send a notification, use the userland module
[electron-notification-state](https://github.com/felixrieseberg/electron-notification-state).
[electron-notification-state][electron-notification-state].
This will allow you to detect ahead of time whether or not the notification will be displayed.
## Linux
[electron-notification-state]: https://github.com/felixrieseberg/electron-notification-state
### Linux
Notifications are sent using `libnotify` which can show notifications on any
desktop environment that follows [Desktop Notifications

View File

@@ -1,14 +1,30 @@
# Online/Offline Event Detection
[Online and offline event](https://developer.mozilla.org/en-US/docs/Online_and_offline_events) detection can be implemented in the renderer process using the [`navigator.onLine`](http://html5index.org/Offline%20-%20NavigatorOnLine.html) attribute, part of standard HTML5 API.
The `navigator.onLine` attribute returns `false` if any network requests are guaranteed to fail i.e. definitely offline (disconnected from the network). It returns `true` in all other cases.
Since all other conditions return `true`, one has to be mindful of getting false positives, as we cannot assume `true` value necessarily means that Electron can access the internet. Such as in cases where the computer is running a virtualization software that has virtual ethernet adapters that are always “connected.”
Therefore, if you really want to determine the internet access status of Electron,
you should develop additional means for checking.
## Overview
Example:
[Online and offline event](https://developer.mozilla.org/en-US/docs/Online_and_offline_events)
detection can be implemented in the Renderer process using the
[`navigator.onLine`](http://html5index.org/Offline%20-%20NavigatorOnLine.html)
attribute, part of standard HTML5 API.
_main.js_
The `navigator.onLine` attribute returns:
* `false` if all network requests are guaranteed to fail (e.g. when disconnected from the network).
* `true` in all other cases.
Since many cases return `true`, you should treat with care situations of
getting false positives, as we cannot always assume that `true` value means
that Electron can access the Internet. For example, in cases when the computer
is running a virtualization software that has virtual Ethernet adapters in "always
connected" state. Therefore, if you want to determine the Internet access
status of Electron, you should develop additional means for this check.
## Example
### Event detection in the Renderer process
Starting with a working application from the
[Quick Start Guide](quick-start.md), update the `main.js` file
with the following lines:
```javascript
const { app, BrowserWindow } = require('electron')
@@ -21,33 +37,39 @@ app.whenReady().then(() => {
})
```
_online-status.html_
create the `online-status.html` file and add the following line before the
closing `</body>` tag:
```html
<!DOCTYPE html>
<html>
<body>
<script>
const alertOnlineStatus = () => {
window.alert(navigator.onLine ? 'online' : 'offline')
}
window.addEventListener('online', alertOnlineStatus)
window.addEventListener('offline', alertOnlineStatus)
alertOnlineStatus()
</script>
</body>
</html>
<script src="renderer.js"></script>
```
There may be instances where you want to respond to these events in the
main process as well. The main process however does not have a
`navigator` object and thus cannot detect these events directly. Using
Electron's inter-process communication utilities, the events can be forwarded
to the main process and handled as needed, as shown in the following example.
and add the `renderer.js` file:
_main.js_
```javascript
const alertOnlineStatus = () => { window.alert(navigator.onLine ? 'online' : 'offline') }
window.addEventListener('online', alertOnlineStatus)
window.addEventListener('offline', alertOnlineStatus)
alertOnlineStatus()
```
After launching the Electron application, you should see the notification:
![Online-offline-event detection](../images/online-event-detection.png)
### Event detection in the Main process
There may be situations when you want to respond to online/offline events in
the Main process as well. The Main process, however, does not have a
`navigator` object and cannot detect these events directly. In this case, you
need to forward the events to the Main process using Electron's inter-process
communication (IPC) utilities.
Starting with a working application from the
[Quick Start Guide](quick-start.md), update the `main.js` file
with the following lines:
```javascript
const { app, BrowserWindow, ipcMain } = require('electron')
@@ -63,23 +85,33 @@ ipcMain.on('online-status-changed', (event, status) => {
})
```
_online-status.html_
create the `online-status.html` file and add the following line before the
closing `</body>` tag:
```html
<!DOCTYPE html>
<html>
<body>
<script>
const { ipcRenderer } = require('electron')
const updateOnlineStatus = () => {
ipcRenderer.send('online-status-changed', navigator.onLine ? 'online' : 'offline')
}
window.addEventListener('online', updateOnlineStatus)
window.addEventListener('offline', updateOnlineStatus)
updateOnlineStatus()
</script>
</body>
</html>
<script src="renderer.js"></script>
```
and add the `renderer.js` file:
```javascript
const { ipcRenderer } = require('electron')
const updateOnlineStatus = () => { ipcRenderer.send('online-status-changed', navigator.onLine ? 'online' : 'offline') }
window.addEventListener('online', updateOnlineStatus)
window.addEventListener('offline', updateOnlineStatus)
updateOnlineStatus()
```
After launching the Electron application, you should see the notification in the
Console:
```sh
npm start
> electron@1.0.0 start /electron
> electron .
online
```

View File

@@ -32,4 +32,4 @@ win.setProgressBar(0.5)
```
[taskbar-progress-image]: https://cloud.githubusercontent.com/assets/639601/5081682/16691fda-6f0e-11e4-9676-49b6418f1264.png
[setprogressbar]: ../api/browser-window.md#winsetprogressbarprogress
[setprogressbar]: ../api/browser-window.md#winsetprogressbarprogress-options

View File

@@ -1,5 +1,7 @@
# Recent Documents (Windows & macOS)
## Overview
Windows and macOS provide access to a list of recent documents opened by
the application via JumpList or dock menu, respectively.
@@ -11,39 +13,58 @@ __Application dock menu:__
![macOS Dock Menu][dock-menu-image]
To add a file to recent documents, you can use the
[app.addRecentDocument][addrecentdocument] API:
To add a file to recent documents, you need to use the
[app.addRecentDocument][addrecentdocument] API.
## Example
### Add an item to recent documents
Starting with a working application from the
[Quick Start Guide](quick-start.md), add the following lines to the
`main.js` file:
```javascript
const { app } = require('electron')
app.addRecentDocument('/Users/USERNAME/Desktop/work.type')
```
And you can use [app.clearRecentDocuments][clearrecentdocuments] API to empty
the recent documents list:
After launching the Electron application, right click the application icon.
You should see the item you just added. In this guide, the item is a Markdown
file located in the root of the project:
![Recent document](../images/recent-documents.png)
### Clear the list of recent documents
To clear the list of recent documents, you need to use
[app.clearRecentDocuments][clearrecentdocuments] API in the `main.js` file:
```javascript
const { app } = require('electron')
app.clearRecentDocuments()
```
## Windows Notes
## Additional information
In order to be able to use this feature on Windows, your application has to be
registered as a handler of the file type of the document, otherwise the file
won't appear in JumpList even after you have added it. You can find everything
### Windows Notes
To use this feature on Windows, your application has to be registered as
a handler of the file type of the document, otherwise the file won't appear
in JumpList even after you have added it. You can find everything
on registering your application in [Application Registration][app-registration].
When a user clicks a file from the JumpList, a new instance of your application
will be started with the path of the file added as a command line argument.
## macOS Notes
### macOS Notes
### Adding the Recent Documents list to the application menu:
#### Add the Recent Documents list to the application menu
![macOS Recent Documents menu item][menu-item-image]
You can add menu items to access and clear recent documents by adding the following code snippet to your menu's template.
You can add menu items to access and clear recent documents by adding the
following code snippet to your menu template:
```json
{
@@ -62,6 +83,8 @@ You can add menu items to access and clear recent documents by adding the follow
}
```
![macOS Recent Documents menu item][menu-item-image]
When a file is requested from the recent documents menu, the `open-file` event
of `app` module will be emitted for it.

View File

@@ -814,6 +814,6 @@ which potential security issues are not as widely known.
[web-contents]: ../api/web-contents.md
[new-window]: ../api/web-contents.md#event-new-window
[will-navigate]: ../api/web-contents.md#event-will-navigate
[open-external]: ../api/shell.md#shellopenexternalurl-options-callback
[open-external]: ../api/shell.md#shellopenexternalurl-options
[sandbox]: ../api/sandbox-option.md
[responsible-disclosure]: https://en.wikipedia.org/wiki/Responsible_disclosure

View File

@@ -49,6 +49,7 @@ auto_filenames = {
"docs/api/screen.md",
"docs/api/service-workers.md",
"docs/api/session.md",
"docs/api/share-menu.md",
"docs/api/shell.md",
"docs/api/structures",
"docs/api/synopsis.md",
@@ -119,6 +120,7 @@ auto_filenames = {
"docs/api/structures/serial-port.md",
"docs/api/structures/service-worker-info.md",
"docs/api/structures/shared-worker-info.md",
"docs/api/structures/sharing-item.md",
"docs/api/structures/shortcut-details.md",
"docs/api/structures/size.md",
"docs/api/structures/task.md",
@@ -219,6 +221,7 @@ auto_filenames = {
"lib/browser/api/protocol.ts",
"lib/browser/api/screen.ts",
"lib/browser/api/session.ts",
"lib/browser/api/share-menu.ts",
"lib/browser/api/system-preferences.ts",
"lib/browser/api/touch-bar.ts",
"lib/browser/api/tray.ts",

View File

@@ -1,3 +1,5 @@
import("//build/config/ui.gni")
filenames = {
default_app_ts_sources = [
"default_app/default_app.ts",
@@ -22,20 +24,10 @@ filenames = {
]
lib_sources_linux = [
"chromium_src/chrome/browser/ui/views/frame/global_menu_bar_registrar_x11.cc",
"chromium_src/chrome/browser/ui/views/frame/global_menu_bar_registrar_x11.h",
"shell/browser/ui/file_dialog_gtk.cc",
"shell/browser/ui/message_box_gtk.cc",
"shell/browser/ui/tray_icon_gtk.cc",
"shell/browser/ui/tray_icon_gtk.h",
"shell/browser/ui/views/global_menu_bar_x11.cc",
"shell/browser/ui/views/global_menu_bar_x11.h",
"shell/browser/ui/x/event_disabler.cc",
"shell/browser/ui/x/event_disabler.h",
"shell/browser/ui/x/window_state_watcher.cc",
"shell/browser/ui/x/window_state_watcher.h",
"shell/browser/ui/x/x_window_utils.cc",
"shell/browser/ui/x/x_window_utils.h",
"shell/browser/browser_linux.cc",
"shell/browser/lib/power_observer_linux.cc",
"shell/browser/lib/power_observer_linux.h",
@@ -642,6 +634,21 @@ filenames = {
"shell/utility/electron_content_utility_client.h",
]
if (use_x11) {
lib_sources_linux += [
"chromium_src/chrome/browser/ui/views/frame/global_menu_bar_registrar_x11.cc",
"chromium_src/chrome/browser/ui/views/frame/global_menu_bar_registrar_x11.h",
"shell/browser/ui/views/global_menu_bar_x11.cc",
"shell/browser/ui/views/global_menu_bar_x11.h",
"shell/browser/ui/x/event_disabler.cc",
"shell/browser/ui/x/event_disabler.h",
"shell/browser/ui/x/window_state_watcher.cc",
"shell/browser/ui/x/window_state_watcher.h",
"shell/browser/ui/x/x_window_utils.cc",
"shell/browser/ui/x/x_window_utils.h",
]
}
lib_sources_nss = [
"chromium_src/chrome/browser/certificate_manager_model.cc",
"chromium_src/chrome/browser/certificate_manager_model.h",

View File

@@ -6,7 +6,7 @@ const isLinux = process.platform === 'linux';
type RoleId = 'about' | 'close' | 'copy' | 'cut' | 'delete' | 'forcereload' | 'front' | 'help' | 'hide' | 'hideothers' | 'minimize' |
'paste' | 'pasteandmatchstyle' | 'quit' | 'redo' | 'reload' | 'resetzoom' | 'selectall' | 'services' | 'recentdocuments' | 'clearrecentdocuments' | 'startspeaking' | 'stopspeaking' |
'toggledevtools' | 'togglefullscreen' | 'undo' | 'unhide' | 'window' | 'zoom' | 'zoomin' | 'zoomout' | 'appmenu' | 'filemenu' | 'editmenu' | 'viewmenu' | 'windowmenu'
'toggledevtools' | 'togglefullscreen' | 'undo' | 'unhide' | 'window' | 'zoom' | 'zoomin' | 'zoomout' | 'appmenu' | 'filemenu' | 'editmenu' | 'viewmenu' | 'windowmenu' | 'sharemenu'
interface Role {
label: string;
accelerator?: string;
@@ -261,6 +261,11 @@ export const roleList: Record<RoleId, Role> = {
{ role: 'close' }
] as MenuItemConstructorOptions[])
]
},
// Share submenu
sharemenu: {
label: 'Share',
submenu: []
}
};

View File

@@ -41,6 +41,12 @@ Menu.prototype._shouldRegisterAcceleratorForCommandId = function (id) {
return this.commandsMap[id] ? this.commandsMap[id].registerAccelerator : false;
};
if (process.platform === 'darwin') {
Menu.prototype._getSharingItemForCommandId = function (id) {
return this.commandsMap[id] ? this.commandsMap[id].sharingItem : null;
};
}
Menu.prototype._executeCommand = function (event, id) {
const command = this.commandsMap[id];
if (!command) return;

View File

@@ -26,6 +26,7 @@ export const browserModuleList: ElectronInternal.ModuleEntry[] = [
{ name: 'protocol', loader: () => require('./protocol') },
{ name: 'screen', loader: () => require('./screen') },
{ name: 'session', loader: () => require('./session') },
{ name: 'ShareMenu', loader: () => require('./share-menu') },
{ name: 'systemPreferences', loader: () => require('./system-preferences') },
{ name: 'TouchBar', loader: () => require('./touch-bar') },
{ name: 'Tray', loader: () => require('./tray') },

View File

@@ -29,6 +29,7 @@ export const browserModuleNames = [
'protocol',
'screen',
'session',
'ShareMenu',
'systemPreferences',
'TouchBar',
'Tray',

View File

@@ -4,6 +4,7 @@ import { app } from 'electron/main';
import type { ClientRequestConstructorOptions, UploadProgress } from 'electron/main';
const {
isOnline,
isValidHeaderName,
isValidHeaderValue,
createURLLoader
@@ -516,3 +517,9 @@ export class ClientRequest extends Writable implements Electron.ClientRequest {
export function request (options: ClientRequestConstructorOptions | string, callback?: (message: IncomingMessage) => void) {
return new ClientRequest(options, callback);
}
exports.isOnline = isOnline;
Object.defineProperty(exports, 'online', {
get: () => isOnline()
});

View File

@@ -0,0 +1,19 @@
import { BrowserWindow, Menu, SharingItem, PopupOptions } from 'electron/main';
class ShareMenu {
private menu: Menu;
constructor (sharingItem: SharingItem) {
this.menu = new (Menu as any)({ sharingItem });
}
popup (options?: PopupOptions) {
this.menu.popup(options);
}
closePopup (browserWindow?: BrowserWindow) {
this.menu.closePopup(browserWindow);
}
}
export default ShareMenu;

View File

@@ -1,6 +1,6 @@
{
"name": "electron",
"version": "12.0.0-nightly.20201019",
"version": "12.0.0-nightly.20201021",
"repository": "https://github.com/electron/electron",
"description": "Build cross platform desktop apps with JavaScript, HTML, and CSS",
"devDependencies": {
@@ -63,7 +63,8 @@
"ts-node": "6.2.0",
"typescript": "^4.0.2",
"webpack": "^4.43.0",
"webpack-cli": "^3.3.12"
"webpack-cli": "^3.3.12",
"wrapper-webpack-plugin": "^2.1.0"
},
"private": true,
"scripts": {
@@ -91,7 +92,7 @@
"start": "node ./script/start.js",
"test": "node ./script/spec-runner.js",
"tsc": "tsc",
"webpack": "node build/webpack/run-compiler"
"webpack": "webpack"
},
"license": "MIT",
"author": "Electron Community",

View File

@@ -81,7 +81,7 @@ index 5575c90cf05ec43bc787711f1d44b8dd58ead99c..a544d836159522751c1262370d8c1562
!command_line->HasSwitch(switches::kUIDisablePartialSwap);
#if defined(OS_APPLE)
diff --git a/components/viz/service/display/gl_renderer.cc b/components/viz/service/display/gl_renderer.cc
index 31fa3d22a28cb673a1eac983acafb7bcd484e6ca..58d52c207f12dd329a0cb8593af5f76ab5ba70f1 100644
index 31fa3d22a28cb673a1eac983acafb7bcd484e6ca..e1bfab6b716fa5d2f552b7af149748b3b0dc0a23 100644
--- a/components/viz/service/display/gl_renderer.cc
+++ b/components/viz/service/display/gl_renderer.cc
@@ -88,6 +88,9 @@
@@ -121,7 +121,7 @@ index 31fa3d22a28cb673a1eac983acafb7bcd484e6ca..58d52c207f12dd329a0cb8593af5f76a
tint_gl_composited_content_,
ShouldApplyRoundedCorner(quad)),
- CurrentRenderPassColorSpace(), CurrentRenderPassColorSpace());
+ PATCH_CS(CurrentRenderPassColorSpace()),
+ PATCH_CS(CurrentRenderPassColorSpace()),
+ PATCH_CS(CurrentRenderPassColorSpace()));
gfx::ColorSpace quad_color_space = gfx::ColorSpace::CreateSRGB();

View File

@@ -7,7 +7,7 @@ This tweaks Chrome's Accessibility support at chrome://accessibility
to make it usable from Electron by removing Profile references.
diff --git a/chrome/browser/accessibility/accessibility_ui.cc b/chrome/browser/accessibility/accessibility_ui.cc
index 42d79b5651e204dc8014489f8feb6b6ad7994d8c..77ca7e88b9e5c2f1dd80d28452588f85a1120169 100644
index 42d79b5651e204dc8014489f8feb6b6ad7994d8c..bed9a4f98f566d368a891a8247f3e528f9db910d 100644
--- a/chrome/browser/accessibility/accessibility_ui.cc
+++ b/chrome/browser/accessibility/accessibility_ui.cc
@@ -19,7 +19,10 @@
@@ -101,7 +101,7 @@ index 42d79b5651e204dc8014489f8feb6b6ad7994d8c..77ca7e88b9e5c2f1dd80d28452588f85
+#if 0
PrefService* pref = Profile::FromWebUI(web_ui())->GetPrefs();
bool internal = pref->GetBoolean(prefs::kShowInternalAccessibilityTree);
+#endif
+#endif
std::string accessibility_contents =
- web_contents->DumpAccessibilityTree(internal, property_filters);
+ web_contents->DumpAccessibilityTree(true, property_filters);

View File

@@ -25,7 +25,7 @@ index f63f7f2674d9562f57dea4f9c9f473aa595a0c5f..78a46dbea7ff31209748ef47d5417253
// Returns true if duplex mode is set.
bool SetDuplexModeInPrintSettings(mojom::DuplexMode mode);
diff --git a/printing/printing_context_mac.mm b/printing/printing_context_mac.mm
index aa950b59390fdae9a5152affb7a7438cb78eb6f4..3ec9ee0ee464960a48d23f5000137cc44027e9b1 100644
index aa950b59390fdae9a5152affb7a7438cb78eb6f4..9b5307bda7b73cb502fe185be2a7c02e23a7722c 100644
--- a/printing/printing_context_mac.mm
+++ b/printing/printing_context_mac.mm
@@ -189,7 +189,8 @@ PMPaper MatchPaper(CFArrayRef paper_list,
@@ -45,7 +45,7 @@ index aa950b59390fdae9a5152affb7a7438cb78eb6f4..3ec9ee0ee464960a48d23f5000137cc4
+bool PrintingContextMac::SetPrintRangeInPrintSettings(const PageRanges& ranges) {
+ // Default is already NSPrintAllPages - we can safely bail.
+ if (ranges.empty())
+ return true;
+ return true;
+
+ auto* print_settings =
+ static_cast<PMPrintSettings>([print_info_.get() PMPrintSettings]);
@@ -100,14 +100,14 @@ index d3c8677f30d72efc49b28f293260c74c7b8d8b4e..f6e66aaa58ab1881d64dcbb320ae8b5a
} else {
// No need to bother, we don't know how many pages are available.
diff --git a/ui/gtk/printing/print_dialog_gtk.cc b/ui/gtk/printing/print_dialog_gtk.cc
index f2ed36e1258f4f3ef1bfce972e215e3d5d7335b6..405839e9f944f70106c1c203652044c3abfade3d 100644
index f2ed36e1258f4f3ef1bfce972e215e3d5d7335b6..5b38bf1369a68546f0aeea8948abba995c65e7f7 100644
--- a/ui/gtk/printing/print_dialog_gtk.cc
+++ b/ui/gtk/printing/print_dialog_gtk.cc
@@ -239,6 +239,24 @@ void PrintDialogGtk::UpdateSettings(
gtk_print_settings_set_n_copies(gtk_settings_, settings->copies());
gtk_print_settings_set_collate(gtk_settings_, settings->collate());
+
+
+ auto print_ranges = settings->ranges();
+ if (!print_ranges.empty()) {
+ // Tell the system that we only intend to print a subset of pages.

View File

@@ -12,14 +12,14 @@ rendering and there is no signal from browser process on this event
to identify it.
diff --git a/content/browser/gpu/gpu_data_manager_impl.cc b/content/browser/gpu/gpu_data_manager_impl.cc
index 694f63ecd2de241fd1a8b7b529bbd4d1bea78337..cc9679eb86f85239f5612d8db8200db5392f5bc5 100644
index 694f63ecd2de241fd1a8b7b529bbd4d1bea78337..705d24cb09a2a8b07ac7acd21b18e2e3483856bf 100644
--- a/content/browser/gpu/gpu_data_manager_impl.cc
+++ b/content/browser/gpu/gpu_data_manager_impl.cc
@@ -229,6 +229,11 @@ void GpuDataManagerImpl::TerminateInfoCollectionGpuProcess() {
base::AutoLock auto_lock(lock_);
private_->TerminateInfoCollectionGpuProcess();
}
+
+
+bool GpuDataManagerImpl::DxdiagDx12VulkanRequested() const {
+ base::AutoLock auto_lock(lock_);
+ return private_->DxdiagDx12VulkanRequested();

View File

@@ -419,7 +419,7 @@ index 894ac47e596c1c96a7e0659be80ed8a5629d0304..eca797a24df79b8502b9698e6ed8830a
} // namespace
diff --git a/content/renderer/theme_helper_mac.mm b/content/renderer/theme_helper_mac.mm
index 1db129740992672a4e8be8100da18b6813f1a4f8..5b1e456020ac859c826dbef2826cacf3bb60108b 100644
index 1db129740992672a4e8be8100da18b6813f1a4f8..dc18d623869e815d4d1ef64ad8bceb6948f5cc9e 100644
--- a/content/renderer/theme_helper_mac.mm
+++ b/content/renderer/theme_helper_mac.mm
@@ -7,11 +7,11 @@
@@ -445,7 +445,7 @@ index 1db129740992672a4e8be8100da18b6813f1a4f8..5b1e456020ac859c826dbef2826cacf3
+#else
+ NSUserDefaults* defaults = [NSUserDefaults standardUserDefaults];
+ NSString *default_key = @"CGFontRenderingGetFontSmoothingDisabled";
+ // Check that key exists since boolForKey defaults to NO when the
+ // Check that key exists since boolForKey defaults to NO when the
+ // key is missing and this key in fact defaults to YES;
+ if ([defaults objectForKey:default_key] == nil)
+ return false;

View File

@@ -102,7 +102,7 @@ index 89c7798d8ddf21eb74e726c142377afa05b59c26..dd75b8e82552a54868ce86caf90ba175
}
diff --git a/chrome/browser/printing/print_view_manager_base.cc b/chrome/browser/printing/print_view_manager_base.cc
index ad70dada204132ce44d6613378072a080771148a..02ecf3e77bee365eef4dc8a985cfe092785b8b8e 100644
index ad70dada204132ce44d6613378072a080771148a..75908fc9978db020d752e7fc7211d1a075c11ffb 100644
--- a/chrome/browser/printing/print_view_manager_base.cc
+++ b/chrome/browser/printing/print_view_manager_base.cc
@@ -28,10 +28,7 @@
@@ -145,7 +145,7 @@ index ad70dada204132ce44d6613378072a080771148a..02ecf3e77bee365eef4dc8a985cfe092
: PrintManager(web_contents),
queue_(g_browser_process->print_job_manager()->queue()) {
DCHECK(queue_);
+#if 0
+#if 0 // Printing is always enabled.
Profile* profile =
Profile::FromBrowserContext(web_contents->GetBrowserContext());
printing_enabled_.Init(
@@ -197,7 +197,22 @@ index ad70dada204132ce44d6613378072a080771148a..02ecf3e77bee365eef4dc8a985cfe092
}
void PrintViewManagerBase::NavigationStopped() {
@@ -441,7 +454,7 @@ void PrintViewManagerBase::PrintingFailed(int32_t cookie) {
@@ -421,12 +434,13 @@ void PrintViewManagerBase::OnDidPrintDocument(
void PrintViewManagerBase::GetDefaultPrintSettings(
GetDefaultPrintSettingsCallback callback) {
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
+#if 0 // Printing is always enabled.
if (!printing_enabled_.GetValue()) {
auto params = mojom::PrintParams::New();
GetDefaultPrintSettingsReply(std::move(callback), std::move(params));
return;
}
-
+#endif
content::RenderFrameHost* render_frame_host =
print_manager_host_receivers_.GetCurrentTargetFrame();
@@ -441,7 +455,7 @@ void PrintViewManagerBase::PrintingFailed(int32_t cookie) {
PrintManager::PrintingFailed(cookie);
#if BUILDFLAG(ENABLE_PRINT_PREVIEW)
@@ -206,7 +221,7 @@ index ad70dada204132ce44d6613378072a080771148a..02ecf3e77bee365eef4dc8a985cfe092
#endif
ReleasePrinterQuery();
@@ -460,6 +473,11 @@ void PrintViewManagerBase::OnScriptedPrint(
@@ -460,6 +474,11 @@ void PrintViewManagerBase::OnScriptedPrint(
}
void PrintViewManagerBase::ShowInvalidPrinterSettingsError() {
@@ -218,7 +233,7 @@ index ad70dada204132ce44d6613378072a080771148a..02ecf3e77bee365eef4dc8a985cfe092
base::ThreadTaskRunnerHandle::Get()->PostTask(
FROM_HERE, base::BindOnce(&ShowWarningMessageBox,
l10n_util::GetStringUTF16(
@@ -529,9 +547,13 @@ void PrintViewManagerBase::OnNotifyPrintJobEvent(
@@ -529,9 +548,13 @@ void PrintViewManagerBase::OnNotifyPrintJobEvent(
content::NotificationService::NoDetails());
break;
}
@@ -234,7 +249,7 @@ index ad70dada204132ce44d6613378072a080771148a..02ecf3e77bee365eef4dc8a985cfe092
NOTREACHED();
break;
}
@@ -627,8 +649,10 @@ bool PrintViewManagerBase::CreateNewPrintJob(
@@ -627,8 +650,10 @@ bool PrintViewManagerBase::CreateNewPrintJob(
DCHECK(!quit_inner_loop_);
DCHECK(query);
@@ -247,7 +262,7 @@ index ad70dada204132ce44d6613378072a080771148a..02ecf3e77bee365eef4dc8a985cfe092
// We can't print if there is no renderer.
if (!web_contents()->GetRenderViewHost() ||
@@ -649,8 +673,6 @@ bool PrintViewManagerBase::CreateNewPrintJob(
@@ -649,8 +674,6 @@ bool PrintViewManagerBase::CreateNewPrintJob(
print_job_->SetSource(source, /*source_id=*/"");
#endif
@@ -256,7 +271,7 @@ index ad70dada204132ce44d6613378072a080771148a..02ecf3e77bee365eef4dc8a985cfe092
printing_succeeded_ = false;
return true;
}
@@ -699,14 +721,22 @@ void PrintViewManagerBase::ReleasePrintJob() {
@@ -699,14 +722,22 @@ void PrintViewManagerBase::ReleasePrintJob() {
content::RenderFrameHost* rfh = printing_rfh_;
printing_rfh_ = nullptr;
@@ -281,7 +296,7 @@ index ad70dada204132ce44d6613378072a080771148a..02ecf3e77bee365eef4dc8a985cfe092
// Don't close the worker thread.
print_job_ = nullptr;
}
@@ -742,7 +772,7 @@ bool PrintViewManagerBase::RunInnerMessageLoop() {
@@ -742,7 +773,7 @@ bool PrintViewManagerBase::RunInnerMessageLoop() {
}
bool PrintViewManagerBase::OpportunisticallyCreatePrintJob(int cookie) {

View File

@@ -25,8 +25,6 @@ fix_use_crypto_impls_for_compat.patch
fix_comment_out_incompatible_crypto_modules.patch
update_tests_after_increasing_typed_array_size.patch
feat_add_implementation_of_v8_platform_postjob.patch
crypto_update_certdata_to_nss_3_56.patch
fix_-wincompatible-pointer-types-discards-qualifiers_error.patch
fix_add_v8_enable_reverse_jsargs_defines_in_common_gypi.patch
fix_allow_preventing_initializeinspector_in_env.patch
chore_expose_v8_initialization_isolate_callbacks.patch

View File

@@ -846,10 +846,10 @@ index 0000000000000000000000000000000000000000..2c9d2826c85bdd033f1df1d6188df636
+}
diff --git a/filenames.json b/filenames.json
new file mode 100644
index 0000000000000000000000000000000000000000..fbf2c13688d52b5ba320eadac42d472f09441e79
index 0000000000000000000000000000000000000000..9480edd9b00591e7aad7f764a409b86094e4cd5d
--- /dev/null
+++ b/filenames.json
@@ -0,0 +1,527 @@
@@ -0,0 +1,530 @@
+// This file is automatically generated by generate_gn_filenames_json.py
+// DO NOT EDIT
+{
@@ -871,6 +871,7 @@ index 0000000000000000000000000000000000000000..fbf2c13688d52b5ba320eadac42d472f
+ "files": [
+ "//v8/include/cppgc/allocation.h",
+ "//v8/include/cppgc/common.h",
+ "//v8/include/cppgc/cross-thread-persistent.h",
+ "//v8/include/cppgc/custom-space.h",
+ "//v8/include/cppgc/default-platform.h",
+ "//v8/include/cppgc/garbage-collected.h",
@@ -878,6 +879,7 @@ index 0000000000000000000000000000000000000000..fbf2c13688d52b5ba320eadac42d472f
+ "//v8/include/cppgc/liveness-broker.h",
+ "//v8/include/cppgc/macros.h",
+ "//v8/include/cppgc/member.h",
+ "//v8/include/cppgc/name-provider.h",
+ "//v8/include/cppgc/persistent.h",
+ "//v8/include/cppgc/platform.h",
+ "//v8/include/cppgc/prefinalizer.h",
@@ -897,6 +899,7 @@ index 0000000000000000000000000000000000000000..fbf2c13688d52b5ba320eadac42d472f
+ "//v8/include/cppgc/internal/finalizer-trait.h",
+ "//v8/include/cppgc/internal/gc-info.h",
+ "//v8/include/cppgc/internal/logging.h",
+ "//v8/include/cppgc/internal/name-trait.h",
+ "//v8/include/cppgc/internal/persistent-node.h",
+ "//v8/include/cppgc/internal/pointer-policies.h",
+ "//v8/include/cppgc/internal/prefinalizer-handler.h",
@@ -1153,7 +1156,6 @@ index 0000000000000000000000000000000000000000..fbf2c13688d52b5ba320eadac42d472f
+ "lib/internal/worker/js_transferable.js",
+ "lib/internal/watchdog.js",
+ "lib/internal/streams/lazy_transform.js",
+ "lib/internal/streams/async_iterator.js",
+ "lib/internal/streams/buffer_list.js",
+ "lib/internal/streams/duplexpair.js",
+ "lib/internal/streams/from.js",
@@ -1183,7 +1185,8 @@ index 0000000000000000000000000000000000000000..fbf2c13688d52b5ba320eadac42d472f
+ "deps/acorn-plugins/acorn-private-class-elements/index.js",
+ "deps/acorn-plugins/acorn-private-methods/index.js",
+ "deps/acorn-plugins/acorn-static-class-features/index.js",
+ "deps/cjs-module-lexer/lexer.js"
+ "deps/cjs-module-lexer/lexer.js",
+ "deps/cjs-module-lexer/dist/lexer.js"
+ ],
+ "node_sources": [
+ "src/api/async_resource.cc",
@@ -1583,7 +1586,7 @@ index 0000000000000000000000000000000000000000..f3c5c798c0aefcb8cf9b1570a7b4817c
+ args = rebase_path(inputs + outputs, root_build_dir)
+}
diff --git a/src/node_version.h b/src/node_version.h
index 19fa04ebe755ecd120ef0842a02688e121c4c963..fdbde0397dd4bfaa117ca8e9223510b885511ce6 100644
index 7f2f31389637d07fcf0f721daf18b409ade039b4..ffc4ed7085f2b97ce2017245947085e26e7633ac 100644
--- a/src/node_version.h
+++ b/src/node_version.h
@@ -89,7 +89,10 @@

View File

@@ -10,7 +10,7 @@ THe fix for this should land in node-gyp as discussed in above issue,
landing this as temporary patch.
diff --git a/common.gypi b/common.gypi
index 6f309e5cdbf336d27ec88ee5be431a8aebf85d7f..c8618597d8d71b58a46d4aa405536357055edcd3 100644
index 81568d5afabd6d80b4df445124ccd7108801769d..463adbfdd8fb3af5d19ed30461eae46fd647de1a 100644
--- a/common.gypi
+++ b/common.gypi
@@ -19,7 +19,7 @@

View File

@@ -1,89 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Shelley Vohr <shelley.vohr@gmail.com>
Date: Mon, 5 Oct 2020 16:05:45 -0700
Subject: chore: expose v8 initialization isolate callbacks
Exposes v8 initializer callbacks to Electron so that we can call them
directly. We expand upon and adapt their behavior, so allows us to
ensure that we stay in sync with Node.js default behavior.
This will be upstreamed.
diff --git a/src/api/environment.cc b/src/api/environment.cc
index 274d0481529ace763c997910ce40e2c730a20146..194094e1d5bdda4589c7cc4d99270af3cb3ef5a3 100644
--- a/src/api/environment.cc
+++ b/src/api/environment.cc
@@ -30,14 +30,16 @@ using v8::PropertyDescriptor;
using v8::String;
using v8::Value;
-static bool AllowWasmCodeGenerationCallback(Local<Context> context,
+// static
+bool Environment::AllowWasmCodeGenerationCallback(Local<Context> context,
Local<String>) {
Local<Value> wasm_code_gen =
context->GetEmbedderData(ContextEmbedderIndex::kAllowWasmCodeGeneration);
return wasm_code_gen->IsUndefined() || wasm_code_gen->IsTrue();
}
-static bool ShouldAbortOnUncaughtException(Isolate* isolate) {
+// static
+bool Environment::ShouldAbortOnUncaughtException(Isolate* isolate) {
DebugSealHandleScope scope(isolate);
Environment* env = Environment::GetCurrent(isolate);
return env != nullptr &&
@@ -47,7 +49,8 @@ static bool ShouldAbortOnUncaughtException(Isolate* isolate) {
!env->inside_should_not_abort_on_uncaught_scope();
}
-static MaybeLocal<Value> PrepareStackTraceCallback(Local<Context> context,
+// static
+MaybeLocal<Value> Environment::PrepareStackTraceCallback(Local<Context> context,
Local<Value> exception,
Local<Array> trace) {
Environment* env = Environment::GetCurrent(context);
@@ -221,7 +224,7 @@ void SetIsolateErrorHandlers(v8::Isolate* isolate, const IsolateSettings& s) {
auto* abort_callback = s.should_abort_on_uncaught_exception_callback ?
s.should_abort_on_uncaught_exception_callback :
- ShouldAbortOnUncaughtException;
+ Environment::ShouldAbortOnUncaughtException;
isolate->SetAbortOnUncaughtExceptionCallback(abort_callback);
auto* fatal_error_cb = s.fatal_error_callback ?
@@ -229,7 +232,7 @@ void SetIsolateErrorHandlers(v8::Isolate* isolate, const IsolateSettings& s) {
isolate->SetFatalErrorHandler(fatal_error_cb);
auto* prepare_stack_trace_cb = s.prepare_stack_trace_callback ?
- s.prepare_stack_trace_callback : PrepareStackTraceCallback;
+ s.prepare_stack_trace_callback : Environment::PrepareStackTraceCallback;
isolate->SetPrepareStackTraceCallback(prepare_stack_trace_cb);
}
@@ -237,7 +240,7 @@ void SetIsolateMiscHandlers(v8::Isolate* isolate, const IsolateSettings& s) {
isolate->SetMicrotasksPolicy(s.policy);
auto* allow_wasm_codegen_cb = s.allow_wasm_code_generation_callback ?
- s.allow_wasm_code_generation_callback : AllowWasmCodeGenerationCallback;
+ s.allow_wasm_code_generation_callback : Environment::AllowWasmCodeGenerationCallback;
isolate->SetAllowWasmCodeGenerationCallback(allow_wasm_codegen_cb);
if ((s.flags & SHOULD_NOT_SET_PROMISE_REJECTION_CALLBACK) == 0) {
diff --git a/src/env.h b/src/env.h
index 4fe2eb3b7699efcab87c377743a955effbbfd9de..2bb196d199bd9b6c27d9de8ca7e5a9bffad0c788 100644
--- a/src/env.h
+++ b/src/env.h
@@ -904,6 +904,13 @@ class Environment : public MemoryRetainer {
void Exit(int code);
void ExitEnv();
+ static bool AllowWasmCodeGenerationCallback(v8::Local<v8::Context> context,
+ v8::Local<v8::String>);
+ static bool ShouldAbortOnUncaughtException(v8::Isolate* isolate);
+ static v8::MaybeLocal<v8::Value> PrepareStackTraceCallback(v8::Local<v8::Context> context,
+ v8::Local<v8::Value> exception,
+ v8::Local<v8::Array> trace);
+
// Register clean-up cb to be called on environment destruction.
inline void RegisterHandleCleanup(uv_handle_t* handle,
HandleCleanupCb cb,

View File

@@ -8,10 +8,10 @@ once we stop warning and begin to unilaterally prevent non-context aware modules
from being loaded.
diff --git a/lib/internal/bootstrap/pre_execution.js b/lib/internal/bootstrap/pre_execution.js
index f947c6bf27e80c534a8f72265d0139a8b5b3f13a..d7e56d9c3fe5a56897989915984cb823d27b9c52 100644
index 1b781fb8193002e111d8904e44ca66dbec9daaac..3f80a6e4c03a51d40c25717baab5c690c53abccd 100644
--- a/lib/internal/bootstrap/pre_execution.js
+++ b/lib/internal/bootstrap/pre_execution.js
@@ -92,10 +92,12 @@ function patchProcessObject(expandArgv1) {
@@ -93,10 +93,12 @@ function patchProcessObject(expandArgv1) {
if (expandArgv1 && process.argv[1] && !process.argv[1].startsWith('-')) {
// Expand process.argv[1] into a full path.

File diff suppressed because it is too large Load Diff

View File

@@ -8,7 +8,7 @@ node modules will have different (wrong) ideas about how v8 structs are laid
out in memory on 64-bit machines, and will summarily fail to work.
diff --git a/common.gypi b/common.gypi
index c8618597d8d71b58a46d4aa405536357055edcd3..5e209300b5ce85c2a6e15480465623f911053960 100644
index 463adbfdd8fb3af5d19ed30461eae46fd647de1a..4d63ac7981edca3f99c05ce08af8ea41628b0387 100644
--- a/common.gypi
+++ b/common.gypi
@@ -64,7 +64,7 @@

View File

@@ -65,7 +65,7 @@ index 905afd8c235b7b1a7b45823db486384935a2a52b..102847cd32d03addeb40c9539eafc92b
NativeModuleEnv::InitializeCodeCache();
diff --git a/src/node.h b/src/node.h
index 33e11327e487bca9d0d7b5cd5a1c036c7009a359..7340d1a6f0cf2f912aaee15d66ed137fe2870bab 100644
index 38e0ef50f9b283b1d7ca8f54412d99b8cd38e524..34a16feaed229a59181e1b2e48b0e111d5b0b2a6 100644
--- a/src/node.h
+++ b/src/node.h
@@ -220,6 +220,8 @@ namespace node {

View File

@@ -6,10 +6,10 @@ Subject: feat: initialize asar support
This patch initializes asar support in Node.js.
diff --git a/lib/internal/bootstrap/pre_execution.js b/lib/internal/bootstrap/pre_execution.js
index dfbefa955cab8adcafc5f46151ac83ed893645e0..f947c6bf27e80c534a8f72265d0139a8b5b3f13a 100644
index 9689e2a9edf69530546d5238155f6ea28dd70daf..1b781fb8193002e111d8904e44ca66dbec9daaac 100644
--- a/lib/internal/bootstrap/pre_execution.js
+++ b/lib/internal/bootstrap/pre_execution.js
@@ -73,6 +73,7 @@ function prepareMainThreadExecution(expandArgv1 = false) {
@@ -74,6 +74,7 @@ function prepareMainThreadExecution(expandArgv1 = false) {
assert(!CJSLoader.hasLoadedAnyUserCJSModule);
loadPreloadModules();
initializeFrozenIntrinsics();
@@ -17,7 +17,7 @@ index dfbefa955cab8adcafc5f46151ac83ed893645e0..f947c6bf27e80c534a8f72265d0139a8
}
function patchProcessObject(expandArgv1) {
@@ -447,6 +448,10 @@ function loadPreloadModules() {
@@ -448,6 +449,10 @@ function loadPreloadModules() {
}
}

View File

@@ -8,7 +8,7 @@ common.gypi is a file that's included in the node header bundle, despite
the fact that we do not build node with gyp.
diff --git a/common.gypi b/common.gypi
index 33b1325eb513eadfb4b5aba77e52bd63aa1c9980..6f309e5cdbf336d27ec88ee5be431a8aebf85d7f 100644
index 4745bb5ac77639a97b30a9730d0ab990fdcca05e..81568d5afabd6d80b4df445124ccd7108801769d 100644
--- a/common.gypi
+++ b/common.gypi
@@ -81,6 +81,22 @@

View File

@@ -6,7 +6,7 @@ Subject: fix: add v8_enable_reverse_jsargs defines in common.gypi
This can be removed once node upgrades V8 and inevitably has to do this exact same thing. Also hi node people if you are looking at this.
diff --git a/common.gypi b/common.gypi
index 5e209300b5ce85c2a6e15480465623f911053960..27892535631a3e6431bdb3bdea15d0c4ee6e2b59 100644
index 4d63ac7981edca3f99c05ce08af8ea41628b0387..42d353c7495ff29a58a942ad72227ada8be662a9 100644
--- a/common.gypi
+++ b/common.gypi
@@ -65,6 +65,7 @@

View File

@@ -11,7 +11,7 @@ initialize it in the browser process. This adds a new
EnvironmentFlags option which allows preventing that invocation.
diff --git a/src/api/environment.cc b/src/api/environment.cc
index 5110c9f754f7653261f7de6d5f0c35e541880a4d..274d0481529ace763c997910ce40e2c730a20146 100644
index 53b07052e43a09f29f863ee1b2287bdebe7b7a7f..c08fe4b32d4155badb572f15529f903c0ec63146 100644
--- a/src/api/environment.cc
+++ b/src/api/environment.cc
@@ -358,12 +358,14 @@ Environment* CreateEnvironment(
@@ -63,7 +63,7 @@ index 38d17f4e18aa38fde2c2f59a9816c8fb0f65fd51..4fe2eb3b7699efcab87c377743a955ef
inline worker::Worker* worker_context() const;
Environment* worker_parent_env() const;
diff --git a/src/node.h b/src/node.h
index b9493d1f3d5b4f192609f1e7529715ec30ab46e2..019620ad0c6a0ca80e6cbcfc5a8322f4e1220bb1 100644
index a649f52403659fd18898e1e813f97e32f33784e7..b646fdda58ebcbf2dd92ee4fc9cb0d9c039174d1 100644
--- a/src/node.h
+++ b/src/node.h
@@ -426,7 +426,11 @@ enum Flags : uint64_t {

View File

@@ -6,10 +6,10 @@ Subject: fix: expose InternalCallbackScope
This commit exposes InternalCallbackScope in order to allow us access to its internal flags.
diff --git a/src/node_internals.h b/src/node_internals.h
index c8952e59a2b071c94eaba41393df5b2aa238318e..ab664208076ea776fcb2223dbc228cacd3eb7e58 100644
index aa7180e18544cab4004a0ef87ba230bd2e732d28..9a5b2165d5648045ea18d66b0c15d29b4ea1cced 100644
--- a/src/node_internals.h
+++ b/src/node_internals.h
@@ -204,7 +204,7 @@ v8::MaybeLocal<v8::Value> InternalMakeCallback(
@@ -200,7 +200,7 @@ v8::MaybeLocal<v8::Value> InternalMakeCallback(
v8::Local<v8::Value> argv[],
async_context asyncContext);

View File

@@ -5,7 +5,7 @@ Subject: fix: expose tracing::Agent and use tracing::TracingController instead
of v8::TracingController
diff --git a/src/api/environment.cc b/src/api/environment.cc
index 9a2661ce8b6146a73b910444a49e01e20c8d96e5..5110c9f754f7653261f7de6d5f0c35e541880a4d 100644
index 2c4acbc4fa0eca3b7c6d03b997445633646446e7..53b07052e43a09f29f863ee1b2287bdebe7b7a7f 100644
--- a/src/api/environment.cc
+++ b/src/api/environment.cc
@@ -472,6 +472,10 @@ MultiIsolatePlatform* GetMultiIsolatePlatform(IsolateData* env) {
@@ -20,7 +20,7 @@ index 9a2661ce8b6146a73b910444a49e01e20c8d96e5..5110c9f754f7653261f7de6d5f0c35e5
int thread_pool_size,
node::tracing::TracingController* tracing_controller) {
diff --git a/src/node.h b/src/node.h
index 7340d1a6f0cf2f912aaee15d66ed137fe2870bab..b9493d1f3d5b4f192609f1e7529715ec30ab46e2 100644
index 34a16feaed229a59181e1b2e48b0e111d5b0b2a6..a649f52403659fd18898e1e813f97e32f33784e7 100644
--- a/src/node.h
+++ b/src/node.h
@@ -125,6 +125,7 @@ namespace node {
@@ -31,7 +31,7 @@ index 7340d1a6f0cf2f912aaee15d66ed137fe2870bab..b9493d1f3d5b4f192609f1e7529715ec
class TracingController;
}
@@ -512,6 +513,8 @@ NODE_DEPRECATED("Use GetMultiIsolatePlatform(env) instead",
@@ -522,6 +523,8 @@ NODE_DEPRECATED("Use GetMultiIsolatePlatform(env) instead",
NODE_EXTERN MultiIsolatePlatform* GetMultiIsolatePlatform(Environment* env);
NODE_EXTERN MultiIsolatePlatform* GetMultiIsolatePlatform(IsolateData* env);

View File

@@ -7,10 +7,10 @@ This broke the build at some point. Does it still? We should probably remove
this patch and find out!
diff --git a/src/node_internals.h b/src/node_internals.h
index ab664208076ea776fcb2223dbc228cacd3eb7e58..4a1c3392cf53490bcb883e826bf731a4a674ef61 100644
index 9a5b2165d5648045ea18d66b0c15d29b4ea1cced..6aff1a4ee7f708437dbf581b9eacc21e5bdd1c43 100644
--- a/src/node_internals.h
+++ b/src/node_internals.h
@@ -372,10 +372,11 @@ class TraceEventScope {
@@ -368,10 +368,11 @@ class TraceEventScope {
TraceEventScope(const char* category,
const char* name,
void* id) : category_(category), name_(name), id_(id) {

View File

@@ -48,14 +48,20 @@ def getBrokenLinks(filepath):
finally:
f.close()
regexLink = re.compile('\[(.*?)\]\((?P<links>(.*?))\)')
linkRegexLink = re.compile('\[(.*?)\]\((?P<link>(.*?))\)')
referenceLinkRegex = re.compile('^\s{0,3}\[.*?\]:\s*(?P<link>[^<\s]+|<[^<>\r\n]+>)')
links = []
for line in lines:
matchLinks = regexLink.search(line)
matchLinks = linkRegexLink.search(line)
matchReferenceLinks = referenceLinkRegex.search(line)
if matchLinks:
relativeLink = matchLinks.group('links')
relativeLink = matchLinks.group('link')
if not str(relativeLink).startswith('http'):
links.append(relativeLink)
if matchReferenceLinks:
referenceLink = matchReferenceLinks.group('link').strip('<>')
if not str(referenceLink).startswith('http'):
links.append(referenceLink)
for link in links:
sections = link.split('#')

View File

@@ -46,9 +46,12 @@ const main = async () => {
const webpackTargetsWithDeps = await Promise.all(webpackTargets.map(async webpackTarget => {
const tmpDir = await fs.mkdtemp(path.resolve(os.tmpdir(), 'electron-filenames-'));
const child = cp.spawn('node', [
'build/webpack/get-outputs.js',
`./${webpackTarget.config}`,
path.resolve(tmpDir, `${webpackTarget.name}.measure.js`)
'./node_modules/webpack-cli/bin/cli.js',
'--config', `./build/webpack/${webpackTarget.config}`,
'--display', 'errors-only',
`--output-path=${tmpDir}`,
`--output-filename=${webpackTarget.name}.measure.js`,
'--env.PRINT_WEBPACK_GRAPH'
], {
cwd: path.resolve(__dirname, '..')
});

View File

@@ -23,6 +23,8 @@ const IGNORELIST = new Set([
['spec', 'ts-smoke', 'runner.js']
].map(tokens => path.join(SOURCE_ROOT, ...tokens)));
const IS_WINDOWS = process.platform === 'win32';
function spawnAndCheckExitCode (cmd, args, opts) {
opts = Object.assign({ stdio: 'inherit' }, opts);
const status = childProcess.spawnSync(cmd, args, opts).status;
@@ -30,7 +32,7 @@ function spawnAndCheckExitCode (cmd, args, opts) {
}
function cpplint (args) {
const result = childProcess.spawnSync('cpplint.py', args, { encoding: 'utf8' });
const result = childProcess.spawnSync(IS_WINDOWS ? 'cpplint.bat' : 'cpplint.py', args, { encoding: 'utf8', shell: true });
// cpplint.py writes EVERYTHING to stderr, including status messages
if (result.stderr) {
for (const line of result.stderr.split(/[\r\n]+/)) {
@@ -39,8 +41,9 @@ function cpplint (args) {
}
}
}
if (result.status) {
process.exit(result.status);
if (result.status !== 0) {
if (result.error) console.error(result.error);
process.exit(result.status || 1);
}
}
@@ -183,6 +186,11 @@ const LINTERS = [{
console.warn(`Patch file '${f}' has no description. Every patch must contain a justification for why the patch exists and the plan for its removal.`);
ok = false;
}
const trailingWhitespace = patchText.split('\n').filter(line => line.startsWith('+')).some(line => /\s+$/.test(line));
if (trailingWhitespace) {
console.warn(`Patch file '${f}' has trailing whitespace on some lines.`);
ok = false;
}
});
if (!ok) {
process.exit(1);

View File

@@ -0,0 +1,185 @@
#!/usr/bin/env python
from __future__ import print_function
import argparse
import hashlib
import json
import os
import posixpath
import sys
import traceback
from lib.patches import patch_from_dir
def patched_file_paths(patches_config):
for patch_dir, repo in patches_config.items():
for line in patch_from_dir(patch_dir).split("\n"):
if line.startswith("+++"):
yield posixpath.join(repo, line[6:])
def generate_cache(patches_config):
mtime_cache = {}
for file_path in patched_file_paths(patches_config):
if file_path in mtime_cache:
# File may be patched multiple times, we don't need to
# rehash it since we are looking at the final result
continue
if not os.path.exists(file_path):
print("Skipping non-existent file:", file_path)
continue
with open(file_path, "rb") as f:
mtime_cache[file_path] = {
"sha256": hashlib.sha256(f.read()).hexdigest(),
"atime": os.path.getatime(file_path),
"mtime": os.path.getmtime(file_path),
}
return mtime_cache
def apply_mtimes(mtime_cache):
updates = []
for file_path, metadata in mtime_cache.items():
if not os.path.exists(file_path):
print("Skipping non-existent file:", file_path)
continue
with open(file_path, "rb") as f:
if hashlib.sha256(f.read()).hexdigest() == metadata["sha256"]:
updates.append(
[file_path, metadata["atime"], metadata["mtime"]]
)
# We can't atomically set the times for all files at once, but by waiting
# to update until we've checked all the files we at least have less chance
# of only updating some files due to an error on one of the files
for [file_path, atime, mtime] in updates:
os.utime(file_path, (atime, mtime))
def set_mtimes(patches_config, mtime):
mtime_cache = {}
for file_path in patched_file_paths(patches_config):
if file_path in mtime_cache:
continue
if not os.path.exists(file_path):
print("Skipping non-existent file:", file_path)
continue
mtime_cache[file_path] = mtime
for file_path in mtime_cache:
os.utime(file_path, (mtime_cache[file_path], mtime_cache[file_path]))
def main():
parser = argparse.ArgumentParser(
description="Make mtime cache for patched files"
)
subparsers = parser.add_subparsers(
dest="operation", help="sub-command help"
)
apply_subparser = subparsers.add_parser(
"apply", help="apply the mtimes from the cache"
)
apply_subparser.add_argument(
"--cache-file", required=True, help="mtime cache file"
)
apply_subparser.add_argument(
"--preserve-cache",
action="store_true",
help="don't delete cache after applying",
)
generate_subparser = subparsers.add_parser(
"generate", help="generate the mtime cache"
)
generate_subparser.add_argument(
"--cache-file",
type=argparse.FileType("w"),
required=True,
help="mtime cache file",
)
set_subparser = subparsers.add_parser(
"set", help="set all mtimes to a specific date"
)
set_subparser.add_argument(
"--mtime",
type=int,
required=True,
help="mtime to use for all patched files",
)
for subparser in [generate_subparser, set_subparser]:
subparser.add_argument(
"--patches-config",
type=argparse.FileType("r"),
required=True,
help="patches' config in the JSON format",
)
args = parser.parse_args()
if args.operation == "generate":
try:
mtime_cache = generate_cache(json.load(args.patches_config))
json.dump(mtime_cache, args.cache_file, indent=2)
except Exception:
print(
"ERROR: failed to generate mtime cache for patches",
file=sys.stderr,
)
traceback.print_exc(file=sys.stderr)
return 0
elif args.operation == "apply":
if not os.path.exists(args.cache_file):
print("ERROR: --cache-file does not exist", file=sys.stderr)
return 0 # Cache file may not exist, fail more gracefully
try:
with open(args.cache_file, mode="r") as f:
apply_mtimes(json.load(f))
if not args.preserve_cache:
os.remove(args.cache_file)
except Exception:
print(
"ERROR: failed to apply mtime cache for patches",
file=sys.stderr,
)
traceback.print_exc(file=sys.stderr)
return 0
elif args.operation == "set":
# Python 2/3 compatibility
try:
user_input = raw_input
except NameError:
user_input = input
answer = user_input(
"WARNING: Manually setting mtimes could mess up your build. "
"If you're sure, type yes: "
)
if answer.lower() != "yes":
print("Aborting")
return 0
set_mtimes(json.load(args.patches_config), args.mtime)
return 0
if __name__ == "__main__":
sys.exit(main())

View File

@@ -381,6 +381,7 @@ async function getBranchNameOfRef (ref, dir) {
return (await runGit(dir, ['branch', '--all', '--contains', ref, '--sort', 'version:refname']))
.split(/\r?\n/) // split into lines
.shift() // we sorted by refname and want the first result
.match(/(?:\s?\*\s){0,1}(.*)/)[1] // if present, remove leading '* ' in case we're currently in that branch
.match(/(?:.*\/)?(.*)/)[1] // 'remote/origins/10-x-y' -> '10-x-y'
.trim();
}
@@ -398,7 +399,7 @@ const getNotes = async (fromRef, toRef, newVersion) => {
const pool = new Pool();
const toBranch = await getBranchNameOfRef(toRef, ELECTRON_DIR);
console.log(`Generating release notes between ${fromRef} and ${toRef} for version ${newVersion} in branch ${toBranch}`);
console.log(`Generating release notes between '${fromRef}' and '${toRef}' for version '${newVersion}' in branch '${toBranch}'`);
// get the electron/electron commits
const electron = { owner: 'electron', repo: 'electron', dir: ELECTRON_DIR };

View File

@@ -999,7 +999,7 @@ void BaseWindow::SetIcon(gin::Handle<NativeImage> icon) {
static_cast<NativeWindowViews*>(window_.get())
->SetIcon(icon->GetHICON(GetSystemMetrics(SM_CXSMICON)),
icon->GetHICON(GetSystemMetrics(SM_CXICON)));
#elif defined(USE_X11)
#elif defined(OS_LINUX)
static_cast<NativeWindowViews*>(window_.get())
->SetIcon(icon->image().AsImageSkia());
#endif

View File

@@ -12,12 +12,39 @@
#include "shell/browser/native_window.h"
#include "shell/common/gin_converters/accelerator_converter.h"
#include "shell/common/gin_converters/callback_converter.h"
#include "shell/common/gin_converters/file_path_converter.h"
#include "shell/common/gin_converters/gurl_converter.h"
#include "shell/common/gin_converters/image_converter.h"
#include "shell/common/gin_helper/dictionary.h"
#include "shell/common/gin_helper/object_template_builder.h"
#include "shell/common/node_includes.h"
#include "ui/base/models/image_model.h"
#if defined(OS_MAC)
namespace gin {
using SharingItem = electron::ElectronMenuModel::SharingItem;
template <>
struct Converter<SharingItem> {
static bool FromV8(v8::Isolate* isolate,
v8::Local<v8::Value> val,
SharingItem* out) {
gin_helper::Dictionary dict;
if (!ConvertFromV8(isolate, val, &dict))
return false;
dict.GetOptional("texts", &(out->texts));
dict.GetOptional("filePaths", &(out->file_paths));
dict.GetOptional("urls", &(out->urls));
return true;
}
};
} // namespace gin
#endif
namespace electron {
namespace api {
@@ -26,6 +53,15 @@ gin::WrapperInfo Menu::kWrapperInfo = {gin::kEmbedderNativeGin};
Menu::Menu(gin::Arguments* args) : model_(new ElectronMenuModel(this)) {
model_->AddObserver(this);
#if defined(OS_MAC)
gin_helper::Dictionary options;
if (args->GetNext(&options)) {
ElectronMenuModel::SharingItem item;
if (options.Get("sharingItem", &item))
model_->SetSharingItem(std::move(item));
}
#endif
}
Menu::~Menu() {
@@ -81,6 +117,19 @@ bool Menu::ShouldRegisterAcceleratorForCommandId(int command_id) const {
command_id);
}
#if defined(OS_MAC)
bool Menu::GetSharingItemForCommandId(
int command_id,
ElectronMenuModel::SharingItem* item) const {
v8::Isolate* isolate = JavascriptEnvironment::GetIsolate();
v8::HandleScope handle_scope(isolate);
v8::Local<v8::Value> val =
gin_helper::CallMethod(isolate, const_cast<Menu*>(this),
"_getSharingItemForCommandId", command_id);
return gin::ConvertFromV8(isolate, val, item);
}
#endif
void Menu::ExecuteCommand(int command_id, int flags) {
v8::Isolate* isolate = JavascriptEnvironment::GetIsolate();
v8::HandleScope scope(isolate);

View File

@@ -64,6 +64,11 @@ class Menu : public gin::Wrappable<Menu>,
bool use_default_accelerator,
ui::Accelerator* accelerator) const override;
bool ShouldRegisterAcceleratorForCommandId(int command_id) const override;
#if defined(OS_MAC)
bool GetSharingItemForCommandId(
int command_id,
ElectronMenuModel::SharingItem* item) const override;
#endif
void ExecuteCommand(int command_id, int event_flags) override;
void OnMenuWillShow(ui::SimpleMenuModel* source) override;

View File

@@ -5,6 +5,7 @@
#include <string>
#include "gin/handle.h"
#include "net/base/network_change_notifier.h"
#include "services/network/public/cpp/features.h"
#include "shell/browser/api/electron_api_url_loader.h"
#include "shell/common/gin_helper/dictionary.h"
@@ -14,6 +15,10 @@
namespace {
bool IsOnline() {
return !net::NetworkChangeNotifier::IsOffline();
}
bool IsValidHeaderName(std::string header_name) {
return net::HttpUtil::IsValidHeaderName(header_name);
}
@@ -31,6 +36,7 @@ void Initialize(v8::Local<v8::Object> exports,
v8::Isolate* isolate = context->GetIsolate();
gin_helper::Dictionary dict(isolate, exports);
dict.SetMethod("isOnline", &IsOnline);
dict.SetMethod("isValidHeaderName", &IsValidHeaderName);
dict.SetMethod("isValidHeaderValue", &IsValidHeaderValue);
dict.SetMethod("createURLLoader", &SimpleURLLoaderWrapper::Create);

View File

@@ -236,11 +236,11 @@ const base::FilePath::StringPieceType kPathDelimiter = FILE_PATH_LITERAL(":");
// below. Extension, and isolated apps require different privileges to be
// granted to their RenderProcessHosts. This classification allows us to make
// sure URLs are served by hosts with the right set of privileges.
enum RenderProcessHostPrivilege {
PRIV_NORMAL,
PRIV_HOSTED,
PRIV_ISOLATED,
PRIV_EXTENSION,
enum class RenderProcessHostPrivilege {
Normal,
Hosted,
Isolated,
Extension,
};
RenderProcessHostPrivilege GetPrivilegeRequiredByUrl(
@@ -253,12 +253,12 @@ RenderProcessHostPrivilege GetPrivilegeRequiredByUrl(
// than normal webrenderer, the navigation logic will correct us out of band
// anyways.
if (!url.is_valid())
return PRIV_NORMAL;
return RenderProcessHostPrivilege::Normal;
if (!url.SchemeIs(extensions::kExtensionScheme))
return PRIV_NORMAL;
return RenderProcessHostPrivilege::Normal;
return PRIV_EXTENSION;
return RenderProcessHostPrivilege::Extension;
}
RenderProcessHostPrivilege GetProcessPrivilege(
@@ -268,9 +268,9 @@ RenderProcessHostPrivilege GetProcessPrivilege(
std::set<std::string> extension_ids =
process_map->GetExtensionsInProcess(process_host->GetID());
if (extension_ids.empty())
return PRIV_NORMAL;
return RenderProcessHostPrivilege::Normal;
return PRIV_EXTENSION;
return RenderProcessHostPrivilege::Extension;
}
const extensions::Extension* GetEnabledExtensionFromEffectiveURL(

View File

@@ -59,20 +59,32 @@
#include "ui/wm/core/wm_state.h"
#endif
#if defined(USE_X11)
#if defined(OS_LINUX)
#include "base/environment.h"
#include "base/nix/xdg_util.h"
#include "base/threading/thread_task_runner_handle.h"
#include "ui/gtk/gtk_ui.h"
#include "ui/gtk/gtk_ui_delegate.h"
#include "ui/gtk/gtk_util.h"
#include "ui/views/linux_ui/linux_ui.h"
#if defined(USE_OZONE)
#include "ui/ozone/public/ozone_platform.h"
#endif
#if defined(USE_X11)
#include "ui/base/x/x11_util.h"
#include "ui/events/devices/x11/touch_factory_x11.h"
#include "ui/gfx/color_utils.h"
#include "ui/gfx/x/x11_types.h"
#include "ui/gfx/x/xproto_util.h"
#include "ui/gtk/gtk_ui.h"
#include "ui/gtk/gtk_ui_delegate.h"
#include "ui/gtk/gtk_util.h"
#include "ui/gtk/x/gtk_ui_delegate_x11.h"
#include "ui/views/linux_ui/linux_ui.h"
#endif
#if defined(USE_OZONE) || defined(USE_X11)
#include "ui/base/ui_base_features.h"
#endif
#endif
#if defined(OS_WIN)
@@ -336,11 +348,15 @@ void ElectronBrowserMainParts::PostDestroyThreads() {
void ElectronBrowserMainParts::ToolkitInitialized() {
#if defined(USE_X11)
// In Aura/X11, Gtk-based LinuxUI implementation is used.
gtk_ui_delegate_ =
std::make_unique<ui::GtkUiDelegateX11>(x11::Connection::Get());
ui::GtkUiDelegate::SetInstance(gtk_ui_delegate_.get());
views::LinuxUI* linux_ui = BuildGtkUi(gtk_ui_delegate_.get());
if (!features::IsUsingOzonePlatform()) {
// In Aura/X11, Gtk-based LinuxUI implementation is used.
gtk_ui_delegate_ =
std::make_unique<ui::GtkUiDelegateX11>(x11::Connection::Get());
ui::GtkUiDelegate::SetInstance(gtk_ui_delegate_.get());
}
#endif
#if defined(OS_LINUX)
views::LinuxUI* linux_ui = BuildGtkUi(ui::GtkUiDelegate::instance());
views::LinuxUI::SetInstance(linux_ui);
linux_ui->Initialize();
@@ -402,14 +418,10 @@ void ElectronBrowserMainParts::PreMainMessageLoopRun() {
#endif
#if defined(USE_X11)
ui::TouchFactory::SetTouchDeviceListFromCommandLine();
if (!features::IsUsingOzonePlatform())
ui::TouchFactory::SetTouchDeviceListFromCommandLine();
#endif
// Start idle gc.
gc_timer_.Start(FROM_HERE, base::TimeDelta::FromMinutes(1),
base::BindRepeating(&v8::Isolate::LowMemoryNotification,
base::Unretained(js_env_->isolate())));
content::WebUIControllerFactory::RegisterFactory(
ElectronWebUIControllerFactory::GetInstance());
@@ -444,6 +456,14 @@ void ElectronBrowserMainParts::PreDefaultMainMessageLoopRun(
}
void ElectronBrowserMainParts::PostMainMessageLoopStart() {
#if defined(USE_OZONE)
if (features::IsUsingOzonePlatform()) {
auto shutdown_cb =
base::BindOnce(base::RunLoop::QuitCurrentWhenIdleClosureDeprecated());
ui::OzonePlatform::GetInstance()->PostMainMessageLoopStart(
std::move(shutdown_cb));
}
#endif
#if defined(OS_LINUX)
bluez::DBusBluezManagerWrapperLinux::Initialize();
#endif

View File

@@ -29,7 +29,7 @@ class WMState;
}
#endif
#if defined(OS_LINUX)
#if defined(USE_X11)
namespace ui {
class GtkUiDelegate;
}
@@ -133,6 +133,9 @@ class ElectronBrowserMainParts : public content::BrowserMainParts {
#if defined(USE_X11)
std::unique_ptr<ui::GtkUiDelegate> gtk_ui_delegate_;
#endif
#if defined(OS_LINUX)
// Used to notify the native theme of changes to dark mode.
std::unique_ptr<DarkThemeObserver> dark_theme_observer_;
#endif
@@ -158,8 +161,6 @@ class ElectronBrowserMainParts : public content::BrowserMainParts {
std::unique_ptr<ElectronExtensionsBrowserClient> extensions_browser_client_;
#endif
base::RepeatingTimer gc_timer_;
// List of callbacks should be executed before destroying JS env.
std::list<base::OnceClosure> destructors_;

View File

@@ -63,6 +63,11 @@ void AddStringsForPdf(base::DictionaryValue* dict) {
void AddAdditionalDataForPdf(base::DictionaryValue* dict) {
#if BUILDFLAG(ENABLE_PDF)
dict->SetStringKey(
"pdfViewerUpdateEnabledAttribute",
base::FeatureList::IsEnabled(chrome_pdf::features::kPDFViewerUpdate)
? "pdf-viewer-update-enabled"
: "");
dict->SetKey("pdfFormSaveEnabled",
base::Value(base::FeatureList::IsEnabled(
chrome_pdf::features::kSaveEditedPDFForm)));

View File

@@ -27,7 +27,7 @@ void NativeBrowserViewViews::SetAutoResizeProportions(
if ((auto_resize_flags_ & AutoResizeFlags::kAutoResizeHorizontal) &&
!auto_horizontal_proportion_set_) {
auto* iwc_view = GetInspectableWebContentsView();
if (iwc_view)
if (!iwc_view)
return;
auto* view = iwc_view->GetView();
auto view_bounds = view->bounds();
@@ -41,7 +41,7 @@ void NativeBrowserViewViews::SetAutoResizeProportions(
if ((auto_resize_flags_ & AutoResizeFlags::kAutoResizeVertical) &&
!auto_vertical_proportion_set_) {
auto* iwc_view = GetInspectableWebContentsView();
if (iwc_view)
if (!iwc_view)
return;
auto* view = iwc_view->GetView();
auto view_bounds = view->bounds();
@@ -58,7 +58,7 @@ void NativeBrowserViewViews::AutoResize(const gfx::Rect& new_window,
int width_delta,
int height_delta) {
auto* iwc_view = GetInspectableWebContentsView();
if (iwc_view)
if (!iwc_view)
return;
auto* view = iwc_view->GetView();
const auto flags = GetAutoResizeFlags();

View File

@@ -109,7 +109,7 @@ void NativeWindow::InitFromOptions(const gin_helper::Dictionary& options) {
} else {
SetSizeConstraints(size_constraints);
}
#if defined(OS_WIN) || defined(USE_X11)
#if defined(OS_WIN) || defined(OS_LINUX)
bool resizable;
if (options.Get(options::kResizable, &resizable)) {
SetResizable(resizable);

View File

@@ -43,13 +43,17 @@
#include "ui/wm/core/shadow_types.h"
#include "ui/wm/core/window_util.h"
#if defined(USE_X11)
#if defined(OS_LINUX)
#include "base/strings/string_util.h"
#include "shell/browser/browser.h"
#include "shell/browser/linux/unity_service.h"
#include "shell/browser/ui/views/frameless_view.h"
#include "shell/browser/ui/views/global_menu_bar_x11.h"
#include "shell/browser/ui/views/native_frame_view.h"
#include "ui/views/widget/desktop_aura/desktop_window_tree_host_linux.h"
#include "ui/views/window/native_frame_view.h"
#if defined(USE_X11)
#include "shell/browser/ui/views/global_menu_bar_x11.h"
#include "shell/browser/ui/x/event_disabler.h"
#include "shell/browser/ui/x/window_state_watcher.h"
#include "shell/browser/ui/x/x_window_utils.h"
@@ -57,8 +61,12 @@
#include "ui/gfx/x/shape.h"
#include "ui/gfx/x/x11_atom_cache.h"
#include "ui/gfx/x/x11_types.h"
#include "ui/views/widget/desktop_aura/desktop_window_tree_host_linux.h"
#include "ui/views/window/native_frame_view.h"
#endif
#if defined(USE_OZONE) || defined(USE_X11)
#include "ui/base/ui_base_features.h"
#endif
#elif defined(OS_WIN)
#include "base/win/win_util.h"
#include "shell/browser/ui/views/win_frame_view.h"
@@ -211,45 +219,56 @@ NativeWindowViews::NativeWindowViews(const gin_helper::Dictionary& options,
options.Get(options::kType, &window_type);
#if defined(USE_X11)
// Start monitoring window states.
window_state_watcher_ = std::make_unique<WindowStateWatcher>(this);
if (!features::IsUsingOzonePlatform()) {
// Start monitoring window states.
window_state_watcher_ = std::make_unique<WindowStateWatcher>(this);
// Set _GTK_THEME_VARIANT to dark if we have "dark-theme" option set.
bool use_dark_theme = false;
if (options.Get(options::kDarkTheme, &use_dark_theme) && use_dark_theme) {
SetGTKDarkThemeEnabled(use_dark_theme);
// Set _GTK_THEME_VARIANT to dark if we have "dark-theme" option set.
bool use_dark_theme = false;
if (options.Get(options::kDarkTheme, &use_dark_theme) && use_dark_theme) {
SetGTKDarkThemeEnabled(use_dark_theme);
}
}
#endif
// Before the window is mapped the SetWMSpecState can not work, so we have
// to manually set the _NET_WM_STATE.
std::vector<x11::Atom> state_atom_list;
bool skip_taskbar = false;
if (options.Get(options::kSkipTaskbar, &skip_taskbar) && skip_taskbar) {
state_atom_list.push_back(gfx::GetAtom("_NET_WM_STATE_SKIP_TASKBAR"));
}
// Before the window is mapped, there is no SHOW_FULLSCREEN_STATE.
if (fullscreen) {
state_atom_list.push_back(gfx::GetAtom("_NET_WM_STATE_FULLSCREEN"));
}
if (parent) {
#if defined(OS_LINUX)
if (parent)
SetParentWindow(parent);
// Force using dialog type for child window.
window_type = "dialog";
// Modal window needs the _NET_WM_STATE_MODAL hint.
if (is_modal())
state_atom_list.push_back(gfx::GetAtom("_NET_WM_STATE_MODAL"));
#endif
#if defined(USE_X11)
if (!features::IsUsingOzonePlatform()) {
// Before the window is mapped the SetWMSpecState can not work, so we have
// to manually set the _NET_WM_STATE.
std::vector<x11::Atom> state_atom_list;
bool skip_taskbar = false;
if (options.Get(options::kSkipTaskbar, &skip_taskbar) && skip_taskbar) {
state_atom_list.push_back(gfx::GetAtom("_NET_WM_STATE_SKIP_TASKBAR"));
}
// Before the window is mapped, there is no SHOW_FULLSCREEN_STATE.
if (fullscreen) {
state_atom_list.push_back(gfx::GetAtom("_NET_WM_STATE_FULLSCREEN"));
}
if (parent) {
// Force using dialog type for child window.
window_type = "dialog";
// Modal window needs the _NET_WM_STATE_MODAL hint.
if (is_modal())
state_atom_list.push_back(gfx::GetAtom("_NET_WM_STATE_MODAL"));
}
if (!state_atom_list.empty())
ui::SetAtomArrayProperty(static_cast<x11::Window>(GetAcceleratedWidget()),
"_NET_WM_STATE", "ATOM", state_atom_list);
// Set the _NET_WM_WINDOW_TYPE.
if (!window_type.empty())
SetWindowType(static_cast<x11::Window>(GetAcceleratedWidget()),
window_type);
}
if (!state_atom_list.empty())
ui::SetAtomArrayProperty(static_cast<x11::Window>(GetAcceleratedWidget()),
"_NET_WM_STATE", "ATOM", state_atom_list);
// Set the _NET_WM_WINDOW_TYPE.
if (!window_type.empty())
SetWindowType(static_cast<x11::Window>(GetAcceleratedWidget()),
window_type);
#endif
#if defined(OS_WIN)
@@ -331,14 +350,11 @@ NativeWindowViews::~NativeWindowViews() {
void NativeWindowViews::SetGTKDarkThemeEnabled(bool use_dark_theme) {
#if defined(USE_X11)
if (use_dark_theme) {
if (!features::IsUsingOzonePlatform()) {
const std::string color = use_dark_theme ? "dark" : "light";
ui::SetStringProperty(static_cast<x11::Window>(GetAcceleratedWidget()),
gfx::GetAtom("_GTK_THEME_VARIANT"),
gfx::GetAtom("UTF8_STRING"), "dark");
} else {
ui::SetStringProperty(static_cast<x11::Window>(GetAcceleratedWidget()),
gfx::GetAtom("_GTK_THEME_VARIANT"),
gfx::GetAtom("UTF8_STRING"), "light");
gfx::GetAtom("UTF8_STRING"), color);
}
#endif
}
@@ -395,7 +411,7 @@ void NativeWindowViews::Show() {
NotifyWindowShow();
#if defined(USE_X11)
if (global_menu_bar_)
if (!features::IsUsingOzonePlatform() && global_menu_bar_)
global_menu_bar_->OnWindowMapped();
#endif
}
@@ -406,7 +422,7 @@ void NativeWindowViews::ShowInactive() {
NotifyWindowShow();
#if defined(USE_X11)
if (global_menu_bar_)
if (!features::IsUsingOzonePlatform() && global_menu_bar_)
global_menu_bar_->OnWindowMapped();
#endif
}
@@ -420,7 +436,7 @@ void NativeWindowViews::Hide() {
NotifyWindowHide();
#if defined(USE_X11)
if (global_menu_bar_)
if (!features::IsUsingOzonePlatform() && global_menu_bar_)
global_menu_bar_->OnWindowUnmapped();
#endif
}
@@ -432,8 +448,14 @@ bool NativeWindowViews::IsVisible() {
bool NativeWindowViews::IsEnabled() {
#if defined(OS_WIN)
return ::IsWindowEnabled(GetAcceleratedWidget());
#elif defined(USE_X11)
return !event_disabler_.get();
#elif defined(OS_LINUX)
#if defined(USE_X11)
if (!features::IsUsingOzonePlatform()) {
return !event_disabler_.get();
}
#endif
NOTIMPLEMENTED();
return true;
#endif
}
@@ -470,15 +492,17 @@ void NativeWindowViews::SetEnabledInternal(bool enable) {
#if defined(OS_WIN)
::EnableWindow(GetAcceleratedWidget(), enable);
#elif defined(USE_X11)
views::DesktopWindowTreeHostPlatform* tree_host =
views::DesktopWindowTreeHostLinux::GetHostForWidget(
GetAcceleratedWidget());
if (enable) {
tree_host->RemoveEventRewriter(event_disabler_.get());
event_disabler_.reset();
} else {
event_disabler_ = std::make_unique<EventDisabler>();
tree_host->AddEventRewriter(event_disabler_.get());
if (!features::IsUsingOzonePlatform()) {
views::DesktopWindowTreeHostPlatform* tree_host =
views::DesktopWindowTreeHostLinux::GetHostForWidget(
GetAcceleratedWidget());
if (enable) {
tree_host->RemoveEventRewriter(event_disabler_.get());
event_disabler_.reset();
} else {
event_disabler_ = std::make_unique<EventDisabler>();
tree_host->AddEventRewriter(event_disabler_.get());
}
}
#endif
}
@@ -584,7 +608,7 @@ bool NativeWindowViews::IsFullscreen() const {
}
void NativeWindowViews::SetBounds(const gfx::Rect& bounds, bool animate) {
#if defined(OS_WIN) || defined(USE_X11)
#if defined(OS_WIN) || defined(OS_LINUX)
// On Linux and Windows the minimum and maximum size should be updated with
// window size when window is not resizable.
if (!resizable_) {
@@ -675,11 +699,13 @@ bool NativeWindowViews::MoveAbove(const std::string& sourceId) {
0, 0, 0,
SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE | SWP_SHOWWINDOW);
#elif defined(USE_X11)
if (!IsWindowValid(static_cast<x11::Window>(id.id)))
return false;
if (!features::IsUsingOzonePlatform()) {
if (!IsWindowValid(static_cast<x11::Window>(id.id)))
return false;
electron::MoveWindowAbove(static_cast<x11::Window>(GetAcceleratedWidget()),
static_cast<x11::Window>(id.id));
electron::MoveWindowAbove(static_cast<x11::Window>(GetAcceleratedWidget()),
static_cast<x11::Window>(id.id));
}
#endif
return true;
@@ -695,8 +721,10 @@ void NativeWindowViews::MoveTop() {
size.width(), size.height(),
SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE | SWP_SHOWWINDOW);
#elif defined(USE_X11)
electron::MoveWindowToForeground(
static_cast<x11::Window>(GetAcceleratedWidget()));
if (!features::IsUsingOzonePlatform()) {
electron::MoveWindowToForeground(
static_cast<x11::Window>(GetAcceleratedWidget()));
}
#endif
}
@@ -881,8 +909,10 @@ void NativeWindowViews::SetSkipTaskbar(bool skip) {
taskbar_host_.RestoreThumbarButtons(GetAcceleratedWidget());
}
#elif defined(USE_X11)
SetWMSpecState(static_cast<x11::Window>(GetAcceleratedWidget()), skip,
gfx::GetAtom("_NET_WM_STATE_SKIP_TASKBAR"));
if (!features::IsUsingOzonePlatform()) {
SetWMSpecState(static_cast<x11::Window>(GetAcceleratedWidget()), skip,
gfx::GetAtom("_NET_WM_STATE_SKIP_TASKBAR"));
}
#endif
}
@@ -980,23 +1010,27 @@ void NativeWindowViews::SetIgnoreMouseEvents(bool ignore, bool forward) {
SetForwardMouseMessages(forward);
}
#elif defined(USE_X11)
auto* connection = x11::Connection::Get();
if (ignore) {
x11::Rectangle r{0, 0, 1, 1};
connection->shape().Rectangles({
.operation = x11::Shape::So::Set,
.destination_kind = x11::Shape::Sk::Input,
.ordering = x11::ClipOrdering::YXBanded,
.destination_window = static_cast<x11::Window>(GetAcceleratedWidget()),
.rectangles = {r},
});
} else {
connection->shape().Mask({
.operation = x11::Shape::So::Set,
.destination_kind = x11::Shape::Sk::Input,
.destination_window = static_cast<x11::Window>(GetAcceleratedWidget()),
.source_bitmap = x11::Pixmap::None,
});
if (!features::IsUsingOzonePlatform()) {
auto* connection = x11::Connection::Get();
if (ignore) {
x11::Rectangle r{0, 0, 1, 1};
connection->shape().Rectangles({
.operation = x11::Shape::So::Set,
.destination_kind = x11::Shape::Sk::Input,
.ordering = x11::ClipOrdering::YXBanded,
.destination_window =
static_cast<x11::Window>(GetAcceleratedWidget()),
.rectangles = {r},
});
} else {
connection->shape().Mask({
.operation = x11::Shape::So::Set,
.destination_kind = x11::Shape::Sk::Input,
.destination_window =
static_cast<x11::Window>(GetAcceleratedWidget()),
.source_bitmap = x11::Pixmap::None,
});
}
}
#endif
}
@@ -1024,22 +1058,24 @@ void NativeWindowViews::SetFocusable(bool focusable) {
void NativeWindowViews::SetMenu(ElectronMenuModel* menu_model) {
#if defined(USE_X11)
// Remove global menu bar.
if (global_menu_bar_ && menu_model == nullptr) {
global_menu_bar_.reset();
root_view_->UnregisterAcceleratorsWithFocusManager();
return;
}
// Use global application menu bar when possible.
if (ShouldUseGlobalMenuBar()) {
if (!global_menu_bar_)
global_menu_bar_ = std::make_unique<GlobalMenuBarX11>(this);
if (global_menu_bar_->IsServerStarted()) {
root_view_->RegisterAcceleratorsWithFocusManager(menu_model);
global_menu_bar_->SetMenu(menu_model);
if (!features::IsUsingOzonePlatform()) {
// Remove global menu bar.
if (global_menu_bar_ && menu_model == nullptr) {
global_menu_bar_.reset();
root_view_->UnregisterAcceleratorsWithFocusManager();
return;
}
// Use global application menu bar when possible.
if (ShouldUseGlobalMenuBar()) {
if (!global_menu_bar_)
global_menu_bar_ = std::make_unique<GlobalMenuBarX11>(this);
if (global_menu_bar_->IsServerStarted()) {
root_view_->RegisterAcceleratorsWithFocusManager(menu_model);
global_menu_bar_->SetMenu(menu_model);
return;
}
}
}
#endif
@@ -1104,11 +1140,13 @@ void NativeWindowViews::SetParentWindow(NativeWindow* parent) {
NativeWindow::SetParentWindow(parent);
#if defined(USE_X11)
ui::SetProperty(static_cast<x11::Window>(GetAcceleratedWidget()),
x11::Atom::WM_TRANSIENT_FOR, x11::Atom::WINDOW,
parent
? static_cast<x11::Window>(parent->GetAcceleratedWidget())
: ui::GetX11RootWindow());
if (!features::IsUsingOzonePlatform()) {
ui::SetProperty(
static_cast<x11::Window>(GetAcceleratedWidget()),
x11::Atom::WM_TRANSIENT_FOR, x11::Atom::WINDOW,
parent ? static_cast<x11::Window>(parent->GetAcceleratedWidget())
: ui::GetX11RootWindow());
}
#elif defined(OS_WIN)
// To set parentship between windows into Windows is better to play with the
// owner instead of the parent, as Windows natively seems to do if a parent
@@ -1183,14 +1221,16 @@ void NativeWindowViews::SetVisibleOnAllWorkspaces(bool visible,
bool NativeWindowViews::IsVisibleOnAllWorkspaces() {
#if defined(USE_X11)
// Use the presence/absence of _NET_WM_STATE_STICKY in _NET_WM_STATE to
// determine whether the current window is visible on all workspaces.
x11::Atom sticky_atom = gfx::GetAtom("_NET_WM_STATE_STICKY");
std::vector<x11::Atom> wm_states;
ui::GetAtomArrayProperty(static_cast<x11::Window>(GetAcceleratedWidget()),
"_NET_WM_STATE", &wm_states);
return std::find(wm_states.begin(), wm_states.end(), sticky_atom) !=
wm_states.end();
if (!features::IsUsingOzonePlatform()) {
// Use the presence/absence of _NET_WM_STATE_STICKY in _NET_WM_STATE to
// determine whether the current window is visible on all workspaces.
x11::Atom sticky_atom = gfx::GetAtom("_NET_WM_STATE_STICKY");
std::vector<x11::Atom> wm_states;
ui::GetAtomArrayProperty(static_cast<x11::Window>(GetAcceleratedWidget()),
"_NET_WM_STATE", &wm_states);
return std::find(wm_states.begin(), wm_states.end(), sticky_atom) !=
wm_states.end();
}
#endif
return false;
}

View File

@@ -50,8 +50,8 @@ END
//
VS_VERSION_INFO VERSIONINFO
FILEVERSION 12,0,0,20201019
PRODUCTVERSION 12,0,0,20201019
FILEVERSION 12,0,0,20201021
PRODUCTVERSION 12,0,0,20201021
FILEFLAGSMASK 0x3fL
#ifdef _DEBUG
FILEFLAGS 0x1L

View File

@@ -77,11 +77,13 @@ SerialChooserController::SerialChooserController(
DCHECK(chooser_context_);
chooser_context_->GetPortManager()->GetDevices(base::BindOnce(
&SerialChooserController::OnGetDevices, weak_factory_.GetWeakPtr()));
observer_.Add(chooser_context_.get());
}
SerialChooserController::~SerialChooserController() {
RunCallback(/*port=*/nullptr);
if (chooser_context_) {
chooser_context_->RemovePortObserver(this);
}
}
api::Session* SerialChooserController::GetSession() {
@@ -114,10 +116,6 @@ void SerialChooserController::OnPortRemoved(
}
}
void SerialChooserController::OnPortManagerConnectionError() {
observer_.RemoveAll();
}
void SerialChooserController::OnDeviceChosen(const std::string& port_id) {
if (port_id.empty()) {
RunCallback(/*port=*/nullptr);

View File

@@ -10,7 +10,6 @@
#include "base/macros.h"
#include "base/memory/weak_ptr.h"
#include "base/scoped_observer.h"
#include "base/strings/string16.h"
#include "content/public/browser/serial_chooser.h"
#include "content/public/browser/web_contents.h"
@@ -44,7 +43,7 @@ class SerialChooserController final : public SerialChooserContext::PortObserver,
// SerialChooserContext::PortObserver:
void OnPortAdded(const device::mojom::SerialPortInfo& port) override;
void OnPortRemoved(const device::mojom::SerialPortInfo& port) override;
void OnPortManagerConnectionError() override;
void OnPortManagerConnectionError() override {}
private:
api::Session* GetSession();
@@ -59,11 +58,6 @@ class SerialChooserController final : public SerialChooserContext::PortObserver,
url::Origin embedding_origin_;
base::WeakPtr<SerialChooserContext> chooser_context_;
ScopedObserver<SerialChooserContext,
SerialChooserContext::PortObserver,
&SerialChooserContext::AddPortObserver,
&SerialChooserContext::RemovePortObserver>
observer_{this};
std::vector<device::mojom::SerialPortInfoPtr> ports_;

View File

@@ -23,7 +23,8 @@ class ElectronMenuModel;
// allow for hierarchical menus). The tag is the index into that model for
// that particular item. It is important that the model outlives this object
// as it only maintains weak references.
@interface ElectronMenuController : NSObject <NSMenuDelegate> {
@interface ElectronMenuController
: NSObject <NSMenuDelegate, NSSharingServiceDelegate> {
@protected
base::WeakPtr<electron::ElectronMenuModel> model_;
base::scoped_nsobject<NSMenu> menu_;

View File

@@ -5,6 +5,7 @@
#import "shell/browser/ui/cocoa/electron_menu_controller.h"
#include <string>
#include <utility>
#include "base/logging.h"
@@ -14,8 +15,11 @@
#include "base/task/post_task.h"
#include "content/public/browser/browser_task_traits.h"
#include "content/public/browser/browser_thread.h"
#include "net/base/mac/url_conversions.h"
#include "shell/browser/mac/electron_application.h"
#include "shell/browser/native_window.h"
#include "shell/browser/ui/electron_menu_model.h"
#include "shell/browser/window_list.h"
#include "ui/base/accelerators/accelerator.h"
#include "ui/base/accelerators/platform_accelerator_cocoa.h"
#include "ui/base/l10n/l10n_util_mac.h"
@@ -24,6 +28,7 @@
#include "ui/strings/grit/ui_strings.h"
using content::BrowserThread;
using SharingItem = electron::ElectronMenuModel::SharingItem;
namespace {
@@ -86,6 +91,24 @@ NSMenu* MakeEmptySubmenu() {
return submenu.autorelease();
}
// Convert an SharingItem to an array of NSObjects.
NSArray* ConvertSharingItemToNS(const SharingItem& item) {
NSMutableArray* result = [NSMutableArray array];
if (item.texts) {
for (const std::string& str : *item.texts)
[result addObject:base::SysUTF8ToNSString(str)];
}
if (item.file_paths) {
for (const base::FilePath& path : *item.file_paths)
[result addObject:base::mac::FilePathToNSURL(path)];
}
if (item.urls) {
for (const GURL& url : *item.urls)
[result addObject:net::NSURLWithGURL(url)];
}
return result;
}
} // namespace
// This class stores a base::WeakPtr<electron::ElectronMenuModel> as an
@@ -267,6 +290,31 @@ static base::scoped_nsobject<NSMenu> recentDocumentsMenuSwap_;
recentDocumentsMenuItem_.reset([item retain]);
}
// Fill the menu with Share Menu items.
- (NSMenu*)createShareMenuForItem:(const SharingItem&)item {
NSArray* items = ConvertSharingItemToNS(item);
if ([items count] == 0)
return MakeEmptySubmenu();
base::scoped_nsobject<NSMenu> menu([[NSMenu alloc] init]);
NSArray* services = [NSSharingService sharingServicesForItems:items];
for (NSSharingService* service in services)
[menu addItem:[self menuItemForService:service withItems:items]];
return menu.autorelease();
}
// Creates a menu item that calls |service| when invoked.
- (NSMenuItem*)menuItemForService:(NSSharingService*)service
withItems:(NSArray*)items {
base::scoped_nsobject<NSMenuItem> item([[NSMenuItem alloc]
initWithTitle:service.menuItemTitle
action:@selector(performShare:)
keyEquivalent:@""]);
[item setTarget:self];
[item setImage:service.image];
[item setRepresentedObject:@{@"service" : service, @"items" : items}];
return item.autorelease();
}
// Adds an item or a hierarchical menu to the item at the |index|,
// associated with the entry in the model identified by |modelIndex|.
- (void)addItemToMenu:(NSMenu*)menu
@@ -300,6 +348,12 @@ static base::scoped_nsobject<NSMenu> recentDocumentsMenuSwap_;
NSMenu* submenu = [[[NSMenu alloc] initWithTitle:label] autorelease];
[item setSubmenu:submenu];
[NSApp setServicesMenu:submenu];
} else if (role == base::ASCIIToUTF16("sharemenu")) {
SharingItem sharing_item;
model->GetSharingItemAt(index, &sharing_item);
[item setTarget:nil];
[item setAction:nil];
[item setSubmenu:[self createShareMenuForItem:sharing_item]];
} else if (type == electron::ElectronMenuModel::TYPE_SUBMENU &&
model->IsVisibleAt(index)) {
// We need to specifically check that the submenu top-level item has been
@@ -372,6 +426,8 @@ static base::scoped_nsobject<NSMenu> recentDocumentsMenuSwap_;
// radio, etc) of each item in the menu.
- (BOOL)validateUserInterfaceItem:(id<NSValidatedUserInterfaceItem>)item {
SEL action = [item action];
if (action == @selector(performShare:))
return YES;
if (action != @selector(itemSelected:))
return NO;
@@ -405,14 +461,30 @@ static base::scoped_nsobject<NSMenu> recentDocumentsMenuSwap_;
}
}
// Performs the share action using the sharing service represented by |sender|.
- (void)performShare:(NSMenuItem*)sender {
NSDictionary* object =
base::mac::ObjCCastStrict<NSDictionary>([sender representedObject]);
NSSharingService* service =
base::mac::ObjCCastStrict<NSSharingService>(object[@"service"]);
NSArray* items = base::mac::ObjCCastStrict<NSArray>(object[@"items"]);
[service setDelegate:self];
[service performWithItems:items];
}
- (NSMenu*)menu {
if (menu_)
return menu_.get();
menu_.reset([[NSMenu alloc] initWithTitle:@""]);
if (model_ && model_->GetSharingItem()) {
NSMenu* menu = [self createShareMenuForItem:*model_->GetSharingItem()];
menu_.reset([menu retain]);
} else {
menu_.reset([[NSMenu alloc] initWithTitle:@""]);
if (model_)
[self populateWithModel:model_.get()];
}
[menu_ setDelegate:self];
if (model_)
[self populateWithModel:model_.get()];
return menu_.get();
}
@@ -439,4 +511,18 @@ static base::scoped_nsobject<NSMenu> recentDocumentsMenuSwap_;
}
}
// NSSharingServiceDelegate
- (NSWindow*)sharingService:(NSSharingService*)service
sourceWindowForShareItems:(NSArray*)items
sharingContentScope:(NSSharingContentScope*)scope {
// Return the current active window.
const auto& list = electron::WindowList::GetWindows();
for (electron::NativeWindow* window : list) {
if (window->IsFocused())
return window->GetNativeWindow().GetNativeNSWindow();
}
return nil;
}
@end

View File

@@ -4,10 +4,18 @@
#include "shell/browser/ui/electron_menu_model.h"
#include <utility>
#include "base/stl_util.h"
namespace electron {
#if defined(OS_MAC)
ElectronMenuModel::SharingItem::SharingItem() = default;
ElectronMenuModel::SharingItem::SharingItem(SharingItem&&) = default;
ElectronMenuModel::SharingItem::~SharingItem() = default;
#endif
bool ElectronMenuModel::Delegate::GetAcceleratorForCommandId(
int command_id,
ui::Accelerator* accelerator) const {
@@ -79,6 +87,23 @@ bool ElectronMenuModel::WorksWhenHiddenAt(int index) const {
return true;
}
#if defined(OS_MAC)
bool ElectronMenuModel::GetSharingItemAt(int index, SharingItem* item) const {
if (delegate_)
return delegate_->GetSharingItemForCommandId(GetCommandIdAt(index), item);
return false;
}
void ElectronMenuModel::SetSharingItem(SharingItem item) {
sharing_item_.emplace(std::move(item));
}
const base::Optional<ElectronMenuModel::SharingItem>&
ElectronMenuModel::GetSharingItem() const {
return sharing_item_;
}
#endif
void ElectronMenuModel::MenuWillClose() {
ui::SimpleMenuModel::MenuWillClose();
for (Observer& observer : observers_) {

View File

@@ -6,16 +6,34 @@
#define SHELL_BROWSER_UI_ELECTRON_MENU_MODEL_H_
#include <map>
#include <string>
#include <vector>
#include "base/files/file_path.h"
#include "base/memory/weak_ptr.h"
#include "base/observer_list.h"
#include "base/observer_list_types.h"
#include "base/optional.h"
#include "ui/base/models/simple_menu_model.h"
#include "url/gurl.h"
namespace electron {
class ElectronMenuModel : public ui::SimpleMenuModel {
public:
#if defined(OS_MAC)
struct SharingItem {
SharingItem();
SharingItem(SharingItem&&);
SharingItem(const SharingItem&) = delete;
~SharingItem();
base::Optional<std::vector<std::string>> texts;
base::Optional<std::vector<GURL>> urls;
base::Optional<std::vector<base::FilePath>> file_paths;
};
#endif
class Delegate : public ui::SimpleMenuModel::Delegate {
public:
~Delegate() override {}
@@ -30,6 +48,11 @@ class ElectronMenuModel : public ui::SimpleMenuModel {
virtual bool ShouldCommandIdWorkWhenHidden(int command_id) const = 0;
#if defined(OS_MAC)
virtual bool GetSharingItemForCommandId(int command_id,
SharingItem* item) const = 0;
#endif
private:
// ui::SimpleMenuModel::Delegate:
bool GetAcceleratorForCommandId(
@@ -65,6 +88,13 @@ class ElectronMenuModel : public ui::SimpleMenuModel {
ui::Accelerator* accelerator) const;
bool ShouldRegisterAcceleratorAt(int index) const;
bool WorksWhenHiddenAt(int index) const;
#if defined(OS_MAC)
// Return the SharingItem of menu item.
bool GetSharingItemAt(int index, SharingItem* item) const;
// Set/Get the SharingItem of this menu.
void SetSharingItem(SharingItem item);
const base::Optional<SharingItem>& GetSharingItem() const;
#endif
// ui::SimpleMenuModel:
void MenuWillClose() override;
@@ -80,6 +110,10 @@ class ElectronMenuModel : public ui::SimpleMenuModel {
private:
Delegate* delegate_; // weak ref.
#if defined(OS_MAC)
base::Optional<SharingItem> sharing_item_;
#endif
std::map<int, base::string16> toolTips_; // command id -> tooltip
std::map<int, base::string16> roles_; // command id -> role
std::map<int, base::string16> sublabels_; // command id -> sublabel

View File

@@ -15,9 +15,16 @@
#include "shell/browser/unresponsive_suppressor.h"
#include "shell/common/gin_converters/file_path_converter.h"
#include "ui/base/glib/glib_signal.h"
#include "ui/events/platform/x11/x11_event_source.h"
#include "ui/gtk/gtk_util.h"
#if defined(USE_X11)
#include "ui/events/platform/x11/x11_event_source.h"
#endif
#if defined(USE_OZONE) || defined(USE_X11)
#include "ui/base/ui_base_features.h"
#endif
namespace file_dialog {
DialogSettings::DialogSettings() = default;
@@ -135,11 +142,15 @@ class FileChooserDialog {
this);
gtk_widget_show_all(dialog_);
// We need to call gtk_window_present after making the widgets visible to
// make sure window gets correctly raised and gets focus.
x11::Time time = ui::X11EventSource::GetInstance()->GetTimestamp();
gtk_window_present_with_time(GTK_WINDOW(dialog_),
static_cast<uint32_t>(time));
#if defined(USE_X11)
if (!features::IsUsingOzonePlatform()) {
// We need to call gtk_window_present after making the widgets visible to
// make sure window gets correctly raised and gets focus.
x11::Time time = ui::X11EventSource::GetInstance()->GetTimestamp();
gtk_window_present_with_time(GTK_WINDOW(dialog_),
static_cast<uint32_t>(time));
}
#endif
}
void RunSaveAsynchronous(

View File

@@ -22,6 +22,10 @@
#include "ui/events/event_constants.h"
#include "ui/events/keycodes/keyboard_code_conversion_x.h"
#if defined(USE_OZONE) || defined(USE_X11)
#include "ui/base/ui_base_features.h"
#endif
namespace electron {
namespace gtkui {
@@ -222,12 +226,14 @@ void BuildSubmenuFromModel(ui::MenuModel* model,
}
#if defined(USE_X11)
ui::Accelerator accelerator;
if (model->GetAcceleratorAt(i, &accelerator)) {
gtk_widget_add_accelerator(menu_item, "activate", nullptr,
GetGdkKeyCodeForAccelerator(accelerator),
GetGdkModifierForAccelerator(accelerator),
GTK_ACCEL_VISIBLE);
if (!features::IsUsingOzonePlatform()) {
ui::Accelerator accelerator;
if (model->GetAcceleratorAt(i, &accelerator)) {
gtk_widget_add_accelerator(menu_item, "activate", nullptr,
GetGdkKeyCodeForAccelerator(accelerator),
GetGdkModifierForAccelerator(accelerator),
GTK_ACCEL_VISIBLE);
}
}
#endif

View File

@@ -13,10 +13,17 @@
#include "shell/browser/native_window_views.h"
#include "shell/browser/unresponsive_suppressor.h"
#include "ui/base/glib/glib_signal.h"
#include "ui/events/platform/x11/x11_event_source.h"
#include "ui/gfx/image/image_skia.h"
#include "ui/gtk/gtk_util.h"
#if defined(USE_X11)
#include "ui/events/platform/x11/x11_event_source.h"
#endif
#if defined(USE_OZONE) || defined(USE_X11)
#include "ui/base/ui_base_features.h"
#endif
#define ANSI_FOREGROUND_RED "\x1b[31m"
#define ANSI_FOREGROUND_BLACK "\x1b[30m"
#define ANSI_TEXT_BOLD "\x1b[1m"
@@ -133,11 +140,16 @@ class GtkMessageBox : public NativeWindowObserver {
void Show() {
gtk_widget_show(dialog_);
// We need to call gtk_window_present after making the widgets visible to
// make sure window gets correctly raised and gets focus.
x11::Time time = ui::X11EventSource::GetInstance()->GetTimestamp();
gtk_window_present_with_time(GTK_WINDOW(dialog_),
static_cast<uint32_t>(time));
#if defined(USE_X11)
if (!features::IsUsingOzonePlatform()) {
// We need to call gtk_window_present after making the widgets visible to
// make sure window gets correctly raised and gets focus.
x11::Time time = ui::X11EventSource::GetInstance()->GetTimestamp();
gtk_window_present_with_time(GTK_WINDOW(dialog_),
static_cast<uint32_t>(time));
}
#endif
}
int RunSynchronous() {

View File

@@ -17,7 +17,7 @@
#include "ui/views/layout/box_layout.h"
#include "ui/views/widget/widget.h"
#if defined(USE_X11)
#if defined(OS_LINUX)
#include "ui/gtk/gtk_util.h"
#endif
@@ -282,7 +282,7 @@ void MenuBar::ButtonPressed(views::Button* source, const ui::Event& event) {
void MenuBar::RefreshColorCache() {
const ui::NativeTheme* theme = GetNativeTheme();
if (theme) {
#if defined(USE_X11)
#if defined(OS_LINUX)
background_color_ = gtk::GetBgColor("GtkMenuBar#menubar");
enabled_color_ =
gtk::GetFgColor("GtkMenuBar#menubar GtkMenuItem#menuitem GtkLabel");
@@ -319,7 +319,7 @@ void MenuBar::UpdateViewColors() {
// set child colors
if (menu_model_ == nullptr)
return;
#if defined(USE_X11)
#if defined(OS_LINUX)
const auto& textColor = has_focus_ ? enabled_color_ : disabled_color_;
for (auto* child : GetChildrenInZOrder()) {
auto* button = static_cast<SubmenuButton*>(child);

View File

@@ -90,7 +90,7 @@ class MenuBar : public views::AccessiblePaneView,
void RefreshColorCache();
SkColor background_color_;
#if defined(USE_X11)
#if defined(OS_LINUX)
SkColor enabled_color_;
SkColor disabled_color_;
#endif

View File

@@ -6,7 +6,9 @@
#define SHELL_COMMON_GIN_HELPER_DICTIONARY_H_
#include <type_traits>
#include <utility>
#include "base/optional.h"
#include "gin/dictionary.h"
#include "shell/common/gin_converters/std_converter.h"
#include "shell/common/gin_helper/function_template.h"
@@ -59,6 +61,18 @@ class Dictionary : public gin::Dictionary {
return !result.IsNothing() && result.FromJust();
}
// Like normal Get but put result in an base::Optional.
template <typename T>
bool GetOptional(base::StringPiece key, base::Optional<T>* out) const {
T ret;
if (Get(key, &ret)) {
out->emplace(std::move(ret));
return true;
} else {
return false;
}
}
template <typename T>
bool GetHidden(base::StringPiece key, T* out) const {
v8::Local<v8::Context> context = isolate()->GetCurrentContext();

View File

@@ -166,8 +166,8 @@ bool AllowWasmCodeGenerationCallback(v8::Local<v8::Context> context,
context, v8::String::Empty(isolate));
}
return node::Environment::AllowWasmCodeGenerationCallback(
context, v8::String::Empty(isolate));
return node::AllowWasmCodeGenerationCallback(context,
v8::String::Empty(isolate));
}
// Initialize Node.js cli options to pass to Node.js
@@ -424,7 +424,7 @@ node::Environment* NodeBindings::CreateEnvironment(
DCHECK(env);
// This will only be caught when something has gone terrible wrong as all
// electron scripts are wrapped in a try {} catch {} in run-compiler.js
// electron scripts are wrapped in a try {} catch {} by webpack
if (try_catch.HasCaught()) {
LOG(ERROR) << "Failed to initialize node environment in process: "
<< process_type;

View File

@@ -29,7 +29,7 @@ v8::MaybeLocal<v8::Value> CompileAndCall(
v8::MaybeLocal<v8::Value> ret = fn->Call(
context, v8::Null(isolate), arguments->size(), arguments->data());
// This will only be caught when something has gone terrible wrong as all
// electron scripts are wrapped in a try {} catch {} in run-compiler.js
// electron scripts are wrapped in a try {} catch {} by webpack
if (try_catch.HasCaught()) {
LOG(ERROR) << "Failed to CompileAndCall electron script: " << id;
}

View File

@@ -1500,6 +1500,16 @@ describe('net module', () => {
});
});
describe('net.isOnline', () => {
it('getter returns boolean', () => {
expect(net.isOnline()).to.be.a('boolean');
});
it('property returns boolean', () => {
expect(net.online).to.be.a('boolean');
});
});
describe('Stability and performance', () => {
it('should free unreferenced, never-started request objects without crash', (done) => {
net.request('https://test');

View File

@@ -7,6 +7,7 @@ import { v4 } from 'uuid';
import { AddressInfo } from 'net';
import { closeWindow } from './window-helpers';
import { emittedOnce, emittedNTimes } from './events-helpers';
import { ifdescribe } from './spec-helpers';
const partition = 'service-workers-spec';
const uuid = v4();
@@ -65,7 +66,8 @@ describe('session.serviceWorkers', () => {
});
});
describe('getFromVersionID()', () => {
// TODO (jkleinsc) - reenable this test once https://github.com/electron/electron/issues/26043 is resolved
ifdescribe(!process.arch.includes('arm'))('getFromVersionID()', () => {
it('should report the correct script url and scope', async () => {
const eventInfo = await emittedOnce(ses.serviceWorkers, 'console-message', () => w.loadURL(`${baseUrl}/index.html`));
const details: Electron.MessageDetails = eventInfo[1];

View File

@@ -1375,7 +1375,8 @@ describe('webContents module', () => {
}
});
describe('did-change-theme-color event', () => {
// TODO (jkleinsc) - reenable this test on WOA once https://github.com/electron/electron/issues/26045 is resolved
ifdescribe(process.platform !== 'win32' || process.arch !== 'arm64')('did-change-theme-color event', () => {
afterEach(closeAllWindows);
it('is triggered with correct theme color', (done) => {
const w = new BrowserWindow({ show: true });

View File

@@ -986,7 +986,8 @@ describe('<webview> tag', function () {
});
});
describe('did-change-theme-color event', () => {
// TODO (jkleinsc) - reenable this test on WOA once https://github.com/electron/electron/issues/26045 is resolved
ifdescribe(process.platform !== 'win32' || process.arch !== 'arm64')('did-change-theme-color event', () => {
it('emits when theme color changes', async () => {
loadWebView(webview, {
src: `file://${fixtures}/pages/theme-color.html`

View File

@@ -194,6 +194,7 @@ declare namespace NodeJS {
createPair(): { port1: Electron.MessagePortMain, port2: Electron.MessagePortMain };
};
_linkedBinding(name: 'electron_browser_net'): {
isOnline(): boolean;
isValidHeaderName: (headerName: string) => boolean;
isValidHeaderValue: (headerValue: string) => boolean;
Net: any;

View File

@@ -108,6 +108,7 @@ declare namespace Electron {
_isCommandIdVisible(id: string): boolean;
_getAcceleratorForCommandId(id: string, useDefaultAccelerator: boolean): Accelerator | undefined;
_shouldRegisterAcceleratorForCommandId(id: string): boolean;
_getSharingItemForCommandId(id: string): SharingItem | null;
_callMenuWillShow(): void;
_executeCommand(event: any, id: number): void;
_menuWillShow(): void;

View File

@@ -8151,7 +8151,7 @@ webpack-cli@^3.3.12:
v8-compile-cache "^2.1.1"
yargs "^13.3.2"
webpack-sources@^1.4.0, webpack-sources@^1.4.1:
webpack-sources@^1.1.0, webpack-sources@^1.4.0, webpack-sources@^1.4.1:
version "1.4.3"
resolved "https://registry.yarnpkg.com/webpack-sources/-/webpack-sources-1.4.3.tgz#eedd8ec0b928fbf1cbfe994e22d2d890f330a933"
integrity sha512-lgTS3Xhv1lCOKo7SA5TjKXMjpSM4sBjNV5+q2bqesbSPs5FjGmU6jjtBSkX9b4qW87vDIsCIlUPOEhbZrMdjeQ==
@@ -8257,6 +8257,13 @@ wrapped@^1.0.1:
co "3.1.0"
sliced "^1.0.1"
wrapper-webpack-plugin@^2.1.0:
version "2.1.0"
resolved "https://registry.yarnpkg.com/wrapper-webpack-plugin/-/wrapper-webpack-plugin-2.1.0.tgz#2b5d80f46af84c9eeb707d08796a115e233adeac"
integrity sha512-e+2FhSYGCxhDq3PcUw5mRhH+8vcYa+9d9AuLChJUZ9ZbUPhQOHZ/O2dnN98iTqeUuvrzSSOv13+x/NhrAm5JEg==
dependencies:
webpack-sources "^1.1.0"
wrappy@1:
version "1.0.2"
resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f"