mirror of
https://github.com/electron/electron.git
synced 2026-02-26 03:01:17 -05:00
Compare commits
17 Commits
v20.0.0-al
...
v20.0.0-al
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
33670ac928 | ||
|
|
8ecbc11aa2 | ||
|
|
4ab3b1d624 | ||
|
|
bce95c4886 | ||
|
|
5b583c8808 | ||
|
|
c20d6e54c5 | ||
|
|
ff7f2a5091 | ||
|
|
10062c9a5b | ||
|
|
82a6e9bd5a | ||
|
|
10131e36f3 | ||
|
|
37078297c6 | ||
|
|
48f4ef65ed | ||
|
|
e174aac845 | ||
|
|
dd1a692aba | ||
|
|
aa05c43994 | ||
|
|
16561d08ae | ||
|
|
edc0a47c89 |
14
BUILD.gn
14
BUILD.gn
@@ -87,7 +87,10 @@ if (is_linux) {
|
||||
# implementation. In future, this file can be extended to contain
|
||||
# gtk4 stubs to switch gtk version in runtime.
|
||||
generate_stubs("electron_gtk_stubs") {
|
||||
sigs = [ "shell/browser/ui/electron_gtk.sigs" ]
|
||||
sigs = [
|
||||
"shell/browser/ui/electron_gdk_pixbuf.sigs",
|
||||
"shell/browser/ui/electron_gtk.sigs",
|
||||
]
|
||||
extra_header = "shell/browser/ui/electron_gtk.fragment"
|
||||
output_name = "electron_gtk_stubs"
|
||||
public_deps = [ "//ui/gtk:gtk_config" ]
|
||||
@@ -371,6 +374,7 @@ source_set("electron_lib") {
|
||||
"//chrome/app/resources:platform_locale_settings",
|
||||
"//components/autofill/core/common:features",
|
||||
"//components/certificate_transparency",
|
||||
"//components/embedder_support:browser_util",
|
||||
"//components/language/core/browser",
|
||||
"//components/net_log",
|
||||
"//components/network_hints/browser",
|
||||
@@ -726,14 +730,6 @@ source_set("electron_lib") {
|
||||
|
||||
sources += get_target_outputs(":electron_fuses")
|
||||
|
||||
if (is_win && enable_win_dark_mode_window_ui) {
|
||||
sources += [
|
||||
"shell/browser/win/dark_mode.cc",
|
||||
"shell/browser/win/dark_mode.h",
|
||||
]
|
||||
libs += [ "uxtheme.lib" ]
|
||||
}
|
||||
|
||||
if (allow_runtime_configurable_key_storage) {
|
||||
defines += [ "ALLOW_RUNTIME_CONFIGURABLE_KEY_STORAGE" ]
|
||||
}
|
||||
|
||||
@@ -1 +1 @@
|
||||
20.0.0-alpha.4
|
||||
20.0.0-alpha.7
|
||||
@@ -19,7 +19,6 @@ buildflag_header("buildflags") {
|
||||
"ENABLE_ELECTRON_EXTENSIONS=$enable_electron_extensions",
|
||||
"ENABLE_BUILTIN_SPELLCHECKER=$enable_builtin_spellchecker",
|
||||
"ENABLE_PICTURE_IN_PICTURE=$enable_picture_in_picture",
|
||||
"ENABLE_WIN_DARK_MODE_WINDOW_UI=$enable_win_dark_mode_window_ui",
|
||||
"OVERRIDE_LOCATION_PROVIDER=$enable_fake_location_provider",
|
||||
]
|
||||
}
|
||||
|
||||
@@ -31,7 +31,4 @@ declare_args() {
|
||||
|
||||
# Enable Spellchecker support
|
||||
enable_builtin_spellchecker = true
|
||||
|
||||
# Undocumented Windows dark mode API
|
||||
enable_win_dark_mode_window_ui = false
|
||||
}
|
||||
|
||||
@@ -105,6 +105,8 @@ filenames = {
|
||||
"shell/browser/ui/win/notify_icon.h",
|
||||
"shell/browser/ui/win/taskbar_host.cc",
|
||||
"shell/browser/ui/win/taskbar_host.h",
|
||||
"shell/browser/win/dark_mode.cc",
|
||||
"shell/browser/win/dark_mode.h",
|
||||
"shell/browser/win/scoped_hstring.cc",
|
||||
"shell/browser/win/scoped_hstring.h",
|
||||
"shell/common/api/electron_api_native_image_win.cc",
|
||||
|
||||
@@ -504,6 +504,7 @@ WebContents.prototype._callWindowOpenHandler = function (event: Electron.Event,
|
||||
if (!this._windowOpenHandler) {
|
||||
return defaultResponse;
|
||||
}
|
||||
|
||||
const response = this._windowOpenHandler(details);
|
||||
|
||||
if (typeof response !== 'object') {
|
||||
@@ -666,7 +667,15 @@ WebContents.prototype._init = function () {
|
||||
postBody,
|
||||
disposition
|
||||
};
|
||||
const result = this._callWindowOpenHandler(event, details);
|
||||
|
||||
let result;
|
||||
try {
|
||||
result = this._callWindowOpenHandler(event, details);
|
||||
} catch (err) {
|
||||
event.preventDefault();
|
||||
throw err;
|
||||
}
|
||||
|
||||
const options = result.browserWindowConstructorOptions;
|
||||
if (!event.defaultPrevented) {
|
||||
openGuestWindow({
|
||||
@@ -697,7 +706,15 @@ WebContents.prototype._init = function () {
|
||||
referrer,
|
||||
postBody
|
||||
};
|
||||
const result = this._callWindowOpenHandler(event, details);
|
||||
|
||||
let result;
|
||||
try {
|
||||
result = this._callWindowOpenHandler(event, details);
|
||||
} catch (err) {
|
||||
event.preventDefault();
|
||||
throw err;
|
||||
}
|
||||
|
||||
windowOpenOutlivesOpenerOption = result.outlivesOpener;
|
||||
windowOpenOverriddenOptions = result.browserWindowConstructorOptions;
|
||||
if (!event.defaultPrevented) {
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
* out-of-process (cross-origin) are created here. "Embedder" roughly means
|
||||
* "parent."
|
||||
*/
|
||||
import { BrowserWindow } from 'electron/main';
|
||||
import { BrowserWindow, deprecate } from 'electron/main';
|
||||
import type { BrowserWindowConstructorOptions, Referrer, WebContents, LoadURLOptions } from 'electron/main';
|
||||
import { parseFeatures } from '@electron/internal/browser/parse-features-string';
|
||||
|
||||
@@ -155,6 +155,10 @@ function emitDeprecatedNewWindowEvent ({ event, embedder, guest, windowOpenArgs,
|
||||
...parseContentTypeFormat(postData)
|
||||
} : null;
|
||||
|
||||
if (embedder.listenerCount('new-window') > 0) {
|
||||
deprecate.log('The new-window event is deprecated and will be removed. Please use contents.setWindowOpenHandler() instead.');
|
||||
}
|
||||
|
||||
embedder.emit(
|
||||
'new-window',
|
||||
event,
|
||||
|
||||
@@ -68,6 +68,10 @@ ipcMainUtils.handleSync(IPC_MESSAGES.BROWSER_SANDBOX_LOAD, async function (event
|
||||
};
|
||||
});
|
||||
|
||||
ipcMainUtils.handleSync(IPC_MESSAGES.BROWSER_NONSANDBOX_LOAD, function (event) {
|
||||
return { preloadPaths: event.sender._getPreloadPaths() };
|
||||
});
|
||||
|
||||
ipcMainInternal.on(IPC_MESSAGES.BROWSER_PRELOAD_ERROR, function (event, preloadPath: string, error: Error) {
|
||||
event.sender.emit('preload-error', event, preloadPath, error);
|
||||
});
|
||||
|
||||
@@ -3,6 +3,7 @@ export const enum IPC_MESSAGES {
|
||||
BROWSER_GET_LAST_WEB_PREFERENCES = 'BROWSER_GET_LAST_WEB_PREFERENCES',
|
||||
BROWSER_PRELOAD_ERROR = 'BROWSER_PRELOAD_ERROR',
|
||||
BROWSER_SANDBOX_LOAD = 'BROWSER_SANDBOX_LOAD',
|
||||
BROWSER_NONSANDBOX_LOAD = 'BROWSER_NONSANDBOX_LOAD',
|
||||
BROWSER_WINDOW_CLOSE = 'BROWSER_WINDOW_CLOSE',
|
||||
BROWSER_GET_PROCESS_MEMORY_INFO = 'BROWSER_GET_PROCESS_MEMORY_INFO',
|
||||
|
||||
|
||||
@@ -2,6 +2,7 @@ import * as path from 'path';
|
||||
import { IPC_MESSAGES } from '@electron/internal/common/ipc-messages';
|
||||
|
||||
import type * as ipcRendererInternalModule from '@electron/internal/renderer/ipc-renderer-internal';
|
||||
import type * as ipcRendererUtilsModule from '@electron/internal/renderer/ipc-renderer-internal-utils';
|
||||
|
||||
const Module = require('module');
|
||||
|
||||
@@ -38,6 +39,7 @@ require('../common/reset-search-paths');
|
||||
require('@electron/internal/common/init');
|
||||
|
||||
const { ipcRendererInternal } = require('@electron/internal/renderer/ipc-renderer-internal') as typeof ipcRendererInternalModule;
|
||||
const ipcRendererUtils = require('@electron/internal/renderer/ipc-renderer-internal-utils') as typeof ipcRendererUtilsModule;
|
||||
|
||||
process.getProcessMemoryInfo = () => {
|
||||
return ipcRendererInternal.invoke<Electron.ProcessMemoryInfo>(IPC_MESSAGES.BROWSER_GET_PROCESS_MEMORY_INFO);
|
||||
@@ -48,15 +50,8 @@ const { hasSwitch, getSwitchValue } = process._linkedBinding('electron_common_co
|
||||
const { mainFrame } = process._linkedBinding('electron_renderer_web_frame');
|
||||
|
||||
const nodeIntegration = mainFrame.getWebPreference('nodeIntegration');
|
||||
const preloadScript = mainFrame.getWebPreference('preload');
|
||||
const preloadScripts = mainFrame.getWebPreference('preloadScripts');
|
||||
const appPath = hasSwitch('app-path') ? getSwitchValue('app-path') : null;
|
||||
|
||||
// The webContents preload script is loaded after the session preload scripts.
|
||||
if (preloadScript) {
|
||||
preloadScripts.push(preloadScript);
|
||||
}
|
||||
|
||||
// Common renderer initialization
|
||||
require('@electron/internal/renderer/common-init');
|
||||
|
||||
@@ -127,8 +122,9 @@ if (nodeIntegration) {
|
||||
}
|
||||
}
|
||||
|
||||
const { preloadPaths } = ipcRendererUtils.invokeSync(IPC_MESSAGES.BROWSER_NONSANDBOX_LOAD);
|
||||
// Load the preload scripts.
|
||||
for (const preloadScript of preloadScripts) {
|
||||
for (const preloadScript of preloadPaths) {
|
||||
try {
|
||||
Module._load(preloadScript);
|
||||
} catch (error) {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "electron",
|
||||
"version": "20.0.0-alpha.4",
|
||||
"version": "20.0.0-alpha.7",
|
||||
"repository": "https://github.com/electron/electron",
|
||||
"description": "Build cross platform desktop apps with JavaScript, HTML, and CSS",
|
||||
"devDependencies": {
|
||||
|
||||
@@ -8,10 +8,10 @@ WebPreferences of in-process child windows, rather than relying on
|
||||
process-level command line switches, as before.
|
||||
|
||||
diff --git a/third_party/blink/common/web_preferences/web_preferences.cc b/third_party/blink/common/web_preferences/web_preferences.cc
|
||||
index 6d51f6a77c21b60ab756dbf8d4961b351a2e2b07..c6dc3cebfb32489a5e50b850ed02a066bf3f258e 100644
|
||||
index 6d51f6a77c21b60ab756dbf8d4961b351a2e2b07..26b820b3ce387e01900cec4227ff290113a833c3 100644
|
||||
--- a/third_party/blink/common/web_preferences/web_preferences.cc
|
||||
+++ b/third_party/blink/common/web_preferences/web_preferences.cc
|
||||
@@ -142,6 +142,20 @@ WebPreferences::WebPreferences()
|
||||
@@ -142,6 +142,19 @@ WebPreferences::WebPreferences()
|
||||
fake_no_alloc_direct_call_for_testing_enabled(false),
|
||||
v8_cache_options(blink::mojom::V8CacheOptions::kDefault),
|
||||
record_whole_document(false),
|
||||
@@ -20,7 +20,6 @@ index 6d51f6a77c21b60ab756dbf8d4961b351a2e2b07..c6dc3cebfb32489a5e50b850ed02a066
|
||||
+ is_webview(false),
|
||||
+ hidden_page(false),
|
||||
+ offscreen(false),
|
||||
+ preload(base::FilePath::StringType()),
|
||||
+ node_integration(false),
|
||||
+ node_integration_in_worker(false),
|
||||
+ node_integration_in_sub_frames(false),
|
||||
@@ -33,21 +32,10 @@ index 6d51f6a77c21b60ab756dbf8d4961b351a2e2b07..c6dc3cebfb32489a5e50b850ed02a066
|
||||
accelerated_video_decode_enabled(false),
|
||||
animation_policy(
|
||||
diff --git a/third_party/blink/common/web_preferences/web_preferences_mojom_traits.cc b/third_party/blink/common/web_preferences/web_preferences_mojom_traits.cc
|
||||
index 187fd8d9818693262256d5cbddd5e02659ba903d..f166517f4e70ced310253539fb6197f6b3af559c 100644
|
||||
index 187fd8d9818693262256d5cbddd5e02659ba903d..28e5178361e03d1ac851fa74214931b2332dd9c2 100644
|
||||
--- a/third_party/blink/common/web_preferences/web_preferences_mojom_traits.cc
|
||||
+++ b/third_party/blink/common/web_preferences/web_preferences_mojom_traits.cc
|
||||
@@ -23,6 +23,10 @@ bool StructTraits<blink::mojom::WebPreferencesDataView,
|
||||
!data.ReadCursiveFontFamilyMap(&out->cursive_font_family_map) ||
|
||||
!data.ReadFantasyFontFamilyMap(&out->fantasy_font_family_map) ||
|
||||
!data.ReadMathFontFamilyMap(&out->math_font_family_map) ||
|
||||
+ // Begin Electron-specific WebPreferences.
|
||||
+ !data.ReadPreloads(&out->preloads) ||
|
||||
+ !data.ReadPreload(&out->preload) ||
|
||||
+ // End Electron-specific WebPreferences.
|
||||
!data.ReadLazyFrameLoadingDistanceThresholdsPx(
|
||||
&out->lazy_frame_loading_distance_thresholds_px) ||
|
||||
!data.ReadLazyImageLoadingDistanceThresholdsPx(
|
||||
@@ -148,6 +152,19 @@ bool StructTraits<blink::mojom::WebPreferencesDataView,
|
||||
@@ -148,6 +148,19 @@ bool StructTraits<blink::mojom::WebPreferencesDataView,
|
||||
data.fake_no_alloc_direct_call_for_testing_enabled();
|
||||
out->v8_cache_options = data.v8_cache_options();
|
||||
out->record_whole_document = data.record_whole_document();
|
||||
@@ -68,7 +56,7 @@ index 187fd8d9818693262256d5cbddd5e02659ba903d..f166517f4e70ced310253539fb6197f6
|
||||
out->accelerated_video_decode_enabled =
|
||||
data.accelerated_video_decode_enabled();
|
||||
diff --git a/third_party/blink/public/common/web_preferences/web_preferences.h b/third_party/blink/public/common/web_preferences/web_preferences.h
|
||||
index 59947bfd3c042e5f7d3993967fece9b519f93472..368ec7fb398409cd6386269934eaffcce356793f 100644
|
||||
index 59947bfd3c042e5f7d3993967fece9b519f93472..cb2a53f6147767394585ed371744d8a140aace71 100644
|
||||
--- a/third_party/blink/public/common/web_preferences/web_preferences.h
|
||||
+++ b/third_party/blink/public/common/web_preferences/web_preferences.h
|
||||
@@ -10,6 +10,7 @@
|
||||
@@ -79,17 +67,15 @@ index 59947bfd3c042e5f7d3993967fece9b519f93472..368ec7fb398409cd6386269934eaffcc
|
||||
#include "net/nqe/effective_connection_type.h"
|
||||
#include "third_party/blink/public/common/common_export.h"
|
||||
#include "third_party/blink/public/mojom/css/preferred_color_scheme.mojom-shared.h"
|
||||
@@ -154,6 +155,22 @@ struct BLINK_COMMON_EXPORT WebPreferences {
|
||||
@@ -154,6 +155,20 @@ struct BLINK_COMMON_EXPORT WebPreferences {
|
||||
blink::mojom::V8CacheOptions v8_cache_options;
|
||||
bool record_whole_document;
|
||||
|
||||
+ // Begin Electron-specific WebPreferences.
|
||||
+ std::vector<base::FilePath> preloads;
|
||||
+ bool context_isolation;
|
||||
+ bool is_webview;
|
||||
+ bool hidden_page;
|
||||
+ bool offscreen;
|
||||
+ base::FilePath preload;
|
||||
+ bool node_integration;
|
||||
+ bool node_integration_in_worker;
|
||||
+ bool node_integration_in_sub_frames;
|
||||
@@ -103,7 +89,7 @@ index 59947bfd3c042e5f7d3993967fece9b519f93472..368ec7fb398409cd6386269934eaffcc
|
||||
// only controls whether or not the "document.cookie" field is properly
|
||||
// connected to the backing store, for instance if you wanted to be able to
|
||||
diff --git a/third_party/blink/public/common/web_preferences/web_preferences_mojom_traits.h b/third_party/blink/public/common/web_preferences/web_preferences_mojom_traits.h
|
||||
index bd425a5869477de9095c6a41c683609d065b08c0..3a5d7450aa40e8a7614e83f316d3d0fb59583381 100644
|
||||
index bd425a5869477de9095c6a41c683609d065b08c0..c7ba3ff52c9de01028c9e2be214e20cd91cbf309 100644
|
||||
--- a/third_party/blink/public/common/web_preferences/web_preferences_mojom_traits.h
|
||||
+++ b/third_party/blink/public/common/web_preferences/web_preferences_mojom_traits.h
|
||||
@@ -6,6 +6,7 @@
|
||||
@@ -114,15 +100,11 @@ index bd425a5869477de9095c6a41c683609d065b08c0..3a5d7450aa40e8a7614e83f316d3d0fb
|
||||
#include "mojo/public/cpp/bindings/struct_traits.h"
|
||||
#include "net/nqe/effective_connection_type.h"
|
||||
#include "third_party/blink/public/common/common_export.h"
|
||||
@@ -428,6 +429,60 @@ struct BLINK_COMMON_EXPORT StructTraits<blink::mojom::WebPreferencesDataView,
|
||||
@@ -428,6 +429,52 @@ struct BLINK_COMMON_EXPORT StructTraits<blink::mojom::WebPreferencesDataView,
|
||||
return r.record_whole_document;
|
||||
}
|
||||
|
||||
+ // Begin Electron-specific WebPreferences.
|
||||
+ static const std::vector<base::FilePath>& preloads(const blink::web_pref::WebPreferences& r) {
|
||||
+ return r.preloads;
|
||||
+ }
|
||||
+
|
||||
+ static bool context_isolation(const blink::web_pref::WebPreferences& r) {
|
||||
+ return r.context_isolation;
|
||||
+ }
|
||||
@@ -139,10 +121,6 @@ index bd425a5869477de9095c6a41c683609d065b08c0..3a5d7450aa40e8a7614e83f316d3d0fb
|
||||
+ return r.offscreen;
|
||||
+ }
|
||||
+
|
||||
+ static const base::FilePath& preload(const blink::web_pref::WebPreferences& r) {
|
||||
+ return r.preload;
|
||||
+ }
|
||||
+
|
||||
+ static bool node_integration(const blink::web_pref::WebPreferences& r) {
|
||||
+ return r.node_integration;
|
||||
+ }
|
||||
@@ -176,7 +154,7 @@ index bd425a5869477de9095c6a41c683609d065b08c0..3a5d7450aa40e8a7614e83f316d3d0fb
|
||||
return r.cookie_enabled;
|
||||
}
|
||||
diff --git a/third_party/blink/public/mojom/webpreferences/web_preferences.mojom b/third_party/blink/public/mojom/webpreferences/web_preferences.mojom
|
||||
index 738ac646e075f7a37ba2a263c7799a755e63d3fb..80d6ae17d34ef5c7fd14e21c4e1ee3ed4ef9c5fe 100644
|
||||
index 738ac646e075f7a37ba2a263c7799a755e63d3fb..40ab2a4b9a1f9de5f201502adebc166a48fccd35 100644
|
||||
--- a/third_party/blink/public/mojom/webpreferences/web_preferences.mojom
|
||||
+++ b/third_party/blink/public/mojom/webpreferences/web_preferences.mojom
|
||||
@@ -10,6 +10,7 @@ import "third_party/blink/public/mojom/v8_cache_options.mojom";
|
||||
@@ -187,17 +165,15 @@ index 738ac646e075f7a37ba2a263c7799a755e63d3fb..80d6ae17d34ef5c7fd14e21c4e1ee3ed
|
||||
|
||||
enum PointerType {
|
||||
kPointerNone = 1, // 1 << 0
|
||||
@@ -206,6 +207,22 @@ struct WebPreferences {
|
||||
@@ -206,6 +207,20 @@ struct WebPreferences {
|
||||
V8CacheOptions v8_cache_options;
|
||||
bool record_whole_document;
|
||||
|
||||
+ // Begin Electron-specific WebPreferences.
|
||||
+ array<mojo_base.mojom.FilePath> preloads;
|
||||
+ bool context_isolation;
|
||||
+ bool is_webview;
|
||||
+ bool hidden_page;
|
||||
+ bool offscreen;
|
||||
+ mojo_base.mojom.FilePath preload;
|
||||
+ bool node_integration;
|
||||
+ bool node_integration_in_worker;
|
||||
+ bool node_integration_in_sub_frames;
|
||||
|
||||
@@ -1,16 +1,28 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: deepak1556 <hop2deep@gmail.com>
|
||||
Date: Thu, 7 Apr 2022 20:30:16 +0900
|
||||
Subject: Make gtk::GetLibGtk public
|
||||
Subject: Make gtk::GetLibGtk and gtk::GetLibGdkPixbuf public
|
||||
|
||||
Allows embedders to get a handle to the gtk library
|
||||
already loaded in the process.
|
||||
Allows embedders to get a handle to the gtk and
|
||||
gdk_pixbuf libraries already loaded in the process.
|
||||
|
||||
diff --git a/ui/gtk/gtk_compat.cc b/ui/gtk/gtk_compat.cc
|
||||
index b5c7af5bdb93b320f95252d35d2d76bae7f8c445..40b706ed7cde206e98274025148604760b7477f9 100644
|
||||
index b5c7af5bdb93b320f95252d35d2d76bae7f8c445..65b097cfab72b92f301968715eb218ef0e468567 100644
|
||||
--- a/ui/gtk/gtk_compat.cc
|
||||
+++ b/ui/gtk/gtk_compat.cc
|
||||
@@ -86,12 +86,6 @@ void* GetLibGtk4(bool check = true) {
|
||||
@@ -66,11 +66,6 @@ void* GetLibGio() {
|
||||
return libgio;
|
||||
}
|
||||
|
||||
-void* GetLibGdkPixbuf() {
|
||||
- static void* libgdk_pixbuf = DlOpen("libgdk_pixbuf-2.0.so.0");
|
||||
- return libgdk_pixbuf;
|
||||
-}
|
||||
-
|
||||
void* GetLibGdk3() {
|
||||
static void* libgdk3 = DlOpen("libgdk-3.so.0");
|
||||
return libgdk3;
|
||||
@@ -86,12 +81,6 @@ void* GetLibGtk4(bool check = true) {
|
||||
return libgtk4;
|
||||
}
|
||||
|
||||
@@ -23,10 +35,15 @@ index b5c7af5bdb93b320f95252d35d2d76bae7f8c445..40b706ed7cde206e9827402514860476
|
||||
bool LoadGtk3() {
|
||||
if (!GetLibGtk3(false))
|
||||
return false;
|
||||
@@ -134,6 +128,12 @@ gfx::Insets InsetsFromGtkBorder(const GtkBorder& border) {
|
||||
@@ -134,6 +123,17 @@ gfx::Insets InsetsFromGtkBorder(const GtkBorder& border) {
|
||||
|
||||
} // namespace
|
||||
|
||||
+void* GetLibGdkPixbuf() {
|
||||
+ static void* libgdk_pixbuf = DlOpen("libgdk_pixbuf-2.0.so.0");
|
||||
+ return libgdk_pixbuf;
|
||||
+}
|
||||
+
|
||||
+void* GetLibGtk() {
|
||||
+ if (GtkCheckVersion(4))
|
||||
+ return GetLibGtk4();
|
||||
@@ -37,13 +54,16 @@ index b5c7af5bdb93b320f95252d35d2d76bae7f8c445..40b706ed7cde206e9827402514860476
|
||||
static bool loaded = LoadGtkImpl();
|
||||
return loaded;
|
||||
diff --git a/ui/gtk/gtk_compat.h b/ui/gtk/gtk_compat.h
|
||||
index 57e55b9e749b43d327deff449a530e1f435a8e8b..2245974f91be4a691d82f54b55e12e44ae2000c5 100644
|
||||
index 57e55b9e749b43d327deff449a530e1f435a8e8b..37720be9e393d192b3b7db13a007431a9ce77ddc 100644
|
||||
--- a/ui/gtk/gtk_compat.h
|
||||
+++ b/ui/gtk/gtk_compat.h
|
||||
@@ -34,6 +34,9 @@ using SkColor = uint32_t;
|
||||
@@ -34,6 +34,12 @@ using SkColor = uint32_t;
|
||||
|
||||
namespace gtk {
|
||||
|
||||
+// Get handle to the currently loaded gdk_pixbuf library in the process.
|
||||
+void* GetLibGdkPixbuf();
|
||||
+
|
||||
+// Get handle to the currently loaded gtk library in the process.
|
||||
+void* GetLibGtk();
|
||||
+
|
||||
|
||||
@@ -10,9 +10,9 @@
|
||||
"Tarball": "debian_bullseye_arm_sysroot.tar.xz"
|
||||
},
|
||||
"bullseye_arm64": {
|
||||
"Sha1Sum": "de38cc85d51a820c3307e1937f3c2d3cedcce988",
|
||||
"Sha1Sum": "5a56c1ef714154ea5003bcafb16f21b0f8dde023",
|
||||
"SysrootDir": "debian_bullseye_arm64-sysroot",
|
||||
"Tarball": "debian_bullseye_arm64_sysroot.tar.xz"
|
||||
"Tarball": "debian_sid_arm64_sysroot.tar.xz"
|
||||
},
|
||||
"bullseye_armel": {
|
||||
"Sha1Sum": "db15aab39af3cfbc55a8ff0386943db1b78a1eab",
|
||||
|
||||
@@ -28,6 +28,7 @@
|
||||
#include "chrome/browser/ui/exclusive_access/exclusive_access_manager.h"
|
||||
#include "chrome/browser/ui/views/eye_dropper/eye_dropper.h"
|
||||
#include "chrome/common/pref_names.h"
|
||||
#include "components/embedder_support/user_agent_utils.h"
|
||||
#include "components/prefs/pref_service.h"
|
||||
#include "components/prefs/scoped_user_pref_update.h"
|
||||
#include "components/security_state/content/content_utils.h"
|
||||
@@ -659,9 +660,10 @@ WebContents::WebContents(v8::Isolate* isolate,
|
||||
auto session = Session::CreateFrom(isolate, GetBrowserContext());
|
||||
session_.Reset(isolate, session.ToV8());
|
||||
|
||||
web_contents->SetUserAgentOverride(blink::UserAgentOverride::UserAgentOnly(
|
||||
GetBrowserContext()->GetUserAgent()),
|
||||
false);
|
||||
absl::optional<std::string> user_agent_override =
|
||||
GetBrowserContext()->GetUserAgentOverride();
|
||||
if (user_agent_override)
|
||||
SetUserAgent(*user_agent_override);
|
||||
web_contents->SetUserData(kElectronApiWebContentsKey,
|
||||
std::make_unique<UserDataLink>(GetWeakPtr()));
|
||||
InitZoomController(web_contents, gin::Dictionary::CreateEmpty(isolate));
|
||||
@@ -867,9 +869,10 @@ void WebContents::InitWithSessionAndOptions(
|
||||
|
||||
AutofillDriverFactory::CreateForWebContents(web_contents());
|
||||
|
||||
web_contents()->SetUserAgentOverride(blink::UserAgentOverride::UserAgentOnly(
|
||||
GetBrowserContext()->GetUserAgent()),
|
||||
false);
|
||||
absl::optional<std::string> user_agent_override =
|
||||
GetBrowserContext()->GetUserAgentOverride();
|
||||
if (user_agent_override)
|
||||
SetUserAgent(*user_agent_override);
|
||||
|
||||
if (IsGuest()) {
|
||||
NativeWindow* owner_window = nullptr;
|
||||
@@ -2150,8 +2153,7 @@ void WebContents::LoadURL(const GURL& url,
|
||||
|
||||
std::string user_agent;
|
||||
if (options.Get("userAgent", &user_agent))
|
||||
web_contents()->SetUserAgentOverride(
|
||||
blink::UserAgentOverride::UserAgentOnly(user_agent), false);
|
||||
SetUserAgent(user_agent);
|
||||
|
||||
std::string extra_headers;
|
||||
if (options.Get("extraHeaders", &extra_headers))
|
||||
@@ -2366,8 +2368,12 @@ void WebContents::ForcefullyCrashRenderer() {
|
||||
}
|
||||
|
||||
void WebContents::SetUserAgent(const std::string& user_agent) {
|
||||
web_contents()->SetUserAgentOverride(
|
||||
blink::UserAgentOverride::UserAgentOnly(user_agent), false);
|
||||
blink::UserAgentOverride ua_override;
|
||||
ua_override.ua_string_override = user_agent;
|
||||
if (!user_agent.empty())
|
||||
ua_override.ua_metadata_override = embedder_support::GetUserAgentMetadata();
|
||||
|
||||
web_contents()->SetUserAgentOverride(ua_override, false);
|
||||
}
|
||||
|
||||
std::string WebContents::GetUserAgent() {
|
||||
|
||||
@@ -30,6 +30,7 @@
|
||||
#include "chrome/common/chrome_paths.h"
|
||||
#include "chrome/common/chrome_switches.h"
|
||||
#include "chrome/common/chrome_version.h"
|
||||
#include "components/embedder_support/user_agent_utils.h"
|
||||
#include "components/net_log/chrome_net_log.h"
|
||||
#include "components/network_hints/common/network_hints.mojom.h"
|
||||
#include "content/browser/keyboard_lock/keyboard_lock_service_impl.h" // nogncheck
|
||||
@@ -496,11 +497,6 @@ void ElectronBrowserClient::OverrideWebkitPrefs(
|
||||
? blink::mojom::PreferredColorScheme::kDark
|
||||
: blink::mojom::PreferredColorScheme::kLight;
|
||||
|
||||
auto preloads =
|
||||
SessionPreferences::GetValidPreloads(web_contents->GetBrowserContext());
|
||||
if (!preloads.empty())
|
||||
prefs->preloads = preloads;
|
||||
|
||||
SetFontDefaults(prefs);
|
||||
|
||||
// Custom preferences of guest page.
|
||||
@@ -1159,6 +1155,10 @@ void ElectronBrowserClient::SetUserAgent(const std::string& user_agent) {
|
||||
user_agent_override_ = user_agent;
|
||||
}
|
||||
|
||||
blink::UserAgentMetadata ElectronBrowserClient::GetUserAgentMetadata() {
|
||||
return embedder_support::GetUserAgentMetadata();
|
||||
}
|
||||
|
||||
void ElectronBrowserClient::RegisterNonNetworkNavigationURLLoaderFactories(
|
||||
int frame_tree_node_id,
|
||||
ukm::SourceIdObj ukm_source_id,
|
||||
|
||||
@@ -93,6 +93,7 @@ class ElectronBrowserClient : public content::ContentBrowserClient,
|
||||
|
||||
std::string GetUserAgent() override;
|
||||
void SetUserAgent(const std::string& user_agent);
|
||||
blink::UserAgentMetadata GetUserAgentMetadata() override;
|
||||
|
||||
content::SerialDelegate* GetSerialDelegate() override;
|
||||
|
||||
|
||||
@@ -107,8 +107,6 @@ ElectronBrowserContext::ElectronBrowserContext(const std::string& partition,
|
||||
protocol_registry_(base::WrapUnique(new ProtocolRegistry)),
|
||||
in_memory_(in_memory),
|
||||
ssl_config_(network::mojom::SSLConfig::New()) {
|
||||
user_agent_ = ElectronBrowserClient::Get()->GetUserAgent();
|
||||
|
||||
// Read options.
|
||||
base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
|
||||
use_cache_ = !command_line->HasSwitch(switches::kDisableHttpCache);
|
||||
@@ -305,6 +303,11 @@ ElectronBrowserContext::GetSpecialStoragePolicy() {
|
||||
}
|
||||
|
||||
std::string ElectronBrowserContext::GetUserAgent() const {
|
||||
return user_agent_.value_or(ElectronBrowserClient::Get()->GetUserAgent());
|
||||
}
|
||||
|
||||
absl::optional<std::string> ElectronBrowserContext::GetUserAgentOverride()
|
||||
const {
|
||||
return user_agent_;
|
||||
}
|
||||
|
||||
|
||||
@@ -85,6 +85,7 @@ class ElectronBrowserContext : public content::BrowserContext {
|
||||
|
||||
void SetUserAgent(const std::string& user_agent);
|
||||
std::string GetUserAgent() const;
|
||||
absl::optional<std::string> GetUserAgentOverride() const;
|
||||
bool CanUseHttpCache() const;
|
||||
int GetMaxCacheSize() const;
|
||||
ResolveProxyHelper* GetResolveProxyHelper();
|
||||
@@ -170,7 +171,7 @@ class ElectronBrowserContext : public content::BrowserContext {
|
||||
std::unique_ptr<predictors::PreconnectManager> preconnect_manager_;
|
||||
std::unique_ptr<ProtocolRegistry> protocol_registry_;
|
||||
|
||||
std::string user_agent_;
|
||||
absl::optional<std::string> user_agent_;
|
||||
base::FilePath path_;
|
||||
bool in_memory_ = false;
|
||||
bool use_cache_ = true;
|
||||
|
||||
@@ -371,6 +371,10 @@ void ElectronBrowserMainParts::ToolkitInitialized() {
|
||||
electron::UninitializeElectron_gtk();
|
||||
}
|
||||
|
||||
electron::InitializeElectron_gdk_pixbuf(gtk::GetLibGdkPixbuf());
|
||||
CHECK(electron::IsElectron_gdk_pixbufInitialized())
|
||||
<< "Failed to initialize libgdk_pixbuf-2.0.so.0";
|
||||
|
||||
// Chromium does not respect GTK dark theme setting, but they may change
|
||||
// in future and this code might be no longer needed. Check the Chromium
|
||||
// issue to keep updated:
|
||||
|
||||
@@ -27,6 +27,9 @@ void NativeBrowserViewViews::SetAutoResizeFlags(uint8_t flags) {
|
||||
|
||||
void NativeBrowserViewViews::UpdateDraggableRegions(
|
||||
const std::vector<mojom::DraggableRegionPtr>& regions) {
|
||||
if (&draggable_regions_ != ®ions)
|
||||
draggable_regions_ = mojo::Clone(regions);
|
||||
|
||||
// We need to snap the regions to the bounds of the current BrowserView.
|
||||
// For example, if an attached BrowserView is draggable but its bounds are
|
||||
// { x: 200, y: 100, width: 300, height: 300 }
|
||||
@@ -35,12 +38,10 @@ void NativeBrowserViewViews::UpdateDraggableRegions(
|
||||
// assumed that the regions begin in the top left corner as they
|
||||
// would for the main client window.
|
||||
auto const offset = GetBounds().OffsetFromOrigin();
|
||||
auto snapped_regions = mojo::Clone(regions);
|
||||
for (auto& snapped_region : snapped_regions) {
|
||||
for (auto& snapped_region : draggable_regions_) {
|
||||
snapped_region->bounds.Offset(offset);
|
||||
}
|
||||
|
||||
draggable_region_ = DraggableRegionsToSkRegion(snapped_regions);
|
||||
draggable_region_ = DraggableRegionsToSkRegion(draggable_regions_);
|
||||
}
|
||||
|
||||
void NativeBrowserViewViews::SetAutoResizeProportions(
|
||||
@@ -128,6 +129,12 @@ void NativeBrowserViewViews::SetBounds(const gfx::Rect& bounds) {
|
||||
auto* view = iwc_view->GetView();
|
||||
view->SetBoundsRect(bounds);
|
||||
ResetAutoResizeProportions();
|
||||
|
||||
view->InvalidateLayout();
|
||||
view->SchedulePaint();
|
||||
|
||||
// Ensure draggable regions are properly updated to reflect new bounds.
|
||||
UpdateDraggableRegions(draggable_regions_);
|
||||
}
|
||||
|
||||
gfx::Rect NativeBrowserViewViews::GetBounds() {
|
||||
|
||||
@@ -165,6 +165,8 @@ class NativeWindowMac : public NativeWindow,
|
||||
|
||||
void UpdateVibrancyRadii(bool fullscreen);
|
||||
|
||||
void UpdateWindowOriginalFrame();
|
||||
|
||||
// Set the attribute of NSWindow while work around a bug of zoom button.
|
||||
bool HasStyleMask(NSUInteger flag) const;
|
||||
void SetStyleMask(bool on, NSUInteger flag);
|
||||
|
||||
@@ -451,7 +451,7 @@ NativeWindowMac::NativeWindowMac(const gin_helper::Dictionary& options,
|
||||
SetContentView(new views::View());
|
||||
AddContentViewLayers();
|
||||
|
||||
original_frame_ = [window_ frame];
|
||||
UpdateWindowOriginalFrame();
|
||||
original_level_ = [window_ level];
|
||||
}
|
||||
|
||||
@@ -613,7 +613,7 @@ void NativeWindowMac::Maximize() {
|
||||
|
||||
// Take note of the current window size
|
||||
if (IsNormal())
|
||||
original_frame_ = [window_ frame];
|
||||
UpdateWindowOriginalFrame();
|
||||
[window_ zoom:nil];
|
||||
|
||||
if (!is_visible) {
|
||||
@@ -657,7 +657,7 @@ void NativeWindowMac::Minimize() {
|
||||
|
||||
// Take note of the current window size
|
||||
if (IsNormal())
|
||||
original_frame_ = [window_ frame];
|
||||
UpdateWindowOriginalFrame();
|
||||
[window_ miniaturize:nil];
|
||||
}
|
||||
|
||||
@@ -701,7 +701,7 @@ void NativeWindowMac::SetFullScreen(bool fullscreen) {
|
||||
|
||||
// Take note of the current window size
|
||||
if (IsNormal())
|
||||
original_frame_ = [window_ frame];
|
||||
UpdateWindowOriginalFrame();
|
||||
|
||||
// This needs to be set here because it can be the case that
|
||||
// SetFullScreen is called by a user before windowWillEnterFullScreen
|
||||
@@ -737,6 +737,7 @@ void NativeWindowMac::SetBounds(const gfx::Rect& bounds, bool animate) {
|
||||
|
||||
[window_ setFrame:cocoa_bounds display:YES animate:animate];
|
||||
user_set_bounds_maximized_ = IsMaximized() ? true : false;
|
||||
UpdateWindowOriginalFrame();
|
||||
}
|
||||
|
||||
gfx::Rect NativeWindowMac::GetBounds() {
|
||||
@@ -1009,7 +1010,7 @@ void NativeWindowMac::SetSimpleFullScreen(bool simple_fullscreen) {
|
||||
|
||||
// Take note of the current window size and level
|
||||
if (IsNormal()) {
|
||||
original_frame_ = [window_ frame];
|
||||
UpdateWindowOriginalFrame();
|
||||
original_level_ = [window_ level];
|
||||
}
|
||||
|
||||
@@ -1406,6 +1407,10 @@ void NativeWindowMac::UpdateVibrancyRadii(bool fullscreen) {
|
||||
}
|
||||
}
|
||||
|
||||
void NativeWindowMac::UpdateWindowOriginalFrame() {
|
||||
original_frame_ = [window_ frame];
|
||||
}
|
||||
|
||||
void NativeWindowMac::SetVibrancy(const std::string& type) {
|
||||
NSVisualEffectView* vibrantView = [window_ vibrantView];
|
||||
|
||||
|
||||
@@ -50,8 +50,8 @@ END
|
||||
//
|
||||
|
||||
VS_VERSION_INFO VERSIONINFO
|
||||
FILEVERSION 20,0,0,4
|
||||
PRODUCTVERSION 20,0,0,4
|
||||
FILEVERSION 20,0,0,7
|
||||
PRODUCTVERSION 20,0,0,7
|
||||
FILEFLAGSMASK 0x3fL
|
||||
#ifdef _DEBUG
|
||||
FILEFLAGS 0x1L
|
||||
|
||||
@@ -203,6 +203,7 @@ using FullScreenTransitionState =
|
||||
// windowDidDeminiaturize
|
||||
level_ = [window level];
|
||||
shell_->SetWindowLevel(NSNormalWindowLevel);
|
||||
shell_->UpdateWindowOriginalFrame();
|
||||
}
|
||||
|
||||
- (void)windowDidMiniaturize:(NSNotification*)notification {
|
||||
|
||||
3
shell/browser/ui/electron_gdk_pixbuf.sigs
Normal file
3
shell/browser/ui/electron_gdk_pixbuf.sigs
Normal file
@@ -0,0 +1,3 @@
|
||||
GdkPixbuf* gdk_pixbuf_new(GdkColorspace colorspace, gboolean has_alpha, int bits_per_sample, int width, int height)
|
||||
GdkPixbuf* gdk_pixbuf_scale_simple(const GdkPixbuf* src, int dest_width, int dest_height, GdkInterpType interp_type)
|
||||
guchar* gdk_pixbuf_get_pixels(const GdkPixbuf* pixbuf)
|
||||
@@ -1 +1,2 @@
|
||||
#include <gtk/gtk.h>
|
||||
#include <gdk-pixbuf/gdk-pixbuf.h>
|
||||
#include <gtk/gtk.h>
|
||||
|
||||
@@ -4,4 +4,4 @@ void gtk_native_dialog_show(GtkNativeDialog* self);
|
||||
void gtk_native_dialog_hide(GtkNativeDialog* self);
|
||||
gint gtk_native_dialog_run(GtkNativeDialog* self);
|
||||
void gtk_native_dialog_destroy(GtkNativeDialog* self);
|
||||
GType gtk_native_dialog_get_type(void);
|
||||
GType gtk_native_dialog_get_type(void);
|
||||
|
||||
@@ -32,8 +32,11 @@ static const int kPreviewWidth = 256;
|
||||
static const int kPreviewHeight = 512;
|
||||
|
||||
std::string MakeCaseInsensitivePattern(const std::string& extension) {
|
||||
std::string pattern("*.");
|
||||
// If the extension is the "all files" extension, no change needed.
|
||||
if (extension == "*")
|
||||
return extension;
|
||||
|
||||
std::string pattern("*.");
|
||||
for (std::size_t i = 0, n = extension.size(); i < n; i++) {
|
||||
char ch = extension[i];
|
||||
if (!base::IsAsciiAlpha(ch)) {
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
|
||||
#include "base/no_destructor.h"
|
||||
#include "base/strings/string_number_conversions.h"
|
||||
#include "electron/electron_gtk_stubs.h"
|
||||
#include "third_party/skia/include/core/SkBitmap.h"
|
||||
#include "third_party/skia/include/core/SkColor.h"
|
||||
#include "third_party/skia/include/core/SkUnPreMultiply.h"
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
#include "base/no_destructor.h"
|
||||
#include "base/strings/string_util.h"
|
||||
#include "base/strings/utf_string_conversions.h"
|
||||
#include "electron/electron_gtk_stubs.h"
|
||||
#include "shell/browser/browser.h"
|
||||
#include "shell/browser/native_window_observer.h"
|
||||
#include "shell/browser/native_window_views.h"
|
||||
|
||||
@@ -7,13 +7,10 @@
|
||||
#include "base/win/windows_version.h"
|
||||
#include "electron/buildflags/buildflags.h"
|
||||
#include "shell/browser/ui/views/win_frame_view.h"
|
||||
#include "shell/browser/win/dark_mode.h"
|
||||
#include "ui/base/win/hwnd_metrics.h"
|
||||
#include "ui/base/win/shell.h"
|
||||
|
||||
#if BUILDFLAG(ENABLE_WIN_DARK_MODE_WINDOW_UI)
|
||||
#include "shell/browser/win/dark_mode.h"
|
||||
#endif
|
||||
|
||||
namespace electron {
|
||||
|
||||
ElectronDesktopWindowTreeHostWin::ElectronDesktopWindowTreeHostWin(
|
||||
@@ -29,14 +26,13 @@ bool ElectronDesktopWindowTreeHostWin::PreHandleMSG(UINT message,
|
||||
WPARAM w_param,
|
||||
LPARAM l_param,
|
||||
LRESULT* result) {
|
||||
#if BUILDFLAG(ENABLE_WIN_DARK_MODE_WINDOW_UI)
|
||||
if (message == WM_NCCREATE) {
|
||||
HWND const hwnd = GetAcceleratedWidget();
|
||||
auto const theme_source =
|
||||
ui::NativeTheme::GetInstanceForNativeUi()->theme_source();
|
||||
win::SetDarkModeForWindow(hwnd, theme_source);
|
||||
const bool dark_mode_supported = win::IsDarkModeSupported();
|
||||
if (dark_mode_supported && message == WM_NCCREATE) {
|
||||
win::SetDarkModeForWindow(GetAcceleratedWidget());
|
||||
ui::NativeTheme::GetInstanceForNativeUi()->AddObserver(this);
|
||||
} else if (dark_mode_supported && message == WM_DESTROY) {
|
||||
ui::NativeTheme::GetInstanceForNativeUi()->RemoveObserver(this);
|
||||
}
|
||||
#endif
|
||||
|
||||
return native_window_view_->PreHandleMSG(message, w_param, l_param, result);
|
||||
}
|
||||
@@ -99,4 +95,9 @@ bool ElectronDesktopWindowTreeHostWin::GetClientAreaInsets(
|
||||
return false;
|
||||
}
|
||||
|
||||
void ElectronDesktopWindowTreeHostWin::OnNativeThemeUpdated(
|
||||
ui::NativeTheme* observed_theme) {
|
||||
win::SetDarkModeForWindow(GetAcceleratedWidget());
|
||||
}
|
||||
|
||||
} // namespace electron
|
||||
|
||||
@@ -12,8 +12,8 @@
|
||||
|
||||
namespace electron {
|
||||
|
||||
class ElectronDesktopWindowTreeHostWin
|
||||
: public views::DesktopWindowTreeHostWin {
|
||||
class ElectronDesktopWindowTreeHostWin : public views::DesktopWindowTreeHostWin,
|
||||
public ::ui::NativeThemeObserver {
|
||||
public:
|
||||
ElectronDesktopWindowTreeHostWin(
|
||||
NativeWindowViews* native_window_view,
|
||||
@@ -37,6 +37,9 @@ class ElectronDesktopWindowTreeHostWin
|
||||
bool GetClientAreaInsets(gfx::Insets* insets,
|
||||
HMONITOR monitor) const override;
|
||||
|
||||
// ui::NativeThemeObserver:
|
||||
void OnNativeThemeUpdated(ui::NativeTheme* observed_theme) override;
|
||||
|
||||
private:
|
||||
NativeWindowViews* native_window_view_; // weak ref
|
||||
};
|
||||
|
||||
@@ -486,10 +486,6 @@ void WebContentsPreferences::OverrideWebkitPrefs(
|
||||
|
||||
prefs->offscreen = offscreen_;
|
||||
|
||||
// The preload script.
|
||||
if (preload_path_)
|
||||
prefs->preload = *preload_path_;
|
||||
|
||||
prefs->node_integration = node_integration_;
|
||||
prefs->node_integration_in_worker = node_integration_in_worker_;
|
||||
prefs->node_integration_in_sub_frames = node_integration_in_sub_frames_;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright (c) 2020 Microsoft Inc. All rights reserved.
|
||||
// Copyright (c) 2022 Microsoft Inc. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE-CHROMIUM file.
|
||||
|
||||
@@ -6,173 +6,57 @@
|
||||
|
||||
#include <dwmapi.h> // DwmSetWindowAttribute()
|
||||
|
||||
#include "base/files/file_path.h"
|
||||
#include "base/scoped_native_library.h"
|
||||
#include "base/win/pe_image.h"
|
||||
#include "base/win/win_util.h"
|
||||
#include "base/win/windows_version.h"
|
||||
|
||||
// This flag works since Win10 20H1 but is not documented until Windows 11
|
||||
#define DWMWA_USE_IMMERSIVE_DARK_MODE 20
|
||||
|
||||
// This namespace contains code originally from
|
||||
// https://github.com/ysc3839/win32-darkmode/
|
||||
// governed by the MIT license and (c) Richard Yu
|
||||
// https://github.com/microsoft/terminal
|
||||
// governed by the MIT license and (c) Microsoft Corporation.
|
||||
namespace {
|
||||
|
||||
// 1903 18362
|
||||
enum PreferredAppMode { Default, AllowDark, ForceDark, ForceLight, Max };
|
||||
// https://docs.microsoft.com/en-us/windows/win32/api/dwmapi/ne-dwmapi-dwmwindowattribute
|
||||
HRESULT TrySetWindowTheme(HWND hWnd, bool dark) {
|
||||
const BOOL isDarkMode = dark;
|
||||
HRESULT result = DwmSetWindowAttribute(hWnd, DWMWA_USE_IMMERSIVE_DARK_MODE,
|
||||
&isDarkMode, sizeof(isDarkMode));
|
||||
|
||||
bool g_darkModeSupported = false;
|
||||
bool g_darkModeEnabled = false;
|
||||
DWORD g_buildNumber = 0;
|
||||
if (FAILED(result))
|
||||
return result;
|
||||
|
||||
enum WINDOWCOMPOSITIONATTRIB {
|
||||
WCA_USEDARKMODECOLORS = 26 // build 18875+
|
||||
};
|
||||
struct WINDOWCOMPOSITIONATTRIBDATA {
|
||||
WINDOWCOMPOSITIONATTRIB Attrib;
|
||||
PVOID pvData;
|
||||
SIZE_T cbData;
|
||||
};
|
||||
|
||||
using fnSetWindowCompositionAttribute =
|
||||
BOOL(WINAPI*)(HWND hWnd, WINDOWCOMPOSITIONATTRIBDATA*);
|
||||
fnSetWindowCompositionAttribute _SetWindowCompositionAttribute = nullptr;
|
||||
|
||||
bool IsHighContrast() {
|
||||
HIGHCONTRASTW highContrast = {sizeof(highContrast)};
|
||||
if (SystemParametersInfoW(SPI_GETHIGHCONTRAST, sizeof(highContrast),
|
||||
&highContrast, FALSE))
|
||||
return highContrast.dwFlags & HCF_HIGHCONTRASTON;
|
||||
return false;
|
||||
}
|
||||
|
||||
void RefreshTitleBarThemeColor(HWND hWnd, bool dark) {
|
||||
LONG ldark = dark;
|
||||
if (g_buildNumber >= 20161) {
|
||||
// DWMA_USE_IMMERSIVE_DARK_MODE = 20
|
||||
DwmSetWindowAttribute(hWnd, 20, &ldark, sizeof dark);
|
||||
return;
|
||||
}
|
||||
if (g_buildNumber >= 18363) {
|
||||
auto data = WINDOWCOMPOSITIONATTRIBDATA{WCA_USEDARKMODECOLORS, &ldark,
|
||||
sizeof ldark};
|
||||
_SetWindowCompositionAttribute(hWnd, &data);
|
||||
return;
|
||||
}
|
||||
DwmSetWindowAttribute(hWnd, 0x13, &ldark, sizeof ldark);
|
||||
}
|
||||
|
||||
void InitDarkMode() {
|
||||
// confirm that we're running on a version of Windows
|
||||
// where the Dark Mode API is known
|
||||
auto* os_info = base::win::OSInfo::GetInstance();
|
||||
g_buildNumber = os_info->version_number().build;
|
||||
auto const version = os_info->version();
|
||||
if ((version < base::win::Version::WIN10_RS5) ||
|
||||
(version > base::win::Version::WIN10_20H1)) {
|
||||
return;
|
||||
|
||||
// Toggle the nonclient area active state to force a redraw (Win10 workaround)
|
||||
if (version < base::win::Version::WIN11) {
|
||||
HWND activeWindow = GetActiveWindow();
|
||||
SendMessage(hWnd, WM_NCACTIVATE, hWnd != activeWindow, 0);
|
||||
SendMessage(hWnd, WM_NCACTIVATE, hWnd == activeWindow, 0);
|
||||
}
|
||||
|
||||
// load "SetWindowCompositionAttribute", used in RefreshTitleBarThemeColor()
|
||||
_SetWindowCompositionAttribute =
|
||||
reinterpret_cast<decltype(_SetWindowCompositionAttribute)>(
|
||||
base::win::GetUser32FunctionPointer("SetWindowCompositionAttribute"));
|
||||
if (_SetWindowCompositionAttribute == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
// load the dark mode functions from uxtheme.dll
|
||||
// * RefreshImmersiveColorPolicyState()
|
||||
// * ShouldAppsUseDarkMode()
|
||||
// * AllowDarkModeForApp()
|
||||
// * SetPreferredAppMode()
|
||||
// * AllowDarkModeForApp() (build < 18362)
|
||||
// * SetPreferredAppMode() (build >= 18362)
|
||||
|
||||
base::NativeLibrary uxtheme =
|
||||
base::PinSystemLibrary(FILE_PATH_LITERAL("uxtheme.dll"));
|
||||
if (!uxtheme) {
|
||||
return;
|
||||
}
|
||||
auto ux_pei = base::win::PEImage(uxtheme);
|
||||
auto get_ux_proc_from_ordinal = [&ux_pei](int ordinal, auto* setme) {
|
||||
FARPROC proc = ux_pei.GetProcAddress(reinterpret_cast<LPCSTR>(ordinal));
|
||||
*setme = reinterpret_cast<decltype(*setme)>(proc);
|
||||
};
|
||||
|
||||
// ordinal 104
|
||||
using fnRefreshImmersiveColorPolicyState = VOID(WINAPI*)();
|
||||
fnRefreshImmersiveColorPolicyState _RefreshImmersiveColorPolicyState = {};
|
||||
get_ux_proc_from_ordinal(104, &_RefreshImmersiveColorPolicyState);
|
||||
|
||||
// ordinal 132
|
||||
using fnShouldAppsUseDarkMode = BOOL(WINAPI*)();
|
||||
fnShouldAppsUseDarkMode _ShouldAppsUseDarkMode = {};
|
||||
get_ux_proc_from_ordinal(132, &_ShouldAppsUseDarkMode);
|
||||
|
||||
// ordinal 135, in 1809
|
||||
using fnAllowDarkModeForApp = BOOL(WINAPI*)(BOOL allow);
|
||||
fnAllowDarkModeForApp _AllowDarkModeForApp = {};
|
||||
|
||||
// ordinal 135, in 1903
|
||||
typedef PreferredAppMode(WINAPI *
|
||||
fnSetPreferredAppMode)(PreferredAppMode appMode);
|
||||
fnSetPreferredAppMode _SetPreferredAppMode = {};
|
||||
|
||||
if (g_buildNumber < 18362) {
|
||||
get_ux_proc_from_ordinal(135, &_AllowDarkModeForApp);
|
||||
} else {
|
||||
get_ux_proc_from_ordinal(135, &_SetPreferredAppMode);
|
||||
}
|
||||
|
||||
// dark mode is supported iff we found the functions
|
||||
g_darkModeSupported = _RefreshImmersiveColorPolicyState &&
|
||||
_ShouldAppsUseDarkMode &&
|
||||
(_AllowDarkModeForApp || _SetPreferredAppMode);
|
||||
if (!g_darkModeSupported) {
|
||||
return;
|
||||
}
|
||||
|
||||
// initial setup: allow dark mode to be used
|
||||
if (_AllowDarkModeForApp) {
|
||||
_AllowDarkModeForApp(true);
|
||||
} else if (_SetPreferredAppMode) {
|
||||
_SetPreferredAppMode(AllowDark);
|
||||
}
|
||||
_RefreshImmersiveColorPolicyState();
|
||||
|
||||
// check to see if dark mode is currently enabled
|
||||
g_darkModeEnabled = _ShouldAppsUseDarkMode() && !IsHighContrast();
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
namespace electron {
|
||||
|
||||
void EnsureInitialized() {
|
||||
static bool initialized = false;
|
||||
if (!initialized) {
|
||||
initialized = true;
|
||||
::InitDarkMode();
|
||||
}
|
||||
}
|
||||
|
||||
bool IsDarkPreferred(ui::NativeTheme::ThemeSource theme_source) {
|
||||
switch (theme_source) {
|
||||
case ui::NativeTheme::ThemeSource::kForcedLight:
|
||||
return false;
|
||||
case ui::NativeTheme::ThemeSource::kForcedDark:
|
||||
return g_darkModeSupported;
|
||||
case ui::NativeTheme::ThemeSource::kSystem:
|
||||
return g_darkModeEnabled;
|
||||
}
|
||||
}
|
||||
|
||||
namespace win {
|
||||
|
||||
void SetDarkModeForWindow(HWND hWnd,
|
||||
ui::NativeTheme::ThemeSource theme_source) {
|
||||
EnsureInitialized();
|
||||
RefreshTitleBarThemeColor(hWnd, IsDarkPreferred(theme_source));
|
||||
bool IsDarkModeSupported() {
|
||||
auto* os_info = base::win::OSInfo::GetInstance();
|
||||
auto const version = os_info->version();
|
||||
|
||||
return version >= base::win::Version::WIN10_20H1;
|
||||
}
|
||||
|
||||
void SetDarkModeForWindow(HWND hWnd) {
|
||||
ui::NativeTheme* theme = ui::NativeTheme::GetInstanceForNativeUi();
|
||||
bool dark =
|
||||
theme->ShouldUseDarkColors() && !theme->UserHasContrastPreference();
|
||||
|
||||
TrySetWindowTheme(hWnd, dark);
|
||||
}
|
||||
|
||||
} // namespace win
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright (c) 2020 Microsoft Inc. All rights reserved.
|
||||
// Copyright (c) 2022 Microsoft Inc. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE-CHROMIUM file.
|
||||
|
||||
@@ -19,7 +19,8 @@ namespace electron {
|
||||
|
||||
namespace win {
|
||||
|
||||
void SetDarkModeForWindow(HWND hWnd, ui::NativeTheme::ThemeSource theme_source);
|
||||
bool IsDarkModeSupported();
|
||||
void SetDarkModeForWindow(HWND hWnd);
|
||||
|
||||
} // namespace win
|
||||
|
||||
|
||||
@@ -54,10 +54,6 @@ bool IsPictureInPictureEnabled() {
|
||||
return BUILDFLAG(ENABLE_PICTURE_IN_PICTURE);
|
||||
}
|
||||
|
||||
bool IsWinDarkModeWindowUiEnabled() {
|
||||
return BUILDFLAG(ENABLE_WIN_DARK_MODE_WINDOW_UI);
|
||||
}
|
||||
|
||||
bool IsComponentBuild() {
|
||||
#if defined(COMPONENT_BUILD)
|
||||
return true;
|
||||
@@ -84,7 +80,6 @@ void Initialize(v8::Local<v8::Object> exports,
|
||||
dict.SetMethod("isPictureInPictureEnabled", &IsPictureInPictureEnabled);
|
||||
dict.SetMethod("isComponentBuild", &IsComponentBuild);
|
||||
dict.SetMethod("isExtensionsEnabled", &IsExtensionsEnabled);
|
||||
dict.SetMethod("isWinDarkModeWindowUiEnabled", &IsWinDarkModeWindowUiEnabled);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
@@ -496,9 +496,7 @@ class WebFrameRenderer : public gin::Wrappable<WebFrameRenderer>,
|
||||
|
||||
const auto& prefs = render_frame->GetBlinkPreferences();
|
||||
|
||||
if (pref_name == options::kPreloadScripts) {
|
||||
return gin::ConvertToV8(isolate, prefs.preloads);
|
||||
} else if (pref_name == "isWebView") {
|
||||
if (pref_name == "isWebView") {
|
||||
// FIXME(zcbenz): For child windows opened with window.open('') from
|
||||
// webview, the WebPreferences is inherited from webview and the value
|
||||
// of |is_webview| is wrong.
|
||||
@@ -513,8 +511,6 @@ class WebFrameRenderer : public gin::Wrappable<WebFrameRenderer>,
|
||||
return gin::ConvertToV8(isolate, prefs.hidden_page);
|
||||
} else if (pref_name == options::kOffscreen) {
|
||||
return gin::ConvertToV8(isolate, prefs.offscreen);
|
||||
} else if (pref_name == options::kPreloadScript) {
|
||||
return gin::ConvertToV8(isolate, prefs.preload.value());
|
||||
} else if (pref_name == options::kNodeIntegration) {
|
||||
return gin::ConvertToV8(isolate, prefs.node_integration);
|
||||
} else if (pref_name == options::kNodeIntegrationInWorker) {
|
||||
|
||||
@@ -24,15 +24,6 @@
|
||||
|
||||
namespace electron {
|
||||
|
||||
namespace {
|
||||
|
||||
bool IsDevToolsExtension(content::RenderFrame* render_frame) {
|
||||
return static_cast<GURL>(render_frame->GetWebFrame()->GetDocument().Url())
|
||||
.SchemeIs("chrome-extension");
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
ElectronRendererClient::ElectronRendererClient()
|
||||
: node_bindings_(
|
||||
NodeBindings::Create(NodeBindings::BrowserEnvironment::kRenderer)),
|
||||
@@ -77,15 +68,7 @@ void ElectronRendererClient::DidCreateScriptContext(
|
||||
|
||||
// Only load Node.js if we are a main frame or a devtools extension
|
||||
// unless Node.js support has been explicitly enabled for subframes.
|
||||
auto prefs = render_frame->GetBlinkPreferences();
|
||||
bool is_main_frame = render_frame->IsMainFrame();
|
||||
bool is_devtools = IsDevToolsExtension(render_frame);
|
||||
bool allow_node_in_subframes = prefs.node_integration_in_sub_frames;
|
||||
|
||||
bool should_load_node =
|
||||
(is_main_frame || is_devtools || allow_node_in_subframes) &&
|
||||
!IsWebViewFrame(renderer_context, render_frame);
|
||||
if (!should_load_node)
|
||||
if (!ShouldLoadPreload(renderer_context, render_frame))
|
||||
return;
|
||||
|
||||
injected_frames_.insert(render_frame);
|
||||
|
||||
@@ -36,16 +36,6 @@ namespace {
|
||||
const char kLifecycleKey[] = "lifecycle";
|
||||
const char kModuleCacheKey[] = "native-module-cache";
|
||||
|
||||
bool IsDevTools(content::RenderFrame* render_frame) {
|
||||
return render_frame->GetWebFrame()->GetDocument().Url().ProtocolIs(
|
||||
"devtools");
|
||||
}
|
||||
|
||||
bool IsDevToolsExtension(content::RenderFrame* render_frame) {
|
||||
return render_frame->GetWebFrame()->GetDocument().Url().ProtocolIs(
|
||||
"chrome-extension");
|
||||
}
|
||||
|
||||
v8::Local<v8::Object> GetModuleCache(v8::Isolate* isolate) {
|
||||
auto context = isolate->GetCurrentContext();
|
||||
gin_helper::Dictionary global(isolate, context->Global());
|
||||
@@ -207,17 +197,7 @@ void ElectronSandboxedRendererClient::DidCreateScriptContext(
|
||||
// Only allow preload for the main frame or
|
||||
// For devtools we still want to run the preload_bundle script
|
||||
// Or when nodeSupport is explicitly enabled in sub frames
|
||||
bool is_main_frame = render_frame->IsMainFrame();
|
||||
bool is_devtools =
|
||||
IsDevTools(render_frame) || IsDevToolsExtension(render_frame);
|
||||
|
||||
bool allow_node_in_sub_frames =
|
||||
render_frame->GetBlinkPreferences().node_integration_in_sub_frames;
|
||||
|
||||
bool should_load_preload =
|
||||
(is_main_frame || is_devtools || allow_node_in_sub_frames) &&
|
||||
!IsWebViewFrame(context, render_frame);
|
||||
if (!should_load_preload)
|
||||
if (!ShouldLoadPreload(context, render_frame))
|
||||
return;
|
||||
|
||||
injected_frames_.insert(render_frame);
|
||||
|
||||
@@ -134,6 +134,16 @@ class ChromePdfInternalPluginDelegate final
|
||||
// static
|
||||
RendererClientBase* g_renderer_client_base = nullptr;
|
||||
|
||||
bool IsDevTools(content::RenderFrame* render_frame) {
|
||||
return render_frame->GetWebFrame()->GetDocument().Url().ProtocolIs(
|
||||
"devtools");
|
||||
}
|
||||
|
||||
bool IsDevToolsExtension(content::RenderFrame* render_frame) {
|
||||
return render_frame->GetWebFrame()->GetDocument().Url().ProtocolIs(
|
||||
"chrome-extension");
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
RendererClientBase::RendererClientBase() {
|
||||
@@ -196,6 +206,19 @@ void RendererClientBase::BindProcess(v8::Isolate* isolate,
|
||||
process->SetReadOnly("contextId", context_id);
|
||||
}
|
||||
|
||||
bool RendererClientBase::ShouldLoadPreload(
|
||||
v8::Handle<v8::Context> context,
|
||||
content::RenderFrame* render_frame) const {
|
||||
auto prefs = render_frame->GetBlinkPreferences();
|
||||
bool is_main_frame = render_frame->IsMainFrame();
|
||||
bool is_devtools =
|
||||
IsDevTools(render_frame) || IsDevToolsExtension(render_frame);
|
||||
bool allow_node_in_sub_frames = prefs.node_integration_in_sub_frames;
|
||||
|
||||
return (is_main_frame || is_devtools || allow_node_in_sub_frames) &&
|
||||
!IsWebViewFrame(context, render_frame);
|
||||
}
|
||||
|
||||
void RendererClientBase::RenderThreadStarted() {
|
||||
auto* command_line = base::CommandLine::ForCurrentProcess();
|
||||
|
||||
|
||||
@@ -93,6 +93,9 @@ class RendererClientBase : public content::ContentRendererClient
|
||||
gin_helper::Dictionary* process,
|
||||
content::RenderFrame* render_frame);
|
||||
|
||||
bool ShouldLoadPreload(v8::Handle<v8::Context> context,
|
||||
content::RenderFrame* render_frame) const;
|
||||
|
||||
// content::ContentRendererClient:
|
||||
void RenderThreadStarted() override;
|
||||
void ExposeInterfacesToBrowser(mojo::BinderMap* binders) override;
|
||||
|
||||
@@ -1228,6 +1228,7 @@ describe('BrowserWindow module', () => {
|
||||
await resize;
|
||||
expectBoundsEqual(w.getNormalBounds(), w.getBounds());
|
||||
});
|
||||
|
||||
it('checks normal bounds after move', async () => {
|
||||
const pos = [10, 10];
|
||||
const move = emittedOnce(w, 'move');
|
||||
@@ -1246,6 +1247,51 @@ describe('BrowserWindow module', () => {
|
||||
await maximize;
|
||||
expectBoundsEqual(w.getNormalBounds(), bounds);
|
||||
});
|
||||
|
||||
it('updates normal bounds after resize and maximize', async () => {
|
||||
const size = [300, 400];
|
||||
const resize = emittedOnce(w, 'resize');
|
||||
w.setSize(size[0], size[1]);
|
||||
await resize;
|
||||
const original = w.getBounds();
|
||||
|
||||
const maximize = emittedOnce(w, 'maximize');
|
||||
w.maximize();
|
||||
await maximize;
|
||||
|
||||
const normal = w.getNormalBounds();
|
||||
const bounds = w.getBounds();
|
||||
|
||||
expect(normal).to.deep.equal(original);
|
||||
expect(normal).to.not.deep.equal(bounds);
|
||||
|
||||
const close = emittedOnce(w, 'close');
|
||||
w.close();
|
||||
await close;
|
||||
});
|
||||
|
||||
it('updates normal bounds after move and maximize', async () => {
|
||||
const pos = [10, 10];
|
||||
const move = emittedOnce(w, 'move');
|
||||
w.setPosition(pos[0], pos[1]);
|
||||
await move;
|
||||
const original = w.getBounds();
|
||||
|
||||
const maximize = emittedOnce(w, 'maximize');
|
||||
w.maximize();
|
||||
await maximize;
|
||||
|
||||
const normal = w.getNormalBounds();
|
||||
const bounds = w.getBounds();
|
||||
|
||||
expect(normal).to.deep.equal(original);
|
||||
expect(normal).to.not.deep.equal(bounds);
|
||||
|
||||
const close = emittedOnce(w, 'close');
|
||||
w.close();
|
||||
await close;
|
||||
});
|
||||
|
||||
it('checks normal bounds when unmaximized', async () => {
|
||||
const bounds = w.getBounds();
|
||||
w.once('maximize', () => {
|
||||
@@ -1257,6 +1303,7 @@ describe('BrowserWindow module', () => {
|
||||
await unmaximize;
|
||||
expectBoundsEqual(w.getNormalBounds(), bounds);
|
||||
});
|
||||
|
||||
it('does not change size for a frameless window with min size', async () => {
|
||||
w.destroy();
|
||||
w = new BrowserWindow({
|
||||
@@ -1277,6 +1324,7 @@ describe('BrowserWindow module', () => {
|
||||
await unmaximize;
|
||||
expectBoundsEqual(w.getNormalBounds(), bounds);
|
||||
});
|
||||
|
||||
it('correctly checks transparent window maximization state', async () => {
|
||||
w.destroy();
|
||||
w = new BrowserWindow({
|
||||
@@ -1296,6 +1344,7 @@ describe('BrowserWindow module', () => {
|
||||
await unmaximize;
|
||||
expect(w.isMaximized()).to.equal(false);
|
||||
});
|
||||
|
||||
it('returns the correct value for windows with an aspect ratio', async () => {
|
||||
w.destroy();
|
||||
w = new BrowserWindow({
|
||||
@@ -1325,6 +1374,41 @@ describe('BrowserWindow module', () => {
|
||||
await minimize;
|
||||
expectBoundsEqual(w.getNormalBounds(), bounds);
|
||||
});
|
||||
|
||||
it('updates normal bounds after move and minimize', async () => {
|
||||
const pos = [10, 10];
|
||||
const move = emittedOnce(w, 'move');
|
||||
w.setPosition(pos[0], pos[1]);
|
||||
await move;
|
||||
const original = w.getBounds();
|
||||
|
||||
const minimize = emittedOnce(w, 'minimize');
|
||||
w.minimize();
|
||||
await minimize;
|
||||
|
||||
const normal = w.getNormalBounds();
|
||||
|
||||
expect(original).to.deep.equal(normal);
|
||||
expectBoundsEqual(normal, w.getBounds());
|
||||
});
|
||||
|
||||
it('updates normal bounds after resize and minimize', async () => {
|
||||
const size = [300, 400];
|
||||
const resize = emittedOnce(w, 'resize');
|
||||
w.setSize(size[0], size[1]);
|
||||
await resize;
|
||||
const original = w.getBounds();
|
||||
|
||||
const minimize = emittedOnce(w, 'minimize');
|
||||
w.minimize();
|
||||
await minimize;
|
||||
|
||||
const normal = w.getNormalBounds();
|
||||
|
||||
expect(original).to.deep.equal(normal);
|
||||
expectBoundsEqual(normal, w.getBounds());
|
||||
});
|
||||
|
||||
it('checks normal bounds when restored', async () => {
|
||||
const bounds = w.getBounds();
|
||||
w.once('minimize', () => {
|
||||
@@ -1336,6 +1420,7 @@ describe('BrowserWindow module', () => {
|
||||
await restore;
|
||||
expectBoundsEqual(w.getNormalBounds(), bounds);
|
||||
});
|
||||
|
||||
it('does not change size for a frameless window with min size', async () => {
|
||||
w.destroy();
|
||||
w = new BrowserWindow({
|
||||
@@ -1381,6 +1466,50 @@ describe('BrowserWindow module', () => {
|
||||
expectBoundsEqual(w.getNormalBounds(), bounds);
|
||||
});
|
||||
|
||||
it('updates normal bounds after resize and fullscreen', async () => {
|
||||
const size = [300, 400];
|
||||
const resize = emittedOnce(w, 'resize');
|
||||
w.setSize(size[0], size[1]);
|
||||
await resize;
|
||||
const original = w.getBounds();
|
||||
|
||||
const fsc = emittedOnce(w, 'enter-full-screen');
|
||||
w.fullScreen = true;
|
||||
await fsc;
|
||||
|
||||
const normal = w.getNormalBounds();
|
||||
const bounds = w.getBounds();
|
||||
|
||||
expect(normal).to.deep.equal(original);
|
||||
expect(normal).to.not.deep.equal(bounds);
|
||||
|
||||
const close = emittedOnce(w, 'close');
|
||||
w.close();
|
||||
await close;
|
||||
});
|
||||
|
||||
it('updates normal bounds after move and fullscreen', async () => {
|
||||
const pos = [10, 10];
|
||||
const move = emittedOnce(w, 'move');
|
||||
w.setPosition(pos[0], pos[1]);
|
||||
await move;
|
||||
const original = w.getBounds();
|
||||
|
||||
const fsc = emittedOnce(w, 'enter-full-screen');
|
||||
w.fullScreen = true;
|
||||
await fsc;
|
||||
|
||||
const normal = w.getNormalBounds();
|
||||
const bounds = w.getBounds();
|
||||
|
||||
expect(normal).to.deep.equal(original);
|
||||
expect(normal).to.not.deep.equal(bounds);
|
||||
|
||||
const close = emittedOnce(w, 'close');
|
||||
w.close();
|
||||
await close;
|
||||
});
|
||||
|
||||
it('checks normal bounds when unfullscreen\'ed', async () => {
|
||||
const bounds = w.getBounds();
|
||||
w.once('enter-full-screen', () => {
|
||||
@@ -1418,6 +1547,50 @@ describe('BrowserWindow module', () => {
|
||||
expectBoundsEqual(w.getNormalBounds(), bounds);
|
||||
});
|
||||
|
||||
it('updates normal bounds after resize and fullscreen', async () => {
|
||||
const size = [300, 400];
|
||||
const resize = emittedOnce(w, 'resize');
|
||||
w.setSize(size[0], size[1]);
|
||||
await resize;
|
||||
const original = w.getBounds();
|
||||
|
||||
const fsc = emittedOnce(w, 'enter-full-screen');
|
||||
w.setFullScreen(true);
|
||||
await fsc;
|
||||
|
||||
const normal = w.getNormalBounds();
|
||||
const bounds = w.getBounds();
|
||||
|
||||
expect(normal).to.deep.equal(original);
|
||||
expect(normal).to.not.deep.equal(bounds);
|
||||
|
||||
const close = emittedOnce(w, 'close');
|
||||
w.close();
|
||||
await close;
|
||||
});
|
||||
|
||||
it('updates normal bounds after move and fullscreen', async () => {
|
||||
const pos = [10, 10];
|
||||
const move = emittedOnce(w, 'move');
|
||||
w.setPosition(pos[0], pos[1]);
|
||||
await move;
|
||||
const original = w.getBounds();
|
||||
|
||||
const fsc = emittedOnce(w, 'enter-full-screen');
|
||||
w.setFullScreen(true);
|
||||
await fsc;
|
||||
|
||||
const normal = w.getNormalBounds();
|
||||
const bounds = w.getBounds();
|
||||
|
||||
expect(normal).to.deep.equal(original);
|
||||
expect(normal).to.not.deep.equal(bounds);
|
||||
|
||||
const close = emittedOnce(w, 'close');
|
||||
w.close();
|
||||
await close;
|
||||
});
|
||||
|
||||
it('checks normal bounds when unfullscreen\'ed', async () => {
|
||||
const bounds = w.getBounds();
|
||||
w.show();
|
||||
@@ -3090,7 +3263,15 @@ describe('BrowserWindow module', () => {
|
||||
});
|
||||
w.webContents.setWindowOpenHandler(() => ({
|
||||
action: 'allow',
|
||||
overrideBrowserWindowOptions: { show: false, webPreferences: { contextIsolation: false, webviewTag: true, nodeIntegrationInSubFrames: true } }
|
||||
overrideBrowserWindowOptions: {
|
||||
show: false,
|
||||
webPreferences: {
|
||||
contextIsolation: false,
|
||||
webviewTag: true,
|
||||
nodeIntegrationInSubFrames: true,
|
||||
preload
|
||||
}
|
||||
}
|
||||
}));
|
||||
w.webContents.once('new-window', (event, url, frameName, disposition, options) => {
|
||||
options.show = false;
|
||||
|
||||
@@ -1508,6 +1508,68 @@ describe('chromium features', () => {
|
||||
expect(focus).to.be.false();
|
||||
});
|
||||
});
|
||||
|
||||
describe('navigator.userAgentData', () => {
|
||||
// These tests are done on an http server because navigator.userAgentData
|
||||
// requires a secure context.
|
||||
let server: http.Server;
|
||||
let serverUrl: string;
|
||||
before(async () => {
|
||||
server = http.createServer((req, res) => {
|
||||
res.setHeader('Content-Type', 'text/html');
|
||||
res.end('');
|
||||
});
|
||||
await new Promise<void>(resolve => server.listen(0, '127.0.0.1', resolve));
|
||||
serverUrl = `http://localhost:${(server.address() as any).port}`;
|
||||
});
|
||||
after(() => {
|
||||
server.close();
|
||||
});
|
||||
|
||||
describe('is not empty', () => {
|
||||
it('by default', async () => {
|
||||
const w = new BrowserWindow({ show: false });
|
||||
await w.loadURL(serverUrl);
|
||||
const platform = await w.webContents.executeJavaScript('navigator.userAgentData.platform');
|
||||
expect(platform).not.to.be.empty();
|
||||
});
|
||||
|
||||
it('when there is a session-wide UA override', async () => {
|
||||
const ses = session.fromPartition(`${Math.random()}`);
|
||||
ses.setUserAgent('foobar');
|
||||
const w = new BrowserWindow({ show: false, webPreferences: { session: ses } });
|
||||
await w.loadURL(serverUrl);
|
||||
const platform = await w.webContents.executeJavaScript('navigator.userAgentData.platform');
|
||||
expect(platform).not.to.be.empty();
|
||||
});
|
||||
|
||||
it('when there is a WebContents-specific UA override', async () => {
|
||||
const w = new BrowserWindow({ show: false });
|
||||
w.webContents.setUserAgent('foo');
|
||||
await w.loadURL(serverUrl);
|
||||
const platform = await w.webContents.executeJavaScript('navigator.userAgentData.platform');
|
||||
expect(platform).not.to.be.empty();
|
||||
});
|
||||
|
||||
it('when there is a WebContents-specific UA override at load time', async () => {
|
||||
const w = new BrowserWindow({ show: false });
|
||||
await w.loadURL(serverUrl, {
|
||||
userAgent: 'foo'
|
||||
});
|
||||
const platform = await w.webContents.executeJavaScript('navigator.userAgentData.platform');
|
||||
expect(platform).not.to.be.empty();
|
||||
});
|
||||
});
|
||||
|
||||
describe('brand list', () => {
|
||||
it('contains chromium', async () => {
|
||||
const w = new BrowserWindow({ show: false });
|
||||
await w.loadURL(serverUrl);
|
||||
const brands = await w.webContents.executeJavaScript('navigator.userAgentData.brands');
|
||||
expect(brands.map((b: any) => b.brand)).to.include('Chromium');
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('font fallback', () => {
|
||||
|
||||
@@ -1,166 +0,0 @@
|
||||
[
|
||||
[
|
||||
"top=5,left=10,resizable=no",
|
||||
{
|
||||
"sender": "[WebContents]",
|
||||
"frameId": 1,
|
||||
"processId": "placeholder-process-id"
|
||||
},
|
||||
"about:blank",
|
||||
"frame-name",
|
||||
"new-window",
|
||||
{
|
||||
"show": true,
|
||||
"width": 800,
|
||||
"height": 600,
|
||||
"top": 5,
|
||||
"left": 10,
|
||||
"resizable": false,
|
||||
"x": 10,
|
||||
"y": 5,
|
||||
"webPreferences": {
|
||||
"contextIsolation": true,
|
||||
"nodeIntegration": false,
|
||||
"webviewTag": false,
|
||||
"nodeIntegrationInSubFrames": false
|
||||
},
|
||||
"webContents": "[WebContents]"
|
||||
},
|
||||
[],
|
||||
{
|
||||
"url": "",
|
||||
"policy": "strict-origin-when-cross-origin"
|
||||
},
|
||||
null
|
||||
],
|
||||
[
|
||||
"zoomFactor=2,resizable=0,x=0,y=10",
|
||||
{
|
||||
"sender": "[WebContents]",
|
||||
"frameId": 1,
|
||||
"processId": "placeholder-process-id"
|
||||
},
|
||||
"about:blank",
|
||||
"frame-name",
|
||||
"new-window",
|
||||
{
|
||||
"show": true,
|
||||
"width": 800,
|
||||
"height": 600,
|
||||
"resizable": false,
|
||||
"x": 0,
|
||||
"y": 10,
|
||||
"webPreferences": {
|
||||
"zoomFactor": "2",
|
||||
"contextIsolation": true,
|
||||
"nodeIntegration": false,
|
||||
"webviewTag": false,
|
||||
"nodeIntegrationInSubFrames": false
|
||||
},
|
||||
"webContents": "[WebContents]"
|
||||
},
|
||||
[],
|
||||
{
|
||||
"url": "",
|
||||
"policy": "strict-origin-when-cross-origin"
|
||||
},
|
||||
null
|
||||
],
|
||||
[
|
||||
"backgroundColor=gray,webPreferences=0,x=100,y=100",
|
||||
{
|
||||
"sender": "[WebContents]",
|
||||
"frameId": 1,
|
||||
"processId": "placeholder-process-id"
|
||||
},
|
||||
"about:blank",
|
||||
"frame-name",
|
||||
"new-window",
|
||||
{
|
||||
"show": true,
|
||||
"width": 800,
|
||||
"height": 600,
|
||||
"backgroundColor": "gray",
|
||||
"webPreferences": {
|
||||
"contextIsolation": true,
|
||||
"nodeIntegration": false,
|
||||
"webviewTag": false,
|
||||
"nodeIntegrationInSubFrames": false
|
||||
},
|
||||
"x": 100,
|
||||
"y": 100,
|
||||
"webContents": "[WebContents]"
|
||||
},
|
||||
[],
|
||||
{
|
||||
"url": "",
|
||||
"policy": "strict-origin-when-cross-origin"
|
||||
},
|
||||
null
|
||||
],
|
||||
[
|
||||
"x=50,y=20,title=sup",
|
||||
{
|
||||
"sender": "[WebContents]",
|
||||
"frameId": 1,
|
||||
"processId": "placeholder-process-id"
|
||||
},
|
||||
"about:blank",
|
||||
"frame-name",
|
||||
"new-window",
|
||||
{
|
||||
"show": true,
|
||||
"width": 800,
|
||||
"height": 600,
|
||||
"x": 50,
|
||||
"y": 20,
|
||||
"title": "sup",
|
||||
"webPreferences": {
|
||||
"contextIsolation": true,
|
||||
"nodeIntegration": false,
|
||||
"webviewTag": false,
|
||||
"nodeIntegrationInSubFrames": false
|
||||
},
|
||||
"webContents": "[WebContents]"
|
||||
},
|
||||
[],
|
||||
{
|
||||
"url": "",
|
||||
"policy": "strict-origin-when-cross-origin"
|
||||
},
|
||||
null
|
||||
],
|
||||
[
|
||||
"show=false,top=1,left=1",
|
||||
{
|
||||
"sender": "[WebContents]",
|
||||
"frameId": 1,
|
||||
"processId": "placeholder-process-id"
|
||||
},
|
||||
"about:blank",
|
||||
"frame-name",
|
||||
"new-window",
|
||||
{
|
||||
"show": false,
|
||||
"width": 800,
|
||||
"height": 600,
|
||||
"top": 1,
|
||||
"left": 1,
|
||||
"x": 1,
|
||||
"y": 1,
|
||||
"webPreferences": {
|
||||
"contextIsolation": true,
|
||||
"nodeIntegration": false,
|
||||
"webviewTag": false,
|
||||
"nodeIntegrationInSubFrames": false
|
||||
},
|
||||
"webContents": "[WebContents]"
|
||||
},
|
||||
[],
|
||||
{
|
||||
"url": "",
|
||||
"policy": "strict-origin-when-cross-origin"
|
||||
},
|
||||
null
|
||||
]
|
||||
]
|
||||
@@ -79,6 +79,58 @@ describe('webContents.setWindowOpenHandler', () => {
|
||||
|
||||
afterEach(closeAllWindows);
|
||||
|
||||
it('does not fire window creation events if the handler callback throws an error', (done) => {
|
||||
const error = new Error('oh no');
|
||||
const listeners = process.listeners('uncaughtException');
|
||||
process.removeAllListeners('uncaughtException');
|
||||
process.on('uncaughtException', (thrown) => {
|
||||
try {
|
||||
expect(thrown).to.equal(error);
|
||||
done();
|
||||
} catch (e) {
|
||||
done(e);
|
||||
} finally {
|
||||
process.removeAllListeners('uncaughtException');
|
||||
listeners.forEach((listener) => process.on('uncaughtException', listener));
|
||||
}
|
||||
});
|
||||
|
||||
browserWindow.webContents.on('new-window', () => {
|
||||
assert.fail('new-window should not be called with an overridden window.open');
|
||||
});
|
||||
|
||||
browserWindow.webContents.on('did-create-window', () => {
|
||||
assert.fail('did-create-window should not be called with an overridden window.open');
|
||||
});
|
||||
|
||||
browserWindow.webContents.executeJavaScript("window.open('about:blank', '', 'show=no') && true");
|
||||
|
||||
browserWindow.webContents.setWindowOpenHandler(() => {
|
||||
throw error;
|
||||
});
|
||||
});
|
||||
|
||||
it('does not fire window creation events if the handler callback returns a bad result', async () => {
|
||||
const bad = new Promise((resolve) => {
|
||||
browserWindow.webContents.setWindowOpenHandler(() => {
|
||||
setTimeout(resolve);
|
||||
return [1, 2, 3] as any;
|
||||
});
|
||||
});
|
||||
|
||||
browserWindow.webContents.on('new-window', () => {
|
||||
assert.fail('new-window should not be called with an overridden window.open');
|
||||
});
|
||||
|
||||
browserWindow.webContents.on('did-create-window', () => {
|
||||
assert.fail('did-create-window should not be called with an overridden window.open');
|
||||
});
|
||||
|
||||
browserWindow.webContents.executeJavaScript("window.open('about:blank', '', 'show=no') && true");
|
||||
|
||||
await bad;
|
||||
});
|
||||
|
||||
it('does not fire window creation events if an override returns action: deny', async () => {
|
||||
const denied = new Promise((resolve) => {
|
||||
browserWindow.webContents.setWindowOpenHandler(() => {
|
||||
@@ -87,11 +139,11 @@ describe('webContents.setWindowOpenHandler', () => {
|
||||
});
|
||||
});
|
||||
browserWindow.webContents.on('new-window', () => {
|
||||
assert.fail('new-window should not to be called with an overridden window.open');
|
||||
assert.fail('new-window should not be called with an overridden window.open');
|
||||
});
|
||||
|
||||
browserWindow.webContents.on('did-create-window', () => {
|
||||
assert.fail('did-create-window should not to be called with an overridden window.open');
|
||||
assert.fail('did-create-window should not be called with an overridden window.open');
|
||||
});
|
||||
|
||||
browserWindow.webContents.executeJavaScript("window.open('about:blank', '', 'show=no') && true");
|
||||
@@ -107,11 +159,11 @@ describe('webContents.setWindowOpenHandler', () => {
|
||||
});
|
||||
});
|
||||
browserWindow.webContents.on('new-window', () => {
|
||||
assert.fail('new-window should not to be called with an overridden window.open');
|
||||
assert.fail('new-window should not be called with an overridden window.open');
|
||||
});
|
||||
|
||||
browserWindow.webContents.on('did-create-window', () => {
|
||||
assert.fail('did-create-window should not to be called with an overridden window.open');
|
||||
assert.fail('did-create-window should not be called with an overridden window.open');
|
||||
});
|
||||
|
||||
await browserWindow.webContents.loadURL('data:text/html,<a target="_blank" href="http://example.com" style="display: block; width: 100%; height: 100%; position: fixed; left: 0; top: 0;">link</a>');
|
||||
@@ -129,11 +181,11 @@ describe('webContents.setWindowOpenHandler', () => {
|
||||
});
|
||||
});
|
||||
browserWindow.webContents.on('new-window', () => {
|
||||
assert.fail('new-window should not to be called with an overridden window.open');
|
||||
assert.fail('new-window should not be called with an overridden window.open');
|
||||
});
|
||||
|
||||
browserWindow.webContents.on('did-create-window', () => {
|
||||
assert.fail('did-create-window should not to be called with an overridden window.open');
|
||||
assert.fail('did-create-window should not be called with an overridden window.open');
|
||||
});
|
||||
|
||||
await browserWindow.webContents.loadURL('data:text/html,<a href="http://example.com" style="display: block; width: 100%; height: 100%; position: fixed; left: 0; top: 0;">link</a>');
|
||||
|
||||
@@ -554,6 +554,18 @@ describe('<webview> tag', function () {
|
||||
});
|
||||
});
|
||||
|
||||
describe('page-title-updated event', () => {
|
||||
it('emits when title is set', async () => {
|
||||
loadWebView(webview, {
|
||||
src: `file://${fixtures}/pages/a.html`
|
||||
});
|
||||
const { title, explicitSet } = await waitForEvent(webview, 'page-title-updated');
|
||||
|
||||
expect(title).to.equal('test');
|
||||
expect(explicitSet).to.be.true();
|
||||
});
|
||||
});
|
||||
|
||||
describe('page-title-set event', () => {
|
||||
it('emits when title is set', async () => {
|
||||
loadWebView(webview, {
|
||||
|
||||
3
typings/internal-ambient.d.ts
vendored
3
typings/internal-ambient.d.ts
vendored
@@ -27,7 +27,6 @@ declare namespace NodeJS {
|
||||
isPictureInPictureEnabled(): boolean;
|
||||
isExtensionsEnabled(): boolean;
|
||||
isComponentBuild(): boolean;
|
||||
isWinDarkModeWindowUiEnabled(): boolean;
|
||||
}
|
||||
|
||||
interface IpcRendererBinding {
|
||||
@@ -108,8 +107,6 @@ declare namespace NodeJS {
|
||||
isWebView: boolean;
|
||||
hiddenPage: boolean;
|
||||
nodeIntegration: boolean;
|
||||
preload: string
|
||||
preloadScripts: string[];
|
||||
webviewTag: boolean;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user