macOS: Add support for building clients with ARC enabled (fixes issue #2623).

Under ARC (Automatic Reference Counting), assigning to an Objective-C
pointer has different semantics than assigning to a void* pointer.
This makes it dangerous to treat the same memory address as an
Objective-C pointer in some cases and as a "regular C pointer" in
other cases.

This change removes the conditional type defines and instead uses
void* everywhere. Explicit type casting in combination with ARC
annotations makes it safe to get typed Objective-C pointers from the
void* pointers.

This change enables ARC by default in the CEF binary distribution CMake
configuration for the cefclient and cefsimple sample applications. It can be
disabled by adding `-DOPTION_USE_ARC=Off` to the CMake command line.

ARC is not supported when building Chromium due to the substantial
number of changes that would be required in the Chromium code base.
This commit is contained in:
Jesper Papmehl-Dufay 2019-04-23 17:17:56 +00:00 committed by Marshall Greenblatt
parent 491253fa03
commit 019611c764
22 changed files with 1414 additions and 980 deletions

View File

@ -37,29 +37,37 @@
#include "include/internal/cef_string.h"
// Handle types.
#ifdef __cplusplus
#ifdef __OBJC__
@class NSCursor;
@class NSEvent;
@class NSView;
#else
class NSCursor;
class NSEvent;
struct NSView;
#endif
#define cef_cursor_handle_t NSCursor*
#define cef_event_handle_t NSEvent*
#define cef_window_handle_t NSView*
#else
// Actually NSCursor*
#define cef_cursor_handle_t void*
// Acutally NSEvent*
#define cef_event_handle_t void*
// Actually NSView*
#define cef_window_handle_t void*
#endif
#define kNullCursorHandle NULL
#define kNullEventHandle NULL
#define kNullWindowHandle NULL
#ifdef __OBJC__
#if __has_feature(objc_arc)
#define CAST_CEF_CURSOR_HANDLE_TO_NSCURSOR(handle) ((__bridge NSCursor*)handle)
#define CAST_CEF_EVENT_HANDLE_TO_NSEVENT(handle) ((__bridge NSEvent*)handle)
#define CAST_CEF_WINDOW_HANDLE_TO_NSVIEW(handle) ((__bridge NSView*)handle)
#define CAST_NSCURSOR_TO_CEF_CURSOR_HANDLE(cursor) ((__bridge void*)cursor)
#define CAST_NSEVENT_TO_CEF_EVENT_HANDLE(event) ((__bridge void*)event)
#define CAST_NSVIEW_TO_CEF_WINDOW_HANDLE(view) ((__bridge void*)view)
#else // __has_feature(objc_arc)
#define CAST_CEF_CURSOR_HANDLE_TO_NSCURSOR(handle) ((NSCursor*)handle)
#define CAST_CEF_EVENT_HANDLE_TO_NSEVENT(handle) ((NSEvent*)handle)
#define CAST_CEF_WINDOW_HANDLE_TO_NSVIEW(handle) ((NSView*)handle)
#define CAST_NSCURSOR_TO_CEF_CURSOR_HANDLE(cursor) ((void*)cursor)
#define CAST_NSEVENT_TO_CEF_EVENT_HANDLE(event) ((void*)event)
#define CAST_NSVIEW_TO_CEF_WINDOW_HANDLE(view) ((void*)view)
#endif // __has_feature(objc_arc)
#endif // __OBJC__
#ifdef __cplusplus
extern "C" {
#endif

View File

@ -56,7 +56,7 @@
@end
// Receives notifications from the browser window. Will delete itself when done.
@interface CefWindowDelegate : NSObject<NSWindowDelegate> {
@interface CefWindowDelegate : NSObject <NSWindowDelegate> {
@private
CefBrowserHostImpl* browser_; // weak
NSWindow* window_;
@ -165,7 +165,8 @@ bool CefBrowserPlatformDelegateNativeMac::CreateHostWindow() {
NSWindow* newWnd = nil;
NSView* parentView = window_info_.parent_view;
NSView* parentView =
CAST_CEF_WINDOW_HANDLE_TO_NSVIEW(window_info_.parent_view);
NSRect contentRect = {{window_info_.x, window_info_.y},
{window_info_.width, window_info_.height}};
if (parentView == nil) {
@ -239,11 +240,11 @@ bool CefBrowserPlatformDelegateNativeMac::CreateHostWindow() {
}
void CefBrowserPlatformDelegateNativeMac::CloseHostWindow() {
if (window_info_.view != nil) {
[[window_info_.view window]
performSelectorOnMainThread:@selector(performClose:)
withObject:nil
waitUntilDone:NO];
NSView* nsview = CAST_CEF_WINDOW_HANDLE_TO_NSVIEW(window_info_.view);
if (nsview != nil) {
[[nsview window] performSelectorOnMainThread:@selector(performClose:)
withObject:nil
waitUntilDone:NO];
}
}
@ -275,7 +276,7 @@ gfx::Point CefBrowserPlatformDelegateNativeMac::GetScreenPoint(
if (windowless_handler_)
return windowless_handler_->GetParentScreenPoint(view);
NSView* nsview = window_info_.parent_view;
NSView* nsview = CAST_CEF_WINDOW_HANDLE_TO_NSVIEW(window_info_.parent_view);
if (nsview) {
NSRect bounds = [nsview bounds];
NSPoint view_pt = {view.x(), bounds.size.height - view.y()};
@ -336,8 +337,8 @@ void CefBrowserPlatformDelegateNativeMac::TranslateKeyEvent(
[[[NSString alloc] initWithCharacters:&key_event.unmodified_character
length:1] autorelease];
NSString* characters =
[[[NSString alloc] initWithCharacters:&key_event.character length:1]
autorelease];
[[[NSString alloc] initWithCharacters:&key_event.character
length:1] autorelease];
NSEvent* synthetic_event =
[NSEvent keyEventWithType:event_type

View File

@ -387,7 +387,7 @@ void CefFileDialogRunnerMac::Run(CefBrowserHostImpl* browser,
const FileChooserParams& params,
RunFileChooserCallback callback) {
int filter_index = params.selected_accept_filter;
NSView* owner = browser->GetWindowHandle();
NSView* owner = CAST_CEF_WINDOW_HANDLE_TO_NSVIEW(browser->GetWindowHandle());
if (params.mode == blink::mojom::FileChooserParams::Mode::kOpen ||
params.mode == blink::mojom::FileChooserParams::Mode::kOpenMultiple ||

View File

@ -152,6 +152,16 @@ endif()
#
if(OS_MACOSX)
option(OPTION_USE_ARC "Build with ARC (automatic Reference Counting) on macOS." ON)
if(OPTION_USE_ARC)
list(APPEND CEF_COMPILER_FLAGS
-fobjc-arc
)
set_target_properties(${target} PROPERTIES
CLANG_ENABLE_OBJC_ARC "YES"
)
endif()
# All sources required by the "cefclient" target. Generates an app bundle that
# is used only for the browser process.
set(CEFCLIENT_SRCS

View File

@ -13,6 +13,8 @@
namespace client {
class BrowserWindowOsrMacImpl;
// Represents a native child window hosting a single off-screen browser
// instance. The methods of this class must be called on the main thread unless
// otherwise indicated.
@ -88,17 +90,11 @@ class BrowserWindowOsrMac : public BrowserWindow,
void UpdateAccessibilityLocation(CefRefPtr<CefValue> value) OVERRIDE;
private:
// Create the NSView.
void Create(ClientWindowHandle parent_handle, const CefRect& rect);
// The below members will only be accessed on the main thread which should be
// the same as the CEF UI thread.
OsrRenderer renderer_;
ClientWindowHandle nsview_;
bool hidden_;
bool painting_popup_;
scoped_ptr<BrowserWindowOsrMacImpl> impl_;
DISALLOW_COPY_AND_ASSIGN(BrowserWindowOsrMac);
friend class BrowserWindowOsrMacImpl;
};
} // namespace client

File diff suppressed because it is too large Load Diff

View File

@ -52,11 +52,11 @@ void BrowserWindowStdMac::ShowPopup(ClientWindowHandle parent_handle,
size_t height) {
REQUIRE_MAIN_THREAD();
NSView* browser_view = GetWindowHandle();
NSView* browser_view = CAST_CEF_WINDOW_HANDLE_TO_NSVIEW(GetWindowHandle());
// Re-parent |browser_view| to |parent_handle|.
[browser_view removeFromSuperview];
[parent_handle addSubview:browser_view];
[CAST_CEF_WINDOW_HANDLE_TO_NSVIEW(parent_handle) addSubview:browser_view];
NSSize size = NSMakeSize(static_cast<int>(width), static_cast<int>(height));
[browser_view setFrameSize:size];

View File

@ -18,15 +18,12 @@
#endif
#if defined(OS_MACOSX)
// Forward declaration of ObjC types used by cefclient and not provided by
// include/internal/cef_types_mac.h.
#ifdef __cplusplus
#define ClientNativeMacWindow void*
#ifdef __OBJC__
@class NSWindow;
#else
class NSWindow;
#endif
#endif
#define CAST_CLIENT_NATIVE_MAC_WINDOW_TO_NSWINDOW(native) \
(__bridge NSWindow*)native
#define CAST_NSWINDOW_TO_CLIENT_NATIVE_MAC_WINDOW(window) (__bridge void*)window
#endif // __OBJC__
#endif // defined OS_MACOSX
#endif // CEF_TESTS_CEFCLIENT_BROWSER_CLIENT_TYPES_H_

View File

@ -11,12 +11,19 @@
#include "include/cef_browser.h"
#if defined(OS_MACOSX)
#ifdef __OBJC__
@class NSObject;
#else
class NSObject;
#endif
typedef NSObject CefNativeAccessible;
typedef void CefNativeAccessible;
#if __OBJC__
#if __has_feature(objc_arc)
#define CAST_CEF_NATIVE_ACCESSIBLE_TO_NSOBJECT(accessible) \
(__bridge NSObject*)accessible
#define CAST_NSOBJECT_TO_CEF_NATIVE_ACCESSIBLE(object) \
(__bridge CefNativeAccessible*)object
#else // __has_feature(objc_arc)
#define CAST_CEF_NATIVE_ACCESSIBLE_TO_NSOBJECT(accessible) (NSObject*)accessible
#define CAST_NSOBJECT_TO_CEF_NATIVE_ACCESSIBLE(object) \
(__bridge CefNativeAccessible*)object
#endif // __has_feature(objc_arc)
#endif // __OBJC__
#elif defined(OS_WIN)
struct IAccessible;
typedef IAccessible CefNativeAccessible;

View File

@ -320,7 +320,9 @@ inline int MiddleY(const CefRect& rect) {
NSMutableArray* kids = [NSMutableArray arrayWithCapacity:numChilds];
for (int index = 0; index < numChilds; index++) {
client::OsrAXNode* child = node_->ChildAtIndex(index);
[kids addObject:child ? child->GetNativeAccessibleObject(node_) : nil];
[kids addObject:child ? CAST_CEF_NATIVE_ACCESSIBLE_TO_NSOBJECT(
child->GetNativeAccessibleObject(node_))
: nil];
}
return kids;
}
@ -332,7 +334,7 @@ inline int MiddleY(const CefRect& rect) {
NSPoint origin = NSMakePoint(cef_rect.x, cef_rect.y);
NSSize size = NSMakeSize(cef_rect.width, cef_rect.height);
NSView* view = node_->GetWindowHandle();
NSView* view = CAST_CEF_WINDOW_HANDLE_TO_NSVIEW(node_->GetWindowHandle());
origin.y = NSHeight([view bounds]) - origin.y;
NSPoint originInWindow = [view convertPoint:origin toView:nil];
@ -348,7 +350,7 @@ inline int MiddleY(const CefRect& rect) {
CefRect cef_rect = node_->AxLocation();
NSRect rect =
NSMakeRect(cef_rect.x, cef_rect.y, cef_rect.width, cef_rect.height);
NSView* view = node_->GetWindowHandle();
NSView* view = CAST_CEF_WINDOW_HANDLE_TO_NSVIEW(node_->GetWindowHandle());
rect = [[view window] convertRectToScreen:rect];
return rect.size;
}
@ -384,6 +386,7 @@ inline int MiddleY(const CefRect& rect) {
}
- (id)accessibilityAttributeValue:(NSString*)attribute {
NSObject* typed_parent = CAST_CEF_NATIVE_ACCESSIBLE_TO_NSOBJECT(parent_);
if (!node_)
return nil;
if ([attribute isEqualToString:NSAccessibilityRoleAttribute]) {
@ -397,16 +400,17 @@ inline int MiddleY(const CefRect& rect) {
accessibilityAttributeValue:NSAccessibilityFocusedUIElementAttribute];
return [NSNumber numberWithBool:[focusedElement isEqual:self]];
} else if ([attribute isEqualToString:NSAccessibilityParentAttribute]) {
return NSAccessibilityUnignoredAncestor(parent_);
return NSAccessibilityUnignoredAncestor(typed_parent);
} else if ([attribute isEqualToString:NSAccessibilityChildrenAttribute]) {
return NSAccessibilityUnignoredChildren([self getKids]);
} else if ([attribute isEqualToString:NSAccessibilityWindowAttribute]) {
// We're in the same window as our parent.
return [parent_ accessibilityAttributeValue:NSAccessibilityWindowAttribute];
return [typed_parent
accessibilityAttributeValue:NSAccessibilityWindowAttribute];
} else if ([attribute
isEqualToString:NSAccessibilityTopLevelUIElementAttribute]) {
// We're in the same top level element as our parent.
return [parent_
return [typed_parent
accessibilityAttributeValue:NSAccessibilityTopLevelUIElementAttribute];
} else if ([attribute isEqualToString:NSAccessibilityPositionAttribute]) {
return [NSValue valueWithPoint:[self position]];
@ -460,17 +464,18 @@ inline int MiddleY(const CefRect& rect) {
namespace client {
void OsrAXNode::NotifyAccessibilityEvent(std::string event_type) const {
NSView* view = CAST_CEF_WINDOW_HANDLE_TO_NSVIEW(GetWindowHandle());
if (event_type == "focus") {
NSAccessibilityPostNotification(
GetWindowHandle(), NSAccessibilityFocusedUIElementChangedNotification);
view, NSAccessibilityFocusedUIElementChangedNotification);
} else if (event_type == "textChanged") {
NSAccessibilityPostNotification(GetWindowHandle(),
NSAccessibilityPostNotification(view,
NSAccessibilityTitleChangedNotification);
} else if (event_type == "valueChanged") {
NSAccessibilityPostNotification(GetWindowHandle(),
NSAccessibilityPostNotification(view,
NSAccessibilityValueChangedNotification);
} else if (event_type == "textSelectionChanged") {
NSAccessibilityPostNotification(GetWindowHandle(),
NSAccessibilityPostNotification(view,
NSAccessibilityValueChangedNotification);
}
}
@ -478,7 +483,8 @@ void OsrAXNode::NotifyAccessibilityEvent(std::string event_type) const {
void OsrAXNode::Destroy() {
if (platform_accessibility_) {
NSAccessibilityPostNotification(
platform_accessibility_, NSAccessibilityUIElementDestroyedNotification);
CAST_CEF_NATIVE_ACCESSIBLE_TO_NSOBJECT(platform_accessibility_),
NSAccessibilityUIElementDestroyedNotification);
}
delete this;
@ -488,7 +494,8 @@ void OsrAXNode::Destroy() {
CefNativeAccessible* OsrAXNode::GetNativeAccessibleObject(
client::OsrAXNode* parent) {
if (!platform_accessibility_) {
platform_accessibility_ = [OsrAXNodeObject elementWithNode:this];
platform_accessibility_ = CAST_NSOBJECT_TO_CEF_NATIVE_ACCESSIBLE(
[OsrAXNodeObject elementWithNode:this]);
SetParent(parent);
}
return platform_accessibility_;

View File

@ -17,6 +17,10 @@
#include "tests/cefclient/browser/image_cache.h"
#include "tests/shared/browser/main_message_loop.h"
#if defined(OS_MACOSX) && __OBJC__
@class NSWindow;
#endif // defined(OS_MACOSX) && __OBJC__
namespace client {
// Used to configure how a RootWindow is created.
@ -117,7 +121,7 @@ class RootWindow
// called on the main thread.
static scoped_refptr<RootWindow> GetForBrowser(int browser_id);
#if defined(OS_MACOSX)
#if defined(OS_MACOSX) && __OBJC__
// Returns the RootWindow associated with the specified |window|. Must be
// called on the main thread.
static scoped_refptr<RootWindow> GetForNSWindow(NSWindow* window);

View File

@ -12,18 +12,10 @@
#include "tests/cefclient/browser/browser_window.h"
#include "tests/cefclient/browser/root_window.h"
#ifdef __OBJC__
@class NSWindow;
@class NSButton;
@class NSTextField;
#else
class NSWindow;
class NSButton;
class NSTextField;
#endif
namespace client {
class RootWindowMacImpl;
// OS X implementation of a top-level native window in the browser process.
// The methods of this class must be called on the main thread unless otherwise
// indicated.
@ -33,6 +25,9 @@ class RootWindowMac : public RootWindow, public BrowserWindow::Delegate {
RootWindowMac();
~RootWindowMac();
BrowserWindow* browser_window() const;
RootWindow::Delegate* delegate() const;
// RootWindow methods.
void Init(RootWindow::Delegate* delegate,
const RootWindowConfig& config,
@ -55,18 +50,6 @@ class RootWindowMac : public RootWindow, public BrowserWindow::Delegate {
bool WithWindowlessRendering() const OVERRIDE;
bool WithExtension() const OVERRIDE;
// Called by RootWindowDelegate after the associated NSWindow has been
// destroyed.
void WindowDestroyed();
BrowserWindow* browser_window() const { return browser_window_.get(); }
RootWindow::Delegate* delegate() const { return delegate_; }
private:
void CreateBrowserWindow(const std::string& startup_url);
void CreateRootWindow(const CefBrowserSettings& settings,
bool initially_hidden);
// BrowserWindow::Delegate methods.
void OnBrowserCreated(CefRefPtr<CefBrowser> browser) OVERRIDE;
void OnBrowserWindowDestroyed() OVERRIDE;
@ -80,34 +63,14 @@ class RootWindowMac : public RootWindow, public BrowserWindow::Delegate {
void OnSetDraggableRegions(
const std::vector<CefDraggableRegion>& regions) OVERRIDE;
void NotifyDestroyedIfDone();
void OnNativeWindowClosed();
// After initialization all members are only accessed on the main thread.
// Members set during initialization.
bool with_controls_;
bool with_osr_;
bool with_extension_;
bool is_popup_;
CefRect start_rect_;
scoped_ptr<BrowserWindow> browser_window_;
bool initialized_;
// Main window.
NSWindow* window_;
// Buttons.
NSButton* back_button_;
NSButton* forward_button_;
NSButton* reload_button_;
NSButton* stop_button_;
// URL text field.
NSTextField* url_textfield_;
bool window_destroyed_;
bool browser_destroyed_;
private:
CefRefPtr<RootWindowMacImpl> impl_;
DISALLOW_COPY_AND_ASSIGN(RootWindowMac);
friend class RootWindowMacImpl;
};
} // namespace client

File diff suppressed because it is too large Load Diff

View File

@ -10,6 +10,8 @@
namespace client {
class TempWindowMacImpl;
// Represents a singleton hidden window that acts as a temporary parent for
// popup browsers. Only accessed on the UI thread.
class TempWindowMac {
@ -26,7 +28,7 @@ class TempWindowMac {
TempWindowMac();
~TempWindowMac();
NSWindow* window_;
scoped_ptr<TempWindowMacImpl> impl_;
DISALLOW_COPY_AND_ASSIGN(TempWindowMac);
};

View File

@ -17,29 +17,43 @@ TempWindowMac* g_temp_window = NULL;
} // namespace
TempWindowMac::TempWindowMac() : window_(nil) {
DCHECK(!g_temp_window);
g_temp_window = this;
class TempWindowMacImpl {
public:
TempWindowMacImpl() {
// Create a borderless non-visible 1x1 window.
window_ = [[NSWindow alloc] initWithContentRect:NSMakeRect(0, 0, 1, 1)
styleMask:NSBorderlessWindowMask
backing:NSBackingStoreBuffered
defer:NO];
CHECK(window_);
}
~TempWindowMacImpl() {
DCHECK(window_);
[window_ close];
}
// Create a borderless non-visible 1x1 window.
window_ = [[NSWindow alloc] initWithContentRect:NSMakeRect(0, 0, 1, 1)
styleMask:NSBorderlessWindowMask
backing:NSBackingStoreBuffered
defer:NO];
CHECK(window_);
private:
NSWindow* window_;
friend class TempWindowMac;
};
TempWindowMac::TempWindowMac() {
DCHECK(!g_temp_window);
impl_.reset(new TempWindowMacImpl);
g_temp_window = this;
}
TempWindowMac::~TempWindowMac() {
impl_.reset();
g_temp_window = NULL;
DCHECK(window_);
[window_ close];
}
// static
CefWindowHandle TempWindowMac::GetWindowHandle() {
DCHECK(g_temp_window);
return [g_temp_window->window_ contentView];
return CAST_NSVIEW_TO_CEF_WINDOW_HANDLE(
g_temp_window->impl_->window_.contentView);
}
} // namespace client

View File

@ -15,7 +15,8 @@ namespace window_test {
namespace {
NSWindow* GetWindow(CefRefPtr<CefBrowser> browser) {
NSView* view = (NSView*)browser->GetHost()->GetWindowHandle();
NSView* view =
CAST_CEF_WINDOW_HANDLE_TO_NSVIEW(browser->GetHost()->GetWindowHandle());
return [view window];
}

View File

@ -355,71 +355,77 @@ int RunMain(int argc, char* argv[]) {
if (!library_loader.LoadInMain())
return 1;
int result = -1;
CefMainArgs main_args(argc, argv);
// Initialize the AutoRelease pool.
NSAutoreleasePool* autopool = [[NSAutoreleasePool alloc] init];
@autoreleasepool {
// Initialize the ClientApplication instance.
[ClientApplication sharedApplication];
// Initialize the ClientApplication instance.
[ClientApplication sharedApplication];
// Parse command-line arguments.
CefRefPtr<CefCommandLine> command_line =
CefCommandLine::CreateCommandLine();
command_line->InitFromArgv(argc, argv);
// Parse command-line arguments.
CefRefPtr<CefCommandLine> command_line = CefCommandLine::CreateCommandLine();
command_line->InitFromArgv(argc, argv);
// Create a ClientApp of the correct type.
CefRefPtr<CefApp> app;
ClientApp::ProcessType process_type =
ClientApp::GetProcessType(command_line);
if (process_type == ClientApp::BrowserProcess)
app = new ClientAppBrowser();
// Create a ClientApp of the correct type.
CefRefPtr<CefApp> app;
ClientApp::ProcessType process_type = ClientApp::GetProcessType(command_line);
if (process_type == ClientApp::BrowserProcess)
app = new ClientAppBrowser();
// Create the main context object.
scoped_ptr<MainContextImpl> context(
new MainContextImpl(command_line, true));
// Create the main context object.
scoped_ptr<MainContextImpl> context(new MainContextImpl(command_line, true));
CefSettings settings;
CefSettings settings;
// When generating projects with CMake the CEF_USE_SANDBOX value will be defined
// automatically. Pass -DUSE_SANDBOX=OFF to the CMake command-line to disable
// use of the sandbox.
#if !defined(CEF_USE_SANDBOX)
settings.no_sandbox = true;
settings.no_sandbox = true;
#endif
// Populate the settings based on command line arguments.
context->PopulateSettings(&settings);
// Populate the settings based on command line arguments.
context->PopulateSettings(&settings);
// Create the main message loop object.
scoped_ptr<MainMessageLoop> message_loop;
if (settings.external_message_pump)
message_loop = MainMessageLoopExternalPump::Create();
else
message_loop.reset(new MainMessageLoopStd);
// Create the main message loop object.
scoped_ptr<MainMessageLoop> message_loop;
if (settings.external_message_pump)
message_loop = MainMessageLoopExternalPump::Create();
else
message_loop.reset(new MainMessageLoopStd);
// Initialize CEF.
context->Initialize(main_args, settings, app, NULL);
// Initialize CEF.
context->Initialize(main_args, settings, app, NULL);
// Register scheme handlers.
test_runner::RegisterSchemeHandlers();
// Register scheme handlers.
test_runner::RegisterSchemeHandlers();
// Create the application delegate and window.
ClientAppDelegate* delegate = [[ClientAppDelegate alloc]
initWithControls:!command_line->HasSwitch(switches::kHideControls)
andOsr:settings.windowless_rendering_enabled ? true : false];
[delegate performSelectorOnMainThread:@selector(createApplication:)
withObject:nil
waitUntilDone:NO];
// Create the application delegate and window.
ClientAppDelegate* delegate = [[ClientAppDelegate alloc]
initWithControls:!command_line->HasSwitch(switches::kHideControls)
andOsr:settings.windowless_rendering_enabled ? true : false];
[delegate performSelectorOnMainThread:@selector(createApplication:)
withObject:nil
waitUntilDone:NO];
// Run the message loop. This will block until Quit() is called.
int result = message_loop->Run();
// Run the message loop. This will block until Quit() is called.
result = message_loop->Run();
// Shut down CEF.
context->Shutdown();
// Shut down CEF.
context->Shutdown();
// Release objects in reverse order of creation.
[delegate release];
message_loop.reset();
context.reset();
[autopool release];
// Release objects in reverse order of creation.
#if !__has_feature(objc_arc)
[delegate release];
#endif // !__has_feature(objc_arc)
delegate = nil;
message_loop.reset();
context.reset();
} // @autoreleasepool
return result;
}

View File

@ -87,6 +87,16 @@ endif()
#
if(OS_MACOSX)
option(OPTION_USE_ARC "Build with ARC (automatic Reference Counting) on macOS." ON)
if(OPTION_USE_ARC)
list(APPEND CEF_COMPILER_FLAGS
-fobjc-arc
)
set_target_properties(${target} PROPERTIES
CLANG_ENABLE_OBJC_ARC "YES"
)
endif()
# Output paths for the app bundles.
set(CEF_APP "${CEF_TARGET_OUT_DIR}/${CEF_TARGET}.app")
set(CEF_HELPER_APP "${CEF_TARGET_OUT_DIR}/${CEF_HELPER_OUTPUT_NAME}.app")

View File

@ -12,13 +12,13 @@
#include "tests/cefsimple/simple_handler.h"
// Receives notifications from the application.
@interface SimpleAppDelegate : NSObject<NSApplicationDelegate>
@interface SimpleAppDelegate : NSObject <NSApplicationDelegate>
- (void)createApplication:(id)object;
- (void)tryToTerminateApplication:(NSApplication*)app;
@end
// Provide the CefAppProtocol implementation required by CEF.
@interface SimpleApplication : NSApplication<CefAppProtocol> {
@interface SimpleApplication : NSApplication <CefAppProtocol> {
@private
BOOL handlingSendEvent_;
}
@ -119,48 +119,47 @@ int main(int argc, char* argv[]) {
// Provide CEF with command-line arguments.
CefMainArgs main_args(argc, argv);
// Initialize the AutoRelease pool.
NSAutoreleasePool* autopool = [[NSAutoreleasePool alloc] init];
@autoreleasepool {
// Initialize the SimpleApplication instance.
[SimpleApplication sharedApplication];
// Initialize the SimpleApplication instance.
[SimpleApplication sharedApplication];
// Specify CEF global settings here.
CefSettings settings;
// Specify CEF global settings here.
CefSettings settings;
// When generating projects with CMake the CEF_USE_SANDBOX value will be defined
// automatically. Pass -DUSE_SANDBOX=OFF to the CMake command-line to disable
// use of the sandbox.
// When generating projects with CMake the CEF_USE_SANDBOX value will be
// defined automatically. Pass -DUSE_SANDBOX=OFF to the CMake command-line
// to disable use of the sandbox.
#if !defined(CEF_USE_SANDBOX)
settings.no_sandbox = true;
settings.no_sandbox = true;
#endif
// SimpleApp implements application-level callbacks for the browser process.
// It will create the first browser instance in OnContextInitialized() after
// CEF has initialized.
CefRefPtr<SimpleApp> app(new SimpleApp);
// SimpleApp implements application-level callbacks for the browser process.
// It will create the first browser instance in OnContextInitialized() after
// CEF has initialized.
CefRefPtr<SimpleApp> app(new SimpleApp);
// Initialize CEF for the browser process.
CefInitialize(main_args, settings, app.get(), NULL);
// Initialize CEF for the browser process.
CefInitialize(main_args, settings, app.get(), NULL);
// Create the application delegate.
NSObject* delegate = [[SimpleAppDelegate alloc] init];
[delegate performSelectorOnMainThread:@selector(createApplication:)
withObject:nil
waitUntilDone:NO];
// Create the application delegate.
NSObject* delegate = [[SimpleAppDelegate alloc] init];
[delegate performSelectorOnMainThread:@selector(createApplication:)
withObject:nil
waitUntilDone:NO];
// Run the CEF message loop. This will block until CefQuitMessageLoop() is
// called.
CefRunMessageLoop();
// Run the CEF message loop. This will block until CefQuitMessageLoop() is
// called.
CefRunMessageLoop();
// Shut down CEF.
CefShutdown();
// Shut down CEF.
CefShutdown();
// Release the delegate.
[delegate release];
// Release the AutoRelease pool.
[autopool release];
// Release the delegate.
#if !__has_feature(objc_arc)
[delegate release];
#endif // !__has_feature(objc_arc)
delegate = nil;
} // @autoreleasepool
return 0;
}

View File

@ -10,7 +10,8 @@
void SimpleHandler::PlatformTitleChange(CefRefPtr<CefBrowser> browser,
const CefString& title) {
NSView* view = (NSView*)browser->GetHost()->GetWindowHandle();
NSView* view =
CAST_CEF_WINDOW_HANDLE_TO_NSVIEW(browser->GetHost()->GetWindowHandle());
NSWindow* window = [view window];
std::string titleStr(title);
NSString* str = [NSString stringWithUTF8String:titleStr.c_str()];

View File

@ -12,7 +12,7 @@ CefWindowHandle GetFakeView() {
NSScreen* mainScreen = [NSScreen mainScreen];
NSRect screenRect = [mainScreen visibleFrame];
NSView* fakeView = [[NSView alloc] initWithFrame:screenRect];
return fakeView;
return CAST_NSVIEW_TO_CEF_WINDOW_HANDLE(fakeView);
}
} // namespace osr_unittests

View File

@ -82,14 +82,21 @@ class MainMessageLoopExternalPumpMac : public MainMessageLoopExternalPump {
namespace client {
MainMessageLoopExternalPumpMac::MainMessageLoopExternalPumpMac()
: owner_thread_([[NSThread currentThread] retain]), timer_(nil) {
event_handler_ = [[[EventHandler alloc] initWithPump:this] retain];
: owner_thread_([NSThread currentThread]), timer_(nil) {
#if !__has_feature(objc_arc)
[owner_thread_ retain];
#endif // !__has_feature(objc_arc)
event_handler_ = [[EventHandler alloc] initWithPump:this];
}
MainMessageLoopExternalPumpMac::~MainMessageLoopExternalPumpMac() {
KillTimer();
#if !__has_feature(objc_arc)
[owner_thread_ release];
[event_handler_ release];
#endif // !__has_feature(objc_arc)
owner_thread_ = nil;
event_handler_ = nil;
}
void MainMessageLoopExternalPumpMac::Quit() {
@ -140,11 +147,14 @@ void MainMessageLoopExternalPumpMac::SetTimer(int64 delay_ms) {
DCHECK(!timer_);
const double delay_s = static_cast<double>(delay_ms) / 1000.0;
timer_ = [[NSTimer timerWithTimeInterval:delay_s
target:event_handler_
selector:@selector(timerTimeout:)
userInfo:nil
repeats:NO] retain];
timer_ = [NSTimer timerWithTimeInterval:delay_s
target:event_handler_
selector:@selector(timerTimeout:)
userInfo:nil
repeats:NO];
#if !__has_feature(objc_arc)
[timer_ retain];
#endif // !__has_feature(objc_arc)
// Add the timer to default and tracking runloop modes.
NSRunLoop* owner_runloop = [NSRunLoop currentRunLoop];
@ -155,7 +165,9 @@ void MainMessageLoopExternalPumpMac::SetTimer(int64 delay_ms) {
void MainMessageLoopExternalPumpMac::KillTimer() {
if (timer_ != nil) {
[timer_ invalidate];
#if !__has_feature(objc_arc)
[timer_ release];
#endif // !__has_feature(objc_arc)
timer_ = nil;
}
}