完善浏览器
This commit is contained in:
parent
c41a936bbf
commit
8ff67ba1cd
28
app.manifest
28
app.manifest
@ -1,28 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8" standalone="yes"?>
|
||||
<assembly manifestVersion="1.0" xmlns="urn:schemas-microsoft-com:asm.v1" xmlns:asmv3="urn:schemas-microsoft-com:asm.v3">
|
||||
<description>ctai</description>
|
||||
<trustInfo xmlns="urn:schemas-microsoft-com:asm.v3">
|
||||
<security>
|
||||
<requestedPrivileges>
|
||||
<requestedExecutionLevel
|
||||
level="asInvoker"
|
||||
uiAccess="false"
|
||||
/>
|
||||
</requestedPrivileges>
|
||||
</security>
|
||||
</trustInfo>
|
||||
<compatibility xmlns="urn:schemas-microsoft-com:compatibility.v1">
|
||||
<application>
|
||||
<!-- Windows 10 -->
|
||||
<supportedOS Id="{8e0f7a12-bfb3-4fe8-b9a5-48fd50a15a9a}"/>
|
||||
<!-- Windows 8.1 -->
|
||||
<supportedOS Id="{1f676c76-80e1-4239-95bb-83d0f6d0da78}"/>
|
||||
<!-- Windows Vista -->
|
||||
<supportedOS Id="{e2011457-1546-43c5-a5fe-008deee3d3f0}"/>
|
||||
<!-- Windows 7 -->
|
||||
<supportedOS Id="{35138b9a-5d96-4fbd-8e2d-a2440225f93a}"/>
|
||||
<!-- Windows 8 -->
|
||||
<supportedOS Id="{4a2f28e3-53b9-4441-ba9c-d69d4a4a6e38}"/>
|
||||
</application>
|
||||
</compatibility>
|
||||
</assembly>
|
||||
46
compatibility.manifest
Normal file
46
compatibility.manifest
Normal file
@ -0,0 +1,46 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
||||
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
|
||||
<assemblyIdentity type="Win32" name="ctai" version="6.0.0.0" processorArchitecture="x86" />
|
||||
<file name="chrome_100_percent.pak" loadFrom=".\cef_binary\chrome_100_percent.pak"></file>
|
||||
<file name="chrome_200_percent.pak" loadFrom=".\cef_binary\chrome_200_percent.pak"></file>
|
||||
<file name="chrome_elf.dll" loadFrom=".\cef_binary\chrome_elf.dll"></file>
|
||||
<file name="d3dcompiler_47.dll" loadFrom=".\cef_binary\d3dcompiler_47.dll"></file>
|
||||
<file name="dxcompiler.dll" loadFrom=".\cef_binary\dxcompiler.dll"></file>
|
||||
<file name="dxil.dll" loadFrom=".\cef_binary\dxil.dll"></file>
|
||||
<file name="icudtl.dat" loadFrom=".\cef_binary\icudtl.dat"></file>
|
||||
<file name="libcef.dll" loadFrom=".\cef_binary\libcef.dll"></file>
|
||||
<file name="libEGL.dll" loadFrom=".\cef_binary\libEGL.dll"></file>
|
||||
<file name="libGLESv2.dll" loadFrom=".\cef_binary\libGLESv2.dll"></file>
|
||||
<file name="resources.pak" loadFrom=".\cef_binary\resources.pak"></file>
|
||||
<file name="snapshot_blob.bin" loadFrom=".\cef_binary\snapshot_blob.bin"></file>
|
||||
<file name="v8_context_snapshot.bin" loadFrom=".\cef_binary\v8_context_snapshot.bin"></file>
|
||||
<file name="vk_swiftshader.dll" loadFrom=".\cef_binary\vk_swiftshader.dll"></file>
|
||||
<file name="vk_swiftshader_icd.json" loadFrom=".\cef_binary\vk_swiftshader_icd.json"></file>
|
||||
<file name="vulkan-1.dll" loadFrom=".\cef_binary\vulkan-1.dll"></file>
|
||||
|
||||
<trustInfo xmlns="urn:schemas-microsoft-com:asm.v3">
|
||||
<security>
|
||||
<requestedPrivileges>
|
||||
<requestedExecutionLevel level="asInvoker" />
|
||||
</requestedPrivileges>
|
||||
</security>
|
||||
</trustInfo>
|
||||
|
||||
<compatibility xmlns="urn:schemas-microsoft-com:compatibility.v1">
|
||||
<application>
|
||||
<!--The ID below indicates application support for Windows Vista -->
|
||||
<supportedOS Id="{e2011457-1546-43c5-a5fe-008deee3d3f0}"/>
|
||||
<!--The ID below indicates application support for Windows 7 -->
|
||||
<supportedOS Id="{35138b9a-5d96-4fbd-8e2d-a2440225f93a}"/>
|
||||
<!--The ID below indicates application support for Windows 8 -->
|
||||
<supportedOS Id="{4a2f28e3-53b9-4441-ba9c-d69d4a4a6e38}"/>
|
||||
<!--The ID below indicates application support for Windows 8.1 -->
|
||||
<supportedOS Id="{1f676c76-80e1-4239-95bb-83d0f6d0da78}"/>
|
||||
<!--The ID below indicates application support for Windows 10 -->
|
||||
<supportedOS Id="{8e0f7a12-bfb3-4fe8-b9a5-48fd50a15a9a}"/>
|
||||
<!-- This tag is required for XAML islands usage in the process for media scenarios. -->
|
||||
<!-- This version corresponds to the Windows 10 May 2019 Update. -->
|
||||
<maxversiontested Id="10.0.18362.0"/>
|
||||
</application>
|
||||
</compatibility>
|
||||
</assembly>
|
||||
@ -1,73 +0,0 @@
|
||||
#include "CefViewAppBase.h"
|
||||
|
||||
#include "../Common/CefViewCoreLog.h"
|
||||
#include <CefViewCoreProtocol.h>
|
||||
|
||||
// These flags must match the Chromium values.
|
||||
const char kProcessType[] = "type";
|
||||
const char kZygoteProcess[] = "zygote";
|
||||
const char kRendererProcess[] = "renderer";
|
||||
|
||||
CefViewAppBase::CefViewAppBase(const CefString& scheme_name)
|
||||
: builtin_scheme_name_(scheme_name)
|
||||
{
|
||||
}
|
||||
|
||||
// static
|
||||
CefViewAppBase::ProcessType
|
||||
CefViewAppBase::GetProcessType(CefRefPtr<CefCommandLine> command_line)
|
||||
{
|
||||
// The command-line flag won't be specified for the browser process.
|
||||
if (!command_line->HasSwitch(kProcessType))
|
||||
return UnkownProcess;
|
||||
|
||||
auto process_type = command_line->GetSwitchValue(kProcessType);
|
||||
logI("process type parameter is: %s", process_type.c_str());
|
||||
if (process_type == kZygoteProcess) {
|
||||
// for linux only
|
||||
return ZygoteProcess;
|
||||
} else if (process_type == kRendererProcess) {
|
||||
return RendererProcess;
|
||||
}
|
||||
|
||||
return OtherProcess;
|
||||
}
|
||||
|
||||
CefString
|
||||
CefViewAppBase::GetBridgeObjectName(CefRefPtr<CefCommandLine> command_line)
|
||||
{
|
||||
if (!command_line->HasSwitch(kCefViewBridgeObjectNameKey))
|
||||
return "";
|
||||
|
||||
auto name = command_line->GetSwitchValue(kCefViewBridgeObjectNameKey);
|
||||
logI("bridge object name: %s", name.c_str());
|
||||
return name;
|
||||
}
|
||||
|
||||
CefString
|
||||
CefViewAppBase::GetBuiltinSchemeName(CefRefPtr<CefCommandLine> command_line)
|
||||
{
|
||||
if (!command_line->HasSwitch(kCefViewBuiltinSchemeNameKey))
|
||||
return "";
|
||||
|
||||
auto name = command_line->GetSwitchValue(kCefViewBuiltinSchemeNameKey);
|
||||
logI("built-in scheme name: %s", name.c_str());
|
||||
return name;
|
||||
}
|
||||
|
||||
void
|
||||
CefViewAppBase::OnRegisterCustomSchemes(CefRawPtr<CefSchemeRegistrar> registrar)
|
||||
{
|
||||
if (registrar) {
|
||||
int options = 0 //
|
||||
| CEF_SCHEME_OPTION_STANDARD //
|
||||
| CEF_SCHEME_OPTION_SECURE //
|
||||
| CEF_SCHEME_OPTION_CORS_ENABLED //
|
||||
| CEF_SCHEME_OPTION_FETCH_ENABLED //
|
||||
| 0;
|
||||
auto scheme = builtin_scheme_name_.empty() ? kCefViewDefaultBuiltinSchemaName : builtin_scheme_name_;
|
||||
if (!registrar->AddCustomScheme(scheme, options)) {
|
||||
logE("faield to add built-in scheme: %s", scheme.c_str());
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,67 +0,0 @@
|
||||
//
|
||||
// CefWingAppBase.hpp
|
||||
// CefViewWing
|
||||
//
|
||||
// Created by Sheen Tian on 2020/6/17.
|
||||
//
|
||||
|
||||
#ifndef CefAppBase_h
|
||||
#define CefAppBase_h
|
||||
|
||||
#pragma region stl_headers
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#pragma endregion
|
||||
|
||||
#pragma region cef_headers
|
||||
#include <include/cef_app.h>
|
||||
#pragma endregion
|
||||
|
||||
class CefViewAppBase : public CefApp
|
||||
{
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
CefString builtin_scheme_name_;
|
||||
|
||||
public:
|
||||
CefViewAppBase(const CefString& scheme_name);
|
||||
|
||||
enum ProcessType
|
||||
{
|
||||
UnkownProcess,
|
||||
ZygoteProcess,
|
||||
RendererProcess,
|
||||
OtherProcess,
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// Gets the current process type
|
||||
/// </summary>
|
||||
/// <param name="command_line">The command line</param>
|
||||
/// <returns>The process type</returns>
|
||||
static ProcessType GetProcessType(CefRefPtr<CefCommandLine> command_line);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the bridge object name from command line
|
||||
/// </summary>
|
||||
/// <param name="command_line">The command line</param>
|
||||
/// <returns>The bridge object name</returns>
|
||||
static CefString GetBridgeObjectName(CefRefPtr<CefCommandLine> command_line);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the built-in scheme name
|
||||
/// </summary>
|
||||
/// <param name="command_line">The command line</param>
|
||||
/// <returns>The built-in scheme name</returns>
|
||||
static CefString GetBuiltinSchemeName(CefRefPtr<CefCommandLine> command_line);
|
||||
|
||||
private:
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="registrar"></param>
|
||||
virtual void OnRegisterCustomSchemes(CefRawPtr<CefSchemeRegistrar> registrar) override;
|
||||
};
|
||||
|
||||
#endif
|
||||
@ -1,6 +0,0 @@
|
||||
#include "CefViewOtherApp.h"
|
||||
|
||||
CefViewOtherApp::CefViewOtherApp(const CefString& scheme_name)
|
||||
: CefViewAppBase(scheme_name)
|
||||
{
|
||||
}
|
||||
@ -1,22 +0,0 @@
|
||||
//
|
||||
// CefOtherApp.hpp
|
||||
// CefViewWing
|
||||
//
|
||||
// Created by Sheen Tian on 2020/6/17.
|
||||
//
|
||||
|
||||
#ifndef CefOtherApp_h
|
||||
#define CefOtherApp_h
|
||||
#pragma once
|
||||
|
||||
#include "CefViewAppBase.h"
|
||||
|
||||
class CefViewOtherApp : public CefViewAppBase
|
||||
{
|
||||
IMPLEMENT_REFCOUNTING(CefViewOtherApp);
|
||||
|
||||
public:
|
||||
CefViewOtherApp(const CefString& scheme_name);
|
||||
};
|
||||
|
||||
#endif
|
||||
@ -1,208 +0,0 @@
|
||||
#include "CefViewRenderApp.h"
|
||||
|
||||
#pragma region cef_headers
|
||||
#include <include/cef_browser.h>
|
||||
#include <include/cef_command_line.h>
|
||||
#include <include/wrapper/cef_helpers.h>
|
||||
#pragma endregion
|
||||
|
||||
#include "../Common/CefViewCoreLog.h"
|
||||
|
||||
#include <CefViewCoreProtocol.h>
|
||||
|
||||
CefViewRenderApp::CefViewRenderApp(const CefString& scheme_name, const CefString& bridge_name)
|
||||
: CefViewAppBase(scheme_name)
|
||||
, bridge_object_name_(bridge_name)
|
||||
, last_node_is_editable_(false)
|
||||
{
|
||||
}
|
||||
|
||||
CefViewRenderApp::~CefViewRenderApp() {}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
CefRefPtr<CefRenderProcessHandler>
|
||||
CefViewRenderApp::GetRenderProcessHandler()
|
||||
{
|
||||
return this;
|
||||
}
|
||||
|
||||
void
|
||||
CefViewRenderApp::OnWebKitInitialized()
|
||||
{
|
||||
CEF_REQUIRE_RENDERER_THREAD();
|
||||
|
||||
CefMessageRouterConfig config;
|
||||
config.js_query_function = kCefViewQueryFuntionName;
|
||||
config.js_cancel_function = kCefViewQueryCancelFunctionName;
|
||||
message_router_ = CefMessageRouterRendererSide::Create(config);
|
||||
}
|
||||
|
||||
void
|
||||
CefViewRenderApp::OnBrowserCreated(CefRefPtr<CefBrowser> browser, CefRefPtr<CefDictionaryValue> extra_info)
|
||||
{
|
||||
CEF_REQUIRE_RENDERER_THREAD();
|
||||
}
|
||||
|
||||
void
|
||||
CefViewRenderApp::OnBrowserDestroyed(CefRefPtr<CefBrowser> browser)
|
||||
{
|
||||
CEF_REQUIRE_RENDERER_THREAD();
|
||||
}
|
||||
|
||||
CefRefPtr<CefLoadHandler>
|
||||
CefViewRenderApp::GetLoadHandler()
|
||||
{
|
||||
CEF_REQUIRE_RENDERER_THREAD();
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void
|
||||
CefViewRenderApp::OnContextCreated(CefRefPtr<CefBrowser> browser,
|
||||
CefRefPtr<CefFrame> frame,
|
||||
CefRefPtr<CefV8Context> context)
|
||||
{
|
||||
CEF_REQUIRE_RENDERER_THREAD();
|
||||
|
||||
// [Javascript Context]
|
||||
// V8 context for this frame has been initialized already,
|
||||
// but the script of the page hasn't been executed now
|
||||
message_router_->OnContextCreated(browser, frame, context);
|
||||
|
||||
// log this event
|
||||
frame->ExecuteJavaScript("console.info('[JSRuntime]:frame context created')", frame->GetURL(), 0);
|
||||
|
||||
// binding bridge object and functions
|
||||
auto frameId = frame->GetIdentifier();
|
||||
auto it = frame_id_to_bridge_obj_map_.find(frameId);
|
||||
if (it == frame_id_to_bridge_obj_map_.end()) {
|
||||
// create and insert the bridge Object into this frame.window object
|
||||
CefRefPtr<CefV8Value> objWindow = context->GetGlobal();
|
||||
CefRefPtr<CefViewBridgeObject> objClient = new CefViewBridgeObject(browser, frame, objWindow, bridge_object_name_);
|
||||
if (!objClient) {
|
||||
log_error("Failed to create the client object");
|
||||
return;
|
||||
}
|
||||
frame_id_to_bridge_obj_map_[frameId] = objClient;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
CefViewRenderApp::OnContextReleased(CefRefPtr<CefBrowser> browser,
|
||||
CefRefPtr<CefFrame> frame,
|
||||
CefRefPtr<CefV8Context> context)
|
||||
{
|
||||
CEF_REQUIRE_RENDERER_THREAD();
|
||||
|
||||
message_router_->OnContextReleased(browser, frame, context);
|
||||
|
||||
auto frameId = frame->GetIdentifier();
|
||||
auto it = frame_id_to_bridge_obj_map_.find(frameId);
|
||||
if (it != frame_id_to_bridge_obj_map_.end()) {
|
||||
frame_id_to_bridge_obj_map_.erase(it);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
CefViewRenderApp::OnUncaughtException(CefRefPtr<CefBrowser> browser,
|
||||
CefRefPtr<CefFrame> frame,
|
||||
CefRefPtr<CefV8Context> context,
|
||||
CefRefPtr<CefV8Exception> exception,
|
||||
CefRefPtr<CefV8StackTrace> stackTrace)
|
||||
{
|
||||
CEF_REQUIRE_RENDERER_THREAD();
|
||||
}
|
||||
|
||||
void
|
||||
CefViewRenderApp::OnFocusedNodeChanged(CefRefPtr<CefBrowser> browser,
|
||||
CefRefPtr<CefFrame> frame,
|
||||
CefRefPtr<CefDOMNode> node)
|
||||
{
|
||||
CEF_REQUIRE_RENDERER_THREAD();
|
||||
|
||||
bool is_editable = (node.get() && node->IsEditable());
|
||||
if (is_editable != last_node_is_editable_) {
|
||||
// Notify the browser of the change in focused element type.
|
||||
last_node_is_editable_ = is_editable;
|
||||
CefRefPtr<CefProcessMessage> message = CefProcessMessage::Create(kCefViewClientRenderFocusedNodeChangedMessage);
|
||||
message->GetArgumentList()->SetBool(0, is_editable);
|
||||
frame->SendProcessMessage(PID_BROWSER, message);
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
CefViewRenderApp::OnProcessMessageReceived(CefRefPtr<CefBrowser> browser,
|
||||
CefRefPtr<CefFrame> frame,
|
||||
CefProcessId source_process,
|
||||
CefRefPtr<CefProcessMessage> message)
|
||||
{
|
||||
CEF_REQUIRE_RENDERER_THREAD();
|
||||
|
||||
bool handled = false;
|
||||
|
||||
if (message_router_->OnProcessMessageReceived(browser, frame, source_process, message)) {
|
||||
handled = true;
|
||||
}
|
||||
|
||||
if (OnTriggerEventNotifyMessage(browser, frame, source_process, message)) {
|
||||
handled = true;
|
||||
}
|
||||
|
||||
return handled;
|
||||
}
|
||||
|
||||
bool
|
||||
CefViewRenderApp::OnTriggerEventNotifyMessage(CefRefPtr<CefBrowser> browser,
|
||||
CefRefPtr<CefFrame> frame,
|
||||
CefProcessId source_process,
|
||||
CefRefPtr<CefProcessMessage> message)
|
||||
{
|
||||
if (message->GetName() == kCefViewClientBrowserTriggerEventMessage) {
|
||||
CefRefPtr<CefListValue> args = message->GetArgumentList()->Copy();
|
||||
//** arguments(CefValueList)
|
||||
//** +------------+
|
||||
//** | event name |
|
||||
//** | event arg1 |
|
||||
//** | event arg2 |
|
||||
//** | event arg3 |
|
||||
//** | event arg4 |
|
||||
//** | ... |
|
||||
//** | ... |
|
||||
//** | ... |
|
||||
//** | ... |
|
||||
//** +------------+
|
||||
if (!args || args->GetSize() <= 0) {
|
||||
log_error("Invalid message arguments, event name is required");
|
||||
return true;
|
||||
}
|
||||
|
||||
if (CefValueType::VTYPE_STRING != args->GetType(0)) {
|
||||
log_error("Invalid message arguments, invalid type for event name");
|
||||
return true;
|
||||
}
|
||||
|
||||
auto name = args->GetString(0);
|
||||
args->Remove(0);
|
||||
ExecuteEventListener(browser, frame, name, args);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void
|
||||
CefViewRenderApp::ExecuteEventListener(CefRefPtr<CefBrowser> browser,
|
||||
CefRefPtr<CefFrame> frame,
|
||||
const CefString& name,
|
||||
CefRefPtr<CefListValue> args)
|
||||
{
|
||||
if (browser && frame) {
|
||||
auto frameId = frame->GetIdentifier();
|
||||
auto it = frame_id_to_bridge_obj_map_.find(frameId);
|
||||
if (it != frame_id_to_bridge_obj_map_.end()) {
|
||||
const CefRefPtr<CefViewBridgeObject>& objClient = it->second;
|
||||
objClient->ExecuteEventListener(name, args);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,180 +0,0 @@
|
||||
#ifndef CefRenderApp_h
|
||||
#define CefRenderApp_h
|
||||
#pragma once
|
||||
|
||||
#pragma region stl_headers
|
||||
#include <unordered_map>
|
||||
#pragma endregion
|
||||
|
||||
#pragma region cef_headers
|
||||
#include <include/wrapper/cef_message_router.h>
|
||||
#pragma endregion
|
||||
|
||||
#include <CefViewCoreGlobal.h>
|
||||
|
||||
#include "CefViewAppBase.h"
|
||||
#include "../Bridge/CefViewBridgeObject.h"
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
class CefViewRenderApp
|
||||
: public CefViewAppBase
|
||||
, public CefRenderProcessHandler
|
||||
{
|
||||
// Include the default reference counting implementation.
|
||||
IMPLEMENT_REFCOUNTING(CefViewRenderApp);
|
||||
|
||||
private:
|
||||
CefString bridge_object_name_;
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
CefRefPtr<CefMessageRouterRendererSide> message_router_;
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
typedef std::unordered_map<CefFrameId, CefRefPtr<CefViewBridgeObject>> FrameID2BridgeObjMap;
|
||||
FrameID2BridgeObjMap frame_id_to_bridge_obj_map_;
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
bool last_node_is_editable_;
|
||||
|
||||
public:
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
CefViewRenderApp(const CefString& scheme_name, const CefString& bridge_name);
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
~CefViewRenderApp();
|
||||
|
||||
private:
|
||||
#pragma region CefApp
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
virtual CefRefPtr<CefRenderProcessHandler> GetRenderProcessHandler() override;
|
||||
|
||||
#pragma endregion
|
||||
|
||||
#pragma region CefRenderProcessHandler
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
virtual void OnWebKitInitialized() override;
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="browser"></param>
|
||||
/// <param name="extra_info"></param>
|
||||
virtual void OnBrowserCreated(CefRefPtr<CefBrowser> browser, CefRefPtr<CefDictionaryValue> extra_info) override;
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="browser"></param>
|
||||
virtual void OnBrowserDestroyed(CefRefPtr<CefBrowser> browser) override;
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
virtual CefRefPtr<CefLoadHandler> GetLoadHandler() override;
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="browser"></param>
|
||||
/// <param name="frame"></param>
|
||||
/// <param name="context"></param>
|
||||
virtual void OnContextCreated(CefRefPtr<CefBrowser> browser,
|
||||
CefRefPtr<CefFrame> frame,
|
||||
CefRefPtr<CefV8Context> context) override;
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="browser"></param>
|
||||
/// <param name="frame"></param>
|
||||
/// <param name="context"></param>
|
||||
virtual void OnContextReleased(CefRefPtr<CefBrowser> browser,
|
||||
CefRefPtr<CefFrame> frame,
|
||||
CefRefPtr<CefV8Context> context) override;
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="browser"></param>
|
||||
/// <param name="frame"></param>
|
||||
/// <param name="context"></param>
|
||||
/// <param name="exception"></param>
|
||||
/// <param name="stackTrace"></param>
|
||||
virtual void OnUncaughtException(CefRefPtr<CefBrowser> browser,
|
||||
CefRefPtr<CefFrame> frame,
|
||||
CefRefPtr<CefV8Context> context,
|
||||
CefRefPtr<CefV8Exception> exception,
|
||||
CefRefPtr<CefV8StackTrace> stackTrace) override;
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="browser"></param>
|
||||
/// <param name="frame"></param>
|
||||
/// <param name="node"></param>
|
||||
virtual void OnFocusedNodeChanged(CefRefPtr<CefBrowser> browser,
|
||||
CefRefPtr<CefFrame> frame,
|
||||
CefRefPtr<CefDOMNode> node) override;
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="browser"></param>
|
||||
/// <param name="frame"></param>
|
||||
/// <param name="source_process"></param>
|
||||
/// <param name="message"></param>
|
||||
/// <returns></returns>
|
||||
virtual bool OnProcessMessageReceived(CefRefPtr<CefBrowser> browser,
|
||||
CefRefPtr<CefFrame> frame,
|
||||
CefProcessId source_process,
|
||||
CefRefPtr<CefProcessMessage> message) override;
|
||||
|
||||
#pragma endregion
|
||||
|
||||
private:
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="browser"></param>
|
||||
/// <param name="frame"></param>
|
||||
/// <param name="source_process"></param>
|
||||
/// <param name="message"></param>
|
||||
/// <returns></returns>
|
||||
bool OnTriggerEventNotifyMessage(CefRefPtr<CefBrowser> browser,
|
||||
CefRefPtr<CefFrame> frame,
|
||||
CefProcessId source_process,
|
||||
CefRefPtr<CefProcessMessage> message);
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="browser"></param>
|
||||
/// <param name="frame"></param>
|
||||
/// <param name="name"></param>
|
||||
/// <param name="list"></param>
|
||||
void ExecuteEventListener(CefRefPtr<CefBrowser> browser,
|
||||
CefRefPtr<CefFrame> frame,
|
||||
const CefString& name,
|
||||
CefRefPtr<CefListValue> args);
|
||||
};
|
||||
|
||||
#endif
|
||||
@ -1,517 +0,0 @@
|
||||
#include "CefViewBridgeObject.h"
|
||||
|
||||
#include <include/cef_version.h>
|
||||
|
||||
#include "../Common/CefViewCoreLog.h"
|
||||
#include <CefViewCoreProtocol.h>
|
||||
|
||||
|
||||
#if CEF_VERSION_MAJOR >= 119
|
||||
class CefViewArrayBuffer : public CefV8ArrayBufferReleaseCallback
|
||||
{
|
||||
IMPLEMENT_REFCOUNTING(CefViewArrayBuffer);
|
||||
DISALLOW_COPY_AND_ASSIGN(CefViewArrayBuffer);
|
||||
|
||||
public:
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="v"></param>
|
||||
CefViewArrayBuffer(CefBinaryValue* v)
|
||||
: m_size(0)
|
||||
, m_buffer(nullptr)
|
||||
{
|
||||
if (v) {
|
||||
auto l = v->GetSize();
|
||||
if (l) {
|
||||
m_buffer = std::make_unique<uint8_t[]>(l);
|
||||
v->GetData(m_buffer.get(), l, 0);
|
||||
m_size = l;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
~CefViewArrayBuffer()
|
||||
{
|
||||
m_buffer.reset();
|
||||
m_size = 0;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
void* GetBuffer()
|
||||
{
|
||||
// get under layer buffer address
|
||||
return m_buffer.get();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
size_t GetSize()
|
||||
{
|
||||
// return size
|
||||
return m_size;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="buffer"></param>
|
||||
void ReleaseBuffer(void* buffer) override
|
||||
{
|
||||
// release under layer buffer
|
||||
m_buffer.reset();
|
||||
m_size = 0;
|
||||
}
|
||||
|
||||
private:
|
||||
size_t m_size;
|
||||
std::unique_ptr<uint8_t[]> m_buffer;
|
||||
};
|
||||
#endif
|
||||
|
||||
CefViewBridgeObject::V8Handler::V8Handler(CefViewBridgeObject* object)
|
||||
: object_(object)
|
||||
{
|
||||
}
|
||||
|
||||
bool
|
||||
CefViewBridgeObject::V8Handler::Execute(const CefString& function,
|
||||
CefRefPtr<CefV8Value> object,
|
||||
const CefV8ValueList& arguments,
|
||||
CefRefPtr<CefV8Value>& retval,
|
||||
CefString& exception)
|
||||
{
|
||||
if (function == kCefViewInvokeMethodFunctionName)
|
||||
ExecuteNativeMethod(object, arguments, retval, exception);
|
||||
else if (function == kCefViewAddEventListenerFunctionName)
|
||||
ExecuteAddEventListener(object, arguments, retval, exception);
|
||||
else if (function == kCefViewRemoveEventListenerFunctionName)
|
||||
ExecuteRemoveEventListener(object, arguments, retval, exception);
|
||||
else if (function == kCefViewReportJSResultFunctionName)
|
||||
ExecuteReportJSResult(object, arguments, retval, exception);
|
||||
else
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
CefViewBridgeObject::V8Handler::ExecuteNativeMethod(CefRefPtr<CefV8Value> object,
|
||||
const CefV8ValueList& arguments,
|
||||
CefRefPtr<CefV8Value>& retval,
|
||||
CefString& exception)
|
||||
{
|
||||
object_->AsyncExecuteNativeMethod(arguments);
|
||||
retval = CefV8Value::CreateUndefined();
|
||||
}
|
||||
|
||||
void
|
||||
CefViewBridgeObject::V8Handler::ExecuteAddEventListener(CefRefPtr<CefV8Value> object,
|
||||
const CefV8ValueList& arguments,
|
||||
CefRefPtr<CefV8Value>& retval,
|
||||
CefString& exception)
|
||||
{
|
||||
bool bRet = false;
|
||||
|
||||
if (arguments.size() == 2) {
|
||||
if (arguments[0]->IsString()) {
|
||||
if (arguments[1]->IsFunction()) {
|
||||
CefString eventName = arguments[0]->GetStringValue();
|
||||
EventListener listener;
|
||||
listener.callback_ = arguments[1];
|
||||
listener.context_ = CefV8Context::GetCurrentContext();
|
||||
object_->AddEventListener(eventName, listener);
|
||||
bRet = true;
|
||||
} else
|
||||
exception = "Invalid arguments; argument 2 must be a function";
|
||||
} else
|
||||
exception = "Invalid arguments; argument 1 must be a string";
|
||||
} else
|
||||
exception = "Invalid arguments; expecting 2 arguments";
|
||||
|
||||
retval = CefV8Value::CreateBool(bRet);
|
||||
}
|
||||
|
||||
void
|
||||
CefViewBridgeObject::V8Handler::ExecuteRemoveEventListener(CefRefPtr<CefV8Value> object,
|
||||
const CefV8ValueList& arguments,
|
||||
CefRefPtr<CefV8Value>& retval,
|
||||
CefString& exception)
|
||||
{
|
||||
bool bRet = false;
|
||||
|
||||
if (arguments.size() == 2) {
|
||||
if (arguments[0]->IsString()) {
|
||||
if (arguments[1]->IsFunction()) {
|
||||
CefString eventName = arguments[0]->GetStringValue();
|
||||
EventListener listener;
|
||||
listener.callback_ = arguments[1];
|
||||
listener.context_ = CefV8Context::GetCurrentContext();
|
||||
object_->RemoveEventListener(eventName, listener);
|
||||
bRet = true;
|
||||
} else
|
||||
exception = "Invalid arguments; argument 2 must be a function";
|
||||
} else
|
||||
exception = "Invalid arguments; argument 1 must be a string";
|
||||
} else
|
||||
exception = "Invalid arguments; expecting 2 arguments";
|
||||
|
||||
retval = CefV8Value::CreateBool(bRet);
|
||||
}
|
||||
|
||||
void
|
||||
CefViewBridgeObject::V8Handler::ExecuteReportJSResult(CefRefPtr<CefV8Value> object,
|
||||
const CefV8ValueList& arguments,
|
||||
CefRefPtr<CefV8Value>& retval,
|
||||
CefString& exception)
|
||||
{
|
||||
if (arguments.size() == 2) {
|
||||
if (arguments[0]->IsString()) {
|
||||
object_->AsyncExecuteReportJSResult(arguments);
|
||||
} else
|
||||
exception = "Invalid argument; argument 1 must be a double";
|
||||
} else
|
||||
exception = "Invalid argument; expecting 2 argument";
|
||||
|
||||
retval = CefV8Value::CreateUndefined();
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
CefViewBridgeObject::CefViewBridgeObject(CefRefPtr<CefBrowser> browser,
|
||||
CefRefPtr<CefFrame> frame,
|
||||
CefRefPtr<CefV8Value> global,
|
||||
const CefString& name)
|
||||
: name_(name.empty() ? kCefViewDefaultBridgeObjectName : name)
|
||||
, bridgeObject_(nullptr)
|
||||
, reportJSResultFunction_(nullptr)
|
||||
, browser_(browser)
|
||||
, frame_(frame)
|
||||
, v8Handler_(new V8Handler(this))
|
||||
{
|
||||
// create bridge object and mount it on the global context(window)
|
||||
bridgeObject_ = CefV8Value::CreateObject(nullptr, nullptr);
|
||||
|
||||
// create function "invokeMethod"
|
||||
CefRefPtr<CefV8Value> funcInvokeMethod = CefV8Value::CreateFunction(kCefViewInvokeMethodFunctionName, v8Handler_);
|
||||
// add this function to window object
|
||||
bridgeObject_->SetValue(kCefViewInvokeMethodFunctionName,
|
||||
funcInvokeMethod,
|
||||
static_cast<CefV8Value::PropertyAttribute>(V8_PROPERTY_ATTRIBUTE_READONLY |
|
||||
V8_PROPERTY_ATTRIBUTE_DONTENUM |
|
||||
V8_PROPERTY_ATTRIBUTE_DONTDELETE));
|
||||
|
||||
// create function addEventListener
|
||||
CefRefPtr<CefV8Value> funcAddEventListener =
|
||||
CefV8Value::CreateFunction(kCefViewAddEventListenerFunctionName, v8Handler_);
|
||||
// add this function to window object
|
||||
bridgeObject_->SetValue(kCefViewAddEventListenerFunctionName,
|
||||
funcAddEventListener,
|
||||
static_cast<CefV8Value::PropertyAttribute>(V8_PROPERTY_ATTRIBUTE_READONLY |
|
||||
V8_PROPERTY_ATTRIBUTE_DONTENUM |
|
||||
V8_PROPERTY_ATTRIBUTE_DONTDELETE));
|
||||
|
||||
// create function removeListener
|
||||
CefRefPtr<CefV8Value> funcRemoveEventListener =
|
||||
CefV8Value::CreateFunction(kCefViewRemoveEventListenerFunctionName, v8Handler_);
|
||||
// add this function to window object
|
||||
bridgeObject_->SetValue(kCefViewRemoveEventListenerFunctionName,
|
||||
funcRemoveEventListener,
|
||||
static_cast<CefV8Value::PropertyAttribute>(V8_PROPERTY_ATTRIBUTE_READONLY |
|
||||
V8_PROPERTY_ATTRIBUTE_DONTENUM |
|
||||
V8_PROPERTY_ATTRIBUTE_DONTDELETE));
|
||||
|
||||
// mount the client object to the global context(usually the window object)
|
||||
global->SetValue(name_,
|
||||
bridgeObject_,
|
||||
static_cast<CefV8Value::PropertyAttribute>(V8_PROPERTY_ATTRIBUTE_READONLY |
|
||||
V8_PROPERTY_ATTRIBUTE_DONTENUM |
|
||||
V8_PROPERTY_ATTRIBUTE_DONTDELETE));
|
||||
frame_->ExecuteJavaScript("console.info('[JSRuntime]:window." + name_.ToString() + " [object] created');", frame_->GetURL(), 0);
|
||||
|
||||
// create "__cefview_report_js_result__" function and mount it on the global context(window)
|
||||
reportJSResultFunction_ = CefV8Value::CreateFunction(kCefViewReportJSResultFunctionName, v8Handler_);
|
||||
global->SetValue(kCefViewReportJSResultFunctionName,
|
||||
reportJSResultFunction_,
|
||||
static_cast<CefV8Value::PropertyAttribute>(V8_PROPERTY_ATTRIBUTE_READONLY |
|
||||
V8_PROPERTY_ATTRIBUTE_DONTENUM |
|
||||
V8_PROPERTY_ATTRIBUTE_DONTDELETE));
|
||||
frame_->ExecuteJavaScript("console.info('[JSRuntime]:window." kCefViewReportJSResultFunctionName
|
||||
" [function] created');",
|
||||
frame_->GetURL(),
|
||||
0);
|
||||
}
|
||||
|
||||
CefRefPtr<CefV8Value>
|
||||
CefViewBridgeObject::CefValueToV8Value(CefValue* cefValue)
|
||||
{
|
||||
CefRefPtr<CefV8Value> v8Value = CefV8Value::CreateNull();
|
||||
if (!cefValue) {
|
||||
return v8Value;
|
||||
}
|
||||
|
||||
auto type = cefValue->GetType();
|
||||
switch (type) {
|
||||
case CefValueType::VTYPE_INVALID: {
|
||||
v8Value = CefV8Value::CreateUndefined();
|
||||
} break;
|
||||
case CefValueType::VTYPE_NULL: {
|
||||
v8Value = CefV8Value::CreateNull();
|
||||
} break;
|
||||
case CefValueType::VTYPE_BOOL: {
|
||||
auto v = cefValue->GetBool();
|
||||
v8Value = CefV8Value::CreateBool(v);
|
||||
} break;
|
||||
case CefValueType::VTYPE_INT: {
|
||||
auto v = cefValue->GetInt();
|
||||
v8Value = CefV8Value::CreateInt(v);
|
||||
} break;
|
||||
case CefValueType::VTYPE_DOUBLE: {
|
||||
auto v = cefValue->GetDouble();
|
||||
v8Value = CefV8Value::CreateDouble(v);
|
||||
} break;
|
||||
case CefValueType::VTYPE_STRING: {
|
||||
auto v = cefValue->GetString();
|
||||
v8Value = CefV8Value::CreateString(v);
|
||||
} break;
|
||||
case CefValueType::VTYPE_BINARY: {
|
||||
#if CEF_VERSION_MAJOR >= 119
|
||||
auto v = cefValue->GetBinary();
|
||||
auto arryBuffer = new CefViewArrayBuffer(v.get());
|
||||
v8Value = CefV8Value::CreateArrayBuffer(arryBuffer->GetBuffer(), arryBuffer->GetSize(), arryBuffer);
|
||||
#else
|
||||
// currently not supported
|
||||
#endif
|
||||
} break;
|
||||
case CefValueType::VTYPE_DICTIONARY: {
|
||||
auto cDict = cefValue->GetDictionary();
|
||||
CefDictionaryValue::KeyList cKeys;
|
||||
cDict->GetKeys(cKeys);
|
||||
v8Value = CefV8Value::CreateObject(nullptr, nullptr);
|
||||
for (auto& key : cKeys) {
|
||||
auto cVal = cDict->GetValue(key);
|
||||
auto v8Val = CefValueToV8Value(cVal.get());
|
||||
v8Value->SetValue(key, v8Val.get(), V8_PROPERTY_ATTRIBUTE_NONE);
|
||||
}
|
||||
} break;
|
||||
case CefValueType::VTYPE_LIST: {
|
||||
auto cList = cefValue->GetList();
|
||||
int cCount = static_cast<int>(cList->GetSize());
|
||||
v8Value = CefV8Value::CreateArray(static_cast<int>(cCount));
|
||||
for (int i = 0; i < cCount; i++) {
|
||||
auto cVal = cList->GetValue(i);
|
||||
auto v8Val = CefValueToV8Value(cVal.get());
|
||||
v8Value->SetValue(i, v8Val.get());
|
||||
}
|
||||
} break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return v8Value;
|
||||
}
|
||||
|
||||
CefRefPtr<CefValue>
|
||||
CefViewBridgeObject::V8ValueToCefValue(CefV8Value* v8Value)
|
||||
{
|
||||
CefRefPtr<CefValue> cefValue = CefValue::Create();
|
||||
if (!v8Value) {
|
||||
return cefValue;
|
||||
}
|
||||
|
||||
/**
|
||||
* The IsDouble, IsInt and IsUint methods return a boolean value indicating whether the CefV8Value instance is an
|
||||
* target type or can be converted to the target type.If the value can be converted to the target type, the methods
|
||||
* will attempt to do so and return true. If the value is not the target type or cannot be converted to the target
|
||||
* type, the method will return false.
|
||||
*
|
||||
* For example the code below:
|
||||
* auto v = CefV8Value::CreateInt(1000);
|
||||
* auto isDouble = v->IsDouble();
|
||||
* logD("isDouble: %d", isDouble); // true
|
||||
* auto isUnint = v->IsUInt();
|
||||
* logD("isUnint: %d", isUnint); // true
|
||||
* auto isInt = v->IsInt();
|
||||
* logD("isInt: %d", isInt); // true
|
||||
*
|
||||
* auto v = CefV8Value::CreateDouble(0.1);
|
||||
* auto isDouble = v->IsDouble();
|
||||
* logD("isDouble: %d", isDouble); // true
|
||||
* auto isUnint = v->IsUInt();
|
||||
* logD("isUnint: %d", isUnint); // false
|
||||
* auto isInt = v->IsInt();
|
||||
* logD("isInt: %d", isInt); // false
|
||||
*
|
||||
* so we need to keep the testing order, IsInt/IsUint - IsDouble
|
||||
* since there is no Uint type in JavaScript, we just ignore it.
|
||||
* Please refer to this test souce:
|
||||
* https://github.com/svn2github/cef/blob/master/tests/cefclient/binding_test.cpp
|
||||
*/
|
||||
if (v8Value->IsNull() || v8Value->IsUndefined())
|
||||
cefValue->SetNull();
|
||||
else if (v8Value->IsBool())
|
||||
cefValue->SetBool(v8Value->GetBoolValue());
|
||||
else if (v8Value->IsInt())
|
||||
cefValue->SetInt(v8Value->GetIntValue());
|
||||
else if (v8Value->IsDouble())
|
||||
cefValue->SetDouble(v8Value->GetDoubleValue());
|
||||
else if (v8Value->IsString())
|
||||
cefValue->SetString(v8Value->GetStringValue());
|
||||
else if (v8Value->IsArrayBuffer()) {
|
||||
#if CEF_VERSION_MAJOR >= 119
|
||||
auto size = v8Value->GetArrayBufferByteLength();
|
||||
auto data = v8Value->GetArrayBufferData();
|
||||
cefValue->SetBinary(CefBinaryValue::Create(data, size));
|
||||
#else
|
||||
// currently not supported
|
||||
#endif
|
||||
} else if (v8Value->IsArray()) {
|
||||
auto s = v8Value->GetArrayLength();
|
||||
auto cefList = CefListValue::Create();
|
||||
for (int i = 0; i < s; i++) {
|
||||
auto v8Val = v8Value->GetValue(i);
|
||||
auto cefVal = V8ValueToCefValue(v8Val.get());
|
||||
cefList->SetValue(i, cefVal);
|
||||
}
|
||||
cefValue->SetList(cefList);
|
||||
} else if (v8Value->IsObject()) {
|
||||
CefDictionaryValue::KeyList keys;
|
||||
v8Value->GetKeys(keys);
|
||||
auto cefDict = CefDictionaryValue::Create();
|
||||
for (auto& key : keys) {
|
||||
auto v8Val = v8Value->GetValue(key);
|
||||
auto cefVal = V8ValueToCefValue(v8Val.get());
|
||||
cefDict->SetValue(key, cefVal.get());
|
||||
}
|
||||
cefValue->SetDictionary(cefDict);
|
||||
} else
|
||||
cefValue->SetNull();
|
||||
|
||||
return cefValue;
|
||||
}
|
||||
|
||||
void
|
||||
CefViewBridgeObject::AsyncExecuteNativeMethod(const CefV8ValueList& arguments)
|
||||
{
|
||||
CefRefPtr<CefProcessMessage> msg = CefProcessMessage::Create(kCefViewClientRenderInvokeMethodMessage);
|
||||
|
||||
//** arguments(CefValueList)
|
||||
//** +-------+
|
||||
//** |0 name | <- the method name
|
||||
//** |1 arg1 |
|
||||
//** |2 arg2 |
|
||||
//** |3 arg3 |
|
||||
//** |4 arg4 |
|
||||
//** | ... |
|
||||
//** | ... |
|
||||
//** | ... |
|
||||
//** | ... |
|
||||
//** +-------+
|
||||
CefRefPtr<CefListValue> args = msg->GetArgumentList();
|
||||
|
||||
// push back all the arguments
|
||||
for (std::size_t i = 0; i < arguments.size(); i++) {
|
||||
auto cefValue = V8ValueToCefValue(arguments[i].get());
|
||||
args->SetValue(i, cefValue);
|
||||
}
|
||||
|
||||
// send the message
|
||||
if (browser_)
|
||||
frame_->SendProcessMessage(PID_BROWSER, msg);
|
||||
}
|
||||
|
||||
void
|
||||
CefViewBridgeObject::AsyncExecuteReportJSResult(const CefV8ValueList& arguments)
|
||||
{
|
||||
CefRefPtr<CefProcessMessage> msg = CefProcessMessage::Create(kCefViewClientRenderReportJSResultMessage);
|
||||
|
||||
//** arguments(CefValueList)
|
||||
//** +_------+
|
||||
//** |0 arg | <- the context (string)
|
||||
//** |1 arg | <- the result value
|
||||
//** +-------+
|
||||
CefRefPtr<CefListValue> args = msg->GetArgumentList();
|
||||
|
||||
// push back the result value
|
||||
for (std::size_t i = 0; i < arguments.size(); i++) {
|
||||
auto cefValue = V8ValueToCefValue(arguments[i].get());
|
||||
args->SetValue(i, cefValue.get());
|
||||
}
|
||||
|
||||
// send the message
|
||||
if (browser_)
|
||||
frame_->SendProcessMessage(PID_BROWSER, msg);
|
||||
}
|
||||
|
||||
void
|
||||
CefViewBridgeObject::AddEventListener(const CefString& name, const EventListener& listener)
|
||||
{
|
||||
auto itListenerList = eventListenerListMap_.find(name);
|
||||
if (itListenerList == eventListenerListMap_.end()) {
|
||||
EventListenerList eventListenerList;
|
||||
eventListenerList.push_back(listener);
|
||||
eventListenerListMap_[name] = eventListenerList;
|
||||
} else {
|
||||
EventListenerList& eventListenerList = itListenerList->second;
|
||||
// does this listener exist?
|
||||
bool found = false;
|
||||
for (auto item : eventListenerList) {
|
||||
if (item.callback_->IsSame(listener.callback_)) {
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!found)
|
||||
eventListenerList.push_back(listener);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
CefViewBridgeObject::RemoveEventListener(const CefString& name, const EventListener& listener)
|
||||
{
|
||||
auto itListenerList = eventListenerListMap_.find(name);
|
||||
if (itListenerList != eventListenerListMap_.end()) {
|
||||
EventListenerList& eventListenerList = itListenerList->second;
|
||||
for (auto itListener = eventListenerList.begin(); itListener != eventListenerList.end(); itListener++) {
|
||||
if (itListener->callback_->IsSame(listener.callback_)) {
|
||||
eventListenerList.erase(itListener);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
CefViewBridgeObject::ExecuteEventListener(const CefString eventName, CefRefPtr<CefListValue> args)
|
||||
{
|
||||
// find the listeners
|
||||
auto itListenerList = eventListenerListMap_.find(eventName);
|
||||
if (itListenerList == eventListenerListMap_.end()) {
|
||||
return;
|
||||
}
|
||||
|
||||
EventListenerList& eventListenerList = itListenerList->second;
|
||||
for (auto listener : eventListenerList) {
|
||||
listener.context_->Enter();
|
||||
|
||||
// convert argument list from CefValue to CefV8Value
|
||||
CefV8ValueList v8ArgList;
|
||||
for (size_t i = 0; i < args->GetSize(); i++) {
|
||||
auto cefValue = args->GetValue(i);
|
||||
auto v8Value = CefValueToV8Value(cefValue.get());
|
||||
v8ArgList.push_back(v8Value.get());
|
||||
}
|
||||
|
||||
listener.callback_->ExecuteFunction(bridgeObject_, v8ArgList);
|
||||
listener.context_->Exit();
|
||||
}
|
||||
}
|
||||
@ -1,221 +0,0 @@
|
||||
#pragma once
|
||||
#pragma region stl_headers
|
||||
#include <list>
|
||||
#include <map>
|
||||
#pragma endregion
|
||||
|
||||
#pragma region cef_headers
|
||||
#include <include/cef_v8.h>
|
||||
#pragma endregion
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
class CefViewBridgeObject : public CefBaseRefCounted
|
||||
{
|
||||
IMPLEMENT_REFCOUNTING(CefViewBridgeObject);
|
||||
DISALLOW_COPY_AND_ASSIGN(CefViewBridgeObject);
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
typedef struct _EventListener
|
||||
{
|
||||
CefRefPtr<CefV8Value> callback_;
|
||||
CefRefPtr<CefV8Context> context_;
|
||||
} EventListener;
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
typedef std::list<EventListener> EventListenerList;
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
typedef std::map<CefString, std::list<EventListener>> EventListenerListMap;
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
class V8Handler : public CefV8Handler
|
||||
{
|
||||
public:
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="client"></param>
|
||||
V8Handler(CefViewBridgeObject* object);
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="function"></param>
|
||||
/// <param name="object"></param>
|
||||
/// <param name="arguments"></param>
|
||||
/// <param name="retval"></param>
|
||||
/// <param name="exception"></param>
|
||||
/// <returns></returns>
|
||||
virtual bool Execute(const CefString& function,
|
||||
CefRefPtr<CefV8Value> object,
|
||||
const CefV8ValueList& arguments,
|
||||
CefRefPtr<CefV8Value>& retval,
|
||||
CefString& exception) override;
|
||||
|
||||
protected:
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="object"></param>
|
||||
/// <param name="arguments"></param>
|
||||
/// <param name="retval"></param>
|
||||
/// <param name="exception"></param>
|
||||
void ExecuteNativeMethod(CefRefPtr<CefV8Value> object,
|
||||
const CefV8ValueList& arguments,
|
||||
CefRefPtr<CefV8Value>& retval,
|
||||
CefString& exception);
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="object"></param>
|
||||
/// <param name="arguments"></param>
|
||||
/// <param name="retval"></param>
|
||||
/// <param name="exception"></param>
|
||||
void ExecuteAddEventListener(CefRefPtr<CefV8Value> object,
|
||||
const CefV8ValueList& arguments,
|
||||
CefRefPtr<CefV8Value>& retval,
|
||||
CefString& exception);
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="object"></param>
|
||||
/// <param name="arguments"></param>
|
||||
/// <param name="retval"></param>
|
||||
/// <param name="exception"></param>
|
||||
void ExecuteRemoveEventListener(CefRefPtr<CefV8Value> object,
|
||||
const CefV8ValueList& arguments,
|
||||
CefRefPtr<CefV8Value>& retval,
|
||||
CefString& exception);
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="object"></param>
|
||||
/// <param name="arguments"></param>
|
||||
/// <param name="retval"></param>
|
||||
/// <param name="exception"></param>
|
||||
void ExecuteReportJSResult(CefRefPtr<CefV8Value> object,
|
||||
const CefV8ValueList& arguments,
|
||||
CefRefPtr<CefV8Value>& retval,
|
||||
CefString& exception);
|
||||
|
||||
private:
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
CefViewBridgeObject* object_;
|
||||
|
||||
private:
|
||||
IMPLEMENT_REFCOUNTING(V8Handler);
|
||||
};
|
||||
|
||||
public:
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="browser"></param>
|
||||
/// <param name="frame"></param>
|
||||
/// <param name="global"></param>
|
||||
/// <param name="name"></param>
|
||||
CefViewBridgeObject(CefRefPtr<CefBrowser> browser,
|
||||
CefRefPtr<CefFrame> frame,
|
||||
CefRefPtr<CefV8Value> global,
|
||||
const CefString& name);
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="v8Value"></param>
|
||||
/// <param name="cefValue"></param>
|
||||
/// <returns></returns>
|
||||
CefRefPtr<CefV8Value> CefValueToV8Value(CefValue* cefValue);
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="v8Value"></param>
|
||||
/// <returns></returns>
|
||||
CefRefPtr<CefValue> V8ValueToCefValue(CefV8Value* v8Value);
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="arguments"></param>
|
||||
void AsyncExecuteNativeMethod(const CefV8ValueList& arguments);
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="arguments"></param>
|
||||
void AsyncExecuteReportJSResult(const CefV8ValueList& arguments);
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="name"></param>
|
||||
/// <param name="listener"></param>
|
||||
/// <returns></returns>
|
||||
void AddEventListener(const CefString& name, const EventListener& listener);
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="name"></param>
|
||||
/// <param name="listener"></param>
|
||||
void RemoveEventListener(const CefString& name, const EventListener& listener);
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="eventName"></param>
|
||||
/// <param name="args"></param>
|
||||
void ExecuteEventListener(const CefString eventName, CefRefPtr<CefListValue> args);
|
||||
|
||||
private:
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
CefString name_;
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
CefRefPtr<CefV8Value> bridgeObject_;
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
CefRefPtr<CefV8Value> reportJSResultFunction_;
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
CefRefPtr<CefBrowser> browser_;
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
CefRefPtr<CefFrame> frame_;
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
CefRefPtr<V8Handler> v8Handler_;
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
CefViewBridgeObject::EventListenerListMap eventListenerListMap_;
|
||||
};
|
||||
@ -1,128 +0,0 @@
|
||||
#include "CefViewWidget.h"
|
||||
|
||||
#if defined(Q_OS_WIN)
|
||||
#include <windows.h>
|
||||
#elif defined(Q_OS_MAC)
|
||||
#elif defined(Q_OS_LINUX)
|
||||
#else
|
||||
#endif
|
||||
|
||||
#include <QColor>
|
||||
#include <QDebug>
|
||||
#include <QPainterPath>
|
||||
#include <QRandomGenerator>
|
||||
#include <QResizeEvent>
|
||||
#include <QWindow>
|
||||
|
||||
#include "DownloadManager.h"
|
||||
|
||||
CefViewWidget::CefViewWidget(const QString url, const QCefSetting* setting, QWidget* parent /* = 0*/)
|
||||
: QCefView(url, setting, parent)
|
||||
{
|
||||
// setStyleSheet("background: blue;");
|
||||
|
||||
connect(this, &CefViewWidget::draggableRegionChanged, this, &CefViewWidget::onDraggableRegionChanged);
|
||||
connect(this, &CefViewWidget::nativeBrowserCreated, this, &CefViewWidget::onNativeBrowserWindowCreated);
|
||||
}
|
||||
|
||||
CefViewWidget::~CefViewWidget() {}
|
||||
|
||||
void
|
||||
CefViewWidget::onScreenChanged(QScreen* screen)
|
||||
{
|
||||
if (!m_pCefWindow)
|
||||
return;
|
||||
|
||||
updateMask();
|
||||
}
|
||||
|
||||
void
|
||||
CefViewWidget::onNativeBrowserWindowCreated(QWindow* window)
|
||||
{
|
||||
m_pCefWindow = window;
|
||||
if (!m_pCefWindow)
|
||||
return;
|
||||
|
||||
connect(this->window()->windowHandle(), SIGNAL(screenChanged(QScreen*)), this, SLOT(onScreenChanged(QScreen*)));
|
||||
|
||||
updateMask();
|
||||
}
|
||||
|
||||
void
|
||||
CefViewWidget::onDraggableRegionChanged(const QRegion& draggableRegion, const QRegion& nonDraggableRegion)
|
||||
{
|
||||
m_draggableRegion = draggableRegion;
|
||||
m_nonDraggableRegion = nonDraggableRegion;
|
||||
}
|
||||
|
||||
bool
|
||||
CefViewWidget::onNewPopup(const QCefFrameId& sourceFrameId,
|
||||
const QString& targetUrl,
|
||||
QString& targetFrameName,
|
||||
QCefView::CefWindowOpenDisposition targetDisposition,
|
||||
QRect& rect,
|
||||
QCefSetting& settings,
|
||||
bool& disableJavascriptAccess)
|
||||
{
|
||||
// create new QCefView as popup browser
|
||||
// settings.setBackgroundColor(Qt::red);
|
||||
return false;
|
||||
}
|
||||
|
||||
void
|
||||
CefViewWidget::onNewDownloadItem(const QSharedPointer<QCefDownloadItem>& item, const QString& suggestedName)
|
||||
{
|
||||
// keep the item into list or map, and call item->start() to allow the download
|
||||
|
||||
DownloadManager::getInstance().AddNewDownloadItem(item);
|
||||
}
|
||||
|
||||
void
|
||||
CefViewWidget::onUpdateDownloadItem(const QSharedPointer<QCefDownloadItem>& item)
|
||||
{
|
||||
|
||||
// control the download by invoking item->pause(), item->resume(), item->cancel()
|
||||
|
||||
DownloadManager::getInstance().UpdateDownloadItem(item);
|
||||
}
|
||||
|
||||
void
|
||||
CefViewWidget::resizeEvent(QResizeEvent* event)
|
||||
{
|
||||
// update mask first, because the new mask will be
|
||||
// used in the QCefView::resizeEvent
|
||||
updateMask();
|
||||
|
||||
QCefView::resizeEvent(event);
|
||||
}
|
||||
|
||||
void
|
||||
CefViewWidget::mousePressEvent(QMouseEvent* event)
|
||||
{
|
||||
QCefView::mousePressEvent(event);
|
||||
|
||||
#if defined(Q_OS_WIN)
|
||||
if (event->buttons().testFlag(Qt::LeftButton) && m_draggableRegion.contains(event->pos())) {
|
||||
HWND hWnd = ::GetAncestor((HWND)(window()->windowHandle()->winId()), GA_ROOT);
|
||||
POINT pt;
|
||||
::GetCursorPos(&pt);
|
||||
::ReleaseCapture();
|
||||
::SendMessage(hWnd, WM_NCLBUTTONDOWN, HTCAPTION, POINTTOPOINTS(pt));
|
||||
}
|
||||
#elif defined(Q_OS_MAC)
|
||||
#elif defined(Q_OS_LINUX)
|
||||
#else
|
||||
#endif
|
||||
}
|
||||
|
||||
void
|
||||
CefViewWidget::updateMask()
|
||||
{
|
||||
// create a rect with rounded corner (50px radius) as mask
|
||||
QPainterPath path;
|
||||
path.addRoundedRect(rect(), 50, 50);
|
||||
QRegion mask = QRegion(path.toFillPolygon().toPolygon());
|
||||
|
||||
// apply the mask
|
||||
setMask(mask);
|
||||
}
|
||||
@ -1,58 +0,0 @@
|
||||
#ifndef CUSTOMCEFVIEW_H
|
||||
#define CUSTOMCEFVIEW_H
|
||||
|
||||
#include <QScreen>
|
||||
|
||||
#include <QCefView.h>
|
||||
|
||||
/// <summary>
|
||||
/// Represents the customized QCefView
|
||||
/// </summary>
|
||||
class CefViewWidget : public QCefView
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
CefViewWidget(const QString url, const QCefSetting* setting, QWidget* parent = 0);
|
||||
|
||||
~CefViewWidget();
|
||||
|
||||
protected slots:
|
||||
void onScreenChanged(QScreen* screen);
|
||||
|
||||
void onNativeBrowserWindowCreated(QWindow* window);
|
||||
|
||||
void onDraggableRegionChanged(const QRegion& draggableRegion, const QRegion& nonDraggableRegion);
|
||||
|
||||
protected:
|
||||
bool onNewPopup(const QCefFrameId& sourceFrameId,
|
||||
const QString& targetUrl,
|
||||
QString& targetFrameName,
|
||||
QCefView::CefWindowOpenDisposition targetDisposition,
|
||||
QRect& rect,
|
||||
QCefSetting& settings,
|
||||
bool& disableJavascriptAccess) override;
|
||||
|
||||
void onNewDownloadItem(const QSharedPointer<QCefDownloadItem>& item, const QString& suggestedName) override;
|
||||
|
||||
void onUpdateDownloadItem(const QSharedPointer<QCefDownloadItem>& item) override;
|
||||
|
||||
protected:
|
||||
void resizeEvent(QResizeEvent* event) override;
|
||||
|
||||
void mousePressEvent(QMouseEvent* event) override;
|
||||
|
||||
private:
|
||||
void updateMask();
|
||||
|
||||
private:
|
||||
QWindow* m_pCefWindow = nullptr;
|
||||
|
||||
int m_iCornerRadius = 50;
|
||||
|
||||
QRegion m_draggableRegion;
|
||||
|
||||
QRegion m_nonDraggableRegion;
|
||||
};
|
||||
|
||||
#endif // CUSTOMCEFVIEW_H
|
||||
@ -67,7 +67,7 @@ void CefWidget::initBrowser()
|
||||
m_CefWidget = nullptr;
|
||||
}
|
||||
setting.setHardwareAcceleration(true);
|
||||
m_CefWidget = new CefViewWidget("", &setting, this);
|
||||
m_CefWidget = new QCefView("about:blank", &setting, this);
|
||||
connect(m_CefWidget, &QCefView::invokeMethod, this, &CefWidget::onInvokeMethod);
|
||||
connect(m_CefWidget, &QCefView::cefUrlRequest, this, &CefWidget::onQCefUrlRequest);
|
||||
connect(m_CefWidget, &QCefView::cefQueryRequest, this, &CefWidget::onQCefQueryRequest);
|
||||
|
||||
@ -7,7 +7,7 @@
|
||||
#include <QWidget>
|
||||
#include <QLineEdit>
|
||||
#include <QPushButton>
|
||||
#include "CefViewWidget.h"
|
||||
#include <QCefView.h>
|
||||
|
||||
class CefWidget : public QWidget
|
||||
{
|
||||
|
||||
@ -1,141 +0,0 @@
|
||||
//
|
||||
// CefViewCoreLog.cpp
|
||||
// CefViewCore
|
||||
//
|
||||
// Created by Sheen Tian on 2020/6/19.
|
||||
//
|
||||
|
||||
#include "CefViewCoreLog.h"
|
||||
|
||||
#include <cstdarg>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
typedef enum log_level
|
||||
{
|
||||
ll_debug = 1,
|
||||
ll_info,
|
||||
ll_error,
|
||||
ll_fatal,
|
||||
} log_level;
|
||||
|
||||
#if defined(__APPLE__)
|
||||
#include <os/log.h>
|
||||
void
|
||||
cefView_log(log_level level, const char* message)
|
||||
{
|
||||
switch (level) {
|
||||
case ll_debug:
|
||||
os_log_debug(OS_LOG_DEFAULT, "[DEBUG]%s", message);
|
||||
break;
|
||||
case ll_info:
|
||||
os_log_info(OS_LOG_DEFAULT, "[INFO]%s", message);
|
||||
break;
|
||||
case ll_error:
|
||||
os_log_error(OS_LOG_DEFAULT, "[ERROR]%s", message);
|
||||
break;
|
||||
case ll_fatal:
|
||||
os_log_fault(OS_LOG_DEFAULT, "[FATAL]%s", message);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
#elif defined(_WIN32)
|
||||
#include <Windows.h>
|
||||
void
|
||||
cefView_log(log_level level, const char* message)
|
||||
{
|
||||
std::string msg;
|
||||
switch (level) {
|
||||
case ll_debug:
|
||||
msg = "[DEBUG]";
|
||||
break;
|
||||
case ll_info:
|
||||
msg = "[INFO]";
|
||||
break;
|
||||
case ll_error:
|
||||
msg = "[ERROR]";
|
||||
break;
|
||||
case ll_fatal:
|
||||
msg = "[FATAL]";
|
||||
break;
|
||||
default:
|
||||
msg = "[]";
|
||||
break;
|
||||
}
|
||||
msg += message;
|
||||
msg += "\r\n";
|
||||
OutputDebugStringA(msg.c_str());
|
||||
}
|
||||
#elif defined(__linux__)
|
||||
#include <syslog.h>
|
||||
void
|
||||
cefView_log(log_level level, const char* message)
|
||||
{
|
||||
switch (level) {
|
||||
case ll_debug:
|
||||
syslog(LOG_USER | LOG_DEBUG, "[DEBUG]%s", message);
|
||||
break;
|
||||
case ll_info:
|
||||
syslog(LOG_USER | LOG_INFO, "[INFO]%s", message);
|
||||
break;
|
||||
case ll_error:
|
||||
syslog(LOG_USER | LOG_ERR, "[ERROR]%s", message);
|
||||
break;
|
||||
case ll_fatal:
|
||||
syslog(LOG_USER | LOG_CRIT, "[FATAL]%s", message);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
#else
|
||||
#error "unsupported platform"
|
||||
#endif
|
||||
|
||||
#define LOG_MSG_BUFFER_LIMIT 4096
|
||||
|
||||
void
|
||||
log_debug(const char* fmt, ...)
|
||||
{
|
||||
std::vector<char> msg(LOG_MSG_BUFFER_LIMIT, 0);
|
||||
va_list args;
|
||||
va_start(args, fmt);
|
||||
vsnprintf(msg.data(), LOG_MSG_BUFFER_LIMIT, fmt, args);
|
||||
va_end(args);
|
||||
cefView_log(ll_debug, msg.data());
|
||||
}
|
||||
|
||||
void
|
||||
log_info(const char* fmt, ...)
|
||||
{
|
||||
std::vector<char> msg(LOG_MSG_BUFFER_LIMIT, 0);
|
||||
va_list args;
|
||||
va_start(args, fmt);
|
||||
vsnprintf(msg.data(), LOG_MSG_BUFFER_LIMIT, fmt, args);
|
||||
va_end(args);
|
||||
cefView_log(ll_info, msg.data());
|
||||
}
|
||||
|
||||
void
|
||||
log_error(const char* fmt, ...)
|
||||
{
|
||||
std::vector<char> msg(LOG_MSG_BUFFER_LIMIT, 0);
|
||||
va_list args;
|
||||
va_start(args, fmt);
|
||||
vsnprintf(msg.data(), LOG_MSG_BUFFER_LIMIT, fmt, args);
|
||||
va_end(args);
|
||||
cefView_log(ll_error, msg.data());
|
||||
}
|
||||
|
||||
void
|
||||
log_fatal(const char* fmt, ...)
|
||||
{
|
||||
std::vector<char> msg(LOG_MSG_BUFFER_LIMIT, 0);
|
||||
va_list args;
|
||||
va_start(args, fmt);
|
||||
vsnprintf(msg.data(), LOG_MSG_BUFFER_LIMIT, fmt, args);
|
||||
va_end(args);
|
||||
cefView_log(ll_fatal, msg.data());
|
||||
}
|
||||
@ -1,57 +0,0 @@
|
||||
//
|
||||
// CefViewCoreLog.h
|
||||
// CefViewCore
|
||||
//
|
||||
// Created by Sheen Tian on 2020/6/19.
|
||||
//
|
||||
|
||||
#ifndef CefViewCoreLog_h
|
||||
#define CefViewCoreLog_h
|
||||
#pragma once
|
||||
#include <string>
|
||||
|
||||
void
|
||||
log_debug(const char* fmt, ...);
|
||||
void
|
||||
log_info(const char* fmt, ...);
|
||||
void
|
||||
log_error(const char* fmt, ...);
|
||||
void
|
||||
log_fatal(const char* fmt, ...);
|
||||
|
||||
class ScopeLogger
|
||||
{
|
||||
public:
|
||||
ScopeLogger(const std::string& fn)
|
||||
: functionName_(fn)
|
||||
{
|
||||
// enter scope
|
||||
log_debug("+++ %s", functionName_.c_str());
|
||||
}
|
||||
|
||||
~ScopeLogger()
|
||||
{
|
||||
// leave scope
|
||||
log_debug("--- %s", functionName_.c_str());
|
||||
}
|
||||
|
||||
std::string functionName_;
|
||||
};
|
||||
|
||||
#if (defined(DEBUG) || defined(_DEBUG) || !defined(NDEBUG))
|
||||
// DEBUG BUILD
|
||||
#define logD(format, ...) log_debug(format, ##__VA_ARGS__)
|
||||
#define logI(format, ...) log_info(format, ##__VA_ARGS__)
|
||||
#define logE(format, ...) log_error(format, ##__VA_ARGS__)
|
||||
#define logF(format, ...) log_fatal(format, ##__VA_ARGS__)
|
||||
#define logScope() ScopeLogger __scope_logger__(__FUNCTION__);
|
||||
#else
|
||||
// RELEASE BUILD
|
||||
#define logD(format, ...)
|
||||
#define logI(format, ...) log_info(format, ##__VA_ARGS__)
|
||||
#define logE(format, ...) log_error(format, ##__VA_ARGS__)
|
||||
#define logF(format, ...) log_fatal(format, ##__VA_ARGS__)
|
||||
#define logScope()
|
||||
#endif
|
||||
|
||||
#endif /* CefViewCoreLog_hpp */
|
||||
@ -1,64 +0,0 @@
|
||||
//
|
||||
// CefViewCoreLog.cpp
|
||||
// CefViewCore
|
||||
//
|
||||
// Created by leashi on 2022/5/10.
|
||||
//
|
||||
|
||||
#include <CefViewCoreGlobal.h>
|
||||
|
||||
#include "CefViewDebug.h"
|
||||
|
||||
#include <string>
|
||||
|
||||
std::string
|
||||
toString(CefRefPtr<CefBrowser> browser)
|
||||
{
|
||||
std::string msg;
|
||||
|
||||
msg += "( ";
|
||||
msg += "CefBrowser:";
|
||||
msg += ", ptr=" + std::to_string((int64_t)browser.get());
|
||||
#if CEF_VERSION_MAJOR > 91
|
||||
msg += ", IsValid=" + std::to_string(browser->IsValid());
|
||||
#endif
|
||||
msg += ", GetHost=" + std::to_string((int64_t)browser->GetHost().get());
|
||||
msg += ", CanGoBack=" + std::to_string(browser->CanGoBack());
|
||||
msg += ", CanGoForward=" + std::to_string(browser->CanGoForward());
|
||||
msg += ", IsLoading=" + std::to_string(browser->IsLoading());
|
||||
msg += ", GetIdentifier=" + std::to_string(browser->GetIdentifier());
|
||||
msg += ", IsPopup=" + std::to_string(browser->IsPopup());
|
||||
msg += ", HasDocument=" + std::to_string(browser->HasDocument());
|
||||
msg += ", GetMainFrame=" + std::to_string((int64_t)browser->GetMainFrame().get());
|
||||
msg += ", GetFocusedFrame=" + std::to_string((int64_t)browser->GetFocusedFrame().get());
|
||||
msg += ", GetFrameCount=" + std::to_string(browser->GetFrameCount());
|
||||
msg += " )";
|
||||
|
||||
return msg;
|
||||
}
|
||||
|
||||
std::string
|
||||
toString(CefRefPtr<CefFrame> frame)
|
||||
{
|
||||
std::string msg;
|
||||
|
||||
msg += "( ";
|
||||
msg += "CefFrame:";
|
||||
msg += ", ptr=" + std::to_string((int64_t)frame.get());
|
||||
msg += ", IsValid=" + std::to_string(frame->IsValid());
|
||||
msg += ", IsMain=" + std::to_string(frame->IsMain());
|
||||
msg += ", IsFocused=" + std::to_string(frame->IsFocused());
|
||||
msg += ", GetName=" + frame->GetName().ToString();
|
||||
#if CEF_VERSION_MAJOR < 122
|
||||
msg += ", GetIdentifier=" + std::to_string(frame->GetIdentifier());
|
||||
#else
|
||||
msg += ", GetIdentifier=" + frame->GetIdentifier().ToString();
|
||||
#endif
|
||||
msg += ", GetParent=" + std::to_string((int64_t)frame->GetParent().get());
|
||||
msg += ", GetURL=" + frame->GetURL().ToString();
|
||||
msg += ", GetBrowser=" + std::to_string((int64_t)frame->GetBrowser().get());
|
||||
// msg += ", GetV8Context=" + std::to_string((int64_t)frame->GetV8Context().get());
|
||||
msg += " )";
|
||||
|
||||
return msg;
|
||||
}
|
||||
@ -1,21 +0,0 @@
|
||||
//
|
||||
// CefViewDebug.h
|
||||
// CefViewCore
|
||||
//
|
||||
// Created by leashi on 2022/5/10.
|
||||
//
|
||||
|
||||
#ifndef CefViewDebug_h
|
||||
#define CefViewDebug_h
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <include/cef_browser.h>
|
||||
#include <include/cef_frame.h>
|
||||
|
||||
|
||||
std::string toString(CefRefPtr<CefBrowser> browser);
|
||||
std::string toString(CefRefPtr<CefFrame> frame);
|
||||
|
||||
|
||||
#endif /* CefViewDebug_h */
|
||||
@ -1,52 +0,0 @@
|
||||
#include "DownloadManager.h"
|
||||
|
||||
#include <QDebug>
|
||||
|
||||
DownloadManager&
|
||||
DownloadManager::getInstance()
|
||||
{
|
||||
static DownloadManager s_instance;
|
||||
return s_instance;
|
||||
}
|
||||
|
||||
void
|
||||
DownloadManager::AddNewDownloadItem(const QSharedPointer<QCefDownloadItem>& item)
|
||||
{
|
||||
qDebug() << "DownloadManager::AddNewDownloadItem:"
|
||||
<< " id: " << item->id() << "\n"
|
||||
<< " name: " << item->suggestedFileName() << "\n"
|
||||
<< " path: " << item->fullPath() << "\n"
|
||||
<< " percent: " << item->percentComplete() << "%, " << item->totalBytes() << "/" << item->receivedBytes()
|
||||
<< "\n"
|
||||
<< " canceled: " << item->isCanceled() << "\n"
|
||||
<< " complete: " << item->isComplete();
|
||||
|
||||
m_mapDownloadingItem[item->id()] = item;
|
||||
item->start("", true);
|
||||
}
|
||||
|
||||
void
|
||||
DownloadManager::UpdateDownloadItem(const QSharedPointer<QCefDownloadItem>& item)
|
||||
{
|
||||
qDebug() << "DownloadManager::UpdateDownloadItem:"
|
||||
<< " id: " << item->id() << "\n"
|
||||
<< " name: " << item->suggestedFileName() << "\n"
|
||||
<< " path: " << item->fullPath() << "\n"
|
||||
<< " percent: " << item->percentComplete() << "%, " << item->totalBytes() << "/" << item->receivedBytes()
|
||||
<< "\n"
|
||||
<< " canceled: " << item->isCanceled() << "\n"
|
||||
<< " complete: " << item->isComplete();
|
||||
|
||||
if (item->isCanceled() || item->isComplete())
|
||||
m_mapDownloadingItem.remove(item->id());
|
||||
}
|
||||
|
||||
DownloadManager::DownloadManager() {}
|
||||
|
||||
DownloadManager::~DownloadManager()
|
||||
{
|
||||
for (auto& item : m_mapDownloadingItem) {
|
||||
item->cancel();
|
||||
}
|
||||
m_mapDownloadingItem.clear();
|
||||
}
|
||||
@ -1,26 +0,0 @@
|
||||
#ifndef DOWNLOADMANAGER_H
|
||||
#define DOWNLOADMANAGER_H
|
||||
#pragma once
|
||||
|
||||
#include <QMap>
|
||||
#include <QSharedPointer>
|
||||
|
||||
#include <QCefDownloadItem.h>
|
||||
|
||||
class DownloadManager
|
||||
{
|
||||
public:
|
||||
static DownloadManager& getInstance();
|
||||
|
||||
void AddNewDownloadItem(const QSharedPointer<QCefDownloadItem>& item);
|
||||
|
||||
void UpdateDownloadItem(const QSharedPointer<QCefDownloadItem>& item);
|
||||
|
||||
private:
|
||||
DownloadManager();
|
||||
~DownloadManager();
|
||||
|
||||
QMap<qint32, QSharedPointer<QCefDownloadItem>> m_mapDownloadingItem;
|
||||
};
|
||||
|
||||
#endif
|
||||
@ -1,317 +0,0 @@
|
||||
#include "MainWindow.h"
|
||||
|
||||
#include <QCoreApplication>
|
||||
#include <QDebug>
|
||||
#include <QDir>
|
||||
#include <QHBoxLayout>
|
||||
#include <QJsonDocument>
|
||||
#include <QJsonValue>
|
||||
#include <QMessageBox>
|
||||
#include <QRandomGenerator>
|
||||
|
||||
#include <QCefContext.h>
|
||||
|
||||
#define URL_ROOT "http://QCefViewDoc"
|
||||
#define LEFT_INDEX_URL URL_ROOT "/left.html"
|
||||
#define RIGHT_INDEX_URL URL_ROOT "/right.html"
|
||||
|
||||
MainWindow::MainWindow(QWidget* parent)
|
||||
: QMainWindow(parent /*, Qt::FramelessWindowHint*/)
|
||||
{
|
||||
m_ui.setupUi(this);
|
||||
|
||||
#ifdef Q_OS_MACOS
|
||||
this->m_ui.nativeContainer->setContentsMargins(0, 28, 0, 0);
|
||||
#endif
|
||||
|
||||
setupWindow();
|
||||
// setWindowFlags(Qt::FramelessWindowHint);
|
||||
// setAttribute(Qt::WA_TranslucentBackground);
|
||||
|
||||
connect(m_ui.btn_showDevTools, &QPushButton::clicked, this, &MainWindow::onBtnShowDevToolsClicked);
|
||||
connect(m_ui.btn_reloadRight, &QPushButton::clicked, this, &MainWindow::onBtnReloadRightViewClicked);
|
||||
connect(m_ui.btn_recreateRight, &QPushButton::clicked, this, &MainWindow::onBtnRecreateRightViewClicked);
|
||||
connect(m_ui.btn_changeColor, &QPushButton::clicked, this, &MainWindow::onBtnChangeColorClicked);
|
||||
connect(m_ui.btn_setFocus, &QPushButton::clicked, this, &MainWindow::onBtnSetFocusClicked);
|
||||
connect(m_ui.btn_callJSCode, &QPushButton::clicked, this, &MainWindow::onBtnCallJSCodeClicked);
|
||||
connect(m_ui.btn_newBrowser, &QPushButton::clicked, this, &MainWindow::onBtnNewBrowserClicked);
|
||||
connect(m_ui.btn_quitApp, &QPushButton::clicked, qApp, &QCoreApplication::quit);
|
||||
|
||||
// build the path to the web resource
|
||||
QDir dir = QCoreApplication::applicationDirPath();
|
||||
// #if defined(Q_OS_MACOS)
|
||||
// QString webResourceDir = /*QString("file://") +*/ QDir::toNativeSeparators(dir.filePath("../Resources/webres"));
|
||||
// #else
|
||||
// QString webResourceDir = /*QString("file://") +*/ QDir::toNativeSeparators(dir.filePath("webres"));
|
||||
// #endif
|
||||
|
||||
// // add a local folder to URL map (global)
|
||||
// QCefContext::instance()->addLocalFolderResource(webResourceDir, URL_ROOT);
|
||||
|
||||
createLeftCefView();
|
||||
createRightCefView();
|
||||
}
|
||||
|
||||
MainWindow::~MainWindow() {}
|
||||
|
||||
void
|
||||
MainWindow::createLeftCefView()
|
||||
{
|
||||
if (m_pLeftCefViewWidget) {
|
||||
m_pLeftCefViewWidget->deleteLater();
|
||||
m_pLeftCefViewWidget = nullptr;
|
||||
}
|
||||
|
||||
QCefSetting setting;
|
||||
setting.setWindowlessFrameRate(1000);
|
||||
setting.setHardwareAcceleration(true);
|
||||
setting.setWindowInitialSize(QSize(1000,800));
|
||||
// setting.setBackgroundColor(Qt::magenta);
|
||||
m_pLeftCefViewWidget = new CefViewWidget("https://www.testufo.com/", &setting, this);
|
||||
// connect the invokeMethod to the slot
|
||||
connect(m_pLeftCefViewWidget, &QCefView::invokeMethod, this, &MainWindow::onInvokeMethod);
|
||||
|
||||
// connect the cefQueryRequest to the slot
|
||||
connect(m_pLeftCefViewWidget, &QCefView::cefUrlRequest, this, &MainWindow::onQCefUrlRequest);
|
||||
connect(m_pLeftCefViewWidget, &QCefView::cefQueryRequest, this, &MainWindow::onQCefQueryRequest);
|
||||
connect(m_pLeftCefViewWidget, &QCefView::reportJavascriptResult, this, &MainWindow::onJavascriptResult);
|
||||
connect(m_pLeftCefViewWidget, &QCefView::loadStart, this, &MainWindow::onLoadStart);
|
||||
connect(m_pLeftCefViewWidget, &QCefView::loadEnd, this, &MainWindow::onLoadEnd);
|
||||
connect(m_pLeftCefViewWidget, &QCefView::loadError, this, &MainWindow::onLoadError);
|
||||
|
||||
m_ui.leftCefViewContainer->layout()->addWidget(m_pLeftCefViewWidget);
|
||||
}
|
||||
|
||||
void
|
||||
MainWindow::createRightCefView()
|
||||
{
|
||||
if (m_pRightCefViewWidget) {
|
||||
m_pRightCefViewWidget->deleteLater();
|
||||
m_pRightCefViewWidget = nullptr;
|
||||
}
|
||||
|
||||
// build settings for per QCefView
|
||||
QCefSetting setting;
|
||||
#if CEF_VERSION_MAJOR < 100
|
||||
setting.setPlugins(false);
|
||||
#endif
|
||||
setting.setWindowlessFrameRate(1000);
|
||||
setting.setHardwareAcceleration(true);
|
||||
QColor background(0, 255, 0, 255);
|
||||
setting.setBackgroundColor(background);
|
||||
setting.setWindowInitialSize(QSize(1000,800));
|
||||
// create the QCefView widget and add it to the layout container
|
||||
// m_pRightCefViewWidget = new QCefView(RIGHT_INDEX_URL, &setting, this);
|
||||
m_pRightCefViewWidget = new QCefView("https://www.testufo.com/", &setting, this);
|
||||
|
||||
// auto vl = new QVBoxLayout(m_pRightCefViewWidget);
|
||||
// auto btn = new QPushButton("TEST BUTTON OVERLAY", m_pRightCefViewWidget);
|
||||
//// btn->setFixedSize(320, 240);
|
||||
// btn->setStyleSheet("background-color: rgba(1, 1, 1, 0);");
|
||||
// btn->setAttribute(Qt::WA_TranslucentBackground);
|
||||
// btn->setWindowFlags(Qt::FramelessWindowHint);
|
||||
// btn->setAttribute(Qt::WA_NoSystemBackground);
|
||||
// vl->setAlignment(Qt::AlignVCenter);
|
||||
|
||||
// vl->addWidget(btn);
|
||||
// m_pRightCefViewWidget->setLayout(vl);
|
||||
|
||||
// all the following values will disable the context menu for both NCW and OSR mode
|
||||
// m_pRightCefViewWidget->setContextMenuPolicy(Qt::NoContextMenu);
|
||||
// m_pRightCefViewWidget->setContextMenuPolicy(Qt::ActionsContextMenu);
|
||||
// m_pRightCefViewWidget->setContextMenuPolicy(Qt::CustomContextMenu);
|
||||
// m_pRightCefViewWidget->setContextMenuPolicy(Qt::PreventContextMenu);
|
||||
m_pRightCefViewWidget->setContextMenuPolicy(Qt::DefaultContextMenu);
|
||||
|
||||
// add the QCefView widget to the layout
|
||||
m_ui.rightCefViewContainer->layout()->addWidget(m_pRightCefViewWidget);
|
||||
}
|
||||
|
||||
void
|
||||
MainWindow::onInvokeMethod(const QCefBrowserId& browserId,
|
||||
const QCefFrameId& frameId,
|
||||
const QString& method,
|
||||
const QVariantList& arguments)
|
||||
{
|
||||
// extract the arguments and dispatch the invocation to corresponding handler
|
||||
if (0 == method.compare("TestMethod")) {
|
||||
QString title("QCef InvokeMethod Notify");
|
||||
QString text = QString("================== Current Thread: QT_UI ==================\r\n"
|
||||
"Frame: %1\r\n"
|
||||
"Method: %2\r\n"
|
||||
"Arguments:\r\n")
|
||||
.arg(frameId)
|
||||
.arg(method);
|
||||
|
||||
for (int i = 0; i < arguments.size(); i++) {
|
||||
auto jv = QJsonValue::fromVariant(arguments[i]);
|
||||
|
||||
// clang-format off
|
||||
text.append(
|
||||
QString("%1 Type:%2, Value:%3\r\n")
|
||||
.arg(i).arg(arguments[i].typeName()).arg(arguments[i].toString())
|
||||
);
|
||||
// clang-format on
|
||||
}
|
||||
|
||||
auto jsonValue = QJsonDocument::fromVariant(arguments);
|
||||
auto jsonString = QString(jsonValue.toJson());
|
||||
text.append(QString("\r\nArguments List in JSON format:\r\n%1").arg(jsonString));
|
||||
|
||||
QMessageBox::information(this->window(), title, text);
|
||||
} else {
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
MainWindow::onQCefUrlRequest(const QCefBrowserId& browserId, const QCefFrameId& frameId, const QString& url)
|
||||
{
|
||||
QString title("QCef URL Request");
|
||||
QString text = QString("Current Thread: QT_UI\r\n"
|
||||
"URL: %1")
|
||||
.arg(url);
|
||||
|
||||
QMessageBox::information(this->window(), title, text);
|
||||
}
|
||||
|
||||
void
|
||||
MainWindow::onQCefQueryRequest(const QCefBrowserId& browserId, const QCefFrameId& frameId, const QCefQuery& query)
|
||||
{
|
||||
QString title("QCef Query Request");
|
||||
QString text = QString("Current Thread: QT_UI\r\n"
|
||||
"Query: %1")
|
||||
.arg(query.request());
|
||||
|
||||
QMessageBox::information(this->window(), title, text);
|
||||
|
||||
QString response = query.request().toUpper();
|
||||
query.setResponseResult(true, response);
|
||||
m_pLeftCefViewWidget->responseQCefQuery(query);
|
||||
}
|
||||
|
||||
void
|
||||
MainWindow::onJavascriptResult(const QCefBrowserId& browserId,
|
||||
const QCefFrameId& frameId,
|
||||
const QString& context,
|
||||
const QVariant& result)
|
||||
{
|
||||
auto jsonValue = QJsonDocument::fromVariant(result);
|
||||
auto jsonString = QString(jsonValue.toJson());
|
||||
|
||||
QString title("Javascript result notification");
|
||||
QString text = QString("Context: %1\r\nResult in JSON format:\r\n%2").arg(context).arg(jsonString);
|
||||
|
||||
QMessageBox::information(this->window(), title, text);
|
||||
}
|
||||
|
||||
void
|
||||
MainWindow::onLoadingStateChanged(const QCefBrowserId& browserId, bool isLoading, bool canGoBack, bool canGoForward)
|
||||
{
|
||||
qDebug() << "onLoadingStateChanged, browserId:" << browserId << ", isLoading:" << isLoading
|
||||
<< ", canGoBack:" << canGoBack << ", canGoForward:" << canGoForward;
|
||||
}
|
||||
|
||||
void
|
||||
MainWindow::onLoadStart(const QCefBrowserId& browserId,
|
||||
const QCefFrameId& frameId,
|
||||
bool isMainFrame,
|
||||
int transitionType)
|
||||
{
|
||||
qDebug() << "onLoadStart, browserId:" << browserId << ", frameId:" << frameId << ", isMainFrame:" << isMainFrame
|
||||
<< ", transitionType:" << transitionType;
|
||||
}
|
||||
|
||||
void
|
||||
MainWindow::onLoadEnd(const QCefBrowserId& browserId, const QCefFrameId& frameId, bool isMainFrame, int httpStatusCode)
|
||||
{
|
||||
qDebug() << "onLoadEnd, browserId:" << browserId << ", frameId:" << frameId << ", isMainFrame:" << isMainFrame
|
||||
<< ", httpStatusCode:" << httpStatusCode;
|
||||
}
|
||||
|
||||
void
|
||||
MainWindow::onLoadError(const QCefBrowserId& browserId,
|
||||
const QCefFrameId& frameId,
|
||||
bool isMainFrame,
|
||||
int errorCode,
|
||||
const QString& errorMsg,
|
||||
const QString& failedUrl)
|
||||
{
|
||||
qDebug() << "onLoadError, browserId:" << browserId << ", frameId:" << frameId << ", isMainFrame:" << isMainFrame
|
||||
<< ", errorCode:" << errorCode;
|
||||
}
|
||||
|
||||
void
|
||||
MainWindow::onBtnShowDevToolsClicked()
|
||||
{
|
||||
if (m_pLeftCefViewWidget) {
|
||||
m_pLeftCefViewWidget->showDevTools();
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
MainWindow::onBtnReloadRightViewClicked()
|
||||
{
|
||||
if (m_pRightCefViewWidget) {
|
||||
m_pRightCefViewWidget->navigateToUrl("https://www.google.com");
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
MainWindow::onBtnRecreateRightViewClicked()
|
||||
{
|
||||
createRightCefView();
|
||||
}
|
||||
|
||||
void
|
||||
MainWindow::onBtnChangeColorClicked()
|
||||
{
|
||||
if (m_pLeftCefViewWidget) {
|
||||
// create a random color
|
||||
QColor color(QRandomGenerator::global()->generate());
|
||||
|
||||
// create the cef event and set the arguments
|
||||
QCefEvent event("colorChange");
|
||||
event.arguments().append(QVariant::fromValue(color.name(QColor::HexArgb)));
|
||||
|
||||
// broadcast the event to all frames in all browsers created by this QCefView widget
|
||||
m_pLeftCefViewWidget->broadcastEvent(event);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
MainWindow::onBtnCallJSCodeClicked()
|
||||
{
|
||||
QString context = "helloQCefView";
|
||||
QString code = "alert('hello QCefView'); return {k1: 'str', k2: true, k3: 100};";
|
||||
m_pLeftCefViewWidget->executeJavascriptWithResult(QCefView::MainFrameID, code, "", context);
|
||||
}
|
||||
|
||||
void
|
||||
MainWindow::onBtnSetFocusClicked()
|
||||
{
|
||||
if (m_pLeftCefViewWidget) {
|
||||
m_pLeftCefViewWidget->setFocus();
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
MainWindow::onBtnNewBrowserClicked()
|
||||
{
|
||||
QMainWindow* w = new QMainWindow(nullptr);
|
||||
w->setAttribute(Qt::WA_DeleteOnClose);
|
||||
|
||||
QCefSetting settings;
|
||||
QCefView* view = new QCefView("https://cefview.github.io/QCefView/", &settings, w);
|
||||
|
||||
w->setCentralWidget(view);
|
||||
w->resize(1024, 768);
|
||||
w->show();
|
||||
}
|
||||
|
||||
#ifndef Q_OS_MACOS
|
||||
void
|
||||
MainWindow::setupWindow()
|
||||
{
|
||||
|
||||
}
|
||||
#endif
|
||||
@ -1,77 +0,0 @@
|
||||
#ifndef QCEFVIEWTEST_H
|
||||
#define QCEFVIEWTEST_H
|
||||
|
||||
#include <QCloseEvent>
|
||||
#include <QMainWindow>
|
||||
|
||||
#include "ui_MainWindow.h"
|
||||
|
||||
#include "CefViewWidget.h"
|
||||
|
||||
class MainWindow : public QMainWindow
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
MainWindow(QWidget* parent = 0);
|
||||
~MainWindow();
|
||||
|
||||
protected:
|
||||
void createLeftCefView();
|
||||
void createRightCefView();
|
||||
void setupWindow();
|
||||
|
||||
// QCefView slots
|
||||
protected slots:
|
||||
|
||||
void onInvokeMethod(const QCefBrowserId& browserId,
|
||||
const QCefFrameId& frameId,
|
||||
const QString& method,
|
||||
const QVariantList& arguments);
|
||||
|
||||
void onQCefUrlRequest(const QCefBrowserId& browserId, const QCefFrameId& frameId, const QString& url);
|
||||
|
||||
void onQCefQueryRequest(const QCefBrowserId& browserId, const QCefFrameId& frameId, const QCefQuery& query);
|
||||
|
||||
void onJavascriptResult(const QCefBrowserId& browserId,
|
||||
const QCefFrameId& frameId,
|
||||
const QString& context,
|
||||
const QVariant& result);
|
||||
|
||||
void onLoadingStateChanged(const QCefBrowserId& browserId, bool isLoading, bool canGoBack, bool canGoForward);
|
||||
|
||||
void onLoadStart(const QCefBrowserId& browserId, const QCefFrameId& frameId, bool isMainFrame, int transitionType);
|
||||
|
||||
void onLoadEnd(const QCefBrowserId& browserId, const QCefFrameId& frameId, bool isMainFrame, int httpStatusCode);
|
||||
|
||||
void onLoadError(const QCefBrowserId& browserId,
|
||||
const QCefFrameId& frameId,
|
||||
bool isMainFrame,
|
||||
int errorCode,
|
||||
const QString& errorMsg,
|
||||
const QString& failedUrl);
|
||||
|
||||
// ui slots
|
||||
protected slots:
|
||||
void onBtnShowDevToolsClicked();
|
||||
|
||||
void onBtnReloadRightViewClicked();
|
||||
|
||||
void onBtnRecreateRightViewClicked();
|
||||
|
||||
void onBtnChangeColorClicked();
|
||||
|
||||
void onBtnSetFocusClicked();
|
||||
|
||||
void onBtnCallJSCodeClicked();
|
||||
|
||||
void onBtnNewBrowserClicked();
|
||||
|
||||
private:
|
||||
Ui::MainWindow m_ui;
|
||||
|
||||
QCefView* m_pLeftCefViewWidget = nullptr;
|
||||
QCefView* m_pRightCefViewWidget = nullptr;
|
||||
};
|
||||
|
||||
#endif // QCEFVIEWTEST_H
|
||||
@ -1,250 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>MainWindow</class>
|
||||
<widget class="QMainWindow" name="MainWindow">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>1280</width>
|
||||
<height>900</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>QCefViewTest</string>
|
||||
</property>
|
||||
<widget class="QWidget" name="centralWidget">
|
||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||
<property name="spacing">
|
||||
<number>3</number>
|
||||
</property>
|
||||
<property name="leftMargin">
|
||||
<number>2</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>2</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>2</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>2</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QWidget" name="nativeContainer" native="true">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Fixed" vsizetype="Expanding">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="styleSheet">
|
||||
<string notr="true">
|
||||
#nativeContainer {
|
||||
background-color: rgb(170, 255, 255);
|
||||
}
|
||||
</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_nativeContainer">
|
||||
<property name="spacing">
|
||||
<number>6</number>
|
||||
</property>
|
||||
<property name="leftMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QLabel" name="label">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="styleSheet">
|
||||
<string notr="true">
|
||||
#label{
|
||||
font: 12pt "MS Shell Dlg 2";
|
||||
}
|
||||
</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Native Area</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="btn_showDevTools">
|
||||
<property name="text">
|
||||
<string>Show Left DevTools</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="btn_reloadRight">
|
||||
<property name="text">
|
||||
<string>Reload Right QCefView</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="btn_recreateRight">
|
||||
<property name="text">
|
||||
<string>Recreate Right QCefView</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="btn_changeColor">
|
||||
<property name="text">
|
||||
<string>ChangeColor</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLineEdit" name="lineEdit"/>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="btn_setFocus">
|
||||
<property name="text">
|
||||
<string>SetFocus</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLineEdit" name="lineEdit_2"/>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="btn_callJSCode">
|
||||
<property name="text">
|
||||
<string>CallJSCode</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLineEdit" name="lineEdit_3"/>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="btn_newBrowser">
|
||||
<property name="text">
|
||||
<string>NewBrowser</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="btn_quitApp">
|
||||
<property name="text">
|
||||
<string>Exit App</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="verticalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>20</width>
|
||||
<height>40</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QSplitter" name="splitter">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="frameShadow">
|
||||
<enum>QFrame::Plain</enum>
|
||||
</property>
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<widget class="QWidget" name="leftCefViewContainer" native="true">
|
||||
<property name="styleSheet">
|
||||
<string notr="true">QWidget#leftCefViewContainer {
|
||||
background-color: rgb(217, 183, 255);
|
||||
}</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_cefContainer">
|
||||
<property name="spacing">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="leftMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
</layout>
|
||||
</widget>
|
||||
<widget class="QWidget" name="rightCefViewContainer" native="true">
|
||||
<property name="styleSheet">
|
||||
<string notr="true">QWidget#rightCefViewContainer {
|
||||
background-color: rgb(217, 183, 255);
|
||||
}</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_cefContainer_2">
|
||||
<property name="spacing">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="leftMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
</layout>
|
||||
</widget>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</widget>
|
||||
<layoutdefault spacing="6" margin="11"/>
|
||||
<tabstops>
|
||||
<tabstop>btn_showDevTools</tabstop>
|
||||
<tabstop>btn_reloadRight</tabstop>
|
||||
<tabstop>btn_recreateRight</tabstop>
|
||||
<tabstop>btn_changeColor</tabstop>
|
||||
<tabstop>lineEdit</tabstop>
|
||||
<tabstop>lineEdit_2</tabstop>
|
||||
<tabstop>btn_callJSCode</tabstop>
|
||||
<tabstop>lineEdit_3</tabstop>
|
||||
<tabstop>btn_newBrowser</tabstop>
|
||||
<tabstop>btn_quitApp</tabstop>
|
||||
</tabstops>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
||||
259
src/main.cpp
259
src/main.cpp
@ -7,141 +7,142 @@
|
||||
#include <QApplication>
|
||||
#include <QStandardPaths>
|
||||
#include <QCefContext.h>
|
||||
#include "QCefWidget/MainWindow.h"
|
||||
#include <include/cef_app.h>
|
||||
#include <include/cef_client.h>
|
||||
#include <include/cef_render_handler.h>
|
||||
#include <include/cef_browser.h>
|
||||
// // 自定义 CefApp 类
|
||||
// class CefAppQt : public CefApp, public CefBrowserProcessHandler
|
||||
// {
|
||||
// public:
|
||||
// CefAppQt() {}
|
||||
|
||||
// // 重写 CefApp 方法
|
||||
// CefRefPtr<CefBrowserProcessHandler> GetBrowserProcessHandler() override
|
||||
// {
|
||||
// return this;
|
||||
// }
|
||||
|
||||
// // 重写 CefBrowserProcessHandler 方法
|
||||
// void OnContextInitialized() override
|
||||
// {
|
||||
// CefWindowInfo window_info;
|
||||
// CefBrowserSettings browser_settings;
|
||||
// browser_settings.windowless_frame_rate = 60;
|
||||
// CefBrowserHost::CreateBrowser(window_info, nullptr, "https://html5test.opensuse.org", browser_settings, nullptr, nullptr);
|
||||
// }
|
||||
|
||||
// IMPLEMENT_REFCOUNTING(CefAppQt);
|
||||
// };
|
||||
|
||||
// int main(int argc, char *argv[])
|
||||
// {
|
||||
// HINSTANCE hInstance = GetModuleHandle(NULL);
|
||||
// CefMainArgs main_args(hInstance);
|
||||
|
||||
// // 处理多进程逻辑
|
||||
// CefRefPtr<CefAppQt> app(new CefAppQt);
|
||||
// int exit_code = CefExecuteProcess(main_args, app, nullptr);
|
||||
// if (exit_code >= 0)
|
||||
// {
|
||||
// std::cerr << "exit code:" << exit_code << std::endl;
|
||||
// return exit_code;
|
||||
// }
|
||||
|
||||
// // 初始化 CEF
|
||||
// CefSettings settings;
|
||||
// settings.windowless_rendering_enabled = true;
|
||||
// settings.multi_threaded_message_loop = false;
|
||||
// settings.external_message_pump = false;
|
||||
// settings.no_sandbox = true;
|
||||
|
||||
// // 自定义 root_cache_path
|
||||
// QString cache = QDir::currentPath() + "/usercache";
|
||||
// CefString(&settings.root_cache_path) = cache.toStdString();
|
||||
// if (!CefInitialize(main_args, settings, app, nullptr))
|
||||
// {
|
||||
// std::cerr << "CEF initialization failed." << std::endl;
|
||||
// return 1;
|
||||
// }
|
||||
// std::cout << "init CefWidget" << std::endl;
|
||||
// // 初始化 Qt 应用
|
||||
// QApplication a(argc, argv);
|
||||
// std::cout << "CefRunMessageLoop" << std::endl;
|
||||
// // 运行 CEF 消息循环
|
||||
// CefRunMessageLoop();
|
||||
// std::cout << "CefShutdown" << std::endl;
|
||||
// // 关闭 CEF
|
||||
// CefShutdown();
|
||||
|
||||
// return a.exec();
|
||||
// }
|
||||
|
||||
#include "QCefWidget/CefWidget.h"
|
||||
#define DEBUG_PRINT true
|
||||
void debug_print_argv(int argc, char *argv[])
|
||||
{
|
||||
if(!argc){
|
||||
return;
|
||||
}
|
||||
std::lock_guard<std::mutex> lock(m_mutex);
|
||||
DWORD process_id = GetCurrentProcessId();
|
||||
std::cout << "Process ID:"<<process_id<<" Argvs"<<std::endl;
|
||||
for (int i = 0; i < argc; ++i)
|
||||
{
|
||||
std::cout << "Process ID:"<<process_id<<" Argv:" << i << ": " << argv[i]<<std::endl;
|
||||
}
|
||||
}
|
||||
QString curExeDir(){
|
||||
return QDir::currentPath();
|
||||
}
|
||||
void exsMkDir(QString Dir){
|
||||
if(!QDir(Dir).exists()){
|
||||
QDir().mkdir(Dir);
|
||||
}
|
||||
}
|
||||
bool exeCinfog(int argc,char *argv[]){
|
||||
if(argc<=0){
|
||||
return true;
|
||||
}
|
||||
std::string ex_1="renderer";
|
||||
std::string ex_2="utility";
|
||||
for (int i = 0; i < argc; ++i){
|
||||
std::string arg = argv[i];
|
||||
if (arg.find(ex_1) == std::string::npos||arg.find(ex_2)== std::string::npos){
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
void initConfig(int argc,char *argv[],QCefConfig &config,QString currentDir)
|
||||
{
|
||||
//检测自定义缓存路径
|
||||
exsMkDir(currentDir+"/user");
|
||||
exsMkDir(currentDir+"/user/userCache");
|
||||
//子进程路径和名字,可以利用本进程复用,
|
||||
//Mingw编译下多进程情况需要设置否则程序会退出因为无法拉起子进程
|
||||
if(exeCinfog(argc,argv)){
|
||||
config.setBrowserSubProcessPath(currentDir+"/ctai.exe");
|
||||
}
|
||||
config.setRootCachePath(currentDir+"/user");
|
||||
config.setCachePath(currentDir+"/user/userCache");
|
||||
config.setResourceDirectoryPath(currentDir+"/cef_binary");
|
||||
config.setLocalesDirectoryPath(currentDir+"/cef_binary/locales");
|
||||
//浏览器标识
|
||||
config.setUserAgent("Mozilla/5.0 (Windows NT 10.0; CEF/3.2272.2035) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/41.0.2228.0 SoftwareInformer/1.6.1400");
|
||||
//日志输出级别
|
||||
config.setLogLevel(QCefConfig::LOGSEVERITY_VERBOSE);
|
||||
//桥名字
|
||||
config.setBridgeObjectName("CtaiClient");
|
||||
//内置的协议方案名称
|
||||
config.setBuiltinSchemeName("Ctai");
|
||||
//无窗口渲染模式
|
||||
config.setWindowlessRenderingEnabled(true);
|
||||
//远程Debug端口
|
||||
//config.setRemoteDebuggingPort(9000);
|
||||
//请求头的语言
|
||||
config.setAcceptLanguageList("zh-CN");
|
||||
//允许忽略 localhost 上的 TLS/SSL 错误
|
||||
config.addCommandLineSwitch("allow-insecure-localhost");
|
||||
config.addCommandLineSwitch("ignore-certificate-errors-spki-list");
|
||||
config.addCommandLineSwitch("ignore-ssl-errors");
|
||||
//单进程模式
|
||||
// config.addCommandLineSwitch("single-process");
|
||||
//启用GPU加速
|
||||
config.addCommandLineSwitch("enable-gpu");
|
||||
//GPU加速合成
|
||||
config.addCommandLineSwitch("enable-gpu-compositing");
|
||||
//在进程中使用GPU渲染-开启后只有一个进程
|
||||
config.addCommandLineSwitch("in-process-gpu");
|
||||
//无头模式
|
||||
config.addCommandLineSwitch("headless");
|
||||
//密钥链
|
||||
config.addCommandLineSwitch("use-mock-keychain");
|
||||
//chrome运行时环境
|
||||
config.addCommandLineSwitch("enable-chrome-runtime");
|
||||
//Alloy 风格
|
||||
config.addCommandLineSwitch("use-alloy-style");
|
||||
//离屏渲染
|
||||
config.addCommandLineSwitch("off-screen-rendering-enabled");
|
||||
//网络服务In进程
|
||||
config.addCommandLineSwitchWithValue("enable-features", "NetworkServiceInProcess");
|
||||
//语言
|
||||
config.addCommandLineSwitchWithValue("lang", "zh-CN");
|
||||
//跨域进行远程
|
||||
//config.addCommandLineSwitchWithValue("remote-allow-origins", "*");
|
||||
// 禁用沙盒
|
||||
config.addCommandLineSwitchWithValue("no-sandbox", "ture");
|
||||
//渲染进程限制
|
||||
config.addCommandLineSwitchWithValue("renderer-process-limit", "1");
|
||||
//外部消息循环
|
||||
config.addCommandLineSwitchWithValue("external-message-pump", "false");
|
||||
//多线程消息循环
|
||||
config.addCommandLineSwitchWithValue("multi-threaded-message-loop", "true");
|
||||
}
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
|
||||
QString currentDir=QDir::currentPath();
|
||||
qDebug() << "UI线程ID-1: " << QThread::currentThreadId();
|
||||
if (DEBUG_PRINT)
|
||||
{
|
||||
debug_print_argv(argc, argv);
|
||||
}
|
||||
QApplication a(argc, argv);
|
||||
QCefConfig config;
|
||||
config.setUserAgent("Mozilla/5.0 (Windows NT 10.0; CEF/3.2272.2035) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/41.0.2228.0 SoftwareInformer/1.6.1400");
|
||||
config.setLogLevel(QCefConfig::LOGSEVERITY_VERBOSE);
|
||||
config.setBridgeObjectName("CtaiClient");
|
||||
config.setBuiltinSchemeName("Ctai");
|
||||
config.setWindowlessRenderingEnabled(false);
|
||||
config.setRemoteDebuggingPort(9000);
|
||||
//config.setCachePath(currentDir+"/user/userData");
|
||||
//config.setRootCachePath(currentDir+"/user/userCache");
|
||||
//config.setResourceDirectoryPath(currentDir+"/Resources");
|
||||
//config.setLocalesDirectoryPath(currentDir+"/locales");
|
||||
config.setAcceptLanguageList("zh-CN");
|
||||
config.setBrowserSubProcessPath(currentDir+"/ctai.exe");
|
||||
//config.addCommandLineSwitch("single-process");
|
||||
//config.addCommandLineSwitch("enable-gpu");
|
||||
//config.addCommandLineSwitch("in-process-gpu");
|
||||
//config.addCommandLineSwitch("disable-gpu-compositing");
|
||||
config.addCommandLineSwitch("headless");
|
||||
config.addCommandLineSwitch("use-mock-keychain");
|
||||
config.addCommandLineSwitch("disable-chrome-runtime");
|
||||
config.addCommandLineSwitchWithValue("enable-features","NetworkServiceInProcess");
|
||||
config.addCommandLineSwitchWithValue("log-severity","verbose");
|
||||
config.addCommandLineSwitchWithValue("lang","zh-CN");
|
||||
config.addCommandLineSwitchWithValue("builtin-scheme-name","Ctai");
|
||||
config.addCommandLineSwitchWithValue("bridge-obj-name","CtaiClient");
|
||||
config.addCommandLineSwitchWithValue("pack_loading_disabled","false");
|
||||
//config.addCommandLineSwitchWithValue("user-data-dir","false");
|
||||
//config.addCommandLineSwitchWithValue("log-file","false");
|
||||
config.addCommandLineSwitchWithValue("remote-allow-origins", "*");
|
||||
//禁用沙盒
|
||||
config.addCommandLineSwitchWithValue("no-sandbox","ture");
|
||||
//禁止多线程会话循环(单进程为true,多进程为false);
|
||||
config.addCommandLineSwitchWithValue("renderer-process-limit", "1");
|
||||
config.addCommandLineSwitchWithValue("external-message-pump","false");
|
||||
config.addCommandLineSwitchWithValue("multi-threaded-message-loop","true");
|
||||
//初始化上下文的配置
|
||||
initConfig(argc,argv,config,curExeDir());
|
||||
//初始化浏览器上下文
|
||||
QCefContext cefContext(&a, argc, argv, &config);
|
||||
MainWindow cw;
|
||||
//初始化浏览器
|
||||
CefWidget cw;
|
||||
cw.show();
|
||||
qDebug() << "UI线程ID-2: " << QThread::currentThreadId();
|
||||
// qputenv("QT_QPA_PLATFORM", "windows:fontengine=freetype");
|
||||
// // 加载语言包
|
||||
// QTranslator qtBaseTranslator;
|
||||
// if (!qtBaseTranslator.load(QStringLiteral(":/res/translator/qtbase_zh_CN.qm")))
|
||||
// {
|
||||
// // 处理加载翻译文件失败的情况
|
||||
// qDebug() << "Failed to load translation file.";
|
||||
// return -1;
|
||||
// }
|
||||
// a.installTranslator(&qtBaseTranslator);
|
||||
// // 读取窗体的配置并初始化
|
||||
// sui_init_config();
|
||||
// ctai x;
|
||||
// x.init_layout();
|
||||
// // 仅限于windows平台
|
||||
// #if defined(__WIN32__)
|
||||
// x.title()->set_type(QD_TYPE::QD_EXIT);
|
||||
// #endif
|
||||
// x.show();
|
||||
// qputenv("QT_QPA_PLATFORM", "windows:fontengine=freetype");
|
||||
// // 加载语言包
|
||||
// QTranslator qtBaseTranslator;
|
||||
// if (!qtBaseTranslator.load(QStringLiteral(":/res/translator/qtbase_zh_CN.qm")))
|
||||
// {
|
||||
// // 处理加载翻译文件失败的情况
|
||||
// qDebug() << "Failed to load translation file.";
|
||||
// return -1;
|
||||
// }
|
||||
// a.installTranslator(&qtBaseTranslator);
|
||||
// // 读取窗体的配置并初始化
|
||||
// sui_init_config();
|
||||
// ctai x;
|
||||
// x.init_layout();
|
||||
// // 仅限于windows平台
|
||||
// #if defined(__WIN32__)
|
||||
// x.title()->set_type(QD_TYPE::QD_EXIT);
|
||||
// #endif
|
||||
// x.show();
|
||||
a.exec();
|
||||
qDebug() << "EXIT";
|
||||
return 0;
|
||||
|
||||
Loading…
Reference in New Issue
Block a user