diff --git a/cef/application-callback.go b/cef/application-callback.go index aa0ccfba6563dbdf3f8df50c8621797b7a119593..1c1c15a96c328ccb07796f07046ff6fe27413ef4 100644 --- a/cef/application-callback.go +++ b/cef/application-callback.go @@ -13,8 +13,10 @@ package cef import ( + "fmt" "github.com/energye/energy/v2/cef/internal/ipc" "github.com/energye/energy/v2/cef/internal/process" + ipcArgument "github.com/energye/energy/v2/cef/ipc/argument" "github.com/energye/energy/v2/consts" ) @@ -26,6 +28,11 @@ func appOnContextCreated(browser *ICefBrowser, frame *ICefFrame, context *ICefV8 ipcRender.registerGoSyncReplayEvent() // render ipc ipcRender.makeIPC(context) // render ipc make makeProcess(browser, frame, context) // process make + + // 只在LCL窗口中使用自定义窗口拖拽, VF窗口默认已实现 + // 在MacOS中LCL窗口没有有效的消息事件 + var executeJS = `energyExtension.drag.setEnableDrag(true); energyExtension.drag.setup();` + frame.ExecuteJavaScript(executeJS, "", 0) } // appMainRunCallback 应用运行 - 默认实现 @@ -35,45 +42,89 @@ func appMainRunCallback() { // appWebKitInitialized - webkit - 默认实现 func appWebKitInitialized() { - // var myparamValue string - // v8Handler := V8HandlerRef.New() - // v8Handler.Execute(func(name string, object *ICefV8Value, arguments *TCefV8ValueArray, retVal *ResultV8Value, exception *ResultString) bool { - // fmt.Println("v8Handler.Execute", name) - // var result bool - // if name == "GetMyParam" { - // result = true - // retVal.SetResult(V8ValueRef.NewString(myparamValue)) - // } else if name == "SetMyParam" { - // if arguments.Size() > 0 { - // newValue := arguments.Get(0) - // fmt.Println("value is string:", newValue.IsString()) - // fmt.Println("value:", newValue.GetStringValue()) - // myparamValue = newValue.GetStringValue() - // newValue.Free() - // } - // result = true - // } - // return result - // }) - // //注册js - // var jsCode = ` - // let energyExtension; - // if (!energyExtension) { - // energyExtension = {}; - // } - // (function () { - // test.__defineGetter__('mouseover', function (e) { - // native function mouseover(); - // return mouseover(e); - // }); - // test.__defineSetter__('mousemove', function (e) { - // native function mousemove(); - // mousemove(e); - // }); - // })(); - //` - // // 注册JS 和v8处理器 - // RegisterExtension("v8/test", jsCode, v8Handler) + energyExtensionHandler := V8HandlerRef.New() + energyExtensionHandler.Execute(func(name string, object *ICefV8Value, arguments *TCefV8ValueArray, retVal *ResultV8Value, exception *ResultString) bool { + fmt.Println("Execute", name, consts.IsMessageLoop, application.SingleProcess()) + message := &ipcArgument.List{ + Id: -1, + BId: ipc.RenderChan().BrowserId(), + Name: internalIPCDRAG, + } + ipc.RenderChan().IPC().Send(message.Bytes()) + return false + }) + var code = ` + let energyExtension; + if (!energyExtension) { + energyExtension = { + drag: { + enableDrag: false, + shouldDrag: false, + cssDragProperty: "--webkit-app-region", + cssDragValue: "drag", + defaultCursor: null + }, + }; + } + (function () { + energyExtension.drag.war = function (e) { + let v = window.getComputedStyle(e.target).getPropertyValue(energyExtension.drag.cssDragProperty); + if (v) { + v = v.trim(); + if (v !== energyExtension.drag.cssDragValue || e.buttons !== 1) { + return false; + } + return e.detail === 1; + } + return false; + } + energyExtension.drag.mouseMove = function (e) { + if (!energyExtension.drag.enableDrag && !energyExtension.drag.shouldDrag) { + return + } + if (energyExtension.drag.shouldDrag) { + energyExtension.drag.shouldDrag = false; + native function mouseMove(); + mouseMove(e); + } + } + energyExtension.drag.mouseUp = function (e) { + if (!energyExtension.drag.enableDrag) { + return + } + energyExtension.drag.shouldDrag = false; + //document.body.style.cursor = "default"; + native function mouseUp(); + mouseUp(e); + } + energyExtension.drag.mouseDown = function (e) { + if (!energyExtension.drag.enableDrag && ((e.offsetX > e.target.clientWidth || e.offsetY > e.target.clientHeight))) { + return + } + if (energyExtension.drag.war(e)) { + console.log('mouseDown'); + e.preventDefault(); + energyExtension.drag.shouldDrag = true; + native function mouseDown(); + mouseDown(e); + } else { + energyExtension.drag.shouldDrag = false; + } + } + energyExtension.drag.setEnableDrag = function (v) { + console.log('drag.setEnableDrag', v, energyExtension); + energyExtension.drag.enableDrag = v; + } + energyExtension.drag.setup = function () { + console.log('drag.setup', energyExtension); + window.addEventListener("mousemove", energyExtension.drag.mouseMove); + window.addEventListener("mousedown", energyExtension.drag.mouseDown); + window.addEventListener("mouseup", energyExtension.drag.mouseUp); + } + })(); +` + // 注册 EnergyExtension JS + RegisterExtension("energyExtension", code, energyExtensionHandler) } // renderProcessMessageReceived 渲染进程消息 - 默认实现 diff --git a/cef/application-run.go b/cef/application-run.go index c97929c433371607b596c229a5925ea94d316755..dedc20969da1645b0c1c8a5e29178e126a8a0aa9 100644 --- a/cef/application-run.go +++ b/cef/application-run.go @@ -81,6 +81,7 @@ func Run(app *TCEFApplication) { } appMainRunCallback() if consts.IsMessageLoop { + lcl.Application.Initialize() // VF窗口消息轮询 app.RunMessageLoop() } else { diff --git a/cef/browser-window-lcl.go b/cef/browser-window-lcl.go index f7450e7ceaaf7d10b83b69ed2bdadd88c3545dcb..cd4151bf9e741c1a3fbf36d684981e21f795ab3d 100644 --- a/cef/browser-window-lcl.go +++ b/cef/browser-window-lcl.go @@ -22,8 +22,10 @@ import ( "github.com/energye/golcl/energy/emfs" "github.com/energye/golcl/energy/tools" "github.com/energye/golcl/lcl" + "github.com/energye/golcl/lcl/api" "github.com/energye/golcl/lcl/rtl" "github.com/energye/golcl/lcl/types" + "runtime" "time" ) @@ -132,6 +134,20 @@ func (m *LCLBrowserWindow) Handle() types.HWND { return m.hWnd } +// RunOnMainThread +// 在主线程中运行 +func (m *LCLBrowserWindow) RunOnMainThread(fn func()) { + runtime.LockOSThread() + defer runtime.UnlockOSThread() + if api.DMainThreadId() == api.DCurrentThreadId() { + fn() + } else { + lcl.ThreadSync(func() { + fn() + }) + } +} + // BrowserWindow 返回LCL窗口组件实例对象 func (m *LCLBrowserWindow) BrowserWindow() *LCLBrowserWindow { return m diff --git a/cef/browser-window-lcl_other.go b/cef/browser-window-lcl_other.go index f97eae478af78f9d5469a0d4b2a36eb2e67f27f5..20f9badf3150d3b9f39f79281eafd1012a145e47 100644 --- a/cef/browser-window-lcl_other.go +++ b/cef/browser-window-lcl_other.go @@ -111,3 +111,7 @@ func (m *LCLBrowserWindow) Maximize() { } }) } + +func (m *LCLBrowserWindow) drag() { + +} diff --git a/cef/browser-window-lcl_windows.go b/cef/browser-window-lcl_windows.go index 2716ef586139804da98c5f0411c948b28ddcb3aa..51b48eb45363dddec0dbd9617750c86f60228025 100644 --- a/cef/browser-window-lcl_windows.go +++ b/cef/browser-window-lcl_windows.go @@ -357,3 +357,9 @@ func (m *LCLBrowserWindow) Maximize() { // //LWA_ALPHA | LWA_COLORKEY: crKey的地方全透明,其它地方根据bAlpha确定透明度 // win.LWA_ALPHA|win.LWA_COLORKEY) //} + +func (m *LCLBrowserWindow) drag() { + if win.ReleaseCapture() { + win.PostMessage(m.Handle(), consts.WM_NCLBUTTONDOWN, consts.HTCAPTION, 0) + } +} diff --git a/cef/browser-window-views-framework.go b/cef/browser-window-views-framework.go index 392cb26302db76bf825e1e6b0d6be2c16ae8db58..ce94e74186e9648c8ab69b08262a3adba00257d6 100644 --- a/cef/browser-window-views-framework.go +++ b/cef/browser-window-views-framework.go @@ -22,7 +22,9 @@ import ( "github.com/energye/golcl/energy/emfs" "github.com/energye/golcl/energy/tools" "github.com/energye/golcl/lcl" + "github.com/energye/golcl/lcl/api" "github.com/energye/golcl/lcl/types" + "runtime" ) // ViewsFrameworkBrowserWindow 基于CEF views framework 窗口组件 @@ -598,3 +600,17 @@ func (m *ViewsFrameworkBrowserWindow) WindowComponent() *TCEFWindowComponent { func (m *ViewsFrameworkBrowserWindow) BrowserViewComponent() *TCEFBrowserViewComponent { return m.browserViewComponent } + +// RunOnMainThread +// 在主线程中运行 +func (m *ViewsFrameworkBrowserWindow) RunOnMainThread(fn func()) { + runtime.LockOSThread() + defer runtime.UnlockOSThread() + if api.DMainThreadId() == api.DCurrentThreadId() { + fn() + } else { + lcl.ThreadSync(func() { + fn() + }) + } +} diff --git a/cef/browser-window.go b/cef/browser-window.go index 5d5cfcc602b4c72f2206a90e3a780f93de677ed2..60022f81f5db99bfd73791c3ac823a14316c71fb 100644 --- a/cef/browser-window.go +++ b/cef/browser-window.go @@ -103,6 +103,7 @@ type IBrowserWindow interface { NewCefTray(width, height int32, url string) ITray //仅支持windows托盘LCL+[CEF|VF](使用web端技术自定义实现,如使用LCL窗口组件该托盘实现是LCL+CEF,如使用VF窗口组件该托盘实现是LCL+VF) NewSysTray() ITray //systray系统原生 SetCreateBrowserExtraInfo(windowName string, context *ICefRequestContext, extraInfo *ICefDictionaryValue) //设置 Chromium 创建浏览器时设置的扩展信息 + RunOnMainThread(fn func()) //在主线程中运行 } // ILCLBrowserWindow diff --git a/cef/ipc-browser.go b/cef/ipc-browser.go index 096db5bf8320f1777b5d52788290fe5c68ad9072..ed1c560b2b202f0ec393003b06b1ebfd7a44c5a0 100644 --- a/cef/ipc-browser.go +++ b/cef/ipc-browser.go @@ -13,11 +13,13 @@ package cef import ( + "fmt" "github.com/energye/energy/v2/cef/internal/ipc" ipcArgument "github.com/energye/energy/v2/cef/ipc/argument" "github.com/energye/energy/v2/cef/ipc/context" "github.com/energye/energy/v2/consts" "github.com/energye/energy/v2/pkgs/json" + "github.com/energye/golcl/lcl/api" ) // ipcBrowserProcess 主进程 @@ -140,7 +142,23 @@ func (m *ipcBrowserProcess) registerEvent() { } return false }) - + // drag + ipc.BrowserChan().AddCallback(func(channelId int64, argument ipcArgument.IList) bool { + if argument != nil { + if argument.GetName() == internalIPCDRAG { + if wi := BrowserWindow.GetWindowInfo(argument.BrowserId()); wi != nil { + if wi.IsLCL() { + wi.RunOnMainThread(func() { + fmt.Println("call-1-DMainThreadId:", api.DMainThreadId(), api.DCurrentThreadId()) + wi.AsLCLBrowserWindow().BrowserWindow().drag() + }) + } + } + return true + } + } + return false + }) } // jsExecuteGoSyncMethodMessage JS执行Go事件 - 同步消息处理 diff --git a/cef/ipc.go b/cef/ipc.go index 16b6ea904855f81526caa9cf8939b393a084c179..a46bfaf37ef4f4ea1e4f7f1c7cbf05f2ca6f687a 100644 --- a/cef/ipc.go +++ b/cef/ipc.go @@ -25,6 +25,7 @@ const ( internalIPCEmit = "emit" // JavaScript -> ipc.emit 在 JavaScript 触发 GO 监听事件函数名, 异步 internalIPCEmitSync = "emitSync" // JavaScript -> ipc.emitSync 在 JavaScript 触发 GO 监听事件函数名, 同步 internalIPCOn = "on" // JavaScript -> ipc.on 在 JavaScript 监听事件, 提供给 GO 调用 + internalIPCDRAG = "drag" // JavaScript -> ipc.on drag ) // ipc message name @@ -77,7 +78,7 @@ type ipcCallback struct { // isIPCInternalKey IPC 内部定义使用 key 不允许使用 func isIPCInternalKey(key string) bool { - return key == internalIPC || key == internalIPCEmit || key == internalIPCOn || key == internalIPCEmitSync || + return key == internalIPC || key == internalIPCEmit || key == internalIPCOn || key == internalIPCDRAG || key == internalIPCEmitSync || key == internalIPCJSExecuteGoEvent || key == internalIPCJSExecuteGoEventReplay || key == internalIPCGoExecuteJSEvent || key == internalIPCGoExecuteJSEventReplay || key == internalIPCJSExecuteGoSyncEvent || key == internalIPCJSExecuteGoSyncEventReplay diff --git a/cef/types-browser.go b/cef/types-browser.go index 2553cc85d2f0e58394540741771538b86c6712f7..ce2d4a9cfb7fa2ec0d073b6c52b1e389ab78fd3e 100644 --- a/cef/types-browser.go +++ b/cef/types-browser.go @@ -80,8 +80,10 @@ func (m *ICefBrowser) HostWindowHandle() types.HWND { if !m.IsValid() { return 0 } - r1, _, _ := imports.Proc(def.CEFBrowser_GetHostWindowHandle).Call(m.Instance()) - return r1 + if m.windowHandle == 0 { + m.windowHandle, _, _ = imports.Proc(def.CEFBrowser_GetHostWindowHandle).Call(m.Instance()) + } + return m.windowHandle } // CloseBrowser 关闭浏览器,同时关闭窗口 diff --git a/cef/types.go b/cef/types.go index 26c484425c2fd70d9b93be83c1291c918b7a3e52..0ec8e2ebc7ed71e80b87dbba5c6b1126370dc3a5 100644 --- a/cef/types.go +++ b/cef/types.go @@ -20,6 +20,7 @@ import ( . "github.com/energye/energy/v2/types" "github.com/energye/golcl/lcl" "github.com/energye/golcl/lcl/api" + "github.com/energye/golcl/lcl/types" "time" "unsafe" ) @@ -263,6 +264,7 @@ type ICefBrowser struct { instance unsafe.Pointer mainFrame *ICefFrame requestContext *ICefRequestContext + windowHandle types.HWND idFrames map[int64]*ICefFrame nameFrames map[string]*ICefFrame }