Skip to content

Commit

Permalink
views: mac: Fix frameless window behavior (fixes issue chromiumembedd…
Browse files Browse the repository at this point in the history
…ed#3189)

Frameless windows now display as expected. Default traffic light buttons can
optionally be shown at configurable vertical position. Layout respects text
direction.
  • Loading branch information
nik-sp authored and magreenblatt committed Mar 8, 2023
1 parent 6926287 commit f6de034
Show file tree
Hide file tree
Showing 22 changed files with 581 additions and 59 deletions.
4 changes: 4 additions & 0 deletions BUILD.gn
Expand Up @@ -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",
Expand Down
21 changes: 20 additions & 1 deletion include/capi/views/cef_window_delegate_capi.h
Expand Up @@ -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_
Expand Down Expand Up @@ -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.
///
Expand Down
8 changes: 4 additions & 4 deletions include/cef_api_hash.h
Expand Up @@ -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
Expand Down
23 changes: 23 additions & 0 deletions include/views/cef_window_delegate.h
Expand Up @@ -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.
///
Expand Down
37 changes: 37 additions & 0 deletions libcef/browser/views/native_widget_mac.h
@@ -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_
52 changes: 52 additions & 0 deletions libcef/browser/views/native_widget_mac.mm
@@ -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);
}
}
20 changes: 20 additions & 0 deletions libcef/browser/views/ns_window.h
@@ -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_
104 changes: 104 additions & 0 deletions libcef/browser/views/ns_window.mm
@@ -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
11 changes: 11 additions & 0 deletions libcef/browser/views/view_util.h
Expand Up @@ -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"

Expand All @@ -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()) \
Expand Down Expand Up @@ -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_
10 changes: 10 additions & 0 deletions libcef/browser/views/view_util_aura.cc
Expand Up @@ -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 {
Expand Down Expand Up @@ -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
9 changes: 9 additions & 0 deletions libcef/browser/views/view_util_mac.mm
Expand Up @@ -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"

Expand Down Expand Up @@ -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

0 comments on commit f6de034

Please sign in to comment.