From 743b9657e55f82b0e6b35d74f8b4653a8ad094e1 Mon Sep 17 00:00:00 2001 From: Geert-Johan Riemer Date: Sun, 18 Aug 2019 19:11:47 +0200 Subject: [PATCH] Adds comments and renames internals. Also some re-ordering of init code. --- application.go | 77 ++++++++++++++++++++++++-------------- embedder/embedder_proxy.go | 6 ++- glfw.go | 20 +++++++--- option.go | 25 +++++++++---- platform.go | 1 + texture-registry.go | 4 +- 6 files changed, 87 insertions(+), 46 deletions(-) diff --git a/application.go b/application.go index d2f47cb4..b569f14f 100644 --- a/application.go +++ b/application.go @@ -12,7 +12,6 @@ import ( "github.com/go-flutter-desktop/go-flutter/embedder" "github.com/go-flutter-desktop/go-flutter/internal/execpath" - "github.com/go-flutter-desktop/go-flutter/internal/tasker" ) // Run executes a flutter application with the provided options. @@ -105,7 +104,7 @@ func (a *Application) Run() error { glfw.WindowHint(glfw.OpenGLProfile, glfw.OpenGLCoreProfile) glfw.WindowHint(glfw.OpenGLForwardCompatible, glfw.True) - if a.config.windowInitialLocations.xpos != 0 { + if a.config.windowInitialLocation.xpos != 0 { // To create the window at a specific position, make it initially invisible // using the Visible window hint, set its position and then show it. glfw.WindowHint(glfw.Visible, glfw.False) @@ -115,12 +114,11 @@ func (a *Application) Run() error { if err != nil { return errors.Wrap(err, "creating glfw window") } - glfw.DefaultWindowHints() defer a.window.Destroy() + glfw.DefaultWindowHints() - if a.config.windowInitialLocations.xpos != 0 { - a.window.SetPos(a.config.windowInitialLocations.xpos, - a.config.windowInitialLocations.ypos) + if a.config.windowInitialLocation.xpos != 0 { + a.window.SetPos(a.config.windowInitialLocation.xpos, a.config.windowInitialLocation.ypos) a.window.Show() } @@ -157,6 +155,7 @@ func (a *Application) Run() error { a.engine = embedder.NewFlutterEngine() + // Create a messenger and init plugins messenger := newMessenger(a.engine) for _, p := range a.config.plugins { err = p.InitPlugin(messenger) @@ -173,6 +172,16 @@ func (a *Application) Run() error { } } + // Create a TextureRegistry + texturer := newTextureRegistry(a.engine, a.window) + + // Create a new eventloop + eventLoop := newEventLoop( + glfw.PostEmptyEvent, // Wakeup GLFW + a.engine.RunTask, // Flush tasks + ) + + // Set configuration values to engine, with fallbacks to sane defaults. if a.config.flutterAssetsPath != "" { a.engine.AssetsPath = a.config.flutterAssetsPath } else { @@ -182,7 +191,6 @@ func (a *Application) Run() error { } a.engine.AssetsPath = filepath.Join(filepath.Dir(execPath), "flutter_assets") } - if a.config.icuDataPath != "" { a.engine.IcuDataPath = a.config.icuDataPath } else { @@ -193,7 +201,7 @@ func (a *Application) Run() error { a.engine.IcuDataPath = filepath.Join(filepath.Dir(execPath), "icudtl.dat") } - // Render callbacks + // Attach GL callback functions onto the engine a.engine.GLMakeCurrent = func() bool { a.window.MakeContextCurrent() return true @@ -219,29 +227,29 @@ func (a *Application) Run() error { a.engine.GLProcResolver = func(procName string) unsafe.Pointer { return glfw.GetProcAddress(procName) } + a.engine.GLExternalTextureFrameCallback = texturer.handleExternalTexture - eventLoop := newEventLoop( - glfw.PostEmptyEvent, // Wakeup GLFW - a.engine.RunTask, // Flush tasks - ) + // Attach TaskRunner callback functions onto the engine a.engine.TaskRunnerRunOnCurrentThread = eventLoop.RunOnCurrentThread a.engine.TaskRunnerPostTask = eventLoop.PostTask + // Attach PlatformMessage callback functions onto the engine a.engine.PlatfromMessage = messenger.handlePlatformMessage - texturer := newRegistry(a.engine, a.window) - a.engine.GLExternalTextureFrameCallback = texturer.handleExternalTexture - // Not very nice, but we can only really fix this when there's a pluggable // renderer. defaultTextinputPlugin.keyboardLayout = a.config.keyboardLayout + // Set the glfw window user pointer to point to the FlutterEngine so that + // callback functions may obtain the FlutterEngine from the glfw window + // user pointer. flutterEnginePointer := uintptr(unsafe.Pointer(a.engine)) defer func() { runtime.KeepAlive(flutterEnginePointer) }() a.window.SetUserPointer(unsafe.Pointer(&flutterEnginePointer)) + // Start the engine result := a.engine.Run(unsafe.Pointer(&flutterEnginePointer), a.config.vmArguments) if result != embedder.ResultSuccess { switch result { @@ -255,25 +263,27 @@ func (a *Application) Run() error { os.Exit(1) } - defaultPlatformPlugin.glfwTasker = tasker.New() - - m := newWindowManager() - m.forcedPixelRatio = a.config.forcePixelRatio - - m.glfwRefreshCallback(a.window) - a.window.SetRefreshCallback(m.glfwRefreshCallback) - a.window.SetPosCallback(m.glfwPosCallback) + // Setup a new windowManager to handle windows pixel ratio's and pointer + // devices. + windowManager := newWindowManager(a.config.forcePixelRatio) + // force first refresh + windowManager.glfwRefreshCallback(a.window) + // Attach glfw window callbacks for refresh and position changes + a.window.SetRefreshCallback(windowManager.glfwRefreshCallback) + a.window.SetPosCallback(windowManager.glfwPosCallback) + // TODO: Can this only be done here? Why not in the plugin/glfwPlugin init loop above? for _, p := range a.config.plugins { // Extra init call for plugins that satisfy the PluginTexture interface. - if glfwPlugin, ok := p.(PluginTexture); ok { - err = glfwPlugin.InitPluginTexture(texturer) + if texturePlugin, ok := p.(PluginTexture); ok { + err = texturePlugin.InitPluginTexture(texturer) if err != nil { return errors.Wrap(err, "failed to initialize texture plugin"+fmt.Sprintf("%T", p)) } } } + // Attach glfw window callbacks for text input a.window.SetKeyCallback( func(window *glfw.Window, key glfw.Key, scancode int, action glfw.Action, mods glfw.ModifierKey) { defaultTextinputPlugin.glfwKeyCallback(window, key, scancode, action, mods) @@ -281,14 +291,20 @@ func (a *Application) Run() error { }) a.window.SetCharCallback(defaultTextinputPlugin.glfwCharCallback) + // Attach glfw window callback for iconification a.window.SetIconifyCallback(defaultLifecyclePlugin.glfwIconifyCallback) - a.window.SetCursorEnterCallback(m.glfwCursorEnterCallback) - a.window.SetCursorPosCallback(m.glfwCursorPosCallback) - a.window.SetMouseButtonCallback(m.glfwMouseButtonCallback) - a.window.SetScrollCallback(m.glfwScrollCallback) + // Attach glfw window callbacks for mouse input + a.window.SetCursorEnterCallback(windowManager.glfwCursorEnterCallback) + a.window.SetCursorPosCallback(windowManager.glfwCursorPosCallback) + a.window.SetMouseButtonCallback(windowManager.glfwMouseButtonCallback) + a.window.SetScrollCallback(windowManager.glfwScrollCallback) + + // Shutdown the engine if we return from this function (on purpose or panic) defer a.engine.Shutdown() + // Handle events until the window indicates we should stop. An event may tell the window to stop, in which case + // we'll exit on next iteration. for !a.window.ShouldClose() { eventLoop.WaitForEvents(func(duration float64) { glfw.WaitEventsTimeout(duration) @@ -297,6 +313,9 @@ func (a *Application) Run() error { messenger.engineTasker.ExecuteTasks() } + // TODO: What if the window indicates to stop, but there are tasks left on + // the queue? + fmt.Println("go-flutter: closing application") return nil diff --git a/embedder/embedder_proxy.go b/embedder/embedder_proxy.go index 1256d699..8b3d0079 100644 --- a/embedder/embedder_proxy.go +++ b/embedder/embedder_proxy.go @@ -61,11 +61,13 @@ func proxy_gl_proc_resolver(userData unsafe.Pointer, procname *C.char) unsafe.Po } //export proxy_gl_external_texture_frame_callback -func proxy_gl_external_texture_frame_callback(userData unsafe.Pointer, +func proxy_gl_external_texture_frame_callback( + userData unsafe.Pointer, textureID int64, width C.size_t, height C.size_t, - texture *C.FlutterOpenGLTexture) C.bool { + texture *C.FlutterOpenGLTexture, +) C.bool { flutterEnginePointer := *(*uintptr)(userData) flutterEngine := (*FlutterEngine)(unsafe.Pointer(flutterEnginePointer)) embedderGLTexture := flutterEngine.GLExternalTextureFrameCallback(textureID, int(width), int(height)) diff --git a/glfw.go b/glfw.go index 0e73fda1..633fcf4a 100644 --- a/glfw.go +++ b/glfw.go @@ -19,16 +19,24 @@ const dpPerInch = 160.0 // glfwRenderer or glfwManager? All the attaching to glfw.Window must be done // during manager init in that case. Cannot be done by Application. type windowManager struct { - forcedPixelRatio float64 - oncePrintPixelRatioLimit sync.Once - pointerPhase embedder.PointerPhase + // forcedPixelRatio forces the pixelRatio to given value, when value is not zero. + forcedPixelRatio float64 + + // sync.Once to limit pixelRatio warning messages. + oncePrintPixelRatioLimit sync.Once + + // current pointer state + pointerPhase embedder.PointerPhase + pointerButton embedder.PointerButtonMouse + pointerCurrentlyAdded bool + + // caching of ppsc to avoid re-calculating every event pixelsPerScreenCoordinate float64 - pointerCurrentlyAdded bool - pointerButton embedder.PointerButtonMouse } -func newWindowManager() *windowManager { +func newWindowManager(forcedPixelRatio float64) *windowManager { return &windowManager{ + forcedPixelRatio: forcedPixelRatio, pixelsPerScreenCoordinate: 1.0, pointerPhase: embedder.PointerPhaseHover, } diff --git a/option.go b/option.go index 43f628e3..5f07693d 100644 --- a/option.go +++ b/option.go @@ -16,7 +16,7 @@ type config struct { windowInitializerDeprecated func(*glfw.Window) error windowIconProvider func() ([]image.Image, error) windowInitialDimensions windowDimensions - windowInitialLocations windowLocations + windowInitialLocation windowLocation windowDimensionLimits windowDimensionLimits windowMode windowMode @@ -31,7 +31,7 @@ type windowDimensions struct { height int } -type windowLocations struct { +type windowLocation struct { xpos int ypos int } @@ -102,8 +102,8 @@ func OptionVMArguments(a []string) Option { // // Deprecated, please use WindowInitialDimensions(x, y). func ApplicationWindowDimension(x, y int) Option { - // deprecated on 2019-03-10 - fmt.Println("go-flutter: ApplicationWindowDimension is deprecated, use WindowInitialDimensions(x, y).") + // deprecated on 2019-03-10, to be removed 2020-01-01 + fmt.Println("go-flutter: ApplicationWindowDimension (singular) is deprecated, use WindowInitialDimensions (plural).") return WindowInitialDimensions(x, y) } @@ -127,7 +127,18 @@ func WindowInitialDimensions(width, height int) Option { // WindowInitialLocations specify the startup's position of the window. // Location, in screen coordinates, of the upper-left corner of the client area // of the window. +// +// Deprecated, please use WindowInitialLocation(xpos, ypos). func WindowInitialLocations(xpos, ypos int) Option { + // deprecated on 2019-08-18, to be removed 2020-06-01 + fmt.Println("go-flutter: WindowInitialLocations (plural) is deprecated, use WindowInitialLocation (singular).") + return WindowInitialLocation(xpos, ypos) +} + +// WindowInitialLocation specify the startup's position of the window. +// Location, in screen coordinates, of the upper-left corner of the client area +// of the window. +func WindowInitialLocation(xpos, ypos int) Option { if xpos < 1 { fmt.Println("go-flutter: invalid initial value for xpos location, must be 1 or greater.") os.Exit(1) @@ -138,8 +149,8 @@ func WindowInitialLocations(xpos, ypos int) Option { } return func(c *config) { - c.windowInitialLocations.xpos = xpos - c.windowInitialLocations.ypos = ypos + c.windowInitialLocation.xpos = xpos + c.windowInitialLocation.ypos = ypos } } @@ -175,7 +186,7 @@ func WindowDimensionLimits(minWidth, minHeight, maxWidth, maxHeight int) Option // // Deprecated, please use WindowIcon if you'd like to set the window icon. func OptionWindowInitializer(ini func(*glfw.Window) error) Option { - // deprecated on 2019-03-05 + // deprecated on 2019-03-05, to be removed 2020-01-01 fmt.Println("go-flutter: OptionWindowInitializer is deprecated. Please read https://is.gd/gflut_window_init_deprecated") return func(c *config) { c.windowInitializerDeprecated = ini diff --git a/platform.go b/platform.go index 6f76e645..fc477041 100644 --- a/platform.go +++ b/platform.go @@ -31,6 +31,7 @@ var _ PluginGLFW = &platformPlugin{} // compile-time type check func (p *platformPlugin) InitPlugin(messenger plugin.BinaryMessenger) error { p.messenger = messenger + p.glfwTasker = tasker.New() return nil } diff --git a/texture-registry.go b/texture-registry.go index 406e61e7..075eec33 100644 --- a/texture-registry.go +++ b/texture-registry.go @@ -32,7 +32,7 @@ type externalTextureHanlder struct { texture uint32 } -func newRegistry(engine *embedder.FlutterEngine, window *glfw.Window) *TextureRegistry { +func newTextureRegistry(engine *embedder.FlutterEngine, window *glfw.Window) *TextureRegistry { return &TextureRegistry{ window: window, engine: engine, @@ -45,7 +45,7 @@ func (t *TextureRegistry) init() error { // Important! Call gl.Init only under the presence of an active OpenGL context, // i.e., after MakeContextCurrent. if err := gl.Init(); err != nil { - return errors.Wrap(err, "TextureRegistry gl init") + return errors.Wrap(err, "TextureRegistry gl init failed") } return nil }