Compare commits

...

4 Commits

Author SHA1 Message Date
Charles Kerr
2f2b6ea4bd chore: remove NativeWindowsMac from the grandfathered-classes-that-can-call-deprecated-views-behavior patch 2025-05-01 09:44:02 -05:00
Charles Kerr
975dd40424 refactor: remove NativeWindowMac private API calls
Remove call to WidgetDelegate::RegisterDeleteDelegateCallback()
because this is now private API upstream.

Move the on-delegate-destroyed work into OnWidgetDestroying() instead.
2025-05-01 09:41:43 -05:00
David Sanders
4f89c31956 refactor: add EmitDeprecationWarning helper (#46860)
* refactor: add EmitDeprecationWarning helper

Also switches EmitWarning to using Node's ProcessEmitWarningGeneric

* chore: use node namespace for function call
2025-04-30 13:48:35 -05:00
Charles Kerr
25d77fd1ce refactor: use WidgetDelegate's title property (#46849)
* refactor: use WidgetDelegate::SetTitle()

* Make NativeWindow::SetTitle() and NativeWindow::GetTitle() non-virtual.
  Use WidgetDelegate for their implementation.

* Add NativeWindow::OnTitleChanged(), a new protected virtual method to update
  subclasses (e.g. NativeWindowMac needs to redraw the button proxy).

* In NativeWindowMac, replace SetTitle() and GetTitle() with OnTitleChanged().

* In NativeWindowViews, replace SetTitle() and GetTitle() with OnTitleChanged().

* test: enable BrowserWindow.title tests on Linux

* test: add a test to confirm win.title changes when document.title is set in the renderer
2025-04-30 08:22:27 -07:00
12 changed files with 105 additions and 95 deletions

View File

@@ -49,24 +49,23 @@ index ae7eab37f12ba80ec423d229cf048021e9ba6765..507a75dc7947295db221b01356fa57ba
// These existing cases are "grandfathered in", but there shouldn't be more.
// See comments atop class.
diff --git a/ui/views/widget/widget_delegate.h b/ui/views/widget/widget_delegate.h
index 7c2463cb91d00de2b0fa4f10221ea960be860d9a..0d5c63e7efbe42d5352abdeb594175904af30c41 100644
index 7c2463cb91d00de2b0fa4f10221ea960be860d9a..78b3dc6fa4702e9021a10b60a5e3808114c71364 100644
--- a/ui/views/widget/widget_delegate.h
+++ b/ui/views/widget/widget_delegate.h
@@ -169,6 +169,13 @@ namespace data_controls {
@@ -169,6 +169,12 @@ namespace data_controls {
class DesktopDataControlsDialog;
}
+namespace electron {
+class AutofillPopupView;
+class DevToolsWindowDelegate;
+class NativeWindowMac;
+class NativeWindowViews;
+}
+
namespace enterprise_connectors {
class ContentAnalysisDialog;
class ContentAnalysisDialogBehaviorBrowserTest;
@@ -371,6 +378,7 @@ class VIEWS_EXPORT WidgetDelegate {
@@ -371,6 +377,7 @@ class VIEWS_EXPORT WidgetDelegate {
class OwnedByWidgetPassKey {
private:
@@ -74,16 +73,15 @@ index 7c2463cb91d00de2b0fa4f10221ea960be860d9a..0d5c63e7efbe42d5352abdeb59417590
// DO NOT ADD TO THIS LIST!
// These existing cases are "grandfathered in", but there shouldn't be more.
// See comments atop `SetOwnedByWidget()`.
@@ -468,6 +476,8 @@ class VIEWS_EXPORT WidgetDelegate {
@@ -468,6 +475,7 @@ class VIEWS_EXPORT WidgetDelegate {
};
class RegisterDeleteCallbackPassKey {
private:
+ friend class electron::NativeWindowMac;
+ friend class electron::NativeWindowViews;
// DO NOT ADD TO THIS LIST!
// These existing cases are "grandfathered in", but there shouldn't be more.
// See comments atop `RegisterDeleteDelegateCallback()`.
@@ -918,6 +928,7 @@ class VIEWS_EXPORT WidgetDelegateView : public WidgetDelegate, public View {
@@ -918,6 +926,7 @@ class VIEWS_EXPORT WidgetDelegateView : public WidgetDelegate, public View {
View* GetContentsView() override;
private:

View File

@@ -666,10 +666,9 @@ void WebRequest::SetListener(Event event,
}
if (filter_include_patterns.empty()) {
util::EmitWarning(
util::EmitDeprecationWarning(
"The urls array in WebRequestFilter is empty, which is deprecated. "
"Please use '<all_urls>' to match all URLs.",
"DeprecationWarning");
"Please use '<all_urls>' to match all URLs.");
filter_include_patterns.insert("<all_urls>");
}

View File

@@ -804,6 +804,18 @@ std::u16string NativeWindow::GetAccessibleWindowTitle() const {
return accessible_title_;
}
std::string NativeWindow::GetTitle() const {
return base::UTF16ToUTF8(WidgetDelegate::GetWindowTitle());
}
void NativeWindow::SetTitle(const std::string_view title) {
if (title == GetTitle())
return;
WidgetDelegate::SetTitle(base::UTF8ToUTF16(title));
OnTitleChanged();
}
void NativeWindow::SetAccessibleTitle(const std::string& title) {
accessible_title_ = base::UTF8ToUTF16(title);
}

View File

@@ -148,8 +148,6 @@ class NativeWindow : public base::SupportsUserData,
virtual ui::ZOrderLevel GetZOrderLevel() const = 0;
virtual void Center() = 0;
virtual void Invalidate() = 0;
virtual void SetTitle(const std::string& title) = 0;
virtual std::string GetTitle() const = 0;
#if BUILDFLAG(IS_MAC)
virtual std::string GetAlwaysOnTopLevel() const = 0;
virtual void SetActive(bool is_key) = 0;
@@ -160,6 +158,9 @@ class NativeWindow : public base::SupportsUserData,
virtual void DetachChildren() = 0;
#endif
void SetTitle(std::string_view title);
[[nodiscard]] std::string GetTitle() const;
// Ability to augment the window title for the screen readers.
void SetAccessibleTitle(const std::string& title);
std::string GetAccessibleTitle();
@@ -437,6 +438,8 @@ class NativeWindow : public base::SupportsUserData,
NativeWindow(const gin_helper::Dictionary& options, NativeWindow* parent);
virtual void OnTitleChanged() {}
// views::WidgetDelegate:
views::Widget* GetWidget() override;
const views::Widget* GetWidget() const override;

View File

@@ -37,6 +37,7 @@ class NativeWindowMac : public NativeWindow,
~NativeWindowMac() override;
// NativeWindow:
void OnTitleChanged() override;
void SetContentView(views::View* view) override;
void Close() override;
void CloseImmediately() override;
@@ -85,8 +86,6 @@ class NativeWindowMac : public NativeWindow,
ui::ZOrderLevel GetZOrderLevel() const override;
void Center() override;
void Invalidate() override;
void SetTitle(const std::string& title) override;
std::string GetTitle() const override;
void FlashFrame(bool flash) override;
void SetSkipTaskbar(bool skip) override;
void SetExcludedFromShownWindowsMenu(bool excluded) override;
@@ -224,6 +223,7 @@ class NativeWindowMac : public NativeWindow,
std::unique_ptr<views::NonClientFrameView> CreateNonClientFrameView(
views::Widget* widget) override;
void OnWidgetInitialized() override;
void OnWidgetDestroying(views::Widget* widget) override;
// ui::NativeThemeObserver:
void OnNativeThemeUpdated(ui::NativeTheme* observed_theme) override;

View File

@@ -182,9 +182,8 @@ NativeWindowMac::NativeWindowMac(const gin_helper::Dictionary& options,
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
if (windowType == "textured" && (transparent() || !has_frame())) {
util::EmitWarning(
"The 'textured' window type is deprecated and will be removed",
"DeprecationWarning");
util::EmitDeprecationWarning(
"The 'textured' window type is deprecated and will be removed");
styleMask |= NSWindowStyleMaskTexturedBackground;
}
#pragma clang diagnostic pop
@@ -210,16 +209,6 @@ NativeWindowMac::NativeWindowMac(const gin_helper::Dictionary& options,
window_ = static_cast<ElectronNSWindow*>(
widget()->GetNativeWindow().GetNativeNSWindow());
RegisterDeleteDelegateCallback(RegisterDeleteCallbackPassKey(),
base::BindOnce(
[](NativeWindowMac* window) {
if (window->window_)
window->window_ = nil;
if (window->buttons_proxy_)
window->buttons_proxy_ = nil;
},
this));
[window_ setEnableLargerThanScreen:enable_larger_than_screen()];
window_delegate_ = [[ElectronNSWindowDelegate alloc] initWithShell:this];
@@ -938,16 +927,13 @@ void NativeWindowMac::Invalidate() {
[[window_ contentView] setNeedsDisplay:YES];
}
void NativeWindowMac::SetTitle(const std::string& title) {
[window_ setTitle:base::SysUTF8ToNSString(title)];
void NativeWindowMac::OnTitleChanged() {
[window_ setTitle:base::SysUTF8ToNSString(GetTitle())];
if (buttons_proxy_)
[buttons_proxy_ redraw];
}
std::string NativeWindowMac::GetTitle() const {
return base::SysNSStringToUTF8([window_ title]);
}
void NativeWindowMac::FlashFrame(bool flash) {
if (flash) {
attention_request_id_ = [NSApp requestUserAttention:NSCriticalRequest];
@@ -1875,6 +1861,11 @@ void NativeWindowMac::OnWidgetInitialized() {
}
}
void NativeWindowMac::OnWidgetDestroying(views::Widget* widget) {
window_ = nil;
buttons_proxy_ = nil;
}
// static
std::unique_ptr<NativeWindow> NativeWindow::Create(
const gin_helper::Dictionary& options,

View File

@@ -198,7 +198,8 @@ class NativeWindowClientView : public views::ClientView {
NativeWindowViews::NativeWindowViews(const gin_helper::Dictionary& options,
NativeWindow* parent)
: NativeWindow(options, parent) {
options.Get(options::kTitle, &title_);
if (std::string val; options.Get(options::kTitle, &val))
SetTitle(val);
bool menu_bar_autohide;
if (options.Get(options::kAutoHideMenuBar, &menu_bar_autohide))
@@ -1160,15 +1161,6 @@ void NativeWindowViews::Invalidate() {
widget()->SchedulePaintInRect(gfx::Rect(GetBounds().size()));
}
void NativeWindowViews::SetTitle(const std::string& title) {
title_ = title;
widget()->UpdateWindowTitle();
}
std::string NativeWindowViews::GetTitle() const {
return title_;
}
void NativeWindowViews::FlashFrame(bool flash) {
#if BUILDFLAG(IS_WIN)
// The Chromium's implementation has a bug stopping flash.
@@ -1750,10 +1742,6 @@ bool NativeWindowViews::CanMinimize() const {
#endif
}
std::u16string NativeWindowViews::GetWindowTitle() const {
return base::UTF8ToUTF16(title_);
}
views::View* NativeWindowViews::GetContentsView() {
return root_view_.GetMainView();
}

View File

@@ -98,8 +98,6 @@ class NativeWindowViews : public NativeWindow,
ui::ZOrderLevel GetZOrderLevel() const override;
void Center() override;
void Invalidate() override;
void SetTitle(const std::string& title) override;
std::string GetTitle() const override;
void FlashFrame(bool flash) override;
void SetSkipTaskbar(bool skip) override;
void SetExcludedFromShownWindowsMenu(bool excluded) override {}
@@ -191,7 +189,6 @@ class NativeWindowViews : public NativeWindow,
views::View* GetInitiallyFocusedView() override;
bool CanMaximize() const override;
bool CanMinimize() const override;
std::u16string GetWindowTitle() const override;
views::View* GetContentsView() override;
bool ShouldDescendIntoChildForEventHandling(
gfx::NativeView child,
@@ -327,7 +324,6 @@ class NativeWindowViews : public NativeWindow,
bool maximizable_ = true;
bool minimizable_ = true;
bool fullscreenable_ = true;
std::string title_;
gfx::Size widget_size_;
double opacity_ = 1.0;
bool widget_destroyed_ = false;

View File

@@ -286,9 +286,8 @@ v8::Local<v8::Value> NativeImage::GetBitmap(gin::Arguments* args) {
if (!deprecated_warning_issued) {
deprecated_warning_issued = true;
util::EmitWarning(isolate_,
"getBitmap() is deprecated, use toBitmap() instead.",
"DeprecationWarning");
util::EmitDeprecationWarning(
isolate_, "getBitmap() is deprecated, use toBitmap() instead.");
}
return ToBitmap(args);

View File

@@ -12,10 +12,10 @@
#include "base/strings/string_number_conversions.h"
#include "base/values.h"
#include "gin/converter.h"
#include "gin/dictionary.h"
#include "shell/browser/javascript_environment.h"
#include "shell/common/gin_converters/callback_converter.h"
#include "shell/common/node_includes.h"
#include "third_party/electron_node/src/node_process-inl.h"
namespace electron::util {
@@ -65,14 +65,22 @@ void EmitWarning(const std::string_view warning_msg,
void EmitWarning(v8::Isolate* isolate,
const std::string_view warning_msg,
const std::string_view warning_type) {
v8::HandleScope scope{isolate};
gin::Dictionary process{
isolate, node::Environment::GetCurrent(isolate)->process_object()};
base::RepeatingCallback<void(std::string_view, std::string_view,
std::string_view)>
emit_warning;
process.Get("emitWarning", &emit_warning);
emit_warning.Run(warning_msg, warning_type, "");
node::ProcessEmitWarningGeneric(node::Environment::GetCurrent(isolate),
warning_msg, warning_type);
}
void EmitDeprecationWarning(const std::string_view warning_msg,
const std::string_view deprecation_code) {
EmitDeprecationWarning(JavascriptEnvironment::GetIsolate(), warning_msg,
deprecation_code);
}
void EmitDeprecationWarning(v8::Isolate* isolate,
const std::string_view warning_msg,
const std::string_view deprecation_code) {
node::ProcessEmitWarningGeneric(node::Environment::GetCurrent(isolate),
warning_msg, "DeprecationWarning",
deprecation_code);
}
node::Environment* CreateEnvironment(v8::Isolate* isolate,

View File

@@ -30,9 +30,19 @@ void EmitWarning(v8::Isolate* isolate,
std::string_view warning_type);
// Emit a warning via node's process.emitWarning(),
// using JavscriptEnvironment's isolate
// using JavascriptEnvironment's isolate
void EmitWarning(std::string_view warning_msg, std::string_view warning_type);
// Emit a deprecation warning via node's process.emitWarning()
void EmitDeprecationWarning(v8::Isolate* isolate,
std::string_view warning_msg,
std::string_view deprecation_code = "");
// Emit a deprecation warning via node's process.emitWarning(),
// using JavascriptEnvironment's isolate
void EmitDeprecationWarning(std::string_view warning_msg,
std::string_view deprecation_code = "");
// Run a script with JS source bundled inside the binary as if it's wrapped
// in a function called with a null receiver and arguments specified in C++.
// The returned value is empty if an exception is encountered.

View File

@@ -3888,8 +3888,14 @@ describe('BrowserWindow module', () => {
});
it('works for window events', async () => {
const pageTitleUpdated = once(w, 'page-title-updated');
w.loadURL('data:text/html,<script>document.title = \'changed\'</script>');
const newTitle = 'changed';
w.loadURL(`data:text/html,<script>document.title = '${newTitle}'</script>`);
await pageTitleUpdated;
// w.title should update after 'page-title-updated'.
// It happens right *after* the event fires though,
// so we have to waitUntil it changes
waitUntil(() => w.title === newTitle);
});
it('works for stop events', async () => {
@@ -5428,6 +5434,36 @@ describe('BrowserWindow module', () => {
});
});
});
describe('native window title', () => {
describe('with properties', () => {
it('can be set with title constructor option', () => {
const w = new BrowserWindow({ show: false, title: 'mYtItLe' });
expect(w.title).to.eql('mYtItLe');
});
it('can be changed', () => {
const w = new BrowserWindow({ show: false });
expect(w.title).to.eql('Electron Test Main');
w.title = 'NEW TITLE';
expect(w.title).to.eql('NEW TITLE');
});
});
describe('with functions', () => {
it('can be set with minimizable constructor option', () => {
const w = new BrowserWindow({ show: false, title: 'mYtItLe' });
expect(w.getTitle()).to.eql('mYtItLe');
});
it('can be changed', () => {
const w = new BrowserWindow({ show: false });
expect(w.getTitle()).to.eql('Electron Test Main');
w.setTitle('NEW TITLE');
expect(w.getTitle()).to.eql('NEW TITLE');
});
});
});
});
ifdescribe(process.platform !== 'linux')('window states (excluding Linux)', () => {
@@ -5508,36 +5544,6 @@ describe('BrowserWindow module', () => {
});
});
describe('native window title', () => {
describe('with properties', () => {
it('can be set with title constructor option', () => {
const w = new BrowserWindow({ show: false, title: 'mYtItLe' });
expect(w.title).to.eql('mYtItLe');
});
it('can be changed', () => {
const w = new BrowserWindow({ show: false });
expect(w.title).to.eql('Electron Test Main');
w.title = 'NEW TITLE';
expect(w.title).to.eql('NEW TITLE');
});
});
describe('with functions', () => {
it('can be set with minimizable constructor option', () => {
const w = new BrowserWindow({ show: false, title: 'mYtItLe' });
expect(w.getTitle()).to.eql('mYtItLe');
});
it('can be changed', () => {
const w = new BrowserWindow({ show: false });
expect(w.getTitle()).to.eql('Electron Test Main');
w.setTitle('NEW TITLE');
expect(w.getTitle()).to.eql('NEW TITLE');
});
});
});
describe('minimizable state', () => {
describe('with properties', () => {
it('can be set with minimizable constructor option', () => {