mirror of
https://github.com/xiaoqidun/ofdgo.git
synced 2026-10-30 01:27:26 +08:00
1 parent
1c576bde18
commit
1de949abfc
8 files changed
+210
-18
No files matched your search
+31
-3
@@ -2631,7 +2631,15 @@ async function closeWorkspace() {
|
|||||||
async function closeApplicationWindow() {
|
async function closeApplicationWindow() {
|
||||||
window.removeEventListener("beforeunload", warnUnsaved);
|
window.removeEventListener("beforeunload", warnUnsaved);
|
||||||
window.removeEventListener("beforeunload", warnBatch);
|
window.removeEventListener("beforeunload", warnBatch);
|
||||||
await nativeHost.call("window.close", {});
|
let closed = false;
|
||||||
|
try {
|
||||||
|
closed = await nativeHost.call("window.close", {});
|
||||||
|
} finally {
|
||||||
|
if (!closed) {
|
||||||
|
window.addEventListener("beforeunload", warnUnsaved);
|
||||||
|
window.addEventListener("beforeunload", warnBatch);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function createDocumentTab(value = createDocumentState()) {
|
function createDocumentTab(value = createDocumentState()) {
|
||||||
@@ -2847,19 +2855,21 @@ async function activateDocumentTab(tab, closing = false) {
|
|||||||
if (workspace.switching) { workspace.nextTab = tab; return false; }
|
if (workspace.switching) { workspace.nextTab = tab; return false; }
|
||||||
const focused = el.documentTitleBar.contains(document.activeElement);
|
const focused = el.documentTitleBar.contains(document.activeElement);
|
||||||
workspace.switching = true;
|
workspace.switching = true;
|
||||||
|
try {
|
||||||
try {
|
try {
|
||||||
if (!documentTab().busy && !await commitDocumentView()) return false;
|
if (!documentTab().busy && !await commitDocumentView()) return false;
|
||||||
detachDocumentView();
|
detachDocumentView();
|
||||||
attachDocumentTab(tab);
|
attachDocumentTab(tab);
|
||||||
if (focused) el.documentTabs.querySelector('[data-selected="true"]')?.focus({preventScroll: true});
|
if (focused) el.documentTabs.querySelector('[data-selected="true"]')?.focus({preventScroll: true});
|
||||||
|
} finally {
|
||||||
workspace.switching = false;
|
workspace.switching = false;
|
||||||
|
}
|
||||||
await mountDocumentTab(tab);
|
await mountDocumentTab(tab);
|
||||||
return true;
|
return true;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
if (isForegroundDocument(tab)) showError(error, !state.doc);
|
if (isForegroundDocument(tab)) showError(error, !state.doc);
|
||||||
return false;
|
return false;
|
||||||
} finally {
|
} finally {
|
||||||
if (workspace.active === tab) workspace.switching = false;
|
|
||||||
const next = workspace.nextTab;
|
const next = workspace.nextTab;
|
||||||
workspace.nextTab = null;
|
workspace.nextTab = null;
|
||||||
if (next && next !== workspace.active && !next.closed) queueMicrotask(() => activateDocumentTab(next));
|
if (next && next !== workspace.active && !next.closed) queueMicrotask(() => activateDocumentTab(next));
|
||||||
@@ -5163,7 +5173,25 @@ async function boot() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async function openNativeFiles(files) {
|
async function openNativeDocument(file) {
|
||||||
|
let retained = false;
|
||||||
|
try {
|
||||||
|
retained = await openOFD(file);
|
||||||
|
} catch (error) {
|
||||||
|
showError(error, !state.doc);
|
||||||
|
} finally {
|
||||||
|
if (!retained) await nativeHost.discardFiles([file]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function openNativeFiles(files, launch = false) {
|
||||||
|
if (launch) {
|
||||||
|
for (const file of files) {
|
||||||
|
while (workspace.closing || workspace.switching || batchElements.Panel.open || documentDialogs?.applicationOpen()) await new Promise(resolve => setTimeout(resolve, 100));
|
||||||
|
void openNativeDocument(file).catch(error => showError(error, !state.doc));
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
let retained = [];
|
let retained = [];
|
||||||
try {
|
try {
|
||||||
if (workspace.closing || batchElements.Panel.open && batch.running) { setStatus("请等待当前操作完成"); return; }
|
if (workspace.closing || batchElements.Panel.open && batch.running) { setStatus("请等待当前操作完成"); return; }
|
||||||
|
|||||||
@@ -726,6 +726,13 @@ class NativeHost {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async start(onFiles, onError) {
|
async start(onFiles, onError) {
|
||||||
|
let launching = Promise.resolve();
|
||||||
|
this.bridge.on("ofdgo.launch", values => {
|
||||||
|
launching = launching.then(async () => {
|
||||||
|
try { await onFiles(values.map(value => new NativeFile(value)), true); }
|
||||||
|
finally { await this.call("launch.done", {}); }
|
||||||
|
}).catch(onError);
|
||||||
|
});
|
||||||
this.bridge.on("ofdgo.files", async values => {
|
this.bridge.on("ofdgo.files", async values => {
|
||||||
try { await onFiles(values.map(value => new NativeFile(value))); }
|
try { await onFiles(values.map(value => new NativeFile(value))); }
|
||||||
catch (error) { onError(error); }
|
catch (error) { onError(error); }
|
||||||
|
|||||||
@@ -8,12 +8,13 @@ require (
|
|||||||
github.com/go-text/typesetting v0.3.5
|
github.com/go-text/typesetting v0.3.5
|
||||||
github.com/tdewolff/canvas v0.0.0-20260923214215-09804640d00c
|
github.com/tdewolff/canvas v0.0.0-20260923214215-09804640d00c
|
||||||
github.com/tdewolff/font v0.0.0-20261010204837-88a7f6b56918
|
github.com/tdewolff/font v0.0.0-20261010204837-88a7f6b56918
|
||||||
github.com/xiaoqidun/guigo v0.0.0-20261025075751-73659d2a5eba
|
github.com/xiaoqidun/guigo v0.0.0-20261025093134-18d57dc4973b
|
||||||
github.com/xiaoqidun/j2kgo v1.0.2
|
github.com/xiaoqidun/j2kgo v1.0.2
|
||||||
github.com/xiaoqidun/jbig2 v1.1.8
|
github.com/xiaoqidun/jbig2 v1.1.8
|
||||||
github.com/xiaoqidun/pdfgo v0.0.0-20261023171626-3473b442eed5
|
github.com/xiaoqidun/pdfgo v0.0.0-20261023171626-3473b442eed5
|
||||||
golang.org/x/crypto v0.58.0
|
golang.org/x/crypto v0.58.0
|
||||||
golang.org/x/image v0.47.0
|
golang.org/x/image v0.47.0
|
||||||
|
golang.org/x/sys v0.49.0
|
||||||
golang.org/x/text v0.43.0
|
golang.org/x/text v0.43.0
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -35,7 +36,6 @@ require (
|
|||||||
github.com/tdewolff/parse/v2 v2.8.16 // indirect
|
github.com/tdewolff/parse/v2 v2.8.16 // indirect
|
||||||
github.com/yuin/goldmark v1.8.5 // indirect
|
github.com/yuin/goldmark v1.8.5 // indirect
|
||||||
golang.org/x/net v0.60.0 // indirect
|
golang.org/x/net v0.60.0 // indirect
|
||||||
golang.org/x/sys v0.49.0 // indirect
|
|
||||||
modernc.org/knuth v0.6.0 // indirect
|
modernc.org/knuth v0.6.0 // indirect
|
||||||
modernc.org/token v1.1.0 // indirect
|
modernc.org/token v1.1.0 // indirect
|
||||||
star-tex.org/x/tex v0.7.1 // indirect
|
star-tex.org/x/tex v0.7.1 // indirect
|
||||||
|
|||||||
@@ -60,8 +60,8 @@ github.com/tdewolff/parse/v2 v2.8.16 h1:bLk5svUOQRkW/Y2SJ+DeENSIkZBcTIkq+Atyv5D8
|
|||||||
github.com/tdewolff/parse/v2 v2.8.16/go.mod h1:XdsoSFThlVIRIajAuqz1evNY7bagZS8LBOPA3aVopwQ=
|
github.com/tdewolff/parse/v2 v2.8.16/go.mod h1:XdsoSFThlVIRIajAuqz1evNY7bagZS8LBOPA3aVopwQ=
|
||||||
github.com/tdewolff/test v1.0.12 h1:7F21DqIajswxuche0geHdrUZRCWE4oko4b7bcmkkrxk=
|
github.com/tdewolff/test v1.0.12 h1:7F21DqIajswxuche0geHdrUZRCWE4oko4b7bcmkkrxk=
|
||||||
github.com/tdewolff/test v1.0.12/go.mod h1:XPuWBzvdUzhCuxWO1ojpXsyzsA5bFoS3tO/Q3kFuTG8=
|
github.com/tdewolff/test v1.0.12/go.mod h1:XPuWBzvdUzhCuxWO1ojpXsyzsA5bFoS3tO/Q3kFuTG8=
|
||||||
github.com/xiaoqidun/guigo v0.0.0-20261025075751-73659d2a5eba h1:8gQ9K2aIpYl72TdPAYWDju4YDhkrc3EyqIapWJd0AO8=
|
github.com/xiaoqidun/guigo v0.0.0-20261025093134-18d57dc4973b h1:GlNcsrDSkahmjrQdA/q5yjkM5qWQw7pOBqY1qv625tU=
|
||||||
github.com/xiaoqidun/guigo v0.0.0-20261025075751-73659d2a5eba/go.mod h1:bXz+dPMVntPIVwePTTuMXt8Q0z1YoUGuROQSsXyUEfY=
|
github.com/xiaoqidun/guigo v0.0.0-20261025093134-18d57dc4973b/go.mod h1:bXz+dPMVntPIVwePTTuMXt8Q0z1YoUGuROQSsXyUEfY=
|
||||||
github.com/xiaoqidun/j2kgo v1.0.2 h1:OAjjEOfaBaQzBNcj9wx+eM68UI5pewR6SzNZa1R1DIw=
|
github.com/xiaoqidun/j2kgo v1.0.2 h1:OAjjEOfaBaQzBNcj9wx+eM68UI5pewR6SzNZa1R1DIw=
|
||||||
github.com/xiaoqidun/j2kgo v1.0.2/go.mod h1:DCwAfuDzCDYqUiAlZ7BDwigTjaXw7o9L1FtEma/D1aA=
|
github.com/xiaoqidun/j2kgo v1.0.2/go.mod h1:DCwAfuDzCDYqUiAlZ7BDwigTjaXw7o9L1FtEma/D1aA=
|
||||||
github.com/xiaoqidun/jbig2 v1.1.8 h1:dERPW7F8gs18a/DOD9gXHR3fP1Vl6KhCNsLnq5l3BIo=
|
github.com/xiaoqidun/jbig2 v1.1.8 h1:dERPW7F8gs18a/DOD9gXHR3fP1Vl6KhCNsLnq5l3BIo=
|
||||||
|
|||||||
+125
-11
@@ -63,6 +63,10 @@ type Host struct {
|
|||||||
fontFiles map[string]string
|
fontFiles map[string]string
|
||||||
fontError error
|
fontError error
|
||||||
pendingPaths []string
|
pendingPaths []string
|
||||||
|
launchMu sync.Mutex
|
||||||
|
launchActivate bool
|
||||||
|
launchClosed bool
|
||||||
|
launchPending int
|
||||||
frontendReady bool
|
frontendReady bool
|
||||||
closeAllowed bool
|
closeAllowed bool
|
||||||
}
|
}
|
||||||
@@ -93,11 +97,38 @@ func Run(ctx context.Context, paths []string, dataDir string) error {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
paths = append([]string(nil), paths...)
|
||||||
|
for index, path := range paths {
|
||||||
|
paths[index], err = filepath.Abs(path)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
h := &Host{pendingPaths: paths}
|
||||||
|
data, err := json.Marshal(paths)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err := os.MkdirAll(options.UserDataDir, 0700); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
key, err := instanceDirectory(options.UserDataDir)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
instance, err := guigo.OpenInstance(ctx, "OFDGo:"+key, data, h.receiveLaunch)
|
||||||
|
if err != nil || instance == nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer instance.Close()
|
||||||
files, err := newFileStore()
|
files, err := newFileStore()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
h := &Host{files: files, engines: make(map[string]*webui.NativeEngine), cancels: make(map[string]context.CancelFunc), fontFiles: make(map[string]string), pendingPaths: append([]string(nil), paths...)}
|
h.files = files
|
||||||
|
h.engines = make(map[string]*webui.NativeEngine)
|
||||||
|
h.cancels = make(map[string]context.CancelFunc)
|
||||||
|
h.fontFiles = make(map[string]string)
|
||||||
cacheBytes := int64(256 << 20)
|
cacheBytes := int64(256 << 20)
|
||||||
if memory := conversionMemory; memory != nil {
|
if memory := conversionMemory; memory != nil {
|
||||||
cacheBytes = max(32<<20, memory()/8)
|
cacheBytes = max(32<<20, memory()/8)
|
||||||
@@ -110,7 +141,7 @@ func Run(ctx context.Context, paths []string, dataDir string) error {
|
|||||||
h.conversionPool = h.resources.ConversionPool()
|
h.conversionPool = h.resources.ConversionPool()
|
||||||
defer h.close()
|
defer h.close()
|
||||||
bindings := make(map[string]guigo.HandlerFunc)
|
bindings := make(map[string]guigo.HandlerFunc)
|
||||||
for _, name := range []string{"engine.open", "engine.close", "engine.call", "engine.start", "engine.cancel", "engine.finish", "batch", "open", "save", "directory", "file", "release", "drop.release", "child", "remove", "write.begin", "write.data", "write.commit", "write.abort", "fonts", "ready", "title", "window.info", "window.drag", "window.close", "update.check", "update.open", "association.query", "association.register", "association.remove", "print.capabilities", "print.dialog", "print.printers", "print.query", "print.properties", "print"} {
|
for _, name := range []string{"engine.open", "engine.close", "engine.call", "engine.start", "engine.cancel", "engine.finish", "batch", "open", "save", "directory", "file", "release", "drop.release", "child", "remove", "write.begin", "write.data", "write.commit", "write.abort", "fonts", "ready", "launch.done", "title", "window.info", "window.drag", "window.close", "update.check", "update.open", "association.query", "association.register", "association.remove", "print.capabilities", "print.dialog", "print.printers", "print.query", "print.properties", "print"} {
|
||||||
bindings["ofdgo.host."+name] = func(ctx context.Context, args any) (any, error) { return h.call(ctx, name, args) }
|
bindings["ofdgo.host."+name] = func(ctx context.Context, args any) (any, error) { return h.call(ctx, name, args) }
|
||||||
}
|
}
|
||||||
static := http.FileServerFS(webuiassets.NativeFS)
|
static := http.FileServerFS(webuiassets.NativeFS)
|
||||||
@@ -136,6 +167,9 @@ func Run(ctx context.Context, paths []string, dataDir string) error {
|
|||||||
h.mu.Unlock()
|
h.mu.Unlock()
|
||||||
}
|
}
|
||||||
options.OnClose = func() {
|
options.OnClose = func() {
|
||||||
|
h.launchMu.Lock()
|
||||||
|
h.launchClosed = true
|
||||||
|
h.launchMu.Unlock()
|
||||||
h.mu.Lock()
|
h.mu.Lock()
|
||||||
for _, cancel := range h.cancels {
|
for _, cancel := range h.cancels {
|
||||||
cancel()
|
cancel()
|
||||||
@@ -278,6 +312,13 @@ func (h *Host) emit(name string, value any) {
|
|||||||
// openPaths 将操作系统提供的文件登记后交给界面
|
// openPaths 将操作系统提供的文件登记后交给界面
|
||||||
// 入参: names 文件路径列表
|
// 入参: names 文件路径列表
|
||||||
func (h *Host) openPaths(names []string) {
|
func (h *Host) openPaths(names []string) {
|
||||||
|
_ = h.sendPaths(names, "ofdgo.files")
|
||||||
|
}
|
||||||
|
|
||||||
|
// sendPaths 将文件登记后发送到指定界面入口
|
||||||
|
// 入参: names 文件路径列表, event 界面事件名称
|
||||||
|
// 返回: error 投递错误
|
||||||
|
func (h *Host) sendPaths(names []string, event string) error {
|
||||||
files := make([]any, 0, len(names))
|
files := make([]any, 0, len(names))
|
||||||
for _, name := range names {
|
for _, name := range names {
|
||||||
file, err := h.files.addDrop(name)
|
file, err := h.files.addDrop(name)
|
||||||
@@ -290,12 +331,72 @@ func (h *Host) openPaths(names []string) {
|
|||||||
h.mu.Lock()
|
h.mu.Lock()
|
||||||
w := h.window
|
w := h.window
|
||||||
h.mu.Unlock()
|
h.mu.Unlock()
|
||||||
if w != nil && w.Emit("ofdgo.files", files) == nil {
|
var err error
|
||||||
return
|
if w == nil {
|
||||||
|
err = guigo.ErrClosed
|
||||||
|
} else {
|
||||||
|
err = w.Emit(event, files)
|
||||||
|
}
|
||||||
|
if err == nil {
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
for _, file := range files {
|
for _, file := range files {
|
||||||
h.files.discardDrop(file.(map[string]any)["nativeFile"].(string))
|
h.files.discardDrop(file.(map[string]any)["nativeFile"].(string))
|
||||||
}
|
}
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// receiveLaunch 接收已有进程转交的文件及激活请求
|
||||||
|
// 入参: ctx 请求上下文, data 文件路径消息
|
||||||
|
// 返回: error 接收错误
|
||||||
|
func (h *Host) receiveLaunch(ctx context.Context, data []byte) error {
|
||||||
|
var paths []string
|
||||||
|
if err := json.Unmarshal(data, &paths); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
for _, path := range paths {
|
||||||
|
if !filepath.IsAbs(path) {
|
||||||
|
return errors.New("file path must be absolute")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
h.launchMu.Lock()
|
||||||
|
defer h.launchMu.Unlock()
|
||||||
|
if h.launchClosed {
|
||||||
|
return guigo.ErrClosed
|
||||||
|
}
|
||||||
|
if err := ctx.Err(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
h.pendingPaths = append(h.pendingPaths, paths...)
|
||||||
|
h.launchActivate = true
|
||||||
|
return h.flushLaunch()
|
||||||
|
}
|
||||||
|
|
||||||
|
// flushLaunch 在界面就绪后按接收顺序投递外部打开请求,调用方持有launchMu
|
||||||
|
// 返回: error 投递错误
|
||||||
|
func (h *Host) flushLaunch() error {
|
||||||
|
h.mu.Lock()
|
||||||
|
ready, window := h.frontendReady, h.window
|
||||||
|
h.mu.Unlock()
|
||||||
|
if !ready || window == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
if h.launchActivate {
|
||||||
|
if err := window.Activate(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
h.launchActivate = false
|
||||||
|
}
|
||||||
|
if len(h.pendingPaths) == 0 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
paths := h.pendingPaths
|
||||||
|
h.pendingPaths = nil
|
||||||
|
if err := h.sendPaths(paths, "ofdgo.launch"); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
h.launchPending++
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// call 执行宿主协议并保留业务结果结构
|
// call 执行宿主协议并保留业务结果结构
|
||||||
@@ -603,10 +704,16 @@ func (h *Host) call(ctx context.Context, name string, value any) (any, error) {
|
|||||||
return window.TitleBarInfo()
|
return window.TitleBarInfo()
|
||||||
}
|
}
|
||||||
if name == "window.close" {
|
if name == "window.close" {
|
||||||
|
h.launchMu.Lock()
|
||||||
|
defer h.launchMu.Unlock()
|
||||||
|
if h.launchPending != 0 || len(h.pendingPaths) != 0 {
|
||||||
|
return false, nil
|
||||||
|
}
|
||||||
|
h.launchClosed = true
|
||||||
h.mu.Lock()
|
h.mu.Lock()
|
||||||
h.closeAllowed = true
|
h.closeAllowed = true
|
||||||
h.mu.Unlock()
|
h.mu.Unlock()
|
||||||
return nil, window.Close()
|
return true, window.Close()
|
||||||
}
|
}
|
||||||
values, ok := args["regions"].([]any)
|
values, ok := args["regions"].([]any)
|
||||||
if !ok {
|
if !ok {
|
||||||
@@ -628,16 +735,20 @@ func (h *Host) call(ctx context.Context, name string, value any) (any, error) {
|
|||||||
regions = append(regions, guigo.Rect{X: x, Y: y, Width: width, Height: height})
|
regions = append(regions, guigo.Rect{X: x, Y: y, Width: width, Height: height})
|
||||||
}
|
}
|
||||||
return nil, window.SetDragRegions(regions)
|
return nil, window.SetDragRegions(regions)
|
||||||
|
case "launch.done":
|
||||||
|
h.launchMu.Lock()
|
||||||
|
if h.launchPending > 0 {
|
||||||
|
h.launchPending--
|
||||||
|
}
|
||||||
|
h.launchMu.Unlock()
|
||||||
|
return nil, nil
|
||||||
case "ready":
|
case "ready":
|
||||||
|
h.launchMu.Lock()
|
||||||
|
defer h.launchMu.Unlock()
|
||||||
h.mu.Lock()
|
h.mu.Lock()
|
||||||
paths := h.pendingPaths
|
|
||||||
h.pendingPaths = nil
|
|
||||||
h.frontendReady = true
|
h.frontendReady = true
|
||||||
h.mu.Unlock()
|
h.mu.Unlock()
|
||||||
if len(paths) != 0 {
|
return nil, h.flushLaunch()
|
||||||
h.openPaths(paths)
|
|
||||||
}
|
|
||||||
return nil, nil
|
|
||||||
}
|
}
|
||||||
return nil, fmt.Errorf("未知宿主操作")
|
return nil, fmt.Errorf("未知宿主操作")
|
||||||
}
|
}
|
||||||
@@ -1019,6 +1130,9 @@ func (h *Host) closeEngine(id string) error {
|
|||||||
|
|
||||||
// close 取消任务并释放当前窗口持有的会话
|
// close 取消任务并释放当前窗口持有的会话
|
||||||
func (h *Host) close() {
|
func (h *Host) close() {
|
||||||
|
h.launchMu.Lock()
|
||||||
|
h.launchClosed = true
|
||||||
|
h.launchMu.Unlock()
|
||||||
h.mu.Lock()
|
h.mu.Lock()
|
||||||
for _, cancel := range h.cancels {
|
for _, cancel := range h.cancels {
|
||||||
cancel()
|
cancel()
|
||||||
|
|||||||
@@ -16,12 +16,20 @@ package webview
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"os"
|
"os"
|
||||||
|
"path/filepath"
|
||||||
"strings"
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
// conversionMemory 未提供系统内存探测时仅按并行数调度
|
// conversionMemory 未提供系统内存探测时仅按并行数调度
|
||||||
var conversionMemory func() int64
|
var conversionMemory func() int64
|
||||||
|
|
||||||
|
// instanceDirectory 解析数据目录的实际路径,使符号链接复用同一实例
|
||||||
|
// 入参: path 数据目录路径
|
||||||
|
// 返回: string 规范路径, error 路径解析错误
|
||||||
|
func instanceDirectory(path string) (string, error) {
|
||||||
|
return filepath.EvalSymlinks(path)
|
||||||
|
}
|
||||||
|
|
||||||
// fontNameLanguage 获取Linux区域设置对应的OpenType名称表标识
|
// fontNameLanguage 获取Linux区域设置对应的OpenType名称表标识
|
||||||
// 返回: uint16 名称表平台标识, uint16 显示语言标识
|
// 返回: uint16 名称表平台标识, uint16 显示语言标识
|
||||||
func fontNameLanguage() (uint16, uint16) {
|
func fontNameLanguage() (uint16, uint16) {
|
||||||
|
|||||||
@@ -16,9 +16,18 @@
|
|||||||
|
|
||||||
package webview
|
package webview
|
||||||
|
|
||||||
|
import "path/filepath"
|
||||||
|
|
||||||
// conversionMemory 未提供系统内存探测时仅按并行数调度
|
// conversionMemory 未提供系统内存探测时仅按并行数调度
|
||||||
var conversionMemory func() int64
|
var conversionMemory func() int64
|
||||||
|
|
||||||
|
// instanceDirectory 解析数据目录的实际路径
|
||||||
|
// 入参: path 数据目录路径
|
||||||
|
// 返回: string 规范路径, error 路径解析错误
|
||||||
|
func instanceDirectory(path string) (string, error) {
|
||||||
|
return filepath.EvalSymlinks(path)
|
||||||
|
}
|
||||||
|
|
||||||
// fontNameLanguage 未指定系统显示语言时沿用字体名称表顺序
|
// fontNameLanguage 未指定系统显示语言时沿用字体名称表顺序
|
||||||
// 返回: uint16 未指定平台标识, uint16 未指定语言标识
|
// 返回: uint16 未指定平台标识, uint16 未指定语言标识
|
||||||
func fontNameLanguage() (uint16, uint16) {
|
func fontNameLanguage() (uint16, uint16) {
|
||||||
|
|||||||
@@ -15,13 +15,39 @@
|
|||||||
package webview
|
package webview
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"os"
|
||||||
|
"strings"
|
||||||
"syscall"
|
"syscall"
|
||||||
"unsafe"
|
"unsafe"
|
||||||
|
|
||||||
|
"golang.org/x/sys/windows"
|
||||||
)
|
)
|
||||||
|
|
||||||
// memoryStatusProc 查询系统物理内存和提交额度
|
// memoryStatusProc 查询系统物理内存和提交额度
|
||||||
var memoryStatusProc = syscall.NewLazyDLL("kernel32.dll").NewProc("GlobalMemoryStatusEx")
|
var memoryStatusProc = syscall.NewLazyDLL("kernel32.dll").NewProc("GlobalMemoryStatusEx")
|
||||||
|
|
||||||
|
// instanceDirectory 解析数据目录的实际路径,使目录联接及大小写别名复用同一实例
|
||||||
|
// 入参: path 数据目录路径
|
||||||
|
// 返回: string 规范路径, error 路径解析错误
|
||||||
|
func instanceDirectory(path string) (string, error) {
|
||||||
|
dir, err := os.Open(path)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
defer dir.Close()
|
||||||
|
buffer := make([]uint16, 256)
|
||||||
|
for {
|
||||||
|
n, err := windows.GetFinalPathNameByHandle(windows.Handle(dir.Fd()), &buffer[0], uint32(len(buffer)), 0)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
if n < uint32(len(buffer)) {
|
||||||
|
return strings.ToLower(windows.UTF16ToString(buffer[:n])), nil
|
||||||
|
}
|
||||||
|
buffer = make([]uint16, n+1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// fontNameLanguage 获取系统显示语言对应的OpenType名称表标识
|
// fontNameLanguage 获取系统显示语言对应的OpenType名称表标识
|
||||||
// 返回: uint16 名称表平台标识, uint16 系统显示语言标识
|
// 返回: uint16 名称表平台标识, uint16 系统显示语言标识
|
||||||
func fontNameLanguage() (uint16, uint16) {
|
func fontNameLanguage() (uint16, uint16) {
|
||||||
|
|||||||
Reference in new issue
Block a user