diff --git a/shell/browser/native_window.cc b/shell/browser/native_window.cc index 9a6db49f0763..533c3ac36694 100644 --- a/shell/browser/native_window.cc +++ b/shell/browser/native_window.cc @@ -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); } diff --git a/shell/browser/native_window.h b/shell/browser/native_window.h index 7a9b762c60b2..96a1cb361e3b 100644 --- a/shell/browser/native_window.h +++ b/shell/browser/native_window.h @@ -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; diff --git a/shell/browser/native_window_mac.h b/shell/browser/native_window_mac.h index fa51e9ee447d..acd6f871a421 100644 --- a/shell/browser/native_window_mac.h +++ b/shell/browser/native_window_mac.h @@ -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; diff --git a/shell/browser/native_window_mac.mm b/shell/browser/native_window_mac.mm index 3fef4cba6c24..f848e5cf7884 100644 --- a/shell/browser/native_window_mac.mm +++ b/shell/browser/native_window_mac.mm @@ -938,16 +938,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]; diff --git a/shell/browser/native_window_views.cc b/shell/browser/native_window_views.cc index 610ecc7ecad8..0d6e6acd02d1 100644 --- a/shell/browser/native_window_views.cc +++ b/shell/browser/native_window_views.cc @@ -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(); } diff --git a/shell/browser/native_window_views.h b/shell/browser/native_window_views.h index 5bc9db1ea7bb..f79dc9fc1e67 100644 --- a/shell/browser/native_window_views.h +++ b/shell/browser/native_window_views.h @@ -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; diff --git a/spec/api-browser-window-spec.ts b/spec/api-browser-window-spec.ts index f8aebc55d93b..5d44f5281d3f 100755 --- a/spec/api-browser-window-spec.ts +++ b/spec/api-browser-window-spec.ts @@ -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,'); + const newTitle = 'changed'; + w.loadURL(`data:text/html,`); 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', () => {