views: mac: Fix frameless window behavior (fixes issue #3189)

Frameless windows now display as expected. Default traffic light buttons can
optionally be shown at configurable vertical position. Layout respects text
direction.
This commit is contained in:
Nik Pavlov 2023-02-28 18:34:12 +00:00 committed by Marshall Greenblatt
parent 6926287894
commit f6de0344cb
22 changed files with 579 additions and 57 deletions

View File

@ -1145,6 +1145,10 @@ source_set("libcef_static") {
"libcef/browser/native/menu_runner_mac.mm",
"libcef/browser/osr/browser_platform_delegate_osr_mac.h",
"libcef/browser/osr/browser_platform_delegate_osr_mac.mm",
"libcef/browser/views/native_widget_mac.h",
"libcef/browser/views/native_widget_mac.mm",
"libcef/browser/views/ns_window.h",
"libcef/browser/views/ns_window.mm",
"libcef/browser/views/view_util_mac.mm",
"libcef/common/util_mac.h",
"libcef/common/util_mac.mm",

View File

@ -33,7 +33,7 @@
// by hand. See the translator.README.txt file in the tools directory for
// more information.
//
// $hash=019abf16be4e151d31181a6bdcb1ad8dfef03d00$
// $hash=9f0389a439e6787282880d53375369829adb6a3d$
//
#ifndef CEF_INCLUDE_CAPI_VIEWS_CEF_WINDOW_DELEGATE_CAPI_H_
@ -137,6 +137,25 @@ typedef struct _cef_window_delegate_t {
int(CEF_CALLBACK* is_frameless)(struct _cef_window_delegate_t* self,
struct _cef_window_t* window);
///
/// Return true (1) if |window| should be created with standard window buttons
/// like close, minimize and zoom.
///
int(CEF_CALLBACK* with_standard_window_buttons)(
struct _cef_window_delegate_t* self,
struct _cef_window_t* window);
///
/// Return whether the titlebar height should be overridden, and sets the
/// height of the titlebar in |titlebar_height|. On macOS, it can also be used
/// to adjust the vertical position of the traffic light buttons in frameless
/// windows. The buttons will be positioned halfway down the titlebar at a
/// height of |titlebar_height| / 2.
///
int(CEF_CALLBACK* get_titlebar_height)(struct _cef_window_delegate_t* self,
struct _cef_window_t* window,
float* titlebar_height);
///
/// Return true (1) if |window| can be resized.
///

View File

@ -42,13 +42,13 @@
// way that may cause binary incompatibility with other builds. The universal
// hash value will change if any platform is affected whereas the platform hash
// values will change only if that particular platform is affected.
#define CEF_API_HASH_UNIVERSAL "17e2f5f1944618780d9d2f445d6f7ca17ad31f2a"
#define CEF_API_HASH_UNIVERSAL "1d8347d8e06dc0dd17f882ca253e1c7bf43d5863"
#if defined(OS_WIN)
#define CEF_API_HASH_PLATFORM "43e4bd792e5b0bbe8004dcecca0997803d1effbb"
#define CEF_API_HASH_PLATFORM "b6865f1992a10dcefc0bbc450cf296b648003271"
#elif defined(OS_MAC)
#define CEF_API_HASH_PLATFORM "a3e1a9d8eeda6791d3a990d0e94407b4d0569aca"
#define CEF_API_HASH_PLATFORM "d04c2a5ab471493c185eb7c7aa894bc4a79d5a7c"
#elif defined(OS_LINUX)
#define CEF_API_HASH_PLATFORM "63cbcad670b313815a78186a5e029c8b09339e36"
#define CEF_API_HASH_PLATFORM "d7d4cbffa4a798fea97e7b9f3610b5cb803d949e"
#endif
#ifdef __cplusplus

View File

@ -128,6 +128,29 @@ class CefWindowDelegate : public CefPanelDelegate {
/*--cef()--*/
virtual bool IsFrameless(CefRefPtr<CefWindow> window) { return false; }
///
/// Return true if |window| should be created with standard window buttons
/// like close, minimize and zoom.
///
/*--cef()--*/
virtual bool WithStandardWindowButtons(CefRefPtr<CefWindow> window) {
return false;
}
///
/// Return whether the titlebar height should be overridden,
/// and sets the height of the titlebar in |titlebar_height|.
/// On macOS, it can also be used to adjust the vertical position
/// of the traffic light buttons in frameless windows.
/// The buttons will be positioned halfway down the titlebar
/// at a height of |titlebar_height| / 2.
///
/*--cef()--*/
virtual bool GetTitlebarHeight(CefRefPtr<CefWindow> window,
float* titlebar_height) {
return false;
}
///
/// Return true if |window| can be resized.
///

View File

@ -0,0 +1,37 @@
// Copyright 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.
#ifndef CEF_LIBCEF_BROWSER_VIEWS_NATIVE_WIDGET_MAC_H_
#define CEF_LIBCEF_BROWSER_VIEWS_NATIVE_WIDGET_MAC_H_
#pragma once
#include "third_party/abseil-cpp/absl/types/optional.h"
#include "ui/views/widget/native_widget_mac.h"
class CefNativeWidgetMac : public views::NativeWidgetMac {
public:
CefNativeWidgetMac(views::internal::NativeWidgetDelegate* delegate,
bool is_frameless,
bool with_window_buttons,
absl::optional<float> title_bar_height);
~CefNativeWidgetMac() override = default;
CefNativeWidgetMac(const CefNativeWidgetMac&) = delete;
CefNativeWidgetMac& operator=(const CefNativeWidgetMac&) = delete;
protected:
// NativeWidgetMac:
NativeWidgetMacNSWindow* CreateNSWindow(
const remote_cocoa::mojom::CreateWindowParams* params) override;
void GetWindowFrameTitlebarHeight(bool* override_titlebar_height,
float* titlebar_height) override;
private:
const bool is_frameless_;
const bool with_window_buttons_;
const absl::optional<float> title_bar_height_;
};
#endif // CEF_LIBCEF_BROWSER_VIEWS_NATIVE_WIDGET_MAC_H_

View File

@ -0,0 +1,52 @@
// Copyright 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 "libcef/browser/views/native_widget_mac.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)
: views::NativeWidgetMac(delegate),
is_frameless_(is_frameless),
with_window_buttons_(with_window_buttons),
title_bar_height_(title_bar_height) {}
NativeWidgetMacNSWindow* CefNativeWidgetMac::CreateNSWindow(
const remote_cocoa::mojom::CreateWindowParams* params) {
NSUInteger style_mask =
NSWindowStyleMaskTitled | NSWindowStyleMaskMiniaturizable |
NSWindowStyleMaskClosable | NSWindowStyleMaskResizable |
NSWindowStyleMaskTexturedBackground;
auto window = [[CefNSWindow alloc] initWithStyle:style_mask
isFrameless:is_frameless_];
if (is_frameless_) {
[window setTitlebarAppearsTransparent:YES];
[window setTitleVisibility:NSWindowTitleHidden];
}
if (!with_window_buttons_) {
[[window standardWindowButton:NSWindowCloseButton] setHidden:YES];
[[window standardWindowButton:NSWindowMiniaturizeButton] setHidden:YES];
[[window standardWindowButton:NSWindowZoomButton] setHidden:YES];
}
return window;
}
void CefNativeWidgetMac::GetWindowFrameTitlebarHeight(
bool* override_titlebar_height,
float* titlebar_height) {
if (title_bar_height_) {
*override_titlebar_height = true;
*titlebar_height = title_bar_height_.value();
} else {
views::NativeWidgetMac::GetWindowFrameTitlebarHeight(
override_titlebar_height, titlebar_height);
}
}

View File

@ -0,0 +1,20 @@
// Copyright 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.
#ifndef CEF_LIBCEF_BROWSER_VIEWS_NS_WINDOW_H_
#define CEF_LIBCEF_BROWSER_VIEWS_NS_WINDOW_H_
#pragma once
#include "components/remote_cocoa/app_shim/native_widget_mac_nswindow.h"
@interface CefNSWindow : NativeWidgetMacNSWindow {
@private
bool is_frameless_;
}
- (id)initWithStyle:(NSUInteger)style_mask isFrameless:(bool)is_frameless;
- (BOOL)shouldCenterTrafficLights;
@end
#endif // CEF_LIBCEF_BROWSER_VIEWS_NS_WINDOW_H_

View File

@ -0,0 +1,104 @@
// Copyright 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 "libcef/browser/views/ns_window.h"
#include "base/i18n/rtl.h"
#include "components/remote_cocoa/app_shim/native_widget_ns_window_bridge.h"
#include "components/remote_cocoa/common/native_widget_ns_window_host.mojom.h"
#include "ui/base/cocoa/window_size_constants.h"
@interface CefThemeFrame : NativeWidgetMacNSWindowTitledFrame
@end
// NSThemeFrame (PrivateAPI) definitions.
@interface NSThemeFrame (PrivateAPI)
- (void)setStyleMask:(NSUInteger)styleMask;
- (CGFloat)_titlebarHeight;
- (BOOL)_shouldCenterTrafficLights;
@end
@implementation CefThemeFrame {
bool in_full_screen_;
}
// NSThemeFrame (PrivateAPI) overrides.
- (void)setStyleMask:(NSUInteger)styleMask {
in_full_screen_ = (styleMask & NSWindowStyleMaskFullScreen) != 0;
[super setStyleMask:styleMask];
}
- (CGFloat)_titlebarHeight {
if (!in_full_screen_) {
bool override_titlebar_height = false;
float titlebar_height = 0;
auto* window = base::mac::ObjCCast<CefNSWindow>([self window]);
if (auto* bridge = [window bridge]) {
bridge->host()->GetWindowFrameTitlebarHeight(&override_titlebar_height,
&titlebar_height);
if (override_titlebar_height)
return titlebar_height;
}
}
return [super _titlebarHeight];
}
- (BOOL)_shouldCenterTrafficLights {
auto* window = base::mac::ObjCCast<CefNSWindow>([self window]);
return [window shouldCenterTrafficLights];
}
- (BOOL)_shouldFlipTrafficLightsForRTL {
return base::i18n::IsRTL() ? YES : NO;
}
@end
@interface NSWindow (PrivateAPI)
+ (Class)frameViewClassForStyleMask:(NSUInteger)windowStyle;
@end
@implementation CefNSWindow
- (id)initWithStyle:(NSUInteger)style_mask isFrameless:(bool)is_frameless {
if ((self = [super initWithContentRect:ui::kWindowSizeDeterminedLater
styleMask:style_mask
backing:NSBackingStoreBuffered
defer:NO])) {
is_frameless_ = is_frameless;
}
return self;
}
- (BOOL)shouldCenterTrafficLights {
return is_frameless_ ? YES : NO;
}
// NSWindow overrides.
- (NSRect)contentRectForFrameRect:(NSRect)frameRect {
if (is_frameless_) {
return frameRect;
}
return [super contentRectForFrameRect:frameRect];
}
- (NSRect)frameRectForContentRect:(NSRect)contentRect {
if (is_frameless_) {
return contentRect;
}
return [super frameRectForContentRect:contentRect];
}
// NSWindow (PrivateAPI) overrides.
+ (Class)frameViewClassForStyleMask:(NSUInteger)windowStyle {
if (Class custom_frame = [CefThemeFrame class]) {
return custom_frame;
}
return [super frameViewClassForStyleMask:windowStyle];
}
@end

View File

@ -9,6 +9,7 @@
#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"
@ -21,8 +22,12 @@ class Point;
}
namespace views {
class NativeWidget;
class Widget;
namespace internal {
class NativeWidgetDelegate;
}
} // namespace views
#define CEF_REQUIRE_VALID_RETURN(ret) \
if (!ParentClass::IsValid()) \
@ -141,6 +146,12 @@ CefWindowHandle GetWindowHandle(views::Widget* widget);
// Returns the platform window handle for |window|. May return nullptr.
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);
} // namespace view_util
#endif // CEF_LIBCEF_BROWSER_VIEWS_VIEW_UTIL_H_

View File

@ -6,6 +6,8 @@
#include "ui/aura/window.h"
#include "ui/aura/window_tree_host.h"
#include "ui/views/widget/native_widget.h"
#include "ui/views/widget/native_widget_delegate.h"
#include "ui/views/widget/widget.h"
namespace view_util {
@ -40,4 +42,12 @@ CefWindowHandle GetWindowHandle(gfx::NativeWindow window) {
return kNullWindowHandle;
}
views::NativeWidget* CreateNativeWidget(
views::internal::NativeWidgetDelegate* delegate,
bool is_frameless,
bool with_window_buttons,
absl::optional<float> title_bar_height) {
return nullptr;
}
} // namespace view_util

View File

@ -7,6 +7,7 @@
#import <Cocoa/Cocoa.h>
#include "include/internal/cef_types_mac.h"
#include "libcef/browser/views/native_widget_mac.h"
#include "ui/views/widget/widget.h"
@ -44,4 +45,12 @@ CefWindowHandle GetWindowHandle(gfx::NativeWindow window) {
return kNullWindowHandle;
}
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);
}
} // namespace view_util

View File

@ -312,6 +312,15 @@ void CefWindowView::CreateWidget(gfx::AcceleratedWidget parent_widget) {
DCHECK(!params.bounds.IsEmpty());
} 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);
can_resize = cef_delegate()->CanResize(cef_window);
const auto show_state = cef_delegate()->GetInitialShowState(cef_window);
@ -657,3 +666,14 @@ 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;
}

View File

@ -14,6 +14,7 @@
#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"
@ -119,6 +120,9 @@ class CefWindowView
void MoveOverlaysIfNecessary();
absl::optional<float> GetTitlebarHeight(
const CefRefPtr<CefWindow>& window) const;
// Not owned by this object.
Delegate* window_delegate_;

View File

@ -9,7 +9,7 @@
// implementations. See the translator.README.txt file in the tools directory
// for more information.
//
// $hash=af80a36cdcb47a18eb1ac8bc3315dfd322f4e96e$
// $hash=18f715de465689a4e8484bbced8ad92d9434438a$
//
#include "libcef_dll/cpptoc/views/window_delegate_cpptoc.h"
@ -270,6 +270,62 @@ window_delegate_is_frameless(struct _cef_window_delegate_t* self,
return _retval;
}
int CEF_CALLBACK window_delegate_with_standard_window_buttons(
struct _cef_window_delegate_t* self,
cef_window_t* window) {
shutdown_checker::AssertNotShutdown();
// AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
DCHECK(self);
if (!self) {
return 0;
}
// Verify param: window; type: refptr_diff
DCHECK(window);
if (!window) {
return 0;
}
// Execute
bool _retval = CefWindowDelegateCppToC::Get(self)->WithStandardWindowButtons(
CefWindowCToCpp::Wrap(window));
// Return type: bool
return _retval;
}
int CEF_CALLBACK
window_delegate_get_titlebar_height(struct _cef_window_delegate_t* self,
cef_window_t* window,
float* titlebar_height) {
shutdown_checker::AssertNotShutdown();
// AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
DCHECK(self);
if (!self) {
return 0;
}
// Verify param: window; type: refptr_diff
DCHECK(window);
if (!window) {
return 0;
}
// Verify param: titlebar_height; type: simple_byaddr
DCHECK(titlebar_height);
if (!titlebar_height) {
return 0;
}
// Execute
bool _retval = CefWindowDelegateCppToC::Get(self)->GetTitlebarHeight(
CefWindowCToCpp::Wrap(window), titlebar_height);
// Return type: bool
return _retval;
}
int CEF_CALLBACK window_delegate_can_resize(struct _cef_window_delegate_t* self,
cef_window_t* window) {
shutdown_checker::AssertNotShutdown();
@ -705,6 +761,9 @@ CefWindowDelegateCppToC::CefWindowDelegateCppToC() {
GetStruct()->get_initial_bounds = window_delegate_get_initial_bounds;
GetStruct()->get_initial_show_state = window_delegate_get_initial_show_state;
GetStruct()->is_frameless = window_delegate_is_frameless;
GetStruct()->with_standard_window_buttons =
window_delegate_with_standard_window_buttons;
GetStruct()->get_titlebar_height = window_delegate_get_titlebar_height;
GetStruct()->can_resize = window_delegate_can_resize;
GetStruct()->can_maximize = window_delegate_can_maximize;
GetStruct()->can_minimize = window_delegate_can_minimize;

View File

@ -9,7 +9,7 @@
// implementations. See the translator.README.txt file in the tools directory
// for more information.
//
// $hash=18f601c8e152c39928595e1f02c9274f0dc6ce8a$
// $hash=40aea12873a3c8803c9d2d6c06a0270197ead58e$
//
#include "libcef_dll/ctocpp/views/window_delegate_ctocpp.h"
@ -257,6 +257,63 @@ bool CefWindowDelegateCToCpp::IsFrameless(CefRefPtr<CefWindow> window) {
return _retval ? true : false;
}
NO_SANITIZE("cfi-icall")
bool CefWindowDelegateCToCpp::WithStandardWindowButtons(
CefRefPtr<CefWindow> window) {
shutdown_checker::AssertNotShutdown();
cef_window_delegate_t* _struct = GetStruct();
if (CEF_MEMBER_MISSING(_struct, with_standard_window_buttons)) {
return false;
}
// AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
// Verify param: window; type: refptr_diff
DCHECK(window.get());
if (!window.get()) {
return false;
}
// Execute
int _retval = _struct->with_standard_window_buttons(
_struct, CefWindowCppToC::Wrap(window));
// Return type: bool
return _retval ? true : false;
}
NO_SANITIZE("cfi-icall")
bool CefWindowDelegateCToCpp::GetTitlebarHeight(CefRefPtr<CefWindow> window,
float* titlebar_height) {
shutdown_checker::AssertNotShutdown();
cef_window_delegate_t* _struct = GetStruct();
if (CEF_MEMBER_MISSING(_struct, get_titlebar_height)) {
return false;
}
// AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
// Verify param: window; type: refptr_diff
DCHECK(window.get());
if (!window.get()) {
return false;
}
// Verify param: titlebar_height; type: simple_byaddr
DCHECK(titlebar_height);
if (!titlebar_height) {
return false;
}
// Execute
int _retval = _struct->get_titlebar_height(
_struct, CefWindowCppToC::Wrap(window), titlebar_height);
// Return type: bool
return _retval ? true : false;
}
NO_SANITIZE("cfi-icall")
bool CefWindowDelegateCToCpp::CanResize(CefRefPtr<CefWindow> window) {
shutdown_checker::AssertNotShutdown();

View File

@ -9,7 +9,7 @@
// implementations. See the translator.README.txt file in the tools directory
// for more information.
//
// $hash=1a923e68b1e07234f97d3c219cc70cc91c118a77$
// $hash=d100d8866a7eab2a163d4ddb3cacd00141f65757$
//
#ifndef CEF_LIBCEF_DLL_CTOCPP_VIEWS_WINDOW_DELEGATE_CTOCPP_H_
@ -50,6 +50,9 @@ class CefWindowDelegateCToCpp
CefRect GetInitialBounds(CefRefPtr<CefWindow> window) override;
cef_show_state_t GetInitialShowState(CefRefPtr<CefWindow> window) override;
bool IsFrameless(CefRefPtr<CefWindow> window) override;
bool WithStandardWindowButtons(CefRefPtr<CefWindow> window) override;
bool GetTitlebarHeight(CefRefPtr<CefWindow> window,
float* titlebar_height) override;
bool CanResize(CefRefPtr<CefWindow> window) override;
bool CanMaximize(CefRefPtr<CefWindow> window) override;
bool CanMinimize(CefRefPtr<CefWindow> window) override;

View File

@ -5,6 +5,7 @@
#include "tests/cefclient/browser/views_overlay_controls.h"
#include <algorithm>
#include <array>
#include <string>
#include "include/views/cef_box_layout.h"
@ -34,9 +35,37 @@ std::string GetLabel(ViewsOverlayControls::Command command, bool maximized) {
return std::string();
}
std::array<ViewsOverlayControls::Command, 3> GetButtons() {
#if defined(OS_MAC)
return {ViewsOverlayControls::Command::kClose,
ViewsOverlayControls::Command::kMaximize,
ViewsOverlayControls::Command::kMinimize};
#else
return {ViewsOverlayControls::Command::kMinimize,
ViewsOverlayControls::Command::kMaximize,
ViewsOverlayControls::Command::kClose};
#endif
}
cef_docking_mode_t GetPanelDockingMode() {
#if defined(OS_MAC)
return CEF_DOCKING_MODE_TOP_LEFT;
#else
return CEF_DOCKING_MODE_TOP_RIGHT;
#endif
}
cef_docking_mode_t GetMenuDockingMode() {
#if defined(OS_MAC)
return CEF_DOCKING_MODE_TOP_RIGHT;
#else
return CEF_DOCKING_MODE_TOP_LEFT;
#endif
}
} // namespace
ViewsOverlayControls::ViewsOverlayControls() = default;
ViewsOverlayControls::ViewsOverlayControls(bool with_window_buttons)
: with_window_buttons_(with_window_buttons) {}
void ViewsOverlayControls::Initialize(CefRefPtr<CefWindow> window,
CefRefPtr<CefMenuButton> menu_button,
@ -49,9 +78,11 @@ void ViewsOverlayControls::Initialize(CefRefPtr<CefWindow> window,
window_ = window;
window_maximized_ = window_->IsMaximized();
// Window control buttons. These controls are currently text which means that
// we can't use a transparent background because subpixel text rendering will
// break. See comments on the related DCHECK in Label::PaintText.
if (with_window_buttons_) {
// Window control buttons. These controls are currently text which means
// that we can't use a transparent background because subpixel text
// rendering will break.
// See comments on the related DCHECK in Label::PaintText.
panel_ = CefPanel::CreatePanel(nullptr);
views_style::ApplyTo(panel_);
@ -60,19 +91,18 @@ void ViewsOverlayControls::Initialize(CefRefPtr<CefWindow> window,
panel_layout_settings.horizontal = true;
panel_->SetToBoxLayout(panel_layout_settings);
panel_->AddChildView(CreateButton(ViewsOverlayControls::Command::kMinimize));
panel_->AddChildView(CreateButton(ViewsOverlayControls::Command::kMaximize));
panel_->AddChildView(CreateButton(ViewsOverlayControls::Command::kClose));
panel_controller_ =
window->AddOverlayView(panel_, CEF_DOCKING_MODE_TOP_RIGHT);
for (auto button : GetButtons()) {
panel_->AddChildView(CreateButton(button));
}
panel_controller_ = window->AddOverlayView(panel_, GetPanelDockingMode());
panel_controller_->SetInsets(CefInsets(kInsets, kInsets, 0, kInsets));
panel_controller_->SetVisible(true);
}
// Menu button.
menu_button->SetBackgroundColor(kBackgroundColor);
menu_controller_ =
window_->AddOverlayView(menu_button, CEF_DOCKING_MODE_TOP_LEFT);
menu_controller_->SetInsets(CefInsets(kInsets, kInsets, 0, 0));
menu_controller_ = window_->AddOverlayView(menu_button, GetMenuDockingMode());
menu_controller_->SetInsets(CefInsets(kInsets, kInsets, 0, kInsets));
menu_controller_->SetVisible(true);
// Location bar. Will be made visible in UpdateControls().
@ -87,8 +117,10 @@ void ViewsOverlayControls::Initialize(CefRefPtr<CefWindow> window,
void ViewsOverlayControls::Destroy() {
window_ = nullptr;
panel_ = nullptr;
if (panel_controller_) {
panel_controller_->Destroy();
panel_controller_ = nullptr;
}
menu_controller_->Destroy();
menu_controller_ = nullptr;
location_bar_ = nullptr;
@ -180,7 +212,7 @@ CefRefPtr<CefLabelButton> ViewsOverlayControls::CreateButton(Command command) {
}
void ViewsOverlayControls::MaybeUpdateMaximizeButton() {
if (window_->IsMaximized() == window_maximized_) {
if (!with_window_buttons_ || window_->IsMaximized() == window_maximized_) {
return;
}
window_maximized_ = !window_maximized_;

View File

@ -25,7 +25,7 @@ class ViewsOverlayControls : public CefButtonDelegate {
kClose,
};
ViewsOverlayControls();
explicit ViewsOverlayControls(bool with_window_buttons);
void Initialize(CefRefPtr<CefWindow> window,
CefRefPtr<CefMenuButton> menu_button,
@ -53,6 +53,7 @@ class ViewsOverlayControls : public CefButtonDelegate {
// Window control buttons.
CefRefPtr<CefPanel> panel_;
CefRefPtr<CefOverlayController> panel_controller_;
const bool with_window_buttons_;
// Location bar.
CefRefPtr<CefView> location_bar_;

View File

@ -34,6 +34,11 @@ const char kDefaultExtensionIcon[] = "window_icon";
constexpr int kDefaultWidth = 800;
constexpr int kDefaultHeight = 600;
#if defined(OS_MAC)
constexpr int kTitleBarHeight = 35;
constexpr int kWindowButtonsWidth = 80;
#endif
// Control IDs for Views in the top-level Window.
enum ControlIds {
ID_WINDOW = 1,
@ -106,6 +111,22 @@ void AddFileMenuItems(CefRefPtr<CefMenuModel> file_menu) {
true);
}
CefBrowserViewDelegate::ChromeToolbarType CalculateChromeToolbarType(
const std::string& toolbar_type,
bool hide_toolbar,
bool with_overlay_controls) {
if (!MainContext::Get()->UseChromeRuntime() || toolbar_type == "none" ||
hide_toolbar) {
return CEF_CTT_NONE;
}
if (toolbar_type == "location") {
return CEF_CTT_LOCATION;
}
return with_overlay_controls ? CEF_CTT_LOCATION : CEF_CTT_NORMAL;
}
} // namespace
// static
@ -278,17 +299,13 @@ void ViewsWindow::SetDraggableRegions(
return;
}
std::vector<CefDraggableRegion> window_regions;
// Convert the regions from BrowserView to Window coordinates.
std::vector<CefDraggableRegion>::const_iterator it = regions.begin();
for (; it != regions.end(); ++it) {
CefDraggableRegion region = *it;
std::vector<CefDraggableRegion> window_regions = regions;
for (auto& region : window_regions) {
CefPoint origin = CefPoint(region.bounds.x, region.bounds.y);
browser_view_->ConvertPointToWindow(origin);
region.bounds.x = origin.x;
region.bounds.y = origin.y;
window_regions.push_back(region);
}
if (overlay_controls_) {
@ -653,6 +670,14 @@ void ViewsWindow::OnWindowBoundsChanged(CefRefPtr<CefWindow> window,
// Track the last visible bounds for window restore purposes.
last_visible_bounds_ = new_bounds;
}
#if defined(OS_MAC)
if (frameless_ && with_standard_buttons_ && top_toolbar_) {
auto insets = top_toolbar_->GetInsets();
insets.left = window->IsFullscreen() ? 0 : kWindowButtonsWidth;
top_toolbar_->SetInsets(insets);
}
#endif
}
bool ViewsWindow::CanClose(CefRefPtr<CefWindow> window) {
@ -701,6 +726,24 @@ bool ViewsWindow::IsFrameless(CefRefPtr<CefWindow> window) {
return frameless_;
}
bool ViewsWindow::WithStandardWindowButtons(CefRefPtr<CefWindow> window) {
CEF_REQUIRE_UI_THREAD();
return with_standard_buttons_;
}
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;
return true;
}
#endif
return false;
}
bool ViewsWindow::CanResize(CefRefPtr<CefWindow> window) {
CEF_REQUIRE_UI_THREAD();
// Don't allow windows hosting extensions to resize.
@ -815,7 +858,9 @@ void ViewsWindow::OnWindowChanged(CefRefPtr<CefView> view, bool added) {
}
if (with_overlay_controls_) {
overlay_controls_ = new ViewsOverlayControls();
// Add window buttons if we don't have standard ones
const bool with_window_buttons = !with_standard_buttons_;
overlay_controls_ = new ViewsOverlayControls(with_window_buttons);
overlay_controls_->Initialize(window_, CreateMenuButton(),
CreateLocationBar(),
chrome_toolbar_type_ != CEF_CTT_NONE);
@ -865,6 +910,10 @@ ViewsWindow::ViewsWindow(Delegate* delegate,
const bool hide_frame = command_line->HasSwitch(switches::kHideFrame);
const bool hide_overlays = command_line->HasSwitch(switches::kHideOverlays);
const bool hide_toolbar =
hide_frame && hide_overlays && !delegate_->WithControls();
const bool show_window_buttons =
command_line->HasSwitch(switches::kShowWindowButtons);
// Without a window frame.
frameless_ = hide_frame || delegate_->WithExtension();
@ -873,20 +922,13 @@ ViewsWindow::ViewsWindow(Delegate* delegate,
with_overlay_controls_ =
hide_frame && !hide_overlays && !delegate_->WithControls();
if (MainContext::Get()->UseChromeRuntime()) {
// If window has frame or flag passed explicitly
with_standard_buttons_ = !frameless_ || show_window_buttons;
const std::string& toolbar_type =
command_line->GetSwitchValue(switches::kShowChromeToolbar);
if (toolbar_type == "none") {
chrome_toolbar_type_ = CEF_CTT_NONE;
} else if (toolbar_type == "location") {
chrome_toolbar_type_ = CEF_CTT_LOCATION;
} else {
chrome_toolbar_type_ =
with_overlay_controls_ ? CEF_CTT_LOCATION : CEF_CTT_NORMAL;
}
} else {
chrome_toolbar_type_ = CEF_CTT_NONE;
}
chrome_toolbar_type_ = CalculateChromeToolbarType(toolbar_type, hide_toolbar,
with_overlay_controls_);
#if !defined(OS_MAC)
// On Mac we don't show a top menu on the window. The options are available in
@ -1025,9 +1067,8 @@ void ViewsWindow::AddControls() {
top_panel->SetToBoxLayout(top_panel_layout_settings);
// Add the buttons and URL textfield to |top_panel|.
for (size_t i = 0U; i < browse_buttons.size(); ++i) {
top_panel->AddChildView(browse_buttons[i]);
}
for (auto& browse_button : browse_buttons)
top_panel->AddChildView(browse_button);
top_panel->AddChildView(location_bar_);
UpdateExtensionControls();
@ -1043,6 +1084,14 @@ void ViewsWindow::AddControls() {
top_toolbar_ = top_panel;
}
#if defined(OS_MAC)
if (frameless_ && with_standard_buttons_) {
auto insets = top_toolbar_->GetInsets();
insets.left = kWindowButtonsWidth;
top_toolbar_->SetInsets(insets);
}
#endif
// Add the top panel and browser view to |window|.
int top_index = 0;
if (top_menu_panel) {
@ -1061,8 +1110,10 @@ void ViewsWindow::AddControls() {
// Lay out |window| again with the new button sizes.
window_->Layout();
const int buttons_number = static_cast<int>(browse_buttons.size());
// Minimum window width is the size of all buttons plus some extra.
min_width = browse_buttons[0]->GetBounds().width * 4 +
min_width = browse_buttons[0]->GetBounds().width * buttons_number +
menu_button_->GetBounds().width + 100;
}

View File

@ -174,6 +174,9 @@ class ViewsWindow : public CefBrowserViewDelegate,
CefRect GetInitialBounds(CefRefPtr<CefWindow> window) override;
cef_show_state_t GetInitialShowState(CefRefPtr<CefWindow> window) override;
bool IsFrameless(CefRefPtr<CefWindow> window) override;
bool WithStandardWindowButtons(CefRefPtr<CefWindow> window) override;
bool GetTitlebarHeight(CefRefPtr<CefWindow> window,
float* titlebar_height) override;
bool CanResize(CefRefPtr<CefWindow> window) override;
bool CanClose(CefRefPtr<CefWindow> window) override;
bool OnAccelerator(CefRefPtr<CefWindow> window, int command_id) override;
@ -238,6 +241,7 @@ class ViewsWindow : public CefBrowserViewDelegate,
bool frameless_;
bool with_controls_;
bool with_overlay_controls_;
bool with_standard_buttons_;
ChromeToolbarType chrome_toolbar_type_;
CefRefPtr<CefWindow> window_;

View File

@ -52,6 +52,7 @@ const char kHideChromeStatusBubble[] = "hide-chrome-status-bubble";
const char kUseDefaultPopup[] = "use-default-popup";
const char kUseClientDialogs[] = "use-client-dialogs";
const char kUseTestHttpServer[] = "use-test-http-server";
const char kShowWindowButtons[] = "show-window-buttons";
} // namespace switches
} // namespace client

View File

@ -46,6 +46,7 @@ extern const char kHideChromeStatusBubble[];
extern const char kUseDefaultPopup[];
extern const char kUseClientDialogs[];
extern const char kUseTestHttpServer[];
extern const char kShowWindowButtons[];
} // namespace switches
} // namespace client