Skip to content

Commit

Permalink
views: mac: Support dynamic resize of title bar height (see #3189)
Browse files Browse the repository at this point in the history
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
  • Loading branch information
nik-sp authored and magreenblatt committed Mar 16, 2023
1 parent 0a2c7a1 commit c83b3cd
Show file tree
Hide file tree
Showing 19 changed files with 155 additions and 61 deletions.
1 change: 1 addition & 0 deletions cef_paths2.gypi
Expand Up @@ -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',
Expand Down
16 changes: 9 additions & 7 deletions libcef/browser/views/native_widget_mac.h
Expand Up @@ -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<float> title_bar_height);
CefRefPtr<CefWindow> window,
CefWindowDelegate* window_delegate);
~CefNativeWidgetMac() override = default;

CefNativeWidgetMac(const CefNativeWidgetMac&) = delete;
Expand All @@ -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<float> title_bar_height_;
const CefRefPtr<CefWindow> window_;
CefWindowDelegate* const window_delegate_;
};

#endif // CEF_LIBCEF_BROWSER_VIEWS_NATIVE_WIDGET_MAC_H_
24 changes: 13 additions & 11 deletions libcef/browser/views/native_widget_mac.mm
Expand Up @@ -4,33 +4,36 @@

#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<float> title_bar_height)
CefRefPtr<CefWindow> 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) {
NSUInteger style_mask =
NSWindowStyleMaskTitled | NSWindowStyleMaskMiniaturizable |
NSWindowStyleMaskClosable | NSWindowStyleMaskResizable |
NSWindowStyleMaskTexturedBackground;

bool is_frameless = window_delegate_->IsFrameless(window_);

auto window = [[CefNSWindow alloc] initWithStyle:style_mask
isFrameless:is_frameless_];
isFrameless:is_frameless];

if (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];
Expand All @@ -42,9 +45,8 @@
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);
Expand Down
8 changes: 4 additions & 4 deletions libcef/browser/views/view_util.h
Expand Up @@ -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"

Expand All @@ -29,6 +28,8 @@ class NativeWidgetDelegate;
}
} // namespace views

class CefWindowDelegate;

#define CEF_REQUIRE_VALID_RETURN(ret) \
if (!ParentClass::IsValid()) \
return ret;
Expand Down Expand Up @@ -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<float> title_bar_height);
CefRefPtr<CefWindow> window,
CefWindowDelegate* window_delegate);

} // namespace view_util

Expand Down
5 changes: 2 additions & 3 deletions libcef/browser/views/view_util_aura.cc
Expand Up @@ -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<float> title_bar_height) {
CefRefPtr<CefWindow> window,
CefWindowDelegate* window_delegate) {
return nullptr;
}

Expand Down
8 changes: 3 additions & 5 deletions libcef/browser/views/view_util_mac.mm
Expand Up @@ -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<float> title_bar_height) {
return new CefNativeWidgetMac(delegate, is_frameless, with_window_buttons,
title_bar_height);
CefRefPtr<CefWindow> window,
CefWindowDelegate* window_delegate) {
return new CefNativeWidgetMac(delegate, window, window_delegate);
}
} // namespace view_util
20 changes: 2 additions & 18 deletions libcef/browser/views/window_view.cc
Expand Up @@ -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);

Expand Down Expand Up @@ -666,14 +661,3 @@ views::NonClientFrameView* CefWindowView::GetNonClientFrameView() const {
}
return widget->non_client_view()->frame_view();
}

absl::optional<float> CefWindowView::GetTitlebarHeight(
const CefRefPtr<CefWindow>& 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;
}
4 changes: 0 additions & 4 deletions libcef/browser/views/window_view.h
Expand Up @@ -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"
Expand Down Expand Up @@ -120,9 +119,6 @@ class CefWindowView

void MoveOverlaysIfNecessary();

absl::optional<float> GetTitlebarHeight(
const CefRefPtr<CefWindow>& window) const;

// Not owned by this object.
Delegate* window_delegate_;

Expand Down
6 changes: 6 additions & 0 deletions tests/cefclient/browser/root_window_views.cc
Expand Up @@ -28,6 +28,12 @@ RootWindowViews::~RootWindowViews() {
REQUIRE_MAIN_THREAD();
}

void RootWindowViews::SetTitlebarHeight(const std::optional<float>& height) {
if (window_) {
window_->SetTitlebarHeight(height);
}
}

void RootWindowViews::Init(RootWindow::Delegate* delegate,
std::unique_ptr<RootWindowConfig> config,
const CefBrowserSettings& settings) {
Expand Down
2 changes: 2 additions & 0 deletions tests/cefclient/browser/root_window_views.h
Expand Up @@ -26,6 +26,8 @@ class RootWindowViews : public RootWindow,
RootWindowViews();
~RootWindowViews();

void SetTitlebarHeight(const std::optional<float>& height);

// RootWindow methods:
void Init(RootWindow::Delegate* delegate,
std::unique_ptr<RootWindowConfig> config,
Expand Down
27 changes: 25 additions & 2 deletions tests/cefclient/browser/views_window.cc
Expand Up @@ -399,6 +399,16 @@ bool ViewsWindow::GetWindowRestorePreferences(
return true;
}

void ViewsWindow::SetTitlebarHeight(const std::optional<float>& height) {
CEF_REQUIRE_UI_THREAD();
if (height.has_value()) {
override_titlebar_height_ = height;
} else {
override_titlebar_height_ = default_titlebar_height_;
}
NudgeWindow();
}

CefRefPtr<CefBrowserViewDelegate> ViewsWindow::GetDelegateForPopupBrowserView(
CefRefPtr<CefBrowserView> browser_view,
const CefBrowserSettings& settings,
Expand Down Expand Up @@ -735,8 +745,8 @@ bool ViewsWindow::GetTitlebarHeight(CefRefPtr<CefWindow> 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
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -1262,4 +1279,10 @@ void ViewsWindow::OnExtensionWindowClosed() {
extension_button_pressed_lock_ = nullptr;
}

#if !defined(OS_MAC)
void ViewsWindow::NudgeWindow() {
NOTIMPLEMENTED();
}
#endif

} // namespace client
6 changes: 6 additions & 0 deletions tests/cefclient/browser/views_window.h
Expand Up @@ -130,6 +130,7 @@ class ViewsWindow : public CefBrowserViewDelegate,

bool GetWindowRestorePreferences(cef_show_state_t& show_state,
std::optional<CefRect>& dip_bounds);
void SetTitlebarHeight(const std::optional<float>& height);

// CefBrowserViewDelegate methods:
CefRefPtr<CefBrowserViewDelegate> GetDelegateForPopupBrowserView(
Expand Down Expand Up @@ -236,6 +237,8 @@ class ViewsWindow : public CefBrowserViewDelegate,
const ImageCache::ImageSet& images);
void OnExtensionWindowClosed();

void NudgeWindow();

Delegate* delegate_; // Not owned by this object.
CefRefPtr<CefBrowserView> browser_view_;
bool frameless_;
Expand All @@ -258,6 +261,9 @@ class ViewsWindow : public CefBrowserViewDelegate,

CefRefPtr<ViewsOverlayControls> overlay_controls_;

std::optional<float> default_titlebar_height_;
std::optional<float> override_titlebar_height_;

// Structure representing an extension.
struct ExtensionInfo {
ExtensionInfo(CefRefPtr<CefExtension> extension, CefRefPtr<CefImage> image)
Expand Down
24 changes: 24 additions & 0 deletions 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 <Cocoa/Cocoa.h>

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];
}
}

}
17 changes: 13 additions & 4 deletions tests/cefclient/browser/window_test.cc
Expand Up @@ -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<WindowTestRunner> CreateWindowTestRunner() {
Expand Down Expand Up @@ -69,6 +70,15 @@ std::vector<int> ParsePosition(const std::string& message_name) {
return vec;
}

std::optional<float> 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:
Expand All @@ -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();
}
Expand Down
5 changes: 5 additions & 0 deletions tests/cefclient/browser/window_test_runner.cc
Expand Up @@ -36,5 +36,10 @@ void WindowTestRunner::ModifyBounds(const CefRect& display, CefRect& window) {
}
}

void WindowTestRunner::SetTitleBarHeight(CefRefPtr<CefBrowser> browser,
const std::optional<float>& height) {
NOTIMPLEMENTED();
}

} // namespace window_test
} // namespace client

0 comments on commit c83b3cd

Please sign in to comment.