mirror of
https://github.com/electron/electron.git
synced 2026-04-10 03:01:51 -04:00
Compare commits
18 Commits
v30.0.0-ni
...
flake-fix
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
2b83114b75 | ||
|
|
cee51785e1 | ||
|
|
b253d52faf | ||
|
|
4d060afc98 | ||
|
|
8eb580e79a | ||
|
|
42087e306c | ||
|
|
2ea569e0d2 | ||
|
|
4367c5ad9e | ||
|
|
92c5ff30a7 | ||
|
|
5686f88bd2 | ||
|
|
768ece6b54 | ||
|
|
08236f7a9e | ||
|
|
5dfa9e3317 | ||
|
|
fb888a6989 | ||
|
|
398ca2a019 | ||
|
|
dac29f9949 | ||
|
|
3ec04fd449 | ||
|
|
2ebaebb603 |
@@ -29,7 +29,7 @@
|
||||
|
||||
version: 1.0.{build}
|
||||
build_cloud: electronhq-16-core
|
||||
image: e-123.0.6264.0
|
||||
image: e-123.0.6272.0
|
||||
environment:
|
||||
GIT_CACHE_PATH: C:\Users\appveyor\libcc_cache
|
||||
ELECTRON_OUT_DIR: Default
|
||||
|
||||
@@ -29,7 +29,7 @@
|
||||
|
||||
version: 1.0.{build}
|
||||
build_cloud: electronhq-16-core
|
||||
image: e-123.0.6264.0
|
||||
image: e-123.0.6272.0
|
||||
environment:
|
||||
GIT_CACHE_PATH: C:\Users\appveyor\libcc_cache
|
||||
ELECTRON_OUT_DIR: Default
|
||||
|
||||
@@ -14,4 +14,15 @@ buildflag_header("buildflags") {
|
||||
"ENABLE_BUILTIN_SPELLCHECKER=$enable_builtin_spellchecker",
|
||||
"OVERRIDE_LOCATION_PROVIDER=$enable_fake_location_provider",
|
||||
]
|
||||
|
||||
if (electron_vendor_version != "") {
|
||||
result = string_split(electron_vendor_version, ":")
|
||||
flags += [
|
||||
"HAS_VENDOR_VERSION=true",
|
||||
"VENDOR_VERSION_NAME=\"${result[0]}\"",
|
||||
"VENDOR_VERSION_VALUE=\"${result[1]}\"",
|
||||
]
|
||||
} else {
|
||||
flags += [ "HAS_VENDOR_VERSION=false" ]
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,4 +21,10 @@ declare_args() {
|
||||
# Packagers and vendor builders should set this in gn args to avoid running
|
||||
# the script that reads git tag.
|
||||
override_electron_version = ""
|
||||
|
||||
# Define an extra item that will show in process.versions, the value must
|
||||
# be in the format of "key:value".
|
||||
# Packagers and vendor builders can set this in gn args to attach extra info
|
||||
# about the build in the binary.
|
||||
electron_vendor_version = ""
|
||||
}
|
||||
|
||||
@@ -345,6 +345,10 @@ A `Integer` property representing the unique ID of the window. Each ID is unique
|
||||
|
||||
A `View` property for the content view of the window.
|
||||
|
||||
#### `win.tabbingIdentifier` _macOS_ _Readonly_
|
||||
|
||||
A `string` (optional) property that is equal to the `tabbingIdentifier` passed to the `BrowserWindow` constructor or `undefined` if none was set.
|
||||
|
||||
#### `win.autoHideMenuBar`
|
||||
|
||||
A `boolean` property that determines whether the window menu bar should hide itself automatically. Once set, the menu bar will only show when users press the single `Alt` key.
|
||||
@@ -519,7 +523,7 @@ Hides the window.
|
||||
|
||||
#### `win.isVisible()`
|
||||
|
||||
Returns `boolean` - Whether the window is visible to the user.
|
||||
Returns `boolean` - Whether the window is visible to the user in the foreground of the app.
|
||||
|
||||
#### `win.isModal()`
|
||||
|
||||
@@ -557,6 +561,8 @@ Returns `boolean` - Whether the window is minimized.
|
||||
|
||||
Sets whether the window should be in fullscreen mode.
|
||||
|
||||
**Note:** On macOS, fullscreen transitions take place asynchronously. If further actions depend on the fullscreen state, use the ['enter-full-screen'](base-window.md#event-enter-full-screen) or ['leave-full-screen'](base-window.md#event-leave-full-screen) events.
|
||||
|
||||
#### `win.isFullScreen()`
|
||||
|
||||
Returns `boolean` - Whether the window is in fullscreen mode.
|
||||
@@ -669,10 +675,14 @@ win.setBounds({ width: 100 })
|
||||
console.log(win.getBounds())
|
||||
```
|
||||
|
||||
**Note:** On macOS, the y-coordinate value cannot be smaller than the [Tray](tray.md) height. The tray height has changed over time and depends on the operating system, but is between 20-40px. Passing a value lower than the tray height will result in a window that is flush to the tray.
|
||||
|
||||
#### `win.getBounds()`
|
||||
|
||||
Returns [`Rectangle`](structures/rectangle.md) - The `bounds` of the window as `Object`.
|
||||
|
||||
**Note:** On macOS, the y-coordinate value returned will be at minimum the [Tray](tray.md) height. For example, calling `win.setBounds({ x: 25, y: 20, width: 800, height: 600 })` with a tray height of 38 means that `win.getBounds()` will return `{ x: 25, y: 38, width: 800, height: 600 }`.
|
||||
|
||||
#### `win.getBackgroundColor()`
|
||||
|
||||
Returns `string` - Gets the background color of the window in Hex (`#RRGGBB`) format.
|
||||
@@ -903,8 +913,8 @@ window.
|
||||
* `offsetX` Float (optional)
|
||||
|
||||
Changes the attachment point for sheets on macOS. By default, sheets are
|
||||
attached just below the window frame, but you may want to offset them. For
|
||||
example:
|
||||
attached just below the window frame, but you may want to display them beneath
|
||||
a HTML-rendered toolbar. For example:
|
||||
|
||||
```js
|
||||
const { BaseWindow } = require('electron')
|
||||
@@ -1289,6 +1299,10 @@ tabs in the window.
|
||||
Selects the next tab when native tabs are enabled and there are other
|
||||
tabs in the window.
|
||||
|
||||
#### `win.showAllTabs()` _macOS_
|
||||
|
||||
Shows or hides the tab overview when native tabs are enabled.
|
||||
|
||||
#### `win.mergeAllWindows()` _macOS_
|
||||
|
||||
Merges all windows into one window with multiple tabs when native tabs
|
||||
@@ -1312,15 +1326,26 @@ Adds a window as a tab on this window, after the tab for the window instance.
|
||||
|
||||
#### `win.setVibrancy(type)` _macOS_
|
||||
|
||||
* `type` string | null - Can be `appearance-based`, `light`, `dark`, `titlebar`,
|
||||
`selection`, `menu`, `popover`, `sidebar`, `medium-light`, `ultra-dark`, `header`, `sheet`, `window`, `hud`, `fullscreen-ui`, `tooltip`, `content`, `under-window`, or `under-page`. See
|
||||
* `type` string | null - Can be `titlebar`, `selection`, `menu`, `popover`, `sidebar`, `header`, `sheet`, `window`, `hud`, `fullscreen-ui`, `tooltip`, `content`, `under-window`, or `under-page`. See
|
||||
the [macOS documentation][vibrancy-docs] for more details.
|
||||
|
||||
Adds a vibrancy effect to the window. Passing `null` or an empty string
|
||||
will remove the vibrancy effect on the window.
|
||||
|
||||
Note that `appearance-based`, `light`, `dark`, `medium-light`, and `ultra-dark` have been
|
||||
deprecated and will be removed in an upcoming version of macOS.
|
||||
#### `win.setBackgroundMaterial(material)` _Windows_
|
||||
|
||||
* `material` string
|
||||
* `auto` - Let the Desktop Window Manager (DWM) automatically decide the system-drawn backdrop material for this window. This is the default.
|
||||
* `none` - Don't draw any system backdrop.
|
||||
* `mica` - Draw the backdrop material effect corresponding to a long-lived window.
|
||||
* `acrylic` - Draw the backdrop material effect corresponding to a transient window.
|
||||
* `tabbed` - Draw the backdrop material effect corresponding to a window with a tabbed title bar.
|
||||
|
||||
This method sets the browser window's system-drawn background material, including behind the non-client area.
|
||||
|
||||
See the [Windows documentation](https://learn.microsoft.com/en-us/windows/win32/api/dwmapi/ne-dwmapi-dwm_systembackdrop_type) for more details.
|
||||
|
||||
**Note:** This method is only supported on Windows 11 22H2 and up.
|
||||
|
||||
#### `win.setWindowButtonPosition(position)` _macOS_
|
||||
|
||||
@@ -1334,25 +1359,6 @@ Passing `null` will reset the position to default.
|
||||
Returns `Point | null` - The custom position for the traffic light buttons in
|
||||
frameless window, `null` will be returned when there is no custom position.
|
||||
|
||||
#### `win.setTrafficLightPosition(position)` _macOS_ _Deprecated_
|
||||
|
||||
* `position` [Point](structures/point.md)
|
||||
|
||||
Set a custom position for the traffic light buttons in frameless window.
|
||||
Passing `{ x: 0, y: 0 }` will reset the position to default.
|
||||
|
||||
> **Note**
|
||||
> This function is deprecated. Use [setWindowButtonPosition](#winsetwindowbuttonpositionposition-macos) instead.
|
||||
|
||||
#### `win.getTrafficLightPosition()` _macOS_ _Deprecated_
|
||||
|
||||
Returns `Point` - The custom position for the traffic light buttons in
|
||||
frameless window, `{ x: 0, y: 0 }` will be returned when there is no custom
|
||||
position.
|
||||
|
||||
> **Note**
|
||||
> This function is deprecated. Use [getWindowButtonPosition](#wingetwindowbuttonposition-macos) instead.
|
||||
|
||||
#### `win.setTouchBar(touchBar)` _macOS_
|
||||
|
||||
* `touchBar` TouchBar | null
|
||||
|
||||
@@ -644,6 +644,14 @@ Shows the window but doesn't focus on it.
|
||||
|
||||
Hides the window.
|
||||
|
||||
#### `win.isOccluded()`
|
||||
|
||||
Returns `boolean` - Whether the window is covered by other windows.
|
||||
|
||||
On macOS, a `BrowserWindow` is occluded if the entire window is obscured by other windows. A completely transparent window may also be considered non-occluded. See [docs](https://developer.apple.com/documentation/appkit/nswindowocclusionstate?language=objc) for more details.
|
||||
|
||||
On Windows and Linux, a window is occluded if it or one of its descendants is visible, and all visible windows have their bounds completely covered by fully opaque windows. A window is considered "fully opaque" if it is visible, it is not transparent, and its combined opacity is 1. See [Chromium Source](https://source.chromium.org/chromium/chromium/src/+/refs/heads/main:ui/aura/window.h;l=124-151;drc=7d2d8ccab2b68fbbfc5e1611d45bd4ecf87090b8) for more details.
|
||||
|
||||
#### `win.isVisible()`
|
||||
|
||||
Returns `boolean` - Whether the window is visible to the user in the foreground of the app.
|
||||
@@ -744,16 +752,16 @@ Examples of valid `backgroundColor` values:
|
||||
* #ffffff (RGB)
|
||||
* #ffffffff (ARGB)
|
||||
* RGB
|
||||
* rgb\((\[\d]+),\s*(\[\d]+),\s*(\[\d]+)\)
|
||||
* `rgb\(([\d]+),\s*([\d]+),\s*([\d]+)\)`
|
||||
* e.g. rgb(255, 255, 255)
|
||||
* RGBA
|
||||
* rgba\((\[\d]+),\s*(\[\d]+),\s*(\[\d]+),\s*(\[\d.]+)\)
|
||||
* `rgba\(([\d]+),\s*([\d]+),\s*([\d]+),\s*([\d.]+)\)`
|
||||
* e.g. rgba(255, 255, 255, 1.0)
|
||||
* HSL
|
||||
* hsl\((-?\[\d.]+),\s*(\[\d.]+)%,\s*(\[\d.]+)%\)
|
||||
* `hsl\((-?[\d.]+),\s*([\d.]+)%,\s*([\d.]+)%\)`
|
||||
* e.g. hsl(200, 20%, 50%)
|
||||
* HSLA
|
||||
* hsla\((-?\[\d.]+),\s*(\[\d.]+)%,\s*(\[\d.]+)%,\s*(\[\d.]+)\)
|
||||
* `hsla\((-?[\d.]+),\s*([\d.]+)%,\s*([\d.]+)%,\s*([\d.]+)\)`
|
||||
* e.g. hsla(200, 20%, 50%, 0.5)
|
||||
* Color name
|
||||
* Options are listed in [SkParseColor.cpp](https://source.chromium.org/chromium/chromium/src/+/main:third_party/skia/src/utils/SkParseColor.cpp;l=11-152;drc=eea4bf52cb0d55e2a39c828b017c80a5ee054148)
|
||||
|
||||
@@ -51,6 +51,13 @@ Check the _Size requirements_ section in [this article][icons].
|
||||
|
||||
[icons]: https://learn.microsoft.com/en-us/windows/win32/uxguide/vis-icons
|
||||
|
||||
:::note
|
||||
|
||||
EXIF metadata is currently not supported and will not be taken into account during
|
||||
image encoding and decoding.
|
||||
|
||||
:::
|
||||
|
||||
## High Resolution Image
|
||||
|
||||
On platforms that have high-DPI support such as Apple Retina displays, you can
|
||||
|
||||
@@ -21,12 +21,11 @@ Process: [Main](../glossary.md#main-process)<br />
|
||||
of the child process. Default is `inherit`.
|
||||
String value can be one of `pipe`, `ignore`, `inherit`, for more details on these values you can refer to
|
||||
[stdio][] documentation from Node.js. Currently this option only supports configuring `stdout` and
|
||||
`stderr` to either `pipe`, `inherit` or `ignore`. Configuring `stdin` is not supported; `stdin` will
|
||||
always be ignored.
|
||||
`stderr` to either `pipe`, `inherit` or `ignore`. Configuring `stdin` to any property other than `ignore` is not supported and will result in an error.
|
||||
For example, the supported values will be processed as following:
|
||||
* `pipe`: equivalent to \['ignore', 'pipe', 'pipe'] (the default)
|
||||
* `pipe`: equivalent to \['ignore', 'pipe', 'pipe']
|
||||
* `ignore`: equivalent to \['ignore', 'ignore', 'ignore']
|
||||
* `inherit`: equivalent to \['ignore', 'inherit', 'inherit']
|
||||
* `inherit`: equivalent to \['ignore', 'inherit', 'inherit'] (the default)
|
||||
* `serviceName` string (optional) - Name of the process that will appear in `name` property of
|
||||
[`ProcessMetric`](structures/process-metric.md) returned by [`app.getAppMetrics`](app.md#appgetappmetrics)
|
||||
and [`child-process-gone` event of `app`](app.md#event-child-process-gone).
|
||||
|
||||
@@ -15,7 +15,7 @@ Fuses are the solution to this problem, at a high level they are "magic bits" in
|
||||
**Default:** Enabled
|
||||
**@electron/fuses:** `FuseV1Options.RunAsNode`
|
||||
|
||||
The runAsNode fuse toggles whether the `ELECTRON_RUN_AS_NODE` environment variable is respected or not. Please note that if this fuse is disabled then `process.fork` in the main process will not function as expected as it depends on this environment variable to function.
|
||||
The runAsNode fuse toggles whether the `ELECTRON_RUN_AS_NODE` environment variable is respected or not. Please note that if this fuse is disabled then `process.fork` in the main process will not function as expected as it depends on this environment variable to function. Instead, we recommend that you use [Utility Processes](../api/utility-process.md), which work for many use cases where you need a standalone Node.js process (like a Sqlite server process or similar scenarios).
|
||||
|
||||
### `cookieEncryption`
|
||||
|
||||
|
||||
@@ -126,7 +126,7 @@ folder of your project:
|
||||
|
||||
```html
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<!-- https://developer.mozilla.org/en-US/docs/Web/HTTP/CSP -->
|
||||
@@ -420,9 +420,8 @@ window.addEventListener('DOMContentLoaded', () => {
|
||||
|
||||
```html
|
||||
<!--index.html-->
|
||||
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<!-- https://developer.mozilla.org/en-US/docs/Web/HTTP/CSP -->
|
||||
|
||||
@@ -114,6 +114,8 @@ You should at least follow these steps to improve the security of your applicati
|
||||
15. [Do not use `shell.openExternal` with untrusted content](#15-do-not-use-shellopenexternal-with-untrusted-content)
|
||||
16. [Use a current version of Electron](#16-use-a-current-version-of-electron)
|
||||
17. [Validate the `sender` of all IPC messages](#17-validate-the-sender-of-all-ipc-messages)
|
||||
18. [Avoid usage of the `file://` protocol and prefer usage of custom protocols](#18-avoid-usage-of-the-file-protocol-and-prefer-usage-of-custom-protocols)
|
||||
19. [Check which fuses you can change](#19-check-which-fuses-you-can-change)
|
||||
|
||||
To automate the detection of misconfigurations and insecure patterns, it is
|
||||
possible to use
|
||||
@@ -780,6 +782,28 @@ set of files.
|
||||
Follow the [`protocol.handle`](../api/protocol.md#protocolhandlescheme-handler) examples to
|
||||
learn how to serve files / content from a custom protocol.
|
||||
|
||||
### 19. Check which fuses you can change
|
||||
|
||||
Electron ships with a number of options that can be useful but a large portion of
|
||||
applications probably don't need. In order to avoid having to build your own version of
|
||||
Electron, these can be turned off or on using [Fuses](./fuses.md).
|
||||
|
||||
#### Why?
|
||||
|
||||
Some fuses, like `runAsNode` and `nodeCliInspect`, allow the application to behave differently
|
||||
when run from the command line using specific environment variables or CLI arguments. These
|
||||
can be used to execute commands on the device through your application.
|
||||
|
||||
This can let external scripts run commands that they potentially would not be allowed to, but
|
||||
that your application might have the rights for.
|
||||
|
||||
#### How?
|
||||
|
||||
We've made a module, [`@electron/fuses`](https://npmjs.com/package/@electron/fuses), to make
|
||||
flipping these fuses easy. Check out the README of that module for more details on usage and
|
||||
potential error cases, and refer to
|
||||
[How do I flip the fuses?](./fuses.md#how-do-i-flip-the-fuses) in our documentation.
|
||||
|
||||
[breaking-changes]: ../breaking-changes.md
|
||||
[browser-window]: ../api/browser-window.md
|
||||
[webview-tag]: ../api/webview-tag.md
|
||||
|
||||
@@ -366,11 +366,6 @@ WebContents.prototype.loadURL = function (url, options) {
|
||||
resolveAndCleanup();
|
||||
}
|
||||
};
|
||||
const failListener = (event: Electron.Event, errorCode: number, errorDescription: string, validatedURL: string, isMainFrame: boolean) => {
|
||||
if (!error && isMainFrame) {
|
||||
error = { errorCode, errorDescription, url: validatedURL };
|
||||
}
|
||||
};
|
||||
|
||||
let navigationStarted = false;
|
||||
let browserInitiatedInPageNavigation = false;
|
||||
@@ -392,6 +387,14 @@ WebContents.prototype.loadURL = function (url, options) {
|
||||
navigationStarted = true;
|
||||
}
|
||||
};
|
||||
const failListener = (event: Electron.Event, errorCode: number, errorDescription: string, validatedURL: string, isMainFrame: boolean) => {
|
||||
if (!error && isMainFrame) {
|
||||
error = { errorCode, errorDescription, url: validatedURL };
|
||||
}
|
||||
if (!navigationStarted && isMainFrame) {
|
||||
finishListener();
|
||||
}
|
||||
};
|
||||
const stopLoadingListener = () => {
|
||||
// By the time we get here, either 'finish' or 'fail' should have fired
|
||||
// if the navigation occurred. However, in some situations (e.g. when
|
||||
|
||||
@@ -3,6 +3,8 @@ import * as fs from 'fs';
|
||||
import * as path from 'path';
|
||||
|
||||
import type * as defaultMenuModule from '@electron/internal/browser/default-menu';
|
||||
import type * as url from 'url';
|
||||
import type * as v8 from 'v8';
|
||||
|
||||
const Module = require('module') as NodeJS.ModuleInternal;
|
||||
|
||||
@@ -132,7 +134,7 @@ if (packageJson.desktopName != null) {
|
||||
// Set v8 flags, deliberately lazy load so that apps that do not use this
|
||||
// feature do not pay the price
|
||||
if (packageJson.v8Flags != null) {
|
||||
require('v8').setFlagsFromString(packageJson.v8Flags);
|
||||
(require('v8') as typeof v8).setFlagsFromString(packageJson.v8Flags);
|
||||
}
|
||||
|
||||
app.setAppPath(packagePath);
|
||||
@@ -199,7 +201,7 @@ if (packagePath) {
|
||||
// Finally load app's main.js and transfer control to C++.
|
||||
if ((packageJson.type === 'module' && !mainStartupScript.endsWith('.cjs')) || mainStartupScript.endsWith('.mjs')) {
|
||||
const { loadESM } = __non_webpack_require__('internal/process/esm_loader');
|
||||
const main = require('url').pathToFileURL(path.join(packagePath, mainStartupScript));
|
||||
const main = (require('url') as typeof url).pathToFileURL(path.join(packagePath, mainStartupScript));
|
||||
loadESM(async (esmLoader: any) => {
|
||||
try {
|
||||
await esmLoader.import(main.toString(), undefined, Object.create(null));
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import * as util from 'util';
|
||||
import type * as stream from 'stream';
|
||||
|
||||
const timers = require('timers');
|
||||
import timers = require('timers');
|
||||
|
||||
type AnyFn = (...args: any[]) => any
|
||||
|
||||
@@ -62,7 +63,7 @@ if (process.type === 'browser' ||
|
||||
|
||||
if (process.platform === 'win32') {
|
||||
// Always returns EOF for stdin stream.
|
||||
const { Readable } = require('stream');
|
||||
const { Readable } = require('stream') as typeof stream;
|
||||
const stdin = new Readable();
|
||||
stdin.push(null);
|
||||
Object.defineProperty(process, 'stdin', {
|
||||
|
||||
@@ -2,7 +2,9 @@ import { Buffer } from 'buffer';
|
||||
import { constants } from 'fs';
|
||||
import * as path from 'path';
|
||||
import * as util from 'util';
|
||||
|
||||
import type * as Crypto from 'crypto';
|
||||
import type * as os from 'os';
|
||||
|
||||
const asar = process._linkedBinding('electron_common_asar');
|
||||
|
||||
@@ -255,7 +257,7 @@ export const wrapFsWithAsar = (fs: Record<string, any>) => {
|
||||
if (!process.env.ELECTRON_LOG_ASAR_READS) return;
|
||||
if (!logFDs.has(asarPath)) {
|
||||
const logFilename = `${path.basename(asarPath, '.asar')}-access-log.txt`;
|
||||
const logPath = path.join(require('os').tmpdir(), logFilename);
|
||||
const logPath = path.join((require('os') as typeof os).tmpdir(), logFilename);
|
||||
logFDs.set(asarPath, fs.openSync(logPath, 'a'));
|
||||
}
|
||||
fs.writeSync(logFDs.get(asarPath), `${offset}: ${filePath}\n`);
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import * as events from 'events';
|
||||
import { setImmediate, clearImmediate } from 'timers';
|
||||
import { IPC_MESSAGES } from '@electron/internal/common/ipc-messages';
|
||||
|
||||
import type * as ipcRendererUtilsModule from '@electron/internal/renderer/ipc-renderer-internal-utils';
|
||||
@@ -126,7 +127,6 @@ function runPreloadScript (preloadSrc: string) {
|
||||
|
||||
// eval in window scope
|
||||
const preloadFn = binding.createPreloadScript(preloadWrapperSrc);
|
||||
const { setImmediate, clearImmediate } = require('timers');
|
||||
const exports = {};
|
||||
|
||||
preloadFn(preloadRequire, preloadProcess, Buffer, global, setImmediate, clearImmediate, exports, { exports });
|
||||
|
||||
@@ -47,7 +47,6 @@ feat_add_support_for_overriding_the_base_spellchecker_download_url.patch
|
||||
feat_enable_offscreen_rendering_with_viz_compositor.patch
|
||||
gpu_notify_when_dxdiag_request_fails.patch
|
||||
feat_allow_embedders_to_add_observers_on_created_hunspell.patch
|
||||
feat_add_onclose_to_messageport.patch
|
||||
allow_in-process_windows_to_have_different_web_prefs.patch
|
||||
refactor_expose_cursor_changes_to_the_webcontentsobserver.patch
|
||||
crash_allow_setting_more_options.patch
|
||||
|
||||
@@ -1,31 +0,0 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Jeremy Apthorp <nornagon@nornagon.net>
|
||||
Date: Wed, 4 Mar 2020 11:18:03 -0800
|
||||
Subject: feat: add onclose to MessagePort
|
||||
|
||||
This adds the 'onclose' event to MessagePort. Can be removed once
|
||||
https://bugs.chromium.org/p/chromium/issues/detail?id=1495616 is fixed.
|
||||
|
||||
diff --git a/third_party/blink/renderer/core/messaging/message_port.cc b/third_party/blink/renderer/core/messaging/message_port.cc
|
||||
index 2e0961fd8c0bc8f9a2a7c124693033eb234928bd..5c54705e3c1766553e9cba13142345485ca44578 100644
|
||||
--- a/third_party/blink/renderer/core/messaging/message_port.cc
|
||||
+++ b/third_party/blink/renderer/core/messaging/message_port.cc
|
||||
@@ -195,6 +195,7 @@ void MessagePort::close() {
|
||||
Entangle(pipe.TakePort0(), nullptr);
|
||||
}
|
||||
closed_ = true;
|
||||
+ DispatchEvent(*Event::Create(event_type_names::kClose));
|
||||
}
|
||||
|
||||
void MessagePort::OnConnectionError() {
|
||||
diff --git a/third_party/blink/renderer/core/messaging/message_port.idl b/third_party/blink/renderer/core/messaging/message_port.idl
|
||||
index 9df43655b569428a6abc54341b4b0023e159f99b..3f1f181d9b8a66997136f870f55c97c08294b6eb 100644
|
||||
--- a/third_party/blink/renderer/core/messaging/message_port.idl
|
||||
+++ b/third_party/blink/renderer/core/messaging/message_port.idl
|
||||
@@ -40,5 +40,5 @@
|
||||
// event handlers
|
||||
attribute EventHandler onmessage;
|
||||
attribute EventHandler onmessageerror;
|
||||
- [RuntimeEnabled=MessagePortCloseEvent] attribute EventHandler onclose;
|
||||
+ attribute EventHandler onclose;
|
||||
};
|
||||
@@ -1,27 +1,15 @@
|
||||
{
|
||||
"src/electron/patches/chromium": "src",
|
||||
|
||||
"src/electron/patches/boringssl": "src/third_party/boringssl/src",
|
||||
|
||||
"src/electron/patches/devtools_frontend": "src/third_party/devtools-frontend/src",
|
||||
|
||||
"src/electron/patches/ffmpeg": "src/third_party/ffmpeg",
|
||||
|
||||
"src/electron/patches/v8": "src/v8",
|
||||
|
||||
"src/electron/patches/node": "src/third_party/electron_node",
|
||||
|
||||
"src/electron/patches/nan": "src/third_party/nan",
|
||||
|
||||
"src/electron/patches/perfetto": "src/third_party/perfetto",
|
||||
|
||||
"src/electron/patches/squirrel.mac": "src/third_party/squirrel.mac",
|
||||
|
||||
"src/electron/patches/Mantle": "src/third_party/squirrel.mac/vendor/Mantle",
|
||||
|
||||
"src/electron/patches/ReactiveObjC": "src/third_party/squirrel.mac/vendor/ReactiveObjC",
|
||||
|
||||
"src/electron/patches/webrtc": "src/third_party/webrtc",
|
||||
|
||||
"src/electron/patches/reclient-configs": "src/third_party/engflow-reclient-configs"
|
||||
}
|
||||
[
|
||||
{ "patch_dir": "src/electron/patches/chromium", "repo": "src" },
|
||||
{ "patch_dir": "src/electron/patches/boringssl", "repo": "src/third_party/boringssl/src" },
|
||||
{ "patch_dir": "src/electron/patches/devtools_frontend", "repo": "src/third_party/devtools-frontend/src" },
|
||||
{ "patch_dir": "src/electron/patches/ffmpeg", "repo": "src/third_party/ffmpeg" },
|
||||
{ "patch_dir": "src/electron/patches/v8", "repo": "src/v8" },
|
||||
{ "patch_dir": "src/electron/patches/node", "repo": "src/third_party/electron_node" },
|
||||
{ "patch_dir": "src/electron/patches/nan", "repo": "src/third_party/nan" },
|
||||
{ "patch_dir": "src/electron/patches/perfetto", "repo": "src/third_party/perfetto" },
|
||||
{ "patch_dir": "src/electron/patches/squirrel.mac", "repo": "src/third_party/squirrel.mac" },
|
||||
{ "patch_dir": "src/electron/patches/Mantle", "repo": "src/third_party/squirrel.mac/vendor/Mantle" },
|
||||
{ "patch_dir": "src/electron/patches/ReactiveObjC", "repo": "src/third_party/squirrel.mac/vendor/ReactiveObjC" },
|
||||
{ "patch_dir": "src/electron/patches/webrtc", "repo": "src/third_party/webrtc" },
|
||||
{ "patch_dir": "src/electron/patches/reclient-configs", "repo": "src/third_party/engflow-reclient-configs" }
|
||||
]
|
||||
|
||||
@@ -2312,10 +2312,10 @@ index 0000000000000000000000000000000000000000..7848ddb1841b6d4f36e9376c73564eb4
|
||||
+ f.write('\n')
|
||||
diff --git a/tools/generate_original_fs.py b/tools/generate_original_fs.py
|
||||
new file mode 100644
|
||||
index 0000000000000000000000000000000000000000..98d569e6ba6d85a29a215a8f9ce3c1f6a9bd655e
|
||||
index 0000000000000000000000000000000000000000..a6cdf33f2c0bcca4d7b4eacaa407f1ac5bdcb5cb
|
||||
--- /dev/null
|
||||
+++ b/tools/generate_original_fs.py
|
||||
@@ -0,0 +1,18 @@
|
||||
@@ -0,0 +1,19 @@
|
||||
+import os
|
||||
+import sys
|
||||
+
|
||||
@@ -2332,8 +2332,9 @@ index 0000000000000000000000000000000000000000..98d569e6ba6d85a29a215a8f9ce3c1f6
|
||||
+ original_f.write(contents)
|
||||
+
|
||||
+ with open(os.path.join(out_dir, original_fs_file), 'w') as transformed_f:
|
||||
+ transformed_contents = contents.replace('internal/fs/', 'internal/original-fs/')
|
||||
+ transformed_contents = contents.replace('internal/fs/', 'internal/original-fs/').replace('require(\'fs', 'require(\'original-fs')
|
||||
+ transformed_f.write(transformed_contents)
|
||||
+
|
||||
diff --git a/tools/install.py b/tools/install.py
|
||||
index 11616e1bcac5308020eb68fdb811bfb86cb14dd5..74b01f8352021f1105c080dbbf8bb29121a13501 100755
|
||||
--- a/tools/install.py
|
||||
|
||||
@@ -3,19 +3,30 @@
|
||||
import argparse
|
||||
import json
|
||||
import os
|
||||
import warnings
|
||||
|
||||
from lib import git
|
||||
from lib.patches import patch_from_dir
|
||||
|
||||
THREEWAY = "ELECTRON_USE_THREE_WAY_MERGE_FOR_PATCHES" in os.environ
|
||||
|
||||
def apply_patches(dirs):
|
||||
threeway = os.environ.get("ELECTRON_USE_THREE_WAY_MERGE_FOR_PATCHES")
|
||||
for patch_dir, repo in dirs.items():
|
||||
if os.path.exists(repo):
|
||||
git.import_patches(repo=repo, patch_data=patch_from_dir(patch_dir),
|
||||
threeway=threeway is not None,
|
||||
committer_name="Electron Scripts", committer_email="scripts@electron")
|
||||
def apply_patches(target):
|
||||
repo = target.get('repo')
|
||||
if not os.path.exists(repo):
|
||||
warnings.warn('repo not found: %s' % repo)
|
||||
return
|
||||
patch_dir = target.get('patch_dir')
|
||||
git.import_patches(
|
||||
committer_email="scripts@electron",
|
||||
committer_name="Electron Scripts",
|
||||
patch_data=patch_from_dir(patch_dir),
|
||||
repo=repo,
|
||||
threeway=THREEWAY,
|
||||
)
|
||||
|
||||
def apply_config(config):
|
||||
for target in config:
|
||||
apply_patches(target)
|
||||
|
||||
def parse_args():
|
||||
parser = argparse.ArgumentParser(description='Apply Electron patches')
|
||||
@@ -26,9 +37,8 @@ def parse_args():
|
||||
|
||||
|
||||
def main():
|
||||
configs = parse_args().config
|
||||
for config_json in configs:
|
||||
apply_patches(json.load(config_json))
|
||||
for config_json in parse_args().config:
|
||||
apply_config(json.load(config_json))
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
|
||||
@@ -3,14 +3,27 @@
|
||||
import argparse
|
||||
import json
|
||||
import os
|
||||
import warnings
|
||||
|
||||
from lib import git
|
||||
|
||||
|
||||
def export_patches(dirs, dry_run):
|
||||
for patch_dir, repo in dirs.items():
|
||||
if os.path.exists(repo):
|
||||
git.export_patches(repo=repo, out_dir=patch_dir, dry_run=dry_run)
|
||||
def export_patches(target, dry_run):
|
||||
repo = target.get('repo')
|
||||
if not os.path.exists(repo):
|
||||
warnings.warn('repo not found: %s' % repo)
|
||||
return
|
||||
git.export_patches(
|
||||
dry_run=dry_run,
|
||||
grep=target.get('grep'),
|
||||
out_dir=target.get('patch_dir'),
|
||||
repo=repo
|
||||
)
|
||||
|
||||
|
||||
def export_config(config, dry_run):
|
||||
for target in config:
|
||||
export_patches(target, dry_run)
|
||||
|
||||
|
||||
def parse_args():
|
||||
@@ -28,7 +41,7 @@ def main():
|
||||
configs = parse_args().config
|
||||
dry_run = parse_args().dry_run
|
||||
for config_json in configs:
|
||||
export_patches(json.load(config_json), dry_run)
|
||||
export_config(json.load(config_json), dry_run)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
|
||||
@@ -10,13 +10,15 @@ def main(argv):
|
||||
parser.add_argument("-o", "--output",
|
||||
help="directory into which exported patches will be written",
|
||||
required=True)
|
||||
parser.add_argument("--grep",
|
||||
help="only export patches matching a keyword")
|
||||
parser.add_argument("patch_range",
|
||||
nargs='?',
|
||||
help="range of patches to export. Defaults to all commits since the "
|
||||
"most recent tag or remote branch.")
|
||||
args = parser.parse_args(argv)
|
||||
|
||||
git.export_patches('.', args.output, patch_range=args.patch_range)
|
||||
git.export_patches('.', args.output, patch_range=args.patch_range, grep=args.grep)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
|
||||
@@ -149,6 +149,7 @@ def format_patch(repo, since):
|
||||
'format-patch',
|
||||
'--keep-subject',
|
||||
'--no-stat',
|
||||
'--notes',
|
||||
'--stdout',
|
||||
|
||||
# Per RFC 3676 the signature is separated from the body by a line with
|
||||
@@ -181,6 +182,16 @@ def split_patches(patch_data):
|
||||
patches[-1].append(line)
|
||||
return patches
|
||||
|
||||
def filter_patches(patches, key):
|
||||
"""Return patches that include the specified key"""
|
||||
if key is None:
|
||||
return patches
|
||||
matches = []
|
||||
for patch in patches:
|
||||
if any(key in line for line in patch):
|
||||
matches.append(patch)
|
||||
continue
|
||||
return matches
|
||||
|
||||
def munge_subject_to_filename(subject):
|
||||
"""Derive a suitable filename from a commit's subject"""
|
||||
@@ -227,7 +238,7 @@ def remove_patch_filename(patch):
|
||||
force_keep_next_line = l.startswith('Subject: ')
|
||||
|
||||
|
||||
def export_patches(repo, out_dir, patch_range=None, dry_run=False):
|
||||
def export_patches(repo, out_dir, patch_range=None, dry_run=False, grep=None):
|
||||
if not os.path.exists(repo):
|
||||
sys.stderr.write(
|
||||
"Skipping patches in {} because it does not exist.\n".format(repo)
|
||||
@@ -239,6 +250,8 @@ def export_patches(repo, out_dir, patch_range=None, dry_run=False):
|
||||
num_patches, repo, patch_range[0:7]))
|
||||
patch_data = format_patch(repo, patch_range)
|
||||
patches = split_patches(patch_data)
|
||||
if grep:
|
||||
patches = filter_patches(patches, grep)
|
||||
|
||||
try:
|
||||
os.mkdir(out_dir)
|
||||
|
||||
@@ -201,10 +201,9 @@ const LINTERS = [{
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
const config = JSON.parse(fs.readFileSync(patchesConfig, 'utf8'));
|
||||
for (const key of Object.keys(config)) {
|
||||
for (const target of JSON.parse(fs.readFileSync(patchesConfig, 'utf8'))) {
|
||||
// The directory the config points to should exist
|
||||
const targetPatchesDir = path.resolve(__dirname, '../../..', key);
|
||||
const targetPatchesDir = path.resolve(__dirname, '../../..', target.patch_dir);
|
||||
if (!fs.existsSync(targetPatchesDir)) {
|
||||
console.error(`target patch directory: "${targetPatchesDir}" does not exist`);
|
||||
process.exit(1);
|
||||
|
||||
@@ -12,7 +12,9 @@ from lib.patches import patch_from_dir
|
||||
|
||||
|
||||
def patched_file_paths(patches_config):
|
||||
for patch_dir, repo in patches_config.items():
|
||||
for target in patches_config:
|
||||
patch_dir = target.get('patch_dir')
|
||||
repo = target.get('repo')
|
||||
for line in patch_from_dir(patch_dir).split("\n"):
|
||||
if line.startswith("+++"):
|
||||
yield posixpath.join(repo, line[6:])
|
||||
|
||||
@@ -1228,13 +1228,10 @@ void App::ImportCertificate(gin_helper::ErrorThrower thrower,
|
||||
return;
|
||||
}
|
||||
|
||||
auto* browser_context = ElectronBrowserContext::From("", false);
|
||||
if (!certificate_manager_model_) {
|
||||
CertificateManagerModel::Create(
|
||||
browser_context,
|
||||
base::BindOnce(&App::OnCertificateManagerModelCreated,
|
||||
base::Unretained(this), std::move(options),
|
||||
std::move(callback)));
|
||||
CertificateManagerModel::Create(base::BindOnce(
|
||||
&App::OnCertificateManagerModelCreated, base::Unretained(this),
|
||||
std::move(options), std::move(callback)));
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1684,7 +1681,7 @@ gin::ObjectTemplateBuilder App::GetObjectTemplateBuilder(v8::Isolate* isolate) {
|
||||
.SetMethod("setBadgeCount",
|
||||
base::BindRepeating(&Browser::SetBadgeCount, browser))
|
||||
.SetMethod("getBadgeCount",
|
||||
base::BindRepeating(&Browser::GetBadgeCount, browser))
|
||||
base::BindRepeating(&Browser::badge_count, browser))
|
||||
.SetMethod("getLoginItemSettings", &App::GetLoginItemSettings)
|
||||
.SetMethod("setLoginItemSettings",
|
||||
base::BindRepeating(&Browser::SetLoginItemSettings, browser))
|
||||
|
||||
@@ -355,6 +355,10 @@ bool BaseWindow::IsVisible() const {
|
||||
return window_->IsVisible();
|
||||
}
|
||||
|
||||
bool BaseWindow::IsOccluded() const {
|
||||
return window_->IsOccluded();
|
||||
}
|
||||
|
||||
bool BaseWindow::IsEnabled() const {
|
||||
return window_->IsEnabled();
|
||||
}
|
||||
@@ -1086,6 +1090,7 @@ void BaseWindow::BuildPrototype(v8::Isolate* isolate,
|
||||
.SetMethod("showInactive", &BaseWindow::ShowInactive)
|
||||
.SetMethod("hide", &BaseWindow::Hide)
|
||||
.SetMethod("isVisible", &BaseWindow::IsVisible)
|
||||
.SetMethod("isOccluded", &BaseWindow::IsOccluded)
|
||||
.SetMethod("isEnabled", &BaseWindow::IsEnabled)
|
||||
.SetMethod("setEnabled", &BaseWindow::SetEnabled)
|
||||
.SetMethod("maximize", &BaseWindow::Maximize)
|
||||
|
||||
@@ -98,6 +98,7 @@ class BaseWindow : public gin_helper::TrackableObject<BaseWindow>,
|
||||
void ShowInactive();
|
||||
void Hide();
|
||||
bool IsVisible() const;
|
||||
bool IsOccluded() const;
|
||||
bool IsEnabled() const;
|
||||
void SetEnabled(bool enable);
|
||||
void Maximize();
|
||||
|
||||
@@ -159,8 +159,7 @@ v8::Local<v8::Promise> Debugger::SendCommand(gin::Arguments* args) {
|
||||
request.Set("sessionId", session_id);
|
||||
}
|
||||
|
||||
std::string json_args;
|
||||
base::JSONWriter::Write(request, &json_args);
|
||||
const auto json_args = base::WriteJson(request).value_or("");
|
||||
agent_host_->DispatchProtocolMessage(
|
||||
this, base::as_bytes(base::make_span(json_args)));
|
||||
|
||||
|
||||
@@ -31,7 +31,7 @@ bool IsEncryptionAvailable() {
|
||||
return OSCrypt::IsEncryptionAvailable() ||
|
||||
(use_password_v10 &&
|
||||
static_cast<BrowserProcessImpl*>(g_browser_process)
|
||||
->GetLinuxStorageBackend() == "basic_text");
|
||||
->linux_storage_backend() == "basic_text");
|
||||
#else
|
||||
return OSCrypt::IsEncryptionAvailable();
|
||||
#endif
|
||||
@@ -46,7 +46,7 @@ std::string GetSelectedLinuxBackend() {
|
||||
if (!Browser::Get()->is_ready())
|
||||
return "unknown";
|
||||
return static_cast<BrowserProcessImpl*>(g_browser_process)
|
||||
->GetLinuxStorageBackend();
|
||||
->linux_storage_backend();
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
@@ -852,7 +852,7 @@ WebContents::WebContents(v8::Isolate* isolate,
|
||||
session_.Reset(isolate, session.ToV8());
|
||||
|
||||
std::unique_ptr<content::WebContents> web_contents;
|
||||
if (IsGuest()) {
|
||||
if (is_guest()) {
|
||||
scoped_refptr<content::SiteInstance> site_instance =
|
||||
content::SiteInstance::CreateForURL(session->browser_context(),
|
||||
GURL("chrome-guest://fake-host"));
|
||||
@@ -922,7 +922,7 @@ void WebContents::InitWithSessionAndOptions(
|
||||
const gin_helper::Dictionary& options) {
|
||||
Observe(owned_web_contents.get());
|
||||
InitWithWebContents(std::move(owned_web_contents), session->browser_context(),
|
||||
IsGuest());
|
||||
is_guest());
|
||||
|
||||
inspectable_web_contents_->GetView()->SetDelegate(this);
|
||||
|
||||
@@ -982,7 +982,7 @@ void WebContents::InitWithSessionAndOptions(
|
||||
|
||||
SetUserAgent(GetBrowserContext()->GetUserAgent());
|
||||
|
||||
if (IsGuest()) {
|
||||
if (is_guest()) {
|
||||
NativeWindow* owner_window = nullptr;
|
||||
if (embedder_) {
|
||||
// New WebContents's owner_window is the embedder's owner_window.
|
||||
@@ -1017,7 +1017,7 @@ void WebContents::InitWithExtensionView(v8::Isolate* isolate,
|
||||
// Allow toggling DevTools for background pages
|
||||
Observe(web_contents);
|
||||
InitWithWebContents(std::unique_ptr<content::WebContents>(web_contents),
|
||||
GetBrowserContext(), IsGuest());
|
||||
GetBrowserContext(), is_guest());
|
||||
inspectable_web_contents_->GetView()->SetDelegate(this);
|
||||
}
|
||||
#endif
|
||||
@@ -1066,7 +1066,7 @@ WebContents::~WebContents() {
|
||||
|
||||
// For guest view based on OOPIF, the WebContents is released by the embedder
|
||||
// frame, and we need to clear the reference to the memory.
|
||||
bool not_owned_by_this = IsGuest() && attached_;
|
||||
bool not_owned_by_this = is_guest() && attached_;
|
||||
#if BUILDFLAG(ENABLE_ELECTRON_EXTENSIONS)
|
||||
// And background pages are owned by extensions::ExtensionHost.
|
||||
if (type_ == Type::kBackgroundPage)
|
||||
@@ -1096,7 +1096,7 @@ void WebContents::DeleteThisIfAlive() {
|
||||
void WebContents::Destroy() {
|
||||
// The content::WebContents should be destroyed asynchronously when possible
|
||||
// as user may choose to destroy WebContents during an event of it.
|
||||
if (Browser::Get()->is_shutting_down() || IsGuest()) {
|
||||
if (Browser::Get()->is_shutting_down() || is_guest()) {
|
||||
DeleteThisIfAlive();
|
||||
} else {
|
||||
content::GetUIThreadTaskRunner({})->PostTask(
|
||||
@@ -2155,7 +2155,7 @@ void WebContents::DidFinishNavigation(
|
||||
Emit("did-navigate", url, http_response_code, http_status_text);
|
||||
}
|
||||
}
|
||||
if (IsGuest())
|
||||
if (is_guest())
|
||||
Emit("load-commit", url, is_main_frame);
|
||||
} else {
|
||||
auto url = navigation_handle->GetURL();
|
||||
@@ -2374,10 +2374,6 @@ base::ProcessId WebContents::GetOSProcessID() const {
|
||||
return base::GetProcId(process_handle);
|
||||
}
|
||||
|
||||
WebContents::Type WebContents::GetType() const {
|
||||
return type_;
|
||||
}
|
||||
|
||||
bool WebContents::Equal(const WebContents* web_contents) const {
|
||||
return ID() == web_contents->ID();
|
||||
}
|
||||
@@ -3371,7 +3367,7 @@ bool WebContents::IsFocused() const {
|
||||
if (!view)
|
||||
return false;
|
||||
|
||||
if (GetType() != Type::kBackgroundPage) {
|
||||
if (type() != Type::kBackgroundPage) {
|
||||
auto* window = web_contents()->GetNativeView()->GetToplevelWindow();
|
||||
if (window && !window->IsVisible())
|
||||
return false;
|
||||
@@ -3567,10 +3563,6 @@ void WebContents::OnCursorChanged(const ui::Cursor& cursor) {
|
||||
}
|
||||
}
|
||||
|
||||
bool WebContents::IsGuest() const {
|
||||
return type_ == Type::kWebView;
|
||||
}
|
||||
|
||||
void WebContents::AttachToIframe(content::WebContents* embedder_web_contents,
|
||||
int embedder_frame_id) {
|
||||
attached_ = true;
|
||||
@@ -3782,7 +3774,7 @@ void WebContents::SetImageAnimationPolicy(const std::string& new_policy) {
|
||||
}
|
||||
|
||||
void WebContents::SetBackgroundColor(std::optional<SkColor> maybe_color) {
|
||||
SkColor color = maybe_color.value_or((IsGuest() && guest_transparent_) ||
|
||||
SkColor color = maybe_color.value_or((is_guest() && guest_transparent_) ||
|
||||
type_ == Type::kBrowserView
|
||||
? SK_ColorTRANSPARENT
|
||||
: SK_ColorWHITE);
|
||||
@@ -4304,7 +4296,7 @@ void WebContents::UpdateHtmlApiFullscreen(bool fullscreen) {
|
||||
}
|
||||
|
||||
// Make sure all child webviews quit html fullscreen.
|
||||
if (!fullscreen && !IsGuest()) {
|
||||
if (!fullscreen && !is_guest()) {
|
||||
auto* manager = WebViewManager::GetWebViewManager(web_contents());
|
||||
manager->ForEachGuest(web_contents(), [&](content::WebContents* guest) {
|
||||
WebContents* api_web_contents = WebContents::From(guest);
|
||||
@@ -4416,7 +4408,7 @@ void WebContents::FillObjectTemplate(v8::Isolate* isolate,
|
||||
.SetMethod("getZoomLevel", &WebContents::GetZoomLevel)
|
||||
.SetMethod("setZoomFactor", &WebContents::SetZoomFactor)
|
||||
.SetMethod("getZoomFactor", &WebContents::GetZoomFactor)
|
||||
.SetMethod("getType", &WebContents::GetType)
|
||||
.SetMethod("getType", &WebContents::type)
|
||||
.SetMethod("_getPreloadPaths", &WebContents::GetPreloadPaths)
|
||||
.SetMethod("getLastWebPreferences", &WebContents::GetLastWebPreferences)
|
||||
.SetMethod("getOwnerBrowserWindow", &WebContents::GetOwnerBrowserWindow)
|
||||
|
||||
@@ -173,7 +173,7 @@ class WebContents : public ExclusiveAccessContext,
|
||||
void SetBackgroundThrottling(bool allowed);
|
||||
int GetProcessID() const;
|
||||
base::ProcessId GetOSProcessID() const;
|
||||
Type GetType() const;
|
||||
[[nodiscard]] Type type() const { return type_; }
|
||||
bool Equal(const WebContents* web_contents) const;
|
||||
void LoadURL(const GURL& url, const gin_helper::Dictionary& options);
|
||||
void Reload();
|
||||
@@ -292,7 +292,7 @@ class WebContents : public ExclusiveAccessContext,
|
||||
v8::Local<v8::Promise> CapturePage(gin::Arguments* args);
|
||||
|
||||
// Methods for creating <webview>.
|
||||
bool IsGuest() const;
|
||||
[[nodiscard]] bool is_guest() const { return type_ == Type::kWebView; }
|
||||
void AttachToIframe(content::WebContents* embedder_web_contents,
|
||||
int embedder_frame_id);
|
||||
void DetachFromOuterFrame();
|
||||
|
||||
@@ -24,7 +24,7 @@ bool WebContents::IsFocused() const {
|
||||
if (!view)
|
||||
return false;
|
||||
|
||||
if (GetType() != Type::kBackgroundPage) {
|
||||
if (type() != Type::kBackgroundPage) {
|
||||
auto window = [web_contents()->GetNativeView().GetNativeNSView() window];
|
||||
// On Mac the render widget host view does not lose focus when the window
|
||||
// loses focus so check if the top level window is the key window.
|
||||
|
||||
@@ -159,10 +159,6 @@ void Browser::SetName(const std::string& name) {
|
||||
OverriddenApplicationName() = name;
|
||||
}
|
||||
|
||||
int Browser::GetBadgeCount() {
|
||||
return badge_count_;
|
||||
}
|
||||
|
||||
bool Browser::OpenFile(const std::string& file_path) {
|
||||
bool prevent_default = false;
|
||||
for (BrowserObserver& observer : observers_)
|
||||
|
||||
@@ -110,7 +110,7 @@ class Browser : public WindowListObserver {
|
||||
|
||||
// Set/Get the badge count.
|
||||
bool SetBadgeCount(std::optional<int> count);
|
||||
int GetBadgeCount();
|
||||
[[nodiscard]] int badge_count() const { return badge_count_; }
|
||||
|
||||
#if BUILDFLAG(IS_WIN)
|
||||
struct LaunchItem {
|
||||
|
||||
@@ -340,10 +340,6 @@ void BrowserProcessImpl::SetLinuxStorageBackend(
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
const std::string& BrowserProcessImpl::GetLinuxStorageBackend() const {
|
||||
return selected_linux_storage_backend_;
|
||||
}
|
||||
#endif // BUILDFLAG(IS_LINUX)
|
||||
|
||||
void BrowserProcessImpl::SetApplicationLocale(const std::string& locale) {
|
||||
|
||||
@@ -59,7 +59,9 @@ class BrowserProcessImpl : public BrowserProcess {
|
||||
|
||||
#if BUILDFLAG(IS_LINUX)
|
||||
void SetLinuxStorageBackend(os_crypt::SelectedLinuxBackend selected_backend);
|
||||
const std::string& GetLinuxStorageBackend() const;
|
||||
[[nodiscard]] const std::string& linux_storage_backend() const {
|
||||
return selected_linux_storage_backend_;
|
||||
}
|
||||
#endif
|
||||
|
||||
void EndSession() override {}
|
||||
|
||||
@@ -7,9 +7,7 @@
|
||||
#include <utility>
|
||||
|
||||
#include "base/functional/bind.h"
|
||||
#include "base/logging.h"
|
||||
#include "base/strings/utf_string_conversions.h"
|
||||
#include "content/public/browser/browser_context.h"
|
||||
#include "base/memory/ptr_util.h"
|
||||
#include "content/public/browser/browser_task_traits.h"
|
||||
#include "content/public/browser/browser_thread.h"
|
||||
#include "content/public/browser/resource_context.h"
|
||||
@@ -25,8 +23,7 @@ namespace {
|
||||
|
||||
net::NSSCertDatabase* g_nss_cert_database = nullptr;
|
||||
|
||||
net::NSSCertDatabase* GetNSSCertDatabaseForResourceContext(
|
||||
content::ResourceContext* context,
|
||||
net::NSSCertDatabase* GetNSSCertDatabase(
|
||||
base::OnceCallback<void(net::NSSCertDatabase*)> callback) {
|
||||
// This initialization is not thread safe. This CHECK ensures that this code
|
||||
// is only run on a single thread.
|
||||
@@ -57,7 +54,7 @@ net::NSSCertDatabase* GetNSSCertDatabaseForResourceContext(
|
||||
// \--------------------------------------v
|
||||
// CertificateManagerModel::GetCertDBOnIOThread
|
||||
// |
|
||||
// GetNSSCertDatabaseForResourceContext
|
||||
// GetNSSCertDatabase
|
||||
// |
|
||||
// CertificateManagerModel::DidGetCertDBOnIOThread
|
||||
// v--------------------------------------/
|
||||
@@ -68,12 +65,10 @@ net::NSSCertDatabase* GetNSSCertDatabaseForResourceContext(
|
||||
// callback
|
||||
|
||||
// static
|
||||
void CertificateManagerModel::Create(content::BrowserContext* browser_context,
|
||||
CreationCallback callback) {
|
||||
void CertificateManagerModel::Create(CreationCallback callback) {
|
||||
DCHECK_CURRENTLY_ON(BrowserThread::UI);
|
||||
content::GetIOThreadTaskRunner({})->PostTask(
|
||||
FROM_HERE, base::BindOnce(&CertificateManagerModel::GetCertDBOnIOThread,
|
||||
browser_context->GetResourceContext(),
|
||||
std::move(callback)));
|
||||
}
|
||||
|
||||
@@ -151,16 +146,14 @@ void CertificateManagerModel::DidGetCertDBOnIOThread(
|
||||
}
|
||||
|
||||
// static
|
||||
void CertificateManagerModel::GetCertDBOnIOThread(
|
||||
content::ResourceContext* context,
|
||||
CreationCallback callback) {
|
||||
void CertificateManagerModel::GetCertDBOnIOThread(CreationCallback callback) {
|
||||
DCHECK_CURRENTLY_ON(BrowserThread::IO);
|
||||
|
||||
auto split_callback = base::SplitOnceCallback(base::BindOnce(
|
||||
&CertificateManagerModel::DidGetCertDBOnIOThread, std::move(callback)));
|
||||
|
||||
net::NSSCertDatabase* cert_db = GetNSSCertDatabaseForResourceContext(
|
||||
context, std::move(split_callback.first));
|
||||
net::NSSCertDatabase* cert_db =
|
||||
GetNSSCertDatabase(std::move(split_callback.first));
|
||||
|
||||
// If the NSS database was already available, |cert_db| is non-null and
|
||||
// |did_get_cert_db_callback| has not been called. Call it explicitly.
|
||||
|
||||
@@ -13,11 +13,6 @@
|
||||
#include "base/memory/ref_counted.h"
|
||||
#include "net/cert/nss_cert_database.h"
|
||||
|
||||
namespace content {
|
||||
class BrowserContext;
|
||||
class ResourceContext;
|
||||
} // namespace content
|
||||
|
||||
// CertificateManagerModel provides the data to be displayed in the certificate
|
||||
// manager dialog, and processes changes from the view.
|
||||
class CertificateManagerModel {
|
||||
@@ -26,10 +21,8 @@ class CertificateManagerModel {
|
||||
base::OnceCallback<void(std::unique_ptr<CertificateManagerModel>)>;
|
||||
|
||||
// Creates a CertificateManagerModel. The model will be passed to the callback
|
||||
// when it is ready. The caller must ensure the model does not outlive the
|
||||
// |browser_context|.
|
||||
static void Create(content::BrowserContext* browser_context,
|
||||
CreationCallback callback);
|
||||
// when it is ready.
|
||||
static void Create(CreationCallback callback);
|
||||
|
||||
// disable copy
|
||||
CertificateManagerModel(const CertificateManagerModel&) = delete;
|
||||
@@ -105,8 +98,7 @@ class CertificateManagerModel {
|
||||
CreationCallback callback);
|
||||
static void DidGetCertDBOnIOThread(CreationCallback callback,
|
||||
net::NSSCertDatabase* cert_db);
|
||||
static void GetCertDBOnIOThread(content::ResourceContext* context,
|
||||
CreationCallback callback);
|
||||
static void GetCertDBOnIOThread(CreationCallback callback);
|
||||
|
||||
raw_ptr<net::NSSCertDatabase> cert_db_;
|
||||
// Whether the certificate database has a public slot associated with the
|
||||
|
||||
@@ -631,10 +631,11 @@ ExtensionFunction::ResponseAction ScriptingExecuteScriptFunction::Run() {
|
||||
std::vector<std::string> string_args;
|
||||
string_args.reserve(injection_.args->size());
|
||||
for (const auto& arg : *injection_.args) {
|
||||
std::string json;
|
||||
if (!base::JSONWriter::Write(arg, &json))
|
||||
if (auto json = base::WriteJson(arg)) {
|
||||
string_args.push_back(std::move(*json));
|
||||
} else {
|
||||
return RespondNow(Error("Unserializable argument passed."));
|
||||
string_args.push_back(std::move(json));
|
||||
}
|
||||
}
|
||||
args_expression = base::JoinString(string_args, ",");
|
||||
}
|
||||
|
||||
@@ -13,10 +13,10 @@
|
||||
namespace electron {
|
||||
|
||||
NSArray* ListValueToNSArray(const base::Value::List& value) {
|
||||
std::string json;
|
||||
if (!base::JSONWriter::Write(base::ValueView{value}, &json))
|
||||
const auto json = base::WriteJson(value);
|
||||
if (!json.has_value())
|
||||
return nil;
|
||||
NSData* jsonData = [NSData dataWithBytes:json.c_str() length:json.length()];
|
||||
NSData* jsonData = [NSData dataWithBytes:json->data() length:json->size()];
|
||||
id obj = [NSJSONSerialization JSONObjectWithData:jsonData
|
||||
options:0
|
||||
error:nil];
|
||||
@@ -56,10 +56,10 @@ base::Value::List NSArrayToValue(NSArray* arr) {
|
||||
}
|
||||
|
||||
NSDictionary* DictionaryValueToNSDictionary(const base::Value::Dict& value) {
|
||||
std::string json;
|
||||
if (!base::JSONWriter::Write(base::ValueView{value}, &json))
|
||||
const auto json = base::WriteJson(value);
|
||||
if (!json.has_value())
|
||||
return nil;
|
||||
NSData* jsonData = [NSData dataWithBytes:json.c_str() length:json.length()];
|
||||
NSData* jsonData = [NSData dataWithBytes:json->data() length:json->size()];
|
||||
id obj = [NSJSONSerialization JSONObjectWithData:jsonData
|
||||
options:0
|
||||
error:nil];
|
||||
|
||||
@@ -520,14 +520,6 @@ bool NativeWindow::IsMenuBarVisible() const {
|
||||
return true;
|
||||
}
|
||||
|
||||
double NativeWindow::GetAspectRatio() const {
|
||||
return aspect_ratio_;
|
||||
}
|
||||
|
||||
gfx::Size NativeWindow::GetAspectRatioExtraSize() const {
|
||||
return aspect_ratio_extraSize_;
|
||||
}
|
||||
|
||||
void NativeWindow::SetAspectRatio(double aspect_ratio,
|
||||
const gfx::Size& extra_size) {
|
||||
aspect_ratio_ = aspect_ratio;
|
||||
|
||||
@@ -87,6 +87,7 @@ class NativeWindow : public base::SupportsUserData,
|
||||
virtual void Show() = 0;
|
||||
virtual void ShowInactive() = 0;
|
||||
virtual void Hide() = 0;
|
||||
virtual bool IsOccluded() const = 0;
|
||||
virtual bool IsVisible() const = 0;
|
||||
virtual bool IsEnabled() const = 0;
|
||||
virtual void SetEnabled(bool enable) = 0;
|
||||
@@ -263,8 +264,10 @@ class NativeWindow : public base::SupportsUserData,
|
||||
virtual bool IsMenuBarVisible() const;
|
||||
|
||||
// Set the aspect ratio when resizing window.
|
||||
double GetAspectRatio() const;
|
||||
gfx::Size GetAspectRatioExtraSize() const;
|
||||
[[nodiscard]] double aspect_ratio() const { return aspect_ratio_; }
|
||||
[[nodiscard]] gfx::Size aspect_ratio_extra_size() const {
|
||||
return aspect_ratio_extraSize_;
|
||||
}
|
||||
virtual void SetAspectRatio(double aspect_ratio, const gfx::Size& extra_size);
|
||||
|
||||
// File preview APIs.
|
||||
|
||||
@@ -44,6 +44,7 @@ class NativeWindowMac : public NativeWindow,
|
||||
void Show() override;
|
||||
void ShowInactive() override;
|
||||
void Hide() override;
|
||||
bool IsOccluded() const override;
|
||||
bool IsVisible() const override;
|
||||
bool IsEnabled() const override;
|
||||
void SetEnabled(bool enable) override;
|
||||
|
||||
@@ -561,9 +561,12 @@ void NativeWindowMac::Hide() {
|
||||
[window_ orderOut:nil];
|
||||
}
|
||||
|
||||
bool NativeWindowMac::IsOccluded() const {
|
||||
return !([window_ occlusionState] & NSWindowOcclusionStateVisible);
|
||||
}
|
||||
|
||||
bool NativeWindowMac::IsVisible() const {
|
||||
bool occluded = [window_ occlusionState] == NSWindowOcclusionStateVisible;
|
||||
return [window_ isVisible] && !occluded && !IsMinimized();
|
||||
return [window_ isVisible] && !IsMinimized();
|
||||
}
|
||||
|
||||
bool NativeWindowMac::IsEnabled() const {
|
||||
@@ -638,7 +641,7 @@ bool NativeWindowMac::IsMaximized() const {
|
||||
if (HasStyleMask(NSWindowStyleMaskResizable) != 0)
|
||||
return [window_ isZoomed];
|
||||
|
||||
NSRect rectScreen = GetAspectRatio() > 0.0
|
||||
NSRect rectScreen = aspect_ratio() > 0.0
|
||||
? default_frame_for_zoom()
|
||||
: [[NSScreen mainScreen] visibleFrame];
|
||||
|
||||
|
||||
@@ -562,6 +562,14 @@ void NativeWindowViews::Hide() {
|
||||
#endif
|
||||
}
|
||||
|
||||
bool NativeWindowViews::IsOccluded() const {
|
||||
if (!GetNativeWindow())
|
||||
return false;
|
||||
auto occlusion_state =
|
||||
GetNativeWindow()->GetHost()->GetNativeWindowOcclusionState();
|
||||
return occlusion_state == aura::Window::OcclusionState::OCCLUDED;
|
||||
}
|
||||
|
||||
bool NativeWindowViews::IsVisible() const {
|
||||
#if BUILDFLAG(IS_WIN)
|
||||
// widget()->IsVisible() calls ::IsWindowVisible, which returns non-zero if a
|
||||
|
||||
@@ -56,6 +56,7 @@ class NativeWindowViews : public NativeWindow,
|
||||
void Hide() override;
|
||||
bool IsVisible() const override;
|
||||
bool IsEnabled() const override;
|
||||
bool IsOccluded() const override;
|
||||
void SetEnabled(bool enable) override;
|
||||
void Maximize() override;
|
||||
void Unmaximize() override;
|
||||
|
||||
@@ -231,7 +231,7 @@ void AutofillPopup::SetItems(const std::vector<std::u16string>& values,
|
||||
void AutofillPopup::AcceptSuggestion(int index) {
|
||||
mojo::AssociatedRemote<mojom::ElectronAutofillAgent> autofill_agent;
|
||||
frame_host_->GetRemoteAssociatedInterfaces()->GetInterface(&autofill_agent);
|
||||
autofill_agent->AcceptDataListSuggestion(GetValueAt(index));
|
||||
autofill_agent->AcceptDataListSuggestion(value_at(index));
|
||||
}
|
||||
|
||||
void AutofillPopup::UpdatePopupBounds() {
|
||||
@@ -272,11 +272,10 @@ int AutofillPopup::GetDesiredPopupWidth() {
|
||||
int popup_width = element_bounds_.width();
|
||||
|
||||
for (size_t i = 0; i < values_.size(); ++i) {
|
||||
int row_size =
|
||||
kEndPadding + 2 * kPopupBorderThickness +
|
||||
gfx::GetStringWidth(GetValueAt(i), GetValueFontListForRow(i)) +
|
||||
gfx::GetStringWidth(GetLabelAt(i), GetLabelFontListForRow(i));
|
||||
if (!GetLabelAt(i).empty())
|
||||
int row_size = kEndPadding + 2 * kPopupBorderThickness +
|
||||
gfx::GetStringWidth(value_at(i), GetValueFontListForRow(i)) +
|
||||
gfx::GetStringWidth(label_at(i), GetLabelFontListForRow(i));
|
||||
if (!label_at(i).empty())
|
||||
row_size += kNamePadding + kEndPadding;
|
||||
|
||||
popup_width = std::max(popup_width, row_size);
|
||||
@@ -307,18 +306,6 @@ ui::ColorId AutofillPopup::GetBackgroundColorIDForRow(int index) const {
|
||||
: ui::kColorResultsTableNormalBackground;
|
||||
}
|
||||
|
||||
int AutofillPopup::GetLineCount() {
|
||||
return values_.size();
|
||||
}
|
||||
|
||||
std::u16string AutofillPopup::GetValueAt(int i) {
|
||||
return values_.at(i);
|
||||
}
|
||||
|
||||
std::u16string AutofillPopup::GetLabelAt(int i) {
|
||||
return labels_.at(i);
|
||||
}
|
||||
|
||||
int AutofillPopup::LineFromY(int y) const {
|
||||
int current_height = kPopupBorderThickness;
|
||||
|
||||
|
||||
@@ -57,9 +57,9 @@ class AutofillPopup : public views::ViewObserver {
|
||||
const gfx::FontList& GetLabelFontListForRow(int index) const;
|
||||
ui::ColorId GetBackgroundColorIDForRow(int index) const;
|
||||
|
||||
int GetLineCount();
|
||||
std::u16string GetValueAt(int i);
|
||||
std::u16string GetLabelAt(int i);
|
||||
int line_count() const { return values_.size(); }
|
||||
const std::u16string& value_at(int i) const { return values_.at(i); }
|
||||
const std::u16string& label_at(int i) const { return labels_.at(i); }
|
||||
int LineFromY(int y) const;
|
||||
|
||||
int selected_index_;
|
||||
|
||||
@@ -27,7 +27,7 @@
|
||||
devtools_is_first_responder_ = NO;
|
||||
attached_to_window_ = NO;
|
||||
|
||||
if (inspectableWebContentsView_->inspectable_web_contents()->IsGuest()) {
|
||||
if (inspectableWebContentsView_->inspectable_web_contents()->is_guest()) {
|
||||
fake_view_ = [[NSView alloc] init];
|
||||
[fake_view_ setAutoresizingMask:NSViewWidthSizable | NSViewHeightSizable];
|
||||
[self addSubview:fake_view_];
|
||||
|
||||
@@ -493,8 +493,8 @@ NSArray* ConvertSharingItemToNS(const SharingItem& item) {
|
||||
if (menu_)
|
||||
return menu_;
|
||||
|
||||
if (model_ && model_->GetSharingItem()) {
|
||||
NSMenu* menu = [self createShareMenuForItem:*model_->GetSharingItem()];
|
||||
if (model_ && model_->sharing_item()) {
|
||||
NSMenu* menu = [self createShareMenuForItem:*model_->sharing_item()];
|
||||
menu_ = menu;
|
||||
} else {
|
||||
menu_ = [[NSMenu alloc] initWithTitle:@""];
|
||||
|
||||
@@ -76,7 +76,7 @@ using FullScreenTransitionState =
|
||||
- (NSRect)windowWillUseStandardFrame:(NSWindow*)window
|
||||
defaultFrame:(NSRect)frame {
|
||||
if (!shell_->zoom_to_page_width()) {
|
||||
if (shell_->GetAspectRatio() > 0.0)
|
||||
if (shell_->aspect_ratio() > 0.0)
|
||||
shell_->set_default_frame_for_zoom(frame);
|
||||
return frame;
|
||||
}
|
||||
@@ -104,7 +104,7 @@ using FullScreenTransitionState =
|
||||
// Set the width. Don't touch y or height.
|
||||
frame.size.width = zoomed_width;
|
||||
|
||||
if (shell_->GetAspectRatio() > 0.0)
|
||||
if (shell_->aspect_ratio() > 0.0)
|
||||
shell_->set_default_frame_for_zoom(frame);
|
||||
|
||||
return frame;
|
||||
@@ -139,13 +139,12 @@ using FullScreenTransitionState =
|
||||
|
||||
- (NSSize)windowWillResize:(NSWindow*)sender toSize:(NSSize)frameSize {
|
||||
NSSize newSize = frameSize;
|
||||
double aspectRatio = shell_->GetAspectRatio();
|
||||
NSWindow* window = shell_->GetNativeWindow().GetNativeNSWindow();
|
||||
|
||||
if (aspectRatio > 0.0) {
|
||||
gfx::Size windowSize = shell_->GetSize();
|
||||
gfx::Size contentSize = shell_->GetContentSize();
|
||||
gfx::Size extraSize = shell_->GetAspectRatioExtraSize();
|
||||
if (const double aspectRatio = shell_->aspect_ratio(); aspectRatio > 0.0) {
|
||||
const gfx::Size windowSize = shell_->GetSize();
|
||||
const gfx::Size contentSize = shell_->GetContentSize();
|
||||
const gfx::Size extraSize = shell_->aspect_ratio_extra_size();
|
||||
|
||||
double titleBarHeight = windowSize.height() - contentSize.height();
|
||||
double extraWidthPlusFrame =
|
||||
|
||||
@@ -99,11 +99,6 @@ bool ElectronMenuModel::GetSharingItemAt(size_t index,
|
||||
void ElectronMenuModel::SetSharingItem(SharingItem item) {
|
||||
sharing_item_.emplace(std::move(item));
|
||||
}
|
||||
|
||||
const std::optional<ElectronMenuModel::SharingItem>&
|
||||
ElectronMenuModel::GetSharingItem() const {
|
||||
return sharing_item_;
|
||||
}
|
||||
#endif
|
||||
|
||||
void ElectronMenuModel::MenuWillClose() {
|
||||
|
||||
@@ -98,7 +98,10 @@ class ElectronMenuModel : public ui::SimpleMenuModel {
|
||||
bool GetSharingItemAt(size_t index, SharingItem* item) const;
|
||||
// Set/Get the SharingItem of this menu.
|
||||
void SetSharingItem(SharingItem item);
|
||||
const std::optional<SharingItem>& GetSharingItem() const;
|
||||
[[nodiscard]] const std::optional<SharingItem>& sharing_item() const {
|
||||
return sharing_item_;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
// ui::SimpleMenuModel:
|
||||
|
||||
@@ -384,10 +384,6 @@ InspectableWebContentsDelegate* InspectableWebContents::GetDelegate() const {
|
||||
return delegate_;
|
||||
}
|
||||
|
||||
bool InspectableWebContents::IsGuest() const {
|
||||
return is_guest_;
|
||||
}
|
||||
|
||||
void InspectableWebContents::ReleaseWebContents() {
|
||||
web_contents_.release();
|
||||
WebContentsDestroyed();
|
||||
@@ -454,7 +450,7 @@ void InspectableWebContents::CloseDevTools() {
|
||||
managed_devtools_web_contents_.reset();
|
||||
}
|
||||
embedder_message_dispatcher_.reset();
|
||||
if (!IsGuest())
|
||||
if (!is_guest())
|
||||
web_contents_->Focus();
|
||||
}
|
||||
}
|
||||
@@ -516,10 +512,6 @@ void InspectableWebContents::CallClientFunction(
|
||||
std::move(arguments), std::move(cb));
|
||||
}
|
||||
|
||||
gfx::Rect InspectableWebContents::GetDevToolsBounds() const {
|
||||
return devtools_bounds_;
|
||||
}
|
||||
|
||||
void InspectableWebContents::SaveDevToolsBounds(const gfx::Rect& bounds) {
|
||||
pref_service_->Set(kDevToolsBoundsPref,
|
||||
base::Value{RectToDictionary(bounds)});
|
||||
|
||||
@@ -55,7 +55,7 @@ class InspectableWebContents
|
||||
|
||||
void SetDelegate(InspectableWebContentsDelegate* delegate);
|
||||
InspectableWebContentsDelegate* GetDelegate() const;
|
||||
bool IsGuest() const;
|
||||
[[nodiscard]] bool is_guest() const { return is_guest_; }
|
||||
void ReleaseWebContents();
|
||||
void SetDevToolsWebContents(content::WebContents* devtools);
|
||||
void SetDockState(const std::string& state);
|
||||
@@ -76,7 +76,9 @@ class InspectableWebContents
|
||||
void InspectElement(int x, int y);
|
||||
|
||||
// Return the last position and size of devtools window.
|
||||
gfx::Rect GetDevToolsBounds() const;
|
||||
[[nodiscard]] const gfx::Rect& dev_tools_bounds() const {
|
||||
return devtools_bounds_;
|
||||
}
|
||||
void SaveDevToolsBounds(const gfx::Rect& bounds);
|
||||
|
||||
// Return the last set zoom level of devtools window.
|
||||
|
||||
@@ -124,7 +124,7 @@ void AutofillPopupView::OnSuggestionsChanged() {
|
||||
return;
|
||||
|
||||
CreateChildViews();
|
||||
if (popup_->GetLineCount() == 0) {
|
||||
if (popup_->line_count() == 0) {
|
||||
popup_->Hide();
|
||||
return;
|
||||
}
|
||||
@@ -177,28 +177,28 @@ void AutofillPopupView::DrawAutofillEntry(gfx::Canvas* canvas,
|
||||
|
||||
int x_align_left = value_rect.x();
|
||||
const int value_width = gfx::GetStringWidth(
|
||||
popup_->GetValueAt(index), popup_->GetValueFontListForRow(index));
|
||||
popup_->value_at(index), popup_->GetValueFontListForRow(index));
|
||||
int value_x_align_left = x_align_left;
|
||||
value_x_align_left =
|
||||
is_rtl ? value_rect.right() - value_width : value_rect.x();
|
||||
|
||||
canvas->DrawStringRectWithFlags(
|
||||
popup_->GetValueAt(index), popup_->GetValueFontListForRow(index),
|
||||
popup_->value_at(index), popup_->GetValueFontListForRow(index),
|
||||
GetColorProvider()->GetColor(ui::kColorResultsTableNormalText),
|
||||
gfx::Rect(value_x_align_left, value_rect.y(), value_width,
|
||||
value_rect.height()),
|
||||
text_align);
|
||||
|
||||
// Draw the label text, if one exists.
|
||||
if (!popup_->GetLabelAt(index).empty()) {
|
||||
const int label_width = gfx::GetStringWidth(
|
||||
popup_->GetLabelAt(index), popup_->GetLabelFontListForRow(index));
|
||||
if (auto const& label = popup_->label_at(index); !label.empty()) {
|
||||
const int label_width =
|
||||
gfx::GetStringWidth(label, popup_->GetLabelFontListForRow(index));
|
||||
int label_x_align_left = x_align_left;
|
||||
label_x_align_left =
|
||||
is_rtl ? value_rect.x() : value_rect.right() - label_width;
|
||||
|
||||
canvas->DrawStringRectWithFlags(
|
||||
popup_->GetLabelAt(index), popup_->GetLabelFontListForRow(index),
|
||||
label, popup_->GetLabelFontListForRow(index),
|
||||
GetColorProvider()->GetColor(ui::kColorResultsTableDimmedText),
|
||||
gfx::Rect(label_x_align_left, entry_rect.y(), label_width,
|
||||
entry_rect.height()),
|
||||
@@ -212,8 +212,8 @@ void AutofillPopupView::CreateChildViews() {
|
||||
|
||||
RemoveAllChildViews();
|
||||
|
||||
for (int i = 0; i < popup_->GetLineCount(); ++i) {
|
||||
auto* child_view = new AutofillPopupChildView(popup_->GetValueAt(i));
|
||||
for (int i = 0; i < popup_->line_count(); ++i) {
|
||||
auto* child_view = new AutofillPopupChildView(popup_->value_at(i));
|
||||
child_view->set_drag_controller(this);
|
||||
AddChildView(child_view);
|
||||
}
|
||||
@@ -234,8 +234,7 @@ void AutofillPopupView::DoUpdateBoundsAndRedrawPopup() {
|
||||
}
|
||||
|
||||
void AutofillPopupView::OnPaint(gfx::Canvas* canvas) {
|
||||
if (!popup_ ||
|
||||
static_cast<size_t>(popup_->GetLineCount()) != children().size())
|
||||
if (!popup_ || static_cast<size_t>(popup_->line_count()) != children().size())
|
||||
return;
|
||||
gfx::Canvas* draw_canvas = canvas;
|
||||
SkBitmap bitmap;
|
||||
@@ -252,7 +251,7 @@ void AutofillPopupView::OnPaint(gfx::Canvas* canvas) {
|
||||
GetColorProvider()->GetColor(ui::kColorResultsTableNormalBackground));
|
||||
OnPaintBorder(draw_canvas);
|
||||
|
||||
for (int i = 0; i < popup_->GetLineCount(); ++i) {
|
||||
for (int i = 0; i < popup_->line_count(); ++i) {
|
||||
gfx::Rect line_rect = popup_->GetRowBounds(i);
|
||||
|
||||
DrawAutofillEntry(draw_canvas, i, line_rect);
|
||||
@@ -381,7 +380,7 @@ bool AutofillPopupView::HandleKeyPressEvent(
|
||||
SetSelectedLine(0);
|
||||
return true;
|
||||
case ui::VKEY_NEXT: // Page down.
|
||||
SetSelectedLine(popup_->GetLineCount() - 1);
|
||||
SetSelectedLine(popup_->line_count() - 1);
|
||||
return true;
|
||||
case ui::VKEY_ESCAPE:
|
||||
popup_->Hide();
|
||||
@@ -421,7 +420,7 @@ void AutofillPopupView::AcceptSuggestion(int index) {
|
||||
}
|
||||
|
||||
bool AutofillPopupView::AcceptSelectedLine() {
|
||||
if (!selected_line_ || selected_line_.value() >= popup_->GetLineCount())
|
||||
if (!selected_line_ || selected_line_.value() >= popup_->line_count())
|
||||
return false;
|
||||
|
||||
AcceptSuggestion(selected_line_.value());
|
||||
@@ -441,7 +440,7 @@ void AutofillPopupView::SetSelectedLine(std::optional<int> selected_line) {
|
||||
return;
|
||||
if (selected_line_ == selected_line)
|
||||
return;
|
||||
if (selected_line && selected_line.value() >= popup_->GetLineCount())
|
||||
if (selected_line && selected_line.value() >= popup_->line_count())
|
||||
return;
|
||||
|
||||
auto previous_selected_line(selected_line_);
|
||||
@@ -461,7 +460,7 @@ void AutofillPopupView::SelectNextLine() {
|
||||
return;
|
||||
|
||||
int new_selected_line = selected_line_ ? *selected_line_ + 1 : 0;
|
||||
if (new_selected_line >= popup_->GetLineCount())
|
||||
if (new_selected_line >= popup_->line_count())
|
||||
new_selected_line = 0;
|
||||
|
||||
SetSelectedLine(new_selected_line);
|
||||
@@ -473,7 +472,7 @@ void AutofillPopupView::SelectPreviousLine() {
|
||||
|
||||
int new_selected_line = selected_line_.value_or(0) - 1;
|
||||
if (new_selected_line < 0)
|
||||
new_selected_line = popup_->GetLineCount() - 1;
|
||||
new_selected_line = popup_->line_count() - 1;
|
||||
|
||||
SetSelectedLine(new_selected_line);
|
||||
}
|
||||
|
||||
@@ -83,7 +83,7 @@ InspectableWebContentsViewViews::InspectableWebContentsViewViews(
|
||||
: InspectableWebContentsView(inspectable_web_contents),
|
||||
devtools_web_view_(new views::WebView(nullptr)),
|
||||
title_(u"Developer Tools") {
|
||||
if (!inspectable_web_contents_->IsGuest() &&
|
||||
if (!inspectable_web_contents_->is_guest() &&
|
||||
inspectable_web_contents_->GetWebContents()->GetNativeView()) {
|
||||
auto* contents_web_view = new views::WebView(nullptr);
|
||||
contents_web_view->SetWebContents(
|
||||
@@ -116,8 +116,7 @@ void InspectableWebContentsViewViews::ShowDevTools(bool activate) {
|
||||
if (devtools_window_) {
|
||||
devtools_window_web_view_->SetWebContents(
|
||||
inspectable_web_contents_->GetDevToolsWebContents());
|
||||
devtools_window_->SetBounds(
|
||||
inspectable_web_contents()->GetDevToolsBounds());
|
||||
devtools_window_->SetBounds(inspectable_web_contents()->dev_tools_bounds());
|
||||
if (activate) {
|
||||
devtools_window_->Show();
|
||||
} else {
|
||||
@@ -182,7 +181,7 @@ void InspectableWebContentsViewViews::SetIsDocked(bool docked, bool activate) {
|
||||
views::Widget::InitParams params;
|
||||
params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
|
||||
params.delegate = devtools_window_delegate_;
|
||||
params.bounds = inspectable_web_contents()->GetDevToolsBounds();
|
||||
params.bounds = inspectable_web_contents()->dev_tools_bounds();
|
||||
|
||||
#if BUILDFLAG(IS_LINUX)
|
||||
params.wm_role_name = "devtools";
|
||||
|
||||
@@ -295,11 +295,8 @@ void HandleAccessibilityRequestCallback(
|
||||
|
||||
data.Set(kBrowsersField, std::move(window_list));
|
||||
|
||||
std::string json_string;
|
||||
base::JSONWriter::Write(data, &json_string);
|
||||
|
||||
std::move(callback).Run(
|
||||
base::MakeRefCounted<base::RefCountedString>(std::move(json_string)));
|
||||
std::move(callback).Run(base::MakeRefCounted<base::RefCountedString>(
|
||||
base::WriteJson(data).value_or("")));
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
@@ -107,7 +107,7 @@ class TrackableObject : public TrackableObjectBase, public EventEmitter<T> {
|
||||
|
||||
// Removes this instance from the weak map.
|
||||
void RemoveFromWeakMap() {
|
||||
if (weak_map_ && weak_map_->Has(weak_map_id()))
|
||||
if (weak_map_)
|
||||
weak_map_->Remove(weak_map_id());
|
||||
}
|
||||
|
||||
|
||||
@@ -9,24 +9,17 @@
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#include "base/containers/contains.h"
|
||||
#include "base/memory/raw_ptr.h"
|
||||
#include "v8/include/v8.h"
|
||||
|
||||
namespace electron {
|
||||
|
||||
// Like ES6's WeakMap, but the key is Integer and the value is Weak Pointer.
|
||||
// Like ES6's WeakMap, with a K key and Weak Pointer value.
|
||||
template <typename K>
|
||||
class KeyWeakMap {
|
||||
public:
|
||||
// Records the key and self, used by SetWeak.
|
||||
struct KeyObject {
|
||||
K key;
|
||||
raw_ptr<KeyWeakMap> self;
|
||||
};
|
||||
|
||||
KeyWeakMap() {}
|
||||
virtual ~KeyWeakMap() {
|
||||
~KeyWeakMap() {
|
||||
for (auto& p : map_)
|
||||
p.second.second.ClearWeak();
|
||||
}
|
||||
@@ -45,23 +38,19 @@ class KeyWeakMap {
|
||||
|
||||
// Gets the object from WeakMap by its |key|.
|
||||
v8::MaybeLocal<v8::Object> Get(v8::Isolate* isolate, const K& key) {
|
||||
auto iter = map_.find(key);
|
||||
if (iter == map_.end())
|
||||
return v8::MaybeLocal<v8::Object>();
|
||||
else
|
||||
if (auto iter = map_.find(key); iter != map_.end())
|
||||
return v8::Local<v8::Object>::New(isolate, iter->second.second);
|
||||
return {};
|
||||
}
|
||||
|
||||
// Whether there is an object with |key| in this WeakMap.
|
||||
constexpr bool Has(const K& key) const { return base::Contains(map_, key); }
|
||||
|
||||
// Returns all objects.
|
||||
std::vector<v8::Local<v8::Object>> Values(v8::Isolate* isolate) const {
|
||||
std::vector<v8::Local<v8::Object>> keys;
|
||||
keys.reserve(map_.size());
|
||||
std::vector<v8::Local<v8::Object>> values;
|
||||
values.reserve(map_.size());
|
||||
for (const auto& it : map_)
|
||||
keys.emplace_back(v8::Local<v8::Object>::New(isolate, it.second.second));
|
||||
return keys;
|
||||
values.emplace_back(
|
||||
v8::Local<v8::Object>::New(isolate, it.second.second));
|
||||
return values;
|
||||
}
|
||||
|
||||
// Remove object with |key| in the WeakMap.
|
||||
@@ -75,6 +64,12 @@ class KeyWeakMap {
|
||||
}
|
||||
|
||||
private:
|
||||
// Records the key and self, used by SetWeak.
|
||||
struct KeyObject {
|
||||
K key;
|
||||
raw_ptr<KeyWeakMap> self;
|
||||
};
|
||||
|
||||
static void OnObjectGC(
|
||||
const v8::WeakCallbackInfo<typename KeyWeakMap<K>::KeyObject>& data) {
|
||||
KeyWeakMap<K>::KeyObject* key_object = data.GetParameter();
|
||||
|
||||
@@ -942,6 +942,10 @@ void OnNodePreload(node::Environment* env,
|
||||
if (dict.Get("versions", &versions)) {
|
||||
versions.SetReadOnly(ELECTRON_PROJECT_NAME, ELECTRON_VERSION_STRING);
|
||||
versions.SetReadOnly("chrome", CHROME_VERSION_STRING);
|
||||
#if BUILDFLAG(HAS_VENDOR_VERSION)
|
||||
versions.SetReadOnly(BUILDFLAG(VENDOR_VERSION_NAME),
|
||||
BUILDFLAG(VENDOR_VERSION_VALUE));
|
||||
#endif
|
||||
}
|
||||
|
||||
// Execute lib/node/init.ts.
|
||||
|
||||
@@ -4164,6 +4164,68 @@ describe('BrowserWindow module', () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe('BrowserWindow.isOccluded()', () => {
|
||||
afterEach(closeAllWindows);
|
||||
|
||||
it('returns false for a visible window', async () => {
|
||||
const w = new BrowserWindow({ show: false });
|
||||
|
||||
const shown = once(w, 'show');
|
||||
w.show();
|
||||
await shown;
|
||||
|
||||
expect(w.isOccluded()).to.be.false('window is occluded');
|
||||
});
|
||||
|
||||
it('returns false when the window is only partially obscured', async () => {
|
||||
const w1 = new BrowserWindow({ x: 250, y: 250, width: 400, height: 400 });
|
||||
const w2 = new BrowserWindow({ show: false, x: 200, y: 200, width: 500, height: 500 });
|
||||
|
||||
const focused = once(w2, 'focus');
|
||||
w2.show();
|
||||
await focused;
|
||||
|
||||
await setTimeout(2000);
|
||||
console.log(w1.getBounds(), w2.getBounds());
|
||||
expect(w1.isOccluded()).to.be.true('window is not occluded');
|
||||
|
||||
const pos = w2.getPosition();
|
||||
const move = once(w2, 'move');
|
||||
w2.setPosition(pos[0] - 100, pos[1]);
|
||||
await move;
|
||||
|
||||
await setTimeout(2000);
|
||||
console.log(w1.getBounds(), w2.getBounds());
|
||||
expect(w1.isOccluded()).to.be.false('window is occluded');
|
||||
});
|
||||
|
||||
// FIXME: this test fails on Linux CI due to windowing issues.
|
||||
ifit(process.platform !== 'linux')('returns false for a visible window covered by a transparent window', async () => {
|
||||
const w1 = new BrowserWindow({ width: 200, height: 200 });
|
||||
const w2 = new BrowserWindow({ show: false, transparent: true, frame: false });
|
||||
|
||||
const focused = once(w2, 'focus');
|
||||
w2.show();
|
||||
await focused;
|
||||
|
||||
await setTimeout(1000);
|
||||
expect(w1.isOccluded()).to.be.false('window is occluded');
|
||||
});
|
||||
|
||||
it('returns true for an obscured window', async () => {
|
||||
const w1 = new BrowserWindow({ x: 200, y: 200, width: 200, height: 200 });
|
||||
const w2 = new BrowserWindow({ show: false, x: 100, y: 100, width: 800, height: 800 });
|
||||
|
||||
const focused = once(w2, 'focus');
|
||||
w2.show();
|
||||
await focused;
|
||||
|
||||
await setTimeout(2000);
|
||||
console.log(w1.getBounds(), w2.getBounds());
|
||||
expect(w1.isOccluded()).to.be.true('visible window');
|
||||
});
|
||||
});
|
||||
|
||||
// TODO(codebytere): figure out how to make these pass in CI on Windows.
|
||||
ifdescribe(process.platform !== 'win32')('document.visibilityState/hidden', () => {
|
||||
afterEach(closeAllWindows);
|
||||
|
||||
@@ -345,6 +345,59 @@ describe('ipc module', () => {
|
||||
}})()`);
|
||||
});
|
||||
});
|
||||
|
||||
describe('when context destroyed', () => {
|
||||
it('does not crash', async () => {
|
||||
let count = 0;
|
||||
const server = http.createServer((req, res) => {
|
||||
switch (req.url) {
|
||||
case '/index.html':
|
||||
res.setHeader('content-type', 'text/html');
|
||||
res.statusCode = 200;
|
||||
count = count + 1;
|
||||
res.end(`
|
||||
<title>Hello${count}</title>
|
||||
<script>
|
||||
var sharedWorker = new SharedWorker('worker.js');
|
||||
|
||||
sharedWorker.port.addEventListener('close', function(event) {
|
||||
console.log('close event', event.data);
|
||||
});
|
||||
</script>`);
|
||||
|
||||
break;
|
||||
case '/worker.js':
|
||||
res.setHeader('content-type', 'application/javascript; charset=UTF-8');
|
||||
res.statusCode = 200;
|
||||
res.end(`
|
||||
self.addEventListener('connect', function(event) {
|
||||
var port = event.ports[0];
|
||||
|
||||
port.addEventListener('message', function(event) {
|
||||
console.log('Message from main:', event.data);
|
||||
port.postMessage('Hello from SharedWorker!');
|
||||
});
|
||||
|
||||
});`);
|
||||
break;
|
||||
default:
|
||||
throw new Error(`unsupported endpoint: ${req.url}`);
|
||||
}
|
||||
});
|
||||
const { port } = await listen(server);
|
||||
defer(() => {
|
||||
server.close();
|
||||
});
|
||||
const w = new BrowserWindow({ show: false });
|
||||
await w.loadURL(`http://localhost:${port}/index.html`);
|
||||
expect(w.webContents.getTitle()).to.equal('Hello1');
|
||||
// Before the fix, it would crash if reloaded, but now it doesn't
|
||||
await w.loadURL(`http://localhost:${port}/index.html`);
|
||||
expect(w.webContents.getTitle()).to.equal('Hello2');
|
||||
// const crashEvent = emittedOnce(w.webContents, 'render-process-gone');
|
||||
// await crashEvent;
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('MessageChannelMain', () => {
|
||||
|
||||
@@ -519,6 +519,10 @@ describe('webContents module', () => {
|
||||
await expect(w.loadURL('file:non-existent')).to.eventually.be.rejected();
|
||||
await expect(w.loadURL('file:non-existent')).to.eventually.be.rejected();
|
||||
});
|
||||
|
||||
it('invalid URL load rejects', async () => {
|
||||
await expect(w.loadURL('invalidURL')).to.eventually.be.rejected();
|
||||
});
|
||||
});
|
||||
|
||||
describe('getFocusedWebContents() API', () => {
|
||||
|
||||
@@ -1528,7 +1528,7 @@ describe('asar package', function () {
|
||||
originalFs.createReadStream(path.join(asarDir, 'a.asar'));
|
||||
});
|
||||
|
||||
itremote('can recursively delete a directory with an asar file in itremote', () => {
|
||||
itremote('can recursively delete a directory with an asar file in itremote using rmdirSync', () => {
|
||||
const deleteDir = path.join(asarDir, 'deleteme');
|
||||
fs.mkdirSync(deleteDir);
|
||||
|
||||
@@ -1538,6 +1538,16 @@ describe('asar package', function () {
|
||||
expect(fs.existsSync(deleteDir)).to.be.false();
|
||||
});
|
||||
|
||||
itremote('can recursively delete a directory with an asar file in itremote using promises.rmdir', async () => {
|
||||
const deleteDir = path.join(asarDir, 'deleteme');
|
||||
fs.mkdirSync(deleteDir);
|
||||
|
||||
const originalFs = require('original-fs');
|
||||
await originalFs.promises.rmdir(deleteDir, { recursive: true });
|
||||
|
||||
expect(fs.existsSync(deleteDir)).to.be.false();
|
||||
});
|
||||
|
||||
itremote('has the same APIs as fs', function () {
|
||||
expect(Object.keys(require('node:fs'))).to.deep.equal(Object.keys(require('original-fs')));
|
||||
expect(Object.keys(require('node:fs').promises)).to.deep.equal(Object.keys(require('original-fs').promises));
|
||||
|
||||
Reference in New Issue
Block a user