U: Optimized LibLCL library loading

This commit is contained in:
yanghy
2024-12-19 22:58:40 +08:00
parent dd500dcda1
commit beb49919c7
19 changed files with 526 additions and 133 deletions

View File

@@ -13,12 +13,15 @@
package cef
import (
"github.com/energye/energy/v2/cef/config"
"github.com/energye/energy/v2/cef/i18n"
"github.com/energye/energy/v2/cef/internal/def"
"github.com/energye/energy/v2/common"
"github.com/energye/energy/v2/common/imports"
. "github.com/energye/energy/v2/consts"
"github.com/energye/energy/v2/types"
"github.com/energye/golcl/energy/consts"
"github.com/energye/golcl/energy/tools"
"github.com/energye/golcl/lcl/api"
"path/filepath"
"strings"
@@ -80,19 +83,32 @@ func (m *TCEFApplication) initDefaultSettings() {
panic("Unsupported system, currently only supports Windows, Mac OS, and Linux")
}
if m.FrameworkDirPath() == "" {
// 默认CEF框架目录
// 当前执行文件所在目录或ENERGY_HOME环境配置目录
lp := common.FrameworkDir()
if lp != "" {
m.SetFrameworkDirPath(lp)
// 默认 CEF Framework 目录
cfg := config.GetConfig()
if cfg != nil {
libCef := func() string {
if common.IsWindows() {
return "libcef.dll"
} else if common.IsLinux() {
return "libcef.so"
}
return ""
}()
if libCef != "" {
if tools.IsExist(filepath.Join(consts.ExeDir, libCef)) {
m.SetFrameworkDirPath(consts.ExeDir)
} else if frameworkDir := cfg.FrameworkPath(); tools.IsExist(filepath.Join(frameworkDir, libCef)) {
m.SetFrameworkDirPath(frameworkDir)
}
}
}
}
m.SetLocale(LANGUAGE_zh_CN)
m.SetLogSeverity(LOGSEVERITY_DISABLE)
m.SetEnablePrintPreview(true)
//m.SetEnableGPU(true) 默认还是关闭GPU加速
// 以下条件判断根据不同平台, 启动不同的窗口组件
// m.SetEnableGPU(true) 默认还是关闭GPU加速
// DefaultMessageLoop() 根据不同平台, 启动不同的窗口组件
// ViewsFrameworkBrowserWindow 简称(VF)窗口组件, 同时支持 Windows/Linux/MacOSX
// LCL 窗口组件,同时支持 Windows/MacOSX, CEF版本<=106.xx时支持GTK2, CEF版本 >= 107.xx时默认开启 GTK3 且不支持 GTK2 和 LCL提供的各种组件
m.DefaultMessageLoop()
@@ -168,7 +184,6 @@ func (m *TCEFApplication) FrameworkDirPath() string {
}
func (m *TCEFApplication) SetFrameworkDirPath(value string) {
common.SetFrameworkEnv(value)
imports.Proc(def.CEFAppConfig_SetFrameworkDirPath).Call(api.PascalStr(value))
// resources 和 locals 在同一目录
m.SetResourcesDirPath(value)

View File

@@ -242,5 +242,5 @@ func dragExtensionJS(frame *ICefFrame, window IBrowserWindow) {
// 2. 通过IPC将鼠标消息发送到主进程主进程监听到消息处理鼠标事件
// 3. macos 使用窗口坐标实现窗口拖拽
func registerDragExtensionHandler() {
RegisterExtension("__drag", string(ipc.IPCJS), nil)
RegisterExtension("__drag", ipc.IPCJS, nil)
}

22
cef/config/config.go Normal file
View File

@@ -0,0 +1,22 @@
//----------------------------------------
//
// Copyright © yanghy. All Rights Reserved.
//
// Licensed under Apache License Version 2.0, January 2004
//
// https://www.apache.org/licenses/LICENSE-2.0
//
//----------------------------------------
package config
var config *Config
type Config struct {
Root string `json:"root"`
Framework string `json:"framework"`
}
func GetConfig() *Config {
return config
}

46
cef/config/config_dev.go Normal file
View File

@@ -0,0 +1,46 @@
//----------------------------------------
//
// Copyright © yanghy. All Rights Reserved.
//
// Licensed under Apache License Version 2.0, January 2004
//
// https://www.apache.org/licenses/LICENSE-2.0
//
//----------------------------------------
//go:build !prod
// +build !prod
package config
import (
"encoding/json"
"github.com/energye/energy/v2/consts"
"io/ioutil"
"path/filepath"
)
func init() {
homeDIR := consts.HomeDir
if homeDIR == "" {
println("Warning, failed to obtain the current user directory.")
} else {
filePath := filepath.Join(homeDIR, ".energy")
energyConfig, err := ioutil.ReadFile(filePath)
if err != nil {
println("Read .energy Error:", err.Error())
return
}
tempConfig := &Config{}
err = json.Unmarshal(energyConfig, tempConfig)
if err != nil {
println("Parsing .energy file Error:", err.Error())
return
}
config = tempConfig
}
}
func (m *Config) FrameworkPath() string {
return filepath.Join(m.Root, "energy", m.Framework)
}

26
cef/config/config_prod.go Normal file
View File

@@ -0,0 +1,26 @@
//----------------------------------------
//
// Copyright © yanghy. All Rights Reserved.
//
// Licensed under Apache License Version 2.0, January 2004
//
// https://www.apache.org/licenses/LICENSE-2.0
//
//----------------------------------------
//go:build prod
// +build prod
package config
import (
"github.com/energye/energy/v2/consts"
)
func init() {
config = &Config{Framework: consts.ExeDir}
}
func (m *Config) FrameworkPath() string {
return m.Framework
}

View File

@@ -14,17 +14,11 @@ package cef
import (
_ "github.com/energye/energy/v2/cef/internal/def"
"github.com/energye/energy/v2/cef/internal/initialize"
. "github.com/energye/energy/v2/cef/process"
. "github.com/energye/energy/v2/common"
"github.com/energye/energy/v2/common/imports"
"github.com/energye/energy/v2/common/imports/tempdll"
"github.com/energye/golcl/energy/emfs"
"github.com/energye/golcl/energy/inits"
"github.com/energye/golcl/lcl"
"github.com/energye/golcl/lcl/api"
"github.com/energye/golcl/lcl/api/dllimports"
"github.com/energye/golcl/pkgs/libname"
"github.com/energye/golcl/pkgs/macapp"
"os"
)
@@ -35,76 +29,8 @@ import (
// 参数:
// libs 内置到应用程序的类库
// resources 内置到应用程序的资源文件
//
// MacOS开发环境需命令行参数[env=dev]以正常运行
func GlobalInit(libs emfs.IEmbedFS, resources emfs.IEmbedFS) {
if IsDarwin() {
macapp.MacApp.IsCEF(true)
//MacOSX环境, ide开发环境需命令行参数[energy_env=dev]以保证应用正常运行
var env = func() string {
energyEnv, env := Args.Args("energy_env"), Args.Args("env")
if energyEnv != "" {
return energyEnv
}
if env != "" {
return env
}
return ""
}()
if env != "" {
macapp.MacApp.SetEnergyEnv(macapp.ENERGY_ENV(env))
}
}
// lcl 初始化时回调如果设置了该回调函数需要通过该函数返回liblcl库
api.SetLoadLibCallback(func() (liblcl dllimports.DLL, err error) {
// load liblcl
// liblcl name, 不为空时表示自定义加载目录
if libname.LibName == "" {
// 如果使用内置dll编译,则通过该方式加载动态库
path, fullPath, ok := tempdll.CheckAndReleaseDLL(libname.GetDLLName())
if ok {
libname.LibName = fullPath
// 设置到tempDllDir, 使用tempdll将最优先从该目录加载
libname.SetTempDllDir(path)
}
}
if IsDarwin() { // MacOS固定加载目录
//MacOSX从Frameworks加载
libname.LibName = "@executable_path/../Frameworks/" + libname.GetDLLName()
} else if libname.LibName == "" {
libname.LibName = libname.LibPath(libname.GetDLLName())
}
if libname.LibName != "" {
liblcl, err = dllimports.NewDLL(libname.LibName)
}
if liblcl == 0 {
if err != nil {
println("LoadLibrary liblcl ERROR:", err.Error())
}
panic(`Hint:
Golcl dependency library liblcl was not found
Please check whether liblcl exists locally
If local liblcl exist, please put it in the specified location, If it does not exist, please download it from the Energy official website.
Configuration Location:
1. Current program execution directory
2. USER_HOME/golcl/
3. Environment variables LCL_HOME or ENERGY_HOME
environment variable LCL_HOME is configured preferentially in the non-energy framework
environment variable ENERGY_HOME takes precedence in the Energy framework
ENERGY_HOME environment variable is recommended
`)
}
// 加载完成设置到libenergy全局
imports.LibEnergy().SetOk(true)
imports.LibEnergy().SetDll(liblcl)
imports.LibLCLExt().SetOk(true)
imports.LibLCLExt().SetDll(liblcl)
return
})
emfs.SetEMFS(libs, resources)
// go lcl init
inits.InitAll()
initialize.Initialize(libs, resources)
// macos command line
if IsDarwin() {
argsList := lcl.NewStringList()

View File

@@ -0,0 +1,23 @@
// ----------------------------------------
//
// Copyright © yanghy. All Rights Reserved.
//
// # Licensed under Apache License Version 2.0, January 2004
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// ----------------------------------------
// Package Application environment initialization loads dynamic libraries
package initialize
import (
"github.com/energye/golcl/energy/emfs"
)
// Initialize
// 初始化,运行时加载 LibLCL
func Initialize(libs emfs.IEmbedFS, resources emfs.IEmbedFS) {
loadLibLCL(libs, resources)
}

View File

@@ -0,0 +1,94 @@
// ----------------------------------------
//
// Copyright © yanghy. All Rights Reserved.
//
// # Licensed under Apache License Version 2.0, January 2004
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// ----------------------------------------
//go:build !prod
// +build !prod
package initialize
import (
"github.com/energye/energy/v2/cef/config"
"github.com/energye/energy/v2/common"
"github.com/energye/energy/v2/common/imports"
"github.com/energye/energy/v2/consts"
"github.com/energye/golcl/energy/emfs"
"github.com/energye/golcl/energy/inits"
"github.com/energye/golcl/energy/tools"
"github.com/energye/golcl/lcl/api"
"github.com/energye/golcl/lcl/api/dllimports"
"github.com/energye/golcl/pkgs/libname"
"github.com/energye/golcl/pkgs/macapp"
"path"
"path/filepath"
)
// 开发环境加载 libLCL在程序启动后读取用户目录 .energy 配置文件
// 不同操作系统加载方式也不同
// 优先级: 1. 自定义, 2. 当前执行目录, 3. .energy 配置文件, 4. 相对目录
// .energy 配置文件 root 字段是 energy 框架所在根目录, framework 字段是当前正在使用的 CEF Framework
// 获得一个完整目录 [root]+energy+[framework]
func loadLibLCL(libs emfs.IEmbedFS, resources emfs.IEmbedFS) {
if common.IsDarwin() {
macapp.MacApp.IsCEF(true)
macapp.MacApp.SetEnergyEnv("dev")
}
// LCL 初始化时回调, 返回 lib 地址
api.SetLoadLibCallback(func() (liblcl dllimports.DLL, err error) {
libPath := libname.LibName
if libPath != "" {
// 自定义加载目录
liblcl, err = dllimports.NewDLL(libPath)
} else if common.IsDarwin() {
// MacOS 固定加载目录
libPath = "@executable_path/../Frameworks/" + libname.GetDLLName()
} else {
// Windows, Linux
// 优先当前执行目录
currentPathLibPath := path.Join(consts.ExeDir, libname.GetDLLName())
if tools.IsExist(currentPathLibPath) {
libPath = currentPathLibPath
} else {
// 开发环境配置目录
if config.GetConfig() != nil {
libPath = filepath.Join(config.GetConfig().FrameworkPath(), libname.GetDLLName())
} else {
// 最后尝试相对目录
libPath = libname.GetDLLName()
}
}
}
// 加载 LibLCL
if libPath != "" {
libname.LibName = libPath
liblcl, err = dllimports.NewDLL(libPath)
}
if liblcl == 0 {
if err != nil {
println("Load LibLCL Error:", err.Error())
}
println("LibLCL Path:", libname.LibName)
panic(`Hint:
Failed initialize LibLCL, check the development environment
Use CLI:
"energy env" : Check the configuration of the development environment
"energy install" : Installation development environment
`)
} else {
imports.LibEnergy().SetOk(true)
imports.LibEnergy().SetDll(liblcl)
imports.LibLCLExt().SetOk(true)
imports.LibLCLExt().SetDll(liblcl)
}
return
})
emfs.SetEMFS(libs, resources)
// go lcl init
inits.InitAll()
}

View File

@@ -0,0 +1,75 @@
//----------------------------------------
//
// Copyright © yanghy. All Rights Reserved.
//
// Licensed under Apache License Version 2.0, January 2004
//
// https://www.apache.org/licenses/LICENSE-2.0
//
//----------------------------------------
//go:build prod
// +build prod
package initialize
import (
"github.com/energye/energy/v2/common"
"github.com/energye/energy/v2/common/imports"
"github.com/energye/energy/v2/consts"
"github.com/energye/golcl/energy/emfs"
"github.com/energye/golcl/energy/inits"
"github.com/energye/golcl/energy/tools"
"github.com/energye/golcl/lcl/api"
"github.com/energye/golcl/lcl/api/dllimports"
"github.com/energye/golcl/pkgs/libname"
"path"
)
// 发布环境加载 libLCL不再依赖 .energy 配置文件
// 优先级: 1. 自定义, 2. 当前执行目录, 3. 相对目录
// 不同操作系统加载方式也不同
func loadLibLCL(libs emfs.IEmbedFS, resources emfs.IEmbedFS) {
// LCL 初始化时回调, 返回 lib 地址
api.SetLoadLibCallback(func() (liblcl dllimports.DLL, err error) {
libPath := libname.LibName
if libPath != "" {
// 自定义加载目录
liblcl, err = dllimports.NewDLL(libPath)
} else if common.IsDarwin() {
// MacOS 固定加载目录
libPath = "@executable_path/../Frameworks/" + libname.GetDLLName()
} else {
// Windows, Linux
// 优先当前执行目录
currentPathLibPath := path.Join(consts.ExeDir, libname.GetDLLName())
if tools.IsExist(currentPathLibPath) {
libPath = currentPathLibPath
} else {
// 最后尝试相对目录
libPath = libname.GetDLLName()
}
}
// 加载 LibLCL
if libPath != "" {
libname.LibName = libPath
liblcl, err = dllimports.NewDLL(libPath)
}
if liblcl == 0 {
if err != nil {
println("Load LibLCL Error:", err.Error())
}
println("LibLCL Path:", libname.LibName)
panic(`Failed initialize LibLCL`)
} else {
imports.LibEnergy().SetOk(true)
imports.LibEnergy().SetDll(liblcl)
imports.LibLCLExt().SetOk(true)
imports.LibLCLExt().SetDll(liblcl)
}
return
})
emfs.SetEMFS(libs, resources)
// go lcl init
inits.InitAll()
}

View File

@@ -0,0 +1,17 @@
// ----------------------------------------
//
// Copyright © yanghy. All Rights Reserved.
//
// # Licensed under Apache License Version 2.0, January 2004
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// ----------------------------------------
//go:build darwin
// +build darwin
package initialize
func dll() string {
return ""
}

View File

@@ -0,0 +1,17 @@
// ----------------------------------------
//
// Copyright © yanghy. All Rights Reserved.
//
// # Licensed under Apache License Version 2.0, January 2004
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// ----------------------------------------
//go:build linux
// +build linux
package initialize
func dll() string {
return ""
}

View File

@@ -0,0 +1,17 @@
// ----------------------------------------
//
// Copyright © yanghy. All Rights Reserved.
//
// # Licensed under Apache License Version 2.0, January 2004
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// ----------------------------------------
//go:build windows
// +build windows
package initialize
func dll() string {
return ""
}

View File

@@ -27,9 +27,6 @@ import (
"time"
)
//go:embed ipc.js
var IPCJS []byte
var (
isMainProcess bool
isSubProcess bool

142
cef/internal/ipc/ipc.js.go Normal file
View File

@@ -0,0 +1,142 @@
//----------------------------------------
//
// Copyright © yanghy. All Rights Reserved.
//
// Licensed under Apache License Version 2.0, January 2004
//
// https://www.apache.org/licenses/LICENSE-2.0
//
//----------------------------------------
package ipc
var IPCJS = `
let __drag;
if (!__drag) {
__drag = {
cssDragProperty: "-webkit-app-region",
cssDragValue: "drag",
os: null,
enableResize: true,
};
}
(function () {
let shouldDrag = false;
let idcCursor = null;
let frameWidth = 4;
let frameHeight = 4;
let frameCorner = 8;
function isWindows() {
return __drag.os === "windows";
}
function isDarwin() {
return __drag.os === "darwin";
}
function isLinux() {
return __drag.os === "linux";
}
function setCursor(cursor, ht) {
if (idcCursor !== cursor) {
document.documentElement.style.cursor = cursor || 'auto';
idcCursor = cursor;
}
}
function enableResize() {
return __drag.enableResize;
}
function mouseDragResize(e) {
let leftBorder = e.clientX < frameWidth;
let topBorder = e.clientY < frameHeight;
let rightBorder = window.outerWidth - e.clientX < frameWidth;
let bottomBorder = window.outerHeight - e.clientY < frameHeight;
let leftCorner = e.clientX < frameWidth + frameCorner;
let topCorner = e.clientY < frameHeight + frameCorner;
let rightCorner = window.outerWidth - e.clientX < frameWidth + frameCorner;
let bottomCorner = window.outerHeight - e.clientY < frameHeight + frameCorner;
if (!leftBorder && !topBorder && !rightBorder && !bottomBorder && idcCursor !== void 0) {
setCursor();
} else if (rightCorner && bottomCorner) {
setCursor("se-resize", 17);
} else if (leftCorner && bottomCorner) {
setCursor("sw-resize", 16);
} else if (leftCorner && topCorner) {
setCursor("nw-resize", 13);
} else if (topCorner && rightCorner) {
setCursor("ne-resize", 14);
} else if (leftBorder) {
setCursor("w-resize", 10);
} else if (topBorder) {
setCursor("n-resize", 12);
} else if (bottomBorder) {
setCursor("s-resize", 15);
} else if (rightBorder) {
setCursor("e-resize", 11);
}
}
function test(e) {
let v = window.getComputedStyle(e.target)[__drag.cssDragProperty];
if (v) {
v = v.trim();
if (v !== __drag.cssDragValue) {
return false;
}
return e.detail === 1 || e.detail === 2;
}
return false;
}
function mouseMove(e) {
if (shouldDrag) {
if (isWindows() || isDarwin()) {
shouldDrag = false;// && !IsDarwin();
}
energyExtension.mouseMove({x: e.screenX, y: e.screenY, ts: parseInt(e.timeStamp)});
} else if (enableResize() && isWindows()) {
mouseDragResize(e);
}
}
function mouseUp(e) {
shouldDrag = false;
}
function mouseDown(e) {
if (enableResize() && idcCursor) {
e.preventDefault();
energyExtension.mouseResize(idcCursor);
} else if (!(e.offsetX > e.target.clientWidth || e.offsetY > e.target.clientHeight) && test(e)) {
shouldDrag = true;
energyExtension.mouseDown({x: e.screenX, y: e.screenY, ts: parseInt(e.timeStamp)});
} else {
shouldDrag = false;
}
}
function dblClick(e) {
if (test(e)) {
e.preventDefault();
energyExtension.mouseDblClick();
}
}
__drag.setup = function () {
window.addEventListener("mousemove", mouseMove);
window.addEventListener("mousedown", mouseDown);
window.addEventListener("mouseup", mouseUp);
window.addEventListener("dblclick", dblClick);
}
/**
* 在JS里判断 x y 点是否在指定区域,以下步骤
* 1. CreateRectRgn(x, y, x+w, y+h) 创建一个区域 x, y, w, h
* 2. CreateRectRgn 创建当前区域
* 3. CombineRgn 合并区域
* 4. PtInRegion(rgn, x, y) 检查点是否在区域
*/
})();
`

View File

@@ -6,4 +6,16 @@
go install github.com/energye/energy/v2/cmd/energy
```
https://energye.github.io/course/cli-use-instructions
https://energye.github.io/course/cli-use-instructions
macos:
```
brew install nsis
brew install llvm
```
ubuntu:
```
sudo apt install nsis
sudo apt install lld llvm
```

View File

@@ -15,12 +15,8 @@ import (
"bytes"
"encoding/binary"
"fmt"
"github.com/energye/energy/v2/consts"
"github.com/energye/energy/v2/pkgs/decimal"
"github.com/energye/golcl/energy/tools"
"math"
"os"
"path/filepath"
"reflect"
"runtime"
"strconv"
@@ -543,6 +539,7 @@ func GoStr(ptr uintptr) string {
return *(*string)(unsafe.Pointer(resultString))
}
func string2bytes1(s string) []byte {
stringHeader := (*reflect.StringHeader)(unsafe.Pointer(&s))
var b []byte
@@ -552,36 +549,3 @@ func string2bytes1(s string) []byte {
pbytes.Cap = stringHeader.Len
return b
}
func libCef() string {
if IsWindows() {
return "libcef.dll"
} else if IsLinux() {
return "libcef.so"
}
return ""
}
// FrameworkDir
// 返回CEF框架目录, 以当前执行文件所在目录开始查找
// 如果当前执行文件目录未找到再从ENERGY_HOME环境变量查找
// Darwin 平台除外
func FrameworkDir() string {
var lib = libCef() // 根据CEF libcef.xx 动态库
if lib != "" {
//当前目录
if tools.IsExist(filepath.Join(consts.ExeDir, lib)) {
return consts.ExeDir
}
//环境变量
var env = os.Getenv(consts.ENERGY_HOME_KEY)
if tools.IsExist(filepath.Join(env, lib)) {
return env
}
}
return ""
}
func SetFrameworkEnv(value string) {
os.Setenv(consts.ENERGY_HOME_KEY, value)
}

View File

@@ -27,7 +27,8 @@ func init() {
}
// CheckAndReleaseDLL
// 检查动态库并释放
//
// 检查动态库并释放
func CheckAndReleaseDLL(dllName string) (filePath string, fileFullPath string, ok bool) {
if TempDLL == nil || TempDLL.DllSaveDirType() == TddInvalid || emfs.GetLibsFS() == nil {
return
@@ -45,7 +46,7 @@ func CheckAndReleaseDLL(dllName string) (filePath string, fileFullPath string, o
case TddCurrent:
tempDLLDir = consts.ExeDir
case TddEnergyHome:
tempDLLDir = os.Getenv(consts.ENERGY_HOME_KEY)
//tempDLLDir = os.Getenv(consts.ENERGY_HOME_KEY)// TODO
case TddCustom:
if TempDLL.DllSaveDir() != "" {
tempDLLDir = TempDLL.DllSaveDir()

View File

@@ -29,11 +29,6 @@ var (
Separator = string(filepath.Separator) // 平台目录分隔符
)
const (
ENERGY_HOME_KEY = "ENERGY_HOME"
MemoryNetwork = "unix"
)
func init() {
CurrentExecuteDir, _ = os.Getwd()
ExePath = os.Args[0]

View File

@@ -32,6 +32,10 @@ import (
"strings"
)
const (
MemoryNetwork = "unix"
)
var (
protocolHeader = []byte{0x01, 0x09, 0x08, 0x07, 0x00, 0x08, 0x02, 0x02} // 协议头
protocolHeaderLength = int32(len(protocolHeader)) // 协议头长度