mirror of
https://github.com/aphrody-labs/cef.git
synced 2026-10-13 21:07:07 +00:00
tests: Add cefsimple_capi example project
This is a more-or-less direct translation of the cefsimple (C++) project to use C API based on the updated UsingTheCAPI.md docs. Translation was performed using Claude Code.
This commit is contained in:
1 parent
69a352bf67
commit
2305ffe1d6
51 files changed
+4183
-17
No files matched your search
@@ -306,6 +306,12 @@ includes_mac = gypi_paths2.includes_mac + gypi_paths2.includes_mac_capi
|
||||
includes_linux = gypi_paths2.includes_linux + gypi_paths2.includes_linux_capi
|
||||
includes_win = gypi_paths2.includes_win + gypi_paths2.includes_win_capi
|
||||
|
||||
# CAPI-only includes for pure C implementations.
|
||||
includes_common_capi = gypi_paths2.includes_common_capi + gypi_paths2.includes_capi
|
||||
includes_mac_capi = gypi_paths2.includes_mac_capi
|
||||
includes_linux_capi = gypi_paths2.includes_linux_capi
|
||||
includes_win_capi = gypi_paths2.includes_win_capi
|
||||
|
||||
#
|
||||
# Targets that will be built when depending on "//cef".
|
||||
#
|
||||
@@ -314,6 +320,7 @@ group("cef") {
|
||||
testonly = true
|
||||
deps = [
|
||||
":cefsimple",
|
||||
":cefsimple_capi",
|
||||
":ceftests",
|
||||
":libcef_static_unittests",
|
||||
]
|
||||
@@ -324,6 +331,7 @@ group("cef") {
|
||||
":bootstrapc",
|
||||
":cefclient_dll",
|
||||
":cefsimple_dll",
|
||||
":cefsimple_capi_dll",
|
||||
":ceftests_dll",
|
||||
]
|
||||
}
|
||||
@@ -1123,6 +1131,49 @@ source_set("libcef_static") {
|
||||
# libcef_dll_wrapper static targets.
|
||||
#
|
||||
|
||||
if (is_mac) {
|
||||
# Minimal target for loading the CEF framework dynamically on macOS.
|
||||
# This provides just the necessary C API functions without the full
|
||||
# C++ wrapper.
|
||||
static_library("cef_capi_library_loader") {
|
||||
# Necessary because the generated file includes test API headers.
|
||||
testonly = true
|
||||
|
||||
sources = [
|
||||
"include/wrapper/cef_library_loader.h",
|
||||
"libcef_dll/wrapper/libcef_dll_dylib.cc",
|
||||
"libcef_dll/wrapper/cef_scoped_library_loader_mac.mm",
|
||||
]
|
||||
|
||||
defines = [ "WRAPPING_CEF_SHARED" ]
|
||||
|
||||
configs += [ ":libcef_includes_config" ]
|
||||
public_configs = [ ":libcef_includes_config" ]
|
||||
|
||||
deps = [ ":cef_make_headers" ]
|
||||
}
|
||||
|
||||
# Minimal target for loading the CEF sandbox dynamically on macOS.
|
||||
# This provides just the necessary C API functions without the full
|
||||
# C++ wrapper.
|
||||
static_library("cef_capi_sandbox_loader") {
|
||||
# Necessary because the generated file includes test API headers.
|
||||
testonly = true
|
||||
|
||||
sources = [
|
||||
"include/cef_sandbox_mac.h",
|
||||
"libcef_dll/wrapper/cef_scoped_sandbox_context_mac.mm",
|
||||
]
|
||||
|
||||
defines = [ "WRAPPING_CEF_SHARED" ]
|
||||
|
||||
configs += [ ":libcef_includes_config" ]
|
||||
public_configs = [ ":libcef_includes_config" ]
|
||||
|
||||
deps = [ ":cef_make_headers" ]
|
||||
}
|
||||
}
|
||||
|
||||
# Configuration that will be applied to all targets that build autogen files.
|
||||
config("libcef_autogen_config") {
|
||||
if (is_clang) {
|
||||
@@ -1886,7 +1937,6 @@ if (is_mac) {
|
||||
|
||||
deps = [
|
||||
":cef_make_headers",
|
||||
":libcef_dll_wrapper",
|
||||
]
|
||||
if (defined(invoker.helper_deps)) {
|
||||
deps += invoker.helper_deps
|
||||
@@ -1909,6 +1959,10 @@ if (is_mac) {
|
||||
defines = invoker.helper_defines
|
||||
}
|
||||
|
||||
if (defined(invoker.helper_cflags_c)) {
|
||||
cflags_c = invoker.helper_cflags_c
|
||||
}
|
||||
|
||||
# Disable clang modules for this target (see issue #3611).
|
||||
use_libcxx_modules = false
|
||||
}
|
||||
@@ -1942,6 +1996,9 @@ if (is_mac) {
|
||||
if (defined(invoker.helper_defines)) {
|
||||
helper_defines = invoker.helper_defines
|
||||
}
|
||||
if (defined(invoker.helper_cflags_c)) {
|
||||
helper_cflags_c = invoker.helper_cflags_c
|
||||
}
|
||||
|
||||
helper_name_suffix = _helper_suffix
|
||||
helper_bundle_id_suffix = _helper_bundle_id
|
||||
@@ -1986,10 +2043,8 @@ if (is_mac) {
|
||||
|
||||
sources = invoker.sources
|
||||
|
||||
public_deps = [ ":libcef_dll_wrapper" ]
|
||||
deps = [
|
||||
":cef_make_headers",
|
||||
":libcef_dll_wrapper",
|
||||
":${app_name}_framework_bundle_data",
|
||||
]
|
||||
if (defined(invoker.deps)) {
|
||||
@@ -2004,6 +2059,10 @@ if (is_mac) {
|
||||
defines = invoker.defines
|
||||
}
|
||||
|
||||
if (defined(invoker.cflags_c)) {
|
||||
cflags_c = invoker.cflags_c
|
||||
}
|
||||
|
||||
info_plist_target = ":${app_name}_plist"
|
||||
|
||||
# Disable clang modules for this target (see issue #3611).
|
||||
@@ -2059,6 +2118,9 @@ if (is_mac) {
|
||||
gypi_paths2.shared_sources_mac_helper +
|
||||
gypi_paths2.cefclient_sources_common +
|
||||
gypi_paths2.cefclient_sources_renderer
|
||||
helper_deps = [
|
||||
":libcef_dll_wrapper",
|
||||
]
|
||||
helper_defines = [
|
||||
"CEF_USE_SANDBOX",
|
||||
]
|
||||
@@ -2075,6 +2137,7 @@ if (is_mac) {
|
||||
gypi_paths2.cefclient_sources_common +
|
||||
gypi_paths2.cefclient_sources_mac
|
||||
deps = [
|
||||
":libcef_dll_wrapper",
|
||||
":cefclient_resources_bundle_data",
|
||||
":cefclient_resources_bundle_data_english",
|
||||
":cefclient_xibs",
|
||||
@@ -2131,6 +2194,9 @@ if (is_mac) {
|
||||
gypi_paths2.includes_wrapper +
|
||||
gypi_paths2.includes_wrapper_mac +
|
||||
gypi_paths2.cefsimple_sources_mac_helper
|
||||
helper_deps = [
|
||||
":libcef_dll_wrapper",
|
||||
]
|
||||
helper_defines = [
|
||||
"CEF_USE_SANDBOX",
|
||||
]
|
||||
@@ -2143,6 +2209,7 @@ if (is_mac) {
|
||||
gypi_paths2.cefsimple_sources_common +
|
||||
gypi_paths2.cefsimple_sources_mac
|
||||
deps = [
|
||||
":libcef_dll_wrapper",
|
||||
":cefsimple_resources_bundle_data",
|
||||
":cefsimple_resources_bundle_data_english",
|
||||
":cefsimple_xibs",
|
||||
@@ -2156,6 +2223,75 @@ if (is_mac) {
|
||||
}
|
||||
|
||||
|
||||
#
|
||||
# cefsimple_capi app targets (Pure C API implementation).
|
||||
#
|
||||
|
||||
bundle_data("cefsimple_capi_resources_bundle_data") {
|
||||
sources = [
|
||||
"tests/cefsimple_capi/mac/cefsimple_capi.icns",
|
||||
]
|
||||
|
||||
outputs = [
|
||||
"{{bundle_resources_dir}}/{{source_file_part}}",
|
||||
]
|
||||
}
|
||||
|
||||
bundle_data("cefsimple_capi_resources_bundle_data_english") {
|
||||
sources = [
|
||||
"tests/cefsimple_capi/mac/English.lproj/InfoPlist.strings",
|
||||
]
|
||||
|
||||
outputs = [
|
||||
"{{bundle_resources_dir}}/English.lproj/{{source_file_part}}",
|
||||
]
|
||||
}
|
||||
|
||||
mac_xib_bundle_data("cefsimple_capi_xibs") {
|
||||
sources = [
|
||||
"tests/cefsimple_capi/mac/English.lproj/MainMenu.xib",
|
||||
]
|
||||
output_path = "{{bundle_resources_dir}}/English.lproj"
|
||||
}
|
||||
|
||||
cef_app("cefsimple_capi") {
|
||||
# Necessary because the cef_framework target is testonly.
|
||||
testonly = true
|
||||
|
||||
helper_info_plist = "tests/cefsimple_capi/mac/helper-Info.plist.in"
|
||||
helper_sources = includes_common_capi +
|
||||
includes_mac_capi +
|
||||
gypi_paths2.cefsimple_capi_sources_mac_helper
|
||||
helper_deps = [
|
||||
":cef_capi_library_loader",
|
||||
":cef_capi_sandbox_loader",
|
||||
]
|
||||
helper_defines = [
|
||||
"CEF_USE_SANDBOX",
|
||||
]
|
||||
helper_cflags_c = [ "-std=c11" ]
|
||||
|
||||
info_plist = "tests/cefsimple_capi/mac/Info.plist.in"
|
||||
sources = includes_common_capi +
|
||||
includes_mac_capi +
|
||||
gypi_paths2.cefsimple_capi_sources_common +
|
||||
gypi_paths2.cefsimple_capi_sources_mac
|
||||
deps = [
|
||||
":cef_capi_library_loader",
|
||||
":cefsimple_capi_resources_bundle_data",
|
||||
":cefsimple_capi_resources_bundle_data_english",
|
||||
":cefsimple_capi_xibs",
|
||||
]
|
||||
frameworks = [
|
||||
"AppKit.framework",
|
||||
]
|
||||
defines = [
|
||||
"CEF_USE_SANDBOX",
|
||||
]
|
||||
cflags_c = [ "-std=c11" ]
|
||||
}
|
||||
|
||||
|
||||
#
|
||||
# ceftests app targets.
|
||||
#
|
||||
@@ -2197,6 +2333,7 @@ if (is_mac) {
|
||||
gypi_paths2.ceftests_sources_mac_helper +
|
||||
gypi_paths2.ceftests_sources_mac_helper_shared
|
||||
helper_deps = [
|
||||
":libcef_dll_wrapper",
|
||||
":gtest_teamcity",
|
||||
"//testing/gtest",
|
||||
]
|
||||
@@ -2219,6 +2356,7 @@ if (is_mac) {
|
||||
gypi_paths2.ceftests_sources_common +
|
||||
gypi_paths2.ceftests_sources_mac
|
||||
deps = [
|
||||
":libcef_dll_wrapper",
|
||||
":ceftests_resources_bundle_data",
|
||||
":ceftests_resources_bundle_data_english",
|
||||
":ceftests_xibs",
|
||||
@@ -2557,6 +2695,122 @@ if (is_mac) {
|
||||
}
|
||||
|
||||
|
||||
#
|
||||
# cefsimple_capi targets (Pure C API implementation).
|
||||
#
|
||||
|
||||
executable("cefsimple_capi") {
|
||||
# Necessary because the libcef target is testonly.
|
||||
testonly = true
|
||||
|
||||
sources = includes_common_capi +
|
||||
gypi_paths2.cefsimple_capi_sources_common
|
||||
|
||||
deps = [
|
||||
":libcef",
|
||||
]
|
||||
|
||||
configs += [ ":libcef_includes_config" ]
|
||||
|
||||
defines = [
|
||||
"CEF_USE_SANDBOX",
|
||||
]
|
||||
|
||||
if (is_win) {
|
||||
sources += includes_win_capi +
|
||||
gypi_paths2.cefsimple_capi_sources_win +
|
||||
gypi_paths2.cefsimple_capi_sources_resources_win_rc
|
||||
|
||||
# Set /SUBSYSTEM:WINDOWS.
|
||||
configs -= [ "//build/config/win:console" ]
|
||||
configs += [ "//build/config/win:windowed" ]
|
||||
|
||||
# Delay-load as many DLLs as possible for sandbox and startup perf
|
||||
# improvements.
|
||||
configs += [
|
||||
"//build/config/win:delayloads",
|
||||
"//build/config/win:delayloads_not_for_child_dll",
|
||||
]
|
||||
|
||||
deps += [
|
||||
":cef_sandbox",
|
||||
"//build/win:default_exe_manifest",
|
||||
]
|
||||
|
||||
libs = [
|
||||
"comctl32.lib",
|
||||
"shlwapi.lib",
|
||||
"rpcrt4.lib",
|
||||
]
|
||||
|
||||
# Use C11 standard for C files.
|
||||
cflags_c = [ "/std:c11" ]
|
||||
}
|
||||
|
||||
if (is_linux) {
|
||||
sources += includes_linux_capi +
|
||||
gypi_paths2.cefsimple_capi_sources_linux
|
||||
|
||||
if (ozone_platform_x11) {
|
||||
libs = [
|
||||
"X11",
|
||||
]
|
||||
}
|
||||
|
||||
if (!is_component_build) {
|
||||
# Set rpath to find our own libfreetype even in a non-component build.
|
||||
configs += [ "//build/config/gcc:rpath_for_built_shared_libraries" ]
|
||||
}
|
||||
|
||||
# Use C11 standard for C files.
|
||||
cflags_c = [ "-std=c11" ]
|
||||
}
|
||||
}
|
||||
|
||||
if (is_win) {
|
||||
# Like the "cefsimple_capi" executable target, but building a DLL to be loaded by
|
||||
# bootstrap.exe.
|
||||
shared_library("cefsimple_capi_dll") {
|
||||
# Necessary because the libcef target is testonly.
|
||||
testonly = true
|
||||
|
||||
output_name = "cefsimple_capi"
|
||||
|
||||
sources = includes_common_capi +
|
||||
includes_win_capi +
|
||||
gypi_paths2.cefsimple_capi_sources_common +
|
||||
gypi_paths2.cefsimple_capi_sources_win +
|
||||
gypi_paths2.cefsimple_capi_sources_resources_win_rc
|
||||
|
||||
deps = [
|
||||
":bootstrap",
|
||||
":libcef",
|
||||
]
|
||||
|
||||
defines = [
|
||||
"CEF_USE_BOOTSTRAP",
|
||||
]
|
||||
|
||||
# Delay-load as many DLLs as possible for sandbox and startup perf
|
||||
# improvements.
|
||||
configs += [
|
||||
":libcef_includes_config",
|
||||
"//build/config/win:delayloads",
|
||||
"//build/config/win:delayloads_not_for_child_dll",
|
||||
]
|
||||
|
||||
libs = [
|
||||
"comctl32.lib",
|
||||
"shlwapi.lib",
|
||||
"rpcrt4.lib",
|
||||
]
|
||||
|
||||
# Use C11 standard for C files.
|
||||
cflags_c = [ "/std:c11" ]
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#
|
||||
# ceftests targets.
|
||||
#
|
||||
|
||||
@@ -223,6 +223,7 @@ add_subdirectory(${CEF_LIBCEF_DLL_WRAPPER_PATH} libcef_dll_wrapper)
|
||||
# TODO: Change these lines to match your project target when you copy this file.
|
||||
if(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/tests")
|
||||
add_subdirectory(tests/cefsimple)
|
||||
add_subdirectory(tests/cefsimple_capi)
|
||||
add_subdirectory(tests/gtest)
|
||||
add_subdirectory(tests/ceftests)
|
||||
endif()
|
||||
|
||||
@@ -62,12 +62,27 @@ def declare_cc_library(copts=[], local_defines=[], **kwargs):
|
||||
**kwargs
|
||||
)
|
||||
|
||||
def declare_objc_library(copts=[], **kwargs):
|
||||
def declare_objc_library(copts=[], enable_cxx17=True, **kwargs):
|
||||
"""
|
||||
objc_library wrapper that applies common copts.
|
||||
|
||||
Args:
|
||||
copts: Additional compiler options to add.
|
||||
enable_cxx17: If True (default), adds -std=c++17 for Objective-C++ (.mm) files.
|
||||
Set to False for pure Objective-C (.m) files that should not use C++ standard.
|
||||
**kwargs: Additional arguments passed to objc_library.
|
||||
"""
|
||||
# NOTE: objc_library does not support local_defines on MacOS, so on
|
||||
# that platform we put the defines in copts instead.
|
||||
|
||||
# Add C++17 standard for Objective-C++ files on macOS (default behavior)
|
||||
# This allows .mm files to properly parse C++ headers while allowing
|
||||
# pure .m files to opt out when needed.
|
||||
cxx_standard = select({
|
||||
"@platforms//os:macos": ["-std=c++17"] if enable_cxx17 else [],
|
||||
"//conditions:default": [],
|
||||
})
|
||||
|
||||
objc_library(
|
||||
copts = select({
|
||||
"@platforms//os:windows": WIN_COMMON_COPTS,
|
||||
@@ -85,6 +100,6 @@ def declare_objc_library(copts=[], **kwargs):
|
||||
"@cef//:macos_dbg": MAC_COMMON_COPTS_DEBUG,
|
||||
"@cef//:macos_fastbuild": MAC_COMMON_COPTS_RELEASE,
|
||||
"//conditions:default": None,
|
||||
}) + copts,
|
||||
}) + cxx_standard + copts,
|
||||
**kwargs
|
||||
)
|
||||
@@ -494,6 +494,51 @@
|
||||
'tests/cefsimple/cefsimple_linux.cc',
|
||||
'tests/cefsimple/simple_handler_linux.cc',
|
||||
],
|
||||
'cefsimple_capi_sources_common': [
|
||||
'tests/cefsimple_capi/ref_counted.h',
|
||||
'tests/cefsimple_capi/simple_app.c',
|
||||
'tests/cefsimple_capi/simple_app.h',
|
||||
'tests/cefsimple_capi/simple_browser_list.c',
|
||||
'tests/cefsimple_capi/simple_browser_list.h',
|
||||
'tests/cefsimple_capi/simple_display_handler.c',
|
||||
'tests/cefsimple_capi/simple_handler.c',
|
||||
'tests/cefsimple_capi/simple_handler.h',
|
||||
'tests/cefsimple_capi/simple_life_span_handler.c',
|
||||
'tests/cefsimple_capi/simple_load_handler.c',
|
||||
'tests/cefsimple_capi/simple_utils.h',
|
||||
'tests/cefsimple_capi/simple_views.c',
|
||||
'tests/cefsimple_capi/simple_views.h',
|
||||
],
|
||||
'cefsimple_capi_sources_win': [
|
||||
'tests/cefsimple_capi/cefsimple_win.c',
|
||||
'tests/cefsimple_capi/resource.h',
|
||||
'tests/cefsimple_capi/simple_handler_win.c',
|
||||
],
|
||||
'cefsimple_capi_sources_resources_win': [
|
||||
'tests/cefsimple_capi/win/cefsimple.exe.manifest',
|
||||
'tests/cefsimple_capi/win/cefsimple.ico',
|
||||
'tests/cefsimple_capi/win/small.ico',
|
||||
],
|
||||
'cefsimple_capi_sources_resources_win_rc': [
|
||||
'tests/cefsimple_capi/win/cefsimple.rc',
|
||||
],
|
||||
'cefsimple_capi_sources_mac': [
|
||||
'tests/cefsimple_capi/cefsimple_mac.m',
|
||||
'tests/cefsimple_capi/simple_handler_mac.m',
|
||||
],
|
||||
'cefsimple_capi_sources_mac_helper': [
|
||||
'tests/cefsimple_capi/process_helper_mac.c',
|
||||
],
|
||||
'cefsimple_capi_bundle_resources_mac': [
|
||||
'tests/cefsimple_capi/mac/cefsimple_capi.icns',
|
||||
'tests/cefsimple_capi/mac/English.lproj/InfoPlist.strings',
|
||||
'tests/cefsimple_capi/mac/English.lproj/MainMenu.xib',
|
||||
'tests/cefsimple_capi/mac/Info.plist.in',
|
||||
],
|
||||
'cefsimple_capi_sources_linux': [
|
||||
'tests/cefsimple_capi/cefsimple_linux.c',
|
||||
'tests/cefsimple_capi/simple_handler_linux.c',
|
||||
],
|
||||
'ceftests_data_resources': [
|
||||
'tests/ceftests/resources/net/data/ssl/certificates/expired_cert.pem',
|
||||
'tests/ceftests/resources/net/data/ssl/certificates/localhost_cert.pem',
|
||||
|
||||
@@ -338,8 +338,10 @@ macro(SET_COMMON_TARGET_PROPERTIES target)
|
||||
# Compile flags.
|
||||
target_compile_options(${target} PRIVATE $<$<COMPILE_LANGUAGE:C>:${CEF_COMPILER_FLAGS} ${CEF_C_COMPILER_FLAGS}>)
|
||||
target_compile_options(${target} PRIVATE $<$<COMPILE_LANGUAGE:CXX>:${CEF_COMPILER_FLAGS} ${CEF_CXX_COMPILER_FLAGS}>)
|
||||
target_compile_options(${target} PRIVATE $<$<CONFIG:Debug>:${CEF_COMPILER_FLAGS_DEBUG} ${CEF_CXX_COMPILER_FLAGS_DEBUG}>)
|
||||
target_compile_options(${target} PRIVATE $<$<CONFIG:Release>:${CEF_COMPILER_FLAGS_RELEASE} ${CEF_CXX_COMPILER_FLAGS_RELEASE}>)
|
||||
target_compile_options(${target} PRIVATE $<$<AND:$<COMPILE_LANGUAGE:C>,$<CONFIG:Debug>>:${CEF_COMPILER_FLAGS_DEBUG} ${CEF_C_COMPILER_FLAGS_DEBUG}>)
|
||||
target_compile_options(${target} PRIVATE $<$<AND:$<COMPILE_LANGUAGE:CXX>,$<CONFIG:Debug>>:${CEF_COMPILER_FLAGS_DEBUG} ${CEF_CXX_COMPILER_FLAGS_DEBUG}>)
|
||||
target_compile_options(${target} PRIVATE $<$<AND:$<COMPILE_LANGUAGE:C>,$<CONFIG:Release>>:${CEF_COMPILER_FLAGS_RELEASE} ${CEF_C_COMPILER_FLAGS_RELEASE}>)
|
||||
target_compile_options(${target} PRIVATE $<$<AND:$<COMPILE_LANGUAGE:CXX>,$<CONFIG:Release>>:${CEF_COMPILER_FLAGS_RELEASE} ${CEF_CXX_COMPILER_FLAGS_RELEASE}>)
|
||||
|
||||
# Compile definitions.
|
||||
target_compile_definitions(${target} PRIVATE ${CEF_COMPILER_DEFINES})
|
||||
|
||||
@@ -60,10 +60,25 @@ extern "C" {
|
||||
CEF_EXPORT void* cef_sandbox_initialize(int argc, char** argv);
|
||||
|
||||
///
|
||||
/// Destroy the specified sandbox context handle.
|
||||
/// Destroy the specified sandbox context handle created by
|
||||
/// cef_sandbox_initialize().
|
||||
///
|
||||
CEF_EXPORT void cef_sandbox_destroy(void* sandbox_context);
|
||||
|
||||
///
|
||||
/// Initialize the scoped sandbox for this process. Returns an opaque handle
|
||||
/// on success or NULL on failure. The returned handle should be passed to
|
||||
/// cef_scoped_sandbox_destroy() immediately before process termination.
|
||||
/// This is a wrapper around CefScopedSandboxContext for C API users.
|
||||
///
|
||||
void* cef_scoped_sandbox_initialize(int argc, char** argv);
|
||||
|
||||
///
|
||||
/// Destroy the specified scoped sandbox handle created by
|
||||
/// cef_scoped_sandbox_initialize().
|
||||
///
|
||||
void cef_scoped_sandbox_destroy(void* sandbox_context);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
||||
|
||||
@@ -51,6 +51,22 @@ int cef_load_library(const char* path);
|
||||
///
|
||||
int cef_unload_library(void);
|
||||
|
||||
///
|
||||
/// Load the CEF library from the expected app bundle location relative to the
|
||||
/// executable. Pass |helper| as 1 for helper processes or 0 for the main
|
||||
/// process. Returns an opaque handle on success or NULL on failure. The
|
||||
/// returned handle should be passed to cef_scoped_library_loader_free()
|
||||
/// immediately before process termination. This is a wrapper around
|
||||
/// CefScopedLibraryLoader for C API users.
|
||||
///
|
||||
void* cef_scoped_library_loader_create(int helper);
|
||||
|
||||
///
|
||||
/// Destroy the specified library loader handle created by
|
||||
/// cef_scoped_library_loader_create().
|
||||
///
|
||||
void cef_scoped_library_loader_free(void* loader);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -75,3 +75,20 @@ CefScopedLibraryLoader::~CefScopedLibraryLoader() {
|
||||
cef_unload_library();
|
||||
}
|
||||
}
|
||||
|
||||
// C API wrapper functions for use with pure C code.
|
||||
void* cef_scoped_library_loader_create(int helper) {
|
||||
CefScopedLibraryLoader* loader = new CefScopedLibraryLoader();
|
||||
bool success = helper ? loader->LoadInHelper() : loader->LoadInMain();
|
||||
if (!success) {
|
||||
delete loader;
|
||||
return nullptr;
|
||||
}
|
||||
return loader;
|
||||
}
|
||||
|
||||
void cef_scoped_library_loader_free(void* loader) {
|
||||
if (loader) {
|
||||
delete static_cast<CefScopedLibraryLoader*>(loader);
|
||||
}
|
||||
}
|
||||
@@ -111,3 +111,19 @@ bool CefScopedSandboxContext::Initialize(int argc, char** argv) {
|
||||
sandbox_context_ = SandboxInitialize(library_handle_, argc, argv);
|
||||
return !!sandbox_context_;
|
||||
}
|
||||
|
||||
// C API wrapper functions for use with pure C code.
|
||||
void* cef_scoped_sandbox_initialize(int argc, char** argv) {
|
||||
CefScopedSandboxContext* context = new CefScopedSandboxContext();
|
||||
if (!context->Initialize(argc, argv)) {
|
||||
delete context;
|
||||
return nullptr;
|
||||
}
|
||||
return context;
|
||||
}
|
||||
|
||||
void cef_scoped_sandbox_destroy(void* sandbox_context) {
|
||||
if (sandbox_context) {
|
||||
delete static_cast<CefScopedSandboxContext*>(sandbox_context);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,113 @@
|
||||
# CEF Simple C++ Example
|
||||
|
||||
This directory contains a minimal CEF browser application written in C++ using the CEF C++ API.
|
||||
|
||||
## Overview
|
||||
|
||||
**cefsimple** is the canonical minimal CEF application demonstrating:
|
||||
|
||||
- **C++ implementation** - Uses CEF C++ API with automatic reference counting
|
||||
- **Basic browser functionality** - Window creation, navigation, and lifecycle management
|
||||
- **Cross-platform** - Supports Windows, Linux, and macOS
|
||||
- **Minimal code** - Simple architecture suitable for learning CEF basics
|
||||
|
||||
### C API Version
|
||||
|
||||
A pure C implementation of this example is available at [../cefsimple_capi/](../cefsimple_capi/). The C version demonstrates the same functionality using the CEF C API with manual reference counting.
|
||||
|
||||
**When to use each:**
|
||||
|
||||
- **Use cefsimple (C++)** - For production applications and most use cases
|
||||
- **Use cefsimple_capi (C)** - When C++ is not available or for embedding in C projects
|
||||
|
||||
## Learning Resources
|
||||
|
||||
**New to CEF?** Start with the [CEF Tutorial](https://bitbucket.org/chromiumembedded/cef/wiki/Tutorial.md), which provides a detailed walkthrough of this exact example:
|
||||
|
||||
- **Architecture overview** - CEF processes, threads, and callbacks
|
||||
- **Code walkthrough** - Detailed explanation of each file and function
|
||||
- **Program flow** - How cefsimple initializes and runs
|
||||
- **Key concepts** - CefApp, CefClient, handlers, and browser lifecycle
|
||||
|
||||
The Tutorial is the recommended starting point for understanding how CEF applications work.
|
||||
|
||||
For complete API documentation, see [GeneralUsage](https://bitbucket.org/chromiumembedded/cef/wiki/GeneralUsage.md).
|
||||
|
||||
## Architecture
|
||||
|
||||
### Core Files
|
||||
|
||||
- **simple_app.h/cc** - Application handler (CefApp)
|
||||
- **simple_handler.h/cc** - Client handler with display, life span, and load handlers
|
||||
|
||||
### Platform-Specific Files
|
||||
|
||||
#### Windows
|
||||
|
||||
- **cefsimple_win.cc** - Windows entry point (wWinMain)
|
||||
- **simple_handler_win.cc** - Windows-specific handler implementation
|
||||
|
||||
#### Linux
|
||||
|
||||
- **cefsimple_linux.cc** - Linux entry point (main)
|
||||
- **simple_handler_linux.cc** - Linux/X11-specific handler implementation
|
||||
|
||||
#### macOS
|
||||
|
||||
- **cefsimple_mac.mm** - macOS entry point with NSApplication integration
|
||||
- **simple_handler_mac.mm** - macOS-specific handler implementation
|
||||
- **process_helper_mac.cc** - Helper process entry point
|
||||
|
||||
## Building
|
||||
|
||||
From the Chromium `src` directory:
|
||||
|
||||
```bash
|
||||
# Debug build (x64)
|
||||
autoninja -C out/Debug_GN_x64 cefsimple
|
||||
|
||||
# Debug build (ARM64 on macOS)
|
||||
autoninja -C out/Debug_GN_arm64 cefsimple
|
||||
|
||||
# Release build
|
||||
autoninja -C out/Release_GN_x64 cefsimple
|
||||
```
|
||||
|
||||
## Running
|
||||
|
||||
```bash
|
||||
# macOS
|
||||
out/Debug_GN_arm64/cefsimple.app/Contents/MacOS/cefsimple
|
||||
|
||||
# Linux
|
||||
out/Debug_GN_x64/cefsimple
|
||||
|
||||
# Windows
|
||||
out/Debug_GN_x64/cefsimple.exe
|
||||
```
|
||||
|
||||
Expected behavior: Opens a window displaying https://www.google.com
|
||||
|
||||
## Key Features
|
||||
|
||||
- **Automatic reference counting** - CefRefPtr handles object lifetime
|
||||
- **Helper window** - Creates a browser window with navigation controls
|
||||
- **Error handling** - Displays error pages for failed navigations
|
||||
- **Cross-platform UI** - Uses Views framework for consistent UI
|
||||
|
||||
## Maintenance Pattern
|
||||
|
||||
This is the primary CEF sample application. Changes to CEF features, API updates, or bug fixes should be applied here first, then ported to cefsimple_capi (the C version).
|
||||
|
||||
**Typical workflow:**
|
||||
|
||||
1. Update cefsimple (C++ version) with new features or API changes
|
||||
2. Port equivalent changes to cefsimple_capi using C API patterns
|
||||
3. Result: Both examples demonstrate the same functionality
|
||||
|
||||
## References
|
||||
|
||||
- [CEF Tutorial](https://bitbucket.org/chromiumembedded/cef/wiki/Tutorial.md) - Detailed walkthrough of this example
|
||||
- [CEF General Usage](https://bitbucket.org/chromiumembedded/cef/wiki/GeneralUsage.md) - Complete API documentation
|
||||
- [CEF C++ API Documentation](https://bitbucket.org/chromiumembedded/cef/wiki/)
|
||||
- [C API Version](../cefsimple_capi/) - Pure C implementation of this example
|
||||
@@ -0,0 +1,239 @@
|
||||
# CLAUDE.md - CEF Simple C API Example
|
||||
|
||||
This file provides guidance to Claude Code when working with the cefsimple_capi example application.
|
||||
|
||||
## Project Overview
|
||||
|
||||
**cefsimple_capi** is a minimal CEF browser application written in **pure C** (C11 standard) using the CEF C API. It demonstrates proper usage of CEF's C API including manual reference counting, handler callbacks, and cross-platform implementation.
|
||||
|
||||
This is a reference implementation showing how to use CEF from C without any C++ code.
|
||||
|
||||
## Essential Documentation
|
||||
|
||||
**ALWAYS read these documents when working on this project:**
|
||||
|
||||
1. **[cef_wiki/UsingTheCAPI.md](../../cef_wiki/UsingTheCAPI.md)** - Complete CEF C API guide
|
||||
|
||||
- Base structure types (ref-counted vs scoped)
|
||||
- Reference counting rules and patterns
|
||||
- String handling
|
||||
- Thread safety and atomic operations
|
||||
- Complete working examples
|
||||
|
||||
2. **[cef/tools/claude/CLAUDE_BUILD_INSTRUCTIONS.md](../../tools/claude/CLAUDE_BUILD_INSTRUCTIONS.md)** - Build workflow and error fixing
|
||||
|
||||
- Build system usage (GN and Ninja)
|
||||
- Fixing build errors during Chromium updates
|
||||
- Common error patterns and solutions
|
||||
|
||||
3. **[README.md](README.md)** - Project-specific documentation
|
||||
|
||||
- Architecture and file organization
|
||||
- Key differences from C++ version
|
||||
- Critical C API rules specific to this implementation
|
||||
|
||||
**Note:** If the `cef_wiki` directory doesn't exist, create it by running from the `chromium/src` directory:
|
||||
```bash
|
||||
git clone https://bitbucket.org/chromiumembedded/cef.git/wiki cef_wiki
|
||||
```
|
||||
|
||||
## Building
|
||||
|
||||
From the Chromium `src` directory:
|
||||
|
||||
```bash
|
||||
# Debug build (x64)
|
||||
autoninja -C out/Debug_GN_x64 cefsimple_capi
|
||||
|
||||
# Debug build (ARM64 on macOS)
|
||||
autoninja -C out/Debug_GN_arm64 cefsimple_capi
|
||||
|
||||
# Release build
|
||||
autoninja -C out/Release_GN_x64 cefsimple_capi
|
||||
|
||||
# Rebuild after fixing errors in a specific file
|
||||
autoninja -C out/Debug_GN_x64 obj/cef/tests/cefsimple_capi/cefsimple_capi/simple_app.o
|
||||
```
|
||||
|
||||
## Architecture and API Layers
|
||||
|
||||
Understanding the layering is critical when fixing build errors:
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────┐
|
||||
│ cefsimple_capi (this project) │ ← We work here
|
||||
│ - Pure C code (C11) │
|
||||
│ - Uses CEF C API │
|
||||
└─────────────────────────────────────────┘
|
||||
↓ calls
|
||||
┌─────────────────────────────────────────┐
|
||||
│ CEF C API (cef/include/capi/*.h) │ ← Auto-generated headers
|
||||
│ - C wrappers around CEF C++ API │ ← We reference these
|
||||
│ - Generated by CEF translator tool │
|
||||
└─────────────────────────────────────────┘
|
||||
↓ wraps
|
||||
┌─────────────────────────────────────────┐
|
||||
│ CEF C++ Implementation (cef/libcef/) │ ← We don't modify
|
||||
│ - C++ code wrapping Chromium │
|
||||
│ - Updated when Chromium updates │
|
||||
└─────────────────────────────────────────┘
|
||||
↓ uses
|
||||
┌─────────────────────────────────────────┐
|
||||
│ Chromium (chrome/, content/, base/) │ ← We don't modify
|
||||
│ - Core browser engine │
|
||||
│ - Updates cause cascading changes │
|
||||
└─────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
**Key points:**
|
||||
|
||||
- **We only modify** code in `cef/tests/cefsimple_capi/`
|
||||
- **We consult** CEF C API headers in `cef/include/capi/` to understand the API
|
||||
- When Chromium updates → CEF C++ updates → CEF C API updates → we update our C code
|
||||
|
||||
## File Organization
|
||||
|
||||
See [README.md](README.md) for complete architecture details. Key files:
|
||||
|
||||
### Utility Modules
|
||||
|
||||
- **ref_counted.h** - Reference counting macros (`IMPLEMENT_REFCOUNTING_SIMPLE`, `IMPLEMENT_REFCOUNTING_MANUAL`, `INIT_CEF_BASE_REFCOUNTED`)
|
||||
- **simple_utils.h** - Common utilities (`CHECK` macro)
|
||||
- **simple_browser_list.h/c** - Browser list with automatic reference counting
|
||||
|
||||
### Core Implementation
|
||||
|
||||
- **simple_app.h/c** - Application handler (`cef_app_t`)
|
||||
- **simple_handler.h** - Client handler interface and structure definitions
|
||||
- **simple_handler.c** - Main client handler, public API, browser close operations
|
||||
- **simple_display_handler.c** - Display handler (title change)
|
||||
- **simple_life_span_handler.c** - Life span handler (browser lifecycle)
|
||||
- **simple_load_handler.c** - Load handler (error pages)
|
||||
- **simple_views.h/c** - Browser view and window delegates
|
||||
|
||||
### Platform Entry Points
|
||||
|
||||
- **cefsimple_win.c** - Windows (wWinMain)
|
||||
- **cefsimple_linux.c** - Linux (main)
|
||||
- **cefsimple_mac.m** - macOS (NSApplicationMain integration)
|
||||
|
||||
### Platform Handlers
|
||||
|
||||
- **simple_handler_win.c** - Windows-specific (window title)
|
||||
- **simple_handler_linux.c** - Linux-specific (X11 window title)
|
||||
- **simple_handler_mac.m** - macOS-specific (NSWindow title)
|
||||
- **process_helper_mac.c** - macOS helper process entry point
|
||||
|
||||
## Fixing Build Errors
|
||||
|
||||
**Important context:** This application uses the **CEF C API**, not Chromium APIs directly. When Chromium updates, CEF updates its C API wrappers to reflect changes in underlying Chromium functionality. This can cause build errors in our C code that need to be fixed.
|
||||
|
||||
#### What We're Working With
|
||||
|
||||
- **We modify:** Only files in `cef/tests/cefsimple_capi/` directory
|
||||
- **We use:** CEF C API headers from `cef/include/capi/*.h`
|
||||
- **We don't modify:** Chromium code, CEF implementation code, or patch files
|
||||
|
||||
#### When CEF C APIs Change
|
||||
|
||||
Similar to Chromium API updates, CEF C API changes follow patterns:
|
||||
|
||||
**Common CEF C API change patterns:**
|
||||
|
||||
1. **Function pointer signature changes** (new/removed parameters):
|
||||
```c
|
||||
// Old CEF API
|
||||
void CEF_CALLBACK on_load_end(
|
||||
cef_load_handler_t* self,
|
||||
cef_browser_t* browser,
|
||||
cef_frame_t* frame,
|
||||
int httpStatusCode) { ... }
|
||||
|
||||
// New CEF API (added is_main_frame parameter)
|
||||
void CEF_CALLBACK on_load_end(
|
||||
cef_load_handler_t* self,
|
||||
cef_browser_t* browser,
|
||||
cef_frame_t* frame,
|
||||
int httpStatusCode,
|
||||
int is_main_frame) { ... }
|
||||
```
|
||||
|
||||
2. **Structure field changes** (renamed/removed members):
|
||||
```c
|
||||
// Old
|
||||
window_info.window = parent_window;
|
||||
|
||||
// New (if renamed)
|
||||
window_info.parent_window = parent_window;
|
||||
```
|
||||
|
||||
3. **New required function pointers** in base structures:
|
||||
```c
|
||||
// CEF added new function pointer to cef_base_ref_counted_t
|
||||
app->app.base.get_size = app_get_size; // Must implement
|
||||
```
|
||||
|
||||
4. **Handler callback changes** (different return types or parameters):
|
||||
```c
|
||||
// Old - returned int
|
||||
int CEF_CALLBACK on_before_browse(...);
|
||||
|
||||
// New - returns cef_return_value_t enum
|
||||
cef_return_value_t CEF_CALLBACK on_before_browse(...);
|
||||
```
|
||||
|
||||
#### Fixing Process
|
||||
|
||||
1. **Read the error carefully** - Compiler tells you exactly what's wrong
|
||||
2. **Check CEF C API headers** - Look at the current definition in `cef/include/capi/*.h`
|
||||
3. **Update our code** - Modify files in `cef/tests/cefsimple_capi/` to match
|
||||
4. **Rebuild incrementally** - Build individual .o files for fast feedback:
|
||||
```bash
|
||||
autoninja -C out/Debug_GN_x64 obj/cef/tests/cefsimple_capi/cefsimple_capi/simple_handler.o
|
||||
```
|
||||
5. **Consult UsingTheCAPI.md** - Reference patterns for correct implementation
|
||||
|
||||
#### Example Fix Workflow
|
||||
|
||||
If you see this error:
|
||||
```
|
||||
simple_handler.c:45:3: error: too few arguments to function call
|
||||
```
|
||||
|
||||
1. Read the full error to identify the function
|
||||
2. Open the relevant CEF header (`cef/include/capi/cef_life_span_handler_capi.h`)
|
||||
3. Compare the signature in the header with our code
|
||||
4. Update our callback to match the new signature
|
||||
5. Rebuild just that file to verify
|
||||
6. If successful, continue to next error
|
||||
|
||||
See [CLAUDE_BUILD_INSTRUCTIONS.md](../../tools/claude/CLAUDE_BUILD_INSTRUCTIONS.md) for detailed workflow and common patterns. The same principles apply, but remember we're working with CEF C API changes, not Chromium API changes directly.
|
||||
|
||||
## Key Reminders
|
||||
|
||||
1. **We work with CEF C API** - Not Chromium APIs directly; consult `cef/include/capi/*.h` headers
|
||||
2. **Only modify cefsimple_capi files** - Never change Chromium code, CEF implementation, or patches
|
||||
3. **Always check documentation first** - UsingTheCAPI.md has complete reference implementations
|
||||
4. **Reference counting is critical** - Use atomics, release parameters, add_ref returns
|
||||
5. **API version must be initialized** - Call `cef_api_hash()` before any CEF functions
|
||||
6. **Structure ordering matters** - CEF base structure MUST be first member
|
||||
7. **Size field is CEF size** - Use `sizeof(cef_*_t)`, not `sizeof(your_wrapper_t)`
|
||||
8. **Thread safety required** - Reference counting functions called from any thread
|
||||
9. **When APIs change** - Check CEF C API headers first, then update our C code to match
|
||||
|
||||
## Testing
|
||||
|
||||
Run the application after building:
|
||||
|
||||
```bash
|
||||
# macOS
|
||||
out/Debug_GN_arm64/cefsimple_capi.app/Contents/MacOS/cefsimple_capi
|
||||
|
||||
# Linux
|
||||
out/Debug_GN_x64/cefsimple_capi
|
||||
|
||||
# Windows
|
||||
out/Debug_GN_x64/cefsimple_capi.exe
|
||||
```
|
||||
|
||||
Expected behavior: Opens a window displaying https://www.google.com
|
||||
@@ -0,0 +1,256 @@
|
||||
# Copyright (c) 2025 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.
|
||||
|
||||
#
|
||||
# Source files.
|
||||
#
|
||||
|
||||
# cefsimple_capi sources.
|
||||
{{
|
||||
'prefix': 'cefsimple_capi',
|
||||
'set': 'CEFSIMPLE_CAPI_SRCS',
|
||||
'includes': [
|
||||
'cefsimple_capi_sources_common',
|
||||
'cefsimple_capi_sources_win:WINDOWS',
|
||||
'cefsimple_capi_sources_resources_win_rc:WINDOWS',
|
||||
'cefsimple_capi_sources_mac:MAC',
|
||||
'cefsimple_capi_sources_linux:LINUX',
|
||||
],
|
||||
}}
|
||||
|
||||
# cefsimple_capi helper sources.
|
||||
{{
|
||||
'prefix': 'cefsimple_capi_helper',
|
||||
'includes': [
|
||||
'cefsimple_capi_sources_mac_helper:MAC',
|
||||
],
|
||||
}}
|
||||
|
||||
# cefsimple_capi resources.
|
||||
{{
|
||||
'prefix': 'cefsimple_capi_resources',
|
||||
'set': 'CEFSIMPLE_CAPI_RESOURCES_SRCS',
|
||||
'includes': [
|
||||
'cefsimple_capi_bundle_resources_mac:MAC',
|
||||
],
|
||||
}}
|
||||
|
||||
|
||||
#
|
||||
# Shared configuration.
|
||||
#
|
||||
|
||||
# Target executable names.
|
||||
set(CEF_TARGET "cefsimple_capi")
|
||||
if(OS_MAC)
|
||||
set(CEF_HELPER_TARGET "cefsimple_capi_Helper")
|
||||
set(CEF_HELPER_OUTPUT_NAME "cefsimple_capi Helper")
|
||||
else()
|
||||
# Logical target used to link the libcef library.
|
||||
ADD_LOGICAL_TARGET("libcef_lib" "${CEF_LIB_DEBUG}" "${CEF_LIB_RELEASE}")
|
||||
endif()
|
||||
|
||||
# Determine the target output directory.
|
||||
SET_CEF_TARGET_OUT_DIR()
|
||||
|
||||
# cefsimple_capi requires C11 for stdatomic.h and other C11 features.
|
||||
# Override the default C99 standard set by CEF.
|
||||
if(OS_LINUX OR OS_MAC)
|
||||
# Replace -std=c99 with -std=c11 for C files.
|
||||
list(REMOVE_ITEM CEF_C_COMPILER_FLAGS "-std=c99")
|
||||
list(APPEND CEF_C_COMPILER_FLAGS "-std=c11")
|
||||
endif()
|
||||
if(OS_WINDOWS)
|
||||
# Add /std:c11 for C files.
|
||||
list(APPEND CEF_C_COMPILER_FLAGS "/std:c11")
|
||||
# Remove C++ standard flag since this is a C-only target.
|
||||
# The Visual Studio generator sets both <LanguageStandard> and <LanguageStandard_C>
|
||||
# properties, and <LanguageStandard> takes precedence when compiling C files.
|
||||
list(REMOVE_ITEM CEF_CXX_COMPILER_FLAGS "/std:c++17")
|
||||
endif()
|
||||
|
||||
|
||||
#
|
||||
# Linux configuration.
|
||||
#
|
||||
|
||||
if(OS_LINUX)
|
||||
# Executable target.
|
||||
add_executable(${CEF_TARGET} ${CEFSIMPLE_CAPI_SRCS})
|
||||
SET_EXECUTABLE_TARGET_PROPERTIES(${CEF_TARGET})
|
||||
add_dependencies(${CEF_TARGET} libcef_dll_wrapper)
|
||||
target_link_libraries(${CEF_TARGET} libcef_lib libcef_dll_wrapper ${CEF_STANDARD_LIBS})
|
||||
|
||||
# Set rpath so that libraries can be placed next to the executable.
|
||||
set_target_properties(${CEF_TARGET} PROPERTIES
|
||||
INSTALL_RPATH "$ORIGIN"
|
||||
BUILD_WITH_INSTALL_RPATH TRUE
|
||||
RUNTIME_OUTPUT_DIRECTORY ${CEF_TARGET_OUT_DIR}
|
||||
C_STANDARD 11
|
||||
C_STANDARD_REQUIRED ON
|
||||
)
|
||||
|
||||
# Copy binary and resource files to the target output directory.
|
||||
COPY_FILES("${CEF_TARGET}" "${CEF_BINARY_FILES}" "${CEF_BINARY_DIR}" "${CEF_TARGET_OUT_DIR}")
|
||||
COPY_FILES("${CEF_TARGET}" "${CEF_RESOURCE_FILES}" "${CEF_RESOURCE_DIR}" "${CEF_TARGET_OUT_DIR}")
|
||||
if (EXISTS "${CEF_BINARY_DIR}/libminigbm.so")
|
||||
COPY_FILES("${CEF_TARGET}" "libminigbm.so" "${CEF_BINARY_DIR}" "${CEF_TARGET_OUT_DIR}")
|
||||
endif()
|
||||
|
||||
# Set SUID permissions on the chrome-sandbox target.
|
||||
SET_LINUX_SUID_PERMISSIONS("${CEF_TARGET}" "${CEF_TARGET_OUT_DIR}/chrome-sandbox")
|
||||
endif()
|
||||
|
||||
|
||||
#
|
||||
# Mac OS X configuration.
|
||||
#
|
||||
|
||||
if(OS_MAC)
|
||||
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 path for the main app bundle.
|
||||
set(CEF_APP "${CEF_TARGET_OUT_DIR}/${CEF_TARGET}.app")
|
||||
|
||||
# Variables referenced from the main Info.plist file.
|
||||
set(EXECUTABLE_NAME "${CEF_TARGET}")
|
||||
set(PRODUCT_NAME "${CEF_TARGET}")
|
||||
|
||||
# Main app bundle target.
|
||||
add_executable(${CEF_TARGET} MACOSX_BUNDLE ${CEFSIMPLE_CAPI_RESOURCES_SRCS} ${CEFSIMPLE_CAPI_SRCS})
|
||||
SET_EXECUTABLE_TARGET_PROPERTIES(${CEF_TARGET})
|
||||
add_dependencies(${CEF_TARGET} libcef_dll_wrapper)
|
||||
target_link_libraries(${CEF_TARGET} libcef_dll_wrapper ${CEF_STANDARD_LIBS})
|
||||
set_target_properties(${CEF_TARGET} PROPERTIES
|
||||
MACOSX_BUNDLE_INFO_PLIST ${CMAKE_CURRENT_SOURCE_DIR}/mac/Info.plist.in
|
||||
C_STANDARD 11
|
||||
C_STANDARD_REQUIRED ON
|
||||
XCODE_ATTRIBUTE_GCC_C_LANGUAGE_STANDARD "c11"
|
||||
)
|
||||
|
||||
# Copy the CEF framework into the Frameworks directory and create the necessary symlinks.
|
||||
COPY_MAC_FRAMEWORK("${CEF_TARGET}" "${CEF_BINARY_DIR}" "${CEF_APP}")
|
||||
|
||||
# Create the multiple Helper app bundle targets.
|
||||
foreach(_suffix_list ${CEF_HELPER_APP_SUFFIXES})
|
||||
# Convert to a list and extract the suffix values.
|
||||
string(REPLACE ":" ";" _suffix_list ${_suffix_list})
|
||||
list(GET _suffix_list 0 _name_suffix)
|
||||
list(GET _suffix_list 1 _target_suffix)
|
||||
list(GET _suffix_list 2 _plist_suffix)
|
||||
|
||||
# Define Helper target and output names.
|
||||
set(_helper_target "${CEF_HELPER_TARGET}${_target_suffix}")
|
||||
set(_helper_output_name "${CEF_HELPER_OUTPUT_NAME}${_name_suffix}")
|
||||
|
||||
# Create Helper-specific variants of the helper-Info.plist file. Do this
|
||||
# manually because the configure_file command (which is executed as part of
|
||||
# MACOSX_BUNDLE_INFO_PLIST) uses global env variables and would insert the
|
||||
# wrong values with multiple targets.
|
||||
set(_helper_info_plist "${CMAKE_CURRENT_BINARY_DIR}/helper-Info${_target_suffix}.plist")
|
||||
file(READ "${CMAKE_CURRENT_SOURCE_DIR}/mac/helper-Info.plist.in" _plist_contents)
|
||||
string(REPLACE "\${EXECUTABLE_NAME}" "${_helper_output_name}" _plist_contents ${_plist_contents})
|
||||
string(REPLACE "\${PRODUCT_NAME}" "${_helper_output_name}" _plist_contents ${_plist_contents})
|
||||
string(REPLACE "\${BUNDLE_ID_SUFFIX}" "${_plist_suffix}" _plist_contents ${_plist_contents})
|
||||
file(WRITE ${_helper_info_plist} ${_plist_contents})
|
||||
|
||||
# Create Helper executable target.
|
||||
add_executable(${_helper_target} MACOSX_BUNDLE ${CEFSIMPLE_CAPI_HELPER_SRCS})
|
||||
SET_EXECUTABLE_TARGET_PROPERTIES(${_helper_target})
|
||||
add_dependencies(${_helper_target} libcef_dll_wrapper)
|
||||
target_link_libraries(${_helper_target} libcef_dll_wrapper ${CEF_STANDARD_LIBS})
|
||||
set_target_properties(${_helper_target} PROPERTIES
|
||||
MACOSX_BUNDLE_INFO_PLIST ${_helper_info_plist}
|
||||
OUTPUT_NAME ${_helper_output_name}
|
||||
C_STANDARD 11
|
||||
C_STANDARD_REQUIRED ON
|
||||
XCODE_ATTRIBUTE_GCC_C_LANGUAGE_STANDARD "c11"
|
||||
)
|
||||
|
||||
# Add the Helper as a dependency of the main executable target.
|
||||
add_dependencies(${CEF_TARGET} "${_helper_target}")
|
||||
|
||||
# Copy the Helper app bundle into the Frameworks directory.
|
||||
add_custom_command(
|
||||
TARGET ${CEF_TARGET}
|
||||
POST_BUILD
|
||||
COMMAND ${CMAKE_COMMAND} -E copy_directory
|
||||
"${CEF_TARGET_OUT_DIR}/${_helper_output_name}.app"
|
||||
"${CEF_APP}/Contents/Frameworks/${_helper_output_name}.app"
|
||||
VERBATIM
|
||||
)
|
||||
endforeach()
|
||||
|
||||
# Manually process and copy over resource files.
|
||||
# The Xcode generator can support this via the set_target_properties RESOURCE
|
||||
# directive but that doesn't properly handle nested resource directories.
|
||||
# Remove these prefixes from input file paths.
|
||||
set(PREFIXES "mac/")
|
||||
COPY_MAC_RESOURCES("${CEFSIMPLE_CAPI_RESOURCES_SRCS}" "${PREFIXES}" "${CEF_TARGET}" "${CMAKE_CURRENT_SOURCE_DIR}" "${CEF_APP}")
|
||||
endif()
|
||||
|
||||
|
||||
#
|
||||
# Windows configuration.
|
||||
#
|
||||
|
||||
if(OS_WINDOWS)
|
||||
if(USE_SANDBOX)
|
||||
# Shared library (DLL) target.
|
||||
add_library(${CEF_TARGET} SHARED ${CEFSIMPLE_CAPI_SRCS})
|
||||
SET_LIBRARY_TARGET_PROPERTIES(${CEF_TARGET})
|
||||
set_target_properties(${CEF_TARGET} PROPERTIES
|
||||
C_STANDARD 11
|
||||
C_STANDARD_REQUIRED ON
|
||||
)
|
||||
|
||||
# Copy and rename the bootstrap binary.
|
||||
COPY_SINGLE_FILE(${CEF_TARGET} ${CEF_BINARY_DIR}/bootstrap.exe ${CEF_TARGET_OUT_DIR}/${CEF_TARGET}.exe)
|
||||
|
||||
if (CMAKE_GENERATOR MATCHES "Visual Studio")
|
||||
# Make the bootstrap binary the default command for the Visual Studio debugger.
|
||||
set_target_properties(${CEF_TARGET} PROPERTIES
|
||||
VS_DEBUGGER_COMMAND "$<TARGET_FILE_DIR:${CEF_TARGET}>/${CEF_TARGET}.exe"
|
||||
)
|
||||
endif()
|
||||
else()
|
||||
# Executable target.
|
||||
add_executable(${CEF_TARGET} WIN32 ${CEFSIMPLE_CAPI_SRCS})
|
||||
SET_EXECUTABLE_TARGET_PROPERTIES(${CEF_TARGET})
|
||||
set_target_properties(${CEF_TARGET} PROPERTIES
|
||||
C_STANDARD 11
|
||||
C_STANDARD_REQUIRED ON
|
||||
)
|
||||
|
||||
# Add the custom manifest files to the executable.
|
||||
ADD_WINDOWS_MANIFEST("${CMAKE_CURRENT_SOURCE_DIR}/win" "${CEF_TARGET}" "exe")
|
||||
endif()
|
||||
|
||||
add_dependencies(${CEF_TARGET} libcef_dll_wrapper)
|
||||
target_link_libraries(${CEF_TARGET} libcef_lib libcef_dll_wrapper ${CEF_STANDARD_LIBS})
|
||||
|
||||
# Enable C11 atomics support (required for stdatomic.h in MSVC).
|
||||
# Must use set_property instead of CEF_C_COMPILER_FLAGS because the Visual Studio
|
||||
# generator doesn't properly handle this flag when passed through generator expressions.
|
||||
if(CMAKE_GENERATOR MATCHES "Visual Studio")
|
||||
set_property(TARGET ${CEF_TARGET} APPEND PROPERTY COMPILE_OPTIONS "/experimental:c11atomics")
|
||||
endif()
|
||||
|
||||
# Copy binary and resource files to the target output directory.
|
||||
COPY_FILES("${CEF_TARGET}" "${CEF_BINARY_FILES}" "${CEF_BINARY_DIR}" "${CEF_TARGET_OUT_DIR}")
|
||||
COPY_FILES("${CEF_TARGET}" "${CEF_RESOURCE_FILES}" "${CEF_RESOURCE_DIR}" "${CEF_TARGET_OUT_DIR}")
|
||||
|
||||
if(USE_SANDBOX)
|
||||
# Set LPAC ACLs required for Windows sandbox support.
|
||||
SET_LPAC_ACLS("${CEF_TARGET}")
|
||||
endif()
|
||||
endif()
|
||||
@@ -0,0 +1,114 @@
|
||||
# CEF Simple C API Example
|
||||
|
||||
This directory contains a pure C implementation of the cefsimple sample application using the CEF C API (CAPI).
|
||||
|
||||
## Overview
|
||||
|
||||
This is a conversion of `cef/tests/cefsimple` from C++ to pure C, demonstrating:
|
||||
|
||||
- **Pure C implementation** - No C++ code, uses C11 standard
|
||||
- **Manual reference counting** - Using atomic operations for thread safety
|
||||
- **CEF C API usage** - All CEF calls use the C API (`include/capi/*.h`)
|
||||
- **Cross-platform** - Supports Windows, Linux, and macOS
|
||||
|
||||
### Maintenance Pattern
|
||||
|
||||
This project serves as a reference C API implementation that mirrors the C++ `cefsimple` example. When changes are made to `cef/tests/cefsimple` (the C++ version), **equivalent changes should be applied to this project** using the C API patterns.
|
||||
|
||||
**Intended workflow:**
|
||||
|
||||
1. Changes are made to C++ `cefsimple` (new features, API updates, bug fixes)
|
||||
2. Claude Code analyzes the C++ changes
|
||||
3. Claude Code applies equivalent changes to `cefsimple_capi` using CEF C API
|
||||
4. Result: Both examples stay in sync, demonstrating the same functionality in C++ and C
|
||||
|
||||
**Example Claude prompt:**
|
||||
```
|
||||
Apply the equivalent changes from the latest commits in cef/tests/cefsimple
|
||||
to cef/tests/cefsimple_capi, converting the C++ code to C API patterns.
|
||||
Use the reference counting and handler patterns from UsingTheCAPI.md.
|
||||
```
|
||||
|
||||
This ensures the C API example remains current and demonstrates the same CEF features as the C++ version.
|
||||
|
||||
## Learning Path
|
||||
|
||||
For best results, we recommend this learning path:
|
||||
|
||||
1. **[CEF Tutorial](https://bitbucket.org/chromiumembedded/cef/wiki/Tutorial.md)** - Start here to understand CEF architecture and concepts using the C++ cefsimple example
|
||||
2. **[Using the C API](https://bitbucket.org/chromiumembedded/cef/wiki/UsingTheCAPI.md)** - Learn C-specific patterns and reference counting rules
|
||||
3. **This example (cefsimple_capi)** - See the C API implementation in practice
|
||||
|
||||
**Note:** The Tutorial uses C++ code examples, but the architectural concepts (processes, threads, callbacks, program flow) apply equally to the C API version.
|
||||
|
||||
## Architecture
|
||||
|
||||
### Utility Modules
|
||||
|
||||
- **ref_counted.h** - Macros for implementing reference counting (`IMPLEMENT_REFCOUNTING_SIMPLE`, `IMPLEMENT_REFCOUNTING_MANUAL`, `INIT_CEF_BASE_REFCOUNTED`)
|
||||
- **simple_utils.h** - Common utilities (`CHECK` macro for invariant validation)
|
||||
- **simple_browser_list.h/c** - Dynamic list of browser instances with automatic reference counting
|
||||
|
||||
### Application Core
|
||||
|
||||
- **simple_app.h/c** - Application handler (`cef_app_t`) and browser process handler
|
||||
|
||||
### Client Handler Module
|
||||
|
||||
- **simple_handler.h** - Client handler interface and structure definitions
|
||||
- **simple_handler.c** - Main client handler implementation, public API, and browser close operations
|
||||
- **simple_display_handler.c** - Display handler (title change notifications)
|
||||
- **simple_life_span_handler.c** - Life span handler (browser lifecycle management)
|
||||
- **simple_load_handler.c** - Load handler (error page display)
|
||||
|
||||
### Views Framework
|
||||
|
||||
- **simple_views.h/c** - Browser view and window delegates for Views-based UI
|
||||
|
||||
### Platform-Specific Files
|
||||
|
||||
#### Windows
|
||||
|
||||
- **cefsimple_win.c** - Windows entry point (wWinMain)
|
||||
- **simple_handler_win.c** - Windows-specific handler (window title updates)
|
||||
|
||||
#### Linux
|
||||
|
||||
- **cefsimple_linux.c** - Linux entry point (main)
|
||||
- **simple_handler_linux.c** - Linux/X11-specific handler (window title updates)
|
||||
|
||||
#### macOS
|
||||
|
||||
- **cefsimple_mac.m** - macOS entry point with NSApplication integration
|
||||
- **simple_handler_mac.m** - macOS-specific handler (window title updates)
|
||||
- **process_helper_mac.c** - Helper process entry point
|
||||
|
||||
## Key Differences from C++ Version
|
||||
|
||||
The C API requires significantly different patterns than C++:
|
||||
|
||||
- **Manual reference counting** - Implement atomic `add_ref`/`release` functions instead of `IMPLEMENT_REFCOUNTING` macro
|
||||
- **Explicit parameter release** - Must call `release()` on all object parameters in callbacks (memory leak if forgotten)
|
||||
- **Function pointers** - Use structure fields with `CEF_CALLBACK` functions instead of virtual methods
|
||||
- **Manual string conversion** - Use `cef_string_from_ascii()` / `cef_string_clear()` instead of `CefString` class
|
||||
- **Structure initialization** - Use `calloc()` and set function pointers instead of C++ constructors
|
||||
|
||||
**See [UsingTheCAPI.md](https://bitbucket.org/chromiumembedded/cef/wiki/UsingTheCAPI.md) for complete C API patterns and examples.**
|
||||
|
||||
## Critical C API Rules
|
||||
|
||||
When working with the C API, you **must** follow these rules to avoid crashes and memory leaks:
|
||||
|
||||
1. **CEF structure MUST be first member** - Allows safe casting between base and wrapper types
|
||||
2. **Set `size` to CEF type size** - Use `sizeof(cef_*_t)`, not `sizeof(your_wrapper_t)`
|
||||
3. **Release all callback parameters** - Except `self`; failure causes memory leaks
|
||||
4. **Add reference when returning to CEF** - CEF will release when done
|
||||
5. **Use atomic operations** - Reference counting functions called from any thread
|
||||
|
||||
**See [UsingTheCAPI.md](https://bitbucket.org/chromiumembedded/cef/wiki/UsingTheCAPI.md) for detailed explanations, complete code examples, and reference counting patterns.**
|
||||
|
||||
## References
|
||||
|
||||
- [CEF Tutorial](https://bitbucket.org/chromiumembedded/cef/wiki/Tutorial.md) - Architecture overview (uses C++ examples)
|
||||
- [CEF C API Documentation](https://bitbucket.org/chromiumembedded/cef/wiki/UsingTheCAPI.md) - C-specific patterns
|
||||
- [Original C++ cefsimple](../cefsimple/)
|
||||
@@ -0,0 +1,95 @@
|
||||
// Copyright (c) 2025 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/cefsimple_capi/simple_app.h"
|
||||
|
||||
#if defined(CEF_X11)
|
||||
#include <X11/Xlib.h>
|
||||
#endif
|
||||
|
||||
#include "include/capi/cef_app_capi.h"
|
||||
#include "include/cef_api_hash.h"
|
||||
#include "tests/cefsimple_capi/simple_utils.h"
|
||||
|
||||
#if defined(CEF_X11)
|
||||
static int XErrorHandlerImpl(Display* display, XErrorEvent* event) {
|
||||
// X error handler - just return to avoid terminating the application.
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int XIOErrorHandlerImpl(Display* display) {
|
||||
return 0;
|
||||
}
|
||||
#endif // defined(CEF_X11)
|
||||
|
||||
// Entry point function for all processes.
|
||||
int main(int argc, char* argv[]) {
|
||||
// Configure the CEF API version. This must be called before any other CEF
|
||||
// API functions.
|
||||
cef_api_hash(CEF_API_VERSION, 0);
|
||||
|
||||
// Provide CEF with command-line arguments.
|
||||
cef_main_args_t main_args = {};
|
||||
main_args.argc = argc;
|
||||
main_args.argv = argv;
|
||||
|
||||
// Create the application instance.
|
||||
simple_app_t* app = simple_app_create();
|
||||
CHECK(app);
|
||||
|
||||
// Add reference before cef_execute_process. Both cef_execute_process and
|
||||
// cef_initialize will take ownership of a reference, so we need 2 total.
|
||||
app->app.base.add_ref(&app->app.base);
|
||||
|
||||
// CEF applications have multiple sub-processes (render, GPU, etc) that share
|
||||
// the same executable. This function checks the command-line and, if this is
|
||||
// a sub-process, executes the appropriate logic.
|
||||
int exit_code = cef_execute_process(&main_args, &app->app, NULL);
|
||||
if (exit_code >= 0) {
|
||||
// The sub-process has completed so return here.
|
||||
// cef_execute_process took ownership of one reference.
|
||||
// Release only the additional reference we added.
|
||||
app->app.base.release(&app->app.base);
|
||||
return exit_code;
|
||||
}
|
||||
|
||||
#if defined(CEF_X11)
|
||||
// Install xlib error handlers so that the application won't be terminated
|
||||
// on non-fatal errors.
|
||||
XSetErrorHandler(XErrorHandlerImpl);
|
||||
XSetIOErrorHandler(XIOErrorHandlerImpl);
|
||||
#endif
|
||||
|
||||
// Specify CEF global settings here.
|
||||
cef_settings_t settings = {};
|
||||
settings.size = sizeof(cef_settings_t);
|
||||
|
||||
// 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 = 1;
|
||||
#endif
|
||||
|
||||
// Initialize the CEF browser process. May return false if initialization
|
||||
// fails or if early exit is desired (for example, due to process singleton
|
||||
// relaunch behavior).
|
||||
if (!cef_initialize(&main_args, &settings, &app->app, NULL)) {
|
||||
app->app.base.release(&app->app.base);
|
||||
return cef_get_exit_code();
|
||||
}
|
||||
|
||||
// Run the CEF message loop. This will block until cef_quit_message_loop() is
|
||||
// called.
|
||||
cef_run_message_loop();
|
||||
|
||||
// Shut down CEF.
|
||||
cef_shutdown();
|
||||
|
||||
// Note: We DON'T release the app here.
|
||||
// We transferred our creation reference to CEF via cef_initialize.
|
||||
// CEF will release it during cef_shutdown().
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,179 @@
|
||||
// Copyright (c) 2025 The Chromium Embedded Framework Authors.
|
||||
// Portions copyright (c) 2010 The Chromium Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#import <Cocoa/Cocoa.h>
|
||||
|
||||
#include "include/capi/cef_app_capi.h"
|
||||
#include "include/cef_api_hash.h"
|
||||
#include "include/cef_application_mac.h"
|
||||
#include "include/wrapper/cef_library_loader.h"
|
||||
#include "tests/cefsimple_capi/simple_app.h"
|
||||
#include "tests/cefsimple_capi/simple_handler.h"
|
||||
#include "tests/cefsimple_capi/simple_utils.h"
|
||||
|
||||
// Receives notifications from the application.
|
||||
@interface SimpleAppDelegate : NSObject <NSApplicationDelegate>
|
||||
- (void)createApplication:(id)object;
|
||||
- (void)tryToTerminateApplication:(NSApplication*)app;
|
||||
@end
|
||||
|
||||
// Provide the CefAppProtocol implementation required by CEF.
|
||||
@interface SimpleApplication : NSApplication <CefAppProtocol> {
|
||||
@private
|
||||
BOOL handlingSendEvent_;
|
||||
}
|
||||
@end
|
||||
|
||||
@implementation SimpleApplication
|
||||
- (BOOL)isHandlingSendEvent {
|
||||
return handlingSendEvent_;
|
||||
}
|
||||
|
||||
- (void)setHandlingSendEvent:(BOOL)handlingSendEvent {
|
||||
handlingSendEvent_ = handlingSendEvent;
|
||||
}
|
||||
|
||||
- (void)sendEvent:(NSEvent*)event {
|
||||
BOOL wasHandlingSendEvent = [self isHandlingSendEvent];
|
||||
[self setHandlingSendEvent:YES];
|
||||
[super sendEvent:event];
|
||||
[self setHandlingSendEvent:wasHandlingSendEvent];
|
||||
}
|
||||
|
||||
- (void)terminate:(id)sender {
|
||||
SimpleAppDelegate* delegate = (SimpleAppDelegate*)[NSApp delegate];
|
||||
[delegate tryToTerminateApplication:self];
|
||||
// Return, don't exit. The application is responsible for exiting on its own.
|
||||
}
|
||||
@end
|
||||
|
||||
@implementation SimpleAppDelegate
|
||||
|
||||
// Create the application on the UI thread.
|
||||
- (void)createApplication:(id)object {
|
||||
[[NSBundle mainBundle] loadNibNamed:@"MainMenu"
|
||||
owner:NSApp
|
||||
topLevelObjects:nil];
|
||||
|
||||
// Set the delegate for application events.
|
||||
[[NSApplication sharedApplication] setDelegate:self];
|
||||
}
|
||||
|
||||
- (void)tryToTerminateApplication:(NSApplication*)app {
|
||||
simple_handler_t* handler = simple_handler_get_instance();
|
||||
if (handler && !handler->is_closing) {
|
||||
simple_handler_close_all_browsers(handler, 0);
|
||||
}
|
||||
}
|
||||
|
||||
- (NSApplicationTerminateReply)applicationShouldTerminate:
|
||||
(NSApplication*)sender {
|
||||
return NSTerminateNow;
|
||||
}
|
||||
|
||||
// Called when the user clicks the app dock icon while the application is
|
||||
// already running.
|
||||
- (BOOL)applicationShouldHandleReopen:(NSApplication*)theApplication
|
||||
hasVisibleWindows:(BOOL)flag {
|
||||
simple_handler_t* handler = simple_handler_get_instance();
|
||||
if (handler && !handler->is_closing) {
|
||||
simple_handler_show_main_window(handler);
|
||||
}
|
||||
return NO;
|
||||
}
|
||||
|
||||
// Requests that any state restoration archive be created with secure encoding
|
||||
// (macOS 12+ only). See https://crrev.com/c737387656 for details. This also
|
||||
// fixes an issue with macOS default behavior incorrectly restoring windows
|
||||
// after hard reset (holding down the power button).
|
||||
- (BOOL)applicationSupportsSecureRestorableState:(NSApplication*)app {
|
||||
return YES;
|
||||
}
|
||||
@end
|
||||
|
||||
// Entry point function for the browser process.
|
||||
int main(int argc, char* argv[]) {
|
||||
// Load the CEF framework library at runtime instead of linking directly
|
||||
// as required by the macOS sandbox implementation.
|
||||
void* library_loader = cef_scoped_library_loader_create(/*helper=*/0);
|
||||
if (!library_loader) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Configure the CEF API version. This must be called before any other CEF
|
||||
// API functions.
|
||||
cef_api_hash(CEF_API_VERSION, 0);
|
||||
|
||||
// Provide CEF with command-line arguments.
|
||||
cef_main_args_t main_args = {};
|
||||
main_args.argc = argc;
|
||||
main_args.argv = argv;
|
||||
|
||||
@autoreleasepool {
|
||||
// Initialize the SimpleApplication instance.
|
||||
[SimpleApplication sharedApplication];
|
||||
|
||||
// If there was an invocation to NSApp prior to this method, then the NSApp
|
||||
// will not be a SimpleApplication, but will instead be an NSApplication.
|
||||
// This is undesirable and we must enforce that this doesn't happen.
|
||||
if (![NSApp isKindOfClass:[SimpleApplication class]]) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Create the application instance.
|
||||
simple_app_t* app = simple_app_create();
|
||||
CHECK(app);
|
||||
|
||||
// Specify CEF global settings here.
|
||||
cef_settings_t settings = {};
|
||||
settings.size = sizeof(cef_settings_t);
|
||||
|
||||
// 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 = 1;
|
||||
#endif
|
||||
|
||||
// Initialize the CEF browser process. May return false if initialization
|
||||
// fails or if early exit is desired (for example, due to process singleton
|
||||
// relaunch behavior).
|
||||
if (!cef_initialize(&main_args, &settings, &app->app, NULL)) {
|
||||
app->app.base.release(&app->app.base);
|
||||
return cef_get_exit_code();
|
||||
}
|
||||
|
||||
// Create the application delegate.
|
||||
SimpleAppDelegate* delegate = [[SimpleAppDelegate alloc] init];
|
||||
// Set as the delegate for application events.
|
||||
NSApp.delegate = delegate;
|
||||
|
||||
[delegate performSelectorOnMainThread:@selector(createApplication:)
|
||||
withObject:nil
|
||||
waitUntilDone:NO];
|
||||
|
||||
// Run the CEF message loop. This will block until cef_quit_message_loop()
|
||||
// is called.
|
||||
cef_run_message_loop();
|
||||
|
||||
// Shut down CEF.
|
||||
cef_shutdown();
|
||||
|
||||
// Release the delegate.
|
||||
#if !__has_feature(objc_arc)
|
||||
[delegate release];
|
||||
#endif // !__has_feature(objc_arc)
|
||||
delegate = nil;
|
||||
|
||||
// Note: We DON'T release the app here.
|
||||
// We transferred our creation reference to CEF via cef_initialize.
|
||||
// CEF will release it during cef_shutdown().
|
||||
} // @autoreleasepool
|
||||
|
||||
// Unload the CEF framework library.
|
||||
cef_scoped_library_loader_free(library_loader);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,134 @@
|
||||
// Copyright (c) 2025 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 <windows.h>
|
||||
|
||||
#include "include/capi/cef_app_capi.h"
|
||||
#include "include/cef_api_hash.h"
|
||||
#include "include/cef_sandbox_win.h"
|
||||
#include "tests/cefsimple_capi/simple_app.h"
|
||||
#include "tests/cefsimple_capi/simple_utils.h"
|
||||
|
||||
static int RunMain(HINSTANCE hInstance,
|
||||
LPTSTR lpCmdLine,
|
||||
int nCmdShow,
|
||||
void* sandbox_info) {
|
||||
int exit_code;
|
||||
|
||||
// Configure the CEF API version. This must be called before any other CEF
|
||||
// API functions.
|
||||
cef_api_hash(CEF_API_VERSION, 0);
|
||||
|
||||
// Provide CEF with command-line arguments.
|
||||
cef_main_args_t main_args = {};
|
||||
main_args.instance = hInstance;
|
||||
|
||||
// Create the application instance.
|
||||
simple_app_t* app = simple_app_create();
|
||||
CHECK(app);
|
||||
|
||||
// Add reference before cef_execute_process. Both cef_execute_process and
|
||||
// cef_initialize will take ownership of a reference, so we need 2 total.
|
||||
app->app.base.add_ref(&app->app.base);
|
||||
|
||||
// CEF applications have multiple sub-processes (render, GPU, etc) that share
|
||||
// the same executable. This function checks the command-line and, if this is
|
||||
// a sub-process, executes the appropriate logic.
|
||||
exit_code = cef_execute_process(&main_args, &app->app, sandbox_info);
|
||||
if (exit_code >= 0) {
|
||||
// The sub-process has completed so return here.
|
||||
// cef_execute_process took ownership of one reference.
|
||||
// Release only the additional reference we added.
|
||||
app->app.base.release(&app->app.base);
|
||||
return exit_code;
|
||||
}
|
||||
|
||||
// Specify CEF global settings here.
|
||||
cef_settings_t settings = {};
|
||||
settings.size = sizeof(cef_settings_t);
|
||||
|
||||
if (!sandbox_info) {
|
||||
settings.no_sandbox = 1;
|
||||
}
|
||||
|
||||
// Initialize the CEF browser process. May return false if initialization
|
||||
// fails or if early exit is desired (for example, due to process singleton
|
||||
// relaunch behavior).
|
||||
if (!cef_initialize(&main_args, &settings, &app->app, sandbox_info)) {
|
||||
app->app.base.release(&app->app.base);
|
||||
return cef_get_exit_code();
|
||||
}
|
||||
|
||||
// Run the CEF message loop. This will block until cef_quit_message_loop() is
|
||||
// called.
|
||||
cef_run_message_loop();
|
||||
|
||||
// Shut down CEF.
|
||||
cef_shutdown();
|
||||
|
||||
// Note: We DON'T release the app here.
|
||||
// We transferred our creation reference to CEF via cef_initialize.
|
||||
// CEF will release it during cef_shutdown().
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#if defined(CEF_USE_BOOTSTRAP)
|
||||
|
||||
// Entry point called by bootstrap.exe when built as a DLL.
|
||||
CEF_BOOTSTRAP_EXPORT int RunWinMain(HINSTANCE hInstance,
|
||||
LPTSTR lpCmdLine,
|
||||
int nCmdShow,
|
||||
void* sandbox_info,
|
||||
cef_version_info_t* version_info) {
|
||||
(void)version_info; // Unused parameter
|
||||
return RunMain(hInstance, lpCmdLine, nCmdShow, sandbox_info);
|
||||
}
|
||||
|
||||
#else // !defined(CEF_USE_BOOTSTRAP)
|
||||
|
||||
// Entry point function for all processes.
|
||||
int APIENTRY wWinMain(HINSTANCE hInstance,
|
||||
HINSTANCE hPrevInstance,
|
||||
LPTSTR lpCmdLine,
|
||||
int nCmdShow) {
|
||||
UNREFERENCED_PARAMETER(hPrevInstance);
|
||||
UNREFERENCED_PARAMETER(lpCmdLine);
|
||||
|
||||
#if defined(ARCH_CPU_32_BITS)
|
||||
// Run the main thread on 32-bit Windows using a fiber with the preferred 4MiB
|
||||
// stack size. This function must be called at the top of the executable entry
|
||||
// point function (`main()` or `wWinMain()`). It is used in combination with
|
||||
// the initial stack size of 0.5MiB configured via the `/STACK:0x80000` linker
|
||||
// flag on executable targets. This saves significant memory on threads (like
|
||||
// those in the Windows thread pool, and others) whose stack size can only be
|
||||
// controlled via the linker flag.
|
||||
int exit_code = cef_run_winmain_with_preferred_stack_size(
|
||||
wWinMain, hInstance, lpCmdLine, nCmdShow);
|
||||
if (exit_code >= 0) {
|
||||
// The fiber has completed so return here.
|
||||
return exit_code;
|
||||
}
|
||||
#endif
|
||||
|
||||
void* sandbox_info = NULL;
|
||||
|
||||
#if defined(CEF_USE_SANDBOX)
|
||||
// Manage the life span of the sandbox information object. This is necessary
|
||||
// for sandbox support on Windows. See cef_sandbox_win.h for complete details.
|
||||
sandbox_info = cef_sandbox_info_create();
|
||||
#endif
|
||||
|
||||
int result = RunMain(hInstance, lpCmdLine, nCmdShow, sandbox_info);
|
||||
|
||||
#if defined(CEF_USE_SANDBOX)
|
||||
if (sandbox_info) {
|
||||
cef_sandbox_info_destroy(sandbox_info);
|
||||
}
|
||||
#endif
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
#endif // !defined(CEF_USE_BOOTSTRAP)
|
||||
@@ -0,0 +1,3 @@
|
||||
/* Localized versions of Info.plist keys */
|
||||
|
||||
NSHumanReadableCopyright = "© Chromium Embedded Framework Authors, 2013";
|
||||
@@ -0,0 +1,330 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="10117" systemVersion="16B2657" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none">
|
||||
<dependencies>
|
||||
<deployment version="1090" identifier="macosx"/>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="10117"/>
|
||||
</dependencies>
|
||||
<objects>
|
||||
<customObject id="-2" userLabel="File's Owner" customClass="NSApplication"/>
|
||||
<customObject id="-1" userLabel="First Responder" customClass="FirstResponder"/>
|
||||
<customObject id="-3" userLabel="Application"/>
|
||||
<menu title="AMainMenu" systemMenu="main" id="29" userLabel="MainMenu">
|
||||
<items>
|
||||
<menuItem title="cefsimple" id="56">
|
||||
<menu key="submenu" title="TestShell" systemMenu="apple" id="57">
|
||||
<items>
|
||||
<menuItem title="About cefsimple" id="58">
|
||||
<modifierMask key="keyEquivalentModifierMask"/>
|
||||
<connections>
|
||||
<action selector="orderFrontStandardAboutPanel:" target="-2" id="142"/>
|
||||
</connections>
|
||||
</menuItem>
|
||||
<menuItem isSeparatorItem="YES" id="236">
|
||||
<modifierMask key="keyEquivalentModifierMask" command="YES"/>
|
||||
</menuItem>
|
||||
<menuItem title="Preferences…" keyEquivalent="," id="129" userLabel="121"/>
|
||||
<menuItem isSeparatorItem="YES" id="143">
|
||||
<modifierMask key="keyEquivalentModifierMask" command="YES"/>
|
||||
</menuItem>
|
||||
<menuItem title="Services" id="131">
|
||||
<menu key="submenu" title="Services" systemMenu="services" id="130"/>
|
||||
</menuItem>
|
||||
<menuItem isSeparatorItem="YES" id="144">
|
||||
<modifierMask key="keyEquivalentModifierMask" command="YES"/>
|
||||
</menuItem>
|
||||
<menuItem title="Hide cefsimple" keyEquivalent="h" id="134">
|
||||
<connections>
|
||||
<action selector="hide:" target="-1" id="367"/>
|
||||
</connections>
|
||||
</menuItem>
|
||||
<menuItem title="Hide Others" keyEquivalent="h" id="145">
|
||||
<modifierMask key="keyEquivalentModifierMask" option="YES" command="YES"/>
|
||||
<connections>
|
||||
<action selector="hideOtherApplications:" target="-1" id="368"/>
|
||||
</connections>
|
||||
</menuItem>
|
||||
<menuItem title="Show All" id="150">
|
||||
<connections>
|
||||
<action selector="unhideAllApplications:" target="-1" id="370"/>
|
||||
</connections>
|
||||
</menuItem>
|
||||
<menuItem isSeparatorItem="YES" id="149">
|
||||
<modifierMask key="keyEquivalentModifierMask" command="YES"/>
|
||||
</menuItem>
|
||||
<menuItem title="Quit cefsimple" keyEquivalent="q" id="136" userLabel="1111">
|
||||
<connections>
|
||||
<action selector="terminate:" target="-1" id="369"/>
|
||||
</connections>
|
||||
</menuItem>
|
||||
</items>
|
||||
</menu>
|
||||
</menuItem>
|
||||
<menuItem title="File" id="83">
|
||||
<menu key="submenu" title="File" id="81">
|
||||
<items>
|
||||
<menuItem title="New" keyEquivalent="n" id="82" userLabel="9">
|
||||
<connections>
|
||||
<action selector="newDocument:" target="-1" id="373"/>
|
||||
</connections>
|
||||
</menuItem>
|
||||
<menuItem title="Open…" keyEquivalent="o" id="72">
|
||||
<connections>
|
||||
<action selector="openDocument:" target="-1" id="374"/>
|
||||
</connections>
|
||||
</menuItem>
|
||||
<menuItem title="Open Recent" id="124">
|
||||
<menu key="submenu" title="Open Recent" systemMenu="recentDocuments" id="125">
|
||||
<items>
|
||||
<menuItem title="Clear Menu" id="126">
|
||||
<connections>
|
||||
<action selector="clearRecentDocuments:" target="-1" id="127"/>
|
||||
</connections>
|
||||
</menuItem>
|
||||
</items>
|
||||
</menu>
|
||||
</menuItem>
|
||||
<menuItem isSeparatorItem="YES" id="79" userLabel="7">
|
||||
<modifierMask key="keyEquivalentModifierMask" command="YES"/>
|
||||
</menuItem>
|
||||
<menuItem title="Close" keyEquivalent="w" id="73" userLabel="1">
|
||||
<connections>
|
||||
<action selector="performClose:" target="-1" id="193"/>
|
||||
</connections>
|
||||
</menuItem>
|
||||
<menuItem title="Save" keyEquivalent="s" id="75" userLabel="3">
|
||||
<connections>
|
||||
<action selector="saveDocument:" target="-1" id="362"/>
|
||||
</connections>
|
||||
</menuItem>
|
||||
<menuItem title="Save As…" keyEquivalent="S" id="80" userLabel="8">
|
||||
<modifierMask key="keyEquivalentModifierMask" shift="YES" command="YES"/>
|
||||
<connections>
|
||||
<action selector="saveDocumentAs:" target="-1" id="363"/>
|
||||
</connections>
|
||||
</menuItem>
|
||||
<menuItem title="Revert to Saved" id="112" userLabel="10">
|
||||
<modifierMask key="keyEquivalentModifierMask"/>
|
||||
<connections>
|
||||
<action selector="revertDocumentToSaved:" target="-1" id="364"/>
|
||||
</connections>
|
||||
</menuItem>
|
||||
<menuItem isSeparatorItem="YES" id="74" userLabel="2">
|
||||
<modifierMask key="keyEquivalentModifierMask" command="YES"/>
|
||||
</menuItem>
|
||||
<menuItem title="Page Setup..." keyEquivalent="P" id="77" userLabel="5">
|
||||
<modifierMask key="keyEquivalentModifierMask" shift="YES" command="YES"/>
|
||||
<connections>
|
||||
<action selector="runPageLayout:" target="-1" id="87"/>
|
||||
</connections>
|
||||
</menuItem>
|
||||
<menuItem title="Print…" keyEquivalent="p" id="78" userLabel="6">
|
||||
<connections>
|
||||
<action selector="print:" target="-1" id="86"/>
|
||||
</connections>
|
||||
</menuItem>
|
||||
</items>
|
||||
</menu>
|
||||
</menuItem>
|
||||
<menuItem title="Edit" id="217">
|
||||
<menu key="submenu" title="Edit" id="205">
|
||||
<items>
|
||||
<menuItem title="Undo" keyEquivalent="z" id="207">
|
||||
<connections>
|
||||
<action selector="undo:" target="-1" id="223"/>
|
||||
</connections>
|
||||
</menuItem>
|
||||
<menuItem title="Redo" keyEquivalent="Z" id="215">
|
||||
<modifierMask key="keyEquivalentModifierMask" shift="YES" command="YES"/>
|
||||
<connections>
|
||||
<action selector="redo:" target="-1" id="231"/>
|
||||
</connections>
|
||||
</menuItem>
|
||||
<menuItem isSeparatorItem="YES" id="206">
|
||||
<modifierMask key="keyEquivalentModifierMask" command="YES"/>
|
||||
</menuItem>
|
||||
<menuItem title="Cut" keyEquivalent="x" id="199">
|
||||
<connections>
|
||||
<action selector="cut:" target="-1" id="228"/>
|
||||
</connections>
|
||||
</menuItem>
|
||||
<menuItem title="Copy" keyEquivalent="c" id="197">
|
||||
<connections>
|
||||
<action selector="copy:" target="-1" id="224"/>
|
||||
</connections>
|
||||
</menuItem>
|
||||
<menuItem title="Paste" keyEquivalent="v" id="203">
|
||||
<connections>
|
||||
<action selector="paste:" target="-1" id="226"/>
|
||||
</connections>
|
||||
</menuItem>
|
||||
<menuItem title="Delete" id="202">
|
||||
<connections>
|
||||
<action selector="delete:" target="-1" id="235"/>
|
||||
</connections>
|
||||
</menuItem>
|
||||
<menuItem title="Select All" keyEquivalent="a" id="198">
|
||||
<connections>
|
||||
<action selector="selectAll:" target="-1" id="232"/>
|
||||
</connections>
|
||||
</menuItem>
|
||||
<menuItem isSeparatorItem="YES" id="214">
|
||||
<modifierMask key="keyEquivalentModifierMask" command="YES"/>
|
||||
</menuItem>
|
||||
<menuItem title="Find" id="218">
|
||||
<menu key="submenu" title="Find" id="220">
|
||||
<items>
|
||||
<menuItem title="Find…" tag="1" keyEquivalent="f" id="209">
|
||||
<connections>
|
||||
<action selector="performFindPanelAction:" target="-1" id="241"/>
|
||||
</connections>
|
||||
</menuItem>
|
||||
<menuItem title="Find Next" tag="2" keyEquivalent="g" id="208"/>
|
||||
<menuItem title="Find Previous" tag="3" keyEquivalent="G" id="213">
|
||||
<modifierMask key="keyEquivalentModifierMask" shift="YES" command="YES"/>
|
||||
</menuItem>
|
||||
<menuItem title="Use Selection for Find" tag="7" keyEquivalent="e" id="221"/>
|
||||
<menuItem title="Jump to Selection" keyEquivalent="j" id="210">
|
||||
<connections>
|
||||
<action selector="centerSelectionInVisibleArea:" target="-1" id="245"/>
|
||||
</connections>
|
||||
</menuItem>
|
||||
</items>
|
||||
</menu>
|
||||
</menuItem>
|
||||
<menuItem title="Spelling and Grammar" id="216">
|
||||
<menu key="submenu" title="Spelling and Grammar" id="200">
|
||||
<items>
|
||||
<menuItem title="Show Spelling…" keyEquivalent=":" id="204">
|
||||
<connections>
|
||||
<action selector="showGuessPanel:" target="-1" id="230"/>
|
||||
</connections>
|
||||
</menuItem>
|
||||
<menuItem title="Check Spelling" keyEquivalent=";" id="201">
|
||||
<connections>
|
||||
<action selector="checkSpelling:" target="-1" id="225"/>
|
||||
</connections>
|
||||
</menuItem>
|
||||
<menuItem title="Check Spelling While Typing" id="219">
|
||||
<connections>
|
||||
<action selector="toggleContinuousSpellChecking:" target="-1" id="222"/>
|
||||
</connections>
|
||||
</menuItem>
|
||||
<menuItem title="Check Grammar With Spelling" id="346">
|
||||
<connections>
|
||||
<action selector="toggleGrammarChecking:" target="-1" id="347"/>
|
||||
</connections>
|
||||
</menuItem>
|
||||
</items>
|
||||
</menu>
|
||||
</menuItem>
|
||||
<menuItem title="Substitutions" id="348">
|
||||
<menu key="submenu" title="Substitutions" id="349">
|
||||
<items>
|
||||
<menuItem title="Smart Copy/Paste" tag="1" keyEquivalent="f" id="350">
|
||||
<connections>
|
||||
<action selector="toggleSmartInsertDelete:" target="-1" id="355"/>
|
||||
</connections>
|
||||
</menuItem>
|
||||
<menuItem title="Smart Quotes" tag="2" keyEquivalent="g" id="351">
|
||||
<connections>
|
||||
<action selector="toggleAutomaticQuoteSubstitution:" target="-1" id="356"/>
|
||||
</connections>
|
||||
</menuItem>
|
||||
<menuItem title="Smart Links" tag="3" keyEquivalent="G" id="354">
|
||||
<modifierMask key="keyEquivalentModifierMask" shift="YES" command="YES"/>
|
||||
<connections>
|
||||
<action selector="toggleAutomaticLinkDetection:" target="-1" id="357"/>
|
||||
</connections>
|
||||
</menuItem>
|
||||
</items>
|
||||
</menu>
|
||||
</menuItem>
|
||||
<menuItem title="Speech" id="211">
|
||||
<menu key="submenu" title="Speech" id="212">
|
||||
<items>
|
||||
<menuItem title="Start Speaking" id="196">
|
||||
<connections>
|
||||
<action selector="startSpeaking:" target="-1" id="233"/>
|
||||
</connections>
|
||||
</menuItem>
|
||||
<menuItem title="Stop Speaking" id="195">
|
||||
<connections>
|
||||
<action selector="stopSpeaking:" target="-1" id="227"/>
|
||||
</connections>
|
||||
</menuItem>
|
||||
</items>
|
||||
</menu>
|
||||
</menuItem>
|
||||
</items>
|
||||
</menu>
|
||||
</menuItem>
|
||||
<menuItem title="Format" id="299">
|
||||
<menu key="submenu" title="Format" id="300">
|
||||
<items>
|
||||
<menuItem title="Show Fonts" keyEquivalent="t" id="344"/>
|
||||
<menuItem title="Show Colors" keyEquivalent="C" id="345">
|
||||
<modifierMask key="keyEquivalentModifierMask" shift="YES" command="YES"/>
|
||||
<connections>
|
||||
<action selector="orderFrontColorPanel:" target="-1" id="361"/>
|
||||
</connections>
|
||||
</menuItem>
|
||||
</items>
|
||||
</menu>
|
||||
</menuItem>
|
||||
<menuItem title="View" id="295">
|
||||
<menu key="submenu" title="View" id="296">
|
||||
<items>
|
||||
<menuItem title="Show Toolbar" keyEquivalent="t" id="297">
|
||||
<modifierMask key="keyEquivalentModifierMask" option="YES" command="YES"/>
|
||||
<connections>
|
||||
<action selector="toggleToolbarShown:" target="-1" id="366"/>
|
||||
</connections>
|
||||
</menuItem>
|
||||
<menuItem title="Customize Toolbar…" id="298">
|
||||
<connections>
|
||||
<action selector="runToolbarCustomizationPalette:" target="-1" id="365"/>
|
||||
</connections>
|
||||
</menuItem>
|
||||
</items>
|
||||
</menu>
|
||||
</menuItem>
|
||||
<menuItem title="Window" id="19">
|
||||
<menu key="submenu" title="Window" systemMenu="window" id="24">
|
||||
<items>
|
||||
<menuItem title="Minimize" keyEquivalent="m" id="23">
|
||||
<connections>
|
||||
<action selector="performMiniaturize:" target="-1" id="37"/>
|
||||
</connections>
|
||||
</menuItem>
|
||||
<menuItem title="Zoom" id="239">
|
||||
<connections>
|
||||
<action selector="performZoom:" target="-1" id="240"/>
|
||||
</connections>
|
||||
</menuItem>
|
||||
<menuItem isSeparatorItem="YES" id="92">
|
||||
<modifierMask key="keyEquivalentModifierMask" command="YES"/>
|
||||
</menuItem>
|
||||
<menuItem title="Bring All to Front" id="5">
|
||||
<connections>
|
||||
<action selector="arrangeInFront:" target="-1" id="39"/>
|
||||
</connections>
|
||||
</menuItem>
|
||||
</items>
|
||||
</menu>
|
||||
</menuItem>
|
||||
<menuItem title="Help" id="103" userLabel="1">
|
||||
<menu key="submenu" title="Help" id="106" userLabel="2">
|
||||
<items>
|
||||
<menuItem title="cefsimple Help" keyEquivalent="?" id="111">
|
||||
<connections>
|
||||
<action selector="showHelp:" target="-1" id="360"/>
|
||||
</connections>
|
||||
</menuItem>
|
||||
</items>
|
||||
</menu>
|
||||
</menuItem>
|
||||
</items>
|
||||
</menu>
|
||||
<userDefaultsController representsSharedInstance="YES" id="389"/>
|
||||
</objects>
|
||||
</document>
|
||||
@@ -0,0 +1,39 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>CFBundleDevelopmentRegion</key>
|
||||
<string>English</string>
|
||||
<key>CFBundleExecutable</key>
|
||||
<string>${EXECUTABLE_NAME}</string>
|
||||
<key>CFBundleIconFile</key>
|
||||
<string>cefsimple_capi.icns</string>
|
||||
<key>CFBundleIdentifier</key>
|
||||
<string>org.cef.cefsimple_capi</string>
|
||||
<key>CFBundleInfoDictionaryVersion</key>
|
||||
<string>6.0</string>
|
||||
<key>CFBundleName</key>
|
||||
<string>${PRODUCT_NAME}</string>
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>APPL</string>
|
||||
<key>CFBundleSignature</key>
|
||||
<string>????</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>${VERSION_SHORT}</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>${VERSION_SHORT}</string>
|
||||
<key>LSEnvironment</key>
|
||||
<dict>
|
||||
<key>MallocNanoZone</key>
|
||||
<string>0</string>
|
||||
</dict>
|
||||
<key>LSMinimumSystemVersion</key>
|
||||
<string>12.0</string>
|
||||
<key>NSMainNibFile</key>
|
||||
<string>MainMenu</string>
|
||||
<key>NSPrincipalClass</key>
|
||||
<string>NSApplication</string>
|
||||
<key>NSSupportsAutomaticGraphicsSwitching</key>
|
||||
<true/>
|
||||
</dict>
|
||||
</plist>
|
||||
Binary file not shown.
@@ -0,0 +1,39 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>CFBundleDevelopmentRegion</key>
|
||||
<string>en</string>
|
||||
<key>CFBundleDisplayName</key>
|
||||
<string>${EXECUTABLE_NAME}</string>
|
||||
<key>CFBundleExecutable</key>
|
||||
<string>${EXECUTABLE_NAME}</string>
|
||||
<key>CFBundleIdentifier</key>
|
||||
<string>org.cef.cefsimple_capi.helper${BUNDLE_ID_SUFFIX}</string>
|
||||
<key>CFBundleInfoDictionaryVersion</key>
|
||||
<string>6.0</string>
|
||||
<key>CFBundleName</key>
|
||||
<string>${PRODUCT_NAME}</string>
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>APPL</string>
|
||||
<key>CFBundleSignature</key>
|
||||
<string>????</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>${VERSION_SHORT}</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>${VERSION_SHORT}</string>
|
||||
<key>LSEnvironment</key>
|
||||
<dict>
|
||||
<key>MallocNanoZone</key>
|
||||
<string>0</string>
|
||||
</dict>
|
||||
<key>LSFileQuarantineEnabled</key>
|
||||
<true/>
|
||||
<key>LSMinimumSystemVersion</key>
|
||||
<string>12.0</string>
|
||||
<key>LSUIElement</key>
|
||||
<string>1</string>
|
||||
<key>NSSupportsAutomaticGraphicsSwitching</key>
|
||||
<true/>
|
||||
</dict>
|
||||
</plist>
|
||||
@@ -0,0 +1,57 @@
|
||||
// Copyright (c) 2025 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 "include/capi/cef_app_capi.h"
|
||||
#include "include/cef_api_hash.h"
|
||||
#include "include/wrapper/cef_library_loader.h"
|
||||
|
||||
// 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)
|
||||
#include "include/cef_sandbox_mac.h"
|
||||
#endif
|
||||
|
||||
// Entry point function for sub-processes.
|
||||
int main(int argc, char* argv[]) {
|
||||
#if defined(CEF_USE_SANDBOX)
|
||||
// Initialize the macOS sandbox for this helper process.
|
||||
void* sandbox_context = cef_scoped_sandbox_initialize(argc, argv);
|
||||
if (!sandbox_context) {
|
||||
return 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
// Load the CEF framework library at runtime instead of linking directly
|
||||
// as required by the macOS sandbox implementation.
|
||||
void* library_loader = cef_scoped_library_loader_create(/*helper=*/1);
|
||||
if (!library_loader) {
|
||||
#if defined(CEF_USE_SANDBOX)
|
||||
cef_scoped_sandbox_destroy(sandbox_context);
|
||||
#endif
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Configure the CEF API version. This must be called before any other CEF
|
||||
// API functions.
|
||||
cef_api_hash(CEF_API_VERSION, 0);
|
||||
|
||||
// Provide CEF with command-line arguments.
|
||||
cef_main_args_t main_args = {};
|
||||
main_args.argc = argc;
|
||||
main_args.argv = argv;
|
||||
|
||||
// Execute the sub-process.
|
||||
int result = cef_execute_process(&main_args, NULL, NULL);
|
||||
|
||||
// Unload the CEF framework library.
|
||||
cef_unload_library();
|
||||
|
||||
#if defined(CEF_USE_SANDBOX)
|
||||
// Destroy the sandbox context.
|
||||
cef_scoped_sandbox_destroy(sandbox_context);
|
||||
#endif
|
||||
|
||||
return result;
|
||||
}
|
||||
@@ -0,0 +1,85 @@
|
||||
// Copyright (c) 2025 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_TESTS_CEFSIMPLE_CAPI_REF_COUNTED_H_
|
||||
#define CEF_TESTS_CEFSIMPLE_CAPI_REF_COUNTED_H_
|
||||
|
||||
#include <stdatomic.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
// Generic macros for implementing reference counting on CEF C API structures.
|
||||
// These macros help reduce boilerplate when implementing add_ref, release,
|
||||
// has_one_ref, and has_at_least_one_ref functions.
|
||||
|
||||
// Macro to implement add_ref for a structure type.
|
||||
// Usage: IMPLEMENT_ADDREF(my_struct_t, my_struct, ref_count)
|
||||
#define IMPLEMENT_ADDREF(struct_type, struct_name, ref_field) \
|
||||
void CEF_CALLBACK struct_name##_add_ref(cef_base_ref_counted_t* self) { \
|
||||
struct_type* obj = (struct_type*)self; \
|
||||
atomic_fetch_add(&obj->ref_field, 1); \
|
||||
}
|
||||
|
||||
// Macro to implement has_one_ref for a structure type.
|
||||
#define IMPLEMENT_HAS_ONE_REF(struct_type, struct_name, ref_field) \
|
||||
int CEF_CALLBACK struct_name##_has_one_ref(cef_base_ref_counted_t* self) { \
|
||||
struct_type* obj = (struct_type*)self; \
|
||||
return atomic_load(&obj->ref_field) == 1; \
|
||||
}
|
||||
|
||||
// Macro to implement has_at_least_one_ref for a structure type.
|
||||
#define IMPLEMENT_HAS_AT_LEAST_ONE_REF(struct_type, struct_name, ref_field) \
|
||||
int CEF_CALLBACK struct_name##_has_at_least_one_ref( \
|
||||
cef_base_ref_counted_t* self) { \
|
||||
struct_type* obj = (struct_type*)self; \
|
||||
return atomic_load(&obj->ref_field) >= 1; \
|
||||
}
|
||||
|
||||
// Macro to implement a simple release function that only frees the object.
|
||||
// Use this for structures that don't own other ref-counted objects.
|
||||
// For complex cleanup, implement release manually.
|
||||
// Usage: IMPLEMENT_RELEASE_SIMPLE(my_struct_t, my_struct, ref_count)
|
||||
#define IMPLEMENT_RELEASE_SIMPLE(struct_type, struct_name, ref_field) \
|
||||
int CEF_CALLBACK struct_name##_release(cef_base_ref_counted_t* self) { \
|
||||
struct_type* obj = (struct_type*)self; \
|
||||
int count = atomic_fetch_sub(&obj->ref_field, 1) - 1; \
|
||||
if (count == 0) { \
|
||||
free(obj); \
|
||||
return 1; \
|
||||
} \
|
||||
return 0; \
|
||||
}
|
||||
|
||||
// Implement all ref-counting for structures with no cleanup needed.
|
||||
// Use when structure only needs free(), no owned objects to release.
|
||||
// Usage: IMPLEMENT_REFCOUNTING_SIMPLE(my_struct_t, my_struct, ref_count)
|
||||
#define IMPLEMENT_REFCOUNTING_SIMPLE(struct_type, struct_name, ref_field) \
|
||||
IMPLEMENT_ADDREF(struct_type, struct_name, ref_field) \
|
||||
IMPLEMENT_RELEASE_SIMPLE(struct_type, struct_name, ref_field) \
|
||||
IMPLEMENT_HAS_ONE_REF(struct_type, struct_name, ref_field) \
|
||||
IMPLEMENT_HAS_AT_LEAST_ONE_REF(struct_type, struct_name, ref_field)
|
||||
|
||||
// Implement ref-counting WITHOUT release for structures with custom cleanup.
|
||||
// Use when you need to manually implement release() with custom logic.
|
||||
// You must manually implement struct_name##_release().
|
||||
// Usage: IMPLEMENT_REFCOUNTING_MANUAL(my_struct_t, my_struct, ref_count)
|
||||
#define IMPLEMENT_REFCOUNTING_MANUAL(struct_type, struct_name, ref_field) \
|
||||
IMPLEMENT_ADDREF(struct_type, struct_name, ref_field) \
|
||||
IMPLEMENT_HAS_ONE_REF(struct_type, struct_name, ref_field) \
|
||||
IMPLEMENT_HAS_AT_LEAST_ONE_REF(struct_type, struct_name, ref_field)
|
||||
|
||||
// Macro to initialize CEF base ref-counted structure.
|
||||
// Must be called after allocating the structure.
|
||||
// Usage: INIT_CEF_BASE_REFCOUNTED(ptr, cef_type_t, struct_name)
|
||||
// Example: INIT_CEF_BASE_REFCOUNTED(&handler->handler, cef_display_handler_t,
|
||||
// display_handler)
|
||||
#define INIT_CEF_BASE_REFCOUNTED(ptr, cef_type, struct_name) \
|
||||
do { \
|
||||
(ptr)->size = sizeof(cef_type); \
|
||||
(ptr)->add_ref = struct_name##_add_ref; \
|
||||
(ptr)->release = struct_name##_release; \
|
||||
(ptr)->has_one_ref = struct_name##_has_one_ref; \
|
||||
(ptr)->has_at_least_one_ref = struct_name##_has_at_least_one_ref; \
|
||||
} while (0)
|
||||
|
||||
#endif // CEF_TESTS_CEFSIMPLE_CAPI_REF_COUNTED_H_
|
||||
@@ -0,0 +1,26 @@
|
||||
// Copyright (c) 2013 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.
|
||||
|
||||
//{{NO_DEPENDENCIES}}
|
||||
// Microsoft Visual C++ generated include file.
|
||||
// Used by cefsimple.rc
|
||||
//
|
||||
|
||||
#define IDI_CEFSIMPLE 120
|
||||
#define IDI_SMALL 121
|
||||
|
||||
// Avoid files associated with MacOS
|
||||
#define _X86_
|
||||
|
||||
// Next default values for new objects
|
||||
//
|
||||
#ifdef APSTUDIO_INVOKED
|
||||
#ifndef APSTUDIO_READONLY_SYMBOLS
|
||||
#define _APS_NO_MFC 1
|
||||
#define _APS_NEXT_RESOURCE_VALUE 102
|
||||
#define _APS_NEXT_COMMAND_VALUE 32700
|
||||
#define _APS_NEXT_CONTROL_VALUE 1000
|
||||
#define _APS_NEXT_SYMED_VALUE 102
|
||||
#endif
|
||||
#endif
|
||||
@@ -0,0 +1,290 @@
|
||||
// Copyright (c) 2025 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/cefsimple_capi/simple_app.h"
|
||||
|
||||
#include <stdatomic.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "include/capi/cef_browser_capi.h"
|
||||
#include "include/capi/cef_command_line_capi.h"
|
||||
#include "include/capi/views/cef_browser_view_capi.h"
|
||||
#include "include/capi/views/cef_window_capi.h"
|
||||
#include "tests/cefsimple_capi/ref_counted.h"
|
||||
#include "tests/cefsimple_capi/simple_handler.h"
|
||||
#include "tests/cefsimple_capi/simple_utils.h"
|
||||
#include "tests/cefsimple_capi/simple_views.h"
|
||||
|
||||
// Implement reference counting functions for simple_app_t.
|
||||
IMPLEMENT_REFCOUNTING_MANUAL(simple_app_t, simple_app, ref_count)
|
||||
|
||||
// Release function for simple_app_t with custom cleanup logic.
|
||||
int CEF_CALLBACK simple_app_release(cef_base_ref_counted_t* self) {
|
||||
simple_app_t* app = (simple_app_t*)self;
|
||||
int count = atomic_fetch_sub(&app->ref_count, 1) - 1;
|
||||
if (count == 0) {
|
||||
// Release the browser process handler if we own one.
|
||||
if (app->browser_process_handler) {
|
||||
app->browser_process_handler->handler.base.release(
|
||||
&app->browser_process_handler->handler.base);
|
||||
}
|
||||
free(app);
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Returns the browser process handler.
|
||||
// Adds a reference before returning (CEF will release it when done).
|
||||
cef_browser_process_handler_t* CEF_CALLBACK
|
||||
simple_app_get_browser_process_handler(cef_app_t* self) {
|
||||
simple_app_t* app = (simple_app_t*)self;
|
||||
if (app->browser_process_handler) {
|
||||
// Add reference for CEF (it will release when done).
|
||||
app->browser_process_handler->handler.base.add_ref(
|
||||
&app->browser_process_handler->handler.base);
|
||||
return &app->browser_process_handler->handler;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Forward declarations for browser process handler functions.
|
||||
void CEF_CALLBACK browser_process_handler_on_context_initialized(
|
||||
cef_browser_process_handler_t* self);
|
||||
cef_client_t* CEF_CALLBACK
|
||||
browser_process_handler_get_default_client(cef_browser_process_handler_t* self);
|
||||
|
||||
// Implement reference counting functions for browser process handler.
|
||||
IMPLEMENT_REFCOUNTING_SIMPLE(simple_browser_process_handler_t,
|
||||
browser_process_handler,
|
||||
ref_count)
|
||||
|
||||
// Called after CEF initialization to create the browser.
|
||||
void CEF_CALLBACK browser_process_handler_on_context_initialized(
|
||||
cef_browser_process_handler_t* self) {
|
||||
// Get the global command line.
|
||||
cef_command_line_t* command_line = cef_command_line_get_global();
|
||||
CHECK(command_line);
|
||||
|
||||
// Check if Alloy style will be used.
|
||||
cef_string_t alloy_switch = {};
|
||||
cef_string_from_ascii("use-alloy-style", 15, &alloy_switch);
|
||||
int use_alloy_style = command_line->has_switch(command_line, &alloy_switch);
|
||||
cef_string_clear(&alloy_switch);
|
||||
|
||||
// Create the client handler.
|
||||
simple_handler_t* client_handler = simple_handler_create(use_alloy_style);
|
||||
CHECK(client_handler);
|
||||
|
||||
// The client_handler is stored globally via simple_handler_get_instance().
|
||||
// GetDefaultClient() will retrieve it from there when needed.
|
||||
|
||||
// Specify CEF browser settings.
|
||||
cef_browser_settings_t browser_settings = {};
|
||||
browser_settings.size = sizeof(cef_browser_settings_t);
|
||||
|
||||
// Get the URL from command line or use default.
|
||||
cef_string_t url_switch = {};
|
||||
cef_string_from_ascii("url", 3, &url_switch);
|
||||
cef_string_userfree_t url_value =
|
||||
command_line->get_switch_value(command_line, &url_switch);
|
||||
cef_string_clear(&url_switch);
|
||||
|
||||
cef_string_t url = {};
|
||||
if (url_value && url_value->length > 0) {
|
||||
cef_string_copy(url_value->str, url_value->length, &url);
|
||||
} else {
|
||||
cef_string_from_ascii("https://www.google.com", 22, &url);
|
||||
}
|
||||
if (url_value) {
|
||||
cef_string_userfree_free(url_value);
|
||||
}
|
||||
|
||||
// Check if Views framework should be used.
|
||||
// Views is enabled by default (add `--use-native` to disable).
|
||||
cef_string_t native_switch = {};
|
||||
cef_string_from_ascii("use-native", 10, &native_switch);
|
||||
int use_native = command_line->has_switch(command_line, &native_switch);
|
||||
cef_string_clear(&native_switch);
|
||||
|
||||
int use_views = !use_native;
|
||||
|
||||
// Determine runtime style.
|
||||
cef_runtime_style_t runtime_style = CEF_RUNTIME_STYLE_DEFAULT;
|
||||
if (use_alloy_style) {
|
||||
runtime_style = CEF_RUNTIME_STYLE_ALLOY;
|
||||
}
|
||||
|
||||
if (use_views) {
|
||||
// Create the BrowserView using Views framework.
|
||||
simple_browser_view_delegate_t* browser_view_delegate =
|
||||
browser_view_delegate_create(runtime_style);
|
||||
CHECK(browser_view_delegate);
|
||||
|
||||
// Create the browser view.
|
||||
// We transfer our client_handler and browser_view_delegate references to
|
||||
// CEF. CEF will release them when the browser view is destroyed.
|
||||
cef_browser_view_t* browser_view = cef_browser_view_create(
|
||||
&client_handler->client, &url, &browser_settings, NULL, NULL,
|
||||
&browser_view_delegate->delegate);
|
||||
|
||||
// Note: We DON'T release browser_view_delegate here - we transferred
|
||||
// ownership to CEF.
|
||||
|
||||
if (browser_view) {
|
||||
// Optionally configure the initial show state.
|
||||
cef_show_state_t initial_show_state = CEF_SHOW_STATE_NORMAL;
|
||||
cef_string_t show_state_switch = {};
|
||||
cef_string_from_ascii("initial-show-state", 18, &show_state_switch);
|
||||
cef_string_userfree_t show_state_value =
|
||||
command_line->get_switch_value(command_line, &show_state_switch);
|
||||
cef_string_clear(&show_state_switch);
|
||||
|
||||
if (show_state_value && show_state_value->length > 0) {
|
||||
// Check for "minimized"
|
||||
cef_string_t minimized = {};
|
||||
cef_string_from_ascii("minimized", 9, &minimized);
|
||||
if (cef_string_utf16_cmp(show_state_value, &minimized) == 0) {
|
||||
initial_show_state = CEF_SHOW_STATE_MINIMIZED;
|
||||
}
|
||||
cef_string_clear(&minimized);
|
||||
|
||||
// Check for "maximized"
|
||||
cef_string_t maximized = {};
|
||||
cef_string_from_ascii("maximized", 9, &maximized);
|
||||
if (cef_string_utf16_cmp(show_state_value, &maximized) == 0) {
|
||||
initial_show_state = CEF_SHOW_STATE_MAXIMIZED;
|
||||
}
|
||||
cef_string_clear(&maximized);
|
||||
|
||||
#if defined(OS_MAC)
|
||||
// Hidden show state is only supported on macOS.
|
||||
cef_string_t hidden = {};
|
||||
cef_string_from_ascii("hidden", 6, &hidden);
|
||||
if (cef_string_utf16_cmp(show_state_value, &hidden) == 0) {
|
||||
initial_show_state = CEF_SHOW_STATE_HIDDEN;
|
||||
}
|
||||
cef_string_clear(&hidden);
|
||||
#endif
|
||||
}
|
||||
|
||||
if (show_state_value) {
|
||||
cef_string_userfree_free(show_state_value);
|
||||
}
|
||||
|
||||
// Create the Window. It will show itself after creation.
|
||||
// We transfer our browser_view reference to the window delegate.
|
||||
simple_window_delegate_t* window_delegate = window_delegate_create(
|
||||
browser_view, runtime_style, initial_show_state);
|
||||
CHECK(window_delegate);
|
||||
|
||||
// Create the window.
|
||||
// We transfer our window_delegate reference to CEF.
|
||||
cef_window_create_top_level(&window_delegate->delegate);
|
||||
}
|
||||
} else {
|
||||
// Information used when creating the native window.
|
||||
cef_window_info_t window_info = {};
|
||||
window_info.size = sizeof(cef_window_info_t);
|
||||
|
||||
#if defined(OS_WIN)
|
||||
// On Windows we need to specify certain flags that will be passed to
|
||||
// CreateWindowEx().
|
||||
cef_string_t window_name = {};
|
||||
cef_string_from_ascii("cefsimple_capi", 14, &window_name);
|
||||
|
||||
window_info.style =
|
||||
WS_OVERLAPPEDWINDOW | WS_CLIPCHILDREN | WS_CLIPSIBLINGS | WS_VISIBLE;
|
||||
window_info.bounds.x = CW_USEDEFAULT;
|
||||
window_info.bounds.y = CW_USEDEFAULT;
|
||||
window_info.bounds.width = CW_USEDEFAULT;
|
||||
window_info.bounds.height = CW_USEDEFAULT;
|
||||
window_info.window_name = window_name;
|
||||
#elif defined(OS_LINUX)
|
||||
window_info.bounds.width = 800;
|
||||
window_info.bounds.height = 600;
|
||||
#endif
|
||||
|
||||
// Use the runtime style determined earlier.
|
||||
window_info.runtime_style = runtime_style;
|
||||
|
||||
// Create the browser window.
|
||||
// We pass our creation reference to CEF - don't release it!
|
||||
// CEF takes ownership of this reference and will release it when the
|
||||
// browser closes.
|
||||
cef_browser_host_create_browser(&window_info, &client_handler->client, &url,
|
||||
&browser_settings, NULL, NULL);
|
||||
|
||||
#if defined(OS_WIN)
|
||||
cef_string_clear(&window_name);
|
||||
#endif
|
||||
}
|
||||
|
||||
cef_string_clear(&url);
|
||||
// Note: We DON'T release the client_handler here.
|
||||
// We transferred our creation reference to CEF via
|
||||
// cef_browser_host_create_browser. CEF will release it when the browser
|
||||
// closes.
|
||||
}
|
||||
|
||||
// Returns the default client handler for Chrome style UI.
|
||||
cef_client_t* CEF_CALLBACK browser_process_handler_get_default_client(
|
||||
cef_browser_process_handler_t* self) {
|
||||
// Return the global instance (matches C++ SimpleApp::GetDefaultClient).
|
||||
simple_handler_t* instance = simple_handler_get_instance();
|
||||
if (instance) {
|
||||
// Add reference before returning (CEF will release it).
|
||||
instance->client.base.add_ref(&instance->client.base);
|
||||
return &instance->client;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Creates a browser process handler instance.
|
||||
simple_browser_process_handler_t* browser_process_handler_create(void) {
|
||||
simple_browser_process_handler_t* handler =
|
||||
(simple_browser_process_handler_t*)calloc(
|
||||
1, sizeof(simple_browser_process_handler_t));
|
||||
CHECK(handler);
|
||||
|
||||
// Initialize base structure.
|
||||
INIT_CEF_BASE_REFCOUNTED(&handler->handler.base,
|
||||
cef_browser_process_handler_t,
|
||||
browser_process_handler);
|
||||
|
||||
// Set callbacks.
|
||||
handler->handler.on_context_initialized =
|
||||
browser_process_handler_on_context_initialized;
|
||||
handler->handler.get_default_client =
|
||||
browser_process_handler_get_default_client;
|
||||
|
||||
// Initialize with ref count of 1.
|
||||
atomic_store(&handler->ref_count, 1);
|
||||
|
||||
return handler;
|
||||
}
|
||||
|
||||
// Creates the application instance.
|
||||
simple_app_t* simple_app_create(void) {
|
||||
simple_app_t* app = (simple_app_t*)calloc(1, sizeof(simple_app_t));
|
||||
CHECK(app);
|
||||
|
||||
// Initialize base structure.
|
||||
INIT_CEF_BASE_REFCOUNTED(&app->app.base, cef_app_t, simple_app);
|
||||
|
||||
// Set callbacks.
|
||||
app->app.get_browser_process_handler = simple_app_get_browser_process_handler;
|
||||
|
||||
// Create the browser process handler.
|
||||
app->browser_process_handler = browser_process_handler_create();
|
||||
CHECK(app->browser_process_handler);
|
||||
|
||||
// Initialize with ref count of 1.
|
||||
atomic_store(&app->ref_count, 1);
|
||||
|
||||
return app;
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
// Copyright (c) 2025 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_TESTS_CEFSIMPLE_CAPI_SIMPLE_APP_H_
|
||||
#define CEF_TESTS_CEFSIMPLE_CAPI_SIMPLE_APP_H_
|
||||
|
||||
#include <stdatomic.h>
|
||||
|
||||
#include "include/capi/cef_app_capi.h"
|
||||
#include "include/capi/cef_browser_process_handler_capi.h"
|
||||
|
||||
// Forward declaration.
|
||||
typedef struct _simple_browser_process_handler_t
|
||||
simple_browser_process_handler_t;
|
||||
typedef struct _simple_handler_t simple_handler_t;
|
||||
|
||||
// Application handler structure.
|
||||
// Implements cef_app_t interface.
|
||||
typedef struct _simple_app_t {
|
||||
// MUST be first member - CEF base structure.
|
||||
cef_app_t app;
|
||||
|
||||
// Reference count for this object.
|
||||
atomic_int ref_count;
|
||||
|
||||
// Browser process handler (owned by this structure).
|
||||
simple_browser_process_handler_t* browser_process_handler;
|
||||
} simple_app_t;
|
||||
|
||||
// Browser process handler structure.
|
||||
// Implements cef_browser_process_handler_t interface.
|
||||
typedef struct _simple_browser_process_handler_t {
|
||||
// MUST be first member - CEF base structure.
|
||||
cef_browser_process_handler_t handler;
|
||||
|
||||
// Reference count for this object.
|
||||
atomic_int ref_count;
|
||||
|
||||
// Note: We don't store a client reference here.
|
||||
// GetDefaultClient() uses simple_handler_get_instance() to get the global
|
||||
// instance.
|
||||
} simple_browser_process_handler_t;
|
||||
|
||||
// Create a new application handler instance.
|
||||
// Returns a pointer with ref count of 1.
|
||||
// Caller is responsible for releasing the reference when done.
|
||||
simple_app_t* simple_app_create(void);
|
||||
|
||||
#endif // CEF_TESTS_CEFSIMPLE_CAPI_SIMPLE_APP_H_
|
||||
@@ -0,0 +1,96 @@
|
||||
// Copyright (c) 2025 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/cefsimple_capi/simple_browser_list.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "tests/cefsimple_capi/simple_utils.h"
|
||||
|
||||
void browser_list_init(browser_list_t* list) {
|
||||
CHECK(list);
|
||||
list->browsers = NULL;
|
||||
list->count = 0;
|
||||
list->capacity = 0;
|
||||
}
|
||||
|
||||
int browser_list_add(browser_list_t* list, cef_browser_t* browser) {
|
||||
CHECK(list);
|
||||
CHECK(browser);
|
||||
|
||||
// Ensure capacity.
|
||||
if (list->count >= list->capacity) {
|
||||
size_t new_capacity = list->capacity == 0 ? 4 : list->capacity * 2;
|
||||
cef_browser_t** new_list = (cef_browser_t**)realloc(
|
||||
list->browsers, new_capacity * sizeof(cef_browser_t*));
|
||||
if (!new_list) {
|
||||
return 0; // Allocation failed.
|
||||
}
|
||||
list->browsers = new_list;
|
||||
list->capacity = new_capacity;
|
||||
}
|
||||
|
||||
// Add a reference for the list.
|
||||
// The list now owns one reference to this browser.
|
||||
browser->base.add_ref(&browser->base);
|
||||
|
||||
// Store the browser pointer.
|
||||
list->browsers[list->count++] = browser;
|
||||
return 1;
|
||||
}
|
||||
|
||||
void browser_list_remove(browser_list_t* list, cef_browser_t* browser) {
|
||||
CHECK(list);
|
||||
CHECK(browser);
|
||||
|
||||
// Find and remove the browser.
|
||||
for (size_t i = 0; i < list->count; ++i) {
|
||||
// Add a reference before calling is_same, since CEF functions take
|
||||
// ownership of parameters passed to them.
|
||||
browser->base.add_ref(&browser->base);
|
||||
|
||||
if (list->browsers[i]->is_same(list->browsers[i], browser)) {
|
||||
// Release the list's reference to this browser.
|
||||
list->browsers[i]->base.release(&list->browsers[i]->base);
|
||||
|
||||
// Shift remaining elements.
|
||||
for (size_t j = i; j < list->count - 1; ++j) {
|
||||
list->browsers[j] = list->browsers[j + 1];
|
||||
}
|
||||
list->count--;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void browser_list_destroy(browser_list_t* list) {
|
||||
CHECK(list);
|
||||
|
||||
// Release all browsers in the list.
|
||||
for (size_t i = 0; i < list->count; ++i) {
|
||||
list->browsers[i]->base.release(&list->browsers[i]->base);
|
||||
}
|
||||
|
||||
// Free the array.
|
||||
free(list->browsers);
|
||||
|
||||
// Reset to empty state.
|
||||
list->browsers = NULL;
|
||||
list->count = 0;
|
||||
list->capacity = 0;
|
||||
}
|
||||
|
||||
size_t browser_list_count(const browser_list_t* list) {
|
||||
CHECK(list);
|
||||
return list->count;
|
||||
}
|
||||
|
||||
cef_browser_t* browser_list_get(const browser_list_t* list, size_t index) {
|
||||
CHECK(list);
|
||||
if (index >= list->count) {
|
||||
return NULL;
|
||||
}
|
||||
return list->browsers[index];
|
||||
}
|
||||
@@ -0,0 +1,62 @@
|
||||
// Copyright (c) 2025 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_TESTS_CEFSIMPLE_CAPI_SIMPLE_BROWSER_LIST_H_
|
||||
#define CEF_TESTS_CEFSIMPLE_CAPI_SIMPLE_BROWSER_LIST_H_
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
#include "include/capi/cef_browser_capi.h"
|
||||
|
||||
// Dynamic list of browser instances with automatic reference counting.
|
||||
//
|
||||
// THREAD SAFETY:
|
||||
// - NOT thread-safe. All methods must be called on the CEF UI thread.
|
||||
//
|
||||
// REF-COUNTING RULES:
|
||||
//
|
||||
// browser_list_add():
|
||||
// - Takes a browser pointer and ADDS a reference (list takes ownership)
|
||||
// - Ref count change: +1 (one new reference owned by the list)
|
||||
// - Caller must still release their own reference if they have one
|
||||
//
|
||||
// browser_list_remove():
|
||||
// - Finds the browser in the list and RELEASES the list's reference
|
||||
// - Ref count change: -1 (list gives up ownership)
|
||||
// - Does NOT modify the browser parameter's reference (caller still owns it)
|
||||
//
|
||||
// browser_list_destroy():
|
||||
// - Releases ALL browser references owned by the list
|
||||
// - Frees the internal array
|
||||
//
|
||||
typedef struct {
|
||||
cef_browser_t** browsers;
|
||||
size_t count;
|
||||
size_t capacity;
|
||||
} browser_list_t;
|
||||
|
||||
// Initialize an empty browser list.
|
||||
void browser_list_init(browser_list_t* list);
|
||||
|
||||
// Add a browser to the list.
|
||||
// Adds a reference - the list takes ownership of one reference.
|
||||
int browser_list_add(browser_list_t* list, cef_browser_t* browser);
|
||||
|
||||
// Remove a browser from the list.
|
||||
// Releases the list's reference - does not affect the caller's reference.
|
||||
void browser_list_remove(browser_list_t* list, cef_browser_t* browser);
|
||||
|
||||
// Destroy the browser list.
|
||||
// Releases all browser references and frees internal memory.
|
||||
void browser_list_destroy(browser_list_t* list);
|
||||
|
||||
// Get the number of browsers in the list.
|
||||
size_t browser_list_count(const browser_list_t* list);
|
||||
|
||||
// Get a browser by index.
|
||||
// Does NOT add a reference.
|
||||
// Returns NULL if index is out of bounds.
|
||||
cef_browser_t* browser_list_get(const browser_list_t* list, size_t index);
|
||||
|
||||
#endif // CEF_TESTS_CEFSIMPLE_CAPI_SIMPLE_BROWSER_LIST_H_
|
||||
@@ -0,0 +1,53 @@
|
||||
// Copyright (c) 2025 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 <stdatomic.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "tests/cefsimple_capi/ref_counted.h"
|
||||
#include "tests/cefsimple_capi/simple_handler.h"
|
||||
#include "tests/cefsimple_capi/simple_utils.h"
|
||||
|
||||
//
|
||||
// Display handler implementation.
|
||||
//
|
||||
|
||||
IMPLEMENT_REFCOUNTING_SIMPLE(simple_display_handler_t,
|
||||
display_handler,
|
||||
ref_count)
|
||||
|
||||
void CEF_CALLBACK display_handler_on_title_change(cef_display_handler_t* self,
|
||||
cef_browser_t* browser,
|
||||
const cef_string_t* title) {
|
||||
simple_display_handler_t* handler = (simple_display_handler_t*)self;
|
||||
|
||||
// Call platform-specific implementation.
|
||||
if (handler->parent->is_alloy_style) {
|
||||
simple_handler_platform_title_change(handler->parent, browser, title);
|
||||
}
|
||||
|
||||
// Release the browser reference (CEF gave us one for this callback).
|
||||
browser->base.release(&browser->base);
|
||||
}
|
||||
|
||||
simple_display_handler_t* display_handler_create(simple_handler_t* parent) {
|
||||
simple_display_handler_t* handler =
|
||||
(simple_display_handler_t*)calloc(1, sizeof(simple_display_handler_t));
|
||||
CHECK(handler);
|
||||
|
||||
// Initialize base structure.
|
||||
INIT_CEF_BASE_REFCOUNTED(&handler->handler.base, cef_display_handler_t,
|
||||
display_handler);
|
||||
|
||||
// Set callbacks.
|
||||
handler->handler.on_title_change = display_handler_on_title_change;
|
||||
|
||||
// Store parent reference (no ref count - parent owns us).
|
||||
handler->parent = parent;
|
||||
|
||||
// Initialize with ref count of 1.
|
||||
atomic_store(&handler->ref_count, 1);
|
||||
|
||||
return handler;
|
||||
}
|
||||
@@ -0,0 +1,241 @@
|
||||
// Copyright (c) 2025 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/cefsimple_capi/simple_handler.h"
|
||||
|
||||
#include <stdatomic.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "include/capi/cef_task_capi.h"
|
||||
#include "tests/cefsimple_capi/ref_counted.h"
|
||||
#include "tests/cefsimple_capi/simple_browser_list.h"
|
||||
#include "tests/cefsimple_capi/simple_utils.h"
|
||||
|
||||
// Global instance pointer.
|
||||
static simple_handler_t* g_instance = NULL;
|
||||
|
||||
// Forward declarations for handler create functions.
|
||||
simple_display_handler_t* display_handler_create(simple_handler_t* parent);
|
||||
simple_life_span_handler_t* life_span_handler_create(simple_handler_t* parent);
|
||||
simple_load_handler_t* load_handler_create(simple_handler_t* parent);
|
||||
|
||||
//
|
||||
// Client handler implementation.
|
||||
//
|
||||
|
||||
IMPLEMENT_REFCOUNTING_MANUAL(simple_handler_t, simple_handler, ref_count)
|
||||
|
||||
int CEF_CALLBACK simple_handler_release(cef_base_ref_counted_t* self) {
|
||||
simple_handler_t* handler = (simple_handler_t*)self;
|
||||
int count = atomic_fetch_sub(&handler->ref_count, 1) - 1;
|
||||
if (count == 0) {
|
||||
// Release all handlers.
|
||||
if (handler->display_handler) {
|
||||
handler->display_handler->handler.base.release(
|
||||
&handler->display_handler->handler.base);
|
||||
}
|
||||
if (handler->life_span_handler) {
|
||||
handler->life_span_handler->handler.base.release(
|
||||
&handler->life_span_handler->handler.base);
|
||||
}
|
||||
if (handler->load_handler) {
|
||||
handler->load_handler->handler.base.release(
|
||||
&handler->load_handler->handler.base);
|
||||
}
|
||||
|
||||
// Destroy the browser list.
|
||||
browser_list_destroy(&handler->browser_list);
|
||||
|
||||
// Clear global instance if this is it.
|
||||
if (g_instance == handler) {
|
||||
g_instance = NULL;
|
||||
}
|
||||
|
||||
free(handler);
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
//
|
||||
// Client handler getter implementations.
|
||||
//
|
||||
|
||||
cef_display_handler_t* CEF_CALLBACK
|
||||
simple_handler_get_display_handler(cef_client_t* self) {
|
||||
simple_handler_t* handler = (simple_handler_t*)self;
|
||||
if (handler->display_handler) {
|
||||
// Add reference before returning.
|
||||
handler->display_handler->handler.base.add_ref(
|
||||
&handler->display_handler->handler.base);
|
||||
return &handler->display_handler->handler;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
cef_life_span_handler_t* CEF_CALLBACK
|
||||
simple_handler_get_life_span_handler(cef_client_t* self) {
|
||||
simple_handler_t* handler = (simple_handler_t*)self;
|
||||
if (handler->life_span_handler) {
|
||||
// Add reference before returning.
|
||||
handler->life_span_handler->handler.base.add_ref(
|
||||
&handler->life_span_handler->handler.base);
|
||||
return &handler->life_span_handler->handler;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
cef_load_handler_t* CEF_CALLBACK
|
||||
simple_handler_get_load_handler(cef_client_t* self) {
|
||||
simple_handler_t* handler = (simple_handler_t*)self;
|
||||
if (handler->load_handler) {
|
||||
// Add reference before returning.
|
||||
handler->load_handler->handler.base.add_ref(
|
||||
&handler->load_handler->handler.base);
|
||||
return &handler->load_handler->handler;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
//
|
||||
// Public API implementation.
|
||||
//
|
||||
|
||||
simple_handler_t* simple_handler_create(int is_alloy_style) {
|
||||
simple_handler_t* handler =
|
||||
(simple_handler_t*)calloc(1, sizeof(simple_handler_t));
|
||||
CHECK(handler);
|
||||
|
||||
// Initialize base structure.
|
||||
INIT_CEF_BASE_REFCOUNTED(&handler->client.base, cef_client_t, simple_handler);
|
||||
|
||||
// Set callbacks.
|
||||
handler->client.get_display_handler = simple_handler_get_display_handler;
|
||||
handler->client.get_life_span_handler = simple_handler_get_life_span_handler;
|
||||
handler->client.get_load_handler = simple_handler_get_load_handler;
|
||||
|
||||
// Create sub-handlers.
|
||||
handler->display_handler = display_handler_create(handler);
|
||||
CHECK(handler->display_handler);
|
||||
handler->life_span_handler = life_span_handler_create(handler);
|
||||
CHECK(handler->life_span_handler);
|
||||
handler->load_handler = load_handler_create(handler);
|
||||
CHECK(handler->load_handler);
|
||||
|
||||
// Initialize other fields.
|
||||
handler->is_alloy_style = is_alloy_style;
|
||||
browser_list_init(&handler->browser_list);
|
||||
handler->is_closing = 0;
|
||||
|
||||
// Initialize with ref count of 1.
|
||||
atomic_store(&handler->ref_count, 1);
|
||||
|
||||
// Set global instance.
|
||||
if (!g_instance) {
|
||||
g_instance = handler;
|
||||
}
|
||||
|
||||
return handler;
|
||||
}
|
||||
|
||||
simple_handler_t* simple_handler_get_instance(void) {
|
||||
return g_instance;
|
||||
}
|
||||
|
||||
// Task for closing browsers on the UI thread.
|
||||
typedef struct _close_browsers_task_t {
|
||||
cef_task_t task;
|
||||
atomic_int ref_count;
|
||||
simple_handler_t* handler;
|
||||
int force_close;
|
||||
} close_browsers_task_t;
|
||||
|
||||
IMPLEMENT_REFCOUNTING_MANUAL(close_browsers_task_t,
|
||||
close_browsers_task,
|
||||
ref_count)
|
||||
|
||||
int CEF_CALLBACK close_browsers_task_release(cef_base_ref_counted_t* self) {
|
||||
close_browsers_task_t* task = (close_browsers_task_t*)self;
|
||||
int count = atomic_fetch_sub(&task->ref_count, 1) - 1;
|
||||
if (count == 0) {
|
||||
// Don't release handler reference - we don't own it.
|
||||
free(task);
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void CEF_CALLBACK close_browsers_task_execute(cef_task_t* self) {
|
||||
close_browsers_task_t* task = (close_browsers_task_t*)self;
|
||||
|
||||
size_t count = browser_list_count(&task->handler->browser_list);
|
||||
if (count == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Close all browsers.
|
||||
for (size_t i = 0; i < count; ++i) {
|
||||
cef_browser_t* browser = browser_list_get(&task->handler->browser_list, i);
|
||||
cef_browser_host_t* host = browser->get_host(browser);
|
||||
if (host) {
|
||||
host->close_browser(host, task->force_close);
|
||||
host->base.release(&host->base);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void simple_handler_close_all_browsers(simple_handler_t* handler,
|
||||
int force_close) {
|
||||
CHECK(handler);
|
||||
|
||||
if (!cef_currently_on(TID_UI)) {
|
||||
// Execute on the UI thread.
|
||||
close_browsers_task_t* task =
|
||||
(close_browsers_task_t*)calloc(1, sizeof(close_browsers_task_t));
|
||||
CHECK(task);
|
||||
|
||||
INIT_CEF_BASE_REFCOUNTED(&task->task.base, cef_task_t, close_browsers_task);
|
||||
task->task.execute = close_browsers_task_execute;
|
||||
task->handler = handler;
|
||||
task->force_close = force_close;
|
||||
atomic_store(&task->ref_count, 1);
|
||||
|
||||
cef_post_task(TID_UI, &task->task);
|
||||
return;
|
||||
}
|
||||
|
||||
// Already on UI thread, execute directly.
|
||||
size_t count = browser_list_count(&handler->browser_list);
|
||||
if (count == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < count; ++i) {
|
||||
cef_browser_t* browser = browser_list_get(&handler->browser_list, i);
|
||||
cef_browser_host_t* host = browser->get_host(browser);
|
||||
if (host) {
|
||||
host->close_browser(host, force_close);
|
||||
host->base.release(&host->base);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void simple_handler_show_main_window(simple_handler_t* handler) {
|
||||
CHECK(handler);
|
||||
if (browser_list_count(&handler->browser_list) == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
cef_browser_t* main_browser = browser_list_get(&handler->browser_list, 0);
|
||||
simple_handler_platform_show_window(handler, main_browser);
|
||||
}
|
||||
|
||||
// Default platform implementations (can be overridden in platform-specific
|
||||
// files).
|
||||
#if !defined(OS_MAC)
|
||||
void simple_handler_platform_show_window(simple_handler_t* handler,
|
||||
cef_browser_t* browser) {
|
||||
// Not implemented on this platform.
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,112 @@
|
||||
// Copyright (c) 2025 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_TESTS_CEFSIMPLE_CAPI_SIMPLE_HANDLER_H_
|
||||
#define CEF_TESTS_CEFSIMPLE_CAPI_SIMPLE_HANDLER_H_
|
||||
|
||||
#include <stdatomic.h>
|
||||
|
||||
#include "include/capi/cef_browser_capi.h"
|
||||
#include "include/capi/cef_client_capi.h"
|
||||
#include "tests/cefsimple_capi/simple_browser_list.h"
|
||||
|
||||
// Forward declarations.
|
||||
typedef struct _simple_display_handler_t simple_display_handler_t;
|
||||
typedef struct _simple_life_span_handler_t simple_life_span_handler_t;
|
||||
typedef struct _simple_load_handler_t simple_load_handler_t;
|
||||
|
||||
// Client handler structure.
|
||||
// Implements cef_client_t interface.
|
||||
typedef struct _simple_handler_t {
|
||||
// MUST be first member - CEF base structure.
|
||||
cef_client_t client;
|
||||
|
||||
// Reference count for this object.
|
||||
atomic_int ref_count;
|
||||
|
||||
// Handler implementations (owned by this structure).
|
||||
simple_display_handler_t* display_handler;
|
||||
simple_life_span_handler_t* life_span_handler;
|
||||
simple_load_handler_t* load_handler;
|
||||
|
||||
// True if this client is Alloy style, otherwise Chrome style.
|
||||
int is_alloy_style;
|
||||
|
||||
// List of existing browser windows.
|
||||
browser_list_t browser_list;
|
||||
|
||||
// Set to true when browsers are closing.
|
||||
int is_closing;
|
||||
} simple_handler_t;
|
||||
|
||||
// Display handler structure.
|
||||
// Implements cef_display_handler_t interface.
|
||||
typedef struct _simple_display_handler_t {
|
||||
// MUST be first member - CEF base structure.
|
||||
cef_display_handler_t handler;
|
||||
|
||||
// Reference count for this object.
|
||||
atomic_int ref_count;
|
||||
|
||||
// Back reference to parent handler.
|
||||
simple_handler_t* parent;
|
||||
} simple_display_handler_t;
|
||||
|
||||
// Life span handler structure.
|
||||
// Implements cef_life_span_handler_t interface.
|
||||
typedef struct _simple_life_span_handler_t {
|
||||
// MUST be first member - CEF base structure.
|
||||
cef_life_span_handler_t handler;
|
||||
|
||||
// Reference count for this object.
|
||||
atomic_int ref_count;
|
||||
|
||||
// Back reference to parent handler.
|
||||
simple_handler_t* parent;
|
||||
} simple_life_span_handler_t;
|
||||
|
||||
// Load handler structure.
|
||||
// Implements cef_load_handler_t interface.
|
||||
typedef struct _simple_load_handler_t {
|
||||
// MUST be first member - CEF base structure.
|
||||
cef_load_handler_t handler;
|
||||
|
||||
// Reference count for this object.
|
||||
atomic_int ref_count;
|
||||
|
||||
// Back reference to parent handler.
|
||||
simple_handler_t* parent;
|
||||
} simple_load_handler_t;
|
||||
|
||||
// Create a new client handler instance.
|
||||
// Parameters:
|
||||
// is_alloy_style - 1 for Alloy style, 0 for Chrome style
|
||||
// Returns a pointer with ref count of 1.
|
||||
// Caller is responsible for releasing the reference when done.
|
||||
simple_handler_t* simple_handler_create(int is_alloy_style);
|
||||
|
||||
// Get the global singleton instance (if created).
|
||||
// Does NOT add a reference.
|
||||
// Returns NULL if no instance has been created yet.
|
||||
simple_handler_t* simple_handler_get_instance(void);
|
||||
|
||||
// Request that all existing browser windows close.
|
||||
void simple_handler_close_all_browsers(simple_handler_t* handler,
|
||||
int force_close);
|
||||
|
||||
// Show the main window (for macOS dock icon activation).
|
||||
void simple_handler_show_main_window(simple_handler_t* handler);
|
||||
|
||||
// Platform-specific title change implementation.
|
||||
// Declared here but implemented in platform-specific .c files.
|
||||
void simple_handler_platform_title_change(simple_handler_t* handler,
|
||||
cef_browser_t* browser,
|
||||
const cef_string_t* title);
|
||||
|
||||
// Platform-specific show window implementation (macOS only).
|
||||
// Declared here but implemented in platform-specific .c files.
|
||||
void simple_handler_platform_show_window(simple_handler_t* handler,
|
||||
cef_browser_t* browser);
|
||||
|
||||
#endif // CEF_TESTS_CEFSIMPLE_CAPI_SIMPLE_HANDLER_H_
|
||||
@@ -0,0 +1,60 @@
|
||||
// Copyright (c) 2025 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/cefsimple_capi/simple_handler.h"
|
||||
|
||||
#if defined(CEF_X11)
|
||||
#include <X11/Xatom.h>
|
||||
#include <X11/Xlib.h>
|
||||
#include <string.h>
|
||||
#endif
|
||||
|
||||
#include "include/capi/cef_browser_capi.h"
|
||||
|
||||
void simple_handler_platform_title_change(simple_handler_t* handler,
|
||||
cef_browser_t* browser,
|
||||
const cef_string_t* title) {
|
||||
#if defined(CEF_X11)
|
||||
// Convert the title to UTF-8.
|
||||
cef_string_utf8_t title_utf8 = {};
|
||||
cef_string_to_utf8(title->str, title->length, &title_utf8);
|
||||
|
||||
// Retrieve the X11 display shared with Chromium.
|
||||
Display* display = cef_get_xdisplay();
|
||||
if (!display) {
|
||||
cef_string_utf8_clear(&title_utf8);
|
||||
return;
|
||||
}
|
||||
|
||||
// Retrieve the X11 window handle for the browser.
|
||||
cef_browser_host_t* host = browser->get_host(browser);
|
||||
if (!host) {
|
||||
cef_string_utf8_clear(&title_utf8);
|
||||
return;
|
||||
}
|
||||
|
||||
cef_window_handle_t window = host->get_window_handle(host);
|
||||
if (window == 0) {
|
||||
host->base.release(&host->base);
|
||||
cef_string_utf8_clear(&title_utf8);
|
||||
return;
|
||||
}
|
||||
|
||||
// Retrieve the atoms required by the below XChangeProperty call.
|
||||
const char* kAtoms[] = {"_NET_WM_NAME", "UTF8_STRING"};
|
||||
Atom atoms[2];
|
||||
int result = XInternAtoms(display, (char**)kAtoms, 2, False, atoms);
|
||||
if (result) {
|
||||
// Set the window title.
|
||||
XChangeProperty(display, window, atoms[0], atoms[1], 8, PropModeReplace,
|
||||
(const unsigned char*)title_utf8.str, title_utf8.length);
|
||||
|
||||
// Also set via XStoreName as fallback.
|
||||
XStoreName(display, window, title_utf8.str);
|
||||
}
|
||||
|
||||
host->base.release(&host->base);
|
||||
cef_string_utf8_clear(&title_utf8);
|
||||
#endif // defined(CEF_X11)
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
// Copyright (c) 2025 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/cefsimple_capi/simple_handler.h"
|
||||
|
||||
#import <Cocoa/Cocoa.h>
|
||||
|
||||
#include "include/capi/cef_browser_capi.h"
|
||||
#include "include/internal/cef_types_mac.h"
|
||||
|
||||
static NSWindow* GetNSWindowForBrowser(cef_browser_t* browser) {
|
||||
cef_browser_host_t* host = browser->get_host(browser);
|
||||
if (!host) {
|
||||
return nil;
|
||||
}
|
||||
|
||||
cef_window_handle_t handle = host->get_window_handle(host);
|
||||
host->base.release(&host->base);
|
||||
|
||||
if (!handle) {
|
||||
return nil;
|
||||
}
|
||||
|
||||
NSView* view = CAST_CEF_WINDOW_HANDLE_TO_NSVIEW(handle);
|
||||
return [view window];
|
||||
}
|
||||
|
||||
void simple_handler_platform_title_change(simple_handler_t* handler,
|
||||
cef_browser_t* browser,
|
||||
const cef_string_t* title) {
|
||||
NSWindow* window = GetNSWindowForBrowser(browser);
|
||||
if (!window) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Convert CEF string to UTF-8.
|
||||
cef_string_utf8_t title_utf8 = {};
|
||||
cef_string_to_utf8(title->str, title->length, &title_utf8);
|
||||
|
||||
NSString* str = [NSString stringWithUTF8String:title_utf8.str];
|
||||
[window setTitle:str];
|
||||
|
||||
cef_string_utf8_clear(&title_utf8);
|
||||
}
|
||||
|
||||
void simple_handler_platform_show_window(simple_handler_t* handler,
|
||||
cef_browser_t* browser) {
|
||||
NSWindow* window = GetNSWindowForBrowser(browser);
|
||||
if (!window) {
|
||||
return;
|
||||
}
|
||||
|
||||
[window makeKeyAndOrderFront:window];
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
// Copyright (c) 2025 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/cefsimple_capi/simple_handler.h"
|
||||
|
||||
#include <windows.h>
|
||||
|
||||
#include "include/capi/cef_browser_capi.h"
|
||||
|
||||
void simple_handler_platform_title_change(simple_handler_t* handler,
|
||||
cef_browser_t* browser,
|
||||
const cef_string_t* title) {
|
||||
cef_browser_host_t* host = browser->get_host(browser);
|
||||
if (!host) {
|
||||
return;
|
||||
}
|
||||
|
||||
cef_window_handle_t hwnd = host->get_window_handle(host);
|
||||
if (hwnd) {
|
||||
// CEF uses UTF-16 strings, which Windows SetWindowTextW expects.
|
||||
SetWindowTextW(hwnd, title->str);
|
||||
}
|
||||
|
||||
host->base.release(&host->base);
|
||||
}
|
||||
@@ -0,0 +1,92 @@
|
||||
// Copyright (c) 2025 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 <stdatomic.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "include/capi/cef_app_capi.h"
|
||||
#include "tests/cefsimple_capi/ref_counted.h"
|
||||
#include "tests/cefsimple_capi/simple_browser_list.h"
|
||||
#include "tests/cefsimple_capi/simple_handler.h"
|
||||
#include "tests/cefsimple_capi/simple_utils.h"
|
||||
|
||||
//
|
||||
// Life span handler implementation.
|
||||
//
|
||||
|
||||
IMPLEMENT_REFCOUNTING_SIMPLE(simple_life_span_handler_t,
|
||||
life_span_handler,
|
||||
ref_count)
|
||||
|
||||
void CEF_CALLBACK
|
||||
life_span_handler_on_after_created(cef_life_span_handler_t* self,
|
||||
cef_browser_t* browser) {
|
||||
simple_life_span_handler_t* handler = (simple_life_span_handler_t*)self;
|
||||
|
||||
// Add to the list of existing browsers.
|
||||
// browser_list_add adds its own reference, so we can release the parameter.
|
||||
browser_list_add(&handler->parent->browser_list, browser);
|
||||
|
||||
// Release the browser callback parameter.
|
||||
// The list has its own reference now.
|
||||
browser->base.release(&browser->base);
|
||||
}
|
||||
|
||||
int CEF_CALLBACK life_span_handler_do_close(cef_life_span_handler_t* self,
|
||||
cef_browser_t* browser) {
|
||||
simple_life_span_handler_t* handler = (simple_life_span_handler_t*)self;
|
||||
|
||||
// Closing the main window requires special handling.
|
||||
if (browser_list_count(&handler->parent->browser_list) == 1) {
|
||||
// Set a flag to indicate that the window close should be allowed.
|
||||
handler->parent->is_closing = 1;
|
||||
}
|
||||
|
||||
// Release the browser callback parameter before returning.
|
||||
browser->base.release(&browser->base);
|
||||
|
||||
// Allow the close. Return false to proceed with closing.
|
||||
return 0;
|
||||
}
|
||||
|
||||
void CEF_CALLBACK
|
||||
life_span_handler_on_before_close(cef_life_span_handler_t* self,
|
||||
cef_browser_t* browser) {
|
||||
simple_life_span_handler_t* handler = (simple_life_span_handler_t*)self;
|
||||
|
||||
// Remove from the list of existing browsers.
|
||||
// This releases the list's reference to the browser.
|
||||
browser_list_remove(&handler->parent->browser_list, browser);
|
||||
|
||||
if (browser_list_count(&handler->parent->browser_list) == 0) {
|
||||
// All browser windows have closed. Quit the application message loop.
|
||||
cef_quit_message_loop();
|
||||
}
|
||||
|
||||
// Release the browser callback parameter before returning.
|
||||
browser->base.release(&browser->base);
|
||||
}
|
||||
|
||||
simple_life_span_handler_t* life_span_handler_create(simple_handler_t* parent) {
|
||||
simple_life_span_handler_t* handler = (simple_life_span_handler_t*)calloc(
|
||||
1, sizeof(simple_life_span_handler_t));
|
||||
CHECK(handler);
|
||||
|
||||
// Initialize base structure.
|
||||
INIT_CEF_BASE_REFCOUNTED(&handler->handler.base, cef_life_span_handler_t,
|
||||
life_span_handler);
|
||||
|
||||
// Set callbacks.
|
||||
handler->handler.on_after_created = life_span_handler_on_after_created;
|
||||
handler->handler.do_close = life_span_handler_do_close;
|
||||
handler->handler.on_before_close = life_span_handler_on_before_close;
|
||||
|
||||
// Store parent reference (no ref count - parent owns us).
|
||||
handler->parent = parent;
|
||||
|
||||
// Initialize with ref count of 1.
|
||||
atomic_store(&handler->ref_count, 1);
|
||||
|
||||
return handler;
|
||||
}
|
||||
@@ -0,0 +1,97 @@
|
||||
// Copyright (c) 2025 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 <stdatomic.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "include/capi/cef_parser_capi.h"
|
||||
#include "tests/cefsimple_capi/ref_counted.h"
|
||||
#include "tests/cefsimple_capi/simple_handler.h"
|
||||
#include "tests/cefsimple_capi/simple_utils.h"
|
||||
|
||||
//
|
||||
// Load handler implementation.
|
||||
//
|
||||
|
||||
IMPLEMENT_REFCOUNTING_SIMPLE(simple_load_handler_t, load_handler, ref_count)
|
||||
|
||||
void CEF_CALLBACK load_handler_on_load_error(cef_load_handler_t* self,
|
||||
cef_browser_t* browser,
|
||||
cef_frame_t* frame,
|
||||
cef_errorcode_t errorCode,
|
||||
const cef_string_t* errorText,
|
||||
const cef_string_t* failedUrl) {
|
||||
simple_load_handler_t* handler = (simple_load_handler_t*)self;
|
||||
|
||||
// Only display error page in alloy style and not for aborted downloads.
|
||||
// Allow Chrome to show the error page in other cases.
|
||||
if (handler->parent->is_alloy_style && errorCode != ERR_ABORTED) {
|
||||
// Display a load error message using a data: URI.
|
||||
char error_html[1024];
|
||||
snprintf(error_html, sizeof(error_html),
|
||||
"<html><body bgcolor=\"white\">"
|
||||
"<h2>Failed to load URL with error %d.</h2></body></html>",
|
||||
errorCode);
|
||||
|
||||
// Convert to cef_string_t.
|
||||
cef_string_t error_str = {};
|
||||
cef_string_from_ascii(error_html, strlen(error_html), &error_str);
|
||||
|
||||
// Create data URI.
|
||||
cef_string_t mime_type = {};
|
||||
cef_string_from_ascii("text/html", 9, &mime_type);
|
||||
|
||||
// Base64 encode the error HTML.
|
||||
cef_string_userfree_t encoded =
|
||||
cef_base64_encode(error_str.str, error_str.length);
|
||||
|
||||
if (encoded) {
|
||||
// Create the data URI.
|
||||
char data_uri[2048];
|
||||
cef_string_utf8_t encoded_utf8 = {};
|
||||
cef_string_to_utf8(encoded->str, encoded->length, &encoded_utf8);
|
||||
snprintf(data_uri, sizeof(data_uri), "data:text/html;base64,%s",
|
||||
encoded_utf8.str);
|
||||
cef_string_utf8_clear(&encoded_utf8);
|
||||
|
||||
// Load the data URI.
|
||||
cef_string_t data_uri_str = {};
|
||||
cef_string_from_ascii(data_uri, strlen(data_uri), &data_uri_str);
|
||||
frame->load_url(frame, &data_uri_str);
|
||||
cef_string_clear(&data_uri_str);
|
||||
|
||||
cef_string_userfree_free(encoded);
|
||||
}
|
||||
|
||||
cef_string_clear(&error_str);
|
||||
cef_string_clear(&mime_type);
|
||||
}
|
||||
|
||||
// Release all object parameters.
|
||||
browser->base.release(&browser->base);
|
||||
frame->base.release(&frame->base);
|
||||
}
|
||||
|
||||
simple_load_handler_t* load_handler_create(simple_handler_t* parent) {
|
||||
simple_load_handler_t* handler =
|
||||
(simple_load_handler_t*)calloc(1, sizeof(simple_load_handler_t));
|
||||
CHECK(handler);
|
||||
|
||||
// Initialize base structure.
|
||||
INIT_CEF_BASE_REFCOUNTED(&handler->handler.base, cef_load_handler_t,
|
||||
load_handler);
|
||||
|
||||
// Set callbacks.
|
||||
handler->handler.on_load_error = load_handler_on_load_error;
|
||||
|
||||
// Store parent reference (no ref count - parent owns us).
|
||||
handler->parent = parent;
|
||||
|
||||
// Initialize with ref count of 1.
|
||||
atomic_store(&handler->ref_count, 1);
|
||||
|
||||
return handler;
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
// Copyright (c) 2025 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_TESTS_CEFSIMPLE_CAPI_SIMPLE_UTILS_H_
|
||||
#define CEF_TESTS_CEFSIMPLE_CAPI_SIMPLE_UTILS_H_
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
//
|
||||
// Assertion Helpers
|
||||
//
|
||||
// For invariants that should never fail, crash immediately with a clear
|
||||
// message.
|
||||
//
|
||||
|
||||
// Check that a condition is true. If false, crash with error message.
|
||||
// Example: CHECK(handler != NULL);
|
||||
#define CHECK(cond) \
|
||||
do { \
|
||||
if (!(cond)) { \
|
||||
fprintf(stderr, "[cefsimple_capi FATAL] %s:%d: CHECK failed: %s\n", \
|
||||
__FILE__, __LINE__, #cond); \
|
||||
abort(); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#endif // CEF_TESTS_CEFSIMPLE_CAPI_SIMPLE_UTILS_H_
|
||||
@@ -0,0 +1,330 @@
|
||||
// Copyright (c) 2025 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/cefsimple_capi/simple_views.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "tests/cefsimple_capi/ref_counted.h"
|
||||
#include "tests/cefsimple_capi/simple_utils.h"
|
||||
|
||||
//
|
||||
// Browser View Delegate Implementation
|
||||
//
|
||||
|
||||
// Implement reference counting functions for browser view delegate.
|
||||
IMPLEMENT_REFCOUNTING_SIMPLE(simple_browser_view_delegate_t,
|
||||
browser_view_delegate,
|
||||
ref_count)
|
||||
|
||||
// Returns the delegate for a popup BrowserView.
|
||||
// Called before on_popup_browser_view_created.
|
||||
cef_browser_view_delegate_t* CEF_CALLBACK
|
||||
browser_view_delegate_get_delegate_for_popup_browser_view(
|
||||
cef_browser_view_delegate_t* self,
|
||||
cef_browser_view_t* browser_view,
|
||||
const cef_browser_settings_t* settings,
|
||||
cef_client_t* client,
|
||||
int is_devtools) {
|
||||
simple_browser_view_delegate_t* delegate =
|
||||
(simple_browser_view_delegate_t*)self;
|
||||
|
||||
// Release parameters before returning.
|
||||
browser_view->base.base.release(&browser_view->base.base);
|
||||
// settings is a const pointer, not ref-counted
|
||||
client->base.release(&client->base);
|
||||
|
||||
// Return this same delegate for the popup (matches C++ default).
|
||||
// Add a reference since we're returning to CEF.
|
||||
delegate->delegate.base.base.add_ref(&delegate->delegate.base.base);
|
||||
return &delegate->delegate;
|
||||
}
|
||||
|
||||
// Called when a popup BrowserView is created.
|
||||
// Return true if we handle creating the window for the popup.
|
||||
int CEF_CALLBACK browser_view_delegate_on_popup_browser_view_created(
|
||||
cef_browser_view_delegate_t* self,
|
||||
cef_browser_view_t* browser_view,
|
||||
cef_browser_view_t* popup_browser_view,
|
||||
int is_devtools) {
|
||||
simple_browser_view_delegate_t* delegate =
|
||||
(simple_browser_view_delegate_t*)self;
|
||||
|
||||
// Create a new top-level Window for the popup.
|
||||
// We transfer our reference to the window delegate.
|
||||
simple_window_delegate_t* window_delegate = window_delegate_create(
|
||||
popup_browser_view, delegate->runtime_style, CEF_SHOW_STATE_NORMAL);
|
||||
|
||||
if (window_delegate) {
|
||||
// Create the window. The window will show itself after creation.
|
||||
// We transfer our window_delegate reference to CEF.
|
||||
cef_window_create_top_level(&window_delegate->delegate);
|
||||
}
|
||||
|
||||
// Release parameters before returning.
|
||||
browser_view->base.base.release(&browser_view->base.base);
|
||||
// Don't release popup_browser_view - we transferred it to window_delegate.
|
||||
|
||||
// We created the Window.
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Returns the runtime style for the browser.
|
||||
cef_runtime_style_t CEF_CALLBACK
|
||||
browser_view_delegate_get_browser_runtime_style(
|
||||
cef_browser_view_delegate_t* self) {
|
||||
simple_browser_view_delegate_t* delegate =
|
||||
(simple_browser_view_delegate_t*)self;
|
||||
return delegate->runtime_style;
|
||||
}
|
||||
|
||||
// Creates a browser view delegate instance.
|
||||
simple_browser_view_delegate_t* browser_view_delegate_create(
|
||||
cef_runtime_style_t runtime_style) {
|
||||
simple_browser_view_delegate_t* delegate =
|
||||
(simple_browser_view_delegate_t*)calloc(
|
||||
1, sizeof(simple_browser_view_delegate_t));
|
||||
CHECK(delegate);
|
||||
|
||||
// Initialize base structure.
|
||||
INIT_CEF_BASE_REFCOUNTED(&delegate->delegate.base.base,
|
||||
cef_browser_view_delegate_t, browser_view_delegate);
|
||||
|
||||
// Set callbacks.
|
||||
delegate->delegate.get_delegate_for_popup_browser_view =
|
||||
browser_view_delegate_get_delegate_for_popup_browser_view;
|
||||
delegate->delegate.on_popup_browser_view_created =
|
||||
browser_view_delegate_on_popup_browser_view_created;
|
||||
delegate->delegate.get_browser_runtime_style =
|
||||
browser_view_delegate_get_browser_runtime_style;
|
||||
|
||||
// Store runtime style.
|
||||
delegate->runtime_style = runtime_style;
|
||||
|
||||
// Initialize with ref count of 1.
|
||||
atomic_store(&delegate->ref_count, 1);
|
||||
|
||||
return delegate;
|
||||
}
|
||||
|
||||
//
|
||||
// Window Delegate Implementation
|
||||
//
|
||||
|
||||
// Implement reference counting functions for window delegate.
|
||||
IMPLEMENT_REFCOUNTING_MANUAL(simple_window_delegate_t,
|
||||
window_delegate,
|
||||
ref_count)
|
||||
|
||||
// Release function for window delegate with custom cleanup.
|
||||
int CEF_CALLBACK window_delegate_release(cef_base_ref_counted_t* self) {
|
||||
simple_window_delegate_t* delegate = (simple_window_delegate_t*)self;
|
||||
int count = atomic_fetch_sub(&delegate->ref_count, 1) - 1;
|
||||
if (count == 0) {
|
||||
// Release the browser view reference if we still have it.
|
||||
if (delegate->browser_view) {
|
||||
delegate->browser_view->base.base.release(
|
||||
&delegate->browser_view->base.base);
|
||||
}
|
||||
free(delegate);
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Called when the window is created.
|
||||
void CEF_CALLBACK window_delegate_on_window_created(cef_window_delegate_t* self,
|
||||
cef_window_t* window) {
|
||||
simple_window_delegate_t* delegate = (simple_window_delegate_t*)self;
|
||||
|
||||
// Add a reference for ourselves since add_child_view transfers ownership.
|
||||
// This gives us an independent reference to use in can_close.
|
||||
delegate->browser_view->base.base.add_ref(&delegate->browser_view->base.base);
|
||||
|
||||
// Add the browser view to the window (transfers the original reference).
|
||||
window->base.add_child_view(&window->base, &delegate->browser_view->base);
|
||||
|
||||
// Show the window if not hidden.
|
||||
if (delegate->initial_show_state != CEF_SHOW_STATE_HIDDEN) {
|
||||
window->show(window);
|
||||
}
|
||||
|
||||
// Release the window parameter before returning.
|
||||
window->base.base.base.release(&window->base.base.base);
|
||||
}
|
||||
|
||||
// Called when the window is destroyed.
|
||||
void CEF_CALLBACK
|
||||
window_delegate_on_window_destroyed(cef_window_delegate_t* self,
|
||||
cef_window_t* window) {
|
||||
simple_window_delegate_t* delegate = (simple_window_delegate_t*)self;
|
||||
|
||||
// Release our browser_view reference (added in on_window_created).
|
||||
// We won't need browser_view anymore since the window is being destroyed.
|
||||
// Note: Releasing the browser_view may also release the contained browser,
|
||||
// so on_before_close will be called before this callback returns.
|
||||
if (delegate->browser_view) {
|
||||
delegate->browser_view->base.base.release(
|
||||
&delegate->browser_view->base.base);
|
||||
delegate->browser_view = NULL;
|
||||
}
|
||||
|
||||
// Release the window parameter before returning.
|
||||
window->base.base.base.release(&window->base.base.base);
|
||||
}
|
||||
|
||||
// Called to check if the window can be resized.
|
||||
// C++ defaults this to true in the header. We don't get those defaults with
|
||||
// the C API.
|
||||
int CEF_CALLBACK window_delegate_can_resize(cef_window_delegate_t* self,
|
||||
cef_window_t* window) {
|
||||
// Release the window parameter before returning.
|
||||
window->base.base.base.release(&window->base.base.base);
|
||||
|
||||
// Default: allow resize.
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Called to check if the window can be maximized.
|
||||
// C++ defaults this to true in the header. We don't get those defaults with
|
||||
// the C API.
|
||||
int CEF_CALLBACK window_delegate_can_maximize(cef_window_delegate_t* self,
|
||||
cef_window_t* window) {
|
||||
// Release the window parameter before returning.
|
||||
window->base.base.base.release(&window->base.base.base);
|
||||
|
||||
// Default: allow maximize.
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Called to check if the window can be minimized.
|
||||
// C++ defaults this to true in the header. We don't get those defaults with
|
||||
// the C API.
|
||||
int CEF_CALLBACK window_delegate_can_minimize(cef_window_delegate_t* self,
|
||||
cef_window_t* window) {
|
||||
// Release the window parameter before returning.
|
||||
window->base.base.base.release(&window->base.base.base);
|
||||
|
||||
// Default: allow minimize.
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Called to check if the window can close.
|
||||
int CEF_CALLBACK window_delegate_can_close(cef_window_delegate_t* self,
|
||||
cef_window_t* window) {
|
||||
simple_window_delegate_t* delegate = (simple_window_delegate_t*)self;
|
||||
|
||||
int can_close = 1; // Default to allowing close.
|
||||
|
||||
// Ask the browser if it's OK to close.
|
||||
if (delegate->browser_view) {
|
||||
cef_browser_t* browser =
|
||||
delegate->browser_view->get_browser(delegate->browser_view);
|
||||
if (browser) {
|
||||
cef_browser_host_t* host = browser->get_host(browser);
|
||||
if (host) {
|
||||
can_close = host->try_close_browser(host);
|
||||
// Release host (get_host returns a new reference).
|
||||
host->base.release(&host->base);
|
||||
}
|
||||
// Release browser (get_browser returns a new reference).
|
||||
browser->base.release(&browser->base);
|
||||
}
|
||||
}
|
||||
|
||||
// Release the window parameter before returning.
|
||||
window->base.base.base.release(&window->base.base.base);
|
||||
|
||||
return can_close;
|
||||
}
|
||||
|
||||
// Called to check if the window should have standard window buttons (macOS).
|
||||
// C++ defaults this to true in the header. We don't get those defaults with
|
||||
// the C API.
|
||||
int CEF_CALLBACK
|
||||
window_delegate_with_standard_window_buttons(cef_window_delegate_t* self,
|
||||
cef_window_t* window) {
|
||||
// Release the window parameter before returning.
|
||||
window->base.base.base.release(&window->base.base.base);
|
||||
|
||||
// Default: show standard window buttons.
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Returns the preferred size for the view.
|
||||
cef_size_t CEF_CALLBACK
|
||||
window_delegate_get_preferred_size(cef_view_delegate_t* self,
|
||||
cef_view_t* view) {
|
||||
cef_size_t size = {800, 600};
|
||||
|
||||
// Release the view parameter before returning.
|
||||
view->base.release(&view->base);
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
// Returns the initial show state for the window.
|
||||
cef_show_state_t CEF_CALLBACK
|
||||
window_delegate_get_initial_show_state(cef_window_delegate_t* self,
|
||||
cef_window_t* window) {
|
||||
simple_window_delegate_t* delegate = (simple_window_delegate_t*)self;
|
||||
|
||||
cef_show_state_t show_state = delegate->initial_show_state;
|
||||
|
||||
// Release the window parameter before returning.
|
||||
window->base.base.base.release(&window->base.base.base);
|
||||
|
||||
return show_state;
|
||||
}
|
||||
|
||||
// Returns the runtime style for the window.
|
||||
cef_runtime_style_t CEF_CALLBACK
|
||||
window_delegate_get_window_runtime_style(cef_window_delegate_t* self) {
|
||||
simple_window_delegate_t* delegate = (simple_window_delegate_t*)self;
|
||||
return delegate->runtime_style;
|
||||
}
|
||||
|
||||
// Creates a window delegate instance.
|
||||
simple_window_delegate_t* window_delegate_create(
|
||||
cef_browser_view_t* browser_view,
|
||||
cef_runtime_style_t runtime_style,
|
||||
cef_show_state_t initial_show_state) {
|
||||
simple_window_delegate_t* delegate =
|
||||
(simple_window_delegate_t*)calloc(1, sizeof(simple_window_delegate_t));
|
||||
CHECK(delegate);
|
||||
|
||||
// Initialize base structure.
|
||||
INIT_CEF_BASE_REFCOUNTED(&delegate->delegate.base.base.base,
|
||||
cef_window_delegate_t, window_delegate);
|
||||
|
||||
// Set callbacks for cef_window_delegate_t.
|
||||
delegate->delegate.on_window_created = window_delegate_on_window_created;
|
||||
delegate->delegate.on_window_destroyed = window_delegate_on_window_destroyed;
|
||||
delegate->delegate.can_resize = window_delegate_can_resize;
|
||||
delegate->delegate.can_maximize = window_delegate_can_maximize;
|
||||
delegate->delegate.can_minimize = window_delegate_can_minimize;
|
||||
delegate->delegate.can_close = window_delegate_can_close;
|
||||
delegate->delegate.with_standard_window_buttons =
|
||||
window_delegate_with_standard_window_buttons;
|
||||
delegate->delegate.get_initial_show_state =
|
||||
window_delegate_get_initial_show_state;
|
||||
delegate->delegate.get_window_runtime_style =
|
||||
window_delegate_get_window_runtime_style;
|
||||
|
||||
// Set callbacks for cef_view_delegate_t (parent structure).
|
||||
delegate->delegate.base.base.get_preferred_size =
|
||||
window_delegate_get_preferred_size;
|
||||
|
||||
// Store the browser view reference (we take ownership).
|
||||
delegate->browser_view = browser_view;
|
||||
|
||||
// Store runtime style and initial show state.
|
||||
delegate->runtime_style = runtime_style;
|
||||
delegate->initial_show_state = initial_show_state;
|
||||
|
||||
// Initialize with ref count of 1.
|
||||
atomic_store(&delegate->ref_count, 1);
|
||||
|
||||
return delegate;
|
||||
}
|
||||
@@ -0,0 +1,68 @@
|
||||
// Copyright (c) 2025 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_TESTS_CEFSIMPLE_CAPI_SIMPLE_VIEWS_H_
|
||||
#define CEF_TESTS_CEFSIMPLE_CAPI_SIMPLE_VIEWS_H_
|
||||
|
||||
#include <stdatomic.h>
|
||||
|
||||
#include "include/capi/views/cef_browser_view_capi.h"
|
||||
#include "include/capi/views/cef_window_capi.h"
|
||||
|
||||
// Forward declaration.
|
||||
typedef struct _simple_window_delegate_t simple_window_delegate_t;
|
||||
|
||||
//
|
||||
// Browser view delegate structure.
|
||||
// Implements cef_browser_view_delegate_t callbacks.
|
||||
//
|
||||
typedef struct _simple_browser_view_delegate_t {
|
||||
cef_browser_view_delegate_t delegate;
|
||||
|
||||
// Reference count for this object.
|
||||
atomic_int ref_count;
|
||||
|
||||
// Runtime style for the browser.
|
||||
cef_runtime_style_t runtime_style;
|
||||
} simple_browser_view_delegate_t;
|
||||
|
||||
//
|
||||
// Window delegate structure.
|
||||
// Implements cef_window_delegate_t callbacks.
|
||||
//
|
||||
typedef struct _simple_window_delegate_t {
|
||||
cef_window_delegate_t delegate;
|
||||
|
||||
// Reference count for this object.
|
||||
atomic_int ref_count;
|
||||
|
||||
// Browser view to add to the window (owned by this structure).
|
||||
// We keep CEF's reference from the creation call.
|
||||
cef_browser_view_t* browser_view;
|
||||
|
||||
// Runtime style for the window.
|
||||
cef_runtime_style_t runtime_style;
|
||||
|
||||
// Initial show state for the window.
|
||||
cef_show_state_t initial_show_state;
|
||||
} simple_window_delegate_t;
|
||||
|
||||
//
|
||||
// Creates a browser view delegate.
|
||||
// Caller is responsible for releasing the reference when done.
|
||||
//
|
||||
simple_browser_view_delegate_t* browser_view_delegate_create(
|
||||
cef_runtime_style_t runtime_style);
|
||||
|
||||
//
|
||||
// Creates a window delegate.
|
||||
// Takes ownership of the browser_view reference.
|
||||
// Caller is responsible for releasing the reference when done.
|
||||
//
|
||||
simple_window_delegate_t* window_delegate_create(
|
||||
cef_browser_view_t* browser_view,
|
||||
cef_runtime_style_t runtime_style,
|
||||
cef_show_state_t initial_show_state);
|
||||
|
||||
#endif // CEF_TESTS_CEFSIMPLE_CAPI_SIMPLE_VIEWS_H_
|
||||
@@ -0,0 +1,20 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
||||
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
|
||||
|
||||
<!--The compatibility section will be merged from build/win/compatibility.manifest -->
|
||||
|
||||
<dependency>
|
||||
<dependentAssembly>
|
||||
<assemblyIdentity type="Win32" name="Microsoft.Windows.Common-Controls" version="6.0.0.0" processorArchitecture="*" publicKeyToken="6595b64144ccf1df" language="*"></assemblyIdentity>
|
||||
</dependentAssembly>
|
||||
</dependency>
|
||||
|
||||
<trustInfo xmlns="urn:schemas-microsoft-com:asm.v3">
|
||||
<security>
|
||||
<requestedPrivileges>
|
||||
<requestedExecutionLevel level="asInvoker" />
|
||||
</requestedPrivileges>
|
||||
</security>
|
||||
</trustInfo>
|
||||
|
||||
</assembly>
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 23 KiB |
@@ -0,0 +1,79 @@
|
||||
// Microsoft Visual C++ generated resource script.
|
||||
//
|
||||
#include "tests/cefsimple/resource.h"
|
||||
|
||||
#define APSTUDIO_READONLY_SYMBOLS
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Generated from the TEXTINCLUDE 2 resource.
|
||||
//
|
||||
#define APSTUDIO_HIDDEN_SYMBOLS
|
||||
#include "windows.h"
|
||||
#undef APSTUDIO_HIDDEN_SYMBOLS
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
#undef APSTUDIO_READONLY_SYMBOLS
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
// English (U.S.) resources
|
||||
|
||||
#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)
|
||||
#ifdef _WIN32
|
||||
LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
|
||||
#pragma code_page(1252)
|
||||
#endif //_WIN32
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Icon
|
||||
//
|
||||
|
||||
// Icon with lowest ID value placed first to ensure application icon
|
||||
// remains consistent on all systems.
|
||||
IDI_CEFSIMPLE ICON "cefsimple.ico"
|
||||
IDI_SMALL ICON "small.ico"
|
||||
|
||||
|
||||
#ifdef APSTUDIO_INVOKED
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// TEXTINCLUDE
|
||||
//
|
||||
|
||||
1 TEXTINCLUDE
|
||||
BEGIN
|
||||
"resource.h\0"
|
||||
END
|
||||
|
||||
2 TEXTINCLUDE
|
||||
BEGIN
|
||||
"#define APSTUDIO_HIDDEN_SYMBOLS\r\n"
|
||||
"#include ""windows.h""\r\n"
|
||||
"#undef APSTUDIO_HIDDEN_SYMBOLS\r\n"
|
||||
"\0"
|
||||
END
|
||||
|
||||
3 TEXTINCLUDE
|
||||
BEGIN
|
||||
"\r\n"
|
||||
"\0"
|
||||
END
|
||||
|
||||
#endif // APSTUDIO_INVOKED
|
||||
|
||||
|
||||
#endif // English (U.S.) resources
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
|
||||
#ifndef APSTUDIO_INVOKED
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Generated from the TEXTINCLUDE 3 resource.
|
||||
//
|
||||
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
#endif // not APSTUDIO_INVOKED
|
||||
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 23 KiB |
@@ -13,17 +13,11 @@ build --enable_platform_specific_config
|
||||
#
|
||||
|
||||
# Build with C++17.
|
||||
# See also the enable_cxx17 argument to declare_objc_library()
|
||||
build:linux --cxxopt='-std=c++17'
|
||||
build:macos --cxxopt='-std=c++17'
|
||||
build:macos --copt='-std=c++17'
|
||||
build:windows --cxxopt='/std:c++17'
|
||||
|
||||
#
|
||||
# MacOS configuration.
|
||||
#
|
||||
|
||||
build:macos --copt='-ObjC++'
|
||||
|
||||
#
|
||||
# Windows configuration.
|
||||
#
|
||||
|
||||
@@ -0,0 +1,142 @@
|
||||
# Copyright (c) 2025 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.
|
||||
|
||||
PRODUCT_NAME = "cefsimple_capi"
|
||||
PKG_NAME = "//tests/{}".format(PRODUCT_NAME)
|
||||
|
||||
# Allow access from subpackages only.
|
||||
package(default_visibility = [
|
||||
":__subpackages__",
|
||||
])
|
||||
|
||||
load("//bazel:library_helpers.bzl", "declare_cc_library", "declare_objc_library")
|
||||
load("@rules_cc//cc:defs.bzl", "cc_library")
|
||||
|
||||
#
|
||||
# Source file lists.
|
||||
#
|
||||
|
||||
srcs_browser = [
|
||||
${cefsimple_capi_sources_common}
|
||||
]
|
||||
|
||||
srcs_browser_linux = [
|
||||
${cefsimple_capi_sources_linux}
|
||||
]
|
||||
|
||||
srcs_browser_mac = [
|
||||
${cefsimple_capi_sources_mac}
|
||||
]
|
||||
|
||||
srcs_browser_win = [
|
||||
${cefsimple_capi_sources_win}
|
||||
]
|
||||
|
||||
srcs_renderer_mac = [
|
||||
${cefsimple_capi_sources_mac_helper}
|
||||
]
|
||||
|
||||
#
|
||||
# MacOS targets.
|
||||
#
|
||||
|
||||
# Pure C sources
|
||||
declare_cc_library(
|
||||
name = "BrowserLibMac_C",
|
||||
srcs = srcs_browser, # Pure .c files
|
||||
target_compatible_with = [
|
||||
"@platforms//os:macos",
|
||||
],
|
||||
copts = [
|
||||
"-std=c11", # Use C11 standard
|
||||
],
|
||||
deps = [
|
||||
"//:cef_wrapper",
|
||||
],
|
||||
)
|
||||
|
||||
# Objective-C sources
|
||||
declare_objc_library(
|
||||
name = "BrowserLibMac_ObjC",
|
||||
srcs = srcs_browser_mac, # .m files
|
||||
enable_cxx17 = False, # Pure Objective-C, not Objective-C++
|
||||
target_compatible_with = [
|
||||
"@platforms//os:macos",
|
||||
],
|
||||
deps = [
|
||||
"//:cef_wrapper",
|
||||
":BrowserLibMac_C",
|
||||
],
|
||||
)
|
||||
|
||||
# Combined library
|
||||
alias(
|
||||
name = "BrowserLibMac",
|
||||
actual = ":BrowserLibMac_ObjC",
|
||||
)
|
||||
|
||||
# Pure C helper process sources
|
||||
declare_cc_library(
|
||||
name = "RendererLibMac",
|
||||
srcs = srcs_renderer_mac,
|
||||
target_compatible_with = [
|
||||
"@platforms//os:macos",
|
||||
],
|
||||
copts = [
|
||||
"-std=c11", # Use C11 standard
|
||||
],
|
||||
deps = [
|
||||
"//:cef_wrapper",
|
||||
],
|
||||
)
|
||||
|
||||
#
|
||||
# Windows targets.
|
||||
#
|
||||
|
||||
# Allow access to resource.h from the declare_exe target.
|
||||
cc_library(
|
||||
name = "ResourceH",
|
||||
hdrs = [
|
||||
"resource.h"
|
||||
]
|
||||
)
|
||||
|
||||
# Include files directly in the declare_exe target. This simplifies the build
|
||||
# configuration and avoids issues with Windows discarding symbols (like WinMain)
|
||||
# when linking libraries.
|
||||
filegroup(
|
||||
name = "SrcsWin",
|
||||
srcs = srcs_browser + srcs_browser_win,
|
||||
target_compatible_with = [
|
||||
"@platforms//os:windows",
|
||||
],
|
||||
)
|
||||
|
||||
#
|
||||
# Linux targets.
|
||||
#
|
||||
|
||||
# Include files directly in the declare_exe target. This simplifies the build
|
||||
# configuration.
|
||||
filegroup(
|
||||
name = "SrcsLinux",
|
||||
srcs = srcs_browser + srcs_browser_linux,
|
||||
target_compatible_with = [
|
||||
"@platforms//os:linux",
|
||||
],
|
||||
)
|
||||
|
||||
#
|
||||
# Alias to platform-specific build targets.
|
||||
#
|
||||
|
||||
alias(
|
||||
name = PRODUCT_NAME,
|
||||
actual = select({
|
||||
"@platforms//os:linux": "{}/linux:{}".format(PKG_NAME, PRODUCT_NAME),
|
||||
"@platforms//os:macos": "{}/mac:{}".format(PKG_NAME, PRODUCT_NAME),
|
||||
"@platforms//os:windows": "{}/win:{}".format(PKG_NAME, PRODUCT_NAME),
|
||||
}),
|
||||
)
|
||||
@@ -0,0 +1,27 @@
|
||||
# Copyright (c) 2025 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.
|
||||
|
||||
PRODUCT_NAME = "cefsimple_capi"
|
||||
PKG_NAME = "//tests/{}".format(PRODUCT_NAME)
|
||||
|
||||
# Allow access from the parent package only.
|
||||
package(default_visibility = [
|
||||
"{}:__pkg__".format(PKG_NAME),
|
||||
])
|
||||
|
||||
load("//bazel/linux:exe_helpers.bzl", "declare_exe")
|
||||
|
||||
#
|
||||
# Linux executable target.
|
||||
#
|
||||
|
||||
declare_exe(
|
||||
name = PRODUCT_NAME,
|
||||
srcs = [
|
||||
"{}:SrcsLinux".format(PKG_NAME),
|
||||
],
|
||||
copts = [
|
||||
"-std=c11", # cefsimple_capi requires C11 for stdatomic.h
|
||||
],
|
||||
)
|
||||
@@ -0,0 +1,48 @@
|
||||
# Copyright (c) 2025 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.
|
||||
|
||||
PRODUCT_NAME = "cefsimple_capi"
|
||||
PKG_NAME = "//tests/{}".format(PRODUCT_NAME)
|
||||
|
||||
# Allow access from the parent package only.
|
||||
package(default_visibility = [
|
||||
"{}:__pkg__".format(PKG_NAME),
|
||||
])
|
||||
|
||||
load("//bazel/mac:app_helpers.bzl", "declare_all_helper_apps", "declare_main_app")
|
||||
|
||||
#
|
||||
# MacOS app bundle target.
|
||||
#
|
||||
|
||||
filegroup(
|
||||
name = "ResourcesMac",
|
||||
srcs = [
|
||||
"English.lproj/InfoPlist.strings",
|
||||
"English.lproj/MainMenu.xib",
|
||||
"cefsimple_capi.icns",
|
||||
],
|
||||
)
|
||||
|
||||
# Helper app bundles.
|
||||
declare_all_helper_apps(
|
||||
name = PRODUCT_NAME,
|
||||
info_plist = "helper-Info.plist.in",
|
||||
deps = [
|
||||
"{}:RendererLibMac".format(PKG_NAME),
|
||||
],
|
||||
)
|
||||
|
||||
# Main app bundle.
|
||||
declare_main_app(
|
||||
name = PRODUCT_NAME,
|
||||
info_plist = "Info.plist.in",
|
||||
deps = [
|
||||
"{}:BrowserLibMac".format(PKG_NAME),
|
||||
],
|
||||
linkopts = [],
|
||||
resources = [
|
||||
":ResourcesMac",
|
||||
]
|
||||
)
|
||||
@@ -0,0 +1,68 @@
|
||||
# Copyright (c) 2025 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.
|
||||
|
||||
PRODUCT_NAME = "cefsimple_capi"
|
||||
PKG_NAME = "//tests/{}".format(PRODUCT_NAME)
|
||||
|
||||
# Allow access from the parent package only.
|
||||
package(default_visibility = [
|
||||
"{}:__pkg__".format(PKG_NAME),
|
||||
])
|
||||
|
||||
#
|
||||
# Windows DLL target (sandbox enabled).
|
||||
#
|
||||
|
||||
load("//bazel/win:exe_helpers.bzl", "declare_dll")
|
||||
|
||||
declare_dll(
|
||||
name = PRODUCT_NAME,
|
||||
srcs = [
|
||||
"{}:SrcsWin".format(PKG_NAME),
|
||||
],
|
||||
rc_file = "cefsimple.rc",
|
||||
resources_srcs = [
|
||||
"cefsimple.ico",
|
||||
"small.ico",
|
||||
],
|
||||
resources_deps = [
|
||||
"{}:ResourceH".format(PKG_NAME),
|
||||
],
|
||||
copts = [
|
||||
"/std:c11", # cefsimple_capi requires C11 for stdatomic.h
|
||||
"/experimental:c11atomics", # Enable C11 atomics support in MSVC
|
||||
],
|
||||
local_defines = [
|
||||
# Enable use of the bootstrap executable.
|
||||
"CEF_USE_BOOTSTRAP",
|
||||
],
|
||||
)
|
||||
|
||||
#
|
||||
# Windows executable target (sandbox disabled).
|
||||
#
|
||||
|
||||
# load("//bazel/win:exe_helpers.bzl", "declare_exe")
|
||||
#
|
||||
# declare_exe(
|
||||
# name = PRODUCT_NAME,
|
||||
# srcs = [
|
||||
# "{}:SrcsWin".format(PKG_NAME),
|
||||
# ],
|
||||
# rc_file = "cefsimple.rc",
|
||||
# manifest_srcs = [
|
||||
# "compatibility.manifest",
|
||||
# "cefsimple.exe.manifest",
|
||||
# ],
|
||||
# resources_srcs = [
|
||||
# "cefsimple.ico",
|
||||
# "small.ico",
|
||||
# ],
|
||||
# resources_deps = [
|
||||
# "{}:ResourceH".format(PKG_NAME),
|
||||
# ],
|
||||
# linkopts = [
|
||||
# "/SUBSYSTEM:WINDOWS",
|
||||
# ],
|
||||
# )
|
||||
+1
-1
@@ -12,7 +12,7 @@ from git_util import get_changed_files
|
||||
from yapf_util import yapf_format
|
||||
|
||||
# File extensions that can be formatted.
|
||||
DEFAULT_LINT_WHITELIST_REGEX = r"(.*\.cpp|.*\.cc|.*\.h|.*\.java|.*\.mm|.*\.py)$"
|
||||
DEFAULT_LINT_WHITELIST_REGEX = r"(.*\.cpp|.*\.cc|.*\.c|.*\.h|.*\.java|.*\.mm|.*\.m|.*\.py)$"
|
||||
DEFAULT_LINT_BLACKLIST_REGEX = r"$^"
|
||||
|
||||
# Directories containing these path components will be ignored.
|
||||
|
||||
@@ -966,6 +966,10 @@ if mode == 'standard':
|
||||
cefsimple_dir = os.path.join(tests_dir, 'cefsimple')
|
||||
make_dir(cefsimple_dir, options.quiet)
|
||||
|
||||
# create the tests/cefsimple_capi directory
|
||||
cefsimple_capi_dir = os.path.join(tests_dir, 'cefsimple_capi')
|
||||
make_dir(cefsimple_capi_dir, options.quiet)
|
||||
|
||||
# create the tests/ceftests directory
|
||||
ceftests_dir = os.path.join(tests_dir, 'ceftests')
|
||||
make_dir(ceftests_dir, options.quiet)
|
||||
@@ -995,6 +999,10 @@ if mode == 'standard':
|
||||
transfer_gypi_files(cef_dir, cef_paths2['cefsimple_sources_common'], \
|
||||
'tests/cefsimple/', cefsimple_dir, options.quiet)
|
||||
|
||||
# transfer common cefsimple_capi files
|
||||
transfer_gypi_files(cef_dir, cef_paths2['cefsimple_capi_sources_common'], \
|
||||
'tests/cefsimple_capi/', cefsimple_capi_dir, options.quiet)
|
||||
|
||||
# transfer common ceftests files
|
||||
transfer_gypi_files(cef_dir, cef_paths2['ceftests_sources_common'], \
|
||||
'tests/ceftests/', ceftests_dir, options.quiet)
|
||||
@@ -1010,6 +1018,9 @@ if mode == 'standard':
|
||||
process_cmake_template(os.path.join(cef_dir, 'tests', 'cefsimple', 'CMakeLists.txt.in'), \
|
||||
os.path.join(cefsimple_dir, 'CMakeLists.txt'), \
|
||||
variables, options.quiet)
|
||||
process_cmake_template(os.path.join(cef_dir, 'tests', 'cefsimple_capi', 'CMakeLists.txt.in'), \
|
||||
os.path.join(cefsimple_capi_dir, 'CMakeLists.txt'), \
|
||||
variables, options.quiet)
|
||||
process_cmake_template(os.path.join(cef_dir, 'tests', 'gtest', 'CMakeLists.txt.in'), \
|
||||
os.path.join(tests_dir, 'gtest', 'CMakeLists.txt'), \
|
||||
variables, options.quiet)
|
||||
@@ -1196,6 +1207,12 @@ elif platform == 'windows':
|
||||
cef_paths2['cefsimple_sources_resources_win_rc'],
|
||||
'tests/cefsimple/', cefsimple_dir, options.quiet)
|
||||
|
||||
# transfer cefsimple_capi files
|
||||
transfer_gypi_files(cef_dir, cef_paths2['cefsimple_capi_sources_win'] +
|
||||
cef_paths2['cefsimple_capi_sources_resources_win'] +
|
||||
cef_paths2['cefsimple_capi_sources_resources_win_rc'],
|
||||
'tests/cefsimple_capi/', cefsimple_capi_dir, options.quiet)
|
||||
|
||||
# transfer ceftests files
|
||||
transfer_gypi_files(cef_dir, cef_paths2['ceftests_sources_win'] +
|
||||
cef_paths2['ceftests_sources_resources_win'] +
|
||||
@@ -1350,6 +1367,17 @@ elif platform == 'mac':
|
||||
os.path.join(cefsimple_dir, 'mac'), \
|
||||
options.quiet)
|
||||
|
||||
# transfer cefsimple_capi files
|
||||
transfer_gypi_files(cef_dir, cef_paths2['cefsimple_capi_sources_mac'], \
|
||||
'tests/cefsimple_capi/', cefsimple_capi_dir, options.quiet)
|
||||
transfer_gypi_files(cef_dir, cef_paths2['cefsimple_capi_sources_mac_helper'], \
|
||||
'tests/cefsimple_capi/', cefsimple_capi_dir, options.quiet)
|
||||
|
||||
# transfer cefsimple_capi/mac files
|
||||
copy_dir(os.path.join(cef_dir, 'tests/cefsimple_capi/mac'), \
|
||||
os.path.join(cefsimple_capi_dir, 'mac'), \
|
||||
options.quiet)
|
||||
|
||||
# transfer ceftests files
|
||||
transfer_gypi_files(cef_dir, cef_paths2['ceftests_sources_mac'], \
|
||||
'tests/ceftests/', ceftests_dir, options.quiet)
|
||||
@@ -1448,6 +1476,10 @@ elif platform == 'linux':
|
||||
transfer_gypi_files(cef_dir, cef_paths2['cefsimple_sources_linux'], \
|
||||
'tests/cefsimple/', cefsimple_dir, options.quiet)
|
||||
|
||||
# transfer cefsimple_capi files
|
||||
transfer_gypi_files(cef_dir, cef_paths2['cefsimple_capi_sources_linux'], \
|
||||
'tests/cefsimple_capi/', cefsimple_capi_dir, options.quiet)
|
||||
|
||||
# transfer ceftests files
|
||||
transfer_gypi_files(cef_dir, cef_paths2['ceftests_sources_linux'], \
|
||||
'tests/ceftests/', ceftests_dir, options.quiet)
|
||||
|
||||
@@ -158,9 +158,14 @@ int cef_load_library(const char* path) {
|
||||
if (g_libcef_handle)
|
||||
return 0;
|
||||
|
||||
if (!path) {
|
||||
fprintf(stderr, "cef_load_library: Invalid path argument");
|
||||
return 0;
|
||||
}
|
||||
|
||||
g_libcef_handle = dlopen(path, RTLD_LAZY | RTLD_LOCAL | RTLD_FIRST);
|
||||
if (!g_libcef_handle) {
|
||||
fprintf(stderr, "dlopen %s: %s\\n", path, dlerror());
|
||||
fprintf(stderr, "cef_load_library: dlopen %s: %s\\n", path, dlerror());
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
Reference in new issue
Block a user