From c83b3cda24e2960141dc13e1f089edb93c939add Mon Sep 17 00:00:00 2001 From: Nik Pavlov Date: Thu, 16 Mar 2023 17:19:50 +0000 Subject: [PATCH] views: mac: Support dynamic resize of title bar height (see #3189) This is intended for usage with frameless windows that show the standard window buttons, where resizing the title bar height changes the button offset. Returning a different value from CefWindowDelegate::GetTitlebarHeight and forcing a resize of the NSWindow's theme frame (see ViewsWindow::NudgeWindow) will update the title bar height. To test: 1. Run `cefclient --use-views --hide-frame --show-window-buttons --url=http://tests/window` 2. Enter a new value for title bar height and click the "Set Titlebar Height" button --- cef_paths2.gypi | 1 + libcef/browser/views/native_widget_mac.h | 16 ++++++----- libcef/browser/views/native_widget_mac.mm | 26 +++++++++--------- libcef/browser/views/view_util.h | 8 +++--- libcef/browser/views/view_util_aura.cc | 5 ++-- libcef/browser/views/view_util_mac.mm | 8 +++--- libcef/browser/views/window_view.cc | 20 ++------------ libcef/browser/views/window_view.h | 4 --- tests/cefclient/browser/root_window_views.cc | 6 +++++ tests/cefclient/browser/root_window_views.h | 2 ++ tests/cefclient/browser/views_window.cc | 27 +++++++++++++++++-- tests/cefclient/browser/views_window.h | 6 +++++ tests/cefclient/browser/views_window_mac.mm | 24 +++++++++++++++++ tests/cefclient/browser/window_test.cc | 17 +++++++++--- tests/cefclient/browser/window_test_runner.cc | 5 ++++ tests/cefclient/browser/window_test_runner.h | 7 ++++- .../browser/window_test_runner_views.cc | 21 ++++++++++++++- .../browser/window_test_runner_views.h | 2 ++ tests/cefclient/resources/window.html | 13 ++++++++- 19 files changed, 156 insertions(+), 62 deletions(-) create mode 100644 tests/cefclient/browser/views_window_mac.mm diff --git a/cef_paths2.gypi b/cef_paths2.gypi index 377b48d4b..38718e4b0 100644 --- a/cef_paths2.gypi +++ b/cef_paths2.gypi @@ -393,6 +393,7 @@ 'tests/cefclient/browser/temp_window_mac.mm', 'tests/cefclient/browser/text_input_client_osr_mac.h', 'tests/cefclient/browser/text_input_client_osr_mac.mm', + 'tests/cefclient/browser/views_window_mac.mm', 'tests/cefclient/browser/window_test_runner_mac.h', 'tests/cefclient/browser/window_test_runner_mac.mm', 'tests/cefclient/cefclient_mac.mm', diff --git a/libcef/browser/views/native_widget_mac.h b/libcef/browser/views/native_widget_mac.h index bbe220688..b47457643 100644 --- a/libcef/browser/views/native_widget_mac.h +++ b/libcef/browser/views/native_widget_mac.h @@ -6,15 +6,18 @@ #define CEF_LIBCEF_BROWSER_VIEWS_NATIVE_WIDGET_MAC_H_ #pragma once -#include "third_party/abseil-cpp/absl/types/optional.h" +#include "include/internal/cef_ptr.h" + #include "ui/views/widget/native_widget_mac.h" +class CefWindow; +class CefWindowDelegate; + class CefNativeWidgetMac : public views::NativeWidgetMac { public: CefNativeWidgetMac(views::internal::NativeWidgetDelegate* delegate, - bool is_frameless, - bool with_window_buttons, - absl::optional title_bar_height); + CefRefPtr window, + CefWindowDelegate* window_delegate); ~CefNativeWidgetMac() override = default; CefNativeWidgetMac(const CefNativeWidgetMac&) = delete; @@ -29,9 +32,8 @@ class CefNativeWidgetMac : public views::NativeWidgetMac { float* titlebar_height) override; private: - const bool is_frameless_; - const bool with_window_buttons_; - const absl::optional title_bar_height_; + const CefRefPtr window_; + CefWindowDelegate* const window_delegate_; }; #endif // CEF_LIBCEF_BROWSER_VIEWS_NATIVE_WIDGET_MAC_H_ diff --git a/libcef/browser/views/native_widget_mac.mm b/libcef/browser/views/native_widget_mac.mm index 34ffdb1a0..b722c3731 100644 --- a/libcef/browser/views/native_widget_mac.mm +++ b/libcef/browser/views/native_widget_mac.mm @@ -4,17 +4,17 @@ #include "libcef/browser/views/native_widget_mac.h" +#include "include/views/cef_window.h" +#include "include/views/cef_window_delegate.h" #include "libcef/browser/views/ns_window.h" CefNativeWidgetMac::CefNativeWidgetMac( views::internal::NativeWidgetDelegate* delegate, - bool is_frameless, - bool with_window_buttons, - absl::optional title_bar_height) + CefRefPtr window, + CefWindowDelegate* window_delegate) : views::NativeWidgetMac(delegate), - is_frameless_(is_frameless), - with_window_buttons_(with_window_buttons), - title_bar_height_(title_bar_height) {} + window_(window), + window_delegate_(window_delegate) {} NativeWidgetMacNSWindow* CefNativeWidgetMac::CreateNSWindow( const remote_cocoa::mojom::CreateWindowParams* params) { @@ -22,15 +22,18 @@ NativeWidgetMacNSWindow* CefNativeWidgetMac::CreateNSWindow( NSWindowStyleMaskTitled | NSWindowStyleMaskMiniaturizable | NSWindowStyleMaskClosable | NSWindowStyleMaskResizable | NSWindowStyleMaskTexturedBackground; - auto window = [[CefNSWindow alloc] initWithStyle:style_mask - isFrameless:is_frameless_]; - if (is_frameless_) { + bool is_frameless = window_delegate_->IsFrameless(window_); + + auto window = [[CefNSWindow alloc] initWithStyle:style_mask + isFrameless:is_frameless]; + + if (is_frameless) { [window setTitlebarAppearsTransparent:YES]; [window setTitleVisibility:NSWindowTitleHidden]; } - if (!with_window_buttons_) { + if (!window_delegate_->WithStandardWindowButtons(window_)) { [[window standardWindowButton:NSWindowCloseButton] setHidden:YES]; [[window standardWindowButton:NSWindowMiniaturizeButton] setHidden:YES]; [[window standardWindowButton:NSWindowZoomButton] setHidden:YES]; @@ -42,9 +45,8 @@ NativeWidgetMacNSWindow* CefNativeWidgetMac::CreateNSWindow( void CefNativeWidgetMac::GetWindowFrameTitlebarHeight( bool* override_titlebar_height, float* titlebar_height) { - if (title_bar_height_) { + if (window_delegate_->GetTitlebarHeight(window_, titlebar_height)) { *override_titlebar_height = true; - *titlebar_height = title_bar_height_.value(); } else { views::NativeWidgetMac::GetWindowFrameTitlebarHeight( override_titlebar_height, titlebar_height); diff --git a/libcef/browser/views/view_util.h b/libcef/browser/views/view_util.h index 2a9000619..50828da92 100644 --- a/libcef/browser/views/view_util.h +++ b/libcef/browser/views/view_util.h @@ -9,7 +9,6 @@ #include "include/views/cef_view.h" #include "include/views/cef_window.h" -#include "third_party/abseil-cpp/absl/types/optional.h" #include "ui/gfx/native_widget_types.h" #include "ui/views/view.h" @@ -29,6 +28,8 @@ class NativeWidgetDelegate; } } // namespace views +class CefWindowDelegate; + #define CEF_REQUIRE_VALID_RETURN(ret) \ if (!ParentClass::IsValid()) \ return ret; @@ -148,9 +149,8 @@ CefWindowHandle GetWindowHandle(gfx::NativeWindow window); views::NativeWidget* CreateNativeWidget( views::internal::NativeWidgetDelegate* delegate, - bool is_frameless, - bool with_window_buttons, - absl::optional title_bar_height); + CefRefPtr window, + CefWindowDelegate* window_delegate); } // namespace view_util diff --git a/libcef/browser/views/view_util_aura.cc b/libcef/browser/views/view_util_aura.cc index f58b9b3f9..f28d55264 100644 --- a/libcef/browser/views/view_util_aura.cc +++ b/libcef/browser/views/view_util_aura.cc @@ -44,9 +44,8 @@ CefWindowHandle GetWindowHandle(gfx::NativeWindow window) { views::NativeWidget* CreateNativeWidget( views::internal::NativeWidgetDelegate* delegate, - bool is_frameless, - bool with_window_buttons, - absl::optional title_bar_height) { + CefRefPtr window, + CefWindowDelegate* window_delegate) { return nullptr; } diff --git a/libcef/browser/views/view_util_mac.mm b/libcef/browser/views/view_util_mac.mm index f69bf8323..2bab6b473 100644 --- a/libcef/browser/views/view_util_mac.mm +++ b/libcef/browser/views/view_util_mac.mm @@ -47,10 +47,8 @@ CefWindowHandle GetWindowHandle(gfx::NativeWindow window) { views::NativeWidget* CreateNativeWidget( views::internal::NativeWidgetDelegate* delegate, - bool is_frameless, - bool with_window_buttons, - absl::optional title_bar_height) { - return new CefNativeWidgetMac(delegate, is_frameless, with_window_buttons, - title_bar_height); + CefRefPtr window, + CefWindowDelegate* window_delegate) { + return new CefNativeWidgetMac(delegate, window, window_delegate); } } // namespace view_util diff --git a/libcef/browser/views/window_view.cc b/libcef/browser/views/window_view.cc index 4bf06c66e..0c5ee9ebc 100644 --- a/libcef/browser/views/window_view.cc +++ b/libcef/browser/views/window_view.cc @@ -313,13 +313,8 @@ void CefWindowView::CreateWidget(gfx::AcceleratedWidget parent_widget) { } else { is_frameless_ = cef_delegate()->IsFrameless(cef_window); - const bool with_standard_buttons = - cef_delegate()->WithStandardWindowButtons(cef_window); - - const auto title_bar_height = GetTitlebarHeight(cef_window); - - params.native_widget = view_util::CreateNativeWidget( - widget, is_frameless_, with_standard_buttons, title_bar_height); + params.native_widget = + view_util::CreateNativeWidget(widget, cef_window, cef_delegate()); can_resize = cef_delegate()->CanResize(cef_window); @@ -666,14 +661,3 @@ views::NonClientFrameView* CefWindowView::GetNonClientFrameView() const { } return widget->non_client_view()->frame_view(); } - -absl::optional CefWindowView::GetTitlebarHeight( - const CefRefPtr& window) const { - float title_bar_height = 0; - const bool has_title_bar_height = - cef_delegate()->GetTitlebarHeight(window, &title_bar_height); - if (has_title_bar_height) { - return title_bar_height; - } - return absl::nullopt; -} \ No newline at end of file diff --git a/libcef/browser/views/window_view.h b/libcef/browser/views/window_view.h index 5b52a3f3f..6789636b8 100644 --- a/libcef/browser/views/window_view.h +++ b/libcef/browser/views/window_view.h @@ -14,7 +14,6 @@ #include "libcef/browser/views/overlay_view_host.h" #include "libcef/browser/views/panel_view.h" -#include "third_party/abseil-cpp/absl/types/optional.h" #include "third_party/skia/include/core/SkRegion.h" #include "ui/display/display.h" #include "ui/views/widget/widget_delegate.h" @@ -120,9 +119,6 @@ class CefWindowView void MoveOverlaysIfNecessary(); - absl::optional GetTitlebarHeight( - const CefRefPtr& window) const; - // Not owned by this object. Delegate* window_delegate_; diff --git a/tests/cefclient/browser/root_window_views.cc b/tests/cefclient/browser/root_window_views.cc index 973a81c8b..a8e6ff1cb 100644 --- a/tests/cefclient/browser/root_window_views.cc +++ b/tests/cefclient/browser/root_window_views.cc @@ -28,6 +28,12 @@ RootWindowViews::~RootWindowViews() { REQUIRE_MAIN_THREAD(); } +void RootWindowViews::SetTitlebarHeight(const std::optional& height) { + if (window_) { + window_->SetTitlebarHeight(height); + } +} + void RootWindowViews::Init(RootWindow::Delegate* delegate, std::unique_ptr config, const CefBrowserSettings& settings) { diff --git a/tests/cefclient/browser/root_window_views.h b/tests/cefclient/browser/root_window_views.h index d282f6041..75997e1aa 100644 --- a/tests/cefclient/browser/root_window_views.h +++ b/tests/cefclient/browser/root_window_views.h @@ -26,6 +26,8 @@ class RootWindowViews : public RootWindow, RootWindowViews(); ~RootWindowViews(); + void SetTitlebarHeight(const std::optional& height); + // RootWindow methods: void Init(RootWindow::Delegate* delegate, std::unique_ptr config, diff --git a/tests/cefclient/browser/views_window.cc b/tests/cefclient/browser/views_window.cc index fc6f09c0d..a466047ed 100644 --- a/tests/cefclient/browser/views_window.cc +++ b/tests/cefclient/browser/views_window.cc @@ -399,6 +399,16 @@ bool ViewsWindow::GetWindowRestorePreferences( return true; } +void ViewsWindow::SetTitlebarHeight(const std::optional& height) { + CEF_REQUIRE_UI_THREAD(); + if (height.has_value()) { + override_titlebar_height_ = height; + } else { + override_titlebar_height_ = default_titlebar_height_; + } + NudgeWindow(); +} + CefRefPtr ViewsWindow::GetDelegateForPopupBrowserView( CefRefPtr browser_view, const CefBrowserSettings& settings, @@ -735,8 +745,8 @@ bool ViewsWindow::GetTitlebarHeight(CefRefPtr window, float* titlebar_height) { CEF_REQUIRE_UI_THREAD(); #if defined(OS_MAC) - if (frameless_ && with_standard_buttons_) { - *titlebar_height = kTitleBarHeight; + if (override_titlebar_height_.has_value()) { + *titlebar_height = override_titlebar_height_.value(); return true; } #endif @@ -925,6 +935,13 @@ ViewsWindow::ViewsWindow(Delegate* delegate, // If window has frame or flag passed explicitly with_standard_buttons_ = !frameless_ || show_window_buttons; +#if defined(OS_MAC) + if (frameless_ && with_standard_buttons_) { + default_titlebar_height_ = kTitleBarHeight; + override_titlebar_height_ = kTitleBarHeight; + } +#endif + const std::string& toolbar_type = command_line->GetSwitchValue(switches::kShowChromeToolbar); chrome_toolbar_type_ = CalculateChromeToolbarType(toolbar_type, hide_toolbar, @@ -1262,4 +1279,10 @@ void ViewsWindow::OnExtensionWindowClosed() { extension_button_pressed_lock_ = nullptr; } +#if !defined(OS_MAC) +void ViewsWindow::NudgeWindow() { + NOTIMPLEMENTED(); +} +#endif + } // namespace client diff --git a/tests/cefclient/browser/views_window.h b/tests/cefclient/browser/views_window.h index 14c974469..9dc34ada8 100644 --- a/tests/cefclient/browser/views_window.h +++ b/tests/cefclient/browser/views_window.h @@ -130,6 +130,7 @@ class ViewsWindow : public CefBrowserViewDelegate, bool GetWindowRestorePreferences(cef_show_state_t& show_state, std::optional& dip_bounds); + void SetTitlebarHeight(const std::optional& height); // CefBrowserViewDelegate methods: CefRefPtr GetDelegateForPopupBrowserView( @@ -236,6 +237,8 @@ class ViewsWindow : public CefBrowserViewDelegate, const ImageCache::ImageSet& images); void OnExtensionWindowClosed(); + void NudgeWindow(); + Delegate* delegate_; // Not owned by this object. CefRefPtr browser_view_; bool frameless_; @@ -258,6 +261,9 @@ class ViewsWindow : public CefBrowserViewDelegate, CefRefPtr overlay_controls_; + std::optional default_titlebar_height_; + std::optional override_titlebar_height_; + // Structure representing an extension. struct ExtensionInfo { ExtensionInfo(CefRefPtr extension, CefRefPtr image) diff --git a/tests/cefclient/browser/views_window_mac.mm b/tests/cefclient/browser/views_window_mac.mm new file mode 100644 index 000000000..936a85c08 --- /dev/null +++ b/tests/cefclient/browser/views_window_mac.mm @@ -0,0 +1,24 @@ +// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights +// reserved. Use of this source code is governed by a BSD-style license that +// can be found in the LICENSE file. + +#include "tests/cefclient/browser/views_window.h" + +#include + +namespace client { + +void ViewsWindow::NudgeWindow() { + if (window_) { + auto view = CAST_CEF_WINDOW_HANDLE_TO_NSVIEW(window_->GetWindowHandle()); + NSWindow* main_window = view.window; + + auto theme_frame = main_window.contentView.superview; + // Nudge view frame a little to force an update. + NSSize size = theme_frame.frame.size; + [theme_frame setFrameSize:NSMakeSize(size.width - 1, size.height)]; + [theme_frame setFrameSize:size]; + } +} + +} diff --git a/tests/cefclient/browser/window_test.cc b/tests/cefclient/browser/window_test.cc index 172a22433..316f6147e 100644 --- a/tests/cefclient/browser/window_test.cc +++ b/tests/cefclient/browser/window_test.cc @@ -35,6 +35,7 @@ const char kMessagePositionName[] = "WindowTest.Position"; const char kMessageMinimizeName[] = "WindowTest.Minimize"; const char kMessageMaximizeName[] = "WindowTest.Maximize"; const char kMessageRestoreName[] = "WindowTest.Restore"; +const char kMessageTitlebarHeightName[] = "WindowTest.TitlebarHeight"; // Create the appropriate platform test runner object. std::unique_ptr CreateWindowTestRunner() { @@ -69,6 +70,15 @@ std::vector ParsePosition(const std::string& message_name) { return vec; } +std::optional ParseHeight(const std::string& message) { + if (message.size() > sizeof(kMessageTitlebarHeightName)) { + const std::string& val = message.substr(sizeof(kMessageTitlebarHeightName)); + return std::stof(val); + } else { + return std::nullopt; + } +} + // Handle messages in the browser process. class Handler : public CefMessageRouterBrowserSide::Handler { public: @@ -91,18 +101,17 @@ class Handler : public CefMessageRouterBrowserSide::Handler { if (message_name.find(kMessagePositionName) == 0) { const auto vec = ParsePosition(message_name); if (vec.size() == 4) { - // Execute SetPos() on the main thread. runner_->SetPos(browser, vec[0], vec[1], vec[2], vec[3]); } } else if (message_name == kMessageMinimizeName) { - // Execute Minimize() on the main thread. runner_->Minimize(browser); } else if (message_name == kMessageMaximizeName) { - // Execute Maximize() on the main thread. runner_->Maximize(browser); } else if (message_name == kMessageRestoreName) { - // Execute Restore() on the main thread. runner_->Restore(browser); + } else if (message_name.find(kMessageTitlebarHeightName) == 0) { + const auto height = ParseHeight(message_name); + runner_->SetTitleBarHeight(browser, height); } else { NOTREACHED(); } diff --git a/tests/cefclient/browser/window_test_runner.cc b/tests/cefclient/browser/window_test_runner.cc index b410812f4..c3edce6fe 100644 --- a/tests/cefclient/browser/window_test_runner.cc +++ b/tests/cefclient/browser/window_test_runner.cc @@ -36,5 +36,10 @@ void WindowTestRunner::ModifyBounds(const CefRect& display, CefRect& window) { } } +void WindowTestRunner::SetTitleBarHeight(CefRefPtr browser, + const std::optional& height) { + NOTIMPLEMENTED(); +} + } // namespace window_test } // namespace client diff --git a/tests/cefclient/browser/window_test_runner.h b/tests/cefclient/browser/window_test_runner.h index 26a5324c2..877fb59ed 100644 --- a/tests/cefclient/browser/window_test_runner.h +++ b/tests/cefclient/browser/window_test_runner.h @@ -8,6 +8,8 @@ #include "include/cef_browser.h" +#include + namespace client { namespace window_test { @@ -15,6 +17,8 @@ namespace window_test { // the browser process UI thread unless otherwise indicated. class WindowTestRunner { public: + virtual ~WindowTestRunner() = default; + virtual void SetPos(CefRefPtr browser, int x, int y, @@ -28,7 +32,8 @@ class WindowTestRunner { // corner of the display. static void ModifyBounds(const CefRect& display, CefRect& window); - virtual ~WindowTestRunner() {} + virtual void SetTitleBarHeight(CefRefPtr browser, + const std::optional& height); }; } // namespace window_test diff --git a/tests/cefclient/browser/window_test_runner_views.cc b/tests/cefclient/browser/window_test_runner_views.cc index 03aecf4dc..9efda0ced 100644 --- a/tests/cefclient/browser/window_test_runner_views.cc +++ b/tests/cefclient/browser/window_test_runner_views.cc @@ -9,12 +9,15 @@ #include "include/views/cef_window.h" #include "include/wrapper/cef_helpers.h" +#include "tests/cefclient/browser/root_window_views.h" +#include "tests/cefclient/browser/views_window.h" + namespace client { namespace window_test { namespace { -CefRefPtr GetWindow(CefRefPtr browser) { +CefRefPtr GetWindow(const CefRefPtr& browser) { CEF_REQUIRE_UI_THREAD(); DCHECK(browser->GetHost()->HasView()); @@ -27,6 +30,16 @@ CefRefPtr GetWindow(CefRefPtr browser) { return window; } +void SetTitlebarHeight(const CefRefPtr& browser, + const std::optional& height) { + CEF_REQUIRE_UI_THREAD(); + auto root_window = RootWindow::GetForBrowser(browser->GetIdentifier()); + DCHECK(root_window.get()); + + auto root_window_views = static_cast(root_window.get()); + root_window_views->SetTitlebarHeight(height); +} + } // namespace WindowTestRunnerViews::WindowTestRunnerViews() {} @@ -56,5 +69,11 @@ void WindowTestRunnerViews::Restore(CefRefPtr browser) { GetWindow(browser)->Restore(); } +void WindowTestRunnerViews::SetTitleBarHeight( + CefRefPtr browser, + const std::optional& height) { + SetTitlebarHeight(browser, height); +} + } // namespace window_test } // namespace client diff --git a/tests/cefclient/browser/window_test_runner_views.h b/tests/cefclient/browser/window_test_runner_views.h index 6bc66b0da..851e3742d 100644 --- a/tests/cefclient/browser/window_test_runner_views.h +++ b/tests/cefclient/browser/window_test_runner_views.h @@ -24,6 +24,8 @@ class WindowTestRunnerViews : public WindowTestRunner { void Minimize(CefRefPtr browser) override; void Maximize(CefRefPtr browser) override; void Restore(CefRefPtr browser) override; + void SetTitleBarHeight(CefRefPtr browser, + const std::optional& height) override; }; } // namespace window_test diff --git a/tests/cefclient/resources/window.html b/tests/cefclient/resources/window.html index 7703d0d7d..f01f7f524 100644 --- a/tests/cefclient/resources/window.html +++ b/tests/cefclient/resources/window.html @@ -1,4 +1,5 @@ - + + Window Test @@ -60,6 +69,8 @@ X: Y: Width: Height: +
+ (works on macOS with Views)