Fixed Chinese input and gtk3 issues for linux packaging

This commit is contained in:
杨红岩 2023-01-01 22:19:26 +08:00
parent 81f741a279
commit ef3393bb03
10 changed files with 135 additions and 66 deletions

View File

@ -63,9 +63,18 @@ func NewApplicationConfig() *tCefApplicationConfig {
m.SetDisableZygote(true)
m.SetCheckCEFFiles(false)
m.SetRemoteDebuggingPort(0)
m.SetExternalMessagePump(false)
m.SetMultiThreadedMessageLoop(true)
m.SetChromeRuntime(false)
//linux >= 107.xxx 版本以后默认启用的GTK3106及以前版本默认支持GTK2但无法正常输入中文
//顾强制使用GTK3方式但又无法正常创建lcl组件到窗口中该框架只对浏览器应用做封装
//所以初衷以浏览器应用建设为目标
if common.IsLinux() {
//linux平台默认设置为false,将启用 ViewsFrameworkBrowserWindow 窗口
m.SetExternalMessagePump(false)
m.SetMultiThreadedMessageLoop(false)
} else {
m.SetExternalMessagePump(false)
m.SetMultiThreadedMessageLoop(true)
}
return m
}

View File

@ -32,14 +32,6 @@ func NewCEFApplication(cfg *tCefApplicationConfig) *TCEFApplication {
cfg = NewApplicationConfig()
}
cfg.framework()
//linux >= 107.xxx 版本以后默认不支持GTK2同时GTK2又无法正常输入中文
//顾强制使用GTK3方式但又无法正常创建lcl组件到窗口中该框架只是对浏览器应用做封装
//所以尽量以正常使用为基准
if IsLinux() {
cfg.SetExternalMessagePump(false)
cfg.SetMultiThreadedMessageLoop(false)
}
m := new(TCEFApplication)
r1, _, _ := Proc(internale_CEFApplication_Create).Call(uintptr(unsafe.Pointer(cfg)))
m.instance = unsafe.Pointer(r1)

View File

@ -35,24 +35,23 @@ type IBaseWindow interface {
//BaseWindow 是一个基于chromium 和 lcl 的窗口组件
type BaseWindow struct {
*lcl.TForm //
chromium IChromium //
windowParent ITCefWindow //
browserViewComponent *TCEFBrowserViewComponent //
windowComponent *TCEFWindowComponent //
windowInfo *TCefWindowInfo //窗口信息
windowId int32 //
windowType WINDOW_TYPE //0:browser 1:devTools 2:viewSource 默认:0
isClosing bool //
canClose bool //
onResize []TNotifyEvent //
onActivate []TNotifyEvent //
onShow []TNotifyEvent //
onClose []TCloseEvent //
onCloseQuery []TCloseQueryEvent //
onActivateAfter lcl.TNotifyEvent //
isFormCreate bool //是否创建完成 WindowForm
isChromiumCreate bool //是否创建完成 Chromium
*lcl.TForm //
chromium IChromium //
windowParent ITCefWindow //
vFrameBrowserWindow *ViewsFrameworkBrowserWindow //基于CEF views framework窗口
windowInfo *TCefWindowInfo //基于LCL窗口信息
windowId int32 //
windowType WINDOW_TYPE //0:browser 1:devTools 2:viewSource 默认:0
isClosing bool //
canClose bool //
onResize []TNotifyEvent //
onActivate []TNotifyEvent //
onShow []TNotifyEvent //
onClose []TCloseEvent //
onCloseQuery []TCloseQueryEvent //
onActivateAfter lcl.TNotifyEvent //
isFormCreate bool //是否创建完成 WindowForm
isChromiumCreate bool //是否创建完成 Chromium
}
//创建一个带有 chromium 窗口
@ -67,6 +66,10 @@ func NewBrowserWindow(config *tCefChromiumConfig, defaultUrl string) *Window {
return window
}
func (m *BaseWindow) Id() int32 {
return m.windowId
}
func (m *BaseWindow) Show() {
m.TForm.Show()
}

View File

@ -12,16 +12,21 @@ import (
"github.com/energye/energy/common"
)
type viewsFrameBrowserWindowOnEventCallback func(event *BrowserEvent, window *ViewsFrameworkBrowserWindow)
type browserWindowOnEventCallback func(event *BrowserEvent, window *TCefWindowInfo)
type browserWindowAfterOnEventCallback func(window *TCefWindowInfo)
//创建主窗口指定的一些快捷配置属性
type browserConfig struct {
DefaultUrl string //默认URL地址
Title string //窗口标题
Icon string //窗口图标
Width int32 //窗口宽
Height int32 //窗口高
chromiumConfig *tCefChromiumConfig //主窗体浏览器配置
browserWindowOnEventCallback func(browserEvent *BrowserEvent, window *TCefWindowInfo) //主窗口初始化回调
browserWindowAfterOnEventCallback func(window *TCefWindowInfo) //主窗口初始化之后回调
DefaultUrl string //默认URL地址
Title string //窗口标题
Icon string //窗口图标
Width int32 //窗口宽
Height int32 //窗口高
chromiumConfig *tCefChromiumConfig //主窗体浏览器配置
viewsFrameBrowserWindowOnEventCallback viewsFrameBrowserWindowOnEventCallback //主窗口初始化回调 - 基于CEF views framework窗口
browserWindowOnEventCallback browserWindowOnEventCallback //主窗口初始化回调 - 基于LCL窗口
browserWindowAfterOnEventCallback browserWindowAfterOnEventCallback //主窗口初始化之后回调
}
//设置chromium配置
@ -31,13 +36,26 @@ func (m *browserConfig) SetChromiumConfig(chromiumConfig *tCefChromiumConfig) {
}
}
func (m *browserConfig) setBrowserWindowInitOnEvent(fn func(event *BrowserEvent, browserWindow *TCefWindowInfo)) {
//主窗口初始化回调 - 基于CEF views framework窗口
//
//该回调函数和基于LCL窗口回调是互斥的默认情况只有一个会被回调
func (m *browserConfig) setViewsFrameBrowserWindowOnEventCallback(fn viewsFrameBrowserWindowOnEventCallback) {
if fn != nil && common.Args.IsMain() {
m.viewsFrameBrowserWindowOnEventCallback = fn
}
}
//主窗口初始化回调 - 基于LCL窗口
//
//该回调函数和基于CEF窗口回调是互斥的默认情况只有一个会被回调
func (m *browserConfig) setBrowserWindowInitOnEvent(fn browserWindowOnEventCallback) {
if fn != nil && common.Args.IsMain() {
m.browserWindowOnEventCallback = fn
}
}
func (m *browserConfig) setBrowserWindowInitAfterOnEvent(fn func(browserWindow *TCefWindowInfo)) {
//主窗口初始化回调 - 基于LCL窗口
func (m *browserConfig) setBrowserWindowInitAfterOnEvent(fn browserWindowAfterOnEventCallback) {
if fn != nil && common.Args.IsMain() {
m.browserWindowAfterOnEventCallback = fn
}

View File

@ -18,6 +18,7 @@ import (
)
type TCEFBrowserViewComponent struct {
lcl.IComponent
instance unsafe.Pointer
}

View File

@ -98,7 +98,7 @@ type browserWindow struct {
//
// 主进程启动成功之后,将创建主窗口 mainBrowserWindow 是一个默认的主窗口
//
// externalMessagePump和multiThreadedMessageLoop是false时将使用RunMessageLoop这对linux v107.xxx之后版本支持的更好
// externalMessagePump和multiThreadedMessageLoop是false时启用 ViewsFrameworkBrowserWindow 窗口
//
// 在这里启动浏览器的主进程和子进程
func Run(cefApp *TCEFApplication) {
@ -179,24 +179,40 @@ func (m *browser) MainWindow() *TCefWindowInfo {
return m.mainWindow
}
// 主窗口和chromium初始化时回调
// 基于CEF views framework窗口 - 主窗口和chromium初始化时回调
//
// 当使用ViewsFramework创建窗口后我们无法使用lcl创建组件到窗口中
//
// ViewsFramework窗口主要解决在linux下gtk2和gtk3共存以及无法输入中文问题
//
// ViewsFramework窗口 和 LCL窗口同时只能存在一种
//
// event 浏览器事件
//
// views framework window 窗口信息对象
func (m *browser) SetViewFrameBrowserInit(fn viewsFrameBrowserWindowOnEventCallback) {
m.Config.setViewsFrameBrowserWindowOnEventCallback(fn)
}
// 基于LCL窗口 - 主窗口和chromium初始化时回调
//
// 在这里可以对主窗体事件监听和属性设置,和主窗口上的子组件创建
//
// 如果想创建子窗口或带有browser的窗口最好在 SetBrowserInitAfter 回调函数中创建
//
// event 浏览器事件
// mainBrowserWindow 窗口信息对象
func (m *browser) SetBrowserInit(fn func(event *BrowserEvent, browserWindow *TCefWindowInfo)) {
// event 浏览器事件
//
// browserWindow 窗口信息对象
func (m *browser) SetBrowserInit(fn browserWindowOnEventCallback) {
m.Config.setBrowserWindowInitOnEvent(fn)
}
// 主窗体和chromium初始后回调
// 基于LCL窗口 - 主窗体和chromium初始后回调
//
// 在这里可以对主窗体属性设置、添加子窗口、带有browser的窗口和子组件创建
//
// mainBrowserWindow 窗口信息对象
func (m *browser) SetBrowserInitAfter(fn func(browserWindow *TCefWindowInfo)) {
func (m *browser) SetBrowserInitAfter(fn browserWindowAfterOnEventCallback) {
m.Config.setBrowserWindowInitAfterOnEvent(fn)
}

View File

@ -10,17 +10,41 @@ package cef
import (
"fmt"
"github.com/energye/energy/common"
"github.com/energye/energy/consts"
"github.com/energye/golcl/lcl"
)
//基于CEF views framework窗口
//
//该窗口使用CEF内部实现在linux下107.xx以后版本默认使用GTK3但无法使用lcl组件集成到窗口中
//
//当创建应用配置时 MultiThreadedMessageLoop 和 ExternalMessagePump 属性同时为false(linux系统默认强制false)时启用ViewsFramework窗口
type ViewsFrameworkBrowserWindow struct {
component lcl.IComponent //
windowComponent *TCEFWindowComponent //
browserViewComponent *TCEFBrowserViewComponent //
}
func (m *ViewsFrameworkBrowserWindow) Component() lcl.IComponent {
return m.component
}
func (m *ViewsFrameworkBrowserWindow) WindowComponent() *TCEFWindowComponent {
return m.windowComponent
}
func (m *ViewsFrameworkBrowserWindow) BrowserViewComponent() *TCEFBrowserViewComponent {
return m.browserViewComponent
}
func (m *browserWindow) appContextInitialized(app *TCEFApplication) {
if !common.Args.IsMain() {
return
}
app.SetOnContextInitialized(func() {
fmt.Println("OnContextInitialized()")
component := lcl.NewComponent(nil)
m.vFrameBrowserWindow = &ViewsFrameworkBrowserWindow{}
m.vFrameBrowserWindow.component = lcl.NewComponent(nil)
if BrowserWindow.Config.chromiumConfig == nil {
BrowserWindow.Config.chromiumConfig = NewChromiumConfig()
BrowserWindow.Config.chromiumConfig.SetEnableMenu(true)
@ -28,43 +52,43 @@ func (m *browserWindow) appContextInitialized(app *TCEFApplication) {
BrowserWindow.Config.chromiumConfig.SetEnableOpenUrlTab(true)
BrowserWindow.Config.chromiumConfig.SetEnableWindowPopup(true)
}
m.chromium = NewChromium(component, BrowserWindow.Config.chromiumConfig)
m.chromium = NewChromium(m.vFrameBrowserWindow.component, BrowserWindow.Config.chromiumConfig)
m.chromium.SetEnableMultiBrowserMode(true)
m.browserViewComponent = NewBrowserViewComponent(component)
m.windowComponent = NewWindowComponent(component)
m.vFrameBrowserWindow.browserViewComponent = NewBrowserViewComponent(m.vFrameBrowserWindow.component)
m.vFrameBrowserWindow.windowComponent = NewWindowComponent(m.vFrameBrowserWindow.component)
m.chromium.SetOnBeforePopup(func(sender lcl.IObject, browser *ICefBrowser, frame *ICefFrame, beforePopupInfo *BeforePopupInfo, client *ICefClient, noJavascriptAccess *bool) bool {
fmt.Println("OnBeforePopup TargetUrl:", beforePopupInfo.TargetUrl)
return false
})
m.windowComponent.SetOnWindowCreated(func(sender lcl.IObject, window *ICefWindow) {
if m.chromium.CreateBrowserByBrowserViewComponent(BrowserWindow.Config.DefaultUrl, m.browserViewComponent) {
m.windowComponent.AddChildView(m.browserViewComponent)
m.windowComponent.SetTitle(BrowserWindow.Config.Title)
m.vFrameBrowserWindow.windowComponent.SetOnWindowCreated(func(sender lcl.IObject, window *ICefWindow) {
if m.chromium.CreateBrowserByBrowserViewComponent(BrowserWindow.Config.DefaultUrl, m.vFrameBrowserWindow.browserViewComponent) {
m.vFrameBrowserWindow.windowComponent.AddChildView(m.vFrameBrowserWindow.browserViewComponent)
m.vFrameBrowserWindow.windowComponent.SetTitle(BrowserWindow.Config.Title)
window.CenterWindow(NewCefSize(BrowserWindow.Config.Width, BrowserWindow.Config.Height))
m.browserViewComponent.RequestFocus()
m.vFrameBrowserWindow.browserViewComponent.RequestFocus()
if BrowserWindow.Config.Icon != "" {
window.SetWindowAppIconFS(1, BrowserWindow.Config.Icon)
}
if BrowserWindow.Config.browserWindowOnEventCallback != nil {
if BrowserWindow.Config.viewsFrameBrowserWindowOnEventCallback != nil {
BrowserWindow.browserEvent.chromium = m.chromium
BrowserWindow.Config.browserWindowOnEventCallback(BrowserWindow.browserEvent, m.windowInfo)
BrowserWindow.Config.viewsFrameBrowserWindowOnEventCallback(BrowserWindow.browserEvent, m.vFrameBrowserWindow)
}
window.Show()
}
})
m.windowComponent.SetOnCanClose(func(sender lcl.IObject, window *ICefWindow, aResult *bool) {
m.vFrameBrowserWindow.windowComponent.SetOnCanClose(func(sender lcl.IObject, window *ICefWindow, aResult *bool) {
fmt.Println("OnCanClose")
*aResult = true
app.QuitMessageLoop()
})
m.windowComponent.SetOnGetInitialBounds(func(sender lcl.IObject, window *ICefWindow, aResult *TCefRect) {
m.vFrameBrowserWindow.windowComponent.SetOnGetInitialBounds(func(sender lcl.IObject, window *ICefWindow, aResult *TCefRect) {
fmt.Println("OnGetInitialBounds")
})
m.windowComponent.SetOnGetInitialShowState(func(sender lcl.IObject, window *ICefWindow, aResult *consts.TCefShowState) {
m.vFrameBrowserWindow.windowComponent.SetOnGetInitialShowState(func(sender lcl.IObject, window *ICefWindow, aResult *consts.TCefShowState) {
fmt.Println("OnGetInitialShowState", *aResult)
})
m.windowComponent.CreateTopLevelWindow()
m.vFrameBrowserWindow.windowComponent.CreateTopLevelWindow()
})
}

View File

@ -20,6 +20,7 @@ import (
)
type TCEFWindowComponent struct {
lcl.IComponent
instance unsafe.Pointer
}

View File

@ -117,10 +117,6 @@ func (m *TCefWindowInfo) Maximize() {
})
}
func (m *TCefWindowInfo) WindowId() int32 {
return m.Window.windowId
}
// 关闭窗口-在ui线程中执行
func (m *TCefWindowInfo) Close() {
BrowserWindow.uiLock.Lock()
@ -131,7 +127,7 @@ func (m *TCefWindowInfo) Close() {
return
}
if m.Window == nil {
logger.Error("关闭浏览器 Form 为空 WindowId:", m.WindowId())
logger.Error("关闭浏览器 Window 为空")
return
}
if common.IsDarwin() {

View File

@ -21,7 +21,16 @@ func main() {
//指定一个URL地址或本地html文件目录
cef.BrowserWindow.Config.DefaultUrl = "http://localhost:22022/index.html"
cef.BrowserWindow.Config.Icon = "resources/icon.png"
cef.BrowserWindow.SetViewFrameBrowserInit(func(event *cef.BrowserEvent, window *cef.ViewsFrameworkBrowserWindow) {
fmt.Println("cef.BrowserWindow.SetViewFrameBrowserInit", window)
fmt.Printf("%+v\n", window)
})
cef.BrowserWindow.SetBrowserInit(func(event *cef.BrowserEvent, window *cef.TCefWindowInfo) {
fmt.Println("cef.BrowserWindow.SetBrowserInit", window)
fmt.Printf("%+v\n", window)
})
//在主进程启动成功之后执行
//在这里启动内置http服务
//内置http服务需要使用 go:embed resources 内置资源到执行程序中